summaryrefslogtreecommitdiff
path: root/cli_ure/CliLibrary_cli_basetypes.mk
AgeCommit message (Expand)AuthorFilesLines
2012-10-07most of this is not necessary anymoreDavid Tardon1-4/+0
2012-10-07fix gbuildized cli_urePeter Foley1-0/+4
2012-10-07use key directly from $(SRCDIR)David Tardon1-1/+1
2012-10-03CLI assemblies must depend on the key file used for signingDavid Tardon1-0/+2
2012-09-22gbuildize cli_ureDavid Tardon1-0/+33
09f84a395596d4953858'>Documentation/RCU/whatisRCU.txt6
-rw-r--r--Documentation/SubmittingPatches4
-rw-r--r--Documentation/acpi/enumeration.txt57
-rw-r--r--Documentation/arm/CCN.txt17
-rw-r--r--Documentation/arm/Samsung/Bootloader-interface.txt53
-rw-r--r--Documentation/arm/stm32/overview.txt32
-rw-r--r--Documentation/arm/stm32/stm32f429-overview.txt22
-rw-r--r--Documentation/arm/vlocks.txt2
-rw-r--r--Documentation/arm64/booting.txt10
-rw-r--r--Documentation/blackfin/gptimers-example.c14
-rw-r--r--Documentation/blockdev/zram.txt29
-rw-r--r--Documentation/cgroups/blkio-controller.txt83
-rw-r--r--Documentation/cgroups/memory.txt1
-rw-r--r--Documentation/cgroups/unified-hierarchy.txt102
-rw-r--r--Documentation/cpu-freq/governors.txt2
-rw-r--r--Documentation/cpu-freq/intel-pstate.txt21
-rw-r--r--Documentation/cpu-freq/user-guide.txt2
-rw-r--r--Documentation/cputopology.txt37
-rw-r--r--Documentation/debugging-via-ohci1394.txt2
-rw-r--r--Documentation/device-mapper/cache-policies.txt67
-rw-r--r--Documentation/device-mapper/cache.txt9
-rw-r--r--Documentation/device-mapper/dm-raid.txt2
-rw-r--r--Documentation/device-mapper/statistics.txt41
-rw-r--r--Documentation/devicetree/bindings/arm/altera/socfpga-sdram-controller.txt12
-rw-r--r--Documentation/devicetree/bindings/arm/altera/socfpga-sdram-edac.txt2
-rw-r--r--Documentation/devicetree/bindings/arm/arm-boards66
-rw-r--r--Documentation/devicetree/bindings/arm/armv7m_systick.txt26
-rw-r--r--Documentation/devicetree/bindings/arm/atmel-at91.txt2
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt31
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/brcm,bcm63138.txt76
-rw-r--r--Documentation/devicetree/bindings/arm/cci.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/coresight.txt12
-rw-r--r--Documentation/devicetree/bindings/arm/cpus.txt1
-rw-r--r--Documentation/devicetree/bindings/arm/exynos/power_domain.txt7
-rw-r--r--Documentation/devicetree/bindings/arm/fsl.txt3
-rw-r--r--Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt87
-rw-r--r--Documentation/devicetree/bindings/arm/l2cc.txt5
-rw-r--r--Documentation/devicetree/bindings/arm/marvell,berlin.txt100
-rw-r--r--Documentation/devicetree/bindings/arm/scu.txt25
-rw-r--r--Documentation/devicetree/bindings/arm/ux500/boards.txt83
-rw-r--r--Documentation/devicetree/bindings/arm/zte.txt15
-rw-r--r--Documentation/devicetree/bindings/ata/ahci-ceva.txt20
-rw-r--r--Documentation/devicetree/bindings/ata/ahci-platform.txt2
-rw-r--r--Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt34
-rw-r--r--Documentation/devicetree/bindings/clock/at91-clock.txt2
-rw-r--r--Documentation/devicetree/bindings/clock/hi6220-clock.txt34
-rw-r--r--Documentation/devicetree/bindings/clock/imx7d-clock.txt13
-rw-r--r--Documentation/devicetree/bindings/clock/marvell,berlin.txt31
-rw-r--r--Documentation/devicetree/bindings/clock/renesas,h8300-div-clock.txt24
-rw-r--r--Documentation/devicetree/bindings/clock/renesas,h8s2678-pll-clock.txt23
-rw-r--r--Documentation/devicetree/bindings/clock/zx296702-clk.txt35
-rw-r--r--Documentation/devicetree/bindings/crypto/fsl-sec2.txt6
-rw-r--r--Documentation/devicetree/bindings/crypto/marvell-cesa.txt45
-rw-r--r--Documentation/devicetree/bindings/crypto/mv_cesa.txt31
-rw-r--r--Documentation/devicetree/bindings/drm/msm/dsi.txt120
-rw-r--r--Documentation/devicetree/bindings/drm/msm/edp.txt60
-rw-r--r--Documentation/devicetree/bindings/drm/msm/hdmi.txt6
-rw-r--r--Documentation/devicetree/bindings/drm/tilcdc/slave.txt18
-rw-r--r--Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt27
-rw-r--r--Documentation/devicetree/bindings/edac/apm-xgene-edac.txt79
-rw-r--r--Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt2
-rw-r--r--Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt65
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-atlas7.txt50
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt21
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-xlp.txt47
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-zynq.txt2
-rw-r--r--Documentation/devicetree/bindings/gpio/nxp,lpc1850-gpio.txt39
-rw-r--r--Documentation/devicetree/bindings/h8300/cpu.txt13
-rw-r--r--Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt1
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-at91.txt30
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt28
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-mt6577.txt41
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-xgene-slimpro.txt15
-rw-r--r--Documentation/devicetree/bindings/i2c/trivial-devices.txt3
-rw-r--r--Documentation/devicetree/bindings/iio/adc/berlin2_adc.txt19
-rw-r--r--Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt4
-rw-r--r--Documentation/devicetree/bindings/iio/adc/vf610-adc.txt9
-rw-r--r--Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt17
-rw-r--r--Documentation/devicetree/bindings/iio/magnetometer/bmc150_magn.txt22
-rw-r--r--Documentation/devicetree/bindings/iio/st-sensors.txt2
-rw-r--r--Documentation/devicetree/bindings/iio/temperature/mlx90614.txt24
-rw-r--r--Documentation/devicetree/bindings/input/ti,drv2665.txt17
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt24
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt2
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/renesas,h8300h-intc.txt22
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/renesas,h8s-intc.txt22
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt39
-rw-r--r--Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt37
-rw-r--r--Documentation/devicetree/bindings/mailbox/brcm,bcm2835-mbox.txt26
-rw-r--r--Documentation/devicetree/bindings/mailbox/mailbox.txt10
-rw-r--r--Documentation/devicetree/bindings/media/i2c/adp1653.txt37
-rw-r--r--Documentation/devicetree/bindings/media/st,stih4xx.txt32
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt84
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/renesas,h8300-bsc.txt12
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/tegra-emc.txt374
-rw-r--r--Documentation/devicetree/bindings/mfd/arizona.txt19
-rw-r--r--Documentation/devicetree/bindings/mfd/axp20x.txt32
-rw-r--r--Documentation/devicetree/bindings/mfd/cros-ec.txt4
-rw-r--r--Documentation/devicetree/bindings/mfd/da9063.txt18
-rw-r--r--Documentation/devicetree/bindings/mfd/max77686.txt2
-rw-r--r--Documentation/devicetree/bindings/mfd/max77693.txt67
-rw-r--r--Documentation/devicetree/bindings/mfd/mfd.txt41
-rw-r--r--Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt2
-rw-r--r--Documentation/devicetree/bindings/mmc/arasan,sdhci.txt3
-rw-r--r--Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt9
-rw-r--r--Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt28
-rw-r--r--Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt4
-rw-r--r--Documentation/devicetree/bindings/mmc/mmc.txt5
-rw-r--r--Documentation/devicetree/bindings/mmc/mtk-sd.txt32
-rw-r--r--Documentation/devicetree/bindings/mmc/renesas,mmcif.txt3
-rw-r--r--Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt150
-rw-r--r--Documentation/devicetree/bindings/net/amd-xgbe-phy.txt48
-rw-r--r--Documentation/devicetree/bindings/net/amd-xgbe.txt40
-rw-r--r--Documentation/devicetree/bindings/net/ezchip_enet.txt15
-rw-r--r--Documentation/devicetree/bindings/net/ipq806x-dwmac.txt35
-rw-r--r--Documentation/devicetree/bindings/net/macb.txt6
-rw-r--r--Documentation/devicetree/bindings/net/nfc/nfcmrvl.txt29
-rw-r--r--Documentation/devicetree/bindings/net/nfc/st-nci.txt (renamed from Documentation/devicetree/bindings/net/nfc/st21nfcb.txt)4
-rw-r--r--Documentation/devicetree/bindings/net/nfc/trf7970a.txt4
-rw-r--r--Documentation/devicetree/bindings/net/nxp,lpc1850-dwmac.txt20
-rw-r--r--Documentation/devicetree/bindings/net/phy.txt3
-rw-r--r--Documentation/devicetree/bindings/net/renesas,ravb.txt48
-rw-r--r--Documentation/devicetree/bindings/net/rockchip-dwmac.txt2
-rw-r--r--Documentation/devicetree/bindings/net/ti,dp83867.txt25
-rw-r--r--Documentation/devicetree/bindings/panel/hannstar,hsd100pxn1.txt7
-rw-r--r--Documentation/devicetree/bindings/panel/lg,lb070wv8.txt7
-rw-r--r--Documentation/devicetree/bindings/pci/xgene-pci-msi.txt68
-rw-r--r--Documentation/devicetree/bindings/pci/xilinx-pcie.txt2
-rw-r--r--Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt40
-rw-r--r--Documentation/devicetree/bindings/phy/pxa1928-usb-phy.txt18
-rw-r--r--Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt1
-rw-r--r--Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/berlin,pinctrl.txt43
-rw-r--r--Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt27
-rw-r--r--Documentation/devicetree/bindings/pinctrl/img,pistachio-pinctrl.txt217
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt18
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt34
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt66
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-39x-pinctrl.txt84
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt80
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nxp,lpc1850-scu.txt57
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-atlas7.txt109
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.txt90
-rw-r--r--Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt4
-rw-r--r--Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt5
-rw-r--r--Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.txt7
-rw-r--r--Documentation/devicetree/bindings/power/bq24257.txt21
-rw-r--r--Documentation/devicetree/bindings/power/bq25890.txt46
-rw-r--r--Documentation/devicetree/bindings/power/opp.txt448
-rw-r--r--Documentation/devicetree/bindings/power/rt9455_charger.txt48
-rw-r--r--Documentation/devicetree/bindings/power/twl-charger.txt10
-rw-r--r--Documentation/devicetree/bindings/power_supply/max17042_battery.txt13
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/fman.txt13
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/guts.txt5
-rw-r--r--Documentation/devicetree/bindings/regulator/max8973-regulator.txt20
-rw-r--r--Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt121
-rw-r--r--Documentation/devicetree/bindings/regulator/regulator.txt7
-rw-r--r--Documentation/devicetree/bindings/reset/berlin,reset.txt23
-rw-r--r--Documentation/devicetree/bindings/reset/brcm,bcm63138-pmb.txt19
-rw-r--r--Documentation/devicetree/bindings/rtc/haoyu,hym8563.txt2
-rw-r--r--Documentation/devicetree/bindings/rtc/rtc-st-lpc.txt25
-rw-r--r--Documentation/devicetree/bindings/rtc/s3c-rtc.txt3
-rw-r--r--Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt10
-rw-r--r--Documentation/devicetree/bindings/serial/mtk-uart.txt12
-rw-r--r--Documentation/devicetree/bindings/serial/nxp,lpc1850-uart.txt28
-rw-r--r--Documentation/devicetree/bindings/serial/nxp,sc16is7xx.txt37
-rw-r--r--Documentation/devicetree/bindings/serial/pl011.txt2
-rw-r--r--Documentation/devicetree/bindings/serial/renesas,sci-serial.txt8
-rw-r--r--Documentation/devicetree/bindings/serial/sirf-uart.txt15
-rw-r--r--Documentation/devicetree/bindings/serial/uniphier-uart.txt23
-rw-r--r--Documentation/devicetree/bindings/soc/fsl/qman-portals.txt4
-rw-r--r--Documentation/devicetree/bindings/soc/sunxi/sram.txt72
-rw-r--r--Documentation/devicetree/bindings/sound/adi,adau1701.txt4
-rw-r--r--Documentation/devicetree/bindings/sound/bt-sco.txt13
-rw-r--r--Documentation/devicetree/bindings/sound/gtm601.txt13
-rw-r--r--Documentation/devicetree/bindings/sound/max98090.txt6
-rw-r--r--Documentation/devicetree/bindings/sound/mt8173-max98090.txt13
-rw-r--r--Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt13
-rw-r--r--Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt45
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt60
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt13
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsnd.txt3
-rw-r--r--Documentation/devicetree/bindings/sound/rt5645.txt72
-rw-r--r--Documentation/devicetree/bindings/sound/rt5677.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/simple-card.txt6
-rw-r--r--Documentation/devicetree/bindings/sound/tas2552.txt6
-rw-r--r--Documentation/devicetree/bindings/sound/tas571x.txt41
-rw-r--r--Documentation/devicetree/bindings/sound/wm8741.txt11
-rw-r--r--Documentation/devicetree/bindings/sound/zte,zx-i2s.txt44
-rw-r--r--Documentation/devicetree/bindings/sound/zte,zx-spdif.txt28
-rw-r--r--Documentation/devicetree/bindings/spi/sh-msiof.txt2
-rw-r--r--Documentation/devicetree/bindings/spi/spi-ath79.txt24
-rw-r--r--Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt2
-rw-r--r--Documentation/devicetree/bindings/spi/spi-orion.txt8
-rw-r--r--Documentation/devicetree/bindings/spi/spi-sirf.txt3
-rw-r--r--Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt26
-rw-r--r--Documentation/devicetree/bindings/spi/spi_atmel.txt8
-rw-r--r--Documentation/devicetree/bindings/spi/spi_pl022.txt2
-rw-r--r--Documentation/devicetree/bindings/thermal/hisilicon-thermal.txt23
-rw-r--r--Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt57
-rw-r--r--Documentation/devicetree/bindings/thermal/thermal.txt9
-rw-r--r--Documentation/devicetree/bindings/timer/cadence,ttc-timer.txt4
-rw-r--r--Documentation/devicetree/bindings/timer/nxp,lpc3220-timer.txt26
-rw-r--r--Documentation/devicetree/bindings/timer/renesas,16bit-timer.txt25
-rw-r--r--Documentation/devicetree/bindings/timer/renesas,8bit-timer.txt25
-rw-r--r--Documentation/devicetree/bindings/timer/renesas,tpu.txt21
-rw-r--r--Documentation/devicetree/bindings/timer/st,stm32-timer.txt22
-rw-r--r--Documentation/devicetree/bindings/usb/atmel-usb.txt25
-rw-r--r--Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt35
-rw-r--r--Documentation/devicetree/bindings/usb/ci-hdrc-qcom.txt17
-rw-r--r--Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt22
-rw-r--r--Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt17
-rw-r--r--Documentation/devicetree/bindings/usb/dwc3-st.txt7
-rw-r--r--Documentation/devicetree/bindings/usb/dwc3.txt2
-rw-r--r--Documentation/devicetree/bindings/usb/msm-hsusb.txt11
-rw-r--r--Documentation/devicetree/bindings/usb/renesas_usbhs.txt1
-rw-r--r--Documentation/devicetree/bindings/usb/twlxxxx-usb.txt3
-rw-r--r--Documentation/devicetree/bindings/usb/usb-ehci.txt2
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt13
-rw-r--r--Documentation/devicetree/bindings/video/exynos-mic.txt51
-rw-r--r--Documentation/devicetree/bindings/video/exynos5433-decon.txt65
-rw-r--r--Documentation/devicetree/bindings/video/exynos_dsim.txt31
-rw-r--r--Documentation/devicetree/bindings/video/ssd1307fb.txt23
-rw-r--r--Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt38
-rw-r--r--Documentation/devicetree/booting-without-of.txt4
-rw-r--r--Documentation/edac.txt289
-rw-r--r--Documentation/features/arch-support.txt11
-rw-r--r--Documentation/features/core/BPF-JIT/arch-support.txt40
-rw-r--r--Documentation/features/core/generic-idle-thread/arch-support.txt40
-rw-r--r--Documentation/features/core/jump-labels/arch-support.txt40
-rw-r--r--Documentation/features/core/tracehook/arch-support.txt40
-rw-r--r--Documentation/features/debug/KASAN/arch-support.txt40
-rw-r--r--Documentation/features/debug/gcov-profile-all/arch-support.txt40
-rw-r--r--Documentation/features/debug/kgdb/arch-support.txt40
-rw-r--r--Documentation/features/debug/kprobes-on-ftrace/arch-support.txt40
-rw-r--r--Documentation/features/debug/kprobes/arch-support.txt40
-rw-r--r--Documentation/features/debug/kretprobes/arch-support.txt40
-rw-r--r--Documentation/features/debug/optprobes/arch-support.txt40
-rw-r--r--Documentation/features/debug/stackprotector/arch-support.txt40
-rw-r--r--Documentation/features/debug/uprobes/arch-support.txt40
-rw-r--r--Documentation/features/debug/user-ret-profiler/arch-support.txt40
-rw-r--r--Documentation/features/io/dma-api-debug/arch-support.txt40
-rw-r--r--Documentation/features/io/dma-contiguous/arch-support.txt40
-rw-r--r--Documentation/features/io/dma_map_attrs/arch-support.txt40
-rw-r--r--Documentation/features/io/sg-chain/arch-support.txt40
-rw-r--r--Documentation/features/lib/strncasecmp/arch-support.txt40
-rwxr-xr-xDocumentation/features/list-arch.sh24
-rw-r--r--Documentation/features/locking/cmpxchg-local/arch-support.txt40
-rw-r--r--Documentation/features/locking/lockdep/arch-support.txt40
-rw-r--r--Documentation/features/locking/queued-rwlocks/arch-support.txt40
-rw-r--r--Documentation/features/locking/queued-spinlocks/arch-support.txt40
-rw-r--r--Documentation/features/locking/rwsem-optimized/arch-support.txt40
-rw-r--r--Documentation/features/perf/kprobes-event/arch-support.txt40
-rw-r--r--Documentation/features/perf/perf-regs/arch-support.txt40
-rw-r--r--Documentation/features/perf/perf-stackdump/arch-support.txt40
-rw-r--r--Documentation/features/sched/numa-balancing/arch-support.txt40
-rw-r--r--Documentation/features/seccomp/seccomp-filter/arch-support.txt40
-rw-r--r--Documentation/features/time/arch-tick-broadcast/arch-support.txt40
-rw-r--r--Documentation/features/time/clockevents/arch-support.txt40
-rw-r--r--Documentation/features/time/context-tracking/arch-support.txt40
-rw-r--r--Documentation/features/time/irq-time-acct/arch-support.txt40
-rw-r--r--Documentation/features/time/modern-timekeeping/arch-support.txt40
-rw-r--r--Documentation/features/time/virt-cpuacct/arch-support.txt40
-rw-r--r--Documentation/features/vm/ELF-ASLR/arch-support.txt40
-rw-r--r--Documentation/features/vm/PG_uncached/arch-support.txt40
-rw-r--r--Documentation/features/vm/THP/arch-support.txt40
-rw-r--r--Documentation/features/vm/huge-vmap/arch-support.txt40
-rw-r--r--Documentation/features/vm/ioremap_prot/arch-support.txt40
-rw-r--r--Documentation/features/vm/numa-memblock/arch-support.txt40
-rw-r--r--Documentation/features/vm/pmdp_splitting_flush/arch-support.txt40
-rw-r--r--Documentation/features/vm/pte_special/arch-support.txt40
-rw-r--r--Documentation/filesystems/Locking4
-rw-r--r--Documentation/filesystems/automount-support.txt51
-rw-r--r--Documentation/filesystems/nfs/knfsd-stats.txt44
-rw-r--r--Documentation/filesystems/porting25
-rw-r--r--Documentation/filesystems/proc.txt3
-rw-r--r--Documentation/filesystems/quota.txt5
-rw-r--r--Documentation/filesystems/vfs.txt39
-rw-r--r--Documentation/gpio/consumer.txt30
-rw-r--r--Documentation/gpio/gpio-legacy.txt9
-rw-r--r--Documentation/gpio/sysfs.txt8
-rw-r--r--Documentation/hwmon/ntc_thermistor6
-rw-r--r--Documentation/hwmon/tc7420
-rw-r--r--Documentation/i2c/slave-interface31
-rw-r--r--Documentation/input/rotary-encoder.txt2
-rw-r--r--Documentation/ja_JP/HOWTO2
-rw-r--r--Documentation/kasan.txt2
-rw-r--r--Documentation/kbuild/headers_install.txt9
-rw-r--r--Documentation/kbuild/makefiles.txt4
-rw-r--r--Documentation/kernel-parameters.txt122
-rw-r--r--Documentation/kmemleak.txt2
-rw-r--r--Documentation/laptops/.gitignore1
-rw-r--r--Documentation/laptops/00-INDEX2
-rw-r--r--Documentation/laptops/Makefile2
-rw-r--r--Documentation/leds/leds-class.txt3
-rw-r--r--Documentation/lockup-watchdogs.txt18
-rw-r--r--Documentation/magic-number.txt2
-rw-r--r--Documentation/md.txt2
-rw-r--r--Documentation/memory-barriers.txt68
-rw-r--r--Documentation/mic/mic_overview.txt28
-rw-r--r--Documentation/mic/mpssd/Makefile2
-rwxr-xr-xDocumentation/mic/mpssd/mpss24
-rw-r--r--Documentation/mic/scif_overview.txt98
-rw-r--r--Documentation/misc-devices/spear-pcie-gadget.txt2
-rw-r--r--Documentation/networking/bonding.txt84
-rw-r--r--Documentation/networking/can.txt3
-rw-r--r--Documentation/networking/dctcp.txt1
-rw-r--r--Documentation/networking/fore200e.txt2
-rw-r--r--Documentation/networking/ieee802154.txt32
-rw-r--r--Documentation/networking/ip-sysctl.txt25
-rw-r--r--Documentation/networking/netconsole.txt35
-rw-r--r--Documentation/networking/pktgen.txt150
-rw-r--r--Documentation/networking/switchdev.txt419
-rw-r--r--Documentation/networking/tc-actions-env-rules.txt6
-rw-r--r--Documentation/networking/timestamping/txtimestamp.c4
-rw-r--r--Documentation/nfc/nfc-hci.txt2
-rw-r--r--Documentation/phy.txt7
-rw-r--r--Documentation/pinctrl.txt11
-rw-r--r--Documentation/power/runtime_pm.txt6
-rw-r--r--Documentation/powerpc/00-INDEX2
-rw-r--r--Documentation/powerpc/cxl.txt4
-rw-r--r--Documentation/powerpc/dscr.txt83
-rw-r--r--Documentation/powerpc/transactional_memory.txt32
-rw-r--r--Documentation/pps/pps.txt2
-rw-r--r--Documentation/prctl/Makefile2
-rw-r--r--Documentation/preempt-locking.txt2
-rw-r--r--Documentation/s390/qeth.txt4
-rw-r--r--Documentation/scheduler/sched-deadline.txt184
-rw-r--r--Documentation/scsi/scsi_mid_low_api.txt2
-rw-r--r--Documentation/scsi/st.txt59
-rw-r--r--Documentation/serial/serial-rs485.txt50
-rw-r--r--Documentation/serial/tty.txt3
-rw-r--r--Documentation/sound/alsa/HD-Audio-Models.txt14
-rw-r--r--Documentation/sound/alsa/Jack-Controls.txt43
-rw-r--r--Documentation/sound/oss/PSS-updates2
-rw-r--r--Documentation/sound/oss/README.OSS2
-rw-r--r--Documentation/sound/oss/btaudio2
-rw-r--r--Documentation/stable_kernel_rules.txt19
-rw-r--r--Documentation/sysctl/kernel.txt25
-rwxr-xr-xDocumentation/target/tcm_mod_builder.py7
-rw-r--r--Documentation/thermal/cpu-cooling-api.txt156
-rw-r--r--Documentation/thermal/power_allocator.txt247
-rw-r--r--Documentation/thermal/sysfs-api.txt99
-rw-r--r--Documentation/trace/ftrace.txt4
-rw-r--r--Documentation/usb/gadget-testing.txt4
-rw-r--r--Documentation/usb/usb-serial.txt12
-rw-r--r--Documentation/vDSO/Makefile2
-rw-r--r--Documentation/vfio.txt62
-rw-r--r--Documentation/video4linux/CARDLIST.cx238859
-rw-r--r--Documentation/video4linux/CARDLIST.em28xx2
-rw-r--r--Documentation/video4linux/CARDLIST.saa71341
-rw-r--r--Documentation/video4linux/CARDLIST.saa71643
-rw-r--r--Documentation/video4linux/v4l2-framework.txt4
-rw-r--r--Documentation/video4linux/v4l2-pci-skeleton.c2
-rw-r--r--Documentation/video4linux/vivid.txt32
-rw-r--r--Documentation/virtual/kvm/api.txt69
-rw-r--r--Documentation/virtual/kvm/mmu.txt6
-rw-r--r--Documentation/vm/unevictable-lru.txt8
-rw-r--r--Documentation/vm/zswap.txt18
-rw-r--r--Documentation/vme_api.txt6
-rw-r--r--Documentation/w1/slaves/w1_therm11
-rw-r--r--Documentation/w1/w1.generic30
-rw-r--r--Documentation/workqueue.txt2
-rw-r--r--Documentation/x86/boot.txt1
-rw-r--r--Documentation/x86/entry_64.txt4
-rw-r--r--Documentation/x86/kernel-stacks (renamed from Documentation/x86/x86_64/kernel-stacks)54
-rw-r--r--Documentation/x86/mtrr.txt18
-rw-r--r--Documentation/x86/pat.txt48
-rw-r--r--Documentation/x86/x86_64/boot-options.txt3
-rw-r--r--Documentation/zh_CN/gpio.txt8
-rw-r--r--Documentation/zh_CN/magic-number.txt2
-rw-r--r--Kbuild34
-rw-r--r--MAINTAINERS342
-rw-r--r--Makefile7
-rw-r--r--arch/Kconfig7
-rw-r--r--arch/alpha/include/asm/Kbuild1
-rw-r--r--arch/alpha/include/asm/cmpxchg.h2
-rw-r--r--arch/alpha/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/alpha/include/asm/pci.h18
-rw-r--r--arch/alpha/include/asm/serial.h2
-rw-r--r--arch/alpha/kernel/core_irongate.c1
-rw-r--r--arch/alpha/kernel/sys_eiger.c1
-rw-r--r--arch/alpha/kernel/sys_nautilus.c1
-rw-r--r--arch/alpha/mm/fault.c5
-rw-r--r--arch/arc/include/asm/Kbuild1
-rw-r--r--arch/arc/include/asm/futex.h10
-rw-r--r--arch/arc/include/asm/io.h1
-rw-r--r--arch/arc/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/arc/mm/fault.c2
-rw-r--r--arch/arm/Kconfig108
-rw-r--r--arch/arm/Kconfig.debug67
-rw-r--r--arch/arm/Makefile8
-rw-r--r--arch/arm/boot/compressed/Makefile2
-rw-r--r--arch/arm/boot/compressed/head.S4
-rw-r--r--arch/arm/boot/dts/Makefile72
-rw-r--r--arch/arm/boot/dts/am335x-baltos-ir5221.dts532
-rw-r--r--arch/arm/boot/dts/am335x-bone-common.dtsi66
-rw-r--r--arch/arm/boot/dts/am335x-evm.dts81
-rw-r--r--arch/arm/boot/dts/am335x-sl50.dts482
-rw-r--r--arch/arm/boot/dts/am3517.dtsi11
-rw-r--r--arch/arm/boot/dts/am437x-gp-evm.dts144
-rw-r--r--arch/arm/boot/dts/am57xx-beagle-x15.dts81
-rw-r--r--arch/arm/boot/dts/arm-realview-pb1176.dts2
-rw-r--r--arch/arm/boot/dts/armada-370-db.dts2
-rw-r--r--arch/arm/boot/dts/armada-370-dlink-dns327l.dts357
-rw-r--r--arch/arm/boot/dts/armada-370-synology-ds213j.dts2
-rw-r--r--arch/arm/boot/dts/armada-370-xp.dtsi2
-rw-r--r--arch/arm/boot/dts/armada-370.dtsi4
-rw-r--r--arch/arm/boot/dts/armada-375-db.dts2
-rw-r--r--arch/arm/boot/dts/armada-375.dtsi6
-rw-r--r--arch/arm/boot/dts/armada-385-db-ap.dts2
-rw-r--r--arch/arm/boot/dts/armada-385-linksys-caiman.dts114
-rw-r--r--arch/arm/boot/dts/armada-385-linksys-cobra.dts114
-rw-r--r--arch/arm/boot/dts/armada-385-linksys.dtsi332
-rw-r--r--arch/arm/boot/dts/armada-388-db.dts2
-rw-r--r--arch/arm/boot/dts/armada-388-gp.dts2
-rw-r--r--arch/arm/boot/dts/armada-388-rd.dts2
-rw-r--r--arch/arm/boot/dts/armada-38x.dtsi8
-rw-r--r--arch/arm/boot/dts/armada-398-db.dts2
-rw-r--r--arch/arm/boot/dts/armada-39x.dtsi6
-rw-r--r--arch/arm/boot/dts/armada-xp-axpwifiap.dts2
-rw-r--r--arch/arm/boot/dts/armada-xp-db.dts2
-rw-r--r--arch/arm/boot/dts/armada-xp-gp.dts2
-rw-r--r--arch/arm/boot/dts/armada-xp-synology-ds414.dts2
-rw-r--r--arch/arm/boot/dts/armada-xp.dtsi8
-rw-r--r--arch/arm/boot/dts/armv7-m.dtsi6
-rw-r--r--arch/arm/boot/dts/at91-ariettag25.dts79
-rw-r--r--arch/arm/boot/dts/at91-kizbox.dts159
-rw-r--r--arch/arm/boot/dts/at91-kizbox2.dts216
-rw-r--r--arch/arm/boot/dts/at91-kizboxmini.dts129
-rw-r--r--arch/arm/boot/dts/at91-sama5d3_xplained.dts35
-rw-r--r--arch/arm/boot/dts/at91-sama5d4_xplained.dts28
-rw-r--r--arch/arm/boot/dts/at91-sama5d4ek.dts7
-rw-r--r--arch/arm/boot/dts/at91rm9200.dtsi6
-rw-r--r--arch/arm/boot/dts/at91rm9200ek.dts4
-rw-r--r--arch/arm/boot/dts/at91sam9260.dtsi4
-rw-r--r--arch/arm/boot/dts/at91sam9261.dtsi4
-rw-r--r--arch/arm/boot/dts/at91sam9261ek.dts3
-rw-r--r--arch/arm/boot/dts/at91sam9263.dtsi4
-rw-r--r--arch/arm/boot/dts/at91sam9263ek.dts3
-rw-r--r--arch/arm/boot/dts/at91sam9g20ek_common.dtsi3
-rw-r--r--arch/arm/boot/dts/at91sam9g45.dtsi8
-rw-r--r--arch/arm/boot/dts/at91sam9m10g45ek.dts3
-rw-r--r--arch/arm/boot/dts/at91sam9n12.dtsi5
-rw-r--r--arch/arm/boot/dts/at91sam9n12ek.dts3
-rw-r--r--arch/arm/boot/dts/at91sam9rl.dtsi15
-rw-r--r--arch/arm/boot/dts/at91sam9rlek.dts11
-rw-r--r--arch/arm/boot/dts/at91sam9x5.dtsi56
-rw-r--r--arch/arm/boot/dts/at91sam9x5ek.dtsi3
-rw-r--r--arch/arm/boot/dts/axp209.dtsi5
-rw-r--r--arch/arm/boot/dts/bcm-cygnus.dtsi12
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b-plus.dts4
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b.dts4
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi.dtsi8
-rw-r--r--arch/arm/boot/dts/bcm2835.dtsi13
-rw-r--r--arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts97
-rw-r--r--arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts84
-rw-r--r--arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts7
-rw-r--r--arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts9
-rw-r--r--arch/arm/boot/dts/bcm4708-netgear-r6250.dts1
-rw-r--r--arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts1
-rw-r--r--arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts120
-rw-r--r--arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts1
-rw-r--r--arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts1
-rw-r--r--arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts1
-rw-r--r--arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts65
-rw-r--r--arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts128
-rw-r--r--arch/arm/boot/dts/bcm4709-netgear-r8000.dts1
-rw-r--r--arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi24
-rw-r--r--arch/arm/boot/dts/bcm5301x.dtsi36
-rw-r--r--arch/arm/boot/dts/bcm63138.dtsi43
-rw-r--r--arch/arm/boot/dts/bcm7445-bcm97445svmb.dts23
-rw-r--r--arch/arm/boot/dts/bcm7445.dtsi59
-rw-r--r--arch/arm/boot/dts/bcm958300k.dts16
-rw-r--r--arch/arm/boot/dts/bcm963138dvt.dts12
-rw-r--r--arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts34
-rw-r--r--arch/arm/boot/dts/berlin2.dtsi124
-rw-r--r--arch/arm/boot/dts/berlin2cd-google-chromecast.dts34
-rw-r--r--arch/arm/boot/dts/berlin2cd.dtsi100
-rw-r--r--arch/arm/boot/dts/berlin2q-marvell-dmp.dts34
-rw-r--r--arch/arm/boot/dts/berlin2q.dtsi154
-rw-r--r--arch/arm/boot/dts/cx92755.dtsi17
-rw-r--r--arch/arm/boot/dts/cx92755_equinox.dts4
-rw-r--r--arch/arm/boot/dts/dove-cm-a510.dts38
-rw-r--r--arch/arm/boot/dts/dove-cm-a510.dtsi195
-rw-r--r--arch/arm/boot/dts/dove-sbc-a510.dts182
-rw-r--r--arch/arm/boot/dts/dove.dtsi40
-rw-r--r--arch/arm/boot/dts/dra7.dtsi43
-rw-r--r--arch/arm/boot/dts/dra72-evm.dts110
-rw-r--r--arch/arm/boot/dts/dra72x.dtsi11
-rw-r--r--arch/arm/boot/dts/dra74x.dtsi15
-rw-r--r--arch/arm/boot/dts/dra7xx-clocks.dtsi11
-rw-r--r--arch/arm/boot/dts/emev2-kzm9d.dts4
-rw-r--r--arch/arm/boot/dts/exynos3250-monk.dts3
-rw-r--r--arch/arm/boot/dts/exynos3250-rinato.dts7
-rw-r--r--arch/arm/boot/dts/exynos3250.dtsi48
-rw-r--r--arch/arm/boot/dts/exynos4.dtsi152
-rw-r--r--arch/arm/boot/dts/exynos4210-origen.dts418
-rw-r--r--arch/arm/boot/dts/exynos4210-smdkv310.dts280
-rw-r--r--arch/arm/boot/dts/exynos4210-trats.dts592
-rw-r--r--arch/arm/boot/dts/exynos4210.dtsi72
-rw-r--r--arch/arm/boot/dts/exynos4212.dtsi12
-rw-r--r--arch/arm/boot/dts/exynos4412-odroid-common.dtsi732
-rw-r--r--arch/arm/boot/dts/exynos4412-odroidx.dts16
-rw-r--r--arch/arm/boot/dts/exynos4412-origen.dts892
-rw-r--r--arch/arm/boot/dts/exynos4412-smdk4412.dts210
-rw-r--r--arch/arm/boot/dts/exynos4412-tiny4412.dts54
-rw-r--r--arch/arm/boot/dts/exynos4412-trats2.dts1339
-rw-r--r--arch/arm/boot/dts/exynos4412.dtsi20
-rw-r--r--arch/arm/boot/dts/exynos4415.dtsi15
-rw-r--r--arch/arm/boot/dts/exynos4x12-pinctrl.dtsi8
-rw-r--r--arch/arm/boot/dts/exynos4x12.dtsi290
-rw-r--r--arch/arm/boot/dts/exynos5.dtsi6
-rw-r--r--arch/arm/boot/dts/exynos5250-smdk5250.dts12
-rw-r--r--arch/arm/boot/dts/exynos5250-snow.dts46
-rw-r--r--arch/arm/boot/dts/exynos5250.dtsi332
-rw-r--r--arch/arm/boot/dts/exynos5260-xyref5260.dts2
-rw-r--r--arch/arm/boot/dts/exynos5420-arndale-octa.dts652
-rw-r--r--arch/arm/boot/dts/exynos5420-peach-pit.dts2
-rw-r--r--arch/arm/boot/dts/exynos5420-smdk5420.dts645
-rw-r--r--arch/arm/boot/dts/exynos5420.dtsi305
-rw-r--r--arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi479
-rw-r--r--arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts20
-rw-r--r--arch/arm/boot/dts/exynos5422-odroidxu3.dts339
-rw-r--r--arch/arm/boot/dts/exynos5440-sd5v1.dts10
-rw-r--r--arch/arm/boot/dts/exynos5440-ssdk5440.dts85
-rw-r--r--arch/arm/boot/dts/exynos5440.dtsi4
-rw-r--r--arch/arm/boot/dts/exynos5800-peach-pi.dts2
-rw-r--r--arch/arm/boot/dts/imx23-olinuxino.dts6
-rw-r--r--arch/arm/boot/dts/imx23.dtsi40
-rw-r--r--arch/arm/boot/dts/imx28-cfa10036.dts3
-rw-r--r--arch/arm/boot/dts/imx6dl-apf6dev.dts60
-rw-r--r--arch/arm/boot/dts/imx6dl-aristainetos2_4.dts159
-rw-r--r--arch/arm/boot/dts/imx6dl-aristainetos2_7.dts97
-rw-r--r--arch/arm/boot/dts/imx6dl-cubox-i.dts5
-rw-r--r--arch/arm/boot/dts/imx6dl-gw551x.dts55
-rw-r--r--arch/arm/boot/dts/imx6dl-hummingboard.dts5
-rw-r--r--arch/arm/boot/dts/imx6dl.dtsi4
-rw-r--r--arch/arm/boot/dts/imx6q-apf6dev.dts64
-rw-r--r--arch/arm/boot/dts/imx6q-cubox-i.dts5
-rw-r--r--arch/arm/boot/dts/imx6q-gw551x.dts55
-rw-r--r--arch/arm/boot/dts/imx6q-hummingboard.dts5
-rw-r--r--arch/arm/boot/dts/imx6qdl-apf6.dtsi158
-rw-r--r--arch/arm/boot/dts/imx6qdl-apf6dev.dtsi479
-rw-r--r--arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi633
-rw-r--r--arch/arm/boot/dts/imx6qdl-cubox-i.dtsi5
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw551x.dtsi314
-rw-r--r--arch/arm/boot/dts/imx6qdl-hummingboard.dtsi19
-rw-r--r--arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi5
-rw-r--r--arch/arm/boot/dts/imx6qdl-microsom.dtsi108
-rw-r--r--arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi30
-rw-r--r--arch/arm/boot/dts/imx6qdl-sabrelite.dtsi30
-rw-r--r--arch/arm/boot/dts/imx6qdl.dtsi57
-rw-r--r--arch/arm/boot/dts/imx6sl-warp.dts39
-rw-r--r--arch/arm/boot/dts/imx7d-pinfunc.h1038
-rw-r--r--arch/arm/boot/dts/imx7d-sdb.dts408
-rw-r--r--arch/arm/boot/dts/imx7d.dtsi486
-rw-r--r--arch/arm/boot/dts/integrator.dtsi4
-rw-r--r--arch/arm/boot/dts/k2e-evm.dts1
-rw-r--r--arch/arm/boot/dts/k2e-netcp.dtsi206
-rw-r--r--arch/arm/boot/dts/k2e.dtsi1
-rw-r--r--arch/arm/boot/dts/k2hk-evm.dts1
-rw-r--r--arch/arm/boot/dts/k2hk-netcp.dtsi208
-rw-r--r--arch/arm/boot/dts/k2hk.dtsi1
-rw-r--r--arch/arm/boot/dts/k2l-evm.dts1
-rw-r--r--arch/arm/boot/dts/k2l-netcp.dtsi189
-rw-r--r--arch/arm/boot/dts/k2l.dtsi1
-rw-r--r--arch/arm/boot/dts/kirkwood-b3.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-cloudbox.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-dir665.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-dreamplug.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-lsxl.dtsi2
-rw-r--r--arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-netxbig.dtsi2
-rw-r--r--arch/arm/boot/dts/kirkwood-ns2-common.dtsi2
-rw-r--r--arch/arm/boot/dts/kirkwood-rd88f6192.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-synology.dtsi2
-rw-r--r--arch/arm/boot/dts/kirkwood-t5325.dts2
-rw-r--r--arch/arm/boot/dts/kirkwood-ts219.dtsi2
-rw-r--r--arch/arm/boot/dts/kizbox.dts150
-rw-r--r--arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts157
-rw-r--r--arch/arm/boot/dts/logicpd-torpedo-som.dtsi162
-rw-r--r--arch/arm/boot/dts/lpc18xx.dtsi114
-rw-r--r--arch/arm/boot/dts/lpc4350-hitex-eval.dts45
-rw-r--r--arch/arm/boot/dts/lpc4350.dtsi39
-rw-r--r--arch/arm/boot/dts/lpc4357-ea4357-devkit.dts41
-rw-r--r--arch/arm/boot/dts/lpc4357.dtsi39
-rw-r--r--arch/arm/boot/dts/mt8127.dtsi8
-rw-r--r--arch/arm/boot/dts/mt8135-pinfunc.h1302
-rw-r--r--arch/arm/boot/dts/mt8135.dtsi29
-rw-r--r--arch/arm/boot/dts/omap3-cm-t3517.dts2
-rw-r--r--arch/arm/boot/dts/omap3-devkit8000.dts41
-rw-r--r--arch/arm/boot/dts/omap3-evm-common.dtsi1
-rw-r--r--arch/arm/boot/dts/omap3-gta04.dtsi37
-rw-r--r--arch/arm/boot/dts/omap3-ldp.dts18
-rw-r--r--arch/arm/boot/dts/omap5-uevm.dts14
-rw-r--r--arch/arm/boot/dts/pxa27x.dtsi46
-rw-r--r--arch/arm/boot/dts/pxa2xx.dtsi7
-rw-r--r--arch/arm/boot/dts/pxa3xx.dtsi29
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts100
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-ifc6410.dts136
-rw-r--r--arch/arm/boot/dts/qcom-apq8064.dtsi175
-rw-r--r--arch/arm/boot/dts/qcom-msm8660.dtsi5
-rw-r--r--arch/arm/boot/dts/qcom-pm8841.dtsi18
-rw-r--r--arch/arm/boot/dts/qcom-pm8941.dtsi133
-rw-r--r--arch/arm/boot/dts/qcom-pma8084.dtsi92
-rw-r--r--arch/arm/boot/dts/r8a73a4-ape6evm.dts2
-rw-r--r--arch/arm/boot/dts/r8a73a4.dtsi11
-rw-r--r--arch/arm/boot/dts/r8a7740-armadillo800eva.dts2
-rw-r--r--arch/arm/boot/dts/r8a7740.dtsi10
-rw-r--r--arch/arm/boot/dts/r8a7778-bockw-reference.dts2
-rw-r--r--arch/arm/boot/dts/r8a7778-bockw.dts4
-rw-r--r--arch/arm/boot/dts/r8a7778.dtsi2
-rw-r--r--arch/arm/boot/dts/r8a7779-marzen.dts6
-rw-r--r--arch/arm/boot/dts/r8a7779.dtsi2
-rw-r--r--arch/arm/boot/dts/r8a7790-lager.dts4
-rw-r--r--arch/arm/boot/dts/r8a7790.dtsi66
-rw-r--r--arch/arm/boot/dts/r8a7791-henninger.dts2
-rw-r--r--arch/arm/boot/dts/r8a7791-koelsch.dts4
-rw-r--r--arch/arm/boot/dts/r8a7791.dtsi79
-rw-r--r--arch/arm/boot/dts/r8a7794.dtsi45
-rw-r--r--arch/arm/boot/dts/rk3066a-bqcurie2.dts44
-rw-r--r--arch/arm/boot/dts/rk3066a.dtsi44
-rw-r--r--arch/arm/boot/dts/rk3188-radxarock.dts45
-rw-r--r--arch/arm/boot/dts/rk3188.dtsi44
-rw-r--r--arch/arm/boot/dts/rk3288-evb-act8846.dts44
-rw-r--r--arch/arm/boot/dts/rk3288-evb-rk808.dts44
-rw-r--r--arch/arm/boot/dts/rk3288-evb.dtsi67
-rw-r--r--arch/arm/boot/dts/rk3288-firefly.dtsi14
-rw-r--r--arch/arm/boot/dts/rk3288-popmetal.dts6
-rw-r--r--arch/arm/boot/dts/rk3288-thermal.dtsi40
-rw-r--r--arch/arm/boot/dts/rk3288.dtsi58
-rw-r--r--arch/arm/boot/dts/rk3xxx.dtsi44
-rw-r--r--arch/arm/boot/dts/s3c2416-smdk2416.dts86
-rw-r--r--arch/arm/boot/dts/s3c2416.dtsi18
-rw-r--r--arch/arm/boot/dts/sama5d3.dtsi11
-rw-r--r--arch/arm/boot/dts/sama5d3xcm.dtsi9
-rw-r--r--arch/arm/boot/dts/sama5d4.dtsi218
-rw-r--r--arch/arm/boot/dts/sh73a0-kzm9g.dts1
-rw-r--r--arch/arm/boot/dts/sh73a0.dtsi10
-rw-r--r--arch/arm/boot/dts/socfpga.dtsi20
-rw-r--r--arch/arm/boot/dts/socfpga_arria10.dtsi363
-rw-r--r--[-rwxr-xr-x]arch/arm/boot/dts/socfpga_arria10_socdk.dtsi (renamed from arch/arm/boot/dts/socfpga_arria10_socdk.dts)40
-rw-r--r--arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts (renamed from include/linux/platform_data/irq-renesas-irqc.h)23
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5_sockit.dts16
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5_socrates.dts31
-rw-r--r--arch/arm/boot/dts/ste-dbx5x0.dtsi175
-rw-r--r--arch/arm/boot/dts/ste-href-stuib.dtsi50
-rw-r--r--arch/arm/boot/dts/ste-href-tvk1281618.dtsi7
-rw-r--r--arch/arm/boot/dts/ste-nomadik-stn8815.dtsi5
-rw-r--r--arch/arm/boot/dts/ste-snowball.dts23
-rw-r--r--arch/arm/boot/dts/stih407-b2120.dts2
-rw-r--r--arch/arm/boot/dts/stih407-family.dtsi231
-rw-r--r--arch/arm/boot/dts/stih407-pinctrl.dtsi2
-rw-r--r--arch/arm/boot/dts/stih407.dtsi28
-rw-r--r--arch/arm/boot/dts/stih410-b2120.dts10
-rw-r--r--arch/arm/boot/dts/stih416-b2020e.dts10
-rw-r--r--arch/arm/boot/dts/stih416-pinctrl.dtsi50
-rw-r--r--arch/arm/boot/dts/stih416.dtsi66
-rw-r--r--arch/arm/boot/dts/stih418-b2199.dts27
-rw-r--r--arch/arm/boot/dts/stihxxx-b2120.dtsi13
-rw-r--r--arch/arm/boot/dts/stm32f429-disco.dts71
-rw-r--r--arch/arm/boot/dts/stm32f429.dtsi214
-rw-r--r--arch/arm/boot/dts/sun4i-a10-a1000.dts211
-rw-r--r--arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts185
-rw-r--r--arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts40
-rw-r--r--arch/arm/boot/dts/sun4i-a10-cubieboard.dts226
-rw-r--r--arch/arm/boot/dts/sun4i-a10-gemei-g9.dts171
-rw-r--r--arch/arm/boot/dts/sun4i-a10-hackberry.dts200
-rw-r--r--arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts13
-rw-r--r--arch/arm/boot/dts/sun4i-a10-inet97fv2.dts123
-rw-r--r--arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts193
-rw-r--r--arch/arm/boot/dts/sun4i-a10-marsboard.dts20
-rw-r--r--arch/arm/boot/dts/sun4i-a10-mini-xplus.dts149
-rw-r--r--arch/arm/boot/dts/sun4i-a10-mk802.dts13
-rw-r--r--arch/arm/boot/dts/sun4i-a10-mk802ii.dts13
-rw-r--r--arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts228
-rw-r--r--arch/arm/boot/dts/sun4i-a10-pcduino.dts189
-rw-r--r--arch/arm/boot/dts/sun4i-a10.dtsi166
-rw-r--r--arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts154
-rw-r--r--arch/arm/boot/dts/sun5i-a10s-mk802.dts13
-rw-r--r--arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts328
-rw-r--r--arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts139
-rw-r--r--arch/arm/boot/dts/sun5i-a10s.dtsi651
-rw-r--r--arch/arm/boot/dts/sun5i-a13-hsg-h702.dts143
-rw-r--r--arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts155
-rw-r--r--arch/arm/boot/dts/sun5i-a13-olinuxino.dts245
-rw-r--r--arch/arm/boot/dts/sun5i-a13-utoo-p66.dts226
-rw-r--r--arch/arm/boot/dts/sun5i-a13.dtsi608
-rw-r--r--arch/arm/boot/dts/sun5i.dtsi609
-rw-r--r--arch/arm/boot/dts/sun6i-a31-app4-evb1.dts63
-rw-r--r--arch/arm/boot/dts/sun6i-a31-colombus.dts145
-rw-r--r--arch/arm/boot/dts/sun6i-a31-hummingbird.dts108
-rw-r--r--arch/arm/boot/dts/sun6i-a31-i7.dts149
-rw-r--r--arch/arm/boot/dts/sun6i-a31-m9.dts161
-rw-r--r--arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts149
-rw-r--r--arch/arm/boot/dts/sun6i-a31.dtsi133
-rw-r--r--arch/arm/boot/dts/sun6i-a31s-cs908.dts48
-rw-r--r--arch/arm/boot/dts/sun6i-a31s.dtsi5
-rw-r--r--arch/arm/boot/dts/sun7i-a20-bananapi.dts271
-rw-r--r--arch/arm/boot/dts/sun7i-a20-bananapro.dts25
-rw-r--r--arch/arm/boot/dts/sun7i-a20-cubieboard2.dts205
-rw-r--r--arch/arm/boot/dts/sun7i-a20-cubietruck.dts331
-rw-r--r--arch/arm/boot/dts/sun7i-a20-hummingbird.dts426
-rw-r--r--arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts267
-rw-r--r--arch/arm/boot/dts/sun7i-a20-m3.dts191
-rw-r--r--arch/arm/boot/dts/sun7i-a20-mk808c.dts148
-rw-r--r--arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts197
-rw-r--r--arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts301
-rw-r--r--arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts411
-rw-r--r--arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts250
-rw-r--r--arch/arm/boot/dts/sun7i-a20-orangepi.dts228
-rw-r--r--arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts194
-rw-r--r--arch/arm/boot/dts/sun7i-a20-pcduino3.dts217
-rw-r--r--arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts183
-rw-r--r--arch/arm/boot/dts/sun7i-a20.dtsi196
-rw-r--r--arch/arm/boot/dts/sun8i-a23-a33.dtsi636
-rw-r--r--arch/arm/boot/dts/sun8i-a23-evb.dts134
-rw-r--r--arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts5
-rw-r--r--arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts117
-rw-r--r--arch/arm/boot/dts/sun8i-a23.dtsi557
-rw-r--r--arch/arm/boot/dts/sun8i-a33-et-q8-v1.6.dts88
-rw-r--r--arch/arm/boot/dts/sun8i-a33-ga10h-v1.1.dts125
-rw-r--r--arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts129
-rw-r--r--arch/arm/boot/dts/sun8i-a33.dtsi97
-rw-r--r--arch/arm/boot/dts/sun9i-a80-cubieboard4.dts99
-rw-r--r--arch/arm/boot/dts/sun9i-a80-optimus.dts72
-rw-r--r--arch/arm/boot/dts/sun9i-a80.dtsi145
-rw-r--r--arch/arm/boot/dts/sunxi-common-regulators.dtsi5
-rw-r--r--arch/arm/boot/dts/tegra124-jetson-tk1.dts4
-rw-r--r--arch/arm/boot/dts/tegra124-venice2.dts3
-rw-r--r--arch/arm/boot/dts/tegra124.dtsi6
-rw-r--r--arch/arm/boot/dts/tegra20-seaboard.dts12
-rw-r--r--arch/arm/boot/dts/tegra20.dtsi2
-rw-r--r--arch/arm/boot/dts/tegra30-cardhu.dtsi30
-rw-r--r--arch/arm/boot/dts/tegra30.dtsi15
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts79
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-ld4.dtsi110
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts79
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-pro4.dtsi117
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts80
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-sld3.dtsi117
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts79
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-sld8.dtsi110
-rw-r--r--arch/arm/boot/dts/uniphier-support-card.dtsi65
-rw-r--r--arch/arm/boot/dts/vf-colibri.dtsi2
-rw-r--r--arch/arm/boot/dts/vf610-cosmic.dts2
-rw-r--r--arch/arm/boot/dts/vf610-pinfunc.h2
-rw-r--r--arch/arm/boot/dts/vf610-twr.dts2
-rw-r--r--arch/arm/boot/dts/vf610m4-colibri.dts99
-rw-r--r--arch/arm/boot/dts/vf610m4.dtsi50
-rw-r--r--arch/arm/boot/dts/zx296702-ad1.dts48
-rw-r--r--arch/arm/boot/dts/zx296702.dtsi139
-rw-r--r--arch/arm/boot/dts/zynq-7000.dtsi4
-rw-r--r--arch/arm/boot/dts/zynq-parallella.dts9
-rw-r--r--arch/arm/boot/dts/zynq-zc702.dts3
-rw-r--r--arch/arm/boot/dts/zynq-zc706.dts3
-rw-r--r--arch/arm/boot/dts/zynq-zed.dts3
-rw-r--r--arch/arm/boot/dts/zynq-zybo.dts8
-rw-r--r--arch/arm/common/Makefile1
-rw-r--r--arch/arm/common/edma.c3
-rw-r--r--arch/arm/common/mcpm_entry.c281
-rw-r--r--arch/arm/common/mcpm_head.S2
-rw-r--r--arch/arm/common/sa1111.c7
-rw-r--r--arch/arm/configs/at91_dt_defconfig2
-rw-r--r--arch/arm/configs/efm32_defconfig2
-rw-r--r--arch/arm/configs/exynos_defconfig50
-rw-r--r--arch/arm/configs/hisi_defconfig2
-rw-r--r--arch/arm/configs/imx_v6_v7_defconfig9
-rw-r--r--arch/arm/configs/keystone_defconfig6
-rw-r--r--arch/arm/configs/lpc18xx_defconfig151
-rw-r--r--arch/arm/configs/multi_v7_defconfig110
-rw-r--r--arch/arm/configs/omap2plus_defconfig3
-rw-r--r--arch/arm/configs/qcom_defconfig2
-rw-r--r--arch/arm/configs/sama5_defconfig1
-rw-r--r--arch/arm/configs/shmobile_defconfig4
-rw-r--r--arch/arm/configs/stm32_defconfig70
-rw-r--r--arch/arm/configs/tegra_defconfig10
-rw-r--r--arch/arm/configs/u8500_defconfig5
-rw-r--r--arch/arm/configs/vf610m4_defconfig42
-rw-r--r--arch/arm/configs/zx_defconfig129
-rw-r--r--arch/arm/crypto/Kconfig15
-rw-r--r--arch/arm/crypto/Makefile10
-rw-r--r--arch/arm/crypto/aes-ce-core.S7
-rw-r--r--arch/arm/crypto/sha512-armv4.pl649
-rw-r--r--arch/arm/crypto/sha512-armv7-neon.S455
-rw-r--r--arch/arm/crypto/sha512-core.S_shipped1861
-rw-r--r--arch/arm/crypto/sha512-glue.c121
-rw-r--r--arch/arm/crypto/sha512-neon-glue.c98
-rw-r--r--arch/arm/crypto/sha512.h8
-rw-r--r--arch/arm/crypto/sha512_neon_glue.c305
-rw-r--r--arch/arm/include/asm/Kbuild1
-rw-r--r--arch/arm/include/asm/assembler.h17
-rw-r--r--arch/arm/include/asm/barrier.h2
-rw-r--r--arch/arm/include/asm/cacheflush.h7
-rw-r--r--arch/arm/include/asm/cmpxchg.h67
-rw-r--r--arch/arm/include/asm/dma.h2
-rw-r--r--arch/arm/include/asm/edac.h5
-rw-r--r--arch/arm/include/asm/entry-macro-multi.S4
-rw-r--r--arch/arm/include/asm/firmware.h4
-rw-r--r--arch/arm/include/asm/futex.h13
-rw-r--r--arch/arm/include/asm/hugetlb.h13
-rw-r--r--arch/arm/include/asm/io.h53
-rw-r--r--arch/arm/include/asm/irqflags.h11
-rw-r--r--arch/arm/include/asm/kvm_asm.h2
-rw-r--r--arch/arm/include/asm/kvm_host.h5
-rw-r--r--arch/arm/include/asm/mach/arch.h2
-rw-r--r--arch/arm/include/asm/mcpm.h73
-rw-r--r--arch/arm/include/asm/memory.h16
-rw-r--r--arch/arm/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/arm/include/asm/module.h12
-rw-r--r--arch/arm/include/asm/pci.h10
-rw-r--r--arch/arm/include/asm/perf_event.h7
-rw-r--r--arch/arm/include/asm/pmu.h19
-rw-r--r--arch/arm/include/asm/proc-fns.h7
-rw-r--r--arch/arm/include/asm/smp.h3
-rw-r--r--arch/arm/include/asm/suspend.h1
-rw-r--r--arch/arm/include/asm/system_info.h1
-rw-r--r--arch/arm/include/asm/topology.h2
-rw-r--r--arch/arm/include/asm/unified.h2
-rw-r--r--arch/arm/include/asm/vfp.h9
-rw-r--r--arch/arm/include/debug/8250.S3
-rw-r--r--arch/arm/include/debug/efm32.S2
-rw-r--r--arch/arm/include/debug/imx-uart.h15
-rw-r--r--arch/arm/include/debug/pl01x.S7
-rw-r--r--arch/arm/kernel/Makefile5
-rw-r--r--arch/arm/kernel/debug.S2
-rw-r--r--arch/arm/kernel/entry-armv.S12
-rw-r--r--arch/arm/kernel/entry-common.S6
-rw-r--r--arch/arm/kernel/entry-ftrace.S2
-rw-r--r--arch/arm/kernel/entry-v7m.S13
-rw-r--r--arch/arm/kernel/head-nommu.S27
-rw-r--r--arch/arm/kernel/head.S52
-rw-r--r--arch/arm/kernel/module-plts.c183
-rw-r--r--arch/arm/kernel/module.c32
-rw-r--r--arch/arm/kernel/module.lds4
-rw-r--r--arch/arm/kernel/perf_event.c408
-rw-r--r--arch/arm/kernel/perf_event_cpu.c421
-rw-r--r--arch/arm/kernel/perf_event_v6.c49
-rw-r--r--arch/arm/kernel/perf_event_v7.c129
-rw-r--r--arch/arm/kernel/perf_event_xscale.c32
-rw-r--r--arch/arm/kernel/setup.c30
-rw-r--r--arch/arm/kernel/sleep.S16
-rw-r--r--arch/arm/kernel/smp.c10
-rw-r--r--arch/arm/kernel/tcm.c104
-rw-r--r--arch/arm/kernel/traps.c8
-rw-r--r--arch/arm/kvm/Kconfig1
-rw-r--r--arch/arm/kvm/Makefile2
-rw-r--r--arch/arm/kvm/arm.c24
-rw-r--r--arch/arm/kvm/interrupts.S12
-rw-r--r--arch/arm/kvm/interrupts_head.S23
-rw-r--r--arch/arm/kvm/mmu.c14
-rw-r--r--arch/arm/kvm/psci.c18
-rw-r--r--arch/arm/lib/call_with_stack.S2
-rw-r--r--arch/arm/lib/lib1funcs.S4
-rw-r--r--arch/arm/mach-at91/Makefile5
-rw-r--r--arch/arm/mach-at91/Makefile.boot8
-rw-r--r--arch/arm/mach-at91/include/mach/at91_ramc.h28
-rw-r--r--arch/arm/mach-at91/include/mach/at91rm9200_mc.h116
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9_smc.h98
-rw-r--r--arch/arm/mach-at91/pm.c8
-rw-r--r--arch/arm/mach-at91/pm.h14
-rw-r--r--arch/arm/mach-at91/pm_suspend.S3
-rw-r--r--arch/arm/mach-at91/sam9_smc.c136
-rw-r--r--arch/arm/mach-at91/sam9_smc.h11
-rw-r--r--arch/arm/mach-bcm/Kconfig2
-rw-r--r--arch/arm/mach-bcm/Makefile9
-rw-r--r--arch/arm/mach-bcm/bcm63xx_headsmp.S23
-rw-r--r--arch/arm/mach-bcm/bcm63xx_pmb.c221
-rw-r--r--arch/arm/mach-bcm/bcm63xx_smp.c169
-rw-r--r--arch/arm/mach-bcm/bcm63xx_smp.h9
-rw-r--r--arch/arm/mach-bcm/bcm_5301x.c9
-rw-r--r--arch/arm/mach-bcm/board_bcm2835.c91
-rw-r--r--arch/arm/mach-bcm/brcmstb.h19
-rw-r--r--arch/arm/mach-bcm/headsmp-brcmstb.S33
-rw-r--r--arch/arm/mach-bcm/platsmp-brcmstb.c4
-rw-r--r--arch/arm/mach-berlin/Kconfig1
-rw-r--r--arch/arm/mach-berlin/headsmp.S6
-rw-r--r--arch/arm/mach-berlin/platsmp.c3
-rw-r--r--arch/arm/mach-davinci/da850.c1
-rw-r--r--arch/arm/mach-davinci/include/mach/da8xx.h2
-rw-r--r--arch/arm/mach-davinci/pm_domain.c32
-rw-r--r--arch/arm/mach-ep93xx/simone.c135
-rw-r--r--arch/arm/mach-exynos/common.h4
-rw-r--r--arch/arm/mach-exynos/exynos.c3
-rw-r--r--arch/arm/mach-exynos/firmware.c18
-rw-r--r--arch/arm/mach-exynos/platsmp.c86
-rw-r--r--arch/arm/mach-exynos/pm.c51
-rw-r--r--arch/arm/mach-exynos/pm_domains.c53
-rw-r--r--arch/arm/mach-exynos/pmu.c6
-rw-r--r--arch/arm/mach-exynos/suspend.c10
-rw-r--r--arch/arm/mach-footbridge/dma.c2
-rw-r--r--arch/arm/mach-gemini/gpio.c4
-rw-r--r--arch/arm/mach-hisi/Makefile2
-rw-r--r--arch/arm/mach-hisi/core.h1
-rw-r--r--arch/arm/mach-hisi/headsmp.S16
-rw-r--r--arch/arm/mach-hisi/platmcpm.c133
-rw-r--r--arch/arm/mach-hisi/platsmp.c4
-rw-r--r--arch/arm/mach-imx/Kconfig83
-rw-r--r--arch/arm/mach-imx/Makefile33
-rw-r--r--arch/arm/mach-imx/Makefile.boot0
-rw-r--r--arch/arm/mach-imx/anatop.c5
-rw-r--r--arch/arm/mach-imx/common.h15
-rw-r--r--arch/arm/mach-imx/cpu.c3
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6q.c4
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6sl.c4
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6sx.c4
-rw-r--r--arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c318
-rw-r--r--arch/arm/mach-imx/gpc.c3
-rw-r--r--arch/arm/mach-imx/hardware.h1
-rw-r--r--arch/arm/mach-imx/headsmp.S1
-rw-r--r--arch/arm/mach-imx/iomux-imx31.c2
-rw-r--r--arch/arm/mach-imx/mach-cpuimx35.c206
-rw-r--r--arch/arm/mach-imx/mach-imx6q.c1
-rw-r--r--arch/arm/mach-imx/mach-imx6sl.c1
-rw-r--r--arch/arm/mach-imx/mach-imx6sx.c1
-rw-r--r--arch/arm/mach-imx/mach-imx7d.c43
-rw-r--r--arch/arm/mach-imx/mach-vf610.c1
-rw-r--r--arch/arm/mach-imx/mmdc.c2
-rw-r--r--arch/arm/mach-imx/mx27.h4
-rw-r--r--arch/arm/mach-imx/mx3x.h7
-rw-r--r--arch/arm/mach-imx/mxc.h24
-rw-r--r--arch/arm/mach-imx/pm-imx5.c205
-rw-r--r--arch/arm/mach-imx/pm-imx6.c38
-rw-r--r--arch/arm/mach-imx/suspend-imx53.S139
-rw-r--r--arch/arm/mach-imx/time.c385
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c1
-rw-r--r--arch/arm/mach-iop13xx/include/mach/time.h2
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/platform.h2
-rw-r--r--arch/arm/mach-keystone/keystone.c41
-rw-r--r--arch/arm/mach-keystone/platsmp.c13
-rw-r--r--arch/arm/mach-keystone/pm_domain.c33
-rw-r--r--arch/arm/mach-ks8695/include/mach/hardware.h2
-rw-r--r--arch/arm/mach-lpc18xx/Makefile1
-rw-r--r--arch/arm/mach-lpc18xx/Makefile.boot3
-rw-r--r--arch/arm/mach-lpc18xx/board-dt.c22
-rw-r--r--arch/arm/mach-lpc32xx/clock.c5
-rw-r--r--arch/arm/mach-mvebu/headsmp-a9.S1
-rw-r--r--arch/arm/mach-nspire/nspire.c2
-rw-r--r--arch/arm/mach-omap1/ams-delta-fiq-handler.S3
-rw-r--r--arch/arm/mach-omap1/board-ams-delta.c1
-rw-r--r--arch/arm/mach-omap1/board-fsample.c1
-rw-r--r--arch/arm/mach-omap1/board-generic.c1
-rw-r--r--arch/arm/mach-omap1/board-h2.c1
-rw-r--r--arch/arm/mach-omap1/board-h3-mmc.c1
-rw-r--r--arch/arm/mach-omap1/board-h3.c1
-rw-r--r--arch/arm/mach-omap1/board-htcherald.c1
-rw-r--r--arch/arm/mach-omap1/board-innovator.c1
-rw-r--r--arch/arm/mach-omap1/board-nokia770.c3
-rw-r--r--arch/arm/mach-omap1/board-osk.c1
-rw-r--r--arch/arm/mach-omap1/board-palmte.c1
-rw-r--r--arch/arm/mach-omap1/board-palmtt.c1
-rw-r--r--arch/arm/mach-omap1/board-palmz71.c1
-rw-r--r--arch/arm/mach-omap1/board-perseus2.c1
-rw-r--r--arch/arm/mach-omap1/board-sx1.c1
-rw-r--r--arch/arm/mach-omap1/board-voiceblue.c1
-rw-r--r--arch/arm/mach-omap1/common.h7
-rw-r--r--arch/arm/mach-omap1/dma.c2
-rw-r--r--arch/arm/mach-omap1/gpio16xx.c2
-rw-r--r--arch/arm/mach-omap1/gpio7xx.c2
-rw-r--r--arch/arm/mach-omap1/i2c.c3
-rw-r--r--arch/arm/mach-omap1/include/mach/entry-macro.S39
-rw-r--r--arch/arm/mach-omap1/include/mach/irqs.h124
-rw-r--r--arch/arm/mach-omap1/include/mach/memory.h4
-rw-r--r--arch/arm/mach-omap1/include/mach/serial.h5
-rw-r--r--arch/arm/mach-omap1/include/mach/soc.h4
-rw-r--r--arch/arm/mach-omap1/irq.c157
-rw-r--r--arch/arm/mach-omap1/mux.c8
-rw-r--r--arch/arm/mach-omap1/pm.c1
-rw-r--r--arch/arm/mach-omap1/pm_bus.c37
-rw-r--r--arch/arm/mach-omap1/serial.c1
-rw-r--r--arch/arm/mach-omap1/timer.c4
-rw-r--r--arch/arm/mach-omap2/Kconfig22
-rw-r--r--arch/arm/mach-omap2/Makefile3
-rw-r--r--arch/arm/mach-omap2/board-cm-t35.c769
-rw-r--r--arch/arm/mach-omap2/board-omap3beagle.c595
-rw-r--r--arch/arm/mach-omap2/board-overo.c571
-rw-r--r--arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c12
-rw-r--r--arch/arm/mach-omap2/control.c3
-rw-r--r--arch/arm/mach-omap2/control.h3
-rw-r--r--arch/arm/mach-omap2/devices.c4
-rw-r--r--arch/arm/mach-omap2/display.c32
-rw-r--r--arch/arm/mach-omap2/fb.c2
-rw-r--r--arch/arm/mach-omap2/gpmc-onenand.c4
-rw-r--r--arch/arm/mach-omap2/hsmmc.c2
-rw-r--r--arch/arm/mach-omap2/omap-wakeupgen.c2
-rw-r--r--arch/arm/mach-omap2/omap_device.c61
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c10
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.h6
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c12
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_33xx_43xx_common_data.h1
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c16
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_33xx_data.c13
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_3xxx_data.c119
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_43xx_data.c22
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c11
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_7xx_data.c37
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_81xx_data.c2
-rw-r--r--arch/arm/mach-omap2/opp2430_data.c4
-rw-r--r--arch/arm/mach-omap2/pdata-quirks.c22
-rw-r--r--arch/arm/mach-omap2/pmu.c2
-rw-r--r--arch/arm/mach-omap2/prcm43xx.h2
-rw-r--r--arch/arm/mach-omap2/sdrc2xxx.c2
-rw-r--r--arch/arm/mach-omap2/serial.c2
-rw-r--r--arch/arm/mach-omap2/sram242x.S2
-rw-r--r--arch/arm/mach-omap2/sram243x.S2
-rw-r--r--arch/arm/mach-prima2/headsmp.S1
-rw-r--r--arch/arm/mach-pxa/Makefile9
-rw-r--r--arch/arm/mach-pxa/clock-pxa2xx.c55
-rw-r--r--arch/arm/mach-pxa/clock-pxa3xx.c212
-rw-r--r--arch/arm/mach-pxa/clock.c86
-rw-r--r--arch/arm/mach-pxa/clock.h80
-rw-r--r--arch/arm/mach-pxa/eseries.c28
-rw-r--r--arch/arm/mach-pxa/generic.c6
-rw-r--r--arch/arm/mach-pxa/generic.h3
-rw-r--r--arch/arm/mach-pxa/irq.c2
-rw-r--r--arch/arm/mach-pxa/lubbock.c5
-rw-r--r--arch/arm/mach-pxa/mp900.c2
-rw-r--r--arch/arm/mach-pxa/pxa25x.c183
-rw-r--r--arch/arm/mach-pxa/pxa27x.c182
-rw-r--r--arch/arm/mach-pxa/pxa300.c20
-rw-r--r--arch/arm/mach-pxa/pxa320.c10
-rw-r--r--arch/arm/mach-pxa/pxa3xx.c59
-rw-r--r--arch/arm/mach-pxa/raumfeld.c1
-rw-r--r--arch/arm/mach-pxa/tosa.c2
-rw-r--r--arch/arm/mach-realview/core.c13
-rw-r--r--arch/arm/mach-rockchip/core.h1
-rw-r--r--arch/arm/mach-rockchip/headsmp.S8
-rw-r--r--arch/arm/mach-rockchip/platsmp.c5
-rw-r--r--arch/arm/mach-sa1100/Makefile2
-rw-r--r--arch/arm/mach-sa1100/generic.c37
-rw-r--r--arch/arm/mach-sa1100/neponset.c3
-rw-r--r--arch/arm/mach-shmobile/Kconfig4
-rw-r--r--arch/arm/mach-shmobile/common.h1
-rw-r--r--arch/arm/mach-shmobile/headsmp-scu.S4
-rw-r--r--arch/arm/mach-shmobile/headsmp.S7
-rw-r--r--arch/arm/mach-shmobile/platsmp-apmu.c2
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7740.c55
-rw-r--r--arch/arm/mach-socfpga/Kconfig11
-rw-r--r--arch/arm/mach-socfpga/Makefile1
-rw-r--r--arch/arm/mach-socfpga/core.h12
-rw-r--r--arch/arm/mach-socfpga/headsmp.S10
-rw-r--r--arch/arm/mach-socfpga/platsmp.c59
-rw-r--r--arch/arm/mach-socfpga/pm.c149
-rw-r--r--arch/arm/mach-socfpga/self-refresh.S136
-rw-r--r--arch/arm/mach-socfpga/socfpga.c41
-rw-r--r--arch/arm/mach-sti/Kconfig1
-rw-r--r--arch/arm/mach-stm32/Makefile1
-rw-r--r--arch/arm/mach-stm32/Makefile.boot3
-rw-r--r--arch/arm/mach-stm32/board-dt.c19
-rw-r--r--arch/arm/mach-sunxi/platsmp.c69
-rw-r--r--arch/arm/mach-tegra/Makefile2
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra20.c5
-rw-r--r--arch/arm/mach-tegra/headsmp.S12
-rw-r--r--arch/arm/mach-tegra/reset-handler.S10
-rw-r--r--arch/arm/mach-tegra/reset.c2
-rw-r--r--arch/arm/mach-tegra/reset.h5
-rw-r--r--arch/arm/mach-tegra/sleep-tegra20.S37
-rw-r--r--arch/arm/mach-tegra/sleep-tegra30.S2
-rw-r--r--arch/arm/mach-tegra/sleep.h4
-rw-r--r--arch/arm/mach-tegra/tegra.c1
-rw-r--r--arch/arm/mach-uniphier/Kconfig11
-rw-r--r--arch/arm/mach-uniphier/Makefile2
-rw-r--r--arch/arm/mach-uniphier/platsmp.c90
-rw-r--r--arch/arm/mach-uniphier/uniphier.c (renamed from arch/ia64/kernel/paravirt_patchlist.h)28
-rw-r--r--arch/arm/mach-ux500/cache-l2x0.c11
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c60
-rw-r--r--arch/arm/mach-ux500/cpu.c20
-rw-r--r--arch/arm/mach-ux500/id.c2
-rw-r--r--arch/arm/mach-ux500/platsmp.c35
-rw-r--r--arch/arm/mach-ux500/pm.c15
-rw-r--r--arch/arm/mach-ux500/setup.h16
-rw-r--r--arch/arm/mach-versatile/core.c12
-rw-r--r--arch/arm/mach-zx/Kconfig18
-rw-r--r--arch/arm/mach-zx/Makefile2
-rw-r--r--arch/arm/mach-zx/core.h19
-rw-r--r--arch/arm/mach-zx/headsmp.S33
-rw-r--r--arch/arm/mach-zx/platsmp.c189
-rw-r--r--arch/arm/mach-zx/zx296702.c25
-rw-r--r--arch/arm/mach-zynq/common.c6
-rw-r--r--arch/arm/mach-zynq/common.h3
-rw-r--r--arch/arm/mach-zynq/headsmp.S5
-rw-r--r--arch/arm/mach-zynq/platsmp.c5
-rw-r--r--arch/arm/mach-zynq/slcr.c28
-rw-r--r--arch/arm/mm/Kconfig24
-rw-r--r--arch/arm/mm/Makefile3
-rw-r--r--arch/arm/mm/cache-l2x0.c107
-rw-r--r--arch/arm/mm/dma-mapping.c32
-rw-r--r--arch/arm/mm/fault.c2
-rw-r--r--arch/arm/mm/highmem.c3
-rw-r--r--arch/arm/mm/hugetlbpage.c5
-rw-r--r--arch/arm/mm/init.c1
-rw-r--r--arch/arm/mm/mmu.c153
-rw-r--r--arch/arm/mm/nommu.c9
-rw-r--r--arch/arm/mm/proc-v7-2level.S12
-rw-r--r--arch/arm/mm/proc-v7-3level.S14
-rw-r--r--arch/arm/mm/proc-v7.S184
-rw-r--r--arch/arm/mm/proc-v7m.S2
-rw-r--r--arch/arm/mm/pv-fixup-asm.S88
-rw-r--r--arch/arm/net/bpf_jit_32.c10
-rw-r--r--arch/arm/plat-omap/dma.c4
-rw-r--r--arch/arm/plat-orion/common.c6
-rw-r--r--arch/arm/plat-samsung/adc.c6
-rw-r--r--arch/arm/vdso/Makefile18
-rw-r--r--arch/arm/vfp/vfpmodule.c13
-rw-r--r--arch/arm64/Kconfig8
-rw-r--r--arch/arm64/boot/dts/Makefile1
-rw-r--r--arch/arm64/boot/dts/apm/apm-storm.dtsi110
-rw-r--r--arch/arm64/boot/dts/arm/Makefile2
-rw-r--r--arch/arm64/boot/dts/arm/juno-base.dtsi154
-rw-r--r--arch/arm64/boot/dts/arm/juno-clocks.dtsi4
-rw-r--r--arch/arm64/boot/dts/arm/juno-motherboard.dtsi129
-rw-r--r--arch/arm64/boot/dts/arm/juno-r1.dts116
-rw-r--r--arch/arm64/boot/dts/arm/juno.dts129
-rw-r--r--arch/arm64/boot/dts/hisilicon/Makefile5
-rw-r--r--arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts31
-rw-r--r--arch/arm64/boot/dts/hisilicon/hi6220.dtsi171
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8173.dtsi41
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc-pmic-pins.dtsi30
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi21
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi3
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi1
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916.dtsi25
-rw-r--r--arch/arm64/boot/dts/qcom/pm8916.dtsi99
-rw-r--r--arch/arm64/boot/dts/skeleton.dtsi13
-rw-r--r--arch/arm64/configs/defconfig9
-rw-r--r--arch/arm64/crypto/aes-ce-ccm-glue.c2
-rw-r--r--arch/arm64/include/asm/Kbuild1
-rw-r--r--arch/arm64/include/asm/acpi.h19
-rw-r--r--arch/arm64/include/asm/alternative-asm.h29
-rw-r--r--arch/arm64/include/asm/alternative.h46
-rw-r--r--arch/arm64/include/asm/barrier.h2
-rw-r--r--arch/arm64/include/asm/boot.h14
-rw-r--r--arch/arm64/include/asm/cacheflush.h5
-rw-r--r--arch/arm64/include/asm/cpu_ops.h27
-rw-r--r--arch/arm64/include/asm/cpufeature.h8
-rw-r--r--arch/arm64/include/asm/cpuidle.h8
-rw-r--r--arch/arm64/include/asm/dma-mapping.h18
-rw-r--r--arch/arm64/include/asm/fixmap.h15
-rw-r--r--arch/arm64/include/asm/futex.h4
-rw-r--r--arch/arm64/include/asm/hugetlb.h13
-rw-r--r--arch/arm64/include/asm/insn.h3
-rw-r--r--arch/arm64/include/asm/io.h9
-rw-r--r--arch/arm64/include/asm/kvm_asm.h7
-rw-r--r--arch/arm64/include/asm/kvm_host.h23
-rw-r--r--arch/arm64/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/arm64/include/asm/mmu.h1
-rw-r--r--arch/arm64/include/asm/perf_event.h7
-rw-r--r--arch/arm64/include/asm/proc-fns.h4
-rw-r--r--arch/arm64/include/asm/processor.h19
-rw-r--r--arch/arm64/include/asm/psci.h12
-rw-r--r--arch/arm64/include/asm/smp.h2
-rw-r--r--arch/arm64/include/asm/smp_plat.h16
-rw-r--r--arch/arm64/include/asm/suspend.h2
-rw-r--r--arch/arm64/include/asm/system_misc.h14
-rw-r--r--arch/arm64/include/asm/tlbflush.h2
-rw-r--r--arch/arm64/include/asm/topology.h2
-rw-r--r--arch/arm64/kernel/acpi.c123
-rw-r--r--arch/arm64/kernel/alternative.c71
-rw-r--r--arch/arm64/kernel/asm-offsets.c1
-rw-r--r--arch/arm64/kernel/cpu_ops.c72
-rw-r--r--arch/arm64/kernel/cpufeature.c16
-rw-r--r--arch/arm64/kernel/cpuidle.c11
-rw-r--r--arch/arm64/kernel/entry.S37
-rw-r--r--arch/arm64/kernel/fpsimd.c31
-rw-r--r--arch/arm64/kernel/head.S52
-rw-r--r--arch/arm64/kernel/insn.c60
-rw-r--r--arch/arm64/kernel/perf_event.c2
-rw-r--r--arch/arm64/kernel/process.c62
-rw-r--r--arch/arm64/kernel/psci.c244
-rw-r--r--arch/arm64/kernel/setup.c37
-rw-r--r--arch/arm64/kernel/signal32.c4
-rw-r--r--arch/arm64/kernel/sleep.S9
-rw-r--r--arch/arm64/kernel/smp.c246
-rw-r--r--arch/arm64/kernel/smp_spin_table.c8
-rw-r--r--arch/arm64/kernel/suspend.c9
-rw-r--r--arch/arm64/kernel/traps.c5
-rw-r--r--arch/arm64/kernel/vdso/Makefile4
-rw-r--r--arch/arm64/kernel/vmlinux.lds.S11
-rw-r--r--arch/arm64/kvm/Kconfig1
-rw-r--r--arch/arm64/kvm/Makefile2
-rw-r--r--arch/arm64/kvm/hyp.S26
-rw-r--r--arch/arm64/kvm/vgic-v2-switch.S3
-rw-r--r--arch/arm64/kvm/vgic-v3-switch.S2
-rw-r--r--arch/arm64/mm/Makefile2
-rw-r--r--arch/arm64/mm/cache.S75
-rw-r--r--arch/arm64/mm/context.c8
-rw-r--r--arch/arm64/mm/dma-mapping.c92
-rw-r--r--arch/arm64/mm/fault.c14
-rw-r--r--arch/arm64/mm/flush.c1
-rw-r--r--arch/arm64/mm/hugetlbpage.c7
-rw-r--r--arch/arm64/mm/init.c2
-rw-r--r--arch/arm64/mm/mmu.c66
-rw-r--r--arch/arm64/mm/proc.S46
-rw-r--r--arch/avr32/include/asm/Kbuild1
-rw-r--r--arch/avr32/include/asm/cmpxchg.h2
-rw-r--r--arch/avr32/include/asm/dma-mapping.h19
-rw-r--r--arch/avr32/include/asm/io.h1
-rw-r--r--arch/avr32/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/avr32/include/asm/uaccess.h12
-rw-r--r--arch/avr32/mm/fault.c4
-rw-r--r--arch/blackfin/include/asm/Kbuild1
-rw-r--r--arch/blackfin/include/asm/bfin_serial.h8
-rw-r--r--arch/blackfin/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/blackfin/include/asm/pci.h2
-rw-r--r--arch/c6x/include/asm/Kbuild1
-rw-r--r--arch/c6x/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/cris/include/asm/Kbuild1
-rw-r--r--arch/cris/include/asm/dma-mapping.h2
-rw-r--r--arch/cris/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/cris/include/asm/pci.h2
-rw-r--r--arch/cris/mm/fault.c6
-rw-r--r--arch/frv/include/asm/Kbuild1
-rw-r--r--arch/frv/include/asm/dma-mapping.h2
-rw-r--r--arch/frv/include/asm/io.h4
-rw-r--r--arch/frv/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/frv/include/asm/pci.h12
-rw-r--r--arch/frv/include/asm/sections.h6
-rw-r--r--arch/frv/mb93090-mb00/pci-dma-nommu.c10
-rw-r--r--arch/frv/mb93090-mb00/pci-dma.c7
-rw-r--r--arch/frv/mm/fault.c4
-rw-r--r--arch/frv/mm/highmem.c2
-rw-r--r--arch/h8300/Kconfig76
-rw-r--r--arch/h8300/Kconfig.cpu99
-rw-r--r--arch/h8300/Makefile55
-rw-r--r--arch/h8300/boot/Makefile26
-rw-r--r--arch/h8300/boot/compressed/Makefile37
-rw-r--r--arch/h8300/boot/compressed/head.S48
-rw-r--r--arch/h8300/boot/compressed/misc.c74
-rw-r--r--arch/h8300/boot/compressed/vmlinux.lds32
-rw-r--r--arch/h8300/boot/compressed/vmlinux.scr9
-rw-r--r--arch/h8300/boot/dts/Makefile12
-rw-r--r--arch/h8300/boot/dts/edosk2674.dts107
-rw-r--r--arch/h8300/boot/dts/h8300h_sim.dts96
-rw-r--r--arch/h8300/boot/dts/h8s_sim.dts99
-rw-r--r--arch/h8300/configs/edosk2674_defconfig49
-rw-r--r--arch/h8300/configs/h8300h-sim_defconfig49
-rw-r--r--arch/h8300/configs/h8s-sim_defconfig49
-rw-r--r--arch/h8300/include/asm/Kbuild75
-rw-r--r--arch/h8300/include/asm/atomic.h159
-rw-r--r--arch/h8300/include/asm/bitops.h185
-rw-r--r--arch/h8300/include/asm/bitsperlong.h14
-rw-r--r--arch/h8300/include/asm/bug.h12
-rw-r--r--arch/h8300/include/asm/byteorder.h7
-rw-r--r--arch/h8300/include/asm/cache.h11
-rw-r--r--arch/h8300/include/asm/cmpxchg.h65
-rw-r--r--arch/h8300/include/asm/dma-mapping.h57
-rw-r--r--arch/h8300/include/asm/elf.h101
-rw-r--r--arch/h8300/include/asm/flat.h28
-rw-r--r--arch/h8300/include/asm/io.h57
-rw-r--r--arch/h8300/include/asm/irq.h26
-rw-r--r--arch/h8300/include/asm/irqflags.h96
-rw-r--r--arch/h8300/include/asm/mc146818rtc.h9
-rw-r--r--arch/h8300/include/asm/mutex.h9
-rw-r--r--arch/h8300/include/asm/page.h18
-rw-r--r--arch/h8300/include/asm/page_offset.h2
-rw-r--r--arch/h8300/include/asm/pci.h19
-rw-r--r--arch/h8300/include/asm/pgtable.h49
-rw-r--r--arch/h8300/include/asm/processor.h144
-rw-r--r--arch/h8300/include/asm/ptrace.h36
-rw-r--r--arch/h8300/include/asm/segment.h45
-rw-r--r--arch/h8300/include/asm/signal.h22
-rw-r--r--arch/h8300/include/asm/smp.h1
-rw-r--r--arch/h8300/include/asm/string.h17
-rw-r--r--arch/h8300/include/asm/switch_to.h51
-rw-r--r--arch/h8300/include/asm/syscall.h56
-rw-r--r--arch/h8300/include/asm/thread_info.h111
-rw-r--r--arch/h8300/include/asm/tlb.h8
-rw-r--r--arch/h8300/include/asm/traps.h41
-rw-r--r--arch/h8300/include/asm/user.h74
-rw-r--r--arch/h8300/include/uapi/asm/Kbuild30
-rw-r--r--arch/h8300/include/uapi/asm/byteorder.h6
-rw-r--r--arch/h8300/include/uapi/asm/ptrace.h42
-rw-r--r--arch/h8300/include/uapi/asm/sigcontext.h18
-rw-r--r--arch/h8300/include/uapi/asm/signal.h115
-rw-r--r--arch/h8300/include/uapi/asm/unistd.h3
-rw-r--r--arch/h8300/kernel/Makefile19
-rw-r--r--arch/h8300/kernel/asm-offsets.c67
-rw-r--r--arch/h8300/kernel/dma.c69
-rw-r--r--arch/h8300/kernel/entry.S414
-rw-r--r--arch/h8300/kernel/h8300_ksyms.c36
-rw-r--r--arch/h8300/kernel/head_ram.S60
-rw-r--r--arch/h8300/kernel/head_rom.S110
-rw-r--r--arch/h8300/kernel/irq.c97
-rw-r--r--arch/h8300/kernel/module.c70
-rw-r--r--arch/h8300/kernel/process.c171
-rw-r--r--arch/h8300/kernel/ptrace.c203
-rw-r--r--arch/h8300/kernel/ptrace_h.c256
-rw-r--r--arch/h8300/kernel/ptrace_s.c44
-rw-r--r--arch/h8300/kernel/setup.c255
-rw-r--r--arch/h8300/kernel/signal.c289
-rw-r--r--arch/h8300/kernel/sim-console.c79
-rw-r--r--arch/h8300/kernel/syscalls.c14
-rw-r--r--arch/h8300/kernel/traps.c161
-rw-r--r--arch/h8300/kernel/vmlinux.lds.S67
-rw-r--r--arch/h8300/lib/Makefile8
-rw-r--r--arch/h8300/lib/abs.S20
-rw-r--r--arch/h8300/lib/ashldi3.c24
-rw-r--r--arch/h8300/lib/ashrdi3.c24
-rw-r--r--arch/h8300/lib/delay.c40
-rw-r--r--arch/h8300/lib/libgcc.h77
-rw-r--r--arch/h8300/lib/lshrdi3.c23
-rw-r--r--arch/h8300/lib/memcpy.S85
-rw-r--r--arch/h8300/lib/memset.S69
-rw-r--r--arch/h8300/lib/moddivsi3.S72
-rw-r--r--arch/h8300/lib/modsi3.S72
-rw-r--r--arch/h8300/lib/muldi3.c44
-rw-r--r--arch/h8300/lib/mulsi3.S38
-rw-r--r--arch/h8300/lib/strncpy.S34
-rw-r--r--arch/h8300/lib/ucmpdi2.c17
-rw-r--r--arch/h8300/lib/udivsi3.S76
-rw-r--r--arch/h8300/mm/Makefile5
-rw-r--r--arch/h8300/mm/fault.c57
-rw-r--r--arch/h8300/mm/init.c128
-rw-r--r--arch/h8300/mm/memory.c53
-rw-r--r--arch/hexagon/include/asm/Kbuild1
-rw-r--r--arch/hexagon/include/asm/cmpxchg.h1
-rw-r--r--arch/hexagon/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/hexagon/include/asm/uaccess.h3
-rw-r--r--arch/ia64/Kconfig23
-rw-r--r--arch/ia64/include/asm/Kbuild1
-rw-r--r--arch/ia64/include/asm/barrier.h7
-rw-r--r--arch/ia64/include/asm/hugetlb.h13
-rw-r--r--arch/ia64/include/asm/hw_irq.h8
-rw-r--r--arch/ia64/include/asm/intrinsics.h13
-rw-r--r--arch/ia64/include/asm/iosapic.h4
-rw-r--r--arch/ia64/include/asm/irq_remapping.h2
-rw-r--r--arch/ia64/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/ia64/include/asm/module.h6
-rw-r--r--arch/ia64/include/asm/native/inst.h103
-rw-r--r--arch/ia64/include/asm/native/pvchk_inst.h271
-rw-r--r--arch/ia64/include/asm/paravirt.h321
-rw-r--r--arch/ia64/include/asm/paravirt_patch.h143
-rw-r--r--arch/ia64/include/asm/paravirt_privop.h479
-rw-r--r--arch/ia64/include/asm/pci.h34
-rw-r--r--arch/ia64/include/asm/topology.h2
-rw-r--r--arch/ia64/include/uapi/asm/cmpxchg.h2
-rw-r--r--arch/ia64/kernel/Makefile34
-rw-r--r--arch/ia64/kernel/efi.c1
-rw-r--r--arch/ia64/kernel/entry.S41
-rw-r--r--arch/ia64/kernel/fsys.S18
-rw-r--r--arch/ia64/kernel/gate.S9
-rw-r--r--arch/ia64/kernel/gate.lds.S17
-rw-r--r--arch/ia64/kernel/head.S42
-rw-r--r--arch/ia64/kernel/ivt.S4
-rw-r--r--arch/ia64/kernel/minstate.h2
-rw-r--r--arch/ia64/kernel/module.c32
-rw-r--r--arch/ia64/kernel/msi_ia64.c30
-rw-r--r--arch/ia64/kernel/paravirt.c902
-rw-r--r--arch/ia64/kernel/paravirt_inst.h28
-rw-r--r--arch/ia64/kernel/paravirt_patch.c514
-rw-r--r--arch/ia64/kernel/paravirt_patchlist.c81
-rw-r--r--arch/ia64/kernel/paravirtentry.S121
-rw-r--r--arch/ia64/kernel/patch.c38
-rw-r--r--arch/ia64/kernel/setup.c12
-rw-r--r--arch/ia64/kernel/smpboot.c2
-rw-r--r--arch/ia64/kernel/time.c29
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S21
-rw-r--r--arch/ia64/mm/fault.c4
-rw-r--r--arch/ia64/mm/hugetlbpage.c5
-rw-r--r--arch/ia64/mm/init.c9
-rw-r--r--arch/ia64/scripts/pvcheck.sed33
-rw-r--r--arch/m32r/include/asm/Kbuild1
-rw-r--r--arch/m32r/include/asm/cmpxchg.h2
-rw-r--r--arch/m32r/include/asm/io.h1
-rw-r--r--arch/m32r/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/m32r/include/asm/uaccess.h30
-rw-r--r--arch/m32r/mm/fault.c8
-rw-r--r--arch/m68k/configs/amiga_defconfig8
-rw-r--r--arch/m68k/configs/apollo_defconfig8
-rw-r--r--arch/m68k/configs/atari_defconfig8
-rw-r--r--arch/m68k/configs/bvme6000_defconfig8
-rw-r--r--arch/m68k/configs/hp300_defconfig8
-rw-r--r--arch/m68k/configs/mac_defconfig8
-rw-r--r--arch/m68k/configs/multi_defconfig8
-rw-r--r--arch/m68k/configs/mvme147_defconfig8
-rw-r--r--arch/m68k/configs/mvme16x_defconfig8
-rw-r--r--arch/m68k/configs/q40_defconfig8
-rw-r--r--arch/m68k/configs/sun3_defconfig8
-rw-r--r--arch/m68k/configs/sun3x_defconfig8
-rw-r--r--arch/m68k/include/asm/Kbuild1
-rw-r--r--arch/m68k/include/asm/cmpxchg.h1
-rw-r--r--arch/m68k/include/asm/io_mm.h4
-rw-r--r--arch/m68k/include/asm/io_no.h4
-rw-r--r--arch/m68k/include/asm/irqflags.h3
-rw-r--r--arch/m68k/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/m68k/include/asm/serial.h2
-rw-r--r--arch/m68k/kernel/dma.c19
-rw-r--r--arch/m68k/mm/fault.c4
-rw-r--r--arch/metag/include/asm/Kbuild1
-rw-r--r--arch/metag/include/asm/barrier.h2
-rw-r--r--arch/metag/include/asm/cmpxchg.h2
-rw-r--r--arch/metag/include/asm/dma-mapping.h14
-rw-r--r--arch/metag/include/asm/hugetlb.h13
-rw-r--r--arch/metag/include/asm/io.h3
-rw-r--r--arch/metag/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/metag/mm/fault.c2
-rw-r--r--arch/metag/mm/highmem.c4
-rw-r--r--arch/metag/mm/hugetlbpage.c5
-rw-r--r--arch/microblaze/include/asm/Kbuild1
-rw-r--r--arch/microblaze/include/asm/io.h2
-rw-r--r--arch/microblaze/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/microblaze/include/asm/pci.h42
-rw-r--r--arch/microblaze/include/asm/uaccess.h6
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo.c2
-rw-r--r--arch/microblaze/kernel/dma.c1
-rw-r--r--arch/microblaze/kernel/kgdb.c2
-rw-r--r--arch/microblaze/mm/fault.c8
-rw-r--r--arch/microblaze/mm/highmem.c4
-rw-r--r--arch/mips/Kconfig1
-rw-r--r--arch/mips/cavium-octeon/crypto/octeon-md5.c8
-rw-r--r--arch/mips/include/asm/Kbuild1
-rw-r--r--arch/mips/include/asm/barrier.h4
-rw-r--r--arch/mips/include/asm/cmpxchg.h2
-rw-r--r--arch/mips/include/asm/dma-mapping.h2
-rw-r--r--arch/mips/include/asm/edac.h4
-rw-r--r--arch/mips/include/asm/hugetlb.h13
-rw-r--r--arch/mips/include/asm/kvm_host.h2
-rw-r--r--arch/mips/include/asm/mach-ath79/ath79_spi_platform.h4
-rw-r--r--arch/mips/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/mips/include/asm/pci.h12
-rw-r--r--arch/mips/include/asm/pgtable.h8
-rw-r--r--arch/mips/include/asm/topology.h2
-rw-r--r--arch/mips/include/asm/uaccess.h45
-rw-r--r--arch/mips/kernel/signal-common.h9
-rw-r--r--arch/mips/kvm/mips.c13
-rw-r--r--arch/mips/mm/fault.c4
-rw-r--r--arch/mips/mm/highmem.c5
-rw-r--r--arch/mips/mm/hugetlbpage.c5
-rw-r--r--arch/mips/mm/init.c2
-rw-r--r--arch/mips/pci/fixup-cobalt.c1
-rw-r--r--arch/mips/pci/ops-mace.c1
-rw-r--r--arch/mips/pci/pci-lantiq.c1
-rw-r--r--arch/mn10300/include/asm/Kbuild1
-rw-r--r--arch/mn10300/include/asm/highmem.h3
-rw-r--r--arch/mn10300/include/asm/io.h1
-rw-r--r--arch/mn10300/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/mn10300/include/asm/pci.h15
-rw-r--r--arch/mn10300/include/asm/serial.h4
-rw-r--r--arch/mn10300/mm/fault.c4
-rw-r--r--arch/nios2/include/asm/Kbuild1
-rw-r--r--arch/nios2/include/asm/io.h1
-rw-r--r--arch/nios2/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/nios2/kernel/time.c2
-rw-r--r--arch/nios2/mm/fault.c2
-rw-r--r--arch/openrisc/include/asm/Kbuild1
-rw-r--r--arch/openrisc/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/parisc/include/asm/Kbuild1
-rw-r--r--arch/parisc/include/asm/cacheflush.h2
-rw-r--r--arch/parisc/include/asm/cmpxchg.h2
-rw-r--r--arch/parisc/include/asm/dma-mapping.h2
-rw-r--r--arch/parisc/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/parisc/include/asm/pci.h21
-rw-r--r--arch/parisc/kernel/pci-dma.c27
-rw-r--r--arch/parisc/kernel/traps.c4
-rw-r--r--arch/parisc/mm/fault.c4
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--arch/powerpc/Kconfig.debug8
-rw-r--r--arch/powerpc/Makefile50
-rw-r--r--arch/powerpc/boot/dts/b4qds.dtsi12
-rw-r--r--arch/powerpc/boot/dts/fsl/b4420si-post.dtsi15
-rw-r--r--arch/powerpc/boot/dts/fsl/b4860si-post.dtsi84
-rw-r--r--arch/powerpc/boot/dts/fsl/b4si-post.dtsi118
-rw-r--r--arch/powerpc/boot/dts/fsl/p1023si-post.dtsi43
-rw-r--r--arch/powerpc/boot/dts/fsl/p2041si-post.dtsi14
-rw-r--r--arch/powerpc/boot/dts/fsl/p3041si-post.dtsi14
-rw-r--r--arch/powerpc/boot/dts/fsl/p4080si-post.dtsi14
-rw-r--r--arch/powerpc/boot/dts/fsl/p5020si-post.dtsi14
-rw-r--r--arch/powerpc/boot/dts/fsl/p5040si-post.dtsi14
-rw-r--r--arch/powerpc/boot/dts/fsl/qoriq-qman1-portals.dtsi20
-rw-r--r--arch/powerpc/boot/dts/fsl/t1023si-post.dtsi330
-rw-r--r--arch/powerpc/boot/dts/fsl/t1024si-post.dtsi100
-rw-r--r--arch/powerpc/boot/dts/fsl/t102xsi-pre.dtsi87
-rw-r--r--arch/powerpc/boot/dts/fsl/t1040si-post.dtsi78
-rw-r--r--arch/powerpc/boot/dts/fsl/t2081si-post.dtsi130
-rw-r--r--arch/powerpc/boot/dts/fsl/t4240si-post.dtsi318
-rw-r--r--arch/powerpc/boot/dts/kmcoge4.dts12
-rw-r--r--arch/powerpc/boot/dts/oca4080.dts12
-rw-r--r--arch/powerpc/boot/dts/p1023rdb.dts12
-rw-r--r--arch/powerpc/boot/dts/p2041rdb.dts12
-rw-r--r--arch/powerpc/boot/dts/p3041ds.dts12
-rw-r--r--arch/powerpc/boot/dts/p4080ds.dts12
-rw-r--r--arch/powerpc/boot/dts/p5020ds.dts12
-rw-r--r--arch/powerpc/boot/dts/p5040ds.dts12
-rw-r--r--arch/powerpc/boot/dts/t1023rdb.dts151
-rw-r--r--arch/powerpc/boot/dts/t1024qds.dts251
-rw-r--r--arch/powerpc/boot/dts/t1024rdb.dts185
-rw-r--r--arch/powerpc/boot/dts/t104xqds.dtsi12
-rw-r--r--arch/powerpc/boot/dts/t104xrdb.dtsi12
-rw-r--r--arch/powerpc/boot/dts/t208xqds.dtsi12
-rw-r--r--arch/powerpc/boot/dts/t208xrdb.dtsi12
-rw-r--r--arch/powerpc/boot/dts/t4240qds.dts12
-rw-r--r--arch/powerpc/boot/dts/t4240rdb.dts12
-rw-r--r--arch/powerpc/configs/85xx/xes_mpc85xx_defconfig2
-rw-r--r--arch/powerpc/configs/le.config1
-rw-r--r--arch/powerpc/configs/ppc64_defconfig1
-rw-r--r--arch/powerpc/configs/pseries_defconfig2
-rw-r--r--arch/powerpc/configs/pseries_le_defconfig319
-rw-r--r--arch/powerpc/crypto/md5-glue.c8
-rw-r--r--arch/powerpc/include/asm/Kbuild1
-rw-r--r--arch/powerpc/include/asm/barrier.h3
-rw-r--r--arch/powerpc/include/asm/cmpxchg.h1
-rw-r--r--arch/powerpc/include/asm/cputable.h12
-rw-r--r--arch/powerpc/include/asm/cputhreads.h13
-rw-r--r--arch/powerpc/include/asm/device.h3
-rw-r--r--arch/powerpc/include/asm/edac.h4
-rw-r--r--arch/powerpc/include/asm/eeh.h9
-rw-r--r--arch/powerpc/include/asm/hugetlb.h14
-rw-r--r--arch/powerpc/include/asm/icswx.h184
-rw-r--r--arch/powerpc/include/asm/iommu.h119
-rw-r--r--arch/powerpc/include/asm/kvm_book3s_64.h2
-rw-r--r--arch/powerpc/include/asm/kvm_host.h2
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h14
-rw-r--r--arch/powerpc/include/asm/machdep.h31
-rw-r--r--arch/powerpc/include/asm/mm-arch-hooks.h28
-rw-r--r--arch/powerpc/include/asm/mmu-8xx.h33
-rw-r--r--arch/powerpc/include/asm/mmu-hash64.h3
-rw-r--r--arch/powerpc/include/asm/mmu_context.h41
-rw-r--r--arch/powerpc/include/asm/opal-api.h28
-rw-r--r--arch/powerpc/include/asm/opal.h8
-rw-r--r--arch/powerpc/include/asm/page.h4
-rw-r--r--arch/powerpc/include/asm/pci-bridge.h16
-rw-r--r--arch/powerpc/include/asm/pci.h32
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc32.h19
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc64.h42
-rw-r--r--arch/powerpc/include/asm/pnv-pci.h2
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h13
-rw-r--r--arch/powerpc/include/asm/processor.h9
-rw-r--r--arch/powerpc/include/asm/pte-8xx.h31
-rw-r--r--arch/powerpc/include/asm/pte-book3e.h1
-rw-r--r--arch/powerpc/include/asm/pte-common.h2
-rw-r--r--arch/powerpc/include/asm/pte-hash64.h1
-rw-r--r--arch/powerpc/include/asm/systbl.h2
-rw-r--r--arch/powerpc/include/asm/topology.h2
-rw-r--r--arch/powerpc/include/asm/trace.h20
-rw-r--r--arch/powerpc/include/asm/uaccess.h8
-rw-r--r--arch/powerpc/include/asm/vio.h2
-rw-r--r--arch/powerpc/include/uapi/asm/Kbuild1
-rw-r--r--arch/powerpc/include/uapi/asm/cputable.h1
-rw-r--r--arch/powerpc/include/uapi/asm/eeh.h56
-rw-r--r--arch/powerpc/include/uapi/asm/opal-prd.h58
-rw-r--r--arch/powerpc/include/uapi/asm/tm.h2
-rw-r--r--arch/powerpc/kernel/Makefile3
-rw-r--r--arch/powerpc/kernel/asm-offsets.c2
-rw-r--r--arch/powerpc/kernel/cputable.c4
-rw-r--r--arch/powerpc/kernel/dma.c8
-rw-r--r--arch/powerpc/kernel/eeh.c43
-rw-r--r--arch/powerpc/kernel/eeh_cache.c16
-rw-r--r--arch/powerpc/kernel/eeh_driver.c2
-rw-r--r--arch/powerpc/kernel/entry_64.S37
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S16
-rw-r--r--arch/powerpc/kernel/head_8xx.S110
-rw-r--r--arch/powerpc/kernel/idle_e500.S9
-rw-r--r--arch/powerpc/kernel/iommu.c245
-rw-r--r--arch/powerpc/kernel/msi.c11
-rw-r--r--arch/powerpc/kernel/pci-common.c11
-rw-r--r--arch/powerpc/kernel/pci-hotplug.c5
-rw-r--r--arch/powerpc/kernel/process.c1
-rw-r--r--arch/powerpc/kernel/prom.c3
-rw-r--r--arch/powerpc/kernel/prom_init.c1
-rw-r--r--arch/powerpc/kernel/setup_64.c6
-rw-r--r--arch/powerpc/kernel/sysfs.c38
-rw-r--r--arch/powerpc/kernel/tm.S4
-rw-r--r--arch/powerpc/kernel/traps.c45
-rw-r--r--arch/powerpc/kernel/vdso.c135
-rw-r--r--arch/powerpc/kernel/vio.c15
-rw-r--r--arch/powerpc/kvm/book3s.c9
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_hv.c2
-rw-r--r--arch/powerpc/kvm/book3s_hv.c15
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S2
-rw-r--r--arch/powerpc/kvm/book3s_pr.c11
-rw-r--r--arch/powerpc/kvm/booke.c13
-rw-r--r--arch/powerpc/kvm/powerpc.c9
-rw-r--r--arch/powerpc/lib/Makefile2
-rw-r--r--arch/powerpc/lib/vmx-helper.c11
-rw-r--r--arch/powerpc/mm/Makefile1
-rw-r--r--arch/powerpc/mm/copro_fault.c9
-rw-r--r--arch/powerpc/mm/fault.c9
-rw-r--r--arch/powerpc/mm/hash_native_64.c2
-rw-r--r--arch/powerpc/mm/hash_utils_64.c4
-rw-r--r--arch/powerpc/mm/highmem.c4
-rw-r--r--arch/powerpc/mm/hugetlbpage.c9
-rw-r--r--arch/powerpc/mm/mem.c2
-rw-r--r--arch/powerpc/mm/mmu_context_hash64.c6
-rw-r--r--arch/powerpc/mm/mmu_context_iommu.c316
-rw-r--r--arch/powerpc/mm/pgtable_64.c73
-rw-r--r--arch/powerpc/mm/tlb_low_64e.S51
-rw-r--r--arch/powerpc/mm/tlb_nohash.c2
-rw-r--r--arch/powerpc/perf/core-book3s.c11
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_gpt.c2
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pci.c2
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig2
-rw-r--r--arch/powerpc/platforms/85xx/corenet_generic.c3
-rw-r--r--arch/powerpc/platforms/85xx/smp.c51
-rw-r--r--arch/powerpc/platforms/85xx/twr_p102x.c4
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype11
-rw-r--r--arch/powerpc/platforms/cell/axon_msi.c7
-rw-r--r--arch/powerpc/platforms/cell/iommu.c8
-rw-r--r--arch/powerpc/platforms/embedded6xx/hlwd-pic.c2
-rw-r--r--arch/powerpc/platforms/pasemi/Makefile1
-rw-r--r--arch/powerpc/platforms/pasemi/iommu.c7
-rw-r--r--arch/powerpc/platforms/pasemi/msi.c (renamed from arch/powerpc/sysdev/mpic_pasemi_msi.c)13
-rw-r--r--arch/powerpc/platforms/powernv/Kconfig7
-rw-r--r--arch/powerpc/platforms/powernv/Makefile5
-rw-r--r--arch/powerpc/platforms/powernv/eeh-powernv.c62
-rw-r--r--arch/powerpc/platforms/powernv/idle.c293
-rw-r--r--arch/powerpc/platforms/powernv/opal-async.c3
-rw-r--r--arch/powerpc/platforms/powernv/opal-dump.c56
-rw-r--r--arch/powerpc/platforms/powernv/opal-elog.c32
-rw-r--r--arch/powerpc/platforms/powernv/opal-hmi.c3
-rw-r--r--arch/powerpc/platforms/powernv/opal-irqchip.c253
-rw-r--r--arch/powerpc/platforms/powernv/opal-memory-errors.c2
-rw-r--r--arch/powerpc/platforms/powernv/opal-prd.c449
-rw-r--r--arch/powerpc/platforms/powernv/opal-sensor.c3
-rw-r--r--arch/powerpc/platforms/powernv/opal-sysparam.c43
-rw-r--r--arch/powerpc/platforms/powernv/opal-wrappers.S2
-rw-r--r--arch/powerpc/platforms/powernv/opal.c221
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c790
-rw-r--r--arch/powerpc/platforms/powernv/pci-p5ioc2.c45
-rw-r--r--arch/powerpc/platforms/powernv/pci.c204
-rw-r--r--arch/powerpc/platforms/powernv/pci.h31
-rw-r--r--arch/powerpc/platforms/powernv/powernv.h11
-rw-r--r--arch/powerpc/platforms/powernv/setup.c181
-rw-r--r--arch/powerpc/platforms/pseries/dlpar.c3
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pseries.c2
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c179
-rw-r--r--arch/powerpc/platforms/pseries/msi.c16
-rw-r--r--arch/powerpc/sysdev/Makefile2
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c12
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c23
-rw-r--r--arch/powerpc/sysdev/i8259.c2
-rw-r--r--arch/powerpc/sysdev/ipic.c2
-rw-r--r--arch/powerpc/sysdev/mpc8xx_pic.c2
-rw-r--r--arch/powerpc/sysdev/mpic.c2
-rw-r--r--arch/powerpc/sysdev/mpic.h10
-rw-r--r--arch/powerpc/sysdev/mpic_u3msi.c9
-rw-r--r--arch/powerpc/sysdev/mv64x60_pic.c2
-rw-r--r--arch/powerpc/sysdev/ppc4xx_hsta_msi.c7
-rw-r--r--arch/powerpc/sysdev/ppc4xx_msi.c7
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_ic.c2
-rw-r--r--arch/powerpc/sysdev/tsi108_pci.c2
-rw-r--r--arch/powerpc/sysdev/uic.c4
-rw-r--r--arch/powerpc/sysdev/xics/icp-native.c14
-rw-r--r--arch/powerpc/sysdev/xics/xics-common.c4
-rw-r--r--arch/powerpc/sysdev/xilinx_intc.c2
-rw-r--r--arch/s390/hypfs/hypfs_sprp.c4
-rw-r--r--arch/s390/include/asm/Kbuild1
-rw-r--r--arch/s390/include/asm/barrier.h2
-rw-r--r--arch/s390/include/asm/cmpxchg.h2
-rw-r--r--arch/s390/include/asm/hugetlb.h4
-rw-r--r--arch/s390/include/asm/io.h1
-rw-r--r--arch/s390/include/asm/kvm_host.h6
-rw-r--r--arch/s390/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/s390/include/asm/page.h8
-rw-r--r--arch/s390/include/asm/pgtable.h34
-rw-r--r--arch/s390/include/asm/sclp.h34
-rw-r--r--arch/s390/include/asm/timex.h5
-rw-r--r--arch/s390/include/asm/topology.h3
-rw-r--r--arch/s390/include/asm/uaccess.h15
-rw-r--r--arch/s390/kernel/compat_wrapper.c2
-rw-r--r--arch/s390/kernel/crash_dump.c13
-rw-r--r--arch/s390/kernel/debug.c11
-rw-r--r--arch/s390/kernel/entry.S2
-rw-r--r--arch/s390/kernel/setup.c25
-rw-r--r--arch/s390/kernel/smp.c13
-rw-r--r--arch/s390/kernel/suspend.c2
-rw-r--r--arch/s390/kernel/time.c6
-rw-r--r--arch/s390/kvm/intercept.c16
-rw-r--r--arch/s390/kvm/interrupt.c94
-rw-r--r--arch/s390/kvm/kvm-s390.c89
-rw-r--r--arch/s390/kvm/kvm-s390.h25
-rw-r--r--arch/s390/kvm/priv.c8
-rw-r--r--arch/s390/mm/fault.c2
-rw-r--r--arch/s390/mm/hugetlbpage.c70
-rw-r--r--arch/s390/mm/init.c2
-rw-r--r--arch/s390/mm/mem_detect.c4
-rw-r--r--arch/s390/mm/pgtable.c2
-rw-r--r--arch/s390/net/bpf_jit.h10
-rw-r--r--arch/s390/net/bpf_jit_comp.c106
-rw-r--r--arch/s390/pci/pci_event.c8
-rw-r--r--arch/score/include/asm/Kbuild1
-rw-r--r--arch/score/include/asm/cmpxchg.h2
-rw-r--r--arch/score/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/score/include/asm/uaccess.h15
-rw-r--r--arch/score/mm/fault.c3
-rw-r--r--arch/sh/drivers/pci/ops-sh5.c1
-rw-r--r--arch/sh/drivers/pci/pci-sh5.c1
-rw-r--r--arch/sh/include/asm/Kbuild1
-rw-r--r--arch/sh/include/asm/barrier.h2
-rw-r--r--arch/sh/include/asm/cmpxchg.h2
-rw-r--r--arch/sh/include/asm/hugetlb.h12
-rw-r--r--arch/sh/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/sh/include/asm/pci.h18
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7734.c3
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7757.c4
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7785.c4
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7786.c4
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-shx3.c4
-rw-r--r--arch/sh/mm/fault.c5
-rw-r--r--arch/sh/mm/hugetlbpage.c5
-rw-r--r--arch/sparc/Kconfig2
-rw-r--r--arch/sparc/crypto/md5_glue.c8
-rw-r--r--arch/sparc/include/asm/Kbuild1
-rw-r--r--arch/sparc/include/asm/barrier_64.h4
-rw-r--r--arch/sparc/include/asm/cmpxchg_32.h1
-rw-r--r--arch/sparc/include/asm/cmpxchg_64.h2
-rw-r--r--arch/sparc/include/asm/hugetlb.h13
-rw-r--r--arch/sparc/include/asm/io_32.h1
-rw-r--r--arch/sparc/include/asm/io_64.h1
-rw-r--r--arch/sparc/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/sparc/include/asm/pci_32.h10
-rw-r--r--arch/sparc/include/asm/pci_64.h19
-rw-r--r--arch/sparc/include/asm/pgtable_64.h8
-rw-r--r--arch/sparc/include/asm/topology_64.h2
-rw-r--r--arch/sparc/include/asm/uaccess_64.h22
-rw-r--r--arch/sparc/kernel/iommu_common.h2
-rw-r--r--arch/sparc/kernel/ldc.c8
-rw-r--r--arch/sparc/kernel/perf_event.c24
-rw-r--r--arch/sparc/kernel/time_32.c21
-rw-r--r--arch/sparc/kernel/time_64.c14
-rw-r--r--arch/sparc/mm/fault_32.c4
-rw-r--r--arch/sparc/mm/fault_64.c9
-rw-r--r--arch/sparc/mm/highmem.c4
-rw-r--r--arch/sparc/mm/hugetlbpage.c5
-rw-r--r--arch/sparc/mm/init_64.c8
-rw-r--r--arch/tile/Kconfig1
-rw-r--r--arch/tile/include/asm/Kbuild1
-rw-r--r--arch/tile/include/asm/atomic_64.h3
-rw-r--r--arch/tile/include/asm/edac.h29
-rw-r--r--arch/tile/include/asm/hugetlb.h13
-rw-r--r--arch/tile/include/asm/io.h2
-rw-r--r--arch/tile/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/tile/include/asm/pgtable.h8
-rw-r--r--arch/tile/include/asm/topology.h2
-rw-r--r--arch/tile/include/asm/uaccess.h18
-rw-r--r--arch/tile/mm/fault.c4
-rw-r--r--arch/tile/mm/highmem.c3
-rw-r--r--arch/tile/mm/hugetlbpage.c5
-rw-r--r--arch/um/include/asm/Kbuild1
-rw-r--r--arch/um/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/um/kernel/trap.c5
-rw-r--r--arch/um/os-Linux/drivers/ethertap_user.c2
-rw-r--r--arch/unicore32/include/asm/Kbuild1
-rw-r--r--arch/unicore32/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/unicore32/include/asm/pci.h10
-rw-r--r--arch/unicore32/mm/fault.c2
-rw-r--r--arch/x86/Kbuild5
-rw-r--r--arch/x86/Kconfig259
-rw-r--r--arch/x86/Kconfig.debug23
-rw-r--r--arch/x86/Makefile23
-rw-r--r--arch/x86/crypto/aesni-intel_glue.c425
-rw-r--r--arch/x86/crypto/camellia_aesni_avx2_glue.c10
-rw-r--r--arch/x86/crypto/camellia_aesni_avx_glue.c15
-rw-r--r--arch/x86/crypto/cast5_avx_glue.c15
-rw-r--r--arch/x86/crypto/cast6_avx_glue.c15
-rw-r--r--arch/x86/crypto/crc32-pclmul_glue.c2
-rw-r--r--arch/x86/crypto/crc32c-intel_glue.c3
-rw-r--r--arch/x86/crypto/crct10dif-pclmul_glue.c2
-rw-r--r--arch/x86/crypto/fpu.c4
-rw-r--r--arch/x86/crypto/ghash-clmulni-intel_glue.c2
-rw-r--r--arch/x86/crypto/serpent_avx2_glue.c11
-rw-r--r--arch/x86/crypto/serpent_avx_glue.c15
-rw-r--r--arch/x86/crypto/sha-mb/sha1_mb.c8
-rw-r--r--arch/x86/crypto/sha1_ssse3_glue.c16
-rw-r--r--arch/x86/crypto/sha256_ssse3_glue.c16
-rw-r--r--arch/x86/crypto/sha512_ssse3_glue.c16
-rw-r--r--arch/x86/crypto/twofish_avx_glue.c16
-rw-r--r--arch/x86/entry/Makefile10
-rw-r--r--arch/x86/entry/calling.h (renamed from arch/x86/include/asm/calling.h)98
-rw-r--r--arch/x86/entry/entry_32.S1248
-rw-r--r--arch/x86/entry/entry_64.S (renamed from arch/x86/kernel/entry_64.S)1125
-rw-r--r--arch/x86/entry/entry_64_compat.S556
-rw-r--r--arch/x86/entry/syscall_32.c (renamed from arch/x86/kernel/syscall_32.c)6
-rw-r--r--arch/x86/entry/syscall_64.c (renamed from arch/x86/kernel/syscall_64.c)0
-rw-r--r--arch/x86/entry/syscalls/Makefile (renamed from arch/x86/syscalls/Makefile)4
-rw-r--r--arch/x86/entry/syscalls/syscall_32.tbl (renamed from arch/x86/syscalls/syscall_32.tbl)0
-rw-r--r--arch/x86/entry/syscalls/syscall_64.tbl (renamed from arch/x86/syscalls/syscall_64.tbl)0
-rw-r--r--arch/x86/entry/syscalls/syscallhdr.sh (renamed from arch/x86/syscalls/syscallhdr.sh)0
-rw-r--r--arch/x86/entry/syscalls/syscalltbl.sh (renamed from arch/x86/syscalls/syscalltbl.sh)0
-rw-r--r--arch/x86/entry/thunk_32.S (renamed from arch/x86/lib/thunk_32.S)19
-rw-r--r--arch/x86/entry/thunk_64.S (renamed from arch/x86/lib/thunk_64.S)50
-rw-r--r--arch/x86/entry/vdso/.gitignore (renamed from arch/x86/vdso/.gitignore)0
-rw-r--r--arch/x86/entry/vdso/Makefile (renamed from arch/x86/vdso/Makefile)0
-rwxr-xr-xarch/x86/entry/vdso/checkundef.sh (renamed from arch/x86/vdso/checkundef.sh)0
-rw-r--r--arch/x86/entry/vdso/vclock_gettime.c (renamed from arch/x86/vdso/vclock_gettime.c)0
-rw-r--r--arch/x86/entry/vdso/vdso-layout.lds.S (renamed from arch/x86/vdso/vdso-layout.lds.S)0
-rw-r--r--arch/x86/entry/vdso/vdso-note.S (renamed from arch/x86/vdso/vdso-note.S)0
-rw-r--r--arch/x86/entry/vdso/vdso.lds.S (renamed from arch/x86/vdso/vdso.lds.S)0
-rw-r--r--arch/x86/entry/vdso/vdso2c.c (renamed from arch/x86/vdso/vdso2c.c)0
-rw-r--r--arch/x86/entry/vdso/vdso2c.h (renamed from arch/x86/vdso/vdso2c.h)0
-rw-r--r--arch/x86/entry/vdso/vdso32-setup.c (renamed from arch/x86/vdso/vdso32-setup.c)0
-rw-r--r--arch/x86/entry/vdso/vdso32/.gitignore (renamed from arch/x86/vdso/vdso32/.gitignore)0
-rw-r--r--arch/x86/entry/vdso/vdso32/int80.S (renamed from arch/x86/vdso/vdso32/int80.S)0
-rw-r--r--arch/x86/entry/vdso/vdso32/note.S (renamed from arch/x86/vdso/vdso32/note.S)0
-rw-r--r--arch/x86/entry/vdso/vdso32/sigreturn.S (renamed from arch/x86/vdso/vdso32/sigreturn.S)0
-rw-r--r--arch/x86/entry/vdso/vdso32/syscall.S (renamed from arch/x86/vdso/vdso32/syscall.S)0
-rw-r--r--arch/x86/entry/vdso/vdso32/sysenter.S (renamed from arch/x86/vdso/vdso32/sysenter.S)0
-rw-r--r--arch/x86/entry/vdso/vdso32/vclock_gettime.c (renamed from arch/x86/vdso/vdso32/vclock_gettime.c)0
-rw-r--r--arch/x86/entry/vdso/vdso32/vdso-fakesections.c (renamed from arch/x86/vdso/vdso32/vdso-fakesections.c)0
-rw-r--r--arch/x86/entry/vdso/vdso32/vdso32.lds.S (renamed from arch/x86/vdso/vdso32/vdso32.lds.S)0
-rw-r--r--arch/x86/entry/vdso/vdsox32.lds.S (renamed from arch/x86/vdso/vdsox32.lds.S)0
-rw-r--r--arch/x86/entry/vdso/vgetcpu.c (renamed from arch/x86/vdso/vgetcpu.c)0
-rw-r--r--arch/x86/entry/vdso/vma.c (renamed from arch/x86/vdso/vma.c)0
-rw-r--r--arch/x86/entry/vsyscall/Makefile7
-rw-r--r--arch/x86/entry/vsyscall/vsyscall_64.c (renamed from arch/x86/kernel/vsyscall_64.c)0
-rw-r--r--arch/x86/entry/vsyscall/vsyscall_emu_64.S (renamed from arch/x86/kernel/vsyscall_emu_64.S)0
-rw-r--r--arch/x86/entry/vsyscall/vsyscall_gtod.c (renamed from arch/x86/kernel/vsyscall_gtod.c)0
-rw-r--r--arch/x86/entry/vsyscall/vsyscall_trace.h (renamed from arch/x86/kernel/vsyscall_trace.h)2
-rw-r--r--arch/x86/ia32/Makefile2
-rw-r--r--arch/x86/ia32/ia32_signal.c13
-rw-r--r--arch/x86/ia32/ia32entry.S611
-rw-r--r--arch/x86/include/asm/Kbuild1
-rw-r--r--arch/x86/include/asm/alternative-asm.h18
-rw-r--r--arch/x86/include/asm/alternative.h6
-rw-r--r--arch/x86/include/asm/amd_nb.h11
-rw-r--r--arch/x86/include/asm/apic.h6
-rw-r--r--arch/x86/include/asm/asm.h25
-rw-r--r--arch/x86/include/asm/atomic.h30
-rw-r--r--arch/x86/include/asm/atomic64_64.h8
-rw-r--r--arch/x86/include/asm/barrier.h4
-rw-r--r--arch/x86/include/asm/cacheflush.h6
-rw-r--r--arch/x86/include/asm/cmpxchg.h2
-rw-r--r--arch/x86/include/asm/crypto/glue_helper.h2
-rw-r--r--arch/x86/include/asm/dma-mapping.h46
-rw-r--r--arch/x86/include/asm/dwarf2.h170
-rw-r--r--arch/x86/include/asm/edac.h2
-rw-r--r--arch/x86/include/asm/efi.h2
-rw-r--r--arch/x86/include/asm/entry_arch.h5
-rw-r--r--arch/x86/include/asm/fpu-internal.h626
-rw-r--r--arch/x86/include/asm/fpu/api.h48
-rw-r--r--arch/x86/include/asm/fpu/internal.h694
-rw-r--r--arch/x86/include/asm/fpu/regset.h21
-rw-r--r--arch/x86/include/asm/fpu/signal.h33
-rw-r--r--arch/x86/include/asm/fpu/types.h293
-rw-r--r--arch/x86/include/asm/fpu/xstate.h46
-rw-r--r--arch/x86/include/asm/frame.h7
-rw-r--r--arch/x86/include/asm/hardirq.h4
-rw-r--r--arch/x86/include/asm/hpet.h16
-rw-r--r--arch/x86/include/asm/hugetlb.h12
-rw-r--r--arch/x86/include/asm/hw_irq.h140
-rw-r--r--arch/x86/include/asm/i387.h108
-rw-r--r--arch/x86/include/asm/io.h9
-rw-r--r--arch/x86/include/asm/io_apic.h114
-rw-r--r--arch/x86/include/asm/irq.h4
-rw-r--r--arch/x86/include/asm/irq_remapping.h80
-rw-r--r--arch/x86/include/asm/irq_vectors.h51
-rw-r--r--arch/x86/include/asm/irqdomain.h63
-rw-r--r--arch/x86/include/asm/kvm_emulate.h9
-rw-r--r--arch/x86/include/asm/kvm_host.h94
-rw-r--r--arch/x86/include/asm/livepatch.h1
-rw-r--r--arch/x86/include/asm/mce.h28
-rw-r--r--arch/x86/include/asm/microcode.h8
-rw-r--r--arch/x86/include/asm/microcode_amd.h4
-rw-r--r--arch/x86/include/asm/microcode_intel.h13
-rw-r--r--arch/x86/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/x86/include/asm/mmu_context.h13
-rw-r--r--arch/x86/include/asm/mpx.h74
-rw-r--r--arch/x86/include/asm/msi.h7
-rw-r--r--arch/x86/include/asm/msr-index.h (renamed from arch/x86/include/uapi/asm/msr-index.h)2
-rw-r--r--arch/x86/include/asm/msr.h12
-rw-r--r--arch/x86/include/asm/mtrr.h15
-rw-r--r--arch/x86/include/asm/paravirt.h29
-rw-r--r--arch/x86/include/asm/paravirt_types.h17
-rw-r--r--arch/x86/include/asm/pat.h9
-rw-r--r--arch/x86/include/asm/pci.h14
-rw-r--r--arch/x86/include/asm/pgtable.h12
-rw-r--r--arch/x86/include/asm/pgtable_types.h3
-rw-r--r--arch/x86/include/asm/preempt.h8
-rw-r--r--arch/x86/include/asm/processor.h161
-rw-r--r--arch/x86/include/asm/proto.h10
-rw-r--r--arch/x86/include/asm/pvclock-abi.h1
-rw-r--r--arch/x86/include/asm/pvclock.h1
-rw-r--r--arch/x86/include/asm/qspinlock.h57
-rw-r--r--arch/x86/include/asm/qspinlock_paravirt.h6
-rw-r--r--arch/x86/include/asm/serial.h2
-rw-r--r--arch/x86/include/asm/setup.h7
-rw-r--r--arch/x86/include/asm/simd.h2
-rw-r--r--arch/x86/include/asm/smp.h10
-rw-r--r--arch/x86/include/asm/special_insns.h38
-rw-r--r--arch/x86/include/asm/spinlock.h5
-rw-r--r--arch/x86/include/asm/spinlock_types.h4
-rw-r--r--arch/x86/include/asm/stackprotector.h2
-rw-r--r--arch/x86/include/asm/suspend_32.h2
-rw-r--r--arch/x86/include/asm/suspend_64.h2
-rw-r--r--arch/x86/include/asm/thread_info.h8
-rw-r--r--arch/x86/include/asm/topology.h4
-rw-r--r--arch/x86/include/asm/trace/irq_vectors.h6
-rw-r--r--arch/x86/include/asm/trace/mpx.h132
-rw-r--r--arch/x86/include/asm/traps.h3
-rw-r--r--arch/x86/include/asm/uaccess.h15
-rw-r--r--arch/x86/include/asm/uaccess_32.h10
-rw-r--r--arch/x86/include/asm/user.h12
-rw-r--r--arch/x86/include/asm/x86_init.h21
-rw-r--r--arch/x86/include/asm/xcr.h49
-rw-r--r--arch/x86/include/asm/xor.h2
-rw-r--r--arch/x86/include/asm/xor_32.h2
-rw-r--r--arch/x86/include/asm/xor_avx.h2
-rw-r--r--arch/x86/include/asm/xsave.h257
-rw-r--r--arch/x86/include/uapi/asm/kvm.h14
-rw-r--r--arch/x86/include/uapi/asm/msr.h2
-rw-r--r--arch/x86/include/uapi/asm/mtrr.h8
-rw-r--r--arch/x86/include/uapi/asm/sigcontext.h8
-rw-r--r--arch/x86/kernel/Makefile7
-rw-r--r--arch/x86/kernel/acpi/boot.c73
-rw-r--r--arch/x86/kernel/acpi/wakeup_32.S6
-rw-r--r--arch/x86/kernel/acpi/wakeup_64.S6
-rw-r--r--arch/x86/kernel/alternative.c14
-rw-r--r--arch/x86/kernel/amd_nb.c4
-rw-r--r--arch/x86/kernel/apb_timer.c4
-rw-r--r--arch/x86/kernel/aperture_64.c8
-rw-r--r--arch/x86/kernel/apic/htirq.c173
-rw-r--r--arch/x86/kernel/apic/io_apic.c1303
-rw-r--r--arch/x86/kernel/apic/msi.c417
-rw-r--r--arch/x86/kernel/apic/vector.c448
-rw-r--r--arch/x86/kernel/apic/x2apic_phys.c2
-rw-r--r--arch/x86/kernel/asm-offsets.c21
-rw-r--r--arch/x86/kernel/asm-offsets_32.c18
-rw-r--r--arch/x86/kernel/asm-offsets_64.c23
-rw-r--r--arch/x86/kernel/check.c3
-rw-r--r--arch/x86/kernel/cpu/amd.c41
-rw-r--r--arch/x86/kernel/cpu/bugs.c55
-rw-r--r--arch/x86/kernel/cpu/common.c90
-rw-r--r--arch/x86/kernel/cpu/intel_cacheinfo.c8
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c65
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_amd.c141
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_intel.c44
-rw-r--r--arch/x86/kernel/cpu/microcode/amd_early.c24
-rw-r--r--arch/x86/kernel/cpu/microcode/core.c76
-rw-r--r--arch/x86/kernel/cpu/microcode/core_early.c26
-rw-r--r--arch/x86/kernel/cpu/microcode/intel.c79
-rw-r--r--arch/x86/kernel/cpu/microcode/intel_early.c42
-rw-r--r--arch/x86/kernel/cpu/microcode/intel_lib.c45
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c6
-rw-r--r--arch/x86/kernel/cpu/mtrr/cleanup.c3
-rw-r--r--arch/x86/kernel/cpu/mtrr/generic.c209
-rw-r--r--arch/x86/kernel/cpu/mtrr/main.c48
-rw-r--r--arch/x86/kernel/cpu/mtrr/mtrr.h2
-rw-r--r--arch/x86/kernel/cpu/perf_event.c91
-rw-r--r--arch/x86/kernel/cpu/perf_event.h25
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c244
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_bts.c9
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_cqm.c108
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_ds.c317
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_lbr.c13
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_pt.c38
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_rapl.c5
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore.c8
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore.h1
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c20
-rw-r--r--arch/x86/kernel/cpu/proc.c3
-rw-r--r--arch/x86/kernel/crash.c1
-rw-r--r--arch/x86/kernel/devicetree.c41
-rw-r--r--arch/x86/kernel/e820.c3
-rw-r--r--arch/x86/kernel/early-quirks.c9
-rw-r--r--arch/x86/kernel/entry_32.S1401
-rw-r--r--arch/x86/kernel/fpu/Makefile5
-rw-r--r--arch/x86/kernel/fpu/bugs.c71
-rw-r--r--arch/x86/kernel/fpu/core.c523
-rw-r--r--arch/x86/kernel/fpu/init.c354
-rw-r--r--arch/x86/kernel/fpu/regset.c356
-rw-r--r--arch/x86/kernel/fpu/signal.c404
-rw-r--r--arch/x86/kernel/fpu/xstate.c461
-rw-r--r--arch/x86/kernel/head_32.S17
-rw-r--r--arch/x86/kernel/head_64.S4
-rw-r--r--arch/x86/kernel/hpet.c50
-rw-r--r--arch/x86/kernel/i386_ksyms_32.c4
-rw-r--r--arch/x86/kernel/i387.c671
-rw-r--r--arch/x86/kernel/i8259.c8
-rw-r--r--arch/x86/kernel/irq.c62
-rw-r--r--arch/x86/kernel/irq_32.c6
-rw-r--r--arch/x86/kernel/irq_64.c6
-rw-r--r--arch/x86/kernel/irq_work.c10
-rw-r--r--arch/x86/kernel/irqinit.c10
-rw-r--r--arch/x86/kernel/kvm.c47
-rw-r--r--arch/x86/kernel/kvmclock.c14
-rw-r--r--arch/x86/kernel/machine_kexec_64.c4
-rw-r--r--arch/x86/kernel/mpparse.c7
-rw-r--r--arch/x86/kernel/paravirt-spinlocks.c24
-rw-r--r--arch/x86/kernel/paravirt.c4
-rw-r--r--arch/x86/kernel/paravirt_patch_32.c22
-rw-r--r--arch/x86/kernel/paravirt_patch_64.c23
-rw-r--r--arch/x86/kernel/pci-dma.c45
-rw-r--r--arch/x86/kernel/pci-swiotlb.c7
-rw-r--r--arch/x86/kernel/process.c61
-rw-r--r--arch/x86/kernel/process_32.c20
-rw-r--r--arch/x86/kernel/process_64.c16
-rw-r--r--arch/x86/kernel/ptrace.c12
-rw-r--r--arch/x86/kernel/setup.c20
-rw-r--r--arch/x86/kernel/signal.c38
-rw-r--r--arch/x86/kernel/smp.c19
-rw-r--r--arch/x86/kernel/smpboot.c88
-rw-r--r--arch/x86/kernel/traps.c155
-rw-r--r--arch/x86/kernel/tsc_sync.c2
-rw-r--r--arch/x86/kernel/uprobes.c10
-rw-r--r--arch/x86/kernel/x8664_ksyms_64.c4
-rw-r--r--arch/x86/kernel/x86_init.c10
-rw-r--r--arch/x86/kernel/xsave.c724
-rw-r--r--arch/x86/kvm/Kconfig9
-rw-r--r--arch/x86/kvm/Makefile6
-rw-r--r--arch/x86/kvm/cpuid.c17
-rw-r--r--arch/x86/kvm/cpuid.h8
-rw-r--r--arch/x86/kvm/emulate.c303
-rw-r--r--arch/x86/kvm/ioapic.c9
-rw-r--r--arch/x86/kvm/irq_comm.c14
-rw-r--r--arch/x86/kvm/kvm_cache_regs.h5
-rw-r--r--arch/x86/kvm/lapic.c85
-rw-r--r--arch/x86/kvm/lapic.h15
-rw-r--r--arch/x86/kvm/mmu.c678
-rw-r--r--arch/x86/kvm/mmu.h2
-rw-r--r--arch/x86/kvm/mmu_audit.c20
-rw-r--r--arch/x86/kvm/mmutrace.h2
-rw-r--r--arch/x86/kvm/mtrr.c699
-rw-r--r--arch/x86/kvm/paging_tmpl.h18
-rw-r--r--arch/x86/kvm/pmu.c553
-rw-r--r--arch/x86/kvm/pmu.h118
-rw-r--r--arch/x86/kvm/pmu_amd.c207
-rw-r--r--arch/x86/kvm/pmu_intel.c358
-rw-r--r--arch/x86/kvm/svm.c118
-rw-r--r--arch/x86/kvm/trace.h22
-rw-r--r--arch/x86/kvm/vmx.c370
-rw-r--r--arch/x86/kvm/x86.c958
-rw-r--r--arch/x86/kvm/x86.h8
-rw-r--r--arch/x86/lguest/boot.c6
-rw-r--r--arch/x86/lib/Makefile3
-rw-r--r--arch/x86/lib/atomic64_386_32.S7
-rw-r--r--arch/x86/lib/atomic64_cx8_32.S61
-rw-r--r--arch/x86/lib/checksum_32.S52
-rw-r--r--arch/x86/lib/clear_page_64.S7
-rw-r--r--arch/x86/lib/cmpxchg16b_emu.S12
-rw-r--r--arch/x86/lib/cmpxchg8b_emu.S11
-rw-r--r--arch/x86/lib/copy_page_64.S11
-rw-r--r--arch/x86/lib/copy_user_64.S127
-rw-r--r--arch/x86/lib/copy_user_nocache_64.S136
-rw-r--r--arch/x86/lib/csum-copy_64.S17
-rw-r--r--arch/x86/lib/getuser.S13
-rw-r--r--arch/x86/lib/iomap_copy_64.S3
-rw-r--r--arch/x86/lib/memcpy_64.S3
-rw-r--r--arch/x86/lib/memmove_64.S3
-rw-r--r--arch/x86/lib/memset_64.S5
-rw-r--r--arch/x86/lib/mmx_32.c2
-rw-r--r--arch/x86/lib/msr-reg.S44
-rw-r--r--arch/x86/lib/putuser.S8
-rw-r--r--arch/x86/lib/rwsem.S49
-rw-r--r--arch/x86/lib/usercopy_32.c6
-rw-r--r--arch/x86/math-emu/fpu_aux.c4
-rw-r--r--arch/x86/math-emu/fpu_entry.c20
-rw-r--r--arch/x86/math-emu/fpu_system.h2
-rw-r--r--arch/x86/mm/fault.c5
-rw-r--r--arch/x86/mm/highmem_32.c3
-rw-r--r--arch/x86/mm/init.c6
-rw-r--r--arch/x86/mm/init_32.c2
-rw-r--r--arch/x86/mm/iomap_32.c14
-rw-r--r--arch/x86/mm/ioremap.c78
-rw-r--r--arch/x86/mm/mpx.c519
-rw-r--r--arch/x86/mm/pageattr-test.c1
-rw-r--r--arch/x86/mm/pageattr.c84
-rw-r--r--arch/x86/mm/pat.c337
-rw-r--r--arch/x86/mm/pat_internal.h2
-rw-r--r--arch/x86/mm/pat_rbtree.c6
-rw-r--r--arch/x86/mm/pgtable.c60
-rw-r--r--arch/x86/net/bpf_jit.S1
-rw-r--r--arch/x86/net/bpf_jit_comp.c150
-rw-r--r--arch/x86/pci/acpi.c17
-rw-r--r--arch/x86/pci/i386.c6
-rw-r--r--arch/x86/pci/intel_mid_pci.c6
-rw-r--r--arch/x86/pci/irq.c13
-rw-r--r--arch/x86/platform/Makefile1
-rw-r--r--arch/x86/platform/atom/Makefile1
-rw-r--r--arch/x86/platform/atom/punit_atom_debug.c183
-rw-r--r--arch/x86/platform/efi/efi.c23
-rw-r--r--arch/x86/platform/intel-mid/device_libs/platform_wdt.c5
-rw-r--r--arch/x86/platform/intel-mid/intel-mid.c18
-rw-r--r--arch/x86/platform/intel-mid/sfi.c30
-rw-r--r--arch/x86/platform/sfi/sfi.c7
-rw-r--r--arch/x86/platform/uv/uv_irq.c298
-rw-r--r--arch/x86/power/cpu.c11
-rw-r--r--arch/x86/power/hibernate_asm_64.S8
-rw-r--r--arch/x86/um/Makefile2
-rw-r--r--arch/x86/um/asm/barrier.h3
-rw-r--r--arch/x86/xen/enlighten.c10
-rw-r--r--arch/x86/xen/p2m.c1
-rw-r--r--arch/x86/xen/spinlock.c64
-rw-r--r--arch/x86/xen/xen-asm_64.S28
-rw-r--r--arch/x86/xen/xen-ops.h2
-rw-r--r--arch/xtensa/Kconfig2
-rw-r--r--arch/xtensa/include/asm/Kbuild1
-rw-r--r--arch/xtensa/include/asm/dma-mapping.h19
-rw-r--r--arch/xtensa/include/asm/io.h1
-rw-r--r--arch/xtensa/include/asm/mm-arch-hooks.h15
-rw-r--r--arch/xtensa/include/asm/pci.h2
-rw-r--r--arch/xtensa/mm/fault.c4
-rw-r--r--arch/xtensa/mm/highmem.c2
-rw-r--r--block/bio-integrity.c4
-rw-r--r--block/bio.c112
-rw-r--r--block/blk-cgroup.c215
-rw-r--r--block/blk-core.c112
-rw-r--r--block/blk-exec.c10
-rw-r--r--block/blk-integrity.c1
-rw-r--r--block/blk-merge.c3
-rw-r--r--block/blk-mq-cpumap.c2
-rw-r--r--block/blk-mq-tag.c38
-rw-r--r--block/blk-mq-tag.h1
-rw-r--r--block/blk-mq.c160
-rw-r--r--block/blk-sysfs.c3
-rw-r--r--block/blk-throttle.c2
-rw-r--r--block/blk.h5
-rw-r--r--block/bounce.c4
-rw-r--r--block/cfq-iosched.c127
-rw-r--r--block/elevator.c4
-rw-r--r--block/genhd.c1
-rw-r--r--block/ioctl.c37
-rw-r--r--crypto/.gitignore1
-rw-r--r--crypto/842.c174
-rw-r--r--crypto/Kconfig106
-rw-r--r--crypto/Makefile17
-rw-r--r--crypto/ablkcipher.c12
-rw-r--r--crypto/aead.c684
-rw-r--r--crypto/af_alg.c9
-rw-r--r--crypto/akcipher.c117
-rw-r--r--crypto/algapi.c31
-rw-r--r--crypto/algif_aead.c70
-rw-r--r--crypto/algif_rng.c2
-rw-r--r--crypto/ansi_cprng.c88
-rw-r--r--crypto/asymmetric_keys/rsa.c4
-rw-r--r--crypto/authenc.c17
-rw-r--r--crypto/authencesn.c17
-rw-r--r--crypto/blkcipher.c1
-rw-r--r--crypto/ccm.c14
-rw-r--r--crypto/chacha20_generic.c216
-rw-r--r--crypto/chacha20poly1305.c695
-rw-r--r--crypto/chainiv.c105
-rw-r--r--crypto/cryptd.c135
-rw-r--r--crypto/crypto_null.c39
-rw-r--r--crypto/crypto_user.c34
-rw-r--r--crypto/drbg.c567
-rw-r--r--crypto/echainiv.c312
-rw-r--r--crypto/eseqiv.c52
-rw-r--r--crypto/fips.c53
-rw-r--r--crypto/gcm.c940
-rw-r--r--crypto/internal.h3
-rw-r--r--crypto/jitterentropy-kcapi.c208
-rw-r--r--crypto/jitterentropy.c787
-rw-r--r--crypto/krng.c66
-rw-r--r--crypto/md5.c8
-rw-r--r--crypto/pcompress.c7
-rw-r--r--crypto/pcrypt.c199
-rw-r--r--crypto/poly1305_generic.c321
-rw-r--r--crypto/proc.c41
-rw-r--r--crypto/rng.c132
-rw-r--r--crypto/rsa.c315
-rw-r--r--crypto/rsa_helper.c121
-rw-r--r--crypto/rsakey.asn15
-rw-r--r--crypto/scatterwalk.c45
-rw-r--r--crypto/seqiv.c587
-rw-r--r--crypto/shash.c7
-rw-r--r--crypto/tcrypt.c36
-rw-r--r--crypto/tcrypt.h1
-rw-r--r--crypto/testmgr.c318
-rw-r--r--crypto/testmgr.h2443
-rw-r--r--crypto/zlib.c4
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/acpi/Kconfig5
-rw-r--r--drivers/acpi/Makefile5
-rw-r--r--drivers/acpi/ac.c2
-rw-r--r--drivers/acpi/acpi_lpss.c22
-rw-r--r--drivers/acpi/acpi_pad.c2
-rw-r--r--drivers/acpi/acpi_platform.c2
-rw-r--r--drivers/acpi/acpi_processor.c20
-rw-r--r--drivers/acpi/acpi_video.c (renamed from drivers/acpi/video.c)283
-rw-r--r--drivers/acpi/acpica/acdebug.h4
-rw-r--r--drivers/acpi/acpica/aclocal.h15
-rw-r--r--drivers/acpi/acpica/acparser.h3
-rw-r--r--drivers/acpi/acpica/acpredef.h45
-rw-r--r--drivers/acpi/acpica/acutils.h2
-rw-r--r--drivers/acpi/acpica/dsmethod.c5
-rw-r--r--drivers/acpi/acpica/hwpci.c9
-rw-r--r--drivers/acpi/acpica/nsprepkg.c13
-rw-r--r--drivers/acpi/acpica/nsrepair.c2
-rw-r--r--drivers/acpi/acpica/psopinfo.c3
-rw-r--r--drivers/acpi/acpica/utfileio.c9
-rw-r--r--drivers/acpi/acpica/uthex.c4
-rw-r--r--drivers/acpi/acpica/utxferror.c11
-rw-r--r--drivers/acpi/apei/erst.c1
-rw-r--r--drivers/acpi/apei/ghes.c108
-rw-r--r--drivers/acpi/battery.c48
-rw-r--r--drivers/acpi/bus.c56
-rw-r--r--drivers/acpi/device_pm.c98
-rw-r--r--drivers/acpi/ec.c357
-rw-r--r--drivers/acpi/fan.c5
-rw-r--r--drivers/acpi/glue.c5
-rw-r--r--drivers/acpi/hed.c2
-rw-r--r--drivers/acpi/internal.h11
-rw-r--r--drivers/acpi/osl.c14
-rw-r--r--drivers/acpi/pci_irq.c3
-rw-r--r--drivers/acpi/power.c45
-rw-r--r--drivers/acpi/processor_core.c10
-rw-r--r--drivers/acpi/processor_idle.c2
-rw-r--r--drivers/acpi/processor_pdc.c5
-rw-r--r--drivers/acpi/property.c54
-rw-r--r--drivers/acpi/resource.c160
-rw-r--r--drivers/acpi/scan.c147
-rw-r--r--drivers/acpi/thermal.c9
-rw-r--r--drivers/acpi/utils.c15
-rw-r--r--drivers/acpi/video_detect.c409
-rw-r--r--drivers/ata/Kconfig19
-rw-r--r--drivers/ata/Makefile2
-rw-r--r--drivers/ata/acard-ahci.c4
-rw-r--r--drivers/ata/ahci.c104
-rw-r--r--drivers/ata/ahci.h6
-rw-r--r--drivers/ata/ahci_brcmstb.c322
-rw-r--r--drivers/ata/ahci_ceva.c238
-rw-r--r--drivers/ata/ahci_mvebu.c22
-rw-r--r--drivers/ata/ahci_platform.c1
-rw-r--r--drivers/ata/ahci_xgene.c103
-rw-r--r--drivers/ata/libahci.c105
-rw-r--r--drivers/ata/libahci_platform.c4
-rw-r--r--drivers/ata/libata-core.c13
-rw-r--r--drivers/ata/libata-eh.c13
-rw-r--r--drivers/ata/libata-transport.c22
-rw-r--r--drivers/ata/pata_at91.c92
-rw-r--r--drivers/ata/pata_hpt366.c4
-rw-r--r--drivers/ata/pata_samsung_cf.c2
-rw-r--r--drivers/ata/sata_highbank.c3
-rw-r--r--drivers/ata/sata_nv.c2
-rw-r--r--drivers/atm/he.c4
-rw-r--r--drivers/atm/idt77105.c6
-rw-r--r--drivers/atm/iphase.c2
-rw-r--r--drivers/base/base.h1
-rw-r--r--drivers/base/bus.c31
-rw-r--r--drivers/base/cacheinfo.c4
-rw-r--r--drivers/base/core.c9
-rw-r--r--drivers/base/cpu.c29
-rw-r--r--drivers/base/dd.c163
-rw-r--r--drivers/base/firmware_class.c63
-rw-r--r--drivers/base/platform.c13
-rw-r--r--drivers/base/power/Makefile2
-rw-r--r--drivers/base/power/clock_ops.c43
-rw-r--r--drivers/base/power/domain.c42
-rw-r--r--drivers/base/power/main.c14
-rw-r--r--drivers/base/power/power.h48
-rw-r--r--drivers/base/power/runtime.c6
-rw-r--r--drivers/base/power/wakeirq.c273
-rw-r--r--drivers/base/power/wakeup.c146
-rw-r--r--drivers/base/property.c14
-rw-r--r--drivers/base/regmap/internal.h3
-rw-r--r--drivers/base/regmap/regcache.c45
-rw-r--r--drivers/base/regmap/regmap-irq.c11
-rw-r--r--drivers/base/regmap/regmap.c32
-rw-r--r--drivers/base/topology.c2
-rw-r--r--drivers/bcma/Kconfig12
-rw-r--r--drivers/bcma/driver_gpio.c20
-rw-r--r--drivers/block/cciss.c27
-rw-r--r--drivers/block/cciss_scsi.c1
-rw-r--r--drivers/block/drbd/drbd_int.h1
-rw-r--r--drivers/block/drbd/drbd_main.c10
-rw-r--r--drivers/block/drbd/drbd_receiver.c4
-rw-r--r--drivers/block/loop.c82
-rw-r--r--drivers/block/loop.h3
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c228
-rw-r--r--drivers/block/mtip32xx/mtip32xx.h10
-rw-r--r--drivers/block/nbd.c52
-rw-r--r--drivers/block/null_blk.c14
-rw-r--r--drivers/block/nvme-core.c812
-rw-r--r--drivers/block/nvme-scsi.c1230
-rw-r--r--drivers/block/paride/paride.c57
-rw-r--r--drivers/block/paride/paride.h2
-rw-r--r--drivers/block/paride/pcd.c9
-rw-r--r--drivers/block/paride/pd.c16
-rw-r--r--drivers/block/paride/pf.c7
-rw-r--r--drivers/block/paride/pg.c8
-rw-r--r--drivers/block/paride/pt.c8
-rw-r--r--drivers/block/pktcdvd.c1
-rw-r--r--drivers/block/pmem.c4
-rw-r--r--drivers/block/ps3vram.c34
-rw-r--r--drivers/block/sx8.c4
-rw-r--r--drivers/block/virtio_blk.c6
-rw-r--r--drivers/block/zram/Kconfig10
-rw-r--r--drivers/block/zram/zcomp.c7
-rw-r--r--drivers/block/zram/zcomp.h1
-rw-r--r--drivers/block/zram/zram_drv.c959
-rw-r--r--drivers/block/zram/zram_drv.h10
-rw-r--r--drivers/bluetooth/Kconfig15
-rw-r--r--drivers/bluetooth/Makefile1
-rw-r--r--drivers/bluetooth/ath3k.c6
-rw-r--r--drivers/bluetooth/bt3c_cs.c3
-rw-r--r--drivers/bluetooth/btbcm.c138
-rw-r--r--drivers/bluetooth/btbcm.h61
-rw-r--r--drivers/bluetooth/btintel.c6
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c2
-rw-r--r--drivers/bluetooth/btrtl.c390
-rw-r--r--drivers/bluetooth/btrtl.h52
-rw-r--r--drivers/bluetooth/btusb.c572
-rw-r--r--drivers/bluetooth/btwilink.c2
-rw-r--r--drivers/bluetooth/hci_ath.c1
-rw-r--r--drivers/bluetooth/hci_bcm.c107
-rw-r--r--drivers/bluetooth/hci_bcsp.c20
-rw-r--r--drivers/bluetooth/hci_h4.c1
-rw-r--r--drivers/bluetooth/hci_ldisc.c123
-rw-r--r--drivers/bluetooth/hci_uart.h11
-rw-r--r--drivers/bluetooth/hci_vhci.c2
-rw-r--r--drivers/bus/Kconfig31
-rw-r--r--drivers/bus/arm-cci.c905
-rw-r--r--drivers/bus/arm-ccn.c270
-rw-r--r--drivers/bus/brcmstb_gisb.c13
-rw-r--r--drivers/bus/mvebu-mbus.c117
-rw-r--r--drivers/bus/omap_l3_noc.c4
-rw-r--r--drivers/char/Kconfig8
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/hw_random/via-rng.c2
-rw-r--r--drivers/char/ipmi/ipmi_powernv.c39
-rw-r--r--drivers/char/misc.c23
-rw-r--r--drivers/char/msm_smd_pkt.c465
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c5
-rw-r--r--drivers/char/pcmcia/synclink_cs.c2
-rw-r--r--drivers/char/random.c80
-rw-r--r--drivers/char/raw.c1
-rw-r--r--drivers/char/snsc.c4
-rw-r--r--drivers/char/virtio_console.c4
-rw-r--r--drivers/char/xilinx_hwicap/buffer_icap.c6
-rw-r--r--drivers/char/xillybus/Kconfig2
-rw-r--r--drivers/clk/Makefile3
-rw-r--r--drivers/clk/at91/clk-peripheral.c8
-rw-r--r--drivers/clk/at91/clk-pll.c12
-rw-r--r--drivers/clk/at91/pmc.h2
-rw-r--r--drivers/clk/berlin/bg2.c7
-rw-r--r--drivers/clk/berlin/bg2q.c7
-rw-r--r--drivers/clk/clk-s2mps11.c4
-rw-r--r--drivers/clk/clkdev.c83
-rw-r--r--drivers/clk/h8300/Makefile2
-rw-r--r--drivers/clk/h8300/clk-div.c53
-rw-r--r--drivers/clk/h8300/clk-h8s2678.c146
-rw-r--r--drivers/clk/imx/Makefile26
-rw-r--r--drivers/clk/imx/clk-busy.c (renamed from arch/arm/mach-imx/clk-busy.c)0
-rw-r--r--drivers/clk/imx/clk-cpu.c (renamed from arch/arm/mach-imx/clk-cpu.c)1
-rw-r--r--drivers/clk/imx/clk-fixup-div.c (renamed from arch/arm/mach-imx/clk-fixup-div.c)0
-rw-r--r--drivers/clk/imx/clk-fixup-mux.c (renamed from arch/arm/mach-imx/clk-fixup-mux.c)0
-rw-r--r--drivers/clk/imx/clk-gate-exclusive.c (renamed from arch/arm/mach-imx/clk-gate-exclusive.c)0
-rw-r--r--drivers/clk/imx/clk-gate2.c (renamed from arch/arm/mach-imx/clk-gate2.c)0
-rw-r--r--drivers/clk/imx/clk-imx1.c (renamed from arch/arm/mach-imx/clk-imx1.c)17
-rw-r--r--drivers/clk/imx/clk-imx21.c (renamed from arch/arm/mach-imx/clk-imx21.c)14
-rw-r--r--drivers/clk/imx/clk-imx25.c (renamed from arch/arm/mach-imx/clk-imx25.c)6
-rw-r--r--drivers/clk/imx/clk-imx27.c (renamed from arch/arm/mach-imx/clk-imx27.c)15
-rw-r--r--drivers/clk/imx/clk-imx31.c (renamed from arch/arm/mach-imx/clk-imx31.c)35
-rw-r--r--drivers/clk/imx/clk-imx35.c (renamed from arch/arm/mach-imx/clk-imx35.c)36
-rw-r--r--drivers/clk/imx/clk-imx51-imx53.c (renamed from arch/arm/mach-imx/clk-imx51-imx53.c)5
-rw-r--r--drivers/clk/imx/clk-imx6q.c (renamed from arch/arm/mach-imx/clk-imx6q.c)36
-rw-r--r--drivers/clk/imx/clk-imx6sl.c (renamed from arch/arm/mach-imx/clk-imx6sl.c)7
-rw-r--r--drivers/clk/imx/clk-imx6sx.c (renamed from arch/arm/mach-imx/clk-imx6sx.c)10
-rw-r--r--drivers/clk/imx/clk-imx7d.c860
-rw-r--r--drivers/clk/imx/clk-pfd.c (renamed from arch/arm/mach-imx/clk-pfd.c)0
-rw-r--r--drivers/clk/imx/clk-pllv1.c (renamed from arch/arm/mach-imx/clk-pllv1.c)33
-rw-r--r--drivers/clk/imx/clk-pllv2.c (renamed from arch/arm/mach-imx/clk-pllv2.c)0
-rw-r--r--drivers/clk/imx/clk-pllv3.c (renamed from arch/arm/mach-imx/clk-pllv3.c)13
-rw-r--r--drivers/clk/imx/clk-vf610.c (renamed from arch/arm/mach-imx/clk-vf610.c)4
-rw-r--r--drivers/clk/imx/clk.c (renamed from arch/arm/mach-imx/clk.c)0
-rw-r--r--drivers/clk/imx/clk.h (renamed from arch/arm/mach-imx/clk.h)14
-rw-r--r--drivers/clk/pxa/clk-pxa27x.c32
-rw-r--r--drivers/clk/qcom/gcc-ipq806x.c594
-rw-r--r--drivers/clk/ti/clk-7xx.c8
-rw-r--r--drivers/clk/zte/Makefile2
-rw-r--r--drivers/clk/zte/clk-pll.c172
-rw-r--r--drivers/clk/zte/clk-zx296702.c657
-rw-r--r--drivers/clk/zte/clk.h32
-rw-r--r--drivers/clocksource/Kconfig35
-rw-r--r--drivers/clocksource/Makefile8
-rw-r--r--drivers/clocksource/armv7m_systick.c79
-rw-r--r--drivers/clocksource/asm9260_timer.c2
-rw-r--r--drivers/clocksource/exynos_mct.c22
-rw-r--r--drivers/clocksource/h8300_timer16.c254
-rw-r--r--drivers/clocksource/h8300_timer8.c313
-rw-r--r--drivers/clocksource/h8300_tpu.c207
-rw-r--r--drivers/clocksource/qcom-timer.c59
-rw-r--r--drivers/clocksource/time-lpc32xx.c272
-rw-r--r--drivers/clocksource/timer-imx-gpt.c540
-rw-r--r--drivers/clocksource/timer-integrator-ap.c5
-rw-r--r--drivers/clocksource/timer-sp.h (renamed from arch/arm/include/asm/hardware/arm_timer.h)5
-rw-r--r--drivers/clocksource/timer-sp804.c (renamed from arch/arm/common/timer-sp.c)12
-rw-r--r--drivers/clocksource/timer-stm32.c184
-rw-r--r--drivers/clocksource/timer-sun5i.c2
-rw-r--r--drivers/cpufreq/Kconfig.arm2
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c5
-rw-r--r--drivers/cpufreq/arm_big_little.c40
-rw-r--r--drivers/cpufreq/cpufreq-dt.c1
-rw-r--r--drivers/cpufreq/cpufreq-nforce2.c2
-rw-r--r--drivers/cpufreq/cpufreq.c573
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c28
-rw-r--r--drivers/cpufreq/cpufreq_governor.c345
-rw-r--r--drivers/cpufreq/cpufreq_governor.h16
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c6
-rw-r--r--drivers/cpufreq/gx-suspmod.c4
-rw-r--r--drivers/cpufreq/intel_pstate.c73
-rw-r--r--drivers/cpufreq/p4-clockmod.c2
-rw-r--r--drivers/cpufreq/powernow-k8.c13
-rw-r--r--drivers/cpufreq/pxa2xx-cpufreq.c20
-rw-r--r--drivers/cpufreq/qoriq-cpufreq.c32
-rw-r--r--drivers/cpufreq/speedstep-ich.c2
-rw-r--r--drivers/cpuidle/cpuidle-big_little.c8
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c12
-rw-r--r--drivers/cpuidle/cpuidle-pseries.c11
-rw-r--r--drivers/cpuidle/cpuidle.c40
-rw-r--r--drivers/cpuidle/governors/menu.c4
-rw-r--r--drivers/crypto/Kconfig87
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/caam/Kconfig5
-rw-r--r--drivers/crypto/caam/caamalg.c1371
-rw-r--r--drivers/crypto/caam/caamhash.c11
-rw-r--r--drivers/crypto/caam/caamrng.c2
-rw-r--r--drivers/crypto/caam/compat.h2
-rw-r--r--drivers/crypto/caam/ctrl.c4
-rw-r--r--drivers/crypto/caam/regs.h38
-rw-r--r--drivers/crypto/caam/sg_sw_sec4.h50
-rw-r--r--drivers/crypto/ccp/Kconfig1
-rw-r--r--drivers/crypto/ccp/ccp-ops.c9
-rw-r--r--drivers/crypto/ccp/ccp-platform.c62
-rw-r--r--drivers/crypto/ixp4xx_crypto.c9
-rw-r--r--drivers/crypto/marvell/Makefile2
-rw-r--r--drivers/crypto/marvell/cesa.c548
-rw-r--r--drivers/crypto/marvell/cesa.h791
-rw-r--r--drivers/crypto/marvell/cipher.c797
-rw-r--r--drivers/crypto/marvell/hash.c1441
-rw-r--r--drivers/crypto/marvell/tdma.c224
-rw-r--r--drivers/crypto/mv_cesa.c73
-rw-r--r--drivers/crypto/n2_core.c8
-rw-r--r--drivers/crypto/nx/Kconfig61
-rw-r--r--drivers/crypto/nx/Makefile9
-rw-r--r--drivers/crypto/nx/nx-842-crypto.c580
-rw-r--r--drivers/crypto/nx/nx-842-platform.c84
-rw-r--r--drivers/crypto/nx/nx-842-powernv.c637
-rw-r--r--drivers/crypto/nx/nx-842-pseries.c1140
-rw-r--r--drivers/crypto/nx/nx-842.c1610
-rw-r--r--drivers/crypto/nx/nx-842.h144
-rw-r--r--drivers/crypto/nx/nx-aes-gcm.c110
-rw-r--r--drivers/crypto/nx/nx-sha256.c84
-rw-r--r--drivers/crypto/nx/nx-sha512.c85
-rw-r--r--drivers/crypto/nx/nx.c233
-rw-r--r--drivers/crypto/nx/nx.h9
-rw-r--r--drivers/crypto/omap-sham.c27
-rw-r--r--drivers/crypto/padlock-aes.c2
-rw-r--r--drivers/crypto/padlock-sha.c2
-rw-r--r--drivers/crypto/picoxcell_crypto.c41
-rw-r--r--drivers/crypto/qat/Kconfig6
-rw-r--r--drivers/crypto/qat/qat_common/adf_accel_devices.h1
-rw-r--r--drivers/crypto/qat/qat_common/adf_cfg_user.h12
-rw-r--r--drivers/crypto/qat/qat_common/adf_common_drv.h7
-rw-r--r--drivers/crypto/qat/qat_common/adf_ctl_drv.c1
-rw-r--r--drivers/crypto/qat/qat_common/qat_algs.c39
-rw-r--r--drivers/crypto/qat/qat_dh895xcc/adf_drv.c5
-rw-r--r--drivers/crypto/sahara.c13
-rw-r--r--drivers/crypto/talitos.c743
-rw-r--r--drivers/crypto/talitos.h153
-rw-r--r--drivers/crypto/ux500/Kconfig4
-rw-r--r--drivers/crypto/vmx/Kconfig2
-rw-r--r--drivers/crypto/vmx/Makefile2
-rw-r--r--drivers/crypto/vmx/aes.c172
-rw-r--r--drivers/crypto/vmx/aes_cbc.c246
-rw-r--r--drivers/crypto/vmx/aes_ctr.c225
-rw-r--r--drivers/crypto/vmx/aesp8-ppc.h15
-rw-r--r--drivers/crypto/vmx/ghash.c290
-rw-r--r--drivers/crypto/vmx/vmx.c68
-rw-r--r--drivers/dma-buf/dma-buf.c19
-rw-r--r--drivers/dma-buf/reservation.c9
-rw-r--r--drivers/dma-buf/seqno-fence.c8
-rw-r--r--drivers/dma/edma.c7
-rw-r--r--drivers/dma/mic_x100_dma.c1
-rw-r--r--drivers/dma/sh/rcar-dmac.c37
-rw-r--r--drivers/edac/Kconfig22
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/altera_edac.c381
-rw-r--r--drivers/edac/altera_edac.h201
-rw-r--r--drivers/edac/amd64_edac.c1
-rw-r--r--drivers/edac/edac_mc.c9
-rw-r--r--drivers/edac/edac_mc_sysfs.c5
-rw-r--r--drivers/edac/edac_stub.c1
-rw-r--r--drivers/edac/mce_amd_inj.c177
-rw-r--r--drivers/edac/mpc85xx_edac.c10
-rw-r--r--drivers/edac/mpc85xx_edac.h1
-rw-r--r--drivers/edac/sb_edac.c215
-rw-r--r--drivers/edac/xgene_edac.c1215
-rw-r--r--drivers/extcon/Kconfig25
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/extcon-adc-jack.c15
-rw-r--r--drivers/extcon/extcon-arizona.c88
-rw-r--r--drivers/extcon/extcon-axp288.c381
-rw-r--r--drivers/extcon/extcon-gpio.c1
-rw-r--r--drivers/extcon/extcon-max14577.c60
-rw-r--r--drivers/extcon/extcon-max77693.c140
-rw-r--r--drivers/extcon/extcon-max77843.c89
-rw-r--r--drivers/extcon/extcon-max8997.c64
-rw-r--r--drivers/extcon/extcon-palmas.c23
-rw-r--r--drivers/extcon/extcon-rt8973a.c55
-rw-r--r--drivers/extcon/extcon-sm5502.c33
-rw-r--r--drivers/extcon/extcon-usb-gpio.c35
-rw-r--r--drivers/extcon/extcon.c316
-rw-r--r--drivers/firewire/sbp2.c1
-rw-r--r--drivers/firmware/Makefile3
-rw-r--r--drivers/firmware/dmi-sysfs.c17
-rw-r--r--drivers/firmware/dmi_scan.c123
-rw-r--r--drivers/firmware/efi/Kconfig5
-rw-r--r--drivers/firmware/efi/Makefile1
-rw-r--r--drivers/firmware/efi/efi.c91
-rw-r--r--drivers/firmware/efi/efivars.c11
-rw-r--r--drivers/firmware/efi/esrt.c471
-rw-r--r--drivers/firmware/memmap.c24
-rw-r--r--drivers/firmware/qcom_scm-32.c503
-rw-r--r--drivers/firmware/qcom_scm.c474
-rw-r--r--drivers/firmware/qcom_scm.h47
-rw-r--r--drivers/gpio/Kconfig39
-rw-r--r--drivers/gpio/Makefile4
-rw-r--r--drivers/gpio/gpio-altera.c3
-rw-r--r--drivers/gpio/gpio-bcm-kona.c28
-rw-r--r--drivers/gpio/gpio-brcmstb.c252
-rw-r--r--drivers/gpio/gpio-crystalcove.c5
-rw-r--r--drivers/gpio/gpio-dln2.c1
-rw-r--r--drivers/gpio/gpio-em.c2
-rw-r--r--drivers/gpio/gpio-etraxfs.c176
-rw-r--r--drivers/gpio/gpio-f7188x.c4
-rw-r--r--drivers/gpio/gpio-generic.c22
-rw-r--r--drivers/gpio/gpio-grgpio.c2
-rw-r--r--drivers/gpio/gpio-it8761e.c2
-rw-r--r--drivers/gpio/gpio-lpc18xx.c180
-rw-r--r--drivers/gpio/gpio-lynxpoint.c2
-rw-r--r--drivers/gpio/gpio-max732x.c21
-rw-r--r--drivers/gpio/gpio-moxart.c17
-rw-r--r--drivers/gpio/gpio-mpc8xxx.c2
-rw-r--r--drivers/gpio/gpio-mxc.c18
-rw-r--r--drivers/gpio/gpio-mxs.c6
-rw-r--r--drivers/gpio/gpio-omap.c83
-rw-r--r--drivers/gpio/gpio-pca953x.c23
-rw-r--r--drivers/gpio/gpio-pcf857x.c56
-rw-r--r--drivers/gpio/gpio-rcar.c13
-rw-r--r--drivers/gpio/gpio-sa1100.c2
-rw-r--r--drivers/gpio/gpio-sodaville.c2
-rw-r--r--drivers/gpio/gpio-stp-xway.c29
-rw-r--r--drivers/gpio/gpio-tb10x.c1
-rw-r--r--drivers/gpio/gpio-tegra.c6
-rw-r--r--drivers/gpio/gpio-ts5500.c2
-rw-r--r--drivers/gpio/gpio-xgene-sb.c22
-rw-r--r--drivers/gpio/gpio-xilinx.c4
-rw-r--r--drivers/gpio/gpio-xlp.c427
-rw-r--r--drivers/gpio/gpio-zynq.c193
-rw-r--r--drivers/gpio/gpiolib-acpi.c40
-rw-r--r--drivers/gpio/gpiolib-of.c2
-rw-r--r--drivers/gpio/gpiolib-sysfs.c567
-rw-r--r--drivers/gpio/gpiolib.c112
-rw-r--r--drivers/gpio/gpiolib.h16
-rw-r--r--drivers/gpu/drm/Kconfig23
-rw-r--r--drivers/gpu/drm/Makefile6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/Kconfig17
-rw-r--r--drivers/gpu/drm/amd/amdgpu/Makefile81
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ObjectID.h736
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h2337
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c768
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h445
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_afmt.c105
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c1598
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h206
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c572
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c221
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c363
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c268
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c1907
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.h42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c796
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c193
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c2003
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_display.c832
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c955
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h85
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c545
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.h48
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c245
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_family.h62
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c421
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c1133
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c371
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h72
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c716
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c72
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h30
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c395
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h44
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c354
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c216
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h62
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ioc32.c47
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c458
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h92
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c697
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c322
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h586
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.c670
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.h203
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_pll.c350
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_pll.h38
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c807
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h35
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c125
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c561
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c419
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c102
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c234
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_test.c552
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h208
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_trace_points.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c1215
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c317
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h176
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c984
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h39
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c724
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h47
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c1269
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atom-bits.h48
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atom-names.h100
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atom-types.h42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atom.c1408
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atom.h159
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios.h8555
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_crtc.c807
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_crtc.h58
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_dp.c775
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_dp.h42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_encoders.c2066
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_encoders.h73
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_i2c.c158
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_i2c.h31
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ci_dpm.c6699
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ci_dpm.h348
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ci_smc.c279
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik.c2513
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik.h33
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_dpm.h30
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_ih.c471
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_ih.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_sdma.c1407
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_sdma.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cikd.h555
-rw-r--r--drivers/gpu/drm/amd/amdgpu/clearstate_ci.h944
-rw-r--r--drivers/gpu/drm/amd/amdgpu/clearstate_defs.h44
-rw-r--r--drivers/gpu/drm/amd/amdgpu/clearstate_vi.h944
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_dpm.c1941
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_dpm.h237
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_ih.c452
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_ih.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_ppsmc.h185
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_smc.c962
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_smumgr.h94
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v10_0.c3802
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v10_0.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v11_0.c3801
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v11_0.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v8_0.c3753
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v8_0.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c5644
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v7_0.h37
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c4329
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v8_0.h33
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c1339
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v7_0.h36
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c1301
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v8_0.h36
-rw-r--r--drivers/gpu/drm/amd/amdgpu/iceland_dpm.c195
-rw-r--r--drivers/gpu/drm/amd/amdgpu/iceland_ih.c450
-rw-r--r--drivers/gpu/drm/amd/amdgpu/iceland_ih.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/iceland_sdma_pkt_open.h2167
-rw-r--r--drivers/gpu/drm/amd/amdgpu/iceland_smc.c675
-rw-r--r--drivers/gpu/drm/amd/amdgpu/iceland_smumgr.h41
-rw-r--r--drivers/gpu/drm/amd/amdgpu/kv_dpm.c3343
-rw-r--r--drivers/gpu/drm/amd/amdgpu/kv_dpm.h229
-rw-r--r--drivers/gpu/drm/amd/amdgpu/kv_smc.c219
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ppsmc.h196
-rw-r--r--drivers/gpu/drm/amd/amdgpu/pptable.h698
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c1417
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v2_4.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c1483
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v3_0.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/smu7.h170
-rw-r--r--drivers/gpu/drm/amd/amdgpu/smu7_discrete.h514
-rw-r--r--drivers/gpu/drm/amd/amdgpu/smu7_fusion.h300
-rw-r--r--drivers/gpu/drm/amd/amdgpu/smu8.h72
-rw-r--r--drivers/gpu/drm/amd/amdgpu/smu8_fusion.h127
-rw-r--r--drivers/gpu/drm/amd/amdgpu/smu_ucode_xfer_cz.h147
-rw-r--r--drivers/gpu/drm/amd/amdgpu/smu_ucode_xfer_vi.h100
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_dpm.c194
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_ih.c473
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_ih.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_ppsmc.h198
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_sdma_pkt_open.h2240
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_smc.c852
-rw-r--r--drivers/gpu/drm/amd/amdgpu/tonga_smumgr.h42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c905
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v4_2.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c844
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v5_0.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c824
-rw-r--r--drivers/gpu/drm/amd/amdgpu/uvd_v6_0.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v2_0.c663
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v2_0.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v3_0.c573
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v3_0.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vi.c1377
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vi.h33
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vi_dpm.h36
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vid.h368
-rw-r--r--drivers/gpu/drm/amd/amdkfd/Makefile2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c66
-rw-r--r--drivers/gpu/drm/amd/amdkfd/cik_int.h41
-rw-r--r--drivers/gpu/drm/amd/amdkfd/cik_regs.h177
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c395
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c886
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.h193
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.c168
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_dbgmgr.h294
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device.c60
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c82
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h27
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c18
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c10
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c15
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_events.c969
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_events.h84
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c188
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c5
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_module.c9
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c46
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers.h6
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_diq.h290
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h99
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process.c49
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c18
-rw-r--r--drivers/gpu/drm/amd/include/amd_shared.h81
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/bif/bif_4_1_d.h921
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/bif/bif_4_1_sh_mask.h10250
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_0_d.h1068
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_0_enum.h1198
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_0_sh_mask.h11494
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_1_d.h3577
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_1_enum.h1068
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/bif/bif_5_1_sh_mask.h33080
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_d.h7350
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_enum.h1773
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_10_0_sh_mask.h16647
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_d.h7648
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_enum.h6129
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_11_0_sh_mask.h17557
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_8_0_d.h5703
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dce/dce_8_0_sh_mask.h13109
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gca/gfx_7_0_d.h2532
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gca/gfx_7_2_d.h2557
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gca/gfx_7_2_enum.h6274
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gca/gfx_7_2_sh_mask.h18444
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gca/gfx_8_0_d.h2811
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gca/gfx_8_0_enum.h6858
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gca/gfx_8_0_sh_mask.h20776
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gmc/gmc_7_0_d.h657
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gmc/gmc_7_0_sh_mask.h6116
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gmc/gmc_7_1_d.h1464
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gmc/gmc_7_1_sh_mask.h14416
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gmc/gmc_8_1_d.h1708
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gmc/gmc_8_1_enum.h1198
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gmc/gmc_8_1_sh_mask.h15682
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gmc/gmc_8_2_d.h910
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gmc/gmc_8_2_enum.h1068
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gmc/gmc_8_2_sh_mask.h7850
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/oss/oss_2_0_d.h642
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/oss/oss_2_0_sh_mask.h2476
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/oss/oss_2_4_d.h471
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/oss/oss_2_4_enum.h1340
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/oss/oss_2_4_sh_mask.h2544
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/oss/oss_3_0_1_d.h593
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/oss/oss_3_0_1_enum.h1464
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/oss/oss_3_0_1_sh_mask.h3558
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/oss/oss_3_0_d.h688
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/oss/oss_3_0_enum.h1497
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/oss/oss_3_0_sh_mask.h3660
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_0_0_d.h741
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_0_0_sh_mask.h3842
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_0_1_d.h1314
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_0_1_sh_mask.h5456
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_0_d.h1344
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_0_enum.h1191
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_0_sh_mask.h5648
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_1_d.h1123
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_1_enum.h1205
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_1_sh_mask.h4864
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_2_d.h1273
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_2_enum.h1246
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_7_1_2_sh_mask.h5834
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_8_0_d.h671
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_8_0_enum.h1072
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/smu/smu_8_0_sh_mask.h2964
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_4_2_d.h95
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_4_2_sh_mask.h800
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_5_0_d.h114
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_5_0_enum.h1211
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_5_0_sh_mask.h1046
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_6_0_d.h115
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_6_0_enum.h1081
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/uvd/uvd_6_0_sh_mask.h1034
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/vce/vce_2_0_d.h68
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/vce/vce_2_0_sh_mask.h104
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/vce/vce_3_0_d.h73
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/vce/vce_3_0_sh_mask.h120
-rw-r--r--drivers/gpu/drm/amd/include/kgd_kfd_interface.h23
-rw-r--r--drivers/gpu/drm/armada/armada_drm.h2
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c10
-rw-r--r--drivers/gpu/drm/armada/armada_output.c16
-rw-r--r--drivers/gpu/drm/armada/armada_output.h6
-rw-r--r--drivers/gpu/drm/bridge/dw_hdmi.c6
-rw-r--r--drivers/gpu/drm/bridge/ps8622.c27
-rw-r--r--drivers/gpu/drm/bridge/ptn3460.c34
-rw-r--r--drivers/gpu/drm/drm_atomic.c299
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c186
-rw-r--r--drivers/gpu/drm/drm_auth.c178
-rw-r--r--drivers/gpu/drm/drm_bridge.c242
-rw-r--r--drivers/gpu/drm/drm_cache.c5
-rw-r--r--drivers/gpu/drm/drm_crtc.c652
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c96
-rw-r--r--drivers/gpu/drm/drm_dp_helper.c12
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c67
-rw-r--r--drivers/gpu/drm/drm_drv.c22
-rw-r--r--drivers/gpu/drm/drm_edid.c238
-rw-r--r--drivers/gpu/drm/drm_edid_load.c7
-rw-r--r--drivers/gpu/drm/drm_flip_work.c4
-rw-r--r--drivers/gpu/drm/drm_fops.c12
-rw-r--r--drivers/gpu/drm/drm_gem_cma_helper.c4
-rw-r--r--drivers/gpu/drm/drm_internal.h1
-rw-r--r--drivers/gpu/drm/drm_ioctl.c19
-rw-r--r--drivers/gpu/drm/drm_irq.c109
-rw-r--r--drivers/gpu/drm/drm_mm.c4
-rw-r--r--drivers/gpu/drm/drm_modes.c87
-rw-r--r--drivers/gpu/drm/drm_modeset_lock.c8
-rw-r--r--drivers/gpu/drm/drm_prime.c10
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c4
-rw-r--r--drivers/gpu/drm/drm_sysfs.c160
-rw-r--r--drivers/gpu/drm/exynos/Kconfig22
-rw-r--r--drivers/gpu/drm/exynos/Makefile2
-rw-r--r--drivers/gpu/drm/exynos/exynos5433_drm_decon.c660
-rw-r--r--drivers/gpu/drm/exynos/exynos7_drm_decon.c173
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp_core.c21
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c201
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dpi.c26
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c429
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h49
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c539
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_encoder.c35
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c39
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c323
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.h2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu.c21
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu.h11
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_ipp.c81
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_mic.c490
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c137
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.h11
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c125
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c32
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c118
-rw-r--r--drivers/gpu/drm/i2c/adv7511.c2
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c27
-rw-r--r--drivers/gpu/drm/i915/Makefile5
-rw-r--r--drivers/gpu/drm/i915/dvo_ivch.c21
-rw-r--r--drivers/gpu/drm/i915/dvo_ns2501.c670
-rw-r--r--drivers/gpu/drm/i915/i915_cmd_parser.c209
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c733
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c283
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c120
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h296
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c988
-rw-r--r--drivers/gpu/drm/i915/i915_gem_batch_pool.c84
-rw-r--r--drivers/gpu/drm/i915/i915_gem_batch_pool.h42
-rw-r--r--drivers/gpu/drm/i915/i915_gem_context.c39
-rw-r--r--drivers/gpu/drm/i915/i915_gem_debug.c92
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c93
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c1118
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.h121
-rw-r--r--drivers/gpu/drm/i915/i915_gem_shrinker.c8
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_userptr.c15
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.c30
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c329
-rw-r--r--drivers/gpu/drm/i915/i915_params.c8
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h613
-rw-r--r--drivers/gpu/drm/i915/i915_trace.h44
-rw-r--r--drivers/gpu/drm/i915/intel_atomic.c184
-rw-r--r--drivers/gpu/drm/i915/intel_atomic_plane.c48
-rw-r--r--drivers/gpu/drm/i915/intel_audio.c51
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c183
-rw-r--r--drivers/gpu/drm/i915/intel_bios.h4
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c17
-rw-r--r--drivers/gpu/drm/i915/intel_csr.c467
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c912
-rw-r--r--drivers/gpu/drm/i915/intel_display.c3411
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c593
-rw-r--r--drivers/gpu/drm/i915/intel_dp_mst.c27
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h156
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.c8
-rw-r--r--drivers/gpu/drm/i915/intel_dsi_panel_vbt.c4
-rw-r--r--drivers/gpu/drm/i915/intel_dsi_pll.c80
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c27
-rw-r--r--drivers/gpu/drm/i915/intel_fbc.c2
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c28
-rw-r--r--drivers/gpu/drm/i915/intel_frontbuffer.c2
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c192
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c118
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.c523
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.h5
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c4
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c12
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c68
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c87
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c354
-rw-r--r--drivers/gpu/drm/i915/intel_psr.c118
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c196
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h15
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c476
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c85
-rw-r--r--drivers/gpu/drm/i915/intel_sideband.c18
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c374
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.c98
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c5
-rw-r--r--drivers/gpu/drm/msm/Kconfig7
-rw-r--r--drivers/gpu/drm/msm/Makefile5
-rw-r--r--drivers/gpu/drm/msm/adreno/a2xx.xml.h6
-rw-r--r--drivers/gpu/drm/msm/adreno/a3xx.xml.h168
-rw-r--r--drivers/gpu/drm/msm/adreno/a3xx_gpu.c15
-rw-r--r--drivers/gpu/drm/msm/adreno/a4xx.xml.h420
-rw-r--r--drivers/gpu/drm/msm/adreno/a4xx_gpu.c3
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_common.xml.h6
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_device.c12
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c34
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.h9
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h31
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.c43
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.h61
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.xml.h163
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c120
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_manager.c79
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_phy.c315
-rw-r--r--drivers/gpu/drm/msm/dsi/mmss_cc.xml.h12
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll.c164
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll.h89
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c652
-rw-r--r--drivers/gpu/drm/msm/dsi/sfpb.xml.h12
-rw-r--r--drivers/gpu/drm/msm/edp/edp.xml.h101
-rw-r--r--drivers/gpu/drm/msm/edp/edp_aux.c12
-rw-r--r--drivers/gpu/drm/msm/edp/edp_ctrl.c9
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.xml.h99
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_connector.c43
-rw-r--r--drivers/gpu/drm/msm/hdmi/qfprom.xml.h12
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h32
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c39
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c9
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h3
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c22
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h398
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c20
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c128
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c11
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h3
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c24
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c7
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h1
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp_common.xml.h16
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp_format.c6
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp_kms.h2
-rw-r--r--drivers/gpu/drm/msm/msm_atomic.c46
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c27
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h4
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c4
-rw-r--r--drivers/gpu/drm/msm/msm_gem.h1
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c1
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c52
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.h6
-rw-r--r--drivers/gpu/drm/msm/msm_kms.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_connector.c12
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c541
-rw-r--r--drivers/gpu/drm/omapdrm/omap_debugfs.c6
-rw-r--r--drivers/gpu/drm/omapdrm/omap_dmm_tiler.c19
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c224
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.h59
-rw-r--r--drivers/gpu/drm/omapdrm/omap_encoder.c99
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fb.c27
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c6
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_irq.c106
-rw-r--r--drivers/gpu/drm/omapdrm/omap_plane.c424
-rw-r--r--drivers/gpu/drm/panel/panel-ld9040.c10
-rw-r--r--drivers/gpu/drm/panel/panel-s6e8aa0.c2
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c54
-rw-r--r--drivers/gpu/drm/qxl/qxl_cmd.c11
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.c2
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h2
-rw-r--r--drivers/gpu/drm/qxl/qxl_fb.c275
-rw-r--r--drivers/gpu/drm/qxl/qxl_gem.c10
-rw-r--r--drivers/gpu/drm/qxl/qxl_ioctl.c46
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.c11
-rw-r--r--drivers/gpu/drm/qxl/qxl_release.c13
-rw-r--r--drivers/gpu/drm/radeon/atombios.h4
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c8
-rw-r--r--drivers/gpu/drm/radeon/cik.c25
-rw-r--r--drivers/gpu/drm/radeon/cik_reg.h58
-rw-r--r--drivers/gpu/drm/radeon/cikd.h10
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c69
-rw-r--r--drivers/gpu/drm/radeon/ni.c102
-rw-r--r--drivers/gpu/drm/radeon/nid.h7
-rw-r--r--drivers/gpu/drm/radeon/r100.c22
-rw-r--r--drivers/gpu/drm/radeon/r300.c25
-rw-r--r--drivers/gpu/drm/radeon/r600.c47
-rw-r--r--drivers/gpu/drm/radeon/radeon.h243
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c21
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h6
-rw-r--r--drivers/gpu/drm/radeon/radeon_audio.c18
-rw-r--r--drivers/gpu/drm/radeon/radeon_audio.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_dp_mst.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c10
-rw-r--r--drivers/gpu/drm/radeon/radeon_kfd.c172
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_vce.c28
-rw-r--r--drivers/gpu/drm/radeon/radeon_vm.c53
-rw-r--r--drivers/gpu/drm/radeon/si.c167
-rw-r--r--drivers/gpu/drm/radeon/si_dpm.c109
-rw-r--r--drivers/gpu/drm/radeon/sid.h29
-rw-r--r--drivers/gpu/drm/radeon/trinity_dpm.c83
-rw-r--r--drivers/gpu/drm/radeon/vce_v1_0.c197
-rw-r--r--drivers/gpu/drm/radeon/vce_v2_0.c16
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c74
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.h14
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h6
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_group.c6
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_group.h10
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c136
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.c84
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.h21
-rw-r--r--drivers/gpu/drm/sti/sti_dvo.c4
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c4
-rw-r--r--drivers/gpu/drm/sti/sti_vtg.c56
-rw-r--r--drivers/gpu/drm/tegra/dpaux.c39
-rw-r--r--drivers/gpu/drm/tegra/drm.c12
-rw-r--r--drivers/gpu/drm/tegra/gem.c25
-rw-r--r--drivers/gpu/drm/tilcdc/Kconfig12
-rw-r--r--drivers/gpu/drm/tilcdc/Makefile5
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_crtc.c36
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c99
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.h6
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_external.c166
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_external.h (renamed from drivers/gpu/drm/tilcdc/tilcdc_slave.h)17
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_slave.c411
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c270
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_slave_compat.dts72
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_slave_compat.h25
-rw-r--r--drivers/gpu/drm/ttm/ttm_page_alloc_dma.c9
-rw-r--r--drivers/gpu/drm/vgem/vgem_drv.c2
-rw-r--r--drivers/gpu/drm/virtio/Kconfig14
-rw-r--r--drivers/gpu/drm/virtio/Makefile11
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_debugfs.c64
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_display.c473
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drm_bus.c95
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.c136
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.h352
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_fb.c431
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_fence.c119
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_gem.c140
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_kms.c175
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_object.c170
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_plane.c120
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_ttm.c467
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_vq.c623
-rw-r--r--drivers/gpu/ipu-v3/ipu-common.c13
-rw-r--r--drivers/hid/Kconfig7
-rw-r--r--drivers/hid/Makefile6
-rw-r--r--drivers/hid/hid-core.c38
-rw-r--r--drivers/hid/hid-cypress.c6
-rw-r--r--drivers/hid/hid-ids.h31
-rw-r--r--drivers/hid/hid-input.c3
-rw-r--r--drivers/hid/hid-lenovo.c59
-rw-r--r--drivers/hid/hid-lg.c24
-rw-r--r--drivers/hid/hid-lg4ff.c458
-rw-r--r--drivers/hid/hid-lg4ff.h4
-rw-r--r--drivers/hid/hid-logitech-hidpp.c227
-rw-r--r--drivers/hid/hid-microsoft.c2
-rw-r--r--drivers/hid/hid-plantronics.c132
-rw-r--r--drivers/hid/hid-prodikeys.c3
-rw-r--r--drivers/hid/hid-rmi.c15
-rw-r--r--drivers/hid/hid-sjoy.c3
-rw-r--r--drivers/hid/hid-sony.c376
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c7
-rw-r--r--drivers/hid/usbhid/hid-quirks.c6
-rw-r--r--drivers/hid/wacom.h6
-rw-r--r--drivers/hid/wacom_sys.c309
-rw-r--r--drivers/hid/wacom_wac.c419
-rw-r--r--drivers/hid/wacom_wac.h27
-rw-r--r--drivers/hsi/clients/cmt_speech.c9
-rw-r--r--drivers/hsi/clients/nokia-modem.c11
-rw-r--r--drivers/hv/Makefile2
-rw-r--r--drivers/hv/channel.c27
-rw-r--r--drivers/hv/channel_mgmt.c156
-rw-r--r--drivers/hv/connection.c13
-rw-r--r--drivers/hv/hv_balloon.c4
-rw-r--r--drivers/hv/hv_fcopy.c287
-rw-r--r--drivers/hv/hv_kvp.c192
-rw-r--r--drivers/hv/hv_snapshot.c168
-rw-r--r--drivers/hv/hv_utils_transport.c276
-rw-r--r--drivers/hv/hv_utils_transport.h51
-rw-r--r--drivers/hv/hyperv_vmbus.h31
-rw-r--r--drivers/hv/vmbus_drv.c21
-rw-r--r--drivers/hwmon/Kconfig29
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/atxp1.c58
-rw-r--r--drivers/hwmon/coretemp.c3
-rw-r--r--drivers/hwmon/dell-smm-hwmon.c (renamed from drivers/char/i8k.c)156
-rw-r--r--drivers/hwmon/max197.c2
-rw-r--r--drivers/hwmon/ntc_thermistor.c82
-rw-r--r--drivers/hwmon/sht15.c2
-rw-r--r--drivers/hwmon/tc74.c177
-rw-r--r--drivers/hwtracing/coresight/Kconfig19
-rw-r--r--drivers/hwtracing/coresight/Makefile2
-rw-r--r--drivers/hwtracing/coresight/coresight-etb10.c79
-rw-r--r--drivers/hwtracing/coresight/coresight-etm.h4
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x.c112
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x.c2702
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x.h391
-rw-r--r--drivers/hwtracing/coresight/coresight-funnel.c61
-rw-r--r--drivers/hwtracing/coresight/coresight-replicator-qcom.c215
-rw-r--r--drivers/hwtracing/coresight/coresight-replicator.c71
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.c31
-rw-r--r--drivers/hwtracing/coresight/coresight-tpiu.c60
-rw-r--r--drivers/hwtracing/coresight/of_coresight.c2
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c2
-rw-r--r--drivers/i2c/busses/Kconfig34
-rw-r--r--drivers/i2c/busses/Makefile3
-rw-r--r--drivers/i2c/busses/i2c-at91.c362
-rw-r--r--drivers/i2c/busses/i2c-axxia.c41
-rw-r--r--drivers/i2c/busses/i2c-bcm-iproc.c57
-rw-r--r--drivers/i2c/busses/i2c-bcm2835.c11
-rw-r--r--drivers/i2c/busses/i2c-brcmstb.c694
-rw-r--r--drivers/i2c/busses/i2c-cros-ec-tunnel.c45
-rw-r--r--drivers/i2c/busses/i2c-davinci.c80
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c35
-rw-r--r--drivers/i2c/busses/i2c-imx.c2
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c731
-rw-r--r--drivers/i2c/busses/i2c-mxs.c2
-rw-r--r--drivers/i2c/busses/i2c-octeon.c7
-rw-r--r--drivers/i2c/busses/i2c-omap.c74
-rw-r--r--drivers/i2c/busses/i2c-parport.c38
-rw-r--r--drivers/i2c/busses/i2c-piix4.c4
-rw-r--r--drivers/i2c/busses/i2c-rcar.c10
-rw-r--r--drivers/i2c/busses/i2c-rk3x.c2
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c2
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c49
-rw-r--r--drivers/i2c/busses/i2c-tegra.c11
-rw-r--r--drivers/i2c/busses/i2c-xgene-slimpro.c469
-rw-r--r--drivers/i2c/busses/i2c-xiic.c1
-rw-r--r--drivers/i2c/i2c-core.c75
-rw-r--r--drivers/i2c/i2c-mux.c3
-rw-r--r--drivers/i2c/i2c-smbus.c2
-rw-r--r--drivers/i2c/muxes/Kconfig5
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca9541.c4
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c2
-rw-r--r--drivers/ide/ide-atapi.c10
-rw-r--r--drivers/ide/ide-cd.c10
-rw-r--r--drivers/ide/ide-cd_ioctl.c2
-rw-r--r--drivers/ide/ide-devsets.c2
-rw-r--r--drivers/ide/ide-eh.c4
-rw-r--r--drivers/ide/ide-floppy.c8
-rw-r--r--drivers/ide/ide-io.c12
-rw-r--r--drivers/ide/ide-ioctls.c2
-rw-r--r--drivers/ide/ide-park.c4
-rw-r--r--drivers/ide/ide-pm.c56
-rw-r--r--drivers/ide/ide-tape.c6
-rw-r--r--drivers/ide/ide-taskfile.c2
-rw-r--r--drivers/iio/accel/Kconfig21
-rw-r--r--drivers/iio/accel/Makefile3
-rw-r--r--drivers/iio/accel/bmc150-accel.c55
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c15
-rw-r--r--drivers/iio/accel/kxcjk-1013.c42
-rw-r--r--drivers/iio/accel/mma8452.c555
-rw-r--r--drivers/iio/accel/mma9551_core.c8
-rw-r--r--drivers/iio/accel/mma9551_core.h2
-rw-r--r--drivers/iio/accel/mma9553.c148
-rw-r--r--drivers/iio/accel/st_accel.h1
-rw-r--r--drivers/iio/accel/st_accel_core.c86
-rw-r--r--drivers/iio/accel/st_accel_i2c.c4
-rw-r--r--drivers/iio/accel/stk8312.c390
-rw-r--r--drivers/iio/accel/stk8ba50.c302
-rw-r--r--drivers/iio/adc/Kconfig11
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/axp288_adc.c2
-rw-r--r--drivers/iio/adc/berlin2-adc.c378
-rw-r--r--drivers/iio/adc/ti-adc128s052.c30
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c83
-rw-r--r--drivers/iio/adc/twl4030-madc.c8
-rw-r--r--drivers/iio/adc/vf610_adc.c146
-rw-r--r--drivers/iio/buffer_cb.c2
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c27
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_trigger.c4
-rw-r--r--drivers/iio/dac/Kconfig10
-rw-r--r--drivers/iio/dac/Makefile1
-rw-r--r--drivers/iio/dac/m62332.c269
-rw-r--r--drivers/iio/gyro/bmg160.c67
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c15
-rw-r--r--drivers/iio/humidity/Kconfig2
-rw-r--r--drivers/iio/industrialio-buffer.c378
-rw-r--r--drivers/iio/industrialio-core.c6
-rw-r--r--drivers/iio/industrialio-event.c2
-rw-r--r--drivers/iio/kfifo_buf.c2
-rw-r--r--drivers/iio/light/Kconfig37
-rw-r--r--drivers/iio/light/Makefile3
-rw-r--r--drivers/iio/light/acpi-als.c231
-rw-r--r--drivers/iio/light/bh1750.c334
-rw-r--r--drivers/iio/light/hid-sensor-als.c14
-rw-r--r--drivers/iio/light/hid-sensor-prox.c2
-rw-r--r--drivers/iio/light/ltr501.c1284
-rw-r--r--drivers/iio/light/stk3310.c722
-rw-r--r--drivers/iio/light/tsl2563.c36
-rw-r--r--drivers/iio/light/tsl4531.c10
-rw-r--r--drivers/iio/magnetometer/Kconfig29
-rw-r--r--drivers/iio/magnetometer/Makefile3
-rw-r--r--drivers/iio/magnetometer/bmc150_magn.c1109
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c2
-rw-r--r--drivers/iio/magnetometer/mmc35240.c579
-rw-r--r--drivers/iio/magnetometer/st_magn.h1
-rw-r--r--drivers/iio/magnetometer/st_magn_core.c116
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c5
-rw-r--r--drivers/iio/orientation/hid-sensor-incl-3d.c16
-rw-r--r--drivers/iio/orientation/hid-sensor-rotation.c17
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c14
-rw-r--r--drivers/iio/proximity/sx9500.c457
-rw-r--r--drivers/iio/temperature/mlx90614.c353
-rw-r--r--drivers/iio/temperature/tmp006.c6
-rw-r--r--drivers/infiniband/core/addr.c4
-rw-r--r--drivers/infiniband/core/agent.c23
-rw-r--r--drivers/infiniband/core/agent.h6
-rw-r--r--drivers/infiniband/core/cache.c69
-rw-r--r--drivers/infiniband/core/cm.c26
-rw-r--r--drivers/infiniband/core/cma.c287
-rw-r--r--drivers/infiniband/core/device.c96
-rw-r--r--drivers/infiniband/core/mad.c639
-rw-r--r--drivers/infiniband/core/mad_priv.h15
-rw-r--r--drivers/infiniband/core/mad_rmpp.c33
-rw-r--r--drivers/infiniband/core/multicast.c12
-rw-r--r--drivers/infiniband/core/opa_smi.h78
-rw-r--r--drivers/infiniband/core/sa_query.c33
-rw-r--r--drivers/infiniband/core/smi.c228
-rw-r--r--drivers/infiniband/core/sysfs.c8
-rw-r--r--drivers/infiniband/core/ucm.c3
-rw-r--r--drivers/infiniband/core/ucma.c25
-rw-r--r--drivers/infiniband/core/user_mad.c64
-rw-r--r--drivers/infiniband/core/uverbs.h1
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c188
-rw-r--r--drivers/infiniband/core/uverbs_main.c1
-rw-r--r--drivers/infiniband/core/verbs.c85
-rw-r--r--drivers/infiniband/hw/amso1100/c2_provider.c42
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c47
-rw-r--r--drivers/infiniband/hw/cxgb4/cq.c31
-rw-r--r--drivers/infiniband/hw/cxgb4/device.c16
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h13
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c44
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c64
-rw-r--r--drivers/infiniband/hw/cxgb4/t4.h60
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c7
-rw-r--r--drivers/infiniband/hw/ehca/ehca_hca.c6
-rw-r--r--drivers/infiniband/hw/ehca/ehca_iverbs.h16
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c25
-rw-r--r--drivers/infiniband/hw/ehca/ehca_sqp.c21
-rw-r--r--drivers/infiniband/hw/ipath/Kconfig3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_cq.c9
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c18
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mad.c15
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c26
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h11
-rw-r--r--drivers/infiniband/hw/ipath/ipath_wc_x86_64.c43
-rw-r--r--drivers/infiniband/hw/mlx4/alias_GUID.c7
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c13
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c85
-rw-r--r--drivers/infiniband/hw/mlx4/main.c213
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h37
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c7
-rw-r--r--drivers/infiniband/hw/mlx5/Kconfig4
-rw-r--r--drivers/infiniband/hw/mlx5/cq.c21
-rw-r--r--drivers/infiniband/hw/mlx5/mad.c314
-rw-r--r--drivers/infiniband/hw/mlx5/main.c681
-rw-r--r--drivers/infiniband/hw/mlx5/mlx5_ib.h38
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c3
-rw-r--r--drivers/infiniband/hw/mlx5/odp.c47
-rw-r--r--drivers/infiniband/hw/mlx5/qp.c89
-rw-r--r--drivers/infiniband/hw/mlx5/srq.c11
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c4
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.h4
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h9
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mad.c21
-rw-r--r--drivers/infiniband/hw/mthca/mthca_profile.c8
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c34
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c7
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.h2
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c41
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_ah.c13
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_ah.h8
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c20
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c21
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.h12
-rw-r--r--drivers/infiniband/hw/qib/qib_cq.c11
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7322.c3
-rw-r--r--drivers/infiniband/hw/qib/qib_mad.c20
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.c25
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.h11
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_main.c17
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_verbs.c16
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_verbs.h12
-rw-r--r--drivers/infiniband/hw/usnic/usnic_uiom.c7
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c19
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c8
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c33
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c49
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c146
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h3
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c8
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.h2
-rw-r--r--drivers/input/Kconfig13
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/evdev.c5
-rw-r--r--drivers/input/ff-core.c4
-rw-r--r--drivers/input/input-leds.c212
-rw-r--r--drivers/input/input.c2
-rw-r--r--drivers/input/keyboard/Kconfig3
-rw-r--r--drivers/input/keyboard/adp5589-keys.c6
-rw-r--r--drivers/input/keyboard/clps711x-keypad.c7
-rw-r--r--drivers/input/keyboard/cros_ec_keyb.c31
-rw-r--r--drivers/input/keyboard/max7359_keypad.c31
-rw-r--r--drivers/input/keyboard/samsung-keypad.c2
-rw-r--r--drivers/input/keyboard/spear-keyboard.c2
-rw-r--r--drivers/input/misc/Kconfig23
-rw-r--r--drivers/input/misc/Makefile2
-rw-r--r--drivers/input/misc/adxl34x-i2c.c21
-rw-r--r--drivers/input/misc/da9063_onkey.c226
-rw-r--r--drivers/input/misc/drv260x.c13
-rw-r--r--drivers/input/misc/drv2665.c322
-rw-r--r--drivers/input/misc/gpio-beeper.c7
-rw-r--r--drivers/input/misc/retu-pwrbutton.c3
-rw-r--r--drivers/input/misc/soc_button_array.c1
-rw-r--r--drivers/input/misc/twl4030-pwrbutton.c3
-rw-r--r--drivers/input/misc/twl6040-vibra.c3
-rw-r--r--drivers/input/misc/wm831x-on.c3
-rw-r--r--drivers/input/mouse/alps.c244
-rw-r--r--drivers/input/mouse/alps.h1
-rw-r--r--drivers/input/mouse/cyapa_gen3.c3
-rw-r--r--drivers/input/mouse/cyapa_gen5.c23
-rw-r--r--drivers/input/mouse/elan_i2c.h8
-rw-r--r--drivers/input/mouse/elan_i2c_core.c63
-rw-r--r--drivers/input/mouse/elan_i2c_i2c.c4
-rw-r--r--drivers/input/mouse/elan_i2c_smbus.c6
-rw-r--r--drivers/input/mouse/focaltech.c13
-rw-r--r--drivers/input/mouse/psmouse-base.c2
-rw-r--r--drivers/input/mouse/sentelic.h4
-rw-r--r--drivers/input/mouse/synaptics_i2c.c6
-rw-r--r--drivers/input/serio/serport.c5
-rw-r--r--drivers/input/touchscreen/Kconfig4
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c8
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.c5
-rw-r--r--drivers/input/touchscreen/goodix.c58
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c2
-rw-r--r--drivers/input/touchscreen/s3c2410_ts.c2
-rw-r--r--drivers/input/touchscreen/stmpe-ts.c37
-rw-r--r--drivers/input/touchscreen/sur40.c46
-rw-r--r--drivers/input/touchscreen/zforce_ts.c1
-rw-r--r--drivers/iommu/Kconfig18
-rw-r--r--drivers/iommu/Makefile1
-rw-r--r--drivers/iommu/amd_iommu.c1066
-rw-r--r--drivers/iommu/amd_iommu_init.c38
-rw-r--r--drivers/iommu/amd_iommu_proto.h11
-rw-r--r--drivers/iommu/amd_iommu_types.h16
-rw-r--r--drivers/iommu/arm-smmu-v3.c2670
-rw-r--r--drivers/iommu/arm-smmu.c23
-rw-r--r--drivers/iommu/dmar.c47
-rw-r--r--drivers/iommu/exynos-iommu.c527
-rw-r--r--drivers/iommu/intel-iommu.c495
-rw-r--r--drivers/iommu/intel_irq_remapping.c880
-rw-r--r--drivers/iommu/iommu.c373
-rw-r--r--drivers/iommu/iova.c4
-rw-r--r--drivers/iommu/irq_remapping.c253
-rw-r--r--drivers/iommu/irq_remapping.h42
-rw-r--r--drivers/iommu/rockchip-iommu.c27
-rw-r--r--drivers/iommu/tegra-smmu.c109
-rw-r--r--drivers/irqchip/Kconfig9
-rw-r--r--drivers/irqchip/Makefile3
-rw-r--r--drivers/irqchip/exynos-combiner.c66
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c2
-rw-r--r--drivers/irqchip/irq-atmel-aic5.c9
-rw-r--r--drivers/irqchip/irq-bcm2835.c2
-rw-r--r--drivers/irqchip/irq-gic-common.c17
-rw-r--r--drivers/irqchip/irq-gic-v3.c1
-rw-r--r--drivers/irqchip/irq-gic.c1
-rw-r--r--drivers/irqchip/irq-hip04.c1
-rw-r--r--drivers/irqchip/irq-keystone.c5
-rw-r--r--drivers/irqchip/irq-mips-gic.c2
-rw-r--r--drivers/irqchip/irq-mtk-sysirq.c4
-rw-r--r--drivers/irqchip/irq-mxs.c2
-rw-r--r--drivers/irqchip/irq-nvic.c28
-rw-r--r--drivers/irqchip/irq-renesas-h8300h.c95
-rw-r--r--drivers/irqchip/irq-renesas-h8s.c101
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c2
-rw-r--r--drivers/irqchip/irq-renesas-irqc.c19
-rw-r--r--drivers/irqchip/irq-s3c24xx.c4
-rw-r--r--drivers/irqchip/irq-sa11x0.c (renamed from arch/arm/mach-sa1100/irq.c)85
-rw-r--r--drivers/irqchip/irq-sun4i.c2
-rw-r--r--drivers/irqchip/irq-versatile-fpga.c2
-rw-r--r--drivers/irqchip/irq-vf610-mscm-ir.c28
-rw-r--r--drivers/irqchip/irq-vic.c2
-rw-r--r--drivers/irqchip/irq-vt8500.c2
-rw-r--r--drivers/irqchip/spear-shirq.c3
-rw-r--r--drivers/isdn/capi/capidrv.c4
-rw-r--r--drivers/isdn/hisax/Kconfig4
-rw-r--r--drivers/isdn/hisax/st5481_usb.c4
-rw-r--r--drivers/isdn/i4l/isdn_net.c2
-rw-r--r--drivers/isdn/mISDN/socket.c12
-rw-r--r--drivers/leds/Kconfig3
-rw-r--r--drivers/leds/led-class.c7
-rw-r--r--drivers/leds/leds-syscon.c170
-rw-r--r--drivers/lguest/interrupts_and_traps.c10
-rw-r--r--drivers/lguest/x86/core.c12
-rw-r--r--drivers/macintosh/nvram.c130
-rw-r--r--drivers/mailbox/Kconfig10
-rw-r--r--drivers/mailbox/Makefile2
-rw-r--r--drivers/mailbox/arm_mhu.c2
-rw-r--r--drivers/mailbox/bcm2835-mailbox.c217
-rw-r--r--drivers/mailbox/mailbox-altera.c2
-rw-r--r--drivers/mailbox/mailbox.c40
-rw-r--r--drivers/mailbox/omap-mailbox.c8
-rw-r--r--drivers/mailbox/pcc.c2
-rw-r--r--drivers/md/Kconfig12
-rw-r--r--drivers/md/Makefile2
-rw-r--r--drivers/md/bcache/io.c2
-rw-r--r--drivers/md/bcache/request.c3
-rw-r--r--drivers/md/dm-bio-prison.c26
-rw-r--r--drivers/md/dm-bio-prison.h13
-rw-r--r--drivers/md/dm-cache-metadata.c133
-rw-r--r--drivers/md/dm-cache-metadata.h10
-rw-r--r--drivers/md/dm-cache-policy-cleaner.c6
-rw-r--r--drivers/md/dm-cache-policy-internal.h52
-rw-r--r--drivers/md/dm-cache-policy-mq.c93
-rw-r--r--drivers/md/dm-cache-policy-smq.c1791
-rw-r--r--drivers/md/dm-cache-policy.h30
-rw-r--r--drivers/md/dm-cache-target.c838
-rw-r--r--drivers/md/dm-crypt.c30
-rw-r--r--drivers/md/dm-log-writes.c4
-rw-r--r--drivers/md/dm-raid.c225
-rw-r--r--drivers/md/dm-raid1.c77
-rw-r--r--drivers/md/dm-snap.c1
-rw-r--r--drivers/md/dm-stats.c341
-rw-r--r--drivers/md/dm-stats.h4
-rw-r--r--drivers/md/dm-stripe.c4
-rw-r--r--drivers/md/dm-thin-metadata.c124
-rw-r--r--drivers/md/dm-thin-metadata.h11
-rw-r--r--drivers/md/dm-thin.c615
-rw-r--r--drivers/md/dm-verity.c2
-rw-r--r--drivers/md/dm.c123
-rw-r--r--drivers/md/dm.h1
-rw-r--r--drivers/md/md.c4
-rw-r--r--drivers/md/md.h1
-rw-r--r--drivers/md/persistent-data/dm-block-manager.c6
-rw-r--r--drivers/md/persistent-data/dm-block-manager.h1
-rw-r--r--drivers/md/persistent-data/dm-btree-remove.c127
-rw-r--r--drivers/md/persistent-data/dm-btree.h9
-rw-r--r--drivers/md/persistent-data/dm-space-map-metadata.c50
-rw-r--r--drivers/md/raid1.c4
-rw-r--r--drivers/md/raid10.c2
-rw-r--r--drivers/media/Kconfig3
-rw-r--r--drivers/media/common/b2c2/Kconfig1
-rw-r--r--drivers/media/common/b2c2/flexcop-common.h1
-rw-r--r--drivers/media/common/b2c2/flexcop-fe-tuner.c63
-rw-r--r--drivers/media/common/b2c2/flexcop-hw-filter.c16
-rw-r--r--drivers/media/common/b2c2/flexcop-misc.c1
-rw-r--r--drivers/media/common/b2c2/flexcop-reg.h1
-rw-r--r--drivers/media/common/siano/smscoreapi.h3
-rw-r--r--drivers/media/common/siano/smsdvb-main.c6
-rw-r--r--drivers/media/common/siano/smsdvb.h2
-rw-r--r--drivers/media/common/siano/smsir.c2
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c78
-rw-r--r--drivers/media/dvb-core/dvb_frontend.h45
-rw-r--r--drivers/media/dvb-frontends/Kconfig13
-rw-r--r--drivers/media/dvb-frontends/Makefile1
-rw-r--r--drivers/media/dvb-frontends/a8293.c89
-rw-r--r--drivers/media/dvb-frontends/a8293.h15
-rw-r--r--drivers/media/dvb-frontends/af9013.c8
-rw-r--r--drivers/media/dvb-frontends/af9033.c4
-rw-r--r--drivers/media/dvb-frontends/as102_fe.c4
-rw-r--r--drivers/media/dvb-frontends/atbm8830.c3
-rw-r--r--drivers/media/dvb-frontends/au8522_dig.c4
-rw-r--r--drivers/media/dvb-frontends/au8522_priv.h2
-rw-r--r--drivers/media/dvb-frontends/bcm3510.c6
-rw-r--r--drivers/media/dvb-frontends/cx22700.c9
-rw-r--r--drivers/media/dvb-frontends/cx22702.c2
-rw-r--r--drivers/media/dvb-frontends/cx24110.c19
-rw-r--r--drivers/media/dvb-frontends/cx24116.c46
-rw-r--r--drivers/media/dvb-frontends/cx24117.c42
-rw-r--r--drivers/media/dvb-frontends/cx24120.c1595
-rw-r--r--drivers/media/dvb-frontends/cx24120.h58
-rw-r--r--drivers/media/dvb-frontends/cx24123.c18
-rw-r--r--drivers/media/dvb-frontends/cx24123.h2
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_c.c2
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_core.c5
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_priv.h8
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_t.c2
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_t2.c2
-rw-r--r--drivers/media/dvb-frontends/dib0070.c575
-rw-r--r--drivers/media/dvb-frontends/dib0090.c4
-rw-r--r--drivers/media/dvb-frontends/dib3000mb.c7
-rw-r--r--drivers/media/dvb-frontends/dib3000mc.c20
-rw-r--r--drivers/media/dvb-frontends/dib7000m.c2
-rw-r--r--drivers/media/dvb-frontends/dib7000p.c6
-rw-r--r--drivers/media/dvb-frontends/dib8000.c10
-rw-r--r--drivers/media/dvb-frontends/dib8000.h2
-rw-r--r--drivers/media/dvb-frontends/dib9000.c4
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.c42
-rw-r--r--drivers/media/dvb-frontends/drxd_hard.c2
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.c11
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.h2
-rw-r--r--drivers/media/dvb-frontends/ds3000.c13
-rw-r--r--drivers/media/dvb-frontends/dvb_dummy_fe.c9
-rw-r--r--drivers/media/dvb-frontends/ec100.c2
-rw-r--r--drivers/media/dvb-frontends/hd29l2.c2
-rw-r--r--drivers/media/dvb-frontends/hd29l2_priv.h2
-rw-r--r--drivers/media/dvb-frontends/isl6405.c3
-rw-r--r--drivers/media/dvb-frontends/isl6421.c6
-rw-r--r--drivers/media/dvb-frontends/l64781.c2
-rw-r--r--drivers/media/dvb-frontends/lg2160.c2
-rw-r--r--drivers/media/dvb-frontends/lgdt3305.c4
-rw-r--r--drivers/media/dvb-frontends/lgdt3306a.c11
-rw-r--r--drivers/media/dvb-frontends/lgdt330x.c8
-rw-r--r--drivers/media/dvb-frontends/lgs8gl5.c2
-rw-r--r--drivers/media/dvb-frontends/lgs8gxx.c3
-rw-r--r--drivers/media/dvb-frontends/lnbp21.c4
-rw-r--r--drivers/media/dvb-frontends/lnbp22.c3
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.c1275
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.h67
-rw-r--r--drivers/media/dvb-frontends/m88ds3103_priv.h20
-rw-r--r--drivers/media/dvb-frontends/m88rs2000.c19
-rw-r--r--drivers/media/dvb-frontends/mb86a16.c7
-rw-r--r--drivers/media/dvb-frontends/mb86a16.h3
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.c6
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.h2
-rw-r--r--drivers/media/dvb-frontends/mt312.c17
-rw-r--r--drivers/media/dvb-frontends/mt352.c2
-rw-r--r--drivers/media/dvb-frontends/nxt200x.c2
-rw-r--r--drivers/media/dvb-frontends/nxt6000.c12
-rw-r--r--drivers/media/dvb-frontends/or51132.c6
-rw-r--r--drivers/media/dvb-frontends/or51211.c2
-rw-r--r--drivers/media/dvb-frontends/rtl2830.c2
-rw-r--r--drivers/media/dvb-frontends/rtl2830_priv.h2
-rw-r--r--drivers/media/dvb-frontends/rtl2832.c10
-rw-r--r--drivers/media/dvb-frontends/rtl2832.h2
-rw-r--r--drivers/media/dvb-frontends/rtl2832_priv.h51
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c120
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.h1
-rw-r--r--drivers/media/dvb-frontends/s5h1409.c6
-rw-r--r--drivers/media/dvb-frontends/s5h1411.c6
-rw-r--r--drivers/media/dvb-frontends/s5h1420.c43
-rw-r--r--drivers/media/dvb-frontends/s5h1432.c4
-rw-r--r--drivers/media/dvb-frontends/s921.c6
-rw-r--r--drivers/media/dvb-frontends/s921.h2
-rw-r--r--drivers/media/dvb-frontends/si2165.c2
-rw-r--r--drivers/media/dvb-frontends/si2168.c144
-rw-r--r--drivers/media/dvb-frontends/si2168.h3
-rw-r--r--drivers/media/dvb-frontends/si2168_priv.h6
-rw-r--r--drivers/media/dvb-frontends/si21xx.c10
-rw-r--r--drivers/media/dvb-frontends/sp8870.c3
-rw-r--r--drivers/media/dvb-frontends/sp887x.c2
-rw-r--r--drivers/media/dvb-frontends/stb0899_drv.c8
-rw-r--r--drivers/media/dvb-frontends/stv0288.c39
-rw-r--r--drivers/media/dvb-frontends/stv0297.c19
-rw-r--r--drivers/media/dvb-frontends/stv0299.c34
-rw-r--r--drivers/media/dvb-frontends/stv0367.c12
-rw-r--r--drivers/media/dvb-frontends/stv0367_priv.h2
-rw-r--r--drivers/media/dvb-frontends/stv0900_core.c6
-rw-r--r--drivers/media/dvb-frontends/stv0900_sw.c6
-rw-r--r--drivers/media/dvb-frontends/stv090x.c5
-rw-r--r--drivers/media/dvb-frontends/stv6110.c2
-rw-r--r--drivers/media/dvb-frontends/tc90522.c17
-rw-r--r--drivers/media/dvb-frontends/tda10021.c9
-rw-r--r--drivers/media/dvb-frontends/tda10023.c5
-rw-r--r--drivers/media/dvb-frontends/tda10048.c2
-rw-r--r--drivers/media/dvb-frontends/tda1004x.c5
-rw-r--r--drivers/media/dvb-frontends/tda10071.c117
-rw-r--r--drivers/media/dvb-frontends/tda10071.h29
-rw-r--r--drivers/media/dvb-frontends/tda10071_priv.h11
-rw-r--r--drivers/media/dvb-frontends/tda10086.c13
-rw-r--r--drivers/media/dvb-frontends/tda8083.c38
-rw-r--r--drivers/media/dvb-frontends/ts2020.c591
-rw-r--r--drivers/media/dvb-frontends/ts2020.h17
-rw-r--r--drivers/media/dvb-frontends/ves1820.c6
-rw-r--r--drivers/media/dvb-frontends/ves1x93.c15
-rw-r--r--drivers/media/dvb-frontends/zl10353.c12
-rw-r--r--drivers/media/firewire/firedtv-fe.c8
-rw-r--r--drivers/media/firewire/firedtv.h4
-rw-r--r--drivers/media/i2c/Kconfig4
-rw-r--r--drivers/media/i2c/adp1653.c100
-rw-r--r--drivers/media/i2c/adv7170.c42
-rw-r--r--drivers/media/i2c/adv7175.c42
-rw-r--r--drivers/media/i2c/adv7183.c61
-rw-r--r--drivers/media/i2c/adv7511.c160
-rw-r--r--drivers/media/i2c/adv7604.c192
-rw-r--r--drivers/media/i2c/adv7842.c309
-rw-r--r--drivers/media/i2c/ak881x.c39
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c17
-rw-r--r--drivers/media/i2c/ml86v7667.c29
-rw-r--r--drivers/media/i2c/mt9v011.c53
-rw-r--r--drivers/media/i2c/ov2659.c38
-rw-r--r--drivers/media/i2c/ov7670.c65
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c2
-rw-r--r--drivers/media/i2c/s5k5baf.c4
-rw-r--r--drivers/media/i2c/s5k6aa.c2
-rw-r--r--drivers/media/i2c/saa6752hs.c42
-rw-r--r--drivers/media/i2c/saa7115.c16
-rw-r--r--drivers/media/i2c/saa717x.c20
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c38
-rw-r--r--drivers/media/i2c/soc_camera/imx074.c66
-rw-r--r--drivers/media/i2c/soc_camera/mt9m001.c43
-rw-r--r--drivers/media/i2c/soc_camera/mt9m111.c57
-rw-r--r--drivers/media/i2c/soc_camera/mt9t031.c74
-rw-r--r--drivers/media/i2c/soc_camera/mt9t112.c41
-rw-r--r--drivers/media/i2c/soc_camera/mt9v022.c43
-rw-r--r--drivers/media/i2c/soc_camera/ov2640.c62
-rw-r--r--drivers/media/i2c/soc_camera/ov5642.c60
-rw-r--r--drivers/media/i2c/soc_camera/ov6650.c43
-rw-r--r--drivers/media/i2c/soc_camera/ov772x.c41
-rw-r--r--drivers/media/i2c/soc_camera/ov9640.c32
-rw-r--r--drivers/media/i2c/soc_camera/ov9740.c35
-rw-r--r--drivers/media/i2c/soc_camera/rj54n1cb0c.c66
-rw-r--r--drivers/media/i2c/soc_camera/tw9910.c41
-rw-r--r--drivers/media/i2c/sr030pc30.c62
-rw-r--r--drivers/media/i2c/tvaudio.c2
-rw-r--r--drivers/media/i2c/tvp514x.c55
-rw-r--r--drivers/media/i2c/tvp5150.c30
-rw-r--r--drivers/media/i2c/tvp7002.c48
-rw-r--r--drivers/media/i2c/vs6624.c55
-rw-r--r--drivers/media/pci/Kconfig2
-rw-r--r--drivers/media/pci/Makefile2
-rw-r--r--drivers/media/pci/bt8xx/bttv-audio-hook.c443
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c5
-rw-r--r--drivers/media/pci/bt8xx/dst.c25
-rw-r--r--drivers/media/pci/bt8xx/dst_ca.c138
-rw-r--r--drivers/media/pci/bt8xx/dst_common.h12
-rw-r--r--drivers/media/pci/cobalt/Kconfig18
-rw-r--r--drivers/media/pci/cobalt/Makefile5
-rw-r--r--drivers/media/pci/cobalt/cobalt-alsa-main.c162
-rw-r--r--drivers/media/pci/cobalt/cobalt-alsa-pcm.c603
-rw-r--r--drivers/media/pci/cobalt/cobalt-alsa-pcm.h22
-rw-r--r--drivers/media/pci/cobalt/cobalt-alsa.h41
-rw-r--r--drivers/media/pci/cobalt/cobalt-cpld.c341
-rw-r--r--drivers/media/pci/cobalt/cobalt-cpld.h29
-rw-r--r--drivers/media/pci/cobalt/cobalt-driver.c832
-rw-r--r--drivers/media/pci/cobalt/cobalt-driver.h380
-rw-r--r--drivers/media/pci/cobalt/cobalt-flash.c128
-rw-r--r--drivers/media/pci/cobalt/cobalt-flash.h29
-rw-r--r--drivers/media/pci/cobalt/cobalt-i2c.c396
-rw-r--r--drivers/media/pci/cobalt/cobalt-i2c.h25
-rw-r--r--drivers/media/pci/cobalt/cobalt-irq.c258
-rw-r--r--drivers/media/pci/cobalt/cobalt-irq.h25
-rw-r--r--drivers/media/pci/cobalt/cobalt-omnitek.c341
-rw-r--r--drivers/media/pci/cobalt/cobalt-omnitek.h62
-rw-r--r--drivers/media/pci/cobalt/cobalt-v4l2.c1272
-rw-r--r--drivers/media/pci/cobalt/cobalt-v4l2.h22
-rw-r--r--drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h115
-rw-r--r--drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h44
-rw-r--r--drivers/media/pci/cobalt/m00389_cvi_memmap_package.h59
-rw-r--r--drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h44
-rw-r--r--drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h57
-rw-r--r--drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h53
-rw-r--r--drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h88
-rw-r--r--drivers/media/pci/cx18/cx18-av-core.c16
-rw-r--r--drivers/media/pci/cx18/cx18-controls.c13
-rw-r--r--drivers/media/pci/cx18/cx18-driver.c4
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c12
-rw-r--r--drivers/media/pci/cx18/cx18-streams.c1
-rw-r--r--drivers/media/pci/cx23885/altera-ci.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c150
-rw-r--r--drivers/media/pci/cx23885/cx23885-f300.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-f300.h2
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c12
-rw-r--r--drivers/media/pci/cx23885/cx23885.h3
-rw-r--r--drivers/media/pci/cx25821/cx25821-medusa-reg.h6
-rw-r--r--drivers/media/pci/cx88/cx88-core.c2
-rw-r--r--drivers/media/pci/cx88/cx88-dvb.c12
-rw-r--r--drivers/media/pci/cx88/cx88-mpeg.c6
-rw-r--r--drivers/media/pci/cx88/cx88-vbi.c6
-rw-r--r--drivers/media/pci/cx88/cx88-video.c9
-rw-r--r--drivers/media/pci/cx88/cx88.h6
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c3
-rw-r--r--drivers/media/pci/dm1105/dm1105.c3
-rw-r--r--drivers/media/pci/dt3155/Kconfig13
-rw-r--r--drivers/media/pci/dt3155/Makefile1
-rw-r--r--drivers/media/pci/dt3155/dt3155.c631
-rw-r--r--drivers/media/pci/dt3155/dt3155.h (renamed from drivers/staging/media/dt3155v4l/dt3155v4l.h)64
-rw-r--r--drivers/media/pci/ivtv/Kconfig3
-rw-r--r--drivers/media/pci/ivtv/ivtv-controls.c12
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.c4
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.h3
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c15
-rw-r--r--drivers/media/pci/ivtv/ivtvfb.c58
-rw-r--r--drivers/media/pci/mantis/hopper_cards.c14
-rw-r--r--drivers/media/pci/mantis/mantis_cards.c94
-rw-r--r--drivers/media/pci/mantis/mantis_common.h33
-rw-r--r--drivers/media/pci/mantis/mantis_dma.c5
-rw-r--r--drivers/media/pci/mantis/mantis_i2c.c12
-rw-r--r--drivers/media/pci/mantis/mantis_input.c110
-rw-r--r--drivers/media/pci/mantis/mantis_input.h24
-rw-r--r--drivers/media/pci/mantis/mantis_pcmcia.c4
-rw-r--r--drivers/media/pci/mantis/mantis_uart.c61
-rw-r--r--drivers/media/pci/mantis/mantis_vp1034.c2
-rw-r--r--drivers/media/pci/mantis/mantis_vp1034.h3
-rw-r--r--drivers/media/pci/ngene/ngene-core.c10
-rw-r--r--drivers/media/pci/ngene/ngene.h2
-rw-r--r--drivers/media/pci/pt1/pt1.c6
-rw-r--r--drivers/media/pci/pt1/va1j5jf8007s.c4
-rw-r--r--drivers/media/pci/pt1/va1j5jf8007t.c4
-rw-r--r--drivers/media/pci/pt3/pt3.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-alsa.c55
-rw-r--r--drivers/media/pci/saa7134/saa7134-cards.c150
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c161
-rw-r--r--drivers/media/pci/saa7134/saa7134-dvb.c122
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c55
-rw-r--r--drivers/media/pci/saa7134/saa7134-go7007.c11
-rw-r--r--drivers/media/pci/saa7134/saa7134-i2c.c87
-rw-r--r--drivers/media/pci/saa7134/saa7134-input.c59
-rw-r--r--drivers/media/pci/saa7134/saa7134-ts.c24
-rw-r--r--drivers/media/pci/saa7134/saa7134-tvaudio.c168
-rw-r--r--drivers/media/pci/saa7134/saa7134-vbi.c14
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c43
-rw-r--r--drivers/media/pci/saa7134/saa7134.h6
-rw-r--r--drivers/media/pci/saa7164/saa7164-api.c11
-rw-r--r--drivers/media/pci/saa7164/saa7164-buffer.c2
-rw-r--r--drivers/media/pci/saa7164/saa7164-bus.c2
-rw-r--r--drivers/media/pci/saa7164/saa7164-cards.c188
-rw-r--r--drivers/media/pci/saa7164/saa7164-cmd.c2
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c82
-rw-r--r--drivers/media/pci/saa7164/saa7164-dvb.c241
-rw-r--r--drivers/media/pci/saa7164/saa7164-encoder.c13
-rw-r--r--drivers/media/pci/saa7164/saa7164-fw.c2
-rw-r--r--drivers/media/pci/saa7164/saa7164-i2c.c9
-rw-r--r--drivers/media/pci/saa7164/saa7164-reg.h2
-rw-r--r--drivers/media/pci/saa7164/saa7164-types.h2
-rw-r--r--drivers/media/pci/saa7164/saa7164-vbi.c13
-rw-r--r--drivers/media/pci/saa7164/saa7164.h8
-rw-r--r--drivers/media/pci/smipcie/smipcie.c1
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c3
-rw-r--r--drivers/media/pci/ttpci/av7110.c18
-rw-r--r--drivers/media/pci/ttpci/av7110.h27
-rw-r--r--drivers/media/pci/ttpci/budget-core.c3
-rw-r--r--drivers/media/pci/ttpci/budget-patch.c15
-rw-r--r--drivers/media/pci/ttpci/budget.c12
-rw-r--r--drivers/media/pci/ttpci/budget.h2
-rw-r--r--drivers/media/pci/zoran/zoran_device.c13
-rw-r--r--drivers/media/platform/Kconfig12
-rw-r--r--drivers/media/platform/Makefile2
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe.c35
-rw-r--r--drivers/media/platform/blackfin/bfin_capture.c40
-rw-r--r--drivers/media/platform/coda/coda-bit.c4
-rw-r--r--drivers/media/platform/coda/coda-common.c27
-rw-r--r--drivers/media/platform/coda/coda.h3
-rw-r--r--drivers/media/platform/coda/trace.h2
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c9
-rw-r--r--drivers/media/platform/davinci/vpfe_capture.c19
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.c2
-rw-r--r--drivers/media/platform/exynos4-is/Kconfig1
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c2
-rw-r--r--drivers/media/platform/fsl-viu.c2
-rw-r--r--drivers/media/platform/m2m-deinterlace.c1
-rw-r--r--drivers/media/platform/marvell-ccic/cafe-driver.c13
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c480
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.h3
-rw-r--r--drivers/media/platform/marvell-ccic/mmp-driver.c1
-rw-r--r--drivers/media/platform/omap/omap_vout.c10
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c4
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c13
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.c2
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c2
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c6
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c4
-rw-r--r--drivers/media/platform/s5p-tv/hdmi_drv.c14
-rw-r--r--drivers/media/platform/s5p-tv/mixer_drv.c15
-rw-r--r--drivers/media/platform/s5p-tv/sdo_drv.c14
-rw-r--r--drivers/media/platform/sh_vou.c75
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c74
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c113
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c105
-rw-r--r--drivers/media/platform/soc_camera/omap1_camera.c106
-rw-r--r--drivers/media/platform/soc_camera/pxa_camera.c99
-rw-r--r--drivers/media/platform/soc_camera/rcar_vin.c113
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c115
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_csi2.c35
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c30
-rw-r--r--drivers/media/platform/soc_camera/soc_camera_platform.c24
-rw-r--r--drivers/media/platform/soc_camera/soc_scale_crop.c37
-rw-r--r--drivers/media/platform/sti/bdisp/Makefile3
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp-debug.c679
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp-filter.h346
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp-hw.c823
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp-reg.h235
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp-v4l2.c1416
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp.h216
-rw-r--r--drivers/media/platform/via-camera.c19
-rw-r--r--drivers/media/platform/vim2m.c12
-rw-r--r--drivers/media/platform/vivid/vivid-core.c20
-rw-r--r--drivers/media/platform/vivid/vivid-core.h6
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.c139
-rw-r--r--drivers/media/platform/vivid/vivid-radio-rx.c2
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.c96
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.h2
-rw-r--r--drivers/media/platform/vivid/vivid-tpg-colors.c478
-rw-r--r--drivers/media/platform/vivid/vivid-tpg-colors.h4
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.c313
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.h20
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.c31
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.c68
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.c7
-rw-r--r--drivers/media/platform/xilinx/Kconfig2
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c4
-rw-r--r--drivers/media/radio/radio-si476x.c4
-rw-r--r--drivers/media/radio/radio-timb.c4
-rw-r--r--drivers/media/radio/si470x/radio-si470x-i2c.c9
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c6
-rw-r--r--drivers/media/radio/si470x/radio-si470x.h8
-rw-r--r--drivers/media/radio/si4713/si4713.c4
-rw-r--r--drivers/media/radio/wl128x/Kconfig4
-rw-r--r--drivers/media/radio/wl128x/fmdrv.h2
-rw-r--r--drivers/media/rc/fintek-cir.c1
-rw-r--r--drivers/media/rc/gpio-ir-recv.c4
-rw-r--r--drivers/media/rc/ir-hix5hd2.c8
-rw-r--r--drivers/media/rc/ir-rc5-decoder.c116
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c122
-rw-r--r--drivers/media/rc/ir-sony-decoder.c28
-rw-r--r--drivers/media/rc/keymaps/Makefile4
-rw-r--r--drivers/media/rc/keymaps/rc-technisat-ts35.c76
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c88
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c86
-rw-r--r--drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c98
-rw-r--r--drivers/media/rc/nuvoton-cir.c127
-rw-r--r--drivers/media/rc/nuvoton-cir.h1
-rw-r--r--drivers/media/rc/rc-core-priv.h36
-rw-r--r--drivers/media/rc/rc-ir-raw.c139
-rw-r--r--drivers/media/rc/rc-loopback.c36
-rw-r--r--drivers/media/rc/rc-main.c9
-rw-r--r--drivers/media/rc/redrat3.c7
-rw-r--r--drivers/media/rc/st_rc.c12
-rw-r--r--drivers/media/rc/streamzap.c6
-rw-r--r--drivers/media/tuners/Kconfig5
-rw-r--r--drivers/media/tuners/e4000.c592
-rw-r--r--drivers/media/tuners/e4000.h1
-rw-r--r--drivers/media/tuners/e4000_priv.h11
-rw-r--r--drivers/media/tuners/fc0013.c2
-rw-r--r--drivers/media/tuners/fc2580.c781
-rw-r--r--drivers/media/tuners/fc2580.h40
-rw-r--r--drivers/media/tuners/fc2580_priv.h36
-rw-r--r--drivers/media/tuners/msi001.c267
-rw-r--r--drivers/media/tuners/qt1010.c8
-rw-r--r--drivers/media/tuners/r820t.c4
-rw-r--r--drivers/media/tuners/si2157.c44
-rw-r--r--drivers/media/tuners/si2157.h6
-rw-r--r--drivers/media/tuners/si2157_priv.h2
-rw-r--r--drivers/media/tuners/tua9001.c331
-rw-r--r--drivers/media/tuners/tua9001.h35
-rw-r--r--drivers/media/tuners/tua9001_priv.h19
-rw-r--r--drivers/media/tuners/tuner-i2c.h10
-rw-r--r--drivers/media/tuners/tuner-xc2028.c2
-rw-r--r--drivers/media/usb/as102/as102_drv.c1
-rw-r--r--drivers/media/usb/au0828/au0828-cards.c2
-rw-r--r--drivers/media/usb/au0828/au0828-core.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c21
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-avcore.c44
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c56
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-core.c30
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dvb.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-vbi.c3
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c26
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h1
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c58
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvbsky.c18
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.c112
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c14
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c193
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.h5
-rw-r--r--drivers/media/usb/dvb-usb/af9005-fe.c7
-rw-r--r--drivers/media/usb/dvb-usb/az6027.c3
-rw-r--r--drivers/media/usb/dvb-usb/cinergyT2-fe.c2
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.c1
-rw-r--r--drivers/media/usb/dvb-usb/dib0700.h2
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_core.c70
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c145
-rw-r--r--drivers/media/usb/dvb-usb/dtt200u-fe.c7
-rw-r--r--drivers/media/usb/dvb-usb/dw2102.c55
-rw-r--r--drivers/media/usb/dvb-usb/friio-fe.c3
-rw-r--r--drivers/media/usb/dvb-usb/gp8psk-fe.c13
-rw-r--r--drivers/media/usb/dvb-usb/opera1.c3
-rw-r--r--drivers/media/usb/dvb-usb/technisat-usb2.c2
-rw-r--r--drivers/media/usb/dvb-usb/vp702x-fe.c17
-rw-r--r--drivers/media/usb/dvb-usb/vp702x.c7
-rw-r--r--drivers/media/usb/dvb-usb/vp7045-fe.c3
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c12
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c216
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c1
-rw-r--r--drivers/media/usb/go7007/go7007-driver.c3
-rw-r--r--drivers/media/usb/go7007/go7007-usb.c4
-rw-r--r--drivers/media/usb/go7007/go7007-v4l2.c12
-rw-r--r--drivers/media/usb/go7007/s2250-board.c18
-rw-r--r--drivers/media/usb/gspca/benq.c4
-rw-r--r--drivers/media/usb/gspca/sn9c2028.c241
-rw-r--r--drivers/media/usb/gspca/sn9c2028.h18
-rw-r--r--drivers/media/usb/gspca/sonixj.c2
-rw-r--r--drivers/media/usb/gspca/stk014.c2
-rw-r--r--drivers/media/usb/gspca/xirlink_cit.c12
-rw-r--r--drivers/media/usb/gspca/zc3xx.c16
-rw-r--r--drivers/media/usb/msi2500/msi2500.c655
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-context.c3
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c35
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-io.c30
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ioread.c24
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c3
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c5
-rw-r--r--drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c9
-rw-r--r--drivers/media/usb/ttusb-dec/ttusb_dec.c4
-rw-r--r--drivers/media/usb/ttusb-dec/ttusbdecfe.c10
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c12
-rw-r--r--drivers/media/usb/usbvision/usbvision-core.c4
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c17
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c2
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c12
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c16
-rw-r--r--drivers/media/usb/uvc/uvc_video.c8
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h7
-rw-r--r--drivers/media/usb/zr364xx/zr364xx.c3
-rw-r--r--drivers/media/v4l2-core/Kconfig2
-rw-r--r--drivers/media/v4l2-core/v4l2-dv-timings.c117
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c214
-rw-r--r--drivers/media/v4l2-core/v4l2-mem2mem.c38
-rw-r--r--drivers/media/v4l2-core/v4l2-of.c100
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c63
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-contig.c6
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-sg.c22
-rw-r--r--drivers/media/v4l2-core/videobuf2-vmalloc.c6
-rw-r--r--drivers/memory/Kconfig8
-rw-r--r--drivers/memory/omap-gpmc.c6
-rw-r--r--drivers/memory/tegra/Kconfig10
-rw-r--r--drivers/memory/tegra/Makefile3
-rw-r--r--drivers/memory/tegra/mc.c143
-rw-r--r--drivers/memory/tegra/mc.h4
-rw-r--r--drivers/memory/tegra/tegra114.c32
-rw-r--r--drivers/memory/tegra/tegra124-emc.c1140
-rw-r--r--drivers/memory/tegra/tegra124.c123
-rw-r--r--drivers/memory/tegra/tegra30.c32
-rw-r--r--drivers/message/fusion/mptbase.c24
-rw-r--r--drivers/message/fusion/mptbase.h1
-rw-r--r--drivers/message/fusion/mptsas.c4
-rw-r--r--drivers/mfd/88pm860x-core.c2
-rw-r--r--drivers/mfd/Kconfig12
-rw-r--r--drivers/mfd/Makefile6
-rw-r--r--drivers/mfd/ab8500-core.c2
-rw-r--r--drivers/mfd/ab8500-debugfs.c2
-rw-r--r--drivers/mfd/ab8500-gpadc.c6
-rw-r--r--drivers/mfd/arizona-core.c361
-rw-r--r--drivers/mfd/arizona-irq.c2
-rw-r--r--drivers/mfd/axp20x.c100
-rw-r--r--drivers/mfd/cros_ec.c173
-rw-r--r--drivers/mfd/cros_ec_i2c.c170
-rw-r--r--drivers/mfd/cros_ec_spi.c408
-rw-r--r--drivers/mfd/da9052-irq.c4
-rw-r--r--drivers/mfd/da9055-core.c6
-rw-r--r--drivers/mfd/da9063-core.c54
-rw-r--r--drivers/mfd/da9063-irq.c4
-rw-r--r--drivers/mfd/da9150-core.c4
-rw-r--r--drivers/mfd/db8500-prcmu.c2
-rw-r--r--drivers/mfd/htc-i2cpld.c3
-rw-r--r--drivers/mfd/intel_soc_pmic_core.h2
-rw-r--r--drivers/mfd/intel_soc_pmic_crc.c2
-rw-r--r--drivers/mfd/janz-cmodio.c4
-rw-r--r--drivers/mfd/lp8788-irq.c2
-rw-r--r--drivers/mfd/lpc_ich.c8
-rw-r--r--drivers/mfd/max8925-core.c2
-rw-r--r--drivers/mfd/max8997-irq.c2
-rw-r--r--drivers/mfd/max8998-irq.c2
-rw-r--r--drivers/mfd/mc13xxx-core.c2
-rw-r--r--drivers/mfd/mfd-core.c8
-rw-r--r--drivers/mfd/mt6397-core.c23
-rw-r--r--drivers/mfd/si476x-i2c.c3
-rw-r--r--drivers/mfd/stmpe.c2
-rw-r--r--drivers/mfd/tc3589x.c2
-rw-r--r--drivers/mfd/tps6586x.c2
-rw-r--r--drivers/mfd/twl4030-irq.c2
-rw-r--r--drivers/mfd/twl4030-power.c45
-rw-r--r--drivers/mfd/twl6030-irq.c2
-rw-r--r--drivers/mfd/ucb1x00-core.c3
-rw-r--r--drivers/mfd/wm831x-auxadc.c3
-rw-r--r--drivers/mfd/wm831x-irq.c2
-rw-r--r--drivers/mfd/wm8350-core.c3
-rw-r--r--drivers/mfd/wm8994-irq.c6
-rw-r--r--drivers/misc/Kconfig1
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/altera-stapl/altera.c2
-rw-r--r--drivers/misc/carma/Kconfig15
-rw-r--r--drivers/misc/carma/Makefile2
-rw-r--r--drivers/misc/carma/carma-fpga-program.c1182
-rw-r--r--drivers/misc/carma/carma-fpga.c1507
-rw-r--r--drivers/misc/cxl/Kconfig5
-rw-r--r--drivers/misc/cxl/Makefile4
-rw-r--r--drivers/misc/cxl/api.c331
-rw-r--r--drivers/misc/cxl/base.c2
-rw-r--r--drivers/misc/cxl/context.c36
-rw-r--r--drivers/misc/cxl/cxl.h38
-rw-r--r--drivers/misc/cxl/fault.c34
-rw-r--r--drivers/misc/cxl/file.c48
-rw-r--r--drivers/misc/cxl/irq.c37
-rw-r--r--drivers/misc/cxl/main.c2
-rw-r--r--drivers/misc/cxl/native.c83
-rw-r--r--drivers/misc/cxl/pci.c129
-rw-r--r--drivers/misc/cxl/sysfs.c35
-rw-r--r--drivers/misc/cxl/vphb.c270
-rw-r--r--drivers/misc/kgdbts.c2
-rw-r--r--drivers/misc/mei/amthif.c28
-rw-r--r--drivers/misc/mei/bus.c150
-rw-r--r--drivers/misc/mei/client.c473
-rw-r--r--drivers/misc/mei/client.h114
-rw-r--r--drivers/misc/mei/debugfs.c15
-rw-r--r--drivers/misc/mei/hbm.c16
-rw-r--r--drivers/misc/mei/hw-me.c59
-rw-r--r--drivers/misc/mei/hw-txe.c33
-rw-r--r--drivers/misc/mei/init.c8
-rw-r--r--drivers/misc/mei/interrupt.c95
-rw-r--r--drivers/misc/mei/main.c57
-rw-r--r--drivers/misc/mei/mei_dev.h102
-rw-r--r--drivers/misc/mei/nfc.c223
-rw-r--r--drivers/misc/mei/pci-txe.c2
-rw-r--r--drivers/misc/mei/wd.c22
-rw-r--r--drivers/misc/mic/Kconfig40
-rw-r--r--drivers/misc/mic/Makefile3
-rw-r--r--drivers/misc/mic/bus/Makefile1
-rw-r--r--drivers/misc/mic/bus/scif_bus.c210
-rw-r--r--drivers/misc/mic/bus/scif_bus.h129
-rw-r--r--drivers/misc/mic/card/mic_device.c132
-rw-r--r--drivers/misc/mic/card/mic_device.h11
-rw-r--r--drivers/misc/mic/card/mic_x100.c61
-rw-r--r--drivers/misc/mic/card/mic_x100.h1
-rw-r--r--drivers/misc/mic/common/mic_dev.h3
-rw-r--r--drivers/misc/mic/host/mic_boot.c264
-rw-r--r--drivers/misc/mic/host/mic_debugfs.c13
-rw-r--r--drivers/misc/mic/host/mic_device.h11
-rw-r--r--drivers/misc/mic/host/mic_intr.h3
-rw-r--r--drivers/misc/mic/host/mic_main.c6
-rw-r--r--drivers/misc/mic/host/mic_smpt.c7
-rw-r--r--drivers/misc/mic/host/mic_smpt.h1
-rw-r--r--drivers/misc/mic/host/mic_virtio.c6
-rw-r--r--drivers/misc/mic/host/mic_x100.c3
-rw-r--r--drivers/misc/mic/scif/Makefile15
-rw-r--r--drivers/misc/mic/scif/scif_api.c1276
-rw-r--r--drivers/misc/mic/scif/scif_debugfs.c85
-rw-r--r--drivers/misc/mic/scif/scif_epd.c353
-rw-r--r--drivers/misc/mic/scif/scif_epd.h160
-rw-r--r--drivers/misc/mic/scif/scif_fd.c303
-rw-r--r--drivers/misc/mic/scif/scif_main.c388
-rw-r--r--drivers/misc/mic/scif/scif_main.h254
-rw-r--r--drivers/misc/mic/scif/scif_map.h113
-rw-r--r--drivers/misc/mic/scif/scif_nm.c237
-rw-r--r--drivers/misc/mic/scif/scif_nodeqp.c1312
-rw-r--r--drivers/misc/mic/scif/scif_nodeqp.h183
-rw-r--r--drivers/misc/mic/scif/scif_peer_bus.c124
-rw-r--r--drivers/misc/mic/scif/scif_peer_bus.h65
-rw-r--r--drivers/misc/mic/scif/scif_ports.c124
-rw-r--r--drivers/misc/mic/scif/scif_rb.c249
-rw-r--r--drivers/misc/mic/scif/scif_rb.h100
-rw-r--r--drivers/misc/spear13xx_pcie_gadget.c2
-rw-r--r--drivers/misc/sram.c137
-rw-r--r--drivers/misc/ti-st/st_kim.c3
-rw-r--r--drivers/mmc/card/block.c25
-rw-r--r--drivers/mmc/card/mmc_test.c104
-rw-r--r--drivers/mmc/card/queue.c6
-rw-r--r--drivers/mmc/card/queue.h1
-rw-r--r--drivers/mmc/core/core.c100
-rw-r--r--drivers/mmc/core/core.h4
-rw-r--r--drivers/mmc/core/host.c88
-rw-r--r--drivers/mmc/core/host.h6
-rw-r--r--drivers/mmc/core/mmc.c156
-rw-r--r--drivers/mmc/core/mmc_ops.c44
-rw-r--r--drivers/mmc/core/mmc_ops.h1
-rw-r--r--drivers/mmc/core/sd.c113
-rw-r--r--drivers/mmc/core/sdio.c90
-rw-r--r--drivers/mmc/core/sdio_bus.c12
-rw-r--r--drivers/mmc/host/Kconfig9
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/android-goldfish.c2
-rw-r--r--drivers/mmc/host/davinci_mmc.c2
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c2
-rw-r--r--drivers/mmc/host/dw_mmc-k3.c105
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c2
-rw-r--r--drivers/mmc/host/dw_mmc.c63
-rw-r--r--drivers/mmc/host/dw_mmc.h5
-rw-r--r--drivers/mmc/host/mtk-sd.c1462
-rw-r--r--drivers/mmc/host/mxcmmc.c6
-rw-r--r--drivers/mmc/host/mxs-mmc.c2
-rw-r--r--drivers/mmc/host/rtsx_pci_sdmmc.c2
-rw-r--r--drivers/mmc/host/rtsx_usb_sdmmc.c2
-rw-r--r--drivers/mmc/host/s3cmci.c2
-rw-r--r--drivers/mmc/host/sdhci-bcm2835.c12
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c94
-rw-r--r--drivers/mmc/host/sdhci-of-arasan.c7
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c11
-rw-r--r--drivers/mmc/host/sdhci-pci-data.c3
-rw-r--r--drivers/mmc/host/sdhci-pci.c109
-rw-r--r--drivers/mmc/host/sdhci-pci.h4
-rw-r--r--drivers/mmc/host/sdhci-pxav2.c4
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c10
-rw-r--r--drivers/mmc/host/sdhci-s3c.c2
-rw-r--r--drivers/mmc/host/sdhci-sirf.c44
-rw-r--r--drivers/mmc/host/sdhci-st.c2
-rw-r--r--drivers/mmc/host/sdhci.c151
-rw-r--r--drivers/mmc/host/sdhci.h7
-rw-r--r--drivers/mmc/host/sdhci_f_sdh30.c9
-rw-r--r--drivers/mmc/host/sh_mmcif.c296
-rw-r--r--drivers/mmc/host/tmio_mmc.c10
-rw-r--r--drivers/mmc/host/tmio_mmc_pio.c5
-rw-r--r--drivers/mtd/chips/Kconfig1
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c2
-rw-r--r--drivers/mtd/chips/cfi_util.c188
-rw-r--r--drivers/mtd/devices/Kconfig8
-rw-r--r--drivers/mtd/devices/Makefile1
-rw-r--r--drivers/mtd/devices/block2mtd.c1
-rw-r--r--drivers/mtd/devices/docg3.c18
-rw-r--r--drivers/mtd/devices/m25p80.c60
-rw-r--r--drivers/mtd/devices/powernv_flash.c285
-rw-r--r--drivers/mtd/devices/spear_smi.c4
-rw-r--r--drivers/mtd/maps/Kconfig2
-rw-r--r--drivers/mtd/maps/amd76xrom.c2
-rw-r--r--drivers/mtd/maps/dc21285.c4
-rw-r--r--drivers/mtd/maps/esb2rom.c2
-rw-r--r--drivers/mtd/maps/ichxrom.c2
-rw-r--r--drivers/mtd/maps/lantiq-flash.c4
-rw-r--r--drivers/mtd/maps/physmap_of.c4
-rw-r--r--drivers/mtd/mtd_blkdevs.c7
-rw-r--r--drivers/mtd/mtdcore.c62
-rw-r--r--drivers/mtd/nand/Kconfig10
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/brcmnand/Makefile6
-rw-r--r--drivers/mtd/nand/brcmnand/bcm63138_nand.c111
-rw-r--r--drivers/mtd/nand/brcmnand/brcmnand.c2246
-rw-r--r--drivers/mtd/nand/brcmnand/brcmnand.h73
-rw-r--r--drivers/mtd/nand/brcmnand/brcmstb_nand.c44
-rw-r--r--drivers/mtd/nand/brcmnand/iproc_nand.c150
-rw-r--r--drivers/mtd/nand/cs553x_nand.c12
-rw-r--r--drivers/mtd/nand/diskonchip.c37
-rw-r--r--drivers/mtd/nand/fsmc_nand.c8
-rw-r--r--drivers/mtd/nand/mpc5121_nfc.c2
-rw-r--r--drivers/mtd/nand/mxc_nand.c112
-rw-r--r--drivers/mtd/nand/nand_base.c48
-rw-r--r--drivers/mtd/nand/nand_bbt.c26
-rw-r--r--drivers/mtd/nand/nand_ids.c2
-rw-r--r--drivers/mtd/nand/nandsim.c10
-rw-r--r--drivers/mtd/nand/ndfc.c2
-rw-r--r--drivers/mtd/nand/plat_nand.c4
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c43
-rw-r--r--drivers/mtd/nand/r852.c6
-rw-r--r--drivers/mtd/nand/s3c2410.c2
-rw-r--r--drivers/mtd/nand/xway_nand.c4
-rw-r--r--drivers/mtd/onenand/samsung.c2
-rw-r--r--drivers/mtd/spi-nor/fsl-quadspi.c2
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c18
-rw-r--r--drivers/mtd/ubi/block.c16
-rw-r--r--drivers/mtd/ubi/build.c107
-rw-r--r--drivers/mtd/ubi/fastmap.c83
-rw-r--r--drivers/mtd/ubi/ubi.h2
-rw-r--r--drivers/mtd/ubi/vmt.c98
-rw-r--r--drivers/mtd/ubi/vtbl.c45
-rw-r--r--drivers/mtd/ubi/wl.c2
-rw-r--r--drivers/net/Kconfig14
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/arcnet/Kconfig4
-rw-r--r--drivers/net/bonding/bond_3ad.c26
-rw-r--r--drivers/net/bonding/bond_main.c55
-rw-r--r--drivers/net/bonding/bond_netlink.c66
-rw-r--r--drivers/net/bonding/bond_options.c91
-rw-r--r--drivers/net/bonding/bond_procfs.c93
-rw-r--r--drivers/net/bonding/bond_sysfs.c52
-rw-r--r--drivers/net/bonding/bond_sysfs_slave.c32
-rw-r--r--drivers/net/can/dev.c5
-rw-r--r--drivers/net/can/flexcan.c53
-rw-r--r--drivers/net/can/janz-ican3.c125
-rw-r--r--drivers/net/can/slcan.c1
-rw-r--r--drivers/net/can/spi/mcp251x.c9
-rw-r--r--drivers/net/can/vcan.c3
-rw-r--r--drivers/net/dsa/Kconfig12
-rw-r--r--drivers/net/dsa/bcm_sf2.c14
-rw-r--r--drivers/net/dsa/mv88e6123_61_65.c186
-rw-r--r--drivers/net/dsa/mv88e6131.c185
-rw-r--r--drivers/net/dsa/mv88e6171.c234
-rw-r--r--drivers/net/dsa/mv88e6352.c188
-rw-r--r--drivers/net/dsa/mv88e6xxx.c980
-rw-r--r--drivers/net/dsa/mv88e6xxx.h112
-rw-r--r--drivers/net/ethernet/3com/Kconfig18
-rw-r--r--drivers/net/ethernet/8390/Kconfig26
-rw-r--r--drivers/net/ethernet/Kconfig2
-rw-r--r--drivers/net/ethernet/Makefile2
-rw-r--r--drivers/net/ethernet/adaptec/Kconfig4
-rw-r--r--drivers/net/ethernet/adi/Kconfig2
-rw-r--r--drivers/net/ethernet/agere/Kconfig4
-rw-r--r--drivers/net/ethernet/allwinner/Kconfig3
-rw-r--r--drivers/net/ethernet/alteon/Kconfig4
-rw-r--r--drivers/net/ethernet/amd/Kconfig20
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-common.h155
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-dcb.c17
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-desc.c35
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-dev.c99
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-drv.c341
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c79
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-main.c411
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-mdio.c1332
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe.h236
-rw-r--r--drivers/net/ethernet/apm/xgene/Makefile2
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_hw.c43
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_hw.h8
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.c257
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.h30
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c200
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_ring2.h49
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c73
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c12
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h20
-rw-r--r--drivers/net/ethernet/apple/Kconfig7
-rw-r--r--drivers/net/ethernet/arc/Kconfig4
-rw-r--r--drivers/net/ethernet/atheros/Kconfig4
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig3
-rw-r--r--drivers/net/ethernet/broadcom/b44.h8
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.c170
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.h4
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.h3
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h16
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c59
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h31
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c67
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c7
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c2
-rw-r--r--drivers/net/ethernet/brocade/Kconfig4
-rw-r--r--drivers/net/ethernet/brocade/bna/Makefile2
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cee.c1
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cs.h14
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs.h11
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs_cna.h16
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h10
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.c71
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.h23
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c101
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_msgq.c10
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi.h84
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi_cna.h30
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi_enet.h176
-rw-r--r--drivers/net/ethernet/brocade/bna/bna.h199
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_enet.c101
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_hw_defs.h70
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_tx_rx.c673
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_types.h19
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c119
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.h4
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad_debugfs.c67
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad_ethtool.c15
-rw-r--r--drivers/net/ethernet/brocade/bna/cna.h62
-rw-r--r--drivers/net/ethernet/brocade/bna/cna_fwimg.c2
-rw-r--r--drivers/net/ethernet/cadence/Kconfig2
-rw-r--r--drivers/net/ethernet/cadence/macb.c61
-rw-r--r--drivers/net/ethernet/cadence/macb.h9
-rw-r--r--drivers/net/ethernet/cavium/Kconfig57
-rw-r--r--drivers/net/ethernet/cavium/Makefile5
-rw-r--r--drivers/net/ethernet/cavium/liquidio/Makefile16
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn66xx_device.c796
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn66xx_device.h107
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn66xx_regs.h535
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn68xx_device.c198
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn68xx_device.h33
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn68xx_regs.h51
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_ethtool.c1216
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_main.c3668
-rw-r--r--drivers/net/ethernet/cavium/liquidio/liquidio_common.h673
-rw-r--r--drivers/net/ethernet/cavium/liquidio/liquidio_image.h57
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_config.h424
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_console.c723
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_device.c1309
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_device.h649
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_droq.c989
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_droq.h426
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_iq.h319
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_main.h237
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c199
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.h75
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_network.h224
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_nic.c189
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_nic.h227
-rw-r--r--drivers/net/ethernet/cavium/liquidio/request_manager.c766
-rw-r--r--drivers/net/ethernet/cavium/liquidio/response_manager.c178
-rw-r--r--drivers/net/ethernet/cavium/liquidio/response_manager.h140
-rw-r--r--drivers/net/ethernet/cavium/thunder/Makefile11
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic.h423
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic_main.c932
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic_reg.h213
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c600
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_main.c1341
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_queues.c1545
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_queues.h381
-rw-r--r--drivers/net/ethernet/cavium/thunder/q_struct.h701
-rw-r--r--drivers/net/ethernet/cavium/thunder/thunder_bgx.c966
-rw-r--r--drivers/net/ethernet/cavium/thunder/thunder_bgx.h220
-rw-r--r--drivers/net/ethernet/chelsio/Kconfig4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c12
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h221
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c363
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c294
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c493
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sge.c382
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c2222
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.h38
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_msg.h86
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_regs.h184
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_values.h24
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h72
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h5
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c13
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/sge.c123
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h18
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c36
-rw-r--r--drivers/net/ethernet/cirrus/Kconfig12
-rw-r--r--drivers/net/ethernet/cisco/Kconfig4
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_clsf.c31
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_ethtool.c10
-rw-r--r--drivers/net/ethernet/dec/Kconfig4
-rw-r--r--drivers/net/ethernet/dec/tulip/Kconfig10
-rw-r--r--drivers/net/ethernet/dec/tulip/de4x5.c10
-rw-r--r--drivers/net/ethernet/dec/tulip/uli526x.c2
-rw-r--r--drivers/net/ethernet/dlink/Kconfig4
-rw-r--r--drivers/net/ethernet/dlink/dl2k.c4
-rw-r--r--drivers/net/ethernet/emulex/Kconfig4
-rw-r--r--drivers/net/ethernet/emulex/benet/Kconfig9
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h55
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c56
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h50
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c11
-rw-r--r--drivers/net/ethernet/emulex/benet/be_hw.h14
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c502
-rw-r--r--drivers/net/ethernet/emulex/benet/be_roce.c2
-rw-r--r--drivers/net/ethernet/emulex/benet/be_roce.h2
-rw-r--r--drivers/net/ethernet/ezchip/Kconfig26
-rw-r--r--drivers/net/ethernet/ezchip/Makefile1
-rw-r--r--drivers/net/ethernet/ezchip/nps_enet.c658
-rw-r--r--drivers/net/ethernet/ezchip/nps_enet.h336
-rw-r--r--drivers/net/ethernet/faraday/Kconfig4
-rw-r--r--drivers/net/ethernet/freescale/Kconfig4
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c82
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c1
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c33
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c53
-rw-r--r--drivers/net/ethernet/fujitsu/Kconfig4
-rw-r--r--drivers/net/ethernet/hisilicon/Kconfig4
-rw-r--r--drivers/net/ethernet/hisilicon/hip04_eth.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hix5hd2_gmac.c1
-rw-r--r--drivers/net/ethernet/hp/Kconfig8
-rw-r--r--drivers/net/ethernet/i825xx/Kconfig4
-rw-r--r--drivers/net/ethernet/ibm/Kconfig4
-rw-r--r--drivers/net/ethernet/ibm/emac/core.c10
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c41
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.h5
-rw-r--r--drivers/net/ethernet/intel/Kconfig4
-rw-r--r--drivers/net/ethernet/intel/e100.c6
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c19
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.c4
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/defines.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/e1000.h8
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c29
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c26
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.h11
-rw-r--r--drivers/net/ethernet/intel/e1000e/mac.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/mac.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/manage.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/manage.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c205
-rw-r--r--drivers/net/ethernet/intel/e1000e/nvm.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/nvm.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/param.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/ptp.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/regs.h4
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c5
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_iov.c38
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_main.c66
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_mbx.c5
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_netdev.c11
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_pci.c27
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_pf.c18
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_pf.h8
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_ptp.c13
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_type.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e.h5
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c30
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_fcoe.c11
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c43
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c146
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_type.h1
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c7
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_txrx.c160
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_txrx.h2
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_type.h1
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c38
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c7
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.c63
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c51
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c161
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c91
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type.h272
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c46
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c896
-rw-r--r--drivers/net/ethernet/marvell/Kconfig4
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c9
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c8
-rw-r--r--drivers/net/ethernet/mellanox/Kconfig4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c110
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cq.c13
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_cq.c56
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c30
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_port.c29
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_resources.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c13
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c400
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c285
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h17
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_stats.h10
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/profile.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/qp.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c208
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Kconfig14
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Makefile5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/alloc.c96
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cmd.c36
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cq.c18
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en.h521
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c679
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c860
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c1915
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c252
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tx.c350
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c105
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eq.c23
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/flow_table.c422
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw.c146
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mad.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c343
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mcg.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h21
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/port.c226
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/qp.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/srq.c444
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/transobj.c360
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/transobj.h64
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/uar.c44
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/vport.c345
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/wq.c183
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/wq.h171
-rw-r--r--drivers/net/ethernet/micrel/Kconfig4
-rw-r--r--drivers/net/ethernet/micrel/ksz884x.c4
-rw-r--r--drivers/net/ethernet/microchip/Kconfig4
-rw-r--r--drivers/net/ethernet/moxa/Kconfig4
-rw-r--r--drivers/net/ethernet/moxa/moxart_ether.c1
-rw-r--r--drivers/net/ethernet/myricom/Kconfig4
-rw-r--r--drivers/net/ethernet/natsemi/Kconfig7
-rw-r--r--drivers/net/ethernet/neterion/Kconfig4
-rw-r--r--drivers/net/ethernet/neterion/s2io.c6
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-traffic.c7
-rw-r--r--drivers/net/ethernet/nuvoton/Kconfig4
-rw-r--r--drivers/net/ethernet/nvidia/Kconfig8
-rw-r--r--drivers/net/ethernet/oki-semi/Kconfig4
-rw-r--r--drivers/net/ethernet/packetengines/Kconfig8
-rw-r--r--drivers/net/ethernet/pasemi/Kconfig4
-rw-r--r--drivers/net/ethernet/qlogic/Kconfig4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h3
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c77
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_main.c4
-rw-r--r--drivers/net/ethernet/qualcomm/Kconfig4
-rw-r--r--drivers/net/ethernet/qualcomm/qca_spi.c46
-rw-r--r--drivers/net/ethernet/rdc/Kconfig4
-rw-r--r--drivers/net/ethernet/realtek/Kconfig14
-rw-r--r--drivers/net/ethernet/renesas/Kconfig29
-rw-r--r--drivers/net/ethernet/renesas/Makefile4
-rw-r--r--drivers/net/ethernet/renesas/ravb.h832
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c1824
-rw-r--r--drivers/net/ethernet/renesas/ravb_ptp.c357
-rw-r--r--drivers/net/ethernet/rocker/rocker.c1615
-rw-r--r--drivers/net/ethernet/rocker/rocker.h28
-rw-r--r--drivers/net/ethernet/seeq/Kconfig4
-rw-r--r--drivers/net/ethernet/sfc/Kconfig9
-rw-r--r--drivers/net/ethernet/sfc/Makefile2
-rw-r--r--drivers/net/ethernet/sfc/ef10.c1147
-rw-r--r--drivers/net/ethernet/sfc/ef10_sriov.c783
-rw-r--r--drivers/net/ethernet/sfc/ef10_sriov.h69
-rw-r--r--drivers/net/ethernet/sfc/efx.c319
-rw-r--r--drivers/net/ethernet/sfc/efx.h15
-rw-r--r--drivers/net/ethernet/sfc/enum.h2
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c7
-rw-r--r--drivers/net/ethernet/sfc/falcon.c33
-rw-r--r--drivers/net/ethernet/sfc/farch.c64
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c228
-rw-r--r--drivers/net/ethernet/sfc/mcdi.h16
-rw-r--r--drivers/net/ethernet/sfc/mcdi_pcol.h434
-rw-r--r--drivers/net/ethernet/sfc/mcdi_port.c13
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h34
-rw-r--r--drivers/net/ethernet/sfc/nic.h251
-rw-r--r--drivers/net/ethernet/sfc/ptp.c40
-rw-r--r--drivers/net/ethernet/sfc/siena.c27
-rw-r--r--drivers/net/ethernet/sfc/siena_sriov.c156
-rw-r--r--drivers/net/ethernet/sfc/siena_sriov.h79
-rw-r--r--drivers/net/ethernet/sfc/sriov.c83
-rw-r--r--drivers/net/ethernet/sfc/sriov.h31
-rw-r--r--drivers/net/ethernet/sgi/Kconfig8
-rw-r--r--drivers/net/ethernet/silan/Kconfig4
-rw-r--r--drivers/net/ethernet/sis/Kconfig4
-rw-r--r--drivers/net/ethernet/smsc/Kconfig18
-rw-r--r--drivers/net/ethernet/stmicro/Kconfig4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig90
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile14
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/descs.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c41
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c365
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c99
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c24
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c350
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c21
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c29
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c25
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/norm_desc.c3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h14
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c108
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c19
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c129
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h9
-rw-r--r--drivers/net/ethernet/sun/Kconfig4
-rw-r--r--drivers/net/ethernet/sun/cassini.c1
-rw-r--r--drivers/net/ethernet/tehuti/Kconfig4
-rw-r--r--drivers/net/ethernet/ti/Kconfig8
-rw-r--r--drivers/net/ethernet/ti/cpsw.c9
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.c45
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.h2
-rw-r--r--drivers/net/ethernet/ti/netcp_core.c3
-rw-r--r--drivers/net/ethernet/tile/tilepro.c3
-rw-r--r--drivers/net/ethernet/toshiba/Kconfig4
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.c24
-rw-r--r--drivers/net/ethernet/toshiba/spider_net.c3
-rw-r--r--drivers/net/ethernet/tundra/Kconfig4
-rw-r--r--drivers/net/ethernet/via/Kconfig8
-rw-r--r--drivers/net/ethernet/via/via-rhine.c250
-rw-r--r--drivers/net/ethernet/wiznet/Kconfig4
-rw-r--r--drivers/net/ethernet/xilinx/Kconfig4
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_main.c16
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet.h108
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c288
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c30
-rw-r--r--drivers/net/ethernet/xircom/Kconfig4
-rw-r--r--drivers/net/ethernet/xscale/Kconfig4
-rw-r--r--drivers/net/fddi/skfp/srf.c2
-rw-r--r--drivers/net/geneve.c523
-rw-r--r--drivers/net/hamradio/bpqether.c1
-rw-r--r--drivers/net/hyperv/hyperv_net.h10
-rw-r--r--drivers/net/hyperv/netvsc.c55
-rw-r--r--drivers/net/hyperv/netvsc_drv.c97
-rw-r--r--drivers/net/hyperv/rndis_filter.c17
-rw-r--r--drivers/net/ieee802154/Kconfig10
-rw-r--r--drivers/net/ieee802154/Makefile1
-rw-r--r--drivers/net/ieee802154/at86rf230.c488
-rw-r--r--drivers/net/ieee802154/at86rf230.h220
-rw-r--r--drivers/net/ieee802154/atusb.c762
-rw-r--r--drivers/net/ieee802154/atusb.h84
-rw-r--r--drivers/net/ieee802154/cc2520.c153
-rw-r--r--drivers/net/ieee802154/fakelb.c212
-rw-r--r--drivers/net/ieee802154/mrf24j40.c12
-rw-r--r--drivers/net/ipvlan/ipvlan.h5
-rw-r--r--drivers/net/ipvlan/ipvlan_core.c138
-rw-r--r--drivers/net/ipvlan/ipvlan_main.c25
-rw-r--r--drivers/net/irda/irda-usb.c4
-rw-r--r--drivers/net/macvtap.c44
-rw-r--r--drivers/net/netconsole.c169
-rw-r--r--drivers/net/phy/Kconfig13
-rw-r--r--drivers/net/phy/Makefile2
-rw-r--r--drivers/net/phy/amd-xgbe-phy.c1901
-rw-r--r--drivers/net/phy/bcm7xxx.c7
-rw-r--r--drivers/net/phy/davicom.c13
-rw-r--r--drivers/net/phy/dp83867.c239
-rw-r--r--drivers/net/phy/icplus.c5
-rw-r--r--drivers/net/phy/marvell.c10
-rw-r--r--drivers/net/phy/mdio-bcm-unimac.c8
-rw-r--r--drivers/net/phy/mdio-bitbang.c7
-rw-r--r--drivers/net/phy/mdio-gpio.c1
-rw-r--r--drivers/net/phy/mdio-mux-gpio.c3
-rw-r--r--drivers/net/phy/micrel.c53
-rw-r--r--drivers/net/phy/phy.c34
-rw-r--r--drivers/net/phy/realtek.c68
-rw-r--r--drivers/net/ppp/pppoe.c4
-rw-r--r--drivers/net/ppp/pppox.c2
-rw-r--r--drivers/net/ppp/pptp.c6
-rw-r--r--drivers/net/team/team.c10
-rw-r--r--drivers/net/tun.c26
-rw-r--r--drivers/net/vmxnet3/vmxnet3_defs.h38
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c164
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h4
-rw-r--r--drivers/net/vxlan.c10
-rw-r--r--drivers/net/wan/cosa.c2
-rw-r--r--drivers/net/wan/dscc4.c9
-rw-r--r--drivers/net/wan/lapbether.c1
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/adm8211.c35
-rw-r--r--drivers/net/wireless/at76c50x-usb.c4
-rw-r--r--drivers/net/wireless/at76c50x-usb.h2
-rw-r--r--drivers/net/wireless/ath/ar5523/ar5523.c9
-rw-r--r--drivers/net/wireless/ath/ath.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile4
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c182
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h65
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c127
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c50
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.c98
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h132
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c208
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c34
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.c21
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h59
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c2840
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.h29
-rw-r--r--drivers/net/wireless/ath/ath10k/p2p.c156
-rw-r--r--drivers/net/wireless/ath/ath10k/p2p.h28
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c362
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h95
-rw-r--r--drivers/net/wireless/ath/ath10k/rx_desc.h22
-rw-r--r--drivers/net/wireless/ath/ath10k/spectral.c5
-rw-r--r--drivers/net/wireless/ath/ath10k/thermal.c134
-rw-r--r--drivers/net/wireless/ath/ath10k/thermal.h10
-rw-r--r--drivers/net/wireless/ath/ath10k/trace.h22
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c9
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-ops.h194
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c582
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h168
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c312
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h229
-rw-r--r--drivers/net/wireless/ath/ath10k/wow.c321
-rw-r--r--drivers/net/wireless/ath/ath10k/wow.h40
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h1
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c12
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c16
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c4
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c155
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_phy.c144
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.c740
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.h35
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c19
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c25
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c20
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c24
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c5
-rw-r--r--drivers/net/wireless/ath/carl9170/fw.c5
-rw-r--r--drivers/net/wireless/ath/carl9170/led.c2
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c27
-rw-r--r--drivers/net/wireless/ath/carl9170/usb.c5
-rw-r--r--drivers/net/wireless/ath/dfs_pattern_detector.c72
-rw-r--r--drivers/net/wireless/ath/dfs_pattern_detector.h4
-rw-r--r--drivers/net/wireless/ath/dfs_pri_detector.c4
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c12
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c4
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile1
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c174
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c115
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c33
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c8
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c105
-rw-r--r--drivers/net/wireless/ath/wil6210/pmc.c375
-rw-r--r--drivers/net/wireless/ath/wil6210/pmc.h27
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c50
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h24
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h33
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.c14
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.h3
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c75
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h50
-rw-r--r--drivers/net/wireless/b43/main.c16
-rw-r--r--drivers/net/wireless/b43legacy/main.c13
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c37
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c521
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/chip.c1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/commonring.c37
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/commonring.h3
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/core.c4
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/debug.c50
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/feature.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/feature.h8
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/firmware.c251
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/firmware.h6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/flowring.c5
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/flowring.h4
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h79
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c32
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/of.c11
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c203
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/pcie.c200
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio.c17
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c9
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c12
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.c2
-rw-r--r--drivers/net/wireless/brcm80211/include/brcm_hw_ids.h3
-rw-r--r--drivers/net/wireless/cw1200/main.c16
-rw-r--r--drivers/net/wireless/cw1200/sta.c10
-rw-r--r--drivers/net/wireless/iwlegacy/3945-mac.c10
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c16
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig12
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile1
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c33
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-7000.c25
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-8000.c71
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h45
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h15
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h107
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.c113
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h22
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex.c103
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c22
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c21
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h91
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h63
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c23
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c443
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h162
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c16
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c37
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c44
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c1418
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c33
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tt.c40
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c35
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c2
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c17
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h51
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/rx.c415
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c135
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c2
-rw-r--r--drivers/net/wireless/libertas/cfg.c13
-rw-r--r--drivers/net/wireless/libertas/cfg.h3
-rw-r--r--drivers/net/wireless/libertas/cmd.h3
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c13
-rw-r--r--drivers/net/wireless/libertas_tf/main.c9
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c77
-rw-r--r--drivers/net/wireless/mediatek/Kconfig10
-rw-r--r--drivers/net/wireless/mediatek/Makefile1
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/Kconfig6
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/Makefile9
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/core.c78
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/debugfs.c172
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/dma.c505
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/dma.h127
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/eeprom.c418
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/eeprom.h151
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/init.c628
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/initvals.h164
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/initvals_phy.h291
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mac.c573
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mac.h178
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/main.c413
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mcu.c534
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mcu.h94
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mt7601u.h390
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/phy.c1251
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/regs.h636
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/trace.c21
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/trace.h400
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/tx.c319
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/usb.c367
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/usb.h77
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/util.c42
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/util.h77
-rw-r--r--drivers/net/wireless/mwifiex/11h.c72
-rw-r--r--drivers/net/wireless/mwifiex/11n.c128
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.c7
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c136
-rw-r--r--drivers/net/wireless/mwifiex/Kconfig2
-rw-r--r--drivers/net/wireless/mwifiex/README6
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c592
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c50
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c368
-rw-r--r--drivers/net/wireless/mwifiex/debugfs.c165
-rw-r--r--drivers/net/wireless/mwifiex/decl.h7
-rw-r--r--drivers/net/wireless/mwifiex/ethtool.c97
-rw-r--r--drivers/net/wireless/mwifiex/fw.h71
-rw-r--r--drivers/net/wireless/mwifiex/ie.c102
-rw-r--r--drivers/net/wireless/mwifiex/init.c54
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h7
-rw-r--r--drivers/net/wireless/mwifiex/join.c254
-rw-r--r--drivers/net/wireless/mwifiex/main.c224
-rw-r--r--drivers/net/wireless/mwifiex/main.h96
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c589
-rw-r--r--drivers/net/wireless/mwifiex/scan.c377
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c458
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c159
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c223
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c194
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c147
-rw-r--r--drivers/net/wireless/mwifiex/sta_rx.c13
-rw-r--r--drivers/net/wireless/mwifiex/sta_tx.c18
-rw-r--r--drivers/net/wireless/mwifiex/tdls.c86
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c51
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c75
-rw-r--r--drivers/net/wireless/mwifiex/uap_event.c112
-rw-r--r--drivers/net/wireless/mwifiex/uap_txrx.c54
-rw-r--r--drivers/net/wireless/mwifiex/usb.c141
-rw-r--r--drivers/net/wireless/mwifiex/util.c84
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c107
-rw-r--r--drivers/net/wireless/mwl8k.c11
-rw-r--r--drivers/net/wireless/p54/fwio.c3
-rw-r--r--drivers/net/wireless/p54/led.c2
-rw-r--r--drivers/net/wireless/p54/main.c18
-rw-r--r--drivers/net/wireless/ray_cs.c2
-rw-r--r--drivers/net/wireless/rndis_wlan.c8
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mac80211.c7
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c13
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h10
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c92
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h5
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800soc.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c22
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c13
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c13
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/dev.c9
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/dev.c6
-rw-r--r--drivers/net/wireless/rtlwifi/Kconfig2
-rw-r--r--drivers/net/wireless/rtlwifi/base.c22
-rw-r--r--drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c7
-rw-r--r--drivers/net/wireless/rtlwifi/core.h3
-rw-r--r--drivers/net/wireless/rtlwifi/regd.c42
-rw-r--r--drivers/net/wireless/rtlwifi/regd.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/hw.c20
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/hw.c54
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/mac.c17
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/mac.h5
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/phy.c28
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/rf.c22
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/trx.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/fw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/hw.c21
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/hw.c13
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/fw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/hw.c21
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8821ae/dm.c14
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8821ae/hw.c24
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h1
-rw-r--r--drivers/net/wireless/ti/wl1251/acx.c3
-rw-r--r--drivers/net/wireless/ti/wl1251/main.c12
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c71
-rw-r--r--drivers/net/wireless/ti/wl18xx/reg.h1
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c54
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c12
-rw-r--r--drivers/net/xen-netback/netback.c21
-rw-r--r--drivers/net/xen-netback/xenbus.c4
-rw-r--r--drivers/net/xen-netfront.c7
-rw-r--r--drivers/nfc/Kconfig2
-rw-r--r--drivers/nfc/Makefile4
-rw-r--r--drivers/nfc/mei_phy.c295
-rw-r--r--drivers/nfc/mei_phy.h38
-rw-r--r--drivers/nfc/microread/i2c.c3
-rw-r--r--drivers/nfc/microread/mei.c2
-rw-r--r--drivers/nfc/nfcmrvl/Kconfig11
-rw-r--r--drivers/nfc/nfcmrvl/Makefile3
-rw-r--r--drivers/nfc/nfcmrvl/main.c134
-rw-r--r--drivers/nfc/nfcmrvl/nfcmrvl.h60
-rw-r--r--drivers/nfc/nfcmrvl/uart.c225
-rw-r--r--drivers/nfc/nfcmrvl/usb.c27
-rw-r--r--drivers/nfc/nxp-nci/Makefile2
-rw-r--r--drivers/nfc/nxp-nci/i2c.c52
-rw-r--r--drivers/nfc/pn544/i2c.c43
-rw-r--r--drivers/nfc/pn544/mei.c2
-rw-r--r--drivers/nfc/st-nci/Kconfig23
-rw-r--r--drivers/nfc/st-nci/Makefile9
-rw-r--r--drivers/nfc/st-nci/core.c179
-rw-r--r--drivers/nfc/st-nci/i2c.c (renamed from drivers/nfc/st21nfcb/i2c.c)147
-rw-r--r--drivers/nfc/st-nci/ndlc.c (renamed from drivers/nfc/st21nfcb/ndlc.c)23
-rw-r--r--drivers/nfc/st-nci/ndlc.h (renamed from drivers/nfc/st21nfcb/ndlc.h)5
-rw-r--r--drivers/nfc/st-nci/st-nci.h (renamed from drivers/nfc/st21nfcb/st21nfcb.h)30
-rw-r--r--drivers/nfc/st-nci/st-nci_se.c (renamed from drivers/nfc/st21nfcb/st21nfcb_se.c)383
-rw-r--r--drivers/nfc/st-nci/st-nci_se.h61
-rw-r--r--drivers/nfc/st21nfcb/Kconfig22
-rw-r--r--drivers/nfc/st21nfcb/Makefile9
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb.c143
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb_se.h61
-rw-r--r--drivers/nfc/trf7970a.c23
-rw-r--r--drivers/ntb/ntb_hw.c2
-rw-r--r--drivers/of/address.c2
-rw-r--r--drivers/of/base.c34
-rw-r--r--drivers/of/fdt.c19
-rw-r--r--drivers/of/of_mdio.c3
-rw-r--r--drivers/of/platform.c1
-rw-r--r--drivers/parport/parport_pc.c4
-rw-r--r--drivers/parport/procfs.c15
-rw-r--r--drivers/parport/share.c373
-rw-r--r--drivers/pci/Kconfig4
-rw-r--r--drivers/pci/bus.c10
-rw-r--r--drivers/pci/host/Kconfig20
-rw-r--r--drivers/pci/host/Makefile2
-rw-r--r--drivers/pci/host/pci-dra7xx.c19
-rw-r--r--drivers/pci/host/pci-exynos.c34
-rw-r--r--drivers/pci/host/pci-imx6.c88
-rw-r--r--drivers/pci/host/pci-keystone.c16
-rw-r--r--drivers/pci/host/pci-layerscape.c25
-rw-r--r--drivers/pci/host/pci-mvebu.c18
-rw-r--r--drivers/pci/host/pci-tegra.c16
-rw-r--r--drivers/pci/host/pci-xgene-msi.c596
-rw-r--r--drivers/pci/host/pci-xgene.c66
-rw-r--r--drivers/pci/host/pcie-designware.c154
-rw-r--r--drivers/pci/host/pcie-iproc-bcma.c110
-rw-r--r--drivers/pci/host/pcie-iproc-platform.c12
-rw-r--r--drivers/pci/host/pcie-iproc.c6
-rw-r--r--drivers/pci/host/pcie-iproc.h4
-rw-r--r--drivers/pci/host/pcie-spear13xx.c23
-rw-r--r--drivers/pci/hotplug/Makefile3
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c5
-rw-r--r--drivers/pci/hotplug/pciehp.h23
-rw-r--r--drivers/pci/hotplug/pciehp_acpi.c137
-rw-r--r--drivers/pci/hotplug/pciehp_core.c54
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c154
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c145
-rw-r--r--drivers/pci/htirq.c48
-rw-r--r--drivers/pci/msi.c53
-rw-r--r--drivers/pci/pci-acpi.c2
-rw-r--r--drivers/pci/pci.c44
-rw-r--r--drivers/pci/pci.h32
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c3
-rw-r--r--drivers/pci/pcie/aspm.c57
-rw-r--r--drivers/pci/probe.c69
-rw-r--r--drivers/pci/quirks.c13
-rw-r--r--drivers/pci/vc.c3
-rw-r--r--drivers/pci/xen-pcifront.c16
-rw-r--r--drivers/pcmcia/Kconfig1
-rw-r--r--drivers/pcmcia/at91_cf.c25
-rw-r--r--drivers/pcmcia/cistpl.c50
-rw-r--r--drivers/pcmcia/cs.c39
-rw-r--r--drivers/pcmcia/ds.c76
-rw-r--r--drivers/pcmcia/electra_cf.c19
-rw-r--r--drivers/pcmcia/i82365.c43
-rw-r--r--drivers/pcmcia/m32r_cfc.c7
-rw-r--r--drivers/pcmcia/m32r_pcc.c7
-rw-r--r--drivers/pcmcia/pcmcia_cis.c4
-rw-r--r--drivers/pcmcia/pcmcia_resource.c11
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c44
-rw-r--r--drivers/pcmcia/ti113x.h78
-rw-r--r--drivers/pcmcia/topic.h16
-rw-r--r--drivers/pcmcia/vrc4171_card.c30
-rw-r--r--drivers/pcmcia/yenta_socket.c94
-rw-r--r--drivers/phy/Kconfig36
-rw-r--r--drivers/phy/Makefile4
-rw-r--r--drivers/phy/phy-brcmstb-sata.c216
-rw-r--r--drivers/phy/phy-core.c67
-rw-r--r--drivers/phy/phy-miphy28lp.c9
-rw-r--r--drivers/phy/phy-miphy365x.c9
-rw-r--r--drivers/phy/phy-pxa-28nm-hsic.c220
-rw-r--r--drivers/phy/phy-pxa-28nm-usb2.c355
-rw-r--r--drivers/phy/phy-rcar-gen2.c6
-rw-r--r--drivers/phy/phy-spear1310-miphy.c6
-rw-r--r--drivers/phy/phy-spear1340-miphy.c6
-rw-r--r--drivers/phy/phy-sun4i-usb.c9
-rw-r--r--drivers/phy/phy-tusb1210.c153
-rw-r--r--drivers/phy/phy-twl4030-usb.c34
-rw-r--r--drivers/phy/ulpi_phy.h31
-rw-r--r--drivers/pinctrl/Kconfig19
-rw-r--r--drivers/pinctrl/Makefile2
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm281xx.c4
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm2835.c4
-rw-r--r--drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c8
-rw-r--r--drivers/pinctrl/bcm/pinctrl-cygnus-mux.c4
-rw-r--r--drivers/pinctrl/berlin/berlin-bg2.c44
-rw-r--r--drivers/pinctrl/berlin/berlin-bg2cd.c34
-rw-r--r--drivers/pinctrl/berlin/berlin-bg2q.c42
-rw-r--r--drivers/pinctrl/berlin/berlin.c13
-rw-r--r--drivers/pinctrl/core.c21
-rw-r--r--drivers/pinctrl/freescale/Kconfig7
-rw-r--r--drivers/pinctrl/freescale/Makefile1
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx.c59
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx1-core.c4
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx7d.c384
-rw-r--r--drivers/pinctrl/freescale/pinctrl-mxs.c4
-rw-r--r--drivers/pinctrl/intel/pinctrl-cherryview.c4
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.c4
-rw-r--r--drivers/pinctrl/intel/pinctrl-sunrisepoint.c263
-rw-r--r--drivers/pinctrl/mediatek/Kconfig13
-rw-r--r--drivers/pinctrl/mediatek/Makefile2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt6397.c77
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8127.c358
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8135.c13
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8173.c377
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c161
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.h75
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-mt6397.h424
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-mt8127.h1318
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.c4
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-370.c22
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-375.c50
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-38x.c120
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-39x.c131
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-xp.c98
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c4
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-ab8505.c2
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-abx500.c5
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-nomadik.c66
-rw-r--r--drivers/pinctrl/pinctrl-adi2.c5
-rw-r--r--drivers/pinctrl/pinctrl-amd.c5
-rw-r--r--drivers/pinctrl/pinctrl-as3722.c4
-rw-r--r--drivers/pinctrl/pinctrl-at91.c20
-rw-r--r--drivers/pinctrl/pinctrl-lantiq.c4
-rw-r--r--drivers/pinctrl/pinctrl-lpc18xx.c1220
-rw-r--r--drivers/pinctrl/pinctrl-palmas.c4
-rw-r--r--drivers/pinctrl/pinctrl-pistachio.c1504
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c131
-rw-r--r--drivers/pinctrl/pinctrl-single.c6
-rw-r--r--drivers/pinctrl/pinctrl-st.c4
-rw-r--r--drivers/pinctrl/pinctrl-tb10x.c4
-rw-r--r--drivers/pinctrl/pinctrl-tegra-xusb.c27
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c4
-rw-r--r--drivers/pinctrl/pinctrl-tz1090-pdc.c4
-rw-r--r--drivers/pinctrl/pinctrl-tz1090.c4
-rw-r--r--drivers/pinctrl/pinctrl-u300.c4
-rw-r--r--drivers/pinctrl/pinctrl-zynq.c91
-rw-r--r--drivers/pinctrl/pinmux.c59
-rw-r--r--drivers/pinctrl/qcom/Kconfig8
-rw-r--r--drivers/pinctrl/qcom/Makefile1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm8660.c984
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-gpio.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-mpp.c4
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos5440.c4
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.c6
-rw-r--r--drivers/pinctrl/sh-pfc/Kconfig10
-rw-r--r--drivers/pinctrl/sh-pfc/Makefile2
-rw-r--r--drivers/pinctrl/sh-pfc/core.c15
-rw-r--r--drivers/pinctrl/sh-pfc/core.h2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a73a4.c4
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7740.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7790.c101
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7791.c186
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7794.c4207
-rw-r--r--drivers/pinctrl/sh-pfc/pinctrl.c4
-rw-r--r--drivers/pinctrl/sirf/Makefile1
-rw-r--r--drivers/pinctrl/sirf/pinctrl-atlas7.c4637
-rw-r--r--drivers/pinctrl/sirf/pinctrl-sirf.c4
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.c4
-rw-r--r--drivers/pinctrl/sunxi/Kconfig4
-rw-r--r--drivers/pinctrl/sunxi/Makefile1
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c1
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c513
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c4
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wmt.c4
-rw-r--r--drivers/platform/chrome/Kconfig9
-rw-r--r--drivers/platform/chrome/Makefile1
-rw-r--r--drivers/platform/chrome/cros_ec_dev.c189
-rw-r--r--drivers/platform/chrome/cros_ec_dev.h7
-rw-r--r--drivers/platform/chrome/cros_ec_lightbar.c217
-rw-r--r--drivers/platform/chrome/cros_ec_lpc.c85
-rw-r--r--drivers/platform/chrome/cros_ec_proto.c382
-rw-r--r--drivers/platform/chrome/cros_ec_sysfs.c178
-rw-r--r--drivers/platform/goldfish/goldfish_pipe.c20
-rw-r--r--drivers/platform/x86/Kconfig25
-rw-r--r--drivers/platform/x86/acer-wmi.c10
-rw-r--r--drivers/platform/x86/acerhdf.c3
-rw-r--r--drivers/platform/x86/apple-gmux.c4
-rw-r--r--drivers/platform/x86/asus-laptop.c6
-rw-r--r--drivers/platform/x86/asus-wmi.c15
-rw-r--r--drivers/platform/x86/compal-laptop.c4
-rw-r--r--drivers/platform/x86/dell-laptop.c8
-rw-r--r--drivers/platform/x86/dell-wmi.c3
-rw-r--r--drivers/platform/x86/eeepc-laptop.c5
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c6
-rw-r--r--drivers/platform/x86/ideapad-laptop.c3
-rw-r--r--drivers/platform/x86/intel_oaktrail.c7
-rw-r--r--drivers/platform/x86/msi-laptop.c6
-rw-r--r--drivers/platform/x86/msi-wmi.c4
-rw-r--r--drivers/platform/x86/samsung-laptop.c27
-rw-r--r--drivers/platform/x86/sony-laptop.c7
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c5
-rw-r--r--drivers/platform/x86/toshiba_acpi.c7
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c10
-rw-r--r--drivers/pnp/system.c35
-rw-r--r--drivers/power/88pm860x_charger.c1
-rw-r--r--drivers/power/Kconfig28
-rw-r--r--drivers/power/Makefile4
-rw-r--r--drivers/power/axp288_charger.c941
-rw-r--r--drivers/power/axp288_fuel_gauge.c2
-rw-r--r--drivers/power/bq2415x_charger.c94
-rw-r--r--drivers/power/bq24190_charger.c11
-rw-r--r--drivers/power/bq24257_charger.c858
-rw-r--r--drivers/power/bq25890_charger.c994
-rw-r--r--drivers/power/charger-manager.c3
-rw-r--r--drivers/power/max17042_battery.c199
-rw-r--r--drivers/power/power_supply_core.c106
-rw-r--r--drivers/power/power_supply_leds.c4
-rw-r--r--drivers/power/power_supply_sysfs.c4
-rw-r--r--drivers/power/reset/at91-reset.c2
-rw-r--r--drivers/power/reset/gpio-poweroff.c25
-rw-r--r--drivers/power/reset/gpio-restart.c2
-rw-r--r--drivers/power/reset/ltc2952-poweroff.c8
-rw-r--r--drivers/power/rt9455_charger.c1752
-rw-r--r--drivers/power/sbs-battery.c21
-rw-r--r--drivers/power/twl4030_charger.c21
-rw-r--r--drivers/power/wm831x_power.c1
-rw-r--r--drivers/powercap/intel_rapl.c51
-rw-r--r--drivers/pwm/core.c40
-rw-r--r--drivers/pwm/pwm-atmel.c63
-rw-r--r--drivers/pwm/pwm-bcm-kona.c9
-rw-r--r--drivers/pwm/pwm-lpss-pci.c2
-rw-r--r--drivers/pwm/pwm-samsung.c1
-rw-r--r--drivers/rapidio/rio-scan.c2
-rw-r--r--drivers/regulator/88pm8607.c2
-rw-r--r--drivers/regulator/Kconfig23
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/arizona-ldo1.c20
-rw-r--r--drivers/regulator/axp20x-regulator.c239
-rw-r--r--drivers/regulator/core.c76
-rw-r--r--drivers/regulator/da9062-regulator.c842
-rw-r--r--drivers/regulator/da9063-regulator.c21
-rw-r--r--drivers/regulator/fan53555.c1
-rw-r--r--drivers/regulator/helpers.c2
-rw-r--r--drivers/regulator/lp8755.c23
-rw-r--r--drivers/regulator/max14577.c128
-rw-r--r--drivers/regulator/max77686.c8
-rw-r--r--drivers/regulator/max77693.c17
-rw-r--r--drivers/regulator/max77843.c68
-rw-r--r--drivers/regulator/max8973-regulator.c269
-rw-r--r--drivers/regulator/of_regulator.c16
-rw-r--r--drivers/regulator/pwm-regulator.c41
-rw-r--r--drivers/regulator/qcom_spmi-regulator.c1435
-rw-r--r--drivers/regulator/s2mps11.c10
-rw-r--r--drivers/regulator/wm831x-dcdc.c12
-rw-r--r--drivers/regulator/wm831x-isink.c3
-rw-r--r--drivers/regulator/wm831x-ldo.c6
-rw-r--r--drivers/reset/reset-berlin.c74
-rw-r--r--drivers/rtc/Kconfig115
-rw-r--r--drivers/rtc/Makefile43
-rw-r--r--drivers/rtc/interface.c49
-rw-r--r--drivers/rtc/rtc-ab8500.c2
-rw-r--r--drivers/rtc/rtc-at32ap700x.c2
-rw-r--r--drivers/rtc/rtc-ds1216.c4
-rw-r--r--drivers/rtc/rtc-ds1286.c4
-rw-r--r--drivers/rtc/rtc-ds1307.c12
-rw-r--r--drivers/rtc/rtc-ds1672.c1
-rw-r--r--drivers/rtc/rtc-efi.c43
-rw-r--r--drivers/rtc/rtc-ep93xx.c6
-rw-r--r--drivers/rtc/rtc-gemini.c175
-rw-r--r--drivers/rtc/rtc-hid-sensor-time.c2
-rw-r--r--drivers/rtc/rtc-hym8563.c18
-rw-r--r--drivers/rtc/rtc-imxdi.c438
-rw-r--r--drivers/rtc/rtc-isl1208.c9
-rw-r--r--drivers/rtc/rtc-max6900.c1
-rw-r--r--drivers/rtc/rtc-max77686.c1
-rw-r--r--drivers/rtc/rtc-max77802.c1
-rw-r--r--drivers/rtc/rtc-max8998.c1
-rw-r--r--drivers/rtc/rtc-mc13xxx.c2
-rw-r--r--drivers/rtc/rtc-mt6397.c395
-rw-r--r--drivers/rtc/rtc-mv.c13
-rw-r--r--drivers/rtc/rtc-mxc.c2
-rw-r--r--drivers/rtc/rtc-palmas.c2
-rw-r--r--drivers/rtc/rtc-pcf8563.c21
-rw-r--r--drivers/rtc/rtc-s3c.c14
-rw-r--r--drivers/rtc/rtc-snvs.c30
-rw-r--r--drivers/rtc/rtc-spear.c7
-rw-r--r--drivers/rtc/rtc-st-lpc.c354
-rw-r--r--drivers/rtc/rtc-sunxi.c32
-rw-r--r--drivers/rtc/rtc-v3020.c41
-rw-r--r--drivers/rtc/systohc.c2
-rw-r--r--drivers/s390/block/dasd.c17
-rw-r--r--drivers/s390/block/dasd_genhd.c19
-rw-r--r--drivers/s390/char/keyboard.c13
-rw-r--r--drivers/s390/char/sclp.c2
-rw-r--r--drivers/s390/char/sclp.h15
-rw-r--r--drivers/s390/char/sclp_cmd.c29
-rw-r--r--drivers/s390/char/sclp_early.c118
-rw-r--r--drivers/s390/char/sclp_sdias.c3
-rw-r--r--drivers/s390/char/zcore.c10
-rw-r--r--drivers/s390/crypto/zcrypt_pcicc.c8
-rw-r--r--drivers/s390/kvm/kvm_virtio.c4
-rw-r--r--drivers/s390/net/lcs.c2
-rw-r--r--drivers/s390/net/qeth_core.h2
-rw-r--r--drivers/s390/net/qeth_core_main.c3
-rw-r--r--drivers/s390/net/qeth_core_mpc.c3
-rw-r--r--drivers/s390/net/qeth_core_mpc.h3
-rw-r--r--drivers/s390/net/qeth_l2_main.c124
-rw-r--r--drivers/s390/net/qeth_l2_sys.c74
-rw-r--r--drivers/s390/net/qeth_l3_main.c9
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c1
-rw-r--r--drivers/scsi/Kconfig22
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/NCR53c406a.c1
-rw-r--r--drivers/scsi/a100u2w.c1
-rw-r--r--drivers/scsi/aacraid/src.c2
-rw-r--r--drivers/scsi/advansys.c1474
-rw-r--r--drivers/scsi/aha152x.c1
-rw-r--r--drivers/scsi/aha1542.c1
-rw-r--r--drivers/scsi/aha1740.c1
-rw-r--r--drivers/scsi/aha1740.h1
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c1
-rw-r--r--drivers/scsi/arm/arxescsi.c1
-rw-r--r--drivers/scsi/arm/cumana_2.c1
-rw-r--r--drivers/scsi/arm/eesox.c1
-rw-r--r--drivers/scsi/atp870u.c1
-rw-r--r--drivers/scsi/atp870u.h1
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c4
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h12
-rw-r--r--drivers/scsi/be2iscsi/be_main.c76
-rw-r--r--drivers/scsi/be2iscsi/be_main.h6
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c69
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h3
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c5
-rw-r--r--drivers/scsi/csiostor/csio_hw.c1
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/cxgb3i.c20
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/cxgb3i.h2
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c52
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.h4
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.c22
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.h6
-rw-r--r--drivers/scsi/dpt_i2o.c1
-rw-r--r--drivers/scsi/fdomain.c1
-rw-r--r--drivers/scsi/fnic/fnic_debugfs.c1
-rw-r--r--drivers/scsi/fnic/fnic_trace.c1
-rw-r--r--drivers/scsi/hpsa.c2780
-rw-r--r--drivers/scsi/hpsa.h19
-rw-r--r--drivers/scsi/hpsa_cmd.h34
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c6
-rw-r--r--drivers/scsi/imm.c1
-rw-r--r--drivers/scsi/initio.c1
-rw-r--r--drivers/scsi/ipr.h2
-rw-r--r--drivers/scsi/ips.c9
-rw-r--r--drivers/scsi/isci/init.c1
-rw-r--r--drivers/scsi/lpfc/lpfc.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c12
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c733
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c181
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h201
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h236
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c26
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c152
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c10
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c65
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c82
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h21
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c9
-rw-r--r--drivers/scsi/mac53c94.c1
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h342
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c741
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c25
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c556
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h281
-rw-r--r--drivers/scsi/mvsas/mv_init.c1
-rw-r--r--drivers/scsi/nsp32.c1
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c1
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c1
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c1
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c1
-rw-r--r--drivers/scsi/ppa.c1
-rw-r--r--drivers/scsi/ps3rom.c1
-rw-r--r--drivers/scsi/qla1280.c1
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c8
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_nx2.c13
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c16
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c1
-rw-r--r--drivers/scsi/qla4xxx/ql4_83xx.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_bsg.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h1
-rw-r--r--drivers/scsi/qlogicfas.c1
-rw-r--r--drivers/scsi/qlogicpti.c1
-rw-r--r--drivers/scsi/scsi.c46
-rw-r--r--drivers/scsi/scsi_common.c178
-rw-r--r--drivers/scsi/scsi_error.c64
-rw-r--r--drivers/scsi/scsi_scan.c65
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c2
-rw-r--r--drivers/scsi/scsi_transport_srp.c67
-rw-r--r--drivers/scsi/sd.c3
-rw-r--r--drivers/scsi/snic/Makefile17
-rw-r--r--drivers/scsi/snic/cq_desc.h77
-rw-r--r--drivers/scsi/snic/cq_enet_desc.h38
-rw-r--r--drivers/scsi/snic/snic.h414
-rw-r--r--drivers/scsi/snic/snic_attrs.c77
-rw-r--r--drivers/scsi/snic/snic_ctl.c279
-rw-r--r--drivers/scsi/snic/snic_debugfs.c560
-rw-r--r--drivers/scsi/snic/snic_disc.c551
-rw-r--r--drivers/scsi/snic/snic_disc.h124
-rw-r--r--drivers/scsi/snic/snic_fwint.h525
-rw-r--r--drivers/scsi/snic/snic_io.c518
-rw-r--r--drivers/scsi/snic/snic_io.h118
-rw-r--r--drivers/scsi/snic/snic_isr.c204
-rw-r--r--drivers/scsi/snic/snic_main.c1044
-rw-r--r--drivers/scsi/snic/snic_res.c295
-rw-r--r--drivers/scsi/snic/snic_res.h97
-rw-r--r--drivers/scsi/snic/snic_scsi.c2632
-rw-r--r--drivers/scsi/snic/snic_stats.h123
-rw-r--r--drivers/scsi/snic/snic_trc.c181
-rw-r--r--drivers/scsi/snic/snic_trc.h121
-rw-r--r--drivers/scsi/snic/vnic_cq.c86
-rw-r--r--drivers/scsi/snic/vnic_cq.h110
-rw-r--r--drivers/scsi/snic/vnic_cq_fw.h62
-rw-r--r--drivers/scsi/snic/vnic_dev.c748
-rw-r--r--drivers/scsi/snic/vnic_dev.h110
-rw-r--r--drivers/scsi/snic/vnic_devcmd.h270
-rw-r--r--drivers/scsi/snic/vnic_intr.c59
-rw-r--r--drivers/scsi/snic/vnic_intr.h105
-rw-r--r--drivers/scsi/snic/vnic_resource.h68
-rw-r--r--drivers/scsi/snic/vnic_snic.h54
-rw-r--r--drivers/scsi/snic/vnic_stats.h68
-rw-r--r--drivers/scsi/snic/vnic_wq.c237
-rw-r--r--drivers/scsi/snic/vnic_wq.h170
-rw-r--r--drivers/scsi/snic/wq_enet_desc.h96
-rw-r--r--drivers/scsi/st.c272
-rw-r--r--drivers/scsi/st.h22
-rw-r--r--drivers/scsi/sym53c416.c1
-rw-r--r--drivers/scsi/ufs/Kconfig2
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c39
-rw-r--r--drivers/scsi/ufs/ufshcd.c108
-rw-r--r--drivers/scsi/ufs/ufshcd.h53
-rw-r--r--drivers/scsi/ufs/ufshci.h8
-rw-r--r--drivers/scsi/ufs/unipro.h8
-rw-r--r--drivers/scsi/virtio_scsi.c11
-rw-r--r--drivers/scsi/wd719x.c1
-rw-r--r--drivers/scsi/wd719x.h2
-rw-r--r--drivers/sh/pm_runtime.c47
-rw-r--r--drivers/soc/Kconfig1
-rw-r--r--drivers/soc/Makefile1
-rw-r--r--drivers/soc/qcom/Kconfig7
-rw-r--r--drivers/soc/qcom/Makefile1
-rw-r--r--drivers/soc/qcom/spm.c385
-rw-r--r--drivers/soc/sunxi/Kconfig10
-rw-r--r--drivers/soc/sunxi/Makefile1
-rw-r--r--drivers/soc/sunxi/sunxi_sram.c284
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra20.c6
-rw-r--r--drivers/soc/tegra/fuse/tegra-apbmisc.c21
-rw-r--r--drivers/soc/tegra/pmc.c23
-rw-r--r--drivers/spi/Kconfig26
-rw-r--r--drivers/spi/Makefile3
-rw-r--r--drivers/spi/spi-ath79.c34
-rw-r--r--drivers/spi/spi-atmel.c292
-rw-r--r--drivers/spi/spi-bcm2835.c392
-rw-r--r--drivers/spi/spi-davinci.c2
-rw-r--r--drivers/spi/spi-fsl-dspi.c307
-rw-r--r--drivers/spi/spi-fsl-espi.c6
-rw-r--r--drivers/spi/spi-imx.c2
-rw-r--r--drivers/spi/spi-omap2-mcspi.c280
-rw-r--r--drivers/spi/spi-orion.c70
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c8
-rw-r--r--drivers/spi/spi-pxa2xx-pxadma.c487
-rw-r--r--drivers/spi/spi-pxa2xx.c159
-rw-r--r--drivers/spi/spi-pxa2xx.h6
-rw-r--r--drivers/spi/spi-rb4xx.c210
-rw-r--r--drivers/spi/spi-rspi.c23
-rw-r--r--drivers/spi/spi-s3c64xx.c2
-rw-r--r--drivers/spi/spi-sh-msiof.c2
-rw-r--r--drivers/spi/spi-sirf.c877
-rw-r--r--drivers/spi/spi-zynqmp-gqspi.c1122
-rw-r--r--drivers/spi/spi.c45
-rw-r--r--drivers/spi/spidev.c33
-rw-r--r--drivers/spmi/Kconfig1
-rw-r--r--drivers/staging/Kconfig4
-rw-r--r--drivers/staging/Makefile4
-rw-r--r--drivers/staging/android/Kconfig11
-rw-r--r--drivers/staging/android/ion/ion.c1
-rw-r--r--drivers/staging/android/ion/ion_chunk_heap.c2
-rw-r--r--drivers/staging/android/ion/ion_priv.h6
-rw-r--r--drivers/staging/android/ion/ion_test.c20
-rw-r--r--drivers/staging/android/ion/tegra/tegra_ion.c1
-rw-r--r--drivers/staging/android/lowmemorykiller.c19
-rw-r--r--drivers/staging/android/uapi/ion.h2
-rw-r--r--drivers/staging/board/Kconfig1
-rw-r--r--drivers/staging/board/Makefile3
-rw-r--r--drivers/staging/board/armadillo800eva.c105
-rw-r--r--drivers/staging/board/board.c136
-rw-r--r--drivers/staging/board/board.h27
-rw-r--r--drivers/staging/board/kzm9d.c10
-rw-r--r--drivers/staging/comedi/Kconfig18
-rw-r--r--drivers/staging/comedi/comedi.h2
-rw-r--r--drivers/staging/comedi/comedi_fops.c48
-rw-r--r--drivers/staging/comedi/comedi_internal.h1
-rw-r--r--drivers/staging/comedi/comedidev.h30
-rw-r--r--drivers/staging/comedi/drivers.c2
-rw-r--r--drivers/staging/comedi/drivers/8255.c232
-rw-r--r--drivers/staging/comedi/drivers/8255.h19
-rw-r--r--drivers/staging/comedi/drivers/Makefile3
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1516.c24
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c14
-rw-r--r--drivers/staging/comedi/drivers/addi_watchdog.h2
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1724.c6
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c48
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c37
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.h44
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_common.c61
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_pci.c35
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236_common.c12
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c42
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c52
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c64
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c372
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c16
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c8
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c6
-rw-r--r--drivers/staging/comedi/drivers/comedi_8254.h6
-rw-r--r--drivers/staging/comedi/drivers/comedi_8255.c285
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c3
-rw-r--r--drivers/staging/comedi/drivers/comedi_isadma.h4
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c196
-rw-r--r--drivers/staging/comedi/drivers/das08.c378
-rw-r--r--drivers/staging/comedi/drivers/das08.h48
-rw-r--r--drivers/staging/comedi/drivers/das08_isa.c4
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c4
-rw-r--r--drivers/staging/comedi/drivers/das1800.c86
-rw-r--r--drivers/staging/comedi/drivers/das800.c75
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c22
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c191
-rw-r--r--drivers/staging/comedi/drivers/me4000.c30
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c3
-rw-r--r--drivers/staging/comedi/drivers/mite.c110
-rw-r--r--drivers/staging/comedi/drivers/mite.h88
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c12
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c40
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio.c27
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c2408
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c17
-rw-r--r--drivers/staging/comedi/drivers/ni_stc.h2237
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c10
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c2
-rw-r--r--drivers/staging/comedi/drivers/serial2002.c2
-rw-r--r--drivers/staging/comedi/drivers/vmk80xx.c33
-rw-r--r--drivers/staging/dgap/dgap.c133
-rw-r--r--drivers/staging/dgap/dgap.h2
-rw-r--r--drivers/staging/dgnc/TODO6
-rw-r--r--drivers/staging/dgnc/dgnc_cls.c4
-rw-r--r--drivers/staging/dgnc/dgnc_driver.c9
-rw-r--r--drivers/staging/dgnc/dgnc_driver.h6
-rw-r--r--drivers/staging/dgnc/dgnc_neo.c4
-rw-r--r--drivers/staging/dgnc/dgnc_sysfs.c110
-rw-r--r--drivers/staging/dgnc/dgnc_tty.c110
-rw-r--r--drivers/staging/dgnc/digi.h14
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.c65
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.h10
-rw-r--r--drivers/staging/fbtft/Kconfig8
-rw-r--r--drivers/staging/fbtft/Makefile1
-rw-r--r--drivers/staging/fbtft/fb_agm1264k-fl.c6
-rw-r--r--drivers/staging/fbtft/fb_hx8357d.c222
-rw-r--r--drivers/staging/fbtft/fb_hx8357d.h102
-rw-r--r--drivers/staging/fbtft/fb_ili9320.c118
-rw-r--r--drivers/staging/fbtft/fb_ra8875.c13
-rw-r--r--drivers/staging/fbtft/fb_st7735r.c8
-rw-r--r--drivers/staging/fbtft/fb_tinylcd.c2
-rw-r--r--drivers/staging/fbtft/fb_tls8204.c12
-rw-r--r--drivers/staging/fbtft/fbtft-bus.c8
-rw-r--r--drivers/staging/fbtft/fbtft-core.c34
-rw-r--r--drivers/staging/fbtft/fbtft.h5
-rw-r--r--drivers/staging/fbtft/fbtft_device.c54
-rw-r--r--drivers/staging/fbtft/flexfb.c161
-rw-r--r--drivers/staging/fbtft/internal.h2
-rw-r--r--drivers/staging/fsl-mc/bus/mc-bus.c1
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_debug.c7
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_hw.c58
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_usb.c2
-rw-r--r--drivers/staging/fwserial/dma_fifo.c2
-rw-r--r--drivers/staging/fwserial/fwserial.c5
-rw-r--r--drivers/staging/fwserial/fwserial.h2
-rw-r--r--drivers/staging/gdm724x/gdm_endian.c46
-rw-r--r--drivers/staging/gdm724x/gdm_endian.h11
-rw-r--r--drivers/staging/gdm72xx/gdm_wimax.c2
-rw-r--r--drivers/staging/gdm72xx/netlink_k.c2
-rw-r--r--drivers/staging/goldfish/goldfish_audio.c2
-rw-r--r--drivers/staging/goldfish/goldfish_nand.c2
-rw-r--r--drivers/staging/i2o/Kconfig120
-rw-r--r--drivers/staging/i2o/Makefile16
-rw-r--r--drivers/staging/i2o/README98
-rw-r--r--drivers/staging/i2o/README.ioctl394
-rw-r--r--drivers/staging/i2o/bus-osm.c177
-rw-r--r--drivers/staging/i2o/config-osm.c90
-rw-r--r--drivers/staging/i2o/core.h69
-rw-r--r--drivers/staging/i2o/debug.c473
-rw-r--r--drivers/staging/i2o/device.c592
-rw-r--r--drivers/staging/i2o/driver.c381
-rw-r--r--drivers/staging/i2o/exec-osm.c612
-rw-r--r--drivers/staging/i2o/i2o.h988
-rw-r--r--drivers/staging/i2o/i2o_block.c1228
-rw-r--r--drivers/staging/i2o/i2o_block.h103
-rw-r--r--drivers/staging/i2o/i2o_config.c1162
-rw-r--r--drivers/staging/i2o/i2o_proc.c2049
-rw-r--r--drivers/staging/i2o/i2o_scsi.c814
-rw-r--r--drivers/staging/i2o/iop.c1255
-rw-r--r--drivers/staging/i2o/memory.c312
-rw-r--r--drivers/staging/i2o/pci.c500
-rw-r--r--drivers/staging/iio/Documentation/device.txt2
-rw-r--r--drivers/staging/iio/accel/Kconfig2
-rw-r--r--drivers/staging/iio/accel/sca3000_ring.c2
-rw-r--r--drivers/staging/iio/adc/Kconfig6
-rw-r--r--drivers/staging/iio/adc/ad7606_par.c2
-rw-r--r--drivers/staging/iio/addac/Kconfig2
-rw-r--r--drivers/staging/iio/iio_dummy_evgen.c4
-rw-r--r--drivers/staging/iio/iio_dummy_evgen.h2
-rw-r--r--drivers/staging/iio/iio_simple_dummy.c21
-rw-r--r--drivers/staging/iio/iio_simple_dummy.h10
-rw-r--r--drivers/staging/iio/iio_simple_dummy_events.c6
-rw-r--r--drivers/staging/iio/light/isl29018.c297
-rw-r--r--drivers/staging/iio/resolver/Kconfig4
-rw-r--r--drivers/staging/lustre/TODO2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs.h44
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_private.h68
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h1
-rw-r--r--drivers/staging/lustre/include/linux/lnet/api-support.h44
-rw-r--r--drivers/staging/lustre/include/linux/lnet/api.h49
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-lnet.h285
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-types.h667
-rw-r--r--drivers/staging/lustre/include/linux/lnet/linux/api-support.h42
-rw-r--r--drivers/staging/lustre/include/linux/lnet/linux/lib-lnet.h71
-rw-r--r--drivers/staging/lustre/include/linux/lnet/linux/lib-types.h45
-rw-r--r--drivers/staging/lustre/include/linux/lnet/linux/lnet.h56
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lnet-sysctl.h49
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lnet.h17
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lnetctl.h7
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lnetst.h490
-rw-r--r--drivers/staging/lustre/include/linux/lnet/nidstr.h77
-rw-r--r--drivers/staging/lustre/include/linux/lnet/ptllnd.h93
-rw-r--r--drivers/staging/lustre/include/linux/lnet/ptllnd_wire.h119
-rw-r--r--drivers/staging/lustre/include/linux/lnet/socklnd.h68
-rw-r--r--drivers/staging/lustre/include/linux/lnet/types.h290
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c474
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h681
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c484
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c48
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/Makefile2
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c485
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h602
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c402
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.h86
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c (renamed from drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c)172
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c33
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c171
-rw-r--r--drivers/staging/lustre/lnet/lnet/Makefile7
-rw-r--r--drivers/staging/lustre/lnet/lnet/acceptor.c91
-rw-r--r--drivers/staging/lustre/lnet/lnet/api-ni.c325
-rw-r--r--drivers/staging/lustre/lnet/lnet/config.c310
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-eq.c46
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-md.c32
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-me.c26
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-move.c264
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-msg.c52
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-ptl.c116
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-socket.c (renamed from drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c)315
-rw-r--r--drivers/staging/lustre/lnet/lnet/lo.c2
-rw-r--r--drivers/staging/lustre/lnet/lnet/module.c28
-rw-r--r--drivers/staging/lustre/lnet/lnet/peer.c50
-rw-r--r--drivers/staging/lustre/lnet/lnet/router.c355
-rw-r--r--drivers/staging/lustre/lnet/lnet/router_proc.c210
-rw-r--r--drivers/staging/lustre/lnet/selftest/brw_test.c60
-rw-r--r--drivers/staging/lustre/lnet/selftest/conctl.c54
-rw-r--r--drivers/staging/lustre/lnet/selftest/conrpc.c124
-rw-r--r--drivers/staging/lustre/lnet/selftest/conrpc.h34
-rw-r--r--drivers/staging/lustre/lnet/selftest/console.c246
-rw-r--r--drivers/staging/lustre/lnet/selftest/console.h186
-rw-r--r--drivers/staging/lustre/lnet/selftest/framework.c160
-rw-r--r--drivers/staging/lustre/lnet/selftest/module.c10
-rw-r--r--drivers/staging/lustre/lnet/selftest/ping_test.c24
-rw-r--r--drivers/staging/lustre/lnet/selftest/rpc.c152
-rw-r--r--drivers/staging/lustre/lnet/selftest/rpc.h141
-rw-r--r--drivers/staging/lustre/lnet/selftest/selftest.h311
-rw-r--r--drivers/staging/lustre/lnet/selftest/timer.c20
-rw-r--r--drivers/staging/lustre/lnet/selftest/timer.h16
-rw-r--r--drivers/staging/lustre/lustre/fid/Makefile3
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_internal.h6
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_request.c78
-rw-r--r--drivers/staging/lustre/lustre/fid/lproc_fid.c55
-rw-r--r--drivers/staging/lustre/lustre/fld/Makefile3
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_cache.c16
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_internal.h5
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_request.c74
-rw-r--r--drivers/staging/lustre/lustre/fld/lproc_fld.c43
-rw-r--r--drivers/staging/lustre/lustre/include/dt_object.h3
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_compat25.h15
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_lite.h1
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h4
-rw-r--r--drivers/staging/lustre/lustre/include/linux/obd.h10
-rw-r--r--drivers/staging/lustre/lustre/include/lprocfs_status.h316
-rw-r--r--drivers/staging/lustre/lustre/include/lu_object.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_idl.h1
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_user.h1
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_dlm.h69
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_dlm_flags.h17
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_export.h29
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fid.h5
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fld.h16
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_lib.h15
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_net.h21
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_quota.h241
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_sec.h8
-rw-r--r--drivers/staging/lustre/lustre/include/obd.h22
-rw-r--r--drivers/staging/lustre/lustre/include/obd_class.h36
-rw-r--r--drivers/staging/lustre/lustre/include/obd_support.h66
-rw-r--r--drivers/staging/lustre/lustre/lclient/lcommon_cl.c45
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_internal.h76
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lib.c10
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lock.c22
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c90
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_pool.c178
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_request.c4
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_resource.c358
-rw-r--r--drivers/staging/lustre/lustre/libcfs/Makefile2
-rw-r--r--drivers/staging/lustre/lustre/libcfs/fail.c2
-rw-r--r--drivers/staging/lustre/lustre/libcfs/hash.c32
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c2
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-mem.c59
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c13
-rw-r--r--drivers/staging/lustre/lustre/libcfs/module.c12
-rw-r--r--drivers/staging/lustre/lustre/libcfs/tracefile.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/Makefile3
-rw-r--r--drivers/staging/lustre/lustre/llite/dcache.c6
-rw-r--r--drivers/staging/lustre/lustre/llite/dir.c128
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c95
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_capa.c1
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_close.c6
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_internal.h45
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_lib.c74
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_nfs.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_rmtacl.c4
-rw-r--r--drivers/staging/lustre/lustre/llite/lloop.c8
-rw-r--r--drivers/staging/lustre/lustre/llite/lproc_llite.c713
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/rw26.c24
-rw-r--r--drivers/staging/lustre/lustre/llite/statahead.c21
-rw-r--r--drivers/staging/lustre/lustre/llite/super25.c27
-rw-r--r--drivers/staging/lustre/lustre/llite/symlink.c26
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_dev.c23
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr.c10
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr_cache.c6
-rw-r--r--drivers/staging/lustre/lustre/lmv/Makefile3
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_intent.c4
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_internal.h8
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_obd.c124
-rw-r--r--drivers/staging/lustre/lustre/lmv/lproc_lmv.c107
-rw-r--r--drivers/staging/lustre/lustre/lov/Makefile3
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_dev.c19
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_ea.c7
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_internal.h44
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_io.c23
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_lock.c5
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_obd.c95
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_object.c5
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pack.c11
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pool.c53
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_request.c48
-rw-r--r--drivers/staging/lustre/lustre/lov/lovsub_dev.c4
-rw-r--r--drivers/staging/lustre/lustre/lov/lproc_lov.c58
-rw-r--r--drivers/staging/lustre/lustre/mdc/Makefile3
-rw-r--r--drivers/staging/lustre/lustre/mdc/lproc_mdc.c92
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_internal.h7
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_locks.c6
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_request.c51
-rw-r--r--drivers/staging/lustre/lustre/mgc/Makefile3
-rw-r--r--drivers/staging/lustre/lustre/mgc/lproc_mgc.c9
-rw-r--r--drivers/staging/lustre/lustre/mgc/mgc_internal.h11
-rw-r--r--drivers/staging/lustre/lustre/mgc/mgc_request.c28
-rw-r--r--drivers/staging/lustre/lustre/obdclass/Makefile4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/acl.c30
-rw-r--r--drivers/staging/lustre/lustre/obdclass/capa.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_io.c13
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_object.c6
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_page.c20
-rw-r--r--drivers/staging/lustre/lustre/obdclass/class_obd.c41
-rw-r--r--drivers/staging/lustre/lustre/obdclass/dt_object.c15
-rw-r--r--drivers/staging/lustre/lustre/obdclass/genops.c75
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-module.c157
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c25
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog.c25
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_cat.c6
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_obd.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lprocfs_status.c625
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lu_object.c18
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lustre_handles.c7
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lustre_peer.c6
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_config.c147
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_mount.c109
-rw-r--r--drivers/staging/lustre/lustre/obdecho/Makefile2
-rw-r--r--drivers/staging/lustre/lustre/obdecho/echo_client.c53
-rw-r--r--drivers/staging/lustre/lustre/obdecho/lproc_echo.c57
-rw-r--r--drivers/staging/lustre/lustre/osc/Makefile3
-rw-r--r--drivers/staging/lustre/lustre/osc/lproc_osc.c408
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_cache.c196
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_dev.c16
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_internal.h8
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_io.c124
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_lock.c151
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_object.c18
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_page.c38
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_quota.c14
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_request.c221
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/Makefile3
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/client.c114
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/connection.c6
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/events.c60
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/import.c8
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/layout.c70
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/llog_client.c82
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c371
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/niobuf.c62
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/nrs.c178
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/nrs_fifo.c10
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pack_generic.c18
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pinger.c30
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h21
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c20
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec.c108
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c76
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_config.c76
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_gc.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c39
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_null.c24
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_plain.c107
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/service.c364
-rw-r--r--drivers/staging/lustre/sysfs-fs-lustre543
-rw-r--r--drivers/staging/media/Kconfig2
-rw-r--r--drivers/staging/media/Makefile1
-rw-r--r--drivers/staging/media/bcm2048/radio-bcm2048.c7
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_resizer.c1
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h2
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c18
-rw-r--r--drivers/staging/media/dt3155v4l/Kconfig29
-rw-r--r--drivers/staging/media/dt3155v4l/Makefile1
-rw-r--r--drivers/staging/media/dt3155v4l/dt3155v4l.c981
-rw-r--r--drivers/staging/media/lirc/lirc_imon.c97
-rw-r--r--drivers/staging/media/lirc/lirc_sir.c75
-rw-r--r--drivers/staging/media/mn88472/mn88472.c6
-rw-r--r--drivers/staging/media/mn88472/mn88472_priv.h2
-rw-r--r--drivers/staging/media/mn88473/mn88473.c2
-rw-r--r--drivers/staging/media/mn88473/mn88473_priv.h2
-rw-r--r--drivers/staging/media/omap4iss/iss.c2
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.c18
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipe.c30
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipeif.c10
-rw-r--r--drivers/staging/media/omap4iss/iss_resizer.c8
-rw-r--r--drivers/staging/nvec/nvec.c2
-rw-r--r--drivers/staging/nvec/nvec_ps2.c4
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c16
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.h2
-rw-r--r--drivers/staging/octeon/ethernet-defines.h62
-rw-r--r--drivers/staging/octeon/ethernet-mdio.c48
-rw-r--r--drivers/staging/octeon/ethernet-mdio.h24
-rw-r--r--drivers/staging/octeon/ethernet-mem.c30
-rw-r--r--drivers/staging/octeon/ethernet-mem.h23
-rw-r--r--drivers/staging/octeon/ethernet-rgmii.c306
-rw-r--r--drivers/staging/octeon/ethernet-rx.c38
-rw-r--r--drivers/staging/octeon/ethernet-rx.h24
-rw-r--r--drivers/staging/octeon/ethernet-sgmii.c112
-rw-r--r--drivers/staging/octeon/ethernet-spi.c237
-rw-r--r--drivers/staging/octeon/ethernet-tx.c28
-rw-r--r--drivers/staging/octeon/ethernet-tx.h23
-rw-r--r--drivers/staging/octeon/ethernet-util.h23
-rw-r--r--drivers/staging/octeon/ethernet-xaui.c114
-rw-r--r--drivers/staging/octeon/ethernet.c115
-rw-r--r--drivers/staging/octeon/octeon-ethernet.h35
-rw-r--r--drivers/staging/ozwpan/ozusbsvc1.c11
-rw-r--r--drivers/staging/panel/panel.c74
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ap.c56
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_efuse.c2
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ioctl_set.c19
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_led.c2
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme.c11
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c3379
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_recv.c2
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_sta_mgt.c38
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_wlan_util.c12
-rw-r--r--drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/hal_intf.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/phy.c10
-rw-r--r--drivers/staging/rtl8188eu/hal/pwrseqcmd.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_dm.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_halinit.c1
-rw-r--r--drivers/staging/rtl8188eu/include/drv_types.h1
-rw-r--r--drivers/staging/rtl8188eu/include/ieee80211.h29
-rw-r--r--drivers/staging/rtl8188eu/include/odm.h10
-rw-r--r--drivers/staging/rtl8188eu/include/odm_HWConfig.h3
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_intf.h2
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_service.h2
-rw-r--r--drivers/staging/rtl8188eu/include/recv_osdep.h3
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_hal.h17
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_ap.h2
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_ioctl.h2
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_led.h2
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme.h2
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme_ext.h86
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_security.h2
-rw-r--r--drivers/staging/rtl8188eu/include/wifi.h77
-rw-r--r--drivers/staging/rtl8188eu/os_dep/ioctl_linux.c8
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mlme_linux.c4
-rw-r--r--drivers/staging/rtl8188eu/os_dep/os_intfs.c112
-rw-r--r--drivers/staging/rtl8188eu/os_dep/osdep_service.c3
-rw-r--r--drivers/staging/rtl8188eu/os_dep/rtw_android.c2
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_intf.c12
-rw-r--r--drivers/staging/rtl8192e/dot11d.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8190P_def.h40
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c25
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c290
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h134
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c74
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c43
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h5
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.h6
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c118
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h6
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h1496
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h908
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_cam.c34
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_cam.h9
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.c148
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.h419
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_crypto.h382
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.c1188
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.h103
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pci.c6
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pci.h17
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pm.c6
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_ps.c13
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.c107
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.h4
-rw-r--r--drivers/staging/rtl8192e/rtl819x_BAProc.c149
-rw-r--r--drivers/staging/rtl8192e/rtl819x_HT.h136
-rw-r--r--drivers/staging/rtl8192e/rtl819x_HTProc.c55
-rw-r--r--drivers/staging/rtl8192e/rtl819x_Qos.h198
-rw-r--r--drivers/staging/rtl8192e/rtl819x_TS.h3
-rw-r--r--drivers/staging/rtl8192e/rtl819x_TSProc.c93
-rw-r--r--drivers/staging/rtl8192e/rtllib.h645
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt.c254
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt.h34
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt_ccmp.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt_tkip.c89
-rw-r--r--drivers/staging/rtl8192e/rtllib_debug.h11
-rw-r--r--drivers/staging/rtl8192e/rtllib_module.c72
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c1016
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac.c295
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac_wx.c18
-rw-r--r--drivers/staging/rtl8192e/rtllib_tx.c78
-rw-r--r--drivers/staging/rtl8192e/rtllib_wx.c108
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h188
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c10
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c26
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_wep.c43
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c76
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c61
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c14
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c48
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c26
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.c14
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware.h11
-rw-r--r--drivers/staging/rtl8712/ieee80211.h29
-rw-r--r--drivers/staging/rtl8712/os_intfs.c8
-rw-r--r--drivers/staging/rtl8712/recv_linux.c4
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.c3
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.c12
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_linux.c3
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h2
-rw-r--r--drivers/staging/rtl8712/rtl871x_sta_mgt.c4
-rw-r--r--drivers/staging/rtl8723au/core/rtw_ap.c8
-rw-r--r--drivers/staging/rtl8723au/core/rtw_mlme_ext.c20
-rw-r--r--drivers/staging/rtl8723au/core/rtw_wlan_util.c12
-rw-r--r--drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c2
-rw-r--r--drivers/staging/rtl8723au/hal/odm.c4
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723a_cmd.c2
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c4
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c2
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c8
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723au_xmit.c2
-rw-r--r--drivers/staging/rtl8723au/hal/usb_halinit.c2
-rw-r--r--drivers/staging/rtl8723au/include/odm_debug.h2
-rw-r--r--drivers/staging/rtl8723au/include/rtl8723a_hal.h23
-rw-r--r--drivers/staging/rtl8723au/include/rtw_cmd.h2
-rw-r--r--drivers/staging/rtl8723au/include/rtw_mlme.h10
-rw-r--r--drivers/staging/rtl8723au/include/rtw_mlme_ext.h2
-rw-r--r--drivers/staging/rtl8723au/include/sta_info.h2
-rw-r--r--drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c4
-rw-r--r--drivers/staging/rtl8723au/os_dep/os_intfs.c4
-rw-r--r--drivers/staging/rts5208/rtsx.c3
-rw-r--r--drivers/staging/rts5208/rtsx.h28
-rw-r--r--drivers/staging/rts5208/rtsx_chip.c452
-rw-r--r--drivers/staging/rts5208/rtsx_scsi.c8
-rw-r--r--drivers/staging/rts5208/xd.c3
-rw-r--r--drivers/staging/skein/skein_api.h6
-rw-r--r--drivers/staging/slicoss/TODO1
-rw-r--r--drivers/staging/slicoss/slic.h22
-rw-r--r--drivers/staging/slicoss/slicoss.c130
-rw-r--r--drivers/staging/sm750fb/Kconfig4
-rw-r--r--drivers/staging/sm750fb/TODO3
-rw-r--r--drivers/staging/sm750fb/ddk750_chip.c19
-rw-r--r--drivers/staging/sm750fb/ddk750_chip.h75
-rw-r--r--drivers/staging/sm750fb/ddk750_display.c44
-rw-r--r--drivers/staging/sm750fb/ddk750_dvi.c4
-rw-r--r--drivers/staging/sm750fb/ddk750_dvi.h68
-rw-r--r--drivers/staging/sm750fb/ddk750_help.c6
-rw-r--r--drivers/staging/sm750fb/ddk750_help.h8
-rw-r--r--drivers/staging/sm750fb/ddk750_hwi2c.h4
-rw-r--r--drivers/staging/sm750fb/ddk750_mode.c56
-rw-r--r--drivers/staging/sm750fb/ddk750_mode.h2
-rw-r--r--drivers/staging/sm750fb/ddk750_power.c4
-rw-r--r--drivers/staging/sm750fb/ddk750_power.h2
-rw-r--r--drivers/staging/sm750fb/ddk750_reg.h4
-rw-r--r--drivers/staging/sm750fb/ddk750_sii164.c15
-rw-r--r--drivers/staging/sm750fb/ddk750_swi2c.c448
-rw-r--r--drivers/staging/sm750fb/ddk750_swi2c.h18
-rw-r--r--drivers/staging/sm750fb/modedb.h446
-rw-r--r--drivers/staging/sm750fb/readme8
-rw-r--r--drivers/staging/sm750fb/sm750.c62
-rw-r--r--drivers/staging/sm750fb/sm750.h70
-rw-r--r--drivers/staging/sm750fb/sm750_accel.c199
-rw-r--r--drivers/staging/sm750fb/sm750_accel.h16
-rw-r--r--drivers/staging/sm750fb/sm750_cursor.c63
-rw-r--r--drivers/staging/sm750fb/sm750_cursor.h24
-rw-r--r--drivers/staging/sm750fb/sm750_help.h40
-rw-r--r--drivers/staging/sm750fb/sm750_hw.c89
-rw-r--r--drivers/staging/sm750fb/sm750_hw.h23
-rw-r--r--drivers/staging/sm7xxfb/sm7xx.h664
-rw-r--r--drivers/staging/sm7xxfb/sm7xxfb.c1074
-rw-r--r--drivers/staging/speakup/main.c9
-rw-r--r--drivers/staging/unisys/Kconfig10
-rw-r--r--drivers/staging/unisys/Makefile8
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/controlframework.h62
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/diagchannel.h427
-rw-r--r--drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h310
-rw-r--r--drivers/staging/unisys/include/channel.h (renamed from drivers/staging/unisys/common-spar/include/channels/channel.h)35
-rw-r--r--drivers/staging/unisys/include/channel_guid.h (renamed from drivers/staging/unisys/common-spar/include/channels/channel_guid.h)0
-rw-r--r--drivers/staging/unisys/include/diagchannel.h43
-rw-r--r--drivers/staging/unisys/include/guestlinuxdebug.h3
-rw-r--r--drivers/staging/unisys/include/iochannel.h (renamed from drivers/staging/unisys/common-spar/include/channels/iochannel.h)450
-rw-r--r--drivers/staging/unisys/include/periodic_work.h10
-rw-r--r--drivers/staging/unisys/include/procobjecttree.h47
-rw-r--r--drivers/staging/unisys/include/sparstop.h30
-rw-r--r--drivers/staging/unisys/include/timskmod.h153
-rw-r--r--drivers/staging/unisys/include/uisqueue.h396
-rw-r--r--drivers/staging/unisys/include/uisthread.h42
-rw-r--r--drivers/staging/unisys/include/uisutils.h299
-rw-r--r--drivers/staging/unisys/include/vbushelper.h2
-rw-r--r--drivers/staging/unisys/include/version.h (renamed from drivers/staging/unisys/common-spar/include/version.h)0
-rw-r--r--drivers/staging/unisys/include/visorbus.h222
-rw-r--r--drivers/staging/unisys/uislib/Kconfig10
-rw-r--r--drivers/staging/unisys/uislib/Makefile12
-rw-r--r--drivers/staging/unisys/uislib/uislib.c1372
-rw-r--r--drivers/staging/unisys/uislib/uisqueue.c322
-rw-r--r--drivers/staging/unisys/uislib/uisthread.c69
-rw-r--r--drivers/staging/unisys/uislib/uisutils.c137
-rw-r--r--drivers/staging/unisys/virthba/Kconfig13
-rw-r--r--drivers/staging/unisys/virthba/Makefile12
-rw-r--r--drivers/staging/unisys/virthba/virthba.c1572
-rw-r--r--drivers/staging/unisys/virthba/virthba.h27
-rw-r--r--drivers/staging/unisys/virtpci/Kconfig10
-rw-r--r--drivers/staging/unisys/virtpci/Makefile10
-rw-r--r--drivers/staging/unisys/virtpci/virtpci.c1394
-rw-r--r--drivers/staging/unisys/virtpci/virtpci.h103
-rw-r--r--drivers/staging/unisys/visorbus/Kconfig9
-rw-r--r--drivers/staging/unisys/visorbus/Makefile13
-rw-r--r--drivers/staging/unisys/visorbus/controlvmchannel.h (renamed from drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h)304
-rw-r--r--drivers/staging/unisys/visorbus/controlvmcompletionstatus.h (renamed from drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h)0
-rw-r--r--drivers/staging/unisys/visorbus/iovmcall_gnuc.h (renamed from drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h)0
-rw-r--r--drivers/staging/unisys/visorbus/periodic_work.c (renamed from drivers/staging/unisys/visorutil/periodic_work.c)56
-rw-r--r--drivers/staging/unisys/visorbus/vbuschannel.h (renamed from drivers/staging/unisys/common-spar/include/channels/vbuschannel.h)2
-rw-r--r--drivers/staging/unisys/visorbus/vbusdeviceinfo.h (renamed from drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h)0
-rw-r--r--drivers/staging/unisys/visorbus/visorbus_main.c1518
-rw-r--r--drivers/staging/unisys/visorbus/visorbus_private.h69
-rw-r--r--drivers/staging/unisys/visorbus/visorchannel.c (renamed from drivers/staging/unisys/visorchannel/visorchannel_funcs.c)468
-rw-r--r--drivers/staging/unisys/visorbus/visorchipset.c (renamed from drivers/staging/unisys/visorchipset/visorchipset_main.c)1552
-rw-r--r--drivers/staging/unisys/visorbus/vmcallinterface.h (renamed from drivers/staging/unisys/common-spar/include/vmcallinterface.h)16
-rw-r--r--drivers/staging/unisys/visorchannel/Kconfig10
-rw-r--r--drivers/staging/unisys/visorchannel/Makefile12
-rw-r--r--drivers/staging/unisys/visorchannel/globals.h27
-rw-r--r--drivers/staging/unisys/visorchannel/visorchannel.h76
-rw-r--r--drivers/staging/unisys/visorchannel/visorchannel_main.c50
-rw-r--r--drivers/staging/unisys/visorchipset/Kconfig11
-rw-r--r--drivers/staging/unisys/visorchipset/Makefile15
-rw-r--r--drivers/staging/unisys/visorchipset/file.c160
-rw-r--r--drivers/staging/unisys/visorchipset/file.h27
-rw-r--r--drivers/staging/unisys/visorchipset/globals.h42
-rw-r--r--drivers/staging/unisys/visorchipset/parser.c430
-rw-r--r--drivers/staging/unisys/visorchipset/parser.h46
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset.h236
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset_umode.h35
-rw-r--r--drivers/staging/unisys/visornic/Kconfig15
-rw-r--r--drivers/staging/unisys/visornic/Makefile10
-rw-r--r--drivers/staging/unisys/visornic/visornic_main.c2140
-rw-r--r--drivers/staging/unisys/visorutil/Kconfig9
-rw-r--r--drivers/staging/unisys/visorutil/Makefile9
-rw-r--r--drivers/staging/unisys/visorutil/charqueue.c127
-rw-r--r--drivers/staging/unisys/visorutil/charqueue.h37
-rw-r--r--drivers/staging/unisys/visorutil/memregion.h43
-rw-r--r--drivers/staging/unisys/visorutil/memregion_direct.c207
-rw-r--r--drivers/staging/unisys/visorutil/visorkmodutils.c71
-rw-r--r--drivers/staging/vme/devices/vme_user.c257
-rw-r--r--drivers/staging/vt6655/Makefile1
-rw-r--r--drivers/staging/vt6655/device.h11
-rw-r--r--drivers/staging/vt6655/device_main.c250
-rw-r--r--drivers/staging/vt6655/mac.c49
-rw-r--r--drivers/staging/vt6655/mib.c139
-rw-r--r--drivers/staging/vt6655/mib.h82
-rw-r--r--drivers/staging/vt6655/power.h8
-rw-r--r--drivers/staging/vt6655/rxtx.c10
-rw-r--r--drivers/staging/vt6656/card.c2
-rw-r--r--drivers/staging/vt6656/device.h2
-rw-r--r--drivers/staging/vt6656/main_usb.c21
-rw-r--r--drivers/staging/vt6656/rxtx.c2
-rw-r--r--drivers/staging/vt6656/usbpipe.c2
-rw-r--r--drivers/staging/wilc1000/Kconfig59
-rw-r--r--drivers/staging/wilc1000/Makefile34
-rw-r--r--drivers/staging/wilc1000/TODO14
-rw-r--r--drivers/staging/wilc1000/coreconfigsimulator.h17
-rw-r--r--drivers/staging/wilc1000/coreconfigurator.c2156
-rw-r--r--drivers/staging/wilc1000/coreconfigurator.h197
-rw-r--r--drivers/staging/wilc1000/fifo_buffer.c133
-rw-r--r--drivers/staging/wilc1000/fifo_buffer.h26
-rw-r--r--drivers/staging/wilc1000/host_interface.c7963
-rw-r--r--drivers/staging/wilc1000/host_interface.h1281
-rw-r--r--drivers/staging/wilc1000/linux_mon.c598
-rw-r--r--drivers/staging/wilc1000/linux_wlan.c2783
-rw-r--r--drivers/staging/wilc1000/linux_wlan_common.h182
-rw-r--r--drivers/staging/wilc1000/linux_wlan_sdio.c249
-rw-r--r--drivers/staging/wilc1000/linux_wlan_sdio.h14
-rw-r--r--drivers/staging/wilc1000/linux_wlan_spi.c479
-rw-r--r--drivers/staging/wilc1000/linux_wlan_spi.h14
-rw-r--r--drivers/staging/wilc1000/wilc_debugfs.c191
-rw-r--r--drivers/staging/wilc1000/wilc_errorsupport.h67
-rw-r--r--drivers/staging/wilc1000/wilc_exported_buf.c76
-rw-r--r--drivers/staging/wilc1000/wilc_log.h47
-rw-r--r--drivers/staging/wilc1000/wilc_memory.c58
-rw-r--r--drivers/staging/wilc1000/wilc_memory.h239
-rw-r--r--drivers/staging/wilc1000/wilc_msgqueue.c190
-rw-r--r--drivers/staging/wilc1000/wilc_msgqueue.h108
-rw-r--r--drivers/staging/wilc1000/wilc_osconfig.h9
-rw-r--r--drivers/staging/wilc1000/wilc_oswrapper.h41
-rw-r--r--drivers/staging/wilc1000/wilc_platform.h52
-rw-r--r--drivers/staging/wilc1000/wilc_sdio.c1254
-rw-r--r--drivers/staging/wilc1000/wilc_sleep.c18
-rw-r--r--drivers/staging/wilc1000/wilc_sleep.h20
-rw-r--r--drivers/staging/wilc1000/wilc_spi.c1406
-rw-r--r--drivers/staging/wilc1000/wilc_strutils.c80
-rw-r--r--drivers/staging/wilc1000/wilc_strutils.h134
-rw-r--r--drivers/staging/wilc1000/wilc_timer.c45
-rw-r--r--drivers/staging/wilc1000/wilc_timer.h129
-rw-r--r--drivers/staging/wilc1000/wilc_type.h34
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.c3957
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.h129
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_netdevice.c951
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_netdevice.h254
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.c2332
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.h321
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_cfg.c617
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_cfg.h33
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_if.h969
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c2
-rw-r--r--drivers/staging/wlan-ng/p80211conv.c6
-rw-r--r--drivers/staging/wlan-ng/p80211wep.c14
-rw-r--r--drivers/staging/wlan-ng/prism2fw.c8
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c23
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c27
-rw-r--r--drivers/staging/xgifb/vb_setmode.c21
-rw-r--r--drivers/target/iscsi/iscsi_target.c3
-rw-r--r--drivers/target/iscsi/iscsi_target_device.c1
-rw-r--r--drivers/target/iscsi/iscsi_target_tmr.c2
-rw-r--r--drivers/target/sbp/sbp_target.c2
-rw-r--r--drivers/target/target_core_alua.c3
-rw-r--r--drivers/target/target_core_device.c4
-rw-r--r--drivers/target/target_core_fabric_lib.c4
-rw-r--r--drivers/target/target_core_file.c4
-rw-r--r--drivers/target/target_core_iblock.c3
-rw-r--r--drivers/target/target_core_pr.c4
-rw-r--r--drivers/target/target_core_pscsi.c2
-rw-r--r--drivers/target/target_core_pscsi.h6
-rw-r--r--drivers/target/target_core_rd.c3
-rw-r--r--drivers/target/target_core_sbc.c2
-rw-r--r--drivers/target/target_core_spc.c3
-rw-r--r--drivers/target/target_core_stat.c3
-rw-r--r--drivers/target/target_core_tmr.c2
-rw-r--r--drivers/target/target_core_tpg.c3
-rw-r--r--drivers/target/target_core_transport.c5
-rw-r--r--drivers/target/target_core_ua.c3
-rw-r--r--drivers/target/target_core_user.c6
-rw-r--r--drivers/target/target_core_xcopy.c3
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c4
-rw-r--r--drivers/target/tcm_fc/tfc_conf.c4
-rw-r--r--drivers/target/tcm_fc/tfc_io.c4
-rw-r--r--drivers/target/tcm_fc/tfc_sess.c4
-rw-r--r--drivers/thermal/Kconfig68
-rw-r--r--drivers/thermal/Makefile5
-rw-r--r--drivers/thermal/cpu_cooling.c585
-rw-r--r--drivers/thermal/db8500_thermal.c2
-rw-r--r--drivers/thermal/fair_share.c41
-rw-r--r--drivers/thermal/hisi_thermal.c421
-rw-r--r--drivers/thermal/imx_thermal.c3
-rw-r--r--drivers/thermal/int340x_thermal/processor_thermal_device.c59
-rw-r--r--drivers/thermal/intel_powerclamp.c1
-rw-r--r--drivers/thermal/intel_quark_dts_thermal.c473
-rw-r--r--drivers/thermal/intel_soc_dts_iosf.c478
-rw-r--r--drivers/thermal/intel_soc_dts_iosf.h62
-rw-r--r--drivers/thermal/intel_soc_dts_thermal.c430
-rw-r--r--drivers/thermal/of-thermal.c41
-rw-r--r--drivers/thermal/power_allocator.c539
-rw-r--r--drivers/thermal/qcom-spmi-temp-alarm.c309
-rw-r--r--drivers/thermal/samsung/exynos_tmu.c187
-rw-r--r--drivers/thermal/samsung/exynos_tmu.h1
-rw-r--r--drivers/thermal/thermal_core.c314
-rw-r--r--drivers/thermal/thermal_core.h11
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-bandgap.c104
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-thermal-common.c5
-rw-r--r--drivers/thermal/x86_pkg_temp_thermal.c2
-rw-r--r--drivers/tty/amiserial.c11
-rw-r--r--drivers/tty/cyclades.c8
-rw-r--r--drivers/tty/goldfish.c4
-rw-r--r--drivers/tty/hvc/Kconfig7
-rw-r--r--drivers/tty/hvc/Makefile1
-rw-r--r--drivers/tty/hvc/hvc_beat.c134
-rw-r--r--drivers/tty/hvc/hvc_console.c3
-rw-r--r--drivers/tty/hvc/hvc_opal.c33
-rw-r--r--drivers/tty/hvc/hvcs.c4
-rw-r--r--drivers/tty/n_gsm.c5
-rw-r--r--drivers/tty/n_tty.c7
-rw-r--r--drivers/tty/nozomi.c8
-rw-r--r--drivers/tty/rocket.h2
-rw-r--r--drivers/tty/serial/68328serial.c3
-rw-r--r--drivers/tty/serial/8250/8250_core.c27
-rw-r--r--drivers/tty/serial/8250/8250_dw.c19
-rw-r--r--drivers/tty/serial/8250/8250_early.c2
-rw-r--r--drivers/tty/serial/8250/8250_lpc18xx.c230
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c119
-rw-r--r--drivers/tty/serial/8250/8250_omap.c65
-rw-r--r--drivers/tty/serial/8250/8250_pci.c41
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c257
-rw-r--r--drivers/tty/serial/8250/Kconfig15
-rw-r--r--drivers/tty/serial/8250/Makefile2
-rw-r--r--drivers/tty/serial/Kconfig74
-rw-r--r--drivers/tty/serial/Makefile4
-rw-r--r--drivers/tty/serial/altera_jtaguart.c2
-rw-r--r--drivers/tty/serial/altera_uart.c2
-rw-r--r--drivers/tty/serial/amba-pl011.c651
-rw-r--r--drivers/tty/serial/atmel_serial.c22
-rw-r--r--drivers/tty/serial/bfin_uart.c24
-rw-r--r--drivers/tty/serial/crisv10.c106
-rw-r--r--drivers/tty/serial/earlycon.c9
-rw-r--r--drivers/tty/serial/icom.c11
-rw-r--r--drivers/tty/serial/ifx6x60.c19
-rw-r--r--drivers/tty/serial/imx.c18
-rw-r--r--drivers/tty/serial/ioc3_serial.c3
-rw-r--r--drivers/tty/serial/ioc4_serial.c9
-rw-r--r--drivers/tty/serial/kgdb_nmi.c6
-rw-r--r--drivers/tty/serial/mcf.c2
-rw-r--r--drivers/tty/serial/meson_uart.c2
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c2
-rw-r--r--drivers/tty/serial/mpsc.c25
-rw-r--r--drivers/tty/serial/msm_smd_tty.c232
-rw-r--r--drivers/tty/serial/mxs-auart.c2
-rw-r--r--drivers/tty/serial/of_serial.c8
-rw-r--r--drivers/tty/serial/samsung.c4
-rw-r--r--drivers/tty/serial/sc16is7xx.c328
-rw-r--r--drivers/tty/serial/serial-tegra.c158
-rw-r--r--drivers/tty/serial/serial_core.c32
-rw-r--r--drivers/tty/serial/serial_ks8695.c2
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c7
-rw-r--r--drivers/tty/serial/sh-sci.c136
-rw-r--r--drivers/tty/serial/sh-sci.h140
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c622
-rw-r--r--drivers/tty/serial/sirfsoc_uart.h120
-rw-r--r--drivers/tty/serial/sprd_serial.c2
-rw-r--r--drivers/tty/serial/stm32-usart.c739
-rw-r--r--drivers/tty/serial/xilinx_uartps.c3
-rw-r--r--drivers/tty/synclink.c15
-rw-r--r--drivers/tty/synclink_gt.c15
-rw-r--r--drivers/tty/synclinkmp.c12
-rw-r--r--drivers/tty/sysrq.c21
-rw-r--r--drivers/tty/tty_buffer.c3
-rw-r--r--drivers/tty/tty_io.c34
-rw-r--r--drivers/tty/tty_ioctl.c4
-rw-r--r--drivers/tty/tty_ldisc.c8
-rw-r--r--drivers/tty/tty_ldsem.c3
-rw-r--r--drivers/tty/vt/consolemap.c60
-rw-r--r--drivers/tty/vt/keyboard.c156
-rw-r--r--drivers/tty/vt/vt.c92
-rw-r--r--drivers/uio/Kconfig2
-rw-r--r--drivers/uio/uio.c3
-rw-r--r--drivers/uio/uio_pruss.c1
-rw-r--r--drivers/usb/atm/speedtch.c18
-rw-r--r--drivers/usb/atm/usbatm.c6
-rw-r--r--drivers/usb/atm/xusbatm.c6
-rw-r--r--drivers/usb/chipidea/ci_hdrc_usb2.c8
-rw-r--r--drivers/usb/chipidea/host.c12
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c2
-rw-r--r--drivers/usb/class/cdc-acm.c57
-rw-r--r--drivers/usb/class/cdc-acm.h3
-rw-r--r--drivers/usb/class/usblp.c15
-rw-r--r--drivers/usb/class/usbtmc.c1
-rw-r--r--drivers/usb/common/Makefile1
-rw-r--r--drivers/usb/common/ulpi.c255
-rw-r--r--drivers/usb/core/Kconfig20
-rw-r--r--drivers/usb/core/buffer.c3
-rw-r--r--drivers/usb/core/devio.c2
-rw-r--r--drivers/usb/core/hcd.c3
-rw-r--r--drivers/usb/core/hub.c122
-rw-r--r--drivers/usb/dwc2/Kconfig8
-rw-r--r--drivers/usb/dwc2/Makefile9
-rw-r--r--drivers/usb/dwc2/core.c439
-rw-r--r--drivers/usb/dwc2/core.h120
-rw-r--r--drivers/usb/dwc2/core_intr.c45
-rw-r--r--drivers/usb/dwc2/debug.h27
-rw-r--r--drivers/usb/dwc2/debugfs.c771
-rw-r--r--drivers/usb/dwc2/gadget.c459
-rw-r--r--drivers/usb/dwc2/hcd.c100
-rw-r--r--drivers/usb/dwc2/hcd.h7
-rw-r--r--drivers/usb/dwc2/hcd_intr.c66
-rw-r--r--drivers/usb/dwc2/hcd_queue.c18
-rw-r--r--drivers/usb/dwc2/platform.c25
-rw-r--r--drivers/usb/dwc3/Kconfig7
-rw-r--r--drivers/usb/dwc3/Makefile4
-rw-r--r--drivers/usb/dwc3/core.c108
-rw-r--r--drivers/usb/dwc3/core.h26
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c36
-rw-r--r--drivers/usb/dwc3/gadget.c10
-rw-r--r--drivers/usb/dwc3/platform_data.h2
-rw-r--r--drivers/usb/dwc3/ulpi.c91
-rw-r--r--drivers/usb/gadget/epautoconf.c24
-rw-r--r--drivers/usb/gadget/function/f_fs.c10
-rw-r--r--drivers/usb/gadget/function/f_rndis.c60
-rw-r--r--drivers/usb/gadget/function/rndis.c352
-rw-r--r--drivers/usb/gadget/function/rndis.h33
-rw-r--r--drivers/usb/gadget/function/u_rndis.h2
-rw-r--r--drivers/usb/gadget/function/uvc.h1
-rw-r--r--drivers/usb/gadget/legacy/inode.c9
-rw-r--r--drivers/usb/gadget/legacy/tcm_usb_gadget.c1
-rw-r--r--drivers/usb/gadget/legacy/tcm_usb_gadget.h1
-rw-r--r--drivers/usb/gadget/udc/atmel_usba_udc.c6
-rw-r--r--drivers/usb/gadget/udc/net2280.c140
-rw-r--r--drivers/usb/gadget/udc/s3c2410_udc.c28
-rw-r--r--drivers/usb/host/Kconfig2
-rw-r--r--drivers/usb/host/Makefile5
-rw-r--r--drivers/usb/host/ehci-dbg.c3
-rw-r--r--drivers/usb/host/ehci-fsl.c168
-rw-r--r--drivers/usb/host/ehci-hcd.c8
-rw-r--r--drivers/usb/host/ehci-hub.c3
-rw-r--r--drivers/usb/host/ehci-platform.c73
-rw-r--r--drivers/usb/host/ehci-tegra.c12
-rw-r--r--drivers/usb/host/ehci.h3
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c8
-rw-r--r--drivers/usb/host/fusbh200-hcd.c3
-rw-r--r--drivers/usb/host/isp116x-hcd.c3
-rw-r--r--drivers/usb/host/ohci-dbg.c6
-rw-r--r--drivers/usb/host/ohci-hcd.c3
-rw-r--r--drivers/usb/host/ohci-platform.c69
-rw-r--r--drivers/usb/host/ohci-q.c3
-rw-r--r--drivers/usb/host/ssb-hcd.c15
-rw-r--r--drivers/usb/host/xhci-hub.c65
-rw-r--r--drivers/usb/host/xhci-pci.c17
-rw-r--r--drivers/usb/host/xhci-plat.c43
-rw-r--r--drivers/usb/host/xhci-ring.c7
-rw-r--r--drivers/usb/host/xhci.c44
-rw-r--r--drivers/usb/host/xhci.h19
-rw-r--r--drivers/usb/image/microtek.c1
-rw-r--r--drivers/usb/isp1760/isp1760-udc.c2
-rw-r--r--drivers/usb/misc/ldusb.c10
-rw-r--r--drivers/usb/misc/lvstest.c2
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c39
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c54
-rw-r--r--drivers/usb/misc/uss720.c6
-rw-r--r--drivers/usb/mon/mon_bin.c7
-rw-r--r--drivers/usb/mon/mon_main.c12
-rw-r--r--drivers/usb/mon/mon_stat.c3
-rw-r--r--drivers/usb/musb/am35x.c8
-rw-r--r--drivers/usb/musb/blackfin.c5
-rw-r--r--drivers/usb/musb/cppi_dma.c9
-rw-r--r--drivers/usb/musb/da8xx.c6
-rw-r--r--drivers/usb/musb/davinci.c7
-rw-r--r--drivers/usb/musb/jz4740.c6
-rw-r--r--drivers/usb/musb/musb_core.c81
-rw-r--r--drivers/usb/musb/musb_core.h28
-rw-r--r--drivers/usb/musb/musb_cppi41.c8
-rw-r--r--drivers/usb/musb/musb_debugfs.c100
-rw-r--r--drivers/usb/musb/musb_dma.h67
-rw-r--r--drivers/usb/musb/musb_dsps.c6
-rw-r--r--drivers/usb/musb/musb_gadget.c24
-rw-r--r--drivers/usb/musb/musb_host.c536
-rw-r--r--drivers/usb/musb/musb_io.h2
-rw-r--r--drivers/usb/musb/musb_regs.h80
-rw-r--r--drivers/usb/musb/musb_virthub.c2
-rw-r--r--drivers/usb/musb/musbhsdma.c9
-rw-r--r--drivers/usb/musb/omap2430.c5
-rw-r--r--drivers/usb/musb/tusb6010.c8
-rw-r--r--drivers/usb/musb/tusb6010.h6
-rw-r--r--drivers/usb/musb/tusb6010_omap.c9
-rw-r--r--drivers/usb/musb/ux500.c8
-rw-r--r--drivers/usb/musb/ux500_dma.c8
-rw-r--r--drivers/usb/phy/Kconfig16
-rw-r--r--drivers/usb/phy/Makefile1
-rw-r--r--drivers/usb/phy/phy-ab8500-usb.c2
-rw-r--r--drivers/usb/phy/phy-msm-usb.c110
-rw-r--r--drivers/usb/phy/phy-rcar-gen2-usb.c246
-rw-r--r--drivers/usb/phy/phy-tahvo.c9
-rw-r--r--drivers/usb/phy/phy.c97
-rw-r--r--drivers/usb/renesas_usbhs/common.c19
-rw-r--r--drivers/usb/renesas_usbhs/fifo.h9
-rw-r--r--drivers/usb/renesas_usbhs/mod.c63
-rw-r--r--drivers/usb/serial/Kconfig2
-rw-r--r--drivers/usb/serial/mos7840.c11
-rw-r--r--drivers/usb/storage/alauda.c12
-rw-r--r--drivers/usb/storage/cypress_atacb.c10
-rw-r--r--drivers/usb/storage/datafab.c12
-rw-r--r--drivers/usb/storage/ene_ub6250.c11
-rw-r--r--drivers/usb/storage/freecom.c12
-rw-r--r--drivers/usb/storage/isd200.c11
-rw-r--r--drivers/usb/storage/jumpshot.c11
-rw-r--r--drivers/usb/storage/karma.c12
-rw-r--r--drivers/usb/storage/onetouch.c12
-rw-r--r--drivers/usb/storage/realtek_cr.c12
-rw-r--r--drivers/usb/storage/scsiglue.c31
-rw-r--r--drivers/usb/storage/scsiglue.h3
-rw-r--r--drivers/usb/storage/sddr09.c12
-rw-r--r--drivers/usb/storage/sddr55.c11
-rw-r--r--drivers/usb/storage/shuttle_usbat.c12
-rw-r--r--drivers/usb/storage/uas.c1
-rw-r--r--drivers/usb/storage/usb.c16
-rw-r--r--drivers/usb/storage/usb.h16
-rw-r--r--drivers/vfio/Kconfig2
-rw-r--r--drivers/vfio/vfio_iommu_spapr_tce.c1101
-rw-r--r--drivers/vfio/vfio_spapr_eeh.c10
-rw-r--r--drivers/vhost/scsi.c4
-rw-r--r--drivers/video/backlight/Kconfig8
-rw-r--r--drivers/video/backlight/da9052_bl.c2
-rw-r--r--drivers/video/backlight/gpio_backlight.c2
-rw-r--r--drivers/video/backlight/lp855x_bl.c18
-rw-r--r--drivers/video/backlight/pwm_bl.c6
-rw-r--r--drivers/video/console/fbcon.c5
-rw-r--r--drivers/video/console/fbcon.h1
-rw-r--r--drivers/video/console/newport_con.c6
-rw-r--r--drivers/video/fbdev/Kconfig8
-rw-r--r--drivers/video/fbdev/Makefile1
-rw-r--r--drivers/video/fbdev/amifb.c8
-rw-r--r--drivers/video/fbdev/atafb.c3
-rw-r--r--drivers/video/fbdev/atmel_lcdfb.c3
-rw-r--r--drivers/video/fbdev/aty/aty128fb.c36
-rw-r--r--drivers/video/fbdev/aty/radeon_base.c29
-rw-r--r--drivers/video/fbdev/aty/radeonfb.h2
-rw-r--r--drivers/video/fbdev/core/Makefile2
-rw-r--r--drivers/video/fbdev/core/fb_defio.c2
-rw-r--r--drivers/video/fbdev/core/fbmon.c4
-rw-r--r--drivers/video/fbdev/gbefb.c25
-rw-r--r--drivers/video/fbdev/geode/gxfb_core.c3
-rw-r--r--drivers/video/fbdev/hpfb.c4
-rw-r--r--drivers/video/fbdev/i810/i810.h3
-rw-r--r--drivers/video/fbdev/i810/i810_main.c11
-rw-r--r--drivers/video/fbdev/i810/i810_main.h26
-rw-r--r--drivers/video/fbdev/imxfb.c2
-rw-r--r--drivers/video/fbdev/intelfb/intelfb.h4
-rw-r--r--drivers/video/fbdev/intelfb/intelfbdrv.c38
-rw-r--r--drivers/video/fbdev/matrox/matroxfb_base.c42
-rw-r--r--drivers/video/fbdev/matrox/matroxfb_base.h27
-rw-r--r--drivers/video/fbdev/msm/Makefile19
-rw-r--r--drivers/video/fbdev/msm/mddi.c821
-rw-r--r--drivers/video/fbdev/msm/mddi_client_dummy.c85
-rw-r--r--drivers/video/fbdev/msm/mddi_client_nt35399.c252
-rw-r--r--drivers/video/fbdev/msm/mddi_client_toshiba.c280
-rw-r--r--drivers/video/fbdev/msm/mddi_hw.h305
-rw-r--r--drivers/video/fbdev/msm/mdp.c520
-rw-r--r--drivers/video/fbdev/msm/mdp_csc_table.h582
-rw-r--r--drivers/video/fbdev/msm/mdp_hw.h627
-rw-r--r--drivers/video/fbdev/msm/mdp_ppp.c731
-rw-r--r--drivers/video/fbdev/msm/mdp_scale_tables.c766
-rw-r--r--drivers/video/fbdev/msm/mdp_scale_tables.h38
-rw-r--r--drivers/video/fbdev/msm/msm_fb.c659
-rw-r--r--drivers/video/fbdev/mxsfb.c70
-rw-r--r--drivers/video/fbdev/neofb.c26
-rw-r--r--drivers/video/fbdev/nvidia/nv_type.h7
-rw-r--r--drivers/video/fbdev/nvidia/nvidia.c37
-rw-r--r--drivers/video/fbdev/omap/Kconfig2
-rw-r--r--drivers/video/fbdev/omap2/displays-new/encoder-opa362.c12
-rw-r--r--drivers/video/fbdev/omap2/displays-new/panel-dpi.c13
-rw-r--r--drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c7
-rw-r--r--drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c9
-rw-r--r--drivers/video/fbdev/omap2/dss/core.c80
-rw-r--r--drivers/video/fbdev/omap2/dss/dispc.c156
-rw-r--r--drivers/video/fbdev/omap2/dss/display-sysfs.c2
-rw-r--r--drivers/video/fbdev/omap2/dss/dpi.c36
-rw-r--r--drivers/video/fbdev/omap2/dss/dsi.c27
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.c223
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.h32
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4.c30
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4_core.c12
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5.c28
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5_core.c5
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_wp.c16
-rw-r--r--drivers/video/fbdev/omap2/dss/rfbi.c32
-rw-r--r--drivers/video/fbdev/omap2/dss/sdi.c35
-rw-r--r--drivers/video/fbdev/omap2/dss/venc.c31
-rw-r--r--drivers/video/fbdev/pm2fb.c31
-rw-r--r--drivers/video/fbdev/pm3fb.c30
-rw-r--r--drivers/video/fbdev/riva/fbdev.c39
-rw-r--r--drivers/video/fbdev/riva/rivafb.h4
-rw-r--r--drivers/video/fbdev/savage/savagefb.h4
-rw-r--r--drivers/video/fbdev/savage/savagefb_driver.c17
-rw-r--r--drivers/video/fbdev/sis/sis.h2
-rw-r--r--drivers/video/fbdev/sis/sis_main.c27
-rw-r--r--drivers/video/fbdev/ssd1307fb.c289
-rw-r--r--drivers/video/fbdev/tdfxfb.c41
-rw-r--r--drivers/video/fbdev/vesafb.c80
-rw-r--r--drivers/virtio/virtio_pci_common.c3
-rw-r--r--drivers/vme/bridges/Kconfig2
-rw-r--r--drivers/vme/bridges/vme_ca91cx42.c18
-rw-r--r--drivers/vme/bridges/vme_ca91cx42.h2
-rw-r--r--drivers/vme/bridges/vme_tsi148.c42
-rw-r--r--drivers/vme/vme.c11
-rw-r--r--drivers/w1/masters/ds2482.c1
-rw-r--r--drivers/w1/slaves/w1_therm.c162
-rw-r--r--drivers/w1/w1.c17
-rw-r--r--drivers/watchdog/Kconfig12
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/bcm2835_wdt.c62
-rw-r--r--drivers/watchdog/st_lpc_wdt.c344
-rw-r--r--drivers/xen/tmem.c8
-rw-r--r--drivers/xen/xen-acpi-cpuhotplug.c12
-rw-r--r--drivers/xen/xen-scsiback.c5
-rw-r--r--firmware/README.AddingFirmware14
-rw-r--r--fs/9p/v9fs.c50
-rw-r--r--fs/9p/v9fs.h2
-rw-r--r--fs/9p/vfs_inode.c123
-rw-r--r--fs/9p/vfs_inode_dotl.c39
-rw-r--r--fs/9p/vfs_super.c8
-rw-r--r--fs/afs/rxrpc.c2
-rw-r--r--fs/autofs4/symlink.c5
-rw-r--r--fs/befs/btree.c6
-rw-r--r--fs/befs/linuxvfs.c57
-rw-r--r--fs/block_dev.c9
-rw-r--r--fs/btrfs/disk-io.c13
-rw-r--r--fs/btrfs/extent_io.c2
-rw-r--r--fs/btrfs/volumes.c18
-rw-r--r--fs/btrfs/volumes.h2
-rw-r--r--fs/buffer.c75
-rw-r--r--fs/ceph/inode.c11
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/link.c28
-rw-r--r--fs/configfs/item.c3
-rw-r--r--fs/configfs/symlink.c31
-rw-r--r--fs/coredump.c19
-rw-r--r--fs/dcache.c16
-rw-r--r--fs/debugfs/file.c12
-rw-r--r--fs/debugfs/inode.c6
-rw-r--r--fs/dlm/lowcomms.c16
-rw-r--r--fs/ecryptfs/inode.c11
-rw-r--r--fs/efs/super.c2
-rw-r--r--fs/exofs/Kbuild2
-rw-r--r--fs/exofs/exofs.h4
-rw-r--r--fs/exofs/inode.c9
-rw-r--r--fs/exofs/namei.c5
-rw-r--r--fs/exofs/symlink.c55
-rw-r--r--fs/ext2/inode.c1
-rw-r--r--fs/ext2/namei.c3
-rw-r--r--fs/ext2/super.c1
-rw-r--r--fs/ext2/symlink.c10
-rw-r--r--fs/ext3/inode.c1
-rw-r--r--fs/ext3/namei.c3
-rw-r--r--fs/ext3/super.c2
-rw-r--r--fs/ext3/symlink.c10
-rw-r--r--fs/ext4/Kconfig1
-rw-r--r--fs/ext4/balloc.c4
-rw-r--r--fs/ext4/crypto.c211
-rw-r--r--fs/ext4/crypto_fname.c490
-rw-r--r--fs/ext4/crypto_key.c152
-rw-r--r--fs/ext4/crypto_policy.c87
-rw-r--r--fs/ext4/dir.c29
-rw-r--r--fs/ext4/ext4.h160
-rw-r--r--fs/ext4/ext4_crypto.h51
-rw-r--r--fs/ext4/extents.c340
-rw-r--r--fs/ext4/file.c19
-rw-r--r--fs/ext4/ialloc.c45
-rw-r--r--fs/ext4/indirect.c4
-rw-r--r--fs/ext4/inline.c31
-rw-r--r--fs/ext4/inode.c100
-rw-r--r--fs/ext4/ioctl.c11
-rw-r--r--fs/ext4/mballoc.c44
-rw-r--r--fs/ext4/move_extent.c19
-rw-r--r--fs/ext4/namei.c553
-rw-r--r--fs/ext4/page-io.c3
-rw-r--r--fs/ext4/readpage.c10
-rw-r--r--fs/ext4/super.c65
-rw-r--r--fs/ext4/symlink.c62
-rw-r--r--fs/f2fs/Kconfig19
-rw-r--r--fs/f2fs/Makefile2
-rw-r--r--fs/f2fs/acl.c46
-rw-r--r--fs/f2fs/checkpoint.c56
-rw-r--r--fs/f2fs/crypto.c491
-rw-r--r--fs/f2fs/crypto_fname.c440
-rw-r--r--fs/f2fs/crypto_key.c255
-rw-r--r--fs/f2fs/crypto_policy.c209
-rw-r--r--fs/f2fs/data.c593
-rw-r--r--fs/f2fs/debug.c11
-rw-r--r--fs/f2fs/dir.c194
-rw-r--r--fs/f2fs/f2fs.h320
-rw-r--r--fs/f2fs/f2fs_crypto.h151
-rw-r--r--fs/f2fs/file.c516
-rw-r--r--fs/f2fs/gc.c115
-rw-r--r--fs/f2fs/hash.c3
-rw-r--r--fs/f2fs/inline.c43
-rw-r--r--fs/f2fs/inode.c9
-rw-r--r--fs/f2fs/namei.c390
-rw-r--r--fs/f2fs/node.c52
-rw-r--r--fs/f2fs/node.h22
-rw-r--r--fs/f2fs/recovery.c28
-rw-r--r--fs/f2fs/segment.c250
-rw-r--r--fs/f2fs/segment.h4
-rw-r--r--fs/f2fs/super.c178
-rw-r--r--fs/f2fs/trace.c6
-rw-r--r--fs/f2fs/trace.h4
-rw-r--r--fs/f2fs/xattr.c3
-rw-r--r--fs/f2fs/xattr.h4
-rw-r--r--fs/fat/file.c1
-rw-r--r--fs/fat/inode.c1
-rw-r--r--fs/freevxfs/vxfs_extern.h3
-rw-r--r--fs/freevxfs/vxfs_immed.c34
-rw-r--r--fs/freevxfs/vxfs_inode.c7
-rw-r--r--fs/fs-writeback.c1167
-rw-r--r--fs/fuse/dir.c22
-rw-r--r--fs/fuse/file.c12
-rw-r--r--fs/gfs2/aops.c12
-rw-r--r--fs/gfs2/file.c4
-rw-r--r--fs/gfs2/glock.c3
-rw-r--r--fs/gfs2/glops.c20
-rw-r--r--fs/gfs2/incore.h2
-rw-r--r--fs/gfs2/inode.c221
-rw-r--r--fs/gfs2/ops_fstype.c1
-rw-r--r--fs/gfs2/quota.c212
-rw-r--r--fs/gfs2/rgrp.c48
-rw-r--r--fs/gfs2/rgrp.h1
-rw-r--r--fs/gfs2/super.c2
-rw-r--r--fs/gfs2/sys.c66
-rw-r--r--fs/hfs/super.c1
-rw-r--r--fs/hfsplus/super.c1
-rw-r--r--fs/hostfs/hostfs_kern.c15
-rw-r--r--fs/hppfs/hppfs.c13
-rw-r--r--fs/hugetlbfs/inode.c1
-rw-r--r--fs/inode.c32
-rw-r--r--fs/jbd2/checkpoint.c7
-rw-r--r--fs/jbd2/journal.c67
-rw-r--r--fs/jbd2/revoke.c15
-rw-r--r--fs/jbd2/transaction.c270
-rw-r--r--fs/jffs2/dir.c1
-rw-r--r--fs/jffs2/fs.c8
-rw-r--r--fs/jffs2/readinode.c27
-rw-r--r--fs/jffs2/symlink.c45
-rw-r--r--fs/jfs/inode.c3
-rw-r--r--fs/jfs/namei.c5
-rw-r--r--fs/jfs/symlink.c10
-rw-r--r--fs/kernfs/file.c1
-rw-r--r--fs/kernfs/kernfs-internal.h1
-rw-r--r--fs/kernfs/symlink.c25
-rw-r--r--fs/libfs.c25
-rw-r--r--fs/logfs/dir.c1
-rw-r--r--fs/minix/inode.c2
-rw-r--r--fs/mount.h1
-rw-r--r--fs/mpage.c3
-rw-r--r--fs/namei.c1453
-rw-r--r--fs/namespace.c27
-rw-r--r--fs/nfs/filelayout/filelayout.c1
-rw-r--r--fs/nfs/internal.h2
-rw-r--r--fs/nfs/symlink.c19
-rw-r--r--fs/nfs/write.c3
-rw-r--r--fs/nfsd/nfs3xdr.c12
-rw-r--r--fs/nfsd/nfs4acl.c18
-rw-r--r--fs/nfsd/nfs4callback.c15
-rw-r--r--fs/nfsd/nfs4proc.c43
-rw-r--r--fs/nfsd/nfs4state.c148
-rw-r--r--fs/nfsd/nfs4xdr.c75
-rw-r--r--fs/nfsd/nfsproc.c52
-rw-r--r--fs/nfsd/state.h7
-rw-r--r--fs/nfsd/vfs.c128
-rw-r--r--fs/nfsd/vfs.h11
-rw-r--r--fs/nfsd/xdr4.h1
-rw-r--r--fs/nilfs2/namei.c5
-rw-r--r--fs/nilfs2/segbuf.c12
-rw-r--r--fs/ntfs/file.c3
-rw-r--r--fs/ntfs/malloc.h7
-rw-r--r--fs/ntfs/namei.c2
-rw-r--r--fs/ocfs2/alloc.c37
-rw-r--r--fs/ocfs2/aops.c23
-rw-r--r--fs/ocfs2/aops.h7
-rw-r--r--fs/ocfs2/cluster/masklog.c34
-rw-r--r--fs/ocfs2/cluster/masklog.h42
-rw-r--r--fs/ocfs2/cluster/tcp.c2
-rw-r--r--fs/ocfs2/dir.c25
-rw-r--r--fs/ocfs2/dlm/dlmcommon.h1
-rw-r--r--fs/ocfs2/file.c32
-rw-r--r--fs/ocfs2/journal.c76
-rw-r--r--fs/ocfs2/namei.c33
-rw-r--r--fs/ocfs2/namei.h4
-rw-r--r--fs/ocfs2/ocfs2.h10
-rw-r--r--fs/ocfs2/refcounttree.c6
-rw-r--r--fs/ocfs2/xattr.c2
-rw-r--r--fs/open.c2
-rw-r--r--fs/overlayfs/inode.c35
-rw-r--r--fs/proc/Kconfig4
-rw-r--r--fs/proc/array.c12
-rw-r--r--fs/proc/base.c211
-rw-r--r--fs/proc/inode.c9
-rw-r--r--fs/proc/namespaces.c4
-rw-r--r--fs/proc/self.c24
-rw-r--r--fs/proc/thread_self.c22
-rw-r--r--fs/pstore/platform.c8
-rw-r--r--fs/pstore/ram.c50
-rw-r--r--fs/reiserfs/super.c4
-rw-r--r--fs/select.c6
-rw-r--r--fs/splice.c3
-rw-r--r--fs/sysfs/file.c2
-rw-r--r--fs/sysfs/group.c6
-rw-r--r--fs/sysv/Makefile2
-rw-r--r--fs/sysv/inode.c5
-rw-r--r--fs/sysv/symlink.c20
-rw-r--r--fs/sysv/sysv.h1
-rw-r--r--fs/ubifs/dir.c1
-rw-r--r--fs/ubifs/file.c11
-rw-r--r--fs/ubifs/super.c6
-rw-r--r--fs/udf/dir.c2
-rw-r--r--fs/udf/file.c2
-rw-r--r--fs/udf/namei.c95
-rw-r--r--fs/udf/super.c26
-rw-r--r--fs/udf/symlink.c3
-rw-r--r--fs/udf/unicode.c49
-rw-r--r--fs/ufs/inode.c5
-rw-r--r--fs/ufs/namei.c3
-rw-r--r--fs/ufs/super.c1
-rw-r--r--fs/ufs/symlink.c13
-rw-r--r--fs/xfs/xfs_aops.c13
-rw-r--r--fs/xfs/xfs_file.c1
-rw-r--r--fs/xfs/xfs_iops.c11
-rw-r--r--include/acpi/acpi_bus.h41
-rw-r--r--include/acpi/acpiosxf.h2
-rw-r--r--include/acpi/acpixf.h2
-rw-r--r--include/acpi/actbl.h17
-rw-r--r--include/acpi/actbl1.h176
-rw-r--r--include/acpi/actbl2.h146
-rw-r--r--include/acpi/actbl3.h88
-rw-r--r--include/acpi/actypes.h6
-rw-r--r--include/acpi/acuuid.h89
-rw-r--r--include/acpi/platform/acenv.h3
-rw-r--r--include/acpi/platform/acenvex.h3
-rw-r--r--include/acpi/video.h21
-rw-r--r--include/asm-generic/asm-offsets.h1
-rw-r--r--include/asm-generic/barrier.h4
-rw-r--r--include/asm-generic/cmpxchg.h3
-rw-r--r--include/asm-generic/futex.h7
-rw-r--r--include/asm-generic/gpio.h5
-rw-r--r--include/asm-generic/io.h17
-rw-r--r--include/asm-generic/iomap.h4
-rw-r--r--include/asm-generic/pci.h13
-rw-r--r--include/asm-generic/pgtable.h38
-rw-r--r--include/asm-generic/preempt.h7
-rw-r--r--include/asm-generic/qspinlock.h139
-rw-r--r--include/asm-generic/qspinlock_types.h79
-rw-r--r--include/asm-generic/scatterlist.h34
-rw-r--r--include/clocksource/timer-sp804.h (renamed from arch/arm/include/asm/hardware/timer-sp.h)5
-rw-r--r--include/crypto/aead.h533
-rw-r--r--include/crypto/akcipher.h340
-rw-r--r--include/crypto/algapi.h35
-rw-r--r--include/crypto/compress.h8
-rw-r--r--include/crypto/cryptd.h1
-rw-r--r--include/crypto/drbg.h59
-rw-r--r--include/crypto/hash.h2
-rw-r--r--include/crypto/internal/aead.h102
-rw-r--r--include/crypto/internal/akcipher.h60
-rw-r--r--include/crypto/internal/geniv.h24
-rw-r--r--include/crypto/internal/rng.h21
-rw-r--r--include/crypto/internal/rsa.h27
-rw-r--r--include/crypto/md5.h5
-rw-r--r--include/crypto/null.h3
-rw-r--r--include/crypto/rng.h100
-rw-r--r--include/crypto/scatterwalk.h4
-rw-r--r--include/drm/bridge/ptn3460.h45
-rw-r--r--include/drm/drmP.h19
-rw-r--r--include/drm/drm_atomic.h95
-rw-r--r--include/drm/drm_atomic_helper.h5
-rw-r--r--include/drm/drm_crtc.h65
-rw-r--r--include/drm/drm_dp_helper.h6
-rw-r--r--include/drm/drm_dp_mst_helper.h4
-rw-r--r--include/drm/drm_modes.h4
-rw-r--r--include/drm/i915_component.h1
-rw-r--r--include/drm/i915_pciids.h4
-rw-r--r--include/dt-bindings/clock/imx7d-clock.h450
-rw-r--r--include/dt-bindings/clock/qcom,gcc-ipq806x.h2
-rw-r--r--include/dt-bindings/clock/r8a73a4-clock.h1
-rw-r--r--include/dt-bindings/clock/r8a7790-clock.h3
-rw-r--r--include/dt-bindings/clock/r8a7791-clock.h3
-rw-r--r--include/dt-bindings/clock/r8a7794-clock.h3
-rw-r--r--include/dt-bindings/clock/samsung,s2mps11.h23
-rw-r--r--include/dt-bindings/clock/vf610-clock.h3
-rw-r--r--include/dt-bindings/clock/zx296702-clock.h170
-rw-r--r--include/dt-bindings/mfd/arizona.h18
-rw-r--r--include/dt-bindings/mfd/st-lpc.h15
-rw-r--r--include/dt-bindings/net/ti-dp83867.h45
-rw-r--r--include/dt-bindings/pinctrl/am43xx.h1
-rw-r--r--include/dt-bindings/pinctrl/bcm2835.h27
-rw-r--r--include/dt-bindings/pinctrl/mt6397-pinfunc.h256
-rw-r--r--include/dt-bindings/reset/qcom,gcc-ipq806x.h43
-rw-r--r--include/dt-bindings/sound/apq8016-lpass.h9
-rw-r--r--include/dt-bindings/sound/audio-jack-events.h9
-rw-r--r--include/dt-bindings/sound/tas2552.h18
-rw-r--r--include/linux/acpi.h76
-rw-r--r--include/linux/alarmtimer.h4
-rw-r--r--include/linux/ata.h12
-rw-r--r--include/linux/backing-dev-defs.h255
-rw-r--r--include/linux/backing-dev.h557
-rw-r--r--include/linux/backlight.h8
-rw-r--r--include/linux/basic_mmio_gpio.h1
-rw-r--r--include/linux/bcma/bcma.h9
-rw-r--r--include/linux/bcma/bcma_driver_pci.h11
-rw-r--r--include/linux/bio.h20
-rw-r--r--include/linux/blk-cgroup.h (renamed from block/blk-cgroup.h)72
-rw-r--r--include/linux/blk-mq.h4
-rw-r--r--include/linux/blk_types.h23
-rw-r--r--include/linux/blkdev.h63
-rw-r--r--include/linux/bootmem.h8
-rw-r--r--include/linux/bottom_half.h1
-rw-r--r--include/linux/bpf.h36
-rw-r--r--include/linux/brcmphy.h7
-rw-r--r--include/linux/cacheinfo.h2
-rw-r--r--include/linux/cgroup-defs.h501
-rw-r--r--include/linux/cgroup.h994
-rw-r--r--include/linux/clk.h27
-rw-r--r--include/linux/clkdev.h6
-rw-r--r--include/linux/clockchips.h37
-rw-r--r--include/linux/clocksource.h1
-rw-r--r--include/linux/compiler-gcc.h207
-rw-r--r--include/linux/compiler-gcc3.h23
-rw-r--r--include/linux/compiler-gcc4.h91
-rw-r--r--include/linux/compiler-gcc5.h67
-rw-r--r--include/linux/compiler-intel.h2
-rw-r--r--include/linux/compiler.h20
-rw-r--r--include/linux/configfs.h1
-rw-r--r--include/linux/console.h1
-rw-r--r--include/linux/console_struct.h1
-rw-r--r--include/linux/context_tracking.h10
-rw-r--r--include/linux/context_tracking_state.h1
-rw-r--r--include/linux/cpu_cooling.h39
-rw-r--r--include/linux/cpufreq.h5
-rw-r--r--include/linux/cpuidle.h20
-rw-r--r--include/linux/crc-itu-t.h2
-rw-r--r--include/linux/crypto.h501
-rw-r--r--include/linux/debugfs.h1
-rw-r--r--include/linux/device.h31
-rw-r--r--include/linux/dma-buf.h10
-rw-r--r--include/linux/dmapool.h2
-rw-r--r--include/linux/dmar.h85
-rw-r--r--include/linux/dmi.h4
-rw-r--r--include/linux/efi.h15
-rw-r--r--include/linux/elevator.h2
-rw-r--r--include/linux/etherdevice.h42
-rw-r--r--include/linux/extcon.h134
-rw-r--r--include/linux/extcon/extcon-adc-jack.h5
-rw-r--r--include/linux/f2fs_fs.h8
-rw-r--r--include/linux/filter.h30
-rw-r--r--include/linux/frontswap.h14
-rw-r--r--include/linux/fs.h45
-rw-r--r--include/linux/fsl_devices.h1
-rw-r--r--include/linux/fsnotify_backend.h2
-rw-r--r--include/linux/gfp.h5
-rw-r--r--include/linux/goldfish.h19
-rw-r--r--include/linux/gpio.h7
-rw-r--r--include/linux/gpio/consumer.h43
-rw-r--r--include/linux/gpio/driver.h13
-rw-r--r--include/linux/hardirq.h2
-rw-r--r--include/linux/hid.h2
-rw-r--r--include/linux/highmem.h2
-rw-r--r--include/linux/hrtimer.h167
-rw-r--r--include/linux/htirq.h22
-rw-r--r--include/linux/hyperv.h48
-rw-r--r--include/linux/i2c/twl.h1
-rw-r--r--include/linux/ide.h27
-rw-r--r--include/linux/ieee802154.h16
-rw-r--r--include/linux/if_link.h9
-rw-r--r--include/linux/if_macvlan.h2
-rw-r--r--include/linux/if_pppox.h2
-rw-r--r--include/linux/if_vlan.h28
-rw-r--r--include/linux/igmp.h1
-rw-r--r--include/linux/iio/buffer.h3
-rw-r--r--include/linux/iio/iio.h3
-rw-r--r--include/linux/iio/types.h2
-rw-r--r--include/linux/inet_diag.h1
-rw-r--r--include/linux/inetdevice.h3
-rw-r--r--include/linux/init_task.h13
-rw-r--r--include/linux/intel-iommu.h10
-rw-r--r--include/linux/interrupt.h9
-rw-r--r--include/linux/io-mapping.h2
-rw-r--r--include/linux/io.h8
-rw-r--r--include/linux/iommu.h44
-rw-r--r--include/linux/irq.h88
-rw-r--r--include/linux/irqchip/irq-sa11x0.h17
-rw-r--r--include/linux/irqdesc.h12
-rw-r--r--include/linux/irqdomain.h8
-rw-r--r--include/linux/jbd2.h4
-rw-r--r--include/linux/jiffies.h130
-rw-r--r--include/linux/kernel.h9
-rw-r--r--include/linux/kernfs.h5
-rw-r--r--include/linux/kmemleak.h6
-rw-r--r--include/linux/kvm_host.h96
-rw-r--r--include/linux/kvm_types.h1
-rw-r--r--include/linux/lglock.h5
-rw-r--r--include/linux/libata.h3
-rw-r--r--include/linux/livepatch.h8
-rw-r--r--include/linux/lockdep.h14
-rw-r--r--include/linux/mailbox_client.h2
-rw-r--r--include/linux/mailbox_controller.h2
-rw-r--r--include/linux/mbus.h5
-rw-r--r--include/linux/mdio-gpio.h3
-rw-r--r--include/linux/mei_cl_bus.h38
-rw-r--r--include/linux/memblock.h49
-rw-r--r--include/linux/memcontrol.h29
-rw-r--r--include/linux/mfd/arizona/core.h9
-rw-r--r--include/linux/mfd/arizona/pdata.h8
-rw-r--r--include/linux/mfd/arizona/registers.h27
-rw-r--r--include/linux/mfd/axp20x.h98
-rw-r--r--include/linux/mfd/cros_ec.h86
-rw-r--r--include/linux/mfd/cros_ec_commands.h277
-rw-r--r--include/linux/mfd/da9055/core.h2
-rw-r--r--include/linux/mfd/da9063/pdata.h1
-rw-r--r--include/linux/mfd/max77686.h5
-rw-r--r--include/linux/mfd/stmpe.h44
-rw-r--r--include/linux/mfd/syscon/atmel-mc.h144
-rw-r--r--include/linux/mlx4/cmd.h6
-rw-r--r--include/linux/mlx4/device.h30
-rw-r--r--include/linux/mlx5/cq.h3
-rw-r--r--include/linux/mlx5/device.h215
-rw-r--r--include/linux/mlx5/driver.h173
-rw-r--r--include/linux/mlx5/flow_table.h54
-rw-r--r--include/linux/mlx5/mlx5_ifc.h6584
-rw-r--r--include/linux/mlx5/qp.h25
-rw-r--r--include/linux/mlx5/vport.h55
-rw-r--r--include/linux/mm-arch-hooks.h25
-rw-r--r--include/linux/mm.h45
-rw-r--r--include/linux/mm_types.h18
-rw-r--r--include/linux/mmc/card.h2
-rw-r--r--include/linux/mmc/core.h1
-rw-r--r--include/linux/mmc/dw_mmc.h6
-rw-r--r--include/linux/mmc/host.h28
-rw-r--r--include/linux/mmc/mmc.h4
-rw-r--r--include/linux/mmc/sdhci-pci-data.h2
-rw-r--r--include/linux/mmu_notifier.h12
-rw-r--r--include/linux/mod_devicetable.h19
-rw-r--r--include/linux/module.h27
-rw-r--r--include/linux/moduleparam.h12
-rw-r--r--include/linux/mpi.h15
-rw-r--r--include/linux/mtd/cfi.h188
-rw-r--r--include/linux/mtd/nand.h6
-rw-r--r--include/linux/namei.h41
-rw-r--r--include/linux/net.h3
-rw-r--r--include/linux/netdev_features.h5
-rw-r--r--include/linux/netdevice.h31
-rw-r--r--include/linux/netfilter.h45
-rw-r--r--include/linux/netfilter/ipset/ip_set.h61
-rw-r--r--include/linux/netfilter/ipset/ip_set_comment.h38
-rw-r--r--include/linux/netfilter/ipset/ip_set_timeout.h27
-rw-r--r--include/linux/netfilter/x_tables.h60
-rw-r--r--include/linux/netfilter_bridge.h7
-rw-r--r--include/linux/netfilter_bridge/ebtables.h2
-rw-r--r--include/linux/netfilter_defs.h9
-rw-r--r--include/linux/netfilter_ingress.h41
-rw-r--r--include/linux/netfilter_ipv6.h3
-rw-r--r--include/linux/netlink.h2
-rw-r--r--include/linux/nmi.h3
-rw-r--r--include/linux/nvme.h31
-rw-r--r--include/linux/nx842.h11
-rw-r--r--include/linux/of_fdt.h2
-rw-r--r--include/linux/of_graph.h8
-rw-r--r--include/linux/oom.h12
-rw-r--r--include/linux/osq_lock.h5
-rw-r--r--include/linux/pagemap.h3
-rw-r--r--include/linux/parport.h43
-rw-r--r--include/linux/pci.h44
-rw-r--r--include/linux/pci_ids.h3
-rw-r--r--include/linux/perf_event.h53
-rw-r--r--include/linux/phy.h14
-rw-r--r--include/linux/phy/phy-sun4i-usb.h26
-rw-r--r--include/linux/phy/phy.h9
-rw-r--r--include/linux/pinctrl/consumer.h2
-rw-r--r--include/linux/pinctrl/pinctrl.h2
-rw-r--r--include/linux/pinctrl/pinmux.h6
-rw-r--r--include/linux/platform_data/gpio-omap.h12
-rw-r--r--include/linux/platform_data/keyboard-spear.h2
-rw-r--r--include/linux/platform_data/nfcmrvl.h40
-rw-r--r--include/linux/platform_data/ntc_thermistor.h1
-rw-r--r--include/linux/platform_data/st-nci.h (renamed from include/linux/platform_data/st21nfcb.h)14
-rw-r--r--include/linux/platform_data/st_nci.h29
-rw-r--r--include/linux/platform_data/usb-rcar-gen2-phy.h22
-rw-r--r--include/linux/platform_data/video-msm_fb.h146
-rw-r--r--include/linux/pm.h14
-rw-r--r--include/linux/pm_clock.h10
-rw-r--r--include/linux/pm_wakeirq.h51
-rw-r--r--include/linux/pm_wakeup.h9
-rw-r--r--include/linux/power/max17042_battery.h4
-rw-r--r--include/linux/power_supply.h11
-rw-r--r--include/linux/preempt.h159
-rw-r--r--include/linux/preempt_mask.h117
-rw-r--r--include/linux/printk.h2
-rw-r--r--include/linux/property.h2
-rw-r--r--include/linux/pwm.h12
-rw-r--r--include/linux/pxa2xx_ssp.h3
-rw-r--r--include/linux/qcom_scm.h13
-rw-r--r--include/linux/random.h9
-rw-r--r--include/linux/rculist.h10
-rw-r--r--include/linux/rcupdate.h76
-rw-r--r--include/linux/rcutiny.h16
-rw-r--r--include/linux/rcutree.h9
-rw-r--r--include/linux/regmap.h14
-rw-r--r--include/linux/regulator/driver.h11
-rw-r--r--include/linux/regulator/machine.h9
-rw-r--r--include/linux/regulator/max8973-regulator.h4
-rw-r--r--include/linux/reset/bcm63xx_pmb.h88
-rw-r--r--include/linux/rio.h2
-rw-r--r--include/linux/rtc.h20
-rw-r--r--include/linux/rtnetlink.h16
-rw-r--r--include/linux/scatterlist.h40
-rw-r--r--include/linux/sched.h225
-rw-r--r--include/linux/sched/sysctl.h12
-rw-r--r--include/linux/scif.h993
-rw-r--r--include/linux/security.h13
-rw-r--r--include/linux/seqlock.h47
-rw-r--r--include/linux/serial_8250.h3
-rw-r--r--include/linux/serial_core.h2
-rw-r--r--include/linux/serial_sci.h86
-rw-r--r--include/linux/skbuff.h77
-rw-r--r--include/linux/slab.h26
-rw-r--r--include/linux/smpboot.h5
-rw-r--r--include/linux/soc/sunxi/sunxi_sram.h19
-rw-r--r--include/linux/sock_diag.h42
-rw-r--r--include/linux/spi/cc2520.h1
-rw-r--r--include/linux/spinlock.h2
-rw-r--r--include/linux/stddef.h8
-rw-r--r--include/linux/stmmac.h1
-rw-r--r--include/linux/string.h1
-rw-r--r--include/linux/sunrpc/svc_rdma.h11
-rw-r--r--include/linux/sw842.h12
-rw-r--r--include/linux/swap.h1
-rw-r--r--include/linux/syscalls.h18
-rw-r--r--include/linux/syslog.h6
-rw-r--r--include/linux/tcp.h15
-rw-r--r--include/linux/thermal.h97
-rw-r--r--include/linux/tick.h19
-rw-r--r--include/linux/time64.h2
-rw-r--r--include/linux/timekeeper_internal.h19
-rw-r--r--include/linux/timekeeping.h2
-rw-r--r--include/linux/timer.h63
-rw-r--r--include/linux/timerqueue.h8
-rw-r--r--include/linux/topology.h6
-rw-r--r--include/linux/trace_events.h (renamed from include/linux/ftrace_event.h)177
-rw-r--r--include/linux/tty.h2
-rw-r--r--include/linux/types.h12
-rw-r--r--include/linux/u64_stats_sync.h7
-rw-r--r--include/linux/uaccess.h48
-rw-r--r--include/linux/ulpi/driver.h60
-rw-r--r--include/linux/ulpi/interface.h23
-rw-r--r--include/linux/ulpi/regs.h130
-rw-r--r--include/linux/usb/hcd.h2
-rw-r--r--include/linux/usb/msm_hsusb.h22
-rw-r--r--include/linux/usb/msm_hsusb_hw.h9
-rw-r--r--include/linux/usb/net2280.h3
-rw-r--r--include/linux/usb/phy.h8
-rw-r--r--include/linux/usb/renesas_usbhs.h3
-rw-r--r--include/linux/usb/ulpi.h134
-rw-r--r--include/linux/usb/usb338x.h4
-rw-r--r--include/linux/vme.h2
-rw-r--r--include/linux/wait.h17
-rw-r--r--include/linux/workqueue.h31
-rw-r--r--include/linux/writeback.h221
-rw-r--r--include/linux/zpool.h5
-rw-r--r--include/media/adp1653.h8
-rw-r--r--include/media/adv7511.h7
-rw-r--r--include/media/adv7604.h1
-rw-r--r--include/media/adv7842.h142
-rw-r--r--include/media/rc-core.h9
-rw-r--r--include/media/rc-map.h4
-rw-r--r--include/media/v4l2-dv-timings.h6
-rw-r--r--include/media/v4l2-mediabus.h2
-rw-r--r--include/media/v4l2-mem2mem.h4
-rw-r--r--include/media/v4l2-of.h20
-rw-r--r--include/media/v4l2-subdev.h18
-rw-r--r--include/media/videobuf2-core.h13
-rw-r--r--include/misc/cxl-base.h48
-rw-r--r--include/misc/cxl.h207
-rw-r--r--include/net/addrconf.h1
-rw-r--r--include/net/af_unix.h1
-rw-r--r--include/net/af_vsock.h2
-rw-r--r--include/net/bluetooth/bluetooth.h11
-rw-r--r--include/net/bluetooth/hci.h10
-rw-r--r--include/net/bluetooth/hci_core.h47
-rw-r--r--include/net/bond_options.h3
-rw-r--r--include/net/bonding.h3
-rw-r--r--include/net/cfg80211.h8
-rw-r--r--include/net/cfg802154.h70
-rw-r--r--include/net/checksum.h4
-rw-r--r--include/net/codel.h12
-rw-r--r--include/net/dst.h18
-rw-r--r--include/net/fib_rules.h3
-rw-r--r--include/net/flow_dissector.h220
-rw-r--r--include/net/flow_keys.h45
-rw-r--r--include/net/geneve.h5
-rw-r--r--include/net/ieee802154_netdev.h34
-rw-r--r--include/net/inet_common.h2
-rw-r--r--include/net/inet_frag.h2
-rw-r--r--include/net/inet_hashtables.h49
-rw-r--r--include/net/inet_sock.h1
-rw-r--r--include/net/ip.h43
-rw-r--r--include/net/ip6_fib.h45
-rw-r--r--include/net/ip6_route.h21
-rw-r--r--include/net/ip_fib.h20
-rw-r--r--include/net/ipv6.h43
-rw-r--r--include/net/llc_conn.h2
-rw-r--r--include/net/mac80211.h265
-rw-r--r--include/net/mac802154.h160
-rw-r--r--include/net/net_namespace.h5
-rw-r--r--include/net/netfilter/br_netfilter.h60
-rw-r--r--include/net/netfilter/nf_queue.h2
-rw-r--r--include/net/netfilter/nf_tables.h15
-rw-r--r--include/net/netns/ipv4.h3
-rw-r--r--include/net/netns/ipv6.h1
-rw-r--r--include/net/netns/netfilter.h4
-rw-r--r--include/net/netns/nftables.h1
-rw-r--r--include/net/netns/sctp.h1
-rw-r--r--include/net/netns/x_tables.h2
-rw-r--r--include/net/nfc/hci.h7
-rw-r--r--include/net/nfc/nci.h1
-rw-r--r--include/net/nfc/nci_core.h71
-rw-r--r--include/net/nfc/nfc.h22
-rw-r--r--include/net/nl802154.h85
-rw-r--r--include/net/request_sock.h4
-rw-r--r--include/net/sch_generic.h23
-rw-r--r--include/net/sctp/structs.h4
-rw-r--r--include/net/sock.h32
-rw-r--r--include/net/switchdev.h257
-rw-r--r--include/net/tcp.h95
-rw-r--r--include/net/xfrm.h3
-rw-r--r--include/ras/ras_event.h85
-rw-r--r--include/rdma/ib_addr.h6
-rw-r--r--include/rdma/ib_cache.h8
-rw-r--r--include/rdma/ib_mad.h41
-rw-r--r--include/rdma/ib_verbs.h394
-rw-r--r--include/rdma/iw_cm.h1
-rw-r--r--include/rdma/opa_smi.h106
-rw-r--r--include/rdma/rdma_cm.h2
-rw-r--r--include/scsi/scsi.h291
-rw-r--r--include/scsi/scsi_common.h64
-rw-r--r--include/scsi/scsi_device.h2
-rw-r--r--include/scsi/scsi_eh.h31
-rw-r--r--include/scsi/scsi_proto.h281
-rw-r--r--include/scsi/srp.h7
-rw-r--r--include/soc/at91/at91rm9200_sdramc.h63
-rw-r--r--include/soc/imx/revision.h37
-rw-r--r--include/soc/imx/timer.h26
-rw-r--r--include/soc/sa1100/pwer.h15
-rw-r--r--include/soc/tegra/emc.h19
-rw-r--r--include/soc/tegra/fuse.h1
-rw-r--r--include/soc/tegra/mc.h20
-rw-r--r--include/soc/tegra/pmc.h2
-rw-r--r--include/sound/control.h2
-rw-r--r--include/sound/core.h4
-rw-r--r--include/sound/dmaengine_pcm.h5
-rw-r--r--include/sound/emux_synth.h2
-rw-r--r--include/sound/hda_i915.h36
-rw-r--r--include/sound/hda_register.h244
-rw-r--r--include/sound/hdaudio.h309
-rw-r--r--include/sound/hdaudio_ext.h132
-rw-r--r--include/sound/info.h37
-rw-r--r--include/sound/jack.h13
-rw-r--r--include/sound/pcm.h5
-rw-r--r--include/sound/pcm_drm_eld.h6
-rw-r--r--include/sound/pcm_iec958.h9
-rw-r--r--include/sound/rt5645.h6
-rw-r--r--include/sound/soc-dapm.h49
-rw-r--r--include/sound/soc-topology.h168
-rw-r--r--include/sound/soc.h118
-rw-r--r--include/sound/tlv.h15
-rw-r--r--include/target/iscsi/iscsi_target_core.h1
-rw-r--r--include/target/target_core_base.h15
-rw-r--r--include/trace/define_trace.h3
-rw-r--r--include/trace/events/ext4.h35
-rw-r--r--include/trace/events/f2fs.h33
-rw-r--r--include/trace/events/power.h27
-rw-r--r--include/trace/events/sched.h3
-rw-r--r--include/trace/events/target.h2
-rw-r--r--include/trace/events/thermal.h58
-rw-r--r--include/trace/events/thermal_power_allocator.h87
-rw-r--r--include/trace/events/timer.h12
-rw-r--r--include/trace/events/v4l2.h3
-rw-r--r--include/trace/events/writeback.h15
-rw-r--r--include/trace/perf.h350
-rw-r--r--include/trace/syscall.h6
-rw-r--r--include/trace/trace_events.h (renamed from include/trace/ftrace.h)413
-rw-r--r--include/uapi/drm/amdgpu_drm.h631
-rw-r--r--include/uapi/drm/drm.h2
-rw-r--r--include/uapi/drm/drm_fourcc.h15
-rw-r--r--include/uapi/drm/drm_mode.h20
-rw-r--r--include/uapi/drm/i915_drm.h9
-rw-r--r--include/uapi/drm/msm_drm.h76
-rw-r--r--include/uapi/drm/radeon_drm.h2
-rw-r--r--include/uapi/linux/Kbuild3
-rw-r--r--include/uapi/linux/bpf.h43
-rw-r--r--include/uapi/linux/can.h6
-rw-r--r--include/uapi/linux/can/gw.h5
-rw-r--r--include/uapi/linux/cryptouser.h (renamed from include/linux/cryptouser.h)6
-rw-r--r--include/uapi/linux/dcbnl.h10
-rw-r--r--include/uapi/linux/dm-ioctl.h4
-rw-r--r--include/uapi/linux/dvb/dmx.h10
-rw-r--r--include/uapi/linux/dvb/frontend.h223
-rw-r--r--include/uapi/linux/elf-em.h1
-rw-r--r--include/uapi/linux/ethtool.h37
-rw-r--r--include/uapi/linux/gsmmux.h (renamed from include/linux/gsmmux.h)3
-rw-r--r--include/uapi/linux/hsi/cs-protocol.h16
-rw-r--r--include/uapi/linux/hyperv.h8
-rw-r--r--include/uapi/linux/i2c.h1
-rw-r--r--include/uapi/linux/if_link.h29
-rw-r--r--include/uapi/linux/if_packet.h7
-rw-r--r--include/uapi/linux/iio/types.h2
-rw-r--r--include/uapi/linux/in.h3
-rw-r--r--include/uapi/linux/inet_diag.h4
-rw-r--r--include/uapi/linux/ip.h1
-rw-r--r--include/uapi/linux/ipv6_route.h1
-rw-r--r--include/uapi/linux/kfd_ioctl.h135
-rw-r--r--include/uapi/linux/kvm.h9
-rw-r--r--include/uapi/linux/mic_common.h12
-rw-r--r--include/uapi/linux/nbd.h2
-rw-r--r--include/uapi/linux/netfilter.h9
-rw-r--r--include/uapi/linux/netfilter/ipset/ip_set.h6
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h2
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_queue.h4
-rw-r--r--include/uapi/linux/netfilter/xt_socket.h8
-rw-r--r--include/uapi/linux/netfilter_bridge/ebtables.h2
-rw-r--r--include/uapi/linux/netlink.h16
-rw-r--r--include/uapi/linux/nfc.h10
-rw-r--r--include/uapi/linux/nfs4.h7
-rw-r--r--include/uapi/linux/nl80211.h28
-rw-r--r--include/uapi/linux/nvme.h5
-rw-r--r--include/uapi/linux/openvswitch.h4
-rw-r--r--include/uapi/linux/perf_event.h18
-rw-r--r--include/uapi/linux/pkt_cls.h57
-rw-r--r--include/uapi/linux/pkt_sched.h7
-rw-r--r--include/uapi/linux/rds.h10
-rw-r--r--include/uapi/linux/rtnetlink.h3
-rw-r--r--include/uapi/linux/scif_ioctl.h130
-rw-r--r--include/uapi/linux/serial_core.h3
-rw-r--r--include/uapi/linux/serial_reg.h3
-rw-r--r--include/uapi/linux/snmp.h2
-rw-r--r--include/uapi/linux/sock_diag.h10
-rw-r--r--include/uapi/linux/tcp.h6
-rw-r--r--include/uapi/linux/tty.h1
-rw-r--r--include/uapi/linux/tty_flags.h2
-rw-r--r--include/uapi/linux/v4l2-mediabus.h4
-rw-r--r--include/uapi/linux/vfio.h102
-rw-r--r--include/uapi/linux/videodev2.h83
-rw-r--r--include/uapi/linux/virtio_gpu.h206
-rw-r--r--include/uapi/linux/virtio_ids.h1
-rw-r--r--include/uapi/misc/cxl.h22
-rw-r--r--include/uapi/rdma/ib_user_verbs.h19
-rw-r--r--include/uapi/sound/asoc.h388
-rw-r--r--include/uapi/sound/tlv.h31
-rw-r--r--include/video/exynos5433_decon.h165
-rw-r--r--include/video/neomagic.h5
-rw-r--r--include/video/tdfx.h2
-rw-r--r--init/Kconfig81
-rw-r--r--init/do_mounts.c9
-rw-r--r--init/main.c26
-rw-r--r--ipc/mqueue.c54
-rw-r--r--kernel/Kconfig.locks13
-rw-r--r--kernel/bpf/arraymap.c113
-rw-r--r--kernel/bpf/core.c105
-rw-r--r--kernel/bpf/helpers.c105
-rw-r--r--kernel/bpf/syscall.c42
-rw-r--r--kernel/bpf/verifier.c54
-rw-r--r--kernel/cgroup.c273
-rw-r--r--kernel/context_tracking.c67
-rw-r--r--kernel/cpu.c4
-rw-r--r--kernel/events/core.c180
-rw-r--r--kernel/events/internal.h9
-rw-r--r--kernel/events/ring_buffer.c2
-rw-r--r--kernel/exit.c4
-rw-r--r--kernel/fork.c60
-rw-r--r--kernel/futex.c72
-rw-r--r--kernel/irq/chip.c87
-rw-r--r--kernel/irq/devres.c4
-rw-r--r--kernel/irq/dummychip.c1
-rw-r--r--kernel/irq/generic-chip.c5
-rw-r--r--kernel/irq/internals.h17
-rw-r--r--kernel/irq/irqdesc.c13
-rw-r--r--kernel/irq/irqdomain.c25
-rw-r--r--kernel/irq/manage.c33
-rw-r--r--kernel/irq/migration.c15
-rw-r--r--kernel/irq/msi.c2
-rw-r--r--kernel/irq/pm.c4
-rw-r--r--kernel/irq/proc.c2
-rw-r--r--kernel/livepatch/core.c96
-rw-r--r--kernel/locking/Makefile3
-rw-r--r--kernel/locking/lglock.c22
-rw-r--r--kernel/locking/lockdep.c180
-rw-r--r--kernel/locking/locktorture.c14
-rw-r--r--kernel/locking/mcs_spinlock.h1
-rw-r--r--kernel/locking/qrwlock.c30
-rw-r--r--kernel/locking/qspinlock.c473
-rw-r--r--kernel/locking/qspinlock_paravirt.h325
-rw-r--r--kernel/locking/rtmutex.c105
-rw-r--r--kernel/locking/rtmutex_common.h3
-rw-r--r--kernel/locking/rwsem-xadd.c44
-rw-r--r--kernel/module.c20
-rw-r--r--kernel/params.c11
-rw-r--r--kernel/power/Makefile3
-rw-r--r--kernel/power/block_io.c103
-rw-r--r--kernel/power/main.c2
-rw-r--r--kernel/power/power.h9
-rw-r--r--kernel/power/suspend.c8
-rw-r--r--kernel/power/swap.c159
-rw-r--r--kernel/printk/printk.c235
-rw-r--r--kernel/rcu/rcutorture.c103
-rw-r--r--kernel/rcu/srcu.c10
-rw-r--r--kernel/rcu/tiny.c40
-rw-r--r--kernel/rcu/tiny_plugin.h12
-rw-r--r--kernel/rcu/tree.c367
-rw-r--r--kernel/rcu/tree.h35
-rw-r--r--kernel/rcu/tree_plugin.h232
-rw-r--r--kernel/rcu/tree_trace.c6
-rw-r--r--kernel/rcu/update.c30
-rw-r--r--kernel/sched/Makefile2
-rw-r--r--kernel/sched/auto_group.c6
-rw-r--r--kernel/sched/auto_group.h2
-rw-r--r--kernel/sched/core.c726
-rw-r--r--kernel/sched/cputime.c2
-rw-r--r--kernel/sched/deadline.c299
-rw-r--r--kernel/sched/debug.c13
-rw-r--r--kernel/sched/fair.c459
-rw-r--r--kernel/sched/idle.c114
-rw-r--r--kernel/sched/loadavg.c (renamed from kernel/sched/proc.c)236
-rw-r--r--kernel/sched/rt.c108
-rw-r--r--kernel/sched/sched.h47
-rw-r--r--kernel/sched/stats.h15
-rw-r--r--kernel/sched/wait.c8
-rw-r--r--kernel/seccomp.c70
-rw-r--r--kernel/signal.c6
-rw-r--r--kernel/smpboot.c60
-rw-r--r--kernel/stop_machine.c42
-rw-r--r--kernel/sys.c166
-rw-r--r--kernel/sysctl.c25
-rw-r--r--kernel/time/Makefile17
-rw-r--r--kernel/time/alarmtimer.c17
-rw-r--r--kernel/time/clockevents.c67
-rw-r--r--kernel/time/clocksource.c24
-rw-r--r--kernel/time/hrtimer.c699
-rw-r--r--kernel/time/ntp.c61
-rw-r--r--kernel/time/ntp_internal.h1
-rw-r--r--kernel/time/posix-cpu-timers.c87
-rw-r--r--kernel/time/posix-timers.c17
-rw-r--r--kernel/time/tick-broadcast-hrtimer.c18
-rw-r--r--kernel/time/tick-broadcast.c97
-rw-r--r--kernel/time/tick-common.c35
-rw-r--r--kernel/time/tick-internal.h31
-rw-r--r--kernel/time/tick-oneshot.c22
-rw-r--r--kernel/time/tick-sched.c320
-rw-r--r--kernel/time/tick-sched.h2
-rw-r--r--kernel/time/time.c78
-rw-r--r--kernel/time/timeconst.bc3
-rw-r--r--kernel/time/timekeeping.c153
-rw-r--r--kernel/time/timekeeping.h11
-rw-r--r--kernel/time/timer.c362
-rw-r--r--kernel/time/timer_list.c51
-rw-r--r--kernel/time/timer_stats.c10
-rw-r--r--kernel/torture.c26
-rw-r--r--kernel/trace/blktrace.c10
-rw-r--r--kernel/trace/bpf_trace.c42
-rw-r--r--kernel/trace/ring_buffer.c221
-rw-r--r--kernel/trace/ring_buffer_benchmark.c23
-rw-r--r--kernel/trace/trace.c23
-rw-r--r--kernel/trace/trace.h44
-rw-r--r--kernel/trace/trace_branch.c4
-rw-r--r--kernel/trace/trace_clock.c3
-rw-r--r--kernel/trace/trace_event_perf.c20
-rw-r--r--kernel/trace/trace_events.c304
-rw-r--r--kernel/trace/trace_events_filter.c110
-rw-r--r--kernel/trace/trace_events_trigger.c70
-rw-r--r--kernel/trace/trace_export.c10
-rw-r--r--kernel/trace/trace_functions_graph.c8
-rw-r--r--kernel/trace/trace_kprobe.c70
-rw-r--r--kernel/trace/trace_mmiotrace.c4
-rw-r--r--kernel/trace/trace_output.c78
-rw-r--r--kernel/trace/trace_output.h2
-rw-r--r--kernel/trace/trace_probe.h8
-rw-r--r--kernel/trace/trace_sched_wakeup.c4
-rw-r--r--kernel/trace/trace_syscalls.c72
-rw-r--r--kernel/trace/trace_uprobe.c46
-rw-r--r--kernel/watchdog.c67
-rw-r--r--kernel/workqueue.c484
-rw-r--r--lib/842/842.h127
-rw-r--r--lib/842/842_compress.c626
-rw-r--r--lib/842/842_debugfs.h52
-rw-r--r--lib/842/842_decompress.c405
-rw-r--r--lib/842/Makefile2
-rw-r--r--lib/Kconfig6
-rw-r--r--lib/Kconfig.debug66
-rw-r--r--lib/Makefile2
-rw-r--r--lib/bitmap.c32
-rw-r--r--lib/cpu_rmap.c2
-rw-r--r--lib/cpumask.c9
-rw-r--r--lib/crc-itu-t.c2
-rw-r--r--lib/dynamic_debug.c4
-rw-r--r--lib/kobject.c13
-rw-r--r--lib/lz4/lz4_decompress.c12
-rw-r--r--lib/mpi/mpicoder.c87
-rw-r--r--lib/mpi/mpiutil.c6
-rw-r--r--lib/radix-tree.c30
-rw-r--r--lib/raid6/Makefile2
-rw-r--r--lib/raid6/x86.h2
-rw-r--r--lib/rhashtable.c8
-rw-r--r--lib/scatterlist.c32
-rw-r--r--lib/sort.c23
-rw-r--r--lib/string.c17
-rw-r--r--lib/strnlen_user.c6
-rw-r--r--lib/swiotlb.c13
-rw-r--r--lib/test-hexdump.c6
-rw-r--r--lib/test_bpf.c2664
-rw-r--r--lib/test_rhashtable.c215
-rw-r--r--lib/timerqueue.c10
-rw-r--r--mm/Kconfig1
-rw-r--r--mm/backing-dev.c634
-rw-r--r--mm/cma.c10
-rw-r--r--mm/debug.c2
-rw-r--r--mm/fadvise.c2
-rw-r--r--mm/filemap.c57
-rw-r--r--mm/frontswap.c215
-rw-r--r--mm/huge_memory.c22
-rw-r--r--mm/hugetlb.c197
-rw-r--r--mm/hwpoison-inject.c4
-rw-r--r--mm/kasan/kasan.h1
-rw-r--r--mm/kmemleak.c168
-rw-r--r--mm/madvise.c1
-rw-r--r--mm/memblock.c123
-rw-r--r--mm/memcontrol.c282
-rw-r--r--mm/memory-failure.c351
-rw-r--r--mm/memory.c28
-rw-r--r--mm/memory_hotplug.c1
-rw-r--r--mm/mempolicy.c38
-rw-r--r--mm/memtest.c3
-rw-r--r--mm/migrate.c11
-rw-r--r--mm/mmap.c6
-rw-r--r--mm/mprotect.c11
-rw-r--r--mm/mremap.c17
-rw-r--r--mm/nobootmem.c14
-rw-r--r--mm/nommu.c112
-rw-r--r--mm/oom_kill.c158
-rw-r--r--mm/page-writeback.c1231
-rw-r--r--mm/page_alloc.c275
-rw-r--r--mm/page_io.c2
-rw-r--r--mm/percpu.c2
-rw-r--r--mm/pgtable-generic.c29
-rw-r--r--mm/readahead.c2
-rw-r--r--mm/rmap.c11
-rw-r--r--mm/shmem.c42
-rw-r--r--mm/slab.c1
-rw-r--r--mm/slab.h1
-rw-r--r--mm/slab_common.c98
-rw-r--r--mm/slub.c1
-rw-r--r--mm/swap.c1
-rw-r--r--mm/truncate.c18
-rw-r--r--mm/vmscan.c94
-rw-r--r--mm/zbud.c23
-rw-r--r--mm/zpool.c35
-rw-r--r--mm/zsmalloc.c7
-rw-r--r--mm/zswap.c12
-rw-r--r--net/8021q/vlan.c96
-rw-r--r--net/9p/trans_rdma.c4
-rw-r--r--net/Kconfig3
-rw-r--r--net/appletalk/ddp.c2
-rw-r--r--net/atm/common.c4
-rw-r--r--net/atm/common.h2
-rw-r--r--net/atm/pvc.c2
-rw-r--r--net/atm/svc.c2
-rw-r--r--net/ax25/af_ax25.c5
-rw-r--r--net/ax25/ax25_in.c1
-rw-r--r--net/ax25/ax25_ip.c1
-rw-r--r--net/ax25/ax25_out.c1
-rw-r--r--net/ax25/ax25_uid.c1
-rw-r--r--net/batman-adv/Makefile6
-rw-r--r--net/batman-adv/bat_algo.h2
-rw-r--r--net/batman-adv/bat_iv_ogm.c210
-rw-r--r--net/batman-adv/bitarray.c6
-rw-r--r--net/batman-adv/bitarray.h8
-rw-r--r--net/batman-adv/bridge_loop_avoidance.c56
-rw-r--r--net/batman-adv/bridge_loop_avoidance.h12
-rw-r--r--net/batman-adv/debugfs.c47
-rw-r--r--net/batman-adv/debugfs.h43
-rw-r--r--net/batman-adv/distributed-arp-table.c47
-rw-r--r--net/batman-adv/distributed-arp-table.h15
-rw-r--r--net/batman-adv/fragmentation.c44
-rw-r--r--net/batman-adv/fragmentation.h11
-rw-r--r--net/batman-adv/gateway_client.c41
-rw-r--r--net/batman-adv/gateway_client.h10
-rw-r--r--net/batman-adv/gateway_common.c13
-rw-r--r--net/batman-adv/gateway_common.h9
-rw-r--r--net/batman-adv/hard-interface.c40
-rw-r--r--net/batman-adv/hard-interface.h13
-rw-r--r--net/batman-adv/hash.c8
-rw-r--r--net/batman-adv/hash.h33
-rw-r--r--net/batman-adv/icmp_socket.c35
-rw-r--r--net/batman-adv/icmp_socket.h9
-rw-r--r--net/batman-adv/main.c103
-rw-r--r--net/batman-adv/main.h40
-rw-r--r--net/batman-adv/multicast.c31
-rw-r--r--net/batman-adv/multicast.h8
-rw-r--r--net/batman-adv/network-coding.c53
-rw-r--r--net/batman-adv/network-coding.h15
-rw-r--r--net/batman-adv/originator.c36
-rw-r--r--net/batman-adv/originator.h28
-rw-r--r--net/batman-adv/packet.h5
-rw-r--r--net/batman-adv/routing.c38
-rw-r--r--net/batman-adv/routing.h12
-rw-r--r--net/batman-adv/send.c40
-rw-r--r--net/batman-adv/send.h15
-rw-r--r--net/batman-adv/soft-interface.c72
-rw-r--r--net/batman-adv/soft-interface.h13
-rw-r--r--net/batman-adv/sysfs.c62
-rw-r--r--net/batman-adv/sysfs.h12
-rw-r--r--net/batman-adv/translation-table.c91
-rw-r--r--net/batman-adv/translation-table.h11
-rw-r--r--net/batman-adv/types.h33
-rw-r--r--net/bluetooth/6lowpan.c15
-rw-r--r--net/bluetooth/Makefile3
-rw-r--r--net/bluetooth/bnep/sock.c2
-rw-r--r--net/bluetooth/cmtp/sock.c2
-rw-r--r--net/bluetooth/hci_conn.c4
-rw-r--r--net/bluetooth/hci_core.c153
-rw-r--r--net/bluetooth/hci_event.c113
-rw-r--r--net/bluetooth/hci_sock.c32
-rw-r--r--net/bluetooth/hidp/sock.c2
-rw-r--r--net/bluetooth/l2cap_core.c13
-rw-r--r--net/bluetooth/l2cap_sock.c10
-rw-r--r--net/bluetooth/mgmt.c576
-rw-r--r--net/bluetooth/rfcomm/core.c2
-rw-r--r--net/bluetooth/rfcomm/sock.c28
-rw-r--r--net/bluetooth/sco.c13
-rw-r--r--net/bluetooth/smp.c158
-rw-r--r--net/bridge/Makefile2
-rw-r--r--net/bridge/br.c22
-rw-r--r--net/bridge/br_fdb.c38
-rw-r--r--net/bridge/br_if.c4
-rw-r--r--net/bridge/br_ioctl.c2
-rw-r--r--net/bridge/br_multicast.c266
-rw-r--r--net/bridge/br_netfilter_hooks.c (renamed from net/bridge/br_netfilter.c)312
-rw-r--r--net/bridge/br_netfilter_ipv6.c245
-rw-r--r--net/bridge/br_netlink.c24
-rw-r--r--net/bridge/br_private.h13
-rw-r--r--net/bridge/br_stp.c13
-rw-r--r--net/bridge/br_stp_if.c6
-rw-r--r--net/bridge/br_sysfs_if.c2
-rw-r--r--net/bridge/br_vlan.c60
-rw-r--r--net/bridge/netfilter/ebt_stp.c6
-rw-r--r--net/bridge/netfilter/ebtables.c4
-rw-r--r--net/caif/caif_socket.c2
-rw-r--r--net/can/af_can.c8
-rw-r--r--net/can/gw.c68
-rw-r--r--net/ceph/messenger.c4
-rw-r--r--net/core/dev.c220
-rw-r--r--net/core/ethtool.c13
-rw-r--r--net/core/filter.c261
-rw-r--r--net/core/flow_dissector.c656
-rw-r--r--net/core/neighbour.c16
-rw-r--r--net/core/net-sysfs.c10
-rw-r--r--net/core/net_namespace.c133
-rw-r--r--net/core/netevent.c5
-rw-r--r--net/core/pktgen.c112
-rw-r--r--net/core/rtnetlink.c81
-rw-r--r--net/core/secure_seq.c2
-rw-r--r--net/core/skbuff.c387
-rw-r--r--net/core/sock.c55
-rw-r--r--net/core/sock_diag.c85
-rw-r--r--net/core/stream.c6
-rw-r--r--net/core/utils.c12
-rw-r--r--net/dccp/diag.c1
-rw-r--r--net/decnet/af_decnet.c8
-rw-r--r--net/dsa/slave.c54
-rw-r--r--net/ethernet/eth.c15
-rw-r--r--net/ieee802154/6lowpan/core.c28
-rw-r--r--net/ieee802154/6lowpan/tx.c5
-rw-r--r--net/ieee802154/core.c2
-rw-r--r--net/ieee802154/nl-mac.c39
-rw-r--r--net/ieee802154/nl-phy.c10
-rw-r--r--net/ieee802154/nl802154.c316
-rw-r--r--net/ieee802154/rdev-ops.h23
-rw-r--r--net/ieee802154/socket.c28
-rw-r--r--net/ieee802154/trace.h38
-rw-r--r--net/ipv4/Kconfig24
-rw-r--r--net/ipv4/Makefile3
-rw-r--r--net/ipv4/af_inet.c13
-rw-r--r--net/ipv4/devinet.c2
-rw-r--r--net/ipv4/esp4.c201
-rw-r--r--net/ipv4/fib_frontend.c29
-rw-r--r--net/ipv4/fib_rules.c5
-rw-r--r--net/ipv4/fib_semantics.c97
-rw-r--r--net/ipv4/fib_trie.c75
-rw-r--r--net/ipv4/geneve_core.c (renamed from net/ipv4/geneve.c)10
-rw-r--r--net/ipv4/igmp.c162
-rw-r--r--net/ipv4/inet_connection_sock.c19
-rw-r--r--net/ipv4/inet_diag.c60
-rw-r--r--net/ipv4/inet_hashtables.c57
-rw-r--r--net/ipv4/inet_timewait_sock.c2
-rw-r--r--net/ipv4/ip_forward.c18
-rw-r--r--net/ipv4/ip_fragment.c46
-rw-r--r--net/ipv4/ip_output.c88
-rw-r--r--net/ipv4/ip_sockglue.c18
-rw-r--r--net/ipv4/ip_tunnel_core.c20
-rw-r--r--net/ipv4/ipip.c3
-rw-r--r--net/ipv4/netfilter/Kconfig3
-rw-r--r--net/ipv4/netfilter/arp_tables.c86
-rw-r--r--net/ipv4/netfilter/ip_tables.c99
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c5
-rw-r--r--net/ipv4/netfilter/ipt_SYNPROXY.c4
-rw-r--r--net/ipv4/netfilter/ipt_rpfilter.c2
-rw-r--r--net/ipv4/proc.c2
-rw-r--r--net/ipv4/route.c33
-rw-r--r--net/ipv4/syncookies.c10
-rw-r--r--net/ipv4/sysctl_net_ipv4.c25
-rw-r--r--net/ipv4/tcp.c100
-rw-r--r--net/ipv4/tcp_cdg.c433
-rw-r--r--net/ipv4/tcp_dctcp.c26
-rw-r--r--net/ipv4/tcp_diag.c6
-rw-r--r--net/ipv4/tcp_fastopen.c2
-rw-r--r--net/ipv4/tcp_input.c139
-rw-r--r--net/ipv4/tcp_ipv4.c15
-rw-r--r--net/ipv4/tcp_minisocks.c4
-rw-r--r--net/ipv4/tcp_offload.c4
-rw-r--r--net/ipv4/tcp_output.c106
-rw-r--r--net/ipv4/tcp_timer.c4
-rw-r--r--net/ipv4/udp_diag.c2
-rw-r--r--net/ipv4/udp_tunnel.c8
-rw-r--r--net/ipv6/Makefile1
-rw-r--r--net/ipv6/addrconf.c2
-rw-r--r--net/ipv6/af_inet6.c6
-rw-r--r--net/ipv6/datagram.c12
-rw-r--r--net/ipv6/esp6.c201
-rw-r--r--net/ipv6/icmp.c6
-rw-r--r--net/ipv6/inet6_hashtables.c8
-rw-r--r--net/ipv6/ip6_fib.c25
-rw-r--r--net/ipv6/ip6_flowlabel.c4
-rw-r--r--net/ipv6/ip6_output.c60
-rw-r--r--net/ipv6/ip6_tunnel.c2
-rw-r--r--net/ipv6/ip6_udp_tunnel.c6
-rw-r--r--net/ipv6/mcast_snoop.c213
-rw-r--r--net/ipv6/ndisc.c2
-rw-r--r--net/ipv6/netfilter.c2
-rw-r--r--net/ipv6/netfilter/Kconfig3
-rw-r--r--net/ipv6/netfilter/ip6_tables.c100
-rw-r--r--net/ipv6/output_core.c14
-rw-r--r--net/ipv6/raw.c11
-rw-r--r--net/ipv6/route.c561
-rw-r--r--net/ipv6/syncookies.c19
-rw-r--r--net/ipv6/sysctl_net_ipv6.c8
-rw-r--r--net/ipv6/tcp_ipv6.c16
-rw-r--r--net/ipv6/xfrm6_policy.c20
-rw-r--r--net/ipx/af_ipx.c2
-rw-r--r--net/irda/af_irda.c2
-rw-r--r--net/irda/timer.c4
-rw-r--r--net/iucv/af_iucv.c10
-rw-r--r--net/key/af_key.c3
-rw-r--r--net/l2tp/l2tp_core.c15
-rw-r--r--net/l2tp/l2tp_ppp.c4
-rw-r--r--net/llc/af_llc.c2
-rw-r--r--net/llc/llc_conn.c6
-rw-r--r--net/mac80211/Kconfig16
-rw-r--r--net/mac80211/aes_ccm.c33
-rw-r--r--net/mac80211/aes_gcm.c33
-rw-r--r--net/mac80211/aes_gmac.c14
-rw-r--r--net/mac80211/agg-tx.c4
-rw-r--r--net/mac80211/cfg.c214
-rw-r--r--net/mac80211/chan.c10
-rw-r--r--net/mac80211/debugfs.c177
-rw-r--r--net/mac80211/debugfs_key.c17
-rw-r--r--net/mac80211/debugfs_sta.c85
-rw-r--r--net/mac80211/driver-ops.h13
-rw-r--r--net/mac80211/ethtool.c3
-rw-r--r--net/mac80211/ibss.c6
-rw-r--r--net/mac80211/ieee80211_i.h36
-rw-r--r--net/mac80211/iface.c74
-rw-r--r--net/mac80211/key.c109
-rw-r--r--net/mac80211/key.h7
-rw-r--r--net/mac80211/led.c268
-rw-r--r--net/mac80211/led.h44
-rw-r--r--net/mac80211/main.c34
-rw-r--r--net/mac80211/mesh.c1
-rw-r--r--net/mac80211/mesh_hwmp.c35
-rw-r--r--net/mac80211/mesh_plink.c44
-rw-r--r--net/mac80211/mlme.c247
-rw-r--r--net/mac80211/offchannel.c2
-rw-r--r--net/mac80211/pm.c4
-rw-r--r--net/mac80211/rate.c14
-rw-r--r--net/mac80211/rate.h14
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c2
-rw-r--r--net/mac80211/rx.c227
-rw-r--r--net/mac80211/scan.c18
-rw-r--r--net/mac80211/sta_info.c24
-rw-r--r--net/mac80211/sta_info.h44
-rw-r--r--net/mac80211/status.c163
-rw-r--r--net/mac80211/tdls.c52
-rw-r--r--net/mac80211/trace.h42
-rw-r--r--net/mac80211/tx.c549
-rw-r--r--net/mac80211/util.c6
-rw-r--r--net/mac80211/wpa.c10
-rw-r--r--net/mac802154/Kconfig1
-rw-r--r--net/mac802154/Makefile4
-rw-r--r--net/mac802154/cfg.c101
-rw-r--r--net/mac802154/driver-ops.h96
-rw-r--r--net/mac802154/ieee802154_i.h9
-rw-r--r--net/mac802154/iface.c156
-rw-r--r--net/mac802154/llsec.c44
-rw-r--r--net/mac802154/mac_cmd.c42
-rw-r--r--net/mac802154/main.c32
-rw-r--r--net/mac802154/mib.c63
-rw-r--r--net/mac802154/rx.c13
-rw-r--r--net/mac802154/trace.c9
-rw-r--r--net/mac802154/trace.h272
-rw-r--r--net/mac802154/util.c5
-rw-r--r--net/mpls/mpls_gso.c2
-rw-r--r--net/netfilter/Kconfig31
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/core.c38
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_gen.h44
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ip.c44
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ipmac.c59
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_port.c27
-rw-r--r--net/netfilter/ipset/ip_set_core.c387
-rw-r--r--net/netfilter/ipset/ip_set_getport.c19
-rw-r--r--net/netfilter/ipset/ip_set_hash_gen.h736
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c72
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipmark.c87
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c98
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c91
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c96
-rw-r--r--net/netfilter/ipset/ip_set_hash_mac.c30
-rw-r--r--net/netfilter/ipset/ip_set_hash_net.c73
-rw-r--r--net/netfilter/ipset/ip_set_hash_netiface.c250
-rw-r--r--net/netfilter/ipset/ip_set_hash_netnet.c146
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c86
-rw-r--r--net/netfilter/ipset/ip_set_hash_netportnet.c176
-rw-r--r--net/netfilter/ipset/ip_set_list_set.c422
-rw-r--r--net/netfilter/ipset/pfxlen.c16
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c30
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c19
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c4
-rw-r--r--net/netfilter/nf_conntrack_proto_generic.c8
-rw-r--r--net/netfilter/nf_internals.h1
-rw-r--r--net/netfilter/nf_queue.c17
-rw-r--r--net/netfilter/nf_synproxy_core.c1
-rw-r--r--net/netfilter/nf_tables_api.c117
-rw-r--r--net/netfilter/nf_tables_core.c7
-rw-r--r--net/netfilter/nf_tables_netdev.c258
-rw-r--r--net/netfilter/nfnetlink_log.c2
-rw-r--r--net/netfilter/nfnetlink_queue_core.c63
-rw-r--r--net/netfilter/nft_compat.c2
-rw-r--r--net/netfilter/x_tables.c55
-rw-r--r--net/netfilter/xt_TCPMSS.c6
-rw-r--r--net/netfilter/xt_TEE.c1
-rw-r--r--net/netfilter/xt_addrtype.c2
-rw-r--r--net/netfilter/xt_mark.c1
-rw-r--r--net/netfilter/xt_set.c47
-rw-r--r--net/netfilter/xt_socket.c59
-rw-r--r--net/netlink/af_netlink.c170
-rw-r--r--net/netrom/af_netrom.c4
-rw-r--r--net/netrom/nr_route.c1
-rw-r--r--net/nfc/af_nfc.c2
-rw-r--r--net/nfc/llcp.h2
-rw-r--r--net/nfc/llcp_core.c2
-rw-r--r--net/nfc/llcp_sock.c8
-rw-r--r--net/nfc/nci/Kconfig7
-rw-r--r--net/nfc/nci/Makefile3
-rw-r--r--net/nfc/nci/core.c105
-rw-r--r--net/nfc/nci/hci.c11
-rw-r--r--net/nfc/nci/ntf.c10
-rw-r--r--net/nfc/nci/rsp.c10
-rw-r--r--net/nfc/nci/uart.c494
-rw-r--r--net/nfc/netlink.c55
-rw-r--r--net/nfc/nfc.h2
-rw-r--r--net/nfc/rawsock.c4
-rw-r--r--net/openvswitch/Kconfig2
-rw-r--r--net/openvswitch/actions.c23
-rw-r--r--net/openvswitch/datapath.c20
-rw-r--r--net/openvswitch/datapath.h2
-rw-r--r--net/openvswitch/flow.c4
-rw-r--r--net/openvswitch/flow_netlink.c2
-rw-r--r--net/openvswitch/vport-geneve.c5
-rw-r--r--net/packet/af_packet.c198
-rw-r--r--net/packet/internal.h13
-rw-r--r--net/phonet/af_phonet.c2
-rw-r--r--net/phonet/pep.c2
-rw-r--r--net/rds/af_rds.c52
-rw-r--r--net/rds/bind.c4
-rw-r--r--net/rds/ib.h23
-rw-r--r--net/rds/ib_cm.c43
-rw-r--r--net/rds/ib_recv.c4
-rw-r--r--net/rds/ib_send.c55
-rw-r--r--net/rds/iw_cm.c7
-rw-r--r--net/rds/iw_send.c18
-rw-r--r--net/rds/rdma_transport.c34
-rw-r--r--net/rds/rds.h9
-rw-r--r--net/rds/transport.c21
-rw-r--r--net/rfkill/core.c12
-rw-r--r--net/rfkill/rfkill-gpio.c24
-rw-r--r--net/rose/af_rose.c7
-rw-r--r--net/rose/rose_link.c1
-rw-r--r--net/rose/rose_route.c1
-rw-r--r--net/rxrpc/af_rxrpc.c2
-rw-r--r--net/rxrpc/ar-local.c4
-rw-r--r--net/sched/Kconfig11
-rw-r--r--net/sched/Makefile1
-rw-r--r--net/sched/act_api.c5
-rw-r--r--net/sched/act_bpf.c9
-rw-r--r--net/sched/act_mirred.c2
-rw-r--r--net/sched/act_pedit.c5
-rw-r--r--net/sched/cls_bpf.c16
-rw-r--r--net/sched/cls_flow.c28
-rw-r--r--net/sched/cls_flower.c691
-rw-r--r--net/sched/em_ipset.c4
-rw-r--r--net/sched/sch_api.c17
-rw-r--r--net/sched/sch_choke.c20
-rw-r--r--net/sched/sch_codel.c15
-rw-r--r--net/sched/sch_fq_codel.c26
-rw-r--r--net/sched/sch_gred.c28
-rw-r--r--net/sched/sch_hhf.c19
-rw-r--r--net/sched/sch_ingress.c59
-rw-r--r--net/sched/sch_netem.c4
-rw-r--r--net/sched/sch_qfq.c3
-rw-r--r--net/sched/sch_sfb.c24
-rw-r--r--net/sched/sch_sfq.c27
-rw-r--r--net/sctp/ipv6.c7
-rw-r--r--net/sctp/protocol.c2
-rw-r--r--net/sctp/socket.c43
-rw-r--r--net/socket.c7
-rw-r--r--net/sunrpc/Kconfig28
-rw-r--r--net/sunrpc/Makefile3
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_crypto.c8
-rw-r--r--net/sunrpc/svc.c2
-rw-r--r--net/sunrpc/xprtrdma/Makefile14
-rw-r--r--net/sunrpc/xprtrdma/frwr_ops.c4
-rw-r--r--net/sunrpc/xprtrdma/module.c46
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma.c8
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_marshal.c140
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_recvfrom.c6
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_sendto.c16
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c119
-rw-r--r--net/sunrpc/xprtrdma/transport.c13
-rw-r--r--net/sunrpc/xprtrdma/verbs.c99
-rw-r--r--net/sunrpc/xprtrdma/xprt_rdma.h11
-rw-r--r--net/switchdev/switchdev.c951
-rw-r--r--net/tipc/addr.c7
-rw-r--r--net/tipc/addr.h8
-rw-r--r--net/tipc/bcast.c41
-rw-r--r--net/tipc/bcast.h1
-rw-r--r--net/tipc/bearer.c20
-rw-r--r--net/tipc/bearer.h2
-rw-r--r--net/tipc/core.c4
-rw-r--r--net/tipc/core.h37
-rw-r--r--net/tipc/link.c311
-rw-r--r--net/tipc/link.h59
-rw-r--r--net/tipc/msg.c51
-rw-r--r--net/tipc/msg.h37
-rw-r--r--net/tipc/name_table.c34
-rw-r--r--net/tipc/net.c1
-rw-r--r--net/tipc/netlink_compat.c137
-rw-r--r--net/tipc/node.c3
-rw-r--r--net/tipc/node.h2
-rw-r--r--net/tipc/server.c6
-rw-r--r--net/tipc/socket.c10
-rw-r--r--net/tipc/subscr.c242
-rw-r--r--net/tipc/subscr.h18
-rw-r--r--net/unix/af_unix.c267
-rw-r--r--net/vmw_vsock/af_vsock.c7
-rw-r--r--net/vmw_vsock/vmci_transport.c2
-rw-r--r--net/wireless/chan.c65
-rw-r--r--net/wireless/core.h1
-rw-r--r--net/wireless/nl80211.c7
-rw-r--r--net/wireless/reg.c4
-rw-r--r--net/wireless/sme.c4
-rw-r--r--net/wireless/sysfs.c14
-rw-r--r--net/wireless/util.c5
-rw-r--r--net/x25/af_x25.c8
-rw-r--r--net/xfrm/xfrm_algo.c28
-rw-r--r--net/xfrm/xfrm_input.c12
-rw-r--r--net/xfrm/xfrm_output.c12
-rw-r--r--net/xfrm/xfrm_policy.c42
-rw-r--r--net/xfrm/xfrm_state.c4
-rw-r--r--net/xfrm/xfrm_user.c40
-rw-r--r--samples/bpf/Makefile14
-rw-r--r--samples/bpf/bpf_helpers.h10
-rw-r--r--samples/bpf/bpf_load.c57
-rw-r--r--samples/bpf/lathist_kern.c99
-rw-r--r--samples/bpf/lathist_user.c103
-rw-r--r--samples/bpf/sockex3_kern.c290
-rw-r--r--samples/bpf/sockex3_user.c66
-rw-r--r--samples/bpf/tcbpf1_kern.c8
-rw-r--r--samples/bpf/test_verifier.c84
-rw-r--r--samples/bpf/tracex2_kern.c24
-rw-r--r--samples/bpf/tracex2_user.c67
-rw-r--r--samples/bpf/tracex5_kern.c75
-rw-r--r--samples/bpf/tracex5_user.c46
-rw-r--r--samples/pktgen/README.rst43
-rw-r--r--samples/pktgen/functions.sh121
-rw-r--r--samples/pktgen/parameters.sh97
-rwxr-xr-xsamples/pktgen/pktgen.conf-1-159
-rwxr-xr-xsamples/pktgen/pktgen.conf-2-166
-rwxr-xr-xsamples/pktgen/pktgen.conf-2-273
-rwxr-xr-xsamples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh86
-rwxr-xr-xsamples/pktgen/pktgen_sample01_simple.sh71
-rwxr-xr-xsamples/pktgen/pktgen_sample02_multiqueue.sh75
-rwxr-xr-xsamples/pktgen/pktgen_sample03_burst_single_flow.sh82
-rwxr-xr-xscripts/checkkconfigsymbols.py34
-rwxr-xr-xscripts/checkpatch.pl319
-rwxr-xr-xscripts/checksyscalls.sh2
-rwxr-xr-xscripts/get_maintainer.pl65
-rwxr-xr-xscripts/mksysmap2
-rw-r--r--scripts/mod/devicetable-offsets.c5
-rw-r--r--scripts/mod/file2alias.c34
-rw-r--r--security/capability.c4
-rw-r--r--security/security.c7
-rw-r--r--security/selinux/avc.c18
-rw-r--r--security/selinux/hooks.c18
-rw-r--r--security/selinux/include/avc.h9
-rw-r--r--security/selinux/xfrm.c3
-rw-r--r--sound/aoa/soundbus/core.c4
-rw-r--r--sound/aoa/soundbus/soundbus.h2
-rw-r--r--sound/aoa/soundbus/sysfs.c13
-rw-r--r--sound/core/Kconfig20
-rw-r--r--sound/core/Makefile13
-rw-r--r--sound/core/ctljack.c41
-rw-r--r--sound/core/hrtimer.c9
-rw-r--r--sound/core/hwdep.c6
-rw-r--r--sound/core/info.c833
-rw-r--r--sound/core/info_oss.c29
-rw-r--r--sound/core/init.c59
-rw-r--r--sound/core/jack.c146
-rw-r--r--sound/core/oss/mixer_oss.c6
-rw-r--r--sound/core/pcm.c12
-rw-r--r--sound/core/pcm_drm_eld.c99
-rw-r--r--sound/core/pcm_iec958.c95
-rw-r--r--sound/core/seq/Makefile3
-rw-r--r--sound/core/seq/oss/seq_oss.c6
-rw-r--r--sound/core/seq/oss/seq_oss_init.c5
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c4
-rw-r--r--sound/core/seq/oss/seq_oss_readq.c4
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c4
-rw-r--r--sound/core/seq/seq_clientmgr.c4
-rw-r--r--sound/core/seq/seq_device.c6
-rw-r--r--sound/core/seq/seq_info.c19
-rw-r--r--sound/core/seq/seq_info.h2
-rw-r--r--sound/core/seq/seq_queue.c4
-rw-r--r--sound/core/seq/seq_timer.c4
-rw-r--r--sound/core/sound.c28
-rw-r--r--sound/core/sound_oss.c34
-rw-r--r--sound/core/timer.c4
-rw-r--r--sound/drivers/aloop.c8
-rw-r--r--sound/drivers/dummy.c18
-rw-r--r--sound/drivers/opl4/Makefile3
-rw-r--r--sound/drivers/opl4/opl4_lib.c4
-rw-r--r--sound/drivers/opl4/opl4_local.h7
-rw-r--r--sound/drivers/opl4/opl4_proc.c4
-rw-r--r--sound/drivers/pcsp/pcsp.c17
-rw-r--r--sound/firewire/Kconfig2
-rw-r--r--sound/firewire/amdtp.c271
-rw-r--r--sound/firewire/amdtp.h4
-rw-r--r--sound/firewire/bebob/bebob.c17
-rw-r--r--sound/firewire/bebob/bebob.h20
-rw-r--r--sound/firewire/bebob/bebob_focusrite.c33
-rw-r--r--sound/firewire/bebob/bebob_maudio.c23
-rw-r--r--sound/firewire/bebob/bebob_midi.c8
-rw-r--r--sound/firewire/bebob/bebob_pcm.c14
-rw-r--r--sound/firewire/bebob/bebob_proc.c22
-rw-r--r--sound/firewire/bebob/bebob_stream.c150
-rw-r--r--sound/firewire/bebob/bebob_terratec.c30
-rw-r--r--sound/firewire/bebob/bebob_yamaha.c20
-rw-r--r--sound/firewire/oxfw/oxfw-stream.c10
-rw-r--r--sound/hda/Kconfig26
-rw-r--r--sound/hda/Makefile8
-rw-r--r--sound/hda/ext/Makefile3
-rw-r--r--sound/hda/ext/hdac_ext_bus.c174
-rw-r--r--sound/hda/ext/hdac_ext_controller.c288
-rw-r--r--sound/hda/ext/hdac_ext_stream.c452
-rw-r--r--sound/hda/hda_bus_type.c41
-rw-r--r--sound/hda/hdac_bus.c20
-rw-r--r--sound/hda/hdac_controller.c507
-rw-r--r--sound/hda/hdac_device.c315
-rw-r--r--sound/hda/hdac_i915.c196
-rw-r--r--sound/hda/hdac_stream.c697
-rw-r--r--sound/hda/trace.h27
-rw-r--r--sound/i2c/other/ak4xxx-adda.c4
-rw-r--r--sound/isa/gus/gus_mixer.c9
-rw-r--r--sound/mips/Kconfig2
-rw-r--r--sound/oss/ad1848.c2
-rw-r--r--sound/oss/msnd_pinnacle.c3
-rw-r--r--sound/oss/sb_audio.c8
-rw-r--r--sound/pci/ac97/Makefile2
-rw-r--r--sound/pci/ac97/ac97_local.h2
-rw-r--r--sound/pci/ad1889.c4
-rw-r--r--sound/pci/ak4531_codec.c6
-rw-r--r--sound/pci/ali5451/ali5451.c4
-rw-r--r--sound/pci/als300.c4
-rw-r--r--sound/pci/als4000.c4
-rw-r--r--sound/pci/asihpi/hpioctl.c1
-rw-r--r--sound/pci/atiixp.c4
-rw-r--r--sound/pci/atiixp_modem.c4
-rw-r--r--sound/pci/au88x0/au88x0.c4
-rw-r--r--sound/pci/aw2/aw2-alsa.c4
-rw-r--r--sound/pci/azt3328.c4
-rw-r--r--sound/pci/ca0106/Makefile3
-rw-r--r--sound/pci/ca0106/ca0106_main.c6
-rw-r--r--sound/pci/ca0106/ca0106_proc.c4
-rw-r--r--sound/pci/cmipci.c5
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c4
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.h4
-rw-r--r--sound/pci/cs46xx/dsp_spos.c4
-rw-r--r--sound/pci/cs46xx/dsp_spos_scb_lib.c6
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c4
-rw-r--r--sound/pci/ctxfi/cthw20k1.c4
-rw-r--r--sound/pci/ctxfi/cthw20k2.c4
-rw-r--r--sound/pci/emu10k1/Makefile3
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c6
-rw-r--r--sound/pci/emu10k1/emuproc.c2
-rw-r--r--sound/pci/es1938.c4
-rw-r--r--sound/pci/es1968.c4
-rw-r--r--sound/pci/hda/Kconfig31
-rw-r--r--sound/pci/hda/Makefile9
-rw-r--r--sound/pci/hda/hda_beep.c2
-rw-r--r--sound/pci/hda/hda_beep.h2
-rw-r--r--sound/pci/hda/hda_bind.c10
-rw-r--r--sound/pci/hda/hda_codec.c425
-rw-r--r--sound/pci/hda/hda_codec.h87
-rw-r--r--sound/pci/hda/hda_controller.c1347
-rw-r--r--sound/pci/hda/hda_controller.h272
-rw-r--r--sound/pci/hda/hda_controller_trace.h98
-rw-r--r--sound/pci/hda/hda_eld.c4
-rw-r--r--sound/pci/hda/hda_i915.c196
-rw-r--r--sound/pci/hda/hda_intel.c380
-rw-r--r--sound/pci/hda/hda_intel.h26
-rw-r--r--sound/pci/hda/hda_intel_trace.h55
-rw-r--r--sound/pci/hda/hda_jack.c90
-rw-r--r--sound/pci/hda/hda_jack.h5
-rw-r--r--sound/pci/hda/hda_local.h4
-rw-r--r--sound/pci/hda/hda_tegra.c102
-rw-r--r--sound/pci/hda/patch_analog.c3
-rw-r--r--sound/pci/hda/patch_ca0110.c3
-rw-r--r--sound/pci/hda/patch_ca0132.c133
-rw-r--r--sound/pci/hda/patch_cirrus.c12
-rw-r--r--sound/pci/hda/patch_cmedia.c4
-rw-r--r--sound/pci/hda/patch_conexant.c3
-rw-r--r--sound/pci/hda/patch_hdmi.c193
-rw-r--r--sound/pci/hda/patch_realtek.c119
-rw-r--r--sound/pci/hda/patch_sigmatel.c47
-rw-r--r--sound/pci/hda/patch_via.c21
-rw-r--r--sound/pci/ice1712/ice1712.c4
-rw-r--r--sound/pci/ice1712/quartet.c7
-rw-r--r--sound/pci/intel8x0.c4
-rw-r--r--sound/pci/intel8x0m.c5
-rw-r--r--sound/pci/lx6464es/lx6464es.c18
-rw-r--r--sound/pci/maestro3.c4
-rw-r--r--sound/pci/mixart/mixart.c2
-rw-r--r--sound/pci/oxygen/oxygen_lib.c4
-rw-r--r--sound/pci/oxygen/xonar_wm87x6.c2
-rw-r--r--sound/pci/pcxhr/pcxhr.c2
-rw-r--r--sound/pci/sis7019.c10
-rw-r--r--sound/pci/sonicvibes.c4
-rw-r--r--sound/pci/trident/trident_main.c4
-rw-r--r--sound/ppc/keywest.c36
-rw-r--r--sound/soc/Kconfig2
-rw-r--r--sound/soc/Makefile3
-rw-r--r--sound/soc/atmel/Kconfig37
-rw-r--r--sound/soc/atmel/atmel-pcm-dma.c3
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c10
-rw-r--r--sound/soc/au1x/db1200.c2
-rw-r--r--sound/soc/cirrus/ep93xx-pcm.c1
-rw-r--r--sound/soc/codecs/88pm860x-codec.c19
-rw-r--r--sound/soc/codecs/Kconfig17
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/ab8500-codec.c20
-rw-r--r--sound/soc/codecs/ac97.c8
-rw-r--r--sound/soc/codecs/ad1836.c2
-rw-r--r--sound/soc/codecs/adau1373.c1
-rw-r--r--sound/soc/codecs/adau1701.c126
-rw-r--r--sound/soc/codecs/adau1761.c27
-rw-r--r--sound/soc/codecs/adau1781.c10
-rw-r--r--sound/soc/codecs/adau17x1.c20
-rw-r--r--sound/soc/codecs/adau1977.c14
-rw-r--r--sound/soc/codecs/adav80x.c11
-rw-r--r--sound/soc/codecs/ak4535.c1
-rw-r--r--sound/soc/codecs/ak4641.c3
-rw-r--r--sound/soc/codecs/ak4642.c1
-rw-r--r--sound/soc/codecs/ak4671.c1
-rw-r--r--sound/soc/codecs/alc5623.c3
-rw-r--r--sound/soc/codecs/alc5632.c1
-rw-r--r--sound/soc/codecs/arizona.c201
-rw-r--r--sound/soc/codecs/arizona.h19
-rw-r--r--sound/soc/codecs/bt-sco.c11
-rw-r--r--sound/soc/codecs/cq93vc.c1
-rw-r--r--sound/soc/codecs/cs35l32.c1
-rw-r--r--sound/soc/codecs/cs4265.c1
-rw-r--r--sound/soc/codecs/cs42l52.c5
-rw-r--r--sound/soc/codecs/cs42l56.c5
-rw-r--r--sound/soc/codecs/cs42l73.c3
-rw-r--r--sound/soc/codecs/cs42xx8.c2
-rw-r--r--sound/soc/codecs/cx20442.c6
-rw-r--r--sound/soc/codecs/da7213.c3
-rw-r--r--sound/soc/codecs/da732x.c4
-rw-r--r--sound/soc/codecs/da9055.c3
-rw-r--r--sound/soc/codecs/es8328.c3
-rw-r--r--sound/soc/codecs/isabelle.c2
-rw-r--r--sound/soc/codecs/jz4740.c4
-rw-r--r--sound/soc/codecs/lm4857.c114
-rw-r--r--sound/soc/codecs/lm49453.c4
-rw-r--r--sound/soc/codecs/max98088.c3
-rw-r--r--sound/soc/codecs/max98090.c38
-rw-r--r--sound/soc/codecs/max98095.c24
-rw-r--r--sound/soc/codecs/max98357a.c3
-rw-r--r--sound/soc/codecs/max9850.c3
-rw-r--r--sound/soc/codecs/max98925.c2
-rw-r--r--sound/soc/codecs/ml26124.c61
-rw-r--r--sound/soc/codecs/pcm512x.c8
-rw-r--r--sound/soc/codecs/rl6347a.c128
-rw-r--r--sound/soc/codecs/rl6347a.h32
-rw-r--r--sound/soc/codecs/rt286.c130
-rw-r--r--sound/soc/codecs/rt5631.c5
-rw-r--r--sound/soc/codecs/rt5640.c21
-rw-r--r--sound/soc/codecs/rt5645.c1112
-rw-r--r--sound/soc/codecs/rt5645.h31
-rw-r--r--sound/soc/codecs/rt5651.c5
-rw-r--r--sound/soc/codecs/rt5670.c31
-rw-r--r--sound/soc/codecs/rt5677.c157
-rw-r--r--sound/soc/codecs/rt5677.h15
-rw-r--r--sound/soc/codecs/sgtl5000.c56
-rw-r--r--sound/soc/codecs/sirf-audio-codec.c2
-rw-r--r--sound/soc/codecs/sn95031.c12
-rw-r--r--sound/soc/codecs/ssm2518.c9
-rw-r--r--sound/soc/codecs/ssm2602.c5
-rw-r--r--sound/soc/codecs/ssm4567.c9
-rw-r--r--sound/soc/codecs/sta32x.c19
-rw-r--r--sound/soc/codecs/sta350.c9
-rw-r--r--sound/soc/codecs/sta529.c8
-rw-r--r--sound/soc/codecs/stac9766.c3
-rw-r--r--sound/soc/codecs/tas2552.c430
-rw-r--r--sound/soc/codecs/tas2552.h153
-rw-r--r--sound/soc/codecs/tas571x.c514
-rw-r--r--sound/soc/codecs/tas571x.h33
-rw-r--r--sound/soc/codecs/tlv320aic23.c1
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c11
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c1
-rw-r--r--sound/soc/codecs/tlv320aic3x.c10
-rw-r--r--sound/soc/codecs/tlv320dac33.c5
-rw-r--r--sound/soc/codecs/ts3a227e.c15
-rw-r--r--sound/soc/codecs/twl4030.c3
-rw-r--r--sound/soc/codecs/twl6040.c9
-rw-r--r--sound/soc/codecs/uda134x.c4
-rw-r--r--sound/soc/codecs/uda1380.c6
-rw-r--r--sound/soc/codecs/wm0010.c6
-rw-r--r--sound/soc/codecs/wm1250-ev1.c2
-rw-r--r--sound/soc/codecs/wm2200.c2
-rw-r--r--sound/soc/codecs/wm5100.c12
-rw-r--r--sound/soc/codecs/wm5102.c73
-rw-r--r--sound/soc/codecs/wm5110.c29
-rw-r--r--sound/soc/codecs/wm8350.c3
-rw-r--r--sound/soc/codecs/wm8400.c3
-rw-r--r--sound/soc/codecs/wm8510.c3
-rw-r--r--sound/soc/codecs/wm8523.c29
-rw-r--r--sound/soc/codecs/wm8580.c3
-rw-r--r--sound/soc/codecs/wm8711.c3
-rw-r--r--sound/soc/codecs/wm8728.c3
-rw-r--r--sound/soc/codecs/wm8731.c8
-rw-r--r--sound/soc/codecs/wm8737.c11
-rw-r--r--sound/soc/codecs/wm8741.c190
-rw-r--r--sound/soc/codecs/wm8741.h10
-rw-r--r--sound/soc/codecs/wm8750.c3
-rw-r--r--sound/soc/codecs/wm8753.c3
-rw-r--r--sound/soc/codecs/wm8770.c3
-rw-r--r--sound/soc/codecs/wm8776.c3
-rw-r--r--sound/soc/codecs/wm8804.c2
-rw-r--r--sound/soc/codecs/wm8900.c13
-rw-r--r--sound/soc/codecs/wm8903.c4
-rw-r--r--sound/soc/codecs/wm8903.h2
-rw-r--r--sound/soc/codecs/wm8904.c5
-rw-r--r--sound/soc/codecs/wm8940.c6
-rw-r--r--sound/soc/codecs/wm8955.c7
-rw-r--r--sound/soc/codecs/wm8960.c127
-rw-r--r--sound/soc/codecs/wm8961.c6
-rw-r--r--sound/soc/codecs/wm8962.c21
-rw-r--r--sound/soc/codecs/wm8971.c3
-rw-r--r--sound/soc/codecs/wm8974.c3
-rw-r--r--sound/soc/codecs/wm8978.c7
-rw-r--r--sound/soc/codecs/wm8983.c3
-rw-r--r--sound/soc/codecs/wm8985.c3
-rw-r--r--sound/soc/codecs/wm8988.c3
-rw-r--r--sound/soc/codecs/wm8990.c5
-rw-r--r--sound/soc/codecs/wm8991.c3
-rw-r--r--sound/soc/codecs/wm8993.c12
-rw-r--r--sound/soc/codecs/wm8994.c68
-rw-r--r--sound/soc/codecs/wm8995.c8
-rw-r--r--sound/soc/codecs/wm8996.c23
-rw-r--r--sound/soc/codecs/wm8997.c18
-rw-r--r--sound/soc/codecs/wm9081.c4
-rw-r--r--sound/soc/codecs/wm9090.c6
-rw-r--r--sound/soc/codecs/wm9712.c3
-rw-r--r--sound/soc/codecs/wm9713.c7
-rw-r--r--sound/soc/codecs/wm_adsp.c1452
-rw-r--r--sound/soc/codecs/wm_adsp.h35
-rw-r--r--sound/soc/codecs/wm_hubs.c4
-rw-r--r--sound/soc/codecs/wmfw.h44
-rw-r--r--sound/soc/davinci/davinci-mcasp.c239
-rw-r--r--sound/soc/davinci/davinci-mcasp.h5
-rw-r--r--sound/soc/fsl/fsl_dma.c4
-rw-r--r--sound/soc/fsl/fsl_sai.c144
-rw-r--r--sound/soc/fsl/fsl_sai.h9
-rw-r--r--sound/soc/fsl/fsl_spdif.c10
-rw-r--r--sound/soc/fsl/fsl_ssi.c7
-rw-r--r--sound/soc/fsl/imx-audmux.c2
-rw-r--r--sound/soc/fsl/imx-mc13783.c6
-rw-r--r--sound/soc/fsl/imx-wm8962.c2
-rw-r--r--sound/soc/generic/simple-card.c34
-rw-r--r--sound/soc/intel/Kconfig19
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.c187
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.h9
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c47
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform.h2
-rw-r--r--sound/soc/intel/atom/sst/sst.c4
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c4
-rw-r--r--sound/soc/intel/atom/sst/sst_drv_interface.c2
-rw-r--r--sound/soc/intel/baytrail/sst-baytrail-ipc.c11
-rw-r--r--sound/soc/intel/boards/Makefile2
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c348
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c118
-rw-r--r--sound/soc/intel/common/sst-acpi.c2
-rw-r--r--sound/soc/intel/common/sst-ipc.c34
-rw-r--r--sound/soc/intel/common/sst-ipc.h7
-rw-r--r--sound/soc/intel/haswell/sst-haswell-ipc.c12
-rw-r--r--sound/soc/intel/haswell/sst-haswell-pcm.c32
-rw-r--r--sound/soc/mediatek/Kconfig30
-rw-r--r--sound/soc/mediatek/Makefile5
-rw-r--r--sound/soc/mediatek/mt8173-max98090.c213
-rw-r--r--sound/soc/mediatek/mt8173-rt5650-rt5676.c278
-rw-r--r--sound/soc/mediatek/mtk-afe-common.h109
-rw-r--r--sound/soc/mediatek/mtk-afe-pcm.c1233
-rw-r--r--sound/soc/omap/Kconfig5
-rw-r--r--sound/soc/omap/omap-hdmi-audio.c12
-rw-r--r--sound/soc/omap/omap-twl4030.c3
-rw-r--r--sound/soc/omap/rx51.c40
-rw-r--r--sound/soc/pxa/brownstone.c25
-rw-r--r--sound/soc/pxa/poodle.c19
-rw-r--r--sound/soc/pxa/tosa.c13
-rw-r--r--sound/soc/pxa/z2.c9
-rw-r--r--sound/soc/qcom/Kconfig28
-rw-r--r--sound/soc/qcom/Makefile6
-rw-r--r--sound/soc/qcom/apq8016_sbc.c198
-rw-r--r--sound/soc/qcom/lpass-apq8016.c242
-rw-r--r--sound/soc/qcom/lpass-cpu.c240
-rw-r--r--sound/soc/qcom/lpass-ipq806x.c109
-rw-r--r--sound/soc/qcom/lpass-lpaif-reg.h (renamed from sound/soc/qcom/lpass-lpaif-ipq806x.h)92
-rw-r--r--sound/soc/qcom/lpass-platform.c202
-rw-r--r--sound/soc/qcom/lpass.h51
-rw-r--r--sound/soc/qcom/storm.c26
-rw-r--r--sound/soc/samsung/Kconfig15
-rw-r--r--sound/soc/samsung/i2s.c2
-rw-r--r--sound/soc/samsung/lowland.c2
-rw-r--r--sound/soc/samsung/smartq_wm8987.c6
-rw-r--r--sound/soc/samsung/smdk_wm8994.c3
-rw-r--r--sound/soc/samsung/speyside.c2
-rw-r--r--sound/soc/sh/migor.c3
-rw-r--r--sound/soc/sh/rcar/core.c139
-rw-r--r--sound/soc/sh/rcar/dma.c113
-rw-r--r--sound/soc/sh/rcar/dvc.c30
-rw-r--r--sound/soc/sh/rcar/rsnd.h113
-rw-r--r--sound/soc/sh/rcar/rsrc-card.c439
-rw-r--r--sound/soc/sh/rcar/src.c130
-rw-r--r--sound/soc/sh/rcar/ssi.c160
-rw-r--r--sound/soc/soc-core.c67
-rw-r--r--sound/soc/soc-dapm.c349
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c25
-rw-r--r--sound/soc/soc-jack.c12
-rw-r--r--sound/soc/soc-pcm.c47
-rw-r--r--sound/soc/soc-topology.c1826
-rw-r--r--sound/soc/ux500/mop500_ab8500.c4
-rw-r--r--sound/soc/ux500/ux500_pcm.c1
-rw-r--r--sound/soc/zte/Kconfig17
-rw-r--r--sound/soc/zte/Makefile2
-rw-r--r--sound/soc/zte/zx296702-i2s.c436
-rw-r--r--sound/soc/zte/zx296702-spdif.c365
-rw-r--r--sound/sound_firmware.c4
-rw-r--r--sound/synth/emux/Makefile5
-rw-r--r--sound/synth/emux/emux.c4
-rw-r--r--sound/synth/emux/emux_proc.c4
-rw-r--r--sound/synth/emux/emux_voice.h6
-rw-r--r--sound/usb/bcd2000/bcd2000.c2
-rw-r--r--sound/usb/mixer.c6
-rw-r--r--tools/Makefile40
-rw-r--r--tools/arch/alpha/include/asm/barrier.h8
-rw-r--r--tools/arch/arm/include/asm/barrier.h12
-rw-r--r--tools/arch/arm64/include/asm/barrier.h16
-rw-r--r--tools/arch/ia64/include/asm/barrier.h48
-rw-r--r--tools/arch/mips/include/asm/barrier.h20
-rw-r--r--tools/arch/powerpc/include/asm/barrier.h29
-rw-r--r--tools/arch/s390/include/asm/barrier.h30
-rw-r--r--tools/arch/sh/include/asm/barrier.h32
-rw-r--r--tools/arch/sparc/include/asm/barrier.h8
-rw-r--r--tools/arch/sparc/include/asm/barrier_32.h6
-rw-r--r--tools/arch/sparc/include/asm/barrier_64.h42
-rw-r--r--tools/arch/tile/include/asm/barrier.h15
-rw-r--r--tools/arch/x86/include/asm/atomic.h65
-rw-r--r--tools/arch/x86/include/asm/barrier.h28
-rw-r--r--tools/arch/x86/include/asm/rmwcc.h41
-rw-r--r--tools/arch/xtensa/include/asm/barrier.h18
-rw-r--r--tools/build/Makefile.build10
-rw-r--r--tools/build/Makefile.feature4
-rw-r--r--tools/build/tests/ex/Build1
-rw-r--r--tools/build/tests/ex/empty2/README2
-rw-r--r--tools/hv/hv_fcopy_daemon.c15
-rw-r--r--tools/hv/hv_kvp_daemon.c166
-rw-r--r--tools/hv/hv_vss_daemon.c149
-rw-r--r--tools/iio/Makefile4
-rw-r--r--tools/iio/generic_buffer.c200
-rw-r--r--tools/iio/iio_event_monitor.c50
-rw-r--r--tools/iio/iio_utils.c469
-rw-r--r--tools/iio/iio_utils.h20
-rw-r--r--tools/iio/lsiio.c63
-rw-r--r--tools/include/asm-generic/atomic-gcc.h63
-rw-r--r--tools/include/asm-generic/barrier.h44
-rw-r--r--tools/include/asm/atomic.h10
-rw-r--r--tools/include/asm/barrier.h27
-rw-r--r--tools/include/linux/atomic.h6
-rw-r--r--tools/include/linux/compiler.h4
-rw-r--r--tools/include/linux/kernel.h (renamed from tools/perf/util/include/linux/kernel.h)4
-rw-r--r--tools/include/linux/list.h (renamed from tools/perf/util/include/linux/list.h)6
-rw-r--r--tools/include/linux/poison.h1
-rw-r--r--tools/include/linux/types.h8
-rw-r--r--tools/laptop/freefall/Makefile17
-rw-r--r--tools/laptop/freefall/freefall.c (renamed from Documentation/laptops/freefall.c)0
-rw-r--r--tools/lib/traceevent/.gitignore1
-rw-r--r--tools/lib/traceevent/Makefile34
-rw-r--r--tools/lib/traceevent/event-parse.c6
-rw-r--r--tools/lib/traceevent/event-parse.h1
-rw-r--r--tools/lib/traceevent/plugin_cfg80211.c13
-rw-r--r--tools/perf/.gitignore1
-rw-r--r--tools/perf/Documentation/callchain-overhead-calculation.txt108
-rw-r--r--tools/perf/Documentation/perf-bench.txt3
-rw-r--r--tools/perf/Documentation/perf-inject.txt27
-rw-r--r--tools/perf/Documentation/perf-kmem.txt11
-rw-r--r--tools/perf/Documentation/perf-kvm.txt6
-rw-r--r--tools/perf/Documentation/perf-probe.txt17
-rw-r--r--tools/perf/Documentation/perf-record.txt27
-rw-r--r--tools/perf/Documentation/perf-report.txt35
-rw-r--r--tools/perf/Documentation/perf-script.txt37
-rw-r--r--tools/perf/Documentation/perf-top.txt9
-rw-r--r--tools/perf/Documentation/perf-trace.txt7
-rw-r--r--tools/perf/MANIFEST26
-rw-r--r--tools/perf/Makefile.perf30
-rw-r--r--tools/perf/arch/arm64/Build1
-rw-r--r--tools/perf/arch/arm64/include/perf_regs.h3
-rw-r--r--tools/perf/arch/arm64/tests/Build2
-rw-r--r--tools/perf/arch/arm64/tests/dwarf-unwind.c61
-rw-r--r--tools/perf/arch/arm64/tests/regs_load.S46
-rw-r--r--tools/perf/arch/common.c2
-rw-r--r--tools/perf/arch/powerpc/util/Build1
-rw-r--r--tools/perf/arch/powerpc/util/sym-handling.c82
-rw-r--r--tools/perf/bench/Build1
-rw-r--r--tools/perf/bench/bench.h2
-rw-r--r--tools/perf/bench/futex-wake-parallel.c294
-rw-r--r--tools/perf/bench/futex-wake.c7
-rw-r--r--tools/perf/bench/numa.c33
-rw-r--r--tools/perf/builtin-annotate.c19
-rw-r--r--tools/perf/builtin-bench.c1
-rw-r--r--tools/perf/builtin-buildid-list.c9
-rw-r--r--tools/perf/builtin-diff.c9
-rw-r--r--tools/perf/builtin-inject.c175
-rw-r--r--tools/perf/builtin-kmem.c988
-rw-r--r--tools/perf/builtin-kvm.c11
-rw-r--r--tools/perf/builtin-lock.c8
-rw-r--r--tools/perf/builtin-mem.c5
-rw-r--r--tools/perf/builtin-probe.c195
-rw-r--r--tools/perf/builtin-record.c382
-rw-r--r--tools/perf/builtin-report.c47
-rw-r--r--tools/perf/builtin-sched.c159
-rw-r--r--tools/perf/builtin-script.c94
-rw-r--r--tools/perf/builtin-stat.c490
-rw-r--r--tools/perf/builtin-timechart.c9
-rw-r--r--tools/perf/builtin-top.c72
-rw-r--r--tools/perf/builtin-trace.c139
-rw-r--r--tools/perf/config/Makefile13
-rw-r--r--tools/perf/config/utilities.mak19
-rw-r--r--tools/perf/perf-sys.h73
-rw-r--r--tools/perf/perf.h6
-rw-r--r--tools/perf/tests/Build8
-rw-r--r--tools/perf/tests/builtin-test.c16
-rw-r--r--tools/perf/tests/code-reading.c26
-rw-r--r--tools/perf/tests/dso-data.c15
-rw-r--r--tools/perf/tests/dwarf-unwind.c3
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c4
-rw-r--r--tools/perf/tests/hists_common.c10
-rw-r--r--tools/perf/tests/hists_cumulate.c10
-rw-r--r--tools/perf/tests/hists_filter.c12
-rw-r--r--tools/perf/tests/hists_link.c12
-rw-r--r--tools/perf/tests/hists_output.c10
-rw-r--r--tools/perf/tests/keep-tracking.c4
-rw-r--r--tools/perf/tests/kmod-path.c72
-rw-r--r--tools/perf/tests/make18
-rw-r--r--tools/perf/tests/mmap-basic.c6
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c6
-rw-r--r--tools/perf/tests/openat-syscall-all-cpus.c (renamed from tools/perf/tests/open-syscall-all-cpus.c)13
-rw-r--r--tools/perf/tests/openat-syscall-tp-fields.c (renamed from tools/perf/tests/open-syscall-tp-fields.c)6
-rw-r--r--tools/perf/tests/openat-syscall.c (renamed from tools/perf/tests/open-syscall.c)14
-rw-r--r--tools/perf/tests/parse-events.c14
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c2
-rw-r--r--tools/perf/tests/pmu.c3
-rw-r--r--tools/perf/tests/switch-tracking.c8
-rw-r--r--tools/perf/tests/tests.h17
-rw-r--r--tools/perf/tests/thread-mg-share.c41
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c34
-rw-r--r--tools/perf/ui/browsers/annotate.c64
-rw-r--r--tools/perf/ui/browsers/hists.c646
-rw-r--r--tools/perf/ui/tui/setup.c2
-rw-r--r--tools/perf/util/Build13
-rw-r--r--tools/perf/util/annotate.c73
-rw-r--r--tools/perf/util/annotate.h7
-rw-r--r--tools/perf/util/auxtrace.c1352
-rw-r--r--tools/perf/util/auxtrace.h643
-rw-r--r--tools/perf/util/build-id.c64
-rw-r--r--tools/perf/util/cache.h1
-rw-r--r--tools/perf/util/callchain.h4
-rw-r--r--tools/perf/util/cgroup.c10
-rw-r--r--tools/perf/util/cgroup.h4
-rw-r--r--tools/perf/util/comm.c13
-rw-r--r--tools/perf/util/data-convert-bt.c410
-rw-r--r--tools/perf/util/db-export.c31
-rw-r--r--tools/perf/util/dso.c334
-rw-r--r--tools/perf/util/dso.h47
-rw-r--r--tools/perf/util/dwarf-aux.c220
-rw-r--r--tools/perf/util/dwarf-aux.h13
-rw-r--r--tools/perf/util/environment.c1
-rw-r--r--tools/perf/util/event.c119
-rw-r--r--tools/perf/util/event.h99
-rw-r--r--tools/perf/util/evlist.c103
-rw-r--r--tools/perf/util/evlist.h13
-rw-r--r--tools/perf/util/evsel.c26
-rw-r--r--tools/perf/util/evsel.h7
-rw-r--r--tools/perf/util/header.c52
-rw-r--r--tools/perf/util/header.h1
-rw-r--r--tools/perf/util/hist.c63
-rw-r--r--tools/perf/util/hist.h1
-rw-r--r--tools/perf/util/include/linux/poison.h1
-rw-r--r--tools/perf/util/include/linux/rbtree.h14
-rw-r--r--tools/perf/util/machine.c281
-rw-r--r--tools/perf/util/machine.h32
-rw-r--r--tools/perf/util/map.c267
-rw-r--r--tools/perf/util/map.h52
-rw-r--r--tools/perf/util/pager.c5
-rw-r--r--tools/perf/util/parse-branch-options.c94
-rw-r--r--tools/perf/util/parse-branch-options.h5
-rw-r--r--tools/perf/util/parse-events.c196
-rw-r--r--tools/perf/util/parse-events.h42
-rw-r--r--tools/perf/util/parse-events.l41
-rw-r--r--tools/perf/util/parse-events.y50
-rw-r--r--tools/perf/util/parse-options.h4
-rw-r--r--tools/perf/util/pmu.c72
-rw-r--r--tools/perf/util/pmu.h6
-rw-r--r--tools/perf/util/probe-event.c662
-rw-r--r--tools/perf/util/probe-event.h26
-rw-r--r--tools/perf/util/probe-finder.c165
-rw-r--r--tools/perf/util/probe-finder.h10
-rw-r--r--tools/perf/util/pstack.c7
-rw-r--r--tools/perf/util/pstack.h1
-rw-r--r--tools/perf/util/python-ext-sources1
-rw-r--r--tools/perf/util/record.c15
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c4
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c4
-rw-r--r--tools/perf/util/session.c288
-rw-r--r--tools/perf/util/session.h6
-rw-r--r--tools/perf/util/sort.c12
-rw-r--r--tools/perf/util/sort.h38
-rw-r--r--tools/perf/util/stat-shadow.c434
-rw-r--r--tools/perf/util/stat.c71
-rw-r--r--tools/perf/util/stat.h46
-rw-r--r--tools/perf/util/strfilter.c107
-rw-r--r--tools/perf/util/strfilter.h35
-rw-r--r--tools/perf/util/symbol-elf.c23
-rw-r--r--tools/perf/util/symbol.c117
-rw-r--r--tools/perf/util/symbol.h12
-rw-r--r--tools/perf/util/thread-stack.c18
-rw-r--r--tools/perf/util/thread-stack.h1
-rw-r--r--tools/perf/util/thread.c12
-rw-r--r--tools/perf/util/thread.h5
-rw-r--r--tools/perf/util/thread_map.c24
-rw-r--r--tools/perf/util/tool.h13
-rw-r--r--tools/perf/util/trace-event-parse.c2
-rw-r--r--tools/perf/util/unwind-libunwind.c11
-rw-r--r--tools/perf/util/util.c121
-rw-r--r--tools/perf/util/util.h6
-rw-r--r--tools/perf/util/vdso.c60
-rw-r--r--tools/perf/util/vdso.h4
-rw-r--r--tools/perf/util/xyarray.c8
-rw-r--r--tools/perf/util/xyarray.h2
-rw-r--r--tools/power/cpupower/utils/idle_monitor/mperf_monitor.c5
-rw-r--r--tools/power/x86/turbostat/Makefile2
-rw-r--r--tools/testing/selftests/net/psock_fanout.c2
-rw-r--r--tools/testing/selftests/powerpc/Makefile2
-rw-r--r--tools/testing/selftests/powerpc/dscr/.gitignore7
-rw-r--r--tools/testing/selftests/powerpc/dscr/Makefile14
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr.h127
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr_default_test.c127
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr_explicit_test.c71
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c117
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c95
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c97
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr_sysfs_thread_test.c80
-rw-r--r--tools/testing/selftests/powerpc/dscr/dscr_user_test.c61
-rw-r--r--tools/testing/selftests/powerpc/switch_endian/Makefile14
-rw-r--r--tools/testing/selftests/powerpc/tm/Makefile4
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-syscall.c3
-rw-r--r--tools/testing/selftests/powerpc/vphn/Makefile13
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/configinit.sh2
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck.sh4
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm.sh25
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/CFcommon2
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-N1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-P1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-P.boot2
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS015
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS021
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS032
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TINY022
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TINY02.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE011
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE022
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE02-T1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE038
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE03.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE048
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE054
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE064
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE06.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE074
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE086
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE08-T1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE08-T.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE091
-rw-r--r--tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt36
-rw-r--r--tools/testing/selftests/timers/leap-a-day.c77
-rw-r--r--tools/testing/selftests/x86/Makefile5
-rw-r--r--tools/testing/selftests/x86/sysret_ss_attrs.c112
-rw-r--r--tools/testing/selftests/x86/thunks.S67
-rw-r--r--virt/kvm/arm/vgic-v3-emul.c56
-rw-r--r--virt/kvm/arm/vgic.c10
-rw-r--r--virt/kvm/async_pf.h4
-rw-r--r--virt/kvm/coalesced_mmio.h4
-rw-r--r--virt/kvm/irqchip.c41
-rw-r--r--virt/kvm/kvm_main.c432
8599 files changed, 933056 insertions, 201465 deletions
diff --git a/.mailmap b/.mailmap
index 6287004040e7..977f958eedbe 100644
--- a/.mailmap
+++ b/.mailmap
@@ -84,6 +84,7 @@ Mayuresh Janorkar <mayur@ti.com>
Michael Buesch <m@bues.ch>
Michel Dänzer <michel@tungstengraphics.com>
Mitesh shah <mshah@teja.com>
+Mohit Kumar <mohit.kumar@st.com> <mohit.kumar.dhaka@gmail.com>
Morten Welinder <terra@gnome.org>
Morten Welinder <welinder@anemone.rentec.com>
Morten Welinder <welinder@darter.rentec.com>
@@ -95,10 +96,12 @@ Patrick Mochel <mochel@digitalimplant.org>
Peter A Jonsson <pj@ludd.ltu.se>
Peter Oruba <peter@oruba.de>
Peter Oruba <peter.oruba@amd.com>
+Pratyush Anand <pratyush.anand@gmail.com> <pratyush.anand@st.com>
Praveen BP <praveenbp@ti.com>
Rajesh Shah <rajesh.shah@intel.com>
Ralf Baechle <ralf@linux-mips.org>
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
+Randy Dunlap <rdunlap@infradead.org> <rdunlap@xenotime.net>
Rémi Denis-Courmont <rdenis@simphalempin.com>
Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
Rudolf Marek <R.Marek@sh.cvut.cz>
diff --git a/CREDITS b/CREDITS
index ec7e6c7fdd1b..4df764ebe217 100644
--- a/CREDITS
+++ b/CREDITS
@@ -3219,11 +3219,6 @@ N: Dipankar Sarma
E: dipankar@in.ibm.com
D: RCU
-N: Yoshinori Sato
-E: ysato@users.sourceforge.jp
-D: uClinux for Renesas H8/300 (H8300)
-D: http://uclinux-h8.sourceforge.jp/
-
N: Hannu Savolainen
E: hannu@opensound.com
D: Maintainer of the sound drivers until 2.1.x days.
diff --git a/Documentation/ABI/stable/sysfs-bus-w1 b/Documentation/ABI/stable/sysfs-bus-w1
new file mode 100644
index 000000000000..140d85b4ae92
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-bus-w1
@@ -0,0 +1,11 @@
+What: /sys/bus/w1/devices/.../w1_master_timeout_us
+Date: April 2015
+Contact: Dmitry Khromov <dk@icelogic.net>
+Description: Bus scanning interval, microseconds component.
+ Some of 1-Wire devices commonly associated with physical access
+ control systems are attached/generate presence for as short as
+ 100 ms - hence the tens-to-hundreds milliseconds scan intervals
+ are required.
+ see Documentation/w1/w1.generic for detailed information.
+Users: any user space application which wants to know bus scanning
+ interval
diff --git a/Documentation/ABI/stable/sysfs-driver-w1_ds28ea00 b/Documentation/ABI/stable/sysfs-driver-w1_ds28ea00
new file mode 100644
index 000000000000..e928def14f28
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-driver-w1_ds28ea00
@@ -0,0 +1,6 @@
+What: /sys/bus/w1/devices/.../w1_seq
+Date: Apr 2015
+Contact: Matt Campbell <mattrcampbell@gmail.com>
+Description: Support for the DS28EA00 chain sequence function
+ see Documentation/w1/slaves/w1_therm for detailed information
+Users: any user space application which wants to communicate with DS28EA00
diff --git a/Documentation/ABI/testing/configfs-spear-pcie-gadget b/Documentation/ABI/testing/configfs-spear-pcie-gadget
index 875988146a63..840c324ef34d 100644
--- a/Documentation/ABI/testing/configfs-spear-pcie-gadget
+++ b/Documentation/ABI/testing/configfs-spear-pcie-gadget
@@ -1,7 +1,7 @@
What: /config/pcie-gadget
Date: Feb 2011
KernelVersion: 2.6.37
-Contact: Pratyush Anand <pratyush.anand@st.com>
+Contact: Pratyush Anand <pratyush.anand@gmail.com>
Description:
Interface is used to configure selected dual mode PCIe controller
diff --git a/Documentation/ABI/testing/dev-kmsg b/Documentation/ABI/testing/dev-kmsg
index bb820be48179..fff817efa508 100644
--- a/Documentation/ABI/testing/dev-kmsg
+++ b/Documentation/ABI/testing/dev-kmsg
@@ -98,4 +98,13 @@ Description: The /dev/kmsg character device node provides userspace access
logic is used internally when messages are printed to the
console, /proc/kmsg or the syslog() syscall.
+ By default, kernel tries to avoid fragments by concatenating
+ when it can and fragments are rare; however, when extended
+ console support is enabled, the in-kernel concatenation is
+ disabled and /dev/kmsg output will contain more fragments. If
+ the log consumer performs concatenation, the end result
+ should be the same. In the future, the in-kernel concatenation
+ may be removed entirely and /dev/kmsg users are recommended to
+ implement fragment handling.
+
Users: dmesg(1), userspace kernel log consumers
diff --git a/Documentation/ABI/testing/sysfs-ata b/Documentation/ABI/testing/sysfs-ata
index 0a932155cbba..aa4296498859 100644
--- a/Documentation/ABI/testing/sysfs-ata
+++ b/Documentation/ABI/testing/sysfs-ata
@@ -90,6 +90,17 @@ gscr
130: SATA_PMP_GSCR_SII_GPIO
Only valid if the device is a PM.
+trim
+
+ Shows the DSM TRIM mode currently used by the device. Valid
+ values are:
+ unsupported: Drive does not support DSM TRIM
+ unqueued: Drive supports unqueued DSM TRIM only
+ queued: Drive supports queued DSM TRIM
+ forced_unqueued: Drive's queued DSM support is known to be
+ buggy and only unqueued TRIM commands
+ are sent
+
spdn_cnt
Number of time libata decided to lower the speed of link due to errors.
diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
new file mode 100644
index 000000000000..2fe2e3dae487
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x
@@ -0,0 +1,450 @@
+What: /sys/bus/coresight/devices/<memory_map>.etm/enable_source
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Enable/disable tracing on this specific trace entiry.
+ Enabling a source implies the source has been configured
+ properly and a sink has been identidifed for it. The path
+ of coresight components linking the source to the sink is
+ configured and managed automatically by the coresight framework.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/cpu
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) The CPU this tracing entity is associated with.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/nr_pe_cmp
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Indicates the number of PE comparator inputs that are
+ available for tracing.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/nr_addr_cmp
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Indicates the number of address comparator pairs that are
+ available for tracing.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/nr_cntr
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Indicates the number of counters that are available for
+ tracing.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/nr_ext_inp
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Indicates how many external inputs are implemented.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/numcidc
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Indicates the number of Context ID comparators that are
+ available for tracing.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/numvmidc
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Indicates the number of VMID comparators that are available
+ for tracing.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/nrseqstate
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Indicates the number of sequencer states that are
+ implemented.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/nr_resource
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Indicates the number of resource selection pairs that are
+ available for tracing.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/nr_ss_cmp
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Indicates the number of single-shot comparator controls that
+ are available for tracing.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/reset
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (W) Cancels all configuration on a trace unit and set it back
+ to its boot configuration.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mode
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Controls various modes supported by this ETM, for example
+ P0 instruction tracing, branch broadcast, cycle counting and
+ context ID tracing.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/pe
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Controls which PE to trace.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/event
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Controls the tracing of arbitrary events from bank 0 to 3.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/event_instren
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Controls the behavior of the events in bank 0 to 3.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/event_ts
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Controls the insertion of global timestamps in the trace
+ streams.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/syncfreq
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Controls how often trace synchronization requests occur.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/cyc_threshold
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Sets the threshold value for cycle counting.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/bb_ctrl
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Controls which regions in the memory map are enabled to
+ use branch broadcasting.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/event_vinst
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Controls instruction trace filtering.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/s_exlevel_vinst
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) In Secure state, each bit controls whether instruction
+ tracing is enabled for the corresponding exception level.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/ns_exlevel_vinst
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) In non-secure state, each bit controls whether instruction
+ tracing is enabled for the corresponding exception level.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/addr_idx
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Select which address comparator or pair (of comparators) to
+ work with.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/addr_instdatatype
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Controls what type of comparison the trace unit performs.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/addr_single
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Used to setup single address comparator values.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/addr_range
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Used to setup address range comparator values.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/seq_idx
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Select which sequensor.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/seq_state
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Use this to set, or read, the sequencer state.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/seq_event
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Moves the sequencer state to a specific state.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/seq_reset_event
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Moves the sequencer to state 0 when a programmed event
+ occurs.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/cntr_idx
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Select which counter unit to work with.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/cntrldvr
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) This sets or returns the reload count value of the
+ specific counter.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/cntr_val
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) This sets or returns the current count value of the
+ specific counter.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/cntr_ctrl
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Controls the operation of the selected counter.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/res_idx
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Select which resource selection unit to work with.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/res_ctrl
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Controls the selection of the resources in the trace unit.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/ctxid_idx
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Select which context ID comparator to work with.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/ctxid_val
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Get/Set the context ID comparator value to trigger on.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/ctxid_masks
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Mask for all 8 context ID comparator value
+ registers (if implemented).
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/vmid_idx
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Select which virtual machine ID comparator to work with.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/vmid_val
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Get/Set the virtual machine ID comparator value to
+ trigger on.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/vmid_masks
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (RW) Mask for all 8 virtual machine ID comparator value
+ registers (if implemented).
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcoslsr
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the OS Lock Status Register (0x304).
+ The value it taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpdcr
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the Power Down Control Register
+ (0x310). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpdsr
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the Power Down Status Register
+ (0x314). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trclsr
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the SW Lock Status Register
+ (0xFB4). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcauthstatus
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the Authentication Status Register
+ (0xFB8). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcdevid
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the Device ID Register
+ (0xFC8). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcdevtype
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the Device Type Register
+ (0xFCC). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpidr0
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the Peripheral ID0 Register
+ (0xFE0). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpidr1
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the Peripheral ID1 Register
+ (0xFE4). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpidr2
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the Peripheral ID2 Register
+ (0xFE8). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpidr3
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Print the content of the Peripheral ID3 Register
+ (0xFEC). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr0
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Returns the tracing capabilities of the trace unit (0x1E0).
+ The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr1
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Returns the tracing capabilities of the trace unit (0x1E4).
+ The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr2
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Returns the maximum size of the data value, data address,
+ VMID, context ID and instuction address in the trace unit
+ (0x1E8). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr3
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Returns the value associated with various resources
+ available to the trace unit. See the Trace Macrocell
+ architecture specification for more details (0x1E8).
+ The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr4
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Returns how many resources the trace unit supports (0x1F0).
+ The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr5
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Returns how many resources the trace unit supports (0x1F4).
+ The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr8
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Returns the maximum speculation depth of the instruction
+ trace stream. (0x180). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr9
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Returns the number of P0 right-hand keys that the trace unit
+ can use (0x184). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr10
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Returns the number of P1 right-hand keys that the trace unit
+ can use (0x188). The value is taken directly from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr11
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Returns the number of special P1 right-hand keys that the
+ trace unit can use (0x18C). The value is taken directly from
+ the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr12
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Returns the number of conditional P1 right-hand keys that
+ the trace unit can use (0x190). The value is taken directly
+ from the HW.
+
+What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr13
+Date: April 2015
+KernelVersion: 4.01
+Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
+Description: (R) Returns the number of special conditional P1 right-hand keys
+ that the trace unit can use (0x194). The value is taken
+ directly from the HW.
diff --git a/Documentation/ABI/testing/sysfs-bus-fcoe b/Documentation/ABI/testing/sysfs-bus-fcoe
index 21640eaad371..657df13b100d 100644
--- a/Documentation/ABI/testing/sysfs-bus-fcoe
+++ b/Documentation/ABI/testing/sysfs-bus-fcoe
@@ -32,7 +32,7 @@ Description: 'FCoE Controller' instances on the fcoe bus.
Attributes:
- fcf_dev_loss_tmo: Device loss timeout peroid (see below). Changing
+ fcf_dev_loss_tmo: Device loss timeout period (see below). Changing
this value will change the dev_loss_tmo for all
FCFs discovered by this controller.
@@ -61,7 +61,7 @@ Attributes:
lesb/err_block: Link Error Status Block (LESB) block error count.
lesb/fcs_error: Link Error Status Block (LESB) Fibre Channel
- Serivces error count.
+ Services error count.
Notes: ctlr_X (global increment starting at 0)
@@ -85,7 +85,7 @@ Attributes:
fabric.
selected: 1 indicates that the switch has been selected for use;
- 0 indicates that the swich will not be used.
+ 0 indicates that the switch will not be used.
fc_map: The Fibre Channel MAP
@@ -93,7 +93,7 @@ Attributes:
mac: The FCF's MAC address
- fka_peroid: The FIP Keep-Alive peroid
+ fka_period: The FIP Keep-Alive period
fabric_state: The internal kernel state
"Unknown" - Initialization value
@@ -101,9 +101,9 @@ Attributes:
"Connected" - Host is connected to the FCF
"Deleted" - FCF is being removed from the system
- dev_loss_tmo: The device loss timeout peroid for this FCF.
+ dev_loss_tmo: The device loss timeout period for this FCF.
-Notes: A device loss infrastructre similar to the FC Transport's
+Notes: A device loss infrastructure similar to the FC Transport's
is present in fcoe_sysfs. It is nice to have so that a
link flapping adapter doesn't continually advance the count
used to identify the discovered FCF. FCFs will exist in a
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 3befcb19f414..bbed111c31b4 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -71,6 +71,8 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_raw
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_raw
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
@@ -81,6 +83,11 @@ Description:
unique to allow association with event codes. Units after
application of scale and offset are millivolts.
+ Channels with 'i' and 'q' modifiers always exist in pairs and both
+ channels refer to the same signal. The 'i' channel contains the in-phase
+ component of the signal while the 'q' channel contains the quadrature
+ component.
+
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_raw
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
@@ -246,8 +253,16 @@ What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_offset
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_current_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_currentY_i_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_currentY_q_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_current_q_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_current_i_offset
What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
@@ -273,14 +288,22 @@ Description:
to the _raw output.
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_scale
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_scale
What: /sys/bus/iio/devices/iio:deviceX/in_current_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_currentY_i_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_currentY_q_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_current_i_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_current_q_scale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
@@ -328,6 +351,10 @@ Description:
What /sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale
+What /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_calibscale
+What /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_calibscale
+What /sys/bus/iio/devices/iio:deviceX/in_voltage_i_calibscale
+What /sys/bus/iio/devices/iio:deviceX/in_voltage_q_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale
@@ -420,6 +447,16 @@ Description:
to the underlying data channel, then this parameter
gives the 3dB frequency of the filter in Hz.
+What: /sys/.../in_accel_filter_high_pass_3db_frequency
+What: /sys/.../in_anglvel_filter_high_pass_3db_frequency
+What: /sys/.../in_magn_filter_high_pass_3db_frequency
+KernelVersion: 4.2
+Contact: linux-iio@vger.kernel.org
+Description:
+ If a known or controllable high pass filter is applied
+ to the underlying data channel, then this parameter
+ gives the 3dB frequency of the filter in Hz.
+
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_raw
KernelVersion: 2.6.37
@@ -880,6 +917,26 @@ Description:
met before an event is generated. If direction is not
specified then this period applies to both directions.
+What: /sys/.../events/in_accel_thresh_rising_low_pass_filter_3db
+What: /sys/.../events/in_anglvel_thresh_rising_low_pass_filter_3db
+What: /sys/.../events/in_magn_thresh_rising_low_pass_filter_3db
+KernelVersion: 4.2
+Contact: linux-iio@vger.kernel.org
+Description:
+ If a low pass filter can be applied to the event generation
+ this property gives its 3db frequency in Hz.
+ A value of zero disables the filter.
+
+What: /sys/.../events/in_accel_thresh_rising_high_pass_filter_3db
+What: /sys/.../events/in_anglvel_thresh_rising_high_pass_filter_3db
+What: /sys/.../events/in_magn_thresh_rising_high_pass_filter_3db
+KernelVersion: 4.2
+Contact: linux-iio@vger.kernel.org
+Description:
+ If a high pass filter can be applied to the event generation
+ this property gives its 3db frequency in Hz.
+ A value of zero disables the filter.
+
What: /sys/.../events/in_activity_still_thresh_rising_en
What: /sys/.../events/in_activity_still_thresh_falling_en
What: /sys/.../events/in_activity_walking_thresh_rising_en
@@ -1016,6 +1073,10 @@ What: /sys/.../iio:deviceX/scan_elements/in_timestamp_en
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_en
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_en
What: /sys/.../iio:deviceX/scan_elements/in_voltageY-voltageZ_en
+What: /sys/.../iio:deviceX/scan_elements/in_voltageY_i_en
+What: /sys/.../iio:deviceX/scan_elements/in_voltageY_q_en
+What: /sys/.../iio:deviceX/scan_elements/in_voltage_i_en
+What: /sys/.../iio:deviceX/scan_elements/in_voltage_q_en
What: /sys/.../iio:deviceX/scan_elements/in_incli_x_en
What: /sys/.../iio:deviceX/scan_elements/in_incli_y_en
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_en
@@ -1034,6 +1095,10 @@ What: /sys/.../iio:deviceX/scan_elements/in_incli_type
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_type
What: /sys/.../iio:deviceX/scan_elements/in_voltage_type
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_type
+What: /sys/.../iio:deviceX/scan_elements/in_voltageY_i_type
+What: /sys/.../iio:deviceX/scan_elements/in_voltageY_q_type
+What: /sys/.../iio:deviceX/scan_elements/in_voltage_i_type
+What: /sys/.../iio:deviceX/scan_elements/in_voltage_q_type
What: /sys/.../iio:deviceX/scan_elements/in_timestamp_type
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_type
What: /sys/.../iio:deviceX/scan_elements/in_pressure_type
@@ -1071,6 +1136,10 @@ Description:
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_index
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_index
+What: /sys/.../iio:deviceX/scan_elements/in_voltageY_i_index
+What: /sys/.../iio:deviceX/scan_elements/in_voltageY_q_index
+What: /sys/.../iio:deviceX/scan_elements/in_voltage_i_index
+What: /sys/.../iio:deviceX/scan_elements/in_voltage_q_index
What: /sys/.../iio:deviceX/scan_elements/in_accel_x_index
What: /sys/.../iio:deviceX/scan_elements/in_accel_y_index
What: /sys/.../iio:deviceX/scan_elements/in_accel_z_index
@@ -1230,6 +1299,8 @@ Description:
or without compensation from tilt sensors.
What: /sys/bus/iio/devices/iio:deviceX/in_currentX_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_currentX_i_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_currentX_q_raw
KernelVersion: 3.18
Contact: linux-iio@vger.kernel.org
Description:
@@ -1238,6 +1309,11 @@ Description:
present, output should be considered as processed with the
unit in milliamps.
+ Channels with 'i' and 'q' modifiers always exist in pairs and both
+ channels refer to the same signal. The 'i' channel contains the in-phase
+ component of the signal while the 'q' channel contains the quadrature
+ component.
+
What: /sys/.../iio:deviceX/in_energy_en
What: /sys/.../iio:deviceX/in_distance_en
What: /sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_en
@@ -1364,3 +1440,26 @@ Description:
hwfifo_watermak_min but not equal to any of the values in this
list, the driver will chose an appropriate value for the
hardware fifo watermark level.
+
+What: /sys/bus/iio/devices/iio:deviceX/in_temp_calibemissivity
+What: /sys/bus/iio/devices/iio:deviceX/in_tempX_calibemissivity
+What: /sys/bus/iio/devices/iio:deviceX/in_temp_object_calibemissivity
+What: /sys/bus/iio/devices/iio:deviceX/in_tempX_object_calibemissivity
+KernelVersion: 4.1
+Contact: linux-iio@vger.kernel.org
+Description:
+ The emissivity ratio of the surface in the field of view of the
+ contactless temperature sensor. Emissivity varies from 0 to 1,
+ with 1 being the emissivity of a black body.
+
+What: /sys/bus/iio/devices/iio:deviceX/in_magn_x_oversampling_ratio
+What: /sys/bus/iio/devices/iio:deviceX/in_magn_y_oversampling_ratio
+What: /sys/bus/iio/devices/iio:deviceX/in_magn_z_oversampling_ratio
+KernelVersion: 4.2
+Contact: linux-iio@vger.kernel.org
+Description:
+ Hardware applied number of measurements for acquiring one
+ data point. The HW will do <type>[_name]_oversampling_ratio
+ measurements and return the average value as output data. Each
+ value resulted from <type>[_name]_oversampling_ratio measurements
+ is considered as one sample for <type>[_name]_sampling_frequency.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-vf610 b/Documentation/ABI/testing/sysfs-bus-iio-vf610
new file mode 100644
index 000000000000..ecbc1f4af921
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-vf610
@@ -0,0 +1,7 @@
+What: /sys/bus/iio/devices/iio:deviceX/conversion_mode
+KernelVersion: 4.2
+Contact: linux-iio@vger.kernel.org
+Description:
+ Specifies the hardware conversion mode used. The three
+ available modes are "normal", "high-speed" and "low-power",
+ where the last is the default mode.
diff --git a/Documentation/ABI/testing/sysfs-bus-mei b/Documentation/ABI/testing/sysfs-bus-mei
index 2066f0bbd453..20e4d1638bac 100644
--- a/Documentation/ABI/testing/sysfs-bus-mei
+++ b/Documentation/ABI/testing/sysfs-bus-mei
@@ -4,4 +4,18 @@ KernelVersion: 3.10
Contact: Samuel Ortiz <sameo@linux.intel.com>
linux-mei@linux.intel.com
Description: Stores the same MODALIAS value emitted by uevent
- Format: mei:<mei device name>
+ Format: mei:<mei device name>:<device uuid>:
+
+What: /sys/bus/mei/devices/.../name
+Date: May 2015
+KernelVersion: 4.2
+Contact: Tomas Winkler <tomas.winkler@intel.com>
+Description: Stores mei client device name
+ Format: string
+
+What: /sys/bus/mei/devices/.../uuid
+Date: May 2015
+KernelVersion: 4.2
+Contact: Tomas Winkler <tomas.winkler@intel.com>
+Description: Stores mei client device uuid
+ Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
diff --git a/Documentation/ABI/testing/sysfs-bus-pci-drivers-janz-cmodio b/Documentation/ABI/testing/sysfs-bus-pci-drivers-janz-cmodio
new file mode 100644
index 000000000000..4d08f28dc871
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-pci-drivers-janz-cmodio
@@ -0,0 +1,8 @@
+What: /sys/bus/pci/drivers/janz-cmodio/.../modulbus_number
+Date: May 2010
+KernelVersion: 2.6.35
+Contact: Ira W. Snyder <ira.snyder@gmail.com>
+Description:
+ Value representing the HEX switch S2 of the janz carrier board CMOD-IO or CAN-PCI2
+
+ Read-only: value of the configuration switch (0..15)
diff --git a/Documentation/ABI/testing/sysfs-bus-usb-lvstest b/Documentation/ABI/testing/sysfs-bus-usb-lvstest
index aae68fc2d842..5151290cf8e7 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb-lvstest
+++ b/Documentation/ABI/testing/sysfs-bus-usb-lvstest
@@ -4,14 +4,14 @@ driver is bound with root hub device.
What: /sys/bus/usb/devices/.../get_dev_desc
Date: March 2014
-Contact: Pratyush Anand <pratyush.anand@st.com>
+Contact: Pratyush Anand <pratyush.anand@gmail.com>
Description:
Write to this node to issue "Get Device Descriptor"
for Link Layer Validation device. It is needed for TD.7.06.
What: /sys/bus/usb/devices/.../u1_timeout
Date: March 2014
-Contact: Pratyush Anand <pratyush.anand@st.com>
+Contact: Pratyush Anand <pratyush.anand@gmail.com>
Description:
Set "U1 timeout" for the downstream port where Link Layer
Validation device is connected. Timeout value must be between 0
@@ -19,7 +19,7 @@ Description:
What: /sys/bus/usb/devices/.../u2_timeout
Date: March 2014
-Contact: Pratyush Anand <pratyush.anand@st.com>
+Contact: Pratyush Anand <pratyush.anand@gmail.com>
Description:
Set "U2 timeout" for the downstream port where Link Layer
Validation device is connected. Timeout value must be between 0
@@ -27,21 +27,21 @@ Description:
What: /sys/bus/usb/devices/.../hot_reset
Date: March 2014
-Contact: Pratyush Anand <pratyush.anand@st.com>
+Contact: Pratyush Anand <pratyush.anand@gmail.com>
Description:
Write to this node to issue "Reset" for Link Layer Validation
device. It is needed for TD.7.29, TD.7.31, TD.7.34 and TD.7.35.
What: /sys/bus/usb/devices/.../u3_entry
Date: March 2014
-Contact: Pratyush Anand <pratyush.anand@st.com>
+Contact: Pratyush Anand <pratyush.anand@gmail.com>
Description:
Write to this node to issue "U3 entry" for Link Layer
Validation device. It is needed for TD.7.35 and TD.7.36.
What: /sys/bus/usb/devices/.../u3_exit
Date: March 2014
-Contact: Pratyush Anand <pratyush.anand@st.com>
+Contact: Pratyush Anand <pratyush.anand@gmail.com>
Description:
Write to this node to issue "U3 exit" for Link Layer
Validation device. It is needed for TD.7.36.
diff --git a/Documentation/ABI/testing/sysfs-class-cxl b/Documentation/ABI/testing/sysfs-class-cxl
index d46bba801aac..acfe9df83139 100644
--- a/Documentation/ABI/testing/sysfs-class-cxl
+++ b/Documentation/ABI/testing/sysfs-class-cxl
@@ -6,6 +6,17 @@ Example: The real path of the attribute /sys/class/cxl/afu0.0s/irqs_max is
Slave contexts (eg. /sys/class/cxl/afu0.0s):
+What: /sys/class/cxl/<afu>/afu_err_buf
+Date: September 2014
+Contact: linuxppc-dev@lists.ozlabs.org
+Description: read only
+ AFU Error Buffer contents. The contents of this file are
+ application specific and depends on the AFU being used.
+ Applications interacting with the AFU can use this attribute
+ to know about the current error condition and take appropriate
+ action like logging the event etc.
+
+
What: /sys/class/cxl/<afu>/irqs_max
Date: September 2014
Contact: linuxppc-dev@lists.ozlabs.org
@@ -15,6 +26,7 @@ Description: read/write
that hardware can support (eg. 2037). Write values will limit
userspace applications to that many userspace interrupts. Must
be >= irqs_min.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>/irqs_min
Date: September 2014
@@ -24,6 +36,7 @@ Description: read only
userspace must request on a CXL_START_WORK ioctl. Userspace may
omit the num_interrupts field in the START_WORK IOCTL to get
this minimum automatically.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>/mmio_size
Date: September 2014
@@ -31,6 +44,7 @@ Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
Decimal value of the size of the MMIO space that may be mmaped
by userspace.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>/modes_supported
Date: September 2014
@@ -38,6 +52,7 @@ Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
List of the modes this AFU supports. One per line.
Valid entries are: "dedicated_process" and "afu_directed"
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>/mode
Date: September 2014
@@ -46,6 +61,7 @@ Description: read/write
The current mode the AFU is using. Will be one of the modes
given in modes_supported. Writing will change the mode
provided that no user contexts are attached.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>/prefault_mode
@@ -59,6 +75,7 @@ Description: read/write
descriptor as an effective address and
prefault what it points to.
all: all segments process calling START_WORK maps.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>/reset
Date: September 2014
@@ -66,12 +83,14 @@ Contact: linuxppc-dev@lists.ozlabs.org
Description: write only
Writing 1 here will reset the AFU provided there are not
contexts active on the AFU.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>/api_version
Date: September 2014
Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
Decimal value of the current version of the kernel/user API.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>/api_version_compatible
Date: September 2014
@@ -79,6 +98,7 @@ Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
Decimal value of the the lowest version of the userspace API
this this kernel supports.
+Users: https://github.com/ibm-capi/libcxl
AFU configuration records (eg. /sys/class/cxl/afu0.0/cr0):
@@ -92,6 +112,7 @@ Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
Hexadecimal value of the vendor ID found in this AFU
configuration record.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>/cr<config num>/device
Date: February 2015
@@ -99,6 +120,7 @@ Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
Hexadecimal value of the device ID found in this AFU
configuration record.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>/cr<config num>/class
Date: February 2015
@@ -106,6 +128,7 @@ Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
Hexadecimal value of the class code found in this AFU
configuration record.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>/cr<config num>/config
Date: February 2015
@@ -115,6 +138,7 @@ Description: read only
record. The format is expected to match the either the standard
or extended configuration space defined by the PCIe
specification.
+Users: https://github.com/ibm-capi/libcxl
@@ -126,18 +150,21 @@ Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
Decimal value of the size of the MMIO space that may be mmaped
by userspace. This includes all slave contexts space also.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>m/pp_mmio_len
Date: September 2014
Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
Decimal value of the Per Process MMIO space length.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<afu>m/pp_mmio_off
Date: September 2014
Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
Decimal value of the Per Process MMIO space offset.
+Users: https://github.com/ibm-capi/libcxl
Card info (eg. /sys/class/cxl/card0)
@@ -147,12 +174,14 @@ Date: September 2014
Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
Identifies the CAIA Version the card implements.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<card>/psl_revision
Date: September 2014
Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
Identifies the revision level of the PSL.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<card>/base_image
Date: September 2014
@@ -162,6 +191,7 @@ Description: read only
that support loadable PSLs. For FPGAs this field identifies
the image contained in the on-adapter flash which is loaded
during the initial program load.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<card>/image_loaded
Date: September 2014
@@ -169,6 +199,7 @@ Contact: linuxppc-dev@lists.ozlabs.org
Description: read only
Will return "user" or "factory" depending on the image loaded
onto the card.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<card>/load_image_on_perst
Date: December 2014
@@ -183,6 +214,7 @@ Description: read/write
user or factory image to be loaded.
Default is to reload on PERST whichever image the card has
loaded.
+Users: https://github.com/ibm-capi/libcxl
What: /sys/class/cxl/<card>/reset
Date: October 2014
@@ -190,3 +222,4 @@ Contact: linuxppc-dev@lists.ozlabs.org
Description: write only
Writing 1 will issue a PERST to card which may cause the card
to reload the FPGA depending on load_image_on_perst.
+Users: https://github.com/ibm-capi/libcxl
diff --git a/Documentation/ABI/testing/sysfs-class-net b/Documentation/ABI/testing/sysfs-class-net
index 5ecfd72ba684..668604fc8e06 100644
--- a/Documentation/ABI/testing/sysfs-class-net
+++ b/Documentation/ABI/testing/sysfs-class-net
@@ -39,6 +39,25 @@ Description:
Format is a string, e.g: 00:11:22:33:44:55 for an Ethernet MAC
address.
+What: /sys/class/net/<bridge iface>/bridge/group_fwd_mask
+Date: January 2012
+KernelVersion: 3.2
+Contact: netdev@vger.kernel.org
+Description:
+ Bitmask to allow forwarding of link local frames with address
+ 01-80-C2-00-00-0X on a bridge device. Only values that set bits
+ not matching BR_GROUPFWD_RESTRICTED in net/bridge/br_private.h
+ allowed.
+ Default value 0 does not forward any link local frames.
+
+ Restricted bits:
+ 0: 01-80-C2-00-00-00 Bridge Group Address used for STP
+ 1: 01-80-C2-00-00-01 (MAC Control) 802.3 used for MAC PAUSE
+ 2: 01-80-C2-00-00-02 (Link Aggregation) 802.3ad
+
+ Any values not setting these bits can be used. Take special
+ care when forwarding control frames e.g. 802.1X-PAE or LLDP.
+
What: /sys/class/net/<iface>/broadcast
Date: April 2005
KernelVersion: 2.6.12
diff --git a/Documentation/ABI/testing/sysfs-class-net-janz-ican3 b/Documentation/ABI/testing/sysfs-class-net-janz-ican3
new file mode 100644
index 000000000000..fdbc03a2b8f8
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-net-janz-ican3
@@ -0,0 +1,19 @@
+What: /sys/class/net/<iface>/termination
+Date: May 2010
+KernelVersion: 2.6.35
+Contact: Ira W. Snyder <ira.snyder@gmail.com>
+Description:
+ Value representing the can bus termination
+
+ Default: 1 (termination active)
+ Reading: get actual termination state
+ Writing: set actual termination state (0=no termination, 1=termination active)
+
+What: /sys/class/net/<iface>/fwinfo
+Date: May 2015
+KernelVersion: 3.19
+Contact: Andreas Gröger <andreas24groeger@gmail.com>
+Description:
+ Firmware stamp of ican3 module
+ Read-only: 32 byte string identification of the ICAN3 module
+ (known values: "JANZ-ICAN3 ICANOS 1.xx", "JANZ-ICAN3 CAL/CANopen 1.xx")
diff --git a/Documentation/ABI/testing/sysfs-class-scsi_tape b/Documentation/ABI/testing/sysfs-class-scsi_tape
new file mode 100644
index 000000000000..9be398b87ee9
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-scsi_tape
@@ -0,0 +1,109 @@
+What: /sys/class/scsi_tape/*/stats/in_flight
+Date: Apr 2015
+KernelVersion: 4.2
+Contact: Shane Seymour <shane.seymour@hp.com>
+Description:
+ Show the number of I/Os currently in-flight between the st
+ module and the SCSI mid-layer.
+Users:
+
+
+What: /sys/class/scsi_tape/*/stats/io_ns
+Date: Apr 2015
+KernelVersion: 4.2
+Contact: Shane Seymour <shane.seymour@hp.com>
+Description:
+ Shows the total amount of time spent waiting for all I/O
+ to and from the tape drive to complete. This includes all
+ reads, writes, and other SCSI commands issued to the tape
+ drive. An example of other SCSI commands would be tape
+ movement such as a rewind when a rewind tape device is
+ closed. This item is measured in nanoseconds.
+
+ To determine the amount of time spent waiting for other I/O
+ to complete subtract read_ns and write_ns from this value.
+Users:
+
+
+What: /sys/class/scsi_tape/*/stats/other_cnt
+Date: Apr 2015
+KernelVersion: 4.2
+Contact: Shane Seymour <shane.seymour@hp.com>
+Description:
+ The number of I/O requests issued to the tape drive other
+ than SCSI read/write requests.
+Users:
+
+
+What: /sys/class/scsi_tape/*/stats/read_byte_cnt
+Date: Apr 2015
+KernelVersion: 4.2
+Contact: Shane Seymour <shane.seymour@hp.com>
+Description:
+ Shows the total number of bytes requested from the tape drive.
+ This value is presented in bytes because tape drives support
+ variable length block sizes.
+Users:
+
+
+What: /sys/class/scsi_tape/*/stats/read_cnt
+Date: Apr 2015
+KernelVersion: 4.2
+Contact: Shane Seymour <shane.seymour@hp.com>
+Description:
+ Shows the total number of read requests issued to the tape
+ drive.
+Users:
+
+
+What: /sys/class/scsi_tape/*/stats/read_ns
+Date: Apr 2015
+KernelVersion: 4.2
+Contact: Shane Seymour <shane.seymour@hp.com>
+Description:
+ Shows the total amount of time in nanoseconds waiting for
+ read I/O requests to complete.
+Users:
+
+
+What: /sys/class/scsi_tape/*/stats/write_byte_cnt
+Date: Apr 2015
+KernelVersion: 4.2
+Contact: Shane Seymour <shane.seymour@hp.com>
+Description:
+ Shows the total number of bytes written to the tape drive.
+ This value is presented in bytes because tape drives support
+ variable length block sizes.
+Users:
+
+
+What: /sys/class/scsi_tape/*/stats/write_cnt
+Date: Apr 2015
+KernelVersion: 4.2
+Contact: Shane Seymour <shane.seymour@hp.com>
+Description:
+ Shows the total number of write requests issued to the tape
+ drive.
+Users:
+
+
+What: /sys/class/scsi_tape/*/stats/write_ms
+Date: Apr 2015
+KernelVersion: 4.2
+Contact: Shane Seymour <shane.seymour@hp.com>
+Description:
+ Shows the total amount of time in nanoseconds waiting for
+ write I/O requests to complete.
+Users:
+
+
+What: /sys/class/scsi_tape/*/stats/resid_cnt
+Date: Apr 2015
+KernelVersion: 4.2
+Contact: Shane Seymour <shane.seymour@hp.com>
+Description:
+ Shows the number of times we found that a residual >0
+ was found when the SCSI midlayer indicated that there was
+ an error. For reads this may be a case of someone issuing
+ reads greater than the block size.
+Users:
diff --git a/Documentation/ABI/testing/sysfs-class-zram b/Documentation/ABI/testing/sysfs-class-zram
new file mode 100644
index 000000000000..48ddacbe0e69
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-zram
@@ -0,0 +1,24 @@
+What: /sys/class/zram-control/
+Date: August 2015
+KernelVersion: 4.2
+Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Description:
+ The zram-control/ class sub-directory belongs to zram
+ device class
+
+What: /sys/class/zram-control/hot_add
+Date: August 2015
+KernelVersion: 4.2
+Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Description:
+ RO attribute. Read operation will cause zram to add a new
+ device and return its device id back to user (so one can
+ use /dev/zram<id>), or error code.
+
+What: /sys/class/zram-control/hot_remove
+Date: August 2015
+KernelVersion: 4.2
+Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Description:
+ WO attribute. Remove a specific /dev/zramX device, where X
+ is a device_id provided by user.
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index da95513571ea..b683e8ee69ec 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -243,7 +243,7 @@ Description: Parameters for the CPU cache attributes
coherency_line_size: the minimum amount of data in bytes that gets
transferred from memory to cache
- level: the cache hierarcy in the multi-level cache configuration
+ level: the cache hierarchy in the multi-level cache configuration
number_of_sets: total number of sets in the cache, a set is a
collection of cache lines with the same cache index
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
index b3f6a2ac5007..db197a879580 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
+++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
@@ -1,7 +1,7 @@
-What: /sys/module/hid_logitech/drivers/hid:logitech/<dev>/range.
+What: /sys/bus/hid/drivers/logitech/<dev>/range
Date: July 2011
KernelVersion: 3.2
-Contact: Michal Malý <madcatxster@gmail.com>
+Contact: Michal Malý <madcatxster@devoid-pointer.net>
Description: Display minimum, maximum and current range of the steering
wheel. Writing a value within min and max boundaries sets the
range of the wheel.
@@ -9,7 +9,7 @@ Description: Display minimum, maximum and current range of the steering
What: /sys/bus/hid/drivers/logitech/<dev>/alternate_modes
Date: Feb 2015
KernelVersion: 4.1
-Contact: Michal Malý <madcatxster@gmail.com>
+Contact: Michal Malý <madcatxster@devoid-pointer.net>
Description: Displays a set of alternate modes supported by a wheel. Each
mode is listed as follows:
Tag: Mode Name
@@ -45,7 +45,7 @@ Description: Displays a set of alternate modes supported by a wheel. Each
What: /sys/bus/hid/drivers/logitech/<dev>/real_id
Date: Feb 2015
KernelVersion: 4.1
-Contact: Michal Malý <madcatxster@gmail.com>
+Contact: Michal Malý <madcatxster@devoid-pointer.net>
Description: Displays the real model of the wheel regardless of any
alternate mode the wheel might be switched to.
It is a read-only value.
diff --git a/Documentation/ABI/testing/sysfs-firmware-dmi b/Documentation/ABI/testing/sysfs-firmware-dmi-entries
index c78f9ab01e56..210ad44b95a5 100644
--- a/Documentation/ABI/testing/sysfs-firmware-dmi
+++ b/Documentation/ABI/testing/sysfs-firmware-dmi-entries
@@ -1,4 +1,4 @@
-What: /sys/firmware/dmi/
+What: /sys/firmware/dmi/entries/
Date: February 2011
Contact: Mike Waychison <mikew@google.com>
Description:
diff --git a/Documentation/ABI/testing/sysfs-firmware-dmi-tables b/Documentation/ABI/testing/sysfs-firmware-dmi-tables
new file mode 100644
index 000000000000..ff3cac8ed0bd
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-dmi-tables
@@ -0,0 +1,22 @@
+What: /sys/firmware/dmi/tables/
+Date: April 2015
+Contact: Ivan Khoronzhuk <ivan.khoronzhuk@globallogic.com>
+Description:
+ The firmware provides DMI structures as a packed list of
+ data referenced by a SMBIOS table entry point. The SMBIOS
+ entry point contains general information, like SMBIOS
+ version, DMI table size, etc. The structure, content and
+ size of SMBIOS entry point is dependent on SMBIOS version.
+ The format of SMBIOS entry point and DMI structures
+ can be read in SMBIOS specification.
+
+ The dmi/tables provides raw SMBIOS entry point and DMI tables
+ through sysfs as an alternative to utilities reading them
+ from /dev/mem. The raw SMBIOS entry point and DMI table are
+ presented as binary attributes and are accessible via:
+
+ /sys/firmware/dmi/tables/smbios_entry_point
+ /sys/firmware/dmi/tables/DMI
+
+ The complete DMI information can be obtained using these two
+ tables.
diff --git a/Documentation/ABI/testing/sysfs-firmware-efi b/Documentation/ABI/testing/sysfs-firmware-efi
index 05874da7ce80..e794eac32a90 100644
--- a/Documentation/ABI/testing/sysfs-firmware-efi
+++ b/Documentation/ABI/testing/sysfs-firmware-efi
@@ -18,3 +18,13 @@ Contact: Dave Young <dyoung@redhat.com>
Description: It shows the physical address of config table entry in the EFI
system table.
Users: Kexec
+
+What: /sys/firmware/efi/systab
+Date: April 2005
+Contact: linux-efi@vger.kernel.org
+Description: Displays the physical addresses of all EFI Configuration
+ Tables found via the EFI System Table. The order in
+ which the tables are printed forms an ABI and newer
+ versions are always printed first, i.e. ACPI20 comes
+ before ACPI.
+Users: dmidecode
diff --git a/Documentation/ABI/testing/sysfs-firmware-efi-esrt b/Documentation/ABI/testing/sysfs-firmware-efi-esrt
new file mode 100644
index 000000000000..6e431d1a4e79
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-efi-esrt
@@ -0,0 +1,81 @@
+What: /sys/firmware/efi/esrt/
+Date: February 2015
+Contact: Peter Jones <pjones@redhat.com>
+Description: Provides userland access to read the EFI System Resource Table
+ (ESRT), a catalog of firmware for which can be updated with
+ the UEFI UpdateCapsule mechanism described in section 7.5 of
+ the UEFI Standard.
+Users: fwupdate - https://github.com/rhinstaller/fwupdate
+
+What: /sys/firmware/efi/esrt/fw_resource_count
+Date: February 2015
+Contact: Peter Jones <pjones@redhat.com>
+Description: The number of entries in the ESRT
+
+What: /sys/firmware/efi/esrt/fw_resource_count_max
+Date: February 2015
+Contact: Peter Jones <pjones@redhat.com>
+Description: The maximum number of entries that /could/ be registered
+ in the allocation the table is currently in. This is
+ really only useful to the system firmware itself.
+
+What: /sys/firmware/efi/esrt/fw_resource_version
+Date: February 2015
+Contact: Peter Jones <pjones@redhat.com>
+Description: The version of the ESRT structure provided by the firmware.
+
+What: /sys/firmware/efi/esrt/entries/entry$N/
+Date: February 2015
+Contact: Peter Jones <pjones@redhat.com>
+Description: Each ESRT entry is identified by a GUID, and each gets a
+ subdirectory under entries/ .
+ example: /sys/firmware/efi/esrt/entries/entry0/
+
+What: /sys/firmware/efi/esrt/entries/entry$N/fw_type
+Date: February 2015
+Contact: Peter Jones <pjones@redhat.com>
+Description: What kind of firmware entry this is:
+ 0 - Unknown
+ 1 - System Firmware
+ 2 - Device Firmware
+ 3 - UEFI Driver
+
+What: /sys/firmware/efi/esrt/entries/entry$N/fw_class
+Date: February 2015
+Contact: Peter Jones <pjones@redhat.com>
+Description: This is the entry's guid, and will match the directory name.
+
+What: /sys/firmware/efi/esrt/entries/entry$N/fw_version
+Date: February 2015
+Contact: Peter Jones <pjones@redhat.com>
+Description: The version of the firmware currently installed. This is a
+ 32-bit unsigned integer.
+
+What: /sys/firmware/efi/esrt/entries/entry$N/lowest_supported_fw_version
+Date: February 2015
+Contact: Peter Jones <pjones@redhat.com>
+Description: The lowest version of the firmware that can be installed.
+
+What: /sys/firmware/efi/esrt/entries/entry$N/capsule_flags
+Date: February 2015
+Contact: Peter Jones <pjones@redhat.com>
+Description: Flags that must be passed to UpdateCapsule()
+
+What: /sys/firmware/efi/esrt/entries/entry$N/last_attempt_version
+Date: February 2015
+Contact: Peter Jones <pjones@redhat.com>
+Description: The last firmware version for which an update was attempted.
+
+What: /sys/firmware/efi/esrt/entries/entry$N/last_attempt_status
+Date: February 2015
+Contact: Peter Jones <pjones@redhat.com>
+Description: The result of the last firmware update attempt for the
+ firmware resource entry.
+ 0 - Success
+ 1 - Insufficient resources
+ 2 - Incorrect version
+ 3 - Invalid format
+ 4 - Authentication error
+ 5 - AC power event
+ 6 - Battery power event
+
diff --git a/Documentation/ABI/testing/sysfs-platform-twl4030-usb b/Documentation/ABI/testing/sysfs-platform-twl4030-usb
new file mode 100644
index 000000000000..512c51be64ae
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-twl4030-usb
@@ -0,0 +1,8 @@
+What: /sys/bus/platform/devices/*twl4030-usb/vbus
+Description:
+ Read-only status reporting if VBUS (approx 5V)
+ is being supplied by the USB bus.
+
+ Possible values: "on", "off".
+
+ Changes are notified via select/poll.
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index f4b78eafd92a..b713c35f8543 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -670,7 +670,7 @@ functions:
typeof(x) ret; \
ret = calc_ret(x); \
(ret); \
-)}
+})
ret is a common name for a local variable - __foo_ret is less likely
to collide with an existing variable.
diff --git a/Documentation/DMA-API-HOWTO.txt b/Documentation/DMA-API-HOWTO.txt
index 0f7afb2bb442..55b70b903ead 100644
--- a/Documentation/DMA-API-HOWTO.txt
+++ b/Documentation/DMA-API-HOWTO.txt
@@ -25,13 +25,18 @@ physical addresses. These are the addresses in /proc/iomem. The physical
address is not directly useful to a driver; it must use ioremap() to map
the space and produce a virtual address.
-I/O devices use a third kind of address: a "bus address" or "DMA address".
-If a device has registers at an MMIO address, or if it performs DMA to read
-or write system memory, the addresses used by the device are bus addresses.
-In some systems, bus addresses are identical to CPU physical addresses, but
-in general they are not. IOMMUs and host bridges can produce arbitrary
+I/O devices use a third kind of address: a "bus address". If a device has
+registers at an MMIO address, or if it performs DMA to read or write system
+memory, the addresses used by the device are bus addresses. In some
+systems, bus addresses are identical to CPU physical addresses, but in
+general they are not. IOMMUs and host bridges can produce arbitrary
mappings between physical and bus addresses.
+From a device's point of view, DMA uses the bus address space, but it may
+be restricted to a subset of that space. For example, even if a system
+supports 64-bit addresses for main memory and PCI BARs, it may use an IOMMU
+so devices only need to use 32-bit DMA addresses.
+
Here's a picture and some examples:
CPU CPU Bus
@@ -72,11 +77,11 @@ can use virtual address X to access the buffer, but the device itself
cannot because DMA doesn't go through the CPU virtual memory system.
In some simple systems, the device can do DMA directly to physical address
-Y. But in many others, there is IOMMU hardware that translates bus
+Y. But in many others, there is IOMMU hardware that translates DMA
addresses to physical addresses, e.g., it translates Z to Y. This is part
of the reason for the DMA API: the driver can give a virtual address X to
an interface like dma_map_single(), which sets up any required IOMMU
-mapping and returns the bus address Z. The driver then tells the device to
+mapping and returns the DMA address Z. The driver then tells the device to
do DMA to Z, and the IOMMU maps it to the buffer at address Y in system
RAM.
@@ -98,7 +103,7 @@ First of all, you should make sure
#include <linux/dma-mapping.h>
is in your driver, which provides the definition of dma_addr_t. This type
-can hold any valid DMA or bus address for the platform and should be used
+can hold any valid DMA address for the platform and should be used
everywhere you hold a DMA address returned from the DMA mapping functions.
What memory is DMA'able?
@@ -240,7 +245,7 @@ the case would look like this:
if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
using_dac = 1;
- consistent_using_dac = 1;
+ consistent_using_dac = 1;
} else if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
using_dac = 0;
consistent_using_dac = 0;
@@ -316,7 +321,7 @@ There are two types of DMA mappings:
Think of "consistent" as "synchronous" or "coherent".
The current default is to return consistent memory in the low 32
- bits of the bus space. However, for future compatibility you should
+ bits of the DMA space. However, for future compatibility you should
set the consistent mask even if this default is fine for your
driver.
@@ -353,7 +358,7 @@ There are two types of DMA mappings:
transfer, unmapped right after it (unless you use dma_sync_* below)
and for which hardware can optimize for sequential accesses.
- This of "streaming" as "asynchronous" or "outside the coherency
+ Think of "streaming" as "asynchronous" or "outside the coherency
domain".
Good examples of what to use streaming mappings for are:
@@ -403,7 +408,7 @@ dma_alloc_coherent() returns two values: the virtual address which you
can use to access it from the CPU and dma_handle which you pass to the
card.
-The CPU virtual address and the DMA bus address are both
+The CPU virtual address and the DMA address are both
guaranteed to be aligned to the smallest PAGE_SIZE order which
is greater than or equal to the requested size. This invariant
exists (for example) to guarantee that if you allocate a chunk
@@ -645,8 +650,8 @@ PLEASE NOTE: The 'nents' argument to the dma_unmap_sg call must be
dma_map_sg call.
Every dma_map_{single,sg}() call should have its dma_unmap_{single,sg}()
-counterpart, because the bus address space is a shared resource and
-you could render the machine unusable by consuming all bus addresses.
+counterpart, because the DMA address space is a shared resource and
+you could render the machine unusable by consuming all DMA addresses.
If you need to use the same streaming DMA region multiple times and touch
the data in between the DMA transfers, the buffer needs to be synced
diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
index 52088408668a..7eba542eff7c 100644
--- a/Documentation/DMA-API.txt
+++ b/Documentation/DMA-API.txt
@@ -18,10 +18,10 @@ Part I - dma_ API
To get the dma_ API, you must #include <linux/dma-mapping.h>. This
provides dma_addr_t and the interfaces described below.
-A dma_addr_t can hold any valid DMA or bus address for the platform. It
-can be given to a device to use as a DMA source or target. A CPU cannot
-reference a dma_addr_t directly because there may be translation between
-its physical address space and the bus address space.
+A dma_addr_t can hold any valid DMA address for the platform. It can be
+given to a device to use as a DMA source or target. A CPU cannot reference
+a dma_addr_t directly because there may be translation between its physical
+address space and the DMA address space.
Part Ia - Using large DMA-coherent buffers
------------------------------------------
@@ -42,7 +42,7 @@ It returns a pointer to the allocated region (in the processor's virtual
address space) or NULL if the allocation failed.
It also returns a <dma_handle> which may be cast to an unsigned integer the
-same width as the bus and given to the device as the bus address base of
+same width as the bus and given to the device as the DMA address base of
the region.
Note: consistent memory can be expensive on some platforms, and the
@@ -193,7 +193,7 @@ dma_map_single(struct device *dev, void *cpu_addr, size_t size,
enum dma_data_direction direction)
Maps a piece of processor virtual memory so it can be accessed by the
-device and returns the bus address of the memory.
+device and returns the DMA address of the memory.
The direction for both APIs may be converted freely by casting.
However the dma_ API uses a strongly typed enumerator for its
@@ -212,20 +212,20 @@ contiguous piece of memory. For this reason, memory to be mapped by
this API should be obtained from sources which guarantee it to be
physically contiguous (like kmalloc).
-Further, the bus address of the memory must be within the
+Further, the DMA address of the memory must be within the
dma_mask of the device (the dma_mask is a bit mask of the
-addressable region for the device, i.e., if the bus address of
-the memory ANDed with the dma_mask is still equal to the bus
+addressable region for the device, i.e., if the DMA address of
+the memory ANDed with the dma_mask is still equal to the DMA
address, then the device can perform DMA to the memory). To
ensure that the memory allocated by kmalloc is within the dma_mask,
the driver may specify various platform-dependent flags to restrict
-the bus address range of the allocation (e.g., on x86, GFP_DMA
-guarantees to be within the first 16MB of available bus addresses,
+the DMA address range of the allocation (e.g., on x86, GFP_DMA
+guarantees to be within the first 16MB of available DMA addresses,
as required by ISA devices).
Note also that the above constraints on physical contiguity and
dma_mask may not apply if the platform has an IOMMU (a device which
-maps an I/O bus address to a physical memory address). However, to be
+maps an I/O DMA address to a physical memory address). However, to be
portable, device driver writers may *not* assume that such an IOMMU
exists.
@@ -296,7 +296,7 @@ reduce current DMA mapping usage or delay and try again later).
dma_map_sg(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction direction)
-Returns: the number of bus address segments mapped (this may be shorter
+Returns: the number of DMA address segments mapped (this may be shorter
than <nents> passed in if some elements of the scatter/gather list are
physically or virtually adjacent and an IOMMU maps them with a single
entry).
@@ -340,7 +340,7 @@ must be the same as those and passed in to the scatter/gather mapping
API.
Note: <nents> must be the number you passed in, *not* the number of
-bus address entries returned.
+DMA address entries returned.
void
dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
@@ -507,7 +507,7 @@ it's asked for coherent memory for this device.
phys_addr is the CPU physical address to which the memory is currently
assigned (this will be ioremapped so the CPU can access the region).
-device_addr is the bus address the device needs to be programmed
+device_addr is the DMA address the device needs to be programmed
with to actually address this memory (this will be handed out as the
dma_addr_t in dma_alloc_coherent()).
diff --git a/Documentation/DocBook/crypto-API.tmpl b/Documentation/DocBook/crypto-API.tmpl
index efc8d90a9a3f..0992531ffefb 100644
--- a/Documentation/DocBook/crypto-API.tmpl
+++ b/Documentation/DocBook/crypto-API.tmpl
@@ -119,7 +119,7 @@
<para>
Note: The terms "transformation" and cipher algorithm are used
- interchangably.
+ interchangeably.
</para>
</sect1>
@@ -536,8 +536,8 @@
<para>
For other use cases of AEAD ciphers, the ASCII art applies as
- well, but the caller may not use the GIVCIPHER interface. In
- this case, the caller must generate the IV.
+ well, but the caller may not use the AEAD cipher with a separate
+ IV generator. In this case, the caller must generate the IV.
</para>
<para>
@@ -584,8 +584,8 @@ kernel crypto API | IPSEC Layer
|
+-----------+ |
| | (1)
-| givcipher | <----------------------------------- esp_output
-| (seqiv) | ---+
+| aead | <----------------------------------- esp_output
+| (seqniv) | ---+
+-----------+ |
| (2)
+-----------+ |
@@ -620,8 +620,8 @@ kernel crypto API | IPSEC Layer
<orderedlist>
<listitem>
<para>
- esp_output() invokes crypto_aead_givencrypt() to trigger an encryption
- operation of the GIVCIPHER implementation.
+ esp_output() invokes crypto_aead_encrypt() to trigger an encryption
+ operation of the AEAD cipher with IV generator.
</para>
<para>
@@ -1563,7 +1563,7 @@ struct sockaddr_alg sa = {
<sect1><title>Zero-Copy Interface</title>
<para>
- In addition to the send/write/read/recv system call familty, the AF_ALG
+ In addition to the send/write/read/recv system call family, the AF_ALG
interface can be accessed with the zero-copy interface of splice/vmsplice.
As the name indicates, the kernel tries to avoid a copy operation into
kernel space.
@@ -1669,9 +1669,19 @@ read(opfd, out, outlen);
</chapter>
<chapter id="API"><title>Programming Interface</title>
+ <para>
+ Please note that the kernel crypto API contains the AEAD givcrypt
+ API (crypto_aead_giv* and aead_givcrypt_* function calls in
+ include/crypto/aead.h). This API is obsolete and will be removed
+ in the future. To obtain the functionality of an AEAD cipher with
+ internal IV generation, use the IV generator as a regular cipher.
+ For example, rfc4106(gcm(aes)) is the AEAD cipher with external
+ IV generation and seqniv(rfc4106(gcm(aes))) implies that the kernel
+ crypto API generates the IV. Different IV generators are available.
+ </para>
<sect1><title>Block Cipher Context Data Structures</title>
!Pinclude/linux/crypto.h Block Cipher Context Data Structures
-!Finclude/linux/crypto.h aead_request
+!Finclude/crypto/aead.h aead_request
</sect1>
<sect1><title>Block Cipher Algorithm Definitions</title>
!Pinclude/linux/crypto.h Block Cipher Algorithm Definitions
@@ -1680,7 +1690,7 @@ read(opfd, out, outlen);
!Finclude/linux/crypto.h aead_alg
!Finclude/linux/crypto.h blkcipher_alg
!Finclude/linux/crypto.h cipher_alg
-!Finclude/linux/crypto.h rng_alg
+!Finclude/crypto/rng.h rng_alg
</sect1>
<sect1><title>Asynchronous Block Cipher API</title>
!Pinclude/linux/crypto.h Asynchronous Block Cipher API
@@ -1704,26 +1714,27 @@ read(opfd, out, outlen);
!Finclude/linux/crypto.h ablkcipher_request_set_crypt
</sect1>
<sect1><title>Authenticated Encryption With Associated Data (AEAD) Cipher API</title>
-!Pinclude/linux/crypto.h Authenticated Encryption With Associated Data (AEAD) Cipher API
-!Finclude/linux/crypto.h crypto_alloc_aead
-!Finclude/linux/crypto.h crypto_free_aead
-!Finclude/linux/crypto.h crypto_aead_ivsize
-!Finclude/linux/crypto.h crypto_aead_authsize
-!Finclude/linux/crypto.h crypto_aead_blocksize
-!Finclude/linux/crypto.h crypto_aead_setkey
-!Finclude/linux/crypto.h crypto_aead_setauthsize
-!Finclude/linux/crypto.h crypto_aead_encrypt
-!Finclude/linux/crypto.h crypto_aead_decrypt
+!Pinclude/crypto/aead.h Authenticated Encryption With Associated Data (AEAD) Cipher API
+!Finclude/crypto/aead.h crypto_alloc_aead
+!Finclude/crypto/aead.h crypto_free_aead
+!Finclude/crypto/aead.h crypto_aead_ivsize
+!Finclude/crypto/aead.h crypto_aead_authsize
+!Finclude/crypto/aead.h crypto_aead_blocksize
+!Finclude/crypto/aead.h crypto_aead_setkey
+!Finclude/crypto/aead.h crypto_aead_setauthsize
+!Finclude/crypto/aead.h crypto_aead_encrypt
+!Finclude/crypto/aead.h crypto_aead_decrypt
</sect1>
<sect1><title>Asynchronous AEAD Request Handle</title>
-!Pinclude/linux/crypto.h Asynchronous AEAD Request Handle
-!Finclude/linux/crypto.h crypto_aead_reqsize
-!Finclude/linux/crypto.h aead_request_set_tfm
-!Finclude/linux/crypto.h aead_request_alloc
-!Finclude/linux/crypto.h aead_request_free
-!Finclude/linux/crypto.h aead_request_set_callback
-!Finclude/linux/crypto.h aead_request_set_crypt
-!Finclude/linux/crypto.h aead_request_set_assoc
+!Pinclude/crypto/aead.h Asynchronous AEAD Request Handle
+!Finclude/crypto/aead.h crypto_aead_reqsize
+!Finclude/crypto/aead.h aead_request_set_tfm
+!Finclude/crypto/aead.h aead_request_alloc
+!Finclude/crypto/aead.h aead_request_free
+!Finclude/crypto/aead.h aead_request_set_callback
+!Finclude/crypto/aead.h aead_request_set_crypt
+!Finclude/crypto/aead.h aead_request_set_assoc
+!Finclude/crypto/aead.h aead_request_set_ad
</sect1>
<sect1><title>Synchronous Block Cipher API</title>
!Pinclude/linux/crypto.h Synchronous Block Cipher API
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 9765a4c0829d..c0312cbd023d 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -2439,6 +2439,18 @@ void intel_crt_init(struct drm_device *dev)
<title>Tile group</title>
!Pdrivers/gpu/drm/drm_crtc.c Tile group
</sect2>
+ <sect2>
+ <title>Bridges</title>
+ <sect3>
+ <title>Overview</title>
+!Pdrivers/gpu/drm/drm_bridge.c overview
+ </sect3>
+ <sect3>
+ <title>Default bridge callback sequence</title>
+!Pdrivers/gpu/drm/drm_bridge.c bridge callbacks
+ </sect3>
+!Edrivers/gpu/drm/drm_bridge.c
+ </sect2>
</sect1>
<!-- Internals: kms properties -->
@@ -2573,7 +2585,22 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >Description/Restrictions</td>
</tr>
<tr>
- <td rowspan="36" valign="top" >DRM</td>
+ <td rowspan="37" valign="top" >DRM</td>
+ <td valign="top" >Generic</td>
+ <td valign="top" >“rotationâ€</td>
+ <td valign="top" >BITMASK</td>
+ <td valign="top" >{ 0, "rotate-0" },
+ { 1, "rotate-90" },
+ { 2, "rotate-180" },
+ { 3, "rotate-270" },
+ { 4, "reflect-x" },
+ { 5, "reflect-y" }</td>
+ <td valign="top" >CRTC, Plane</td>
+ <td valign="top" >rotate-(degrees) rotates the image by the specified amount in degrees
+ in counter clockwise direction. reflect-x and reflect-y reflects the
+ image along the specified axis prior to rotation</td>
+ </tr>
+ <tr>
<td rowspan="5" valign="top" >Connector</td>
<td valign="top" >“EDIDâ€</td>
<td valign="top" >BLOB | IMMUTABLE</td>
@@ -2834,7 +2861,7 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >TBD</td>
</tr>
<tr>
- <td rowspan="21" valign="top" >i915</td>
+ <td rowspan="20" valign="top" >i915</td>
<td rowspan="2" valign="top" >Generic</td>
<td valign="top" >"Broadcast RGB"</td>
<td valign="top" >ENUM</td>
@@ -2850,14 +2877,6 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >TBD</td>
</tr>
<tr>
- <td rowspan="1" valign="top" >Plane</td>
- <td valign="top" >“rotationâ€</td>
- <td valign="top" >BITMASK</td>
- <td valign="top" >{ 0, "rotate-0" }, { 2, "rotate-180" }</td>
- <td valign="top" >Plane</td>
- <td valign="top" >TBD</td>
- </tr>
- <tr>
<td rowspan="17" valign="top" >SDVO-TV</td>
<td valign="top" >“modeâ€</td>
<td valign="top" >ENUM</td>
@@ -3365,19 +3384,7 @@ void intel_crt_init(struct drm_device *dev)
</tr>
<tr>
<td rowspan="2" valign="top" >omap</td>
- <td rowspan="2" valign="top" >Generic</td>
- <td valign="top" >“rotationâ€</td>
- <td valign="top" >BITMASK</td>
- <td valign="top" >{ 0, "rotate-0" },
- { 1, "rotate-90" },
- { 2, "rotate-180" },
- { 3, "rotate-270" },
- { 4, "reflect-x" },
- { 5, "reflect-y" }</td>
- <td valign="top" >CRTC, Plane</td>
- <td valign="top" >TBD</td>
- </tr>
- <tr>
+ <td valign="top" >Generic</td>
<td valign="top" >“zorderâ€</td>
<td valign="top" >RANGE</td>
<td valign="top" >Min=0, Max=3</td>
@@ -4067,7 +4074,7 @@ int num_ioctls;</synopsis>
<title>DPIO</title>
!Pdrivers/gpu/drm/i915/i915_reg.h DPIO
<table id="dpiox2">
- <title>Dual channel PHY (VLV/CHV)</title>
+ <title>Dual channel PHY (VLV/CHV/BXT)</title>
<tgroup cols="8">
<colspec colname="c0" />
<colspec colname="c1" />
@@ -4118,7 +4125,7 @@ int num_ioctls;</synopsis>
</tgroup>
</table>
<table id="dpiox1">
- <title>Single channel PHY (CHV)</title>
+ <title>Single channel PHY (CHV/BXT)</title>
<tgroup cols="4">
<colspec colname="c0" />
<colspec colname="c1" />
@@ -4153,6 +4160,12 @@ int num_ioctls;</synopsis>
</tgroup>
</table>
</sect2>
+
+ <sect2>
+ <title>CSR firmware support for DMC</title>
+!Pdrivers/gpu/drm/i915/intel_csr.c csr support for dmc
+!Idrivers/gpu/drm/i915/intel_csr.c
+ </sect2>
</sect1>
<sect1>
@@ -4204,7 +4217,6 @@ int num_ioctls;</synopsis>
!Idrivers/gpu/drm/i915/i915_gem_shrinker.c
</sect2>
</sect1>
-
<sect1>
<title> Tracing </title>
<para>
diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl
index e84f09467cd7..589b40cc5eb5 100644
--- a/Documentation/DocBook/kernel-hacking.tmpl
+++ b/Documentation/DocBook/kernel-hacking.tmpl
@@ -954,6 +954,8 @@ printk(KERN_INFO "my ip: %pI4\n", &amp;ipaddress);
<function>MODULE_LICENSE()</function> that specifies a GPL
compatible license. It implies that the function is considered
an internal implementation issue, and not really an interface.
+ Some maintainers and developers may however
+ require EXPORT_SYMBOL_GPL() when adding any new APIs or functionality.
</para>
</sect1>
</chapter>
diff --git a/Documentation/DocBook/media/.gitignore b/Documentation/DocBook/media/.gitignore
new file mode 100644
index 000000000000..e461c585fde8
--- /dev/null
+++ b/Documentation/DocBook/media/.gitignore
@@ -0,0 +1 @@
+!*.svg
diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile
index 8bf7c6191296..23996f88cd58 100644
--- a/Documentation/DocBook/media/Makefile
+++ b/Documentation/DocBook/media/Makefile
@@ -65,29 +65,31 @@ IOCTLS = \
$(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/video.h) \
$(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/media.h) \
$(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \
- VIDIOC_SUBDEV_G_FRAME_INTERVAL \
- VIDIOC_SUBDEV_S_FRAME_INTERVAL \
- VIDIOC_SUBDEV_ENUM_MBUS_CODE \
- VIDIOC_SUBDEV_ENUM_FRAME_SIZE \
- VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \
- VIDIOC_SUBDEV_G_SELECTION \
- VIDIOC_SUBDEV_S_SELECTION \
+
+DEFINES = \
+ $(shell perl -ne 'print "$$1 " if /\#define\s+(DTV_[^\s]+)\s+/' $(srctree)/include/uapi/linux/dvb/frontend.h) \
TYPES = \
- $(shell perl -ne 'print "$$1 " if /^typedef\s+[^\s]+\s+([^\s]+)\;/' $(srctree)/include/uapi/linux/videodev2.h) \
- $(shell perl -ne 'print "$$1 " if /^}\s+([a-z0-9_]+_t)/' $(srctree)/include/uapi/linux/dvb/frontend.h)
+ $(shell perl -ne 'print "$$1 " if /^typedef\s+.*\s+(\S+)\;/' $(srctree)/include/uapi/linux/videodev2.h) \
+ $(shell perl -ne 'print "$$1 " if /^typedef\s+.*\s+(\S+)\;/' $(srctree)/include/uapi/linux/dvb/frontend.h)
ENUMS = \
- $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/videodev2.h) \
- $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/dvb/audio.h) \
- $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/dvb/ca.h) \
- $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/dvb/dmx.h) \
- $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/dvb/frontend.h) \
- $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/dvb/net.h) \
- $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/dvb/video.h) \
- $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/media.h) \
- $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-mediabus.h) \
- $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-subdev.h)
+ $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' \
+ $(srctree)/include/uapi/linux/videodev2.h \
+ $(srctree)/include/uapi/linux/dvb/audio.h \
+ $(srctree)/include/uapi/linux/dvb/ca.h \
+ $(srctree)/include/uapi/linux/dvb/dmx.h \
+ $(srctree)/include/uapi/linux/dvb/frontend.h \
+ $(srctree)/include/uapi/linux/dvb/net.h \
+ $(srctree)/include/uapi/linux/dvb/video.h \
+ $(srctree)/include/uapi/linux/media.h \
+ $(srctree)/include/uapi/linux/v4l2-mediabus.h \
+ $(srctree)/include/uapi/linux/v4l2-subdev.h)
+
+ENUM_DEFS = \
+ $(shell perl -e 'open IN,"cat @ARGV| cpp -fpreprocessed |"; while (<IN>) { if ($$enum) {print "$$1\n" if (/\s*([A-Z]\S+)\b/); } $$enum = 0 if ($$enum && /^\}/); $$enum = 1 if(/^\s*enum\s/); }; close IN;' \
+ $(srctree)/include/uapi/linux/dvb/dmx.h \
+ $(srctree)/include/uapi/linux/dvb/frontend.h)
STRUCTS = \
$(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/videodev2.h) \
@@ -95,7 +97,7 @@ STRUCTS = \
$(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/ca.h) \
$(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/dmx.h) \
$(shell perl -ne 'print "$$1 " if (!/dtv\_cmds\_h/ && /^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/frontend.h) \
- $(shell perl -ne 'print "$$1 " if (/^struct\s+([A-Z][^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/net.h) \
+ $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/ && !/_old/)' $(srctree)/include/uapi/linux/dvb/net.h) \
$(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/video.h) \
$(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/media.h) \
$(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \
@@ -179,7 +181,6 @@ DOCUMENTED = \
-e "s/v4l2\-mpeg\-vbi\-ITV0/v4l2-mpeg-vbi-itv0-1/g"
DVB_DOCUMENTED = \
- -e "s/\(linkend\=\"\)FE_SET_PROPERTY/\1FE_GET_PROPERTY/g" \
-e "s,\(struct\s\+\)\([a-z0-9_]\+\)\(\s\+{\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
-e "s,\(}\s\+\)\([a-z0-9_]\+_t\+\),\1\<link linkend=\"\2\">\2\<\/link\>,g" \
-e "s,\(define\s\+\)\(DTV_[A-Z0-9_]\+\)\(\s\+[0-9]\+\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
@@ -188,14 +189,17 @@ DVB_DOCUMENTED = \
-e "s,\(audio-mixer\|audio-karaoke\|audio-status\|ca-slot-info\|ca-descr-info\|ca-caps\|ca-msg\|ca-descr\|ca-pid\|dmx-filter\|dmx-caps\|video-system\|video-highlight\|video-spu\|video-spu-palette\|video-navi-pack\)-t,\1,g" \
-e "s,DTV-ISDBT-LAYER[A-C],DTV-ISDBT-LAYER,g" \
-e "s,\(define\s\+\)\([A-Z0-9_]\+\)\(\s\+_IO\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
+ -e "s,\(define\s\+\)\(DTV_[A-Z0-9_]\+\)\(\s\+\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
-e "s,<link\s\+linkend=\".*\">\(__.*_OLD\)<\/link>,\1,g" \
+ -e "s/\(linkend\=\"\)FE_SET_PROPERTY/\1FE_GET_PROPERTY/g" \
+ -e "s,<link\s\+linkend=\".*\">\(DTV_ISDBS_TS_ID_LEGACY\|DTV_MAX_COMMAND\|DTV_IOCTL_MAX_MSGS\)<\/link>,\1,g" \
#
# Media targets and dependencies
#
install_media_images = \
- $(Q)-cp $(OBJIMGFILES) $(MEDIA_SRC_DIR)/v4l/*.svg $(MEDIA_OBJ_DIR)/media_api
+ $(Q)-cp $(OBJIMGFILES) $(MEDIA_SRC_DIR)/*.svg $(MEDIA_SRC_DIR)/v4l/*.svg $(MEDIA_OBJ_DIR)/media_api
$(MEDIA_OBJ_DIR)/%: $(MEDIA_SRC_DIR)/%.b64
$(Q)base64 -d $< >$@
@@ -243,9 +247,14 @@ $(MEDIA_OBJ_DIR)/dmx.h.xml: $(srctree)/include/uapi/linux/dvb/dmx.h $(MEDIA_OBJ_
@( \
echo "<programlisting>") > $@
@( \
+ for ident in $(ENUM_DEFS) ; do \
+ entity=`echo $$ident | tr _ -` ; \
+ r="$$r s/([^\w\-])$$ident([^\w\-])/\1\&$$entity\;\2/g;";\
+ done; \
expand --tabs=8 < $< | \
sed $(ESCAPE) $(DVB_DOCUMENTED) | \
- sed 's/i\.e\./&ie;/') >> $@
+ sed 's/i\.e\./&ie;/' | \
+ perl -ne "$$r print $$_;") >> $@
@( \
echo "</programlisting>") >> $@
@@ -254,9 +263,14 @@ $(MEDIA_OBJ_DIR)/frontend.h.xml: $(srctree)/include/uapi/linux/dvb/frontend.h $(
@( \
echo "<programlisting>") > $@
@( \
+ for ident in $(ENUM_DEFS) ; do \
+ entity=`echo $$ident | tr _ -` ; \
+ r="$$r s/([^\w\-])$$ident([^\w\-])/\1\&$$entity\;\2/g;";\
+ done; \
expand --tabs=8 < $< | \
sed $(ESCAPE) $(DVB_DOCUMENTED) | \
- sed 's/i\.e\./&ie;/') >> $@
+ sed 's/i\.e\./&ie;/' | \
+ perl -ne "$$r print $$_;") >> $@
@( \
echo "</programlisting>") >> $@
@@ -298,11 +312,22 @@ $(MEDIA_OBJ_DIR)/media-entities.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml
@( \
echo -e "\n<!-- Ioctls -->") >>$@
@( \
- for ident in $(IOCTLS) ; do \
+ for ident in `echo $(IOCTLS) | sed -e "s,VIDIOC_RESERVED,,"`; do\
entity=`echo $$ident | tr _ -` ; \
- id=`grep "<refname>$$ident" $(MEDIA_OBJ_DIR)/vidioc-*.xml $(MEDIA_OBJ_DIR)/media-ioc-*.xml | sed -r s,"^.*/(.*).xml.*","\1",` ; \
- echo "<!ENTITY $$entity \"<link" \
+ id=`grep -e "<refname>$$ident" -e "<section id=\"$$ident\"" $$(find $(MEDIA_SRC_DIR) -name *.xml -type f)| sed -r s,"^.*/(.*).xml.*","\1",` ; \
+ if [ "$$id" != "" ]; then echo "<!ENTITY $$entity \"<link" \
"linkend='$$id'><constant>$$ident</constant></link>\">" \
+ >>$@ ; else \
+ echo "Warning: undocumented ioctl: $$ident. Please document it at the media DocBook!" >&2; \
+ fi; \
+ done)
+ @( \
+ echo -e "\n<!-- Defines -->") >>$@
+ @( \
+ for ident in $(DEFINES) ; do \
+ entity=`echo $$ident | tr _ -` ; \
+ echo "<!ENTITY $$entity \"<link" \
+ "linkend='$$entity'><constant>$$ident</constant></link>\">" \
>>$@ ; \
done)
@( \
@@ -322,6 +347,15 @@ $(MEDIA_OBJ_DIR)/media-entities.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml
"linkend='$$entity'>$$ident</link>\">" >>$@ ; \
done)
@( \
+ echo -e "\n<!-- Enum definitions -->") >>$@
+ @( \
+ for ident in $(ENUM_DEFS) ; do \
+ entity=`echo $$ident | tr _ -` ; \
+ echo "<!ENTITY $$entity \"<link" \
+ "linkend='$$entity'><constant>$$ident</constant></link>\">" \
+ >>$@ ; \
+ done)
+ @( \
echo -e "\n<!-- Structures -->") >>$@
@( \
for ident in $(STRUCTS) ; do \
diff --git a/Documentation/DocBook/media/dvb/audio.xml b/Documentation/DocBook/media/dvb/audio.xml
index a7ea56c71a27..ea56743ddbe7 100644
--- a/Documentation/DocBook/media/dvb/audio.xml
+++ b/Documentation/DocBook/media/dvb/audio.xml
@@ -1,7 +1,7 @@
<title>DVB Audio Device</title>
<para>The DVB audio device controls the MPEG2 audio decoder of the DVB hardware. It
-can be accessed through <emphasis role="tt">/dev/dvb/adapter0/audio0</emphasis>. Data types and and
-ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/audio.h</emphasis> in your
+can be accessed through <constant>/dev/dvb/adapter?/audio?</constant>. Data types and and
+ioctl definitions can be accessed by including <constant>linux/dvb/audio.h</constant> in your
application.
</para>
<para>Please note that some DVB cards don&#8217;t have their own MPEG decoder, which results in
@@ -32,7 +32,7 @@ typedef enum {
</programlisting>
<para>AUDIO_SOURCE_DEMUX selects the demultiplexer (fed either by the frontend or the
DVR device) as the source of the video stream. If AUDIO_SOURCE_MEMORY
-is selected the stream comes from the application through the <emphasis role="tt">write()</emphasis> system
+is selected the stream comes from the application through the <constant>write()</constant> system
call.
</para>
diff --git a/Documentation/DocBook/media/dvb/ca.xml b/Documentation/DocBook/media/dvb/ca.xml
index 85eaf4fe2931..d0b07e763908 100644
--- a/Documentation/DocBook/media/dvb/ca.xml
+++ b/Documentation/DocBook/media/dvb/ca.xml
@@ -1,7 +1,7 @@
<title>DVB CA Device</title>
<para>The DVB CA device controls the conditional access hardware. It can be accessed through
-<emphasis role="tt">/dev/dvb/adapter0/ca0</emphasis>. Data types and and ioctl definitions can be accessed by
-including <emphasis role="tt">linux/dvb/ca.h</emphasis> in your application.
+<constant>/dev/dvb/adapter?/ca?</constant>. Data types and and ioctl definitions can be accessed by
+including <constant>linux/dvb/ca.h</constant> in your application.
</para>
<section id="ca_data_types">
diff --git a/Documentation/DocBook/media/dvb/demux.xml b/Documentation/DocBook/media/dvb/demux.xml
index c8683d66f059..34f2fb1cd601 100644
--- a/Documentation/DocBook/media/dvb/demux.xml
+++ b/Documentation/DocBook/media/dvb/demux.xml
@@ -1,33 +1,50 @@
<title>DVB Demux Device</title>
<para>The DVB demux device controls the filters of the DVB hardware/software. It can be
-accessed through <emphasis role="tt">/dev/adapter0/demux0</emphasis>. Data types and and ioctl definitions can be
-accessed by including <emphasis role="tt">linux/dvb/dmx.h</emphasis> in your application.
+accessed through <constant>/dev/adapter?/demux?</constant>. Data types and and ioctl definitions can be
+accessed by including <constant>linux/dvb/dmx.h</constant> in your application.
</para>
<section id="dmx_types">
<title>Demux Data Types</title>
<section id="dmx-output-t">
-<title>dmx_output_t</title>
-<programlisting>
-typedef enum
-{
- DMX_OUT_DECODER, /&#x22C6; Streaming directly to decoder. &#x22C6;/
- DMX_OUT_TAP, /&#x22C6; Output going to a memory buffer &#x22C6;/
- /&#x22C6; (to be retrieved via the read command).&#x22C6;/
- DMX_OUT_TS_TAP, /&#x22C6; Output multiplexed into a new TS &#x22C6;/
- /&#x22C6; (to be retrieved by reading from the &#x22C6;/
- /&#x22C6; logical DVR device). &#x22C6;/
- DMX_OUT_TSDEMUX_TAP /&#x22C6; Like TS_TAP but retrieved from the DMX device &#x22C6;/
-} dmx_output_t;
-</programlisting>
-<para><emphasis role="tt">DMX_OUT_TAP</emphasis> delivers the stream output to the demux device on which the ioctl is
-called.
-</para>
-<para><emphasis role="tt">DMX_OUT_TS_TAP</emphasis> routes output to the logical DVR device <emphasis role="tt">/dev/dvb/adapter0/dvr0</emphasis>,
-which delivers a TS multiplexed from all filters for which <emphasis role="tt">DMX_OUT_TS_TAP</emphasis> was
-specified.
-</para>
+<title>Output for the demux</title>
+
+<table pgwide="1" frame="none" id="dmx-output">
+ <title>enum dmx_output</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry align="char" id="DMX-OUT-DECODER">DMX_OUT_DECODER</entry>
+ <entry>Streaming directly to decoder.</entry>
+ </row><row>
+ <entry align="char" id="DMX-OUT-TAP">DMX_OUT_TAP</entry>
+ <entry>Output going to a memory buffer (to be retrieved via the
+ read command). Delivers the stream output to the demux
+ device on which the ioctl is called.</entry>
+ </row><row>
+ <entry align="char" id="DMX-OUT-TS-TAP">DMX_OUT_TS_TAP</entry>
+ <entry>Output multiplexed into a new TS (to be retrieved by
+ reading from the logical DVR device). Routes output to the
+ logical DVR device <constant>/dev/dvb/adapter?/dvr?</constant>,
+ which delivers a TS multiplexed from all filters for which
+ <constant>DMX_OUT_TS_TAP</constant> was specified.</entry>
+ </row><row>
+ <entry align="char" id="DMX-OUT-TSDEMUX-TAP">DMX_OUT_TSDEMUX_TAP</entry>
+ <entry>Like &DMX-OUT-TS-TAP; but retrieved from the DMX
+ device.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+
</section>
<section id="dmx-input-t">
diff --git a/Documentation/DocBook/media/dvb/dvbapi.xml b/Documentation/DocBook/media/dvb/dvbapi.xml
index 4c15396c67e5..858fd7d17104 100644
--- a/Documentation/DocBook/media/dvb/dvbapi.xml
+++ b/Documentation/DocBook/media/dvb/dvbapi.xml
@@ -28,13 +28,23 @@
<holder>Convergence GmbH</holder>
</copyright>
<copyright>
- <year>2009-2014</year>
+ <year>2009-2015</year>
<holder>Mauro Carvalho Chehab</holder>
</copyright>
<revhistory>
<!-- Put document revisions here, newest first. -->
<revision>
+ <revnumber>2.1.0</revnumber>
+ <date>2015-05-29</date>
+ <authorinitials>mcc</authorinitials>
+ <revremark>
+ DocBook improvements and cleanups, in order to document the
+ system calls on a more standard way and provide more description
+ about the current DVB API.
+ </revremark>
+</revision>
+<revision>
<revnumber>2.0.4</revnumber>
<date>2011-05-06</date>
<authorinitials>mcc</authorinitials>
@@ -95,18 +105,26 @@ Added ISDB-T test originally written by Patrick Boettcher
<chapter id="dvb_demux">
&sub-demux;
</chapter>
- <chapter id="dvb_video">
- &sub-video;
- </chapter>
- <chapter id="dvb_audio">
- &sub-audio;
- </chapter>
<chapter id="dvb_ca">
&sub-ca;
</chapter>
- <chapter id="dvb_net">
+ <chapter id="net">
&sub-net;
</chapter>
+ <chapter id="legacy_dvb_apis">
+ <title>DVB Deprecated APIs</title>
+ <para>The APIs described here are kept only for historical reasons. There's
+ just one driver for a very legacy hardware that uses this API. No
+ modern drivers should use it. Instead, audio and video should be using
+ the V4L2 and ALSA APIs, and the pipelines should be set using the
+ Media Controller API</para>
+ <section id="dvb_video">
+ &sub-video;
+ </section>
+ <section id="dvb_audio">
+ &sub-audio;
+ </section>
+ </chapter>
<chapter id="dvb_kdapi">
&sub-kdapi;
</chapter>
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
index 3018564ddfd9..08227d4e9150 100644
--- a/Documentation/DocBook/media/dvb/dvbproperty.xml
+++ b/Documentation/DocBook/media/dvb/dvbproperty.xml
@@ -1,14 +1,88 @@
-<section id="FE_GET_SET_PROPERTY">
-<title><constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></title>
-<para>This section describes the DVB version 5 extension of the DVB-API, also
-called "S2API", as this API were added to provide support for DVB-S2. It was
-designed to be able to replace the old frontend API. Yet, the DISEQC and
-the capability ioctls weren't implemented yet via the new way.</para>
-<para>The typical usage for the <constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant>
-API is to replace the ioctl's were the <link linkend="dvb-frontend-parameters">
-struct <constant>dvb_frontend_parameters</constant></link> were used.</para>
+<section id="frontend-properties">
+<title>DVB Frontend properties</title>
+<para>Tuning into a Digital TV physical channel and starting decoding it
+ requires changing a set of parameters, in order to control the
+ tuner, the demodulator, the Linear Low-noise Amplifier (LNA) and to set the
+ antenna subsystem via Satellite Equipment Control (SEC), on satellite
+ systems. The actual parameters are specific to each particular digital
+ TV standards, and may change as the digital TV specs evolves.</para>
+<para>In the past, the strategy used was to have a union with the parameters
+ needed to tune for DVB-S, DVB-C, DVB-T and ATSC delivery systems grouped
+ there. The problem is that, as the second generation standards appeared,
+ those structs were not big enough to contain the additional parameters.
+ Also, the union didn't have any space left to be expanded without breaking
+ userspace. So, the decision was to deprecate the legacy union/struct based
+ approach, in favor of a properties set approach.</para>
+
+<para>NOTE: on Linux DVB API version 3, setting a frontend were done via
+ <link linkend="dvb-frontend-parameters">struct <constant>dvb_frontend_parameters</constant></link>.
+ This got replaced on version 5 (also called "S2API", as this API were
+ added originally_enabled to provide support for DVB-S2), because the old
+ API has a very limited support to new standards and new hardware. This
+ section describes the new and recommended way to set the frontend, with
+ suppports all digital TV delivery systems.</para>
+
+<para>Example: with the properties based approach, in order to set the tuner
+ to a DVB-C channel at 651 kHz, modulated with 256-QAM, FEC 3/4 and symbol
+ rate of 5.217 Mbauds, those properties should be sent to
+ <link linkend="FE_GET_PROPERTY"><constant>FE_SET_PROPERTY</constant></link> ioctl:</para>
+ <itemizedlist>
+ <listitem><para>&DTV-DELIVERY-SYSTEM; = SYS_DVBC_ANNEX_A</para></listitem>
+ <listitem><para>&DTV-FREQUENCY; = 651000000</para></listitem>
+ <listitem><para>&DTV-MODULATION; = QAM_256</para></listitem>
+ <listitem><para>&DTV-INVERSION; = INVERSION_AUTO</para></listitem>
+ <listitem><para>&DTV-SYMBOL-RATE; = 5217000</para></listitem>
+ <listitem><para>&DTV-INNER-FEC; = FEC_3_4</para></listitem>
+ <listitem><para>&DTV-TUNE;</para></listitem>
+ </itemizedlist>
+
+<para>The code that would do the above is:</para>
+<programlisting>
+#include &lt;stdio.h&gt;
+#include &lt;fcntl.h&gt;
+#include &lt;sys/ioctl.h&gt;
+#include &lt;linux/dvb/frontend.h&gt;
+
+static struct dtv_property props[] = {
+ { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_A },
+ { .cmd = DTV_FREQUENCY, .u.data = 651000000 },
+ { .cmd = DTV_MODULATION, .u.data = QAM_256 },
+ { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
+ { .cmd = DTV_SYMBOL_RATE, .u.data = 5217000 },
+ { .cmd = DTV_INNER_FEC, .u.data = FEC_3_4 },
+ { .cmd = DTV_TUNE }
+};
+
+static struct dtv_properties dtv_prop = {
+ .num = 6, .props = props
+};
+
+int main(void)
+{
+ int fd = open("/dev/dvb/adapter0/frontend0", O_RDWR);
+
+ if (!fd) {
+ perror ("open");
+ return -1;
+ }
+ if (ioctl(fd, FE_SET_PROPERTY, &amp;dtv_prop) == -1) {
+ perror("ioctl");
+ return -1;
+ }
+ printf("Frontend set\n");
+ return 0;
+}
+</programlisting>
+
+<para>NOTE: While it is possible to directly call the Kernel code like the
+ above example, it is strongly recommended to use
+ <ulink url="http://linuxtv.org/docs/libdvbv5/index.html">libdvbv5</ulink>,
+ as it provides abstraction to work with the supported digital TV standards
+ and provides methods for usual operations like program scanning and to
+ read/write channel descriptor files.</para>
+
<section id="dtv-stats">
-<title>DTV stats type</title>
+<title>struct <structname>dtv_stats</structname></title>
<programlisting>
struct dtv_stats {
__u8 scale; /* enum fecap_scale_params type */
@@ -20,19 +94,19 @@ struct dtv_stats {
</programlisting>
</section>
<section id="dtv-fe-stats">
-<title>DTV stats type</title>
+<title>struct <structname>dtv_fe_stats</structname></title>
<programlisting>
#define MAX_DTV_STATS 4
struct dtv_fe_stats {
__u8 len;
- struct dtv_stats stat[MAX_DTV_STATS];
+ &dtv-stats; stat[MAX_DTV_STATS];
} __packed;
</programlisting>
</section>
<section id="dtv-property">
-<title>DTV property type</title>
+<title>struct <structname>dtv_property</structname></title>
<programlisting>
/* Reserved fields should be set to 0 */
@@ -41,7 +115,7 @@ struct dtv_property {
__u32 reserved[3];
union {
__u32 data;
- struct dtv_fe_stats st;
+ &dtv-fe-stats; st;
struct {
__u8 data[32];
__u32 len;
@@ -57,115 +131,19 @@ struct dtv_property {
</programlisting>
</section>
<section id="dtv-properties">
-<title>DTV properties type</title>
+<title>struct <structname>dtv_properties</structname></title>
<programlisting>
struct dtv_properties {
__u32 num;
- struct dtv_property *props;
+ &dtv-property; *props;
};
</programlisting>
</section>
-<section id="FE_GET_PROPERTY">
-<title>FE_GET_PROPERTY</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns one or more frontend properties. This call only
- requires read-only access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>,
- dtv_properties &#x22C6;props);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int num</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct dtv_property *props</para>
-</entry><entry
- align="char">
-<para>Points to the location where the front-end property commands are stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row>
- <entry align="char"><para>EOPNOTSUPP</para></entry>
- <entry align="char"><para>Property type not supported.</para></entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_SET_PROPERTY">
-<title>FE_SET_PROPERTY</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call sets one or more frontend properties. This call
- requires read/write access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
- dtv_properties &#x22C6;props);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int num</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct dtv_property *props</para>
-</entry><entry
- align="char">
-<para>Points to the location where the front-end property commands are stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row>
- <entry align="char"><para>EOPNOTSUPP</para></entry>
- <entry align="char"><para>Property type not supported.</para></entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
<section>
<title>Property types</title>
<para>
-On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
+On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY and FE_SET_PROPERTY</link>,
the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to
get/set up to 64 properties. The actual meaning of each property is described on the next sections.
</para>
@@ -193,7 +171,7 @@ get/set up to 64 properties. The actual meaning of each property is described on
<para>Central frequency of the channel.</para>
<para>Notes:</para>
- <para>1)For satellital delivery systems, it is measured in kHz.
+ <para>1)For satellite delivery systems, it is measured in kHz.
For the other ones, it is measured in Hz.</para>
<para>2)For ISDB-T, the channels are usually transmitted with an offset of 143kHz.
E.g. a valid frequency could be 474143 kHz. The stepping is bound to the bandwidth of
@@ -205,25 +183,78 @@ get/set up to 64 properties. The actual meaning of each property is described on
</section>
<section id="DTV-MODULATION">
<title><constant>DTV_MODULATION</constant></title>
-<para>Specifies the frontend modulation type for cable and satellite types. The modulation can be one of the types bellow:</para>
-<programlisting>
- typedef enum fe_modulation {
- QPSK,
- QAM_16,
- QAM_32,
- QAM_64,
- QAM_128,
- QAM_256,
- QAM_AUTO,
- VSB_8,
- VSB_16,
- PSK_8,
- APSK_16,
- APSK_32,
- DQPSK,
- QAM_4_NR,
- } fe_modulation_t;
-</programlisting>
+<para>Specifies the frontend modulation type for delivery systems that supports
+ more than one modulation type. The modulation can be one of the types
+ defined by &fe-modulation;.</para>
+
+
+<section id="fe-modulation-t">
+<title>Modulation property</title>
+
+<para>Most of the digital TV standards currently offers more than one possible
+ modulation (sometimes called as "constellation" on some standards). This
+ enum contains the values used by the Kernel. Please note that not all
+ modulations are supported by a given standard.</para>
+
+<table pgwide="1" frame="none" id="fe-modulation">
+ <title>enum fe_modulation</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="QPSK"><constant>QPSK</constant></entry>
+ <entry>QPSK modulation</entry>
+ </row><row>
+ <entry id="QAM-16"><constant>QAM_16</constant></entry>
+ <entry>16-QAM modulation</entry>
+ </row><row>
+ <entry id="QAM-32"><constant>QAM_32</constant></entry>
+ <entry>32-QAM modulation</entry>
+ </row><row>
+ <entry id="QAM-64"><constant>QAM_64</constant></entry>
+ <entry>64-QAM modulation</entry>
+ </row><row>
+ <entry id="QAM-128"><constant>QAM_128</constant></entry>
+ <entry>128-QAM modulation</entry>
+ </row><row>
+ <entry id="QAM-256"><constant>QAM_256</constant></entry>
+ <entry>256-QAM modulation</entry>
+ </row><row>
+ <entry id="QAM-AUTO"><constant>QAM_AUTO</constant></entry>
+ <entry>Autodetect QAM modulation</entry>
+ </row><row>
+ <entry id="VSB-8"><constant>VSB_8</constant></entry>
+ <entry>8-VSB modulation</entry>
+ </row><row>
+ <entry id="VSB-16"><constant>VSB_16</constant></entry>
+ <entry>16-VSB modulation</entry>
+ </row><row>
+ <entry id="PSK-8"><constant>PSK_8</constant></entry>
+ <entry>8-PSK modulation</entry>
+ </row><row>
+ <entry id="APSK-16"><constant>APSK_16</constant></entry>
+ <entry>16-APSK modulation</entry>
+ </row><row>
+ <entry id="APSK-32"><constant>APSK_32</constant></entry>
+ <entry>32-APSK modulation</entry>
+ </row><row>
+ <entry id="DQPSK"><constant>DQPSK</constant></entry>
+ <entry>DQPSK modulation</entry>
+ </row><row>
+ <entry id="QAM-4-NR"><constant>QAM_4_NR</constant></entry>
+ <entry>4-QAM-NR modulation</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+</section>
+
</section>
<section id="DTV-BANDWIDTH-HZ">
<title><constant>DTV_BANDWIDTH_HZ</constant></title>
@@ -253,19 +284,45 @@ get/set up to 64 properties. The actual meaning of each property is described on
</section>
<section id="DTV-INVERSION">
<title><constant>DTV_INVERSION</constant></title>
- <para>The Inversion field can take one of these values:
- </para>
- <programlisting>
- typedef enum fe_spectral_inversion {
- INVERSION_OFF,
- INVERSION_ON,
- INVERSION_AUTO
- } fe_spectral_inversion_t;
- </programlisting>
- <para>It indicates if spectral inversion should be presumed or not. In the automatic setting
- (<constant>INVERSION_AUTO</constant>) the hardware will try to figure out the correct setting by
- itself.
- </para>
+
+ <para>Specifies if the frontend should do spectral inversion or not.</para>
+
+<section id="fe-spectral-inversion-t">
+<title>enum fe_modulation: Frontend spectral inversion</title>
+
+<para>This parameter indicates if spectral inversion should be presumed or not.
+ In the automatic setting (<constant>INVERSION_AUTO</constant>) the hardware
+ will try to figure out the correct setting by itself. If the hardware
+ doesn't support, the DVB core will try to lock at the carrier first with
+ inversion off. If it fails, it will try to enable inversion.
+</para>
+
+<table pgwide="1" frame="none" id="fe-spectral-inversion">
+ <title>enum fe_modulation</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="INVERSION-OFF"><constant>INVERSION_OFF</constant></entry>
+ <entry>Don't do spectral band inversion.</entry>
+ </row><row>
+ <entry id="INVERSION-ON"><constant>INVERSION_ON</constant></entry>
+ <entry>Do spectral band inversion.</entry>
+ </row><row>
+ <entry id="INVERSION-AUTO"><constant>INVERSION_AUTO</constant></entry>
+ <entry>Autodetect spectral band inversion.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+</section>
+
</section>
<section id="DTV-DISEQC-MASTER">
<title><constant>DTV_DISEQC_MASTER</constant></title>
@@ -279,25 +336,64 @@ get/set up to 64 properties. The actual meaning of each property is described on
<title><constant>DTV_INNER_FEC</constant></title>
<para>Used cable/satellite transmissions. The acceptable values are:
</para>
- <programlisting>
-typedef enum fe_code_rate {
- FEC_NONE = 0,
- FEC_1_2,
- FEC_2_3,
- FEC_3_4,
- FEC_4_5,
- FEC_5_6,
- FEC_6_7,
- FEC_7_8,
- FEC_8_9,
- FEC_AUTO,
- FEC_3_5,
- FEC_9_10,
- FEC_2_5,
-} fe_code_rate_t;
- </programlisting>
- <para>which correspond to error correction rates of 1/2, 2/3, etc.,
- no error correction or auto detection.</para>
+<section id="fe-code-rate-t">
+<title>enum fe_code_rate: type of the Forward Error Correction.</title>
+
+<table pgwide="1" frame="none" id="fe-code-rate">
+ <title>enum fe_code_rate</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="FEC-NONE"><constant>FEC_NONE</constant></entry>
+ <entry>No Forward Error Correction Code</entry>
+ </row><row>
+ <entry id="FEC-AUTO"><constant>FEC_AUTO</constant></entry>
+ <entry>Autodetect Error Correction Code</entry>
+ </row><row>
+ <entry id="FEC-1-2"><constant>FEC_1_2</constant></entry>
+ <entry>Forward Error Correction Code 1/2</entry>
+ </row><row>
+ <entry id="FEC-2-3"><constant>FEC_2_3</constant></entry>
+ <entry>Forward Error Correction Code 2/3</entry>
+ </row><row>
+ <entry id="FEC-3-4"><constant>FEC_3_4</constant></entry>
+ <entry>Forward Error Correction Code 3/4</entry>
+ </row><row>
+ <entry id="FEC-4-5"><constant>FEC_4_5</constant></entry>
+ <entry>Forward Error Correction Code 4/5</entry>
+ </row><row>
+ <entry id="FEC-5-6"><constant>FEC_5_6</constant></entry>
+ <entry>Forward Error Correction Code 5/6</entry>
+ </row><row>
+ <entry id="FEC-6-7"><constant>FEC_6_7</constant></entry>
+ <entry>Forward Error Correction Code 6/7</entry>
+ </row><row>
+ <entry id="FEC-7-8"><constant>FEC_7_8</constant></entry>
+ <entry>Forward Error Correction Code 7/8</entry>
+ </row><row>
+ <entry id="FEC-8-9"><constant>FEC_8_9</constant></entry>
+ <entry>Forward Error Correction Code 8/9</entry>
+ </row><row>
+ <entry id="FEC-9-10"><constant>FEC_9_10</constant></entry>
+ <entry>Forward Error Correction Code 9/10</entry>
+ </row><row>
+ <entry id="FEC-2-5"><constant>FEC_2_5</constant></entry>
+ <entry>Forward Error Correction Code 2/5</entry>
+ </row><row>
+ <entry id="FEC-3-5"><constant>FEC_3_5</constant></entry>
+ <entry>Forward Error Correction Code 3/5</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+</section>
</section>
<section id="DTV-VOLTAGE">
<title><constant>DTV_VOLTAGE</constant></title>
@@ -305,12 +401,31 @@ typedef enum fe_code_rate {
the polarzation (horizontal/vertical). When using DiSEqC epuipment this
voltage has to be switched consistently to the DiSEqC commands as
described in the DiSEqC spec.</para>
- <programlisting>
- typedef enum fe_sec_voltage {
- SEC_VOLTAGE_13,
- SEC_VOLTAGE_18
- } fe_sec_voltage_t;
- </programlisting>
+
+<table pgwide="1" frame="none" id="fe-sec-voltage">
+ <title id="fe-sec-voltage-t">enum fe_sec_voltage</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry align="char" id="SEC-VOLTAGE-13"><constant>SEC_VOLTAGE_13</constant></entry>
+ <entry align="char">Set DC voltage level to 13V</entry>
+ </row><row>
+ <entry align="char" id="SEC-VOLTAGE-18"><constant>SEC_VOLTAGE_18</constant></entry>
+ <entry align="char">Set DC voltage level to 18V</entry>
+ </row><row>
+ <entry align="char" id="SEC-VOLTAGE-OFF"><constant>SEC_VOLTAGE_OFF</constant></entry>
+ <entry align="char">Don't send any voltage to the antenna</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
</section>
<section id="DTV-TONE">
<title><constant>DTV_TONE</constant></title>
@@ -321,13 +436,30 @@ typedef enum fe_code_rate {
<para>Sets DVB-S2 pilot</para>
<section id="fe-pilot-t">
<title>fe_pilot type</title>
- <programlisting>
-typedef enum fe_pilot {
- PILOT_ON,
- PILOT_OFF,
- PILOT_AUTO,
-} fe_pilot_t;
- </programlisting>
+<table pgwide="1" frame="none" id="fe-pilot">
+ <title>enum fe_pilot</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry align="char" id="PILOT-ON"><constant>PILOT_ON</constant></entry>
+ <entry align="char">Pilot tones enabled</entry>
+ </row><row>
+ <entry align="char" id="PILOT-OFF"><constant>PILOT_OFF</constant></entry>
+ <entry align="char">Pilot tones disabled</entry>
+ </row><row>
+ <entry align="char" id="PILOT-AUTO"><constant>PILOT_AUTO</constant></entry>
+ <entry align="char">Autodetect pilot tones</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
</section>
</section>
<section id="DTV-ROLLOFF">
@@ -336,14 +468,33 @@ typedef enum fe_pilot {
<section id="fe-rolloff-t">
<title>fe_rolloff type</title>
- <programlisting>
-typedef enum fe_rolloff {
- ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */
- ROLLOFF_20,
- ROLLOFF_25,
- ROLLOFF_AUTO,
-} fe_rolloff_t;
- </programlisting>
+<table pgwide="1" frame="none" id="fe-rolloff">
+ <title>enum fe_rolloff</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry align="char" id="ROLLOFF-35"><constant>ROLLOFF_35</constant></entry>
+ <entry align="char">Roloff factor: &alpha;=35%</entry>
+ </row><row>
+ <entry align="char" id="ROLLOFF-20"><constant>ROLLOFF_20</constant></entry>
+ <entry align="char">Roloff factor: &alpha;=20%</entry>
+ </row><row>
+ <entry align="char" id="ROLLOFF-25"><constant>ROLLOFF_25</constant></entry>
+ <entry align="char">Roloff factor: &alpha;=25%</entry>
+ </row><row>
+ <entry align="char" id="ROLLOFF-AUTO"><constant>ROLLOFF_AUTO</constant></entry>
+ <entry align="char">Auto-detect the roloff factor.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
</section>
</section>
<section id="DTV-DISEQC-SLAVE-REPLY">
@@ -364,31 +515,82 @@ typedef enum fe_rolloff {
<section id="fe-delivery-system-t">
<title>fe_delivery_system type</title>
<para>Possible values: </para>
-<programlisting>
-typedef enum fe_delivery_system {
- SYS_UNDEFINED,
- SYS_DVBC_ANNEX_A,
- SYS_DVBC_ANNEX_B,
- SYS_DVBT,
- SYS_DSS,
- SYS_DVBS,
- SYS_DVBS2,
- SYS_DVBH,
- SYS_ISDBT,
- SYS_ISDBS,
- SYS_ISDBC,
- SYS_ATSC,
- SYS_ATSCMH,
- SYS_DTMB,
- SYS_CMMB,
- SYS_DAB,
- SYS_DVBT2,
- SYS_TURBO,
- SYS_DVBC_ANNEX_C,
-} fe_delivery_system_t;
-</programlisting>
- </section>
+<table pgwide="1" frame="none" id="fe-delivery-system">
+ <title>enum fe_delivery_system</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="SYS-UNDEFINED"><constant>SYS_UNDEFINED</constant></entry>
+ <entry>Undefined standard. Generally, indicates an error</entry>
+ </row><row>
+ <entry id="SYS-DVBC-ANNEX-A"><constant>SYS_DVBC_ANNEX_A</constant></entry>
+ <entry>Cable TV: DVB-C following ITU-T J.83 Annex A spec</entry>
+ </row><row>
+ <entry id="SYS-DVBC-ANNEX-B"><constant>SYS_DVBC_ANNEX_B</constant></entry>
+ <entry>Cable TV: DVB-C following ITU-T J.83 Annex B spec (ClearQAM)</entry>
+ </row><row>
+ <entry id="SYS-DVBC-ANNEX-C"><constant>SYS_DVBC_ANNEX_C</constant></entry>
+ <entry>Cable TV: DVB-C following ITU-T J.83 Annex C spec</entry>
+ </row><row>
+ <entry id="SYS-ISDBC"><constant>SYS_ISDBC</constant></entry>
+ <entry>Cable TV: ISDB-C (no drivers yet)</entry>
+ </row><row>
+ <entry id="SYS-DVBT"><constant>SYS_DVBT</constant></entry>
+ <entry>Terrestral TV: DVB-T</entry>
+ </row><row>
+ <entry id="SYS-DVBT2"><constant>SYS_DVBT2</constant></entry>
+ <entry>Terrestral TV: DVB-T2</entry>
+ </row><row>
+ <entry id="SYS-ISDBT"><constant>SYS_ISDBT</constant></entry>
+ <entry>Terrestral TV: ISDB-T</entry>
+ </row><row>
+ <entry id="SYS-ATSC"><constant>SYS_ATSC</constant></entry>
+ <entry>Terrestral TV: ATSC</entry>
+ </row><row>
+ <entry id="SYS-ATSCMH"><constant>SYS_ATSCMH</constant></entry>
+ <entry>Terrestral TV (mobile): ATSC-M/H</entry>
+ </row><row>
+ <entry id="SYS-DTMB"><constant>SYS_DTMB</constant></entry>
+ <entry>Terrestrial TV: DTMB</entry>
+ </row><row>
+ <entry id="SYS-DVBS"><constant>SYS_DVBS</constant></entry>
+ <entry>Satellite TV: DVB-S</entry>
+ </row><row>
+ <entry id="SYS-DVBS2"><constant>SYS_DVBS2</constant></entry>
+ <entry>Satellite TV: DVB-S2</entry>
+ </row><row>
+ <entry id="SYS-TURBO"><constant>SYS_TURBO</constant></entry>
+ <entry>Satellite TV: DVB-S Turbo</entry>
+ </row><row>
+ <entry id="SYS-ISDBS"><constant>SYS_ISDBS</constant></entry>
+ <entry>Satellite TV: ISDB-S</entry>
+ </row><row>
+ <entry id="SYS-DAB"><constant>SYS_DAB</constant></entry>
+ <entry>Digital audio: DAB (not fully supported)</entry>
+ </row><row>
+ <entry id="SYS-DSS"><constant>SYS_DSS</constant></entry>
+ <entry>Satellite TV:"DSS (not fully supported)</entry>
+ </row><row>
+ <entry id="SYS-CMMB"><constant>SYS_CMMB</constant></entry>
+ <entry>Terrestral TV (mobile):CMMB (not fully supported)</entry>
+ </row><row>
+ <entry id="SYS-DVBH"><constant>SYS_DVBH</constant></entry>
+ <entry>Terrestral TV (mobile): DVB-H (standard deprecated)</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+
+
+</section>
</section>
<section id="DTV-ISDBT-PARTIAL-RECEPTION">
<title><constant>DTV_ISDBT_PARTIAL_RECEPTION</constant></title>
@@ -630,114 +832,177 @@ typedef enum fe_delivery_system {
</section>
<section id="DTV-ATSCMH-RS-FRAME-MODE">
<title><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></title>
- <para>RS frame mode.</para>
+ <para>Reed Solomon (RS) frame mode.</para>
<para>Possible values are:</para>
- <para id="atscmh-rs-frame-mode">
-<programlisting>
-typedef enum atscmh_rs_frame_mode {
- ATSCMH_RSFRAME_PRI_ONLY = 0,
- ATSCMH_RSFRAME_PRI_SEC = 1,
-} atscmh_rs_frame_mode_t;
-</programlisting>
- </para>
+<table pgwide="1" frame="none" id="atscmh-rs-frame-mode">
+ <title>enum atscmh_rs_frame_mode</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="ATSCMH-RSFRAME-PRI-ONLY"><constant>ATSCMH_RSFRAME_PRI_ONLY</constant></entry>
+ <entry>Single Frame: There is only a primary RS Frame for all
+ Group Regions.</entry>
+ </row><row>
+ <entry id="ATSCMH-RSFRAME-PRI-SEC"><constant>ATSCMH_RSFRAME_PRI_SEC</constant></entry>
+ <entry>Dual Frame: There are two separate RS Frames: Primary RS
+ Frame for Group Region A and B and Secondary RS Frame for Group
+ Region C and D.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
</section>
<section id="DTV-ATSCMH-RS-FRAME-ENSEMBLE">
<title><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></title>
- <para>RS frame ensemble.</para>
+ <para>Reed Solomon(RS) frame ensemble.</para>
<para>Possible values are:</para>
- <para id="atscmh-rs-frame-ensemble">
-<programlisting>
-typedef enum atscmh_rs_frame_ensemble {
- ATSCMH_RSFRAME_ENS_PRI = 0,
- ATSCMH_RSFRAME_ENS_SEC = 1,
-} atscmh_rs_frame_ensemble_t;
-</programlisting>
- </para>
+<table pgwide="1" frame="none" id="atscmh-rs-frame-ensemble">
+ <title>enum atscmh_rs_frame_ensemble</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="ATSCMH-RSFRAME-ENS-PRI"><constant>ATSCMH_RSFRAME_ENS_PRI</constant></entry>
+ <entry>Primary Ensemble.</entry>
+ </row><row>
+ <entry id="ATSCMH-RSFRAME-ENS-SEC"><constant>AATSCMH_RSFRAME_PRI_SEC</constant></entry>
+ <entry>Secondary Ensemble.</entry>
+ </row><row>
+ <entry id="ATSCMH-RSFRAME-RES"><constant>AATSCMH_RSFRAME_RES</constant></entry>
+ <entry>Reserved. Shouldn't be used.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
</section>
<section id="DTV-ATSCMH-RS-CODE-MODE-PRI">
<title><constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant></title>
- <para>RS code mode (primary).</para>
+ <para>Reed Solomon (RS) code mode (primary).</para>
<para>Possible values are:</para>
- <para id="atscmh-rs-code-mode">
-<programlisting>
-typedef enum atscmh_rs_code_mode {
- ATSCMH_RSCODE_211_187 = 0,
- ATSCMH_RSCODE_223_187 = 1,
- ATSCMH_RSCODE_235_187 = 2,
-} atscmh_rs_code_mode_t;
-</programlisting>
- </para>
+<table pgwide="1" frame="none" id="atscmh-rs-code-mode">
+ <title>enum atscmh_rs_code_mode</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="ATSCMH-RSCODE-211-187"><constant>ATSCMH_RSCODE_211_187</constant></entry>
+ <entry>Reed Solomon code (211,187).</entry>
+ </row><row>
+ <entry id="ATSCMH-RSCODE-223-187"><constant>ATSCMH_RSCODE_223_187</constant></entry>
+ <entry>Reed Solomon code (223,187).</entry>
+ </row><row>
+ <entry id="ATSCMH-RSCODE-235-187"><constant>ATSCMH_RSCODE_235_187</constant></entry>
+ <entry>Reed Solomon code (235,187).</entry>
+ </row><row>
+ <entry id="ATSCMH-RSCODE-RES"><constant>ATSCMH_RSCODE_RES</constant></entry>
+ <entry>Reserved. Shouldn't be used.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
</section>
<section id="DTV-ATSCMH-RS-CODE-MODE-SEC">
<title><constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant></title>
- <para>RS code mode (secondary).</para>
- <para>Possible values are:</para>
-<programlisting>
-typedef enum atscmh_rs_code_mode {
- ATSCMH_RSCODE_211_187 = 0,
- ATSCMH_RSCODE_223_187 = 1,
- ATSCMH_RSCODE_235_187 = 2,
-} atscmh_rs_code_mode_t;
-</programlisting>
+ <para>Reed Solomon (RS) code mode (secondary).</para>
+ <para>Possible values are the same as documented on
+ &atscmh-rs-code-mode;:</para>
</section>
<section id="DTV-ATSCMH-SCCC-BLOCK-MODE">
<title><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></title>
<para>Series Concatenated Convolutional Code Block Mode.</para>
<para>Possible values are:</para>
- <para id="atscmh-sccc-block-mode">
-<programlisting>
-typedef enum atscmh_sccc_block_mode {
- ATSCMH_SCCC_BLK_SEP = 0,
- ATSCMH_SCCC_BLK_COMB = 1,
-} atscmh_sccc_block_mode_t;
-</programlisting>
- </para>
+<table pgwide="1" frame="none" id="atscmh-sccc-block-mode">
+ <title>enum atscmh_scc_block_mode</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="ATSCMH-SCCC-BLK-SEP"><constant>ATSCMH_SCCC_BLK_SEP</constant></entry>
+ <entry>Separate SCCC: the SCCC outer code mode shall be set independently
+ for each Group Region (A, B, C, D)</entry>
+ </row><row>
+ <entry id="ATSCMH-SCCC-BLK-COMB"><constant>ATSCMH_SCCC_BLK_COMB</constant></entry>
+ <entry>Combined SCCC: all four Regions shall have the same SCCC outer
+ code mode.</entry>
+ </row><row>
+ <entry id="ATSCMH-SCCC-BLK-RES"><constant>ATSCMH_SCCC_BLK_RES</constant></entry>
+ <entry>Reserved. Shouldn't be used.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
</section>
<section id="DTV-ATSCMH-SCCC-CODE-MODE-A">
<title><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></title>
<para>Series Concatenated Convolutional Code Rate.</para>
<para>Possible values are:</para>
- <para id="atscmh-sccc-code-mode">
-<programlisting>
-typedef enum atscmh_sccc_code_mode {
- ATSCMH_SCCC_CODE_HLF = 0,
- ATSCMH_SCCC_CODE_QTR = 1,
-} atscmh_sccc_code_mode_t;
-</programlisting>
- </para>
+<table pgwide="1" frame="none" id="atscmh-sccc-code-mode">
+ <title>enum atscmh_sccc_code_mode</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="ATSCMH-SCCC-CODE-HLF"><constant>ATSCMH_SCCC_CODE_HLF</constant></entry>
+ <entry>The outer code rate of a SCCC Block is 1/2 rate.</entry>
+ </row><row>
+ <entry id="ATSCMH-SCCC-CODE-QTR"><constant>ATSCMH_SCCC_CODE_QTR</constant></entry>
+ <entry>The outer code rate of a SCCC Block is 1/4 rate.</entry>
+ </row><row>
+ <entry id="ATSCMH-SCCC-CODE-RES"><constant>ATSCMH_SCCC_CODE_RES</constant></entry>
+ <entry>to be documented.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
</section>
<section id="DTV-ATSCMH-SCCC-CODE-MODE-B">
<title><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></title>
<para>Series Concatenated Convolutional Code Rate.</para>
- <para>Possible values are:</para>
-<programlisting>
-typedef enum atscmh_sccc_code_mode {
- ATSCMH_SCCC_CODE_HLF = 0,
- ATSCMH_SCCC_CODE_QTR = 1,
-} atscmh_sccc_code_mode_t;
-</programlisting>
+ <para>Possible values are the same as documented on
+ &atscmh-sccc-code-mode;.</para>
</section>
<section id="DTV-ATSCMH-SCCC-CODE-MODE-C">
<title><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></title>
<para>Series Concatenated Convolutional Code Rate.</para>
- <para>Possible values are:</para>
-<programlisting>
-typedef enum atscmh_sccc_code_mode {
- ATSCMH_SCCC_CODE_HLF = 0,
- ATSCMH_SCCC_CODE_QTR = 1,
-} atscmh_sccc_code_mode_t;
-</programlisting>
+ <para>Possible values are the same as documented on
+ &atscmh-sccc-code-mode;.</para>
</section>
<section id="DTV-ATSCMH-SCCC-CODE-MODE-D">
<title><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></title>
<para>Series Concatenated Convolutional Code Rate.</para>
- <para>Possible values are:</para>
-<programlisting>
-typedef enum atscmh_sccc_code_mode {
- ATSCMH_SCCC_CODE_HLF = 0,
- ATSCMH_SCCC_CODE_QTR = 1,
-} atscmh_sccc_code_mode_t;
-</programlisting>
+ <para>Possible values are the same as documented on
+ &atscmh-sccc-code-mode;.</para>
</section>
</section>
<section id="DTV-API-VERSION">
@@ -746,65 +1011,74 @@ typedef enum atscmh_sccc_code_mode {
</section>
<section id="DTV-CODE-RATE-HP">
<title><constant>DTV_CODE_RATE_HP</constant></title>
- <para>Used on terrestrial transmissions. The acceptable values are:
+ <para>Used on terrestrial transmissions. The acceptable values are
+ the ones described at &fe-transmit-mode-t;.
</para>
- <programlisting>
-typedef enum fe_code_rate {
- FEC_NONE = 0,
- FEC_1_2,
- FEC_2_3,
- FEC_3_4,
- FEC_4_5,
- FEC_5_6,
- FEC_6_7,
- FEC_7_8,
- FEC_8_9,
- FEC_AUTO,
- FEC_3_5,
- FEC_9_10,
-} fe_code_rate_t;
- </programlisting>
</section>
<section id="DTV-CODE-RATE-LP">
<title><constant>DTV_CODE_RATE_LP</constant></title>
- <para>Used on terrestrial transmissions. The acceptable values are:
+ <para>Used on terrestrial transmissions. The acceptable values are
+ the ones described at &fe-transmit-mode-t;.
</para>
- <programlisting>
-typedef enum fe_code_rate {
- FEC_NONE = 0,
- FEC_1_2,
- FEC_2_3,
- FEC_3_4,
- FEC_4_5,
- FEC_5_6,
- FEC_6_7,
- FEC_7_8,
- FEC_8_9,
- FEC_AUTO,
- FEC_3_5,
- FEC_9_10,
-} fe_code_rate_t;
- </programlisting>
+
</section>
+
<section id="DTV-GUARD-INTERVAL">
<title><constant>DTV_GUARD_INTERVAL</constant></title>
<para>Possible values are:</para>
-<programlisting>
-typedef enum fe_guard_interval {
- GUARD_INTERVAL_1_32,
- GUARD_INTERVAL_1_16,
- GUARD_INTERVAL_1_8,
- GUARD_INTERVAL_1_4,
- GUARD_INTERVAL_AUTO,
- GUARD_INTERVAL_1_128,
- GUARD_INTERVAL_19_128,
- GUARD_INTERVAL_19_256,
- GUARD_INTERVAL_PN420,
- GUARD_INTERVAL_PN595,
- GUARD_INTERVAL_PN945,
-} fe_guard_interval_t;
-</programlisting>
+
+<section id="fe-guard-interval-t">
+<title>Modulation guard interval</title>
+
+<table pgwide="1" frame="none" id="fe-guard-interval">
+ <title>enum fe_guard_interval</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="GUARD-INTERVAL-AUTO"><constant>GUARD_INTERVAL_AUTO</constant></entry>
+ <entry>Autodetect the guard interval</entry>
+ </row><row>
+ <entry id="GUARD-INTERVAL-1-128"><constant>GUARD_INTERVAL_1_128</constant></entry>
+ <entry>Guard interval 1/128</entry>
+ </row><row>
+ <entry id="GUARD-INTERVAL-1-32"><constant>GUARD_INTERVAL_1_32</constant></entry>
+ <entry>Guard interval 1/32</entry>
+ </row><row>
+ <entry id="GUARD-INTERVAL-1-16"><constant>GUARD_INTERVAL_1_16</constant></entry>
+ <entry>Guard interval 1/16</entry>
+ </row><row>
+ <entry id="GUARD-INTERVAL-1-8"><constant>GUARD_INTERVAL_1_8</constant></entry>
+ <entry>Guard interval 1/8</entry>
+ </row><row>
+ <entry id="GUARD-INTERVAL-1-4"><constant>GUARD_INTERVAL_1_4</constant></entry>
+ <entry>Guard interval 1/4</entry>
+ </row><row>
+ <entry id="GUARD-INTERVAL-19-128"><constant>GUARD_INTERVAL_19_128</constant></entry>
+ <entry>Guard interval 19/128</entry>
+ </row><row>
+ <entry id="GUARD-INTERVAL-19-256"><constant>GUARD_INTERVAL_19_256</constant></entry>
+ <entry>Guard interval 19/256</entry>
+ </row><row>
+ <entry id="GUARD-INTERVAL-PN420"><constant>GUARD_INTERVAL_PN420</constant></entry>
+ <entry>PN length 420 (1/4)</entry>
+ </row><row>
+ <entry id="GUARD-INTERVAL-PN595"><constant>GUARD_INTERVAL_PN595</constant></entry>
+ <entry>PN length 595 (1/6)</entry>
+ </row><row>
+ <entry id="GUARD-INTERVAL-PN945"><constant>GUARD_INTERVAL_PN945</constant></entry>
+ <entry>PN length 945 (1/9)</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
<para>Notes:</para>
<para>1) If <constant>DTV_GUARD_INTERVAL</constant> is set the <constant>GUARD_INTERVAL_AUTO</constant> the hardware will
@@ -812,26 +1086,64 @@ typedef enum fe_guard_interval {
in the missing parameters.</para>
<para>2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present</para>
<para>3) DTMB specifies PN420, PN595 and PN945.</para>
+</section>
</section>
<section id="DTV-TRANSMISSION-MODE">
<title><constant>DTV_TRANSMISSION_MODE</constant></title>
- <para>Specifies the number of carriers used by the standard</para>
+ <para>Specifies the number of carriers used by the standard.
+ This is used only on OFTM-based standards, e. g.
+ DVB-T/T2, ISDB-T, DTMB</para>
+
+<section id="fe-transmit-mode-t">
+<title>enum fe_transmit_mode: Number of carriers per channel</title>
+
+<table pgwide="1" frame="none" id="fe-transmit-mode">
+ <title>enum fe_transmit_mode</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="TRANSMISSION-MODE-AUTO"><constant>TRANSMISSION_MODE_AUTO</constant></entry>
+ <entry>Autodetect transmission mode. The hardware will try to find
+ the correct FFT-size (if capable) to fill in the missing
+ parameters.</entry>
+ </row><row>
+ <entry id="TRANSMISSION-MODE-1K"><constant>TRANSMISSION_MODE_1K</constant></entry>
+ <entry>Transmission mode 1K</entry>
+ </row><row>
+ <entry id="TRANSMISSION-MODE-2K"><constant>TRANSMISSION_MODE_2K</constant></entry>
+ <entry>Transmission mode 2K</entry>
+ </row><row>
+ <entry id="TRANSMISSION-MODE-8K"><constant>TRANSMISSION_MODE_8K</constant></entry>
+ <entry>Transmission mode 8K</entry>
+ </row><row>
+ <entry id="TRANSMISSION-MODE-4K"><constant>TRANSMISSION_MODE_4K</constant></entry>
+ <entry>Transmission mode 4K</entry>
+ </row><row>
+ <entry id="TRANSMISSION-MODE-16K"><constant>TRANSMISSION_MODE_16K</constant></entry>
+ <entry>Transmission mode 16K</entry>
+ </row><row>
+ <entry id="TRANSMISSION-MODE-32K"><constant>TRANSMISSION_MODE_32K</constant></entry>
+ <entry>Transmission mode 32K</entry>
+ </row><row>
+ <entry id="TRANSMISSION-MODE-C1"><constant>TRANSMISSION_MODE_C1</constant></entry>
+ <entry>Single Carrier (C=1) transmission mode (DTMB)</entry>
+ </row><row>
+ <entry id="TRANSMISSION-MODE-C3780"><constant>TRANSMISSION_MODE_C3780</constant></entry>
+ <entry>Multi Carrier (C=3780) transmission mode (DTMB)</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+
- <para>Possible values are:</para>
-<programlisting>
-typedef enum fe_transmit_mode {
- TRANSMISSION_MODE_2K,
- TRANSMISSION_MODE_8K,
- TRANSMISSION_MODE_AUTO,
- TRANSMISSION_MODE_4K,
- TRANSMISSION_MODE_1K,
- TRANSMISSION_MODE_16K,
- TRANSMISSION_MODE_32K,
- TRANSMISSION_MODE_C1,
- TRANSMISSION_MODE_C3780,
-} fe_transmit_mode_t;
-</programlisting>
<para>Notes:</para>
<para>1) ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called
'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K</para>
@@ -842,19 +1154,48 @@ typedef enum fe_transmit_mode {
<para>3) DVB-T specifies 2K and 8K as valid sizes.</para>
<para>4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K.</para>
<para>5) DTMB specifies C1 and C3780.</para>
+</section>
</section>
<section id="DTV-HIERARCHY">
<title><constant>DTV_HIERARCHY</constant></title>
<para>Frontend hierarchy</para>
- <programlisting>
-typedef enum fe_hierarchy {
- HIERARCHY_NONE,
- HIERARCHY_1,
- HIERARCHY_2,
- HIERARCHY_4,
- HIERARCHY_AUTO
- } fe_hierarchy_t;
- </programlisting>
+
+
+<section id="fe-hierarchy-t">
+<title>Frontend hierarchy</title>
+
+<table pgwide="1" frame="none" id="fe-hierarchy">
+ <title>enum fe_hierarchy</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="HIERARCHY-NONE"><constant>HIERARCHY_NONE</constant></entry>
+ <entry>No hierarchy</entry>
+ </row><row>
+ <entry id="HIERARCHY-AUTO"><constant>HIERARCHY_AUTO</constant></entry>
+ <entry>Autodetect hierarchy (if supported)</entry>
+ </row><row>
+ <entry id="HIERARCHY-1"><constant>HIERARCHY_1</constant></entry>
+ <entry>Hierarchy 1</entry>
+ </row><row>
+ <entry id="HIERARCHY-2"><constant>HIERARCHY_2</constant></entry>
+ <entry>Hierarchy 2</entry>
+ </row><row>
+ <entry id="HIERARCHY-4"><constant>HIERARCHY_4</constant></entry>
+ <entry>Hierarchy 4</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+</section>
+
</section>
<section id="DTV-STREAM-ID">
<title><constant>DTV_STREAM_ID</constant></title>
@@ -891,15 +1232,37 @@ typedef enum fe_hierarchy {
</section>
<section id="DTV-INTERLEAVING">
<title><constant>DTV_INTERLEAVING</constant></title>
- <para id="fe-interleaving">Interleaving mode</para>
- <programlisting>
-enum fe_interleaving {
- INTERLEAVING_NONE,
- INTERLEAVING_AUTO,
- INTERLEAVING_240,
- INTERLEAVING_720,
-};
- </programlisting>
+
+<para>Time interleaving to be used. Currently, used only on DTMB.</para>
+
+<table pgwide="1" frame="none" id="fe-interleaving">
+ <title>enum fe_interleaving</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="INTERLEAVING-NONE"><constant>INTERLEAVING_NONE</constant></entry>
+ <entry>No interleaving.</entry>
+ </row><row>
+ <entry id="INTERLEAVING-AUTO"><constant>INTERLEAVING_AUTO</constant></entry>
+ <entry>Auto-detect interleaving.</entry>
+ </row><row>
+ <entry id="INTERLEAVING-240"><constant>INTERLEAVING_240</constant></entry>
+ <entry>Interleaving of 240 symbols.</entry>
+ </row><row>
+ <entry id="INTERLEAVING-720"><constant>INTERLEAVING_720</constant></entry>
+ <entry>Interleaving of 720 symbols.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+
</section>
<section id="DTV-LNA">
<title><constant>DTV_LNA</constant></title>
@@ -921,7 +1284,7 @@ enum fe_interleaving {
<para>For most delivery systems, <constant>dtv_property.stat.len</constant>
will be 1 if the stats is supported, and the properties will
return a single value for each parameter.</para>
- <para>It should be noticed, however, that new OFDM delivery systems
+ <para>It should be noted, however, that new OFDM delivery systems
like ISDB can use different modulation types for each group of
carriers. On such standards, up to 3 groups of statistics can be
provided, and <constant>dtv_property.stat.len</constant> is updated
@@ -940,10 +1303,10 @@ enum fe_interleaving {
and <constant>uvalue</constant> is for unsigned values (counters, relative scale)</para></listitem>
<listitem><para><constant>scale</constant> - Scale for the value. It can be:</para>
<itemizedlist mark='bullet' id="fecap-scale-params">
- <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - The parameter is supported by the frontend, but it was not possible to collect it (could be a transitory or permanent condition)</para></listitem>
- <listitem><para><constant>FE_SCALE_DECIBEL</constant> - parameter is a signed value, measured in 1/1000 dB</para></listitem>
- <listitem><para><constant>FE_SCALE_RELATIVE</constant> - parameter is a unsigned value, where 0 means 0% and 65535 means 100%.</para></listitem>
- <listitem><para><constant>FE_SCALE_COUNTER</constant> - parameter is a unsigned value that counts the occurrence of an event, like bit error, block error, or lapsed time.</para></listitem>
+ <listitem id="FE-SCALE-NOT-AVAILABLE"><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - The parameter is supported by the frontend, but it was not possible to collect it (could be a transitory or permanent condition)</para></listitem>
+ <listitem id="FE-SCALE-DECIBEL"><para><constant>FE_SCALE_DECIBEL</constant> - parameter is a signed value, measured in 1/1000 dB</para></listitem>
+ <listitem id="FE-SCALE-RELATIVE"><para><constant>FE_SCALE_RELATIVE</constant> - parameter is a unsigned value, where 0 means 0% and 65535 means 100%.</para></listitem>
+ <listitem id="FE-SCALE-COUNTER"><para><constant>FE_SCALE_COUNTER</constant> - parameter is a unsigned value that counts the occurrence of an event, like bit error, block error, or lapsed time.</para></listitem>
</itemizedlist>
</listitem>
</itemizedlist>
@@ -953,7 +1316,7 @@ enum fe_interleaving {
<para>Possible scales for this metric are:</para>
<itemizedlist mark='bullet'>
<listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
- <listitem><para><constant>FE_SCALE_DECIBEL</constant> - signal strength is in 0.0001 dBm units, power measured in miliwatts. This value is generally negative.</para></listitem>
+ <listitem><para><constant>FE_SCALE_DECIBEL</constant> - signal strength is in 0.001 dBm units, power measured in miliwatts. This value is generally negative.</para></listitem>
<listitem><para><constant>FE_SCALE_RELATIVE</constant> - The frontend provides a 0% to 100% measurement for power (actually, 0 to 65535).</para></listitem>
</itemizedlist>
</section>
@@ -963,7 +1326,7 @@ enum fe_interleaving {
<para>Possible scales for this metric are:</para>
<itemizedlist mark='bullet'>
<listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
- <listitem><para><constant>FE_SCALE_DECIBEL</constant> - Signal/Noise ratio is in 0.0001 dB units.</para></listitem>
+ <listitem><para><constant>FE_SCALE_DECIBEL</constant> - Signal/Noise ratio is in 0.001 dB units.</para></listitem>
<listitem><para><constant>FE_SCALE_RELATIVE</constant> - The frontend provides a 0% to 100% measurement for Signal/Noise (actually, 0 to 65535).</para></listitem>
</itemizedlist>
</section>
@@ -985,7 +1348,7 @@ enum fe_interleaving {
<title><constant>DTV_STAT_PRE_TOTAL_BIT_COUNT</constant></title>
<para>Measures the amount of bits received before the inner code block, during the same period as
<link linkend="DTV-STAT-PRE-ERROR-BIT-COUNT"><constant>DTV_STAT_PRE_ERROR_BIT_COUNT</constant></link> measurement was taken.</para>
- <para>It should be noticed that this measurement can be smaller than the total amount of bits on the transport stream,
+ <para>It should be noted that this measurement can be smaller than the total amount of bits on the transport stream,
as the frontend may need to manually restart the measurement, losing some data between each measurement interval.</para>
<para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
The frontend may reset it when a channel/transponder is tuned.</para>
@@ -1014,7 +1377,7 @@ enum fe_interleaving {
<title><constant>DTV_STAT_POST_TOTAL_BIT_COUNT</constant></title>
<para>Measures the amount of bits received after the inner coding, during the same period as
<link linkend="DTV-STAT-POST-ERROR-BIT-COUNT"><constant>DTV_STAT_POST_ERROR_BIT_COUNT</constant></link> measurement was taken.</para>
- <para>It should be noticed that this measurement can be smaller than the total amount of bits on the transport stream,
+ <para>It should be noted that this measurement can be smaller than the total amount of bits on the transport stream,
as the frontend may need to manually restart the measurement, losing some data between each measurement interval.</para>
<para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
The frontend may reset it when a channel/transponder is tuned.</para>
@@ -1255,8 +1618,8 @@ enum fe_interleaving {
<para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
</section>
</section>
- <section id="frontend-property-satellital-systems">
- <title>Properties used on satellital delivery systems</title>
+ <section id="frontend-property-satellite-systems">
+ <title>Properties used on satellite delivery systems</title>
<section id="dvbs-params">
<title>DVB-S delivery system</title>
<para>The following parameters are valid for DVB-S:</para>
diff --git a/Documentation/DocBook/media/dvb/examples.xml b/Documentation/DocBook/media/dvb/examples.xml
index f037e568eb6e..c9f68c7183cc 100644
--- a/Documentation/DocBook/media/dvb/examples.xml
+++ b/Documentation/DocBook/media/dvb/examples.xml
@@ -1,8 +1,10 @@
<title>Examples</title>
<para>In this section we would like to present some examples for using the DVB API.
</para>
-<para>Maintainer note: This section is out of date. Please refer to the sample programs packaged
-with the driver distribution from <ulink url="http://linuxtv.org/hg/dvb-apps" />.
+<para>NOTE: This section is out of date, and the code below won't even
+ compile. Please refer to the
+ <ulink url="http://linuxtv.org/docs/libdvbv5/index.html">libdvbv5</ulink>
+ for updated/recommended examples.
</para>
<section id="tuning">
diff --git a/Documentation/DocBook/media/dvb/fe-diseqc-recv-slave-reply.xml b/Documentation/DocBook/media/dvb/fe-diseqc-recv-slave-reply.xml
new file mode 100644
index 000000000000..4595dbfff208
--- /dev/null
+++ b/Documentation/DocBook/media/dvb/fe-diseqc-recv-slave-reply.xml
@@ -0,0 +1,78 @@
+<refentry id="FE_DISEQC_RECV_SLAVE_REPLY">
+ <refmeta>
+ <refentrytitle>ioctl FE_DISEQC_RECV_SLAVE_REPLY</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>FE_DISEQC_RECV_SLAVE_REPLY</refname>
+ <refpurpose>Receives reply from a DiSEqC 2.0 command</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 dvb_diseqc_slave_reply *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_DISEQC_RECV_SLAVE_REPLY</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para>pointer to &dvb-diseqc-slave-reply;</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>Receives reply from a DiSEqC 2.0 command.</para>
+&return-value-dvb;
+
+<table pgwide="1" frame="none" id="dvb-diseqc-slave-reply">
+ <title>struct <structname>dvb_diseqc_slave_reply</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>uint8_t</entry>
+ <entry>msg[4]</entry>
+ <entry>DiSEqC message (framing, data[3])</entry>
+ </row><row>
+ <entry>uint8_t</entry>
+ <entry>msg_len</entry>
+ <entry>Length of the DiSEqC message. Valid values are 0 to 4,
+ where 0 means no msg</entry>
+ </row><row>
+ <entry>int</entry>
+ <entry>timeout</entry>
+ <entry>Return from ioctl after timeout ms with errorcode when no
+ message was received</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+
+</refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-diseqc-reset-overload.xml b/Documentation/DocBook/media/dvb/fe-diseqc-reset-overload.xml
new file mode 100644
index 000000000000..c104df77ecd0
--- /dev/null
+++ b/Documentation/DocBook/media/dvb/fe-diseqc-reset-overload.xml
@@ -0,0 +1,51 @@
+<refentry id="FE_DISEQC_RESET_OVERLOAD">
+ <refmeta>
+ <refentrytitle>ioctl FE_DISEQC_RESET_OVERLOAD</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>FE_DISEQC_RESET_OVERLOAD</refname>
+ <refpurpose>Restores the power to the antenna subsystem, if it was powered
+ off due to power overload.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>NULL</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_DISEQC_RESET_OVERLOAD</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>If the bus has been automatically powered off due to power overload, this ioctl
+ call restores the power to the bus. The call requires read/write access to the
+ device. This call has no effect if the device is manually powered off. Not all
+ DVB adapters support this ioctl.</para>
+&return-value-dvb;
+</refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-diseqc-send-burst.xml b/Documentation/DocBook/media/dvb/fe-diseqc-send-burst.xml
new file mode 100644
index 000000000000..9f6a68f32de3
--- /dev/null
+++ b/Documentation/DocBook/media/dvb/fe-diseqc-send-burst.xml
@@ -0,0 +1,89 @@
+<refentry id="FE_DISEQC_SEND_BURST">
+ <refmeta>
+ <refentrytitle>ioctl FE_DISEQC_SEND_BURST</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>FE_DISEQC_SEND_BURST</refname>
+ <refpurpose>Sends a 22KHz tone burst for 2x1 mini DiSEqC satellite selection.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>enum fe_sec_mini_cmd *<parameter>tone</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_DISEQC_SEND_BURST</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>tone</parameter></term>
+ <listitem>
+ <para>pointer to &fe-sec-mini-cmd;</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+<para>This ioctl is used to set the generation of a 22kHz tone burst for mini
+ DiSEqC satellite
+ selection for 2x1 switches.
+ This call requires read/write permissions.</para>
+<para>It provides support for what's specified at
+ <ulink url="http://www.eutelsat.com/files/contributed/satellites/pdf/Diseqc/associated%20docs/simple_tone_burst_detec.pdf">Digital Satellite Equipment Control
+ (DiSEqC) - Simple "ToneBurst" Detection Circuit specification.</ulink>
+ </para>
+&return-value-dvb;
+</refsect1>
+
+<refsect1 id="fe-sec-mini-cmd-t">
+<title>enum fe_sec_mini_cmd</title>
+
+<table pgwide="1" frame="none" id="fe-sec-mini-cmd">
+ <title>enum fe_sec_mini_cmd</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry align="char" id="SEC-MINI-A"><constant>SEC_MINI_A</constant></entry>
+ <entry align="char">Sends a mini-DiSEqC 22kHz '0' Tone Burst to
+ select satellite-A</entry>
+ </row><row>
+ <entry align="char" id="SEC-MINI-B"><constant>SEC_MINI_B</constant></entry>
+ <entry align="char">Sends a mini-DiSEqC 22kHz '1' Data Burst to
+ select satellite-B</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+</refsect1>
+
+</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-diseqc-send-master-cmd.xml b/Documentation/DocBook/media/dvb/fe-diseqc-send-master-cmd.xml
new file mode 100644
index 000000000000..38cf313e121b
--- /dev/null
+++ b/Documentation/DocBook/media/dvb/fe-diseqc-send-master-cmd.xml
@@ -0,0 +1,72 @@
+<refentry id="FE_DISEQC_SEND_MASTER_CMD">
+ <refmeta>
+ <refentrytitle>ioctl FE_DISEQC_SEND_MASTER_CMD</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>FE_DISEQC_SEND_MASTER_CMD</refname>
+ <refpurpose>Sends a DiSEqC command</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 dvb_diseqc_master_cmd *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_DISEQC_SEND_MASTER_CMD</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para>pointer to &dvb-diseqc-master-cmd;</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>Sends a DiSEqC command to the antenna subsystem.</para>
+&return-value-dvb;
+
+<table pgwide="1" frame="none" id="dvb-diseqc-master-cmd">
+ <title>struct <structname>dvb_diseqc_master_cmd</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>uint8_t</entry>
+ <entry>msg[6]</entry>
+ <entry>DiSEqC message (framing, address, command, data[3])</entry>
+ </row><row>
+ <entry>uint8_t</entry>
+ <entry>msg_len</entry>
+ <entry>Length of the DiSEqC message. Valid values are 3 to 6</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+
+</refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-enable-high-lnb-voltage.xml b/Documentation/DocBook/media/dvb/fe-enable-high-lnb-voltage.xml
new file mode 100644
index 000000000000..c11890b184ad
--- /dev/null
+++ b/Documentation/DocBook/media/dvb/fe-enable-high-lnb-voltage.xml
@@ -0,0 +1,61 @@
+<refentry id="FE_ENABLE_HIGH_LNB_VOLTAGE">
+ <refmeta>
+ <refentrytitle>ioctl FE_ENABLE_HIGH_LNB_VOLTAGE</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>FE_ENABLE_HIGH_LNB_VOLTAGE</refname>
+ <refpurpose>Select output DC level between normal LNBf voltages or higher
+ LNBf voltages.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>unsigned int <parameter>high</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_ENABLE_HIGH_LNB_VOLTAGE</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>high</parameter></term>
+ <listitem>
+ <para>Valid flags:</para>
+ <itemizedlist>
+ <listitem><para>0 - normal 13V and 18V.</para></listitem>
+ <listitem><para>&gt;0 - enables slightly higher voltages instead of
+ 13/18V, in order to compensate for long antenna cables.</para></listitem>
+ </itemizedlist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>Select output DC level between normal LNBf voltages or higher
+ LNBf voltages between 0 (normal) or a value grater than 0 for higher
+ voltages.</para>
+&return-value-dvb;
+</refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-get-info.xml b/Documentation/DocBook/media/dvb/fe-get-info.xml
new file mode 100644
index 000000000000..ed0eeb29dd65
--- /dev/null
+++ b/Documentation/DocBook/media/dvb/fe-get-info.xml
@@ -0,0 +1,266 @@
+<refentry id="FE_GET_INFO">
+ <refmeta>
+ <refentrytitle>ioctl FE_GET_INFO</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>FE_GET_INFO</refname>
+ <refpurpose>Query DVB frontend capabilities and returns information about
+ the front-end. This call only requires read-only access to the device</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 dvb_frontend_info *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_GET_INFO</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para>pointer to struct &dvb-frontend-info;</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>All DVB frontend devices support the
+<constant>FE_GET_INFO</constant> ioctl. It is used to identify
+kernel devices compatible with this specification and to obtain
+information about driver and hardware capabilities. The ioctl takes a
+pointer to dvb_frontend_info which is filled by the driver. When the
+driver is not compatible with this specification the ioctl returns an error.
+</para>
+&return-value-dvb;
+
+ <table pgwide="1" frame="none" id="dvb-frontend-info">
+ <title>struct <structname>dvb_frontend_info</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>char</entry>
+ <entry>name[128]</entry>
+ <entry>Name of the frontend</entry>
+ </row><row>
+ <entry>fe_type_t</entry>
+ <entry>type</entry>
+ <entry><emphasis role="bold">DEPRECATED</emphasis>. DVBv3 type. Should not be used on modern programs, as a
+ frontend may have more than one type. So, the DVBv5 API should
+ be used instead to enumerate and select the frontend type.</entry>
+ </row><row>
+ <entry>uint32_t</entry>
+ <entry>frequency_min</entry>
+ <entry>Minimal frequency supported by the frontend</entry>
+ </row><row>
+ <entry>uint32_t</entry>
+ <entry>frequency_max</entry>
+ <entry>Maximal frequency supported by the frontend</entry>
+ </row><row>
+ <entry>uint32_t</entry>
+ <entry>frequency_stepsize</entry>
+ <entry>Frequency step - all frequencies are multiple of this value</entry>
+ </row><row>
+ <entry>uint32_t</entry>
+ <entry>frequency_tolerance</entry>
+ <entry>Tolerance of the frequency</entry>
+ </row><row>
+ <entry>uint32_t</entry>
+ <entry>symbol_rate_min</entry>
+ <entry>Minimal symbol rate (for Cable/Satellite systems), in bauds</entry>
+ </row><row>
+ <entry>uint32_t</entry>
+ <entry>symbol_rate_max</entry>
+ <entry>Maximal symbol rate (for Cable/Satellite systems), in bauds</entry>
+ </row><row>
+ <entry>uint32_t</entry>
+ <entry>symbol_rate_tolerance</entry>
+ <entry>Maximal symbol rate tolerance, in ppm</entry>
+ </row><row>
+ <entry>uint32_t</entry>
+ <entry>notifier_delay</entry>
+ <entry><emphasis role="bold">DEPRECATED</emphasis>. Not used by any driver.</entry>
+ </row><row>
+ <entry>&fe-caps;</entry>
+ <entry>caps</entry>
+ <entry>Capabilities supported by the frontend</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>NOTE: The frequencies are specified in Hz for Terrestrial and Cable
+ systems. They're specified in kHz for Satellite systems</para>
+ </refsect1>
+
+<refsect1 id="fe-caps-t">
+<title>frontend capabilities</title>
+
+<para>Capabilities describe what a frontend can do. Some capabilities are
+ supported only on some specific frontend types.</para>
+
+<table pgwide="1" frame="none" id="fe-caps">
+ <title>enum fe_caps</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="FE-IS-STUPID"><constant>FE_IS_STUPID</constant></entry>
+ <entry>There's something wrong at the frontend, and it can't
+ report its capabilities</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-INVERSION-AUTO"><constant>FE_CAN_INVERSION_AUTO</constant></entry>
+ <entry>The frontend is capable of auto-detecting inversion</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-FEC-1-2"><constant>FE_CAN_FEC_1_2</constant></entry>
+ <entry>The frontend supports FEC 1/2</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-FEC-2-3"><constant>FE_CAN_FEC_2_3</constant></entry>
+ <entry>The frontend supports FEC 2/3</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-FEC-3-4"><constant>FE_CAN_FEC_3_4</constant></entry>
+ <entry>The frontend supports FEC 3/4</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-FEC-4-5"><constant>FE_CAN_FEC_4_5</constant></entry>
+ <entry>The frontend supports FEC 4/5</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-FEC-5-6"><constant>FE_CAN_FEC_5_6</constant></entry>
+ <entry>The frontend supports FEC 5/6</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-FEC-6-7"><constant>FE_CAN_FEC_6_7</constant></entry>
+ <entry>The frontend supports FEC 6/7</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-FEC-7-8"><constant>FE_CAN_FEC_7_8</constant></entry>
+ <entry>The frontend supports FEC 7/8</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-FEC-8-9"><constant>FE_CAN_FEC_8_9</constant></entry>
+ <entry>The frontend supports FEC 8/9</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-FEC-AUTO"><constant>FE_CAN_FEC_AUTO</constant></entry>
+ <entry>The frontend can autodetect FEC.</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-QPSK"><constant>FE_CAN_QPSK</constant></entry>
+ <entry>The frontend supports QPSK modulation</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-QAM-16"><constant>FE_CAN_QAM_16</constant></entry>
+ <entry>The frontend supports 16-QAM modulation</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-QAM-32"><constant>FE_CAN_QAM_32</constant></entry>
+ <entry>The frontend supports 32-QAM modulation</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-QAM-64"><constant>FE_CAN_QAM_64</constant></entry>
+ <entry>The frontend supports 64-QAM modulation</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-QAM-128"><constant>FE_CAN_QAM_128</constant></entry>
+ <entry>The frontend supports 128-QAM modulation</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-QAM-256"><constant>FE_CAN_QAM_256</constant></entry>
+ <entry>The frontend supports 256-QAM modulation</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-QAM-AUTO"><constant>FE_CAN_QAM_AUTO</constant></entry>
+ <entry>The frontend can autodetect modulation</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-TRANSMISSION-MODE-AUTO"><constant>FE_CAN_TRANSMISSION_MODE_AUTO</constant></entry>
+ <entry>The frontend can autodetect the transmission mode</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-BANDWIDTH-AUTO"><constant>FE_CAN_BANDWIDTH_AUTO</constant></entry>
+ <entry>The frontend can autodetect the bandwidth</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-GUARD-INTERVAL-AUTO"><constant>FE_CAN_GUARD_INTERVAL_AUTO</constant></entry>
+ <entry>The frontend can autodetect the guard interval</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-HIERARCHY-AUTO"><constant>FE_CAN_HIERARCHY_AUTO</constant></entry>
+ <entry>The frontend can autodetect hierarch</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-8VSB"><constant>FE_CAN_8VSB</constant></entry>
+ <entry>The frontend supports 8-VSB modulation</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-16VSB"><constant>FE_CAN_16VSB</constant></entry>
+ <entry>The frontend supports 16-VSB modulation</entry>
+ </row>
+ <row>
+ <entry id="FE-HAS-EXTENDED-CAPS"><constant>FE_HAS_EXTENDED_CAPS</constant></entry>
+ <entry>Currently, unused</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-MULTISTREAM"><constant>FE_CAN_MULTISTREAM</constant></entry>
+ <entry>The frontend supports multistream filtering</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-TURBO-FEC"><constant>FE_CAN_TURBO_FEC</constant></entry>
+ <entry>The frontend supports turbo FEC modulation</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-2G-MODULATION"><constant>FE_CAN_2G_MODULATION</constant></entry>
+ <entry>The frontend supports "2nd generation modulation" (DVB-S2/T2)></entry>
+ </row>
+ <row>
+ <entry id="FE-NEEDS-BENDING"><constant>FE_NEEDS_BENDING</constant></entry>
+ <entry>Not supported anymore, don't use it</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-RECOVER"><constant>FE_CAN_RECOVER</constant></entry>
+ <entry>The frontend can recover from a cable unplug automatically</entry>
+ </row>
+ <row>
+ <entry id="FE-CAN-MUTE-TS"><constant>FE_CAN_MUTE_TS</constant></entry>
+ <entry>The frontend can stop spurious TS data output</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+</refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-get-property.xml b/Documentation/DocBook/media/dvb/fe-get-property.xml
new file mode 100644
index 000000000000..53a170ed3bd1
--- /dev/null
+++ b/Documentation/DocBook/media/dvb/fe-get-property.xml
@@ -0,0 +1,81 @@
+<refentry id="FE_GET_PROPERTY">
+ <refmeta>
+ <refentrytitle>ioctl FE_SET_PROPERTY, FE_GET_PROPERTY</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>FE_SET_PROPERTY</refname>
+ <refname>FE_GET_PROPERTY</refname>
+ <refpurpose>FE_SET_PROPERTY sets one or more frontend properties.
+ FE_GET_PROPERTY returns one or more frontend 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 dtv_properties *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_SET_PROPERTY, FE_GET_PROPERTY</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para>pointer to &dtv-properties;</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>All DVB frontend devices support the
+<constant>FE_SET_PROPERTY</constant> and <constant>FE_GET_PROPERTY</constant>
+ioctls. The supported properties and statistics depends on the delivery system
+and on the device:</para>
+<itemizedlist>
+<listitem>
+ <para><constant>FE_SET_PROPERTY:</constant></para>
+<itemizedlist>
+<listitem><para>This ioctl is used to set one or more
+ frontend properties.</para></listitem>
+<listitem><para>This is the basic command to request the frontend to tune into some
+ frequency and to start decoding the digital TV signal.</para></listitem>
+<listitem><para>This call requires read/write access to the device.</para></listitem>
+<listitem><para>At return, the values are updated to reflect the
+ actual parameters used.</para></listitem>
+</itemizedlist>
+</listitem>
+<listitem>
+ <para><constant>FE_GET_PROPERTY:</constant></para>
+<itemizedlist>
+<listitem><para>This ioctl is used to get properties and
+statistics from the frontend.</para></listitem>
+<listitem><para>No properties are changed, and statistics aren't reset.</para></listitem>
+<listitem><para>This call only requires read-only access to the device.</para></listitem>
+</itemizedlist>
+</listitem>
+</itemizedlist>
+&return-value-dvb;
+</refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-read-status.xml b/Documentation/DocBook/media/dvb/fe-read-status.xml
new file mode 100644
index 000000000000..bc0dc2a55f19
--- /dev/null
+++ b/Documentation/DocBook/media/dvb/fe-read-status.xml
@@ -0,0 +1,107 @@
+<refentry id="FE_READ_STATUS">
+ <refmeta>
+ <refentrytitle>ioctl FE_READ_STATUS</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>FE_READ_STATUS</refname>
+ <refpurpose>Returns status information about the front-end. This call only
+ requires read-only access to the device</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>unsigned int *<parameter>status</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_READ_STATUS</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>status</parameter></term>
+ <listitem>
+ <para>pointer to a bitmask integer filled with the values defined by
+ &fe-status;.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>All DVB frontend devices support the
+<constant>FE_READ_STATUS</constant> ioctl. It is used to check about the
+locking status of the frontend after being tuned. The ioctl takes a
+pointer to an integer where the status will be written.
+</para>
+<para>NOTE: the size of status is actually sizeof(enum fe_status), with varies
+ according with the architecture. This needs to be fixed in the future.</para>
+&return-value-dvb;
+</refsect1>
+
+<refsect1 id="fe-status-t">
+<title>int fe_status</title>
+
+<para>The fe_status parameter is used to indicate the current state
+ and/or state changes of the frontend hardware. It is produced using
+ the &fe-status; values on a bitmask</para>
+
+<table pgwide="1" frame="none" id="fe-status">
+ <title>enum fe_status</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry align="char" id="FE-HAS-SIGNAL"><constant>FE_HAS_SIGNAL</constant></entry>
+ <entry align="char">The frontend has found something above the noise level</entry>
+ </row><row>
+ <entry align="char" id="FE-HAS-CARRIER"><constant>FE_HAS_CARRIER</constant></entry>
+ <entry align="char">The frontend has found a DVB signal</entry>
+ </row><row>
+ <entry align="char" id="FE-HAS-VITERBI"><constant>FE_HAS_VITERBI</constant></entry>
+ <entry align="char">The frontend FEC inner coding (Viterbi, LDPC or other inner code) is stable</entry>
+ </row><row>
+ <entry align="char" id="FE-HAS-SYNC"><constant>FE_HAS_SYNC</constant></entry>
+ <entry align="char">Synchronization bytes was found</entry>
+ </row><row>
+ <entry align="char" id="FE-HAS-LOCK"><constant>FE_HAS_LOCK</constant></entry>
+ <entry align="char">The DVB were locked and everything is working</entry>
+ </row><row>
+ <entry align="char" id="FE-TIMEDOUT"><constant>FE_TIMEDOUT</constant></entry>
+ <entry align="char">no lock within the last about 2 seconds</entry>
+ </row><row>
+ <entry align="char" id="FE-REINIT"><constant>FE_REINIT</constant></entry>
+ <entry align="char">The frontend was reinitialized, application is
+ recommended to reset DiSEqC, tone and parameters</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+</refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-set-frontend-tune-mode.xml b/Documentation/DocBook/media/dvb/fe-set-frontend-tune-mode.xml
new file mode 100644
index 000000000000..99fa8a015c7a
--- /dev/null
+++ b/Documentation/DocBook/media/dvb/fe-set-frontend-tune-mode.xml
@@ -0,0 +1,64 @@
+<refentry id="FE_SET_FRONTEND_TUNE_MODE">
+ <refmeta>
+ <refentrytitle>ioctl FE_SET_FRONTEND_TUNE_MODE</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>FE_SET_FRONTEND_TUNE_MODE</refname>
+ <refpurpose>Allow setting tuner mode flags to the frontend.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>unsigned int <parameter>flags</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_SET_FRONTEND_TUNE_MODE</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>flags</parameter></term>
+ <listitem>
+ <para>Valid flags:</para>
+ <itemizedlist>
+ <listitem><para>0 - normal tune mode</para></listitem>
+ <listitem><para>FE_TUNE_MODE_ONESHOT - When set, this flag will
+ disable any zigzagging or other "normal" tuning behaviour.
+ Additionally, there will be no automatic monitoring of the
+ lock status, and hence no frontend events will be
+ generated. If a frontend device is closed, this flag will
+ be automatically turned off when the device is reopened
+ read-write.</para></listitem>
+ </itemizedlist>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>Allow setting tuner mode flags to the frontend, between 0 (normal)
+ or FE_TUNE_MODE_ONESHOT mode</para>
+&return-value-dvb;
+</refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-set-tone.xml b/Documentation/DocBook/media/dvb/fe-set-tone.xml
new file mode 100644
index 000000000000..62d44e4ccc39
--- /dev/null
+++ b/Documentation/DocBook/media/dvb/fe-set-tone.xml
@@ -0,0 +1,91 @@
+<refentry id="FE_SET_TONE">
+ <refmeta>
+ <refentrytitle>ioctl FE_SET_TONE</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>FE_SET_TONE</refname>
+ <refpurpose>Sets/resets the generation of the continuous 22kHz tone.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>enum fe_sec_tone_mode *<parameter>tone</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_SET_TONE</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>tone</parameter></term>
+ <listitem>
+ <para>pointer to &fe-sec-tone-mode;</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+<para>This ioctl is used to set the generation of the continuous 22kHz tone.
+ This call requires read/write permissions.</para>
+<para>Usually, satellite antenna subsystems require that the digital TV
+ device to send a 22kHz tone in order to select between high/low band on
+ some dual-band LNBf. It is also used to send signals to DiSEqC equipment,
+ but this is done using the DiSEqC ioctls.</para>
+<para>NOTE: if more than one device is connected to the same antenna,
+ setting a tone may interfere on other devices, as they may lose
+ the capability of selecting the band. So, it is recommended that
+ applications would change to SEC_TONE_OFF when the device is not used.</para>
+
+&return-value-dvb;
+</refsect1>
+
+<refsect1 id="fe-sec-tone-mode-t">
+<title>enum fe_sec_tone_mode</title>
+
+<table pgwide="1" frame="none" id="fe-sec-tone-mode">
+ <title>enum fe_sec_tone_mode</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry align="char" id="SEC-TONE-ON"><constant>SEC_TONE_ON</constant></entry>
+ <entry align="char">Sends a 22kHz tone burst to the antenna</entry>
+ </row><row>
+ <entry align="char" id="SEC-TONE-OFF"><constant>SEC_TONE_OFF</constant></entry>
+ <entry align="char">Don't send a 22kHz tone to the antenna
+ (except if the FE_DISEQC_* ioctls are called)</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+</refsect1>
+
+</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-set-voltage.xml b/Documentation/DocBook/media/dvb/fe-set-voltage.xml
new file mode 100644
index 000000000000..c89a6f79b5af
--- /dev/null
+++ b/Documentation/DocBook/media/dvb/fe-set-voltage.xml
@@ -0,0 +1,69 @@
+<refentry id="FE_SET_VOLTAGE">
+ <refmeta>
+ <refentrytitle>ioctl FE_SET_VOLTAGE</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>FE_SET_VOLTAGE</refname>
+ <refpurpose>Allow setting the DC level sent to the antenna subsystem.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>enum fe_sec_voltage *<parameter>voltage</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_SET_VOLTAGE</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>voltage</parameter></term>
+ <listitem>
+ <para>pointer to &fe-sec-voltage;</para>
+ <para>Valid values are described at &fe-sec-voltage;.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+<para>This ioctl allows to set the DC voltage level sent through the antenna
+ cable to 13V, 18V or off.</para>
+<para>Usually, a satellite antenna subsystems require that the digital TV
+ device to send a DC voltage to feed power to the LNBf. Depending on the
+ LNBf type, the polarization or the intermediate frequency (IF) of the LNBf
+ can controlled by the voltage level. Other devices (for example, the ones
+ that implement DISEqC and multipoint LNBf's don't need to control the
+ voltage level, provided that either 13V or 18V is sent to power up the
+ LNBf.</para>
+<para>NOTE: if more than one device is connected to the same antenna,
+ setting a voltage level may interfere on other devices, as they may lose
+ the capability of setting polarization or IF. So, on those
+ cases, setting the voltage to SEC_VOLTAGE_OFF while the device is not is
+ used is recommended.</para>
+
+&return-value-dvb;
+</refsect1>
+
+</refentry>
diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml
index 8a6a6ff27af5..01210b33c130 100644
--- a/Documentation/DocBook/media/dvb/frontend.xml
+++ b/Documentation/DocBook/media/dvb/frontend.xml
@@ -1,485 +1,112 @@
<title>DVB Frontend API</title>
-<para>The DVB frontend device controls the tuner and DVB demodulator
-hardware. It can be accessed through <emphasis
-role="tt">/dev/dvb/adapter0/frontend0</emphasis>. Data types and and
-ioctl definitions can be accessed by including <emphasis
-role="tt">linux/dvb/frontend.h</emphasis> in your application.</para>
-
-<para>DVB frontends come in three varieties: DVB-S (satellite), DVB-C
-(cable) and DVB-T (terrestrial). Transmission via the internet (DVB-IP)
-is not yet handled by this API but a future extension is possible. For
-DVB-S the frontend device also supports satellite equipment control
-(SEC) via DiSEqC and V-SEC protocols. The DiSEqC (digital SEC)
-specification is available from
+<para>The DVB frontend API was designed to support three types of delivery systems:</para>
+<itemizedlist>
+ <listitem><para>Terrestrial systems: DVB-T, DVB-T2, ATSC, ATSC M/H, ISDB-T, DVB-H, DTMB, CMMB</para></listitem>
+ <listitem><para>Cable systems: DVB-C Annex A/C, ClearQAM (DVB-C Annex B), ISDB-C</para></listitem>
+ <listitem><para>Satellite systems: DVB-S, DVB-S2, DVB Turbo, ISDB-S, DSS</para></listitem>
+</itemizedlist>
+<para>The DVB frontend controls several sub-devices including:</para>
+<itemizedlist>
+ <listitem><para>Tuner</para></listitem>
+ <listitem><para>Digital TV demodulator</para></listitem>
+ <listitem><para>Low noise amplifier (LNA)</para></listitem>
+ <listitem><para>Satellite Equipment Control (SEC) hardware (only for Satellite).</para></listitem>
+</itemizedlist>
+<para>The frontend can be accessed through
+ <constant>/dev/dvb/adapter?/frontend?</constant>. Data types and
+ ioctl definitions can be accessed by including
+ <constant>linux/dvb/frontend.h</constant> in your application.
+</para>
+
+<para>NOTE: Transmission via the internet (DVB-IP)
+ is not yet handled by this API but a future extension is possible.</para>
+<para>On Satellite systems, the API support for the Satellite Equipment Control
+ (SEC) allows to power control and to send/receive signals to control the
+ antenna subsystem, selecting the polarization and choosing the Intermediate
+ Frequency IF) of the Low Noise Block Converter Feed Horn (LNBf). It
+ supports the DiSEqC and V-SEC protocols. The DiSEqC (digital SEC)
+specification is available at
<ulink url="http://www.eutelsat.com/satellites/4_5_5.html">Eutelsat</ulink>.</para>
-<para>Note that the DVB API may also be used for MPEG decoder-only PCI
-cards, in which case there exists no frontend device.</para>
-
-<section id="frontend_types">
-<title>Frontend Data Types</title>
-
-<section id="fe-type-t">
-<title>Frontend type</title>
-
-<para>For historical reasons, frontend types are named by the type of modulation used in
-transmission. The fontend types are given by fe_type_t type, defined as:</para>
-
-<table pgwide="1" frame="none" id="fe-type">
-<title>Frontend types</title>
-<tgroup cols="3">
- &cs-def;
- <thead>
- <row>
- <entry>fe_type</entry>
- <entry>Description</entry>
- <entry><link linkend="DTV-DELIVERY-SYSTEM">DTV_DELIVERY_SYSTEM</link> equivalent type</entry>
- </row>
- </thead>
- <tbody valign="top">
- <row>
- <entry id="FE_QPSK"><constant>FE_QPSK</constant></entry>
- <entry>For DVB-S standard</entry>
- <entry><constant>SYS_DVBS</constant></entry>
- </row>
- <row>
- <entry id="FE_QAM"><constant>FE_QAM</constant></entry>
- <entry>For DVB-C annex A standard</entry>
- <entry><constant>SYS_DVBC_ANNEX_A</constant></entry>
- </row>
- <row>
- <entry id="FE_OFDM"><constant>FE_OFDM</constant></entry>
- <entry>For DVB-T standard</entry>
- <entry><constant>SYS_DVBT</constant></entry>
- </row>
- <row>
- <entry id="FE_ATSC"><constant>FE_ATSC</constant></entry>
- <entry>For ATSC standard (terrestrial) or for DVB-C Annex B (cable) used in US.</entry>
- <entry><constant>SYS_ATSC</constant> (terrestrial) or <constant>SYS_DVBC_ANNEX_B</constant> (cable)</entry>
- </row>
-</tbody></tgroup></table>
-
-<para>Newer formats like DVB-S2, ISDB-T, ISDB-S and DVB-T2 are not described at the above, as they're
-supported via the new <link linkend="FE_GET_SET_PROPERTY">FE_GET_PROPERTY/FE_GET_SET_PROPERTY</link> ioctl's, using the <link linkend="DTV-DELIVERY-SYSTEM">DTV_DELIVERY_SYSTEM</link> parameter.
-</para>
-
-<para>The usage of this field is deprecated, as it doesn't report all supported standards, and
-will provide an incomplete information for frontends that support multiple delivery systems.
-Please use <link linkend="DTV-ENUM-DELSYS">DTV_ENUM_DELSYS</link> instead.</para>
-</section>
-
-<section id="fe-caps-t">
-<title>frontend capabilities</title>
-
-<para>Capabilities describe what a frontend can do. Some capabilities can only be supported for
-a specific frontend type.</para>
-<programlisting>
- typedef enum fe_caps {
- FE_IS_STUPID = 0,
- FE_CAN_INVERSION_AUTO = 0x1,
- FE_CAN_FEC_1_2 = 0x2,
- FE_CAN_FEC_2_3 = 0x4,
- FE_CAN_FEC_3_4 = 0x8,
- FE_CAN_FEC_4_5 = 0x10,
- FE_CAN_FEC_5_6 = 0x20,
- FE_CAN_FEC_6_7 = 0x40,
- FE_CAN_FEC_7_8 = 0x80,
- FE_CAN_FEC_8_9 = 0x100,
- FE_CAN_FEC_AUTO = 0x200,
- FE_CAN_QPSK = 0x400,
- FE_CAN_QAM_16 = 0x800,
- FE_CAN_QAM_32 = 0x1000,
- FE_CAN_QAM_64 = 0x2000,
- FE_CAN_QAM_128 = 0x4000,
- FE_CAN_QAM_256 = 0x8000,
- FE_CAN_QAM_AUTO = 0x10000,
- FE_CAN_TRANSMISSION_MODE_AUTO = 0x20000,
- FE_CAN_BANDWIDTH_AUTO = 0x40000,
- FE_CAN_GUARD_INTERVAL_AUTO = 0x80000,
- FE_CAN_HIERARCHY_AUTO = 0x100000,
- FE_CAN_8VSB = 0x200000,
- FE_CAN_16VSB = 0x400000,
- FE_HAS_EXTENDED_CAPS = 0x800000,
- FE_CAN_MULTISTREAM = 0x4000000,
- FE_CAN_TURBO_FEC = 0x8000000,
- FE_CAN_2G_MODULATION = 0x10000000,
- FE_NEEDS_BENDING = 0x20000000,
- FE_CAN_RECOVER = 0x40000000,
- FE_CAN_MUTE_TS = 0x80000000
- } fe_caps_t;
-</programlisting>
-</section>
-
-<section id="dvb-frontend-info">
-<title>frontend information</title>
-
-<para>Information about the frontend ca be queried with
- <link linkend="FE_GET_INFO">FE_GET_INFO</link>.</para>
-
-<programlisting>
- struct dvb_frontend_info {
- char name[128];
- fe_type_t type;
- uint32_t frequency_min;
- uint32_t frequency_max;
- uint32_t frequency_stepsize;
- uint32_t frequency_tolerance;
- uint32_t symbol_rate_min;
- uint32_t symbol_rate_max;
- uint32_t symbol_rate_tolerance; /&#x22C6; ppm &#x22C6;/
- uint32_t notifier_delay; /&#x22C6; ms &#x22C6;/
- fe_caps_t caps;
- };
-</programlisting>
-</section>
-
-<section id="dvb-diseqc-master-cmd">
-<title>diseqc master command</title>
-
-<para>A message sent from the frontend to DiSEqC capable equipment.</para>
-<programlisting>
- struct dvb_diseqc_master_cmd {
- uint8_t msg [6]; /&#x22C6; { framing, address, command, data[3] } &#x22C6;/
- uint8_t msg_len; /&#x22C6; valid values are 3...6 &#x22C6;/
- };
-</programlisting>
-</section>
-<section role="subsection" id="dvb-diseqc-slave-reply">
-<title>diseqc slave reply</title>
-
-<para>A reply to the frontend from DiSEqC 2.0 capable equipment.</para>
-<programlisting>
- struct dvb_diseqc_slave_reply {
- uint8_t msg [4]; /&#x22C6; { framing, data [3] } &#x22C6;/
- uint8_t msg_len; /&#x22C6; valid values are 0...4, 0 means no msg &#x22C6;/
- int timeout; /&#x22C6; return from ioctl after timeout ms with &#x22C6;/
- }; /&#x22C6; errorcode when no message was received &#x22C6;/
-</programlisting>
-</section>
-
-<section id="fe-sec-voltage-t">
-<title>diseqc slave reply</title>
-<para>The voltage is usually used with non-DiSEqC capable LNBs to switch the polarzation
-(horizontal/vertical). When using DiSEqC epuipment this voltage has to be switched
-consistently to the DiSEqC commands as described in the DiSEqC spec.</para>
-<programlisting>
- typedef enum fe_sec_voltage {
- SEC_VOLTAGE_13,
- SEC_VOLTAGE_18
- } fe_sec_voltage_t;
-</programlisting>
-</section>
-
-<section id="fe-sec-tone-mode-t">
-<title>SEC continuous tone</title>
+<section id="query-dvb-frontend-info">
+<title>Querying frontend information</title>
-<para>The continuous 22KHz tone is usually used with non-DiSEqC capable LNBs to switch the
-high/low band of a dual-band LNB. When using DiSEqC epuipment this voltage has to
-be switched consistently to the DiSEqC commands as described in the DiSEqC
-spec.</para>
-<programlisting>
- typedef enum fe_sec_tone_mode {
- SEC_TONE_ON,
- SEC_TONE_OFF
- } fe_sec_tone_mode_t;
-</programlisting>
+<para>Usually, the first thing to do when the frontend is opened is to
+ check the frontend capabilities. This is done using <link linkend="FE_GET_INFO">FE_GET_INFO</link>. This ioctl will enumerate
+ the DVB API version and other characteristics about the frontend, and
+ can be opened either in read only or read/write mode.</para>
</section>
-<section id="fe-sec-mini-cmd-t">
-<title>SEC tone burst</title>
-
-<para>The 22KHz tone burst is usually used with non-DiSEqC capable switches to select
-between two connected LNBs/satellites. When using DiSEqC epuipment this voltage has to
-be switched consistently to the DiSEqC commands as described in the DiSEqC
-spec.</para>
-<programlisting>
- typedef enum fe_sec_mini_cmd {
- SEC_MINI_A,
- SEC_MINI_B
- } fe_sec_mini_cmd_t;
-</programlisting>
-
-<para></para>
-</section>
-
-<section id="fe-status-t">
-<title>frontend status</title>
-<para>Several functions of the frontend device use the fe_status data type defined
-by</para>
-<programlisting>
-typedef enum fe_status {
- FE_HAS_SIGNAL = 0x01,
- FE_HAS_CARRIER = 0x02,
- FE_HAS_VITERBI = 0x04,
- FE_HAS_SYNC = 0x08,
- FE_HAS_LOCK = 0x10,
- FE_TIMEDOUT = 0x20,
- FE_REINIT = 0x40,
-} fe_status_t;
-</programlisting>
-<para>to indicate the current state and/or state changes of the frontend hardware:
-</para>
-
-<informaltable><tgroup cols="2"><tbody>
-<row>
-<entry align="char">FE_HAS_SIGNAL</entry>
-<entry align="char">The frontend has found something above the noise level</entry>
-</row><row>
-<entry align="char">FE_HAS_CARRIER</entry>
-<entry align="char">The frontend has found a DVB signal</entry>
-</row><row>
-<entry align="char">FE_HAS_VITERBI</entry>
-<entry align="char">The frontend FEC inner coding (Viterbi, LDPC or other inner code) is stable</entry>
-</row><row>
-<entry align="char">FE_HAS_SYNC</entry>
-<entry align="char">Synchronization bytes was found</entry>
-</row><row>
-<entry align="char">FE_HAS_LOCK</entry>
-<entry align="char">The DVB were locked and everything is working</entry>
-</row><row>
-<entry align="char">FE_TIMEDOUT</entry>
-<entry align="char">no lock within the last about 2 seconds</entry>
-</row><row>
-<entry align="char">FE_REINIT</entry>
-<entry align="char">The frontend was reinitialized, application is
-recommended to reset DiSEqC, tone and parameters</entry>
-</row>
-</tbody></tgroup></informaltable>
+<section id="dvb-fe-read-status">
+<title>Querying frontend status and statistics</title>
+<para>Once <link linkend="FE_GET_PROPERTY"><constant>FE_SET_PROPERTY</constant></link>
+ is called, the frontend will run a kernel thread that will periodically
+ check for the tuner lock status and provide statistics about the quality
+ of the signal.</para>
+<para>The information about the frontend tuner locking status can be queried
+ using <link linkend="FE_READ_STATUS">FE_READ_STATUS</link>.</para>
+<para>Signal statistics are provided via <link linkend="FE_GET_PROPERTY"><constant>FE_GET_PROPERTY</constant></link>.
+ Please note that several statistics require the demodulator to be fully
+ locked (e. g. with FE_HAS_LOCK bit set). See
+ <link linkend="frontend-stat-properties">Frontend statistics indicators</link>
+ for more details.</para>
</section>
-<section id="dvb-frontend-parameters">
-<title>frontend parameters</title>
-<para>The kind of parameters passed to the frontend device for tuning depend on
-the kind of hardware you are using.</para>
-<para>The struct <constant>dvb_frontend_parameters</constant> uses an
-union with specific per-system parameters. However, as newer delivery systems
-required more data, the structure size weren't enough to fit, and just
-extending its size would break the existing applications. So, those parameters
-were replaced by the usage of <link linkend="FE_GET_SET_PROPERTY">
-<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></link> ioctl's. The
-new API is flexible enough to add new parameters to existing delivery systems,
-and to add newer delivery systems.</para>
-<para>So, newer applications should use <link linkend="FE_GET_SET_PROPERTY">
-<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></link> instead, in
-order to be able to support the newer System Delivery like DVB-S2, DVB-T2,
-DVB-C2, ISDB, etc.</para>
-<para>All kinds of parameters are combined as an union in the FrontendParameters structure:
-<programlisting>
-struct dvb_frontend_parameters {
- uint32_t frequency; /&#x22C6; (absolute) frequency in Hz for QAM/OFDM &#x22C6;/
- /&#x22C6; intermediate frequency in kHz for QPSK &#x22C6;/
- fe_spectral_inversion_t inversion;
- union {
- struct dvb_qpsk_parameters qpsk;
- struct dvb_qam_parameters qam;
- struct dvb_ofdm_parameters ofdm;
- struct dvb_vsb_parameters vsb;
- } u;
-};
-</programlisting></para>
-<para>In the case of QPSK frontends the <constant>frequency</constant> field specifies the intermediate
-frequency, i.e. the offset which is effectively added to the local oscillator frequency (LOF) of
-the LNB. The intermediate frequency has to be specified in units of kHz. For QAM and
-OFDM frontends the <constant>frequency</constant> specifies the absolute frequency and is given in Hz.
-</para>
-
-<section id="dvb-qpsk-parameters">
-<title>QPSK parameters</title>
-<para>For satellite QPSK frontends you have to use the <constant>dvb_qpsk_parameters</constant> structure:</para>
-<programlisting>
- struct dvb_qpsk_parameters {
- uint32_t symbol_rate; /&#x22C6; symbol rate in Symbols per second &#x22C6;/
- fe_code_rate_t fec_inner; /&#x22C6; forward error correction (see above) &#x22C6;/
- };
-</programlisting>
-</section>
-<section id="dvb-qam-parameters">
-<title>QAM parameters</title>
-<para>for cable QAM frontend you use the <constant>dvb_qam_parameters</constant> structure:</para>
-<programlisting>
- struct dvb_qam_parameters {
- uint32_t symbol_rate; /&#x22C6; symbol rate in Symbols per second &#x22C6;/
- fe_code_rate_t fec_inner; /&#x22C6; forward error correction (see above) &#x22C6;/
- fe_modulation_t modulation; /&#x22C6; modulation type (see above) &#x22C6;/
- };
-</programlisting>
-</section>
-<section id="dvb-vsb-parameters">
-<title>VSB parameters</title>
-<para>ATSC frontends are supported by the <constant>dvb_vsb_parameters</constant> structure:</para>
-<programlisting>
-struct dvb_vsb_parameters {
- fe_modulation_t modulation; /&#x22C6; modulation type (see above) &#x22C6;/
-};
-</programlisting>
-</section>
-<section id="dvb-ofdm-parameters">
-<title>OFDM parameters</title>
-<para>DVB-T frontends are supported by the <constant>dvb_ofdm_parameters</constant> structure:</para>
-<programlisting>
- struct dvb_ofdm_parameters {
- fe_bandwidth_t bandwidth;
- fe_code_rate_t code_rate_HP; /&#x22C6; high priority stream code rate &#x22C6;/
- fe_code_rate_t code_rate_LP; /&#x22C6; low priority stream code rate &#x22C6;/
- fe_modulation_t constellation; /&#x22C6; modulation type (see above) &#x22C6;/
- fe_transmit_mode_t transmission_mode;
- fe_guard_interval_t guard_interval;
- fe_hierarchy_t hierarchy_information;
- };
-</programlisting>
-</section>
-<section id="fe-spectral-inversion-t">
-<title>frontend spectral inversion</title>
-<para>The Inversion field can take one of these values:
-</para>
-<programlisting>
-typedef enum fe_spectral_inversion {
- INVERSION_OFF,
- INVERSION_ON,
- INVERSION_AUTO
-} fe_spectral_inversion_t;
-</programlisting>
-<para>It indicates if spectral inversion should be presumed or not. In the automatic setting
-(<constant>INVERSION_AUTO</constant>) the hardware will try to figure out the correct setting by
-itself.
-</para>
-</section>
-<section id="fe-code-rate-t">
-<title>frontend code rate</title>
-<para>The possible values for the <constant>fec_inner</constant> field used on
-<link linkend="dvb-qpsk-parameters"><constant>struct dvb_qpsk_parameters</constant></link> and
-<link linkend="dvb-qam-parameters"><constant>struct dvb_qam_parameters</constant></link> are:
-</para>
-<programlisting>
-typedef enum fe_code_rate {
- FEC_NONE = 0,
- FEC_1_2,
- FEC_2_3,
- FEC_3_4,
- FEC_4_5,
- FEC_5_6,
- FEC_6_7,
- FEC_7_8,
- FEC_8_9,
- FEC_AUTO,
- FEC_3_5,
- FEC_9_10,
-} fe_code_rate_t;
-</programlisting>
-<para>which correspond to error correction rates of 1/2, 2/3, etc., no error correction or auto
-detection.
-</para>
-</section>
-<section id="fe-modulation-t">
-<title>frontend modulation type for QAM, OFDM and VSB</title>
-<para>For cable and terrestrial frontends, e. g. for
-<link linkend="dvb-qam-parameters"><constant>struct dvb_qpsk_parameters</constant></link>,
-<link linkend="dvb-ofdm-parameters"><constant>struct dvb_qam_parameters</constant></link> and
-<link linkend="dvb-vsb-parameters"><constant>struct dvb_qam_parameters</constant></link>,
-it needs to specify the quadrature modulation mode which can be one of the following:
-</para>
-<programlisting>
- typedef enum fe_modulation {
- QPSK,
- QAM_16,
- QAM_32,
- QAM_64,
- QAM_128,
- QAM_256,
- QAM_AUTO,
- VSB_8,
- VSB_16,
- PSK_8,
- APSK_16,
- APSK_32,
- DQPSK,
- } fe_modulation_t;
-</programlisting>
-</section>
-<section>
-<title>More OFDM parameters</title>
-<section id="fe-transmit-mode-t">
-<title>Number of carriers per channel</title>
-<programlisting>
-typedef enum fe_transmit_mode {
- TRANSMISSION_MODE_2K,
- TRANSMISSION_MODE_8K,
- TRANSMISSION_MODE_AUTO,
- TRANSMISSION_MODE_4K,
- TRANSMISSION_MODE_1K,
- TRANSMISSION_MODE_16K,
- TRANSMISSION_MODE_32K,
- } fe_transmit_mode_t;
-</programlisting>
-</section>
-<section id="fe-bandwidth-t">
-<title>frontend bandwidth</title>
-<programlisting>
-typedef enum fe_bandwidth {
- BANDWIDTH_8_MHZ,
- BANDWIDTH_7_MHZ,
- BANDWIDTH_6_MHZ,
- BANDWIDTH_AUTO,
- BANDWIDTH_5_MHZ,
- BANDWIDTH_10_MHZ,
- BANDWIDTH_1_712_MHZ,
-} fe_bandwidth_t;
-</programlisting>
-</section>
-<section id="fe-guard-interval-t">
-<title>frontend guard inverval</title>
-<programlisting>
-typedef enum fe_guard_interval {
- GUARD_INTERVAL_1_32,
- GUARD_INTERVAL_1_16,
- GUARD_INTERVAL_1_8,
- GUARD_INTERVAL_1_4,
- GUARD_INTERVAL_AUTO,
- GUARD_INTERVAL_1_128,
- GUARD_INTERVAL_19_128,
- GUARD_INTERVAL_19_256,
-} fe_guard_interval_t;
-</programlisting>
-</section>
-<section id="fe-hierarchy-t">
-<title>frontend hierarchy</title>
-<programlisting>
-typedef enum fe_hierarchy {
- HIERARCHY_NONE,
- HIERARCHY_1,
- HIERARCHY_2,
- HIERARCHY_4,
- HIERARCHY_AUTO
- } fe_hierarchy_t;
-</programlisting>
-</section>
-</section>
-
-</section>
-
-<section id="dvb-frontend-event">
-<title>frontend events</title>
- <programlisting>
- struct dvb_frontend_event {
- fe_status_t status;
- struct dvb_frontend_parameters parameters;
- };
-</programlisting>
- </section>
-</section>
-
+&sub-dvbproperty;
<section id="frontend_fcalls">
<title>Frontend Function Calls</title>
-<section id="frontend_f_open">
-<title>open()</title>
-<para>DESCRIPTION</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-<para>This system call opens a named frontend device (/dev/dvb/adapter0/frontend0)
+<refentry id="frontend_f_open">
+ <refmeta>
+ <refentrytitle>DVB frontend open()</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>fe-open</refname>
+ <refpurpose>Open a frontend device</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>int <function>open</function></funcdef>
+ <paramdef>const char *<parameter>device_name</parameter></paramdef>
+ <paramdef>int <parameter>flags</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>device_name</parameter></term>
+ <listitem>
+ <para>Device to be opened.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>flags</parameter></term>
+ <listitem>
+ <para>Open flags. Access can either be
+ <constant>O_RDWR</constant> or <constant>O_RDONLY</constant>.</para>
+ <para>Multiple opens are allowed with <constant>O_RDONLY</constant>. In this mode, only query and read ioctls are allowed.</para>
+ <para>Only one open is allowed in <constant>O_RDWR</constant>. In this mode, all ioctls are allowed.</para>
+ <para>When the <constant>O_NONBLOCK</constant> flag is given, the system calls may return &EAGAIN; when no data is available or when the device driver is temporarily busy.</para>
+ <para>Other flags have no effect.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>Description</title>
+ <para>This system call opens a named frontend device (<constant>/dev/dvb/adapter?/frontend?</constant>)
for subsequent use. Usually the first thing to do after a successful open is to
find out the frontend type with <link linkend="FE_GET_INFO">FE_GET_INFO</link>.</para>
<para>The device can be opened in read-only mode, which only allows monitoring of
@@ -497,1052 +124,146 @@ typedef enum fe_hierarchy {
for use in the specified mode. This implies that the corresponding hardware is
powered up, and that other front-ends may have been powered down to make
that possible.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int open(const char &#x22C6;deviceName, int flags);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>const char
- *deviceName</para>
-</entry><entry
- align="char">
-<para>Name of specific video device.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int flags</para>
-</entry><entry
- align="char">
-<para>A bit-wise OR of the following flags:</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDONLY read-only access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDWR read/write access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_NONBLOCK open in non-blocking mode</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>(blocking mode is the default)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="frontend_f_close">
-<title>close()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success <function>open</function> returns the new file
+descriptor. On error -1 is returned, and the <varname>errno</varname>
+variable is set appropriately. Possible error codes are:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EACCES</errorcode></term>
+ <listitem>
+ <para>The caller has no permission to access the
+device.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EBUSY</errorcode></term>
+ <listitem>
+ <para>The the device driver is already in use.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>ENXIO</errorcode></term>
+ <listitem>
+ <para>No device corresponding to this device special file
+exists.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>ENOMEM</errorcode></term>
+ <listitem>
+ <para>Not enough kernel memory was available to complete the
+request.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EMFILE</errorcode></term>
+ <listitem>
+ <para>The process already has the maximum number of
+files open.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>ENFILE</errorcode></term>
+ <listitem>
+ <para>The limit on the total number of files open on the
+system has been reached.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>ENODEV</errorcode></term>
+ <listitem>
+ <para>The device got removed.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
+
+<refentry id="frontend_f_close">
+ <refmeta>
+ <refentrytitle>DVB frontend close()</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>fe-close</refname>
+ <refpurpose>Close a frontend device</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>int <function>close</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
<para>This system call closes a previously opened front-end device. After closing
a front-end device, its corresponding hardware might be powered down
automatically.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int close(int fd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_READ_STATUS">
-<title>FE_READ_STATUS</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns status information about the front-end. This call only
- requires read-only access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_READ_STATUS">FE_READ_STATUS</link>,
- fe_status_t &#x22C6;status);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_STATUS">FE_READ_STATUS</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct fe_status_t
- *status</para>
-</entry><entry
- align="char">
-<para>Points to the location where the front-end status word is
- to be stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>status points to invalid address.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_READ_BER">
-<title>FE_READ_BER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the bit error rate for the signal currently
- received/demodulated by the front-end. For this command, read-only access to
- the device is sufficient.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_READ_BER">FE_READ_BER</link>,
- uint32_t &#x22C6;ber);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_BER">FE_READ_BER</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>uint32_t *ber</para>
-</entry><entry
- align="char">
-<para>The bit error rate is stored into *ber.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_READ_SNR">
-<title>FE_READ_SNR</title>
-
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the signal-to-noise ratio for the signal currently received
- by the front-end. For this command, read-only access to the device is sufficient.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_READ_SNR">FE_READ_SNR</link>, uint16_t
- &#x22C6;snr);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_SNR">FE_READ_SNR</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>uint16_t *snr</para>
-</entry><entry
- align="char">
-<para>The signal-to-noise ratio is stored into *snr.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_READ_SIGNAL_STRENGTH">
-<title>FE_READ_SIGNAL_STRENGTH</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the signal strength value for the signal currently received
- by the front-end. For this command, read-only access to the device is sufficient.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request =
- <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link>, uint16_t &#x22C6;strength);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link> for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>uint16_t *strength</para>
-</entry><entry
- align="char">
-<para>The signal strength value is stored into *strength.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_READ_UNCORRECTED_BLOCKS">
-<title>FE_READ_UNCORRECTED_BLOCKS</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the number of uncorrected blocks detected by the device
- driver during its lifetime. For meaningful measurements, the increment in block
- count during a specific time interval should be calculated. For this command,
- read-only access to the device is sufficient.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>Note that the counter will wrap to zero after its maximum count has been
- reached.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request =
- <link linkend="FE_READ_UNCORRECTED_BLOCKS">FE_READ_UNCORRECTED_BLOCKS</link>, uint32_t &#x22C6;ublocks);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_UNCORRECTED_BLOCKS">FE_READ_UNCORRECTED_BLOCKS</link> for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>uint32_t *ublocks</para>
-</entry><entry
- align="char">
-<para>The total number of uncorrected blocks seen by the driver
- so far.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_SET_FRONTEND">
-<title>FE_SET_FRONTEND</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call starts a tuning operation using specified parameters. The result
- of this call will be successful if the parameters were valid and the tuning could
- be initiated. The result of the tuning operation in itself, however, will arrive
- asynchronously as an event (see documentation for <link linkend="FE_GET_EVENT">FE_GET_EVENT</link> and
- FrontendEvent.) If a new <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> operation is initiated before
- the previous one was completed, the previous operation will be aborted in favor
- of the new one. This command requires read/write access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link>,
- struct dvb_frontend_parameters &#x22C6;p);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_frontend_parameters
- *p</para>
-</entry><entry
- align="char">
-<para>Points to parameters for tuning operation.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Maximum supported symbol rate reached.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_GET_FRONTEND">
-<title>FE_GET_FRONTEND</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call queries the currently effective frontend parameters. For this
- command, read-only access to the device is sufficient.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_GET_FRONTEND">FE_GET_FRONTEND</link>,
- struct dvb_frontend_parameters &#x22C6;p);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_frontend_parameters
- *p</para>
-</entry><entry
- align="char">
-<para>Points to parameters for tuning operation.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Maximum supported symbol rate reached.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-
-<section id="FE_GET_EVENT">
-<title>FE_GET_EVENT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns a frontend event if available. If an event is not
- available, the behavior depends on whether the device is in blocking or
- non-blocking mode. In the latter case, the call fails immediately with errno
- set to EWOULDBLOCK. In the former case, the call blocks until an event
- becomes available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The standard Linux poll() and/or select() system calls can be used with the
- device file descriptor to watch for new events. For select(), the file descriptor
- should be included in the exceptfds argument, and for poll(), POLLPRI should
- be specified as the wake-up condition. Since the event queue allocated is
- rather small (room for 8 events), the queue must be serviced regularly to avoid
- overflow. If an overflow happens, the oldest event is discarded from the queue,
- and an error (EOVERFLOW) occurs the next time the queue is read. After
- reporting the error condition in this fashion, subsequent
- <link linkend="FE_GET_EVENT">FE_GET_EVENT</link>
- calls will return events from the queue as usual.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>For the sake of implementation simplicity, this command requires read/write
- access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = QPSK_GET_EVENT,
- struct dvb_frontend_event &#x22C6;ev);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_GET_EVENT">FE_GET_EVENT</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_frontend_event
- *ev</para>
-</entry><entry
- align="char">
-<para>Points to the location where the event,</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>if any, is to be stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EWOULDBLOCK</para>
-</entry><entry
- align="char">
-<para>There is no event pending, and the device is in
- non-blocking mode.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EOVERFLOW</para>
-</entry><entry
- align="char">
-<para>Overflow in event queue - one or more events were lost.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_GET_INFO">
-<title>FE_GET_INFO</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns information about the front-end. This call only requires
- read-only access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(int fd, int request = <link linkend="FE_GET_INFO">FE_GET_INFO</link>, struct
- dvb_frontend_info &#x22C6;info);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_GET_INFO">FE_GET_INFO</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_frontend_info
- *info</para>
-</entry><entry
- align="char">
-<para>Points to the location where the front-end information is
- to be stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="FE_DISEQC_RESET_OVERLOAD">
-<title>FE_DISEQC_RESET_OVERLOAD</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>If the bus has been automatically powered off due to power overload, this ioctl
- call restores the power to the bus. The call requires read/write access to the
- device. This call has no effect if the device is manually powered off. Not all
- DVB adapters support this ioctl.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- <link linkend="FE_DISEQC_RESET_OVERLOAD">FE_DISEQC_RESET_OVERLOAD</link>);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_DISEQC_RESET_OVERLOAD">FE_DISEQC_RESET_OVERLOAD</link> for this
- command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_DISEQC_SEND_MASTER_CMD">
-<title>FE_DISEQC_SEND_MASTER_CMD</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call is used to send a a DiSEqC command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- <link linkend="FE_DISEQC_SEND_MASTER_CMD">FE_DISEQC_SEND_MASTER_CMD</link>, struct
- dvb_diseqc_master_cmd &#x22C6;cmd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_DISEQC_SEND_MASTER_CMD">FE_DISEQC_SEND_MASTER_CMD</link> for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_diseqc_master_cmd
- *cmd</para>
-</entry><entry
- align="char">
-<para>Pointer to the command to be transmitted.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
+</refsect1>
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>The function returns <returnvalue>0</returnvalue> on
+success, <returnvalue>-1</returnvalue> on failure and the
+<varname>errno</varname> is set appropriately. Possible error
+codes:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EBADF</errorcode></term>
+ <listitem>
+ <para><parameter>fd</parameter> is not a valid open file
+descriptor.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
+
+&sub-fe-get-info;
+&sub-fe-read-status;
+&sub-fe-get-property;
+&sub-fe-diseqc-reset-overload;
+&sub-fe-diseqc-send-master-cmd;
+&sub-fe-diseqc-recv-slave-reply;
+&sub-fe-diseqc-send-burst;
+&sub-fe-set-tone;
+&sub-fe-set-voltage;
+&sub-fe-enable-high-lnb-voltage;
+&sub-fe-set-frontend-tune-mode;
+
+</section>
+
+<section id="frontend_legacy_dvbv3_api">
+<title>DVB Frontend legacy API (a. k. a. DVBv3)</title>
+<para>The usage of this API is deprecated, as it doesn't support all digital
+ TV standards, doesn't provide good statistics measurements and provides
+ incomplete information. This is kept only to support legacy applications.</para>
+
+&sub-frontend_legacy_api;
</section>
-
-<section id="FE_DISEQC_RECV_SLAVE_REPLY">
-<title>FE_DISEQC_RECV_SLAVE_REPLY</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call is used to receive reply to a DiSEqC 2.0 command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- <link linkend="FE_DISEQC_RECV_SLAVE_REPLY">FE_DISEQC_RECV_SLAVE_REPLY</link>, struct
- dvb_diseqc_slave_reply &#x22C6;reply);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_DISEQC_RECV_SLAVE_REPLY">FE_DISEQC_RECV_SLAVE_REPLY</link> for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_diseqc_slave_reply
- *reply</para>
-</entry><entry
- align="char">
-<para>Pointer to the command to be received.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="FE_DISEQC_SEND_BURST">
-<title>FE_DISEQC_SEND_BURST</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call is used to send a 22KHz tone burst.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- <link linkend="FE_DISEQC_SEND_BURST">FE_DISEQC_SEND_BURST</link>, fe_sec_mini_cmd_t burst);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_DISEQC_SEND_BURST">FE_DISEQC_SEND_BURST</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>fe_sec_mini_cmd_t
- burst</para>
-</entry><entry
- align="char">
-<para>burst A or B.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_SET_TONE">
-<title>FE_SET_TONE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This call is used to set the generation of the continuous 22kHz tone. This call
- requires read/write permissions.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_SET_TONE">FE_SET_TONE</link>,
- fe_sec_tone_mode_t tone);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_TONE">FE_SET_TONE</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>fe_sec_tone_mode_t
- tone</para>
-</entry><entry
- align="char">
-<para>The requested tone generation mode (on/off).</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="FE_SET_VOLTAGE">
-<title>FE_SET_VOLTAGE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This call is used to set the bus voltage. This call requires read/write
- permissions.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_SET_VOLTAGE">FE_SET_VOLTAGE</link>,
- fe_sec_voltage_t voltage);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_VOLTAGE">FE_SET_VOLTAGE</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>fe_sec_voltage_t
- voltage</para>
-</entry><entry
- align="char">
-<para>The requested bus voltage.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_ENABLE_HIGH_LNB_VOLTAGE">
-<title>FE_ENABLE_HIGH_LNB_VOLTAGE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>If high != 0 enables slightly higher voltages instead of 13/18V (to compensate
- for long cables). This call requires read/write permissions. Not all DVB
- adapters support this ioctl.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- <link linkend="FE_ENABLE_HIGH_LNB_VOLTAGE">FE_ENABLE_HIGH_LNB_VOLTAGE</link>, int high);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_VOLTAGE">FE_SET_VOLTAGE</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int high</para>
-</entry><entry
- align="char">
-<para>The requested bus voltage.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_SET_FRONTEND_TUNE_MODE">
-<title>FE_SET_FRONTEND_TUNE_MODE</title>
-<para>DESCRIPTION</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-<para>Allow setting tuner mode flags to the frontend.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-<para>int ioctl(int fd, int request =
-<link linkend="FE_SET_FRONTEND_TUNE_MODE">FE_SET_FRONTEND_TUNE_MODE</link>, unsigned int flags);</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS</para>
-<informaltable><tgroup cols="2"><tbody><row>
-<entry align="char">
- <para>unsigned int flags</para>
-</entry>
-<entry align="char">
-<para>
-FE_TUNE_MODE_ONESHOT When set, this flag will disable any zigzagging or other "normal" tuning behaviour. Additionally, there will be no automatic monitoring of the lock status, and hence no frontend events will be generated. If a frontend device is closed, this flag will be automatically turned off when the device is reopened read-write.
-</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_DISHNETWORK_SEND_LEGACY_CMD">
- <title>FE_DISHNETWORK_SEND_LEGACY_CMD</title>
-<para>DESCRIPTION</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-<para>WARNING: This is a very obscure legacy command, used only at stv0299 driver. Should not be used on newer drivers.</para>
-<para>It provides a non-standard method for selecting Diseqc voltage on the frontend, for Dish Network legacy switches.</para>
-<para>As support for this ioctl were added in 2004, this means that such dishes were already legacy in 2004.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-<para>int ioctl(int fd, int request =
- <link linkend="FE_DISHNETWORK_SEND_LEGACY_CMD">FE_DISHNETWORK_SEND_LEGACY_CMD</link>, unsigned long cmd);</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS</para>
-<informaltable><tgroup cols="2"><tbody><row>
-<entry align="char">
- <para>unsigned long cmd</para>
-</entry>
-<entry align="char">
-<para>
-sends the specified raw cmd to the dish via DISEqC.
-</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-</section>
-
-&sub-dvbproperty;
diff --git a/Documentation/DocBook/media/dvb/frontend_legacy_api.xml b/Documentation/DocBook/media/dvb/frontend_legacy_api.xml
new file mode 100644
index 000000000000..8fadf3a4ba44
--- /dev/null
+++ b/Documentation/DocBook/media/dvb/frontend_legacy_api.xml
@@ -0,0 +1,654 @@
+<section id="frontend_legacy_types">
+<title>Frontend Legacy Data Types</title>
+
+<section id="fe-type-t">
+<title>Frontend type</title>
+
+<para>For historical reasons, frontend types are named by the type of modulation
+ used in transmission. The fontend types are given by fe_type_t type, defined as:</para>
+
+<table pgwide="1" frame="none" id="fe-type">
+<title>Frontend types</title>
+<tgroup cols="3">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>fe_type</entry>
+ <entry>Description</entry>
+ <entry><link linkend="DTV-DELIVERY-SYSTEM">DTV_DELIVERY_SYSTEM</link> equivalent type</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="FE-QPSK"><constant>FE_QPSK</constant></entry>
+ <entry>For DVB-S standard</entry>
+ <entry><constant>SYS_DVBS</constant></entry>
+ </row>
+ <row>
+ <entry id="FE-QAM"><constant>FE_QAM</constant></entry>
+ <entry>For DVB-C annex A standard</entry>
+ <entry><constant>SYS_DVBC_ANNEX_A</constant></entry>
+ </row>
+ <row>
+ <entry id="FE-OFDM"><constant>FE_OFDM</constant></entry>
+ <entry>For DVB-T standard</entry>
+ <entry><constant>SYS_DVBT</constant></entry>
+ </row>
+ <row>
+ <entry id="FE-ATSC"><constant>FE_ATSC</constant></entry>
+ <entry>For ATSC standard (terrestrial) or for DVB-C Annex B (cable) used in US.</entry>
+ <entry><constant>SYS_ATSC</constant> (terrestrial) or <constant>SYS_DVBC_ANNEX_B</constant> (cable)</entry>
+ </row>
+</tbody></tgroup></table>
+
+<para>Newer formats like DVB-S2, ISDB-T, ISDB-S and DVB-T2 are not described at the above, as they're
+supported via the new <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY/FE_GET_SET_PROPERTY</link> ioctl's, using the <link linkend="DTV-DELIVERY-SYSTEM">DTV_DELIVERY_SYSTEM</link> parameter.
+</para>
+
+<para>In the old days, &dvb-frontend-info; used to contain
+ <constant>fe_type_t</constant> field to indicate the delivery systems,
+ filled with either FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC. While this is
+ still filled to keep backward compatibility, the usage of this
+ field is deprecated, as it can report just one delivery system, but some
+ devices support multiple delivery systems. Please use
+ <link linkend="DTV-ENUM-DELSYS">DTV_ENUM_DELSYS</link> instead.
+</para>
+<para>On devices that support multiple delivery systems,
+ &dvb-frontend-info;::<constant>fe_type_t</constant> is filled with the
+ currently standard, as selected by the last call to
+ <link linkend="FE_GET_PROPERTY">FE_SET_PROPERTY</link>
+ using the &DTV-DELIVERY-SYSTEM; property.</para>
+</section>
+
+<section id="fe-bandwidth-t">
+<title>Frontend bandwidth</title>
+
+<table pgwide="1" frame="none" id="fe-bandwidth">
+ <title>enum fe_bandwidth</title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry id="BANDWIDTH-AUTO"><constant>BANDWIDTH_AUTO</constant></entry>
+ <entry>Autodetect bandwidth (if supported)</entry>
+ </row><row>
+ <entry id="BANDWIDTH-1-712-MHZ"><constant>BANDWIDTH_1_712_MHZ</constant></entry>
+ <entry>1.712 MHz</entry>
+ </row><row>
+ <entry id="BANDWIDTH-5-MHZ"><constant>BANDWIDTH_5_MHZ</constant></entry>
+ <entry>5 MHz</entry>
+ </row><row>
+ <entry id="BANDWIDTH-6-MHZ"><constant>BANDWIDTH_6_MHZ</constant></entry>
+ <entry>6 MHz</entry>
+ </row><row>
+ <entry id="BANDWIDTH-7-MHZ"><constant>BANDWIDTH_7_MHZ</constant></entry>
+ <entry>7 MHz</entry>
+ </row><row>
+ <entry id="BANDWIDTH-8-MHZ"><constant>BANDWIDTH_8_MHZ</constant></entry>
+ <entry>8 MHz</entry>
+ </row><row>
+ <entry id="BANDWIDTH-10-MHZ"><constant>BANDWIDTH_10_MHZ</constant></entry>
+ <entry>10 MHz</entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+
+</section>
+
+<section id="dvb-frontend-parameters">
+<title>frontend parameters</title>
+<para>The kind of parameters passed to the frontend device for tuning depend on
+the kind of hardware you are using.</para>
+<para>The struct <constant>dvb_frontend_parameters</constant> uses an
+union with specific per-system parameters. However, as newer delivery systems
+required more data, the structure size weren't enough to fit, and just
+extending its size would break the existing applications. So, those parameters
+were replaced by the usage of <link linkend="FE_GET_PROPERTY">
+<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></link> ioctl's. The
+new API is flexible enough to add new parameters to existing delivery systems,
+and to add newer delivery systems.</para>
+<para>So, newer applications should use <link linkend="FE_GET_PROPERTY">
+<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></link> instead, in
+order to be able to support the newer System Delivery like DVB-S2, DVB-T2,
+DVB-C2, ISDB, etc.</para>
+<para>All kinds of parameters are combined as an union in the FrontendParameters structure:
+<programlisting>
+struct dvb_frontend_parameters {
+ uint32_t frequency; /&#x22C6; (absolute) frequency in Hz for QAM/OFDM &#x22C6;/
+ /&#x22C6; intermediate frequency in kHz for QPSK &#x22C6;/
+ &fe-spectral-inversion-t; inversion;
+ union {
+ struct dvb_qpsk_parameters qpsk;
+ struct dvb_qam_parameters qam;
+ struct dvb_ofdm_parameters ofdm;
+ struct dvb_vsb_parameters vsb;
+ } u;
+};
+</programlisting></para>
+<para>In the case of QPSK frontends the <constant>frequency</constant> field specifies the intermediate
+frequency, i.e. the offset which is effectively added to the local oscillator frequency (LOF) of
+the LNB. The intermediate frequency has to be specified in units of kHz. For QAM and
+OFDM frontends the <constant>frequency</constant> specifies the absolute frequency and is given in Hz.
+</para>
+
+<section id="dvb-qpsk-parameters">
+<title>QPSK parameters</title>
+<para>For satellite QPSK frontends you have to use the <constant>dvb_qpsk_parameters</constant> structure:</para>
+<programlisting>
+ struct dvb_qpsk_parameters {
+ uint32_t symbol_rate; /&#x22C6; symbol rate in Symbols per second &#x22C6;/
+ &fe-code-rate-t; fec_inner; /&#x22C6; forward error correction (see above) &#x22C6;/
+ };
+</programlisting>
+</section>
+
+<section id="dvb-qam-parameters">
+<title>QAM parameters</title>
+<para>for cable QAM frontend you use the <constant>dvb_qam_parameters</constant> structure:</para>
+<programlisting>
+ struct dvb_qam_parameters {
+ uint32_t symbol_rate; /&#x22C6; symbol rate in Symbols per second &#x22C6;/
+ &fe-code-rate-t; fec_inner; /&#x22C6; forward error correction (see above) &#x22C6;/
+ &fe-modulation-t; modulation; /&#x22C6; modulation type (see above) &#x22C6;/
+ };
+</programlisting>
+</section>
+
+<section id="dvb-vsb-parameters">
+<title>VSB parameters</title>
+<para>ATSC frontends are supported by the <constant>dvb_vsb_parameters</constant> structure:</para>
+<programlisting>
+struct dvb_vsb_parameters {
+ &fe-modulation-t; modulation; /&#x22C6; modulation type (see above) &#x22C6;/
+};
+</programlisting>
+</section>
+
+<section id="dvb-ofdm-parameters">
+<title>OFDM parameters</title>
+<para>DVB-T frontends are supported by the <constant>dvb_ofdm_parameters</constant> structure:</para>
+<programlisting>
+ struct dvb_ofdm_parameters {
+ &fe-bandwidth-t; bandwidth;
+ &fe-code-rate-t; code_rate_HP; /&#x22C6; high priority stream code rate &#x22C6;/
+ &fe-code-rate-t; code_rate_LP; /&#x22C6; low priority stream code rate &#x22C6;/
+ &fe-modulation-t; constellation; /&#x22C6; modulation type (see above) &#x22C6;/
+ &fe-transmit-mode-t; transmission_mode;
+ &fe-guard-interval-t; guard_interval;
+ &fe-hierarchy-t; hierarchy_information;
+ };
+</programlisting>
+</section>
+</section>
+
+<section id="dvb-frontend-event">
+<title>frontend events</title>
+ <programlisting>
+ struct dvb_frontend_event {
+ fe_status_t status;
+ struct dvb_frontend_parameters parameters;
+ };
+</programlisting>
+ </section>
+</section>
+
+<section id="frontend_legacy_fcalls">
+<title>Frontend Legacy Function Calls</title>
+
+<para>Those functions are defined at DVB version 3. The support is kept in
+ the kernel due to compatibility issues only. Their usage is strongly
+ not recommended</para>
+
+<section id="FE_READ_BER">
+<title>FE_READ_BER</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns the bit error rate for the signal currently
+ received/demodulated by the front-end. For this command, read-only access to
+ the device is sufficient.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_READ_BER">FE_READ_BER</link>,
+ uint32_t &#x22C6;ber);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_READ_BER">FE_READ_BER</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>uint32_t *ber</para>
+</entry><entry
+ align="char">
+<para>The bit error rate is stored into *ber.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_READ_SNR">
+<title>FE_READ_SNR</title>
+
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns the signal-to-noise ratio for the signal currently received
+ by the front-end. For this command, read-only access to the device is sufficient.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_READ_SNR">FE_READ_SNR</link>, uint16_t
+ &#x22C6;snr);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_READ_SNR">FE_READ_SNR</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>uint16_t *snr</para>
+</entry><entry
+ align="char">
+<para>The signal-to-noise ratio is stored into *snr.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_READ_SIGNAL_STRENGTH">
+<title>FE_READ_SIGNAL_STRENGTH</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns the signal strength value for the signal currently received
+ by the front-end. For this command, read-only access to the device is sufficient.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl( int fd, int request =
+ <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link>, uint16_t &#x22C6;strength);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link> for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>uint16_t *strength</para>
+</entry><entry
+ align="char">
+<para>The signal strength value is stored into *strength.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_READ_UNCORRECTED_BLOCKS">
+<title>FE_READ_UNCORRECTED_BLOCKS</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns the number of uncorrected blocks detected by the device
+ driver during its lifetime. For meaningful measurements, the increment in block
+ count during a specific time interval should be calculated. For this command,
+ read-only access to the device is sufficient.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>Note that the counter will wrap to zero after its maximum count has been
+ reached.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl( int fd, int request =
+ <link linkend="FE_READ_UNCORRECTED_BLOCKS">FE_READ_UNCORRECTED_BLOCKS</link>, uint32_t &#x22C6;ublocks);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_READ_UNCORRECTED_BLOCKS">FE_READ_UNCORRECTED_BLOCKS</link> for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>uint32_t *ublocks</para>
+</entry><entry
+ align="char">
+<para>The total number of uncorrected blocks seen by the driver
+ so far.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_SET_FRONTEND">
+<title>FE_SET_FRONTEND</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call starts a tuning operation using specified parameters. The result
+ of this call will be successful if the parameters were valid and the tuning could
+ be initiated. The result of the tuning operation in itself, however, will arrive
+ asynchronously as an event (see documentation for <link linkend="FE_GET_EVENT">FE_GET_EVENT</link> and
+ FrontendEvent.) If a new <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> operation is initiated before
+ the previous one was completed, the previous operation will be aborted in favor
+ of the new one. This command requires read/write access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link>,
+ struct dvb_frontend_parameters &#x22C6;p);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct
+ dvb_frontend_parameters
+ *p</para>
+</entry><entry
+ align="char">
+<para>Points to parameters for tuning operation.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>Maximum supported symbol rate reached.</para>
+</entry>
+</row></tbody></tgroup></informaltable>
+</section>
+
+<section id="FE_GET_FRONTEND">
+<title>FE_GET_FRONTEND</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call queries the currently effective frontend parameters. For this
+ command, read-only access to the device is sufficient.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_GET_FRONTEND">FE_GET_FRONTEND</link>,
+ struct dvb_frontend_parameters &#x22C6;p);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct
+ dvb_frontend_parameters
+ *p</para>
+</entry><entry
+ align="char">
+<para>Points to parameters for tuning operation.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>Maximum supported symbol rate reached.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section>
+
+<section id="FE_GET_EVENT">
+<title>FE_GET_EVENT</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns a frontend event if available. If an event is not
+ available, the behavior depends on whether the device is in blocking or
+ non-blocking mode. In the latter case, the call fails immediately with errno
+ set to EWOULDBLOCK. In the former case, the call blocks until an event
+ becomes available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>The standard Linux poll() and/or select() system calls can be used with the
+ device file descriptor to watch for new events. For select(), the file descriptor
+ should be included in the exceptfds argument, and for poll(), POLLPRI should
+ be specified as the wake-up condition. Since the event queue allocated is
+ rather small (room for 8 events), the queue must be serviced regularly to avoid
+ overflow. If an overflow happens, the oldest event is discarded from the queue,
+ and an error (EOVERFLOW) occurs the next time the queue is read. After
+ reporting the error condition in this fashion, subsequent
+ <link linkend="FE_GET_EVENT">FE_GET_EVENT</link>
+ calls will return events from the queue as usual.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>For the sake of implementation simplicity, this command requires read/write
+ access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = QPSK_GET_EVENT,
+ struct dvb_frontend_event &#x22C6;ev);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_GET_EVENT">FE_GET_EVENT</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct
+ dvb_frontend_event
+ *ev</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the event,</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>if any, is to be stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EWOULDBLOCK</para>
+</entry><entry
+ align="char">
+<para>There is no event pending, and the device is in
+ non-blocking mode.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EOVERFLOW</para>
+</entry><entry
+ align="char">
+<para>Overflow in event queue - one or more events were lost.</para>
+</entry>
+</row></tbody></tgroup></informaltable>
+</section>
+
+<section id="FE_DISHNETWORK_SEND_LEGACY_CMD">
+ <title>FE_DISHNETWORK_SEND_LEGACY_CMD</title>
+<para>DESCRIPTION</para>
+<informaltable><tgroup cols="1"><tbody><row>
+<entry align="char">
+<para>WARNING: This is a very obscure legacy command, used only at stv0299 driver. Should not be used on newer drivers.</para>
+<para>It provides a non-standard method for selecting Diseqc voltage on the frontend, for Dish Network legacy switches.</para>
+<para>As support for this ioctl were added in 2004, this means that such dishes were already legacy in 2004.</para>
+</entry>
+</row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS</para>
+<informaltable><tgroup cols="1"><tbody><row>
+<entry align="char">
+<para>int ioctl(int fd, int request =
+ <link linkend="FE_DISHNETWORK_SEND_LEGACY_CMD">FE_DISHNETWORK_SEND_LEGACY_CMD</link>, unsigned long cmd);</para>
+</entry>
+</row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS</para>
+<informaltable><tgroup cols="2"><tbody><row>
+<entry align="char">
+ <para>unsigned long cmd</para>
+</entry>
+<entry align="char">
+<para>
+sends the specified raw cmd to the dish via DISEqC.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+</section>
diff --git a/Documentation/DocBook/media/dvb/intro.xml b/Documentation/DocBook/media/dvb/intro.xml
index 2048b53d19b9..bcc72c216402 100644
--- a/Documentation/DocBook/media/dvb/intro.xml
+++ b/Documentation/DocBook/media/dvb/intro.xml
@@ -129,41 +129,41 @@ hardware. It can depend on the individual security requirements of the
platform, if and how many of the CA functions are made available to the
application through this device.</para>
-<para>All devices can be found in the <emphasis role="tt">/dev</emphasis>
-tree under <emphasis role="tt">/dev/dvb</emphasis>. The individual devices
+<para>All devices can be found in the <constant>/dev</constant>
+tree under <constant>/dev/dvb</constant>. The individual devices
are called:</para>
<itemizedlist>
<listitem>
-<para><emphasis role="tt">/dev/dvb/adapterN/audioM</emphasis>,</para>
+<para><constant>/dev/dvb/adapterN/audioM</constant>,</para>
</listitem>
<listitem>
-<para><emphasis role="tt">/dev/dvb/adapterN/videoM</emphasis>,</para>
+<para><constant>/dev/dvb/adapterN/videoM</constant>,</para>
</listitem>
<listitem>
-<para><emphasis role="tt">/dev/dvb/adapterN/frontendM</emphasis>,</para>
+<para><constant>/dev/dvb/adapterN/frontendM</constant>,</para>
</listitem>
<listitem>
-<para><emphasis role="tt">/dev/dvb/adapterN/netM</emphasis>,</para>
+<para><constant>/dev/dvb/adapterN/netM</constant>,</para>
</listitem>
<listitem>
-<para><emphasis role="tt">/dev/dvb/adapterN/demuxM</emphasis>,</para>
+<para><constant>/dev/dvb/adapterN/demuxM</constant>,</para>
</listitem>
<listitem>
-<para><emphasis role="tt">/dev/dvb/adapterN/dvrM</emphasis>,</para>
+<para><constant>/dev/dvb/adapterN/dvrM</constant>,</para>
</listitem>
<listitem>
-<para><emphasis role="tt">/dev/dvb/adapterN/caM</emphasis>,</para></listitem></itemizedlist>
+<para><constant>/dev/dvb/adapterN/caM</constant>,</para></listitem></itemizedlist>
<para>where N enumerates the DVB PCI cards in a system starting
from&#x00A0;0, and M enumerates the devices of each type within each
-adapter, starting from&#x00A0;0, too. We will omit the &#8220;<emphasis
-role="tt">/dev/dvb/adapterN/</emphasis>&#8221; in the further dicussion
+adapter, starting from&#x00A0;0, too. We will omit the &#8220;
+<constant>/dev/dvb/adapterN/</constant>&#8221; in the further dicussion
of these devices. The naming scheme for the devices is the same wheter
devfs is used or not.</para>
@@ -202,10 +202,10 @@ a partial path like:</para>
</programlisting>
<para>To enable applications to support different API version, an
-additional include file <emphasis
-role="tt">linux/dvb/version.h</emphasis> exists, which defines the
-constant <emphasis role="tt">DVB_API_VERSION</emphasis>. This document
-describes <emphasis role="tt">DVB_API_VERSION 5.8</emphasis>.
+additional include file
+<constant>linux/dvb/version.h</constant> exists, which defines the
+constant <constant>DVB_API_VERSION</constant>. This document
+describes <constant>DVB_API_VERSION 5.10</constant>.
</para>
</section>
diff --git a/Documentation/DocBook/media/dvb/kdapi.xml b/Documentation/DocBook/media/dvb/kdapi.xml
index 6c11ec52cbee..68bcd33a82c3 100644
--- a/Documentation/DocBook/media/dvb/kdapi.xml
+++ b/Documentation/DocBook/media/dvb/kdapi.xml
@@ -1,8 +1,8 @@
<title>Kernel Demux API</title>
<para>The kernel demux API defines a driver-internal interface for registering low-level,
hardware specific driver to a hardware independent demux layer. It is only of interest for
-DVB device driver writers. The header file for this API is named <emphasis role="tt">demux.h</emphasis> and located in
-<emphasis role="tt">drivers/media/dvb-core</emphasis>.
+DVB device driver writers. The header file for this API is named <constant>demux.h</constant> and located in
+<constant>">drivers/media/dvb-core</constant>.
</para>
<para>Maintainer note: This section must be reviewed. It is probably out of date.
</para>
diff --git a/Documentation/DocBook/media/dvb/net.xml b/Documentation/DocBook/media/dvb/net.xml
index a193e86941b5..d2e44b7e07df 100644
--- a/Documentation/DocBook/media/dvb/net.xml
+++ b/Documentation/DocBook/media/dvb/net.xml
@@ -1,156 +1,238 @@
<title>DVB Network API</title>
-<para>The DVB net device enables feeding of MPE (multi protocol encapsulation) packets
-received via DVB into the Linux network protocol stack, e.g. for internet via satellite
-applications. It can be accessed through <emphasis role="tt">/dev/dvb/adapter0/net0</emphasis>. Data types and
-and ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/net.h</emphasis> in your
-application.
-</para>
-<section id="dvb_net_types">
-<title>DVB Net Data Types</title>
-
-<section id="dvb-net-if">
-<title>struct dvb_net_if</title>
-<programlisting>
-struct dvb_net_if {
- __u16 pid;
- __u16 if_num;
- __u8 feedtype;
-#define DVB_NET_FEEDTYPE_MPE 0 /&#x22C6; multi protocol encapsulation &#x22C6;/
-#define DVB_NET_FEEDTYPE_ULE 1 /&#x22C6; ultra lightweight encapsulation &#x22C6;/
-};
-</programlisting>
-</section>
+<para>The DVB net device controls the mapping of data packages that are
+ part of a transport stream to be mapped into a virtual network interface,
+ visible through the standard Linux network protocol stack.</para>
+<para>Currently, two encapsulations are supported:</para>
+<itemizedlist>
+ <listitem><para><ulink url="http://en.wikipedia.org/wiki/Multiprotocol_Encapsulation">
+ Multi Protocol Encapsulation (MPE)</ulink></para></listitem>
+ <listitem><para><ulink url="http://en.wikipedia.org/wiki/Unidirectional_Lightweight_Encapsulation">
+ Ultra Lightweight Encapsulation (ULE)</ulink></para></listitem>
+</itemizedlist>
+
+<para>In order to create the Linux virtual network interfaces, an application
+ needs to tell to the Kernel what are the PIDs and the encapsulation types
+ that are present on the transport stream. This is done through
+ <constant>/dev/dvb/adapter?/net?</constant> device node.
+ The data will be available via virtual <constant>dvb?_?</constant>
+ network interfaces, and will be controled/routed via the standard
+ ip tools (like ip, route, netstat, ifconfig, etc).</para>
+<para> Data types and and ioctl definitions are defined via
+ <constant>linux/dvb/net.h</constant> header.</para>
-</section>
<section id="net_fcalls">
<title>DVB net Function Calls</title>
-<para>To be written&#x2026;
-</para>
-
-<section id="NET_ADD_IF"
-role="subsection"><title>NET_ADD_IF</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = NET_ADD_IF,
- struct dvb_net_if *if);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals NET_ADD_IF for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct dvb_net_if *if
-</para>
-</entry><entry
- align="char">
-<para>Undocumented.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
+
+
+<refentry id="NET_ADD_IF">
+ <refmeta>
+ <refentrytitle>ioctl NET_ADD_IF</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>NET_ADD_IF</refname>
+ <refpurpose>Creates a new network interface for a given Packet ID.</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 dvb_net_if *<parameter>net_if</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_SET_TONE</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>net_if</parameter></term>
+ <listitem>
+ <para>pointer to &dvb-net-if;</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+<para>The NET_ADD_IF ioctl system call selects the Packet ID (PID) that
+ contains a TCP/IP traffic, the type of encapsulation to be used (MPE or ULE)
+ and the interface number for the new interface to be created. When the
+ system call successfully returns, a new virtual network interface is created.</para>
+<para>The &dvb-net-if;::ifnum field will be filled with the number of the
+ created interface.</para>
+
&return-value-dvb;
-</section>
+</refsect1>
+
+<refsect1 id="dvb-net-if-t">
+<title>struct <structname>dvb_net_if</structname> description</title>
+
+<table pgwide="1" frame="none" id="dvb-net-if">
+ <title>struct <structname>dvb_net_if</structname></title>
+ <tgroup cols="2">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>ID</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry align="char">pid</entry>
+ <entry align="char">Packet ID (PID) of the MPEG-TS that contains
+ data</entry>
+ </row><row>
+ <entry align="char">ifnum</entry>
+ <entry align="char">number of the DVB interface.</entry>
+ </row><row>
+ <entry align="char">feedtype</entry>
+ <entry align="char">Encapsulation type of the feed. It can be:
+ <constant>DVB_NET_FEEDTYPE_MPE</constant> for MPE encoding
+ or
+ <constant>DVB_NET_FEEDTYPE_ULE</constant> for ULE encoding.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+</table>
+</refsect1>
+</refentry>
+
+<refentry id="NET_REMOVE_IF">
+ <refmeta>
+ <refentrytitle>ioctl NET_REMOVE_IF</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>NET_REMOVE_IF</refname>
+ <refpurpose>Removes a network interface.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>int <parameter>ifnum</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_SET_TONE</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>net_if</parameter></term>
+ <listitem>
+ <para>number of the interface to be removed</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+<para>The NET_REMOVE_IF ioctl deletes an interface previously created
+ via &NET-ADD-IF;.</para>
-<section id="NET_REMOVE_IF"
-role="subsection"><title>NET_REMOVE_IF</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = NET_REMOVE_IF);
-</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals NET_REMOVE_IF for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
&return-value-dvb;
-</section>
+</refsect1>
+</refentry>
+
+
+<refentry id="NET_GET_IF">
+ <refmeta>
+ <refentrytitle>ioctl NET_GET_IF</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>NET_GET_IF</refname>
+ <refpurpose>Read the configuration data of an interface created via
+ &NET-ADD-IF;.</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 dvb_net_if *<parameter>net_if</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fe_fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>FE_SET_TONE</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>net_if</parameter></term>
+ <listitem>
+ <para>pointer to &dvb-net-if;</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+<para>The NET_GET_IF ioctl uses the interface number given by the
+ &dvb-net-if;::ifnum field and fills the content of &dvb-net-if; with
+ the packet ID and encapsulation type used on such interface. If the
+ interface was not created yet with &NET-ADD-IF;, it will return -1 and
+ fill the <constant>errno</constant> with <constant>EINVAL</constant>
+ error code.</para>
-<section id="NET_GET_IF"
-role="subsection"><title>NET_GET_IF</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = NET_GET_IF,
- struct dvb_net_if *if);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals NET_GET_IF for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct dvb_net_if *if
-</para>
-</entry><entry
- align="char">
-<para>Undocumented.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
&return-value-dvb;
-</section>
+</refsect1>
+</refentry>
</section>
diff --git a/Documentation/DocBook/media/dvb/video.xml b/Documentation/DocBook/media/dvb/video.xml
index 3ea1ca7e785e..71547fcd7ba0 100644
--- a/Documentation/DocBook/media/dvb/video.xml
+++ b/Documentation/DocBook/media/dvb/video.xml
@@ -1,12 +1,12 @@
<title>DVB Video Device</title>
<para>The DVB video device controls the MPEG2 video decoder of the DVB hardware. It
-can be accessed through <emphasis role="tt">/dev/dvb/adapter0/video0</emphasis>. Data types and and
-ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/video.h</emphasis> in your
+can be accessed through <emphasis role="bold">/dev/dvb/adapter0/video0</emphasis>. Data types and and
+ioctl definitions can be accessed by including <emphasis role="bold">linux/dvb/video.h</emphasis> in your
application.
</para>
<para>Note that the DVB video device only controls decoding of the MPEG video stream, not
its presentation on the TV or computer screen. On PCs this is typically handled by an
-associated video4linux device, e.g. <emphasis role="tt">/dev/video</emphasis>, which allows scaling and defining output
+associated video4linux device, e.g. <emphasis role="bold">/dev/video</emphasis>, which allows scaling and defining output
windows.
</para>
<para>Some DVB cards don&#8217;t have their own MPEG decoder, which results in the omission of
@@ -24,7 +24,7 @@ have been created to replace that functionality.</para>
<section id="video-format-t">
<title>video_format_t</title>
-<para>The <emphasis role="tt">video_format_t</emphasis> data type defined by
+<para>The <constant>video_format_t</constant> data type defined by
</para>
<programlisting>
typedef enum {
@@ -74,7 +74,7 @@ typedef enum {
</programlisting>
<para>VIDEO_SOURCE_DEMUX selects the demultiplexer (fed either by the frontend or the
DVR device) as the source of the video stream. If VIDEO_SOURCE_MEMORY
-is selected the stream comes from the application through the <emphasis role="tt">write()</emphasis> system
+is selected the stream comes from the application through the <emphasis role="bold">write()</emphasis> system
call.
</para>
</section>
diff --git a/Documentation/DocBook/media/typical_media_device.svg b/Documentation/DocBook/media/typical_media_device.svg
new file mode 100644
index 000000000000..f0c82f72c4b6
--- /dev/null
+++ b/Documentation/DocBook/media/typical_media_device.svg
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg stroke-linejoin="round" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" clip-path="url(#a)" xml:space="preserve" fill-rule="evenodd" height="178.78mm" viewBox="0 0 24285.662 17877.829" width="251.99mm" version="1.2" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" preserveAspectRatio="xMidYMid" stroke-width="28.222"><defs><clipPath id="a" clipPathUnits="userSpaceOnUse"><rect y="0" x="0" width="28000" height="21000"/></clipPath></defs><g transform="matrix(1.004 0 0 1 -2185.6 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#fcf" d="m12231 4800c-516 0-1031 515-1031 1031v4124c0 516 515 1032 1031 1032h8538c516 0 1032-516 1032-1032v-4124c0-516-516-1031-1032-1031h-8538z"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#ffc" d="m3595 15607c-293 0-585 292-585 585v2340c0 293 292 586 585 586h3275c293 0 586-293 586-586v-2340c0-293-293-585-586-585h-3275z"/></g><g transform="translate(-2197.3 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#e6e6e6" d="m2663 2186c-461 0-922 461-922 922v11169c0 461 461 923 922 923h3692c461 0 922-462 922-923v-11169c0-461-461-922-922-922h-3692z"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#ff8080" d="m4461 8602h-2260v-1086h4520v1086h-2260z"/><path fill="none" d="m4461 8602h-2260v-1086h4520v1086h-2260z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="8275" x="2579" class="TextPosition"><tspan fill="#000000">Audio decoder</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#ff8080" d="m4461 11772h-2260v-1270h4520v1270h-2260z"/><path fill="none" d="m4461 11772h-2260v-1270h4520v1270h-2260z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="11353" x="2617" class="TextPosition"><tspan fill="#000000">Video decoder</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#ff8080" d="m4453 10217h-2269v-1224h4537v1224h-2268z"/><path fill="none" d="m4453 10217h-2269v-1224h4537v1224h-2268z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="9821" x="2571" class="TextPosition"><tspan fill="#000000">Audio encoder</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2468.2)" class="com.sun.star.drawing.RectangleShape"><path fill="#cfc" d="m15711 12832h-3810v-1281h7620v1281h-3810z"/><path fill="none" d="m15711 12832h-3810v-1281h7620v1281h-3810z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="12407" x="12377" class="TextPosition"><tspan fill="#000000">Button Key/IR input logic</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2411.8)" class="com.sun.star.drawing.RectangleShape"><path fill="#cfe7f5" d="m14169 14572h-2268v-1412h4536v1412h-2268z"/><path fill="none" d="m14169 14572h-2268v-1412h4536v1412h-2268z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="14082" x="12882" class="TextPosition"><tspan fill="#000000">EEPROM</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#fc9" d="m5140 17662h-1563v-1715h3126v1715h-1563z"/><path fill="none" d="m5140 17662h-1563v-1715h3126v1715h-1563z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="17020" x="4276" class="TextPosition"><tspan fill="#000000">Sensor</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m6719 8030 385-353v176h1167v-176l386 353-386 354v-177h-1167v177l-385-354z"/><path fill="none" d="m6719 8030 385-353v176h1167v-176l386 353-386 354v-177h-1167v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m6719 9612 385-353v176h1167v-176l386 353-386 354v-177h-1167v177l-385-354z"/><path fill="none" d="m6719 9612 385-353v176h1167v-176l386 353-386 354v-177h-1167v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m6721 11100 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z"/><path fill="none" d="m6721 11100 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2411.8)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9962 13854 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z"/><path fill="none" d="m9962 13854 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2468.2)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9962 12163 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z"/><path fill="none" d="m9962 12163 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9962 17158 670-353v176h2028v-176l671 353-671 354v-177h-2028v177l-670-354z"/><path fill="none" d="m9962 17158 670-353v176h2028v-176l671 353-671 354v-177h-2028v177l-670-354z" stroke="#3465af"/></g><g transform="matrix(0 .83339 -1.0005 0 30268 -5276.3)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m23229 12779 1009-978 1009 978h-505v2959h505l-1009 979-1009-979h504v-2959h-504z"/><path fill="none" d="m23229 12779 1009-978 1009 978h-505v2959h505l-1009 979-1009-979h504v-2959h-504z" stroke="#3465af"/></g><g transform="translate(-9973.6 -666.6)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="706px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="15832" x="24341" class="TextPosition" transform="matrix(0,-1,1,0,8509,40173)"><tspan fill="#000000">System Bus</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#cff" d="m13151 9262h-1250v-875h2499v875h-1249z"/><path fill="none" d="m13151 9262h-1250v-875h2499v875h-1249z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="9040" x="12215" class="TextPosition"><tspan fill="#000000">Demux</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9996 8765 373-357v178h1130v-178l374 357-374 358v-179h-1130v179l-373-358z"/><path fill="none" d="m9996 8765 373-357v178h1130v-178l374 357-374 358v-179h-1130v179l-373-358z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9996 7378 373-358v179h1130v-179l374 358-374 358v-179h-1130v179l-373-358z"/><path fill="none" d="m9996 7378 373-358v179h1130v-179l374 358-374 358v-179h-1130v179l-373-358z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#cff" d="m16322 7992h-4421v-1270h8841v1270h-4420z"/><path fill="none" d="m16322 7992h-4421v-1270h8841v1270h-4420z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="7573" x="12786" class="TextPosition"><tspan fill="#000000">Conditional Access Module</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#ff8080" d="m4445 13287h-2269v-1224h4537v1224h-2268z"/><path fill="none" d="m4445 13287h-2269v-1224h4537v1224h-2268z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="12891" x="2601" class="TextPosition"><tspan fill="#000000">Video encoder</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m6721 12634 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z"/><path fill="none" d="m6721 12634 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m20791 7545 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z"/><path fill="none" d="m20791 7545 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2028 -2186)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="14478" x="1990" class="TextPosition"><tspan fill="#000000">Radio / Analog TV</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="700" class="TextParagraph"><tspan y="10724" x="14956" class="TextPosition"><tspan fill="#000000">Digital TV</tspan></tspan></tspan></text>
+</g><g transform="translate(-8970.5 -1395.8)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="494px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="19167" x="14724" class="TextPosition"><tspan fill="#000000">PS.: picture is not complete: other blocks may be present</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="18561" x="4199" class="TextPosition"><tspan fill="#000000">Webcam</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2468.2)" class="com.sun.star.drawing.RectangleShape"><path fill="#f90" d="m14552 16372h-2650v-1412h5299v1412h-2649z"/><path fill="none" d="m14552 16372h-2650v-1412h5299v1412h-2649z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="15882" x="12265" class="TextPosition"><tspan fill="#000000">Processing blocks</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2468.2)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9962 15654 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z"/><path fill="none" d="m9962 15654 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m6702 16954 397-353v176h1201v-176l398 353-398 354v-177h-1201v177l-397-354z"/><path fill="none" d="m6702 16954 397-353v176h1201v-176l398 353-398 354v-177h-1201v177l-397-354z" stroke="#3465af"/></g><g transform="translate(-2479.5 -2186)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="8792" x="22850" class="TextPosition"><tspan fill="#000000">Smartcard</tspan></tspan></tspan></text>
+</g><g transform="matrix(1.0048 0 0 1 -2207.4 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#fcf" d="m2766 2600c-333 0-666 333-666 666v2668c0 333 333 666 666 666h18368c333 0 667-333 667-666v-2668c0-333-334-666-667-666h-18368z"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#ff8080" d="m5121 5155h-1614v-1816h3227v1816h-1613z"/><path fill="none" d="m5121 5155h-1614v-1816h3227v1816h-1613z" stroke="#3465af"/><text font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextShape"><tspan class="TextParagraph"><tspan y="4111" x="4374" class="TextPosition"><tspan fill="#000000">Tuner</tspan></tspan></tspan><tspan class="TextParagraph"><tspan y="4814" x="4151" class="TextPosition"><tspan fill="#000000">FM/TV</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#ff8080" d="m2902 3702c0 111 40 202 88 202h530c48 0 89-91 89-202 0-110-41-202-89-202h-530c-48 0-88 92-88 202z"/><path fill="none" d="m2902 3702c0 111 40 202 88 202h530c48 0 89-91 89-202 0-110-41-202-89-202h-530c-48 0-88 92-88 202z" stroke="#3465af"/><path fill="#ffb3b3" d="m2902 3702c0 111 40 202 88 202s88-91 88-202c0-110-40-202-88-202s-88 92-88 202z"/><path fill="none" d="m2902 3702c0 111 40 202 88 202s88-91 88-202c0-110-40-202-88-202s-88 92-88 202z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#ff8080" d="m2903 4267c0 110 40 202 88 202h530c48 0 89-92 89-202s-41-203-89-203h-530c-48 0-88 93-88 203z"/><path fill="none" d="m2903 4267c0 110 40 202 88 202h530c48 0 89-92 89-202s-41-203-89-203h-530c-48 0-88 93-88 203z" stroke="#3465af"/><path fill="#ffb3b3" d="m2903 4267c0 110 40 202 88 202s88-92 88-202-40-203-88-203-88 93-88 203z"/><path fill="none" d="m2903 4267c0 110 40 202 88 202s88-92 88-202-40-203-88-203-88 93-88 203z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m6719 4196 385-353v176h1167v-176l386 353-386 354v-177h-1167v177l-385-354z"/><path fill="none" d="m6719 4196 385-353v176h1167v-176l386 353-386 354v-177h-1167v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9979 4150 402-368v184h1217v-184l403 368-403 369v-185h-1217v185l-402-369z"/><path fill="none" d="m9979 4150 402-368v184h1217v-184l403 368-403 369v-185h-1217v185l-402-369z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#cff" d="m16500 6189h-4500v-1389h9e3v1389h-4500z"/><path fill="none" d="m16500 6189h-4500v-1389h9e3v1389h-4500z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="5710" x="12051" class="TextPosition"><tspan fill="#000000">Satellite Equipment Control (SEC)</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#cff" d="m13400 4600h-1400v-1e3h2800v1e3h-1400z"/><path fill="none" d="m13400 4600h-1400v-1e3h2800v1e3h-1400z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="4316" x="12465" class="TextPosition"><tspan fill="#000000">Demod</tspan></tspan></tspan></text>
+</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9979 5451 402-368v184h1217v-184l403 368-403 369v-185h-1217v185l-402-369z"/><path fill="none" d="m9979 5451 402-368v184h1217v-184l403 368-403 369v-185h-1217v185l-402-369z" stroke="#3465af"/></g><path fill="#ff9" d="m7855.1 9099v7302h-1270v-14605h1270v7303z"/><path fill="none" d="m7855.1 9099v7302h-1270v-14605h1270v7303z" stroke="#3465af"/><text y="-6640.4663" x="-20770.572" transform="rotate(-90)" class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="7409.5396" x="-11193.634" class="TextPosition" transform="matrix(0,-1,1,0,-4473,23627)"><tspan fill="#000000">I2C Bus (control bus)</tspan></tspan></tspan></text>
+<g transform="translate(-2197.3 -2186)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="3278" x="9391" class="TextPosition"><tspan fill="#000000">Digital TV Frontend</tspan></tspan></tspan></text>
+</g><g transform="matrix(1.015 0 0 .99994 -2233.3 -2185.7)" class="com.sun.star.drawing.CustomShape"><g stroke="#3465af" fill="none"><path d="m3e3 2800c-18 0-35 1-53 3"/><path d="m2915 2808c-17 3-35 7-52 12"/><path d="m2832 2830c-16 6-33 12-49 20"/><path d="m2754 2864c-15 8-31 17-46 27"/><path d="m2681 2909c-14 10-28 21-42 32"/><path d="m2614 2962c-13 12-26 24-38 37"/><path d="m2554 3023c-11 13-22 27-33 41"/><path d="m2502 3091c-10 14-19 29-28 45"/><path d="m2459 3164c-8 16-15 32-22 49"/><path d="m2426 3243c-5 17-10 34-14 51"/><path d="m2406 3326c-3 18-5 35-6 53"/><path d="m2400 3411v53"/><path d="m2400 3497v53"/><path d="m2400 3582v53"/><path d="m2400 3668v53"/><path d="m2400 3753v53"/><path d="m2400 3839v53"/><path d="m2400 3924v53"/><path d="m2400 4009v54"/><path d="m2400 4095v53"/><path d="m2400 4180v53"/><path d="m2400 4266v53"/><path d="m2400 4351v53"/><path d="m2400 4437v53"/><path d="m2400 4522v53"/><path d="m2400 4607v54"/><path d="m2400 4693v53"/><path d="m2400 4778v53"/><path d="m2400 4864v53"/><path d="m2400 4949v53"/><path d="m2400 5035v53"/><path d="m2400 5120v53"/><path d="m2400 5205v54"/><path d="m2400 5291v53"/><path d="m2400 5376v53"/><path d="m2400 5462v53"/><path d="m2400 5547v53"/><path d="m2400 5633v53"/><path d="m2400 5718v53"/><path d="m2400 5803c0 18 1 36 3 53"/><path d="m2408 5888c4 18 8 35 13 52"/><path d="m2431 5971c6 16 13 33 20 49"/><path d="m2466 6049c8 15 17 31 27 46"/><path d="m2511 6122c10 14 21 28 32 42"/><path d="m2564 6188c12 13 25 26 38 38"/><path d="m2626 6248c13 11 27 23 41 33"/><path d="m2694 6300c14 10 29 19 45 27"/><path d="m2768 6343c15 7 32 15 48 21"/><path d="m2847 6375c17 5 34 10 51 14"/><path d="m2930 6395c17 2 35 4 53 5"/><path d="m3015 6400h53"/><path d="m3100 6400h53"/><path d="m3186 6400h53"/><path d="m3271 6400h53"/><path d="m3357 6400h53"/><path d="m3442 6400h53"/><path d="m3527 6400h54"/><path d="m3613 6400h53"/><path d="m3698 6400h53"/><path d="m3784 6400h53"/><path d="m3869 6400h53"/><path d="m3955 6400h53"/><path d="m4040 6400h53"/><path d="m4125 6400h54"/><path d="m4211 6400h53"/><path d="m4296 6400h53"/><path d="m4382 6400h53"/><path d="m4467 6400h53"/><path d="m4553 6400h53"/><path d="m4638 6400h53"/><path d="m4723 6400h54"/><path d="m4809 6400h53"/><path d="m4894 6400h53"/><path d="m4980 6400h53"/><path d="m5065 6400h53"/><path d="m5151 6400h53"/><path d="m5236 6400h53"/><path d="m5322 6400h53"/><path d="m5407 6400h53"/><path d="m5492 6400h53"/><path d="m5578 6400h53"/><path d="m5663 6400h53"/><path d="m5749 6400h53"/><path d="m5834 6400h53"/><path d="m5920 6400h53"/><path d="m6005 6400h53"/><path d="m6090 6400h53"/><path d="m6176 6400h53"/><path d="m6261 6400h53"/><path d="m6347 6400h53"/><path d="m6432 6400h53"/><path d="m6518 6400h53"/><path d="m6603 6400h53"/><path d="m6688 6400h54"/><path d="m6774 6400h53"/><path d="m6859 6400h53"/><path d="m6945 6400h53"/><path d="m7030 6400h53"/><path d="m7116 6400h53"/><path d="m7201 6400h53"/><path d="m7286 6400h54"/><path d="m7372 6400h53"/><path d="m7457 6400h53"/><path d="m7543 6400h53"/><path d="m7628 6400h53"/><path d="m7714 6400h53"/><path d="m7799 6400h53"/><path d="m7884 6400h54"/><path d="m7970 6400h53"/><path d="m8055 6400h53"/><path d="m8141 6400h53"/><path d="m8226 6400h53"/><path d="m8312 6400h53"/><path d="m8397 6400h53"/><path d="m8482 6400h54"/><path d="m8568 6400h53"/><path d="m8653 6400h53"/><path d="m8739 6400h53"/><path d="m8824 6400h53"/><path d="m8910 6400h53"/><path d="m8995 6400h53"/><path d="m9081 6400h53"/><path d="m9166 6400h53"/><path d="m9251 6400h53"/><path d="m9337 6400h53"/><path d="m9422 6400h53"/><path d="m9508 6400h53"/><path d="m9593 6400h53"/><path d="m9679 6400h53"/><path d="m9764 6400h53"/><path d="m9849 6400h53"/><path d="m9935 6400h53"/><path d="m10020 6400h53"/><path d="m10106 6400h53"/><path d="m10191 6400h53"/><path d="m10277 6400h53"/><path d="m10362 6400h53"/><path d="m10447 6400h53"/><path d="m10533 6400h53"/><path d="m10618 6400h53"/><path d="m10704 6400h53"/><path d="m10789 6400h53"/><path d="m10875 6400h53"/><path d="m10960 6400h53"/><path d="m11045 6400h54"/><path d="m11131 6400h53"/><path d="m11216 6400h53"/><path d="m11302 6400h53"/><path d="m11387 6400h53"/><path d="m11473 6400h53"/><path d="m11558 6400h53"/><path d="m11643 6400h54"/><path d="m11729 6400h53"/><path d="m11814 6400h53"/><path d="m11900 6400h53"/><path d="m11985 6400h53"/><path d="m12071 6400h53"/><path d="m12156 6400h53"/><path d="m12241 6400h54"/><path d="m12327 6400h53"/><path d="m12412 6400h53"/><path d="m12498 6400h53"/><path d="m12583 6400h53"/><path d="m12669 6400h53"/><path d="m12754 6400h53"/><path d="m12839 6400h54"/><path d="m12925 6400h53"/><path d="m13010 6400h53"/><path d="m13096 6400h53"/><path d="m13181 6400h53"/><path d="m13267 6400h53"/><path d="m13352 6400h53"/><path d="m13438 6400h53"/><path d="m13523 6400h53"/><path d="m13608 6400h53"/><path d="m13694 6400h53"/><path d="m13779 6400h53"/><path d="m13865 6400h53"/><path d="m13950 6400h53"/><path d="m14036 6400h53"/><path d="m14121 6400h53"/><path d="m14206 6400h53"/><path d="m14292 6400h53"/><path d="m14377 6400h53"/><path d="m14463 6400h53"/><path d="m14548 6400h53"/><path d="m14634 6400h53"/><path d="m14719 6400h53"/><path d="m14804 6400h54"/><path d="m14890 6400h53"/><path d="m14975 6400h53"/><path d="m15061 6400h53"/><path d="m15146 6400h53"/><path d="m15232 6400h53"/><path d="m15317 6400h53"/><path d="m15402 6400h54"/><path d="m15488 6400h53"/><path d="m15573 6400h53"/><path d="m15659 6400h53"/><path d="m15744 6400h53"/><path d="m15830 6400h53"/><path d="m15915 6400h53"/><path d="m16000 6400h54"/><path d="m16086 6400h53"/><path d="m16171 6400h53"/><path d="m16257 6400h53"/><path d="m16342 6400h53"/><path d="m16428 6400h53"/><path d="m16513 6400h53"/><path d="m16598 6400h54"/><path d="m16684 6400h53"/><path d="m16769 6400h53"/><path d="m16855 6400h53"/><path d="m16940 6400h53"/><path d="m17026 6400h53"/><path d="m17111 6400h53"/><path d="m17196 6400h54"/><path d="m17282 6400h53"/><path d="m17367 6400h53"/><path d="m17453 6400h53"/><path d="m17538 6400h53"/><path d="m17624 6400h53"/><path d="m17709 6400h53"/><path d="m17795 6400h53"/><path d="m17880 6400h53"/><path d="m17965 6400h53"/><path d="m18051 6400h53"/><path d="m18136 6400h53"/><path d="m18222 6400h53"/><path d="m18307 6400h53"/><path d="m18393 6400h53"/><path d="m18478 6400h53"/><path d="m18563 6400h53"/><path d="m18649 6400h53"/><path d="m18734 6400h53"/><path d="m18820 6400h53"/><path d="m18905 6400h53"/><path d="m18991 6400h53"/><path d="m19076 6400h53"/><path d="m19161 6400h54"/><path d="m19247 6400h53"/><path d="m19332 6400h53"/><path d="m19418 6400h53"/><path d="m19503 6400h53"/><path d="m19589 6400h53"/><path d="m19674 6400h53"/><path d="m19759 6400h54"/><path d="m19845 6400h53"/><path d="m19930 6400h53"/><path d="m20016 6400h53"/><path d="m20101 6400h53"/><path d="m20187 6400h53"/><path d="m20272 6400h53"/><path d="m20357 6400h54"/><path d="m20443 6400h53"/><path d="m20528 6400h53"/><path d="m20614 6400c17-1 35-2 53-5"/><path d="m20699 6390c17-4 34-9 51-14"/><path d="m20781 6365c16-6 32-13 48-21"/><path d="m20858 6329c15-8 31-17 45-27"/><path d="m20930 6283c14-10 28-21 42-32"/><path d="m20996 6229c13-12 25-25 37-38"/><path d="m21055 6167c11-14 22-28 33-42"/><path d="m21106 6098c10-15 19-30 27-45"/><path d="m21148 6024c7-16 14-33 20-49"/><path d="m21179 5944c5-17 9-34 13-51"/><path d="m21197 5861c2-18 4-35 4-53"/><path d="m21201 5776v-54"/><path d="m21201 5690v-53"/><path d="m21201 5605v-53"/><path d="m21201 5519v-53"/><path d="m21201 5434v-53"/><path d="m21201 5348v-53"/><path d="m21201 5263v-53"/><path d="m21201 5178v-54"/><path d="m21201 5092v-53"/><path d="m21201 5007v-53"/><path d="m21201 4921v-53"/><path d="m21201 4836v-53"/><path d="m21201 4750v-53"/><path d="m21201 4665v-53"/><path d="m21201 4579v-53"/><path d="m21201 4494v-53"/><path d="m21201 4409v-53"/><path d="m21201 4323v-53"/><path d="m21201 4238v-53"/><path d="m21201 4152v-53"/><path d="m21201 4067v-53"/><path d="m21201 3981v-53"/><path d="m21201 3896v-53"/><path d="m21201 3811v-53"/><path d="m21201 3725v-53"/><path d="m21201 3640v-53"/><path d="m21201 3554v-53"/><path d="m21201 3469v-53"/><path d="m21201 3383c-1-17-3-35-5-52"/><path d="m21190 3299c-4-17-8-35-14-51"/><path d="m21165 3217c-6-16-13-33-21-49"/><path d="m21129 3140c-9-16-18-31-28-46"/><path d="m21082 3068c-10-14-21-28-33-42"/><path d="m21027 3002c-12-13-24-25-37-37"/><path d="m20965 2944c-14-12-28-22-42-33"/><path d="m20896 2893c-15-9-30-18-46-27"/><path d="m20821 2852c-16-8-32-14-49-20"/><path d="m20741 2821c-17-5-34-9-51-12"/><path d="m20658 2804c-18-3-35-4-53-4"/><path d="m20573 2800h-53"/><path d="m20487 2800h-53"/><path d="m20402 2800h-53"/><path d="m20316 2800h-53"/><path d="m20231 2800h-53"/><path d="m20146 2800h-54"/><path d="m20060 2800h-53"/><path d="m19975 2800h-53"/><path d="m19889 2800h-53"/><path d="m19804 2800h-53"/><path d="m19718 2800h-53"/><path d="m19633 2800h-53"/><path d="m19548 2800h-54"/><path d="m19462 2800h-53"/><path d="m19377 2800h-53"/><path d="m19291 2800h-53"/><path d="m19206 2800h-53"/><path d="m19120 2800h-53"/><path d="m19035 2800h-53"/><path d="m18950 2800h-54"/><path d="m18864 2800h-53"/><path d="m18779 2800h-53"/><path d="m18693 2800h-53"/><path d="m18608 2800h-53"/><path d="m18522 2800h-53"/><path d="m18437 2800h-53"/><path d="m18352 2800h-54"/><path d="m18266 2800h-53"/><path d="m18181 2800h-53"/><path d="m18095 2800h-53"/><path d="m18010 2800h-53"/><path d="m17924 2800h-53"/><path d="m17839 2800h-53"/><path d="m17753 2800h-53"/><path d="m17668 2800h-53"/><path d="m17583 2800h-53"/><path d="m17497 2800h-53"/><path d="m17412 2800h-53"/><path d="m17326 2800h-53"/><path d="m17241 2800h-53"/><path d="m17155 2800h-53"/><path d="m17070 2800h-53"/><path d="m16985 2800h-53"/><path d="m16899 2800h-53"/><path d="m16814 2800h-53"/><path d="m16728 2800h-53"/><path d="m16643 2800h-53"/><path d="m16557 2800h-53"/><path d="m16472 2800h-53"/><path d="m16387 2800h-54"/><path d="m16301 2800h-53"/><path d="m16216 2800h-53"/><path d="m16130 2800h-53"/><path d="m16045 2800h-53"/><path d="m15959 2800h-53"/><path d="m15874 2800h-53"/><path d="m15789 2800h-54"/><path d="m15703 2800h-53"/><path d="m15618 2800h-53"/><path d="m15532 2800h-53"/><path d="m15447 2800h-53"/><path d="m15361 2800h-53"/><path d="m15276 2800h-53"/><path d="m15191 2800h-54"/><path d="m15105 2800h-53"/><path d="m15020 2800h-53"/><path d="m14934 2800h-53"/><path d="m14849 2800h-53"/><path d="m14763 2800h-53"/><path d="m14678 2800h-53"/><path d="m14593 2800h-54"/><path d="m14507 2800h-53"/><path d="m14422 2800h-53"/><path d="m14336 2800h-53"/><path d="m14251 2800h-53"/><path d="m14165 2800h-53"/><path d="m14080 2800h-53"/><path d="m13994 2800h-53"/><path d="m13909 2800h-53"/><path d="m13824 2800h-53"/><path d="m13738 2800h-53"/><path d="m13653 2800h-53"/><path d="m13567 2800h-53"/><path d="m13482 2800h-53"/><path d="m13396 2800h-53"/><path d="m13311 2800h-53"/><path d="m13226 2800h-53"/><path d="m13140 2800h-53"/><path d="m13055 2800h-53"/><path d="m12969 2800h-53"/><path d="m12884 2800h-53"/><path d="m12798 2800h-53"/><path d="m12713 2800h-53"/><path d="m12628 2800h-53"/><path d="m12542 2800h-53"/><path d="m12457 2800h-53"/><path d="m12371 2800h-53"/><path d="m12286 2800h-53"/><path d="m12200 2800h-53"/><path d="m12115 2800h-53"/><path d="m12030 2800h-54"/><path d="m11944 2800h-53"/><path d="m11859 2800h-53"/><path d="m11773 2800h-53"/><path d="m11688 2800h-53"/><path d="m11602 2800h-53"/><path d="m11517 2800h-53"/><path d="m11432 2800h-54"/><path d="m11346 2800h-53"/><path d="m11261 2800h-53"/><path d="m11175 2800h-53"/><path d="m11090 2800h-53"/><path d="m11004 2800h-53"/><path d="m10919 2800h-53"/><path d="m10834 2800h-54"/><path d="m10748 2800h-53"/><path d="m10663 2800h-53"/><path d="m10577 2800h-53"/><path d="m10492 2800h-53"/><path d="m10406 2800h-53"/><path d="m10321 2800h-53"/><path d="m10236 2800h-54"/><path d="m10150 2800h-53"/><path d="m10065 2800h-53"/><path d="m9979 2800h-53"/><path d="m9894 2800h-53"/><path d="m9808 2800h-53"/><path d="m9723 2800h-53"/><path d="m9637 2800h-53"/><path d="m9552 2800h-53"/><path d="m9467 2800h-53"/><path d="m9381 2800h-53"/><path d="m9296 2800h-53"/><path d="m9210 2800h-53"/><path d="m9125 2800h-53"/><path d="m9039 2800h-53"/><path d="m8954 2800h-53"/><path d="m8869 2800h-53"/><path d="m8783 2800h-53"/><path d="m8698 2800h-53"/><path d="m8612 2800h-53"/><path d="m8527 2800h-53"/><path d="m8441 2800h-53"/><path d="m8356 2800h-53"/><path d="m8271 2800h-54"/><path d="m8185 2800h-53"/><path d="m8100 2800h-53"/><path d="m8014 2800h-53"/><path d="m7929 2800h-53"/><path d="m7843 2800h-53"/><path d="m7758 2800h-53"/><path d="m7673 2800h-54"/><path d="m7587 2800h-53"/><path d="m7502 2800h-53"/><path d="m7416 2800h-53"/><path d="m7331 2800h-53"/><path d="m7245 2800h-53"/><path d="m7160 2800h-53"/><path d="m7075 2800h-54"/><path d="m6989 2800h-53"/><path d="m6904 2800h-53"/><path d="m6818 2800h-53"/><path d="m6733 2800h-53"/><path d="m6647 2800h-53"/><path d="m6562 2800h-53"/><path d="m6477 2800h-54"/><path d="m6391 2800h-53"/><path d="m6306 2800h-53"/><path d="m6220 2800h-53"/><path d="m6135 2800h-53"/><path d="m6049 2800h-53"/><path d="m5964 2800h-53"/><path d="m5879 2800h-54"/><path d="m5793 2800h-53"/><path d="m5708 2800h-53"/><path d="m5622 2800h-53"/><path d="m5537 2800h-53"/><path d="m5451 2800h-53"/><path d="m5366 2800h-53"/><path d="m5280 2800h-53"/><path d="m5195 2800h-53"/><path d="m5110 2800h-53"/><path d="m5024 2800h-53"/><path d="m4939 2800h-53"/><path d="m4853 2800h-53"/><path d="m4768 2800h-53"/><path d="m4682 2800h-53"/><path d="m4597 2800h-53"/><path d="m4512 2800h-53"/><path d="m4426 2800h-53"/><path d="m4341 2800h-53"/><path d="m4255 2800h-53"/><path d="m4170 2800h-53"/><path d="m4084 2800h-53"/><path d="m3999 2800h-53"/><path d="m3914 2800h-54"/><path d="m3828 2800h-53"/><path d="m3743 2800h-53"/><path d="m3657 2800h-53"/><path d="m3572 2800h-53"/><path d="m3486 2800h-53"/><path d="m3401 2800h-53"/><path d="m3316 2800h-54"/><path d="m3230 2800h-53"/><path d="m3145 2800h-53"/><path d="m3059 2800h-53"/></g></g><g transform="translate(-2197.3 -2186)"><rect height="1100.7" width="1213.6" y="6917.1" x="23255" fill="#f3e777"/><path fill="#ca4677" d="m22802 7700.4v-405.46l150.7-169.16c82.886-93.039 170.53-186.62 194.77-207.96l44.069-38.798 783.23-0.086 783.23-0.086v613.5 613.5h-978-978v-405.46zm1027.7 136.98v-78.372l-169.91 4.925-169.91 4.9249-5.09 45.854c-8.249 74.303 46.711 101.04 207.69 101.04h137.21v-78.372zm235.86-262.94 4.495-341.31 207.2-8.6408 207.2-8.6408 5.144-46.443c9.596-86.615-41.863-102.05-322.02-96.607l-246.71 4.7956-4.438 419.08-4.439 419.08h74.537 74.538l4.494-341.31zm391.3 313.72c26.41-19.286 36.255-41.399 32.697-73.447l-5.09-45.854h-174.05-174.05l-5.38 48.984c-9.97 90.771 0.993 97.91 150.36 97.91 99.305 0 148.27-7.6982 175.52-27.594zm-627.16-274.84v-77.768h-174.05-174.05v66.246c0 36.436 4.973 71.431 11.051 77.768 6.078 6.3366 84.401 11.521 174.05 11.521h163v-77.768zm659.89-4.9154 5.125-74.042-179.18 4.9155-179.18 4.9155-5.38 48.984c-10.473 95.348-2.259 99.57 183.28 94.197l170.2-4.9284 5.125-74.042zm-659.89-237.63v-78.372l-169.91 4.925-169.91 4.925-5.097 73.447-5.097 73.447h175 175v-78.372zm659.86 4.925-5.097-73.447h-174.05-174.05l-5.38 48.984c-10.289 93.673-2.146 97.91 188.15 97.91h175.52l-5.097-73.447zm-659.86-228.98v-77.768h-137.21c-97.358 0-147.91 7.8138-174.05 26.902-34.952 25.523-49.645 92.242-25.79 117.11 6.078 6.3366 84.401 11.521 174.05 11.521h163v-77.768z"/></g><g transform="matrix(.84874 0 0 .76147 2408.1 3615.3)"><rect height="3076.2" width="2734.3" y="13264" x="19249" fill="#6076b3"/><g stroke-linejoin="round" fill-rule="evenodd" stroke-width="28.222" fill="#e0ee2c"><rect y="13369" width="356.65" x="18937" height="180.95"/><rect y="13708" width="356.65" x="18937" height="180.95"/><rect y="14048" width="356.65" x="18937" height="180.95"/><rect y="14387" width="356.65" x="18937" height="180.95"/><rect y="14726" width="356.65" x="18937" height="180.95"/><rect y="15066" width="356.65" x="18937" height="180.95"/><rect y="15405" width="356.65" x="18937" height="180.95"/><rect y="15744" width="356.65" x="18937" height="180.95"/><rect y="16083" width="356.65" x="18937" height="180.95"/><rect y="13324" width="356.65" x="21939" height="180.95"/><rect y="13663" width="356.65" x="21939" height="180.95"/><rect y="14002" width="356.65" x="21939" height="180.95"/><rect y="14342" width="356.65" x="21939" height="180.95"/><rect y="14681" width="356.65" x="21939" height="180.95"/><rect y="15020" width="356.65" x="21939" height="180.95"/><rect y="15360" width="356.65" x="21939" height="180.95"/><rect y="15699" width="356.65" x="21939" height="180.95"/><rect y="16038" width="356.65" x="21939" height="180.95"/></g><g stroke-linejoin="round" fill-rule="evenodd" transform="matrix(.98702 0 0 .90336 -2675 7020.8)" class="com.sun.star.drawing.TextShape" stroke-width="28.222"><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"/></text>
+<text style="word-spacing:0px;letter-spacing:0px" xml:space="preserve" font-size="1128.9px" y="9042.0264" x="22439.668" font-family="Sans" line-height="125%" fill="#000000"><tspan y="9042.0264" x="22439.668">CPU</tspan></text>
+</g></g><g stroke-linejoin="round" fill-rule="evenodd" transform="translate(-11752 543.6)" class="com.sun.star.drawing.TextShape" stroke-width="28.222"><text class="TextShape"><tspan font-size="706px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="15832" x="24341" class="TextPosition" transform="matrix(0,-1,1,0,8509,40173)"><tspan fill="#000000">PCI, USB, SPI, I2C, ...</tspan></tspan></tspan></text>
+</g><g stroke-linejoin="round" fill-rule="evenodd" transform="translate(-655.31 963.83)" class="com.sun.star.drawing.RectangleShape" stroke-width="28.222"><g transform="matrix(.49166 0 0 1.0059 6045.6 -82.24)"><path fill="#cfe7f5" d="m14169 14572h-2268v-1412h4536v1412h-2268z"/><path fill="none" d="m14169 14572h-2268v-1412h4536v1412h-2268z" stroke="#3465af"/></g><text y="-395.11282" x="-790.22229" class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="13686.9" x="12091.779" class="TextPosition"><tspan fill="#000000">Bridge</tspan></tspan></tspan></text>
+<text y="338.66486" x="-846.66675" class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="14420.677" x="12035.335" class="TextPosition"><tspan fill="#000000"> DMA</tspan></tspan></tspan></text>
+</g></svg>
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 4e9462f1ab4c..6e1667b5f3eb 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -4863,7 +4863,7 @@ interface and may change in the future.</para>
</note>
<para>
- The Image Source control class is intended for low-level control of
+ The Image Process control class is intended for low-level control of
image processing functions. Unlike
<constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant>, the controls in
this class affect processing the image, and do not control capturing
@@ -4871,7 +4871,7 @@ interface and may change in the future.</para>
</para>
<table pgwide="1" frame="none" id="image-process-control-id">
- <title>Image Source Control IDs</title>
+ <title>Image Process Control IDs</title>
<tgroup cols="4">
<colspec colname="c1" colwidth="1*" />
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index 1c17f802b471..7bbc2a48911e 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -841,15 +841,15 @@ is the file descriptor associated with a DMABUF buffer.</entry>
<entry>__u32</entry>
<entry><structfield>reserved2</structfield></entry>
<entry></entry>
- <entry>A place holder for future extensions. Applications
-should set this to 0.</entry>
+ <entry>A place holder for future extensions. Drivers and applications
+must set this to 0.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>reserved</structfield></entry>
<entry></entry>
- <entry>A place holder for future extensions. Applications
-should set this to 0.</entry>
+ <entry>A place holder for future extensions. Drivers and applications
+must set this to 0.</entry>
</row>
</tbody>
</tgroup>
@@ -930,8 +930,8 @@ should set this to 0.</entry>
<entry>__u32</entry>
<entry><structfield>reserved[11]</structfield></entry>
<entry></entry>
- <entry>Reserved for future use. Should be zeroed by an
- application.</entry>
+ <entry>Reserved for future use. Should be zeroed by drivers and
+ applications.</entry>
</row>
</tbody>
</tgroup>
@@ -1129,6 +1129,18 @@ in this buffer has not been created by the CPU but by some DMA-capable unit,
in which case caches have not been used.</entry>
</row>
<row>
+ <entry><constant>V4L2_BUF_FLAG_LAST</constant></entry>
+ <entry>0x00100000</entry>
+ <entry>Last buffer produced by the hardware. mem2mem codec drivers
+set this flag on the capture queue for the last buffer when the
+<link linkend="vidioc-querybuf">VIDIOC_QUERYBUF</link> or
+<link linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl is called. Due to hardware
+limitations, the last buffer may be empty. In this case the driver will set the
+<structfield>bytesused</structfield> field to 0, regardless of the format. Any
+Any subsequent call to the <link linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl
+will not block anymore, but return an &EPIPE;.</entry>
+ </row>
+ <row>
<entry><constant>V4L2_BUF_FLAG_TIMESTAMP_MASK</constant></entry>
<entry>0x0000e000</entry>
<entry>Mask for timestamp types below. To test the
@@ -1155,7 +1167,7 @@ in which case caches have not been used.</entry>
<entry>The buffer timestamp has been taken from the
<constant>CLOCK_MONOTONIC</constant> clock. To access the
same clock outside V4L2, use
- <function>clock_gettime(2)</function> .</entry>
+ <function>clock_gettime(2)</function>.</entry>
</row>
<row>
<entry><constant>V4L2_BUF_FLAG_TIMESTAMP_COPY</constant></entry>
diff --git a/Documentation/DocBook/media/v4l/media-func-open.xml b/Documentation/DocBook/media/v4l/media-func-open.xml
index f7df034dc9ed..122374a3e894 100644
--- a/Documentation/DocBook/media/v4l/media-func-open.xml
+++ b/Documentation/DocBook/media/v4l/media-func-open.xml
@@ -44,7 +44,7 @@
<para>To open a media device applications call <function>open()</function>
with the desired device name. The function has no side effects; the device
configuration remain unchanged.</para>
- <para>When the device is opened in read-only mode, attemps to modify its
+ <para>When the device is opened in read-only mode, attempts to modify its
configuration will result in an error, and <varname>errno</varname> will be
set to <errorcode>EBADF</errorcode>.</para>
</refsect1>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y16-be.xml b/Documentation/DocBook/media/v4l/pixfmt-y16-be.xml
new file mode 100644
index 000000000000..cea53e1eaa43
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/pixfmt-y16-be.xml
@@ -0,0 +1,81 @@
+<refentry id="V4L2-PIX-FMT-Y16-BE">
+ <refmeta>
+ <refentrytitle>V4L2_PIX_FMT_Y16_BE ('Y16 ' | (1 &lt;&lt; 31))</refentrytitle>
+ &manvol;
+ </refmeta>
+ <refnamediv>
+ <refname><constant>V4L2_PIX_FMT_Y16_BE</constant></refname>
+ <refpurpose>Grey-scale image</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>Description</title>
+
+ <para>This is a grey-scale image with a depth of 16 bits per
+pixel. The most significant byte is stored at lower memory addresses
+(big-endian). Note the actual sampling precision may be lower than
+16 bits, for example 10 bits per pixel with values in range 0 to
+1023.</para>
+
+ <example>
+ <title><constant>V4L2_PIX_FMT_Y16_BE</constant> 4 &times; 4
+pixel image</title>
+
+ <formalpara>
+ <title>Byte Order.</title>
+ <para>Each cell is one byte.
+ <informaltable frame="none">
+ <tgroup cols="9" align="center">
+ <colspec align="left" colwidth="2*" />
+ <tbody valign="top">
+ <row>
+ <entry>start&nbsp;+&nbsp;0:</entry>
+ <entry>Y'<subscript>00high</subscript></entry>
+ <entry>Y'<subscript>00low</subscript></entry>
+ <entry>Y'<subscript>01high</subscript></entry>
+ <entry>Y'<subscript>01low</subscript></entry>
+ <entry>Y'<subscript>02high</subscript></entry>
+ <entry>Y'<subscript>02low</subscript></entry>
+ <entry>Y'<subscript>03high</subscript></entry>
+ <entry>Y'<subscript>03low</subscript></entry>
+ </row>
+ <row>
+ <entry>start&nbsp;+&nbsp;8:</entry>
+ <entry>Y'<subscript>10high</subscript></entry>
+ <entry>Y'<subscript>10low</subscript></entry>
+ <entry>Y'<subscript>11high</subscript></entry>
+ <entry>Y'<subscript>11low</subscript></entry>
+ <entry>Y'<subscript>12high</subscript></entry>
+ <entry>Y'<subscript>12low</subscript></entry>
+ <entry>Y'<subscript>13high</subscript></entry>
+ <entry>Y'<subscript>13low</subscript></entry>
+ </row>
+ <row>
+ <entry>start&nbsp;+&nbsp;16:</entry>
+ <entry>Y'<subscript>20high</subscript></entry>
+ <entry>Y'<subscript>20low</subscript></entry>
+ <entry>Y'<subscript>21high</subscript></entry>
+ <entry>Y'<subscript>21low</subscript></entry>
+ <entry>Y'<subscript>22high</subscript></entry>
+ <entry>Y'<subscript>22low</subscript></entry>
+ <entry>Y'<subscript>23high</subscript></entry>
+ <entry>Y'<subscript>23low</subscript></entry>
+ </row>
+ <row>
+ <entry>start&nbsp;+&nbsp;24:</entry>
+ <entry>Y'<subscript>30high</subscript></entry>
+ <entry>Y'<subscript>30low</subscript></entry>
+ <entry>Y'<subscript>31high</subscript></entry>
+ <entry>Y'<subscript>31low</subscript></entry>
+ <entry>Y'<subscript>32high</subscript></entry>
+ <entry>Y'<subscript>32low</subscript></entry>
+ <entry>Y'<subscript>33high</subscript></entry>
+ <entry>Y'<subscript>33low</subscript></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ </formalpara>
+ </example>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
index fcde4e20205e..965ea916784a 100644
--- a/Documentation/DocBook/media/v4l/pixfmt.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt.xml
@@ -157,6 +157,14 @@ see <xref linkend="colorspaces" />.</entry>
capture streams and by the application for output streams,
see <xref linkend="colorspaces" />.</entry>
</row>
+ <row>
+ <entry>&v4l2-xfer-func;</entry>
+ <entry><structfield>xfer_func</structfield></entry>
+ <entry>This information supplements the
+<structfield>colorspace</structfield> and must be set by the driver for
+capture streams and by the application for output streams,
+see <xref linkend="colorspaces" />.</entry>
+ </row>
</tbody>
</tgroup>
</table>
@@ -190,8 +198,8 @@ see <xref linkend="colorspaces" />.</entry>
<row>
<entry>__u16</entry>
<entry><structfield>reserved[6]</structfield></entry>
- <entry>Reserved for future extensions. Should be zeroed by the
- application.</entry>
+ <entry>Reserved for future extensions. Should be zeroed by drivers and
+ applications.</entry>
</row>
</tbody>
</tgroup>
@@ -264,11 +272,19 @@ see <xref linkend="colorspaces" />.</entry>
capture streams and by the application for output streams,
see <xref linkend="colorspaces" />.</entry>
</row>
+ <row>
+ <entry>&v4l2-xfer-func;</entry>
+ <entry><structfield>xfer_func</structfield></entry>
+ <entry>This information supplements the
+<structfield>colorspace</structfield> and must be set by the driver for
+capture streams and by the application for output streams,
+see <xref linkend="colorspaces" />.</entry>
+ </row>
<row>
<entry>__u8</entry>
- <entry><structfield>reserved[8]</structfield></entry>
- <entry>Reserved for future extensions. Should be zeroed by the
- application.</entry>
+ <entry><structfield>reserved[7]</structfield></entry>
+ <entry>Reserved for future extensions. Should be zeroed by drivers
+ and applications.</entry>
</row>
</tbody>
</tgroup>
@@ -476,15 +492,16 @@ is also very useful.</para>
<section>
<title>Defining Colorspaces in V4L2</title>
- <para>In V4L2 colorspaces are defined by three values. The first is the colorspace
-identifier (&v4l2-colorspace;) which defines the chromaticities, the transfer
+ <para>In V4L2 colorspaces are defined by four values. The first is the colorspace
+identifier (&v4l2-colorspace;) which defines the chromaticities, the default transfer
function, the default Y'CbCr encoding and the default quantization method. The second
-is the Y'CbCr encoding identifier (&v4l2-ycbcr-encoding;) to specify non-standard
-Y'CbCr encodings and the third is the quantization identifier (&v4l2-quantization;)
-to specify non-standard quantization methods. Most of the time only the colorspace
-field of &v4l2-pix-format; or &v4l2-pix-format-mplane; needs to be filled in. Note
-that the default R'G'B' quantization is full range for all colorspaces except for
-BT.2020 which uses limited range R'G'B' quantization.</para>
+is the transfer function identifier (&v4l2-xfer-func;) to specify non-standard
+transfer functions. The third is the Y'CbCr encoding identifier (&v4l2-ycbcr-encoding;)
+to specify non-standard Y'CbCr encodings and the fourth is the quantization identifier
+(&v4l2-quantization;) to specify non-standard quantization methods. Most of the time
+only the colorspace field of &v4l2-pix-format; or &v4l2-pix-format-mplane; needs to
+be filled in. Note that the default R'G'B' quantization is full range for all
+colorspaces except for BT.2020 which uses limited range R'G'B' quantization.</para>
<table pgwide="1" frame="none" id="v4l2-colorspace">
<title>V4L2 Colorspaces</title>
@@ -498,6 +515,11 @@ BT.2020 which uses limited range R'G'B' quantization.</para>
</thead>
<tbody valign="top">
<row>
+ <entry><constant>V4L2_COLORSPACE_DEFAULT</constant></entry>
+ <entry>The default colorspace. This can be used by applications to let the
+ driver fill in the colorspace.</entry>
+ </row>
+ <row>
<entry><constant>V4L2_COLORSPACE_SMPTE170M</constant></entry>
<entry>See <xref linkend="col-smpte-170m" />.</entry>
</row>
@@ -533,6 +555,52 @@ BT.2020 which uses limited range R'G'B' quantization.</para>
<entry><constant>V4L2_COLORSPACE_JPEG</constant></entry>
<entry>See <xref linkend="col-jpeg" />.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_COLORSPACE_RAW</constant></entry>
+ <entry>The raw colorspace. This is used for raw image capture where
+ the image is minimally processed and is using the internal colorspace
+ of the device. The software that processes an image using this
+ 'colorspace' will have to know the internals of the capture device.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="v4l2-xfer-func">
+ <title>V4L2 Transfer Function</title>
+ <tgroup cols="2" align="left">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>Identifier</entry>
+ <entry>Details</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_XFER_FUNC_DEFAULT</constant></entry>
+ <entry>Use the default transfer function as defined by the colorspace.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_XFER_FUNC_709</constant></entry>
+ <entry>Use the Rec. 709 transfer function.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_XFER_FUNC_SRGB</constant></entry>
+ <entry>Use the sRGB transfer function.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_XFER_FUNC_ADOBERGB</constant></entry>
+ <entry>Use the AdobeRGB transfer function.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_XFER_FUNC_SMPTE240M</constant></entry>
+ <entry>Use the SMPTE 240M transfer function.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_XFER_FUNC_NONE</constant></entry>
+ <entry>Do not use a transfer function (i.e. use linear RGB values).</entry>
+ </row>
</tbody>
</tgroup>
</table>
@@ -624,7 +692,8 @@ is mapped to [16&hellip;235]. Cb and Cr are mapped from [-0.5&hellip;0.5] to [16
<section id="col-smpte-170m">
<title>Colorspace SMPTE 170M (<constant>V4L2_COLORSPACE_SMPTE170M</constant>)</title>
<para>The <xref linkend="smpte170m" /> standard defines the colorspace used by NTSC and PAL and by SDTV
-in general. The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>.
+in general. The default transfer function is <constant>V4L2_XFER_FUNC_709</constant>.
+The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>.
The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and
the white reference are:</para>
<table frame="none">
@@ -706,7 +775,8 @@ rarely seen.</para>
<section id="col-rec709">
<title>Colorspace Rec. 709 (<constant>V4L2_COLORSPACE_REC709</constant>)</title>
- <para>The <xref linkend="itu709" /> standard defines the colorspace used by HDTV in general. The default
+ <para>The <xref linkend="itu709" /> standard defines the colorspace used by HDTV in general.
+The default transfer function is <constant>V4L2_XFER_FUNC_709</constant>. The default
Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_709</constant>. The default Y'CbCr quantization is
limited range. The chromaticities of the primary colors and the white reference are:</para>
<table frame="none">
@@ -817,9 +887,11 @@ The xvYCC encodings always use full range quantization.</para>
<section id="col-srgb">
<title>Colorspace sRGB (<constant>V4L2_COLORSPACE_SRGB</constant>)</title>
- <para>The <xref linkend="srgb" /> standard defines the colorspace used by most webcams and computer graphics. The
-default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_SYCC</constant>. The default Y'CbCr quantization
-is full range. The chromaticities of the primary colors and the white reference are:</para>
+ <para>The <xref linkend="srgb" /> standard defines the colorspace used by most webcams
+and computer graphics. The default transfer function is <constant>V4L2_XFER_FUNC_SRGB</constant>.
+The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_SYCC</constant>. The default Y'CbCr
+quantization is full range. The chromaticities of the primary colors and the white
+reference are:</para>
<table frame="none">
<title>sRGB Chromaticities</title>
<tgroup cols="3" align="left">
@@ -896,6 +968,7 @@ values before quantization, but this encoding does not do that.</para>
<title>Colorspace Adobe RGB (<constant>V4L2_COLORSPACE_ADOBERGB</constant>)</title>
<para>The <xref linkend="adobergb" /> standard defines the colorspace used by computer graphics
that use the AdobeRGB colorspace. This is also known as the <xref linkend="oprgb" /> standard.
+The default transfer function is <constant>V4L2_XFER_FUNC_ADOBERGB</constant>.
The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>. The default Y'CbCr
quantization is limited range. The chromaticities of the primary colors and the white reference
are:</para>
@@ -967,7 +1040,8 @@ SMPTE 170M/BT.601. The Y'CbCr quantization is limited range.</para>
<section id="col-bt2020">
<title>Colorspace BT.2020 (<constant>V4L2_COLORSPACE_BT2020</constant>)</title>
<para>The <xref linkend="itu2020" /> standard defines the colorspace used by Ultra-high definition
-television (UHDTV). The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_BT2020</constant>.
+television (UHDTV). The default transfer function is <constant>V4L2_XFER_FUNC_709</constant>.
+The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_BT2020</constant>.
The default R'G'B' quantization is limited range (!), and so is the default Y'CbCr quantization.
The chromaticities of the primary colors and the white reference are:</para>
<table frame="none">
@@ -1082,8 +1156,10 @@ clamped to the range [-0.5&hellip;0.5]. The Yc'CbcCrc quantization is limited ra
<section id="col-smpte-240m">
<title>Colorspace SMPTE 240M (<constant>V4L2_COLORSPACE_SMPTE240M</constant>)</title>
- <para>The <xref linkend="smpte240m" /> standard was an interim standard used during the early days of HDTV (1988-1998).
-It has been superseded by Rec. 709. The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_SMPTE240M</constant>.
+ <para>The <xref linkend="smpte240m" /> standard was an interim standard used during
+the early days of HDTV (1988-1998). It has been superseded by Rec. 709.
+The default transfer function is <constant>V4L2_XFER_FUNC_SMPTE240M</constant>.
+The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_SMPTE240M</constant>.
The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and the
white reference are:</para>
<table frame="none">
@@ -1156,8 +1232,10 @@ clamped to the range [-0.5&hellip;0.5]. The Y'CbCr quantization is limited range
<section id="col-sysm">
<title>Colorspace NTSC 1953 (<constant>V4L2_COLORSPACE_470_SYSTEM_M</constant>)</title>
<para>This standard defines the colorspace used by NTSC in 1953. In practice this
-colorspace is obsolete and SMPTE 170M should be used instead. The default Y'CbCr encoding
-is <constant>V4L2_YCBCR_ENC_601</constant>. The default Y'CbCr quantization is limited range.
+colorspace is obsolete and SMPTE 170M should be used instead.
+The default transfer function is <constant>V4L2_XFER_FUNC_709</constant>.
+The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>.
+The default Y'CbCr quantization is limited range.
The chromaticities of the primary colors and the white reference are:</para>
<table frame="none">
<title>NTSC 1953 Chromaticities</title>
@@ -1234,8 +1312,10 @@ This transform is identical to one defined in SMPTE 170M/BT.601.</para>
<section id="col-sysbg">
<title>Colorspace EBU Tech. 3213 (<constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant>)</title>
<para>The <xref linkend="tech3213" /> standard defines the colorspace used by PAL/SECAM in 1975. In practice this
-colorspace is obsolete and SMPTE 170M should be used instead. The default Y'CbCr encoding
-is <constant>V4L2_YCBCR_ENC_601</constant>. The default Y'CbCr quantization is limited range.
+colorspace is obsolete and SMPTE 170M should be used instead.
+The default transfer function is <constant>V4L2_XFER_FUNC_709</constant>.
+The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>.
+The default Y'CbCr quantization is limited range.
The chromaticities of the primary colors and the white reference are:</para>
<table frame="none">
<title>EBU Tech. 3213 Chromaticities</title>
@@ -1308,7 +1388,8 @@ This transform is identical to one defined in SMPTE 170M/BT.601.</para>
<section id="col-jpeg">
<title>Colorspace JPEG (<constant>V4L2_COLORSPACE_JPEG</constant>)</title>
<para>This colorspace defines the colorspace used by most (Motion-)JPEG formats. The chromaticities
-of the primary colors and the white reference are identical to sRGB. The Y'CbCr encoding is
+of the primary colors and the white reference are identical to sRGB. The transfer
+function use is <constant>V4L2_XFER_FUNC_SRGB</constant>. The Y'CbCr encoding is
<constant>V4L2_YCBCR_ENC_601</constant> with full range quantization where
Y' is scaled to [0&hellip;255] and Cb/Cr are scaled to [-128&hellip;128] and
then clipped to [-128&hellip;127].</para>
@@ -1429,6 +1510,7 @@ information.</para>
&sub-y12;
&sub-y10b;
&sub-y16;
+ &sub-y16-be;
&sub-uv8;
&sub-yuyv;
&sub-uyvy;
diff --git a/Documentation/DocBook/media/v4l/remote_controllers.xml b/Documentation/DocBook/media/v4l/remote_controllers.xml
index 5124a6c4daa8..b86844e80257 100644
--- a/Documentation/DocBook/media/v4l/remote_controllers.xml
+++ b/Documentation/DocBook/media/v4l/remote_controllers.xml
@@ -284,7 +284,7 @@ different IR's. Due to that, V4L2 API now specifies a standard for mapping Media
</tgroup>
</table>
-<para>It should be noticed that, sometimes, there some fundamental missing keys at some cheaper IR's. Due to that, it is recommended to:</para>
+<para>It should be noted that, sometimes, there some fundamental missing keys at some cheaper IR's. Due to that, it is recommended to:</para>
<table pgwide="1" frame="none" id="rc_keymap_notes">
<title>Notes</title>
diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml
index 2588ad781242..4e73345e3eab 100644
--- a/Documentation/DocBook/media/v4l/subdev-formats.xml
+++ b/Documentation/DocBook/media/v4l/subdev-formats.xml
@@ -50,8 +50,16 @@ capture streams and by the application for output streams,
see <xref linkend="colorspaces" />.</entry>
</row>
<row>
- <entry>__u32</entry>
- <entry><structfield>reserved</structfield>[6]</entry>
+ <entry>&v4l2-xfer-func;</entry>
+ <entry><structfield>xfer_func</structfield></entry>
+ <entry>This information supplements the
+<structfield>colorspace</structfield> and must be set by the driver for
+capture streams and by the application for output streams,
+see <xref linkend="colorspaces" />.</entry>
+ </row>
+ <row>
+ <entry>__u16</entry>
+ <entry><structfield>reserved</structfield>[11]</entry>
<entry>Reserved for future extensions. Applications and drivers must
set the array to zero.</entry>
</row>
diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
index 9b700a5f4df7..8ffe74f84af1 100644
--- a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
@@ -134,7 +134,8 @@ information.</para>
<row>
<entry>__u32</entry>
<entry><structfield>reserved</structfield>[8]</entry>
- <entry>A place holder for future extensions.</entry>
+ <entry>A place holder for future extensions. Drivers and applications
+must set the array to zero.</entry>
</row>
</tbody>
</tgroup>
diff --git a/Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml b/Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml
index 9215627b04c7..73eb5cfe698a 100644
--- a/Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml
@@ -197,7 +197,17 @@ be muted when playing back at a non-standard speed.
this command does nothing. This command has two flags:
if <constant>V4L2_DEC_CMD_STOP_TO_BLACK</constant> is set, then the decoder will
set the picture to black after it stopped decoding. Otherwise the last image will
-repeat. If <constant>V4L2_DEC_CMD_STOP_IMMEDIATELY</constant> is set, then the decoder
+repeat. mem2mem decoders will stop producing new frames altogether. They will send
+a <constant>V4L2_EVENT_EOS</constant> event when the last frame has been decoded
+and all frames are ready to be dequeued and will set the
+<constant>V4L2_BUF_FLAG_LAST</constant> buffer flag on the last buffer of the
+capture queue to indicate there will be no new buffers produced to dequeue. This
+buffer may be empty, indicated by the driver setting the
+<structfield>bytesused</structfield> field to 0. Once the
+<constant>V4L2_BUF_FLAG_LAST</constant> flag was set, the
+<link linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl will not block anymore,
+but return an &EPIPE;.
+If <constant>V4L2_DEC_CMD_STOP_IMMEDIATELY</constant> is set, then the decoder
stops immediately (ignoring the <structfield>pts</structfield> value), otherwise it
will keep decoding until timestamp >= pts or until the last of the pending data from
its internal buffers was decoded.
diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
index 50ccd33948c1..c9c3c7713832 100644
--- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
@@ -133,7 +133,10 @@
<entry>struct timespec</entry>
<entry><structfield>timestamp</structfield></entry>
<entry></entry>
- <entry>Event timestamp.</entry>
+ <entry>Event timestamp. The timestamp has been taken from the
+ <constant>CLOCK_MONOTONIC</constant> clock. To access the
+ same clock outside V4L2, use <function>clock_gettime(2)</function>.
+ </entry>
</row>
<row>
<entry>u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml b/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml
index 0619ca5d2d36..fc1d4625a78c 100644
--- a/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml
@@ -129,7 +129,15 @@ this command.</entry>
encoding will continue until the end of the current <wordasword>Group
Of Pictures</wordasword>, otherwise encoding will stop immediately.
When the encoder is already stopped, this command does
-nothing.</entry>
+nothing. mem2mem encoders will send a <constant>V4L2_EVENT_EOS</constant> event
+when the last frame has been decoded and all frames are ready to be dequeued and
+will set the <constant>V4L2_BUF_FLAG_LAST</constant> buffer flag on the last
+buffer of the capture queue to indicate there will be no new buffers produced to
+dequeue. This buffer may be empty, indicated by the driver setting the
+<structfield>bytesused</structfield> field to 0. Once the
+<constant>V4L2_BUF_FLAG_LAST</constant> flag was set, the
+<link linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl will not block anymore,
+but return an &EPIPE;.</entry>
</row>
<row>
<entry><constant>V4L2_ENC_CMD_PAUSE</constant></entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml b/Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml
index 5fd72c4c33e3..7c839ab0afbb 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml
@@ -217,7 +217,8 @@ enumerated.</entry>
<entry>__u32</entry>
<entry><structfield>reserved[2]</structfield></entry>
<entry></entry>
- <entry>Reserved space for future use.</entry>
+ <entry>Reserved space for future use. Must be zeroed by drivers and
+ applications.</entry>
</row>
</tbody>
</tgroup>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml b/Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml
index a78454b5abcd..9ed68ac8f474 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml
@@ -223,7 +223,8 @@ application should zero out all members except for the
<entry>__u32</entry>
<entry><structfield>reserved[2]</structfield></entry>
<entry></entry>
- <entry>Reserved space for future use.</entry>
+ <entry>Reserved space for future use. Must be zeroed by drivers and
+ applications.</entry>
</row>
</tbody>
</tgroup>
diff --git a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml
index 4165e7bfa4ff..a78c9207422f 100644
--- a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml
@@ -184,7 +184,8 @@ of open() for more details.</entry>
<row>
<entry>__u32</entry>
<entry><structfield>reserved[11]</structfield></entry>
- <entry>Reserved field for future use. Must be set to zero.</entry>
+ <entry>Reserved field for future use. Drivers and applications must
+set the array to zero.</entry>
</row>
</tbody>
</tgroup>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml
index 764b635ed4cf..06952d7cc770 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml
@@ -7,6 +7,8 @@
<refnamediv>
<refname>VIDIOC_G_DV_TIMINGS</refname>
<refname>VIDIOC_S_DV_TIMINGS</refname>
+ <refname>VIDIOC_SUBDEV_G_DV_TIMINGS</refname>
+ <refname>VIDIOC_SUBDEV_S_DV_TIMINGS</refname>
<refpurpose>Get or set DV timings for input or output</refpurpose>
</refnamediv>
@@ -34,7 +36,7 @@
<varlistentry>
<term><parameter>request</parameter></term>
<listitem>
- <para>VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS</para>
+ <para>VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS, VIDIOC_SUBDEV_G_DV_TIMINGS, VIDIOC_SUBDEV_S_DV_TIMINGS</para>
</listitem>
</varlistentry>
<varlistentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml
index 6df40db4c8ba..2702536bbc7c 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml
@@ -7,6 +7,8 @@
<refnamediv>
<refname>VIDIOC_G_EDID</refname>
<refname>VIDIOC_S_EDID</refname>
+ <refname>VIDIOC_SUBDEV_G_EDID</refname>
+ <refname>VIDIOC_SUBDEV_S_EDID</refname>
<refpurpose>Get or set the EDID of a video receiver/transmitter</refpurpose>
</refnamediv>
@@ -42,7 +44,7 @@
<varlistentry>
<term><parameter>request</parameter></term>
<listitem>
- <para>VIDIOC_G_EDID, VIDIOC_S_EDID</para>
+ <para>VIDIOC_G_EDID, VIDIOC_S_EDID, VIDIOC_SUBDEV_G_EDID, VIDIOC_SUBDEV_S_EDID</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -82,6 +84,13 @@
<para>If blocks have to be retrieved from the sink, then this call will block until they
have been read.</para>
+ <para>If <structfield>start_block</structfield> and <structfield>blocks</structfield> are
+ both set to 0 when <constant>VIDIOC_G_EDID</constant> is called, then the driver will
+ set <structfield>blocks</structfield> to the total number of available EDID blocks
+ and it will return 0 without copying any data. This is an easy way to discover how many
+ EDID blocks there are. Note that if there are no EDID blocks available at all, then
+ the driver will set <structfield>blocks</structfield> to 0 and it returns 0.</para>
+
<para>To set the EDID blocks of a receiver the application has to fill in the <structfield>pad</structfield>,
<structfield>blocks</structfield> and <structfield>edid</structfield> fields and set
<structfield>start_block</structfield> to 0. It is not possible to set part of an EDID,
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
index 0bb5c060db27..7865351688da 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
@@ -199,7 +199,7 @@ exist no rectangle</emphasis> that satisfies the constraints.</para>
<row>
<entry>__u32</entry>
<entry><structfield>reserved[9]</structfield></entry>
- <entry>Reserved fields for future use.</entry>
+ <entry>Reserved fields for future use. Drivers and applications must zero this array.</entry>
</row>
</tbody>
</tgroup>
diff --git a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
index 3504a7f2f382..8b98a0e421fc 100644
--- a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
@@ -187,6 +187,16 @@ continue streaming.
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><errorcode>EPIPE</errorcode></term>
+ <listitem>
+ <para><constant>VIDIOC_DQBUF</constant> returns this on an empty
+capture queue for mem2mem codecs if a buffer with the
+<constant>V4L2_BUF_FLAG_LAST</constant> was already dequeued and no new buffers
+are expected to become available.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml
index e185f149e0a1..e9c70a8f3476 100644
--- a/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml
@@ -6,6 +6,7 @@
<refnamediv>
<refname>VIDIOC_QUERY_DV_TIMINGS</refname>
+ <refname>VIDIOC_SUBDEV_QUERY_DV_TIMINGS</refname>
<refpurpose>Sense the DV preset received by the current
input</refpurpose>
</refnamediv>
@@ -34,7 +35,7 @@ input</refpurpose>
<varlistentry>
<term><parameter>request</parameter></term>
<listitem>
- <para>VIDIOC_QUERY_DV_TIMINGS</para>
+ <para>VIDIOC_QUERY_DV_TIMINGS, VIDIOC_SUBDEV_QUERY_DV_TIMINGS</para>
</listitem>
</varlistentry>
<varlistentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-querybuf.xml b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml
index a597155c052d..50bfcb5e8508 100644
--- a/Documentation/DocBook/media/v4l/vidioc-querybuf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml
@@ -60,7 +60,8 @@ buffer at any time after buffers have been allocated with the
field. Valid index numbers range from zero
to the number of buffers allocated with &VIDIOC-REQBUFS;
(&v4l2-requestbuffers; <structfield>count</structfield>) minus one.
-The <structfield>reserved</structfield> field should to set to 0.
+The <structfield>reserved</structfield> and <structfield>reserved2 </structfield>
+fields must be set to 0.
When using the <link linkend="planar-apis">multi-planar API</link>, the
<structfield>m.planes</structfield> field must contain a userspace pointer to an
array of &v4l2-plane; and the <structfield>length</structfield> field has
diff --git a/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml b/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml
index 78a06a9a5ece..0f193fda0470 100644
--- a/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml
@@ -112,8 +112,8 @@ as the &v4l2-format; <structfield>type</structfield> field. See <xref
<row>
<entry>__u32</entry>
<entry><structfield>reserved</structfield>[2]</entry>
- <entry>A place holder for future extensions. This array should
-be zeroed by applications.</entry>
+ <entry>A place holder for future extensions. Drivers and applications
+must set the array to zero.</entry>
</row>
</tbody>
</tgroup>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
index d0332f610929..5fd0ee78f880 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
@@ -5,7 +5,8 @@
</refmeta>
<refnamediv>
- <refname>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refname>
+ <refname>VIDIOC_SUBSCRIBE_EVENT</refname>
+ <refname>VIDIOC_UNSUBSCRIBE_EVENT</refname>
<refpurpose>Subscribe or unsubscribe event</refpurpose>
</refnamediv>
diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl
index 03f9a1f8d413..f3f5fe5b64c9 100644
--- a/Documentation/DocBook/media_api.tmpl
+++ b/Documentation/DocBook/media_api.tmpl
@@ -1,12 +1,13 @@
-<?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % media-entities SYSTEM "./media-entities.tmpl"> %media-entities;
<!ENTITY media-indices SYSTEM "./media-indices.tmpl">
<!ENTITY eg "e.&nbsp;g.">
<!ENTITY ie "i.&nbsp;e.">
<!ENTITY fd "File descriptor returned by <link linkend='func-open'><function>open()</function></link>.">
+<!ENTITY fe_fd "File descriptor returned by <link linkend='frontend_f_open'><function>open()</function></link>.">
<!ENTITY i2c "I<superscript>2</superscript>C">
<!ENTITY return-value "<title>Return Value</title><para>On success <returnvalue>0</returnvalue> is returned, on error <returnvalue>-1</returnvalue> and the <varname>errno</varname> variable is set appropriately. The generic error codes are described at the <link linkend='gen-errors'>Generic Error Codes</link> chapter.</para>">
<!ENTITY return-value-dvb "<para>RETURN VALUE</para><para>On success <returnvalue>0</returnvalue> is returned, on error <returnvalue>-1</returnvalue> and the <varname>errno</varname> variable is set appropriately. The generic error codes are described at the <link linkend='gen-errors'>Generic Error Codes</link> chapter.</para>">
@@ -32,7 +33,7 @@
<!ENTITY dash-ent-24 "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
]>
-<book id="media_api">
+<book id="media_api" lang="en">
<bookinfo>
<title>LINUX MEDIA INFRASTRUCTURE API</title>
@@ -60,28 +61,56 @@
analog and digital TV receiver cards, AM/FM receiver cards,
streaming capture and output devices, codec devices and remote
controllers.</para>
- <para>It is divided into four parts.</para>
+ <para>A typical media device hardware is shown at
+ <xref linkend="typical_media_device" />.</para>
+ <figure id="typical_media_device">
+ <title>Typical Media Device</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="typical_media_device.svg" format="SVG" />
+ </imageobject>
+ <textobject>
+ <phrase>Typical Media Device Block Diagram</phrase>
+ </textobject>
+ </mediaobject>
+ </figure>
+ <para>The media infrastructure API was designed to control such
+ devices. It is divided into four parts.</para>
<para>The first part covers radio, video capture and output,
cameras, analog TV devices and codecs.</para>
<para>The second part covers the
API used for digital TV and Internet reception via one of the
several digital tv standards. While it is called as DVB API,
in fact it covers several different video standards including
- DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated
- to document support also for DVB-S2, ISDB-T and ISDB-S.</para>
+ DVB-T/T2, DVB-S/S2, DVB-C, ATSC, ISDB-T, ISDB-S,etc. The complete
+ list of supported standards can be found at
+ <xref linkend="fe-delivery-system-t" />.</para>
<para>The third part covers the Remote Controller API.</para>
<para>The fourth part covers the Media Controller API.</para>
+ <para>It should also be noted that a media device may also have audio
+ components, like mixers, PCM capture, PCM playback, etc, which
+ are controlled via ALSA API.</para>
<para>For additional information and for the latest development code,
see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
<para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
</preface>
-<part id="v4l2spec">&sub-v4l2;</part>
-<part id="dvbapi">&sub-dvbapi;</part>
-<part id="remotes">&sub-remote_controllers;</part>
-<part id="media_common">&sub-media-controller;</part>
+<part id="v4l2spec">
+&sub-v4l2;
+</part>
+<part id="dvbapi">
+&sub-dvbapi;
+</part>
+<part id="remotes">
+&sub-remote_controllers;
+</part>
+<part id="media_common">
+&sub-media-controller;
+</part>
-<chapter id="gen_errors">&sub-gen-errors;</chapter>
+<chapter id="gen_errors">
+&sub-gen-errors;
+</chapter>
&sub-fdl-appendix;
diff --git a/Documentation/DocBook/scsi.tmpl b/Documentation/DocBook/scsi.tmpl
index 324b53494f08..4b9b9b286cea 100644
--- a/Documentation/DocBook/scsi.tmpl
+++ b/Documentation/DocBook/scsi.tmpl
@@ -81,7 +81,7 @@
SAS, Fibre Channel, FireWire, and ATAPI devices. SCSI packets are
also commonly exchanged over Infiniband,
<ulink url='http://i2o.shadowconnect.com/faq.php'>I20</ulink>, TCP/IP
- (<ulink url='http://en.wikipedia.org/wiki/ISCSI'>iSCSI</ulink>), even
+ (<ulink url='https://en.wikipedia.org/wiki/ISCSI'>iSCSI</ulink>), even
<ulink url='http://cyberelk.net/tim/parport/parscsi.html'>Parallel
ports</ulink>.
</para>
diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt
index f29bcbc463e7..370ca006db7a 100644
--- a/Documentation/RCU/RTFP.txt
+++ b/Documentation/RCU/RTFP.txt
@@ -1496,7 +1496,7 @@ Canis Rufus and Zoicon5 and Anome and Hal Eisen"
,month="July"
,day="8"
,year="2006"
-,note="\url{http://en.wikipedia.org/wiki/Read-copy-update}"
+,note="\url{https://en.wikipedia.org/wiki/Read-copy-update}"
,annotation={
Wikipedia RCU page as of July 8 2006.
[Viewed August 21, 2006]
diff --git a/Documentation/RCU/arrayRCU.txt b/Documentation/RCU/arrayRCU.txt
index 453ebe6953ee..f05a9afb2c39 100644
--- a/Documentation/RCU/arrayRCU.txt
+++ b/Documentation/RCU/arrayRCU.txt
@@ -10,7 +10,19 @@ also be used to protect arrays. Three situations are as follows:
3. Resizeable Arrays
-Each of these situations are discussed below.
+Each of these three situations involves an RCU-protected pointer to an
+array that is separately indexed. It might be tempting to consider use
+of RCU to instead protect the index into an array, however, this use
+case is -not- supported. The problem with RCU-protected indexes into
+arrays is that compilers can play way too many optimization games with
+integers, which means that the rules governing handling of these indexes
+are far more trouble than they are worth. If RCU-protected indexes into
+arrays prove to be particularly valuable (which they have not thus far),
+explicit cooperation from the compiler will be required to permit them
+to be safely used.
+
+That aside, each of the three RCU-protected pointer situations are
+described in the following sections.
Situation 1: Hash Tables
@@ -36,9 +48,9 @@ Quick Quiz: Why is it so important that updates be rare when
Situation 3: Resizeable Arrays
Use of RCU for resizeable arrays is demonstrated by the grow_ary()
-function used by the System V IPC code. The array is used to map from
-semaphore, message-queue, and shared-memory IDs to the data structure
-that represents the corresponding IPC construct. The grow_ary()
+function formerly used by the System V IPC code. The array is used
+to map from semaphore, message-queue, and shared-memory IDs to the data
+structure that represents the corresponding IPC construct. The grow_ary()
function does not acquire any locks; instead its caller must hold the
ids->sem semaphore.
diff --git a/Documentation/RCU/lockdep.txt b/Documentation/RCU/lockdep.txt
index cd83d2348fef..da51d3068850 100644
--- a/Documentation/RCU/lockdep.txt
+++ b/Documentation/RCU/lockdep.txt
@@ -47,11 +47,6 @@ checking of rcu_dereference() primitives:
Use explicit check expression "c" along with
srcu_read_lock_held()(). This is useful in code that
is invoked by both SRCU readers and updaters.
- rcu_dereference_index_check(p, c):
- Use explicit check expression "c", but the caller
- must supply one of the rcu_read_lock_held() functions.
- This is useful in code that uses RCU-protected arrays
- that is invoked by both RCU readers and updaters.
rcu_dereference_raw(p):
Don't check. (Use sparingly, if at all.)
rcu_dereference_protected(p, c):
@@ -64,11 +59,6 @@ checking of rcu_dereference() primitives:
but retain the compiler constraints that prevent duplicating
or coalescsing. This is useful when when testing the
value of the pointer itself, for example, against NULL.
- rcu_access_index(idx):
- Return the value of the index and omit all barriers, but
- retain the compiler constraints that prevent duplicating
- or coalescsing. This is useful when when testing the
- value of the index itself, for example, against -1.
The rcu_dereference_check() check expression can be any boolean
expression, but would normally include a lockdep expression. However,
diff --git a/Documentation/RCU/rcu_dereference.txt b/Documentation/RCU/rcu_dereference.txt
index ceb05da5a5ac..1e6c0da994f5 100644
--- a/Documentation/RCU/rcu_dereference.txt
+++ b/Documentation/RCU/rcu_dereference.txt
@@ -25,17 +25,6 @@ o You must use one of the rcu_dereference() family of primitives
for an example where the compiler can in fact deduce the exact
value of the pointer, and thus cause misordering.
-o Do not use single-element RCU-protected arrays. The compiler
- is within its right to assume that the value of an index into
- such an array must necessarily evaluate to zero. The compiler
- could then substitute the constant zero for the computation, so
- that the array index no longer depended on the value returned
- by rcu_dereference(). If the array index no longer depends
- on rcu_dereference(), then both the compiler and the CPU
- are within their rights to order the array access before the
- rcu_dereference(), which can cause the array access to return
- garbage.
-
o Avoid cancellation when using the "+" and "-" infix arithmetic
operators. For example, for a given variable "x", avoid
"(x-x)". There are similar arithmetic pitfalls from other
@@ -76,14 +65,15 @@ o Do not use the results from the boolean "&&" and "||" when
dereferencing. For example, the following (rather improbable)
code is buggy:
- int a[2];
- int index;
- int force_zero_index = 1;
+ int *p;
+ int *q;
...
- r1 = rcu_dereference(i1)
- r2 = a[r1 && force_zero_index]; /* BUGGY!!! */
+ p = rcu_dereference(gp)
+ q = &global_q;
+ q += p != &oom_p1 && p != &oom_p2;
+ r1 = *q; /* BUGGY!!! */
The reason this is buggy is that "&&" and "||" are often compiled
using branches. While weak-memory machines such as ARM or PowerPC
@@ -94,14 +84,15 @@ o Do not use the results from relational operators ("==", "!=",
">", ">=", "<", or "<=") when dereferencing. For example,
the following (quite strange) code is buggy:
- int a[2];
- int index;
- int flip_index = 0;
+ int *p;
+ int *q;
...
- r1 = rcu_dereference(i1)
- r2 = a[r1 != flip_index]; /* BUGGY!!! */
+ p = rcu_dereference(gp)
+ q = &global_q;
+ q += p > &oom_p;
+ r1 = *q; /* BUGGY!!! */
As before, the reason this is buggy is that relational operators
are often compiled using branches. And as before, although
@@ -193,6 +184,11 @@ o Be very careful about comparing pointers obtained from
pointer. Note that the volatile cast in rcu_dereference()
will normally prevent the compiler from knowing too much.
+ However, please note that if the compiler knows that the
+ pointer takes on only one of two values, a not-equal
+ comparison will provide exactly the information that the
+ compiler needs to deduce the value of the pointer.
+
o Disable any value-speculation optimizations that your compiler
might provide, especially if you are making use of feedback-based
optimizations that take data collected from prior runs. Such
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index 88dfce182f66..5746b0c77f3e 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -256,7 +256,9 @@ rcu_dereference()
If you are going to be fetching multiple fields from the
RCU-protected structure, using the local variable is of
course preferred. Repeated rcu_dereference() calls look
- ugly and incur unnecessary overhead on Alpha CPUs.
+ ugly, do not guarantee that the same pointer will be returned
+ if an update happened while in the critical section, and incur
+ unnecessary overhead on Alpha CPUs.
Note that the value returned by rcu_dereference() is valid
only within the enclosing RCU read-side critical section.
@@ -879,9 +881,7 @@ SRCU: Initialization/cleanup
All: lockdep-checked RCU-protected pointer access
- rcu_access_index
rcu_access_pointer
- rcu_dereference_index_check
rcu_dereference_raw
rcu_lockdep_assert
rcu_sleep_check
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index b03a832a08e2..27e7e5edeca8 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -299,7 +299,9 @@ toward the stable maintainers by putting a line like this:
Cc: stable@vger.kernel.org
-into your patch.
+into the sign-off area of your patch (note, NOT an email recipient). You
+should also read Documentation/stable_kernel_rules.txt in addition to this
+file.
Note, however, that some subsystem maintainers want to come to their own
conclusions on which patches should go to the stable trees. The networking
diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt
index 15dfce708ebf..b731b292e812 100644
--- a/Documentation/acpi/enumeration.txt
+++ b/Documentation/acpi/enumeration.txt
@@ -42,7 +42,7 @@ Adding ACPI support for an existing driver should be pretty
straightforward. Here is the simplest example:
#ifdef CONFIG_ACPI
- static struct acpi_device_id mydrv_acpi_match[] = {
+ static const struct acpi_device_id mydrv_acpi_match[] = {
/* ACPI IDs here */
{ }
};
@@ -166,7 +166,7 @@ the platform device drivers. Below is an example where we add ACPI support
to at25 SPI eeprom driver (this is meant for the above ACPI snippet):
#ifdef CONFIG_ACPI
- static struct acpi_device_id at25_acpi_match[] = {
+ static const struct acpi_device_id at25_acpi_match[] = {
{ "AT25", 0 },
{ },
};
@@ -230,7 +230,7 @@ Below is an example of how to add ACPI support to the existing mpu3050
input driver:
#ifdef CONFIG_ACPI
- static struct acpi_device_id mpu3050_acpi_match[] = {
+ static const struct acpi_device_id mpu3050_acpi_match[] = {
{ "MPU3050", 0 },
{ },
};
@@ -359,3 +359,54 @@ the id should be set like:
The ACPI id "XYZ0001" is then used to lookup an ACPI device directly under
the MFD device and if found, that ACPI companion device is bound to the
resulting child platform device.
+
+Device Tree namespace link device ID
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The Device Tree protocol uses device indentification based on the "compatible"
+property whose value is a string or an array of strings recognized as device
+identifiers by drivers and the driver core. The set of all those strings may be
+regarded as a device indentification namespace analogous to the ACPI/PNP device
+ID namespace. Consequently, in principle it should not be necessary to allocate
+a new (and arguably redundant) ACPI/PNP device ID for a devices with an existing
+identification string in the Device Tree (DT) namespace, especially if that ID
+is only needed to indicate that a given device is compatible with another one,
+presumably having a matching driver in the kernel already.
+
+In ACPI, the device identification object called _CID (Compatible ID) is used to
+list the IDs of devices the given one is compatible with, but those IDs must
+belong to one of the namespaces prescribed by the ACPI specification (see
+Section 6.1.2 of ACPI 6.0 for details) and the DT namespace is not one of them.
+Moreover, the specification mandates that either a _HID or an _ADR identificaion
+object be present for all ACPI objects representing devices (Section 6.1 of ACPI
+6.0). For non-enumerable bus types that object must be _HID and its value must
+be a device ID from one of the namespaces prescribed by the specification too.
+
+The special DT namespace link device ID, PRP0001, provides a means to use the
+existing DT-compatible device identification in ACPI and to satisfy the above
+requirements following from the ACPI specification at the same time. Namely,
+if PRP0001 is returned by _HID, the ACPI subsystem will look for the
+"compatible" property in the device object's _DSD and will use the value of that
+property to identify the corresponding device in analogy with the original DT
+device identification algorithm. If the "compatible" property is not present
+or its value is not valid, the device will not be enumerated by the ACPI
+subsystem. Otherwise, it will be enumerated automatically as a platform device
+(except when an I2C or SPI link from the device to its parent is present, in
+which case the ACPI core will leave the device enumeration to the parent's
+driver) and the identification strings from the "compatible" property value will
+be used to find a driver for the device along with the device IDs listed by _CID
+(if present).
+
+Analogously, if PRP0001 is present in the list of device IDs returned by _CID,
+the identification strings listed by the "compatible" property value (if present
+and valid) will be used to look for a driver matching the device, but in that
+case their relative priority with respect to the other device IDs listed by
+_HID and _CID depends on the position of PRP0001 in the _CID return package.
+Specifically, the device IDs returned by _HID and preceding PRP0001 in the _CID
+return package will be checked first. Also in that case the bus type the device
+will be enumerated to depends on the device ID returned by _HID.
+
+It is valid to define device objects with a _HID returning PRP0001 and without
+the "compatible" property in the _DSD or a _CID as long as one of their
+ancestors provides a _DSD with a valid "compatible" property. Such device
+objects are then simply regarded as additional "blocks" providing hierarchical
+configuration information to the driver of the composite ancestor device.
diff --git a/Documentation/arm/CCN.txt b/Documentation/arm/CCN.txt
index 0632b3aad83e..ffca443a19b4 100644
--- a/Documentation/arm/CCN.txt
+++ b/Documentation/arm/CCN.txt
@@ -33,20 +33,23 @@ directory, with first 8 configurable by user and additional
Cycle counter is described by a "type" value 0xff and does
not require any other settings.
+The driver also provides a "cpumask" sysfs attribute, which contains
+a single CPU ID, of the processor which will be used to handle all
+the CCN PMU events. It is recommended that the user space tools
+request the events on this processor (if not, the perf_event->cpu value
+will be overwritten anyway). In case of this processor being offlined,
+the events are migrated to another one and the attribute is updated.
+
Example of perf tool use:
/ # perf list | grep ccn
ccn/cycles/ [Kernel PMU event]
<...>
- ccn/xp_valid_flit/ [Kernel PMU event]
+ ccn/xp_valid_flit,xp=?,port=?,vc=?,dir=?/ [Kernel PMU event]
<...>
-/ # perf stat -C 0 -e ccn/cycles/,ccn/xp_valid_flit,xp=1,port=0,vc=1,dir=1/ \
+/ # perf stat -a -e ccn/cycles/,ccn/xp_valid_flit,xp=1,port=0,vc=1,dir=1/ \
sleep 1
The driver does not support sampling, therefore "perf record" will
-not work. Also notice that only single cpu is being selected
-("-C 0") - this is because perf framework does not support
-"non-CPU related" counters (yet?) so system-wide session ("-a")
-would try (and in most cases fail) to set up the same event
-per each CPU.
+not work. Per-task (without "-a") perf sessions are not supported.
diff --git a/Documentation/arm/Samsung/Bootloader-interface.txt b/Documentation/arm/Samsung/Bootloader-interface.txt
new file mode 100644
index 000000000000..b96ead9a6919
--- /dev/null
+++ b/Documentation/arm/Samsung/Bootloader-interface.txt
@@ -0,0 +1,53 @@
+ Interface between kernel and boot loaders on Exynos boards
+ ==========================================================
+
+Author: Krzysztof Kozlowski
+Date : 6 June 2015
+
+The document tries to describe currently used interface between Linux kernel
+and boot loaders on Samsung Exynos based boards. This is not a definition
+of interface but rather a description of existing state, a reference
+for information purpose only.
+
+In the document "boot loader" means any of following: U-boot, proprietary
+SBOOT or any other firmware for ARMv7 and ARMv8 initializing the board before
+executing kernel.
+
+
+1. Non-Secure mode
+Address: sysram_ns_base_addr
+Offset Value Purpose
+=============================================================================
+0x08 exynos_cpu_resume_ns System suspend
+0x0c 0x00000bad (Magic cookie) System suspend
+0x1c exynos4_secondary_startup Secondary CPU boot
+0x1c + 4*cpu exynos4_secondary_startup (Exynos4412) Secondary CPU boot
+0x20 0xfcba0d10 (Magic cookie) AFTR
+0x24 exynos_cpu_resume_ns AFTR
+0x28 + 4*cpu 0x8 (Magic cookie, Exynos3250) AFTR
+
+
+2. Secure mode
+Address: sysram_base_addr
+Offset Value Purpose
+=============================================================================
+0x00 exynos4_secondary_startup Secondary CPU boot
+0x04 exynos4_secondary_startup (Exynos542x) Secondary CPU boot
+4*cpu exynos4_secondary_startup (Exynos4412) Secondary CPU boot
+0x20 exynos_cpu_resume (Exynos4210 r1.0) AFTR
+0x24 0xfcba0d10 (Magic cookie, Exynos4210 r1.0) AFTR
+
+Address: pmu_base_addr
+Offset Value Purpose
+=============================================================================
+0x0800 exynos_cpu_resume AFTR
+0x0814 exynos4_secondary_startup (Exynos4210 r1.1) Secondary CPU boot
+0x0818 0xfcba0d10 (Magic cookie, Exynos4210 r1.1) AFTR
+0x081C exynos_cpu_resume (Exynos4210 r1.1) AFTR
+
+
+3. Other (regardless of secure/non-secure mode)
+Address: pmu_base_addr
+Offset Value Purpose
+=============================================================================
+0x0908 Non-zero (only Exynos3250) Secondary CPU boot up indicator
diff --git a/Documentation/arm/stm32/overview.txt b/Documentation/arm/stm32/overview.txt
new file mode 100644
index 000000000000..09aed5588d7c
--- /dev/null
+++ b/Documentation/arm/stm32/overview.txt
@@ -0,0 +1,32 @@
+ STM32 ARM Linux Overview
+ ========================
+
+Introduction
+------------
+
+ The STMicroelectronics family of Cortex-M based MCUs are supported by the
+ 'STM32' platform of ARM Linux. Currently only the STM32F429 is supported.
+
+
+Configuration
+-------------
+
+ A generic configuration is provided for STM32 family, and can be used as the
+ default by
+ make stm32_defconfig
+
+Layout
+------
+
+ All the files for multiple machine families are located in the platform code
+ contained in arch/arm/mach-stm32
+
+ There is a generic board board-dt.c in the mach folder which support
+ Flattened Device Tree, which means, it works with any compatible board with
+ Device Trees.
+
+
+Document Author
+---------------
+
+ Maxime Coquelin <mcoquelin.stm32@gmail.com>
diff --git a/Documentation/arm/stm32/stm32f429-overview.txt b/Documentation/arm/stm32/stm32f429-overview.txt
new file mode 100644
index 000000000000..5206822bd8ef
--- /dev/null
+++ b/Documentation/arm/stm32/stm32f429-overview.txt
@@ -0,0 +1,22 @@
+ STM32F429 Overview
+ ==================
+
+ Introduction
+ ------------
+ The STM32F429 is a Cortex-M4 MCU aimed at various applications.
+ It features:
+ - ARM Cortex-M4 up to 180MHz with FPU
+ - 2MB internal Flash Memory
+ - External memory support through FMC controller (PSRAM, SDRAM, NOR, NAND)
+ - I2C, SPI, SAI, CAN, USB OTG, Ethernet controllers
+ - LCD controller & Camera interface
+ - Cryptographic processor
+
+ Resources
+ ---------
+ Datasheet and reference manual are publicly available on ST website:
+ - http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1577/LN1806?ecmp=stm32f429-439_pron_pr-ces2014_nov2013
+
+ Document Author
+ ---------------
+ Maxime Coquelin <mcoquelin.stm32@gmail.com>
diff --git a/Documentation/arm/vlocks.txt b/Documentation/arm/vlocks.txt
index 415960a9bab0..45731672c564 100644
--- a/Documentation/arm/vlocks.txt
+++ b/Documentation/arm/vlocks.txt
@@ -206,6 +206,6 @@ References
[1] Lamport, L. "A New Solution of Dijkstra's Concurrent Programming
Problem", Communications of the ACM 17, 8 (August 1974), 453-455.
- http://en.wikipedia.org/wiki/Lamport%27s_bakery_algorithm
+ https://en.wikipedia.org/wiki/Lamport%27s_bakery_algorithm
[2] linux/arch/arm/common/vlock.S, www.kernel.org.
diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
index f3c05b5f9f08..1690350f16e7 100644
--- a/Documentation/arm64/booting.txt
+++ b/Documentation/arm64/booting.txt
@@ -45,11 +45,13 @@ sees fit.)
Requirement: MANDATORY
-The device tree blob (dtb) must be placed on an 8-byte boundary within
-the first 512 megabytes from the start of the kernel image and must not
-cross a 2-megabyte boundary. This is to allow the kernel to map the
-blob using a single section mapping in the initial page tables.
+The device tree blob (dtb) must be placed on an 8-byte boundary and must
+not exceed 2 megabytes in size. Since the dtb will be mapped cacheable
+using blocks of up to 2 megabytes in size, it must not be placed within
+any 2M region which must be mapped with any specific attributes.
+NOTE: versions prior to v4.2 also require that the DTB be placed within
+the 512 MB region starting at text_offset bytes below the kernel Image.
3. Decompress the kernel image
------------------------------
diff --git a/Documentation/blackfin/gptimers-example.c b/Documentation/blackfin/gptimers-example.c
index b1bd6340e748..283eba993d9d 100644
--- a/Documentation/blackfin/gptimers-example.c
+++ b/Documentation/blackfin/gptimers-example.c
@@ -17,6 +17,12 @@
#define DRIVER_NAME "gptimer_example"
+#ifdef IRQ_TIMER5
+#define SAMPLE_IRQ_TIMER IRQ_TIMER5
+#else
+#define SAMPLE_IRQ_TIMER IRQ_TIMER2
+#endif
+
struct gptimer_data {
uint32_t period, width;
};
@@ -57,7 +63,8 @@ static int __init gptimer_example_init(void)
}
/* grab the IRQ for the timer */
- ret = request_irq(IRQ_TIMER5, gptimer_example_irq, IRQF_SHARED, DRIVER_NAME, &data);
+ ret = request_irq(SAMPLE_IRQ_TIMER, gptimer_example_irq,
+ IRQF_SHARED, DRIVER_NAME, &data);
if (ret) {
printk(KERN_NOTICE DRIVER_NAME ": IRQ request failed\n");
peripheral_free(P_TMR5);
@@ -65,7 +72,8 @@ static int __init gptimer_example_init(void)
}
/* setup the timer and enable it */
- set_gptimer_config(TIMER5_id, WDTH_CAP | PULSE_HI | PERIOD_CNT | IRQ_ENA);
+ set_gptimer_config(TIMER5_id,
+ WDTH_CAP | PULSE_HI | PERIOD_CNT | IRQ_ENA);
enable_gptimers(TIMER5bit);
return 0;
@@ -75,7 +83,7 @@ module_init(gptimer_example_init);
static void __exit gptimer_example_exit(void)
{
disable_gptimers(TIMER5bit);
- free_irq(IRQ_TIMER5, &data);
+ free_irq(SAMPLE_IRQ_TIMER, &data);
peripheral_free(P_TMR5);
}
module_exit(gptimer_example_exit);
diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt
index 48a183e29988..c4de576093af 100644
--- a/Documentation/blockdev/zram.txt
+++ b/Documentation/blockdev/zram.txt
@@ -19,7 +19,9 @@ Following shows a typical sequence of steps for using zram.
1) Load Module:
modprobe zram num_devices=4
This creates 4 devices: /dev/zram{0,1,2,3}
- (num_devices parameter is optional. Default: 1)
+
+num_devices parameter is optional and tells zram how many devices should be
+pre-created. Default: 1.
2) Set max number of compression streams
Compression backend may use up to max_comp_streams compression streams,
@@ -97,7 +99,24 @@ size of the disk when not in use so a huge zram is wasteful.
mkfs.ext4 /dev/zram1
mount /dev/zram1 /tmp
-7) Stats:
+7) Add/remove zram devices
+
+zram provides a control interface, which enables dynamic (on-demand) device
+addition and removal.
+
+In order to add a new /dev/zramX device, perform read operation on hot_add
+attribute. This will return either new device's device id (meaning that you
+can use /dev/zram<id>) or error code.
+
+Example:
+ cat /sys/class/zram-control/hot_add
+ 1
+
+To remove the existing /dev/zramX device (where X is a device id)
+execute
+ echo X > /sys/class/zram-control/hot_remove
+
+8) Stats:
Per-device statistics are exported as various nodes under /sys/block/zram<id>/
A brief description of exported device attritbutes. For more details please
@@ -126,7 +145,7 @@ mem_used_max RW the maximum amount memory zram have consumed to
mem_limit RW the maximum amount of memory ZRAM can use to store
the compressed data
num_migrated RO the number of objects migrated migrated by compaction
-
+compact WO trigger memory compaction
WARNING
=======
@@ -172,11 +191,11 @@ line of text and contains the following stats separated by whitespace:
zero_pages
num_migrated
-8) Deactivate:
+9) Deactivate:
swapoff /dev/zram0
umount /dev/zram1
-9) Reset:
+10) Reset:
Write any positive value to 'reset' sysfs node
echo 1 > /sys/block/zram0/reset
echo 1 > /sys/block/zram1/reset
diff --git a/Documentation/cgroups/blkio-controller.txt b/Documentation/cgroups/blkio-controller.txt
index cd556b914786..68b6a6a470b0 100644
--- a/Documentation/cgroups/blkio-controller.txt
+++ b/Documentation/cgroups/blkio-controller.txt
@@ -387,8 +387,81 @@ groups and put applications in that group which are not driving enough
IO to keep disk busy. In that case set group_idle=0, and CFQ will not idle
on individual groups and throughput should improve.
-What works
-==========
-- Currently only sync IO queues are support. All the buffered writes are
- still system wide and not per group. Hence we will not see service
- differentiation between buffered writes between groups.
+Writeback
+=========
+
+Page cache is dirtied through buffered writes and shared mmaps and
+written asynchronously to the backing filesystem by the writeback
+mechanism. Writeback sits between the memory and IO domains and
+regulates the proportion of dirty memory by balancing dirtying and
+write IOs.
+
+On traditional cgroup hierarchies, relationships between different
+controllers cannot be established making it impossible for writeback
+to operate accounting for cgroup resource restrictions and all
+writeback IOs are attributed to the root cgroup.
+
+If both the blkio and memory controllers are used on the v2 hierarchy
+and the filesystem supports cgroup writeback, writeback operations
+correctly follow the resource restrictions imposed by both memory and
+blkio controllers.
+
+Writeback examines both system-wide and per-cgroup dirty memory status
+and enforces the more restrictive of the two. Also, writeback control
+parameters which are absolute values - vm.dirty_bytes and
+vm.dirty_background_bytes - are distributed across cgroups according
+to their current writeback bandwidth.
+
+There's a peculiarity stemming from the discrepancy in ownership
+granularity between memory controller and writeback. While memory
+controller tracks ownership per page, writeback operates on inode
+basis. cgroup writeback bridges the gap by tracking ownership by
+inode but migrating ownership if too many foreign pages, pages which
+don't match the current inode ownership, have been encountered while
+writing back the inode.
+
+This is a conscious design choice as writeback operations are
+inherently tied to inodes making strictly following page ownership
+complicated and inefficient. The only use case which suffers from
+this compromise is multiple cgroups concurrently dirtying disjoint
+regions of the same inode, which is an unlikely use case and decided
+to be unsupported. Note that as memory controller assigns page
+ownership on the first use and doesn't update it until the page is
+released, even if cgroup writeback strictly follows page ownership,
+multiple cgroups dirtying overlapping areas wouldn't work as expected.
+In general, write-sharing an inode across multiple cgroups is not well
+supported.
+
+Filesystem support for cgroup writeback
+---------------------------------------
+
+A filesystem can make writeback IOs cgroup-aware by updating
+address_space_operations->writepage[s]() to annotate bio's using the
+following two functions.
+
+* wbc_init_bio(@wbc, @bio)
+
+ Should be called for each bio carrying writeback data and associates
+ the bio with the inode's owner cgroup. Can be called anytime
+ between bio allocation and submission.
+
+* wbc_account_io(@wbc, @page, @bytes)
+
+ Should be called for each data segment being written out. While
+ this function doesn't care exactly when it's called during the
+ writeback session, it's the easiest and most natural to call it as
+ data segments are added to a bio.
+
+With writeback bio's annotated, cgroup support can be enabled per
+super_block by setting MS_CGROUPWB in ->s_flags. This allows for
+selective disabling of cgroup writeback support which is helpful when
+certain filesystem features, e.g. journaled data mode, are
+incompatible.
+
+wbc_init_bio() binds the specified bio to its cgroup. Depending on
+the configuration, the bio may be executed at a lower priority and if
+the writeback session is holding shared resources, e.g. a journal
+entry, may lead to priority inversion. There is no one easy solution
+for the problem. Filesystems can try to work around specific problem
+cases by skipping wbc_init_bio() or using bio_associate_blkcg()
+directly.
diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt
index f456b4315e86..ff71e16cc752 100644
--- a/Documentation/cgroups/memory.txt
+++ b/Documentation/cgroups/memory.txt
@@ -493,6 +493,7 @@ pgpgin - # of charging events to the memory cgroup. The charging
pgpgout - # of uncharging events to the memory cgroup. The uncharging
event happens each time a page is unaccounted from the cgroup.
swap - # of bytes of swap usage
+dirty - # of bytes that are waiting to get written back to the disk.
writeback - # of bytes of file/anon cache that are queued for syncing to
disk.
inactive_anon - # of bytes of anonymous and swap cache memory on inactive
diff --git a/Documentation/cgroups/unified-hierarchy.txt b/Documentation/cgroups/unified-hierarchy.txt
index eb102fb72213..86847a7647ab 100644
--- a/Documentation/cgroups/unified-hierarchy.txt
+++ b/Documentation/cgroups/unified-hierarchy.txt
@@ -17,15 +17,18 @@ CONTENTS
3. Structural Constraints
3-1. Top-down
3-2. No internal tasks
-4. Other Changes
- 4-1. [Un]populated Notification
- 4-2. Other Core Changes
- 4-3. Per-Controller Changes
- 4-3-1. blkio
- 4-3-2. cpuset
- 4-3-3. memory
-5. Planned Changes
- 5-1. CAP for resource control
+4. Delegation
+ 4-1. Model of delegation
+ 4-2. Common ancestor rule
+5. Other Changes
+ 5-1. [Un]populated Notification
+ 5-2. Other Core Changes
+ 5-3. Per-Controller Changes
+ 5-3-1. blkio
+ 5-3-2. cpuset
+ 5-3-3. memory
+6. Planned Changes
+ 6-1. CAP for resource control
1. Background
@@ -245,9 +248,72 @@ cgroup must create children and transfer all its tasks to the children
before enabling controllers in its "cgroup.subtree_control" file.
-4. Other Changes
+4. Delegation
-4-1. [Un]populated Notification
+4-1. Model of delegation
+
+A cgroup can be delegated to a less privileged user by granting write
+access of the directory and its "cgroup.procs" file to the user. Note
+that the resource control knobs in a given directory concern the
+resources of the parent and thus must not be delegated along with the
+directory.
+
+Once delegated, the user can build sub-hierarchy under the directory,
+organize processes as it sees fit and further distribute the resources
+it got from the parent. The limits and other settings of all resource
+controllers are hierarchical and regardless of what happens in the
+delegated sub-hierarchy, nothing can escape the resource restrictions
+imposed by the parent.
+
+Currently, cgroup doesn't impose any restrictions on the number of
+cgroups in or nesting depth of a delegated sub-hierarchy; however,
+this may in the future be limited explicitly.
+
+
+4-2. Common ancestor rule
+
+On the unified hierarchy, to write to a "cgroup.procs" file, in
+addition to the usual write permission to the file and uid match, the
+writer must also have write access to the "cgroup.procs" file of the
+common ancestor of the source and destination cgroups. This prevents
+delegatees from smuggling processes across disjoint sub-hierarchies.
+
+Let's say cgroups C0 and C1 have been delegated to user U0 who created
+C00, C01 under C0 and C10 under C1 as follows.
+
+ ~~~~~~~~~~~~~ - C0 - C00
+ ~ cgroup ~ \ C01
+ ~ hierarchy ~
+ ~~~~~~~~~~~~~ - C1 - C10
+
+C0 and C1 are separate entities in terms of resource distribution
+regardless of their relative positions in the hierarchy. The
+resources the processes under C0 are entitled to are controlled by
+C0's ancestors and may be completely different from C1. It's clear
+that the intention of delegating C0 to U0 is allowing U0 to organize
+the processes under C0 and further control the distribution of C0's
+resources.
+
+On traditional hierarchies, if a task has write access to "tasks" or
+"cgroup.procs" file of a cgroup and its uid agrees with the target, it
+can move the target to the cgroup. In the above example, U0 will not
+only be able to move processes in each sub-hierarchy but also across
+the two sub-hierarchies, effectively allowing it to violate the
+organizational and resource restrictions implied by the hierarchical
+structure above C0 and C1.
+
+On the unified hierarchy, let's say U0 wants to write the pid of a
+process which has a matching uid and is currently in C10 into
+"C00/cgroup.procs". U0 obviously has write access to the file and
+migration permission on the process; however, the common ancestor of
+the source cgroup C10 and the destination cgroup C00 is above the
+points of delegation and U0 would not have write access to its
+"cgroup.procs" and thus be denied with -EACCES.
+
+
+5. Other Changes
+
+5-1. [Un]populated Notification
cgroup users often need a way to determine when a cgroup's
subhierarchy becomes empty so that it can be cleaned up. cgroup
@@ -289,7 +355,7 @@ supported and the interface files "release_agent" and
"notify_on_release" do not exist.
-4-2. Other Core Changes
+5-2. Other Core Changes
- None of the mount options is allowed.
@@ -306,14 +372,14 @@ supported and the interface files "release_agent" and
- The "cgroup.clone_children" file is removed.
-4-3. Per-Controller Changes
+5-3. Per-Controller Changes
-4-3-1. blkio
+5-3-1. blkio
- blk-throttle becomes properly hierarchical.
-4-3-2. cpuset
+5-3-2. cpuset
- Tasks are kept in empty cpusets after hotplug and take on the masks
of the nearest non-empty ancestor, instead of being moved to it.
@@ -322,7 +388,7 @@ supported and the interface files "release_agent" and
masks of the nearest non-empty ancestor.
-4-3-3. memory
+5-3-3. memory
- use_hierarchy is on by default and the cgroup file for the flag is
not created.
@@ -407,9 +473,9 @@ supported and the interface files "release_agent" and
memory.low, memory.high, and memory.max will use the string "max" to
indicate and set the highest possible value.
-5. Planned Changes
+6. Planned Changes
-5-1. CAP for resource control
+6-1. CAP for resource control
Unified hierarchy will require one of the capabilities(7), which is
yet to be decided, for all resource control related knobs. Process
diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt
index 77ec21574fb1..c15aa75f5227 100644
--- a/Documentation/cpu-freq/governors.txt
+++ b/Documentation/cpu-freq/governors.txt
@@ -36,7 +36,7 @@ Contents:
1. What Is A CPUFreq Governor?
==============================
-Most cpufreq drivers (in fact, all except one, longrun) or even most
+Most cpufreq drivers (except the intel_pstate and longrun) or even most
cpu frequency scaling algorithms only offer the CPU to be set to one
frequency. In order to offer dynamic frequency scaling, the cpufreq
core must be able to tell these drivers of a "target frequency". So
diff --git a/Documentation/cpu-freq/intel-pstate.txt b/Documentation/cpu-freq/intel-pstate.txt
index 655750743fb0..be8d4006bf76 100644
--- a/Documentation/cpu-freq/intel-pstate.txt
+++ b/Documentation/cpu-freq/intel-pstate.txt
@@ -3,24 +3,25 @@ Intel P-state driver
This driver provides an interface to control the P state selection for
SandyBridge+ Intel processors. The driver can operate two different
-modes based on the processor model legacy and Hardware P state (HWP)
+modes based on the processor model, legacy mode and Hardware P state (HWP)
mode.
-In legacy mode the driver implements a scaling driver with an internal
-governor for Intel Core processors. The driver follows the same model
-as the Transmeta scaling driver (longrun.c) and implements the
-setpolicy() instead of target(). Scaling drivers that implement
-setpolicy() are assumed to implement internal governors by the cpufreq
-core. All the logic for selecting the current P state is contained
-within the driver; no external governor is used by the cpufreq core.
+In legacy mode, the Intel P-state implements two internal governors,
+performance and powersave, that differ from the general cpufreq governors of
+the same name (the general cpufreq governors implement target(), whereas the
+internal Intel P-state governors implement setpolicy()). The internal
+performance governor sets the max_perf_pct and min_perf_pct to 100; that is,
+the governor selects the highest available P state to maximize the performance
+of the core. The internal powersave governor selects the appropriate P state
+based on the current load on the CPU.
In HWP mode P state selection is implemented in the processor
itself. The driver provides the interfaces between the cpufreq core and
the processor to control P state selection based on user preferences
and reporting frequency to the cpufreq core. In this mode the
-internal governor code is disabled.
+internal Intel P-state governor code is disabled.
-In addtion to the interfaces provided by the cpufreq core for
+In addition to the interfaces provided by the cpufreq core for
controlling frequency the driver provides sysfs files for
controlling P state selection. These files have been added to
/sys/devices/system/cpu/intel_pstate/
diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt
index ff2f28332cc4..109e97bbab77 100644
--- a/Documentation/cpu-freq/user-guide.txt
+++ b/Documentation/cpu-freq/user-guide.txt
@@ -196,8 +196,6 @@ affected_cpus : List of Online CPUs that require software
related_cpus : List of Online + Offline CPUs that need software
coordination of frequency.
-scaling_driver : Hardware driver for cpufreq.
-
scaling_cur_freq : Current frequency of the CPU as determined by
the governor and cpufreq core, in KHz. This is
the frequency the kernel thinks the CPU runs
diff --git a/Documentation/cputopology.txt b/Documentation/cputopology.txt
index 0aad6deb2d96..12b1b25b4da9 100644
--- a/Documentation/cputopology.txt
+++ b/Documentation/cputopology.txt
@@ -1,6 +1,6 @@
Export CPU topology info via sysfs. Items (attributes) are similar
-to /proc/cpuinfo.
+to /proc/cpuinfo output of some architectures:
1) /sys/devices/system/cpu/cpuX/topology/physical_package_id:
@@ -23,20 +23,35 @@ to /proc/cpuinfo.
4) /sys/devices/system/cpu/cpuX/topology/thread_siblings:
internal kernel map of cpuX's hardware threads within the same
- core as cpuX
+ core as cpuX.
-5) /sys/devices/system/cpu/cpuX/topology/core_siblings:
+5) /sys/devices/system/cpu/cpuX/topology/thread_siblings_list:
+
+ human-readable list of cpuX's hardware threads within the same
+ core as cpuX.
+
+6) /sys/devices/system/cpu/cpuX/topology/core_siblings:
internal kernel map of cpuX's hardware threads within the same
physical_package_id.
-6) /sys/devices/system/cpu/cpuX/topology/book_siblings:
+7) /sys/devices/system/cpu/cpuX/topology/core_siblings_list:
+
+ human-readable list of cpuX's hardware threads within the same
+ physical_package_id.
+
+8) /sys/devices/system/cpu/cpuX/topology/book_siblings:
internal kernel map of cpuX's hardware threads within the same
book_id.
+9) /sys/devices/system/cpu/cpuX/topology/book_siblings_list:
+
+ human-readable list of cpuX's hardware threads within the same
+ book_id.
+
To implement it in an architecture-neutral way, a new source file,
-drivers/base/topology.c, is to export the 4 or 6 attributes. The two book
+drivers/base/topology.c, is to export the 6 or 9 attributes. The three book
related sysfs files will only be created if CONFIG_SCHED_BOOK is selected.
For an architecture to support this feature, it must define some of
@@ -44,20 +59,22 @@ these macros in include/asm-XXX/topology.h:
#define topology_physical_package_id(cpu)
#define topology_core_id(cpu)
#define topology_book_id(cpu)
-#define topology_thread_cpumask(cpu)
+#define topology_sibling_cpumask(cpu)
#define topology_core_cpumask(cpu)
#define topology_book_cpumask(cpu)
-The type of **_id is int.
-The type of siblings is (const) struct cpumask *.
+The type of **_id macros is int.
+The type of **_cpumask macros is (const) struct cpumask *. The latter
+correspond with appropriate **_siblings sysfs attributes (except for
+topology_sibling_cpumask() which corresponds with thread_siblings).
To be consistent on all architectures, include/linux/topology.h
provides default definitions for any of the above macros that are
not defined by include/asm-XXX/topology.h:
1) physical_package_id: -1
2) core_id: 0
-3) thread_siblings: just the given CPU
-4) core_siblings: just the given CPU
+3) sibling_cpumask: just the given CPU
+4) core_cpumask: just the given CPU
For architectures that don't support books (CONFIG_SCHED_BOOK) there are no
default definitions for topology_book_id() and topology_book_cpumask().
diff --git a/Documentation/debugging-via-ohci1394.txt b/Documentation/debugging-via-ohci1394.txt
index 5c9a567b3fac..03703afc4d30 100644
--- a/Documentation/debugging-via-ohci1394.txt
+++ b/Documentation/debugging-via-ohci1394.txt
@@ -181,4 +181,4 @@ Notes
Documentation and specifications: http://halobates.de/firewire/
FireWire is a trademark of Apple Inc. - for more information please refer to:
-http://en.wikipedia.org/wiki/FireWire
+https://en.wikipedia.org/wiki/FireWire
diff --git a/Documentation/device-mapper/cache-policies.txt b/Documentation/device-mapper/cache-policies.txt
index 0d124a971801..d9246a32e673 100644
--- a/Documentation/device-mapper/cache-policies.txt
+++ b/Documentation/device-mapper/cache-policies.txt
@@ -25,10 +25,10 @@ trying to see when the io scheduler has let the ios run.
Overview of supplied cache replacement policies
===============================================
-multiqueue
-----------
+multiqueue (mq)
+---------------
-This policy is the default.
+This policy has been deprecated in favor of the smq policy (see below).
The multiqueue policy has three sets of 16 queues: one set for entries
waiting for the cache and another two for those in the cache (a set for
@@ -73,6 +73,67 @@ If you're trying to quickly warm a new cache device you may wish to
reduce these to encourage promotion. Remember to switch them back to
their defaults after the cache fills though.
+Stochastic multiqueue (smq)
+---------------------------
+
+This policy is the default.
+
+The stochastic multi-queue (smq) policy addresses some of the problems
+with the multiqueue (mq) policy.
+
+The smq policy (vs mq) offers the promise of less memory utilization,
+improved performance and increased adaptability in the face of changing
+workloads. SMQ also does not have any cumbersome tuning knobs.
+
+Users may switch from "mq" to "smq" simply by appropriately reloading a
+DM table that is using the cache target. Doing so will cause all of the
+mq policy's hints to be dropped. Also, performance of the cache may
+degrade slightly until smq recalculates the origin device's hotspots
+that should be cached.
+
+Memory usage:
+The mq policy uses a lot of memory; 88 bytes per cache block on a 64
+bit machine.
+
+SMQ uses 28bit indexes to implement it's data structures rather than
+pointers. It avoids storing an explicit hit count for each block. It
+has a 'hotspot' queue rather than a pre cache which uses a quarter of
+the entries (each hotspot block covers a larger area than a single
+cache block).
+
+All these mean smq uses ~25bytes per cache block. Still a lot of
+memory, but a substantial improvement nontheless.
+
+Level balancing:
+MQ places entries in different levels of the multiqueue structures
+based on their hit count (~ln(hit count)). This means the bottom
+levels generally have the most entries, and the top ones have very
+few. Having unbalanced levels like this reduces the efficacy of the
+multiqueue.
+
+SMQ does not maintain a hit count, instead it swaps hit entries with
+the least recently used entry from the level above. The over all
+ordering being a side effect of this stochastic process. With this
+scheme we can decide how many entries occupy each multiqueue level,
+resulting in better promotion/demotion decisions.
+
+Adaptability:
+The MQ policy maintains a hit count for each cache block. For a
+different block to get promoted to the cache it's hit count has to
+exceed the lowest currently in the cache. This means it can take a
+long time for the cache to adapt between varying IO patterns.
+Periodically degrading the hit counts could help with this, but I
+haven't found a nice general solution.
+
+SMQ doesn't maintain hit counts, so a lot of this problem just goes
+away. In addition it tracks performance of the hotspot queue, which
+is used to decide which blocks to promote. If the hotspot queue is
+performing badly then it starts moving entries more quickly between
+levels. This lets it adapt to new IO patterns very quickly.
+
+Performance:
+Testing SMQ shows substantially better performance than MQ.
+
cleaner
-------
diff --git a/Documentation/device-mapper/cache.txt b/Documentation/device-mapper/cache.txt
index 68c0f517c60e..82960cffbad3 100644
--- a/Documentation/device-mapper/cache.txt
+++ b/Documentation/device-mapper/cache.txt
@@ -221,6 +221,7 @@ Status
<#read hits> <#read misses> <#write hits> <#write misses>
<#demotions> <#promotions> <#dirty> <#features> <features>*
<#core args> <core args>* <policy name> <#policy args> <policy args>*
+<cache metadata mode>
metadata block size : Fixed block size for each metadata block in
sectors
@@ -251,8 +252,12 @@ core args : Key/value pairs for tuning the core
e.g. migration_threshold
policy name : Name of the policy
#policy args : Number of policy arguments to follow (must be even)
-policy args : Key/value pairs
- e.g. sequential_threshold
+policy args : Key/value pairs e.g. sequential_threshold
+cache metadata mode : ro if read-only, rw if read-write
+ In serious cases where even a read-only mode is deemed unsafe
+ no further I/O will be permitted and the status will just
+ contain the string 'Fail'. The userspace recovery tools
+ should then be used.
Messages
--------
diff --git a/Documentation/device-mapper/dm-raid.txt b/Documentation/device-mapper/dm-raid.txt
index ef8ba9fa58c4..cb12af3b51c2 100644
--- a/Documentation/device-mapper/dm-raid.txt
+++ b/Documentation/device-mapper/dm-raid.txt
@@ -224,3 +224,5 @@ Version History
New status (STATUSTYPE_INFO) fields: sync_action and mismatch_cnt.
1.5.1 Add ability to restore transiently failed devices on resume.
1.5.2 'mismatch_cnt' is zero unless [last_]sync_action is "check".
+1.6.0 Add discard support (and devices_handle_discard_safely module param).
+1.7.0 Add support for MD RAID0 mappings.
diff --git a/Documentation/device-mapper/statistics.txt b/Documentation/device-mapper/statistics.txt
index 2a1673adc200..4919b2dfd1b3 100644
--- a/Documentation/device-mapper/statistics.txt
+++ b/Documentation/device-mapper/statistics.txt
@@ -13,9 +13,14 @@ the range specified.
The I/O statistics counters for each step-sized area of a region are
in the same format as /sys/block/*/stat or /proc/diskstats (see:
Documentation/iostats.txt). But two extra counters (12 and 13) are
-provided: total time spent reading and writing in milliseconds. All
-these counters may be accessed by sending the @stats_print message to
-the appropriate DM device via dmsetup.
+provided: total time spent reading and writing. When the histogram
+argument is used, the 14th parameter is reported that represents the
+histogram of latencies. All these counters may be accessed by sending
+the @stats_print message to the appropriate DM device via dmsetup.
+
+The reported times are in milliseconds and the granularity depends on
+the kernel ticks. When the option precise_timestamps is used, the
+reported times are in nanoseconds.
Each region has a corresponding unique identifier, which we call a
region_id, that is assigned when the region is created. The region_id
@@ -33,7 +38,9 @@ memory is used by reading
Messages
========
- @stats_create <range> <step> [<program_id> [<aux_data>]]
+ @stats_create <range> <step>
+ [<number_of_optional_arguments> <optional_arguments>...]
+ [<program_id> [<aux_data>]]
Create a new region and return the region_id.
@@ -48,6 +55,29 @@ Messages
"/<number_of_areas>" - the range is subdivided into the specified
number of areas.
+ <number_of_optional_arguments>
+ The number of optional arguments
+
+ <optional_arguments>
+ The following optional arguments are supported
+ precise_timestamps - use precise timer with nanosecond resolution
+ instead of the "jiffies" variable. When this argument is
+ used, the resulting times are in nanoseconds instead of
+ milliseconds. Precise timestamps are a little bit slower
+ to obtain than jiffies-based timestamps.
+ histogram:n1,n2,n3,n4,... - collect histogram of latencies. The
+ numbers n1, n2, etc are times that represent the boundaries
+ of the histogram. If precise_timestamps is not used, the
+ times are in milliseconds, otherwise they are in
+ nanoseconds. For each range, the kernel will report the
+ number of requests that completed within this range. For
+ example, if we use "histogram:10,20,30", the kernel will
+ report four numbers a:b:c:d. a is the number of requests
+ that took 0-10 ms to complete, b is the number of requests
+ that took 10-20 ms to complete, c is the number of requests
+ that took 20-30 ms to complete and d is the number of
+ requests that took more than 30 ms to complete.
+
<program_id>
An optional parameter. A name that uniquely identifies
the userspace owner of the range. This groups ranges together
@@ -55,6 +85,9 @@ Messages
created and ignore those created by others.
The kernel returns this string back in the output of
@stats_list message, but it doesn't use it for anything else.
+ If we omit the number of optional arguments, program id must not
+ be a number, otherwise it would be interpreted as the number of
+ optional arguments.
<aux_data>
An optional parameter. A word that provides auxiliary data
diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-sdram-controller.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-sdram-controller.txt
new file mode 100644
index 000000000000..77ca635765e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/altera/socfpga-sdram-controller.txt
@@ -0,0 +1,12 @@
+Altera SOCFPGA SDRAM Controller
+
+Required properties:
+- compatible : Should contain "altr,sdr-ctl" and "syscon".
+ syscon is required by the Altera SOCFPGA SDRAM EDAC.
+- reg : Should contain 1 register range (address and length)
+
+Example:
+ sdr: sdr@ffc25000 {
+ compatible = "altr,sdr-ctl", "syscon";
+ reg = <0xffc25000 0x1000>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-sdram-edac.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-sdram-edac.txt
index d0ce01da5c59..f5ad0ff69fae 100644
--- a/Documentation/devicetree/bindings/arm/altera/socfpga-sdram-edac.txt
+++ b/Documentation/devicetree/bindings/arm/altera/socfpga-sdram-edac.txt
@@ -2,7 +2,7 @@ Altera SOCFPGA SDRAM Error Detection & Correction [EDAC]
The EDAC accesses a range of registers in the SDRAM controller.
Required properties:
-- compatible : should contain "altr,sdram-edac";
+- compatible : should contain "altr,sdram-edac" or "altr,sdram-edac-a10"
- altr,sdr-syscon : phandle of the sdr module
- interrupts : Should contain the SDRAM ECC IRQ in the
appropriate format for the IRQ controller.
diff --git a/Documentation/devicetree/bindings/arm/arm-boards b/Documentation/devicetree/bindings/arm/arm-boards
index b78564b2b201..1a709970e7f7 100644
--- a/Documentation/devicetree/bindings/arm/arm-boards
+++ b/Documentation/devicetree/bindings/arm/arm-boards
@@ -157,3 +157,69 @@ Example:
};
};
+
+ARM Versatile Express Boards
+-----------------------------
+For details on the device tree bindings for ARM Versatile Express boards
+please consult the vexpress.txt file in the same directory as this file.
+
+ARM Juno Boards
+----------------
+The Juno boards are targeting development for AArch64 systems. The first
+iteration, Juno r0, is a vehicle for evaluating big.LITTLE on AArch64,
+with the second iteration, Juno r1, mainly aimed at development of PCIe
+based systems. Juno r1 also has support for AXI masters placed on the TLX
+connectors to join the coherency domain.
+
+Juno boards are described in a similar way to ARM Versatile Express boards,
+with the motherboard part of the hardware being described in a separate file
+to highlight the fact that is part of the support infrastructure for the SoC.
+Juno device tree bindings also share the Versatile Express bindings as
+described under the RS1 memory mapping.
+
+Required properties (in root node):
+ compatible = "arm,juno"; /* For Juno r0 board */
+ compatible = "arm,juno-r1"; /* For Juno r1 board */
+
+Required nodes:
+The description for the board must include:
+ - a "psci" node describing the boot method used for the secondary CPUs.
+ A detailed description of the bindings used for "psci" nodes is present
+ in the psci.txt file.
+ - a "cpus" node describing the available cores and their associated
+ "enable-method"s. For more details see cpus.txt file.
+
+Example:
+
+/dts-v1/;
+/ {
+ model = "ARM Juno development board (r0)";
+ compatible = "arm,juno", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ A57_0: cpu@0 {
+ compatible = "arm,cortex-a57","arm,armv8";
+ reg = <0x0 0x0>;
+ device_type = "cpu";
+ enable-method = "psci";
+ };
+
+ .....
+
+ A53_0: cpu@100 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ };
+
+ .....
+ };
+
+};
diff --git a/Documentation/devicetree/bindings/arm/armv7m_systick.txt b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
new file mode 100644
index 000000000000..7cf4a24601eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
@@ -0,0 +1,26 @@
+* ARMv7M System Timer
+
+ARMv7-M includes a system timer, known as SysTick. Current driver only
+implements the clocksource feature.
+
+Required properties:
+- compatible : Should be "arm,armv7m-systick"
+- reg : The address range of the timer
+
+Required clocking property, have to be one of:
+- clocks : The input clock of the timer
+- clock-frequency : The rate in HZ in input of the ARM SysTick
+
+Examples:
+
+systick: timer@e000e010 {
+ compatible = "arm,armv7m-systick";
+ reg = <0xe000e010 0x10>;
+ clocks = <&clk_systick>;
+};
+
+systick: timer@e000e010 {
+ compatible = "arm,armv7m-systick";
+ reg = <0xe000e010 0x10>;
+ clock-frequency = <90000000>;
+};
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt
index 2e99b5b57350..424ac8cbfa08 100644
--- a/Documentation/devicetree/bindings/arm/atmel-at91.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt
@@ -98,7 +98,7 @@ Example:
};
RAMC SDRAM/DDR Controller required properties:
-- compatible: Should be "atmel,at91rm9200-sdramc",
+- compatible: Should be "atmel,at91rm9200-sdramc", "syscon"
"atmel,at91sam9260-sdramc",
"atmel,at91sam9g45-ddramc",
"atmel,sama5d3-ddramc",
diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
index ac683480c486..c78576bb7729 100644
--- a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
+++ b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm2835.txt
@@ -1,8 +1,35 @@
Broadcom BCM2835 device tree bindings
-------------------------------------------
-Boards with the BCM2835 SoC shall have the following properties:
+Raspberry Pi Model A
+Required root node properties:
+compatible = "raspberrypi,model-a", "brcm,bcm2835";
-Required root node property:
+Raspberry Pi Model A+
+Required root node properties:
+compatible = "raspberrypi,model-a-plus", "brcm,bcm2835";
+Raspberry Pi Model B
+Required root node properties:
+compatible = "raspberrypi,model-b", "brcm,bcm2835";
+
+Raspberry Pi Model B (no P5)
+early model B with I2C0 rather than I2C1 routed to the expansion header
+Required root node properties:
+compatible = "raspberrypi,model-b-i2c0", "brcm,bcm2835";
+
+Raspberry Pi Model B rev2
+Required root node properties:
+compatible = "raspberrypi,model-b-rev2", "brcm,bcm2835";
+
+Raspberry Pi Model B+
+Required root node properties:
+compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
+
+Raspberry Pi Compute Module
+Required root node properties:
+compatible = "raspberrypi,compute-module", "brcm,bcm2835";
+
+Generic BCM2835 board
+Required root node properties:
compatible = "brcm,bcm2835";
diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm63138.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm63138.txt
index bd49987a8812..b82b6a0ae6f7 100644
--- a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm63138.txt
+++ b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm63138.txt
@@ -7,3 +7,79 @@ following properties:
Required root node property:
compatible: should be "brcm,bcm63138"
+
+An optional Boot lookup table Device Tree node is required for secondary CPU
+initialization as well as a 'resets' phandle to the correct PMB controller as
+defined in reset/brcm,bcm63138-pmb.txt for this secondary CPU, and an
+'enable-method' property.
+
+Required properties for the Boot lookup table node:
+- compatible: should be "brcm,bcm63138-bootlut"
+- reg: register base address and length for the Boot Lookup table
+
+Optional properties for the primary CPU node:
+- enable-method: should be "brcm,bcm63138"
+
+Optional properties for the secondary CPU node:
+- enable-method: should be "brcm,bcm63138"
+- resets: phandle to the relevant PMB controller, one integer indicating the internal
+ bus number, and a second integer indicating the address of the CPU in the PMB
+ internal bus number.
+
+Example:
+
+ cpus {
+ cpu@0 {
+ compatible = "arm,cotex-a9";
+ reg = <0>;
+ ...
+ enable-method = "brcm,bcm63138";
+ };
+
+ cpu@1 {
+ compatible = "arm,cortex-a9";
+ reg = <1>;
+ ...
+ enable-method = "brcm,bcm63138";
+ resets = <&pmb0 4 1>;
+ };
+ };
+
+ bootlut: bootlut@8000 {
+ compatible = "brcm,bcm63138-bootlut";
+ reg = <0x8000 0x50>;
+ };
+
+=======
+reboot
+------
+Two nodes are required for software reboot: a timer node and a syscon-reboot node.
+
+Timer node:
+
+- compatible: Must be "brcm,bcm6328-timer", "syscon"
+- reg: Register base address and length
+
+Syscon reboot node:
+
+See Documentation/devicetree/bindings/power/reset/syscon-reboot.txt for the
+detailed list of properties, the two values defined below are specific to the
+BCM6328-style timer:
+
+- offset: Should be 0x34 to denote the offset of the TIMER_WD_TIMER_RESET register
+ from the beginning of the TIMER block
+- mask: Should be 1 for the SoftRst bit.
+
+Example:
+
+ timer: timer@80 {
+ compatible = "brcm,bcm6328-timer", "syscon";
+ reg = <0x80 0x3c>;
+ };
+
+ reboot {
+ compatible = "syscon-reboot";
+ regmap = <&timer>;
+ offset = <0x34>;
+ mask = <0x1>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/cci.txt b/Documentation/devicetree/bindings/arm/cci.txt
index 3c5c631328d3..aef1d200a9b2 100644
--- a/Documentation/devicetree/bindings/arm/cci.txt
+++ b/Documentation/devicetree/bindings/arm/cci.txt
@@ -31,8 +31,9 @@ specific to ARM.
- compatible
Usage: required
Value type: <string>
- Definition: must be set to
+ Definition: must contain one of the following:
"arm,cci-400"
+ "arm,cci-500"
- reg
Usage: required
@@ -99,6 +100,7 @@ specific to ARM.
"arm,cci-400-pmu,r1"
"arm,cci-400-pmu" - DEPRECATED, permitted only where OS has
secure acces to CCI registers
+ "arm,cci-500-pmu,r0"
- reg:
Usage: required
Value type: Integer cells. A register entry, expressed
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index 88602b75418e..65a6db2271a2 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -17,15 +17,19 @@ its hardware characteristcs.
- "arm,coresight-tmc", "arm,primecell";
- "arm,coresight-funnel", "arm,primecell";
- "arm,coresight-etm3x", "arm,primecell";
+ - "qcom,coresight-replicator1x", "arm,primecell";
* reg: physical base address and length of the register
set(s) of the component.
- * clocks: the clock associated to this component.
+ * clocks: the clocks associated to this component.
- * clock-names: the name of the clock as referenced by the code.
- Since we are using the AMBA framework, the name should be
- "apb_pclk".
+ * clock-names: the name of the clocks referenced by the code.
+ Since we are using the AMBA framework, the name of the clock
+ providing the interconnect should be "apb_pclk", and some
+ coresight blocks also have an additional clock "atclk", which
+ clocks the core of that coresight component. The latter clock
+ is optional.
* port or ports: The representation of the component's port
layout using the generic DT graph presentation found in
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index 6aa331d11c5e..d6b794cef0b8 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -188,6 +188,7 @@ nodes to be present and contain the properties described below.
# On ARM 32-bit systems this property is optional and
can be one of:
"allwinner,sun6i-a31"
+ "allwinner,sun8i-a23"
"arm,psci"
"brcm,brahma-b15"
"marvell,armada-375-smp"
diff --git a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
index 5da38c5ed476..e151057d92f0 100644
--- a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
+++ b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
@@ -19,9 +19,10 @@ Optional Properties:
domains.
- clock-names: The following clocks can be specified:
- oscclk: Oscillator clock.
- - pclkN, clkN: Pairs of parent of input clock and input clock to the
- devices in this power domain. Maximum of 4 pairs (N = 0 to 3)
- are supported currently.
+ - clkN: Input clocks to the devices in this power domain. These clocks
+ will be reparented to oscclk before swithing power domain off.
+ Their original parent will be brought back after turning on
+ the domain. Maximum of 4 clocks (N = 0 to 3) are supported.
- asbN: Clocks required by asynchronous bridges (ASB) present in
the power domain. These clock should be enabled during power
domain on/off operations.
diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt
index a5462b6b3c30..2a3ba73f0c5c 100644
--- a/Documentation/devicetree/bindings/arm/fsl.txt
+++ b/Documentation/devicetree/bindings/arm/fsl.txt
@@ -81,12 +81,15 @@ Freescale Vybrid Platform Device Tree Bindings
For the Vybrid SoC familiy all variants with DDR controller are supported,
which is the VF5xx and VF6xx series. Out of historical reasons, in most
places the kernel uses vf610 to refer to the whole familiy.
+The compatible string "fsl,vf610m4" is used for the secondary Cortex-M4
+core support.
Required root node compatible property (one of them):
- compatible = "fsl,vf500";
- compatible = "fsl,vf510";
- compatible = "fsl,vf600";
- compatible = "fsl,vf610";
+ - compatible = "fsl,vf610m4";
Freescale LS1021A Platform Device Tree Bindings
------------------------------------------------
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index 35b1bd49cfa1..c431c67524d6 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -1,5 +1,8 @@
Hisilicon Platforms Device Tree Bindings
----------------------------------------------------
+Hi6220 SoC
+Required root node properties:
+ - compatible = "hisilicon,hi6220";
Hi4511 Board
Required root node properties:
@@ -13,6 +16,9 @@ HiP01 ca9x2 Board
Required root node properties:
- compatible = "hisilicon,hip01-ca9x2";
+HiKey Board
+Required root node properties:
+ - compatible = "hisilicon,hi6220-hikey", "hisilicon,hi6220";
Hisilicon system controller
@@ -41,6 +47,87 @@ Example:
};
-----------------------------------------------------------------------
+Hisilicon Hi6220 system controller
+
+Required properties:
+- compatible : "hisilicon,hi6220-sysctrl"
+- reg : Register address and size
+- #clock-cells: should be set to 1, many clock registers are defined
+ under this controller and this property must be present.
+
+Hisilicon designs this controller as one of the system controllers,
+its main functions are the same as Hisilicon system controller, but
+the register offset of some core modules are different.
+
+Example:
+ /*for Hi6220*/
+ sys_ctrl: sys_ctrl@f7030000 {
+ compatible = "hisilicon,hi6220-sysctrl", "syscon";
+ reg = <0x0 0xf7030000 0x0 0x2000>;
+ #clock-cells = <1>;
+ };
+
+
+Hisilicon Hi6220 Power Always ON domain controller
+
+Required properties:
+- compatible : "hisilicon,hi6220-aoctrl"
+- reg : Register address and size
+- #clock-cells: should be set to 1, many clock registers are defined
+ under this controller and this property must be present.
+
+Hisilicon designs this system controller to control the power always
+on domain for mobile platform.
+
+Example:
+ /*for Hi6220*/
+ ao_ctrl: ao_ctrl@f7800000 {
+ compatible = "hisilicon,hi6220-aoctrl", "syscon";
+ reg = <0x0 0xf7800000 0x0 0x2000>;
+ #clock-cells = <1>;
+ };
+
+
+Hisilicon Hi6220 Media domain controller
+
+Required properties:
+- compatible : "hisilicon,hi6220-mediactrl"
+- reg : Register address and size
+- #clock-cells: should be set to 1, many clock registers are defined
+ under this controller and this property must be present.
+
+Hisilicon designs this system controller to control the multimedia
+domain(e.g. codec, G3D ...) for mobile platform.
+
+Example:
+ /*for Hi6220*/
+ media_ctrl: media_ctrl@f4410000 {
+ compatible = "hisilicon,hi6220-mediactrl", "syscon";
+ reg = <0x0 0xf4410000 0x0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+
+Hisilicon Hi6220 Power Management domain controller
+
+Required properties:
+- compatible : "hisilicon,hi6220-pmctrl"
+- reg : Register address and size
+- #clock-cells: should be set to 1, some clock registers are define
+ under this controller and this property must be present.
+
+Hisilicon designs this system controller to control the power management
+domain for mobile platform.
+
+Example:
+ /*for Hi6220*/
+ pm_ctrl: pm_ctrl@f7032000 {
+ compatible = "hisilicon,hi6220-pmctrl", "syscon";
+ reg = <0x0 0xf7032000 0x0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+-----------------------------------------------------------------------
Hisilicon HiP01 system controller
Required properties:
diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt
index 0dbabe9a6b0a..2251dccb141e 100644
--- a/Documentation/devicetree/bindings/arm/l2cc.txt
+++ b/Documentation/devicetree/bindings/arm/l2cc.txt
@@ -67,6 +67,11 @@ Optional properties:
disable if zero.
- arm,prefetch-offset : Override prefetch offset value. Valid values are
0-7, 15, 23, and 31.
+- prefetch-data : Data prefetch. Value: <0> (forcibly disable), <1>
+ (forcibly enable), property absent (retain settings set by firmware)
+- prefetch-instr : Instruction prefetch. Value: <0> (forcibly disable),
+ <1> (forcibly enable), property absent (retain settings set by
+ firmware)
Example:
diff --git a/Documentation/devicetree/bindings/arm/marvell,berlin.txt b/Documentation/devicetree/bindings/arm/marvell,berlin.txt
index a99eb9eb14c0..3bab18409b7a 100644
--- a/Documentation/devicetree/bindings/arm/marvell,berlin.txt
+++ b/Documentation/devicetree/bindings/arm/marvell,berlin.txt
@@ -1,6 +1,18 @@
Marvell Berlin SoC Family Device Tree Bindings
---------------------------------------------------------------
+Work in progress statement:
+
+Device tree files and bindings applying to Marvell Berlin SoCs and boards are
+considered "unstable". Any Marvell Berlin device tree binding may change at any
+time. Be sure to use a device tree binary and a kernel image generated from the
+same source tree.
+
+Please refer to Documentation/devicetree/bindings/ABI.txt for a definition of a
+stable binding/ABI.
+
+---------------------------------------------------------------
+
Boards with a SoC of the Marvell Berlin family, e.g. Armada 1500
shall have the following properties:
@@ -49,10 +61,9 @@ chip control registers, so there should be a single DT node only providing the
different functions which are described below.
Required properties:
-- compatible: shall be one of
- "marvell,berlin2-chip-ctrl" for BG2
- "marvell,berlin2cd-chip-ctrl" for BG2CD
- "marvell,berlin2q-chip-ctrl" for BG2Q
+- compatible:
+ * the first and second values must be:
+ "simple-mfd", "syscon"
- reg: address and length of following register sets for
BG2/BG2CD: chip control register set
BG2Q: chip control register set and cpu pll registers
@@ -63,90 +74,23 @@ Marvell Berlin SoCs have a system control register set providing several
individual registers dealing with pinmux, padmux, and reset.
Required properties:
-- compatible: should be one of
- "marvell,berlin2-system-ctrl" for BG2
- "marvell,berlin2cd-system-ctrl" for BG2CD
- "marvell,berlin2q-system-ctrl" for BG2Q
+- compatible:
+ * the first and second values must be:
+ "simple-mfd", "syscon"
- reg: address and length of the system control register set
-* Clock provider binding
-
-As clock related registers are spread among the chip control registers, the
-chip control node also provides the clocks. Marvell Berlin2 (BG2, BG2CD, BG2Q)
-SoCs share the same IP for PLLs and clocks, with some minor differences in
-features and register layout.
-
-Required properties:
-- #clock-cells: shall be set to 1
-- clocks: clock specifiers referencing the core clock input clocks
-- clock-names: array of strings describing the input clock specifiers above.
- Allowed clock-names for the reference clocks are
- "refclk" for the SoCs osciallator input on all SoCs,
- and SoC-specific input clocks for
- BG2/BG2CD: "video_ext0" for the external video clock input
-
-Clocks provided by core clocks shall be referenced by a clock specifier
-indexing one of the provided clocks. Refer to dt-bindings/clock/berlin<soc>.h
-for the corresponding index mapping.
-
-* Pin controller binding
-
-Pin control registers are part of both register sets, chip control and system
-control. The pins controlled are organized in groups, so no actual pin
-information is needed.
-
-A pin-controller node should contain subnodes representing the pin group
-configurations, one per function. Each subnode has the group name and the muxing
-function used.
-
-Be aware the Marvell Berlin datasheets use the keyword 'mode' for what is called
-a 'function' in the pin-controller subsystem.
-
-Required subnode-properties:
-- groups: a list of strings describing the group names.
-- function: a string describing the function used to mux the groups.
-
-* Reset controller binding
-
-A reset controller is part of the chip control registers set. The chip control
-node also provides the reset. The register set is not at the same offset between
-Berlin SoCs.
-
-Required property:
-- #reset-cells: must be set to 2
-
Example:
chip: chip-control@ea0000 {
- compatible = "marvell,berlin2-chip-ctrl";
- #clock-cells = <1>;
- #reset-cells = <2>;
+ compatible = "simple-mfd", "syscon";
reg = <0xea0000 0x400>;
- clocks = <&refclk>, <&externaldev 0>;
- clock-names = "refclk", "video_ext0";
- spi1_pmux: spi1-pmux {
- groups = "G0";
- function = "spi1";
- };
+ /* sub-device nodes */
};
sysctrl: system-controller@d000 {
- compatible = "marvell,berlin2-system-ctrl";
+ compatible = "simple-mfd", "syscon";
reg = <0xd000 0x100>;
- uart0_pmux: uart0-pmux {
- groups = "GSM4";
- function = "uart0";
- };
-
- uart1_pmux: uart1-pmux {
- groups = "GSM5";
- function = "uart1";
- };
-
- uart2_pmux: uart2-pmux {
- groups = "GSM3";
- function = "uart2";
- };
+ /* sub-device nodes */
};
diff --git a/Documentation/devicetree/bindings/arm/scu.txt b/Documentation/devicetree/bindings/arm/scu.txt
new file mode 100644
index 000000000000..c447680519bb
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/scu.txt
@@ -0,0 +1,25 @@
+* ARM Snoop Control Unit (SCU)
+
+As part of the MPCore complex, Cortex-A5 and Cortex-A9 are provided
+with a Snoop Control Unit. The register range is usually 256 (0x100)
+bytes.
+
+References:
+
+- Cortex-A9: see DDI0407E Cortex-A9 MPCore Technical Reference Manual
+ Revision r2p0
+- Cortex-A5: see DDI0434B Cortex-A5 MPCore Technical Reference Manual
+ Revision r0p1
+
+- compatible : Should be:
+ "arm,cortex-a9-scu"
+ "arm,cortex-a5-scu"
+
+- reg : Specify the base address and the size of the SCU register window.
+
+Example:
+
+scu@a04100000 {
+ compatible = "arm,cortex-a9-scu";
+ reg = <0xa0410000 0x100>;
+};
diff --git a/Documentation/devicetree/bindings/arm/ux500/boards.txt b/Documentation/devicetree/bindings/arm/ux500/boards.txt
new file mode 100644
index 000000000000..b8737a8de718
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/ux500/boards.txt
@@ -0,0 +1,83 @@
+ST-Ericsson Ux500 boards
+------------------------
+
+Required properties (in root node) one of these:
+ compatible = "st-ericsson,mop500" (legacy)
+ compatible = "st-ericsson,u8500"
+
+Required node (under root node):
+
+soc: represents the system-on-chip and contains the chip
+peripherals
+
+Required property of soc node, one of these:
+ compatible = "stericsson,db8500"
+
+Required subnodes under soc node:
+
+backupram: (used for CPU spin tables and for storing data
+during retention, system won't boot without this):
+ compatible = "ste,dbx500-backupram"
+
+scu:
+ see binding for arm/scu.txt
+
+interrupt-controller:
+ see binding for arm/gic.txt
+
+timer:
+ see binding for arm/twd.txt
+
+clocks:
+ see binding for clocks/ux500.txt
+
+Example:
+
+/dts-v1/;
+
+/ {
+ model = "ST-Ericsson HREF (pre-v60) and ST UIB";
+ compatible = "st-ericsson,mop500", "st-ericsson,u8500";
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "stericsson,db8500";
+ interrupt-parent = <&intc>;
+ ranges;
+
+ backupram@80150000 {
+ compatible = "ste,dbx500-backupram";
+ reg = <0x80150000 0x2000>;
+ };
+
+ intc: interrupt-controller@a0411000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ interrupt-controller;
+ reg = <0xa0411000 0x1000>,
+ <0xa0410100 0x100>;
+ };
+
+ scu@a04100000 {
+ compatible = "arm,cortex-a9-scu";
+ reg = <0xa0410000 0x100>;
+ };
+
+ timer@a0410600 {
+ compatible = "arm,cortex-a9-twd-timer";
+ reg = <0xa0410600 0x20>;
+ interrupts = <1 13 0x304>; /* IRQ level high per-CPU */
+ clocks = <&smp_twd_clk>;
+ };
+
+ clocks {
+ compatible = "stericsson,u8500-clks";
+
+ smp_twd_clk: smp-twd-clock {
+ #clock-cells = <0>;
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/arm/zte.txt b/Documentation/devicetree/bindings/arm/zte.txt
new file mode 100644
index 000000000000..3ff5c9e85c1c
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/zte.txt
@@ -0,0 +1,15 @@
+ZTE platforms device tree bindings
+---------------------------------------
+
+- ZX296702 board:
+ Required root node properties:
+ - compatible = "zte,zx296702-ad1", "zte,zx296702"
+
+System management required properties:
+ - compatible = "zte,sysctrl"
+
+Low power management required properties:
+ - compatible = "zte,zx296702-pcu"
+
+Bus matrix required properties:
+ - compatible = "zte,zx-bus-matrix"
diff --git a/Documentation/devicetree/bindings/ata/ahci-ceva.txt b/Documentation/devicetree/bindings/ata/ahci-ceva.txt
new file mode 100644
index 000000000000..7ca8b976c13a
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/ahci-ceva.txt
@@ -0,0 +1,20 @@
+Binding for CEVA AHCI SATA Controller
+
+Required properties:
+ - reg: Physical base address and size of the controller's register area.
+ - compatible: Compatibility string. Must be 'ceva,ahci-1v84'.
+ - clocks: Input clock specifier. Refer to common clock bindings.
+ - interrupts: Interrupt specifier. Refer to interrupt binding.
+
+Optional properties:
+ - ceva,broken-gen2: limit to gen1 speed instead of gen2.
+
+Examples:
+ ahci@fd0c0000 {
+ compatible = "ceva,ahci-1v84";
+ reg = <0xfd0c0000 0x200>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 133 4>;
+ clocks = <&clkc SATA_CLK_ID>;
+ ceva,broken-gen2;
+ };
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index c2340eeeb97f..a2321819e7f5 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -16,6 +16,8 @@ Required properties:
- "snps,dwc-ahci"
- "snps,exynos5440-ahci"
- "snps,spear-ahci"
+ - "fsl,qoriq-ahci" : for qoriq series socs which include ls1021, ls2085, etc.
+ - "fsl,<chip>-ahci" : chip could be ls1021, ls2085 etc.
- "generic-ahci"
- interrupts : <interrupt mapping for SATA IRQ>
- reg : <registers mapping>
diff --git a/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt b/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt
new file mode 100644
index 000000000000..20ac9bbfa1fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt
@@ -0,0 +1,34 @@
+* Broadcom SATA3 AHCI Controller for STB
+
+SATA nodes are defined to describe on-chip Serial ATA controllers.
+Each SATA controller should have its own node.
+
+Required properties:
+- compatible : compatible list, may contain "brcm,bcm7445-ahci" and/or
+ "brcm,sata3-ahci"
+- reg : register mappings for AHCI and SATA_TOP_CTRL
+- reg-names : "ahci" and "top-ctrl"
+- interrupts : interrupt mapping for SATA IRQ
+
+Also see ahci-platform.txt.
+
+Example:
+
+ sata@f045a000 {
+ compatible = "brcm,bcm7445-ahci", "brcm,sata3-ahci";
+ reg = <0xf045a000 0xa9c>, <0xf0458040 0x24>;
+ reg-names = "ahci", "top-ctrl";
+ interrupts = <0 30 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sata0: sata-port@0 {
+ reg = <0>;
+ phys = <&sata_phy 0>;
+ };
+
+ sata1: sata-port@1 {
+ reg = <1>;
+ phys = <&sata_phy 1>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt
index 7a4d4926f44e..5ba6450693b9 100644
--- a/Documentation/devicetree/bindings/clock/at91-clock.txt
+++ b/Documentation/devicetree/bindings/clock/at91-clock.txt
@@ -248,7 +248,7 @@ Required properties for peripheral clocks:
- #address-cells : shall be 1 (reg is used to encode clk id).
- clocks : shall be the master clock phandle.
e.g. clocks = <&mck>;
-- name: device tree node describing a specific system clock.
+- name: device tree node describing a specific peripheral clock.
* #clock-cells : from common clock binding; shall be set to 0.
* reg: peripheral id. See Atmel's datasheets to get a full
list of peripheral ids.
diff --git a/Documentation/devicetree/bindings/clock/hi6220-clock.txt b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
new file mode 100644
index 000000000000..259e30af9597
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
@@ -0,0 +1,34 @@
+* Hisilicon Hi6220 Clock Controller
+
+Clock control registers reside in different Hi6220 system controllers,
+please refer the following document to know more about the binding rules
+for these system controllers:
+
+Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+
+Required Properties:
+
+- compatible: the compatible should be one of the following strings to
+ indicate the clock controller functionality.
+
+ - "hisilicon,hi6220-aoctrl"
+ - "hisilicon,hi6220-sysctrl"
+ - "hisilicon,hi6220-mediactrl"
+ - "hisilicon,hi6220-pmctrl"
+
+- reg: physical base address of the controller and length of memory mapped
+ region.
+
+- #clock-cells: should be 1.
+
+For example:
+ sys_ctrl: sys_ctrl@f7030000 {
+ compatible = "hisilicon,hi6220-sysctrl", "syscon";
+ reg = <0x0 0xf7030000 0x0 0x2000>;
+ #clock-cells = <1>;
+ };
+
+Each clock is assigned an identifier and client nodes use this identifier
+to specify the clock which they consume.
+
+All these identifier could be found in <dt-bindings/clock/hi6220-clock.h>.
diff --git a/Documentation/devicetree/bindings/clock/imx7d-clock.txt b/Documentation/devicetree/bindings/clock/imx7d-clock.txt
new file mode 100644
index 000000000000..9d3026d81a68
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/imx7d-clock.txt
@@ -0,0 +1,13 @@
+* Clock bindings for Freescale i.MX7 Dual
+
+Required properties:
+- compatible: Should be "fsl,imx7d-ccm"
+- reg: Address and length of the register set
+- #clock-cells: Should be <1>
+- clocks: list of clock specifiers, must contain an entry for each required
+ entry in clock-names
+- clock-names: should include entries "ckil", "osc"
+
+The clock consumer should specify the desired clock by having the clock
+ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx7d-clock.h
+for the full list of i.MX7 Dual clock IDs.
diff --git a/Documentation/devicetree/bindings/clock/marvell,berlin.txt b/Documentation/devicetree/bindings/clock/marvell,berlin.txt
new file mode 100644
index 000000000000..c611c495f3ff
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/marvell,berlin.txt
@@ -0,0 +1,31 @@
+Device Tree Clock bindings for Marvell Berlin
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Clock related registers are spread among the chip control registers. Berlin
+clock node should be a sub-node of the chip controller node. Marvell Berlin2
+(BG2, BG2CD, BG2Q) SoCs share the same IP for PLLs and clocks, with some
+minor differences in features and register layout.
+
+Required properties:
+- compatible: must be "marvell,berlin2-clk" or "marvell,berlin2q-clk"
+- #clock-cells: must be 1
+- clocks: must be the input parent clock phandle
+- clock-names: name of the input parent clock
+ Allowed clock-names for the reference clocks are
+ "refclk" for the SoCs oscillator input on all SoCs,
+ and SoC-specific input clocks for
+ BG2/BG2CD: "video_ext0" for the external video clock input
+
+
+Example:
+
+chip_clk: clock {
+ compatible = "marvell,berlin2q-clk";
+
+ #clock-cells = <1>;
+ clocks = <&refclk>;
+ clock-names = "refclk";
+};
diff --git a/Documentation/devicetree/bindings/clock/renesas,h8300-div-clock.txt b/Documentation/devicetree/bindings/clock/renesas,h8300-div-clock.txt
new file mode 100644
index 000000000000..36c2b528245c
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/renesas,h8300-div-clock.txt
@@ -0,0 +1,24 @@
+* Renesas H8/300 divider clock
+
+Required Properties:
+
+ - compatible: Must be "renesas,sh73a0-h8300-div-clock"
+
+ - clocks: Reference to the parent clocks ("extal1" and "extal2")
+
+ - #clock-cells: Must be 1
+
+ - reg: Base address and length of the divide rate selector
+
+ - renesas,width: bit width of selector
+
+Example
+-------
+
+ cclk: cclk {
+ compatible = "renesas,h8300-div-clock";
+ clocks = <&xclk>;
+ #clock-cells = <0>;
+ reg = <0xfee01b 2>;
+ renesas,width = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/renesas,h8s2678-pll-clock.txt b/Documentation/devicetree/bindings/clock/renesas,h8s2678-pll-clock.txt
new file mode 100644
index 000000000000..500cdadbceb7
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/renesas,h8s2678-pll-clock.txt
@@ -0,0 +1,23 @@
+Renesas H8S2678 PLL clock
+
+This device is Clock multiplyer
+
+Required Properties:
+
+ - compatible: Must be "renesas,h8s2678-pll-clock"
+
+ - clocks: Reference to the parent clocks
+
+ - #clock-cells: Must be 0
+
+ - reg: Two rate selector (Multiply / Divide) register address
+
+Example
+-------
+
+ pllclk: pllclk {
+ compatible = "renesas,h8s2678-pll-clock";
+ clocks = <&xclk>;
+ #clock-cells = <0>;
+ reg = <0xfee03b 2>, <0xfee045 2>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/zx296702-clk.txt b/Documentation/devicetree/bindings/clock/zx296702-clk.txt
new file mode 100644
index 000000000000..750442b65505
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/zx296702-clk.txt
@@ -0,0 +1,35 @@
+Device Tree Clock bindings for ZTE zx296702
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be one of the following:
+ "zte,zx296702-topcrm-clk":
+ zx296702 top clock selection, divider and gating
+
+ "zte,zx296702-lsp0crpm-clk" and
+ "zte,zx296702-lsp1crpm-clk":
+ zx296702 device level clock selection and gating
+
+- reg: Address and length of the register set
+
+The clock consumer should specify the desired clock by having the clock
+ID in its "clocks" phandle cell. See include/dt-bindings/clock/zx296702-clock.h
+for the full list of zx296702 clock IDs.
+
+
+topclk: topcrm@0x09800000 {
+ compatible = "zte,zx296702-topcrm-clk";
+ reg = <0x09800000 0x1000>;
+ #clock-cells = <1>;
+};
+
+uart0: serial@0x09405000 {
+ compatible = "zte,zx296702-uart";
+ reg = <0x09405000 0x1000>;
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&lsp1clk ZX296702_UART0_PCLK>;
+ status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec2.txt b/Documentation/devicetree/bindings/crypto/fsl-sec2.txt
index 38988ef1336b..f0d926bf9f36 100644
--- a/Documentation/devicetree/bindings/crypto/fsl-sec2.txt
+++ b/Documentation/devicetree/bindings/crypto/fsl-sec2.txt
@@ -1,9 +1,11 @@
-Freescale SoC SEC Security Engines versions 2.x-3.x
+Freescale SoC SEC Security Engines versions 1.x-2.x-3.x
Required properties:
- compatible : Should contain entries for this and backward compatible
- SEC versions, high to low, e.g., "fsl,sec2.1", "fsl,sec2.0"
+ SEC versions, high to low, e.g., "fsl,sec2.1", "fsl,sec2.0" (SEC2/3)
+ e.g., "fsl,sec1.2", "fsl,sec1.0" (SEC1)
+ warning: SEC1 and SEC2 are mutually exclusive
- reg : Offset and length of the register set for the device
- interrupts : the SEC's interrupt number
- fsl,num-channels : An integer representing the number of channels
diff --git a/Documentation/devicetree/bindings/crypto/marvell-cesa.txt b/Documentation/devicetree/bindings/crypto/marvell-cesa.txt
new file mode 100644
index 000000000000..c6c6a4a045bd
--- /dev/null
+++ b/Documentation/devicetree/bindings/crypto/marvell-cesa.txt
@@ -0,0 +1,45 @@
+Marvell Cryptographic Engines And Security Accelerator
+
+Required properties:
+- compatible: should be one of the following string
+ "marvell,orion-crypto"
+ "marvell,kirkwood-crypto"
+ "marvell,dove-crypto"
+ "marvell,armada-370-crypto"
+ "marvell,armada-xp-crypto"
+ "marvell,armada-375-crypto"
+ "marvell,armada-38x-crypto"
+- reg: base physical address of the engine and length of memory mapped
+ region. Can also contain an entry for the SRAM attached to the CESA,
+ but this representation is deprecated and marvell,crypto-srams should
+ be used instead
+- reg-names: "regs". Can contain an "sram" entry, but this representation
+ is deprecated and marvell,crypto-srams should be used instead
+- interrupts: interrupt number
+- clocks: reference to the crypto engines clocks. This property is not
+ required for orion and kirkwood platforms
+- clock-names: "cesaX" and "cesazX", X should be replaced by the crypto engine
+ id.
+ This property is not required for the orion and kirkwoord
+ platforms.
+ "cesazX" clocks are not required on armada-370 platforms
+- marvell,crypto-srams: phandle to crypto SRAM definitions
+
+Optional properties:
+- marvell,crypto-sram-size: SRAM size reserved for crypto operations, if not
+ specified the whole SRAM is used (2KB)
+
+
+Examples:
+
+ crypto@90000 {
+ compatible = "marvell,armada-xp-crypto";
+ reg = <0x90000 0x10000>;
+ reg-names = "regs";
+ interrupts = <48>, <49>;
+ clocks = <&gateclk 23>, <&gateclk 23>;
+ clock-names = "cesa0", "cesa1";
+ marvell,crypto-srams = <&crypto_sram0>, <&crypto_sram1>;
+ marvell,crypto-sram-size = <0x600>;
+ status = "okay";
+ };
diff --git a/Documentation/devicetree/bindings/crypto/mv_cesa.txt b/Documentation/devicetree/bindings/crypto/mv_cesa.txt
index 47229b1a594b..c0c35f00335b 100644
--- a/Documentation/devicetree/bindings/crypto/mv_cesa.txt
+++ b/Documentation/devicetree/bindings/crypto/mv_cesa.txt
@@ -1,20 +1,33 @@
Marvell Cryptographic Engines And Security Accelerator
Required properties:
-- compatible : should be "marvell,orion-crypto"
-- reg : base physical address of the engine and length of memory mapped
- region, followed by base physical address of sram and its memory
- length
-- reg-names : "regs" , "sram";
-- interrupts : interrupt number
+- compatible: should be one of the following string
+ "marvell,orion-crypto"
+ "marvell,kirkwood-crypto"
+ "marvell,dove-crypto"
+- reg: base physical address of the engine and length of memory mapped
+ region. Can also contain an entry for the SRAM attached to the CESA,
+ but this representation is deprecated and marvell,crypto-srams should
+ be used instead
+- reg-names: "regs". Can contain an "sram" entry, but this representation
+ is deprecated and marvell,crypto-srams should be used instead
+- interrupts: interrupt number
+- clocks: reference to the crypto engines clocks. This property is only
+ required for Dove platforms
+- marvell,crypto-srams: phandle to crypto SRAM definitions
+
+Optional properties:
+- marvell,crypto-sram-size: SRAM size reserved for crypto operations, if not
+ specified the whole SRAM is used (2KB)
Examples:
crypto@30000 {
compatible = "marvell,orion-crypto";
- reg = <0x30000 0x10000>,
- <0x4000000 0x800>;
- reg-names = "regs" , "sram";
+ reg = <0x30000 0x10000>;
+ reg-names = "regs";
interrupts = <22>;
+ marvell,crypto-srams = <&crypto_sram>;
+ marvell,crypto-sram-size = <0x600>;
status = "okay";
};
diff --git a/Documentation/devicetree/bindings/drm/msm/dsi.txt b/Documentation/devicetree/bindings/drm/msm/dsi.txt
new file mode 100644
index 000000000000..cd8fe6cf536c
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/msm/dsi.txt
@@ -0,0 +1,120 @@
+Qualcomm Technologies Inc. adreno/snapdragon DSI output
+
+DSI Controller:
+Required properties:
+- compatible:
+ * "qcom,mdss-dsi-ctrl"
+- reg: Physical base address and length of the registers of controller
+- reg-names: The names of register regions. The following regions are required:
+ * "dsi_ctrl"
+- qcom,dsi-host-index: The ID of DSI controller hardware instance. This should
+ be 0 or 1, since we have 2 DSI controllers at most for now.
+- interrupts: The interrupt signal from the DSI block.
+- power-domains: Should be <&mmcc MDSS_GDSC>.
+- clocks: device clocks
+ See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
+- clock-names: the following clocks are required:
+ * "bus_clk"
+ * "byte_clk"
+ * "core_clk"
+ * "core_mmss_clk"
+ * "iface_clk"
+ * "mdp_core_clk"
+ * "pixel_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
+
+Optional properties:
+- panel@0: Node of panel connected to this DSI controller.
+ See files in Documentation/devicetree/bindings/panel/ for each supported
+ panel.
+- qcom,dual-panel-mode: Boolean value indicating if the DSI controller is
+ driving a panel which needs 2 DSI links.
+- qcom,master-panel: Boolean value indicating if the DSI controller is driving
+ the master link of the 2-DSI panel.
+- qcom,sync-dual-panel: Boolean value indicating if the DSI controller is
+ driving a 2-DSI panel whose 2 links need receive command simultaneously.
+- interrupt-parent: phandle to the MDP block if the interrupt signal is routed
+ through MDP block
+
+DSI PHY:
+Required properties:
+- compatible: Could be the following
+ * "qcom,dsi-phy-28nm-hpm"
+ * "qcom,dsi-phy-28nm-lp"
+- 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:
+ * "dsi_pll"
+ * "dsi_phy"
+ * "dsi_phy_regulator"
+- qcom,dsi-phy-index: The ID of DSI PHY hardware instance. This should
+ be 0 or 1, since we have 2 DSI PHYs at most for now.
+- power-domains: Should be <&mmcc MDSS_GDSC>.
+- clocks: device clocks
+ See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
+- clock-names: the following clocks are required:
+ * "iface_clk"
+- vddio-supply: phandle to vdd-io regulator device node
+
+Example:
+ mdss_dsi0: qcom,mdss_dsi@fd922800 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ qcom,dsi-host-index = <0>;
+ interrupt-parent = <&mdss_mdp>;
+ interrupts = <4 0>;
+ reg-names = "dsi_ctrl";
+ reg = <0xfd922800 0x200>;
+ power-domains = <&mmcc MDSS_GDSC>;
+ clock-names =
+ "bus_clk",
+ "byte_clk",
+ "core_clk",
+ "core_mmss_clk",
+ "iface_clk",
+ "mdp_core_clk",
+ "pixel_clk";
+ clocks =
+ <&mmcc MDSS_AXI_CLK>,
+ <&mmcc MDSS_BYTE0_CLK>,
+ <&mmcc MDSS_ESC0_CLK>,
+ <&mmcc MMSS_MISC_AHB_CLK>,
+ <&mmcc MDSS_AHB_CLK>,
+ <&mmcc MDSS_MDP_CLK>,
+ <&mmcc MDSS_PCLK0_CLK>;
+ vdda-supply = <&pma8084_l2>;
+ vdd-supply = <&pma8084_l22>;
+ vddio-supply = <&pma8084_l12>;
+
+ qcom,dsi-phy = <&mdss_dsi_phy0>;
+
+ qcom,dual-panel-mode;
+ qcom,master-panel;
+ qcom,sync-dual-panel;
+
+ panel: panel@0 {
+ compatible = "sharp,lq101r1sx01";
+ reg = <0>;
+ link2 = <&secondary>;
+
+ power-supply = <...>;
+ backlight = <...>;
+ };
+ };
+
+ mdss_dsi_phy0: qcom,mdss_dsi_phy@fd922a00 {
+ compatible = "qcom,dsi-phy-28nm-hpm";
+ qcom,dsi-phy-index = <0>;
+ reg-names =
+ "dsi_pll",
+ "dsi_phy",
+ "dsi_phy_regulator";
+ reg = <0xfd922a00 0xd4>,
+ <0xfd922b00 0x2b0>,
+ <0xfd922d80 0x7b>;
+ clock-names = "iface_clk";
+ clocks = <&mmcc MDSS_AHB_CLK>;
+ vddio-supply = <&pma8084_l12>;
+ };
diff --git a/Documentation/devicetree/bindings/drm/msm/edp.txt b/Documentation/devicetree/bindings/drm/msm/edp.txt
new file mode 100644
index 000000000000..3a20f6ea5898
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/msm/edp.txt
@@ -0,0 +1,60 @@
+Qualcomm Technologies Inc. adreno/snapdragon eDP output
+
+Required properties:
+- compatible:
+ * "qcom,mdss-edp"
+- reg: Physical base address and length of the registers of controller and PLL
+- reg-names: The names of register regions. The following regions are required:
+ * "edp"
+ * "pll_base"
+- interrupts: The interrupt signal from the eDP block.
+- power-domains: Should be <&mmcc MDSS_GDSC>.
+- clocks: device clocks
+ See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
+- clock-names: the following clocks are required:
+ * "core_clk"
+ * "iface_clk"
+ * "mdp_core_clk"
+ * "pixel_clk"
+ * "link_clk"
+- #clock-cells: The value should be 1.
+- vdda-supply: phandle to vdda regulator device node
+- lvl-vdd-supply: phandle to regulator device node which is used to supply power
+ to HPD receiving chip
+- panel-en-gpios: GPIO pin to supply power to panel.
+- panel-hpd-gpios: GPIO pin used for eDP hpd.
+
+
+Optional properties:
+- interrupt-parent: phandle to the MDP block if the interrupt signal is routed
+ through MDP block
+
+Example:
+ mdss_edp: qcom,mdss_edp@fd923400 {
+ compatible = "qcom,mdss-edp";
+ reg-names =
+ "edp",
+ "pll_base";
+ reg = <0xfd923400 0x700>,
+ <0xfd923a00 0xd4>;
+ interrupt-parent = <&mdss_mdp>;
+ interrupts = <12 0>;
+ power-domains = <&mmcc MDSS_GDSC>;
+ clock-names =
+ "core_clk",
+ "pixel_clk",
+ "iface_clk",
+ "link_clk",
+ "mdp_core_clk";
+ clocks =
+ <&mmcc MDSS_EDPAUX_CLK>,
+ <&mmcc MDSS_EDPPIXEL_CLK>,
+ <&mmcc MDSS_AHB_CLK>,
+ <&mmcc MDSS_EDPLINK_CLK>,
+ <&mmcc MDSS_MDP_CLK>;
+ #clock-cells = <1>;
+ vdda-supply = <&pma8084_l12>;
+ lvl-vdd-supply = <&lvl_vreg>;
+ panel-en-gpios = <&tlmm 137 0>;
+ panel-hpd-gpios = <&tlmm 103 0>;
+ };
diff --git a/Documentation/devicetree/bindings/drm/msm/hdmi.txt b/Documentation/devicetree/bindings/drm/msm/hdmi.txt
index a29a55f3d937..c43aa53debed 100644
--- a/Documentation/devicetree/bindings/drm/msm/hdmi.txt
+++ b/Documentation/devicetree/bindings/drm/msm/hdmi.txt
@@ -20,6 +20,9 @@ Required properties:
Optional properties:
- qcom,hdmi-tx-mux-en-gpio: hdmi mux enable pin
- qcom,hdmi-tx-mux-sel-gpio: hdmi mux select pin
+- pinctrl-names: the pin control state names; should contain "default"
+- pinctrl-0: the default pinctrl state (active)
+- pinctrl-1: the "sleep" pinctrl state
Example:
@@ -44,5 +47,8 @@ Example:
qcom,hdmi-tx-hpd = <&msmgpio 72 GPIO_ACTIVE_HIGH>;
core-vdda-supply = <&pm8921_hdmi_mvs>;
hdmi-mux-supply = <&ext_3p3v>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&hpd_active &ddc_active &cec_active>;
+ pinctrl-1 = <&hpd_suspend &ddc_suspend &cec_suspend>;
};
};
diff --git a/Documentation/devicetree/bindings/drm/tilcdc/slave.txt b/Documentation/devicetree/bindings/drm/tilcdc/slave.txt
deleted file mode 100644
index 3d2c52460dca..000000000000
--- a/Documentation/devicetree/bindings/drm/tilcdc/slave.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-Device-Tree bindings for tilcdc DRM encoder slave output driver
-
-Required properties:
- - compatible: value should be "ti,tilcdc,slave".
- - i2c: the phandle for the i2c device the encoder slave is connected to
-
-Recommended properties:
- - pinctrl-names, pinctrl-0: the pincontrol settings to configure
- muxing properly for pins that connect to TFP410 device
-
-Example:
-
- hdmi {
- compatible = "ti,tilcdc,slave";
- i2c = <&i2c0>;
- pinctrl-names = "default";
- pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
- };
diff --git a/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt b/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt
index fff10da5e927..2136ee81e061 100644
--- a/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt
+++ b/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt
@@ -18,6 +18,12 @@ Optional properties:
- max-pixelclock: The maximum pixel clock that can be supported
by the lcd controller in KHz.
+Optional nodes:
+
+ - port/ports: to describe a connection to an external encoder. The
+ binding follows Documentation/devicetree/bindings/graph.txt and
+ suppors a single port with a single endpoint.
+
Example:
fb: fb@4830e000 {
@@ -26,4 +32,25 @@ Example:
interrupt-parent = <&intc>;
interrupts = <36>;
ti,hwmods = "lcdc";
+
+ port {
+ lcdc_0: endpoint@0 {
+ remote-endpoint = <&hdmi_0>;
+ };
+ };
+ };
+
+ tda19988: tda19988 {
+ compatible = "nxp,tda998x";
+ reg = <0x70>;
+
+ pinctrl-names = "default", "off";
+ pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
+ pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
+
+ port {
+ hdmi_0: endpoint@0 {
+ remote-endpoint = <&lcdc_0>;
+ };
+ };
};
diff --git a/Documentation/devicetree/bindings/edac/apm-xgene-edac.txt b/Documentation/devicetree/bindings/edac/apm-xgene-edac.txt
new file mode 100644
index 000000000000..78edb80002c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/edac/apm-xgene-edac.txt
@@ -0,0 +1,79 @@
+* APM X-Gene SoC EDAC node
+
+EDAC node is defined to describe on-chip error detection and correction.
+The follow error types are supported:
+
+ memory controller - Memory controller
+ PMD (L1/L2) - Processor module unit (PMD) L1/L2 cache
+
+The following section describes the EDAC DT node binding.
+
+Required properties:
+- compatible : Shall be "apm,xgene-edac".
+- regmap-csw : Regmap of the CPU switch fabric (CSW) resource.
+- regmap-mcba : Regmap of the MCB-A (memory bridge) resource.
+- regmap-mcbb : Regmap of the MCB-B (memory bridge) resource.
+- regmap-efuse : Regmap of the PMD efuse resource.
+- reg : First resource shall be the CPU bus (PCP) resource.
+- interrupts : Interrupt-specifier for MCU, PMD, L3, or SoC error
+ IRQ(s).
+
+Required properties for memory controller subnode:
+- compatible : Shall be "apm,xgene-edac-mc".
+- reg : First resource shall be the memory controller unit
+ (MCU) resource.
+- memory-controller : Instance number of the memory controller.
+
+Required properties for PMD subnode:
+- compatible : Shall be "apm,xgene-edac-pmd" or
+ "apm,xgene-edac-pmd-v2".
+- reg : First resource shall be the PMD resource.
+- pmd-controller : Instance number of the PMD controller.
+
+Example:
+ 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>;
+ };
+
+ edacpmd@7c000000 {
+ compatible = "apm,xgene-edac-pmd";
+ reg = <0x0 0x7c000000 0x0 0x200000>;
+ pmd-controller = <0>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt b/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt
index 23e1d3194174..41372d441131 100644
--- a/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt
+++ b/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt
@@ -29,7 +29,7 @@ Example:
fuse@7000f800 {
compatible = "nvidia,tegra20-efuse";
- reg = <0x7000F800 0x400>,
+ reg = <0x7000f800 0x400>,
<0x70000000 0x400>;
clocks = <&tegra_car TEGRA20_CLK_FUSE>;
clock-names = "fuse";
diff --git a/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt b/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
new file mode 100644
index 000000000000..435f1bcca341
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
@@ -0,0 +1,65 @@
+Broadcom STB "UPG GIO" GPIO controller
+
+The controller's registers are organized as sets of eight 32-bit
+registers with each set controlling a bank of up to 32 pins. A single
+interrupt is shared for all of the banks handled by the controller.
+
+Required properties:
+
+- compatible:
+ Must be "brcm,brcmstb-gpio"
+
+- reg:
+ Define the base and range of the I/O address space containing
+ the brcmstb GPIO controller registers
+
+- #gpio-cells:
+ Should be <2>. The first cell is the pin number (within the controller's
+ pin space), and the second is used for the following:
+ bit[0]: polarity (0 for active-high, 1 for active-low)
+
+- gpio-controller:
+ Specifies that the node is a GPIO controller.
+
+- brcm,gpio-bank-widths:
+ Number of GPIO lines for each bank. Number of elements must
+ correspond to number of banks suggested by the 'reg' property.
+
+Optional properties:
+
+- interrupts:
+ The interrupt shared by all GPIO lines for this controller.
+
+- interrupt-parent:
+ phandle of the parent interrupt controller
+
+- #interrupt-cells:
+ Should be <2>. The first cell is the GPIO number, the second should specify
+ flags. The following subset of flags is supported:
+ - bits[3:0] trigger type and level flags
+ 1 = low-to-high edge triggered
+ 2 = high-to-low edge triggered
+ 4 = active high level-sensitive
+ 8 = active low level-sensitive
+ Valid combinations are 1, 2, 3, 4, 8.
+ See also Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+
+- interrupt-controller:
+ Marks the device node as an interrupt controller
+
+- interrupt-names:
+ The name of the IRQ resource used by this controller
+
+Example:
+ upg_gio: gpio@f040a700 {
+ #gpio-cells = <0x2>;
+ #interrupt-cells = <0x2>;
+ compatible = "brcm,bcm7445-gpio", "brcm,brcmstb-gpio";
+ gpio-controller;
+ interrupt-controller;
+ reg = <0xf040a700 0x80>;
+ interrupt-parent = <0xf>;
+ interrupts = <0x6>;
+ interrupt-names = "upg_gio";
+ brcm,gpio-bank-widths = <0x20 0x20 0x20 0x18>;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-atlas7.txt b/Documentation/devicetree/bindings/gpio/gpio-atlas7.txt
new file mode 100644
index 000000000000..d7e123fc90b5
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-atlas7.txt
@@ -0,0 +1,50 @@
+CSR SiRFatlas7 GPIO controller bindings
+
+Required properties:
+- compatible : "sirf,atlas7-gpio"
+- reg : Address range of the pinctrl registers
+- interrupts : Interrupts used by every GPIO group
+- gpio-banks : How many gpio banks on this controller
+- gpio-controller : Indicates this device is a GPIO controller
+- interrupt-controller : Marks the device node as an interrupt controller
+
+The GPIO controller also acts as an interrupt controller. It uses the default
+two cells specifier as described in Documentation/devicetree/bindings/
+interrupt-controller/interrupts.txt.
+
+Example:
+
+ gpio_0: gpio_mediam@17040000 {
+ compatible = "sirf,atlas7-gpio";
+ reg = <0x17040000 0x1000>;
+ interrupts = <0 13 0>, <0 14 0>;
+
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+
+ gpio-controller;
+ interrupt-controller;
+
+ gpio-banks = <2>;
+ gpio-ranges = <&pinctrl 0 0 0>,
+ <&pinctrl 32 0 0>;
+ gpio-ranges-group-names = "lvds_gpio_grp",
+ "uart_nand_gpio_grp";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led1 {
+ gpios = <&gpio_1 15 0>;
+ ...
+ };
+
+ led2 {
+ gpios = <&gpio_2 34 0>;
+ ...
+ };
+ };
+
+Please refer to gpio.txt in this directory for details of the common
+gpio properties used by devices.
diff --git a/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt b/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt
new file mode 100644
index 000000000000..abf4db736c6e
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt
@@ -0,0 +1,21 @@
+Axis ETRAX FS General I/O controller bindings
+
+Required properties:
+
+- compatible:
+ - "axis,etraxfs-gio"
+- reg: Physical base address and length of the controller's registers.
+- #gpio-cells: Should be 3
+ - The first cell is the gpio offset number.
+ - The second cell is reserved and is currently unused.
+ - The third cell is the port number (hex).
+- gpio-controller: Marks the device node as a GPIO controller.
+
+Example:
+
+ gio: gpio@b001a000 {
+ compatible = "axis,etraxfs-gio";
+ reg = <0xb001a000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <3>;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-xlp.txt b/Documentation/devicetree/bindings/gpio/gpio-xlp.txt
new file mode 100644
index 000000000000..262ee4ddf2cb
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-xlp.txt
@@ -0,0 +1,47 @@
+Netlogic XLP Family GPIO
+========================
+
+This GPIO driver is used for following Netlogic XLP SoCs:
+ XLP832, XLP316, XLP208, XLP980, XLP532
+
+Required properties:
+-------------------
+
+- compatible: Should be one of the following:
+ - "netlogic,xlp832-gpio": For Netlogic XLP832
+ - "netlogic,xlp316-gpio": For Netlogic XLP316
+ - "netlogic,xlp208-gpio": For Netlogic XLP208
+ - "netlogic,xlp980-gpio": For Netlogic XLP980
+ - "netlogic,xlp532-gpio": For Netlogic XLP532
+- reg: Physical base address and length of the controller's registers.
+- #gpio-cells: Should be two. The first cell is the pin number and the second
+ cell is used to specify optional parameters (currently unused).
+- gpio-controller: Marks the device node as a GPIO controller.
+- nr-gpios: Number of GPIO pins supported by the controller.
+- interrupt-cells: Should be two. The first cell is the GPIO Number. The
+ second cell is used to specify flags. The following subset of flags is
+ supported:
+ - trigger type:
+ 1 = low to high edge triggered.
+ 2 = high to low edge triggered.
+ 4 = active high level-sensitive.
+ 8 = active low level-sensitive.
+- interrupts: Interrupt number for this device.
+- interrupt-parent: phandle of the parent interrupt controller.
+- interrupt-controller: Identifies the node as an interrupt controller.
+
+Example:
+
+ gpio: xlp_gpio@34000 {
+ compatible = "netlogic,xlp316-gpio";
+ reg = <0 0x34100 0x1000
+ 0 0x35100 0x1000>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ nr-gpios = <57>;
+
+ #interrupt-cells = <2>;
+ interrupt-parent = <&pic>;
+ interrupts = <39>;
+ interrupt-controller;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-zynq.txt b/Documentation/devicetree/bindings/gpio/gpio-zynq.txt
index 986371a4be2c..db4c6a663c03 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-zynq.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-zynq.txt
@@ -6,7 +6,7 @@ Required properties:
- First cell is the GPIO line number
- Second cell is used to specify optional
parameters (unused)
-- compatible : Should be "xlnx,zynq-gpio-1.0"
+- compatible : Should be "xlnx,zynq-gpio-1.0" or "xlnx,zynqmp-gpio-1.0"
- clocks : Clock specifier (see clock bindings for details)
- gpio-controller : Marks the device node as a GPIO controller.
- interrupts : Interrupt specifier (see interrupt bindings for
diff --git a/Documentation/devicetree/bindings/gpio/nxp,lpc1850-gpio.txt b/Documentation/devicetree/bindings/gpio/nxp,lpc1850-gpio.txt
new file mode 100644
index 000000000000..eb7cdd69e10b
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/nxp,lpc1850-gpio.txt
@@ -0,0 +1,39 @@
+NXP LPC18xx/43xx GPIO controller Device Tree Bindings
+-----------------------------------------------------
+
+Required properties:
+- compatible : Should be "nxp,lpc1850-gpio"
+- reg : Address and length of the register set for the device
+- clocks : Clock specifier (see clock bindings for details)
+- gpio-controller : Marks the device node as a GPIO controller.
+- #gpio-cells : Should be two
+ - First cell is the GPIO line number
+ - Second cell is used to specify polarity
+
+Optional properties:
+- gpio-ranges : Mapping between GPIO and pinctrl
+
+Example:
+#define LPC_GPIO(port, pin) (port * 32 + pin)
+#define LPC_PIN(port, pin) (0x##port * 32 + pin)
+
+gpio: gpio@400f4000 {
+ compatible = "nxp,lpc1850-gpio";
+ reg = <0x400f4000 0x4000>;
+ clocks = <&ccu1 CLK_CPU_GPIO>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinctrl LPC_GPIO(0,0) LPC_PIN(0,0) 2>,
+ ...
+ <&pinctrl LPC_GPIO(7,19) LPC_PIN(f,5) 7>;
+};
+
+gpio_joystick {
+ compatible = "gpio-keys-polled";
+ ...
+
+ button@0 {
+ ...
+ gpios = <&gpio LPC_GPIO(4,8) GPIO_ACTIVE_LOW>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/h8300/cpu.txt b/Documentation/devicetree/bindings/h8300/cpu.txt
new file mode 100644
index 000000000000..70cd58608f4b
--- /dev/null
+++ b/Documentation/devicetree/bindings/h8300/cpu.txt
@@ -0,0 +1,13 @@
+* H8/300 CPU bindings
+
+Required properties:
+
+- compatible: Compatible property value should be "renesas,h8300".
+- clock-frequency: Contains the clock frequency for CPU, in Hz.
+
+Example:
+
+ cpu@0 {
+ compatible = "renesas,h8300";
+ clock-frequency = <20000000>;
+ };
diff --git a/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt b/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt
index fcca8e744f41..a04a80f9cc70 100644
--- a/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt
+++ b/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt
@@ -9,6 +9,7 @@ Requires node properties:
"murata,ncp21wb473"
"murata,ncp03wb473"
"murata,ncp15wl333"
+ "murata,ncp03wf104"
/* Usage of vendor name "ntc" is deprecated */
<DEPRECATED> "ntc,ncp15wb473"
diff --git a/Documentation/devicetree/bindings/i2c/i2c-at91.txt b/Documentation/devicetree/bindings/i2c/i2c-at91.txt
index 388f0a275fba..6e81dc153f3b 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-at91.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-at91.txt
@@ -2,8 +2,8 @@ I2C for Atmel platforms
Required properties :
- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
- "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c"
- or "atmel,at91sam9x5-i2c"
+ "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c",
+ "atmel,at91sam9x5-i2c" or "atmel,sama5d2-i2c"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: interrupt number to the cpu.
@@ -13,6 +13,10 @@ Required properties :
Optional properties:
- clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000
+- dmas: A list of two dma specifiers, one for each entry in dma-names.
+- 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.
- Child nodes conforming to i2c bus binding
Examples :
@@ -32,3 +36,25 @@ i2c0: i2c@fff84000 {
pagesize = <128>;
}
}
+
+i2c0: i2c@f8034600 {
+ compatible = "atmel,sama5d2-i2c";
+ reg = <0xf8034600 0x100>;
+ interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>;
+ dmas = <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1))
+ AT91_XDMAC_DT_PERID(11)>,
+ <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1))
+ AT91_XDMAC_DT_PERID(12)>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&flx0>;
+ atmel,fifo-size = <16>;
+
+ wm8731: wm8731@1a {
+ compatible = "wm8731";
+ reg = <0x1a>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt b/Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt
new file mode 100644
index 000000000000..d6f724efdcf2
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-brcmstb.txt
@@ -0,0 +1,28 @@
+Broadcom stb bsc iic master controller
+
+Required properties:
+
+- compatible: should be "brcm,brcmstb-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
+- reg: specifies the base physical address and size of the registers
+
+Optional properties :
+
+- interrupt-parent: specifies the phandle to the parent interrupt controller
+ this one is cascaded from
+- interrupts: specifies the interrupt number, the irq line to be used
+- interrupt-names: Interrupt name string
+
+Example:
+
+bsca: i2c@f0406200 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&irq0_intc>;
+ reg = <0xf0406200 0x58>;
+ interrupts = <0x18>;
+ interrupt-names = "upg_bsca";
+};
+
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mt6577.txt b/Documentation/devicetree/bindings/i2c/i2c-mt6577.txt
new file mode 100644
index 000000000000..0ce6fa3242f0
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-mt6577.txt
@@ -0,0 +1,41 @@
+* Mediatek's I2C controller
+
+The Mediatek's I2C controller is used to interface with I2C devices.
+
+Required properties:
+ - compatible: value should be either of the following.
+ (a) "mediatek,mt6577-i2c", for i2c compatible with mt6577 i2c.
+ (b) "mediatek,mt6589-i2c", for i2c compatible with mt6589 i2c.
+ (c) "mediatek,mt8127-i2c", for i2c compatible with mt8127 i2c.
+ (d) "mediatek,mt8135-i2c", for i2c compatible with mt8135 i2c.
+ (e) "mediatek,mt8173-i2c", for i2c compatible with mt8173 i2c.
+ - reg: physical base address of the controller and dma base, length of memory
+ mapped region.
+ - interrupts: interrupt number to the cpu.
+ - clock-div: the fixed value for frequency divider of clock source in i2c
+ module. Each IC may be different.
+ - clocks: clock name from clock manager
+ - clock-names: Must include "main" and "dma", if enable have-pmic need include
+ "pmic" extra.
+
+Optional properties:
+ - clock-frequency: Frequency in Hz of the bus when transfer, the default value
+ is 100000.
+ - mediatek,have-pmic: platform can control i2c form special pmic side.
+ Only mt6589 and mt8135 support this feature.
+ - mediatek,use-push-pull: IO config use push-pull mode.
+
+Example:
+
+ i2c0: i2c@1100d000 {
+ compatible = "mediatek,mt6577-i2c";
+ reg = <0x1100d000 0x70>,
+ <0x11000300 0x80>;
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_LOW>;
+ clock-frequency = <400000>;
+ mediatek,have-pmic;
+ clock-div = <16>;
+ clocks = <&i2c0_ck>, <&ap_dma_ck>;
+ clock-names = "main", "dma";
+ };
+
diff --git a/Documentation/devicetree/bindings/i2c/i2c-xgene-slimpro.txt b/Documentation/devicetree/bindings/i2c/i2c-xgene-slimpro.txt
new file mode 100644
index 000000000000..f6b2c20cfbf6
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-xgene-slimpro.txt
@@ -0,0 +1,15 @@
+APM X-Gene SLIMpro Mailbox I2C Driver
+
+An I2C controller accessed over the "SLIMpro" mailbox.
+
+Required properties :
+
+ - compatible : should be "apm,xgene-slimpro-i2c"
+ - mboxes : use the label reference for the mailbox as the first parameter.
+ The second parameter is the channel number.
+
+Example :
+ i2cslimpro {
+ compatible = "apm,xgene-slimpro-i2c";
+ mboxes = <&mailbox 0>;
+ };
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index ad0c4ac916dd..00f8652e193a 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -19,8 +19,7 @@ adi,adt7475 +/-1C TDM Extended Temp Range I.C
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
-adi,adxl34x Three-Axis Digital Accelerometer
+adi,adxl346 Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too)
at,24c08 i2c serial eeprom (24cxx)
atmel,24c00 i2c serial eeprom (24cxx)
atmel,24c01 i2c serial eeprom (24cxx)
diff --git a/Documentation/devicetree/bindings/iio/adc/berlin2_adc.txt b/Documentation/devicetree/bindings/iio/adc/berlin2_adc.txt
new file mode 100644
index 000000000000..908334c6b07f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/berlin2_adc.txt
@@ -0,0 +1,19 @@
+* Berlin Analog to Digital Converter (ADC)
+
+The Berlin ADC has 8 channels, with one connected to a temperature sensor.
+It is part of the system controller register set. The ADC node should be a
+sub-node of the system controller node.
+
+Required properties:
+- compatible: must be "marvell,berlin2-adc"
+- interrupts: the interrupts for the ADC and the temperature sensor
+- interrupt-names: should be "adc" and "tsen"
+
+Example:
+
+adc: adc {
+ compatible = "marvell,berlin2-adc";
+ interrupt-parent = <&sic>;
+ interrupts = <12>, <14>;
+ interrupt-names = "adc", "tsen";
+};
diff --git a/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt b/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt
index 42ca7deec97d..15ca6b47958e 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 ADC chip
+* Texas Instruments' ADC128S052 and ADC122S021 ADC chip
Required properties:
- - compatible: Should be "ti,adc128s052"
+ - compatible: Should be "ti,adc128s052" or "ti,adc122s021"
- 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/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
index 1a4a43d5c9ea..3eb40e20c143 100644
--- a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
@@ -11,6 +11,13 @@ Required properties:
- clock-names: Must contain "adc", matching entry in the clocks property.
- vref-supply: The regulator supply ADC reference voltage.
+Recommended properties:
+- fsl,adck-max-frequency: Maximum frequencies according to datasheets operating
+ requirements. Three values are required, depending on conversion mode:
+ - Frequency in normal mode (ADLPC=0, ADHSC=0)
+ - Frequency in high-speed mode (ADLPC=0, ADHSC=1)
+ - Frequency in low-power mode (ADLPC=1, ADHSC=0)
+
Example:
adc0: adc@4003b000 {
compatible = "fsl,vf610-adc";
@@ -18,5 +25,7 @@ adc0: adc@4003b000 {
interrupts = <0 53 0x04>;
clocks = <&clks VF610_CLK_ADC0>;
clock-names = "adc";
+ fsl,adck-max-frequency = <30000000>, <40000000>,
+ <20000000>;
vref-supply = <&reg_vcc_3v3_mcu>;
};
diff --git a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
new file mode 100644
index 000000000000..e4d8f1c52f4a
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
@@ -0,0 +1,17 @@
+InvenSense MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device
+
+http://www.invensense.com/mems/gyro/mpu6050.html
+
+Required properties:
+ - compatible : should be "invensense,mpu6050"
+ - reg : the I2C address of the sensor
+ - interrupt-parent : should be the phandle for the interrupt controller
+ - interrupts : interrupt mapping for GPIO IRQ
+
+Example:
+ mpu6050@68 {
+ compatible = "invensense,mpu6050";
+ reg = <0x68>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <18 1>;
+ };
diff --git a/Documentation/devicetree/bindings/iio/magnetometer/bmc150_magn.txt b/Documentation/devicetree/bindings/iio/magnetometer/bmc150_magn.txt
new file mode 100644
index 000000000000..9f263b7df162
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/magnetometer/bmc150_magn.txt
@@ -0,0 +1,22 @@
+* Bosch BMC150 magnetometer sensor
+
+http://ae-bst.resource.bosch.com/media/products/dokumente/bmc150/BST-BMC150-DS000-04.pdf
+
+Required properties:
+
+ - compatible : should be "bosch,bmc150_magn"
+ - reg : the I2C address of the magnetometer
+
+Optional properties:
+
+ - interrupt-parent : phandle to the parent interrupt controller
+ - interrupts : interrupt mapping for GPIO IRQ
+
+Example:
+
+bmc150_magn@12 {
+ compatible = "bosch,bmc150_magn";
+ reg = <0x12>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <0 1>;
+};
diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt
index d2aaca974531..8a6be3bdf267 100644
--- a/Documentation/devicetree/bindings/iio/st-sensors.txt
+++ b/Documentation/devicetree/bindings/iio/st-sensors.txt
@@ -30,6 +30,7 @@ Accelerometers:
- st,lsm330d-accel
- st,lsm330dl-accel
- st,lsm330dlc-accel
+- st,lis331dl-accel
- st,lis331dlh-accel
- st,lsm303dl-accel
- st,lsm303dlm-accel
@@ -45,6 +46,7 @@ Gyroscopes:
- st,lsm330-gyro
Magnetometers:
+- st,lsm303dlh-magn
- st,lsm303dlhc-magn
- st,lsm303dlm-magn
- st,lis3mdl-magn
diff --git a/Documentation/devicetree/bindings/iio/temperature/mlx90614.txt b/Documentation/devicetree/bindings/iio/temperature/mlx90614.txt
new file mode 100644
index 000000000000..9be57b036092
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/temperature/mlx90614.txt
@@ -0,0 +1,24 @@
+* Melexis MLX90614 contactless IR temperature sensor
+
+http://melexis.com/Infrared-Thermometer-Sensors/Infrared-Thermometer-Sensors/MLX90614-615.aspx
+
+Required properties:
+
+ - compatible: should be "melexis,mlx90614"
+ - reg: the I2C address of the sensor
+
+Optional properties:
+
+ - wakeup-gpios: device tree identifier of the GPIO connected to the SDA line
+ to hold low in order to wake up the device. In normal operation, the
+ GPIO is set as input and will not interfere in I2C communication. There
+ is no need for a GPIO driving the SCL line. If no GPIO is given, power
+ management is disabled.
+
+Example:
+
+mlx90614@5a {
+ compatible = "melexis,mlx90614";
+ reg = <0x5a>;
+ wakeup-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
+};
diff --git a/Documentation/devicetree/bindings/input/ti,drv2665.txt b/Documentation/devicetree/bindings/input/ti,drv2665.txt
new file mode 100644
index 000000000000..1ba97ac04305
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/ti,drv2665.txt
@@ -0,0 +1,17 @@
+* Texas Instruments - drv2665 Haptics driver
+
+Required properties:
+ - compatible - "ti,drv2665" - DRV2665
+ - reg - I2C slave address
+ - vbat-supply - Required supply regulator
+
+Example:
+
+haptics: haptics@59 {
+ compatible = "ti,drv2665";
+ reg = <0x59>;
+ vbat-supply = <&vbat>;
+};
+
+For more product information please see the link below:
+http://www.ti.com/product/drv2665
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt
index 6c4fb34823d3..b1163bf97146 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt
@@ -42,6 +42,27 @@ Optional properties:
hardware knob for adjusting the amount of "settling
time".
+- child "adc"
+ ti,chan-step-opendelay: List of open delays for each channel of
+ ADC in the order of ti,adc-channels. The
+ value corresponds to the number of ADC
+ clock cycles to wait after applying the
+ step configuration registers and before
+ sending the start of ADC conversion.
+ Maximum value is 0x3FFFF.
+ ti,chan-step-sampledelay: List of sample delays for each channel
+ of ADC in the order of ti,adc-channels.
+ The value corresponds to the number of
+ ADC clock cycles to sample (to hold
+ start of conversion high).
+ Maximum value is 0xFF.
+ ti,chan-step-avg: Number of averages to be performed for each
+ channel of ADC. If average is 16 then input
+ is sampled 16 times and averaged to get more
+ accurate value. This increases the time taken
+ by ADC to generate a sample. Valid range is 0
+ average to 16 averages. Maximum value is 16.
+
Example:
tscadc: tscadc@44e0d000 {
compatible = "ti,am3359-tscadc";
@@ -55,5 +76,8 @@ Example:
adc {
ti,adc-channels = <4 5 6 7>;
+ ti,chan-step-opendelay = <0x098 0x3ffff 0x098 0x0>;
+ ti,chan-step-sampledelay = <0xff 0x0 0xf 0x0>;
+ ti,chan-step-avg = <16 2 4 8>;
};
}
diff --git a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt
index f292917fa00d..0e9f09a6a2fe 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt
@@ -2,7 +2,7 @@
Required properties:
- compatible: Should be "atmel,<chip>-aic"
- <chip> can be "at91rm9200", "sama5d3" or "sama5d4"
+ <chip> can be "at91rm9200", "sama5d2", "sama5d3" or "sama5d4"
- interrupt-controller: Identifies the node as an interrupt controller.
- interrupt-parent: For single AIC system, it is an empty property.
- #interrupt-cells: The number of cells to define the interrupts. It should be 3.
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,h8300h-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,h8300h-intc.txt
new file mode 100644
index 000000000000..56e8d82aff34
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,h8300h-intc.txt
@@ -0,0 +1,22 @@
+* H8/300H Interrupt controller
+
+Required properties:
+
+- compatible: has to be "renesas,h8300h-intc", "renesas,h8300-intc" as fallback.
+- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
+ interrupts.txt in this directory
+- regs: Base address of interrupt controller registers.
+
+Optional properties:
+
+- any properties, listed in interrupts.txt, and any standard resource allocation
+ properties
+
+Example:
+
+ h8intc: interrupt-controller@fee012 {
+ compatible = "renesas,h8300h-intc", "renesas,h8300-intc";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0xfee012 7>;
+ };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,h8s-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,h8s-intc.txt
new file mode 100644
index 000000000000..faded2b1559b
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,h8s-intc.txt
@@ -0,0 +1,22 @@
+* H8S Interrupt controller
+
+Required properties:
+
+- compatible: has to be "renesas,h8s-intc", "renesas,h8300-intc" as fallback.
+- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
+ interrupts.txt in this directory
+- regs: Base address of interrupt controller registers.
+
+Optional properties:
+
+- any properties, listed in interrupts.txt, and any standard resource allocation
+ properties
+
+Example:
+
+ h8intc: interrupt-controller@fffe00 {
+ compatible = "renesas,h8s-intc", "renesas,h8300-intc";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0xfffe00 24>;
+ };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt
index 4f7946ae8adc..772c550d3b4b 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt
@@ -13,9 +13,12 @@ Required properties:
- reg: Base address and length of each register bank used by the external
IRQ pins driven by the interrupt controller hardware module. The base
addresses, length and number of required register banks varies with soctype.
-
+- interrupt-controller: Identifies the node as an interrupt controller.
- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
- interrupts.txt in this directory
+ interrupts.txt in this directory.
+- interrupts: Must contain a list of interrupt specifiers. For each interrupt
+ provided by this irqpin controller instance, there must be one entry,
+ referring to the corresponding parent interrupt.
Optional properties:
@@ -25,3 +28,35 @@ Optional properties:
if different from the default 4 bits
- control-parent: disable and enable interrupts on the parent interrupt
controller, needed for some broken implementations
+- clocks: Must contain a reference to the functional clock. This property is
+ mandatory if the hardware implements a controllable functional clock for
+ the irqpin controller instance.
+- power-domains: Must contain a reference to the power domain. This property is
+ mandatory if the irqpin controller instance is part of a controllable power
+ domain.
+
+
+Example
+-------
+
+ irqpin1: interrupt-controller@e6900004 {
+ compatible = "renesas,intc-irqpin-r8a7740",
+ "renesas,intc-irqpin";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0xe6900004 4>,
+ <0xe6900014 4>,
+ <0xe6900024 1>,
+ <0xe6900044 1>,
+ <0xe6900064 1>;
+ interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH
+ 0 149 IRQ_TYPE_LEVEL_HIGH
+ 0 149 IRQ_TYPE_LEVEL_HIGH
+ 0 149 IRQ_TYPE_LEVEL_HIGH
+ 0 149 IRQ_TYPE_LEVEL_HIGH
+ 0 149 IRQ_TYPE_LEVEL_HIGH
+ 0 149 IRQ_TYPE_LEVEL_HIGH
+ 0 149 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks R8A7740_CLK_INTCA>;
+ power-domains = <&pd_a4s>;
+ };
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
new file mode 100644
index 000000000000..c03eec116872
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
@@ -0,0 +1,37 @@
+* ARM SMMUv3 Architecture Implementation
+
+The SMMUv3 architecture is a significant deparature from previous
+revisions, replacing the MMIO register interface with in-memory command
+and event queues and adding support for the ATS and PRI components of
+the PCIe specification.
+
+** SMMUv3 required properties:
+
+- compatible : Should include:
+
+ * "arm,smmu-v3" for any SMMUv3 compliant
+ implementation. This entry should be last in the
+ compatible list.
+
+- reg : Base address and size of the SMMU.
+
+- interrupts : Non-secure interrupt list describing the wired
+ interrupt sources corresponding to entries in
+ interrupt-names. If no wired interrupts are
+ present then this property may be omitted.
+
+- interrupt-names : When the interrupts property is present, should
+ include the following:
+ * "eventq" - Event Queue not empty
+ * "priq" - PRI Queue not empty
+ * "cmdq-sync" - CMD_SYNC complete
+ * "gerror" - Global Error activated
+
+** SMMUv3 optional properties:
+
+- dma-coherent : Present if DMA operations made by the SMMU (page
+ table walks, stream table accesses etc) are cache
+ coherent with the CPU.
+
+ NOTE: this only applies to the SMMU itself, not
+ masters connected upstream of the SMMU.
diff --git a/Documentation/devicetree/bindings/mailbox/brcm,bcm2835-mbox.txt b/Documentation/devicetree/bindings/mailbox/brcm,bcm2835-mbox.txt
new file mode 100644
index 000000000000..e893615ef635
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/brcm,bcm2835-mbox.txt
@@ -0,0 +1,26 @@
+Broadcom BCM2835 VideoCore mailbox IPC
+
+Required properties:
+
+- compatible: Should be "brcm,bcm2835-mbox"
+- reg: Specifies base physical address and size of the registers
+- interrupts: The interrupt number
+ See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
+- #mbox-cells: Specifies the number of cells needed to encode a mailbox
+ channel. The value shall be 0, since there is only one
+ mailbox channel implemented by the device.
+
+Example:
+
+mailbox: mailbox@7e00b800 {
+ compatible = "brcm,bcm2835-mbox";
+ reg = <0x7e00b880 0x40>;
+ interrupts = <0 1>;
+ #mbox-cells = <0>;
+};
+
+firmware: firmware {
+ compatible = "raspberrypi,firmware";
+ mboxes = <&mailbox>;
+ #power-domain-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/mailbox/mailbox.txt b/Documentation/devicetree/bindings/mailbox/mailbox.txt
index 1a2cd3d266db..be05b9746c69 100644
--- a/Documentation/devicetree/bindings/mailbox/mailbox.txt
+++ b/Documentation/devicetree/bindings/mailbox/mailbox.txt
@@ -22,17 +22,11 @@ Required property:
- mboxes: List of phandle and mailbox channel specifiers.
Optional property:
-- mbox-names: List of identifier strings for each mailbox channel
- required by the client. The use of this property
- is discouraged in favor of using index in list of
- 'mboxes' while requesting a mailbox. Instead the
- platforms may define channel indices, in DT headers,
- to something legible.
+- mbox-names: List of identifier strings for each mailbox channel.
Example:
pwr_cntrl: power {
...
mbox-names = "pwr-ctrl", "rpc";
- mboxes = <&mailbox 0
- &mailbox 1>;
+ mboxes = <&mailbox 0 &mailbox 1>;
};
diff --git a/Documentation/devicetree/bindings/media/i2c/adp1653.txt b/Documentation/devicetree/bindings/media/i2c/adp1653.txt
new file mode 100644
index 000000000000..5ce66f2104e3
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/adp1653.txt
@@ -0,0 +1,37 @@
+* Analog Devices ADP1653 flash LED driver
+
+Required Properties:
+
+ - compatible: Must contain "adi,adp1653"
+
+ - reg: I2C slave address
+
+ - enable-gpios: Specifier of the GPIO connected to EN pin
+
+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
+
+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
+
+Example:
+
+ adp1653: led-controller@30 {
+ compatible = "adi,adp1653";
+ reg = <0x30>;
+ enable-gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>; /* 88 */
+
+ flash {
+ flash-timeout-us = <500000>;
+ flash-max-microamp = <320000>;
+ max-microamp = <50000>;
+ };
+ indicator {
+ max-microamp = <17500>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/st,stih4xx.txt b/Documentation/devicetree/bindings/media/st,stih4xx.txt
new file mode 100644
index 000000000000..df655cd3a4f8
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/st,stih4xx.txt
@@ -0,0 +1,32 @@
+STMicroelectronics stih4xx platforms
+
+bdisp: 2D blitter for STMicroelectronics SoC.
+
+Required properties:
+- compatible: should be "st,stih407-bdisp".
+- reg: BDISP physical address location and length.
+- interrupts: BDISP interrupt number.
+- clocks: from common clock binding: handle hardware IP needed clocks, the
+ number of clocks may depend on the SoC type.
+ See ../clocks/clock-bindings.txt for details.
+- clock-names: names of the clocks listed in clocks property in the same order.
+
+Example:
+
+ bdisp0:bdisp@9f10000 {
+ compatible = "st,stih407-bdisp";
+ reg = <0x9f10000 0x1000>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_NONE>;
+ clock-names = "bdisp";
+ clocks = <&clk_s_c0_flexgen CLK_IC_BDISP_0>;
+ };
+
+Aliases:
+Each BDISP should have a numbered alias in the aliases node, in the form of
+bdispN, N = 0 or 1.
+
+Example:
+
+ aliases {
+ bdisp0 = &bdisp0;
+ };
diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt
index f3db93c85eea..3338a2834ad7 100644
--- a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt
@@ -1,6 +1,9 @@
NVIDIA Tegra Memory Controller device tree bindings
===================================================
+memory-controller node
+----------------------
+
Required properties:
- compatible: Should be "nvidia,tegra<chip>-mc"
- reg: Physical base address and length of the controller's registers.
@@ -15,9 +18,49 @@ Required properties:
This device implements an IOMMU that complies with the generic IOMMU binding.
See ../iommu/iommu.txt for details.
-Example:
---------
+emc-timings subnode
+-------------------
+
+The node should contain a "emc-timings" subnode for each supported RAM type (see field RAM_CODE in
+register PMC_STRAPPING_OPT_A).
+
+Required properties for "emc-timings" nodes :
+- nvidia,ram-code : Should contain the value of RAM_CODE this timing set is used for.
+
+timing subnode
+--------------
+
+Each "emc-timings" node should contain a subnode for every supported EMC clock rate.
+
+Required properties for timing nodes :
+- clock-frequency : Should contain the memory clock rate in Hz.
+- nvidia,emem-configuration : Values to be written to the EMEM register block. For the Tegra124 SoC
+(see section "15.6.1 MC Registers" in the TRM), these are the registers whose values need to be
+specified, according to the board documentation:
+
+ MC_EMEM_ARB_CFG
+ MC_EMEM_ARB_OUTSTANDING_REQ
+ MC_EMEM_ARB_TIMING_RCD
+ MC_EMEM_ARB_TIMING_RP
+ MC_EMEM_ARB_TIMING_RC
+ MC_EMEM_ARB_TIMING_RAS
+ MC_EMEM_ARB_TIMING_FAW
+ MC_EMEM_ARB_TIMING_RRD
+ MC_EMEM_ARB_TIMING_RAP2PRE
+ MC_EMEM_ARB_TIMING_WAP2PRE
+ MC_EMEM_ARB_TIMING_R2R
+ MC_EMEM_ARB_TIMING_W2W
+ MC_EMEM_ARB_TIMING_R2W
+ MC_EMEM_ARB_TIMING_W2R
+ MC_EMEM_ARB_DA_TURNS
+ MC_EMEM_ARB_DA_COVERS
+ MC_EMEM_ARB_MISC0
+ MC_EMEM_ARB_MISC1
+ MC_EMEM_ARB_RING1_THROTTLE
+Example SoC include file:
+
+/ {
mc: memory-controller@0,70019000 {
compatible = "nvidia,tegra124-mc";
reg = <0x0 0x70019000 0x0 0x1000>;
@@ -34,3 +77,40 @@ Example:
...
iommus = <&mc TEGRA_SWGROUP_SDMMC1A>;
};
+};
+
+Example board file:
+
+/ {
+ memory-controller@0,70019000 {
+ emc-timings-3 {
+ nvidia,ram-code = <3>;
+
+ timing-12750000 {
+ clock-frequency = <12750000>;
+
+ nvidia,emem-configuration = <
+ 0x40040001 /* MC_EMEM_ARB_CFG */
+ 0x8000000a /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001 /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001 /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000002 /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000000 /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000002 /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001 /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000003 /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002 /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000003 /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006 /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06030203 /* MC_EMEM_ARB_DA_TURNS */
+ 0x000a0402 /* MC_EMEM_ARB_DA_COVERS */
+ 0x77e30303 /* MC_EMEM_ARB_MISC0 */
+ 0x70000f03 /* MC_EMEM_ARB_MISC1 */
+ 0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */
+ >;
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/memory-controllers/renesas,h8300-bsc.txt b/Documentation/devicetree/bindings/memory-controllers/renesas,h8300-bsc.txt
new file mode 100644
index 000000000000..cdf406c902e2
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/renesas,h8300-bsc.txt
@@ -0,0 +1,12 @@
+* H8/300 bus controller
+
+Required properties:
+ - compatible: Must be "renesas,h8300-bsc".
+ - reg: Base address and length of BSC registers.
+
+Example.
+ bsc: memory-controller@fee01e {
+ compatible = "renesas,h8300h-bsc", "renesas,h8300-bsc";
+ reg = <0xfee01e 8>;
+ };
+
diff --git a/Documentation/devicetree/bindings/memory-controllers/tegra-emc.txt b/Documentation/devicetree/bindings/memory-controllers/tegra-emc.txt
new file mode 100644
index 000000000000..b59c625d6336
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/tegra-emc.txt
@@ -0,0 +1,374 @@
+NVIDIA Tegra124 SoC EMC (external memory controller)
+====================================================
+
+Required properties :
+- compatible : Should be "nvidia,tegra124-emc".
+- reg : physical base address and length of the controller's registers.
+- nvidia,memory-controller : phandle of the MC driver.
+
+The node should contain a "emc-timings" subnode for each supported RAM type
+(see field RAM_CODE in register PMC_STRAPPING_OPT_A), with its unit address
+being its RAM_CODE.
+
+Required properties for "emc-timings" nodes :
+- nvidia,ram-code : Should contain the value of RAM_CODE this timing set is
+used for.
+
+Each "emc-timings" node should contain a "timing" subnode for every supported
+EMC clock rate. The "timing" subnodes should have the clock rate in Hz as
+their unit address.
+
+Required properties for "timing" nodes :
+- clock-frequency : Should contain the memory clock rate in Hz.
+- The following properties contain EMC timing characterization values
+(specified in the board documentation) :
+ - nvidia,emc-auto-cal-config : EMC_AUTO_CAL_CONFIG
+ - nvidia,emc-auto-cal-config2 : EMC_AUTO_CAL_CONFIG2
+ - nvidia,emc-auto-cal-config3 : EMC_AUTO_CAL_CONFIG3
+ - nvidia,emc-auto-cal-interval : EMC_AUTO_CAL_INTERVAL
+ - nvidia,emc-bgbias-ctl0 : EMC_BGBIAS_CTL0
+ - nvidia,emc-cfg : EMC_CFG
+ - nvidia,emc-cfg-2 : EMC_CFG_2
+ - nvidia,emc-ctt-term-ctrl : EMC_CTT_TERM_CTRL
+ - nvidia,emc-mode-1 : Mode Register 1
+ - nvidia,emc-mode-2 : Mode Register 2
+ - nvidia,emc-mode-4 : Mode Register 4
+ - nvidia,emc-mode-reset : Mode Register 0
+ - nvidia,emc-mrs-wait-cnt : EMC_MRS_WAIT_CNT
+ - nvidia,emc-sel-dpd-ctrl : EMC_SEL_DPD_CTRL
+ - nvidia,emc-xm2dqspadctrl2 : EMC_XM2DQSPADCTRL2
+ - nvidia,emc-zcal-cnt-long : EMC_ZCAL_WAIT_CNT after clock change
+ - nvidia,emc-zcal-interval : EMC_ZCAL_INTERVAL
+- nvidia,emc-configuration : EMC timing characterization data. These are the
+registers (see section "15.6.2 EMC Registers" in the TRM) whose values need to
+be specified, according to the board documentation:
+
+ EMC_RC
+ EMC_RFC
+ EMC_RFC_SLR
+ EMC_RAS
+ EMC_RP
+ EMC_R2W
+ EMC_W2R
+ EMC_R2P
+ EMC_W2P
+ EMC_RD_RCD
+ EMC_WR_RCD
+ EMC_RRD
+ EMC_REXT
+ EMC_WEXT
+ EMC_WDV
+ EMC_WDV_MASK
+ EMC_QUSE
+ EMC_QUSE_WIDTH
+ EMC_IBDLY
+ EMC_EINPUT
+ EMC_EINPUT_DURATION
+ EMC_PUTERM_EXTRA
+ EMC_PUTERM_WIDTH
+ EMC_PUTERM_ADJ
+ EMC_CDB_CNTL_1
+ EMC_CDB_CNTL_2
+ EMC_CDB_CNTL_3
+ EMC_QRST
+ EMC_QSAFE
+ EMC_RDV
+ EMC_RDV_MASK
+ EMC_REFRESH
+ EMC_BURST_REFRESH_NUM
+ EMC_PRE_REFRESH_REQ_CNT
+ EMC_PDEX2WR
+ EMC_PDEX2RD
+ EMC_PCHG2PDEN
+ EMC_ACT2PDEN
+ EMC_AR2PDEN
+ EMC_RW2PDEN
+ EMC_TXSR
+ EMC_TXSRDLL
+ EMC_TCKE
+ EMC_TCKESR
+ EMC_TPD
+ EMC_TFAW
+ EMC_TRPAB
+ EMC_TCLKSTABLE
+ EMC_TCLKSTOP
+ EMC_TREFBW
+ EMC_FBIO_CFG6
+ EMC_ODT_WRITE
+ EMC_ODT_READ
+ EMC_FBIO_CFG5
+ EMC_CFG_DIG_DLL
+ EMC_CFG_DIG_DLL_PERIOD
+ EMC_DLL_XFORM_DQS0
+ EMC_DLL_XFORM_DQS1
+ EMC_DLL_XFORM_DQS2
+ EMC_DLL_XFORM_DQS3
+ EMC_DLL_XFORM_DQS4
+ EMC_DLL_XFORM_DQS5
+ EMC_DLL_XFORM_DQS6
+ EMC_DLL_XFORM_DQS7
+ EMC_DLL_XFORM_DQS8
+ EMC_DLL_XFORM_DQS9
+ EMC_DLL_XFORM_DQS10
+ EMC_DLL_XFORM_DQS11
+ EMC_DLL_XFORM_DQS12
+ EMC_DLL_XFORM_DQS13
+ EMC_DLL_XFORM_DQS14
+ EMC_DLL_XFORM_DQS15
+ EMC_DLL_XFORM_QUSE0
+ EMC_DLL_XFORM_QUSE1
+ EMC_DLL_XFORM_QUSE2
+ EMC_DLL_XFORM_QUSE3
+ EMC_DLL_XFORM_QUSE4
+ EMC_DLL_XFORM_QUSE5
+ EMC_DLL_XFORM_QUSE6
+ EMC_DLL_XFORM_QUSE7
+ EMC_DLL_XFORM_ADDR0
+ EMC_DLL_XFORM_ADDR1
+ EMC_DLL_XFORM_ADDR2
+ EMC_DLL_XFORM_ADDR3
+ EMC_DLL_XFORM_ADDR4
+ EMC_DLL_XFORM_ADDR5
+ EMC_DLL_XFORM_QUSE8
+ EMC_DLL_XFORM_QUSE9
+ EMC_DLL_XFORM_QUSE10
+ EMC_DLL_XFORM_QUSE11
+ EMC_DLL_XFORM_QUSE12
+ EMC_DLL_XFORM_QUSE13
+ EMC_DLL_XFORM_QUSE14
+ EMC_DLL_XFORM_QUSE15
+ EMC_DLI_TRIM_TXDQS0
+ EMC_DLI_TRIM_TXDQS1
+ EMC_DLI_TRIM_TXDQS2
+ EMC_DLI_TRIM_TXDQS3
+ EMC_DLI_TRIM_TXDQS4
+ EMC_DLI_TRIM_TXDQS5
+ EMC_DLI_TRIM_TXDQS6
+ EMC_DLI_TRIM_TXDQS7
+ EMC_DLI_TRIM_TXDQS8
+ EMC_DLI_TRIM_TXDQS9
+ EMC_DLI_TRIM_TXDQS10
+ EMC_DLI_TRIM_TXDQS11
+ EMC_DLI_TRIM_TXDQS12
+ EMC_DLI_TRIM_TXDQS13
+ EMC_DLI_TRIM_TXDQS14
+ EMC_DLI_TRIM_TXDQS15
+ EMC_DLL_XFORM_DQ0
+ EMC_DLL_XFORM_DQ1
+ EMC_DLL_XFORM_DQ2
+ EMC_DLL_XFORM_DQ3
+ EMC_DLL_XFORM_DQ4
+ EMC_DLL_XFORM_DQ5
+ EMC_DLL_XFORM_DQ6
+ EMC_DLL_XFORM_DQ7
+ EMC_XM2CMDPADCTRL
+ EMC_XM2CMDPADCTRL4
+ EMC_XM2CMDPADCTRL5
+ EMC_XM2DQPADCTRL2
+ EMC_XM2DQPADCTRL3
+ EMC_XM2CLKPADCTRL
+ EMC_XM2CLKPADCTRL2
+ EMC_XM2COMPPADCTRL
+ EMC_XM2VTTGENPADCTRL
+ EMC_XM2VTTGENPADCTRL2
+ EMC_XM2VTTGENPADCTRL3
+ EMC_XM2DQSPADCTRL3
+ EMC_XM2DQSPADCTRL4
+ EMC_XM2DQSPADCTRL5
+ EMC_XM2DQSPADCTRL6
+ EMC_DSR_VTTGEN_DRV
+ EMC_TXDSRVTTGEN
+ EMC_FBIO_SPARE
+ EMC_ZCAL_WAIT_CNT
+ EMC_MRS_WAIT_CNT2
+ EMC_CTT
+ EMC_CTT_DURATION
+ EMC_CFG_PIPE
+ EMC_DYN_SELF_REF_CONTROL
+ EMC_QPOP
+
+Example SoC include file:
+
+/ {
+ emc@0,7001b000 {
+ compatible = "nvidia,tegra124-emc";
+ reg = <0x0 0x7001b000 0x0 0x1000>;
+
+ nvidia,memory-controller = <&mc>;
+ };
+};
+
+Example board file:
+
+/ {
+ emc@0,7001b000 {
+ emc-timings-3 {
+ nvidia,ram-code = <3>;
+
+ timing-12750000 {
+ clock-frequency = <12750000>;
+
+ nvidia,emc-zcal-cnt-long = <0x00000042>;
+ nvidia,emc-auto-cal-interval = <0x001fffff>;
+ nvidia,emc-ctt-term-ctrl = <0x00000802>;
+ nvidia,emc-cfg = <0x73240000>;
+ nvidia,emc-cfg-2 = <0x000008c5>;
+ nvidia,emc-sel-dpd-ctrl = <0x00040128>;
+ nvidia,emc-bgbias-ctl0 = <0x00000008>;
+ nvidia,emc-auto-cal-config = <0xa1430000>;
+ nvidia,emc-auto-cal-config2 = <0x00000000>;
+ nvidia,emc-auto-cal-config3 = <0x00000000>;
+ nvidia,emc-mode-reset = <0x80001221>;
+ nvidia,emc-mode-1 = <0x80100003>;
+ nvidia,emc-mode-2 = <0x80200008>;
+ nvidia,emc-mode-4 = <0x00000000>;
+
+ nvidia,emc-configuration = <
+ 0x00000000 /* EMC_RC */
+ 0x00000003 /* EMC_RFC */
+ 0x00000000 /* EMC_RFC_SLR */
+ 0x00000000 /* EMC_RAS */
+ 0x00000000 /* EMC_RP */
+ 0x00000004 /* EMC_R2W */
+ 0x0000000a /* EMC_W2R */
+ 0x00000003 /* EMC_R2P */
+ 0x0000000b /* EMC_W2P */
+ 0x00000000 /* EMC_RD_RCD */
+ 0x00000000 /* EMC_WR_RCD */
+ 0x00000003 /* EMC_RRD */
+ 0x00000003 /* EMC_REXT */
+ 0x00000000 /* EMC_WEXT */
+ 0x00000006 /* EMC_WDV */
+ 0x00000006 /* EMC_WDV_MASK */
+ 0x00000006 /* EMC_QUSE */
+ 0x00000002 /* EMC_QUSE_WIDTH */
+ 0x00000000 /* EMC_IBDLY */
+ 0x00000005 /* EMC_EINPUT */
+ 0x00000005 /* EMC_EINPUT_DURATION */
+ 0x00010000 /* EMC_PUTERM_EXTRA */
+ 0x00000003 /* EMC_PUTERM_WIDTH */
+ 0x00000000 /* EMC_PUTERM_ADJ */
+ 0x00000000 /* EMC_CDB_CNTL_1 */
+ 0x00000000 /* EMC_CDB_CNTL_2 */
+ 0x00000000 /* EMC_CDB_CNTL_3 */
+ 0x00000004 /* EMC_QRST */
+ 0x0000000c /* EMC_QSAFE */
+ 0x0000000d /* EMC_RDV */
+ 0x0000000f /* EMC_RDV_MASK */
+ 0x00000060 /* EMC_REFRESH */
+ 0x00000000 /* EMC_BURST_REFRESH_NUM */
+ 0x00000018 /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000002 /* EMC_PDEX2WR */
+ 0x00000002 /* EMC_PDEX2RD */
+ 0x00000001 /* EMC_PCHG2PDEN */
+ 0x00000000 /* EMC_ACT2PDEN */
+ 0x00000007 /* EMC_AR2PDEN */
+ 0x0000000f /* EMC_RW2PDEN */
+ 0x00000005 /* EMC_TXSR */
+ 0x00000005 /* EMC_TXSRDLL */
+ 0x00000004 /* EMC_TCKE */
+ 0x00000005 /* EMC_TCKESR */
+ 0x00000004 /* EMC_TPD */
+ 0x00000000 /* EMC_TFAW */
+ 0x00000000 /* EMC_TRPAB */
+ 0x00000005 /* EMC_TCLKSTABLE */
+ 0x00000005 /* EMC_TCLKSTOP */
+ 0x00000064 /* EMC_TREFBW */
+ 0x00000000 /* EMC_FBIO_CFG6 */
+ 0x00000000 /* EMC_ODT_WRITE */
+ 0x00000000 /* EMC_ODT_READ */
+ 0x106aa298 /* EMC_FBIO_CFG5 */
+ 0x002c00a0 /* EMC_CFG_DIG_DLL */
+ 0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00064000 /* EMC_DLL_XFORM_DQS0 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS1 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS2 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS3 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS4 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS5 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS6 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS7 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS8 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS9 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS10 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS11 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS12 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS13 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS14 */
+ 0x00064000 /* EMC_DLL_XFORM_DQS15 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000 /* EMC_DLL_XFORM_ADDR0 */
+ 0x00000000 /* EMC_DLL_XFORM_ADDR1 */
+ 0x00000000 /* EMC_DLL_XFORM_ADDR2 */
+ 0x00000000 /* EMC_DLL_XFORM_ADDR3 */
+ 0x00000000 /* EMC_DLL_XFORM_ADDR4 */
+ 0x00000000 /* EMC_DLL_XFORM_ADDR5 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE8 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE9 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE10 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE11 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE12 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE13 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE14 */
+ 0x00000000 /* EMC_DLL_XFORM_QUSE15 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS8 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS9 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS10 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS11 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS12 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS13 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS14 */
+ 0x00000000 /* EMC_DLI_TRIM_TXDQS15 */
+ 0x000fc000 /* EMC_DLL_XFORM_DQ0 */
+ 0x000fc000 /* EMC_DLL_XFORM_DQ1 */
+ 0x000fc000 /* EMC_DLL_XFORM_DQ2 */
+ 0x000fc000 /* EMC_DLL_XFORM_DQ3 */
+ 0x0000fc00 /* EMC_DLL_XFORM_DQ4 */
+ 0x0000fc00 /* EMC_DLL_XFORM_DQ5 */
+ 0x0000fc00 /* EMC_DLL_XFORM_DQ6 */
+ 0x0000fc00 /* EMC_DLL_XFORM_DQ7 */
+ 0x10000280 /* EMC_XM2CMDPADCTRL */
+ 0x00000000 /* EMC_XM2CMDPADCTRL4 */
+ 0x00111111 /* EMC_XM2CMDPADCTRL5 */
+ 0x00000000 /* EMC_XM2DQPADCTRL2 */
+ 0x00000000 /* EMC_XM2DQPADCTRL3 */
+ 0x77ffc081 /* EMC_XM2CLKPADCTRL */
+ 0x00000e0e /* EMC_XM2CLKPADCTRL2 */
+ 0x81f1f108 /* EMC_XM2COMPPADCTRL */
+ 0x07070004 /* EMC_XM2VTTGENPADCTRL */
+ 0x0000003f /* EMC_XM2VTTGENPADCTRL2 */
+ 0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */
+ 0x51451400 /* EMC_XM2DQSPADCTRL3 */
+ 0x00514514 /* EMC_XM2DQSPADCTRL4 */
+ 0x00514514 /* EMC_XM2DQSPADCTRL5 */
+ 0x51451400 /* EMC_XM2DQSPADCTRL6 */
+ 0x0000003f /* EMC_DSR_VTTGEN_DRV */
+ 0x00000007 /* EMC_TXDSRVTTGEN */
+ 0x00000000 /* EMC_FBIO_SPARE */
+ 0x00000042 /* EMC_ZCAL_WAIT_CNT */
+ 0x000e000e /* EMC_MRS_WAIT_CNT2 */
+ 0x00000000 /* EMC_CTT */
+ 0x00000003 /* EMC_CTT_DURATION */
+ 0x0000f2f3 /* EMC_CFG_PIPE */
+ 0x800001c5 /* EMC_DYN_SELF_REF_CONTROL */
+ 0x0000000a /* EMC_QPOP */
+ >;
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/mfd/arizona.txt b/Documentation/devicetree/bindings/mfd/arizona.txt
index 7665aa95979f..a8fee60dc20d 100644
--- a/Documentation/devicetree/bindings/mfd/arizona.txt
+++ b/Documentation/devicetree/bindings/mfd/arizona.txt
@@ -10,6 +10,9 @@ Required properties:
"wlf,wm5110"
"wlf,wm8280"
"wlf,wm8997"
+ "wlf,wm8998"
+ "wlf,wm1814"
+
- reg : I2C slave address when connected using I2C, chip select number when
using SPI.
@@ -31,10 +34,10 @@ Required properties:
as covered in Documentation/devicetree/bindings/regulator/regulator.txt
- DBVDD2-supply, DBVDD3-supply : Additional databus power supplies (wm5102,
- wm5110, wm8280)
+ wm5110, wm8280, wm8998, wm1814)
- SPKVDDL-supply, SPKVDDR-supply : Speaker driver power supplies (wm5102,
- wm5110, wm8280)
+ wm5110, wm8280, wm8998, wm1814)
- SPKVDD-supply : Speaker driver power supply (wm8997)
@@ -53,8 +56,10 @@ Optional properties:
of input signals. Valid values are 0 (Differential), 1 (Single-ended) and
2 (Digital Microphone). If absent, INn_MODE registers set to 0 by default.
If present, values must be specified less than or equal to the number of
- input singals. If values less than the number of input signals, elements
- that has not been specifed are set to 0 by default.
+ input signals. If values less than the number of input signals, elements
+ 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,dmic-ref : DMIC reference voltage source for each input, can be
selected from either MICVDD or one of the MICBIAS's, defines
@@ -62,6 +67,12 @@ Optional properties:
present, the number of values should be less than or equal to the
number of inputs, unspecified inputs will use the chip default.
+ - wlf,hpdet-channel : Headphone detection channel.
+ ARIZONA_ACCDET_MODE_HPL or 1 - Headphone detect mode is set to HPDETL
+ 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.
+
- 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
diff --git a/Documentation/devicetree/bindings/mfd/axp20x.txt b/Documentation/devicetree/bindings/mfd/axp20x.txt
index 98685f291a72..753f14f46e85 100644
--- a/Documentation/devicetree/bindings/mfd/axp20x.txt
+++ b/Documentation/devicetree/bindings/mfd/axp20x.txt
@@ -1,15 +1,16 @@
-AXP202/AXP209 device tree bindings
+AXP family PMIC device tree bindings
The axp20x family current members :
axp202 (X-Powers)
axp209 (X-Powers)
+axp221 (X-Powers)
Required properties:
-- compatible: "x-powers,axp202" or "x-powers,axp209"
+- compatible: "x-powers,axp202", "x-powers,axp209", "x-powers,axp221"
- reg: The I2C slave address for the AXP chip
- interrupt-parent: The parent interrupt controller
- interrupts: SoC NMI / GPIO interrupt connected to the PMIC's IRQ pin
-- interrupt-controller: axp20x has its own internal IRQs
+- interrupt-controller: The PMIC has its own internal IRQs
- #interrupt-cells: Should be set to 1
Optional properties:
@@ -48,6 +49,31 @@ LDO3 : LDO : ldo3in-supply
LDO4 : LDO : ldo24in-supply : shared supply
LDO5 : LDO : ldo5in-supply
+AXP221 regulators, type, and corresponding input supply names:
+
+Regulator Type Supply Name Notes
+--------- ---- ----------- -----
+DCDC1 : DC-DC buck : vin1-supply
+DCDC2 : DC-DC buck : vin2-supply
+DCDC3 : DC-DC buck : vin3-supply
+DCDC4 : DC-DC buck : vin4-supply
+DCDC5 : DC-DC buck : vin5-supply
+DC1SW : On/Off Switch : dcdc1-supply : DCDC1 secondary output
+DC5LDO : LDO : dcdc5-supply : input from DCDC5
+ALDO1 : LDO : aldoin-supply : shared supply
+ALDO2 : LDO : aldoin-supply : shared supply
+ALDO3 : LDO : aldoin-supply : shared supply
+DLDO1 : LDO : dldoin-supply : shared supply
+DLDO2 : LDO : dldoin-supply : shared supply
+DLDO3 : LDO : dldoin-supply : shared supply
+DLDO4 : LDO : dldoin-supply : shared supply
+ELDO1 : LDO : eldoin-supply : shared supply
+ELDO2 : LDO : eldoin-supply : shared supply
+ELDO3 : LDO : eldoin-supply : shared supply
+LDO_IO0 : LDO : ips-supply : GPIO 0
+LDO_IO1 : LDO : ips-supply : GPIO 1
+RTC_LDO : LDO : ips-supply : always on
+
Example:
axp209: pmic@34 {
diff --git a/Documentation/devicetree/bindings/mfd/cros-ec.txt b/Documentation/devicetree/bindings/mfd/cros-ec.txt
index 8009c3d87f33..1777916e9e28 100644
--- a/Documentation/devicetree/bindings/mfd/cros-ec.txt
+++ b/Documentation/devicetree/bindings/mfd/cros-ec.txt
@@ -18,6 +18,10 @@ Required properties (SPI):
- reg: SPI chip select
Optional properties (SPI):
+- google,cros-ec-spi-pre-delay: Some implementations of the EC need a little
+ time to wake up from sleep before they can receive SPI transfers at a high
+ clock rate. This property specifies the delay, in usecs, between the
+ assertion of the CS to the start of the first clock pulse.
- google,cros-ec-spi-msg-delay: Some implementations of the EC require some
additional processing time in order to accept new transactions. If the delay
between transactions is not long enough the EC may not be able to respond
diff --git a/Documentation/devicetree/bindings/mfd/da9063.txt b/Documentation/devicetree/bindings/mfd/da9063.txt
index 42c6fa6f1c9a..05b21bcb8543 100644
--- a/Documentation/devicetree/bindings/mfd/da9063.txt
+++ b/Documentation/devicetree/bindings/mfd/da9063.txt
@@ -5,6 +5,7 @@ DA9093 consists of a large and varied group of sub-devices (I2C Only):
Device Supply Names Description
------ ------------ -----------
da9063-regulator : : LDOs & BUCKs
+da9063-onkey : : On Key
da9063-rtc : : Real-Time Clock
da9063-watchdog : : Watchdog
@@ -51,6 +52,18 @@ Sub-nodes:
the DA9063. There are currently no entries in this binding, however
compatible = "dlg,da9063-rtc" should be added if a node is created.
+- onkey : This node defines the OnKey settings for controlling the key
+ functionality of the device. The node should contain the compatible property
+ with the value "dlg,da9063-onkey".
+
+ Optional onkey properties:
+
+ - dlg,disable-key-power : Disable power-down using a long key-press. If this
+ entry exists the OnKey driver will remove support for the KEY_POWER key
+ press. If this entry does not exist then by default the key-press
+ triggered power down is enabled and the OnKey will support both KEY_POWER
+ and KEY_SLEEP.
+
- watchdog : This node defines settings for the Watchdog timer associated
with the DA9063. There are currently no entries in this binding, however
compatible = "dlg,da9063-watchdog" should be added if a node is created.
@@ -73,6 +86,11 @@ Example:
compatible = "dlg,da9063-watchdog";
};
+ onkey {
+ compatible = "dlg,da9063-onkey";
+ dlg,disable-key-power;
+ };
+
regulators {
DA9063_BCORE1: bcore1 {
regulator-name = "BCORE1";
diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt
index e39f0bc1f55e..163bd81a4607 100644
--- a/Documentation/devicetree/bindings/mfd/max77686.txt
+++ b/Documentation/devicetree/bindings/mfd/max77686.txt
@@ -1,6 +1,6 @@
Maxim MAX77686 multi-function device
-MAX77686 is a Mulitifunction device with PMIC, RTC and Charger on chip. It is
+MAX77686 is a Multifunction device with PMIC, RTC and Charger on chip. It is
interfaced to host controller using i2c interface. PMIC and Charger submodules
are addressed using same i2c slave address whereas RTC submodule uses
different i2c slave address,presently for which we are statically creating i2c
diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt
index 38e64405e98d..d3425846aa5b 100644
--- a/Documentation/devicetree/bindings/mfd/max77693.txt
+++ b/Documentation/devicetree/bindings/mfd/max77693.txt
@@ -76,7 +76,60 @@ Optional properties:
Valid values: 4300000, 4700000, 4800000, 4900000
Default: 4300000
+- led : the LED submodule device node
+
+There are two LED outputs available - FLED1 and FLED2. Each of them can
+control a separate LED or they can be connected together to double
+the maximum current for a single connected LED. One LED is represented
+by one child node.
+
+Required properties:
+- compatible : Must be "maxim,max77693-led".
+
+Optional properties:
+- maxim,boost-mode :
+ In boost mode the device can produce up to 1.2A of total current
+ on both outputs. The maximum current on each output is reduced
+ to 625mA then. If not enabled explicitly, boost setting defaults to
+ LEDS_BOOST_FIXED in case both current sources are used.
+ Possible values:
+ LEDS_BOOST_OFF (0) - no boost,
+ LEDS_BOOST_ADAPTIVE (1) - adaptive mode,
+ LEDS_BOOST_FIXED (2) - fixed mode.
+- maxim,boost-mvout : Output voltage of the boost module in millivolts.
+ Valid values: 3300 - 5500, step by 25 (rounded down)
+ Default: 3300
+- maxim,mvsys-min : Low input voltage level in millivolts. Flash is not fired
+ if chip estimates that system voltage could drop below this level due
+ to flash power consumption.
+ Valid values: 2400 - 3400, step by 33 (rounded down)
+ Default: 2400
+
+Required properties for the LED child node:
+- led-sources : see Documentation/devicetree/bindings/leds/common.txt;
+ device current output identifiers: 0 - FLED1, 1 - FLED2
+- led-max-microamp : see Documentation/devicetree/bindings/leds/common.txt
+ Valid values for a LED connected to one FLED output:
+ 15625 - 250000, step by 15625 (rounded down)
+ Valid values for a LED connected to both FLED outputs:
+ 15625 - 500000, step by 15625 (rounded down)
+- flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt
+ Valid values for a single LED connected to one FLED output
+ (boost mode must be turned off):
+ 15625 - 1000000, step by 15625 (rounded down)
+ Valid values for a single LED connected to both FLED outputs:
+ 15625 - 1250000, step by 15625 (rounded down)
+ Valid values for two LEDs case:
+ 15625 - 625000, step by 15625 (rounded down)
+- flash-max-timeout-us : see Documentation/devicetree/bindings/leds/common.txt
+ Valid values: 62500 - 1000000, step by 62500 (rounded down)
+
+Optional properties for the LED child node:
+- label : see Documentation/devicetree/bindings/leds/common.txt
+
Example:
+#include <dt-bindings/leds/common.h>
+
max77693@66 {
compatible = "maxim,max77693";
reg = <0x66>;
@@ -117,5 +170,19 @@ Example:
maxim,thermal-regulation-celsius = <75>;
maxim,battery-overcurrent-microamp = <3000000>;
maxim,charge-input-threshold-microvolt = <4300000>;
+
+ led {
+ compatible = "maxim,max77693-led";
+ maxim,boost-mode = <LEDS_BOOST_FIXED>;
+ maxim,boost-mvout = <5000>;
+ maxim,mvsys-min = <2400>;
+
+ camera_flash: flash-led {
+ label = "max77693-flash";
+ led-sources = <0>, <1>;
+ led-max-microamp = <500000>;
+ flash-max-microamp = <1250000>;
+ flash-max-timeout-us = <1000000>;
+ };
};
};
diff --git a/Documentation/devicetree/bindings/mfd/mfd.txt b/Documentation/devicetree/bindings/mfd/mfd.txt
new file mode 100644
index 000000000000..af9d6931a1a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/mfd.txt
@@ -0,0 +1,41 @@
+Multi-Function Devices (MFD)
+
+These devices comprise a nexus for heterogeneous hardware blocks containing
+more than one non-unique yet varying hardware functionality.
+
+A typical MFD can be:
+
+- A mixed signal ASIC on an external bus, sometimes a PMIC (Power Management
+ Integrated Circuit) that is manufactured in a lower technology node (rough
+ silicon) that handles analog drivers for things like audio amplifiers, LED
+ drivers, level shifters, PHY (physical interfaces to things like USB or
+ ethernet), regulators etc.
+
+- A range of memory registers containing "miscellaneous system registers" also
+ known as a system controller "syscon" or any other memory range containing a
+ mix of unrelated hardware devices.
+
+Optional properties:
+
+- compatible : "simple-mfd" - this signifies that the operating system should
+ consider all subnodes of the MFD device as separate devices akin to how
+ "simple-bus" inidicates when to see subnodes as children for a simple
+ memory-mapped bus. For more complex devices, when the nexus driver has to
+ probe registers to figure out what child devices exist etc, this should not
+ be used. In the latter case the child devices will be determined by the
+ operating system.
+
+Example:
+
+foo@1000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0x01000 0x1000>;
+
+ led@08.0 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x01>;
+ label = "myled";
+ default-state = "on";
+ };
+};
diff --git a/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt b/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt
index 47b205cc9cc7..4556359c5876 100644
--- a/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt
+++ b/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt
@@ -10,3 +10,5 @@ Required properties:
The second entry gives the physical address and length of the
registers indicating the strapping options.
+Optional properties:
+- nvidia,long-ram-code: If present, the RAM code is long (4 bit). If not, short (2 bit).
diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
index 98ee2abbe138..7e9490313d5a 100644
--- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
+++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
@@ -8,7 +8,8 @@ Device Tree Bindings for the Arasan SDHCI Controller
[3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Required Properties:
- - compatible: Compatibility string. Must be 'arasan,sdhci-8.9a'
+ - compatible: Compatibility string. Must be 'arasan,sdhci-8.9a' or
+ 'arasan,sdhci-4.9a'
- reg: From mmc bindings: Register location and length.
- clocks: From clock bindings: Handles to clock inputs.
- clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb"
diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
index 415c5575cbf7..5d0376b8f202 100644
--- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
+++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
@@ -7,7 +7,14 @@ This file documents differences between the core properties described
by mmc.txt and the properties used by the sdhci-esdhc-imx driver.
Required properties:
-- compatible : Should be "fsl,<chip>-esdhc"
+- compatible : Should be "fsl,<chip>-esdhc", the supported chips include
+ "fsl,imx25-esdhc"
+ "fsl,imx35-esdhc"
+ "fsl,imx51-esdhc"
+ "fsl,imx53-esdhc"
+ "fsl,imx6q-usdhc"
+ "fsl,imx6sl-usdhc"
+ "fsl,imx6sx-usdhc"
Optional properties:
- fsl,cd-controller : Indicate to use controller internal card detection
diff --git a/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
index 3b3544931437..df370585cbcc 100644
--- a/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
@@ -13,6 +13,10 @@ Required Properties:
* compatible: should be one of the following.
- "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extensions.
+ - "hisilicon,hi6220-dw-mshc": for controllers with hi6220 specific extensions.
+
+Optional Properties:
+- hisilicon,peripheral-syscon: phandle of syscon used to control peripheral.
Example:
@@ -42,3 +46,27 @@ Example:
cap-mmc-highspeed;
cap-sd-highspeed;
};
+
+ /* for Hi6220 */
+
+ dwmmc_1: dwmmc1@f723e000 {
+ compatible = "hisilicon,hi6220-dw-mshc";
+ num-slots = <0x1>;
+ bus-width = <0x4>;
+ disable-wp;
+ cap-sd-highspeed;
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ card-detect-delay = <200>;
+ hisilicon,peripheral-syscon = <&ao_ctrl>;
+ reg = <0x0 0xf723e000 0x0 0x1000>;
+ interrupts = <0x0 0x49 0x4>;
+ clocks = <&clock_sys HI6220_MMC1_CIUCLK>, <&clock_sys HI6220_MMC1_CLK>;
+ clock-names = "ciu", "biu";
+ cd-gpios = <&gpio1 0 1>;
+ pinctrl-names = "default", "idle";
+ pinctrl-0 = <&sd_pmx_func &sd_clk_cfg_func &sd_cfg_func>;
+ pinctrl-1 = <&sd_pmx_idle &sd_clk_cfg_idle &sd_cfg_idle>;
+ vqmmc-supply = <&ldo7>;
+ vmmc-supply = <&ldo10>;
+ };
diff --git a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
index a462c50f19a8..ce0e76749671 100644
--- a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
@@ -21,5 +21,7 @@ Example:
sdhci0_pwrseq {
compatible = "mmc-pwrseq-simple";
- reset-gpios = <&gpio1 12 0>;
+ reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
+ clocks = <&clk_32768_ck>;
+ clock-names = "ext_clock";
}
diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 438899e8829b..0384fc3f64e8 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -21,6 +21,11 @@ Optional properties:
below for the case, when a GPIO is used for the CD line
- wp-inverted: when present, polarity on the WP line is inverted. See the note
below for the case, when a GPIO is used for the WP line
+- disable-wp: When set no physical WP line is present. This property should
+ only be specified when the controller has a dedicated write-protect
+ detection logic. If a GPIO is always used for the write-protect detection
+ logic it is sufficient to not specify wp-gpios property in the absence of a WP
+ line.
- max-frequency: maximum operating clock frequency
- no-1-8-v: when present, denotes that 1.8v card voltage is not supported on
this system, even if the controller claims it is.
diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.txt b/Documentation/devicetree/bindings/mmc/mtk-sd.txt
new file mode 100644
index 000000000000..a1adfa495ad3
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/mtk-sd.txt
@@ -0,0 +1,32 @@
+* MTK MMC controller
+
+The MTK MSDC can act as a MMC controller
+to support MMC, SD, and SDIO types of memory cards.
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the msdc driver.
+
+Required properties:
+- compatible: Should be "mediatek,mt8173-mmc","mediatek,mt8135-mmc"
+- interrupts: Should contain MSDC interrupt number
+- clocks: MSDC source clock, HCLK
+- clock-names: "source", "hclk"
+- pinctrl-names: should be "default", "state_uhs"
+- pinctrl-0: should contain default/high speed pin ctrl
+- pinctrl-1: should contain uhs mode pin ctrl
+- vmmc-supply: power to the Core
+- vqmmc-supply: power to the IO
+
+Examples:
+mmc0: mmc@11230000 {
+ compatible = "mediatek,mt8173-mmc", "mediatek,mt8135-mmc";
+ reg = <0 0x11230000 0 0x108>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_LOW>;
+ vmmc-supply = <&mt6397_vemc_3v3_reg>;
+ vqmmc-supply = <&mt6397_vio18_reg>;
+ clocks = <&pericfg CLK_PERI_MSDC30_0>, <&topckgen CLK_TOP_MSDC50_0_H_SEL>;
+ clock-names = "source", "hclk";
+ pinctrl-names = "default", "state_uhs";
+ pinctrl-0 = <&mmc0_pins_default>;
+ pinctrl-1 = <&mmc0_pins_uhs>;
+};
diff --git a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
index 299081f94abd..d38942f6c5ae 100644
--- a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
+++ b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
@@ -18,6 +18,8 @@ Required properties:
dma-names property.
- dma-names: must contain "tx" for the transmit DMA channel and "rx" for the
receive DMA channel.
+- max-frequency: Maximum operating clock frequency, driver uses default clock
+ frequency if it is not set.
Example: R8A7790 (R-Car H2) MMCIF0
@@ -29,4 +31,5 @@ Example: R8A7790 (R-Car H2) MMCIF0
clocks = <&mstp3_clks R8A7790_CLK_MMCIF0>;
dmas = <&dmac0 0xd1>, <&dmac0 0xd2>;
dma-names = "tx", "rx";
+ max-frequency = <97500000>;
};
diff --git a/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
new file mode 100644
index 000000000000..4ff7128ee3b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
@@ -0,0 +1,150 @@
+* Broadcom STB NAND Controller
+
+The Broadcom Set-Top Box NAND controller supports low-level access to raw NAND
+flash chips. It has a memory-mapped register interface for both control
+registers and for its data input/output buffer. On some SoCs, this controller is
+paired with a custom DMA engine (inventively named "Flash DMA") which supports
+basic PROGRAM and READ functions, among other features.
+
+This controller was originally designed for STB SoCs (BCM7xxx) but is now
+available on a variety of Broadcom SoCs, including some BCM3xxx, BCM63xx, and
+iProc/Cygnus. Its history includes several similar (but not fully register
+compatible) versions.
+
+Required properties:
+- compatible : May contain an SoC-specific compatibility string (see below)
+ to account for any SoC-specific hardware bits that may be
+ added on top of the base core controller.
+ In addition, must contain compatibility information about
+ the core NAND controller, of the following form:
+ "brcm,brcmnand" and an appropriate version compatibility
+ string, like "brcm,brcmnand-v7.0"
+ Possible values:
+ brcm,brcmnand-v4.0
+ brcm,brcmnand-v5.0
+ brcm,brcmnand-v6.0
+ brcm,brcmnand-v6.1
+ brcm,brcmnand-v7.0
+ brcm,brcmnand-v7.1
+ brcm,brcmnand
+- reg : the register start and length for NAND register region.
+ (optional) Flash DMA register range (if present)
+ (optional) NAND flash cache range (if at non-standard offset)
+- reg-names : a list of the names corresponding to the previous register
+ ranges. Should contain "nand" and (optionally)
+ "flash-dma" and/or "nand-cache".
+- interrupts : The NAND CTLRDY interrupt and (if Flash DMA is available)
+ FLASH_DMA_DONE
+- interrupt-names : May be "nand_ctlrdy" or "flash_dma_done", if broken out as
+ individual interrupts.
+ May be "nand", if the SoC has the individual NAND
+ interrupts multiplexed behind another custom piece of
+ hardware
+- interrupt-parent : See standard interrupt bindings
+- #address-cells : <1> - subnodes give the chip-select number
+- #size-cells : <0>
+
+Optional properties:
+- 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
+ earlier versions of this core that include WP
+
+ -- Additonal SoC-specific NAND controller properties --
+
+The NAND controller is integrated differently on the variety of SoCs on which it
+is found. Part of this integration involves providing status and enable bits
+with which to control the 8 exposed NAND interrupts, as well as hardware for
+configuring the endianness of the data bus. On some SoCs, these features are
+handled via standard, modular components (e.g., their interrupts look like a
+normal IRQ chip), but on others, they are controlled in unique and interesting
+ways, sometimes with registers that lump multiple NAND-related functions
+together. The former case can be described simply by the standard interrupts
+properties in the main controller node. But for the latter exceptional cases,
+we define additional 'compatible' properties and associated register resources within the NAND controller node above.
+
+ - compatible: Can be one of several SoC-specific strings. Each SoC may have
+ different requirements for its additional properties, as described below each
+ bullet point below.
+
+ * "brcm,nand-bcm63138"
+ - reg: (required) the 'NAND_INT_BASE' register range, with separate status
+ and enable 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,
+ for interrupt status/ack.
+ - reg-names: (required) a list of the names corresponding to the previous
+ register ranges. Should contain "iproc-idm" and "iproc-ext".
+
+
+* NAND chip-select
+
+Each controller (compatible: "brcm,brcmnand") may contain one or more subnodes
+to represent enabled chip-selects which (may) contain NAND flash chips. Their
+properties are as follows.
+
+Required properties:
+- compatible : should contain "brcm,nandcs"
+- reg : a single integer representing the chip-select
+ number (e.g., 0, 1, 2, etc.)
+- #address-cells : see partition.txt
+- #size-cells : see partition.txt
+- nand-ecc-strength : see nand.txt
+- nand-ecc-step-size : must be 512 or 1024. See nand.txt
+
+Optional properties:
+- nand-on-flash-bbt : boolean, to enable the on-flash BBT for this
+ chip-select. See nand.txt
+- brcm,nand-oob-sector-size : integer, to denote the spare area sector size
+ expected for the ECC layout in use. This size, in
+ addition to the strength and step-size,
+ determines how the hardware BCH engine will lay
+ out the parity bytes it stores on the flash.
+ This property can be automatically determined by
+ the flash geometry (particularly the NAND page
+ and OOB size) in many cases, but when booting
+ from NAND, the boot controller has only a limited
+ number of available options for its default ECC
+ layout.
+
+Each nandcs device node may optionally contain sub-nodes describing the flash
+partition mapping. See partition.txt for more detail.
+
+
+Example:
+
+nand@f0442800 {
+ compatible = "brcm,brcmnand-v7.0", "brcm,brcmnand";
+ reg = <0xF0442800 0x600>,
+ <0xF0443000 0x100>;
+ reg-names = "nand", "flash-dma";
+ interrupt-parent = <&hif_intr2_intc>;
+ interrupts = <24>, <4>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ nandcs@1 {
+ compatible = "brcm,nandcs";
+ reg = <1>; // Chip select 1
+ nand-on-flash-bbt;
+ nand-ecc-strength = <12>;
+ nand-ecc-step-size = <512>;
+
+ // Partitions
+ #address-cells = <1>; // <2>, for 64-bit offset
+ #size-cells = <1>; // <2>, for 64-bit length
+ flash0.rootfs@0 {
+ reg = <0 0x10000000>;
+ };
+ flash0@0 {
+ reg = <0 0>; // MTDPART_SIZ_FULL
+ };
+ flash0.kernel@10000000 {
+ reg = <0x10000000 0x400000>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt b/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt
deleted file mode 100644
index 8db32384a486..000000000000
--- a/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-* AMD 10GbE PHY driver (amd-xgbe-phy)
-
-Required properties:
-- compatible: Should be "amd,xgbe-phy-seattle-v1a" and
- "ethernet-phy-ieee802.3-c45"
-- reg: Address and length of the register sets for the device
- - SerDes Rx/Tx registers
- - SerDes integration registers (1/2)
- - SerDes integration registers (2/2)
-- interrupt-parent: Should be the phandle for the interrupt controller
- that services interrupts for this device
-- interrupts: Should contain the amd-xgbe-phy interrupt.
-
-Optional properties:
-- amd,speed-set: Speed capabilities of the device
- 0 - 1GbE and 10GbE (default)
- 1 - 2.5GbE and 10GbE
-
-The following optional properties are represented by an array with each
-value corresponding to a particular speed. The first array value represents
-the setting for the 1GbE speed, the second value for the 2.5GbE speed and
-the third value for the 10GbE speed. All three values are required if the
-property is used.
-- amd,serdes-blwc: Baseline wandering correction enablement
- 0 - Off
- 1 - On
-- amd,serdes-cdr-rate: CDR rate speed selection
-- amd,serdes-pq-skew: PQ (data sampling) skew
-- amd,serdes-tx-amp: TX amplitude boost
-- amd,serdes-dfe-tap-config: DFE taps available to run
-- amd,serdes-dfe-tap-enable: DFE taps to enable
-
-Example:
- xgbe_phy@e1240800 {
- compatible = "amd,xgbe-phy-seattle-v1a", "ethernet-phy-ieee802.3-c45";
- reg = <0 0xe1240800 0 0x00400>,
- <0 0xe1250000 0 0x00060>,
- <0 0xe1250080 0 0x00004>;
- interrupt-parent = <&gic>;
- interrupts = <0 323 4>;
- amd,speed-set = <0>;
- amd,serdes-blwc = <1>, <1>, <0>;
- amd,serdes-cdr-rate = <2>, <2>, <7>;
- amd,serdes-pq-skew = <10>, <10>, <30>;
- amd,serdes-tx-amp = <15>, <15>, <10>;
- amd,serdes-dfe-tap-config = <3>, <3>, <1>;
- amd,serdes-dfe-tap-enable = <0>, <0>, <127>;
- };
diff --git a/Documentation/devicetree/bindings/net/amd-xgbe.txt b/Documentation/devicetree/bindings/net/amd-xgbe.txt
index 26efd526d16c..4bb624a73b54 100644
--- a/Documentation/devicetree/bindings/net/amd-xgbe.txt
+++ b/Documentation/devicetree/bindings/net/amd-xgbe.txt
@@ -5,12 +5,16 @@ Required properties:
- reg: Address and length of the register sets for the device
- MAC registers
- PCS registers
+ - SerDes Rx/Tx registers
+ - SerDes integration registers (1/2)
+ - SerDes integration registers (2/2)
- interrupt-parent: Should be the phandle for the interrupt controller
that services interrupts for this device
- interrupts: Should contain the amd-xgbe interrupt(s). The first interrupt
listed is required and is the general device interrupt. If the optional
amd,per-channel-interrupt property is specified, then one additional
- interrupt for each DMA channel supported by the device should be specified
+ interrupt for each DMA channel supported by the device should be specified.
+ The last interrupt listed should be the PCS auto-negotiation interrupt.
- clocks:
- DMA clock for the amd-xgbe device (used for calculating the
correct Rx interrupt watchdog timer value on a DMA channel
@@ -19,7 +23,6 @@ Required properties:
- clock-names: Should be the names of the clocks
- "dma_clk" for the DMA clock
- "ptp_clk" for the PTP clock
-- phy-handle: See ethernet.txt file in the same directory
- phy-mode: See ethernet.txt file in the same directory
Optional properties:
@@ -29,19 +32,46 @@ Optional properties:
- amd,per-channel-interrupt: Indicates that Rx and Tx complete will generate
a unique interrupt for each DMA channel - this requires an additional
interrupt be configured for each DMA channel
+- amd,speed-set: Speed capabilities of the device
+ 0 - 1GbE and 10GbE (default)
+ 1 - 2.5GbE and 10GbE
+
+The following optional properties are represented by an array with each
+value corresponding to a particular speed. The first array value represents
+the setting for the 1GbE speed, the second value for the 2.5GbE speed and
+the third value for the 10GbE speed. All three values are required if the
+property is used.
+- amd,serdes-blwc: Baseline wandering correction enablement
+ 0 - Off
+ 1 - On
+- amd,serdes-cdr-rate: CDR rate speed selection
+- amd,serdes-pq-skew: PQ (data sampling) skew
+- amd,serdes-tx-amp: TX amplitude boost
+- amd,serdes-dfe-tap-config: DFE taps available to run
+- amd,serdes-dfe-tap-enable: DFE taps to enable
Example:
xgbe@e0700000 {
compatible = "amd,xgbe-seattle-v1a";
reg = <0 0xe0700000 0 0x80000>,
- <0 0xe0780000 0 0x80000>;
+ <0 0xe0780000 0 0x80000>,
+ <0 0xe1240800 0 0x00400>,
+ <0 0xe1250000 0 0x00060>,
+ <0 0xe1250080 0 0x00004>;
interrupt-parent = <&gic>;
interrupts = <0 325 4>,
- <0 326 1>, <0 327 1>, <0 328 1>, <0 329 1>;
+ <0 326 1>, <0 327 1>, <0 328 1>, <0 329 1>,
+ <0 323 4>;
amd,per-channel-interrupt;
clocks = <&xgbe_dma_clk>, <&xgbe_ptp_clk>;
clock-names = "dma_clk", "ptp_clk";
- phy-handle = <&phy>;
phy-mode = "xgmii";
mac-address = [ 02 a1 a2 a3 a4 a5 ];
+ amd,speed-set = <0>;
+ amd,serdes-blwc = <1>, <1>, <0>;
+ amd,serdes-cdr-rate = <2>, <2>, <7>;
+ amd,serdes-pq-skew = <10>, <10>, <30>;
+ amd,serdes-tx-amp = <15>, <15>, <10>;
+ amd,serdes-dfe-tap-config = <3>, <3>, <1>;
+ amd,serdes-dfe-tap-enable = <0>, <0>, <127>;
};
diff --git a/Documentation/devicetree/bindings/net/ezchip_enet.txt b/Documentation/devicetree/bindings/net/ezchip_enet.txt
new file mode 100644
index 000000000000..4e29b2b82873
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/ezchip_enet.txt
@@ -0,0 +1,15 @@
+* EZchip NPS Management Ethernet port driver
+
+Required properties:
+- compatible: Should be "ezchip,nps-mgt-enet"
+- reg: Address and length of the register set for the device
+- interrupts: Should contain the ENET interrupt
+
+Examples:
+
+ ethernet@f0003000 {
+ compatible = "ezchip,nps-mgt-enet";
+ reg = <0xf0003000 0x44>;
+ interrupts = <7>;
+ mac-address = [ 00 11 22 33 44 55 ];
+ };
diff --git a/Documentation/devicetree/bindings/net/ipq806x-dwmac.txt b/Documentation/devicetree/bindings/net/ipq806x-dwmac.txt
new file mode 100644
index 000000000000..6d7ab4e524d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/ipq806x-dwmac.txt
@@ -0,0 +1,35 @@
+* IPQ806x DWMAC Ethernet controller
+
+The device inherits all the properties of the dwmac/stmmac devices
+described in the file net/stmmac.txt with the following changes.
+
+Required properties:
+
+- compatible: should be "qcom,ipq806x-gmac" along with "snps,dwmac"
+ and any applicable more detailed version number
+ described in net/stmmac.txt
+
+- qcom,nss-common: should contain a phandle to a syscon device mapping the
+ nss-common registers.
+
+- qcom,qsgmii-csr: should contain a phandle to a syscon device mapping the
+ qsgmii-csr registers.
+
+Example:
+
+ gmac: ethernet@37000000 {
+ device_type = "network";
+ compatible = "qcom,ipq806x-gmac";
+ reg = <0x37000000 0x200000>;
+ interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+
+ qcom,nss-common = <&nss_common>;
+ qcom,qsgmii-csr = <&qsgmii_csr>;
+
+ clocks = <&gcc GMAC_CORE1_CLK>;
+ clock-names = "stmmaceth";
+
+ resets = <&gcc GMAC_CORE1_RESET>;
+ reset-names = "stmmaceth";
+ };
diff --git a/Documentation/devicetree/bindings/net/macb.txt b/Documentation/devicetree/bindings/net/macb.txt
index ba19d671e808..b5d79761ac97 100644
--- a/Documentation/devicetree/bindings/net/macb.txt
+++ b/Documentation/devicetree/bindings/net/macb.txt
@@ -7,8 +7,10 @@ Required properties:
Use "cdns,at32ap7000-macb" for other 10/100 usage or use the generic form: "cdns,macb".
Use "cdns,pc302-gem" for Picochip picoXcell pc302 and later devices based on
the Cadence GEM, or the generic form: "cdns,gem".
- Use "cdns,sama5d3-gem" for the Gigabit IP available on Atmel sama5d3 SoCs.
- Use "cdns,sama5d4-gem" for the Gigabit IP available on Atmel sama5d4 SoCs.
+ 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,zynqmp-gem" for Zynq Ultrascale+ MPSoC.
- 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/net/nfc/nfcmrvl.txt b/Documentation/devicetree/bindings/net/nfc/nfcmrvl.txt
new file mode 100644
index 000000000000..7c4a0cc370cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nfc/nfcmrvl.txt
@@ -0,0 +1,29 @@
+* Marvell International Ltd. NCI NFC Controller
+
+Required properties:
+- compatible: Should be "mrvl,nfc-uart".
+
+Optional SoC specific properties:
+- pinctrl-names: Contains only one value - "default".
+- pintctrl-0: Specifies the pin control groups used for this controller.
+- reset-n-io: Output GPIO pin used to reset the chip (active low).
+- hci-muxed: Specifies that the chip is muxing NCI over HCI frames.
+
+Optional UART-based chip specific properties:
+- flow-control: Specifies that the chip is using RTS/CTS.
+- break-control: Specifies that the chip needs specific break management.
+
+Example (for ARM-based BeagleBoard Black with 88W8887 on UART5):
+
+&uart5 {
+ status = "okay";
+
+ nfcmrvluart: nfcmrvluart@5 {
+ compatible = "mrvl,nfc-uart";
+
+ reset-n-io = <&gpio3 16 0>;
+
+ hci-muxed;
+ flow-control;
+ }
+};
diff --git a/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt b/Documentation/devicetree/bindings/net/nfc/st-nci.txt
index bb237072dbe9..d707588ed734 100644
--- a/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt
+++ b/Documentation/devicetree/bindings/net/nfc/st-nci.txt
@@ -1,7 +1,7 @@
-* STMicroelectronics SAS. ST21NFCB NFC Controller
+* STMicroelectronics SAS. ST NCI NFC Controller
Required properties:
-- compatible: Should be "st,st21nfcb-i2c".
+- compatible: Should be "st,st21nfcb-i2c" or "st,st21nfcc-i2c".
- clock-frequency: I²C work frequency.
- reg: address on the bus
- interrupt-parent: phandle for the interrupt gpio controller
diff --git a/Documentation/devicetree/bindings/net/nfc/trf7970a.txt b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt
index 7c89ca290ced..32b35a07abe4 100644
--- a/Documentation/devicetree/bindings/net/nfc/trf7970a.txt
+++ b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt
@@ -18,6 +18,9 @@ Optional SoC Specific Properties:
"IRQ Status Read" erratum.
- en2-rf-quirk: Specify that the trf7970a being used has the "EN2 RF"
erratum.
+- t5t-rmb-extra-byte-quirk: Specify that the trf7970a has the erratum
+ where an extra byte is returned by Read Multiple Block commands issued
+ to Type 5 tags.
Example (for ARM-based BeagleBone with TRF7970A on SPI1):
@@ -39,6 +42,7 @@ Example (for ARM-based BeagleBone with TRF7970A on SPI1):
autosuspend-delay = <30000>;
irq-status-read-quirk;
en2-rf-quirk;
+ t5t-rmb-extra-byte-quirk;
status = "okay";
};
};
diff --git a/Documentation/devicetree/bindings/net/nxp,lpc1850-dwmac.txt b/Documentation/devicetree/bindings/net/nxp,lpc1850-dwmac.txt
new file mode 100644
index 000000000000..7edba1264f6f
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nxp,lpc1850-dwmac.txt
@@ -0,0 +1,20 @@
+* NXP LPC1850 GMAC ethernet controller
+
+This device is a platform glue layer for stmmac.
+Please see stmmac.txt for the other unchanged properties.
+
+Required properties:
+ - compatible: Should contain "nxp,lpc1850-dwmac"
+
+Examples:
+
+mac: ethernet@40010000 {
+ compatible = "nxp,lpc1850-dwmac", "snps,dwmac-3.611", "snps,dwmac";
+ reg = <0x40010000 0x2000>;
+ interrupts = <5>;
+ interrupt-names = "macirq";
+ clocks = <&ccu1 CLK_CPU_ETHERNET>;
+ clock-names = "stmmaceth";
+ resets = <&rgu 22>;
+ reset-names = "stmmaceth";
+}
diff --git a/Documentation/devicetree/bindings/net/phy.txt b/Documentation/devicetree/bindings/net/phy.txt
index 40831fbaff72..525e1658f2da 100644
--- a/Documentation/devicetree/bindings/net/phy.txt
+++ b/Documentation/devicetree/bindings/net/phy.txt
@@ -30,6 +30,9 @@ Optional Properties:
- max-speed: Maximum PHY supported speed (10, 100, 1000...)
+- broken-turn-around: If set, indicates the PHY device does not correctly
+ release the turn around line low at the end of a MDIO transaction.
+
Example:
ethernet-phy@0 {
diff --git a/Documentation/devicetree/bindings/net/renesas,ravb.txt b/Documentation/devicetree/bindings/net/renesas,ravb.txt
new file mode 100644
index 000000000000..1fd8831437bf
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/renesas,ravb.txt
@@ -0,0 +1,48 @@
+* Renesas Electronics Ethernet AVB
+
+This file provides information on what the device node for the Ethernet AVB
+interface contains.
+
+Required properties:
+- compatible: "renesas,etheravb-r8a7790" if the device is a part of R8A7790 SoC.
+ "renesas,etheravb-r8a7794" if the device is a part of R8A7794 SoC.
+- reg: offset and length of (1) the register block and (2) the stream buffer.
+- interrupts: interrupt specifier for the sole interrupt.
+- phy-mode: see ethernet.txt file in the same directory.
+- phy-handle: see ethernet.txt file in the same directory.
+- #address-cells: number of address cells for the MDIO bus, must be equal to 1.
+- #size-cells: number of size cells on the MDIO bus, must be equal to 0.
+- clocks: clock phandle and specifier pair.
+- pinctrl-0: phandle, referring to a default pin configuration node.
+
+Optional properties:
+- interrupt-parent: the phandle for the interrupt controller that services
+ interrupts for this device.
+- pinctrl-names: pin configuration state name ("default").
+- renesas,no-ether-link: boolean, specify when a board does not provide a proper
+ AVB_LINK signal.
+- renesas,ether-link-active-low: boolean, specify when the AVB_LINK signal is
+ active-low instead of normal active-high.
+
+Example:
+
+ ethernet@e6800000 {
+ compatible = "renesas,etheravb-r8a7790";
+ reg = <0 0xe6800000 0 0x800>, <0 0xee0e8000 0 0x4000>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 163 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp8_clks R8A7790_CLK_ETHERAVB>;
+ phy-mode = "rmii";
+ phy-handle = <&phy0>;
+ pinctrl-0 = <&ether_pins>;
+ pinctrl-names = "default";
+ renesas,no-ether-link;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/net/rockchip-dwmac.txt b/Documentation/devicetree/bindings/net/rockchip-dwmac.txt
index 21fd199e89b5..93eac7ce1446 100644
--- a/Documentation/devicetree/bindings/net/rockchip-dwmac.txt
+++ b/Documentation/devicetree/bindings/net/rockchip-dwmac.txt
@@ -3,7 +3,7 @@ Rockchip SoC RK3288 10/100/1000 Ethernet driver(GMAC)
The device node has following properties.
Required properties:
- - compatible: Can be "rockchip,rk3288-gmac".
+ - compatible: Can be one of "rockchip,rk3288-gmac", "rockchip,rk3368-gmac"
- reg: addresses and length of the register sets for the device.
- interrupts: Should contain the GMAC interrupts.
- interrupt-names: Should contain the interrupt names "macirq".
diff --git a/Documentation/devicetree/bindings/net/ti,dp83867.txt b/Documentation/devicetree/bindings/net/ti,dp83867.txt
new file mode 100644
index 000000000000..58d935b58598
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/ti,dp83867.txt
@@ -0,0 +1,25 @@
+* Texas Instruments - dp83867 Giga bit ethernet phy
+
+Required properties:
+ - reg - The ID number for the phy, usually a small integer
+ - ti,rx-internal-delay - RGMII Recieve Clock Delay - see dt-bindings/net/ti-dp83867.h
+ for applicable values
+ - ti,tx-internal-delay - RGMII Transmit Clock Delay - see dt-bindings/net/ti-dp83867.h
+ for applicable values
+ - ti,fifo-depth - Transmitt FIFO depth- see dt-bindings/net/ti-dp83867.h
+ for applicable values
+
+Default child nodes are standard Ethernet PHY device
+nodes as described in Documentation/devicetree/bindings/net/phy.txt
+
+Example:
+
+ ethernet-phy@0 {
+ reg = <0>;
+ ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
+ ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_75_NS>;
+ ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+ };
+
+Datasheet can be found:
+http://www.ti.com/product/DP83867IR/datasheet
diff --git a/Documentation/devicetree/bindings/panel/hannstar,hsd100pxn1.txt b/Documentation/devicetree/bindings/panel/hannstar,hsd100pxn1.txt
new file mode 100644
index 000000000000..8270319a99de
--- /dev/null
+++ b/Documentation/devicetree/bindings/panel/hannstar,hsd100pxn1.txt
@@ -0,0 +1,7 @@
+HannStar Display Corp. HSD100PXN1 10.1" XGA LVDS panel
+
+Required properties:
+- compatible: should be "hannstar,hsd100pxn1"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/lg,lb070wv8.txt b/Documentation/devicetree/bindings/panel/lg,lb070wv8.txt
new file mode 100644
index 000000000000..a7588e5259cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/panel/lg,lb070wv8.txt
@@ -0,0 +1,7 @@
+LG 7" (800x480 pixels) TFT LCD panel
+
+Required properties:
+- compatible: should be "lg,lb070wv8"
+
+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/pci/xgene-pci-msi.txt b/Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
new file mode 100644
index 000000000000..36d881c8e6d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
@@ -0,0 +1,68 @@
+* AppliedMicro X-Gene v1 PCIe MSI controller
+
+Required properties:
+
+- compatible: should be "apm,xgene1-msi" to identify
+ X-Gene v1 PCIe MSI controller block.
+- msi-controller: indicates that this is X-Gene v1 PCIe MSI controller node
+- reg: physical base address (0x79000000) and length (0x900000) for controller
+ registers. These registers include the MSI termination address and data
+ registers as well as the MSI interrupt status registers.
+- reg-names: not required
+- interrupts: A list of 16 interrupt outputs of the controller, starting from
+ interrupt number 0x10 to 0x1f.
+- interrupt-names: not required
+
+Each PCIe node needs to have property msi-parent that points to msi controller node
+
+Examples:
+
+SoC DTSI:
+
+ + MSI node:
+ msi@79000000 {
+ compatible = "apm,xgene1-msi";
+ msi-controller;
+ reg = <0x00 0x79000000 0x0 0x900000>;
+ interrupts = <0x0 0x10 0x4>
+ <0x0 0x11 0x4>
+ <0x0 0x12 0x4>
+ <0x0 0x13 0x4>
+ <0x0 0x14 0x4>
+ <0x0 0x15 0x4>
+ <0x0 0x16 0x4>
+ <0x0 0x17 0x4>
+ <0x0 0x18 0x4>
+ <0x0 0x19 0x4>
+ <0x0 0x1a 0x4>
+ <0x0 0x1b 0x4>
+ <0x0 0x1c 0x4>
+ <0x0 0x1d 0x4>
+ <0x0 0x1e 0x4>
+ <0x0 0x1f 0x4>;
+ };
+
+ + PCIe controller node with msi-parent property pointing to MSI node:
+ pcie0: pcie@1f2b0000 {
+ status = "disabled";
+ device_type = "pci";
+ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */
+ 0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */
+ reg-names = "csr", "cfg";
+ ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000 /* io */
+ 0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* 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 0xc2 0x1
+ 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
+ 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
+ 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
+ dma-coherent;
+ clocks = <&pcie0clk 0>;
+ msi-parent= <&msi>;
+ };
diff --git a/Documentation/devicetree/bindings/pci/xilinx-pcie.txt b/Documentation/devicetree/bindings/pci/xilinx-pcie.txt
index 3e2c88d97ad4..02f979a48aeb 100644
--- a/Documentation/devicetree/bindings/pci/xilinx-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/xilinx-pcie.txt
@@ -58,5 +58,5 @@ Example:
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <1>;
- }
+ };
};
diff --git a/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt b/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt
new file mode 100644
index 000000000000..7f81ef90146a
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt
@@ -0,0 +1,40 @@
+* Broadcom SATA3 PHY for STB
+
+Required properties:
+- compatible: should be one or more of
+ "brcm,bcm7445-sata-phy"
+ "brcm,phy-sata3"
+- address-cells: should be 1
+- size-cells: should be 0
+- reg: register range for the PHY PCB interface
+- reg-names: should be "phy"
+
+Sub-nodes:
+ Each port's PHY should be represented as a sub-node.
+
+Sub-nodes required properties:
+- reg: the PHY number
+- phy-cells: generic PHY binding; must be 0
+Optional:
+- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port
+
+
+Example:
+
+ sata-phy@f0458100 {
+ compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3";
+ reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>;
+ reg-names = "phy";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sata-phy@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ };
+
+ sata-phy@1 {
+ reg = <1>;
+ #phy-cells = <0>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/phy/pxa1928-usb-phy.txt b/Documentation/devicetree/bindings/phy/pxa1928-usb-phy.txt
new file mode 100644
index 000000000000..660a13ca90b3
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/pxa1928-usb-phy.txt
@@ -0,0 +1,18 @@
+* Marvell PXA1928 USB and HSIC PHYs
+
+Required properties:
+- compatible: "marvell,pxa1928-usb-phy" or "marvell,pxa1928-hsic-phy"
+- reg: base address and length of the registers
+- clocks - A single clock. From common clock binding.
+- #phys-cells: should be 0. From commmon phy binding.
+- resets: reference to the reset controller
+
+Example:
+
+ usbphy: phy@7000 {
+ compatible = "marvell,pxa1928-usb-phy";
+ reg = <0x7000 0xe0>;
+ clocks = <&apmu_clocks PXA1928_CLK_USB>;
+ #phy-cells = <0>;
+ };
+
diff --git a/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt b/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt
index 00fc52a034b7..d564ba4f1cf6 100644
--- a/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt
+++ b/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt
@@ -6,6 +6,7 @@ This file provides information on what the device node for the R-Car generation
Required properties:
- compatible: "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC.
"renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC.
+ "renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC.
- reg: offset and length of the register block.
- #address-cells: number of address cells for the USB channel subnodes, must
be <1>.
diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
index fdd8046e650a..9462ab7ddd1f 100644
--- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
@@ -16,6 +16,8 @@ Required properties:
"allwinner,sun7i-a20-pinctrl"
"allwinner,sun8i-a23-pinctrl"
"allwinner,sun8i-a23-r-pinctrl"
+ "allwinner,sun8i-a33-pinctrl"
+
- reg: Should contain the register physical address and length for the
pin controller.
diff --git a/Documentation/devicetree/bindings/pinctrl/berlin,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/berlin,pinctrl.txt
new file mode 100644
index 000000000000..a8bb5e26019c
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/berlin,pinctrl.txt
@@ -0,0 +1,43 @@
+* Pin-controller driver for the Marvell Berlin SoCs
+
+Pin control registers are part of both chip controller and system
+controller register sets. Pin controller nodes should be a sub-node of
+either the chip controller or system controller node. The pins
+controlled are organized in groups, so no actual pin information is
+needed.
+
+A pin-controller node should contain subnodes representing the pin group
+configurations, one per function. Each subnode has the group name and
+the muxing function used.
+
+Be aware the Marvell Berlin datasheets use the keyword 'mode' for what
+is called a 'function' in the pin-controller subsystem.
+
+Required properties:
+- compatible: should be one of:
+ "marvell,berlin2-soc-pinctrl",
+ "marvell,berlin2-system-pinctrl",
+ "marvell,berlin2cd-soc-pinctrl",
+ "marvell,berlin2cd-system-pinctrl",
+ "marvell,berlin2q-soc-pinctrl",
+ "marvell,berlin2q-system-pinctrl"
+
+Required subnode-properties:
+- groups: a list of strings describing the group names.
+- function: a string describing the function used to mux the groups.
+
+Example:
+
+sys_pinctrl: pin-controller {
+ compatible = "marvell,berlin2q-system-pinctrl";
+
+ uart0_pmux: uart0-pmux {
+ groups = "GSM12";
+ function = "uart0";
+ };
+};
+
+&uart0 {
+ pinctrl-0 = <&uart0_pmux>;
+ pinctrl-names = "default";
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt
new file mode 100644
index 000000000000..8bbf25d58656
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt
@@ -0,0 +1,27 @@
+* Freescale i.MX7 Dual IOMUX Controller
+
+Please refer to fsl,imx-pinctrl.txt in this directory for common binding part
+and usage.
+
+Required properties:
+- compatible: "fsl,imx7d-iomuxc"
+- fsl,pins: each entry consists of 6 integers and represents the mux and config
+ setting for one pin. The first 5 integers <mux_reg conf_reg input_reg mux_val
+ input_val> are specified using a PIN_FUNC_ID macro, which can be found in
+ imx7d-pinfunc.h under device tree source folder. The last integer CONFIG is
+ the pad setting value like pull-up on this pin. Please refer to i.MX7 Dual
+ Reference Manual for detailed CONFIG settings.
+
+CONFIG bits definition:
+PAD_CTL_PUS_100K_DOWN (0 << 5)
+PAD_CTL_PUS_5K_UP (1 << 5)
+PAD_CTL_PUS_47K_UP (2 << 5)
+PAD_CTL_PUS_100K_UP (3 << 5)
+PAD_CTL_PUE (1 << 4)
+PAD_CTL_HYS (1 << 3)
+PAD_CTL_SRE_SLOW (1 << 2)
+PAD_CTL_SRE_FAST (0 << 2)
+PAD_CTL_DSE_X1 (0 << 0)
+PAD_CTL_DSE_X2 (1 << 0)
+PAD_CTL_DSE_X3 (2 << 0)
+PAD_CTL_DSE_X4 (3 << 0)
diff --git a/Documentation/devicetree/bindings/pinctrl/img,pistachio-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/img,pistachio-pinctrl.txt
new file mode 100644
index 000000000000..08a4a32c8eb0
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/img,pistachio-pinctrl.txt
@@ -0,0 +1,217 @@
+Imagination Technologies Pistachio SoC pin controllers
+======================================================
+
+The pin controllers on Pistachio are a combined GPIO controller, (GPIO)
+interrupt controller, and pinmux + pinconf device. The system ("east") pin
+controller on Pistachio has 99 pins, 90 of which are MFIOs which can be
+configured as GPIOs. The 90 GPIOs are divided into 6 banks of up to 16 GPIOs
+each. The GPIO banks are represented as sub-nodes of the pad controller node.
+
+Please refer to pinctrl-bindings.txt, ../gpio/gpio.txt, and
+../interrupt-controller/interrupts.txt for generic information regarding
+pin controller, GPIO, and interrupt bindings.
+
+Required properties for pin controller node:
+--------------------------------------------
+ - compatible: "img,pistachio-system-pinctrl".
+ - reg: Address range of the pinctrl registers.
+
+Required properties for GPIO bank sub-nodes:
+--------------------------------------------
+ - interrupts: Interrupt line for the GPIO bank.
+ - gpio-controller: Indicates the device is a GPIO controller.
+ - #gpio-cells: Must be two. The first cell is the GPIO pin number and the
+ second cell indicates the polarity. See <dt-bindings/gpio/gpio.h> for
+ a list of possible values.
+ - interrupt-controller: Indicates the device is an interrupt controller.
+ - #interrupt-cells: Must be two. The first cell is the GPIO pin number and
+ the second cell encodes the interrupt flags. See
+ <dt-bindings/interrupt-controller/irq.h> for a list of valid flags.
+
+Note that the N GPIO bank sub-nodes *must* be named gpio0, gpio1, ... gpioN-1.
+
+Required properties for pin configuration sub-nodes:
+----------------------------------------------------
+ - pins: List of pins to which the configuration applies. See below for a
+ list of possible pins.
+
+Optional properties for pin configuration sub-nodes:
+----------------------------------------------------
+ - function: Mux function for the specified pins. This is not applicable for
+ non-MFIO pins. See below for a list of valid functions for each pin.
+ - bias-high-impedance: Enable high-impedance mode.
+ - bias-pull-up: Enable weak pull-up.
+ - bias-pull-down: Enable weak pull-down.
+ - bias-bus-hold: Enable bus-keeper mode.
+ - drive-strength: Drive strength in mA. Supported values: 2, 4, 8, 12.
+ - input-schmitt-enable: Enable Schmitt trigger.
+ - input-schmitt-disable: Disable Schmitt trigger.
+ - slew-rate: Slew rate control. 0 for slow, 1 for fast.
+
+Pin Functions
+--- ---------
+mfio0 spim1
+mfio1 spim1, spim0, uart1
+mfio2 spim1, spim0, uart1
+mfio3 spim1
+mfio4 spim1
+mfio5 spim1
+mfio6 spim1
+mfio7 spim1
+mfio8 spim0
+mfio9 spim0
+mfio10 spim0
+mfio11 spis
+mfio12 spis
+mfio13 spis
+mfio14 spis
+mfio15 sdhost, mips_trace_clk, mips_trace_data
+mfio16 sdhost, mips_trace_dint, mips_trace_data
+mfio17 sdhost, mips_trace_trigout, mips_trace_data
+mfio18 sdhost, mips_trace_trigin, mips_trace_data
+mfio19 sdhost, mips_trace_dm, mips_trace_data
+mfio20 sdhost, mips_trace_probe_n, mips_trace_data
+mfio21 sdhost, mips_trace_data
+mfio22 sdhost, mips_trace_data
+mfio23 sdhost
+mfio24 sdhost
+mfio25 sdhost
+mfio26 sdhost
+mfio27 sdhost
+mfio28 i2c0, spim0
+mfio29 i2c0, spim0
+mfio30 i2c1, spim0
+mfio31 i2c1, spim1
+mfio32 i2c2
+mfio33 i2c2
+mfio34 i2c3
+mfio35 i2c3
+mfio36 i2s_out, audio_clk_in
+mfio37 i2s_out, debug_raw_cca_ind
+mfio38 i2s_out, debug_ed_sec20_cca_ind
+mfio39 i2s_out, debug_ed_sec40_cca_ind
+mfio40 i2s_out, debug_agc_done_0
+mfio41 i2s_out, debug_agc_done_1
+mfio42 i2s_out, debug_ed_cca_ind
+mfio43 i2s_out, debug_s2l_done
+mfio44 i2s_out
+mfio45 i2s_dac_clk, audio_sync
+mfio46 audio_trigger
+mfio47 i2s_in
+mfio48 i2s_in
+mfio49 i2s_in
+mfio50 i2s_in
+mfio51 i2s_in
+mfio52 i2s_in
+mfio53 i2s_in
+mfio54 i2s_in, spdif_in
+mfio55 uart0, spim0, spim1
+mfio56 uart0, spim0, spim1
+mfio57 uart0, spim0, spim1
+mfio58 uart0, spim1
+mfio59 uart1
+mfio60 uart1
+mfio61 spdif_out
+mfio62 spdif_in
+mfio63 eth, mips_trace_clk, mips_trace_data
+mfio64 eth, mips_trace_dint, mips_trace_data
+mfio65 eth, mips_trace_trigout, mips_trace_data
+mfio66 eth, mips_trace_trigin, mips_trace_data
+mfio67 eth, mips_trace_dm, mips_trace_data
+mfio68 eth, mips_trace_probe_n, mips_trace_data
+mfio69 eth, mips_trace_data
+mfio70 eth, mips_trace_data
+mfio71 eth
+mfio72 ir
+mfio73 pwmpdm, mips_trace_clk, sram_debug
+mfio74 pwmpdm, mips_trace_dint, sram_debug
+mfio75 pwmpdm, mips_trace_trigout, rom_debug
+mfio76 pwmpdm, mips_trace_trigin, rom_debug
+mfio77 mdc_debug, mips_trace_dm, rpu_debug
+mfio78 mdc_debug, mips_trace_probe_n, rpu_debug
+mfio79 ddr_debug, mips_trace_data, mips_debug
+mfio80 ddr_debug, mips_trace_data, mips_debug
+mfio81 dreq0, mips_trace_data, eth_debug
+mfio82 dreq1, mips_trace_data, eth_debug
+mfio83 mips_pll_lock, mips_trace_data, usb_debug
+mfio84 sys_pll_lock, mips_trace_data, usb_debug
+mfio85 wifi_pll_lock, mips_trace_data, sdhost_debug
+mfio86 bt_pll_lock, mips_trace_data, sdhost_debug
+mfio87 rpu_v_pll_lock, dreq2, socif_debug
+mfio88 rpu_l_pll_lock, dreq3, socif_debug
+mfio89 audio_pll_lock, dreq4, dreq5
+tck
+trstn
+tdi
+tms
+tdo
+jtag_comply
+safe_mode
+por_disable
+resetn
+
+Example:
+--------
+pinctrl@18101C00 {
+ compatible = "img,pistachio-system-pinctrl";
+ reg = <0x18101C00 0x400>;
+
+ gpio0: gpio0 {
+ interrupts = <GIC_SHARED 71 IRQ_TYPE_LEVEL_HIGH>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ ...
+
+ gpio5: gpio5 {
+ interrupts = <GIC_SHARED 76 IRQ_TYPE_LEVEL_HIGH>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ ...
+
+ uart0_xfer: uart0-xfer {
+ uart0-rxd {
+ pins = "mfio55";
+ function = "uart0";
+ };
+ uart0-txd {
+ pins = "mfio56";
+ function = "uart0";
+ };
+ };
+
+ uart0_rts_cts: uart0-rts-cts {
+ uart0-rts {
+ pins = "mfio57";
+ function = "uart0";
+ };
+ uart0-cts {
+ pins = "mfio58";
+ function = "uart0";
+ };
+ };
+};
+
+uart@... {
+ ...
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_xfer>, <&uart0_rts_cts>;
+ ...
+};
+
+usb_vbus: fixed-regulator {
+ ...
+ gpio = <&gpio5 6 GPIO_ACTIVE_HIGH>;
+ ...
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
index adda2a8d1d52..add7c38ec7d8 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
@@ -17,10 +17,10 @@ mpp0 0 gpio, uart0(rxd)
mpp1 1 gpo, uart0(txd)
mpp2 2 gpio, i2c0(sck), uart0(txd)
mpp3 3 gpio, i2c0(sda), uart0(rxd)
-mpp4 4 gpio, cpu_pd(vdd)
-mpp5 5 gpo, ge0(txclko), uart1(txd), spi1(clk), audio(mclk)
+mpp4 4 gpio, vdd(cpu-pd)
+mpp5 5 gpo, ge0(txclkout), uart1(txd), spi1(sck), audio(mclk)
mpp6 6 gpio, ge0(txd0), sata0(prsnt), tdm(rst), audio(sdo)
-mpp7 7 gpo, ge0(txd1), tdm(tdx), audio(lrclk)
+mpp7 7 gpo, ge0(txd1), tdm(dtx), audio(lrclk)
mpp8 8 gpio, ge0(txd2), uart0(rts), tdm(drx), audio(bclk)
mpp9 9 gpo, ge0(txd3), uart1(txd), sd0(clk), audio(spdifo)
mpp10 10 gpio, ge0(txctl), uart0(cts), tdm(fsync), audio(sdi)
@@ -52,8 +52,8 @@ mpp30 30 gpio, ge0(rxd7), ge1(rxclk), i2c1(sck)
mpp31 31 gpio, tclk, ge0(txerr)
mpp32 32 gpio, spi0(cs0)
mpp33 33 gpio, dev(bootcs), spi0(cs0)
-mpp34 34 gpo, dev(wen0), spi0(mosi)
-mpp35 35 gpo, dev(oen), spi0(sck)
+mpp34 34 gpo, dev(we0), spi0(mosi)
+mpp35 35 gpo, dev(oe), spi0(sck)
mpp36 36 gpo, dev(a1), spi0(miso)
mpp37 37 gpo, dev(a0), sata0(prsnt)
mpp38 38 gpio, dev(ready), uart1(cts), uart0(cts)
@@ -86,11 +86,11 @@ mpp57 57 gpio, dev(cs3), uart1(rxd), tdm(fsync), sata0(prsnt),
mpp58 58 gpio, dev(cs0), uart1(rts), tdm(int), audio(extclk),
uart0(rts)
mpp59 59 gpo, dev(ale0), uart1(rts), uart0(rts), audio(bclk)
-mpp60 60 gpio, dev(ale1), uart1(rxd), sata0(prsnt), pcie(rst-out),
+mpp60 60 gpio, dev(ale1), uart1(rxd), sata0(prsnt), pcie(rstout),
audio(sdi)
-mpp61 61 gpo, dev(wen1), uart1(txd), audio(rclk)
+mpp61 61 gpo, dev(we1), uart1(txd), audio(lrclk)
mpp62 62 gpio, dev(a2), uart1(cts), tdm(drx), pcie(clkreq0),
audio(mclk), uart0(cts)
mpp63 63 gpo, spi0(sck), tclk
-mpp64 64 gpio, spi0(miso), spi0-1(cs1)
-mpp65 65 gpio, spi0(mosi), spi0-1(cs2)
+mpp64 64 gpio, spi0(miso), spi0(cs1)
+mpp65 65 gpio, spi0(mosi), spi0(cs2)
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt
index 7de0cda4a379..06e5bb0367f5 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt
@@ -15,24 +15,24 @@ name pins functions
================================================================================
mpp0 0 gpio, dev(ad2), spi0(cs1), spi1(cs1)
mpp1 1 gpio, dev(ad3), spi0(mosi), spi1(mosi)
-mpp2 2 gpio, dev(ad4), ptp(eventreq), led(c0), audio(sdi)
-mpp3 3 gpio, dev(ad5), ptp(triggen), led(p3), audio(mclk)
+mpp2 2 gpio, dev(ad4), ptp(evreq), led(c0), audio(sdi)
+mpp3 3 gpio, dev(ad5), ptp(trig), led(p3), audio(mclk)
mpp4 4 gpio, dev(ad6), spi0(miso), spi1(miso)
mpp5 5 gpio, dev(ad7), spi0(cs2), spi1(cs2)
-mpp6 6 gpio, dev(ad0), led(p1), audio(rclk)
+mpp6 6 gpio, dev(ad0), led(p1), audio(lrclk)
mpp7 7 gpio, dev(ad1), ptp(clk), led(p2), audio(extclk)
mpp8 8 gpio, dev (bootcs), spi0(cs0), spi1(cs0)
-mpp9 9 gpio, nf(wen), spi0(sck), spi1(sck)
-mpp10 10 gpio, nf(ren), dram(vttctrl), led(c1)
+mpp9 9 gpio, spi0(sck), spi1(sck), nand(we)
+mpp10 10 gpio, dram(vttctrl), led(c1), nand(re)
mpp11 11 gpio, dev(a0), led(c2), audio(sdo)
mpp12 12 gpio, dev(a1), audio(bclk)
-mpp13 13 gpio, dev(readyn), pcie0(rstoutn), pcie1(rstoutn)
+mpp13 13 gpio, dev(ready), pcie0(rstout), pcie1(rstout)
mpp14 14 gpio, i2c0(sda), uart1(txd)
mpp15 15 gpio, i2c0(sck), uart1(rxd)
mpp16 16 gpio, uart0(txd)
mpp17 17 gpio, uart0(rxd)
-mpp18 18 gpio, tdm(intn)
-mpp19 19 gpio, tdm(rstn)
+mpp18 18 gpio, tdm(int)
+mpp19 19 gpio, tdm(rst)
mpp20 20 gpio, tdm(pclk)
mpp21 21 gpio, tdm(fsync)
mpp22 22 gpio, tdm(drx)
@@ -45,12 +45,12 @@ mpp28 28 gpio, led(p3), ge1(txctl), sd(clk)
mpp29 29 gpio, pcie1(clkreq), ge1(rxclk), sd(d3)
mpp30 30 gpio, ge1(txd0), spi1(cs0)
mpp31 31 gpio, ge1(txd1), spi1(mosi)
-mpp32 32 gpio, ge1(txd2), spi1(sck), ptp(triggen)
+mpp32 32 gpio, ge1(txd2), spi1(sck), ptp(trig)
mpp33 33 gpio, ge1(txd3), spi1(miso)
mpp34 34 gpio, ge1(txclkout), spi1(sck)
mpp35 35 gpio, ge1(rxctl), spi1(cs1), spi0(cs2)
mpp36 36 gpio, pcie0(clkreq)
-mpp37 37 gpio, pcie0(clkreq), tdm(intn), ge(mdc)
+mpp37 37 gpio, pcie0(clkreq), tdm(int), ge(mdc)
mpp38 38 gpio, pcie1(clkreq), ge(mdio)
mpp39 39 gpio, ref(clkout)
mpp40 40 gpio, uart1(txd)
@@ -58,25 +58,25 @@ mpp41 41 gpio, uart1(rxd)
mpp42 42 gpio, spi1(cs2), led(c0)
mpp43 43 gpio, sata0(prsnt), dram(vttctrl)
mpp44 44 gpio, sata0(prsnt)
-mpp45 45 gpio, spi0(cs2), pcie0(rstoutn)
-mpp46 46 gpio, led(p0), ge0(txd0), ge1(txd0)
+mpp45 45 gpio, spi0(cs2), pcie0(rstout)
+mpp46 46 gpio, led(p0), ge0(txd0), ge1(txd0), dev(we1)
mpp47 47 gpio, led(p1), ge0(txd1), ge1(txd1)
mpp48 48 gpio, led(p2), ge0(txd2), ge1(txd2)
mpp49 49 gpio, led(p3), ge0(txd3), ge1(txd3)
mpp50 50 gpio, led(c0), ge0(rxd0), ge1(rxd0)
mpp51 51 gpio, led(c1), ge0(rxd1), ge1(rxd1)
mpp52 52 gpio, led(c2), ge0(rxd2), ge1(rxd2)
-mpp53 53 gpio, pcie1(rstoutn), ge0(rxd3), ge1(rxd3)
-mpp54 54 gpio, pcie0(rstoutn), ge0(rxctl), ge1(rxctl)
+mpp53 53 gpio, pcie1(rstout), ge0(rxd3), ge1(rxd3)
+mpp54 54 gpio, pcie0(rstout), ge0(rxctl), ge1(rxctl)
mpp55 55 gpio, ge0(rxclk), ge1(rxclk)
mpp56 56 gpio, ge0(txclkout), ge1(txclkout)
-mpp57 57 gpio, ge0(txctl), ge1(txctl)
+mpp57 57 gpio, ge0(txctl), ge1(txctl), dev(we0)
mpp58 58 gpio, led(c0)
mpp59 59 gpio, led(c1)
mpp60 60 gpio, uart1(txd), led(c2)
mpp61 61 gpio, i2c1(sda), uart1(rxd), spi1(cs2), led(p0)
mpp62 62 gpio, i2c1(sck), led(p1)
-mpp63 63 gpio, ptp(triggen), led(p2)
+mpp63 63 gpio, ptp(trig), led(p2), dev(burst/last)
mpp64 64 gpio, dram(vttctrl), led(p3)
mpp65 65 gpio, sata1(prsnt)
-mpp66 66 gpio, ptp(eventreq), spi1(cs3)
+mpp66 66 gpio, ptp(evreq), spi1(cs3)
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt
index b17c96849fc9..54ec4c0a0d0e 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt
@@ -27,16 +27,16 @@ mpp8 8 gpio, ge0(txd1), dev(ad10)
mpp9 9 gpio, ge0(txd2), dev(ad11)
mpp10 10 gpio, ge0(txd3), dev(ad12)
mpp11 11 gpio, ge0(txctl), dev(ad13)
-mpp12 12 gpio, ge0(rxd0), pcie0(rstout), pcie1(rstout) [1], spi0(cs1), dev(ad14)
-mpp13 13 gpio, ge0(rxd1), pcie0(clkreq), pcie1(clkreq) [1], spi0(cs2), dev(ad15)
-mpp14 14 gpio, ge0(rxd2), ptp(clk), m(vtt_ctrl), spi0(cs3), dev(wen1)
-mpp15 15 gpio, ge0(rxd3), ge(mdc slave), pcie0(rstout), spi0(mosi), pcie1(rstout) [1]
-mpp16 16 gpio, ge0(rxctl), ge(mdio slave), m(decc_err), spi0(miso), pcie0(clkreq)
-mpp17 17 gpio, ge0(rxclk), ptp(clk), ua1(rxd), spi0(sck), sata1(prsnt)
-mpp18 18 gpio, ge0(rxerr), ptp(trig_gen), ua1(txd), spi0(cs0), pcie1(rstout) [1]
-mpp19 19 gpio, ge0(col), ptp(event_req), pcie0(clkreq), sata1(prsnt), ua0(cts)
-mpp20 20 gpio, ge0(txclk), ptp(clk), pcie1(rstout) [1], sata0(prsnt), ua0(rts)
-mpp21 21 gpio, spi0(cs1), ge1(rxd0), sata0(prsnt), sd0(cmd), dev(bootcs)
+mpp12 12 gpio, ge0(rxd0), pcie0(rstout), spi0(cs1), dev(ad14), pcie3(clkreq)
+mpp13 13 gpio, ge0(rxd1), pcie0(clkreq), pcie1(clkreq) [1], spi0(cs2), dev(ad15), pcie2(clkreq)
+mpp14 14 gpio, ge0(rxd2), ptp(clk), dram(vttctrl), spi0(cs3), dev(we1), pcie3(clkreq)
+mpp15 15 gpio, ge0(rxd3), ge(mdc slave), pcie0(rstout), spi0(mosi)
+mpp16 16 gpio, ge0(rxctl), ge(mdio slave), dram(deccerr), spi0(miso), pcie0(clkreq), pcie1(clkreq) [1]
+mpp17 17 gpio, ge0(rxclk), ptp(clk), ua1(rxd), spi0(sck), sata1(prsnt), sata0(prsnt)
+mpp18 18 gpio, ge0(rxerr), ptp(trig), ua1(txd), spi0(cs0)
+mpp19 19 gpio, ge0(col), ptp(evreq), ge0(txerr), sata1(prsnt), ua0(cts)
+mpp20 20 gpio, ge0(txclk), ptp(clk), sata0(prsnt), ua0(rts)
+mpp21 21 gpio, spi0(cs1), ge1(rxd0), sata0(prsnt), sd0(cmd), dev(bootcs), sata1(prsnt)
mpp22 22 gpio, spi0(mosi), dev(ad0)
mpp23 23 gpio, spi0(sck), dev(ad2)
mpp24 24 gpio, spi0(miso), ua0(cts), ua1(rxd), sd0(d4), dev(ready)
@@ -45,36 +45,36 @@ mpp26 26 gpio, spi0(cs2), i2c1(sck), sd0(d6), dev(cs1)
mpp27 27 gpio, spi0(cs3), ge1(txclkout), i2c1(sda), sd0(d7), dev(cs2)
mpp28 28 gpio, ge1(txd0), sd0(clk), dev(ad5)
mpp29 29 gpio, ge1(txd1), dev(ale0)
-mpp30 30 gpio, ge1(txd2), dev(oen)
+mpp30 30 gpio, ge1(txd2), dev(oe)
mpp31 31 gpio, ge1(txd3), dev(ale1)
-mpp32 32 gpio, ge1(txctl), dev(wen0)
-mpp33 33 gpio, m(decc_err), dev(ad3)
+mpp32 32 gpio, ge1(txctl), dev(we0)
+mpp33 33 gpio, dram(deccerr), dev(ad3)
mpp34 34 gpio, dev(ad1)
mpp35 35 gpio, ref(clk_out1), dev(a1)
-mpp36 36 gpio, ptp(trig_gen), dev(a0)
+mpp36 36 gpio, ptp(trig), dev(a0)
mpp37 37 gpio, ptp(clk), ge1(rxclk), sd0(d3), dev(ad8)
-mpp38 38 gpio, ptp(event_req), ge1(rxd1), ref(clk_out0), sd0(d0), dev(ad4)
+mpp38 38 gpio, ptp(evreq), ge1(rxd1), ref(clk_out0), sd0(d0), dev(ad4)
mpp39 39 gpio, i2c1(sck), ge1(rxd2), ua0(cts), sd0(d1), dev(a2)
mpp40 40 gpio, i2c1(sda), ge1(rxd3), ua0(rts), sd0(d2), dev(ad6)
-mpp41 41 gpio, ua1(rxd), ge1(rxctl), ua0(cts), spi1(cs3), dev(burst/last)
+mpp41 41 gpio, ua1(rxd), ge1(rxctl), ua0(cts), spi1(cs3), dev(burst/last), nand(rb0)
mpp42 42 gpio, ua1(txd), ua0(rts), dev(ad7)
-mpp43 43 gpio, pcie0(clkreq), m(vtt_ctrl), m(decc_err), pcie0(rstout), dev(clkout)
-mpp44 44 gpio, sata0(prsnt), sata1(prsnt), sata2(prsnt) [2], sata3(prsnt) [3], pcie0(rstout)
-mpp45 45 gpio, ref(clk_out0), pcie0(rstout), pcie1(rstout) [1], pcie2(rstout), pcie3(rstout)
-mpp46 46 gpio, ref(clk_out1), pcie0(rstout), pcie1(rstout) [1], pcie2(rstout), pcie3(rstout)
-mpp47 47 gpio, sata0(prsnt), sata1(prsnt), sata2(prsnt) [2], spi1(cs2), sata3(prsnt) [2]
-mpp48 48 gpio, sata0(prsnt), m(vtt_ctrl), tdm2c(pclk), audio(mclk), sd0(d4)
-mpp49 49 gpio, sata2(prsnt) [2], sata3(prsnt) [2], tdm2c(fsync), audio(lrclk), sd0(d5)
-mpp50 50 gpio, pcie0(rstout), pcie1(rstout) [1], tdm2c(drx), audio(extclk), sd0(cmd)
-mpp51 51 gpio, tdm2c(dtx), audio(sdo), m(decc_err)
-mpp52 52 gpio, pcie0(rstout), pcie1(rstout) [1], tdm2c(intn), audio(sdi), sd0(d6)
-mpp53 53 gpio, sata1(prsnt), sata0(prsnt), tdm2c(rstn), audio(bclk), sd0(d7)
-mpp54 54 gpio, sata0(prsnt), sata1(prsnt), pcie0(rstout), pcie1(rstout) [1], sd0(d3)
-mpp55 55 gpio, ua1(cts), ge(mdio), pcie1(clkreq) [1], spi1(cs1), sd0(d0)
-mpp56 56 gpio, ua1(rts), ge(mdc), m(decc_err), spi1(mosi)
-mpp57 57 gpio, spi1(sck), sd0(clk)
-mpp58 58 gpio, pcie1(clkreq) [1], i2c1(sck), pcie2(clkreq), spi1(miso), sd0(d1)
-mpp59 59 gpio, pcie0(rstout), i2c1(sda), pcie1(rstout) [1], spi1(cs0), sd0(d2)
+mpp43 43 gpio, pcie0(clkreq), dram(vttctrl), dram(deccerr), spi1(cs2), dev(clkout), nand(rb1)
+mpp44 44 gpio, sata0(prsnt), sata1(prsnt), sata2(prsnt) [2], sata3(prsnt) [3]
+mpp45 45 gpio, ref(clk_out0), pcie0(rstout), ua1(rxd)
+mpp46 46 gpio, ref(clk_out1), pcie0(rstout), ua1(txd)
+mpp47 47 gpio, sata0(prsnt), sata1(prsnt), sata2(prsnt) [2], sata3(prsnt) [2]
+mpp48 48 gpio, sata0(prsnt), dram(vttctrl), tdm(pclk), audio(mclk), sd0(d4), pcie0(clkreq)
+mpp49 49 gpio, sata2(prsnt) [2], sata3(prsnt) [2], tdm(fsync), audio(lrclk), sd0(d5), pcie1(clkreq)
+mpp50 50 gpio, pcie0(rstout), tdm(drx), audio(extclk), sd0(cmd)
+mpp51 51 gpio, tdm(dtx), audio(sdo), dram(deccerr), ptp(trig)
+mpp52 52 gpio, pcie0(rstout), tdm(int), audio(sdi), sd0(d6), ptp(clk)
+mpp53 53 gpio, sata1(prsnt), sata0(prsnt), tdm(rst), audio(bclk), sd0(d7), ptp(evreq)
+mpp54 54 gpio, sata0(prsnt), sata1(prsnt), pcie0(rstout), ge0(txerr), sd0(d3)
+mpp55 55 gpio, ua1(cts), ge(mdio), pcie1(clkreq) [1], spi1(cs1), sd0(d0), ua1(rxd)
+mpp56 56 gpio, ua1(rts), ge(mdc), dram(deccerr), spi1(mosi), ua1(txd)
+mpp57 57 gpio, spi1(sck), sd0(clk), ua1(txd)
+mpp58 58 gpio, pcie1(clkreq) [1], i2c1(sck), pcie2(clkreq), spi1(miso), sd0(d1), ua1(rxd)
+mpp59 59 gpio, pcie0(rstout), i2c1(sda), spi1(cs0), sd0(d2)
[1]: only available on 88F6820 and 88F6828
[2]: only available on 88F6828
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-39x-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-39x-pinctrl.txt
index 5b1a9dc004f4..a40b60f1ca4c 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-39x-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-39x-pinctrl.txt
@@ -4,8 +4,9 @@ Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
part and usage.
Required properties:
-- compatible: "marvell,88f6920-pinctrl", "marvell,88f6928-pinctrl"
- depending on the specific variant of the SoC being used.
+- compatible: "marvell,88f6920-pinctrl", "marvell,88f6925-pinctrl" or
+ "marvell,88f6928-pinctrl" depending on the specific variant of the
+ SoC being used.
- reg: register specifier of MPP registers
Available mpp pins/groups and functions:
@@ -24,55 +25,60 @@ mpp6 6 gpio, dev(cs3), xsmi(mdio)
mpp7 7 gpio, dev(ad9), xsmi(mdc)
mpp8 8 gpio, dev(ad10), ptp(trig)
mpp9 9 gpio, dev(ad11), ptp(clk)
-mpp10 10 gpio, dev(ad12), ptp(event)
+mpp10 10 gpio, dev(ad12), ptp(evreq)
mpp11 11 gpio, dev(ad13), led(clk)
mpp12 12 gpio, pcie0(rstout), dev(ad14), led(stb)
-mpp13 13 gpio, dev(ad15), led(data)
-mpp14 14 gpio, m(vtt), dev(wen1), ua1(txd)
+mpp13 13 gpio, dev(ad15), pcie2(clkreq), led(data)
+mpp14 14 gpio, dram(vttctrl), dev(we1), ua1(txd)
mpp15 15 gpio, pcie0(rstout), spi0(mosi), i2c1(sck)
-mpp16 16 gpio, m(decc), spi0(miso), i2c1(sda)
-mpp17 17 gpio, ua1(rxd), spi0(sck), smi(mdio)
+mpp16 16 gpio, dram(deccerr), spi0(miso), pcie0(clkreq), i2c1(sda)
+mpp17 17 gpio, ua1(rxd), spi0(sck), sata1(prsnt) [1], sata0(prsnt) [1], smi(mdio)
mpp18 18 gpio, ua1(txd), spi0(cs0), i2c2(sck)
-mpp19 19 gpio, sata1(present) [1], ua0(cts), ua1(rxd), i2c2(sda)
-mpp20 20 gpio, sata0(present) [1], ua0(rts), ua1(txd), smi(mdc)
-mpp21 21 gpio, spi0(cs1), sata0(present) [1], sd(cmd), dev(bootcs), ge(rxd0)
+mpp19 19 gpio, sata1(prsnt) [1], ua0(cts), ua1(rxd), i2c2(sda)
+mpp20 20 gpio, sata0(prsnt) [1], ua0(rts), ua1(txd), smi(mdc)
+mpp21 21 gpio, spi0(cs1), sata0(prsnt) [1], sd0(cmd), dev(bootcs),
+ sata1(prsnt) [1], ge(rxd0)
mpp22 22 gpio, spi0(mosi), dev(ad0)
mpp23 23 gpio, spi0(sck), dev(ad2)
-mpp24 24 gpio, spi0(miso), ua0(cts), ua1(rxd), sd(d4), dev(readyn)
-mpp25 25 gpio, spi0(cs0), ua0(rts), ua1(txd), sd(d5), dev(cs0)
-mpp26 26 gpio, spi0(cs2), i2c1(sck), sd(d6), dev(cs1)
-mpp27 27 gpio, spi0(cs3), i2c1(sda), sd(d7), dev(cs2), ge(txclkout)
-mpp28 28 gpio, sd(clk), dev(ad5), ge(txd0)
+mpp24 24 gpio, spi0(miso), ua0(cts), ua1(rxd), sd0(d4), dev(ready)
+mpp25 25 gpio, spi0(cs0), ua0(rts), ua1(txd), sd0(d5), dev(cs0)
+mpp26 26 gpio, spi0(cs2), i2c1(sck), sd0(d6), dev(cs1)
+mpp27 27 gpio, spi0(cs3), i2c1(sda), sd0(d7), dev(cs2), ge(txclkout)
+mpp28 28 gpio, sd0(clk), dev(ad5), ge(txd0)
mpp29 29 gpio, dev(ale0), ge(txd1)
-mpp30 30 gpio, dev(oen), ge(txd2)
+mpp30 30 gpio, dev(oe), ge(txd2)
mpp31 31 gpio, dev(ale1), ge(txd3)
-mpp32 32 gpio, dev(wen0), ge(txctl)
-mpp33 33 gpio, m(decc), dev(ad3)
+mpp32 32 gpio, dev(we0), ge(txctl)
+mpp33 33 gpio, dram(deccerr), dev(ad3)
mpp34 34 gpio, dev(ad1)
mpp35 35 gpio, ref(clk), dev(a1)
mpp36 36 gpio, dev(a0)
-mpp37 37 gpio, sd(d3), dev(ad8), ge(rxclk)
-mpp38 38 gpio, ref(clk), sd(d0), dev(ad4), ge(rxd1)
-mpp39 39 gpio, i2c1(sck), ua0(cts), sd(d1), dev(a2), ge(rxd2)
-mpp40 40 gpio, i2c1(sda), ua0(rts), sd(d2), dev(ad6), ge(rxd3)
-mpp41 41 gpio, ua1(rxd), ua0(cts), spi1(cs3), dev(burstn), nd(rbn0), ge(rxctl)
+mpp37 37 gpio, sd0(d3), dev(ad8), ge(rxclk)
+mpp38 38 gpio, ref(clk), sd0(d0), dev(ad4), ge(rxd1)
+mpp39 39 gpio, i2c1(sck), ua0(cts), sd0(d1), dev(a2), ge(rxd2)
+mpp40 40 gpio, i2c1(sda), ua0(rts), sd0(d2), dev(ad6), ge(rxd3)
+mpp41 41 gpio, ua1(rxd), ua0(cts), spi1(cs3), dev(burst/last), nand(rb0), ge(rxctl)
mpp42 42 gpio, ua1(txd), ua0(rts), dev(ad7)
-mpp43 43 gpio, pcie0(clkreq), m(vtt), m(decc), spi1(cs2), dev(clkout), nd(rbn1)
-mpp44 44 gpio, sata0(present) [1], sata1(present) [1], led(clk)
+mpp43 43 gpio, pcie0(clkreq), dram(vttctrl), dram(deccerr), spi1(cs2), dev(clkout), nand(rb1)
+mpp44 44 gpio, sata0(prsnt) [1], sata1(prsnt) [1], sata2(prsnt) [2],
+ sata3(prsnt) [2], led(clk)
mpp45 45 gpio, ref(clk), pcie0(rstout), ua1(rxd)
mpp46 46 gpio, ref(clk), pcie0(rstout), ua1(txd), led(stb)
-mpp47 47 gpio, sata0(present) [1], sata1(present) [1], led(data)
-mpp48 48 gpio, sata0(present) [1], m(vtt), tdm(pclk) [1], audio(mclk) [1], sd(d4), pcie0(clkreq), ua1(txd)
-mpp49 49 gpio, tdm(fsync) [1], audio(lrclk) [1], sd(d5), ua2(rxd)
-mpp50 50 gpio, pcie0(rstout), tdm(drx) [1], audio(extclk) [1], sd(cmd), ua2(rxd)
-mpp51 51 gpio, tdm(dtx) [1], audio(sdo) [1], m(decc), ua2(txd)
-mpp52 52 gpio, pcie0(rstout), tdm(intn) [1], audio(sdi) [1], sd(d6), i2c3(sck)
-mpp53 53 gpio, sata1(present) [1], sata0(present) [1], tdm(rstn) [1], audio(bclk) [1], sd(d7), i2c3(sda)
-mpp54 54 gpio, sata0(present) [1], sata1(present) [1], pcie0(rstout), sd(d3), ua3(txd)
-mpp55 55 gpio, ua1(cts), spi1(cs1), sd(d0), ua1(rxd), ua3(rxd)
-mpp56 56 gpio, ua1(rts), m(decc), spi1(mosi), ua1(txd)
-mpp57 57 gpio, spi1(sck), sd(clk), ua1(txd)
-mpp58 58 gpio, i2c1(sck), pcie2(clkreq), spi1(miso), sd(d1), ua1(rxd)
-mpp59 59 gpio, pcie0(rstout), i2c1(sda), spi1(cs0), sd(d2)
+mpp47 47 gpio, sata0(prsnt) [1], sata1(prsnt) [1], sata2(prsnt) [2],
+ sata3(prsnt) [2], led(data)
+mpp48 48 gpio, sata0(prsnt) [1], dram(vttctrl), tdm(pclk) [2], audio(mclk) [2], sd0(d4), pcie0(clkreq), ua1(txd)
+mpp49 49 gpio, sata2(prsnt) [2], sata3(prsnt) [2], tdm(fsync) [2],
+ audio(lrclk) [2], sd0(d5), ua2(rxd)
+mpp50 50 gpio, pcie0(rstout), tdm(drx) [2], audio(extclk) [2], sd0(cmd), ua2(rxd)
+mpp51 51 gpio, tdm(dtx) [2], audio(sdo) [2], dram(deccerr), ua2(txd)
+mpp52 52 gpio, pcie0(rstout), tdm(int) [2], audio(sdi) [2], sd0(d6), i2c3(sck)
+mpp53 53 gpio, sata1(prsnt) [1], sata0(prsnt) [1], tdm(rst) [2], audio(bclk) [2], sd0(d7), i2c3(sda)
+mpp54 54 gpio, sata0(prsnt) [1], sata1(prsnt) [1], pcie0(rstout), sd0(d3), ua3(txd)
+mpp55 55 gpio, ua1(cts), spi1(cs1), sd0(d0), ua1(rxd), ua3(rxd)
+mpp56 56 gpio, ua1(rts), dram(deccerr), spi1(mosi), ua1(txd)
+mpp57 57 gpio, spi1(sck), sd0(clk), ua1(txd)
+mpp58 58 gpio, i2c1(sck), pcie2(clkreq), spi1(miso), sd0(d1), ua1(rxd)
+mpp59 59 gpio, pcie0(rstout), i2c1(sda), spi1(cs0), sd0(d2)
-[1]: only available on 88F6928
+[1]: only available on 88F6925/88F6928
+[2]: only available on 88F6928
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
index 373dbccd7ab0..76da7222ff92 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
@@ -18,7 +18,7 @@ only for more detailed description in this document.
name pins functions
================================================================================
-mpp0 0 gpio, ge0(txclko), lcd(d0)
+mpp0 0 gpio, ge0(txclkout), lcd(d0)
mpp1 1 gpio, ge0(txd0), lcd(d1)
mpp2 2 gpio, ge0(txd1), lcd(d2)
mpp3 3 gpio, ge0(txd2), lcd(d3)
@@ -30,49 +30,50 @@ mpp8 8 gpio, ge0(rxd2), lcd(d8)
mpp9 9 gpio, ge0(rxd3), lcd(d9)
mpp10 10 gpio, ge0(rxctl), lcd(d10)
mpp11 11 gpio, ge0(rxclk), lcd(d11)
-mpp12 12 gpio, ge0(txd4), ge1(txd0), lcd(d12)
-mpp13 13 gpio, ge0(txd5), ge1(txd1), lcd(d13)
-mpp14 14 gpio, ge0(txd6), ge1(txd2), lcd(d15)
-mpp15 15 gpio, ge0(txd7), ge1(txd3), lcd(d16)
-mpp16 16 gpio, ge0(txd7), ge1(txd3), lcd(d16)
-mpp17 17 gpio, ge0(col), ge1(txctl), lcd(d17)
+mpp12 12 gpio, ge0(txd4), ge1(txclkout), lcd(d12)
+mpp13 13 gpio, ge0(txd5), ge1(txd0), spi1(mosi), lcd(d13)
+mpp14 14 gpio, ge0(txd6), ge1(txd1), spi1(sck), lcd(d15)
+mpp15 15 gpio, ge0(txd7), ge1(txd2), lcd(d16)
+mpp16 16 gpio, ge0(txd7), ge1(txd3), spi1(cs0), lcd(d16)
+mpp17 17 gpio, ge0(col), ge1(txctl), spi1(miso), lcd(d17)
mpp18 18 gpio, ge0(rxerr), ge1(rxd0), lcd(d18), ptp(trig)
mpp19 19 gpio, ge0(crs), ge1(rxd1), lcd(d19), ptp(evreq)
mpp20 20 gpio, ge0(rxd4), ge1(rxd2), lcd(d20), ptp(clk)
-mpp21 21 gpio, ge0(rxd5), ge1(rxd3), lcd(d21), mem(bat)
+mpp21 21 gpio, ge0(rxd5), ge1(rxd3), lcd(d21), dram(bat)
mpp22 22 gpio, ge0(rxd6), ge1(rxctl), lcd(d22), sata0(prsnt)
mpp23 23 gpio, ge0(rxd7), ge1(rxclk), lcd(d23), sata1(prsnt)
-mpp24 24 gpio, lcd(hsync), sata1(prsnt), nf(bootcs-re), tdm(rst)
-mpp25 25 gpio, lcd(vsync), sata0(prsnt), nf(bootcs-we), tdm(pclk)
-mpp26 26 gpio, lcd(clk), tdm(fsync), vdd(cpu1-pd)
+mpp24 24 gpio, lcd(hsync), sata1(prsnt), tdm(rst)
+mpp25 25 gpio, lcd(vsync), sata0(prsnt), tdm(pclk)
+mpp26 26 gpio, lcd(clk), tdm(fsync)
mpp27 27 gpio, lcd(e), tdm(dtx), ptp(trig)
mpp28 28 gpio, lcd(pwm), tdm(drx), ptp(evreq)
-mpp29 29 gpio, lcd(ref-clk), tdm(int0), ptp(clk), vdd(cpu0-pd)
+mpp29 29 gpio, lcd(ref-clk), tdm(int0), ptp(clk)
mpp30 30 gpio, tdm(int1), sd0(clk)
-mpp31 31 gpio, tdm(int2), sd0(cmd), vdd(cpu0-pd)
-mpp32 32 gpio, tdm(int3), sd0(d0), vdd(cpu1-pd)
-mpp33 33 gpio, tdm(int4), sd0(d1), mem(bat)
-mpp34 34 gpio, tdm(int5), sd0(d2), sata0(prsnt)
+mpp31 31 gpio, tdm(int2), sd0(cmd)
+mpp32 32 gpio, tdm(int3), sd0(d0)
+mpp33 33 gpio, tdm(int4), sd0(d1), dram(bat), dram(vttctrl)
+mpp34 34 gpio, tdm(int5), sd0(d2), sata0(prsnt), dram(deccerr)
mpp35 35 gpio, tdm(int6), sd0(d3), sata1(prsnt)
-mpp36 36 gpio, spi(mosi)
-mpp37 37 gpio, spi(miso)
-mpp38 38 gpio, spi(sck)
-mpp39 39 gpio, spi(cs0)
-mpp40 40 gpio, spi(cs1), uart2(cts), lcd(vga-hsync), vdd(cpu1-pd),
- pcie(clkreq0)
-mpp41 41 gpio, spi(cs2), uart2(rts), lcd(vga-vsync), sata1(prsnt),
- pcie(clkreq1)
-mpp42 42 gpio, uart2(rxd), uart0(cts), tdm(int7), tdm-1(timer),
- vdd(cpu0-pd)
-mpp43 43 gpio, uart2(txd), uart0(rts), spi(cs3), pcie(rstout),
- vdd(cpu2-3-pd){1}
-mpp44 44 gpio, uart2(cts), uart3(rxd), spi(cs4), pcie(clkreq2),
- mem(bat)
-mpp45 45 gpio, uart2(rts), uart3(txd), spi(cs5), sata1(prsnt)
-mpp46 46 gpio, uart3(rts), uart1(rts), spi(cs6), sata0(prsnt)
-mpp47 47 gpio, uart3(cts), uart1(cts), spi(cs7), pcie(clkreq3),
- ref(clkout)
-mpp48 48 gpio, tclk, dev(burst/last)
+mpp36 36 gpio, spi0(mosi)
+mpp37 37 gpio, spi0(miso)
+mpp38 38 gpio, spi0(sck)
+mpp39 39 gpio, spi0(cs0)
+mpp40 40 gpio, spi0(cs1), uart2(cts), lcd(vga-hsync), pcie(clkreq0),
+ spi1(cs1)
+mpp41 41 gpio, spi0(cs2), uart2(rts), lcd(vga-vsync), sata1(prsnt),
+ pcie(clkreq1), spi1(cs2)
+mpp42 42 gpio, uart2(rxd), uart0(cts), tdm(int7), tdm(timer)
+mpp43 43 gpio, uart2(txd), uart0(rts), spi0(cs3), pcie(rstout),
+ spi1(cs3)
+mpp44 44 gpio, uart2(cts), uart3(rxd), spi0(cs4), pcie(clkreq2),
+ dram(bat), spi1(cs4)
+mpp45 45 gpio, uart2(rts), uart3(txd), spi0(cs5), sata1(prsnt),
+ spi1(cs5), dram(vttctrl)
+mpp46 46 gpio, uart3(rts), uart1(rts), spi0(cs6), sata0(prsnt),
+ spi1(cs6)
+mpp47 47 gpio, uart3(cts), uart1(cts), spi0(cs7), pcie(clkreq3),
+ ref(clkout), spi1(cs7)
+mpp48 48 gpio, dev(clkout), dev(burst/last), nand(rb)
* Marvell Armada XP (mv78260 and mv78460 only)
@@ -84,9 +85,9 @@ mpp51 51 gpio, dev(ad16)
mpp52 52 gpio, dev(ad17)
mpp53 53 gpio, dev(ad18)
mpp54 54 gpio, dev(ad19)
-mpp55 55 gpio, dev(ad20), vdd(cpu0-pd)
-mpp56 56 gpio, dev(ad21), vdd(cpu1-pd)
-mpp57 57 gpio, dev(ad22), vdd(cpu2-3-pd){1}
+mpp55 55 gpio, dev(ad20)
+mpp56 56 gpio, dev(ad21)
+mpp57 57 gpio, dev(ad22)
mpp58 58 gpio, dev(ad23)
mpp59 59 gpio, dev(ad24)
mpp60 60 gpio, dev(ad25)
@@ -96,6 +97,3 @@ mpp63 63 gpio, dev(ad28)
mpp64 64 gpio, dev(ad29)
mpp65 65 gpio, dev(ad30)
mpp66 66 gpio, dev(ad31)
-
-Notes:
-* {1} vdd(cpu2-3-pd) only available on mv78460.
diff --git a/Documentation/devicetree/bindings/pinctrl/nxp,lpc1850-scu.txt b/Documentation/devicetree/bindings/pinctrl/nxp,lpc1850-scu.txt
new file mode 100644
index 000000000000..df0309c57505
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/nxp,lpc1850-scu.txt
@@ -0,0 +1,57 @@
+NXP LPC18xx/43xx SCU pin controller Device Tree Bindings
+--------------------------------------------------------
+
+Required properties:
+- compatible : Should be "nxp,lpc1850-scu"
+- reg : Address and length of the register set for the device
+- clocks : Clock specifier (see clock bindings for details)
+
+The lpc1850-scu driver uses the generic pin multiplexing and generic pin
+configuration documented in pinctrl-bindings.txt.
+
+The following generic nodes are supported:
+ - function
+ - pins
+ - bias-disable
+ - bias-pull-up
+ - bias-pull-down
+ - drive-strength
+ - input-enable
+ - input-disable
+ - input-schmitt-enable
+ - input-schmitt-disable
+ - slew-rate
+
+Not all pins support all properties so either refer to the NXP 1850/4350
+user manual or the pin table in the pinctrl-lpc18xx driver for supported
+pin properties.
+
+Example:
+pinctrl: pinctrl@40086000 {
+ compatible = "nxp,lpc1850-scu";
+ reg = <0x40086000 0x1000>;
+ clocks = <&ccu1 CLK_CPU_SCU>;
+
+ i2c0_pins: i2c0-pins {
+ i2c0_pins_cfg {
+ pins = "i2c0_scl", "i2c0_sda";
+ function = "i2c0";
+ input-enable;
+ };
+ };
+
+ uart0_pins: uart0-pins {
+ uart0_rx_cfg {
+ pins = "pf_11";
+ function = "uart0";
+ bias-disable;
+ input-enable;
+ };
+
+ uart0_tx_cfg {
+ pins = "pf_10";
+ function = "uart0";
+ bias-disable;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-atlas7.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-atlas7.txt
new file mode 100644
index 000000000000..eecf028ff485
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-atlas7.txt
@@ -0,0 +1,109 @@
+CSR SiRFatlas7 pinmux controller
+
+Required properties:
+- compatible : "sirf,atlas7-ioc"
+- reg : Address range of the pinctrl registers
+
+For example, pinctrl might have properties like the following:
+ pinctrl: ioc@18880000 {
+ compatible = "sirf,atlas7-ioc";
+ reg = <0x18880000 0x1000>;
+
+ a_ac97_pmx: ac97@0 {
+ ac97 {
+ groups = "audio_ac97_grp";
+ function = "audio_ac97";
+ };
+ };
+
+ ...
+
+ sd2_pmx: sd2@0 {
+ sd2 {
+ groups = "sd2_grp0";
+ function = "sd2";
+ };
+ };
+
+ ...
+
+
+ sample0_cfg: sample0@0 {
+ sample0 {
+ pins = "ldd_0", "ldd_1";
+ bias-pull-up;
+ };
+ };
+
+ sample1_cfg: sample1@0 {
+ sample1 {
+ pins = "ldd_2", "ldd_3";
+ input-schmitt-enable;
+ };
+ };
+
+ sample2_cfg: sample2@0 {
+ sample2 {
+ groups = "uart4_nopause_grp";
+ bias-pull-down;
+ };
+ };
+
+ sample3_cfg: sample3@0 {
+ sample3 {
+ pins = "ldd_4", "ldd_5";
+ drive-strength = <2>;
+ };
+ };
+ };
+
+Please refer to pinctrl-bindings.txt in this directory for details of the common
+pinctrl bindings used by client devices.
+
+SiRFatlas7's pinmux nodes act as a container for an abitrary number of subnodes.
+Each of these subnodes represents some desired configuration for a group of pins.
+
+Required subnode-properties:
+- groups : An array of strings. Each string contains the name of a group.
+- function: A string containing the name of the function to mux to the
+ group.
+
+ Valid values for group and function names can be found from looking at the
+ group and function arrays in driver files:
+ drivers/pinctrl/pinctrl-sirf.c
+
+For example, pinctrl might have subnodes like the following:
+ sd0_pmx: sd0@0 {
+ sd0 {
+ groups = "sd0_grp";
+ function = "sd0";
+ };
+ };
+
+ sd1_pmx0: sd1@0 {
+ sd1 {
+ groups = "sd1_grp0";
+ function = "sd1_m0";
+ };
+ };
+
+ sd1_pmx1: sd1@1 {
+ sd1 {
+ groups = "sd1_grp1";
+ function = "sd1_m1";
+ };
+ };
+
+For a specific board, if it wants to use sd1,
+it can add the following to its board-specific .dts file.
+sd1: sd@0x12340000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd1_pmx0>;
+}
+
+or
+
+sd1: sd@0x12340000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd1_pmx1>;
+}
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
index 5868a0f7255d..0480bc31bfd7 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
@@ -3,9 +3,11 @@
The Mediatek's Pin controller is used to control SoC pins.
Required properties:
-- compatible: value should be either of the following.
+- compatible: value should be one of the following.
(a) "mediatek,mt8135-pinctrl", compatible with mt8135 pinctrl.
-- mediatek,pctl-regmap: Should be a phandle of the syscfg node.
+ (b) "mediatek,mt8173-pinctrl", compatible with mt8173 pinctrl.
+ (c) "mediatek,mt6397-pinctrl", compatible with mt6397 pinctrl.
+ (d) "mediatek,mt8127-pinctrl", compatible with mt8127 pinctrl.
- pins-are-numbered: Specify the subnodes are using numbered pinmux to
specify pins.
- gpio-controller : Marks the device node as a gpio controller.
@@ -24,6 +26,9 @@ Required properties:
Only the following flags are supported:
0 - GPIO_ACTIVE_HIGH
1 - GPIO_ACTIVE_LOW
+
+Optional properties:
+- mediatek,pctl-regmap: Should be a phandle of the syscfg node.
- reg: physicall address base for EINT registers
- interrupt-controller: Marks the device node as an interrupt controller
- #interrupt-cells: Should be two.
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.txt
new file mode 100644
index 000000000000..77aa11790163
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.txt
@@ -0,0 +1,90 @@
+Qualcomm MSM8660 TLMM block
+
+Required properties:
+- compatible: "qcom,msm8660-pinctrl"
+- reg: Should be the base address and length of the TLMM block.
+- interrupts: Should be the parent IRQ of the TLMM block.
+- interrupt-controller: Marks the device node as an interrupt controller.
+- #interrupt-cells: Should be two.
+- gpio-controller: Marks the device node as a GPIO controller.
+- #gpio-cells : Should be two.
+ The first cell is the gpio pin number and the
+ second cell is used for optional parameters.
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+Qualcomm's pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+ pins, function, bias-disable, bias-pull-down, bias-pull,up, drive-strength,
+ output-low, output-high.
+
+Non-empty subnodes must specify the 'pins' property.
+
+Valid values for pins are:
+ gpio0-gpio172, sdc3_clk, sdc3_cmd, sdc3_data sdc4_clk, sdc4_cmd, sdc4_data
+
+Valid values for function are:
+ gpio, cam_mclk, dsub, ext_gps, gp_clk_0a, gp_clk_0b, gp_clk_1a, gp_clk_1b,
+ gp_clk_2a, gp_clk_2b, gp_mn, gsbi1, gsbi1_spi_cs1_n, gsbi1_spi_cs2a_n,
+ gsbi1_spi_cs2b_n, gsbi1_spi_cs3_n, gsbi2, gsbi2_spi_cs1_n, gsbi2_spi_cs2_n,
+ gsbi2_spi_cs3_n, gsbi3, gsbi3_spi_cs1_n, gsbi3_spi_cs2_n, gsbi3_spi_cs3_n,
+ gsbi4, gsbi5, gsbi6, gsbi7, gsbi8, gsbi9, gsbi10, gsbi11, gsbi12, hdmi, i2s,
+ lcdc, mdp_vsync, mi2s, pcm, ps_hold, sdc1, sdc2, sdc5, tsif1, tsif2, usb_fs1,
+ usb_fs1_oe_n, usb_fs2, usb_fs2_oe_n, vfe, vsens_alarm,
+
+Example:
+
+ msmgpio: pinctrl@800000 {
+ compatible = "qcom,msm8660-pinctrl";
+ reg = <0x800000 0x4000>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <0 16 0x4>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&gsbi12_uart>;
+
+ gsbi12_uart: gsbi12-uart {
+ mux {
+ pins = "gpio117", "gpio118";
+ function = "gsbi12";
+ };
+
+ tx {
+ pins = "gpio118";
+ drive-strength = <8>;
+ bias-disable;
+ };
+
+ rx {
+ pins = "gpio117";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt
index bfe72ec055e3..51cee44fc140 100644
--- a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt
@@ -16,7 +16,9 @@ Required Properties:
- "renesas,pfc-r8a7778": for R8A7778 (R-Mobile M1) compatible pin-controller.
- "renesas,pfc-r8a7779": for R8A7779 (R-Car H1) compatible pin-controller.
- "renesas,pfc-r8a7790": for R8A7790 (R-Car H2) compatible pin-controller.
- - "renesas,pfc-r8a7791": for R8A7791 (R-Car M2) compatible pin-controller.
+ - "renesas,pfc-r8a7791": for R8A7791 (R-Car M2-W) compatible pin-controller.
+ - "renesas,pfc-r8a7793": for R8A7793 (R-Car M2-N) compatible pin-controller.
+ - "renesas,pfc-r8a7794": for R8A7794 (R-Car E2) compatible pin-controller.
- "renesas,pfc-sh73a0": for SH73A0 (SH-Mobile AG5) compatible pin-controller.
- reg: Base address and length of each memory resource used by the pin
diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt
index 388b213249fd..391ef4be8d50 100644
--- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt
@@ -21,14 +21,15 @@ defined as gpio sub-nodes of the pinmux controller.
Required properties for iomux controller:
- compatible: one of "rockchip,rk2928-pinctrl", "rockchip,rk3066a-pinctrl"
"rockchip,rk3066b-pinctrl", "rockchip,rk3188-pinctrl"
- "rockchip,rk3288-pinctrl"
+ "rockchip,rk3288-pinctrl", "rockchip,rk3368-pinctrl"
- rockchip,grf: phandle referencing a syscon providing the
"general register files"
Optional properties for iomux controller:
- rockchip,pmu: phandle referencing a syscon providing the pmu registers
as some SoCs carry parts of the iomux controller registers there.
- Required for at least rk3188 and rk3288.
+ Required for at least rk3188 and rk3288. On the rk3368 this should
+ point to the PMUGRF syscon.
Deprecated properties for iomux controller:
- reg: first element is the general register space of the iomux controller
diff --git a/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.txt
index b7b55a964f65..f488b0f77406 100644
--- a/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.txt
@@ -45,8 +45,9 @@ to specify in a pinconf subnode:
Valid values for groups are:
ethernet0_0_grp, ethernet1_0_grp, mdio0_0_grp, mdio1_0_grp,
- qspi0_0_grp, qspi1_0_grp, qspi_fbclk, qspi_cs1_grp, spi0_0_grp,
- spi0_1_grp - spi0_2_grp, spi1_0_grp - spi1_3_grp, sdio0_0_grp - sdio0_2_grp,
+ qspi0_0_grp, qspi1_0_grp, qspi_fbclk, qspi_cs1_grp, spi0_0_grp - spi0_2_grp,
+ spi0_X_ssY (X=0..2, Y=0..2), spi1_0_grp - spi1_3_grp,
+ spi1_X_ssY (X=0..3, Y=0..2), sdio0_0_grp - sdio0_2_grp,
sdio1_0_grp - sdio1_3_grp, sdio0_emio_wp, sdio0_emio_cd, sdio1_emio_wp,
sdio1_emio_cd, smc0_nor, smc0_nor_cs1_grp, smc0_nor_addr25_grp, smc0_nand,
can0_0_grp - can0_10_grp, can1_0_grp - can1_11_grp, uart0_0_grp - uart0_10_grp,
@@ -59,7 +60,7 @@ to specify in a pinconf subnode:
Valid values for function are:
ethernet0, ethernet1, mdio0, mdio1, qspi0, qspi1, qspi_fbclk, qspi_cs1,
- spi0, spi1, sdio0, sdio0_pc, sdio0_cd, sdio0_wp,
+ spi0, spi0_ss, spi1, spi1_ss, sdio0, sdio0_pc, sdio0_cd, sdio0_wp,
sdio1, sdio1_pc, sdio1_cd, sdio1_wp,
smc0_nor, smc0_nor_cs1, smc0_nor_addr25, smc0_nand, can0, can1, uart0, uart1,
i2c0, i2c1, ttc0, ttc1, swdt0, gpio0, usb0, usb1
diff --git a/Documentation/devicetree/bindings/power/bq24257.txt b/Documentation/devicetree/bindings/power/bq24257.txt
new file mode 100644
index 000000000000..5c9d3940d07c
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/bq24257.txt
@@ -0,0 +1,21 @@
+Binding for TI bq24257 Li-Ion Charger
+
+Required properties:
+- compatible: Should contain one of the following:
+ * "ti,bq24257"
+- reg: integer, i2c address of the device.
+- ti,battery-regulation-voltage: integer, maximum charging voltage in uV.
+- ti,charge-current: integer, maximum charging current in uA.
+- ti,termination-current: integer, charge will be terminated when current in
+ constant-voltage phase drops below this value (in uA).
+
+Example:
+
+bq24257 {
+ compatible = "ti,bq24257";
+ reg = <0x6a>;
+
+ ti,battery-regulation-voltage = <4200000>;
+ ti,charge-current = <1000000>;
+ ti,termination-current = <50000>;
+};
diff --git a/Documentation/devicetree/bindings/power/bq25890.txt b/Documentation/devicetree/bindings/power/bq25890.txt
new file mode 100644
index 000000000000..c9dd17d142ad
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/bq25890.txt
@@ -0,0 +1,46 @@
+Binding for TI bq25890 Li-Ion Charger
+
+Required properties:
+- compatible: Should contain one of the following:
+ * "ti,bq25890"
+- reg: integer, i2c address of the device.
+- ti,battery-regulation-voltage: integer, maximum charging voltage (in uV);
+- ti,charge-current: integer, maximum charging current (in uA);
+- ti,termination-current: integer, charge will be terminated when current in
+ constant-voltage phase drops below this value (in uA);
+- ti,precharge-current: integer, maximum charge current during precharge
+ phase (in uA);
+- ti,minimum-sys-voltage: integer, when battery is charging and it is below
+ minimum system voltage, the system will be regulated above
+ minimum-sys-voltage setting (in uV);
+- ti,boost-voltage: integer, VBUS voltage level in boost mode (in uV);
+- ti,boost-max-current: integer, maximum allowed current draw in boost mode
+ (in uA).
+
+Optional properties:
+- ti,boost-low-freq: boolean, if present boost mode frequency will be 500kHz,
+ otherwise 1.5MHz;
+- ti,use-ilim-pin: boolean, if present the ILIM resistor will be used and the
+ input current will be the lower between the resistor setting and the IINLIM
+ register setting;
+- ti,thermal-regulation-threshold: integer, temperature above which the charge
+ current is lowered, to avoid overheating (in degrees Celsius). If omitted,
+ the default setting will be used (120 degrees);
+
+Example:
+
+bq25890 {
+ compatible = "ti,bq25890";
+ reg = <0x6a>;
+
+ ti,battery-regulation-voltage = <4200000>;
+ ti,charge-current = <1000000>;
+ ti,termination-current = <50000>;
+ ti,precharge-current = <128000>;
+ ti,minimum-sys-voltage = <3600000>;
+ ti,boost-voltage = <5000000>;
+ ti,boost-max-current = <1000000>;
+
+ ti,use-ilim-pin;
+ ti,thermal-regulation-threshold = <120>;
+};
diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt
index 74499e5033fc..0d5e7c978121 100644
--- a/Documentation/devicetree/bindings/power/opp.txt
+++ b/Documentation/devicetree/bindings/power/opp.txt
@@ -1,8 +1,19 @@
-* Generic OPP Interface
+Generic OPP (Operating Performance Points) Bindings
+----------------------------------------------------
-SoCs have a standard set of tuples consisting of frequency and
-voltage pairs that the device will support per voltage domain. These
-are called Operating Performance Points or OPPs.
+Devices work at voltage-current-frequency combinations and some implementations
+have the liberty of choosing these. These combinations are called Operating
+Performance Points aka OPPs. This document defines bindings for these OPPs
+applicable across wide range of devices. For illustration purpose, this document
+uses CPU as a device.
+
+This document contain multiple versions of OPP binding and only one of them
+should be used per device.
+
+Binding 1: operating-points
+============================
+
+This binding only supports voltage-frequency pairs.
Properties:
- operating-points: An array of 2-tuples items, and each item consists
@@ -23,3 +34,432 @@ cpu@0 {
198000 850000
>;
};
+
+
+Binding 2: operating-points-v2
+============================
+
+* Property: operating-points-v2
+
+Devices supporting OPPs must set their "operating-points-v2" property with
+phandle to a OPP table in their DT node. The OPP core will use this phandle to
+find the operating points for the device.
+
+Devices may want to choose OPP tables at runtime and so can provide a list of
+phandles here. But only *one* of them should be chosen at runtime. This must be
+accompanied by a corresponding "operating-points-names" property, to uniquely
+identify the OPP tables.
+
+If required, this can be extended for SoC vendor specfic bindings. Such bindings
+should be documented as Documentation/devicetree/bindings/power/<vendor>-opp.txt
+and should have a compatible description like: "operating-points-v2-<vendor>".
+
+Optional properties:
+- operating-points-names: Names of OPP tables (required if multiple OPP
+ tables are present), to uniquely identify them. The same list must be present
+ for all the CPUs which are sharing clock/voltage rails and hence the OPP
+ tables.
+
+* OPP Table Node
+
+This describes the OPPs belonging to a device. This node can have following
+properties:
+
+Required properties:
+- compatible: Allow OPPs to express their compatibility. It should be:
+ "operating-points-v2".
+
+- OPP nodes: One or more OPP nodes describing voltage-current-frequency
+ combinations. Their name isn't significant but their phandle can be used to
+ reference an OPP.
+
+Optional properties:
+- opp-shared: Indicates that device nodes using this OPP Table Node's phandle
+ switch their DVFS state together, i.e. they share clock/voltage/current lines.
+ Missing property means devices have independent clock/voltage/current lines,
+ but they share OPP tables.
+
+- status: Marks the OPP table enabled/disabled.
+
+
+* OPP Node
+
+This defines voltage-current-frequency combinations along with other related
+properties.
+
+Required properties:
+- opp-hz: Frequency in Hz
+
+Optional properties:
+- opp-microvolt: voltage in micro Volts.
+
+ A single regulator's voltage is specified with an array of size one or three.
+ Single entry is for target voltage and three entries are for <target min max>
+ voltages.
+
+ Entries for multiple regulators must be present in the same order as
+ regulators are specified in device's DT node.
+
+- opp-microamp: The maximum current drawn by the device in microamperes
+ considering system specific parameters (such as transients, process, aging,
+ maximum operating temperature range etc.) as necessary. This may be used to
+ set the most efficient regulator operating mode.
+
+ Should only be set if opp-microvolt is set for the OPP.
+
+ Entries for multiple regulators must be present in the same order as
+ regulators are specified in device's DT node. If this property isn't required
+ for few regulators, then this should be marked as zero for them. If it isn't
+ required for any regulator, then this property need not be present.
+
+- clock-latency-ns: Specifies the maximum possible transition latency (in
+ nanoseconds) for switching to this OPP from any other OPP.
+
+- turbo-mode: Marks the OPP to be used only for turbo modes. Turbo mode is
+ available on some platforms, where the device can run over its operating
+ frequency for a short duration of time limited by the device's power, current
+ and thermal limits.
+
+- opp-suspend: Marks the OPP to be used during device suspend. Only one OPP in
+ the table should have this.
+
+- status: Marks the node enabled/disabled.
+
+Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together.
+
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ clocks = <&clk_controller 0>;
+ clock-names = "cpu";
+ cpu-supply = <&cpu_supply0>;
+ operating-points-v2 = <&cpu0_opp_table>;
+ };
+
+ cpu@1 {
+ compatible = "arm,cortex-a9";
+ reg = <1>;
+ next-level-cache = <&L2>;
+ clocks = <&clk_controller 0>;
+ clock-names = "cpu";
+ cpu-supply = <&cpu_supply0>;
+ operating-points-v2 = <&cpu0_opp_table>;
+ };
+ };
+
+ cpu0_opp_table: opp_table0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp00 {
+ opp-hz = <1000000000>;
+ opp-microvolt = <970000 975000 985000>;
+ opp-microamp = <70000>;
+ clock-latency-ns = <300000>;
+ opp-suspend;
+ };
+ opp01 {
+ opp-hz = <1100000000>;
+ opp-microvolt = <980000 1000000 1010000>;
+ opp-microamp = <80000>;
+ clock-latency-ns = <310000>;
+ };
+ opp02 {
+ opp-hz = <1200000000>;
+ opp-microvolt = <1025000>;
+ clock-latency-ns = <290000>;
+ turbo-mode;
+ };
+ };
+};
+
+Example 2: Single cluster, Quad-core Qualcom-krait, switches DVFS states
+independently.
+
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "qcom,krait";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ clocks = <&clk_controller 0>;
+ clock-names = "cpu";
+ cpu-supply = <&cpu_supply0>;
+ operating-points-v2 = <&cpu_opp_table>;
+ };
+
+ cpu@1 {
+ compatible = "qcom,krait";
+ reg = <1>;
+ next-level-cache = <&L2>;
+ clocks = <&clk_controller 1>;
+ clock-names = "cpu";
+ cpu-supply = <&cpu_supply1>;
+ operating-points-v2 = <&cpu_opp_table>;
+ };
+
+ cpu@2 {
+ compatible = "qcom,krait";
+ reg = <2>;
+ next-level-cache = <&L2>;
+ clocks = <&clk_controller 2>;
+ clock-names = "cpu";
+ cpu-supply = <&cpu_supply2>;
+ operating-points-v2 = <&cpu_opp_table>;
+ };
+
+ cpu@3 {
+ compatible = "qcom,krait";
+ reg = <3>;
+ next-level-cache = <&L2>;
+ clocks = <&clk_controller 3>;
+ clock-names = "cpu";
+ cpu-supply = <&cpu_supply3>;
+ operating-points-v2 = <&cpu_opp_table>;
+ };
+ };
+
+ cpu_opp_table: opp_table {
+ compatible = "operating-points-v2";
+
+ /*
+ * Missing opp-shared property means CPUs switch DVFS states
+ * independently.
+ */
+
+ opp00 {
+ opp-hz = <1000000000>;
+ opp-microvolt = <970000 975000 985000>;
+ opp-microamp = <70000>;
+ clock-latency-ns = <300000>;
+ opp-suspend;
+ };
+ opp01 {
+ opp-hz = <1100000000>;
+ opp-microvolt = <980000 1000000 1010000>;
+ opp-microamp = <80000>;
+ clock-latency-ns = <310000>;
+ };
+ opp02 {
+ opp-hz = <1200000000>;
+ opp-microvolt = <1025000>;
+ opp-microamp = <90000;
+ lock-latency-ns = <290000>;
+ turbo-mode;
+ };
+ };
+};
+
+Example 3: Dual-cluster, Dual-core per cluster. CPUs within a cluster switch
+DVFS state together.
+
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "arm,cortex-a7";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ clocks = <&clk_controller 0>;
+ clock-names = "cpu";
+ cpu-supply = <&cpu_supply0>;
+ operating-points-v2 = <&cluster0_opp>;
+ };
+
+ cpu@1 {
+ compatible = "arm,cortex-a7";
+ reg = <1>;
+ next-level-cache = <&L2>;
+ clocks = <&clk_controller 0>;
+ clock-names = "cpu";
+ cpu-supply = <&cpu_supply0>;
+ operating-points-v2 = <&cluster0_opp>;
+ };
+
+ cpu@100 {
+ compatible = "arm,cortex-a15";
+ reg = <100>;
+ next-level-cache = <&L2>;
+ clocks = <&clk_controller 1>;
+ clock-names = "cpu";
+ cpu-supply = <&cpu_supply1>;
+ operating-points-v2 = <&cluster1_opp>;
+ };
+
+ cpu@101 {
+ compatible = "arm,cortex-a15";
+ reg = <101>;
+ next-level-cache = <&L2>;
+ clocks = <&clk_controller 1>;
+ clock-names = "cpu";
+ cpu-supply = <&cpu_supply1>;
+ operating-points-v2 = <&cluster1_opp>;
+ };
+ };
+
+ cluster0_opp: opp_table0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp00 {
+ opp-hz = <1000000000>;
+ opp-microvolt = <970000 975000 985000>;
+ opp-microamp = <70000>;
+ clock-latency-ns = <300000>;
+ opp-suspend;
+ };
+ opp01 {
+ opp-hz = <1100000000>;
+ opp-microvolt = <980000 1000000 1010000>;
+ opp-microamp = <80000>;
+ clock-latency-ns = <310000>;
+ };
+ opp02 {
+ opp-hz = <1200000000>;
+ opp-microvolt = <1025000>;
+ opp-microamp = <90000>;
+ clock-latency-ns = <290000>;
+ turbo-mode;
+ };
+ };
+
+ cluster1_opp: opp_table1 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp10 {
+ opp-hz = <1300000000>;
+ opp-microvolt = <1045000 1050000 1055000>;
+ opp-microamp = <95000>;
+ clock-latency-ns = <400000>;
+ opp-suspend;
+ };
+ opp11 {
+ opp-hz = <1400000000>;
+ opp-microvolt = <1075000>;
+ opp-microamp = <100000>;
+ clock-latency-ns = <400000>;
+ };
+ opp12 {
+ opp-hz = <1500000000>;
+ opp-microvolt = <1010000 1100000 1110000>;
+ opp-microamp = <95000>;
+ clock-latency-ns = <400000>;
+ turbo-mode;
+ };
+ };
+};
+
+Example 4: Handling multiple regulators
+
+/ {
+ cpus {
+ cpu@0 {
+ compatible = "arm,cortex-a7";
+ ...
+
+ cpu-supply = <&cpu_supply0>, <&cpu_supply1>, <&cpu_supply2>;
+ operating-points-v2 = <&cpu0_opp_table>;
+ };
+ };
+
+ cpu0_opp_table: opp_table0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp00 {
+ opp-hz = <1000000000>;
+ opp-microvolt = <970000>, /* Supply 0 */
+ <960000>, /* Supply 1 */
+ <960000>; /* Supply 2 */
+ opp-microamp = <70000>, /* Supply 0 */
+ <70000>, /* Supply 1 */
+ <70000>; /* Supply 2 */
+ clock-latency-ns = <300000>;
+ };
+
+ /* OR */
+
+ opp00 {
+ opp-hz = <1000000000>;
+ opp-microvolt = <970000 975000 985000>, /* Supply 0 */
+ <960000 965000 975000>, /* Supply 1 */
+ <960000 965000 975000>; /* Supply 2 */
+ opp-microamp = <70000>, /* Supply 0 */
+ <70000>, /* Supply 1 */
+ <70000>; /* Supply 2 */
+ clock-latency-ns = <300000>;
+ };
+
+ /* OR */
+
+ opp00 {
+ opp-hz = <1000000000>;
+ opp-microvolt = <970000 975000 985000>, /* Supply 0 */
+ <960000 965000 975000>, /* Supply 1 */
+ <960000 965000 975000>; /* Supply 2 */
+ opp-microamp = <70000>, /* Supply 0 */
+ <0>, /* Supply 1 doesn't need this */
+ <70000>; /* Supply 2 */
+ clock-latency-ns = <300000>;
+ };
+ };
+};
+
+Example 5: Multiple OPP tables
+
+/ {
+ cpus {
+ cpu@0 {
+ compatible = "arm,cortex-a7";
+ ...
+
+ cpu-supply = <&cpu_supply>
+ operating-points-v2 = <&cpu0_opp_table_slow>, <&cpu0_opp_table_fast>;
+ operating-points-names = "slow", "fast";
+ };
+ };
+
+ cpu0_opp_table_slow: opp_table_slow {
+ compatible = "operating-points-v2";
+ status = "okay";
+ opp-shared;
+
+ opp00 {
+ opp-hz = <600000000>;
+ ...
+ };
+
+ opp01 {
+ opp-hz = <800000000>;
+ ...
+ };
+ };
+
+ cpu0_opp_table_fast: opp_table_fast {
+ compatible = "operating-points-v2";
+ status = "okay";
+ opp-shared;
+
+ opp10 {
+ opp-hz = <1000000000>;
+ ...
+ };
+
+ opp11 {
+ opp-hz = <1100000000>;
+ ...
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/power/rt9455_charger.txt b/Documentation/devicetree/bindings/power/rt9455_charger.txt
new file mode 100644
index 000000000000..5d9ad5cf2c5a
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/rt9455_charger.txt
@@ -0,0 +1,48 @@
+Binding for Richtek rt9455 battery charger
+
+Required properties:
+- compatible: it should contain one of the following:
+ "richtek,rt9455".
+- reg: integer, i2c address of the device.
+- interrupt-parent: the phandle for the interrupt controller that
+ services interrupts for this device.
+- interrupts: interrupt mapping for GPIO IRQ, it should be
+ configured with IRQ_TYPE_LEVEL_LOW flag.
+- richtek,output-charge-current: integer, output current from the charger to the
+ battery, in uA.
+- richtek,end-of-charge-percentage: integer, percent of the output charge current.
+ When the current in constant-voltage phase drops
+ below output_charge_current x end-of-charge-percentage,
+ charge is terminated.
+- richtek,battery-regulation-voltage: integer, maximum battery voltage in uV.
+- richtek,boost-output-voltage: integer, maximum voltage provided to consumer
+ devices, when the charger is in boost mode, in uV.
+
+Optional properties:
+- richtek,min-input-voltage-regulation: integer, input voltage level in uV, used to
+ decrease voltage level when the over current
+ of the input power source occurs.
+ This prevents input voltage drop due to insufficient
+ current provided by the power source.
+ Default: 4500000 uV (4.5V)
+- richtek,avg-input-current-regulation: integer, input current value in uA drained by the
+ charger from the power source.
+ Default: 500000 uA (500mA)
+
+Example:
+
+rt9455@22 {
+ compatible = "richtek,rt9455";
+ reg = <0x22>;
+
+ interrupt-parent = <&gpio1>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+
+ richtek,output-charge-current = <500000>;
+ richtek,end-of-charge-percentage = <10>;
+ richtek,battery-regulation-voltage = <4200000>;
+ richtek,boost-output-voltage = <5050000>;
+
+ richtek,min-input-voltage-regulation = <4500000>;
+ richtek,avg-input-current-regulation = <500000>;
+};
diff --git a/Documentation/devicetree/bindings/power/twl-charger.txt b/Documentation/devicetree/bindings/power/twl-charger.txt
index d5c706216df5..3b4ea1b73b38 100644
--- a/Documentation/devicetree/bindings/power/twl-charger.txt
+++ b/Documentation/devicetree/bindings/power/twl-charger.txt
@@ -1,5 +1,15 @@
TWL BCI (Battery Charger Interface)
+The battery charger needs to interact with the USB phy in order
+to know when charging is permissible, and when there is a connection
+or disconnection.
+
+The choice of phy cannot be configured at a hardware level, so there
+is no value in explicit configuration in device-tree. Rather
+if there is a sibling of the BCI node which is compatible with
+"ti,twl4030-usb", then that is used to determine when and how
+use USB power for charging.
+
Required properties:
- compatible:
- "ti,twl4030-bci"
diff --git a/Documentation/devicetree/bindings/power_supply/max17042_battery.txt b/Documentation/devicetree/bindings/power_supply/max17042_battery.txt
index 5bc9b685cf8a..3f3894aaeebc 100644
--- a/Documentation/devicetree/bindings/power_supply/max17042_battery.txt
+++ b/Documentation/devicetree/bindings/power_supply/max17042_battery.txt
@@ -9,10 +9,23 @@ Optional properties :
(datasheet-recommended value is 10000).
Defining this property enables current-sense functionality.
+Optional threshold properties :
+ If skipped the condition won't be reported.
+ - maxim,cold-temp : Temperature threshold to report battery
+ as cold (in tenths of degree Celsius).
+ - maxim,over-heat-temp : Temperature threshold to report battery
+ as over heated (in tenths of degree Celsius).
+ - maxim,dead-volt : Voltage threshold to report battery
+ as dead (in mV).
+ - maxim,over-volt : Voltage threshold to report battery
+ as over voltage (in mV).
+
Example:
battery-charger@36 {
compatible = "maxim,max17042";
reg = <0x36>;
maxim,rsns-microohm = <10000>;
+ maxim,over-heat-temp = <600>;
+ maxim,over-volt = <4300>;
};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/fman.txt b/Documentation/devicetree/bindings/powerpc/fsl/fman.txt
index edda55f74004..1fc5328c0651 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/fman.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/fman.txt
@@ -189,6 +189,19 @@ PROPERTIES
Definition: There is one reg region describing the port
configuration registers.
+- fsl,fman-10g-port
+ Usage: optional
+ Value type: boolean
+ Definition: The default port rate is 1G.
+ If this property exists, the port is s 10G port.
+
+- fsl,fman-best-effort-port
+ Usage: optional
+ Value type: boolean
+ Definition: Can be defined only if 10G-support is set.
+ This property marks a best-effort 10G port (10G port that
+ may not be capable of line rate).
+
EXAMPLE
port@a8000 {
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/guts.txt b/Documentation/devicetree/bindings/powerpc/fsl/guts.txt
index 7f150b5012cc..b71b2039e112 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/guts.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/guts.txt
@@ -9,6 +9,11 @@ Required properties:
- compatible : Should define the compatible device type for
global-utilities.
+ Possible compatibles:
+ "fsl,qoriq-device-config-1.0"
+ "fsl,qoriq-device-config-2.0"
+ "fsl,<chip>-device-config"
+ "fsl,<chip>-guts"
- reg : Offset and length of the register set for the device.
Recommended properties:
diff --git a/Documentation/devicetree/bindings/regulator/max8973-regulator.txt b/Documentation/devicetree/bindings/regulator/max8973-regulator.txt
index 4f15d8a1bfd0..55efb24e5683 100644
--- a/Documentation/devicetree/bindings/regulator/max8973-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/max8973-regulator.txt
@@ -2,12 +2,30 @@
Required properties:
-- compatible: must be "maxim,max8973"
+- compatible: must be one of following:
+ "maxim,max8973"
+ "maxim,max77621".
- reg: the i2c slave address of the regulator. It should be 0x1b.
Any standard regulator properties can be used to configure the single max8973
DCDC.
+Optional properties:
+
+-maxim,externally-enable: boolean, externally control the regulator output
+ enable/disable.
+-maxim,enable-gpio: GPIO for enable control. If the valid GPIO is provided
+ then externally enable control will be considered.
+-maxim,dvs-gpio: GPIO which is connected to DVS pin of device.
+-maxim,dvs-default-state: Default state of GPIO during initialisation.
+ 1 for HIGH and 0 for LOW.
+-maxim,enable-remote-sense: boolean, enable reote sense.
+-maxim,enable-falling-slew-rate: boolean, enable falling slew rate.
+-maxim,enable-active-discharge: boolean: enable active discharge.
+-maxim,enable-frequency-shift: boolean, enable 9% frequency shift.
+-maxim,enable-bias-control: boolean, enable bias control. By enabling this
+ startup delay can be reduce to 20us from 220us.
+
Example:
max8973@1b {
diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt
new file mode 100644
index 000000000000..75b4604bad07
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt
@@ -0,0 +1,121 @@
+Qualcomm SPMI Regulators
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,pm8841-regulators"
+ "qcom,pm8916-regulators"
+ "qcom,pm8941-regulators"
+
+- interrupts:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: List of OCP interrupts.
+
+- interrupt-names:
+ Usage: required if 'interrupts' property present
+ Value type: <string-array>
+ Definition: List of strings defining the names of the
+ interrupts in the 'interrupts' property 1-to-1.
+ Supported values are "ocp-<regulator_name>", where
+ <regulator_name> corresponds to a voltage switch
+ type regulator.
+
+- vdd_s1-supply:
+- vdd_s2-supply:
+- vdd_s3-supply:
+- vdd_s4-supply:
+- vdd_s5-supply:
+- vdd_s6-supply:
+- vdd_s7-supply:
+- vdd_s8-supply:
+ Usage: optional (pm8841 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_s4-supply:
+- vdd_l1_l3-supply:
+- vdd_l2-supply:
+- vdd_l4_l5_l6-supply:
+- vdd_l7-supply:
+- vdd_l8_l11_l14_l15_l16-supply:
+- vdd_l9_l10_l12_l13_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_lvs_1_2_3-supply:
+- vdd_l4_l11-supply:
+- vdd_l5_l7-supply:
+- vdd_l6_l12_l14_l15-supply:
+- vdd_l8_l16_l18_19-supply:
+- vdd_l9_l10_l17_l22-supply:
+- vdd_l13_l20_l23_l24-supply:
+- vdd_l21-supply:
+- vin_5vs-supply:
+ Usage: optional (pm8941 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.
+
+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, 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,
+ mvs1, mvs2
+
+The content of each sub-node is defined by the standard binding for regulators -
+see regulator.txt - with additional custom properties described below:
+
+- regulator-initial-mode:
+ Usage: optional
+ Value type: <u32>
+ Descrption: 1 = Set initial mode to high power mode (HPM), also referred
+ to as NPM. HPM consumes more ground current than LPM, but
+ it can source significantly higher load current. HPM is not
+ available on boost type regulators. For voltage switch type
+ regulators, HPM implies that over current protection and
+ soft start are active all the time. 0 = Set initial mode to
+ low power mode (LPM).
+
+Example:
+
+ regulators {
+ compatible = "qcom,pm8941-regulators";
+ vdd_l1_l3-supply = <&s1>;
+
+ s1: s1 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1400000>;
+ };
+
+ ...
+
+ l1: l1 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ ....
+ };
diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
index abb26b58c83e..db88feb28c03 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -7,18 +7,20 @@ Optional properties:
- regulator-microvolt-offset: Offset applied to voltages to compensate for voltage drops
- regulator-min-microamp: smallest current consumers may set
- regulator-max-microamp: largest current consumers may set
+- regulator-input-current-limit-microamp: maximum input current regulator allows
- regulator-always-on: boolean, regulator should never be disabled
- regulator-boot-on: bootloader/firmware enabled regulator
- regulator-allow-bypass: allow the regulator to go into bypass mode
- <name>-supply: phandle to the parent supply/regulator node
- regulator-ramp-delay: ramp delay for regulator(in uV/uS)
For hardware which supports disabling ramp rate, it should be explicitly
- intialised to zero (regulator-ramp-delay = <0>) for disabling ramp delay.
+ initialised to zero (regulator-ramp-delay = <0>) for disabling ramp delay.
- regulator-enable-ramp-delay: The time taken, in microseconds, for the supply
rail to reach the target voltage, plus/minus whatever tolerance the board
design requires. This property describes the total system ramp time
required due to the combination of internal ramping of the regulator itself,
and board design issues such as trace capacitance and load on the supply.
+- regulator-soft-start: Enable soft start so that voltage ramps slowly
- regulator-state-mem sub-root node for Suspend-to-RAM mode
: suspend to memory, the device goes to sleep, but all data stored in memory,
only some external interrupt can wake the device.
@@ -37,6 +39,9 @@ Optional properties:
- regulator-initial-mode: initial operating mode. The set of possible operating
modes depends on the capabilities of every hardware so each device binding
documentation explains which values the regulator supports.
+- regulator-system-load: Load in uA present on regulator that is not captured by
+ any consumer request.
+- regulator-pull-down: Enable pull down resistor when the regulator is disabled.
Deprecated properties:
- regulator-compatible: If a regulator chip contains multiple
diff --git a/Documentation/devicetree/bindings/reset/berlin,reset.txt b/Documentation/devicetree/bindings/reset/berlin,reset.txt
new file mode 100644
index 000000000000..514fee098b4b
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/berlin,reset.txt
@@ -0,0 +1,23 @@
+Marvell Berlin reset controller
+===============================
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+The reset controller node must be a sub-node of the chip controller
+node on Berlin SoCs.
+
+Required properties:
+- compatible: should be "marvell,berlin2-reset"
+- #reset-cells: must be set to 2
+
+Example:
+
+chip_rst: reset {
+ compatible = "marvell,berlin2-reset";
+ #reset-cells = <2>;
+};
+
+&usb_phy0 {
+ resets = <&chip_rst 0x104 12>;
+};
diff --git a/Documentation/devicetree/bindings/reset/brcm,bcm63138-pmb.txt b/Documentation/devicetree/bindings/reset/brcm,bcm63138-pmb.txt
new file mode 100644
index 000000000000..a98872d27872
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/brcm,bcm63138-pmb.txt
@@ -0,0 +1,19 @@
+Broadcom BCM63138 Processor Monitor Bus binding
+===============================================
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Require properties:
+
+- compatible: must be "brcm,bcm63138-pmb"
+- reg: base register address and size for this bus controller
+- #reset-cells: must be 2 first cell is the address within the bus instance designated
+ by the phandle, and the second is the number of zones for this peripheral
+
+Example:
+ pmb0: reset-controller@4800c0 {
+ compatible = "brcm,bcm63138-pmb";
+ reg = <0x4800c0 0x10>;
+ #reset-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/rtc/haoyu,hym8563.txt b/Documentation/devicetree/bindings/rtc/haoyu,hym8563.txt
index 5c199ee044cb..a8934fe2ab4c 100644
--- a/Documentation/devicetree/bindings/rtc/haoyu,hym8563.txt
+++ b/Documentation/devicetree/bindings/rtc/haoyu,hym8563.txt
@@ -6,11 +6,11 @@ as well as a clock output of up to 32kHz.
Required properties:
- compatible: should be: "haoyu,hym8563"
- reg: i2c address
-- interrupts: rtc alarm/event interrupt
- #clock-cells: the value should be 0
Optional properties:
- clock-output-names: From common clock binding
+- interrupts: rtc alarm/event interrupt
Example:
diff --git a/Documentation/devicetree/bindings/rtc/rtc-st-lpc.txt b/Documentation/devicetree/bindings/rtc/rtc-st-lpc.txt
new file mode 100644
index 000000000000..73407f502e4e
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/rtc-st-lpc.txt
@@ -0,0 +1,25 @@
+STMicroelectronics Low Power Controller (LPC) - RTC
+===================================================
+
+LPC currently supports Watchdog OR Real Time Clock functionality.
+
+[See: ../watchdog/st_lpc_wdt.txt for Watchdog options]
+
+Required properties
+
+- compatible : Must be one of: "st,stih407-lpc" "st,stih416-lpc"
+ "st,stih415-lpc" "st,stid127-lpc"
+- reg : LPC registers base address + size
+- interrupts : LPC interrupt line number and associated flags
+- clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt)
+- st,lpc-mode : The LPC can run either one of two modes ST_LPC_MODE_RTC [0] or
+ ST_LPC_MODE_WDT [1]. One (and only one) mode must be
+ selected.
+
+Example:
+ lpc@fde05000 {
+ compatible = "st,stih407-lpc";
+ reg = <0xfde05000 0x1000>;
+ clocks = <&clk_s_d3_flexgen CLK_LPC_0>;
+ st,lpc-mode = <ST_LPC_MODE_RTC>;
+ };
diff --git a/Documentation/devicetree/bindings/rtc/s3c-rtc.txt b/Documentation/devicetree/bindings/rtc/s3c-rtc.txt
index ab757b84daa7..ac2fcd6ff4b8 100644
--- a/Documentation/devicetree/bindings/rtc/s3c-rtc.txt
+++ b/Documentation/devicetree/bindings/rtc/s3c-rtc.txt
@@ -6,7 +6,8 @@ Required properties:
* "samsung,s3c2416-rtc" - for controllers compatible with s3c2416 rtc.
* "samsung,s3c2443-rtc" - for controllers compatible with s3c2443 rtc.
* "samsung,s3c6410-rtc" - for controllers compatible with s3c6410 rtc.
- * "samsung,exynos3250-rtc" - for controllers compatible with exynos3250 rtc.
+ * "samsung,exynos3250-rtc" - (deprecated) for controllers compatible with
+ exynos3250 rtc (use "samsung,s3c6410-rtc").
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: Two interrupt numbers to the cpu should be specified. First
diff --git a/Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt b/Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt
new file mode 100644
index 000000000000..4163e7eb7763
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt
@@ -0,0 +1,10 @@
+* ARM SBSA defined generic UART
+This UART uses a subset of the PL011 registers and consequently lives
+in the PL011 driver. It's baudrate and other communication parameters
+cannot be adjusted at runtime, so it lacks a clock specifier here.
+
+Required properties:
+- compatible: must be "arm,sbsa-uart"
+- reg: exactly one register range
+- interrupts: exactly one interrupt specifier
+- current-speed: the (fixed) baud rate set by the firmware
diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt
index 44152261e5c5..8d63f1da07aa 100644
--- a/Documentation/devicetree/bindings/serial/mtk-uart.txt
+++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt
@@ -14,7 +14,14 @@ Required properties:
- interrupts: A single interrupt specifier.
-- clocks: Clock driving the hardware.
+- clocks : Must contain an entry for each entry in clock-names.
+ See ../clocks/clock-bindings.txt for details.
+- clock-names:
+ - "baud": The clock the baudrate is derived from
+ - "bus": The bus clock for register accesses (optional)
+
+For compatibility with older device trees an unnamed clock is used for the
+baud clock if the baudclk does not exist. Do not use this for new designs.
Example:
@@ -22,5 +29,6 @@ Example:
compatible = "mediatek,mt6589-uart", "mediatek,mt6577-uart";
reg = <0x11006000 0x400>;
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&uart_clk>;
+ clocks = <&uart_clk>, <&bus_clk>;
+ clock-names = "baud", "bus";
};
diff --git a/Documentation/devicetree/bindings/serial/nxp,lpc1850-uart.txt b/Documentation/devicetree/bindings/serial/nxp,lpc1850-uart.txt
new file mode 100644
index 000000000000..04e23e63ee4f
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/nxp,lpc1850-uart.txt
@@ -0,0 +1,28 @@
+* NXP LPC1850 UART
+
+Required properties:
+- compatible : "nxp,lpc1850-uart", "ns16550a".
+- reg : offset and length of the register set for the device.
+- interrupts : should contain uart interrupt.
+- clocks : phandle to the input clocks.
+- clock-names : required elements: "uartclk", "reg".
+
+Optional properties:
+- dmas : Two or more DMA channel specifiers following the
+ convention outlined in bindings/dma/dma.txt
+- dma-names : Names for the dma channels, if present. There must
+ be at least one channel named "tx" for transmit
+ and named "rx" for receive.
+
+Since it's also possible to also use the of_serial.c driver all
+parameters from 8250.txt also apply but are optional.
+
+Example:
+uart0: serial@40081000 {
+ compatible = "nxp,lpc1850-uart", "ns16550a";
+ reg = <0x40081000 0x1000>;
+ reg-shift = <2>;
+ interrupts = <24>;
+ clocks = <&ccu2 CLK_APB0_UART0>, <&ccu1 CLK_CPU_UART0>;
+ clock-names = "uartclk", "reg";
+};
diff --git a/Documentation/devicetree/bindings/serial/nxp,sc16is7xx.txt b/Documentation/devicetree/bindings/serial/nxp,sc16is7xx.txt
index 246c795668dc..fbfe53635a3a 100644
--- a/Documentation/devicetree/bindings/serial/nxp,sc16is7xx.txt
+++ b/Documentation/devicetree/bindings/serial/nxp,sc16is7xx.txt
@@ -1,4 +1,5 @@
* NXP SC16IS7xx advanced Universal Asynchronous Receiver-Transmitter (UART)
+* i2c as bus
Required properties:
- compatible: Should be one of the following:
@@ -31,3 +32,39 @@ Example:
gpio-controller;
#gpio-cells = <2>;
};
+
+* spi as bus
+
+Required properties:
+- compatible: Should be one of the following:
+ - "nxp,sc16is740" for NXP SC16IS740,
+ - "nxp,sc16is741" for NXP SC16IS741,
+ - "nxp,sc16is750" for NXP SC16IS750,
+ - "nxp,sc16is752" for NXP SC16IS752,
+ - "nxp,sc16is760" for NXP SC16IS760,
+ - "nxp,sc16is762" for NXP SC16IS762.
+- reg: SPI chip select number.
+- interrupt-parent: The phandle for the interrupt controller that
+ services interrupts for this IC.
+- interrupts: Specifies the interrupt source of the parent interrupt
+ controller. The format of the interrupt specifier depends on the
+ parent interrupt controller.
+- clocks: phandle to the IC source clock.
+
+Optional properties:
+- gpio-controller: Marks the device node as a GPIO controller.
+- #gpio-cells: Should be two. The first cell is the GPIO number and
+ the second cell is used to specify the GPIO polarity:
+ 0 = active high,
+ 1 = active low.
+
+Example:
+ sc16is750: sc16is750@0 {
+ compatible = "nxp,sc16is750";
+ reg = <0>;
+ clocks = <&clk20m>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/serial/pl011.txt b/Documentation/devicetree/bindings/serial/pl011.txt
index ba3ecb8cb5a1..cbae3d9a0278 100644
--- a/Documentation/devicetree/bindings/serial/pl011.txt
+++ b/Documentation/devicetree/bindings/serial/pl011.txt
@@ -1,7 +1,7 @@
* ARM AMBA Primecell PL011 serial UART
Required properties:
-- compatible: must be "arm,primecell", "arm,pl011"
+- compatible: must be "arm,primecell", "arm,pl011", "zte,zx296702-uart"
- reg: exactly one register range with length 0x1000
- interrupts: exactly one interrupt specifier
diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
index ae73bb0e9ad9..e84b13a8eda3 100644
--- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
+++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
@@ -29,6 +29,7 @@ Required properties:
- "renesas,scifa" for generic SCIFA compatible UART.
- "renesas,scifb" for generic SCIFB compatible UART.
- "renesas,hscif" for generic HSCIF compatible UART.
+ - "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
@@ -44,6 +45,11 @@ Required properties:
Note: Each enabled SCIx UART should have an alias correctly numbered in the
"aliases" node.
+Optional properties:
+ - dmas: Must contain a list of two references to DMA specifiers, one for
+ transmission, and one for reception.
+ - dma-names: Must contain a list of two DMA names, "tx" and "rx".
+
Example:
aliases {
serial0 = &scifa0;
@@ -56,4 +62,6 @@ Example:
interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7790_CLK_SCIFA0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x21>, <&dmac0 0x22>;
+ dma-names = "tx", "rx";
};
diff --git a/Documentation/devicetree/bindings/serial/sirf-uart.txt b/Documentation/devicetree/bindings/serial/sirf-uart.txt
index f0c39261c5d4..67e2a0aeb042 100644
--- a/Documentation/devicetree/bindings/serial/sirf-uart.txt
+++ b/Documentation/devicetree/bindings/serial/sirf-uart.txt
@@ -2,8 +2,7 @@
Required properties:
- compatible : Should be "sirf,prima2-uart", "sirf, prima2-usp-uart",
- "sirf,atlas7-uart" or "sirf,atlas7-bt-uart" which means
- uart located in BT module and used for BT.
+ "sirf,atlas7-uart" or "sirf,atlas7-usp-uart".
- reg : Offset and length of the register set for the device
- interrupts : Should contain uart interrupt
- fifosize : Should define hardware rx/tx fifo size
@@ -33,15 +32,3 @@ usp@b0090000 {
rts-gpios = <&gpio 15 0>;
cts-gpios = <&gpio 46 0>;
};
-
-for uart use in BT module,
-uart6: uart@11000000 {
- cell-index = <6>;
- compatible = "sirf,atlas7-bt-uart", "sirf,atlas7-uart";
- reg = <0x11000000 0x1000>;
- interrupts = <0 100 0>;
- clocks = <&clks 138>, <&clks 140>, <&clks 141>;
- clock-names = "uart", "general", "noc";
- fifosize = <128>;
- status = "disabled";
-}
diff --git a/Documentation/devicetree/bindings/serial/uniphier-uart.txt b/Documentation/devicetree/bindings/serial/uniphier-uart.txt
new file mode 100644
index 000000000000..0b3892a7a528
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/uniphier-uart.txt
@@ -0,0 +1,23 @@
+UniPhier UART controller
+
+Required properties:
+- compatible: should be "socionext,uniphier-uart".
+- reg: offset and length of the register set for the device.
+- interrupts: a single interrupt specifier.
+- clocks: phandle to the input clock.
+
+Optional properties:
+- fifo-size: the RX/TX FIFO size. Defaults to 64 if not specified.
+
+Example:
+ aliases {
+ serial0 = &serial0;
+ };
+
+ serial0: serial@54006800 {
+ compatible = "socionext,uniphier-uart";
+ reg = <0x54006800 0x40>;
+ interrupts = <0 33 4>;
+ clocks = <&uart_clk>;
+ fifo-size = <64>;
+ };
diff --git a/Documentation/devicetree/bindings/soc/fsl/qman-portals.txt b/Documentation/devicetree/bindings/soc/fsl/qman-portals.txt
index 48c4dae5d6f9..47e46ccbc170 100644
--- a/Documentation/devicetree/bindings/soc/fsl/qman-portals.txt
+++ b/Documentation/devicetree/bindings/soc/fsl/qman-portals.txt
@@ -47,7 +47,7 @@ PROPERTIES
For additional details about the PAMU/LIODN binding(s) see pamu.txt
-- fsl,qman-channel-id
+- cell-index
Usage: Required
Value type: <u32>
Definition: The hardware index of the channel. This can also be
@@ -136,7 +136,7 @@ The example below shows a (P4080) QMan portals container/bus node with two porta
reg = <0x4000 0x4000>, <0x101000 0x1000>;
interrupts = <106 2 0 0>;
fsl,liodn = <3 4>;
- fsl,qman-channel-id = <1>;
+ cell-index = <1>;
fman0 {
fsl,liodn = <0x22>;
diff --git a/Documentation/devicetree/bindings/soc/sunxi/sram.txt b/Documentation/devicetree/bindings/soc/sunxi/sram.txt
new file mode 100644
index 000000000000..067698112f5f
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/sunxi/sram.txt
@@ -0,0 +1,72 @@
+Allwinnner SoC SRAM controllers
+-----------------------------------------------------
+
+The SRAM controller found on most Allwinner devices is represented by
+a regular node for the SRAM controller itself, with sub-nodes
+reprensenting the SRAM handled by the SRAM controller.
+
+Controller Node
+---------------
+
+Required properties:
+- compatible : "allwinner,sun4i-a10-sram-controller"
+- reg : sram controller register offset + length
+
+SRAM nodes
+----------
+
+Each SRAM is described using the mmio-sram bindings documented in
+Documentation/devicetree/bindings/misc/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
+once again the representation described in the mmio-sram binding.
+
+The valid sections compatible are:
+ - allwinner,sun4i-a10-sram-a3-a4
+ - allwinner,sun4i-a10-sram-d
+
+Devices using SRAM sections
+---------------------------
+
+Some devices need to request to the SRAM controller to map an SRAM for
+their exclusive use.
+
+The relationship between such a device and an SRAM section is
+expressed through the allwinner,sram property, that will take a
+phandle and an argument.
+
+This valid values for this argument are:
+ - 0: CPU
+ - 1: Device
+
+Example
+-------
+sram-controller@01c00000 {
+ compatible = "allwinner,sun4i-a10-sram-controller";
+ reg = <0x01c00000 0x30>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram_a: sram@00000000 {
+ compatible = "mmio-sram";
+ reg = <0x00000000 0xc000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00000000 0xc000>;
+
+ emac_sram: sram-section@8000 {
+ compatible = "allwinner,sun4i-a10-sram-a3-a4";
+ reg = <0x8000 0x4000>;
+ status = "disabled";
+ };
+ };
+};
+
+emac: ethernet@01c0b000 {
+ compatible = "allwinner,sun4i-a10-emac";
+ ...
+
+ allwinner,sram = <&emac_sram 1>;
+};
diff --git a/Documentation/devicetree/bindings/sound/adi,adau1701.txt b/Documentation/devicetree/bindings/sound/adi,adau1701.txt
index 547a49b56a62..0d1128ce2ea7 100644
--- a/Documentation/devicetree/bindings/sound/adi,adau1701.txt
+++ b/Documentation/devicetree/bindings/sound/adi,adau1701.txt
@@ -20,6 +20,8 @@ Optional properties:
pin configurations as described in the datasheet,
table 53. Note that the value of this property has
to be prefixed with '/bits/ 8'.
+ - avdd-supply: Power supply for AVDD, providing 3.3V
+ - dvdd-supply: Power supply for DVDD, providing 3.3V
Examples:
@@ -28,6 +30,8 @@ Examples:
compatible = "adi,adau1701";
reg = <0x34>;
reset-gpio = <&gpio 23 0>;
+ avdd-supply = <&vdd_3v3_reg>;
+ dvdd-supply = <&vdd_3v3_reg>;
adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>;
adi,pin-config = /bits/ 8 <0x4 0x7 0x5 0x5 0x4 0x4
0x4 0x4 0x4 0x4 0x4 0x4>;
diff --git a/Documentation/devicetree/bindings/sound/bt-sco.txt b/Documentation/devicetree/bindings/sound/bt-sco.txt
new file mode 100644
index 000000000000..29b8e5d40203
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/bt-sco.txt
@@ -0,0 +1,13 @@
+Bluetooth-SCO audio CODEC
+
+This device support generic Bluetooth SCO link.
+
+Required properties:
+
+ - compatible : "delta,dfbmcs320"
+
+Example:
+
+codec: bt_sco {
+ compatible = "delta,dfbmcs320";
+};
diff --git a/Documentation/devicetree/bindings/sound/gtm601.txt b/Documentation/devicetree/bindings/sound/gtm601.txt
new file mode 100644
index 000000000000..5efc8c068de0
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/gtm601.txt
@@ -0,0 +1,13 @@
+GTM601 UMTS modem audio interface CODEC
+
+This device has no configuration interface. Sample rate is fixed - 8kHz.
+
+Required properties:
+
+ - compatible : "option,gtm601"
+
+Example:
+
+codec: gtm601_codec {
+ compatible = "option,gtm601";
+};
diff --git a/Documentation/devicetree/bindings/sound/max98090.txt b/Documentation/devicetree/bindings/sound/max98090.txt
index aa802a274520..4e3be6682c98 100644
--- a/Documentation/devicetree/bindings/sound/max98090.txt
+++ b/Documentation/devicetree/bindings/sound/max98090.txt
@@ -18,6 +18,12 @@ Optional properties:
- maxim,dmic-freq: Frequency at which to clock DMIC
+- maxim,micbias: Micbias voltage applies to the analog mic, valid voltages value are:
+ 0 - 2.2v
+ 1 - 2.55v
+ 2 - 2.4v
+ 3 - 2.8v
+
Pins on the device (for linking into audio routes):
* MIC1
diff --git a/Documentation/devicetree/bindings/sound/mt8173-max98090.txt b/Documentation/devicetree/bindings/sound/mt8173-max98090.txt
new file mode 100644
index 000000000000..829bd26d17f8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mt8173-max98090.txt
@@ -0,0 +1,13 @@
+MT8173 with MAX98090 CODEC
+
+Required properties:
+- compatible : "mediatek,mt8173-max98090"
+- mediatek,audio-codec: the phandle of the MAX98090 audio codec
+
+Example:
+
+ sound {
+ compatible = "mediatek,mt8173-max98090";
+ mediatek,audio-codec = <&max98090>;
+ };
+
diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt
new file mode 100644
index 000000000000..61e98c976bd4
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt
@@ -0,0 +1,13 @@
+MT8173 with RT5650 RT5676 CODECS
+
+Required properties:
+- compatible : "mediatek,mt8173-rt5650-rt5676"
+- mediatek,audio-codec: the phandles of rt5650 and rt5676 codecs
+
+Example:
+
+ sound {
+ compatible = "mediatek,mt8173-rt5650-rt5676";
+ mediatek,audio-codec = <&rt5650 &rt5676>;
+ };
+
diff --git a/Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt b/Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt
new file mode 100644
index 000000000000..e302c7f43b95
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt
@@ -0,0 +1,45 @@
+Mediatek AFE PCM controller
+
+Required properties:
+- compatible = "mediatek,mt8173-afe-pcm";
+- reg: register location and size
+- interrupts: Should contain AFE interrupt
+- clock-names: should have these clock names:
+ "infra_sys_audio_clk",
+ "top_pdn_audio",
+ "top_pdn_aud_intbus",
+ "bck0",
+ "bck1",
+ "i2s0_m",
+ "i2s1_m",
+ "i2s2_m",
+ "i2s3_m",
+ "i2s3_b";
+
+Example:
+
+ afe: mt8173-afe-pcm@11220000 {
+ compatible = "mediatek,mt8173-afe-pcm";
+ reg = <0 0x11220000 0 0x1000>;
+ interrupts = <GIC_SPI 134 IRQ_TYPE_EDGE_FALLING>;
+ clocks = <&infracfg INFRA_AUDIO>,
+ <&topckgen TOP_AUDIO_SEL>,
+ <&topckgen TOP_AUD_INTBUS_SEL>,
+ <&topckgen TOP_APLL1_DIV0>,
+ <&topckgen TOP_APLL2_DIV0>,
+ <&topckgen TOP_I2S0_M_CK_SEL>,
+ <&topckgen TOP_I2S1_M_CK_SEL>,
+ <&topckgen TOP_I2S2_M_CK_SEL>,
+ <&topckgen TOP_I2S3_M_CK_SEL>,
+ <&topckgen TOP_I2S3_B_CK_SEL>;
+ clock-names = "infra_sys_audio_clk",
+ "top_pdn_audio",
+ "top_pdn_aud_intbus",
+ "bck0",
+ "bck1",
+ "i2s0_m",
+ "i2s1_m",
+ "i2s2_m",
+ "i2s3_m",
+ "i2s3_b";
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
new file mode 100644
index 000000000000..48129368d4d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
@@ -0,0 +1,60 @@
+* Qualcomm Technologies APQ8016 SBC ASoC machine driver
+
+This node models the Qualcomm Technologies APQ8016 SBC ASoC machine driver
+
+Required properties:
+
+- compatible : "qcom,apq8016-sbc-sndcard"
+
+- pinctrl-N : One property must exist for each entry in
+ pinctrl-names. See ../pinctrl/pinctrl-bindings.txt
+ for details of the property values.
+- pinctrl-names : Must contain a "default" entry.
+- reg : Must contain an address for each entry in reg-names.
+- reg-names : A list which must include the following entries:
+ * "mic-iomux"
+ * "spkr-iomux"
+- qcom,model : Name of the sound card.
+
+Dai-link subnode properties and subnodes:
+
+Required dai-link subnodes:
+
+- cpu : CPU sub-node
+- codec : CODEC sub-node
+
+Required CPU/CODEC subnodes properties:
+
+-link-name : Name of the dai link.
+-sound-dai : phandle and port of CPU/CODEC
+-capture-dai : phandle and port of CPU/CODEC
+
+Example:
+
+sound: sound {
+ compatible = "qcom,apq8016-sbc-sndcard";
+ reg = <0x07702000 0x4>, <0x07702004 0x4>;
+ reg-names = "mic-iomux", "spkr-iomux";
+ qcom,model = "DB410c";
+
+ /* I2S - Internal codec */
+ internal-dai-link@0 {
+ cpu { /* PRIMARY */
+ sound-dai = <&lpass MI2S_PRIMARY>;
+ };
+ codec {
+ sound-dai = <&wcd_codec 0>;
+ };
+ };
+
+ /* External Primary or External Secondary -ADV7533 HDMI */
+ external-dai-link@0 {
+ link-name = "ADV7533";
+ cpu { /* QUAT */
+ sound-dai = <&lpass MI2S_QUATERNARY>;
+ };
+ codec {
+ sound-dai = <&adv_bridge 0>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
index e00732dac939..21c648328be9 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
@@ -4,12 +4,21 @@ This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS).
Required properties:
-- compatible : "qcom,lpass-cpu"
+- compatible : "qcom,lpass-cpu" or "qcom,apq8016-lpass-cpu"
- clocks : Must contain an entry for each entry in clock-names.
- clock-names : A list which must include the following entries:
* "ahbix-clk"
* "mi2s-osr-clk"
* "mi2s-bit-clk"
+ : required clocks for "qcom,lpass-cpu-apq8016"
+ * "ahbix-clk"
+ * "mi2s-bit-clk0"
+ * "mi2s-bit-clk1"
+ * "mi2s-bit-clk2"
+ * "mi2s-bit-clk3"
+ * "pcnoc-mport-clk"
+ * "pcnoc-sway-clk"
+
- interrupts : Must contain an entry for each entry in
interrupt-names.
- interrupt-names : A list which must include the following entries:
@@ -22,6 +31,8 @@ Required properties:
- reg-names : A list which must include the following entries:
* "lpass-lpaif"
+
+
Optional properties:
- qcom,adsp : Phandle for the audio DSP node
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
index f316ce1f214a..b6b3a786855f 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -5,6 +5,7 @@ Required properties:
"renesas,rcar_sound-gen1" if generation1, and
"renesas,rcar_sound-gen2" if generation2
Examples with soctypes are:
+ - "renesas,rcar_sound-r8a7778" (R-Car M1A)
- "renesas,rcar_sound-r8a7790" (R-Car H2)
- "renesas,rcar_sound-r8a7791" (R-Car M2-W)
- reg : Should contain the register physical address.
@@ -47,7 +48,7 @@ DAI subnode properties:
Example:
-rcar_sound: rcar_sound@ec500000 {
+rcar_sound: sound@ec500000 {
#sound-dai-cells = <1>;
compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
reg = <0 0xec500000 0 0x1000>, /* SCU */
diff --git a/Documentation/devicetree/bindings/sound/rt5645.txt b/Documentation/devicetree/bindings/sound/rt5645.txt
new file mode 100644
index 000000000000..7cee1f518f59
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5645.txt
@@ -0,0 +1,72 @@
+RT5650/RT5645 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : One of "realtek,rt5645" or "realtek,rt5650".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+Optional properties:
+
+- hp-detect-gpios:
+ a GPIO spec for the external headphone detect pin. If jd-mode = 0,
+ we will get the JD status by getting the value of hp-detect-gpios.
+
+- realtek,in2-differential
+ Boolean. Indicate MIC2 input are differential, rather than single-ended.
+
+- realtek,dmic1-data-pin
+ 0: dmic1 is not used
+ 1: using IN2P pin as dmic1 data pin
+ 2: using GPIO6 pin as dmic1 data pin
+ 3: using GPIO10 pin as dmic1 data pin
+ 4: using GPIO12 pin as dmic1 data pin
+
+- realtek,dmic2-data-pin
+ 0: dmic2 is not used
+ 1: using IN2N pin as dmic2 data pin
+ 2: using GPIO5 pin as dmic2 data pin
+ 3: using GPIO11 pin as dmic2 data pin
+
+-- realtek,jd-mode : The JD mode of rt5645/rt5650
+ 0 : rt5645/rt5650 JD function is not used
+ 1 : Mode-0 (VDD=3.3V), two port jack detection
+ 2 : Mode-1 (VDD=3.3V), one port jack detection
+ 3 : Mode-2 (VDD=1.8V), one port jack detection
+
+Pins on the device (for linking into audio routes) for RT5645/RT5650:
+
+ * DMIC L1
+ * DMIC R1
+ * DMIC L2
+ * DMIC R2
+ * IN1P
+ * IN1N
+ * IN2P
+ * IN2N
+ * Haptic Generator
+ * HPOL
+ * HPOR
+ * LOUTL
+ * LOUTR
+ * PDM1L
+ * PDM1R
+ * SPOL
+ * SPOR
+
+Example:
+
+codec: rt5650@1a {
+ compatible = "realtek,rt5650";
+ reg = <0x1a>;
+ hp-detect-gpios = <&gpio 19 0>;
+ interrupt-parent = <&gpio>;
+ interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+ realtek,dmic-en = "true";
+ realtek,en-jd-func = "true";
+ realtek,jd-mode = <3>;
+}; \ No newline at end of file
diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt
index 740ff771aa8b..f07078997f87 100644
--- a/Documentation/devicetree/bindings/sound/rt5677.txt
+++ b/Documentation/devicetree/bindings/sound/rt5677.txt
@@ -18,6 +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,in1-differential
- realtek,in2-differential
@@ -70,6 +71,7 @@ rt5677 {
realtek,pow-ldo2-gpio =
<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+ realtek,reset-gpio = <&gpio TEGRA_GPIO(BB, 3) GPIO_ACTIVE_LOW>;
realtek,in1-differential = "true";
realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */
realtek,jd2-gpio = <3>; /* Enables Jack detection for GPIO6 */
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
index 73bf314f7240..cf3979eb3578 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-card.txt
@@ -16,7 +16,8 @@ Optional properties:
connection's sink, the second being the connection's
source.
- simple-audio-card,mclk-fs : Multiplication factor between stream rate and codec
- mclk.
+ mclk. When defined, mclk-fs property defined in
+ dai-link sub nodes are ignored.
- simple-audio-card,hp-det-gpio : Reference to GPIO that signals when
headphones are attached.
- simple-audio-card,mic-det-gpio : Reference to GPIO that signals when
@@ -55,6 +56,9 @@ Optional dai-link subnode properties:
dai-link uses bit clock inversion.
- frame-inversion : bool property. Add this if the
dai-link uses frame clock inversion.
+- mclk-fs : Multiplication factor between stream
+ rate and codec mclk, applied only for
+ the dai-link.
For backward compatibility the frame-master and bitclock-master
properties can be used as booleans in codec subnode to indicate if the
diff --git a/Documentation/devicetree/bindings/sound/tas2552.txt b/Documentation/devicetree/bindings/sound/tas2552.txt
index 55e2a0af5645..c49992c0b62a 100644
--- a/Documentation/devicetree/bindings/sound/tas2552.txt
+++ b/Documentation/devicetree/bindings/sound/tas2552.txt
@@ -14,6 +14,12 @@ Required properties:
Optional properties:
- enable-gpio - gpio pin to enable/disable the device
+tas2552 can receive it's reference clock via MCLK, BCLK, IVCLKIN pin or use the
+internal 1.8MHz. This CLKIN is used by the PLL. In addition to PLL, the PDM
+reference clock is also selectable: PLL, IVCLKIN, BCLK or MCLK.
+For system integration the dt-bindings/sound/tas2552.h header file provides
+defined values to selct and configure the PLL and PDM reference clocks.
+
Example:
tas2552: tas2552@41 {
diff --git a/Documentation/devicetree/bindings/sound/tas571x.txt b/Documentation/devicetree/bindings/sound/tas571x.txt
new file mode 100644
index 000000000000..0ac31d8d5ac4
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tas571x.txt
@@ -0,0 +1,41 @@
+Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers
+
+The codec is controlled through an I2C interface. It also has two other
+signals that can be wired up to GPIOs: reset (strongly recommended), and
+powerdown (optional).
+
+Required properties:
+
+- compatible: "ti,tas5711", "ti,tas5717", or "ti,tas5719"
+- reg: The I2C address of the device
+- #sound-dai-cells: must be equal to 0
+
+Optional properties:
+
+- reset-gpios: GPIO specifier for the TAS571x's active low reset line
+- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line
+- clocks: clock phandle for the MCLK input
+- clock-names: should be "mclk"
+- AVDD-supply: regulator phandle for the AVDD supply (all chips)
+- DVDD-supply: regulator phandle for the DVDD supply (all chips)
+- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719)
+- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719)
+- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719)
+- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711)
+- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711)
+- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711)
+- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711)
+
+Example:
+
+ tas5717: audio-codec@2a {
+ compatible = "ti,tas5717";
+ reg = <0x2a>;
+ #sound-dai-cells = <0>;
+
+ reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
+ pdn-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
+
+ clocks = <&clk_core CLK_I2S>;
+ clock-names = "mclk";
+ };
diff --git a/Documentation/devicetree/bindings/sound/wm8741.txt b/Documentation/devicetree/bindings/sound/wm8741.txt
index 74bda58c1bcf..a13315408719 100644
--- a/Documentation/devicetree/bindings/sound/wm8741.txt
+++ b/Documentation/devicetree/bindings/sound/wm8741.txt
@@ -10,9 +10,20 @@ Required properties:
- reg : the I2C address of the device for I2C, the chip select
number for SPI.
+Optional properties:
+
+ - diff-mode: Differential output mode configuration. Default value for field
+ DIFF in register R8 (MODE_CONTROL_2). If absent, the default is 0, shall be:
+ 0 = stereo
+ 1 = mono left
+ 2 = stereo reversed
+ 3 = mono right
+
Example:
codec: wm8741@1a {
compatible = "wlf,wm8741";
reg = <0x1a>;
+
+ diff-mode = <3>;
};
diff --git a/Documentation/devicetree/bindings/sound/zte,zx-i2s.txt b/Documentation/devicetree/bindings/sound/zte,zx-i2s.txt
new file mode 100644
index 000000000000..7e5aa6f6b5a1
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/zte,zx-i2s.txt
@@ -0,0 +1,44 @@
+ZTE ZX296702 I2S controller
+
+Required properties:
+ - compatible : Must be "zte,zx296702-i2s"
+ - reg : Must contain I2S core's registers location and length
+ - clocks : Pairs of phandle and specifier referencing the controller's clocks.
+ - clock-names: "tx" for the clock to the I2S interface.
+ - dmas: Pairs of phandle and specifier for the DMA channel that is used by
+ the core. The core expects two dma channels for transmit.
+ - dma-names : Must be "tx" and "rx"
+
+For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
+please check:
+ * resource-names.txt
+ * clock/clock-bindings.txt
+ * dma/dma.txt
+
+Example:
+ i2s0: i2s0@0b005000 {
+ #sound-dai-cells = <0>;
+ compatible = "zte,zx296702-i2s";
+ reg = <0x0b005000 0x1000>;
+ clocks = <&lsp0clk ZX296702_I2S0_DIV>;
+ clock-names = "tx";
+ interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma 5>, <&dma 6>;
+ dma-names = "tx", "rx";
+ status = "okay";
+ };
+
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "zx296702_snd";
+ 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 = <&i2s0>;
+ };
+
+ sndcodec: simple-audio-card,codec {
+ sound-dai = <&acodec>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/zte,zx-spdif.txt b/Documentation/devicetree/bindings/sound/zte,zx-spdif.txt
new file mode 100644
index 000000000000..989544ea6eb5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/zte,zx-spdif.txt
@@ -0,0 +1,28 @@
+ZTE ZX296702 SPDIF controller
+
+Required properties:
+ - compatible : Must be "zte,zx296702-spdif"
+ - reg : Must contain SPDIF core's registers location and length
+ - clocks : Pairs of phandle and specifier referencing the controller's clocks.
+ - clock-names: "tx" for the clock to the SPDIF interface.
+ - dmas: Pairs of phandle and specifier for the DMA channel that is used by
+ the core. The core expects one dma channel for transmit.
+ - dma-names : Must be "tx"
+
+For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
+please check:
+ * resource-names.txt
+ * clock/clock-bindings.txt
+ * dma/dma.txt
+
+Example:
+ spdif0: spdif0@0b004000 {
+ compatible = "zte,zx296702-spdif";
+ reg = <0x0b004000 0x1000>;
+ clocks = <&lsp0clk ZX296702_SPDIF0_DIV>;
+ clock-names = "tx";
+ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma 4>;
+ dma-names = "tx";
+ status = "okay";
+ };
diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt
index 4c388bb2f0a2..8f771441be60 100644
--- a/Documentation/devicetree/bindings/spi/sh-msiof.txt
+++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt
@@ -60,7 +60,7 @@ Example:
msiof0: spi@e6e20000 {
compatible = "renesas,msiof-r8a7791";
- reg = <0 0xe6e20000 0 0x0064>, <0 0xe7e20000 0 0x0064>;
+ reg = <0 0xe6e20000 0 0x0064>;
interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
dmas = <&dmac0 0x51>, <&dmac0 0x52>;
diff --git a/Documentation/devicetree/bindings/spi/spi-ath79.txt b/Documentation/devicetree/bindings/spi/spi-ath79.txt
new file mode 100644
index 000000000000..f1ad9c367532
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-ath79.txt
@@ -0,0 +1,24 @@
+Binding for Qualcomm Atheros AR7xxx/AR9xxx SPI controller
+
+Required properties:
+- compatible: has to be "qca,<soc-type>-spi", "qca,ar7100-spi" as fallback.
+- reg: Base address and size of the controllers memory area
+- clocks: phandle to the AHB clock.
+- clock-names: has to be "ahb".
+- #address-cells: <1>, as required by generic SPI binding.
+- #size-cells: <0>, also as required by generic SPI binding.
+
+Child nodes as per the generic SPI binding.
+
+Example:
+
+ spi@1F000000 {
+ compatible = "qca,ar9132-spi", "qca,ar7100-spi";
+ reg = <0x1F000000 0x10>;
+
+ clocks = <&pll 2>;
+ clock-names = "ahb";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
index 70af78a9185e..fa77f874e321 100644
--- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
+++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
@@ -1,7 +1,7 @@
ARM Freescale DSPI controller
Required properties:
-- compatible : "fsl,vf610-dspi"
+- compatible : "fsl,vf610-dspi", "fsl,ls1021a-v1.0-dspi", "fsl,ls2085a-dspi"
- reg : Offset and length of the register set for the device
- interrupts : Should contain SPI controller interrupt
- clocks: from common clock binding: handle to dspi clock.
diff --git a/Documentation/devicetree/bindings/spi/spi-orion.txt b/Documentation/devicetree/bindings/spi/spi-orion.txt
index 50c3a3de61c1..98bc69815eb3 100644
--- a/Documentation/devicetree/bindings/spi/spi-orion.txt
+++ b/Documentation/devicetree/bindings/spi/spi-orion.txt
@@ -1,7 +1,13 @@
Marvell Orion SPI device
Required properties:
-- compatible : should be "marvell,orion-spi" or "marvell,armada-370-spi".
+- compatible : should be on of the following:
+ - "marvell,orion-spi" for the Orion, mv78x00, Kirkwood and Dove SoCs
+ - "marvell,armada-370-spi", for the Armada 370 SoCs
+ - "marvell,armada-375-spi", for the Armada 375 SoCs
+ - "marvell,armada-380-spi", for the Armada 38x SoCs
+ - "marvell,armada-390-spi", for the Armada 39x SoCs
+ - "marvell,armada-xp-spi", for the Armada XP SoCs
- reg : offset and length of the register set for the device
- cell-index : Which of multiple SPI controllers is this.
Optional properties:
diff --git a/Documentation/devicetree/bindings/spi/spi-sirf.txt b/Documentation/devicetree/bindings/spi/spi-sirf.txt
index 4c7adb8f777c..ddd78ff68fae 100644
--- a/Documentation/devicetree/bindings/spi/spi-sirf.txt
+++ b/Documentation/devicetree/bindings/spi/spi-sirf.txt
@@ -1,7 +1,8 @@
* CSR SiRFprimaII Serial Peripheral Interface
Required properties:
-- compatible : Should be "sirf,prima2-spi"
+- compatible : Should be "sirf,prima2-spi", "sirf,prima2-usp"
+ or "sirf,atlas7-usp"
- reg : Offset and length of the register set for the device
- interrupts : Should contain SPI interrupt
- resets: phandle to the reset controller asserting this device in
diff --git a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt
new file mode 100644
index 000000000000..c8f50e5cf70b
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt
@@ -0,0 +1,26 @@
+Xilinx Zynq UltraScale+ MPSoC GQSPI controller Device Tree Bindings
+-------------------------------------------------------------------
+
+Required properties:
+- compatible : Should be "xlnx,zynqmp-qspi-1.0".
+- reg : Physical base address and size of GQSPI registers map.
+- interrupts : Property with a value describing the interrupt
+ number.
+- interrupt-parent : Must be core interrupt controller.
+- clock-names : List of input clock names - "ref_clk", "pclk"
+ (See clock bindings for details).
+- clocks : Clock phandles (see clock bindings for details).
+
+Optional properties:
+- num-cs : Number of chip selects used.
+
+Example:
+ qspi: spi@ff0f0000 {
+ compatible = "xlnx,zynqmp-qspi-1.0";
+ clock-names = "ref_clk", "pclk";
+ clocks = <&misc_clk &misc_clk>;
+ interrupts = <0 15 4>;
+ interrupt-parent = <&gic>;
+ num-cs = <1>;
+ reg = <0x0 0xff0f0000 0x1000>,<0x0 0xc0000000 0x8000000>;
+ };
diff --git a/Documentation/devicetree/bindings/spi/spi_atmel.txt b/Documentation/devicetree/bindings/spi/spi_atmel.txt
index 4f8184d069cb..fb588b3e6a9a 100644
--- a/Documentation/devicetree/bindings/spi/spi_atmel.txt
+++ b/Documentation/devicetree/bindings/spi/spi_atmel.txt
@@ -4,11 +4,16 @@ Required properties:
- compatible : should be "atmel,at91rm9200-spi".
- reg: Address and length of the register set for the device
- interrupts: Should contain spi interrupt
-- cs-gpios: chipselects
+- cs-gpios: chipselects (optional for SPI controller version >= 2 with the
+ Chip Select Active After Transfer feature).
- clock-names: tuple listing input clock names.
Required elements: "spi_clk"
- clocks: phandles to input clocks.
+Optional properties:
+- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO
+ capable SPI controllers.
+
Example:
spi1: spi@fffcc000 {
@@ -20,6 +25,7 @@ spi1: spi@fffcc000 {
clocks = <&spi1_clk>;
clock-names = "spi_clk";
cs-gpios = <&pioB 3 0>;
+ atmel,fifo-size = <32>;
status = "okay";
mmc-slot@0 {
diff --git a/Documentation/devicetree/bindings/spi/spi_pl022.txt b/Documentation/devicetree/bindings/spi/spi_pl022.txt
index 22ed6797216d..4d1673ca8cf8 100644
--- a/Documentation/devicetree/bindings/spi/spi_pl022.txt
+++ b/Documentation/devicetree/bindings/spi/spi_pl022.txt
@@ -4,9 +4,9 @@ Required properties:
- compatible : "arm,pl022", "arm,primecell"
- reg : Offset and length of the register set for the device
- interrupts : Should contain SPI controller interrupt
+- num-cs : total number of chipselects
Optional properties:
-- num-cs : total number of chipselects
- cs-gpios : should specify GPIOs used for chipselects.
The gpios will be referred to as reg = <index> in the SPI child nodes.
If unspecified, a single SPI device without a chip select can be used.
diff --git a/Documentation/devicetree/bindings/thermal/hisilicon-thermal.txt b/Documentation/devicetree/bindings/thermal/hisilicon-thermal.txt
new file mode 100644
index 000000000000..d48fc5280d5a
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/hisilicon-thermal.txt
@@ -0,0 +1,23 @@
+* Temperature Sensor on hisilicon SoCs
+
+** Required properties :
+
+- compatible: "hisilicon,tsensor".
+- reg: physical base address of thermal sensor and length of memory mapped
+ region.
+- interrupt: The interrupt number to the cpu. Defines the interrupt used
+ by /SOCTHERM/tsensor.
+- clock-names: Input clock name, should be 'thermal_clk'.
+- clocks: phandles for clock specified in "clock-names" property.
+- #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description.
+
+Example :
+
+ tsensor: tsensor@0,f7030700 {
+ compatible = "hisilicon,tsensor";
+ reg = <0x0 0xf7030700 0x0 0x1000>;
+ interrupts = <0 7 0x4>;
+ clocks = <&sys_ctrl HI6220_TSENSOR_CLK>;
+ clock-names = "thermal_clk";
+ #thermal-sensor-cells = <1>;
+ }
diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt b/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt
new file mode 100644
index 000000000000..290ec06fa33a
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt
@@ -0,0 +1,57 @@
+Qualcomm QPNP PMIC Temperature Alarm
+
+QPNP temperature alarm peripherals are found inside of Qualcomm PMIC chips
+that utilize the Qualcomm SPMI implementation. These peripherals provide an
+interrupt signal and status register to identify high PMIC die temperature.
+
+Required properties:
+- compatible: Should contain "qcom,spmi-temp-alarm".
+- reg: Specifies the SPMI address and length of the controller's
+ registers.
+- interrupts: PMIC temperature alarm interrupt.
+- #thermal-sensor-cells: Should be 0. See thermal.txt for a description.
+
+Optional properties:
+- io-channels: Should contain IIO channel specifier for the ADC channel,
+ which report chip die temperature.
+- io-channel-names: Should contain "thermal".
+
+Example:
+
+ pm8941_temp: thermal-alarm@2400 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>;
+ #thermal-sensor-cells = <0>;
+
+ io-channels = <&pm8941_vadc VADC_DIE_TEMP>;
+ io-channel-names = "thermal";
+ };
+
+ thermal-zones {
+ pm8941 {
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+
+ thermal-sensors = <&pm8941_temp>;
+
+ trips {
+ passive {
+ temperature = <1050000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ alert {
+ temperature = <125000>;
+ hysteresis = <2000>;
+ type = "hot";
+ };
+ crit {
+ temperature = <145000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+ };
+
diff --git a/Documentation/devicetree/bindings/thermal/thermal.txt b/Documentation/devicetree/bindings/thermal/thermal.txt
index 29fe0bfae38e..8a49362dea6e 100644
--- a/Documentation/devicetree/bindings/thermal/thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/thermal.txt
@@ -167,6 +167,13 @@ Optional property:
by means of sensor ID. Additional coefficients are
interpreted as constant offset.
+- sustainable-power: An estimate of the sustainable power (in mW) that the
+ Type: unsigned thermal zone can dissipate at the desired
+ Size: one cell control temperature. For reference, the
+ sustainable power of a 4'' phone is typically
+ 2000mW, while on a 10'' tablet is around
+ 4500mW.
+
Note: The delay properties are bound to the maximum dT/dt (temperature
derivative over time) in two situations for a thermal zone:
(i) - when passive cooling is activated (polling-delay-passive); and
@@ -546,6 +553,8 @@ thermal-zones {
*/
coefficients = <1200 -345 890>;
+ sustainable-power = <2500>;
+
trips {
/* Trips are based on resulting linear equation */
cpu_trip: cpu-trip {
diff --git a/Documentation/devicetree/bindings/timer/cadence,ttc-timer.txt b/Documentation/devicetree/bindings/timer/cadence,ttc-timer.txt
index 993695c659e1..eeee6cd51e5c 100644
--- a/Documentation/devicetree/bindings/timer/cadence,ttc-timer.txt
+++ b/Documentation/devicetree/bindings/timer/cadence,ttc-timer.txt
@@ -6,6 +6,9 @@ Required properties:
- interrupts : A list of 3 interrupts; one per timer channel.
- clocks: phandle to the source clock
+Optional properties:
+- timer-width: Bit width of the timer, necessary if not 16.
+
Example:
ttc0: ttc0@f8001000 {
@@ -14,4 +17,5 @@ ttc0: ttc0@f8001000 {
compatible = "cdns,ttc";
reg = <0xF8001000 0x1000>;
clocks = <&cpu_clk 3>;
+ timer-width = <32>;
};
diff --git a/Documentation/devicetree/bindings/timer/nxp,lpc3220-timer.txt b/Documentation/devicetree/bindings/timer/nxp,lpc3220-timer.txt
new file mode 100644
index 000000000000..51b05a0e70d1
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/nxp,lpc3220-timer.txt
@@ -0,0 +1,26 @@
+* NXP LPC3220 timer
+
+The NXP LPC3220 timer is used on a wide range of NXP SoCs. This
+includes LPC32xx, LPC178x, LPC18xx and LPC43xx parts.
+
+Required properties:
+- compatible:
+ Should be "nxp,lpc3220-timer".
+- reg:
+ Address and length of the register set.
+- interrupts:
+ Reference to the timer interrupt
+- clocks:
+ Should contain a reference to timer clock.
+- clock-names:
+ Should contain "timerclk".
+
+Example:
+
+timer1: timer@40085000 {
+ compatible = "nxp,lpc3220-timer";
+ reg = <0x40085000 0x1000>;
+ interrupts = <13>;
+ clocks = <&ccu1 CLK_CPU_TIMER1>;
+ clock-names = "timerclk";
+};
diff --git a/Documentation/devicetree/bindings/timer/renesas,16bit-timer.txt b/Documentation/devicetree/bindings/timer/renesas,16bit-timer.txt
new file mode 100644
index 000000000000..e8792447a199
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/renesas,16bit-timer.txt
@@ -0,0 +1,25 @@
+* Renesas H8/300 16bit timer
+
+The 16bit timer is a 16bit timer/counter with configurable clock inputs and
+programmable compare match.
+
+Required Properties:
+
+ - compatible: must contain "renesas,16bit-timer"
+ - reg: base address and length of the registers block for the timer module.
+ - interrupts: interrupt-specifier for the timer, IMIA
+ - clocks: a list of phandle, one for each entry in clock-names.
+ - clock-names: must contain "peripheral_clk" for the functional clock.
+ - renesas,channel: timer channel number.
+
+Example:
+
+ timer16: timer@ffff68 {
+ compatible = "reneas,16bit-timer";
+ reg = <0xffff68 8>, <0xffff60 8>;
+ interrupts = <24>;
+ renesas,channel = <0>;
+ clocks = <&pclk>;
+ clock-names = "peripheral_clk";
+ };
+
diff --git a/Documentation/devicetree/bindings/timer/renesas,8bit-timer.txt b/Documentation/devicetree/bindings/timer/renesas,8bit-timer.txt
new file mode 100644
index 000000000000..9dca3759a0f0
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/renesas,8bit-timer.txt
@@ -0,0 +1,25 @@
+* Renesas H8/300 8bit timer
+
+The 8bit timer is a 8bit timer/counter with configurable clock inputs and
+programmable compare match.
+
+This implement only supported cascade mode.
+
+Required Properties:
+
+ - compatible: must contain "renesas,8bit-timer"
+ - reg: base address and length of the registers block for the timer module.
+ - interrupts: interrupt-specifier for the timer, CMIA and TOVI
+ - clocks: a list of phandle, one for each entry in clock-names.
+ - clock-names: must contain "fck" for the functional clock.
+
+Example:
+
+ timer8_0: timer@ffff80 {
+ compatible = "renesas,8bit-timer";
+ reg = <0xffff80 10>;
+ interrupts = <36>;
+ clocks = <&fclk>;
+ clock-names = "fck";
+ };
+
diff --git a/Documentation/devicetree/bindings/timer/renesas,tpu.txt b/Documentation/devicetree/bindings/timer/renesas,tpu.txt
new file mode 100644
index 000000000000..f8b25897fb31
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/renesas,tpu.txt
@@ -0,0 +1,21 @@
+* Renesas H8/300 Timer Pluse Unit
+
+The TPU is a 16bit timer/counter with configurable clock inputs and
+programmable compare match.
+This implementation support only cascade mode.
+
+Required Properties:
+
+ - compatible: must contain "renesas,tpu"
+ - reg: base address and length of the registers block in 2 channel.
+ - clocks: a list of phandle, one for each entry in clock-names.
+ - clock-names: must contain "peripheral_clk" for the functional clock.
+
+
+Example:
+ tpu: tpu@ffffe0 {
+ compatible = "renesas,tpu";
+ reg = <0xffffe0 16>, <0xfffff0 12>;
+ clocks = <&pclk>;
+ clock-names = "peripheral_clk";
+ };
diff --git a/Documentation/devicetree/bindings/timer/st,stm32-timer.txt b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
new file mode 100644
index 000000000000..8ef28e70d6e8
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/st,stm32-timer.txt
@@ -0,0 +1,22 @@
+. STMicroelectronics STM32 timer
+
+The STM32 MCUs family has several general-purpose 16 and 32 bits timers.
+
+Required properties:
+- compatible : Should be "st,stm32-timer"
+- reg : Address and length of the register set
+- clocks : Reference on the timer input clock
+- interrupts : Reference to the timer interrupt
+
+Optional properties:
+- resets: Reference to a reset controller asserting the timer
+
+Example:
+
+timer5: timer@40000c00 {
+ compatible = "st,stm32-timer";
+ reg = <0x40000c00 0x400>;
+ interrupts = <50>;
+ resets = <&rrc 259>;
+ clocks = <&clk_pmtr1>;
+};
diff --git a/Documentation/devicetree/bindings/usb/atmel-usb.txt b/Documentation/devicetree/bindings/usb/atmel-usb.txt
index e180d56c75db..1be8d7a26c15 100644
--- a/Documentation/devicetree/bindings/usb/atmel-usb.txt
+++ b/Documentation/devicetree/bindings/usb/atmel-usb.txt
@@ -5,6 +5,13 @@ OHCI
Required properties:
- compatible: Should be "atmel,at91rm9200-ohci" for USB controllers
used in host mode.
+ - reg: Address and length of the register set for the device
+ - interrupts: Should contain ehci interrupt
+ - clocks: Should reference the peripheral, host and system clocks
+ - clock-names: Should contains two strings
+ "ohci_clk" for the peripheral clock
+ "hclk" for the host clock
+ "uhpck" for the system clock
- num-ports: Number of ports.
- atmel,vbus-gpio: If present, specifies a gpio that needs to be
activated for the bus to be powered.
@@ -14,6 +21,8 @@ Required properties:
usb0: ohci@00500000 {
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00500000 0x100000>;
+ clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
+ clock-names = "ohci_clk", "hclk", "uhpck";
interrupts = <20 4>;
num-ports = <2>;
};
@@ -23,11 +32,19 @@ EHCI
Required properties:
- compatible: Should be "atmel,at91sam9g45-ehci" for USB controllers
used in host mode.
+ - reg: Address and length of the register set for the device
+ - interrupts: Should contain ehci interrupt
+ - clocks: Should reference the peripheral and the UTMI clocks
+ - clock-names: Should contains two strings
+ "ehci_clk" for the peripheral clock
+ "usb_clk" for the UTMI clock
usb1: ehci@00800000 {
compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
reg = <0x00800000 0x100000>;
interrupts = <22 4>;
+ clocks = <&utmi>, <&uhphs_clk>;
+ clock-names = "usb_clk", "ehci_clk";
};
AT91 USB device controller
@@ -53,6 +70,8 @@ usb1: gadget@fffa4000 {
compatible = "atmel,at91rm9200-udc";
reg = <0xfffa4000 0x4000>;
interrupts = <10 4>;
+ clocks = <&udc_clk>, <&udpck>;
+ clock-names = "pclk", "hclk";
atmel,vbus-gpio = <&pioC 5 0>;
};
@@ -65,6 +84,10 @@ Required properties:
"sama5d3-udc"
- reg: Address and length of the register set for the device
- interrupts: Should contain usba interrupt
+ - clocks: Should reference the peripheral and host clocks
+ - clock-names: Should contains two strings
+ "pclk" for the peripheral clock
+ "hclk" for the host clock
- ep childnode: To specify the number of endpoints and their properties.
Optional properties:
@@ -86,6 +109,8 @@ usb2: gadget@fff78000 {
reg = <0x00600000 0x80000
0xfff78000 0x400>;
interrupts = <27 4 0>;
+ clocks = <&utmi>, <&udphs_clk>;
+ clock-names = "hclk", "pclk";
atmel,vbus-gpio = <&pioB 19 0>;
ep0 {
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt
deleted file mode 100644
index 38a548001e3a..000000000000
--- a/Documentation/devicetree/bindings/usb/ci-hdrc-imx.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-* Freescale i.MX ci13xxx usb controllers
-
-Required properties:
-- compatible: Should be "fsl,imx27-usb"
-- reg: Should contain registers location and length
-- interrupts: Should contain controller interrupt
-- fsl,usbphy: phandle of usb phy that connects to the port
-
-Recommended properies:
-- phy_type: the type of the phy connected to the core. Should be one
- of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
- property the PORTSC register won't be touched
-- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
-
-Optional properties:
-- fsl,usbmisc: phandler of non-core register device, with one argument
- that indicate usb controller index
-- vbus-supply: regulator for vbus
-- disable-over-current: disable over current detect
-- external-vbus-divider: enables off-chip resistor divider for Vbus
-- maximum-speed: limit the maximum connection speed to "full-speed".
-- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts
-
-Examples:
-usb@02184000 { /* USB OTG */
- compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
- reg = <0x02184000 0x200>;
- interrupts = <0 43 0x04>;
- fsl,usbphy = <&usbphy1>;
- fsl,usbmisc = <&usbmisc 0>;
- disable-over-current;
- external-vbus-divider;
- maximum-speed = "full-speed";
- tpl-support;
-};
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-qcom.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-qcom.txt
deleted file mode 100644
index f2899b550939..000000000000
--- a/Documentation/devicetree/bindings/usb/ci-hdrc-qcom.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Qualcomm CI13xxx (Chipidea) USB controllers
-
-Required properties:
-- compatible: should contain "qcom,ci-hdrc"
-- reg: offset and length of the register set in the memory map
-- interrupts: interrupt-specifier for the controller interrupt.
-- usb-phy: phandle for the PHY device
-- dr_mode: Should be "peripheral"
-
-Examples:
- gadget@f9a55000 {
- compatible = "qcom,ci-hdrc";
- reg = <0xf9a55000 0x400>;
- dr_mode = "peripheral";
- interrupts = <0 134 0>;
- usb-phy = <&usbphy0>;
- };
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt
index 27f8b1e5ee46..553e2fae3a76 100644
--- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt
+++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt
@@ -1,15 +1,35 @@
* USB2 ChipIdea USB controller for ci13xxx
Required properties:
-- compatible: should be "chipidea,usb2"
+- compatible: should be one of:
+ "fsl,imx27-usb"
+ "lsi,zevio-usb"
+ "qcom,ci-hdrc"
+ "chipidea,usb2"
- reg: base address and length of the registers
- interrupts: interrupt for the USB controller
+Recommended properies:
+- phy_type: the type of the phy connected to the core. Should be one
+ of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
+ property the PORTSC register won't be touched.
+- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
+
+Deprecated properties:
+- usb-phy: phandle for the PHY device. Use "phys" instead.
+- fsl,usbphy: phandle of usb phy that connects to the port. Use "phys" instead.
+
Optional properties:
- clocks: reference to the USB clock
- phys: reference to the USB PHY
- phy-names: should be "usb-phy"
- vbus-supply: reference to the VBUS regulator
+- maximum-speed: limit the maximum connection speed to "full-speed".
+- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts
+- fsl,usbmisc: (FSL only) phandler of non-core register device, with one
+ argument that indicate usb controller index
+- disable-over-current: (FSL only) disable over current detect
+- external-vbus-divider: (FSL only) enables off-chip resistor divider for Vbus
Example:
diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt
deleted file mode 100644
index abbcb2aea38c..000000000000
--- a/Documentation/devicetree/bindings/usb/ci-hdrc-zevio.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-* LSI Zevio USB OTG Controller
-
-Required properties:
-- compatible: Should be "lsi,zevio-usb"
-- reg: Should contain registers location and length
-- interrupts: Should contain controller interrupt
-
-Optional properties:
-- vbus-supply: regulator for vbus
-
-Examples:
- usb0: usb@b0000000 {
- reg = <0xb0000000 0x1000>;
- compatible = "lsi,zevio-usb";
- interrupts = <8>;
- vbus-supply = <&vbus_reg>;
- };
diff --git a/Documentation/devicetree/bindings/usb/dwc3-st.txt b/Documentation/devicetree/bindings/usb/dwc3-st.txt
index f9d70252bbb2..01c71b1258f4 100644
--- a/Documentation/devicetree/bindings/usb/dwc3-st.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3-st.txt
@@ -49,8 +49,7 @@ st_dwc3: dwc3@8f94000 {
st,syscfg = <&syscfg_core>;
resets = <&powerdown STIH407_USB3_POWERDOWN>,
<&softreset STIH407_MIPHY2_SOFTRESET>;
- reset-names = "powerdown",
- "softreset";
+ reset-names = "powerdown", "softreset";
#address-cells = <1>;
#size-cells = <1>;
pinctrl-names = "default";
@@ -62,7 +61,7 @@ st_dwc3: dwc3@8f94000 {
reg = <0x09900000 0x100000>;
interrupts = <GIC_SPI 155 IRQ_TYPE_NONE>;
dr_mode = "host";
- phys-names = "usb2-phy", "usb3-phy";
- phys = <&usb2_picophy2>, <&phy_port2 MIPHY_TYPE_USB>;
+ phy-names = "usb2-phy", "usb3-phy";
+ phys = <&usb2_picophy2>, <&phy_port2 PHY_TYPE_USB3>;
};
};
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 5cc364309edb..0815eac5b185 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -38,6 +38,8 @@ Optional properties:
- snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
utmi_l1_suspend_n, false when asserts utmi_sleep_n
- snps,hird-threshold: HIRD threshold
+ - snps,hsphy_interface: High-Speed PHY interface selection between "utmi" for
+ UTMI+ and "ulpi" for ULPI when the DWC_USB3_HSPHY_INTERFACE has value 3.
This is usually a subnode to DWC3 glue to which it is connected.
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 2826f2af503a..bd8d9e753029 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -69,6 +69,17 @@ Optional properties:
(no, min, max) where each value represents either a voltage
in microvolts or a value corresponding to voltage corner.
+- qcom,manual-pullup: If present, vbus is not routed to USB controller/phy
+ and controller driver therefore enables pull-up explicitly
+ before starting controller using usbcmd run/stop bit.
+
+- extcon: phandles to external connector devices. First phandle
+ should point to external connector, which provide "USB"
+ cable events, the second should point to external connector
+ device, which provide "USB-HOST" cable events. If one of
+ the external connector devices is not required empty <0>
+ phandle should be specified.
+
Example HSUSB OTG controller device node:
usb@f9a55000 {
diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
index ddbe304beb21..64a4ca6cf96f 100644
--- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
+++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
@@ -4,6 +4,7 @@ Required properties:
- compatible: Must contain one of the following:
- "renesas,usbhs-r8a7790"
- "renesas,usbhs-r8a7791"
+ - "renesas,usbhs-r8a7794"
- 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
diff --git a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
index 0aee0ad3f035..17327a296110 100644
--- a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
+++ b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
@@ -30,6 +30,9 @@ TWL4030 USB PHY AND COMPARATOR
- usb_mode : The mode used by the phy to connect to the controller. "1"
specifies "ULPI" mode and "2" specifies "CEA2011_3PIN" mode.
+If a sibling node is compatible "ti,twl4030-bci", then it will find
+this device and query it for USB power status.
+
twl4030-usb {
compatible = "ti,twl4030-usb";
interrupts = < 10 4 >;
diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
index 0b04fdff9d5a..a12d6012a40f 100644
--- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
@@ -13,6 +13,8 @@ Optional properties:
- big-endian-desc : boolean, set this for hcds with big-endian descriptors
- big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
- needs-reset-on-resume : boolean, set this to force EHCI reset after resume
+ - has-transaction-translator : boolean, set this if EHCI have a Transaction
+ Translator built into the root hub.
- clocks : a list of phandle + clock specifier pairs
- phys : phandle + phy specifier pair
- phy-names : "usb"
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 8270e9db8fcd..7b607761b774 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -40,6 +40,7 @@ calxeda Calxeda
capella Capella Microsystems, Inc
cavium Cavium, Inc.
cdns Cadence Design Systems Inc.
+ceva Ceva, Inc.
chipidea Chipidea, Inc
chipone ChipOne
chipspark ChipSPARK
@@ -52,14 +53,17 @@ cnxt Conexant Systems, Inc.
cortina Cortina Systems, Inc.
cosmic Cosmic Circuits
crystalfontz Crystalfontz America, Inc.
+cubietech Cubietech, Ltd.
dallas Maxim Integrated Products (formerly Dallas Semiconductor)
davicom DAVICOM Semiconductor, Inc.
+delta Delta Electronics, Inc.
denx Denx Software Engineering
digi Digi International Inc.
digilent Diglent, Inc.
dlg Dialog Semiconductor
dlink D-Link Corporation
dmo Data Modul AG
+ea Embedded Artists AB
ebv EBV Elektronik
edt Emerging Display Technologies
elan Elan Microelectronic Corp.
@@ -90,9 +94,11 @@ gumstix Gumstix, Inc.
gw Gateworks Corporation
hannstar HannStar Display Corporation
haoyu Haoyu Microelectronic Co. Ltd.
+hardkernel Hardkernel Co., Ltd
himax Himax Technologies, Inc.
hisilicon Hisilicon Limited.
hit Hitachi Ltd.
+hitex Hitex Development Tools
honeywell Honeywell
hp Hewlett Packard
i2se I2SE GmbH
@@ -118,6 +124,7 @@ lltc Linear Technology Corporation
marvell Marvell Technology Group Ltd.
maxim Maxim Integrated Products
mediatek MediaTek Inc.
+melexis Melexis N.V.
merrii Merrii Technology Co., Ltd.
micrel Micrel Inc.
microchip Microchip Technology Inc.
@@ -161,8 +168,10 @@ radxa Radxa
raidsonic RaidSonic Technology GmbH
ralink Mediatek/Ralink Technology Corp.
ramtron Ramtron International
+raspberrypi Raspberry Pi Foundation
realtek Realtek Semiconductor Corp.
renesas Renesas Electronics Corporation
+richtek Richtek Technology Corporation
ricoh Ricoh Co. Ltd.
rockchip Fuzhou Rockchip Electronics Co., Ltd
samsung Samsung Semiconductor
@@ -183,6 +192,7 @@ skyworks Skyworks Solutions, Inc.
smsc Standard Microsystems Corporation
snps Synopsys, Inc.
solidrun SolidRun
+solomon Solomon Systech Limited
sony Sony Corporation
spansion Spansion Inc.
sprd Spreadtrum Communications Inc.
@@ -191,6 +201,7 @@ ste ST-Ericsson
stericsson ST-Ericsson
synology Synology, Inc.
tbs TBS Technologies
+tcl Toby Churchill Ltd.
thine THine Electronics, Inc.
ti Texas Instruments
tlm Trusted Logic Mobility
@@ -205,6 +216,7 @@ variscite Variscite Ltd.
via VIA Technologies, Inc.
virtio Virtual I/O Device Specification, developed by the OASIS consortium
voipac Voipac Technologies s.r.o.
+wexler Wexler
winbond Winbond Electronics corp.
wlf Wolfson Microelectronics
wm Wondermedia Technologies, Inc.
@@ -214,3 +226,4 @@ xillybus Xillybus Ltd.
xlnx Xilinx
zyxel ZyXEL Communications Corp.
zarlink Zarlink Semiconductor
+zte ZTE Corp.
diff --git a/Documentation/devicetree/bindings/video/exynos-mic.txt b/Documentation/devicetree/bindings/video/exynos-mic.txt
new file mode 100644
index 000000000000..0fba2ee6440a
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/exynos-mic.txt
@@ -0,0 +1,51 @@
+Device-Tree bindings for Samsung Exynos SoC mobile image compressor (MIC)
+
+MIC (mobile image compressor) resides between decon and mipi dsi. Mipi dsi is
+not capable to transfer high resoltuion frame data as decon can send. MIC
+solves this problem by compressing the frame data by 1/2 before it is
+transferred through mipi dsi. The compressed frame data must be uncompressed in
+the panel PCB.
+
+Required properties:
+- compatible: value should be "samsung,exynos5433-mic".
+- reg: physical base address and length of the MIC registers set and system
+ register of mic.
+- clocks: must include clock specifiers corresponding to entries in the
+ clock-names property.
+- clock-names: list of clock names sorted in the same order as the clocks
+ property. Must contain "pclk_mic0", "sclk_rgb_vclk_to_mic0".
+- samsung,disp-syscon: the reference node for syscon for DISP block.
+- ports: contains a port which is connected to decon node and dsi node.
+ address-cells and size-cells must 1 and 0, respectively.
+- port: contains an endpoint node which is connected to the endpoint in the
+ decon node or dsi node. The reg value must be 0 and 1 respectively.
+
+Example:
+SoC specific DT entry:
+mic: mic@13930000 {
+ compatible = "samsung,exynos5433-mic";
+ reg = <0x13930000 0x48>;
+ clocks = <&cmu_disp CLK_PCLK_MIC0>,
+ <&cmu_disp CLK_SCLK_RGB_VCLK_TO_MIC0>;
+ clock-names = "pclk_mic0", "sclk_rgb_vclk_to_mic0";
+ samsung,disp-syscon = <&syscon_disp>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ mic_to_decon: endpoint {
+ remote-endpoint = <&decon_to_mic>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ mic_to_dsi: endpoint {
+ remote-endpoint = <&dsi_to_mic>;
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/video/exynos5433-decon.txt b/Documentation/devicetree/bindings/video/exynos5433-decon.txt
new file mode 100644
index 000000000000..377afbf5122a
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/exynos5433-decon.txt
@@ -0,0 +1,65 @@
+Device-Tree bindings for Samsung Exynos SoC display controller (DECON)
+
+DECON (Display and Enhancement Controller) is the Display Controller for the
+Exynos series of SoCs which transfers the image data from a video memory
+buffer to an external LCD interface.
+
+Required properties:
+- compatible: value should be "samsung,exynos5433-decon";
+- reg: physical base address and length of the DECON registers set.
+- interrupts: should contain a list of all DECON IP block interrupts in the
+ order: VSYNC, LCD_SYSTEM. The interrupt specifier format
+ depends on the interrupt controller used.
+- interrupt-names: should contain the interrupt names: "vsync", "lcd_sys"
+ in the same order as they were listed in the interrupts
+ property.
+- clocks: must include clock specifiers corresponding to entries in the
+ clock-names property.
+- clock-names: list of clock names sorted in the same order as the clocks
+ property. Must contain "aclk_decon", "aclk_smmu_decon0x",
+ "aclk_xiu_decon0x", "pclk_smmu_decon0x", clk_decon_vclk",
+ "sclk_decon_eclk"
+- ports: contains a port which is connected to mic node. address-cells and
+ size-cells must 1 and 0, respectively.
+- port: contains an endpoint node which is connected to the endpoint in the mic
+ node. The reg value muset be 0.
+- i80-if-timings: specify whether the panel which is connected to decon uses
+ i80 lcd interface or mipi video interface. This node contains
+ no timing information as that of fimd does. Because there is
+ no register in decon to specify i80 interface timing value,
+ it is not needed, but make it remain to use same kind of node
+ in fimd and exynos7 decon.
+
+Example:
+SoC specific DT entry:
+decon: decon@13800000 {
+ compatible = "samsung,exynos5433-decon";
+ reg = <0x13800000 0x2104>;
+ clocks = <&cmu_disp CLK_ACLK_DECON>, <&cmu_disp CLK_ACLK_SMMU_DECON0X>,
+ <&cmu_disp CLK_ACLK_XIU_DECON0X>,
+ <&cmu_disp CLK_PCLK_SMMU_DECON0X>,
+ <&cmu_disp CLK_SCLK_DECON_VCLK>,
+ <&cmu_disp CLK_SCLK_DECON_ECLK>;
+ clock-names = "aclk_decon", "aclk_smmu_decon0x", "aclk_xiu_decon0x",
+ "pclk_smmu_decon0x", "sclk_decon_vclk", "sclk_decon_eclk";
+ interrupt-names = "vsync", "lcd_sys";
+ interrupts = <0 202 0>, <0 203 0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ decon_to_mic: endpoint {
+ remote-endpoint = <&mic_to_decon>;
+ };
+ };
+ };
+};
+
+Board specific DT entry:
+&decon {
+ i80-if-timings {
+ };
+};
diff --git a/Documentation/devicetree/bindings/video/exynos_dsim.txt b/Documentation/devicetree/bindings/video/exynos_dsim.txt
index 802aa7ef64e5..0be036270661 100644
--- a/Documentation/devicetree/bindings/video/exynos_dsim.txt
+++ b/Documentation/devicetree/bindings/video/exynos_dsim.txt
@@ -6,17 +6,19 @@ Required properties:
"samsung,exynos4210-mipi-dsi" /* for Exynos4 SoCs */
"samsung,exynos4415-mipi-dsi" /* for Exynos4415 SoC */
"samsung,exynos5410-mipi-dsi" /* for Exynos5410/5420/5440 SoCs */
+ "samsung,exynos5433-mipi-dsi" /* for Exynos5433 SoCs */
- reg: physical base address and length of the registers set for the device
- interrupts: should contain DSI interrupt
- clocks: list of clock specifiers, must contain an entry for each required
entry in clock-names
- - clock-names: should include "bus_clk"and "pll_clk" entries
+ - clock-names: should include "bus_clk"and "sclk_mipi" entries
+ the use of "pll_clk" is deprecated
- phys: list of phy specifiers, must contain an entry for each required
entry in phy-names
- phy-names: should include "dsim" entry
- vddcore-supply: MIPI DSIM Core voltage supply (e.g. 1.1V)
- vddio-supply: MIPI DSIM I/O and PLL voltage supply (e.g. 1.8V)
- - samsung,pll-clock-frequency: specifies frequency of the "pll_clk" clock
+ - samsung,pll-clock-frequency: specifies frequency of the oscillator clock
- #address-cells, #size-cells: should be set respectively to <1> and <0>
according to DSI host bindings (see MIPI DSI bindings [1])
@@ -30,10 +32,19 @@ Video interfaces:
Device node can contain video interface port nodes according to [2].
The following are properties specific to those nodes:
- port node:
- - reg: (required) can be 0 for input RGB/I80 port or 1 for DSI port;
+ port node inbound:
+ - reg: (required) must be 0.
+ port node outbound:
+ - reg: (required) must be 1.
- endpoint node of DSI port (reg = 1):
+ endpoint node connected from mic node (reg = 0):
+ - remote-endpoint: specifies the endpoint in mic node. This node is required
+ for Exynos5433 mipi dsi. So mic can access to panel node
+ thoughout this dsi node.
+ endpoint node connected to panel node (reg = 1):
+ - remote-endpoint: specifies the endpoint in panel node. This node is
+ required in all kinds of exynos mipi dsi to represent
+ the connection between mipi dsi and panel.
- samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst
mode
- samsung,esc-clock-frequency: specifies DSI frequency in escape mode
@@ -48,7 +59,7 @@ Example:
reg = <0x11C80000 0x10000>;
interrupts = <0 79 0>;
clocks = <&clock 286>, <&clock 143>;
- clock-names = "bus_clk", "pll_clk";
+ clock-names = "bus_clk", "sclk_mipi";
phys = <&mipi_phy 1>;
phy-names = "dsim";
vddcore-supply = <&vusb_reg>;
@@ -72,7 +83,15 @@ Example:
#address-cells = <1>;
#size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ decon_to_mic: endpoint {
+ remote-endpoint = <&mic_to_decon>;
+ };
+ };
+
port@1 {
+ reg = <1>;
dsi_ep: endpoint {
reg = <0>;
samsung,burst-clock-frequency = <500000000>;
diff --git a/Documentation/devicetree/bindings/video/ssd1307fb.txt b/Documentation/devicetree/bindings/video/ssd1307fb.txt
index 7a125427ff4b..d1be78db63f5 100644
--- a/Documentation/devicetree/bindings/video/ssd1307fb.txt
+++ b/Documentation/devicetree/bindings/video/ssd1307fb.txt
@@ -2,7 +2,7 @@
Required properties:
- compatible: Should be "solomon,<chip>fb-<bus>". The only supported bus for
- now is i2c, and the supported chips are ssd1306 and ssd1307.
+ now is i2c, and the supported chips are ssd1305, ssd1306 and ssd1307.
- reg: Should contain address of the controller on the I2C bus. Most likely
0x3c or 0x3d
- pwm: Should contain the pwm to use according to the OF device tree PWM
@@ -15,6 +15,16 @@ Required properties:
Optional properties:
- reset-active-low: Is the reset gpio is active on physical low?
+ - solomon,segment-no-remap: Display needs normal (non-inverted) data column
+ to segment mapping
+ - solomon,com-seq: Display uses sequential COM pin configuration
+ - solomon,com-lrremap: Display uses left-right COM pin remap
+ - solomon,com-invdir: Display uses inverted COM pin scan direction
+ - solomon,com-offset: Number of the COM pin wired to the first display line
+ - solomon,prechargep1: Length of deselect period (phase 1) in clock cycles.
+ - solomon,prechargep2: Length of precharge period (phase 2) in clock cycles.
+ This needs to be the higher, the higher the capacitance
+ of the OLED's pixels is
[0]: Documentation/devicetree/bindings/pwm/pwm.txt
@@ -26,3 +36,14 @@ ssd1307: oled@3c {
reset-gpios = <&gpio2 7>;
reset-active-low;
};
+
+ssd1306: oled@3c {
+ compatible = "solomon,ssd1306fb-i2c";
+ reg = <0x3c>;
+ pwms = <&pwm 4 3000>;
+ reset-gpios = <&gpio2 7>;
+ reset-active-low;
+ solomon,com-lrremap;
+ solomon,com-invdir;
+ solomon,com-offset = <32>;
+};
diff --git a/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt b/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt
new file mode 100644
index 000000000000..388c88a01222
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt
@@ -0,0 +1,38 @@
+STMicroelectronics Low Power Controller (LPC) - Watchdog
+========================================================
+
+LPC currently supports Watchdog OR Real Time Clock functionality.
+
+[See: ../rtc/rtc-st-lpc.txt for RTC options]
+
+Required properties
+
+- compatible : Must be one of: "st,stih407-lpc" "st,stih416-lpc"
+ "st,stih415-lpc" "st,stid127-lpc"
+- reg : LPC registers base address + size
+- interrupts : LPC interrupt line number and associated flags
+- clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt)
+- st,lpc-mode : The LPC can run either one of two modes ST_LPC_MODE_RTC [0] or
+ ST_LPC_MODE_WDT [1]. One (and only one) mode must be
+ selected.
+
+Required properties [watchdog mode]
+
+- st,syscfg : Phandle to syscfg node used to enable watchdog and configure
+ CPU reset type.
+- timeout-sec : Watchdog timeout in seconds
+
+Optional properties [watchdog mode]
+
+- st,warm-reset : If present reset type will be 'warm' - if not it will be cold
+
+Example:
+ lpc@fde05000 {
+ compatible = "st,stih407-lpc";
+ reg = <0xfde05000 0x1000>;
+ clocks = <&clk_s_d3_flexgen CLK_LPC_0>;
+ st,syscfg = <&syscfg_core>;
+ timeout-sec = <120>;
+ st,lpc-mode = <ST_LPC_MODE_WDT>;
+ st,warm-reset;
+ };
diff --git a/Documentation/devicetree/booting-without-of.txt b/Documentation/devicetree/booting-without-of.txt
index e49e423268c0..04d34f6a58f3 100644
--- a/Documentation/devicetree/booting-without-of.txt
+++ b/Documentation/devicetree/booting-without-of.txt
@@ -856,6 +856,10 @@ address which can extend beyond that limit.
name may clash with standard defined ones, you prefix them with your
vendor name and a comma.
+ Additional properties for the root node:
+
+ - serial-number : a string representing the device's serial number
+
b) The /cpus node
This node is the parent of all individual CPU nodes. It doesn't
diff --git a/Documentation/edac.txt b/Documentation/edac.txt
index 73fff13e848f..0cf27a3544a5 100644
--- a/Documentation/edac.txt
+++ b/Documentation/edac.txt
@@ -1,53 +1,34 @@
-
-
EDAC - Error Detection And Correction
-
-Written by Doug Thompson <dougthompson@xmission.com>
-7 Dec 2005
-17 Jul 2007 Updated
-
-(c) Mauro Carvalho Chehab
-05 Aug 2009 Nehalem interface
-
-EDAC is maintained and written by:
-
- Doug Thompson, Dave Jiang, Dave Peterson et al,
- original author: Thayne Harbaugh,
-
-Contact:
- website: bluesmoke.sourceforge.net
- mailing list: bluesmoke-devel@lists.sourceforge.net
+=====================================
"bluesmoke" was the name for this device driver when it was "out-of-tree"
and maintained at sourceforge.net. When it was pushed into 2.6.16 for the
first time, it was renamed to 'EDAC'.
-The bluesmoke project at sourceforge.net is now utilized as a 'staging area'
-for EDAC development, before it is sent upstream to kernel.org
-
-At the bluesmoke/EDAC project site is a series of quilt patches against
-recent kernels, stored in a SVN repository. For easier downloading, there
-is also a tarball snapshot available.
+PURPOSE
+-------
-============================================================================
-EDAC PURPOSE
-
-The 'edac' kernel module goal is to detect and report errors that occur
-within the computer system running under linux.
+The 'edac' kernel module's goal is to detect and report hardware errors
+that occur within the computer system running under linux.
MEMORY
+------
-In the initial release, memory Correctable Errors (CE) and Uncorrectable
-Errors (UE) are the primary errors being harvested. These types of errors
-are harvested by the 'edac_mc' class of device.
+Memory Correctable Errors (CE) and Uncorrectable Errors (UE) are the
+primary errors being harvested. These types of errors are harvested by
+the 'edac_mc' device.
Detecting CE events, then harvesting those events and reporting them,
-CAN be a predictor of future UE events. With CE events, the system can
-continue to operate, but with less safety. Preventive maintenance and
-proactive part replacement of memory DIMMs exhibiting CEs can reduce
-the likelihood of the dreaded UE events and system 'panics'.
+*can* but must not necessarily be a predictor of future UE events. With
+CE events only, the system can and will continue to operate as no data
+has been damaged yet.
+
+However, preventive maintenance and proactive part replacement of memory
+DIMMs exhibiting CEs can reduce the likelihood of the dreaded UE events
+and system panics.
-NON-MEMORY
+OTHER HARDWARE ELEMENTS
+-----------------------
A new feature for EDAC, the edac_device class of device, was added in
the 2.6.23 version of the kernel.
@@ -56,70 +37,57 @@ This new device type allows for non-memory type of ECC hardware detectors
to have their states harvested and presented to userspace via the sysfs
interface.
-Some architectures have ECC detectors for L1, L2 and L3 caches, along with DMA
-engines, fabric switches, main data path switches, interconnections,
-and various other hardware data paths. If the hardware reports it, then
-a edac_device device probably can be constructed to harvest and present
-that to userspace.
+Some architectures have ECC detectors for L1, L2 and L3 caches,
+along with DMA engines, fabric switches, main data path switches,
+interconnections, and various other hardware data paths. If the hardware
+reports it, then a edac_device device probably can be constructed to
+harvest and present that to userspace.
PCI BUS SCANNING
+----------------
-In addition, PCI Bus Parity and SERR Errors are scanned for on PCI devices
-in order to determine if errors are occurring on data transfers.
+In addition, PCI devices are scanned for PCI Bus Parity and SERR Errors
+in order to determine if errors are occurring during data transfers.
The presence of PCI Parity errors must be examined with a grain of salt.
-There are several add-in adapters that do NOT follow the PCI specification
+There are several add-in adapters that do *not* follow the PCI specification
with regards to Parity generation and reporting. The specification says
the vendor should tie the parity status bits to 0 if they do not intend
to generate parity. Some vendors do not do this, and thus the parity bit
can "float" giving false positives.
-In the kernel there is a PCI device attribute located in sysfs that is
-checked by the EDAC PCI scanning code. If that attribute is set,
-PCI parity/error scanning is skipped for that device. The attribute
-is:
+There is a PCI device attribute located in sysfs that is checked by
+the EDAC PCI scanning code. If that attribute is set, PCI parity/error
+scanning is skipped for that device. The attribute is:
broken_parity_status
-as is located in /sys/devices/pci<XXX>/0000:XX:YY.Z directories for
+and is located in /sys/devices/pci<XXX>/0000:XX:YY.Z directories for
PCI devices.
-FUTURE HARDWARE SCANNING
-EDAC will have future error detectors that will be integrated with
-EDAC or added to it, in the following list:
-
- MCE Machine Check Exception
- MCA Machine Check Architecture
- NMI NMI notification of ECC errors
- MSRs Machine Specific Register error cases
- and other mechanisms.
-
-These errors are usually bus errors, ECC errors, thermal throttling
-and the like.
-
-
-============================================================================
-EDAC VERSIONING
+VERSIONING
+----------
EDAC is composed of a "core" module (edac_core.ko) and several Memory
-Controller (MC) driver modules. On a given system, the CORE
-is loaded and one MC driver will be loaded. Both the CORE and
-the MC driver (or edac_device driver) have individual versions that reflect
-current release level of their respective modules.
+Controller (MC) driver modules. On a given system, the CORE is loaded
+and one MC driver will be loaded. Both the CORE and the MC driver (or
+edac_device driver) have individual versions that reflect current
+release level of their respective modules.
-Thus, to "report" on what version a system is running, one must report both
-the CORE's and the MC driver's versions.
+Thus, to "report" on what version a system is running, one must report
+both the CORE's and the MC driver's versions.
LOADING
+-------
-If 'edac' was statically linked with the kernel then no loading is
-necessary. If 'edac' was built as modules then simply modprobe the
-'edac' pieces that you need. You should be able to modprobe
-hardware-specific modules and have the dependencies load the necessary core
-modules.
+If 'edac' was statically linked with the kernel then no loading
+is necessary. If 'edac' was built as modules then simply modprobe
+the 'edac' pieces that you need. You should be able to modprobe
+hardware-specific modules and have the dependencies load the necessary
+core modules.
Example:
@@ -129,35 +97,33 @@ loads both the amd76x_edac.ko memory controller module and the edac_mc.ko
core module.
-============================================================================
-EDAC sysfs INTERFACE
-
-EDAC presents a 'sysfs' interface for control, reporting and attribute
-reporting purposes.
+SYSFS INTERFACE
+---------------
-EDAC lives in the /sys/devices/system/edac directory.
+EDAC presents a 'sysfs' interface for control and reporting purposes. It
+lives in the /sys/devices/system/edac directory.
-Within this directory there currently reside 2 'edac' components:
+Within this directory there currently reside 2 components:
mc memory controller(s) system
pci PCI control and status system
-============================================================================
+
Memory Controller (mc) Model
+----------------------------
-First a background on the memory controller's model abstracted in EDAC.
-Each 'mc' device controls a set of DIMM memory modules. These modules are
-laid out in a Chip-Select Row (csrowX) and Channel table (chX). There can
-be multiple csrows and multiple channels.
+Each 'mc' device controls a set of DIMM memory modules. These modules
+are laid out in a Chip-Select Row (csrowX) and Channel table (chX).
+There can be multiple csrows and multiple channels.
-Memory controllers allow for several csrows, with 8 csrows being a typical value.
-Yet, the actual number of csrows depends on the electrical "loading"
-of a given motherboard, memory controller and DIMM characteristics.
+Memory controllers allow for several csrows, with 8 csrows being a
+typical value. Yet, the actual number of csrows depends on the layout of
+a given motherboard, memory controller and DIMM characteristics.
-Dual channels allows for 128 bit data transfers to the CPU from memory.
-Some newer chipsets allow for more than 2 channels, like Fully Buffered DIMMs
-(FB-DIMMs). The following example will assume 2 channels:
+Dual channels allows for 128 bit data transfers to/from the CPU from/to
+memory. Some newer chipsets allow for more than 2 channels, like Fully
+Buffered DIMMs (FB-DIMMs). The following example will assume 2 channels:
Channel 0 Channel 1
@@ -179,12 +145,12 @@ for memory DIMMs:
DIMM_A1
DIMM_B1
-Labels for these slots are usually silk screened on the motherboard. Slots
-labeled 'A' are channel 0 in this example. Slots labeled 'B'
-are channel 1. Notice that there are two csrows possible on a
-physical DIMM. These csrows are allocated their csrow assignment
-based on the slot into which the memory DIMM is placed. Thus, when 1 DIMM
-is placed in each Channel, the csrows cross both DIMMs.
+Labels for these slots are usually silk-screened on the motherboard.
+Slots labeled 'A' are channel 0 in this example. Slots labeled 'B' are
+channel 1. Notice that there are two csrows possible on a physical DIMM.
+These csrows are allocated their csrow assignment based on the slot into
+which the memory DIMM is placed. Thus, when 1 DIMM is placed in each
+Channel, the csrows cross both DIMMs.
Memory DIMMs come single or dual "ranked". A rank is a populated csrow.
Thus, 2 single ranked DIMMs, placed in slots DIMM_A0 and DIMM_B0 above
@@ -193,8 +159,8 @@ when 2 dual ranked DIMMs are similarly placed, then both csrow0 and
csrow1 will be populated. The pattern repeats itself for csrow2 and
csrow3.
-The representation of the above is reflected in the directory tree
-in EDAC's sysfs interface. Starting in directory
+The representation of the above is reflected in the directory
+tree in EDAC's sysfs interface. Starting in directory
/sys/devices/system/edac/mc each memory controller will be represented
by its own 'mcX' directory, where 'X' is the index of the MC.
@@ -217,34 +183,35 @@ Under each 'mcX' directory each 'csrowX' is again represented by a
|->csrow3
....
-Notice that there is no csrow1, which indicates that csrow0 is
-composed of a single ranked DIMMs. This should also apply in both
-Channels, in order to have dual-channel mode be operational. Since
-both csrow2 and csrow3 are populated, this indicates a dual ranked
-set of DIMMs for channels 0 and 1.
+Notice that there is no csrow1, which indicates that csrow0 is composed
+of a single ranked DIMMs. This should also apply in both Channels, in
+order to have dual-channel mode be operational. Since both csrow2 and
+csrow3 are populated, this indicates a dual ranked set of DIMMs for
+channels 0 and 1.
-Within each of the 'mcX' and 'csrowX' directories are several
-EDAC control and attribute files.
+Within each of the 'mcX' and 'csrowX' directories are several EDAC
+control and attribute files.
-============================================================================
-'mcX' DIRECTORIES
+'mcX' directories
+-----------------
In 'mcX' directories are EDAC control and attribute files for
this 'X' instance of the memory controllers.
For a description of the sysfs API, please see:
- Documentation/ABI/testing/sysfs/devices-edac
+ Documentation/ABI/testing/sysfs-devices-edac
+
-============================================================================
-'csrowX' DIRECTORIES
+'csrowX' directories
+--------------------
-When CONFIG_EDAC_LEGACY_SYSFS is enabled, the sysfs will contain the
-csrowX directories. As this API doesn't work properly for Rambus, FB-DIMMs
-and modern Intel Memory Controllers, this is being deprecated in favor
-of dimmX directories.
+When CONFIG_EDAC_LEGACY_SYSFS is enabled, sysfs will contain the csrowX
+directories. As this API doesn't work properly for Rambus, FB-DIMMs and
+modern Intel Memory Controllers, this is being deprecated in favor of
+dimmX directories.
In the 'csrowX' directories are EDAC control and attribute files for
this 'X' instance of csrow:
@@ -265,18 +232,18 @@ Total Correctable Errors count attribute file:
'ce_count'
This attribute file displays the total count of correctable
- errors that have occurred on this csrow. This
- count is very important to examine. CEs provide early
- indications that a DIMM is beginning to fail. This count
- field should be monitored for non-zero values and report
- such information to the system administrator.
+ errors that have occurred on this csrow. This count is very
+ important to examine. CEs provide early indications that a
+ DIMM is beginning to fail. This count field should be
+ monitored for non-zero values and report such information
+ to the system administrator.
Total memory managed by this csrow attribute file:
'size_mb'
- This attribute file displays, in count of megabytes, of memory
+ This attribute file displays, in count of megabytes, the memory
that this csrow contains.
@@ -377,11 +344,13 @@ Channel 1 DIMM Label control file:
motherboard specific and determination of this information
must occur in userland at this time.
-============================================================================
+
+
SYSTEM LOGGING
+--------------
-If logging for UEs and CEs are enabled then system logs will have
-error notices indicating errors that have been detected:
+If logging for UEs and CEs is enabled, then system logs will contain
+information indicating that errors have been detected:
EDAC MC0: CE page 0x283, offset 0xce0, grain 8, syndrome 0x6ec3, row 0,
channel 1 "DIMM_B1": amd76x_edac
@@ -404,24 +373,23 @@ The structure of the message is:
and then an optional, driver-specific message that may
have additional information.
-Both UEs and CEs with no info will lack all but memory controller,
-error type, a notice of "no info" and then an optional,
-driver-specific error message.
+Both UEs and CEs with no info will lack all but memory controller, error
+type, a notice of "no info" and then an optional, driver-specific error
+message.
-============================================================================
PCI Bus Parity Detection
+------------------------
-
-On Header Type 00 devices the primary status is looked at
-for any parity error regardless of whether Parity is enabled on the
-device. (The spec indicates parity is generated in some cases).
-On Header Type 01 bridges, the secondary status register is also
-looked at to see if parity occurred on the bus on the other side of
-the bridge.
+On Header Type 00 devices, the primary status is looked at for any
+parity error regardless of whether parity is enabled on the device or
+not. (The spec indicates parity is generated in some cases). On Header
+Type 01 bridges, the secondary status register is also looked at to see
+if parity occurred on the bus on the other side of the bridge.
SYSFS CONFIGURATION
+-------------------
Under /sys/devices/system/edac/pci are control and attribute files as follows:
@@ -450,8 +418,9 @@ Parity Count:
have been detected.
-============================================================================
+
MODULE PARAMETERS
+-----------------
Panic on UE control file:
@@ -516,7 +485,7 @@ Panic on PCI PARITY Error:
'panic_on_pci_parity'
- This control files enables or disables panicking when a parity
+ This control file enables or disables panicking when a parity
error has been detected.
@@ -530,10 +499,8 @@ Panic on PCI PARITY Error:
-=======================================================================
-
-
-EDAC_DEVICE type of device
+EDAC device type
+----------------
In the header file, edac_core.h, there is a series of edac_device structures
and APIs for the EDAC_DEVICE.
@@ -573,6 +540,7 @@ The test_device_edac device adds at least one of its own custom control:
The symlink points to the 'struct dev' that is registered for this edac_device.
INSTANCES
+---------
One or more instance directories are present. For the 'test_device_edac' case:
@@ -586,6 +554,7 @@ counter in deeper subdirectories.
ue_count total of UE events of subdirectories
BLOCKS
+------
At the lowest directory level is the 'block' directory. There can be 0, 1
or more blocks specified in each instance.
@@ -617,14 +586,15 @@ The 'test_device_edac' device adds 4 attributes and 1 control:
reset all the above counters.
-Use of the 'test_device_edac' driver should any others to create their own
+Use of the 'test_device_edac' driver should enable any others to create their own
unique drivers for their hardware systems.
The 'test_device_edac' sample driver is located at the
bluesmoke.sourceforge.net project site for EDAC.
-=======================================================================
+
NEHALEM USAGE OF EDAC APIs
+--------------------------
This chapter documents some EXPERIMENTAL mappings for EDAC API to handle
Nehalem EDAC driver. They will likely be changed on future versions
@@ -633,7 +603,7 @@ of the driver.
Due to the way Nehalem exports Memory Controller data, some adjustments
were done at i7core_edac driver. This chapter will cover those differences
-1) On Nehalem, there are one Memory Controller per Quick Patch Interconnect
+1) On Nehalem, there is one Memory Controller per Quick Patch Interconnect
(QPI). At the driver, the term "socket" means one QPI. This is
associated with a physical CPU socket.
@@ -642,7 +612,7 @@ were done at i7core_edac driver. This chapter will cover those differences
Each channel can have up to 3 DIMMs.
The minimum known unity is DIMMs. There are no information about csrows.
- As EDAC API maps the minimum unity is csrows, the driver sequencially
+ As EDAC API maps the minimum unity is csrows, the driver sequentially
maps channel/dimm into different csrows.
For example, supposing the following layout:
@@ -664,7 +634,7 @@ exports one
Each QPI is exported as a different memory controller.
-2) Nehalem MC has the hability to generate errors. The driver implements this
+2) Nehalem MC has the ability to generate errors. The driver implements this
functionality via some error injection nodes:
For injecting a memory error, there are some sysfs nodes, under
@@ -771,5 +741,22 @@ exports one
The standard error counters are generated when an mcelog error is received
by the driver. Since, with udimm, this is counted by software, it is
- possible that some errors could be lost. With rdimm's, they displays the
+ possible that some errors could be lost. With rdimm's, they display the
contents of the registers
+
+CREDITS:
+========
+
+Written by Doug Thompson <dougthompson@xmission.com>
+7 Dec 2005
+17 Jul 2007 Updated
+
+(c) Mauro Carvalho Chehab
+05 Aug 2009 Nehalem interface
+
+EDAC authors/maintainers:
+
+ Doug Thompson, Dave Jiang, Dave Peterson et al,
+ Mauro Carvalho Chehab
+ Borislav Petkov
+ original author: Thayne Harbaugh
diff --git a/Documentation/features/arch-support.txt b/Documentation/features/arch-support.txt
new file mode 100644
index 000000000000..d22a1095e661
--- /dev/null
+++ b/Documentation/features/arch-support.txt
@@ -0,0 +1,11 @@
+
+For generic kernel features that need architecture support, the
+arch-support.txt file in each feature directory shows the arch
+support matrix, for all upstream Linux architectures.
+
+The meaning of entries in the tables is:
+
+ | ok | # feature supported by the architecture
+ |TODO| # feature not yet supported by the architecture
+ | .. | # feature cannot be supported by the hardware
+
diff --git a/Documentation/features/core/BPF-JIT/arch-support.txt b/Documentation/features/core/BPF-JIT/arch-support.txt
new file mode 100644
index 000000000000..c1b4f917238f
--- /dev/null
+++ b/Documentation/features/core/BPF-JIT/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: BPF-JIT
+# Kconfig: HAVE_BPF_JIT
+# description: arch supports BPF JIT optimizations
+#
+ -----------------------
+ | 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: | ok |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/core/generic-idle-thread/arch-support.txt b/Documentation/features/core/generic-idle-thread/arch-support.txt
new file mode 100644
index 000000000000..6d930fcbe519
--- /dev/null
+++ b/Documentation/features/core/generic-idle-thread/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: generic-idle-thread
+# Kconfig: GENERIC_SMP_IDLE_THREAD
+# description: arch makes use of the generic SMP idle thread facility
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | ok |
+ | arc: | ok |
+ | arm: | ok |
+ | arm64: | ok |
+ | avr32: | TODO |
+ | blackfin: | ok |
+ | c6x: | TODO |
+ | cris: | TODO |
+ | frv: | TODO |
+ | h8300: | TODO |
+ | hexagon: | ok |
+ | ia64: | ok |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | ok |
+ | microblaze: | TODO |
+ | mips: | ok |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | ok |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | TODO |
+ | sh: | ok |
+ | sparc: | ok |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | ok |
+ -----------------------
diff --git a/Documentation/features/core/jump-labels/arch-support.txt b/Documentation/features/core/jump-labels/arch-support.txt
new file mode 100644
index 000000000000..136868b636e6
--- /dev/null
+++ b/Documentation/features/core/jump-labels/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: jump-labels
+# Kconfig: HAVE_ARCH_JUMP_LABEL
+# description: arch supports live patched, high efficiency branches
+#
+ -----------------------
+ | 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: | ok |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/core/tracehook/arch-support.txt b/Documentation/features/core/tracehook/arch-support.txt
new file mode 100644
index 000000000000..728061d763b1
--- /dev/null
+++ b/Documentation/features/core/tracehook/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: tracehook
+# Kconfig: HAVE_ARCH_TRACEHOOK
+# description: arch supports tracehook (ptrace) register handling APIs
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | ok |
+ | arm: | ok |
+ | arm64: | ok |
+ | avr32: | TODO |
+ | blackfin: | ok |
+ | c6x: | ok |
+ | cris: | TODO |
+ | frv: | ok |
+ | h8300: | TODO |
+ | hexagon: | ok |
+ | ia64: | ok |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | ok |
+ | microblaze: | TODO |
+ | mips: | ok |
+ | mn10300: | ok |
+ | nios2: | ok |
+ | openrisc: | ok |
+ | parisc: | TODO |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | TODO |
+ | sh: | ok |
+ | sparc: | ok |
+ | tile: | ok |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/debug/KASAN/arch-support.txt b/Documentation/features/debug/KASAN/arch-support.txt
new file mode 100644
index 000000000000..14531da2fb54
--- /dev/null
+++ b/Documentation/features/debug/KASAN/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: KASAN
+# Kconfig: HAVE_ARCH_KASAN
+# description: arch supports the KASAN runtime memory checker
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | TODO |
+ | arm64: | TODO |
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/debug/gcov-profile-all/arch-support.txt b/Documentation/features/debug/gcov-profile-all/arch-support.txt
new file mode 100644
index 000000000000..38dea8eeba0a
--- /dev/null
+++ b/Documentation/features/debug/gcov-profile-all/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: gcov-profile-all
+# Kconfig: ARCH_HAS_GCOV_PROFILE_ALL
+# description: arch supports whole-kernel GCOV code coverage profiling
+#
+ -----------------------
+ | 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: | ok |
+ | mips: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | TODO |
+ | sh: | ok |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/debug/kgdb/arch-support.txt b/Documentation/features/debug/kgdb/arch-support.txt
new file mode 100644
index 000000000000..862e15d6f79e
--- /dev/null
+++ b/Documentation/features/debug/kgdb/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: kgdb
+# Kconfig: HAVE_ARCH_KGDB
+# description: arch supports the kGDB kernel debugger
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | ok |
+ | arm: | ok |
+ | arm64: | ok |
+ | avr32: | TODO |
+ | blackfin: | ok |
+ | c6x: | TODO |
+ | cris: | TODO |
+ | frv: | TODO |
+ | h8300: | TODO |
+ | hexagon: | ok |
+ | ia64: | TODO |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | TODO |
+ | microblaze: | ok |
+ | mips: | ok |
+ | mn10300: | ok |
+ | nios2: | ok |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | ok |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | ok |
+ | sparc: | ok |
+ | tile: | ok |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt b/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt
new file mode 100644
index 000000000000..40f44d041fb4
--- /dev/null
+++ b/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: kprobes-on-ftrace
+# Kconfig: HAVE_KPROBES_ON_FTRACE
+# description: arch supports combined kprobes and ftrace live patching
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | TODO |
+ | arm64: | TODO |
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/debug/kprobes/arch-support.txt b/Documentation/features/debug/kprobes/arch-support.txt
new file mode 100644
index 000000000000..a44bfff6940b
--- /dev/null
+++ b/Documentation/features/debug/kprobes/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: kprobes
+# Kconfig: HAVE_KPROBES
+# description: arch supports live patched kernel probe
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | ok |
+ | arm: | ok |
+ | arm64: | TODO |
+ | avr32: | ok |
+ | blackfin: | TODO |
+ | c6x: | TODO |
+ | cris: | TODO |
+ | frv: | TODO |
+ | h8300: | TODO |
+ | hexagon: | TODO |
+ | ia64: | ok |
+ | 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: | ok |
+ | sparc: | ok |
+ | tile: | ok |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/debug/kretprobes/arch-support.txt b/Documentation/features/debug/kretprobes/arch-support.txt
new file mode 100644
index 000000000000..d87c1ce24204
--- /dev/null
+++ b/Documentation/features/debug/kretprobes/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: kretprobes
+# Kconfig: HAVE_KRETPROBES
+# description: arch supports kernel function-return probes
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | ok |
+ | arm: | ok |
+ | arm64: | TODO |
+ | avr32: | TODO |
+ | blackfin: | TODO |
+ | c6x: | TODO |
+ | cris: | TODO |
+ | frv: | TODO |
+ | h8300: | TODO |
+ | hexagon: | TODO |
+ | ia64: | ok |
+ | 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: | ok |
+ | sparc: | ok |
+ | tile: | ok |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/debug/optprobes/arch-support.txt b/Documentation/features/debug/optprobes/arch-support.txt
new file mode 100644
index 000000000000..b8999d8544ca
--- /dev/null
+++ b/Documentation/features/debug/optprobes/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: optprobes
+# Kconfig: HAVE_OPTPROBES
+# description: arch supports live patched optprobes
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | ok |
+ | arm64: | TODO |
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | ok |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/debug/stackprotector/arch-support.txt b/Documentation/features/debug/stackprotector/arch-support.txt
new file mode 100644
index 000000000000..0fa423313409
--- /dev/null
+++ b/Documentation/features/debug/stackprotector/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: stackprotector
+# Kconfig: HAVE_CC_STACKPROTECTOR
+# description: arch supports compiler driven stack overflow protection
+#
+ -----------------------
+ | 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: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | ok |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/debug/uprobes/arch-support.txt b/Documentation/features/debug/uprobes/arch-support.txt
new file mode 100644
index 000000000000..4efe36c3ace9
--- /dev/null
+++ b/Documentation/features/debug/uprobes/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: uprobes
+# Kconfig: ARCH_SUPPORTS_UPROBES
+# description: arch supports live patched user probes
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | ok |
+ | arm64: | TODO |
+ | 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: | TODO |
+ | 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/features/debug/user-ret-profiler/arch-support.txt b/Documentation/features/debug/user-ret-profiler/arch-support.txt
new file mode 100644
index 000000000000..44cc1ff3f603
--- /dev/null
+++ b/Documentation/features/debug/user-ret-profiler/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: user-ret-profiler
+# Kconfig: HAVE_USER_RETURN_NOTIFIER
+# description: arch supports user-space return from system call profiler
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | TODO |
+ | arm64: | TODO |
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | ok |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/io/dma-api-debug/arch-support.txt b/Documentation/features/io/dma-api-debug/arch-support.txt
new file mode 100644
index 000000000000..4f4a3443b114
--- /dev/null
+++ b/Documentation/features/io/dma-api-debug/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: dma-api-debug
+# Kconfig: HAVE_DMA_API_DEBUG
+# description: arch supports DMA debug facilities
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | ok |
+ | arm64: | ok |
+ | avr32: | TODO |
+ | blackfin: | TODO |
+ | c6x: | ok |
+ | cris: | TODO |
+ | frv: | TODO |
+ | h8300: | TODO |
+ | hexagon: | TODO |
+ | ia64: | ok |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | TODO |
+ | microblaze: | ok |
+ | mips: | ok |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | TODO |
+ | sh: | ok |
+ | sparc: | ok |
+ | tile: | ok |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/io/dma-contiguous/arch-support.txt b/Documentation/features/io/dma-contiguous/arch-support.txt
new file mode 100644
index 000000000000..a97e8e3f4ebb
--- /dev/null
+++ b/Documentation/features/io/dma-contiguous/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: dma-contiguous
+# Kconfig: HAVE_DMA_CONTIGUOUS
+# description: arch supports the DMA CMA (continuous memory allocator)
+#
+ -----------------------
+ | 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: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/io/dma_map_attrs/arch-support.txt b/Documentation/features/io/dma_map_attrs/arch-support.txt
new file mode 100644
index 000000000000..51d0f1c02a3e
--- /dev/null
+++ b/Documentation/features/io/dma_map_attrs/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: dma_map_attrs
+# Kconfig: HAVE_DMA_ATTRS
+# description: arch provides dma_*map*_attrs() APIs
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | ok |
+ | arc: | TODO |
+ | arm: | ok |
+ | arm64: | ok |
+ | avr32: | TODO |
+ | blackfin: | TODO |
+ | c6x: | TODO |
+ | cris: | TODO |
+ | frv: | TODO |
+ | h8300: | ok |
+ | hexagon: | ok |
+ | ia64: | ok |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | TODO |
+ | microblaze: | ok |
+ | mips: | ok |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | ok |
+ | parisc: | TODO |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | TODO |
+ | sh: | ok |
+ | sparc: | ok |
+ | tile: | ok |
+ | um: | TODO |
+ | unicore32: | ok |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/io/sg-chain/arch-support.txt b/Documentation/features/io/sg-chain/arch-support.txt
new file mode 100644
index 000000000000..b9b675539b9d
--- /dev/null
+++ b/Documentation/features/io/sg-chain/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: sg-chain
+# Kconfig: ARCH_HAS_SG_CHAIN
+# description: arch supports chained scatter-gather lists
+#
+ -----------------------
+ | 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: | ok |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | TODO |
+ | microblaze: | TODO |
+ | mips: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | ok |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/lib/strncasecmp/arch-support.txt b/Documentation/features/lib/strncasecmp/arch-support.txt
new file mode 100644
index 000000000000..12b1c9358e57
--- /dev/null
+++ b/Documentation/features/lib/strncasecmp/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: strncasecmp
+# Kconfig: __HAVE_ARCH_STRNCASECMP
+# description: arch provides an optimized strncasecmp() function
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | TODO |
+ | arm64: | TODO |
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | TODO |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/list-arch.sh b/Documentation/features/list-arch.sh
new file mode 100755
index 000000000000..6065124a072f
--- /dev/null
+++ b/Documentation/features/list-arch.sh
@@ -0,0 +1,24 @@
+#
+# Small script that visualizes the kernel feature support status
+# of an architecture.
+#
+# (If no arguments are given then it will print the host architecture's status.)
+#
+
+ARCH=${1:-$(arch | sed 's/x86_64/x86/' | sed 's/i386/x86/')}
+
+cd $(dirname $0)
+echo "#"
+echo "# Kernel feature support matrix of the '$ARCH' architecture:"
+echo "#"
+
+for F in */*/arch-support.txt; do
+ SUBSYS=$(echo $F | cut -d/ -f1)
+ N=$(grep -h "^# Feature name:" $F | cut -c25-)
+ C=$(grep -h "^# Kconfig:" $F | cut -c25-)
+ D=$(grep -h "^# description:" $F | cut -c25-)
+ S=$(grep -hw $ARCH $F | cut -d\| -f3)
+
+ printf "%10s/%-22s:%s| %35s # %s\n" "$SUBSYS" "$N" "$S" "$C" "$D"
+done
+
diff --git a/Documentation/features/locking/cmpxchg-local/arch-support.txt b/Documentation/features/locking/cmpxchg-local/arch-support.txt
new file mode 100644
index 000000000000..d9c310889bc1
--- /dev/null
+++ b/Documentation/features/locking/cmpxchg-local/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: cmpxchg-local
+# Kconfig: HAVE_CMPXCHG_LOCAL
+# description: arch supports the this_cpu_cmpxchg() API
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | TODO |
+ | arm64: | TODO |
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | ok |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/locking/lockdep/arch-support.txt b/Documentation/features/locking/lockdep/arch-support.txt
new file mode 100644
index 000000000000..cf90635bdcbb
--- /dev/null
+++ b/Documentation/features/locking/lockdep/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: lockdep
+# Kconfig: LOCKDEP_SUPPORT
+# description: arch supports the runtime locking correctness debug facility
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | ok |
+ | arm: | ok |
+ | arm64: | ok |
+ | avr32: | ok |
+ | blackfin: | ok |
+ | c6x: | TODO |
+ | cris: | TODO |
+ | frv: | TODO |
+ | h8300: | TODO |
+ | hexagon: | ok |
+ | ia64: | TODO |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | ok |
+ | microblaze: | ok |
+ | mips: | ok |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | ok |
+ | sh: | ok |
+ | sparc: | ok |
+ | tile: | ok |
+ | um: | ok |
+ | unicore32: | ok |
+ | x86: | ok |
+ | xtensa: | ok |
+ -----------------------
diff --git a/Documentation/features/locking/queued-rwlocks/arch-support.txt b/Documentation/features/locking/queued-rwlocks/arch-support.txt
new file mode 100644
index 000000000000..68c3a5ddd9b9
--- /dev/null
+++ b/Documentation/features/locking/queued-rwlocks/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: queued-rwlocks
+# Kconfig: ARCH_USE_QUEUED_RWLOCKS
+# description: arch supports queued rwlocks
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | TODO |
+ | arm64: | TODO |
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/locking/queued-spinlocks/arch-support.txt b/Documentation/features/locking/queued-spinlocks/arch-support.txt
new file mode 100644
index 000000000000..e973b1a9572f
--- /dev/null
+++ b/Documentation/features/locking/queued-spinlocks/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: queued-spinlocks
+# Kconfig: ARCH_USE_QUEUED_SPINLOCKS
+# description: arch supports queued spinlocks
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | TODO |
+ | arm64: | TODO |
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/locking/rwsem-optimized/arch-support.txt b/Documentation/features/locking/rwsem-optimized/arch-support.txt
new file mode 100644
index 000000000000..ac93d7ab66c4
--- /dev/null
+++ b/Documentation/features/locking/rwsem-optimized/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: rwsem-optimized
+# Kconfig: Optimized asm/rwsem.h
+# description: arch provides optimized rwsem APIs
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | ok |
+ | arc: | TODO |
+ | arm: | TODO |
+ | arm64: | TODO |
+ | avr32: | TODO |
+ | blackfin: | TODO |
+ | c6x: | TODO |
+ | cris: | TODO |
+ | frv: | TODO |
+ | h8300: | TODO |
+ | hexagon: | TODO |
+ | ia64: | ok |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | TODO |
+ | microblaze: | TODO |
+ | mips: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | ok |
+ | score: | TODO |
+ | sh: | ok |
+ | sparc: | ok |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | ok |
+ -----------------------
diff --git a/Documentation/features/perf/kprobes-event/arch-support.txt b/Documentation/features/perf/kprobes-event/arch-support.txt
new file mode 100644
index 000000000000..9855ad044386
--- /dev/null
+++ b/Documentation/features/perf/kprobes-event/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: kprobes-event
+# Kconfig: HAVE_REGS_AND_STACK_ACCESS_API
+# description: arch supports kprobes with perf events
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | ok |
+ | arm64: | TODO |
+ | avr32: | TODO |
+ | blackfin: | TODO |
+ | c6x: | TODO |
+ | cris: | TODO |
+ | frv: | TODO |
+ | h8300: | TODO |
+ | hexagon: | ok |
+ | ia64: | TODO |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | TODO |
+ | microblaze: | TODO |
+ | mips: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | TODO |
+ | sh: | ok |
+ | sparc: | TODO |
+ | tile: | ok |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/perf/perf-regs/arch-support.txt b/Documentation/features/perf/perf-regs/arch-support.txt
new file mode 100644
index 000000000000..e2b4a78ec543
--- /dev/null
+++ b/Documentation/features/perf/perf-regs/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: perf-regs
+# Kconfig: HAVE_PERF_REGS
+# description: arch supports perf events register access
+#
+ -----------------------
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/perf/perf-stackdump/arch-support.txt b/Documentation/features/perf/perf-stackdump/arch-support.txt
new file mode 100644
index 000000000000..3dc24b0673c0
--- /dev/null
+++ b/Documentation/features/perf/perf-stackdump/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: perf-stackdump
+# Kconfig: HAVE_PERF_USER_STACK_DUMP
+# description: arch supports perf events stack dumps
+#
+ -----------------------
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/sched/numa-balancing/arch-support.txt b/Documentation/features/sched/numa-balancing/arch-support.txt
new file mode 100644
index 000000000000..ac7cd6b1502b
--- /dev/null
+++ b/Documentation/features/sched/numa-balancing/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: numa-balancing
+# Kconfig: ARCH_SUPPORTS_NUMA_BALANCING
+# description: arch supports NUMA balancing
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | .. |
+ | arm: | .. |
+ | arm64: | .. |
+ | avr32: | .. |
+ | blackfin: | .. |
+ | c6x: | .. |
+ | cris: | .. |
+ | frv: | .. |
+ | h8300: | .. |
+ | hexagon: | .. |
+ | ia64: | TODO |
+ | m32r: | .. |
+ | m68k: | .. |
+ | metag: | .. |
+ | microblaze: | .. |
+ | mips: | TODO |
+ | mn10300: | .. |
+ | nios2: | .. |
+ | openrisc: | .. |
+ | parisc: | .. |
+ | powerpc: | ok |
+ | s390: | .. |
+ | score: | .. |
+ | sh: | .. |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | .. |
+ | unicore32: | .. |
+ | x86: | ok |
+ | xtensa: | .. |
+ -----------------------
diff --git a/Documentation/features/seccomp/seccomp-filter/arch-support.txt b/Documentation/features/seccomp/seccomp-filter/arch-support.txt
new file mode 100644
index 000000000000..bea800910342
--- /dev/null
+++ b/Documentation/features/seccomp/seccomp-filter/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: seccomp-filter
+# Kconfig: HAVE_ARCH_SECCOMP_FILTER
+# description: arch supports seccomp filters
+#
+ -----------------------
+ | 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: | TODO |
+ | s390: | ok |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/time/arch-tick-broadcast/arch-support.txt b/Documentation/features/time/arch-tick-broadcast/arch-support.txt
new file mode 100644
index 000000000000..8acb439a4a17
--- /dev/null
+++ b/Documentation/features/time/arch-tick-broadcast/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: arch-tick-broadcast
+# Kconfig: ARCH_HAS_TICK_BROADCAST
+# description: arch provides tick_broadcast()
+#
+ -----------------------
+ | 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: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | TODO |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/time/clockevents/arch-support.txt b/Documentation/features/time/clockevents/arch-support.txt
new file mode 100644
index 000000000000..ff670b2207f1
--- /dev/null
+++ b/Documentation/features/time/clockevents/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: clockevents
+# Kconfig: GENERIC_CLOCKEVENTS
+# description: arch support generic clock events
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | ok |
+ | arc: | ok |
+ | arm: | ok |
+ | arm64: | ok |
+ | avr32: | ok |
+ | blackfin: | ok |
+ | c6x: | ok |
+ | cris: | ok |
+ | frv: | TODO |
+ | h8300: | ok |
+ | hexagon: | ok |
+ | ia64: | TODO |
+ | m32r: | TODO |
+ | m68k: | ok |
+ | metag: | ok |
+ | microblaze: | ok |
+ | mips: | ok |
+ | mn10300: | ok |
+ | nios2: | ok |
+ | openrisc: | ok |
+ | parisc: | TODO |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | ok |
+ | sh: | ok |
+ | sparc: | ok |
+ | tile: | ok |
+ | um: | ok |
+ | unicore32: | ok |
+ | x86: | ok |
+ | xtensa: | ok |
+ -----------------------
diff --git a/Documentation/features/time/context-tracking/arch-support.txt b/Documentation/features/time/context-tracking/arch-support.txt
new file mode 100644
index 000000000000..a1e3eea7003f
--- /dev/null
+++ b/Documentation/features/time/context-tracking/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: context-tracking
+# Kconfig: HAVE_CONTEXT_TRACKING
+# description: arch supports context tracking for NO_HZ_FULL
+#
+ -----------------------
+ | 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: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | ok |
+ | tile: | ok |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/time/irq-time-acct/arch-support.txt b/Documentation/features/time/irq-time-acct/arch-support.txt
new file mode 100644
index 000000000000..e63316239938
--- /dev/null
+++ b/Documentation/features/time/irq-time-acct/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: irq-time-acct
+# Kconfig: HAVE_IRQ_TIME_ACCOUNTING
+# description: arch supports precise IRQ time accounting
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | .. |
+ | arc: | TODO |
+ | arm: | ok |
+ | arm64: | .. |
+ | avr32: | TODO |
+ | blackfin: | TODO |
+ | c6x: | TODO |
+ | cris: | TODO |
+ | frv: | TODO |
+ | h8300: | TODO |
+ | hexagon: | TODO |
+ | ia64: | .. |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | TODO |
+ | microblaze: | TODO |
+ | mips: | ok |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | .. |
+ | powerpc: | .. |
+ | s390: | .. |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | .. |
+ | tile: | .. |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | ok |
+ -----------------------
diff --git a/Documentation/features/time/modern-timekeeping/arch-support.txt b/Documentation/features/time/modern-timekeeping/arch-support.txt
new file mode 100644
index 000000000000..17f68a02e84d
--- /dev/null
+++ b/Documentation/features/time/modern-timekeeping/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: modern-timekeeping
+# Kconfig: !ARCH_USES_GETTIMEOFFSET
+# description: arch does not use arch_gettimeoffset() anymore
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | ok |
+ | arc: | ok |
+ | arm: | TODO |
+ | arm64: | ok |
+ | avr32: | ok |
+ | blackfin: | TODO |
+ | c6x: | ok |
+ | cris: | TODO |
+ | frv: | ok |
+ | h8300: | ok |
+ | hexagon: | ok |
+ | ia64: | ok |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | ok |
+ | microblaze: | ok |
+ | mips: | ok |
+ | mn10300: | ok |
+ | nios2: | ok |
+ | openrisc: | ok |
+ | parisc: | ok |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | ok |
+ | sh: | ok |
+ | sparc: | ok |
+ | tile: | ok |
+ | um: | ok |
+ | unicore32: | ok |
+ | x86: | ok |
+ | xtensa: | ok |
+ -----------------------
diff --git a/Documentation/features/time/virt-cpuacct/arch-support.txt b/Documentation/features/time/virt-cpuacct/arch-support.txt
new file mode 100644
index 000000000000..cf3c3e383d15
--- /dev/null
+++ b/Documentation/features/time/virt-cpuacct/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: virt-cpuacct
+# Kconfig: HAVE_VIRT_CPU_ACCOUNTING
+# description: arch supports precise virtual CPU time accounting
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | ok |
+ | arc: | TODO |
+ | arm: | ok |
+ | arm64: | ok |
+ | avr32: | TODO |
+ | blackfin: | TODO |
+ | c6x: | TODO |
+ | cris: | TODO |
+ | frv: | TODO |
+ | h8300: | TODO |
+ | hexagon: | TODO |
+ | ia64: | ok |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | TODO |
+ | microblaze: | TODO |
+ | mips: | ok |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | ok |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | ok |
+ | tile: | ok |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/vm/ELF-ASLR/arch-support.txt b/Documentation/features/vm/ELF-ASLR/arch-support.txt
new file mode 100644
index 000000000000..ec4dd28e1297
--- /dev/null
+++ b/Documentation/features/vm/ELF-ASLR/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: ELF-ASLR
+# Kconfig: ARCH_HAS_ELF_RANDOMIZE
+# description: arch randomizes the stack, heap and binary images of ELF binaries
+#
+ -----------------------
+ | 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/features/vm/PG_uncached/arch-support.txt b/Documentation/features/vm/PG_uncached/arch-support.txt
new file mode 100644
index 000000000000..991974275a3e
--- /dev/null
+++ b/Documentation/features/vm/PG_uncached/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: PG_uncached
+# Kconfig: ARCH_USES_PG_UNCACHED
+# description: arch supports the PG_uncached page flag
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | TODO |
+ | arm64: | TODO |
+ | avr32: | TODO |
+ | blackfin: | TODO |
+ | c6x: | TODO |
+ | cris: | TODO |
+ | frv: | TODO |
+ | h8300: | TODO |
+ | hexagon: | TODO |
+ | ia64: | ok |
+ | m32r: | TODO |
+ | m68k: | TODO |
+ | metag: | TODO |
+ | microblaze: | TODO |
+ | mips: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/vm/THP/arch-support.txt b/Documentation/features/vm/THP/arch-support.txt
new file mode 100644
index 000000000000..972d02c2a74c
--- /dev/null
+++ b/Documentation/features/vm/THP/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: THP
+# Kconfig: HAVE_ARCH_TRANSPARENT_HUGEPAGE
+# description: arch supports transparent hugepages
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | .. |
+ | arm: | ok |
+ | arm64: | ok |
+ | avr32: | .. |
+ | blackfin: | .. |
+ | c6x: | .. |
+ | cris: | .. |
+ | frv: | .. |
+ | h8300: | .. |
+ | hexagon: | .. |
+ | ia64: | TODO |
+ | m32r: | .. |
+ | m68k: | .. |
+ | metag: | .. |
+ | microblaze: | .. |
+ | mips: | ok |
+ | mn10300: | .. |
+ | nios2: | .. |
+ | openrisc: | .. |
+ | parisc: | TODO |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | .. |
+ | sh: | .. |
+ | sparc: | ok |
+ | tile: | TODO |
+ | um: | .. |
+ | unicore32: | .. |
+ | x86: | ok |
+ | xtensa: | .. |
+ -----------------------
diff --git a/Documentation/features/vm/huge-vmap/arch-support.txt b/Documentation/features/vm/huge-vmap/arch-support.txt
new file mode 100644
index 000000000000..af6816bccb43
--- /dev/null
+++ b/Documentation/features/vm/huge-vmap/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: huge-vmap
+# Kconfig: HAVE_ARCH_HUGE_VMAP
+# description: arch supports the ioremap_pud_enabled() and ioremap_pmd_enabled() VM APIs
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | TODO |
+ | arm: | TODO |
+ | arm64: | TODO |
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | TODO |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | TODO |
+ | sparc: | TODO |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/vm/ioremap_prot/arch-support.txt b/Documentation/features/vm/ioremap_prot/arch-support.txt
new file mode 100644
index 000000000000..90c53749fde7
--- /dev/null
+++ b/Documentation/features/vm/ioremap_prot/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: ioremap_prot
+# Kconfig: HAVE_IOREMAP_PROT
+# description: arch has ioremap_prot()
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | ok |
+ | arm: | TODO |
+ | arm64: | TODO |
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | ok |
+ | s390: | TODO |
+ | score: | TODO |
+ | sh: | ok |
+ | sparc: | TODO |
+ | tile: | ok |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/features/vm/numa-memblock/arch-support.txt b/Documentation/features/vm/numa-memblock/arch-support.txt
new file mode 100644
index 000000000000..e7c252a0c531
--- /dev/null
+++ b/Documentation/features/vm/numa-memblock/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: numa-memblock
+# Kconfig: HAVE_MEMBLOCK_NODE_MAP
+# description: arch supports NUMA aware memblocks
+#
+ -----------------------
+ | arch |status|
+ -----------------------
+ | alpha: | TODO |
+ | arc: | .. |
+ | arm: | .. |
+ | arm64: | .. |
+ | avr32: | .. |
+ | blackfin: | .. |
+ | c6x: | .. |
+ | cris: | .. |
+ | frv: | .. |
+ | h8300: | .. |
+ | hexagon: | .. |
+ | ia64: | ok |
+ | m32r: | TODO |
+ | m68k: | .. |
+ | metag: | ok |
+ | microblaze: | ok |
+ | mips: | ok |
+ | mn10300: | TODO |
+ | nios2: | .. |
+ | openrisc: | .. |
+ | parisc: | .. |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | ok |
+ | sh: | ok |
+ | sparc: | ok |
+ | tile: | TODO |
+ | um: | .. |
+ | unicore32: | .. |
+ | x86: | ok |
+ | xtensa: | .. |
+ -----------------------
diff --git a/Documentation/features/vm/pmdp_splitting_flush/arch-support.txt b/Documentation/features/vm/pmdp_splitting_flush/arch-support.txt
new file mode 100644
index 000000000000..26f74b457e0b
--- /dev/null
+++ b/Documentation/features/vm/pmdp_splitting_flush/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# 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/features/vm/pte_special/arch-support.txt b/Documentation/features/vm/pte_special/arch-support.txt
new file mode 100644
index 000000000000..aaaa21db6226
--- /dev/null
+++ b/Documentation/features/vm/pte_special/arch-support.txt
@@ -0,0 +1,40 @@
+#
+# Feature name: pte_special
+# Kconfig: __HAVE_ARCH_PTE_SPECIAL
+# description: arch supports the pte_special()/pte_mkspecial() VM APIs
+#
+ -----------------------
+ | 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: | TODO |
+ | mn10300: | TODO |
+ | nios2: | TODO |
+ | openrisc: | TODO |
+ | parisc: | TODO |
+ | powerpc: | ok |
+ | s390: | ok |
+ | score: | TODO |
+ | sh: | ok |
+ | sparc: | ok |
+ | tile: | TODO |
+ | um: | TODO |
+ | unicore32: | TODO |
+ | x86: | ok |
+ | xtensa: | TODO |
+ -----------------------
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 0a926e2ba3ab..6a34a0f4d37c 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -50,8 +50,8 @@ prototypes:
int (*rename2) (struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
int (*readlink) (struct dentry *, char __user *,int);
- void * (*follow_link) (struct dentry *, struct nameidata *);
- void (*put_link) (struct dentry *, struct nameidata *, void *);
+ const char *(*follow_link) (struct dentry *, void **);
+ void (*put_link) (struct inode *, void *);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int, unsigned int);
int (*get_acl)(struct inode *, int);
diff --git a/Documentation/filesystems/automount-support.txt b/Documentation/filesystems/automount-support.txt
index 7cac200e2a85..7eb762eb3136 100644
--- a/Documentation/filesystems/automount-support.txt
+++ b/Documentation/filesystems/automount-support.txt
@@ -1,41 +1,15 @@
-Support is available for filesystems that wish to do automounting support (such
-as kAFS which can be found in fs/afs/). This facility includes allowing
-in-kernel mounts to be performed and mountpoint degradation to be
-requested. The latter can also be requested by userspace.
+Support is available for filesystems that wish to do automounting
+support (such as kAFS which can be found in fs/afs/ and NFS in
+fs/nfs/). This facility includes allowing in-kernel mounts to be
+performed and mountpoint degradation to be requested. The latter can
+also be requested by userspace.
======================
IN-KERNEL AUTOMOUNTING
======================
-A filesystem can now mount another filesystem on one of its directories by the
-following procedure:
-
- (1) Give the directory a follow_link() operation.
-
- When the directory is accessed, the follow_link op will be called, and
- it will be provided with the location of the mountpoint in the nameidata
- structure (vfsmount and dentry).
-
- (2) Have the follow_link() op do the following steps:
-
- (a) Call vfs_kern_mount() to call the appropriate filesystem to set up a
- superblock and gain a vfsmount structure representing it.
-
- (b) Copy the nameidata provided as an argument and substitute the dentry
- argument into it the copy.
-
- (c) Call do_add_mount() to install the new vfsmount into the namespace's
- mountpoint tree, thus making it accessible to userspace. Use the
- nameidata set up in (b) as the destination.
-
- If the mountpoint will be automatically expired, then do_add_mount()
- should also be given the location of an expiration list (see further
- down).
-
- (d) Release the path in the nameidata argument and substitute in the new
- vfsmount and its root dentry. The ref counts on these will need
- incrementing.
+See section "Mount Traps" of Documentation/filesystems/autofs4.txt
Then from userspace, you can just do something like:
@@ -61,17 +35,18 @@ AUTOMATIC MOUNTPOINT EXPIRY
===========================
Automatic expiration of mountpoints is easy, provided you've mounted the
-mountpoint to be expired in the automounting procedure outlined above.
+mountpoint to be expired in the automounting procedure outlined separately.
To do expiration, you need to follow these steps:
- (3) Create at least one list off which the vfsmounts to be expired can be
- hung. Access to this list will be governed by the vfsmount_lock.
+ (1) Create at least one list off which the vfsmounts to be expired can be
+ hung.
- (4) In step (2c) above, the call to do_add_mount() should be provided with a
- pointer to this list. It will hang the vfsmount off of it if it succeeds.
+ (2) When a new mountpoint is created in the ->d_automount method, add
+ the mnt to the list using mnt_set_expiry()
+ mnt_set_expiry(newmnt, &afs_vfsmounts);
- (5) When you want mountpoints to be expired, call mark_mounts_for_expiry()
+ (3) When you want mountpoints to be expired, call mark_mounts_for_expiry()
with a pointer to this list. This will process the list, marking every
vfsmount thereon for potential expiry on the next call.
diff --git a/Documentation/filesystems/nfs/knfsd-stats.txt b/Documentation/filesystems/nfs/knfsd-stats.txt
index 64ced5149d37..1a5d82180b84 100644
--- a/Documentation/filesystems/nfs/knfsd-stats.txt
+++ b/Documentation/filesystems/nfs/knfsd-stats.txt
@@ -68,16 +68,10 @@ sockets-enqueued
rate of change for this counter is zero; significantly non-zero
values may indicate a performance limitation.
- This can happen either because there are too few nfsd threads in the
- thread pool for the NFS workload (the workload is thread-limited),
- or because the NFS workload needs more CPU time than is available in
- the thread pool (the workload is CPU-limited). In the former case,
- configuring more nfsd threads will probably improve the performance
- of the NFS workload. In the latter case, the sunrpc server layer is
- already choosing not to wake idle nfsd threads because there are too
- many nfsd threads which want to run but cannot, so configuring more
- nfsd threads will make no difference whatsoever. The overloads-avoided
- statistic (see below) can be used to distinguish these cases.
+ This can happen because there are too few nfsd threads in the thread
+ pool for the NFS workload (the workload is thread-limited), in which
+ case configuring more nfsd threads will probably improve the
+ performance of the NFS workload.
threads-woken
Counts how many times an idle nfsd thread is woken to try to
@@ -88,36 +82,6 @@ threads-woken
thing. The ideal rate of change for this counter will be close
to but less than the rate of change of the packets-arrived counter.
-overloads-avoided
- Counts how many times the sunrpc server layer chose not to wake an
- nfsd thread, despite the presence of idle nfsd threads, because
- too many nfsd threads had been recently woken but could not get
- enough CPU time to actually run.
-
- This statistic counts a circumstance where the sunrpc layer
- heuristically avoids overloading the CPU scheduler with too many
- runnable nfsd threads. The ideal rate of change for this counter
- is zero. Significant non-zero values indicate that the workload
- is CPU limited. Usually this is associated with heavy CPU usage
- on all the CPUs in the nfsd thread pool.
-
- If a sustained large overloads-avoided rate is detected on a pool,
- the top(1) utility should be used to check for the following
- pattern of CPU usage on all the CPUs associated with the given
- nfsd thread pool.
-
- - %us ~= 0 (as you're *NOT* running applications on your NFS server)
-
- - %wa ~= 0
-
- - %id ~= 0
-
- - %sy + %hi + %si ~= 100
-
- If this pattern is seen, configuring more nfsd threads will *not*
- improve the performance of the workload. If this patten is not
- seen, then something more subtle is wrong.
-
threads-timedout
Counts how many times an nfsd thread triggered an idle timeout,
i.e. was not woken to handle any incoming network packets for
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index e69274de8d0c..68f1c9106573 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -379,10 +379,10 @@ may now be called in rcu-walk mode (nd->flags & LOOKUP_RCU). -ECHILD should be
returned if the filesystem cannot handle rcu-walk. See
Documentation/filesystems/vfs.txt for more details.
- permission and check_acl are inode permission checks that are called
-on many or all directory inodes on the way down a path walk (to check for
-exec permission). These must now be rcu-walk aware (flags & IPERM_FLAG_RCU).
-See Documentation/filesystems/vfs.txt for more details.
+ permission is an inode permission check that is called on many or all
+directory inodes on the way down a path walk (to check for exec permission). It
+must now be rcu-walk aware (mask & MAY_NOT_BLOCK). See
+Documentation/filesystems/vfs.txt for more details.
--
[mandatory]
@@ -483,3 +483,20 @@ in your dentry operations instead.
--
[mandatory]
->aio_read/->aio_write are gone. Use ->read_iter/->write_iter.
+---
+[recommended]
+ for embedded ("fast") symlinks just set inode->i_link to wherever the
+ symlink body is and use simple_follow_link() as ->follow_link().
+--
+[mandatory]
+ calling conventions for ->follow_link() have changed. Instead of returning
+ cookie and using nd_set_link() to store the body to traverse, we return
+ the body to traverse and store the cookie using explicit void ** argument.
+ nameidata isn't passed at all - nd_jump_link() doesn't need it and
+ nd_[gs]et_link() is gone.
+--
+[mandatory]
+ calling conventions for ->put_link() have changed. It gets inode instead of
+ dentry, it does not get nameidata at all and it gets called only when cookie
+ is non-NULL. Note that link body isn't available anymore, so if you need it,
+ store it as cookie.
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index c3b6b301d8b0..6f7fafde0884 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -205,7 +205,7 @@ asynchronous manner and the value may not be very precise. To see a precise
snapshot of a moment, you can see /proc/<pid>/smaps file and scan page table.
It's slow but very precise.
-Table 1-2: Contents of the status files (as of 3.20.0)
+Table 1-2: Contents of the status files (as of 4.1)
..............................................................................
Field Content
Name filename of the executable
@@ -235,6 +235,7 @@ Table 1-2: Contents of the status files (as of 3.20.0)
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)
Threads number of threads
SigQ number of signals queued/max. number for queue
diff --git a/Documentation/filesystems/quota.txt b/Documentation/filesystems/quota.txt
index 5e8de25bf0f1..29fc01552646 100644
--- a/Documentation/filesystems/quota.txt
+++ b/Documentation/filesystems/quota.txt
@@ -32,7 +32,10 @@ The interface uses generic netlink framework (see
http://lwn.net/Articles/208755/ and http://people.suug.ch/~tgr/libnl/ for more
details about this layer). The name of the quota generic netlink interface
is "VFS_DQUOT". Definitions of constants below are in <linux/quota.h>.
- Currently, the interface supports only one message type QUOTA_NL_C_WARNING.
+Since the quota netlink protocol is not namespace aware, quota netlink messages
+are sent only in initial network namespace.
+
+Currently, the interface supports only one message type QUOTA_NL_C_WARNING.
This command is used to send a notification about any of the above mentioned
events. Each message has six attributes. These are (type of the argument is
in parentheses):
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 5d833b32bbcd..5eb8456fc41e 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -350,8 +350,8 @@ struct inode_operations {
int (*rename2) (struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
int (*readlink) (struct dentry *, char __user *,int);
- void * (*follow_link) (struct dentry *, struct nameidata *);
- void (*put_link) (struct dentry *, struct nameidata *, void *);
+ const char *(*follow_link) (struct dentry *, void **);
+ void (*put_link) (struct inode *, void *);
int (*permission) (struct inode *, int);
int (*get_acl)(struct inode *, int);
int (*setattr) (struct dentry *, struct iattr *);
@@ -436,16 +436,18 @@ otherwise noted.
follow_link: called by the VFS to follow a symbolic link to the
inode it points to. Only required if you want to support
- symbolic links. This method returns a void pointer cookie
- that is passed to put_link().
+ symbolic links. This method returns the symlink body
+ to traverse (and possibly resets the current position with
+ nd_jump_link()). If the body won't go away until the inode
+ is gone, nothing else is needed; if it needs to be otherwise
+ pinned, the data needed to release whatever we'd grabbed
+ is to be stored in void * variable passed by address to
+ follow_link() instance.
put_link: called by the VFS to release resources allocated by
- follow_link(). The cookie returned by follow_link() is passed
- to this method as the last parameter. It is used by
- filesystems such as NFS where page cache is not stable
- (i.e. page that was installed when the symbolic link walk
- started might not be in the page cache at the end of the
- walk).
+ follow_link(). The cookie stored by follow_link() is passed
+ to this method as the last parameter; only called when
+ cookie isn't NULL.
permission: called by the VFS to check for access rights on a POSIX-like
filesystem.
@@ -797,7 +799,7 @@ struct file_operations
----------------------
This describes how the VFS can manipulate an open file. As of kernel
-3.12, the following members are defined:
+4.1, the following members are defined:
struct file_operations {
struct module *owner;
@@ -811,8 +813,9 @@ struct file_operations {
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
+ int (*mremap)(struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
- int (*flush) (struct file *);
+ int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
@@ -822,11 +825,15 @@ struct file_operations {
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
- ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int);
- ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int);
- int (*setlease)(struct file *, long arg, struct file_lock **, void **);
- long (*fallocate)(struct file *, int mode, loff_t offset, loff_t len);
+ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
+ ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
+ int (*setlease)(struct file *, long, struct file_lock **, void **);
+ long (*fallocate)(struct file *file, int mode, loff_t offset,
+ loff_t len);
void (*show_fdinfo)(struct seq_file *m, struct file *f);
+#ifndef CONFIG_MMU
+ unsigned (*mmap_capabilities)(struct file *);
+#endif
};
Again, all methods are called without any locks being held, unless
diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt
index c21c1313f09e..75542b91b766 100644
--- a/Documentation/gpio/consumer.txt
+++ b/Documentation/gpio/consumer.txt
@@ -241,18 +241,18 @@ Set multiple GPIO outputs with a single function call
-----------------------------------------------------
The following functions set the output values of an array of GPIOs:
- void gpiod_set_array(unsigned int array_size,
- struct gpio_desc **desc_array,
- int *value_array)
- void gpiod_set_raw_array(unsigned int array_size,
- struct gpio_desc **desc_array,
- int *value_array)
- void gpiod_set_array_cansleep(unsigned int array_size,
- struct gpio_desc **desc_array,
- int *value_array)
- void gpiod_set_raw_array_cansleep(unsigned int array_size,
- struct gpio_desc **desc_array,
- int *value_array)
+ void gpiod_set_array_value(unsigned int array_size,
+ struct gpio_desc **desc_array,
+ int *value_array)
+ void gpiod_set_raw_array_value(unsigned int array_size,
+ struct gpio_desc **desc_array,
+ int *value_array)
+ void gpiod_set_array_value_cansleep(unsigned int array_size,
+ struct gpio_desc **desc_array,
+ int *value_array)
+ void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
+ struct gpio_desc **desc_array,
+ int *value_array)
The array can be an arbitrary set of GPIOs. The functions will try to set
GPIOs belonging to the same bank or chip simultaneously if supported by the
@@ -271,8 +271,8 @@ matches the desired group of GPIOs, those GPIOs can be set by simply using
the struct gpio_descs returned by gpiod_get_array():
struct gpio_descs *my_gpio_descs = gpiod_get_array(...);
- gpiod_set_array(my_gpio_descs->ndescs, my_gpio_descs->desc,
- my_gpio_values);
+ gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc,
+ my_gpio_values);
It is also possible to set a completely arbitrary array of descriptors. The
descriptors may be obtained using any combination of gpiod_get() and
@@ -290,7 +290,7 @@ corresponding to a given GPIO using the following call:
int gpiod_to_irq(const struct gpio_desc *desc)
-It will return an IRQ number, or an negative errno code if the mapping can't be
+It will return an IRQ number, or a negative errno code if the mapping can't be
done (most likely because that particular GPIO cannot be used as IRQ). It is an
unchecked error to use a GPIO that wasn't set up as an input using
gpiod_direction_input(), or to use an IRQ number that didn't originally come
diff --git a/Documentation/gpio/gpio-legacy.txt b/Documentation/gpio/gpio-legacy.txt
index 6f83fa965b4b..79ab5648d69b 100644
--- a/Documentation/gpio/gpio-legacy.txt
+++ b/Documentation/gpio/gpio-legacy.txt
@@ -751,9 +751,6 @@ requested using gpio_request():
int gpio_export_link(struct device *dev, const char *name,
unsigned gpio)
- /* change the polarity of a GPIO node in sysfs */
- int gpio_sysfs_set_active_low(unsigned gpio, int value);
-
After a kernel driver requests a GPIO, it may only be made available in
the sysfs interface by gpio_export(). The driver can control whether the
signal direction may change. This helps drivers prevent userspace code
@@ -767,9 +764,3 @@ After the GPIO has been exported, gpio_export_link() allows creating
symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
use this to provide the interface under their own device in sysfs with
a descriptive name.
-
-Drivers can use gpio_sysfs_set_active_low() to hide GPIO line polarity
-differences between boards from user space. This only affects the
-sysfs interface. Polarity change can be done both before and after
-gpio_export(), and previously enabled poll(2) support for either
-rising or falling edge will be reconfigured to follow this setting.
diff --git a/Documentation/gpio/sysfs.txt b/Documentation/gpio/sysfs.txt
index c2c3a97f8ff7..535b6a8a7a7c 100644
--- a/Documentation/gpio/sysfs.txt
+++ b/Documentation/gpio/sysfs.txt
@@ -132,9 +132,6 @@ requested using gpio_request():
int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc);
- /* change the polarity of a GPIO node in sysfs */
- int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value);
-
After a kernel driver requests a GPIO, it may only be made available in
the sysfs interface by gpiod_export(). The driver can control whether the
signal direction may change. This helps drivers prevent userspace code
@@ -148,8 +145,3 @@ After the GPIO has been exported, gpiod_export_link() allows creating
symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
use this to provide the interface under their own device in sysfs with
a descriptive name.
-
-Drivers can use gpiod_sysfs_set_active_low() to hide GPIO line polarity
-differences between boards from user space. Polarity change can be done both
-before and after gpiod_export(), and previously enabled poll(2) support for
-either rising or falling edge will be reconfigured to follow this setting.
diff --git a/Documentation/hwmon/ntc_thermistor b/Documentation/hwmon/ntc_thermistor
index c5e05e2900a3..1d4cc847c6fe 100644
--- a/Documentation/hwmon/ntc_thermistor
+++ b/Documentation/hwmon/ntc_thermistor
@@ -2,8 +2,10 @@ Kernel driver ntc_thermistor
=================
Supported thermistors from Murata:
-* Murata NTC Thermistors NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, NCP15WL333
- Prefixes: 'ncp15wb473', 'ncp18wb473', 'ncp21wb473', 'ncp03wb473', 'ncp15wl333'
+* Murata NTC Thermistors NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473,
+ NCP15WL333, NCP03WF104
+ Prefixes: 'ncp15wb473', 'ncp18wb473', 'ncp21wb473', 'ncp03wb473',
+ 'ncp15wl333', 'ncp03wf104'
Datasheet: Publicly available at Murata
Supported thermistors from EPCOS:
diff --git a/Documentation/hwmon/tc74 b/Documentation/hwmon/tc74
new file mode 100644
index 000000000000..43027aad5f8e
--- /dev/null
+++ b/Documentation/hwmon/tc74
@@ -0,0 +1,20 @@
+Kernel driver tc74
+====================
+
+Supported chips:
+ * Microchip TC74
+ Prefix: 'tc74'
+ Datasheet: Publicly available at Microchip website.
+
+Description
+-----------
+
+Driver supports the above part.
+
+The tc74 has an 8-bit sensor, with 1 degree centigrade resolution
+and +- 2 degrees centigrade accuracy.
+
+Notes
+-----
+
+Currently entering low power standby mode is not supported.
diff --git a/Documentation/i2c/slave-interface b/Documentation/i2c/slave-interface
index 389bb5d61854..2dee4e2d62df 100644
--- a/Documentation/i2c/slave-interface
+++ b/Documentation/i2c/slave-interface
@@ -3,16 +3,16 @@ Linux I2C slave interface description
by Wolfram Sang <wsa@sang-engineering.com> in 2014-15
-Linux can also be an I2C slave in case I2C controllers have slave support.
-Besides this HW requirement, one also needs a software backend providing the
-actual functionality. An example for this is the slave-eeprom driver, which
-acts as a dual memory driver. While another I2C master on the bus can access it
-like a regular EEPROM, the Linux I2C slave can access the content via sysfs and
-retrieve/provide information as needed. The software backend driver and the I2C
-bus driver communicate via events. Here is a small graph visualizing the data
-flow and the means by which data is transported. The dotted line marks only one
-example. The backend could also use e.g. a character device, be in-kernel
-only, or something completely different:
+Linux can also be an I2C slave if the I2C controller in use has slave
+functionality. For that to work, one needs slave support in the bus driver plus
+a hardware independent software backend providing the actual functionality. An
+example for the latter is the slave-eeprom driver, which acts as a dual memory
+driver. While another I2C master on the bus can access it like a regular
+EEPROM, the Linux I2C slave can access the content via sysfs and handle data as
+needed. The backend driver and the I2C bus driver communicate via events. Here
+is a small graph visualizing the data flow and the means by which data is
+transported. The dotted line marks only one example. The backend could also
+use a character device, be in-kernel only, or something completely different:
e.g. sysfs I2C slave events I/O registers
@@ -31,10 +31,10 @@ User manual
===========
I2C slave backends behave like standard I2C clients. So, you can instantiate
-them like described in the document 'instantiating-devices'. A quick example
-for instantiating the slave-eeprom driver from userspace:
+them as described in the document 'instantiating-devices'. A quick example for
+instantiating the slave-eeprom driver from userspace at address 0x64 on bus 1:
- # echo 0-0064 > /sys/bus/i2c/drivers/i2c-slave-eeprom/bind
+ # echo slave-24c02 0x64 > /sys/bus/i2c/devices/i2c-1/new_device
Each backend should come with separate documentation to describe its specific
behaviour and setup.
@@ -43,6 +43,11 @@ behaviour and setup.
Developer manual
================
+First, the events which are used by the bus driver and the backend will be
+described in detail. After that, some implementation hints for extending bus
+drivers and writing backends will be given.
+
+
I2C slave events
----------------
diff --git a/Documentation/input/rotary-encoder.txt b/Documentation/input/rotary-encoder.txt
index 92e68bce13a4..5737e3590adb 100644
--- a/Documentation/input/rotary-encoder.txt
+++ b/Documentation/input/rotary-encoder.txt
@@ -33,7 +33,7 @@ The phase diagram of these two outputs look like this:
one step (half-period mode)
For more information, please see
- http://en.wikipedia.org/wiki/Rotary_encoder
+ https://en.wikipedia.org/wiki/Rotary_encoder
1. Events / state machine
diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO
index b61885c35ce1..5a0f2bdc2cf9 100644
--- a/Documentation/ja_JP/HOWTO
+++ b/Documentation/ja_JP/HOWTO
@@ -445,7 +445,7 @@ MAINTAINERS ファイルã«ãƒªã‚¹ãƒˆãŒã‚ã‚Šã¾ã™ã®ã§å‚ç…§ã—ã¦ãã ã•ã
メールã®å…ˆé ­ã§ãªãã€å„引用行ã®é–“ã«ã‚ãªãŸã®è¨€ã„ãŸã„ã“ã¨ã‚’追加ã™ã‚‹ã¹ãã§
ã™ã€‚
-ã‚‚ã—パッãƒã‚’メールã«ä»˜ã‘ã‚‹å ´åˆã¯ã€Documentaion/SubmittingPatches ã«æ
+ã‚‚ã—パッãƒã‚’メールã«ä»˜ã‘ã‚‹å ´åˆã¯ã€Documentation/SubmittingPatches ã«æ
示ã•ã‚Œã¦ã„るよã†ã«ã€ãれ㯠プレーンãªå¯èª­ãƒ†ã‚­ã‚¹ãƒˆã«ã™ã‚‹ã“ã¨ã‚’忘れãªã„
よã†ã«ã—ã¾ã—ょã†ã€‚カーãƒãƒ«é–‹ç™ºè€…㯠添付や圧縮ã—ãŸãƒ‘ッãƒã‚’扱ã„ãŸãŒã‚Šã¾
ã›ã‚“-
diff --git a/Documentation/kasan.txt b/Documentation/kasan.txt
index 4692241789b1..0d32355a4c34 100644
--- a/Documentation/kasan.txt
+++ b/Documentation/kasan.txt
@@ -150,7 +150,7 @@ AddressSanitizer dedicates 1/8 of kernel memory to its shadow memory
(e.g. 16TB to cover 128TB on x86_64) and uses direct mapping with a scale and
offset to translate a memory address to its corresponding shadow address.
-Here is the function witch translate an address to its corresponding shadow
+Here is the function which translates an address to its corresponding shadow
address:
static inline void *kasan_mem_to_shadow(const void *addr)
diff --git a/Documentation/kbuild/headers_install.txt b/Documentation/kbuild/headers_install.txt
index 951eb9f1e040..f0153adb95e2 100644
--- a/Documentation/kbuild/headers_install.txt
+++ b/Documentation/kbuild/headers_install.txt
@@ -24,7 +24,7 @@ The "make headers_install" command can be run in the top level directory of the
kernel source code (or using a standard out-of-tree build). It takes two
optional arguments:
- make headers_install ARCH=i386 INSTALL_HDR_PATH=/usr/include
+ make headers_install ARCH=i386 INSTALL_HDR_PATH=/usr
ARCH indicates which architecture to produce headers for, and defaults to the
current architecture. The linux/asm directory of the exported kernel headers
@@ -33,8 +33,11 @@ the command:
ls -d include/asm-* | sed 's/.*-//'
-INSTALL_HDR_PATH indicates where to install the headers. It defaults to
-"./usr/include".
+INSTALL_HDR_PATH indicates where to install the headers. It defaults to
+"./usr".
+
+An 'include' directory is automatically created inside INSTALL_HDR_PATH and
+headers are installed in 'INSTALL_HDR_PATH/include'.
The command "make headers_install_all" exports headers for all architectures
simultaneously. (This is mostly of interest to distribution maintainers,
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index 74b6c6d97210..e63b446d973c 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -755,8 +755,8 @@ Additional files can be specified in kbuild makefiles by use of $(clean-files).
#lib/Makefile
clean-files := crc32table.h
-When executing "make clean", the two files "devlist.h classlist.h" will be
-deleted. Kbuild will assume files to be in the same relative directory as the
+When executing "make clean", the file "crc32table.h" will be deleted.
+Kbuild will assume files to be in the same relative directory as the
Makefile, except if prefixed with $(objtree).
To delete a directory hierarchy use:
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 6726139bd289..8bb54c95cece 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -179,11 +179,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
See also Documentation/power/runtime_pm.txt, pci=noacpi
- acpi_rsdp= [ACPI,EFI,KEXEC]
- Pass the RSDP address to the kernel, mostly used
- on machines running EFI runtime service to boot the
- second kernel for kdump.
-
acpi_apic_instance= [ACPI, IOAPIC]
Format: <int>
2: use 2nd APIC table, if available
@@ -197,6 +192,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
(e.g. thinkpad_acpi, sony_acpi, etc.) instead
of the ACPI video.ko driver.
+ acpica_no_return_repair [HW, ACPI]
+ Disable AML predefined validation mechanism
+ This mechanism can repair the evaluation result to make
+ the return objects more ACPI specification compliant.
+ This option is useful for developers to identify the
+ root cause of an AML interpreter issue when the issue
+ has something to do with the repair mechanism.
+
acpi.debug_layer= [HW,ACPI,ACPI_DEBUG]
acpi.debug_level= [HW,ACPI,ACPI_DEBUG]
Format: <int>
@@ -225,6 +228,22 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
unusable. The "log_buf_len" parameter may be useful
if you need to capture more output.
+ acpi_enforce_resources= [ACPI]
+ { strict | lax | no }
+ Check for resource conflicts between native drivers
+ and ACPI OperationRegions (SystemIO and SystemMemory
+ only). IO ports and memory declared in ACPI might be
+ used by the ACPI subsystem in arbitrary AML code and
+ can interfere with legacy drivers.
+ strict (default): access to resources claimed by ACPI
+ is denied; legacy drivers trying to access reserved
+ resources will fail to bind to device using them.
+ lax: access to resources claimed by ACPI is allowed;
+ legacy drivers trying to access reserved resources
+ will bind successfully but a warning message is logged.
+ no: ACPI OperationRegions are not marked as reserved,
+ no further checks are performed.
+
acpi_force_table_verification [HW,ACPI]
Enable table checksum verification during early stage.
By default, this is disabled due to x86 early mapping
@@ -253,6 +272,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
This feature is enabled by default.
This option allows to turn off the feature.
+ acpi_no_memhotplug [ACPI] Disable memory hotplug. Useful for kdump
+ kernels.
+
acpi_no_static_ssdt [HW,ACPI]
Disable installation of static SSDTs at early boot time
By default, SSDTs contained in the RSDT/XSDT will be
@@ -263,13 +285,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
dynamic table installation which will install SSDT
tables to /sys/firmware/acpi/tables/dynamic.
- acpica_no_return_repair [HW, ACPI]
- Disable AML predefined validation mechanism
- This mechanism can repair the evaluation result to make
- the return objects more ACPI specification compliant.
- This option is useful for developers to identify the
- root cause of an AML interpreter issue when the issue
- has something to do with the repair mechanism.
+ acpi_rsdp= [ACPI,EFI,KEXEC]
+ Pass the RSDP address to the kernel, mostly used
+ on machines running EFI runtime service to boot the
+ second kernel for kdump.
acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS
Format: To spoof as Windows 98: ="Microsoft Windows"
@@ -365,25 +384,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Use timer override. For some broken Nvidia NF5 boards
that require a timer override, but don't have HPET
- acpi_enforce_resources= [ACPI]
- { strict | lax | no }
- Check for resource conflicts between native drivers
- and ACPI OperationRegions (SystemIO and SystemMemory
- only). IO ports and memory declared in ACPI might be
- used by the ACPI subsystem in arbitrary AML code and
- can interfere with legacy drivers.
- strict (default): access to resources claimed by ACPI
- is denied; legacy drivers trying to access reserved
- resources will fail to bind to device using them.
- lax: access to resources claimed by ACPI is allowed;
- legacy drivers trying to access reserved resources
- will bind successfully but a warning message is logged.
- no: ACPI OperationRegions are not marked as reserved,
- no further checks are performed.
-
- acpi_no_memhotplug [ACPI] Disable memory hotplug. Useful for kdump
- kernels.
-
add_efi_memmap [EFI; X86] Include EFI memory map in
kernel's map of available physical RAM.
@@ -746,6 +746,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
cpuidle.off=1 [CPU_IDLE]
disable the cpuidle sub-system
+ cpu_init_udelay=N
+ [X86] Delay for N microsec between assert and de-assert
+ of APIC INIT to start processors. This delay occurs
+ on every CPU online, such as boot, and resume from suspend.
+ Default: 10000
+
cpcihp_generic= [HW,PCI] Generic port I/O CompactPCI driver
Format:
<first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>]
@@ -937,12 +943,19 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Enable debug messages at boot time. See
Documentation/dynamic-debug-howto.txt for details.
+ nompx [X86] Disables Intel Memory Protection Extensions.
+ See Documentation/x86/intel_mpx.txt for more
+ information about the feature.
+
eagerfpu= [X86]
on enable eager fpu restore
off disable eager fpu restore
auto selects the default scheme, which automatically
enables eagerfpu restore for xsaveopt.
+ module.async_probe [KNL]
+ Enable asynchronous probe on this module.
+
early_ioremap_debug [KNL]
Enable debug messages in early_ioremap support. This
is useful for tracking down temporary early mappings
@@ -959,14 +972,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
uart[8250],io,<addr>[,options]
uart[8250],mmio,<addr>[,options]
uart[8250],mmio32,<addr>[,options]
+ uart[8250],mmio32be,<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.
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 "console=ttyS<n>"; if
+ (mmio) or 32-bit (mmio32 or mmio32be).
+ If none of [io|mmio|mmio32|mmio32be], <addr> is assumed
+ to be equivalent to 'mmio'. 'options' are specified
+ in the same format described for "console=ttyS<n>"; if
unspecified, the h/w is not initialized.
pl011,<addr>
@@ -1009,6 +1023,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
earlyprintk=serial[,0x...[,baudrate]]
earlyprintk=ttySn[,baudrate]
earlyprintk=dbgp[debugController#]
+ earlyprintk=pciserial,bus:device.function[,baudrate]
earlyprintk is useful when the kernel crashes before
the normal console is initialized. It is not enabled by
@@ -1780,6 +1795,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
* [no]ncq: Turn on or off NCQ.
+ * [no]ncqtrim: Turn off queued DSM TRIM.
+
* nohrst, nosrst, norst: suppress hard, soft
and both resets.
@@ -2443,7 +2460,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
nomca [IA-64] Disable machine check abort handling
- nomce [X86-32] Machine Check Exception
+ nomce [X86-32] Disable Machine Check Exception
nomfgpt [X86-32] Disable Multi-Function General Purpose
Timer usage (for AMD Geode machines).
@@ -2998,11 +3015,34 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Set maximum number of finished RCU callbacks to
process in one batch.
+ rcutree.dump_tree= [KNL]
+ Dump the structure of the rcu_node combining tree
+ out at early boot. This is used for diagnostic
+ purposes, to verify correct tree setup.
+
+ rcutree.gp_cleanup_delay= [KNL]
+ Set the number of jiffies to delay each step of
+ RCU grace-period cleanup. This only has effect
+ when CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP is set.
+
rcutree.gp_init_delay= [KNL]
Set the number of jiffies to delay each step of
RCU grace-period initialization. This only has
- effect when CONFIG_RCU_TORTURE_TEST_SLOW_INIT is
- set.
+ effect when CONFIG_RCU_TORTURE_TEST_SLOW_INIT
+ is set.
+
+ rcutree.gp_preinit_delay= [KNL]
+ Set the number of jiffies to delay each step of
+ RCU grace-period pre-initialization, that is,
+ the propagation of recent CPU-hotplug changes up
+ the rcu_node combining tree. This only has effect
+ when CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT is set.
+
+ rcutree.rcu_fanout_exact= [KNL]
+ Disable autobalancing of the rcu_node combining
+ tree. This is used by rcutorture, and might
+ possibly be useful for architectures having high
+ cache-to-cache transfer latencies.
rcutree.rcu_fanout_leaf= [KNL]
Increase the number of CPUs assigned to each
@@ -3107,7 +3147,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
test, hence the "fake".
rcutorture.nreaders= [KNL]
- Set number of RCU readers.
+ Set number of RCU readers. The value -1 selects
+ N-1, where N is the number of CPUs. A value
+ "n" less than -1 selects N-n-2, where N is again
+ the number of CPUs. For example, -2 selects N
+ (the number of CPUs), -3 selects N+1, and so on.
rcutorture.object_debug= [KNL]
Enable debug-object double-call_rcu() testing.
diff --git a/Documentation/kmemleak.txt b/Documentation/kmemleak.txt
index 45e777f4e41d..18e24abb3ecf 100644
--- a/Documentation/kmemleak.txt
+++ b/Documentation/kmemleak.txt
@@ -6,7 +6,7 @@ Introduction
Kmemleak provides a way of detecting possible kernel memory leaks in a
way similar to a tracing garbage collector
-(http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29#Tracing_garbage_collectors),
+(https://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29#Tracing_garbage_collectors),
with the difference that the orphan objects are not freed but only
reported via /sys/kernel/debug/kmemleak. A similar method is used by the
Valgrind tool (memcheck --leak-check) to detect the memory leaks in
diff --git a/Documentation/laptops/.gitignore b/Documentation/laptops/.gitignore
index da2bd065f4bc..9fc984e64386 100644
--- a/Documentation/laptops/.gitignore
+++ b/Documentation/laptops/.gitignore
@@ -1,2 +1 @@
dslm
-freefall
diff --git a/Documentation/laptops/00-INDEX b/Documentation/laptops/00-INDEX
index a3b4f209e562..7c0ac2a26b9e 100644
--- a/Documentation/laptops/00-INDEX
+++ b/Documentation/laptops/00-INDEX
@@ -8,8 +8,6 @@ disk-shock-protection.txt
- information on hard disk shock protection.
dslm.c
- Simple Disk Sleep Monitor program
-freefall.c
- - (HP/DELL) laptop accelerometer program for disk protection.
laptop-mode.txt
- how to conserve battery power using laptop-mode.
sony-laptop.txt
diff --git a/Documentation/laptops/Makefile b/Documentation/laptops/Makefile
index 2b0fa5edf1d3..0abe44f68965 100644
--- a/Documentation/laptops/Makefile
+++ b/Documentation/laptops/Makefile
@@ -1,5 +1,5 @@
# List of programs to build
-hostprogs-y := dslm freefall
+hostprogs-y := dslm
# Tell kbuild to always build the programs
always := $(hostprogs-y)
diff --git a/Documentation/leds/leds-class.txt b/Documentation/leds/leds-class.txt
index 79699c200766..62261c04060a 100644
--- a/Documentation/leds/leds-class.txt
+++ b/Documentation/leds/leds-class.txt
@@ -2,9 +2,6 @@
LED handling under Linux
========================
-If you're reading this and thinking about keyboard leds, these are
-handled by the input subsystem and the led class is *not* needed.
-
In its simplest form, the LED class just allows control of LEDs from
userspace. LEDs appear in /sys/class/leds/. The maximum brightness of the
LED is defined in max_brightness file. The brightness file will set the brightness
diff --git a/Documentation/lockup-watchdogs.txt b/Documentation/lockup-watchdogs.txt
index ab0baa692c13..22dd6af2e4bd 100644
--- a/Documentation/lockup-watchdogs.txt
+++ b/Documentation/lockup-watchdogs.txt
@@ -61,3 +61,21 @@ As explained above, a kernel knob is provided that allows
administrators to configure the period of the hrtimer and the perf
event. The right value for a particular environment is a trade-off
between fast response to lockups and detection overhead.
+
+By default, the watchdog runs on all online cores. However, on a
+kernel configured with NO_HZ_FULL, by default the watchdog runs only
+on the housekeeping cores, not the cores specified in the "nohz_full"
+boot argument. If we allowed the watchdog to run by default on
+the "nohz_full" cores, we would have to run timer ticks to activate
+the scheduler, which would prevent the "nohz_full" functionality
+from protecting the user code on those cores from the kernel.
+Of course, disabling it by default on the nohz_full cores means that
+when those cores do enter the kernel, by default we will not be
+able to detect if they lock up. However, allowing the watchdog
+to continue to run on the housekeeping (non-tickless) cores means
+that we will continue to detect lockups properly on those cores.
+
+In either case, the set of cores excluded from running the watchdog
+may be adjusted via the kernel.watchdog_cpumask sysctl. For
+nohz_full cores, this may be useful for debugging a case where the
+kernel seems to be hanging on the nohz_full cores.
diff --git a/Documentation/magic-number.txt b/Documentation/magic-number.txt
index 4c8e142db2ef..28befed9f610 100644
--- a/Documentation/magic-number.txt
+++ b/Documentation/magic-number.txt
@@ -116,7 +116,6 @@ COW_MAGIC 0x4f4f4f4d cow_header_v1 arch/um/drivers/ubd_user.c
I810_CARD_MAGIC 0x5072696E i810_card sound/oss/i810_audio.c
TRIDENT_CARD_MAGIC 0x5072696E trident_card sound/oss/trident.c
ROUTER_MAGIC 0x524d4157 wan_device [in wanrouter.h pre 3.9]
-SCC_MAGIC 0x52696368 gs_port drivers/char/scc.h
SAVEKMSG_MAGIC1 0x53415645 savekmsg arch/*/amiga/config.c
GDA_MAGIC 0x58464552 gda arch/mips/include/asm/sn/gda.h
RED_MAGIC1 0x5a2cf071 (any) mm/slab.c
@@ -138,7 +137,6 @@ KMALLOC_MAGIC 0x87654321 snd_alloc_track sound/core/memory.c
PWC_MAGIC 0x89DC10AB pwc_device drivers/usb/media/pwc.h
NBD_REPLY_MAGIC 0x96744668 nbd_reply include/linux/nbd.h
ENI155_MAGIC 0xa54b872d midway_eprom drivers/atm/eni.h
-SCI_MAGIC 0xbabeface gs_port drivers/char/sh-sci.h
CODA_MAGIC 0xC0DAC0DA coda_file_info fs/coda/coda_fs_i.h
DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram drivers/scsi/gdth.h
YAM_MAGIC 0xF10A7654 yam_port drivers/net/hamradio/yam.c
diff --git a/Documentation/md.txt b/Documentation/md.txt
index f925666e4342..1a2ada46aaed 100644
--- a/Documentation/md.txt
+++ b/Documentation/md.txt
@@ -549,7 +549,7 @@ also have
sync_speed_max
This are similar to /proc/sys/dev/raid/speed_limit_{min,max}
however they only apply to the particular array.
- If no value has been written to these, of if the word 'system'
+ If no value has been written to these, or if the word 'system'
is written, then the system-wide value is used. If a value,
in kibibytes-per-second is written, then it is used.
When the files are read, they show the currently active value
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index f95746189b5d..13feb697271f 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -617,16 +617,16 @@ case what's actually required is:
However, stores are not speculated. This means that ordering -is- provided
for load-store control dependencies, as in the following example:
- q = ACCESS_ONCE(a);
+ q = READ_ONCE_CTRL(a);
if (q) {
ACCESS_ONCE(b) = p;
}
-Control dependencies pair normally with other types of barriers.
-That said, please note that ACCESS_ONCE() is not optional! Without the
-ACCESS_ONCE(), might combine the load from 'a' with other loads from
-'a', and the store to 'b' with other stores to 'b', with possible highly
-counterintuitive effects on ordering.
+Control dependencies pair normally with other types of barriers. That
+said, please note that READ_ONCE_CTRL() is not optional! Without the
+READ_ONCE_CTRL(), the compiler might combine the load from 'a' with
+other loads from 'a', and the store to 'b' with other stores to 'b',
+with possible highly counterintuitive effects on ordering.
Worse yet, if the compiler is able to prove (say) that the value of
variable 'a' is always non-zero, it would be well within its rights
@@ -636,12 +636,15 @@ as follows:
q = a;
b = p; /* BUG: Compiler and CPU can both reorder!!! */
-So don't leave out the ACCESS_ONCE().
+Finally, the READ_ONCE_CTRL() includes an smp_read_barrier_depends()
+that DEC Alpha needs in order to respect control depedencies.
+
+So don't leave out the READ_ONCE_CTRL().
It is tempting to try to enforce ordering on identical stores on both
branches of the "if" statement as follows:
- q = ACCESS_ONCE(a);
+ q = READ_ONCE_CTRL(a);
if (q) {
barrier();
ACCESS_ONCE(b) = p;
@@ -655,7 +658,7 @@ branches of the "if" statement as follows:
Unfortunately, current compilers will transform this as follows at high
optimization levels:
- q = ACCESS_ONCE(a);
+ q = READ_ONCE_CTRL(a);
barrier();
ACCESS_ONCE(b) = p; /* BUG: No ordering vs. load from a!!! */
if (q) {
@@ -685,7 +688,7 @@ memory barriers, for example, smp_store_release():
In contrast, without explicit memory barriers, two-legged-if control
ordering is guaranteed only when the stores differ, for example:
- q = ACCESS_ONCE(a);
+ q = READ_ONCE_CTRL(a);
if (q) {
ACCESS_ONCE(b) = p;
do_something();
@@ -694,14 +697,14 @@ ordering is guaranteed only when the stores differ, for example:
do_something_else();
}
-The initial ACCESS_ONCE() is still required to prevent the compiler from
-proving the value of 'a'.
+The initial READ_ONCE_CTRL() is still required to prevent the compiler
+from proving the value of 'a'.
In addition, you need to be careful what you do with the local variable 'q',
otherwise the compiler might be able to guess the value and again remove
the needed conditional. For example:
- q = ACCESS_ONCE(a);
+ q = READ_ONCE_CTRL(a);
if (q % MAX) {
ACCESS_ONCE(b) = p;
do_something();
@@ -714,7 +717,7 @@ If MAX is defined to be 1, then the compiler knows that (q % MAX) is
equal to zero, in which case the compiler is within its rights to
transform the above code into the following:
- q = ACCESS_ONCE(a);
+ q = READ_ONCE_CTRL(a);
ACCESS_ONCE(b) = p;
do_something_else();
@@ -725,7 +728,7 @@ is gone, and the barrier won't bring it back. Therefore, if you are
relying on this ordering, you should make sure that MAX is greater than
one, perhaps as follows:
- q = ACCESS_ONCE(a);
+ q = READ_ONCE_CTRL(a);
BUILD_BUG_ON(MAX <= 1); /* Order load from a with store to b. */
if (q % MAX) {
ACCESS_ONCE(b) = p;
@@ -742,14 +745,15 @@ of the 'if' statement.
You must also be careful not to rely too much on boolean short-circuit
evaluation. Consider this example:
- q = ACCESS_ONCE(a);
+ q = READ_ONCE_CTRL(a);
if (a || 1 > 0)
ACCESS_ONCE(b) = 1;
-Because the second condition is always true, the compiler can transform
-this example as following, defeating control dependency:
+Because the first condition cannot fault and the second condition is
+always true, the compiler can transform this example as following,
+defeating control dependency:
- q = ACCESS_ONCE(a);
+ q = READ_ONCE_CTRL(a);
ACCESS_ONCE(b) = 1;
This example underscores the need to ensure that the compiler cannot
@@ -762,8 +766,8 @@ demonstrated by two related examples, with the initial values of
x and y both being zero:
CPU 0 CPU 1
- ===================== =====================
- r1 = ACCESS_ONCE(x); r2 = ACCESS_ONCE(y);
+ ======================= =======================
+ r1 = READ_ONCE_CTRL(x); r2 = READ_ONCE_CTRL(y);
if (r1 > 0) if (r2 > 0)
ACCESS_ONCE(y) = 1; ACCESS_ONCE(x) = 1;
@@ -783,7 +787,8 @@ But because control dependencies do -not- provide transitivity, the above
assertion can fail after the combined three-CPU example completes. If you
need the three-CPU example to provide ordering, you will need smp_mb()
between the loads and stores in the CPU 0 and CPU 1 code fragments,
-that is, just before or just after the "if" statements.
+that is, just before or just after the "if" statements. Furthermore,
+the original two-CPU example is very fragile and should be avoided.
These two examples are the LB and WWC litmus tests from this paper:
http://www.cl.cam.ac.uk/users/pes20/ppc-supplemental/test6.pdf and this
@@ -791,6 +796,12 @@ site: https://www.cl.cam.ac.uk/~pes20/ppcmem/index.html.
In summary:
+ (*) Control dependencies must be headed by READ_ONCE_CTRL().
+ Or, as a much less preferable alternative, interpose
+ be headed by READ_ONCE() or an ACCESS_ONCE() read and must
+ have smp_read_barrier_depends() between this read and the
+ control-dependent write.
+
(*) Control dependencies can order prior loads against later stores.
However, they do -not- guarantee any other sort of ordering:
Not prior loads against later loads, nor prior stores against
@@ -1662,7 +1673,7 @@ CPU from reordering them.
There are some more advanced barrier functions:
- (*) set_mb(var, value)
+ (*) smp_store_mb(var, value)
This assigns the value to the variable and then inserts a full memory
barrier after it, depending on the function. It isn't guaranteed to
@@ -1784,10 +1795,9 @@ for each construct. These operations all imply certain barriers:
Memory operations issued before the ACQUIRE may be completed after
the ACQUIRE operation has completed. An smp_mb__before_spinlock(),
- combined with a following ACQUIRE, orders prior loads against
- subsequent loads and stores and also orders prior stores against
- subsequent stores. Note that this is weaker than smp_mb()! The
- smp_mb__before_spinlock() primitive is free on many architectures.
+ combined with a following ACQUIRE, orders prior stores against
+ subsequent loads and stores. Note that this is weaker than smp_mb()!
+ The smp_mb__before_spinlock() primitive is free on many architectures.
(2) RELEASE operation implication:
@@ -1975,7 +1985,7 @@ after it has altered the task state:
CPU 1
===============================
set_current_state();
- set_mb();
+ smp_store_mb();
STORE current->state
<general barrier>
LOAD event_indicated
@@ -2016,7 +2026,7 @@ between the STORE to indicate the event and the STORE to set TASK_RUNNING:
CPU 1 CPU 2
=============================== ===============================
set_current_state(); STORE event_indicated
- set_mb(); wake_up();
+ smp_store_mb(); wake_up();
STORE current->state <write barrier>
<general barrier> STORE current->state
LOAD event_indicated
diff --git a/Documentation/mic/mic_overview.txt b/Documentation/mic/mic_overview.txt
index 77c541802ad9..1a2f2c8ec59e 100644
--- a/Documentation/mic/mic_overview.txt
+++ b/Documentation/mic/mic_overview.txt
@@ -24,6 +24,10 @@ a virtual bus called mic bus is created and virtual dma devices are
created on it by the host/card drivers. On host the channels are private
and used only by the host driver to transfer data for the virtio devices.
+The Symmetric Communication Interface (SCIF (pronounced as skiff)) is a
+low level communications API across PCIe currently implemented for MIC.
+More details are available at scif_overview.txt.
+
Here is a block diagram of the various components described above. The
virtio backends are situated on the host rather than the card given better
single threaded performance for the host compared to MIC, the ability of
@@ -47,18 +51,18 @@ the fact that the virtio block storage backend can only be on the host.
| | | Virtio over PCIe IOCTLs |
| | +--------------------------+
+-----------+ | | | +-----------+
-| MIC DMA | | | | | MIC DMA |
-| Driver | | | | | Driver |
-+-----------+ | | | +-----------+
- | | | | |
-+---------------+ | | | +----------------+
-|MIC virtual Bus| | | | |MIC virtual Bus |
-+---------------+ | | | +----------------+
- | | | | |
- | +--------------+ | +---------------+ |
- | |Intel MIC | | |Intel MIC | |
- +---|Card Driver | | |Host Driver | |
- +--------------+ | +---------------+-----+
+| MIC DMA | | +----------+ | +-----------+ | | MIC DMA |
+| Driver | | | SCIF | | | SCIF | | | Driver |
++-----------+ | +----------+ | +-----------+ | +-----------+
+ | | | | | | |
++---------------+ | +-----+-----+ | +-----+-----+ | +---------------+
+|MIC virtual Bus| | |SCIF HW Bus| | |SCIF HW BUS| | |MIC virtual Bus|
++---------------+ | +-----------+ | +-----+-----+ | +---------------+
+ | | | | | | |
+ | +--------------+ | | | +---------------+ |
+ | |Intel MIC | | | | |Intel MIC | |
+ +---|Card Driver +----+ | | |Host Driver | |
+ +--------------+ | +----+---------------+-----+
| | |
+-------------------------------------------------------------+
| |
diff --git a/Documentation/mic/mpssd/Makefile b/Documentation/mic/mpssd/Makefile
index f47fe6ba7300..06871b0c08a6 100644
--- a/Documentation/mic/mpssd/Makefile
+++ b/Documentation/mic/mpssd/Makefile
@@ -1,3 +1,4 @@
+ifndef CROSS_COMPILE
# List of programs to build
hostprogs-$(CONFIG_X86_64) := mpssd
@@ -17,3 +18,4 @@ HOSTLOADLIBES_mpssd := -lpthread
install:
install mpssd /usr/sbin/mpssd
install micctrl /usr/sbin/micctrl
+endif
diff --git a/Documentation/mic/mpssd/mpss b/Documentation/mic/mpssd/mpss
index cacbdb0aefb9..582aad4811ae 100755
--- a/Documentation/mic/mpssd/mpss
+++ b/Documentation/mic/mpssd/mpss
@@ -35,6 +35,7 @@
exec=/usr/sbin/mpssd
sysfs="/sys/class/mic"
+mic_modules="mic_host mic_x100_dma scif"
start()
{
@@ -48,18 +49,15 @@ start()
fi
echo -e $"Starting MPSS Stack"
- echo -e $"Loading MIC_X100_DMA & MIC_HOST Modules"
+ echo -e $"Loading MIC drivers:" $mic_modules
- for f in "mic_host" "mic_x100_dma"
- do
- modprobe $f
- RETVAL=$?
- if [ $RETVAL -ne 0 ]; then
- failure
- echo
- return $RETVAL
- fi
- done
+ modprobe -a $mic_modules
+ RETVAL=$?
+ if [ $RETVAL -ne 0 ]; then
+ failure
+ echo
+ return $RETVAL
+ fi
# Start the daemon
echo -n $"Starting MPSSD "
@@ -170,8 +168,8 @@ unload()
stop
sleep 5
- echo -n $"Removing MIC_HOST & MIC_X100_DMA Modules: "
- modprobe -r mic_host mic_x100_dma
+ echo -n $"Removing MIC drivers:" $mic_modules
+ modprobe -r $mic_modules
RETVAL=$?
[ $RETVAL -ne 0 ] && failure || success
echo
diff --git a/Documentation/mic/scif_overview.txt b/Documentation/mic/scif_overview.txt
new file mode 100644
index 000000000000..0a280d986731
--- /dev/null
+++ b/Documentation/mic/scif_overview.txt
@@ -0,0 +1,98 @@
+The Symmetric Communication Interface (SCIF (pronounced as skiff)) is a low
+level communications API across PCIe currently implemented for MIC. Currently
+SCIF provides inter-node communication within a single host platform, where a
+node is a MIC Coprocessor or Xeon based host. SCIF abstracts the details of
+communicating over the PCIe bus while providing an API that is symmetric
+across all the nodes in the PCIe network. An important design objective for SCIF
+is to deliver the maximum possible performance given the communication
+abilities of the hardware. SCIF has been used to implement an offload compiler
+runtime and OFED support for MPI implementations for MIC coprocessors.
+
+==== SCIF API Components ====
+The SCIF API has the following parts:
+1. Connection establishment using a client server model
+2. Byte stream messaging intended for short messages
+3. Node enumeration to determine online nodes
+4. Poll semantics for detection of incoming connections and messages
+5. Memory registration to pin down pages
+6. Remote memory mapping for low latency CPU accesses via mmap
+7. Remote DMA (RDMA) for high bandwidth DMA transfers
+8. Fence APIs for RDMA synchronization
+
+SCIF exposes the notion of a connection which can be used by peer processes on
+nodes in a SCIF PCIe "network" to share memory "windows" and to communicate. A
+process in a SCIF node initiates a SCIF connection to a peer process on a
+different node via a SCIF "endpoint". SCIF endpoints support messaging APIs
+which are similar to connection oriented socket APIs. Connected SCIF endpoints
+can also register local memory which is followed by data transfer using either
+DMA, CPU copies or remote memory mapping via mmap. SCIF supports both user and
+kernel mode clients which are functionally equivalent.
+
+==== SCIF Performance for MIC ====
+DMA bandwidth comparison between the TCP (over ethernet over PCIe) stack versus
+SCIF shows the performance advantages of SCIF for HPC applications and runtimes.
+
+ Comparison of TCP and SCIF based BW
+
+ Throughput (GB/sec)
+ 8 + PCIe Bandwidth ******
+ + TCP ######
+ 7 + ************************************** SCIF %%%%%%
+ | %%%%%%%%%%%%%%%%%%%
+ 6 + %%%%
+ | %%
+ | %%%
+ 5 + %%
+ | %%
+ 4 + %%
+ | %%
+ 3 + %%
+ | %
+ 2 + %%
+ | %%
+ | %
+ 1 +
+ + ######################################
+ 0 +++---+++--+--+-+--+--+-++-+--+-++-+--+-++-+-
+ 1 10 100 1000 10000 100000
+ Transfer Size (KBytes)
+
+SCIF allows memory sharing via mmap(..) between processes on different PCIe
+nodes and thus provides bare-metal PCIe latency. The round trip SCIF mmap
+latency from the host to an x100 MIC for an 8 byte message is 0.44 usecs.
+
+SCIF has a user space library which is a thin IOCTL wrapper providing a user
+space API similar to the kernel API in scif.h. The SCIF user space library
+is distributed @ https://software.intel.com/en-us/mic-developer
+
+Here is some pseudo code for an example of how two applications on two PCIe
+nodes would typically use the SCIF API:
+
+Process A (on node A) Process B (on node B)
+
+/* get online node information */
+scif_get_node_ids(..) scif_get_node_ids(..)
+scif_open(..) scif_open(..)
+scif_bind(..) scif_bind(..)
+scif_listen(..)
+scif_accept(..) scif_connect(..)
+/* SCIF connection established */
+
+/* Send and receive short messages */
+scif_send(..)/scif_recv(..) scif_send(..)/scif_recv(..)
+
+/* Register memory */
+scif_register(..) scif_register(..)
+
+/* RDMA */
+scif_readfrom(..)/scif_writeto(..) scif_readfrom(..)/scif_writeto(..)
+
+/* Fence DMAs */
+scif_fence_signal(..) scif_fence_signal(..)
+
+mmap(..) mmap(..)
+
+/* Access remote registered memory */
+
+/* Close the endpoints */
+scif_close(..) scif_close(..)
diff --git a/Documentation/misc-devices/spear-pcie-gadget.txt b/Documentation/misc-devices/spear-pcie-gadget.txt
index 02c13ef5e908..89b88dee4143 100644
--- a/Documentation/misc-devices/spear-pcie-gadget.txt
+++ b/Documentation/misc-devices/spear-pcie-gadget.txt
@@ -2,7 +2,7 @@ Spear PCIe Gadget Driver:
Author
=============
-Pratyush Anand (pratyush.anand@st.com)
+Pratyush Anand (pratyush.anand@gmail.com)
Location
============
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 83bf4986baea..334b49ef02d1 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -51,6 +51,7 @@ Table of Contents
3.4 Configuring Bonding Manually via Sysfs
3.5 Configuration with Interfaces Support
3.6 Overriding Configuration for Special Cases
+3.7 Configuring LACP for 802.3ad mode in a more secure way
4. Querying Bonding Configuration
4.1 Bonding Configuration
@@ -178,6 +179,27 @@ active_slave
active slave, or the empty string if there is no active slave or
the current mode does not use an active slave.
+ad_actor_sys_prio
+
+ In an AD system, this specifies the system priority. The allowed range
+ is 1 - 65535. If the value is not specified, it takes 65535 as the
+ default value.
+
+ This parameter has effect only in 802.3ad mode and is available through
+ SysFs interface.
+
+ad_actor_system
+
+ In an AD system, this specifies the mac-address for the actor in
+ protocol packet exchanges (LACPDUs). The value cannot be NULL or
+ multicast. It is preferred to have the local-admin bit set for this
+ mac but driver does not enforce it. If the value is not given then
+ system defaults to using the masters' mac address as actors' system
+ address.
+
+ This parameter has effect only in 802.3ad mode and is available through
+ SysFs interface.
+
ad_select
Specifies the 802.3ad aggregation selection logic to use. The
@@ -220,6 +242,21 @@ ad_select
This option was added in bonding version 3.4.0.
+ad_user_port_key
+
+ In an AD system, the port-key has three parts as shown below -
+
+ Bits Use
+ 00 Duplex
+ 01-05 Speed
+ 06-15 User-defined
+
+ This defines the upper 10 bits of the port key. The values can be
+ from 0 - 1023. If not given, the system defaults to 0.
+
+ This parameter has effect only in 802.3ad mode and is available through
+ SysFs interface.
+
all_slaves_active
Specifies that duplicate frames (received on inactive ports) should be
@@ -1622,6 +1659,53 @@ output port selection.
This feature first appeared in bonding driver version 3.7.0 and support for
output slave selection was limited to round-robin and active-backup modes.
+3.7 Configuring LACP for 802.3ad mode in a more secure way
+----------------------------------------------------------
+
+When using 802.3ad bonding mode, the Actor (host) and Partner (switch)
+exchange LACPDUs. These LACPDUs cannot be sniffed, because they are
+destined to link local mac addresses (which switches/bridges are not
+supposed to forward). However, most of the values are easily predictable
+or are simply the machine's MAC address (which is trivially known to all
+other hosts in the same L2). This implies that other machines in the L2
+domain can spoof LACPDU packets from other hosts to the switch and potentially
+cause mayhem by joining (from the point of view of the switch) another
+machine's aggregate, thus receiving a portion of that hosts incoming
+traffic and / or spoofing traffic from that machine themselves (potentially
+even successfully terminating some portion of flows). Though this is not
+a likely scenario, one could avoid this possibility by simply configuring
+few bonding parameters:
+
+ (a) ad_actor_system : You can set a random mac-address that can be used for
+ these LACPDU exchanges. The value can not be either NULL or Multicast.
+ Also it's preferable to set the local-admin bit. Following shell code
+ generates a random mac-address as described above.
+
+ # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \
+ $(( (RANDOM & 0xFE) | 0x02 )) \
+ $(( RANDOM & 0xFF )) \
+ $(( RANDOM & 0xFF )) \
+ $(( RANDOM & 0xFF )) \
+ $(( RANDOM & 0xFF )) \
+ $(( RANDOM & 0xFF )))
+ # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system
+
+ (b) ad_actor_sys_prio : Randomize the system priority. The default value
+ is 65535, but system can take the value from 1 - 65535. Following shell
+ code generates random priority and sets it.
+
+ # sys_prio=$(( 1 + RANDOM + RANDOM ))
+ # echo $sys_prio > /sys/class/net/bond0/bonding/ad_actor_sys_prio
+
+ (c) ad_user_port_key : Use the user portion of the port-key. The default
+ keeps this empty. These are the upper 10 bits of the port-key and value
+ ranges from 0 - 1023. Following shell code generates these 10 bits and
+ sets it.
+
+ # usr_port_key=$(( RANDOM & 0x3FF ))
+ # echo $usr_port_key > /sys/class/net/bond0/bonding/ad_user_port_key
+
+
4 Querying Bonding Configuration
=================================
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt
index 5abad1e921ca..b48d4a149411 100644
--- a/Documentation/networking/can.txt
+++ b/Documentation/networking/can.txt
@@ -268,6 +268,9 @@ solution for a couple of reasons:
struct can_frame {
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
__u8 can_dlc; /* frame payload length in byte (0 .. 8) */
+ __u8 __pad; /* padding */
+ __u8 __res0; /* reserved / padding */
+ __u8 __res1; /* reserved / padding */
__u8 data[8] __attribute__((aligned(8)));
};
diff --git a/Documentation/networking/dctcp.txt b/Documentation/networking/dctcp.txt
index 0d5dfbc89ec9..13a857753208 100644
--- a/Documentation/networking/dctcp.txt
+++ b/Documentation/networking/dctcp.txt
@@ -8,6 +8,7 @@ the data center network to provide multi-bit feedback to the end hosts.
To enable it on end hosts:
sysctl -w net.ipv4.tcp_congestion_control=dctcp
+ sysctl -w net.ipv4.tcp_ecn_fallback=0 (optional)
All switches in the data center network running DCTCP must support ECN
marking and be configured for marking when reaching defined switch buffer
diff --git a/Documentation/networking/fore200e.txt b/Documentation/networking/fore200e.txt
index d52af53efdc5..1f98f62b4370 100644
--- a/Documentation/networking/fore200e.txt
+++ b/Documentation/networking/fore200e.txt
@@ -37,7 +37,7 @@ version. Alternative binary firmware images can be found somewhere on the
ForeThought CD-ROM supplied with your adapter by FORE Systems.
You can also get the latest firmware images from FORE Systems at
-http://en.wikipedia.org/wiki/FORE_Systems. Register TACTics Online and go to
+https://en.wikipedia.org/wiki/FORE_Systems. Register TACTics Online and go to
the 'software updates' pages. The firmware binaries are part of
the various ForeThought software distributions.
diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt
index 22bbc7225f8e..1700756af057 100644
--- a/Documentation/networking/ieee802154.txt
+++ b/Documentation/networking/ieee802154.txt
@@ -30,8 +30,8 @@ int sd = socket(PF_IEEE802154, SOCK_DGRAM, 0);
The address family, socket addresses etc. are defined in the
include/net/af_ieee802154.h header or in the special header
-in our userspace package (see either linux-zigbee sourceforge download page
-or git tree at git://linux-zigbee.git.sourceforge.net/gitroot/linux-zigbee).
+in the userspace package (see either http://wpan.cakelab.org/ or the
+git tree at https://github.com/linux-wpan/wpan-tools).
One can use SOCK_RAW for passing raw data towards device xmit function. YMMV.
@@ -49,15 +49,6 @@ Like with WiFi, there are several types of devices implementing IEEE 802.15.4.
Those types of devices require different approach to be hooked into Linux kernel.
-MLME - MAC Level Management
-============================
-
-Most of IEEE 802.15.4 MLME interfaces are directly mapped on netlink commands.
-See the include/net/nl802154.h header. Our userspace tools package
-(see above) provides CLI configuration utility for radio interfaces and simple
-coordinator for IEEE 802.15.4 networks as an example users of MLME protocol.
-
-
HardMAC
=======
@@ -75,8 +66,6 @@ net_device with a pointer to struct ieee802154_mlme_ops instance. The fields
assoc_req, assoc_resp, disassoc_req, start_req, and scan_req are optional.
All other fields are required.
-We provide an example of simple HardMAC driver at drivers/ieee802154/fakehard.c
-
SoftMAC
=======
@@ -89,7 +78,8 @@ stack interface for network sniffers (e.g. WireShark).
This layer is going to be extended soon.
-See header include/net/mac802154.h and several drivers in drivers/ieee802154/.
+See header include/net/mac802154.h and several drivers in
+drivers/net/ieee802154/.
Device drivers API
@@ -114,18 +104,17 @@ Moreover IEEE 802.15.4 device operations structure should be filled.
Fake drivers
============
-In addition there are two drivers available which simulate real devices with
-HardMAC (fakehard) and SoftMAC (fakelb - IEEE 802.15.4 loopback driver)
-interfaces. This option provides possibility to test and debug stack without
-usage of real hardware.
+In addition there is a driver available which simulates a real device with
+SoftMAC (fakelb - IEEE 802.15.4 loopback driver) interface. This option
+provides possibility to test and debug stack without usage of real hardware.
-See sources in drivers/ieee802154 folder for more details.
+See sources in drivers/net/ieee802154 folder for more details.
6LoWPAN Linux implementation
============================
-The IEEE 802.15.4 standard specifies an MTU of 128 bytes, yielding about 80
+The IEEE 802.15.4 standard specifies an MTU of 127 bytes, yielding about 80
octets of actual MAC payload once security is turned on, on a wireless link
with a link throughput of 250 kbps or less. The 6LoWPAN adaptation format
[RFC4944] was specified to carry IPv6 datagrams over such constrained links,
@@ -140,7 +129,8 @@ In Semptember 2011 the standard update was published - [RFC6282].
It deprecates HC1 and HC2 compression and defines IPHC encoding format which is
used in this Linux implementation.
-All the code related to 6lowpan you may find in files: net/ieee802154/6lowpan.*
+All the code related to 6lowpan you may find in files: net/6lowpan/*
+and net/ieee802154/6lowpan/*
To setup 6lowpan interface you need (busybox release > 1.17.0):
1. Add IEEE802.15.4 interface and initialize PANid;
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 071fb18dc57c..5fae7704daab 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -267,6 +267,15 @@ tcp_ecn - INTEGER
but do not request ECN on outgoing connections.
Default: 2
+tcp_ecn_fallback - BOOLEAN
+ If the kernel detects that ECN connection misbehaves, enable fall
+ back to non-ECN. Currently, this knob implements the fallback
+ from RFC3168, section 6.1.1.1., but we reserve that in future,
+ additional detection mechanisms could be implemented under this
+ knob. The value is not used, if tcp_ecn or per route (or congestion
+ control) ECN settings are disabled.
+ Default: 1 (fallback enabled)
+
tcp_fack - BOOLEAN
Enable FACK congestion avoidance and fast retransmission.
The value is not used, if tcp_sack is not enabled.
@@ -742,8 +751,10 @@ IP Variables:
ip_local_port_range - 2 INTEGERS
Defines the local port range that is used by TCP and UDP to
choose the local port. The first number is the first, the
- second the last local port number. The default values are
- 32768 and 61000 respectively.
+ second the last local port number.
+ If possible, it is better these numbers have different parity.
+ (one even and one odd values)
+ The default values are 32768 and 60999 respectively.
ip_local_reserved_ports - list of comma separated ranges
Specify the ports which are reserved for known third-party
@@ -766,7 +777,7 @@ ip_local_reserved_ports - list of comma separated ranges
ip_local_port_range, e.g.:
$ cat /proc/sys/net/ipv4/ip_local_port_range
- 32000 61000
+ 32000 60999
$ cat /proc/sys/net/ipv4/ip_local_reserved_ports
8080,9148
@@ -1213,6 +1224,14 @@ auto_flowlabels - BOOLEAN
FALSE: disabled
Default: false
+flowlabel_state_ranges - BOOLEAN
+ Split the flow label number space into two ranges. 0-0x7FFFF is
+ reserved for the IPv6 flow manager facility, 0x80000-0xFFFFF
+ is reserved for stateless flow labels as described in RFC6437.
+ TRUE: enabled
+ FALSE: disabled
+ Default: true
+
anycast_src_echo_reply - BOOLEAN
Controls the use of anycast addresses as source addresses for ICMPv6
echo reply
diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt
index a5d574a9ae09..30409a36e95d 100644
--- a/Documentation/networking/netconsole.txt
+++ b/Documentation/networking/netconsole.txt
@@ -2,6 +2,7 @@
started by Ingo Molnar <mingo@redhat.com>, 2001.09.17
2.6 port and netpoll api by Matt Mackall <mpm@selenic.com>, Sep 9 2003
IPv6 support by Cong Wang <xiyou.wangcong@gmail.com>, Jan 1 2013
+Extended console support by Tejun Heo <tj@kernel.org>, May 1 2015
Please send bug reports to Matt Mackall <mpm@selenic.com>
Satyam Sharma <satyam.sharma@gmail.com>, and Cong Wang <xiyou.wangcong@gmail.com>
@@ -24,9 +25,10 @@ Sender and receiver configuration:
It takes a string configuration parameter "netconsole" in the
following format:
- netconsole=[src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr]
+ netconsole=[+][src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr]
where
+ + if present, enable extended console support
src-port source for UDP packets (defaults to 6665)
src-ip source IP to use (interface address)
dev network interface (eth0)
@@ -107,6 +109,7 @@ To remove a target:
The interface exposes these parameters of a netconsole target to userspace:
enabled Is this target currently enabled? (read-write)
+ extended Extended mode enabled (read-write)
dev_name Local network interface name (read-write)
local_port Source UDP port to use (read-write)
remote_port Remote agent's UDP port (read-write)
@@ -132,6 +135,36 @@ You can also update the local interface dynamically. This is especially
useful if you want to use interfaces that have newly come up (and may not
have existed when netconsole was loaded / initialized).
+Extended console:
+=================
+
+If '+' is prefixed to the configuration line or "extended" config file
+is set to 1, extended console support is enabled. An example boot
+param follows.
+
+ linux netconsole=+4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc
+
+Log messages are transmitted with extended metadata header in the
+following format which is the same as /dev/kmsg.
+
+ <level>,<sequnum>,<timestamp>,<contflag>;<message text>
+
+Non printable characters in <message text> are escaped using "\xff"
+notation. If the message contains optional dictionary, verbatim
+newline is used as the delimeter.
+
+If a message doesn't fit in certain number of bytes (currently 1000),
+the message is split into multiple fragments by netconsole. These
+fragments are transmitted with "ncfrag" header field added.
+
+ ncfrag=<byte-offset>/<total-bytes>
+
+For example, assuming a lot smaller chunk size, a message "the first
+chunk, the 2nd chunk." may be split as follows.
+
+ 6,416,1758426,-,ncfrag=0/31;the first chunk,
+ 6,416,1758426,-,ncfrag=16/31; the 2nd chunk.
+
Miscellaneous notes:
====================
diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt
index 0344f1d45b37..f4be85e96005 100644
--- a/Documentation/networking/pktgen.txt
+++ b/Documentation/networking/pktgen.txt
@@ -1,6 +1,6 @@
- HOWTO for the linux packet generator
+ HOWTO for the linux packet generator
------------------------------------
Enable CONFIG_NET_PKTGEN to compile and build pktgen either in-kernel
@@ -50,17 +50,33 @@ For ixgbe use e.g. "30" resulting in approx 33K interrupts/sec (1/30*10^6):
# ethtool -C ethX rx-usecs 30
-Viewing threads
-===============
-/proc/net/pktgen/kpktgend_0
-Name: kpktgend_0 max_before_softirq: 10000
-Running:
-Stopped: eth1
-Result: OK: max_before_softirq=10000
+Kernel threads
+==============
+Pktgen creates a thread for each CPU with affinity to that CPU.
+Which is controlled through procfile /proc/net/pktgen/kpktgend_X.
+
+Example: /proc/net/pktgen/kpktgend_0
+
+ Running:
+ Stopped: eth4@0
+ Result: OK: add_device=eth4@0
+
+Most important are the devices assigned to the thread.
+
+The two basic thread commands are:
+ * add_device DEVICE@NAME -- adds a single device
+ * rem_device_all -- remove all associated devices
+
+When adding a device to a thread, a corrosponding procfile is created
+which is used for configuring this device. Thus, device names need to
+be unique.
-Most important are the devices assigned to the thread. Note that a
-device can only belong to one thread.
+To support adding the same device to multiple threads, which is useful
+with multi queue NICs, a the device naming scheme is extended with "@":
+ device@something
+The part after "@" can be anything, but it is custom to use the thread
+number.
Viewing devices
===============
@@ -69,29 +85,32 @@ The Params section holds configured information. The Current section
holds running statistics. The Result is printed after a run or after
interruption. Example:
-/proc/net/pktgen/eth1
+/proc/net/pktgen/eth4@0
-Params: count 10000000 min_pkt_size: 60 max_pkt_size: 60
- frags: 0 delay: 0 clone_skb: 1000000 ifname: eth1
+ Params: count 100000 min_pkt_size: 60 max_pkt_size: 60
+ frags: 0 delay: 0 clone_skb: 64 ifname: eth4@0
flows: 0 flowlen: 0
- dst_min: 10.10.11.2 dst_max:
- src_min: src_max:
- src_mac: 00:00:00:00:00:00 dst_mac: 00:04:23:AC:FD:82
- udp_src_min: 9 udp_src_max: 9 udp_dst_min: 9 udp_dst_max: 9
- src_mac_count: 0 dst_mac_count: 0
- Flags:
-Current:
- pkts-sofar: 10000000 errors: 39664
- started: 1103053986245187us stopped: 1103053999346329us idle: 880401us
- seq_num: 10000011 cur_dst_mac_offset: 0 cur_src_mac_offset: 0
- cur_saddr: 0x10a0a0a cur_daddr: 0x20b0a0a
- cur_udp_dst: 9 cur_udp_src: 9
+ queue_map_min: 0 queue_map_max: 0
+ dst_min: 192.168.81.2 dst_max:
+ src_min: src_max:
+ src_mac: 90:e2:ba:0a:56:b4 dst_mac: 00:1b:21:3c:9d:f8
+ udp_src_min: 9 udp_src_max: 109 udp_dst_min: 9 udp_dst_max: 9
+ src_mac_count: 0 dst_mac_count: 0
+ Flags: UDPSRC_RND NO_TIMESTAMP QUEUE_MAP_CPU
+ Current:
+ pkts-sofar: 100000 errors: 0
+ started: 623913381008us stopped: 623913396439us idle: 25us
+ seq_num: 100001 cur_dst_mac_offset: 0 cur_src_mac_offset: 0
+ cur_saddr: 192.168.8.3 cur_daddr: 192.168.81.2
+ cur_udp_dst: 9 cur_udp_src: 42
+ cur_queue_map: 0
flows: 0
-Result: OK: 13101142(c12220741+d880401) usec, 10000000 (60byte,0frags)
- 763292pps 390Mb/sec (390805504bps) errors: 39664
+ Result: OK: 15430(c15405+d25) usec, 100000 (60byte,0frags)
+ 6480562pps 3110Mb/sec (3110669760bps) errors: 0
-Configuring threads and devices
-================================
+
+Configuring devices
+===================
This is done via the /proc interface, and most easily done via pgset
as defined in the sample scripts.
@@ -126,7 +145,7 @@ Examples:
To select queue 1 of a given device,
use queue_map_min=1 and queue_map_max=1
- pgset "src_mac_count 1" Sets the number of MACs we'll range through.
+ pgset "src_mac_count 1" Sets the number of MACs we'll range through.
The 'minimum' MAC is what you set with srcmac.
pgset "dst_mac_count 1" Sets the number of MACs we'll range through.
@@ -145,6 +164,7 @@ Examples:
UDPCSUM,
IPSEC # IPsec encapsulation (needs CONFIG_XFRM)
NODE_ALLOC # node specific memory allocation
+ NO_TIMESTAMP # disable timestamping
pgset spi SPI_VALUE Set specific SA used to transform packet.
@@ -192,24 +212,43 @@ Examples:
pgset "rate 300M" set rate to 300 Mb/s
pgset "ratep 1000000" set rate to 1Mpps
+ pgset "xmit_mode netif_receive" RX inject into stack netif_receive_skb()
+ Works with "burst" but not with "clone_skb".
+ Default xmit_mode is "start_xmit".
+
Sample scripts
==============
-A collection of small tutorial scripts for pktgen is in the
-samples/pktgen directory:
+A collection of tutorial scripts and helpers for pktgen is in the
+samples/pktgen directory. The helper parameters.sh file support easy
+and consistant parameter parsing across the sample scripts.
+
+Usage example and help:
+ ./pktgen_sample01_simple.sh -i eth4 -m 00:1B:21:3C:9D:F8 -d 192.168.8.2
+
+Usage: ./pktgen_sample01_simple.sh [-vx] -i ethX
+ -i : ($DEV) output interface/device (required)
+ -s : ($PKT_SIZE) packet size
+ -d : ($DEST_IP) destination IP
+ -m : ($DST_MAC) destination MAC-addr
+ -t : ($THREADS) threads to start
+ -c : ($SKB_CLONE) SKB clones send before alloc new SKB
+ -b : ($BURST) HW level bursting of SKBs
+ -v : ($VERBOSE) verbose
+ -x : ($DEBUG) debug
+
+The global variables being set are also listed. E.g. the required
+interface/device parameter "-i" sets variable $DEV. Copy the
+pktgen_sampleXX scripts and modify them to fit your own needs.
+
+The old scripts:
-pktgen.conf-1-1 # 1 CPU 1 dev
pktgen.conf-1-2 # 1 CPU 2 dev
-pktgen.conf-2-1 # 2 CPU's 1 dev
-pktgen.conf-2-2 # 2 CPU's 2 dev
pktgen.conf-1-1-rdos # 1 CPU 1 dev w. route DoS
pktgen.conf-1-1-ip6 # 1 CPU 1 dev ipv6
pktgen.conf-1-1-ip6-rdos # 1 CPU 1 dev ipv6 w. route DoS
pktgen.conf-1-1-flows # 1 CPU 1 dev multiple flows.
-Run in shell: ./pktgen.conf-X-Y
-This does all the setup including sending.
-
Interrupt affinity
===================
@@ -217,6 +256,9 @@ Note that when adding devices to a specific CPU it is a good idea to
also assign /proc/irq/XX/smp_affinity so that the TX interrupts are bound
to the same CPU. This reduces cache bouncing when freeing skbs.
+Plus using the device flag QUEUE_MAP_CPU, which maps the SKBs TX queue
+to the running threads CPU (directly from smp_processor_id()).
+
Enable IPsec
============
Default IPsec transformation with ESP encapsulation plus transport mode
@@ -237,18 +279,19 @@ Current commands and configuration options
start
stop
+reset
** Thread commands:
add_device
rem_device_all
-max_before_softirq
** Device commands:
count
clone_skb
+burst
debug
frags
@@ -257,10 +300,17 @@ delay
src_mac_count
dst_mac_count
-pkt_size
+pkt_size
min_pkt_size
max_pkt_size
+queue_map_min
+queue_map_max
+skb_priority
+
+tos (ipv4)
+traffic_class (ipv6)
+
mpls
udp_src_min
@@ -269,6 +319,8 @@ udp_src_max
udp_dst_min
udp_dst_max
+node
+
flag
IPSRC_RND
IPDST_RND
@@ -287,6 +339,9 @@ flag
UDPCSUM
IPSEC
NODE_ALLOC
+ NO_TIMESTAMP
+
+spi (ipsec)
dst_min
dst_max
@@ -299,8 +354,10 @@ src_mac
clear_counters
-dst6
src6
+dst6
+dst6_max
+dst6_min
flows
flowlen
@@ -308,6 +365,17 @@ flowlen
rate
ratep
+xmit_mode <start_xmit|netif_receive>
+
+vlan_cfi
+vlan_id
+vlan_p
+
+svlan_cfi
+svlan_id
+svlan_p
+
+
References:
ftp://robur.slu.se/pub/Linux/net-development/pktgen-testing/
ftp://robur.slu.se/pub/Linux/net-development/pktgen-testing/examples/
diff --git a/Documentation/networking/switchdev.txt b/Documentation/networking/switchdev.txt
index f981a9295a39..c5d7ade10ff2 100644
--- a/Documentation/networking/switchdev.txt
+++ b/Documentation/networking/switchdev.txt
@@ -1,59 +1,360 @@
-Switch (and switch-ish) device drivers HOWTO
-===========================
-
-Please note that the word "switch" is here used in very generic meaning.
-This include devices supporting L2/L3 but also various flow offloading chips,
-including switches embedded into SR-IOV NICs.
-
-Lets describe a topology a bit. Imagine the following example:
-
- +----------------------------+ +---------------+
- | SOME switch chip | | CPU |
- +----------------------------+ +---------------+
- port1 port2 port3 port4 MNGMNT | PCI-E |
- | | | | | +---------------+
- PHY PHY | | | | NIC0 NIC1
- | | | | | |
- | | +- PCI-E -+ | |
- | +------- MII -------+ |
- +------------- MII ------------+
-
-In this example, there are two independent lines between the switch silicon
-and CPU. NIC0 and NIC1 drivers are not aware of a switch presence. They are
-separate from the switch driver. SOME switch chip is by managed by a driver
-via PCI-E device MNGMNT. Note that MNGMNT device, NIC0 and NIC1 may be
-connected to some other type of bus.
-
-Now, for the previous example show the representation in kernel:
-
- +----------------------------+ +---------------+
- | SOME switch chip | | CPU |
- +----------------------------+ +---------------+
- sw0p0 sw0p1 sw0p2 sw0p3 MNGMNT | PCI-E |
- | | | | | +---------------+
- PHY PHY | | | | eth0 eth1
- | | | | | |
- | | +- PCI-E -+ | |
- | +------- MII -------+ |
- +------------- MII ------------+
-
-Lets call the example switch driver for SOME switch chip "SOMEswitch". This
-driver takes care of PCI-E device MNGMNT. There is a netdevice instance sw0pX
-created for each port of a switch. These netdevices are instances
-of "SOMEswitch" driver. sw0pX netdevices serve as a "representation"
-of the switch chip. eth0 and eth1 are instances of some other existing driver.
-
-The only difference of the switch-port netdevice from the ordinary netdevice
-is that is implements couple more NDOs:
-
- ndo_switch_parent_id_get - This returns the same ID for two port netdevices
- of the same physical switch chip. This is
- mandatory to be implemented by all switch drivers
- and serves the caller for recognition of a port
- netdevice.
- ndo_switch_parent_* - Functions that serve for a manipulation of the switch
- chip itself (it can be though of as a "parent" of the
- port, therefore the name). They are not port-specific.
- Caller might use arbitrary port netdevice of the same
- switch and it will make no difference.
- ndo_switch_port_* - Functions that serve for a port-specific manipulation.
+Ethernet switch device driver model (switchdev)
+===============================================
+Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
+Copyright (c) 2014-2015 Scott Feldman <sfeldma@gmail.com>
+
+
+The Ethernet switch device driver model (switchdev) is an in-kernel driver
+model for switch devices which offload the forwarding (data) plane from the
+kernel.
+
+Figure 1 is a block diagram showing the components of the switchdev model for
+an example setup using a data-center-class switch ASIC chip. Other setups
+with SR-IOV or soft switches, such as OVS, are possible.
+
+
+                             User-space tools                                 
+                                                                              
+       user space                   |                                         
+      +-------------------------------------------------------------------+   
+       kernel                       | Netlink                                 
+                                    |                                         
+                     +--------------+-------------------------------+         
+                     |         Network stack                        |         
+                     |           (Linux)                            |         
+                     |                                              |         
+                     +----------------------------------------------+         
+                                                                              
+ sw1p2 sw1p4 sw1p6
+                      sw1p1  + sw1p3 +  sw1p5 +         eth1             
+                        +    |    +    |    +    |            +               
+                        |    |    |    |    |    |            |               
+                     +--+----+----+----+-+--+----+---+  +-----+-----+         
+                     |         Switch driver         |  |    mgmt   |         
+                     |        (this document)        |  |   driver  |         
+                     |                               |  |           |         
+                     +--------------+----------------+  +-----------+         
+                                    |                                         
+       kernel                       | HW bus (eg PCI)                         
+      +-------------------------------------------------------------------+   
+       hardware                     |                                         
+                     +--------------+---+------------+                        
+                     |         Switch device (sw1)   |                        
+                     |  +----+                       +--------+               
+                     |  |    v offloaded data path   | mgmt port              
+                     |  |    |                       |                        
+                     +--|----|----+----+----+----+---+                        
+                        |    |    |    |    |    |                            
+                        +    +    +    +    +    +                            
+                       p1   p2   p3   p4   p5   p6
+                                       
+                             front-panel ports                                
+                                                                              
+
+ Fig 1.
+
+
+Include Files
+-------------
+
+#include <linux/netdevice.h>
+#include <net/switchdev.h>
+
+
+Configuration
+-------------
+
+Use "depends NET_SWITCHDEV" in driver's Kconfig to ensure switchdev model
+support is built for driver.
+
+
+Switch Ports
+------------
+
+On switchdev driver initialization, the driver will allocate and register a
+struct net_device (using register_netdev()) for each enumerated physical switch
+port, called the port netdev. A port netdev is the software representation of
+the physical port and provides a conduit for control traffic to/from the
+controller (the kernel) and the network, as well as an anchor point for higher
+level constructs such as bridges, bonds, VLANs, tunnels, and L3 routers. Using
+standard netdev tools (iproute2, ethtool, etc), the port netdev can also
+provide to the user access to the physical properties of the switch port such
+as PHY link state and I/O statistics.
+
+There is (currently) no higher-level kernel object for the switch beyond the
+port netdevs. All of the switchdev driver ops are netdev ops or switchdev ops.
+
+A switch management port is outside the scope of the switchdev driver model.
+Typically, the management port is not participating in offloaded data plane and
+is loaded with a different driver, such as a NIC driver, on the management port
+device.
+
+Port Netdev Naming
+^^^^^^^^^^^^^^^^^^
+
+Udev rules should be used for port netdev naming, using some unique attribute
+of the port as a key, for example the port MAC address or the port PHYS name.
+Hard-coding of kernel netdev names within the driver is discouraged; let the
+kernel pick the default netdev name, and let udev set the final name based on a
+port attribute.
+
+Using port PHYS name (ndo_get_phys_port_name) for the key is particularly
+useful for dynamically-named ports where the device names its ports based on
+external configuration. For example, if a physical 40G port is split logically
+into 4 10G ports, resulting in 4 port netdevs, the device can give a unique
+name for each port using port PHYS name. The udev rule would be:
+
+SUBSYSTEM=="net", ACTION=="add", DRIVER="<driver>", ATTR{phys_port_name}!="", \
+ NAME="$attr{phys_port_name}"
+
+Suggested naming convention is "swXpYsZ", where X is the switch name or ID, Y
+is the port name or ID, and Z is the sub-port name or ID. For example, sw1p1s0
+would be sub-port 0 on port 1 on switch 1.
+
+Switch ID
+^^^^^^^^^
+
+The switchdev driver must implement the switchdev op switchdev_port_attr_get
+for SWITCHDEV_ATTR_PORT_PARENT_ID for each port netdev, returning the same
+physical ID for each port of a switch. The ID must be unique between switches
+on the same system. The ID does not need to be unique between switches on
+different systems.
+
+The switch ID is used to locate ports on a switch and to know if aggregated
+ports belong to the same switch.
+
+Port Features
+^^^^^^^^^^^^^
+
+NETIF_F_NETNS_LOCAL
+
+If the switchdev driver (and device) only supports offloading of the default
+network namespace (netns), the driver should set this feature flag to prevent
+the port netdev from being moved out of the default netns. A netns-aware
+driver/device would not set this flag and be responsible for partitioning
+hardware to preserve netns containment. This means hardware cannot forward
+traffic from a port in one namespace to another port in another namespace.
+
+Port Topology
+^^^^^^^^^^^^^
+
+The port netdevs representing the physical switch ports can be organized into
+higher-level switching constructs. The default construct is a standalone
+router port, used to offload L3 forwarding. Two or more ports can be bonded
+together to form a LAG. Two or more ports (or LAGs) can be bridged to bridge
+L2 networks. VLANs can be applied to sub-divide L2 networks. L2-over-L3
+tunnels can be built on ports. These constructs are built using standard Linux
+tools such as the bridge driver, the bonding/team drivers, and netlink-based
+tools such as iproute2.
+
+The switchdev driver can know a particular port's position in the topology by
+monitoring NETDEV_CHANGEUPPER notifications. For example, a port moved into a
+bond will see it's upper master change. If that bond is moved into a bridge,
+the bond's upper master will change. And so on. The driver will track such
+movements to know what position a port is in in the overall topology by
+registering for netdevice events and acting on NETDEV_CHANGEUPPER.
+
+L2 Forwarding Offload
+---------------------
+
+The idea is to offload the L2 data forwarding (switching) path from the kernel
+to the switchdev device by mirroring bridge FDB entries down to the device. An
+FDB entry is the {port, MAC, VLAN} tuple forwarding destination.
+
+To offloading L2 bridging, the switchdev driver/device should support:
+
+ - Static FDB entries installed on a bridge port
+ - Notification of learned/forgotten src mac/vlans from device
+ - STP state changes on the port
+ - VLAN flooding of multicast/broadcast and unknown unicast packets
+
+Static FDB Entries
+^^^^^^^^^^^^^^^^^^
+
+The switchdev driver should implement ndo_fdb_add, ndo_fdb_del and ndo_fdb_dump
+to support static FDB entries installed to the device. Static bridge FDB
+entries are installed, for example, using iproute2 bridge cmd:
+
+ bridge fdb add ADDR dev DEV [vlan VID] [self]
+
+The driver should use the helper switchdev_port_fdb_xxx ops for ndo_fdb_xxx
+ops, and handle add/delete/dump of SWITCHDEV_OBJ_PORT_FDB object using
+switchdev_port_obj_xxx ops.
+
+XXX: what should be done if offloading this rule to hardware fails (for
+example, due to full capacity in hardware tables) ?
+
+Note: by default, the bridge does not filter on VLAN and only bridges untagged
+traffic. To enable VLAN support, turn on VLAN filtering:
+
+ echo 1 >/sys/class/net/<bridge>/bridge/vlan_filtering
+
+Notification of Learned/Forgotten Source MAC/VLANs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The switch device will learn/forget source MAC address/VLAN on ingress packets
+and notify the switch driver of the mac/vlan/port tuples. The switch driver,
+in turn, will notify the bridge driver using the switchdev notifier call:
+
+ err = call_switchdev_notifiers(val, dev, info);
+
+Where val is SWITCHDEV_FDB_ADD when learning and SWITCHDEV_FDB_DEL when
+forgetting, and info points to a struct switchdev_notifier_fdb_info. On
+SWITCHDEV_FDB_ADD, the bridge driver will install the FDB entry into the
+bridge's FDB and mark the entry as NTF_EXT_LEARNED. The iproute2 bridge
+command will label these entries "offload":
+
+ $ bridge fdb
+ 52:54:00:12:35:01 dev sw1p1 master br0 permanent
+ 00:02:00:00:02:00 dev sw1p1 master br0 offload
+ 00:02:00:00:02:00 dev sw1p1 self
+ 52:54:00:12:35:02 dev sw1p2 master br0 permanent
+ 00:02:00:00:03:00 dev sw1p2 master br0 offload
+ 00:02:00:00:03:00 dev sw1p2 self
+ 33:33:00:00:00:01 dev eth0 self permanent
+ 01:00:5e:00:00:01 dev eth0 self permanent
+ 33:33:ff:00:00:00 dev eth0 self permanent
+ 01:80:c2:00:00:0e dev eth0 self permanent
+ 33:33:00:00:00:01 dev br0 self permanent
+ 01:00:5e:00:00:01 dev br0 self permanent
+ 33:33:ff:12:35:01 dev br0 self permanent
+
+Learning on the port should be disabled on the bridge using the bridge command:
+
+ bridge link set dev DEV learning off
+
+Learning on the device port should be enabled, as well as learning_sync:
+
+ bridge link set dev DEV learning on self
+ bridge link set dev DEV learning_sync on self
+
+Learning_sync attribute enables syncing of the learned/forgotton FDB entry to
+the bridge's FDB. It's possible, but not optimal, to enable learning on the
+device port and on the bridge port, and disable learning_sync.
+
+To support learning and learning_sync port attributes, the driver implements
+switchdev op switchdev_port_attr_get/set for SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS.
+The driver should initialize the attributes to the hardware defaults.
+
+FDB Ageing
+^^^^^^^^^^
+
+There are two FDB ageing models supported: 1) ageing by the device, and 2)
+ageing by the kernel. Ageing by the device is preferred if many FDB entries
+are supported. The driver calls call_switchdev_notifiers(SWITCHDEV_FDB_DEL,
+...) to age out the FDB entry. In this model, ageing by the kernel should be
+turned off. XXX: how to turn off ageing in kernel on a per-port basis or
+otherwise prevent the kernel from ageing out the FDB entry?
+
+In the kernel ageing model, the standard bridge ageing mechanism is used to age
+out stale FDB entries. To keep an FDB entry "alive", the driver should refresh
+the FDB entry by calling call_switchdev_notifiers(SWITCHDEV_FDB_ADD, ...). The
+notification will reset the FDB entry's last-used time to now. The driver
+should rate limit refresh notifications, for example, no more than once a
+second. If the FDB entry expires, fdb_delete is called to remove entry from
+the device.
+
+STP State Change on Port
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Internally or with a third-party STP protocol implementation (e.g. mstpd), the
+bridge driver maintains the STP state for ports, and will notify the switch
+driver of STP state change on a port using the switchdev op
+switchdev_attr_port_set for SWITCHDEV_ATTR_PORT_STP_UPDATE.
+
+State is one of BR_STATE_*. The switch driver can use STP state updates to
+update ingress packet filter list for the port. For example, if port is
+DISABLED, no packets should pass, but if port moves to BLOCKED, then STP BPDUs
+and other IEEE 01:80:c2:xx:xx:xx link-local multicast packets can pass.
+
+Note that STP BDPUs are untagged and STP state applies to all VLANs on the port
+so packet filters should be applied consistently across untagged and tagged
+VLANs on the port.
+
+Flooding L2 domain
+^^^^^^^^^^^^^^^^^^
+
+For a given L2 VLAN domain, the switch device should flood multicast/broadcast
+and unknown unicast packets to all ports in domain, if allowed by port's
+current STP state. The switch driver, knowing which ports are within which
+vlan L2 domain, can program the switch device for flooding. The packet should
+also be sent to the port netdev for processing by the bridge driver. The
+bridge should not reflood the packet to the same ports the device flooded.
+XXX: the mechanism to avoid duplicate flood packets is being discuseed.
+
+It is possible for the switch device to not handle flooding and push the
+packets up to the bridge driver for flooding. This is not ideal as the number
+of ports scale in the L2 domain as the device is much more efficient at
+flooding packets that software.
+
+IGMP Snooping
+^^^^^^^^^^^^^
+
+XXX: complete this section
+
+
+L3 Routing Offload
+------------------
+
+Offloading L3 routing requires that device be programmed with FIB entries from
+the kernel, with the device doing the FIB lookup and forwarding. The device
+does a longest prefix match (LPM) on FIB entries matching route prefix and
+forwards the packet to the matching FIB entry's nexthop(s) egress ports.
+
+To program the device, the driver implements support for
+SWITCHDEV_OBJ_IPV[4|6]_FIB object using switchdev_port_obj_xxx ops.
+switchdev_port_obj_add is used for both adding a new FIB entry to the device,
+or modifying an existing entry on the device.
+
+XXX: Currently, only SWITCHDEV_OBJ_IPV4_FIB objects are supported.
+
+SWITCHDEV_OBJ_IPV4_FIB object passes:
+
+ struct switchdev_obj_ipv4_fib { /* IPV4_FIB */
+ u32 dst;
+ int dst_len;
+ struct fib_info *fi;
+ u8 tos;
+ u8 type;
+ u32 nlflags;
+ u32 tb_id;
+ } ipv4_fib;
+
+to add/modify/delete IPv4 dst/dest_len prefix on table tb_id. The *fi
+structure holds details on the route and route's nexthops. *dev is one of the
+port netdevs mentioned in the routes next hop list. If the output port netdevs
+referenced in the route's nexthop list don't all have the same switch ID, the
+driver is not called to add/modify/delete the FIB entry.
+
+Routes offloaded to the device are labeled with "offload" in the ip route
+listing:
+
+ $ ip route show
+ default via 192.168.0.2 dev eth0
+ 11.0.0.0/30 dev sw1p1 proto kernel scope link src 11.0.0.2 offload
+ 11.0.0.4/30 via 11.0.0.1 dev sw1p1 proto zebra metric 20 offload
+ 11.0.0.8/30 dev sw1p2 proto kernel scope link src 11.0.0.10 offload
+ 11.0.0.12/30 via 11.0.0.9 dev sw1p2 proto zebra metric 20 offload
+ 12.0.0.2 proto zebra metric 30 offload
+ nexthop via 11.0.0.1 dev sw1p1 weight 1
+ nexthop via 11.0.0.9 dev sw1p2 weight 1
+ 12.0.0.3 via 11.0.0.1 dev sw1p1 proto zebra metric 20 offload
+ 12.0.0.4 via 11.0.0.9 dev sw1p2 proto zebra metric 20 offload
+ 192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.15
+
+XXX: add/mod/del IPv6 FIB API
+
+Nexthop Resolution
+^^^^^^^^^^^^^^^^^^
+
+The FIB entry's nexthop list contains the nexthop tuple (gateway, dev), but for
+the switch device to forward the packet with the correct dst mac address, the
+nexthop gateways must be resolved to the neighbor's mac address. Neighbor mac
+address discovery comes via the ARP (or ND) process and is available via the
+arp_tbl neighbor table. To resolve the routes nexthop gateways, the driver
+should trigger the kernel's neighbor resolution process. See the rocker
+driver's rocker_port_ipv4_resolve() for an example.
+
+The driver can monitor for updates to arp_tbl using the netevent notifier
+NETEVENT_NEIGH_UPDATE. The device can be programmed with resolved nexthops
+for the routes as arp_tbl updates.
diff --git a/Documentation/networking/tc-actions-env-rules.txt b/Documentation/networking/tc-actions-env-rules.txt
index 70d6cf608251..f37814693ad3 100644
--- a/Documentation/networking/tc-actions-env-rules.txt
+++ b/Documentation/networking/tc-actions-env-rules.txt
@@ -8,14 +8,8 @@ For example if your action queues a packet to be processed later,
or intentionally branches by redirecting a packet, then you need to
clone the packet.
-There are certain fields in the skb tc_verd that need to be reset so we
-avoid loops, etc. A few are generic enough that skb_act_clone()
-resets them for you, so invoke skb_act_clone() rather than skb_clone().
-
2) If you munge any packet thou shalt call pskb_expand_head in the case
someone else is referencing the skb. After that you "own" the skb.
-You must also tell us if it is ok to munge the packet (TC_OK2MUNGE),
-this way any action downstream can stomp on the packet.
3) Dropping packets you don't own is a no-no. You simply return
TC_ACT_SHOT to the caller and they will drop it.
diff --git a/Documentation/networking/timestamping/txtimestamp.c b/Documentation/networking/timestamping/txtimestamp.c
index 8217510d3842..5df07047ca86 100644
--- a/Documentation/networking/timestamping/txtimestamp.c
+++ b/Documentation/networking/timestamping/txtimestamp.c
@@ -36,6 +36,7 @@
#include <asm/types.h>
#include <error.h>
#include <errno.h>
+#include <inttypes.h>
#include <linux/errqueue.h>
#include <linux/if_ether.h>
#include <linux/net_tstamp.h>
@@ -49,7 +50,6 @@
#include <poll.h>
#include <stdarg.h>
#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -96,7 +96,7 @@ static void __print_timestamp(const char *name, struct timespec *cur,
prev_ms = (long) ts_prev.tv_sec * 1000 * 1000;
prev_ms += ts_prev.tv_nsec / 1000;
- fprintf(stderr, " (%+ld us)", cur_ms - prev_ms);
+ fprintf(stderr, " (%+" PRId64 " us)", cur_ms - prev_ms);
}
ts_prev = *cur;
diff --git a/Documentation/nfc/nfc-hci.txt b/Documentation/nfc/nfc-hci.txt
index 0686c9e211c2..0dc078cab972 100644
--- a/Documentation/nfc/nfc-hci.txt
+++ b/Documentation/nfc/nfc-hci.txt
@@ -122,7 +122,7 @@ This must be done from a context that can sleep.
PHY Management
--------------
-The physical link (i2c, ...) management is defined by the following struture:
+The physical link (i2c, ...) management is defined by the following structure:
struct nfc_phy_ops {
int (*write)(void *dev_id, struct sk_buff *skb);
diff --git a/Documentation/phy.txt b/Documentation/phy.txt
index 371361c69a4b..b388c5af9e72 100644
--- a/Documentation/phy.txt
+++ b/Documentation/phy.txt
@@ -76,6 +76,8 @@ struct phy *phy_get(struct device *dev, const char *string);
struct phy *phy_optional_get(struct device *dev, const char *string);
struct phy *devm_phy_get(struct device *dev, const char *string);
struct phy *devm_phy_optional_get(struct device *dev, const char *string);
+struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
+ int index);
phy_get, phy_optional_get, devm_phy_get and devm_phy_optional_get can
be used to get the PHY. In the case of dt boot, the string arguments
@@ -86,7 +88,10 @@ successful PHY get. On driver detach, release function is invoked on
the the devres data and devres data is freed. phy_optional_get and
devm_phy_optional_get should be used when the phy is optional. These
two functions will never return -ENODEV, but instead returns NULL when
-the phy cannot be found.
+the phy cannot be found.Some generic drivers, such as ehci, may use multiple
+phys and for such drivers referencing phy(s) by name(s) does not make sense. In
+this case, devm_of_phy_get_by_index can be used to get a phy reference based on
+the index.
It should be noted that NULL is a valid phy reference. All phy
consumer calls on the NULL phy become NOPs. That is the release calls,
diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
index a9b47163bb5d..4976389e432d 100644
--- a/Documentation/pinctrl.txt
+++ b/Documentation/pinctrl.txt
@@ -714,6 +714,7 @@ static struct pinmux_ops foo_pmxops = {
.get_function_name = foo_get_fname,
.get_function_groups = foo_get_groups,
.set_mux = foo_set_mux,
+ .strict = true,
};
/* Pinmux operations are handled by some pin controller */
@@ -830,6 +831,11 @@ separate memory range only intended for GPIO driving, and the register
range dealing with pin config and pin multiplexing get placed into a
different memory range and a separate section of the data sheet.
+A flag "strict" in struct pinctrl_desc is available to check and deny
+simultaneous access to the same pin from GPIO and pin multiplexing
+consumers on hardware of this type. The pinctrl driver should set this flag
+accordingly.
+
(B)
pin config
@@ -850,6 +856,11 @@ possible that the GPIO, pin config and pin multiplex registers are placed into
the same memory range and the same section of the data sheet, although that
need not be the case.
+In some pin controllers, although the physical pins are designed in the same
+way as (B), the GPIO function still can't be enabled at the same time as the
+peripheral functions. So again the "strict" flag should be set, denying
+simultaneous activation by GPIO and other muxed in devices.
+
From a kernel point of view, however, these are different aspects of the
hardware and shall be put into different subsystems:
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index 44fe1d28a163..e76dc0ad4d2b 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -556,6 +556,12 @@ helper functions described in Section 4. In that case, pm_runtime_resume()
should be used. Of course, for this purpose the device's runtime PM has to be
enabled earlier by calling pm_runtime_enable().
+Note, if the device may execute pm_runtime calls during the probe (such as
+if it is registers with a subsystem that may call back in) then the
+pm_runtime_get_sync() call paired with a pm_runtime_put() call will be
+appropriate to ensure that the device is not put back to sleep during the
+probe. This can happen with systems such as the network device layer.
+
It may be desirable to suspend the device once ->probe() has finished.
Therefore the driver core uses the asyncronous pm_request_idle() to submit a
request to execute the subsystem-level idle callback for the device at that
diff --git a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX
index 6fd0e8bb8140..9dc845cf7d88 100644
--- a/Documentation/powerpc/00-INDEX
+++ b/Documentation/powerpc/00-INDEX
@@ -30,3 +30,5 @@ ptrace.txt
- Information on the ptrace interfaces for hardware debug registers.
transactional_memory.txt
- Overview of the Power8 transactional memory support.
+dscr.txt
+ - Overview DSCR (Data Stream Control Register) support.
diff --git a/Documentation/powerpc/cxl.txt b/Documentation/powerpc/cxl.txt
index 2c71ecc519d9..2a230d01cd8c 100644
--- a/Documentation/powerpc/cxl.txt
+++ b/Documentation/powerpc/cxl.txt
@@ -133,6 +133,9 @@ User API
The following file operations are supported on both slave and
master devices.
+ A userspace library libcxl is avaliable here:
+ https://github.com/ibm-capi/libcxl
+ This provides a C interface to this kernel API.
open
----
@@ -366,6 +369,7 @@ Sysfs Class
enumeration and tuning of the accelerators. Its layout is
described in Documentation/ABI/testing/sysfs-class-cxl
+
Udev rules
==========
diff --git a/Documentation/powerpc/dscr.txt b/Documentation/powerpc/dscr.txt
new file mode 100644
index 000000000000..1ff4400c57b3
--- /dev/null
+++ b/Documentation/powerpc/dscr.txt
@@ -0,0 +1,83 @@
+ DSCR (Data Stream Control Register)
+ ================================================
+
+DSCR register in powerpc allows user to have some control of prefetch of data
+stream in the processor. Please refer to the ISA documents or related manual
+for more detailed information regarding how to use this DSCR to attain this
+control of the pefetches . This document here provides an overview of kernel
+support for DSCR, related kernel objects, it's functionalities and exported
+user interface.
+
+(A) Data Structures:
+
+ (1) thread_struct:
+ dscr /* Thread DSCR value */
+ dscr_inherit /* Thread has changed default DSCR */
+
+ (2) PACA:
+ dscr_default /* per-CPU DSCR default value */
+
+ (3) sysfs.c:
+ dscr_default /* System DSCR default value */
+
+(B) Scheduler Changes:
+
+ Scheduler will write the per-CPU DSCR default which is stored in the
+ CPU's PACA value into the register if the thread has dscr_inherit value
+ cleared which means that it has not changed the default DSCR till now.
+ If the dscr_inherit value is set which means that it has changed the
+ default DSCR value, scheduler will write the changed value which will
+ now be contained in thread struct's dscr into the register instead of
+ the per-CPU default PACA based DSCR value.
+
+ NOTE: Please note here that the system wide global DSCR value never
+ gets used directly in the scheduler process context switch at all.
+
+(C) SYSFS Interface:
+
+ Global DSCR default: /sys/devices/system/cpu/dscr_default
+ CPU specific DSCR default: /sys/devices/system/cpu/cpuN/dscr
+
+ Changing the global DSCR default in the sysfs will change all the CPU
+ specific DSCR defaults immediately in their PACA structures. Again if
+ the current process has the dscr_inherit clear, it also writes the new
+ value into every CPU's DSCR register right away and updates the current
+ thread's DSCR value as well.
+
+ Changing the CPU specif DSCR default value in the sysfs does exactly
+ the same thing as above but unlike the global one above, it just changes
+ stuff for that particular CPU instead for all the CPUs on the system.
+
+(D) User Space Instructions:
+
+ The DSCR register can be accessed in the user space using any of these
+ two SPR numbers available for that purpose.
+
+ (1) Problem state SPR: 0x03 (Un-privileged, POWER8 only)
+ (2) Privileged state SPR: 0x11 (Privileged)
+
+ Accessing DSCR through privileged SPR number (0x11) from user space
+ works, as it is emulated following an illegal instruction exception
+ inside the kernel. Both mfspr and mtspr instructions are emulated.
+
+ Accessing DSCR through user level SPR (0x03) from user space will first
+ create a facility unavailable exception. Inside this exception handler
+ all mfspr isntruction based read attempts will get emulated and returned
+ where as the first mtspr instruction based write attempts will enable
+ the DSCR facility for the next time around (both for read and write) by
+ setting DSCR facility in the FSCR register.
+
+(E) Specifics about 'dscr_inherit':
+
+ The thread struct element 'dscr_inherit' represents whether the thread
+ in question has attempted and changed the DSCR itself using any of the
+ following methods. This element signifies whether the thread wants to
+ use the CPU default DSCR value or its own changed DSCR value in the
+ kernel.
+
+ (1) mtspr instruction (SPR number 0x03)
+ (2) mtspr instruction (SPR number 0x11)
+ (3) ptrace interface (Explicitly set user DSCR value)
+
+ Any child of the process created after this event in the process inherits
+ this same behaviour as well.
diff --git a/Documentation/powerpc/transactional_memory.txt b/Documentation/powerpc/transactional_memory.txt
index ded69794a5c0..ba0a2a4a54ba 100644
--- a/Documentation/powerpc/transactional_memory.txt
+++ b/Documentation/powerpc/transactional_memory.txt
@@ -74,22 +74,23 @@ Causes of transaction aborts
Syscalls
========
-Performing syscalls from within transaction is not recommended, and can lead
-to unpredictable results.
+Syscalls made from within an active transaction will not be performed and the
+transaction will be doomed by the kernel with the failure code TM_CAUSE_SYSCALL
+| TM_CAUSE_PERSISTENT.
-Syscalls do not by design abort transactions, but beware: The kernel code will
-not be running in transactional state. The effect of syscalls will always
-remain visible, but depending on the call they may abort your transaction as a
-side-effect, read soon-to-be-aborted transactional data that should not remain
-invisible, etc. If you constantly retry a transaction that constantly aborts
-itself by calling a syscall, you'll have a livelock & make no progress.
+Syscalls made from within a suspended transaction are performed as normal and
+the transaction is not explicitly doomed by the kernel. However, what the
+kernel does to perform the syscall may result in the transaction being doomed
+by the hardware. The syscall is performed in suspended mode so any side
+effects will be persistent, independent of transaction success or failure. No
+guarantees are provided by the kernel about which syscalls will affect
+transaction success.
-Simple syscalls (e.g. sigprocmask()) "could" be OK. Even things like write()
-from, say, printf() should be OK as long as the kernel does not access any
-memory that was accessed transactionally.
-
-Consider any syscalls that happen to work as debug-only -- not recommended for
-production use. Best to queue them up till after the transaction is over.
+Care must be taken when relying on syscalls to abort during active transactions
+if the calls are made via a library. Libraries may cache values (which may
+give the appearance of success) or perform operations that cause transaction
+failure before entering the kernel (which may produce different failure codes).
+Examples are glibc's getpid() and lazy symbol resolution.
Signals
@@ -176,8 +177,7 @@ kernel aborted a transaction:
TM_CAUSE_RESCHED Thread was rescheduled.
TM_CAUSE_TLBI Software TLB invalid.
TM_CAUSE_FAC_UNAV FP/VEC/VSX unavailable trap.
- TM_CAUSE_SYSCALL Currently unused; future syscalls that must abort
- transactions for consistency will use this.
+ TM_CAUSE_SYSCALL Syscall from active transaction.
TM_CAUSE_SIGNAL Signal delivered.
TM_CAUSE_MISC Currently unused.
TM_CAUSE_ALIGNMENT Alignment fault.
diff --git a/Documentation/pps/pps.txt b/Documentation/pps/pps.txt
index c03b1be5eb15..c508cceeee7d 100644
--- a/Documentation/pps/pps.txt
+++ b/Documentation/pps/pps.txt
@@ -166,7 +166,7 @@ Testing the PPS support
In order to test the PPS support even without specific hardware you can use
the ktimer driver (see the client subsection in the PPS configuration menu)
-and the userland tools provided into Documentaion/pps/ directory.
+and the userland tools provided in the Documentation/pps/ directory.
Once you have enabled the compilation of ktimer just modprobe it (if
not statically compiled):
diff --git a/Documentation/prctl/Makefile b/Documentation/prctl/Makefile
index 2948b7b124b9..44de3080c7f2 100644
--- a/Documentation/prctl/Makefile
+++ b/Documentation/prctl/Makefile
@@ -1,3 +1,4 @@
+ifndef CROSS_COMPILE
# List of programs to build
hostprogs-$(CONFIG_X86) := disable-tsc-ctxt-sw-stress-test disable-tsc-on-off-stress-test disable-tsc-test
# Tell kbuild to always build the programs
@@ -6,3 +7,4 @@ always := $(hostprogs-y)
HOSTCFLAGS_disable-tsc-ctxt-sw-stress-test.o += -I$(objtree)/usr/include
HOSTCFLAGS_disable-tsc-on-off-stress-test.o += -I$(objtree)/usr/include
HOSTCFLAGS_disable-tsc-test.o += -I$(objtree)/usr/include
+endif
diff --git a/Documentation/preempt-locking.txt b/Documentation/preempt-locking.txt
index 57883ca2498b..e89ce6624af2 100644
--- a/Documentation/preempt-locking.txt
+++ b/Documentation/preempt-locking.txt
@@ -48,7 +48,7 @@ preemption must be disabled around such regions.
Note, some FPU functions are already explicitly preempt safe. For example,
kernel_fpu_begin and kernel_fpu_end will disable and enable preemption.
-However, math_state_restore must be called with preemption disabled.
+However, fpu__restore() must be called with preemption disabled.
RULE #3: Lock acquire and release must be performed by same task
diff --git a/Documentation/s390/qeth.txt b/Documentation/s390/qeth.txt
index 74122ada9949..aa06fcf5f8c2 100644
--- a/Documentation/s390/qeth.txt
+++ b/Documentation/s390/qeth.txt
@@ -1,6 +1,6 @@
IBM s390 QDIO Ethernet Driver
-HiperSockets Bridge Port Support
+OSA and HiperSockets Bridge Port Support
Uevents
@@ -8,7 +8,7 @@ To generate the events the device must be assigned a role of either
a primary or a secondary Bridge Port. For more information, see
"z/VM Connectivity, SC24-6174".
-When run on HiperSockets Bridge Capable Port hardware, and the state
+When run on an OSA or HiperSockets Bridge Capable Port hardware, and the state
of some configured Bridge Port device on the channel changes, a udev
event with ACTION=CHANGE is emitted on behalf of the corresponding
ccwgroup device. The event has the following attributes:
diff --git a/Documentation/scheduler/sched-deadline.txt b/Documentation/scheduler/sched-deadline.txt
index 21461a0441c1..e114513a2731 100644
--- a/Documentation/scheduler/sched-deadline.txt
+++ b/Documentation/scheduler/sched-deadline.txt
@@ -8,6 +8,10 @@ CONTENTS
1. Overview
2. Scheduling algorithm
3. Scheduling Real-Time Tasks
+ 3.1 Definitions
+ 3.2 Schedulability Analysis for Uniprocessor Systems
+ 3.3 Schedulability Analysis for Multiprocessor Systems
+ 3.4 Relationship with SCHED_DEADLINE Parameters
4. Bandwidth management
4.1 System-wide settings
4.2 Task interface
@@ -43,7 +47,7 @@ CONTENTS
"deadline", to schedule tasks. A SCHED_DEADLINE task should receive
"runtime" microseconds of execution time every "period" microseconds, and
these "runtime" microseconds are available within "deadline" microseconds
- from the beginning of the period. In order to implement this behaviour,
+ from the beginning of the period. In order to implement this behavior,
every time the task wakes up, the scheduler computes a "scheduling deadline"
consistent with the guarantee (using the CBS[2,3] algorithm). Tasks are then
scheduled using EDF[1] on these scheduling deadlines (the task with the
@@ -52,7 +56,7 @@ CONTENTS
"admission control" strategy (see Section "4. Bandwidth management") is used
(clearly, if the system is overloaded this guarantee cannot be respected).
- Summing up, the CBS[2,3] algorithms assigns scheduling deadlines to tasks so
+ Summing up, the CBS[2,3] algorithm assigns scheduling deadlines to tasks so
that each task runs for at most its runtime every period, avoiding any
interference between different tasks (bandwidth isolation), while the EDF[1]
algorithm selects the task with the earliest scheduling deadline as the one
@@ -63,7 +67,7 @@ CONTENTS
In more details, the CBS algorithm assigns scheduling deadlines to
tasks in the following way:
- - Each SCHED_DEADLINE task is characterised by the "runtime",
+ - Each SCHED_DEADLINE task is characterized by the "runtime",
"deadline", and "period" parameters;
- The state of the task is described by a "scheduling deadline", and
@@ -78,7 +82,7 @@ CONTENTS
then, if the scheduling deadline is smaller than the current time, or
this condition is verified, the scheduling deadline and the
- remaining runtime are re-initialised as
+ remaining runtime are re-initialized as
scheduling deadline = current time + deadline
remaining runtime = runtime
@@ -126,31 +130,37 @@ CONTENTS
suited for periodic or sporadic real-time tasks that need guarantees on their
timing behavior, e.g., multimedia, streaming, control applications, etc.
+3.1 Definitions
+------------------------
+
A typical real-time task is composed of a repetition of computation phases
(task instances, or jobs) which are activated on a periodic or sporadic
fashion.
- Each job J_j (where J_j is the j^th job of the task) is characterised by an
+ Each job J_j (where J_j is the j^th job of the task) is characterized by an
arrival time r_j (the time when the job starts), an amount of computation
time c_j needed to finish the job, and a job absolute deadline d_j, which
is the time within which the job should be finished. The maximum execution
- time max_j{c_j} is called "Worst Case Execution Time" (WCET) for the task.
+ time max{c_j} is called "Worst Case Execution Time" (WCET) for the task.
A real-time task can be periodic with period P if r_{j+1} = r_j + P, or
sporadic with minimum inter-arrival time P is r_{j+1} >= r_j + P. Finally,
d_j = r_j + D, where D is the task's relative deadline.
- The utilisation of a real-time task is defined as the ratio between its
+ Summing up, a real-time task can be described as
+ Task = (WCET, D, P)
+
+ The utilization of a real-time task is defined as the ratio between its
WCET and its period (or minimum inter-arrival time), and represents
the fraction of CPU time needed to execute the task.
- If the total utilisation sum_i(WCET_i/P_i) is larger than M (with M equal
+ If the total utilization U=sum(WCET_i/P_i) is larger than M (with M equal
to the number of CPUs), then the scheduler is unable to respect all the
deadlines.
- Note that total utilisation is defined as the sum of the utilisations
+ Note that total utilization is defined as the sum of the utilizations
WCET_i/P_i over all the real-time tasks in the system. When considering
multiple real-time tasks, the parameters of the i-th task are indicated
with the "_i" suffix.
- Moreover, if the total utilisation is larger than M, then we risk starving
+ Moreover, if the total utilization is larger than M, then we risk starving
non- real-time tasks by real-time tasks.
- If, instead, the total utilisation is smaller than M, then non real-time
+ If, instead, the total utilization is smaller than M, then non real-time
tasks will not be starved and the system might be able to respect all the
deadlines.
As a matter of fact, in this case it is possible to provide an upper bound
@@ -159,38 +169,119 @@ CONTENTS
More precisely, it can be proven that using a global EDF scheduler the
maximum tardiness of each task is smaller or equal than
((M − 1) · WCET_max − WCET_min)/(M − (M − 2) · U_max) + WCET_max
- where WCET_max = max_i{WCET_i} is the maximum WCET, WCET_min=min_i{WCET_i}
- is the minimum WCET, and U_max = max_i{WCET_i/P_i} is the maximum utilisation.
+ where WCET_max = max{WCET_i} is the maximum WCET, WCET_min=min{WCET_i}
+ is the minimum WCET, and U_max = max{WCET_i/P_i} is the maximum
+ utilization[12].
+
+3.2 Schedulability Analysis for Uniprocessor Systems
+------------------------
If M=1 (uniprocessor system), or in case of partitioned scheduling (each
real-time task is statically assigned to one and only one CPU), it is
possible to formally check if all the deadlines are respected.
If D_i = P_i for all tasks, then EDF is able to respect all the deadlines
- of all the tasks executing on a CPU if and only if the total utilisation
+ of all the tasks executing on a CPU if and only if the total utilization
of the tasks running on such a CPU is smaller or equal than 1.
If D_i != P_i for some task, then it is possible to define the density of
- a task as C_i/min{D_i,T_i}, and EDF is able to respect all the deadlines
- of all the tasks running on a CPU if the sum sum_i C_i/min{D_i,T_i} of the
- densities of the tasks running on such a CPU is smaller or equal than 1
- (notice that this condition is only sufficient, and not necessary).
+ a task as WCET_i/min{D_i,P_i}, and EDF is able to respect all the deadlines
+ of all the tasks running on a CPU if the sum of the densities of the tasks
+ running on such a CPU is smaller or equal than 1:
+ sum(WCET_i / min{D_i, P_i}) <= 1
+ It is important to notice that this condition is only sufficient, and not
+ necessary: there are task sets that are schedulable, but do not respect the
+ condition. For example, consider the task set {Task_1,Task_2} composed by
+ Task_1=(50ms,50ms,100ms) and Task_2=(10ms,100ms,100ms).
+ EDF is clearly able to schedule the two tasks without missing any deadline
+ (Task_1 is scheduled as soon as it is released, and finishes just in time
+ to respect its deadline; Task_2 is scheduled immediately after Task_1, hence
+ its response time cannot be larger than 50ms + 10ms = 60ms) even if
+ 50 / min{50,100} + 10 / min{100, 100} = 50 / 50 + 10 / 100 = 1.1
+ Of course it is possible to test the exact schedulability of tasks with
+ D_i != P_i (checking a condition that is both sufficient and necessary),
+ but this cannot be done by comparing the total utilization or density with
+ a constant. Instead, the so called "processor demand" approach can be used,
+ computing the total amount of CPU time h(t) needed by all the tasks to
+ respect all of their deadlines in a time interval of size t, and comparing
+ such a time with the interval size t. If h(t) is smaller than t (that is,
+ the amount of time needed by the tasks in a time interval of size t is
+ smaller than the size of the interval) for all the possible values of t, then
+ EDF is able to schedule the tasks respecting all of their deadlines. Since
+ performing this check for all possible values of t is impossible, it has been
+ proven[4,5,6] that it is sufficient to perform the test for values of t
+ between 0 and a maximum value L. The cited papers contain all of the
+ mathematical details and explain how to compute h(t) and L.
+ In any case, this kind of analysis is too complex as well as too
+ time-consuming to be performed on-line. Hence, as explained in Section
+ 4 Linux uses an admission test based on the tasks' utilizations.
+
+3.3 Schedulability Analysis for Multiprocessor Systems
+------------------------
On multiprocessor systems with global EDF scheduling (non partitioned
systems), a sufficient test for schedulability can not be based on the
- utilisations (it can be shown that task sets with utilisations slightly
- larger than 1 can miss deadlines regardless of the number of CPUs M).
- However, as previously stated, enforcing that the total utilisation is smaller
- than M is enough to guarantee that non real-time tasks are not starved and
- that the tardiness of real-time tasks has an upper bound.
+ utilizations or densities: it can be shown that even if D_i = P_i task
+ sets with utilizations slightly larger than 1 can miss deadlines regardless
+ of the number of CPUs.
+
+ Consider a set {Task_1,...Task_{M+1}} of M+1 tasks on a system with M
+ CPUs, with the first task Task_1=(P,P,P) having period, relative deadline
+ and WCET equal to P. The remaining M tasks Task_i=(e,P-1,P-1) have an
+ arbitrarily small worst case execution time (indicated as "e" here) and a
+ period smaller than the one of the first task. Hence, if all the tasks
+ activate at the same time t, global EDF schedules these M tasks first
+ (because their absolute deadlines are equal to t + P - 1, hence they are
+ smaller than the absolute deadline of Task_1, which is t + P). As a
+ result, Task_1 can be scheduled only at time t + e, and will finish at
+ time t + e + P, after its absolute deadline. The total utilization of the
+ task set is U = M · e / (P - 1) + P / P = M · e / (P - 1) + 1, and for small
+ values of e this can become very close to 1. This is known as "Dhall's
+ effect"[7]. Note: the example in the original paper by Dhall has been
+ slightly simplified here (for example, Dhall more correctly computed
+ lim_{e->0}U).
+
+ More complex schedulability tests for global EDF have been developed in
+ real-time literature[8,9], but they are not based on a simple comparison
+ between total utilization (or density) and a fixed constant. If all tasks
+ have D_i = P_i, a sufficient schedulability condition can be expressed in
+ a simple way:
+ sum(WCET_i / P_i) <= M - (M - 1) · U_max
+ where U_max = max{WCET_i / P_i}[10]. Notice that for U_max = 1,
+ M - (M - 1) · U_max becomes M - M + 1 = 1 and this schedulability condition
+ just confirms the Dhall's effect. A more complete survey of the literature
+ about schedulability tests for multi-processor real-time scheduling can be
+ found in [11].
+
+ As seen, enforcing that the total utilization is smaller than M does not
+ guarantee that global EDF schedules the tasks without missing any deadline
+ (in other words, global EDF is not an optimal scheduling algorithm). However,
+ a total utilization smaller than M is enough to guarantee that non real-time
+ tasks are not starved and that the tardiness of real-time tasks has an upper
+ bound[12] (as previously noted). Different bounds on the maximum tardiness
+ experienced by real-time tasks have been developed in various papers[13,14],
+ but the theoretical result that is important for SCHED_DEADLINE is that if
+ the total utilization is smaller or equal than M then the response times of
+ the tasks are limited.
+
+3.4 Relationship with SCHED_DEADLINE Parameters
+------------------------
- SCHED_DEADLINE can be used to schedule real-time tasks guaranteeing that
- the jobs' deadlines of a task are respected. In order to do this, a task
- must be scheduled by setting:
+ Finally, it is important to understand the relationship between the
+ SCHED_DEADLINE scheduling parameters described in Section 2 (runtime,
+ deadline and period) and the real-time task parameters (WCET, D, P)
+ described in this section. Note that the tasks' temporal constraints are
+ represented by its absolute deadlines d_j = r_j + D described above, while
+ SCHED_DEADLINE schedules the tasks according to scheduling deadlines (see
+ Section 2).
+ If an admission test is used to guarantee that the scheduling deadlines
+ are respected, then SCHED_DEADLINE can be used to schedule real-time tasks
+ guaranteeing that all the jobs' deadlines of a task are respected.
+ In order to do this, a task must be scheduled by setting:
- runtime >= WCET
- deadline = D
- period <= P
- IOW, if runtime >= WCET and if period is >= P, then the scheduling deadlines
+ IOW, if runtime >= WCET and if period is <= P, then the scheduling deadlines
and the absolute deadlines (d_j) coincide, so a proper admission control
allows to respect the jobs' absolute deadlines for this task (this is what is
called "hard schedulability property" and is an extension of Lemma 1 of [2]).
@@ -206,6 +297,39 @@ CONTENTS
Symposium, 1998. http://retis.sssup.it/~giorgio/paps/1998/rtss98-cbs.pdf
3 - L. Abeni. Server Mechanisms for Multimedia Applications. ReTiS Lab
Technical Report. http://disi.unitn.it/~abeni/tr-98-01.pdf
+ 4 - J. Y. Leung and M.L. Merril. A Note on Preemptive Scheduling of
+ Periodic, Real-Time Tasks. Information Processing Letters, vol. 11,
+ no. 3, pp. 115-118, 1980.
+ 5 - S. K. Baruah, A. K. Mok and L. E. Rosier. Preemptively Scheduling
+ Hard-Real-Time Sporadic Tasks on One Processor. Proceedings of the
+ 11th IEEE Real-time Systems Symposium, 1990.
+ 6 - S. K. Baruah, L. E. Rosier and R. R. Howell. Algorithms and Complexity
+ Concerning the Preemptive Scheduling of Periodic Real-Time tasks on
+ One Processor. Real-Time Systems Journal, vol. 4, no. 2, pp 301-324,
+ 1990.
+ 7 - S. J. Dhall and C. L. Liu. On a real-time scheduling problem. Operations
+ research, vol. 26, no. 1, pp 127-140, 1978.
+ 8 - T. Baker. Multiprocessor EDF and Deadline Monotonic Schedulability
+ Analysis. Proceedings of the 24th IEEE Real-Time Systems Symposium, 2003.
+ 9 - T. Baker. An Analysis of EDF Schedulability on a Multiprocessor.
+ IEEE Transactions on Parallel and Distributed Systems, vol. 16, no. 8,
+ pp 760-768, 2005.
+ 10 - J. Goossens, S. Funk and S. Baruah, Priority-Driven Scheduling of
+ Periodic Task Systems on Multiprocessors. Real-Time Systems Journal,
+ vol. 25, no. 2–3, pp. 187–205, 2003.
+ 11 - R. Davis and A. Burns. A Survey of Hard Real-Time Scheduling for
+ Multiprocessor Systems. ACM Computing Surveys, vol. 43, no. 4, 2011.
+ http://www-users.cs.york.ac.uk/~robdavis/papers/MPSurveyv5.0.pdf
+ 12 - U. C. Devi and J. H. Anderson. Tardiness Bounds under Global EDF
+ Scheduling on a Multiprocessor. Real-Time Systems Journal, vol. 32,
+ no. 2, pp 133-189, 2008.
+ 13 - P. Valente and G. Lipari. An Upper Bound to the Lateness of Soft
+ Real-Time Tasks Scheduled by EDF on Multiprocessors. Proceedings of
+ the 26th IEEE Real-Time Systems Symposium, 2005.
+ 14 - J. Erickson, U. Devi and S. Baruah. Improved tardiness bounds for
+ Global EDF. Proceedings of the 22nd Euromicro Conference on
+ Real-Time Systems, 2010.
+
4. Bandwidth management
=======================
@@ -218,10 +342,10 @@ CONTENTS
no guarantee can be given on the actual scheduling of the -deadline tasks.
As already stated in Section 3, a necessary condition to be respected to
- correctly schedule a set of real-time tasks is that the total utilisation
+ correctly schedule a set of real-time tasks is that the total utilization
is smaller than M. When talking about -deadline tasks, this requires that
the sum of the ratio between runtime and period for all tasks is smaller
- than M. Notice that the ratio runtime/period is equivalent to the utilisation
+ than M. Notice that the ratio runtime/period is equivalent to the utilization
of a "traditional" real-time task, and is also often referred to as
"bandwidth".
The interface used to control the CPU bandwidth that can be allocated
@@ -251,7 +375,7 @@ CONTENTS
The system wide settings are configured under the /proc virtual file system.
For now the -rt knobs are used for -deadline admission control and the
- -deadline runtime is accounted against the -rt runtime. We realise that this
+ -deadline runtime is accounted against the -rt runtime. We realize that this
isn't entirely desirable; however, it is better to have a small interface for
now, and be able to change it easily later. The ideal situation (see 5.) is to
run -rt tasks from a -deadline server; in which case the -rt bandwidth is a
diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt
index 731bc4f4c5e6..255075157511 100644
--- a/Documentation/scsi/scsi_mid_low_api.txt
+++ b/Documentation/scsi/scsi_mid_low_api.txt
@@ -1269,7 +1269,7 @@ Members of interest:
request_buffer - either contains data buffer or scatter gather list
depending on the setting of use_sg. Scatter gather
elements are defined by 'struct scatterlist' found
- in include/asm/scatterlist.h .
+ in include/linux/scatterlist.h .
done - function pointer that should be invoked by LLD when the
SCSI command is completed (successfully or otherwise).
Should only be called by an LLD if the LLD has accepted
diff --git a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt
index 0d5bdb153d3b..f29fa550665a 100644
--- a/Documentation/scsi/st.txt
+++ b/Documentation/scsi/st.txt
@@ -151,6 +151,65 @@ A link named 'tape' is made from the SCSI device directory to the class
directory corresponding to the mode 0 auto-rewind device (e.g., st0).
+SYSFS AND STATISTICS FOR TAPE DEVICES
+
+The st driver maintains statistics for tape drives inside the sysfs filesystem.
+The following method can be used to locate the statistics that are
+available (assuming that sysfs is mounted at /sys):
+
+1. Use opendir(3) on the directory /sys/class/scsi_tape
+2. Use readdir(3) to read the directory contents
+3. Use regcomp(3)/regexec(3) to match directory entries to the extended
+ regular expression "^st[0-9]+$"
+4. Access the statistics from the /sys/class/scsi_tape/<match>/stats
+ directory (where <match> is a directory entry from /sys/class/scsi_tape
+ that matched the extended regular expression)
+
+The reason for using this approach is that all the character devices
+pointing to the same tape drive use the same statistics. That means
+that st0 would have the same statistics as nst0.
+
+The directory contains the following statistics files:
+
+1. in_flight - The number of I/Os currently outstanding to this device.
+2. io_ns - The amount of time spent waiting (in nanoseconds) for all I/O
+ to complete (including read and write). This includes tape movement
+ commands such as seeking between file or set marks and implicit tape
+ movement such as when rewind on close tape devices are used.
+3. other_cnt - The number of I/Os issued to the tape drive other than read or
+ write commands. The time taken to complete these commands uses the
+ following calculation io_ms-read_ms-write_ms.
+4. read_byte_cnt - The number of bytes read from the tape drive.
+5. read_cnt - The number of read requests issued to the tape drive.
+6. read_ns - The amount of time (in nanoseconds) spent waiting for read
+ requests to complete.
+7. write_byte_cnt - The number of bytes written to the tape drive.
+8. write_cnt - The number of write requests issued to the tape drive.
+9. write_ns - The amount of time (in nanoseconds) spent waiting for write
+ requests to complete.
+10. resid_cnt - The number of times during a read or write we found
+ the residual amount to be non-zero. This should mean that a program
+ is issuing a read larger thean the block size on tape. For write
+ not all data made it to tape.
+
+Note: The in_flight value is incremented when an I/O starts the I/O
+itself is not added to the statistics until it completes.
+
+The total of read_cnt, write_cnt, and other_cnt may not total to the same
+value as iodone_cnt at the device level. The tape statistics only count
+I/O issued via the st module.
+
+When read the statistics may not be temporally consistent while I/O is in
+progress. The individual values are read and written to atomically however
+when reading them back via sysfs they may be in the process of being
+updated when starting an I/O or when it is completed.
+
+The value shown in in_flight is incremented before any statstics are
+updated and decremented when an I/O completes after updating statistics.
+The value of in_flight is 0 when there are no I/Os outstanding that are
+issued by the st driver. Tape statistics do not take into account any
+I/O performed via the sg device.
+
BSD AND SYS V SEMANTICS
The user can choose between these two behaviours of the tape driver by
diff --git a/Documentation/serial/serial-rs485.txt b/Documentation/serial/serial-rs485.txt
index 39dac95422a3..2253b8b45a74 100644
--- a/Documentation/serial/serial-rs485.txt
+++ b/Documentation/serial/serial-rs485.txt
@@ -33,50 +33,10 @@
the values given by the device tree.
Any driver for devices capable of working both as RS232 and RS485 should
- provide at least the following ioctls:
-
- - TIOCSRS485 (typically associated with number 0x542F). This ioctl is used
- to enable/disable RS485 mode from user-space
-
- - TIOCGRS485 (typically associated with number 0x542E). This ioctl is used
- to get RS485 mode from kernel-space (i.e., driver) to user-space.
-
- In other words, the serial driver should contain a code similar to the next
- one:
-
- static struct uart_ops atmel_pops = {
- /* ... */
- .ioctl = handle_ioctl,
- };
-
- static int handle_ioctl(struct uart_port *port,
- unsigned int cmd,
- unsigned long arg)
- {
- struct serial_rs485 rs485conf;
-
- switch (cmd) {
- case TIOCSRS485:
- if (copy_from_user(&rs485conf,
- (struct serial_rs485 *) arg,
- sizeof(rs485conf)))
- return -EFAULT;
-
- /* ... */
- break;
-
- case TIOCGRS485:
- if (copy_to_user((struct serial_rs485 *) arg,
- ...,
- sizeof(rs485conf)))
- return -EFAULT;
- /* ... */
- break;
-
- /* ... */
- }
- }
-
+ implement the rs485_config callback in the uart_port structure. The
+ serial_core calls rs485_config to do the device specific part in response
+ to TIOCSRS485 and TIOCGRS485 ioctls (see below). The rs485_config callback
+ receives a pointer to struct serial_rs485.
4. USAGE FROM USER-LEVEL
@@ -85,7 +45,7 @@
#include <linux/serial.h>
- /* Driver-specific ioctls: */
+ /* RS485 ioctls: */
#define TIOCGRS485 0x542E
#define TIOCSRS485 0x542F
diff --git a/Documentation/serial/tty.txt b/Documentation/serial/tty.txt
index dbe6623fed1c..973c8ad3f959 100644
--- a/Documentation/serial/tty.txt
+++ b/Documentation/serial/tty.txt
@@ -4,9 +4,6 @@
Your guide to the ancient and twisted locking policies of the tty layer and
the warped logic behind them. Beware all ye who read on.
-FIXME: still need to work out the full set of BKL assumptions and document
-them so they can eventually be killed off.
-
Line Discipline
---------------
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 5a3163cac6c3..ec099d4343f2 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -11,7 +11,10 @@ ALC880
ALC260
======
- N/A
+ gpio1 Enable GPIO1
+ coef Enable EAPD via COEF table
+ fujitsu Quirk for FSC S7020
+ fujitsu-jwse Quirk for FSC S7020 with jack modes and HP mic support
ALC262
======
@@ -20,8 +23,9 @@ ALC262
ALC267/268
==========
inv-dmic Inverted internal mic workaround
+ hp-eapd Disable HP EAPD on NID 0x15
-ALC269/270/275/276/28x/29x
+ALC22x/23x/25x/269/27x/28x/29x (and vendor-specific ALC3xxx models)
======
laptop-amic Laptops with analog-mic input
laptop-dmic Laptops with digital-mic input
@@ -29,9 +33,15 @@ ALC269/270/275/276/28x/29x
alc271-dmic Enable ALC271X digital mic workaround
inv-dmic Inverted internal mic workaround
headset-mic Indicates a combined headset (headphone+mic) jack
+ headset-mode More comprehensive headset support for ALC269 & co
+ headset-mode-no-hp-mic Headset mode support without headphone mic
lenovo-dock Enables docking station I/O for some Lenovos
+ hp-gpio-led GPIO LED support on HP laptops
dell-headset-multi Headset jack, which can also be used as mic-in
dell-headset-dock Headset jack (without mic-in), and also dock I/O
+ alc283-dac-wcaps Fixups for Chromebook with ALC283
+ alc283-sense-combo Combo jack sensing on ALC283
+ tpt440-dock Pin configs for Lenovo Thinkpad Dock support
ALC66x/67x/892
==============
diff --git a/Documentation/sound/alsa/Jack-Controls.txt b/Documentation/sound/alsa/Jack-Controls.txt
new file mode 100644
index 000000000000..fe1c5e0c8555
--- /dev/null
+++ b/Documentation/sound/alsa/Jack-Controls.txt
@@ -0,0 +1,43 @@
+Why we need Jack kcontrols
+==========================
+
+ALSA uses kcontrols to export audio controls(switch, volume, Mux, ...)
+to user space. This means userspace applications like pulseaudio can
+switch off headphones and switch on speakers when no headphones are
+pluged in.
+
+The old ALSA jack code only created input devices for each registered
+jack. These jack input devices are not readable by userspace devices
+that run as non root.
+
+The new jack code creates embedded jack kcontrols for each jack that
+can be read by any process.
+
+This can be combined with UCM to allow userspace to route audio more
+intelligently based on jack insertion or removal events.
+
+Jack Kcontrol Internals
+=======================
+
+Each jack will have a kcontrol list, so that we can create a kcontrol
+and attach it to the jack, at jack creation stage. We can also add a
+kcontrol to an existing jack, at anytime when required.
+
+Those kcontrols will be freed automatically when the Jack is freed.
+
+How to use jack kcontrols
+=========================
+
+In order to keep compatibility, snd_jack_new() has been modified by
+adding two params :-
+
+ - @initial_kctl: if true, create a kcontrol and add it to the jack
+ list.
+ - @phantom_jack: Don't create a input device for phantom jacks.
+
+HDA jacks can set phantom_jack to true in order to create a phantom
+jack and set initial_kctl to true to create an initial kcontrol with
+the correct id.
+
+ASoC jacks should set initial_kctl as false. The pin name will be
+assigned as the jack kcontrol name.
diff --git a/Documentation/sound/oss/PSS-updates b/Documentation/sound/oss/PSS-updates
index c84dd7597e64..11914a1dc7e7 100644
--- a/Documentation/sound/oss/PSS-updates
+++ b/Documentation/sound/oss/PSS-updates
@@ -41,7 +41,7 @@ pss_no_sound
This module parameter is a flag that can be used to tell the driver to
just configure non-sound components. 0 configures all components, a non-0
-value will only attept to configure the CDROM and joystick ports. This
+value will only attempt to configure the CDROM and joystick ports. This
parameter can be used by a user who only wished to use the builtin joystick
and/or CDROM port(s) of his PSS sound card. If this driver is loaded with this
parameter and with the parameter below set to true then a user can safely unload
diff --git a/Documentation/sound/oss/README.OSS b/Documentation/sound/oss/README.OSS
index 4be259428a1c..a085ea3611a1 100644
--- a/Documentation/sound/oss/README.OSS
+++ b/Documentation/sound/oss/README.OSS
@@ -1346,7 +1346,7 @@ implement nice real-time signal processing audio effect software and
network telephones. The ACI mixer has to be switched into the "solo"
mode for duplex operation in order to avoid feedback caused by the
mixer (input hears output signal). You can de-/activate this mode
-through toggleing the record button for the wave controller with an
+through toggling the record button for the wave controller with an
OSS-mixer.
The PCM20 contains a radio tuner, which is also controlled by
diff --git a/Documentation/sound/oss/btaudio b/Documentation/sound/oss/btaudio
index 1a693e69d44b..effdb9a3f898 100644
--- a/Documentation/sound/oss/btaudio
+++ b/Documentation/sound/oss/btaudio
@@ -29,7 +29,7 @@ Driver Status
Still somewhat experimental. The driver should work stable, i.e. it
should'nt crash your box. It might not work as expected, have bugs,
-not being fully OSS API compilant, ...
+not being fully OSS API compliant, ...
Latest versions are available from http://bytesex.org/bttv/, the
driver is in the bttv tarball. Kernel patches might be available too,
diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
index 58d0ac4df946..3049a612291b 100644
--- a/Documentation/stable_kernel_rules.txt
+++ b/Documentation/stable_kernel_rules.txt
@@ -59,11 +59,20 @@ For all other submissions, choose one of the following procedures:
changelog of your submission, as well as the kernel version you wish
it to be applied to.
-Option 1 is probably the easiest and most common. Options 2 and 3 are more
-useful if the patch isn't deemed worthy at the time it is applied to a public
-git tree (for instance, because it deserves more regression testing first).
-Option 3 is especially useful if the patch needs some special handling to apply
-to an older kernel (e.g., if API's have changed in the meantime).
+Option 1 is *strongly* preferred, is the easiest and most common. Options 2 and
+3 are more useful if the patch isn't deemed worthy at the time it is applied to
+a public git tree (for instance, because it deserves more regression testing
+first). Option 3 is especially useful if the patch needs some special handling
+to apply to an older kernel (e.g., if API's have changed in the meantime).
+
+Note that for Option 3, if the patch deviates from the original upstream patch
+(for example because it had to be backported) this must be very clearly
+documented and justified in the patch description.
+
+The upstream commit ID must be specified with a separate line above the commit
+text, like this:
+
+ commit <sha1> upstream.
Additionally, some patches submitted via Option 1 may have additional patch
prerequisites which can be cherry-picked. This can be specified in the following
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index c831001c45f1..6fccb69c03e7 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -197,8 +197,8 @@ core_pattern is used to specify a core dumpfile pattern name.
%P global pid (init PID namespace)
%i tid
%I global tid (init PID namespace)
- %u uid
- %g gid
+ %u uid (in initial user namespace)
+ %g gid (in initial user namespace)
%d dump mode, matches PR_SET_DUMPABLE and
/proc/sys/fs/suid_dumpable
%s signal number
@@ -923,6 +923,27 @@ and nmi_watchdog.
==============================================================
+watchdog_cpumask:
+
+This value can be used to control on which cpus the watchdog may run.
+The default cpumask is all possible cores, but if NO_HZ_FULL is
+enabled in the kernel config, and cores are specified with the
+nohz_full= boot argument, those cores are excluded by default.
+Offline cores can be included in this mask, and if the core is later
+brought online, the watchdog will be started based on the mask value.
+
+Typically this value would only be touched in the nohz_full case
+to re-enable cores that by default were not running the watchdog,
+if a kernel lockup was suspected on those cores.
+
+The argument value is the standard cpulist format for cpumasks,
+so for example to enable the watchdog on cores 0, 2, 3, and 4 you
+might say:
+
+ echo 0,2-4 > /proc/sys/kernel/watchdog_cpumask
+
+==============================================================
+
watchdog_thresh:
This value can be used to control the frequency of hrtimer and NMI
diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py
index 2ba71cea0172..6085e1f19c9d 100755
--- a/Documentation/target/tcm_mod_builder.py
+++ b/Documentation/target/tcm_mod_builder.py
@@ -503,11 +503,8 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
buf += "#include <linux/string.h>\n"
buf += "#include <linux/ctype.h>\n"
buf += "#include <asm/unaligned.h>\n"
- buf += "#include <scsi/scsi.h>\n"
- buf += "#include <scsi/scsi_host.h>\n"
- buf += "#include <scsi/scsi_device.h>\n"
- buf += "#include <scsi/scsi_cmnd.h>\n"
- buf += "#include <scsi/libfc.h>\n\n"
+ buf += "#include <scsi/scsi_common.h>\n"
+ buf += "#include <scsi/scsi_proto.h>\n"
buf += "#include <target/target_core_base.h>\n"
buf += "#include <target/target_core_fabric.h>\n"
buf += "#include <target/target_core_configfs.h>\n\n"
diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
index 753e47cc2e20..71653584cd03 100644
--- a/Documentation/thermal/cpu-cooling-api.txt
+++ b/Documentation/thermal/cpu-cooling-api.txt
@@ -36,8 +36,162 @@ the user. The registration APIs returns the cooling device pointer.
np: pointer to the cooling device device tree node
clip_cpus: cpumask of cpus where the frequency constraints will happen.
-1.1.3 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+1.1.3 struct thermal_cooling_device *cpufreq_power_cooling_register(
+ const struct cpumask *clip_cpus, u32 capacitance,
+ get_static_t plat_static_func)
+
+Similar to cpufreq_cooling_register, this function registers a cpufreq
+cooling device. Using this function, the cooling device will
+implement the power extensions by using a simple cpu power model. The
+cpus must have registered their OPPs using the OPP library.
+
+The additional parameters are needed for the power model (See 2. Power
+models). "capacitance" is the dynamic power coefficient (See 2.1
+Dynamic power). "plat_static_func" is a function to calculate the
+static power consumed by these cpus (See 2.2 Static power).
+
+1.1.4 struct thermal_cooling_device *of_cpufreq_power_cooling_register(
+ struct device_node *np, const struct cpumask *clip_cpus, u32 capacitance,
+ get_static_t plat_static_func)
+
+Similar to cpufreq_power_cooling_register, this function register a
+cpufreq cooling device with power extensions using the device tree
+information supplied by the np parameter.
+
+1.1.5 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
This interface function unregisters the "thermal-cpufreq-%x" cooling device.
cdev: Cooling device pointer which has to be unregistered.
+
+2. Power models
+
+The power API registration functions provide a simple power model for
+CPUs. The current power is calculated as dynamic + (optionally)
+static power. This power model requires that the operating-points of
+the CPUs are registered using the kernel's opp library and the
+`cpufreq_frequency_table` is assigned to the `struct device` of the
+cpu. If you are using CONFIG_CPUFREQ_DT then the
+`cpufreq_frequency_table` should already be assigned to the cpu
+device.
+
+The `plat_static_func` parameter of `cpufreq_power_cooling_register()`
+and `of_cpufreq_power_cooling_register()` is optional. If you don't
+provide it, only dynamic power will be considered.
+
+2.1 Dynamic power
+
+The dynamic power consumption of a processor depends on many factors.
+For a given processor implementation the primary factors are:
+
+- The time the processor spends running, consuming dynamic power, as
+ compared to the time in idle states where dynamic consumption is
+ negligible. Herein we refer to this as 'utilisation'.
+- The voltage and frequency levels as a result of DVFS. The DVFS
+ level is a dominant factor governing power consumption.
+- In running time the 'execution' behaviour (instruction types, memory
+ access patterns and so forth) causes, in most cases, a second order
+ variation. In pathological cases this variation can be significant,
+ but typically it is of a much lesser impact than the factors above.
+
+A high level dynamic power consumption model may then be represented as:
+
+Pdyn = f(run) * Voltage^2 * Frequency * Utilisation
+
+f(run) here represents the described execution behaviour and its
+result has a units of Watts/Hz/Volt^2 (this often expressed in
+mW/MHz/uVolt^2)
+
+The detailed behaviour for f(run) could be modelled on-line. However,
+in practice, such an on-line model has dependencies on a number of
+implementation specific processor support and characterisation
+factors. Therefore, in initial implementation that contribution is
+represented as a constant coefficient. This is a simplification
+consistent with the relative contribution to overall power variation.
+
+In this simplified representation our model becomes:
+
+Pdyn = Capacitance * Voltage^2 * Frequency * Utilisation
+
+Where `capacitance` is a constant that represents an indicative
+running time dynamic power coefficient in fundamental units of
+mW/MHz/uVolt^2. Typical values for mobile CPUs might lie in range
+from 100 to 500. For reference, the approximate values for the SoC in
+ARM's Juno Development Platform are 530 for the Cortex-A57 cluster and
+140 for the Cortex-A53 cluster.
+
+
+2.2 Static power
+
+Static leakage power consumption depends on a number of factors. For a
+given circuit implementation the primary factors are:
+
+- Time the circuit spends in each 'power state'
+- Temperature
+- Operating voltage
+- Process grade
+
+The time the circuit spends in each 'power state' for a given
+evaluation period at first order means OFF or ON. However,
+'retention' states can also be supported that reduce power during
+inactive periods without loss of context.
+
+Note: The visibility of state entries to the OS can vary, according to
+platform specifics, and this can then impact the accuracy of a model
+based on OS state information alone. It might be possible in some
+cases to extract more accurate information from system resources.
+
+The temperature, operating voltage and process 'grade' (slow to fast)
+of the circuit are all significant factors in static leakage power
+consumption. All of these have complex relationships to static power.
+
+Circuit implementation specific factors include the chosen silicon
+process as well as the type, number and size of transistors in both
+the logic gates and any RAM elements included.
+
+The static power consumption modelling must take into account the
+power managed regions that are implemented. Taking the example of an
+ARM processor cluster, the modelling would take into account whether
+each CPU can be powered OFF separately or if only a single power
+region is implemented for the complete cluster.
+
+In one view, there are others, a static power consumption model can
+then start from a set of reference values for each power managed
+region (e.g. CPU, Cluster/L2) in each state (e.g. ON, OFF) at an
+arbitrary process grade, voltage and temperature point. These values
+are then scaled for all of the following: the time in each state, the
+process grade, the current temperature and the operating voltage.
+However, since both implementation specific and complex relationships
+dominate the estimate, the appropriate interface to the model from the
+cpu cooling device is to provide a function callback that calculates
+the static power in this platform. When registering the cpu cooling
+device pass a function pointer that follows the `get_static_t`
+prototype:
+
+ int plat_get_static(cpumask_t *cpumask, int interval,
+ unsigned long voltage, u32 &power);
+
+`cpumask` is the cpumask of the cpus involved in the calculation.
+`voltage` is the voltage at which they are operating. The function
+should calculate the average static power for the last `interval`
+milliseconds. It returns 0 on success, -E* on error. If it
+succeeds, it should store the static power in `power`. Reading the
+temperature of the cpus described by `cpumask` is left for
+plat_get_static() to do as the platform knows best which thermal
+sensor is closest to the cpu.
+
+If `plat_static_func` is NULL, static power is considered to be
+negligible for this platform and only dynamic power is considered.
+
+The platform specific callback can then use any combination of tables
+and/or equations to permute the estimated value. Process grade
+information is not passed to the model since access to such data, from
+on-chip measurement capability or manufacture time data, is platform
+specific.
+
+Note: the significance of static power for CPUs in comparison to
+dynamic power is highly dependent on implementation. Given the
+potential complexity in implementation, the importance and accuracy of
+its inclusion when using cpu cooling devices should be assessed on a
+case by case basis.
+
diff --git a/Documentation/thermal/power_allocator.txt b/Documentation/thermal/power_allocator.txt
new file mode 100644
index 000000000000..c3797b529991
--- /dev/null
+++ b/Documentation/thermal/power_allocator.txt
@@ -0,0 +1,247 @@
+Power allocator governor tunables
+=================================
+
+Trip points
+-----------
+
+The governor requires the following two passive trip points:
+
+1. "switch on" trip point: temperature above which the governor
+ control loop starts operating. This is the first passive trip
+ point of the thermal zone.
+
+2. "desired temperature" trip point: it should be higher than the
+ "switch on" trip point. This the target temperature the governor
+ is controlling for. This is the last passive trip point of the
+ thermal zone.
+
+PID Controller
+--------------
+
+The power allocator governor implements a
+Proportional-Integral-Derivative controller (PID controller) with
+temperature as the control input and power as the controlled output:
+
+ P_max = k_p * e + k_i * err_integral + k_d * diff_err + sustainable_power
+
+where
+ e = desired_temperature - current_temperature
+ err_integral is the sum of previous errors
+ diff_err = e - previous_error
+
+It is similar to the one depicted below:
+
+ k_d
+ |
+current_temp |
+ | v
+ | +----------+ +---+
+ | +----->| diff_err |-->| X |------+
+ | | +----------+ +---+ |
+ | | | tdp actor
+ | | k_i | | get_requested_power()
+ | | | | | | |
+ | | | | | | | ...
+ v | v v v v v
+ +---+ | +-------+ +---+ +---+ +---+ +----------+
+ | S |-------+----->| sum e |----->| X |--->| S |-->| S |-->|power |
+ +---+ | +-------+ +---+ +---+ +---+ |allocation|
+ ^ | ^ +----------+
+ | | | | |
+ | | +---+ | | |
+ | +------->| X |-------------------+ v v
+ | +---+ granted performance
+desired_temperature ^
+ |
+ |
+ k_po/k_pu
+
+Sustainable power
+-----------------
+
+An estimate of the sustainable dissipatable power (in mW) should be
+provided while registering the thermal zone. This estimates the
+sustained power that can be dissipated at the desired control
+temperature. This is the maximum sustained power for allocation at
+the desired maximum temperature. The actual sustained power can vary
+for a number of reasons. The closed loop controller will take care of
+variations such as environmental conditions, and some factors related
+to the speed-grade of the silicon. `sustainable_power` is therefore
+simply an estimate, and may be tuned to affect the aggressiveness of
+the thermal ramp. For reference, the sustainable power of a 4" phone
+is typically 2000mW, while on a 10" tablet is around 4500mW (may vary
+depending on screen size).
+
+If you are using device tree, do add it as a property of the
+thermal-zone. For example:
+
+ thermal-zones {
+ soc_thermal {
+ polling-delay = <1000>;
+ polling-delay-passive = <100>;
+ sustainable-power = <2500>;
+ ...
+
+Instead, if the thermal zone is registered from the platform code, pass a
+`thermal_zone_params` that has a `sustainable_power`. If no
+`thermal_zone_params` were being passed, then something like below
+will suffice:
+
+ static const struct thermal_zone_params tz_params = {
+ .sustainable_power = 3500,
+ };
+
+and then pass `tz_params` as the 5th parameter to
+`thermal_zone_device_register()`
+
+k_po and k_pu
+-------------
+
+The implementation of the PID controller in the power allocator
+thermal governor allows the configuration of two proportional term
+constants: `k_po` and `k_pu`. `k_po` is the proportional term
+constant during temperature overshoot periods (current temperature is
+above "desired temperature" trip point). Conversely, `k_pu` is the
+proportional term constant during temperature undershoot periods
+(current temperature below "desired temperature" trip point).
+
+These controls are intended as the primary mechanism for configuring
+the permitted thermal "ramp" of the system. For instance, a lower
+`k_pu` value will provide a slower ramp, at the cost of capping
+available capacity at a low temperature. On the other hand, a high
+value of `k_pu` will result in the governor granting very high power
+whilst temperature is low, and may lead to temperature overshooting.
+
+The default value for `k_pu` is:
+
+ 2 * sustainable_power / (desired_temperature - switch_on_temp)
+
+This means that at `switch_on_temp` the output of the controller's
+proportional term will be 2 * `sustainable_power`. The default value
+for `k_po` is:
+
+ sustainable_power / (desired_temperature - switch_on_temp)
+
+Focusing on the proportional and feed forward values of the PID
+controller equation we have:
+
+ P_max = k_p * e + sustainable_power
+
+The proportional term is proportional to the difference between the
+desired temperature and the current one. When the current temperature
+is the desired one, then the proportional component is zero and
+`P_max` = `sustainable_power`. That is, the system should operate in
+thermal equilibrium under constant load. `sustainable_power` is only
+an estimate, which is the reason for closed-loop control such as this.
+
+Expanding `k_pu` we get:
+ P_max = 2 * sustainable_power * (T_set - T) / (T_set - T_on) +
+ sustainable_power
+
+where
+ T_set is the desired temperature
+ T is the current temperature
+ T_on is the switch on temperature
+
+When the current temperature is the switch_on temperature, the above
+formula becomes:
+
+ P_max = 2 * sustainable_power * (T_set - T_on) / (T_set - T_on) +
+ sustainable_power = 2 * sustainable_power + sustainable_power =
+ 3 * sustainable_power
+
+Therefore, the proportional term alone linearly decreases power from
+3 * `sustainable_power` to `sustainable_power` as the temperature
+rises from the switch on temperature to the desired temperature.
+
+k_i and integral_cutoff
+-----------------------
+
+`k_i` configures the PID loop's integral term constant. This term
+allows the PID controller to compensate for long term drift and for
+the quantized nature of the output control: cooling devices can't set
+the exact power that the governor requests. When the temperature
+error is below `integral_cutoff`, errors are accumulated in the
+integral term. This term is then multiplied by `k_i` and the result
+added to the output of the controller. Typically `k_i` is set low (1
+or 2) and `integral_cutoff` is 0.
+
+k_d
+---
+
+`k_d` configures the PID loop's derivative term constant. It's
+recommended to leave it as the default: 0.
+
+Cooling device power API
+========================
+
+Cooling devices controlled by this governor must supply the additional
+"power" API in their `cooling_device_ops`. It consists on three ops:
+
+1. int get_requested_power(struct thermal_cooling_device *cdev,
+ struct thermal_zone_device *tz, u32 *power);
+@cdev: The `struct thermal_cooling_device` pointer
+@tz: thermal zone in which we are currently operating
+@power: pointer in which to store the calculated power
+
+`get_requested_power()` calculates the power requested by the device
+in milliwatts and stores it in @power . It should return 0 on
+success, -E* on failure. This is currently used by the power
+allocator governor to calculate how much power to give to each cooling
+device.
+
+2. int state2power(struct thermal_cooling_device *cdev, struct
+ thermal_zone_device *tz, unsigned long state, u32 *power);
+@cdev: The `struct thermal_cooling_device` pointer
+@tz: thermal zone in which we are currently operating
+@state: A cooling device state
+@power: pointer in which to store the equivalent power
+
+Convert cooling device state @state into power consumption in
+milliwatts and store it in @power. It should return 0 on success, -E*
+on failure. This is currently used by thermal core to calculate the
+maximum power that an actor can consume.
+
+3. int power2state(struct thermal_cooling_device *cdev, u32 power,
+ unsigned long *state);
+@cdev: The `struct thermal_cooling_device` pointer
+@power: power in milliwatts
+@state: pointer in which to store the resulting state
+
+Calculate a cooling device state that would make the device consume at
+most @power mW and store it in @state. It should return 0 on success,
+-E* on failure. This is currently used by the thermal core to convert
+a given power set by the power allocator governor to a state that the
+cooling device can set. It is a function because this conversion may
+depend on external factors that may change so this function should the
+best conversion given "current circumstances".
+
+Cooling device weights
+----------------------
+
+Weights are a mechanism to bias the allocation among cooling
+devices. They express the relative power efficiency of different
+cooling devices. Higher weight can be used to express higher power
+efficiency. Weighting is relative such that if each cooling device
+has a weight of one they are considered equal. This is particularly
+useful in heterogeneous systems where two cooling devices may perform
+the same kind of compute, but with different efficiency. For example,
+a system with two different types of processors.
+
+If the thermal zone is registered using
+`thermal_zone_device_register()` (i.e., platform code), then weights
+are passed as part of the thermal zone's `thermal_bind_parameters`.
+If the platform is registered using device tree, then they are passed
+as the `contribution` property of each map in the `cooling-maps` node.
+
+Limitations of the power allocator governor
+===========================================
+
+The power allocator governor's PID controller works best if there is a
+periodic tick. If you have a driver that calls
+`thermal_zone_device_update()` (or anything that ends up calling the
+governor's `throttle()` function) repetitively, the governor response
+won't be very good. Note that this is not particular to this
+governor, step-wise will also misbehave if you call its throttle()
+faster than the normal thermal framework tick (due to interrupts for
+example) as it will overreact.
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index 87519cb379ee..c1f6864a8c5d 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -95,7 +95,7 @@ temperature) and throttle appropriate devices.
1.3 interface for binding a thermal zone device with a thermal cooling device
1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
int trip, struct thermal_cooling_device *cdev,
- unsigned long upper, unsigned long lower);
+ unsigned long upper, unsigned long lower, unsigned int weight);
This interface function bind a thermal cooling device to the certain trip
point of a thermal zone device.
@@ -110,6 +110,8 @@ temperature) and throttle appropriate devices.
lower:the Minimum cooling state can be used for this trip point.
THERMAL_NO_LIMIT means no lower limit,
and the cooling device can be in cooling state 0.
+ weight: the influence of this cooling device in this thermal
+ zone. See 1.4.1 below for more information.
1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
int trip, struct thermal_cooling_device *cdev);
@@ -127,9 +129,15 @@ temperature) and throttle appropriate devices.
This structure defines the following parameters that are used to bind
a zone with a cooling device for a particular trip point.
.cdev: The cooling device pointer
- .weight: The 'influence' of a particular cooling device on this zone.
- This is on a percentage scale. The sum of all these weights
- (for a particular zone) cannot exceed 100.
+ .weight: The 'influence' of a particular cooling device on this
+ zone. This is relative to the rest of the cooling
+ devices. For example, if all cooling devices have a
+ weight of 1, then they all contribute the same. You can
+ use percentages if you want, but it's not mandatory. A
+ weight of 0 means that this cooling device doesn't
+ contribute to the cooling of this zone unless all cooling
+ devices have a weight of 0. If all weights are 0, then
+ they all contribute the same.
.trip_mask:This is a bit mask that gives the binding relation between
this thermal zone and cdev, for a particular trip point.
If nth bit is set, then the cdev and thermal zone are bound
@@ -176,6 +184,14 @@ Thermal zone device sys I/F, created once it's registered:
|---trip_point_[0-*]_type: Trip point type
|---trip_point_[0-*]_hyst: Hysteresis value for this trip point
|---emul_temp: Emulated temperature set node
+ |---sustainable_power: Sustainable dissipatable power
+ |---k_po: Proportional term during temperature overshoot
+ |---k_pu: Proportional term during temperature undershoot
+ |---k_i: PID's integral term in the power allocator gov
+ |---k_d: PID's derivative term in the power allocator
+ |---integral_cutoff: Offset above which errors are accumulated
+ |---slope: Slope constant applied as linear extrapolation
+ |---offset: Offset constant applied as linear extrapolation
Thermal cooling device sys I/F, created once it's registered:
/sys/class/thermal/cooling_device[0-*]:
@@ -192,6 +208,8 @@ thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device.
/sys/class/thermal/thermal_zone[0-*]:
|---cdev[0-*]: [0-*]th cooling device in current thermal zone
|---cdev[0-*]_trip_point: Trip point that cdev[0-*] is associated with
+ |---cdev[0-*]_weight: Influence of the cooling device in
+ this thermal zone
Besides the thermal zone device sysfs I/F and cooling device sysfs I/F,
the generic thermal driver also creates a hwmon sysfs I/F for each _type_
@@ -265,6 +283,14 @@ cdev[0-*]_trip_point
point.
RO, Optional
+cdev[0-*]_weight
+ The influence of cdev[0-*] in this thermal zone. This value
+ is relative to the rest of cooling devices in the thermal
+ zone. For example, if a cooling device has a weight double
+ than that of other, it's twice as effective in cooling the
+ thermal zone.
+ RW, Optional
+
passive
Attribute is only present for zones in which the passive cooling
policy is not supported by native thermal driver. Default is zero
@@ -289,6 +315,66 @@ emul_temp
because userland can easily disable the thermal policy by simply
flooding this sysfs node with low temperature values.
+sustainable_power
+ An estimate of the sustained power that can be dissipated by
+ the thermal zone. Used by the power allocator governor. For
+ more information see Documentation/thermal/power_allocator.txt
+ Unit: milliwatts
+ RW, Optional
+
+k_po
+ The proportional term of the power allocator governor's PID
+ controller during temperature overshoot. Temperature overshoot
+ is when the current temperature is above the "desired
+ temperature" trip point. For more information see
+ Documentation/thermal/power_allocator.txt
+ RW, Optional
+
+k_pu
+ The proportional term of the power allocator governor's PID
+ controller during temperature undershoot. Temperature undershoot
+ is when the current temperature is below the "desired
+ temperature" trip point. For more information see
+ Documentation/thermal/power_allocator.txt
+ RW, Optional
+
+k_i
+ The integral term of the power allocator governor's PID
+ controller. This term allows the PID controller to compensate
+ for long term drift. For more information see
+ Documentation/thermal/power_allocator.txt
+ RW, Optional
+
+k_d
+ The derivative term of the power allocator governor's PID
+ controller. For more information see
+ Documentation/thermal/power_allocator.txt
+ RW, Optional
+
+integral_cutoff
+ Temperature offset from the desired temperature trip point
+ above which the integral term of the power allocator
+ governor's PID controller starts accumulating errors. For
+ example, if integral_cutoff is 0, then the integral term only
+ accumulates error when temperature is above the desired
+ temperature trip point. For more information see
+ Documentation/thermal/power_allocator.txt
+ RW, Optional
+
+slope
+ The slope constant used in a linear extrapolation model
+ to determine a hotspot temperature based off the sensor's
+ raw readings. It is up to the device driver to determine
+ the usage of these values.
+ RW, Optional
+
+offset
+ The offset constant used in a linear extrapolation model
+ to determine a hotspot temperature based off the sensor's
+ raw readings. It is up to the device driver to determine
+ the usage of these values.
+ RW, Optional
+
*****************************
* Cooling device attributes *
*****************************
@@ -318,7 +404,8 @@ passive, active. If an ACPI thermal zone supports critical, passive,
active[0] and active[1] at the same time, it may register itself as a
thermal_zone_device (thermal_zone1) with 4 trip points in all.
It has one processor and one fan, which are both registered as
-thermal_cooling_device.
+thermal_cooling_device. Both are considered to have the same
+effectiveness in cooling the thermal zone.
If the processor is listed in _PSL method, and the fan is listed in _AL0
method, the sys I/F structure will be built like this:
@@ -340,8 +427,10 @@ method, the sys I/F structure will be built like this:
|---trip_point_3_type: active1
|---cdev0: --->/sys/class/thermal/cooling_device0
|---cdev0_trip_point: 1 /* cdev0 can be used for passive */
+ |---cdev0_weight: 1024
|---cdev1: --->/sys/class/thermal/cooling_device3
|---cdev1_trip_point: 2 /* cdev1 can be used for active[0]*/
+ |---cdev1_weight: 1024
|cooling_device0:
|---type: Processor
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt
index 572ca923631a..7ddb1e319f84 100644
--- a/Documentation/trace/ftrace.txt
+++ b/Documentation/trace/ftrace.txt
@@ -108,8 +108,8 @@ of ftrace. Here is a list of some of the key files:
data is read from this file, it is consumed, and
will not be read again with a sequential read. The
"trace" file is static, and if the tracer is not
- adding more data,they will display the same
- information every time they are read.
+ adding more data, it will display the same
+ information every time it is read.
trace_options:
diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt
index f45b2bf4b41d..592678009c15 100644
--- a/Documentation/usb/gadget-testing.txt
+++ b/Documentation/usb/gadget-testing.txt
@@ -526,8 +526,6 @@ Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
-By default there can be only 1 RNDIS interface in the system.
-
Testing the RNDIS function
--------------------------
@@ -629,7 +627,7 @@ Function-specific configfs interface
The function name to use when creating the function directory is "uac2".
The uac2 function provides these attributes in its function directory:
- chmask - capture channel mask
+ c_chmask - capture channel mask
c_srate - capture sampling rate
c_ssize - capture sample size (bytes)
p_chmask - playback channel mask
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
index 947fa62bccf2..349f3104fa4f 100644
--- a/Documentation/usb/usb-serial.txt
+++ b/Documentation/usb/usb-serial.txt
@@ -465,12 +465,14 @@ Generic Serial driver
device, and does not support any kind of device flow control. All that
is required of your device is that it has at least one bulk in endpoint,
or one bulk out endpoint.
-
- To enable the generic driver to recognize your device, build the driver
- as a module and load it by the following invocation:
+
+ To enable the generic driver to recognize your device, provide
+ echo <vid> <pid> >/sys/bus/usb-serial/drivers/generic/new_id
+ where the <vid> and <pid> is replaced with the hex representation of your
+ device's vendor id and product id.
+ If the driver is compiled as a module you can also provide one id when
+ loading the module
insmod usbserial vendor=0x#### product=0x####
- where the #### is replaced with the hex representation of your device's
- vendor id and product id.
This driver has been successfully used to connect to the NetChip USB
development board, providing a way to develop USB firmware without
diff --git a/Documentation/vDSO/Makefile b/Documentation/vDSO/Makefile
index ee075c3d2124..b12e98770e1f 100644
--- a/Documentation/vDSO/Makefile
+++ b/Documentation/vDSO/Makefile
@@ -1,3 +1,4 @@
+ifndef CROSS_COMPILE
# vdso_test won't build for glibc < 2.16, so disable it
# hostprogs-y := vdso_test
hostprogs-$(CONFIG_X86) := vdso_standalone_test_x86
@@ -13,3 +14,4 @@ HOSTLOADLIBES_vdso_standalone_test_x86 := -nostdlib
ifeq ($(CONFIG_X86_32),y)
HOSTLOADLIBES_vdso_standalone_test_x86 += -lgcc_s
endif
+endif
diff --git a/Documentation/vfio.txt b/Documentation/vfio.txt
index 96978eced341..1dd3fddfd3a1 100644
--- a/Documentation/vfio.txt
+++ b/Documentation/vfio.txt
@@ -289,10 +289,12 @@ PPC64 sPAPR implementation note
This implementation has some specifics:
-1) Only one IOMMU group per container is supported as an IOMMU group
-represents the minimal entity which isolation can be guaranteed for and
-groups are allocated statically, one per a Partitionable Endpoint (PE)
+1) On older systems (POWER7 with P5IOC2/IODA1) only one IOMMU group per
+container is supported as an IOMMU table is allocated at the boot time,
+one table per a IOMMU group which is a Partitionable Endpoint (PE)
(PE is often a PCI domain but not always).
+Newer systems (POWER8 with IODA2) have improved hardware design which allows
+to remove this limitation and have multiple IOMMU groups per a VFIO container.
2) The hardware supports so called DMA windows - the PCI address range
within which DMA transfer is allowed, any attempt to access address space
@@ -385,6 +387,18 @@ The code flow from the example above should be slightly changed:
....
+ /* Inject EEH error, which is expected to be caused by 32-bits
+ * config load.
+ */
+ pe_op.op = VFIO_EEH_PE_INJECT_ERR;
+ pe_op.err.type = EEH_ERR_TYPE_32;
+ pe_op.err.func = EEH_ERR_FUNC_LD_CFG_ADDR;
+ pe_op.err.addr = 0ul;
+ pe_op.err.mask = 0ul;
+ ioctl(container, VFIO_EEH_PE_OP, &pe_op);
+
+ ....
+
/* When 0xFF's returned from reading PCI config space or IO BARs
* of the PCI device. Check the PE's state to see if that has been
* frozen.
@@ -427,6 +441,48 @@ The code flow from the example above should be slightly changed:
....
+5) There is v2 of SPAPR TCE IOMMU. It deprecates VFIO_IOMMU_ENABLE/
+VFIO_IOMMU_DISABLE and implements 2 new ioctls:
+VFIO_IOMMU_SPAPR_REGISTER_MEMORY and VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY
+(which are unsupported in v1 IOMMU).
+
+PPC64 paravirtualized guests generate a lot of map/unmap requests,
+and the handling of those includes pinning/unpinning pages and updating
+mm::locked_vm counter to make sure we do not exceed the rlimit.
+The v2 IOMMU splits accounting and pinning into separate operations:
+
+- VFIO_IOMMU_SPAPR_REGISTER_MEMORY/VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY ioctls
+receive a user space address and size of the block to be pinned.
+Bisecting is not supported and VFIO_IOMMU_UNREGISTER_MEMORY is expected to
+be called with the exact address and size used for registering
+the memory block. The userspace is not expected to call these often.
+The ranges are stored in a linked list in a VFIO container.
+
+- VFIO_IOMMU_MAP_DMA/VFIO_IOMMU_UNMAP_DMA ioctls only update the actual
+IOMMU table and do not do pinning; instead these check that the userspace
+address is from pre-registered range.
+
+This separation helps in optimizing DMA for guests.
+
+6) sPAPR specification allows guests to have an additional DMA window(s) on
+a PCI bus with a variable page size. Two ioctls have been added to support
+this: VFIO_IOMMU_SPAPR_TCE_CREATE and VFIO_IOMMU_SPAPR_TCE_REMOVE.
+The platform has to support the functionality or error will be returned to
+the userspace. The existing hardware supports up to 2 DMA windows, one is
+2GB long, uses 4K pages and called "default 32bit window"; the other can
+be as big as entire RAM, use different page size, it is optional - guests
+create those in run-time if the guest driver supports 64bit DMA.
+
+VFIO_IOMMU_SPAPR_TCE_CREATE receives a page shift, a DMA window size and
+a number of TCE table levels (if a TCE table is going to be big enough and
+the kernel may not be able to allocate enough of physically contiguous memory).
+It creates a new window in the available slot and returns the bus address where
+the new window starts. Due to hardware limitation, the user space cannot choose
+the location of DMA windows.
+
+VFIO_IOMMU_SPAPR_TCE_REMOVE receives the bus start address of the window
+and removes it.
+
-------------------------------------------------------------------------------
[1] VFIO was originally an acronym for "Virtual Function I/O" in its
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index 4c84ec853265..44a4cfbfdc40 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -36,7 +36,7 @@
35 -> TeVii S471 [d471:9022]
36 -> Hauppauge WinTV-HVR1255 [0070:2259]
37 -> Prof Revolution DVB-S2 8000 [8000:3034]
- 38 -> Hauppauge WinTV-HVR4400 [0070:c108,0070:c138,0070:c12a,0070:c1f8]
+ 38 -> Hauppauge WinTV-HVR4400/HVR5500 [0070:c108,0070:c138,0070:c1f8]
39 -> AVerTV Hybrid Express Slim HC81R [1461:d939]
40 -> TurboSight TBS 6981 [6981:8888]
41 -> TurboSight TBS 6980 [6980:8888]
@@ -45,3 +45,10 @@
44 -> DViCO FusionHDTV DVB-T Dual Express2 [18ac:db98]
45 -> DVBSky T9580 [4254:9580]
46 -> DVBSky T980C [4254:980c]
+ 47 -> DVBSky S950C [4254:950c]
+ 48 -> Technotrend TT-budget CT2-4500 CI [13c2:3013]
+ 49 -> DVBSky S950 [4254:0950]
+ 50 -> DVBSky S952 [4254:0952]
+ 51 -> DVBSky T982 [4254:0982]
+ 52 -> Hauppauge WinTV-HVR5525 [0070:f038]
+ 53 -> Hauppauge WinTV Starburst [0070:c12a]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index 3700edb81db2..9e57ce43c4f4 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -94,3 +94,5 @@
93 -> KWorld USB ATSC TV Stick UB435-Q V3 (em2874) [1b80:e34c]
94 -> PCTV tripleStick (292e) (em28178)
95 -> Leadtek VC100 (em2861) [0413:6f07]
+ 96 -> Terratec Cinergy T2 Stick HD (em28178)
+ 97 -> Elgato EyeTV Hybrid 2008 INT (em2884) [0fd9:0018]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index a93d86455233..f4b395bdc090 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -192,3 +192,4 @@
191 -> Hawell HW-9004V1
192 -> AverMedia AverTV Satellite Hybrid+FM A706 [1461:2055]
193 -> WIS Voyager or compatible [1905:7007]
+194 -> AverMedia AverTV/505 [1461:a10a]
diff --git a/Documentation/video4linux/CARDLIST.saa7164 b/Documentation/video4linux/CARDLIST.saa7164
index 2205e8d55537..6eb057220474 100644
--- a/Documentation/video4linux/CARDLIST.saa7164
+++ b/Documentation/video4linux/CARDLIST.saa7164
@@ -9,3 +9,6 @@
8 -> Hauppauge WinTV-HVR2250 [0070:88A1]
9 -> Hauppauge WinTV-HVR2200 [0070:8940]
10 -> Hauppauge WinTV-HVR2200 [0070:8953]
+ 11 -> Hauppauge WinTV-HVR2255(proto)
+ 12 -> Hauppauge WinTV-HVR2255 [0070:f111]
+ 13 -> Hauppauge WinTV-HVR2205 [0070:f123,0070:f120]
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 59e619f9bbf5..75d5c18d689a 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -1129,6 +1129,10 @@ available event type is 'class base + 1'.
An example on how the V4L2 events may be used can be found in the OMAP
3 ISP driver (drivers/media/platform/omap3isp).
+A subdev can directly send an event to the v4l2_device notify function with
+V4L2_DEVICE_NOTIFY_EVENT. This allows the bridge to map the subdev that sends
+the event to the video node(s) associated with the subdev that need to be
+informed about such an event.
V4L2 clocks
-----------
diff --git a/Documentation/video4linux/v4l2-pci-skeleton.c b/Documentation/video4linux/v4l2-pci-skeleton.c
index 7bd1b975bfd2..9c80c090e92d 100644
--- a/Documentation/video4linux/v4l2-pci-skeleton.c
+++ b/Documentation/video4linux/v4l2-pci-skeleton.c
@@ -406,9 +406,7 @@ static int skeleton_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index != 0)
return -EINVAL;
- strlcpy(f->description, "4:2:2, packed, YUYV", sizeof(f->description));
f->pixelformat = V4L2_PIX_FMT_YUYV;
- f->flags = 0;
return 0;
}
diff --git a/Documentation/video4linux/vivid.txt b/Documentation/video4linux/vivid.txt
index cd4b5a1ac529..e35d376b7f64 100644
--- a/Documentation/video4linux/vivid.txt
+++ b/Documentation/video4linux/vivid.txt
@@ -631,26 +631,33 @@ Timestamp Source: selects when the timestamp for each buffer is taken.
Colorspace: selects which colorspace should be used when generating the image.
This only applies if the CSC Colorbar test pattern is selected,
- otherwise the test pattern will go through unconverted (except for
- the so-called 'Transfer Function' corrections and the R'G'B' to Y'CbCr
- conversion). This behavior is also what you want, since a 75% Colorbar
+ otherwise the test pattern will go through unconverted.
+ This behavior is also what you want, since a 75% Colorbar
should really have 75% signal intensity and should not be affected
by colorspace conversions.
Changing the colorspace will result in the V4L2_EVENT_SOURCE_CHANGE
to be sent since it emulates a detected colorspace change.
+Transfer Function: selects which colorspace transfer function should be used when
+ generating an image. This only applies if the CSC Colorbar test pattern is
+ selected, otherwise the test pattern will go through unconverted.
+ This behavior is also what you want, since a 75% Colorbar
+ should really have 75% signal intensity and should not be affected
+ by colorspace conversions.
+
+ Changing the transfer function will result in the V4L2_EVENT_SOURCE_CHANGE
+ to be sent since it emulates a detected colorspace change.
+
Y'CbCr Encoding: selects which Y'CbCr encoding should be used when generating
- a Y'CbCr image. This only applies if the CSC Colorbar test pattern is
- selected, and if the format is set to a Y'CbCr format as opposed to an
- RGB format.
+ a Y'CbCr image. This only applies if the format is set to a Y'CbCr format
+ as opposed to an RGB format.
Changing the Y'CbCr encoding will result in the V4L2_EVENT_SOURCE_CHANGE
to be sent since it emulates a detected colorspace change.
Quantization: selects which quantization should be used for the RGB or Y'CbCr
- encoding when generating the test pattern. This only applies if the CSC
- Colorbar test pattern is selected.
+ encoding when generating the test pattern.
Changing the quantization will result in the V4L2_EVENT_SOURCE_CHANGE
to be sent since it emulates a detected colorspace change.
@@ -888,7 +895,7 @@ Section 10.1: Video and Sliced VBI looping
The way to enable video/VBI looping is currently fairly crude. A 'Loop Video'
control is available in the "Vivid" control class of the video
-output and VBI output devices. When checked the video looping will be enabled.
+capture and VBI capture devices. When checked the video looping will be enabled.
Once enabled any video S-Video or HDMI input will show a static test pattern
until the video output has started. At that time the video output will be
looped to the video input provided that:
@@ -985,8 +992,9 @@ to change crop and compose rectangles on the fly.
Section 12: Formats
-------------------
-The driver supports all the regular packed YUYV formats, 16, 24 and 32 RGB
-packed formats and two multiplanar formats (one luma and one chroma plane).
+The driver supports all the regular packed and planar 4:4:4, 4:2:2 and 4:2:0
+YUYV formats, 8, 16, 24 and 32 RGB packed formats and various multiplanar
+formats.
The alpha component can be set through the 'Alpha Component' User control
for those formats that support it. If the 'Apply Alpha To Red Only' control
@@ -1119,11 +1127,9 @@ Just as a reminder and in no particular order:
- Use per-queue locks and/or per-device locks to improve throughput
- Add support to loop from a specific output to a specific input across
vivid instances
-- Add support for VIDIOC_EXPBUF once support for that has been added to vb2
- The SDR radio should use the same 'frequencies' for stations as the normal
radio receiver, and give back noise if the frequency doesn't match up with
a station frequency
-- Improve the sine generation of the SDR radio.
- Make a thread for the RDS generation, that would help in particular for the
"Controls" RDS Rx I/O Mode as the read-only RDS controls could be updated
in real-time.
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 9fa2bf8c3f6f..a7926a90156f 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -254,6 +254,11 @@ since the last call to this ioctl. Bit 0 is the first page in the
memory slot. Ensure the entire structure is cleared to avoid padding
issues.
+If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 specifies
+the address space for which you want to return the dirty bitmap.
+They must be less than the value that KVM_CHECK_EXTENSION returns for
+the KVM_CAP_MULTI_ADDRESS_SPACE capability.
+
4.9 KVM_SET_MEMORY_ALIAS
@@ -820,11 +825,21 @@ struct kvm_vcpu_events {
} nmi;
__u32 sipi_vector;
__u32 flags;
+ struct {
+ __u8 smm;
+ __u8 pending;
+ __u8 smm_inside_nmi;
+ __u8 latched_init;
+ } smi;
};
-KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that
-interrupt.shadow contains a valid state. Otherwise, this field is undefined.
+Only two fields are defined in the flags field:
+
+- KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that
+ interrupt.shadow contains a valid state.
+- KVM_VCPUEVENT_VALID_SMM may be set in the flags field to signal that
+ smi contains a valid state.
4.32 KVM_SET_VCPU_EVENTS
@@ -841,17 +856,20 @@ vcpu.
See KVM_GET_VCPU_EVENTS for the data structure.
Fields that may be modified asynchronously by running VCPUs can be excluded
-from the update. These fields are nmi.pending and sipi_vector. Keep the
-corresponding bits in the flags field cleared to suppress overwriting the
-current in-kernel state. The bits are:
+from the update. These fields are nmi.pending, sipi_vector, smi.smm,
+smi.pending. Keep the corresponding bits in the flags field cleared to
+suppress overwriting the current in-kernel state. The bits are:
KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel
KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector
+KVM_VCPUEVENT_VALID_SMM - transfer the smi sub-struct.
If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in
the flags field to signal that interrupt.shadow contains a valid state and
shall be written into the VCPU.
+KVM_VCPUEVENT_VALID_SMM can only be set if KVM_CAP_X86_SMM is available.
+
4.33 KVM_GET_DEBUGREGS
@@ -911,6 +929,13 @@ slot. When changing an existing slot, it may be moved in the guest
physical memory space, or its flags may be modified. It may not be
resized. Slots may not overlap in guest physical address space.
+If KVM_CAP_MULTI_ADDRESS_SPACE is available, bits 16-31 of "slot"
+specifies the address space which is being modified. They must be
+less than the value that KVM_CHECK_EXTENSION returns for the
+KVM_CAP_MULTI_ADDRESS_SPACE capability. Slots in separate address spaces
+are unrelated; the restriction on overlapping slots only applies within
+each address space.
+
Memory for the region is taken starting at the address denoted by the
field userspace_addr, which must point at user addressable memory for
the entire memory slot size. Any object may back this memory, including
@@ -959,7 +984,8 @@ documentation when it pops into existence).
4.37 KVM_ENABLE_CAP
Capability: KVM_CAP_ENABLE_CAP, KVM_CAP_ENABLE_CAP_VM
-Architectures: ppc, s390
+Architectures: x86 (only KVM_CAP_ENABLE_CAP_VM),
+ mips (only KVM_CAP_ENABLE_CAP), ppc, s390
Type: vcpu ioctl, vm ioctl (with KVM_CAP_ENABLE_CAP_VM)
Parameters: struct kvm_enable_cap (in)
Returns: 0 on success; -1 on error
@@ -1268,7 +1294,7 @@ The flags bitmap is defined as:
/* the host supports the ePAPR idle hcall
#define KVM_PPC_PVINFO_FLAGS_EV_IDLE (1<<0)
-4.48 KVM_ASSIGN_PCI_DEVICE
+4.48 KVM_ASSIGN_PCI_DEVICE (deprecated)
Capability: none
Architectures: x86
@@ -1318,7 +1344,7 @@ Errors:
have their standard meanings.
-4.49 KVM_DEASSIGN_PCI_DEVICE
+4.49 KVM_DEASSIGN_PCI_DEVICE (deprecated)
Capability: none
Architectures: x86
@@ -1337,7 +1363,7 @@ Errors:
Other error conditions may be defined by individual device types or
have their standard meanings.
-4.50 KVM_ASSIGN_DEV_IRQ
+4.50 KVM_ASSIGN_DEV_IRQ (deprecated)
Capability: KVM_CAP_ASSIGN_DEV_IRQ
Architectures: x86
@@ -1377,7 +1403,7 @@ Errors:
have their standard meanings.
-4.51 KVM_DEASSIGN_DEV_IRQ
+4.51 KVM_DEASSIGN_DEV_IRQ (deprecated)
Capability: KVM_CAP_ASSIGN_DEV_IRQ
Architectures: x86
@@ -1451,7 +1477,7 @@ struct kvm_irq_routing_s390_adapter {
};
-4.53 KVM_ASSIGN_SET_MSIX_NR
+4.53 KVM_ASSIGN_SET_MSIX_NR (deprecated)
Capability: none
Architectures: x86
@@ -1473,7 +1499,7 @@ struct kvm_assigned_msix_nr {
#define KVM_MAX_MSIX_PER_DEV 256
-4.54 KVM_ASSIGN_SET_MSIX_ENTRY
+4.54 KVM_ASSIGN_SET_MSIX_ENTRY (deprecated)
Capability: none
Architectures: x86
@@ -1629,7 +1655,7 @@ should skip processing the bitmap and just invalidate everything. It must
be set to the number of set bits in the bitmap.
-4.61 KVM_ASSIGN_SET_INTX_MASK
+4.61 KVM_ASSIGN_SET_INTX_MASK (deprecated)
Capability: KVM_CAP_PCI_2_3
Architectures: x86
@@ -2978,6 +3004,16 @@ len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
which is the maximum number of possibly pending cpu-local interrupts.
+4.90 KVM_SMI
+
+Capability: KVM_CAP_X86_SMM
+Architectures: x86
+Type: vcpu ioctl
+Parameters: none
+Returns: 0 on success, -1 on error
+
+Queues an SMI on the thread's vcpu.
+
5. The kvm_run structure
------------------------
@@ -3013,7 +3049,12 @@ an interrupt can be injected now with KVM_INTERRUPT.
The value of the current interrupt flag. Only valid if in-kernel
local APIC is not used.
- __u8 padding2[2];
+ __u16 flags;
+
+More architecture-specific flags detailing state of the VCPU that may
+affect the device's behavior. The only currently defined flag is
+KVM_RUN_X86_SMM, which is valid on x86 machines and is set if the
+VCPU is in system management mode.
/* in (pre_kvm_run), out (post_kvm_run) */
__u64 cr8;
diff --git a/Documentation/virtual/kvm/mmu.txt b/Documentation/virtual/kvm/mmu.txt
index c59bd9bc41ef..3a4d681c3e98 100644
--- a/Documentation/virtual/kvm/mmu.txt
+++ b/Documentation/virtual/kvm/mmu.txt
@@ -173,6 +173,12 @@ Shadow pages contain the following information:
Contains the value of cr4.smap && !cr0.wp for which the page is valid
(pages for which this is true are different from other pages; see the
treatment of cr0.wp=0 below).
+ role.smm:
+ Is 1 if the page is valid in system management mode. This field
+ determines which of the kvm_memslots array was used to build this
+ shadow page; it is also used to go back from a struct kvm_mmu_page
+ to a memslot, through the kvm_memslots_for_spte_role macro and
+ __gfn_to_memslot.
gfn:
Either the guest page table containing the translations shadowed by this
page, or the base page frame for linear translations. See role.direct.
diff --git a/Documentation/vm/unevictable-lru.txt b/Documentation/vm/unevictable-lru.txt
index 3be0bfc4738d..32ee3a67dba2 100644
--- a/Documentation/vm/unevictable-lru.txt
+++ b/Documentation/vm/unevictable-lru.txt
@@ -467,7 +467,13 @@ mmap(MAP_LOCKED) SYSTEM CALL HANDLING
In addition the mlock()/mlockall() system calls, an application can request
that a region of memory be mlocked supplying the MAP_LOCKED flag to the mmap()
-call. Furthermore, any mmap() call or brk() call that expands the heap by a
+call. There is one important and subtle difference here, though. mmap() + mlock()
+will fail if the range cannot be faulted in (e.g. because mm_populate fails)
+and returns with ENOMEM while mmap(MAP_LOCKED) will not fail. The mmaped
+area will still have properties of the locked area - aka. pages will not get
+swapped out - but major page faults to fault memory in might still happen.
+
+Furthermore, any mmap() call or brk() call that expands the heap by a
task that has previously called mlockall() with the MCL_FUTURE flag will result
in the newly mapped memory being mlocked. Before the unevictable/mlock
changes, the kernel simply called make_pages_present() to allocate pages and
diff --git a/Documentation/vm/zswap.txt b/Documentation/vm/zswap.txt
index 00c3d31e7971..8458c0861e4e 100644
--- a/Documentation/vm/zswap.txt
+++ b/Documentation/vm/zswap.txt
@@ -26,8 +26,22 @@ Zswap evicts pages from compressed cache on an LRU basis to the backing swap
device when the compressed pool reaches its size limit. This requirement had
been identified in prior community discussions.
-To enabled zswap, the "enabled" attribute must be set to 1 at boot time. e.g.
-zswap.enabled=1
+Zswap is disabled by default but can be enabled at boot time by setting
+the "enabled" attribute to 1 at boot time. ie: zswap.enabled=1. Zswap
+can also be enabled and disabled at runtime using the sysfs interface.
+An example command to enable zswap at runtime, assuming sysfs is mounted
+at /sys, is:
+
+echo 1 > /sys/modules/zswap/parameters/enabled
+
+When zswap is disabled at runtime it will stop storing pages that are
+being swapped out. However, it will _not_ immediately write out or fault
+back into memory all of the pages stored in the compressed pool. The
+pages stored in zswap will remain in the compressed pool until they are
+either invalidated or faulted back into memory. In order to force all
+pages out of the compressed pool, a swapoff on the swap device(s) will
+fault back into memory all swapped out pages, including those in the
+compressed pool.
Design:
diff --git a/Documentation/vme_api.txt b/Documentation/vme_api.txt
index ffe6e22a2ccd..ca5b82797f6c 100644
--- a/Documentation/vme_api.txt
+++ b/Documentation/vme_api.txt
@@ -171,6 +171,12 @@ This functions by reading the offset, applying the mask. If the bits selected in
the mask match with the values of the corresponding bits in the compare field,
the value of swap is written the specified offset.
+Parts of a VME window can be mapped into user space memory using the following
+function:
+
+ int vme_master_mmap(struct vme_resource *resource,
+ struct vm_area_struct *vma)
+
Slave windows
=============
diff --git a/Documentation/w1/slaves/w1_therm b/Documentation/w1/slaves/w1_therm
index cc62a95e4776..13411fe52f7f 100644
--- a/Documentation/w1/slaves/w1_therm
+++ b/Documentation/w1/slaves/w1_therm
@@ -11,12 +11,14 @@ Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Description
-----------
-w1_therm provides basic temperature conversion for ds18*20 devices.
+w1_therm provides basic temperature conversion for ds18*20 devices, and the
+ds28ea00 device.
supported family codes:
W1_THERM_DS18S20 0x10
W1_THERM_DS1822 0x22
W1_THERM_DS18B20 0x28
W1_THERM_DS1825 0x3B
+W1_THERM_DS28EA00 0x42
Support is provided through the sysfs w1_slave file. Each open and
read sequence will initiate a temperature conversion then provide two
@@ -48,3 +50,10 @@ resistor). The DS18b20 temperature sensor specification lists a
maximum current draw of 1.5mA and that a 5k pullup resistor is not
sufficient. The strong pullup is designed to provide the additional
current required.
+
+The DS28EA00 provides an additional two pins for implementing a sequence
+detection algorithm. This feature allows you to determine the physical
+location of the chip in the 1-wire bus without needing pre-existing
+knowledge of the bus ordering. Support is provided through the sysfs
+w1_seq file. The file will contain a single line with an integer value
+representing the device index in the bus starting at 0.
diff --git a/Documentation/w1/w1.generic b/Documentation/w1/w1.generic
index b2033c64c7da..b3ffaf8cfab2 100644
--- a/Documentation/w1/w1.generic
+++ b/Documentation/w1/w1.generic
@@ -76,21 +76,24 @@ See struct w1_bus_master definition in w1.h for details.
w1 master sysfs interface
------------------------------------------------------------------
-<xx-xxxxxxxxxxxxx> - a directory for a found device. The format is family-serial
+<xx-xxxxxxxxxxxxx> - A directory for a found device. The format is family-serial
bus - (standard) symlink to the w1 bus
driver - (standard) symlink to the w1 driver
-w1_master_add - Manually register a slave device
-w1_master_attempts - the number of times a search was attempted
+w1_master_add - (rw) manually register a slave device
+w1_master_attempts - (ro) the number of times a search was attempted
w1_master_max_slave_count
- - maximum number of slaves to search for at a time
-w1_master_name - the name of the device (w1_bus_masterX)
-w1_master_pullup - 5V strong pullup 0 enabled, 1 disabled
-w1_master_remove - Manually remove a slave device
-w1_master_search - the number of searches left to do, -1=continual (default)
+ - (rw) maximum number of slaves to search for at a time
+w1_master_name - (ro) the name of the device (w1_bus_masterX)
+w1_master_pullup - (rw) 5V strong pullup 0 enabled, 1 disabled
+w1_master_remove - (rw) manually remove a slave device
+w1_master_search - (rw) the number of searches left to do,
+ -1=continual (default)
w1_master_slave_count
- - the number of slaves found
-w1_master_slaves - the names of the slaves, one per line
-w1_master_timeout - the delay in seconds between searches
+ - (ro) the number of slaves found
+w1_master_slaves - (ro) the names of the slaves, one per line
+w1_master_timeout - (ro) the delay in seconds between searches
+w1_master_timeout_us
+ - (ro) the delay in microseconds beetwen searches
If you have a w1 bus that never changes (you don't add or remove devices),
you can set the module parameter search_count to a small positive number
@@ -101,6 +104,11 @@ generally only make sense when searching is disabled, as a search will
redetect manually removed devices that are present and timeout manually
added devices that aren't on the bus.
+Bus searches occur at an interval, specified as a summ of timeout and
+timeout_us module parameters (either of which may be 0) for as long as
+w1_master_search remains greater than 0 or is -1. Each search attempt
+decrements w1_master_search by 1 (down to 0) and increments
+w1_master_attempts by 1.
w1 slave sysfs interface
------------------------------------------------------------------
diff --git a/Documentation/workqueue.txt b/Documentation/workqueue.txt
index f81a65b54c29..5e0e05c5183e 100644
--- a/Documentation/workqueue.txt
+++ b/Documentation/workqueue.txt
@@ -365,7 +365,7 @@ root 5674 0.0 0.0 0 0 ? S 12:13 0:00 [kworker/1:0]
If kworkers are going crazy (using too much cpu), there are two types
of possible problems:
- 1. Something beeing scheduled in rapid succession
+ 1. Something being scheduled in rapid succession
2. A single work item that consumes lots of cpu cycles
The first one can be tracked using tracing:
diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt
index 88b85899d309..7c1f9fad6674 100644
--- a/Documentation/x86/boot.txt
+++ b/Documentation/x86/boot.txt
@@ -1124,7 +1124,6 @@ The boot loader *must* fill out the following fields in bp,
o hdr.code32_start
o hdr.cmd_line_ptr
- o hdr.cmdline_size
o hdr.ramdisk_image (if applicable)
o hdr.ramdisk_size (if applicable)
diff --git a/Documentation/x86/entry_64.txt b/Documentation/x86/entry_64.txt
index 9132b86176a3..33884d156125 100644
--- a/Documentation/x86/entry_64.txt
+++ b/Documentation/x86/entry_64.txt
@@ -18,10 +18,10 @@ Some of these entries are:
- system_call: syscall instruction from 64-bit code.
- - ia32_syscall: int 0x80 from 32-bit or 64-bit code; compat syscall
+ - entry_INT80_compat: int 0x80 from 32-bit or 64-bit code; compat syscall
either way.
- - ia32_syscall, ia32_sysenter: syscall and sysenter from 32-bit
+ - entry_INT80_compat, ia32_sysenter: syscall and sysenter from 32-bit
code
- interrupt: An array of entries. Every IDT vector that doesn't
diff --git a/Documentation/x86/x86_64/kernel-stacks b/Documentation/x86/kernel-stacks
index e3c8a49d1a2f..0f3a6c201943 100644
--- a/Documentation/x86/x86_64/kernel-stacks
+++ b/Documentation/x86/kernel-stacks
@@ -1,3 +1,6 @@
+Kernel stacks on x86-64 bit
+---------------------------
+
Most of the text from Keith Owens, hacked by AK
x86_64 page size (PAGE_SIZE) is 4K.
@@ -56,13 +59,6 @@ If that assumption is ever broken then the stacks will become corrupt.
The currently assigned IST stacks are :-
-* STACKFAULT_STACK. EXCEPTION_STKSZ (PAGE_SIZE).
-
- Used for interrupt 12 - Stack Fault Exception (#SS).
-
- This allows the CPU to recover from invalid stack segments. Rarely
- happens.
-
* DOUBLEFAULT_STACK. EXCEPTION_STKSZ (PAGE_SIZE).
Used for interrupt 8 - Double Fault Exception (#DF).
@@ -99,3 +95,47 @@ The currently assigned IST stacks are :-
assumptions about the previous state of the kernel stack.
For more details see the Intel IA32 or AMD AMD64 architecture manuals.
+
+
+Printing backtraces on x86
+--------------------------
+
+The question about the '?' preceding function names in an x86 stacktrace
+keeps popping up, here's an indepth explanation. It helps if the reader
+stares at print_context_stack() and the whole machinery in and around
+arch/x86/kernel/dumpstack.c.
+
+Adapted from Ingo's mail, Message-ID: <20150521101614.GA10889@gmail.com>:
+
+We always scan the full kernel stack for return addresses stored on
+the kernel stack(s) [*], from stack top to stack bottom, and print out
+anything that 'looks like' a kernel text address.
+
+If it fits into the frame pointer chain, we print it without a question
+mark, knowing that it's part of the real backtrace.
+
+If the address does not fit into our expected frame pointer chain we
+still print it, but we print a '?'. It can mean two things:
+
+ - either the address is not part of the call chain: it's just stale
+ values on the kernel stack, from earlier function calls. This is
+ the common case.
+
+ - or it is part of the call chain, but the frame pointer was not set
+ up properly within the function, so we don't recognize it.
+
+This way we will always print out the real call chain (plus a few more
+entries), regardless of whether the frame pointer was set up correctly
+or not - but in most cases we'll get the call chain right as well. The
+entries printed are strictly in stack order, so you can deduce more
+information from that as well.
+
+The most important property of this method is that we _never_ lose
+information: we always strive to print _all_ addresses on the stack(s)
+that look like kernel text addresses, so if debug information is wrong,
+we still print out the real call chain as well - just with more question
+marks than ideal.
+
+[*] For things like IRQ and IST stacks, we also scan those stacks, in
+ the right order, and try to cross from one stack into another
+ reconstructing the call chain. This works most of the time.
diff --git a/Documentation/x86/mtrr.txt b/Documentation/x86/mtrr.txt
index cc071dc333c2..860bc3adc223 100644
--- a/Documentation/x86/mtrr.txt
+++ b/Documentation/x86/mtrr.txt
@@ -1,7 +1,19 @@
MTRR (Memory Type Range Register) control
-3 Jun 1999
-Richard Gooch
-<rgooch@atnf.csiro.au>
+
+Richard Gooch <rgooch@atnf.csiro.au> - 3 Jun 1999
+Luis R. Rodriguez <mcgrof@do-not-panic.com> - April 9, 2015
+
+===============================================================================
+Phasing out MTRR use
+
+MTRR use is replaced on modern x86 hardware with PAT. Over time the only type
+of effective MTRR that is expected to be supported will be for write-combining.
+As MTRR use is phased out device drivers should use arch_phys_wc_add() to make
+MTRR effective on non-PAT systems while a no-op on PAT enabled systems.
+
+For details refer to Documentation/x86/pat.txt.
+
+===============================================================================
On Intel P6 family processors (Pentium Pro, Pentium II and later)
the Memory Type Range Registers (MTRRs) may be used to control
diff --git a/Documentation/x86/pat.txt b/Documentation/x86/pat.txt
index cf08c9fff3cd..54944c71b819 100644
--- a/Documentation/x86/pat.txt
+++ b/Documentation/x86/pat.txt
@@ -12,7 +12,7 @@ virtual addresses.
PAT allows for different types of memory attributes. The most commonly used
ones that will be supported at this time are Write-back, Uncached,
-Write-combined and Uncached Minus.
+Write-combined, Write-through and Uncached Minus.
PAT APIs
@@ -34,16 +34,23 @@ ioremap | -- | UC- | UC- |
| | | |
ioremap_cache | -- | WB | WB |
| | | |
+ioremap_uc | -- | UC | UC |
+ | | | |
ioremap_nocache | -- | UC- | UC- |
| | | |
ioremap_wc | -- | -- | WC |
| | | |
+ioremap_wt | -- | -- | WT |
+ | | | |
set_memory_uc | UC- | -- | -- |
set_memory_wb | | | |
| | | |
set_memory_wc | WC | -- | -- |
set_memory_wb | | | |
| | | |
+set_memory_wt | WT | -- | -- |
+ set_memory_wb | | | |
+ | | | |
pci sysfs resource | -- | -- | UC- |
| | | |
pci sysfs resource_wc | -- | -- | WC |
@@ -102,7 +109,38 @@ wants to export a RAM region, it has to do set_memory_uc() or set_memory_wc()
as step 0 above and also track the usage of those pages and use set_memory_wb()
before the page is freed to free pool.
-
+MTRR effects on PAT / non-PAT systems
+-------------------------------------
+
+The following table provides the effects of using write-combining MTRRs when
+using ioremap*() calls on x86 for both non-PAT and PAT systems. Ideally
+mtrr_add() usage will be phased out in favor of arch_phys_wc_add() which will
+be a no-op on PAT enabled systems. The region over which a arch_phys_wc_add()
+is made, should already have been ioremapped with WC attributes or PAT entries,
+this can be done by using ioremap_wc() / set_memory_wc(). Devices which
+combine areas of IO memory desired to remain uncacheable with areas where
+write-combining is desirable should consider use of ioremap_uc() followed by
+set_memory_wc() to white-list effective write-combined areas. Such use is
+nevertheless discouraged as the effective memory type is considered
+implementation defined, yet this strategy can be used as last resort on devices
+with size-constrained regions where otherwise MTRR write-combining would
+otherwise not be effective.
+
+----------------------------------------------------------------------
+MTRR Non-PAT PAT Linux ioremap value Effective memory type
+----------------------------------------------------------------------
+ Non-PAT | PAT
+ PAT
+ |PCD
+ ||PWT
+ |||
+WC 000 WB _PAGE_CACHE_MODE_WB WC | WC
+WC 001 WC _PAGE_CACHE_MODE_WC WC* | WC
+WC 010 UC- _PAGE_CACHE_MODE_UC_MINUS WC* | UC
+WC 011 UC _PAGE_CACHE_MODE_UC UC | UC
+----------------------------------------------------------------------
+
+(*) denotes implementation defined and is discouraged
Notes:
@@ -115,8 +153,8 @@ can be more restrictive, in case of any existing aliasing for that address.
For example: If there is an existing uncached mapping, a new ioremap_wc can
return uncached mapping in place of write-combine requested.
-set_memory_[uc|wc] and set_memory_wb should be used in pairs, where driver will
-first make a region uc or wc and switch it back to wb after use.
+set_memory_[uc|wc|wt] and set_memory_wb should be used in pairs, where driver
+will first make a region uc, wc or wt and switch it back to wb after use.
Over time writes to /proc/mtrr will be deprecated in favor of using PAT based
interfaces. Users writing to /proc/mtrr are suggested to use above interfaces.
@@ -124,7 +162,7 @@ interfaces. Users writing to /proc/mtrr are suggested to use above interfaces.
Drivers should use ioremap_[uc|wc] to access PCI BARs with [uc|wc] access
types.
-Drivers should use set_memory_[uc|wc] to set access type for RAM ranges.
+Drivers should use set_memory_[uc|wc|wt] to set access type for RAM ranges.
PAT debugging
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
index 5223479291a2..68ed3114c363 100644
--- a/Documentation/x86/x86_64/boot-options.txt
+++ b/Documentation/x86/x86_64/boot-options.txt
@@ -31,6 +31,9 @@ Machine check
(e.g. BIOS or hardware monitoring applications), conflicting
with OS's error handling, and you cannot deactivate the agent,
then this option will be a help.
+ mce=no_lmce
+ Do not opt-in to Local MCE delivery. Use legacy method
+ to broadcast MCEs.
mce=bootlog
Enable logging of machine checks left over from booting.
Disabled by default on AMD because some BIOS leave bogus ones.
diff --git a/Documentation/zh_CN/gpio.txt b/Documentation/zh_CN/gpio.txt
index d5b8f01833f4..bce972521065 100644
--- a/Documentation/zh_CN/gpio.txt
+++ b/Documentation/zh_CN/gpio.txt
@@ -638,9 +638,6 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
int gpio_export_link(struct device *dev, const char *name,
unsigned gpio)
- /* æ”¹å˜ sysfs 中的一个 GPIO 节点的æžæ€§ */
- int gpio_sysfs_set_active_low(unsigned gpio, int value);
-
在一个内核驱动申请一个 GPIO 之åŽï¼Œå®ƒå¯ä»¥é€šè¿‡ gpio_export()使其在 sysfs
接å£ä¸­å¯è§ã€‚该驱动å¯ä»¥æŽ§åˆ¶ä¿¡å·æ–¹å‘是å¦å¯ä¿®æ”¹ã€‚这有助于防止用户空间代ç æ— æ„é—´
ç ´åé‡è¦çš„系统状æ€ã€‚
@@ -651,8 +648,3 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
在 GPIO 被导出之åŽï¼Œgpio_export_link()å…许在 sysfs 文件系统的任何地方
创建一个到这个 GPIO sysfs 节点的符å·é“¾æŽ¥ã€‚这样驱动就å¯ä»¥é€šè¿‡ä¸€ä¸ªæ述性的
å字,在 sysfs 中他们所拥有的设备下æ供一个(到这个 GPIO sysfs 节点的)接å£ã€‚
-
-驱动å¯ä»¥ä½¿ç”¨ gpio_sysfs_set_active_low() æ¥åœ¨ç”¨æˆ·ç©ºé—´éšè—电路æ¿ä¹‹é—´
-GPIO 线的æžæ€§å·®å¼‚。这个仅对 sysfs 接å£èµ·ä½œç”¨ã€‚æžæ€§çš„改å˜å¯ä»¥åœ¨ gpio_export()
-å‰åŽè¿›è¡Œ,且之å‰ä½¿èƒ½çš„轮询æ“作(poll(2))支æŒ(上å‡æˆ–下é™æ²¿)将会被é‡æ–°é…ç½®æ¥éµå¾ª
-这个设置。
diff --git a/Documentation/zh_CN/magic-number.txt b/Documentation/zh_CN/magic-number.txt
index dfb72a5c63e9..e9db693c0a23 100644
--- a/Documentation/zh_CN/magic-number.txt
+++ b/Documentation/zh_CN/magic-number.txt
@@ -116,7 +116,6 @@ COW_MAGIC 0x4f4f4f4d cow_header_v1 arch/um/drivers/ubd_user.c
I810_CARD_MAGIC 0x5072696E i810_card sound/oss/i810_audio.c
TRIDENT_CARD_MAGIC 0x5072696E trident_card sound/oss/trident.c
ROUTER_MAGIC 0x524d4157 wan_device [in wanrouter.h pre 3.9]
-SCC_MAGIC 0x52696368 gs_port drivers/char/scc.h
SAVEKMSG_MAGIC1 0x53415645 savekmsg arch/*/amiga/config.c
GDA_MAGIC 0x58464552 gda arch/mips/include/asm/sn/gda.h
RED_MAGIC1 0x5a2cf071 (any) mm/slab.c
@@ -138,7 +137,6 @@ KMALLOC_MAGIC 0x87654321 snd_alloc_track sound/core/memory.c
PWC_MAGIC 0x89DC10AB pwc_device drivers/usb/media/pwc.h
NBD_REPLY_MAGIC 0x96744668 nbd_reply include/linux/nbd.h
ENI155_MAGIC 0xa54b872d midway_eprom drivers/atm/eni.h
-SCI_MAGIC 0xbabeface gs_port drivers/char/sh-sci.h
CODA_MAGIC 0xC0DAC0DA coda_file_info include/linux/coda_fs_i.h
DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram drivers/scsi/gdth.h
YAM_MAGIC 0xF10A7654 yam_port drivers/net/hamradio/yam.c
diff --git a/Kbuild b/Kbuild
index 6f0d82a9245d..df99a5f53beb 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2,8 +2,9 @@
# Kbuild for top-level directory of the kernel
# This file takes care of the following:
# 1) Generate bounds.h
-# 2) Generate asm-offsets.h (may need bounds.h)
-# 3) Check for missing system calls
+# 2) Generate timeconst.h
+# 3) Generate asm-offsets.h (may need bounds.h and timeconst.h)
+# 4) Check for missing system calls
# Default sed regexp - multiline due to syntax constraints
define sed-y
@@ -47,7 +48,26 @@ $(obj)/$(bounds-file): kernel/bounds.s FORCE
$(call filechk,offsets,__LINUX_BOUNDS_H__)
#####
-# 2) Generate asm-offsets.h
+# 2) Generate timeconst.h
+
+timeconst-file := include/generated/timeconst.h
+
+#always += $(timeconst-file)
+targets += $(timeconst-file)
+
+quiet_cmd_gentimeconst = GEN $@
+define cmd_gentimeconst
+ (echo $(CONFIG_HZ) | bc -q $< ) > $@
+endef
+define filechk_gentimeconst
+ (echo $(CONFIG_HZ) | bc -q $< )
+endef
+
+$(obj)/$(timeconst-file): kernel/time/timeconst.bc FORCE
+ $(call filechk,gentimeconst)
+
+#####
+# 3) Generate asm-offsets.h
#
offsets-file := include/generated/asm-offsets.h
@@ -57,7 +77,7 @@ targets += arch/$(SRCARCH)/kernel/asm-offsets.s
# We use internal kbuild rules to avoid the "is up to date" message from make
arch/$(SRCARCH)/kernel/asm-offsets.s: arch/$(SRCARCH)/kernel/asm-offsets.c \
- $(obj)/$(bounds-file) FORCE
+ $(obj)/$(timeconst-file) $(obj)/$(bounds-file) FORCE
$(Q)mkdir -p $(dir $@)
$(call if_changed_dep,cc_s_c)
@@ -65,7 +85,7 @@ $(obj)/$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s FORCE
$(call filechk,offsets,__ASM_OFFSETS_H__)
#####
-# 3) Check for missing system calls
+# 4) Check for missing system calls
#
always += missing-syscalls
@@ -77,5 +97,5 @@ quiet_cmd_syscalls = CALL $<
missing-syscalls: scripts/checksyscalls.sh $(offsets-file) FORCE
$(call cmd,syscalls)
-# Keep these two files during make clean
-no-clean-files := $(bounds-file) $(offsets-file)
+# Keep these three files during make clean
+no-clean-files := $(bounds-file) $(offsets-file) $(timeconst-file)
diff --git a/MAINTAINERS b/MAINTAINERS
index 25a17aa20741..6aedd5072323 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -259,7 +259,7 @@ S: Maintained
F: drivers/platform/x86/acer-wmi.c
ACPI
-M: Rafael J. Wysocki <rjw@rjwysocki.net>
+M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
M: Len Brown <lenb@kernel.org>
L: linux-acpi@vger.kernel.org
W: https://01.org/linux-acpi
@@ -280,7 +280,7 @@ F: tools/power/acpi/
ACPI COMPONENT ARCHITECTURE (ACPICA)
M: Robert Moore <robert.moore@intel.com>
M: Lv Zheng <lv.zheng@intel.com>
-M: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+M: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
L: linux-acpi@vger.kernel.org
L: devel@acpica.org
W: https://acpica.org/
@@ -445,6 +445,7 @@ F: drivers/input/misc/adxl34x.c
ADVANSYS SCSI DRIVER
M: Matthew Wilcox <matthew@wil.cx>
+M: Hannes Reinecke <hare@suse.de>
L: linux-scsi@vger.kernel.org
S: Maintained
F: Documentation/scsi/advansys.txt
@@ -631,7 +632,7 @@ F: drivers/iommu/amd_iommu*.[ch]
F: include/linux/amd-iommu.h
AMD KFD
-M: Oded Gabbay <oded.gabbay@amd.com>
+M: Oded Gabbay <oded.gabbay@gmail.com>
L: dri-devel@lists.freedesktop.org
T: git git://people.freedesktop.org/~gabbayo/linux.git
S: Supported
@@ -652,7 +653,6 @@ M: Tom Lendacky <thomas.lendacky@amd.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/amd/xgbe/
-F: drivers/net/phy/amd-xgbe-phy.c
AMS (Apple Motion Sensor) DRIVER
M: Michael Hanselmann <linux-kernel@hansmi.ch>
@@ -732,7 +732,7 @@ ANDROID DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
M: Arve Hjønnevåg <arve@android.com>
M: Riley Andrews <riandrews@android.com>
-T: git git://git.kernel.org/pub/scm/linux/kernel/gregkh/staging.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
L: devel@driverdev.osuosl.org
S: Supported
F: drivers/android/
@@ -922,6 +922,13 @@ M: Krzysztof Halasa <khalasa@piap.pl>
S: Maintained
F: arch/arm/mach-cns3xxx/
+ARM/CAVIUM THUNDER NETWORK DRIVER
+M: Sunil Goutham <sgoutham@cavium.com>
+M: Robert Richter <rric@kernel.org>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Supported
+F: drivers/net/ethernet/cavium/
+
ARM/CIRRUS LOGIC CLPS711X ARM ARCHITECTURE
M: Alexander Shiyan <shc_work@mail.ru>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -977,6 +984,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
T: git git://github.com/ulli-kroll/linux.git
S: Maintained
F: arch/arm/mach-gemini/
+F: drivers/rtc/rtc-gemini.c
ARM/CSR SIRFPRIMA2 MACHINE SUPPORT
M: Barry Song <baohua@kernel.org>
@@ -1035,7 +1043,7 @@ F: arch/arm/include/asm/hardware/dec21285.h
F: arch/arm/mach-footbridge/
ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
-M: Shawn Guo <shawn.guo@linaro.org>
+M: Shawn Guo <shawnguo@kernel.org>
M: Sascha Hauer <kernel@pengutronix.de>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
@@ -1044,9 +1052,11 @@ F: arch/arm/mach-imx/
F: arch/arm/mach-mxs/
F: arch/arm/boot/dts/imx*
F: arch/arm/configs/imx*_defconfig
+F: drivers/clk/imx/
+F: include/soc/imx/
ARM/FREESCALE VYBRID ARM ARCHITECTURE
-M: Shawn Guo <shawn.guo@linaro.org>
+M: Shawn Guo <shawnguo@kernel.org>
M: Sascha Hauer <kernel@pengutronix.de>
R: Stefan Agner <stefan@agner.ch>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1189,6 +1199,12 @@ M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
+ARM/LPC18XX ARCHITECTURE
+M: Joachim Eastwood <manabian@gmail.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+N: lpc18xx
+
ARM/MAGICIAN MACHINE SUPPORT
M: Philipp Zabel <philipp.zabel@gmail.com>
S: Maintained
@@ -1236,6 +1252,13 @@ W: http://www.digriz.org.uk/ts78xx/kernel
S: Maintained
F: arch/arm/mach-orion5x/ts78xx-*
+ARM/Mediatek RTC DRIVER
+M: Eddie Huang <eddie.huang@mediatek.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: drivers/rtc/rtc-mt6397.c
+
ARM/Mediatek SoC support
M: Matthias Brugger <matthias.bgg@gmail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1385,6 +1408,7 @@ L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/boot/dts/s3c*
F: arch/arm/boot/dts/exynos*
+F: arch/arm64/boot/dts/exynos/
F: arch/arm/plat-samsung/
F: arch/arm/mach-s3c24*/
F: arch/arm/mach-s3c64xx/
@@ -1488,12 +1512,22 @@ F: drivers/phy/phy-stih407-usb.c
F: drivers/phy/phy-stih41x-usb.c
F: drivers/pinctrl/pinctrl-st.c
F: drivers/reset/sti/
+F: drivers/rtc/rtc-st-lpc.c
F: drivers/tty/serial/st-asc.c
F: drivers/usb/dwc3/dwc3-st.c
F: drivers/usb/host/ehci-st.c
F: drivers/usb/host/ohci-st.c
+F: drivers/watchdog/st_lpc_wdt.c
F: drivers/ata/ahci_st.c
+ARM/STM32 ARCHITECTURE
+M: Maxime Coquelin <mcoquelin.stm32@gmail.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/mcoquelin/stm32.git
+N: stm32
+F: drivers/clocksource/armv7m_systick.c
+
ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1540,6 +1574,13 @@ F: drivers/rtc/rtc-ab3100.c
F: drivers/rtc/rtc-coh901331.c
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
+ARM/UNIPHIER ARCHITECTURE
+M: Masahiro Yamada <yamada.masahiro@socionext.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: arch/arm/mach-uniphier/
+N: uniphier
+
ARM/Ux500 ARM ARCHITECTURE
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1617,6 +1658,15 @@ S: Maintained
F: arch/arm/mach-pxa/z2.c
F: arch/arm/mach-pxa/include/mach/z2.h
+ARM/ZTE ARCHITECTURE
+M: Jun Nie <jun.nie@linaro.org>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: arch/arm/mach-zx/
+F: drivers/clk/zte/
+F: Documentation/devicetree/bindings/arm/zte.txt
+F: Documentation/devicetree/bindings/clock/zx296702-clk.txt
+
ARM/ZYNQ ARCHITECTURE
M: Michal Simek <michal.simek@xilinx.com>
R: Sören Brinkmann <soren.brinkmann@xilinx.com>
@@ -1634,11 +1684,12 @@ F: drivers/i2c/busses/i2c-cadence.c
F: drivers/mmc/host/sdhci-of-arasan.c
F: drivers/edac/synopsys_edac.c
-ARM SMMU DRIVER
+ARM SMMU DRIVERS
M: Will Deacon <will.deacon@arm.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: drivers/iommu/arm-smmu.c
+F: drivers/iommu/arm-smmu-v3.c
F: drivers/iommu/io-pgtable-arm.c
ARM64 PORT (AARCH64 ARCHITECTURE)
@@ -1869,6 +1920,14 @@ W: http://www.attotech.com
S: Supported
F: drivers/scsi/esas2r
+ATUSB IEEE 802.15.4 RADIO DRIVER
+M: Stefan Schmidt <stefan@osg.samsung.com>
+L: linux-wpan@vger.kernel.org
+S: Maintained
+F: drivers/net/ieee802154/atusb.c
+F: drivers/net/ieee802154/atusb.h
+F: drivers/net/ieee802154/at86rf230.h
+
AUDIT SUBSYSTEM
M: Paul Moore <paul@paul-moore.com>
M: Eric Paris <eparis@redhat.com>
@@ -1973,6 +2032,14 @@ W: http://bcache.evilpiepirate.org
S: Maintained:
F: drivers/md/bcache/
+BDISP ST MEDIA DRIVER
+M: Fabien Dessenne <fabien.dessenne@st.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Supported
+F: drivers/media/platform/sti/bdisp
+
BEFS FILE SYSTEM
S: Orphan
F: Documentation/filesystems/befs.txt
@@ -2057,6 +2124,7 @@ M: Jens Axboe <axboe@kernel.dk>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
S: Maintained
F: block/
+F: kernel/trace/blktrace.c
BLOCK2MTD DRIVER
M: Joern Engel <joern@lazybastard.org>
@@ -2201,6 +2269,7 @@ S: Maintained
F: arch/arm/mach-bcm/*brcmstb*
F: arch/arm/boot/dts/bcm7*.dts*
F: drivers/bus/brcmstb_gisb.c
+N: brcmstb
BROADCOM BMIPS MIPS ARCHITECTURE
M: Kevin Cernekee <cernekee@gmail.com>
@@ -2258,6 +2327,13 @@ N: bcm9583*
N: bcm583*
N: bcm113*
+BROADCOM BRCMSTB GPIO DRIVER
+M: Gregory Fong <gregory.0xf0@gmail.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
+
BROADCOM KONA GPIO DRIVER
M: Ray Jui <rjui@broadcom.com>
L: bcm-kernel-feedback-list@broadcom.com
@@ -2271,6 +2347,12 @@ L: linux-mips@linux-mips.org
S: Maintained
F: drivers/firmware/broadcom/*
+BROADCOM STB NAND FLASH DRIVER
+M: Brian Norris <computersforpeace@gmail.com>
+L: linux-mtd@lists.infradead.org
+S: Maintained
+F: drivers/mtd/nand/brcmnand/
+
BROADCOM SPECIFIC AMBA DRIVER (BCMA)
M: Rafał Miłecki <zajec5@gmail.com>
L: linux-wireless@vger.kernel.org
@@ -2450,6 +2532,17 @@ S: Maintained
F: drivers/iio/light/cm*
F: Documentation/devicetree/bindings/i2c/trivial-devices.txt
+CAVIUM LIQUIDIO NETWORK DRIVER
+M: Derek Chickles <derek.chickles@caviumnetworks.com>
+M: Satanand Burla <satananda.burla@caviumnetworks.com>
+M: Felix Manlunas <felix.manlunas@caviumnetworks.com>
+M: Raghu Vatsavayi <raghu.vatsavayi@caviumnetworks.com>
+L: netdev@vger.kernel.org
+W: http://www.cavium.com
+S: Supported
+F: drivers/net/ethernet/cavium/
+F: drivers/net/ethernet/cavium/liquidio/
+
CC2520 IEEE-802.15.4 RADIO DRIVER
M: Varka Bhadram <varkabhadram@gmail.com>
L: linux-wpan@vger.kernel.org
@@ -2461,7 +2554,6 @@ F: Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
CELL BROADBAND ENGINE ARCHITECTURE
M: Arnd Bergmann <arnd@arndb.de>
L: linuxppc-dev@lists.ozlabs.org
-L: cbe-oss-dev@lists.ozlabs.org
W: http://www.ibm.com/developerworks/power/cell/
S: Supported
F: arch/powerpc/include/asm/cell*.h
@@ -2471,7 +2563,7 @@ F: arch/powerpc/oprofile/*cell*
F: arch/powerpc/platforms/cell/
CEPH DISTRIBUTED FILE SYSTEM CLIENT
-M: Yan, Zheng <zyan@redhat.com>
+M: "Yan, Zheng" <zyan@redhat.com>
M: Sage Weil <sage@redhat.com>
L: ceph-devel@vger.kernel.org
W: http://ceph.com/
@@ -2617,6 +2709,13 @@ L: linux-scsi@vger.kernel.org
S: Supported
F: drivers/scsi/fnic/
+CISCO SCSI HBA DRIVER
+M: Narsimhulu Musini <nmusini@cisco.com>
+M: Sesidhar Baddela <sebaddel@cisco.com>
+L: linux-scsi@vger.kernel.org
+S: Supported
+F: drivers/scsi/snic/
+
CMPC ACPI DRIVER
M: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
M: Daniel Oliveira Nascimento <don@syst.com.br>
@@ -2624,6 +2723,14 @@ L: platform-driver-x86@vger.kernel.org
S: Supported
F: drivers/platform/x86/classmate-laptop.c
+COBALT MEDIA DRIVER
+M: Hans Verkuil <hans.verkuil@cisco.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Supported
+F: drivers/media/pci/cobalt/
+
COCCINELLE/Semantic Patches (SmPL)
M: Julia Lawall <Julia.Lawall@lip6.fr>
M: Gilles Muller <Gilles.Muller@lip6.fr>
@@ -2723,6 +2830,7 @@ F: drivers/connector/
CONTROL GROUP (CGROUP)
M: Tejun Heo <tj@kernel.org>
M: Li Zefan <lizefan@huawei.com>
+M: Johannes Weiner <hannes@cmpxchg.org>
L: cgroups@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
S: Maintained
@@ -2770,7 +2878,7 @@ S: Maintained
F: drivers/net/ethernet/ti/cpmac.c
CPU FREQUENCY DRIVERS
-M: Rafael J. Wysocki <rjw@rjwysocki.net>
+M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
M: Viresh Kumar <viresh.kumar@linaro.org>
L: linux-pm@vger.kernel.org
S: Maintained
@@ -2809,7 +2917,7 @@ F: drivers/cpuidle/cpuidle-exynos.c
F: arch/arm/mach-exynos/pm.c
CPUIDLE DRIVERS
-M: Rafael J. Wysocki <rjw@rjwysocki.net>
+M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
M: Daniel Lezcano <daniel.lezcano@linaro.org>
L: linux-pm@vger.kernel.org
S: Maintained
@@ -2895,6 +3003,15 @@ S: Maintained
F: drivers/media/common/cx2341x*
F: include/media/cx2341x*
+CX24120 MEDIA DRIVER
+M: Jemma Denson <jdenson@gmail.com>
+M: Patrick Boettcher <patrick.boettcher@posteo.de>
+L: linux-media@vger.kernel.org
+W: http://linuxtv.org/
+Q: http://patchwork.linuxtv.org/project/linux-media/list/
+S: Maintained
+F: drivers/media/dvb-frontends/cx24120*
+
CX88 VIDEO4LINUX DRIVER
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
@@ -2969,7 +3086,7 @@ M: Michael Neuling <mikey@neuling.org>
L: linuxppc-dev@lists.ozlabs.org
S: Supported
F: drivers/misc/cxl/
-F: include/misc/cxl.h
+F: include/misc/cxl*
F: include/uapi/misc/cxl.h
F: Documentation/powerpc/cxl.txt
F: Documentation/powerpc/cxl.txt
@@ -3105,9 +3222,9 @@ S: Maintained
F: drivers/platform/x86/dell-smo8800.c
DELL LAPTOP SMM DRIVER
-M: Guenter Roeck <linux@roeck-us.net>
+M: Pali Rohár <pali.rohar@gmail.com>
S: Maintained
-F: drivers/char/i8k.c
+F: drivers/hwmon/dell-smm-hwmon.c
F: include/uapi/linux/i8k.h
DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas)
@@ -3302,6 +3419,8 @@ F: drivers/hwmon/dme1737.c
DMI/SMBIOS SUPPORT
M: Jean Delvare <jdelvare@suse.de>
S: Maintained
+T: quilt http://jdelvare.nerim.net/devel/linux/jdelvare-dmi/
+F: Documentation/ABI/testing/sysfs-firmware-dmi-tables
F: drivers/firmware/dmi-id.c
F: drivers/firmware/dmi_scan.c
F: include/linux/dmi.h
@@ -3346,16 +3465,17 @@ F: drivers/block/drbd/
F: lib/lru_cache.c
F: Documentation/blockdev/drbd/
-DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
+DRIVER CORE, KOBJECTS, DEBUGFS, KERNFS AND SYSFS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
S: Supported
F: Documentation/kobject.txt
F: drivers/base/
-F: fs/sysfs/
F: fs/debugfs/
-F: include/linux/kobj*
+F: fs/kernfs/
+F: fs/sysfs/
F: include/linux/debugfs.h
+F: include/linux/kobj*
F: lib/kobj*
DRM DRIVERS
@@ -3461,6 +3581,14 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/wan/dscc4.c
+DT3155 MEDIA DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Odd Fixes
+F: drivers/media/pci/dt3155/
+
DVB_USB_AF9015 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
@@ -3743,7 +3871,7 @@ S: Maintained
F: drivers/edac/ie31200_edac.c
EDAC-MPC85XX
-M: Johannes Thumshirn <johannes.thumshirn@men.de>
+M: Johannes Thumshirn <morbidrsa@gmail.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
@@ -3770,6 +3898,13 @@ W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/sb_edac.c
+EDAC-XGENE
+APPLIED MICRO (APM) X-GENE SOC EDAC
+M: Loc Ho <lho@apm.com>
+S: Supported
+F: drivers/edac/xgene_edac.c
+F: Documentation/devicetree/bindings/edac/apm-xgene-edac.txt
+
EDIROL UA-101/UA-1000 DRIVER
M: Clemens Ladisch <clemens@ladisch.de>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -4018,7 +4153,7 @@ F: include/uapi/scsi/fc/
FILE LOCKING (flock() and fcntl()/lockf())
M: Jeff Layton <jlayton@poochiereds.net>
-M: J. Bruce Fields <bfields@fieldses.org>
+M: "J. Bruce Fields" <bfields@fieldses.org>
L: linux-fsdevel@vger.kernel.org
S: Maintained
F: include/linux/fcntl.h
@@ -4214,7 +4349,7 @@ F: sound/soc/fsl/imx*
F: sound/soc/fsl/mpc8610_hpcd.c
FREESCALE QORIQ MANAGEMENT COMPLEX DRIVER
-M: J. German Rivera <German.Rivera@freescale.com>
+M: "J. German Rivera" <German.Rivera@freescale.com>
L: linux-kernel@vger.kernel.org
S: Maintained
F: drivers/staging/fsl-mc/
@@ -4496,7 +4631,7 @@ S: Maintained
F: drivers/media/usb/gspca/
GUID PARTITION TABLE (GPT)
-M: Davidlohr Bueso <davidlohr@hp.com>
+M: Davidlohr Bueso <dave@stgolabs.net>
L: linux-efi@vger.kernel.org
S: Maintained
F: block/partitions/efi.*
@@ -4508,6 +4643,17 @@ T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/usb/stk1160/
+H8/300 ARCHITECTURE
+M: Yoshinori Sato <ysato@users.sourceforge.jp>
+L: uclinux-h8-devel@lists.sourceforge.jp
+W: http://uclinux-h8.sourceforge.jp
+T: git git://git.sourceforge.jp/gitroot/uclinux-h8/linux.git
+S: Maintained
+F: arch/h8300/
+F: drivers/clocksource/h8300_*.c
+F: drivers/clk/h8300/
+F: drivers/irqchip/irq-renesas-h8*.c
+
HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
M: Frank Seidel <frank@f-seidel.de>
L: platform-driver-x86@vger.kernel.org
@@ -4657,6 +4803,18 @@ F: drivers/hid/
F: include/linux/hid*
F: include/uapi/linux/hid*
+HID SENSOR HUB DRIVERS
+M: Jiri Kosina <jkosina@suse.cz>
+M: Jonathan Cameron <jic23@kernel.org>
+M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+L: linux-input@vger.kernel.org
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/hid/hid-sensor*
+F: drivers/hid/hid-sensor-*
+F: drivers/iio/*/hid-*
+F: include/linux/hid-sensor-*
+
HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS
M: Thomas Gleixner <tglx@linutronix.de>
L: linux-kernel@vger.kernel.org
@@ -4763,7 +4921,7 @@ S: Maintained
F: fs/hugetlbfs/
Hyper-V CORE AND DRIVERS
-M: K. Y. Srinivasan <kys@microsoft.com>
+M: "K. Y. Srinivasan" <kys@microsoft.com>
M: Haiyang Zhang <haiyangz@microsoft.com>
L: devel@linuxdriverproject.org
S: Maintained
@@ -4893,13 +5051,23 @@ M: Marcelo Henrique Cerri <mhcerri@linux.vnet.ibm.com>
M: Fionnuala Gunter <fin@linux.vnet.ibm.com>
L: linux-crypto@vger.kernel.org
S: Supported
-F: drivers/crypto/nx/
+F: drivers/crypto/nx/Makefile
+F: drivers/crypto/nx/Kconfig
+F: drivers/crypto/nx/nx-aes*
+F: drivers/crypto/nx/nx-sha*
+F: drivers/crypto/nx/nx.*
+F: drivers/crypto/nx/nx_csbcpb.h
+F: drivers/crypto/nx/nx_debugfs.h
IBM Power 842 compression accelerator
M: Dan Streetman <ddstreet@us.ibm.com>
S: Supported
-F: drivers/crypto/nx/nx-842.c
-F: include/linux/nx842.h
+F: drivers/crypto/nx/Makefile
+F: drivers/crypto/nx/Kconfig
+F: drivers/crypto/nx/nx-842*
+F: include/linux/sw842.h
+F: crypto/842.c
+F: lib/842/
IBM Power Linux RAID adapter
M: Brian King <brking@us.ibm.com>
@@ -5108,7 +5276,6 @@ F: include/linux/input/
INPUT MULTITOUCH (MT) PROTOCOL
M: Henrik Rydberg <rydberg@bitmath.org>
L: linux-input@vger.kernel.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/rydberg/input-mt.git
S: Odd fixes
F: Documentation/input/multi-touch-protocol.txt
F: drivers/input/input-mt.c
@@ -5116,7 +5283,7 @@ K: \b(ABS|SYN)_MT_
INTEL ASoC BDW/HSW DRIVERS
M: Jie Yang <yang.jie@linux.intel.com>
-L: alsa-devel@alsa-project.org
+L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported
F: sound/soc/intel/sst-haswell*
F: sound/soc/intel/sst-dsp*
@@ -5293,6 +5460,7 @@ M: Tomas Winkler <tomas.winkler@intel.com>
L: linux-kernel@vger.kernel.org
S: Supported
F: include/uapi/linux/mei.h
+F: include/linux/mei_cl_bus.h
F: drivers/misc/mei/*
F: Documentation/misc-devices/mei/*
@@ -6358,6 +6526,15 @@ W: http://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-maxiradio*
+MEDIA DRIVERS FOR RENESAS - VSP1
+M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+L: linux-media@vger.kernel.org
+L: linux-sh@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Supported
+F: Documentation/devicetree/bindings/media/renesas,vsp1.txt
+F: drivers/media/platform/vsp1/
+
MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
P: LinuxTV.org Project
@@ -6380,6 +6557,12 @@ F: include/uapi/linux/meye.h
F: include/uapi/linux/ivtv*
F: include/uapi/linux/uvcvideo.h
+MEDIATEK MT7601U WIRELESS LAN DRIVER
+M: Jakub Kicinski <kubakici@wp.pl>
+L: linux-wireless@vger.kernel.org
+S: Maintained
+F: drivers/net/wireless/mediatek/mt7601u/
+
MEGARAID SCSI/SAS DRIVERS
M: Kashyap Desai <kashyap.desai@avagotech.com>
M: Sumit Saxena <sumit.saxena@avagotech.com>
@@ -6426,14 +6609,14 @@ F: include/linux/mtd/
F: include/uapi/mtd/
MEN A21 WATCHDOG DRIVER
-M: Johannes Thumshirn <johannes.thumshirn@men.de>
+M: Johannes Thumshirn <morbidrsa@gmail.com>
L: linux-watchdog@vger.kernel.org
-S: Supported
+S: Maintained
F: drivers/watchdog/mena21_wdt.c
MEN CHAMELEON BUS (mcb)
-M: Johannes Thumshirn <johannes.thumshirn@men.de>
-S: Supported
+M: Johannes Thumshirn <morbidrsa@gmail.com>
+S: Maintained
F: drivers/mcb/
F: include/linux/mcb.h
@@ -6693,7 +6876,7 @@ F: drivers/net/ethernet/natsemi/natsemi.c
NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER
M: Daniel Mack <zonque@gmail.com>
S: Maintained
-L: alsa-devel@alsa-project.org
+L: alsa-devel@alsa-project.org (moderated for non-subscribers)
W: http://www.native-instruments.com
F: sound/usb/caiaq/
@@ -7111,7 +7294,7 @@ F: arch/arm/mach-omap2/prm*
OMAP AUDIO SUPPORT
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
M: Jarkko Nikula <jarkko.nikula@bitmer.com>
-L: alsa-devel@alsa-project.org (subscribers-only)
+L: alsa-devel@alsa-project.org (moderated for non-subscribers)
L: linux-omap@vger.kernel.org
S: Maintained
F: sound/soc/omap/
@@ -7406,13 +7589,16 @@ S: Maintained
F: Documentation/mn10300/
F: arch/mn10300/
-PARALLEL PORT SUPPORT
+PARALLEL PORT SUBSYSTEM
+M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
+M: Sudip Mukherjee <sudip@vectorindia.org>
L: linux-parport@lists.infradead.org (subscribers-only)
-S: Orphan
+S: Maintained
F: drivers/parport/
F: include/linux/parport*.h
F: drivers/char/ppdev.c
F: include/uapi/linux/ppdev.h
+F: Documentation/parport*.txt
PARAVIRT_OPS INTERFACE
M: Jeremy Fitzhardinge <jeremy@goop.org>
@@ -7608,6 +7794,14 @@ L: linux-pci@vger.kernel.org
S: Maintained
F: drivers/pci/host/*spear*
+PCI MSI DRIVER FOR APPLIEDMICRO XGENE
+M: Duc Dang <dhdang@apm.com>
+L: linux-pci@vger.kernel.org
+L: linux-arm-kernel@lists.infradead.org
+S: Maintained
+F: Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
+F: drivers/pci/host/pci-xgene-msi.c
+
PCMCIA SUBSYSTEM
P: Linux PCMCIA Team
L: linux-pcmcia@lists.infradead.org
@@ -7648,7 +7842,6 @@ F: kernel/delayacct.c
PERFORMANCE EVENTS SUBSYSTEM
M: Peter Zijlstra <a.p.zijlstra@chello.nl>
-M: Paul Mackerras <paulus@samba.org>
M: Ingo Molnar <mingo@redhat.com>
M: Arnaldo Carvalho de Melo <acme@kernel.org>
L: linux-kernel@vger.kernel.org
@@ -7806,7 +7999,7 @@ F: include/linux/power_supply.h
F: drivers/power/
PNP SUPPORT
-M: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+M: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
S: Maintained
F: drivers/pnp/
@@ -7875,14 +8068,13 @@ F: drivers/net/wireless/prism54/
PS3 NETWORK SUPPORT
M: Geoff Levand <geoff@infradead.org>
L: netdev@vger.kernel.org
-L: cbe-oss-dev@lists.ozlabs.org
+L: linuxppc-dev@lists.ozlabs.org
S: Maintained
F: drivers/net/ethernet/toshiba/ps3_gelic_net.*
PS3 PLATFORM SUPPORT
M: Geoff Levand <geoff@infradead.org>
L: linuxppc-dev@lists.ozlabs.org
-L: cbe-oss-dev@lists.ozlabs.org
S: Maintained
F: arch/powerpc/boot/ps3*
F: arch/powerpc/include/asm/lv1call.h
@@ -7896,7 +8088,8 @@ F: sound/ppc/snd_ps3*
PS3VRAM DRIVER
M: Jim Paris <jim@jtan.com>
-L: cbe-oss-dev@lists.ozlabs.org
+M: Geoff Levand <geoff@infradead.org>
+L: linuxppc-dev@lists.ozlabs.org
S: Maintained
F: drivers/block/ps3vram.c
@@ -8160,8 +8353,6 @@ P: rt2x00 project
M: Stanislaw Gruszka <sgruszka@redhat.com>
M: Helmut Schaa <helmut.schaa@googlemail.com>
L: linux-wireless@vger.kernel.org
-L: users@rt2x00.serialmonkey.com (moderated for non-subscribers)
-W: http://rt2x00.serialmonkey.com/
S: Maintained
F: drivers/net/wireless/rt2x00/
@@ -8251,6 +8442,7 @@ M: Alessandro Zummo <a.zummo@towertech.it>
M: Alexandre Belloni <alexandre.belloni@free-electrons.com>
L: rtc-linux@googlegroups.com
Q: http://patchwork.ozlabs.org/project/rtc-linux/list/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
S: Maintained
F: Documentation/rtc.txt
F: drivers/rtc/
@@ -8551,14 +8743,20 @@ L: linux-fbdev@vger.kernel.org
S: Maintained
F: drivers/video/fbdev/s3c-fb.c
-SAMSUNG MULTIFUNCTION DEVICE DRIVERS
+SAMSUNG MULTIFUNCTION PMIC DEVICE DRIVERS
M: Sangbeom Kim <sbkim73@samsung.com>
+M: Krzysztof Kozlowski <k.kozlowski@samsung.com>
L: linux-kernel@vger.kernel.org
+L: linux-samsung-soc@vger.kernel.org
S: Supported
F: drivers/mfd/sec*.c
F: drivers/regulator/s2m*.c
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
SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
M: Kyungmin Park <kyungmin.park@samsung.com>
@@ -8807,7 +9005,7 @@ F: drivers/mmc/host/sdhci-spear.c
SECURITY SUBSYSTEM
M: James Morris <james.l.morris@oracle.com>
-M: Serge E. Hallyn <serge@hallyn.com>
+M: "Serge E. Hallyn" <serge@hallyn.com>
L: linux-security-module@vger.kernel.org (suggested Cc:)
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git
W: http://kernsec.org/
@@ -9027,7 +9225,7 @@ F: arch/arm/mach-davinci/
F: drivers/i2c/busses/i2c-davinci.c
TI DAVINCI SERIES MEDIA DRIVER
-M: Lad, Prabhakar <prabhakar.csengg@gmail.com>
+M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
@@ -9037,7 +9235,7 @@ F: drivers/media/platform/davinci/
F: include/media/davinci/
TI AM437X VPFE DRIVER
-M: Lad, Prabhakar <prabhakar.csengg@gmail.com>
+M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
@@ -9046,7 +9244,7 @@ S: Maintained
F: drivers/media/platform/am437x/
OV2659 OMNIVISION SENSOR DRIVER
-M: Lad, Prabhakar <prabhakar.csengg@gmail.com>
+M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
@@ -9375,7 +9573,6 @@ F: drivers/net/ethernet/toshiba/spider_net*
SPU FILE SYSTEM
M: Jeremy Kerr <jk@ozlabs.org>
L: linuxppc-dev@lists.ozlabs.org
-L: cbe-oss-dev@lists.ozlabs.org
W: http://www.ibm.com/developerworks/power/cell/
S: Supported
F: Documentation/filesystems/spufs.txt
@@ -9514,6 +9711,15 @@ M: Forest Bond <forest@alittletooquiet.net>
S: Odd Fixes
F: drivers/staging/vt665?/
+STAGING - WILC1000 WIFI DRIVER
+M: Johnny Kim <johnny.kim@atmel.com>
+M: Rachel Kim <rachel.kim@atmel.com>
+M: Dean Lee <dean.lee@atmel.com>
+M: Chris Park <chris.park@atmel.com>
+L: linux-wireless@vger.kernel.org
+S: Supported
+F: drivers/staging/wilc1000/
+
STAGING - XGI Z7,Z9,Z11 PCI DISPLAY DRIVER
M: Arnaud Patard <arnaud.patard@rtp-net.org>
S: Odd Fixes
@@ -9597,6 +9803,13 @@ F: arch/arc/
F: Documentation/devicetree/bindings/arc/
F: drivers/tty/serial/arc_uart.c
+SYSTEM CONFIGURATION (SYSCON)
+M: Lee Jones <lee.jones@linaro.org>
+M: Arnd Bergmann <arnd@arndb.de>
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
+S: Supported
+F: drivers/mfd/syscon.c
+
SYSV FILESYSTEM
M: Christoph Hellwig <hch@infradead.org>
S: Maintained
@@ -9605,7 +9818,7 @@ F: fs/sysv/
F: include/linux/sysv_fs.h
TARGET SUBSYSTEM
-M: Nicholas A. Bellinger <nab@linux-iscsi.org>
+M: "Nicholas A. Bellinger" <nab@linux-iscsi.org>
L: linux-scsi@vger.kernel.org
L: target-devel@vger.kernel.org
W: http://www.linux-iscsi.org
@@ -9747,7 +9960,7 @@ F: include/linux/if_team.h
F: include/uapi/linux/if_team.h
TECHNOLOGIC SYSTEMS TS-5500 PLATFORM SUPPORT
-M: Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>
+M: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
S: Maintained
F: arch/x86/platform/ts5500/
@@ -9938,6 +10151,12 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/ti/netcp*
+TI TAS571X FAMILY ASoC CODEC DRIVER
+M: Kevin Cernekee <cernekee@chromium.org>
+L: alsa-devel@alsa-project.org (moderated for non-subscribers)
+S: Odd Fixes
+F: sound/soc/codecs/tas571x*
+
TI TWL4030 SERIES SOC CODEC DRIVER
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -10031,7 +10250,7 @@ F: include/linux/toshiba.h
F: include/uapi/linux/toshiba.h
TMIO MMC DRIVER
-M: Ian Molton <ian.molton@codethink.co.uk>
+M: Ian Molton <ian@mnementh.co.uk>
L: linux-mmc@vger.kernel.org
S: Maintained
F: drivers/mmc/host/tmio_mmc*
@@ -10112,6 +10331,7 @@ M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
M: Jiri Slaby <jslaby@suse.cz>
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
+F: Documentation/serial/
F: drivers/tty/
F: drivers/tty/serial/serial_core.c
F: include/linux/serial_core.h
@@ -10507,6 +10727,13 @@ S: Maintained
F: Documentation/video4linux/zr364xx.txt
F: drivers/media/usb/zr364xx/
+ULPI BUS
+M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+L: linux-usb@vger.kernel.org
+S: Maintained
+F: drivers/usb/common/ulpi.c
+F: include/linux/ulpi/
+
USER-MODE LINUX (UML)
M: Jeff Dike <jdike@addtoit.com>
M: Richard Weinberger <richard@nod.at>
@@ -10587,6 +10814,15 @@ F: drivers/block/virtio_blk.c
F: include/linux/virtio_*.h
F: include/uapi/linux/virtio_*.h
+VIRTIO GPU DRIVER
+M: David Airlie <airlied@linux.ie>
+M: Gerd Hoffmann <kraxel@redhat.com>
+L: dri-devel@lists.freedesktop.org
+L: virtualization@lists.linux-foundation.org
+S: Maintained
+F: drivers/gpu/drm/virtio/
+F: include/uapi/linux/virtio_gpu.h
+
VIRTIO HOST (VHOST)
M: "Michael S. Tsirkin" <mst@redhat.com>
L: kvm@vger.kernel.org
@@ -10909,7 +11145,7 @@ M: Andy Lutomirski <luto@amacapital.net>
L: linux-kernel@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/vdso
S: Maintained
-F: arch/x86/vdso/
+F: arch/x86/entry/vdso/
XC2028/3028 TUNER DRIVER
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
diff --git a/Makefile b/Makefile
index 3ba504496cb2..6c6f14628f32 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 4
PATCHLEVEL = 1
SUBLEVEL = 0
-EXTRAVERSION = -rc8
+EXTRAVERSION =
NAME = Hurr durr I'ma sheep
# *DOCUMENTATION*
@@ -215,7 +215,6 @@ VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
export srctree objtree VPATH
-
# SUBARCH tells the usermode build what the underlying arch is. That is set
# first, and if a usermode build is happening, the "ARCH=um" on the command
# line overrides the setting of ARCH below. If a native build is happening,
@@ -1497,11 +1496,11 @@ image_name:
# Clear a bunch of variables before executing the submake
tools/: FORCE
$(Q)mkdir -p $(objtree)/tools
- $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/
+ $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(O) subdir=tools -C $(src)/tools/
tools/%: FORCE
$(Q)mkdir -p $(objtree)/tools
- $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/ $*
+ $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(O) subdir=tools -C $(src)/tools/ $*
# Single targets
# ---------------------------------------------------------------------------
diff --git a/arch/Kconfig b/arch/Kconfig
index a65eafb24997..bec6666a3cc4 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -499,6 +499,13 @@ config ARCH_HAS_ELF_RANDOMIZE
- arch_mmap_rnd()
- arch_randomize_brk()
+config HAVE_COPY_THREAD_TLS
+ bool
+ help
+ Architecture provides copy_thread_tls to accept tls argument via
+ normal C parameter passing, rather than extracting the syscall
+ argument from pt_regs.
+
#
# ABI hall of shame
#
diff --git a/arch/alpha/include/asm/Kbuild b/arch/alpha/include/asm/Kbuild
index 76aeb8fa551a..cde23cd03609 100644
--- a/arch/alpha/include/asm/Kbuild
+++ b/arch/alpha/include/asm/Kbuild
@@ -6,6 +6,5 @@ generic-y += exec.h
generic-y += irq_work.h
generic-y += mcs_spinlock.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += trace_clock.h
diff --git a/arch/alpha/include/asm/cmpxchg.h b/arch/alpha/include/asm/cmpxchg.h
index 429e8cd0d78e..e5117766529e 100644
--- a/arch/alpha/include/asm/cmpxchg.h
+++ b/arch/alpha/include/asm/cmpxchg.h
@@ -66,6 +66,4 @@
#undef __ASM__MB
#undef ____cmpxchg
-#define __HAVE_ARCH_CMPXCHG 1
-
#endif /* _ALPHA_CMPXCHG_H */
diff --git a/arch/alpha/include/asm/mm-arch-hooks.h b/arch/alpha/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..b07fd862fec3
--- /dev/null
+++ b/arch/alpha/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_ALPHA_MM_ARCH_HOOKS_H
+#define _ASM_ALPHA_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_ALPHA_MM_ARCH_HOOKS_H */
diff --git a/arch/alpha/include/asm/pci.h b/arch/alpha/include/asm/pci.h
index f7f680f7457d..98f2eeee8f68 100644
--- a/arch/alpha/include/asm/pci.h
+++ b/arch/alpha/include/asm/pci.h
@@ -5,7 +5,7 @@
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <asm/machvec.h>
#include <asm-generic/pci-bridge.h>
@@ -71,22 +71,6 @@ extern void pcibios_set_master(struct pci_dev *dev);
/* implement the pci_ DMA API in terms of the generic device dma_ one */
#include <asm-generic/pci-dma-compat.h>
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- unsigned long cacheline_size;
- u8 byte;
-
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
- if (byte == 0)
- cacheline_size = 1024;
- else
- cacheline_size = (int) byte * 4;
-
- *strat = PCI_DMA_BURST_BOUNDARY;
- *strategy_parameter = cacheline_size;
-}
#endif
/* TODO: integrate with include/asm-generic/pci.h ? */
diff --git a/arch/alpha/include/asm/serial.h b/arch/alpha/include/asm/serial.h
index 9d263e8d8ccc..22909b83f473 100644
--- a/arch/alpha/include/asm/serial.h
+++ b/arch/alpha/include/asm/serial.h
@@ -13,7 +13,7 @@
#define BASE_BAUD ( 1843200 / 16 )
/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
#else
diff --git a/arch/alpha/kernel/core_irongate.c b/arch/alpha/kernel/core_irongate.c
index 00096df0f6ad..83d0a359a1b2 100644
--- a/arch/alpha/kernel/core_irongate.c
+++ b/arch/alpha/kernel/core_irongate.c
@@ -22,7 +22,6 @@
#include <linux/bootmem.h>
#include <asm/ptrace.h>
-#include <asm/pci.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
diff --git a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c
index 79d69d7f63f8..15f42083bdb3 100644
--- a/arch/alpha/kernel/sys_eiger.c
+++ b/arch/alpha/kernel/sys_eiger.c
@@ -22,7 +22,6 @@
#include <asm/irq.h>
#include <asm/mmu_context.h>
#include <asm/io.h>
-#include <asm/pci.h>
#include <asm/pgtable.h>
#include <asm/core_tsunami.h>
#include <asm/hwrpb.h>
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 700686d04869..2cfaa0e5c577 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -39,7 +39,6 @@
#include <asm/irq.h>
#include <asm/mmu_context.h>
#include <asm/io.h>
-#include <asm/pci.h>
#include <asm/pgtable.h>
#include <asm/core_irongate.h>
#include <asm/hwrpb.h>
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index 9d0ac091a52a..4a905bd667e2 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -23,8 +23,7 @@
#include <linux/smp.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *);
@@ -107,7 +106,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
/* If we're in an interrupt context, or have no user context,
we must not take the fault. */
- if (!mm || in_atomic())
+ if (!mm || faulthandler_disabled())
goto no_context;
#ifdef CONFIG_ALPHA_LARGE_VMALLOC
diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild
index be0c39e76f7c..769b312c1abb 100644
--- a/arch/arc/include/asm/Kbuild
+++ b/arch/arc/include/asm/Kbuild
@@ -33,7 +33,6 @@ generic-y += poll.h
generic-y += posix_types.h
generic-y += preempt.h
generic-y += resource.h
-generic-y += scatterlist.h
generic-y += sembuf.h
generic-y += shmbuf.h
generic-y += siginfo.h
diff --git a/arch/arc/include/asm/futex.h b/arch/arc/include/asm/futex.h
index 4dc64ddebece..05b5aaf5b0f9 100644
--- a/arch/arc/include/asm/futex.h
+++ b/arch/arc/include/asm/futex.h
@@ -53,7 +53,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;
- pagefault_disable(); /* implies preempt_disable() */
+ pagefault_disable();
switch (op) {
case FUTEX_OP_SET:
@@ -75,7 +75,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
ret = -ENOSYS;
}
- pagefault_enable(); /* subsumes preempt_enable() */
+ pagefault_enable();
if (!ret) {
switch (cmp) {
@@ -104,7 +104,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
return ret;
}
-/* Compare-xchg with preemption disabled.
+/* Compare-xchg with pagefaults disabled.
* Notes:
* -Best-Effort: Exchg happens only if compare succeeds.
* If compare fails, returns; leaving retry/looping to upper layers
@@ -121,7 +121,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval,
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
return -EFAULT;
- pagefault_disable(); /* implies preempt_disable() */
+ pagefault_disable();
/* TBD : can use llock/scond */
__asm__ __volatile__(
@@ -142,7 +142,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval,
: "r"(oldval), "r"(newval), "r"(uaddr), "ir"(-EFAULT)
: "cc", "memory");
- pagefault_enable(); /* subsumes preempt_enable() */
+ pagefault_enable();
*uval = val;
return val;
diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h
index cabd518cb253..7cc4ced5dbf4 100644
--- a/arch/arc/include/asm/io.h
+++ b/arch/arc/include/asm/io.h
@@ -20,6 +20,7 @@ extern void iounmap(const void __iomem *addr);
#define ioremap_nocache(phy, sz) ioremap(phy, sz)
#define ioremap_wc(phy, sz) ioremap(phy, sz)
+#define ioremap_wt(phy, sz) ioremap(phy, sz)
/* Change struct page to physical address */
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
diff --git a/arch/arc/include/asm/mm-arch-hooks.h b/arch/arc/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..c37541c5f8ba
--- /dev/null
+++ b/arch/arc/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_ARC_MM_ARCH_HOOKS_H
+#define _ASM_ARC_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_ARC_MM_ARCH_HOOKS_H */
diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c
index 6a2e006cbcce..d948e4e9d89c 100644
--- a/arch/arc/mm/fault.c
+++ b/arch/arc/mm/fault.c
@@ -86,7 +86,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto no_context;
if (user_mode(regs))
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 45df48ba0b12..a750c1425c3a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -15,6 +15,8 @@ config ARM
select CLONE_BACKWARDS
select CPU_PM if (SUSPEND || CPU_IDLE)
select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS
+ select EDAC_SUPPORT
+ select EDAC_ATOMIC_SCRUB
select GENERIC_ALLOCATOR
select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI)
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
@@ -31,8 +33,8 @@ config ARM
select HARDIRQS_SW_RESEND
select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT)
select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
- select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
- select HAVE_ARCH_KGDB
+ select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32
+ select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32
select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT)
select HAVE_ARCH_TRACEHOOK
select HAVE_BPF_JIT
@@ -43,7 +45,7 @@ config ARM
select HAVE_DMA_API_DEBUG
select HAVE_DMA_ATTRS
select HAVE_DMA_CONTIGUOUS if MMU
- select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL)
+ select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32
select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU
select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
@@ -57,10 +59,10 @@ config ARM
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_LZO
select HAVE_KERNEL_XZ
- select HAVE_KPROBES if !XIP_KERNEL
+ select HAVE_KPROBES if !XIP_KERNEL && !CPU_ENDIAN_BE32 && !CPU_V7M
select HAVE_KRETPROBES if (HAVE_KPROBES)
select HAVE_MEMBLOCK
- select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND
+ select HAVE_MOD_ARCH_SPECIFIC
select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
select HAVE_OPTPROBES if !THUMB2_KERNEL
select HAVE_PERF_EVENTS
@@ -171,7 +173,7 @@ config LOCKDEP_SUPPORT
config TRACE_IRQFLAGS_SUPPORT
bool
- default y
+ default !CPU_V7M
config RWSEM_XCHGADD_ALGORITHM
bool
@@ -329,6 +331,20 @@ config ARCH_MULTIPLATFORM
select SPARSE_IRQ
select USE_OF
+config ARM_SINGLE_ARMV7M
+ bool "ARMv7-M based platforms (Cortex-M0/M3/M4)"
+ depends on !MMU
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select ARM_NVIC
+ select AUTO_ZRELADDR
+ select CLKSRC_OF
+ select COMMON_CLK
+ select CPU_V7M
+ select GENERIC_CLOCKEVENTS
+ select NO_IOPORT_MAP
+ select SPARSE_IRQ
+ select USE_OF
+
config ARCH_REALVIEW
bool "ARM Ltd. RealView family"
select ARCH_WANT_OPTIONAL_GPIOLIB
@@ -398,24 +414,6 @@ config ARCH_EBSA110
Ethernet interface, two PCMCIA sockets, two serial ports and a
parallel port.
-config ARCH_EFM32
- bool "Energy Micro efm32"
- depends on !MMU
- select ARCH_REQUIRE_GPIOLIB
- select ARM_NVIC
- select AUTO_ZRELADDR
- select CLKSRC_OF
- select COMMON_CLK
- select CPU_V7M
- select GENERIC_CLOCKEVENTS
- select NO_DMA
- select NO_IOPORT_MAP
- select SPARSE_IRQ
- select USE_OF
- help
- Support for Energy Micro's (now Silicon Labs) efm32 Giant Gecko
- processors.
-
config ARCH_EP93XX
bool "EP93xx-based"
select ARCH_HAS_HOLES_MEMORYMODEL
@@ -606,6 +604,7 @@ config ARCH_PXA
select ARCH_REQUIRE_GPIOLIB
select ARM_CPU_SUSPEND if PM
select AUTO_ZRELADDR
+ select COMMON_CLK
select CLKDEV_LOOKUP
select CLKSRC_MMIO
select CLKSRC_OF
@@ -752,8 +751,10 @@ config ARCH_OMAP1
select GENERIC_IRQ_CHIP
select HAVE_IDE
select IRQ_DOMAIN
+ select MULTI_IRQ_HANDLER
select NEED_MACH_IO_H if PCCARD
select NEED_MACH_MEMORY_H
+ select SPARSE_IRQ
help
Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx)
@@ -937,6 +938,8 @@ source "arch/arm/mach-tegra/Kconfig"
source "arch/arm/mach-u300/Kconfig"
+source "arch/arm/mach-uniphier/Kconfig"
+
source "arch/arm/mach-ux500/Kconfig"
source "arch/arm/mach-versatile/Kconfig"
@@ -948,8 +951,40 @@ source "arch/arm/mach-vt8500/Kconfig"
source "arch/arm/mach-w90x900/Kconfig"
+source "arch/arm/mach-zx/Kconfig"
+
source "arch/arm/mach-zynq/Kconfig"
+# ARMv7-M architecture
+config ARCH_EFM32
+ bool "Energy Micro efm32"
+ depends on ARM_SINGLE_ARMV7M
+ select ARCH_REQUIRE_GPIOLIB
+ help
+ Support for Energy Micro's (now Silicon Labs) efm32 Giant Gecko
+ processors.
+
+config ARCH_LPC18XX
+ bool "NXP LPC18xx/LPC43xx"
+ depends on ARM_SINGLE_ARMV7M
+ select ARCH_HAS_RESET_CONTROLLER
+ select ARM_AMBA
+ select CLKSRC_LPC32XX
+ select PINCTRL
+ help
+ Support for NXP's LPC18xx Cortex-M3 and LPC43xx Cortex-M4
+ high performance microcontrollers.
+
+config ARCH_STM32
+ bool "STMicrolectronics STM32"
+ depends on ARM_SINGLE_ARMV7M
+ select ARCH_HAS_RESET_CONTROLLER
+ select ARMV7M_SYSTICK
+ select CLKSRC_STM32
+ select RESET_CONTROLLER
+ help
+ Support for STMicroelectronics STM32 processors.
+
# Definitions to make life easier
config ARCH_ACORN
bool
@@ -975,11 +1010,6 @@ config PLAT_PXA
config PLAT_VERSATILE
bool
-config ARM_TIMER_SP804
- bool
- select CLKSRC_MMIO
- select CLKSRC_OF if OF
-
source "arch/arm/firmware/Kconfig"
source arch/arm/mm/Kconfig
@@ -1307,6 +1337,7 @@ config SMP
depends on GENERIC_CLOCKEVENTS
depends on HAVE_SMP
depends on MMU || ARM_MPU
+ select IRQ_WORK
help
This enables support for systems with more than one CPU. If you have
a system with only one CPU, say N. If you have a system with more
@@ -1477,7 +1508,8 @@ config ARM_PSCI
# selected platforms.
config ARCH_NR_GPIO
int
- default 1024 if ARCH_SHMOBILE || ARCH_TEGRA || ARCH_ZYNQ
+ default 1024 if ARCH_BRCMSTB || ARCH_SHMOBILE || ARCH_TEGRA || \
+ ARCH_ZYNQ
default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || \
SOC_DRA7XX || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210
default 416 if ARCH_SUNXI
@@ -1681,6 +1713,21 @@ config HAVE_ARCH_TRANSPARENT_HUGEPAGE
config ARCH_WANT_GENERAL_HUGETLB
def_bool y
+config ARM_MODULE_PLTS
+ bool "Use PLTs to allow module memory to spill over into vmalloc area"
+ depends on MODULES
+ help
+ Allocate PLTs when loading modules so that jumps and calls whose
+ targets are too far away for their relative offsets to be encoded
+ in the instructions themselves can be bounced via veneers in the
+ module's PLT. This allows modules to be allocated in the generic
+ vmalloc area after the dedicated module memory area has been
+ exhausted. The modules will use slightly more memory, but after
+ rounding up to page size, the actual memory footprint is usually
+ the same.
+
+ Say y if you are getting out of memory errors while loading modules
+
source "mm/Kconfig"
config FORCE_MAX_ZONEORDER
@@ -1951,6 +1998,7 @@ config XIP_PHYS_ADDR
config KEXEC
bool "Kexec system call (EXPERIMENTAL)"
depends on (!SMP || PM_SLEEP_SMP)
+ depends on !CPU_V7M
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 0c12ffb155a2..f1b157971366 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -5,6 +5,7 @@ source "lib/Kconfig.debug"
config ARM_PTDUMP
bool "Export kernel pagetable layout to userspace via debugfs"
depends on DEBUG_KERNEL
+ depends on MMU
select DEBUG_FS
---help---
Say Y here if you want to show the kernel pagetable layout in a
@@ -410,6 +411,13 @@ choice
Say Y here if you want kernel low-level debugging support
on i.MX6SX.
+ config DEBUG_IMX7D_UART
+ bool "i.MX7D Debug UART"
+ depends on SOC_IMX7D
+ help
+ Say Y here if you want kernel low-level debugging support
+ on i.MX7D.
+
config DEBUG_KEYSTONE_UART0
bool "Kernel low-level debugging on KEYSTONE2 using UART0"
depends on ARCH_KEYSTONE
@@ -433,6 +441,14 @@ choice
Say Y here if you want kernel low-level debugging support
on KS8695.
+ config DEBUG_LPC18XX_UART0
+ bool "Kernel low-level debugging via LPC18xx/43xx UART0"
+ depends on ARCH_LPC18XX
+ select DEBUG_UART_8250
+ help
+ Say Y here if you want kernel low-level debugging support
+ on NXP LPC18xx/43xx UART0.
+
config DEBUG_MESON_UARTAO
bool "Kernel low-level debugging via Meson6 UARTAO"
depends on ARCH_MESON
@@ -908,13 +924,22 @@ choice
on SA-11x0 UART ports. The kernel will check for the first
enabled UART in a sequence 3-1-2.
- config DEBUG_SOCFPGA_UART
+ config DEBUG_SOCFPGA_UART0
depends on ARCH_SOCFPGA
- bool "Use SOCFPGA UART for low-level debug"
+ bool "Use SOCFPGA UART0 for low-level debug"
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
- on SOCFPGA based platforms.
+ on SOCFPGA(Cyclone 5 and Arria 5) based platforms.
+
+ config DEBUG_SOCFPGA_UART1
+ depends on ARCH_SOCFPGA
+ bool "Use SOCFPGA UART1 for low-level debug"
+ select DEBUG_UART_8250
+ help
+ Say Y here if you want kernel low-level debugging support
+ on SOCFPGA(Arria 10) based platforms.
+
config DEBUG_SUN9I_UART0
bool "Kernel low-level debugging messages via sun9i UART0"
@@ -1157,6 +1182,18 @@ 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
@@ -1231,7 +1268,8 @@ config DEBUG_IMX_UART_PORT
DEBUG_IMX53_UART || \
DEBUG_IMX6Q_UART || \
DEBUG_IMX6SL_UART || \
- DEBUG_IMX6SX_UART
+ DEBUG_IMX6SX_UART || \
+ DEBUG_IMX7D_UART
default 1
depends on ARCH_MXC
help
@@ -1281,7 +1319,8 @@ config DEBUG_LL_INCLUDE
DEBUG_IMX53_UART ||\
DEBUG_IMX6Q_UART || \
DEBUG_IMX6SL_UART || \
- DEBUG_IMX6SX_UART
+ DEBUG_IMX6SX_UART || \
+ DEBUG_IMX7D_UART
default "debug/ks8695.S" if DEBUG_KS8695_UART
default "debug/msm.S" if DEBUG_QCOM_UARTDM
default "debug/netx.S" if DEBUG_NETX_UART
@@ -1337,6 +1376,7 @@ config DEBUG_UART_PHYS
default 0x02531000 if DEBUG_KEYSTONE_UART1
default 0x03010fe0 if ARCH_RPC
default 0x07000000 if DEBUG_SUN9I_UART0
+ default 0x09405000 if DEBUG_ZTE_ZX
default 0x10009000 if DEBUG_REALVIEW_STD_PORT || \
DEBUG_VEXPRESS_UART0_CA9
default 0x1010c000 if DEBUG_REALVIEW_PB1176_PORT
@@ -1359,6 +1399,7 @@ config DEBUG_UART_PHYS
default 0x20201000 if DEBUG_BCM2835
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 0x40100000 if DEBUG_PXA_UART1
default 0x42000000 if ARCH_GEMINI
@@ -1407,7 +1448,8 @@ config DEBUG_UART_PHYS
default 0xfd883000 if DEBUG_ALPINE_UART0
default 0xfe800000 if ARCH_IOP32X
default 0xff690000 if DEBUG_RK32_UART2
- default 0xffc02000 if DEBUG_SOCFPGA_UART
+ default 0xffc02000 if DEBUG_SOCFPGA_UART0
+ default 0xffc02100 if DEBUG_SOCFPGA_UART1
default 0xffd82340 if ARCH_IOP13XX
default 0xffe40000 if DEBUG_RCAR_GEN1_SCIF0
default 0xffe42000 if DEBUG_RCAR_GEN1_SCIF2
@@ -1466,6 +1508,7 @@ config DEBUG_UART_VIRT
default 0xfb009000 if DEBUG_REALVIEW_STD_PORT
default 0xfb10c000 if DEBUG_REALVIEW_PB1176_PORT
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
@@ -1485,7 +1528,8 @@ config DEBUG_UART_VIRT
default 0xfeb26000 if DEBUG_RK3X_UART1
default 0xfeb30c00 if DEBUG_KEYSTONE_UART0
default 0xfeb31000 if DEBUG_KEYSTONE_UART1
- default 0xfec02000 if DEBUG_SOCFPGA_UART
+ default 0xfec02000 if DEBUG_SOCFPGA_UART0
+ default 0xfec02100 if DEBUG_SOCFPGA_UART1
default 0xfec12000 if DEBUG_MVEBU_UART0 || DEBUG_MVEBU_UART0_ALTERNATE
default 0xfec12100 if DEBUG_MVEBU_UART1_ALTERNATE
default 0xfec10000 if DEBUG_SIRFATLAS7_UART0
@@ -1530,8 +1574,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_UART || \
- ARCH_KEYSTONE || DEBUG_ALPINE_UART0 || \
+ default y if DEBUG_PICOXCELL_UART || DEBUG_SOCFPGA_UART0 || \
+ DEBUG_SOCFPGA_UART1 || ARCH_KEYSTONE || \
+ DEBUG_ALPINE_UART0 || \
DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \
DEBUG_DAVINCI_DA8XX_UART2 || \
DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2 || \
@@ -1544,7 +1589,7 @@ config DEBUG_UART_8250_FLOW_CONTROL
config DEBUG_UNCOMPRESS
bool
- depends on ARCH_MULTIPLATFORM || PLAT_SAMSUNG
+ depends on ARCH_MULTIPLATFORM || PLAT_SAMSUNG || ARM_SINGLE_ARMV7M
default y if DEBUG_LL && !DEBUG_OMAP2PLUS_UART && \
(!DEBUG_TEGRA_UART || !ZBOOT_ROM)
help
@@ -1561,7 +1606,7 @@ config DEBUG_UNCOMPRESS
config UNCOMPRESS_INCLUDE
string
default "debug/uncompress.h" if ARCH_MULTIPLATFORM || ARCH_MSM || \
- PLAT_SAMSUNG || ARCH_EFM32 || \
+ PLAT_SAMSUNG || ARM_SINGLE_ARMV7M || \
ARCH_SHMOBILE_LEGACY
default "mach/uncompress.h"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 985227cbbd1b..07ab3d203916 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -19,6 +19,10 @@ LDFLAGS_vmlinux += --be8
LDFLAGS_MODULE += --be8
endif
+ifeq ($(CONFIG_ARM_MODULE_PLTS),y)
+LDFLAGS_MODULE += -T $(srctree)/arch/arm/kernel/module.lds
+endif
+
OBJCOPYFLAGS :=-O binary -R .comment -S
GZFLAGS :=-9
#KBUILD_CFLAGS +=-pipe
@@ -167,6 +171,7 @@ machine-$(CONFIG_ARCH_IOP33X) += iop33x
machine-$(CONFIG_ARCH_IXP4XX) += ixp4xx
machine-$(CONFIG_ARCH_KEYSTONE) += keystone
machine-$(CONFIG_ARCH_KS8695) += ks8695
+machine-$(CONFIG_ARCH_LPC18XX) += lpc18xx
machine-$(CONFIG_ARCH_LPC32XX) += lpc32xx
machine-$(CONFIG_ARCH_MESON) += meson
machine-$(CONFIG_ARCH_MMP) += mmp
@@ -196,14 +201,17 @@ machine-$(CONFIG_ARCH_SHMOBILE) += shmobile
machine-$(CONFIG_ARCH_SIRF) += prima2
machine-$(CONFIG_ARCH_SOCFPGA) += socfpga
machine-$(CONFIG_ARCH_STI) += sti
+machine-$(CONFIG_ARCH_STM32) += stm32
machine-$(CONFIG_ARCH_SUNXI) += sunxi
machine-$(CONFIG_ARCH_TEGRA) += tegra
machine-$(CONFIG_ARCH_U300) += u300
machine-$(CONFIG_ARCH_U8500) += ux500
+machine-$(CONFIG_ARCH_UNIPHIER) += uniphier
machine-$(CONFIG_ARCH_VERSATILE) += versatile
machine-$(CONFIG_ARCH_VEXPRESS) += vexpress
machine-$(CONFIG_ARCH_VT8500) += vt8500
machine-$(CONFIG_ARCH_W90X900) += w90x900
+machine-$(CONFIG_ARCH_ZX) += zx
machine-$(CONFIG_ARCH_ZYNQ) += zynq
machine-$(CONFIG_PLAT_SPEAR) += spear
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 6e1fb2b2ecc7..7a13aebacf81 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -103,6 +103,8 @@ extra-y += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern piggy.lz4 \
lib1funcs.S ashldi3.S bswapsdi2.S $(libfdt) $(libfdt_hdrs) \
hyp-stub.S
+KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
+
ifeq ($(CONFIG_FUNCTION_TRACER),y)
ORIG_CFLAGS := $(KBUILD_CFLAGS)
KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 2c45b5709fa4..06e983f59980 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -130,7 +130,7 @@ start:
.endr
ARM( mov r0, r0 )
ARM( b 1f )
- THUMB( adr r12, BSYM(1f) )
+ THUMB( badr r12, 1f )
THUMB( bx r12 )
.word _magic_sig @ Magic numbers to help the loader
@@ -447,7 +447,7 @@ dtb_check_done:
bl cache_clean_flush
- adr r0, BSYM(restart)
+ badr r0, restart
add r0, r0, r6
mov pc, r0
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 992736b5229b..246473a244f6 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -20,9 +20,9 @@ dtb-$(CONFIG_SOC_SAM_V4_V5) += \
tny_a9263.dtb \
usb_a9263.dtb \
at91-foxg20.dtb \
+ at91-kizbox.dtb \
at91sam9g20ek.dtb \
at91sam9g20ek_2mmc.dtb \
- kizbox.dtb \
tny_a9g20.dtb \
usb_a9g20.dtb \
usb_a9g20_lpw.dtb \
@@ -31,13 +31,16 @@ dtb-$(CONFIG_SOC_SAM_V4_V5) += \
at91sam9n12ek.dtb \
at91sam9rlek.dtb \
at91-ariag25.dtb \
+ at91-ariettag25.dtb \
at91-cosino_mega2560.dtb \
+ at91-kizboxmini.dtb \
at91sam9g15ek.dtb \
at91sam9g25ek.dtb \
at91sam9g35ek.dtb \
at91sam9x25ek.dtb \
at91sam9x35ek.dtb
dtb-$(CONFIG_SOC_SAM_V7) += \
+ at91-kizbox2.dtb \
at91-sama5d3_xplained.dtb \
sama5d31ek.dtb \
sama5d33ek.dtb \
@@ -56,13 +59,18 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
bcm2835-rpi-b.dtb \
bcm2835-rpi-b-plus.dtb
dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm4708-asus-rt-ac56u.dtb \
+ bcm4708-asus-rt-ac68u.dtb \
bcm4708-buffalo-wzr-1750dhp.dtb \
bcm4708-luxul-xwc-1000.dtb \
bcm4708-netgear-r6250.dtb \
bcm4708-netgear-r6300-v2.dtb \
+ bcm4708-smartrg-sr400ac.dtb \
bcm47081-asus-rt-n18u.dtb \
bcm47081-buffalo-wzr-600dhp2.dtb \
bcm47081-buffalo-wzr-900dhp.dtb \
+ bcm4709-asus-rt-ac87u.dtb \
+ bcm4709-buffalo-wxr-1900dhp.dtb \
bcm4709-netgear-r8000.dtb
dtb-$(CONFIG_ARCH_BCM_63XX) += \
bcm963138dvt.dtb
@@ -113,6 +121,7 @@ dtb-$(CONFIG_ARCH_EXYNOS5) += \
exynos5420-peach-pit.dtb \
exynos5420-smdk5420.dtb \
exynos5422-odroidxu3.dtb \
+ exynos5422-odroidxu3-lite.dtb \
exynos5440-sd5v1.dtb \
exynos5440-ssdk5440.dtb \
exynos5800-peach-pi.dtb
@@ -201,6 +210,9 @@ dtb-$(CONFIG_MACH_KIRKWOOD) += \
kirkwood-ts219-6282.dtb \
kirkwood-ts419-6281.dtb \
kirkwood-ts419-6282.dtb
+dtb-$(CONFIG_ARCH_LPC18XX) += \
+ lpc4350-hitex-eval.dtb \
+ lpc4357-ea4357-devkit.dtb
dtb-$(CONFIG_ARCH_LPC32XX) += \
ea3250.dtb phy3250.dtb
dtb-$(CONFIG_MACH_MESON6) += \
@@ -254,14 +266,18 @@ dtb-$(CONFIG_SOC_IMX53) += \
imx53-tx53-x13x.dtb \
imx53-voipac-bsb.dtb
dtb-$(CONFIG_SOC_IMX6Q) += \
+ imx6dl-apf6dev.dtb \
imx6dl-aristainetos_4.dtb \
imx6dl-aristainetos_7.dtb \
+ imx6dl-aristainetos2_4.dtb \
+ imx6dl-aristainetos2_7.dtb \
imx6dl-cubox-i.dtb \
imx6dl-dfi-fs700-m60.dtb \
imx6dl-gw51xx.dtb \
imx6dl-gw52xx.dtb \
imx6dl-gw53xx.dtb \
imx6dl-gw54xx.dtb \
+ imx6dl-gw551x.dtb \
imx6dl-gw552x.dtb \
imx6dl-hummingboard.dtb \
imx6dl-nitrogen6x.dtb \
@@ -277,6 +293,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6dl-udoo.dtb \
imx6dl-wandboard.dtb \
imx6dl-wandboard-revb1.dtb \
+ imx6q-apf6dev.dtb \
imx6q-arm2.dtb \
imx6q-cm-fx6.dtb \
imx6q-cubox-i.dtb \
@@ -288,6 +305,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6q-gw53xx.dtb \
imx6q-gw5400-a.dtb \
imx6q-gw54xx.dtb \
+ imx6q-gw551x.dtb \
imx6q-gw552x.dtb \
imx6q-hummingboard.dtb \
imx6q-nitrogen6x.dtb \
@@ -313,12 +331,15 @@ dtb-$(CONFIG_SOC_IMX6SX) += \
imx6sx-sabreauto.dtb \
imx6sx-sdb-reva.dtb \
imx6sx-sdb.dtb
+dtb-$(CONFIG_SOC_IMX7D) += \
+ imx7d-sdb.dtb
dtb-$(CONFIG_SOC_LS1021A) += \
ls1021a-qds.dtb \
ls1021a-twr.dtb
dtb-$(CONFIG_SOC_VF610) += \
vf500-colibri-eval-v3.dtb \
vf610-colibri-eval-v3.dtb \
+ vf610m4-colibri.dtb \
vf610-cosmic.dtb \
vf610-twr.dtb
dtb-$(CONFIG_ARCH_MXS) += \
@@ -360,6 +381,7 @@ dtb-$(CONFIG_ARCH_OMAP3) += \
am3517-craneboard.dtb \
am3517-evm.dtb \
am3517_mt_ventoux.dtb \
+ logicpd-torpedo-37xx-devkit.dtb \
omap3430-sdp.dtb \
omap3-beagle.dtb \
omap3-beagle-xm.dtb \
@@ -406,9 +428,11 @@ dtb-$(CONFIG_ARCH_OMAP3) += \
dtb-$(CONFIG_SOC_TI81XX) += \
dm8168-evm.dtb
dtb-$(CONFIG_SOC_AM33XX) += \
+ am335x-baltos-ir5221.dtb \
am335x-base0033.dtb \
am335x-bone.dtb \
am335x-boneblack.dtb \
+ am335x-sl50.dtb \
am335x-evm.dtb \
am335x-evmsk.dtb \
am335x-nano.dtb \
@@ -496,7 +520,7 @@ dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \
sh73a0-kzm9g.dtb
dtb-$(CONFIG_ARCH_SOCFPGA) += \
socfpga_arria5_socdk.dtb \
- socfpga_arria10_socdk.dtb \
+ socfpga_arria10_socdk_sdmmc.dtb \
socfpga_cyclone5_socdk.dtb \
socfpga_cyclone5_sockit.dtb \
socfpga_cyclone5_socrates.dtb \
@@ -520,32 +544,39 @@ dtb-$(CONFIG_ARCH_STI) += \
stih416-b2020.dtb \
stih416-b2020e.dtb \
stih418-b2199.dtb
+dtb-$(CONFIG_ARCH_STM32)+= stm32f429-disco.dtb
dtb-$(CONFIG_MACH_SUN4I) += \
sun4i-a10-a1000.dtb \
sun4i-a10-ba10-tvbox.dtb \
sun4i-a10-chuwi-v7-cw0825.dtb \
sun4i-a10-cubieboard.dtb \
+ sun4i-a10-gemei-g9.dtb \
+ sun4i-a10-hackberry.dtb \
+ sun4i-a10-hyundai-a7hd.dtb \
+ sun4i-a10-inet97fv2.dtb \
+ sun4i-a10-jesurun-q5.dtb \
sun4i-a10-marsboard.dtb \
sun4i-a10-mini-xplus.dtb \
sun4i-a10-mk802.dtb \
sun4i-a10-mk802ii.dtb \
- sun4i-a10-hackberry.dtb \
- sun4i-a10-hyundai-a7hd.dtb \
- sun4i-a10-inet97fv2.dtb \
sun4i-a10-olinuxino-lime.dtb \
sun4i-a10-pcduino.dtb
dtb-$(CONFIG_MACH_SUN5I) += \
+ sun5i-a10s-auxtek-t004.dtb \
sun5i-a10s-mk802.dtb \
sun5i-a10s-olinuxino-micro.dtb \
sun5i-a10s-r7-tv-dongle.dtb \
sun5i-a13-hsg-h702.dtb \
sun5i-a13-olinuxino.dtb \
- sun5i-a13-olinuxino-micro.dtb
+ sun5i-a13-olinuxino-micro.dtb \
+ sun5i-a13-utoo-p66.dtb
dtb-$(CONFIG_MACH_SUN6I) += \
sun6i-a31-app4-evb1.dtb \
sun6i-a31-colombus.dtb \
sun6i-a31-hummingbird.dtb \
+ sun6i-a31-i7.dtb \
sun6i-a31-m9.dtb \
+ sun6i-a31-mele-a1000g-quad.dtb \
sun6i-a31s-cs908.dtb
dtb-$(CONFIG_MACH_SUN7I) += \
sun7i-a20-bananapi.dtb \
@@ -555,15 +586,25 @@ dtb-$(CONFIG_MACH_SUN7I) += \
sun7i-a20-hummingbird.dtb \
sun7i-a20-i12-tvbox.dtb \
sun7i-a20-m3.dtb \
+ sun7i-a20-mk808c.dtb \
sun7i-a20-olinuxino-lime.dtb \
sun7i-a20-olinuxino-lime2.dtb \
sun7i-a20-olinuxino-micro.dtb \
- sun7i-a20-pcduino3.dtb
+ sun7i-a20-orangepi.dtb \
+ sun7i-a20-orangepi-mini.dtb \
+ sun7i-a20-pcduino3.dtb \
+ sun7i-a20-pcduino3-nano.dtb \
+ sun7i-a20-wexler-tab7200.dtb
dtb-$(CONFIG_MACH_SUN8I) += \
+ sun8i-a23-evb.dtb \
sun8i-a23-ippo-q8h-v5.dtb \
- sun8i-a23-ippo-q8h-v1.2.dtb
+ sun8i-a23-ippo-q8h-v1.2.dtb \
+ sun8i-a33-et-q8-v1.6.dtb \
+ sun8i-a33-ga10h-v1.1.dtb \
+ sun8i-a33-sinlinx-sina33.dtb
dtb-$(CONFIG_MACH_SUN9I) += \
- sun9i-a80-optimus.dtb
+ sun9i-a80-optimus.dtb \
+ sun9i-a80-cubieboard4.dtb
dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += \
tegra20-harmony.dtb \
tegra20-iris-512.dtb \
@@ -600,6 +641,11 @@ dtb-$(CONFIG_ARCH_U8500) += \
ste-hrefv60plus-tvk.dtb \
ste-ccu8540.dtb \
ste-ccu9540.dtb
+dtb-$(CONFIG_ARCH_UNIPHIER) += \
+ uniphier-ph1-sld3-ref.dtb \
+ uniphier-ph1-ld4-ref.dtb \
+ uniphier-ph1-pro4-ref.dtb \
+ uniphier-ph1-sld8-ref.dtb
dtb-$(CONFIG_ARCH_VERSATILE) += \
versatile-ab.dtb \
versatile-pb.dtb
@@ -624,6 +670,7 @@ dtb-$(CONFIG_ARCH_ZYNQ) += \
zynq-zybo.dtb
dtb-$(CONFIG_MACH_ARMADA_370) += \
armada-370-db.dtb \
+ armada-370-dlink-dns327l.dtb \
armada-370-mirabox.dtb \
armada-370-netgear-rn102.dtb \
armada-370-netgear-rn104.dtb \
@@ -633,6 +680,8 @@ dtb-$(CONFIG_MACH_ARMADA_375) += \
armada-375-db.dtb
dtb-$(CONFIG_MACH_ARMADA_38X) += \
armada-385-db-ap.dtb \
+ armada-385-linksys-caiman.dtb \
+ armada-385-linksys-cobra.dtb \
armada-388-db.dtb \
armada-388-gp.dtb \
armada-388-rd.dtb
@@ -649,17 +698,18 @@ dtb-$(CONFIG_MACH_ARMADA_XP) += \
armada-xp-openblocks-ax3-4.dtb \
armada-xp-synology-ds414.dtb
dtb-$(CONFIG_MACH_DOVE) += \
- dove-cm-a510.dtb \
dove-cubox.dtb \
dove-cubox-es.dtb \
dove-d2plug.dtb \
dove-d3plug.dtb \
- dove-dove-db.dtb
+ dove-dove-db.dtb \
+ dove-sbc-a510.dtb
dtb-$(CONFIG_ARCH_MEDIATEK) += \
mt6589-aquaris5.dtb \
mt6592-evb.dtb \
mt8127-moose.dtb \
mt8135-evbp1.dtb
+dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb
endif
always := $(dtb-y)
diff --git a/arch/arm/boot/dts/am335x-baltos-ir5221.dts b/arch/arm/boot/dts/am335x-baltos-ir5221.dts
new file mode 100644
index 000000000000..7d36601697da
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-baltos-ir5221.dts
@@ -0,0 +1,532 @@
+/*
+ * 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.
+ */
+
+/*
+ * VScom OnRISC
+ * http://www.vscom.de
+ */
+
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ model = "OnRISC Baltos iR 5221";
+ compatible = "vscom,onrisc", "ti,am33xx";
+
+ cpus {
+ cpu@0 {
+ cpu0-supply = <&vdd1_reg>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x10000000>; /* 256 MB */
+ };
+
+ vbat: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vbat";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
+ };
+
+ wl12xx_vmmc: fixedregulator@2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&wl12xx_gpio>;
+ compatible = "regulator-fixed";
+ regulator-name = "vwl1271";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio3 8 0>;
+ startup-delay-us = <70000>;
+ enable-active-high;
+ };
+};
+
+&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] */
+ >;
+ };
+
+ wl12xx_gpio: pinmux_wl12xx_gpio {
+ pinctrl-single,pins = <
+ 0x1e8 (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] */
+ >;
+ };
+
+ tca6416_pins: pinmux_tca6416_pins {
+ pinctrl-single,pins = <
+ 0x1b4 (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 */
+ >;
+ };
+
+ 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 */
+ >;
+ };
+
+ 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 */
+ >;
+ };
+
+ 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 */
+ >;
+ };
+
+ 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 */
+ >;
+ };
+
+ 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 */
+
+
+ /* 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 */
+ >;
+ };
+
+ 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)
+
+ /* 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)
+ >;
+ };
+
+ 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 */
+ >;
+ };
+
+ davinci_mdio_sleep: davinci_mdio_sleep {
+ pinctrl-single,pins = <
+ /* MDIO reset value */
+ 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x14c (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 */
+ >;
+ };
+};
+
+&elm {
+ status = "okay";
+};
+
+&gpmc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nandflash_pins_s0>;
+ ranges = <0 0 0x08000000 0x10000000>; /* CS0: NAND */
+ status = "okay";
+
+ nand@0,0 {
+ reg = <0 0 0>; /* CS0, offset 0 */
+ nand-bus-width = <8>;
+ ti,nand-ecc-opt = "bch8";
+ ti,nand-xfer-type = "polled";
+
+ gpmc,device-nand = "true";
+ 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>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ elm_id = <&elm>;
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins>;
+
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+ dtr-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>;
+ dsr-gpios = <&gpio2 23 GPIO_ACTIVE_LOW>;
+ dcd-gpios = <&gpio2 24 GPIO_ACTIVE_LOW>;
+ rng-gpios = <&gpio2 25 GPIO_ACTIVE_LOW>;
+ cts-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
+ rts-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ dtr-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
+ dsr-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
+ dcd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
+ rng-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+ cts-gpios = <&gpio3 5 GPIO_ACTIVE_LOW>;
+ rts-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
+
+ status = "okay";
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+
+ status = "okay";
+ clock-frequency = <400000>;
+
+ tps: tps@2d {
+ reg = <0x2d>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <28 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&tps65910_pins>;
+ };
+
+ at24@50 {
+ compatible = "at24,24c02";
+ pagesize = <8>;
+ reg = <0x50>;
+ };
+
+ tca6416: gpio@20 {
+ compatible = "ti,tca6416";
+ reg = <0x20>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <20 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&tca6416_pins>;
+ };
+};
+
+&usb {
+ status = "okay";
+};
+
+&usb_ctrl_mod {
+ status = "okay";
+};
+
+&usb0_phy {
+ status = "okay";
+};
+
+&usb1_phy {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+ dr_mode = "host";
+};
+
+&usb1 {
+ status = "okay";
+ dr_mode = "otg";
+};
+
+&cppi41dma {
+ status = "okay";
+};
+
+#include "tps65910.dtsi"
+
+&tps {
+ vcc1-supply = <&vbat>;
+ vcc2-supply = <&vbat>;
+ vcc3-supply = <&vbat>;
+ vcc4-supply = <&vbat>;
+ vcc5-supply = <&vbat>;
+ vcc6-supply = <&vbat>;
+ vcc7-supply = <&vbat>;
+ vccio-supply = <&vbat>;
+
+ ti,en-ck32k-xtal = <1>;
+
+ regulators {
+ vrtc_reg: regulator@0 {
+ regulator-always-on;
+ };
+
+ vio_reg: regulator@1 {
+ regulator-always-on;
+ };
+
+ vdd1_reg: regulator@2 {
+ /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
+ regulator-name = "vdd_mpu";
+ regulator-min-microvolt = <912500>;
+ regulator-max-microvolt = <1312500>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vdd2_reg: regulator@3 {
+ /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
+ regulator-name = "vdd_core";
+ regulator-min-microvolt = <912500>;
+ regulator-max-microvolt = <1150000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vdd3_reg: regulator@4 {
+ regulator-always-on;
+ };
+
+ vdig1_reg: regulator@5 {
+ regulator-always-on;
+ };
+
+ vdig2_reg: regulator@6 {
+ regulator-always-on;
+ };
+
+ vpll_reg: regulator@7 {
+ regulator-always-on;
+ };
+
+ vdac_reg: regulator@8 {
+ regulator-always-on;
+ };
+
+ vaux1_reg: regulator@9 {
+ regulator-always-on;
+ };
+
+ vaux2_reg: regulator@10 {
+ regulator-always-on;
+ };
+
+ vaux33_reg: regulator@11 {
+ regulator-always-on;
+ };
+
+ vmmc_reg: regulator@12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+};
+
+&mac {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&cpsw_default>;
+ pinctrl-1 = <&cpsw_sleep>;
+ dual_emac = <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 = "rmii";
+ dual_emac_res_vlan = <1>;
+};
+
+&cpsw_emac1 {
+ phy_id = <&davinci_mdio>, <7>;
+ phy-mode = "rgmii-txid";
+ dual_emac_res_vlan = <2>;
+};
+
+&phy_sel {
+ rmii-clock-ext = <1>;
+};
+
+&mmc1 {
+ vmmc-supply = <&vmmc_reg>;
+ status = "okay";
+};
+
+&mmc2 {
+ status = "okay";
+ vmmc-supply = <&wl12xx_vmmc>;
+ ti,non-removable;
+ bus-width = <4>;
+ cap-power-off-card;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wlcore: wlcore@2 {
+ compatible = "ti,wl1835";
+ reg = <2>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
+ };
+};
+
+&sham {
+ status = "okay";
+};
+
+&aes {
+ status = "okay";
+};
+
+&gpio0 {
+ ti,no-reset-on-init;
+};
+
+&dcan1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dcan1_pins>;
+
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi
index dbb3f4d2bf84..fec78349c1f3 100644
--- a/arch/arm/boot/dts/am335x-bone-common.dtsi
+++ b/arch/arm/boot/dts/am335x-bone-common.dtsi
@@ -81,6 +81,13 @@
>;
};
+ 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 */
+ >;
+ };
+
uart0_pins: pinmux_uart0_pins {
pinctrl-single,pins = <
0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
@@ -218,8 +225,67 @@
reg = <0x24>;
};
+ baseboard_eeprom: baseboard_eeprom@50 {
+ compatible = "at,24c256";
+ reg = <0x50>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ baseboard_data: baseboard_data@0 {
+ reg = <0 0x100>;
+ };
+ };
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+
+ status = "okay";
+ clock-frequency = <100000>;
+
+ cape_eeprom0: cape_eeprom0@54 {
+ compatible = "at,24c256";
+ reg = <0x54>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cape0_data: cape_data@0 {
+ reg = <0 0x100>;
+ };
+ };
+
+ cape_eeprom1: cape_eeprom1@55 {
+ compatible = "at,24c256";
+ reg = <0x55>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cape1_data: cape_data@0 {
+ reg = <0 0x100>;
+ };
+ };
+
+ cape_eeprom2: cape_eeprom2@56 {
+ compatible = "at,24c256";
+ reg = <0x56>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cape2_data: cape_data@0 {
+ reg = <0 0x100>;
+ };
+ };
+
+ cape_eeprom3: cape_eeprom3@57 {
+ compatible = "at,24c256";
+ reg = <0x57>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cape3_data: cape_data@0 {
+ reg = <0 0x100>;
+ };
+ };
};
+
/include/ "tps65217.dtsi"
&tps {
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 66342515df20..765be2766eb0 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -8,6 +8,7 @@
/dts-v1/;
#include "am33xx.dtsi"
+#include <dt-bindings/interrupt-controller/irq.h>
/ {
model = "TI AM335x EVM";
@@ -38,6 +39,20 @@
regulator-boot-on;
};
+ wlan_en_reg: fixedregulator@2 {
+ compatible = "regulator-fixed";
+ regulator-name = "wlan-en-regulator";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ /* WLAN_EN GPIO for this board - Bank1, pin16 */
+ gpio = <&gpio1 16 0>;
+
+ /* WLAN card specific delay */
+ startup-delay-us = <70000>;
+ enable-active-high;
+ };
+
matrix_keypad: matrix_keypad@0 {
compatible = "gpio-matrix-keypad";
debounce-delay-ms = <5>;
@@ -176,6 +191,15 @@
>;
};
+ 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 */
+ >;
+ };
+
clkout2_pin: pinmux_clkout2_pin {
pinctrl-single,pins = <
0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
@@ -266,6 +290,25 @@
>;
};
+ 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 */
+ >;
+ };
+
+ 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 */
+ >;
+ };
+
lcd_pins_s0: lcd_pins_s0 {
pinctrl-single,pins = <
0x20 (PIN_OUTPUT | MUX_MODE1) /* gpmc_ad8.lcd_data23 */
@@ -323,6 +366,13 @@
status = "okay";
};
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+
+ status = "okay";
+};
+
&i2c0 {
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins>;
@@ -665,6 +715,37 @@
cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
};
+&mmc3 {
+ /* these are on the crossbar and are outlined in the
+ xbar-event-map element */
+ dmas = <&edma 12
+ &edma 13>;
+ dma-names = "tx", "rx";
+ status = "okay";
+ vmmc-supply = <&wlan_en_reg>;
+ bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc3_pins &wlan_pins>;
+ ti,non-removable;
+ ti,needs-special-hs-handling;
+ cap-power-off-card;
+ keep-power-in-suspend;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wlcore: wlcore@0 {
+ compatible = "ti,wl1835";
+ reg = <2>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
+ };
+};
+
+&edma {
+ ti,edma-xbar-event-map = /bits/ 16 <1 12
+ 2 13>;
+};
+
&sham {
status = "okay";
};
diff --git a/arch/arm/boot/dts/am335x-sl50.dts b/arch/arm/boot/dts/am335x-sl50.dts
new file mode 100644
index 000000000000..3303c281697b
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-sl50.dts
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2015 Toby Churchill - http://www.toby-churchill.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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+
+/ {
+ model = "Toby Churchill SL50 Series";
+ compatible = "tcl,am335x-sl50", "ti,am33xx";
+
+ cpus {
+ cpu@0 {
+ cpu0-supply = <&dcdc2_reg>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins>;
+
+ led@0 {
+ label = "sl50:green:usr0";
+ gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led@1 {
+ label = "sl50:red:usr1";
+ gpios = <&gpio1 22 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led@2 {
+ label = "sl50:green:usr2";
+ gpios = <&gpio1 23 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led@3 {
+ label = "sl50:red:usr3";
+ gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+ };
+
+ backlight0: disp0 {
+ compatible = "pwm-backlight";
+ pwms = <&ehrpwm1 0 500000 0>;
+ brightness-levels = <0 10 20 30 40 50 60 70 80 90 99>;
+ default-brightness-level = <6>;
+ };
+
+ backlight1: disp1 {
+ compatible = "pwm-backlight";
+ pwms = <&ehrpwm1 1 500000 0>;
+ brightness-levels = <0 10 20 30 40 50 60 70 80 90 99>;
+ default-brightness-level = <6>;
+ };
+
+ sound {
+ compatible = "ti,da830-evm-audio";
+ ti,model = "AM335x-SL50";
+ ti,audio-codec = <&audio_codec>;
+ ti,mcasp-controller = <&mcasp0>;
+ ti,codec-clock-rate = <12000000>;
+ ti,audio-routing =
+ "Headphone Jack", "HPLOUT",
+ "Headphone Jack", "HPROUT",
+ "LINE1R", "Line In",
+ "LINE1L", "Line In";
+ };
+
+ emmc_pwrseq: pwrseq@0 {
+ compatible = "mmc-pwrseq-emmc";
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_pwrseq_pins>;
+ reset-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;
+ };
+
+ vmmcsd_fixed: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmcsd_fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+};
+
+&am33xx_pinmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&lwb_pins>;
+
+ led_pins: pinmux_led_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x854, PIN_OUTPUT | MUX_MODE7) /* gpmc_a5.gpio1_21 */
+ AM33XX_IOPAD(0x858, PIN_OUTPUT | MUX_MODE7) /* gpmc_a6.gpio1_22 */
+ AM33XX_IOPAD(0x85c, PIN_OUTPUT | MUX_MODE7) /* gpmc_a7.gpio1_23 */
+ AM33XX_IOPAD(0x860, PIN_OUTPUT | MUX_MODE7) /* gpmc_a8.gpio1_24 */
+ >;
+ };
+
+ uart0_pins: pinmux_uart0_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ >;
+ };
+
+ uart4_pins: pinmux_uart4_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE6) /* gpmc_wait0.uart4_rxd */
+ AM33XX_IOPAD(0x874, PIN_OUTPUT_PULLDOWN | MUX_MODE6) /* gpmc_wpn.uart4_txd */
+ >;
+ };
+
+ i2c0_pins: pinmux_i2c0_pins {
+ pinctrl-single,pins = <
+ 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 = <
+ AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE3) /* uart1_rxd.i2c1_sda */
+ AM33XX_IOPAD(0x984, PIN_INPUT_PULLUP | MUX_MODE3) /* uart1_txdi2c1_scl */
+ >;
+ };
+
+ i2c2_pins: pinmux_i2c2_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE3) /* uart1_ctsn.i2c2_sda */
+ AM33XX_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE3) /* uart1_rtsn.i2c2_scl */
+ >;
+ };
+
+ cpsw_default: cpsw_default {
+ pinctrl-single,pins = <
+ /* Slave 1 */
+ 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 */
+ 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 */
+ 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 */
+ AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+ >;
+ };
+
+ mmc1_pins: pinmux_mmc1_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+ >;
+ };
+
+ emmc_pwrseq_pins: pinmux_emmc_pwrseq_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_a4.gpio1_20 */
+ >;
+ };
+
+ emmc_pins: pinmux_emmc_pins {
+ pinctrl-single,pins = <
+ 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 */
+ >;
+ };
+
+ audio_pins: pinmux_audio_pins {
+ pinctrl-single,pins = <
+ 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(0x99c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2*/
+ >;
+ };
+
+ ehrpwm1_pins: pinmux_ehrpwm1a_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x848, PIN_OUTPUT | MUX_MODE6) /* gpmc_a2.ehrpwm1a */
+ AM33XX_IOPAD(0x84c, PIN_OUTPUT | MUX_MODE6) /* gpmc_a3.ehrpwm1b */
+ >;
+ };
+
+ lwb_pins: pinmux_lwb_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x9a4, PIN_OUTPUT | MUX_MODE7) /* SoundPA_en - mcasp0_fsr.gpio3_19 */
+ AM33XX_IOPAD(0x828, PIN_OUTPUT | MUX_MODE7) /* nKbdOnC - gpmc_ad10.gpio0_26 */
+ AM33XX_IOPAD(0x830, PIN_INPUT_PULLUP | MUX_MODE7) /* nKbdInt - gpmc_ad12.gpio1_12 */
+ AM33XX_IOPAD(0x834, PIN_INPUT_PULLUP | MUX_MODE7) /* nKbdReset - gpmc_ad13.gpio1_13 */
+ AM33XX_IOPAD(0x838, PIN_INPUT_PULLUP | MUX_MODE7) /* nDispReset - gpmc_ad14.gpio1_14 */
+ AM33XX_IOPAD(0x844, PIN_INPUT_PULLUP | MUX_MODE7) /* USB1_enPower - gpmc_a1.gpio1_17 */
+ /* AVR Programming - SPI Bus (bit bang) - Screen and Keyboard */
+ AM33XX_IOPAD(0x954, PIN_INPUT_PULLUP | MUX_MODE7) /* Kbd/Disp/BattMOSI spi0_d0.gpio0_3 */
+ AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE7) /* Kbd/Disp/BattMISO spi0_d1.gpio0_4 */
+ AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE7) /* Kbd/Disp/BattSCLK spi0_clk.gpio0_2 */
+ /* PDI Bus - Battery system */
+ AM33XX_IOPAD(0x840, PIN_INPUT_PULLUP | MUX_MODE7) /* nBattReset gpmc_a0.gpio1_16 */
+ AM33XX_IOPAD(0x83c, PIN_INPUT_PULLUP | MUX_MODE7) /* BattPDIData gpmc_ad15.gpio1_15 */
+ >;
+ };
+};
+
+&i2c0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+
+ clock-frequency = <400000>;
+
+ tps: tps@24 {
+ reg = <0x24>;
+ };
+
+ eeprom: eeprom@50 {
+ compatible = "at,24c256";
+ reg = <0x50>;
+ };
+};
+
+&i2c1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+};
+
+&i2c2 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+
+ clock-frequency = <400000>;
+
+ audio_codec: tlv320aic3106@1b {
+ status = "okay";
+ compatible = "ti,tlv320aic3106";
+ reg = <0x1b>;
+
+ AVDD-supply = <&ldo4_reg>;
+ IOVDD-supply = <&ldo4_reg>;
+ DRVDD-supply = <&ldo4_reg>;
+ DVDD-supply = <&ldo3_reg>;
+ };
+};
+
+&usb {
+ status = "okay";
+};
+
+&usb_ctrl_mod {
+ status = "okay";
+};
+
+&usb0_phy {
+ status = "okay";
+};
+
+&usb1_phy {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+ dr_mode = "peripheral";
+};
+
+&usb1 {
+ status = "okay";
+ dr_mode = "host";
+};
+
+&cppi41dma {
+ status = "okay";
+};
+
+&mmc1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+ bus-width = <4>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
+ vmmc-supply = <&vmmcsd_fixed>;
+};
+
+&mmc2 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_pins>;
+ bus-width = <8>;
+ vmmc-supply = <&vmmcsd_fixed>;
+ mmc-pwrseq = <&emmc_pwrseq>;
+};
+
+&mcasp0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&audio_pins>;
+
+ op-mode = <0>; /* MCASP_ISS_MODE */
+ tdm-slots = <2>;
+ serial-dir = <
+ 2 0 1 0
+ 0 0 0 0
+ 0 0 0 0
+ 0 0 0 0
+ >;
+ tx-num-evt = <1>;
+ rx-num-evt = <1>;
+};
+
+&uart0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins>;
+};
+
+&uart4 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins>;
+};
+
+#include "tps65217.dtsi"
+
+&tps {
+ ti,pmic-shutdown-controller;
+
+ interrupt-parent = <&intc>;
+ interrupts = <7>; /* NNMI */
+
+ regulators {
+ dcdc1_reg: regulator@0 {
+ /* VDDS_DDR */
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ };
+
+ dcdc2_reg: regulator@1 {
+ /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
+ regulator-name = "vdd_mpu";
+ regulator-min-microvolt = <925000>;
+ regulator-max-microvolt = <1325000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ dcdc3_reg: regulator@2 {
+ /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
+ regulator-name = "vdd_core";
+ regulator-min-microvolt = <925000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ ldo1_reg: regulator@3 {
+ /* VRTC / VIO / VDDS*/
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo2_reg: regulator@4 {
+ /* VDD_3V3AUX */
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo3_reg: regulator@5 {
+ /* VDD_1V8 */
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo4_reg: regulator@6 {
+ /* VDD_3V3A */
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+};
+
+&cpsw_emac0 {
+ phy_id = <&davinci_mdio>, <0>;
+ phy-mode = "mii";
+};
+
+&cpsw_emac1 {
+ phy_id = <&davinci_mdio>, <1>;
+ phy-mode = "mii";
+};
+
+&mac {
+ status = "okay";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&cpsw_default>;
+ pinctrl-1 = <&cpsw_sleep>;
+};
+
+&davinci_mdio {
+ status = "okay";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&davinci_mdio_default>;
+ pinctrl-1 = <&davinci_mdio_sleep>;
+};
+
+&sham {
+ status = "okay";
+};
+
+&aes {
+ status = "okay";
+};
+
+&epwmss1 {
+ status = "okay";
+};
+
+&ehrpwm1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&ehrpwm1_pins>;
+};
diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi
index f164dce08755..5e3f5e86ffcf 100644
--- a/arch/arm/boot/dts/am3517.dtsi
+++ b/arch/arm/boot/dts/am3517.dtsi
@@ -60,6 +60,17 @@
dma-names = "tx", "rx";
clock-frequency = <48000000>;
};
+
+ omap3_pmx_core2: pinmux@480025d8 {
+ compatible = "ti,omap3-padconf", "pinctrl-single";
+ reg = <0x480025d8 0x24>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ pinctrl-single,register-width = <16>;
+ pinctrl-single,function-mask = <0xff1f>;
+ };
};
};
diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts
index 26956cb50835..84aa30c3235a 100644
--- a/arch/arm/boot/dts/am437x-gp-evm.dts
+++ b/arch/arm/boot/dts/am437x-gp-evm.dts
@@ -21,6 +21,7 @@
aliases {
display0 = &lcd0;
+ serial3 = &uart3;
};
vmmcsd_fixed: fixedregulator-sd {
@@ -42,6 +43,15 @@
gpio = <&gpio5 7 GPIO_ACTIVE_HIGH>;
};
+ vmmcwl_fixed: fixedregulator-mmcwl {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmcwl_fixed";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ gpio = <&gpio1 20 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
backlight {
compatible = "pwm-backlight";
pwms = <&ecap0 0 50000 PWM_POLARITY_INVERTED>;
@@ -106,9 +116,21 @@
};
};
};
+
+ /* fixed 12MHz oscillator */
+ refclk: oscillator {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <12000000>;
+ };
+
};
&am43xx_pinmux {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&wlan_pins_default>;
+ pinctrl-1 = <&wlan_pins_sleep>;
+
i2c0_pins: i2c0_pins {
pinctrl-single,pins = <
0x188 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_sda.i2c0_sda */
@@ -340,6 +362,53 @@
0x204 (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 */
+ >;
+ };
+
+ 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 */
+ >;
+ };
+
+ 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*/
+ >;
+ };
+
+ 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*/
+ >;
+ };
+
+ 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 */
+ >;
+ };
};
&i2c0 {
@@ -403,6 +472,21 @@
regulator-always-on;
};
};
+
+ ov2659@30 {
+ compatible = "ovti,ov2659";
+ reg = <0x30>;
+
+ clocks = <&refclk 0>;
+ clock-names = "xvclk";
+
+ port {
+ ov2659_0: endpoint {
+ remote-endpoint = <&vpfe1_ep>;
+ link-frequencies = /bits/ 64 <70000000>;
+ };
+ };
+ };
};
&i2c1 {
@@ -422,6 +506,21 @@
touchscreen-size-x = <1024>;
touchscreen-size-y = <600>;
};
+
+ ov2659@30 {
+ compatible = "ovti,ov2659";
+ reg = <0x30>;
+
+ clocks = <&refclk 0>;
+ clock-names = "xvclk";
+
+ port {
+ ov2659_1: endpoint {
+ remote-endpoint = <&vpfe0_ep>;
+ link-frequencies = /bits/ 64 <70000000>;
+ };
+ };
+ };
};
&epwmss0 {
@@ -446,6 +545,10 @@
status = "okay";
};
+&gpio1 {
+ status = "okay";
+};
+
&gpio3 {
status = "okay";
};
@@ -468,6 +571,43 @@
cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
};
+&mmc3 {
+ status = "okay";
+ /* these are on the crossbar and are outlined in the
+ xbar-event-map element */
+ dmas = <&edma 30
+ &edma 31>;
+ dma-names = "tx", "rx";
+ vmmc-supply = <&vmmcwl_fixed>;
+ bus-width = <4>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&mmc3_pins_default>;
+ pinctrl-1 = <&mmc3_pins_sleep>;
+ cap-power-off-card;
+ keep-power-in-suspend;
+ ti,non-removable;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wlcore: wlcore@0 {
+ compatible = "ti,wl1835";
+ reg = <2>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
+ };
+};
+
+&edma {
+ ti,edma-xbar-event-map = /bits/ 16 <1 30
+ 2 31>;
+};
+
+&uart3 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
+};
+
&usb2_phy1 {
status = "okay";
};
@@ -625,7 +765,7 @@
port {
vpfe0_ep: endpoint {
- /* remote-endpoint = <&sensor>; add once we have it */
+ remote-endpoint = <&ov2659_1>;
ti,am437x-vpfe-interface = <0>;
bus-width = <8>;
hsync-active = <0>;
@@ -642,7 +782,7 @@
port {
vpfe1_ep: endpoint {
- /* remote-endpoint = <&sensor>; add once we have it */
+ remote-endpoint = <&ov2659_0>;
ti,am437x-vpfe-interface = <0>;
bus-width = <8>;
hsync-active = <0>;
diff --git a/arch/arm/boot/dts/am57xx-beagle-x15.dts b/arch/arm/boot/dts/am57xx-beagle-x15.dts
index 7128fad991ac..a42cc377a862 100644
--- a/arch/arm/boot/dts/am57xx-beagle-x15.dts
+++ b/arch/arm/boot/dts/am57xx-beagle-x15.dts
@@ -19,6 +19,7 @@
rtc0 = &mcp_rtc;
rtc1 = &tps659038_rtc;
rtc2 = &rtc;
+ display0 = &hdmi0;
};
memory {
@@ -103,6 +104,51 @@
pinctrl-names = "default";
pinctrl-0 = <&extcon_usb2_pins>;
};
+
+ hdmi0: connector {
+ compatible = "hdmi-connector";
+ label = "hdmi";
+
+ type = "a";
+
+ port {
+ hdmi_connector_in: endpoint {
+ remote-endpoint = <&tpd12s015_out>;
+ };
+ };
+ };
+
+ tpd12s015: encoder {
+ compatible = "ti,tpd12s015";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&tpd12s015_pins>;
+
+ gpios = <&gpio7 10 GPIO_ACTIVE_HIGH>, /* gpio7_10, CT CP HPD */
+ <&gpio6 28 GPIO_ACTIVE_HIGH>, /* gpio6_28, LS OE */
+ <&gpio7 12 GPIO_ACTIVE_HIGH>; /* gpio7_12/sp1_cs2, HPD */
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ tpd12s015_in: endpoint {
+ remote-endpoint = <&hdmi_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ tpd12s015_out: endpoint {
+ remote-endpoint = <&hdmi_connector_in>;
+ };
+ };
+ };
+ };
};
&dra7_pmx_core {
@@ -122,6 +168,13 @@
>;
};
+ 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 */
+ >;
+ };
+
i2c3_pins_default: i2c3_pins_default {
pinctrl-single,pins = <
0x2a4 (PIN_INPUT| MUX_MODE10) /* mcasp1_aclkx.i2c3_sda */
@@ -278,6 +331,14 @@
0x3e8 (PIN_INPUT_PULLUP | MUX_MODE14) /* uart1_ctsn.gpio7_24 */
>;
};
+
+ 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 */
+ >;
+ };
};
&i2c1 {
@@ -608,3 +669,23 @@
};
};
};
+
+&dss {
+ status = "ok";
+
+ vdda_video-supply = <&ldoln_reg>;
+};
+
+&hdmi {
+ status = "ok";
+ vdda-supply = <&ldo3_reg>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_pins>;
+
+ port {
+ hdmi_out: endpoint {
+ remote-endpoint = <&tpd12s015_in>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/arm-realview-pb1176.dts b/arch/arm/boot/dts/arm-realview-pb1176.dts
index ff26c7ed8c41..1bc64cda819e 100644
--- a/arch/arm/boot/dts/arm-realview-pb1176.dts
+++ b/arch/arm/boot/dts/arm-realview-pb1176.dts
@@ -114,7 +114,7 @@
ranges;
syscon: syscon@10000000 {
- compatible = "arm,realview-pb1176-syscon", "syscon";
+ compatible = "arm,realview-pb1176-syscon", "syscon", "simple-mfd";
reg = <0x10000000 0x1000>;
led@08.0 {
diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts
index 19f3bf271915..03542f7b5b94 100644
--- a/arch/arm/boot/dts/armada-370-db.dts
+++ b/arch/arm/boot/dts/armada-370-db.dts
@@ -162,7 +162,7 @@
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "mx25l25635e";
+ compatible = "mx25l25635e", "jedec,spi-nor";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <50000000>;
};
diff --git a/arch/arm/boot/dts/armada-370-dlink-dns327l.dts b/arch/arm/boot/dts/armada-370-dlink-dns327l.dts
new file mode 100644
index 000000000000..af4dc548c1c0
--- /dev/null
+++ b/arch/arm/boot/dts/armada-370-dlink-dns327l.dts
@@ -0,0 +1,357 @@
+/*
+ * Device Tree file for D-Link DNS-327L
+ *
+ * Copyright (C) 2015, Andrew Andrianov <andrew@ncrmnt.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
+ * 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.
+ */
+
+/* Remaining unsolved:
+ * There's still some unknown device on i2c address 0x13
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+#include "armada-370.dtsi"
+
+/ {
+ model = "D-Link DNS-327L";
+ compatible = "dlink,dns327l",
+ "marvell,armada370",
+ "marvell,armada-370-xp";
+
+ chosen {
+ stdout-path = &uart0;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x20000000>; /* 512 MiB */
+ };
+
+ soc {
+ ranges = <MBUS_ID(0xf0, 0x01) 0 0xd0000000 0x100000
+ MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+
+ pcie-controller {
+ status = "okay";
+
+ pcie@1,0 {
+ /* Port 0, Lane 0 */
+ status = "okay";
+ };
+
+ pcie@2,0 {
+ /* Port 1, Lane 0 */
+ status = "okay";
+ };
+ };
+
+ internal-regs {
+ sata@a0000 {
+ nr-ports = <2>;
+ status = "okay";
+ };
+
+ usb@50000 {
+ status = "okay";
+ };
+
+ nand@d0000 {
+ status = "okay";
+ num-cs = <1>;
+ marvell,nand-keep-config;
+ marvell,nand-enable-arbiter;
+ nand-on-flash-bbt;
+ nand-ecc-strength = <4>;
+ nand-ecc-step-size = <512>;
+
+ partition@0 {
+ label = "u-boot";
+ /* 1.0 MiB */
+ reg = <0x0000000 0x100000>;
+ read-only;
+ };
+
+ partition@100000 {
+ label = "u-boot-env";
+ /* 128 KiB */
+ reg = <0x100000 0x20000>;
+ read-only;
+ };
+
+ partition@120000 {
+ label = "uImage";
+ /* 7 MiB */
+ reg = <0x120000 0x700000>;
+ };
+
+ partition@820000 {
+ label = "ubifs";
+ /* ~ 84 MiB */
+ reg = <0x820000 0x54e0000>;
+ };
+
+ /* Hardcoded into stock bootloader */
+ partition@5d00000 {
+ label = "failsafe-uImage";
+ /* 5 MiB */
+ reg = <0x5d00000 0x500000>;
+ };
+
+ partition@6200000 {
+ label = "failsafe-fs";
+ /* 29 MiB */
+ reg = <0x6200000 0x1d00000>;
+ };
+
+ partition@7f00000 {
+ label = "bbt";
+ /* 1 MiB for BBT */
+ reg = <0x7f00000 0x100000>;
+ };
+ };
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-0 = <
+ &backup_button_pin
+ &power_button_pin
+ &reset_button_pin>;
+ pinctrl-names = "default";
+
+ power-button {
+ label = "Power Button";
+ linux,code = <KEY_POWER>;
+ gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
+ };
+
+ backup-button {
+ label = "Backup Button";
+ linux,code = <KEY_COPY>;
+ gpios = <&gpio1 31 GPIO_ACTIVE_LOW>;
+ };
+
+ reset-button {
+ label = "Reset Button";
+ linux,code = <KEY_RESTART>;
+ gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+ pinctrl-0 = <
+ &sata_l_amber_pin
+ &sata_r_amber_pin
+ &backup_led_pin
+ /* Ensure these are managed by hardware */
+ &sata_l_white_pin
+ &sata_r_white_pin>;
+
+ pinctrl-names = "default";
+
+ sata-r-amber-pin {
+ label = "dns327l:amber:sata-r";
+ gpios = <&gpio1 20 GPIO_ACTIVE_HIGH>;
+ default-state = "keep";
+ };
+
+ sata-l-amber-pin {
+ label = "dns327l:amber:sata-l";
+ gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
+ default-state = "keep";
+ };
+
+ backup-led-pin {
+ label = "dns327l:white:usb";
+ gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>;
+ default-state = "keep";
+ };
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ usb_power: regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ pinctrl-0 = <&xhci_pwr_pin>;
+ pinctrl-names = "default";
+ regulator-name = "USB3.0 Port Power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ regulator-boot-on;
+ regulator-always-on;
+ gpio = <&gpio0 13 GPIO_ACTIVE_HIGH>;
+ };
+
+ sata_r_power: regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ pinctrl-0 = <&sata_r_pwr_pin>;
+ pinctrl-names = "default";
+ regulator-name = "SATA-R Power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ startup-delay-us = <2000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>;
+ };
+
+ sata_l_power: regulator@3 {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ pinctrl-0 = <&sata_l_pwr_pin>;
+ pinctrl-names = "default";
+ regulator-name = "SATA-L Power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ startup-delay-us = <4000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 24 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
+
+&pinctrl {
+ sata_l_white_pin: sata-l-white-pin {
+ marvell,pins = "mpp57";
+ marvell,function = "sata0";
+ };
+
+ sata_r_white_pin: sata-r-white-pin {
+ marvell,pins = "mpp55";
+ marvell,function = "sata1";
+ };
+
+ sata_r_amber_pin: sata-r-amber-pin {
+ marvell,pins = "mpp52";
+ marvell,function = "gpio";
+ };
+
+ sata_l_amber_pin: sata-l-amber-pin {
+ marvell,pins = "mpp53";
+ marvell,function = "gpio";
+ };
+
+ backup_led_pin: backup-led-pin {
+ marvell,pins = "mpp61";
+ marvell,function = "gpo";
+ };
+
+ xhci_pwr_pin: xhci-pwr-pin {
+ marvell,pins = "mpp13";
+ marvell,function = "gpio";
+ };
+
+ sata_r_pwr_pin: sata-r-pwr-pin {
+ marvell,pins = "mpp54";
+ marvell,function = "gpio";
+ };
+
+ sata_l_pwr_pin: sata-l-pwr-pin {
+ marvell,pins = "mpp56";
+ marvell,function = "gpio";
+ };
+
+ uart1_pins: uart1-pins {
+ marvell,pins = "mpp60", "mpp61";
+ marvell,function = "uart1";
+ };
+
+ power_button_pin: power-button-pin {
+ marvell,pins = "mpp65";
+ marvell,function = "gpio";
+ };
+
+ backup_button_pin: backup-button-pin {
+ marvell,pins = "mpp63";
+ marvell,function = "gpio";
+ };
+
+ reset_button_pin: reset-button-pin {
+ marvell,pins = "mpp64";
+ marvell,function = "gpio";
+ };
+};
+
+/* Serial console */
+&uart0 {
+ status = "okay";
+};
+
+/* Connected to Weltrend MCU */
+&uart1 {
+ pinctrl-0 = <&uart1_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
+&mdio {
+ phy0: ethernet-phy@0 { /* Marvell 88E1318 */
+ reg = <0>;
+ marvell,reg-init = <0x0 0x16 0x0 0x0002>,
+ <0x0 0x19 0x0 0x0077>,
+ <0x0 0x18 0x0 0x5747>;
+ };
+};
+
+&eth1 {
+ phy = <&phy0>;
+ phy-mode = "rgmii-id";
+ status = "okay";
+};
+
+&i2c0 {
+ compatible = "marvell,mv64xxx-i2c";
+ clock-frequency = <100000>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/armada-370-synology-ds213j.dts b/arch/arm/boot/dts/armada-370-synology-ds213j.dts
index b42b767763aa..4f4924362bf0 100644
--- a/arch/arm/boot/dts/armada-370-synology-ds213j.dts
+++ b/arch/arm/boot/dts/armada-370-synology-ds213j.dts
@@ -92,7 +92,7 @@
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "micron,n25q064";
+ compatible = "micron,n25q064", "jedec,spi-nor";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <20000000>;
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index ec96f0b36346..7f0252c580e4 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -149,7 +149,6 @@
};
spi0: spi@10600 {
- compatible = "marvell,armada-370-spi", "marvell,orion-spi";
reg = <0x10600 0x28>;
#address-cells = <1>;
#size-cells = <0>;
@@ -160,7 +159,6 @@
};
spi1: spi@10680 {
- compatible = "marvell,armada-370-spi", "marvell,orion-spi";
reg = <0x10680 0x28>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index 00b50db57c9c..3f036bd635f4 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -139,11 +139,15 @@
* board level if a different configuration is used.
*/
spi0: spi@10600 {
+ compatible = "marvell,armada-370-spi",
+ "marvell,orion-spi";
pinctrl-0 = <&spi0_pins1>;
pinctrl-names = "default";
};
spi1: spi@10680 {
+ compatible = "marvell,armada-370-spi",
+ "marvell,orion-spi";
pinctrl-0 = <&spi1_pins>;
pinctrl-names = "default";
};
diff --git a/arch/arm/boot/dts/armada-375-db.dts b/arch/arm/boot/dts/armada-375-db.dts
index 4eabc9c21f8d..5711b97e876c 100644
--- a/arch/arm/boot/dts/armada-375-db.dts
+++ b/arch/arm/boot/dts/armada-375-db.dts
@@ -81,7 +81,7 @@
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "n25q128a13";
+ compatible = "n25q128a13", "jedec,spi-nor";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <108000000>;
};
diff --git a/arch/arm/boot/dts/armada-375.dtsi b/arch/arm/boot/dts/armada-375.dtsi
index f076ff856d8b..67a0ab0f71e0 100644
--- a/arch/arm/boot/dts/armada-375.dtsi
+++ b/arch/arm/boot/dts/armada-375.dtsi
@@ -238,7 +238,8 @@
};
spi0: spi@10600 {
- compatible = "marvell,orion-spi";
+ compatible = "marvell,armada-375-spi",
+ "marvell,orion-spi";
reg = <0x10600 0x50>;
#address-cells = <1>;
#size-cells = <0>;
@@ -249,7 +250,8 @@
};
spi1: spi@10680 {
- compatible = "marvell,orion-spi";
+ compatible = "marvell,armada-375-spi",
+ "marvell,orion-spi";
reg = <0x10680 0x50>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/armada-385-db-ap.dts b/arch/arm/boot/dts/armada-385-db-ap.dts
index 7219ac3a3d90..89f5a95954ed 100644
--- a/arch/arm/boot/dts/armada-385-db-ap.dts
+++ b/arch/arm/boot/dts/armada-385-db-ap.dts
@@ -70,7 +70,7 @@
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "st,m25p128";
+ compatible = "st,m25p128", "jedec,spi-nor";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <54000000>;
};
diff --git a/arch/arm/boot/dts/armada-385-linksys-caiman.dts b/arch/arm/boot/dts/armada-385-linksys-caiman.dts
new file mode 100644
index 000000000000..f3cee918d285
--- /dev/null
+++ b/arch/arm/boot/dts/armada-385-linksys-caiman.dts
@@ -0,0 +1,114 @@
+/*
+ * Device Tree include for the Linksys WRT1200AC (Caiman)
+ *
+ * Copyright (C) 2015 Imre Kaloz <kaloz@openwrt.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
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) 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.
+ *
+ * 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 "armada-385-linksys.dtsi"
+
+/ {
+ model = "Linksys WRT1200AC";
+ compatible = "linksys,caiman", "linksys,armada385", "marvell,armada385",
+ "marvell,armada380";
+
+ soc {
+ internal-regs{
+ i2c@11000 {
+
+ pca9635@68 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wan_amber@0 {
+ label = "caiman:amber:wan";
+ reg = <0x0>;
+ };
+
+ wan_white@1 {
+ label = "caiman:white:wan";
+ reg = <0x1>;
+ };
+
+ wlan_2g@2 {
+ label = "caiman:white:wlan_2g";
+ reg = <0x2>;
+ };
+
+ wlan_5g@3 {
+ label = "caiman:white:wlan_5g";
+ reg = <0x3>;
+ };
+
+ usb2@5 {
+ label = "caiman:white:usb2";
+ reg = <0x5>;
+ };
+
+ usb3_1@6 {
+ label = "caiman:white:usb3_1";
+ reg = <0x6>;
+ };
+
+ usb3_2@7 {
+ label = "caiman:white:usb3_2";
+ reg = <0x7>;
+ };
+
+ wps_white@8 {
+ label = "caiman:white:wps";
+ reg = <0x8>;
+ };
+
+ wps_amber@9 {
+ label = "caiman:amber:wps";
+ reg = <0x9>;
+ };
+ };
+ };
+ };
+ };
+
+ gpio-leds {
+ power {
+ label = "caiman:white:power";
+ };
+
+ sata {
+ label = "caiman:white:sata";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-385-linksys-cobra.dts b/arch/arm/boot/dts/armada-385-linksys-cobra.dts
new file mode 100644
index 000000000000..111071860559
--- /dev/null
+++ b/arch/arm/boot/dts/armada-385-linksys-cobra.dts
@@ -0,0 +1,114 @@
+/*
+ * Device Tree file for the Linksys WRT1900ACv2 (Cobra)
+ *
+ * Copyright (C) 2015 Imre Kaloz <kaloz@openwrt.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
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) 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.
+ *
+ * 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 "armada-385-linksys.dtsi"
+
+/ {
+ model = "Linksys WRT1900ACv2";
+ compatible = "linksys,cobra", "linksys,armada385", "marvell,armada385",
+ "marvell,armada380";
+
+ soc {
+ internal-regs{
+ i2c@11000 {
+
+ pca9635@68 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wan_amber@0 {
+ label = "cobra:amber:wan";
+ reg = <0x0>;
+ };
+
+ wan_white@1 {
+ label = "cobra:white:wan";
+ reg = <0x1>;
+ };
+
+ wlan_2g@2 {
+ label = "cobra:white:wlan_2g";
+ reg = <0x2>;
+ };
+
+ wlan_5g@3 {
+ label = "cobra:white:wlan_5g";
+ reg = <0x3>;
+ };
+
+ usb2@5 {
+ label = "cobra:white:usb2";
+ reg = <0x5>;
+ };
+
+ usb3_1@6 {
+ label = "cobra:white:usb3_1";
+ reg = <0x6>;
+ };
+
+ usb3_2@7 {
+ label = "cobra:white:usb3_2";
+ reg = <0x7>;
+ };
+
+ wps_white@8 {
+ label = "cobra:white:wps";
+ reg = <0x8>;
+ };
+
+ wps_amber@9 {
+ label = "cobra:amber:wps";
+ reg = <0x9>;
+ };
+ };
+ };
+ };
+ };
+
+ gpio-leds {
+ power {
+ label = "cobra:white:power";
+ };
+
+ sata {
+ label = "cobra:white:sata";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-385-linksys.dtsi b/arch/arm/boot/dts/armada-385-linksys.dtsi
new file mode 100644
index 000000000000..74a9c6b54fa7
--- /dev/null
+++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
@@ -0,0 +1,332 @@
+/*
+ * Device Tree include file for Armada 385 based Linksys boards
+ *
+ * Copyright (C) 2015 Imre Kaloz <kaloz@openwrt.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
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) 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.
+ *
+ * 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/input/input.h>
+#include "armada-385.dtsi"
+
+/ {
+ model = "Linksys boards based on Armada 385";
+ compatible = "linksys,armada385", "marvell,armada385",
+ "marvell,armada380";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x20000000>; /* 512 MB */
+ };
+
+ soc {
+ ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
+ MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+
+ internal-regs {
+
+ spi@10600 {
+ status = "disabled";
+ };
+
+ i2c@11000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ status = "okay";
+
+ tmp421@4c {
+ compatible = "ti,tmp421";
+ reg = <0x4c>;
+ };
+
+ pca9635@68 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "nxp,pca9635";
+ reg = <0x68>;
+ };
+ };
+
+ /* J10: VCC, NC, RX, NC, TX, GND */
+ serial@12000 {
+ status = "okay";
+ };
+
+ ethernet@70000 {
+ status = "okay";
+ phy-mode = "rgmii-id";
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+
+ ethernet@34000 {
+ status = "okay";
+ phy-mode = "sgmii";
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+
+ mdio {
+ status = "okay";
+ };
+
+ sata@a8000 {
+ status = "okay";
+ };
+
+ /* USB part of the eSATA/USB 2.0 port */
+ usb@50000 {
+ status = "okay";
+ };
+
+ usb3@f8000 {
+ status = "okay";
+ usb-phy = <&usb3_phy>;
+ };
+
+ flash@d0000 {
+ status = "okay";
+ num-cs = <1>;
+ marvell,nand-keep-config;
+ marvell,nand-enable-arbiter;
+ nand-on-flash-bbt;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x0000000 0x200000>; /* 2MB */
+ read-only;
+ };
+
+ partition@100000 {
+ label = "u_env";
+ reg = <0x200000 0x40000>; /* 256KB */
+ };
+
+ partition@140000 {
+ label = "s_env";
+ reg = <0x240000 0x40000>; /* 256KB */
+ };
+
+ partition@900000 {
+ label = "devinfo";
+ reg = <0x900000 0x100000>; /* 1MB */
+ read-only;
+ };
+
+ /* kernel1 overlaps with rootfs1 by design */
+ partition@a00000 {
+ label = "kernel1";
+ reg = <0xa00000 0x2800000>; /* 40MB */
+ };
+
+ partition@1000000 {
+ label = "rootfs1";
+ reg = <0x1000000 0x2200000>; /* 34MB */
+ };
+
+ /* kernel2 overlaps with rootfs2 by design */
+ partition@3200000 {
+ label = "kernel2";
+ reg = <0x3200000 0x2800000>; /* 40MB */
+ };
+
+ partition@3800000 {
+ label = "rootfs2";
+ reg = <0x3800000 0x2200000>; /* 34MB */
+ };
+
+ /*
+ * 38MB, last MB is for the BBT, not writable
+ */
+ partition@5a00000 {
+ label = "syscfg";
+ reg = <0x5a00000 0x2600000>;
+ };
+
+ /*
+ * Unused area between "s_env" and "devinfo".
+ * Moved here because otherwise the renumbered
+ * partitions would break the bootloader
+ * supplied bootargs
+ */
+ partition@180000 {
+ label = "unused_area";
+ reg = <0x280000 0x680000>; /* 6.5MB */
+ };
+ };
+ };
+
+ pcie-controller {
+ status = "okay";
+
+ pcie@1,0 {
+ /* Marvell 88W8864, 5GHz-only */
+ status = "okay";
+ };
+
+ pcie@2,0 {
+ /* Marvell 88W8864, 2GHz-only */
+ status = "okay";
+ };
+ };
+ };
+
+ usb3_phy: usb3_phy {
+ compatible = "usb-nop-xceiv";
+ vcc-supply = <&reg_xhci0_vbus>;
+ };
+
+ reg_xhci0_vbus: xhci0-vbus {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&xhci0_vbus_pins>;
+ regulator-name = "xhci0-vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ gpio = <&gpio1 18 GPIO_ACTIVE_HIGH>;
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-0 = <&keys_pin>;
+ pinctrl-names = "default";
+
+ button@1 {
+ label = "WPS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&gpio0 24 GPIO_ACTIVE_LOW>;
+ };
+
+ button@2 {
+ label = "Factory Reset Button";
+ linux,code = <KEY_RESTART>;
+ gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+ pinctrl-0 = <&power_led_pin &sata_led_pin>;
+ pinctrl-names = "default";
+
+ power {
+ gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
+ };
+
+ sata {
+ gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+ };
+
+ dsa@0 {
+ compatible = "marvell,dsa";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ dsa,ethernet = <&eth2>;
+ dsa,mii-bus = <&mdio>;
+
+ switch@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0>; /* MDIO address 0, switch 0 in tree */
+
+ port@0 {
+ reg = <0>;
+ label = "lan4";
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "lan3";
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "lan2";
+ };
+
+ port@3 {
+ reg = <3>;
+ label = "lan1";
+ };
+
+ port@4 {
+ reg = <4>;
+ label = "wan";
+ };
+
+ port@5 {
+ reg = <5>;
+ label = "cpu";
+ };
+ };
+ };
+};
+
+&pinctrl {
+ keys_pin: keys-pin {
+ marvell,pins = "mpp24", "mpp47";
+ marvell,function = "gpio";
+ };
+
+ power_led_pin: power-led-pin {
+ marvell,pins = "mpp55";
+ marvell,function = "gpio";
+ };
+
+ sata_led_pin: sata-led-pin {
+ marvell,pins = "mpp54";
+ marvell,function = "gpio";
+ };
+
+ xhci0_vbus_pins: xhci0-vbus-pins {
+ marvell,pins = "mpp50";
+ marvell,function = "gpio";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-388-db.dts b/arch/arm/boot/dts/armada-388-db.dts
index 51d1623de53e..91ac8c118f37 100644
--- a/arch/arm/boot/dts/armada-388-db.dts
+++ b/arch/arm/boot/dts/armada-388-db.dts
@@ -73,7 +73,7 @@
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "w25q32";
+ compatible = "w25q32", "jedec,spi-nor";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <108000000>;
};
diff --git a/arch/arm/boot/dts/armada-388-gp.dts b/arch/arm/boot/dts/armada-388-gp.dts
index 78514ab0b47a..fd4f6fd8a2e8 100644
--- a/arch/arm/boot/dts/armada-388-gp.dts
+++ b/arch/arm/boot/dts/armada-388-gp.dts
@@ -69,7 +69,7 @@
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "st,m25p128";
+ compatible = "st,m25p128", "jedec,spi-nor";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <50000000>;
m25p,fast-read;
diff --git a/arch/arm/boot/dts/armada-388-rd.dts b/arch/arm/boot/dts/armada-388-rd.dts
index 1dc6e2341cc2..b657b1687e5f 100644
--- a/arch/arm/boot/dts/armada-388-rd.dts
+++ b/arch/arm/boot/dts/armada-388-rd.dts
@@ -74,7 +74,7 @@
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "st,m25p128";
+ compatible = "st,m25p128", "jedec,spi-nor";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <108000000>;
};
diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi
index 218a2acd36e5..04ecfe6e2bc6 100644
--- a/arch/arm/boot/dts/armada-38x.dtsi
+++ b/arch/arm/boot/dts/armada-38x.dtsi
@@ -167,7 +167,8 @@
};
spi0: spi@10600 {
- compatible = "marvell,orion-spi";
+ compatible = "marvell,armada-380-spi",
+ "marvell,orion-spi";
reg = <0x10600 0x50>;
#address-cells = <1>;
#size-cells = <0>;
@@ -178,7 +179,8 @@
};
spi1: spi@10680 {
- compatible = "marvell,orion-spi";
+ compatible = "marvell,armada-380-spi",
+ "marvell,orion-spi";
reg = <0x10680 0x50>;
#address-cells = <1>;
#size-cells = <0>;
@@ -495,7 +497,7 @@
status = "disabled";
};
- mdio@72004 {
+ mdio: mdio@72004 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "marvell,orion-mdio";
diff --git a/arch/arm/boot/dts/armada-398-db.dts b/arch/arm/boot/dts/armada-398-db.dts
index bbf83756c43c..788c3badb681 100644
--- a/arch/arm/boot/dts/armada-398-db.dts
+++ b/arch/arm/boot/dts/armada-398-db.dts
@@ -73,7 +73,7 @@
spi-flash@0 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "n25q128a13";
+ compatible = "n25q128a13", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <108000000>;
diff --git a/arch/arm/boot/dts/armada-39x.dtsi b/arch/arm/boot/dts/armada-39x.dtsi
index ecd1318109ba..fc9864f85fc2 100644
--- a/arch/arm/boot/dts/armada-39x.dtsi
+++ b/arch/arm/boot/dts/armada-39x.dtsi
@@ -128,7 +128,8 @@
};
spi0: spi@10600 {
- compatible = "marvell,orion-spi";
+ compatible = "marvell,armada-390-spi",
+ "marvell,orion-spi";
reg = <0x10600 0x50>;
#address-cells = <1>;
#size-cells = <0>;
@@ -139,7 +140,8 @@
};
spi1: spi@10680 {
- compatible = "marvell,orion-spi";
+ compatible = "marvell,armada-390-spi",
+ "marvell,orion-spi";
reg = <0x10680 0x50>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/armada-xp-axpwifiap.dts b/arch/arm/boot/dts/armada-xp-axpwifiap.dts
index dfd782b44e50..60bbfe32bb80 100644
--- a/arch/arm/boot/dts/armada-xp-axpwifiap.dts
+++ b/arch/arm/boot/dts/armada-xp-axpwifiap.dts
@@ -140,7 +140,7 @@
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "n25q128a13";
+ compatible = "n25q128a13", "jedec,spi-nor";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <108000000>;
};
diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts
index 103782407618..7dd900f158be 100644
--- a/arch/arm/boot/dts/armada-xp-db.dts
+++ b/arch/arm/boot/dts/armada-xp-db.dts
@@ -222,7 +222,7 @@
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "m25p64";
+ compatible = "m25p64", "jedec,spi-nor";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <20000000>;
};
diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts
index 565227eacf06..bf724ca96a33 100644
--- a/arch/arm/boot/dts/armada-xp-gp.dts
+++ b/arch/arm/boot/dts/armada-xp-gp.dts
@@ -227,7 +227,7 @@
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "n25q128a13";
+ compatible = "n25q128a13", "jedec,spi-nor";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <108000000>;
};
diff --git a/arch/arm/boot/dts/armada-xp-synology-ds414.dts b/arch/arm/boot/dts/armada-xp-synology-ds414.dts
index 6063428fa6a0..20267ad2f61e 100644
--- a/arch/arm/boot/dts/armada-xp-synology-ds414.dts
+++ b/arch/arm/boot/dts/armada-xp-synology-ds414.dts
@@ -114,7 +114,7 @@
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "micron,n25q064";
+ compatible = "micron,n25q064", "jedec,spi-nor";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <20000000>;
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index 013d63f69e36..e78ce4ab6b75 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -85,10 +85,18 @@
};
spi0: spi@10600 {
+ compatible = "marvell,armada-xp-spi",
+ "marvell,orion-spi";
pinctrl-0 = <&spi0_pins>;
pinctrl-names = "default";
};
+ spi1: spi@10680 {
+ compatible = "marvell,armada-xp-spi",
+ "marvell,orion-spi";
+ };
+
+
i2c0: i2c@11000 {
compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c";
reg = <0x11000 0x100>;
diff --git a/arch/arm/boot/dts/armv7-m.dtsi b/arch/arm/boot/dts/armv7-m.dtsi
index 5a660d0faf42..b1ad7cf6ac02 100644
--- a/arch/arm/boot/dts/armv7-m.dtsi
+++ b/arch/arm/boot/dts/armv7-m.dtsi
@@ -8,6 +8,12 @@
reg = <0xe000e100 0xc00>;
};
+ systick: timer@e000e010 {
+ compatible = "arm,armv7m-systick";
+ reg = <0xe000e010 0x10>;
+ status = "disabled";
+ };
+
soc {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/at91-ariettag25.dts b/arch/arm/boot/dts/at91-ariettag25.dts
new file mode 100644
index 000000000000..c514502081d2
--- /dev/null
+++ b/arch/arm/boot/dts/at91-ariettag25.dts
@@ -0,0 +1,79 @@
+/*
+ * Device Tree file for Arietta G25
+ * This device tree is minimal, to activate more peripherals, see:
+ * http://dts.acmesystems.it/arietta/
+ */
+/dts-v1/;
+#include "at91sam9g25.dtsi"
+/ {
+ model = "Acme Systems Arietta G25";
+ compatible = "acme,ariettag25", "atmel,at91sam9x5", "atmel,at91sam9";
+
+ aliases {
+ serial0 = &dbgu;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ reg = <0x20000000 0x8000000>;
+ };
+
+ clocks {
+ slow_xtal {
+ clock-frequency = <32768>;
+ };
+
+ main_xtal {
+ clock-frequency = <12000000>;
+ };
+ };
+
+ ahb {
+ apb {
+ mmc0: mmc@f0008000 {
+ pinctrl-0 = <
+ &pinctrl_mmc0_slot0_clk_cmd_dat0
+ &pinctrl_mmc0_slot0_dat1_3>;
+ status = "okay";
+
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ };
+ };
+
+ usb2: gadget@f803c000 {
+ status = "okay";
+ };
+
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+
+ rtc@fffffeb0 {
+ status = "okay";
+ };
+ };
+
+ usb0: ohci@00600000 {
+ status = "okay";
+ num-ports = <3>;
+ };
+
+ usb1: ehci@00700000 {
+ status = "okay";
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ arietta_led {
+ label = "arietta_led";
+ gpios = <&pioB 8 GPIO_ACTIVE_HIGH>; /* PB8 */
+ linux,default-trigger = "heartbeat";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91-kizbox.dts b/arch/arm/boot/dts/at91-kizbox.dts
new file mode 100644
index 000000000000..bf18ece0c027
--- /dev/null
+++ b/arch/arm/boot/dts/at91-kizbox.dts
@@ -0,0 +1,159 @@
+/*
+ * at91-kizbox.dts - Device Tree file for Overkiz Kizbox board
+ *
+ * Copyright (C) 2012-2014 Boris BREZILLON <b.brezillon@overkiz.com>
+ * 2014-2015 Gaël PORTAY <g.portay@overkiz.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+#include "at91sam9g20.dtsi"
+#include <dt-bindings/pwm/pwm.h>
+
+/ {
+ model = "Overkiz Kizbox";
+ compatible = "overkiz,kizbox", "atmel,at91sam9g20", "atmel,at91sam9";
+
+ chosen {
+ bootargs = "ubi.mtd=ubi";
+ stdout-path = &dbgu;
+ };
+
+ memory {
+ reg = <0x20000000 0x2000000>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ main_clock: clock@0 {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <18432000>;
+ };
+
+ main_xtal {
+ clock-frequency = <18432000>;
+ };
+ };
+
+ ahb {
+ apb {
+ macb0: ethernet@fffc4000 {
+ phy-mode = "mii";
+ pinctrl-0 = <&pinctrl_macb_rmii
+ &pinctrl_macb_rmii_mii_alt>;
+ status = "okay";
+ };
+
+ usart3: serial@fffd0000 {
+ status = "okay";
+ };
+
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+
+ watchdog@fffffd40 {
+ timeout-sec = <15>;
+ atmel,max-heartbeat-sec = <16>;
+ atmel,min-heartbeat-sec = <0>;
+ status = "okay";
+ };
+ };
+
+ usb0: ohci@00500000 {
+ num-ports = <1>;
+ status = "okay";
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "soft";
+ status = "okay";
+
+ bootstrap@0 {
+ label = "bootstrap";
+ reg = <0x0 0x20000>;
+ };
+
+ ubi@20000 {
+ label = "ubi";
+ reg = <0x20000 0x7fe0000>;
+ };
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reset {
+ label = "PB_RST";
+ gpios = <&pioB 30 GPIO_ACTIVE_HIGH>;
+ linux,code = <0x100>;
+ gpio-key,wakeup;
+ };
+
+ user {
+ label = "PB_USER";
+ gpios = <&pioB 31 GPIO_ACTIVE_HIGH>;
+ linux,code = <0x101>;
+ gpio-key,wakeup;
+ };
+ };
+
+ i2c@0 {
+ status = "okay";
+
+ rtc: pcf8563@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+ };
+
+ pwm_leds {
+ compatible = "pwm-leds";
+
+ network_green {
+ label = "pwm:green:network";
+ pwms = <&tcb_pwm 2 10000000 PWM_POLARITY_INVERTED>;
+ max-brightness = <255>;
+ linux,default-trigger = "default-on";
+ };
+
+ network_red {
+ label = "pwm:red:network";
+ pwms = <&tcb_pwm 4 10000000 PWM_POLARITY_INVERTED>;
+ max-brightness = <255>;
+ linux,default-trigger = "default-on";
+ };
+
+ user_green {
+ label = "pwm:green:user";
+ pwms = <&tcb_pwm 0 10000000 PWM_POLARITY_INVERTED>;
+ max-brightness = <255>;
+ linux,default-trigger = "default-on";
+ };
+
+ user_red {
+ label = "pwm:red:user";
+ pwms = <&tcb_pwm 1 10000000 PWM_POLARITY_INVERTED>;
+ max-brightness = <255>;
+ linux,default-trigger = "default-on";
+ };
+ };
+
+ tcb_pwm: pwm {
+ compatible = "atmel,tcb-pwm";
+ #pwm-cells = <3>;
+ tc-block = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_tcb1_tioa0
+ &pinctrl_tcb1_tioa1
+ &pinctrl_tcb1_tioa2
+ &pinctrl_tcb1_tiob0>;
+ };
+};
diff --git a/arch/arm/boot/dts/at91-kizbox2.dts b/arch/arm/boot/dts/at91-kizbox2.dts
new file mode 100644
index 000000000000..f0b1563cb3f1
--- /dev/null
+++ b/arch/arm/boot/dts/at91-kizbox2.dts
@@ -0,0 +1,216 @@
+/*
+ * at91-kizbox2.dts - Device Tree file for Overkiz Kizbox 2 board
+ *
+ * Copyright (C) 2014 Gaël PORTAY <g.portay@overkiz.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+#include "sama5d31.dtsi"
+#include <dt-bindings/pwm/pwm.h>
+
+/ {
+ model = "Overkiz Kizbox 2";
+ compatible = "overkiz,kizbox2", "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5";
+
+ chosen {
+ bootargs = "ubi.mtd=ubi";
+ stdout-path = &dbgu;
+ };
+
+ memory {
+ reg = <0x20000000 0x10000000>;
+ };
+
+ clocks {
+ slow_xtal {
+ clock-frequency = <32768>;
+ };
+
+ main_xtal {
+ clock-frequency = <12000000>;
+ };
+ };
+
+ ahb {
+ apb {
+ i2c1: i2c@f0018000 {
+ status = "okay";
+
+ pmic: act8865@5b {
+ compatible = "active-semi,act8865";
+ reg = <0x5b>;
+ status = "okay";
+
+ regulators {
+ vcc_1v8_reg: DCDC_REG1 {
+ regulator-name = "VCC_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ vcc_1v2_reg: DCDC_REG2 {
+ regulator-name = "VCC_1V2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ vcc_3v3_reg: DCDC_REG3 {
+ regulator-name = "VCC_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vddfuse_reg: LDO_REG1 {
+ regulator-name = "FUSE_2V5";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ };
+
+ vddana_reg: LDO_REG2 {
+ regulator-name = "VDDANA";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vled_reg: LDO_REG3 {
+ regulator-name = "VLED";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ v3v8_rf_reg: LDO_REG4 {
+ regulator-name = "V3V8_RF";
+ regulator-min-microvolt = <3800000>;
+ regulator-max-microvolt = <3800000>;
+ regulator-always-on;
+ };
+ };
+ };
+ };
+
+ usart0: serial@f001c000 {
+ status = "okay";
+ };
+
+ usart1: serial@f0020000 {
+ status = "okay";
+ };
+
+ pwm0: pwm@f002c000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm0_pwmh0_1
+ &pinctrl_pwm0_pwmh1_1
+ &pinctrl_pwm0_pwmh2_0>;
+ status = "okay";
+ };
+
+ adc0: adc@f8018000 {
+ atmel,adc-vref = <3333>;
+ status = "okay";
+ };
+
+ usart2: serial@f8020000 {
+ status = "okay";
+ };
+
+ macb1: ethernet@f802c000 {
+ phy-mode = "rmii";
+ status = "okay";
+ };
+
+ dbgu: serial@ffffee00 {
+ status = "okay";
+ };
+
+ watchdog@fffffe40 {
+ status = "okay";
+ };
+ };
+
+ usb1: ohci@00600000 {
+ status = "okay";
+ };
+
+ usb2: ehci@00700000 {
+ status = "okay";
+ };
+
+ nand0: nand@60000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "hw";
+ atmel,has-pmecc;
+ atmel,pmecc-cap = <4>;
+ atmel,pmecc-sector-size = <512>;
+ nand-on-flash-bbt;
+ status = "okay";
+
+ bootstrap@0 {
+ label = "bootstrap";
+ reg = <0x0 0x20000>;
+ };
+
+ ubi@20000 {
+ label = "ubi";
+ reg = <0x20000 0x7fe0000>;
+ };
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ prog {
+ label = "PB_PROG";
+ gpios = <&pioE 27 GPIO_ACTIVE_LOW>;
+ linux,code = <0x102>;
+ gpio-key,wakeup;
+ };
+
+ reset {
+ label = "PB_RST";
+ gpios = <&pioE 29 GPIO_ACTIVE_LOW>;
+ linux,code = <0x100>;
+ gpio-key,wakeup;
+ };
+
+ user {
+ label = "PB_USER";
+ gpios = <&pioE 31 GPIO_ACTIVE_HIGH>;
+ linux,code = <0x101>;
+ gpio-key,wakeup;
+ };
+ };
+
+ pwm_leds {
+ compatible = "pwm-leds";
+
+ blue {
+ label = "pwm:blue:user";
+ pwms = <&pwm0 2 10000000 0>;
+ max-brightness = <255>;
+ linux,default-trigger = "default-on";
+ };
+
+ green {
+ label = "pwm:green:user";
+ pwms = <&pwm0 1 10000000 0>;
+ max-brightness = <255>;
+ linux,default-trigger = "default-on";
+ };
+
+ red {
+ label = "pwm:red:user";
+ pwms = <&pwm0 0 10000000 0>;
+ max-brightness = <255>;
+ linux,default-trigger = "default-on";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91-kizboxmini.dts b/arch/arm/boot/dts/at91-kizboxmini.dts
new file mode 100644
index 000000000000..9f72b4932634
--- /dev/null
+++ b/arch/arm/boot/dts/at91-kizboxmini.dts
@@ -0,0 +1,129 @@
+/*
+ * at91-kizboxmini.dts - Device Tree file for Overkiz Kizbox mini board
+ *
+ * Copyright (C) 2014 Gaël PORTAY <g.portay@overkiz.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+#include "at91sam9g25.dtsi"
+#include <dt-bindings/pwm/pwm.h>
+
+/ {
+ model = "Overkiz Kizbox mini";
+ compatible = "overkiz,kizboxmini", "atmel,at91sam9g25", "atmel,at91sam9x5", "atmel,at91sam9";
+
+ chosen {
+ bootargs = "ubi.mtd=ubi";
+ stdout-path = &dbgu;
+ };
+
+ memory {
+ reg = <0x20000000 0x8000000>;
+ };
+
+ clocks {
+ slow_xtal {
+ clock-frequency = <32768>;
+ };
+
+ main_xtal {
+ clock-frequency = <12000000>;
+ };
+ };
+
+ ahb {
+ apb {
+ usart0: serial@f801c000 {
+ status = "okay";
+ };
+
+ macb0: ethernet@f802c000 {
+ phy-mode = "rmii";
+ status = "okay";
+ };
+
+ pwm0: pwm@f8034000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm0_pwm0_1
+ &pinctrl_pwm0_pwm1_1>;
+ status = "okay";
+ };
+
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+
+ watchdog@fffffe40 {
+ status = "okay";
+ };
+ };
+
+ usb0: ohci@00600000 {
+ num-ports = <1>;
+ status = "okay";
+ };
+
+ usb1: ehci@00700000 {
+ status = "okay";
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "hw";
+ atmel,has-pmecc;
+ atmel,pmecc-cap = <4>;
+ atmel,pmecc-sector-size = <512>;
+ nand-on-flash-bbt;
+ status = "okay";
+
+ bootstrap@0 {
+ label = "bootstrap";
+ reg = <0x0 0x20000>;
+ };
+
+ ubi@20000 {
+ label = "ubi";
+ reg = <0x20000 0x7fe0000>;
+ };
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ prog {
+ label = "PB_PROG";
+ gpios = <&pioC 17 GPIO_ACTIVE_LOW>;
+ linux,code = <0x102>;
+ gpio-key,wakeup;
+ };
+
+ reset {
+ label = "PB_RST";
+ gpios = <&pioC 16 GPIO_ACTIVE_LOW>;
+ linux,code = <0x100>;
+ gpio-key,wakeup;
+ };
+ };
+
+ pwm_leds {
+ compatible = "pwm-leds";
+
+ green {
+ label = "pwm:green:user";
+ pwms = <&pwm0 0 10000000 0>;
+ max-brightness = <255>;
+ linux,default-trigger = "default-on";
+ };
+
+ red {
+ label = "pwm:red:user";
+ pwms = <&pwm0 1 10000000 0>;
+ max-brightness = <255>;
+ linux,default-trigger = "default-on";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts
index 9991240b7438..d81474e0bcd6 100644
--- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts
@@ -14,7 +14,7 @@
compatible = "atmel,sama5d3-xplained", "atmel,sama5d3", "atmel,sama5";
chosen {
- bootargs = "console=ttyS0,115200";
+ stdout-path = "serial0:115200n8";
};
memory {
@@ -35,6 +35,8 @@
apb {
mmc0: mmc@f0000000 {
pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_dat4_7 &pinctrl_mmc0_cd>;
+ vmmc-supply = <&vcc_mmc0_reg>;
+ vqmmc-supply = <&vcc_3v3_reg>;
status = "okay";
slot@0 {
reg = <0>;
@@ -43,6 +45,17 @@
};
};
+ mmc1: mmc@f8000000 {
+ vmmc-supply = <&vcc_3v3_reg>;
+ vqmmc-supply = <&vcc_3v3_reg>;
+ status = "disabled";
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioE 1 GPIO_ACTIVE_LOW>;
+ };
+ };
+
spi0: spi@f0004000 {
cs-gpios = <&pioD 13 0>, <0>, <0>, <&pioD 16 0>;
status = "okay";
@@ -105,7 +118,13 @@
macb0: ethernet@f0028000 {
phy-mode = "rgmii";
+ #address-cells = <1>;
+ #size-cells = <0>;
status = "okay";
+
+ ethernet-phy@7 {
+ reg = <0x7>;
+ };
};
pwm0: pwm@f002c000 {
@@ -215,12 +234,6 @@
};
};
};
-
- pmc: pmc@fffffc00 {
- main: mainck {
- clock-frequency = <12000000>;
- };
- };
};
nand0: nand@60000000 {
@@ -284,6 +297,14 @@
};
};
+ vcc_mmc0_reg: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ gpio = <&pioE 2 GPIO_ACTIVE_LOW>;
+ regulator-name = "mmc0-card-supply";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
gpio_keys {
compatible = "gpio-keys";
diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts
index c740e1a2a3a5..22ad7c959103 100644
--- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts
@@ -50,7 +50,8 @@
compatible = "atmel,sama5d4-xplained", "atmel,sama5d4", "atmel,sama5";
chosen {
- bootargs = "console=ttyS0,115200 ignore_loglevel earlyprintk";
+ bootargs = "ignore_loglevel earlyprintk";
+ stdout-path = "serial0:115200n8";
};
memory {
@@ -106,6 +107,8 @@
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>;
@@ -122,6 +125,11 @@
status = "okay";
};
+ spi1: spi@fc018000 {
+ cs-gpios = <&pioB 21 0>;
+ status = "okay";
+ };
+
adc0: adc@fc034000 {
atmel,adc-vref = <3300>;
status = "okay";
@@ -238,4 +246,22 @@
linux,default-trigger = "heartbeat";
};
};
+
+ 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_mmc1_reg: fixedregulator@1 {
+ compatible = "regulator-fixed";
+ gpio = <&pioE 4 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-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts
index 89ef4a540db5..d782f2926b73 100644
--- a/arch/arm/boot/dts/at91-sama5d4ek.dts
+++ b/arch/arm/boot/dts/at91-sama5d4ek.dts
@@ -50,7 +50,8 @@
compatible = "atmel,sama5d4ek", "atmel,sama5d4", "atmel,sama5";
chosen {
- bootargs = "console=ttyS0,115200 ignore_loglevel earlyprintk";
+ bootargs = "ignore_loglevel earlyprintk";
+ stdout-path = "serial0:115200n8";
};
memory {
@@ -108,8 +109,8 @@
mmc0: mmc@f8000000 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_cd>;
- slot@1 {
- reg = <1>;
+ slot@0 {
+ reg = <0>;
bus-width = <4>;
cd-gpios = <&pioE 5 0>;
};
diff --git a/arch/arm/boot/dts/at91rm9200.dtsi b/arch/arm/boot/dts/at91rm9200.dtsi
index 4fb333bd1f85..e3cfb9972f54 100644
--- a/arch/arm/boot/dts/at91rm9200.dtsi
+++ b/arch/arm/boot/dts/at91rm9200.dtsi
@@ -92,7 +92,7 @@
};
ramc0: ramc@ffffff00 {
- compatible = "atmel,at91rm9200-sdramc";
+ compatible = "atmel,at91rm9200-sdramc", "syscon";
reg = <0xffffff00 0x100>;
};
@@ -940,8 +940,8 @@
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00300000 0x100000>;
interrupts = <23 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&usb>, <&ohci_clk>, <&ohci_clk>, <&uhpck>;
- clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
+ clocks = <&ohci_clk>, <&ohci_clk>, <&uhpck>;
+ clock-names = "ohci_clk", "hclk", "uhpck";
status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/at91rm9200ek.dts b/arch/arm/boot/dts/at91rm9200ek.dts
index 2a5d21247d7e..8dab4b75ca97 100644
--- a/arch/arm/boot/dts/at91rm9200ek.dts
+++ b/arch/arm/boot/dts/at91rm9200ek.dts
@@ -12,6 +12,10 @@
model = "Atmel AT91RM9200 evaluation kit";
compatible = "atmel,at91rm9200ek", "atmel,at91rm9200";
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
memory {
reg = <0x20000000 0x4000000>;
};
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index d88fe62a2b2e..4bc347549102 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -1008,8 +1008,8 @@
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00500000 0x100000>;
interrupts = <20 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&usb>, <&ohci_clk>, <&ohci_clk>, <&uhpck>;
- clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
+ clocks = <&ohci_clk>, <&ohci_clk>, <&uhpck>;
+ clock-names = "ohci_clk", "hclk", "uhpck";
status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/at91sam9261.dtsi b/arch/arm/boot/dts/at91sam9261.dtsi
index bf8d1856a55a..b2c44a07a3d0 100644
--- a/arch/arm/boot/dts/at91sam9261.dtsi
+++ b/arch/arm/boot/dts/at91sam9261.dtsi
@@ -75,8 +75,8 @@
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00500000 0x100000>;
interrupts = <20 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&usb>, <&ohci_clk>, <&hclk0>, <&uhpck>;
- clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
+ clocks = <&ohci_clk>, <&hclk0>, <&uhpck>;
+ clock-names = "ohci_clk", "hclk", "uhpck";
status = "disabled";
};
diff --git a/arch/arm/boot/dts/at91sam9261ek.dts b/arch/arm/boot/dts/at91sam9261ek.dts
index f4a765729c7a..2e92ac020f23 100644
--- a/arch/arm/boot/dts/at91sam9261ek.dts
+++ b/arch/arm/boot/dts/at91sam9261ek.dts
@@ -13,7 +13,8 @@
compatible = "atmel,at91sam9261ek", "atmel,at91sam9261", "atmel,at91sam9";
chosen {
- bootargs = "console=ttyS0,115200 rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw";
+ bootargs = "rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw";
+ stdout-path = "serial0:115200n8";
};
memory {
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index 111889b556cf..e36d966ef5e8 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -1010,8 +1010,8 @@
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00a00000 0x100000>;
interrupts = <29 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&usb>, <&ohci_clk>, <&ohci_clk>, <&uhpck>;
- clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
+ clocks = <&ohci_clk>, <&ohci_clk>, <&uhpck>;
+ clock-names = "ohci_clk", "hclk", "uhpck";
status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
index 5cf93eecd8f1..23381276ffb8 100644
--- a/arch/arm/boot/dts/at91sam9263ek.dts
+++ b/arch/arm/boot/dts/at91sam9263ek.dts
@@ -13,7 +13,8 @@
compatible = "atmel,at91sam9263ek", "atmel,at91sam9263", "atmel,at91sam9";
chosen {
- bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
+ bootargs = "mem=64M root=/dev/mtdblock5 rw rootfstype=ubifs";
+ stdout-path = "serial0:115200n8";
};
memory {
diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
index dfaacb113f2e..57548a2c5a1e 100644
--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
@@ -10,7 +10,8 @@
/ {
chosen {
- bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
+ bootargs = "mem=64M root=/dev/mtdblock5 rw rootfstype=ubifs";
+ stdout-path = "serial0:115200n8";
};
memory {
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index 70e59c5ceb2f..d260ba779ae5 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -1291,8 +1291,8 @@
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00700000 0x100000>;
interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
- clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
+ clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
+ clock-names = "ohci_clk", "hclk", "uhpck";
status = "disabled";
};
@@ -1300,8 +1300,8 @@
compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
reg = <0x00800000 0x100000>;
interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&utmi>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
- clock-names = "usb_clk", "ehci_clk", "hclk", "uhpck";
+ clocks = <&utmi>, <&uhphs_clk>;
+ clock-names = "usb_clk", "ehci_clk";
status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
index 33ce7ca2c404..1375d3362603 100644
--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
+++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
@@ -15,7 +15,8 @@
compatible = "atmel,at91sam9m10g45ek", "atmel,at91sam9g45", "atmel,at91sam9";
chosen {
- bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2";
+ bootargs = "mem=64M root=/dev/mtdblock1 rw rootfstype=jffs2";
+ stdout-path = "serial0:115200n8";
};
memory {
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
index a9e35dfc12d9..5c2a8c8c8bd4 100644
--- a/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -949,9 +949,8 @@
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00500000 0x00100000>;
interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>,
- <&uhpck>;
- clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
+ clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
+ clock-names = "ohci_clk", "hclk", "uhpck";
status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
index 6e067c8a3502..eab17fcace6d 100644
--- a/arch/arm/boot/dts/at91sam9n12ek.dts
+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
@@ -14,7 +14,8 @@
compatible = "atmel,at91sam9n12ek", "atmel,at91sam9n12", "atmel,at91sam9";
chosen {
- bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2";
+ bootargs = "root=/dev/mtdblock1 rw rootfstype=jffs2";
+ stdout-path = "serial0:115200n8";
};
memory {
diff --git a/arch/arm/boot/dts/at91sam9rl.dtsi b/arch/arm/boot/dts/at91sam9rl.dtsi
index ebfd5ce9cb38..c9920c64791c 100644
--- a/arch/arm/boot/dts/at91sam9rl.dtsi
+++ b/arch/arm/boot/dts/at91sam9rl.dtsi
@@ -1065,13 +1065,6 @@
};
};
- rtc@fffffeb0 {
- compatible = "atmel,at91rm9200-rtc";
- reg = <0xfffffeb0 0x40>;
- interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
- status = "disabled";
- };
-
rtc@fffffd20 {
compatible = "atmel,at91sam9260-rtt";
reg = <0xfffffd20 0x10>;
@@ -1085,6 +1078,14 @@
reg = <0xfffffd60 0x10>;
status = "disabled";
};
+
+ rtc@fffffe00 {
+ compatible = "atmel,at91rm9200-rtc";
+ reg = <0xfffffe00 0x40>;
+ interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+ status = "disabled";
+ };
+
};
};
diff --git a/arch/arm/boot/dts/at91sam9rlek.dts b/arch/arm/boot/dts/at91sam9rlek.dts
index 9be5b540eebf..558c9f220bed 100644
--- a/arch/arm/boot/dts/at91sam9rlek.dts
+++ b/arch/arm/boot/dts/at91sam9rlek.dts
@@ -13,7 +13,8 @@
compatible = "atmel,at91sam9rlek", "atmel,at91sam9rl", "atmel,at91sam9";
chosen {
- bootargs = "console=ttyS0,115200 rootfstype=ubifs root=ubi0:rootfs ubi.mtd=5 rw";
+ bootargs = "rootfstype=ubifs root=ubi0:rootfs ubi.mtd=5 rw";
+ stdout-path = "serial0:115200n8";
};
memory {
@@ -181,13 +182,11 @@
};
};
- pmc: pmc@fffffc00 {
- main: mainck {
- clock-frequency = <12000000>;
- };
+ watchdog@fffffd40 {
+ status = "okay";
};
- watchdog@fffffd40 {
+ rtc@fffffe00 {
status = "okay";
};
};
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index 3aa56ae3410a..7521bdf17ef2 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -505,7 +505,7 @@
pinctrl_usart1_sck: usart1_sck-0 {
atmel,pins =
- <AT91_PIOC 28 AT91_PERIPH_C AT91_PINCTRL_NONE>; /* PC29 periph C */
+ <AT91_PIOC 29 AT91_PERIPH_C AT91_PINCTRL_NONE>; /* PC29 periph C */
};
};
@@ -694,6 +694,52 @@
};
};
+ pwm0 {
+ pinctrl_pwm0_pwm0_0: pwm0_pwm0-0 {
+ atmel,pins =
+ <AT91_PIOB 11 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwm0_1: pwm0_pwm0-1 {
+ atmel,pins =
+ <AT91_PIOC 10 AT91_PERIPH_C AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwm0_2: pwm0_pwm0-2 {
+ atmel,pins =
+ <AT91_PIOC 18 AT91_PERIPH_C AT91_PINCTRL_NONE>;
+ };
+
+ pinctrl_pwm0_pwm1_0: pwm0_pwm1-0 {
+ atmel,pins =
+ <AT91_PIOB 12 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwm1_1: pwm0_pwm1-1 {
+ atmel,pins =
+ <AT91_PIOC 11 AT91_PERIPH_C AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwm1_2: pwm0_pwm1-2 {
+ atmel,pins =
+ <AT91_PIOC 19 AT91_PERIPH_C AT91_PINCTRL_NONE>;
+ };
+
+ pinctrl_pwm0_pwm2_0: pwm0_pwm2-0 {
+ atmel,pins =
+ <AT91_PIOB 13 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwm2_1: pwm0_pwm2-1 {
+ atmel,pins =
+ <AT91_PIOC 20 AT91_PERIPH_C AT91_PINCTRL_NONE>;
+ };
+
+ pinctrl_pwm0_pwm3_0: pwm0_pwm3-0 {
+ atmel,pins =
+ <AT91_PIOB 14 AT91_PERIPH_B AT91_PINCTRL_NONE>;
+ };
+ pinctrl_pwm0_pwm3_1: pwm0_pwm3-1 {
+ atmel,pins =
+ <AT91_PIOC 21 AT91_PERIPH_C AT91_PINCTRL_NONE>;
+ };
+ };
+
tcb0 {
pinctrl_tcb0_tclk0: tcb0_tclk0-0 {
atmel,pins = <AT91_PIOA 24 AT91_PERIPH_A AT91_PINCTRL_NONE>;
@@ -1176,8 +1222,8 @@
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00600000 0x100000>;
interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
- clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
+ clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
+ clock-names = "ohci_clk", "hclk", "uhpck";
status = "disabled";
};
@@ -1185,8 +1231,8 @@
compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
reg = <0x00700000 0x100000>;
interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&utmi>, <&uhphs_clk>, <&uhpck>;
- clock-names = "usb_clk", "ehci_clk", "uhpck";
+ clocks = <&utmi>, <&uhphs_clk>;
+ clock-names = "usb_clk", "ehci_clk";
status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi
index cc83a37a7311..d237c462dfc6 100644
--- a/arch/arm/boot/dts/at91sam9x5ek.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi
@@ -13,7 +13,8 @@
compatible = "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
chosen {
- bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
+ bootargs = "root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
+ stdout-path = "serial0:115200n8";
};
ahb {
diff --git a/arch/arm/boot/dts/axp209.dtsi b/arch/arm/boot/dts/axp209.dtsi
index c20cf537f5a5..24c935c72e5e 100644
--- a/arch/arm/boot/dts/axp209.dtsi
+++ b/arch/arm/boot/dts/axp209.dtsi
@@ -18,11 +18,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 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
diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi
index 7b52c33ea69a..e1ac07a16f92 100644
--- a/arch/arm/boot/dts/bcm-cygnus.dtsi
+++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
@@ -212,6 +212,18 @@
status = "disabled";
};
+ nand: nand@18046000 {
+ compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1", "brcm,brcmnand";
+ reg = <0x18046000 0x600>, <0xf8105408 0x600>, <0x18046f00 0x20>;
+ reg-names = "nand", "iproc-idm", "iproc-ext";
+ interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ brcm,nand-has-wp;
+ };
+
gic: interrupt-controller@19021000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
index e479515099c3..668442b1bda5 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
@@ -1,5 +1,5 @@
/dts-v1/;
-/include/ "bcm2835-rpi.dtsi"
+#include "bcm2835-rpi.dtsi"
/ {
compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
@@ -25,6 +25,6 @@
/* I2S interface */
i2s_alt0: i2s_alt0 {
brcm,pins = <18 19 20 21>;
- brcm,function = <4>; /* alt0 */
+ brcm,function = <BCM2835_FSEL_ALT0>;
};
};
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts
index bafa46fc226a..ee89b79426cf 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
@@ -1,5 +1,5 @@
/dts-v1/;
-/include/ "bcm2835-rpi.dtsi"
+#include "bcm2835-rpi.dtsi"
/ {
compatible = "raspberrypi,model-b", "brcm,bcm2835";
@@ -18,6 +18,6 @@
/* I2S interface */
i2s_alt2: i2s_alt2 {
brcm,pins = <28 29 30 31>;
- brcm,function = <6>; /* alt2 */
+ brcm,function = <BCM2835_FSEL_ALT2>;
};
};
diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index c7064487017d..46780bb48bbf 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -1,4 +1,4 @@
-/include/ "bcm2835.dtsi"
+#include "bcm2835.dtsi"
/ {
memory {
@@ -21,17 +21,17 @@
gpioout: gpioout {
brcm,pins = <6>;
- brcm,function = <1>; /* GPIO out */
+ brcm,function = <BCM2835_FSEL_GPIO_OUT>;
};
alt0: alt0 {
brcm,pins = <0 1 2 3 4 5 7 8 9 10 11 14 15 40 45>;
- brcm,function = <4>; /* alt0 */
+ brcm,function = <BCM2835_FSEL_ALT0>;
};
alt3: alt3 {
brcm,pins = <48 49 50 51 52 53>;
- brcm,function = <7>; /* alt3 */
+ brcm,function = <BCM2835_FSEL_ALT3>;
};
};
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index 3342cb1407bc..301c73f4ca33 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -1,4 +1,5 @@
-/include/ "skeleton.dtsi"
+#include <dt-bindings/pinctrl/bcm2835.h>
+#include "skeleton.dtsi"
/ {
compatible = "brcm,bcm2835";
@@ -14,6 +15,7 @@
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x7e000000 0x20000000 0x02000000>;
+ dma-ranges = <0x40000000 0x00000000 0x20000000>;
timer@7e003000 {
compatible = "brcm,bcm2835-system-timer";
@@ -60,6 +62,13 @@
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>;
@@ -112,7 +121,7 @@
status = "disabled";
};
- i2c0: i2c@20205000 {
+ i2c0: i2c@7e205000 {
compatible = "brcm,bcm2835-i2c";
reg = <0x7e205000 0x1000>;
interrupts = <2 21>;
diff --git a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
new file mode 100644
index 000000000000..112a5a834ddc
--- /dev/null
+++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
@@ -0,0 +1,97 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for Asus RT-AC56U
+ *
+ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+/ {
+ compatible = "asus,rt-ac56u", "brcm,bcm4708";
+ model = "Asus RT-AC56U (BCM4708)";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ usb3 {
+ label = "bcm53xx:blue:usb3";
+ gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ wan {
+ label = "bcm53xx:blue:wan";
+ gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ lan {
+ label = "bcm53xx:blue:lan";
+ gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ power {
+ label = "bcm53xx:blue:power";
+ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ all {
+ label = "bcm53xx:blue:all";
+ gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ 2ghz {
+ label = "bcm53xx:blue:2ghz";
+ gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+
+ usb2 {
+ label = "bcm53xx:blue:usb2";
+ gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rfkill {
+ label = "WiFi";
+ linux,code = <KEY_RFKILL>;
+ gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
+ };
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
+ };
+
+ wps {
+ label = "WPS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
new file mode 100644
index 000000000000..3600f56f46f4
--- /dev/null
+++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
@@ -0,0 +1,84 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for Asus RT-AC68U
+ *
+ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+/ {
+ compatible = "asus,rt-ac68u", "brcm,bcm4708";
+ model = "Asus RT-AC68U (BCM4708)";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ usb2 {
+ label = "bcm53xx:blue:usb2";
+ gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ power {
+ label = "bcm53xx:blue:power";
+ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ logo {
+ label = "bcm53xx:white:logo";
+ gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ usb3 {
+ label = "bcm53xx:blue:usb3";
+ gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ brightness {
+ label = "Backlight";
+ linux,code = <KEY_BRIGHTNESS_ZERO>;
+ gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
+ };
+
+ wps {
+ label = "WPS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
+ };
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
+ };
+
+ rfkill {
+ label = "WiFi";
+ linux,code = <KEY_RFKILL>;
+ gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
index b359c1e6178e..24f0ab59bf1b 100644
--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
@@ -10,6 +10,7 @@
/dts-v1/;
#include "bcm4708.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
/ {
compatible = "buffalo,wzr-1750dhp", "brcm,bcm4708";
@@ -47,6 +48,12 @@
leds {
compatible = "gpio-leds";
+ usb {
+ label = "bcm53xx:blue:usb";
+ gpios = <&hc595 0 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
power0 {
label = "bcm53xx:red:power";
gpios = <&hc595 1 GPIO_ACTIVE_HIGH>;
diff --git a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
index 946c728c4eb7..f03939311717 100644
--- a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
+++ b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
@@ -10,6 +10,7 @@
/dts-v1/;
#include "bcm4708.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
/ {
compatible = "luxul,xwc-1000", "brcm,bcm4708";
@@ -23,12 +24,8 @@
reg = <0x00000000 0x08000000>;
};
- axi@18000000 {
- nand@28000 {
- reg = <0x00028000 0x1000>;
- #address-cells = <1>;
- #size-cells = <1>;
-
+ nand: nand@18028000 {
+ nandcs@0 {
partition@0 {
label = "ubi";
reg = <0x00000000 0x08000000>;
diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
index 2ed9e5794785..326ce8f4e49c 100644
--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
@@ -10,6 +10,7 @@
/dts-v1/;
#include "bcm4708.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
/ {
compatible = "netgear,r6250v1", "brcm,bcm4708";
diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
index 39910428246a..3a94606d042b 100644
--- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
+++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
@@ -10,6 +10,7 @@
/dts-v1/;
#include "bcm4708.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
/ {
compatible = "netgear,r6300v2", "brcm,bcm4708";
diff --git a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
new file mode 100644
index 000000000000..d6a033b97c70
--- /dev/null
+++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
@@ -0,0 +1,120 @@
+/*
+ * Broadcom BCM470X / BCM5301X arm platform code.
+ * DTS for SmartRG SR400ac
+ *
+ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+/ {
+ compatible = "smartrg,sr400ac", "brcm,bcm4708";
+ model = "SmartRG SR400ac";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ power-white {
+ label = "bcm53xx:white:power";
+ gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-on";
+ };
+
+ power-amber {
+ label = "bcm53xx:amber:power";
+ gpios = <&chipcommon 2 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ usb2 {
+ label = "bcm53xx:white:usb2";
+ gpios = <&chipcommon 3 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ usb3-white {
+ label = "bcm53xx:white:usb3";
+ gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ usb3-green {
+ label = "bcm53xx:green:usb3";
+ gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ wps {
+ label = "bcm53xx:white:wps";
+ gpios = <&chipcommon 6 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ status-red {
+ label = "bcm53xx:red:status";
+ gpios = <&chipcommon 8 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ status-green {
+ label = "bcm53xx:green:status";
+ gpios = <&chipcommon 9 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ status-blue {
+ label = "bcm53xx:blue:status";
+ gpios = <&chipcommon 10 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ wan-white {
+ label = "bcm53xx:white:wan";
+ gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ wan-red {
+ label = "bcm53xx:red:wan";
+ gpios = <&chipcommon 13 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rfkill {
+ label = "WiFi";
+ linux,code = <KEY_RFKILL>;
+ gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
+ };
+
+ wps {
+ label = "WPS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
+ };
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
index 0ee85ea10bb2..71b98cfaf944 100644
--- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
+++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
@@ -10,6 +10,7 @@
/dts-v1/;
#include "bcm47081.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
/ {
compatible = "asus,rt-n18u", "brcm,bcm47081", "brcm,bcm4708";
diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
index db9131e03268..bb0cb0bfafaf 100644
--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
+++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
@@ -10,6 +10,7 @@
/dts-v1/;
#include "bcm47081.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
/ {
compatible = "buffalo,wzr-600dhp2", "brcm,bcm47081", "brcm,bcm4708";
diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
index 7d6868acb1c6..184fd9214110 100644
--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
+++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
@@ -10,6 +10,7 @@
/dts-v1/;
#include "bcm47081.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
/ {
compatible = "buffalo,wzr-900dhp", "brcm,bcm47081", "brcm,bcm4708";
diff --git a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
new file mode 100644
index 000000000000..aedf3c426e1f
--- /dev/null
+++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
@@ -0,0 +1,65 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for Asus RT-AC87U
+ *
+ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+
+/ {
+ compatible = "asus,rt-ac87u", "brcm,bcm4709", "brcm,bcm4708";
+ model = "Asus RT-AC87U";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ wps {
+ label = "bcm53xx:blue:wps";
+ gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ power {
+ label = "bcm53xx:blue:power";
+ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ wan {
+ label = "bcm53xx:red:wan";
+ gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wps {
+ label = "WPS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
+ };
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
new file mode 100644
index 000000000000..2a92e8d5ab34
--- /dev/null
+++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
@@ -0,0 +1,128 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for Buffalo WXR-1900DHP
+ *
+ * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+/ {
+ compatible = "buffalo,wxr-1900dhp", "brcm,bcm4709", "brcm,bcm4708";
+ model = "Buffalo WXR-1900DHP";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ usb {
+ label = "bcm53xx:green:usb";
+ gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ power-amber {
+ label = "bcm53xx:amber:power";
+ gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ power-white {
+ label = "bcm53xx:white:power";
+ gpios = <&chipcommon 6 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-on";
+ };
+
+ router-amber {
+ label = "bcm53xx:amber:router";
+ gpios = <&chipcommon 7 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ router-white {
+ label = "bcm53xx:white:router";
+ gpios = <&chipcommon 8 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ wan-amber {
+ label = "bcm53xx:amber:wan";
+ gpios = <&chipcommon 9 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ wan-white {
+ label = "bcm53xx:white:wan";
+ gpios = <&chipcommon 10 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ wireless-amber {
+ label = "bcm53xx:amber:wireless";
+ gpios = <&chipcommon 11 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ wireless-white {
+ label = "bcm53xx:white:wireless";
+ gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ power {
+ label = "Power";
+ linux,code = <KEY_POWER>;
+ gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
+ };
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
+ };
+
+ aoss {
+ label = "AOSS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&chipcommon 16 GPIO_ACTIVE_LOW>;
+ };
+
+ /* Commit mode set by switch? */
+ mode {
+ label = "Mode";
+ linux,code = <KEY_SETUP>;
+ gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
+ };
+
+ /* Switch: AP mode */
+ sw_ap {
+ label = "AP";
+ linux,code = <BTN_0>;
+ gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
+ };
+
+ eject {
+ label = "USB eject";
+ linux,code = <KEY_EJECTCD>;
+ gpios = <&chipcommon 20 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
index ea26dd3ec03a..446c586cd473 100644
--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
@@ -10,6 +10,7 @@
/dts-v1/;
#include "bcm4708.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
/ {
compatible = "netgear,r8000", "brcm,bcm4709", "brcm,bcm4708";
diff --git a/arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi b/arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi
new file mode 100644
index 000000000000..d10781e36f54
--- /dev/null
+++ b/arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi
@@ -0,0 +1,24 @@
+/*
+ * Broadcom BCM470X / BCM5301X Nand chip defaults.
+ *
+ * This should be included if the NAND controller is on chip select 0
+ * and uses 8 bit ECC.
+ *
+ * Copyright (C) 2015 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/ {
+ nand@18028000 {
+ nandcs@0 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nand-ecc-strength = <8>;
+ nand-ecc-step-size = <512>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm5301x.dtsi b/arch/arm/boot/dts/bcm5301x.dtsi
index 78aec6270c2f..21fefd4cdc25 100644
--- a/arch/arm/boot/dts/bcm5301x.dtsi
+++ b/arch/arm/boot/dts/bcm5301x.dtsi
@@ -108,6 +108,30 @@
/* ChipCommon */
<0x00000000 0 &gic GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+ /* PCIe Controller 0 */
+ <0x00012000 0 &gic GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00012000 1 &gic GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00012000 2 &gic GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00012000 3 &gic GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00012000 4 &gic GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00012000 5 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+
+ /* PCIe Controller 1 */
+ <0x00013000 0 &gic GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00013000 1 &gic GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00013000 2 &gic GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00013000 3 &gic GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00013000 4 &gic GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00013000 5 &gic GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
+
+ /* PCIe Controller 2 */
+ <0x00014000 0 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 1 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 2 &gic GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 3 &gic GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 4 &gic GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00014000 5 &gic GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
+
/* USB 2.0 Controller */
<0x00021000 0 &gic GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
@@ -143,4 +167,16 @@
#gpio-cells = <2>;
};
};
+
+ nand: nand@18028000 {
+ compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1", "brcm,brcmnand";
+ reg = <0x18028000 0x600>, <0x1811a408 0x600>, <0x18028f00 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;
+ };
};
diff --git a/arch/arm/boot/dts/bcm63138.dtsi b/arch/arm/boot/dts/bcm63138.dtsi
index f46329c8ad75..34cd64051250 100644
--- a/arch/arm/boot/dts/bcm63138.dtsi
+++ b/arch/arm/boot/dts/bcm63138.dtsi
@@ -26,6 +26,7 @@
compatible = "arm,cortex-a9";
next-level-cache = <&L2>;
reg = <0>;
+ enable-method = "brcm,bcm63138";
};
cpu@1 {
@@ -33,6 +34,8 @@
compatible = "arm,cortex-a9";
next-level-cache = <&L2>;
reg = <1>;
+ enable-method = "brcm,bcm63138";
+ resets = <&pmb0 4 1>;
};
};
@@ -105,6 +108,18 @@
reg = <0x1e620 0x20>;
interrupts = <GIC_PPI 14 IRQ_TYPE_LEVEL_HIGH>;
};
+
+ pmb0: reset-controller@4800c0 {
+ compatible = "brcm,bcm63138-pmb";
+ reg = <0x4800c0 0x10>;
+ #reset-cells = <2>;
+ };
+
+ pmb1: reset-controller@4800e0 {
+ compatible = "brcm,bcm63138-pmb";
+ reg = <0x4800e0 0x10>;
+ #reset-cells = <2>;
+ };
};
/* Legacy UBUS base */
@@ -114,6 +129,11 @@
#size-cells = <1>;
ranges = <0 0xfffe8000 0x8100>;
+ timer: timer@80 {
+ compatible = "brcm,bcm6328-timer", "syscon";
+ reg = <0x80 0x3c>;
+ };
+
serial0: serial@600 {
compatible = "brcm,bcm6345-uart";
reg = <0x600 0x1b>;
@@ -131,5 +151,28 @@
clock-names = "periph";
status = "disabled";
};
+
+ nand: nand@2000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "brcm,nand-bcm63138", "brcm,brcmnand-v7.0", "brcm,brcmnand";
+ reg = <0x2000 0x600>, <0xf0 0x10>;
+ reg-names = "nand", "nand-int-base";
+ status = "disabled";
+ interrupts = <GIC_SPI 38 0>;
+ interrupt-names = "nand";
+ };
+
+ bootlut: bootlut@8000 {
+ compatible = "brcm,bcm63138-bootlut";
+ reg = <0x8000 0x50>;
+ };
+
+ reboot {
+ compatible = "syscon-reboot";
+ regmap = <&timer>;
+ offset = <0x34>;
+ mask = <1>;
+ };
};
};
diff --git a/arch/arm/boot/dts/bcm7445-bcm97445svmb.dts b/arch/arm/boot/dts/bcm7445-bcm97445svmb.dts
index 9eec2ac1112f..0bb8d17e4c2d 100644
--- a/arch/arm/boot/dts/bcm7445-bcm97445svmb.dts
+++ b/arch/arm/boot/dts/bcm7445-bcm97445svmb.dts
@@ -12,3 +12,26 @@
<0x00 0x80000000 0x00 0x40000000>;
};
};
+
+&nand {
+ status = "okay";
+
+ nandcs@1 {
+ compatible = "brcm,nandcs";
+ reg = <1>;
+ nand-ecc-step-size = <512>;
+ nand-ecc-strength = <8>;
+ nand-on-flash-bbt;
+
+ #size-cells = <2>;
+ #address-cells = <2>;
+
+ flash1.rootfs0@0 {
+ reg = <0x0 0x0 0x0 0x80000000>;
+ };
+
+ flash1.rootfs1@80000000 {
+ reg = <0x0 0x80000000 0x0 0x80000000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm7445.dtsi b/arch/arm/boot/dts/bcm7445.dtsi
index 39ac7840d7ee..58dcd666257c 100644
--- a/arch/arm/boot/dts/bcm7445.dtsi
+++ b/arch/arm/boot/dts/bcm7445.dtsi
@@ -108,6 +108,65 @@
brcm,int-map-mask = <0x25c>, <0x7000000>;
brcm,int-fwd-mask = <0x70000>;
};
+
+ hif_intr2_intc: interrupt-controller@3e1000 {
+ compatible = "brcm,l2-intc";
+ reg = <0x3e1000 0x30>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupts = <GIC_SPI 0x20 0x0>;
+ interrupt-parent = <&gic>;
+ interrupt-names = "hif";
+ };
+
+ nand: nand@3e2800 {
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "brcm,brcmnand-v7.1", "brcm,brcmnand";
+ reg-names = "nand", "flash-dma";
+ reg = <0x3e2800 0x600>, <0x3e3000 0x2c>;
+ interrupt-parent = <&hif_intr2_intc>;
+ interrupts = <24>, <4>;
+ interrupt-names = "nand_ctlrdy", "flash_dma_done";
+ };
+
+ sata@45a000 {
+ compatible = "brcm,bcm7445-ahci", "brcm,sata3-ahci";
+ reg-names = "ahci", "top-ctrl";
+ reg = <0x45a000 0xa9c>, <0x458040 0x24>;
+ interrupts = <GIC_SPI 30 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sata0: sata-port@0 {
+ reg = <0>;
+ phys = <&sata_phy0>;
+ };
+
+ sata1: sata-port@1 {
+ reg = <1>;
+ phys = <&sata_phy1>;
+ };
+ };
+
+ sata_phy: sata-phy@458100 {
+ compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3";
+ reg = <0x458100 0x1f00>;
+ reg-names = "phy";
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+
+ sata_phy0: sata-phy@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ };
+
+ sata_phy1: sata-phy@1 {
+ reg = <1>;
+ #phy-cells = <0>;
+ };
+ };
};
smpboot {
diff --git a/arch/arm/boot/dts/bcm958300k.dts b/arch/arm/boot/dts/bcm958300k.dts
index c9eb8565eac5..2f63052f9d48 100644
--- a/arch/arm/boot/dts/bcm958300k.dts
+++ b/arch/arm/boot/dts/bcm958300k.dts
@@ -58,4 +58,20 @@
uart3: serial@18023000 {
status = "okay";
};
+
+ nand: nand@18046000 {
+ nandcs@1 {
+ 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>;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/bcm963138dvt.dts b/arch/arm/boot/dts/bcm963138dvt.dts
index 69c93395ecd2..370aa2cfddf2 100644
--- a/arch/arm/boot/dts/bcm963138dvt.dts
+++ b/arch/arm/boot/dts/bcm963138dvt.dts
@@ -28,3 +28,15 @@
&serial1 {
status = "okay";
};
+
+&nand {
+ status = "okay";
+
+ nandcs@0 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-ecc-strength = <4>;
+ nand-ecc-step-size = <512>;
+ brcm,nand-oob-sectors-size = <16>;
+ };
+};
diff --git a/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
index 86d85d8896a3..5c99fb3a4d10 100644
--- a/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
+++ b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
@@ -3,9 +3,37 @@
*
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.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.
+ * 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 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.
+ *
+ * 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/;
diff --git a/arch/arm/boot/dts/berlin2.dtsi b/arch/arm/boot/dts/berlin2.dtsi
index 63d00a63cfa6..ef811de09908 100644
--- a/arch/arm/boot/dts/berlin2.dtsi
+++ b/arch/arm/boot/dts/berlin2.dtsi
@@ -6,9 +6,37 @@
* based on GPL'ed 2.6 kernel sources
* (c) Marvell International Ltd.
*
- * 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.
+ * 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 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.
+ *
+ * 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"
@@ -56,7 +84,7 @@
sdhci0: sdhci@ab0000 {
compatible = "mrvl,pxav3-mmc";
reg = <0xab0000 0x200>;
- clocks = <&chip CLKID_SDIO0XIN>, <&chip CLKID_SDIO0>;
+ clocks = <&chip_clk CLKID_SDIO0XIN>, <&chip_clk CLKID_SDIO0>;
clock-names = "io", "core";
interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -65,7 +93,7 @@
sdhci1: sdhci@ab0800 {
compatible = "mrvl,pxav3-mmc";
reg = <0xab0800 0x200>;
- clocks = <&chip CLKID_SDIO1XIN>, <&chip CLKID_SDIO1>;
+ clocks = <&chip_clk CLKID_SDIO1XIN>, <&chip_clk CLKID_SDIO1>;
clock-names = "io", "core";
interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -75,7 +103,7 @@
compatible = "mrvl,pxav3-mmc";
reg = <0xab1000 0x200>;
interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&chip CLKID_NFC_ECC>, <&chip CLKID_NFC>;
+ clocks = <&chip_clk CLKID_NFC_ECC>, <&chip_clk CLKID_NFC>;
clock-names = "io", "core";
pinctrl-0 = <&emmc_pmux>;
pinctrl-names = "default";
@@ -105,13 +133,13 @@
compatible = "arm,cortex-a9-twd-timer";
reg = <0xad0600 0x20>;
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
- clocks = <&chip CLKID_TWD>;
+ clocks = <&chip_clk CLKID_TWD>;
};
eth1: ethernet@b90000 {
compatible = "marvell,pxa168-eth";
reg = <0xb90000 0x10000>;
- clocks = <&chip CLKID_GETH1>;
+ clocks = <&chip_clk CLKID_GETH1>;
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
/* set by bootloader */
local-mac-address = [00 00 00 00 00 00];
@@ -134,7 +162,7 @@
eth0: ethernet@e50000 {
compatible = "marvell,pxa168-eth";
reg = <0xe50000 0x10000>;
- clocks = <&chip CLKID_GETH0>;
+ clocks = <&chip_clk CLKID_GETH0>;
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
/* set by bootloader */
local-mac-address = [00 00 00 00 00 00];
@@ -233,7 +261,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c00 0x14>;
interrupts = <8>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "okay";
};
@@ -242,7 +270,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c14 0x14>;
interrupts = <9>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "okay";
};
@@ -251,7 +279,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c28 0x14>;
interrupts = <10>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -260,7 +288,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c3c 0x14>;
interrupts = <11>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -269,7 +297,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c50 0x14>;
interrupts = <12>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -278,7 +306,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c64 0x14>;
interrupts = <13>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -287,7 +315,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c78 0x14>;
interrupts = <14>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -296,7 +324,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c8c 0x14>;
interrupts = <15>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -315,7 +343,7 @@
compatible = "marvell,berlin2-ahci", "generic-ahci";
reg = <0xe90000 0x1000>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&chip CLKID_SATA>;
+ clocks = <&chip_clk CLKID_SATA>;
#address-cells = <1>;
#size-cells = <0>;
@@ -335,7 +363,7 @@
sata_phy: phy@e900a0 {
compatible = "marvell,berlin2-sata-phy";
reg = <0xe900a0 0x200>;
- clocks = <&chip CLKID_SATA>;
+ clocks = <&chip_clk CLKID_SATA>;
#address-cells = <1>;
#size-cells = <0>;
#phy-cells = <1>;
@@ -351,16 +379,28 @@
};
chip: chip-control@ea0000 {
- compatible = "marvell,berlin2-chip-ctrl";
- #clock-cells = <1>;
- #reset-cells = <2>;
+ compatible = "simple-mfd", "syscon";
reg = <0xea0000 0x400>;
- clocks = <&refclk>;
- clock-names = "refclk";
- emmc_pmux: emmc-pmux {
- groups = "G26";
- function = "emmc";
+ chip_clk: clock {
+ compatible = "marvell,berlin2-clk";
+ #clock-cells = <1>;
+ clocks = <&refclk>;
+ clock-names = "refclk";
+ };
+
+ soc_pinctrl: pin-controller {
+ compatible = "marvell,berlin2-soc-pinctrl";
+
+ emmc_pmux: emmc-pmux {
+ groups = "G26";
+ function = "emmc";
+ };
+ };
+
+ chip_rst: reset {
+ compatible = "marvell,berlin2-reset";
+ #reset-cells = <2>;
};
};
@@ -442,22 +482,24 @@
};
sysctrl: system-controller@d000 {
- compatible = "marvell,berlin2-system-ctrl";
+ compatible = "simple-mfd", "syscon";
reg = <0xd000 0x100>;
- uart0_pmux: uart0-pmux {
- groups = "GSM4";
- function = "uart0";
- };
-
- uart1_pmux: uart1-pmux {
- groups = "GSM5";
- function = "uart1";
- };
-
- uart2_pmux: uart2-pmux {
- groups = "GSM3";
- function = "uart2";
+ sys_pinctrl: pin-controller {
+ compatible = "marvell,berlin2-system-pinctrl";
+ uart0_pmux: uart0-pmux {
+ groups = "GSM4";
+ function = "uart0";
+ };
+
+ uart1_pmux: uart1-pmux {
+ groups = "GSM5";
+ function = "uart1";
+ };
+ uart2_pmux: uart2-pmux {
+ groups = "GSM3";
+ function = "uart2";
+ };
};
};
diff --git a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
index 30270be4d0c9..772165ad0a52 100644
--- a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
+++ b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
@@ -3,9 +3,37 @@
*
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.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.
+ * 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 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.
+ *
+ * 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/;
diff --git a/arch/arm/boot/dts/berlin2cd.dtsi b/arch/arm/boot/dts/berlin2cd.dtsi
index 81b670ac494a..900213d78a32 100644
--- a/arch/arm/boot/dts/berlin2cd.dtsi
+++ b/arch/arm/boot/dts/berlin2cd.dtsi
@@ -6,9 +6,37 @@
* based on GPL'ed 2.6 kernel sources
* (c) Marvell International Ltd.
*
- * 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.
+ * 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 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.
+ *
+ * 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"
@@ -53,7 +81,7 @@
sdhci0: sdhci@ab0000 {
compatible = "mrvl,pxav3-mmc";
reg = <0xab0000 0x200>;
- clocks = <&chip CLKID_SDIO0XIN>, <&chip CLKID_SDIO0>;
+ clocks = <&chip_clk CLKID_SDIO0XIN>, <&chip_clk CLKID_SDIO0>;
clock-names = "io", "core";
interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -77,14 +105,14 @@
compatible = "arm,cortex-a9-twd-timer";
reg = <0xad0600 0x20>;
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_HIGH)>;
- clocks = <&chip CLKID_TWD>;
+ clocks = <&chip_clk CLKID_TWD>;
};
usb_phy0: usb-phy@b74000 {
compatible = "marvell,berlin2cd-usb-phy";
reg = <0xb74000 0x128>;
#phy-cells = <0>;
- resets = <&chip 0x178 23>;
+ resets = <&chip_rst 0x178 23>;
status = "disabled";
};
@@ -92,14 +120,14 @@
compatible = "marvell,berlin2cd-usb-phy";
reg = <0xb78000 0x128>;
#phy-cells = <0>;
- resets = <&chip 0x178 24>;
+ resets = <&chip_rst 0x178 24>;
status = "disabled";
};
eth1: ethernet@b90000 {
compatible = "marvell,pxa168-eth";
reg = <0xb90000 0x10000>;
- clocks = <&chip CLKID_GETH1>;
+ clocks = <&chip_clk CLKID_GETH1>;
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
/* set by bootloader */
local-mac-address = [00 00 00 00 00 00];
@@ -117,7 +145,7 @@
eth0: ethernet@e50000 {
compatible = "marvell,pxa168-eth";
reg = <0xe50000 0x10000>;
- clocks = <&chip CLKID_GETH0>;
+ clocks = <&chip_clk CLKID_GETH0>;
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
/* set by bootloader */
local-mac-address = [00 00 00 00 00 00];
@@ -216,7 +244,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c00 0x14>;
interrupts = <8>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "okay";
};
@@ -225,7 +253,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c14 0x14>;
interrupts = <9>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "okay";
};
@@ -234,7 +262,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c28 0x14>;
interrupts = <10>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -243,7 +271,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c3c 0x14>;
interrupts = <11>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -252,7 +280,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c50 0x14>;
interrupts = <12>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -261,7 +289,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c64 0x14>;
interrupts = <13>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -270,7 +298,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c78 0x14>;
interrupts = <14>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -279,7 +307,7 @@
compatible = "snps,dw-apb-timer";
reg = <0x2c8c 0x14>;
interrupts = <15>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -295,16 +323,28 @@
};
chip: chip-control@ea0000 {
- compatible = "marvell,berlin2cd-chip-ctrl";
- #clock-cells = <1>;
- #reset-cells = <2>;
+ compatible = "simple-mfd", "syscon";
reg = <0xea0000 0x400>;
- clocks = <&refclk>;
- clock-names = "refclk";
- uart0_pmux: uart0-pmux {
- groups = "G6";
- function = "uart0";
+ chip_clk: clock {
+ compatible = "marvell,berlin2-clk";
+ #clock-cells = <1>;
+ clocks = <&refclk>;
+ clock-names = "refclk";
+ };
+
+ soc_pinctrl: pin-controller {
+ compatible = "marvell,berlin2cd-soc-pinctrl";
+
+ uart0_pmux: uart0-pmux {
+ groups = "G6";
+ function = "uart0";
+ };
+ };
+
+ chip_rst: reset {
+ compatible = "marvell,berlin2-reset";
+ #reset-cells = <2>;
};
};
@@ -312,7 +352,7 @@
compatible = "chipidea,usb2";
reg = <0xed0000 0x200>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&chip CLKID_USB0>;
+ clocks = <&chip_clk CLKID_USB0>;
phys = <&usb_phy0>;
phy-names = "usb-phy";
status = "disabled";
@@ -322,7 +362,7 @@
compatible = "chipidea,usb2";
reg = <0xee0000 0x200>;
interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&chip CLKID_USB1>;
+ clocks = <&chip_clk CLKID_USB1>;
phys = <&usb_phy1>;
phy-names = "usb-phy";
status = "disabled";
@@ -389,8 +429,12 @@
};
sysctrl: system-controller@d000 {
- compatible = "marvell,berlin2cd-system-ctrl";
+ compatible = "simple-mfd", "syscon";
reg = <0xd000 0x100>;
+
+ sys_pinctrl: pin-controller {
+ compatible = "marvell,berlin2cd-system-pinctrl";
+ };
};
sic: interrupt-controller@e000 {
diff --git a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
index a98ac1bd8f65..4a749e5b3b44 100644
--- a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
+++ b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
@@ -1,9 +1,37 @@
/*
* Copyright (C) 2014 Antoine Ténart <antoine.tenart@free-electrons.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.
+ * 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 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.
+ *
+ * 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/;
diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index be5397288d24..63a48490e2f9 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -1,9 +1,37 @@
/*
* Copyright (C) 2014 Antoine Ténart <antoine.tenart@free-electrons.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.
+ * 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 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.
+ *
+ * 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/clock/berlin2q.h>
@@ -74,7 +102,7 @@
sdhci0: sdhci@ab0000 {
compatible = "mrvl,pxav3-mmc";
reg = <0xab0000 0x200>;
- clocks = <&chip CLKID_SDIO1XIN>;
+ clocks = <&chip_clk CLKID_SDIO1XIN>;
interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
@@ -82,7 +110,7 @@
sdhci1: sdhci@ab0800 {
compatible = "mrvl,pxav3-mmc";
reg = <0xab0800 0x200>;
- clocks = <&chip CLKID_SDIO1XIN>;
+ clocks = <&chip_clk CLKID_SDIO1XIN>;
interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
@@ -91,7 +119,7 @@
compatible = "mrvl,pxav3-mmc";
reg = <0xab1000 0x200>;
interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&chip CLKID_NFC_ECC>, <&chip CLKID_NFC>;
+ clocks = <&chip_clk CLKID_NFC_ECC>, <&chip_clk CLKID_NFC>;
clock-names = "io", "core";
status = "disabled";
};
@@ -112,7 +140,7 @@
local-timer@ad0600 {
compatible = "arm,cortex-a9-twd-timer";
reg = <0xad0600 0x20>;
- clocks = <&chip CLKID_TWD>;
+ clocks = <&chip_clk CLKID_TWD>;
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
};
@@ -127,7 +155,7 @@
compatible = "marvell,berlin2-usb-phy";
reg = <0xa2f400 0x128>;
#phy-cells = <0>;
- resets = <&chip 0x104 14>;
+ resets = <&chip_rst 0x104 14>;
status = "disabled";
};
@@ -135,7 +163,7 @@
compatible = "chipidea,usb2";
reg = <0xa30000 0x10000>;
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&chip CLKID_USB2>;
+ clocks = <&chip_clk CLKID_USB2>;
phys = <&usb_phy2>;
phy-names = "usb-phy";
status = "disabled";
@@ -145,7 +173,7 @@
compatible = "marvell,berlin2-usb-phy";
reg = <0xb74000 0x128>;
#phy-cells = <0>;
- resets = <&chip 0x104 12>;
+ resets = <&chip_rst 0x104 12>;
status = "disabled";
};
@@ -153,14 +181,14 @@
compatible = "marvell,berlin2-usb-phy";
reg = <0xb78000 0x128>;
#phy-cells = <0>;
- resets = <&chip 0x104 13>;
+ resets = <&chip_rst 0x104 13>;
status = "disabled";
};
eth0: ethernet@b90000 {
compatible = "marvell,pxa168-eth";
reg = <0xb90000 0x10000>;
- clocks = <&chip CLKID_GETH0>;
+ clocks = <&chip_clk CLKID_GETH0>;
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
/* set by bootloader */
local-mac-address = [00 00 00 00 00 00];
@@ -267,7 +295,7 @@
reg = <0x1400 0x100>;
interrupt-parent = <&aic>;
interrupts = <4>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
pinctrl-0 = <&twsi0_pmux>;
pinctrl-names = "default";
status = "disabled";
@@ -280,7 +308,7 @@
reg = <0x1800 0x100>;
interrupt-parent = <&aic>;
interrupts = <5>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
pinctrl-0 = <&twsi1_pmux>;
pinctrl-names = "default";
status = "disabled";
@@ -289,7 +317,7 @@
timer0: timer@2c00 {
compatible = "snps,dw-apb-timer";
reg = <0x2c00 0x14>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
interrupts = <8>;
};
@@ -297,14 +325,14 @@
timer1: timer@2c14 {
compatible = "snps,dw-apb-timer";
reg = <0x2c14 0x14>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
};
timer2: timer@2c28 {
compatible = "snps,dw-apb-timer";
reg = <0x2c28 0x14>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -312,7 +340,7 @@
timer3: timer@2c3c {
compatible = "snps,dw-apb-timer";
reg = <0x2c3c 0x14>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -320,7 +348,7 @@
timer4: timer@2c50 {
compatible = "snps,dw-apb-timer";
reg = <0x2c50 0x14>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -328,7 +356,7 @@
timer5: timer@2c64 {
compatible = "snps,dw-apb-timer";
reg = <0x2c64 0x14>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -336,7 +364,7 @@
timer6: timer@2c78 {
compatible = "snps,dw-apb-timer";
reg = <0x2c78 0x14>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -344,7 +372,7 @@
timer7: timer@2c8c {
compatible = "snps,dw-apb-timer";
reg = <0x2c8c 0x14>;
- clocks = <&chip CLKID_CFG>;
+ clocks = <&chip_clk CLKID_CFG>;
clock-names = "timer";
status = "disabled";
};
@@ -360,21 +388,33 @@
};
chip: chip-control@ea0000 {
- compatible = "marvell,berlin2q-chip-ctrl";
- #clock-cells = <1>;
- #reset-cells = <2>;
+ compatible = "simple-mfd", "syscon";
reg = <0xea0000 0x400>, <0xdd0170 0x10>;
- clocks = <&refclk>;
- clock-names = "refclk";
- twsi0_pmux: twsi0-pmux {
- groups = "G6";
- function = "twsi0";
+ chip_clk: clock {
+ compatible = "marvell,berlin2q-clk";
+ #clock-cells = <1>;
+ clocks = <&refclk>;
+ clock-names = "refclk";
+ };
+
+ soc_pinctrl: pin-controller {
+ compatible = "marvell,berlin2q-soc-pinctrl";
+
+ twsi0_pmux: twsi0-pmux {
+ groups = "G6";
+ function = "twsi0";
+ };
+
+ twsi1_pmux: twsi1-pmux {
+ groups = "G7";
+ function = "twsi1";
+ };
};
- twsi1_pmux: twsi1-pmux {
- groups = "G7";
- function = "twsi1";
+ chip_rst: reset {
+ compatible = "marvell,berlin2-reset";
+ #reset-cells = <2>;
};
};
@@ -382,7 +422,7 @@
compatible = "marvell,berlin2q-ahci", "generic-ahci";
reg = <0xe90000 0x1000>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&chip CLKID_SATA>;
+ clocks = <&chip_clk CLKID_SATA>;
#address-cells = <1>;
#size-cells = <0>;
@@ -402,7 +442,7 @@
sata_phy: phy@e900a0 {
compatible = "marvell,berlin2q-sata-phy";
reg = <0xe900a0 0x200>;
- clocks = <&chip CLKID_SATA>;
+ clocks = <&chip_clk CLKID_SATA>;
#address-cells = <1>;
#size-cells = <0>;
#phy-cells = <1>;
@@ -421,7 +461,7 @@
compatible = "chipidea,usb2";
reg = <0xed0000 0x10000>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&chip CLKID_USB0>;
+ clocks = <&chip_clk CLKID_USB0>;
phys = <&usb_phy0>;
phy-names = "usb-phy";
status = "disabled";
@@ -431,7 +471,7 @@
compatible = "chipidea,usb2";
reg = <0xee0000 0x10000>;
interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&chip CLKID_USB1>;
+ clocks = <&chip_clk CLKID_USB1>;
phys = <&usb_phy1>;
phy-names = "usb-phy";
status = "disabled";
@@ -526,27 +566,37 @@
};
sysctrl: pin-controller@d000 {
- compatible = "marvell,berlin2q-system-ctrl";
+ compatible = "simple-mfd", "syscon";
reg = <0xd000 0x100>;
- uart0_pmux: uart0-pmux {
- groups = "GSM12";
- function = "uart0";
- };
+ sys_pinctrl: pin-controller {
+ compatible = "marvell,berlin2q-system-pinctrl";
- uart1_pmux: uart1-pmux {
- groups = "GSM14";
- function = "uart1";
- };
+ uart0_pmux: uart0-pmux {
+ groups = "GSM12";
+ function = "uart0";
+ };
+
+ uart1_pmux: uart1-pmux {
+ groups = "GSM14";
+ function = "uart1";
+ };
+
+ twsi2_pmux: twsi2-pmux {
+ groups = "GSM13";
+ function = "twsi2";
+ };
- twsi2_pmux: twsi2-pmux {
- groups = "GSM13";
- function = "twsi2";
+ twsi3_pmux: twsi3-pmux {
+ groups = "GSM14";
+ function = "twsi3";
+ };
};
- twsi3_pmux: twsi3-pmux {
- groups = "GSM14";
- function = "twsi3";
+ adc: adc {
+ compatible = "marvell,berlin2-adc";
+ interrupts = <12>, <14>;
+ interrupt-names = "adc", "tsen";
};
};
diff --git a/arch/arm/boot/dts/cx92755.dtsi b/arch/arm/boot/dts/cx92755.dtsi
index 490c08075e67..af333261d046 100644
--- a/arch/arm/boot/dts/cx92755.dtsi
+++ b/arch/arm/boot/dts/cx92755.dtsi
@@ -82,6 +82,12 @@
clocks = <&main_clk>;
};
+ rtc@f0000c30 {
+ compatible = "cnxt,cx92755-rtc";
+ reg = <0xf0000c30 0x18>;
+ interrupts = <25>;
+ };
+
uc_regs: syscon@f00003a0 {
compatible = "cnxt,cx92755-uc", "syscon";
reg = <0xf00003a0 0x10>;
@@ -110,4 +116,15 @@
interrupts = <46>;
status = "disabled";
};
+
+ i2c: i2c@f0000120 {
+ compatible = "cnxt,cx92755-i2c";
+ reg = <0xf0000120 0x10>;
+ interrupts = <28>;
+ clocks = <&main_clk>;
+ clock-frequency = <100000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
};
diff --git a/arch/arm/boot/dts/cx92755_equinox.dts b/arch/arm/boot/dts/cx92755_equinox.dts
index f33bf5635d47..90d52cc416dc 100644
--- a/arch/arm/boot/dts/cx92755_equinox.dts
+++ b/arch/arm/boot/dts/cx92755_equinox.dts
@@ -72,3 +72,7 @@
&uart0 {
status = "okay";
};
+
+&i2c {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/dove-cm-a510.dts b/arch/arm/boot/dts/dove-cm-a510.dts
deleted file mode 100644
index 50c0d6904497..000000000000
--- a/arch/arm/boot/dts/dove-cm-a510.dts
+++ /dev/null
@@ -1,38 +0,0 @@
-/dts-v1/;
-
-#include "dove.dtsi"
-
-/ {
- model = "Compulab CM-A510";
- compatible = "compulab,cm-a510", "marvell,dove";
-
- memory {
- device_type = "memory";
- reg = <0x00000000 0x40000000>;
- };
-
- chosen {
- bootargs = "console=ttyS0,115200n8 earlyprintk";
- };
-};
-
-&uart0 { status = "okay"; };
-&uart1 { status = "okay"; };
-&sdio0 { status = "okay"; };
-&sdio1 { status = "okay"; };
-&sata0 { status = "okay"; };
-
-&spi0 {
- status = "okay";
-
- /* spi0.0: 4M Flash Winbond W25Q32BV */
- spi-flash@0 {
- compatible = "st,w25q32";
- spi-max-frequency = <20000000>;
- reg = <0>;
- };
-};
-
-&i2c0 {
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/dove-cm-a510.dtsi b/arch/arm/boot/dts/dove-cm-a510.dtsi
new file mode 100644
index 000000000000..59b4056b478f
--- /dev/null
+++ b/arch/arm/boot/dts/dove-cm-a510.dtsi
@@ -0,0 +1,195 @@
+/*
+ * Device Tree include for Compulab CM-A510 System-on-Module
+ *
+ * Copyright (C) 2015, Sebastian Hesselbarth <sebastian.hesselbarth@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; version 2 of the
+ * License.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to 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.
+ */
+
+/*
+ * The CM-A510 comes with several optional components:
+ *
+ * Memory options:
+ * D512: 512M
+ * D1024: 1G
+ *
+ * NAND options:
+ * N512: 512M NAND
+ *
+ * Ethernet options:
+ * E1: PHY RTL8211D on internal GbE (SMI address 0x03)
+ * E2: Additional ethernet NIC RTL8111D on PCIe1
+ *
+ * Audio options:
+ * A: TI TLV320AIC23b audio codec (I2C address 0x1a)
+ *
+ * Touchscreen options:
+ * I: TI TSC2046 touchscreen controller (on SPI1)
+ *
+ * USB options:
+ * U2: 2 dual-role USB2.0 ports
+ * U4: 2 additional USB2.0 host ports (via USB1)
+ *
+ * WiFi options:
+ * W: Broadcom BCM4319 802.11b/g/n (USI WM-N-BM-01 on SDIO1)
+ *
+ * GPIOs used on CM-A510:
+ * 1 GbE PHY reset (active low)
+ * 3 WakeUp
+ * 8 PowerOff (active low)
+ * 13 Touchscreen pen irq (active low)
+ * 65 System LED (active high)
+ * 69 USB Hub reset (active low)
+ * 70 WLAN reset (active low)
+ * 71 WLAN regulator (active high)
+ */
+
+#include "dove.dtsi"
+
+/ {
+ model = "Compulab CM-A510";
+ compatible = "compulab,cm-a510", "marvell,dove";
+
+ /*
+ * Set the minimum memory size here and let the
+ * bootloader set the real size.
+ */
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x20000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ /* Set upper NAND data bit to GPO */
+ pinctrl-0 = <&pmx_nand_gpo>;
+ pinctrl-names = "default";
+
+ system {
+ label = "cm-a510:system:green";
+ gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
+ default-state = "keep";
+ };
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wifi_power: regulator@1 {
+ compatible = "regulator-fixed";
+ regulator-name = "WiFi Power";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
+
+/* Optional RTL8211D GbE PHY on SMI address 0x03 */
+&ethphy {
+ reg = <3>;
+ status = "disabled";
+};
+
+&i2c0 {
+ /* Optional TI TLV320AIC23b audio codec */
+ opt_audio: audio@1a {
+ compatible = "ti,tlv320aic23";
+ reg = <0x1a>;
+ status = "disabled";
+ };
+};
+
+/* Optional RTL8111D GbE NIC on PCIe1 */
+&pcie { status = "disabled"; };
+
+&pcie1 {
+ pinctrl-0 = <&pmx_pcie1_clkreq>;
+ pinctrl-names = "default";
+ status = "disabled";
+};
+
+&pinctrl {
+ pmx_uart2: pmx-uart2 {
+ marvell,pins = "mpp14", "mpp15";
+ marvell,function = "uart2";
+ };
+};
+
+/* Optional Broadcom BCM4319 802.11b/g/n WiFi module */
+&sdio1 {
+ non-removable;
+ vmmc-supply = <&wifi_power>;
+ reset-gpio = <&gpio2 6 GPIO_ACTIVE_LOW>;
+ status = "disabled";
+};
+
+&spi0 {
+ status = "okay";
+
+ /* 1M Flash Winbond W25Q80BL */
+ flash@0 {
+ compatible = "winbond,w25q80";
+ spi-max-frequency = <80000000>;
+ reg = <0>;
+ };
+};
+
+&spi1 {
+ pinctrl-0 = <&pmx_spi1_20_23>;
+ pinctrl-names = "default";
+ status = "disabled";
+
+ /* Optional TI TSC2046 touchscreen controller */
+ opt_touch: touchscreen@0 {
+ compatible = "ti,tsc2046";
+ spi-max-frequency = <2500000>;
+ reg = <0>;
+ pinctrl-0 = <&pmx_gpio_13>;
+ pinctrl-names = "default";
+ interrupts-extended = <&gpio0 13 IRQ_TYPE_EDGE_FALLING>;
+ };
+};
+
+&uart2 {
+ pinctrl-0 = <&pmx_uart2>;
+ pinctrl-names = "default";
+};
diff --git a/arch/arm/boot/dts/dove-sbc-a510.dts b/arch/arm/boot/dts/dove-sbc-a510.dts
new file mode 100644
index 000000000000..288e707dea99
--- /dev/null
+++ b/arch/arm/boot/dts/dove-sbc-a510.dts
@@ -0,0 +1,182 @@
+/*
+ * Device Tree file for Compulab SBC-A510 Single Board Computer
+ *
+ * Copyright (C) 2015, Sebastian Hesselbarth <sebastian.hesselbarth@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; version 2 of the
+ * License.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to 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.
+ */
+
+/*
+ * SBC-A510 comprises a PCA9555 I2C GPIO expander its GPIO lines connected to
+ *
+ * 0.0 USB0 VBUS_EN (active high)
+ * 0.1 USB0 VBUS_GOOD
+ * 0.2 DVI transmitter TI TFP410 MSEN
+ * 0.3 DVI transmitter TI TFP410 PD# (active low power down)
+ * 0.4 LVDS transmitter DS90C365 PD# (active low power down)
+ * 0.5 LCD nRST (active low reset)
+ * 0.6 PCIe0 nRST (active low reset)
+ * 0.7 mini-PCIe slot W_DISABLE#
+ *
+ * 1.0 MMC WP
+ * 1.1 Camera Input FPC FLASH_STB and P21.5
+ * 1.2 Camera Input FPC WE and P21.22
+ * 1.3 MMC VCC_EN (active high) and P21.7
+ * 1.4 Camera Input FPC AFTR_RST and P21.17
+ * 1.5 Camera Input FPC OE and P21.19
+ * 1.6 Camera Input FPC SNPSHT and P21.6
+ * 1.7 Camera Input FPC SHTR and P21.10
+ */
+
+/dts-v1/;
+
+#include "dove-cm-a510.dtsi"
+
+/ {
+ model = "Compulab SBC-A510";
+ compatible = "compulab,sbc-a510", "compulab,cm-a510", "marvell,dove";
+
+ chosen {
+ stdout-path = &uart0;
+ };
+
+ regulators {
+ usb0_power: regulator@2 {
+ compatible = "regulator-fixed";
+ regulator-name = "USB Power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio_ext 0 GPIO_ACTIVE_HIGH>;
+ };
+
+ mmc_power: regulator@3 {
+ compatible = "regulator-fixed";
+ regulator-name = "MMC Power";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio_ext 13 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
+
+/* Ethernet0 depends on CM-A510 option E1 */
+&mdio { status = "disabled"; };
+&eth { status = "disabled"; };
+&ethphy { status = "disabled"; };
+
+/*
+ * USB port 0 can be powered and monitored by I2C GPIO expander:
+ * VBUS_ENABLE on GPIO0, VBUS_GOOD on GPIO1
+ */
+&ehci0 {
+ status = "okay";
+ vbus-supply = <&usb0_power>;
+};
+
+/* USB port 1 (and ports 2, 3 if CM-A510 has U4 option) */
+&ehci1 { status = "okay"; };
+
+/*
+ * I2C bus layout:
+ * i2c0:
+ * - Audio Codec, 0x1a (option from CM-A510)
+ * - DVI transmitter TI TFP410, 0x39
+ * - HDMI/DVI DDC channel
+ * i2c1:
+ * - GPIO expander, NXP PCA9555, 0x20
+ * - VGA DDC channel
+ */
+&i2c {
+ pinctrl-0 = <&pmx_i2c1>;
+ pinctrl-names = "default";
+};
+
+&i2c0 {
+ /* TI TFP410 DVI transmitter */
+ dvi: video@39 {
+ compatible = "ti,tfp410";
+ reg = <0x39>;
+ powerdown-gpio = <&gpio_ext 3 GPIO_ACTIVE_LOW>;
+ };
+};
+
+&i2c1 {
+ status = "okay";
+
+ /* NXP PCA9555 GPIO expander */
+ gpio_ext: gpio@20 {
+ compatible = "nxp,pca9555";
+ reg = <0x20>;
+ #gpio-cells = <2>;
+ };
+};
+
+&pcie { status = "okay"; };
+
+/*
+ * PCIe0 can be configured by Jumper E1 to be either connected to
+ * a mini-PCIe slot or a Pericom PI7C9X111 PCIe-to-PCI bridge.
+ */
+&pcie0 {
+ status = "okay";
+ pinctrl-0 = <&pmx_pcie0_clkreq>;
+ pinctrl-names = "default";
+ reset-gpios = <&gpio_ext 6 GPIO_ACTIVE_LOW>;
+};
+
+/* Ethernet1 depends on CM-A510 option E2 */
+&pcie1 { status = "disabled"; };
+
+/* SATA connector */
+&sata0 { status = "okay"; };
+
+/*
+ * SDIO0 is connected to a MMC/SD/SDIO socket, I2C GPIO expander has
+ * VCC_MMC_ENABLE on GPIO13, MMC_WP on GPIO10
+ */
+&sdio0 {
+ vmmc-supply = <&mmc_power>;
+ wp-gpios = <&gpio_ext 10 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+/* UART0 on RS232 mini-connector */
+&uart0 { status = "okay"; };
+/* UART2 on pin headers */
+&uart2 { status = "okay"; };
diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi
index 9ad829523a13..38b1f7e6004e 100644
--- a/arch/arm/boot/dts/dove.dtsi
+++ b/arch/arm/boot/dts/dove.dtsi
@@ -33,6 +33,42 @@
marvell,tauros2-cache-features = <0>;
};
+ i2c-mux {
+ compatible = "i2c-mux-pinctrl";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c-parent = <&i2c>;
+
+ pinctrl-names = "i2c0", "i2c1", "i2c2";
+ pinctrl-0 = <&pmx_i2cmux_0>;
+ pinctrl-1 = <&pmx_i2cmux_1>;
+ pinctrl-2 = <&pmx_i2cmux_2>;
+
+ i2c0: i2c@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+ };
+
+ i2c1: i2c@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ /* Requires pmx_i2c1 on i2c controller node */
+ status = "disabled";
+ };
+
+ i2c2: i2c@2 {
+ reg = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ /* Requires pmx_i2c2 on i2c controller node */
+ status = "disabled";
+ };
+ };
+
mbus {
compatible = "marvell,dove-mbus", "marvell,mbus", "simple-bus";
#address-cells = <2>;
@@ -123,7 +159,7 @@
status = "disabled";
};
- i2c0: i2c-ctrl@11000 {
+ i2c: i2c-ctrl@11000 {
compatible = "marvell,mv64xxx-i2c";
reg = <0x11000 0x20>;
#address-cells = <1>;
@@ -132,7 +168,7 @@
clock-frequency = <400000>;
timeout-ms = <1000>;
clocks = <&core_clk 0>;
- status = "disabled";
+ status = "okay";
};
uart0: serial@12000 {
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index f03a091cd076..8f1e25bcecbd 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -131,6 +131,11 @@
regulator-max-microvolt = <3000000>;
};
};
+
+ scm_conf_clocks: clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
};
dra7_pmx_core: pinmux@1400 {
@@ -1469,6 +1474,44 @@
clocks = <&sys_clkin1>;
status = "disabled";
};
+
+ dss: dss@58000000 {
+ compatible = "ti,dra7-dss";
+ /* 'reg' defined in dra72x.dtsi and dra74x.dtsi */
+ /* 'clocks' defined in dra72x.dtsi and dra74x.dtsi */
+ status = "disabled";
+ ti,hwmods = "dss_core";
+ /* CTRL_CORE_DSS_PLL_CONTROL */
+ syscon-pll-ctrl = <&scm_conf 0x538>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ dispc@58001000 {
+ compatible = "ti,dra7-dispc";
+ reg = <0x58001000 0x1000>;
+ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ ti,hwmods = "dss_dispc";
+ clocks = <&dss_dss_clk>;
+ clock-names = "fck";
+ /* CTRL_CORE_SMA_SW_1 */
+ syscon-pol = <&scm_conf 0x534>;
+ };
+
+ hdmi: encoder@58060000 {
+ compatible = "ti,dra7-hdmi";
+ reg = <0x58040000 0x200>,
+ <0x58040200 0x80>,
+ <0x58040300 0x80>,
+ <0x58060000 0x19000>;
+ reg-names = "wp", "pll", "phy", "core";
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ ti,hwmods = "dss_hdmi";
+ clocks = <&dss_48mhz_clk>, <&dss_hdmi_clk>;
+ clock-names = "fck", "sys_clk";
+ };
+ };
};
thermal_zones: thermal-zones {
diff --git a/arch/arm/boot/dts/dra72-evm.dts b/arch/arm/boot/dts/dra72-evm.dts
index ce0390f081d9..4e1b60581782 100644
--- a/arch/arm/boot/dts/dra72-evm.dts
+++ b/arch/arm/boot/dts/dra72-evm.dts
@@ -19,6 +19,10 @@
reg = <0x80000000 0x40000000>; /* 1024 MB */
};
+ aliases {
+ display0 = &hdmi0;
+ };
+
evm_3v3: fixedregulator-evm_3v3 {
compatible = "regulator-fixed";
regulator-name = "evm_3v3";
@@ -35,6 +39,51 @@
compatible = "linux,extcon-usb-gpio";
id-gpio = <&pcf_gpio_21 2 GPIO_ACTIVE_HIGH>;
};
+
+ hdmi0: connector {
+ compatible = "hdmi-connector";
+ label = "hdmi";
+
+ type = "a";
+
+ port {
+ hdmi_connector_in: endpoint {
+ remote-endpoint = <&tpd12s015_out>;
+ };
+ };
+ };
+
+ tpd12s015: encoder {
+ compatible = "ti,tpd12s015";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&tpd12s015_pins>;
+
+ gpios = <&pcf_hdmi 4 GPIO_ACTIVE_HIGH>, /* P4, CT CP HPD */
+ <&pcf_hdmi 5 GPIO_ACTIVE_HIGH>, /* P5, LS OE */
+ <&gpio7 12 GPIO_ACTIVE_HIGH>; /* gpio7_12/sp1_cs2, HPD */
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ tpd12s015_in: endpoint {
+ remote-endpoint = <&hdmi_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ tpd12s015_out: endpoint {
+ remote-endpoint = <&hdmi_connector_in>;
+ };
+ };
+ };
+ };
};
&dra7_pmx_core {
@@ -45,6 +94,13 @@
>;
};
+ 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 */
+ >;
+ };
+
nand_default: nand_default {
pinctrl-single,pins = <
0x0 (PIN_INPUT | MUX_MODE0) /* gpmc_ad0 */
@@ -142,6 +198,19 @@
0xb8 (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 */
+ >;
+ };
+
+ tpd12s015_pins: pinmux_tpd12s015_pins {
+ pinctrl-single,pins = <
+ 0x3b8 (PIN_INPUT_PULLDOWN | MUX_MODE14) /* gpio7_12 HPD */
+ >;
+ };
};
&i2c1 {
@@ -277,6 +346,27 @@
};
};
+&i2c5 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c5_pins>;
+ clock-frequency = <400000>;
+
+ pcf_hdmi: pcf8575@26 {
+ compatible = "nxp,pcf8575";
+ reg = <0x26>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ /*
+ * initial state is used here to keep the mdio interface
+ * selected on RU89 through SEL_VIN4_MUX_S0, VIN2_S1 and
+ * VIN2_S0 driven high otherwise Ethernet stops working
+ * VIN6_SEL_S0 is low, thus selecting McASP3 over VIN6
+ */
+ lines-initial-states = <0x0f2b>;
+ };
+};
+
&uart1 {
status = "okay";
};
@@ -566,3 +656,23 @@
};
};
};
+
+&dss {
+ status = "ok";
+
+ vdda_video-supply = <&ldo5_reg>;
+};
+
+&hdmi {
+ status = "ok";
+ vdda-supply = <&ldo3_reg>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_pins>;
+
+ port {
+ hdmi_out: endpoint {
+ remote-endpoint = <&tpd12s015_in>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/dra72x.dtsi b/arch/arm/boot/dts/dra72x.dtsi
index 03d742f8d572..eaca143faa77 100644
--- a/arch/arm/boot/dts/dra72x.dtsi
+++ b/arch/arm/boot/dts/dra72x.dtsi
@@ -34,3 +34,14 @@
interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
};
};
+
+&dss {
+ reg = <0x58000000 0x80>,
+ <0x58004054 0x4>,
+ <0x58004300 0x20>;
+ reg-names = "dss", "pll1_clkctrl", "pll1";
+
+ clocks = <&dss_dss_clk>,
+ <&dss_video1_clk>;
+ clock-names = "fck", "video1_clk";
+};
diff --git a/arch/arm/boot/dts/dra74x.dtsi b/arch/arm/boot/dts/dra74x.dtsi
index cc560a70926f..fa995d0ca1f2 100644
--- a/arch/arm/boot/dts/dra74x.dtsi
+++ b/arch/arm/boot/dts/dra74x.dtsi
@@ -73,3 +73,18 @@
};
};
};
+
+&dss {
+ reg = <0x58000000 0x80>,
+ <0x58004054 0x4>,
+ <0x58004300 0x20>,
+ <0x58005054 0x4>,
+ <0x58005300 0x20>;
+ reg-names = "dss", "pll1_clkctrl", "pll1",
+ "pll2_clkctrl", "pll2";
+
+ clocks = <&dss_dss_clk>,
+ <&dss_video1_clk>,
+ <&dss_video2_clk>;
+ clock-names = "fck", "video1_clk", "video2_clk";
+};
diff --git a/arch/arm/boot/dts/dra7xx-clocks.dtsi b/arch/arm/boot/dts/dra7xx-clocks.dtsi
index 3b933f74d000..357bedeebfac 100644
--- a/arch/arm/boot/dts/dra7xx-clocks.dtsi
+++ b/arch/arm/boot/dts/dra7xx-clocks.dtsi
@@ -1531,6 +1531,7 @@
clocks = <&dpll_per_h12x2_ck>;
ti,bit-shift = <8>;
reg = <0x1120>;
+ ti,set-rate-parent;
};
dss_hdmi_clk: dss_hdmi_clk {
@@ -2136,3 +2137,13 @@
clocks = <&dpll_usb_ck>;
};
};
+
+&scm_conf_clocks {
+ dss_deshdcp_clk: dss_deshdcp_clk {
+ #clock-cells = <0>;
+ compatible = "ti,gate-clock";
+ clocks = <&l3_iclk_div>;
+ ti,bit-shift = <0>;
+ reg = <0x558>;
+ };
+};
diff --git a/arch/arm/boot/dts/emev2-kzm9d.dts b/arch/arm/boot/dts/emev2-kzm9d.dts
index 19446273e4a7..1dee0aa4f40c 100644
--- a/arch/arm/boot/dts/emev2-kzm9d.dts
+++ b/arch/arm/boot/dts/emev2-kzm9d.dts
@@ -81,7 +81,7 @@
regulator-boot-on;
};
- lan9220@20000000 {
+ ethernet@20000000 {
compatible = "smsc,lan9220", "smsc,lan9115";
reg = <0x20000000 0x10000>;
phy-mode = "mii";
@@ -96,7 +96,7 @@
};
&pfc {
- uart1_pins: uart@e1030000 {
+ uart1_pins: serial@e1030000 {
renesas,groups = "uart1_ctrl", "uart1_data";
renesas,function = "uart1";
};
diff --git a/arch/arm/boot/dts/exynos3250-monk.dts b/arch/arm/boot/dts/exynos3250-monk.dts
index 1d483c1c8b48..a5863acc5fff 100644
--- a/arch/arm/boot/dts/exynos3250-monk.dts
+++ b/arch/arm/boot/dts/exynos3250-monk.dts
@@ -16,6 +16,7 @@
#include "exynos3250.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/samsung,s2mps11.h>
/ {
model = "Samsung Monk board";
@@ -432,7 +433,7 @@
};
&rtc {
- clocks = <&cmu CLK_RTC>, <&s2mps14_osc 0>;
+ clocks = <&cmu CLK_RTC>, <&s2mps14_osc S2MPS11_CLK_AP>;
clock-names = "rtc", "rtc_src";
status = "okay";
};
diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts
index 0b9906880c0c..031853b75528 100644
--- a/arch/arm/boot/dts/exynos3250-rinato.dts
+++ b/arch/arm/boot/dts/exynos3250-rinato.dts
@@ -16,6 +16,7 @@
#include "exynos3250.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/samsung,s2mps11.h>
/ {
model = "Samsung Rinato board";
@@ -567,6 +568,10 @@
status = "okay";
};
+&jpeg {
+ status = "okay";
+};
+
&mshc_0 {
#address-cells = <1>;
#size-cells = <0>;
@@ -605,7 +610,7 @@
};
&rtc {
- clocks = <&cmu CLK_RTC>, <&s2mps14_osc 0>;
+ clocks = <&cmu CLK_RTC>, <&s2mps14_osc S2MPS11_CLK_AP>;
clock-names = "rtc", "rtc_src";
status = "okay";
};
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index e3bfb11c6ef8..d7201333e3bc 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -189,7 +189,7 @@
};
rtc: rtc@10070000 {
- compatible = "samsung,exynos3250-rtc";
+ compatible = "samsung,s3c6410-rtc";
reg = <0x10070000 0x100>;
interrupts = <0 73 0>, <0 74 0>;
interrupt-parent = <&pmu_system_controller>;
@@ -243,6 +243,30 @@
interrupts = <0 240 0>;
};
+ jpeg: codec@11830000 {
+ compatible = "samsung,exynos3250-jpeg";
+ reg = <0x11830000 0x1000>;
+ interrupts = <0 171 0>;
+ clocks = <&cmu CLK_JPEG>, <&cmu CLK_SCLK_JPEG>;
+ clock-names = "jpeg", "sclk";
+ power-domains = <&pd_cam>;
+ assigned-clocks = <&cmu CLK_MOUT_CAM_BLK>, <&cmu CLK_SCLK_JPEG>;
+ assigned-clock-rates = <0>, <150000000>;
+ assigned-clock-parents = <&cmu CLK_DIV_MPLL_PRE>;
+ iommus = <&sysmmu_jpeg>;
+ status = "disabled";
+ };
+
+ sysmmu_jpeg: sysmmu@11A60000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11a60000 0x1000>;
+ interrupts = <0 156 0>, <0 161 0>;
+ clock-names = "sysmmu", "master";
+ clocks = <&cmu CLK_SMMUJPEG>, <&cmu CLK_JPEG>;
+ power-domains = <&pd_cam>;
+ #iommu-cells = <0>;
+ };
+
fimd: fimd@11c00000 {
compatible = "samsung,exynos3250-fimd";
reg = <0x11c00000 0x30000>;
@@ -251,6 +275,7 @@
clocks = <&cmu CLK_SCLK_FIMD0>, <&cmu CLK_FIMD0>;
clock-names = "sclk_fimd", "fimd";
power-domains = <&pd_lcd0>;
+ iommus = <&sysmmu_fimd0>;
samsung,sysreg = <&sys_reg>;
status = "disabled";
};
@@ -270,6 +295,16 @@
status = "disabled";
};
+ sysmmu_fimd0: sysmmu@11E20000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11e20000 0x1000>;
+ interrupts = <0 80 0>, <0 81 0>;
+ clock-names = "sysmmu", "master";
+ clocks = <&cmu CLK_SMMUFIMD0>, <&cmu CLK_FIMD0>;
+ power-domains = <&pd_lcd0>;
+ #iommu-cells = <0>;
+ };
+
hsotg: hsotg@12480000 {
compatible = "snps,dwc2";
reg = <0x12480000 0x20000>;
@@ -364,9 +399,20 @@
clock-names = "mfc", "sclk_mfc";
clocks = <&cmu CLK_MFC>, <&cmu CLK_SCLK_MFC>;
power-domains = <&pd_mfc>;
+ iommus = <&sysmmu_mfc>;
status = "disabled";
};
+ sysmmu_mfc: sysmmu@13620000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13620000 0x1000>;
+ interrupts = <0 96 0>, <0 98 0>;
+ clock-names = "sysmmu", "master";
+ clocks = <&cmu CLK_SMMUMFC_L>, <&cmu CLK_MFC>;
+ power-domains = <&pd_mfc>;
+ #iommu-cells = <0>;
+ };
+
serial_0: serial@13800000 {
compatible = "samsung,exynos4210-uart";
reg = <0x13800000 0x100>;
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index e20cdc24c3bb..b0d52b1a646a 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -78,7 +78,6 @@
mipi_phy: video-phy@10020710 {
compatible = "samsung,s5pv210-mipi-video-phy";
- reg = <0x10020710 8>;
#phy-cells = <1>;
syscon = <&pmu_system_controller>;
};
@@ -167,7 +166,7 @@
phys = <&mipi_phy 1>;
phy-names = "dsim";
clocks = <&clock CLK_DSIM0>, <&clock CLK_SCLK_MIPI0>;
- clock-names = "bus_clk", "pll_clk";
+ clock-names = "bus_clk", "sclk_mipi";
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
@@ -190,6 +189,7 @@
clock-names = "fimc", "sclk_fimc";
power-domains = <&pd_cam>;
samsung,sysreg = <&sys_reg>;
+ iommus = <&sysmmu_fimc0>;
status = "disabled";
};
@@ -201,6 +201,7 @@
clock-names = "fimc", "sclk_fimc";
power-domains = <&pd_cam>;
samsung,sysreg = <&sys_reg>;
+ iommus = <&sysmmu_fimc1>;
status = "disabled";
};
@@ -212,6 +213,7 @@
clock-names = "fimc", "sclk_fimc";
power-domains = <&pd_cam>;
samsung,sysreg = <&sys_reg>;
+ iommus = <&sysmmu_fimc2>;
status = "disabled";
};
@@ -223,6 +225,7 @@
clock-names = "fimc", "sclk_fimc";
power-domains = <&pd_cam>;
samsung,sysreg = <&sys_reg>;
+ iommus = <&sysmmu_fimc3>;
status = "disabled";
};
@@ -257,7 +260,7 @@
};
};
- watchdog@10060000 {
+ watchdog: watchdog@10060000 {
compatible = "samsung,s3c2410-wdt";
reg = <0x10060000 0x100>;
interrupts = <0 43 0>;
@@ -266,7 +269,7 @@
status = "disabled";
};
- rtc@10070000 {
+ rtc: rtc@10070000 {
compatible = "samsung,s3c6410-rtc";
reg = <0x10070000 0x100>;
interrupt-parent = <&pmu_system_controller>;
@@ -276,7 +279,7 @@
status = "disabled";
};
- keypad@100A0000 {
+ keypad: keypad@100A0000 {
compatible = "samsung,s5pv210-keypad";
reg = <0x100A0000 0x100>;
interrupts = <0 109 0>;
@@ -285,7 +288,7 @@
status = "disabled";
};
- sdhci@12510000 {
+ sdhci_0: sdhci@12510000 {
compatible = "samsung,exynos4210-sdhci";
reg = <0x12510000 0x100>;
interrupts = <0 73 0>;
@@ -294,7 +297,7 @@
status = "disabled";
};
- sdhci@12520000 {
+ sdhci_1: sdhci@12520000 {
compatible = "samsung,exynos4210-sdhci";
reg = <0x12520000 0x100>;
interrupts = <0 74 0>;
@@ -303,7 +306,7 @@
status = "disabled";
};
- sdhci@12530000 {
+ sdhci_2: sdhci@12530000 {
compatible = "samsung,exynos4210-sdhci";
reg = <0x12530000 0x100>;
interrupts = <0 75 0>;
@@ -312,7 +315,7 @@
status = "disabled";
};
- sdhci@12540000 {
+ sdhci_3: sdhci@12540000 {
compatible = "samsung,exynos4210-sdhci";
reg = <0x12540000 0x100>;
interrupts = <0 76 0>;
@@ -331,7 +334,7 @@
status = "disabled";
};
- hsotg@12480000 {
+ hsotg: hsotg@12480000 {
compatible = "samsung,s3c6400-hsotg";
reg = <0x12480000 0x20000>;
interrupts = <0 71 0>;
@@ -342,7 +345,7 @@
status = "disabled";
};
- ehci@12580000 {
+ ehci: ehci@12580000 {
compatible = "samsung,exynos4210-ehci";
reg = <0x12580000 0x100>;
interrupts = <0 70 0>;
@@ -368,7 +371,7 @@
};
};
- ohci@12590000 {
+ ohci: ohci@12590000 {
compatible = "samsung,exynos4210-ohci";
reg = <0x12590000 0x100>;
interrupts = <0 70 0>;
@@ -417,6 +420,8 @@
power-domains = <&pd_mfc>;
clocks = <&clock CLK_MFC>, <&clock CLK_SCLK_MFC>;
clock-names = "mfc", "sclk_mfc";
+ iommus = <&sysmmu_mfc_l>, <&sysmmu_mfc_r>;
+ iommu-names = "left", "right";
status = "disabled";
};
@@ -621,7 +626,7 @@
status = "disabled";
};
- pwm@139D0000 {
+ pwm: pwm@139D0000 {
compatible = "samsung,exynos4210-pwm";
reg = <0x139D0000 0x1000>;
interrupts = <0 37 0>, <0 38 0>, <0 39 0>, <0 40 0>, <0 41 0>;
@@ -681,6 +686,7 @@
clocks = <&clock CLK_SCLK_FIMD0>, <&clock CLK_FIMD0>;
clock-names = "sclk_fimd", "fimd";
power-domains = <&pd_lcd0>;
+ iommus = <&sysmmu_fimd0>;
samsung,sysreg = <&sys_reg>;
status = "disabled";
};
@@ -689,6 +695,15 @@
#include "exynos4412-tmu-sensor-conf.dtsi"
};
+ jpeg_codec: jpeg-codec@11840000 {
+ compatible = "samsung,exynos4210-jpeg";
+ reg = <0x11840000 0x1000>;
+ interrupts = <0 88 0>;
+ clocks = <&clock CLK_JPEG>;
+ clock-names = "jpeg";
+ power-domains = <&pd_cam>;
+ };
+
hdmi: hdmi@12D00000 {
compatible = "samsung,exynos4210-hdmi";
reg = <0x12D00000 0x70000>;
@@ -709,6 +724,7 @@
interrupts = <0 91 0>;
reg = <0x12C10000 0x2100>, <0x12c00000 0x300>;
power-domains = <&pd_tv>;
+ iommus = <&sysmmu_tv>;
status = "disabled";
};
@@ -819,4 +835,114 @@
clock-names = "ppmu";
status = "disabled";
};
+
+ sysmmu_mfc_l: sysmmu@13620000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13620000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <5 5>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MFCL>, <&clock CLK_MFC>;
+ power-domains = <&pd_mfc>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_mfc_r: sysmmu@13630000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13630000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <5 6>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MFCR>, <&clock CLK_MFC>;
+ power-domains = <&pd_mfc>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_tv: sysmmu@12E20000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x12E20000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <5 4>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_TV>, <&clock CLK_MIXER>;
+ power-domains = <&pd_tv>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc0: sysmmu@11A20000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11A20000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <4 2>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_FIMC0>, <&clock CLK_FIMC0>;
+ power-domains = <&pd_cam>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc1: sysmmu@11A30000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11A30000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <4 3>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_FIMC1>, <&clock CLK_FIMC1>;
+ power-domains = <&pd_cam>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc2: sysmmu@11A40000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11A40000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <4 4>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_FIMC2>, <&clock CLK_FIMC2>;
+ power-domains = <&pd_cam>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc3: sysmmu@11A50000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11A50000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <4 5>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_FIMC3>, <&clock CLK_FIMC3>;
+ power-domains = <&pd_cam>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_jpeg: sysmmu@11A60000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11A60000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <4 6>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_JPEG>, <&clock CLK_JPEG>;
+ power-domains = <&pd_cam>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_rotator: sysmmu@12A30000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x12A30000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <5 0>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_ROTATOR>, <&clock CLK_ROTATOR>;
+ power-domains = <&pd_lcd0>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimd0: sysmmu@11E20000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11E20000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <5 2>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_FIMD0>, <&clock CLK_FIMD0>;
+ power-domains = <&pd_lcd0>;
+ #iommu-cells = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts
index b81146141402..e0abfc3324d1 100644
--- a/arch/arm/boot/dts/exynos4210-origen.dts
+++ b/arch/arm/boot/dts/exynos4210-origen.dts
@@ -50,209 +50,6 @@
};
};
- watchdog@10060000 {
- status = "okay";
- };
-
- rtc@10070000 {
- status = "okay";
- };
-
- tmu@100C0000 {
- status = "okay";
- };
-
- sdhci@12530000 {
- bus-width = <4>;
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4 &sd2_cd>;
- pinctrl-names = "default";
- vmmc-supply = <&mmc_reg>;
- status = "okay";
- };
-
- sdhci@12510000 {
- bus-width = <4>;
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_cd>;
- pinctrl-names = "default";
- vmmc-supply = <&mmc_reg>;
- status = "okay";
- };
-
- g2d@12800000 {
- status = "okay";
- };
-
- codec@13400000 {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
- status = "okay";
- };
-
- serial@13800000 {
- status = "okay";
- };
-
- serial@13810000 {
- status = "okay";
- };
-
- serial@13820000 {
- status = "okay";
- };
-
- serial@13830000 {
- status = "okay";
- };
-
- i2c@13860000 {
- status = "okay";
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <20000>;
- pinctrl-0 = <&i2c0_bus>;
- pinctrl-names = "default";
-
- max8997_pmic@66 {
- compatible = "maxim,max8997-pmic";
- reg = <0x66>;
- interrupt-parent = <&gpx0>;
- interrupts = <4 0>, <3 0>;
-
- max8997,pmic-buck1-dvs-voltage = <1350000>;
- max8997,pmic-buck2-dvs-voltage = <1100000>;
- max8997,pmic-buck5-dvs-voltage = <1200000>;
-
- 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;
- };
-
- ldo3_reg: LDO3 {
- regulator-name = "VMIPI_1.1V";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- };
-
- ldo4_reg: LDO4 {
- regulator-name = "VDD_RTC_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo6_reg: LDO6 {
- regulator-name = "VMIPI_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo7_reg: LDO7 {
- regulator-name = "VDD_AUD_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo8_reg: LDO8 {
- regulator-name = "VADC_3.3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
-
- ldo9_reg: LDO9 {
- regulator-name = "DVDD_SWB_2.8V";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- };
-
- ldo10_reg: LDO10 {
- regulator-name = "VDD_PLL_1.1V";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- };
-
- ldo11_reg: LDO11 {
- regulator-name = "VDD_AUD_3V";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- };
-
- ldo14_reg: LDO14 {
- regulator-name = "AVDD18_SWB_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo17_reg: LDO17 {
- regulator-name = "VDD_SWB_3.3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- };
-
- ldo21_reg: LDO21 {
- regulator-name = "VDD_MIF_1.2V";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- };
-
- buck1_reg: BUCK1 {
- /*
- * HACK: The real name is VDD_ARM_1.2V,
- * but exynos-cpufreq does not support
- * DT-based regulator lookup yet.
- */
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck2_reg: BUCK2 {
- regulator-name = "VDD_INT_1.1V";
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck3_reg: BUCK3 {
- regulator-name = "VDD_G3D_1.1V";
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1100000>;
- };
-
- buck5_reg: BUCK5 {
- regulator-name = "VDDQ_M1M2_1.2V";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- };
-
- buck7_reg: BUCK7 {
- regulator-name = "VDD_LCD_3.3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
- regulator-always-on;
- };
- };
- };
- };
-
gpio_keys {
compatible = "gpio-keys";
#address-cells = <1>;
@@ -314,12 +111,6 @@
};
};
- fimd@11c00000 {
- pinctrl-0 = <&lcd_en &lcd_clk &lcd_data24 &pwm0_out>;
- pinctrl-names = "default";
- status = "okay";
- };
-
display-timings {
native-mode = <&timing0>;
timing0: timing {
@@ -335,3 +126,212 @@
};
};
};
+
+&fimd {
+ pinctrl-0 = <&lcd_en &lcd_clk &lcd_data24 &pwm0_out>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
+&g2d {
+ status = "okay";
+};
+
+&i2c_0 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <20000>;
+ pinctrl-0 = <&i2c0_bus>;
+ pinctrl-names = "default";
+
+ max8997_pmic@66 {
+ compatible = "maxim,max8997-pmic";
+ reg = <0x66>;
+ interrupt-parent = <&gpx0>;
+ interrupts = <4 0>, <3 0>;
+
+ max8997,pmic-buck1-dvs-voltage = <1350000>;
+ max8997,pmic-buck2-dvs-voltage = <1100000>;
+ max8997,pmic-buck5-dvs-voltage = <1200000>;
+
+ 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;
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "VMIPI_1.1V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ ldo4_reg: LDO4 {
+ regulator-name = "VDD_RTC_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "VMIPI_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "VDD_AUD_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "VADC_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo9_reg: LDO9 {
+ regulator-name = "DVDD_SWB_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "VDD_PLL_1.1V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "VDD_AUD_3V";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ ldo14_reg: LDO14 {
+ regulator-name = "AVDD18_SWB_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo17_reg: LDO17 {
+ regulator-name = "VDD_SWB_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ ldo21_reg: LDO21 {
+ regulator-name = "VDD_MIF_1.2V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ buck1_reg: BUCK1 {
+ /*
+ * HACK: The real name is VDD_ARM_1.2V,
+ * but exynos-cpufreq does not support
+ * DT-based regulator lookup yet.
+ */
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "VDD_INT_1.1V";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "VDD_G3D_1.1V";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "VDDQ_M1M2_1.2V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ buck7_reg: BUCK7 {
+ regulator-name = "VDD_LCD_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
+&mfc {
+ samsung,mfc-r = <0x43000000 0x800000>;
+ samsung,mfc-l = <0x51000000 0x800000>;
+ status = "okay";
+};
+
+&sdhci_0 {
+ bus-width = <4>;
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_cd>;
+ pinctrl-names = "default";
+ vmmc-supply = <&mmc_reg>;
+ status = "okay";
+};
+
+&sdhci_2 {
+ bus-width = <4>;
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4 &sd2_cd>;
+ pinctrl-names = "default";
+ vmmc-supply = <&mmc_reg>;
+ status = "okay";
+};
+
+&serial_0 {
+ status = "okay";
+};
+
+&serial_1 {
+ status = "okay";
+};
+
+&serial_2 {
+ status = "okay";
+};
+
+&serial_3 {
+ status = "okay";
+};
+
+&rtc {
+ status = "okay";
+};
+
+&tmu {
+ status = "okay";
+};
+
+&watchdog {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/exynos4210-smdkv310.dts b/arch/arm/boot/dts/exynos4210-smdkv310.dts
index 86216fff1b4f..043b03caff8f 100644
--- a/arch/arm/boot/dts/exynos4210-smdkv310.dts
+++ b/arch/arm/boot/dts/exynos4210-smdkv310.dts
@@ -30,181 +30,181 @@
stdout-path = &serial_1;
};
- sdhci@12530000 {
- bus-width = <4>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
- status = "okay";
- };
+ fixed-rate-clocks {
+ xxti {
+ compatible = "samsung,clock-xxti";
+ clock-frequency = <12000000>;
+ };
- g2d@12800000 {
- status = "okay";
+ xusbxti {
+ compatible = "samsung,clock-xusbxti";
+ clock-frequency = <24000000>;
+ };
};
+};
- codec@13400000 {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
- status = "okay";
- };
+&g2d {
+ status = "okay";
+};
- serial@13800000 {
- status = "okay";
- };
+&i2c_0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <100000>;
+ status = "okay";
- serial@13810000 {
- status = "okay";
+ eeprom@50 {
+ compatible = "samsung,24ad0xd1";
+ reg = <0x50>;
};
- serial@13820000 {
- status = "okay";
+ eeprom@52 {
+ compatible = "samsung,24ad0xd1";
+ reg = <0x52>;
};
+};
- serial@13830000 {
- status = "okay";
+&keypad {
+ samsung,keypad-num-rows = <2>;
+ samsung,keypad-num-columns = <8>;
+ linux,keypad-no-autorepeat;
+ linux,keypad-wakeup;
+ pinctrl-names = "default";
+ pinctrl-0 = <&keypad_rows &keypad_cols>;
+ status = "okay";
+
+ key_1 {
+ keypad,row = <0>;
+ keypad,column = <3>;
+ linux,code = <2>;
};
- pinctrl@11000000 {
- keypad_rows: keypad-rows {
- samsung,pins = "gpx2-0", "gpx2-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
- };
-
- keypad_cols: keypad-cols {
- samsung,pins = "gpx1-0", "gpx1-1", "gpx1-2", "gpx1-3",
- "gpx1-4", "gpx1-5", "gpx1-6", "gpx1-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
+ key_2 {
+ keypad,row = <0>;
+ keypad,column = <4>;
+ linux,code = <3>;
};
- keypad@100A0000 {
- samsung,keypad-num-rows = <2>;
- samsung,keypad-num-columns = <8>;
- linux,keypad-no-autorepeat;
- linux,keypad-wakeup;
- pinctrl-names = "default";
- pinctrl-0 = <&keypad_rows &keypad_cols>;
- status = "okay";
+ key_3 {
+ keypad,row = <0>;
+ keypad,column = <5>;
+ linux,code = <4>;
+ };
- key_1 {
- keypad,row = <0>;
- keypad,column = <3>;
- linux,code = <2>;
- };
+ key_4 {
+ keypad,row = <0>;
+ keypad,column = <6>;
+ linux,code = <5>;
+ };
- key_2 {
- keypad,row = <0>;
- keypad,column = <4>;
- linux,code = <3>;
- };
+ key_5 {
+ keypad,row = <0>;
+ keypad,column = <7>;
+ linux,code = <6>;
+ };
- key_3 {
- keypad,row = <0>;
- keypad,column = <5>;
- linux,code = <4>;
- };
+ key_a {
+ keypad,row = <1>;
+ keypad,column = <3>;
+ linux,code = <30>;
+ };
- key_4 {
- keypad,row = <0>;
- keypad,column = <6>;
- linux,code = <5>;
- };
+ key_b {
+ keypad,row = <1>;
+ keypad,column = <4>;
+ linux,code = <48>;
+ };
- key_5 {
- keypad,row = <0>;
- keypad,column = <7>;
- linux,code = <6>;
- };
+ key_c {
+ keypad,row = <1>;
+ keypad,column = <5>;
+ linux,code = <46>;
+ };
- key_a {
- keypad,row = <1>;
- keypad,column = <3>;
- linux,code = <30>;
- };
+ key_d {
+ keypad,row = <1>;
+ keypad,column = <6>;
+ linux,code = <32>;
+ };
- key_b {
- keypad,row = <1>;
- keypad,column = <4>;
- linux,code = <48>;
- };
+ key_e {
+ keypad,row = <1>;
+ keypad,column = <7>;
+ linux,code = <18>;
+ };
+};
- key_c {
- keypad,row = <1>;
- keypad,column = <5>;
- linux,code = <46>;
- };
+&mfc {
+ samsung,mfc-r = <0x43000000 0x800000>;
+ samsung,mfc-l = <0x51000000 0x800000>;
+ status = "okay";
+};
- key_d {
- keypad,row = <1>;
- keypad,column = <6>;
- linux,code = <32>;
- };
+&pinctrl_1 {
+ keypad_rows: keypad-rows {
+ samsung,pins = "gpx2-0", "gpx2-1";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
- key_e {
- keypad,row = <1>;
- keypad,column = <7>;
- linux,code = <18>;
- };
+ keypad_cols: keypad-cols {
+ samsung,pins = "gpx1-0", "gpx1-1", "gpx1-2", "gpx1-3",
+ "gpx1-4", "gpx1-5", "gpx1-6", "gpx1-7";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
};
+};
- i2c@13860000 {
- #address-cells = <1>;
- #size-cells = <0>;
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <100000>;
- status = "okay";
-
- eeprom@50 {
- compatible = "samsung,24ad0xd1";
- reg = <0x50>;
- };
+&sdhci_2 {
+ bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
+ status = "okay";
+};
- eeprom@52 {
- compatible = "samsung,24ad0xd1";
- reg = <0x52>;
- };
- };
+&serial_0 {
+ status = "okay";
+};
- spi_2: spi@13940000 {
- cs-gpios = <&gpc1 2 0>;
- status = "okay";
+&serial_1 {
+ status = "okay";
+};
- w25x80@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "w25x80";
- reg = <0>;
- spi-max-frequency = <1000000>;
+&serial_2 {
+ status = "okay";
+};
- controller-data {
- samsung,spi-feedback-delay = <0>;
- };
+&serial_3 {
+ status = "okay";
+};
- partition@0 {
- label = "U-Boot";
- reg = <0x0 0x40000>;
- read-only;
- };
+&spi_2 {
+ cs-gpios = <&gpc1 2 0>;
+ status = "okay";
- partition@40000 {
- label = "Kernel";
- reg = <0x40000 0xc0000>;
- };
+ w25x80@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "w25x80";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+
+ controller-data {
+ samsung,spi-feedback-delay = <0>;
};
- };
- fixed-rate-clocks {
- xxti {
- compatible = "samsung,clock-xxti";
- clock-frequency = <12000000>;
+ partition@0 {
+ label = "U-Boot";
+ reg = <0x0 0x40000>;
+ read-only;
};
- xusbxti {
- compatible = "samsung,clock-xusbxti";
- clock-frequency = <24000000>;
+ partition@40000 {
+ label = "Kernel";
+ reg = <0x40000 0xc0000>;
};
};
};
diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts
index 32c5fd8f6269..98f3ce65cb9a 100644
--- a/arch/arm/boot/dts/exynos4210-trats.dts
+++ b/arch/arm/boot/dts/exynos4210-trats.dts
@@ -89,42 +89,6 @@
};
};
- hsotg@12480000 {
- vusb_d-supply = <&vusb_reg>;
- vusb_a-supply = <&vusbdac_reg>;
- dr_mode = "peripheral";
- status = "okay";
- };
-
- sdhci_emmc: sdhci@12510000 {
- bus-width = <8>;
- non-removable;
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus8>;
- pinctrl-names = "default";
- vmmc-supply = <&vemmc_reg>;
- status = "okay";
- };
-
- exynos-usbphy@125B0000 {
- status = "okay";
- };
-
- serial@13800000 {
- status = "okay";
- };
-
- serial@13810000 {
- status = "okay";
- };
-
- serial@13820000 {
- status = "okay";
- };
-
- serial@13830000 {
- status = "okay";
- };
-
gpio-keys {
compatible = "gpio-keys";
@@ -158,201 +122,6 @@
};
};
- i2c@13890000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-slave-addr = <0x10>;
- samsung,i2c-max-bus-freq = <400000>;
- pinctrl-0 = <&i2c3_bus>;
- pinctrl-names = "default";
- status = "okay";
-
- mms114-touchscreen@48 {
- compatible = "melfas,mms114";
- reg = <0x48>;
- interrupt-parent = <&gpx0>;
- interrupts = <4 2>;
- x-size = <720>;
- y-size = <1280>;
- avdd-supply = <&tsp_reg>;
- vdd-supply = <&tsp_reg>;
- };
- };
-
- i2c@138B0000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-slave-addr = <0x10>;
- samsung,i2c-max-bus-freq = <100000>;
- pinctrl-0 = <&i2c5_bus>;
- pinctrl-names = "default";
- status = "okay";
-
- max8997_pmic@66 {
- compatible = "maxim,max8997-pmic";
-
- reg = <0x66>;
-
- max8997,pmic-buck1-uses-gpio-dvs;
- max8997,pmic-buck2-uses-gpio-dvs;
- max8997,pmic-buck5-uses-gpio-dvs;
-
- max8997,pmic-ignore-gpiodvs-side-effect;
- max8997,pmic-buck125-default-dvs-idx = <0>;
-
- max8997,pmic-buck125-dvs-gpios = <&gpx0 5 0>,
- <&gpx0 6 0>,
- <&gpl0 0 0>;
-
- max8997,pmic-buck1-dvs-voltage = <1350000>, <1300000>,
- <1250000>, <1200000>,
- <1150000>, <1100000>,
- <1000000>, <950000>;
-
- max8997,pmic-buck2-dvs-voltage = <1100000>, <1000000>,
- <950000>, <900000>,
- <1100000>, <1000000>,
- <950000>, <900000>;
-
- max8997,pmic-buck5-dvs-voltage = <1200000>, <1200000>,
- <1200000>, <1200000>,
- <1200000>, <1200000>,
- <1200000>, <1200000>;
-
- regulators {
- valive_reg: LDO2 {
- regulator-name = "VALIVE_1.1V_C210";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- };
-
- vusb_reg: LDO3 {
- regulator-name = "VUSB_1.1V_C210";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- };
-
- vmipi_reg: LDO4 {
- regulator-name = "VMIPI_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- vpda_reg: LDO6 {
- regulator-name = "VCC_1.8V_PDA";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- vcam_reg: LDO7 {
- regulator-name = "CAM_ISP_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- vusbdac_reg: LDO8 {
- regulator-name = "VUSB/VDAC_3.3V_C210";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
-
- vccpda_reg: LDO9 {
- regulator-name = "VCC_2.8V_PDA";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- };
-
- vpll_reg: LDO10 {
- regulator-name = "VPLL_1.1V_C210";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- };
-
- vtcam_reg: LDO12 {
- regulator-name = "VT_CAM_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- vcclcd_reg: LDO13 {
- regulator-name = "VCC_3.3V_LCD";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
-
- vlcd_reg: LDO15 {
- regulator-name = "VLCD_2.2V";
- regulator-min-microvolt = <2200000>;
- regulator-max-microvolt = <2200000>;
- };
-
- camsensor_reg: LDO16 {
- regulator-name = "CAM_SENSOR_IO_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- vddq_reg: LDO21 {
- regulator-name = "VDDQ_M1M2_1.2V";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- };
-
- varm_breg: BUCK1 {
- /*
- * HACK: The real name is VARM_1.2V_C210,
- * but exynos-cpufreq does not support
- * DT-based regulator lookup yet.
- */
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- };
-
- vint_breg: BUCK2 {
- regulator-name = "VINT_1.1V_C210";
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- };
-
- camisp_breg: BUCK4 {
- regulator-name = "CAM_ISP_CORE_1.2V";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
-
- vmem_breg: BUCK5 {
- regulator-name = "VMEM_1.2V_C210";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- };
-
- vccsub_breg: BUCK7 {
- regulator-name = "VCC_SUB_2.0V";
- regulator-min-microvolt = <2000000>;
- regulator-max-microvolt = <2000000>;
- regulator-always-on;
- };
-
- safe1_sreg: ESAFEOUT1 {
- regulator-name = "SAFEOUT1";
- regulator-always-on;
- };
-
- safe2_sreg: ESAFEOUT2 {
- regulator-name = "SAFEOUT2";
- regulator-boot-on;
- };
- };
- };
- };
-
fixed-rate-clocks {
xxti {
compatible = "samsung,clock-xxti";
@@ -365,71 +134,6 @@
};
};
- dsi_0: dsi@11C80000 {
- vddcore-supply = <&vusb_reg>;
- vddio-supply = <&vmipi_reg>;
- samsung,pll-clock-frequency = <24000000>;
- status = "okay";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@1 {
- reg = <1>;
-
- dsi_out: endpoint {
- remote-endpoint = <&dsi_in>;
- samsung,burst-clock-frequency = <500000000>;
- samsung,esc-clock-frequency = <20000000>;
- };
- };
- };
-
- panel@0 {
- reg = <0>;
- compatible = "samsung,s6e8aa0";
- vdd3-supply = <&vcclcd_reg>;
- vci-supply = <&vlcd_reg>;
- reset-gpios = <&gpy4 5 0>;
- power-on-delay= <50>;
- reset-delay = <100>;
- init-delay = <100>;
- flip-horizontal;
- flip-vertical;
- panel-width-mm = <58>;
- panel-height-mm = <103>;
-
- display-timings {
- timing-0 {
- clock-frequency = <57153600>;
- hactive = <720>;
- vactive = <1280>;
- hfront-porch = <5>;
- hback-porch = <5>;
- hsync-len = <5>;
- vfront-porch = <13>;
- vback-porch = <1>;
- vsync-len = <2>;
- };
- };
-
- port {
- dsi_in: endpoint {
- remote-endpoint = <&dsi_out>;
- };
- };
- };
- };
-
- fimd@11c00000 {
- status = "okay";
- };
-
- tmu@100C0000 {
- status = "okay";
- };
-
thermal-zones {
cpu_thermal: cpu-thermal {
cooling-maps {
@@ -483,3 +187,299 @@
};
};
};
+
+&dsi_0 {
+ vddcore-supply = <&vusb_reg>;
+ vddio-supply = <&vmipi_reg>;
+ samsung,pll-clock-frequency = <24000000>;
+ status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ reg = <1>;
+
+ dsi_out: endpoint {
+ remote-endpoint = <&dsi_in>;
+ samsung,burst-clock-frequency = <500000000>;
+ samsung,esc-clock-frequency = <20000000>;
+ };
+ };
+ };
+
+ panel@0 {
+ reg = <0>;
+ compatible = "samsung,s6e8aa0";
+ vdd3-supply = <&vcclcd_reg>;
+ vci-supply = <&vlcd_reg>;
+ reset-gpios = <&gpy4 5 0>;
+ power-on-delay= <50>;
+ reset-delay = <100>;
+ init-delay = <100>;
+ flip-horizontal;
+ flip-vertical;
+ panel-width-mm = <58>;
+ panel-height-mm = <103>;
+
+ display-timings {
+ timing-0 {
+ clock-frequency = <57153600>;
+ hactive = <720>;
+ vactive = <1280>;
+ hfront-porch = <5>;
+ hback-porch = <5>;
+ hsync-len = <5>;
+ vfront-porch = <13>;
+ vback-porch = <1>;
+ vsync-len = <2>;
+ };
+ };
+
+ port {
+ dsi_in: endpoint {
+ remote-endpoint = <&dsi_out>;
+ };
+ };
+ };
+};
+
+&exynos_usbphy {
+ status = "okay";
+};
+
+&fimd {
+ status = "okay";
+};
+
+&hsotg {
+ vusb_d-supply = <&vusb_reg>;
+ vusb_a-supply = <&vusbdac_reg>;
+ dr_mode = "peripheral";
+ status = "okay";
+};
+
+&i2c_3 {
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-slave-addr = <0x10>;
+ samsung,i2c-max-bus-freq = <400000>;
+ pinctrl-0 = <&i2c3_bus>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ mms114-touchscreen@48 {
+ compatible = "melfas,mms114";
+ reg = <0x48>;
+ interrupt-parent = <&gpx0>;
+ interrupts = <4 2>;
+ x-size = <720>;
+ y-size = <1280>;
+ avdd-supply = <&tsp_reg>;
+ vdd-supply = <&tsp_reg>;
+ };
+};
+
+&i2c_5 {
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-slave-addr = <0x10>;
+ samsung,i2c-max-bus-freq = <100000>;
+ pinctrl-0 = <&i2c5_bus>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ max8997_pmic@66 {
+ compatible = "maxim,max8997-pmic";
+
+ reg = <0x66>;
+
+ max8997,pmic-buck1-uses-gpio-dvs;
+ max8997,pmic-buck2-uses-gpio-dvs;
+ max8997,pmic-buck5-uses-gpio-dvs;
+
+ max8997,pmic-ignore-gpiodvs-side-effect;
+ max8997,pmic-buck125-default-dvs-idx = <0>;
+
+ max8997,pmic-buck125-dvs-gpios = <&gpx0 5 0>,
+ <&gpx0 6 0>,
+ <&gpl0 0 0>;
+
+ max8997,pmic-buck1-dvs-voltage = <1350000>, <1300000>,
+ <1250000>, <1200000>,
+ <1150000>, <1100000>,
+ <1000000>, <950000>;
+
+ max8997,pmic-buck2-dvs-voltage = <1100000>, <1000000>,
+ <950000>, <900000>,
+ <1100000>, <1000000>,
+ <950000>, <900000>;
+
+ max8997,pmic-buck5-dvs-voltage = <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>;
+
+ regulators {
+ valive_reg: LDO2 {
+ regulator-name = "VALIVE_1.1V_C210";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ vusb_reg: LDO3 {
+ regulator-name = "VUSB_1.1V_C210";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ vmipi_reg: LDO4 {
+ regulator-name = "VMIPI_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vpda_reg: LDO6 {
+ regulator-name = "VCC_1.8V_PDA";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ vcam_reg: LDO7 {
+ regulator-name = "CAM_ISP_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vusbdac_reg: LDO8 {
+ regulator-name = "VUSB/VDAC_3.3V_C210";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vccpda_reg: LDO9 {
+ regulator-name = "VCC_2.8V_PDA";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ vpll_reg: LDO10 {
+ regulator-name = "VPLL_1.1V_C210";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ vtcam_reg: LDO12 {
+ regulator-name = "VT_CAM_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vcclcd_reg: LDO13 {
+ regulator-name = "VCC_3.3V_LCD";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vlcd_reg: LDO15 {
+ regulator-name = "VLCD_2.2V";
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ };
+
+ camsensor_reg: LDO16 {
+ regulator-name = "CAM_SENSOR_IO_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vddq_reg: LDO21 {
+ regulator-name = "VDDQ_M1M2_1.2V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ varm_breg: BUCK1 {
+ /*
+ * HACK: The real name is VARM_1.2V_C210,
+ * but exynos-cpufreq does not support
+ * DT-based regulator lookup yet.
+ */
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ };
+
+ vint_breg: BUCK2 {
+ regulator-name = "VINT_1.1V_C210";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ camisp_breg: BUCK4 {
+ regulator-name = "CAM_ISP_CORE_1.2V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ vmem_breg: BUCK5 {
+ regulator-name = "VMEM_1.2V_C210";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ vccsub_breg: BUCK7 {
+ regulator-name = "VCC_SUB_2.0V";
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-always-on;
+ };
+
+ safe1_sreg: ESAFEOUT1 {
+ regulator-name = "SAFEOUT1";
+ regulator-always-on;
+ };
+
+ safe2_sreg: ESAFEOUT2 {
+ regulator-name = "SAFEOUT2";
+ regulator-boot-on;
+ };
+ };
+ };
+};
+
+&sdhci_0 {
+ bus-width = <8>;
+ non-removable;
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus8>;
+ pinctrl-names = "default";
+ vmmc-supply = <&vemmc_reg>;
+ status = "okay";
+};
+
+&serial_0 {
+ status = "okay";
+};
+
+&serial_1 {
+ status = "okay";
+};
+
+&serial_2 {
+ status = "okay";
+};
+
+&serial_3 {
+ status = "okay";
+};
+
+&tmu {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index be89f83f70e7..10d3c173396e 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -52,17 +52,7 @@
};
};
- pmu_system_controller: system-controller@10020000 {
- clock-names = "clkout0", "clkout1", "clkout2", "clkout3",
- "clkout4", "clkout8", "clkout9";
- clocks = <&clock CLK_OUT_DMC>, <&clock CLK_OUT_TOP>,
- <&clock CLK_OUT_LEFTBUS>, <&clock CLK_OUT_RIGHTBUS>,
- <&clock CLK_OUT_CPU>, <&clock CLK_XXTI>,
- <&clock CLK_XUSBXTI>;
- #clock-cells = <1>;
- };
-
- sysram@02020000 {
+ sysram: sysram@02020000 {
compatible = "mmio-sram";
reg = <0x02020000 0x20000>;
#address-cells = <1>;
@@ -95,19 +85,7 @@
arm,data-latency = <2 2 1>;
};
- gic: interrupt-controller@10490000 {
- cpu-offset = <0x8000>;
- };
-
- combiner: interrupt-controller@10440000 {
- samsung,combiner-nr = <16>;
- interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
- <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
- <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
- <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>;
- };
-
- mct@10050000 {
+ mct: mct@10050000 {
compatible = "samsung,exynos4210-mct";
reg = <0x10050000 0x800>;
interrupt-parent = <&mct_map>;
@@ -189,12 +167,13 @@
};
};
- g2d@12800000 {
+ g2d: g2d@12800000 {
compatible = "samsung,s5pv210-g2d";
reg = <0x12800000 0x1000>;
interrupts = <0 89 0>;
clocks = <&clock CLK_SCLK_FIMG2D>, <&clock CLK_G2D>;
clock-names = "sclk_fimg2d", "fimg2d";
+ iommus = <&sysmmu_g2d>;
status = "disabled";
};
@@ -244,4 +223,47 @@
clock-names = "ppmu";
status = "disabled";
};
+
+ sysmmu_g2d: sysmmu@12A20000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x12A20000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <4 7>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_G2D>, <&clock CLK_G2D>;
+ power-domains = <&pd_lcd0>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimd1: sysmmu@12220000 {
+ compatible = "samsung,exynos-sysmmu";
+ interrupt-parent = <&combiner>;
+ reg = <0x12220000 0x1000>;
+ interrupts = <5 3>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_FIMD1>, <&clock CLK_FIMD1>;
+ power-domains = <&pd_lcd1>;
+ #iommu-cells = <0>;
+ };
+};
+
+&gic {
+ cpu-offset = <0x8000>;
+};
+
+&combiner {
+ samsung,combiner-nr = <16>;
+ interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
+ <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
+ <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
+ <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>;
+};
+
+&pmu_system_controller {
+ clock-names = "clkout0", "clkout1", "clkout2", "clkout3",
+ "clkout4", "clkout8", "clkout9";
+ clocks = <&clock CLK_OUT_DMC>, <&clock CLK_OUT_TOP>,
+ <&clock CLK_OUT_LEFTBUS>, <&clock CLK_OUT_RIGHTBUS>,
+ <&clock CLK_OUT_CPU>, <&clock CLK_XXTI>, <&clock CLK_XUSBXTI>;
+ #clock-cells = <1>;
};
diff --git a/arch/arm/boot/dts/exynos4212.dtsi b/arch/arm/boot/dts/exynos4212.dtsi
index 5be03288f1ee..d9c8efeef208 100644
--- a/arch/arm/boot/dts/exynos4212.dtsi
+++ b/arch/arm/boot/dts/exynos4212.dtsi
@@ -41,12 +41,12 @@
reg = <0xA01>;
};
};
+};
- combiner: interrupt-controller@10440000 {
- samsung,combiner-nr = <18>;
- };
+&combiner {
+ samsung,combiner-nr = <18>;
+};
- gic: interrupt-controller@10490000 {
- cpu-offset = <0x8000>;
- };
+&gic {
+ cpu-offset = <0x8000>;
};
diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
index d6b49e5b32e9..ca7d168d1dd6 100644
--- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -38,16 +38,6 @@
};
};
- i2s0: i2s@03830000 {
- pinctrl-0 = <&i2s0_bus>;
- pinctrl-names = "default";
- status = "okay";
- clocks = <&clock_audss EXYNOS_I2S_BUS>,
- <&clock_audss EXYNOS_DOUT_AUD_BUS>,
- <&clock_audss EXYNOS_SCLK_I2S>;
- clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
- };
-
sound: sound {
compatible = "simple-audio-card";
assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>,
@@ -83,427 +73,437 @@
reset-gpios = <&gpk1 2 1>;
};
- mmc@12550000 {
- pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>;
- pinctrl-names = "default";
- vmmc-supply = <&ldo20_reg &buck8_reg>;
- mmc-pwrseq = <&emmc_pwrseq>;
- status = "okay";
-
- num-slots = <1>;
- broken-cd;
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
- bus-width = <8>;
- cap-mmc-highspeed;
- };
-
- watchdog@10060000 {
- status = "okay";
- };
-
- rtc@10070000 {
- status = "okay";
- clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
- clock-names = "rtc", "rtc_src";
- };
-
- g2d@10800000 {
- status = "okay";
- };
-
camera {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <>;
+ };
- fimc_0: fimc@11800000 {
- status = "okay";
- assigned-clocks = <&clock CLK_MOUT_FIMC0>,
- <&clock CLK_SCLK_FIMC0>;
- assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
- assigned-clock-rates = <0>, <176000000>;
- };
-
- fimc_1: fimc@11810000 {
- status = "okay";
- assigned-clocks = <&clock CLK_MOUT_FIMC1>,
- <&clock CLK_SCLK_FIMC1>;
- assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
- assigned-clock-rates = <0>, <176000000>;
+ fixed-rate-clocks {
+ xxti {
+ compatible = "samsung,clock-xxti";
+ clock-frequency = <0>;
};
- fimc_2: fimc@11820000 {
- status = "okay";
- assigned-clocks = <&clock CLK_MOUT_FIMC2>,
- <&clock CLK_SCLK_FIMC2>;
- assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
- assigned-clock-rates = <0>, <176000000>;
+ xusbxti {
+ compatible = "samsung,clock-xusbxti";
+ clock-frequency = <24000000>;
};
+ };
- fimc_3: fimc@11830000 {
- status = "okay";
- assigned-clocks = <&clock CLK_MOUT_FIMC3>,
- <&clock CLK_SCLK_FIMC3>;
- assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
- assigned-clock-rates = <0>, <176000000>;
+ thermal-zones {
+ cpu_thermal: cpu-thermal {
+ cooling-maps {
+ map0 {
+ /* Corresponds to 800MHz at freq_table */
+ cooling-device = <&cpu0 7 7>;
+ };
+ map1 {
+ /* Corresponds to 200MHz at freq_table */
+ cooling-device = <&cpu0 13 13>;
+ };
+ };
};
};
+};
- sdhci@12530000 {
- bus-width = <4>;
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
- pinctrl-names = "default";
- vmmc-supply = <&ldo4_reg &ldo21_reg>;
- cd-gpios = <&gpk2 2 0>;
- cd-inverted;
- status = "okay";
- };
+/* RSTN signal for eMMC */
+&sd1_cd {
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+};
- serial@13800000 {
- status = "okay";
+&pinctrl_1 {
+ gpio_power_key: power_key {
+ samsung,pins = "gpx1-3";
+ samsung,pin-pud = <0>;
};
- serial@13810000 {
- status = "okay";
+ max77686_irq: max77686-irq {
+ samsung,pins = "gpx3-2";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
};
- fixed-rate-clocks {
- xxti {
- compatible = "samsung,clock-xxti";
- clock-frequency = <0>;
- };
-
- xusbxti {
- compatible = "samsung,clock-xusbxti";
- clock-frequency = <24000000>;
- };
+ hdmi_hpd: hdmi-hpd {
+ samsung,pins = "gpx3-7";
+ samsung,pin-pud = <1>;
};
+};
- i2c@13860000 {
- pinctrl-0 = <&i2c0_bus>;
- pinctrl-names = "default";
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <400000>;
- status = "okay";
+&ehci {
+ status = "okay";
+};
- usb3503: usb3503@08 {
- compatible = "smsc,usb3503";
- reg = <0x08>;
+&exynos_usbphy {
+ status = "okay";
+};
- intn-gpios = <&gpx3 0 0>;
- connect-gpios = <&gpx3 4 0>;
- reset-gpios = <&gpx3 5 0>;
- initial-mode = <1>;
- };
+&fimc_0 {
+ status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC0>,
+ <&clock CLK_SCLK_FIMC0>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
+};
- max77686: pmic@09 {
- compatible = "maxim,max77686";
- interrupt-parent = <&gpx3>;
- interrupts = <2 0>;
- pinctrl-names = "default";
- pinctrl-0 = <&max77686_irq>;
- reg = <0x09>;
- #clock-cells = <1>;
-
- voltage-regulators {
- ldo1_reg: LDO1 {
- regulator-name = "VDD_ALIVE_1.0V";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
+&fimc_1 {
+ status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC1>,
+ <&clock CLK_SCLK_FIMC1>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
+};
- ldo2_reg: LDO2 {
- regulator-name = "VDDQ_M1_2_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
+&fimc_2 {
+ status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC2>,
+ <&clock CLK_SCLK_FIMC2>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
+};
- ldo3_reg: LDO3 {
- regulator-name = "VDDQ_EXT_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
+&fimc_3 {
+ status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC3>,
+ <&clock CLK_SCLK_FIMC3>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
+};
- ldo4_reg: LDO4 {
- regulator-name = "VDDQ_MMC2_2.8V";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- regulator-boot-on;
- };
+&g2d {
+ status = "okay";
+};
- ldo5_reg: LDO5 {
- regulator-name = "VDDQ_MMC1_3_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
+&hdmi {
+ hpd-gpio = <&gpx3 7 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_hpd>;
+ vdd-supply = <&ldo8_reg>;
+ vdd_osc-supply = <&ldo10_reg>;
+ vdd_pll-supply = <&ldo8_reg>;
+ ddc = <&i2c_2>;
+ status = "okay";
+};
- ldo6_reg: LDO6 {
- regulator-name = "VDD10_MPLL_1.0V";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
+&hsotg {
+ dr_mode = "peripheral";
+ status = "okay";
+ vusb_d-supply = <&ldo15_reg>;
+ vusb_a-supply = <&ldo12_reg>;
+};
- ldo7_reg: LDO7 {
- regulator-name = "VDD10_XPLL_1.0V";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
+&i2c_0 {
+ pinctrl-0 = <&i2c0_bus>;
+ pinctrl-names = "default";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <400000>;
+ status = "okay";
+
+ usb3503: usb3503@08 {
+ compatible = "smsc,usb3503";
+ reg = <0x08>;
+
+ intn-gpios = <&gpx3 0 0>;
+ connect-gpios = <&gpx3 4 0>;
+ reset-gpios = <&gpx3 5 0>;
+ initial-mode = <1>;
+ };
- ldo8_reg: ldo@8 {
- regulator-compatible = "LDO8";
- regulator-name = "VDD10_HDMI_1.0V";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- };
+ max77686: pmic@09 {
+ compatible = "maxim,max77686";
+ interrupt-parent = <&gpx3>;
+ interrupts = <2 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&max77686_irq>;
+ reg = <0x09>;
+ #clock-cells = <1>;
+
+ voltage-regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VDD_ALIVE_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
- ldo10_reg: ldo@10 {
- regulator-compatible = "LDO10";
- regulator-name = "VDDQ_MIPIHSI_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ ldo2_reg: LDO2 {
+ regulator-name = "VDDQ_M1_2_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
- ldo11_reg: LDO11 {
- regulator-name = "VDD18_ABB1_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
+ ldo3_reg: LDO3 {
+ regulator-name = "VDDQ_EXT_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
- ldo12_reg: LDO12 {
- regulator-name = "VDD33_USB_3.3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo4_reg: LDO4 {
+ regulator-name = "VDDQ_MMC2_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- ldo13_reg: LDO13 {
- regulator-name = "VDDQ_C2C_W_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo5_reg: LDO5 {
+ regulator-name = "VDDQ_MMC1_3_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- ldo14_reg: LDO14 {
- regulator-name = "VDD18_ABB0_2_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo6_reg: LDO6 {
+ regulator-name = "VDD10_MPLL_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
- ldo15_reg: LDO15 {
- regulator-name = "VDD10_HSIC_1.0V";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo7_reg: LDO7 {
+ regulator-name = "VDD10_XPLL_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
- ldo16_reg: LDO16 {
- regulator-name = "VDD18_HSIC_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo8_reg: ldo@8 {
+ regulator-compatible = "LDO8";
+ regulator-name = "VDD10_HDMI_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
- ldo20_reg: LDO20 {
- regulator-name = "LDO20_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-boot-on;
- };
+ ldo10_reg: ldo@10 {
+ regulator-compatible = "LDO10";
+ regulator-name = "VDDQ_MIPIHSI_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
- ldo21_reg: LDO21 {
- regulator-name = "LDO21_3.3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo11_reg: LDO11 {
+ regulator-name = "VDD18_ABB1_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
- ldo25_reg: LDO25 {
- regulator-name = "VDDQ_LCD_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo12_reg: LDO12 {
+ regulator-name = "VDD33_USB_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- buck1_reg: BUCK1 {
- regulator-name = "vdd_mif";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo13_reg: LDO13 {
+ regulator-name = "VDDQ_C2C_W_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- buck2_reg: BUCK2 {
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo14_reg: LDO14 {
+ regulator-name = "VDD18_ABB0_2_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- buck3_reg: BUCK3 {
- regulator-name = "vdd_int";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo15_reg: LDO15 {
+ regulator-name = "VDD10_HSIC_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- buck4_reg: BUCK4 {
- regulator-name = "vdd_g3d";
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1100000>;
- regulator-microvolt-offset = <50000>;
- };
+ ldo16_reg: LDO16 {
+ regulator-name = "VDD18_HSIC_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- buck5_reg: BUCK5 {
- regulator-name = "VDDQ_CKEM1_2_1.2V";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo20_reg: LDO20 {
+ regulator-name = "LDO20_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ };
- buck6_reg: BUCK6 {
- regulator-name = "BUCK6_1.35V";
- regulator-min-microvolt = <1350000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo21_reg: LDO21 {
+ regulator-name = "LDO21_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- buck7_reg: BUCK7 {
- regulator-name = "BUCK7_2.0V";
- regulator-min-microvolt = <2000000>;
- regulator-max-microvolt = <2000000>;
- regulator-always-on;
- };
+ ldo25_reg: LDO25 {
+ regulator-name = "VDDQ_LCD_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- buck8_reg: BUCK8 {
- regulator-name = "BUCK8_2.8V";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- };
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ regulator-boot-on;
};
- };
- };
- i2c@13870000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_bus>;
- status = "okay";
- max98090: max98090@10 {
- compatible = "maxim,max98090";
- reg = <0x10>;
- interrupt-parent = <&gpx0>;
- interrupts = <0 0>;
- clocks = <&i2s0 CLK_I2S_CDCLK>;
- clock-names = "mclk";
- #sound-dai-cells = <0>;
- };
- };
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- exynos-usbphy@125B0000 {
- status = "okay";
- };
+ buck3_reg: BUCK3 {
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- hsotg@12480000 {
- dr_mode = "peripheral";
- status = "okay";
- vusb_d-supply = <&ldo15_reg>;
- vusb_a-supply = <&ldo12_reg>;
- };
+ buck4_reg: BUCK4 {
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-microvolt-offset = <50000>;
+ };
- ehci: ehci@12580000 {
- status = "okay";
- };
+ buck5_reg: BUCK5 {
+ regulator-name = "VDDQ_CKEM1_2_1.2V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- tmu@100C0000 {
- vtmu-supply = <&ldo10_reg>;
- status = "okay";
- };
+ buck6_reg: BUCK6 {
+ regulator-name = "BUCK6_1.35V";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
- thermal-zones {
- cpu_thermal: cpu-thermal {
- cooling-maps {
- map0 {
- /* Corresponds to 800MHz at freq_table */
- cooling-device = <&cpu0 7 7>;
- };
- map1 {
- /* Corresponds to 200MHz at freq_table */
- cooling-device = <&cpu0 13 13>;
- };
- };
+ buck7_reg: BUCK7 {
+ regulator-name = "BUCK7_2.0V";
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-always-on;
+ };
+
+ buck8_reg: BUCK8 {
+ regulator-name = "BUCK8_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
};
};
+};
- mixer: mixer@12C10000 {
- status = "okay";
+&i2c_1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_bus>;
+ status = "okay";
+ max98090: max98090@10 {
+ compatible = "maxim,max98090";
+ reg = <0x10>;
+ interrupt-parent = <&gpx0>;
+ interrupts = <0 0>;
+ clocks = <&i2s0 CLK_I2S_CDCLK>;
+ clock-names = "mclk";
+ #sound-dai-cells = <0>;
};
+};
- hdmi@12D00000 {
- hpd-gpio = <&gpx3 7 0>;
- pinctrl-names = "default";
- pinctrl-0 = <&hdmi_hpd>;
- vdd-supply = <&ldo8_reg>;
- vdd_osc-supply = <&ldo10_reg>;
- vdd_pll-supply = <&ldo8_reg>;
- ddc = <&hdmi_ddc>;
- status = "okay";
- };
+&i2c_2 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_bus>;
+};
- hdmi_ddc: i2c@13880000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_bus>;
- };
+&i2c_8 {
+ status = "okay";
+};
- i2c@138E0000 {
- status = "okay";
- };
+&i2s0 {
+ pinctrl-0 = <&i2s0_bus>;
+ pinctrl-names = "default";
+ status = "okay";
+ clocks = <&clock_audss EXYNOS_I2S_BUS>,
+ <&clock_audss EXYNOS_DOUT_AUD_BUS>,
+ <&clock_audss EXYNOS_SCLK_I2S>;
+ clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
};
-/* RSTN signal for eMMC */
-&sd1_cd {
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+&mixer {
+ status = "okay";
};
-&pinctrl_1 {
- gpio_power_key: power_key {
- samsung,pins = "gpx1-3";
- samsung,pin-pud = <0>;
- };
+&mshc_0 {
+ pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>;
+ pinctrl-names = "default";
+ vmmc-supply = <&ldo20_reg &buck8_reg>;
+ mmc-pwrseq = <&emmc_pwrseq>;
+ status = "okay";
+
+ num-slots = <1>;
+ broken-cd;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ bus-width = <8>;
+ cap-mmc-highspeed;
+};
- max77686_irq: max77686-irq {
- samsung,pins = "gpx3-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
+&rtc {
+ status = "okay";
+ clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
+ clock-names = "rtc", "rtc_src";
+};
- hdmi_hpd: hdmi-hpd {
- samsung,pins = "gpx3-7";
- samsung,pin-pud = <1>;
- };
+&sdhci_2 {
+ bus-width = <4>;
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
+ pinctrl-names = "default";
+ vmmc-supply = <&ldo4_reg &ldo21_reg>;
+ cd-gpios = <&gpk2 2 0>;
+ cd-inverted;
+ status = "okay";
+};
+
+&serial_0 {
+ status = "okay";
+};
+
+&serial_1 {
+ status = "okay";
+};
+
+&tmu {
+ vtmu-supply = <&ldo10_reg>;
+ status = "okay";
+};
+
+&watchdog {
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/exynos4412-odroidx.dts b/arch/arm/boot/dts/exynos4412-odroidx.dts
index cb1cfe7239c4..679ac103ebf6 100644
--- a/arch/arm/boot/dts/exynos4412-odroidx.dts
+++ b/arch/arm/boot/dts/exynos4412-odroidx.dts
@@ -38,14 +38,6 @@
};
};
- serial@13820000 {
- status = "okay";
- };
-
- serial@13830000 {
- status = "okay";
- };
-
gpio_keys {
pinctrl-0 = <&gpio_power_key &gpio_home_key>;
@@ -83,3 +75,11 @@
samsung,pin-pud = <0>;
};
};
+
+&serial_2 {
+ status = "okay";
+};
+
+&serial_3 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts
index bd8b73077d41..84c76310b312 100644
--- a/arch/arm/boot/dts/exynos4412-origen.dts
+++ b/arch/arm/boot/dts/exynos4412-origen.dts
@@ -50,485 +50,485 @@
};
};
- watchdog@10060000 {
- status = "okay";
- };
-
- rtc@10070000 {
- status = "okay";
+ display-timings {
+ native-mode = <&timing0>;
+ timing0: timing {
+ clock-frequency = <47500000>;
+ hactive = <1024>;
+ vactive = <600>;
+ hfront-porch = <64>;
+ hback-porch = <16>;
+ hsync-len = <48>;
+ vback-porch = <64>;
+ vfront-porch = <16>;
+ vsync-len = <3>;
+ };
};
- pinctrl@11000000 {
- keypad_rows: keypad-rows {
- samsung,pins = "gpx2-0", "gpx2-1", "gpx2-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ fixed-rate-clocks {
+ xxti {
+ compatible = "samsung,clock-xxti";
+ clock-frequency = <0>;
};
- keypad_cols: keypad-cols {
- samsung,pins = "gpx1-0", "gpx1-1";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ xusbxti {
+ compatible = "samsung,clock-xusbxti";
+ clock-frequency = <24000000>;
};
};
+};
- keypad@100A0000 {
- samsung,keypad-num-rows = <3>;
- samsung,keypad-num-columns = <2>;
- linux,keypad-no-autorepeat;
- linux,keypad-wakeup;
- pinctrl-0 = <&keypad_rows &keypad_cols>;
- pinctrl-names = "default";
- status = "okay";
-
- key_home {
- keypad,row = <0>;
- keypad,column = <0>;
- linux,code = <KEY_HOME>;
- };
+&fimd {
+ pinctrl-0 = <&lcd_clk &lcd_data24 &pwm1_out>;
+ pinctrl-names = "default";
+ status = "okay";
+};
- key_down {
- keypad,row = <0>;
- keypad,column = <1>;
- linux,code = <KEY_DOWN>;
- };
+&g2d {
+ status = "okay";
+};
- key_up {
- keypad,row = <1>;
- keypad,column = <0>;
- linux,code = <KEY_UP>;
- };
+&i2c_0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <20000>;
+ pinctrl-0 = <&i2c0_bus>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ s5m8767_pmic@66 {
+ compatible = "samsung,s5m8767-pmic";
+ reg = <0x66>;
+
+ s5m8767,pmic-buck-default-dvs-idx = <3>;
+
+ s5m8767,pmic-buck-dvs-gpios = <&gpx2 3 0>,
+ <&gpx2 4 0>,
+ <&gpx2 5 0>;
+
+ s5m8767,pmic-buck-ds-gpios = <&gpm3 5 0>,
+ <&gpm3 6 0>,
+ <&gpm3 7 0>;
+
+ s5m8767,pmic-buck2-dvs-voltage = <1250000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>;
+
+ s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>,
+ <1100000>, <1100000>,
+ <1100000>, <1100000>,
+ <1100000>, <1100000>;
+
+ s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>;
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VDD_ALIVE";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
- key_menu {
- keypad,row = <1>;
- keypad,column = <1>;
- linux,code = <KEY_MENU>;
- };
+ ldo2_reg: LDO2 {
+ regulator-name = "VDDQ_M12";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
- key_back {
- keypad,row = <2>;
- keypad,column = <0>;
- linux,code = <KEY_BACK>;
- };
+ ldo3_reg: LDO3 {
+ regulator-name = "VDDIOAP_18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo4_reg: LDO4 {
+ regulator-name = "VDDQ_PRE";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "VDD18_2M";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "VDD10_MPLL";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "VDD10_XPLL";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "VDD10_MIPI";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo9_reg: LDO9 {
+ regulator-name = "VDD33_LCD";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "VDD18_MIPI";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "VDD18_ABB1";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "VDD33_UOTG";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo13_reg: LDO13 {
+ regulator-name = "VDDIOPERI_18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo14_reg: LDO14 {
+ regulator-name = "VDD18_ABB02";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "VDD10_USH";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "VDD18_HSIC";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo17_reg: LDO17 {
+ regulator-name = "VDDIOAP_MMC012_28";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo18_reg: LDO18 {
+ regulator-name = "VDDIOPERI_28";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo19_reg: LDO19 {
+ regulator-name = "DVDD25";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo20_reg: LDO20 {
+ regulator-name = "VDD28_CAM";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo21_reg: LDO21 {
+ regulator-name = "VDD28_AF";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo22_reg: LDO22 {
+ regulator-name = "VDDA28_2M";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
- key_enter {
- keypad,row = <2>;
- keypad,column = <1>;
- linux,code = <KEY_ENTER>;
+ ldo23_reg: LDO23 {
+ regulator-name = "VDD28_TF";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo24_reg: LDO24 {
+ regulator-name = "VDD33_A31";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo25_reg: LDO25 {
+ regulator-name = "VDD18_CAM";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo26_reg: LDO26 {
+ regulator-name = "VDD18_A31";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo27_reg: LDO27 {
+ regulator-name = "GPS_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ ldo28_reg: LDO28 {
+ regulator-name = "DVDD12";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "vdd_m12";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ buck6_reg: BUCK6 {
+ regulator-name = "vdd12_5m";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
+
+ buck9_reg: BUCK9 {
+ regulator-name = "vddf28_emmc";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>; /* Normal Mode */
+ };
};
};
+};
- g2d@10800000 {
- status = "okay";
+&keypad {
+ samsung,keypad-num-rows = <3>;
+ samsung,keypad-num-columns = <2>;
+ linux,keypad-no-autorepeat;
+ linux,keypad-wakeup;
+ pinctrl-0 = <&keypad_rows &keypad_cols>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ key_home {
+ keypad,row = <0>;
+ keypad,column = <0>;
+ linux,code = <KEY_HOME>;
};
- sdhci@12530000 {
- bus-width = <4>;
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4 &sd2_cd>;
- pinctrl-names = "default";
- vmmc-supply = <&mmc_reg>;
- status = "okay";
+ key_down {
+ keypad,row = <0>;
+ keypad,column = <1>;
+ linux,code = <KEY_DOWN>;
};
- mmc@12550000 {
- pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>;
- pinctrl-names = "default";
- status = "okay";
-
- num-slots = <1>;
- broken-cd;
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
- bus-width = <8>;
- cap-mmc-highspeed;
+ key_up {
+ keypad,row = <1>;
+ keypad,column = <0>;
+ linux,code = <KEY_UP>;
};
- codec@13400000 {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
- status = "okay";
+ key_menu {
+ keypad,row = <1>;
+ keypad,column = <1>;
+ linux,code = <KEY_MENU>;
};
- fimd@11c00000 {
- pinctrl-0 = <&lcd_clk &lcd_data24 &pwm1_out>;
- pinctrl-names = "default";
- status = "okay";
+ key_back {
+ keypad,row = <2>;
+ keypad,column = <0>;
+ linux,code = <KEY_BACK>;
};
- display-timings {
- native-mode = <&timing0>;
- timing0: timing {
- clock-frequency = <47500000>;
- hactive = <1024>;
- vactive = <600>;
- hfront-porch = <64>;
- hback-porch = <16>;
- hsync-len = <48>;
- vback-porch = <64>;
- vfront-porch = <16>;
- vsync-len = <3>;
- };
+ key_enter {
+ keypad,row = <2>;
+ keypad,column = <1>;
+ linux,code = <KEY_ENTER>;
};
+};
- serial@13800000 {
- status = "okay";
- };
+&mfc {
+ samsung,mfc-r = <0x43000000 0x800000>;
+ samsung,mfc-l = <0x51000000 0x800000>;
+ status = "okay";
+};
- serial@13810000 {
- status = "okay";
- };
+&mshc_0 {
+ pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ num-slots = <1>;
+ broken-cd;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ bus-width = <8>;
+ cap-mmc-highspeed;
+};
- serial@13820000 {
- status = "okay";
+&pinctrl_1 {
+ keypad_rows: keypad-rows {
+ samsung,pins = "gpx2-0", "gpx2-1", "gpx2-2";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
};
- serial@13830000 {
- status = "okay";
+ keypad_cols: keypad-cols {
+ samsung,pins = "gpx1-0", "gpx1-1";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
};
+};
- i2c@13860000 {
- #address-cells = <1>;
- #size-cells = <0>;
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <20000>;
- pinctrl-0 = <&i2c0_bus>;
- pinctrl-names = "default";
- status = "okay";
-
- s5m8767_pmic@66 {
- compatible = "samsung,s5m8767-pmic";
- reg = <0x66>;
-
- s5m8767,pmic-buck-default-dvs-idx = <3>;
-
- s5m8767,pmic-buck-dvs-gpios = <&gpx2 3 0>,
- <&gpx2 4 0>,
- <&gpx2 5 0>;
-
- s5m8767,pmic-buck-ds-gpios = <&gpm3 5 0>,
- <&gpm3 6 0>,
- <&gpm3 7 0>;
-
- s5m8767,pmic-buck2-dvs-voltage = <1250000>, <1200000>,
- <1200000>, <1200000>,
- <1200000>, <1200000>,
- <1200000>, <1200000>;
-
- s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>,
- <1100000>, <1100000>,
- <1100000>, <1100000>,
- <1100000>, <1100000>;
-
- s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>,
- <1200000>, <1200000>,
- <1200000>, <1200000>,
- <1200000>, <1200000>;
-
- regulators {
- ldo1_reg: LDO1 {
- regulator-name = "VDD_ALIVE";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo2_reg: LDO2 {
- regulator-name = "VDDQ_M12";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo3_reg: LDO3 {
- regulator-name = "VDDIOAP_18";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo4_reg: LDO4 {
- regulator-name = "VDDQ_PRE";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo5_reg: LDO5 {
- regulator-name = "VDD18_2M";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo6_reg: LDO6 {
- regulator-name = "VDD10_MPLL";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo7_reg: LDO7 {
- regulator-name = "VDD10_XPLL";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo8_reg: LDO8 {
- regulator-name = "VDD10_MIPI";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo9_reg: LDO9 {
- regulator-name = "VDD33_LCD";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo10_reg: LDO10 {
- regulator-name = "VDD18_MIPI";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo11_reg: LDO11 {
- regulator-name = "VDD18_ABB1";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo12_reg: LDO12 {
- regulator-name = "VDD33_UOTG";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo13_reg: LDO13 {
- regulator-name = "VDDIOPERI_18";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo14_reg: LDO14 {
- regulator-name = "VDD18_ABB02";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo15_reg: LDO15 {
- regulator-name = "VDD10_USH";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo16_reg: LDO16 {
- regulator-name = "VDD18_HSIC";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo17_reg: LDO17 {
- regulator-name = "VDDIOAP_MMC012_28";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo18_reg: LDO18 {
- regulator-name = "VDDIOPERI_28";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo19_reg: LDO19 {
- regulator-name = "DVDD25";
- regulator-min-microvolt = <2500000>;
- regulator-max-microvolt = <2500000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo20_reg: LDO20 {
- regulator-name = "VDD28_CAM";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo21_reg: LDO21 {
- regulator-name = "VDD28_AF";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo22_reg: LDO22 {
- regulator-name = "VDDA28_2M";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo23_reg: LDO23 {
- regulator-name = "VDD28_TF";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo24_reg: LDO24 {
- regulator-name = "VDD33_A31";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo25_reg: LDO25 {
- regulator-name = "VDD18_CAM";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo26_reg: LDO26 {
- regulator-name = "VDD18_A31";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo27_reg: LDO27 {
- regulator-name = "GPS_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- ldo28_reg: LDO28 {
- regulator-name = "DVDD12";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- buck1_reg: BUCK1 {
- regulator-name = "vdd_mif";
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- buck2_reg: BUCK2 {
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- buck3_reg: BUCK3 {
- regulator-name = "vdd_int";
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- buck4_reg: BUCK4 {
- regulator-name = "vdd_g3d";
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- buck5_reg: BUCK5 {
- regulator-name = "vdd_m12";
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- buck6_reg: BUCK6 {
- regulator-name = "vdd12_5m";
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>; /* Normal Mode */
- };
-
- buck9_reg: BUCK9 {
- regulator-name = "vddf28_emmc";
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <3000000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>; /* Normal Mode */
- };
- };
- };
- };
+&rtc {
+ status = "okay";
+};
- fixed-rate-clocks {
- xxti {
- compatible = "samsung,clock-xxti";
- clock-frequency = <0>;
- };
+&sdhci_2 {
+ bus-width = <4>;
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4 &sd2_cd>;
+ pinctrl-names = "default";
+ vmmc-supply = <&mmc_reg>;
+ status = "okay";
+};
- xusbxti {
- compatible = "samsung,clock-xusbxti";
- clock-frequency = <24000000>;
- };
- };
+&serial_0 {
+ status = "okay";
+};
+
+&serial_1 {
+ status = "okay";
+};
+
+&serial_2 {
+ status = "okay";
+};
+
+&serial_3 {
+ status = "okay";
+};
+
+&watchdog {
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/exynos4412-smdk4412.dts b/arch/arm/boot/dts/exynos4412-smdk4412.dts
index b9256afbcc68..c2421df1fa43 100644
--- a/arch/arm/boot/dts/exynos4412-smdk4412.dts
+++ b/arch/arm/boot/dts/exynos4412-smdk4412.dts
@@ -28,135 +28,135 @@
stdout-path = &serial_1;
};
- g2d@10800000 {
- status = "okay";
- };
-
- pinctrl@11000000 {
- keypad_rows: keypad-rows {
- samsung,pins = "gpx2-0", "gpx2-1", "gpx2-2";
- samsung,pin-function = <3>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
+ fixed-rate-clocks {
+ xxti {
+ compatible = "samsung,clock-xxti";
+ clock-frequency = <0>;
};
- keypad_cols: keypad-cols {
- samsung,pins = "gpx1-0", "gpx1-1", "gpx1-2", "gpx1-3",
- "gpx1-4", "gpx1-5", "gpx1-6", "gpx1-7";
- samsung,pin-function = <3>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
+ xusbxti {
+ compatible = "samsung,clock-xusbxti";
+ clock-frequency = <24000000>;
};
};
+};
- keypad@100A0000 {
- samsung,keypad-num-rows = <3>;
- samsung,keypad-num-columns = <8>;
- linux,keypad-no-autorepeat;
- linux,keypad-wakeup;
- pinctrl-0 = <&keypad_rows &keypad_cols>;
- pinctrl-names = "default";
- status = "okay";
-
- key_1 {
- keypad,row = <1>;
- keypad,column = <3>;
- linux,code = <2>;
- };
-
- key_2 {
- keypad,row = <1>;
- keypad,column = <4>;
- linux,code = <3>;
- };
-
- key_3 {
- keypad,row = <1>;
- keypad,column = <5>;
- linux,code = <4>;
- };
-
- key_4 {
- keypad,row = <1>;
- keypad,column = <6>;
- linux,code = <5>;
- };
+&g2d {
+ status = "okay";
+};
- key_5 {
- keypad,row = <1>;
- keypad,column = <7>;
- linux,code = <6>;
- };
+&keypad {
+ samsung,keypad-num-rows = <3>;
+ samsung,keypad-num-columns = <8>;
+ linux,keypad-no-autorepeat;
+ linux,keypad-wakeup;
+ pinctrl-0 = <&keypad_rows &keypad_cols>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ key_1 {
+ keypad,row = <1>;
+ keypad,column = <3>;
+ linux,code = <2>;
+ };
- key_A {
- keypad,row = <2>;
- keypad,column = <6>;
- linux,code = <30>;
- };
+ key_2 {
+ keypad,row = <1>;
+ keypad,column = <4>;
+ linux,code = <3>;
+ };
- key_B {
- keypad,row = <2>;
- keypad,column = <7>;
- linux,code = <48>;
- };
+ key_3 {
+ keypad,row = <1>;
+ keypad,column = <5>;
+ linux,code = <4>;
+ };
- key_C {
- keypad,row = <0>;
- keypad,column = <5>;
- linux,code = <46>;
- };
+ key_4 {
+ keypad,row = <1>;
+ keypad,column = <6>;
+ linux,code = <5>;
+ };
- key_D {
- keypad,row = <2>;
- keypad,column = <5>;
- linux,code = <32>;
- };
+ key_5 {
+ keypad,row = <1>;
+ keypad,column = <7>;
+ linux,code = <6>;
+ };
- key_E {
- keypad,row = <0>;
- keypad,column = <7>;
- linux,code = <18>;
- };
+ key_A {
+ keypad,row = <2>;
+ keypad,column = <6>;
+ linux,code = <30>;
};
- sdhci@12530000 {
- bus-width = <4>;
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4 &sd2_cd>;
- pinctrl-names = "default";
- status = "okay";
+ key_B {
+ keypad,row = <2>;
+ keypad,column = <7>;
+ linux,code = <48>;
};
- codec@13400000 {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
- status = "okay";
+ key_C {
+ keypad,row = <0>;
+ keypad,column = <5>;
+ linux,code = <46>;
};
- serial@13800000 {
- status = "okay";
+ key_D {
+ keypad,row = <2>;
+ keypad,column = <5>;
+ linux,code = <32>;
};
- serial@13810000 {
- status = "okay";
+ key_E {
+ keypad,row = <0>;
+ keypad,column = <7>;
+ linux,code = <18>;
};
+};
+
+&mfc {
+ samsung,mfc-r = <0x43000000 0x800000>;
+ samsung,mfc-l = <0x51000000 0x800000>;
+ status = "okay";
+};
- serial@13820000 {
- status = "okay";
+&pinctrl_1 {
+ keypad_rows: keypad-rows {
+ samsung,pins = "gpx2-0", "gpx2-1", "gpx2-2";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
};
- serial@13830000 {
- status = "okay";
+ keypad_cols: keypad-cols {
+ samsung,pins = "gpx1-0", "gpx1-1", "gpx1-2", "gpx1-3",
+ "gpx1-4", "gpx1-5", "gpx1-6", "gpx1-7";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
};
+};
- fixed-rate-clocks {
- xxti {
- compatible = "samsung,clock-xxti";
- clock-frequency = <0>;
- };
+&sdhci_2 {
+ bus-width = <4>;
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4 &sd2_cd>;
+ pinctrl-names = "default";
+ status = "okay";
+};
- xusbxti {
- compatible = "samsung,clock-xusbxti";
- clock-frequency = <24000000>;
- };
- };
+&serial_0 {
+ status = "okay";
+};
+
+&serial_1 {
+ status = "okay";
+};
+
+&serial_2 {
+ status = "okay";
+};
+
+&serial_3 {
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/exynos4412-tiny4412.dts b/arch/arm/boot/dts/exynos4412-tiny4412.dts
index d46fd4c2aeaa..525684ca8dc0 100644
--- a/arch/arm/boot/dts/exynos4412-tiny4412.dts
+++ b/arch/arm/boot/dts/exynos4412-tiny4412.dts
@@ -56,33 +56,6 @@
};
};
- rtc@10070000 {
- status = "okay";
- };
-
- sdhci@12530000 {
- bus-width = <4>;
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
- pinctrl-names = "default";
- status = "okay";
- };
-
- serial@13800000 {
- status = "okay";
- };
-
- serial@13810000 {
- status = "okay";
- };
-
- serial@13820000 {
- status = "okay";
- };
-
- serial@13830000 {
- status = "okay";
- };
-
fixed-rate-clocks {
xxti {
compatible = "samsung,clock-xxti";
@@ -95,3 +68,30 @@
};
};
};
+
+&rtc {
+ status = "okay";
+};
+
+&sdhci_2 {
+ bus-width = <4>;
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
+&serial_0 {
+ status = "okay";
+};
+
+&serial_1 {
+ status = "okay";
+};
+
+&serial_2 {
+ status = "okay";
+};
+
+&serial_3 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index 792394dd0f2a..afc199d78cb9 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -16,6 +16,7 @@
#include "exynos4412.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/clock/maxim,max77686.h>
/ {
model = "Samsung Trats 2 based on Exynos4412";
@@ -130,411 +131,6 @@
};
};
- adc: adc@126C0000 {
- vdd-supply = <&ldo3_reg>;
- status = "okay";
- };
-
- i2c@13890000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-slave-addr = <0x10>;
- samsung,i2c-max-bus-freq = <400000>;
- pinctrl-0 = <&i2c3_bus>;
- pinctrl-names = "default";
- status = "okay";
-
- mms114-touchscreen@48 {
- compatible = "melfas,mms114";
- reg = <0x48>;
- interrupt-parent = <&gpm2>;
- interrupts = <3 2>;
- x-size = <720>;
- y-size = <1280>;
- avdd-supply = <&ldo23_reg>;
- vdd-supply = <&ldo24_reg>;
- };
- };
-
- i2c_0: i2c@13860000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-slave-addr = <0x10>;
- samsung,i2c-max-bus-freq = <400000>;
- pinctrl-0 = <&i2c0_bus>;
- pinctrl-names = "default";
- status = "okay";
-
- s5c73m3@3c {
- compatible = "samsung,s5c73m3";
- reg = <0x3c>;
- standby-gpios = <&gpm0 1 1>; /* ISP_STANDBY */
- xshutdown-gpios = <&gpf1 3 1>; /* ISP_RESET */
- vdd-int-supply = <&buck9_reg>;
- vddio-cis-supply = <&ldo9_reg>;
- vdda-supply = <&ldo17_reg>;
- vddio-host-supply = <&ldo18_reg>;
- vdd-af-supply = <&cam_af_reg>;
- vdd-reg-supply = <&cam_io_reg>;
- clock-frequency = <24000000>;
- /* CAM_A_CLKOUT */
- clocks = <&camera 0>;
- clock-names = "cis_extclk";
- port {
- s5c73m3_ep: endpoint {
- remote-endpoint = <&csis0_ep>;
- data-lanes = <1 2 3 4>;
- };
- };
- };
- };
-
- i2c@138A0000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-slave-addr = <0x10>;
- samsung,i2c-max-bus-freq = <100000>;
- pinctrl-0 = <&i2c4_bus>;
- pinctrl-names = "default";
- status = "okay";
-
- wm1811: wm1811@1a {
- compatible = "wlf,wm1811";
- reg = <0x1a>;
- clocks = <&pmu_system_controller 0>;
- clock-names = "MCLK1";
- DCVDD-supply = <&ldo3_reg>;
- DBVDD1-supply = <&ldo3_reg>;
- wlf,ldo1ena = <&gpj0 4 0>;
- };
- };
-
- i2c@138D0000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-slave-addr = <0x10>;
- samsung,i2c-max-bus-freq = <100000>;
- pinctrl-0 = <&i2c7_bus>;
- pinctrl-names = "default";
- status = "okay";
-
- max77686_pmic@09 {
- compatible = "maxim,max77686";
- interrupt-parent = <&gpx0>;
- interrupts = <7 0>;
- reg = <0x09>;
- #clock-cells = <1>;
-
- voltage-regulators {
- ldo1_reg: ldo1 {
- regulator-compatible = "LDO1";
- regulator-name = "VALIVE_1.0V_AP";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo2_reg: ldo2 {
- regulator-compatible = "LDO2";
- regulator-name = "VM1M2_1.2V_AP";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- regulator-state-mem {
- regulator-on-in-suspend;
- };
- };
-
- ldo3_reg: ldo3 {
- regulator-compatible = "LDO3";
- regulator-name = "VCC_1.8V_AP";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo4_reg: ldo4 {
- regulator-compatible = "LDO4";
- regulator-name = "VCC_2.8V_AP";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- };
-
- ldo5_reg: ldo5 {
- regulator-compatible = "LDO5";
- regulator-name = "VCC_1.8V_IO";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo6_reg: ldo6 {
- regulator-compatible = "LDO6";
- regulator-name = "VMPLL_1.0V_AP";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- regulator-state-mem {
- regulator-on-in-suspend;
- };
- };
-
- ldo7_reg: ldo7 {
- regulator-compatible = "LDO7";
- regulator-name = "VPLL_1.0V_AP";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- regulator-state-mem {
- regulator-on-in-suspend;
- };
- };
-
- ldo8_reg: ldo8 {
- regulator-compatible = "LDO8";
- regulator-name = "VMIPI_1.0V";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- ldo9_reg: ldo9 {
- regulator-compatible = "LDO9";
- regulator-name = "CAM_ISP_MIPI_1.2V";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
-
- ldo10_reg: ldo10 {
- regulator-compatible = "LDO10";
- regulator-name = "VMIPI_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- ldo11_reg: ldo11 {
- regulator-compatible = "LDO11";
- regulator-name = "VABB1_1.95V";
- regulator-min-microvolt = <1950000>;
- regulator-max-microvolt = <1950000>;
- regulator-always-on;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- ldo12_reg: ldo12 {
- regulator-compatible = "LDO12";
- regulator-name = "VUOTG_3.0V";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- ldo13_reg: ldo13 {
- regulator-compatible = "LDO13";
- regulator-name = "NFC_AVDD_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo14_reg: ldo14 {
- regulator-compatible = "LDO14";
- regulator-name = "VABB2_1.95V";
- regulator-min-microvolt = <1950000>;
- regulator-max-microvolt = <1950000>;
- regulator-always-on;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- ldo15_reg: ldo15 {
- regulator-compatible = "LDO15";
- regulator-name = "VHSIC_1.0V";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-state-mem {
- regulator-on-in-suspend;
- };
- };
-
- ldo16_reg: ldo16 {
- regulator-compatible = "LDO16";
- regulator-name = "VHSIC_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-state-mem {
- regulator-on-in-suspend;
- };
- };
-
- ldo17_reg: ldo17 {
- regulator-compatible = "LDO17";
- regulator-name = "CAM_SENSOR_CORE_1.2V";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
-
- ldo18_reg: ldo18 {
- regulator-compatible = "LDO18";
- regulator-name = "CAM_ISP_SEN_IO_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo19_reg: ldo19 {
- regulator-compatible = "LDO19";
- regulator-name = "VT_CAM_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo20_reg: ldo20 {
- regulator-compatible = "LDO20";
- regulator-name = "VDDQ_PRE_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo21_reg: ldo21 {
- regulator-compatible = "LDO21";
- regulator-name = "VTF_2.8V";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- maxim,ena-gpios = <&gpy2 0 GPIO_ACTIVE_HIGH>;
- };
-
- ldo22_reg: ldo22 {
- regulator-compatible = "LDO22";
- regulator-name = "VMEM_VDD_2.8V";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- maxim,ena-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
- };
-
- ldo23_reg: ldo23 {
- regulator-compatible = "LDO23";
- regulator-name = "TSP_AVDD_3.3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
-
- ldo24_reg: ldo24 {
- regulator-compatible = "LDO24";
- regulator-name = "TSP_VDD_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo25_reg: ldo25 {
- regulator-compatible = "LDO25";
- regulator-name = "LCD_VCC_3.3V";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- };
-
- ldo26_reg: ldo26 {
- regulator-compatible = "LDO26";
- regulator-name = "MOTOR_VCC_3.0V";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- };
-
- buck1_reg: buck1 {
- regulator-compatible = "BUCK1";
- regulator-name = "vdd_mif";
- regulator-min-microvolt = <850000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- regulator-boot-on;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- buck2_reg: buck2 {
- regulator-compatible = "BUCK2";
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <850000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- regulator-state-mem {
- regulator-on-in-suspend;
- };
- };
-
- buck3_reg: buck3 {
- regulator-compatible = "BUCK3";
- regulator-name = "vdd_int";
- regulator-min-microvolt = <850000>;
- regulator-max-microvolt = <1150000>;
- regulator-always-on;
- regulator-boot-on;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- buck4_reg: buck4 {
- regulator-compatible = "BUCK4";
- regulator-name = "vdd_g3d";
- regulator-min-microvolt = <850000>;
- regulator-max-microvolt = <1150000>;
- regulator-boot-on;
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
- buck5_reg: buck5 {
- regulator-compatible = "BUCK5";
- regulator-name = "VMEM_1.2V_AP";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- };
-
- buck6_reg: buck6 {
- regulator-compatible = "BUCK6";
- regulator-name = "VCC_SUB_1.35V";
- regulator-min-microvolt = <1350000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- };
-
- buck7_reg: buck7 {
- regulator-compatible = "BUCK7";
- regulator-name = "VCC_SUB_2.0V";
- regulator-min-microvolt = <2000000>;
- regulator-max-microvolt = <2000000>;
- regulator-always-on;
- };
-
- buck8_reg: buck8 {
- regulator-compatible = "BUCK8";
- regulator-name = "VMEM_VDDF_3.0V";
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- maxim,ena-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
- };
-
- buck9_reg: buck9 {
- regulator-compatible = "BUCK9";
- regulator-name = "CAM_ISP_CORE_1.2V";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1200000>;
- maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>;
- };
- };
- };
- };
-
i2c_max77693: i2c-gpio-1 {
compatible = "i2c-gpio";
gpios = <&gpm2 0 GPIO_ACTIVE_HIGH>, <&gpm2 1 GPIO_ACTIVE_HIGH>;
@@ -597,54 +193,6 @@
};
};
- mmc@12550000 {
- num-slots = <1>;
- broken-cd;
- non-removable;
- card-detect-delay = <200>;
- vmmc-supply = <&ldo22_reg>;
- clock-frequency = <400000000>;
- samsung,dw-mshc-ciu-div = <0>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
- pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>;
- pinctrl-names = "default";
- status = "okay";
- bus-width = <8>;
- cap-mmc-highspeed;
- };
-
- sdhci@12530000 {
- bus-width = <4>;
- cd-gpios = <&gpx3 4 0>;
- cd-inverted;
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4>;
- pinctrl-names = "default";
- vmmc-supply = <&ldo21_reg>;
- status = "okay";
- };
-
- serial@13800000 {
- status = "okay";
- };
-
- serial@13810000 {
- status = "okay";
- };
-
- serial@13820000 {
- status = "okay";
- };
-
- serial@13830000 {
- status = "okay";
- };
-
- tmu@100C0000 {
- vtmu-supply = <&ldo10_reg>;
- status = "okay";
- };
-
i2c_ak8975: i2c-gpio-0 {
compatible = "i2c-gpio";
gpios = <&gpy2 4 0>, <&gpy2 5 0>;
@@ -676,90 +224,6 @@
};
};
- spi_1: spi@13930000 {
- pinctrl-names = "default";
- pinctrl-0 = <&spi1_bus>;
- cs-gpios = <&gpb 5 0>;
- status = "okay";
-
- s5c73m3_spi: s5c73m3 {
- compatible = "samsung,s5c73m3";
- spi-max-frequency = <50000000>;
- reg = <0>;
- controller-data {
- samsung,spi-feedback-delay = <2>;
- };
- };
- };
-
- pwm: pwm@139D0000 {
- pinctrl-0 = <&pwm0_out>;
- pinctrl-names = "default";
- samsung,pwm-outputs = <0>;
- status = "okay";
- };
-
- dsi_0: dsi@11C80000 {
- vddcore-supply = <&ldo8_reg>;
- vddio-supply = <&ldo10_reg>;
- samsung,pll-clock-frequency = <24000000>;
- status = "okay";
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@1 {
- reg = <1>;
-
- dsi_out: endpoint {
- remote-endpoint = <&dsi_in>;
- samsung,burst-clock-frequency = <500000000>;
- samsung,esc-clock-frequency = <20000000>;
- };
- };
- };
-
- panel@0 {
- compatible = "samsung,s6e8aa0";
- reg = <0>;
- vdd3-supply = <&lcd_vdd3_reg>;
- vci-supply = <&ldo25_reg>;
- reset-gpios = <&gpy4 5 0>;
- power-on-delay= <50>;
- reset-delay = <100>;
- init-delay = <100>;
- flip-horizontal;
- flip-vertical;
- panel-width-mm = <58>;
- panel-height-mm = <103>;
-
- display-timings {
- timing-0 {
- clock-frequency = <57153600>;
- hactive = <720>;
- vactive = <1280>;
- hfront-porch = <5>;
- hback-porch = <5>;
- hsync-len = <5>;
- vfront-porch = <13>;
- vback-porch = <1>;
- vsync-len = <2>;
- };
- };
-
- port {
- dsi_in: endpoint {
- remote-endpoint = <&dsi_out>;
- };
- };
- };
- };
-
- fimd@11c00000 {
- status = "okay";
- };
-
camera: camera {
pinctrl-0 = <&cam_port_a_clk_active &cam_port_b_clk_active>;
pinctrl-names = "default";
@@ -769,124 +233,7 @@
assigned-clock-parents = <&clock CLK_XUSBXTI>,
<&clock CLK_XUSBXTI>;
- fimc_0: fimc@11800000 {
- status = "okay";
- assigned-clocks = <&clock CLK_MOUT_FIMC0>,
- <&clock CLK_SCLK_FIMC0>;
- assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
- assigned-clock-rates = <0>, <176000000>;
- };
-
- fimc_1: fimc@11810000 {
- status = "okay";
- assigned-clocks = <&clock CLK_MOUT_FIMC1>,
- <&clock CLK_SCLK_FIMC1>;
- assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
- assigned-clock-rates = <0>, <176000000>;
- };
-
- fimc_2: fimc@11820000 {
- status = "okay";
- assigned-clocks = <&clock CLK_MOUT_FIMC2>,
- <&clock CLK_SCLK_FIMC2>;
- assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
- assigned-clock-rates = <0>, <176000000>;
- };
-
- fimc_3: fimc@11830000 {
- status = "okay";
- assigned-clocks = <&clock CLK_MOUT_FIMC3>,
- <&clock CLK_SCLK_FIMC3>;
- assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
- assigned-clock-rates = <0>, <176000000>;
- };
-
- csis_0: csis@11880000 {
- status = "okay";
- vddcore-supply = <&ldo8_reg>;
- vddio-supply = <&ldo10_reg>;
- assigned-clocks = <&clock CLK_MOUT_CSIS0>,
- <&clock CLK_SCLK_CSIS0>;
- assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
- assigned-clock-rates = <0>, <176000000>;
-
- /* Camera C (3) MIPI CSI-2 (CSIS0) */
- port@3 {
- reg = <3>;
- csis0_ep: endpoint {
- remote-endpoint = <&s5c73m3_ep>;
- data-lanes = <1 2 3 4>;
- samsung,csis-hs-settle = <12>;
- };
- };
- };
-
- csis_1: csis@11890000 {
- status = "okay";
- vddcore-supply = <&ldo8_reg>;
- vddio-supply = <&ldo10_reg>;
- assigned-clocks = <&clock CLK_MOUT_CSIS1>,
- <&clock CLK_SCLK_CSIS1>;
- assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
- assigned-clock-rates = <0>, <176000000>;
-
- /* Camera D (4) MIPI CSI-2 (CSIS1) */
- port@4 {
- reg = <4>;
- csis1_ep: endpoint {
- remote-endpoint = <&is_s5k6a3_ep>;
- data-lanes = <1>;
- samsung,csis-hs-settle = <18>;
- samsung,csis-wclk;
- };
- };
- };
-
- fimc_lite_0: fimc-lite@12390000 {
- status = "okay";
- };
-
- fimc_lite_1: fimc-lite@123A0000 {
- status = "okay";
- };
- fimc-is@12000000 {
- pinctrl-0 = <&fimc_is_uart>;
- pinctrl-names = "default";
- status = "okay";
-
- i2c1_isp: i2c-isp@12140000 {
- pinctrl-0 = <&fimc_is_i2c1>;
- pinctrl-names = "default";
-
- s5k6a3@10 {
- compatible = "samsung,s5k6a3";
- reg = <0x10>;
- svdda-supply = <&cam_io_reg>;
- svddio-supply = <&ldo19_reg>;
- afvdd-supply = <&ldo19_reg>;
- clock-frequency = <24000000>;
- /* CAM_B_CLKOUT */
- clocks = <&camera 1>;
- clock-names = "extclk";
- samsung,camclk-out = <1>;
- gpios = <&gpm1 6 0>;
-
- port {
- is_s5k6a3_ep: endpoint {
- remote-endpoint = <&csis1_ep>;
- data-lanes = <1>;
- };
- };
- };
- };
- };
- };
-
- i2s0: i2s@03830000 {
- pinctrl-0 = <&i2s0_bus>;
- pinctrl-names = "default";
- status = "okay";
};
sound {
@@ -901,17 +248,6 @@
"SPK", "SPKOUTRP";
};
- exynos-usbphy@125B0000 {
- status = "okay";
- };
-
- hsotg@12480000 {
- vusb_d-supply = <&ldo15_reg>;
- vusb_a-supply = <&ldo12_reg>;
- dr_mode = "peripheral";
- status = "okay";
- };
-
thermistor-ap@0 {
compatible = "ntc,ncp15wb473";
pullup-uv = <1800000>; /* VCC_1.8V_AP */
@@ -944,6 +280,619 @@
};
};
+&adc {
+ vdd-supply = <&ldo3_reg>;
+ status = "okay";
+};
+
+&csis_0 {
+ status = "okay";
+ vddcore-supply = <&ldo8_reg>;
+ vddio-supply = <&ldo10_reg>;
+ assigned-clocks = <&clock CLK_MOUT_CSIS0>,
+ <&clock CLK_SCLK_CSIS0>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
+
+ /* Camera C (3) MIPI CSI-2 (CSIS0) */
+ port@3 {
+ reg = <3>;
+ csis0_ep: endpoint {
+ remote-endpoint = <&s5c73m3_ep>;
+ data-lanes = <1 2 3 4>;
+ samsung,csis-hs-settle = <12>;
+ };
+ };
+};
+
+&csis_1 {
+ status = "okay";
+ vddcore-supply = <&ldo8_reg>;
+ vddio-supply = <&ldo10_reg>;
+ assigned-clocks = <&clock CLK_MOUT_CSIS1>,
+ <&clock CLK_SCLK_CSIS1>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
+
+ /* Camera D (4) MIPI CSI-2 (CSIS1) */
+ port@4 {
+ reg = <4>;
+ csis1_ep: endpoint {
+ remote-endpoint = <&is_s5k6a3_ep>;
+ data-lanes = <1>;
+ samsung,csis-hs-settle = <18>;
+ samsung,csis-wclk;
+ };
+ };
+};
+
+&dsi_0 {
+ vddcore-supply = <&ldo8_reg>;
+ vddio-supply = <&ldo10_reg>;
+ samsung,pll-clock-frequency = <24000000>;
+ status = "okay";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ reg = <1>;
+
+ dsi_out: endpoint {
+ remote-endpoint = <&dsi_in>;
+ samsung,burst-clock-frequency = <500000000>;
+ samsung,esc-clock-frequency = <20000000>;
+ };
+ };
+ };
+
+ panel@0 {
+ compatible = "samsung,s6e8aa0";
+ reg = <0>;
+ vdd3-supply = <&lcd_vdd3_reg>;
+ vci-supply = <&ldo25_reg>;
+ reset-gpios = <&gpy4 5 0>;
+ power-on-delay= <50>;
+ reset-delay = <100>;
+ init-delay = <100>;
+ flip-horizontal;
+ flip-vertical;
+ panel-width-mm = <58>;
+ panel-height-mm = <103>;
+
+ display-timings {
+ timing-0 {
+ clock-frequency = <57153600>;
+ hactive = <720>;
+ vactive = <1280>;
+ hfront-porch = <5>;
+ hback-porch = <5>;
+ hsync-len = <5>;
+ vfront-porch = <13>;
+ vback-porch = <1>;
+ vsync-len = <2>;
+ };
+ };
+
+ port {
+ dsi_in: endpoint {
+ remote-endpoint = <&dsi_out>;
+ };
+ };
+ };
+};
+
+&exynos_usbphy {
+ status = "okay";
+};
+
+&fimc_0 {
+ status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC0>,
+ <&clock CLK_SCLK_FIMC0>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
+};
+
+&fimc_1 {
+ status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC1>,
+ <&clock CLK_SCLK_FIMC1>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
+};
+
+&fimc_2 {
+ status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC2>,
+ <&clock CLK_SCLK_FIMC2>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
+};
+
+&fimc_3 {
+ status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC3>,
+ <&clock CLK_SCLK_FIMC3>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
+};
+
+&fimc_is {
+ pinctrl-0 = <&fimc_is_uart>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ i2c1_isp: i2c-isp@12140000 {
+ pinctrl-0 = <&fimc_is_i2c1>;
+ pinctrl-names = "default";
+
+ s5k6a3@10 {
+ compatible = "samsung,s5k6a3";
+ reg = <0x10>;
+ svdda-supply = <&cam_io_reg>;
+ svddio-supply = <&ldo19_reg>;
+ afvdd-supply = <&ldo19_reg>;
+ clock-frequency = <24000000>;
+ /* CAM_B_CLKOUT */
+ clocks = <&camera 1>;
+ clock-names = "extclk";
+ samsung,camclk-out = <1>;
+ gpios = <&gpm1 6 0>;
+
+ port {
+ is_s5k6a3_ep: endpoint {
+ remote-endpoint = <&csis1_ep>;
+ data-lanes = <1>;
+ };
+ };
+ };
+ };
+};
+
+&fimc_lite_0 {
+ status = "okay";
+};
+
+&fimc_lite_1 {
+ status = "okay";
+};
+
+&fimd {
+ status = "okay";
+};
+
+&hsotg {
+ vusb_d-supply = <&ldo15_reg>;
+ vusb_a-supply = <&ldo12_reg>;
+ dr_mode = "peripheral";
+ status = "okay";
+};
+
+&i2c_0 {
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-slave-addr = <0x10>;
+ samsung,i2c-max-bus-freq = <400000>;
+ pinctrl-0 = <&i2c0_bus>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ s5c73m3@3c {
+ compatible = "samsung,s5c73m3";
+ reg = <0x3c>;
+ standby-gpios = <&gpm0 1 1>; /* ISP_STANDBY */
+ xshutdown-gpios = <&gpf1 3 1>; /* ISP_RESET */
+ vdd-int-supply = <&buck9_reg>;
+ vddio-cis-supply = <&ldo9_reg>;
+ vdda-supply = <&ldo17_reg>;
+ vddio-host-supply = <&ldo18_reg>;
+ vdd-af-supply = <&cam_af_reg>;
+ vdd-reg-supply = <&cam_io_reg>;
+ clock-frequency = <24000000>;
+ /* CAM_A_CLKOUT */
+ clocks = <&camera 0>;
+ clock-names = "cis_extclk";
+ port {
+ s5c73m3_ep: endpoint {
+ remote-endpoint = <&csis0_ep>;
+ data-lanes = <1 2 3 4>;
+ };
+ };
+ };
+};
+
+&i2c_3 {
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-slave-addr = <0x10>;
+ samsung,i2c-max-bus-freq = <400000>;
+ pinctrl-0 = <&i2c3_bus>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ mms114-touchscreen@48 {
+ compatible = "melfas,mms114";
+ reg = <0x48>;
+ interrupt-parent = <&gpm2>;
+ interrupts = <3 2>;
+ x-size = <720>;
+ y-size = <1280>;
+ avdd-supply = <&ldo23_reg>;
+ vdd-supply = <&ldo24_reg>;
+ };
+};
+
+&i2c_4 {
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-slave-addr = <0x10>;
+ samsung,i2c-max-bus-freq = <100000>;
+ pinctrl-0 = <&i2c4_bus>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ wm1811: wm1811@1a {
+ compatible = "wlf,wm1811";
+ reg = <0x1a>;
+ clocks = <&pmu_system_controller 0>;
+ clock-names = "MCLK1";
+ DCVDD-supply = <&ldo3_reg>;
+ DBVDD1-supply = <&ldo3_reg>;
+ wlf,ldo1ena = <&gpj0 4 0>;
+ };
+};
+
+&i2c_7 {
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-slave-addr = <0x10>;
+ samsung,i2c-max-bus-freq = <100000>;
+ pinctrl-0 = <&i2c7_bus>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ max77686: max77686_pmic@09 {
+ compatible = "maxim,max77686";
+ interrupt-parent = <&gpx0>;
+ interrupts = <7 0>;
+ reg = <0x09>;
+ #clock-cells = <1>;
+
+ voltage-regulators {
+ ldo1_reg: ldo1 {
+ regulator-compatible = "LDO1";
+ regulator-name = "VALIVE_1.0V_AP";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo2_reg: ldo2 {
+ regulator-compatible = "LDO2";
+ regulator-name = "VM1M2_1.2V_AP";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ ldo3_reg: ldo3 {
+ regulator-compatible = "LDO3";
+ regulator-name = "VCC_1.8V_AP";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo4_reg: ldo4 {
+ regulator-compatible = "LDO4";
+ regulator-name = "VCC_2.8V_AP";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ ldo5_reg: ldo5 {
+ regulator-compatible = "LDO5";
+ regulator-name = "VCC_1.8V_IO";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo6_reg: ldo6 {
+ regulator-compatible = "LDO6";
+ regulator-name = "VMPLL_1.0V_AP";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ ldo7_reg: ldo7 {
+ regulator-compatible = "LDO7";
+ regulator-name = "VPLL_1.0V_AP";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ ldo8_reg: ldo8 {
+ regulator-compatible = "LDO8";
+ regulator-name = "VMIPI_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo9_reg: ldo9 {
+ regulator-compatible = "LDO9";
+ regulator-name = "CAM_ISP_MIPI_1.2V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ ldo10_reg: ldo10 {
+ regulator-compatible = "LDO10";
+ regulator-name = "VMIPI_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo11_reg: ldo11 {
+ regulator-compatible = "LDO11";
+ regulator-name = "VABB1_1.95V";
+ regulator-min-microvolt = <1950000>;
+ regulator-max-microvolt = <1950000>;
+ regulator-always-on;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo12_reg: ldo12 {
+ regulator-compatible = "LDO12";
+ regulator-name = "VUOTG_3.0V";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo13_reg: ldo13 {
+ regulator-compatible = "LDO13";
+ regulator-name = "NFC_AVDD_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo14_reg: ldo14 {
+ regulator-compatible = "LDO14";
+ regulator-name = "VABB2_1.95V";
+ regulator-min-microvolt = <1950000>;
+ regulator-max-microvolt = <1950000>;
+ regulator-always-on;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo15_reg: ldo15 {
+ regulator-compatible = "LDO15";
+ regulator-name = "VHSIC_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ ldo16_reg: ldo16 {
+ regulator-compatible = "LDO16";
+ regulator-name = "VHSIC_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ ldo17_reg: ldo17 {
+ regulator-compatible = "LDO17";
+ regulator-name = "CAM_SENSOR_CORE_1.2V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ ldo18_reg: ldo18 {
+ regulator-compatible = "LDO18";
+ regulator-name = "CAM_ISP_SEN_IO_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo19_reg: ldo19 {
+ regulator-compatible = "LDO19";
+ regulator-name = "VT_CAM_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo20_reg: ldo20 {
+ regulator-compatible = "LDO20";
+ regulator-name = "VDDQ_PRE_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo21_reg: ldo21 {
+ regulator-compatible = "LDO21";
+ regulator-name = "VTF_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ maxim,ena-gpios = <&gpy2 0 GPIO_ACTIVE_HIGH>;
+ };
+
+ ldo22_reg: ldo22 {
+ regulator-compatible = "LDO22";
+ regulator-name = "VMEM_VDD_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ maxim,ena-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
+ };
+
+ ldo23_reg: ldo23 {
+ regulator-compatible = "LDO23";
+ regulator-name = "TSP_AVDD_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo24_reg: ldo24 {
+ regulator-compatible = "LDO24";
+ regulator-name = "TSP_VDD_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo25_reg: ldo25 {
+ regulator-compatible = "LDO25";
+ regulator-name = "LCD_VCC_3.3V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ ldo26_reg: ldo26 {
+ regulator-compatible = "LDO26";
+ regulator-name = "MOTOR_VCC_3.0V";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ buck1_reg: buck1 {
+ regulator-compatible = "BUCK1";
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ buck2_reg: buck2 {
+ regulator-compatible = "BUCK2";
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ buck3_reg: buck3 {
+ regulator-compatible = "BUCK3";
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ buck4_reg: buck4 {
+ regulator-compatible = "BUCK4";
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-boot-on;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ buck5_reg: buck5 {
+ regulator-compatible = "BUCK5";
+ regulator-name = "VMEM_1.2V_AP";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ buck6_reg: buck6 {
+ regulator-compatible = "BUCK6";
+ regulator-name = "VCC_SUB_1.35V";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ };
+
+ buck7_reg: buck7 {
+ regulator-compatible = "BUCK7";
+ regulator-name = "VCC_SUB_2.0V";
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-always-on;
+ };
+
+ buck8_reg: buck8 {
+ regulator-compatible = "BUCK8";
+ regulator-name = "VMEM_VDDF_3.0V";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ maxim,ena-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
+ };
+
+ buck9_reg: buck9 {
+ regulator-compatible = "BUCK9";
+ regulator-name = "CAM_ISP_CORE_1.2V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1200000>;
+ maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>;
+ };
+ };
+ };
+};
+
+&i2s0 {
+ pinctrl-0 = <&i2s0_bus>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
+&mshc_0 {
+ num-slots = <1>;
+ broken-cd;
+ non-removable;
+ card-detect-delay = <200>;
+ vmmc-supply = <&ldo22_reg>;
+ clock-frequency = <400000000>;
+ samsung,dw-mshc-ciu-div = <0>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>;
+ pinctrl-names = "default";
+ status = "okay";
+ bus-width = <8>;
+ cap-mmc-highspeed;
+};
+
&pmu_system_controller {
assigned-clocks = <&pmu_system_controller 0>;
assigned-clock-parents = <&clock CLK_XUSBXTI>;
@@ -1304,3 +1253,63 @@
PIN_SLP(gpv4-0, INPUT, DOWN);
};
};
+
+&pwm {
+ pinctrl-0 = <&pwm0_out>;
+ pinctrl-names = "default";
+ samsung,pwm-outputs = <0>;
+ status = "okay";
+};
+
+&rtc {
+ status = "okay";
+ clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
+ clock-names = "rtc", "rtc_src";
+};
+
+&sdhci_2 {
+ bus-width = <4>;
+ cd-gpios = <&gpx3 4 0>;
+ cd-inverted;
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4>;
+ pinctrl-names = "default";
+ vmmc-supply = <&ldo21_reg>;
+ status = "okay";
+};
+
+&serial_0 {
+ status = "okay";
+};
+
+&serial_1 {
+ status = "okay";
+};
+
+&serial_2 {
+ status = "okay";
+};
+
+&serial_3 {
+ status = "okay";
+};
+
+&spi_1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_bus>;
+ cs-gpios = <&gpb 5 0>;
+ status = "okay";
+
+ s5c73m3_spi: s5c73m3 {
+ compatible = "samsung,s5c73m3";
+ spi-max-frequency = <50000000>;
+ reg = <0>;
+ controller-data {
+ samsung,spi-feedback-delay = <2>;
+ };
+ };
+};
+
+&tmu {
+ vtmu-supply = <&ldo10_reg>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi
index 68ad43b391ae..b78ada70bd05 100644
--- a/arch/arm/boot/dts/exynos4412.dtsi
+++ b/arch/arm/boot/dts/exynos4412.dtsi
@@ -54,19 +54,19 @@
};
};
- combiner: interrupt-controller@10440000 {
- samsung,combiner-nr = <20>;
- };
-
pmu {
interrupts = <2 2>, <3 2>, <18 2>, <19 2>;
};
+};
- gic: interrupt-controller@10490000 {
- cpu-offset = <0x4000>;
- };
+&pmu_system_controller {
+ compatible = "samsung,exynos4412-pmu", "syscon";
+};
- pmu_system_controller: system-controller@10020000 {
- compatible = "samsung,exynos4412-pmu", "syscon";
- };
+&combiner {
+ samsung,combiner-nr = <20>;
+};
+
+&gic {
+ cpu-offset = <0x4000>;
};
diff --git a/arch/arm/boot/dts/exynos4415.dtsi b/arch/arm/boot/dts/exynos4415.dtsi
index 5caea996e090..ad764842fff5 100644
--- a/arch/arm/boot/dts/exynos4415.dtsi
+++ b/arch/arm/boot/dts/exynos4415.dtsi
@@ -124,8 +124,8 @@
mipi_phy: video-phy@10020710 {
compatible = "samsung,s5pv210-mipi-video-phy";
- reg = <0x10020710 8>;
#phy-cells = <1>;
+ syscon = <&pmu_system_controller>;
};
pd_cam: cam-power-domain@10024000 {
@@ -177,7 +177,7 @@
};
rtc: rtc@10070000 {
- compatible = "samsung,exynos3250-rtc";
+ compatible = "samsung,s3c6410-rtc";
reg = <0x10070000 0x100>;
interrupts = <0 73 0>, <0 74 0>;
status = "disabled";
@@ -249,6 +249,7 @@
clocks = <&cmu CLK_SCLK_FIMD0>, <&cmu CLK_FIMD0>;
clock-names = "sclk_fimd", "fimd";
samsung,power-domain = <&pd_lcd0>;
+ iommus = <&sysmmu_fimd0>;
samsung,sysreg = <&sysreg_system_controller>;
status = "disabled";
};
@@ -268,6 +269,16 @@
status = "disabled";
};
+ sysmmu_fimd0: sysmmu@11E20000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11e20000 0x1000>;
+ interrupts = <0 80 0>, <0 81 0>;
+ clock-names = "sysmmu", "master";
+ clocks = <&cmu CLK_SMMUFIMD0>, <&cmu CLK_FIMD0>;
+ power-domains = <&pd_lcd0>;
+ #iommu-cells = <0>;
+ };
+
hsotg: hsotg@12480000 {
compatible = "samsung,s3c6400-hsotg";
reg = <0x12480000 0x20000>;
diff --git a/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi b/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
index c141931378e7..bac25c672789 100644
--- a/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
@@ -29,7 +29,7 @@
}
/ {
- pinctrl@11400000 {
+ pinctrl_0: pinctrl@11400000 {
gpa0: gpa0 {
gpio-controller;
#gpio-cells = <2>;
@@ -441,7 +441,7 @@
};
};
- pinctrl@11000000 {
+ pinctrl_1: pinctrl@11000000 {
gpk0: gpk0 {
gpio-controller;
#gpio-cells = <2>;
@@ -887,7 +887,7 @@
};
};
- pinctrl@03860000 {
+ pinctrl_2: pinctrl@03860000 {
gpz: gpz {
gpio-controller;
#gpio-cells = <2>;
@@ -913,7 +913,7 @@
};
};
- pinctrl@106E0000 {
+ pinctrl_3: pinctrl@106E0000 {
gpv0: gpv0 {
gpio-controller;
#gpio-cells = <2>;
diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index 6a6abe14fd9b..b77dac61ffb5 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -96,32 +96,6 @@
};
};
- combiner: interrupt-controller@10440000 {
- interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
- <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
- <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
- <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>,
- <0 107 0>, <0 108 0>, <0 48 0>, <0 42 0>;
- };
-
- pinctrl_0: pinctrl@11400000 {
- compatible = "samsung,exynos4x12-pinctrl";
- reg = <0x11400000 0x1000>;
- interrupts = <0 47 0>;
- };
-
- pinctrl_1: pinctrl@11000000 {
- compatible = "samsung,exynos4x12-pinctrl";
- reg = <0x11000000 0x1000>;
- interrupts = <0 46 0>;
-
- wakup_eint: wakeup-interrupt-controller {
- compatible = "samsung,exynos4210-wakeup-eint";
- interrupt-parent = <&gic>;
- interrupts = <0 32 0>;
- };
- };
-
adc: adc@126C0000 {
compatible = "samsung,exynos-adc-v1";
reg = <0x126C0000 0x100>;
@@ -135,36 +109,13 @@
status = "disabled";
};
- pinctrl_2: pinctrl@03860000 {
- compatible = "samsung,exynos4x12-pinctrl";
- reg = <0x03860000 0x1000>;
- interrupt-parent = <&combiner>;
- interrupts = <10 0>;
- };
-
- pinctrl_3: pinctrl@106E0000 {
- compatible = "samsung,exynos4x12-pinctrl";
- reg = <0x106E0000 0x1000>;
- interrupts = <0 72 0>;
- };
-
- pmu_system_controller: system-controller@10020000 {
- compatible = "samsung,exynos4212-pmu", "syscon";
- clock-names = "clkout0", "clkout1", "clkout2", "clkout3",
- "clkout4", "clkout8", "clkout9";
- clocks = <&clock CLK_OUT_DMC>, <&clock CLK_OUT_TOP>,
- <&clock CLK_OUT_LEFTBUS>, <&clock CLK_OUT_RIGHTBUS>,
- <&clock CLK_OUT_CPU>, <&clock CLK_XXTI>,
- <&clock CLK_XUSBXTI>;
- #clock-cells = <1>;
- };
-
- g2d@10800000 {
+ g2d: g2d@10800000 {
compatible = "samsung,exynos4212-g2d";
reg = <0x10800000 0x1000>;
interrupts = <0 89 0>;
clocks = <&clock CLK_SCLK_FIMG2D>, <&clock CLK_G2D>;
clock-names = "sclk_fimg2d", "fimg2d";
+ iommus = <&sysmmu_g2d>;
status = "disabled";
};
@@ -173,40 +124,7 @@
<&clock CLK_PIXELASYNCM0>, <&clock CLK_PIXELASYNCM1>;
clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", "pxl_async1";
- fimc_0: fimc@11800000 {
- compatible = "samsung,exynos4212-fimc";
- samsung,pix-limits = <4224 8192 1920 4224>;
- samsung,mainscaler-ext;
- samsung,isp-wb;
- samsung,cam-if;
- };
-
- fimc_1: fimc@11810000 {
- compatible = "samsung,exynos4212-fimc";
- samsung,pix-limits = <4224 8192 1920 4224>;
- samsung,mainscaler-ext;
- samsung,isp-wb;
- samsung,cam-if;
- };
-
- fimc_2: fimc@11820000 {
- compatible = "samsung,exynos4212-fimc";
- samsung,pix-limits = <4224 8192 1920 4224>;
- samsung,mainscaler-ext;
- samsung,isp-wb;
- samsung,lcd-wb;
- samsung,cam-if;
- };
-
- fimc_3: fimc@11830000 {
- compatible = "samsung,exynos4212-fimc";
- samsung,pix-limits = <1920 8192 1366 1920>;
- samsung,rotators = <0>;
- samsung,mainscaler-ext;
- samsung,isp-wb;
- samsung,lcd-wb;
- };
-
+ /* fimc_[0-3] are configured outside, under phandles */
fimc_lite_0: fimc-lite@12390000 {
compatible = "samsung,exynos4212-fimc-lite";
reg = <0x12390000 0x1000>;
@@ -214,6 +132,7 @@
power-domains = <&pd_isp>;
clocks = <&clock CLK_FIMC_LITE0>;
clock-names = "flite";
+ iommus = <&sysmmu_fimc_lite0>;
status = "disabled";
};
@@ -224,6 +143,7 @@
power-domains = <&pd_isp>;
clocks = <&clock CLK_FIMC_LITE1>;
clock-names = "flite";
+ iommus = <&sysmmu_fimc_lite1>;
status = "disabled";
};
@@ -252,6 +172,9 @@
"mcuispdiv1", "uart", "aclk200",
"div_aclk200", "aclk400mcuisp",
"div_aclk400mcuisp";
+ iommus = <&sysmmu_fimc_isp>, <&sysmmu_fimc_drc>,
+ <&sysmmu_fimc_fd>, <&sysmmu_fimc_mcuctl>;
+ iommu-names = "isp", "drc", "fd", "mcuctl";
#address-cells = <1>;
#size-cells = <1>;
ranges;
@@ -284,29 +207,192 @@
status = "disabled";
};
- exynos-usbphy@125B0000 {
- compatible = "samsung,exynos4x12-usb2-phy";
- samsung,sysreg-phandle = <&sys_reg>;
+ sysmmu_g2d: sysmmu@10A40000{
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x10A40000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <4 7>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_G2D>, <&clock CLK_G2D>;
+ #iommu-cells = <0>;
};
- tmu@100C0000 {
- compatible = "samsung,exynos4412-tmu";
+ sysmmu_fimc_isp: sysmmu@12260000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x12260000 0x1000>;
interrupt-parent = <&combiner>;
- interrupts = <2 4>;
- reg = <0x100C0000 0x100>;
- clocks = <&clock 383>;
- clock-names = "tmu_apbif";
- status = "disabled";
+ interrupts = <16 2>;
+ power-domains = <&pd_isp>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_ISP>;
+ #iommu-cells = <0>;
};
- hdmi: hdmi@12D00000 {
- compatible = "samsung,exynos4212-hdmi";
+ sysmmu_fimc_drc: sysmmu@12270000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x12270000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <16 3>;
+ power-domains = <&pd_isp>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_DRC>;
+ #iommu-cells = <0>;
};
- mixer: mixer@12C10000 {
- compatible = "samsung,exynos4212-mixer";
- clock-names = "mixer", "hdmi", "sclk_hdmi", "vp";
- clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
- <&clock CLK_SCLK_HDMI>, <&clock CLK_VP>;
+ sysmmu_fimc_fd: sysmmu@122A0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x122A0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <16 4>;
+ power-domains = <&pd_isp>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_FD>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_mcuctl: sysmmu@122B0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x122B0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <16 5>;
+ power-domains = <&pd_isp>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_ISPCX>;
+ #iommu-cells = <0>;
};
+
+ sysmmu_fimc_lite0: sysmmu@123B0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x123B0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <16 0>;
+ power-domains = <&pd_isp>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_LITE0>, <&clock CLK_FIMC_LITE0>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_lite1: sysmmu@123C0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x123C0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <16 1>;
+ power-domains = <&pd_isp>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_LITE1>, <&clock CLK_FIMC_LITE1>;
+ #iommu-cells = <0>;
+ };
+};
+
+&combiner {
+ interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
+ <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
+ <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
+ <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>,
+ <0 107 0>, <0 108 0>, <0 48 0>, <0 42 0>;
+};
+
+&exynos_usbphy {
+ compatible = "samsung,exynos4x12-usb2-phy";
+ samsung,sysreg-phandle = <&sys_reg>;
+};
+
+&fimc_0 {
+ compatible = "samsung,exynos4212-fimc";
+ samsung,pix-limits = <4224 8192 1920 4224>;
+ samsung,mainscaler-ext;
+ samsung,isp-wb;
+ samsung,cam-if;
+};
+
+&fimc_1 {
+ compatible = "samsung,exynos4212-fimc";
+ samsung,pix-limits = <4224 8192 1920 4224>;
+ samsung,mainscaler-ext;
+ samsung,isp-wb;
+ samsung,cam-if;
+};
+
+&fimc_2 {
+ compatible = "samsung,exynos4212-fimc";
+ samsung,pix-limits = <4224 8192 1920 4224>;
+ samsung,mainscaler-ext;
+ samsung,isp-wb;
+ samsung,lcd-wb;
+ samsung,cam-if;
+};
+
+&fimc_3 {
+ compatible = "samsung,exynos4212-fimc";
+ samsung,pix-limits = <1920 8192 1366 1920>;
+ samsung,rotators = <0>;
+ samsung,mainscaler-ext;
+ samsung,isp-wb;
+ samsung,lcd-wb;
+};
+
+&hdmi {
+ compatible = "samsung,exynos4212-hdmi";
+};
+
+&jpeg_codec {
+ compatible = "samsung,exynos4212-jpeg";
+};
+
+&mixer {
+ compatible = "samsung,exynos4212-mixer";
+ clock-names = "mixer", "hdmi", "sclk_hdmi", "vp";
+ clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
+ <&clock CLK_SCLK_HDMI>, <&clock CLK_VP>;
+};
+
+&pinctrl_0 {
+ compatible = "samsung,exynos4x12-pinctrl";
+ reg = <0x11400000 0x1000>;
+ interrupts = <0 47 0>;
+};
+
+&pinctrl_1 {
+ compatible = "samsung,exynos4x12-pinctrl";
+ reg = <0x11000000 0x1000>;
+ interrupts = <0 46 0>;
+
+ wakup_eint: wakeup-interrupt-controller {
+ compatible = "samsung,exynos4210-wakeup-eint";
+ interrupt-parent = <&gic>;
+ interrupts = <0 32 0>;
+ };
+};
+
+&pinctrl_2 {
+ compatible = "samsung,exynos4x12-pinctrl";
+ reg = <0x03860000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <10 0>;
+};
+
+&pinctrl_3 {
+ compatible = "samsung,exynos4x12-pinctrl";
+ reg = <0x106E0000 0x1000>;
+ interrupts = <0 72 0>;
+};
+
+&pmu_system_controller {
+ compatible = "samsung,exynos4212-pmu", "syscon";
+ clock-names = "clkout0", "clkout1", "clkout2", "clkout3",
+ "clkout4", "clkout8", "clkout9";
+ clocks = <&clock CLK_OUT_DMC>, <&clock CLK_OUT_TOP>,
+ <&clock CLK_OUT_LEFTBUS>, <&clock CLK_OUT_RIGHTBUS>,
+ <&clock CLK_OUT_CPU>, <&clock CLK_XXTI>, <&clock CLK_XUSBXTI>;
+ #clock-cells = <1>;
+};
+
+&tmu {
+ compatible = "samsung,exynos4412-tmu";
+ interrupt-parent = <&combiner>;
+ interrupts = <2 4>;
+ reg = <0x100C0000 0x100>;
+ clocks = <&clock 383>;
+ clock-names = "tmu_apbif";
+ status = "disabled";
};
diff --git a/arch/arm/boot/dts/exynos5.dtsi b/arch/arm/boot/dts/exynos5.dtsi
index a0cc0b6f8f96..110dbd4fb884 100644
--- a/arch/arm/boot/dts/exynos5.dtsi
+++ b/arch/arm/boot/dts/exynos5.dtsi
@@ -81,14 +81,14 @@
interrupts = <0 54 0>;
};
- rtc@101E0000 {
+ rtc: rtc@101E0000 {
compatible = "samsung,s3c6410-rtc";
reg = <0x101E0000 0x100>;
interrupts = <0 43 0>, <0 44 0>;
status = "disabled";
};
- fimd@14400000 {
+ fimd: fimd@14400000 {
compatible = "samsung,exynos5250-fimd";
interrupt-parent = <&combiner>;
reg = <0x14400000 0x40000>;
@@ -98,7 +98,7 @@
status = "disabled";
};
- dp-controller@145B0000 {
+ dp: dp-controller@145B0000 {
compatible = "samsung,exynos5-dp";
reg = <0x145B0000 0x1000>;
interrupts = <10 3>;
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index bc27cc2558fe..4fe186d01f8a 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -131,6 +131,9 @@
reg = <0x09>;
interrupt-parent = <&gpx3>;
interrupts = <2 IRQ_TYPE_NONE>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&max77686_irq>;
+ wakeup-source;
voltage-regulators {
ldo1_reg: LDO1 {
@@ -410,3 +413,12 @@
};
};
};
+
+&pinctrl_0 {
+ max77686_irq: max77686-irq {
+ samsung,pins = "gpx3-2";
+ samsung,pin-function = <0xf>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
index 1eca97ee4bd6..b7f4122df456 100644
--- a/arch/arm/boot/dts/exynos5250-snow.dts
+++ b/arch/arm/boot/dts/exynos5250-snow.dts
@@ -177,30 +177,6 @@
};
};
- i2c@12CD0000 {
- ptn3460: lvds-bridge@20 {
- compatible = "nxp,ptn3460";
- reg = <0x20>;
- powerdown-gpios = <&gpy2 5 GPIO_ACTIVE_HIGH>;
- reset-gpios = <&gpx1 5 GPIO_ACTIVE_HIGH>;
- edid-emulation = <5>;
-
- ports {
- port@0 {
- bridge_out: endpoint {
- remote-endpoint = <&panel_in>;
- };
- };
-
- port@1 {
- bridge_in: endpoint {
- remote-endpoint = <&dp_out>;
- };
- };
- };
- };
- };
-
sound {
compatible = "google,snow-audio-max98095";
@@ -507,6 +483,28 @@
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <66000>;
+ ptn3460: lvds-bridge@20 {
+ compatible = "nxp,ptn3460";
+ reg = <0x20>;
+ powerdown-gpios = <&gpy2 5 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpx1 5 GPIO_ACTIVE_HIGH>;
+ edid-emulation = <5>;
+
+ ports {
+ port@0 {
+ bridge_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+
+ port@1 {
+ bridge_in: endpoint {
+ remote-endpoint = <&dp_out>;
+ };
+ };
+ };
+ };
+
max98095: codec@11 {
compatible = "maxim,max98095";
reg = <0x11>;
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index 257e2f10525d..bf9bee67c416 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -230,6 +230,7 @@
interrupts = <0 91 0>;
clocks = <&clock CLK_G2D>;
clock-names = "fimg2d";
+ iommus = <&sysmmu_g2d>;
};
mfc: codec@11000000 {
@@ -239,13 +240,8 @@
power-domains = <&pd_mfc>;
clocks = <&clock CLK_MFC>;
clock-names = "mfc";
- };
-
- rtc: rtc@101E0000 {
- clocks = <&clock CLK_RTC>;
- clock-names = "rtc";
- interrupt-parent = <&pmu_system_controller>;
- status = "disabled";
+ iommus = <&sysmmu_mfc_l>, <&sysmmu_mfc_r>;
+ iommu-names = "left", "right";
};
tmu: tmu@10060000 {
@@ -276,26 +272,6 @@
};
};
- serial@12C00000 {
- clocks = <&clock CLK_UART0>, <&clock CLK_SCLK_UART0>;
- clock-names = "uart", "clk_uart_baud0";
- };
-
- serial@12C10000 {
- clocks = <&clock CLK_UART1>, <&clock CLK_SCLK_UART1>;
- clock-names = "uart", "clk_uart_baud0";
- };
-
- serial@12C20000 {
- clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>;
- clock-names = "uart", "clk_uart_baud0";
- };
-
- serial@12C30000 {
- clocks = <&clock CLK_UART3>, <&clock CLK_SCLK_UART3>;
- clock-names = "uart", "clk_uart_baud0";
- };
-
sata: sata@122F0000 {
compatible = "snps,dwc-ahci";
samsung,sata-freq = <66>;
@@ -720,6 +696,7 @@
power-domains = <&pd_gsc>;
clocks = <&clock CLK_GSCL0>;
clock-names = "gscl";
+ iommu = <&sysmmu_gsc0>;
};
gsc_1: gsc@13e10000 {
@@ -729,6 +706,7 @@
power-domains = <&pd_gsc>;
clocks = <&clock CLK_GSCL1>;
clock-names = "gscl";
+ iommu = <&sysmmu_gsc1>;
};
gsc_2: gsc@13e20000 {
@@ -738,6 +716,7 @@
power-domains = <&pd_gsc>;
clocks = <&clock CLK_GSCL2>;
clock-names = "gscl";
+ iommu = <&sysmmu_gsc2>;
};
gsc_3: gsc@13e30000 {
@@ -747,6 +726,7 @@
power-domains = <&pd_gsc>;
clocks = <&clock CLK_GSCL3>;
clock-names = "gscl";
+ iommu = <&sysmmu_gsc3>;
};
hdmi: hdmi {
@@ -770,6 +750,7 @@
clocks = <&clock CLK_MIXER>, <&clock CLK_HDMI>,
<&clock CLK_SCLK_HDMI>;
clock-names = "mixer", "hdmi", "sclk_hdmi";
+ iommus = <&sysmmu_tv>;
};
dp_phy: video-phy@10040720 {
@@ -778,20 +759,6 @@
#phy-cells = <0>;
};
- dp: dp-controller@145B0000 {
- power-domains = <&pd_disp1>;
- clocks = <&clock CLK_DP>;
- clock-names = "dp";
- phys = <&dp_phy>;
- phy-names = "dp";
- };
-
- fimd: fimd@14400000 {
- power-domains = <&pd_disp1>;
- clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>;
- clock-names = "sclk_fimd", "fimd";
- };
-
adc: adc@12D10000 {
compatible = "samsung,exynos-adc-v1";
reg = <0x12D10000 0x100>;
@@ -811,4 +778,287 @@
clocks = <&clock CLK_SSS>;
clock-names = "secss";
};
+
+ sysmmu_g2d: sysmmu@10A60000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x10A60000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <24 5>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_2D>, <&clock CLK_G2D>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_mfc_r: sysmmu@11200000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11200000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <6 2>;
+ power-domains = <&pd_mfc>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MFCR>, <&clock CLK_MFC>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_mfc_l: sysmmu@11210000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11210000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <8 5>;
+ power-domains = <&pd_mfc>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MFCL>, <&clock CLK_MFC>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_rotator: sysmmu@11D40000 {
+ 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_jpeg: sysmmu@11F20000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11F20000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <4 2>;
+ power-domains = <&pd_gsc>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_JPEG>, <&clock CLK_JPEG>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_isp: sysmmu@13260000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13260000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <10 6>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_FIMC_ISP>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_drc: sysmmu@13270000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13270000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <11 6>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_FIMC_DRC>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_fd: sysmmu@132A0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x132A0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <5 0>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_FIMC_FD>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_scc: sysmmu@13280000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13280000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <5 2>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_FIMC_SCC>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_scp: sysmmu@13290000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13290000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <3 6>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_FIMC_SCP>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_mcuctl: sysmmu@132B0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x132B0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <5 4>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_FIMC_MCU>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_odc: sysmmu@132C0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x132C0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <11 0>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_FIMC_ODC>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_dis0: sysmmu@132D0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x132D0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <10 4>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_FIMC_DIS0>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_dis1: sysmmu@132E0000{
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x132E0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <9 4>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_FIMC_DIS1>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_3dnr: sysmmu@132F0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x132F0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <5 6>;
+ clock-names = "sysmmu";
+ clocks = <&clock CLK_SMMU_FIMC_3DNR>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_lite0: sysmmu@13C40000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13C40000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <3 4>;
+ power-domains = <&pd_gsc>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_FIMC_LITE0>, <&clock CLK_CAMIF_TOP>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimc_lite1: sysmmu@13C50000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13C50000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <24 1>;
+ power-domains = <&pd_gsc>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_FIMC_LITE1>, <&clock CLK_CAMIF_TOP>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_gsc0: sysmmu@13E80000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13E80000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <2 0>;
+ power-domains = <&pd_gsc>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_GSCL0>, <&clock CLK_GSCL0>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_gsc1: sysmmu@13E90000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13E90000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <2 2>;
+ power-domains = <&pd_gsc>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_GSCL1>, <&clock CLK_GSCL1>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_gsc2: sysmmu@13EA0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13EA0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <2 4>;
+ power-domains = <&pd_gsc>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_GSCL2>, <&clock CLK_GSCL2>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_gsc3: sysmmu@13EB0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13EB0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <2 6>;
+ power-domains = <&pd_gsc>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_GSCL3>, <&clock CLK_GSCL3>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimd1: sysmmu@14640000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x14640000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <3 2>;
+ power-domains = <&pd_disp1>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_FIMD1>, <&clock CLK_FIMD1>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_tv: sysmmu@14650000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x14650000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <7 4>;
+ power-domains = <&pd_disp1>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_TV>, <&clock CLK_MIXER>;
+ #iommu-cells = <0>;
+ };
+};
+
+&dp {
+ power-domains = <&pd_disp1>;
+ clocks = <&clock CLK_DP>;
+ clock-names = "dp";
+ phys = <&dp_phy>;
+ phy-names = "dp";
+};
+
+&fimd {
+ power-domains = <&pd_disp1>;
+ clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>;
+ clock-names = "sclk_fimd", "fimd";
+ iommus = <&sysmmu_fimd1>;
+};
+
+&rtc {
+ clocks = <&clock CLK_RTC>;
+ clock-names = "rtc";
+ interrupt-parent = <&pmu_system_controller>;
+ status = "disabled";
+};
+
+&serial_0 {
+ clocks = <&clock CLK_UART0>, <&clock CLK_SCLK_UART0>;
+ clock-names = "uart", "clk_uart_baud0";
+};
+
+&serial_1 {
+ clocks = <&clock CLK_UART1>, <&clock CLK_SCLK_UART1>;
+ clock-names = "uart", "clk_uart_baud0";
+};
+
+&serial_2 {
+ clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>;
+ clock-names = "uart", "clk_uart_baud0";
+};
+
+&serial_3 {
+ clocks = <&clock CLK_UART3>, <&clock CLK_SCLK_UART3>;
+ clock-names = "uart", "clk_uart_baud0";
};
diff --git a/arch/arm/boot/dts/exynos5260-xyref5260.dts b/arch/arm/boot/dts/exynos5260-xyref5260.dts
index a803b605051b..3daef94bee38 100644
--- a/arch/arm/boot/dts/exynos5260-xyref5260.dts
+++ b/arch/arm/boot/dts/exynos5260-xyref5260.dts
@@ -70,7 +70,7 @@
broken-cd;
bypass-smu;
cap-mmc-highspeed;
- supports-hs200-mode; /* 200 Mhz */
+ supports-hs200-mode; /* 200 MHz */
card-detect-delay = <200>;
samsung,dw-mshc-ciu-div = <3>;
samsung,dw-mshc-sdr-timing = <0 4>;
diff --git a/arch/arm/boot/dts/exynos5420-arndale-octa.dts b/arch/arm/boot/dts/exynos5420-arndale-octa.dts
index b82b6fa15f48..eeb4ac22cfce 100644
--- a/arch/arm/boot/dts/exynos5420-arndale-octa.dts
+++ b/arch/arm/boot/dts/exynos5420-arndale-octa.dts
@@ -13,6 +13,7 @@
#include "exynos5420.dtsi"
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/input.h>
+#include <dt-bindings/clock/samsung,s2mps11.h>
/ {
model = "Insignal Arndale Octa evaluation board based on EXYNOS5420";
@@ -38,325 +39,6 @@
};
};
- rtc@101E0000 {
- status = "okay";
- };
-
- codec@11000000 {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
- };
-
- mmc@12200000 {
- status = "okay";
- broken-cd;
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
- vmmc-supply = <&ldo10_reg>;
- bus-width = <8>;
- cap-mmc-highspeed;
- };
-
- mmc@12220000 {
- status = "okay";
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>;
- vmmc-supply = <&ldo19_reg>;
- vqmmc-supply = <&ldo13_reg>;
- bus-width = <4>;
- cap-sd-highspeed;
- };
-
- hsi2c_4: i2c@12CA0000 {
- status = "okay";
-
- s2mps11_pmic@66 {
- compatible = "samsung,s2mps11-pmic";
- reg = <0x66>;
- s2mps11,buck2-ramp-delay = <12>;
- s2mps11,buck34-ramp-delay = <12>;
- s2mps11,buck16-ramp-delay = <12>;
- s2mps11,buck6-ramp-enable = <1>;
- s2mps11,buck2-ramp-enable = <1>;
- s2mps11,buck3-ramp-enable = <1>;
- s2mps11,buck4-ramp-enable = <1>;
-
- interrupt-parent = <&gpx3>;
- interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
-
- s2mps11_osc: clocks {
- #clock-cells = <1>;
- clock-output-names = "s2mps11_ap",
- "s2mps11_cp", "s2mps11_bt";
- };
-
- regulators {
- ldo1_reg: LDO1 {
- regulator-name = "PVDD_ALIVE_1V0";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo2_reg: LDO2 {
- regulator-name = "PVDD_APIO_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo3_reg: LDO3 {
- regulator-name = "PVDD_APIO_MMCON_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo4_reg: LDO4 {
- regulator-name = "PVDD_ADC_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo5_reg: LDO5 {
- regulator-name = "PVDD_PLL_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo6_reg: LDO6 {
- regulator-name = "PVDD_ANAIP_1V0";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- };
-
- ldo7_reg: LDO7 {
- regulator-name = "PVDD_ANAIP_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo8_reg: LDO8 {
- regulator-name = "PVDD_ABB_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo9_reg: LDO9 {
- regulator-name = "PVDD_USB_3V3";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-always-on;
- };
-
- ldo10_reg: LDO10 {
- regulator-name = "PVDD_PRE_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo11_reg: LDO11 {
- regulator-name = "PVDD_USB_1V0";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo12_reg: LDO12 {
- regulator-name = "PVDD_HSIC_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo13_reg: LDO13 {
- regulator-name = "PVDD_APIO_MMCOFF_2V8";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- };
-
- ldo15_reg: LDO15 {
- regulator-name = "PVDD_PERI_2V8";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
-
- ldo16_reg: LDO16 {
- regulator-name = "PVDD_PERI_3V3";
- regulator-min-microvolt = <2200000>;
- regulator-max-microvolt = <2200000>;
- };
-
- ldo18_reg: LDO18 {
- regulator-name = "PVDD_EMMC_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo19_reg: LDO19 {
- regulator-name = "PVDD_TFLASH_2V8";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- };
-
- ldo20_reg: LDO20 {
- regulator-name = "PVDD_BTWIFI_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo21_reg: LDO21 {
- regulator-name = "PVDD_CAM1IO_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo23_reg: LDO23 {
- regulator-name = "PVDD_MIFS_1V1";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- };
-
- ldo24_reg: LDO24 {
- regulator-name = "PVDD_CAM1_AVDD_2V8";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- };
-
- ldo26_reg: LDO26 {
- regulator-name = "PVDD_CAM0_AF_2V8";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- };
-
- ldo27_reg: LDO27 {
- regulator-name = "PVDD_G3DS_1V0";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
-
- ldo28_reg: LDO28 {
- regulator-name = "PVDD_TSP_3V3";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
-
- ldo29_reg: LDO29 {
- regulator-name = "PVDD_AUDIO_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo31_reg: LDO31 {
- regulator-name = "PVDD_PERI_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo32_reg: LDO32 {
- regulator-name = "PVDD_LCD_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo33_reg: LDO33 {
- regulator-name = "PVDD_CAM0IO_1V8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo35_reg: LDO35 {
- regulator-name = "PVDD_CAM0_DVDD_1V2";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
-
- ldo38_reg: LDO38 {
- regulator-name = "PVDD_CAM0_AVDD_2V8";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- };
-
- buck1_reg: BUCK1 {
- regulator-name = "PVDD_MIF_1V1";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- };
-
- buck2_reg: BUCK2 {
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- buck3_reg: BUCK3 {
- regulator-name = "PVDD_INT_1V0";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- buck4_reg: BUCK4 {
- regulator-name = "PVDD_G3D_1V0";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1000000>;
- };
-
- buck5_reg: BUCK5 {
- regulator-name = "PVDD_LPDDR3_1V2";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- };
-
- buck6_reg: BUCK6 {
- regulator-name = "PVDD_KFC_1V0";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- buck7_reg: BUCK7 {
- regulator-name = "VIN_LLDO_1V4";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1400000>;
- regulator-always-on;
- };
-
- buck8_reg: BUCK8 {
- regulator-name = "VIN_MLDO_2V0";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <2000000>;
- regulator-always-on;
- };
-
- buck9_reg: BUCK9 {
- regulator-name = "VIN_HLDO_3V5";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3500000>;
- regulator-always-on;
- };
-
- buck10_reg: BUCK10 {
- regulator-name = "PVDD_EMMCF_2V8";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- };
- };
- };
- };
-
gpio_keys {
compatible = "gpio-keys";
@@ -376,3 +58,335 @@
&cci {
status = "disabled";
};
+
+&hsi2c_4 {
+ status = "okay";
+
+ s2mps11_pmic@66 {
+ compatible = "samsung,s2mps11-pmic";
+ reg = <0x66>;
+ s2mps11,buck2-ramp-delay = <12>;
+ s2mps11,buck34-ramp-delay = <12>;
+ s2mps11,buck16-ramp-delay = <12>;
+ s2mps11,buck6-ramp-enable = <1>;
+ s2mps11,buck2-ramp-enable = <1>;
+ s2mps11,buck3-ramp-enable = <1>;
+ s2mps11,buck4-ramp-enable = <1>;
+
+ interrupt-parent = <&gpx3>;
+ interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&s2mps11_irq>;
+
+ s2mps11_osc: clocks {
+ #clock-cells = <1>;
+ clock-output-names = "s2mps11_ap",
+ "s2mps11_cp", "s2mps11_bt";
+ };
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "PVDD_ALIVE_1V0";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "PVDD_APIO_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "PVDD_APIO_MMCON_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo4_reg: LDO4 {
+ regulator-name = "PVDD_ADC_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "PVDD_PLL_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "PVDD_ANAIP_1V0";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "PVDD_ANAIP_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "PVDD_ABB_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo9_reg: LDO9 {
+ regulator-name = "PVDD_USB_3V3";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "PVDD_PRE_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "PVDD_USB_1V0";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "PVDD_HSIC_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo13_reg: LDO13 {
+ regulator-name = "PVDD_APIO_MMCOFF_2V8";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "PVDD_PERI_2V8";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "PVDD_PERI_3V3";
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ };
+
+ ldo18_reg: LDO18 {
+ regulator-name = "PVDD_EMMC_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo19_reg: LDO19 {
+ regulator-name = "PVDD_TFLASH_2V8";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ ldo20_reg: LDO20 {
+ regulator-name = "PVDD_BTWIFI_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo21_reg: LDO21 {
+ regulator-name = "PVDD_CAM1IO_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo23_reg: LDO23 {
+ regulator-name = "PVDD_MIFS_1V1";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ ldo24_reg: LDO24 {
+ regulator-name = "PVDD_CAM1_AVDD_2V8";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ ldo26_reg: LDO26 {
+ regulator-name = "PVDD_CAM0_AF_2V8";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ ldo27_reg: LDO27 {
+ regulator-name = "PVDD_G3DS_1V0";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ ldo28_reg: LDO28 {
+ regulator-name = "PVDD_TSP_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo29_reg: LDO29 {
+ regulator-name = "PVDD_AUDIO_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo31_reg: LDO31 {
+ regulator-name = "PVDD_PERI_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo32_reg: LDO32 {
+ regulator-name = "PVDD_LCD_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo33_reg: LDO33 {
+ regulator-name = "PVDD_CAM0IO_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo35_reg: LDO35 {
+ regulator-name = "PVDD_CAM0_DVDD_1V2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+
+ ldo38_reg: LDO38 {
+ regulator-name = "PVDD_CAM0_AVDD_2V8";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "PVDD_MIF_1V1";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "PVDD_INT_1V0";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "PVDD_G3D_1V0";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "PVDD_LPDDR3_1V2";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ buck6_reg: BUCK6 {
+ regulator-name = "PVDD_KFC_1V0";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ buck7_reg: BUCK7 {
+ regulator-name = "VIN_LLDO_1V4";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-always-on;
+ };
+
+ buck8_reg: BUCK8 {
+ regulator-name = "VIN_MLDO_2V0";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-always-on;
+ };
+
+ buck9_reg: BUCK9 {
+ regulator-name = "VIN_HLDO_3V5";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3500000>;
+ regulator-always-on;
+ };
+
+ buck10_reg: BUCK10 {
+ regulator-name = "PVDD_EMMCF_2V8";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+ };
+ };
+};
+
+&mfc {
+ samsung,mfc-r = <0x43000000 0x800000>;
+ samsung,mfc-l = <0x51000000 0x800000>;
+};
+
+&mmc_0 {
+ status = "okay";
+ broken-cd;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <0 4>;
+ samsung,dw-mshc-ddr-timing = <0 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
+ vmmc-supply = <&ldo10_reg>;
+ bus-width = <8>;
+ cap-mmc-highspeed;
+};
+
+&mmc_2 {
+ status = "okay";
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>;
+ vmmc-supply = <&ldo19_reg>;
+ vqmmc-supply = <&ldo13_reg>;
+ bus-width = <4>;
+ cap-sd-highspeed;
+};
+
+&pinctrl_0 {
+ s2mps11_irq: s2mps11-irq {
+ samsung,pins = "gpx3-2";
+ samsung,pin-function = <0xf>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&rtc {
+ status = "okay";
+ clocks = <&clock CLK_RTC>, <&s2mps11_osc S2MPS11_CLK_AP>;
+ clock-names = "rtc", "rtc_src";
+};
diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index 146e71118a72..8f4d76c5e11c 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -1027,7 +1027,7 @@
};
};
-&uart_3 {
+&serial_3 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts
index 9103f2381a6d..98871f972c8a 100644
--- a/arch/arm/boot/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts
@@ -64,105 +64,6 @@
};
};
- rtc@101E0000 {
- status = "okay";
- };
-
- codec@11000000 {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
- };
-
- mmc@12200000 {
- status = "okay";
- broken-cd;
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
- samsung,dw-mshc-hs400-timing = <0 2>;
- samsung,read-strobe-delay = <90>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8
- &sd0_rclk>;
- bus-width = <8>;
- cap-mmc-highspeed;
- };
-
- mmc@12220000 {
- status = "okay";
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>;
- bus-width = <4>;
- cap-sd-highspeed;
- };
-
- dp-controller@145B0000 {
- pinctrl-names = "default";
- pinctrl-0 = <&dp_hpd>;
- samsung,color-space = <0>;
- samsung,dynamic-range = <0>;
- samsung,ycbcr-coeff = <0>;
- samsung,color-depth = <1>;
- samsung,link-rate = <0x0a>;
- samsung,lane-count = <4>;
- status = "okay";
- };
-
- fimd@14400000 {
- status = "okay";
- display-timings {
- native-mode = <&timing0>;
- timing0: timing@0 {
- clock-frequency = <50000>;
- hactive = <2560>;
- vactive = <1600>;
- hfront-porch = <48>;
- hback-porch = <80>;
- hsync-len = <32>;
- vback-porch = <16>;
- vfront-porch = <8>;
- vsync-len = <6>;
- };
- };
- };
-
- pinctrl@13400000 {
- hdmi_hpd_irq: hdmi-hpd-irq {
- samsung,pins = "gpx3-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
- };
- };
-
- pinctrl@14000000 {
- usb300_vbus_en: usb300-vbus-en {
- samsung,pins = "gpg0-5";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-
- usb301_vbus_en: usb301-vbus-en {
- samsung,pins = "gpg1-4";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
- };
-
- hdmi@14530000 {
- status = "okay";
- hpd-gpio = <&gpx3 7 0>;
- pinctrl-names = "default";
- pinctrl-0 = <&hdmi_hpd_irq>;
- };
-
usb300_vbus_reg: regulator-usb300 {
compatible = "regulator-fixed";
regulator-name = "VBUS0";
@@ -185,238 +86,338 @@
enable-active-high;
};
- phy@12100000 {
- vbus-supply = <&usb300_vbus_reg>;
- };
+};
- phy@12500000 {
- vbus-supply = <&usb301_vbus_reg>;
+&dp {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dp_hpd>;
+ samsung,color-space = <0>;
+ samsung,dynamic-range = <0>;
+ samsung,ycbcr-coeff = <0>;
+ samsung,color-depth = <1>;
+ samsung,link-rate = <0x0a>;
+ samsung,lane-count = <4>;
+ status = "okay";
+};
+
+&fimd {
+ status = "okay";
+ display-timings {
+ native-mode = <&timing0>;
+ timing0: timing@0 {
+ clock-frequency = <50000>;
+ hactive = <2560>;
+ vactive = <1600>;
+ hfront-porch = <48>;
+ hback-porch = <80>;
+ hsync-len = <32>;
+ vback-porch = <16>;
+ vfront-porch = <8>;
+ vsync-len = <6>;
+ };
};
+};
- i2c_2: i2c@12C80000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <66000>;
- status = "okay";
+&hdmi {
+ status = "okay";
+ hpd-gpio = <&gpx3 7 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_hpd_irq>;
+};
- hdmiddc@50 {
- compatible = "samsung,exynos4210-hdmiddc";
- reg = <0x50>;
+&hsi2c_4 {
+ status = "okay";
+
+ s2mps11_pmic@66 {
+ compatible = "samsung,s2mps11-pmic";
+ reg = <0x66>;
+ s2mps11,buck2-ramp-delay = <12>;
+ s2mps11,buck34-ramp-delay = <12>;
+ s2mps11,buck16-ramp-delay = <12>;
+ s2mps11,buck6-ramp-enable = <1>;
+ s2mps11,buck2-ramp-enable = <1>;
+ s2mps11,buck3-ramp-enable = <1>;
+ s2mps11,buck4-ramp-enable = <1>;
+
+ s2mps11_osc: clocks {
+ #clock-cells = <1>;
+ clock-output-names = "s2mps11_ap",
+ "s2mps11_cp", "s2mps11_bt";
};
- };
- hsi2c_4: i2c@12CA0000 {
- status = "okay";
-
- s2mps11_pmic@66 {
- compatible = "samsung,s2mps11-pmic";
- reg = <0x66>;
- s2mps11,buck2-ramp-delay = <12>;
- s2mps11,buck34-ramp-delay = <12>;
- s2mps11,buck16-ramp-delay = <12>;
- s2mps11,buck6-ramp-enable = <1>;
- s2mps11,buck2-ramp-enable = <1>;
- s2mps11,buck3-ramp-enable = <1>;
- s2mps11,buck4-ramp-enable = <1>;
-
- s2mps11_osc: clocks {
- #clock-cells = <1>;
- clock-output-names = "s2mps11_ap",
- "s2mps11_cp", "s2mps11_bt";
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "vdd_ldo1";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "vdd_ldo3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "vdd_ldo5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "vdd_ldo6";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "vdd_ldo7";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "vdd_ldo8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo9_reg: LDO9 {
+ regulator-name = "vdd_ldo9";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "vdd_ldo10";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "vdd_ldo11";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "vdd_ldo12";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
};
- regulators {
- ldo1_reg: LDO1 {
- regulator-name = "vdd_ldo1";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo3_reg: LDO3 {
- regulator-name = "vdd_ldo3";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo5_reg: LDO5 {
- regulator-name = "vdd_ldo5";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo6_reg: LDO6 {
- regulator-name = "vdd_ldo6";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo7_reg: LDO7 {
- regulator-name = "vdd_ldo7";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo8_reg: LDO8 {
- regulator-name = "vdd_ldo8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo9_reg: LDO9 {
- regulator-name = "vdd_ldo9";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-always-on;
- };
-
- ldo10_reg: LDO10 {
- regulator-name = "vdd_ldo10";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo11_reg: LDO11 {
- regulator-name = "vdd_ldo11";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo12_reg: LDO12 {
- regulator-name = "vdd_ldo12";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo13_reg: LDO13 {
- regulator-name = "vdd_ldo13";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- };
-
- ldo15_reg: LDO15 {
- regulator-name = "vdd_ldo15";
- regulator-min-microvolt = <3100000>;
- regulator-max-microvolt = <3100000>;
- regulator-always-on;
- };
-
- ldo16_reg: LDO16 {
- regulator-name = "vdd_ldo16";
- regulator-min-microvolt = <2200000>;
- regulator-max-microvolt = <2200000>;
- regulator-always-on;
- };
-
- ldo17_reg: LDO17 {
- regulator-name = "tsp_avdd";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- };
-
- ldo19_reg: LDO19 {
- regulator-name = "vdd_sd";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- };
-
- ldo24_reg: LDO24 {
- regulator-name = "tsp_io";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- };
-
- buck1_reg: BUCK1 {
- regulator-name = "vdd_mif";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1300000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck2_reg: BUCK2 {
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck3_reg: BUCK3 {
- regulator-name = "vdd_int";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1400000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck4_reg: BUCK4 {
- regulator-name = "vdd_g3d";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1400000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck5_reg: BUCK5 {
- regulator-name = "vdd_mem";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1400000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck6_reg: BUCK6 {
- regulator-name = "vdd_kfc";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck7_reg: BUCK7 {
- regulator-name = "vdd_1.0v_ldo";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck8_reg: BUCK8 {
- regulator-name = "vdd_1.8v_ldo";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck9_reg: BUCK9 {
- regulator-name = "vdd_2.8v_ldo";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3750000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck10_reg: BUCK10 {
- regulator-name = "vdd_vmem";
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- regulator-always-on;
- regulator-boot-on;
- };
+ ldo13_reg: LDO13 {
+ regulator-name = "vdd_ldo13";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "vdd_ldo15";
+ regulator-min-microvolt = <3100000>;
+ regulator-max-microvolt = <3100000>;
+ regulator-always-on;
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "vdd_ldo16";
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ regulator-always-on;
+ };
+
+ ldo17_reg: LDO17 {
+ regulator-name = "tsp_avdd";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ ldo19_reg: LDO19 {
+ regulator-name = "vdd_sd";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ ldo24_reg: LDO24 {
+ regulator-name = "tsp_io";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "vdd_mem";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck6_reg: BUCK6 {
+ regulator-name = "vdd_kfc";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck7_reg: BUCK7 {
+ regulator-name = "vdd_1.0v_ldo";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck8_reg: BUCK8 {
+ regulator-name = "vdd_1.8v_ldo";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck9_reg: BUCK9 {
+ regulator-name = "vdd_2.8v_ldo";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3750000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck10_reg: BUCK10 {
+ regulator-name = "vdd_vmem";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ regulator-always-on;
+ regulator-boot-on;
};
};
};
};
+
+&i2c_2 {
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+ status = "okay";
+
+ hdmiddc@50 {
+ compatible = "samsung,exynos4210-hdmiddc";
+ reg = <0x50>;
+ };
+};
+
+&mfc {
+ samsung,mfc-r = <0x43000000 0x800000>;
+ samsung,mfc-l = <0x51000000 0x800000>;
+};
+
+&mmc_0 {
+ status = "okay";
+ broken-cd;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <0 4>;
+ samsung,dw-mshc-ddr-timing = <0 2>;
+ samsung,dw-mshc-hs400-timing = <0 2>;
+ samsung,read-strobe-delay = <90>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8
+ &sd0_rclk>;
+ bus-width = <8>;
+ cap-mmc-highspeed;
+};
+
+&mmc_2 {
+ status = "okay";
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>;
+ bus-width = <4>;
+ cap-sd-highspeed;
+};
+
+&pinctrl_0 {
+ hdmi_hpd_irq: hdmi-hpd-irq {
+ samsung,pins = "gpx3-7";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <1>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&pinctrl_2 {
+ usb300_vbus_en: usb300-vbus-en {
+ samsung,pins = "gpg0-5";
+ samsung,pin-function = <1>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ usb301_vbus_en: usb301-vbus-en {
+ samsung,pins = "gpg1-4";
+ samsung,pin-function = <1>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&rtc {
+ status = "okay";
+};
+
+&usbdrd_phy0 {
+ vbus-supply = <&usb300_vbus_reg>;
+};
+
+&usbdrd_phy1 {
+ vbus-supply = <&usb301_vbus_reg>;
+};
diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi
index 45317538bbae..534f27ceb10b 100644
--- a/arch/arm/boot/dts/exynos5420.dtsi
+++ b/arch/arm/boot/dts/exynos5420.dtsi
@@ -179,6 +179,8 @@
clocks = <&clock CLK_MFC>;
clock-names = "mfc";
power-domains = <&mfc_pd>;
+ iommus = <&sysmmu_mfc_l>, <&sysmmu_mfc_r>;
+ iommu-names = "left", "right";
};
mmc_0: mmc@12200000 {
@@ -264,9 +266,8 @@
mfc_pd: power-domain@10044060 {
compatible = "samsung,exynos4210-pd";
reg = <0x10044060 0x20>;
- clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK333>,
- <&clock CLK_MOUT_USER_ACLK333>;
- clock-names = "oscclk", "pclk0", "clk0";
+ clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_USER_ACLK333>;
+ clock-names = "oscclk", "clk0";
#power-domain-cells = <0>;
};
@@ -280,16 +281,12 @@
compatible = "samsung,exynos4210-pd";
reg = <0x100440C0 0x20>;
#power-domain-cells = <0>;
- clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK200>,
+ clocks = <&clock CLK_FIN_PLL>,
<&clock CLK_MOUT_USER_ACLK200_DISP1>,
- <&clock CLK_MOUT_SW_ACLK300>,
<&clock CLK_MOUT_USER_ACLK300_DISP1>,
- <&clock CLK_MOUT_SW_ACLK400>,
<&clock CLK_MOUT_USER_ACLK400_DISP1>,
<&clock CLK_FIMD1>, <&clock CLK_MIXER>;
- clock-names = "oscclk", "pclk0", "clk0",
- "pclk1", "clk1", "pclk2", "clk2",
- "asb0", "asb1";
+ clock-names = "oscclk", "clk0", "clk1", "clk2", "asb0", "asb1";
};
pinctrl_0: pinctrl@13400000 {
@@ -328,13 +325,6 @@
interrupts = <0 47 0>;
};
- rtc: rtc@101E0000 {
- clocks = <&clock CLK_RTC>;
- clock-names = "rtc";
- interrupt-parent = <&pmu_system_controller>;
- status = "disabled";
- };
-
amba {
#address-cells = <1>;
#size-cells = <1>;
@@ -416,6 +406,9 @@
<&clock_audss EXYNOS_I2S_BUS>,
<&clock_audss EXYNOS_SCLK_I2S>;
clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
+ #clock-cells = <1>;
+ clock-output-names = "i2s_cdclk0";
+ #sound-dai-cells = <1>;
samsung,idma-addr = <0x03000000>;
pinctrl-names = "default";
pinctrl-0 = <&i2s0_bus>;
@@ -430,6 +423,9 @@
dma-names = "tx", "rx";
clocks = <&clock CLK_I2S1>, <&clock CLK_SCLK_I2S1>;
clock-names = "iis", "i2s_opclk0";
+ #clock-cells = <1>;
+ clock-output-names = "i2s_cdclk1";
+ #sound-dai-cells = <1>;
pinctrl-names = "default";
pinctrl-0 = <&i2s1_bus>;
status = "disabled";
@@ -443,6 +439,9 @@
dma-names = "tx", "rx";
clocks = <&clock CLK_I2S2>, <&clock CLK_SCLK_I2S2>;
clock-names = "iis", "i2s_opclk0";
+ #clock-cells = <1>;
+ clock-output-names = "i2s_cdclk2";
+ #sound-dai-cells = <1>;
pinctrl-names = "default";
pinctrl-0 = <&i2s2_bus>;
status = "disabled";
@@ -496,26 +495,6 @@
status = "disabled";
};
- uart_0: serial@12C00000 {
- clocks = <&clock CLK_UART0>, <&clock CLK_SCLK_UART0>;
- clock-names = "uart", "clk_uart_baud0";
- };
-
- uart_1: serial@12C10000 {
- clocks = <&clock CLK_UART1>, <&clock CLK_SCLK_UART1>;
- clock-names = "uart", "clk_uart_baud0";
- };
-
- uart_2: serial@12C20000 {
- clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>;
- clock-names = "uart", "clk_uart_baud0";
- };
-
- uart_3: serial@12C30000 {
- clocks = <&clock CLK_UART3>, <&clock CLK_SCLK_UART3>;
- clock-names = "uart", "clk_uart_baud0";
- };
-
pwm: pwm@12dd0000 {
compatible = "samsung,exynos4210-pwm";
reg = <0x12dd0000 0x100>;
@@ -531,17 +510,9 @@
#phy-cells = <0>;
};
- dp: dp-controller@145B0000 {
- clocks = <&clock CLK_DP1>;
- clock-names = "dp";
- phys = <&dp_phy>;
- phy-names = "dp";
- power-domains = <&disp_pd>;
- };
-
mipi_phy: video-phy@10040714 {
compatible = "samsung,s5pv210-mipi-video-phy";
- reg = <0x10040714 12>;
+ syscon = <&pmu_system_controller>;
#phy-cells = <1>;
};
@@ -558,12 +529,6 @@
status = "disabled";
};
- fimd: fimd@14400000 {
- clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>;
- clock-names = "sclk_fimd", "fimd";
- power-domains = <&disp_pd>;
- };
-
adc: adc@12D10000 {
compatible = "samsung,exynos-adc-v2";
reg = <0x12D10000 0x100>;
@@ -750,6 +715,7 @@
<&clock CLK_SCLK_HDMI>;
clock-names = "mixer", "hdmi", "sclk_hdmi";
power-domains = <&disp_pd>;
+ iommus = <&sysmmu_tv>;
};
gsc_0: video-scaler@13e00000 {
@@ -759,6 +725,7 @@
clocks = <&clock CLK_GSCL0>;
clock-names = "gscl";
power-domains = <&gsc_pd>;
+ iommus = <&sysmmu_gscl0>;
};
gsc_1: video-scaler@13e10000 {
@@ -768,6 +735,25 @@
clocks = <&clock CLK_GSCL1>;
clock-names = "gscl";
power-domains = <&gsc_pd>;
+ iommus = <&sysmmu_gscl1>;
+ };
+
+ jpeg_0: jpeg@11F50000 {
+ compatible = "samsung,exynos5420-jpeg";
+ reg = <0x11F50000 0x1000>;
+ interrupts = <0 89 0>;
+ clock-names = "jpeg";
+ clocks = <&clock CLK_JPEG>;
+ iommus = <&sysmmu_jpeg0>;
+ };
+
+ jpeg_1: jpeg@11F60000 {
+ compatible = "samsung,exynos5420-jpeg";
+ reg = <0x11F60000 0x1000>;
+ interrupts = <0 168 0>;
+ clock-names = "jpeg";
+ clocks = <&clock CLK_JPEG2>;
+ iommus = <&sysmmu_jpeg1>;
};
pmu_system_controller: system-controller@10040000 {
@@ -962,4 +948,221 @@
samsung,sysreg-phandle = <&sysreg_system_controller>;
samsung,pmureg-phandle = <&pmu_system_controller>;
};
+
+ sysmmu_g2dr: sysmmu@0x10A60000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x10A60000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <24 5>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_G2D>, <&clock CLK_G2D>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_g2dw: sysmmu@0x10A70000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x10A70000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <22 2>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_G2D>, <&clock CLK_G2D>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_tv: sysmmu@0x14650000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x14650000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <7 4>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MIXER>, <&clock CLK_MIXER>;
+ power-domains = <&disp_pd>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_gscl0: sysmmu@0x13E80000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13E80000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <2 0>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_GSCL0>, <&clock CLK_GSCL0>;
+ power-domains = <&gsc_pd>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_gscl1: sysmmu@0x13E90000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x13E90000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <2 2>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_GSCL1>, <&clock CLK_GSCL1>;
+ power-domains = <&gsc_pd>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_scaler0r: sysmmu@0x12880000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x12880000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <22 4>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MSCL0>, <&clock CLK_MSCL0>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_scaler1r: sysmmu@0x12890000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x12890000 0x1000>;
+ interrupts = <0 186 0>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MSCL1>, <&clock CLK_MSCL1>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_scaler2r: sysmmu@0x128A0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x128A0000 0x1000>;
+ interrupts = <0 188 0>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MSCL2>, <&clock CLK_MSCL2>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_scaler0w: sysmmu@0x128C0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x128C0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <27 2>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MSCL0>, <&clock CLK_MSCL0>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_scaler1w: sysmmu@0x128D0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x128D0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <22 6>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MSCL1>, <&clock CLK_MSCL1>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_scaler2w: sysmmu@0x128E0000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x128E0000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <19 6>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MSCL2>, <&clock CLK_MSCL2>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_jpeg0: sysmmu@0x11F10000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11F10000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <4 2>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_JPEG>, <&clock CLK_JPEG>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_jpeg1: sysmmu@0x11F20000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11F20000 0x1000>;
+ interrupts = <0 169 0>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_JPEG2>, <&clock CLK_JPEG2>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_mfc_l: sysmmu@0x11200000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11200000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <6 2>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MFCL>, <&clock CLK_MFC>;
+ power-domains = <&mfc_pd>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_mfc_r: sysmmu@0x11210000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x11210000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <8 5>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_MFCR>, <&clock CLK_MFC>;
+ power-domains = <&mfc_pd>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimd1_0: sysmmu@0x14640000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x14640000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <3 2>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_FIMD1M0>, <&clock CLK_FIMD1>;
+ power-domains = <&disp_pd>;
+ #iommu-cells = <0>;
+ };
+
+ sysmmu_fimd1_1: sysmmu@0x14680000 {
+ compatible = "samsung,exynos-sysmmu";
+ reg = <0x14680000 0x1000>;
+ interrupt-parent = <&combiner>;
+ interrupts = <3 0>;
+ clock-names = "sysmmu", "master";
+ clocks = <&clock CLK_SMMU_FIMD1M0>, <&clock CLK_FIMD1>;
+ power-domains = <&disp_pd>;
+ #iommu-cells = <0>;
+ };
+};
+
+&dp {
+ clocks = <&clock CLK_DP1>;
+ clock-names = "dp";
+ phys = <&dp_phy>;
+ phy-names = "dp";
+ power-domains = <&disp_pd>;
+};
+
+&fimd {
+ clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>;
+ clock-names = "sclk_fimd", "fimd";
+ power-domains = <&disp_pd>;
+ iommus = <&sysmmu_fimd1_0>, <&sysmmu_fimd1_1>;
+ iommu-names = "m0", "m1";
+};
+
+&rtc {
+ clocks = <&clock CLK_RTC>;
+ clock-names = "rtc";
+ interrupt-parent = <&pmu_system_controller>;
+ status = "disabled";
+};
+
+&serial_0 {
+ clocks = <&clock CLK_UART0>, <&clock CLK_SCLK_UART0>;
+ clock-names = "uart", "clk_uart_baud0";
+};
+
+&serial_1 {
+ clocks = <&clock CLK_UART1>, <&clock CLK_SCLK_UART1>;
+ clock-names = "uart", "clk_uart_baud0";
+};
+
+&serial_2 {
+ clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>;
+ clock-names = "uart", "clk_uart_baud0";
+};
+
+&serial_3 {
+ clocks = <&clock CLK_UART3>, <&clock CLK_SCLK_UART3>;
+ clock-names = "uart", "clk_uart_baud0";
};
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
new file mode 100644
index 000000000000..8adf455744e9
--- /dev/null
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
@@ -0,0 +1,479 @@
+/*
+ * Hardkernel Odroid XU3 board device tree source
+ *
+ * Copyright (c) 2014 Collabora Ltd.
+ * Copyright (c) 2013 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 version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <dt-bindings/clock/samsung,s2mps11.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/sound/samsung-i2s.h>
+#include "exynos5800.dtsi"
+
+/ {
+ memory {
+ reg = <0x40000000 0x7EA00000>;
+ };
+
+ chosen {
+ linux,stdout-path = &serial_2;
+ };
+
+ firmware@02073000 {
+ compatible = "samsung,secure-firmware";
+ reg = <0x02073000 0x1000>;
+ };
+
+ fixed-rate-clocks {
+ oscclk {
+ compatible = "samsung,exynos5420-oscclk";
+ clock-frequency = <24000000>;
+ };
+ };
+
+ emmc_pwrseq: pwrseq {
+ pinctrl-0 = <&emmc_nrst_pin>;
+ pinctrl-names = "default";
+ compatible = "mmc-pwrseq-emmc";
+ reset-gpios = <&gpd1 0 1>;
+ };
+
+ pwmleds {
+ compatible = "pwm-leds";
+
+ greenled {
+ label = "green:mmc0";
+ pwms = <&pwm 1 2000000 0>;
+ pwm-names = "pwm1";
+ /*
+ * Green LED is much brighter than the others
+ * so limit its max brightness
+ */
+ max_brightness = <127>;
+ linux,default-trigger = "mmc0";
+ };
+
+ blueled {
+ label = "blue:heartbeat";
+ pwms = <&pwm 2 2000000 0>;
+ pwm-names = "pwm2";
+ max_brightness = <255>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ gpioleds {
+ compatible = "gpio-leds";
+ redled {
+ label = "red:microSD";
+ gpios = <&gpx2 3 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ linux,default-trigger = "mmc1";
+ };
+ };
+
+ sound: sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,name = "Odroid-XU3";
+ simple-audio-card,widgets =
+ "Headphone", "Headphone Jack",
+ "Speakers", "Speakers";
+ simple-audio-card,routing =
+ "Headphone Jack", "HPL",
+ "Headphone Jack", "HPR",
+ "Headphone Jack", "MICBIAS",
+ "IN1", "Headphone Jack",
+ "Speakers", "SPKL",
+ "Speakers", "SPKR";
+
+ simple-audio-card,format = "i2s";
+ simple-audio-card,bitclock-master = <&link0_codec>;
+ simple-audio-card,frame-master = <&link0_codec>;
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s0 0>;
+ system-clock-frequency = <19200000>;
+ };
+
+ link0_codec: simple-audio-card,codec {
+ sound-dai = <&max98090>;
+ clocks = <&i2s0 CLK_I2S_CDCLK>;
+ };
+ };
+};
+
+&clock_audss {
+ assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>,
+ <&clock_audss EXYNOS_MOUT_I2S>,
+ <&clock_audss EXYNOS_DOUT_AUD_BUS>;
+ assigned-clock-parents = <&clock CLK_FIN_PLL>,
+ <&clock_audss EXYNOS_MOUT_AUDSS>;
+ assigned-clock-rates = <0>,
+ <0>,
+ <19200000>;
+};
+
+&fimd {
+ status = "okay";
+};
+
+
+&hdmi {
+ status = "okay";
+ hpd-gpio = <&gpx3 7 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_hpd_irq>;
+
+ vdd_osc-supply = <&ldo7_reg>;
+ vdd_pll-supply = <&ldo6_reg>;
+ vdd-supply = <&ldo6_reg>;
+};
+
+&hsi2c_4 {
+ status = "okay";
+
+ s2mps11_pmic@66 {
+ compatible = "samsung,s2mps11-pmic";
+ reg = <0x66>;
+ s2mps11,buck2-ramp-delay = <12>;
+ s2mps11,buck34-ramp-delay = <12>;
+ s2mps11,buck16-ramp-delay = <12>;
+ s2mps11,buck6-ramp-enable = <1>;
+ s2mps11,buck2-ramp-enable = <1>;
+ s2mps11,buck3-ramp-enable = <1>;
+ s2mps11,buck4-ramp-enable = <1>;
+
+ interrupt-parent = <&gpx0>;
+ interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&s2mps11_irq>;
+
+ s2mps11_osc: clocks {
+ #clock-cells = <1>;
+ clock-output-names = "s2mps11_ap",
+ "s2mps11_cp", "s2mps11_bt";
+ };
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "vdd_ldo1";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "vdd_ldo3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "vdd_ldo5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "vdd_ldo6";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "vdd_ldo7";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "vdd_ldo8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo9_reg: LDO9 {
+ regulator-name = "vdd_ldo9";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "vdd_ldo10";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "vdd_ldo11";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "vdd_ldo12";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo13_reg: LDO13 {
+ regulator-name = "vdd_ldo13";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "vdd_ldo15";
+ regulator-min-microvolt = <3100000>;
+ regulator-max-microvolt = <3100000>;
+ regulator-always-on;
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "vdd_ldo16";
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ regulator-always-on;
+ };
+
+ ldo17_reg: LDO17 {
+ regulator-name = "tsp_avdd";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ ldo19_reg: LDO19 {
+ regulator-name = "vdd_sd";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ ldo24_reg: LDO24 {
+ regulator-name = "tsp_io";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ ldo26_reg: LDO26 {
+ regulator-name = "vdd_ldo26";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "vdd_mem";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck6_reg: BUCK6 {
+ regulator-name = "vdd_kfc";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck7_reg: BUCK7 {
+ regulator-name = "vdd_1.0v_ldo";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck8_reg: BUCK8 {
+ regulator-name = "vdd_1.8v_ldo";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck9_reg: BUCK9 {
+ regulator-name = "vdd_2.8v_ldo";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3750000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck10_reg: BUCK10 {
+ regulator-name = "vdd_vmem";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ };
+ };
+};
+
+&hsi2c_5 {
+ status = "okay";
+ max98090: max98090@10 {
+ compatible = "maxim,max98090";
+ reg = <0x10>;
+ interrupt-parent = <&gpx3>;
+ interrupts = <2 0>;
+ clocks = <&i2s0 CLK_I2S_CDCLK>;
+ clock-names = "mclk";
+ #sound-dai-cells = <0>;
+ };
+};
+
+&i2c_2 {
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+ status = "okay";
+
+ hdmiddc@50 {
+ compatible = "samsung,exynos4210-hdmiddc";
+ reg = <0x50>;
+ };
+};
+
+&i2s0 {
+ status = "okay";
+};
+
+&mfc {
+ samsung,mfc-r = <0x43000000 0x800000>;
+ samsung,mfc-l = <0x51000000 0x800000>;
+};
+
+&mmc_0 {
+ status = "okay";
+ mmc-pwrseq = <&emmc_pwrseq>;
+ cd-gpios = <&gpc0 2 GPIO_ACTIVE_LOW>;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <0 4>;
+ samsung,dw-mshc-ddr-timing = <0 2>;
+ samsung,dw-mshc-hs400-timing = <0 2>;
+ samsung,read-strobe-delay = <90>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8 &sd0_cd &sd0_rclk>;
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ mmc-hs200-1_8v;
+ mmc-hs400-1_8v;
+};
+
+&mmc_2 {
+ status = "okay";
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <0 4>;
+ samsung,dw-mshc-ddr-timing = <0 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>;
+ bus-width = <4>;
+ cap-sd-highspeed;
+};
+
+&pinctrl_0 {
+ hdmi_hpd_irq: hdmi-hpd-irq {
+ samsung,pins = "gpx3-7";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <1>;
+ samsung,pin-drv = <0>;
+ };
+
+ s2mps11_irq: s2mps11-irq {
+ samsung,pins = "gpx0-4";
+ samsung,pin-function = <0xf>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&pinctrl_1 {
+ emmc_nrst_pin: emmc-nrst {
+ samsung,pins = "gpd1-0";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&pwm {
+ /*
+ * PWM 0 -- fan
+ * PWM 1 -- Green LED
+ * PWM 2 -- Blue LED
+ * PWM 3 -- on MIPI connector for backlight
+ */
+ pinctrl-0 = <&pwm0_out &pwm1_out &pwm2_out &pwm3_out>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
+&rtc {
+ status = "okay";
+ clocks = <&clock CLK_RTC>, <&s2mps11_osc S2MPS11_CLK_AP>;
+ clock-names = "rtc", "rtc_src";
+};
+
+&usbdrd_dwc3_0 {
+ dr_mode = "host";
+};
+
+&usbdrd_dwc3_1 {
+ dr_mode = "otg";
+};
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts b/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts
new file mode 100644
index 000000000000..c06882bbb822
--- /dev/null
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts
@@ -0,0 +1,20 @@
+/*
+ * Hardkernel Odroid XU3-Lite board device tree source
+ *
+ * Copyright (c) 2015 Krzysztof Kozlowski
+ * Copyright (c) 2014 Collabora Ltd.
+ * Copyright (c) 2013 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 version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/dts-v1/;
+#include "exynos5422-odroidxu3-common.dtsi"
+
+/ {
+ model = "Hardkernel Odroid XU3 Lite";
+ compatible = "hardkernel,odroid-xu3-lite", "samsung,exynos5800", "samsung,exynos5";
+};
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3.dts b/arch/arm/boot/dts/exynos5422-odroidxu3.dts
index edc25cf1d717..78e6a502f320 100644
--- a/arch/arm/boot/dts/exynos5422-odroidxu3.dts
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3.dts
@@ -11,348 +11,11 @@
*/
/dts-v1/;
-#include "exynos5800.dtsi"
+#include "exynos5422-odroidxu3-common.dtsi"
/ {
model = "Hardkernel Odroid XU3";
compatible = "hardkernel,odroid-xu3", "samsung,exynos5800", "samsung,exynos5";
-
- memory {
- reg = <0x40000000 0x7EA00000>;
- };
-
- chosen {
- linux,stdout-path = &serial_2;
- };
-
- fimd@14400000 {
- status = "okay";
- };
-
- firmware@02073000 {
- compatible = "samsung,secure-firmware";
- reg = <0x02073000 0x1000>;
- };
-
- fixed-rate-clocks {
- oscclk {
- compatible = "samsung,exynos5420-oscclk";
- clock-frequency = <24000000>;
- };
- };
-
- hsi2c_4: i2c@12CA0000 {
- status = "okay";
-
- s2mps11_pmic@66 {
- compatible = "samsung,s2mps11-pmic";
- reg = <0x66>;
- s2mps11,buck2-ramp-delay = <12>;
- s2mps11,buck34-ramp-delay = <12>;
- s2mps11,buck16-ramp-delay = <12>;
- s2mps11,buck6-ramp-enable = <1>;
- s2mps11,buck2-ramp-enable = <1>;
- s2mps11,buck3-ramp-enable = <1>;
- s2mps11,buck4-ramp-enable = <1>;
-
- s2mps11_osc: clocks {
- #clock-cells = <1>;
- clock-output-names = "s2mps11_ap",
- "s2mps11_cp", "s2mps11_bt";
- };
-
- regulators {
- ldo1_reg: LDO1 {
- regulator-name = "vdd_ldo1";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo3_reg: LDO3 {
- regulator-name = "vdd_ldo3";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo5_reg: LDO5 {
- regulator-name = "vdd_ldo5";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo6_reg: LDO6 {
- regulator-name = "vdd_ldo6";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo7_reg: LDO7 {
- regulator-name = "vdd_ldo7";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo8_reg: LDO8 {
- regulator-name = "vdd_ldo8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo9_reg: LDO9 {
- regulator-name = "vdd_ldo9";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-always-on;
- };
-
- ldo10_reg: LDO10 {
- regulator-name = "vdd_ldo10";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo11_reg: LDO11 {
- regulator-name = "vdd_ldo11";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo12_reg: LDO12 {
- regulator-name = "vdd_ldo12";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo13_reg: LDO13 {
- regulator-name = "vdd_ldo13";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- };
-
- ldo15_reg: LDO15 {
- regulator-name = "vdd_ldo15";
- regulator-min-microvolt = <3100000>;
- regulator-max-microvolt = <3100000>;
- regulator-always-on;
- };
-
- ldo16_reg: LDO16 {
- regulator-name = "vdd_ldo16";
- regulator-min-microvolt = <2200000>;
- regulator-max-microvolt = <2200000>;
- regulator-always-on;
- };
-
- ldo17_reg: LDO17 {
- regulator-name = "tsp_avdd";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- };
-
- ldo19_reg: LDO19 {
- regulator-name = "vdd_sd";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- };
-
- ldo24_reg: LDO24 {
- regulator-name = "tsp_io";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- };
-
- ldo26_reg: LDO26 {
- regulator-name = "vdd_ldo26";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-always-on;
- };
-
- buck1_reg: BUCK1 {
- regulator-name = "vdd_mif";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1300000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck2_reg: BUCK2 {
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck3_reg: BUCK3 {
- regulator-name = "vdd_int";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1400000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck4_reg: BUCK4 {
- regulator-name = "vdd_g3d";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1400000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck5_reg: BUCK5 {
- regulator-name = "vdd_mem";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1400000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck6_reg: BUCK6 {
- regulator-name = "vdd_kfc";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck7_reg: BUCK7 {
- regulator-name = "vdd_1.0v_ldo";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck8_reg: BUCK8 {
- regulator-name = "vdd_1.8v_ldo";
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck9_reg: BUCK9 {
- regulator-name = "vdd_2.8v_ldo";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3750000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck10_reg: BUCK10 {
- regulator-name = "vdd_vmem";
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- regulator-always-on;
- regulator-boot-on;
- };
- };
- };
- };
-
- emmc_pwrseq: pwrseq {
- pinctrl-0 = <&emmc_nrst_pin>;
- pinctrl-names = "default";
- compatible = "mmc-pwrseq-emmc";
- reset-gpios = <&gpd1 0 1>;
- };
-
- i2c_2: i2c@12C80000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <66000>;
- status = "okay";
-
- hdmiddc@50 {
- compatible = "samsung,exynos4210-hdmiddc";
- reg = <0x50>;
- };
- };
-
- rtc@101E0000 {
- status = "okay";
- };
-};
-
-&hdmi {
- status = "okay";
- hpd-gpio = <&gpx3 7 0>;
- pinctrl-names = "default";
- pinctrl-0 = <&hdmi_hpd_irq>;
-
- vdd_osc-supply = <&ldo7_reg>;
- vdd_pll-supply = <&ldo6_reg>;
- vdd-supply = <&ldo6_reg>;
-};
-
-&mfc {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
-};
-
-&mmc_0 {
- status = "okay";
- mmc-pwrseq = <&emmc_pwrseq>;
- broken-cd;
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
- bus-width = <8>;
- cap-mmc-highspeed;
-};
-
-&mmc_2 {
- status = "okay";
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>;
- bus-width = <4>;
- cap-sd-highspeed;
-};
-
-&pinctrl_0 {
- hdmi_hpd_irq: hdmi-hpd-irq {
- samsung,pins = "gpx3-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
- };
-};
-
-&pinctrl_1 {
- emmc_nrst_pin: emmc-nrst {
- samsung,pins = "gpd1-0";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-};
-
-&usbdrd_dwc3_0 {
- dr_mode = "host";
-};
-
-&usbdrd_dwc3_1 {
- dr_mode = "otg";
};
&i2c_0 {
diff --git a/arch/arm/boot/dts/exynos5440-sd5v1.dts b/arch/arm/boot/dts/exynos5440-sd5v1.dts
index 268609a42b2c..a98501bab6fc 100644
--- a/arch/arm/boot/dts/exynos5440-sd5v1.dts
+++ b/arch/arm/boot/dts/exynos5440-sd5v1.dts
@@ -27,13 +27,13 @@
};
};
- gmac: ethernet@00230000 {
- fixed_phy;
- phy_addr = <1>;
- };
-
spi {
status = "disabled";
};
};
+
+&gmac {
+ fixed_phy;
+ phy_addr = <1>;
+};
diff --git a/arch/arm/boot/dts/exynos5440-ssdk5440.dts b/arch/arm/boot/dts/exynos5440-ssdk5440.dts
index ff55dac6e219..e4443f4e6572 100644
--- a/arch/arm/boot/dts/exynos5440-ssdk5440.dts
+++ b/arch/arm/boot/dts/exynos5440-ssdk5440.dts
@@ -20,59 +20,58 @@
bootargs = "root=/dev/sda2 rw rootwait ignore_loglevel earlyprintk no_console_suspend mem=2048M@0x80000000 mem=6144M@0x100000000 console=ttySAC0,115200";
};
- spi_0: spi@D0000 {
-
- flash: w25q128@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "winbond,w25q128";
- spi-max-frequency = <15625000>;
- reg = <0>;
- controller-data {
- samsung,spi-feedback-delay = <0>;
- };
+ fixed-rate-clocks {
+ xtal {
+ compatible = "samsung,clock-xtal";
+ clock-frequency = <50000000>;
+ };
+ };
+};
- partition@00000 {
- label = "BootLoader";
- reg = <0x60000 0x80000>;
- read-only;
- };
+&pcie_0 {
+ reset-gpio = <&pin_ctrl 5 0>;
+ status = "okay";
+};
- partition@e0000 {
- label = "Recovery-Kernel";
- reg = <0xe0000 0x300000>;
- read-only;
- };
+&pcie_1 {
+ reset-gpio = <&pin_ctrl 22 0>;
+ status = "okay";
+};
- partition@3e0000 {
- label = "CRAM-FS";
- reg = <0x3e0000 0x700000>;
- read-only;
- };
+&spi_0 {
+ flash: w25q128@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "winbond,w25q128";
+ spi-max-frequency = <15625000>;
+ reg = <0>;
+ controller-data {
+ samsung,spi-feedback-delay = <0>;
+ };
- partition@ae0000 {
- label = "User-Data";
- reg = <0xae0000 0x520000>;
- };
+ partition@00000 {
+ label = "BootLoader";
+ reg = <0x60000 0x80000>;
+ read-only;
+ };
+ partition@e0000 {
+ label = "Recovery-Kernel";
+ reg = <0xe0000 0x300000>;
+ read-only;
};
- };
+ partition@3e0000 {
+ label = "CRAM-FS";
+ reg = <0x3e0000 0x700000>;
+ read-only;
+ };
- fixed-rate-clocks {
- xtal {
- compatible = "samsung,clock-xtal";
- clock-frequency = <50000000>;
+ partition@ae0000 {
+ label = "User-Data";
+ reg = <0xae0000 0x520000>;
};
- };
- pcie@290000 {
- reset-gpio = <&pin_ctrl 5 0>;
- status = "okay";
};
- pcie@2a0000 {
- reset-gpio = <&pin_ctrl 22 0>;
- status = "okay";
- };
};
diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi
index 59d9416b3b03..f18b51f2eeaa 100644
--- a/arch/arm/boot/dts/exynos5440.dtsi
+++ b/arch/arm/boot/dts/exynos5440.dtsi
@@ -279,7 +279,7 @@
clock-names = "usbhost";
};
- pcie@290000 {
+ pcie_0: pcie@290000 {
compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
reg = <0x290000 0x1000
0x270000 0x1000
@@ -300,7 +300,7 @@
status = "disabled";
};
- pcie@2a0000 {
+ pcie_1: pcie@2a0000 {
compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
reg = <0x2a0000 0x1000
0x272000 0x1000
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index 02eb8b15374f..7d5b386b5ae6 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -990,7 +990,7 @@
};
};
-&uart_3 {
+&serial_3 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx23-olinuxino.dts b/arch/arm/boot/dts/imx23-olinuxino.dts
index 82045398bf1f..a8b1c53ebe46 100644
--- a/arch/arm/boot/dts/imx23-olinuxino.dts
+++ b/arch/arm/boot/dts/imx23-olinuxino.dts
@@ -74,6 +74,12 @@
status = "okay";
};
+ i2c: i2c@80058000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c_pins_b>;
+ status = "okay";
+ };
+
duart: serial@80070000 {
pinctrl-names = "default";
pinctrl-0 = <&duart_pins_a>;
diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi
index bbcfb5a19c77..c892d58e8dad 100644
--- a/arch/arm/boot/dts/imx23.dtsi
+++ b/arch/arm/boot/dts/imx23.dtsi
@@ -308,6 +308,39 @@
fsl,voltage = <MXS_VOLTAGE_HIGH>;
fsl,pull-up = <MXS_PULL_ENABLE>;
};
+
+ i2c_pins_a: i2c@0 {
+ reg = <0>;
+ fsl,pinmux-ids = <
+ MX23_PAD_I2C_SCL__I2C_SCL
+ MX23_PAD_I2C_SDA__I2C_SDA
+ >;
+ fsl,drive-strength = <MXS_DRIVE_8mA>;
+ fsl,voltage = <MXS_VOLTAGE_HIGH>;
+ fsl,pull-up = <MXS_PULL_ENABLE>;
+ };
+
+ i2c_pins_b: i2c@1 {
+ reg = <1>;
+ fsl,pinmux-ids = <
+ MX23_PAD_LCD_ENABLE__I2C_SCL
+ MX23_PAD_LCD_HSYNC__I2C_SDA
+ >;
+ fsl,drive-strength = <MXS_DRIVE_8mA>;
+ fsl,voltage = <MXS_VOLTAGE_HIGH>;
+ fsl,pull-up = <MXS_PULL_ENABLE>;
+ };
+
+ i2c_pins_c: i2c@2 {
+ reg = <2>;
+ fsl,pinmux-ids = <
+ MX23_PAD_SSP1_DATA1__I2C_SCL
+ MX23_PAD_SSP1_DATA2__I2C_SDA
+ >;
+ fsl,drive-strength = <MXS_DRIVE_8mA>;
+ fsl,voltage = <MXS_VOLTAGE_HIGH>;
+ fsl,pull-up = <MXS_PULL_ENABLE>;
+ };
};
digctl@8001c000 {
@@ -444,8 +477,13 @@
status = "disabled";
};
- i2c@80058000 {
+ i2c: i2c@80058000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx23-i2c";
reg = <0x80058000 0x2000>;
+ interrupts = <27>;
+ clock-frequency = <100000>;
dmas = <&dma_apbx 3>;
dma-names = "rx-tx";
status = "disabled";
diff --git a/arch/arm/boot/dts/imx28-cfa10036.dts b/arch/arm/boot/dts/imx28-cfa10036.dts
index b04b6b8850a7..570aa339a05e 100644
--- a/arch/arm/boot/dts/imx28-cfa10036.dts
+++ b/arch/arm/boot/dts/imx28-cfa10036.dts
@@ -99,6 +99,9 @@
solomon,height = <32>;
solomon,width = <128>;
solomon,page-offset = <0>;
+ solomon,com-lrremap;
+ solomon,com-invdir;
+ solomon,com-offset = <32>;
};
};
diff --git a/arch/arm/boot/dts/imx6dl-apf6dev.dts b/arch/arm/boot/dts/imx6dl-apf6dev.dts
new file mode 100644
index 000000000000..df26e542ab3a
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-apf6dev.dts
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015 Armadeus Systems
+ *
+ * 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 "imx6dl.dtsi"
+#include "imx6qdl-apf6.dtsi"
+#include "imx6qdl-apf6dev.dtsi"
+
+/ {
+ model = "Armadeus APF6 Solo Module on APF6Dev Board";
+ compatible = "armadeus,imx6dl-apf6dev", "armadeus,imx6dl-apf6", "fsl,imx6dl";
+
+ memory {
+ reg = <0x10000000 0x20000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6dl-aristainetos2_4.dts b/arch/arm/boot/dts/imx6dl-aristainetos2_4.dts
new file mode 100644
index 000000000000..bb92f309c191
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-aristainetos2_4.dts
@@ -0,0 +1,159 @@
+/*
+ * support for the imx6 based aristainetos2 board
+ *
+ * Copyright (C) 2015 Heiko Schocher <hs@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
+ * 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 "imx6dl.dtsi"
+#include "imx6qdl-aristainetos2.dtsi"
+
+/ {
+ model = "aristainetos2 i.MX6 Dual Lite Board 4";
+ compatible = "fsl,imx6dl";
+
+ memory {
+ reg = <0x10000000 0x40000000>;
+ };
+
+ display0: display@di0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx-parallel-display";
+ interface-pix-fmt = "rgb24";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ipu_disp>;
+
+ port@0 {
+ reg = <0>;
+ display0_in: endpoint {
+ remote-endpoint = <&ipu1_di0_disp0>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ display_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
+};
+
+&ecspi1 {
+ lcd_panel: display@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "lg,lg4573";
+ spi-max-frequency = <10000000>;
+ reg = <0>;
+ power-on-delay = <10>;
+
+ display-timings {
+ 480x800p57 {
+ native-mode;
+ clock-frequency = <27000027>;
+ hactive = <480>;
+ vactive = <800>;
+ hfront-porch = <10>;
+ hback-porch = <59>;
+ hsync-len = <10>;
+ vback-porch = <15>;
+ vfront-porch = <15>;
+ vsync-len = <15>;
+ hsync-active = <1>;
+ vsync-active = <1>;
+ };
+ };
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&display_out>;
+ };
+ };
+ };
+};
+
+&i2c3 {
+ touch: touch@4b {
+ compatible = "atmel,maxtouch";
+ reg = <0x4b>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <9 8>;
+ };
+};
+
+&ipu1_di0_disp0 {
+ remote-endpoint = <&display0_in>;
+};
+
+&iomuxc {
+ pinctrl_ipu_disp: ipudisp1grp {
+ fsl,pins = <
+ MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x31
+ MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0xE1
+ MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10
+ MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10
+ MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0xE1
+ MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0xE1
+ MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0xE1
+ MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0xE1
+ MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0xE1
+ MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0xE1
+ MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0xE1
+ MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0xE1
+ MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0xE1
+ MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0xE1
+ MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0xE1
+ MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0xE1
+ MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0xE1
+ MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0xE1
+ MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0xe1
+ MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0xE1
+ MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0xE1
+ MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0xE1
+ MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0xE1
+ MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0xE1
+ MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0xE1
+ MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0xE1
+ MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0xE1
+ MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0xE1
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6dl-aristainetos2_7.dts b/arch/arm/boot/dts/imx6dl-aristainetos2_7.dts
new file mode 100644
index 000000000000..3d5ad2cc7e22
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-aristainetos2_7.dts
@@ -0,0 +1,97 @@
+/*
+ * support for the imx6 based aristainetos2 board
+ *
+ * Copyright (C) 2015 Heiko Schocher <hs@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
+ * 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 "imx6dl.dtsi"
+#include "imx6qdl-aristainetos2.dtsi"
+
+/ {
+ model = "aristainetos2 i.MX6 Dual Lite Board 7";
+ compatible = "fsl,imx6dl";
+
+ memory {
+ reg = <0x10000000 0x40000000>;
+ };
+
+ panel: panel {
+ compatible = "lg,lb070wv8";
+ backlight = <&backlight>;
+ enable-gpios = <&gpio6 15 GPIO_ACTIVE_HIGH>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&lvds0_out>;
+ };
+ };
+ };
+};
+
+&i2c3 {
+ touch: touch@4d {
+ compatible = "atmel,maxtouch";
+ reg = <0x4d>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <9 8>;
+ };
+};
+
+&ldb {
+ status = "okay";
+
+ lvds-channel@0 {
+ status = "okay";
+
+ port@0 {
+ reg = <0>;
+ lvds0_in: endpoint {
+ remote-endpoint = <&ipu1_di0_lvds0>;
+ };
+ };
+
+ port@4 {
+ reg = <4>;
+ lvds0_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/imx6dl-cubox-i.dts b/arch/arm/boot/dts/imx6dl-cubox-i.dts
index e0b7fe8e18f8..2a43917d048e 100644
--- a/arch/arm/boot/dts/imx6dl-cubox-i.dts
+++ b/arch/arm/boot/dts/imx6dl-cubox-i.dts
@@ -7,9 +7,8 @@
* 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.
+ * 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
diff --git a/arch/arm/boot/dts/imx6dl-gw551x.dts b/arch/arm/boot/dts/imx6dl-gw551x.dts
new file mode 100644
index 000000000000..82d5f85722ea
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-gw551x.dts
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014 Gateworks Corporation
+ *
+ * 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 "imx6dl.dtsi"
+#include "imx6qdl-gw551x.dtsi"
+
+/ {
+ model = "Gateworks Ventana i.MX6 DualLite/Solo GW551X";
+ compatible = "gw,imx6dl-gw551x", "gw,ventana", "fsl,imx6dl";
+};
diff --git a/arch/arm/boot/dts/imx6dl-hummingboard.dts b/arch/arm/boot/dts/imx6dl-hummingboard.dts
index 7369d2d7da3e..d5c966031962 100644
--- a/arch/arm/boot/dts/imx6dl-hummingboard.dts
+++ b/arch/arm/boot/dts/imx6dl-hummingboard.dts
@@ -8,9 +8,8 @@
* 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.
+ * 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
diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index f94bf72832af..4b0ec0703825 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -106,6 +106,10 @@
};
};
+&gpt {
+ compatible = "fsl,imx6dl-gpt", "fsl,imx6q-gpt";
+};
+
&hdmi {
compatible = "fsl,imx6dl-hdmi";
};
diff --git a/arch/arm/boot/dts/imx6q-apf6dev.dts b/arch/arm/boot/dts/imx6q-apf6dev.dts
new file mode 100644
index 000000000000..4e4de821d9e5
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-apf6dev.dts
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 Armadeus Systems
+ *
+ * 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 "imx6qdl-apf6.dtsi"
+#include "imx6qdl-apf6dev.dtsi"
+
+/ {
+ model = "Armadeus APF6 Quad / Dual Module on APF6Dev Board";
+ compatible = "armadeus,imx6q-apf6dev", "armadeus,imx6q-apf6", "fsl,imx6q";
+
+ memory {
+ reg = <0x10000000 0x40000000>;
+ };
+};
+
+&sata {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6q-cubox-i.dts b/arch/arm/boot/dts/imx6q-cubox-i.dts
index 670bd8c4c847..353425edcdf4 100644
--- a/arch/arm/boot/dts/imx6q-cubox-i.dts
+++ b/arch/arm/boot/dts/imx6q-cubox-i.dts
@@ -7,9 +7,8 @@
* 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.
+ * 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
diff --git a/arch/arm/boot/dts/imx6q-gw551x.dts b/arch/arm/boot/dts/imx6q-gw551x.dts
new file mode 100644
index 000000000000..2c7feeef1b0e
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-gw551x.dts
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014 Gateworks Corporation
+ *
+ * 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 "imx6qdl-gw551x.dtsi"
+
+/ {
+ model = "Gateworks Ventana i.MX6 Dual/Quad GW551X";
+ compatible = "gw,imx6q-gw551x", "gw,ventana", "fsl,imx6q";
+};
diff --git a/arch/arm/boot/dts/imx6q-hummingboard.dts b/arch/arm/boot/dts/imx6q-hummingboard.dts
index 0f6044553a24..1884c16784e2 100644
--- a/arch/arm/boot/dts/imx6q-hummingboard.dts
+++ b/arch/arm/boot/dts/imx6q-hummingboard.dts
@@ -8,9 +8,8 @@
* 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.
+ * 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
diff --git a/arch/arm/boot/dts/imx6qdl-apf6.dtsi b/arch/arm/boot/dts/imx6qdl-apf6.dtsi
new file mode 100644
index 000000000000..1ebf29f43a24
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-apf6.dtsi
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2015 Armadeus Systems
+ *
+ * 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.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+&fec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet>;
+ phy-mode = "rgmii";
+ phy-reset-duration = <10>;
+ phy-reset-gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+/* Bluetooth */
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+/* Wi-Fi */
+&usdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ non-removable;
+ status = "okay";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wlcore: wlcore@2 {
+ compatible = "ti,wl1271";
+ reg = <2>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
+ ref-clock-frequency = <38400000>;
+ tcxo-clock-frequency = <38400000>;
+ };
+};
+
+/* eMMC */
+&usdhc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc3>;
+ bus-width = <8>;
+ no-1-8-v;
+ non-removable;
+ status = "okay";
+};
+
+&iomuxc {
+ apf6 {
+ pinctrl_enet: enetgrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b8b0
+ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
+ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
+ MX6QDL_PAD_ENET_RX_ER__GPIO1_IO24 0x130b0
+ MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x130b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
+ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x13030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x13030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1f030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1f030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x13030
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b0
+ MX6QDL_PAD_SD4_DAT5__UART2_RTS_B 0x1b0b0
+ MX6QDL_PAD_SD4_DAT6__UART2_CTS_B 0x1b0b0
+ MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b0
+ MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x130b0 /* BT_EN */
+ >;
+ };
+
+ pinctrl_usdhc1: usdhc1grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059
+ MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059
+ MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059
+ MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059
+ MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059
+ MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059
+ MX6QDL_PAD_SD4_DAT0__GPIO2_IO08 0x1b0b0 /* WL_EN */
+ MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x1b0b0 /* WL_IRQ */
+ >;
+ };
+
+ pinctrl_usdhc3: usdhc3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
+ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059
+ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059
+ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059
+ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059
+ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059
+ MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059
+ MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059
+ MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059
+ MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059
+ >;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi b/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi
new file mode 100644
index 000000000000..e26ebeb5b45c
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi
@@ -0,0 +1,479 @@
+/*
+ * Copyright 2015 Armadeus Systems
+ *
+ * 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.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ chosen {
+ stdout-path = &uart4;
+ };
+
+ display@di0 {
+ compatible = "fsl,imx-parallel-display";
+ interface-pix-fmt = "bgr666";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ipu1_disp1>;
+
+ display-timings {
+ lw700 {
+ clock-frequency = <33000033>;
+ hactive = <800>;
+ vactive = <480>;
+ hback-porch = <96>;
+ hfront-porch = <96>;
+ vback-porch = <20>;
+ vfront-porch = <21>;
+ hsync-len = <64>;
+ vsync-len = <4>;
+ hsync-active = <1>;
+ vsync-active = <1>;
+ de-active = <1>;
+ pixelclk-active = <1>;
+ };
+ };
+
+ port {
+ display_in: endpoint {
+ remote-endpoint = <&ipu1_di0_disp0>;
+ };
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_keys>;
+
+ user-button {
+ label = "User button";
+ gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
+ linux,code = <BTN_MISC>;
+ gpio-key,wakeup;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_leds>;
+
+ user-led {
+ label = "User LED";
+ gpios = <&gpio7 12 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ default-state = "on";
+ };
+ };
+
+ regulators {
+ compatible = "simple-bus";
+
+ reg_3p3v: 3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ reg_usbh1_vbus: usb-h1-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_h1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+
+ reg_usb_otg_vbus: usb-otg-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_otg_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+ };
+
+ sound {
+ compatible = "fsl,imx6-armadeus-sgtl5000",
+ "fsl,imx-audio-sgtl5000";
+ model = "imx6-armadeus-sgtl5000";
+ ssi-controller = <&ssi1>;
+ audio-codec = <&codec>;
+ audio-routing =
+ "MIC_IN", "Mic Jack",
+ "Mic Jack", "Mic Bias",
+ "Headphone Jack", "HP_OUT";
+ mux-int-port = <1>;
+ mux-ext-port = <3>;
+ };
+
+ sound-spdif {
+ compatible = "fsl,imx-audio-spdif";
+ model = "imx-spdif";
+ spdif-controller = <&spdif>;
+ spdif-out;
+ };
+};
+
+&audmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_audmux>;
+ status = "okay";
+};
+
+&can2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan2>;
+ status = "okay";
+};
+
+&ecspi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi1>;
+ fsl,spi-num-chipselects = <3>;
+ cs-gpios = <&gpio4 9 GPIO_ACTIVE_LOW>,
+ <&gpio4 10 GPIO_ACTIVE_LOW>,
+ <&gpio4 11 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c3>;
+ status = "okay";
+};
+
+&i2c1 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ touchscreen@48 {
+ compatible = "semtech,sx8654";
+ reg = <0x48>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_touchscreen>;
+ interrupt-parent = <&gpio6>;
+ interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+ };
+};
+
+&i2c2 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+
+ codec: sgtl5000@0a {
+ compatible = "fsl,sgtl5000";
+ reg = <0x0a>;
+ clocks = <&clks 201>;
+ VDDA-supply = <&reg_3p3v>;
+ VDDIO-supply = <&reg_3p3v>;
+ };
+};
+
+&i2c3 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ status = "okay";
+};
+
+&ipu1_di0_disp0 {
+ remote-endpoint = <&display_in>;
+};
+
+&pcie {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pcie>;
+ reset-gpio = <&gpio6 2 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&pwm3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm3>;
+ status = "okay";
+};
+
+/* GPS */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+/* GSM */
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3 &pinctrl_gsm>;
+ fsl,uart-has-rtscts;
+ status = "okay";
+};
+
+/* console */
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart4>;
+ status = "okay";
+};
+
+&usbh1 {
+ vbus-supply = <&reg_usbh1_vbus>;
+ phy_type = "utmi";
+ status = "okay";
+};
+
+&usbotg {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg>;
+ vbus-supply = <&reg_usb_otg_vbus>;
+ dr_mode = "otg";
+ status = "okay";
+};
+
+/* microSD */
+&usdhc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc2>;
+ cd-gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
+ no-1-8-v;
+ status = "okay";
+};
+
+&spdif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spdif>;
+ status = "okay";
+};
+
+&ssi1 {
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpios>;
+
+ apf6dev {
+ pinctrl_audmux: audmuxgrp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x1b0b0
+ MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x1b0b0
+ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x1b0b0
+ MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x1b0b0
+ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0
+ >;
+ };
+
+ pinctrl_ecspi1: ecspi1grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x100b1
+ MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x100b1
+ MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x100b1
+ MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 0x1b0b0
+ MX6QDL_PAD_KEY_ROW2__GPIO4_IO11 0x1b0b0
+ MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x1b0b0
+ >;
+ };
+
+ pinctrl_flexcan2: flexcan2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x1b0b0
+ MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x1b0b0
+ >;
+ };
+
+ pinctrl_gpio_keys: gpiokeysgrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0
+ >;
+ };
+
+ pinctrl_gpio_leds: gpioledsgrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x130b0
+ >;
+ };
+
+ pinctrl_gpios: gpiosgrp {
+ fsl,pins = <
+ MX6QDL_PAD_DI0_PIN4__GPIO4_IO20 0x100b1
+ MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12 0x100b1
+ MX6QDL_PAD_DISP0_DAT19__GPIO5_IO13 0x100b1
+ MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14 0x100b1
+ MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15 0x100b1
+ MX6QDL_PAD_DISP0_DAT22__GPIO5_IO16 0x100b1
+ MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x100b1
+ MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18 0x100b1
+ MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21 0x100b1
+ >;
+ };
+
+ pinctrl_gsm: gsmgrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x130b0 /* GSM_POKIN */
+ MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x130b0 /* GSM_PWR_EN */
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1
+ MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1
+ MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1
+ >;
+ };
+
+ pinctrl_ipu1_disp1: ipu1disp1grp {
+ fsl,pins = <
+ MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x100b1
+ MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x100b1
+ MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x100b1
+ MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x100b1
+ MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x100b1
+ MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x100b1
+ MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x100b1
+ MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x100b1
+ MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x100b1
+ MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x100b1
+ MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x100b1
+ MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x100b1
+ MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x100b1
+ MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x100b1
+ MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x100b1
+ MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x100b1
+ MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x100b1
+ MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x100b1
+ MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x100b1
+ MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x100b1
+ MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x100b1
+ MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x100b1
+ >;
+ };
+
+ pinctrl_pcie: pciegrp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT16__GPIO6_IO02 0x130b0
+ >;
+ };
+
+ pinctrl_pwm3: pwm3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b0
+ MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b0
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x1b0b0
+ MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b0
+ MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b0
+ MX6QDL_PAD_EIM_D31__UART3_RTS_B 0x1b0b0
+ >;
+ };
+
+ pinctrl_uart4: uart4grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b0
+ MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b0
+ >;
+ };
+
+ pinctrl_usbotg: usbotggrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x1b0b0
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059
+ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059
+ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059
+ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059
+ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059
+ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059
+ >;
+ };
+
+ pinctrl_spdif: spdifgrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_19__SPDIF_OUT 0x1b0b0
+ >;
+ };
+
+ pinctrl_touchscreen: touchscreengrp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03 0x1b0b0
+ >;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi b/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi
new file mode 100644
index 000000000000..1d85de2befb3
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi
@@ -0,0 +1,633 @@
+/*
+ * support for the imx6 based aristainetos2 board
+ *
+ * Copyright (C) 2015 Heiko Schocher <hs@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
+ * 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/gpio/gpio.h>
+#include <dt-bindings/clock/imx6qdl-clock.h>
+
+/ {
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm1 0 5000000>;
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <7>;
+ enable-gpios = <&gpio6 31 GPIO_ACTIVE_HIGH>;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+
+ reg_2p5v: 2p5v {
+ compatible = "regulator-fixed";
+ regulator-name = "2P5V";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ };
+
+ reg_3p3v: 3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ reg_usbh1_vbus: usb-h1-vbus {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_aristainetos2_usbh1_vbus>;
+ regulator-name = "usb_h1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+
+ reg_usbotg_vbus: usb-otg-vbus {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio4 15 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_aristainetos2_usbotg_vbus>;
+ regulator-name = "usb_otg_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+ };
+};
+
+&audmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_audmux>;
+ status = "okay";
+};
+
+&can1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan1>;
+ status = "okay";
+};
+
+&can2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan2>;
+ status = "okay";
+};
+
+&ecspi1 {
+ fsl,spi-num-chipselects = <3>;
+ cs-gpios = <&gpio4 9 GPIO_ACTIVE_HIGH
+ &gpio4 10 GPIO_ACTIVE_HIGH
+ &gpio4 11 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi1>;
+ status = "okay";
+};
+
+&ecspi2 {
+ fsl,spi-num-chipselects = <2>;
+ cs-gpios = <&gpio2 26 GPIO_ACTIVE_HIGH &gpio2 27 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi2>;
+ status = "okay";
+};
+
+&ecspi4 {
+ fsl,spi-num-chipselects = <2>;
+ cs-gpios = <&gpio3 29 GPIO_ACTIVE_HIGH &gpio5 2 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi4>;
+ status = "okay";
+
+ flash: m25p80@1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "micron,n25q128a11";
+ spi-max-frequency = <20000000>;
+ reg = <1>;
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ pmic@58 {
+ compatible = "dlg,da9063";
+ reg = <0x58>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <04 0x8>;
+
+ regulators {
+ bcore1 {
+ regulator-name = "bcore1";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ bcore2 {
+ regulator-name = "bcore2";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ bpro {
+ regulator-name = "bpro";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ bperi {
+ regulator-name = "bperi";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ bmem {
+ regulator-name = "bmem";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo2 {
+ regulator-name = "ldo2";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo3 {
+ regulator-name = "ldo3";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo4 {
+ regulator-name = "ldo4";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo5 {
+ regulator-name = "ldo5";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo6 {
+ regulator-name = "ldo6";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo7 {
+ regulator-name = "ldo7";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo8 {
+ regulator-name = "ldo8";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo9 {
+ regulator-name = "ldo9";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo10 {
+ regulator-name = "ldo10";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo11 {
+ regulator-name = "ldo11";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ bio {
+ regulator-name = "bio";
+ regulator-always-on = <1>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ };
+ };
+
+ tmp103: tmp103@71 {
+ compatible = "ti,tmp103";
+ reg = <0x71>;
+ };
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&i2c3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ status = "okay";
+
+ expander: tca6416@20 {
+ compatible = "ti,tca6416";
+ reg = <0x20>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+
+ rtc@68 {
+ compatible = "dallas,m41t00";
+ reg = <0x68>;
+ };
+};
+
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c4>;
+ status = "okay";
+
+ eeprom@50{
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+
+ eeprom@57{
+ compatible = "atmel,24c64";
+ reg = <0x57>;
+ };
+};
+
+&fec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet>;
+ phy-mode = "rgmii";
+ phy-reset-gpios = <&gpio7 18 GPIO_ACTIVE_HIGH>;
+ txd0-skew-ps = <0>;
+ txd1-skew-ps = <0>;
+ txd2-skew-ps = <0>;
+ txd3-skew-ps = <0>;
+ status = "okay";
+};
+
+&gpmi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpmi_nand>;
+ status = "okay";
+};
+
+&pcie {
+ reset-gpio = <&gpio2 16 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&pwm1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm1>;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ fsl,uart-has-rtscts;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ fsl,uart-has-rtscts;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart4>;
+ status = "okay";
+};
+
+&usbh1 {
+ vbus-supply = <&reg_usbh1_vbus>;
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbotg {
+ vbus-supply = <&reg_usbotg_vbus>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg>;
+ disable-over-current;
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ cd-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>;
+ no-1-8-v;
+ status = "okay";
+};
+
+&usdhc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc2>;
+ cd-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>;
+ wp-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+ no-1-8-v;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio>;
+
+ pinctrl_audmux: audmux {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x1b0b0
+ MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x1b0b0
+ MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x1b0b0
+ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x1b0b0
+ >;
+ };
+
+ pinctrl_ecspi1: ecspi1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1
+ MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1
+ MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1
+ MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 0x100b1 /* SS0# */
+ MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x100b1 /* SS1# */
+ MX6QDL_PAD_KEY_ROW2__GPIO4_IO11 0x100b1 /* SS2# */
+ >;
+ };
+
+ pinctrl_ecspi2: ecspi2grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1
+ MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1
+ MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1
+ MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x100b1 /* SS0# */
+ MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x100b1 /* SS1# */
+ >;
+ };
+
+ pinctrl_ecspi4: ecspi4grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D21__ECSPI4_SCLK 0x100b1
+ MX6QDL_PAD_EIM_D22__ECSPI4_MISO 0x100b1
+ MX6QDL_PAD_EIM_D28__ECSPI4_MOSI 0x100b1
+ MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x100b1 /* SS0# */
+ MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x100b1 /* SS1# */
+ MX6QDL_PAD_SD4_DAT7__GPIO2_IO15 0x1b0b0 /* WP pin */
+ >;
+ };
+
+ pinctrl_enet: enetgrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
+ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0
+ 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
+ >;
+ };
+
+ pinctrl_flexcan1: flexcan1grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_CLK__FLEXCAN1_RX 0x1b0b0
+ MX6QDL_PAD_SD3_CMD__FLEXCAN1_TX 0x1b0b0
+ >;
+ };
+
+ pinctrl_flexcan2: flexcan2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_DAT0__FLEXCAN2_TX 0x1b0b0
+ MX6QDL_PAD_SD3_DAT1__FLEXCAN2_RX 0x1b0b0
+ >;
+ };
+
+ pinctrl_gpio: gpiogrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0 /* led enable */
+ MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x1b0b0 /* LCD power enable */
+ MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x1b0b0 /* led yellow */
+ MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0x1b0b0 /* led red */
+ MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x1b0b0 /* led green */
+ MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x1b0b0 /* led blue */
+ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 /* Profibus IRQ */
+ MX6QDL_PAD_SD3_DAT6__GPIO6_IO18 0x1b0b0 /* FPGA IRQ */
+ MX6QDL_PAD_EIM_A23__GPIO6_IO06 0x1b0b0 /* spi bus #2 SS driver enable */
+ MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 /* RST_LOC# PHY reset input (has pull-down!)*/
+ MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x1b0b0 /* USB_OTG_ID = GPIO1_24*/
+ MX6QDL_PAD_SD4_DAT1__GPIO2_IO09 0x1b0b0 /* Touchscreen IRQ */
+ MX6QDL_PAD_EIM_A22__GPIO2_IO16 0x1b0b0 /* PCIe reset */
+ >;
+ };
+
+ pinctrl_gpmi_nand: gpmi-nand {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1
+ MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1
+ MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1
+ MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000
+ MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1
+ MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1
+ MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1
+ MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1
+ MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1
+ MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1
+ MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1
+ MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1
+ MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1
+ MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1
+ MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1
+ MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1
+ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c4: i2c4grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_7__I2C4_SCL 0x4001b8b1
+ MX6QDL_PAD_GPIO_8__I2C4_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_pwm1: pwm1grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_9__PWM1_OUT 0x1b0b0
+ MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x1b0b0 /* backlight enable */
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D20__UART1_RTS_B 0x1b0b1
+ MX6QDL_PAD_EIM_D19__UART1_CTS_B 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D31__UART3_RTS_B 0x1b0b1
+ MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart4: uart4grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1
+ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_usbotg: usbotggrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
+ >;
+ };
+
+ pinctrl_aristainetos2_usbh1_vbus: aristainetos-usbh1-vbus {
+ fsl,pins = <MX6QDL_PAD_GPIO_0__USB_H1_PWR 0x130b0>;
+ };
+
+ pinctrl_aristainetos2_usbotg_vbus: aristainetos-usbotg-vbus {
+ fsl,pins = <MX6QDL_PAD_KEY_ROW4__USB_OTG_PWR 0x130b0>;
+ };
+
+ pinctrl_usdhc1: usdhc1grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059
+ MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059
+ MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059
+ MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059
+ MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059
+ MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059
+ MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x1b0b0 /* SD1 card detect input */
+ MX6QDL_PAD_DI0_PIN4__GPIO4_IO20 0x1b0b0 /* SD1 write protect input */
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x71
+ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x71
+ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x71
+ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x71
+ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x71
+ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x71
+ MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x1b0b0 /* SD2 level shifter output enable */
+ MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0 /* SD2 card detect input */
+ MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x1b0b0 /* SD2 write protect input */
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
index d033bb182060..59e5d15e3ec4 100644
--- a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
@@ -7,9 +7,8 @@
* 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.
+ * 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
diff --git a/arch/arm/boot/dts/imx6qdl-gw551x.dtsi b/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
new file mode 100644
index 000000000000..d1866a0a2f13
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2014 Gateworks Corporation
+ *
+ * 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.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ /* these are used by bootloader for disabling nodes */
+ aliases {
+ led0 = &led0;
+ nand = &gpmi;
+ ssi0 = &ssi1;
+ usb0 = &usbh1;
+ usb1 = &usbotg;
+ };
+
+ chosen {
+ bootargs = "console=ttymxc1,115200";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_leds>;
+
+ led0: user1 {
+ label = "user1";
+ gpios = <&gpio4 7 GPIO_ACTIVE_LOW>;
+ default-state = "on";
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ memory {
+ reg = <0x10000000 0x20000000>;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg_5p0v: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "5P0V";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+
+ reg_usb_h1_vbus: regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "usb_h1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+
+ reg_usb_otg_vbus: regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "usb_otg_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+ };
+};
+
+&can1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan1>;
+ status = "okay";
+};
+
+&gpmi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpmi_nand>;
+ status = "okay";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c3>;
+ status = "okay";
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ eeprom1: eeprom@50 {
+ compatible = "atmel,24c02";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+
+ eeprom2: eeprom@51 {
+ compatible = "atmel,24c02";
+ reg = <0x51>;
+ pagesize = <16>;
+ };
+
+ eeprom3: eeprom@52 {
+ compatible = "atmel,24c02";
+ reg = <0x52>;
+ pagesize = <16>;
+ };
+
+ eeprom4: eeprom@53 {
+ compatible = "atmel,24c02";
+ reg = <0x53>;
+ pagesize = <16>;
+ };
+
+ gpio: pca9555@23 {
+ compatible = "nxp,pca9555";
+ reg = <0x23>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ rtc: ds1672@68 {
+ compatible = "dallas,ds1672";
+ reg = <0x68>;
+ };
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&i2c3 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ status = "okay";
+
+ gpio_exp: pca9555@24 {
+ compatible = "nxp,pca9555";
+ reg = <0x24>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+};
+
+&pcie {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pcie>;
+ reset-gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&ssi1 {
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ status = "okay";
+};
+
+&usbotg {
+ vbus-supply = <&reg_usb_otg_vbus>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg>;
+ disable-over-current;
+ status = "okay";
+};
+
+&usbh1 {
+ vbus-supply = <&reg_usb_h1_vbus>;
+ status = "okay";
+};
+
+&iomuxc {
+ imx6qdl-gw51xx {
+ pinctrl_flexcan1: flexcan1grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b1
+ MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b1
+ MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x4001b0b0 /* CAN_STBY */
+ >;
+ };
+
+ pinctrl_gpio_leds: gpioledsgrp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x1b0b0
+ >;
+ };
+
+ pinctrl_gpmi_nand: gpminandgrp {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1
+ MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1
+ MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1
+ MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000
+ MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1
+ MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1
+ MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1
+ MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1
+ MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1
+ MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1
+ MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1
+ MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1
+ MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1
+ MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1
+ MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1
+ MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
+ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1
+ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_pcie: pciegrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0 /* PCIE RST */
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1
+ MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_usbotg: usbotggrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
+ >;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi b/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
index 151a3db2aea9..62a82f3eba88 100644
--- a/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
@@ -7,9 +7,8 @@
* 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.
+ * 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
@@ -192,6 +191,12 @@
>;
};
+ pinctrl_hummingboard_pcie_reset: hummingboard-pcie-reset {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x1b0b1
+ >;
+ };
+
pinctrl_hummingboard_pwm1: pwm1grp {
fsl,pins = <MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b1>;
};
@@ -245,6 +250,13 @@
};
};
+&pcie {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hummingboard_pcie_reset>;
+ reset-gpio = <&gpio3 4 0>;
+ status = "okay";
+};
+
&pwm1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hummingboard_pwm1>;
@@ -263,7 +275,6 @@
};
&ssi1 {
- fsl,mode = "i2s-slave";
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi b/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi
index 4a1820309cdb..469ef58ce4bc 100644
--- a/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi
@@ -10,9 +10,8 @@
* 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.
+ * 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
diff --git a/arch/arm/boot/dts/imx6qdl-microsom.dtsi b/arch/arm/boot/dts/imx6qdl-microsom.dtsi
index 349f82be816e..6d4069cc9419 100644
--- a/arch/arm/boot/dts/imx6qdl-microsom.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-microsom.dtsi
@@ -7,9 +7,8 @@
* 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.
+ * 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
@@ -39,15 +38,98 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dt-bindings/gpio/gpio.h>
+/ {
+ clk_sdio: sdio-clock {
+ compatible = "gpio-gate-clock";
+ #clock-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_microsom_brcm_osc>;
+ enable-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+
+ reg_brcm: brcm-reg {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio3 19 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_microsom_brcm_reg>;
+ regulator-name = "brcm_reg";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <200000>;
+ };
+ };
+
+ usdhc1_pwrseq: usdhc1_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&gpio5 26 GPIO_ACTIVE_LOW>,
+ <&gpio6 0 GPIO_ACTIVE_LOW>;
+ clocks = <&clk_sdio>;
+ clock-names = "ext_clock";
+ };
+};
&iomuxc {
microsom {
+ pinctrl_microsom_brcm_bt: microsom-brcm-bt {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x40013070
+ MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01 0x40013070
+ MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x40013070
+ >;
+ };
+
+ pinctrl_microsom_brcm_osc: microsom-brcm-osc {
+ fsl,pins = <
+ MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070
+ >;
+ };
+
+ pinctrl_microsom_brcm_reg: microsom-brcm-reg {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x40013070
+ >;
+ };
+
+ pinctrl_microsom_brcm_wifi: microsom-brcm-wifi {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x1b0b0
+ MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x40013070
+ MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x40013070
+ MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 0x40013070
+ >;
+ };
+
pinctrl_microsom_uart1: microsom-uart1 {
fsl,pins = <
MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1
MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1
>;
};
+
+ pinctrl_microsom_uart4: microsom-uart4 {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1
+ >;
+ };
+
+ pinctrl_microsom_usdhc1: microsom-usdhc1 {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059
+ MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059
+ MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059
+ MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059
+ MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059
+ MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059
+ >;
+ };
};
};
@@ -56,3 +138,23 @@
pinctrl-0 = <&pinctrl_microsom_uart1>;
status = "okay";
};
+
+/* UART4 - Connected to optional BRCM Wifi/BT/FM */
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_microsom_brcm_bt &pinctrl_microsom_uart4>;
+ fsl,uart-has-rtscts;
+ status = "okay";
+};
+
+/* USDHC1 - Connected to optional BRCM Wifi/BT/FM */
+&usdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_microsom_brcm_wifi &pinctrl_microsom_usdhc1>;
+ bus-width = <4>;
+ mmc-pwrseq = <&usdhc1_pwrseq>;
+ keep-power-in-suspend;
+ non-removable;
+ vmmc-supply = <&reg_brcm>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
index 08218120e770..3af16dfe417b 100644
--- a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
@@ -122,7 +122,7 @@
status = "okay";
};
- backlight_lvds {
+ backlight_lvds: backlight_lvds {
compatible = "pwm-backlight";
pwms = <&pwm4 0 5000000>;
brightness-levels = <0 4 8 16 32 64 128 255>;
@@ -130,6 +130,17 @@
power-supply = <&reg_3p3v>;
status = "okay";
};
+
+ panel {
+ compatible = "hannstar,hsd100pxn1";
+ backlight = <&backlight_lvds>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&lvds0_out>;
+ };
+ };
+ };
};
&audmux {
@@ -379,18 +390,11 @@
fsl,data-width = <18>;
status = "okay";
- display-timings {
- native-mode = <&timing0>;
- timing0: hsd100pxn1 {
- clock-frequency = <65000000>;
- hactive = <1024>;
- vactive = <768>;
- hback-porch = <220>;
- hfront-porch = <40>;
- vback-porch = <21>;
- vfront-porch = <7>;
- hsync-len = <60>;
- vsync-len = <10>;
+ port@4 {
+ reg = <4>;
+
+ lvds0_out: endpoint {
+ remote-endpoint = <&panel_in>;
};
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
index 0b28a9d5241e..e00c44f6a0df 100644
--- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
@@ -121,7 +121,7 @@
status = "okay";
};
- backlight_lvds {
+ backlight_lvds: backlight_lvds {
compatible = "pwm-backlight";
pwms = <&pwm4 0 5000000>;
brightness-levels = <0 4 8 16 32 64 128 255>;
@@ -129,6 +129,17 @@
power-supply = <&reg_3p3v>;
status = "okay";
};
+
+ panel {
+ compatible = "hannstar,hsd100pxn1";
+ backlight = <&backlight_lvds>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&lvds0_out>;
+ };
+ };
+ };
};
&audmux {
@@ -374,18 +385,11 @@
fsl,data-width = <18>;
status = "okay";
- display-timings {
- native-mode = <&timing0>;
- timing0: hsd100pxn1 {
- clock-frequency = <65000000>;
- hactive = <1024>;
- vactive = <768>;
- hback-porch = <220>;
- hfront-porch = <40>;
- vback-porch = <21>;
- vfront-porch = <7>;
- hsync-len = <60>;
- vsync-len = <10>;
+ port@4 {
+ reg = <4>;
+
+ lvds0_out: endpoint {
+ remote-endpoint = <&panel_in>;
};
};
};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index f74a8ded515f..e6d13592080d 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -119,6 +119,34 @@
status = "disabled";
};
+ hdmi: hdmi@0120000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x00120000 0x9000>;
+ interrupts = <0 115 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks IMX6QDL_CLK_HDMI_IAHB>,
+ <&clks IMX6QDL_CLK_HDMI_ISFR>;
+ clock-names = "iahb", "isfr";
+ status = "disabled";
+
+ port@0 {
+ reg = <0>;
+
+ hdmi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_hdmi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ hdmi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_hdmi>;
+ };
+ };
+ };
+
timer@00a00600 {
compatible = "arm,cortex-a9-twd-timer";
reg = <0x00a00600 0x20>;
@@ -343,6 +371,7 @@
clocks = <&clks IMX6QDL_CLK_VPU_AXI>,
<&clks IMX6QDL_CLK_MMDC_CH0_AXI>;
clock-names = "per", "ahb";
+ power-domains = <&gpc 1>;
resets = <&src 1>;
iram = <&ocram>;
};
@@ -778,34 +807,6 @@
};
};
- hdmi: hdmi@0120000 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x00120000 0x9000>;
- interrupts = <0 115 0x04>;
- gpr = <&gpr>;
- clocks = <&clks IMX6QDL_CLK_HDMI_IAHB>,
- <&clks IMX6QDL_CLK_HDMI_ISFR>;
- clock-names = "iahb", "isfr";
- status = "disabled";
-
- port@0 {
- reg = <0>;
-
- hdmi_mux_0: endpoint {
- remote-endpoint = <&ipu1_di0_hdmi>;
- };
- };
-
- port@1 {
- reg = <1>;
-
- hdmi_mux_1: endpoint {
- remote-endpoint = <&ipu1_di1_hdmi>;
- };
- };
- };
-
dcic1: dcic@020e4000 {
reg = <0x020e4000 0x4000>;
interrupts = <0 124 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/imx6sl-warp.dts b/arch/arm/boot/dts/imx6sl-warp.dts
index 64f7decf1fdc..0da906bd8df2 100644
--- a/arch/arm/boot/dts/imx6sl-warp.dts
+++ b/arch/arm/boot/dts/imx6sl-warp.dts
@@ -58,40 +58,6 @@
reg = <0x80000000 0x20000000>;
};
- regulators {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <0>;
-
- reg_usb_otg1_vbus: regulator@0 {
- compatible = "regulator-fixed";
- reg = <0>;
- regulator-name = "usb_otg1_vbus";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- gpio = <&gpio4 0 0>;
- enable-active-high;
- };
-
- reg_usb_otg2_vbus: regulator@1 {
- compatible = "regulator-fixed";
- reg = <1>;
- regulator-name = "usb_otg2_vbus";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- gpio = <&gpio4 2 0>;
- enable-active-high;
- };
-
- reg_1p8v: regulator@2 {
- compatible = "regulator-fixed";
- reg = <2>;
- regulator-name = "1P8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
- };
-
usdhc3_pwrseq: usdhc3_pwrseq {
compatible = "mmc-pwrseq-simple";
reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>, /* WL_REG_ON */
@@ -121,14 +87,13 @@
};
&usbotg1 {
- vbus-supply = <&reg_usb_otg1_vbus>;
- dr_mode = "host";
+ dr_mode = "peripheral";
disable-over-current;
status = "okay";
};
&usbotg2 {
- vbus-supply = <&reg_usb_otg2_vbus>;
+ dr_mode = "host";
disable-over-current;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx7d-pinfunc.h b/arch/arm/boot/dts/imx7d-pinfunc.h
new file mode 100644
index 000000000000..a8d81497edb3
--- /dev/null
+++ b/arch/arm/boot/dts/imx7d-pinfunc.h
@@ -0,0 +1,1038 @@
+/*
+ * Copyright (C) 2014-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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __DTS_IMX7D_PINFUNC_H
+#define __DTS_IMX7D_PINFUNC_H
+
+/*
+ * The pin function ID is a tuple of
+ * <mux_reg conf_reg input_reg mux_mode input_val>
+ */
+
+#define MX7D_PAD_EPDC_DATA00__EPDC_DATA0 0x0034 0x02A4 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA00__SIM1_PORT2_TRXD 0x0034 0x02A4 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA00__QSPI_A_DATA0 0x0034 0x02A4 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA00__KPP_ROW3 0x0034 0x02A4 0x0620 0x3 0x0
+#define MX7D_PAD_EPDC_DATA00__EIM_AD0 0x0034 0x02A4 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA00__GPIO2_IO0 0x0034 0x02A4 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA00__LCD_DATA0 0x0034 0x02A4 0x0638 0x6 0x0
+#define MX7D_PAD_EPDC_DATA00__LCD_CLK 0x0034 0x02A4 0x0000 0x7 0x0
+#define MX7D_PAD_EPDC_DATA01__EPDC_DATA1 0x0038 0x02A8 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA01__SIM1_PORT2_CLK 0x0038 0x02A8 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA01__QSPI_A_DATA1 0x0038 0x02A8 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA01__KPP_COL3 0x0038 0x02A8 0x0600 0x3 0x0
+#define MX7D_PAD_EPDC_DATA01__EIM_AD1 0x0038 0x02A8 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA01__GPIO2_IO1 0x0038 0x02A8 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA01__LCD_DATA1 0x0038 0x02A8 0x063C 0x6 0x0
+#define MX7D_PAD_EPDC_DATA01__LCD_ENABLE 0x0038 0x02A8 0x0000 0x7 0x0
+#define MX7D_PAD_EPDC_DATA02__EPDC_DATA2 0x003C 0x02AC 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA02__SIM1_PORT2_RST_B 0x003C 0x02AC 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA02__QSPI_A_DATA2 0x003C 0x02AC 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA02__KPP_ROW2 0x003C 0x02AC 0x061C 0x3 0x0
+#define MX7D_PAD_EPDC_DATA02__EIM_AD2 0x003C 0x02AC 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA02__GPIO2_IO2 0x003C 0x02AC 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA02__LCD_DATA2 0x003C 0x02AC 0x0640 0x6 0x0
+#define MX7D_PAD_EPDC_DATA02__LCD_VSYNC 0x003C 0x02AC 0x0698 0x7 0x0
+#define MX7D_PAD_EPDC_DATA03__EPDC_DATA3 0x0040 0x02B0 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA03__SIM1_PORT2_SVEN 0x0040 0x02B0 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA03__QSPI_A_DATA3 0x0040 0x02B0 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA03__KPP_COL2 0x0040 0x02B0 0x05FC 0x3 0x0
+#define MX7D_PAD_EPDC_DATA03__EIM_AD3 0x0040 0x02B0 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA03__GPIO2_IO3 0x0040 0x02B0 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA03__LCD_DATA3 0x0040 0x02B0 0x0644 0x6 0x0
+#define MX7D_PAD_EPDC_DATA03__LCD_HSYNC 0x0040 0x02B0 0x0000 0x7 0x0
+#define MX7D_PAD_EPDC_DATA04__EPDC_DATA4 0x0044 0x02B4 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA04__SIM1_PORT2_PD 0x0044 0x02B4 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA04__QSPI_A_DQS 0x0044 0x02B4 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA04__KPP_ROW1 0x0044 0x02B4 0x0618 0x3 0x0
+#define MX7D_PAD_EPDC_DATA04__EIM_AD4 0x0044 0x02B4 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA04__GPIO2_IO4 0x0044 0x02B4 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA04__LCD_DATA4 0x0044 0x02B4 0x0648 0x6 0x0
+#define MX7D_PAD_EPDC_DATA04__JTAG_FAIL 0x0044 0x02B4 0x0000 0x7 0x0
+#define MX7D_PAD_EPDC_DATA05__EPDC_DATA5 0x0048 0x02B8 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA05__SIM2_PORT2_TRXD 0x0048 0x02B8 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA05__QSPI_A_SCLK 0x0048 0x02B8 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA05__KPP_COL1 0x0048 0x02B8 0x05F8 0x3 0x0
+#define MX7D_PAD_EPDC_DATA05__EIM_AD5 0x0048 0x02B8 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA05__GPIO2_IO5 0x0048 0x02B8 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA05__LCD_DATA5 0x0048 0x02B8 0x064C 0x6 0x0
+#define MX7D_PAD_EPDC_DATA05__JTAG_ACTIVE 0x0048 0x02B8 0x0000 0x7 0x0
+#define MX7D_PAD_EPDC_DATA06__EPDC_DATA6 0x004C 0x02BC 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA06__SIM2_PORT2_CLK 0x004C 0x02BC 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA06__QSPI_A_SS0_B 0x004C 0x02BC 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA06__KPP_ROW0 0x004C 0x02BC 0x0614 0x3 0x0
+#define MX7D_PAD_EPDC_DATA06__EIM_AD6 0x004C 0x02BC 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA06__GPIO2_IO6 0x004C 0x02BC 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA06__LCD_DATA6 0x004C 0x02BC 0x0650 0x6 0x0
+#define MX7D_PAD_EPDC_DATA06__JTAG_DE_B 0x004C 0x02BC 0x0000 0x7 0x0
+#define MX7D_PAD_EPDC_DATA07__EPDC_DATA7 0x0050 0x02C0 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA07__SIM2_PORT2_RST_B 0x0050 0x02C0 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA07__QSPI_A_SS1_B 0x0050 0x02C0 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA07__KPP_COL0 0x0050 0x02C0 0x05F4 0x3 0x0
+#define MX7D_PAD_EPDC_DATA07__EIM_AD7 0x0050 0x02C0 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA07__GPIO2_IO7 0x0050 0x02C0 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA07__LCD_DATA7 0x0050 0x02C0 0x0654 0x6 0x0
+#define MX7D_PAD_EPDC_DATA07__JTAG_DONE 0x0050 0x02C0 0x0000 0x7 0x0
+#define MX7D_PAD_EPDC_DATA08__EPDC_DATA8 0x0054 0x02C4 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA08__SIM1_PORT1_TRXD 0x0054 0x02C4 0x06E4 0x1 0x0
+#define MX7D_PAD_EPDC_DATA08__QSPI_B_DATA0 0x0054 0x02C4 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA08__UART6_DCE_RX 0x0054 0x02C4 0x071C 0x3 0x0
+#define MX7D_PAD_EPDC_DATA08__UART6_DTE_TX 0x0054 0x02C4 0x0000 0x3 0x0
+#define MX7D_PAD_EPDC_DATA08__EIM_OE 0x0054 0x02C4 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA08__GPIO2_IO8 0x0054 0x02C4 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA08__LCD_DATA8 0x0054 0x02C4 0x0658 0x6 0x0
+#define MX7D_PAD_EPDC_DATA08__LCD_BUSY 0x0054 0x02C4 0x0634 0x7 0x0
+#define MX7D_PAD_EPDC_DATA08__EPDC_SDCLK 0x0054 0x02C4 0x0000 0x8 0x0
+#define MX7D_PAD_EPDC_DATA09__EPDC_DATA9 0x0058 0x02C8 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA09__SIM1_PORT1_CLK 0x0058 0x02C8 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA09__QSPI_B_DATA1 0x0058 0x02C8 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA09__UART6_DCE_TX 0x0058 0x02C8 0x0000 0x3 0x0
+#define MX7D_PAD_EPDC_DATA09__UART6_DTE_RX 0x0058 0x02C8 0x071C 0x3 0x1
+#define MX7D_PAD_EPDC_DATA09__EIM_RW 0x0058 0x02C8 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA09__GPIO2_IO9 0x0058 0x02C8 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA09__LCD_DATA9 0x0058 0x02C8 0x065C 0x6 0x0
+#define MX7D_PAD_EPDC_DATA09__LCD_DATA0 0x0058 0x02C8 0x0638 0x7 0x1
+#define MX7D_PAD_EPDC_DATA09__EPDC_SDLE 0x0058 0x02C8 0x0000 0x8 0x0
+#define MX7D_PAD_EPDC_DATA10__EPDC_DATA10 0x005C 0x02CC 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA10__SIM1_PORT1_RST_B 0x005C 0x02CC 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA10__QSPI_B_DATA2 0x005C 0x02CC 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA10__UART6_DCE_RTS 0x005C 0x02CC 0x0718 0x3 0x0
+#define MX7D_PAD_EPDC_DATA10__UART6_DTE_CTS 0x005C 0x02CC 0x0000 0x3 0x0
+#define MX7D_PAD_EPDC_DATA10__EIM_CS0_B 0x005C 0x02CC 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA10__GPIO2_IO10 0x005C 0x02CC 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA10__LCD_DATA10 0x005C 0x02CC 0x0660 0x6 0x0
+#define MX7D_PAD_EPDC_DATA10__LCD_DATA9 0x005C 0x02CC 0x065C 0x7 0x1
+#define MX7D_PAD_EPDC_DATA10__EPDC_SDOE 0x005C 0x02CC 0x0000 0x8 0x0
+#define MX7D_PAD_EPDC_DATA11__EPDC_DATA11 0x0060 0x02D0 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA11__SIM1_PORT1_SVEN 0x0060 0x02D0 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA11__QSPI_B_DATA3 0x0060 0x02D0 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA11__UART6_DCE_CTS 0x0060 0x02D0 0x0000 0x3 0x0
+#define MX7D_PAD_EPDC_DATA11__UART6_DTE_RTS 0x0060 0x02D0 0x0718 0x3 0x1
+#define MX7D_PAD_EPDC_DATA11__EIM_BCLK 0x0060 0x02D0 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA11__GPIO2_IO11 0x0060 0x02D0 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA11__LCD_DATA11 0x0060 0x02D0 0x0664 0x6 0x0
+#define MX7D_PAD_EPDC_DATA11__LCD_DATA1 0x0060 0x02D0 0x063C 0x7 0x1
+#define MX7D_PAD_EPDC_DATA11__EPDC_SDCE0 0x0060 0x02D0 0x0000 0x8 0x0
+#define MX7D_PAD_EPDC_DATA12__EPDC_DATA12 0x0064 0x02D4 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA12__SIM1_PORT1_PD 0x0064 0x02D4 0x06E0 0x1 0x0
+#define MX7D_PAD_EPDC_DATA12__QSPI_B_DQS 0x0064 0x02D4 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA12__UART7_DCE_RX 0x0064 0x02D4 0x0724 0x3 0x0
+#define MX7D_PAD_EPDC_DATA12__UART7_DTE_TX 0x0064 0x02D4 0x0000 0x3 0x0
+#define MX7D_PAD_EPDC_DATA12__EIM_LBA_B 0x0064 0x02D4 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA12__GPIO2_IO12 0x0064 0x02D4 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA12__LCD_DATA12 0x0064 0x02D4 0x0668 0x6 0x0
+#define MX7D_PAD_EPDC_DATA12__LCD_DATA21 0x0064 0x02D4 0x068C 0x7 0x0
+#define MX7D_PAD_EPDC_DATA12__EPDC_GDCLK 0x0064 0x02D4 0x0000 0x8 0x0
+#define MX7D_PAD_EPDC_DATA13__EPDC_DATA13 0x0068 0x02D8 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA13__SIM2_PORT1_TRXD 0x0068 0x02D8 0x06EC 0x1 0x0
+#define MX7D_PAD_EPDC_DATA13__QSPI_B_SCLK 0x0068 0x02D8 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA13__UART7_DCE_TX 0x0068 0x02D8 0x0000 0x3 0x0
+#define MX7D_PAD_EPDC_DATA13__UART7_DTE_RX 0x0068 0x02D8 0x0724 0x3 0x1
+#define MX7D_PAD_EPDC_DATA13__EIM_WAIT 0x0068 0x02D8 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA13__GPIO2_IO13 0x0068 0x02D8 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA13__LCD_DATA13 0x0068 0x02D8 0x066C 0x6 0x0
+#define MX7D_PAD_EPDC_DATA13__LCD_CS 0x0068 0x02D8 0x0000 0x7 0x0
+#define MX7D_PAD_EPDC_DATA13__EPDC_GDOE 0x0068 0x02D8 0x0000 0x8 0x0
+#define MX7D_PAD_EPDC_DATA14__EPDC_DATA14 0x006C 0x02DC 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA14__SIM2_PORT1_CLK 0x006C 0x02DC 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA14__QSPI_B_SS0_B 0x006C 0x02DC 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA14__UART7_DCE_RTS 0x006C 0x02DC 0x0720 0x3 0x0
+#define MX7D_PAD_EPDC_DATA14__UART7_DTE_CTS 0x006C 0x02DC 0x0000 0x3 0x0
+#define MX7D_PAD_EPDC_DATA14__EIM_EB_B0 0x006C 0x02DC 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA14__GPIO2_IO14 0x006C 0x02DC 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA14__LCD_DATA14 0x006C 0x02DC 0x0670 0x6 0x0
+#define MX7D_PAD_EPDC_DATA14__LCD_DATA22 0x006C 0x02DC 0x0690 0x7 0x0
+#define MX7D_PAD_EPDC_DATA14__EPDC_GDSP 0x006C 0x02DC 0x0000 0x8 0x0
+#define MX7D_PAD_EPDC_DATA15__EPDC_DATA15 0x0070 0x02E0 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_DATA15__SIM2_PORT1_RST_B 0x0070 0x02E0 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_DATA15__QSPI_B_SS1_B 0x0070 0x02E0 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_DATA15__UART7_DCE_CTS 0x0070 0x02E0 0x0000 0x3 0x0
+#define MX7D_PAD_EPDC_DATA15__UART7_DTE_RTS 0x0070 0x02E0 0x0720 0x3 0x1
+#define MX7D_PAD_EPDC_DATA15__EIM_CS1_B 0x0070 0x02E0 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_DATA15__GPIO2_IO15 0x0070 0x02E0 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_DATA15__LCD_DATA15 0x0070 0x02E0 0x0674 0x6 0x0
+#define MX7D_PAD_EPDC_DATA15__LCD_WR_RWN 0x0070 0x02E0 0x0000 0x7 0x0
+#define MX7D_PAD_EPDC_DATA15__EPDC_PWR_COM 0x0070 0x02E0 0x0000 0x8 0x0
+#define MX7D_PAD_EPDC_SDCLK__EPDC_SDCLK 0x0074 0x02E4 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_SDCLK__SIM2_PORT2_SVEN 0x0074 0x02E4 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0 0x0074 0x02E4 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_SDCLK__KPP_ROW4 0x0074 0x02E4 0x0624 0x3 0x0
+#define MX7D_PAD_EPDC_SDCLK__EIM_AD10 0x0074 0x02E4 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_SDCLK__GPIO2_IO16 0x0074 0x02E4 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_SDCLK__LCD_CLK 0x0074 0x02E4 0x0000 0x6 0x0
+#define MX7D_PAD_EPDC_SDCLK__LCD_DATA20 0x0074 0x02E4 0x0688 0x7 0x0
+#define MX7D_PAD_EPDC_SDLE__EPDC_SDLE 0x0078 0x02E8 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_SDLE__SIM2_PORT2_PD 0x0078 0x02E8 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1 0x0078 0x02E8 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_SDLE__KPP_COL4 0x0078 0x02E8 0x0604 0x3 0x0
+#define MX7D_PAD_EPDC_SDLE__EIM_AD11 0x0078 0x02E8 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_SDLE__GPIO2_IO17 0x0078 0x02E8 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_SDLE__LCD_DATA16 0x0078 0x02E8 0x0678 0x6 0x0
+#define MX7D_PAD_EPDC_SDLE__LCD_DATA8 0x0078 0x02E8 0x0658 0x7 0x1
+#define MX7D_PAD_EPDC_SDOE__EPDC_SDOE 0x007C 0x02EC 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_SDOE__FLEXTIMER1_CH0 0x007C 0x02EC 0x0584 0x1 0x0
+#define MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2 0x007C 0x02EC 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_SDOE__KPP_COL5 0x007C 0x02EC 0x0608 0x3 0x1
+#define MX7D_PAD_EPDC_SDOE__EIM_AD12 0x007C 0x02EC 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_SDOE__GPIO2_IO18 0x007C 0x02EC 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_SDOE__LCD_DATA17 0x007C 0x02EC 0x067C 0x6 0x0
+#define MX7D_PAD_EPDC_SDOE__LCD_DATA23 0x007C 0x02EC 0x0694 0x7 0x0
+#define MX7D_PAD_EPDC_SDSHR__EPDC_SDSHR 0x0080 0x02F0 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_SDSHR__FLEXTIMER1_CH1 0x0080 0x02F0 0x0588 0x1 0x0
+#define MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3 0x0080 0x02F0 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_SDSHR__KPP_ROW5 0x0080 0x02F0 0x0628 0x3 0x1
+#define MX7D_PAD_EPDC_SDSHR__EIM_AD13 0x0080 0x02F0 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_SDSHR__GPIO2_IO19 0x0080 0x02F0 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_SDSHR__LCD_DATA18 0x0080 0x02F0 0x0680 0x6 0x0
+#define MX7D_PAD_EPDC_SDSHR__LCD_DATA10 0x0080 0x02F0 0x0660 0x7 0x1
+#define MX7D_PAD_EPDC_SDCE0__EPDC_SDCE0 0x0084 0x02F4 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_SDCE0__FLEXTIMER1_CH2 0x0084 0x02F4 0x058C 0x1 0x0
+#define MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL 0x0084 0x02F4 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_SDCE0__EIM_AD14 0x0084 0x02F4 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_SDCE0__GPIO2_IO20 0x0084 0x02F4 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_SDCE0__LCD_DATA19 0x0084 0x02F4 0x0684 0x6 0x0
+#define MX7D_PAD_EPDC_SDCE0__LCD_DATA5 0x0084 0x02F4 0x064C 0x7 0x1
+#define MX7D_PAD_EPDC_SDCE1__EPDC_SDCE1 0x0088 0x02F8 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_SDCE1__FLEXTIMER1_CH3 0x0088 0x02F8 0x0590 0x1 0x0
+#define MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC 0x0088 0x02F8 0x0578 0x2 0x0
+#define MX7D_PAD_EPDC_SDCE1__ENET2_RX_ER 0x0088 0x02F8 0x0000 0x3 0x0
+#define MX7D_PAD_EPDC_SDCE1__EIM_AD15 0x0088 0x02F8 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_SDCE1__GPIO2_IO21 0x0088 0x02F8 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_SDCE1__LCD_DATA20 0x0088 0x02F8 0x0688 0x6 0x1
+#define MX7D_PAD_EPDC_SDCE1__LCD_DATA4 0x0088 0x02F8 0x0648 0x7 0x1
+#define MX7D_PAD_EPDC_SDCE2__EPDC_SDCE2 0x008C 0x02FC 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_SDCE2__SIM2_PORT1_SVEN 0x008C 0x02FC 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0 0x008C 0x02FC 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_SDCE2__KPP_COL6 0x008C 0x02FC 0x060C 0x3 0x1
+#define MX7D_PAD_EPDC_SDCE2__EIM_ADDR16 0x008C 0x02FC 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_SDCE2__GPIO2_IO22 0x008C 0x02FC 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_SDCE2__LCD_DATA21 0x008C 0x02FC 0x068C 0x6 0x1
+#define MX7D_PAD_EPDC_SDCE2__LCD_DATA3 0x008C 0x02FC 0x0644 0x7 0x1
+#define MX7D_PAD_EPDC_SDCE3__EPDC_SDCE3 0x0090 0x0300 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_SDCE3__SIM2_PORT1_PD 0x0090 0x0300 0x06E8 0x1 0x0
+#define MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1 0x0090 0x0300 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_SDCE3__KPP_ROW6 0x0090 0x0300 0x062C 0x3 0x1
+#define MX7D_PAD_EPDC_SDCE3__EIM_ADDR17 0x0090 0x0300 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_SDCE3__GPIO2_IO23 0x0090 0x0300 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_SDCE3__LCD_DATA22 0x0090 0x0300 0x0690 0x6 0x1
+#define MX7D_PAD_EPDC_SDCE3__LCD_DATA2 0x0090 0x0300 0x0640 0x7 0x1
+#define MX7D_PAD_EPDC_GDCLK__EPDC_GDCLK 0x0094 0x0304 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_GDCLK__FLEXTIMER2_CH0 0x0094 0x0304 0x05AC 0x1 0x0
+#define MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2 0x0094 0x0304 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_GDCLK__KPP_COL7 0x0094 0x0304 0x0610 0x3 0x0
+#define MX7D_PAD_EPDC_GDCLK__EIM_ADDR18 0x0094 0x0304 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_GDCLK__GPIO2_IO24 0x0094 0x0304 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_GDCLK__LCD_DATA23 0x0094 0x0304 0x0694 0x6 0x1
+#define MX7D_PAD_EPDC_GDCLK__LCD_DATA16 0x0094 0x0304 0x0678 0x7 0x1
+#define MX7D_PAD_EPDC_GDOE__EPDC_GDOE 0x0098 0x0308 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_GDOE__FLEXTIMER2_CH1 0x0098 0x0308 0x05B0 0x1 0x0
+#define MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3 0x0098 0x0308 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_GDOE__KPP_ROW7 0x0098 0x0308 0x0630 0x3 0x0
+#define MX7D_PAD_EPDC_GDOE__EIM_ADDR19 0x0098 0x0308 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_GDOE__GPIO2_IO25 0x0098 0x0308 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_GDOE__LCD_WR_RWN 0x0098 0x0308 0x0000 0x6 0x0
+#define MX7D_PAD_EPDC_GDOE__LCD_DATA18 0x0098 0x0308 0x0680 0x7 0x1
+#define MX7D_PAD_EPDC_GDRL__EPDC_GDRL 0x009C 0x030C 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_GDRL__FLEXTIMER2_CH2 0x009C 0x030C 0x05B4 0x1 0x0
+#define MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL 0x009C 0x030C 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_GDRL__EIM_ADDR20 0x009C 0x030C 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_GDRL__GPIO2_IO26 0x009C 0x030C 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_GDRL__LCD_RD_E 0x009C 0x030C 0x0000 0x6 0x0
+#define MX7D_PAD_EPDC_GDRL__LCD_DATA19 0x009C 0x030C 0x0684 0x7 0x1
+#define MX7D_PAD_EPDC_GDSP__EPDC_GDSP 0x00A0 0x0310 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_GDSP__FLEXTIMER2_CH3 0x00A0 0x0310 0x05B8 0x1 0x0
+#define MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC 0x00A0 0x0310 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_GDSP__ENET2_TX_ER 0x00A0 0x0310 0x0000 0x3 0x0
+#define MX7D_PAD_EPDC_GDSP__EIM_ADDR21 0x00A0 0x0310 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_GDSP__GPIO2_IO27 0x00A0 0x0310 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_GDSP__LCD_BUSY 0x00A0 0x0310 0x0634 0x6 0x1
+#define MX7D_PAD_EPDC_GDSP__LCD_DATA17 0x00A0 0x0310 0x067C 0x7 0x1
+#define MX7D_PAD_EPDC_BDR0__EPDC_BDR0 0x00A4 0x0314 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_BDR0__ENET2_TX_CLK 0x00A4 0x0314 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_BDR0__CCM_ENET_REF_CLK2 0x00A4 0x0314 0x0570 0x3 0x1
+#define MX7D_PAD_EPDC_BDR0__EIM_ADDR22 0x00A4 0x0314 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_BDR0__GPIO2_IO28 0x00A4 0x0314 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_BDR0__LCD_CS 0x00A4 0x0314 0x0000 0x6 0x0
+#define MX7D_PAD_EPDC_BDR0__LCD_DATA7 0x00A4 0x0314 0x0654 0x7 0x1
+#define MX7D_PAD_EPDC_BDR1__EPDC_BDR1 0x00A8 0x0318 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_BDR1__EPDC_SDCLKN 0x00A8 0x0318 0x0000 0x1 0x0
+#define MX7D_PAD_EPDC_BDR1__ENET2_RX_CLK 0x00A8 0x0318 0x0578 0x2 0x1
+#define MX7D_PAD_EPDC_BDR1__EIM_AD8 0x00A8 0x0318 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_BDR1__GPIO2_IO29 0x00A8 0x0318 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_BDR1__LCD_ENABLE 0x00A8 0x0318 0x0000 0x6 0x0
+#define MX7D_PAD_EPDC_BDR1__LCD_DATA6 0x00A8 0x0318 0x0650 0x7 0x1
+#define MX7D_PAD_EPDC_PWR_COM__EPDC_PWR_COM 0x00AC 0x031C 0x0000 0x0 0x0
+#define MX7D_PAD_EPDC_PWR_COM__FLEXTIMER2_PHA 0x00AC 0x031C 0x05CC 0x1 0x0
+#define MX7D_PAD_EPDC_PWR_COM__ENET2_CRS 0x00AC 0x031C 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_PWR_COM__EIM_AD9 0x00AC 0x031C 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_PWR_COM__GPIO2_IO30 0x00AC 0x031C 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_PWR_COM__LCD_HSYNC 0x00AC 0x031C 0x0000 0x6 0x0
+#define MX7D_PAD_EPDC_PWR_COM__LCD_DATA11 0x00AC 0x031C 0x0664 0x7 0x1
+#define MX7D_PAD_EPDC_PWR_STAT__EPDC_PWR_STAT 0x00B0 0x0320 0x0580 0x0 0x0
+#define MX7D_PAD_EPDC_PWR_STAT__FLEXTIMER2_PHB 0x00B0 0x0320 0x05D0 0x1 0x0
+#define MX7D_PAD_EPDC_PWR_STAT__ENET2_COL 0x00B0 0x0320 0x0000 0x2 0x0
+#define MX7D_PAD_EPDC_PWR_STAT__EIM_EB_B1 0x00B0 0x0320 0x0000 0x4 0x0
+#define MX7D_PAD_EPDC_PWR_STAT__GPIO2_IO31 0x00B0 0x0320 0x0000 0x5 0x0
+#define MX7D_PAD_EPDC_PWR_STAT__LCD_VSYNC 0x00B0 0x0320 0x0698 0x6 0x1
+#define MX7D_PAD_EPDC_PWR_STAT__LCD_DATA12 0x00B0 0x0320 0x0668 0x7 0x1
+#define MX7D_PAD_LCD_CLK__LCD_CLK 0x00B4 0x0324 0x0000 0x0 0x0
+#define MX7D_PAD_LCD_CLK__ECSPI4_MISO 0x00B4 0x0324 0x0558 0x1 0x0
+#define MX7D_PAD_LCD_CLK__ENET1_1588_EVENT2_IN 0x00B4 0x0324 0x0000 0x2 0x0
+#define MX7D_PAD_LCD_CLK__CSI_DATA16 0x00B4 0x0324 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_CLK__UART2_DCE_RX 0x00B4 0x0324 0x06FC 0x4 0x0
+#define MX7D_PAD_LCD_CLK__UART2_DTE_TX 0x00B4 0x0324 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_CLK__GPIO3_IO0 0x00B4 0x0324 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_ENABLE__LCD_ENABLE 0x00B8 0x0328 0x0000 0x0 0x0
+#define MX7D_PAD_LCD_ENABLE__ECSPI4_MOSI 0x00B8 0x0328 0x055C 0x1 0x0
+#define MX7D_PAD_LCD_ENABLE__ENET1_1588_EVENT3_IN 0x00B8 0x0328 0x0000 0x2 0x0
+#define MX7D_PAD_LCD_ENABLE__CSI_DATA17 0x00B8 0x0328 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_ENABLE__UART2_DCE_TX 0x00B8 0x0328 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_ENABLE__UART2_DTE_RX 0x00B8 0x0328 0x06FC 0x4 0x1
+#define MX7D_PAD_LCD_ENABLE__GPIO3_IO1 0x00B8 0x0328 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_HSYNC__LCD_HSYNC 0x00BC 0x032C 0x0000 0x0 0x0
+#define MX7D_PAD_LCD_HSYNC__ECSPI4_SCLK 0x00BC 0x032C 0x0554 0x1 0x0
+#define MX7D_PAD_LCD_HSYNC__ENET2_1588_EVENT2_IN 0x00BC 0x032C 0x0000 0x2 0x0
+#define MX7D_PAD_LCD_HSYNC__CSI_DATA18 0x00BC 0x032C 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_HSYNC__UART2_DCE_RTS 0x00BC 0x032C 0x06F8 0x4 0x0
+#define MX7D_PAD_LCD_HSYNC__UART2_DTE_CTS 0x00BC 0x032C 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_HSYNC__GPIO3_IO2 0x00BC 0x032C 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_VSYNC__LCD_VSYNC 0x00C0 0x0330 0x0698 0x0 0x2
+#define MX7D_PAD_LCD_VSYNC__ECSPI4_SS0 0x00C0 0x0330 0x0560 0x1 0x0
+#define MX7D_PAD_LCD_VSYNC__ENET2_1588_EVENT3_IN 0x00C0 0x0330 0x0000 0x2 0x0
+#define MX7D_PAD_LCD_VSYNC__CSI_DATA19 0x00C0 0x0330 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_VSYNC__UART2_DCE_CTS 0x00C0 0x0330 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_VSYNC__UART2_DTE_RTS 0x00C0 0x0330 0x06F8 0x4 0x1
+#define MX7D_PAD_LCD_VSYNC__GPIO3_IO3 0x00C0 0x0330 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_RESET__LCD_RESET 0x00C4 0x0334 0x0000 0x0 0x0
+#define MX7D_PAD_LCD_RESET__GPT1_COMPARE1 0x00C4 0x0334 0x0000 0x1 0x0
+#define MX7D_PAD_LCD_RESET__ARM_PLATFORM_EVENTI 0x00C4 0x0334 0x0000 0x2 0x0
+#define MX7D_PAD_LCD_RESET__CSI_FIELD 0x00C4 0x0334 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_RESET__EIM_DTACK_B 0x00C4 0x0334 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_RESET__GPIO3_IO4 0x00C4 0x0334 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA00__LCD_DATA0 0x00C8 0x0338 0x0638 0x0 0x2
+#define MX7D_PAD_LCD_DATA00__GPT1_COMPARE2 0x00C8 0x0338 0x0000 0x1 0x0
+#define MX7D_PAD_LCD_DATA00__CSI_DATA20 0x00C8 0x0338 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA00__EIM_DATA0 0x00C8 0x0338 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA00__GPIO3_IO5 0x00C8 0x0338 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA00__SRC_BOOT_CFG0 0x00C8 0x0338 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA01__LCD_DATA1 0x00CC 0x033C 0x063C 0x0 0x2
+#define MX7D_PAD_LCD_DATA01__GPT1_COMPARE3 0x00CC 0x033C 0x0000 0x1 0x0
+#define MX7D_PAD_LCD_DATA01__CSI_DATA21 0x00CC 0x033C 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA01__EIM_DATA1 0x00CC 0x033C 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA01__GPIO3_IO6 0x00CC 0x033C 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA01__SRC_BOOT_CFG1 0x00CC 0x033C 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA02__LCD_DATA2 0x00D0 0x0340 0x0640 0x0 0x2
+#define MX7D_PAD_LCD_DATA02__GPT1_CLK 0x00D0 0x0340 0x0000 0x1 0x0
+#define MX7D_PAD_LCD_DATA02__CSI_DATA22 0x00D0 0x0340 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA02__EIM_DATA2 0x00D0 0x0340 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA02__GPIO3_IO7 0x00D0 0x0340 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA02__SRC_BOOT_CFG2 0x00D0 0x0340 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA03__LCD_DATA3 0x00D4 0x0344 0x0644 0x0 0x2
+#define MX7D_PAD_LCD_DATA03__GPT1_CAPTURE1 0x00D4 0x0344 0x0000 0x1 0x0
+#define MX7D_PAD_LCD_DATA03__CSI_DATA23 0x00D4 0x0344 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA03__EIM_DATA3 0x00D4 0x0344 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA03__GPIO3_IO8 0x00D4 0x0344 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA03__SRC_BOOT_CFG3 0x00D4 0x0344 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA04__LCD_DATA4 0x00D8 0x0348 0x0648 0x0 0x2
+#define MX7D_PAD_LCD_DATA04__GPT1_CAPTURE2 0x00D8 0x0348 0x0000 0x1 0x0
+#define MX7D_PAD_LCD_DATA04__CSI_VSYNC 0x00D8 0x0348 0x0520 0x3 0x0
+#define MX7D_PAD_LCD_DATA04__EIM_DATA4 0x00D8 0x0348 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA04__GPIO3_IO9 0x00D8 0x0348 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA04__SRC_BOOT_CFG4 0x00D8 0x0348 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA05__LCD_DATA5 0x00DC 0x034C 0x064C 0x0 0x2
+#define MX7D_PAD_LCD_DATA05__CSI_HSYNC 0x00DC 0x034C 0x0518 0x3 0x0
+#define MX7D_PAD_LCD_DATA05__EIM_DATA5 0x00DC 0x034C 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA05__GPIO3_IO10 0x00DC 0x034C 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA05__SRC_BOOT_CFG5 0x00DC 0x034C 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA06__LCD_DATA6 0x00E0 0x0350 0x0650 0x0 0x2
+#define MX7D_PAD_LCD_DATA06__CSI_PIXCLK 0x00E0 0x0350 0x051C 0x3 0x0
+#define MX7D_PAD_LCD_DATA06__EIM_DATA6 0x00E0 0x0350 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA06__GPIO3_IO11 0x00E0 0x0350 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA06__SRC_BOOT_CFG6 0x00E0 0x0350 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA07__LCD_DATA7 0x00E4 0x0354 0x0654 0x0 0x2
+#define MX7D_PAD_LCD_DATA07__CSI_MCLK 0x00E4 0x0354 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA07__EIM_DATA7 0x00E4 0x0354 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA07__GPIO3_IO12 0x00E4 0x0354 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA07__SRC_BOOT_CFG7 0x00E4 0x0354 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA08__LCD_DATA8 0x00E8 0x0358 0x0658 0x0 0x2
+#define MX7D_PAD_LCD_DATA08__CSI_DATA9 0x00E8 0x0358 0x0514 0x3 0x0
+#define MX7D_PAD_LCD_DATA08__EIM_DATA8 0x00E8 0x0358 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA08__GPIO3_IO13 0x00E8 0x0358 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA08__SRC_BOOT_CFG8 0x00E8 0x0358 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA09__LCD_DATA9 0x00EC 0x035C 0x065C 0x0 0x2
+#define MX7D_PAD_LCD_DATA09__CSI_DATA8 0x00EC 0x035C 0x0510 0x3 0x0
+#define MX7D_PAD_LCD_DATA09__EIM_DATA9 0x00EC 0x035C 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA09__GPIO3_IO14 0x00EC 0x035C 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA09__SRC_BOOT_CFG9 0x00EC 0x035C 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA10__LCD_DATA10 0x00F0 0x0360 0x0660 0x0 0x2
+#define MX7D_PAD_LCD_DATA10__CSI_DATA7 0x00F0 0x0360 0x050C 0x3 0x0
+#define MX7D_PAD_LCD_DATA10__EIM_DATA10 0x00F0 0x0360 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA10__GPIO3_IO15 0x00F0 0x0360 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA10__SRC_BOOT_CFG10 0x00F0 0x0360 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA11__LCD_DATA11 0x00F4 0x0364 0x0664 0x0 0x2
+#define MX7D_PAD_LCD_DATA11__CSI_DATA6 0x00F4 0x0364 0x0508 0x3 0x0
+#define MX7D_PAD_LCD_DATA11__EIM_DATA11 0x00F4 0x0364 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA11__GPIO3_IO16 0x00F4 0x0364 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA11__SRC_BOOT_CFG11 0x00F4 0x0364 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA12__LCD_DATA12 0x00F8 0x0368 0x0668 0x0 0x2
+#define MX7D_PAD_LCD_DATA12__CSI_DATA5 0x00F8 0x0368 0x0504 0x3 0x0
+#define MX7D_PAD_LCD_DATA12__EIM_DATA12 0x00F8 0x0368 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA12__GPIO3_IO17 0x00F8 0x0368 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA12__SRC_BOOT_CFG12 0x00F8 0x0368 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA13__LCD_DATA13 0x00FC 0x036C 0x066C 0x0 0x1
+#define MX7D_PAD_LCD_DATA13__CSI_DATA4 0x00FC 0x036C 0x0500 0x3 0x0
+#define MX7D_PAD_LCD_DATA13__EIM_DATA13 0x00FC 0x036C 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA13__GPIO3_IO18 0x00FC 0x036C 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA13__SRC_BOOT_CFG13 0x00FC 0x036C 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA14__LCD_DATA14 0x0100 0x0370 0x0670 0x0 0x1
+#define MX7D_PAD_LCD_DATA14__CSI_DATA3 0x0100 0x0370 0x04FC 0x3 0x0
+#define MX7D_PAD_LCD_DATA14__EIM_DATA14 0x0100 0x0370 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA14__GPIO3_IO19 0x0100 0x0370 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA14__SRC_BOOT_CFG14 0x0100 0x0370 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA15__LCD_DATA15 0x0104 0x0374 0x0674 0x0 0x1
+#define MX7D_PAD_LCD_DATA15__CSI_DATA2 0x0104 0x0374 0x04F8 0x3 0x0
+#define MX7D_PAD_LCD_DATA15__EIM_DATA15 0x0104 0x0374 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA15__GPIO3_IO20 0x0104 0x0374 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA15__SRC_BOOT_CFG15 0x0104 0x0374 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA16__LCD_DATA16 0x0108 0x0378 0x0678 0x0 0x2
+#define MX7D_PAD_LCD_DATA16__FLEXTIMER1_CH4 0x0108 0x0378 0x0594 0x1 0x0
+#define MX7D_PAD_LCD_DATA16__CSI_DATA1 0x0108 0x0378 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA16__EIM_CRE 0x0108 0x0378 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA16__GPIO3_IO21 0x0108 0x0378 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA16__SRC_BOOT_CFG16 0x0108 0x0378 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA17__LCD_DATA17 0x010C 0x037C 0x067C 0x0 0x2
+#define MX7D_PAD_LCD_DATA17__FLEXTIMER1_CH5 0x010C 0x037C 0x0598 0x1 0x0
+#define MX7D_PAD_LCD_DATA17__CSI_DATA0 0x010C 0x037C 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA17__EIM_ACLK_FREERUN 0x010C 0x037C 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA17__GPIO3_IO22 0x010C 0x037C 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA17__SRC_BOOT_CFG17 0x010C 0x037C 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA18__LCD_DATA18 0x0110 0x0380 0x0680 0x0 0x2
+#define MX7D_PAD_LCD_DATA18__FLEXTIMER1_CH6 0x0110 0x0380 0x059C 0x1 0x0
+#define MX7D_PAD_LCD_DATA18__ARM_PLATFORM_EVENTO 0x0110 0x0380 0x0000 0x2 0x0
+#define MX7D_PAD_LCD_DATA18__CSI_DATA15 0x0110 0x0380 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA18__EIM_CS2_B 0x0110 0x0380 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA18__GPIO3_IO23 0x0110 0x0380 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA18__SRC_BOOT_CFG18 0x0110 0x0380 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA19__EIM_CS3_B 0x0114 0x0384 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA19__GPIO3_IO24 0x0114 0x0384 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA19__SRC_BOOT_CFG19 0x0114 0x0384 0x0000 0x6 0x0
+#define MX7D_PAD_LCD_DATA19__LCD_DATA19 0x0114 0x0384 0x0684 0x0 0x2
+#define MX7D_PAD_LCD_DATA19__FLEXTIMER1_CH7 0x0114 0x0384 0x05A0 0x1 0x0
+#define MX7D_PAD_LCD_DATA19__CSI_DATA14 0x0114 0x0384 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA20__EIM_ADDR23 0x0118 0x0388 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA20__GPIO3_IO25 0x0118 0x0388 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA20__I2C3_SCL 0x0118 0x0388 0x05E4 0x6 0x1
+#define MX7D_PAD_LCD_DATA20__LCD_DATA20 0x0118 0x0388 0x0688 0x0 0x2
+#define MX7D_PAD_LCD_DATA20__FLEXTIMER2_CH4 0x0118 0x0388 0x05BC 0x1 0x0
+#define MX7D_PAD_LCD_DATA20__ENET1_1588_EVENT2_OUT 0x0118 0x0388 0x0000 0x2 0x0
+#define MX7D_PAD_LCD_DATA20__CSI_DATA13 0x0118 0x0388 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA21__LCD_DATA21 0x011C 0x038C 0x068C 0x0 0x2
+#define MX7D_PAD_LCD_DATA21__FLEXTIMER2_CH5 0x011C 0x038C 0x05C0 0x1 0x0
+#define MX7D_PAD_LCD_DATA21__ENET1_1588_EVENT3_OUT 0x011C 0x038C 0x0000 0x2 0x0
+#define MX7D_PAD_LCD_DATA21__CSI_DATA12 0x011C 0x038C 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA21__EIM_ADDR24 0x011C 0x038C 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA21__GPIO3_IO26 0x011C 0x038C 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA21__I2C3_SDA 0x011C 0x038C 0x05E8 0x6 0x1
+#define MX7D_PAD_LCD_DATA22__LCD_DATA22 0x0120 0x0390 0x0690 0x0 0x2
+#define MX7D_PAD_LCD_DATA22__FLEXTIMER2_CH6 0x0120 0x0390 0x05C4 0x1 0x0
+#define MX7D_PAD_LCD_DATA22__ENET2_1588_EVENT2_OUT 0x0120 0x0390 0x0000 0x2 0x0
+#define MX7D_PAD_LCD_DATA22__CSI_DATA11 0x0120 0x0390 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA22__EIM_ADDR25 0x0120 0x0390 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA22__GPIO3_IO27 0x0120 0x0390 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA22__I2C4_SCL 0x0120 0x0390 0x05EC 0x6 0x1
+#define MX7D_PAD_LCD_DATA23__LCD_DATA23 0x0124 0x0394 0x0694 0x0 0x2
+#define MX7D_PAD_LCD_DATA23__FLEXTIMER2_CH7 0x0124 0x0394 0x05C8 0x1 0x0
+#define MX7D_PAD_LCD_DATA23__ENET2_1588_EVENT3_OUT 0x0124 0x0394 0x0000 0x2 0x0
+#define MX7D_PAD_LCD_DATA23__CSI_DATA10 0x0124 0x0394 0x0000 0x3 0x0
+#define MX7D_PAD_LCD_DATA23__EIM_ADDR26 0x0124 0x0394 0x0000 0x4 0x0
+#define MX7D_PAD_LCD_DATA23__GPIO3_IO28 0x0124 0x0394 0x0000 0x5 0x0
+#define MX7D_PAD_LCD_DATA23__I2C4_SDA 0x0124 0x0394 0x05F0 0x6 0x1
+#define MX7D_PAD_UART1_RX_DATA__UART1_DCE_RX 0x0128 0x0398 0x0000 0x0 0x0
+#define MX7D_PAD_UART1_RX_DATA__UART1_DTE_TX 0x0128 0x0398 0x0000 0x0 0x0
+#define MX7D_PAD_UART1_RX_DATA__I2C1_SCL 0x0128 0x0398 0x05D4 0x1 0x0
+#define MX7D_PAD_UART1_RX_DATA__CCM_PMIC_READY 0x0128 0x0398 0x0000 0x2 0x0
+#define MX7D_PAD_UART1_RX_DATA__ECSPI1_SS1 0x0128 0x0398 0x0000 0x3 0x0
+#define MX7D_PAD_UART1_RX_DATA__ENET2_1588_EVENT0_IN 0x0128 0x0398 0x0000 0x4 0x0
+#define MX7D_PAD_UART1_RX_DATA__GPIO4_IO0 0x0128 0x0398 0x0000 0x5 0x0
+#define MX7D_PAD_UART1_RX_DATA__ENET1_MDIO 0x0128 0x0398 0x0000 0x6 0x0
+#define MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x012C 0x039C 0x0000 0x0 0x0
+#define MX7D_PAD_UART1_TX_DATA__UART1_DTE_RX 0x012C 0x039C 0x06F4 0x0 0x1
+#define MX7D_PAD_UART1_TX_DATA__I2C1_SDA 0x012C 0x039C 0x05D8 0x1 0x0
+#define MX7D_PAD_UART1_TX_DATA__SAI3_MCLK 0x012C 0x039C 0x0000 0x2 0x0
+#define MX7D_PAD_UART1_TX_DATA__ECSPI1_SS2 0x012C 0x039C 0x0000 0x3 0x0
+#define MX7D_PAD_UART1_TX_DATA__ENET2_1588_EVENT0_OUT 0x012C 0x039C 0x0000 0x4 0x0
+#define MX7D_PAD_UART1_TX_DATA__GPIO4_IO1 0x012C 0x039C 0x0000 0x5 0x0
+#define MX7D_PAD_UART1_TX_DATA__ENET1_MDC 0x012C 0x039C 0x0000 0x6 0x0
+#define MX7D_PAD_UART2_RX_DATA__UART2_DCE_RX 0x0130 0x03A0 0x0000 0x0 0x0
+#define MX7D_PAD_UART2_RX_DATA__UART2_DTE_TX 0x0130 0x03A0 0x0000 0x0 0x0
+#define MX7D_PAD_UART2_RX_DATA__I2C2_SCL 0x0130 0x03A0 0x05DC 0x1 0x0
+#define MX7D_PAD_UART2_RX_DATA__SAI3_RX_BCLK 0x0130 0x03A0 0x0000 0x2 0x0
+#define MX7D_PAD_UART2_RX_DATA__ECSPI1_SS3 0x0130 0x03A0 0x0000 0x3 0x0
+#define MX7D_PAD_UART2_RX_DATA__ENET2_1588_EVENT1_IN 0x0130 0x03A0 0x0000 0x4 0x0
+#define MX7D_PAD_UART2_RX_DATA__GPIO4_IO2 0x0130 0x03A0 0x0000 0x5 0x0
+#define MX7D_PAD_UART2_RX_DATA__ENET2_MDIO 0x0130 0x03A0 0x0000 0x6 0x0
+#define MX7D_PAD_UART2_TX_DATA__UART2_DCE_TX 0x0134 0x03A4 0x0000 0x0 0x0
+#define MX7D_PAD_UART2_TX_DATA__UART2_DTE_RX 0x0134 0x03A4 0x0000 0x0 0x0
+#define MX7D_PAD_UART2_TX_DATA__I2C2_SDA 0x0134 0x03A4 0x05E0 0x1 0x0
+#define MX7D_PAD_UART2_TX_DATA__SAI3_RX_DATA0 0x0134 0x03A4 0x06C8 0x2 0x0
+#define MX7D_PAD_UART2_TX_DATA__ECSPI1_RDY 0x0134 0x03A4 0x0000 0x3 0x0
+#define MX7D_PAD_UART2_TX_DATA__ENET2_1588_EVENT1_OUT 0x0134 0x03A4 0x0000 0x4 0x0
+#define MX7D_PAD_UART2_TX_DATA__GPIO4_IO3 0x0134 0x03A4 0x0000 0x5 0x0
+#define MX7D_PAD_UART2_TX_DATA__ENET2_MDC 0x0134 0x03A4 0x0000 0x6 0x0
+#define MX7D_PAD_UART3_RX_DATA__UART3_DCE_RX 0x0138 0x03A8 0x0704 0x0 0x2
+#define MX7D_PAD_UART3_RX_DATA__UART3_DTE_TX 0x0138 0x03A8 0x0000 0x0 0x0
+#define MX7D_PAD_UART3_RX_DATA__USB_OTG1_OC 0x0138 0x03A8 0x072C 0x1 0x0
+#define MX7D_PAD_UART3_RX_DATA__SAI3_RX_SYNC 0x0138 0x03A8 0x06CC 0x2 0x0
+#define MX7D_PAD_UART3_RX_DATA__ECSPI1_MISO 0x0138 0x03A8 0x0528 0x3 0x0
+#define MX7D_PAD_UART3_RX_DATA__ENET1_1588_EVENT0_IN 0x0138 0x03A8 0x0000 0x4 0x0
+#define MX7D_PAD_UART3_RX_DATA__GPIO4_IO4 0x0138 0x03A8 0x0000 0x5 0x0
+#define MX7D_PAD_UART3_RX_DATA__SD1_LCTL 0x0138 0x03A8 0x0000 0x6 0x0
+#define MX7D_PAD_UART3_TX_DATA__UART3_DCE_TX 0x013C 0x03AC 0x0000 0x0 0x0
+#define MX7D_PAD_UART3_TX_DATA__UART3_DTE_RX 0x013C 0x03AC 0x0704 0x0 0x3
+#define MX7D_PAD_UART3_TX_DATA__USB_OTG1_PWR 0x013C 0x03AC 0x0000 0x1 0x0
+#define MX7D_PAD_UART3_TX_DATA__SAI3_TX_BCLK 0x013C 0x03AC 0x06D0 0x2 0x0
+#define MX7D_PAD_UART3_TX_DATA__ECSPI1_MOSI 0x013C 0x03AC 0x052C 0x3 0x0
+#define MX7D_PAD_UART3_TX_DATA__ENET1_1588_EVENT0_OUT 0x013C 0x03AC 0x0000 0x4 0x0
+#define MX7D_PAD_UART3_TX_DATA__GPIO4_IO5 0x013C 0x03AC 0x0000 0x5 0x0
+#define MX7D_PAD_UART3_TX_DATA__SD2_LCTL 0x013C 0x03AC 0x0000 0x6 0x0
+#define MX7D_PAD_UART3_RTS_B__UART3_DCE_RTS 0x0140 0x03B0 0x0000 0x0 0x0
+#define MX7D_PAD_UART3_RTS_B__UART3_DTE_CTS 0x0140 0x03B0 0x0000 0x0 0x0
+#define MX7D_PAD_UART3_RTS_B__USB_OTG2_OC 0x0140 0x03B0 0x0728 0x1 0x0
+#define MX7D_PAD_UART3_RTS_B__SAI3_TX_DATA0 0x0140 0x03B0 0x0000 0x2 0x0
+#define MX7D_PAD_UART3_RTS_B__ECSPI1_SCLK 0x0140 0x03B0 0x0000 0x3 0x0
+#define MX7D_PAD_UART3_RTS_B__ENET1_1588_EVENT1_IN 0x0140 0x03B0 0x0000 0x4 0x0
+#define MX7D_PAD_UART3_RTS_B__GPIO4_IO6 0x0140 0x03B0 0x0000 0x5 0x0
+#define MX7D_PAD_UART3_RTS_B__SD3_LCTL 0x0140 0x03B0 0x0000 0x6 0x0
+#define MX7D_PAD_UART3_CTS_B__UART3_DCE_CTS 0x0144 0x03B4 0x0000 0x0 0x0
+#define MX7D_PAD_UART3_CTS_B__UART3_DTE_RTS 0x0144 0x03B4 0x0700 0x0 0x3
+#define MX7D_PAD_UART3_CTS_B__USB_OTG2_PWR 0x0144 0x03B4 0x0000 0x1 0x0
+#define MX7D_PAD_UART3_CTS_B__SAI3_TX_SYNC 0x0144 0x03B4 0x06D4 0x2 0x0
+#define MX7D_PAD_UART3_CTS_B__ECSPI1_SS0 0x0144 0x03B4 0x0530 0x3 0x0
+#define MX7D_PAD_UART3_CTS_B__ENET1_1588_EVENT1_OUT 0x0144 0x03B4 0x0000 0x4 0x0
+#define MX7D_PAD_UART3_CTS_B__GPIO4_IO7 0x0144 0x03B4 0x0000 0x5 0x0
+#define MX7D_PAD_UART3_CTS_B__SD1_VSELECT 0x0144 0x03B4 0x0000 0x6 0x0
+#define MX7D_PAD_I2C1_SCL__I2C1_SCL 0x0148 0x03B8 0x05D4 0x0 0x1
+#define MX7D_PAD_I2C1_SCL__UART4_DCE_CTS 0x0148 0x03B8 0x0000 0x1 0x0
+#define MX7D_PAD_I2C1_SCL__UART4_DTE_RTS 0x0148 0x03B8 0x0708 0x1 0x0
+#define MX7D_PAD_I2C1_SCL__FLEXCAN1_RX 0x0148 0x03B8 0x04DC 0x2 0x1
+#define MX7D_PAD_I2C1_SCL__ECSPI3_MISO 0x0148 0x03B8 0x0548 0x3 0x0
+#define MX7D_PAD_I2C1_SCL__GPIO4_IO8 0x0148 0x03B8 0x0000 0x5 0x0
+#define MX7D_PAD_I2C1_SCL__SD2_VSELECT 0x0148 0x03B8 0x0000 0x6 0x0
+#define MX7D_PAD_I2C1_SDA__I2C1_SDA 0x014C 0x03BC 0x05D8 0x0 0x1
+#define MX7D_PAD_I2C1_SDA__UART4_DCE_RTS 0x014C 0x03BC 0x0708 0x1 0x1
+#define MX7D_PAD_I2C1_SDA__UART4_DTE_CTS 0x014C 0x03BC 0x0000 0x1 0x0
+#define MX7D_PAD_I2C1_SDA__FLEXCAN1_TX 0x014C 0x03BC 0x0000 0x2 0x0
+#define MX7D_PAD_I2C1_SDA__ECSPI3_MOSI 0x014C 0x03BC 0x054C 0x3 0x0
+#define MX7D_PAD_I2C1_SDA__CCM_ENET_REF_CLK1 0x014C 0x03BC 0x0564 0x4 0x1
+#define MX7D_PAD_I2C1_SDA__GPIO4_IO9 0x014C 0x03BC 0x0000 0x5 0x0
+#define MX7D_PAD_I2C1_SDA__SD3_VSELECT 0x014C 0x03BC 0x0000 0x6 0x0
+#define MX7D_PAD_I2C2_SCL__I2C2_SCL 0x0150 0x03C0 0x05DC 0x0 0x1
+#define MX7D_PAD_I2C2_SCL__UART4_DCE_RX 0x0150 0x03C0 0x070C 0x1 0x0
+#define MX7D_PAD_I2C2_SCL__UART4_DTE_TX 0x0150 0x03C0 0x0000 0x1 0x0
+#define MX7D_PAD_I2C2_SCL__WDOG3_WDOG_B 0x0150 0x03C0 0x0000 0x2 0x0
+#define MX7D_PAD_I2C2_SCL__ECSPI3_SCLK 0x0150 0x03C0 0x0544 0x3 0x0
+#define MX7D_PAD_I2C2_SCL__CCM_ENET_REF_CLK2 0x0150 0x03C0 0x0570 0x4 0x2
+#define MX7D_PAD_I2C2_SCL__GPIO4_IO10 0x0150 0x03C0 0x0000 0x5 0x0
+#define MX7D_PAD_I2C2_SCL__SD3_CD_B 0x0150 0x03C0 0x0738 0x6 0x1
+#define MX7D_PAD_I2C2_SDA__I2C2_SDA 0x0154 0x03C4 0x05E0 0x0 0x1
+#define MX7D_PAD_I2C2_SDA__UART4_DCE_TX 0x0154 0x03C4 0x0000 0x1 0x0
+#define MX7D_PAD_I2C2_SDA__UART4_DTE_RX 0x0154 0x03C4 0x070C 0x1 0x1
+#define MX7D_PAD_I2C2_SDA__WDOG3_WDOG_RST_B_DEB 0x0154 0x03C4 0x0000 0x2 0x0
+#define MX7D_PAD_I2C2_SDA__ECSPI3_SS0 0x0154 0x03C4 0x0550 0x3 0x0
+#define MX7D_PAD_I2C2_SDA__CCM_ENET_REF_CLK3 0x0154 0x03C4 0x0000 0x4 0x0
+#define MX7D_PAD_I2C2_SDA__GPIO4_IO11 0x0154 0x03C4 0x0000 0x5 0x0
+#define MX7D_PAD_I2C2_SDA__SD3_WP 0x0154 0x03C4 0x073C 0x6 0x1
+#define MX7D_PAD_I2C3_SCL__I2C3_SCL 0x0158 0x03C8 0x05E4 0x0 0x2
+#define MX7D_PAD_I2C3_SCL__UART5_DCE_CTS 0x0158 0x03C8 0x0000 0x1 0x0
+#define MX7D_PAD_I2C3_SCL__UART5_DTE_RTS 0x0158 0x03C8 0x0710 0x1 0x0
+#define MX7D_PAD_I2C3_SCL__FLEXCAN2_RX 0x0158 0x03C8 0x04E0 0x2 0x1
+#define MX7D_PAD_I2C3_SCL__CSI_VSYNC 0x0158 0x03C8 0x0520 0x3 0x1
+#define MX7D_PAD_I2C3_SCL__SDMA_EXT_EVENT0 0x0158 0x03C8 0x06D8 0x4 0x1
+#define MX7D_PAD_I2C3_SCL__GPIO4_IO12 0x0158 0x03C8 0x0000 0x5 0x0
+#define MX7D_PAD_I2C3_SCL__EPDC_BDR0 0x0158 0x03C8 0x0000 0x6 0x0
+#define MX7D_PAD_I2C3_SDA__I2C3_SDA 0x015C 0x03CC 0x05E8 0x0 0x2
+#define MX7D_PAD_I2C3_SDA__UART5_DCE_RTS 0x015C 0x03CC 0x0710 0x1 0x1
+#define MX7D_PAD_I2C3_SDA__UART5_DTE_CTS 0x015C 0x03CC 0x0000 0x1 0x0
+#define MX7D_PAD_I2C3_SDA__FLEXCAN2_TX 0x015C 0x03CC 0x0000 0x2 0x0
+#define MX7D_PAD_I2C3_SDA__CSI_HSYNC 0x015C 0x03CC 0x0518 0x3 0x1
+#define MX7D_PAD_I2C3_SDA__SDMA_EXT_EVENT1 0x015C 0x03CC 0x06DC 0x4 0x1
+#define MX7D_PAD_I2C3_SDA__GPIO4_IO13 0x015C 0x03CC 0x0000 0x5 0x0
+#define MX7D_PAD_I2C3_SDA__EPDC_BDR1 0x015C 0x03CC 0x0000 0x6 0x0
+#define MX7D_PAD_I2C4_SCL__I2C4_SCL 0x0160 0x03D0 0x05EC 0x0 0x2
+#define MX7D_PAD_I2C4_SCL__UART5_DCE_RX 0x0160 0x03D0 0x0714 0x1 0x0
+#define MX7D_PAD_I2C4_SCL__UART5_DTE_TX 0x0160 0x03D0 0x0000 0x1 0x0
+#define MX7D_PAD_I2C4_SCL__WDOG4_WDOG_B 0x0160 0x03D0 0x0000 0x2 0x0
+#define MX7D_PAD_I2C4_SCL__CSI_PIXCLK 0x0160 0x03D0 0x051C 0x3 0x1
+#define MX7D_PAD_I2C4_SCL__USB_OTG1_ID 0x0160 0x03D0 0x0734 0x4 0x1
+#define MX7D_PAD_I2C4_SCL__GPIO4_IO14 0x0160 0x03D0 0x0000 0x5 0x0
+#define MX7D_PAD_I2C4_SCL__EPDC_VCOM0 0x0160 0x03D0 0x0000 0x6 0x0
+#define MX7D_PAD_I2C4_SDA__I2C4_SDA 0x0164 0x03D4 0x05F0 0x0 0x2
+#define MX7D_PAD_I2C4_SDA__UART5_DCE_TX 0x0164 0x03D4 0x0000 0x1 0x0
+#define MX7D_PAD_I2C4_SDA__UART5_DTE_RX 0x0164 0x03D4 0x0714 0x1 0x1
+#define MX7D_PAD_I2C4_SDA__WDOG4_WDOG_RST_B_DEB 0x0164 0x03D4 0x0000 0x2 0x0
+#define MX7D_PAD_I2C4_SDA__CSI_MCLK 0x0164 0x03D4 0x0000 0x3 0x0
+#define MX7D_PAD_I2C4_SDA__USB_OTG2_ID 0x0164 0x03D4 0x0730 0x4 0x1
+#define MX7D_PAD_I2C4_SDA__GPIO4_IO15 0x0164 0x03D4 0x0000 0x5 0x0
+#define MX7D_PAD_I2C4_SDA__EPDC_VCOM1 0x0164 0x03D4 0x0000 0x6 0x0
+#define MX7D_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x0168 0x03D8 0x0524 0x0 0x1
+#define MX7D_PAD_ECSPI1_SCLK__UART6_DCE_RX 0x0168 0x03D8 0x071C 0x1 0x2
+#define MX7D_PAD_ECSPI1_SCLK__UART6_DTE_TX 0x0168 0x03D8 0x0000 0x1 0x0
+#define MX7D_PAD_ECSPI1_SCLK__SD2_DATA4 0x0168 0x03D8 0x0000 0x2 0x0
+#define MX7D_PAD_ECSPI1_SCLK__CSI_DATA2 0x0168 0x03D8 0x04F8 0x3 0x1
+#define MX7D_PAD_ECSPI1_SCLK__GPIO4_IO16 0x0168 0x03D8 0x0000 0x5 0x0
+#define MX7D_PAD_ECSPI1_SCLK__EPDC_PWR_COM 0x0168 0x03D8 0x0000 0x6 0x0
+#define MX7D_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x016C 0x03DC 0x052C 0x0 0x1
+#define MX7D_PAD_ECSPI1_MOSI__UART6_DCE_TX 0x016C 0x03DC 0x0000 0x1 0x0
+#define MX7D_PAD_ECSPI1_MOSI__UART6_DTE_RX 0x016C 0x03DC 0x071C 0x1 0x3
+#define MX7D_PAD_ECSPI1_MOSI__SD2_DATA5 0x016C 0x03DC 0x0000 0x2 0x0
+#define MX7D_PAD_ECSPI1_MOSI__CSI_DATA3 0x016C 0x03DC 0x04FC 0x3 0x1
+#define MX7D_PAD_ECSPI1_MOSI__GPIO4_IO17 0x016C 0x03DC 0x0000 0x5 0x0
+#define MX7D_PAD_ECSPI1_MOSI__EPDC_PWR_STAT 0x016C 0x03DC 0x0580 0x6 0x1
+#define MX7D_PAD_ECSPI1_MISO__ECSPI1_MISO 0x0170 0x03E0 0x0528 0x0 0x1
+#define MX7D_PAD_ECSPI1_MISO__UART6_DCE_RTS 0x0170 0x03E0 0x0718 0x1 0x2
+#define MX7D_PAD_ECSPI1_MISO__UART6_DTE_CTS 0x0170 0x03E0 0x0000 0x1 0x0
+#define MX7D_PAD_ECSPI1_MISO__SD2_DATA6 0x0170 0x03E0 0x0000 0x2 0x0
+#define MX7D_PAD_ECSPI1_MISO__CSI_DATA4 0x0170 0x03E0 0x0500 0x3 0x1
+#define MX7D_PAD_ECSPI1_MISO__GPIO4_IO18 0x0170 0x03E0 0x0000 0x5 0x0
+#define MX7D_PAD_ECSPI1_MISO__EPDC_PWR_IRQ 0x0170 0x03E0 0x057C 0x6 0x0
+#define MX7D_PAD_ECSPI1_SS0__ECSPI1_SS0 0x0174 0x03E4 0x0530 0x0 0x1
+#define MX7D_PAD_ECSPI1_SS0__UART6_DCE_CTS 0x0174 0x03E4 0x0000 0x1 0x0
+#define MX7D_PAD_ECSPI1_SS0__UART6_DTE_RTS 0x0174 0x03E4 0x0718 0x1 0x3
+#define MX7D_PAD_ECSPI1_SS0__SD2_DATA7 0x0174 0x03E4 0x0000 0x2 0x0
+#define MX7D_PAD_ECSPI1_SS0__CSI_DATA5 0x0174 0x03E4 0x0504 0x3 0x1
+#define MX7D_PAD_ECSPI1_SS0__GPIO4_IO19 0x0174 0x03E4 0x0000 0x5 0x0
+#define MX7D_PAD_ECSPI1_SS0__EPDC_PWR_CTRL3 0x0174 0x03E4 0x0000 0x6 0x0
+#define MX7D_PAD_ECSPI2_SCLK__ECSPI2_SCLK 0x0178 0x03E8 0x0534 0x0 0x0
+#define MX7D_PAD_ECSPI2_SCLK__UART7_DCE_RX 0x0178 0x03E8 0x0724 0x1 0x2
+#define MX7D_PAD_ECSPI2_SCLK__UART7_DTE_TX 0x0178 0x03E8 0x0000 0x1 0x0
+#define MX7D_PAD_ECSPI2_SCLK__SD1_DATA4 0x0178 0x03E8 0x0000 0x2 0x0
+#define MX7D_PAD_ECSPI2_SCLK__CSI_DATA6 0x0178 0x03E8 0x0508 0x3 0x1
+#define MX7D_PAD_ECSPI2_SCLK__LCD_DATA13 0x0178 0x03E8 0x066C 0x4 0x2
+#define MX7D_PAD_ECSPI2_SCLK__GPIO4_IO20 0x0178 0x03E8 0x0000 0x5 0x0
+#define MX7D_PAD_ECSPI2_SCLK__EPDC_PWR_CTRL0 0x0178 0x03E8 0x0000 0x6 0x0
+#define MX7D_PAD_ECSPI2_MOSI__ECSPI2_MOSI 0x017C 0x03EC 0x053C 0x0 0x0
+#define MX7D_PAD_ECSPI2_MOSI__UART7_DCE_TX 0x017C 0x03EC 0x0000 0x1 0x0
+#define MX7D_PAD_ECSPI2_MOSI__UART7_DTE_RX 0x017C 0x03EC 0x0724 0x1 0x3
+#define MX7D_PAD_ECSPI2_MOSI__SD1_DATA5 0x017C 0x03EC 0x0000 0x2 0x0
+#define MX7D_PAD_ECSPI2_MOSI__CSI_DATA7 0x017C 0x03EC 0x050C 0x3 0x1
+#define MX7D_PAD_ECSPI2_MOSI__LCD_DATA14 0x017C 0x03EC 0x0670 0x4 0x2
+#define MX7D_PAD_ECSPI2_MOSI__GPIO4_IO21 0x017C 0x03EC 0x0000 0x5 0x0
+#define MX7D_PAD_ECSPI2_MOSI__EPDC_PWR_CTRL1 0x017C 0x03EC 0x0000 0x6 0x0
+#define MX7D_PAD_ECSPI2_MISO__GPIO4_IO22 0x0180 0x03F0 0x0000 0x5 0x0
+#define MX7D_PAD_ECSPI2_MISO__EPDC_PWR_CTRL2 0x0180 0x03F0 0x0000 0x6 0x0
+#define MX7D_PAD_ECSPI2_MISO__ECSPI2_MISO 0x0180 0x03F0 0x0538 0x0 0x0
+#define MX7D_PAD_ECSPI2_MISO__UART7_DCE_RTS 0x0180 0x03F0 0x0720 0x1 0x2
+#define MX7D_PAD_ECSPI2_MISO__UART7_DTE_CTS 0x0180 0x03F0 0x0000 0x1 0x0
+#define MX7D_PAD_ECSPI2_MISO__SD1_DATA6 0x0180 0x03F0 0x0000 0x2 0x0
+#define MX7D_PAD_ECSPI2_MISO__CSI_DATA8 0x0180 0x03F0 0x0510 0x3 0x1
+#define MX7D_PAD_ECSPI2_MISO__LCD_DATA15 0x0180 0x03F0 0x0674 0x4 0x2
+#define MX7D_PAD_ECSPI2_SS0__ECSPI2_SS0 0x0184 0x03F4 0x0540 0x0 0x0
+#define MX7D_PAD_ECSPI2_SS0__UART7_DCE_CTS 0x0184 0x03F4 0x0000 0x1 0x0
+#define MX7D_PAD_ECSPI2_SS0__UART7_DTE_RTS 0x0184 0x03F4 0x0720 0x1 0x3
+#define MX7D_PAD_ECSPI2_SS0__SD1_DATA7 0x0184 0x03F4 0x0000 0x2 0x0
+#define MX7D_PAD_ECSPI2_SS0__CSI_DATA9 0x0184 0x03F4 0x0514 0x3 0x1
+#define MX7D_PAD_ECSPI2_SS0__LCD_RESET 0x0184 0x03F4 0x0000 0x4 0x0
+#define MX7D_PAD_ECSPI2_SS0__GPIO4_IO23 0x0184 0x03F4 0x0000 0x5 0x0
+#define MX7D_PAD_ECSPI2_SS0__EPDC_PWR_WAKE 0x0184 0x03F4 0x0000 0x6 0x0
+#define MX7D_PAD_SD1_CD_B__SD1_CD_B 0x0188 0x03F8 0x0000 0x0 0x0
+#define MX7D_PAD_SD1_CD_B__UART6_DCE_RX 0x0188 0x03F8 0x071C 0x2 0x4
+#define MX7D_PAD_SD1_CD_B__UART6_DTE_TX 0x0188 0x03F8 0x0000 0x2 0x0
+#define MX7D_PAD_SD1_CD_B__ECSPI4_MISO 0x0188 0x03F8 0x0558 0x3 0x1
+#define MX7D_PAD_SD1_CD_B__FLEXTIMER1_CH0 0x0188 0x03F8 0x0584 0x4 0x1
+#define MX7D_PAD_SD1_CD_B__GPIO5_IO0 0x0188 0x03F8 0x0000 0x5 0x0
+#define MX7D_PAD_SD1_CD_B__CCM_CLKO1 0x0188 0x03F8 0x0000 0x6 0x0
+#define MX7D_PAD_SD1_WP__SD1_WP 0x018C 0x03FC 0x0000 0x0 0x0
+#define MX7D_PAD_SD1_WP__UART6_DCE_TX 0x018C 0x03FC 0x0000 0x2 0x0
+#define MX7D_PAD_SD1_WP__UART6_DTE_RX 0x018C 0x03FC 0x071C 0x2 0x5
+#define MX7D_PAD_SD1_WP__ECSPI4_MOSI 0x018C 0x03FC 0x055C 0x3 0x1
+#define MX7D_PAD_SD1_WP__FLEXTIMER1_CH1 0x018C 0x03FC 0x0588 0x4 0x1
+#define MX7D_PAD_SD1_WP__GPIO5_IO1 0x018C 0x03FC 0x0000 0x5 0x0
+#define MX7D_PAD_SD1_WP__CCM_CLKO2 0x018C 0x03FC 0x0000 0x6 0x0
+#define MX7D_PAD_SD1_RESET_B__SD1_RESET_B 0x0190 0x0400 0x0000 0x0 0x0
+#define MX7D_PAD_SD1_RESET_B__SAI3_MCLK 0x0190 0x0400 0x0000 0x1 0x0
+#define MX7D_PAD_SD1_RESET_B__UART6_DCE_RTS 0x0190 0x0400 0x0718 0x2 0x4
+#define MX7D_PAD_SD1_RESET_B__UART6_DTE_CTS 0x0190 0x0400 0x0000 0x2 0x0
+#define MX7D_PAD_SD1_RESET_B__ECSPI4_SCLK 0x0190 0x0400 0x0554 0x3 0x1
+#define MX7D_PAD_SD1_RESET_B__FLEXTIMER1_CH2 0x0190 0x0400 0x058C 0x4 0x1
+#define MX7D_PAD_SD1_RESET_B__GPIO5_IO2 0x0190 0x0400 0x0000 0x5 0x0
+#define MX7D_PAD_SD1_CLK__SD1_CLK 0x0194 0x0404 0x0000 0x0 0x0
+#define MX7D_PAD_SD1_CLK__SAI3_RX_SYNC 0x0194 0x0404 0x06CC 0x1 0x1
+#define MX7D_PAD_SD1_CLK__UART6_DCE_CTS 0x0194 0x0404 0x0000 0x2 0x0
+#define MX7D_PAD_SD1_CLK__UART6_DTE_RTS 0x0194 0x0404 0x0718 0x2 0x5
+#define MX7D_PAD_SD1_CLK__ECSPI4_SS0 0x0194 0x0404 0x0560 0x3 0x1
+#define MX7D_PAD_SD1_CLK__FLEXTIMER1_CH3 0x0194 0x0404 0x0590 0x4 0x1
+#define MX7D_PAD_SD1_CLK__GPIO5_IO3 0x0194 0x0404 0x0000 0x5 0x0
+#define MX7D_PAD_SD1_CMD__SD1_CMD 0x0198 0x0408 0x0000 0x0 0x0
+#define MX7D_PAD_SD1_CMD__SAI3_RX_BCLK 0x0198 0x0408 0x06C4 0x1 0x1
+#define MX7D_PAD_SD1_CMD__ECSPI4_SS1 0x0198 0x0408 0x0000 0x3 0x0
+#define MX7D_PAD_SD1_CMD__FLEXTIMER2_CH0 0x0198 0x0408 0x05AC 0x4 0x1
+#define MX7D_PAD_SD1_CMD__GPIO5_IO4 0x0198 0x0408 0x0000 0x5 0x0
+#define MX7D_PAD_SD1_DATA0__SD1_DATA0 0x019C 0x040C 0x0000 0x0 0x0
+#define MX7D_PAD_SD1_DATA0__SAI3_RX_DATA0 0x019C 0x040C 0x06C8 0x1 0x1
+#define MX7D_PAD_SD1_DATA0__UART7_DCE_RX 0x019C 0x040C 0x0724 0x2 0x4
+#define MX7D_PAD_SD1_DATA0__UART7_DTE_TX 0x019C 0x040C 0x0000 0x2 0x0
+#define MX7D_PAD_SD1_DATA0__ECSPI4_SS2 0x019C 0x040C 0x0000 0x3 0x0
+#define MX7D_PAD_SD1_DATA0__FLEXTIMER2_CH1 0x019C 0x040C 0x05B0 0x4 0x1
+#define MX7D_PAD_SD1_DATA0__GPIO5_IO5 0x019C 0x040C 0x0000 0x5 0x0
+#define MX7D_PAD_SD1_DATA0__CCM_EXT_CLK1 0x019C 0x040C 0x04E4 0x6 0x1
+#define MX7D_PAD_SD1_DATA1__SD1_DATA1 0x01A0 0x0410 0x0000 0x0 0x0
+#define MX7D_PAD_SD1_DATA1__SAI3_TX_BCLK 0x01A0 0x0410 0x06D0 0x1 0x1
+#define MX7D_PAD_SD1_DATA1__UART7_DCE_TX 0x01A0 0x0410 0x0000 0x2 0x0
+#define MX7D_PAD_SD1_DATA1__UART7_DTE_RX 0x01A0 0x0410 0x0724 0x2 0x5
+#define MX7D_PAD_SD1_DATA1__ECSPI4_SS3 0x01A0 0x0410 0x0000 0x3 0x0
+#define MX7D_PAD_SD1_DATA1__FLEXTIMER2_CH2 0x01A0 0x0410 0x05B4 0x4 0x1
+#define MX7D_PAD_SD1_DATA1__GPIO5_IO6 0x01A0 0x0410 0x0000 0x5 0x0
+#define MX7D_PAD_SD1_DATA1__CCM_EXT_CLK2 0x01A0 0x0410 0x04E8 0x6 0x1
+#define MX7D_PAD_SD1_DATA2__SD1_DATA2 0x01A4 0x0414 0x0000 0x0 0x0
+#define MX7D_PAD_SD1_DATA2__SAI3_TX_SYNC 0x01A4 0x0414 0x06D4 0x1 0x1
+#define MX7D_PAD_SD1_DATA2__UART7_DCE_CTS 0x01A4 0x0414 0x0000 0x2 0x0
+#define MX7D_PAD_SD1_DATA2__UART7_DTE_RTS 0x01A4 0x0414 0x0720 0x2 0x4
+#define MX7D_PAD_SD1_DATA2__ECSPI4_RDY 0x01A4 0x0414 0x0000 0x3 0x0
+#define MX7D_PAD_SD1_DATA2__FLEXTIMER2_CH3 0x01A4 0x0414 0x05B8 0x4 0x1
+#define MX7D_PAD_SD1_DATA2__GPIO5_IO7 0x01A4 0x0414 0x0000 0x5 0x0
+#define MX7D_PAD_SD1_DATA2__CCM_EXT_CLK3 0x01A4 0x0414 0x04EC 0x6 0x1
+#define MX7D_PAD_SD1_DATA3__SD1_DATA3 0x01A8 0x0418 0x0000 0x0 0x0
+#define MX7D_PAD_SD1_DATA3__SAI3_TX_DATA0 0x01A8 0x0418 0x0000 0x1 0x0
+#define MX7D_PAD_SD1_DATA3__UART7_DCE_RTS 0x01A8 0x0418 0x0720 0x2 0x5
+#define MX7D_PAD_SD1_DATA3__UART7_DTE_CTS 0x01A8 0x0418 0x0000 0x2 0x0
+#define MX7D_PAD_SD1_DATA3__ECSPI3_SS1 0x01A8 0x0418 0x0000 0x3 0x0
+#define MX7D_PAD_SD1_DATA3__FLEXTIMER1_PHA 0x01A8 0x0418 0x05A4 0x4 0x1
+#define MX7D_PAD_SD1_DATA3__GPIO5_IO8 0x01A8 0x0418 0x0000 0x5 0x0
+#define MX7D_PAD_SD1_DATA3__CCM_EXT_CLK4 0x01A8 0x0418 0x04F0 0x6 0x1
+#define MX7D_PAD_SD2_CD_B__SD2_CD_B 0x01AC 0x041C 0x0000 0x0 0x0
+#define MX7D_PAD_SD2_CD_B__ENET1_MDIO 0x01AC 0x041C 0x0568 0x1 0x2
+#define MX7D_PAD_SD2_CD_B__ENET2_MDIO 0x01AC 0x041C 0x0574 0x2 0x2
+#define MX7D_PAD_SD2_CD_B__ECSPI3_SS2 0x01AC 0x041C 0x0000 0x3 0x0
+#define MX7D_PAD_SD2_CD_B__FLEXTIMER1_PHB 0x01AC 0x041C 0x05A8 0x4 0x1
+#define MX7D_PAD_SD2_CD_B__GPIO5_IO9 0x01AC 0x041C 0x0000 0x5 0x0
+#define MX7D_PAD_SD2_CD_B__SDMA_EXT_EVENT0 0x01AC 0x041C 0x06D8 0x6 0x2
+#define MX7D_PAD_SD2_WP__SD2_WP 0x01B0 0x0420 0x0000 0x0 0x0
+#define MX7D_PAD_SD2_WP__ENET1_MDC 0x01B0 0x0420 0x0000 0x1 0x0
+#define MX7D_PAD_SD2_WP__ENET2_MDC 0x01B0 0x0420 0x0000 0x2 0x0
+#define MX7D_PAD_SD2_WP__ECSPI3_SS3 0x01B0 0x0420 0x0000 0x3 0x0
+#define MX7D_PAD_SD2_WP__USB_OTG1_ID 0x01B0 0x0420 0x0734 0x4 0x2
+#define MX7D_PAD_SD2_WP__GPIO5_IO10 0x01B0 0x0420 0x0000 0x5 0x0
+#define MX7D_PAD_SD2_WP__SDMA_EXT_EVENT1 0x01B0 0x0420 0x06DC 0x6 0x2
+#define MX7D_PAD_SD2_RESET_B__SD2_RESET_B 0x01B4 0x0424 0x0000 0x0 0x0
+#define MX7D_PAD_SD2_RESET_B__SAI2_MCLK 0x01B4 0x0424 0x0000 0x1 0x0
+#define MX7D_PAD_SD2_RESET_B__SD2_RESET 0x01B4 0x0424 0x0000 0x2 0x0
+#define MX7D_PAD_SD2_RESET_B__ECSPI3_RDY 0x01B4 0x0424 0x0000 0x3 0x0
+#define MX7D_PAD_SD2_RESET_B__USB_OTG2_ID 0x01B4 0x0424 0x0730 0x4 0x2
+#define MX7D_PAD_SD2_RESET_B__GPIO5_IO11 0x01B4 0x0424 0x0000 0x5 0x0
+#define MX7D_PAD_SD2_CLK__SD2_CLK 0x01B8 0x0428 0x0000 0x0 0x0
+#define MX7D_PAD_SD2_CLK__SAI2_RX_SYNC 0x01B8 0x0428 0x06B8 0x1 0x0
+#define MX7D_PAD_SD2_CLK__MQS_RIGHT 0x01B8 0x0428 0x0000 0x2 0x0
+#define MX7D_PAD_SD2_CLK__GPT4_CLK 0x01B8 0x0428 0x0000 0x3 0x0
+#define MX7D_PAD_SD2_CLK__GPIO5_IO12 0x01B8 0x0428 0x0000 0x5 0x0
+#define MX7D_PAD_SD2_CMD__SD2_CMD 0x01BC 0x042C 0x0000 0x0 0x0
+#define MX7D_PAD_SD2_CMD__SAI2_RX_BCLK 0x01BC 0x042C 0x06B0 0x1 0x0
+#define MX7D_PAD_SD2_CMD__MQS_LEFT 0x01BC 0x042C 0x0000 0x2 0x0
+#define MX7D_PAD_SD2_CMD__GPT4_CAPTURE1 0x01BC 0x042C 0x0000 0x3 0x0
+#define MX7D_PAD_SD2_CMD__SIM2_PORT1_TRXD 0x01BC 0x042C 0x06EC 0x4 0x1
+#define MX7D_PAD_SD2_CMD__GPIO5_IO13 0x01BC 0x042C 0x0000 0x5 0x0
+#define MX7D_PAD_SD2_DATA0__SD2_DATA0 0x01C0 0x0430 0x0000 0x0 0x0
+#define MX7D_PAD_SD2_DATA0__SAI2_RX_DATA0 0x01C0 0x0430 0x06B4 0x1 0x0
+#define MX7D_PAD_SD2_DATA0__UART4_DCE_RX 0x01C0 0x0430 0x070C 0x2 0x2
+#define MX7D_PAD_SD2_DATA0__UART4_DTE_TX 0x01C0 0x0430 0x0000 0x2 0x0
+#define MX7D_PAD_SD2_DATA0__GPT4_CAPTURE2 0x01C0 0x0430 0x0000 0x3 0x0
+#define MX7D_PAD_SD2_DATA0__SIM2_PORT1_CLK 0x01C0 0x0430 0x0000 0x4 0x0
+#define MX7D_PAD_SD2_DATA0__GPIO5_IO14 0x01C0 0x0430 0x0000 0x5 0x0
+#define MX7D_PAD_SD2_DATA1__SD2_DATA1 0x01C4 0x0434 0x0000 0x0 0x0
+#define MX7D_PAD_SD2_DATA1__SAI2_TX_BCLK 0x01C4 0x0434 0x06BC 0x1 0x0
+#define MX7D_PAD_SD2_DATA1__UART4_DCE_TX 0x01C4 0x0434 0x0000 0x2 0x0
+#define MX7D_PAD_SD2_DATA1__UART4_DTE_RX 0x01C4 0x0434 0x070C 0x2 0x3
+#define MX7D_PAD_SD2_DATA1__GPT4_COMPARE1 0x01C4 0x0434 0x0000 0x3 0x0
+#define MX7D_PAD_SD2_DATA1__SIM2_PORT1_RST_B 0x01C4 0x0434 0x0000 0x4 0x0
+#define MX7D_PAD_SD2_DATA1__GPIO5_IO15 0x01C4 0x0434 0x0000 0x5 0x0
+#define MX7D_PAD_SD2_DATA2__SD2_DATA2 0x01C8 0x0438 0x0000 0x0 0x0
+#define MX7D_PAD_SD2_DATA2__SAI2_TX_SYNC 0x01C8 0x0438 0x06C0 0x1 0x0
+#define MX7D_PAD_SD2_DATA2__UART4_DCE_CTS 0x01C8 0x0438 0x0000 0x2 0x0
+#define MX7D_PAD_SD2_DATA2__UART4_DTE_RTS 0x01C8 0x0438 0x0708 0x2 0x2
+#define MX7D_PAD_SD2_DATA2__GPT4_COMPARE2 0x01C8 0x0438 0x0000 0x3 0x0
+#define MX7D_PAD_SD2_DATA2__SIM2_PORT1_SVEN 0x01C8 0x0438 0x0000 0x4 0x0
+#define MX7D_PAD_SD2_DATA2__GPIO5_IO16 0x01C8 0x0438 0x0000 0x5 0x0
+#define MX7D_PAD_SD2_DATA3__SD2_DATA3 0x01CC 0x043C 0x0000 0x0 0x0
+#define MX7D_PAD_SD2_DATA3__SAI2_TX_DATA0 0x01CC 0x043C 0x0000 0x1 0x0
+#define MX7D_PAD_SD2_DATA3__UART4_DCE_RTS 0x01CC 0x043C 0x0708 0x2 0x3
+#define MX7D_PAD_SD2_DATA3__UART4_DTE_CTS 0x01CC 0x043C 0x0000 0x2 0x0
+#define MX7D_PAD_SD2_DATA3__GPT4_COMPARE3 0x01CC 0x043C 0x0000 0x3 0x0
+#define MX7D_PAD_SD2_DATA3__SIM2_PORT1_PD 0x01CC 0x043C 0x06E8 0x4 0x1
+#define MX7D_PAD_SD2_DATA3__GPIO5_IO17 0x01CC 0x043C 0x0000 0x5 0x0
+#define MX7D_PAD_SD3_CLK__SD3_CLK 0x01D0 0x0440 0x0000 0x0 0x0
+#define MX7D_PAD_SD3_CLK__NAND_CLE 0x01D0 0x0440 0x0000 0x1 0x0
+#define MX7D_PAD_SD3_CLK__ECSPI4_MISO 0x01D0 0x0440 0x0558 0x2 0x2
+#define MX7D_PAD_SD3_CLK__SAI3_RX_SYNC 0x01D0 0x0440 0x06CC 0x3 0x2
+#define MX7D_PAD_SD3_CLK__GPT3_CLK 0x01D0 0x0440 0x0000 0x4 0x0
+#define MX7D_PAD_SD3_CLK__GPIO6_IO0 0x01D0 0x0440 0x0000 0x5 0x0
+#define MX7D_PAD_SD3_CMD__SD3_CMD 0x01D4 0x0444 0x0000 0x0 0x0
+#define MX7D_PAD_SD3_CMD__NAND_ALE 0x01D4 0x0444 0x0000 0x1 0x0
+#define MX7D_PAD_SD3_CMD__ECSPI4_MOSI 0x01D4 0x0444 0x055C 0x2 0x2
+#define MX7D_PAD_SD3_CMD__SAI3_RX_BCLK 0x01D4 0x0444 0x06C4 0x3 0x2
+#define MX7D_PAD_SD3_CMD__GPT3_CAPTURE1 0x01D4 0x0444 0x0000 0x4 0x0
+#define MX7D_PAD_SD3_CMD__GPIO6_IO1 0x01D4 0x0444 0x0000 0x5 0x0
+#define MX7D_PAD_SD3_DATA0__SD3_DATA0 0x01D8 0x0448 0x0000 0x0 0x0
+#define MX7D_PAD_SD3_DATA0__NAND_DATA00 0x01D8 0x0448 0x0000 0x1 0x0
+#define MX7D_PAD_SD3_DATA0__ECSPI4_SS0 0x01D8 0x0448 0x0560 0x2 0x2
+#define MX7D_PAD_SD3_DATA0__SAI3_RX_DATA0 0x01D8 0x0448 0x06C8 0x3 0x2
+#define MX7D_PAD_SD3_DATA0__GPT3_CAPTURE2 0x01D8 0x0448 0x0000 0x4 0x0
+#define MX7D_PAD_SD3_DATA0__GPIO6_IO2 0x01D8 0x0448 0x0000 0x5 0x0
+#define MX7D_PAD_SD3_DATA1__SD3_DATA1 0x01DC 0x044C 0x0000 0x0 0x0
+#define MX7D_PAD_SD3_DATA1__NAND_DATA01 0x01DC 0x044C 0x0000 0x1 0x0
+#define MX7D_PAD_SD3_DATA1__ECSPI4_SCLK 0x01DC 0x044C 0x0554 0x2 0x2
+#define MX7D_PAD_SD3_DATA1__SAI3_TX_BCLK 0x01DC 0x044C 0x06D0 0x3 0x2
+#define MX7D_PAD_SD3_DATA1__GPT3_COMPARE1 0x01DC 0x044C 0x0000 0x4 0x0
+#define MX7D_PAD_SD3_DATA1__GPIO6_IO3 0x01DC 0x044C 0x0000 0x5 0x0
+#define MX7D_PAD_SD3_DATA2__SD3_DATA2 0x01E0 0x0450 0x0000 0x0 0x0
+#define MX7D_PAD_SD3_DATA2__NAND_DATA02 0x01E0 0x0450 0x0000 0x1 0x0
+#define MX7D_PAD_SD3_DATA2__I2C3_SDA 0x01E0 0x0450 0x05E8 0x2 0x3
+#define MX7D_PAD_SD3_DATA2__SAI3_TX_SYNC 0x01E0 0x0450 0x06D4 0x3 0x2
+#define MX7D_PAD_SD3_DATA2__GPT3_COMPARE2 0x01E0 0x0450 0x0000 0x4 0x0
+#define MX7D_PAD_SD3_DATA2__GPIO6_IO4 0x01E0 0x0450 0x0000 0x5 0x0
+#define MX7D_PAD_SD3_DATA3__SD3_DATA3 0x01E4 0x0454 0x0000 0x0 0x0
+#define MX7D_PAD_SD3_DATA3__NAND_DATA03 0x01E4 0x0454 0x0000 0x1 0x0
+#define MX7D_PAD_SD3_DATA3__I2C3_SCL 0x01E4 0x0454 0x05E4 0x2 0x3
+#define MX7D_PAD_SD3_DATA3__SAI3_TX_DATA0 0x01E4 0x0454 0x0000 0x3 0x0
+#define MX7D_PAD_SD3_DATA3__GPT3_COMPARE3 0x01E4 0x0454 0x0000 0x4 0x0
+#define MX7D_PAD_SD3_DATA3__GPIO6_IO5 0x01E4 0x0454 0x0000 0x5 0x0
+#define MX7D_PAD_SD3_DATA4__SD3_DATA4 0x01E8 0x0458 0x0000 0x0 0x0
+#define MX7D_PAD_SD3_DATA4__NAND_DATA04 0x01E8 0x0458 0x0000 0x1 0x0
+#define MX7D_PAD_SD3_DATA4__UART3_DCE_RX 0x01E8 0x0458 0x0704 0x3 0x4
+#define MX7D_PAD_SD3_DATA4__UART3_DTE_TX 0x01E8 0x0458 0x0000 0x3 0x0
+#define MX7D_PAD_SD3_DATA4__FLEXCAN2_RX 0x01E8 0x0458 0x04E0 0x4 0x2
+#define MX7D_PAD_SD3_DATA4__GPIO6_IO6 0x01E8 0x0458 0x0000 0x5 0x0
+#define MX7D_PAD_SD3_DATA5__SD3_DATA5 0x01EC 0x045C 0x0000 0x0 0x0
+#define MX7D_PAD_SD3_DATA5__NAND_DATA05 0x01EC 0x045C 0x0000 0x1 0x0
+#define MX7D_PAD_SD3_DATA5__UART3_DCE_TX 0x01EC 0x045C 0x0000 0x3 0x0
+#define MX7D_PAD_SD3_DATA5__UART3_DTE_RX 0x01EC 0x045C 0x0704 0x3 0x5
+#define MX7D_PAD_SD3_DATA5__FLEXCAN1_TX 0x01EC 0x045C 0x0000 0x4 0x0
+#define MX7D_PAD_SD3_DATA5__GPIO6_IO7 0x01EC 0x045C 0x0000 0x5 0x0
+#define MX7D_PAD_SD3_DATA6__SD3_DATA6 0x01F0 0x0460 0x0000 0x0 0x0
+#define MX7D_PAD_SD3_DATA6__NAND_DATA06 0x01F0 0x0460 0x0000 0x1 0x0
+#define MX7D_PAD_SD3_DATA6__SD3_WP 0x01F0 0x0460 0x073C 0x2 0x2
+#define MX7D_PAD_SD3_DATA6__UART3_DCE_RTS 0x01F0 0x0460 0x0700 0x3 0x4
+#define MX7D_PAD_SD3_DATA6__UART3_DTE_CTS 0x01F0 0x0460 0x0000 0x3 0x0
+#define MX7D_PAD_SD3_DATA6__FLEXCAN2_TX 0x01F0 0x0460 0x0000 0x4 0x0
+#define MX7D_PAD_SD3_DATA6__GPIO6_IO8 0x01F0 0x0460 0x0000 0x5 0x0
+#define MX7D_PAD_SD3_DATA7__SD3_DATA7 0x01F4 0x0464 0x0000 0x0 0x0
+#define MX7D_PAD_SD3_DATA7__NAND_DATA07 0x01F4 0x0464 0x0000 0x1 0x0
+#define MX7D_PAD_SD3_DATA7__SD3_CD_B 0x01F4 0x0464 0x0738 0x2 0x2
+#define MX7D_PAD_SD3_DATA7__UART3_DCE_CTS 0x01F4 0x0464 0x0000 0x3 0x0
+#define MX7D_PAD_SD3_DATA7__UART3_DTE_RTS 0x01F4 0x0464 0x0700 0x3 0x5
+#define MX7D_PAD_SD3_DATA7__FLEXCAN1_RX 0x01F4 0x0464 0x04DC 0x4 0x2
+#define MX7D_PAD_SD3_DATA7__GPIO6_IO9 0x01F4 0x0464 0x0000 0x5 0x0
+#define MX7D_PAD_SD3_STROBE__SD3_STROBE 0x01F8 0x0468 0x0000 0x0 0x0
+#define MX7D_PAD_SD3_STROBE__NAND_RE_B 0x01F8 0x0468 0x0000 0x1 0x0
+#define MX7D_PAD_SD3_STROBE__GPIO6_IO10 0x01F8 0x0468 0x0000 0x5 0x0
+#define MX7D_PAD_SD3_RESET_B__SD3_RESET_B 0x01FC 0x046C 0x0000 0x0 0x0
+#define MX7D_PAD_SD3_RESET_B__NAND_WE_B 0x01FC 0x046C 0x0000 0x1 0x0
+#define MX7D_PAD_SD3_RESET_B__SD3_RESET 0x01FC 0x046C 0x0000 0x2 0x0
+#define MX7D_PAD_SD3_RESET_B__SAI3_MCLK 0x01FC 0x046C 0x0000 0x3 0x0
+#define MX7D_PAD_SD3_RESET_B__GPIO6_IO11 0x01FC 0x046C 0x0000 0x5 0x0
+#define MX7D_PAD_SAI1_RX_DATA__SAI1_RX_DATA0 0x0200 0x0470 0x06A0 0x0 0x0
+#define MX7D_PAD_SAI1_RX_DATA__NAND_CE1_B 0x0200 0x0470 0x0000 0x1 0x0
+#define MX7D_PAD_SAI1_RX_DATA__UART5_DCE_RX 0x0200 0x0470 0x0714 0x2 0x2
+#define MX7D_PAD_SAI1_RX_DATA__UART5_DTE_TX 0x0200 0x0470 0x0000 0x2 0x0
+#define MX7D_PAD_SAI1_RX_DATA__FLEXCAN1_RX 0x0200 0x0470 0x04DC 0x3 0x3
+#define MX7D_PAD_SAI1_RX_DATA__SIM1_PORT1_TRXD 0x0200 0x0470 0x06E4 0x4 0x1
+#define MX7D_PAD_SAI1_RX_DATA__GPIO6_IO12 0x0200 0x0470 0x0000 0x5 0x0
+#define MX7D_PAD_SAI1_RX_DATA__SRC_ANY_PU_RESET 0x0200 0x0470 0x0000 0x7 0x0
+#define MX7D_PAD_SAI1_TX_BCLK__SAI1_TX_BCLK 0x0204 0x0474 0x06A8 0x0 0x0
+#define MX7D_PAD_SAI1_TX_BCLK__NAND_CE0_B 0x0204 0x0474 0x0000 0x1 0x0
+#define MX7D_PAD_SAI1_TX_BCLK__UART5_DCE_TX 0x0204 0x0474 0x0000 0x2 0x0
+#define MX7D_PAD_SAI1_TX_BCLK__UART5_DTE_RX 0x0204 0x0474 0x0714 0x2 0x3
+#define MX7D_PAD_SAI1_TX_BCLK__FLEXCAN1_TX 0x0204 0x0474 0x0000 0x3 0x0
+#define MX7D_PAD_SAI1_TX_BCLK__SIM1_PORT1_CLK 0x0204 0x0474 0x0000 0x4 0x0
+#define MX7D_PAD_SAI1_TX_BCLK__GPIO6_IO13 0x0204 0x0474 0x0000 0x5 0x0
+#define MX7D_PAD_SAI1_TX_BCLK__SRC_EARLY_RESET 0x0204 0x0474 0x0000 0x7 0x0
+#define MX7D_PAD_SAI1_TX_SYNC__SAI1_TX_SYNC 0x0208 0x0478 0x06AC 0x0 0x0
+#define MX7D_PAD_SAI1_TX_SYNC__NAND_DQS 0x0208 0x0478 0x0000 0x1 0x0
+#define MX7D_PAD_SAI1_TX_SYNC__UART5_DCE_CTS 0x0208 0x0478 0x0000 0x2 0x0
+#define MX7D_PAD_SAI1_TX_SYNC__UART5_DTE_RTS 0x0208 0x0478 0x0710 0x2 0x2
+#define MX7D_PAD_SAI1_TX_SYNC__FLEXCAN2_RX 0x0208 0x0478 0x04E0 0x3 0x3
+#define MX7D_PAD_SAI1_TX_SYNC__SIM1_PORT1_RST_B 0x0208 0x0478 0x0000 0x4 0x0
+#define MX7D_PAD_SAI1_TX_SYNC__GPIO6_IO14 0x0208 0x0478 0x0000 0x5 0x0
+#define MX7D_PAD_SAI1_TX_SYNC__SRC_INT_BOOT 0x0208 0x0478 0x0000 0x7 0x0
+#define MX7D_PAD_SAI1_TX_DATA__SAI1_TX_DATA0 0x020C 0x047C 0x0000 0x0 0x0
+#define MX7D_PAD_SAI1_TX_DATA__NAND_READY_B 0x020C 0x047C 0x0000 0x1 0x0
+#define MX7D_PAD_SAI1_TX_DATA__UART5_DCE_RTS 0x020C 0x047C 0x0710 0x2 0x3
+#define MX7D_PAD_SAI1_TX_DATA__UART5_DTE_CTS 0x020C 0x047C 0x0000 0x2 0x0
+#define MX7D_PAD_SAI1_TX_DATA__FLEXCAN2_TX 0x020C 0x047C 0x0000 0x3 0x0
+#define MX7D_PAD_SAI1_TX_DATA__SIM1_PORT1_SVEN 0x020C 0x047C 0x0000 0x4 0x0
+#define MX7D_PAD_SAI1_TX_DATA__GPIO6_IO15 0x020C 0x047C 0x0000 0x5 0x0
+#define MX7D_PAD_SAI1_TX_DATA__SRC_SYSTEM_RESET 0x020C 0x047C 0x0000 0x7 0x0
+#define MX7D_PAD_SAI1_RX_SYNC__SAI1_RX_SYNC 0x0210 0x0480 0x06A4 0x0 0x0
+#define MX7D_PAD_SAI1_RX_SYNC__NAND_CE2_B 0x0210 0x0480 0x0000 0x1 0x0
+#define MX7D_PAD_SAI1_RX_SYNC__SAI2_RX_SYNC 0x0210 0x0480 0x06B8 0x2 0x1
+#define MX7D_PAD_SAI1_RX_SYNC__I2C4_SCL 0x0210 0x0480 0x05EC 0x3 0x3
+#define MX7D_PAD_SAI1_RX_SYNC__SIM1_PORT1_PD 0x0210 0x0480 0x06E0 0x4 0x1
+#define MX7D_PAD_SAI1_RX_SYNC__GPIO6_IO16 0x0210 0x0480 0x0000 0x5 0x0
+#define MX7D_PAD_SAI1_RX_SYNC__MQS_RIGHT 0x0210 0x0480 0x0000 0x6 0x0
+#define MX7D_PAD_SAI1_RX_SYNC__SRC_CA7_RESET_B0 0x0210 0x0480 0x0000 0x7 0x0
+#define MX7D_PAD_SAI1_RX_BCLK__SAI1_RX_BCLK 0x0214 0x0484 0x069C 0x0 0x0
+#define MX7D_PAD_SAI1_RX_BCLK__NAND_CE3_B 0x0214 0x0484 0x0000 0x1 0x0
+#define MX7D_PAD_SAI1_RX_BCLK__SAI2_RX_BCLK 0x0214 0x0484 0x06B0 0x2 0x1
+#define MX7D_PAD_SAI1_RX_BCLK__I2C4_SDA 0x0214 0x0484 0x05F0 0x3 0x3
+#define MX7D_PAD_SAI1_RX_BCLK__FLEXTIMER2_PHA 0x0214 0x0484 0x05CC 0x4 0x1
+#define MX7D_PAD_SAI1_RX_BCLK__GPIO6_IO17 0x0214 0x0484 0x0000 0x5 0x0
+#define MX7D_PAD_SAI1_RX_BCLK__MQS_LEFT 0x0214 0x0484 0x0000 0x6 0x0
+#define MX7D_PAD_SAI1_RX_BCLK__SRC_CA7_RESET_B1 0x0214 0x0484 0x0000 0x7 0x0
+#define MX7D_PAD_SAI1_MCLK__SAI1_MCLK 0x0218 0x0488 0x0000 0x0 0x0
+#define MX7D_PAD_SAI1_MCLK__NAND_WP_B 0x0218 0x0488 0x0000 0x1 0x0
+#define MX7D_PAD_SAI1_MCLK__SAI2_MCLK 0x0218 0x0488 0x0000 0x2 0x0
+#define MX7D_PAD_SAI1_MCLK__CCM_PMIC_READY 0x0218 0x0488 0x04F4 0x3 0x3
+#define MX7D_PAD_SAI1_MCLK__FLEXTIMER2_PHB 0x0218 0x0488 0x05D0 0x4 0x1
+#define MX7D_PAD_SAI1_MCLK__GPIO6_IO18 0x0218 0x0488 0x0000 0x5 0x0
+#define MX7D_PAD_SAI1_MCLK__SRC_TESTER_ACK 0x0218 0x0488 0x0000 0x7 0x0
+#define MX7D_PAD_SAI2_TX_SYNC__SAI2_TX_SYNC 0x021C 0x048C 0x06C0 0x0 0x1
+#define MX7D_PAD_SAI2_TX_SYNC__ECSPI3_MISO 0x021C 0x048C 0x0548 0x1 0x1
+#define MX7D_PAD_SAI2_TX_SYNC__UART4_DCE_RX 0x021C 0x048C 0x070C 0x2 0x4
+#define MX7D_PAD_SAI2_TX_SYNC__UART4_DTE_TX 0x021C 0x048C 0x0000 0x2 0x0
+#define MX7D_PAD_SAI2_TX_SYNC__UART1_DCE_CTS 0x021C 0x048C 0x0000 0x3 0x0
+#define MX7D_PAD_SAI2_TX_SYNC__UART1_DTE_RTS 0x021C 0x048C 0x06F0 0x3 0x0
+#define MX7D_PAD_SAI2_TX_SYNC__FLEXTIMER2_CH4 0x021C 0x048C 0x05BC 0x4 0x1
+#define MX7D_PAD_SAI2_TX_SYNC__GPIO6_IO19 0x021C 0x048C 0x0000 0x5 0x0
+#define MX7D_PAD_SAI2_TX_BCLK__SAI2_TX_BCLK 0x0220 0x0490 0x06BC 0x0 0x1
+#define MX7D_PAD_SAI2_TX_BCLK__ECSPI3_MOSI 0x0220 0x0490 0x054C 0x1 0x1
+#define MX7D_PAD_SAI2_TX_BCLK__UART4_DCE_TX 0x0220 0x0490 0x0000 0x2 0x0
+#define MX7D_PAD_SAI2_TX_BCLK__UART4_DTE_RX 0x0220 0x0490 0x070C 0x2 0x5
+#define MX7D_PAD_SAI2_TX_BCLK__UART1_DCE_RTS 0x0220 0x0490 0x06F0 0x3 0x1
+#define MX7D_PAD_SAI2_TX_BCLK__UART1_DTE_CTS 0x0220 0x0490 0x0000 0x3 0x0
+#define MX7D_PAD_SAI2_TX_BCLK__FLEXTIMER2_CH5 0x0220 0x0490 0x05C0 0x4 0x1
+#define MX7D_PAD_SAI2_TX_BCLK__GPIO6_IO20 0x0220 0x0490 0x0000 0x5 0x0
+#define MX7D_PAD_SAI2_RX_DATA__SAI2_RX_DATA0 0x0224 0x0494 0x06B4 0x0 0x1
+#define MX7D_PAD_SAI2_RX_DATA__ECSPI3_SCLK 0x0224 0x0494 0x0544 0x1 0x1
+#define MX7D_PAD_SAI2_RX_DATA__UART4_DCE_CTS 0x0224 0x0494 0x0000 0x2 0x0
+#define MX7D_PAD_SAI2_RX_DATA__UART4_DTE_RTS 0x0224 0x0494 0x0708 0x2 0x4
+#define MX7D_PAD_SAI2_RX_DATA__UART2_DCE_CTS 0x0224 0x0494 0x0000 0x3 0x0
+#define MX7D_PAD_SAI2_RX_DATA__UART2_DTE_RTS 0x0224 0x0494 0x06F8 0x3 0x2
+#define MX7D_PAD_SAI2_RX_DATA__FLEXTIMER2_CH6 0x0224 0x0494 0x05C4 0x4 0x1
+#define MX7D_PAD_SAI2_RX_DATA__GPIO6_IO21 0x0224 0x0494 0x0000 0x5 0x0
+#define MX7D_PAD_SAI2_RX_DATA__KPP_COL7 0x0224 0x0494 0x0610 0x6 0x1
+#define MX7D_PAD_SAI2_TX_DATA__SAI2_TX_DATA0 0x0228 0x0498 0x0000 0x0 0x0
+#define MX7D_PAD_SAI2_TX_DATA__ECSPI3_SS0 0x0228 0x0498 0x0550 0x1 0x1
+#define MX7D_PAD_SAI2_TX_DATA__UART4_DCE_RTS 0x0228 0x0498 0x0708 0x2 0x5
+#define MX7D_PAD_SAI2_TX_DATA__UART4_DTE_CTS 0x0228 0x0498 0x0000 0x2 0x0
+#define MX7D_PAD_SAI2_TX_DATA__UART2_DCE_RTS 0x0228 0x0498 0x06F8 0x3 0x3
+#define MX7D_PAD_SAI2_TX_DATA__UART2_DTE_CTS 0x0228 0x0498 0x0000 0x3 0x0
+#define MX7D_PAD_SAI2_TX_DATA__FLEXTIMER2_CH7 0x0228 0x0498 0x05C8 0x4 0x1
+#define MX7D_PAD_SAI2_TX_DATA__GPIO6_IO22 0x0228 0x0498 0x0000 0x5 0x0
+#define MX7D_PAD_SAI2_TX_DATA__KPP_ROW7 0x0228 0x0498 0x0630 0x6 0x1
+#define MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0 0x022C 0x049C 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_RGMII_RD0__PWM1_OUT 0x022C 0x049C 0x0000 0x1 0x0
+#define MX7D_PAD_ENET1_RGMII_RD0__I2C3_SCL 0x022C 0x049C 0x05E4 0x2 0x4
+#define MX7D_PAD_ENET1_RGMII_RD0__UART1_DCE_CTS 0x022C 0x049C 0x0000 0x3 0x0
+#define MX7D_PAD_ENET1_RGMII_RD0__UART1_DTE_RTS 0x022C 0x049C 0x06F0 0x3 0x2
+#define MX7D_PAD_ENET1_RGMII_RD0__EPDC_VCOM0 0x022C 0x049C 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RGMII_RD0__GPIO7_IO0 0x022C 0x049C 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_RGMII_RD0__KPP_ROW3 0x022C 0x049C 0x0620 0x6 0x1
+#define MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1 0x0230 0x04A0 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_RGMII_RD1__PWM2_OUT 0x0230 0x04A0 0x0000 0x1 0x0
+#define MX7D_PAD_ENET1_RGMII_RD1__I2C3_SDA 0x0230 0x04A0 0x05E8 0x2 0x4
+#define MX7D_PAD_ENET1_RGMII_RD1__UART1_DCE_RTS 0x0230 0x04A0 0x06F0 0x3 0x3
+#define MX7D_PAD_ENET1_RGMII_RD1__UART1_DTE_CTS 0x0230 0x04A0 0x0000 0x3 0x0
+#define MX7D_PAD_ENET1_RGMII_RD1__EPDC_VCOM1 0x0230 0x04A0 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RGMII_RD1__GPIO7_IO1 0x0230 0x04A0 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_RGMII_RD1__KPP_COL3 0x0230 0x04A0 0x0600 0x6 0x1
+#define MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2 0x0234 0x04A4 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_RGMII_RD2__FLEXCAN1_RX 0x0234 0x04A4 0x04DC 0x1 0x4
+#define MX7D_PAD_ENET1_RGMII_RD2__ECSPI2_SCLK 0x0234 0x04A4 0x0534 0x2 0x1
+#define MX7D_PAD_ENET1_RGMII_RD2__UART1_DCE_RX 0x0234 0x04A4 0x06F4 0x3 0x2
+#define MX7D_PAD_ENET1_RGMII_RD2__UART1_DTE_TX 0x0234 0x04A4 0x0000 0x3 0x0
+#define MX7D_PAD_ENET1_RGMII_RD2__EPDC_SDCE4 0x0234 0x04A4 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RGMII_RD2__GPIO7_IO2 0x0234 0x04A4 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_RGMII_RD2__KPP_ROW2 0x0234 0x04A4 0x061C 0x6 0x1
+#define MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3 0x0238 0x04A8 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_RGMII_RD3__FLEXCAN1_TX 0x0238 0x04A8 0x0000 0x1 0x0
+#define MX7D_PAD_ENET1_RGMII_RD3__ECSPI2_MOSI 0x0238 0x04A8 0x053C 0x2 0x1
+#define MX7D_PAD_ENET1_RGMII_RD3__UART1_DCE_TX 0x0238 0x04A8 0x0000 0x3 0x0
+#define MX7D_PAD_ENET1_RGMII_RD3__UART1_DTE_RX 0x0238 0x04A8 0x06F4 0x3 0x3
+#define MX7D_PAD_ENET1_RGMII_RD3__EPDC_SDCE5 0x0238 0x04A8 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RGMII_RD3__GPIO7_IO3 0x0238 0x04A8 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_RGMII_RD3__KPP_COL2 0x0238 0x04A8 0x05FC 0x6 0x1
+#define MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x023C 0x04AC 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_RGMII_RX_CTL__ECSPI2_SS1 0x023C 0x04AC 0x0000 0x2 0x0
+#define MX7D_PAD_ENET1_RGMII_RX_CTL__EPDC_SDCE6 0x023C 0x04AC 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RGMII_RX_CTL__GPIO7_IO4 0x023C 0x04AC 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_RGMII_RX_CTL__KPP_ROW1 0x023C 0x04AC 0x0618 0x6 0x1
+#define MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC 0x0240 0x04B0 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_RGMII_RXC__ENET1_RX_ER 0x0240 0x04B0 0x0000 0x1 0x0
+#define MX7D_PAD_ENET1_RGMII_RXC__ECSPI2_SS2 0x0240 0x04B0 0x0000 0x2 0x0
+#define MX7D_PAD_ENET1_RGMII_RXC__EPDC_SDCE7 0x0240 0x04B0 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RGMII_RXC__GPIO7_IO5 0x0240 0x04B0 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_RGMII_RXC__KPP_COL1 0x0240 0x04B0 0x0000 0x6 0x0
+#define MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0 0x0244 0x04B4 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_RGMII_TD0__PWM3_OUT 0x0244 0x04B4 0x0000 0x1 0x0
+#define MX7D_PAD_ENET1_RGMII_TD0__ECSPI2_SS3 0x0244 0x04B4 0x0000 0x2 0x0
+#define MX7D_PAD_ENET1_RGMII_TD0__EPDC_SDCE8 0x0244 0x04B4 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RGMII_TD0__GPIO7_IO6 0x0244 0x04B4 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_RGMII_TD0__KPP_ROW0 0x0244 0x04B4 0x0614 0x6 0x1
+#define MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1 0x0248 0x04B8 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_RGMII_TD1__PWM4_OUT 0x0248 0x04B8 0x0000 0x1 0x0
+#define MX7D_PAD_ENET1_RGMII_TD1__ECSPI2_RDY 0x0248 0x04B8 0x0000 0x2 0x0
+#define MX7D_PAD_ENET1_RGMII_TD1__EPDC_SDCE9 0x0248 0x04B8 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RGMII_TD1__GPIO7_IO7 0x0248 0x04B8 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_RGMII_TD1__KPP_COL0 0x0248 0x04B8 0x05F4 0x6 0x1
+#define MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2 0x024C 0x04BC 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_RGMII_TD2__FLEXCAN2_RX 0x024C 0x04BC 0x04E0 0x1 0x4
+#define MX7D_PAD_ENET1_RGMII_TD2__ECSPI2_MISO 0x024C 0x04BC 0x0538 0x2 0x1
+#define MX7D_PAD_ENET1_RGMII_TD2__I2C4_SCL 0x024C 0x04BC 0x05EC 0x3 0x4
+#define MX7D_PAD_ENET1_RGMII_TD2__EPDC_SDOED 0x024C 0x04BC 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RGMII_TD2__GPIO7_IO8 0x024C 0x04BC 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3 0x0250 0x04C0 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_RGMII_TD3__FLEXCAN2_TX 0x0250 0x04C0 0x0000 0x1 0x0
+#define MX7D_PAD_ENET1_RGMII_TD3__ECSPI2_SS0 0x0250 0x04C0 0x0540 0x2 0x1
+#define MX7D_PAD_ENET1_RGMII_TD3__I2C4_SDA 0x0250 0x04C0 0x05F0 0x3 0x4
+#define MX7D_PAD_ENET1_RGMII_TD3__EPDC_SDOEZ 0x0250 0x04C0 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RGMII_TD3__GPIO7_IO9 0x0250 0x04C0 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_RGMII_TD3__CAAM_RNG_OSC_OBS 0x0250 0x04C0 0x0000 0x7 0x0
+#define MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x0254 0x04C4 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_RGMII_TX_CTL__SAI1_RX_SYNC 0x0254 0x04C4 0x0000 0x2 0x0
+#define MX7D_PAD_ENET1_RGMII_TX_CTL__GPT2_COMPARE1 0x0254 0x04C4 0x0000 0x3 0x0
+#define MX7D_PAD_ENET1_RGMII_TX_CTL__EPDC_PWR_CTRL2 0x0254 0x04C4 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RGMII_TX_CTL__GPIO7_IO10 0x0254 0x04C4 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC 0x0258 0x04C8 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_RGMII_TXC__ENET1_TX_ER 0x0258 0x04C8 0x0000 0x1 0x0
+#define MX7D_PAD_ENET1_RGMII_TXC__SAI1_RX_BCLK 0x0258 0x04C8 0x0000 0x2 0x0
+#define MX7D_PAD_ENET1_RGMII_TXC__GPT2_COMPARE2 0x0258 0x04C8 0x0000 0x3 0x0
+#define MX7D_PAD_ENET1_RGMII_TXC__EPDC_PWR_CTRL3 0x0258 0x04C8 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RGMII_TXC__GPIO7_IO11 0x0258 0x04C8 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_TX_CLK__ENET1_TX_CLK 0x025C 0x04CC 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_TX_CLK__CCM_ENET_REF_CLK1 0x025C 0x04CC 0x0564 0x1 0x2
+#define MX7D_PAD_ENET1_TX_CLK__SAI1_RX_DATA0 0x025C 0x04CC 0x06A0 0x2 0x1
+#define MX7D_PAD_ENET1_TX_CLK__GPT2_COMPARE3 0x025C 0x04CC 0x0000 0x3 0x0
+#define MX7D_PAD_ENET1_TX_CLK__EPDC_PWR_IRQ 0x025C 0x04CC 0x057C 0x4 0x1
+#define MX7D_PAD_ENET1_TX_CLK__GPIO7_IO12 0x025C 0x04CC 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_TX_CLK__CCM_EXT_CLK1 0x025C 0x04CC 0x04E4 0x6 0x2
+#define MX7D_PAD_ENET1_TX_CLK__CSU_ALARM_AUT0 0x025C 0x04CC 0x0000 0x7 0x0
+#define MX7D_PAD_ENET1_RX_CLK__ENET1_RX_CLK 0x0260 0x04D0 0x056C 0x0 0x0
+#define MX7D_PAD_ENET1_RX_CLK__WDOG2_WDOG_B 0x0260 0x04D0 0x0000 0x1 0x0
+#define MX7D_PAD_ENET1_RX_CLK__SAI1_TX_BCLK 0x0260 0x04D0 0x06A8 0x2 0x1
+#define MX7D_PAD_ENET1_RX_CLK__GPT2_CLK 0x0260 0x04D0 0x0000 0x3 0x0
+#define MX7D_PAD_ENET1_RX_CLK__EPDC_PWR_WAKE 0x0260 0x04D0 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_RX_CLK__GPIO7_IO13 0x0260 0x04D0 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_RX_CLK__CCM_EXT_CLK2 0x0260 0x04D0 0x04E8 0x6 0x2
+#define MX7D_PAD_ENET1_RX_CLK__CSU_ALARM_AUT1 0x0260 0x04D0 0x0000 0x7 0x0
+#define MX7D_PAD_ENET1_CRS__ENET1_CRS 0x0264 0x04D4 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_CRS__WDOG2_WDOG_RST_B_DEB 0x0264 0x04D4 0x0000 0x1 0x0
+#define MX7D_PAD_ENET1_CRS__SAI1_TX_SYNC 0x0264 0x04D4 0x06AC 0x2 0x1
+#define MX7D_PAD_ENET1_CRS__GPT2_CAPTURE1 0x0264 0x04D4 0x0000 0x3 0x0
+#define MX7D_PAD_ENET1_CRS__EPDC_PWR_CTRL0 0x0264 0x04D4 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_CRS__GPIO7_IO14 0x0264 0x04D4 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_CRS__CCM_EXT_CLK3 0x0264 0x04D4 0x04EC 0x6 0x2
+#define MX7D_PAD_ENET1_CRS__CSU_ALARM_AUT2 0x0264 0x04D4 0x0000 0x7 0x0
+#define MX7D_PAD_ENET1_COL__ENET1_COL 0x0268 0x04D8 0x0000 0x0 0x0
+#define MX7D_PAD_ENET1_COL__WDOG1_WDOG_ANY 0x0268 0x04D8 0x0000 0x1 0x0
+#define MX7D_PAD_ENET1_COL__SAI1_TX_DATA0 0x0268 0x04D8 0x0000 0x2 0x0
+#define MX7D_PAD_ENET1_COL__GPT2_CAPTURE2 0x0268 0x04D8 0x0000 0x3 0x0
+#define MX7D_PAD_ENET1_COL__EPDC_PWR_CTRL1 0x0268 0x04D8 0x0000 0x4 0x0
+#define MX7D_PAD_ENET1_COL__GPIO7_IO15 0x0268 0x04D8 0x0000 0x5 0x0
+#define MX7D_PAD_ENET1_COL__CCM_EXT_CLK4 0x0268 0x04D8 0x04F0 0x6 0x2
+#define MX7D_PAD_ENET1_COL__CSU_INT_DEB 0x0268 0x04D8 0x0000 0x7 0x0
+
+#endif /* __DTS_IMX7D_PINFUNC_H */
diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts
new file mode 100644
index 000000000000..4d1a4b977d84
--- /dev/null
+++ b/arch/arm/boot/dts/imx7d-sdb.dts
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, 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 <dt-bindings/input/input.h>
+#include "imx7d.dtsi"
+
+/ {
+ model = "Freescale i.MX7 SabreSD Board";
+ compatible = "fsl,imx7d-sdb", "fsl,imx7d";
+
+ memory {
+ reg = <0x80000000 0x80000000>;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg_usb_otg1_vbus: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "usb_otg1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_usb_otg2_vbus: regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "usb_otg2_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio4 7 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_can2_3v3: regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "can2-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio1 7 GPIO_ACTIVE_LOW>;
+ };
+
+ reg_vref_1v8: regulator@3 {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ regulator-name = "vref-1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ };
+};
+
+&cpu0 {
+ arm-supply = <&sw1a_reg>;
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ pmic: pfuze3000@08 {
+ 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;
+ };
+ };
+ };
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&i2c3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ status = "okay";
+};
+
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c4>;
+ status = "okay";
+
+ codec: wm8960@1a {
+ compatible = "wlf,wm8960";
+ reg = <0x1a>;
+ clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
+ clock-names = "mclk";
+ wlf,shared-lrclk;
+ };
+};
+
+&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";
+};
+
+&usdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ cd-gpios = <&gpio5 0 0>;
+ wp-gpios = <&gpio5 1 0>;
+ enable-sdio-wakeup;
+ keep-power-in-suspend;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hog>;
+
+ imx7d-sdb {
+ pinctrl_hog: hoggrp {
+ fsl,pins = <
+ MX7D_PAD_UART3_CTS_B__GPIO4_IO7 0x14
+ MX7D_PAD_ECSPI2_SS0__GPIO4_IO23 0x34 /* bt reg on */
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX7D_PAD_I2C1_SDA__I2C1_SDA 0x4000007f
+ MX7D_PAD_I2C1_SCL__I2C1_SCL 0x4000007f
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX7D_PAD_I2C2_SDA__I2C2_SDA 0x4000007f
+ MX7D_PAD_I2C2_SCL__I2C2_SCL 0x4000007f
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX7D_PAD_I2C3_SDA__I2C3_SDA 0x4000007f
+ MX7D_PAD_I2C3_SCL__I2C3_SCL 0x4000007f
+ >;
+ };
+
+ pinctrl_i2c4: i2c4grp {
+ fsl,pins = <
+ MX7D_PAD_SAI1_RX_BCLK__I2C4_SDA 0x4000007f
+ MX7D_PAD_SAI1_RX_SYNC__I2C4_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_uart5: uart5grp {
+ fsl,pins = <
+ MX7D_PAD_SAI1_TX_BCLK__UART5_DCE_TX 0x79
+ MX7D_PAD_SAI1_RX_DATA__UART5_DCE_RX 0x79
+ MX7D_PAD_SAI1_TX_SYNC__UART5_DCE_CTS 0x79
+ MX7D_PAD_SAI1_TX_DATA__UART5_DCE_RTS 0x79
+ >;
+ };
+
+ pinctrl_uart6: uart6grp {
+ fsl,pins = <
+ MX7D_PAD_ECSPI1_MOSI__UART6_DCE_TX 0x79
+ MX7D_PAD_ECSPI1_SCLK__UART6_DCE_RX 0x79
+ MX7D_PAD_ECSPI1_SS0__UART6_DCE_CTS 0x79
+ MX7D_PAD_ECSPI1_MISO__UART6_DCE_RTS 0x79
+ >;
+ };
+
+ 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 */
+ MX7D_PAD_SD1_RESET_B__GPIO5_IO2 0x59 /* vmmc */
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX7D_PAD_SD2_CMD__SD2_CMD 0x59
+ MX7D_PAD_SD2_CLK__SD2_CLK 0x19
+ MX7D_PAD_SD2_DATA0__SD2_DATA0 0x59
+ MX7D_PAD_SD2_DATA1__SD2_DATA1 0x59
+ MX7D_PAD_SD2_DATA2__SD2_DATA2 0x59
+ MX7D_PAD_SD2_DATA3__SD2_DATA3 0x59
+ MX7D_PAD_ECSPI2_MOSI__GPIO4_IO21 0x59 /* WL_REG_ON */
+ >;
+ };
+
+ pinctrl_usdhc2_100mhz: usdhc2grp_100mhz {
+ fsl,pins = <
+ MX7D_PAD_SD2_CMD__SD2_CMD 0x5a
+ MX7D_PAD_SD2_CLK__SD2_CLK 0x1a
+ MX7D_PAD_SD2_DATA0__SD2_DATA0 0x5a
+ MX7D_PAD_SD2_DATA1__SD2_DATA1 0x5a
+ MX7D_PAD_SD2_DATA2__SD2_DATA2 0x5a
+ MX7D_PAD_SD2_DATA3__SD2_DATA3 0x5a
+ >;
+ };
+
+ pinctrl_usdhc2_200mhz: usdhc2grp_200mhz {
+ fsl,pins = <
+ MX7D_PAD_SD2_CMD__SD2_CMD 0x5b
+ MX7D_PAD_SD2_CLK__SD2_CLK 0x1b
+ MX7D_PAD_SD2_DATA0__SD2_DATA0 0x5b
+ MX7D_PAD_SD2_DATA1__SD2_DATA1 0x5b
+ MX7D_PAD_SD2_DATA2__SD2_DATA2 0x5b
+ MX7D_PAD_SD2_DATA3__SD2_DATA3 0x5b
+ >;
+ };
+
+
+ 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
+ >;
+ };
+
+ pinctrl_usdhc3_100mhz: usdhc3grp_100mhz {
+ fsl,pins = <
+ MX7D_PAD_SD3_CMD__SD3_CMD 0x5a
+ MX7D_PAD_SD3_CLK__SD3_CLK 0x1a
+ MX7D_PAD_SD3_DATA0__SD3_DATA0 0x5a
+ MX7D_PAD_SD3_DATA1__SD3_DATA1 0x5a
+ MX7D_PAD_SD3_DATA2__SD3_DATA2 0x5a
+ MX7D_PAD_SD3_DATA3__SD3_DATA3 0x5a
+ MX7D_PAD_SD3_DATA4__SD3_DATA4 0x5a
+ MX7D_PAD_SD3_DATA5__SD3_DATA5 0x5a
+ MX7D_PAD_SD3_DATA6__SD3_DATA6 0x5a
+ MX7D_PAD_SD3_DATA7__SD3_DATA7 0x5a
+ MX7D_PAD_SD3_STROBE__SD3_STROBE 0x1a
+ >;
+ };
+
+ pinctrl_usdhc3_200mhz: usdhc3grp_200mhz {
+ fsl,pins = <
+ MX7D_PAD_SD3_CMD__SD3_CMD 0x5b
+ MX7D_PAD_SD3_CLK__SD3_CLK 0x1b
+ MX7D_PAD_SD3_DATA0__SD3_DATA0 0x5b
+ MX7D_PAD_SD3_DATA1__SD3_DATA1 0x5b
+ MX7D_PAD_SD3_DATA2__SD3_DATA2 0x5b
+ MX7D_PAD_SD3_DATA3__SD3_DATA3 0x5b
+ MX7D_PAD_SD3_DATA4__SD3_DATA4 0x5b
+ MX7D_PAD_SD3_DATA5__SD3_DATA5 0x5b
+ MX7D_PAD_SD3_DATA6__SD3_DATA6 0x5b
+ MX7D_PAD_SD3_DATA7__SD3_DATA7 0x5b
+ MX7D_PAD_SD3_STROBE__SD3_STROBE 0x1b
+ >;
+ };
+
+ };
+};
diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi
new file mode 100644
index 000000000000..c42cf8db0451
--- /dev/null
+++ b/arch/arm/boot/dts/imx7d.dtsi
@@ -0,0 +1,486 @@
+/*
+ * Copyright 2015 Freescale Semiconductor, 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.
+ */
+
+#include <dt-bindings/clock/imx7d-clock.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "imx7d-pinfunc.h"
+#include "skeleton.dtsi"
+
+/ {
+ aliases {
+ gpio0 = &gpio1;
+ gpio1 = &gpio2;
+ gpio2 = &gpio3;
+ gpio3 = &gpio4;
+ gpio4 = &gpio5;
+ gpio5 = &gpio6;
+ gpio6 = &gpio7;
+ i2c0 = &i2c1;
+ i2c1 = &i2c2;
+ i2c2 = &i2c3;
+ i2c3 = &i2c4;
+ mmc0 = &usdhc1;
+ mmc1 = &usdhc2;
+ mmc2 = &usdhc3;
+ serial0 = &uart1;
+ serial1 = &uart2;
+ serial2 = &uart3;
+ serial3 = &uart4;
+ serial4 = &uart5;
+ serial5 = &uart6;
+ serial6 = &uart7;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <0>;
+ operating-points = <
+ /* KHz uV */
+ 996000 1075000
+ 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";
+ };
+
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ intc: interrupt-controller@31001000 {
+ compatible = "arm,cortex-a7-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x31001000 0x1000>,
+ <0x31002000 0x1000>,
+ <0x31004000 0x2000>,
+ <0x31006000 0x2000>;
+ };
+
+ ckil: clock-cki {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "ckil";
+ };
+
+ osc: clock-osc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ clock-output-names = "osc";
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ interrupt-parent = <&intc>;
+ ranges;
+
+ aips1: aips-bus@30000000 {
+ compatible = "fsl,aips-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x30000000 0x400000>;
+ ranges;
+
+ gpio1: gpio@30200000 {
+ compatible = "fsl,imx7d-gpio", "fsl,imx35-gpio";
+ reg = <0x30200000 0x10000>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>, /* GPIO1_INT15_0 */
+ <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; /* GPIO1_INT31_16 */
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio2: gpio@30210000 {
+ compatible = "fsl,imx7d-gpio", "fsl,imx35-gpio";
+ reg = <0x30210000 0x10000>;
+ interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio3: gpio@30220000 {
+ compatible = "fsl,imx7d-gpio", "fsl,imx35-gpio";
+ reg = <0x30220000 0x10000>;
+ interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio4: gpio@30230000 {
+ compatible = "fsl,imx7d-gpio", "fsl,imx35-gpio";
+ reg = <0x30230000 0x10000>;
+ interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio5: gpio@30240000 {
+ compatible = "fsl,imx7d-gpio", "fsl,imx35-gpio";
+ reg = <0x30240000 0x10000>;
+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio6: gpio@30250000 {
+ compatible = "fsl,imx7d-gpio", "fsl,imx35-gpio";
+ reg = <0x30250000 0x10000>;
+ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio7: gpio@30260000 {
+ compatible = "fsl,imx7d-gpio", "fsl,imx35-gpio";
+ reg = <0x30260000 0x10000>;
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpt1: gpt@302d0000 {
+ compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
+ reg = <0x302d0000 0x10000>;
+ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_GPT1_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ };
+
+ gpt2: gpt@302e0000 {
+ compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
+ reg = <0x302e0000 0x10000>;
+ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_GPT2_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ gpt3: gpt@302f0000 {
+ compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
+ reg = <0x302f0000 0x10000>;
+ interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_GPT3_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ gpt4: gpt@30300000 {
+ compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
+ reg = <0x30300000 0x10000>;
+ interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_GPT4_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ iomuxc: iomuxc@30330000 {
+ compatible = "fsl,imx7d-iomuxc";
+ reg = <0x30330000 0x10000>;
+ };
+
+ gpr: iomuxc-gpr@30340000 {
+ compatible = "fsl,imx7d-iomuxc-gpr", "syscon";
+ reg = <0x30340000 0x10000>;
+ };
+
+ ocotp: ocotp-ctrl@30350000 {
+ compatible = "syscon";
+ reg = <0x30350000 0x10000>;
+ clocks = <&clks IMX7D_CLK_DUMMY>;
+ status = "disabled";
+ };
+
+ anatop: anatop@30360000 {
+ compatible = "fsl,imx7d-anatop", "fsl,imx6q-anatop",
+ "syscon", "simple-bus";
+ reg = <0x30360000 0x10000>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+
+ reg_1p0d: regulator-vdd1p0d@210 {
+ compatible = "fsl,anatop-regulator";
+ regulator-name = "vdd1p0d";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1200000>;
+ anatop-reg-offset = <0x210>;
+ anatop-vol-bit-shift = <8>;
+ anatop-vol-bit-width = <5>;
+ anatop-min-bit-val = <8>;
+ anatop-min-voltage = <800000>;
+ anatop-max-voltage = <1200000>;
+ anatop-enable-bit = <31>;
+ };
+ };
+
+ snvs: snvs@30370000 {
+ compatible = "fsl,sec-v4.0-mon", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x30370000 0x10000>;
+
+ snvs-rtc-lp@34 {
+ compatible = "fsl,sec-v4.0-mon-rtc-lp";
+ reg = <0x34 0x58>;
+ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+
+ clks: ccm@30380000 {
+ compatible = "fsl,imx7d-ccm";
+ reg = <0x30380000 0x10000>;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ #clock-cells = <1>;
+ clocks = <&ckil>, <&osc>;
+ clock-names = "ckil", "osc";
+ };
+
+ src: src@30390000 {
+ compatible = "fsl,imx7d-src", "fsl,imx51-src", "syscon";
+ reg = <0x30390000 0x10000>;
+ interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+ #reset-cells = <1>;
+ };
+ };
+
+ aips3: aips-bus@30800000 {
+ compatible = "fsl,aips-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x30800000 0x400000>;
+ ranges;
+
+ uart1: serial@30860000 {
+ compatible = "fsl,imx7d-uart",
+ "fsl,imx6q-uart";
+ reg = <0x30860000 0x10000>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_UART1_ROOT_CLK>,
+ <&clks IMX7D_UART1_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ uart2: serial@30870000 {
+ compatible = "fsl,imx7d-uart",
+ "fsl,imx6q-uart";
+ reg = <0x30870000 0x10000>;
+ interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_UART2_ROOT_CLK>,
+ <&clks IMX7D_UART2_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ uart3: serial@30880000 {
+ compatible = "fsl,imx7d-uart",
+ "fsl,imx6q-uart";
+ reg = <0x30880000 0x10000>;
+ interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_UART3_ROOT_CLK>,
+ <&clks IMX7D_UART3_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ i2c1: i2c@30a20000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx7d-i2c", "fsl,imx21-i2c";
+ reg = <0x30a20000 0x10000>;
+ interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_I2C1_ROOT_CLK>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@30a30000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx7d-i2c", "fsl,imx21-i2c";
+ reg = <0x30a30000 0x10000>;
+ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_I2C2_ROOT_CLK>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@30a40000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx7d-i2c", "fsl,imx21-i2c";
+ reg = <0x30a40000 0x10000>;
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_I2C3_ROOT_CLK>;
+ status = "disabled";
+ };
+
+ i2c4: i2c@30a50000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx7d-i2c", "fsl,imx21-i2c";
+ reg = <0x30a50000 0x10000>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_I2C4_ROOT_CLK>;
+ status = "disabled";
+ };
+
+ uart4: serial@30a60000 {
+ compatible = "fsl,imx7d-uart",
+ "fsl,imx6q-uart";
+ reg = <0x30a60000 0x10000>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_UART4_ROOT_CLK>,
+ <&clks IMX7D_UART4_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ uart5: serial@30a70000 {
+ compatible = "fsl,imx7d-uart",
+ "fsl,imx6q-uart";
+ reg = <0x30a70000 0x10000>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_UART5_ROOT_CLK>,
+ <&clks IMX7D_UART5_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ uart6: serial@30a80000 {
+ compatible = "fsl,imx7d-uart",
+ "fsl,imx6q-uart";
+ reg = <0x30a80000 0x10000>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_UART6_ROOT_CLK>,
+ <&clks IMX7D_UART6_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ uart7: serial@30a90000 {
+ compatible = "fsl,imx7d-uart",
+ "fsl,imx6q-uart";
+ reg = <0x30a90000 0x10000>;
+ interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_UART7_ROOT_CLK>,
+ <&clks IMX7D_UART7_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ usdhc1: usdhc@30b40000 {
+ compatible = "fsl,imx7d-usdhc", "fsl,imx6sl-usdhc";
+ reg = <0x30b40000 0x10000>;
+ interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_USDHC1_ROOT_CLK>;
+ clock-names = "ipg", "ahb", "per";
+ bus-width = <4>;
+ status = "disabled";
+ };
+
+ usdhc2: usdhc@30b50000 {
+ compatible = "fsl,imx7d-usdhc", "fsl,imx6sl-usdhc";
+ reg = <0x30b50000 0x10000>;
+ interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_USDHC2_ROOT_CLK>;
+ clock-names = "ipg", "ahb", "per";
+ bus-width = <4>;
+ status = "disabled";
+ };
+
+ usdhc3: usdhc@30b60000 {
+ compatible = "fsl,imx7d-usdhc", "fsl,imx6sl-usdhc";
+ reg = <0x30b60000 0x10000>;
+ interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_USDHC3_ROOT_CLK>;
+ clock-names = "ipg", "ahb", "per";
+ bus-width = <4>;
+ status = "disabled";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/integrator.dtsi b/arch/arm/boot/dts/integrator.dtsi
index 28e38f8c6b0f..3807d4f46ef7 100644
--- a/arch/arm/boot/dts/integrator.dtsi
+++ b/arch/arm/boot/dts/integrator.dtsi
@@ -6,7 +6,7 @@
/ {
core-module@10000000 {
- compatible = "arm,core-module-integrator", "syscon";
+ compatible = "arm,core-module-integrator", "syscon", "simple-mfd";
reg = <0x10000000 0x200>;
/* Use core module LED to indicate CPU load */
@@ -95,7 +95,7 @@
syscon {
/* Debug registers mapped as syscon */
- compatible = "syscon";
+ compatible = "syscon", "simple-mfd";
reg = <0x1a000000 0x10>;
led@04.0 {
diff --git a/arch/arm/boot/dts/k2e-evm.dts b/arch/arm/boot/dts/k2e-evm.dts
index 560d62150ade..50c83c21d911 100644
--- a/arch/arm/boot/dts/k2e-evm.dts
+++ b/arch/arm/boot/dts/k2e-evm.dts
@@ -141,6 +141,7 @@
};
&mdio {
+ status = "ok";
ethphy0: ethernet-phy@0 {
compatible = "marvell,88E1514", "marvell,88E1510", "ethernet-phy-ieee802.3-c22";
reg = <0>;
diff --git a/arch/arm/boot/dts/k2e-netcp.dtsi b/arch/arm/boot/dts/k2e-netcp.dtsi
new file mode 100644
index 000000000000..b13b3c94e7fc
--- /dev/null
+++ b/arch/arm/boot/dts/k2e-netcp.dtsi
@@ -0,0 +1,206 @@
+/*
+ * Device Tree Source for Keystone 2 Edison Netcp driver
+ *
+ * Copyright 2015 Texas Instruments, 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.
+ */
+
+qmss: qmss@2a40000 {
+ compatible = "ti,keystone-navigator-qmss";
+ dma-coherent;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ clocks = <&chipclk13>;
+ ranges;
+ queue-range = <0 0x2000>;
+ linkram0 = <0x100000 0x4000>;
+ linkram1 = <0 0x10000>;
+
+ qmgrs {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ qmgr0 {
+ managed-queues = <0 0x2000>;
+ reg = <0x2a40000 0x20000>,
+ <0x2a06000 0x400>,
+ <0x2a02000 0x1000>,
+ <0x2a03000 0x1000>,
+ <0x23a80000 0x20000>,
+ <0x2a80000 0x20000>;
+ reg-names = "peek", "status", "config",
+ "region", "push", "pop";
+ };
+ };
+ queue-pools {
+ qpend {
+ qpend-0 {
+ qrange = <658 8>;
+ interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04
+ 0 43 0xf04 0 44 0xf04 0 45 0xf04
+ 0 46 0xf04 0 47 0xf04>;
+ };
+ qpend-1 {
+ qrange = <528 16>;
+ interrupts = <0 48 0xf04 0 49 0xf04 0 50 0xf04
+ 0 51 0xf04 0 52 0xf04 0 53 0xf04
+ 0 54 0xf04 0 55 0xf04 0 56 0xf04
+ 0 57 0xf04 0 58 0xf04 0 59 0xf04
+ 0 60 0xf04 0 61 0xf04 0 62 0xf04
+ 0 63 0xf04>;
+ qalloc-by-id;
+ };
+ qpend-2 {
+ qrange = <544 16>;
+ interrupts = <0 64 0xf04 0 65 0xf04 0 66 0xf04
+ 0 59 0xf04 0 68 0xf04 0 69 0xf04
+ 0 70 0xf04 0 71 0xf04 0 72 0xf04
+ 0 73 0xf04 0 74 0xf04 0 75 0xf04
+ 0 76 0xf04 0 77 0xf04 0 78 0xf04
+ 0 79 0xf04>;
+ };
+ };
+ general-purpose {
+ gp-0 {
+ qrange = <4000 64>;
+ };
+ netcp-tx {
+ qrange = <896 128>;
+ qalloc-by-id;
+ };
+ };
+ };
+ descriptor-regions {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ region-12 {
+ id = <12>;
+ region-spec = <8192 128>; /* num_desc desc_size */
+ link-index = <0x4000>;
+ };
+ };
+}; /* qmss */
+
+knav_dmas: knav_dmas@0 {
+ compatible = "ti,keystone-navigator-dma";
+ clocks = <&papllclk>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ ti,navigator-cloud-address = <0x23a80000 0x23a90000
+ 0x23a80000 0x23a90000>;
+
+ dma_gbe: dma_gbe@0 {
+ reg = <0x24186000 0x100>,
+ <0x24187000 0x2a0>,
+ <0x24188000 0xb60>,
+ <0x24186100 0x80>,
+ <0x24189000 0x1000>;
+ reg-names = "global", "txchan", "rxchan",
+ "txsched", "rxflow";
+ };
+};
+
+netcp: netcp@24000000 {
+ reg = <0x2620110 0x8>;
+ reg-names = "efuse";
+ compatible = "ti,netcp-1.0";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* NetCP address range */
+ ranges = <0 0x24000000 0x1000000>;
+
+ clocks = <&papllclk>, <&clkcpgmac>, <&chipclk12>;
+ dma-coherent;
+
+ ti,navigator-dmas = <&dma_gbe 0>,
+ <&dma_gbe 8>,
+ <&dma_gbe 0>;
+ ti,navigator-dma-names = "netrx0", "netrx1", "nettx";
+
+ netcp-devices {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ gbe@200000 { /* ETHSS */
+ label = "netcp-gbe";
+ compatible = "ti,netcp-gbe-9";
+ reg = <0x200000 0x900>, <0x220000 0x20000>;
+ /* enable-ale; */
+ tx-queue = <896>;
+ tx-channel = "nettx";
+
+ interfaces {
+ gbe0: interface-0 {
+ slave-port = <0>;
+ link-interface = <1>;
+ phy-handle = <&ethphy0>;
+ };
+ gbe1: interface-1 {
+ slave-port = <1>;
+ link-interface = <1>;
+ phy-handle = <&ethphy1>;
+ };
+ };
+
+ secondary-slave-ports {
+ port-2 {
+ slave-port = <2>;
+ link-interface = <2>;
+ };
+ port-3 {
+ slave-port = <3>;
+ link-interface = <2>;
+ };
+ port-4 {
+ slave-port = <4>;
+ link-interface = <2>;
+ };
+ port-5 {
+ slave-port = <5>;
+ link-interface = <2>;
+ };
+ port-6 {
+ slave-port = <6>;
+ link-interface = <2>;
+ };
+ port-7 {
+ slave-port = <7>;
+ link-interface = <2>;
+ };
+ };
+ };
+ };
+
+ netcp-interfaces {
+ interface-0 {
+ rx-channel = "netrx0";
+ rx-pool = <1024 12>;
+ tx-pool = <1024 12>;
+ rx-queue-depth = <128 128 0 0>;
+ rx-buffer-size = <1518 4096 0 0>;
+ rx-queue = <528>;
+ tx-completion-queue = <530>;
+ efuse-mac = <1>;
+ netcp-gbe = <&gbe0>;
+
+ };
+ interface-1 {
+ rx-channel = "netrx1";
+ rx-pool = <1024 12>;
+ tx-pool = <1024 12>;
+ rx-queue-depth = <128 128 0 0>;
+ rx-buffer-size = <1518 4096 0 0>;
+ rx-queue = <529>;
+ tx-completion-queue = <531>;
+ efuse-mac = <0>;
+ local-mac-address = [02 18 31 7e 3e 00];
+ netcp-gbe = <&gbe1>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/k2e.dtsi b/arch/arm/boot/dts/k2e.dtsi
index 5fc14683d6df..50e555eab50d 100644
--- a/arch/arm/boot/dts/k2e.dtsi
+++ b/arch/arm/boot/dts/k2e.dtsi
@@ -130,6 +130,7 @@
<GIC_SPI 376 IRQ_TYPE_EDGE_RISING>;
};
};
+ /include/ "k2e-netcp.dtsi"
};
};
diff --git a/arch/arm/boot/dts/k2hk-evm.dts b/arch/arm/boot/dts/k2hk-evm.dts
index 3223cc152a85..660ebf58d547 100644
--- a/arch/arm/boot/dts/k2hk-evm.dts
+++ b/arch/arm/boot/dts/k2hk-evm.dts
@@ -169,6 +169,7 @@
};
&mdio {
+ status = "ok";
ethphy0: ethernet-phy@0 {
compatible = "marvell,88E1111", "ethernet-phy-ieee802.3-c22";
reg = <0>;
diff --git a/arch/arm/boot/dts/k2hk-netcp.dtsi b/arch/arm/boot/dts/k2hk-netcp.dtsi
new file mode 100644
index 000000000000..77a32c3c17e4
--- /dev/null
+++ b/arch/arm/boot/dts/k2hk-netcp.dtsi
@@ -0,0 +1,208 @@
+/*
+ * Device Tree Source for Keystone 2 Hawking Netcp driver
+ *
+ * Copyright 2015 Texas Instruments, 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.
+ */
+
+qmss: qmss@2a40000 {
+ compatible = "ti,keystone-navigator-qmss";
+ dma-coherent;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ clocks = <&chipclk13>;
+ ranges;
+ queue-range = <0 0x4000>;
+ linkram0 = <0x100000 0x8000>;
+ linkram1 = <0x0 0x10000>;
+
+ qmgrs {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ qmgr0 {
+ managed-queues = <0 0x2000>;
+ reg = <0x2a40000 0x20000>,
+ <0x2a06000 0x400>,
+ <0x2a02000 0x1000>,
+ <0x2a03000 0x1000>,
+ <0x23a80000 0x20000>,
+ <0x2a80000 0x20000>;
+ reg-names = "peek", "status", "config",
+ "region", "push", "pop";
+ };
+
+ qmgr1 {
+ managed-queues = <0x2000 0x2000>;
+ reg = <0x2a60000 0x20000>,
+ <0x2a06400 0x400>,
+ <0x2a04000 0x1000>,
+ <0x2a05000 0x1000>,
+ <0x23aa0000 0x20000>,
+ <0x2aa0000 0x20000>;
+ reg-names = "peek", "status", "config",
+ "region", "push", "pop";
+ };
+ };
+ queue-pools {
+ qpend {
+ qpend-0 {
+ qrange = <658 8>;
+ interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04
+ 0 43 0xf04 0 44 0xf04 0 45 0xf04
+ 0 46 0xf04 0 47 0xf04>;
+ };
+ qpend-1 {
+ qrange = <8704 16>;
+ interrupts = <0 48 0xf04 0 49 0xf04 0 50 0xf04
+ 0 51 0xf04 0 52 0xf04 0 53 0xf04
+ 0 54 0xf04 0 55 0xf04 0 56 0xf04
+ 0 57 0xf04 0 58 0xf04 0 59 0xf04
+ 0 60 0xf04 0 61 0xf04 0 62 0xf04
+ 0 63 0xf04>;
+ qalloc-by-id;
+ };
+ qpend-2 {
+ qrange = <8720 16>;
+ interrupts = <0 64 0xf04 0 65 0xf04 0 66 0xf04
+ 0 59 0xf04 0 68 0xf04 0 69 0xf04
+ 0 70 0xf04 0 71 0xf04 0 72 0xf04
+ 0 73 0xf04 0 74 0xf04 0 75 0xf04
+ 0 76 0xf04 0 77 0xf04 0 78 0xf04
+ 0 79 0xf04>;
+ };
+ };
+ general-purpose {
+ gp-0 {
+ qrange = <4000 64>;
+ };
+ netcp-tx {
+ qrange = <640 9>;
+ qalloc-by-id;
+ };
+ netcpx-tx {
+ qrange = <8752 8>;
+ qalloc-by-id;
+ };
+ };
+ };
+ descriptor-regions {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ region-12 {
+ id = <12>;
+ region-spec = <8192 128>; /* num_desc desc_size */
+ link-index = <0x4000>;
+ };
+ };
+}; /* qmss */
+
+knav_dmas: knav_dmas@0 {
+ compatible = "ti,keystone-navigator-dma";
+ clocks = <&papllclk>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ ti,navigator-cloud-address = <0x23a80000 0x23a90000
+ 0x23aa0000 0x23ab0000>;
+
+ dma_gbe: dma_gbe@0 {
+ reg = <0x2004000 0x100>,
+ <0x2004400 0x120>,
+ <0x2004800 0x300>,
+ <0x2004c00 0x120>,
+ <0x2005000 0x400>;
+ reg-names = "global", "txchan", "rxchan",
+ "txsched", "rxflow";
+ };
+};
+
+netcp: netcp@2000000 {
+ reg = <0x2620110 0x8>;
+ reg-names = "efuse";
+ compatible = "ti,netcp-1.0";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* NetCP address range */
+ ranges = <0 0x2000000 0x100000>;
+
+ clocks = <&papllclk>, <&clkcpgmac>, <&chipclk12>;
+ dma-coherent;
+
+ ti,navigator-dmas = <&dma_gbe 22>,
+ <&dma_gbe 23>,
+ <&dma_gbe 8>;
+ ti,navigator-dma-names = "netrx0", "netrx1", "nettx";
+
+ netcp-devices {
+ ranges;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ gbe@90000 { /* ETHSS */
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "netcp-gbe";
+ compatible = "ti,netcp-gbe";
+ reg = <0x90000 0x300>, <0x90400 0x400>, <0x90800 0x700>;
+ /* enable-ale; */
+ tx-queue = <648>;
+ tx-channel = "nettx";
+
+ interfaces {
+ gbe0: interface-0 {
+ slave-port = <0>;
+ link-interface = <1>;
+ phy-handle = <&ethphy0>;
+ };
+ gbe1: interface-1 {
+ slave-port = <1>;
+ link-interface = <1>;
+ phy-handle = <&ethphy1>;
+ };
+ };
+
+ secondary-slave-ports {
+ port-2 {
+ slave-port = <2>;
+ link-interface = <2>;
+ };
+ port-3 {
+ slave-port = <3>;
+ link-interface = <2>;
+ };
+ };
+ };
+ };
+
+ netcp-interfaces {
+ interface-0 {
+ rx-channel = "netrx0";
+ rx-pool = <1024 12>;
+ tx-pool = <1024 12>;
+ rx-queue-depth = <128 128 0 0>;
+ rx-buffer-size = <1518 4096 0 0>;
+ rx-queue = <8704>;
+ tx-completion-queue = <8706>;
+ efuse-mac = <1>;
+ netcp-gbe = <&gbe0>;
+
+ };
+ interface-1 {
+ rx-channel = "netrx1";
+ rx-pool = <1024 12>;
+ tx-pool = <1024 12>;
+ rx-queue-depth = <128 128 0 0>;
+ rx-buffer-size = <1518 4096 0 0>;
+ rx-queue = <8705>;
+ tx-completion-queue = <8707>;
+ efuse-mac = <0>;
+ local-mac-address = [02 18 31 7e 3e 6f];
+ netcp-gbe = <&gbe1>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/k2hk.dtsi b/arch/arm/boot/dts/k2hk.dtsi
index d721f4b737f7..ae6472407b22 100644
--- a/arch/arm/boot/dts/k2hk.dtsi
+++ b/arch/arm/boot/dts/k2hk.dtsi
@@ -98,5 +98,6 @@
#gpio-cells = <2>;
gpio,syscon-dev = <&devctrl 0x25c>;
};
+ /include/ "k2hk-netcp.dtsi"
};
};
diff --git a/arch/arm/boot/dts/k2l-evm.dts b/arch/arm/boot/dts/k2l-evm.dts
index 85cc7f2872d7..9a69a6b55374 100644
--- a/arch/arm/boot/dts/k2l-evm.dts
+++ b/arch/arm/boot/dts/k2l-evm.dts
@@ -118,6 +118,7 @@
};
&mdio {
+ status = "ok";
ethphy0: ethernet-phy@0 {
compatible = "marvell,88E1514", "marvell,88E1510", "ethernet-phy-ieee802.3-c22";
reg = <0>;
diff --git a/arch/arm/boot/dts/k2l-netcp.dtsi b/arch/arm/boot/dts/k2l-netcp.dtsi
new file mode 100644
index 000000000000..6b95284d11d4
--- /dev/null
+++ b/arch/arm/boot/dts/k2l-netcp.dtsi
@@ -0,0 +1,189 @@
+/*
+ * Device Tree Source for Keystone 2 Lamarr Netcp driver
+ *
+ * Copyright 2015 Texas Instruments, 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.
+ */
+
+qmss: qmss@2a40000 {
+ compatible = "ti,keystone-navigator-qmss";
+ dma-coherent;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ clocks = <&chipclk13>;
+ ranges;
+ queue-range = <0 0x2000>;
+ linkram0 = <0x100000 0x4000>;
+ linkram1 = <0x70000000 0x10000>; /* 1MB OSR mem */
+
+ qmgrs {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ qmgr0 {
+ managed-queues = <0 0x2000>;
+ reg = <0x2a40000 0x20000>,
+ <0x2a06000 0x400>,
+ <0x2a02000 0x1000>,
+ <0x2a03000 0x1000>,
+ <0x23a80000 0x20000>,
+ <0x2a80000 0x20000>;
+ reg-names = "peek", "status", "config",
+ "region", "push", "pop";
+ };
+ };
+ queue-pools {
+ qpend {
+ qpend-0 {
+ qrange = <658 8>;
+ interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04
+ 0 43 0xf04 0 44 0xf04 0 45 0xf04
+ 0 46 0xf04 0 47 0xf04>;
+ };
+ qpend-1 {
+ qrange = <528 16>;
+ interrupts = <0 48 0xf04 0 49 0xf04 0 50 0xf04
+ 0 51 0xf04 0 52 0xf04 0 53 0xf04
+ 0 54 0xf04 0 55 0xf04 0 56 0xf04
+ 0 57 0xf04 0 58 0xf04 0 59 0xf04
+ 0 60 0xf04 0 61 0xf04 0 62 0xf04
+ 0 63 0xf04>;
+ qalloc-by-id;
+ };
+ qpend-2 {
+ qrange = <544 16>;
+ interrupts = <0 64 0xf04 0 65 0xf04 0 66 0xf04
+ 0 59 0xf04 0 68 0xf04 0 69 0xf04
+ 0 70 0xf04 0 71 0xf04 0 72 0xf04
+ 0 73 0xf04 0 74 0xf04 0 75 0xf04
+ 0 76 0xf04 0 77 0xf04 0 78 0xf04
+ 0 79 0xf04>;
+ };
+ };
+ general-purpose {
+ gp-0 {
+ qrange = <4000 64>;
+ };
+ netcp-tx {
+ qrange = <896 128>;
+ qalloc-by-id;
+ };
+ };
+ };
+ descriptor-regions {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ region-12 {
+ id = <12>;
+ region-spec = <8192 128>; /* num_desc desc_size */
+ link-index = <0x4000>;
+ };
+ };
+}; /* qmss */
+
+knav_dmas: knav_dmas@0 {
+ compatible = "ti,keystone-navigator-dma";
+ clocks = <&papllclk>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ ti,navigator-cloud-address = <0x23a80000 0x23a90000>;
+
+ dma_gbe: dma_gbe@0 {
+ reg = <0x26186000 0x100>,
+ <0x26187000 0x2a0>,
+ <0x26188000 0xb60>,
+ <0x26186100 0x80>,
+ <0x26189000 0x1000>;
+ reg-names = "global", "txchan", "rxchan",
+ "txsched", "rxflow";
+ };
+};
+
+netcp: netcp@26000000 {
+ reg = <0x2620110 0x8>;
+ reg-names = "efuse";
+ compatible = "ti,netcp-1.0";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* NetCP address range */
+ ranges = <0 0x26000000 0x1000000>;
+
+ clocks = <&papllclk>, <&clkcpgmac>, <&chipclk12>;
+ dma-coherent;
+
+ ti,navigator-dmas = <&dma_gbe 0>,
+ <&dma_gbe 8>,
+ <&dma_gbe 0>;
+ ti,navigator-dma-names = "netrx0", "netrx1", "nettx";
+
+ netcp-devices {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ gbe@200000 { /* ETHSS */
+ label = "netcp-gbe";
+ compatible = "ti,netcp-gbe-5";
+ reg = <0x200000 0x900>, <0x220000 0x20000>;
+ /* enable-ale; */
+ tx-queue = <896>;
+ tx-channel = "nettx";
+
+ interfaces {
+ gbe0: interface-0 {
+ slave-port = <0>;
+ link-interface = <1>;
+ phy-handle = <&ethphy0>;
+ };
+ gbe1: interface-1 {
+ slave-port = <1>;
+ link-interface = <1>;
+ phy-handle = <&ethphy1>;
+ };
+ };
+
+ secondary-slave-ports {
+ port-2 {
+ slave-port = <2>;
+ link-interface = <2>;
+ };
+ port-3 {
+ slave-port = <3>;
+ link-interface = <2>;
+ };
+ };
+ };
+ };
+
+ netcp-interfaces {
+ interface-0 {
+ rx-channel = "netrx0";
+ rx-pool = <1024 12>;
+ tx-pool = <1024 12>;
+ rx-queue-depth = <128 128 0 0>;
+ rx-buffer-size = <1518 4096 0 0>;
+ rx-queue = <528>;
+ tx-completion-queue = <530>;
+ efuse-mac = <1>;
+ netcp-gbe = <&gbe0>;
+
+ };
+ interface-1 {
+ rx-channel = "netrx1";
+ rx-pool = <1024 12>;
+ tx-pool = <1024 12>;
+ rx-queue-depth = <128 128 0 0>;
+ rx-buffer-size = <1518 4096 0 0>;
+ rx-queue = <529>;
+ tx-completion-queue = <531>;
+ efuse-mac = <0>;
+ local-mac-address = [02 18 31 7e 3e 7f];
+ netcp-gbe = <&gbe1>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/k2l.dtsi b/arch/arm/boot/dts/k2l.dtsi
index e32c3baa77b8..0e007483615e 100644
--- a/arch/arm/boot/dts/k2l.dtsi
+++ b/arch/arm/boot/dts/k2l.dtsi
@@ -79,6 +79,7 @@
#gpio-cells = <2>;
gpio,syscon-dev = <&devctrl 0x24c>;
};
+ /include/ "k2l-netcp.dtsi"
};
};
diff --git a/arch/arm/boot/dts/kirkwood-b3.dts b/arch/arm/boot/dts/kirkwood-b3.dts
index c9247f8672ae..d2936ad3af1d 100644
--- a/arch/arm/boot/dts/kirkwood-b3.dts
+++ b/arch/arm/boot/dts/kirkwood-b3.dts
@@ -74,7 +74,7 @@
m25p16@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "st,m25p16";
+ compatible = "st,m25p16", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <40000000>;
mode = <0>;
diff --git a/arch/arm/boot/dts/kirkwood-cloudbox.dts b/arch/arm/boot/dts/kirkwood-cloudbox.dts
index ab6ab4933e6b..7ec76566acf2 100644
--- a/arch/arm/boot/dts/kirkwood-cloudbox.dts
+++ b/arch/arm/boot/dts/kirkwood-cloudbox.dts
@@ -42,7 +42,7 @@
flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "mxicy,mx25l4005a";
+ compatible = "mxicy,mx25l4005a", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <20000000>;
mode = <0>;
diff --git a/arch/arm/boot/dts/kirkwood-dir665.dts b/arch/arm/boot/dts/kirkwood-dir665.dts
index 786959ee9cbe..0473fcc260f7 100644
--- a/arch/arm/boot/dts/kirkwood-dir665.dts
+++ b/arch/arm/boot/dts/kirkwood-dir665.dts
@@ -93,7 +93,7 @@
m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "mxicy,mx25l12805d";
+ compatible = "mxicy,mx25l12805d", "jedec,spi-nor";
spi-max-frequency = <50000000>;
reg = <0>;
diff --git a/arch/arm/boot/dts/kirkwood-dreamplug.dts b/arch/arm/boot/dts/kirkwood-dreamplug.dts
index 6467c7924195..e2abc8246bf3 100644
--- a/arch/arm/boot/dts/kirkwood-dreamplug.dts
+++ b/arch/arm/boot/dts/kirkwood-dreamplug.dts
@@ -42,7 +42,7 @@
m25p40@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "mxicy,mx25l1606e";
+ compatible = "mxicy,mx25l1606e", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <50000000>;
mode = <0>;
diff --git a/arch/arm/boot/dts/kirkwood-lsxl.dtsi b/arch/arm/boot/dts/kirkwood-lsxl.dtsi
index 53484474df1f..1d6528d82969 100644
--- a/arch/arm/boot/dts/kirkwood-lsxl.dtsi
+++ b/arch/arm/boot/dts/kirkwood-lsxl.dtsi
@@ -74,7 +74,7 @@
m25p40@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "m25p40";
+ compatible = "m25p40", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <25000000>;
mode = <0>;
diff --git a/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts b/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts
index f82827d6fcff..b7e7d78c484e 100644
--- a/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts
+++ b/arch/arm/boot/dts/kirkwood-mv88f6281gtw-ge.dts
@@ -65,7 +65,7 @@
flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "mxicy,mx25l12805d";
+ compatible = "mxicy,mx25l12805d", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <50000000>;
mode = <0>;
diff --git a/arch/arm/boot/dts/kirkwood-netxbig.dtsi b/arch/arm/boot/dts/kirkwood-netxbig.dtsi
index b0cfb7cd30b9..1508b12147df 100644
--- a/arch/arm/boot/dts/kirkwood-netxbig.dtsi
+++ b/arch/arm/boot/dts/kirkwood-netxbig.dtsi
@@ -33,7 +33,7 @@
flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "mxicy,mx25l4005a";
+ compatible = "mxicy,mx25l4005a", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <20000000>;
mode = <0>;
diff --git a/arch/arm/boot/dts/kirkwood-ns2-common.dtsi b/arch/arm/boot/dts/kirkwood-ns2-common.dtsi
index fe6c0246db1a..e832b6320264 100644
--- a/arch/arm/boot/dts/kirkwood-ns2-common.dtsi
+++ b/arch/arm/boot/dts/kirkwood-ns2-common.dtsi
@@ -29,7 +29,7 @@
flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "mxicy,mx25l4005a";
+ compatible = "mxicy,mx25l4005a", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <20000000>;
mode = <0>;
diff --git a/arch/arm/boot/dts/kirkwood-rd88f6192.dts b/arch/arm/boot/dts/kirkwood-rd88f6192.dts
index 35a29dee8dd8..e0b959396ca2 100644
--- a/arch/arm/boot/dts/kirkwood-rd88f6192.dts
+++ b/arch/arm/boot/dts/kirkwood-rd88f6192.dts
@@ -61,7 +61,7 @@
m25p128@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "st,m25p128";
+ compatible = "st,m25p128", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <20000000>;
mode = <0>;
diff --git a/arch/arm/boot/dts/kirkwood-synology.dtsi b/arch/arm/boot/dts/kirkwood-synology.dtsi
index 8be5b2e4626e..04015c174b99 100644
--- a/arch/arm/boot/dts/kirkwood-synology.dtsi
+++ b/arch/arm/boot/dts/kirkwood-synology.dtsi
@@ -217,7 +217,7 @@
m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "st,m25p80";
+ compatible = "st,m25p80", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <20000000>;
mode = <0>;
diff --git a/arch/arm/boot/dts/kirkwood-t5325.dts b/arch/arm/boot/dts/kirkwood-t5325.dts
index 610ec0f95858..ed956b849a71 100644
--- a/arch/arm/boot/dts/kirkwood-t5325.dts
+++ b/arch/arm/boot/dts/kirkwood-t5325.dts
@@ -88,7 +88,7 @@
flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "st,m25p80";
+ compatible = "st,m25p80", "jedec,spi-nor";
spi-max-frequency = <86000000>;
reg = <0>;
mode = <0>;
diff --git a/arch/arm/boot/dts/kirkwood-ts219.dtsi b/arch/arm/boot/dts/kirkwood-ts219.dtsi
index df7f15276575..c56ab6bbfe3c 100644
--- a/arch/arm/boot/dts/kirkwood-ts219.dtsi
+++ b/arch/arm/boot/dts/kirkwood-ts219.dtsi
@@ -49,7 +49,7 @@
m25p128@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "m25p128";
+ compatible = "m25p128", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <20000000>;
mode = <0>;
diff --git a/arch/arm/boot/dts/kizbox.dts b/arch/arm/boot/dts/kizbox.dts
deleted file mode 100644
index e83e4f9310b8..000000000000
--- a/arch/arm/boot/dts/kizbox.dts
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * kizbox.dts - Device Tree file for Overkiz Kizbox board
- *
- * Copyright (C) 2012 Boris BREZILLON <linux-arm@overkiz.com>
- *
- * Licensed under GPLv2.
- */
-/dts-v1/;
-#include "at91sam9g20.dtsi"
-
-/ {
-
- model = "Overkiz kizbox";
- compatible = "overkiz,kizbox", "atmel,at91sam9g20", "atmel,at91sam9";
-
- chosen {
- bootargs = "panic=5 ubi.mtd=1 rootfstype=ubifs root=ubi0:root";
- };
-
- memory {
- reg = <0x20000000 0x2000000>;
- };
-
- clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <18432000>;
- };
-
- main_xtal {
- clock-frequency = <18432000>;
- };
- };
-
- ahb {
- apb {
- dbgu: serial@fffff200 {
- status = "okay";
- };
-
- usart0: serial@fffb0000 {
- status = "okay";
- };
-
- usart1: serial@fffb4000 {
- status = "okay";
- };
-
- macb0: ethernet@fffc4000 {
- phy-mode = "mii";
- pinctrl-0 = <&pinctrl_macb_rmii
- &pinctrl_macb_rmii_mii_alt>;
- status = "okay";
- };
-
- watchdog@fffffd40 {
- timeout-sec = <15>;
- atmel,max-heartbeat-sec = <16>;
- atmel,min-heartbeat-sec = <0>;
- status = "okay";
- };
- };
-
- nand0: nand@40000000 {
- nand-bus-width = <8>;
- nand-ecc-mode = "soft";
- status = "okay";
-
- bootloaderkernel@0 {
- label = "bootloader-kernel";
- reg = <0x0 0xc0000>;
- };
-
- ubi@c0000 {
- label = "ubi";
- reg = <0xc0000 0x7f40000>;
- };
-
- };
-
- usb0: ohci@00500000 {
- num-ports = <1>;
- status = "okay";
- };
- };
-
- i2c@0 {
- status = "okay";
-
- pcf8563@51 {
- /* nxp pcf8563 rtc */
- compatible = "nxp,pcf8563";
- reg = <0x51>;
- };
-
- };
-
- leds {
- compatible = "gpio-leds";
-
- led1g {
- label = "led1:green";
- gpios = <&pioB 0 GPIO_ACTIVE_LOW>;
- linux,default-trigger = "none";
- };
-
- led1r {
- label = "led1:red";
- gpios = <&pioB 1 GPIO_ACTIVE_LOW>;
- linux,default-trigger = "none";
- };
-
- led2g {
- label = "led2:green";
- gpios = <&pioB 2 GPIO_ACTIVE_LOW>;
- linux,default-trigger = "none";
- default-state = "on";
- };
-
- led2r {
- label = "led2:red";
- gpios = <&pioB 3 GPIO_ACTIVE_LOW>;
- linux,default-trigger = "none";
- };
- };
-
- gpio_keys {
- compatible = "gpio-keys";
- #address-cells = <1>;
- #size-cells = <0>;
-
- reset {
- label = "reset";
- gpios = <&pioB 30 GPIO_ACTIVE_LOW>;
- linux,code = <0x100>;
- gpio-key,wakeup;
- };
-
- mode {
- label = "mode";
- gpios = <&pioB 31 GPIO_ACTIVE_LOW>;
- linux,code = <0x101>;
- gpio-key,wakeup;
- };
- };
-};
diff --git a/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts b/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts
new file mode 100644
index 000000000000..91146c318798
--- /dev/null
+++ b/arch/arm/boot/dts/logicpd-torpedo-37xx-devkit.dts
@@ -0,0 +1,157 @@
+/*
+ * 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 "omap36xx.dtsi"
+#include "logicpd-torpedo-som.dtsi"
+#include "omap-gpmc-smsc9221.dtsi"
+
+/ {
+ model = "LogicPD Zoom DM3730 Torpedo Development Kit";
+ compatible = "logicpd,dm3730-torpedo-devkit", "ti,omap36xx";
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio_key_pins &gpio_key_pins_wkup>;
+
+ sysboot2 {
+ label = "sysboot2";
+ gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; /* gpio2 */
+ linux,code = <BTN_0>;
+ gpio-key,wakeup;
+ };
+
+ sysboot5 {
+ label = "sysboot5";
+ gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; /* gpio7 */
+ linux,code = <BTN_1>;
+ gpio-key,wakeup;
+ };
+
+ gpio1 {
+ label = "gpio1";
+ gpios = <&gpio6 21 GPIO_ACTIVE_LOW>; /* gpio181 */
+ linux,code = <BTN_2>;
+ gpio-key,wakeup;
+ };
+
+ gpio2 {
+ label = "gpio2";
+ gpios = <&gpio6 18 GPIO_ACTIVE_LOW>; /* gpio178 */
+ linux,code = <BTN_3>;
+ gpio-key,wakeup;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins>;
+
+ led1 {
+ label = "led1";
+ gpios = <&gpio6 20 GPIO_ACTIVE_HIGH>; /* gpio180 */
+ linux,default-trigger = "cpu0";
+ };
+
+ led2 {
+ label = "led2";
+ gpios = <&gpio6 19 GPIO_ACTIVE_HIGH>; /* gpio179 */
+ linux,default-trigger = "none";
+ };
+ };
+};
+
+&charger {
+ ti,bb-uvolt = <3200000>;
+ ti,bb-uamp = <150>;
+};
+
+&gpmc {
+ ranges = <1 0 0x08000000 0x1000000>; /* CS1: 16MB for LAN9221 */
+
+ ethernet@gpmc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&lan9221_pins>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <1 IRQ_TYPE_LEVEL_LOW>; /* gpio129 */
+ reg = <1 0 0xff>;
+ };
+};
+
+&mmc1 {
+ interrupts-extended = <&intc 83 &omap3_pmx_core 0x11a>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins &mmc1_cd>;
+ cd-gpios = <&gpio4 31 IRQ_TYPE_LEVEL_LOW>; /* gpio127 */
+ vmmc-supply = <&vmmc1>;
+ bus-width = <4>;
+ cap-power-off-card;
+};
+
+&omap3_pmx_core {
+ gpio_key_pins: pinmux_gpio_key_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x21d6, PIN_INPUT_PULLUP | MUX_MODE4) /* mcspi2_clk.gpio_178 */
+ OMAP3_CORE1_IOPAD(0x21dc, PIN_INPUT_PULLUP | MUX_MODE4) /* mcspi2_cs0.gpio_181 */
+ >;
+ };
+
+ led_pins: pinmux_led_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x21d8, PIN_OUTPUT | MUX_MODE4) /* gpio_179 */
+ OMAP3_CORE1_IOPAD(0x21da, PIN_OUTPUT | MUX_MODE4) /* gpio_180 */
+ >;
+ };
+
+ mmc1_pins: pinmux_mmc1_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x2144, PIN_OUTPUT | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */
+ OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */
+ OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */
+ OMAP3_CORE1_IOPAD(0x214a, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */
+ OMAP3_CORE1_IOPAD(0x214c, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */
+ OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */
+ >;
+ };
+};
+
+&omap3_pmx_wkup {
+ gpio_key_pins_wkup: pinmux_gpio_key_pins_wkup {
+ pinctrl-single,pins = <
+ OMAP3_WKUP_IOPAD(0x2a0a, PIN_INPUT_PULLUP | MUX_MODE4) /* sys_boot0.gpio_2 */
+ OMAP3_WKUP_IOPAD(0x2a14, PIN_INPUT_PULLUP | MUX_MODE4) /* sys_boot5.gpio_7 */
+ >;
+ };
+
+ lan9221_pins: pinmux_lan9221_pins {
+ pinctrl-single,pins = <
+ OMAP3_WKUP_IOPAD(0x2a5a, PIN_INPUT | MUX_MODE4) /* reserved.gpio_129 */
+ >;
+ };
+
+ mmc1_cd: pinmux_mmc1_cd {
+ pinctrl-single,pins = <
+ OMAP3_WKUP_IOPAD(0x2a54, PIN_INPUT_PULLUP | MUX_MODE4) /* reserved.gpio_127 */
+ >;
+ };
+};
+
+&uart1 {
+ interrupts-extended = <&intc 72 &omap3_pmx_core OMAP3_UART1_RX>;
+};
+
+/* Wired to the tps65950 on the SOM, only the USB connector is on the devkit */
+&usb_otg_hs {
+ interface-type = <0>;
+ usb-phy = <&usb2_phy>;
+ phys = <&usb2_phy>;
+ phy-names = "usb2-phy";
+ mode = <3>;
+ power = <50>;
+};
diff --git a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
new file mode 100644
index 000000000000..36387b11451d
--- /dev/null
+++ b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi
@@ -0,0 +1,162 @@
+/*
+ * 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 <dt-bindings/input/input.h>
+
+/ {
+ cpus {
+ cpu@0 {
+ cpu0-supply = <&vcc>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ user0 {
+ label = "user0";
+ gpios = <&twl_gpio 18 GPIO_ACTIVE_LOW>; /* LEDA */
+ linux,default-trigger = "none";
+ };
+ };
+
+ wl12xx_vmmc: wl12xx_vmmc {
+ compatible = "regulator-fixed";
+ regulator-name = "vwl1271";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ gpio = <&gpio5 29 0>; /* gpio157 */
+ startup-delay-us = <70000>;
+ enable-active-high;
+ vin-supply = <&vmmc2>;
+ };
+};
+
+&gpmc {
+ ranges = <0 0 0x00000000 0x1000000>; /* CS0: 16MB for NAND */
+
+ nand@0,0 {
+ linux,mtd-name = "micron,mt29f4g16abbda3w";
+ reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
+ nand-bus-width = <16>;
+ ti,nand-ecc-opt = "bch8";
+ 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-off-ns = <40>;
+ gpmc,oe-off-ns = <54>;
+ gpmc,access-ns = <64>;
+ gpmc,rd-cycle-ns = <82>;
+ gpmc,wr-cycle-ns = <82>;
+ gpmc,wr-access-ns = <40>;
+ gpmc,wr-data-mux-bus-ns = <0>;
+ gpmc,device-width = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* u-boot uses mtdparts=omap2-nand.0:512k(x-loader),1920k(u-boot),128k(u-boot-env),4m(kernel),-(fs) */
+
+ x-loader@0 {
+ label = "x-loader";
+ reg = <0 0x80000>;
+ };
+
+ bootloaders@80000 {
+ label = "u-boot";
+ reg = <0x80000 0x1e0000>;
+ };
+
+ bootloaders_env@260000 {
+ label = "u-boot-env";
+ reg = <0x260000 0x20000>;
+ };
+
+ kernel@280000 {
+ label = "kernel";
+ reg = <0x280000 0x400000>;
+ };
+
+ filesystem@680000 {
+ label = "fs";
+ reg = <0x680000 0>; /* 0 = MTDPART_SIZ_FULL */
+ };
+ };
+};
+
+&i2c1 {
+ clock-frequency = <2600000>;
+
+ twl: twl@48 {
+ reg = <0x48>;
+ interrupts = <7>; /* SYS_NIRQ cascaded to intc */
+ interrupt-parent = <&intc>;
+ };
+};
+
+/*
+ * 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
+ * gpio157 is not connected. So this should be OK to keep common for now,
+ * probably device tree overlays is the way to go with the various SOM and
+ * jumpering combinations for the long run.
+ */
+&mmc3 {
+ interrupts-extended = <&intc 94 &omap3_pmx_core2 0x46>;
+ pinctrl-0 = <&mmc3_pins &mmc3_core2_pins>;
+ pinctrl-names = "default";
+ vmmc-supply = <&wl12xx_vmmc>;
+ non-removable;
+ bus-width = <4>;
+ cap-power-off-card;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wlcore: wlcore@2 {
+ compatible = "ti,wl1283";
+ reg = <2>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; /* gpio 152 */
+ ref-clock-frequency = <26000000>;
+ };
+};
+
+&omap3_pmx_core {
+ mmc3_pins: pinmux_mm3_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x2164, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat4.sdmmc3_dat0 */
+ OMAP3_CORE1_IOPAD(0x2166, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat5.sdmmc3_dat1 */
+ OMAP3_CORE1_IOPAD(0x2168, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat6.sdmmc3_dat2 */
+ OMAP3_CORE1_IOPAD(0x216a, PIN_INPUT_PULLUP | MUX_MODE3) /* sdmmc2_dat6.sdmmc3_dat3 */
+ OMAP3_CORE1_IOPAD(0x2184, PIN_INPUT_PULLUP | MUX_MODE4) /* mcbsp4_clkx.gpio_152 */
+ OMAP3_CORE1_IOPAD(0x218e, PIN_OUTPUT | MUX_MODE4) /* mcbsp1_fsr.gpio_157 */
+ >;
+ };
+};
+
+&omap3_pmx_core2 {
+ mmc3_core2_pins: pinmux_mmc3_core2_pins {
+ pinctrl-single,pins = <
+ OMAP3630_CORE2_IOPAD(0x25d8, PIN_INPUT_PULLUP | MUX_MODE2) /* etk_clk.sdmmc3_clk */
+ OMAP3630_CORE2_IOPAD(0x25da, PIN_INPUT_PULLUP | MUX_MODE2) /* etk_ctl.sdmmc3_cmd */
+ >;
+ };
+};
+
+#include "twl4030.dtsi"
+#include "twl4030_omap3.dtsi"
+
+&twl {
+ twl_power: power {
+ compatible = "ti,twl4030-power-idle-osc-off", "ti,twl4030-power-idle";
+ ti,use_poweroff;
+ };
+};
+
+&twl_gpio {
+ ti,use-leds;
+};
diff --git a/arch/arm/boot/dts/lpc18xx.dtsi b/arch/arm/boot/dts/lpc18xx.dtsi
new file mode 100644
index 000000000000..204da5b52ef9
--- /dev/null
+++ b/arch/arm/boot/dts/lpc18xx.dtsi
@@ -0,0 +1,114 @@
+/*
+ * Common base for NXP LPC18xx and LPC43xx devices.
+ *
+ * Copyright 2015 Joachim Eastwood <manabian@gmail.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
+ *
+ */
+
+#include "armv7-m.dtsi"
+
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "arm,cortex-m3";
+ device_type = "cpu";
+ reg = <0x0>;
+ };
+ };
+
+ clocks {
+ xtal: xtal {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <12000000>;
+ };
+
+ /* Temporary hardcode PLL1 until clk drivers are merged */
+ pll1: pll1 {
+ compatible = "fixed-factor-clock";
+ clocks = <&xtal>;
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <12>;
+ };
+ };
+
+ soc {
+ uart0: serial@40081000 {
+ compatible = "ns16550a";
+ reg = <0x40081000 0x1000>;
+ reg-shift = <2>;
+ interrupts = <24>;
+ clocks = <&pll1>;
+ status = "disabled";
+ };
+
+ uart1: serial@40082000 {
+ compatible = "ns16550a";
+ reg = <0x40082000 0x1000>;
+ reg-shift = <2>;
+ interrupts = <25>;
+ clocks = <&pll1>;
+ status = "disabled";
+ };
+
+ timer0: timer@40084000 {
+ compatible = "nxp,lpc3220-timer";
+ reg = <0x40084000 0x1000>;
+ interrupts = <12>;
+ clocks = <&pll1>;
+ clock-names = "timerclk";
+ };
+
+ timer1: timer@40085000 {
+ compatible = "nxp,lpc3220-timer";
+ reg = <0x40085000 0x1000>;
+ interrupts = <13>;
+ clocks = <&pll1>;
+ clock-names = "timerclk";
+ };
+
+ uart2: serial@400c1000 {
+ compatible = "ns16550a";
+ reg = <0x400c1000 0x1000>;
+ reg-shift = <2>;
+ interrupts = <26>;
+ clocks = <&pll1>;
+ status = "disabled";
+ };
+
+ uart3: serial@400c2000 {
+ compatible = "ns16550a";
+ reg = <0x400c2000 0x1000>;
+ reg-shift = <2>;
+ interrupts = <27>;
+ clocks = <&pll1>;
+ status = "disabled";
+ };
+
+ timer2: timer@400c3000 {
+ compatible = "nxp,lpc3220-timer";
+ reg = <0x400c3000 0x1000>;
+ interrupts = <14>;
+ clocks = <&pll1>;
+ clock-names = "timerclk";
+ };
+
+ timer3: timer@400c4000 {
+ compatible = "nxp,lpc3220-timer";
+ reg = <0x400c4000 0x1000>;
+ interrupts = <15>;
+ clocks = <&pll1>;
+ clock-names = "timerclk";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/lpc4350-hitex-eval.dts b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
new file mode 100644
index 000000000000..d04072f40817
--- /dev/null
+++ b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
@@ -0,0 +1,45 @@
+/*
+ * Hitex LPC4350 Evaluation Board
+ *
+ * Copyright 2015 Ariel D'Alessandro <ariel.dalessandro@gmail.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
+ *
+ */
+/dts-v1/;
+
+#include "lpc18xx.dtsi"
+#include "lpc4350.dtsi"
+
+/ {
+ model = "Hitex LPC4350 Evaluation Board";
+ compatible = "hitex,lpc4350-eval-board", "nxp,lpc4350";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ serial3 = &uart3;
+ };
+
+ chosen {
+ stdout-path = &uart0;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x28000000 0x800000>; /* 8 MB */
+ };
+};
+
+&pll1 {
+ clock-mult = <15>;
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/lpc4350.dtsi b/arch/arm/boot/dts/lpc4350.dtsi
new file mode 100644
index 000000000000..c4422f587055
--- /dev/null
+++ b/arch/arm/boot/dts/lpc4350.dtsi
@@ -0,0 +1,39 @@
+/*
+ * NXP LPC4350 and LPC4330 SoC
+ *
+ * Copyright 2015 Ariel D'Alessandro <ariel.dalessandro@gmail.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
+ *
+ */
+
+/ {
+ compatible = "nxp,lpc4350", "nxp,lpc4330";
+
+ cpus {
+ cpu@0 {
+ compatible = "arm,cortex-m4";
+ };
+ };
+
+ soc {
+ sram0: sram@10000000 {
+ compatible = "mmio-sram";
+ reg = <0x10000000 0x20000>; /* 96 + 32 KiB local SRAM */
+ };
+
+ sram1: sram@10080000 {
+ compatible = "mmio-sram";
+ reg = <0x10080000 0x12000>; /* 64 + 8 KiB local SRAM */
+ };
+
+ sram2: sram@20000000 {
+ compatible = "mmio-sram";
+ reg = <0x20000000 0x10000>; /* 4 x 16 KiB AHB SRAM */
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts b/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
new file mode 100644
index 000000000000..08a6f757f924
--- /dev/null
+++ b/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
@@ -0,0 +1,41 @@
+/*
+ * Embedded Artist LPC4357 Developer's Kit
+ *
+ * Copyright 2015 Joachim Eastwood <manabian@gmail.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
+ *
+ */
+/dts-v1/;
+
+#include "lpc18xx.dtsi"
+#include "lpc4357.dtsi"
+
+/ {
+ model = "Embedded Artists' LPC4357 Developer's Kit";
+ compatible = "ea,lpc4357-developers-kit", "nxp,lpc4357", "nxp,lpc4350";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ serial3 = &uart3;
+ };
+
+ chosen {
+ stdout-path = &uart0;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x28000000 0x2000000>; /* 32 MB */
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/lpc4357.dtsi b/arch/arm/boot/dts/lpc4357.dtsi
new file mode 100644
index 000000000000..fb9ecc754e8d
--- /dev/null
+++ b/arch/arm/boot/dts/lpc4357.dtsi
@@ -0,0 +1,39 @@
+/*
+ * NXP LPC435x, LPC433x, LPC4327, LPC4325, LPC4317 and LPC4315 SoC
+ *
+ * Copyright 2015 Joachim Eastwood <manabian@gmail.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
+ *
+ */
+
+/ {
+ compatible = "nxp,lpc4357";
+
+ cpus {
+ cpu@0 {
+ compatible = "arm,cortex-m4";
+ };
+ };
+
+ soc {
+ sram0: sram@10000000 {
+ compatible = "mmio-sram";
+ reg = <0x10000000 0x8000>; /* 32 KiB local SRAM */
+ };
+
+ sram1: sram@10080000 {
+ compatible = "mmio-sram";
+ reg = <0x10080000 0xa000>; /* 32 + 8 KiB local SRAM */
+ };
+
+ sram2: sram@20000000 {
+ compatible = "mmio-sram";
+ reg = <0x20000000 0x10000>; /* 4 x 16 KiB AHB SRAM */
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/mt8127.dtsi b/arch/arm/boot/dts/mt8127.dtsi
index aaa786233d93..ca3402e8240b 100644
--- a/arch/arm/boot/dts/mt8127.dtsi
+++ b/arch/arm/boot/dts/mt8127.dtsi
@@ -107,7 +107,7 @@
<0 0x10216000 0 0x2000>;
};
- uart0: serial@11006000 {
+ uart0: serial@11002000 {
compatible = "mediatek,mt8127-uart","mediatek,mt6577-uart";
reg = <0 0x11002000 0 0x400>;
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
@@ -115,7 +115,7 @@
status = "disabled";
};
- uart1: serial@11007000 {
+ uart1: serial@11003000 {
compatible = "mediatek,mt8127-uart","mediatek,mt6577-uart";
reg = <0 0x11003000 0 0x400>;
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_LOW>;
@@ -123,7 +123,7 @@
status = "disabled";
};
- uart2: serial@11008000 {
+ uart2: serial@11004000 {
compatible = "mediatek,mt8127-uart","mediatek,mt6577-uart";
reg = <0 0x11004000 0 0x400>;
interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_LOW>;
@@ -131,7 +131,7 @@
status = "disabled";
};
- uart3: serial@11009000 {
+ uart3: serial@11005000 {
compatible = "mediatek,mt8127-uart","mediatek,mt6577-uart";
reg = <0 0x11005000 0 0x400>;
interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_LOW>;
diff --git a/arch/arm/boot/dts/mt8135-pinfunc.h b/arch/arm/boot/dts/mt8135-pinfunc.h
new file mode 100644
index 000000000000..5a609875cb18
--- /dev/null
+++ b/arch/arm/boot/dts/mt8135-pinfunc.h
@@ -0,0 +1,1302 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Hongzhou.Yang <hongzhou.yang@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.
+ */
+
+#ifndef __DTS_MT8135_PINFUNC_H
+#define __DTS_MT8135_PINFUNC_H
+
+#include <dt-bindings/pinctrl/mt65xx.h>
+
+#define MT8135_PIN_0_MSDC0_DAT7__FUNC_GPIO0 (MTK_PIN_NO(0) | 0)
+#define MT8135_PIN_0_MSDC0_DAT7__FUNC_MSDC0_DAT7 (MTK_PIN_NO(0) | 1)
+#define MT8135_PIN_0_MSDC0_DAT7__FUNC_EINT49 (MTK_PIN_NO(0) | 2)
+#define MT8135_PIN_0_MSDC0_DAT7__FUNC_I2SOUT_DAT (MTK_PIN_NO(0) | 3)
+#define MT8135_PIN_0_MSDC0_DAT7__FUNC_DAC_DAT_OUT (MTK_PIN_NO(0) | 4)
+#define MT8135_PIN_0_MSDC0_DAT7__FUNC_PCM1_DO (MTK_PIN_NO(0) | 5)
+#define MT8135_PIN_0_MSDC0_DAT7__FUNC_SPI1_MO (MTK_PIN_NO(0) | 6)
+#define MT8135_PIN_0_MSDC0_DAT7__FUNC_NALE (MTK_PIN_NO(0) | 7)
+
+#define MT8135_PIN_1_MSDC0_DAT6__FUNC_GPIO1 (MTK_PIN_NO(1) | 0)
+#define MT8135_PIN_1_MSDC0_DAT6__FUNC_MSDC0_DAT6 (MTK_PIN_NO(1) | 1)
+#define MT8135_PIN_1_MSDC0_DAT6__FUNC_EINT48 (MTK_PIN_NO(1) | 2)
+#define MT8135_PIN_1_MSDC0_DAT6__FUNC_I2SIN_WS (MTK_PIN_NO(1) | 3)
+#define MT8135_PIN_1_MSDC0_DAT6__FUNC_DAC_WS (MTK_PIN_NO(1) | 4)
+#define MT8135_PIN_1_MSDC0_DAT6__FUNC_PCM1_WS (MTK_PIN_NO(1) | 5)
+#define MT8135_PIN_1_MSDC0_DAT6__FUNC_SPI1_CSN (MTK_PIN_NO(1) | 6)
+#define MT8135_PIN_1_MSDC0_DAT6__FUNC_NCLE (MTK_PIN_NO(1) | 7)
+
+#define MT8135_PIN_2_MSDC0_DAT5__FUNC_GPIO2 (MTK_PIN_NO(2) | 0)
+#define MT8135_PIN_2_MSDC0_DAT5__FUNC_MSDC0_DAT5 (MTK_PIN_NO(2) | 1)
+#define MT8135_PIN_2_MSDC0_DAT5__FUNC_EINT47 (MTK_PIN_NO(2) | 2)
+#define MT8135_PIN_2_MSDC0_DAT5__FUNC_I2SIN_CK (MTK_PIN_NO(2) | 3)
+#define MT8135_PIN_2_MSDC0_DAT5__FUNC_DAC_CK (MTK_PIN_NO(2) | 4)
+#define MT8135_PIN_2_MSDC0_DAT5__FUNC_PCM1_CK (MTK_PIN_NO(2) | 5)
+#define MT8135_PIN_2_MSDC0_DAT5__FUNC_SPI1_CLK (MTK_PIN_NO(2) | 6)
+#define MT8135_PIN_2_MSDC0_DAT5__FUNC_NLD4 (MTK_PIN_NO(2) | 7)
+
+#define MT8135_PIN_3_MSDC0_DAT4__FUNC_GPIO3 (MTK_PIN_NO(3) | 0)
+#define MT8135_PIN_3_MSDC0_DAT4__FUNC_MSDC0_DAT4 (MTK_PIN_NO(3) | 1)
+#define MT8135_PIN_3_MSDC0_DAT4__FUNC_EINT46 (MTK_PIN_NO(3) | 2)
+#define MT8135_PIN_3_MSDC0_DAT4__FUNC_A_FUNC_CK (MTK_PIN_NO(3) | 3)
+#define MT8135_PIN_3_MSDC0_DAT4__FUNC_LSCE1B_2X (MTK_PIN_NO(3) | 6)
+#define MT8135_PIN_3_MSDC0_DAT4__FUNC_NLD5 (MTK_PIN_NO(3) | 7)
+
+#define MT8135_PIN_4_MSDC0_CMD__FUNC_GPIO4 (MTK_PIN_NO(4) | 0)
+#define MT8135_PIN_4_MSDC0_CMD__FUNC_MSDC0_CMD (MTK_PIN_NO(4) | 1)
+#define MT8135_PIN_4_MSDC0_CMD__FUNC_EINT41 (MTK_PIN_NO(4) | 2)
+#define MT8135_PIN_4_MSDC0_CMD__FUNC_A_FUNC_DOUT_0 (MTK_PIN_NO(4) | 3)
+#define MT8135_PIN_4_MSDC0_CMD__FUNC_USB_TEST_IO_0 (MTK_PIN_NO(4) | 5)
+#define MT8135_PIN_4_MSDC0_CMD__FUNC_LRSTB_2X (MTK_PIN_NO(4) | 6)
+#define MT8135_PIN_4_MSDC0_CMD__FUNC_NRNB (MTK_PIN_NO(4) | 7)
+
+#define MT8135_PIN_5_MSDC0_CLK__FUNC_GPIO5 (MTK_PIN_NO(5) | 0)
+#define MT8135_PIN_5_MSDC0_CLK__FUNC_MSDC0_CLK (MTK_PIN_NO(5) | 1)
+#define MT8135_PIN_5_MSDC0_CLK__FUNC_EINT40 (MTK_PIN_NO(5) | 2)
+#define MT8135_PIN_5_MSDC0_CLK__FUNC_A_FUNC_DOUT_1 (MTK_PIN_NO(5) | 3)
+#define MT8135_PIN_5_MSDC0_CLK__FUNC_USB_TEST_IO_1 (MTK_PIN_NO(5) | 5)
+#define MT8135_PIN_5_MSDC0_CLK__FUNC_LPTE (MTK_PIN_NO(5) | 6)
+#define MT8135_PIN_5_MSDC0_CLK__FUNC_NREB (MTK_PIN_NO(5) | 7)
+
+#define MT8135_PIN_6_MSDC0_DAT3__FUNC_GPIO6 (MTK_PIN_NO(6) | 0)
+#define MT8135_PIN_6_MSDC0_DAT3__FUNC_MSDC0_DAT3 (MTK_PIN_NO(6) | 1)
+#define MT8135_PIN_6_MSDC0_DAT3__FUNC_EINT45 (MTK_PIN_NO(6) | 2)
+#define MT8135_PIN_6_MSDC0_DAT3__FUNC_A_FUNC_DOUT_2 (MTK_PIN_NO(6) | 3)
+#define MT8135_PIN_6_MSDC0_DAT3__FUNC_USB_TEST_IO_2 (MTK_PIN_NO(6) | 5)
+#define MT8135_PIN_6_MSDC0_DAT3__FUNC_LSCE0B_2X (MTK_PIN_NO(6) | 6)
+#define MT8135_PIN_6_MSDC0_DAT3__FUNC_NLD7 (MTK_PIN_NO(6) | 7)
+
+#define MT8135_PIN_7_MSDC0_DAT2__FUNC_GPIO7 (MTK_PIN_NO(7) | 0)
+#define MT8135_PIN_7_MSDC0_DAT2__FUNC_MSDC0_DAT2 (MTK_PIN_NO(7) | 1)
+#define MT8135_PIN_7_MSDC0_DAT2__FUNC_EINT44 (MTK_PIN_NO(7) | 2)
+#define MT8135_PIN_7_MSDC0_DAT2__FUNC_A_FUNC_DOUT_3 (MTK_PIN_NO(7) | 3)
+#define MT8135_PIN_7_MSDC0_DAT2__FUNC_USB_TEST_IO_3 (MTK_PIN_NO(7) | 5)
+#define MT8135_PIN_7_MSDC0_DAT2__FUNC_LSA0_2X (MTK_PIN_NO(7) | 6)
+#define MT8135_PIN_7_MSDC0_DAT2__FUNC_NLD14 (MTK_PIN_NO(7) | 7)
+
+#define MT8135_PIN_8_MSDC0_DAT1__FUNC_GPIO8 (MTK_PIN_NO(8) | 0)
+#define MT8135_PIN_8_MSDC0_DAT1__FUNC_MSDC0_DAT1 (MTK_PIN_NO(8) | 1)
+#define MT8135_PIN_8_MSDC0_DAT1__FUNC_EINT43 (MTK_PIN_NO(8) | 2)
+#define MT8135_PIN_8_MSDC0_DAT1__FUNC_USB_TEST_IO_4 (MTK_PIN_NO(8) | 5)
+#define MT8135_PIN_8_MSDC0_DAT1__FUNC_LSCK_2X (MTK_PIN_NO(8) | 6)
+#define MT8135_PIN_8_MSDC0_DAT1__FUNC_NLD11 (MTK_PIN_NO(8) | 7)
+
+#define MT8135_PIN_9_MSDC0_DAT0__FUNC_GPIO9 (MTK_PIN_NO(9) | 0)
+#define MT8135_PIN_9_MSDC0_DAT0__FUNC_MSDC0_DAT0 (MTK_PIN_NO(9) | 1)
+#define MT8135_PIN_9_MSDC0_DAT0__FUNC_EINT42 (MTK_PIN_NO(9) | 2)
+#define MT8135_PIN_9_MSDC0_DAT0__FUNC_USB_TEST_IO_5 (MTK_PIN_NO(9) | 5)
+#define MT8135_PIN_9_MSDC0_DAT0__FUNC_LSDA_2X (MTK_PIN_NO(9) | 6)
+
+#define MT8135_PIN_10_NCEB0__FUNC_GPIO10 (MTK_PIN_NO(10) | 0)
+#define MT8135_PIN_10_NCEB0__FUNC_NCEB0 (MTK_PIN_NO(10) | 1)
+#define MT8135_PIN_10_NCEB0__FUNC_EINT139 (MTK_PIN_NO(10) | 2)
+#define MT8135_PIN_10_NCEB0__FUNC_TESTA_OUT4 (MTK_PIN_NO(10) | 7)
+
+#define MT8135_PIN_11_NCEB1__FUNC_GPIO11 (MTK_PIN_NO(11) | 0)
+#define MT8135_PIN_11_NCEB1__FUNC_NCEB1 (MTK_PIN_NO(11) | 1)
+#define MT8135_PIN_11_NCEB1__FUNC_EINT140 (MTK_PIN_NO(11) | 2)
+#define MT8135_PIN_11_NCEB1__FUNC_USB_DRVVBUS (MTK_PIN_NO(11) | 6)
+#define MT8135_PIN_11_NCEB1__FUNC_TESTA_OUT5 (MTK_PIN_NO(11) | 7)
+
+#define MT8135_PIN_12_NRNB__FUNC_GPIO12 (MTK_PIN_NO(12) | 0)
+#define MT8135_PIN_12_NRNB__FUNC_NRNB (MTK_PIN_NO(12) | 1)
+#define MT8135_PIN_12_NRNB__FUNC_EINT141 (MTK_PIN_NO(12) | 2)
+#define MT8135_PIN_12_NRNB__FUNC_A_FUNC_DOUT_4 (MTK_PIN_NO(12) | 3)
+#define MT8135_PIN_12_NRNB__FUNC_TESTA_OUT6 (MTK_PIN_NO(12) | 7)
+
+#define MT8135_PIN_13_NCLE__FUNC_GPIO13 (MTK_PIN_NO(13) | 0)
+#define MT8135_PIN_13_NCLE__FUNC_NCLE (MTK_PIN_NO(13) | 1)
+#define MT8135_PIN_13_NCLE__FUNC_EINT142 (MTK_PIN_NO(13) | 2)
+#define MT8135_PIN_13_NCLE__FUNC_A_FUNC_DOUT_5 (MTK_PIN_NO(13) | 3)
+#define MT8135_PIN_13_NCLE__FUNC_CM2PDN_1X (MTK_PIN_NO(13) | 4)
+#define MT8135_PIN_13_NCLE__FUNC_NALE (MTK_PIN_NO(13) | 6)
+#define MT8135_PIN_13_NCLE__FUNC_TESTA_OUT7 (MTK_PIN_NO(13) | 7)
+
+#define MT8135_PIN_14_NALE__FUNC_GPIO14 (MTK_PIN_NO(14) | 0)
+#define MT8135_PIN_14_NALE__FUNC_NALE (MTK_PIN_NO(14) | 1)
+#define MT8135_PIN_14_NALE__FUNC_EINT143 (MTK_PIN_NO(14) | 2)
+#define MT8135_PIN_14_NALE__FUNC_A_FUNC_DOUT_6 (MTK_PIN_NO(14) | 3)
+#define MT8135_PIN_14_NALE__FUNC_CM2MCLK_1X (MTK_PIN_NO(14) | 4)
+#define MT8135_PIN_14_NALE__FUNC_IRDA_RXD (MTK_PIN_NO(14) | 5)
+#define MT8135_PIN_14_NALE__FUNC_NCLE (MTK_PIN_NO(14) | 6)
+#define MT8135_PIN_14_NALE__FUNC_TESTA_OUT8 (MTK_PIN_NO(14) | 7)
+
+#define MT8135_PIN_15_NREB__FUNC_GPIO15 (MTK_PIN_NO(15) | 0)
+#define MT8135_PIN_15_NREB__FUNC_NREB (MTK_PIN_NO(15) | 1)
+#define MT8135_PIN_15_NREB__FUNC_EINT144 (MTK_PIN_NO(15) | 2)
+#define MT8135_PIN_15_NREB__FUNC_A_FUNC_DOUT_7 (MTK_PIN_NO(15) | 3)
+#define MT8135_PIN_15_NREB__FUNC_CM2RST_1X (MTK_PIN_NO(15) | 4)
+#define MT8135_PIN_15_NREB__FUNC_IRDA_TXD (MTK_PIN_NO(15) | 5)
+#define MT8135_PIN_15_NREB__FUNC_TESTA_OUT9 (MTK_PIN_NO(15) | 7)
+
+#define MT8135_PIN_16_NWEB__FUNC_GPIO16 (MTK_PIN_NO(16) | 0)
+#define MT8135_PIN_16_NWEB__FUNC_NWEB (MTK_PIN_NO(16) | 1)
+#define MT8135_PIN_16_NWEB__FUNC_EINT145 (MTK_PIN_NO(16) | 2)
+#define MT8135_PIN_16_NWEB__FUNC_A_FUNC_DIN_0 (MTK_PIN_NO(16) | 3)
+#define MT8135_PIN_16_NWEB__FUNC_CM2PCLK_1X (MTK_PIN_NO(16) | 4)
+#define MT8135_PIN_16_NWEB__FUNC_IRDA_PDN (MTK_PIN_NO(16) | 5)
+#define MT8135_PIN_16_NWEB__FUNC_TESTA_OUT10 (MTK_PIN_NO(16) | 7)
+
+#define MT8135_PIN_17_NLD0__FUNC_GPIO17 (MTK_PIN_NO(17) | 0)
+#define MT8135_PIN_17_NLD0__FUNC_NLD0 (MTK_PIN_NO(17) | 1)
+#define MT8135_PIN_17_NLD0__FUNC_EINT146 (MTK_PIN_NO(17) | 2)
+#define MT8135_PIN_17_NLD0__FUNC_A_FUNC_DIN_1 (MTK_PIN_NO(17) | 3)
+#define MT8135_PIN_17_NLD0__FUNC_CM2DAT_1X_0 (MTK_PIN_NO(17) | 4)
+#define MT8135_PIN_17_NLD0__FUNC_I2SIN_CK (MTK_PIN_NO(17) | 5)
+#define MT8135_PIN_17_NLD0__FUNC_DAC_CK (MTK_PIN_NO(17) | 6)
+#define MT8135_PIN_17_NLD0__FUNC_TESTA_OUT11 (MTK_PIN_NO(17) | 7)
+
+#define MT8135_PIN_18_NLD1__FUNC_GPIO18 (MTK_PIN_NO(18) | 0)
+#define MT8135_PIN_18_NLD1__FUNC_NLD1 (MTK_PIN_NO(18) | 1)
+#define MT8135_PIN_18_NLD1__FUNC_EINT147 (MTK_PIN_NO(18) | 2)
+#define MT8135_PIN_18_NLD1__FUNC_A_FUNC_DIN_2 (MTK_PIN_NO(18) | 3)
+#define MT8135_PIN_18_NLD1__FUNC_CM2DAT_1X_1 (MTK_PIN_NO(18) | 4)
+#define MT8135_PIN_18_NLD1__FUNC_I2SIN_WS (MTK_PIN_NO(18) | 5)
+#define MT8135_PIN_18_NLD1__FUNC_DAC_WS (MTK_PIN_NO(18) | 6)
+#define MT8135_PIN_18_NLD1__FUNC_TESTA_OUT12 (MTK_PIN_NO(18) | 7)
+
+#define MT8135_PIN_19_NLD2__FUNC_GPIO19 (MTK_PIN_NO(19) | 0)
+#define MT8135_PIN_19_NLD2__FUNC_NLD2 (MTK_PIN_NO(19) | 1)
+#define MT8135_PIN_19_NLD2__FUNC_EINT148 (MTK_PIN_NO(19) | 2)
+#define MT8135_PIN_19_NLD2__FUNC_A_FUNC_DIN_3 (MTK_PIN_NO(19) | 3)
+#define MT8135_PIN_19_NLD2__FUNC_CM2DAT_1X_2 (MTK_PIN_NO(19) | 4)
+#define MT8135_PIN_19_NLD2__FUNC_I2SOUT_DAT (MTK_PIN_NO(19) | 5)
+#define MT8135_PIN_19_NLD2__FUNC_DAC_DAT_OUT (MTK_PIN_NO(19) | 6)
+#define MT8135_PIN_19_NLD2__FUNC_TESTA_OUT13 (MTK_PIN_NO(19) | 7)
+
+#define MT8135_PIN_20_NLD3__FUNC_GPIO20 (MTK_PIN_NO(20) | 0)
+#define MT8135_PIN_20_NLD3__FUNC_NLD3 (MTK_PIN_NO(20) | 1)
+#define MT8135_PIN_20_NLD3__FUNC_EINT149 (MTK_PIN_NO(20) | 2)
+#define MT8135_PIN_20_NLD3__FUNC_A_FUNC_DIN_4 (MTK_PIN_NO(20) | 3)
+#define MT8135_PIN_20_NLD3__FUNC_CM2DAT_1X_3 (MTK_PIN_NO(20) | 4)
+#define MT8135_PIN_20_NLD3__FUNC_TESTA_OUT14 (MTK_PIN_NO(20) | 7)
+
+#define MT8135_PIN_21_NLD4__FUNC_GPIO21 (MTK_PIN_NO(21) | 0)
+#define MT8135_PIN_21_NLD4__FUNC_NLD4 (MTK_PIN_NO(21) | 1)
+#define MT8135_PIN_21_NLD4__FUNC_EINT150 (MTK_PIN_NO(21) | 2)
+#define MT8135_PIN_21_NLD4__FUNC_A_FUNC_DIN_5 (MTK_PIN_NO(21) | 3)
+#define MT8135_PIN_21_NLD4__FUNC_CM2DAT_1X_4 (MTK_PIN_NO(21) | 4)
+#define MT8135_PIN_21_NLD4__FUNC_TESTA_OUT15 (MTK_PIN_NO(21) | 7)
+
+#define MT8135_PIN_22_NLD5__FUNC_GPIO22 (MTK_PIN_NO(22) | 0)
+#define MT8135_PIN_22_NLD5__FUNC_NLD5 (MTK_PIN_NO(22) | 1)
+#define MT8135_PIN_22_NLD5__FUNC_EINT151 (MTK_PIN_NO(22) | 2)
+#define MT8135_PIN_22_NLD5__FUNC_A_FUNC_DIN_6 (MTK_PIN_NO(22) | 3)
+#define MT8135_PIN_22_NLD5__FUNC_CM2DAT_1X_5 (MTK_PIN_NO(22) | 4)
+#define MT8135_PIN_22_NLD5__FUNC_TESTA_OUT16 (MTK_PIN_NO(22) | 7)
+
+#define MT8135_PIN_23_NLD6__FUNC_GPIO23 (MTK_PIN_NO(23) | 0)
+#define MT8135_PIN_23_NLD6__FUNC_NLD6 (MTK_PIN_NO(23) | 1)
+#define MT8135_PIN_23_NLD6__FUNC_EINT152 (MTK_PIN_NO(23) | 2)
+#define MT8135_PIN_23_NLD6__FUNC_A_FUNC_DIN_7 (MTK_PIN_NO(23) | 3)
+#define MT8135_PIN_23_NLD6__FUNC_CM2DAT_1X_6 (MTK_PIN_NO(23) | 4)
+#define MT8135_PIN_23_NLD6__FUNC_TESTA_OUT17 (MTK_PIN_NO(23) | 7)
+
+#define MT8135_PIN_24_NLD7__FUNC_GPIO24 (MTK_PIN_NO(24) | 0)
+#define MT8135_PIN_24_NLD7__FUNC_NLD7 (MTK_PIN_NO(24) | 1)
+#define MT8135_PIN_24_NLD7__FUNC_EINT153 (MTK_PIN_NO(24) | 2)
+#define MT8135_PIN_24_NLD7__FUNC_A_FUNC_DIN_8 (MTK_PIN_NO(24) | 3)
+#define MT8135_PIN_24_NLD7__FUNC_CM2DAT_1X_7 (MTK_PIN_NO(24) | 4)
+#define MT8135_PIN_24_NLD7__FUNC_TESTA_OUT18 (MTK_PIN_NO(24) | 7)
+
+#define MT8135_PIN_25_NLD8__FUNC_GPIO25 (MTK_PIN_NO(25) | 0)
+#define MT8135_PIN_25_NLD8__FUNC_NLD8 (MTK_PIN_NO(25) | 1)
+#define MT8135_PIN_25_NLD8__FUNC_EINT154 (MTK_PIN_NO(25) | 2)
+#define MT8135_PIN_25_NLD8__FUNC_CM2DAT_1X_8 (MTK_PIN_NO(25) | 4)
+
+#define MT8135_PIN_26_NLD9__FUNC_GPIO26 (MTK_PIN_NO(26) | 0)
+#define MT8135_PIN_26_NLD9__FUNC_NLD9 (MTK_PIN_NO(26) | 1)
+#define MT8135_PIN_26_NLD9__FUNC_EINT155 (MTK_PIN_NO(26) | 2)
+#define MT8135_PIN_26_NLD9__FUNC_CM2DAT_1X_9 (MTK_PIN_NO(26) | 4)
+#define MT8135_PIN_26_NLD9__FUNC_PWM1 (MTK_PIN_NO(26) | 5)
+
+#define MT8135_PIN_27_NLD10__FUNC_GPIO27 (MTK_PIN_NO(27) | 0)
+#define MT8135_PIN_27_NLD10__FUNC_NLD10 (MTK_PIN_NO(27) | 1)
+#define MT8135_PIN_27_NLD10__FUNC_EINT156 (MTK_PIN_NO(27) | 2)
+#define MT8135_PIN_27_NLD10__FUNC_CM2VSYNC_1X (MTK_PIN_NO(27) | 4)
+#define MT8135_PIN_27_NLD10__FUNC_PWM2 (MTK_PIN_NO(27) | 5)
+
+#define MT8135_PIN_28_NLD11__FUNC_GPIO28 (MTK_PIN_NO(28) | 0)
+#define MT8135_PIN_28_NLD11__FUNC_NLD11 (MTK_PIN_NO(28) | 1)
+#define MT8135_PIN_28_NLD11__FUNC_EINT157 (MTK_PIN_NO(28) | 2)
+#define MT8135_PIN_28_NLD11__FUNC_CM2HSYNC_1X (MTK_PIN_NO(28) | 4)
+#define MT8135_PIN_28_NLD11__FUNC_PWM3 (MTK_PIN_NO(28) | 5)
+
+#define MT8135_PIN_29_NLD12__FUNC_GPIO29 (MTK_PIN_NO(29) | 0)
+#define MT8135_PIN_29_NLD12__FUNC_NLD12 (MTK_PIN_NO(29) | 1)
+#define MT8135_PIN_29_NLD12__FUNC_EINT158 (MTK_PIN_NO(29) | 2)
+#define MT8135_PIN_29_NLD12__FUNC_I2SIN_CK (MTK_PIN_NO(29) | 3)
+#define MT8135_PIN_29_NLD12__FUNC_DAC_CK (MTK_PIN_NO(29) | 4)
+#define MT8135_PIN_29_NLD12__FUNC_PCM1_CK (MTK_PIN_NO(29) | 5)
+
+#define MT8135_PIN_30_NLD13__FUNC_GPIO30 (MTK_PIN_NO(30) | 0)
+#define MT8135_PIN_30_NLD13__FUNC_NLD13 (MTK_PIN_NO(30) | 1)
+#define MT8135_PIN_30_NLD13__FUNC_EINT159 (MTK_PIN_NO(30) | 2)
+#define MT8135_PIN_30_NLD13__FUNC_I2SIN_WS (MTK_PIN_NO(30) | 3)
+#define MT8135_PIN_30_NLD13__FUNC_DAC_WS (MTK_PIN_NO(30) | 4)
+#define MT8135_PIN_30_NLD13__FUNC_PCM1_WS (MTK_PIN_NO(30) | 5)
+
+#define MT8135_PIN_31_NLD14__FUNC_GPIO31 (MTK_PIN_NO(31) | 0)
+#define MT8135_PIN_31_NLD14__FUNC_NLD14 (MTK_PIN_NO(31) | 1)
+#define MT8135_PIN_31_NLD14__FUNC_EINT160 (MTK_PIN_NO(31) | 2)
+#define MT8135_PIN_31_NLD14__FUNC_I2SOUT_DAT (MTK_PIN_NO(31) | 3)
+#define MT8135_PIN_31_NLD14__FUNC_DAC_DAT_OUT (MTK_PIN_NO(31) | 4)
+#define MT8135_PIN_31_NLD14__FUNC_PCM1_DO (MTK_PIN_NO(31) | 5)
+
+#define MT8135_PIN_32_NLD15__FUNC_GPIO32 (MTK_PIN_NO(32) | 0)
+#define MT8135_PIN_32_NLD15__FUNC_NLD15 (MTK_PIN_NO(32) | 1)
+#define MT8135_PIN_32_NLD15__FUNC_EINT161 (MTK_PIN_NO(32) | 2)
+#define MT8135_PIN_32_NLD15__FUNC_DISP_PWM (MTK_PIN_NO(32) | 3)
+#define MT8135_PIN_32_NLD15__FUNC_PWM4 (MTK_PIN_NO(32) | 4)
+#define MT8135_PIN_32_NLD15__FUNC_PCM1_DI (MTK_PIN_NO(32) | 5)
+
+#define MT8135_PIN_33_MSDC0_RSTB__FUNC_GPIO33 (MTK_PIN_NO(33) | 0)
+#define MT8135_PIN_33_MSDC0_RSTB__FUNC_MSDC0_RSTB (MTK_PIN_NO(33) | 1)
+#define MT8135_PIN_33_MSDC0_RSTB__FUNC_EINT50 (MTK_PIN_NO(33) | 2)
+#define MT8135_PIN_33_MSDC0_RSTB__FUNC_I2SIN_DAT (MTK_PIN_NO(33) | 3)
+#define MT8135_PIN_33_MSDC0_RSTB__FUNC_PCM1_DI (MTK_PIN_NO(33) | 5)
+#define MT8135_PIN_33_MSDC0_RSTB__FUNC_SPI1_MI (MTK_PIN_NO(33) | 6)
+#define MT8135_PIN_33_MSDC0_RSTB__FUNC_NLD10 (MTK_PIN_NO(33) | 7)
+
+#define MT8135_PIN_34_IDDIG__FUNC_GPIO34 (MTK_PIN_NO(34) | 0)
+#define MT8135_PIN_34_IDDIG__FUNC_IDDIG (MTK_PIN_NO(34) | 1)
+#define MT8135_PIN_34_IDDIG__FUNC_EINT34 (MTK_PIN_NO(34) | 2)
+
+#define MT8135_PIN_35_SCL3__FUNC_GPIO35 (MTK_PIN_NO(35) | 0)
+#define MT8135_PIN_35_SCL3__FUNC_SCL3 (MTK_PIN_NO(35) | 1)
+#define MT8135_PIN_35_SCL3__FUNC_EINT96 (MTK_PIN_NO(35) | 2)
+#define MT8135_PIN_35_SCL3__FUNC_CLKM6 (MTK_PIN_NO(35) | 3)
+#define MT8135_PIN_35_SCL3__FUNC_PWM6 (MTK_PIN_NO(35) | 4)
+
+#define MT8135_PIN_36_SDA3__FUNC_GPIO36 (MTK_PIN_NO(36) | 0)
+#define MT8135_PIN_36_SDA3__FUNC_SDA3 (MTK_PIN_NO(36) | 1)
+#define MT8135_PIN_36_SDA3__FUNC_EINT97 (MTK_PIN_NO(36) | 2)
+
+#define MT8135_PIN_37_AUD_CLK_MOSI__FUNC_GPIO37 (MTK_PIN_NO(37) | 0)
+#define MT8135_PIN_37_AUD_CLK_MOSI__FUNC_AUD_CLK (MTK_PIN_NO(37) | 1)
+#define MT8135_PIN_37_AUD_CLK_MOSI__FUNC_ADC_CK (MTK_PIN_NO(37) | 2)
+#define MT8135_PIN_37_AUD_CLK_MOSI__FUNC_HDMI_SDATA0 (MTK_PIN_NO(37) | 3)
+#define MT8135_PIN_37_AUD_CLK_MOSI__FUNC_EINT19 (MTK_PIN_NO(37) | 4)
+#define MT8135_PIN_37_AUD_CLK_MOSI__FUNC_USB_TEST_IO_6 (MTK_PIN_NO(37) | 5)
+#define MT8135_PIN_37_AUD_CLK_MOSI__FUNC_TESTA_OUT19 (MTK_PIN_NO(37) | 7)
+
+#define MT8135_PIN_38_AUD_DAT_MOSI__FUNC_GPIO38 (MTK_PIN_NO(38) | 0)
+#define MT8135_PIN_38_AUD_DAT_MOSI__FUNC_AUD_DAT_MOSI (MTK_PIN_NO(38) | 1)
+#define MT8135_PIN_38_AUD_DAT_MOSI__FUNC_ADC_WS (MTK_PIN_NO(38) | 2)
+#define MT8135_PIN_38_AUD_DAT_MOSI__FUNC_AUD_DAT_MISO (MTK_PIN_NO(38) | 3)
+#define MT8135_PIN_38_AUD_DAT_MOSI__FUNC_EINT21 (MTK_PIN_NO(38) | 4)
+#define MT8135_PIN_38_AUD_DAT_MOSI__FUNC_USB_TEST_IO_7 (MTK_PIN_NO(38) | 5)
+#define MT8135_PIN_38_AUD_DAT_MOSI__FUNC_TESTA_OUT20 (MTK_PIN_NO(38) | 7)
+
+#define MT8135_PIN_39_AUD_DAT_MISO__FUNC_GPIO39 (MTK_PIN_NO(39) | 0)
+#define MT8135_PIN_39_AUD_DAT_MISO__FUNC_AUD_DAT_MISO (MTK_PIN_NO(39) | 1)
+#define MT8135_PIN_39_AUD_DAT_MISO__FUNC_ADC_DAT_IN (MTK_PIN_NO(39) | 2)
+#define MT8135_PIN_39_AUD_DAT_MISO__FUNC_AUD_DAT_MOSI (MTK_PIN_NO(39) | 3)
+#define MT8135_PIN_39_AUD_DAT_MISO__FUNC_EINT20 (MTK_PIN_NO(39) | 4)
+#define MT8135_PIN_39_AUD_DAT_MISO__FUNC_USB_TEST_IO_8 (MTK_PIN_NO(39) | 5)
+#define MT8135_PIN_39_AUD_DAT_MISO__FUNC_TESTA_OUT21 (MTK_PIN_NO(39) | 7)
+
+#define MT8135_PIN_40_DAC_CLK__FUNC_GPIO40 (MTK_PIN_NO(40) | 0)
+#define MT8135_PIN_40_DAC_CLK__FUNC_DAC_CK (MTK_PIN_NO(40) | 1)
+#define MT8135_PIN_40_DAC_CLK__FUNC_EINT22 (MTK_PIN_NO(40) | 2)
+#define MT8135_PIN_40_DAC_CLK__FUNC_HDMI_SDATA1 (MTK_PIN_NO(40) | 3)
+#define MT8135_PIN_40_DAC_CLK__FUNC_USB_TEST_IO_9 (MTK_PIN_NO(40) | 5)
+#define MT8135_PIN_40_DAC_CLK__FUNC_TESTA_OUT22 (MTK_PIN_NO(40) | 7)
+
+#define MT8135_PIN_41_DAC_WS__FUNC_GPIO41 (MTK_PIN_NO(41) | 0)
+#define MT8135_PIN_41_DAC_WS__FUNC_DAC_WS (MTK_PIN_NO(41) | 1)
+#define MT8135_PIN_41_DAC_WS__FUNC_EINT24 (MTK_PIN_NO(41) | 2)
+#define MT8135_PIN_41_DAC_WS__FUNC_HDMI_SDATA2 (MTK_PIN_NO(41) | 3)
+#define MT8135_PIN_41_DAC_WS__FUNC_USB_TEST_IO_10 (MTK_PIN_NO(41) | 5)
+#define MT8135_PIN_41_DAC_WS__FUNC_TESTA_OUT23 (MTK_PIN_NO(41) | 7)
+
+#define MT8135_PIN_42_DAC_DAT_OUT__FUNC_GPIO42 (MTK_PIN_NO(42) | 0)
+#define MT8135_PIN_42_DAC_DAT_OUT__FUNC_DAC_DAT_OUT (MTK_PIN_NO(42) | 1)
+#define MT8135_PIN_42_DAC_DAT_OUT__FUNC_EINT23 (MTK_PIN_NO(42) | 2)
+#define MT8135_PIN_42_DAC_DAT_OUT__FUNC_HDMI_SDATA3 (MTK_PIN_NO(42) | 3)
+#define MT8135_PIN_42_DAC_DAT_OUT__FUNC_USB_TEST_IO_11 (MTK_PIN_NO(42) | 5)
+#define MT8135_PIN_42_DAC_DAT_OUT__FUNC_TESTA_OUT24 (MTK_PIN_NO(42) | 7)
+
+#define MT8135_PIN_43_PWRAP_SPI0_MO__FUNC_GPIO43 (MTK_PIN_NO(43) | 0)
+#define MT8135_PIN_43_PWRAP_SPI0_MO__FUNC_PWRAP_SPIDI (MTK_PIN_NO(43) | 1)
+#define MT8135_PIN_43_PWRAP_SPI0_MO__FUNC_EINT29 (MTK_PIN_NO(43) | 2)
+
+#define MT8135_PIN_44_PWRAP_SPI0_MI__FUNC_GPIO44 (MTK_PIN_NO(44) | 0)
+#define MT8135_PIN_44_PWRAP_SPI0_MI__FUNC_PWRAP_SPIDO (MTK_PIN_NO(44) | 1)
+#define MT8135_PIN_44_PWRAP_SPI0_MI__FUNC_EINT28 (MTK_PIN_NO(44) | 2)
+
+#define MT8135_PIN_45_PWRAP_SPI0_CSN__FUNC_GPIO45 (MTK_PIN_NO(45) | 0)
+#define MT8135_PIN_45_PWRAP_SPI0_CSN__FUNC_PWRAP_SPICS_B_I (MTK_PIN_NO(45) | 1)
+#define MT8135_PIN_45_PWRAP_SPI0_CSN__FUNC_EINT27 (MTK_PIN_NO(45) | 2)
+
+#define MT8135_PIN_46_PWRAP_SPI0_CLK__FUNC_GPIO46 (MTK_PIN_NO(46) | 0)
+#define MT8135_PIN_46_PWRAP_SPI0_CLK__FUNC_PWRAP_SPICK_I (MTK_PIN_NO(46) | 1)
+#define MT8135_PIN_46_PWRAP_SPI0_CLK__FUNC_EINT26 (MTK_PIN_NO(46) | 2)
+
+#define MT8135_PIN_47_PWRAP_EVENT__FUNC_GPIO47 (MTK_PIN_NO(47) | 0)
+#define MT8135_PIN_47_PWRAP_EVENT__FUNC_PWRAP_EVENT_IN (MTK_PIN_NO(47) | 1)
+#define MT8135_PIN_47_PWRAP_EVENT__FUNC_EINT25 (MTK_PIN_NO(47) | 2)
+#define MT8135_PIN_47_PWRAP_EVENT__FUNC_TESTA_OUT2 (MTK_PIN_NO(47) | 7)
+
+#define MT8135_PIN_48_RTC32K_CK__FUNC_GPIO48 (MTK_PIN_NO(48) | 0)
+#define MT8135_PIN_48_RTC32K_CK__FUNC_RTC32K_CK (MTK_PIN_NO(48) | 1)
+
+#define MT8135_PIN_49_WATCHDOG__FUNC_GPIO49 (MTK_PIN_NO(49) | 0)
+#define MT8135_PIN_49_WATCHDOG__FUNC_WATCHDOG (MTK_PIN_NO(49) | 1)
+#define MT8135_PIN_49_WATCHDOG__FUNC_EINT36 (MTK_PIN_NO(49) | 2)
+
+#define MT8135_PIN_50_SRCLKENA__FUNC_GPIO50 (MTK_PIN_NO(50) | 0)
+#define MT8135_PIN_50_SRCLKENA__FUNC_SRCLKENA (MTK_PIN_NO(50) | 1)
+#define MT8135_PIN_50_SRCLKENA__FUNC_EINT38 (MTK_PIN_NO(50) | 2)
+
+#define MT8135_PIN_51_SRCVOLTEN__FUNC_GPIO51 (MTK_PIN_NO(51) | 0)
+#define MT8135_PIN_51_SRCVOLTEN__FUNC_SRCVOLTEN (MTK_PIN_NO(51) | 1)
+#define MT8135_PIN_51_SRCVOLTEN__FUNC_EINT37 (MTK_PIN_NO(51) | 2)
+
+#define MT8135_PIN_52_EINT0__FUNC_GPIO52 (MTK_PIN_NO(52) | 0)
+#define MT8135_PIN_52_EINT0__FUNC_EINT0 (MTK_PIN_NO(52) | 1)
+#define MT8135_PIN_52_EINT0__FUNC_PWM1 (MTK_PIN_NO(52) | 2)
+#define MT8135_PIN_52_EINT0__FUNC_CLKM0 (MTK_PIN_NO(52) | 3)
+#define MT8135_PIN_52_EINT0__FUNC_SPDIF_OUT (MTK_PIN_NO(52) | 4)
+#define MT8135_PIN_52_EINT0__FUNC_USB_TEST_IO_12 (MTK_PIN_NO(52) | 5)
+#define MT8135_PIN_52_EINT0__FUNC_USB_SCL (MTK_PIN_NO(52) | 7)
+
+#define MT8135_PIN_53_URXD2__FUNC_GPIO53 (MTK_PIN_NO(53) | 0)
+#define MT8135_PIN_53_URXD2__FUNC_URXD2 (MTK_PIN_NO(53) | 1)
+#define MT8135_PIN_53_URXD2__FUNC_EINT83 (MTK_PIN_NO(53) | 2)
+#define MT8135_PIN_53_URXD2__FUNC_HDMI_LRCK (MTK_PIN_NO(53) | 4)
+#define MT8135_PIN_53_URXD2__FUNC_CLKM3 (MTK_PIN_NO(53) | 5)
+#define MT8135_PIN_53_URXD2__FUNC_UTXD2 (MTK_PIN_NO(53) | 7)
+
+#define MT8135_PIN_54_UTXD2__FUNC_GPIO54 (MTK_PIN_NO(54) | 0)
+#define MT8135_PIN_54_UTXD2__FUNC_UTXD2 (MTK_PIN_NO(54) | 1)
+#define MT8135_PIN_54_UTXD2__FUNC_EINT82 (MTK_PIN_NO(54) | 2)
+#define MT8135_PIN_54_UTXD2__FUNC_HDMI_BCK_OUT (MTK_PIN_NO(54) | 4)
+#define MT8135_PIN_54_UTXD2__FUNC_CLKM2 (MTK_PIN_NO(54) | 5)
+#define MT8135_PIN_54_UTXD2__FUNC_URXD2 (MTK_PIN_NO(54) | 7)
+
+#define MT8135_PIN_55_UCTS2__FUNC_GPIO55 (MTK_PIN_NO(55) | 0)
+#define MT8135_PIN_55_UCTS2__FUNC_UCTS2 (MTK_PIN_NO(55) | 1)
+#define MT8135_PIN_55_UCTS2__FUNC_EINT84 (MTK_PIN_NO(55) | 2)
+#define MT8135_PIN_55_UCTS2__FUNC_PWM1 (MTK_PIN_NO(55) | 5)
+#define MT8135_PIN_55_UCTS2__FUNC_URTS2 (MTK_PIN_NO(55) | 7)
+
+#define MT8135_PIN_56_URTS2__FUNC_GPIO56 (MTK_PIN_NO(56) | 0)
+#define MT8135_PIN_56_URTS2__FUNC_URTS2 (MTK_PIN_NO(56) | 1)
+#define MT8135_PIN_56_URTS2__FUNC_EINT85 (MTK_PIN_NO(56) | 2)
+#define MT8135_PIN_56_URTS2__FUNC_PWM2 (MTK_PIN_NO(56) | 5)
+#define MT8135_PIN_56_URTS2__FUNC_UCTS2 (MTK_PIN_NO(56) | 7)
+
+#define MT8135_PIN_57_JTCK__FUNC_GPIO57 (MTK_PIN_NO(57) | 0)
+#define MT8135_PIN_57_JTCK__FUNC_JTCK (MTK_PIN_NO(57) | 1)
+#define MT8135_PIN_57_JTCK__FUNC_EINT188 (MTK_PIN_NO(57) | 2)
+#define MT8135_PIN_57_JTCK__FUNC_DSP1_ICK (MTK_PIN_NO(57) | 3)
+
+#define MT8135_PIN_58_JTDO__FUNC_GPIO58 (MTK_PIN_NO(58) | 0)
+#define MT8135_PIN_58_JTDO__FUNC_JTDO (MTK_PIN_NO(58) | 1)
+#define MT8135_PIN_58_JTDO__FUNC_EINT190 (MTK_PIN_NO(58) | 2)
+#define MT8135_PIN_58_JTDO__FUNC_DSP2_IMS (MTK_PIN_NO(58) | 3)
+
+#define MT8135_PIN_59_JTRST_B__FUNC_GPIO59 (MTK_PIN_NO(59) | 0)
+#define MT8135_PIN_59_JTRST_B__FUNC_JTRST_B (MTK_PIN_NO(59) | 1)
+#define MT8135_PIN_59_JTRST_B__FUNC_EINT0 (MTK_PIN_NO(59) | 2)
+#define MT8135_PIN_59_JTRST_B__FUNC_DSP2_ICK (MTK_PIN_NO(59) | 3)
+
+#define MT8135_PIN_60_JTDI__FUNC_GPIO60 (MTK_PIN_NO(60) | 0)
+#define MT8135_PIN_60_JTDI__FUNC_JTDI (MTK_PIN_NO(60) | 1)
+#define MT8135_PIN_60_JTDI__FUNC_EINT189 (MTK_PIN_NO(60) | 2)
+#define MT8135_PIN_60_JTDI__FUNC_DSP1_IMS (MTK_PIN_NO(60) | 3)
+
+#define MT8135_PIN_61_JRTCK__FUNC_GPIO61 (MTK_PIN_NO(61) | 0)
+#define MT8135_PIN_61_JRTCK__FUNC_JRTCK (MTK_PIN_NO(61) | 1)
+#define MT8135_PIN_61_JRTCK__FUNC_EINT187 (MTK_PIN_NO(61) | 2)
+#define MT8135_PIN_61_JRTCK__FUNC_DSP1_ID (MTK_PIN_NO(61) | 3)
+
+#define MT8135_PIN_62_JTMS__FUNC_GPIO62 (MTK_PIN_NO(62) | 0)
+#define MT8135_PIN_62_JTMS__FUNC_JTMS (MTK_PIN_NO(62) | 1)
+#define MT8135_PIN_62_JTMS__FUNC_EINT191 (MTK_PIN_NO(62) | 2)
+#define MT8135_PIN_62_JTMS__FUNC_DSP2_ID (MTK_PIN_NO(62) | 3)
+
+#define MT8135_PIN_63_MSDC1_INSI__FUNC_GPIO63 (MTK_PIN_NO(63) | 0)
+#define MT8135_PIN_63_MSDC1_INSI__FUNC_MSDC1_INSI (MTK_PIN_NO(63) | 1)
+#define MT8135_PIN_63_MSDC1_INSI__FUNC_SCL5 (MTK_PIN_NO(63) | 3)
+#define MT8135_PIN_63_MSDC1_INSI__FUNC_PWM6 (MTK_PIN_NO(63) | 4)
+#define MT8135_PIN_63_MSDC1_INSI__FUNC_CLKM5 (MTK_PIN_NO(63) | 5)
+#define MT8135_PIN_63_MSDC1_INSI__FUNC_TESTB_OUT6 (MTK_PIN_NO(63) | 7)
+
+#define MT8135_PIN_64_MSDC1_SDWPI__FUNC_GPIO64 (MTK_PIN_NO(64) | 0)
+#define MT8135_PIN_64_MSDC1_SDWPI__FUNC_MSDC1_SDWPI (MTK_PIN_NO(64) | 1)
+#define MT8135_PIN_64_MSDC1_SDWPI__FUNC_EINT58 (MTK_PIN_NO(64) | 2)
+#define MT8135_PIN_64_MSDC1_SDWPI__FUNC_SDA5 (MTK_PIN_NO(64) | 3)
+#define MT8135_PIN_64_MSDC1_SDWPI__FUNC_PWM7 (MTK_PIN_NO(64) | 4)
+#define MT8135_PIN_64_MSDC1_SDWPI__FUNC_CLKM6 (MTK_PIN_NO(64) | 5)
+#define MT8135_PIN_64_MSDC1_SDWPI__FUNC_TESTB_OUT7 (MTK_PIN_NO(64) | 7)
+
+#define MT8135_PIN_65_MSDC2_INSI__FUNC_GPIO65 (MTK_PIN_NO(65) | 0)
+#define MT8135_PIN_65_MSDC2_INSI__FUNC_MSDC2_INSI (MTK_PIN_NO(65) | 1)
+#define MT8135_PIN_65_MSDC2_INSI__FUNC_USB_TEST_IO_27 (MTK_PIN_NO(65) | 5)
+#define MT8135_PIN_65_MSDC2_INSI__FUNC_TESTA_OUT3 (MTK_PIN_NO(65) | 7)
+
+#define MT8135_PIN_66_MSDC2_SDWPI__FUNC_GPIO66 (MTK_PIN_NO(66) | 0)
+#define MT8135_PIN_66_MSDC2_SDWPI__FUNC_MSDC2_SDWPI (MTK_PIN_NO(66) | 1)
+#define MT8135_PIN_66_MSDC2_SDWPI__FUNC_EINT66 (MTK_PIN_NO(66) | 2)
+#define MT8135_PIN_66_MSDC2_SDWPI__FUNC_USB_TEST_IO_28 (MTK_PIN_NO(66) | 5)
+
+#define MT8135_PIN_67_URXD4__FUNC_GPIO67 (MTK_PIN_NO(67) | 0)
+#define MT8135_PIN_67_URXD4__FUNC_URXD4 (MTK_PIN_NO(67) | 1)
+#define MT8135_PIN_67_URXD4__FUNC_EINT89 (MTK_PIN_NO(67) | 2)
+#define MT8135_PIN_67_URXD4__FUNC_URXD1 (MTK_PIN_NO(67) | 3)
+#define MT8135_PIN_67_URXD4__FUNC_UTXD4 (MTK_PIN_NO(67) | 6)
+#define MT8135_PIN_67_URXD4__FUNC_TESTB_OUT10 (MTK_PIN_NO(67) | 7)
+
+#define MT8135_PIN_68_UTXD4__FUNC_GPIO68 (MTK_PIN_NO(68) | 0)
+#define MT8135_PIN_68_UTXD4__FUNC_UTXD4 (MTK_PIN_NO(68) | 1)
+#define MT8135_PIN_68_UTXD4__FUNC_EINT88 (MTK_PIN_NO(68) | 2)
+#define MT8135_PIN_68_UTXD4__FUNC_UTXD1 (MTK_PIN_NO(68) | 3)
+#define MT8135_PIN_68_UTXD4__FUNC_URXD4 (MTK_PIN_NO(68) | 6)
+#define MT8135_PIN_68_UTXD4__FUNC_TESTB_OUT11 (MTK_PIN_NO(68) | 7)
+
+#define MT8135_PIN_69_URXD1__FUNC_GPIO69 (MTK_PIN_NO(69) | 0)
+#define MT8135_PIN_69_URXD1__FUNC_URXD1 (MTK_PIN_NO(69) | 1)
+#define MT8135_PIN_69_URXD1__FUNC_EINT79 (MTK_PIN_NO(69) | 2)
+#define MT8135_PIN_69_URXD1__FUNC_URXD4 (MTK_PIN_NO(69) | 3)
+#define MT8135_PIN_69_URXD1__FUNC_UTXD1 (MTK_PIN_NO(69) | 6)
+#define MT8135_PIN_69_URXD1__FUNC_TESTB_OUT24 (MTK_PIN_NO(69) | 7)
+
+#define MT8135_PIN_70_UTXD1__FUNC_GPIO70 (MTK_PIN_NO(70) | 0)
+#define MT8135_PIN_70_UTXD1__FUNC_UTXD1 (MTK_PIN_NO(70) | 1)
+#define MT8135_PIN_70_UTXD1__FUNC_EINT78 (MTK_PIN_NO(70) | 2)
+#define MT8135_PIN_70_UTXD1__FUNC_UTXD4 (MTK_PIN_NO(70) | 3)
+#define MT8135_PIN_70_UTXD1__FUNC_URXD1 (MTK_PIN_NO(70) | 6)
+#define MT8135_PIN_70_UTXD1__FUNC_TESTB_OUT25 (MTK_PIN_NO(70) | 7)
+
+#define MT8135_PIN_71_UCTS1__FUNC_GPIO71 (MTK_PIN_NO(71) | 0)
+#define MT8135_PIN_71_UCTS1__FUNC_UCTS1 (MTK_PIN_NO(71) | 1)
+#define MT8135_PIN_71_UCTS1__FUNC_EINT80 (MTK_PIN_NO(71) | 2)
+#define MT8135_PIN_71_UCTS1__FUNC_CLKM0 (MTK_PIN_NO(71) | 5)
+#define MT8135_PIN_71_UCTS1__FUNC_URTS1 (MTK_PIN_NO(71) | 6)
+#define MT8135_PIN_71_UCTS1__FUNC_TESTB_OUT31 (MTK_PIN_NO(71) | 7)
+
+#define MT8135_PIN_72_URTS1__FUNC_GPIO72 (MTK_PIN_NO(72) | 0)
+#define MT8135_PIN_72_URTS1__FUNC_URTS1 (MTK_PIN_NO(72) | 1)
+#define MT8135_PIN_72_URTS1__FUNC_EINT81 (MTK_PIN_NO(72) | 2)
+#define MT8135_PIN_72_URTS1__FUNC_CLKM1 (MTK_PIN_NO(72) | 5)
+#define MT8135_PIN_72_URTS1__FUNC_UCTS1 (MTK_PIN_NO(72) | 6)
+#define MT8135_PIN_72_URTS1__FUNC_TESTB_OUT21 (MTK_PIN_NO(72) | 7)
+
+#define MT8135_PIN_73_PWM1__FUNC_GPIO73 (MTK_PIN_NO(73) | 0)
+#define MT8135_PIN_73_PWM1__FUNC_PWM1 (MTK_PIN_NO(73) | 1)
+#define MT8135_PIN_73_PWM1__FUNC_EINT73 (MTK_PIN_NO(73) | 2)
+#define MT8135_PIN_73_PWM1__FUNC_USB_DRVVBUS (MTK_PIN_NO(73) | 5)
+#define MT8135_PIN_73_PWM1__FUNC_DISP_PWM (MTK_PIN_NO(73) | 6)
+#define MT8135_PIN_73_PWM1__FUNC_TESTB_OUT8 (MTK_PIN_NO(73) | 7)
+
+#define MT8135_PIN_74_PWM2__FUNC_GPIO74 (MTK_PIN_NO(74) | 0)
+#define MT8135_PIN_74_PWM2__FUNC_PWM2 (MTK_PIN_NO(74) | 1)
+#define MT8135_PIN_74_PWM2__FUNC_EINT74 (MTK_PIN_NO(74) | 2)
+#define MT8135_PIN_74_PWM2__FUNC_DPI33_CK (MTK_PIN_NO(74) | 3)
+#define MT8135_PIN_74_PWM2__FUNC_PWM5 (MTK_PIN_NO(74) | 4)
+#define MT8135_PIN_74_PWM2__FUNC_URXD2 (MTK_PIN_NO(74) | 5)
+#define MT8135_PIN_74_PWM2__FUNC_DISP_PWM (MTK_PIN_NO(74) | 6)
+#define MT8135_PIN_74_PWM2__FUNC_TESTB_OUT9 (MTK_PIN_NO(74) | 7)
+
+#define MT8135_PIN_75_PWM3__FUNC_GPIO75 (MTK_PIN_NO(75) | 0)
+#define MT8135_PIN_75_PWM3__FUNC_PWM3 (MTK_PIN_NO(75) | 1)
+#define MT8135_PIN_75_PWM3__FUNC_EINT75 (MTK_PIN_NO(75) | 2)
+#define MT8135_PIN_75_PWM3__FUNC_DPI33_D0 (MTK_PIN_NO(75) | 3)
+#define MT8135_PIN_75_PWM3__FUNC_PWM6 (MTK_PIN_NO(75) | 4)
+#define MT8135_PIN_75_PWM3__FUNC_UTXD2 (MTK_PIN_NO(75) | 5)
+#define MT8135_PIN_75_PWM3__FUNC_DISP_PWM (MTK_PIN_NO(75) | 6)
+#define MT8135_PIN_75_PWM3__FUNC_TESTB_OUT12 (MTK_PIN_NO(75) | 7)
+
+#define MT8135_PIN_76_PWM4__FUNC_GPIO76 (MTK_PIN_NO(76) | 0)
+#define MT8135_PIN_76_PWM4__FUNC_PWM4 (MTK_PIN_NO(76) | 1)
+#define MT8135_PIN_76_PWM4__FUNC_EINT76 (MTK_PIN_NO(76) | 2)
+#define MT8135_PIN_76_PWM4__FUNC_DPI33_D1 (MTK_PIN_NO(76) | 3)
+#define MT8135_PIN_76_PWM4__FUNC_PWM7 (MTK_PIN_NO(76) | 4)
+#define MT8135_PIN_76_PWM4__FUNC_DISP_PWM (MTK_PIN_NO(76) | 6)
+#define MT8135_PIN_76_PWM4__FUNC_TESTB_OUT13 (MTK_PIN_NO(76) | 7)
+
+#define MT8135_PIN_77_MSDC2_DAT2__FUNC_GPIO77 (MTK_PIN_NO(77) | 0)
+#define MT8135_PIN_77_MSDC2_DAT2__FUNC_MSDC2_DAT2 (MTK_PIN_NO(77) | 1)
+#define MT8135_PIN_77_MSDC2_DAT2__FUNC_EINT63 (MTK_PIN_NO(77) | 2)
+#define MT8135_PIN_77_MSDC2_DAT2__FUNC_DSP2_IMS (MTK_PIN_NO(77) | 4)
+#define MT8135_PIN_77_MSDC2_DAT2__FUNC_DPI33_D6 (MTK_PIN_NO(77) | 6)
+#define MT8135_PIN_77_MSDC2_DAT2__FUNC_TESTA_OUT25 (MTK_PIN_NO(77) | 7)
+
+#define MT8135_PIN_78_MSDC2_DAT3__FUNC_GPIO78 (MTK_PIN_NO(78) | 0)
+#define MT8135_PIN_78_MSDC2_DAT3__FUNC_MSDC2_DAT3 (MTK_PIN_NO(78) | 1)
+#define MT8135_PIN_78_MSDC2_DAT3__FUNC_EINT64 (MTK_PIN_NO(78) | 2)
+#define MT8135_PIN_78_MSDC2_DAT3__FUNC_DSP2_ID (MTK_PIN_NO(78) | 4)
+#define MT8135_PIN_78_MSDC2_DAT3__FUNC_DPI33_D7 (MTK_PIN_NO(78) | 6)
+#define MT8135_PIN_78_MSDC2_DAT3__FUNC_TESTA_OUT26 (MTK_PIN_NO(78) | 7)
+
+#define MT8135_PIN_79_MSDC2_CMD__FUNC_GPIO79 (MTK_PIN_NO(79) | 0)
+#define MT8135_PIN_79_MSDC2_CMD__FUNC_MSDC2_CMD (MTK_PIN_NO(79) | 1)
+#define MT8135_PIN_79_MSDC2_CMD__FUNC_EINT60 (MTK_PIN_NO(79) | 2)
+#define MT8135_PIN_79_MSDC2_CMD__FUNC_DSP1_IMS (MTK_PIN_NO(79) | 4)
+#define MT8135_PIN_79_MSDC2_CMD__FUNC_PCM1_WS (MTK_PIN_NO(79) | 5)
+#define MT8135_PIN_79_MSDC2_CMD__FUNC_DPI33_D3 (MTK_PIN_NO(79) | 6)
+#define MT8135_PIN_79_MSDC2_CMD__FUNC_TESTA_OUT0 (MTK_PIN_NO(79) | 7)
+
+#define MT8135_PIN_80_MSDC2_CLK__FUNC_GPIO80 (MTK_PIN_NO(80) | 0)
+#define MT8135_PIN_80_MSDC2_CLK__FUNC_MSDC2_CLK (MTK_PIN_NO(80) | 1)
+#define MT8135_PIN_80_MSDC2_CLK__FUNC_EINT59 (MTK_PIN_NO(80) | 2)
+#define MT8135_PIN_80_MSDC2_CLK__FUNC_DSP1_ICK (MTK_PIN_NO(80) | 4)
+#define MT8135_PIN_80_MSDC2_CLK__FUNC_PCM1_CK (MTK_PIN_NO(80) | 5)
+#define MT8135_PIN_80_MSDC2_CLK__FUNC_DPI33_D2 (MTK_PIN_NO(80) | 6)
+#define MT8135_PIN_80_MSDC2_CLK__FUNC_TESTA_OUT1 (MTK_PIN_NO(80) | 7)
+
+#define MT8135_PIN_81_MSDC2_DAT1__FUNC_GPIO81 (MTK_PIN_NO(81) | 0)
+#define MT8135_PIN_81_MSDC2_DAT1__FUNC_MSDC2_DAT1 (MTK_PIN_NO(81) | 1)
+#define MT8135_PIN_81_MSDC2_DAT1__FUNC_EINT62 (MTK_PIN_NO(81) | 2)
+#define MT8135_PIN_81_MSDC2_DAT1__FUNC_DSP2_ICK (MTK_PIN_NO(81) | 4)
+#define MT8135_PIN_81_MSDC2_DAT1__FUNC_PCM1_DO (MTK_PIN_NO(81) | 5)
+#define MT8135_PIN_81_MSDC2_DAT1__FUNC_DPI33_D5 (MTK_PIN_NO(81) | 6)
+
+#define MT8135_PIN_82_MSDC2_DAT0__FUNC_GPIO82 (MTK_PIN_NO(82) | 0)
+#define MT8135_PIN_82_MSDC2_DAT0__FUNC_MSDC2_DAT0 (MTK_PIN_NO(82) | 1)
+#define MT8135_PIN_82_MSDC2_DAT0__FUNC_EINT61 (MTK_PIN_NO(82) | 2)
+#define MT8135_PIN_82_MSDC2_DAT0__FUNC_DSP1_ID (MTK_PIN_NO(82) | 4)
+#define MT8135_PIN_82_MSDC2_DAT0__FUNC_PCM1_DI (MTK_PIN_NO(82) | 5)
+#define MT8135_PIN_82_MSDC2_DAT0__FUNC_DPI33_D4 (MTK_PIN_NO(82) | 6)
+
+#define MT8135_PIN_83_MSDC1_DAT0__FUNC_GPIO83 (MTK_PIN_NO(83) | 0)
+#define MT8135_PIN_83_MSDC1_DAT0__FUNC_MSDC1_DAT0 (MTK_PIN_NO(83) | 1)
+#define MT8135_PIN_83_MSDC1_DAT0__FUNC_EINT53 (MTK_PIN_NO(83) | 2)
+#define MT8135_PIN_83_MSDC1_DAT0__FUNC_SCL1 (MTK_PIN_NO(83) | 3)
+#define MT8135_PIN_83_MSDC1_DAT0__FUNC_PWM2 (MTK_PIN_NO(83) | 4)
+#define MT8135_PIN_83_MSDC1_DAT0__FUNC_CLKM1 (MTK_PIN_NO(83) | 5)
+#define MT8135_PIN_83_MSDC1_DAT0__FUNC_TESTB_OUT2 (MTK_PIN_NO(83) | 7)
+
+#define MT8135_PIN_84_MSDC1_DAT1__FUNC_GPIO84 (MTK_PIN_NO(84) | 0)
+#define MT8135_PIN_84_MSDC1_DAT1__FUNC_MSDC1_DAT1 (MTK_PIN_NO(84) | 1)
+#define MT8135_PIN_84_MSDC1_DAT1__FUNC_EINT54 (MTK_PIN_NO(84) | 2)
+#define MT8135_PIN_84_MSDC1_DAT1__FUNC_SDA1 (MTK_PIN_NO(84) | 3)
+#define MT8135_PIN_84_MSDC1_DAT1__FUNC_PWM3 (MTK_PIN_NO(84) | 4)
+#define MT8135_PIN_84_MSDC1_DAT1__FUNC_CLKM2 (MTK_PIN_NO(84) | 5)
+#define MT8135_PIN_84_MSDC1_DAT1__FUNC_TESTB_OUT3 (MTK_PIN_NO(84) | 7)
+
+#define MT8135_PIN_85_MSDC1_CMD__FUNC_GPIO85 (MTK_PIN_NO(85) | 0)
+#define MT8135_PIN_85_MSDC1_CMD__FUNC_MSDC1_CMD (MTK_PIN_NO(85) | 1)
+#define MT8135_PIN_85_MSDC1_CMD__FUNC_EINT52 (MTK_PIN_NO(85) | 2)
+#define MT8135_PIN_85_MSDC1_CMD__FUNC_SDA0 (MTK_PIN_NO(85) | 3)
+#define MT8135_PIN_85_MSDC1_CMD__FUNC_PWM1 (MTK_PIN_NO(85) | 4)
+#define MT8135_PIN_85_MSDC1_CMD__FUNC_CLKM0 (MTK_PIN_NO(85) | 5)
+#define MT8135_PIN_85_MSDC1_CMD__FUNC_TESTB_OUT1 (MTK_PIN_NO(85) | 7)
+
+#define MT8135_PIN_86_MSDC1_CLK__FUNC_GPIO86 (MTK_PIN_NO(86) | 0)
+#define MT8135_PIN_86_MSDC1_CLK__FUNC_MSDC1_CLK (MTK_PIN_NO(86) | 1)
+#define MT8135_PIN_86_MSDC1_CLK__FUNC_EINT51 (MTK_PIN_NO(86) | 2)
+#define MT8135_PIN_86_MSDC1_CLK__FUNC_SCL0 (MTK_PIN_NO(86) | 3)
+#define MT8135_PIN_86_MSDC1_CLK__FUNC_DISP_PWM (MTK_PIN_NO(86) | 4)
+#define MT8135_PIN_86_MSDC1_CLK__FUNC_TESTB_OUT0 (MTK_PIN_NO(86) | 7)
+
+#define MT8135_PIN_87_MSDC1_DAT2__FUNC_GPIO87 (MTK_PIN_NO(87) | 0)
+#define MT8135_PIN_87_MSDC1_DAT2__FUNC_MSDC1_DAT2 (MTK_PIN_NO(87) | 1)
+#define MT8135_PIN_87_MSDC1_DAT2__FUNC_EINT55 (MTK_PIN_NO(87) | 2)
+#define MT8135_PIN_87_MSDC1_DAT2__FUNC_SCL4 (MTK_PIN_NO(87) | 3)
+#define MT8135_PIN_87_MSDC1_DAT2__FUNC_PWM4 (MTK_PIN_NO(87) | 4)
+#define MT8135_PIN_87_MSDC1_DAT2__FUNC_CLKM3 (MTK_PIN_NO(87) | 5)
+#define MT8135_PIN_87_MSDC1_DAT2__FUNC_TESTB_OUT4 (MTK_PIN_NO(87) | 7)
+
+#define MT8135_PIN_88_MSDC1_DAT3__FUNC_GPIO88 (MTK_PIN_NO(88) | 0)
+#define MT8135_PIN_88_MSDC1_DAT3__FUNC_MSDC1_DAT3 (MTK_PIN_NO(88) | 1)
+#define MT8135_PIN_88_MSDC1_DAT3__FUNC_EINT56 (MTK_PIN_NO(88) | 2)
+#define MT8135_PIN_88_MSDC1_DAT3__FUNC_SDA4 (MTK_PIN_NO(88) | 3)
+#define MT8135_PIN_88_MSDC1_DAT3__FUNC_PWM5 (MTK_PIN_NO(88) | 4)
+#define MT8135_PIN_88_MSDC1_DAT3__FUNC_CLKM4 (MTK_PIN_NO(88) | 5)
+#define MT8135_PIN_88_MSDC1_DAT3__FUNC_TESTB_OUT5 (MTK_PIN_NO(88) | 7)
+
+#define MT8135_PIN_89_MSDC4_DAT0__FUNC_GPIO89 (MTK_PIN_NO(89) | 0)
+#define MT8135_PIN_89_MSDC4_DAT0__FUNC_MSDC4_DAT0 (MTK_PIN_NO(89) | 1)
+#define MT8135_PIN_89_MSDC4_DAT0__FUNC_EINT133 (MTK_PIN_NO(89) | 2)
+#define MT8135_PIN_89_MSDC4_DAT0__FUNC_EXT_FRAME_SYNC (MTK_PIN_NO(89) | 4)
+#define MT8135_PIN_89_MSDC4_DAT0__FUNC_USB_DRVVBUS (MTK_PIN_NO(89) | 5)
+#define MT8135_PIN_89_MSDC4_DAT0__FUNC_A_FUNC_DIN_9 (MTK_PIN_NO(89) | 6)
+#define MT8135_PIN_89_MSDC4_DAT0__FUNC_LPTE (MTK_PIN_NO(89) | 7)
+
+#define MT8135_PIN_90_MSDC4_DAT1__FUNC_GPIO90 (MTK_PIN_NO(90) | 0)
+#define MT8135_PIN_90_MSDC4_DAT1__FUNC_MSDC4_DAT1 (MTK_PIN_NO(90) | 1)
+#define MT8135_PIN_90_MSDC4_DAT1__FUNC_EINT134 (MTK_PIN_NO(90) | 2)
+#define MT8135_PIN_90_MSDC4_DAT1__FUNC_A_FUNC_DIN_10 (MTK_PIN_NO(90) | 6)
+#define MT8135_PIN_90_MSDC4_DAT1__FUNC_LRSTB_1X (MTK_PIN_NO(90) | 7)
+
+#define MT8135_PIN_91_MSDC4_DAT5__FUNC_GPIO91 (MTK_PIN_NO(91) | 0)
+#define MT8135_PIN_91_MSDC4_DAT5__FUNC_MSDC4_DAT5 (MTK_PIN_NO(91) | 1)
+#define MT8135_PIN_91_MSDC4_DAT5__FUNC_EINT136 (MTK_PIN_NO(91) | 2)
+#define MT8135_PIN_91_MSDC4_DAT5__FUNC_I2SIN_WS (MTK_PIN_NO(91) | 3)
+#define MT8135_PIN_91_MSDC4_DAT5__FUNC_DAC_WS (MTK_PIN_NO(91) | 4)
+#define MT8135_PIN_91_MSDC4_DAT5__FUNC_PCM1_WS (MTK_PIN_NO(91) | 5)
+#define MT8135_PIN_91_MSDC4_DAT5__FUNC_A_FUNC_DIN_11 (MTK_PIN_NO(91) | 6)
+#define MT8135_PIN_91_MSDC4_DAT5__FUNC_SPI1_CSN (MTK_PIN_NO(91) | 7)
+
+#define MT8135_PIN_92_MSDC4_DAT6__FUNC_GPIO92 (MTK_PIN_NO(92) | 0)
+#define MT8135_PIN_92_MSDC4_DAT6__FUNC_MSDC4_DAT6 (MTK_PIN_NO(92) | 1)
+#define MT8135_PIN_92_MSDC4_DAT6__FUNC_EINT137 (MTK_PIN_NO(92) | 2)
+#define MT8135_PIN_92_MSDC4_DAT6__FUNC_I2SOUT_DAT (MTK_PIN_NO(92) | 3)
+#define MT8135_PIN_92_MSDC4_DAT6__FUNC_DAC_DAT_OUT (MTK_PIN_NO(92) | 4)
+#define MT8135_PIN_92_MSDC4_DAT6__FUNC_PCM1_DO (MTK_PIN_NO(92) | 5)
+#define MT8135_PIN_92_MSDC4_DAT6__FUNC_A_FUNC_DIN_12 (MTK_PIN_NO(92) | 6)
+#define MT8135_PIN_92_MSDC4_DAT6__FUNC_SPI1_MO (MTK_PIN_NO(92) | 7)
+
+#define MT8135_PIN_93_MSDC4_DAT7__FUNC_GPIO93 (MTK_PIN_NO(93) | 0)
+#define MT8135_PIN_93_MSDC4_DAT7__FUNC_MSDC4_DAT7 (MTK_PIN_NO(93) | 1)
+#define MT8135_PIN_93_MSDC4_DAT7__FUNC_EINT138 (MTK_PIN_NO(93) | 2)
+#define MT8135_PIN_93_MSDC4_DAT7__FUNC_I2SIN_DAT (MTK_PIN_NO(93) | 3)
+#define MT8135_PIN_93_MSDC4_DAT7__FUNC_PCM1_DI (MTK_PIN_NO(93) | 5)
+#define MT8135_PIN_93_MSDC4_DAT7__FUNC_A_FUNC_DIN_13 (MTK_PIN_NO(93) | 6)
+#define MT8135_PIN_93_MSDC4_DAT7__FUNC_SPI1_MI (MTK_PIN_NO(93) | 7)
+
+#define MT8135_PIN_94_MSDC4_DAT4__FUNC_GPIO94 (MTK_PIN_NO(94) | 0)
+#define MT8135_PIN_94_MSDC4_DAT4__FUNC_MSDC4_DAT4 (MTK_PIN_NO(94) | 1)
+#define MT8135_PIN_94_MSDC4_DAT4__FUNC_EINT135 (MTK_PIN_NO(94) | 2)
+#define MT8135_PIN_94_MSDC4_DAT4__FUNC_I2SIN_CK (MTK_PIN_NO(94) | 3)
+#define MT8135_PIN_94_MSDC4_DAT4__FUNC_DAC_CK (MTK_PIN_NO(94) | 4)
+#define MT8135_PIN_94_MSDC4_DAT4__FUNC_PCM1_CK (MTK_PIN_NO(94) | 5)
+#define MT8135_PIN_94_MSDC4_DAT4__FUNC_A_FUNC_DIN_14 (MTK_PIN_NO(94) | 6)
+#define MT8135_PIN_94_MSDC4_DAT4__FUNC_SPI1_CLK (MTK_PIN_NO(94) | 7)
+
+#define MT8135_PIN_95_MSDC4_DAT2__FUNC_GPIO95 (MTK_PIN_NO(95) | 0)
+#define MT8135_PIN_95_MSDC4_DAT2__FUNC_MSDC4_DAT2 (MTK_PIN_NO(95) | 1)
+#define MT8135_PIN_95_MSDC4_DAT2__FUNC_EINT131 (MTK_PIN_NO(95) | 2)
+#define MT8135_PIN_95_MSDC4_DAT2__FUNC_I2SIN_WS (MTK_PIN_NO(95) | 3)
+#define MT8135_PIN_95_MSDC4_DAT2__FUNC_CM2PDN_2X (MTK_PIN_NO(95) | 4)
+#define MT8135_PIN_95_MSDC4_DAT2__FUNC_DAC_WS (MTK_PIN_NO(95) | 5)
+#define MT8135_PIN_95_MSDC4_DAT2__FUNC_PCM1_WS (MTK_PIN_NO(95) | 6)
+#define MT8135_PIN_95_MSDC4_DAT2__FUNC_LSCE0B_1X (MTK_PIN_NO(95) | 7)
+
+#define MT8135_PIN_96_MSDC4_CLK__FUNC_GPIO96 (MTK_PIN_NO(96) | 0)
+#define MT8135_PIN_96_MSDC4_CLK__FUNC_MSDC4_CLK (MTK_PIN_NO(96) | 1)
+#define MT8135_PIN_96_MSDC4_CLK__FUNC_EINT129 (MTK_PIN_NO(96) | 2)
+#define MT8135_PIN_96_MSDC4_CLK__FUNC_DPI1_CK_2X (MTK_PIN_NO(96) | 3)
+#define MT8135_PIN_96_MSDC4_CLK__FUNC_CM2PCLK_2X (MTK_PIN_NO(96) | 4)
+#define MT8135_PIN_96_MSDC4_CLK__FUNC_PWM4 (MTK_PIN_NO(96) | 5)
+#define MT8135_PIN_96_MSDC4_CLK__FUNC_PCM1_DI (MTK_PIN_NO(96) | 6)
+#define MT8135_PIN_96_MSDC4_CLK__FUNC_LSCK_1X (MTK_PIN_NO(96) | 7)
+
+#define MT8135_PIN_97_MSDC4_DAT3__FUNC_GPIO97 (MTK_PIN_NO(97) | 0)
+#define MT8135_PIN_97_MSDC4_DAT3__FUNC_MSDC4_DAT3 (MTK_PIN_NO(97) | 1)
+#define MT8135_PIN_97_MSDC4_DAT3__FUNC_EINT132 (MTK_PIN_NO(97) | 2)
+#define MT8135_PIN_97_MSDC4_DAT3__FUNC_I2SOUT_DAT (MTK_PIN_NO(97) | 3)
+#define MT8135_PIN_97_MSDC4_DAT3__FUNC_CM2RST_2X (MTK_PIN_NO(97) | 4)
+#define MT8135_PIN_97_MSDC4_DAT3__FUNC_DAC_DAT_OUT (MTK_PIN_NO(97) | 5)
+#define MT8135_PIN_97_MSDC4_DAT3__FUNC_PCM1_DO (MTK_PIN_NO(97) | 6)
+#define MT8135_PIN_97_MSDC4_DAT3__FUNC_LSCE1B_1X (MTK_PIN_NO(97) | 7)
+
+#define MT8135_PIN_98_MSDC4_CMD__FUNC_GPIO98 (MTK_PIN_NO(98) | 0)
+#define MT8135_PIN_98_MSDC4_CMD__FUNC_MSDC4_CMD (MTK_PIN_NO(98) | 1)
+#define MT8135_PIN_98_MSDC4_CMD__FUNC_EINT128 (MTK_PIN_NO(98) | 2)
+#define MT8135_PIN_98_MSDC4_CMD__FUNC_DPI1_DE_2X (MTK_PIN_NO(98) | 3)
+#define MT8135_PIN_98_MSDC4_CMD__FUNC_PWM3 (MTK_PIN_NO(98) | 5)
+#define MT8135_PIN_98_MSDC4_CMD__FUNC_LSDA_1X (MTK_PIN_NO(98) | 7)
+
+#define MT8135_PIN_99_MSDC4_RSTB__FUNC_GPIO99 (MTK_PIN_NO(99) | 0)
+#define MT8135_PIN_99_MSDC4_RSTB__FUNC_MSDC4_RSTB (MTK_PIN_NO(99) | 1)
+#define MT8135_PIN_99_MSDC4_RSTB__FUNC_EINT130 (MTK_PIN_NO(99) | 2)
+#define MT8135_PIN_99_MSDC4_RSTB__FUNC_I2SIN_CK (MTK_PIN_NO(99) | 3)
+#define MT8135_PIN_99_MSDC4_RSTB__FUNC_CM2MCLK_2X (MTK_PIN_NO(99) | 4)
+#define MT8135_PIN_99_MSDC4_RSTB__FUNC_DAC_CK (MTK_PIN_NO(99) | 5)
+#define MT8135_PIN_99_MSDC4_RSTB__FUNC_PCM1_CK (MTK_PIN_NO(99) | 6)
+#define MT8135_PIN_99_MSDC4_RSTB__FUNC_LSA0_1X (MTK_PIN_NO(99) | 7)
+
+#define MT8135_PIN_100_SDA0__FUNC_GPIO100 (MTK_PIN_NO(100) | 0)
+#define MT8135_PIN_100_SDA0__FUNC_SDA0 (MTK_PIN_NO(100) | 1)
+#define MT8135_PIN_100_SDA0__FUNC_EINT91 (MTK_PIN_NO(100) | 2)
+#define MT8135_PIN_100_SDA0__FUNC_CLKM1 (MTK_PIN_NO(100) | 3)
+#define MT8135_PIN_100_SDA0__FUNC_PWM1 (MTK_PIN_NO(100) | 4)
+#define MT8135_PIN_100_SDA0__FUNC_A_FUNC_DIN_15 (MTK_PIN_NO(100) | 7)
+
+#define MT8135_PIN_101_SCL0__FUNC_GPIO101 (MTK_PIN_NO(101) | 0)
+#define MT8135_PIN_101_SCL0__FUNC_SCL0 (MTK_PIN_NO(101) | 1)
+#define MT8135_PIN_101_SCL0__FUNC_EINT90 (MTK_PIN_NO(101) | 2)
+#define MT8135_PIN_101_SCL0__FUNC_CLKM0 (MTK_PIN_NO(101) | 3)
+#define MT8135_PIN_101_SCL0__FUNC_DISP_PWM (MTK_PIN_NO(101) | 4)
+#define MT8135_PIN_101_SCL0__FUNC_A_FUNC_DIN_16 (MTK_PIN_NO(101) | 7)
+
+#define MT8135_PIN_102_EINT10_AUXIN2__FUNC_GPIO102 (MTK_PIN_NO(102) | 0)
+#define MT8135_PIN_102_EINT10_AUXIN2__FUNC_EINT10 (MTK_PIN_NO(102) | 1)
+#define MT8135_PIN_102_EINT10_AUXIN2__FUNC_USB_TEST_IO_16 (MTK_PIN_NO(102) | 5)
+#define MT8135_PIN_102_EINT10_AUXIN2__FUNC_TESTB_OUT16 (MTK_PIN_NO(102) | 6)
+#define MT8135_PIN_102_EINT10_AUXIN2__FUNC_A_FUNC_DIN_17 (MTK_PIN_NO(102) | 7)
+
+#define MT8135_PIN_103_EINT11_AUXIN3__FUNC_GPIO103 (MTK_PIN_NO(103) | 0)
+#define MT8135_PIN_103_EINT11_AUXIN3__FUNC_EINT11 (MTK_PIN_NO(103) | 1)
+#define MT8135_PIN_103_EINT11_AUXIN3__FUNC_USB_TEST_IO_17 (MTK_PIN_NO(103) | 5)
+#define MT8135_PIN_103_EINT11_AUXIN3__FUNC_TESTB_OUT17 (MTK_PIN_NO(103) | 6)
+#define MT8135_PIN_103_EINT11_AUXIN3__FUNC_A_FUNC_DIN_18 (MTK_PIN_NO(103) | 7)
+
+#define MT8135_PIN_104_EINT16_AUXIN4__FUNC_GPIO104 (MTK_PIN_NO(104) | 0)
+#define MT8135_PIN_104_EINT16_AUXIN4__FUNC_EINT16 (MTK_PIN_NO(104) | 1)
+#define MT8135_PIN_104_EINT16_AUXIN4__FUNC_USB_TEST_IO_18 (MTK_PIN_NO(104) | 5)
+#define MT8135_PIN_104_EINT16_AUXIN4__FUNC_TESTB_OUT18 (MTK_PIN_NO(104) | 6)
+#define MT8135_PIN_104_EINT16_AUXIN4__FUNC_A_FUNC_DIN_19 (MTK_PIN_NO(104) | 7)
+
+#define MT8135_PIN_105_I2S_CLK__FUNC_GPIO105 (MTK_PIN_NO(105) | 0)
+#define MT8135_PIN_105_I2S_CLK__FUNC_I2SIN_CK (MTK_PIN_NO(105) | 1)
+#define MT8135_PIN_105_I2S_CLK__FUNC_EINT10 (MTK_PIN_NO(105) | 2)
+#define MT8135_PIN_105_I2S_CLK__FUNC_DAC_CK (MTK_PIN_NO(105) | 3)
+#define MT8135_PIN_105_I2S_CLK__FUNC_PCM1_CK (MTK_PIN_NO(105) | 4)
+#define MT8135_PIN_105_I2S_CLK__FUNC_USB_TEST_IO_19 (MTK_PIN_NO(105) | 5)
+#define MT8135_PIN_105_I2S_CLK__FUNC_TESTB_OUT19 (MTK_PIN_NO(105) | 6)
+#define MT8135_PIN_105_I2S_CLK__FUNC_A_FUNC_DIN_20 (MTK_PIN_NO(105) | 7)
+
+#define MT8135_PIN_106_I2S_WS__FUNC_GPIO106 (MTK_PIN_NO(106) | 0)
+#define MT8135_PIN_106_I2S_WS__FUNC_I2SIN_WS (MTK_PIN_NO(106) | 1)
+#define MT8135_PIN_106_I2S_WS__FUNC_EINT13 (MTK_PIN_NO(106) | 2)
+#define MT8135_PIN_106_I2S_WS__FUNC_DAC_WS (MTK_PIN_NO(106) | 3)
+#define MT8135_PIN_106_I2S_WS__FUNC_PCM1_WS (MTK_PIN_NO(106) | 4)
+#define MT8135_PIN_106_I2S_WS__FUNC_USB_TEST_IO_20 (MTK_PIN_NO(106) | 5)
+#define MT8135_PIN_106_I2S_WS__FUNC_TESTB_OUT20 (MTK_PIN_NO(106) | 6)
+#define MT8135_PIN_106_I2S_WS__FUNC_A_FUNC_DIN_21 (MTK_PIN_NO(106) | 7)
+
+#define MT8135_PIN_107_I2S_DATA_IN__FUNC_GPIO107 (MTK_PIN_NO(107) | 0)
+#define MT8135_PIN_107_I2S_DATA_IN__FUNC_I2SIN_DAT (MTK_PIN_NO(107) | 1)
+#define MT8135_PIN_107_I2S_DATA_IN__FUNC_EINT11 (MTK_PIN_NO(107) | 2)
+#define MT8135_PIN_107_I2S_DATA_IN__FUNC_PCM1_DI (MTK_PIN_NO(107) | 4)
+#define MT8135_PIN_107_I2S_DATA_IN__FUNC_USB_TEST_IO_21 (MTK_PIN_NO(107) | 5)
+#define MT8135_PIN_107_I2S_DATA_IN__FUNC_TESTB_OUT22 (MTK_PIN_NO(107) | 6)
+#define MT8135_PIN_107_I2S_DATA_IN__FUNC_A_FUNC_DIN_22 (MTK_PIN_NO(107) | 7)
+
+#define MT8135_PIN_108_I2S_DATA_OUT__FUNC_GPIO108 (MTK_PIN_NO(108) | 0)
+#define MT8135_PIN_108_I2S_DATA_OUT__FUNC_I2SOUT_DAT (MTK_PIN_NO(108) | 1)
+#define MT8135_PIN_108_I2S_DATA_OUT__FUNC_EINT12 (MTK_PIN_NO(108) | 2)
+#define MT8135_PIN_108_I2S_DATA_OUT__FUNC_DAC_DAT_OUT (MTK_PIN_NO(108) | 3)
+#define MT8135_PIN_108_I2S_DATA_OUT__FUNC_PCM1_DO (MTK_PIN_NO(108) | 4)
+#define MT8135_PIN_108_I2S_DATA_OUT__FUNC_USB_TEST_IO_22 (MTK_PIN_NO(108) | 5)
+#define MT8135_PIN_108_I2S_DATA_OUT__FUNC_TESTB_OUT23 (MTK_PIN_NO(108) | 6)
+#define MT8135_PIN_108_I2S_DATA_OUT__FUNC_A_FUNC_DIN_23 (MTK_PIN_NO(108) | 7)
+
+#define MT8135_PIN_109_EINT5__FUNC_GPIO109 (MTK_PIN_NO(109) | 0)
+#define MT8135_PIN_109_EINT5__FUNC_EINT5 (MTK_PIN_NO(109) | 1)
+#define MT8135_PIN_109_EINT5__FUNC_PWM5 (MTK_PIN_NO(109) | 2)
+#define MT8135_PIN_109_EINT5__FUNC_CLKM3 (MTK_PIN_NO(109) | 3)
+#define MT8135_PIN_109_EINT5__FUNC_GPU_JTRSTB (MTK_PIN_NO(109) | 4)
+#define MT8135_PIN_109_EINT5__FUNC_USB_TEST_IO_23 (MTK_PIN_NO(109) | 5)
+#define MT8135_PIN_109_EINT5__FUNC_TESTB_OUT26 (MTK_PIN_NO(109) | 6)
+#define MT8135_PIN_109_EINT5__FUNC_A_FUNC_DIN_24 (MTK_PIN_NO(109) | 7)
+
+#define MT8135_PIN_110_EINT6__FUNC_GPIO110 (MTK_PIN_NO(110) | 0)
+#define MT8135_PIN_110_EINT6__FUNC_EINT6 (MTK_PIN_NO(110) | 1)
+#define MT8135_PIN_110_EINT6__FUNC_PWM6 (MTK_PIN_NO(110) | 2)
+#define MT8135_PIN_110_EINT6__FUNC_CLKM4 (MTK_PIN_NO(110) | 3)
+#define MT8135_PIN_110_EINT6__FUNC_GPU_JTMS (MTK_PIN_NO(110) | 4)
+#define MT8135_PIN_110_EINT6__FUNC_USB_TEST_IO_24 (MTK_PIN_NO(110) | 5)
+#define MT8135_PIN_110_EINT6__FUNC_TESTB_OUT27 (MTK_PIN_NO(110) | 6)
+#define MT8135_PIN_110_EINT6__FUNC_A_FUNC_DIN_25 (MTK_PIN_NO(110) | 7)
+
+#define MT8135_PIN_111_EINT7__FUNC_GPIO111 (MTK_PIN_NO(111) | 0)
+#define MT8135_PIN_111_EINT7__FUNC_EINT7 (MTK_PIN_NO(111) | 1)
+#define MT8135_PIN_111_EINT7__FUNC_PWM7 (MTK_PIN_NO(111) | 2)
+#define MT8135_PIN_111_EINT7__FUNC_CLKM5 (MTK_PIN_NO(111) | 3)
+#define MT8135_PIN_111_EINT7__FUNC_GPU_JTDO (MTK_PIN_NO(111) | 4)
+#define MT8135_PIN_111_EINT7__FUNC_USB_TEST_IO_25 (MTK_PIN_NO(111) | 5)
+#define MT8135_PIN_111_EINT7__FUNC_TESTB_OUT28 (MTK_PIN_NO(111) | 6)
+#define MT8135_PIN_111_EINT7__FUNC_A_FUNC_DIN_26 (MTK_PIN_NO(111) | 7)
+
+#define MT8135_PIN_112_EINT8__FUNC_GPIO112 (MTK_PIN_NO(112) | 0)
+#define MT8135_PIN_112_EINT8__FUNC_EINT8 (MTK_PIN_NO(112) | 1)
+#define MT8135_PIN_112_EINT8__FUNC_DISP_PWM (MTK_PIN_NO(112) | 2)
+#define MT8135_PIN_112_EINT8__FUNC_CLKM6 (MTK_PIN_NO(112) | 3)
+#define MT8135_PIN_112_EINT8__FUNC_GPU_JTDI (MTK_PIN_NO(112) | 4)
+#define MT8135_PIN_112_EINT8__FUNC_USB_TEST_IO_26 (MTK_PIN_NO(112) | 5)
+#define MT8135_PIN_112_EINT8__FUNC_TESTB_OUT29 (MTK_PIN_NO(112) | 6)
+#define MT8135_PIN_112_EINT8__FUNC_EXT_FRAME_SYNC (MTK_PIN_NO(112) | 7)
+
+#define MT8135_PIN_113_EINT9__FUNC_GPIO113 (MTK_PIN_NO(113) | 0)
+#define MT8135_PIN_113_EINT9__FUNC_EINT9 (MTK_PIN_NO(113) | 1)
+#define MT8135_PIN_113_EINT9__FUNC_GPU_JTCK (MTK_PIN_NO(113) | 4)
+#define MT8135_PIN_113_EINT9__FUNC_USB_DRVVBUS (MTK_PIN_NO(113) | 5)
+#define MT8135_PIN_113_EINT9__FUNC_TESTB_OUT30 (MTK_PIN_NO(113) | 6)
+#define MT8135_PIN_113_EINT9__FUNC_A_FUNC_DIN_27 (MTK_PIN_NO(113) | 7)
+
+#define MT8135_PIN_114_LPCE1B__FUNC_GPIO114 (MTK_PIN_NO(114) | 0)
+#define MT8135_PIN_114_LPCE1B__FUNC_LPCE1B (MTK_PIN_NO(114) | 1)
+#define MT8135_PIN_114_LPCE1B__FUNC_EINT127 (MTK_PIN_NO(114) | 2)
+#define MT8135_PIN_114_LPCE1B__FUNC_PWM2 (MTK_PIN_NO(114) | 5)
+#define MT8135_PIN_114_LPCE1B__FUNC_TESTB_OUT14 (MTK_PIN_NO(114) | 6)
+#define MT8135_PIN_114_LPCE1B__FUNC_A_FUNC_DIN_28 (MTK_PIN_NO(114) | 7)
+
+#define MT8135_PIN_115_LPCE0B__FUNC_GPIO115 (MTK_PIN_NO(115) | 0)
+#define MT8135_PIN_115_LPCE0B__FUNC_LPCE0B (MTK_PIN_NO(115) | 1)
+#define MT8135_PIN_115_LPCE0B__FUNC_EINT126 (MTK_PIN_NO(115) | 2)
+#define MT8135_PIN_115_LPCE0B__FUNC_PWM1 (MTK_PIN_NO(115) | 5)
+#define MT8135_PIN_115_LPCE0B__FUNC_TESTB_OUT15 (MTK_PIN_NO(115) | 6)
+#define MT8135_PIN_115_LPCE0B__FUNC_A_FUNC_DIN_29 (MTK_PIN_NO(115) | 7)
+
+#define MT8135_PIN_116_DISP_PWM__FUNC_GPIO116 (MTK_PIN_NO(116) | 0)
+#define MT8135_PIN_116_DISP_PWM__FUNC_DISP_PWM (MTK_PIN_NO(116) | 1)
+#define MT8135_PIN_116_DISP_PWM__FUNC_EINT77 (MTK_PIN_NO(116) | 2)
+#define MT8135_PIN_116_DISP_PWM__FUNC_LSDI (MTK_PIN_NO(116) | 3)
+#define MT8135_PIN_116_DISP_PWM__FUNC_PWM1 (MTK_PIN_NO(116) | 4)
+#define MT8135_PIN_116_DISP_PWM__FUNC_PWM2 (MTK_PIN_NO(116) | 5)
+#define MT8135_PIN_116_DISP_PWM__FUNC_PWM3 (MTK_PIN_NO(116) | 7)
+
+#define MT8135_PIN_117_EINT1__FUNC_GPIO117 (MTK_PIN_NO(117) | 0)
+#define MT8135_PIN_117_EINT1__FUNC_EINT1 (MTK_PIN_NO(117) | 1)
+#define MT8135_PIN_117_EINT1__FUNC_PWM2 (MTK_PIN_NO(117) | 2)
+#define MT8135_PIN_117_EINT1__FUNC_CLKM1 (MTK_PIN_NO(117) | 3)
+#define MT8135_PIN_117_EINT1__FUNC_USB_TEST_IO_13 (MTK_PIN_NO(117) | 5)
+#define MT8135_PIN_117_EINT1__FUNC_USB_SDA (MTK_PIN_NO(117) | 7)
+
+#define MT8135_PIN_118_EINT2__FUNC_GPIO118 (MTK_PIN_NO(118) | 0)
+#define MT8135_PIN_118_EINT2__FUNC_EINT2 (MTK_PIN_NO(118) | 1)
+#define MT8135_PIN_118_EINT2__FUNC_PWM3 (MTK_PIN_NO(118) | 2)
+#define MT8135_PIN_118_EINT2__FUNC_CLKM2 (MTK_PIN_NO(118) | 3)
+#define MT8135_PIN_118_EINT2__FUNC_USB_TEST_IO_14 (MTK_PIN_NO(118) | 5)
+#define MT8135_PIN_118_EINT2__FUNC_SRCLKENAI2 (MTK_PIN_NO(118) | 6)
+#define MT8135_PIN_118_EINT2__FUNC_A_FUNC_DIN_30 (MTK_PIN_NO(118) | 7)
+
+#define MT8135_PIN_119_EINT3__FUNC_GPIO119 (MTK_PIN_NO(119) | 0)
+#define MT8135_PIN_119_EINT3__FUNC_EINT3 (MTK_PIN_NO(119) | 1)
+#define MT8135_PIN_119_EINT3__FUNC_USB_TEST_IO_15 (MTK_PIN_NO(119) | 5)
+#define MT8135_PIN_119_EINT3__FUNC_SRCLKENAI1 (MTK_PIN_NO(119) | 6)
+#define MT8135_PIN_119_EINT3__FUNC_EXT_26M_CK (MTK_PIN_NO(119) | 7)
+
+#define MT8135_PIN_120_EINT4__FUNC_GPIO120 (MTK_PIN_NO(120) | 0)
+#define MT8135_PIN_120_EINT4__FUNC_EINT4 (MTK_PIN_NO(120) | 1)
+#define MT8135_PIN_120_EINT4__FUNC_PWM4 (MTK_PIN_NO(120) | 2)
+#define MT8135_PIN_120_EINT4__FUNC_USB_DRVVBUS (MTK_PIN_NO(120) | 5)
+#define MT8135_PIN_120_EINT4__FUNC_A_FUNC_DIN_31 (MTK_PIN_NO(120) | 7)
+
+#define MT8135_PIN_121_DPIDE__FUNC_GPIO121 (MTK_PIN_NO(121) | 0)
+#define MT8135_PIN_121_DPIDE__FUNC_DPI0_DE (MTK_PIN_NO(121) | 1)
+#define MT8135_PIN_121_DPIDE__FUNC_EINT100 (MTK_PIN_NO(121) | 2)
+#define MT8135_PIN_121_DPIDE__FUNC_I2SOUT_DAT (MTK_PIN_NO(121) | 3)
+#define MT8135_PIN_121_DPIDE__FUNC_DAC_DAT_OUT (MTK_PIN_NO(121) | 4)
+#define MT8135_PIN_121_DPIDE__FUNC_PCM1_DO (MTK_PIN_NO(121) | 5)
+#define MT8135_PIN_121_DPIDE__FUNC_IRDA_TXD (MTK_PIN_NO(121) | 6)
+
+#define MT8135_PIN_122_DPICK__FUNC_GPIO122 (MTK_PIN_NO(122) | 0)
+#define MT8135_PIN_122_DPICK__FUNC_DPI0_CK (MTK_PIN_NO(122) | 1)
+#define MT8135_PIN_122_DPICK__FUNC_EINT101 (MTK_PIN_NO(122) | 2)
+#define MT8135_PIN_122_DPICK__FUNC_I2SIN_DAT (MTK_PIN_NO(122) | 3)
+#define MT8135_PIN_122_DPICK__FUNC_PCM1_DI (MTK_PIN_NO(122) | 5)
+#define MT8135_PIN_122_DPICK__FUNC_IRDA_PDN (MTK_PIN_NO(122) | 6)
+
+#define MT8135_PIN_123_DPIG4__FUNC_GPIO123 (MTK_PIN_NO(123) | 0)
+#define MT8135_PIN_123_DPIG4__FUNC_DPI0_G4 (MTK_PIN_NO(123) | 1)
+#define MT8135_PIN_123_DPIG4__FUNC_EINT114 (MTK_PIN_NO(123) | 2)
+#define MT8135_PIN_123_DPIG4__FUNC_CM2DAT_2X_0 (MTK_PIN_NO(123) | 4)
+#define MT8135_PIN_123_DPIG4__FUNC_DSP2_ID (MTK_PIN_NO(123) | 5)
+
+#define MT8135_PIN_124_DPIG5__FUNC_GPIO124 (MTK_PIN_NO(124) | 0)
+#define MT8135_PIN_124_DPIG5__FUNC_DPI0_G5 (MTK_PIN_NO(124) | 1)
+#define MT8135_PIN_124_DPIG5__FUNC_EINT115 (MTK_PIN_NO(124) | 2)
+#define MT8135_PIN_124_DPIG5__FUNC_CM2DAT_2X_1 (MTK_PIN_NO(124) | 4)
+#define MT8135_PIN_124_DPIG5__FUNC_DSP2_ICK (MTK_PIN_NO(124) | 5)
+
+#define MT8135_PIN_125_DPIR3__FUNC_GPIO125 (MTK_PIN_NO(125) | 0)
+#define MT8135_PIN_125_DPIR3__FUNC_DPI0_R3 (MTK_PIN_NO(125) | 1)
+#define MT8135_PIN_125_DPIR3__FUNC_EINT121 (MTK_PIN_NO(125) | 2)
+#define MT8135_PIN_125_DPIR3__FUNC_CM2DAT_2X_7 (MTK_PIN_NO(125) | 4)
+
+#define MT8135_PIN_126_DPIG1__FUNC_GPIO126 (MTK_PIN_NO(126) | 0)
+#define MT8135_PIN_126_DPIG1__FUNC_DPI0_G1 (MTK_PIN_NO(126) | 1)
+#define MT8135_PIN_126_DPIG1__FUNC_EINT111 (MTK_PIN_NO(126) | 2)
+#define MT8135_PIN_126_DPIG1__FUNC_DSP1_ICK (MTK_PIN_NO(126) | 5)
+
+#define MT8135_PIN_127_DPIVSYNC__FUNC_GPIO127 (MTK_PIN_NO(127) | 0)
+#define MT8135_PIN_127_DPIVSYNC__FUNC_DPI0_VSYNC (MTK_PIN_NO(127) | 1)
+#define MT8135_PIN_127_DPIVSYNC__FUNC_EINT98 (MTK_PIN_NO(127) | 2)
+#define MT8135_PIN_127_DPIVSYNC__FUNC_I2SIN_CK (MTK_PIN_NO(127) | 3)
+#define MT8135_PIN_127_DPIVSYNC__FUNC_DAC_CK (MTK_PIN_NO(127) | 4)
+#define MT8135_PIN_127_DPIVSYNC__FUNC_PCM1_CK (MTK_PIN_NO(127) | 5)
+
+#define MT8135_PIN_128_DPIHSYNC__FUNC_GPIO128 (MTK_PIN_NO(128) | 0)
+#define MT8135_PIN_128_DPIHSYNC__FUNC_DPI0_HSYNC (MTK_PIN_NO(128) | 1)
+#define MT8135_PIN_128_DPIHSYNC__FUNC_EINT99 (MTK_PIN_NO(128) | 2)
+#define MT8135_PIN_128_DPIHSYNC__FUNC_I2SIN_WS (MTK_PIN_NO(128) | 3)
+#define MT8135_PIN_128_DPIHSYNC__FUNC_DAC_WS (MTK_PIN_NO(128) | 4)
+#define MT8135_PIN_128_DPIHSYNC__FUNC_PCM1_WS (MTK_PIN_NO(128) | 5)
+#define MT8135_PIN_128_DPIHSYNC__FUNC_IRDA_RXD (MTK_PIN_NO(128) | 6)
+
+#define MT8135_PIN_129_DPIB0__FUNC_GPIO129 (MTK_PIN_NO(129) | 0)
+#define MT8135_PIN_129_DPIB0__FUNC_DPI0_B0 (MTK_PIN_NO(129) | 1)
+#define MT8135_PIN_129_DPIB0__FUNC_EINT102 (MTK_PIN_NO(129) | 2)
+#define MT8135_PIN_129_DPIB0__FUNC_SCL0 (MTK_PIN_NO(129) | 4)
+#define MT8135_PIN_129_DPIB0__FUNC_DISP_PWM (MTK_PIN_NO(129) | 5)
+
+#define MT8135_PIN_130_DPIB1__FUNC_GPIO130 (MTK_PIN_NO(130) | 0)
+#define MT8135_PIN_130_DPIB1__FUNC_DPI0_B1 (MTK_PIN_NO(130) | 1)
+#define MT8135_PIN_130_DPIB1__FUNC_EINT103 (MTK_PIN_NO(130) | 2)
+#define MT8135_PIN_130_DPIB1__FUNC_CLKM0 (MTK_PIN_NO(130) | 3)
+#define MT8135_PIN_130_DPIB1__FUNC_SDA0 (MTK_PIN_NO(130) | 4)
+#define MT8135_PIN_130_DPIB1__FUNC_PWM1 (MTK_PIN_NO(130) | 5)
+
+#define MT8135_PIN_131_DPIB2__FUNC_GPIO131 (MTK_PIN_NO(131) | 0)
+#define MT8135_PIN_131_DPIB2__FUNC_DPI0_B2 (MTK_PIN_NO(131) | 1)
+#define MT8135_PIN_131_DPIB2__FUNC_EINT104 (MTK_PIN_NO(131) | 2)
+#define MT8135_PIN_131_DPIB2__FUNC_CLKM1 (MTK_PIN_NO(131) | 3)
+#define MT8135_PIN_131_DPIB2__FUNC_SCL1 (MTK_PIN_NO(131) | 4)
+#define MT8135_PIN_131_DPIB2__FUNC_PWM2 (MTK_PIN_NO(131) | 5)
+
+#define MT8135_PIN_132_DPIB3__FUNC_GPIO132 (MTK_PIN_NO(132) | 0)
+#define MT8135_PIN_132_DPIB3__FUNC_DPI0_B3 (MTK_PIN_NO(132) | 1)
+#define MT8135_PIN_132_DPIB3__FUNC_EINT105 (MTK_PIN_NO(132) | 2)
+#define MT8135_PIN_132_DPIB3__FUNC_CLKM2 (MTK_PIN_NO(132) | 3)
+#define MT8135_PIN_132_DPIB3__FUNC_SDA1 (MTK_PIN_NO(132) | 4)
+#define MT8135_PIN_132_DPIB3__FUNC_PWM3 (MTK_PIN_NO(132) | 5)
+
+#define MT8135_PIN_133_DPIB4__FUNC_GPIO133 (MTK_PIN_NO(133) | 0)
+#define MT8135_PIN_133_DPIB4__FUNC_DPI0_B4 (MTK_PIN_NO(133) | 1)
+#define MT8135_PIN_133_DPIB4__FUNC_EINT106 (MTK_PIN_NO(133) | 2)
+#define MT8135_PIN_133_DPIB4__FUNC_CLKM3 (MTK_PIN_NO(133) | 3)
+#define MT8135_PIN_133_DPIB4__FUNC_SCL2 (MTK_PIN_NO(133) | 4)
+#define MT8135_PIN_133_DPIB4__FUNC_PWM4 (MTK_PIN_NO(133) | 5)
+
+#define MT8135_PIN_134_DPIB5__FUNC_GPIO134 (MTK_PIN_NO(134) | 0)
+#define MT8135_PIN_134_DPIB5__FUNC_DPI0_B5 (MTK_PIN_NO(134) | 1)
+#define MT8135_PIN_134_DPIB5__FUNC_EINT107 (MTK_PIN_NO(134) | 2)
+#define MT8135_PIN_134_DPIB5__FUNC_CLKM4 (MTK_PIN_NO(134) | 3)
+#define MT8135_PIN_134_DPIB5__FUNC_SDA2 (MTK_PIN_NO(134) | 4)
+#define MT8135_PIN_134_DPIB5__FUNC_PWM5 (MTK_PIN_NO(134) | 5)
+
+#define MT8135_PIN_135_DPIB6__FUNC_GPIO135 (MTK_PIN_NO(135) | 0)
+#define MT8135_PIN_135_DPIB6__FUNC_DPI0_B6 (MTK_PIN_NO(135) | 1)
+#define MT8135_PIN_135_DPIB6__FUNC_EINT108 (MTK_PIN_NO(135) | 2)
+#define MT8135_PIN_135_DPIB6__FUNC_CLKM5 (MTK_PIN_NO(135) | 3)
+#define MT8135_PIN_135_DPIB6__FUNC_SCL3 (MTK_PIN_NO(135) | 4)
+#define MT8135_PIN_135_DPIB6__FUNC_PWM6 (MTK_PIN_NO(135) | 5)
+
+#define MT8135_PIN_136_DPIB7__FUNC_GPIO136 (MTK_PIN_NO(136) | 0)
+#define MT8135_PIN_136_DPIB7__FUNC_DPI0_B7 (MTK_PIN_NO(136) | 1)
+#define MT8135_PIN_136_DPIB7__FUNC_EINT109 (MTK_PIN_NO(136) | 2)
+#define MT8135_PIN_136_DPIB7__FUNC_CLKM6 (MTK_PIN_NO(136) | 3)
+#define MT8135_PIN_136_DPIB7__FUNC_SDA3 (MTK_PIN_NO(136) | 4)
+#define MT8135_PIN_136_DPIB7__FUNC_PWM7 (MTK_PIN_NO(136) | 5)
+
+#define MT8135_PIN_137_DPIG0__FUNC_GPIO137 (MTK_PIN_NO(137) | 0)
+#define MT8135_PIN_137_DPIG0__FUNC_DPI0_G0 (MTK_PIN_NO(137) | 1)
+#define MT8135_PIN_137_DPIG0__FUNC_EINT110 (MTK_PIN_NO(137) | 2)
+#define MT8135_PIN_137_DPIG0__FUNC_DSP1_ID (MTK_PIN_NO(137) | 5)
+
+#define MT8135_PIN_138_DPIG2__FUNC_GPIO138 (MTK_PIN_NO(138) | 0)
+#define MT8135_PIN_138_DPIG2__FUNC_DPI0_G2 (MTK_PIN_NO(138) | 1)
+#define MT8135_PIN_138_DPIG2__FUNC_EINT112 (MTK_PIN_NO(138) | 2)
+#define MT8135_PIN_138_DPIG2__FUNC_DSP1_IMS (MTK_PIN_NO(138) | 5)
+
+#define MT8135_PIN_139_DPIG3__FUNC_GPIO139 (MTK_PIN_NO(139) | 0)
+#define MT8135_PIN_139_DPIG3__FUNC_DPI0_G3 (MTK_PIN_NO(139) | 1)
+#define MT8135_PIN_139_DPIG3__FUNC_EINT113 (MTK_PIN_NO(139) | 2)
+#define MT8135_PIN_139_DPIG3__FUNC_DSP2_IMS (MTK_PIN_NO(139) | 5)
+
+#define MT8135_PIN_140_DPIG6__FUNC_GPIO140 (MTK_PIN_NO(140) | 0)
+#define MT8135_PIN_140_DPIG6__FUNC_DPI0_G6 (MTK_PIN_NO(140) | 1)
+#define MT8135_PIN_140_DPIG6__FUNC_EINT116 (MTK_PIN_NO(140) | 2)
+#define MT8135_PIN_140_DPIG6__FUNC_CM2DAT_2X_2 (MTK_PIN_NO(140) | 4)
+
+#define MT8135_PIN_141_DPIG7__FUNC_GPIO141 (MTK_PIN_NO(141) | 0)
+#define MT8135_PIN_141_DPIG7__FUNC_DPI0_G7 (MTK_PIN_NO(141) | 1)
+#define MT8135_PIN_141_DPIG7__FUNC_EINT117 (MTK_PIN_NO(141) | 2)
+#define MT8135_PIN_141_DPIG7__FUNC_CM2DAT_2X_3 (MTK_PIN_NO(141) | 4)
+
+#define MT8135_PIN_142_DPIR0__FUNC_GPIO142 (MTK_PIN_NO(142) | 0)
+#define MT8135_PIN_142_DPIR0__FUNC_DPI0_R0 (MTK_PIN_NO(142) | 1)
+#define MT8135_PIN_142_DPIR0__FUNC_EINT118 (MTK_PIN_NO(142) | 2)
+#define MT8135_PIN_142_DPIR0__FUNC_CM2DAT_2X_4 (MTK_PIN_NO(142) | 4)
+
+#define MT8135_PIN_143_DPIR1__FUNC_GPIO143 (MTK_PIN_NO(143) | 0)
+#define MT8135_PIN_143_DPIR1__FUNC_DPI0_R1 (MTK_PIN_NO(143) | 1)
+#define MT8135_PIN_143_DPIR1__FUNC_EINT119 (MTK_PIN_NO(143) | 2)
+#define MT8135_PIN_143_DPIR1__FUNC_CM2DAT_2X_5 (MTK_PIN_NO(143) | 4)
+
+#define MT8135_PIN_144_DPIR2__FUNC_GPIO144 (MTK_PIN_NO(144) | 0)
+#define MT8135_PIN_144_DPIR2__FUNC_DPI0_R2 (MTK_PIN_NO(144) | 1)
+#define MT8135_PIN_144_DPIR2__FUNC_EINT120 (MTK_PIN_NO(144) | 2)
+#define MT8135_PIN_144_DPIR2__FUNC_CM2DAT_2X_6 (MTK_PIN_NO(144) | 4)
+
+#define MT8135_PIN_145_DPIR4__FUNC_GPIO145 (MTK_PIN_NO(145) | 0)
+#define MT8135_PIN_145_DPIR4__FUNC_DPI0_R4 (MTK_PIN_NO(145) | 1)
+#define MT8135_PIN_145_DPIR4__FUNC_EINT122 (MTK_PIN_NO(145) | 2)
+#define MT8135_PIN_145_DPIR4__FUNC_CM2DAT_2X_8 (MTK_PIN_NO(145) | 4)
+
+#define MT8135_PIN_146_DPIR5__FUNC_GPIO146 (MTK_PIN_NO(146) | 0)
+#define MT8135_PIN_146_DPIR5__FUNC_DPI0_R5 (MTK_PIN_NO(146) | 1)
+#define MT8135_PIN_146_DPIR5__FUNC_EINT123 (MTK_PIN_NO(146) | 2)
+#define MT8135_PIN_146_DPIR5__FUNC_CM2DAT_2X_9 (MTK_PIN_NO(146) | 4)
+
+#define MT8135_PIN_147_DPIR6__FUNC_GPIO147 (MTK_PIN_NO(147) | 0)
+#define MT8135_PIN_147_DPIR6__FUNC_DPI0_R6 (MTK_PIN_NO(147) | 1)
+#define MT8135_PIN_147_DPIR6__FUNC_EINT124 (MTK_PIN_NO(147) | 2)
+#define MT8135_PIN_147_DPIR6__FUNC_CM2VSYNC_2X (MTK_PIN_NO(147) | 4)
+
+#define MT8135_PIN_148_DPIR7__FUNC_GPIO148 (MTK_PIN_NO(148) | 0)
+#define MT8135_PIN_148_DPIR7__FUNC_DPI0_R7 (MTK_PIN_NO(148) | 1)
+#define MT8135_PIN_148_DPIR7__FUNC_EINT125 (MTK_PIN_NO(148) | 2)
+#define MT8135_PIN_148_DPIR7__FUNC_CM2HSYNC_2X (MTK_PIN_NO(148) | 4)
+
+#define MT8135_PIN_149_TDN3__FUNC_GPIO149 (MTK_PIN_NO(149) | 0)
+#define MT8135_PIN_149_TDN3__FUNC_EINT36 (MTK_PIN_NO(149) | 2)
+
+#define MT8135_PIN_150_TDP3__FUNC_GPIO150 (MTK_PIN_NO(150) | 0)
+#define MT8135_PIN_150_TDP3__FUNC_EINT35 (MTK_PIN_NO(150) | 2)
+
+#define MT8135_PIN_151_TDN2__FUNC_GPIO151 (MTK_PIN_NO(151) | 0)
+#define MT8135_PIN_151_TDN2__FUNC_EINT169 (MTK_PIN_NO(151) | 2)
+
+#define MT8135_PIN_152_TDP2__FUNC_GPIO152 (MTK_PIN_NO(152) | 0)
+#define MT8135_PIN_152_TDP2__FUNC_EINT168 (MTK_PIN_NO(152) | 2)
+
+#define MT8135_PIN_153_TCN__FUNC_GPIO153 (MTK_PIN_NO(153) | 0)
+#define MT8135_PIN_153_TCN__FUNC_EINT163 (MTK_PIN_NO(153) | 2)
+
+#define MT8135_PIN_154_TCP__FUNC_GPIO154 (MTK_PIN_NO(154) | 0)
+#define MT8135_PIN_154_TCP__FUNC_EINT162 (MTK_PIN_NO(154) | 2)
+
+#define MT8135_PIN_155_TDN1__FUNC_GPIO155 (MTK_PIN_NO(155) | 0)
+#define MT8135_PIN_155_TDN1__FUNC_EINT167 (MTK_PIN_NO(155) | 2)
+
+#define MT8135_PIN_156_TDP1__FUNC_GPIO156 (MTK_PIN_NO(156) | 0)
+#define MT8135_PIN_156_TDP1__FUNC_EINT166 (MTK_PIN_NO(156) | 2)
+
+#define MT8135_PIN_157_TDN0__FUNC_GPIO157 (MTK_PIN_NO(157) | 0)
+#define MT8135_PIN_157_TDN0__FUNC_EINT165 (MTK_PIN_NO(157) | 2)
+
+#define MT8135_PIN_158_TDP0__FUNC_GPIO158 (MTK_PIN_NO(158) | 0)
+#define MT8135_PIN_158_TDP0__FUNC_EINT164 (MTK_PIN_NO(158) | 2)
+
+#define MT8135_PIN_159_RDN3__FUNC_GPIO159 (MTK_PIN_NO(159) | 0)
+#define MT8135_PIN_159_RDN3__FUNC_EINT18 (MTK_PIN_NO(159) | 2)
+
+#define MT8135_PIN_160_RDP3__FUNC_GPIO160 (MTK_PIN_NO(160) | 0)
+#define MT8135_PIN_160_RDP3__FUNC_EINT30 (MTK_PIN_NO(160) | 2)
+
+#define MT8135_PIN_161_RDN2__FUNC_GPIO161 (MTK_PIN_NO(161) | 0)
+#define MT8135_PIN_161_RDN2__FUNC_EINT31 (MTK_PIN_NO(161) | 2)
+
+#define MT8135_PIN_162_RDP2__FUNC_GPIO162 (MTK_PIN_NO(162) | 0)
+#define MT8135_PIN_162_RDP2__FUNC_EINT32 (MTK_PIN_NO(162) | 2)
+
+#define MT8135_PIN_163_RCN__FUNC_GPIO163 (MTK_PIN_NO(163) | 0)
+#define MT8135_PIN_163_RCN__FUNC_EINT33 (MTK_PIN_NO(163) | 2)
+
+#define MT8135_PIN_164_RCP__FUNC_GPIO164 (MTK_PIN_NO(164) | 0)
+#define MT8135_PIN_164_RCP__FUNC_EINT39 (MTK_PIN_NO(164) | 2)
+
+#define MT8135_PIN_165_RDN1__FUNC_GPIO165 (MTK_PIN_NO(165) | 0)
+
+#define MT8135_PIN_166_RDP1__FUNC_GPIO166 (MTK_PIN_NO(166) | 0)
+
+#define MT8135_PIN_167_RDN0__FUNC_GPIO167 (MTK_PIN_NO(167) | 0)
+
+#define MT8135_PIN_168_RDP0__FUNC_GPIO168 (MTK_PIN_NO(168) | 0)
+
+#define MT8135_PIN_169_RDN1_A__FUNC_GPIO169 (MTK_PIN_NO(169) | 0)
+#define MT8135_PIN_169_RDN1_A__FUNC_CMDAT6 (MTK_PIN_NO(169) | 1)
+#define MT8135_PIN_169_RDN1_A__FUNC_EINT175 (MTK_PIN_NO(169) | 2)
+
+#define MT8135_PIN_170_RDP1_A__FUNC_GPIO170 (MTK_PIN_NO(170) | 0)
+#define MT8135_PIN_170_RDP1_A__FUNC_CMDAT7 (MTK_PIN_NO(170) | 1)
+#define MT8135_PIN_170_RDP1_A__FUNC_EINT174 (MTK_PIN_NO(170) | 2)
+
+#define MT8135_PIN_171_RCN_A__FUNC_GPIO171 (MTK_PIN_NO(171) | 0)
+#define MT8135_PIN_171_RCN_A__FUNC_CMDAT8 (MTK_PIN_NO(171) | 1)
+#define MT8135_PIN_171_RCN_A__FUNC_EINT171 (MTK_PIN_NO(171) | 2)
+
+#define MT8135_PIN_172_RCP_A__FUNC_GPIO172 (MTK_PIN_NO(172) | 0)
+#define MT8135_PIN_172_RCP_A__FUNC_CMDAT9 (MTK_PIN_NO(172) | 1)
+#define MT8135_PIN_172_RCP_A__FUNC_EINT170 (MTK_PIN_NO(172) | 2)
+
+#define MT8135_PIN_173_RDN0_A__FUNC_GPIO173 (MTK_PIN_NO(173) | 0)
+#define MT8135_PIN_173_RDN0_A__FUNC_CMHSYNC (MTK_PIN_NO(173) | 1)
+#define MT8135_PIN_173_RDN0_A__FUNC_EINT173 (MTK_PIN_NO(173) | 2)
+
+#define MT8135_PIN_174_RDP0_A__FUNC_GPIO174 (MTK_PIN_NO(174) | 0)
+#define MT8135_PIN_174_RDP0_A__FUNC_CMVSYNC (MTK_PIN_NO(174) | 1)
+#define MT8135_PIN_174_RDP0_A__FUNC_EINT172 (MTK_PIN_NO(174) | 2)
+
+#define MT8135_PIN_175_RDN1_B__FUNC_GPIO175 (MTK_PIN_NO(175) | 0)
+#define MT8135_PIN_175_RDN1_B__FUNC_CMDAT2 (MTK_PIN_NO(175) | 1)
+#define MT8135_PIN_175_RDN1_B__FUNC_EINT181 (MTK_PIN_NO(175) | 2)
+#define MT8135_PIN_175_RDN1_B__FUNC_CMCSD2 (MTK_PIN_NO(175) | 3)
+
+#define MT8135_PIN_176_RDP1_B__FUNC_GPIO176 (MTK_PIN_NO(176) | 0)
+#define MT8135_PIN_176_RDP1_B__FUNC_CMDAT3 (MTK_PIN_NO(176) | 1)
+#define MT8135_PIN_176_RDP1_B__FUNC_EINT180 (MTK_PIN_NO(176) | 2)
+#define MT8135_PIN_176_RDP1_B__FUNC_CMCSD3 (MTK_PIN_NO(176) | 3)
+
+#define MT8135_PIN_177_RCN_B__FUNC_GPIO177 (MTK_PIN_NO(177) | 0)
+#define MT8135_PIN_177_RCN_B__FUNC_CMDAT4 (MTK_PIN_NO(177) | 1)
+#define MT8135_PIN_177_RCN_B__FUNC_EINT177 (MTK_PIN_NO(177) | 2)
+
+#define MT8135_PIN_178_RCP_B__FUNC_GPIO178 (MTK_PIN_NO(178) | 0)
+#define MT8135_PIN_178_RCP_B__FUNC_CMDAT5 (MTK_PIN_NO(178) | 1)
+#define MT8135_PIN_178_RCP_B__FUNC_EINT176 (MTK_PIN_NO(178) | 2)
+
+#define MT8135_PIN_179_RDN0_B__FUNC_GPIO179 (MTK_PIN_NO(179) | 0)
+#define MT8135_PIN_179_RDN0_B__FUNC_CMDAT0 (MTK_PIN_NO(179) | 1)
+#define MT8135_PIN_179_RDN0_B__FUNC_EINT179 (MTK_PIN_NO(179) | 2)
+#define MT8135_PIN_179_RDN0_B__FUNC_CMCSD0 (MTK_PIN_NO(179) | 3)
+
+#define MT8135_PIN_180_RDP0_B__FUNC_GPIO180 (MTK_PIN_NO(180) | 0)
+#define MT8135_PIN_180_RDP0_B__FUNC_CMDAT1 (MTK_PIN_NO(180) | 1)
+#define MT8135_PIN_180_RDP0_B__FUNC_EINT178 (MTK_PIN_NO(180) | 2)
+#define MT8135_PIN_180_RDP0_B__FUNC_CMCSD1 (MTK_PIN_NO(180) | 3)
+
+#define MT8135_PIN_181_CMPCLK__FUNC_GPIO181 (MTK_PIN_NO(181) | 0)
+#define MT8135_PIN_181_CMPCLK__FUNC_CMPCLK (MTK_PIN_NO(181) | 1)
+#define MT8135_PIN_181_CMPCLK__FUNC_EINT182 (MTK_PIN_NO(181) | 2)
+#define MT8135_PIN_181_CMPCLK__FUNC_CMCSK (MTK_PIN_NO(181) | 3)
+#define MT8135_PIN_181_CMPCLK__FUNC_CM2MCLK_4X (MTK_PIN_NO(181) | 4)
+#define MT8135_PIN_181_CMPCLK__FUNC_TS_AUXADC_SEL_3 (MTK_PIN_NO(181) | 5)
+#define MT8135_PIN_181_CMPCLK__FUNC_VENC_TEST_CK (MTK_PIN_NO(181) | 6)
+#define MT8135_PIN_181_CMPCLK__FUNC_TESTA_OUT27 (MTK_PIN_NO(181) | 7)
+
+#define MT8135_PIN_182_CMMCLK__FUNC_GPIO182 (MTK_PIN_NO(182) | 0)
+#define MT8135_PIN_182_CMMCLK__FUNC_CMMCLK (MTK_PIN_NO(182) | 1)
+#define MT8135_PIN_182_CMMCLK__FUNC_EINT183 (MTK_PIN_NO(182) | 2)
+#define MT8135_PIN_182_CMMCLK__FUNC_TS_AUXADC_SEL_2 (MTK_PIN_NO(182) | 5)
+#define MT8135_PIN_182_CMMCLK__FUNC_TESTA_OUT28 (MTK_PIN_NO(182) | 7)
+
+#define MT8135_PIN_183_CMRST__FUNC_GPIO183 (MTK_PIN_NO(183) | 0)
+#define MT8135_PIN_183_CMRST__FUNC_CMRST (MTK_PIN_NO(183) | 1)
+#define MT8135_PIN_183_CMRST__FUNC_EINT185 (MTK_PIN_NO(183) | 2)
+#define MT8135_PIN_183_CMRST__FUNC_TS_AUXADC_SEL_1 (MTK_PIN_NO(183) | 5)
+#define MT8135_PIN_183_CMRST__FUNC_TESTA_OUT30 (MTK_PIN_NO(183) | 7)
+
+#define MT8135_PIN_184_CMPDN__FUNC_GPIO184 (MTK_PIN_NO(184) | 0)
+#define MT8135_PIN_184_CMPDN__FUNC_CMPDN (MTK_PIN_NO(184) | 1)
+#define MT8135_PIN_184_CMPDN__FUNC_EINT184 (MTK_PIN_NO(184) | 2)
+#define MT8135_PIN_184_CMPDN__FUNC_TS_AUXADC_SEL_0 (MTK_PIN_NO(184) | 5)
+#define MT8135_PIN_184_CMPDN__FUNC_TESTA_OUT29 (MTK_PIN_NO(184) | 7)
+
+#define MT8135_PIN_185_CMFLASH__FUNC_GPIO185 (MTK_PIN_NO(185) | 0)
+#define MT8135_PIN_185_CMFLASH__FUNC_CMFLASH (MTK_PIN_NO(185) | 1)
+#define MT8135_PIN_185_CMFLASH__FUNC_EINT186 (MTK_PIN_NO(185) | 2)
+#define MT8135_PIN_185_CMFLASH__FUNC_CM2MCLK_3X (MTK_PIN_NO(185) | 3)
+#define MT8135_PIN_185_CMFLASH__FUNC_MFG_TEST_CK_1 (MTK_PIN_NO(185) | 6)
+#define MT8135_PIN_185_CMFLASH__FUNC_TESTA_OUT31 (MTK_PIN_NO(185) | 7)
+
+#define MT8135_PIN_186_MRG_I2S_PCM_CLK__FUNC_GPIO186 (MTK_PIN_NO(186) | 0)
+#define MT8135_PIN_186_MRG_I2S_PCM_CLK__FUNC_MRG_I2S_P_CLK (MTK_PIN_NO(186) | 1)
+#define MT8135_PIN_186_MRG_I2S_PCM_CLK__FUNC_EINT14 (MTK_PIN_NO(186) | 2)
+#define MT8135_PIN_186_MRG_I2S_PCM_CLK__FUNC_I2SIN_CK (MTK_PIN_NO(186) | 3)
+#define MT8135_PIN_186_MRG_I2S_PCM_CLK__FUNC_PCM0_CK (MTK_PIN_NO(186) | 4)
+#define MT8135_PIN_186_MRG_I2S_PCM_CLK__FUNC_DSP2_ICK (MTK_PIN_NO(186) | 5)
+#define MT8135_PIN_186_MRG_I2S_PCM_CLK__FUNC_IMG_TEST_CK (MTK_PIN_NO(186) | 6)
+#define MT8135_PIN_186_MRG_I2S_PCM_CLK__FUNC_USB_SCL (MTK_PIN_NO(186) | 7)
+
+#define MT8135_PIN_187_MRG_I2S_PCM_SYNC__FUNC_GPIO187 (MTK_PIN_NO(187) | 0)
+#define MT8135_PIN_187_MRG_I2S_PCM_SYNC__FUNC_MRG_I2S_SYNC (MTK_PIN_NO(187) | 1)
+#define MT8135_PIN_187_MRG_I2S_PCM_SYNC__FUNC_EINT16 (MTK_PIN_NO(187) | 2)
+#define MT8135_PIN_187_MRG_I2S_PCM_SYNC__FUNC_I2SIN_WS (MTK_PIN_NO(187) | 3)
+#define MT8135_PIN_187_MRG_I2S_PCM_SYNC__FUNC_PCM0_WS (MTK_PIN_NO(187) | 4)
+#define MT8135_PIN_187_MRG_I2S_PCM_SYNC__FUNC_DISP_TEST_CK (MTK_PIN_NO(187) | 6)
+
+#define MT8135_PIN_188_MRG_I2S_PCM_RX__FUNC_GPIO188 (MTK_PIN_NO(188) | 0)
+#define MT8135_PIN_188_MRG_I2S_PCM_RX__FUNC_MRG_I2S_PCM_RX (MTK_PIN_NO(188) | 1)
+#define MT8135_PIN_188_MRG_I2S_PCM_RX__FUNC_EINT15 (MTK_PIN_NO(188) | 2)
+#define MT8135_PIN_188_MRG_I2S_PCM_RX__FUNC_I2SIN_DAT (MTK_PIN_NO(188) | 3)
+#define MT8135_PIN_188_MRG_I2S_PCM_RX__FUNC_PCM0_DI (MTK_PIN_NO(188) | 4)
+#define MT8135_PIN_188_MRG_I2S_PCM_RX__FUNC_DSP2_ID (MTK_PIN_NO(188) | 5)
+#define MT8135_PIN_188_MRG_I2S_PCM_RX__FUNC_MFG_TEST_CK (MTK_PIN_NO(188) | 6)
+#define MT8135_PIN_188_MRG_I2S_PCM_RX__FUNC_USB_SDA (MTK_PIN_NO(188) | 7)
+
+#define MT8135_PIN_189_MRG_I2S_PCM_TX__FUNC_GPIO189 (MTK_PIN_NO(189) | 0)
+#define MT8135_PIN_189_MRG_I2S_PCM_TX__FUNC_MRG_I2S_PCM_TX (MTK_PIN_NO(189) | 1)
+#define MT8135_PIN_189_MRG_I2S_PCM_TX__FUNC_EINT17 (MTK_PIN_NO(189) | 2)
+#define MT8135_PIN_189_MRG_I2S_PCM_TX__FUNC_I2SOUT_DAT (MTK_PIN_NO(189) | 3)
+#define MT8135_PIN_189_MRG_I2S_PCM_TX__FUNC_PCM0_DO (MTK_PIN_NO(189) | 4)
+#define MT8135_PIN_189_MRG_I2S_PCM_TX__FUNC_VDEC_TEST_CK (MTK_PIN_NO(189) | 6)
+
+#define MT8135_PIN_190_SRCLKENAI__FUNC_GPIO190 (MTK_PIN_NO(190) | 0)
+#define MT8135_PIN_190_SRCLKENAI__FUNC_SRCLKENAI (MTK_PIN_NO(190) | 1)
+
+#define MT8135_PIN_191_URXD3__FUNC_GPIO191 (MTK_PIN_NO(191) | 0)
+#define MT8135_PIN_191_URXD3__FUNC_URXD3 (MTK_PIN_NO(191) | 1)
+#define MT8135_PIN_191_URXD3__FUNC_EINT87 (MTK_PIN_NO(191) | 2)
+#define MT8135_PIN_191_URXD3__FUNC_UTXD3 (MTK_PIN_NO(191) | 3)
+#define MT8135_PIN_191_URXD3__FUNC_TS_AUX_ST (MTK_PIN_NO(191) | 5)
+#define MT8135_PIN_191_URXD3__FUNC_PWM4 (MTK_PIN_NO(191) | 6)
+
+#define MT8135_PIN_192_UTXD3__FUNC_GPIO192 (MTK_PIN_NO(192) | 0)
+#define MT8135_PIN_192_UTXD3__FUNC_UTXD3 (MTK_PIN_NO(192) | 1)
+#define MT8135_PIN_192_UTXD3__FUNC_EINT86 (MTK_PIN_NO(192) | 2)
+#define MT8135_PIN_192_UTXD3__FUNC_URXD3 (MTK_PIN_NO(192) | 3)
+#define MT8135_PIN_192_UTXD3__FUNC_TS_AUX_CS_B (MTK_PIN_NO(192) | 5)
+#define MT8135_PIN_192_UTXD3__FUNC_PWM3 (MTK_PIN_NO(192) | 6)
+
+#define MT8135_PIN_193_SDA2__FUNC_GPIO193 (MTK_PIN_NO(193) | 0)
+#define MT8135_PIN_193_SDA2__FUNC_SDA2 (MTK_PIN_NO(193) | 1)
+#define MT8135_PIN_193_SDA2__FUNC_EINT95 (MTK_PIN_NO(193) | 2)
+#define MT8135_PIN_193_SDA2__FUNC_CLKM5 (MTK_PIN_NO(193) | 3)
+#define MT8135_PIN_193_SDA2__FUNC_PWM5 (MTK_PIN_NO(193) | 4)
+#define MT8135_PIN_193_SDA2__FUNC_TS_AUX_PWDB (MTK_PIN_NO(193) | 5)
+
+#define MT8135_PIN_194_SCL2__FUNC_GPIO194 (MTK_PIN_NO(194) | 0)
+#define MT8135_PIN_194_SCL2__FUNC_SCL2 (MTK_PIN_NO(194) | 1)
+#define MT8135_PIN_194_SCL2__FUNC_EINT94 (MTK_PIN_NO(194) | 2)
+#define MT8135_PIN_194_SCL2__FUNC_CLKM4 (MTK_PIN_NO(194) | 3)
+#define MT8135_PIN_194_SCL2__FUNC_PWM4 (MTK_PIN_NO(194) | 4)
+#define MT8135_PIN_194_SCL2__FUNC_TS_AUXADC_TEST_CK (MTK_PIN_NO(194) | 5)
+
+#define MT8135_PIN_195_SDA1__FUNC_GPIO195 (MTK_PIN_NO(195) | 0)
+#define MT8135_PIN_195_SDA1__FUNC_SDA1 (MTK_PIN_NO(195) | 1)
+#define MT8135_PIN_195_SDA1__FUNC_EINT93 (MTK_PIN_NO(195) | 2)
+#define MT8135_PIN_195_SDA1__FUNC_CLKM3 (MTK_PIN_NO(195) | 3)
+#define MT8135_PIN_195_SDA1__FUNC_PWM3 (MTK_PIN_NO(195) | 4)
+#define MT8135_PIN_195_SDA1__FUNC_TS_AUX_SCLK_PWDB (MTK_PIN_NO(195) | 5)
+
+#define MT8135_PIN_196_SCL1__FUNC_GPIO196 (MTK_PIN_NO(196) | 0)
+#define MT8135_PIN_196_SCL1__FUNC_SCL1 (MTK_PIN_NO(196) | 1)
+#define MT8135_PIN_196_SCL1__FUNC_EINT92 (MTK_PIN_NO(196) | 2)
+#define MT8135_PIN_196_SCL1__FUNC_CLKM2 (MTK_PIN_NO(196) | 3)
+#define MT8135_PIN_196_SCL1__FUNC_PWM2 (MTK_PIN_NO(196) | 4)
+#define MT8135_PIN_196_SCL1__FUNC_TS_AUX_DIN (MTK_PIN_NO(196) | 5)
+
+#define MT8135_PIN_197_MSDC3_DAT2__FUNC_GPIO197 (MTK_PIN_NO(197) | 0)
+#define MT8135_PIN_197_MSDC3_DAT2__FUNC_MSDC3_DAT2 (MTK_PIN_NO(197) | 1)
+#define MT8135_PIN_197_MSDC3_DAT2__FUNC_EINT71 (MTK_PIN_NO(197) | 2)
+#define MT8135_PIN_197_MSDC3_DAT2__FUNC_SCL6 (MTK_PIN_NO(197) | 3)
+#define MT8135_PIN_197_MSDC3_DAT2__FUNC_PWM5 (MTK_PIN_NO(197) | 4)
+#define MT8135_PIN_197_MSDC3_DAT2__FUNC_CLKM4 (MTK_PIN_NO(197) | 5)
+#define MT8135_PIN_197_MSDC3_DAT2__FUNC_MFG_TEST_CK_2 (MTK_PIN_NO(197) | 6)
+
+#define MT8135_PIN_198_MSDC3_DAT3__FUNC_GPIO198 (MTK_PIN_NO(198) | 0)
+#define MT8135_PIN_198_MSDC3_DAT3__FUNC_MSDC3_DAT3 (MTK_PIN_NO(198) | 1)
+#define MT8135_PIN_198_MSDC3_DAT3__FUNC_EINT72 (MTK_PIN_NO(198) | 2)
+#define MT8135_PIN_198_MSDC3_DAT3__FUNC_SDA6 (MTK_PIN_NO(198) | 3)
+#define MT8135_PIN_198_MSDC3_DAT3__FUNC_PWM6 (MTK_PIN_NO(198) | 4)
+#define MT8135_PIN_198_MSDC3_DAT3__FUNC_CLKM5 (MTK_PIN_NO(198) | 5)
+#define MT8135_PIN_198_MSDC3_DAT3__FUNC_MFG_TEST_CK_3 (MTK_PIN_NO(198) | 6)
+
+#define MT8135_PIN_199_MSDC3_CMD__FUNC_GPIO199 (MTK_PIN_NO(199) | 0)
+#define MT8135_PIN_199_MSDC3_CMD__FUNC_MSDC3_CMD (MTK_PIN_NO(199) | 1)
+#define MT8135_PIN_199_MSDC3_CMD__FUNC_EINT68 (MTK_PIN_NO(199) | 2)
+#define MT8135_PIN_199_MSDC3_CMD__FUNC_SDA2 (MTK_PIN_NO(199) | 3)
+#define MT8135_PIN_199_MSDC3_CMD__FUNC_PWM2 (MTK_PIN_NO(199) | 4)
+#define MT8135_PIN_199_MSDC3_CMD__FUNC_CLKM1 (MTK_PIN_NO(199) | 5)
+#define MT8135_PIN_199_MSDC3_CMD__FUNC_MFG_TEST_CK_4 (MTK_PIN_NO(199) | 6)
+
+#define MT8135_PIN_200_MSDC3_CLK__FUNC_GPIO200 (MTK_PIN_NO(200) | 0)
+#define MT8135_PIN_200_MSDC3_CLK__FUNC_MSDC3_CLK (MTK_PIN_NO(200) | 1)
+#define MT8135_PIN_200_MSDC3_CLK__FUNC_EINT67 (MTK_PIN_NO(200) | 2)
+#define MT8135_PIN_200_MSDC3_CLK__FUNC_SCL2 (MTK_PIN_NO(200) | 3)
+#define MT8135_PIN_200_MSDC3_CLK__FUNC_PWM1 (MTK_PIN_NO(200) | 4)
+#define MT8135_PIN_200_MSDC3_CLK__FUNC_CLKM0 (MTK_PIN_NO(200) | 5)
+
+#define MT8135_PIN_201_MSDC3_DAT1__FUNC_GPIO201 (MTK_PIN_NO(201) | 0)
+#define MT8135_PIN_201_MSDC3_DAT1__FUNC_MSDC3_DAT1 (MTK_PIN_NO(201) | 1)
+#define MT8135_PIN_201_MSDC3_DAT1__FUNC_EINT70 (MTK_PIN_NO(201) | 2)
+#define MT8135_PIN_201_MSDC3_DAT1__FUNC_SDA3 (MTK_PIN_NO(201) | 3)
+#define MT8135_PIN_201_MSDC3_DAT1__FUNC_PWM4 (MTK_PIN_NO(201) | 4)
+#define MT8135_PIN_201_MSDC3_DAT1__FUNC_CLKM3 (MTK_PIN_NO(201) | 5)
+
+#define MT8135_PIN_202_MSDC3_DAT0__FUNC_GPIO202 (MTK_PIN_NO(202) | 0)
+#define MT8135_PIN_202_MSDC3_DAT0__FUNC_MSDC3_DAT0 (MTK_PIN_NO(202) | 1)
+#define MT8135_PIN_202_MSDC3_DAT0__FUNC_EINT69 (MTK_PIN_NO(202) | 2)
+#define MT8135_PIN_202_MSDC3_DAT0__FUNC_SCL3 (MTK_PIN_NO(202) | 3)
+#define MT8135_PIN_202_MSDC3_DAT0__FUNC_PWM3 (MTK_PIN_NO(202) | 4)
+#define MT8135_PIN_202_MSDC3_DAT0__FUNC_CLKM2 (MTK_PIN_NO(202) | 5)
+
+#endif /* __DTS_MT8135_PINFUNC_H */
diff --git a/arch/arm/boot/dts/mt8135.dtsi b/arch/arm/boot/dts/mt8135.dtsi
index a161e99ffcc4..0aba9eb28e2b 100644
--- a/arch/arm/boot/dts/mt8135.dtsi
+++ b/arch/arm/boot/dts/mt8135.dtsi
@@ -15,6 +15,7 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include "skeleton64.dtsi"
+#include "mt8135-pinfunc.h"
/ {
compatible = "mediatek,mt8135";
@@ -101,6 +102,29 @@
compatible = "simple-bus";
ranges;
+ /*
+ * Pinctrl access register at 0x10005000 and 0x1020c000 through
+ * regmap. Register 0x1000b000 is used by EINT.
+ */
+ pio: pinctrl@10005000 {
+ compatible = "mediatek,mt8135-pinctrl";
+ reg = <0 0x1000b000 0 0x1000>;
+ mediatek,pctl-regmap = <&syscfg_pctl_a &syscfg_pctl_b>;
+ pins-are-numbered;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ syscfg_pctl_a: syscfg_pctl_a@10005000 {
+ compatible = "mediatek,mt8135-pctl-a-syscfg", "syscon";
+ reg = <0 0x10005000 0 0x1000>;
+ };
+
timer: timer@10008000 {
compatible = "mediatek,mt8135-timer",
"mediatek,mt6577-timer";
@@ -119,6 +143,11 @@
reg = <0 0x10200030 0 0x1c>;
};
+ syscfg_pctl_b: syscfg_pctl_b@1020c000 {
+ compatible = "mediatek,mt8135-pctl-b-syscfg", "syscon";
+ reg = <0 0x1020c000 0 0x1000>;
+ };
+
gic: interrupt-controller@10211000 {
compatible = "arm,cortex-a15-gic";
interrupt-controller;
diff --git a/arch/arm/boot/dts/omap3-cm-t3517.dts b/arch/arm/boot/dts/omap3-cm-t3517.dts
index f5b5a1d96cd7..53ae04f9104d 100644
--- a/arch/arm/boot/dts/omap3-cm-t3517.dts
+++ b/arch/arm/boot/dts/omap3-cm-t3517.dts
@@ -66,7 +66,7 @@
otg_drv_vbus: pinmux_otg_drv_vbus {
pinctrl-single,pins = <
- OMAP3_CORE1_IOPAD(0x2210, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii_50Mhz_clk.usb0_drvvbus */
+ OMAP3_CORE1_IOPAD(0x2210, PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii_50MHz_clk.usb0_drvvbus */
>;
};
diff --git a/arch/arm/boot/dts/omap3-devkit8000.dts b/arch/arm/boot/dts/omap3-devkit8000.dts
index 921de6605f07..be2297116a14 100644
--- a/arch/arm/boot/dts/omap3-devkit8000.dts
+++ b/arch/arm/boot/dts/omap3-devkit8000.dts
@@ -157,3 +157,44 @@
};
};
};
+
+&gpmc {
+ ranges = <6 0 0x2c000000 0x1000000>; /* CS6: 16MB for DM9000 */
+
+ ethernet@0,0 {
+ compatible = "davicom,dm9000";
+ reg = <6 0x000 2
+ 6 0x400 2>; /* CS6, offset 0 and 0x400, IO size 2 */
+ bank-width = <2>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
+ davicom,no-eeprom;
+
+ gpmc,mux-add-data = <0>;
+ gpmc,device-width = <1>;
+ gpmc,wait-pin = <0>;
+ gpmc,cycle2cycle-samecsen = <1>;
+ gpmc,cycle2cycle-diffcsen = <1>;
+
+ gpmc,cs-on-ns = <6>;
+ gpmc,cs-rd-off-ns = <180>;
+ gpmc,cs-wr-off-ns = <180>;
+ gpmc,adv-on-ns = <0>;
+ gpmc,adv-rd-off-ns = <18>;
+ gpmc,adv-wr-off-ns = <48>;
+ gpmc,oe-on-ns = <54>;
+ gpmc,oe-off-ns = <168>;
+ gpmc,we-on-ns = <54>;
+ gpmc,we-off-ns = <168>;
+ gpmc,rd-cycle-ns = <186>;
+ gpmc,wr-cycle-ns = <186>;
+ gpmc,access-ns = <144>;
+ gpmc,page-burst-access-ns = <24>;
+ gpmc,bus-turnaround-ns = <90>;
+ gpmc,cycle2cycle-delay-ns = <90>;
+ gpmc,wait-monitoring-ns = <0>;
+ gpmc,clk-activation-ns = <0>;
+ gpmc,wr-data-mux-bus-ns = <0>;
+ gpmc,wr-access-ns = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/omap3-evm-common.dtsi b/arch/arm/boot/dts/omap3-evm-common.dtsi
index 346552b94d9f..b2589f96d5f7 100644
--- a/arch/arm/boot/dts/omap3-evm-common.dtsi
+++ b/arch/arm/boot/dts/omap3-evm-common.dtsi
@@ -96,6 +96,7 @@
};
&mmc1 {
+ interrupts-extended = <&intc 83 &omap3_pmx_core 0x11a>;
vmmc-supply = <&vmmc1>;
vmmc_aux-supply = <&vsim>;
bus-width = <8>;
diff --git a/arch/arm/boot/dts/omap3-gta04.dtsi b/arch/arm/boot/dts/omap3-gta04.dtsi
index b9f68817bd6e..7166d8876ea8 100644
--- a/arch/arm/boot/dts/omap3-gta04.dtsi
+++ b/arch/arm/boot/dts/omap3-gta04.dtsi
@@ -48,6 +48,28 @@
ti,mcbsp = <&mcbsp2>;
};
+ /* GSM audio */
+ sound_telephony {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "GTA04 voice";
+ simple-audio-card,bitclock-master = <&telephony_link_master>;
+ simple-audio-card,frame-master = <&telephony_link_master>;
+ simple-audio-card,format = "i2s";
+
+ simple-audio-card,cpu {
+ sound-dai = <&mcbsp4>;
+ };
+
+ telephony_link_master: simple-audio-card,codec {
+ sound-dai = <&gtm601_codec>;
+ };
+ };
+
+ gtm601_codec: gsm_codec {
+ compatible = "option,gtm601";
+ #sound-dai-cells = <0>;
+ };
+
spi_lcd {
compatible = "spi-gpio";
#address-cells = <0x1>;
@@ -200,6 +222,12 @@
OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */
>;
};
+
+ hdq_pins: hdq_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x21c6, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_sda.hdq */
+ >;
+ };
};
&omap3_pmx_core2 {
@@ -517,3 +545,12 @@
&mcbsp2 {
status = "okay";
};
+
+&hdqw1w {
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdq_pins>;
+};
+
+&mcbsp4 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/omap3-ldp.dts b/arch/arm/boot/dts/omap3-ldp.dts
index b699bc48f242..bd6e6769c7ce 100644
--- a/arch/arm/boot/dts/omap3-ldp.dts
+++ b/arch/arm/boot/dts/omap3-ldp.dts
@@ -34,63 +34,63 @@
key_enter {
label = "enter";
gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* gpio101 */
- linux,code = <0x0107001c>; /* KEY_ENTER */
+ linux,code = <KEY_ENTER>;
gpio-key,wakeup;
};
key_f1 {
label = "f1";
gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* gpio102 */
- linux,code = <0x0303003b>; /* KEY_F1 */
+ linux,code = <KEY_F1>;
gpio-key,wakeup;
};
key_f2 {
label = "f2";
gpios = <&gpio4 7 GPIO_ACTIVE_LOW>; /* gpio103 */
- linux,code = <0x0403003c>; /* KEY_F2 */
+ linux,code = <KEY_F2>;
gpio-key,wakeup;
};
key_f3 {
label = "f3";
gpios = <&gpio4 8 GPIO_ACTIVE_LOW>; /* gpio104 */
- linux,code = <0x0503003d>; /* KEY_F3 */
+ linux,code = <KEY_F3>;
gpio-key,wakeup;
};
key_f4 {
label = "f4";
gpios = <&gpio4 9 GPIO_ACTIVE_LOW>; /* gpio105 */
- linux,code = <0x0704003e>; /* KEY_F4 */
+ linux,code = <KEY_F4>;
gpio-key,wakeup;
};
key_left {
label = "left";
gpios = <&gpio4 10 GPIO_ACTIVE_LOW>; /* gpio106 */
- linux,code = <0x04070069>; /* KEY_LEFT */
+ linux,code = <KEY_LEFT>;
gpio-key,wakeup;
};
key_right {
label = "right";
gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; /* gpio107 */
- linux,code = <0x0507006a>; /* KEY_RIGHT */
+ linux,code = <KEY_RIGHT>;
gpio-key,wakeup;
};
key_up {
label = "up";
gpios = <&gpio4 12 GPIO_ACTIVE_LOW>; /* gpio108 */
- linux,code = <0x06070067>; /* KEY_UP */
+ linux,code = <KEY_UP>;
gpio-key,wakeup;
};
key_down {
label = "down";
gpios = <&gpio4 13 GPIO_ACTIVE_LOW>; /* gpio109 */
- linux,code = <0x0707006c>; /* KEY_DOWN */
+ linux,code = <KEY_DOWN>;
gpio-key,wakeup;
};
};
diff --git a/arch/arm/boot/dts/omap5-uevm.dts b/arch/arm/boot/dts/omap5-uevm.dts
index 74777a6e200a..275618f19a43 100644
--- a/arch/arm/boot/dts/omap5-uevm.dts
+++ b/arch/arm/boot/dts/omap5-uevm.dts
@@ -597,18 +597,20 @@
};
&uart1 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart1_pins>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
};
&uart3 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_pins>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
+ interrupts-extended = <&wakeupgen GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
+ <&omap5_pmx_core 0x19c>;
};
&uart5 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart5_pins>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart5_pins>;
};
&cpu0 {
diff --git a/arch/arm/boot/dts/pxa27x.dtsi b/arch/arm/boot/dts/pxa27x.dtsi
index 80fc5d7e9ef9..90b99714ad80 100644
--- a/arch/arm/boot/dts/pxa27x.dtsi
+++ b/arch/arm/boot/dts/pxa27x.dtsi
@@ -1,6 +1,6 @@
/* The pxa3xx skeleton simply augments the 2xx version */
#include "pxa2xx.dtsi"
-#include "dt-bindings/clock/pxa2xx-clock.h"
+#include "dt-bindings/clock/pxa-clock.h"
/ {
model = "Marvell PXA27x familiy SoC";
@@ -12,28 +12,61 @@
marvell,intc-nr-irqs = <34>;
};
+ gpio: gpio@40e00000 {
+ compatible = "intel,pxa27x-gpio";
+ clocks = <&clks CLK_NONE>;
+ };
+
pwm0: pwm@40b00000 {
compatible = "marvell,pxa270-pwm", "marvell,pxa250-pwm";
reg = <0x40b00000 0x10>;
#pwm-cells = <1>;
+ clocks = <&clks CLK_PWM0>;
};
pwm1: pwm@40b00010 {
compatible = "marvell,pxa270-pwm", "marvell,pxa250-pwm";
reg = <0x40b00010 0x10>;
#pwm-cells = <1>;
+ clocks = <&clks CLK_PWM1>;
};
pwm2: pwm@40c00000 {
compatible = "marvell,pxa270-pwm", "marvell,pxa250-pwm";
reg = <0x40c00000 0x10>;
#pwm-cells = <1>;
+ clocks = <&clks CLK_PWM0>;
};
pwm3: pwm@40c00010 {
compatible = "marvell,pxa270-pwm", "marvell,pxa250-pwm";
reg = <0x40c00010 0x10>;
#pwm-cells = <1>;
+ clocks = <&clks CLK_PWM1>;
+ };
+
+ pwri2c: i2c@40f000180 {
+ compatible = "mrvl,pxa-i2c";
+ reg = <0x40f00180 0x24>;
+ interrupts = <6>;
+ clocks = <&clks CLK_PWRI2C>;
+ status = "disabled";
+ };
+
+ pxa27x_udc: udc@40600000 {
+ compatible = "marvell,pxa270-udc";
+ reg = <0x40600000 0x10000>;
+ interrupts = <11>;
+ clocks = <&clks CLK_USB>;
+ status = "disabled";
+ };
+
+ keypad: keypad@41500000 {
+ compatible = "marvell,pxa27x-keypad";
+ reg = <0x41500000 0x4c>;
+ interrupts = <4>;
+ clocks = <&clks CLK_KEYPAD>;
+ status = "disabled";
};
};
@@ -46,11 +79,18 @@
#size-cells = <1>;
ranges;
- pxa2xx_clks: pxa2xx_clks@41300004 {
- compatible = "marvell,pxa-clocks";
+ clks: pxa2xx_clks@41300004 {
+ compatible = "marvell,pxa270-clocks";
#clock-cells = <1>;
status = "okay";
};
};
+ timer@40a00000 {
+ compatible = "marvell,pxa-timer";
+ reg = <0x40a00000 0x20>;
+ interrupts = <26>;
+ clocks = <&clks CLK_OSTIMER>;
+ status = "okay";
+ };
};
diff --git a/arch/arm/boot/dts/pxa2xx.dtsi b/arch/arm/boot/dts/pxa2xx.dtsi
index c08f84629aa9..71a0cd7388d1 100644
--- a/arch/arm/boot/dts/pxa2xx.dtsi
+++ b/arch/arm/boot/dts/pxa2xx.dtsi
@@ -6,7 +6,8 @@
* Licensed under GPLv2 or later.
*/
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
+#include "dt-bindings/clock/pxa-clock.h"
/ {
model = "Marvell PXA2xx family SoC";
@@ -79,6 +80,7 @@
compatible = "mrvl,pxa-uart";
reg = <0x40100000 0x30>;
interrupts = <22>;
+ clocks = <&clks CLK_FFUART>;
status = "disabled";
};
@@ -86,6 +88,7 @@
compatible = "mrvl,pxa-uart";
reg = <0x40200000 0x30>;
interrupts = <21>;
+ clocks = <&clks CLK_BTUART>;
status = "disabled";
};
@@ -93,6 +96,7 @@
compatible = "mrvl,pxa-uart";
reg = <0x40700000 0x30>;
interrupts = <20>;
+ clocks = <&clks CLK_STUART>;
status = "disabled";
};
@@ -107,6 +111,7 @@
compatible = "mrvl,pxa-i2c";
reg = <0x40301680 0x30>;
interrupts = <18>;
+ clocks = <&clks CLK_I2C>;
#address-cells = <0x1>;
#size-cells = <0>;
status = "disabled";
diff --git a/arch/arm/boot/dts/pxa3xx.dtsi b/arch/arm/boot/dts/pxa3xx.dtsi
index 83bb0eff697b..7ad0b1771098 100644
--- a/arch/arm/boot/dts/pxa3xx.dtsi
+++ b/arch/arm/boot/dts/pxa3xx.dtsi
@@ -1,5 +1,5 @@
/* The pxa3xx skeleton simply augments the 2xx version */
-/include/ "pxa2xx.dtsi"
+#include "pxa2xx.dtsi"
/ {
model = "Marvell PXA3xx familiy SoC";
@@ -10,6 +10,7 @@
compatible = "mrvl,pwri2c";
reg = <0x40f500c0 0x30>;
interrupts = <6>;
+ clocks = <&clks CLK_PWRI2C>;
#address-cells = <0x1>;
#size-cells = <0>;
status = "disabled";
@@ -19,6 +20,7 @@
compatible = "marvell,pxa3xx-nand";
reg = <0x43100000 90>;
interrupts = <45>;
+ clocks = <&clks CLK_NAND>;
#address-cells = <1>;
#size-cells = <1>;
status = "disabled";
@@ -32,6 +34,7 @@
gpio: gpio@40e00000 {
compatible = "intel,pxa3xx-gpio";
reg = <0x40e00000 0x10000>;
+ clocks = <&clks CLK_GPIO>;
interrupt-names = "gpio0", "gpio1", "gpio_mux";
interrupts = <8 9 10>;
gpio-controller;
@@ -40,4 +43,28 @@
#interrupt-cells = <0x2>;
};
};
+
+ clocks {
+ /*
+ * The muxing of external clocks/internal dividers for osc* clock
+ * sources has been hidden under the carpet by now.
+ */
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ clks: pxa3xx_clks@41300004 {
+ compatible = "marvell,pxa300-clocks";
+ #clock-cells = <1>;
+ status = "okay";
+ };
+ };
+
+ timer@40a00000 {
+ compatible = "marvell,pxa-timer";
+ reg = <0x40a00000 0x20>;
+ interrupts = <26>;
+ clocks = <&clks CLK_OSTIMER>;
+ status = "okay";
+ };
};
diff --git a/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts b/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
index 5d75666f7f6c..71512b3ca444 100644
--- a/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
@@ -14,6 +14,67 @@
};
};
+ rpm@108000 {
+ regulators {
+ vin_lvs1_3_6-supply = <&pm8921_s4>;
+ vin_lvs2-supply = <&pm8921_s1>;
+ vin_lvs4_5_7-supply = <&pm8921_s4>;
+
+ vdd_l1_l2_l12_l18-supply = <&pm8921_s4>;
+ vdd_l24-supply = <&pm8921_s1>;
+ vdd_l25-supply = <&pm8921_s1>;
+ vdd_l26-supply = <&pm8921_s7>;
+ vdd_l27-supply = <&pm8921_s7>;
+ vdd_l28-supply = <&pm8921_s7>;
+
+
+ /* Buck SMPS */
+ pm8921_s1: s1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,switch-mode-frequency = <3200000>;
+ bias-pull-down;
+ };
+
+ pm8921_s3: s3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ qcom,switch-mode-frequency = <4800000>;
+ };
+
+ pm8921_s4: s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <3200000>;
+ };
+
+ pm8921_s7: s7 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <3200000>;
+ };
+
+ pm8921_l3: l3 {
+ regulator-min-microvolt = <3050000>;
+ regulator-max-microvolt = <3300000>;
+ bias-pull-down;
+ };
+
+ pm8921_l4: l4 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+
+ pm8921_l23: l23 {
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ bias-pull-down;
+ };
+ };
+ };
+
gsbi@12440000 {
status = "okay";
qcom,mode = <GSBI_PROT_I2C>;
@@ -40,6 +101,45 @@
};
};
+ /* OTG */
+ usb1_phy: phy@12500000 {
+ status = "okay";
+ vddcx-supply = <&pm8921_s3>;
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l4>;
+ };
+
+ usb3_phy: phy@12520000 {
+ status = "okay";
+ vddcx-supply = <&pm8921_s3>;
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l23>;
+ };
+
+ usb4_phy: phy@12530000 {
+ status = "okay";
+ vddcx-supply = <&pm8921_s3>;
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l23>;
+ };
+
+ gadget1: gadget@12500000 {
+ status = "ok";
+ };
+
+ /* OTG */
+ usb1: usb@12500000 {
+ status = "ok";
+ };
+
+ usb3: usb@12520000 {
+ status = "okay";
+ };
+
+ usb4: usb@12530000 {
+ status = "okay";
+ };
+
amba {
/* eMMC */
sdcc1: sdcc@12400000 {
diff --git a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
index e641001ca2a7..a7c939ba8873 100644
--- a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
@@ -5,15 +5,12 @@
model = "Qualcomm APQ8064/IFC6410";
compatible = "qcom,apq8064-ifc6410", "qcom,apq8064";
+ aliases {
+ serial0 = &gsbi7_serial;
+ };
+
soc {
pinctrl@800000 {
- i2c1_pins: i2c1 {
- mux {
- pins = "gpio20", "gpio21";
- function = "gsbi1";
- };
- };
-
card_detect: card_detect {
mux {
pins = "gpio26";
@@ -23,6 +20,83 @@
};
};
+ rpm@108000 {
+ regulators {
+ vin_lvs1_3_6-supply = <&pm8921_s4>;
+ vin_lvs2-supply = <&pm8921_s1>;
+ vin_lvs4_5_7-supply = <&pm8921_s4>;
+
+ vdd_l1_l2_l12_l18-supply = <&pm8921_s4>;
+ vdd_l24-supply = <&pm8921_s1>;
+ vdd_l25-supply = <&pm8921_s1>;
+ vdd_l26-supply = <&pm8921_s7>;
+ vdd_l27-supply = <&pm8921_s7>;
+ vdd_l28-supply = <&pm8921_s7>;
+
+
+ /* Buck SMPS */
+ pm8921_s1: s1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,switch-mode-frequency = <3200000>;
+ bias-pull-down;
+ };
+
+ pm8921_s3: s3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ qcom,switch-mode-frequency = <4800000>;
+ };
+
+ pm8921_s4: s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <3200000>;
+ };
+
+ pm8921_s7: s7 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <3200000>;
+ };
+
+ pm8921_l3: l3 {
+ regulator-min-microvolt = <3050000>;
+ regulator-max-microvolt = <3300000>;
+ bias-pull-down;
+ };
+
+ pm8921_l4: l4 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+
+ pm8921_l6: l6 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ bias-pull-down;
+ };
+
+ pm8921_l23: l23 {
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ bias-pull-down;
+ };
+ };
+ };
+
+ gsbi3: gsbi@16200000 {
+ status = "okay";
+ qcom,mode = <GSBI_PROT_I2C>;
+ i2c3: i2c@16280000 {
+ status = "okay";
+ pinctrl-0 = <&i2c3_pins>;
+ pinctrl-names = "default";
+ };
+ };
+
gsbi@12440000 {
status = "okay";
qcom,mode = <GSBI_PROT_I2C>;
@@ -49,6 +123,54 @@
};
};
+ sata_phy0: phy@1b400000 {
+ status = "okay";
+ };
+
+ sata0: sata@29000000 {
+ status = "okay";
+ target-supply = <&pm8921_s4>;
+ };
+
+ /* OTG */
+ usb1_phy: phy@12500000 {
+ status = "okay";
+ vddcx-supply = <&pm8921_s3>;
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l4>;
+ };
+
+ usb3_phy: phy@12520000 {
+ status = "okay";
+ vddcx-supply = <&pm8921_s3>;
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l23>;
+ };
+
+ usb4_phy: phy@12530000 {
+ status = "okay";
+ vddcx-supply = <&pm8921_s3>;
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l23>;
+ };
+
+ gadget1: gadget@12500000 {
+ status = "okay";
+ };
+
+ /* OTG */
+ usb1: usb@12500000 {
+ status = "okay";
+ };
+
+ usb3: usb@12520000 {
+ status = "okay";
+ };
+
+ usb4: usb@12530000 {
+ status = "okay";
+ };
+
amba {
/* eMMC */
sdcc1: sdcc@12400000 {
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
index 6c1511263a55..df2061ec630d 100644
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -2,6 +2,7 @@
#include "skeleton.dtsi"
#include <dt-bindings/clock/qcom,gcc-msm8960.h>
+#include <dt-bindings/reset/qcom,gcc-msm8960.h>
#include <dt-bindings/clock/qcom,mmcc-msm8960.h>
#include <dt-bindings/soc/qcom,gsbi.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -112,6 +113,20 @@
function = "ps_hold";
};
};
+
+ i2c1_pins: i2c1 {
+ mux {
+ pins = "gpio20", "gpio21";
+ function = "gsbi1";
+ };
+ };
+
+ i2c3_pins: i2c3 {
+ mux {
+ pins = "gpio8", "gpio9";
+ function = "gsbi3";
+ };
+ };
};
intc: interrupt-controller@2000000 {
@@ -225,6 +240,26 @@
};
};
+ gsbi3: gsbi@16200000 {
+ status = "disabled";
+ compatible = "qcom,gsbi-v1.0.0";
+ reg = <0x16200000 0x100>;
+ clocks = <&gcc GSBI3_H_CLK>;
+ clock-names = "iface";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ i2c3: i2c@16280000 {
+ compatible = "qcom,i2c-qup-v1.1.1";
+ reg = <0x16280000 0x1000>;
+ interrupts = <GIC_SPI 151 IRQ_TYPE_NONE>;
+ clocks = <&gcc GSBI3_QUP_CLK>,
+ <&gcc GSBI3_H_CLK>;
+ clock-names = "core", "iface";
+ };
+ };
+
gsbi7: gsbi@16600000 {
status = "disabled";
compatible = "qcom,gsbi-v1.0.0";
@@ -235,10 +270,9 @@
#address-cells = <1>;
#size-cells = <1>;
ranges;
-
syscon-tcsr = <&tcsr>;
- serial@16640000 {
+ gsbi7_serial: serial@16640000 {
compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
reg = <0x16640000 0x1000>,
<0x16600000 0x1000>;
@@ -276,6 +310,143 @@
#reset-cells = <1>;
};
+ l2cc: clock-controller@2011000 {
+ compatible = "syscon";
+ reg = <0x2011000 0x1000>;
+ };
+
+ rpm@108000 {
+ compatible = "qcom,rpm-apq8064";
+ reg = <0x108000 0x1000>;
+ qcom,ipc = <&l2cc 0x8 2>;
+
+ interrupts = <GIC_SPI 19 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "ack", "err", "wakeup";
+
+ regulators {
+ compatible = "qcom,rpm-pm8921-regulators";
+
+ pm8921_hdmi_switch: hdmi-switch {
+ bias-pull-down;
+ };
+ };
+ };
+
+ usb1_phy: phy@12500000 {
+ compatible = "qcom,usb-otg-ci";
+ reg = <0x12500000 0x400>;
+ interrupts = <GIC_SPI 100 IRQ_TYPE_NONE>;
+ status = "disabled";
+ dr_mode = "host";
+
+ clocks = <&gcc USB_HS1_XCVR_CLK>,
+ <&gcc USB_HS1_H_CLK>;
+ clock-names = "core", "iface";
+
+ resets = <&gcc USB_HS1_RESET>;
+ reset-names = "link";
+ };
+
+ usb3_phy: phy@12520000 {
+ compatible = "qcom,usb-otg-ci";
+ reg = <0x12520000 0x400>;
+ interrupts = <GIC_SPI 188 IRQ_TYPE_NONE>;
+ status = "disabled";
+ dr_mode = "host";
+
+ clocks = <&gcc USB_HS3_XCVR_CLK>,
+ <&gcc USB_HS3_H_CLK>;
+ clock-names = "core", "iface";
+
+ resets = <&gcc USB_HS3_RESET>;
+ reset-names = "link";
+ };
+
+ usb4_phy: phy@12530000 {
+ compatible = "qcom,usb-otg-ci";
+ reg = <0x12530000 0x400>;
+ interrupts = <GIC_SPI 215 IRQ_TYPE_NONE>;
+ status = "disabled";
+ dr_mode = "host";
+
+ clocks = <&gcc USB_HS4_XCVR_CLK>,
+ <&gcc USB_HS4_H_CLK>;
+ clock-names = "core", "iface";
+
+ resets = <&gcc USB_HS4_RESET>;
+ reset-names = "link";
+ };
+
+ gadget1: gadget@12500000 {
+ compatible = "qcom,ci-hdrc";
+ reg = <0x12500000 0x400>;
+ status = "disabled";
+ dr_mode = "peripheral";
+ interrupts = <GIC_SPI 100 IRQ_TYPE_NONE>;
+ usb-phy = <&usb1_phy>;
+ };
+
+ usb1: usb@12500000 {
+ compatible = "qcom,ehci-host";
+ reg = <0x12500000 0x400>;
+ interrupts = <GIC_SPI 100 IRQ_TYPE_NONE>;
+ status = "disabled";
+ usb-phy = <&usb1_phy>;
+ };
+
+ usb3: usb@12520000 {
+ compatible = "qcom,ehci-host";
+ reg = <0x12520000 0x400>;
+ interrupts = <GIC_SPI 188 IRQ_TYPE_NONE>;
+ status = "disabled";
+ usb-phy = <&usb3_phy>;
+ };
+
+ usb4: usb@12530000 {
+ compatible = "qcom,ehci-host";
+ reg = <0x12530000 0x400>;
+ interrupts = <GIC_SPI 215 IRQ_TYPE_NONE>;
+ status = "disabled";
+ usb-phy = <&usb4_phy>;
+ };
+
+ sata_phy0: phy@1b400000 {
+ compatible = "qcom,apq8064-sata-phy";
+ status = "disabled";
+ reg = <0x1b400000 0x200>;
+ reg-names = "phy_mem";
+ clocks = <&gcc SATA_PHY_CFG_CLK>;
+ clock-names = "cfg";
+ #phy-cells = <0>;
+ };
+
+ sata0: sata@29000000 {
+ compatible = "generic-ahci";
+ status = "disabled";
+ reg = <0x29000000 0x180>;
+ interrupts = <GIC_SPI 209 IRQ_TYPE_NONE>;
+
+ clocks = <&gcc SFAB_SATA_S_H_CLK>,
+ <&gcc SATA_H_CLK>,
+ <&gcc SATA_A_CLK>,
+ <&gcc SATA_RXOOB_CLK>,
+ <&gcc SATA_PMALIVE_CLK>;
+ clock-names = "slave_iface",
+ "iface",
+ "bus",
+ "rxoob",
+ "core_pmalive";
+
+ assigned-clocks = <&gcc SATA_RXOOB_CLK>,
+ <&gcc SATA_PMALIVE_CLK>;
+ assigned-clock-rates = <100000000>, <100000000>;
+
+ phys = <&sata_phy0>;
+ phy-names = "sata-phy";
+ };
+
/* Temporary fixed regulator */
vsdcc_fixed: vsdcc-regulator {
compatible = "regulator-fixed";
diff --git a/arch/arm/boot/dts/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom-msm8660.dtsi
index 20bbd19b996e..e0b2ce2910e0 100644
--- a/arch/arm/boot/dts/qcom-msm8660.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8660.dtsi
@@ -37,6 +37,11 @@
};
};
+ cpu-pmu {
+ compatible = "qcom,scorpion-mp-pmu";
+ interrupts = <1 9 0x304>;
+ };
+
soc: soc {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/qcom-pm8841.dtsi b/arch/arm/boot/dts/qcom-pm8841.dtsi
index 73813cc118f9..8f1a0b162017 100644
--- a/arch/arm/boot/dts/qcom-pm8841.dtsi
+++ b/arch/arm/boot/dts/qcom-pm8841.dtsi
@@ -1,3 +1,4 @@
+#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/spmi/spmi.h>
&spmi_bus {
@@ -7,6 +8,23 @@
reg = <0x4 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
+
+ pm8841_mpps: mpps@a000 {
+ compatible = "qcom,pm8841-mpp";
+ reg = <0xa000 0x400>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <4 0xa0 0 IRQ_TYPE_NONE>,
+ <4 0xa1 0 IRQ_TYPE_NONE>,
+ <4 0xa2 0 IRQ_TYPE_NONE>,
+ <4 0xa3 0 IRQ_TYPE_NONE>;
+ };
+
+ temp-alarm@2400 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <4 0x24 0 IRQ_TYPE_EDGE_RISING>;
+ };
};
usid5: pm8841@5 {
diff --git a/arch/arm/boot/dts/qcom-pm8941.dtsi b/arch/arm/boot/dts/qcom-pm8941.dtsi
index 24c5088acea2..aa774e685018 100644
--- a/arch/arm/boot/dts/qcom-pm8941.dtsi
+++ b/arch/arm/boot/dts/qcom-pm8941.dtsi
@@ -1,3 +1,5 @@
+#include <dt-bindings/iio/qcom,spmi-vadc.h>
+#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/spmi/spmi.h>
&spmi_bus {
@@ -7,12 +9,141 @@
reg = <0x0 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
+
+ rtc@6000 {
+ compatible = "qcom,pm8941-rtc";
+ reg = <0x6000 0x100>,
+ <0x6100 0x100>;
+ reg-names = "rtc", "alarm";
+ interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>;
+ };
+
+ pwrkey@800 {
+ compatible = "qcom,pm8941-pwrkey";
+ reg = <0x800 0x100>;
+ interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>;
+ debounce = <15625>;
+ bias-pull-up;
+ };
+
+ pm8941_gpios: gpios@c000 {
+ compatible = "qcom,pm8941-gpio";
+ reg = <0xc000 0x2400>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <0 0xc0 0 IRQ_TYPE_NONE>,
+ <0 0xc1 0 IRQ_TYPE_NONE>,
+ <0 0xc2 0 IRQ_TYPE_NONE>,
+ <0 0xc3 0 IRQ_TYPE_NONE>,
+ <0 0xc4 0 IRQ_TYPE_NONE>,
+ <0 0xc5 0 IRQ_TYPE_NONE>,
+ <0 0xc6 0 IRQ_TYPE_NONE>,
+ <0 0xc7 0 IRQ_TYPE_NONE>,
+ <0 0xc8 0 IRQ_TYPE_NONE>,
+ <0 0xc9 0 IRQ_TYPE_NONE>,
+ <0 0xca 0 IRQ_TYPE_NONE>,
+ <0 0xcb 0 IRQ_TYPE_NONE>,
+ <0 0xcc 0 IRQ_TYPE_NONE>,
+ <0 0xcd 0 IRQ_TYPE_NONE>,
+ <0 0xce 0 IRQ_TYPE_NONE>,
+ <0 0xcf 0 IRQ_TYPE_NONE>,
+ <0 0xd0 0 IRQ_TYPE_NONE>,
+ <0 0xd1 0 IRQ_TYPE_NONE>,
+ <0 0xd2 0 IRQ_TYPE_NONE>,
+ <0 0xd3 0 IRQ_TYPE_NONE>,
+ <0 0xd4 0 IRQ_TYPE_NONE>,
+ <0 0xd5 0 IRQ_TYPE_NONE>,
+ <0 0xd6 0 IRQ_TYPE_NONE>,
+ <0 0xd7 0 IRQ_TYPE_NONE>,
+ <0 0xd8 0 IRQ_TYPE_NONE>,
+ <0 0xd9 0 IRQ_TYPE_NONE>,
+ <0 0xda 0 IRQ_TYPE_NONE>,
+ <0 0xdb 0 IRQ_TYPE_NONE>,
+ <0 0xdc 0 IRQ_TYPE_NONE>,
+ <0 0xdd 0 IRQ_TYPE_NONE>,
+ <0 0xde 0 IRQ_TYPE_NONE>,
+ <0 0xdf 0 IRQ_TYPE_NONE>,
+ <0 0xe0 0 IRQ_TYPE_NONE>,
+ <0 0xe1 0 IRQ_TYPE_NONE>,
+ <0 0xe2 0 IRQ_TYPE_NONE>,
+ <0 0xe3 0 IRQ_TYPE_NONE>;
+ };
+
+ pm8941_mpps: mpps@a000 {
+ compatible = "qcom,pm8941-mpp";
+ reg = <0xa000 0x800>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <0 0xa0 0 IRQ_TYPE_NONE>,
+ <0 0xa1 0 IRQ_TYPE_NONE>,
+ <0 0xa2 0 IRQ_TYPE_NONE>,
+ <0 0xa3 0 IRQ_TYPE_NONE>,
+ <0 0xa4 0 IRQ_TYPE_NONE>,
+ <0 0xa5 0 IRQ_TYPE_NONE>,
+ <0 0xa6 0 IRQ_TYPE_NONE>,
+ <0 0xa7 0 IRQ_TYPE_NONE>;
+ };
+
+ pm8941_temp: temp-alarm@2400 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>;
+ io-channels = <&pm8941_vadc VADC_DIE_TEMP>;
+ io-channel-names = "thermal";
+ #thermal-sensor-cells = <0>;
+ };
+
+ pm8941_vadc: vadc@3100 {
+ compatible = "qcom,spmi-vadc";
+ reg = <0x3100 0x100>;
+ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+
+ die_temp {
+ reg = <VADC_DIE_TEMP>;
+ };
+ ref_625mv {
+ reg = <VADC_REF_625MV>;
+ };
+ ref_1250v {
+ reg = <VADC_REF_1250MV>;
+ };
+ ref_gnd {
+ reg = <VADC_GND_REF>;
+ };
+ ref_vdd {
+ reg = <VADC_VDD_VADC>;
+ };
+ };
+
+ pm8941_iadc: iadc@3600 {
+ compatible = "qcom,pm8941-iadc", "qcom,spmi-iadc";
+ reg = <0x3600 0x100>,
+ <0x12f1 0x1>;
+ interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>;
+ qcom,external-resistor-micro-ohms = <10000>;
+ };
};
usid1: pm8941@1 {
- compatible ="qcom,spmi-pmic";
+ compatible = "qcom,spmi-pmic";
reg = <0x1 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
+
+ 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>;
+ };
};
};
diff --git a/arch/arm/boot/dts/qcom-pma8084.dtsi b/arch/arm/boot/dts/qcom-pma8084.dtsi
index a5a4fe695a46..5e240ccc08b7 100644
--- a/arch/arm/boot/dts/qcom-pma8084.dtsi
+++ b/arch/arm/boot/dts/qcom-pma8084.dtsi
@@ -1,3 +1,5 @@
+#include <dt-bindings/iio/qcom,spmi-vadc.h>
+#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/spmi/spmi.h>
&spmi_bus {
@@ -7,6 +9,96 @@
reg = <0x0 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
+
+ rtc@6000 {
+ compatible = "qcom,pm8941-rtc";
+ reg = <0x6000 0x100>,
+ <0x6100 0x100>;
+ reg-names = "rtc", "alarm";
+ interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>;
+ };
+
+ pma8084_gpios: gpios@c000 {
+ compatible = "qcom,pma8084-gpio";
+ reg = <0xc000 0x1600>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <0 0xc0 0 IRQ_TYPE_NONE>,
+ <0 0xc1 0 IRQ_TYPE_NONE>,
+ <0 0xc2 0 IRQ_TYPE_NONE>,
+ <0 0xc3 0 IRQ_TYPE_NONE>,
+ <0 0xc4 0 IRQ_TYPE_NONE>,
+ <0 0xc5 0 IRQ_TYPE_NONE>,
+ <0 0xc6 0 IRQ_TYPE_NONE>,
+ <0 0xc7 0 IRQ_TYPE_NONE>,
+ <0 0xc8 0 IRQ_TYPE_NONE>,
+ <0 0xc9 0 IRQ_TYPE_NONE>,
+ <0 0xca 0 IRQ_TYPE_NONE>,
+ <0 0xcb 0 IRQ_TYPE_NONE>,
+ <0 0xcc 0 IRQ_TYPE_NONE>,
+ <0 0xcd 0 IRQ_TYPE_NONE>,
+ <0 0xce 0 IRQ_TYPE_NONE>,
+ <0 0xcf 0 IRQ_TYPE_NONE>,
+ <0 0xd0 0 IRQ_TYPE_NONE>,
+ <0 0xd1 0 IRQ_TYPE_NONE>,
+ <0 0xd2 0 IRQ_TYPE_NONE>,
+ <0 0xd3 0 IRQ_TYPE_NONE>,
+ <0 0xd4 0 IRQ_TYPE_NONE>,
+ <0 0xd5 0 IRQ_TYPE_NONE>;
+ };
+
+ pma8084_mpps: mpps@a000 {
+ compatible = "qcom,pma8084-mpp";
+ reg = <0xa000 0x800>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <0 0xa0 0 IRQ_TYPE_NONE>,
+ <0 0xa1 0 IRQ_TYPE_NONE>,
+ <0 0xa2 0 IRQ_TYPE_NONE>,
+ <0 0xa3 0 IRQ_TYPE_NONE>,
+ <0 0xa4 0 IRQ_TYPE_NONE>,
+ <0 0xa5 0 IRQ_TYPE_NONE>,
+ <0 0xa6 0 IRQ_TYPE_NONE>,
+ <0 0xa7 0 IRQ_TYPE_NONE>;
+ };
+
+ pma8084_temp: temp-alarm@2400 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>;
+ #thermal-sensor-cells = <0>;
+ io-channels = <&pma8084_vadc VADC_DIE_TEMP>;
+ io-channel-names = "thermal";
+ };
+
+ pma8084_vadc: vadc@3100 {
+ compatible = "qcom,spmi-vadc";
+ reg = <0x3100 0x100>;
+ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+ io-channel-ranges;
+
+ die_temp {
+ reg = <VADC_DIE_TEMP>;
+ };
+ ref_625mv {
+ reg = <VADC_REF_625MV>;
+ };
+ ref_1250v {
+ reg = <VADC_REF_1250MV>;
+ };
+ ref_buf_625mv {
+ reg = <VADC_SPARE1>;
+ };
+ ref_gnd {
+ reg = <VADC_GND_REF>;
+ };
+ ref_vdd {
+ reg = <VADC_VDD_VADC>;
+ };
+ };
};
usid1: pma8084@1 {
diff --git a/arch/arm/boot/dts/r8a73a4-ape6evm.dts b/arch/arm/boot/dts/r8a73a4-ape6evm.dts
index 81a38ceee098..a4c425923c05 100644
--- a/arch/arm/boot/dts/r8a73a4-ape6evm.dts
+++ b/arch/arm/boot/dts/r8a73a4-ape6evm.dts
@@ -147,7 +147,7 @@
&i2c5 {
status = "okay";
- vdd_dvfs: max8973@1b {
+ vdd_dvfs: regulator@1b {
compatible = "maxim,max8973";
reg = <0x1b>;
diff --git a/arch/arm/boot/dts/r8a73a4.dtsi b/arch/arm/boot/dts/r8a73a4.dtsi
index 0fd889f88109..7ee22a41c6c9 100644
--- a/arch/arm/boot/dts/r8a73a4.dtsi
+++ b/arch/arm/boot/dts/r8a73a4.dtsi
@@ -163,6 +163,7 @@
<0 29 IRQ_TYPE_LEVEL_HIGH>,
<0 30 IRQ_TYPE_LEVEL_HIGH>,
<0 31 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp4_clks R8A73A4_CLK_IRQC>;
power-domains = <&pd_c4>;
};
@@ -197,6 +198,7 @@
<0 55 IRQ_TYPE_LEVEL_HIGH>,
<0 56 IRQ_TYPE_LEVEL_HIGH>,
<0 57 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp4_clks R8A73A4_CLK_IRQC>;
power-domains = <&pd_c4>;
};
@@ -724,15 +726,16 @@
mstp4_clks: mstp4_clks@e6150140 {
compatible = "renesas,r8a73a4-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe6150140 0 4>, <0 0xe615004c 0 4>;
- clocks = <&main_div2_clk>, <&cpg_clocks R8A73A4_CLK_HP>,
+ clocks = <&main_div2_clk>, <&main_div2_clk>,
+ <&cpg_clocks R8A73A4_CLK_HP>,
<&cpg_clocks R8A73A4_CLK_HP>;
#clock-cells = <1>;
clock-indices = <
- R8A73A4_CLK_IIC5 R8A73A4_CLK_IIC4
- R8A73A4_CLK_IIC3
+ R8A73A4_CLK_IRQC R8A73A4_CLK_IIC5
+ R8A73A4_CLK_IIC4 R8A73A4_CLK_IIC3
>;
clock-output-names =
- "iic5", "iic4", "iic3";
+ "irqc", "iic5", "iic4", "iic3";
};
mstp5_clks: mstp5_clks@e6150144 {
compatible = "renesas,r8a73a4-mstp-clocks", "renesas,cpg-mstp-clocks";
diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
index 9bd0cb439f44..2e31d8c01cbf 100644
--- a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
+++ b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
@@ -208,7 +208,7 @@
gpios = <&pfc 166 GPIO_ACTIVE_LOW>;
};
- wm8978: wm8978@1a {
+ wm8978: codec@1a {
#sound-dai-cells = <0>;
compatible = "wlf,wm8978";
reg = <0x1a>;
diff --git a/arch/arm/boot/dts/r8a7740.dtsi b/arch/arm/boot/dts/r8a7740.dtsi
index 83c1c3ca1b8f..d84714468cce 100644
--- a/arch/arm/boot/dts/r8a7740.dtsi
+++ b/arch/arm/boot/dts/r8a7740.dtsi
@@ -67,7 +67,7 @@
};
/* irqpin0: IRQ0 - IRQ7 */
- irqpin0: irqpin@e6900000 {
+ irqpin0: interrupt-controller@e6900000 {
compatible = "renesas,intc-irqpin-r8a7740", "renesas,intc-irqpin";
#interrupt-cells = <2>;
interrupt-controller;
@@ -89,7 +89,7 @@
};
/* irqpin1: IRQ8 - IRQ15 */
- irqpin1: irqpin@e6900004 {
+ irqpin1: interrupt-controller@e6900004 {
compatible = "renesas,intc-irqpin-r8a7740", "renesas,intc-irqpin";
#interrupt-cells = <2>;
interrupt-controller;
@@ -111,7 +111,7 @@
};
/* irqpin2: IRQ16 - IRQ23 */
- irqpin2: irqpin@e6900008 {
+ irqpin2: interrupt-controller@e6900008 {
compatible = "renesas,intc-irqpin-r8a7740", "renesas,intc-irqpin";
#interrupt-cells = <2>;
interrupt-controller;
@@ -133,7 +133,7 @@
};
/* irqpin3: IRQ24 - IRQ31 */
- irqpin3: irqpin@e690000c {
+ irqpin3: interrupt-controller@e690000c {
compatible = "renesas,intc-irqpin-r8a7740", "renesas,intc-irqpin";
#interrupt-cells = <2>;
interrupt-controller;
@@ -275,7 +275,7 @@
status = "disabled";
};
- scifb8: serial@e6c30000 {
+ scifb: serial@e6c30000 {
compatible = "renesas,scifb-r8a7740", "renesas,scifb";
reg = <0xe6c30000 0x100>;
interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/r8a7778-bockw-reference.dts b/arch/arm/boot/dts/r8a7778-bockw-reference.dts
index 04c0c37bb784..dffa6ff30360 100644
--- a/arch/arm/boot/dts/r8a7778-bockw-reference.dts
+++ b/arch/arm/boot/dts/r8a7778-bockw-reference.dts
@@ -119,7 +119,7 @@
flash: flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "spansion,s25fl008k";
+ compatible = "spansion,s25fl008k", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <104000000>;
m25p,fast-read;
diff --git a/arch/arm/boot/dts/r8a7778-bockw.dts b/arch/arm/boot/dts/r8a7778-bockw.dts
index 787fa6f9f46d..90543b12d7e2 100644
--- a/arch/arm/boot/dts/r8a7778-bockw.dts
+++ b/arch/arm/boot/dts/r8a7778-bockw.dts
@@ -85,7 +85,7 @@
&i2c0 {
status = "okay";
- ak4643: sound-codec@12 {
+ ak4643: codec@12 {
compatible = "asahi-kasei,ak4643";
#sound-dai-cells = <0>;
reg = <0x12>;
@@ -186,7 +186,7 @@
flash: flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "spansion,s25fl008k";
+ compatible = "spansion,s25fl008k", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <104000000>;
m25p,fast-read;
diff --git a/arch/arm/boot/dts/r8a7778.dtsi b/arch/arm/boot/dts/r8a7778.dtsi
index 868f97309533..7ce9f5fd5865 100644
--- a/arch/arm/boot/dts/r8a7778.dtsi
+++ b/arch/arm/boot/dts/r8a7778.dtsi
@@ -68,7 +68,7 @@
};
/* irqpin: IRQ0 - IRQ3 */
- irqpin: irqpin@fe78001c {
+ irqpin: interrupt-controller@fe78001c {
compatible = "renesas,intc-irqpin-r8a7778", "renesas,intc-irqpin";
#interrupt-cells = <2>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/r8a7779-marzen.dts b/arch/arm/boot/dts/r8a7779-marzen.dts
index 540756cdf391..20afea6f06ef 100644
--- a/arch/arm/boot/dts/r8a7779-marzen.dts
+++ b/arch/arm/boot/dts/r8a7779-marzen.dts
@@ -42,10 +42,10 @@
regulator-always-on;
};
- lan0@18000000 {
+ ethernet@18000000 {
compatible = "smsc,lan9220", "smsc,lan9115";
reg = <0x18000000 0x100>;
- pinctrl-0 = <&lan0_pins>;
+ pinctrl-0 = <&ethernet_pins>;
pinctrl-names = "default";
phy-mode = "mii";
@@ -176,7 +176,7 @@
};
};
- lan0_pins: lan0 {
+ ethernet_pins: ethernet {
intc {
renesas,groups = "intc_irq1_b";
renesas,function = "intc";
diff --git a/arch/arm/boot/dts/r8a7779.dtsi b/arch/arm/boot/dts/r8a7779.dtsi
index 5c2219b9f3eb..5c8071e87ae9 100644
--- a/arch/arm/boot/dts/r8a7779.dtsi
+++ b/arch/arm/boot/dts/r8a7779.dtsi
@@ -148,7 +148,7 @@
interrupt-controller;
};
- irqpin0: irqpin@fe780010 {
+ irqpin0: interrupt-controller@fe780010 {
compatible = "renesas,intc-irqpin-r8a7779", "renesas,intc-irqpin";
#interrupt-cells = <2>;
status = "disabled";
diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index aaa4f258e279..2eb8a995ae9f 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -429,7 +429,7 @@
flash: flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "spansion,s25fl512s";
+ compatible = "spansion,s25fl512s", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <30000000>;
spi-tx-bus-width = <4>;
@@ -525,7 +525,7 @@
clock-frequency = <100000>;
- ak4643: sound-codec@12 {
+ ak4643: codec@12 {
compatible = "asahi-kasei,ak4643";
#sound-dai-cells = <0>;
reg = <0x12>;
diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index 4bb2f4c17321..51ab8865ea37 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -252,6 +252,7 @@
<0 1 IRQ_TYPE_LEVEL_HIGH>,
<0 2 IRQ_TYPE_LEVEL_HIGH>,
<0 3 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp4_clks R8A7790_CLK_IRQC>;
};
dmac0: dma-controller@e6700000 {
@@ -370,6 +371,28 @@
dma-channels = <13>;
};
+ usb_dmac0: dma-controller@e65a0000 {
+ compatible = "renesas,usb-dmac";
+ reg = <0 0xe65a0000 0 0x100>;
+ interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH
+ 0 109 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "ch0", "ch1";
+ clocks = <&mstp3_clks R8A7790_CLK_USBDMAC0>;
+ #dma-cells = <1>;
+ dma-channels = <2>;
+ };
+
+ usb_dmac1: dma-controller@e65b0000 {
+ compatible = "renesas,usb-dmac";
+ reg = <0 0xe65b0000 0 0x100>;
+ interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH
+ 0 110 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "ch0", "ch1";
+ clocks = <&mstp3_clks R8A7790_CLK_USBDMAC1>;
+ #dma-cells = <1>;
+ dma-channels = <2>;
+ };
+
i2c0: i2c@e6508000 {
#address-cells = <1>;
#size-cells = <0>;
@@ -467,6 +490,7 @@
dma-names = "tx", "rx";
reg-io-width = <4>;
status = "disabled";
+ max-frequency = <97500000>;
};
mmcif1: mmc@ee220000 {
@@ -478,6 +502,7 @@
dma-names = "tx", "rx";
reg-io-width = <4>;
status = "disabled";
+ max-frequency = <97500000>;
};
pfc: pfc@e6060000 {
@@ -531,6 +556,8 @@
interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7790_CLK_SCIFA0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x21>, <&dmac0 0x22>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -540,6 +567,8 @@
interrupts = <0 145 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7790_CLK_SCIFA1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x25>, <&dmac0 0x26>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -549,6 +578,8 @@
interrupts = <0 151 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7790_CLK_SCIFA2>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x27>, <&dmac0 0x28>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -558,6 +589,8 @@
interrupts = <0 148 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7790_CLK_SCIFB0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x3d>, <&dmac0 0x3e>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -567,6 +600,8 @@
interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7790_CLK_SCIFB1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x19>, <&dmac0 0x1a>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -576,6 +611,8 @@
interrupts = <0 150 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7790_CLK_SCIFB2>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x1d>, <&dmac0 0x1e>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -585,6 +622,8 @@
interrupts = <0 152 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7790_CLK_SCIF0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x29>, <&dmac0 0x2a>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -594,6 +633,8 @@
interrupts = <0 153 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7790_CLK_SCIF1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x2d>, <&dmac0 0x2e>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -603,6 +644,8 @@
interrupts = <0 154 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7790_CLK_HSCIF0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x39>, <&dmac0 0x3a>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -612,6 +655,8 @@
interrupts = <0 155 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7790_CLK_HSCIF1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x4d>, <&dmac0 0x4e>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -650,6 +695,9 @@
renesas,buswait = <4>;
phys = <&usb0 1>;
phy-names = "usb";
+ dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
+ <&usb_dmac1 0>, <&usb_dmac1 1>;
+ dma-names = "ch0", "ch1", "ch2", "ch3";
status = "disabled";
};
@@ -1158,6 +1206,14 @@
"iic0", "pciec", "iic1", "ssusb", "cmt1",
"usbdmac0", "usbdmac1";
};
+ mstp4_clks: mstp4_clks@e6150140 {
+ compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
+ reg = <0 0xe6150140 0 4>, <0 0xe615004c 0 4>;
+ clocks = <&cp_clk>;
+ #clock-cells = <1>;
+ clock-indices = <R8A7790_CLK_IRQC>;
+ clock-output-names = "irqc";
+ };
mstp5_clks: mstp5_clks@e6150144 {
compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>;
@@ -1273,7 +1329,7 @@
msiof0: spi@e6e20000 {
compatible = "renesas,msiof-r8a7790";
- reg = <0 0xe6e20000 0 0x0064>, <0 0xe7e20000 0 0x0064>;
+ reg = <0 0xe6e20000 0 0x0064>;
interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp0_clks R8A7790_CLK_MSIOF0>;
dmas = <&dmac0 0x51>, <&dmac0 0x52>;
@@ -1285,7 +1341,7 @@
msiof1: spi@e6e10000 {
compatible = "renesas,msiof-r8a7790";
- reg = <0 0xe6e10000 0 0x0064>, <0 0xe7e10000 0 0x0064>;
+ reg = <0 0xe6e10000 0 0x0064>;
interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7790_CLK_MSIOF1>;
dmas = <&dmac0 0x55>, <&dmac0 0x56>;
@@ -1297,7 +1353,7 @@
msiof2: spi@e6e00000 {
compatible = "renesas,msiof-r8a7790";
- reg = <0 0xe6e00000 0 0x0064>, <0 0xe7e00000 0 0x0064>;
+ reg = <0 0xe6e00000 0 0x0064>;
interrupts = <0 158 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7790_CLK_MSIOF2>;
dmas = <&dmac0 0x41>, <&dmac0 0x42>;
@@ -1309,7 +1365,7 @@
msiof3: spi@e6c90000 {
compatible = "renesas,msiof-r8a7790";
- reg = <0 0xe6c90000 0 0x0064>, <0 0xe7c90000 0 0x0064>;
+ reg = <0 0xe6c90000 0 0x0064>;
interrupts = <0 159 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7790_CLK_MSIOF3>;
dmas = <&dmac0 0x45>, <&dmac0 0x46>;
@@ -1442,7 +1498,7 @@
status = "disabled";
};
- rcar_sound: rcar_sound@ec500000 {
+ rcar_sound: sound@ec500000 {
/*
* #sound-dai-cells is required
*
diff --git a/arch/arm/boot/dts/r8a7791-henninger.dts b/arch/arm/boot/dts/r8a7791-henninger.dts
index e33e4047b0b0..655d1804e5e9 100644
--- a/arch/arm/boot/dts/r8a7791-henninger.dts
+++ b/arch/arm/boot/dts/r8a7791-henninger.dts
@@ -226,7 +226,7 @@
flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "spansion,s25fl512s";
+ compatible = "spansion,s25fl512s", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <30000000>;
spi-tx-bus-width = <4>;
diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index 824ddab9c3ad..cffe33ff4d16 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -474,7 +474,7 @@
flash: flash@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "spansion,s25fl512s";
+ compatible = "spansion,s25fl512s", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <30000000>;
spi-tx-bus-width = <4>;
@@ -522,7 +522,7 @@
status = "okay";
clock-frequency = <100000>;
- ak4643: sound-codec@12 {
+ ak4643: codec@12 {
compatible = "asahi-kasei,ak4643";
#sound-dai-cells = <0>;
reg = <0x12>;
diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index 4696062f6dde..dc1cd3f16606 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -239,6 +239,7 @@
<0 15 IRQ_TYPE_LEVEL_HIGH>,
<0 16 IRQ_TYPE_LEVEL_HIGH>,
<0 17 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp4_clks R8A7791_CLK_IRQC>;
};
dmac0: dma-controller@e6700000 {
@@ -357,6 +358,28 @@
dma-channels = <13>;
};
+ usb_dmac0: dma-controller@e65a0000 {
+ compatible = "renesas,usb-dmac";
+ reg = <0 0xe65a0000 0 0x100>;
+ interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH
+ 0 109 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "ch0", "ch1";
+ clocks = <&mstp3_clks R8A7791_CLK_USBDMAC0>;
+ #dma-cells = <1>;
+ dma-channels = <2>;
+ };
+
+ usb_dmac1: dma-controller@e65b0000 {
+ compatible = "renesas,usb-dmac";
+ reg = <0 0xe65b0000 0 0x100>;
+ interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH
+ 0 110 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "ch0", "ch1";
+ clocks = <&mstp3_clks R8A7791_CLK_USBDMAC1>;
+ #dma-cells = <1>;
+ dma-channels = <2>;
+ };
+
/* The memory map in the User's Manual maps the cores to bus numbers */
i2c0: i2c@e6508000 {
#address-cells = <1>;
@@ -471,6 +494,7 @@
dma-names = "tx", "rx";
reg-io-width = <4>;
status = "disabled";
+ max-frequency = <97500000>;
};
sdhi0: sd@ee100000 {
@@ -509,6 +533,8 @@
interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7791_CLK_SCIFA0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x21>, <&dmac0 0x22>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -518,6 +544,8 @@
interrupts = <0 145 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7791_CLK_SCIFA1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x25>, <&dmac0 0x26>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -527,6 +555,8 @@
interrupts = <0 151 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7791_CLK_SCIFA2>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x27>, <&dmac0 0x28>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -536,6 +566,8 @@
interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp11_clks R8A7791_CLK_SCIFA3>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x1b>, <&dmac0 0x1c>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -545,6 +577,8 @@
interrupts = <0 30 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp11_clks R8A7791_CLK_SCIFA4>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x1f>, <&dmac0 0x20>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -554,6 +588,8 @@
interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp11_clks R8A7791_CLK_SCIFA5>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x23>, <&dmac0 0x24>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -563,6 +599,8 @@
interrupts = <0 148 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7791_CLK_SCIFB0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x3d>, <&dmac0 0x3e>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -572,6 +610,8 @@
interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7791_CLK_SCIFB1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x19>, <&dmac0 0x1a>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -581,6 +621,8 @@
interrupts = <0 150 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7791_CLK_SCIFB2>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x1d>, <&dmac0 0x1e>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -590,6 +632,8 @@
interrupts = <0 152 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7791_CLK_SCIF0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x29>, <&dmac0 0x2a>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -599,6 +643,8 @@
interrupts = <0 153 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7791_CLK_SCIF1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x2d>, <&dmac0 0x2e>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -608,6 +654,8 @@
interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7791_CLK_SCIF2>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x2b>, <&dmac0 0x2c>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -617,6 +665,8 @@
interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7791_CLK_SCIF3>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x2f>, <&dmac0 0x30>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -626,6 +676,8 @@
interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7791_CLK_SCIF4>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0xfb>, <&dmac0 0xfc>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -635,6 +687,8 @@
interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7791_CLK_SCIF5>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0xfd>, <&dmac0 0xfe>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -644,6 +698,8 @@
interrupts = <0 154 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7791_CLK_HSCIF0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x39>, <&dmac0 0x3a>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -653,6 +709,8 @@
interrupts = <0 155 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7791_CLK_HSCIF1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x4d>, <&dmac0 0x4e>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -662,6 +720,8 @@
interrupts = <0 21 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7791_CLK_HSCIF2>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x3b>, <&dmac0 0x3c>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -700,6 +760,9 @@
renesas,buswait = <4>;
phys = <&usb0 1>;
phy-names = "usb";
+ dmas = <&usb_dmac0 0>, <&usb_dmac0 1>,
+ <&usb_dmac1 0>, <&usb_dmac1 1>;
+ dma-names = "ch0", "ch1", "ch2", "ch3";
status = "disabled";
};
@@ -1160,6 +1223,14 @@
"mmcif0", "i2c7", "pciec", "i2c8", "ssusb", "cmt1",
"usbdmac0", "usbdmac1";
};
+ mstp4_clks: mstp4_clks@e6150140 {
+ compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
+ reg = <0 0xe6150140 0 4>, <0 0xe615004c 0 4>;
+ clocks = <&cp_clk>;
+ #clock-cells = <1>;
+ clock-indices = <R8A7791_CLK_IRQC>;
+ clock-output-names = "irqc";
+ };
mstp5_clks: mstp5_clks@e6150144 {
compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>;
@@ -1288,7 +1359,7 @@
msiof0: spi@e6e20000 {
compatible = "renesas,msiof-r8a7791";
- reg = <0 0xe6e20000 0 0x0064>, <0 0xe7e20000 0 0x0064>;
+ reg = <0 0xe6e20000 0 0x0064>;
interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
dmas = <&dmac0 0x51>, <&dmac0 0x52>;
@@ -1300,7 +1371,7 @@
msiof1: spi@e6e10000 {
compatible = "renesas,msiof-r8a7791";
- reg = <0 0xe6e10000 0 0x0064>, <0 0xe7e10000 0 0x0064>;
+ reg = <0 0xe6e10000 0 0x0064>;
interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7791_CLK_MSIOF1>;
dmas = <&dmac0 0x55>, <&dmac0 0x56>;
@@ -1312,7 +1383,7 @@
msiof2: spi@e6e00000 {
compatible = "renesas,msiof-r8a7791";
- reg = <0 0xe6e00000 0 0x0064>, <0 0xe7e00000 0 0x0064>;
+ reg = <0 0xe6e00000 0 0x0064>;
interrupts = <0 158 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7791_CLK_MSIOF2>;
dmas = <&dmac0 0x41>, <&dmac0 0x42>;
@@ -1485,7 +1556,7 @@
status = "disabled";
};
- rcar_sound: rcar_sound@ec500000 {
+ rcar_sound: sound@ec500000 {
/*
* #sound-dai-cells is required
*
diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi
index 7a3ffa51a8bf..b73819423311 100644
--- a/arch/arm/boot/dts/r8a7794.dtsi
+++ b/arch/arm/boot/dts/r8a7794.dtsi
@@ -105,6 +105,7 @@
<0 15 IRQ_TYPE_LEVEL_HIGH>,
<0 16 IRQ_TYPE_LEVEL_HIGH>,
<0 17 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp4_clks R8A7794_CLK_IRQC>;
};
dmac0: dma-controller@e6700000 {
@@ -173,6 +174,8 @@
interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7794_CLK_SCIFA0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x21>, <&dmac0 0x22>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -182,6 +185,8 @@
interrupts = <0 145 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7794_CLK_SCIFA1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x25>, <&dmac0 0x26>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -191,6 +196,8 @@
interrupts = <0 151 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7794_CLK_SCIFA2>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x27>, <&dmac0 0x28>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -200,6 +207,8 @@
interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp11_clks R8A7794_CLK_SCIFA3>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x1b>, <&dmac0 0x1c>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -209,6 +218,8 @@
interrupts = <0 30 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp11_clks R8A7794_CLK_SCIFA4>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x1f>, <&dmac0 0x20>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -218,6 +229,8 @@
interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp11_clks R8A7794_CLK_SCIFA5>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x23>, <&dmac0 0x24>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -227,6 +240,8 @@
interrupts = <0 148 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7794_CLK_SCIFB0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x3d>, <&dmac0 0x3e>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -236,6 +251,8 @@
interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7794_CLK_SCIFB1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x19>, <&dmac0 0x1a>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -245,6 +262,8 @@
interrupts = <0 150 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp2_clks R8A7794_CLK_SCIFB2>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x1d>, <&dmac0 0x1e>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -254,6 +273,8 @@
interrupts = <0 152 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7794_CLK_SCIF0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x29>, <&dmac0 0x2a>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -263,6 +284,8 @@
interrupts = <0 153 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7794_CLK_SCIF1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x2d>, <&dmac0 0x2e>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -272,6 +295,8 @@
interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7794_CLK_SCIF2>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x2b>, <&dmac0 0x2c>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -281,6 +306,8 @@
interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7794_CLK_SCIF3>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x2f>, <&dmac0 0x30>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -290,6 +317,8 @@
interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7794_CLK_SCIF4>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0xfb>, <&dmac0 0xfc>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -299,6 +328,8 @@
interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7794_CLK_SCIF5>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0xfd>, <&dmac0 0xfe>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -308,6 +339,8 @@
interrupts = <0 154 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7794_CLK_HSCIF0>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x39>, <&dmac0 0x3a>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -317,6 +350,8 @@
interrupts = <0 155 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7794_CLK_HSCIF1>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x4d>, <&dmac0 0x4e>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -326,6 +361,8 @@
interrupts = <0 21 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7794_CLK_HSCIF2>;
clock-names = "sci_ick";
+ dmas = <&dmac0 0x3b>, <&dmac0 0x3c>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -625,6 +662,14 @@
"sdhi2", "sdhi1", "sdhi0",
"mmcif0", "cmt1", "usbdmac0", "usbdmac1";
};
+ mstp4_clks: mstp4_clks@e6150140 {
+ compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
+ reg = <0 0xe6150140 0 4>, <0 0xe615004c 0 4>;
+ clocks = <&cp_clk>;
+ #clock-cells = <1>;
+ clock-indices = <R8A7794_CLK_IRQC>;
+ clock-output-names = "irqc";
+ };
mstp7_clks: mstp7_clks@e615014c {
compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe615014c 0 4>, <0 0xe61501c4 0 4>;
diff --git a/arch/arm/boot/dts/rk3066a-bqcurie2.dts b/arch/arm/boot/dts/rk3066a-bqcurie2.dts
index baf21ac6ce7f..b299b26926d4 100644
--- a/arch/arm/boot/dts/rk3066a-bqcurie2.dts
+++ b/arch/arm/boot/dts/rk3066a-bqcurie2.dts
@@ -2,15 +2,43 @@
* Copyright (c) 2013 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.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 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.
*
- * 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.
+ * 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/;
diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi
index 41ffd4951ef3..d32229b8a996 100644
--- a/arch/arm/boot/dts/rk3066a.dtsi
+++ b/arch/arm/boot/dts/rk3066a.dtsi
@@ -2,15 +2,43 @@
* Copyright (c) 2013 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.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 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.
*
- * 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.
+ * 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>
diff --git a/arch/arm/boot/dts/rk3188-radxarock.dts b/arch/arm/boot/dts/rk3188-radxarock.dts
index bdf85701987d..42faa19edb7e 100644
--- a/arch/arm/boot/dts/rk3188-radxarock.dts
+++ b/arch/arm/boot/dts/rk3188-radxarock.dts
@@ -1,15 +1,43 @@
/*
* Copyright (c) 2013 Heiko Stuebner <heiko@sntech.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 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.
*
- * 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.
+ * 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/;
@@ -152,6 +180,7 @@
compatible = "active-semi,act8846";
reg = <0x5a>;
status = "okay";
+ system-power-controller;
pinctrl-names = "default";
pinctrl-0 = <&act8846_dvs0_ctl>;
diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi
index 1d4d79c6688d..0f23aedf9349 100644
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@ -2,15 +2,43 @@
* Copyright (c) 2013 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.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 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.
*
- * 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.
+ * 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>
diff --git a/arch/arm/boot/dts/rk3288-evb-act8846.dts b/arch/arm/boot/dts/rk3288-evb-act8846.dts
index 1687e8336994..43949a6771f0 100644
--- a/arch/arm/boot/dts/rk3288-evb-act8846.dts
+++ b/arch/arm/boot/dts/rk3288-evb-act8846.dts
@@ -1,13 +1,41 @@
/*
- * 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 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.
*
- * 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.
+ * 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/;
diff --git a/arch/arm/boot/dts/rk3288-evb-rk808.dts b/arch/arm/boot/dts/rk3288-evb-rk808.dts
index f62ea78754a9..18eb6cb495f4 100644
--- a/arch/arm/boot/dts/rk3288-evb-rk808.dts
+++ b/arch/arm/boot/dts/rk3288-evb-rk808.dts
@@ -1,13 +1,41 @@
/*
- * 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 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.
*
- * 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.
+ * 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/;
diff --git a/arch/arm/boot/dts/rk3288-evb.dtsi b/arch/arm/boot/dts/rk3288-evb.dtsi
index 4a457518d861..844a6fb64658 100644
--- a/arch/arm/boot/dts/rk3288-evb.dtsi
+++ b/arch/arm/boot/dts/rk3288-evb.dtsi
@@ -1,13 +1,41 @@
/*
- * 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 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.
*
- * 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.
+ * 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>
@@ -112,6 +140,23 @@
regulator-always-on;
regulator-boot-on;
};
+
+ /*
+ * NOTE: vcc_sd isn't hooked up on v1.0 boards where power comes from
+ * vcc_io directly. Those boards won't be able to power cycle SD cards
+ * but it shouldn't hurt to toggle this pin there anyway.
+ */
+ vcc_sd: sdmmc-regulator {
+ compatible = "regulator-fixed";
+ gpio = <&gpio7 11 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc_pwr>;
+ regulator-name = "vcc_sd";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <100000>;
+ vin-supply = <&vcc_io>;
+ };
};
&emmc {
@@ -141,6 +186,8 @@
pinctrl-names = "default";
pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
status = "okay";
+ vmmc-supply = <&vcc_sd>;
+ vqmmc-supply = <&vccio_sd>;
};
&i2c0 {
@@ -232,6 +279,10 @@
sdmmc_cmd: sdmmc-cmd {
rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
};
+
+ sdmmc_pwr: sdmmc-pwr {
+ rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
};
usb {
diff --git a/arch/arm/boot/dts/rk3288-firefly.dtsi b/arch/arm/boot/dts/rk3288-firefly.dtsi
index b54dd78580c1..0b42372e4379 100644
--- a/arch/arm/boot/dts/rk3288-firefly.dtsi
+++ b/arch/arm/boot/dts/rk3288-firefly.dtsi
@@ -246,6 +246,14 @@
pinctrl-0 = <&pmic_vsel>, <&pwr_hold>;
system-power-controller;
+ vp1-supply = <&vcc_sys>;
+ vp2-supply = <&vcc_sys>;
+ vp3-supply = <&vcc_sys>;
+ vp4-supply = <&vcc_sys>;
+ inl1-supply = <&vcc_sys>;
+ inl2-supply = <&vcc_sys>;
+ inl3-supply = <&vcc_20>;
+
regulators {
vcc_ddr: REG1 {
regulator-name = "vcc_ddr";
@@ -457,6 +465,12 @@
status = "okay";
};
+&tsadc {
+ rockchip,hw-tshut-mode = <0>;
+ rockchip,hw-tshut-polarity = <0>;
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_xfer>, <&uart0_cts>, <&uart0_rts>;
diff --git a/arch/arm/boot/dts/rk3288-popmetal.dts b/arch/arm/boot/dts/rk3288-popmetal.dts
index d081f0e0da36..d582811fbd7b 100644
--- a/arch/arm/boot/dts/rk3288-popmetal.dts
+++ b/arch/arm/boot/dts/rk3288-popmetal.dts
@@ -406,6 +406,12 @@
};
};
+&tsadc {
+ rockchip,hw-tshut-mode = <0>;
+ rockchip,hw-tshut-polarity = <0>;
+ status = "okay";
+};
+
&vopb {
status = "okay";
};
diff --git a/arch/arm/boot/dts/rk3288-thermal.dtsi b/arch/arm/boot/dts/rk3288-thermal.dtsi
index 2695200c0af7..340406652186 100644
--- a/arch/arm/boot/dts/rk3288-thermal.dtsi
+++ b/arch/arm/boot/dts/rk3288-thermal.dtsi
@@ -3,9 +3,43 @@
*
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
*
- * 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.
+ * 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>
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 165968d51d8f..22316d00493e 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -1,13 +1,41 @@
/*
- * 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 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.
*
- * 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.
+ * 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>
@@ -44,6 +72,14 @@
spi2 = &spi2;
};
+ arm-pmu {
+ compatible = "arm,cortex-a12-pmu";
+ interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -434,6 +470,7 @@
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru HCLK_USBHOST1>;
clock-names = "otg";
+ dr_mode = "host";
phys = <&usbphy2>;
phy-names = "usb2-phy";
status = "disabled";
@@ -446,6 +483,11 @@
interrupts = <GIC_SPI 23 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;
phys = <&usbphy0>;
phy-names = "usb2-phy";
status = "disabled";
diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
index c54a9715dcfa..a2ae9f32464d 100644
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@ -2,15 +2,43 @@
* Copyright (c) 2013 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.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 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.
*
- * 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.
+ * 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/interrupt-controller/irq.h>
diff --git a/arch/arm/boot/dts/s3c2416-smdk2416.dts b/arch/arm/boot/dts/s3c2416-smdk2416.dts
index ea92fd69529a..f257926c13b7 100644
--- a/arch/arm/boot/dts/s3c2416-smdk2416.dts
+++ b/arch/arm/boot/dts/s3c2416-smdk2416.dts
@@ -31,55 +31,55 @@
#clock-cells = <0>;
};
};
+};
- serial@50000000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_data>, <&uart0_fctl>;
- };
+&rtc {
+ status = "okay";
+};
- serial@50004000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&uart1_data>, <&uart1_fctl>;
- };
+&sdhci_0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd1_clk>, <&sd1_cmd>,
+ <&sd1_bus1>, <&sd1_bus4>;
+ bus-width = <4>;
+ broken-cd;
+ status = "okay";
+};
- serial@50008000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&uart2_data>;
- };
+&sdhci_1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd0_clk>, <&sd0_cmd>,
+ <&sd0_bus1>, <&sd0_bus4>;
+ bus-width = <4>;
+ cd-gpios = <&gpf 1 0>;
+ cd-inverted;
+ status = "okay";
+};
- serial@5000C000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_data>;
- };
+&uart_0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_data>, <&uart0_fctl>;
+};
- watchdog@53000000 {
- status = "okay";
- };
+&uart_1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_data>, <&uart1_fctl>;
+};
- rtc@57000000 {
- status = "okay";
- };
+&uart_2 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_data>;
+};
- sdhci@4AC00000 {
- pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk>, <&sd0_cmd>,
- <&sd0_bus1>, <&sd0_bus4>;
- bus-width = <4>;
- cd-gpios = <&gpf 1 0>;
- cd-inverted;
- status = "okay";
- };
+&uart_3 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_data>;
+};
- sdhci@4A800000 {
- pinctrl-names = "default";
- pinctrl-0 = <&sd1_clk>, <&sd1_cmd>,
- <&sd1_bus1>, <&sd1_bus4>;
- bus-width = <4>;
- broken-cd;
- status = "okay";
- };
+&watchdog {
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/s3c2416.dtsi b/arch/arm/boot/dts/s3c2416.dtsi
index 30b8f7e47454..a5184ff56933 100644
--- a/arch/arm/boot/dts/s3c2416.dtsi
+++ b/arch/arm/boot/dts/s3c2416.dtsi
@@ -17,7 +17,7 @@
compatible = "samsung,s3c2416";
aliases {
- serial3 = &uart3;
+ serial3 = &uart_3;
};
cpus {
@@ -48,7 +48,7 @@
clock-names = "timers";
};
- serial@50000000 {
+ uart_0: serial@50000000 {
compatible = "samsung,s3c2440-uart";
clock-names = "uart", "clk_uart_baud2",
"clk_uart_baud3";
@@ -56,7 +56,7 @@
<&clocks SCLK_UART>;
};
- serial@50004000 {
+ uart_1: serial@50004000 {
compatible = "samsung,s3c2440-uart";
clock-names = "uart", "clk_uart_baud2",
"clk_uart_baud3";
@@ -64,7 +64,7 @@
<&clocks SCLK_UART>;
};
- serial@50008000 {
+ uart_2: serial@50008000 {
compatible = "samsung,s3c2440-uart";
clock-names = "uart", "clk_uart_baud2",
"clk_uart_baud3";
@@ -72,7 +72,7 @@
<&clocks SCLK_UART>;
};
- uart3: serial@5000C000 {
+ uart_3: serial@5000C000 {
compatible = "samsung,s3c2440-uart";
reg = <0x5000C000 0x4000>;
interrupts = <1 18 24 4>, <1 18 25 4>;
@@ -83,7 +83,7 @@
status = "disabled";
};
- sdhci@4AC00000 {
+ sdhci_1: sdhci@4AC00000 {
compatible = "samsung,s3c6410-sdhci";
reg = <0x4AC00000 0x100>;
interrupts = <0 0 21 3>;
@@ -94,7 +94,7 @@
status = "disabled";
};
- sdhci@4A800000 {
+ sdhci_0: sdhci@4A800000 {
compatible = "samsung,s3c6410-sdhci";
reg = <0x4A800000 0x100>;
interrupts = <0 0 20 3>;
@@ -105,13 +105,13 @@
status = "disabled";
};
- watchdog@53000000 {
+ watchdog: watchdog@53000000 {
interrupts = <1 9 27 3>;
clocks = <&clocks PCLK_WDT>;
clock-names = "watchdog";
};
- rtc@57000000 {
+ rtc: rtc@57000000 {
compatible = "samsung,s3c2416-rtc";
clocks = <&clocks PCLK_RTC>;
clock-names = "rtc";
diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi
index 57ab8587f7b9..5ab7548e04e1 100644
--- a/arch/arm/boot/dts/sama5d3.dtsi
+++ b/arch/arm/boot/dts/sama5d3.dtsi
@@ -1439,9 +1439,8 @@
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00600000 0x100000>;
interrupts = <32 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>,
- <&uhpck>;
- clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
+ clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
+ clock-names = "ohci_clk", "hclk", "uhpck";
status = "disabled";
};
@@ -1449,8 +1448,8 @@
compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
reg = <0x00700000 0x100000>;
interrupts = <32 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&utmi>, <&uhphs_clk>, <&uhpck>;
- clock-names = "usb_clk", "ehci_clk", "uhpck";
+ clocks = <&utmi>, <&uhphs_clk>;
+ clock-names = "usb_clk", "ehci_clk";
status = "disabled";
};
@@ -1478,7 +1477,7 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <
- 0x70000000 0x10000000 /* NFC Command Registers */
+ 0x70000000 0x08000000 /* NFC Command Registers */
0xffffc000 0x00000070 /* NFC HSMC regs */
0x00200000 0x00100000 /* NFC SRAM banks */
>;
diff --git a/arch/arm/boot/dts/sama5d3xcm.dtsi b/arch/arm/boot/dts/sama5d3xcm.dtsi
index 7d6babdab039..2cf9c3611db6 100644
--- a/arch/arm/boot/dts/sama5d3xcm.dtsi
+++ b/arch/arm/boot/dts/sama5d3xcm.dtsi
@@ -11,7 +11,8 @@
compatible = "atmel,sama5d3xcm", "atmel,sama5d3", "atmel,sama5";
chosen {
- bootargs = "console=ttyS0,115200 rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs";
+ bootargs = "rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs";
+ stdout-path = "serial0:115200n8";
};
memory {
@@ -67,12 +68,6 @@
rxd3-skew-ps = <400>;
};
};
-
- pmc: pmc@fffffc00 {
- main: mainck {
- clock-frequency = <12000000>;
- };
- };
};
nand0: nand@60000000 {
diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi
index 6b1bb58f9c0b..653a1f851f2b 100644
--- a/arch/arm/boot/dts/sama5d4.dtsi
+++ b/arch/arm/boot/dts/sama5d4.dtsi
@@ -59,6 +59,10 @@
serial0 = &usart3;
serial1 = &usart4;
serial2 = &usart2;
+ serial3 = &usart0;
+ serial4 = &usart1;
+ serial5 = &uart0;
+ serial6 = &uart1;
gpio0 = &pioA;
gpio1 = &pioB;
gpio2 = &pioC;
@@ -254,9 +258,8 @@
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00500000 0x100000>;
interrupts = <46 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>,
- <&uhpck>;
- clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
+ clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
+ clock-names = "ohci_clk", "hclk", "uhpck";
status = "disabled";
};
@@ -264,8 +267,8 @@
compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
reg = <0x00600000 0x100000>;
interrupts = <46 IRQ_TYPE_LEVEL_HIGH 2>;
- clocks = <&utmi>, <&uhphs_clk>, <&uhpck>;
- clock-names = "usb_clk", "ehci_clk", "uhpck";
+ clocks = <&utmi>, <&uhphs_clk>;
+ clock-names = "usb_clk", "ehci_clk";
status = "disabled";
};
@@ -299,7 +302,7 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <
- 0x90000000 0x10000000 /* NFC Command Registers */
+ 0x90000000 0x08000000 /* NFC Command Registers */
0xfc05c000 0x00000070 /* NFC HSMC regs */
0x00100000 0x00100000 /* NFC SRAM banks */
>;
@@ -847,6 +850,24 @@
clock-names = "mci_clk";
};
+ uart0: serial@f8004000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8004000 0x100>;
+ interrupts = <27 IRQ_TYPE_LEVEL_HIGH 5>;
+ dmas = <&dma1
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(22))>,
+ <&dma1
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(23))>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart0>;
+ clocks = <&uart0_clk>;
+ clock-names = "usart";
+ status = "disabled";
+ };
+
ssc0: ssc@f8008000 {
compatible = "atmel,at91sam9g45-ssc";
reg = <0xf8008000 0x4000>;
@@ -977,6 +998,42 @@
reg = <0xf8028000 0x60>;
};
+ usart0: serial@f802c000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf802c000 0x100>;
+ interrupts = <6 IRQ_TYPE_LEVEL_HIGH 5>;
+ dmas = <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(36))>,
+ <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(37))>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart0 &pinctrl_usart0_rts &pinctrl_usart0_cts>;
+ clocks = <&usart0_clk>;
+ clock-names = "usart";
+ status = "disabled";
+ };
+
+ usart1: serial@f8030000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8030000 0x100>;
+ interrupts = <7 IRQ_TYPE_LEVEL_HIGH 5>;
+ dmas = <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(38))>,
+ <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(39))>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1 &pinctrl_usart1_rts &pinctrl_usart1_cts>;
+ clocks = <&usart1_clk>;
+ clock-names = "usart";
+ status = "disabled";
+ };
+
mmc1: mmc@fc000000 {
compatible = "atmel,hsmci";
reg = <0xfc000000 0x600>;
@@ -994,6 +1051,24 @@
clock-names = "mci_clk";
};
+ uart1: serial@fc004000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfc004000 0x100>;
+ interrupts = <28 IRQ_TYPE_LEVEL_HIGH 5>;
+ dmas = <&dma1
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(24))>,
+ <&dma1
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(25))>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ clocks = <&uart1_clk>;
+ clock-names = "usart";
+ status = "disabled";
+ };
+
usart2: serial@fc008000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfc008000 0x100>;
@@ -1066,6 +1141,46 @@
status = "disabled";
};
+ spi1: spi@fc018000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xfc018000 0x100>;
+ interrupts = <38 IRQ_TYPE_LEVEL_HIGH 3>;
+ dmas = <&dma1
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(12))>,
+ <&dma1
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(13))>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi1>;
+ clocks = <&spi1_clk>;
+ clock-names = "spi_clk";
+ status = "disabled";
+ };
+
+ spi2: spi@fc01c000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xfc01c000 0x100>;
+ interrupts = <39 IRQ_TYPE_LEVEL_HIGH 3>;
+ dmas = <&dma1
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(14))>,
+ <&dma1
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(15))>;
+ dma-names = "tx", "rx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi2>;
+ clocks = <&spi2_clk>;
+ clock-names = "spi_clk";
+ status = "disabled";
+ };
+
tcb1: timer@fc020000 {
compatible = "atmel,at91sam9x5-tcb";
reg = <0xfc020000 0x100>;
@@ -1125,10 +1240,10 @@
compatible = "atmel,at91sam9g46-aes";
reg = <0xfc044000 0x100>;
interrupts = <12 IRQ_TYPE_LEVEL_HIGH 0>;
- dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1))
- AT91_XDMAC_DT_PERID(41)>,
- <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1))
- AT91_XDMAC_DT_PERID(40)>;
+ dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(41))>,
+ <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(40))>;
dma-names = "tx", "rx";
clocks = <&aes_clk>;
clock-names = "aes_clk";
@@ -1139,10 +1254,10 @@
compatible = "atmel,at91sam9g46-tdes";
reg = <0xfc04c000 0x100>;
interrupts = <14 IRQ_TYPE_LEVEL_HIGH 0>;
- dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1))
- AT91_XDMAC_DT_PERID(42)>,
- <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1))
- AT91_XDMAC_DT_PERID(43)>;
+ dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(42))>,
+ <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(43))>;
dma-names = "tx", "rx";
clocks = <&tdes_clk>;
clock-names = "tdes_clk";
@@ -1153,8 +1268,8 @@
compatible = "atmel,at91sam9g46-sha";
reg = <0xfc050000 0x100>;
interrupts = <15 IRQ_TYPE_LEVEL_HIGH 0>;
- dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1))
- AT91_XDMAC_DT_PERID(44)>;
+ dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(44))>;
dma-names = "tx";
clocks = <&sha_clk>;
clock-names = "sha_clk";
@@ -1232,7 +1347,8 @@
#address-cells = <1>;
#size-cells = <1>;
compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
- ranges = <0xfc06a000 0xfc06a000 0x4000>;
+ ranges = <0xfc068000 0xfc068000 0x100
+ 0xfc06a000 0xfc06a000 0x4000>;
/* WARNING: revisit as pin spec has changed */
atmel,mux-mask = <
/* A B C */
@@ -1623,6 +1739,74 @@
};
};
+ spi1 {
+ pinctrl_spi1: spi1-0 {
+ atmel,pins =
+ <AT91_PIOB 18 AT91_PERIPH_A AT91_PINCTRL_NONE /* SPI1_MISO */
+ AT91_PIOB 19 AT91_PERIPH_A AT91_PINCTRL_NONE /* SPI1_MOSI */
+ AT91_PIOB 20 AT91_PERIPH_A AT91_PINCTRL_NONE /* SPI1_SPCK */
+ >;
+ };
+ };
+
+ spi2 {
+ pinctrl_spi2: spi2-0 {
+ atmel,pins =
+ <AT91_PIOD 11 AT91_PERIPH_B AT91_PINCTRL_NONE /* SPI2_MISO conflicts with RTS0 */
+ AT91_PIOD 13 AT91_PERIPH_B AT91_PINCTRL_NONE /* SPI2_MOSI conflicts with TXD0 */
+ AT91_PIOD 15 AT91_PERIPH_B AT91_PINCTRL_NONE /* SPI2_SPCK conflicts with RTS1 */
+ >;
+ };
+ };
+
+ uart0 {
+ pinctrl_uart0: uart0-0 {
+ atmel,pins =
+ <AT91_PIOE 29 AT91_PERIPH_B AT91_PINCTRL_NONE /* RXD */
+ AT91_PIOE 30 AT91_PERIPH_B AT91_PINCTRL_PULL_UP /* TXD */
+ >;
+ };
+ };
+
+ uart1 {
+ pinctrl_uart1: uart1-0 {
+ atmel,pins =
+ <AT91_PIOC 25 AT91_PERIPH_C AT91_PINCTRL_NONE /* RXD */
+ AT91_PIOC 26 AT91_PERIPH_C AT91_PINCTRL_PULL_UP /* TXD */
+ >;
+ };
+ };
+
+ usart0 {
+ pinctrl_usart0: usart0-0 {
+ atmel,pins =
+ <AT91_PIOD 12 AT91_PERIPH_A AT91_PINCTRL_NONE /* RXD */
+ AT91_PIOD 13 AT91_PERIPH_A AT91_PINCTRL_PULL_UP /* TXD */
+ >;
+ };
+ pinctrl_usart0_rts: usart0_rts-0 {
+ atmel,pins = <AT91_PIOD 11 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+ pinctrl_usart0_cts: usart0_cts-0 {
+ atmel,pins = <AT91_PIOD 10 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+ };
+
+ usart1 {
+ pinctrl_usart1: usart1-0 {
+ atmel,pins =
+ <AT91_PIOD 16 AT91_PERIPH_A AT91_PINCTRL_NONE /* RXD */
+ AT91_PIOD 17 AT91_PERIPH_A AT91_PINCTRL_PULL_UP /* TXD */
+ >;
+ };
+ pinctrl_usart1_rts: usart1_rts-0 {
+ atmel,pins = <AT91_PIOD 15 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+ pinctrl_usart1_cts: usart1_cts-0 {
+ atmel,pins = <AT91_PIOD 14 AT91_PERIPH_A AT91_PINCTRL_NONE>;
+ };
+ };
+
usart2 {
pinctrl_usart2: usart2-0 {
atmel,pins =
diff --git a/arch/arm/boot/dts/sh73a0-kzm9g.dts b/arch/arm/boot/dts/sh73a0-kzm9g.dts
index 022ba505f573..24b4cd24dceb 100644
--- a/arch/arm/boot/dts/sh73a0-kzm9g.dts
+++ b/arch/arm/boot/dts/sh73a0-kzm9g.dts
@@ -147,6 +147,7 @@
gpios = <&pcf8575 14 GPIO_ACTIVE_LOW>;
linux,code = <KEY_HOME>;
label = "SW1";
+ gpio-key,wakeup;
};
};
diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi
index 45b539ce4d35..11e17c5f26e2 100644
--- a/arch/arm/boot/dts/sh73a0.dtsi
+++ b/arch/arm/boot/dts/sh73a0.dtsi
@@ -90,7 +90,7 @@
status = "disabled";
};
- irqpin0: irqpin@e6900000 {
+ irqpin0: interrupt-controller@e6900000 {
compatible = "renesas,intc-irqpin-sh73a0", "renesas,intc-irqpin";
#interrupt-cells = <2>;
interrupt-controller;
@@ -112,7 +112,7 @@
control-parent;
};
- irqpin1: irqpin@e6900004 {
+ irqpin1: interrupt-controller@e6900004 {
compatible = "renesas,intc-irqpin-sh73a0", "renesas,intc-irqpin";
#interrupt-cells = <2>;
interrupt-controller;
@@ -134,7 +134,7 @@
control-parent;
};
- irqpin2: irqpin@e6900008 {
+ irqpin2: interrupt-controller@e6900008 {
compatible = "renesas,intc-irqpin-sh73a0", "renesas,intc-irqpin";
#interrupt-cells = <2>;
interrupt-controller;
@@ -156,7 +156,7 @@
control-parent;
};
- irqpin3: irqpin@e690000c {
+ irqpin3: interrupt-controller@e690000c {
compatible = "renesas,intc-irqpin-sh73a0", "renesas,intc-irqpin";
#interrupt-cells = <2>;
interrupt-controller;
@@ -376,7 +376,7 @@
status = "disabled";
};
- scifb8: serial@e6c30000 {
+ scifb: serial@e6c30000 {
compatible = "renesas,scifb-sh73a0", "renesas,scifb";
reg = <0xe6c30000 0x100>;
interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
index d9176e606173..80f924deed37 100644
--- a/arch/arm/boot/dts/socfpga.dtsi
+++ b/arch/arm/boot/dts/socfpga.dtsi
@@ -36,6 +36,7 @@
cpus {
#address-cells = <1>;
#size-cells = <0>;
+ enable-method = "altr,socfpga-smp";
cpu@0 {
compatible = "arm,cortex-a9";
@@ -451,6 +452,14 @@
clk-phase = <0 135>;
};
+ sdmmc_clk_divided: sdmmc_clk_divided {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-gate-clk";
+ clocks = <&sdmmc_clk>;
+ clk-gate = <0xa0 8>;
+ fixed-divider = <4>;
+ };
+
nand_x_clk: nand_x_clk {
#clock-cells = <0>;
compatible = "altr,socfpga-gate-clk";
@@ -488,6 +497,8 @@
reset-names = "stmmaceth";
snps,multicast-filter-bins = <256>;
snps,perfect-filter-entries = <128>;
+ tx-fifo-depth = <4096>;
+ rx-fifo-depth = <4096>;
status = "disabled";
};
@@ -504,6 +515,8 @@
reset-names = "stmmaceth";
snps,multicast-filter-bins = <256>;
snps,perfect-filter-entries = <128>;
+ tx-fifo-depth = <4096>;
+ rx-fifo-depth = <4096>;
status = "disabled";
};
@@ -635,7 +648,7 @@
fifo-depth = <0x400>;
#address-cells = <1>;
#size-cells = <0>;
- clocks = <&l4_mp_clk>, <&sdmmc_clk>;
+ clocks = <&l4_mp_clk>, <&sdmmc_clk_divided>;
clock-names = "biu", "ciu";
};
@@ -655,6 +668,11 @@
status = "disabled";
};
+ scu: snoop-control-unit@fffec000 {
+ compatible = "arm,cortex-a9-scu";
+ reg = <0xfffec000 0x100>;
+ };
+
spi1: spi@fff01000 {
compatible = "snps,dw-apb-ssi";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/socfpga_arria10.dtsi b/arch/arm/boot/dts/socfpga_arria10.dtsi
index 8a05c47fd57f..4779b07310df 100644
--- a/arch/arm/boot/dts/socfpga_arria10.dtsi
+++ b/arch/arm/boot/dts/socfpga_arria10.dtsi
@@ -21,21 +21,10 @@
#address-cells = <1>;
#size-cells = <1>;
- aliases {
- ethernet0 = &gmac0;
- ethernet1 = &gmac1;
- ethernet2 = &gmac2;
- serial0 = &uart0;
- serial1 = &uart1;
- timer0 = &timer0;
- timer1 = &timer1;
- timer2 = &timer2;
- timer3 = &timer3;
- };
-
cpus {
#address-cells = <1>;
#size-cells = <0>;
+ enable-method = "altr,socfpga-a10-smp";
cpu@0 {
compatible = "arm,cortex-a9";
@@ -98,6 +87,21 @@
#address-cells = <1>;
#size-cells = <0>;
+ cb_intosc_hs_div2_clk: cb_intosc_hs_div2_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ };
+
+ cb_intosc_ls_clk: cb_intosc_ls_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ };
+
+ f2s_free_clk: f2s_free_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ };
+
osc1: osc1 {
#clock-cells = <0>;
compatible = "fixed-clock";
@@ -107,47 +111,338 @@
#address-cells = <1>;
#size-cells = <0>;
#clock-cells = <0>;
- compatible = "altr,socfpga-pll-clock";
- clocks = <&osc1>;
+ compatible = "altr,socfpga-a10-pll-clock";
+ clocks = <&osc1>, <&cb_intosc_ls_clk>,
+ <&f2s_free_clk>;
+ reg = <0x40>;
+
+ main_mpu_base_clk: main_mpu_base_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_pll>;
+ div-reg = <0x140 0 11>;
+ };
+
+ main_noc_base_clk: main_noc_base_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_pll>;
+ div-reg = <0x144 0 11>;
+ };
+
+ main_emaca_clk: main_emaca_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_pll>;
+ reg = <0x68>;
+ };
+
+ main_emacb_clk: main_emacb_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_pll>;
+ reg = <0x6C>;
+ };
+
+ main_emac_ptp_clk: main_emac_ptp_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_pll>;
+ reg = <0x70>;
+ };
+
+ main_gpio_db_clk: main_gpio_db_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_pll>;
+ reg = <0x74>;
+ };
+
+ main_sdmmc_clk: main_sdmmc_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk"
+;
+ clocks = <&main_pll>;
+ reg = <0x78>;
+ };
+
+ main_s2f_usr0_clk: main_s2f_usr0_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_pll>;
+ reg = <0x7C>;
+ };
+
+ main_s2f_usr1_clk: main_s2f_usr1_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_pll>;
+ reg = <0x80>;
+ };
+
+ main_hmc_pll_ref_clk: main_hmc_pll_ref_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_pll>;
+ reg = <0x84>;
+ };
+
+ main_periph_ref_clk: main_periph_ref_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_pll>;
+ reg = <0x9C>;
+ };
};
periph_pll: periph_pll {
#address-cells = <1>;
#size-cells = <0>;
#clock-cells = <0>;
- compatible = "altr,socfpga-pll-clock";
- clocks = <&osc1>;
+ compatible = "altr,socfpga-a10-pll-clock";
+ clocks = <&osc1>, <&cb_intosc_ls_clk>,
+ <&f2s_free_clk>, <&main_periph_ref_clk>;
+ reg = <0xC0>;
+
+ peri_mpu_base_clk: peri_mpu_base_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&periph_pll>;
+ div-reg = <0x140 16 11>;
+ };
+
+ peri_noc_base_clk: peri_noc_base_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&periph_pll>;
+ div-reg = <0x144 16 11>;
+ };
+
+ peri_emaca_clk: peri_emaca_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&periph_pll>;
+ reg = <0xE8>;
+ };
+
+ peri_emacb_clk: peri_emacb_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&periph_pll>;
+ reg = <0xEC>;
+ };
+
+ peri_emac_ptp_clk: peri_emac_ptp_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&periph_pll>;
+ reg = <0xF0>;
+ };
+
+ peri_gpio_db_clk: peri_gpio_db_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&periph_pll>;
+ reg = <0xF4>;
+ };
+
+ peri_sdmmc_clk: peri_sdmmc_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&periph_pll>;
+ reg = <0xF8>;
+ };
+
+ peri_s2f_usr0_clk: peri_s2f_usr0_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&periph_pll>;
+ reg = <0xFC>;
+ };
+
+ peri_s2f_usr1_clk: peri_s2f_usr1_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&periph_pll>;
+ reg = <0x100>;
+ };
+
+ peri_hmc_pll_ref_clk: peri_hmc_pll_ref_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&periph_pll>;
+ reg = <0x104>;
+ };
+ };
+
+ mpu_free_clk: mpu_free_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_mpu_base_clk>, <&peri_mpu_base_clk>,
+ <&osc1>, <&cb_intosc_hs_div2_clk>,
+ <&f2s_free_clk>;
+ reg = <0x60>;
+ };
+
+ noc_free_clk: noc_free_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_noc_base_clk>, <&peri_noc_base_clk>,
+ <&osc1>, <&cb_intosc_hs_div2_clk>,
+ <&f2s_free_clk>;
+ reg = <0x64>;
+ };
+
+ s2f_user1_free_clk: s2f_user1_free_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_s2f_usr1_clk>, <&peri_s2f_usr1_clk>,
+ <&osc1>, <&cb_intosc_hs_div2_clk>,
+ <&f2s_free_clk>;
+ reg = <0x104>;
+ };
+
+ sdmmc_free_clk: sdmmc_free_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&main_sdmmc_clk>, <&peri_sdmmc_clk>,
+ <&osc1>, <&cb_intosc_hs_div2_clk>,
+ <&f2s_free_clk>;
+ fixed-divider = <4>;
+ reg = <0xF8>;
+ };
+
+ l4_sys_free_clk: l4_sys_free_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-perip-clk";
+ clocks = <&noc_free_clk>;
+ fixed-divider = <4>;
+ };
+
+ l4_main_clk: l4_main_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-gate-clk";
+ clocks = <&noc_free_clk>;
+ div-reg = <0xA8 0 2>;
+ clk-gate = <0x48 1>;
+ };
+
+ l4_mp_clk: l4_mp_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-gate-clk";
+ clocks = <&noc_free_clk>;
+ div-reg = <0xA8 8 2>;
+ clk-gate = <0x48 2>;
+ };
+
+ l4_sp_clk: l4_sp_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-gate-clk";
+ clocks = <&noc_free_clk>;
+ div-reg = <0xA8 16 2>;
+ clk-gate = <0x48 3>;
+ };
+
+ mpu_periph_clk: mpu_periph_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-gate-clk";
+ clocks = <&mpu_free_clk>;
+ fixed-divider = <4>;
+ clk-gate = <0x48 0>;
+ };
+
+ sdmmc_clk: sdmmc_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-gate-clk";
+ clocks = <&sdmmc_free_clk>;
+ clk-gate = <0xC8 5>;
+ };
+
+ qspi_clk: qspi_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-gate-clk";
+ clocks = <&l4_main_clk>;
+ clk-gate = <0xC8 11>;
+ };
+
+ nand_clk: nand_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-gate-clk";
+ clocks = <&l4_mp_clk>;
+ clk-gate = <0xC8 10>;
+ };
+
+ spi_m_clk: spi_m_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-gate-clk";
+ clocks = <&l4_main_clk>;
+ clk-gate = <0xC8 9>;
+ };
+
+ usb_clk: usb_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-gate-clk";
+ clocks = <&l4_mp_clk>;
+ clk-gate = <0xC8 8>;
+ };
+
+ s2f_usr1_clk: s2f_usr1_clk {
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-a10-gate-clk";
+ clocks = <&peri_s2f_usr1_clk>;
+ clk-gate = <0xC8 6>;
};
};
};
gmac0: ethernet@ff800000 {
compatible = "altr,socfpga-stmmac", "snps,dwmac-3.72a", "snps,dwmac";
+ altr,sysmgr-syscon = <&sysmgr 0x44 0>;
reg = <0xff800000 0x2000>;
interrupts = <0 92 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq";
/* Filled in by bootloader */
mac-address = [00 00 00 00 00 00];
+ snps,multicast-filter-bins = <256>;
+ snps,perfect-filter-entries = <128>;
+ tx-fifo-depth = <4096>;
+ rx-fifo-depth = <16384>;
+ clocks = <&l4_mp_clk>;
+ clock-names = "stmmaceth";
status = "disabled";
};
gmac1: ethernet@ff802000 {
compatible = "altr,socfpga-stmmac", "snps,dwmac-3.72a", "snps,dwmac";
+ altr,sysmgr-syscon = <&sysmgr 0x48 0>;
reg = <0xff802000 0x2000>;
interrupts = <0 93 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq";
/* Filled in by bootloader */
mac-address = [00 00 00 00 00 00];
+ snps,multicast-filter-bins = <256>;
+ snps,perfect-filter-entries = <128>;
+ tx-fifo-depth = <4096>;
+ rx-fifo-depth = <16384>;
+ clocks = <&l4_mp_clk>;
+ clock-names = "stmmaceth";
status = "disabled";
};
gmac2: ethernet@ff804000 {
compatible = "altr,socfpga-stmmac", "snps,dwmac-3.72a", "snps,dwmac";
+ altr,sysmgr-syscon = <&sysmgr 0x4C 0>;
reg = <0xff804000 0x2000>;
interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq";
/* Filled in by bootloader */
mac-address = [00 00 00 00 00 00];
+ snps,multicast-filter-bins = <256>;
+ snps,perfect-filter-entries = <128>;
+ tx-fifo-depth = <4096>;
+ rx-fifo-depth = <16384>;
+ clocks = <&l4_mp_clk>;
+ clock-names = "stmmaceth";
status = "disabled";
};
@@ -253,6 +548,17 @@
status = "disabled";
};
+ sdr: sdr@ffc25000 {
+ compatible = "syscon";
+ reg = <0xffcfb100 0x80>;
+ };
+
+ sdramedac {
+ compatible = "altr,sdram-edac-a10";
+ altr,sdr-syscon = <&sdr>;
+ interrupts = <0 2 4>, <0 0 4>;
+ };
+
L2: l2-cache@fffff000 {
compatible = "arm,pl310-cache";
reg = <0xfffff000 0x1000>;
@@ -268,6 +574,9 @@
reg = <0xff808000 0x1000>;
interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>;
fifo-depth = <0x400>;
+ clocks = <&l4_mp_clk>, <&sdmmc_free_clk>;
+ clock-names = "biu", "ciu";
+ status = "disabled";
};
ocram: sram@ffe00000 {
@@ -281,9 +590,15 @@
reg = <0xffd05000 0x100>;
};
+ scu: snoop-control-unit@ffffc000 {
+ compatible = "arm,cortex-a9-scu";
+ reg = <0xffffc000 0x100>;
+ };
+
sysmgr: sysmgr@ffd06000 {
compatible = "altr,sys-mgr", "syscon";
reg = <0xffd06000 0x300>;
+ cpu1-start-addr = <0xffd06230>;
};
/* Local timer */
@@ -291,30 +606,39 @@
compatible = "arm,cortex-a9-twd-timer";
reg = <0xffffc600 0x100>;
interrupts = <1 13 0xf04>;
+ clocks = <&mpu_periph_clk>;
};
timer0: timer0@ffc02700 {
compatible = "snps,dw-apb-timer";
interrupts = <0 115 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xffc02700 0x100>;
+ clocks = <&l4_sp_clk>;
+ clock-names = "timer";
};
timer1: timer1@ffc02800 {
compatible = "snps,dw-apb-timer";
interrupts = <0 116 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xffc02800 0x100>;
+ clocks = <&l4_sp_clk>;
+ clock-names = "timer";
};
timer2: timer2@ffd00000 {
compatible = "snps,dw-apb-timer";
interrupts = <0 117 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xffd00000 0x100>;
+ clocks = <&l4_sys_free_clk>;
+ clock-names = "timer";
};
timer3: timer3@ffd00100 {
compatible = "snps,dw-apb-timer";
interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xffd01000 0x100>;
+ clocks = <&l4_sys_free_clk>;
+ clock-names = "timer";
};
uart0: serial0@ffc02000 {
@@ -323,6 +647,7 @@
interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
+ status = "disabled";
};
uart1: serial1@ffc02100 {
@@ -331,6 +656,8 @@
interrupts = <0 111 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
+ clocks = <&l4_sp_clk>;
+ status = "disabled";
};
usbphy0: usbphy@0 {
@@ -343,6 +670,8 @@
compatible = "snps,dwc2";
reg = <0xffb00000 0xffff>;
interrupts = <0 95 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_clk>;
+ clock-names = "otg";
phys = <&usbphy0>;
phy-names = "usb2-phy";
status = "disabled";
@@ -361,6 +690,7 @@
compatible = "snps,dw-wdt";
reg = <0xffd00200 0x100>;
interrupts = <0 119 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&l4_sys_free_clk>;
status = "disabled";
};
@@ -368,6 +698,7 @@
compatible = "snps,dw-wdt";
reg = <0xffd00300 0x100>;
interrupts = <0 120 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&l4_sys_free_clk>;
status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk.dts b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi
index 3015ce8d3057..94a0709b2fe6 100755..100644
--- a/arch/arm/boot/dts/socfpga_arria10_socdk.dts
+++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Altera Corporation <www.altera.com>
+ * Copyright (C) 2015 Altera Corporation <www.altera.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
@@ -14,8 +14,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
-/dts-v1/;
#include "socfpga_arria10.dtsi"
/ {
@@ -40,9 +38,37 @@
};
};
};
-
- serial0@ffc02000 {
- status = "okay";
- };
};
};
+
+&gmac0 {
+ phy-mode = "rgmii";
+ phy-addr = <0xffffffff>; /* probe for phy addr */
+
+ /*
+ * These skews assume the user's FPGA design is adding 600ps of delay
+ * for TX_CLK on Arria 10.
+ *
+ * All skews are offset since hardware skew values for the ksz9031
+ * range from a negative skew to a positive skew.
+ * See the micrel-ksz90x1.txt Documentation file for details.
+ */
+ txd0-skew-ps = <0>; /* -420ps */
+ txd1-skew-ps = <0>; /* -420ps */
+ txd2-skew-ps = <0>; /* -420ps */
+ txd3-skew-ps = <0>; /* -420ps */
+ rxd0-skew-ps = <420>; /* 0ps */
+ rxd1-skew-ps = <420>; /* 0ps */
+ rxd2-skew-ps = <420>; /* 0ps */
+ rxd3-skew-ps = <420>; /* 0ps */
+ txen-skew-ps = <0>; /* -420ps */
+ txc-skew-ps = <1860>; /* 960ps */
+ rxdv-skew-ps = <420>; /* 0ps */
+ rxc-skew-ps = <1680>; /* 780ps */
+ max-frame-size = <3800>;
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
diff --git a/include/linux/platform_data/irq-renesas-irqc.h b/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts
index 3ae17b3e00ed..dbbb751ac1ba 100644
--- a/include/linux/platform_data/irq-renesas-irqc.h
+++ b/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts
@@ -1,11 +1,10 @@
/*
- * Renesas IRQC Driver
- *
- * Copyright (C) 2013 Magnus Damm
+ * Copyright (C) 2014-2015 Altera Corporation <www.altera.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
+ * 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
@@ -13,15 +12,15 @@
* 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __IRQ_RENESAS_IRQC_H__
-#define __IRQ_RENESAS_IRQC_H__
+/dts-v1/;
+#include "socfpga_arria10_socdk.dtsi"
-struct renesas_irqc_config {
- unsigned int irq_base;
+&mmc {
+ status = "okay";
+ num-slots = <1>;
+ broken-cd;
+ bus-width = <4>;
};
-
-#endif /* __IRQ_RENESAS_IRQC_H__ */
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
index 16ea6f5f2ab8..71468a7eb28f 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
@@ -68,3 +68,19 @@
&usb1 {
status = "okay";
};
+
+&gpio2 {
+ status = "okay";
+};
+
+&i2c1{
+ status = "okay";
+
+ accel1: accel1@53{
+ compatible = "adxl34x";
+ reg = <0x53>;
+
+ interrupt-parent = < &portc >;
+ interrupts = <3 2>;
+ };
+};
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts b/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts
index a1814b457450..019dd2fea208 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts
@@ -30,12 +30,23 @@
device_type = "memory";
reg = <0x0 0x40000000>; /* 1GB */
};
+
+ leds: gpio-leds {
+ };
};
&gmac1 {
status = "okay";
};
+&gpio0 {
+ status = "okay";
+};
+
+&gpio1 {
+ status = "okay";
+};
+
&i2c0 {
status = "okay";
@@ -45,6 +56,26 @@
};
};
+&leds {
+ compatible = "gpio-leds";
+
+ led@0 {
+ label = "led:green:heartbeat";
+ gpios = <&porta 28 1>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ led@1 {
+ label = "led:green:D7";
+ gpios = <&portb 19 1>;
+ };
+
+ led@2 {
+ label = "led:green:D8";
+ gpios = <&portb 25 1>;
+ };
+};
+
&mmc {
status = "okay";
};
diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi
index 2201cd5da3bb..853684ad7773 100644
--- a/arch/arm/boot/dts/ste-dbx5x0.dtsi
+++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi
@@ -22,6 +22,160 @@
interrupt-parent = <&intc>;
ranges;
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&CPU0>;
+ };
+ core1 {
+ cpu = <&CPU1>;
+ };
+ };
+ };
+ CPU0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ };
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <1>;
+ };
+ };
+
+ ptm@801ae000 {
+ compatible = "arm,coresight-etm3x", "arm,primecell";
+ reg = <0x801ae000 0x1000>;
+
+ clocks = <&prcmu_clk PRCMU_APETRACECLK>, <&prcmu_clk PRCMU_APEATCLK>;
+ clock-names = "apb_pclk", "atclk";
+ cpu = <&CPU0>;
+ port {
+ ptm0_out_port: endpoint {
+ remote-endpoint = <&funnel_in_port0>;
+ };
+ };
+ };
+
+ ptm@801af000 {
+ compatible = "arm,coresight-etm3x", "arm,primecell";
+ reg = <0x801af000 0x1000>;
+
+ clocks = <&prcmu_clk PRCMU_APETRACECLK>, <&prcmu_clk PRCMU_APEATCLK>;
+ clock-names = "apb_pclk", "atclk";
+ cpu = <&CPU1>;
+ port {
+ ptm1_out_port: endpoint {
+ remote-endpoint = <&funnel_in_port1>;
+ };
+ };
+ };
+
+ funnel@801a6000 {
+ compatible = "arm,coresight-funnel", "arm,primecell";
+ reg = <0x801a6000 0x1000>;
+
+ clocks = <&prcmu_clk PRCMU_APETRACECLK>, <&prcmu_clk PRCMU_APEATCLK>;
+ clock-names = "apb_pclk", "atclk";
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* funnel output ports */
+ port@0 {
+ reg = <0>;
+ funnel_out_port: endpoint {
+ remote-endpoint =
+ <&replicator_in_port0>;
+ };
+ };
+
+ /* funnel input ports */
+ port@1 {
+ reg = <0>;
+ funnel_in_port0: endpoint {
+ slave-mode;
+ remote-endpoint = <&ptm0_out_port>;
+ };
+ };
+
+ port@2 {
+ reg = <1>;
+ funnel_in_port1: endpoint {
+ slave-mode;
+ remote-endpoint = <&ptm1_out_port>;
+ };
+ };
+ };
+ };
+
+ replicator {
+ compatible = "arm,coresight-replicator";
+ clocks = <&prcmu_clk PRCMU_APEATCLK>;
+ clock-names = "atclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* replicator output ports */
+ port@0 {
+ reg = <0>;
+ replicator_out_port0: endpoint {
+ remote-endpoint = <&tpiu_in_port>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ replicator_out_port1: endpoint {
+ remote-endpoint = <&etb_in_port>;
+ };
+ };
+
+ /* replicator input port */
+ port@2 {
+ reg = <0>;
+ replicator_in_port0: endpoint {
+ slave-mode;
+ remote-endpoint = <&funnel_out_port>;
+ };
+ };
+ };
+ };
+
+ tpiu@80190000 {
+ compatible = "arm,coresight-tpiu", "arm,primecell";
+ reg = <0x80190000 0x1000>;
+
+ clocks = <&prcmu_clk PRCMU_APETRACECLK>, <&prcmu_clk PRCMU_APEATCLK>;
+ clock-names = "apb_pclk", "atclk";
+ port {
+ tpiu_in_port: endpoint {
+ slave-mode;
+ remote-endpoint = <&replicator_out_port0>;
+ };
+ };
+ };
+
+ etb@801a4000 {
+ compatible = "arm,coresight-etb10", "arm,primecell";
+ reg = <0x801a4000 0x1000>;
+
+ clocks = <&prcmu_clk PRCMU_APETRACECLK>, <&prcmu_clk PRCMU_APEATCLK>;
+ clock-names = "apb_pclk", "atclk";
+ port {
+ etb_in_port: endpoint {
+ slave-mode;
+ remote-endpoint = <&replicator_out_port1>;
+ };
+ };
+ };
+
intc: interrupt-controller@a0411000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
@@ -31,6 +185,20 @@
<0xa0410100 0x100>;
};
+ scu@a04100000 {
+ compatible = "arm,cortex-a9-scu";
+ reg = <0xa0410000 0x100>;
+ };
+
+ /*
+ * The backup RAM is used for retention during sleep
+ * and various things like spin tables
+ */
+ backupram@80150000 {
+ compatible = "ste,dbx500-backupram";
+ reg = <0x80150000 0x2000>;
+ };
+
L2: l2-cache {
compatible = "arm,pl310-cache";
reg = <0xa0412000 0x1000>;
@@ -91,6 +259,13 @@
clocks = <&smp_twd_clk>;
};
+ watchdog@a0410620 {
+ compatible = "arm,cortex-a9-twd-wdt";
+ reg = <0xa0410620 0x20>;
+ interrupts = <1 14 0x304>;
+ clocks = <&smp_twd_clk>;
+ };
+
rtc@80154000 {
compatible = "arm,rtc-pl031", "arm,primecell";
reg = <0x80154000 0x1000>;
diff --git a/arch/arm/boot/dts/ste-href-stuib.dtsi b/arch/arm/boot/dts/ste-href-stuib.dtsi
index 7d4f8184c522..78b75256c638 100644
--- a/arch/arm/boot/dts/ste-href-stuib.dtsi
+++ b/arch/arm/boot/dts/ste-href-stuib.dtsi
@@ -77,6 +77,34 @@
};
};
+ /* Sensors mounted on this board variant */
+ i2c@80128000 {
+ 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_stuib_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_stuib_mode>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <0 IRQ_TYPE_EDGE_RISING>;
+ };
+ };
+
i2c@80110000 {
bu21013_tp@5c {
compatible = "rohm,bu21013_tp";
@@ -116,6 +144,28 @@
};
};
};
+ accelerometer {
+ accel_stuib_mode: accel_stuib {
+ /* Accelerometer interrupt lines 1 & 2 */
+ stuib_cfg {
+ pins = "GPIO82_C1", "GPIO83_D3";
+ ste,config = <&gpio_in_pu>;
+ };
+ };
+ };
+ magnetometer {
+ magneto_stuib_mode: magneto_stuib {
+ /* Magnetometer uses GPIO 31 and 32, pull these up/down respectively */
+ stuib_cfg1 {
+ pins = "GPIO31_V3";
+ ste,config = <&gpio_in_pu>;
+ };
+ stuib_cfg2 {
+ pins = "GPIO32_V2";
+ ste,config = <&gpio_in_pd>;
+ };
+ };
+ };
};
};
};
diff --git a/arch/arm/boot/dts/ste-href-tvk1281618.dtsi b/arch/arm/boot/dts/ste-href-tvk1281618.dtsi
index 062c6aae3afa..0e1c96943d47 100644
--- a/arch/arm/boot/dts/ste-href-tvk1281618.dtsi
+++ b/arch/arm/boot/dts/ste-href-tvk1281618.dtsi
@@ -99,10 +99,13 @@
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>;
};
- lsm303dlm@1e {
+ lsm303dlh@1e {
/* Magnetometer */
- compatible = "st,lsm303dlm-magn";
+ compatible = "st,lsm303dlh-magn";
reg = <0x1e>;
vdd-supply = <&ab8500_ldo_aux1_reg>;
vddio-supply = <&db8500_vsmps2_reg>;
diff --git a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
index f182f6538e90..9a5f2ba139b7 100644
--- a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
+++ b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
@@ -722,8 +722,9 @@
reg = <0x1a>;
};
lis3lv02dl@1d {
- compatible = "st,lis3lv02dl";
- reg = <0x1d>;
+ /* Accelerometer */
+ compatible = "st,lis3lv02dl-accel";
+ reg = <0x1d>;
};
};
diff --git a/arch/arm/boot/dts/ste-snowball.dts b/arch/arm/boot/dts/ste-snowball.dts
index 1bc84ebdccaa..9edadc37719f 100644
--- a/arch/arm/boot/dts/ste-snowball.dts
+++ b/arch/arm/boot/dts/ste-snowball.dts
@@ -262,15 +262,19 @@
vddio-supply = <&db8500_vsmps2_reg>;
pinctrl-names = "default";
pinctrl-0 = <&accel_snowball_mode>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <3 IRQ_TYPE_EDGE_RISING>, /* INT1 */
+ <4 IRQ_TYPE_EDGE_RISING>; /* INT2 */
};
- lsm303dlm@1e {
+ lsm303dlh@1e {
/* Magnetometer */
- compatible = "st,lsm303dlm-magn";
+ compatible = "st,lsm303dlh-magn";
reg = <0x1e>;
vdd-supply = <&ab8500_ldo_aux1_reg>;
vddio-supply = <&db8500_vsmps2_reg>;
pinctrl-names = "default";
pinctrl-0 = <&magneto_snowball_mode>;
+ gpios = <&gpio5 5 0x4>; /* DRDY line */
};
l3g4200d@68 {
/* Gyroscope */
@@ -279,6 +283,11 @@
reg = <0x68>;
vdd-supply = <&ab8500_ldo_aux1_reg>;
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 */
};
lsp001wm@5c {
/* Barometer/pressure sensor */
@@ -489,6 +498,16 @@
};
};
};
+ gyro {
+ gyro_snowball_mode: gyro_snowball {
+ snowball_cfg1 {
+ pins =
+ "GPIO166_A22", /* DRDY */
+ "GPIO169_D22"; /* INT */
+ ste,config = <&gpio_in_pu>;
+ };
+ };
+ };
magnetometer {
magneto_snowball_mode: magneto_snowball {
snowball_cfg1 {
diff --git a/arch/arm/boot/dts/stih407-b2120.dts b/arch/arm/boot/dts/stih407-b2120.dts
index af487145cd89..6d93475be554 100644
--- a/arch/arm/boot/dts/stih407-b2120.dts
+++ b/arch/arm/boot/dts/stih407-b2120.dts
@@ -7,8 +7,8 @@
* published by the Free Software Foundation.
*/
/dts-v1/;
-#include "stihxxx-b2120.dtsi"
#include "stih407.dtsi"
+#include "stihxxx-b2120.dtsi"
/ {
model = "STiH407 B2120";
compatible = "st,stih407-b2120", "st,stih407";
diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi
index c06a54681912..838b812cbda1 100644
--- a/arch/arm/boot/dts/stih407-family.dtsi
+++ b/arch/arm/boot/dts/stih407-family.dtsi
@@ -7,7 +7,10 @@
* publishhed by the Free Software Foundation.
*/
#include "stih407-pinctrl.dtsi"
+#include <dt-bindings/mfd/st-lpc.h>
+#include <dt-bindings/phy/phy.h>
#include <dt-bindings/reset-controller/stih407-resets.h>
+#include <dt-bindings/interrupt-controller/irq-st.h>
/ {
#address-cells = <1>;
#size-cells = <1>;
@@ -56,6 +59,12 @@
cache-level = <2>;
};
+ arm-pmu {
+ interrupt-parent = <&intc>;
+ compatible = "arm,cortex-a9-pmu";
+ interrupts = <GIC_PPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -63,6 +72,12 @@
ranges;
compatible = "simple-bus";
+ restart {
+ compatible = "st,stih407-restart";
+ st,syscfg = <&syscfg_sbc_reg>;
+ status = "okay";
+ };
+
powerdown: powerdown-controller {
compatible = "st,stih407-powerdown";
#reset-cells = <1>;
@@ -113,6 +128,15 @@
reg = <0x94b5100 0x1000>;
};
+ irq-syscfg {
+ compatible = "st,stih407-irq-syscfg";
+ st,syscfg = <&syscfg_core>;
+ st,irq-device = <ST_IRQ_SYSCFG_PMU_0>,
+ <ST_IRQ_SYSCFG_PMU_1>;
+ st,fiq-device = <ST_IRQ_SYSCFG_DISABLED>,
+ <ST_IRQ_SYSCFG_DISABLED>;
+ };
+
serial@9830000 {
compatible = "st,asc";
reg = <0x9830000 0x2c>;
@@ -280,7 +304,7 @@
#phy-cells = <0>;
st,syscfg = <&syscfg_core 0x100 0xf4>;
resets = <&softreset STIH407_PICOPHY_SOFTRESET>,
- <&picophyreset STIH407_PICOPHY0_RESET>;
+ <&picophyreset STIH407_PICOPHY2_RESET>;
reset-names = "global", "port";
};
@@ -336,5 +360,210 @@
resets = <&softreset STIH407_MIPHY2_SOFTRESET>;
};
};
+
+ spi@9840000 {
+ compatible = "st,comms-ssc4-spi";
+ reg = <0x9840000 0x110>;
+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
+ clock-names = "ssc";
+ pinctrl-0 = <&pinctrl_spi0_default>;
+ pinctrl-names = "default";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "disabled";
+ };
+
+ spi@9841000 {
+ compatible = "st,comms-ssc4-spi";
+ reg = <0x9841000 0x110>;
+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
+ clock-names = "ssc";
+
+ status = "disabled";
+ };
+
+ spi@9842000 {
+ compatible = "st,comms-ssc4-spi";
+ reg = <0x9842000 0x110>;
+ interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
+ clock-names = "ssc";
+
+ status = "disabled";
+ };
+
+ spi@9843000 {
+ compatible = "st,comms-ssc4-spi";
+ reg = <0x9843000 0x110>;
+ interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
+ clock-names = "ssc";
+
+ status = "disabled";
+ };
+
+ spi@9844000 {
+ compatible = "st,comms-ssc4-spi";
+ reg = <0x9844000 0x110>;
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
+ clock-names = "ssc";
+
+ status = "disabled";
+ };
+
+ /* SBC SSC */
+ spi@9540000 {
+ compatible = "st,comms-ssc4-spi";
+ reg = <0x9540000 0x110>;
+ interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk_sysin>;
+ clock-names = "ssc";
+
+ status = "disabled";
+ };
+
+ spi@9541000 {
+ compatible = "st,comms-ssc4-spi";
+ reg = <0x9541000 0x110>;
+ interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk_sysin>;
+ clock-names = "ssc";
+
+ status = "disabled";
+ };
+
+ spi@9542000 {
+ compatible = "st,comms-ssc4-spi";
+ reg = <0x9542000 0x110>;
+ interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk_sysin>;
+ clock-names = "ssc";
+
+ status = "disabled";
+ };
+
+ mmc0: sdhci@09060000 {
+ compatible = "st,sdhci-stih407", "st,sdhci";
+ status = "disabled";
+ reg = <0x09060000 0x7ff>, <0x9061008 0x20>;
+ reg-names = "mmc", "top-mmc-delay";
+ interrupts = <GIC_SPI 92 IRQ_TYPE_NONE>;
+ interrupt-names = "mmcirq";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mmc0>;
+ clock-names = "mmc";
+ clocks = <&clk_s_c0_flexgen CLK_MMC_0>;
+ bus-width = <8>;
+ non-removable;
+ };
+
+ mmc1: sdhci@09080000 {
+ compatible = "st,sdhci-stih407", "st,sdhci";
+ status = "disabled";
+ reg = <0x09080000 0x7ff>;
+ reg-names = "mmc";
+ interrupts = <GIC_SPI 90 IRQ_TYPE_NONE>;
+ interrupt-names = "mmcirq";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sd1>;
+ clock-names = "mmc";
+ clocks = <&clk_s_c0_flexgen CLK_MMC_1>;
+ resets = <&softreset STIH407_MMC1_SOFTRESET>;
+ bus-width = <4>;
+ };
+
+ /* Watchdog and Real-Time Clock */
+ lpc@8787000 {
+ compatible = "st,stih407-lpc";
+ reg = <0x8787000 0x1000>;
+ interrupts = <GIC_SPI 129 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clk_s_d3_flexgen CLK_LPC_0>;
+ timeout-sec = <120>;
+ st,syscfg = <&syscfg_core>;
+ st,lpc-mode = <ST_LPC_MODE_WDT>;
+ };
+
+ lpc@8788000 {
+ compatible = "st,stih407-lpc";
+ reg = <0x8788000 0x1000>;
+ interrupts = <GIC_SPI 130 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clk_s_d3_flexgen CLK_LPC_1>;
+ st,lpc-mode = <ST_LPC_MODE_RTC>;
+ };
+
+ sata0: sata@9b20000 {
+ compatible = "st,ahci";
+ reg = <0x9b20000 0x1000>;
+
+ interrupts = <GIC_SPI 159 IRQ_TYPE_NONE>;
+ interrupt-names = "hostc";
+
+ phys = <&phy_port0 PHY_TYPE_SATA>;
+ phy-names = "ahci_phy";
+
+ resets = <&powerdown STIH407_SATA0_POWERDOWN>,
+ <&softreset STIH407_SATA0_SOFTRESET>,
+ <&softreset STIH407_SATA0_PWR_SOFTRESET>;
+ reset-names = "pwr-dwn", "sw-rst", "pwr-rst";
+
+ clock-names = "ahci_clk";
+ clocks = <&clk_s_c0_flexgen CLK_ICN_REG>;
+
+ status = "disabled";
+ };
+
+ sata1: sata@9b28000 {
+ compatible = "st,ahci";
+ reg = <0x9b28000 0x1000>;
+
+ interrupts = <GIC_SPI 170 IRQ_TYPE_NONE>;
+ interrupt-names = "hostc";
+
+ phys = <&phy_port1 PHY_TYPE_SATA>;
+ phy-names = "ahci_phy";
+
+ resets = <&powerdown STIH407_SATA1_POWERDOWN>,
+ <&softreset STIH407_SATA1_SOFTRESET>,
+ <&softreset STIH407_SATA1_PWR_SOFTRESET>;
+ reset-names = "pwr-dwn",
+ "sw-rst",
+ "pwr-rst";
+
+ clock-names = "ahci_clk";
+ clocks = <&clk_s_c0_flexgen CLK_ICN_REG>;
+
+ status = "disabled";
+ };
+
+ st_dwc3: dwc3@8f94000 {
+ compatible = "st,stih407-dwc3";
+ reg = <0x08f94000 0x1000>, <0x110 0x4>;
+ reg-names = "reg-glue", "syscfg-reg";
+ st,syscfg = <&syscfg_core>;
+ resets = <&powerdown STIH407_USB3_POWERDOWN>,
+ <&softreset STIH407_MIPHY2_SOFTRESET>;
+ reset-names = "powerdown", "softreset";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb3>;
+ ranges;
+
+ status = "disabled";
+
+ dwc3: dwc3@9900000 {
+ compatible = "snps,dwc3";
+ reg = <0x09900000 0x100000>;
+ interrupts = <GIC_SPI 155 IRQ_TYPE_NONE>;
+ dr_mode = "host";
+ phy-names = "usb2-phy", "usb3-phy";
+ phys = <&usb2_picophy0>,
+ <&phy_port2 PHY_TYPE_USB3>;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/stih407-pinctrl.dtsi b/arch/arm/boot/dts/stih407-pinctrl.dtsi
index 402844cb3152..0a754f275212 100644
--- a/arch/arm/boot/dts/stih407-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stih407-pinctrl.dtsi
@@ -104,6 +104,7 @@
#interrupt-cells = <2>;
reg = <0x5000 0x100>;
st,bank-name = "PIO5";
+ st,retime-pin-mask = <0x3f>;
};
rc {
@@ -519,6 +520,7 @@
#interrupt-cells = <2>;
reg = <0x5000 0x100>;
st,bank-name = "PIO35";
+ st,retime-pin-mask = <0x7f>;
};
i2c4 {
diff --git a/arch/arm/boot/dts/stih407.dtsi b/arch/arm/boot/dts/stih407.dtsi
index 3efa3b2ebe90..2c560fc30503 100644
--- a/arch/arm/boot/dts/stih407.dtsi
+++ b/arch/arm/boot/dts/stih407.dtsi
@@ -147,5 +147,33 @@
};
};
};
+
+ /* COMMS PWM Module */
+ pwm0: pwm@9810000 {
+ compatible = "st,sti-pwm";
+ status = "disabled";
+ #pwm-cells = <2>;
+ reg = <0x9810000 0x68>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm0_chan0_default>;
+ clock-names = "pwm";
+ clocks = <&clk_sysin>;
+ };
+
+ /* SBC PWM Module */
+ pwm1: pwm@9510000 {
+ compatible = "st,sti-pwm";
+ status = "disabled";
+ #pwm-cells = <2>;
+ reg = <0x9510000 0x68>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm1_chan0_default
+ &pinctrl_pwm1_chan1_default
+ &pinctrl_pwm1_chan2_default
+ &pinctrl_pwm1_chan3_default>;
+ clock-names = "pwm";
+ clocks = <&clk_sysin>;
+ st,pwm-num-chan = <4>;
+ };
};
};
diff --git a/arch/arm/boot/dts/stih410-b2120.dts b/arch/arm/boot/dts/stih410-b2120.dts
index 2f61a9960dee..16f02c5e33a4 100644
--- a/arch/arm/boot/dts/stih410-b2120.dts
+++ b/arch/arm/boot/dts/stih410-b2120.dts
@@ -26,4 +26,14 @@
aliases {
ttyAS0 = &sbc_serial0;
};
+
+ soc {
+
+ mmc0: sdhci@09060000 {
+ max-frequency = <200000000>;
+ sd-uhs-sdr50;
+ sd-uhs-sdr104;
+ sd-uhs-ddr50;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/stih416-b2020e.dts b/arch/arm/boot/dts/stih416-b2020e.dts
index 961799e1dc51..f1ceee192a0e 100644
--- a/arch/arm/boot/dts/stih416-b2020e.dts
+++ b/arch/arm/boot/dts/stih416-b2020e.dts
@@ -51,5 +51,15 @@
sata0: sata@fe380000{
status = "okay";
};
+
+ /* SAS PWM Module */
+ pwm0: pwm@fed10000 {
+ status = "okay";
+ };
+
+ /* SBC PWM Module */
+ pwm1: pwm@fe510000 {
+ status = "okay";
+ };
};
};
diff --git a/arch/arm/boot/dts/stih416-pinctrl.dtsi b/arch/arm/boot/dts/stih416-pinctrl.dtsi
index 9cccf2d6aa26..051fc16f3706 100644
--- a/arch/arm/boot/dts/stih416-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stih416-pinctrl.dtsi
@@ -216,6 +216,29 @@
};
};
};
+
+ pwm1 {
+ pinctrl_pwm1_chan0_default: pwm1-0-default {
+ st,pins {
+ pwm-out = <&pio3 0 ALT1 OUT>;
+ };
+ };
+ pinctrl_pwm1_chan1_default: pwm1-1-default {
+ st,pins {
+ pwm-out = <&pio4 4 ALT1 OUT>;
+ };
+ };
+ pinctrl_pwm1_chan2_default: pwm1-2-default {
+ st,pins {
+ pwm-out = <&pio4 6 ALT3 OUT>;
+ };
+ };
+ pinctrl_pwm1_chan3_default: pwm1-3-default {
+ st,pins {
+ pwm-out = <&pio4 7 ALT3 OUT>;
+ };
+ };
+ };
};
pin-controller-front {
@@ -310,6 +333,14 @@
st,bank-name = "PIO31";
};
+ pwm0 {
+ pinctrl_pwm0_chan0_default: pwm0-0-default {
+ st,pins {
+ pwm-out = <&pio9 7 ALT2 OUT>;
+ };
+ };
+ };
+
serial2-oe {
pinctrl_serial2_oe: serial2-1 {
st,pins {
@@ -540,6 +571,25 @@
};
};
};
+
+ pwm0 {
+ pinctrl_pwm0_chan1_default: pwm0-1-default {
+ st,pins {
+ pwm-out = <&pio13 2 ALT2 OUT>;
+ };
+ };
+ pinctrl_pwm0_chan2_default: pwm0-2-default {
+ st,pins {
+ pwm-out = <&pio15 2 ALT4 OUT>;
+ };
+ };
+ pinctrl_pwm0_chan3_default: pwm0-3-default {
+ st,pins {
+ pwm-out = <&pio17 4 ALT1 OUT>;
+ };
+ };
+ };
+
};
pin-controller-fvdp-fe {
diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi
index eeb7afecbbe6..9dca173e694a 100644
--- a/arch/arm/boot/dts/stih416.dtsi
+++ b/arch/arm/boot/dts/stih416.dtsi
@@ -13,6 +13,7 @@
#include <dt-bindings/phy/phy.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/reset-controller/stih416-resets.h>
+#include <dt-bindings/interrupt-controller/irq-st.h>
/ {
L2: cache-controller {
compatible = "arm,pl310-cache";
@@ -23,6 +24,12 @@
cache-level = <2>;
};
+ arm-pmu {
+ compatible = "arm,cortex-a9-pmu";
+ interrupt-parent = <&intc>;
+ interrupts = <GIC_PPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -30,6 +37,12 @@
ranges;
compatible = "simple-bus";
+ restart {
+ compatible = "st,stih416-restart";
+ st,syscfg = <&syscfg_sbc>;
+ status = "okay";
+ };
+
powerdown: powerdown-controller {
#reset-cells = <1>;
compatible = "st,stih416-powerdown";
@@ -86,6 +99,15 @@
reg = <0xfe4b5100 0x8>;
};
+ irq-syscfg {
+ compatible = "st,stih416-irq-syscfg";
+ st,syscfg = <&syscfg_cpu>;
+ st,irq-device = <ST_IRQ_SYSCFG_PMU_0>,
+ <ST_IRQ_SYSCFG_PMU_1>;
+ st,fiq-device = <ST_IRQ_SYSCFG_DISABLED>,
+ <ST_IRQ_SYSCFG_DISABLED>;
+ };
+
serial2: serial@fed32000{
compatible = "st,asc";
status = "disabled";
@@ -104,7 +126,7 @@
interrupts = <0 210 0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sbc_serial1>;
- clocks = <&clk_sysin>;
+ clocks = <&clk_sysin>;
};
i2c@fed40000 {
@@ -445,5 +467,47 @@
<&softreset STIH416_USB3_SOFTRESET>;
reset-names = "power", "softreset";
};
+
+ /* SAS PWM Module */
+ pwm0: pwm@fed10000 {
+ compatible = "st,sti-pwm";
+ status = "disabled";
+ #pwm-cells = <2>;
+ reg = <0xfed10000 0x68>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm0_chan0_default
+ &pinctrl_pwm0_chan1_default
+ &pinctrl_pwm0_chan2_default
+ &pinctrl_pwm0_chan3_default>;
+
+ clock-names = "pwm";
+ clocks = <&clk_sysin>;
+ st,pwm-num-chan = <4>;
+ };
+
+ /* SBC PWM Module */
+ pwm1: pwm@fe510000 {
+ compatible = "st,sti-pwm";
+ status = "disabled";
+ #pwm-cells = <2>;
+ reg = <0xfe510000 0x68>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm1_chan0_default
+ /*
+ * Shared with SBC_OBS_NOTRST. Don't
+ * enable unless you really know what
+ * you're doing.
+ *
+ * &pinctrl_pwm1_chan1_default
+ */
+ &pinctrl_pwm1_chan2_default
+ &pinctrl_pwm1_chan3_default>;
+
+ clock-names = "pwm";
+ clocks = <&clk_sysin>;
+ st,pwm-num-chan = <3>;
+ };
};
};
diff --git a/arch/arm/boot/dts/stih418-b2199.dts b/arch/arm/boot/dts/stih418-b2199.dts
index 926235c08e4d..82eee39ccb31 100644
--- a/arch/arm/boot/dts/stih418-b2199.dts
+++ b/arch/arm/boot/dts/stih418-b2199.dts
@@ -74,5 +74,32 @@
st,i2c-min-scl-pulse-width-us = <0>;
st,i2c-min-sda-pulse-width-us = <5>;
};
+
+ mmc1: sdhci@09080000 {
+ status = "okay";
+ };
+
+ mmc0: sdhci@09060000 {
+ status = "okay";
+ max-frequency = <200000000>;
+ sd-uhs-sdr50;
+ sd-uhs-sdr104;
+ sd-uhs-ddr50;
+ };
+
+ miphy28lp_phy: miphy28lp@9b22000 {
+
+ phy_port0: port@9b22000 {
+ st,osc-rdy;
+ };
+
+ phy_port1: port@9b2a000 {
+ st,osc-force-ext;
+ };
+ };
+
+ st_dwc3: dwc3@8f94000 {
+ status = "okay";
+ };
};
};
diff --git a/arch/arm/boot/dts/stihxxx-b2120.dtsi b/arch/arm/boot/dts/stihxxx-b2120.dtsi
index c1d859092be7..f589fe487f13 100644
--- a/arch/arm/boot/dts/stihxxx-b2120.dtsi
+++ b/arch/arm/boot/dts/stihxxx-b2120.dtsi
@@ -47,6 +47,14 @@
status = "okay";
};
+ mmc0: sdhci@09060000 {
+ status = "okay";
+ };
+
+ mmc1: sdhci@09080000 {
+ status = "okay";
+ };
+
/* SSC11 to HDMI */
hdmiddc: i2c@9541000 {
status = "okay";
@@ -66,5 +74,10 @@
st,osc-force-ext;
};
};
+
+ st_dwc3: dwc3@8f94000 {
+ status = "okay";
+ };
+
};
};
diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts
new file mode 100644
index 000000000000..6b9aa59d978a
--- /dev/null
+++ b/arch/arm/boot/dts/stm32f429-disco.dts
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 - Maxime Coquelin <mcoquelin.stm32@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.
+ *
+ * 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 "stm32f429.dtsi"
+
+/ {
+ model = "STMicroelectronics STM32F429i-DISCO board";
+ compatible = "st,stm32f429i-disco", "st,stm32f429";
+
+ chosen {
+ bootargs = "console=ttyS0,115200 root=/dev/ram rdinit=/linuxrc";
+ linux,stdout-path = &usart1;
+ };
+
+ memory {
+ reg = <0x90000000 0x800000>;
+ };
+
+ aliases {
+ serial0 = &usart1;
+ };
+};
+
+&usart1 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
new file mode 100644
index 000000000000..aa73b4f4172c
--- /dev/null
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2015 - Maxime Coquelin <mcoquelin.stm32@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.
+ *
+ * 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.
+ */
+
+#include "armv7-m.dtsi"
+
+/ {
+ clocks {
+ clk_sysclk: clk-sysclk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <180000000>;
+ };
+
+ clk_hclk: clk-hclk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <180000000>;
+ };
+
+ clk_pclk1: clk-pclk1 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <45000000>;
+ };
+
+ clk_pclk2: clk-pclk2 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <90000000>;
+ };
+
+ clk_pmtr1: clk-pmtr1 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <90000000>;
+ };
+
+ clk_pmtr2: clk-pmtr2 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <180000000>;
+ };
+
+ clk_systick: clk-systick {
+ compatible = "fixed-factor-clock";
+ clocks = <&clk_hclk>;
+ #clock-cells = <0>;
+ clock-div = <8>;
+ clock-mult = <1>;
+ };
+ };
+
+ soc {
+ timer2: timer@40000000 {
+ compatible = "st,stm32-timer";
+ reg = <0x40000000 0x400>;
+ interrupts = <28>;
+ clocks = <&clk_pmtr1>;
+ status = "disabled";
+ };
+
+ timer3: timer@40000400 {
+ compatible = "st,stm32-timer";
+ reg = <0x40000400 0x400>;
+ interrupts = <29>;
+ clocks = <&clk_pmtr1>;
+ status = "disabled";
+ };
+
+ timer4: timer@40000800 {
+ compatible = "st,stm32-timer";
+ reg = <0x40000800 0x400>;
+ interrupts = <30>;
+ clocks = <&clk_pmtr1>;
+ status = "disabled";
+ };
+
+ timer5: timer@40000c00 {
+ compatible = "st,stm32-timer";
+ reg = <0x40000c00 0x400>;
+ interrupts = <50>;
+ clocks = <&clk_pmtr1>;
+ };
+
+ timer6: timer@40001000 {
+ compatible = "st,stm32-timer";
+ reg = <0x40001000 0x400>;
+ interrupts = <54>;
+ clocks = <&clk_pmtr1>;
+ status = "disabled";
+ };
+
+ timer7: timer@40001400 {
+ compatible = "st,stm32-timer";
+ reg = <0x40001400 0x400>;
+ interrupts = <55>;
+ clocks = <&clk_pmtr1>;
+ status = "disabled";
+ };
+
+ usart2: serial@40004400 {
+ compatible = "st,stm32-usart", "st,stm32-uart";
+ reg = <0x40004400 0x400>;
+ interrupts = <38>;
+ clocks = <&clk_pclk1>;
+ status = "disabled";
+ };
+
+ usart3: serial@40004800 {
+ compatible = "st,stm32-usart", "st,stm32-uart";
+ reg = <0x40004800 0x400>;
+ interrupts = <39>;
+ clocks = <&clk_pclk1>;
+ status = "disabled";
+ };
+
+ usart4: serial@40004c00 {
+ compatible = "st,stm32-uart";
+ reg = <0x40004c00 0x400>;
+ interrupts = <52>;
+ clocks = <&clk_pclk1>;
+ status = "disabled";
+ };
+
+ usart5: serial@40005000 {
+ compatible = "st,stm32-uart";
+ reg = <0x40005000 0x400>;
+ interrupts = <53>;
+ clocks = <&clk_pclk1>;
+ status = "disabled";
+ };
+
+ usart7: serial@40007800 {
+ compatible = "st,stm32-usart", "st,stm32-uart";
+ reg = <0x40007800 0x400>;
+ interrupts = <82>;
+ clocks = <&clk_pclk1>;
+ status = "disabled";
+ };
+
+ usart8: serial@40007c00 {
+ compatible = "st,stm32-usart", "st,stm32-uart";
+ reg = <0x40007c00 0x400>;
+ interrupts = <83>;
+ clocks = <&clk_pclk1>;
+ status = "disabled";
+ };
+
+ usart1: serial@40011000 {
+ compatible = "st,stm32-usart", "st,stm32-uart";
+ reg = <0x40011000 0x400>;
+ interrupts = <37>;
+ clocks = <&clk_pclk2>;
+ status = "disabled";
+ };
+
+ usart6: serial@40011400 {
+ compatible = "st,stm32-usart", "st,stm32-uart";
+ reg = <0x40011400 0x400>;
+ interrupts = <71>;
+ clocks = <&clk_pclk2>;
+ status = "disabled";
+ };
+ };
+};
+
+&systick {
+ clocks = <&clk_systick>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
index b67e5be618cf..2630d78d9e04 100644
--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
+++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
@@ -18,11 +18,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 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
@@ -58,101 +53,12 @@
model = "Mele A1000";
compatible = "mele,a1000", "allwinner,sun4i-a10";
- soc@01c00000 {
- emac: ethernet@01c0b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&emac_pins_a>;
- phy = <&phy1>;
- status = "okay";
- };
-
- mdio@01c0b080 {
- phy-supply = <&reg_emac_3v3>;
- status = "okay";
-
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
-
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- ahci: sata@01c18000 {
- status = "okay";
- };
-
- ehci1: usb@01c1c000 {
- status = "okay";
- };
-
- ohci1: usb@01c1c400 {
- status = "okay";
- };
-
- pinctrl@01c20800 {
- emac_power_pin_a1000: emac_power_pin@0 {
- allwinner,pins = "PH15";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- led_pins_a1000: led_pins@0 {
- allwinner,pins = "PH10", "PH20";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- ir0: ir@01c21800 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
- status = "okay";
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupts = <0>;
+ aliases {
+ serial0 = &uart0;
+ };
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
};
leds {
@@ -181,12 +87,111 @@
enable-active-high;
gpio = <&pio 7 15 GPIO_ACTIVE_HIGH>;
};
+};
+
+&ahci {
+ status = "okay";
+};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_pins_a>;
+ phy = <&phy1>;
+ status = "okay";
+};
+
+&emac_sram {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupts = <0>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_pins_a>;
+ status = "okay";
+};
+
+&mdio {
+ phy-supply = <&reg_emac_3v3>;
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ emac_power_pin_a1000: emac_power_pin@0 {
+ allwinner,pins = "PH15";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
+ led_pins_a1000: led_pins@0 {
+ allwinner,pins = "PH10", "PH20";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
+
+&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/sun4i-a10-ba10-tvbox.dts b/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
index 490b77c9bb36..93d435670ef1 100644
--- a/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
+++ b/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
@@ -16,11 +16,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 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
@@ -55,94 +50,104 @@
model = "BA10 tvbox";
compatible = "allwinner,ba10-tvbox", "allwinner,sun4i-a10";
- soc@01c00000 {
- emac: ethernet@01c0b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&emac_pins_a>;
- phy = <&phy1>;
- status = "okay";
- };
-
- mdio@01c0b080 {
- status = "okay";
-
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
-
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- ehci1: usb@01c1c000 {
- status = "okay";
- };
-
- ohci1: usb@01c1c400 {
- status = "okay";
- };
-
- pinctrl@01c20800 {
- usb2_vbus_pin_a: usb2_vbus_pin@0 {
- allwinner,pins = "PH12";
- };
- };
-
- ir0: ir@01c21800 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
- status = "okay";
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupts = <0>;
-
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
};
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_pins_a>;
+ phy = <&phy1>;
+ status = "okay";
+};
+
+&emac_sram {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupts = <0>;
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
+ interrupt-controller;
+ #interrupt-cells = <1>;
};
+};
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_pins_a>;
+ status = "okay";
+};
+
+&mdio {
+ status = "okay";
- reg_usb2_vbus: usb2-vbus {
- gpio = <&pio 7 12 GPIO_ACTIVE_HIGH>;
- status = "okay";
+ phy1: ethernet-phy@1 {
+ reg = <1>;
};
};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ usb2_vbus_pin_a: usb2_vbus_pin@0 {
+ allwinner,pins = "PH12";
+ };
+};
+
+&reg_usb1_vbus {
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ gpio = <&pio 7 12 GPIO_ACTIVE_HIGH>;
+ 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/sun4i-a10-chuwi-v7-cw0825.dts b/arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts
index 58214f249598..5878a0b11f7b 100644
--- a/arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts
+++ b/arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts
@@ -16,11 +16,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 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
@@ -49,10 +44,19 @@
#include "sun4i-a10.dtsi"
#include "sunxi-common-regulators.dtsi"
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
/ {
model = "Chuwi V7 CW0825";
compatible = "chuwi,v7-cw0825", "allwinner,sun4i-a10";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
};
&ehci1 {
@@ -74,6 +78,32 @@
};
};
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
+
+ button@800 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <800000>;
+ };
+
+ button@1000 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <1000000>;
+ };
+
+ button@1200 {
+ label = "Back";
+ linux,code = <KEY_BACK>;
+ channel = <0>;
+ voltage = <1200000>;
+ };
+};
+
&mmc0 {
pinctrl-names = "default";
pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index 4260c2b47607..9afb4e018593 100644
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -17,11 +17,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 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
@@ -57,102 +52,12 @@
model = "Cubietech Cubieboard";
compatible = "cubietech,a10-cubieboard", "allwinner,sun4i-a10";
- soc@01c00000 {
- emac: ethernet@01c0b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&emac_pins_a>;
- phy = <&phy1>;
- status = "okay";
- };
-
- mdio@01c0b080 {
- status = "okay";
-
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
-
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- ahci: sata@01c18000 {
- target-supply = <&reg_ahci_5v>;
- status = "okay";
- };
-
- ehci1: usb@01c1c000 {
- status = "okay";
- };
-
- ohci1: usb@01c1c400 {
- status = "okay";
- };
-
- pinctrl@01c20800 {
- led_pins_cubieboard: led_pins@0 {
- allwinner,pins = "PH20", "PH21";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_20_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- ir0: ir@01c21800 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
- status = "okay";
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- reg = <0x34>;
- interrupts = <0>;
- };
- };
-
- i2c1: i2c@01c2b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
- };
+ aliases {
+ serial0 = &uart0;
+ };
- spi0: spi@01c05000 {
- pinctrl-names = "default";
- pinctrl-0 = <&spi0_pins_a>;
- status = "okay";
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
};
leds {
@@ -171,26 +76,100 @@
linux,default-trigger = "heartbeat";
};
};
+};
- reg_ahci_5v: ahci-5v {
- status = "okay";
- };
+&ahci {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_pins_a>;
+ phy = <&phy1>;
+ status = "okay";
+};
+
+&emac_sram {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ reg = <0x34>;
+ interrupts = <0>;
};
+};
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_pins_a>;
+ status = "okay";
+};
+
+&mdio {
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
};
};
-#include "axp209.dtsi"
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
-&cpu0 {
- cpu-supply = <&reg_dcdc2>;
+&ohci0 {
+ status = "okay";
};
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ led_pins_cubieboard: led_pins@0 {
+ allwinner,pins = "PH20", "PH21";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_ahci_5v {
+ status = "okay";
+};
+
+#include "axp209.dtsi"
+
&reg_dcdc2 {
regulator-always-on;
regulator-min-microvolt = <1000000>;
@@ -215,3 +194,30 @@
regulator-max-microvolt = <3000000>;
regulator-name = "avcc";
};
+
+&reg_usb1_vbus {
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ status = "okay";
+};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pins_a>,
+ <&spi0_cs0_pins_a>;
+ 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/sun4i-a10-gemei-g9.dts b/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts
new file mode 100644
index 000000000000..570754d8df67
--- /dev/null
+++ b/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2015 Priit Laes
+ *
+ * Priit Laes <plaes@plaes.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
+ * 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 "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Gemei G9 Tablet";
+ compatible = "gemei,g9", "allwinner,sun4i-a10";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+/*
+ * TODO:
+ * 2x cameras via CSI
+ * bma250 IRQs
+ * AXP battery management
+ * NAND
+ * OTG
+ * Touchscreen - gt801_2plus1 @ i2c adapter 2 @ 0x48
+ */
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupts = <0>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+
+ /* Accelerometer */
+ bma250@18 {
+ compatible = "bosch,bma250";
+ reg = <0x18>;
+
+ /*
+ * TODO: interrupt pins:
+ * int1 - PH00
+ * int2 - PI10
+ */
+ };
+};
+
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+
+ status = "okay";
+
+ button@158 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <158730>;
+ };
+
+ button@349 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <349206>;
+ };
+
+ button@1142 {
+ label = "Esc";
+ linux,code = <KEY_ESC>;
+ channel = <0>;
+ voltage = <1142856>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH01 */
+ cd-inverted;
+ status = "okay";
+};
+
+&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/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
index d3f73ea25567..2b17c5199151 100644
--- a/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+++ b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
@@ -18,11 +18,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 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
@@ -58,100 +53,12 @@
model = "Miniand Hackberry";
compatible = "miniand,hackberry", "allwinner,sun4i-a10";
- soc@01c00000 {
- emac: ethernet@01c0b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&emac_pins_a>;
- phy = <&phy0>;
- status = "okay";
- };
-
- mdio@01c0b080 {
- phy-supply = <&reg_emac_3v3>;
- status = "okay";
-
- phy0: ethernet-phy@0 {
- reg = <0>;
- };
- };
-
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- ehci1: usb@01c1c000 {
- status = "okay";
- };
-
- ohci1: usb@01c1c400 {
- status = "okay";
- };
-
- pio: pinctrl@01c20800 {
- pinctrl-names = "default";
- pinctrl-0 = <&hackberry_hogs>;
-
- hackberry_hogs: hogs@0 {
- allwinner,pins = "PH19";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- usb2_vbus_pin_hackberry: usb2_vbus_pin@0 {
- allwinner,pins = "PH12";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- ir0: ir@01c21800 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
- status = "okay";
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupts = <0>;
-
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
};
reg_emac_3v3: emac-3v3 {
@@ -162,14 +69,97 @@
enable-active-high;
gpio = <&pio 7 19 GPIO_ACTIVE_HIGH>;
};
+};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_pins_a>;
+ phy = <&phy0>;
+ status = "okay";
+};
+
+&emac_sram {
+ status = "okay";
+};
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_pins_a>;
+ status = "okay";
+};
+
+&mdio {
+ phy-supply = <&reg_emac_3v3>;
+ status = "okay";
+
+ phy0: ethernet-phy@0 {
+ reg = <0>;
};
+};
- reg_usb2_vbus: usb2-vbus {
- pinctrl-0 = <&usb2_vbus_pin_hackberry>;
- gpio = <&pio 7 12 GPIO_ACTIVE_HIGH>;
- 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 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ pinctrl-names = "default";
+ pinctrl-0 = <&hackberry_hogs>;
+
+ hackberry_hogs: hogs@0 {
+ allwinner,pins = "PH19";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb2_vbus_pin_hackberry: usb2_vbus_pin@0 {
+ allwinner,pins = "PH12";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
+
+&reg_usb1_vbus {
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ pinctrl-0 = <&usb2_vbus_pin_hackberry>;
+ gpio = <&pio 7 12 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts b/arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts
index c88382aacc36..43f58fbe161c 100644
--- a/arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts
+++ b/arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts
@@ -16,11 +16,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 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
@@ -53,6 +48,14 @@
/ {
model = "Hyundai A7HD";
compatible = "hyundai,a7hd", "allwinner,sun4i-a10";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
};
&ehci1 {
diff --git a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
index 482914333bba..6c927a824ba2 100644
--- a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
+++ b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
@@ -18,11 +18,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 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
@@ -61,66 +56,68 @@
serial0 = &uart0;
};
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- ehci1: usb@01c1c000 {
- status = "okay";
- };
-
- ohci1: usb@01c1c400 {
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupts = <0>;
-
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
};
+};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
- };
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupts = <0>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
};
};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&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/sun4i-a10-jesurun-q5.dts b/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts
new file mode 100644
index 000000000000..dc2f2aeaff07
--- /dev/null
+++ b/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2015 Gábor Nyers
+ *
+ * Gábor Nyers <gabor.nyers@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 "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Jesurun Q5";
+ compatible = "jesurun,q5", "allwinner,sun4i-a10";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_q5>;
+
+ green {
+ label = "q5:green:usr";
+ gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>; /* PH20 */
+ };
+
+ };
+
+ reg_emac_3v3: emac-3v3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_power_pin_q5>;
+ regulator-name = "emac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ enable-active-high;
+ gpio = <&pio 7 19 GPIO_ACTIVE_HIGH>; /* PH19 */
+ };
+};
+
+&ahci {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_pins_a>;
+ phy = <&phy1>;
+ status = "okay";
+};
+
+&emac_sram {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupts = <0>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_pins_a>;
+ status = "okay";
+};
+
+&mdio {
+ phy-supply = <&reg_emac_3v3>;
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ emac_power_pin_q5: emac_power_pin@0 {
+ allwinner,pins = "PH19";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ led_pins_q5: led_pins@0 {
+ allwinner,pins = "PH20";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&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/sun4i-a10-marsboard.dts b/arch/arm/boot/dts/sun4i-a10-marsboard.dts
index 9ee86a700c2b..02158bcd64ee 100644
--- a/arch/arm/boot/dts/sun4i-a10-marsboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-marsboard.dts
@@ -17,11 +17,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 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
@@ -57,6 +52,14 @@
model = "HAOYU Electronics Marsboard A10";
compatible = "haoyu,a10-marsboard", "allwinner,sun4i-a10";
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
@@ -96,6 +99,10 @@
status = "okay";
};
+&emac_sram {
+ status = "okay";
+};
+
&emac {
pinctrl-names = "default";
pinctrl-0 = <&emac_pins_a>;
@@ -166,7 +173,8 @@
&spi0 {
pinctrl-names = "default";
- pinctrl-0 = <&spi0_pins_a>;
+ pinctrl-0 = <&spi0_pins_a>,
+ <&spi0_cs0_pins_a>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
index eb5fd6904a69..ebe2a04ef649 100644
--- a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
+++ b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
@@ -18,11 +18,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 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
@@ -58,79 +53,83 @@
model = "PineRiver Mini X-Plus";
compatible = "pineriver,mini-xplus", "allwinner,sun4i-a10";
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- ehci1: usb@01c1c000 {
- status = "okay";
- };
-
- ohci1: usb@01c1c400 {
- status = "okay";
- };
-
- pinctrl@01c20800 {
- ir0_pins_a: ir0@0 {
- /* The ir receiver is not always populated */
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
- };
-
- ir0: ir@01c21800 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
- status = "okay";
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupts = <0>;
-
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+ aliases {
+ serial0 = &uart0;
};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
+ chosen {
+ stdout-path = "serial0:115200n8";
};
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupts = <0>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
};
};
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_pins_a>;
+ status = "okay";
+};
+
+&ir0_rx_pins_a {
+ /* The ir receiver is not always populated */
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&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/sun4i-a10-mk802.dts b/arch/arm/boot/dts/sun4i-a10-mk802.dts
index e9a6886f0d51..3c7eebe17088 100644
--- a/arch/arm/boot/dts/sun4i-a10-mk802.dts
+++ b/arch/arm/boot/dts/sun4i-a10-mk802.dts
@@ -16,11 +16,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 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
@@ -53,6 +48,14 @@
/ {
model = "MK802";
compatible = "allwinner,mk802", "allwinner,sun4i-a10";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
};
&ehci0 {
diff --git a/arch/arm/boot/dts/sun4i-a10-mk802ii.dts b/arch/arm/boot/dts/sun4i-a10-mk802ii.dts
index 802eda494d1c..c861fa7e356c 100644
--- a/arch/arm/boot/dts/sun4i-a10-mk802ii.dts
+++ b/arch/arm/boot/dts/sun4i-a10-mk802ii.dts
@@ -16,11 +16,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 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
@@ -53,6 +48,14 @@
/ {
model = "MK802ii";
compatible = "allwinner,mk802ii", "allwinner,sun4i-a10";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
};
&ehci0 {
diff --git a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
index 75742f8f96f3..b64aa4eb071e 100644
--- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
@@ -16,11 +16,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 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
@@ -56,136 +51,143 @@
model = "Olimex A10-OLinuXino-LIME";
compatible = "olimex,a10-olinuxino-lime", "allwinner,sun4i-a10";
- cpus {
- cpu0: cpu@0 {
- /*
- * The A10-Lime is known to be unstable
- * when running at 1008 MHz
- */
- operating-points = <
- /* kHz uV */
- 912000 1350000
- 864000 1300000
- 624000 1250000
- >;
- cooling-max-level = <2>;
- };
+ aliases {
+ serial0 = &uart0;
};
- soc@01c00000 {
- emac: ethernet@01c0b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&emac_pins_a>;
- phy = <&phy1>;
- status = "okay";
- };
-
- mdio@01c0b080 {
- status = "okay";
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_olinuxinolime>;
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
+ green {
+ label = "a10-olinuxino-lime:green:usr";
+ gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
};
+ };
+};
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
+&ahci {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+};
- ehci0: usb@01c14000 {
- status = "okay";
- };
+&cpu0 {
+ /*
+ * The A10-Lime is known to be unstable when running at 1008 MHz
+ */
+ operating-points = <
+ /* kHz uV */
+ 912000 1350000
+ 864000 1300000
+ 624000 1250000
+ >;
+ cooling-max-level = <2>;
+};
- ohci0: usb@01c14400 {
- status = "okay";
- };
+&ehci0 {
+ status = "okay";
+};
- ahci: sata@01c18000 {
- target-supply = <&reg_ahci_5v>;
- status = "okay";
- };
+&ehci1 {
+ status = "okay";
+};
- ehci1: usb@01c1c000 {
- status = "okay";
- };
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_pins_a>;
+ phy = <&phy1>;
+ status = "okay";
+};
- ohci1: usb@01c1c400 {
- status = "okay";
- };
+&emac_sram {
+ status = "okay";
+};
- pinctrl@01c20800 {
- ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
- allwinner,pins = "PC3";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- led_pins_olinuxinolime: led_pins@0 {
- allwinner,pins = "PH2";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_20_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupts = <0>;
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupts = <0>;
+&mdio {
+ status = "okay";
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+ phy1: ethernet-phy@1 {
+ reg = <1>;
};
+};
- leds {
- compatible = "gpio-leds";
- pinctrl-names = "default";
- pinctrl-0 = <&led_pins_olinuxinolime>;
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
- green {
- label = "a10-olinuxino-lime:green:usr";
- gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
- default-state = "on";
- };
- };
+&ohci0 {
+ status = "okay";
+};
- reg_ahci_5v: ahci-5v {
- pinctrl-0 = <&ahci_pwr_pin_olinuxinolime>;
- gpio = <&pio 2 3 GPIO_ACTIVE_HIGH>;
- status = "okay";
- };
+&ohci1 {
+ status = "okay";
+};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
+&pio {
+ ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
+ allwinner,pins = "PC3";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
+ led_pins_olinuxinolime: led_pins@0 {
+ allwinner,pins = "PH2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
+
+&reg_ahci_5v {
+ pinctrl-0 = <&ahci_pwr_pin_olinuxinolime>;
+ gpio = <&pio 2 3 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&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/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
index 9d1e5482cf82..4e3e1b9d8217 100644
--- a/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
@@ -17,11 +17,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 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
@@ -58,90 +53,12 @@
model = "LinkSprite pcDuino";
compatible = "linksprite,a10-pcduino", "allwinner,sun4i-a10";
- soc@01c00000 {
- emac: ethernet@01c0b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&emac_pins_a>;
- phy = <&phy1>;
- status = "okay";
- };
-
- pinctrl@01c20800 {
- led_pins_pcduino: led_pins@0 {
- allwinner,pins = "PH15", "PH16";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- key_pins_pcduino: key_pins@0 {
- allwinner,pins = "PH17", "PH18", "PH19";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- mdio@01c0b080 {
- status = "okay";
-
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
-
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- ehci1: usb@01c1c000 {
- status = "okay";
- };
-
- ohci1: usb@01c1c400 {
- status = "okay";
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupts = <0>;
+ aliases {
+ serial0 = &uart0;
+ };
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
};
leds {
@@ -185,12 +102,100 @@
gpios = <&pio 7 19 GPIO_ACTIVE_LOW>;
};
};
+};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_pins_a>;
+ phy = <&phy1>;
+ status = "okay";
+};
+
+&emac_sram {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupts = <0>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
+
+&mdio {
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ led_pins_pcduino: led_pins@0 {
+ allwinner,pins = "PH15", "PH16";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
+ key_pins_pcduino: key_pins@0 {
+ allwinner,pins = "PH17", "PH18", "PH19";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
+
+&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/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index eebb7853e00b..61c03d1fe530 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -2,12 +2,43 @@
* Copyright 2012 Stefan Roese
* Stefan Roese <sr@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:
+ * 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.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * 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.
*/
#include "skeleton.dtsi"
@@ -30,7 +61,8 @@
ranges;
framebuffer@0 {
- compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+ compatible = "allwinner,simple-framebuffer",
+ "simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-hdmi";
clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
<&ahb_gates 44>;
@@ -38,7 +70,8 @@
};
framebuffer@1 {
- compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+ compatible = "allwinner,simple-framebuffer",
+ "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>;
@@ -74,11 +107,11 @@
clocks = <&cpu>;
clock-latency = <244144>; /* 8 32k periods */
operating-points = <
- /* kHz uV */
+ /* kHz uV */
1008000 1400000
- 912000 1350000
- 864000 1300000
- 624000 1250000
+ 912000 1350000
+ 864000 1300000
+ 624000 1250000
>;
#cooling-cells = <2>;
cooling-min-level = <0>;
@@ -398,11 +431,12 @@
usb_clk: clk@01c200cc {
#clock-cells = <1>;
- #reset-cells = <1>;
+ #reset-cells = <1>;
compatible = "allwinner,sun4i-a10-usb-clk";
reg = <0x01c200cc 0x4>;
clocks = <&pll6 1>;
- clock-output-names = "usb_ohci0", "usb_ohci1", "usb_phy";
+ clock-output-names = "usb_ohci0", "usb_ohci1",
+ "usb_phy";
};
spi3_clk: clk@01c200d4 {
@@ -420,6 +454,42 @@
#size-cells = <1>;
ranges;
+ sram-controller@01c00000 {
+ compatible = "allwinner,sun4i-a10-sram-controller";
+ reg = <0x01c00000 0x30>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram_a: sram@00000000 {
+ compatible = "mmio-sram";
+ reg = <0x00000000 0xc000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00000000 0xc000>;
+
+ emac_sram: sram-section@8000 {
+ compatible = "allwinner,sun4i-a10-sram-a3-a4";
+ reg = <0x8000 0x4000>;
+ status = "disabled";
+ };
+ };
+
+ sram_d: sram@00010000 {
+ compatible = "mmio-sram";
+ reg = <0x00010000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00010000 0x1000>;
+
+ otg_sram: sram-section@0000 {
+ compatible = "allwinner,sun4i-a10-sram-d";
+ reg = <0x0000 0x1000>;
+ status = "disabled";
+ };
+ };
+ };
+
dma: dma-controller@01c02000 {
compatible = "allwinner,sun4i-a10-dma";
reg = <0x01c02000 0x1000>;
@@ -461,6 +531,7 @@
reg = <0x01c0b000 0x1000>;
interrupts = <55>;
clocks = <&ahb_gates 17>;
+ allwinner,sram = <&emac_sram 1>;
status = "disabled";
};
@@ -485,6 +556,8 @@
"sample";
interrupts = <32>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc1: mmc@01c10000 {
@@ -500,6 +573,8 @@
"sample";
interrupts = <33>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc2: mmc@01c11000 {
@@ -515,6 +590,8 @@
"sample";
interrupts = <34>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc3: mmc@01c12000 {
@@ -530,6 +607,8 @@
"sample";
interrupts = <35>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
usbphy: phy@01c13400 {
@@ -706,7 +785,8 @@
};
mmc0_pins_a: mmc0@0 {
- allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
+ allwinner,pins = "PF0", "PF1", "PF2",
+ "PF3", "PF4", "PF5";
allwinner,function = "mmc0";
allwinner,drive = <SUN4I_PINCTRL_30_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
@@ -719,43 +799,85 @@
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
- ir0_pins_a: ir0@0 {
- allwinner,pins = "PB3","PB4";
+ ir0_rx_pins_a: ir0@0 {
+ allwinner,pins = "PB4";
allwinner,function = "ir0";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- ir1_pins_a: ir1@0 {
- allwinner,pins = "PB22","PB23";
+ ir0_tx_pins_a: ir0@1 {
+ allwinner,pins = "PB3";
+ allwinner,function = "ir0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ ir1_rx_pins_a: ir1@0 {
+ allwinner,pins = "PB23";
+ allwinner,function = "ir1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ ir1_tx_pins_a: ir1@1 {
+ allwinner,pins = "PB22";
allwinner,function = "ir1";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
spi0_pins_a: spi0@0 {
- allwinner,pins = "PI10", "PI11", "PI12", "PI13";
+ allwinner,pins = "PI11", "PI12", "PI13";
+ allwinner,function = "spi0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ spi0_cs0_pins_a: spi0_cs0@0 {
+ allwinner,pins = "PI10";
allwinner,function = "spi0";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
spi1_pins_a: spi1@0 {
- allwinner,pins = "PI16", "PI17", "PI18", "PI19";
+ allwinner,pins = "PI17", "PI18", "PI19";
+ allwinner,function = "spi1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ spi1_cs0_pins_a: spi1_cs0@0 {
+ allwinner,pins = "PI16";
allwinner,function = "spi1";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
spi2_pins_a: spi2@0 {
- allwinner,pins = "PB14", "PB15", "PB16", "PB17";
+ allwinner,pins = "PC20", "PC21", "PC22";
allwinner,function = "spi2";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
spi2_pins_b: spi2@1 {
- allwinner,pins = "PC19", "PC20", "PC21", "PC22";
+ allwinner,pins = "PB15", "PB16", "PB17";
+ allwinner,function = "spi2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ spi2_cs0_pins_a: spi2_cs0@0 {
+ allwinner,pins = "PC19";
+ allwinner,function = "spi2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ spi2_cs0_pins_b: spi2_cs0@1 {
+ allwinner,pins = "PB14";
allwinner,function = "spi2";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
diff --git a/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts b/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts
new file mode 100644
index 000000000000..2b3511ea2e5d
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-a10s-auxtek-t004.dts
@@ -0,0 +1,154 @@
+/*
+ * 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-a10s.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Auxtek t004 A10s hdmi tv-stick";
+ compatible = "allwinner,auxtek-t004", "allwinner,sun5i-a10s";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_t004>;
+
+ red {
+ label = "t004-tv-dongle:red:usr";
+ gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; /* PB2 */
+ default-state = "on";
+ };
+ };
+
+ reg_vmmc1: vmmc1 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_vcc_en_pin_t004>;
+ regulator-name = "vmmc1";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ enable-active-high;
+ gpio = <&pio 1 18 GPIO_ACTIVE_HIGH>; /* PB18 */
+ };
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_t004>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_a>;
+ vmmc-supply = <&reg_vmmc1>;
+ bus-width = <4>;
+ non-removable;
+ cap-sdio-irq;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_t004: mmc0_cd_pin@0 {
+ allwinner,pins = "PG1";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ mmc1_vcc_en_pin_t004: mmc1_vcc_en_pin@0 {
+ allwinner,pins = "PB18";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ led_pins_t004: led_pins@0 {
+ allwinner,pins = "PB2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_usb1_vbus {
+ gpio = <&pio 6 13 GPIO_ACTIVE_HIGH>; /* PG13 */
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usb1_vbus_pin_a {
+ allwinner,pins = "PG13";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun5i-a10s-mk802.dts b/arch/arm/boot/dts/sun5i-a10s-mk802.dts
index b21af87d9eae..46ff9407826d 100644
--- a/arch/arm/boot/dts/sun5i-a10s-mk802.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-mk802.dts
@@ -16,11 +16,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 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
@@ -54,6 +49,14 @@
model = "MK802-A10s";
compatible = "allwinner,a10s-mk802", "allwinner,sun5i-a10s";
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
index 2bbc93b935ca..a7e19e4847f7 100644
--- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
@@ -18,11 +18,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 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
@@ -65,184 +60,191 @@
serial2 = &uart3;
};
- soc@01c00000 {
- emac: ethernet@01c0b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&emac_pins_a>;
- phy = <&phy1>;
- status = "okay";
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
- mdio@01c0b080 {
- status = "okay";
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_olinuxino>;
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
+ green {
+ label = "a10s-olinuxino-micro:green:usr";
+ gpios = <&pio 4 3 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
};
+ };
+};
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxino_micro>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
- cd-inverted;
- status = "okay";
- };
+&ehci0 {
+ status = "okay";
+};
- mmc1: mmc@01c10000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc1_pins_a>, <&mmc1_cd_pin_olinuxino_micro>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 6 13 GPIO_ACTIVE_HIGH>; /* PG13 */
- cd-inverted;
- status = "okay";
- };
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_pins_a>;
+ phy = <&phy1>;
+ status = "okay";
+};
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- status = "okay";
- };
+&emac_sram {
+ status = "okay";
+};
- ehci0: usb@01c14000 {
- status = "okay";
- };
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+};
- ohci0: usb@01c14400 {
- status = "okay";
- };
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
- pinctrl@01c20800 {
- mmc0_cd_pin_olinuxino_micro: mmc0_cd_pin@0 {
- allwinner,pins = "PG1";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- mmc1_cd_pin_olinuxino_micro: mmc1_cd_pin@0 {
- allwinner,pins = "PG13";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- led_pins_olinuxino: led_pins@0 {
- allwinner,pins = "PE3";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_20_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- usb1_vbus_pin_olinuxino_m: usb1_vbus_pin@0 {
- allwinner,pins = "PB10";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
+ at24@50 {
+ compatible = "at,24c16";
+ pagesize = <16>;
+ reg = <0x50>;
+ read-only;
+ };
+};
- lradc: lradc@01c22800 {
- vref-supply = <&reg_vcc3v0>;
- status = "okay";
-
- button@191 {
- label = "Volume Up";
- linux,code = <KEY_VOLUMEUP>;
- channel = <0>;
- voltage = <191274>;
- };
-
- button@392 {
- label = "Volume Down";
- linux,code = <KEY_VOLUMEDOWN>;
- channel = <0>;
- voltage = <392644>;
- };
-
- button@601 {
- label = "Menu";
- linux,code = <KEY_MENU>;
- channel = <0>;
- voltage = <601151>;
- };
-
- button@795 {
- label = "Enter";
- linux,code = <KEY_ENTER>;
- channel = <0>;
- voltage = <795090>;
- };
-
- button@987 {
- label = "Home";
- linux,code = <KEY_HOMEPAGE>;
- channel = <0>;
- voltage = <987387>;
- };
- };
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
- uart2: serial@01c28800 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart2_pins_a>;
- status = "okay";
- };
+ button@191 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <191274>;
+ };
- uart3: serial@01c28c00 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_pins_a>;
- status = "okay";
- };
+ button@392 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <392644>;
+ };
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
- };
+ button@601 {
+ label = "Menu";
+ linux,code = <KEY_MENU>;
+ channel = <0>;
+ voltage = <601151>;
+ };
- i2c1: i2c@01c2b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
-
- at24@50 {
- compatible = "at,24c16";
- pagesize = <16>;
- reg = <0x50>;
- read-only;
- };
- };
+ button@795 {
+ label = "Enter";
+ linux,code = <KEY_ENTER>;
+ channel = <0>;
+ voltage = <795090>;
+ };
- i2c2: i2c@01c2b400 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins_a>;
- status = "okay";
- };
+ button@987 {
+ label = "Home";
+ linux,code = <KEY_HOMEPAGE>;
+ channel = <0>;
+ voltage = <987387>;
};
+};
- leds {
- compatible = "gpio-leds";
- pinctrl-names = "default";
- pinctrl-0 = <&led_pins_olinuxino>;
+&mdio {
+ status = "okay";
- green {
- label = "a10s-olinuxino-micro:green:usr";
- gpios = <&pio 4 3 GPIO_ACTIVE_HIGH>;
- default-state = "on";
- };
+ phy1: ethernet-phy@1 {
+ reg = <1>;
};
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxino_micro>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_a>, <&mmc1_cd_pin_olinuxino_micro>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 6 13 GPIO_ACTIVE_HIGH>; /* PG13 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
- reg_usb1_vbus: usb1-vbus {
- pinctrl-0 = <&usb1_vbus_pin_olinuxino_m>;
- gpio = <&pio 1 10 GPIO_ACTIVE_HIGH>;
- status = "okay";
+&pio {
+ mmc0_cd_pin_olinuxino_micro: mmc0_cd_pin@0 {
+ allwinner,pins = "PG1";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+
+ mmc1_cd_pin_olinuxino_micro: mmc1_cd_pin@0 {
+ allwinner,pins = "PG13";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ led_pins_olinuxino: led_pins@0 {
+ allwinner,pins = "PE3";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb1_vbus_pin_olinuxino_m: usb1_vbus_pin@0 {
+ allwinner,pins = "PB10";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_olinuxino_m>;
+ gpio = <&pio 1 10 GPIO_ACTIVE_HIGH>;
+ status = "okay";
};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins_a>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
+
diff --git a/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts b/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts
index 7deddfc9df8b..3b057983c74a 100644
--- a/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts
@@ -16,11 +16,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 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
@@ -56,67 +51,12 @@
model = "R7 A10s hdmi tv-stick";
compatible = "allwinner,r7-tv-dongle", "allwinner,sun5i-a10s";
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_r7>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
- cd-inverted;
- status = "okay";
- };
-
- mmc1: mmc@01c10000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc1_pins_a>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- non-removable;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- pinctrl@01c20800 {
- mmc0_cd_pin_r7: mmc0_cd_pin@0 {
- allwinner,pins = "PG1";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- led_pins_r7: led_pins@0 {
- allwinner,pins = "PB2";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_20_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- usb1_vbus_pin_r7: usb1_vbus_pin@0 {
- allwinner,pins = "PG13";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
+ aliases {
+ serial0 = &uart0;
+ };
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
};
leds {
@@ -130,10 +70,71 @@
default-state = "on";
};
};
+};
+
+&ehci0 {
+ status = "okay";
+};
- reg_usb1_vbus: usb1-vbus {
- pinctrl-0 = <&usb1_vbus_pin_r7>;
- gpio = <&pio 6 13 GPIO_ACTIVE_HIGH>;
- status = "okay";
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_r7>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_a>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_r7: mmc0_cd_pin@0 {
+ allwinner,pins = "PG1";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ led_pins_r7: led_pins@0 {
+ allwinner,pins = "PB2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ usb1_vbus_pin_r7: usb1_vbus_pin@0 {
+ allwinner,pins = "PG13";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_r7>;
+ gpio = <&pio 6 13 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index 2fd8988f310c..f11efb722bbb 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -3,16 +3,49 @@
*
* Maxime Ripard <maxime.ripard@free-electrons.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:
+ * 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.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * 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.
*/
#include "skeleton.dtsi"
+#include "sun5i.dtsi"
+
#include <dt-bindings/dma/sun4i-a10.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
@@ -29,7 +62,8 @@
ranges;
framebuffer@0 {
- compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+ compatible = "allwinner,simple-framebuffer",
+ "simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-hdmi";
clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
<&ahb_gates 44>;
@@ -45,133 +79,23 @@
};
};
- cpus {
- cpu@0 {
- compatible = "arm,cortex-a8";
- };
- };
-
- memory {
- reg = <0x40000000 0x20000000>;
- };
-
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- /*
- * This is a dummy clock, to be used as placeholder on
- * other mux clocks when a specific parent clock is not
- * yet implemented. It should be dropped when the driver
- * is complete.
- */
- dummy: dummy {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <0>;
- };
-
- osc24M: clk@01c20050 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-osc-clk";
- reg = <0x01c20050 0x4>;
- clock-frequency = <24000000>;
- clock-output-names = "osc24M";
- };
-
- osc32k: clk@0 {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <32768>;
- clock-output-names = "osc32k";
- };
-
- pll1: clk@01c20000 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-pll1-clk";
- reg = <0x01c20000 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "pll1";
- };
-
- pll4: clk@01c20018 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-pll1-clk";
- reg = <0x01c20018 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "pll4";
- };
-
- pll5: clk@01c20020 {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-pll5-clk";
- reg = <0x01c20020 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "pll5_ddr", "pll5_other";
- };
-
- pll6: clk@01c20028 {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-pll6-clk";
- reg = <0x01c20028 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "pll6_sata", "pll6_other", "pll6";
- };
-
- /* dummy is 200M */
- cpu: cpu@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-cpu-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
- clock-output-names = "cpu";
- };
-
- axi: axi@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-axi-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&cpu>;
- clock-output-names = "axi";
- };
-
- axi_gates: clk@01c2005c {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-axi-gates-clk";
- reg = <0x01c2005c 0x4>;
- clocks = <&axi>;
- clock-output-names = "axi_dram";
- };
-
- ahb: ahb@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-ahb-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&axi>;
- clock-output-names = "ahb";
- };
-
ahb_gates: clk@01c20060 {
#clock-cells = <1>;
compatible = "allwinner,sun5i-a10s-ahb-gates-clk";
reg = <0x01c20060 0x8>;
clocks = <&ahb>;
- clock-output-names = "ahb_usbotg", "ahb_ehci", "ahb_ohci",
- "ahb_ss", "ahb_dma", "ahb_bist", "ahb_mmc0",
- "ahb_mmc1", "ahb_mmc2", "ahb_nand", "ahb_sdram",
- "ahb_emac", "ahb_ts", "ahb_spi0", "ahb_spi1",
- "ahb_spi2", "ahb_gps", "ahb_stimer", "ahb_ve",
- "ahb_tve", "ahb_lcd", "ahb_csi", "ahb_hdmi",
- "ahb_de_be", "ahb_de_fe", "ahb_iep", "ahb_mali400";
- };
-
- apb0: apb0@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-apb0-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&ahb>;
- clock-output-names = "apb0";
+ clock-output-names = "ahb_usbotg", "ahb_ehci",
+ "ahb_ohci", "ahb_ss", "ahb_dma",
+ "ahb_bist", "ahb_mmc0", "ahb_mmc1",
+ "ahb_mmc2", "ahb_nand",
+ "ahb_sdram", "ahb_emac", "ahb_ts",
+ "ahb_spi0", "ahb_spi1", "ahb_spi2",
+ "ahb_gps", "ahb_stimer", "ahb_ve",
+ "ahb_tve", "ahb_lcd", "ahb_csi",
+ "ahb_hdmi", "ahb_de_be",
+ "ahb_de_fe", "ahb_iep",
+ "ahb_mali400";
};
apb0_gates: clk@01c20068 {
@@ -179,16 +103,9 @@
compatible = "allwinner,sun5i-a10s-apb0-gates-clk";
reg = <0x01c20068 0x4>;
clocks = <&apb0>;
- clock-output-names = "apb0_codec", "apb0_iis", "apb0_pio",
- "apb0_ir", "apb0_keypad";
- };
-
- apb1: clk@01c20058 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-apb1-clk";
- reg = <0x01c20058 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
- clock-output-names = "apb1";
+ clock-output-names = "apb0_codec", "apb0_iis",
+ "apb0_pio", "apb0_ir",
+ "apb0_keypad";
};
apb1_gates: clk@01c2006c {
@@ -200,166 +117,15 @@
"apb1_i2c2", "apb1_uart0", "apb1_uart1",
"apb1_uart2", "apb1_uart3";
};
-
- nand_clk: clk@01c20080 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c20080 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "nand";
- };
-
- ms_clk: clk@01c20084 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c20084 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "ms";
- };
-
- mmc0_clk: clk@01c20088 {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-mmc-clk";
- reg = <0x01c20088 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- 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 1>, <&pll5 1>;
- 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 1>, <&pll5 1>;
- clock-output-names = "mmc2",
- "mmc2_output",
- "mmc2_sample";
- };
-
- ts_clk: clk@01c20098 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c20098 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "ts";
- };
-
- ss_clk: clk@01c2009c {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c2009c 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "ss";
- };
-
- spi0_clk: clk@01c200a0 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c200a0 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "spi0";
- };
-
- spi1_clk: clk@01c200a4 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c200a4 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "spi1";
- };
-
- spi2_clk: clk@01c200a8 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c200a8 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "spi2";
- };
-
- ir0_clk: clk@01c200b0 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c200b0 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "ir0";
- };
-
- usb_clk: clk@01c200cc {
- #clock-cells = <1>;
- #reset-cells = <1>;
- compatible = "allwinner,sun5i-a13-usb-clk";
- reg = <0x01c200cc 0x4>;
- clocks = <&pll6 1>;
- clock-output-names = "usb_ohci0", "usb_phy";
- };
-
- mbus_clk: clk@01c2015c {
- #clock-cells = <0>;
- compatible = "allwinner,sun5i-a13-mbus-clk";
- reg = <0x01c2015c 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mbus";
- };
};
soc@01c00000 {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- dma: dma-controller@01c02000 {
- compatible = "allwinner,sun4i-a10-dma";
- reg = <0x01c02000 0x1000>;
- interrupts = <27>;
- clocks = <&ahb_gates 6>;
- #dma-cells = <2>;
- };
-
- spi0: spi@01c05000 {
- compatible = "allwinner,sun4i-a10-spi";
- reg = <0x01c05000 0x1000>;
- interrupts = <10>;
- clocks = <&ahb_gates 20>, <&spi0_clk>;
- clock-names = "ahb", "mod";
- dmas = <&dma SUN4I_DMA_DEDICATED 27>,
- <&dma SUN4I_DMA_DEDICATED 26>;
- dma-names = "rx", "tx";
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
- };
-
- spi1: spi@01c06000 {
- compatible = "allwinner,sun4i-a10-spi";
- reg = <0x01c06000 0x1000>;
- interrupts = <11>;
- clocks = <&ahb_gates 21>, <&spi1_clk>;
- clock-names = "ahb", "mod";
- dmas = <&dma SUN4I_DMA_DEDICATED 9>,
- <&dma SUN4I_DMA_DEDICATED 8>;
- dma-names = "rx", "tx";
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
- };
-
emac: ethernet@01c0b000 {
compatible = "allwinner,sun4i-a10-emac";
reg = <0x01c0b000 0x1000>;
interrupts = <55>;
clocks = <&ahb_gates 17>;
+ allwinner,sram = <&emac_sram 1>;
status = "disabled";
};
@@ -371,214 +137,6 @@
#size-cells = <0>;
};
- mmc0: mmc@01c0f000 {
- compatible = "allwinner,sun5i-a13-mmc";
- reg = <0x01c0f000 0x1000>;
- clocks = <&ahb_gates 8>,
- <&mmc0_clk 0>,
- <&mmc0_clk 1>,
- <&mmc0_clk 2>;
- clock-names = "ahb",
- "mmc",
- "output",
- "sample";
- interrupts = <32>;
- status = "disabled";
- };
-
- mmc1: mmc@01c10000 {
- compatible = "allwinner,sun5i-a13-mmc";
- reg = <0x01c10000 0x1000>;
- clocks = <&ahb_gates 9>,
- <&mmc1_clk 0>,
- <&mmc1_clk 1>,
- <&mmc1_clk 2>;
- clock-names = "ahb",
- "mmc",
- "output",
- "sample";
- interrupts = <33>;
- status = "disabled";
- };
-
- mmc2: mmc@01c11000 {
- compatible = "allwinner,sun5i-a13-mmc";
- reg = <0x01c11000 0x1000>;
- clocks = <&ahb_gates 10>,
- <&mmc2_clk 0>,
- <&mmc2_clk 1>,
- <&mmc2_clk 2>;
- clock-names = "ahb",
- "mmc",
- "output",
- "sample";
- interrupts = <34>;
- status = "disabled";
- };
-
- usbphy: phy@01c13400 {
- #phy-cells = <1>;
- compatible = "allwinner,sun5i-a13-usb-phy";
- reg = <0x01c13400 0x10 0x01c14800 0x4>;
- reg-names = "phy_ctrl", "pmu1";
- clocks = <&usb_clk 8>;
- clock-names = "usb_phy";
- resets = <&usb_clk 0>, <&usb_clk 1>;
- reset-names = "usb0_reset", "usb1_reset";
- status = "disabled";
- };
-
- ehci0: usb@01c14000 {
- compatible = "allwinner,sun5i-a10s-ehci", "generic-ehci";
- reg = <0x01c14000 0x100>;
- interrupts = <39>;
- clocks = <&ahb_gates 1>;
- phys = <&usbphy 1>;
- phy-names = "usb";
- status = "disabled";
- };
-
- ohci0: usb@01c14400 {
- compatible = "allwinner,sun5i-a10s-ohci", "generic-ohci";
- reg = <0x01c14400 0x100>;
- interrupts = <40>;
- clocks = <&usb_clk 6>, <&ahb_gates 2>;
- phys = <&usbphy 1>;
- phy-names = "usb";
- status = "disabled";
- };
-
- spi2: spi@01c17000 {
- compatible = "allwinner,sun4i-a10-spi";
- reg = <0x01c17000 0x1000>;
- interrupts = <12>;
- clocks = <&ahb_gates 22>, <&spi2_clk>;
- clock-names = "ahb", "mod";
- dmas = <&dma SUN4I_DMA_DEDICATED 29>,
- <&dma SUN4I_DMA_DEDICATED 28>;
- dma-names = "rx", "tx";
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
- };
-
- intc: interrupt-controller@01c20400 {
- compatible = "allwinner,sun4i-a10-ic";
- reg = <0x01c20400 0x400>;
- interrupt-controller;
- #interrupt-cells = <1>;
- };
-
- pio: pinctrl@01c20800 {
- compatible = "allwinner,sun5i-a10s-pinctrl";
- reg = <0x01c20800 0x400>;
- interrupts = <28>;
- clocks = <&apb0_gates 5>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- #size-cells = <0>;
- #gpio-cells = <3>;
-
- uart0_pins_a: uart0@0 {
- allwinner,pins = "PB19", "PB20";
- allwinner,function = "uart0";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- uart2_pins_a: uart2@0 {
- allwinner,pins = "PC18", "PC19";
- allwinner,function = "uart2";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- uart3_pins_a: uart3@0 {
- allwinner,pins = "PG9", "PG10";
- allwinner,function = "uart3";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- emac_pins_a: emac0@0 {
- allwinner,pins = "PA0", "PA1", "PA2",
- "PA3", "PA4", "PA5", "PA6",
- "PA7", "PA8", "PA9", "PA10",
- "PA11", "PA12", "PA13", "PA14",
- "PA15", "PA16";
- allwinner,function = "emac";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- i2c0_pins_a: i2c0@0 {
- allwinner,pins = "PB0", "PB1";
- allwinner,function = "i2c0";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- i2c1_pins_a: i2c1@0 {
- allwinner,pins = "PB15", "PB16";
- allwinner,function = "i2c1";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- i2c2_pins_a: i2c2@0 {
- allwinner,pins = "PB17", "PB18";
- allwinner,function = "i2c2";
- 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>;
- };
-
- mmc1_pins_a: mmc1@0 {
- allwinner,pins = "PG3","PG4","PG5","PG6","PG7","PG8";
- allwinner,function = "mmc1";
- allwinner,drive = <SUN4I_PINCTRL_30_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- timer@01c20c00 {
- compatible = "allwinner,sun4i-a10-timer";
- reg = <0x01c20c00 0x90>;
- interrupts = <22>;
- clocks = <&osc24M>;
- };
-
- wdt: watchdog@01c20c90 {
- compatible = "allwinner,sun4i-a10-wdt";
- reg = <0x01c20c90 0x10>;
- };
-
- lradc: lradc@01c22800 {
- compatible = "allwinner,sun4i-a10-lradc-keys";
- reg = <0x01c22800 0x100>;
- interrupts = <31>;
- status = "disabled";
- };
-
- sid: eeprom@01c23800 {
- compatible = "allwinner,sun4i-a10-sid";
- reg = <0x01c23800 0x10>;
- };
-
- rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-a10-ts";
- reg = <0x01c25000 0x100>;
- interrupts = <29>;
- #thermal-sensor-cells = <0>;
- };
-
uart0: serial@01c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28000 0x400>;
@@ -589,16 +147,6 @@
status = "disabled";
};
- uart1: serial@01c28400 {
- compatible = "snps,dw-apb-uart";
- reg = <0x01c28400 0x400>;
- interrupts = <2>;
- reg-shift = <2>;
- reg-io-width = <4>;
- clocks = <&apb1_gates 17>;
- status = "disabled";
- };
-
uart2: serial@01c28800 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28800 0x400>;
@@ -608,52 +156,57 @@
clocks = <&apb1_gates 18>;
status = "disabled";
};
+ };
+};
- uart3: serial@01c28c00 {
- compatible = "snps,dw-apb-uart";
- reg = <0x01c28c00 0x400>;
- interrupts = <4>;
- reg-shift = <2>;
- reg-io-width = <4>;
- clocks = <&apb1_gates 19>;
- status = "disabled";
- };
+&pio {
+ compatible = "allwinner,sun5i-a10s-pinctrl";
- i2c0: i2c@01c2ac00 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "allwinner,sun5i-a10s-i2c", "allwinner,sun4i-a10-i2c";
- reg = <0x01c2ac00 0x400>;
- interrupts = <7>;
- clocks = <&apb1_gates 0>;
- status = "disabled";
- };
+ uart0_pins_a: uart0@0 {
+ allwinner,pins = "PB19", "PB20";
+ allwinner,function = "uart0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
- i2c1: i2c@01c2b000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "allwinner,sun5i-a10s-i2c", "allwinner,sun4i-a10-i2c";
- reg = <0x01c2b000 0x400>;
- interrupts = <8>;
- clocks = <&apb1_gates 1>;
- status = "disabled";
- };
+ uart2_pins_a: uart2@0 {
+ allwinner,pins = "PC18", "PC19";
+ allwinner,function = "uart2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
- i2c2: i2c@01c2b400 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "allwinner,sun5i-a10s-i2c", "allwinner,sun4i-a10-i2c";
- reg = <0x01c2b400 0x400>;
- interrupts = <9>;
- clocks = <&apb1_gates 2>;
- status = "disabled";
- };
+ uart3_pins_a: uart3@0 {
+ allwinner,pins = "PG9", "PG10";
+ allwinner,function = "uart3";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
- timer@01c60000 {
- compatible = "allwinner,sun5i-a13-hstimer";
- reg = <0x01c60000 0x1000>;
- interrupts = <82>, <83>;
- clocks = <&ahb_gates 28>;
- };
+ emac_pins_a: emac0@0 {
+ allwinner,pins = "PA0", "PA1", "PA2",
+ "PA3", "PA4", "PA5", "PA6",
+ "PA7", "PA8", "PA9", "PA10",
+ "PA11", "PA12", "PA13", "PA14",
+ "PA15", "PA16";
+ allwinner,function = "emac";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mmc1_pins_a: mmc1@0 {
+ allwinner,pins = "PG3", "PG4", "PG5",
+ "PG6", "PG7", "PG8";
+ allwinner,function = "mmc1";
+ allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&sram_a {
+ emac_sram: sram-section@8000 {
+ compatible = "allwinner,sun4i-a10-sram-a3-a4";
+ reg = <0x8000 0x4000>;
+ status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts b/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
index 03aa04555630..990f9d61ae4d 100644
--- a/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
+++ b/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
@@ -16,11 +16,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 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
@@ -60,81 +55,72 @@
serial0 = &uart1;
};
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_h702>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
- cd-inverted;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_ldo3>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- pinctrl@01c20800 {
- mmc0_cd_pin_h702: mmc0_cd_pin@0 {
- allwinner,pins = "PG0";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
- };
-
- uart1: serial@01c28400 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart1_pins_b>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- reg = <0x34>;
- interrupts = <0>;
- };
- };
-
- i2c1: i2c@01c2b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
-
- pcf8563: rtc@51 {
- compatible = "nxp,pcf8563";
- reg = <0x51>;
- };
- };
-
- i2c2: i2c@01c2b400 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins_a>;
- status = "okay";
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
};
};
-#include "axp209.dtsi"
-
&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>;
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+
+ pcf8563: rtc@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_h702>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_h702: mmc0_cd_pin@0 {
+ allwinner,pins = "PG0";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+#include "axp209.dtsi"
+
&reg_dcdc2 {
regulator-always-on;
regulator-min-microvolt = <1000000>;
@@ -165,3 +151,14 @@
regulator-max-microvolt = <3300000>;
regulator-name = "vcc-wifi";
};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins_b>;
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_ldo3>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
index 03deb84268ce..ad84fe4276c9 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
@@ -17,11 +17,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 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
@@ -61,76 +56,8 @@
serial0 = &uart1;
};
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxinom>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
- cd-inverted;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- pinctrl@01c20800 {
- mmc0_cd_pin_olinuxinom: mmc0_cd_pin@0 {
- allwinner,pins = "PG0";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- led_pins_olinuxinom: led_pins@0 {
- allwinner,pins = "PG9";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_20_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- usb1_vbus_pin_olinuxinom: usb1_vbus_pin@0 {
- allwinner,pins = "PG11";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- uart1: serial@01c28400 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart1_pins_b>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
- };
-
- i2c1: i2c@01c2b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
- };
-
- i2c2: i2c@01c2b400 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins_a>;
- status = "okay";
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
};
leds {
@@ -144,10 +71,80 @@
default-state = "on";
};
};
+};
+
+&ehci0 {
+ status = "okay";
+};
- reg_usb1_vbus: usb1-vbus {
- pinctrl-0 = <&usb1_vbus_pin_olinuxinom>;
- gpio = <&pio 6 11 GPIO_ACTIVE_HIGH>;
- status = "okay";
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxinom>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_olinuxinom: mmc0_cd_pin@0 {
+ allwinner,pins = "PG0";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+
+ led_pins_olinuxinom: led_pins@0 {
+ allwinner,pins = "PG9";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb1_vbus_pin_olinuxinom: usb1_vbus_pin@0 {
+ allwinner,pins = "PG11";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_olinuxinom>;
+ gpio = <&pio 6 11 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins_b>;
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
index 6b24876ed462..42324005eb7c 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
@@ -18,11 +18,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 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
@@ -63,141 +58,143 @@
serial0 = &uart1;
};
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxino>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
- cd-inverted;
- status = "okay";
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- status = "okay";
- };
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_olinuxino>;
- ehci0: usb@01c14000 {
- status = "okay";
+ power {
+ gpios = <&pio 6 9 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
};
+ };
+};
- ohci0: usb@01c14400 {
- status = "okay";
- };
+&ehci0 {
+ status = "okay";
+};
- pinctrl@01c20800 {
- mmc0_cd_pin_olinuxino: mmc0_cd_pin@0 {
- allwinner,pins = "PG0";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- led_pins_olinuxino: led_pins@0 {
- allwinner,pins = "PG9";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_20_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- usb1_vbus_pin_olinuxino: usb1_vbus_pin@0 {
- allwinner,pins = "PG11";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
- lradc: lradc@01c22800 {
- vref-supply = <&reg_vcc3v0>;
- status = "okay";
-
- button@191 {
- label = "Volume Up";
- linux,code = <KEY_VOLUMEUP>;
- channel = <0>;
- voltage = <191274>;
- };
-
- button@392 {
- label = "Volume Down";
- linux,code = <KEY_VOLUMEDOWN>;
- channel = <0>;
- voltage = <392644>;
- };
-
- button@601 {
- label = "Menu";
- linux,code = <KEY_MENU>;
- channel = <0>;
- voltage = <601151>;
- };
-
- button@795 {
- label = "Enter";
- linux,code = <KEY_ENTER>;
- channel = <0>;
- voltage = <795090>;
- };
-
- button@987 {
- label = "Home";
- linux,code = <KEY_HOMEPAGE>;
- channel = <0>;
- voltage = <987387>;
- };
- };
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupts = <0>;
- uart1: serial@01c28400 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart1_pins_b>;
- status = "okay";
- };
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupts = <0>;
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
- i2c1: i2c@01c2b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
- };
+ button@191 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <191274>;
+ };
- i2c2: i2c@01c2b400 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins_a>;
- status = "okay";
- };
+ button@392 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <392644>;
};
- leds {
- compatible = "gpio-leds";
- pinctrl-names = "default";
- pinctrl-0 = <&led_pins_olinuxino>;
+ button@601 {
+ label = "Menu";
+ linux,code = <KEY_MENU>;
+ channel = <0>;
+ voltage = <601151>;
+ };
- power {
- gpios = <&pio 6 9 GPIO_ACTIVE_HIGH>;
- default-state = "on";
- };
+ button@795 {
+ label = "Enter";
+ linux,code = <KEY_ENTER>;
+ channel = <0>;
+ voltage = <795090>;
+ };
+
+ button@987 {
+ label = "Home";
+ linux,code = <KEY_HOMEPAGE>;
+ channel = <0>;
+ voltage = <987387>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxino>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_olinuxino: mmc0_cd_pin@0 {
+ allwinner,pins = "PG0";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ led_pins_olinuxino: led_pins@0 {
+ allwinner,pins = "PG9";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- reg_usb1_vbus: usb1-vbus {
- pinctrl-0 = <&usb1_vbus_pin_olinuxino>;
- gpio = <&pio 6 11 GPIO_ACTIVE_HIGH>;
- status = "okay";
+ usb1_vbus_pin_olinuxino: usb1_vbus_pin@0 {
+ allwinner,pins = "PG11";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
+
+&reg_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_olinuxino>;
+ gpio = <&pio 6 11 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins_b>;
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts b/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts
new file mode 100644
index 000000000000..514f159a14d4
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-a13-utoo-p66.dts
@@ -0,0 +1,226 @@
+/*
+ * 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>
+
+/ {
+ model = "Utoo P66";
+ compatible = "utoo,p66", "allwinner,sun5i-a13";
+
+ i2c_lcd: i2c@0 {
+ /* The lcd panel i2c interface is hooked up via gpios */
+ compatible = "i2c-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c_lcd_pins>;
+ gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>, /* PG12, sda */
+ <&pio 6 10 GPIO_ACTIVE_HIGH>; /* PG10, scl */
+ i2c-gpio,delay-us = <5>;
+ };
+};
+
+&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";
+
+ icn8318: touchscreen@40 {
+ compatible = "chipone,icn8318";
+ reg = <0x40>;
+ interrupt-parent = <&pio>;
+ interrupts = <9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */
+ pinctrl-names = "default";
+ pinctrl-0 = <&ts_wake_pin_p66>;
+ wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */
+ touchscreen-size-x = <800>;
+ touchscreen-size-y = <480>;
+ touchscreen-inverted-x;
+ touchscreen-swapped-x-y;
+ };
+
+ 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_p66>;
+ 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;
+ };
+};
+
+&pio {
+ mmc0_cd_pin_p66: mmc0_cd_pin@0 {
+ allwinner,pins = "PG0";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ i2c_lcd_pins: i2c_lcd_pin@0 {
+ allwinner,pins = "PG10", "PG12";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ ts_wake_pin_p66: ts_wake_pin@0 {
+ allwinner,pins = "PB3";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb0_vbus_pin_a: usb0_vbus_pin@0 {
+ allwinner,pins = "PB4";
+ 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 = <1500000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ 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 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
+ status = "okay";
+};
+
+&usbphy {
+ usb0_vbus-supply = <&reg_usb0_vbus>;
+ usb1_vbus-supply = <&reg_ldo3>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index 883cb4873688..976d4faa2179 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -3,20 +3,51 @@
*
* Maxime Ripard <maxime.ripard@free-electrons.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:
+ * 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.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * 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.
*/
#include "skeleton.dtsi"
-#include <dt-bindings/thermal/thermal.h>
+#include "sun5i.dtsi"
-#include <dt-bindings/dma/sun4i-a10.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include <dt-bindings/thermal/thermal.h>
/ {
interrupt-parent = <&intc>;
@@ -35,31 +66,6 @@
};
};
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- cpu0: cpu@0 {
- device_type = "cpu";
- compatible = "arm,cortex-a8";
- reg = <0x0>;
- clocks = <&cpu>;
- clock-latency = <244144>; /* 8 32k periods */
- operating-points = <
- /* kHz uV */
- 1008000 1400000
- 912000 1350000
- 864000 1300000
- 624000 1200000
- 576000 1200000
- 432000 1200000
- >;
- #cooling-cells = <2>;
- cooling-min-level = <0>;
- cooling-max-level = <5>;
- };
- };
-
thermal-zones {
cpu_thermal {
/* milliseconds */
@@ -92,126 +98,22 @@
};
};
- memory {
- reg = <0x40000000 0x20000000>;
- };
-
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- /*
- * This is a dummy clock, to be used as placeholder on
- * other mux clocks when a specific parent clock is not
- * yet implemented. It should be dropped when the driver
- * is complete.
- */
- dummy: dummy {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <0>;
- };
-
- osc24M: clk@01c20050 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-osc-clk";
- reg = <0x01c20050 0x4>;
- clock-frequency = <24000000>;
- clock-output-names = "osc24M";
- };
-
- osc32k: clk@0 {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <32768>;
- clock-output-names = "osc32k";
- };
-
- pll1: clk@01c20000 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-pll1-clk";
- reg = <0x01c20000 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "pll1";
- };
-
- pll4: clk@01c20018 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-pll1-clk";
- reg = <0x01c20018 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "pll4";
- };
-
- pll5: clk@01c20020 {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-pll5-clk";
- reg = <0x01c20020 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "pll5_ddr", "pll5_other";
- };
-
- pll6: clk@01c20028 {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-pll6-clk";
- reg = <0x01c20028 0x4>;
- clocks = <&osc24M>;
- clock-output-names = "pll6_sata", "pll6_other", "pll6";
- };
-
- /* dummy is 200M */
- cpu: cpu@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-cpu-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
- clock-output-names = "cpu";
- };
-
- axi: axi@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-axi-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&cpu>;
- clock-output-names = "axi";
- };
-
- axi_gates: clk@01c2005c {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-axi-gates-clk";
- reg = <0x01c2005c 0x4>;
- clocks = <&axi>;
- clock-output-names = "axi_dram";
- };
-
- ahb: ahb@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-ahb-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&axi>;
- clock-output-names = "ahb";
- };
-
ahb_gates: clk@01c20060 {
#clock-cells = <1>;
compatible = "allwinner,sun5i-a13-ahb-gates-clk";
reg = <0x01c20060 0x8>;
clocks = <&ahb>;
- clock-output-names = "ahb_usbotg", "ahb_ehci", "ahb_ohci",
- "ahb_ss", "ahb_dma", "ahb_bist", "ahb_mmc0",
- "ahb_mmc1", "ahb_mmc2", "ahb_nand", "ahb_sdram",
- "ahb_spi0", "ahb_spi1", "ahb_spi2", "ahb_stimer",
- "ahb_ve", "ahb_lcd", "ahb_csi", "ahb_de_be",
- "ahb_de_fe", "ahb_iep", "ahb_mali400";
- };
-
- apb0: apb0@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-apb0-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&ahb>;
- clock-output-names = "apb0";
+ clock-output-names = "ahb_usbotg", "ahb_ehci",
+ "ahb_ohci", "ahb_ss", "ahb_dma",
+ "ahb_bist", "ahb_mmc0", "ahb_mmc1",
+ "ahb_mmc2", "ahb_nand",
+ "ahb_sdram", "ahb_spi0",
+ "ahb_spi1", "ahb_spi2",
+ "ahb_stimer", "ahb_ve", "ahb_lcd",
+ "ahb_csi", "ahb_de_be",
+ "ahb_de_fe", "ahb_iep",
+ "ahb_mali400";
};
apb0_gates: clk@01c20068 {
@@ -219,15 +121,8 @@
compatible = "allwinner,sun5i-a13-apb0-gates-clk";
reg = <0x01c20068 0x4>;
clocks = <&apb0>;
- clock-output-names = "apb0_codec", "apb0_pio", "apb0_ir";
- };
-
- apb1: clk@01c20058 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-apb1-clk";
- reg = <0x01c20058 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
- clock-output-names = "apb1";
+ clock-output-names = "apb0_codec", "apb0_pio",
+ "apb0_ir";
};
apb1_gates: clk@01c2006c {
@@ -238,384 +133,39 @@
clock-output-names = "apb1_i2c0", "apb1_i2c1",
"apb1_i2c2", "apb1_uart1", "apb1_uart3";
};
-
- nand_clk: clk@01c20080 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c20080 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "nand";
- };
-
- ms_clk: clk@01c20084 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c20084 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "ms";
- };
-
- mmc0_clk: clk@01c20088 {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-mmc-clk";
- reg = <0x01c20088 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- 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 1>, <&pll5 1>;
- 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 1>, <&pll5 1>;
- clock-output-names = "mmc2",
- "mmc2_output",
- "mmc2_sample";
- };
-
- ts_clk: clk@01c20098 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c20098 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "ts";
- };
-
- ss_clk: clk@01c2009c {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c2009c 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "ss";
- };
-
- spi0_clk: clk@01c200a0 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c200a0 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "spi0";
- };
-
- spi1_clk: clk@01c200a4 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c200a4 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "spi1";
- };
-
- spi2_clk: clk@01c200a8 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c200a8 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "spi2";
- };
-
- ir0_clk: clk@01c200b0 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-mod0-clk";
- reg = <0x01c200b0 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "ir0";
- };
-
- usb_clk: clk@01c200cc {
- #clock-cells = <1>;
- #reset-cells = <1>;
- compatible = "allwinner,sun5i-a13-usb-clk";
- reg = <0x01c200cc 0x4>;
- clocks = <&pll6 1>;
- clock-output-names = "usb_ohci0", "usb_phy";
- };
-
- mbus_clk: clk@01c2015c {
- #clock-cells = <0>;
- compatible = "allwinner,sun5i-a13-mbus-clk";
- reg = <0x01c2015c 0x4>;
- clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
- clock-output-names = "mbus";
- };
};
+};
- soc@01c00000 {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- dma: dma-controller@01c02000 {
- compatible = "allwinner,sun4i-a10-dma";
- reg = <0x01c02000 0x1000>;
- interrupts = <27>;
- clocks = <&ahb_gates 6>;
- #dma-cells = <2>;
- };
-
- spi0: spi@01c05000 {
- compatible = "allwinner,sun4i-a10-spi";
- reg = <0x01c05000 0x1000>;
- interrupts = <10>;
- clocks = <&ahb_gates 20>, <&spi0_clk>;
- clock-names = "ahb", "mod";
- dmas = <&dma SUN4I_DMA_DEDICATED 27>,
- <&dma SUN4I_DMA_DEDICATED 26>;
- dma-names = "rx", "tx";
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
- };
-
- spi1: spi@01c06000 {
- compatible = "allwinner,sun4i-a10-spi";
- reg = <0x01c06000 0x1000>;
- interrupts = <11>;
- clocks = <&ahb_gates 21>, <&spi1_clk>;
- clock-names = "ahb", "mod";
- dmas = <&dma SUN4I_DMA_DEDICATED 9>,
- <&dma SUN4I_DMA_DEDICATED 8>;
- dma-names = "rx", "tx";
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
- };
-
- mmc0: mmc@01c0f000 {
- compatible = "allwinner,sun5i-a13-mmc";
- reg = <0x01c0f000 0x1000>;
- clocks = <&ahb_gates 8>,
- <&mmc0_clk 0>,
- <&mmc0_clk 1>,
- <&mmc0_clk 2>;
- clock-names = "ahb",
- "mmc",
- "output",
- "sample";
- interrupts = <32>;
- status = "disabled";
- };
-
- mmc2: mmc@01c11000 {
- compatible = "allwinner,sun5i-a13-mmc";
- reg = <0x01c11000 0x1000>;
- clocks = <&ahb_gates 10>,
- <&mmc2_clk 0>,
- <&mmc2_clk 1>,
- <&mmc2_clk 2>;
- clock-names = "ahb",
- "mmc",
- "output",
- "sample";
- interrupts = <34>;
- status = "disabled";
- };
-
- usbphy: phy@01c13400 {
- #phy-cells = <1>;
- compatible = "allwinner,sun5i-a13-usb-phy";
- reg = <0x01c13400 0x10 0x01c14800 0x4>;
- reg-names = "phy_ctrl", "pmu1";
- clocks = <&usb_clk 8>;
- clock-names = "usb_phy";
- resets = <&usb_clk 0>, <&usb_clk 1>;
- reset-names = "usb0_reset", "usb1_reset";
- status = "disabled";
- };
-
- ehci0: usb@01c14000 {
- compatible = "allwinner,sun5i-a13-ehci", "generic-ehci";
- reg = <0x01c14000 0x100>;
- interrupts = <39>;
- clocks = <&ahb_gates 1>;
- phys = <&usbphy 1>;
- phy-names = "usb";
- status = "disabled";
- };
-
- ohci0: usb@01c14400 {
- compatible = "allwinner,sun5i-a13-ohci", "generic-ohci";
- reg = <0x01c14400 0x100>;
- interrupts = <40>;
- clocks = <&usb_clk 6>, <&ahb_gates 2>;
- phys = <&usbphy 1>;
- phy-names = "usb";
- status = "disabled";
- };
-
- spi2: spi@01c17000 {
- compatible = "allwinner,sun4i-a10-spi";
- reg = <0x01c17000 0x1000>;
- interrupts = <12>;
- clocks = <&ahb_gates 22>, <&spi2_clk>;
- clock-names = "ahb", "mod";
- dmas = <&dma SUN4I_DMA_DEDICATED 29>,
- <&dma SUN4I_DMA_DEDICATED 28>;
- dma-names = "rx", "tx";
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
- };
-
- intc: interrupt-controller@01c20400 {
- compatible = "allwinner,sun4i-a10-ic";
- reg = <0x01c20400 0x400>;
- interrupt-controller;
- #interrupt-cells = <1>;
- };
-
- pio: pinctrl@01c20800 {
- compatible = "allwinner,sun5i-a13-pinctrl";
- reg = <0x01c20800 0x400>;
- interrupts = <28>;
- clocks = <&apb0_gates 5>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- #size-cells = <0>;
- #gpio-cells = <3>;
-
- uart1_pins_a: uart1@0 {
- allwinner,pins = "PE10", "PE11";
- allwinner,function = "uart1";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- uart1_pins_b: uart1@1 {
- allwinner,pins = "PG3", "PG4";
- allwinner,function = "uart1";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- i2c0_pins_a: i2c0@0 {
- allwinner,pins = "PB0", "PB1";
- allwinner,function = "i2c0";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- i2c1_pins_a: i2c1@0 {
- allwinner,pins = "PB15", "PB16";
- allwinner,function = "i2c1";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- i2c2_pins_a: i2c2@0 {
- allwinner,pins = "PB17", "PB18";
- allwinner,function = "i2c2";
- 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>;
- };
- };
-
- timer@01c20c00 {
- compatible = "allwinner,sun4i-a10-timer";
- reg = <0x01c20c00 0x90>;
- interrupts = <22>;
- clocks = <&osc24M>;
- };
-
- wdt: watchdog@01c20c90 {
- compatible = "allwinner,sun4i-a10-wdt";
- reg = <0x01c20c90 0x10>;
- };
-
- lradc: lradc@01c22800 {
- compatible = "allwinner,sun4i-a10-lradc-keys";
- reg = <0x01c22800 0x100>;
- interrupts = <31>;
- status = "disabled";
- };
-
- sid: eeprom@01c23800 {
- compatible = "allwinner,sun4i-a10-sid";
- reg = <0x01c23800 0x10>;
- };
-
- rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-a10-ts";
- reg = <0x01c25000 0x100>;
- interrupts = <29>;
- #thermal-sensor-cells = <0>;
- };
-
- uart1: serial@01c28400 {
- compatible = "snps,dw-apb-uart";
- reg = <0x01c28400 0x400>;
- interrupts = <2>;
- reg-shift = <2>;
- reg-io-width = <4>;
- clocks = <&apb1_gates 17>;
- status = "disabled";
- };
-
- uart3: serial@01c28c00 {
- compatible = "snps,dw-apb-uart";
- reg = <0x01c28c00 0x400>;
- interrupts = <4>;
- reg-shift = <2>;
- reg-io-width = <4>;
- clocks = <&apb1_gates 19>;
- status = "disabled";
- };
-
- i2c0: i2c@01c2ac00 {
- compatible = "allwinner,sun5i-a13-i2c", "allwinner,sun4i-a10-i2c";
- reg = <0x01c2ac00 0x400>;
- interrupts = <7>;
- clocks = <&apb1_gates 0>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
- };
+&cpu0 {
+ clock-latency = <244144>; /* 8 32k periods */
+ operating-points = <
+ /* kHz uV */
+ 1008000 1400000
+ 912000 1350000
+ 864000 1300000
+ 624000 1200000
+ 576000 1200000
+ 432000 1200000
+ >;
+ #cooling-cells = <2>;
+ cooling-min-level = <0>;
+ cooling-max-level = <5>;
+};
- i2c1: i2c@01c2b000 {
- compatible = "allwinner,sun5i-a13-i2c", "allwinner,sun4i-a10-i2c";
- reg = <0x01c2b000 0x400>;
- interrupts = <8>;
- clocks = <&apb1_gates 1>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
- };
+&pio {
+ compatible = "allwinner,sun5i-a13-pinctrl";
- i2c2: i2c@01c2b400 {
- compatible = "allwinner,sun5i-a13-i2c", "allwinner,sun4i-a10-i2c";
- reg = <0x01c2b400 0x400>;
- interrupts = <9>;
- clocks = <&apb1_gates 2>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
- };
+ uart1_pins_a: uart1@0 {
+ allwinner,pins = "PE10", "PE11";
+ allwinner,function = "uart1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
- timer@01c60000 {
- compatible = "allwinner,sun5i-a13-hstimer";
- reg = <0x01c60000 0x1000>;
- interrupts = <82>, <83>;
- clocks = <&ahb_gates 28>;
- };
+ uart1_pins_b: uart1@1 {
+ allwinner,pins = "PG3", "PG4";
+ allwinner,function = "uart1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi
new file mode 100644
index 000000000000..54b097830434
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i.dtsi
@@ -0,0 +1,609 @@
+/*
+ * Copyright 2012-2015 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@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 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.
+ */
+
+#include "skeleton.dtsi"
+
+#include <dt-bindings/dma/sun4i-a10.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ interrupt-parent = <&intc>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a8";
+ reg = <0x0>;
+ clocks = <&cpu>;
+ };
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ /*
+ * This is a dummy clock, to be used as placeholder on
+ * other mux clocks when a specific parent clock is not
+ * yet implemented. It should be dropped when the driver
+ * is complete.
+ */
+ dummy: dummy {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <0>;
+ };
+
+ osc24M: clk@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-osc-clk";
+ reg = <0x01c20050 0x4>;
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24M";
+ };
+
+ osc32k: clk@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "osc32k";
+ };
+
+ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll1";
+ };
+
+ pll4: clk@01c20018 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20018 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll4";
+ };
+
+ pll5: clk@01c20020 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-pll5-clk";
+ reg = <0x01c20020 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll5_ddr", "pll5_other";
+ };
+
+ pll6: clk@01c20028 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-pll6-clk";
+ reg = <0x01c20028 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll6_sata", "pll6_other", "pll6";
+ };
+
+ /* dummy is 200M */
+ cpu: cpu@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
+ clock-output-names = "cpu";
+ };
+
+ axi: axi@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-axi-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&cpu>;
+ clock-output-names = "axi";
+ };
+
+ ahb: ahb@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun5i-a13-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&axi>, <&cpu>, <&pll6 1>;
+ clock-output-names = "ahb";
+ /*
+ * Use PLL6 as parent, instead of CPU/AXI
+ * which has rate changes due to cpufreq
+ */
+ assigned-clocks = <&ahb>;
+ assigned-clock-parents = <&pll6 1>;
+ };
+
+ apb0: apb0@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb>;
+ clock-output-names = "apb0";
+ };
+
+ apb1: clk@01c20058 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-apb1-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
+ clock-output-names = "apb1";
+ };
+
+ axi_gates: clk@01c2005c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-axi-gates-clk";
+ reg = <0x01c2005c 0x4>;
+ clocks = <&axi>;
+ clock-output-names = "axi_dram";
+ };
+
+ nand_clk: clk@01c20080 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20080 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "nand";
+ };
+
+ ms_clk: clk@01c20084 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20084 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ms";
+ };
+
+ mmc0_clk: clk@01c20088 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
+ reg = <0x01c20088 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ 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 1>, <&pll5 1>;
+ 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 1>, <&pll5 1>;
+ clock-output-names = "mmc2",
+ "mmc2_output",
+ "mmc2_sample";
+ };
+
+ ts_clk: clk@01c20098 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20098 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ts";
+ };
+
+ ss_clk: clk@01c2009c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2009c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ss";
+ };
+
+ spi0_clk: clk@01c200a0 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a0 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi0";
+ };
+
+ spi1_clk: clk@01c200a4 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a4 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi1";
+ };
+
+ spi2_clk: clk@01c200a8 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a8 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi2";
+ };
+
+ ir0_clk: clk@01c200b0 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200b0 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ir0";
+ };
+
+ usb_clk: clk@01c200cc {
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ compatible = "allwinner,sun5i-a13-usb-clk";
+ reg = <0x01c200cc 0x4>;
+ clocks = <&pll6 1>;
+ clock-output-names = "usb_ohci0", "usb_phy";
+ };
+
+ mbus_clk: clk@01c2015c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun5i-a13-mbus-clk";
+ reg = <0x01c2015c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mbus";
+ };
+ };
+
+ soc@01c00000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram-controller@01c00000 {
+ compatible = "allwinner,sun4i-a10-sram-controller";
+ reg = <0x01c00000 0x30>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram_a: sram@00000000 {
+ compatible = "mmio-sram";
+ reg = <0x00000000 0xc000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00000000 0xc000>;
+ };
+
+ sram_d: sram@00010000 {
+ compatible = "mmio-sram";
+ reg = <0x00010000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00010000 0x1000>;
+
+ otg_sram: sram-section@0000 {
+ compatible = "allwinner,sun4i-a10-sram-d";
+ reg = <0x0000 0x1000>;
+ status = "disabled";
+ };
+ };
+ };
+
+ dma: dma-controller@01c02000 {
+ compatible = "allwinner,sun4i-a10-dma";
+ reg = <0x01c02000 0x1000>;
+ interrupts = <27>;
+ clocks = <&ahb_gates 6>;
+ #dma-cells = <2>;
+ };
+
+ spi0: spi@01c05000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c05000 0x1000>;
+ interrupts = <10>;
+ clocks = <&ahb_gates 20>, <&spi0_clk>;
+ clock-names = "ahb", "mod";
+ dmas = <&dma SUN4I_DMA_DEDICATED 27>,
+ <&dma SUN4I_DMA_DEDICATED 26>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ spi1: spi@01c06000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c06000 0x1000>;
+ interrupts = <11>;
+ clocks = <&ahb_gates 21>, <&spi1_clk>;
+ clock-names = "ahb", "mod";
+ dmas = <&dma SUN4I_DMA_DEDICATED 9>,
+ <&dma SUN4I_DMA_DEDICATED 8>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mmc0: mmc@01c0f000 {
+ compatible = "allwinner,sun5i-a13-mmc";
+ reg = <0x01c0f000 0x1000>;
+ clocks = <&ahb_gates 8>,
+ <&mmc0_clk 0>,
+ <&mmc0_clk 1>,
+ <&mmc0_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
+ interrupts = <32>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mmc1: mmc@01c10000 {
+ compatible = "allwinner,sun5i-a13-mmc";
+ reg = <0x01c10000 0x1000>;
+ clocks = <&ahb_gates 9>,
+ <&mmc1_clk 0>,
+ <&mmc1_clk 1>,
+ <&mmc1_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
+ interrupts = <33>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mmc2: mmc@01c11000 {
+ compatible = "allwinner,sun5i-a13-mmc";
+ reg = <0x01c11000 0x1000>;
+ clocks = <&ahb_gates 10>,
+ <&mmc2_clk 0>,
+ <&mmc2_clk 1>,
+ <&mmc2_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
+ interrupts = <34>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ usbphy: phy@01c13400 {
+ #phy-cells = <1>;
+ compatible = "allwinner,sun5i-a13-usb-phy";
+ reg = <0x01c13400 0x10 0x01c14800 0x4>;
+ reg-names = "phy_ctrl", "pmu1";
+ clocks = <&usb_clk 8>;
+ clock-names = "usb_phy";
+ resets = <&usb_clk 0>, <&usb_clk 1>;
+ reset-names = "usb0_reset", "usb1_reset";
+ status = "disabled";
+ };
+
+ ehci0: usb@01c14000 {
+ compatible = "allwinner,sun5i-a13-ehci", "generic-ehci";
+ reg = <0x01c14000 0x100>;
+ interrupts = <39>;
+ clocks = <&ahb_gates 1>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci0: usb@01c14400 {
+ compatible = "allwinner,sun5i-a13-ohci", "generic-ohci";
+ reg = <0x01c14400 0x100>;
+ interrupts = <40>;
+ clocks = <&usb_clk 6>, <&ahb_gates 2>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ spi2: spi@01c17000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c17000 0x1000>;
+ interrupts = <12>;
+ clocks = <&ahb_gates 22>, <&spi2_clk>;
+ clock-names = "ahb", "mod";
+ dmas = <&dma SUN4I_DMA_DEDICATED 29>,
+ <&dma SUN4I_DMA_DEDICATED 28>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ intc: interrupt-controller@01c20400 {
+ compatible = "allwinner,sun4i-a10-ic";
+ reg = <0x01c20400 0x400>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ pio: pinctrl@01c20800 {
+ reg = <0x01c20800 0x400>;
+ interrupts = <28>;
+ clocks = <&apb0_gates 5>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ #size-cells = <0>;
+ #gpio-cells = <3>;
+
+ i2c0_pins_a: i2c0@0 {
+ allwinner,pins = "PB0", "PB1";
+ allwinner,function = "i2c0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2c1_pins_a: i2c1@0 {
+ allwinner,pins = "PB15", "PB16";
+ allwinner,function = "i2c1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2c2_pins_a: i2c2@0 {
+ allwinner,pins = "PB17", "PB18";
+ allwinner,function = "i2c2";
+ 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>;
+ };
+
+ mmc2_pins_a: mmc2@0 {
+ allwinner,pins = "PC6", "PC7", "PC8", "PC9",
+ "PC10", "PC11", "PC12", "PC13",
+ "PC14", "PC15";
+ allwinner,function = "mmc2";
+ allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+ };
+
+ timer@01c20c00 {
+ compatible = "allwinner,sun4i-a10-timer";
+ reg = <0x01c20c00 0x90>;
+ interrupts = <22>;
+ clocks = <&osc24M>;
+ };
+
+ wdt: watchdog@01c20c90 {
+ compatible = "allwinner,sun4i-a10-wdt";
+ reg = <0x01c20c90 0x10>;
+ };
+
+ lradc: lradc@01c22800 {
+ compatible = "allwinner,sun4i-a10-lradc-keys";
+ reg = <0x01c22800 0x100>;
+ interrupts = <31>;
+ status = "disabled";
+ };
+
+ sid: eeprom@01c23800 {
+ compatible = "allwinner,sun4i-a10-sid";
+ reg = <0x01c23800 0x10>;
+ };
+
+ rtp: rtp@01c25000 {
+ compatible = "allwinner,sun5i-a13-ts";
+ reg = <0x01c25000 0x100>;
+ interrupts = <29>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ uart1: serial@01c28400 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28400 0x400>;
+ interrupts = <2>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb1_gates 17>;
+ status = "disabled";
+ };
+
+ uart3: serial@01c28c00 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c28c00 0x400>;
+ interrupts = <4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb1_gates 19>;
+ status = "disabled";
+ };
+
+ i2c0: i2c@01c2ac00 {
+ compatible = "allwinner,sun4i-a10-i2c";
+ reg = <0x01c2ac00 0x400>;
+ interrupts = <7>;
+ clocks = <&apb1_gates 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c1: i2c@01c2b000 {
+ compatible = "allwinner,sun4i-a10-i2c";
+ reg = <0x01c2b000 0x400>;
+ interrupts = <8>;
+ clocks = <&apb1_gates 1>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c2: i2c@01c2b400 {
+ compatible = "allwinner,sun4i-a10-i2c";
+ reg = <0x01c2b400 0x400>;
+ interrupts = <9>;
+ clocks = <&apb1_gates 2>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ timer@01c60000 {
+ compatible = "allwinner,sun5i-a13-hstimer";
+ reg = <0x01c60000 0x1000>;
+ interrupts = <82>, <83>;
+ clocks = <&ahb_gates 28>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts b/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts
index be9f5ee6b59e..2f8cfab771e2 100644
--- a/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts
+++ b/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts
@@ -18,11 +18,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 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
@@ -58,39 +53,41 @@
model = "Allwinner A31 APP4 EVB1 Evaluation Board";
compatible = "allwinner,app4-evb1", "allwinner,sun6i-a31";
+ aliases {
+ serial0 = &uart0;
+ };
+
chosen {
- bootargs = "earlyprintk console=ttyS0,115200";
+ stdout-path = "serial0:115200n8";
};
+};
- soc@01c00000 {
- pio: pinctrl@01c20800 {
- usb1_vbus_pin_a: usb1_vbus_pin@0 {
- allwinner,pins = "PH27";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
+&ehci0 {
+ status = "okay";
+};
- usbphy: phy@01c19400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- status = "okay";
- };
+&pio {
+ usb1_vbus_pin_a: usb1_vbus_pin@0 {
+ allwinner,pins = "PH27";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
- ehci0: usb@01c1a000 {
- status = "okay";
- };
+&reg_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_a>;
+ gpio = <&pio 7 27 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
- };
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
- reg_usb1_vbus: usb1-vbus {
- pinctrl-0 = <&usb1_vbus_pin_a>;
- gpio = <&pio 7 27 GPIO_ACTIVE_HIGH>;
- status = "okay";
- };
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/sun6i-a31-colombus.dts b/arch/arm/boot/dts/sun6i-a31-colombus.dts
index 84630e56acd7..0cf9926d1e93 100644
--- a/arch/arm/boot/dts/sun6i-a31-colombus.dts
+++ b/arch/arm/boot/dts/sun6i-a31-colombus.dts
@@ -18,11 +18,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 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
@@ -58,79 +53,81 @@
model = "WITS A31 Colombus Evaluation Board";
compatible = "wits,colombus", "allwinner,sun6i-a31";
+ aliases {
+ serial0 = &uart0;
+ };
+
chosen {
- bootargs = "earlyprintk console=ttyS0,115200";
+ stdout-path = "serial0:115200n8";
};
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "fail";
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_colombus>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
+ cd-inverted;
+ status = "okay";
+};
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_colombus>;
- vmmc-supply = <&reg_vcc3v0>;
- bus-width = <4>;
- cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
- cd-inverted;
- status = "okay";
- };
-
- usbphy: phy@01c19400 {
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci1: usb@01c1b000 {
- status = "okay";
- };
-
- pio: pinctrl@01c20800 {
- mmc0_pins_a: mmc0@0 {
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- mmc0_cd_pin_colombus: mmc0_cd_pin@0 {
- allwinner,pins = "PA8";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- usb2_vbus_pin_colombus: usb2_vbus_pin@0 {
- allwinner,pins = "PH24";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "fail";
- };
-
- i2c1: i2c@01c2b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
- };
-
- i2c2: i2c@01c2b400 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins_a>;
- status = "okay";
- };
+&mmc0_pins_a {
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&pio {
+ mmc0_cd_pin_colombus: mmc0_cd_pin@0 {
+ allwinner,pins = "PA8";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
- reg_usb2_vbus: usb2-vbus {
- pinctrl-names = "default";
- pinctrl-0 = <&usb2_vbus_pin_colombus>;
- gpio = <&pio 7 24 GPIO_ACTIVE_HIGH>;
- status = "okay";
+ usb2_vbus_pin_colombus: usb2_vbus_pin@0 {
+ allwinner,pins = "PH24";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
+
+&reg_usb2_vbus {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb2_vbus_pin_colombus>;
+ gpio = <&pio 7 24 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
index 8b61b1b342e0..d0cfadac0691 100644
--- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -18,11 +18,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 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
@@ -58,8 +53,17 @@
model = "Merrii A31 Hummingbird";
compatible = "merrii,a31-hummingbird", "allwinner,sun6i-a31";
+ aliases {
+ serial0 = &uart0;
+ };
+
chosen {
- bootargs = "earlyprintk console=ttyS0,115200";
+ stdout-path = "serial0:115200n8";
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&pio 6 10 GPIO_ACTIVE_LOW>; /* PG10 */
};
};
@@ -106,10 +110,16 @@
};
};
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir_pins_a>;
+ status = "okay";
+};
+
&mmc0 {
pinctrl-names = "default";
pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_hummingbird>;
- vmmc-supply = <&reg_vcc3v0>;
+ vmmc-supply = <&vcc_3v0>;
bus-width = <4>;
cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
cd-inverted;
@@ -121,6 +131,16 @@
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_a>, <&wifi_reset_pin_hummingbird>;
+ vmmc-supply = <&vcc_wifi>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+};
+
&ohci0 {
status = "okay";
};
@@ -132,6 +152,80 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+
+ wifi_reset_pin_hummingbird: wifi_reset_pin@0 {
+ allwinner,pins = "PG10";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&p2wi {
+ status = "okay";
+
+ axp221: pmic@68 {
+ compatible = "x-powers,axp221";
+ reg = <0x68>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ dcdc1-supply = <&vcc_3v0>;
+ dcdc5-supply = <&vcc_dram>;
+
+ regulators {
+ x-powers,dcdc-freq = <3000>;
+
+ vcc_3v0: dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "vcc-3v0";
+ };
+
+ vdd_cpu: dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-cpu";
+ };
+
+ vdd_gpu: dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-gpu";
+ };
+
+ vdd_sys_dll: dcdc4 {
+ regulator-always-on;
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-name = "vdd-sys-dll";
+ };
+
+ vcc_dram: dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+ };
+
+ vcc_wifi: aldo1 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc_wifi";
+ };
+
+ avcc: aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+ };
+ };
+ };
};
&reg_usb1_vbus {
diff --git a/arch/arm/boot/dts/sun6i-a31-i7.dts b/arch/arm/boot/dts/sun6i-a31-i7.dts
new file mode 100644
index 000000000000..e9185dad67ee
--- /dev/null
+++ b/arch/arm/boot/dts/sun6i-a31-i7.dts
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2015 Marcus Cooper <codekipper@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 "sun6i-a31.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Mele I7 Quad top set box";
+ compatible = "mele,i7", "allwinner,sun6i-a31";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_i7>;
+
+ blue {
+ label = "i7:blue:usr";
+ gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
+
+&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>;
+ };
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir_pins_a>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_i7>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
+ cd-inverted;
+ status = "okay";
+};
+
+&pio {
+ led_pins_i7: led_pins@0 {
+ allwinner,pins = "PH13";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mmc0_cd_pin_i7: mmc0_cd_pin@0 {
+ allwinner,pins = "PH22";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb1_vbus_pin_i7: usb1_vbus_pin@0 {
+ allwinner,pins = "PC27";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_usb1_vbus {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb1_vbus_pin_i7>;
+ gpio = <&pio 2 27 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun6i-a31-m9.dts b/arch/arm/boot/dts/sun6i-a31-m9.dts
index 139a21e6b695..6e0e5687a09c 100644
--- a/arch/arm/boot/dts/sun6i-a31-m9.dts
+++ b/arch/arm/boot/dts/sun6i-a31-m9.dts
@@ -16,11 +16,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 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
@@ -53,100 +48,102 @@
#include <dt-bindings/pinctrl/sun4i-a10.h>
/ {
- model = "Mele M9 / A1000G Quad top set box";
+ model = "Mele M9 top set box";
compatible = "mele,m9", "allwinner,sun6i-a31";
+ aliases {
+ serial0 = &uart0;
+ };
+
chosen {
- bootargs = "earlyprintk console=ttyS0,115200";
+ stdout-path = "serial0:115200n8";
};
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_m9>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
- cd-inverted;
- status = "okay";
- };
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_m9>;
- usbphy: phy@01c19400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- status = "okay";
+ blue {
+ label = "m9:blue:usr";
+ gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>;
};
+ };
+};
- ehci0: usb@01c1a000 {
- status = "okay";
- };
+&ehci0 {
+ status = "okay";
+};
- ehci1: usb@01c1b000 {
- status = "okay";
- };
+&ehci1 {
+ status = "okay";
+};
- pio: pinctrl@01c20800 {
- led_pins_m9: led_pins@0 {
- allwinner,pins = "PH13";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- mmc0_cd_pin_m9: mmc0_cd_pin@0 {
- allwinner,pins = "PH22";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- usb1_vbus_pin_m9: usb1_vbus_pin@0 {
- allwinner,pins = "PC27";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_mii_a>;
+ phy = <&phy1>;
+ phy-mode = "mii";
+ status = "okay";
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
- gmac: ethernet@01c30000 {
- pinctrl-names = "default";
- pinctrl-0 = <&gmac_pins_mii_a>;
- phy = <&phy1>;
- phy-mode = "mii";
- status = "okay";
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir_pins_a>;
+ status = "okay";
+};
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_m9>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
+ cd-inverted;
+ status = "okay";
+};
- ir@01f02000 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir_pins_a>;
- status = "okay";
- };
+&pio {
+ led_pins_m9: led_pins@0 {
+ allwinner,pins = "PH13";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- leds {
- compatible = "gpio-leds";
- pinctrl-names = "default";
- pinctrl-0 = <&led_pins_m9>;
-
- blue {
- label = "m9:blue:usr";
- gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>;
- };
+ mmc0_cd_pin_m9: mmc0_cd_pin@0 {
+ allwinner,pins = "PH22";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
- reg_usb1_vbus: usb1-vbus {
- pinctrl-names = "default";
- pinctrl-0 = <&usb1_vbus_pin_m9>;
- gpio = <&pio 2 27 GPIO_ACTIVE_HIGH>;
- status = "okay";
+ usb1_vbus_pin_m9: usb1_vbus_pin@0 {
+ allwinner,pins = "PC27";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
+
+&reg_usb1_vbus {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb1_vbus_pin_m9>;
+ gpio = <&pio 2 27 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
new file mode 100644
index 000000000000..4404f37d132e
--- /dev/null
+++ b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2014 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 "sun6i-a31.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Mele A1000G Quad top set box";
+ compatible = "mele,a1000g-quad", "allwinner,sun6i-a31";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_m9>;
+
+ blue {
+ label = "m9:blue:usr";
+ gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
+
+&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>;
+ };
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir_pins_a>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_m9>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
+ cd-inverted;
+ status = "okay";
+};
+
+&pio {
+ led_pins_m9: led_pins@0 {
+ allwinner,pins = "PH13";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mmc0_cd_pin_m9: mmc0_cd_pin@0 {
+ allwinner,pins = "PH22";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb1_vbus_pin_m9: usb1_vbus_pin@0 {
+ allwinner,pins = "PC27";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_usb1_vbus {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb1_vbus_pin_m9>;
+ gpio = <&pio 2 27 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index fa2f403ccf28..008047a018cf 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -18,11 +18,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 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
@@ -50,6 +45,7 @@
#include "skeleton.dtsi"
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/thermal.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
@@ -66,7 +62,8 @@
ranges;
framebuffer@0 {
- compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+ compatible = "allwinner,simple-framebuffer",
+ "simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-hdmi";
clocks = <&pll6 0>;
status = "disabled";
@@ -96,10 +93,22 @@
#address-cells = <1>;
#size-cells = <0>;
- cpu@0 {
+ cpu0: cpu@0 {
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
+ clocks = <&cpu>;
+ clock-latency = <244144>; /* 8 32k periods */
+ operating-points = <
+ /* kHz uV */
+ 1008000 1200000
+ 864000 1200000
+ 720000 1100000
+ 480000 1000000
+ >;
+ #cooling-cells = <2>;
+ cooling-min-level = <0>;
+ cooling-max-level = <3>;
};
cpu@1 {
@@ -121,6 +130,38 @@
};
};
+ thermal-zones {
+ cpu_thermal {
+ /* milliseconds */
+ polling-delay-passive = <250>;
+ polling-delay = <1000>;
+ thermal-sensors = <&rtp>;
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert0>;
+ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+
+ trips {
+ cpu_alert0: cpu_alert0 {
+ /* milliCelsius */
+ temperature = <70000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_crit: cpu_crit {
+ /* milliCelsius */
+ temperature = <100000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+ };
+
memory {
reg = <0x40000000 0x80000000>;
};
@@ -196,6 +237,14 @@
reg = <0x01c20054 0x4>;
clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>;
clock-output-names = "ahb1";
+
+ /*
+ * Clock AHB1 from PLL6, instead of CPU/AXI which
+ * has rate changes due to cpufreq. Also the DMA
+ * controller requires AHB1 clocked from PLL6.
+ */
+ assigned-clocks = <&ahb1>;
+ assigned-clock-parents = <&pll6 0>;
};
ahb1_gates: clk@01c20060 {
@@ -251,9 +300,10 @@
reg = <0x01c2006c 0x4>;
clocks = <&apb2>;
clock-output-names = "apb2_i2c0", "apb2_i2c1",
- "apb2_i2c2", "apb2_i2c3", "apb2_uart0",
- "apb2_uart1", "apb2_uart2", "apb2_uart3",
- "apb2_uart4", "apb2_uart5";
+ "apb2_i2c2", "apb2_i2c3",
+ "apb2_uart0", "apb2_uart1",
+ "apb2_uart2", "apb2_uart3",
+ "apb2_uart4", "apb2_uart5";
};
mmc0_clk: clk@01c20088 {
@@ -330,7 +380,7 @@
usb_clk: clk@01c200cc {
#clock-cells = <1>;
- #reset-cells = <1>;
+ #reset-cells = <1>;
compatible = "allwinner,sun6i-a31-usb-clk";
reg = <0x01c200cc 0x4>;
clocks = <&osc24M>;
@@ -340,10 +390,13 @@
};
/*
- * The following two are dummy clocks, placeholders used in the gmac_tx
- * clock. The gmac driver will choose one parent depending on the PHY
- * interface mode, using clk_set_rate auto-reparenting.
- * The actual TX clock rate is not controlled by the gmac_tx clock.
+ * The following two are dummy clocks, placeholders
+ * used in the gmac_tx clock. The gmac driver will
+ * choose one parent depending on the PHY interface
+ * mode, using clk_set_rate auto-reparenting.
+ *
+ * The actual TX clock rate is not controlled by the
+ * gmac_tx clock.
*/
mii_phy_tx_clk: clk@1 {
#clock-cells = <0>;
@@ -381,10 +434,6 @@
clocks = <&ahb1_gates 6>;
resets = <&ahb1_rst 6>;
#dma-cells = <1>;
-
- /* DMA controller requires AHB1 clocked from PLL6 */
- assigned-clocks = <&ahb1>;
- assigned-clock-parents = <&pll6 0>;
};
mmc0: mmc@01c0f000 {
@@ -402,6 +451,8 @@
reset-names = "ahb";
interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc1: mmc@01c10000 {
@@ -419,6 +470,8 @@
reset-names = "ahb";
interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc2: mmc@01c11000 {
@@ -436,6 +489,8 @@
reset-names = "ahb";
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc3: mmc@01c12000 {
@@ -453,6 +508,8 @@
reset-names = "ahb";
interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
usbphy: phy@01c19400 {
@@ -575,12 +632,21 @@
};
mmc0_pins_a: mmc0@0 {
- allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
+ allwinner,pins = "PF0", "PF1", "PF2",
+ "PF3", "PF4", "PF5";
allwinner,function = "mmc0";
allwinner,drive = <SUN4I_PINCTRL_30_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+ 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>;
+ };
+
gmac_pins_mii_a: gmac_mii@0 {
allwinner,pins = "PA0", "PA1", "PA2", "PA3",
"PA8", "PA9", "PA11",
@@ -805,7 +871,8 @@
};
timer@01c60000 {
- compatible = "allwinner,sun6i-a31-hstimer", "allwinner,sun7i-a20-hstimer";
+ compatible = "allwinner,sun6i-a31-hstimer",
+ "allwinner,sun7i-a20-hstimer";
reg = <0x01c60000 0x1000>;
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
@@ -896,7 +963,8 @@
ar100: ar100_clk {
compatible = "allwinner,sun6i-a31-ar100-clk";
#clock-cells = <0>;
- clocks = <&osc32k>, <&osc24M>, <&pll6 0>, <&pll6 0>;
+ clocks = <&osc32k>, <&osc24M>, <&pll6 0>,
+ <&pll6 0>;
clock-output-names = "ar100";
};
@@ -973,6 +1041,27 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ p2wi_pins: p2wi {
+ allwinner,pins = "PL0", "PL1";
+ allwinner,function = "s_p2wi";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+ };
+
+ p2wi: i2c@01f03400 {
+ compatible = "allwinner,sun6i-a31-p2wi";
+ reg = <0x01f03400 0x400>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&apb0_gates 3>;
+ clock-frequency = <100000>;
+ resets = <&apb0_rst 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&p2wi_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
};
};
diff --git a/arch/arm/boot/dts/sun6i-a31s-cs908.dts b/arch/arm/boot/dts/sun6i-a31s-cs908.dts
index bc3734f67cf0..1e2411a2bcea 100644
--- a/arch/arm/boot/dts/sun6i-a31s-cs908.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-cs908.dts
@@ -16,11 +16,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 library; 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
@@ -53,10 +48,14 @@
/ {
model = "CSQ CS908 top set box";
compatible = "csq,cs908", "allwinner,sun6i-a31s";
-};
-&usbphy {
- status = "okay";
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
};
&ehci0 {
@@ -67,25 +66,6 @@
status = "okay";
};
-&ohci1 {
- status = "okay";
-};
-
-&pio {
- usb1_vbus_pin_csq908: usb1_vbus_pin@0 {
- allwinner,pins = "PC27";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-};
-
-&uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
-};
-
&gmac {
pinctrl-names = "default";
pinctrl-0 = <&gmac_pins_mii_a>;
@@ -102,3 +82,17 @@
pinctrl-0 = <&ir_pins_a>;
status = "okay";
};
+
+&ohci1 {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun6i-a31s.dtsi b/arch/arm/boot/dts/sun6i-a31s.dtsi
index eaf5ec8fd459..c17a32771b98 100644
--- a/arch/arm/boot/dts/sun6i-a31s.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31s.dtsi
@@ -16,11 +16,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 library; 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
diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi.dts b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
index 5dd139e7792e..9f7b472e6725 100644
--- a/arch/arm/boot/dts/sun7i-a20-bananapi.dts
+++ b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
@@ -18,11 +18,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 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
@@ -65,160 +60,164 @@
serial2 = &uart7;
};
- soc@01c00000 {
- spi0: spi@01c05000 {
- pinctrl-names = "default";
- pinctrl-0 = <&spi0_pins_a>;
- status = "okay";
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bananapi>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */
- cd-inverted;
- status = "okay";
- };
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_bananapi>;
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
+ green {
+ label = "bananapi:green:usr";
+ gpios = <&pio 7 24 GPIO_ACTIVE_HIGH>;
};
+ };
- ehci0: usb@01c14000 {
- status = "okay";
- };
+ reg_gmac_3v3: gmac-3v3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_power_pin_bananapi>;
+ regulator-name = "gmac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <100000>;
+ enable-active-high;
+ gpio = <&pio 7 23 GPIO_ACTIVE_HIGH>;
+ };
+};
- ohci0: usb@01c14400 {
- status = "okay";
- };
+&ahci {
+ status = "okay";
+};
- ahci: sata@01c18000 {
- status = "okay";
- };
+&ehci0 {
+ status = "okay";
+};
- ehci1: usb@01c1c000 {
- status = "okay";
- };
+&ehci1 {
+ status = "okay";
+};
- ohci1: usb@01c1c400 {
- status = "okay";
- };
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ phy-supply = <&reg_gmac_3v3>;
+ status = "okay";
- pinctrl@01c20800 {
- mmc0_cd_pin_bananapi: mmc0_cd_pin@0 {
- allwinner,pins = "PH10";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- gmac_power_pin_bananapi: gmac_power_pin@0 {
- allwinner,pins = "PH23";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- led_pins_bananapi: led_pins@0 {
- allwinner,pins = "PH24";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
- ir0: ir@01c21800 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
- status = "okay";
- };
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
- uart3: serial@01c28c00 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_pins_b>;
- status = "okay";
- };
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
- uart7: serial@01c29c00 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart7_pins_a>;
- status = "okay";
- };
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_pins_a>;
+ status = "okay";
+};
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupt-parent = <&nmi_intc>;
- interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bananapi>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */
+ cd-inverted;
+ status = "okay";
+};
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+&ohci0 {
+ status = "okay";
+};
- i2c2: i2c@01c2b400 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins_a>;
- status = "okay";
- };
+&ohci1 {
+ status = "okay";
+};
- gmac: ethernet@01c50000 {
- pinctrl-names = "default";
- pinctrl-0 = <&gmac_pins_rgmii_a>;
- phy = <&phy1>;
- phy-mode = "rgmii";
- phy-supply = <&reg_gmac_3v3>;
- status = "okay";
-
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
+&pio {
+ mmc0_cd_pin_bananapi: mmc0_cd_pin@0 {
+ allwinner,pins = "PH10";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
- leds {
- compatible = "gpio-leds";
- pinctrl-names = "default";
- pinctrl-0 = <&led_pins_bananapi>;
-
- green {
- label = "bananapi:green:usr";
- gpios = <&pio 7 24 GPIO_ACTIVE_HIGH>;
- };
+ gmac_power_pin_bananapi: gmac_power_pin@0 {
+ allwinner,pins = "PH23";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
+ led_pins_bananapi: led_pins@0 {
+ allwinner,pins = "PH24";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+};
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
- };
+&reg_usb1_vbus {
+ status = "okay";
+};
- reg_gmac_3v3: gmac-3v3 {
- compatible = "regulator-fixed";
- pinctrl-names = "default";
- pinctrl-0 = <&gmac_power_pin_bananapi>;
- regulator-name = "gmac-3v3";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- startup-delay-us = <100000>;
- enable-active-high;
- gpio = <&pio 7 23 GPIO_ACTIVE_HIGH>;
- };
+&reg_usb2_vbus {
+ status = "okay";
+};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pins_a>,
+ <&spi0_cs0_pins_a>,
+ <&spi0_cs1_pins_a>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins_b>;
+ status = "okay";
+};
+
+&uart7 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_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-bananapro.dts b/arch/arm/boot/dts/sun7i-a20-bananapro.dts
index fb89fe7ed21b..18fcc87f4621 100644
--- a/arch/arm/boot/dts/sun7i-a20-bananapro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-bananapro.dts
@@ -16,11 +16,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 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
@@ -55,6 +50,16 @@
model = "LeMaker Banana Pro";
compatible = "lemaker,bananapro", "allwinner,sun7i-a20";
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart4;
+ serial2 = &uart7;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
@@ -144,7 +149,7 @@
&ir0 {
pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
+ pinctrl-0 = <&ir0_rx_pins_a>;
status = "okay";
};
@@ -233,7 +238,9 @@
&spi0 {
pinctrl-names = "default";
- pinctrl-0 = <&spi0_pins_a>;
+ pinctrl-0 = <&spi0_pins_a>,
+ <&spi0_cs0_pins_a>,
+ <&spi0_cs1_pins_a>;
status = "okay";
};
@@ -243,9 +250,9 @@
status = "okay";
};
-&uart2 {
+&uart4 {
pinctrl-names = "default";
- pinctrl-0 = <&uart2_pins_a>;
+ pinctrl-0 = <&uart4_pins_b>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
index c4ab6edb6f15..39a51d5143f7 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
@@ -18,11 +18,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 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
@@ -59,94 +54,12 @@
model = "Cubietech Cubieboard2";
compatible = "cubietech,cubieboard2", "allwinner,sun7i-a20";
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- ahci: sata@01c18000 {
- target-supply = <&reg_ahci_5v>;
- status = "okay";
- };
-
- ehci1: usb@01c1c000 {
- status = "okay";
- };
-
- ohci1: usb@01c1c400 {
- status = "okay";
- };
-
- pinctrl@01c20800 {
- led_pins_cubieboard2: led_pins@0 {
- allwinner,pins = "PH20", "PH21";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- ir0: ir@01c21800 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
- status = "okay";
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- 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: i2c@01c2b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
- };
-
- gmac: ethernet@01c50000 {
- pinctrl-names = "default";
- pinctrl-0 = <&gmac_pins_mii_a>;
- phy = <&phy1>;
- phy-mode = "mii";
- status = "okay";
+ aliases {
+ serial0 = &uart0;
+ };
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
};
leds {
@@ -164,26 +77,94 @@
gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>;
};
};
+};
- reg_ahci_5v: ahci-5v {
- status = "okay";
- };
+&ahci {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
+&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>;
};
+};
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
+&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>;
};
};
-#include "axp209.dtsi"
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
-&cpu0 {
- cpu-supply = <&reg_dcdc2>;
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_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 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
};
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ led_pins_cubieboard2: led_pins@0 {
+ allwinner,pins = "PH20", "PH21";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_ahci_5v {
+ status = "okay";
+};
+
+#include "axp209.dtsi"
+
&reg_dcdc2 {
regulator-always-on;
regulator-min-microvolt = <1000000>;
@@ -208,3 +189,23 @@
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-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index 8f74a649576d..4611e2f5a99e 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -18,11 +18,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 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
@@ -59,142 +54,12 @@
model = "Cubietech Cubietruck";
compatible = "cubietech,cubietruck", "allwinner,sun7i-a20";
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
-
- mmc3: mmc@01c12000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc3_pins_a>;
- vmmc-supply = <&reg_vmmc3>;
- bus-width = <4>;
- non-removable;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb0_vbus-supply = <&reg_usb0_vbus>;
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- ahci: sata@01c18000 {
- target-supply = <&reg_ahci_5v>;
- status = "okay";
- };
-
- ehci1: usb@01c1c000 {
- status = "okay";
- };
-
- ohci1: usb@01c1c400 {
- status = "okay";
- };
-
- pinctrl@01c20800 {
- mmc3_pins_a: mmc3@0 {
- /* AP6210 requires pull-up */
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- vmmc3_pin_cubietruck: vmmc3_pin@0 {
- allwinner,pins = "PH9";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- ahci_pwr_pin_cubietruck: ahci_pwr_pin@1 {
- allwinner,pins = "PH12";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- led_pins_cubietruck: led_pins@0 {
- allwinner,pins = "PH7", "PH11", "PH20", "PH21";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- usb0_vbus_pin_a: usb0_vbus_pin@0 {
- allwinner,pins = "PH17";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- pwm: pwm@01c20e00 {
- pinctrl-names = "default";
- pinctrl-0 = <&pwm0_pins_a>, <&pwm1_pins_a>;
- status = "okay";
- };
-
- ir0: ir@01c21800 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
- status = "okay";
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- 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: i2c@01c2b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
- };
-
- i2c2: i2c@01c2b400 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins_a>;
- status = "okay";
- };
-
- gmac: ethernet@01c50000 {
- pinctrl-names = "default";
- pinctrl-0 = <&gmac_pins_rgmii_a>;
- phy = <&phy1>;
- phy-mode = "rgmii";
- status = "okay";
+ aliases {
+ serial0 = &uart0;
+ };
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
};
leds {
@@ -223,26 +88,6 @@
};
};
- reg_ahci_5v: ahci-5v {
- pinctrl-0 = <&ahci_pwr_pin_cubietruck>;
- gpio = <&pio 7 12 GPIO_ACTIVE_HIGH>;
- status = "okay";
- };
-
- reg_usb0_vbus: usb0-vbus {
- pinctrl-0 = <&usb0_vbus_pin_a>;
- gpio = <&pio 7 17 GPIO_ACTIVE_HIGH>;
- status = "okay";
- };
-
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
- };
-
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
- };
-
reg_vmmc3: vmmc3 {
compatible = "regulator-fixed";
pinctrl-names = "default";
@@ -255,12 +100,149 @@
};
};
-#include "axp209.dtsi"
+&ahci {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+};
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ 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>;
+ 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";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_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 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc3_pins_a>;
+ vmmc-supply = <&reg_vmmc3>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: bcrmf@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&pio>;
+ interrupts = <10 IRQ_TYPE_LEVEL_LOW>; /* PH10 / EINT10 */
+ interrupt-names = "host-wake";
+ };
+};
+
+&mmc3_pins_a {
+ /* AP6210 requires pull-up */
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ vmmc3_pin_cubietruck: vmmc3_pin@0 {
+ allwinner,pins = "PH9";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ ahci_pwr_pin_cubietruck: ahci_pwr_pin@1 {
+ allwinner,pins = "PH12";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ led_pins_cubietruck: led_pins@0 {
+ allwinner,pins = "PH7", "PH11", "PH20", "PH21";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb0_vbus_pin_a: usb0_vbus_pin@0 {
+ allwinner,pins = "PH17";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins_a>, <&pwm1_pins_a>;
+ status = "okay";
+};
+
+&reg_ahci_5v {
+ pinctrl-0 = <&ahci_pwr_pin_cubietruck>;
+ gpio = <&pio 7 12 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+#include "axp209.dtsi"
+
&reg_dcdc2 {
regulator-always-on;
regulator-min-microvolt = <1000000>;
@@ -285,3 +267,30 @@
regulator-max-microvolt = <3000000>;
regulator-name = "avcc";
};
+
+&reg_usb0_vbus {
+ pinctrl-0 = <&usb0_vbus_pin_a>;
+ gpio = <&pio 7 17 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&reg_usb1_vbus {
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ usb0_vbus-supply = <&reg_usb0_vbus>;
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-hummingbird.dts b/arch/arm/boot/dts/sun7i-a20-hummingbird.dts
index 86a944ce19f8..37f4a5497452 100644
--- a/arch/arm/boot/dts/sun7i-a20-hummingbird.dts
+++ b/arch/arm/boot/dts/sun7i-a20-hummingbird.dts
@@ -3,12 +3,43 @@
*
* Wills Wang <wills.wang.open@gmail.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:
+ * 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.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * 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/;
@@ -31,197 +62,8 @@
serial4 = &uart5;
};
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v0>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
-
- mmc3: mmc@01c12000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc3_pins_a>;
- vmmc-supply = <&reg_mmc3_vdd>;
- bus-width = <4>;
- non-removable;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- ahci: sata@01c18000 {
- target-supply = <&reg_ahci_5v>;
- status = "okay";
- };
-
- ehci1: usb@01c1c000 {
- status = "okay";
- };
-
- ohci1: usb@01c1c400 {
- status = "okay";
- };
-
- pio: pinctrl@01c20800 {
- ahci_pwr_pin_a20_hummingbird: ahci_pwr_pin@0 {
- allwinner,pins = "PH15";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- usb1_vbus_pin_a20_hummingbird: usb1_vbus_pin@0 {
- allwinner,pins = "PH2";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- mmc3_vdd_pin_a20_hummingbird: mmc3_vdd_pin@0 {
- allwinner,pins = "PH9";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- gmac_vdd_pin_a20_hummingbird: gmac_vdd_pin@0 {
- allwinner,pins = "PH16";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- pwm: pwm@01c20e00 {
- pinctrl-names = "default";
- pinctrl-0 = <&pwm0_pins_a>;
- status = "okay";
- };
-
- ir0: ir@01c21800 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
- status = "okay";
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- uart2: serial@01c28800 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart2_pins_a>;
- status = "okay";
- };
-
- uart3: serial@01c28c00 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_pins_a>;
- status = "okay";
- };
-
- uart4: serial@01c29000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart4_pins_a>;
- status = "okay";
- };
-
- uart5: serial@01c29400 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart5_pins_a>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupt-parent = <&nmi_intc>;
- interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
-
- i2c1: i2c@01c2b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
- };
-
- i2c2: i2c@01c2b400 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins_a>;
- status = "okay";
- };
-
- i2c3: i2c@01c2b800 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c3_pins_a>;
- status = "okay";
- };
-
- spi2: spi@01c17000 {
- pinctrl-names = "default";
- pinctrl-0 = <&spi2_pins_b>;
- status = "okay";
- };
-
- gmac: ethernet@01c50000 {
- pinctrl-names = "default";
- pinctrl-0 = <&gmac_pins_rgmii_a>;
- phy = <&phy1>;
- phy-mode = "rgmii";
- phy-supply = <&reg_gmac_vdd>;
- /* phy reset config */
- snps,reset-gpio = <&pio 0 17 GPIO_ACTIVE_HIGH>; /* PA17 */
- snps,reset-active-low;
- /* wait 1s after reset, otherwise fail to read phy id */
- snps,reset-delays-us = <0 10000 1000000>;
- status = "okay";
-
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
- };
-
- reg_ahci_5v: ahci-5v {
- pinctrl-0 = <&ahci_pwr_pin_a20_hummingbird>;
- gpio = <&pio 7 15 GPIO_ACTIVE_HIGH>; /* PH15 */
- status = "okay";
- };
-
- reg_usb1_vbus: usb1-vbus {
- pinctrl-0 = <&usb1_vbus_pin_a20_hummingbird>;
- gpio = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */
- status = "okay";
- };
-
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
+ chosen {
+ stdout-path = "serial0:115200n8";
};
reg_mmc3_vdd: mmc3_vdd {
@@ -246,3 +88,195 @@
gpio = <&pio 7 16 GPIO_ACTIVE_HIGH>; /* PH16 */
};
};
+
+&ahci {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ phy-supply = <&reg_gmac_vdd>;
+ /* phy reset config */
+ snps,reset-gpio = <&pio 0 17 GPIO_ACTIVE_HIGH>; /* PA17 */
+ snps,reset-active-low;
+ /* wait 1s after reset, otherwise fail to read phy id */
+ snps,reset-delays-us = <0 10000 1000000>;
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&i2c3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c3_pins_a>;
+ status = "okay";
+};
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_pins_a>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc3_pins_a>;
+ vmmc-supply = <&reg_mmc3_vdd>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ ahci_pwr_pin_a20_hummingbird: ahci_pwr_pin@0 {
+ allwinner,pins = "PH15";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb1_vbus_pin_a20_hummingbird: usb1_vbus_pin@0 {
+ allwinner,pins = "PH2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mmc3_vdd_pin_a20_hummingbird: mmc3_vdd_pin@0 {
+ allwinner,pins = "PH9";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ gmac_vdd_pin_a20_hummingbird: gmac_vdd_pin@0 {
+ allwinner,pins = "PH16";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins_a>;
+ status = "okay";
+};
+
+&reg_ahci_5v {
+ pinctrl-0 = <&ahci_pwr_pin_a20_hummingbird>;
+ gpio = <&pio 7 15 GPIO_ACTIVE_HIGH>; /* PH15 */
+ status = "okay";
+};
+
+&reg_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_a20_hummingbird>;
+ gpio = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ status = "okay";
+};
+
+&spi2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi2_pins_b>,
+ <&spi2_cs0_pins_b>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins_a>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins_a>;
+ status = "okay";
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_a>;
+ status = "okay";
+};
+
+&uart5 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart5_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-i12-tvbox.dts b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
index 06148b4d000f..f32f6f20d923 100644
--- a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
+++ b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
@@ -16,11 +16,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 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
@@ -57,123 +52,12 @@
model = "I12 / Q5 / QT840A A20 tvbox";
compatible = "allwinner,i12-tvbox", "allwinner,sun7i-a20";
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
-
- mmc3: mmc@01c12000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc3_pins_a>;
- vmmc-supply = <&reg_vmmc3>;
- bus-width = <4>;
- non-removable;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- ehci1: usb@01c1c000 {
- status = "okay";
- };
-
- ohci1: usb@01c1c400 {
- status = "okay";
- };
-
- pinctrl@01c20800 {
- mmc3_pins_a: mmc3@0 {
- /* AP6210 / AP6330 requires pull-up */
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- vmmc3_pin_i12_tvbox: vmmc3_pin@0 {
- allwinner,pins = "PH2";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- vmmc3_io_pin_i12_tvbox: vmmc3_io_pin@0 {
- allwinner,pins = "PH12";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- gmac_power_pin_i12_tvbox: gmac_power_pin@0 {
- allwinner,pins = "PH21";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- led_pins_i12_tvbox: led_pins@0 {
- allwinner,pins = "PH9", "PH20";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- ir0: ir@01c21800 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
- status = "okay";
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupt-parent = <&nmi_intc>;
- interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
-
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+ aliases {
+ serial0 = &uart0;
+ };
- gmac: ethernet@01c50000 {
- pinctrl-names = "default";
- pinctrl-0 = <&gmac_pins_mii_a>;
- phy = <&phy1>;
- phy-mode = "mii";
- phy-supply = <&reg_gmac_3v3>;
- status = "okay";
-
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
};
leds {
@@ -192,14 +76,6 @@
};
};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
- };
-
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
- };
-
reg_vmmc3: vmmc3 {
compatible = "regulator-fixed";
pinctrl-names = "default";
@@ -236,3 +112,136 @@
gpio = <&pio 7 21 GPIO_ACTIVE_HIGH>;
};
};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_mii_a>;
+ phy = <&phy1>;
+ phy-mode = "mii";
+ phy-supply = <&reg_gmac_3v3>;
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_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 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc3_pins_a>;
+ vmmc-supply = <&reg_vmmc3>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: bcrmf@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&pio>;
+ interrupts = <10 IRQ_TYPE_LEVEL_LOW>; /* PH10 / EINT10 */
+ interrupt-names = "host-wake";
+ };
+};
+
+&mmc3_pins_a {
+ /* AP6210 / AP6330 requires pull-up */
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ vmmc3_pin_i12_tvbox: vmmc3_pin@0 {
+ allwinner,pins = "PH2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ vmmc3_io_pin_i12_tvbox: vmmc3_io_pin@0 {
+ allwinner,pins = "PH12";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ gmac_power_pin_i12_tvbox: gmac_power_pin@0 {
+ allwinner,pins = "PH21";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ led_pins_i12_tvbox: led_pins@0 {
+ allwinner,pins = "PH9", "PH20";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&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-m3.dts b/arch/arm/boot/dts/sun7i-a20-m3.dts
index 5add9f243ec3..8d9ea48dd98c 100644
--- a/arch/arm/boot/dts/sun7i-a20-m3.dts
+++ b/arch/arm/boot/dts/sun7i-a20-m3.dts
@@ -18,11 +18,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 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
@@ -59,114 +54,120 @@
model = "Mele M3";
compatible = "mele,m3", "allwinner,sun7i-a20";
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
+ aliases {
+ serial0 = &uart0;
+ };
- mmc2: mmc@01c11000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc2_pins_a>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- non-removable;
- status = "okay";
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_m3>;
- ehci0: usb@01c14000 {
- status = "okay";
+ blue {
+ label = "m3:blue:usr";
+ gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>;
};
+ };
+};
- ohci0: usb@01c14400 {
- status = "okay";
- };
+&ehci0 {
+ status = "okay";
+};
- ehci1: usb@01c1c000 {
- status = "okay";
- };
+&ehci1 {
+ status = "okay";
+};
- ohci1: usb@01c1c400 {
- status = "okay";
- };
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_mii_a>;
+ phy = <&phy1>;
+ phy-mode = "mii";
+ status = "okay";
- pinctrl@01c20800 {
- led_pins_m3: led_pins@0 {
- allwinner,pins = "PH20";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
- ir0: ir@01c21800 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
- status = "okay";
- };
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupt-parent = <&nmi_intc>;
- interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_pins_a>;
+ status = "okay";
+};
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
- gmac: ethernet@01c50000 {
- pinctrl-names = "default";
- pinctrl-0 = <&gmac_pins_mii_a>;
- phy = <&phy1>;
- phy-mode = "mii";
- status = "okay";
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins_a>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+};
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
- };
+&ohci0 {
+ status = "okay";
+};
- leds {
- compatible = "gpio-leds";
- pinctrl-names = "default";
- pinctrl-0 = <&led_pins_m3>;
+&ohci1 {
+ status = "okay";
+};
- blue {
- label = "m3:blue:usr";
- gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>;
- };
+&pio {
+ led_pins_m3: led_pins@0 {
+ allwinner,pins = "PH20";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
- };
+&reg_usb1_vbus {
+ status = "okay";
+};
- reg_usb2_vbus: usb2-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
new file mode 100644
index 000000000000..4f432f8ade77
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-mk808c.dts
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2015 Marcus Cooper
+ *
+ * Marcus Cooper <codekipper@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.
+ *
+ * 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 "sun7i-a20.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ model = "mk808c";
+ compatible = "allwinner,mk808c", "allwinner,sun7i-a20";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart2;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&reg_usb1_vbus {
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_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-olinuxino-lime.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
index 12ded69d61eb..769726dfb046 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
@@ -19,11 +19,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 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
@@ -60,118 +55,124 @@
model = "Olimex A20-OLinuXino-LIME";
compatible = "olimex,a20-olinuxino-lime", "allwinner,sun7i-a20";
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
+ aliases {
+ serial0 = &uart0;
+ };
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
- ehci0: usb@01c14000 {
- status = "okay";
- };
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_olinuxinolime>;
- ohci0: usb@01c14400 {
- status = "okay";
+ green {
+ label = "a20-olinuxino-lime:green:usr";
+ gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
};
+ };
+};
- ahci: sata@01c18000 {
- target-supply = <&reg_ahci_5v>;
- status = "okay";
- };
+&ahci {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+};
- ehci1: usb@01c1c000 {
- status = "okay";
- };
+&ehci0 {
+ status = "okay";
+};
- ohci1: usb@01c1c400 {
- status = "okay";
- };
+&ehci1 {
+ status = "okay";
+};
- pinctrl@01c20800 {
- ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
- allwinner,pins = "PC3";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- led_pins_olinuxinolime: led_pins@0 {
- allwinner,pins = "PH2";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_20_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_mii_a>;
+ phy = <&phy1>;
+ phy-mode = "mii";
+ status = "okay";
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupt-parent = <&nmi_intc>;
- interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
- gmac: ethernet@01c50000 {
- pinctrl-names = "default";
- pinctrl-0 = <&gmac_pins_mii_a>;
- phy = <&phy1>;
- phy-mode = "mii";
- 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 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
- };
+&ohci0 {
+ status = "okay";
+};
- leds {
- compatible = "gpio-leds";
- pinctrl-names = "default";
- pinctrl-0 = <&led_pins_olinuxinolime>;
+&ohci1 {
+ status = "okay";
+};
- green {
- label = "a20-olinuxino-lime:green:usr";
- gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
- default-state = "on";
- };
+&pio {
+ ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
+ allwinner,pins = "PC3";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- reg_ahci_5v: ahci-5v {
- pinctrl-0 = <&ahci_pwr_pin_olinuxinolime>;
- gpio = <&pio 2 3 GPIO_ACTIVE_HIGH>;
- status = "okay";
+ led_pins_olinuxinolime: led_pins@0 {
+ allwinner,pins = "PH2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
- };
+&reg_ahci_5v {
+ pinctrl-0 = <&ahci_pwr_pin_olinuxinolime>;
+ gpio = <&pio 2 3 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
- };
+&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-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
index 260dbd3bf29d..8acff78272b7 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
@@ -16,11 +16,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 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
@@ -57,176 +52,182 @@
model = "Olimex A20-OLinuXino-LIME2";
compatible = "olimex,a20-olinuxino-lime2", "allwinner,sun7i-a20";
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
+ aliases {
+ serial0 = &uart0;
+ };
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
- ehci0: usb@01c14000 {
- status = "okay";
- };
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_olinuxinolime>;
- ohci0: usb@01c14400 {
- status = "okay";
+ green {
+ label = "a20-olinuxino-lime2:green:usr";
+ gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
};
+ };
- ahci: sata@01c18000 {
- target-supply = <&reg_ahci_5v>;
- status = "okay";
- };
+ reg_axp_ipsout: axp_ipsout {
+ compatible = "regulator-fixed";
+ regulator-name = "axp-ipsout";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+};
- ehci1: usb@01c1c000 {
- status = "okay";
- };
+&ahci {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+};
- ohci1: usb@01c1c400 {
- status = "okay";
- };
+&ehci0 {
+ status = "okay";
+};
- pinctrl@01c20800 {
- ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
- allwinner,pins = "PC3";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
+&ehci1 {
+ status = "okay";
+};
+
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ status = "okay";
- led_pins_olinuxinolime: led_pins@0 {
- allwinner,pins = "PH2";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_20_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ acin-supply = <&reg_axp_ipsout>;
+ vin2-supply = <&reg_axp_ipsout>;
+ vin3-supply = <&reg_axp_ipsout>;
+ ldo24in-supply = <&reg_axp_ipsout>;
+ ldo3in-supply = <&reg_axp_ipsout>;
+
+ regulators {
+ vdd_rtc: ldo1 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
};
- };
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
+ avcc: ldo2 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupt-parent = <&nmi_intc>;
- interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
-
- interrupt-controller;
- #interrupt-cells = <1>;
-
- acin-supply = <&reg_axp_ipsout>;
- vin2-supply = <&reg_axp_ipsout>;
- vin3-supply = <&reg_axp_ipsout>;
- ldo24in-supply = <&reg_axp_ipsout>;
- ldo3in-supply = <&reg_axp_ipsout>;
-
- regulators {
- vdd_rtc: ldo1 {
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- regulator-always-on;
- };
-
- avcc: ldo2 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- };
-
- vcc_csi0: ldo3 {
- regulator-min-microvolt = <700000>;
- regulator-max-microvolt = <3500000>;
- regulator-always-on;
- };
-
- vcc_csi1: ldo4 {
- regulator-min-microvolt = <1250000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- };
-
- vdd_cpu: dcdc2 {
- regulator-min-microvolt = <700000>;
- regulator-max-microvolt = <2275000>;
- regulator-always-on;
- };
-
- vdd_int: dcdc3 {
- regulator-min-microvolt = <700000>;
- regulator-max-microvolt = <3500000>;
- regulator-always-on;
- };
- };
+ vcc_csi0: ldo3 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <3500000>;
+ regulator-always-on;
};
- };
- i2c1: i2c@01c2b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
- };
+ vcc_csi1: ldo4 {
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
- gmac: ethernet@01c50000 {
- pinctrl-names = "default";
- pinctrl-0 = <&gmac_pins_rgmii_a>;
- phy = <&phy1>;
- phy-mode = "rgmii";
- status = "okay";
+ vdd_cpu: dcdc2 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <2275000>;
+ regulator-always-on;
+ };
- phy1: ethernet-phy@1 {
- reg = <1>;
+ vdd_int: dcdc3 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <3500000>;
+ regulator-always-on;
};
};
};
+};
- leds {
- compatible = "gpio-leds";
- pinctrl-names = "default";
- pinctrl-0 = <&led_pins_olinuxinolime>;
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
- green {
- label = "a20-olinuxino-lime2:green:usr";
- gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
- default-state = "on";
- };
- };
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
- reg_ahci_5v: ahci-5v {
- pinctrl-0 = <&ahci_pwr_pin_olinuxinolime>;
- gpio = <&pio 2 3 GPIO_ACTIVE_HIGH>;
- status = "okay";
- };
+&ohci0 {
+ status = "okay";
+};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
- };
+&ohci1 {
+ status = "okay";
+};
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
+&pio {
+ ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
+ allwinner,pins = "PC3";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- reg_axp_ipsout: axp_ipsout {
- compatible = "regulator-fixed";
- regulator-name = "axp-ipsout";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- regulator-always-on;
+ led_pins_olinuxinolime: led_pins@0 {
+ allwinner,pins = "PH2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
+
+&reg_ahci_5v {
+ pinctrl-0 = <&ahci_pwr_pin_olinuxinolime>;
+ gpio = <&pio 2 3 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&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-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
index 714e15ac5416..00f8f25eccae 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -3,12 +3,43 @@
*
* Maxime Ripard <maxime.ripard@free-electrons.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:
+ * 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.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * 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/;
@@ -32,216 +63,220 @@
spi1 = &spi2;
};
- soc@01c00000 {
- spi1: spi@01c06000 {
- pinctrl-names = "default";
- pinctrl-0 = <&spi1_pins_a>;
- status = "okay";
- };
-
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
- mmc3: mmc@01c12000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc3_pins_a>, <&mmc3_cd_pin_olinuxinom>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
- cd-inverted;
- status = "okay";
- };
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_olinuxino>;
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
+ green {
+ label = "a20-olinuxino-micro:green:usr";
+ gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
};
+ };
+};
- ehci0: usb@01c14000 {
- status = "okay";
- };
+&ahci {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+};
- ohci0: usb@01c14400 {
- status = "okay";
- };
+&ehci0 {
+ status = "okay";
+};
- spi2: spi@01c17000 {
- pinctrl-names = "default";
- pinctrl-0 = <&spi2_pins_a>;
- status = "okay";
- };
+&ehci1 {
+ status = "okay";
+};
- ahci: sata@01c18000 {
- target-supply = <&reg_ahci_5v>;
- status = "okay";
- };
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_mii_a>;
+ phy = <&phy1>;
+ phy-mode = "mii";
+ status = "okay";
- ehci1: usb@01c1c000 {
- status = "okay";
- };
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
- ohci1: usb@01c1c400 {
- status = "okay";
- };
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
- pinctrl@01c20800 {
- mmc3_cd_pin_olinuxinom: mmc3_cd_pin@0 {
- allwinner,pins = "PH11";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-
- led_pins_olinuxino: led_pins@0 {
- allwinner,pins = "PH2";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_20_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
- lradc: lradc@01c22800 {
- vref-supply = <&reg_vcc3v0>;
- status = "okay";
-
- button@191 {
- label = "Volume Up";
- linux,code = <KEY_VOLUMEUP>;
- channel = <0>;
- voltage = <191274>;
- };
-
- button@392 {
- label = "Volume Down";
- linux,code = <KEY_VOLUMEDOWN>;
- channel = <0>;
- voltage = <392644>;
- };
-
- button@601 {
- label = "Menu";
- linux,code = <KEY_MENU>;
- channel = <0>;
- voltage = <601151>;
- };
-
- button@795 {
- label = "Search";
- linux,code = <KEY_SEARCH>;
- channel = <0>;
- voltage = <795090>;
- };
-
- button@987 {
- label = "Home";
- linux,code = <KEY_HOMEPAGE>;
- channel = <0>;
- voltage = <987387>;
- };
-
- button@1184 {
- label = "Esc";
- linux,code = <KEY_ESC>;
- channel = <0>;
- voltage = <1184678>;
- };
-
- button@1398 {
- label = "Enter";
- linux,code = <KEY_ENTER>;
- channel = <0>;
- voltage = <1398804>;
- };
- };
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
- uart6: serial@01c29800 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart6_pins_a>;
- status = "okay";
- };
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
- uart7: serial@01c29c00 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart7_pins_a>;
- status = "okay";
- };
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
+ button@191 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <191274>;
+ };
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupt-parent = <&nmi_intc>;
- interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ button@392 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <392644>;
+ };
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
+ button@601 {
+ label = "Menu";
+ linux,code = <KEY_MENU>;
+ channel = <0>;
+ voltage = <601151>;
+ };
- i2c1: i2c@01c2b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
- };
+ button@795 {
+ label = "Search";
+ linux,code = <KEY_SEARCH>;
+ channel = <0>;
+ voltage = <795090>;
+ };
- i2c2: i2c@01c2b400 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins_a>;
- status = "okay";
- };
+ button@987 {
+ label = "Home";
+ linux,code = <KEY_HOMEPAGE>;
+ channel = <0>;
+ voltage = <987387>;
+ };
- gmac: ethernet@01c50000 {
- pinctrl-names = "default";
- pinctrl-0 = <&gmac_pins_mii_a>;
- phy = <&phy1>;
- phy-mode = "mii";
- status = "okay";
+ button@1184 {
+ label = "Esc";
+ linux,code = <KEY_ESC>;
+ channel = <0>;
+ voltage = <1184678>;
+ };
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
+ button@1398 {
+ label = "Enter";
+ linux,code = <KEY_ENTER>;
+ channel = <0>;
+ voltage = <1398804>;
};
+};
- leds {
- compatible = "gpio-leds";
- pinctrl-names = "default";
- pinctrl-0 = <&led_pins_olinuxino>;
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
- green {
- label = "a20-olinuxino-micro:green:usr";
- gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
- default-state = "on";
- };
- };
+&mmc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc3_pins_a>, <&mmc3_cd_pin_olinuxinom>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
+ cd-inverted;
+ status = "okay";
+};
- reg_ahci_5v: ahci-5v {
- status = "okay";
- };
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
+&pio {
+ mmc3_cd_pin_olinuxinom: mmc3_cd_pin@0 {
+ allwinner,pins = "PH11";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
+ led_pins_olinuxino: led_pins@0 {
+ allwinner,pins = "PH2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
+
+&reg_ahci_5v {
+ status = "okay";
+};
+
+&reg_usb1_vbus {
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ status = "okay";
+};
+
+&spi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_pins_a>,
+ <&spi1_cs0_pins_a>;
+ status = "okay";
+};
+
+&spi2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi2_pins_a>,
+ <&spi2_cs0_pins_a>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&uart6 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart6_pins_a>;
+ status = "okay";
+};
+
+&uart7 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_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-orangepi-mini.dts b/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts
new file mode 100644
index 000000000000..73cd81ee02e3
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * 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 "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 = "Orange Pi Mini";
+ compatible = "xunlong,orangepi-mini", "allwinner,sun7i-a20";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_orangepi>;
+
+ green {
+ label = "orangepi:green:usr";
+ gpios = <&pio 7 24 GPIO_ACTIVE_HIGH>; /* PH24 */
+ };
+
+ blue {
+ label = "orangepi:blue:usr";
+ gpios = <&pio 7 25 GPIO_ACTIVE_HIGH>; /* PH25 */
+ };
+ };
+
+ reg_gmac_3v3: gmac-3v3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_power_pin_orangepi>;
+ regulator-name = "gmac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <100000>;
+ enable-active-high;
+ gpio = <&pio 7 23 GPIO_ACTIVE_HIGH>; /* PH23 */
+ };
+};
+
+&ahci {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ phy-supply = <&reg_gmac_3v3>;
+ 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>;
+ };
+};
+
+#include "axp209.dtsi"
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_pins_a>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_orangepi>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc3_pins_a>, <&mmc3_cd_pin_orangepi>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
+ cd-inverted;
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_orangepi: mmc0_cd_pin@0 {
+ allwinner,pins = "PH10";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ mmc3_cd_pin_orangepi: mmc3_cd_pin@0 {
+ allwinner,pins = "PH11";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb2_vbus_pin_bananapro: usb2_vbus_pin@0 {
+ allwinner,pins = "PH22";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ gmac_power_pin_orangepi: gmac_power_pin@0 {
+ allwinner,pins = "PH23";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ led_pins_orangepi: led_pins@0 {
+ allwinner,pins = "PH24", "PH25";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb1_vbus_pin_bananapro: usb1_vbus_pin@0 {
+ allwinner,pins = "PH26";
+ 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 = <1500000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ 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_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_bananapro>;
+ gpio = <&pio 7 26 GPIO_ACTIVE_HIGH>; /* PH26 */
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ pinctrl-0 = <&usb2_vbus_pin_bananapro>;
+ gpio = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
+ 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-orangepi.dts b/arch/arm/boot/dts/sun7i-a20-orangepi.dts
new file mode 100644
index 000000000000..55a06ceb80ec
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-orangepi.dts
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * 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 "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 = "Orange Pi";
+ compatible = "xunlong,orangepi", "allwinner,sun7i-a20";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_orangepi>;
+
+ green {
+ label = "orangepi:green:usr";
+ gpios = <&pio 7 24 GPIO_ACTIVE_HIGH>; /* PH24 */
+ };
+ };
+
+ reg_gmac_3v3: gmac-3v3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_power_pin_orangepi>;
+ regulator-name = "gmac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <100000>;
+ enable-active-high;
+ gpio = <&pio 7 23 GPIO_ACTIVE_HIGH>; /* PH23 */
+ };
+};
+
+&ahci {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ phy-supply = <&reg_gmac_3v3>;
+ 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>;
+ };
+};
+
+#include "axp209.dtsi"
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_pins_a>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_orangepi>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */
+ cd-inverted;
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_orangepi: mmc0_cd_pin@0 {
+ allwinner,pins = "PH10";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb2_vbus_pin_bananapro: usb2_vbus_pin@0 {
+ allwinner,pins = "PH22";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ gmac_power_pin_orangepi: gmac_power_pin@0 {
+ allwinner,pins = "PH23";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ led_pins_orangepi: led_pins@0 {
+ allwinner,pins = "PH24";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb1_vbus_pin_bananapro: usb1_vbus_pin@0 {
+ allwinner,pins = "PH26";
+ 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 = <1500000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ 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_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_bananapro>;
+ gpio = <&pio 7 26 GPIO_ACTIVE_HIGH>; /* PH26 */
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ pinctrl-0 = <&usb2_vbus_pin_bananapro>;
+ gpio = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
+ 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-pcduino3-nano.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
new file mode 100644
index 000000000000..5361fce26b45
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2015 Adam Sampson <ats@offog.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
+ * 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/arm-gic.h>
+
+/ {
+ model = "LinkSprite pcDuino3 Nano";
+ compatible = "linksprite,pcduino3-nano", "allwinner,sun7i-a20";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_pcduino3_nano>;
+
+ /* Marked "LED3" on the PCB. */
+ usr1 {
+ label = "pcduino3-nano:green:usr1";
+ gpios = <&pio 7 16 GPIO_ACTIVE_LOW>; /* PH16 */
+ };
+
+ /* Marked "LED4" on the PCB. */
+ usr2 {
+ label = "pcduino3-nano:green:usr2";
+ gpios = <&pio 7 15 GPIO_ACTIVE_LOW>; /* PH15 */
+ };
+ };
+};
+
+&ahci {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ 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>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_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 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ ahci_pwr_pin_pcduino3_nano: ahci_pwr_pin@0 {
+ allwinner,pins = "PH2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ led_pins_pcduino3_nano: led_pins@0 {
+ allwinner,pins = "PH16", "PH15";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb1_vbus_pin_pcduino3_nano: usb1_vbus_pin@0 {
+ allwinner,pins = "PH11";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_ahci_5v {
+ pinctrl-0 = <&ahci_pwr_pin_pcduino3_nano>;
+ gpio = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */
+ status = "okay";
+};
+
+&reg_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_pcduino3_nano>;
+ gpio = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
+ 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-pcduino3.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
index 0a2c2aeb4687..afc9ecebed21 100644
--- a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
+++ b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
@@ -17,11 +17,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 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
@@ -59,103 +54,12 @@
model = "LinkSprite pcDuino3";
compatible = "linksprite,pcduino3", "allwinner,sun7i-a20";
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
- vmmc-supply = <&reg_vcc3v3>;
- bus-width = <4>;
- cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
- cd-inverted;
- status = "okay";
- };
-
- usbphy: phy@01c13400 {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
- status = "okay";
- };
-
- ehci0: usb@01c14000 {
- status = "okay";
- };
-
- ohci0: usb@01c14400 {
- status = "okay";
- };
-
- ahci: sata@01c18000 {
- target-supply = <&reg_ahci_5v>;
- status = "okay";
- };
-
- ehci1: usb@01c1c000 {
- status = "okay";
- };
-
- ohci1: usb@01c1c400 {
- status = "okay";
- };
-
- pinctrl@01c20800 {
- ahci_pwr_pin_a: ahci_pwr_pin@0 {
- allwinner,pins = "PH2";
- };
-
- led_pins_pcduino3: led_pins@0 {
- allwinner,pins = "PH15", "PH16";
- allwinner,function = "gpio_out";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- key_pins_pcduino3: key_pins@0 {
- allwinner,pins = "PH17", "PH18", "PH19";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- ir0: ir@01c21800 {
- pinctrl-names = "default";
- pinctrl-0 = <&ir0_pins_a>;
- status = "okay";
- };
-
- uart0: serial@01c28000 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
- };
-
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-
- axp209: pmic@34 {
- compatible = "x-powers,axp209";
- reg = <0x34>;
- interrupt-parent = <&nmi_intc>;
- interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
-
- interrupt-controller;
- #interrupt-cells = <1>;
- };
- };
-
- gmac: ethernet@01c50000 {
- pinctrl-names = "default";
- pinctrl-0 = <&gmac_pins_mii_a>;
- phy = <&phy1>;
- phy-mode = "mii";
- status = "okay";
+ aliases {
+ serial0 = &uart0;
+ };
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
- };
+ chosen {
+ stdout-path = "serial0:115200n8";
};
leds {
@@ -196,17 +100,114 @@
gpios = <&pio 7 19 GPIO_ACTIVE_LOW>;
};
};
+};
- reg_usb1_vbus: usb1-vbus {
- status = "okay";
+&ahci {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+};
+
+&ahci_pwr_pin_a {
+ allwinner,pins = "PH2";
+};
+
+&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 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
+
+&ir0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_rx_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 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
- reg_usb2_vbus: usb2-vbus {
- status = "okay";
+&pio {
+ led_pins_pcduino3: led_pins@0 {
+ allwinner,pins = "PH15", "PH16";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- reg_ahci_5v: ahci-5v {
- gpio = <&pio 7 2 GPIO_ACTIVE_HIGH>;
- status = "okay";
+ key_pins_pcduino3: key_pins@0 {
+ allwinner,pins = "PH17", "PH18", "PH19";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
+
+&reg_ahci_5v {
+ gpio = <&pio 7 2 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&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-wexler-tab7200.dts b/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts
new file mode 100644
index 000000000000..83c6d3f872ff
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2015 Aleksei Mamlin
+ * Aleksei Mamlin <mamlinav@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 "sun7i-a20.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>
+
+/ {
+ model = "Wexler TAB7200";
+ compatible = "wexler,tab7200", "allwinner,sun7i-a20";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&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";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
+
+ button@571 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <571428>;
+ };
+
+ button@761 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <761904>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ 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 = <1450000>;
+ 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.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index fdd181792b4b..6a63f30c9a69 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -18,11 +18,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 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
@@ -68,7 +63,8 @@
ranges;
framebuffer@0 {
- compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+ compatible = "allwinner,simple-framebuffer",
+ "simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-hdmi";
clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
<&ahb_gates 44>;
@@ -104,14 +100,14 @@
clocks = <&cpu>;
clock-latency = <244144>; /* 8 32k periods */
operating-points = <
- /* kHz uV */
- 960000 1400000
- 912000 1400000
- 864000 1300000
- 720000 1200000
- 528000 1100000
- 312000 1000000
- 144000 900000
+ /* kHz uV */
+ 960000 1400000
+ 912000 1400000
+ 864000 1300000
+ 720000 1200000
+ 528000 1100000
+ 312000 1000000
+ 144000 900000
>;
#cooling-cells = <2>;
cooling-min-level = <0>;
@@ -224,7 +220,8 @@
compatible = "allwinner,sun4i-a10-pll6-clk";
reg = <0x01c20028 0x4>;
clocks = <&osc24M>;
- clock-output-names = "pll6_sata", "pll6_other", "pll6";
+ clock-output-names = "pll6_sata", "pll6_other", "pll6",
+ "pll6_div_4";
};
pll8: clk@01c20040 {
@@ -253,10 +250,16 @@
ahb: ahb@01c20054 {
#clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-ahb-clk";
+ compatible = "allwinner,sun5i-a13-ahb-clk";
reg = <0x01c20054 0x4>;
- clocks = <&axi>;
+ clocks = <&axi>, <&pll6 3>, <&pll6 1>;
clock-output-names = "ahb";
+ /*
+ * Use PLL6 as parent, instead of CPU/AXI
+ * which has rate changes due to cpufreq
+ */
+ assigned-clocks = <&ahb>;
+ assigned-clock-parents = <&pll6 3>;
};
ahb_gates: clk@01c20060 {
@@ -441,11 +444,12 @@
usb_clk: clk@01c200cc {
#clock-cells = <1>;
- #reset-cells = <1>;
+ #reset-cells = <1>;
compatible = "allwinner,sun4i-a10-usb-clk";
reg = <0x01c200cc 0x4>;
clocks = <&pll6 1>;
- clock-output-names = "usb_ohci0", "usb_ohci1", "usb_phy";
+ clock-output-names = "usb_ohci0", "usb_ohci1",
+ "usb_phy";
};
spi3_clk: clk@01c200d4 {
@@ -465,10 +469,13 @@
};
/*
- * The following two are dummy clocks, placeholders used in the gmac_tx
- * clock. The gmac driver will choose one parent depending on the PHY
- * interface mode, using clk_set_rate auto-reparenting.
- * The actual TX clock rate is not controlled by the gmac_tx clock.
+ * The following two are dummy clocks, placeholders
+ * used in the gmac_tx clock. The gmac driver will
+ * choose one parent depending on the PHY interface
+ * mode, using clk_set_rate auto-reparenting.
+ *
+ * The actual TX clock rate is not controlled by the
+ * gmac_tx clock.
*/
mii_phy_tx_clk: clk@2 {
#clock-cells = <0>;
@@ -527,6 +534,42 @@
#size-cells = <1>;
ranges;
+ sram-controller@01c00000 {
+ compatible = "allwinner,sun4i-a10-sram-controller";
+ reg = <0x01c00000 0x30>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram_a: sram@00000000 {
+ compatible = "mmio-sram";
+ reg = <0x00000000 0xc000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00000000 0xc000>;
+
+ emac_sram: sram-section@8000 {
+ compatible = "allwinner,sun4i-a10-sram-a3-a4";
+ reg = <0x8000 0x4000>;
+ status = "disabled";
+ };
+ };
+
+ sram_d: sram@00010000 {
+ compatible = "mmio-sram";
+ reg = <0x00010000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00010000 0x1000>;
+
+ otg_sram: sram-section@0000 {
+ compatible = "allwinner,sun4i-a10-sram-d";
+ reg = <0x0000 0x1000>;
+ status = "disabled";
+ };
+ };
+ };
+
nmi_intc: interrupt-controller@01c00030 {
compatible = "allwinner,sun7i-a20-sc-nmi";
interrupt-controller;
@@ -576,6 +619,7 @@
reg = <0x01c0b000 0x1000>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ahb_gates 17>;
+ allwinner,sram = <&emac_sram 1>;
status = "disabled";
};
@@ -600,6 +644,8 @@
"sample";
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc1: mmc@01c10000 {
@@ -615,6 +661,8 @@
"sample";
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc2: mmc@01c11000 {
@@ -630,6 +678,8 @@
"sample";
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc3: mmc@01c12000 {
@@ -645,6 +695,8 @@
"sample";
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
usbphy: phy@01c13400 {
@@ -795,6 +847,13 @@
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+ uart4_pins_b: uart4@1 {
+ allwinner,pins = "PH4", "PH5";
+ allwinner,function = "uart4";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
uart5_pins_a: uart5@0 {
allwinner,pins = "PI10", "PI11";
allwinner,function = "uart5";
@@ -896,35 +955,71 @@
};
spi0_pins_a: spi0@0 {
- allwinner,pins = "PI10", "PI11", "PI12", "PI13", "PI14";
+ allwinner,pins = "PI11", "PI12", "PI13";
+ allwinner,function = "spi0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ spi0_cs0_pins_a: spi0_cs0@0 {
+ allwinner,pins = "PI10";
+ allwinner,function = "spi0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ spi0_cs1_pins_a: spi0_cs1@0 {
+ allwinner,pins = "PI14";
allwinner,function = "spi0";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
spi1_pins_a: spi1@0 {
- allwinner,pins = "PI16", "PI17", "PI18", "PI19";
+ allwinner,pins = "PI17", "PI18", "PI19";
+ allwinner,function = "spi1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ spi1_cs0_pins_a: spi1_cs0@0 {
+ allwinner,pins = "PI16";
allwinner,function = "spi1";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
spi2_pins_a: spi2@0 {
- allwinner,pins = "PC19", "PC20", "PC21", "PC22";
+ allwinner,pins = "PC20", "PC21", "PC22";
allwinner,function = "spi2";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
spi2_pins_b: spi2@1 {
- allwinner,pins = "PB14", "PB15", "PB16", "PB17";
+ allwinner,pins = "PB15", "PB16", "PB17";
+ allwinner,function = "spi2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ spi2_cs0_pins_a: spi2_cs0@0 {
+ allwinner,pins = "PC19";
+ allwinner,function = "spi2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ spi2_cs0_pins_b: spi2_cs0@1 {
+ allwinner,pins = "PB14";
allwinner,function = "spi2";
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,pins = "PF0", "PF1", "PF2",
+ "PF3", "PF4", "PF5";
allwinner,function = "mmc0";
allwinner,drive = <SUN4I_PINCTRL_30_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
@@ -938,28 +1033,44 @@
};
mmc2_pins_a: mmc2@0 {
- allwinner,pins = "PC6","PC7","PC8","PC9","PC10","PC11";
+ allwinner,pins = "PC6", "PC7", "PC8",
+ "PC9", "PC10", "PC11";
allwinner,function = "mmc2";
allwinner,drive = <SUN4I_PINCTRL_30_MA>;
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
mmc3_pins_a: mmc3@0 {
- allwinner,pins = "PI4","PI5","PI6","PI7","PI8","PI9";
+ allwinner,pins = "PI4", "PI5", "PI6",
+ "PI7", "PI8", "PI9";
allwinner,function = "mmc3";
allwinner,drive = <SUN4I_PINCTRL_30_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- ir0_pins_a: ir0@0 {
- allwinner,pins = "PB3","PB4";
+ ir0_rx_pins_a: ir0@0 {
+ allwinner,pins = "PB4";
allwinner,function = "ir0";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- ir1_pins_a: ir1@0 {
- allwinner,pins = "PB22","PB23";
+ ir0_tx_pins_a: ir0@1 {
+ allwinner,pins = "PB3";
+ allwinner,function = "ir0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ ir1_rx_pins_a: ir1@0 {
+ allwinner,pins = "PB23";
+ allwinner,function = "ir1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ ir1_tx_pins_a: ir1@1 {
+ allwinner,pins = "PB22";
allwinner,function = "ir1";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
@@ -1042,7 +1153,7 @@
};
rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-a10-ts";
+ compatible = "allwinner,sun5i-a13-ts";
reg = <0x01c25000 0x100>;
interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
#thermal-sensor-cells = <0>;
@@ -1129,7 +1240,8 @@
};
i2c0: i2c@01c2ac00 {
- compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c";
+ compatible = "allwinner,sun7i-a20-i2c",
+ "allwinner,sun4i-a10-i2c";
reg = <0x01c2ac00 0x400>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&apb1_gates 0>;
@@ -1139,7 +1251,8 @@
};
i2c1: i2c@01c2b000 {
- compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c";
+ compatible = "allwinner,sun7i-a20-i2c",
+ "allwinner,sun4i-a10-i2c";
reg = <0x01c2b000 0x400>;
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&apb1_gates 1>;
@@ -1149,7 +1262,8 @@
};
i2c2: i2c@01c2b400 {
- compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c";
+ compatible = "allwinner,sun7i-a20-i2c",
+ "allwinner,sun4i-a10-i2c";
reg = <0x01c2b400 0x400>;
interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&apb1_gates 2>;
@@ -1159,7 +1273,8 @@
};
i2c3: i2c@01c2b800 {
- compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c";
+ compatible = "allwinner,sun7i-a20-i2c",
+ "allwinner,sun4i-a10-i2c";
reg = <0x01c2b800 0x400>;
interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&apb1_gates 3>;
@@ -1169,7 +1284,8 @@
};
i2c4: i2c@01c2c000 {
- compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c";
+ compatible = "allwinner,sun7i-a20-i2c",
+ "allwinner,sun4i-a10-i2c";
reg = <0x01c2c000 0x400>;
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&apb1_gates 15>;
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
new file mode 100644
index 000000000000..7abd0ae3143d
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -0,0 +1,636 @@
+/*
+ * Copyright 2014 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.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
+ * 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>;
+
+ chosen {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ framebuffer@0 {
+ compatible = "allwinner,simple-framebuffer",
+ "simple-framebuffer";
+ allwinner,pipeline = "de_be0-lcd0";
+ clocks = <&pll6 0>;
+ status = "disabled";
+ };
+ };
+
+ 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)>;
+ clock-frequency = <24000000>;
+ arm,cpu-registers-not-fw-configured;
+ };
+
+ cpus {
+ enable-method = "allwinner,sun8i-a23";
+ #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>;
+ };
+ };
+
+ 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";
+ };
+
+ cpu: cpu_clk@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-cpu-clk";
+ reg = <0x01c20050 0x4>;
+
+ /*
+ * PLL1 is listed twice here.
+ * While it looks suspicious, it's actually documented
+ * that way both in the datasheet and in the code from
+ * Allwinner.
+ */
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>;
+ clock-output-names = "cpu";
+ };
+
+ axi: axi_clk@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun8i-a23-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";
+ };
+
+ apb1: apb1_clk@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb1>;
+ clock-output-names = "apb1";
+ };
+
+ ahb1_gates: clk@01c20060 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun8i-a23-ahb1-gates-clk";
+ reg = <0x01c20060 0x8>;
+ clocks = <&ahb1>;
+ clock-output-names = "ahb1_mipidsi", "ahb1_dma",
+ "ahb1_mmc0", "ahb1_mmc1", "ahb1_mmc2",
+ "ahb1_nand", "ahb1_sdram",
+ "ahb1_hstimer", "ahb1_spi0",
+ "ahb1_spi1", "ahb1_otg", "ahb1_ehci",
+ "ahb1_ohci", "ahb1_ve", "ahb1_lcd",
+ "ahb1_csi", "ahb1_be", "ahb1_fe",
+ "ahb1_gpu", "ahb1_spinlock",
+ "ahb1_drc";
+ };
+
+ apb1_gates: clk@01c20068 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun8i-a23-apb1-gates-clk";
+ reg = <0x01c20068 0x4>;
+ clocks = <&apb1>;
+ clock-output-names = "apb1_codec", "apb1_pio",
+ "apb1_daudio0", "apb1_daudio1";
+ };
+
+ 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";
+ };
+
+ apb2_gates: clk@01c2006c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun8i-a23-apb2-gates-clk";
+ reg = <0x01c2006c 0x4>;
+ clocks = <&apb2>;
+ clock-output-names = "apb2_i2c0", "apb2_i2c1",
+ "apb2_i2c2", "apb2_uart0",
+ "apb2_uart1", "apb2_uart2",
+ "apb2_uart3", "apb2_uart4";
+ };
+
+ mmc0_clk: clk@01c20088 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-mmc-clk";
+ reg = <0x01c20088 0x4>;
+ clocks = <&osc24M>, <&pll6 0>;
+ 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>;
+ 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>;
+ clock-output-names = "mmc2",
+ "mmc2_output",
+ "mmc2_sample";
+ };
+
+ usb_clk: clk@01c200cc {
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ compatible = "allwinner,sun8i-a23-usb-clk";
+ reg = <0x01c200cc 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "usb_phy0", "usb_phy1", "usb_hsic",
+ "usb_hsic_12M", "usb_ohci0";
+ };
+ };
+
+ soc@01c00000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ dma: dma-controller@01c02000 {
+ compatible = "allwinner,sun8i-a23-dma";
+ reg = <0x01c02000 0x1000>;
+ interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ahb1_gates 6>;
+ resets = <&ahb1_rst 6>;
+ #dma-cells = <1>;
+ };
+
+ mmc0: mmc@01c0f000 {
+ compatible = "allwinner,sun5i-a13-mmc";
+ reg = <0x01c0f000 0x1000>;
+ clocks = <&ahb1_gates 8>,
+ <&mmc0_clk 0>,
+ <&mmc0_clk 1>,
+ <&mmc0_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
+ resets = <&ahb1_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 = <&ahb1_gates 9>,
+ <&mmc1_clk 0>,
+ <&mmc1_clk 1>,
+ <&mmc1_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
+ resets = <&ahb1_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 = <&ahb1_gates 10>,
+ <&mmc2_clk 0>,
+ <&mmc2_clk 1>,
+ <&mmc2_clk 2>;
+ clock-names = "ahb",
+ "mmc",
+ "output",
+ "sample";
+ resets = <&ahb1_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 gets set in SoC specific dtsi file */
+ reg = <0x01c20800 0x400>;
+ /* interrupts get set in SoC specific dtsi file */
+ clocks = <&apb1_gates 5>;
+ gpio-controller;
+ interrupt-controller;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #gpio-cells = <3>;
+
+ uart0_pins_a: uart0@0 {
+ allwinner,pins = "PF2", "PF4";
+ 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>;
+ };
+
+ 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>;
+ };
+
+ mmc2_8bit_pins: mmc2_8bit {
+ allwinner,pins = "PC5", "PC6", "PC8",
+ "PC9", "PC10", "PC11",
+ "PC12", "PC13", "PC14",
+ "PC15";
+ allwinner,function = "mmc2";
+ allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2c0_pins_a: i2c0@0 {
+ allwinner,pins = "PH2", "PH3";
+ allwinner,function = "i2c0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2c1_pins_a: i2c1@0 {
+ allwinner,pins = "PH4", "PH5";
+ allwinner,function = "i2c1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2c2_pins_a: i2c2@0 {
+ allwinner,pins = "PE12", "PE13";
+ allwinner,function = "i2c2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+ };
+
+ ahb1_rst: reset@01c202c0 {
+ #reset-cells = <1>;
+ compatible = "allwinner,sun6i-a31-clock-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>;
+ };
+
+ lradc: lradc@01c22800 {
+ compatible = "allwinner,sun4i-a10-lradc-keys";
+ reg = <0x01c22800 0x100>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ 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 = <&apb2_gates 16>;
+ 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 = <&apb2_gates 17>;
+ 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 = <&apb2_gates 18>;
+ 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 = <&apb2_gates 19>;
+ resets = <&apb2_rst 19>;
+ dmas = <&dma 9>, <&dma 9>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ uart4: serial@01c29000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01c29000 0x400>;
+ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb2_gates 20>;
+ resets = <&apb2_rst 20>;
+ dmas = <&dma 10>, <&dma 10>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ i2c0: i2c@01c2ac00 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01c2ac00 0x400>;
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&apb2_gates 0>;
+ resets = <&apb2_rst 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c1: i2c@01c2b000 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01c2b000 0x400>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&apb2_gates 1>;
+ resets = <&apb2_rst 1>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c2: i2c@01c2b400 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01c2b400 0x400>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&apb2_gates 2>;
+ resets = <&apb2_rst 2>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ 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>;
+ };
+
+ prcm@01f01400 {
+ compatible = "allwinner,sun8i-a23-prcm";
+ reg = <0x01f01400 0x200>;
+
+ ar100: ar100_clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&osc24M>;
+ clock-output-names = "ar100";
+ };
+
+ ahb0: ahb0_clk {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&ar100>;
+ clock-output-names = "ahb0";
+ };
+
+ apb0: apb0_clk {
+ compatible = "allwinner,sun8i-a23-apb0-clk";
+ #clock-cells = <0>;
+ clocks = <&ahb0>;
+ clock-output-names = "apb0";
+ };
+
+ apb0_gates: apb0_gates_clk {
+ compatible = "allwinner,sun8i-a23-apb0-gates-clk";
+ #clock-cells = <1>;
+ clocks = <&apb0>;
+ clock-output-names = "apb0_pio", "apb0_timer",
+ "apb0_rsb", "apb0_uart",
+ "apb0_i2c";
+ };
+
+ apb0_rst: apb0_rst {
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ #reset-cells = <1>;
+ };
+ };
+
+ cpucfg@01f01c00 {
+ compatible = "allwinner,sun8i-a23-cpuconfig";
+ reg = <0x01f01c00 0x300>;
+ };
+
+ r_uart: serial@01f02800 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x01f02800 0x400>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb0_gates 4>;
+ resets = <&apb0_rst 4>;
+ status = "disabled";
+ };
+
+ r_pio: pinctrl@01f02c00 {
+ compatible = "allwinner,sun8i-a23-r-pinctrl";
+ reg = <0x01f02c00 0x400>;
+ interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&apb0_gates 0>;
+ resets = <&apb0_rst 0>;
+ gpio-controller;
+ interrupt-controller;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #gpio-cells = <3>;
+
+ r_uart_pins_a: r_uart@0 {
+ allwinner,pins = "PL2", "PL3";
+ allwinner,function = "s_uart";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/sun8i-a23-evb.dts b/arch/arm/boot/dts/sun8i-a23-evb.dts
new file mode 100644
index 000000000000..610786e635fa
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a23-evb.dts
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2015 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@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 "sun8i-a23.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Allwinner A23 Evaluation Board";
+ compatible = "allwinner,sun8i-a23-evb", "allwinner,sun8i-a23";
+
+ aliases {
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ serial0 = &r_uart;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&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 = "Home";
+ linux,code = <KEY_HOME>;
+ channel = <0>;
+ voltage = <600000>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_evb>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
+ cd-inverted;
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_evb: mmc0_cd_pin@0 {
+ allwinner,pins = "PB4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+/*
+ * The RX line has a non-populated resistance. In order to use it, you
+ * need to solder R207 on the back of the board in order to close the
+ * line and get a working UART.
+ */
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins_a>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts
index dd31c53e2ab6..382d64c3b78e 100644
--- a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts
+++ b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts
@@ -16,11 +16,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 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
diff --git a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
index 623573e46080..95134c69cfc1 100644
--- a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
+++ b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
@@ -18,11 +18,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 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
@@ -64,71 +59,69 @@
};
chosen {
- bootargs = "earlyprintk console=ttyS0,115200";
+ stdout-path = "serial0:115200n8";
};
+};
- soc@01c00000 {
- mmc0: mmc@01c0f000 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_q8h>;
- vmmc-supply = <&reg_vcc3v0>;
- bus-width = <4>;
- cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
- cd-inverted;
- status = "okay";
- };
-
- pinctrl@01c20800 {
- mmc0_cd_pin_q8h: mmc0_cd_pin@0 {
- allwinner,pins = "PB4";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
- };
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+};
- lradc: lradc@01c22800 {
- vref-supply = <&reg_vcc3v0>;
- status = "okay";
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
- button@200 {
- label = "Volume Up";
- linux,code = <KEY_VOLUMEUP>;
- channel = <0>;
- voltage = <200000>;
- };
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ /* pull-ups and devices require PMIC regulator */
+ status = "failed";
+};
- button@400 {
- label = "Volume Down";
- linux,code = <KEY_VOLUMEDOWN>;
- channel = <0>;
- voltage = <400000>;
- };
- };
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
- i2c0: i2c@01c2ac00 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
- };
+ button@200 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <200000>;
+ };
- i2c1: i2c@01c2b000 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
- };
+ button@400 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <400000>;
+ };
+};
- i2c2: i2c@01c2b400 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins_a>;
- /* pull-ups and devices require PMIC regulator */
- status = "failed";
- };
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_q8h>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
+ cd-inverted;
+ status = "okay";
+};
- r_uart: serial@01f02800 {
- pinctrl-names = "default";
- pinctrl-0 = <&r_uart_pins_a>;
- status = "okay";
- };
+&pio {
+ mmc0_cd_pin_q8h: mmc0_cd_pin@0 {
+ allwinner,pins = "PB4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins_a>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-a23.dtsi b/arch/arm/boot/dts/sun8i-a23.dtsi
index 382ebd137ee4..8698f7aa31c7 100644
--- a/arch/arm/boot/dts/sun8i-a23.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23.dtsi
@@ -18,11 +18,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 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
@@ -47,206 +42,14 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "skeleton.dtsi"
-
-#include <dt-bindings/interrupt-controller/arm-gic.h>
-
-#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include "sun8i-a23-a33.dtsi"
/ {
- interrupt-parent = <&gic>;
-
- chosen {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- framebuffer@0 {
- compatible = "allwinner,simple-framebuffer",
- "simple-framebuffer";
- allwinner,pipeline = "de_be0-lcd0";
- clocks = <&pll6 0>;
- status = "disabled";
- };
- };
-
- 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>;
- };
- };
-
memory {
reg = <0x40000000 0x40000000>;
};
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";
- };
-
- cpu: cpu_clk@01c20050 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-cpu-clk";
- reg = <0x01c20050 0x4>;
-
- /*
- * PLL1 is listed twice here.
- * While it looks suspicious, it's actually documented
- * that way both in the datasheet and in the code from
- * Allwinner.
- */
- clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>;
- clock-output-names = "cpu";
- };
-
- axi: axi_clk@01c20050 {
- #clock-cells = <0>;
- compatible = "allwinner,sun8i-a23-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";
- };
-
- apb1: apb1_clk@01c20054 {
- #clock-cells = <0>;
- compatible = "allwinner,sun4i-a10-apb0-clk";
- reg = <0x01c20054 0x4>;
- clocks = <&ahb1>;
- clock-output-names = "apb1";
- };
-
- ahb1_gates: clk@01c20060 {
- #clock-cells = <1>;
- compatible = "allwinner,sun8i-a23-ahb1-gates-clk";
- reg = <0x01c20060 0x8>;
- clocks = <&ahb1>;
- clock-output-names = "ahb1_mipidsi", "ahb1_dma",
- "ahb1_mmc0", "ahb1_mmc1", "ahb1_mmc2",
- "ahb1_nand", "ahb1_sdram",
- "ahb1_hstimer", "ahb1_spi0",
- "ahb1_spi1", "ahb1_otg", "ahb1_ehci",
- "ahb1_ohci", "ahb1_ve", "ahb1_lcd",
- "ahb1_csi", "ahb1_be", "ahb1_fe",
- "ahb1_gpu", "ahb1_spinlock",
- "ahb1_drc";
- };
-
- apb1_gates: clk@01c20068 {
- #clock-cells = <1>;
- compatible = "allwinner,sun8i-a23-apb1-gates-clk";
- reg = <0x01c20068 0x4>;
- clocks = <&apb1>;
- clock-output-names = "apb1_codec", "apb1_pio",
- "apb1_daudio0", "apb1_daudio1";
- };
-
- 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";
- };
-
- apb2_gates: clk@01c2006c {
- #clock-cells = <1>;
- compatible = "allwinner,sun8i-a23-apb2-gates-clk";
- reg = <0x01c2006c 0x4>;
- clocks = <&apb2>;
- clock-output-names = "apb2_i2c0", "apb2_i2c1",
- "apb2_i2c2", "apb2_uart0",
- "apb2_uart1", "apb2_uart2",
- "apb2_uart3", "apb2_uart4";
- };
-
- mmc0_clk: clk@01c20088 {
- #clock-cells = <1>;
- compatible = "allwinner,sun4i-a10-mmc-clk";
- reg = <0x01c20088 0x4>;
- clocks = <&osc24M>, <&pll6 0>;
- 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>;
- 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>;
- clock-output-names = "mmc2",
- "mmc2_output",
- "mmc2_sample";
- };
-
mbus_clk: clk@01c2015c {
#clock-cells = <0>;
compatible = "allwinner,sun8i-a23-mbus-clk";
@@ -255,357 +58,11 @@
clock-output-names = "mbus";
};
};
+};
- soc@01c00000 {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- dma: dma-controller@01c02000 {
- compatible = "allwinner,sun8i-a23-dma";
- reg = <0x01c02000 0x1000>;
- interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ahb1_gates 6>;
- resets = <&ahb1_rst 6>;
- #dma-cells = <1>;
- };
-
- mmc0: mmc@01c0f000 {
- compatible = "allwinner,sun5i-a13-mmc";
- reg = <0x01c0f000 0x1000>;
- clocks = <&ahb1_gates 8>,
- <&mmc0_clk 0>,
- <&mmc0_clk 1>,
- <&mmc0_clk 2>;
- clock-names = "ahb",
- "mmc",
- "output",
- "sample";
- resets = <&ahb1_rst 8>;
- reset-names = "ahb";
- interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
- status = "disabled";
- };
-
- mmc1: mmc@01c10000 {
- compatible = "allwinner,sun5i-a13-mmc";
- reg = <0x01c10000 0x1000>;
- clocks = <&ahb1_gates 9>,
- <&mmc1_clk 0>,
- <&mmc1_clk 1>,
- <&mmc1_clk 2>;
- clock-names = "ahb",
- "mmc",
- "output",
- "sample";
- resets = <&ahb1_rst 9>;
- reset-names = "ahb";
- interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
- status = "disabled";
- };
-
- mmc2: mmc@01c11000 {
- compatible = "allwinner,sun5i-a13-mmc";
- reg = <0x01c11000 0x1000>;
- clocks = <&ahb1_gates 10>,
- <&mmc2_clk 0>,
- <&mmc2_clk 1>,
- <&mmc2_clk 2>;
- clock-names = "ahb",
- "mmc",
- "output",
- "sample";
- resets = <&ahb1_rst 10>;
- reset-names = "ahb";
- interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
- status = "disabled";
- };
-
- pio: pinctrl@01c20800 {
- compatible = "allwinner,sun8i-a23-pinctrl";
- reg = <0x01c20800 0x400>;
- interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb1_gates 5>;
- gpio-controller;
- interrupt-controller;
- #address-cells = <1>;
- #size-cells = <0>;
- #gpio-cells = <3>;
-
- uart0_pins_a: uart0@0 {
- allwinner,pins = "PF2", "PF4";
- 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>;
- };
-
- 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>;
- };
-
- i2c0_pins_a: i2c0@0 {
- allwinner,pins = "PH2", "PH3";
- allwinner,function = "i2c0";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- i2c1_pins_a: i2c1@0 {
- allwinner,pins = "PH4", "PH5";
- allwinner,function = "i2c1";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
- i2c2_pins_a: i2c2@0 {
- allwinner,pins = "PE12", "PE13";
- allwinner,function = "i2c2";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
-
- ahb1_rst: reset@01c202c0 {
- #reset-cells = <1>;
- compatible = "allwinner,sun6i-a31-clock-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>;
- };
-
- lradc: lradc@01c22800 {
- compatible = "allwinner,sun4i-a10-lradc-keys";
- reg = <0x01c22800 0x100>;
- interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
- status = "disabled";
- };
-
- 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 = <&apb2_gates 16>;
- 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 = <&apb2_gates 17>;
- 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 = <&apb2_gates 18>;
- 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 = <&apb2_gates 19>;
- resets = <&apb2_rst 19>;
- dmas = <&dma 9>, <&dma 9>;
- dma-names = "rx", "tx";
- status = "disabled";
- };
-
- uart4: serial@01c29000 {
- compatible = "snps,dw-apb-uart";
- reg = <0x01c29000 0x400>;
- interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
- reg-shift = <2>;
- reg-io-width = <4>;
- clocks = <&apb2_gates 20>;
- resets = <&apb2_rst 20>;
- dmas = <&dma 10>, <&dma 10>;
- dma-names = "rx", "tx";
- status = "disabled";
- };
-
- i2c0: i2c@01c2ac00 {
- compatible = "allwinner,sun6i-a31-i2c";
- reg = <0x01c2ac00 0x400>;
- interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb2_gates 0>;
- resets = <&apb2_rst 0>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
- };
-
- i2c1: i2c@01c2b000 {
- compatible = "allwinner,sun6i-a31-i2c";
- reg = <0x01c2b000 0x400>;
- interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb2_gates 1>;
- resets = <&apb2_rst 1>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
- };
-
- i2c2: i2c@01c2b400 {
- compatible = "allwinner,sun6i-a31-i2c";
- reg = <0x01c2b400 0x400>;
- interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb2_gates 2>;
- resets = <&apb2_rst 2>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
- };
-
- 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>;
- };
-
- prcm@01f01400 {
- compatible = "allwinner,sun8i-a23-prcm";
- reg = <0x01f01400 0x200>;
-
- ar100: ar100_clk {
- compatible = "fixed-factor-clock";
- #clock-cells = <0>;
- clock-div = <1>;
- clock-mult = <1>;
- clocks = <&osc24M>;
- clock-output-names = "ar100";
- };
-
- ahb0: ahb0_clk {
- compatible = "fixed-factor-clock";
- #clock-cells = <0>;
- clock-div = <1>;
- clock-mult = <1>;
- clocks = <&ar100>;
- clock-output-names = "ahb0";
- };
-
- apb0: apb0_clk {
- compatible = "allwinner,sun8i-a23-apb0-clk";
- #clock-cells = <0>;
- clocks = <&ahb0>;
- clock-output-names = "apb0";
- };
-
- apb0_gates: apb0_gates_clk {
- compatible = "allwinner,sun8i-a23-apb0-gates-clk";
- #clock-cells = <1>;
- clocks = <&apb0>;
- clock-output-names = "apb0_pio", "apb0_timer",
- "apb0_rsb", "apb0_uart",
- "apb0_i2c";
- };
-
- apb0_rst: apb0_rst {
- compatible = "allwinner,sun6i-a31-clock-reset";
- #reset-cells = <1>;
- };
- };
-
- r_uart: serial@01f02800 {
- compatible = "snps,dw-apb-uart";
- reg = <0x01f02800 0x400>;
- interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
- reg-shift = <2>;
- reg-io-width = <4>;
- clocks = <&apb0_gates 4>;
- resets = <&apb0_rst 4>;
- status = "disabled";
- };
-
- r_pio: pinctrl@01f02c00 {
- compatible = "allwinner,sun8i-a23-r-pinctrl";
- reg = <0x01f02c00 0x400>;
- interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&apb0_gates 0>;
- resets = <&apb0_rst 0>;
- gpio-controller;
- interrupt-controller;
- #address-cells = <1>;
- #size-cells = <0>;
- #gpio-cells = <3>;
-
- r_uart_pins_a: r_uart@0 {
- allwinner,pins = "PL2", "PL3";
- allwinner,function = "s_uart";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
- };
- };
+&pio {
+ compatible = "allwinner,sun8i-a23-pinctrl";
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
};
diff --git a/arch/arm/boot/dts/sun8i-a33-et-q8-v1.6.dts b/arch/arm/boot/dts/sun8i-a33-et-q8-v1.6.dts
new file mode 100644
index 000000000000..19db844863bb
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a33-et-q8-v1.6.dts
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2015 Vishnu Patekar
+ * Vishnu Patekar <vishnupatekar0510@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-a33.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "ET Q8 Quad Core Tablet (v1.6)";
+ compatible = "et,q8-v1.6", "allwinner,sun8i-a33";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+ 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>;
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-a33-ga10h-v1.1.dts b/arch/arm/boot/dts/sun8i-a33-ga10h-v1.1.dts
new file mode 100644
index 000000000000..866703355b9c
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a33-ga10h-v1.1.dts
@@ -0,0 +1,125 @@
+/*
+ * 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 "sun8i-a33.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Allwinner GA10H Quad Core Tablet (v1.1)";
+ compatible = "allwinner,ga10h-v1.1", "allwinner,sun8i-a33";
+
+ aliases {
+ serial0 = &r_uart;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+ 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>;
+ };
+
+ button@600 {
+ label = "Back";
+ linux,code = <KEY_BACK>;
+ channel = <0>;
+ voltage = <600000>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_q8h>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
+ cd-inverted;
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_q8h: mmc0_cd_pin@0 {
+ allwinner,pins = "PB4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins_a>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
new file mode 100644
index 000000000000..5788c29cb56a
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.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
+ * 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-a33.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Sinlinx SinA33";
+ compatible = "sinlinx,sina33", "allwinner,sun8i-a33";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
+
+ button@200 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <191011>;
+ };
+
+ button@400 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <391304>;
+ };
+
+ button@600 {
+ label = "Home";
+ linux,code = <KEY_HOME>;
+ channel = <0>;
+ voltage = <600000>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_sina33>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <8>;
+ non-removable;
+ status = "okay";
+};
+
+&mmc2_8bit_pins {
+ /* eMMC is missing pull-ups */
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&pio {
+ mmc0_cd_pin_sina33: mmc0_cd_pin@0 {
+ allwinner,pins = "PB4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_b>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
new file mode 100644
index 000000000000..85ee08098b7b
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2014 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.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
+ * 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 "sun8i-a23-a33.dtsi"
+
+/ {
+ cpus {
+ cpu@2 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <2>;
+ };
+
+ cpu@3 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <3>;
+ };
+ };
+
+ memory {
+ reg = <0x40000000 0x80000000>;
+ };
+
+ clocks {
+ /* Dummy clock for pll11 (DDR1) until actually implemented */
+ pll11: pll11_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <0>;
+ clock-output-names = "pll11";
+ };
+
+ mbus_clk: clk@01c2015c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun8i-a23-mbus-clk";
+ reg = <0x01c2015c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5>, <&pll11>;
+ clock-output-names = "mbus";
+ };
+ };
+};
+
+&pio {
+ compatible = "allwinner,sun8i-a33-pinctrl";
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+
+ uart0_pins_b: uart0@1 {
+ allwinner,pins = "PB0", "PB1";
+ allwinner,function = "uart0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+};
diff --git a/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
new file mode 100644
index 000000000000..6484dcf69873
--- /dev/null
+++ b/arch/arm/boot/dts/sun9i-a80-cubieboard4.dts
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2015 Tyler Baker
+ *
+ * Tyler Baker <tyler.baker@linaro.org>
+ * Chen-Yu Tsai <wens@csie.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
+ * 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 "sun9i-a80.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Cubietech Cubieboard4";
+ compatible = "cubietech,a80-cubieboard4", "allwinner,sun9i-a80";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+};
+
+&pio {
+ mmc0_cd_pin_cubieboard4: mmc0_cd_pin@0 {
+ allwinner,pins = "PH18";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins>, <&mmc0_cd_pin_cubieboard4>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 18 GPIO_ACTIVE_HIGH>; /* PH18 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <8>;
+ non-removable;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts
index a3fed2bdf620..6ce4b5e8b615 100644
--- a/arch/arm/boot/dts/sun9i-a80-optimus.dts
+++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -18,11 +18,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 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
@@ -64,7 +59,7 @@
};
chosen {
- bootargs = "earlyprintk console=ttyS0,115200";
+ stdout-path = "serial0:115200n8";
};
leds {
@@ -86,6 +81,29 @@
gpios = <&pio 7 0 GPIO_ACTIVE_HIGH>;
};
};
+
+ reg_usb3_vbus: usb3-vbus {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb3_vbus_pin_optimus>;
+ regulator-name = "usb3-vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+ };
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
};
&i2c3 {
@@ -99,6 +117,14 @@
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+&ohci0 {
+ status = "okay";
+};
+
+&ohci2 {
+ status = "okay";
+};
+
&pio {
led_pins_optimus: led-pins@0 {
allwinner,pins = "PH0", "PH1";
@@ -113,6 +139,20 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+
+ usb1_vbus_pin_optimus: usb1_vbus_pin@1 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb3_vbus_pin_optimus: usb3_vbus_pin@1 {
+ allwinner,pins = "PH5";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};
&mmc0 {
@@ -134,6 +174,12 @@
status = "okay";
};
+&reg_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_optimus>;
+ gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins_a>;
@@ -150,3 +196,17 @@
/* Enable internal pull-up */
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+
+&usbphy1 {
+ phy-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
+
+&usbphy2 {
+ status = "okay";
+};
+
+&usbphy3 {
+ phy-supply = <&reg_usb3_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index f0f6fb91f8c3..a43ad779ee2f 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -18,11 +18,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 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
@@ -114,6 +109,16 @@
reg = <0 0x20000000 0x02 0>;
};
+ 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)>;
+ clock-frequency = <24000000>;
+ arm,cpu-registers-not-fw-configured;
+ };
+
clocks {
#address-cells = <1>;
#size-cells = <1>;
@@ -137,6 +142,28 @@
clock-output-names = "osc32k";
};
+ usb_mod_clk: clk@00a08000 {
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ compatible = "allwinner,sun9i-a80-usb-mod-clk";
+ reg = <0x00a08000 0x4>;
+ clocks = <&ahb1_gates 1>;
+ clock-output-names = "usb0_ahb", "usb_ohci0",
+ "usb1_ahb", "usb_ohci1",
+ "usb2_ahb", "usb_ohci2";
+ };
+
+ usb_phy_clk: clk@00a08004 {
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ compatible = "allwinner,sun9i-a80-usb-phy-clk";
+ reg = <0x00a08004 0x4>;
+ clocks = <&ahb1_gates 1>;
+ clock-output-names = "usb_phy0", "usb_hsic1_480M",
+ "usb_phy1", "usb_hsic2_480M",
+ "usb_phy2", "usb_hsic_12M";
+ };
+
pll4: clk@0600000c {
#clock-cells = <0>;
compatible = "allwinner,sun9i-a80-pll4-clk";
@@ -257,7 +284,7 @@
"ahb0_ss", "ahb0_sd", "ahb0_nand1",
"ahb0_nand0", "ahb0_sdram",
"ahb0_mipi_hsi", "ahb0_sata", "ahb0_ts",
- "ahb0_spi0","ahb0_spi1", "ahb0_spi2",
+ "ahb0_spi0", "ahb0_spi1", "ahb0_spi2",
"ahb0_spi3";
};
@@ -323,6 +350,98 @@
*/
ranges = <0 0 0 0x20000000>;
+ ehci0: usb@00a00000 {
+ compatible = "allwinner,sun9i-a80-ehci", "generic-ehci";
+ reg = <0x00a00000 0x100>;
+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_mod_clk 1>;
+ resets = <&usb_mod_clk 17>;
+ phys = <&usbphy1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci0: usb@00a00400 {
+ compatible = "allwinner,sun9i-a80-ohci", "generic-ohci";
+ reg = <0x00a00400 0x100>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_mod_clk 1>, <&usb_mod_clk 2>;
+ resets = <&usb_mod_clk 17>;
+ phys = <&usbphy1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ usbphy1: phy@00a00800 {
+ compatible = "allwinner,sun9i-a80-usb-phy";
+ reg = <0x00a00800 0x4>;
+ clocks = <&usb_phy_clk 1>;
+ clock-names = "phy";
+ resets = <&usb_phy_clk 17>;
+ reset-names = "phy";
+ status = "disabled";
+ #phy-cells = <0>;
+ };
+
+ ehci1: usb@00a01000 {
+ compatible = "allwinner,sun9i-a80-ehci", "generic-ehci";
+ reg = <0x00a01000 0x100>;
+ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_mod_clk 3>;
+ resets = <&usb_mod_clk 18>;
+ phys = <&usbphy2>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ usbphy2: phy@00a01800 {
+ compatible = "allwinner,sun9i-a80-usb-phy";
+ reg = <0x00a01800 0x4>;
+ clocks = <&usb_phy_clk 2>, <&usb_phy_clk 10>,
+ <&usb_phy_clk 3>;
+ clock-names = "hsic_480M", "hsic_12M", "phy";
+ resets = <&usb_phy_clk 18>, <&usb_phy_clk 19>;
+ reset-names = "hsic", "phy";
+ status = "disabled";
+ #phy-cells = <0>;
+ /* usb1 is always used with HSIC */
+ phy_type = "hsic";
+ };
+
+ ehci2: usb@00a02000 {
+ compatible = "allwinner,sun9i-a80-ehci", "generic-ehci";
+ reg = <0x00a02000 0x100>;
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_mod_clk 5>;
+ resets = <&usb_mod_clk 19>;
+ phys = <&usbphy3>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci2: usb@00a02400 {
+ compatible = "allwinner,sun9i-a80-ohci", "generic-ohci";
+ reg = <0x00a02400 0x100>;
+ interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_mod_clk 5>, <&usb_mod_clk 6>;
+ resets = <&usb_mod_clk 19>;
+ phys = <&usbphy3>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ usbphy3: phy@00a02800 {
+ compatible = "allwinner,sun9i-a80-usb-phy";
+ reg = <0x00a02800 0x4>;
+ clocks = <&usb_phy_clk 4>, <&usb_phy_clk 10>,
+ <&usb_phy_clk 5>;
+ clock-names = "hsic_480M", "hsic_12M", "phy";
+ resets = <&usb_phy_clk 20>, <&usb_phy_clk 21>;
+ reset-names = "hsic", "phy";
+ status = "disabled";
+ #phy-cells = <0>;
+ };
+
mmc0: mmc@01c0f000 {
compatible = "allwinner,sun5i-a13-mmc";
reg = <0x01c0f000 0x1000>;
@@ -333,6 +452,8 @@
reset-names = "ahb";
interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc1: mmc@01c10000 {
@@ -345,6 +466,8 @@
reset-names = "ahb";
interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc2: mmc@01c11000 {
@@ -357,6 +480,8 @@
reset-names = "ahb";
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc3: mmc@01c12000 {
@@ -369,6 +494,8 @@
reset-names = "ahb";
interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
mmc_config_clk: clk@01c13000 {
@@ -438,6 +565,12 @@
clocks = <&osc24M>;
};
+ wdt: watchdog@06000ca0 {
+ compatible = "allwinner,sun6i-a31-wdt";
+ reg = <0x06000ca0 0x20>;
+ interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
pio: pinctrl@06000800 {
compatible = "allwinner,sun9i-a80-pinctrl";
reg = <0x06000800 0x400>;
diff --git a/arch/arm/boot/dts/sunxi-common-regulators.dtsi b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
index e02baa66b33c..51cc8383f70f 100644
--- a/arch/arm/boot/dts/sunxi-common-regulators.dtsi
+++ b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
@@ -18,11 +18,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 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
diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
index ed8a8acd3d34..bd43ed6d6ec7 100644
--- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts
+++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
@@ -1647,6 +1647,10 @@
target-12v-supply = <&vdd_12v0_sata>;
};
+ hda@0,70030000 {
+ status = "okay";
+ };
+
padctl@0,7009f000 {
pinctrl-0 = <&padctl_default>;
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/tegra124-venice2.dts b/arch/arm/boot/dts/tegra124-venice2.dts
index 5c3f7813360d..79e724bb7df7 100644
--- a/arch/arm/boot/dts/tegra124-venice2.dts
+++ b/arch/arm/boot/dts/tegra124-venice2.dts
@@ -899,6 +899,7 @@
sdhci@0,700b0600 {
status = "okay";
bus-width = <8>;
+ non-removable;
};
ahub@0,70300000 {
@@ -1040,6 +1041,8 @@
compatible = "regulator-fixed";
reg = <5>;
regulator-name = "+VDD_LED";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
gpio = <&gpio TEGRA_GPIO(P, 2) GPIO_ACTIVE_HIGH>;
enable-active-high;
vin-supply = <&vdd_mux>;
diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 13cc7ca5e031..01a9f742b08f 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -300,7 +300,7 @@
apbmisc@0,70000800 {
compatible = "nvidia,tegra124-apbmisc", "nvidia,tegra20-apbmisc";
reg = <0x0 0x70000800 0x0 0x64>, /* Chip revision */
- <0x0 0x7000E864 0x0 0x04>; /* Strapping options */
+ <0x0 0x7000e864 0x0 0x04>; /* Strapping options */
};
pinmux: pinmux@0,70000868 {
@@ -633,11 +633,11 @@
clocks = <&tegra_car TEGRA124_CLK_HDA>,
<&tegra_car TEGRA124_CLK_HDA2HDMI>,
<&tegra_car TEGRA124_CLK_HDA2CODEC_2X>;
- clock-names = "hda", "hda2hdmi", "hdacodec_2x";
+ clock-names = "hda", "hda2hdmi", "hda2codec_2x";
resets = <&tegra_car 125>, /* hda */
<&tegra_car 128>, /* hda2hdmi */
<&tegra_car 111>; /* hda2codec_2x */
- reset-names = "hda", "hda2hdmi", "hdacodec_2x";
+ reset-names = "hda", "hda2hdmi", "hda2codec_2x";
status = "disabled";
};
diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
index e2fed2712249..aea8994b35f2 100644
--- a/arch/arm/boot/dts/tegra20-seaboard.dts
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
@@ -31,6 +31,7 @@
vdd-supply = <&hdmi_vdd_reg>;
pll-supply = <&hdmi_pll_reg>;
+ hdmi-supply = <&vdd_hdmi>;
nvidia,ddc-i2c-bus = <&hdmi_ddc>;
nvidia,hpd-gpio = <&gpio TEGRA_GPIO(N, 7)
@@ -893,6 +894,17 @@
gpio = <&gpio TEGRA_GPIO(W, 0) GPIO_ACTIVE_HIGH>;
enable-active-high;
};
+
+ vdd_hdmi: regulator@6 {
+ compatible = "regulator-fixed";
+ reg = <6>;
+ regulator-name = "VDDIO_HDMI";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio TEGRA_GPIO(V, 5) GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ vin-supply = <&vdd_5v0_reg>;
+ };
};
sound {
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index adf6b048d0bb..f444b67f55c6 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -563,7 +563,7 @@
fuse@7000f800 {
compatible = "nvidia,tegra20-efuse";
- reg = <0x7000F800 0x400>;
+ reg = <0x7000f800 0x400>;
clocks = <&tegra_car TEGRA20_CLK_FUSE>;
clock-names = "fuse";
resets = <&tegra_car 39>;
diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi
index a1b682ea01bd..bb1ca158273c 100644
--- a/arch/arm/boot/dts/tegra30-cardhu.dtsi
+++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi
@@ -1,3 +1,4 @@
+#include <dt-bindings/input/input.h>
#include "tegra30.dtsi"
/**
@@ -12,7 +13,7 @@
* tegra30-cardhu-a04.dts.
* The identification of board is done in two ways, by looking the sticker
* on PCB and by reading board id eeprom.
- * The stciker will have number like 600-81291-1000-002 C.3. In this 4th
+ * The sticker will have number like 600-81291-1000-002 C.3. In this 4th
* number is the fab version like here it is 002 and hence fab version A02.
* The (downstream internal) U-Boot of Cardhu display the board-id as
* follows:
@@ -615,4 +616,31 @@
<&tegra_car TEGRA30_CLK_EXTERN1>;
clock-names = "pll_a", "pll_a_out0", "mclk";
};
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ power {
+ label = "Power";
+ interrupt-parent = <&pmic>;
+ interrupts = <2 0>;
+ linux,code = <KEY_POWER>;
+ debounce-interval = <100>;
+ gpio-key,wakeup;
+ };
+
+ volume-down {
+ label = "Volume Down";
+ gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEDOWN>;
+ debounce-interval = <10>;
+ };
+
+ volume-up {
+ label = "Volume Up";
+ gpios = <&gpio TEGRA_GPIO(R, 1) GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEUP>;
+ debounce-interval = <10>;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index 60e205a0f63d..782b11b2af6a 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -654,6 +654,21 @@
reset-names = "fuse";
};
+ hda@70030000 {
+ compatible = "nvidia,tegra30-hda";
+ reg = <0x70030000 0x10000>;
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&tegra_car TEGRA30_CLK_HDA>,
+ <&tegra_car TEGRA30_CLK_HDA2HDMI>,
+ <&tegra_car TEGRA30_CLK_HDA2CODEC_2X>;
+ clock-names = "hda", "hda2hdmi", "hda2codec_2x";
+ resets = <&tegra_car 125>, /* hda */
+ <&tegra_car 128>, /* hda2hdmi */
+ <&tegra_car 111>; /* hda2codec_2x */
+ reset-names = "hda", "hda2hdmi", "hda2codec_2x";
+ status = "disabled";
+ };
+
ahub@70080000 {
compatible = "nvidia,tegra30-ahub";
reg = <0x70080000 0x200
diff --git a/arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts b/arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts
new file mode 100644
index 000000000000..200b0c99ed34
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts
@@ -0,0 +1,79 @@
+/*
+ * Device Tree Source for UniPhier PH1-LD4 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-ld4.dtsi"
+/include/ "uniphier-support-card.dtsi"
+
+/ {
+ model = "UniPhier PH1-LD4 Reference Board";
+ compatible = "socionext,ph1-ld4-ref", "socionext,ph1-ld4";
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x20000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &serialsc;
+ };
+
+ aliases {
+ serial0 = &serialsc;
+ };
+};
+
+&extbus {
+ ranges = <0 0x00000000 0x0f000000 0x01000000
+ 1 0x00000000 0x00000000 0x08000000>;
+};
+
+&support_card {
+ ranges = <0x00000000 1 0x03f00000 0x00100000>;
+};
+
+&serialsc {
+ interrupts = <0 49 4>;
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi b/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi
new file mode 100644
index 000000000000..6a34c56e4693
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi
@@ -0,0 +1,110 @@
+/*
+ * Device Tree Source for UniPhier PH1-LD4 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.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ compatible = "socionext,ph1-ld4";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ };
+ };
+
+ clocks {
+ arm_timer_clk: arm_timer_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ 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>;
+ };
+
+ system-bus-controller-misc@59800000 {
+ compatible = "socionext,uniphier-system-bus-controller-misc",
+ "syscon";
+ reg = <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";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x60001000 0x1000>,
+ <0x60000100 0x100>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts b/arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts
new file mode 100644
index 000000000000..d891135a70c2
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts
@@ -0,0 +1,79 @@
+/*
+ * Device Tree Source for UniPhier PH1-Pro4 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-pro4.dtsi"
+/include/ "uniphier-support-card.dtsi"
+
+/ {
+ model = "UniPhier PH1-Pro4 Reference Board";
+ compatible = "socionext,ph1-pro4-ref", "socionext,ph1-pro4";
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x40000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &serialsc;
+ };
+
+ aliases {
+ serial0 = &serialsc;
+ };
+};
+
+&extbus {
+ ranges = <0 0x00000000 0x0f000000 0x01000000
+ 1 0x00000000 0x00000000 0x08000000>;
+};
+
+&support_card {
+ ranges = <0x00000000 1 0x03f00000 0x00100000>;
+};
+
+&serialsc {
+ interrupts = <0 50 4>;
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi b/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi
new file mode 100644
index 000000000000..dc633603aed2
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi
@@ -0,0 +1,117 @@
+/*
+ * Device Tree Source for UniPhier PH1-Pro4 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.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ compatible = "socionext,ph1-pro4";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ enable-method = "socionext,uniphier-smp";
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <1>;
+ };
+ };
+
+ clocks {
+ arm_timer_clk: arm_timer_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ 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>;
+ };
+
+ system-bus-controller-misc@59800000 {
+ compatible = "socionext,uniphier-system-bus-controller-misc",
+ "syscon";
+ reg = <0x59800000 0x2000>;
+ };
+
+ timer@60000200 {
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0x60000200 0x20>;
+ interrupts = <1 11 0x304>;
+ clocks = <&arm_timer_clk>;
+ };
+
+ timer@60000600 {
+ compatible = "arm,cortex-a9-twd-timer";
+ reg = <0x60000600 0x20>;
+ interrupts = <1 13 0x304>;
+ clocks = <&arm_timer_clk>;
+ };
+
+ intc: interrupt-controller@60001000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x60001000 0x1000>,
+ <0x60000100 0x100>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts b/arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts
new file mode 100644
index 000000000000..3ea64ae009e9
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts
@@ -0,0 +1,80 @@
+/*
+ * Device Tree Source for UniPhier PH1-sLD3 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-sld3.dtsi"
+/include/ "uniphier-support-card.dtsi"
+
+/ {
+ model = "UniPhier PH1-sLD3 Reference Board";
+ compatible = "socionext,ph1-sld3-ref", "socionext,ph1-sld3";
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x20000000
+ 0xc0000000 0x20000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &serialsc;
+ };
+
+ aliases {
+ serial0 = &serialsc;
+ };
+};
+
+&extbus {
+ ranges = <0 0x00000000 0x0f000000 0x01000000
+ 1 0x00000000 0x00000000 0x08000000>;
+};
+
+&support_card {
+ ranges = <0x00000000 1 0x03f00000 0x00100000>;
+};
+
+&serialsc {
+ interrupts = <0 49 4>;
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld3.dtsi b/arch/arm/boot/dts/uniphier-ph1-sld3.dtsi
new file mode 100644
index 000000000000..248b1886834f
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-ph1-sld3.dtsi
@@ -0,0 +1,117 @@
+/*
+ * Device Tree Source for UniPhier PH1-sLD3 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.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ compatible = "socionext,ph1-sld3";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ enable-method = "socionext,uniphier-smp";
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <1>;
+ };
+ };
+
+ clocks {
+ arm_timer_clk: arm_timer_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ 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>;
+ };
+
+ timer@20000200 {
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0x20000200 0x20>;
+ interrupts = <1 11 0x304>;
+ clocks = <&arm_timer_clk>;
+ };
+
+ timer@20000600 {
+ compatible = "arm,cortex-a9-twd-timer";
+ reg = <0x20000600 0x20>;
+ interrupts = <1 13 0x304>;
+ clocks = <&arm_timer_clk>;
+ };
+
+ intc: interrupt-controller@20001000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x20001000 0x1000>,
+ <0x20000100 0x100>;
+ };
+
+ system-bus-controller-misc@59800000 {
+ compatible = "socionext,uniphier-system-bus-controller-misc",
+ "syscon";
+ reg = <0x59800000 0x2000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts b/arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts
new file mode 100644
index 000000000000..dcdc4f74387d
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts
@@ -0,0 +1,79 @@
+/*
+ * Device Tree Source for UniPhier PH1-sLD8 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-sld8.dtsi"
+/include/ "uniphier-support-card.dtsi"
+
+/ {
+ model = "UniPhier PH1-sLD8 Reference Board";
+ compatible = "socionext,ph1-sld8-ref", "socionext,ph1-sld8";
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x20000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &serialsc;
+ };
+
+ aliases {
+ serial0 = &serialsc;
+ };
+};
+
+&extbus {
+ ranges = <0 0x00000000 0x0f000000 0x01000000
+ 1 0x00000000 0x00000000 0x08000000>;
+};
+
+&support_card {
+ ranges = <0x00000000 1 0x03f00000 0x00100000>;
+};
+
+&serialsc {
+ interrupts = <0 48 4>;
+};
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi b/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi
new file mode 100644
index 000000000000..baa71e1febb8
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi
@@ -0,0 +1,110 @@
+/*
+ * Device Tree Source for UniPhier PH1-sLD8 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.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ compatible = "socionext,ph1-sld8";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0>;
+ };
+ };
+
+ clocks {
+ arm_timer_clk: arm_timer_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ 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>;
+ };
+
+ system-bus-controller-misc@59800000 {
+ compatible = "socionext,uniphier-system-bus-controller-misc",
+ "syscon";
+ reg = <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";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x60001000 0x1000>,
+ <0x60000100 0x100>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/uniphier-support-card.dtsi b/arch/arm/boot/dts/uniphier-support-card.dtsi
new file mode 100644
index 000000000000..da271e3b922a
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-support-card.dtsi
@@ -0,0 +1,65 @@
+/*
+ * Device Tree Source for UniPhier Support Card (Expansion 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.
+ */
+
+&extbus {
+ support_card: support_card {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ ethsc: ethernet@00000000 {
+ compatible = "smsc,lan9118", "smsc,lan9115";
+ reg = <0x00000000 0x1000>;
+ phy-mode = "mii";
+ reg-io-width = <4>;
+ };
+
+ serialsc: uart@000b0000 {
+ compatible = "ns16550a";
+ reg = <0x000b0000 0x20>;
+ clock-frequency = <12288000>;
+ reg-shift = <1>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/vf-colibri.dtsi b/arch/arm/boot/dts/vf-colibri.dtsi
index fbef0828e930..68ca125b56ea 100644
--- a/arch/arm/boot/dts/vf-colibri.dtsi
+++ b/arch/arm/boot/dts/vf-colibri.dtsi
@@ -140,7 +140,7 @@
VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2
VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3
VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1
- VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1
+ VF610_PAD_PTC12__ENET_RMII1_RXD1 0x30d1
VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1
VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1
VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2
diff --git a/arch/arm/boot/dts/vf610-cosmic.dts b/arch/arm/boot/dts/vf610-cosmic.dts
index fd8758b639f5..5447f2594659 100644
--- a/arch/arm/boot/dts/vf610-cosmic.dts
+++ b/arch/arm/boot/dts/vf610-cosmic.dts
@@ -68,7 +68,7 @@
VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2
VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3
VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1
- VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1
+ VF610_PAD_PTC12__ENET_RMII1_RXD1 0x30d1
VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1
VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1
VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2
diff --git a/arch/arm/boot/dts/vf610-pinfunc.h b/arch/arm/boot/dts/vf610-pinfunc.h
index 1ee681f7ce2f..fcad7132c871 100644
--- a/arch/arm/boot/dts/vf610-pinfunc.h
+++ b/arch/arm/boot/dts/vf610-pinfunc.h
@@ -369,7 +369,7 @@
#define VF610_PAD_PTC11__MLB_DATA 0x0E0 0x358 ALT6 0x1
#define VF610_PAD_PTC11__DEBUG_OUT 0x0E0 0x000 ALT7 0x0
#define VF610_PAD_PTC12__GPIO_57 0x0E4 0x000 ALT0 0x0
-#define VF610_PAD_PTC12__ENET_RMII_RXD1 0x0E4 0x000 ALT1 0x0
+#define VF610_PAD_PTC12__ENET_RMII1_RXD1 0x0E4 0x000 ALT1 0x0
#define VF610_PAD_PTC12__ESAI_SDO1 0x0E4 0x318 ALT3 0x1
#define VF610_PAD_PTC12__SAI2_TX_BCLK 0x0E4 0x370 ALT5 0x1
#define VF610_PAD_PTC12__DEBUG_OUT3 0x0E4 0x000 ALT7 0x0
diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts
index f64fddce3e2a..375ab23ca743 100644
--- a/arch/arm/boot/dts/vf610-twr.dts
+++ b/arch/arm/boot/dts/vf610-twr.dts
@@ -221,7 +221,7 @@
VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2
VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3
VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1
- VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1
+ VF610_PAD_PTC12__ENET_RMII1_RXD1 0x30d1
VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1
VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1
VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2
diff --git a/arch/arm/boot/dts/vf610m4-colibri.dts b/arch/arm/boot/dts/vf610m4-colibri.dts
new file mode 100644
index 000000000000..2931a80caccb
--- /dev/null
+++ b/arch/arm/boot/dts/vf610m4-colibri.dts
@@ -0,0 +1,99 @@
+/*
+ * Device tree for Colibri VF61 Cortex-M4 support
+ *
+ * Copyright (C) 2015 Stefan Agner
+ *
+ * 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";
+
+ chosen {
+ bootargs = "console=ttyLP2,115200 clk_ignore_unused init=/linuxrc rw";
+ linux,stdout-path = "&uart2";
+ };
+
+ memory {
+ reg = <0x8c000000 0x3000000>;
+ };
+};
+
+&gpio0 {
+ status = "disabled";
+};
+
+&gpio1 {
+ status = "disabled";
+};
+
+&gpio2 {
+ status = "disabled";
+};
+
+&gpio3 {
+ status = "disabled";
+};
+
+&gpio4 {
+ status = "disabled";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+&iomuxc {
+ vf610-colibri {
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ VF610_PAD_PTD0__UART2_TX 0x21a2
+ VF610_PAD_PTD1__UART2_RX 0x21a1
+ VF610_PAD_PTD2__UART2_RTS 0x21a2
+ VF610_PAD_PTD3__UART2_CTS 0x21a1
+ >;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/vf610m4.dtsi b/arch/arm/boot/dts/vf610m4.dtsi
new file mode 100644
index 000000000000..9ffe2eb68ed4
--- /dev/null
+++ b/arch/arm/boot/dts/vf610m4.dtsi
@@ -0,0 +1,50 @@
+/*
+ * Device tree for VF6xx Cortex-M4 support
+ *
+ * Copyright (C) 2015 Stefan Agner
+ *
+ * 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.
+ */
+
+#include "armv7-m.dtsi"
+#include "vfxxx.dtsi"
+
+&mscm_ir {
+ interrupt-parent = <&nvic>;
+};
diff --git a/arch/arm/boot/dts/zx296702-ad1.dts b/arch/arm/boot/dts/zx296702-ad1.dts
new file mode 100644
index 000000000000..081f980cfbe6
--- /dev/null
+++ b/arch/arm/boot/dts/zx296702-ad1.dts
@@ -0,0 +1,48 @@
+
+/dts-v1/;
+
+#include "zx296702.dtsi"
+
+/ {
+ model = "ZTE ZX296702 AD1 Board";
+ compatible = "zte,zx296702-ad1", "zte,zx296702";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ };
+
+ memory {
+ reg = <0x50000000 0x20000000>;
+ };
+};
+
+&mmc0 {
+ num-slots = <1>;
+ supports-highspeed;
+ non-removable;
+ disable-wp;
+ status = "okay";
+
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ };
+};
+
+&mmc1 {
+ num-slots = <1>;
+ supports-highspeed;
+ non-removable;
+ disable-wp;
+ status = "okay";
+
+ slot@0 {
+ reg = <0>;
+ bus-width = <8>;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/zx296702.dtsi b/arch/arm/boot/dts/zx296702.dtsi
new file mode 100644
index 000000000000..d45c8fcd7ab4
--- /dev/null
+++ b/arch/arm/boot/dts/zx296702.dtsi
@@ -0,0 +1,139 @@
+
+#include "skeleton.dtsi"
+#include <dt-bindings/clock/zx296702-clock.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ enable-method = "zte,zx296702-smp";
+
+ cpu@0 {
+ compatible = "arm,cortex-a9";
+ device_type = "cpu";
+ next-level-cache = <&l2cc>;
+ reg = <0>;
+ };
+
+ cpu@1 {
+ compatible = "arm,cortex-a9";
+ device_type = "cpu";
+ next-level-cache = <&l2cc>;
+ reg = <1>;
+ };
+ };
+
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ interrupt-parent = <&intc>;
+ ranges;
+
+ matrix: bus-matrix@400000 {
+ compatible = "zte,zx-bus-matrix";
+ reg = <0x00400000 0x1000>;
+ };
+
+ intc: interrupt-controller@00801000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-controller;
+ reg = <0x00801000 0x1000>,
+ <0x00800100 0x100>;
+ };
+
+ global_timer: timer@008000200 {
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0x00800200 0x20>;
+ interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&intc>;
+ clocks = <&topclk ZX296702_A9_PERIPHCLK>;
+ };
+
+ l2cc: l2-cache-controller@0x00c00000 {
+ compatible = "arm,pl310-cache";
+ reg = <0x00c00000 0x1000>;
+ cache-unified;
+ cache-level = <2>;
+ arm,data-latency = <1 1 1>;
+ arm,tag-latency = <1 1 1>;
+ arm,double-linefill = <1>;
+ arm,double-linefill-incr = <0>;
+ };
+
+ pcu: pcu@0xa0008000 {
+ compatible = "zte,zx296702-pcu";
+ reg = <0xa0008000 0x1000>;
+ };
+
+ topclk: topclk@0x09800000 {
+ compatible = "zte,zx296702-topcrm-clk";
+ reg = <0x09800000 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ lsp1clk: lsp1clk@0x09400000 {
+ compatible = "zte,zx296702-lsp1crpm-clk";
+ reg = <0x09400000 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ lsp0clk: lsp0clk@0x0b000000 {
+ compatible = "zte,zx296702-lsp0crpm-clk";
+ reg = <0x0b000000 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ uart0: serial@0x09405000 {
+ compatible = "zte,zx296702-uart";
+ reg = <0x09405000 0x1000>;
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&lsp1clk ZX296702_UART0_WCLK>;
+ status = "disabled";
+ };
+
+ uart1: serial@0x09406000 {
+ compatible = "zte,zx296702-uart";
+ reg = <0x09406000 0x1000>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&lsp1clk ZX296702_UART1_WCLK>;
+ status = "disabled";
+ };
+
+ mmc0: mmc@0x09408000 {
+ compatible = "snps,dw-mshc";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x09408000 0x1000>;
+ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+ fifo-depth = <32>;
+ clocks = <&lsp1clk ZX296702_SDMMC0_PCLK>,
+ <&lsp1clk ZX296702_SDMMC0_WCLK>;
+ clock-names = "biu", "ciu";
+ status = "disabled";
+ };
+
+ mmc1: mmc@0x0b003000 {
+ compatible = "snps,dw-mshc";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0b003000 0x1000>;
+ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ fifo-depth = <32>;
+ clocks = <&lsp0clk ZX296702_SDMMC1_PCLK>,
+ <&lsp0clk ZX296702_SDMMC1_WCLK>;
+ clock-names = "biu", "ciu";
+ status = "disabled";
+ };
+
+ sysctrl: sysctrl@0xa0007000 {
+ compatible = "zte,sysctrl", "syscon";
+ reg = <0xa0007000 0x1000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi
index 9ea54b3dba09..06915080b875 100644
--- a/arch/arm/boot/dts/zynq-7000.dtsi
+++ b/arch/arm/boot/dts/zynq-7000.dtsi
@@ -193,7 +193,7 @@
};
gem0: ethernet@e000b000 {
- compatible = "cdns,zynq-gem";
+ compatible = "cdns,zynq-gem", "cdns,gem";
reg = <0xe000b000 0x1000>;
status = "disabled";
interrupts = <0 22 4>;
@@ -204,7 +204,7 @@
};
gem1: ethernet@e000c000 {
- compatible = "cdns,zynq-gem";
+ compatible = "cdns,zynq-gem", "cdns,gem";
reg = <0xe000c000 0x1000>;
status = "disabled";
interrupts = <0 45 4>;
diff --git a/arch/arm/boot/dts/zynq-parallella.dts b/arch/arm/boot/dts/zynq-parallella.dts
index 174571232ea5..9efd16cb2859 100644
--- a/arch/arm/boot/dts/zynq-parallella.dts
+++ b/arch/arm/boot/dts/zynq-parallella.dts
@@ -23,14 +23,19 @@
model = "Adapteva Parallella Board";
compatible = "adapteva,parallella", "xlnx,zynq-7000";
+ aliases {
+ ethernet0 = &gem0;
+ serial0 = &uart1;
+ };
+
memory {
device_type = "memory";
reg = <0x0 0x40000000>;
};
chosen {
- bootargs = "console=ttyPS0,115200 earlyprintk root=/dev/mmcblk0p2 rootfstype=ext4 rw rootwait";
- linux,stdout-path = "/amba/serial@e0001000";
+ bootargs = "earlyprintk root=/dev/mmcblk0p2 rootfstype=ext4 rw rootwait";
+ stdout-path = "serial0:115200n8";
};
};
diff --git a/arch/arm/boot/dts/zynq-zc702.dts b/arch/arm/boot/dts/zynq-zc702.dts
index 1fc1d3911e9b..fb59d34e8ee6 100644
--- a/arch/arm/boot/dts/zynq-zc702.dts
+++ b/arch/arm/boot/dts/zynq-zc702.dts
@@ -30,7 +30,8 @@
};
chosen {
- bootargs = "console=ttyPS0,115200 earlyprintk";
+ bootargs = "earlyprintk";
+ stdout-path = "serial0:115200n8";
};
leds {
diff --git a/arch/arm/boot/dts/zynq-zc706.dts b/arch/arm/boot/dts/zynq-zc706.dts
index 850518d9b8ac..abf5d238ae04 100644
--- a/arch/arm/boot/dts/zynq-zc706.dts
+++ b/arch/arm/boot/dts/zynq-zc706.dts
@@ -30,7 +30,8 @@
};
chosen {
- bootargs = "console=ttyPS0,115200 earlyprintk";
+ bootargs = "earlyprintk";
+ stdout-path = "serial0:115200n8";
};
usb_phy0: phy0 {
diff --git a/arch/arm/boot/dts/zynq-zed.dts b/arch/arm/boot/dts/zynq-zed.dts
index 5658bc8434de..b9f2522012e8 100644
--- a/arch/arm/boot/dts/zynq-zed.dts
+++ b/arch/arm/boot/dts/zynq-zed.dts
@@ -29,7 +29,8 @@
};
chosen {
- bootargs = "console=ttyPS0,115200 earlyprintk";
+ bootargs = "earlyprintk";
+ stdout-path = "serial0:115200n8";
};
usb_phy0: phy0 {
diff --git a/arch/arm/boot/dts/zynq-zybo.dts b/arch/arm/boot/dts/zynq-zybo.dts
index a9a12ce5023b..16c9cacd668d 100644
--- a/arch/arm/boot/dts/zynq-zybo.dts
+++ b/arch/arm/boot/dts/zynq-zybo.dts
@@ -18,13 +18,19 @@
model = "Zynq ZYBO Development Board";
compatible = "digilent,zynq-zybo", "xlnx,zynq-7000";
+ aliases {
+ ethernet0 = &gem0;
+ serial0 = &uart1;
+ };
+
memory {
device_type = "memory";
reg = <0x0 0x20000000>;
};
chosen {
- bootargs = "console=ttyPS0,115200 earlyprintk";
+ bootargs = "earlyprintk";
+ stdout-path = "serial0:115200n8";
};
};
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index 70b1eff477b3..6ee5959a813b 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_SHARP_LOCOMO) += locomo.o
obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
obj-$(CONFIG_SHARP_SCOOP) += scoop.o
obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o
-obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o
obj-$(CONFIG_MCPM) += mcpm_head.o mcpm_entry.o mcpm_platsmp.o vlock.o
CFLAGS_REMOVE_mcpm_entry.o = -pg
AFLAGS_mcpm_head.o := -march=armv7-a
diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c
index 5662a872689b..873dbfcc7dc9 100644
--- a/arch/arm/common/edma.c
+++ b/arch/arm/common/edma.c
@@ -1350,6 +1350,9 @@ void edma_stop(unsigned channel)
edma_shadow0_write_array(ctlr, SH_SECR, j, mask);
edma_write_array(ctlr, EDMA_EMCR, j, mask);
+ /* clear possibly pending completion interrupt */
+ edma_shadow0_write_array(ctlr, SH_ICR, j, mask);
+
pr_debug("EDMA: EER%d %08x\n", j,
edma_shadow0_read_array(ctlr, SH_EER, j));
diff --git a/arch/arm/common/mcpm_entry.c b/arch/arm/common/mcpm_entry.c
index 5f8a52ac7edf..a923524d1040 100644
--- a/arch/arm/common/mcpm_entry.c
+++ b/arch/arm/common/mcpm_entry.c
@@ -20,6 +20,126 @@
#include <asm/cputype.h>
#include <asm/suspend.h>
+/*
+ * The public API for this code is documented in arch/arm/include/asm/mcpm.h.
+ * For a comprehensive description of the main algorithm used here, please
+ * see Documentation/arm/cluster-pm-race-avoidance.txt.
+ */
+
+struct sync_struct mcpm_sync;
+
+/*
+ * __mcpm_cpu_going_down: Indicates that the cpu is being torn down.
+ * This must be called at the point of committing to teardown of a CPU.
+ * The CPU cache (SCTRL.C bit) is expected to still be active.
+ */
+static void __mcpm_cpu_going_down(unsigned int cpu, unsigned int cluster)
+{
+ mcpm_sync.clusters[cluster].cpus[cpu].cpu = CPU_GOING_DOWN;
+ sync_cache_w(&mcpm_sync.clusters[cluster].cpus[cpu].cpu);
+}
+
+/*
+ * __mcpm_cpu_down: Indicates that cpu teardown is complete and that the
+ * cluster can be torn down without disrupting this CPU.
+ * To avoid deadlocks, this must be called before a CPU is powered down.
+ * The CPU cache (SCTRL.C bit) is expected to be off.
+ * However L2 cache might or might not be active.
+ */
+static void __mcpm_cpu_down(unsigned int cpu, unsigned int cluster)
+{
+ dmb();
+ mcpm_sync.clusters[cluster].cpus[cpu].cpu = CPU_DOWN;
+ sync_cache_w(&mcpm_sync.clusters[cluster].cpus[cpu].cpu);
+ sev();
+}
+
+/*
+ * __mcpm_outbound_leave_critical: Leave the cluster teardown critical section.
+ * @state: the final state of the cluster:
+ * CLUSTER_UP: no destructive teardown was done and the cluster has been
+ * restored to the previous state (CPU cache still active); or
+ * CLUSTER_DOWN: the cluster has been torn-down, ready for power-off
+ * (CPU cache disabled, L2 cache either enabled or disabled).
+ */
+static void __mcpm_outbound_leave_critical(unsigned int cluster, int state)
+{
+ dmb();
+ mcpm_sync.clusters[cluster].cluster = state;
+ sync_cache_w(&mcpm_sync.clusters[cluster].cluster);
+ sev();
+}
+
+/*
+ * __mcpm_outbound_enter_critical: Enter the cluster teardown critical section.
+ * This function should be called by the last man, after local CPU teardown
+ * is complete. CPU cache expected to be active.
+ *
+ * Returns:
+ * false: the critical section was not entered because an inbound CPU was
+ * observed, or the cluster is already being set up;
+ * true: the critical section was entered: it is now safe to tear down the
+ * cluster.
+ */
+static bool __mcpm_outbound_enter_critical(unsigned int cpu, unsigned int cluster)
+{
+ unsigned int i;
+ struct mcpm_sync_struct *c = &mcpm_sync.clusters[cluster];
+
+ /* Warn inbound CPUs that the cluster is being torn down: */
+ c->cluster = CLUSTER_GOING_DOWN;
+ sync_cache_w(&c->cluster);
+
+ /* Back out if the inbound cluster is already in the critical region: */
+ sync_cache_r(&c->inbound);
+ if (c->inbound == INBOUND_COMING_UP)
+ goto abort;
+
+ /*
+ * Wait for all CPUs to get out of the GOING_DOWN state, so that local
+ * teardown is complete on each CPU before tearing down the cluster.
+ *
+ * If any CPU has been woken up again from the DOWN state, then we
+ * shouldn't be taking the cluster down at all: abort in that case.
+ */
+ sync_cache_r(&c->cpus);
+ for (i = 0; i < MAX_CPUS_PER_CLUSTER; i++) {
+ int cpustate;
+
+ if (i == cpu)
+ continue;
+
+ while (1) {
+ cpustate = c->cpus[i].cpu;
+ if (cpustate != CPU_GOING_DOWN)
+ break;
+
+ wfe();
+ sync_cache_r(&c->cpus[i].cpu);
+ }
+
+ switch (cpustate) {
+ case CPU_DOWN:
+ continue;
+
+ default:
+ goto abort;
+ }
+ }
+
+ return true;
+
+abort:
+ __mcpm_outbound_leave_critical(cluster, CLUSTER_UP);
+ return false;
+}
+
+static int __mcpm_cluster_state(unsigned int cluster)
+{
+ sync_cache_r(&mcpm_sync.clusters[cluster].cluster);
+ return mcpm_sync.clusters[cluster].cluster;
+}
+
extern unsigned long mcpm_entry_vectors[MAX_NR_CLUSTERS][MAX_CPUS_PER_CLUSTER];
void mcpm_set_entry_vector(unsigned cpu, unsigned cluster, void *ptr)
@@ -78,16 +198,11 @@ int mcpm_cpu_power_up(unsigned int cpu, unsigned int cluster)
bool cpu_is_down, cluster_is_down;
int ret = 0;
+ pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
if (!platform_ops)
return -EUNATCH; /* try not to shadow power_up errors */
might_sleep();
- /* backward compatibility callback */
- if (platform_ops->power_up)
- return platform_ops->power_up(cpu, cluster);
-
- pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
-
/*
* Since this is called with IRQs enabled, and no arch_spin_lock_irq
* variant exists, we need to disable IRQs manually here.
@@ -128,29 +243,17 @@ void mcpm_cpu_power_down(void)
bool cpu_going_down, last_man;
phys_reset_t phys_reset;
+ mpidr = read_cpuid_mpidr();
+ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+ pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
if (WARN_ON_ONCE(!platform_ops))
return;
BUG_ON(!irqs_disabled());
- /*
- * Do this before calling into the power_down method,
- * as it might not always be safe to do afterwards.
- */
setup_mm_for_reboot();
- /* backward compatibility callback */
- if (platform_ops->power_down) {
- platform_ops->power_down();
- goto not_dead;
- }
-
- mpidr = read_cpuid_mpidr();
- cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
- cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
- pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
-
__mcpm_cpu_going_down(cpu, cluster);
-
arch_spin_lock(&mcpm_lock);
BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
@@ -187,7 +290,6 @@ void mcpm_cpu_power_down(void)
if (cpu_going_down)
wfi();
-not_dead:
/*
* It is possible for a power_up request to happen concurrently
* with a power_down request for the same CPU. In this case the
@@ -219,22 +321,11 @@ int mcpm_wait_for_cpu_powerdown(unsigned int cpu, unsigned int cluster)
return ret;
}
-void mcpm_cpu_suspend(u64 expected_residency)
+void mcpm_cpu_suspend(void)
{
if (WARN_ON_ONCE(!platform_ops))
return;
- /* backward compatibility callback */
- if (platform_ops->suspend) {
- phys_reset_t phys_reset;
- BUG_ON(!irqs_disabled());
- setup_mm_for_reboot();
- platform_ops->suspend(expected_residency);
- phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
- phys_reset(virt_to_phys(mcpm_entry_point));
- BUG();
- }
-
/* Some platforms might have to enable special resume modes, etc. */
if (platform_ops->cpu_suspend_prepare) {
unsigned int mpidr = read_cpuid_mpidr();
@@ -256,12 +347,6 @@ int mcpm_cpu_powered_up(void)
if (!platform_ops)
return -EUNATCH;
- /* backward compatibility callback */
- if (platform_ops->powered_up) {
- platform_ops->powered_up();
- return 0;
- }
-
mpidr = read_cpuid_mpidr();
cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
@@ -334,120 +419,6 @@ int __init mcpm_loopback(void (*cache_disable)(void))
#endif
-struct sync_struct mcpm_sync;
-
-/*
- * __mcpm_cpu_going_down: Indicates that the cpu is being torn down.
- * This must be called at the point of committing to teardown of a CPU.
- * The CPU cache (SCTRL.C bit) is expected to still be active.
- */
-void __mcpm_cpu_going_down(unsigned int cpu, unsigned int cluster)
-{
- mcpm_sync.clusters[cluster].cpus[cpu].cpu = CPU_GOING_DOWN;
- sync_cache_w(&mcpm_sync.clusters[cluster].cpus[cpu].cpu);
-}
-
-/*
- * __mcpm_cpu_down: Indicates that cpu teardown is complete and that the
- * cluster can be torn down without disrupting this CPU.
- * To avoid deadlocks, this must be called before a CPU is powered down.
- * The CPU cache (SCTRL.C bit) is expected to be off.
- * However L2 cache might or might not be active.
- */
-void __mcpm_cpu_down(unsigned int cpu, unsigned int cluster)
-{
- dmb();
- mcpm_sync.clusters[cluster].cpus[cpu].cpu = CPU_DOWN;
- sync_cache_w(&mcpm_sync.clusters[cluster].cpus[cpu].cpu);
- sev();
-}
-
-/*
- * __mcpm_outbound_leave_critical: Leave the cluster teardown critical section.
- * @state: the final state of the cluster:
- * CLUSTER_UP: no destructive teardown was done and the cluster has been
- * restored to the previous state (CPU cache still active); or
- * CLUSTER_DOWN: the cluster has been torn-down, ready for power-off
- * (CPU cache disabled, L2 cache either enabled or disabled).
- */
-void __mcpm_outbound_leave_critical(unsigned int cluster, int state)
-{
- dmb();
- mcpm_sync.clusters[cluster].cluster = state;
- sync_cache_w(&mcpm_sync.clusters[cluster].cluster);
- sev();
-}
-
-/*
- * __mcpm_outbound_enter_critical: Enter the cluster teardown critical section.
- * This function should be called by the last man, after local CPU teardown
- * is complete. CPU cache expected to be active.
- *
- * Returns:
- * false: the critical section was not entered because an inbound CPU was
- * observed, or the cluster is already being set up;
- * true: the critical section was entered: it is now safe to tear down the
- * cluster.
- */
-bool __mcpm_outbound_enter_critical(unsigned int cpu, unsigned int cluster)
-{
- unsigned int i;
- struct mcpm_sync_struct *c = &mcpm_sync.clusters[cluster];
-
- /* Warn inbound CPUs that the cluster is being torn down: */
- c->cluster = CLUSTER_GOING_DOWN;
- sync_cache_w(&c->cluster);
-
- /* Back out if the inbound cluster is already in the critical region: */
- sync_cache_r(&c->inbound);
- if (c->inbound == INBOUND_COMING_UP)
- goto abort;
-
- /*
- * Wait for all CPUs to get out of the GOING_DOWN state, so that local
- * teardown is complete on each CPU before tearing down the cluster.
- *
- * If any CPU has been woken up again from the DOWN state, then we
- * shouldn't be taking the cluster down at all: abort in that case.
- */
- sync_cache_r(&c->cpus);
- for (i = 0; i < MAX_CPUS_PER_CLUSTER; i++) {
- int cpustate;
-
- if (i == cpu)
- continue;
-
- while (1) {
- cpustate = c->cpus[i].cpu;
- if (cpustate != CPU_GOING_DOWN)
- break;
-
- wfe();
- sync_cache_r(&c->cpus[i].cpu);
- }
-
- switch (cpustate) {
- case CPU_DOWN:
- continue;
-
- default:
- goto abort;
- }
- }
-
- return true;
-
-abort:
- __mcpm_outbound_leave_critical(cluster, CLUSTER_UP);
- return false;
-}
-
-int __mcpm_cluster_state(unsigned int cluster)
-{
- sync_cache_r(&mcpm_sync.clusters[cluster].cluster);
- return mcpm_sync.clusters[cluster].cluster;
-}
-
extern unsigned long mcpm_power_up_setup_phys;
int __init mcpm_sync_init(
diff --git a/arch/arm/common/mcpm_head.S b/arch/arm/common/mcpm_head.S
index e02db4b81a66..08b3bb9bc6a2 100644
--- a/arch/arm/common/mcpm_head.S
+++ b/arch/arm/common/mcpm_head.S
@@ -49,7 +49,7 @@
ENTRY(mcpm_entry_point)
ARM_BE8(setend be)
- THUMB( adr r12, BSYM(1f) )
+ THUMB( badr r12, 1f )
THUMB( bx r12 )
THUMB( .thumb )
1:
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 5cc779c8e9c6..93ee70dbbdd3 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -501,8 +501,8 @@ static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base)
* Register SA1111 interrupt
*/
irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING);
- irq_set_handler_data(sachip->irq, sachip);
- irq_set_chained_handler(sachip->irq, sa1111_irq_handler);
+ irq_set_chained_handler_and_data(sachip->irq, sa1111_irq_handler,
+ sachip);
dev_info(sachip->dev, "Providing IRQ%u-%u\n",
sachip->irq_base, sachip->irq_base + SA1111_IRQ_NR - 1);
@@ -836,8 +836,7 @@ static void __sa1111_remove(struct sa1111 *sachip)
clk_unprepare(sachip->clk);
if (sachip->irq != NO_IRQ) {
- irq_set_chained_handler(sachip->irq, NULL);
- irq_set_handler_data(sachip->irq, NULL);
+ irq_set_chained_handler_and_data(sachip->irq, NULL, NULL);
irq_free_descs(sachip->irq_base, SA1111_IRQ_NR);
release_mem_region(sachip->phys + SA1111_INTC, 512);
diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig
index bcef49a21801..94b5dcabdecc 100644
--- a/arch/arm/configs/at91_dt_defconfig
+++ b/arch/arm/configs/at91_dt_defconfig
@@ -131,6 +131,8 @@ CONFIG_POWER_RESET=y
CONFIG_WATCHDOG=y
CONFIG_AT91SAM9X_WATCHDOG=y
CONFIG_SSB=m
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_FB=y
CONFIG_FB_ATMEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
diff --git a/arch/arm/configs/efm32_defconfig b/arch/arm/configs/efm32_defconfig
index c4c17e3a8e1a..c0dac0f0f804 100644
--- a/arch/arm/configs/efm32_defconfig
+++ b/arch/arm/configs/efm32_defconfig
@@ -16,6 +16,7 @@ CONFIG_EMBEDDED=y
# CONFIG_IOSCHED_DEADLINE is not set
# CONFIG_IOSCHED_CFQ is not set
# CONFIG_MMU is not set
+CONFIG_ARM_SINGLE_ARMV7M=y
CONFIG_ARCH_EFM32=y
CONFIG_SET_MEM_PARAM=y
CONFIG_DRAM_BASE=0x88000000
@@ -85,7 +86,6 @@ CONFIG_GPIO_SYSFS=y
# CONFIG_USB_SUPPORT is not set
CONFIG_MMC=y
CONFIG_MMC_SPI=y
-# CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXT2_FS=y
# CONFIG_FILE_LOCKING is not set
# CONFIG_DNOTIFY is not set
diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig
index d034c96c039b..9504e7790288 100644
--- a/arch/arm/configs/exynos_defconfig
+++ b/arch/arm/configs/exynos_defconfig
@@ -26,11 +26,11 @@ CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc mem=256M"
+CONFIG_CPU_FREQ=y
CONFIG_CPU_IDLE=y
CONFIG_ARM_EXYNOS_CPUIDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
-CONFIG_PM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -40,15 +40,11 @@ CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
-CONFIG_WIRELESS=y
CONFIG_CFG80211=y
-CONFIG_MWIFIEX=y
-CONFIG_MWIFIEX_SDIO=y
CONFIG_RFKILL_REGULATOR=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_PROC_DEVICETREE=y
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=64
CONFIG_BLK_DEV_LOOP=y
@@ -66,7 +62,8 @@ CONFIG_SMSC911X=y
CONFIG_USB_USBNET=y
CONFIG_USB_NET_SMSC75XX=y
CONFIG_USB_NET_SMSC95XX=y
-CONFIG_USB_GADGET=y
+CONFIG_MWIFIEX=y
+CONFIG_MWIFIEX_SDIO=y
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_CROS_EC=y
@@ -81,16 +78,13 @@ CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_HW_RANDOM=y
CONFIG_TCG_TPM=y
CONFIG_TCG_TIS_I2C_INFINEON=y
-CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MUX=y
CONFIG_I2C_ARB_GPIO_CHALLENGE=y
-CONFIG_I2C_EXYNOS5=y
CONFIG_I2C_GPIO=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_SPI=y
CONFIG_SPI_S3C64XX=y
-CONFIG_I2C_S3C2410=y
CONFIG_DEBUG_GPIO=y
CONFIG_POWER_SUPPLY=y
CONFIG_BATTERY_SBS=y
@@ -99,13 +93,13 @@ CONFIG_BATTERY_MAX17042=y
CONFIG_CHARGER_MAX14577=y
CONFIG_CHARGER_MAX77693=y
CONFIG_CHARGER_TPS65090=y
-CONFIG_HWMON=y
CONFIG_SENSORS_LM90=y
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_THERMAL=y
+CONFIG_SENSORS_PWM_FAN=y
+CONFIG_SENSORS_INA2XX=y
CONFIG_THERMAL=y
-CONFIG_EXYNOS_THERMAL=y
+CONFIG_CPU_THERMAL=y
CONFIG_THERMAL_EMULATION=y
+CONFIG_EXYNOS_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_S3C2410_WATCHDOG=y
CONFIG_MFD_CROS_EC=y
@@ -123,36 +117,27 @@ CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_MAX14577=y
CONFIG_REGULATOR_MAX8997=y
CONFIG_REGULATOR_MAX77686=y
-CONFIG_REGULATOR_MAX77802=y
CONFIG_REGULATOR_MAX77693=y
+CONFIG_REGULATOR_MAX77802=y
CONFIG_REGULATOR_S2MPA01=y
CONFIG_REGULATOR_S2MPS11=y
CONFIG_REGULATOR_S5M8767=y
CONFIG_REGULATOR_TPS65090=y
CONFIG_DRM=y
-CONFIG_DRM_EXYNOS_HDMI=y
-CONFIG_DRM_BRIDGE=y
CONFIG_DRM_PTN3460=y
CONFIG_DRM_PS8622=y
CONFIG_DRM_EXYNOS=y
CONFIG_DRM_EXYNOS_FIMD=y
-CONFIG_DRM_EXYNOS_DP=y
-CONFIG_DRM_PANEL=y
+CONFIG_DRM_EXYNOS_DSI=y
+CONFIG_DRM_EXYNOS_HDMI=y
CONFIG_DRM_PANEL_SIMPLE=y
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
+CONFIG_DRM_PANEL_S6E8AA0=y
CONFIG_FB_SIMPLE=y
CONFIG_EXYNOS_VIDEO=y
CONFIG_EXYNOS_MIPI_DSI=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_LCD_PLATFORM=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_GENERIC=y
CONFIG_BACKLIGHT_PWM=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_7x14=y
CONFIG_LOGO=y
CONFIG_SOUND=y
CONFIG_SND=y
@@ -169,6 +154,7 @@ CONFIG_USB_OHCI_EXYNOS=y
CONFIG_USB_STORAGE=y
CONFIG_USB_DWC3=y
CONFIG_USB_HSIC_USB3503=y
+CONFIG_USB_GADGET=y
CONFIG_MMC=y
CONFIG_MMC_BLOCK_MINORS=16
CONFIG_MMC_SDHCI=y
@@ -197,11 +183,6 @@ CONFIG_EXYNOS_ADC=y
CONFIG_PWM=y
CONFIG_PWM_SAMSUNG=y
CONFIG_PHY_EXYNOS5250_SATA=y
-CONFIG_PHY_SAMSUNG_USB2=y
-CONFIG_PHY_EXYNOS4210_USB2=y
-CONFIG_PHY_EXYNOS4X12_USB2=y
-CONFIG_PHY_EXYNOS5250_USB2=y
-CONFIG_PHY_EXYNOS5_USBDRD=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS=y
@@ -217,15 +198,16 @@ CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_FS=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
-CONFIG_DETECT_HUNG_TASK=y
+CONFIG_LOCKUP_DETECTOR=y
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
-CONFIG_LOCKUP_DETECTOR=y
-CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_USER=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRC_CCITT=y
+CONFIG_FONTS=y
+CONFIG_FONT_7x14=y
diff --git a/arch/arm/configs/hisi_defconfig b/arch/arm/configs/hisi_defconfig
index c34da5878b6c..5997dbc69822 100644
--- a/arch/arm/configs/hisi_defconfig
+++ b/arch/arm/configs/hisi_defconfig
@@ -33,6 +33,7 @@ CONFIG_ATA=y
CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_NETDEVICES=y
CONFIG_HIX5HD2_GMAC=y
+CONFIG_HIP04_ETH=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y
CONFIG_SERIAL_8250_CONSOLE=y
@@ -51,6 +52,7 @@ CONFIG_GPIO_SYSFS=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_GENERIC_PLATFORM=y
CONFIG_REGULATOR_GPIO=y
+CONFIG_GPIO_DWAPB=y
CONFIG_MFD_SYSCON=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_DRM=y
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index fdeb1c83dcb5..b47863d49ac6 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -38,7 +38,9 @@ CONFIG_SOC_IMX53=y
CONFIG_SOC_IMX6Q=y
CONFIG_SOC_IMX6SL=y
CONFIG_SOC_IMX6SX=y
+CONFIG_SOC_IMX7D=y
CONFIG_SOC_VF610=y
+CONFIG_SOC_LS1021A=y
CONFIG_PCI=y
CONFIG_PCI_IMX6=y
CONFIG_SMP=y
@@ -73,6 +75,7 @@ CONFIG_CAN=y
CONFIG_CAN_FLEXCAN=y
CONFIG_BT=y
CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_LL=y
CONFIG_BT_HCIUART_3WIRE=y
CONFIG_CFG80211=y
CONFIG_MAC80211=y
@@ -139,6 +142,10 @@ CONFIG_USB_RTL8152=m
CONFIG_USB_USBNET=m
CONFIG_USB_NET_CDC_EEM=m
CONFIG_BRCMFMAC=m
+CONFIG_WL_TI=y
+CONFIG_WL12XX=m
+CONFIG_WLCORE_SDIO=m
+# CONFIG_WILINK_PLATFORM_DATA is not set
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=m
@@ -151,6 +158,7 @@ CONFIG_TOUCHSCREEN_EGALAX=y
CONFIG_TOUCHSCREEN_MC13783=y
CONFIG_TOUCHSCREEN_TSC2007=y
CONFIG_TOUCHSCREEN_STMPE=y
+CONFIG_TOUCHSCREEN_SX8654=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_MMA8450=y
CONFIG_SERIO_SERPORT=m
@@ -283,6 +291,7 @@ CONFIG_RTC_CLASS=y
CONFIG_RTC_INTF_DEV_UIE_EMUL=y
CONFIG_RTC_DRV_DS1307=y
CONFIG_RTC_DRV_ISL1208=y
+CONFIG_RTC_DRV_PCF8523=y
CONFIG_RTC_DRV_PCF8563=y
CONFIG_RTC_DRV_MC13XXX=y
CONFIG_RTC_DRV_MXC=y
diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig
index f8a1c8f2c7c4..95ce1284bd42 100644
--- a/arch/arm/configs/keystone_defconfig
+++ b/arch/arm/configs/keystone_defconfig
@@ -123,6 +123,9 @@ CONFIG_EEPROM_AT24=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_NETDEVICES=y
+CONFIG_TI_KEYSTONE_NETCP=y
+CONFIG_TI_KEYSTONE_NETCP_ETHSS=y
+CONFIG_PHYLIB=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
@@ -152,6 +155,9 @@ CONFIG_USB_DWC3_VERBOSE=y
CONFIG_KEYSTONE_USB_PHY=y
CONFIG_DMADEVICES=y
CONFIG_TI_EDMA=y
+CONFIG_SOC_TI=y
+CONFIG_KEYSTONE_NAVIGATOR_QMSS=y
+CONFIG_KEYSTONE_NAVIGATOR_DMA=y
CONFIG_MEMORY=y
CONFIG_TI_AEMIF=y
CONFIG_EXT4_FS=y
diff --git a/arch/arm/configs/lpc18xx_defconfig b/arch/arm/configs/lpc18xx_defconfig
new file mode 100644
index 000000000000..1c47f86c3970
--- /dev/null
+++ b/arch/arm/configs/lpc18xx_defconfig
@@ -0,0 +1,151 @@
+CONFIG_CROSS_COMPILE="arm-linux-gnueabihf-"
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_UID16 is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
+CONFIG_ARM_SINGLE_ARMV7M=y
+CONFIG_ARCH_LPC18XX=y
+CONFIG_SET_MEM_PARAM=y
+CONFIG_DRAM_BASE=0x28000000
+CONFIG_DRAM_SIZE=0x02000000
+CONFIG_FLASH_MEM_BASE=0x1b000000
+CONFIG_FLASH_SIZE=0x00080000
+CONFIG_PREEMPT=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_COREDUMP is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_SRAM=y
+CONFIG_EEPROM_AT24=y
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_HISILICON is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_ROCKER is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+CONFIG_STMMAC_ETH=y
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_USB_NET_DRIVERS is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_GPIO_POLLED=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_SPI=y
+CONFIG_SPI_PL022=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_74XX_MMIO=y
+CONFIG_SENSORS_LM75=y
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_MFD_SYSCON=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_FB=y
+CONFIG_FB_ARMCLCD=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_MMC=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_IDMAC=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_PCA9532=y
+CONFIG_LEDS_PCA9532_GPIO=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_CLASS=y
+CONFIG_DMADEVICES=y
+CONFIG_AMBA_PL08X=y
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_RCU_CPU_STALL_INFO is not set
+# CONFIG_FTRACE is not set
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index fbbb1915c6a9..fd6a6d23bc20 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -20,6 +20,9 @@ CONFIG_MACH_ARMADA_38X=y
CONFIG_MACH_ARMADA_39X=y
CONFIG_MACH_ARMADA_XP=y
CONFIG_MACH_DOVE=y
+CONFIG_ARCH_AT91=y
+CONFIG_SOC_SAMA5D3=y
+CONFIG_SOC_SAMA5D4=y
CONFIG_ARCH_BCM=y
CONFIG_ARCH_BCM_CYGNUS=y
CONFIG_ARCH_BCM_21664=y
@@ -30,6 +33,7 @@ CONFIG_ARCH_BERLIN=y
CONFIG_MACH_BERLIN_BG2=y
CONFIG_MACH_BERLIN_BG2CD=y
CONFIG_MACH_BERLIN_BG2Q=y
+CONFIG_ARCH_DIGICOLOR=y
CONFIG_ARCH_HIGHBANK=y
CONFIG_ARCH_HISI=y
CONFIG_ARCH_HI3xxx=y
@@ -72,6 +76,7 @@ CONFIG_ARCH_EMEV2=y
CONFIG_ARCH_R7S72100=y
CONFIG_ARCH_R8A73A4=y
CONFIG_ARCH_R8A7740=y
+CONFIG_ARCH_R8A7778=y
CONFIG_ARCH_R8A7779=y
CONFIG_ARCH_R8A7790=y
CONFIG_ARCH_R8A7791=y
@@ -86,6 +91,7 @@ CONFIG_ARCH_TEGRA_3x_SOC=y
CONFIG_ARCH_TEGRA_114_SOC=y
CONFIG_ARCH_TEGRA_124_SOC=y
CONFIG_TEGRA_EMC_SCALING_ENABLE=y
+CONFIG_ARCH_UNIPHIER=y
CONFIG_ARCH_U8500=y
CONFIG_MACH_HREFV60=y
CONFIG_MACH_SNOWBALL=y
@@ -115,8 +121,11 @@ CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_STAT_DETAILS=y
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_IDLE=y
+CONFIG_ARM_CPUIDLE=y
CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
CONFIG_ARM_ZYNQ_CPUIDLE=y
+CONFIG_ARM_EXYNOS_CPUIDLE=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -137,6 +146,7 @@ CONFIG_CAN=y
CONFIG_CAN_RAW=y
CONFIG_CAN_BCM=y
CONFIG_CAN_DEV=y
+CONFIG_CAN_AT91=m
CONFIG_CAN_XILINXCAN=y
CONFIG_CAN_MCP251X=y
CONFIG_BT=m
@@ -158,13 +168,16 @@ CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ATMEL=y
CONFIG_MTD_NAND_DAVINCI=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_UBI=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_AD525X_DPOT=y
CONFIG_AD525X_DPOT_I2C=y
+CONFIG_ATMEL_TCLIB=y
CONFIG_ICS932S401=y
+CONFIG_ATMEL_SSC=m
CONFIG_APDS9802ALS=y
CONFIG_ISL29003=y
CONFIG_EEPROM_AT24=y
@@ -213,12 +226,14 @@ CONFIG_MWIFIEX=m
CONFIG_MWIFIEX_SDIO=m
CONFIG_INPUT_JOYDEV=y
CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_QT1070=m
CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_TEGRA=y
CONFIG_KEYBOARD_SPEAR=y
CONFIG_KEYBOARD_ST_KEYSCAN=y
CONFIG_KEYBOARD_CROS_EC=y
CONFIG_MOUSE_PS2_ELANTECH=y
+CONFIG_MOUSE_CYAPA=m
CONFIG_MOUSE_ELAN_I2C=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
@@ -237,6 +252,9 @@ CONFIG_SERIAL_8250_EM=y
CONFIG_SERIAL_8250_MT6577=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_TTYAT=y
CONFIG_SERIAL_MESON=y
CONFIG_SERIAL_MESON_CONSOLE=y
CONFIG_SERIAL_SAMSUNG=y
@@ -260,15 +278,20 @@ CONFIG_SERIAL_XILINX_PS_UART=y
CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
CONFIG_SERIAL_FSL_LPUART=y
CONFIG_SERIAL_FSL_LPUART_CONSOLE=y
+CONFIG_SERIAL_CONEXANT_DIGICOLOR=y
+CONFIG_SERIAL_CONEXANT_DIGICOLOR_CONSOLE=y
CONFIG_SERIAL_ST_ASC=y
CONFIG_SERIAL_ST_ASC_CONSOLE=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_DAVINCI=y
CONFIG_I2C_MUX=y
+CONFIG_I2C_ARB_GPIO_CHALLENGE=m
CONFIG_I2C_MUX_PCA954x=y
CONFIG_I2C_MUX_PINCTRL=y
+CONFIG_I2C_AT91=m
CONFIG_I2C_CADENCE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_I2C_DIGICOLOR=m
CONFIG_I2C_GPIO=m
CONFIG_I2C_EXYNOS5=y
CONFIG_I2C_MV64XXX=y
@@ -280,13 +303,16 @@ CONFIG_I2C_ST=y
CONFIG_I2C_TEGRA=y
CONFIG_I2C_XILINX=y
CONFIG_I2C_RCAR=y
+CONFIG_I2C_CROS_EC_TUNNEL=m
CONFIG_SPI=y
+CONFIG_SPI_ATMEL=m
CONFIG_SPI_CADENCE=y
CONFIG_SPI_DAVINCI=y
CONFIG_SPI_OMAP24XX=y
CONFIG_SPI_ORION=y
CONFIG_SPI_PL022=y
CONFIG_SPI_RSPI=y
+CONFIG_SPI_S3C64XX=m
CONFIG_SPI_SH_MSIOF=m
CONFIG_SPI_SH_HSPI=y
CONFIG_SPI_SIRF=y
@@ -317,6 +343,10 @@ CONFIG_GPIO_SYSCON=y
CONFIG_GPIO_TPS6586X=y
CONFIG_GPIO_TPS65910=y
CONFIG_BATTERY_SBS=y
+CONFIG_BATTERY_MAX17040=m
+CONFIG_BATTERY_MAX17042=m
+CONFIG_CHARGER_MAX14577=m
+CONFIG_CHARGER_MAX77693=m
CONFIG_CHARGER_TPS65090=y
CONFIG_POWER_RESET_AS3722=y
CONFIG_POWER_RESET_GPIO=y
@@ -330,13 +360,15 @@ CONFIG_THERMAL=y
CONFIG_CPU_THERMAL=y
CONFIG_RCAR_THERMAL=y
CONFIG_ARMADA_THERMAL=y
-CONFIG_DAVINCI_WATCHDOG
+CONFIG_DAVINCI_WATCHDOG=m
+CONFIG_EXYNOS_THERMAL=m
CONFIG_ST_THERMAL_SYSCFG=y
CONFIG_ST_THERMAL_MEMMAP=y
CONFIG_WATCHDOG=y
CONFIG_XILINX_WATCHDOG=y
CONFIG_ARM_SP805_WATCHDOG=y
CONFIG_ORION_WATCHDOG=y
+CONFIG_ST_LPC_WATCHDOG=y
CONFIG_SUNXI_WATCHDOG=y
CONFIG_MESON_WATCHDOG=y
CONFIG_MFD_AS3711=y
@@ -344,8 +376,11 @@ CONFIG_MFD_AS3722=y
CONFIG_MFD_BCM590XX=y
CONFIG_MFD_AXP20X=y
CONFIG_MFD_CROS_EC=y
+CONFIG_MFD_CROS_EC_I2C=m
CONFIG_MFD_CROS_EC_SPI=y
+CONFIG_MFD_MAX14577=y
CONFIG_MFD_MAX77686=y
+CONFIG_MFD_MAX77693=y
CONFIG_MFD_MAX8907=y
CONFIG_MFD_SEC_CORE=y
CONFIG_MFD_STMPE=y
@@ -362,9 +397,11 @@ CONFIG_REGULATOR_DA9210=y
CONFIG_REGULATOR_GPIO=y
CONFIG_MFD_SYSCON=y
CONFIG_POWER_RESET_SYSCON=y
+CONFIG_REGULATOR_MAX14577=m
CONFIG_REGULATOR_MAX8907=y
CONFIG_REGULATOR_MAX8973=y
CONFIG_REGULATOR_MAX77686=y
+CONFIG_REGULATOR_MAX77693=m
CONFIG_REGULATOR_PALMAS=y
CONFIG_REGULATOR_S2MPS11=y
CONFIG_REGULATOR_S5M8767=y
@@ -375,7 +412,7 @@ CONFIG_REGULATOR_TPS6586X=y
CONFIG_REGULATOR_TPS65910=y
CONFIG_REGULATOR_TWL4030=y
CONFIG_REGULATOR_VEXPRESS=y
-CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_SUPPORT=m
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
@@ -390,9 +427,17 @@ CONFIG_V4L_MEM2MEM_DRIVERS=y
CONFIG_VIDEO_RENESAS_VSP1=m
# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
CONFIG_VIDEO_ADV7180=m
+CONFIG_VIDEO_ML86V7667=m
CONFIG_DRM=y
+CONFIG_DRM_PTN3460=m
+CONFIG_DRM_PS8622=m
+CONFIG_DRM_EXYNOS=m
+CONFIG_DRM_EXYNOS_DSI=y
+CONFIG_DRM_EXYNOS_FIMD=y
+CONFIG_DRM_EXYNOS_HDMI=y
CONFIG_DRM_RCAR_DU=m
CONFIG_DRM_TEGRA=y
+CONFIG_DRM_PANEL_S6E8AA0=m
CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_FB_ARMCLCD=y
CONFIG_FB_WM8505=y
@@ -401,24 +446,27 @@ CONFIG_FB_SIMPLE=y
CONFIG_FB_SH_MOBILE_MERAM=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=m
CONFIG_BACKLIGHT_PWM=y
CONFIG_BACKLIGHT_AS3711=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
-CONFIG_SOUND=y
-CONFIG_SND=y
+CONFIG_SOUND=m
+CONFIG_SND=m
CONFIG_SND_DYNAMIC_MINORS=y
CONFIG_SND_USB_AUDIO=y
-CONFIG_SND_SOC=y
+CONFIG_SND_SOC=m
+CONFIG_SND_ATMEL_SOC=m
+CONFIG_SND_ATMEL_SOC_WM8904=m
CONFIG_SND_SOC_SH4_FSI=m
CONFIG_SND_SOC_RCAR=m
-CONFIG_SND_SOC_TEGRA=y
-CONFIG_SND_SOC_TEGRA_RT5640=y
-CONFIG_SND_SOC_TEGRA_WM8753=y
-CONFIG_SND_SOC_TEGRA_WM8903=y
-CONFIG_SND_SOC_TEGRA_TRIMSLICE=y
-CONFIG_SND_SOC_TEGRA_ALC5632=y
-CONFIG_SND_SOC_TEGRA_MAX98090=y
+CONFIG_SND_SOC_TEGRA=m
+CONFIG_SND_SOC_TEGRA_RT5640=m
+CONFIG_SND_SOC_TEGRA_WM8753=m
+CONFIG_SND_SOC_TEGRA_WM8903=m
+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_WM8978=m
CONFIG_USB=y
@@ -433,6 +481,7 @@ CONFIG_USB_ISP1760=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_STI=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_EXYNOS=m
CONFIG_USB_R8A66597_HCD=m
CONFIG_USB_RENESAS_USBHS=m
CONFIG_USB_STORAGE=y
@@ -448,7 +497,6 @@ CONFIG_USB_GPIO_VBUS=y
CONFIG_USB_ISP1301=y
CONFIG_USB_MXS_PHY=y
CONFIG_USB_RCAR_PHY=m
-CONFIG_USB_RCAR_GEN2_PHY=m
CONFIG_USB_GADGET=y
CONFIG_USB_RENESAS_USBHS_UDC=m
CONFIG_MMC=y
@@ -468,6 +516,7 @@ CONFIG_MMC_SDHCI_BCM_KONA=y
CONFIG_MMC_SDHCI_ST=y
CONFIG_MMC_OMAP=y
CONFIG_MMC_OMAP_HS=y
+CONFIG_MMC_ATMELMCI=y
CONFIG_MMC_MVSDIO=y
CONFIG_MMC_SDHI=y
CONFIG_MMC_DW=y
@@ -500,14 +549,22 @@ CONFIG_RTC_DRV_AS3722=y
CONFIG_RTC_DRV_DS1307=y
CONFIG_RTC_DRV_MAX8907=y
CONFIG_RTC_DRV_MAX77686=y
+CONFIG_RTC_DRV_MAX77802=m
CONFIG_RTC_DRV_RS5C372=m
CONFIG_RTC_DRV_PALMAS=y
+CONFIG_RTC_DRV_ST_LPC=y
CONFIG_RTC_DRV_TWL4030=y
CONFIG_RTC_DRV_TPS6586X=y
CONFIG_RTC_DRV_TPS65910=y
CONFIG_RTC_DRV_S35390A=m
+CONFIG_RTC_DRV_RX8581=m
CONFIG_RTC_DRV_EM3027=y
+CONFIG_RTC_DRV_DIGICOLOR=m
+CONFIG_RTC_DRV_S5M=m
+CONFIG_RTC_DRV_S3C=m
CONFIG_RTC_DRV_PL031=y
+CONFIG_RTC_DRV_AT91RM9200=m
+CONFIG_RTC_DRV_AT91SAM9=m
CONFIG_RTC_DRV_VT8500=y
CONFIG_RTC_DRV_SUN6I=y
CONFIG_RTC_DRV_SUNXI=y
@@ -515,6 +572,8 @@ CONFIG_RTC_DRV_MV=y
CONFIG_RTC_DRV_TEGRA=y
CONFIG_DMADEVICES=y
CONFIG_DW_DMAC=y
+CONFIG_AT_HDMAC=y
+CONFIG_AT_XDMAC=y
CONFIG_MV_XOR=y
CONFIG_TEGRA20_APB_DMA=y
CONFIG_SH_DMAE=y
@@ -537,8 +596,13 @@ CONFIG_SERIO_NVEC_PS2=y
CONFIG_NVEC_POWER=y
CONFIG_NVEC_PAZ00=y
CONFIG_QCOM_GSBI=y
+CONFIG_QCOM_PM=y
CONFIG_COMMON_CLK_QCOM=y
+CONFIG_CHROME_PLATFORMS=y
+CONFIG_CROS_EC_CHARDEV=m
CONFIG_COMMON_CLK_MAX77686=y
+CONFIG_COMMON_CLK_MAX77802=m
+CONFIG_COMMON_CLK_S2MPS11=m
CONFIG_APQ_MMCC_8084=y
CONFIG_MSM_GCC_8660=y
CONFIG_MSM_MMCC_8960=y
@@ -550,10 +614,14 @@ CONFIG_ARM_TEGRA_DEVFREQ=m
CONFIG_MEMORY=y
CONFIG_TI_AEMIF=y
CONFIG_IIO=y
+CONFIG_AT91_ADC=m
CONFIG_XILINX_XADC=y
CONFIG_AK8975=y
CONFIG_PWM=y
+CONFIG_PWM_ATMEL=m
+CONFIG_PWM_ATMEL_TCB=m
CONFIG_PWM_RENESAS_TPU=y
+CONFIG_PWM_SAMSUNG=m
CONFIG_PWM_TEGRA=y
CONFIG_PWM_VT8500=y
CONFIG_PHY_HIX5HD2_SATA=y
@@ -561,10 +629,12 @@ CONFIG_OMAP_USB2=y
CONFIG_TI_PIPE3=y
CONFIG_PHY_MIPHY28LP=y
CONFIG_PHY_MIPHY365X=y
+CONFIG_PHY_RCAR_GEN2=m
CONFIG_PHY_STIH41X_USB=y
CONFIG_PHY_STIH407_USB=y
CONFIG_PHY_SUN4I_USB=y
CONFIG_PHY_SUN9I_USB=y
+CONFIG_PHY_SAMSUNG_USB2=m
CONFIG_EXT4_FS=y
CONFIG_AUTOFS4_FS=y
CONFIG_MSDOS_FS=y
@@ -590,3 +660,17 @@ CONFIG_LOCKUP_DETECTOR=y
CONFIG_CRYPTO_DEV_TEGRA_AES=y
CONFIG_CPUFREQ_DT=y
CONFIG_KEYSTONE_IRQ=y
+CONFIG_ARM_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM=m
+CONFIG_CRYPTO_SHA1_ARM_NEON=m
+CONFIG_CRYPTO_SHA1_ARM_CE=m
+CONFIG_CRYPTO_SHA2_ARM_CE=m
+CONFIG_CRYPTO_SHA256_ARM=m
+CONFIG_CRYPTO_SHA512_ARM=m
+CONFIG_CRYPTO_AES_ARM=m
+CONFIG_CRYPTO_AES_ARM_BS=m
+CONFIG_CRYPTO_AES_ARM_CE=m
+CONFIG_CRYPTO_GHASH_ARM_CE=m
+CONFIG_CRYPTO_DEV_ATMEL_AES=m
+CONFIG_CRYPTO_DEV_ATMEL_TDES=m
+CONFIG_CRYPTO_DEV_ATMEL_SHA=m
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 3743ca221d40..ac521e764d10 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -152,6 +152,7 @@ CONFIG_NETDEVICES=y
# CONFIG_NET_CADENCE is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_CIRRUS is not set
+CONFIG_DM9000=y
# CONFIG_NET_VENDOR_FARADAY is not set
# CONFIG_NET_VENDOR_HISILICON is not set
# CONFIG_NET_VENDOR_INTEL is not set
@@ -204,6 +205,7 @@ CONFIG_KEYBOARD_TWL4030=m
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ADS7846=m
CONFIG_TOUCHSCREEN_EDT_FT5X06=m
+CONFIG_TOUCHSCREEN_PIXCIR=m
CONFIG_TOUCHSCREEN_TSC2005=m
CONFIG_TOUCHSCREEN_TSC2007=m
CONFIG_INPUT_MISC=y
@@ -401,6 +403,7 @@ CONFIG_PWM_TIECAP=m
CONFIG_PWM_TIEHRPWM=m
CONFIG_PWM_TWL=m
CONFIG_PWM_TWL_LED=m
+CONFIG_PHY_DM816X_USB=m
CONFIG_OMAP_USB2=m
CONFIG_TI_PIPE3=y
CONFIG_TWL4030_USB=m
diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig
index d2f2babfd47a..e6a6f282e3de 100644
--- a/arch/arm/configs/qcom_defconfig
+++ b/arch/arm/configs/qcom_defconfig
@@ -30,6 +30,7 @@ CONFIG_CLEANCACHE=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_CPU_IDLE=y
+CONFIG_ARM_CPUIDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
@@ -143,6 +144,7 @@ CONFIG_MSM_MMCC_8960=y
CONFIG_MSM_MMCC_8974=y
CONFIG_MSM_IOMMU=y
CONFIG_QCOM_GSBI=y
+CONFIG_QCOM_PM=y
CONFIG_PHY_QCOM_APQ8064_SATA=y
CONFIG_PHY_QCOM_IPQ806X_SATA=y
CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig
index 510c747c65b4..31eb951880ae 100644
--- a/arch/arm/configs/sama5_defconfig
+++ b/arch/arm/configs/sama5_defconfig
@@ -136,6 +136,7 @@ CONFIG_POWER_RESET=y
# CONFIG_HWMON is not set
CONFIG_SSB=m
CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_ACT8865=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig
index b58618e2d13c..9961fbd633f8 100644
--- a/arch/arm/configs/shmobile_defconfig
+++ b/arch/arm/configs/shmobile_defconfig
@@ -121,7 +121,6 @@ CONFIG_WATCHDOG=y
CONFIG_DA9063_WATCHDOG=y
CONFIG_MFD_AS3711=y
CONFIG_MFD_DA9063=y
-CONFIG_REGULATOR=y
CONFIG_REGULATOR_AS3711=y
CONFIG_REGULATOR_DA9210=y
CONFIG_REGULATOR_GPIO=y
@@ -160,7 +159,6 @@ CONFIG_USB_OHCI_HCD=y
CONFIG_USB_R8A66597_HCD=y
CONFIG_USB_RENESAS_USBHS=y
CONFIG_USB_RCAR_PHY=y
-CONFIG_USB_RCAR_GEN2_PHY=y
CONFIG_USB_GADGET=y
CONFIG_USB_RENESAS_USBHS_UDC=y
CONFIG_USB_ETH=y
@@ -182,6 +180,8 @@ CONFIG_IIO=y
CONFIG_AK8975=y
CONFIG_PWM=y
CONFIG_PWM_RENESAS_TPU=y
+CONFIG_GENERIC_PHY=y
+CONFIG_PHY_RCAR_GEN2=y
# CONFIG_DNOTIFY is not set
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
new file mode 100644
index 000000000000..4725fab562cb
--- /dev/null
+++ b/arch/arm/configs/stm32_defconfig
@@ -0,0 +1,70 @@
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_UID16 is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
+CONFIG_ARM_SINGLE_ARMV7M=y
+CONFIG_ARCH_STM32=y
+CONFIG_SET_MEM_PARAM=y
+CONFIG_DRAM_BASE=0x90000000
+CONFIG_FLASH_MEM_BASE=0x08000000
+CONFIG_FLASH_SIZE=0x00200000
+CONFIG_PREEMPT=y
+# CONFIG_ATAGS is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_XIP_KERNEL=y
+CONFIG_XIP_PHYS_ADDR=0x08008000
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_COREDUMP is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_EEPROM_93CX6=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_STM32=y
+CONFIG_SERIAL_STM32_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_NLS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_FTRACE is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index d199eb249151..cdf9abb46015 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -154,6 +154,8 @@ CONFIG_POWER_RESET_AS3722=y
CONFIG_POWER_RESET_GPIO=y
CONFIG_SENSORS_LM90=y
CONFIG_SENSORS_LM95245=y
+CONFIG_WATCHDOG=y
+CONFIG_TEGRA_WATCHDOG=y
CONFIG_MFD_AS3722=y
CONFIG_MFD_CROS_EC=y
CONFIG_MFD_CROS_EC_SPI=y
@@ -194,6 +196,14 @@ CONFIG_SOUND=y
CONFIG_SND=y
# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_DRIVERS is not set
+CONFIG_SND_HDA=y
+CONFIG_SND_HDA_TEGRA=y
+CONFIG_SND_HDA_INPUT_BEEP=y
+CONFIG_SND_HDA_INPUT_JACK=y
+CONFIG_SND_HDA_PATCH_LOADER=y
+CONFIG_SND_HDA_CODEC_REALTEK=y
+CONFIG_SND_HDA_CODEC_HDMI=y
+CONFIG_SND_HDA_GENERIC=y
# CONFIG_SND_ARM is not set
# CONFIG_SND_SPI is not set
# CONFIG_SND_USB is not set
diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig
index 6a1c9898fd03..07055eacbb0f 100644
--- a/arch/arm/configs/u8500_defconfig
+++ b/arch/arm/configs/u8500_defconfig
@@ -4,6 +4,7 @@ CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_KALLSYMS_ALL=y
+CONFIG_PERF_EVENTS=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
@@ -134,6 +135,10 @@ CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_PREEMPT is not set
# CONFIG_FTRACE is not set
CONFIG_DEBUG_USER=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_SINK_TPIU=y
+CONFIG_CORESIGHT_SINK_ETBV10=y
+CONFIG_CORESIGHT_SOURCE_ETM3X=y
CONFIG_CRYPTO_DEV_UX500=y
CONFIG_CRYPTO_DEV_UX500_CRYP=y
CONFIG_CRYPTO_DEV_UX500_HASH=y
diff --git a/arch/arm/configs/vf610m4_defconfig b/arch/arm/configs/vf610m4_defconfig
new file mode 100644
index 000000000000..aeb2482c492e
--- /dev/null
+++ b/arch/arm/configs/vf610m4_defconfig
@@ -0,0 +1,42 @@
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_MMU is not set
+CONFIG_ARM_SINGLE_ARMV7M=y
+CONFIG_ARCH_MXC=y
+CONFIG_SOC_VF610=y
+CONFIG_SET_MEM_PARAM=y
+CONFIG_DRAM_BASE=0x8c000000
+CONFIG_FLASH_MEM_BASE=0x8f000000
+CONFIG_FLASH_SIZE=0x01000000
+CONFIG_CMDLINE="console=/dev/ttyLP2"
+CONFIG_XIP_KERNEL=y
+CONFIG_XIP_PHYS_ADDR=0x0f000080
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+CONFIG_BINFMT_SHARED_FLAT=y
+# CONFIG_SUSPEND is not set
+# CONFIG_UEVENT_HELPER is not set
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+# CONFIG_ALLOW_DEV_COREDUMP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_SERIAL_FSL_LPUART=y
+CONFIG_SERIAL_FSL_LPUART_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_MFD_SYSCON=y
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_FTRACE is not set
diff --git a/arch/arm/configs/zx_defconfig b/arch/arm/configs/zx_defconfig
new file mode 100644
index 000000000000..b200bb0fecdd
--- /dev/null
+++ b/arch/arm/configs/zx_defconfig
@@ -0,0 +1,129 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_ZX=y
+CONFIG_SOC_ZX296702=y
+# CONFIG_SWP_EMULATE is not set
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_ARM_ERRATA_775420=y
+CONFIG_SMP=y
+CONFIG_VMSPLIT_2G=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_KSM=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HIBERNATION=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_DEBUG=y
+CONFIG_SUSPEND_TIME=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyAMA0,115200 debug earlyprintk root=/dev/ram rw rootwait"
+#CONFIG_NET is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=192
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_UID_STAT=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_NETDEVICES=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_SERIO=y
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SPI=y
+CONFIG_LOGO=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_CONSOLE_POLL=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+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
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_DEBUG=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=936
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+#CONFIG_NFS_FS is not set
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_WARN=4096
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_PANIC_TIMEOUT=5
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_FTRACE is not set
+CONFIG_KGDB=y
+CONFIG_KGDB_KDB=y
+# CONFIG_ARM_UNWIND is not set
+CONFIG_DEBUG_PREEMPT=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_STACKTRACE=y
+CONFIG_DEBUG_ZTE_ZX=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_GPIOLIB=y
diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig
index 8da2207b0072..27ed1b1cd1d7 100644
--- a/arch/arm/crypto/Kconfig
+++ b/arch/arm/crypto/Kconfig
@@ -53,20 +53,13 @@ config CRYPTO_SHA256_ARM
SHA-256 secure hash standard (DFIPS 180-2) implemented
using optimized ARM assembler and NEON, when available.
-config CRYPTO_SHA512_ARM_NEON
- tristate "SHA384 and SHA512 digest algorithm (ARM NEON)"
- depends on KERNEL_MODE_NEON
- select CRYPTO_SHA512
+config CRYPTO_SHA512_ARM
+ tristate "SHA-384/512 digest algorithm (ARM-asm and NEON)"
select CRYPTO_HASH
+ depends on !CPU_V7M
help
SHA-512 secure hash standard (DFIPS 180-2) implemented
- using ARM NEON instructions, when available.
-
- This version of SHA implements a 512 bit hash with 256 bits of
- security against collision attacks.
-
- This code also includes SHA-384, a 384 bit hash with 192 bits
- of security against collision attacks.
+ using optimized ARM assembler and NEON, when available.
config CRYPTO_AES_ARM
tristate "AES cipher algorithms (ARM-asm)"
diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile
index 6ea828241fcb..fc5150702b64 100644
--- a/arch/arm/crypto/Makefile
+++ b/arch/arm/crypto/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_CRYPTO_AES_ARM_BS) += aes-arm-bs.o
obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o
obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o
obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o
-obj-$(CONFIG_CRYPTO_SHA512_ARM_NEON) += sha512-arm-neon.o
+obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha512-arm.o
ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o
ce-obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o
@@ -30,7 +30,8 @@ sha1-arm-y := sha1-armv4-large.o sha1_glue.o
sha1-arm-neon-y := sha1-armv7-neon.o sha1_neon_glue.o
sha256-arm-neon-$(CONFIG_KERNEL_MODE_NEON) := sha256_neon_glue.o
sha256-arm-y := sha256-core.o sha256_glue.o $(sha256-arm-neon-y)
-sha512-arm-neon-y := sha512-armv7-neon.o sha512_neon_glue.o
+sha512-arm-neon-$(CONFIG_KERNEL_MODE_NEON) := sha512-neon-glue.o
+sha512-arm-y := sha512-core.o sha512-glue.o $(sha512-arm-neon-y)
sha1-arm-ce-y := sha1-ce-core.o sha1-ce-glue.o
sha2-arm-ce-y := sha2-ce-core.o sha2-ce-glue.o
aes-arm-ce-y := aes-ce-core.o aes-ce-glue.o
@@ -45,4 +46,7 @@ $(src)/aesbs-core.S_shipped: $(src)/bsaes-armv7.pl
$(src)/sha256-core.S_shipped: $(src)/sha256-armv4.pl
$(call cmd,perl)
-.PRECIOUS: $(obj)/aesbs-core.S $(obj)/sha256-core.S
+$(src)/sha512-core.S_shipped: $(src)/sha512-armv4.pl
+ $(call cmd,perl)
+
+.PRECIOUS: $(obj)/aesbs-core.S $(obj)/sha256-core.S $(obj)/sha512-core.S
diff --git a/arch/arm/crypto/aes-ce-core.S b/arch/arm/crypto/aes-ce-core.S
index 8cfa468ee570..987aa632c9f0 100644
--- a/arch/arm/crypto/aes-ce-core.S
+++ b/arch/arm/crypto/aes-ce-core.S
@@ -101,15 +101,14 @@
\dround q10, q11
blo 0f @ AES-128: 10 rounds
vld1.8 {q10-q11}, [ip]!
- beq 1f @ AES-192: 12 rounds
\dround q12, q13
+ beq 1f @ AES-192: 12 rounds
vld1.8 {q12-q13}, [ip]
\dround q10, q11
0: \fround q12, q13, q14
bx lr
-1: \dround q12, q13
- \fround q10, q11, q14
+1: \fround q10, q11, q14
bx lr
.endm
@@ -122,8 +121,8 @@
* q2 : third in/output block (_3x version only)
* q8 : first round key
* q9 : secound round key
- * ip : address of 3rd round key
* q14 : final round key
+ * r2 : address of round key array
* r3 : number of rounds
*/
.align 6
diff --git a/arch/arm/crypto/sha512-armv4.pl b/arch/arm/crypto/sha512-armv4.pl
new file mode 100644
index 000000000000..a2b11a844357
--- /dev/null
+++ b/arch/arm/crypto/sha512-armv4.pl
@@ -0,0 +1,649 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+#
+# Permission to use under GPL terms is granted.
+# ====================================================================
+
+# SHA512 block procedure for ARMv4. September 2007.
+
+# This code is ~4.5 (four and a half) times faster than code generated
+# by gcc 3.4 and it spends ~72 clock cycles per byte [on single-issue
+# Xscale PXA250 core].
+#
+# July 2010.
+#
+# Rescheduling for dual-issue pipeline resulted in 6% improvement on
+# Cortex A8 core and ~40 cycles per processed byte.
+
+# February 2011.
+#
+# Profiler-assisted and platform-specific optimization resulted in 7%
+# improvement on Coxtex A8 core and ~38 cycles per byte.
+
+# March 2011.
+#
+# Add NEON implementation. On Cortex A8 it was measured to process
+# one byte in 23.3 cycles or ~60% faster than integer-only code.
+
+# August 2012.
+#
+# Improve NEON performance by 12% on Snapdragon S4. In absolute
+# terms it's 22.6 cycles per byte, which is disappointing result.
+# Technical writers asserted that 3-way S4 pipeline can sustain
+# multiple NEON instructions per cycle, but dual NEON issue could
+# not be observed, see http://www.openssl.org/~appro/Snapdragon-S4.html
+# for further details. On side note Cortex-A15 processes one byte in
+# 16 cycles.
+
+# Byte order [in]dependence. =========================================
+#
+# Originally caller was expected to maintain specific *dword* order in
+# h[0-7], namely with most significant dword at *lower* address, which
+# was reflected in below two parameters as 0 and 4. Now caller is
+# expected to maintain native byte order for whole 64-bit values.
+$hi="HI";
+$lo="LO";
+# ====================================================================
+
+while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
+open STDOUT,">$output";
+
+$ctx="r0"; # parameter block
+$inp="r1";
+$len="r2";
+
+$Tlo="r3";
+$Thi="r4";
+$Alo="r5";
+$Ahi="r6";
+$Elo="r7";
+$Ehi="r8";
+$t0="r9";
+$t1="r10";
+$t2="r11";
+$t3="r12";
+############ r13 is stack pointer
+$Ktbl="r14";
+############ r15 is program counter
+
+$Aoff=8*0;
+$Boff=8*1;
+$Coff=8*2;
+$Doff=8*3;
+$Eoff=8*4;
+$Foff=8*5;
+$Goff=8*6;
+$Hoff=8*7;
+$Xoff=8*8;
+
+sub BODY_00_15() {
+my $magic = shift;
+$code.=<<___;
+ @ Sigma1(x) (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41))
+ @ LO lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23
+ @ HI hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23
+ mov $t0,$Elo,lsr#14
+ str $Tlo,[sp,#$Xoff+0]
+ mov $t1,$Ehi,lsr#14
+ str $Thi,[sp,#$Xoff+4]
+ eor $t0,$t0,$Ehi,lsl#18
+ ldr $t2,[sp,#$Hoff+0] @ h.lo
+ eor $t1,$t1,$Elo,lsl#18
+ ldr $t3,[sp,#$Hoff+4] @ h.hi
+ eor $t0,$t0,$Elo,lsr#18
+ eor $t1,$t1,$Ehi,lsr#18
+ eor $t0,$t0,$Ehi,lsl#14
+ eor $t1,$t1,$Elo,lsl#14
+ eor $t0,$t0,$Ehi,lsr#9
+ eor $t1,$t1,$Elo,lsr#9
+ eor $t0,$t0,$Elo,lsl#23
+ eor $t1,$t1,$Ehi,lsl#23 @ Sigma1(e)
+ adds $Tlo,$Tlo,$t0
+ ldr $t0,[sp,#$Foff+0] @ f.lo
+ adc $Thi,$Thi,$t1 @ T += Sigma1(e)
+ ldr $t1,[sp,#$Foff+4] @ f.hi
+ adds $Tlo,$Tlo,$t2
+ ldr $t2,[sp,#$Goff+0] @ g.lo
+ adc $Thi,$Thi,$t3 @ T += h
+ ldr $t3,[sp,#$Goff+4] @ g.hi
+
+ eor $t0,$t0,$t2
+ str $Elo,[sp,#$Eoff+0]
+ eor $t1,$t1,$t3
+ str $Ehi,[sp,#$Eoff+4]
+ and $t0,$t0,$Elo
+ str $Alo,[sp,#$Aoff+0]
+ and $t1,$t1,$Ehi
+ str $Ahi,[sp,#$Aoff+4]
+ eor $t0,$t0,$t2
+ ldr $t2,[$Ktbl,#$lo] @ K[i].lo
+ eor $t1,$t1,$t3 @ Ch(e,f,g)
+ ldr $t3,[$Ktbl,#$hi] @ K[i].hi
+
+ adds $Tlo,$Tlo,$t0
+ ldr $Elo,[sp,#$Doff+0] @ d.lo
+ adc $Thi,$Thi,$t1 @ T += Ch(e,f,g)
+ ldr $Ehi,[sp,#$Doff+4] @ d.hi
+ adds $Tlo,$Tlo,$t2
+ and $t0,$t2,#0xff
+ adc $Thi,$Thi,$t3 @ T += K[i]
+ adds $Elo,$Elo,$Tlo
+ ldr $t2,[sp,#$Boff+0] @ b.lo
+ adc $Ehi,$Ehi,$Thi @ d += T
+ teq $t0,#$magic
+
+ ldr $t3,[sp,#$Coff+0] @ c.lo
+#if __ARM_ARCH__>=7
+ it eq @ Thumb2 thing, sanity check in ARM
+#endif
+ orreq $Ktbl,$Ktbl,#1
+ @ Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39))
+ @ LO lo>>28^hi<<4 ^ hi>>2^lo<<30 ^ hi>>7^lo<<25
+ @ HI hi>>28^lo<<4 ^ lo>>2^hi<<30 ^ lo>>7^hi<<25
+ mov $t0,$Alo,lsr#28
+ mov $t1,$Ahi,lsr#28
+ eor $t0,$t0,$Ahi,lsl#4
+ eor $t1,$t1,$Alo,lsl#4
+ eor $t0,$t0,$Ahi,lsr#2
+ eor $t1,$t1,$Alo,lsr#2
+ eor $t0,$t0,$Alo,lsl#30
+ eor $t1,$t1,$Ahi,lsl#30
+ eor $t0,$t0,$Ahi,lsr#7
+ eor $t1,$t1,$Alo,lsr#7
+ eor $t0,$t0,$Alo,lsl#25
+ eor $t1,$t1,$Ahi,lsl#25 @ Sigma0(a)
+ adds $Tlo,$Tlo,$t0
+ and $t0,$Alo,$t2
+ adc $Thi,$Thi,$t1 @ T += Sigma0(a)
+
+ ldr $t1,[sp,#$Boff+4] @ b.hi
+ orr $Alo,$Alo,$t2
+ ldr $t2,[sp,#$Coff+4] @ c.hi
+ and $Alo,$Alo,$t3
+ and $t3,$Ahi,$t1
+ orr $Ahi,$Ahi,$t1
+ orr $Alo,$Alo,$t0 @ Maj(a,b,c).lo
+ and $Ahi,$Ahi,$t2
+ adds $Alo,$Alo,$Tlo
+ orr $Ahi,$Ahi,$t3 @ Maj(a,b,c).hi
+ sub sp,sp,#8
+ adc $Ahi,$Ahi,$Thi @ h += T
+ tst $Ktbl,#1
+ add $Ktbl,$Ktbl,#8
+___
+}
+$code=<<___;
+#ifndef __KERNEL__
+# include "arm_arch.h"
+# define VFP_ABI_PUSH vstmdb sp!,{d8-d15}
+# define VFP_ABI_POP vldmia sp!,{d8-d15}
+#else
+# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+# define __ARM_MAX_ARCH__ 7
+# define VFP_ABI_PUSH
+# define VFP_ABI_POP
+#endif
+
+#ifdef __ARMEL__
+# define LO 0
+# define HI 4
+# define WORD64(hi0,lo0,hi1,lo1) .word lo0,hi0, lo1,hi1
+#else
+# define HI 0
+# define LO 4
+# define WORD64(hi0,lo0,hi1,lo1) .word hi0,lo0, hi1,lo1
+#endif
+
+.text
+#if __ARM_ARCH__<7
+.code 32
+#else
+.syntax unified
+# ifdef __thumb2__
+# define adrl adr
+.thumb
+# else
+.code 32
+# endif
+#endif
+
+.type K512,%object
+.align 5
+K512:
+WORD64(0x428a2f98,0xd728ae22, 0x71374491,0x23ef65cd)
+WORD64(0xb5c0fbcf,0xec4d3b2f, 0xe9b5dba5,0x8189dbbc)
+WORD64(0x3956c25b,0xf348b538, 0x59f111f1,0xb605d019)
+WORD64(0x923f82a4,0xaf194f9b, 0xab1c5ed5,0xda6d8118)
+WORD64(0xd807aa98,0xa3030242, 0x12835b01,0x45706fbe)
+WORD64(0x243185be,0x4ee4b28c, 0x550c7dc3,0xd5ffb4e2)
+WORD64(0x72be5d74,0xf27b896f, 0x80deb1fe,0x3b1696b1)
+WORD64(0x9bdc06a7,0x25c71235, 0xc19bf174,0xcf692694)
+WORD64(0xe49b69c1,0x9ef14ad2, 0xefbe4786,0x384f25e3)
+WORD64(0x0fc19dc6,0x8b8cd5b5, 0x240ca1cc,0x77ac9c65)
+WORD64(0x2de92c6f,0x592b0275, 0x4a7484aa,0x6ea6e483)
+WORD64(0x5cb0a9dc,0xbd41fbd4, 0x76f988da,0x831153b5)
+WORD64(0x983e5152,0xee66dfab, 0xa831c66d,0x2db43210)
+WORD64(0xb00327c8,0x98fb213f, 0xbf597fc7,0xbeef0ee4)
+WORD64(0xc6e00bf3,0x3da88fc2, 0xd5a79147,0x930aa725)
+WORD64(0x06ca6351,0xe003826f, 0x14292967,0x0a0e6e70)
+WORD64(0x27b70a85,0x46d22ffc, 0x2e1b2138,0x5c26c926)
+WORD64(0x4d2c6dfc,0x5ac42aed, 0x53380d13,0x9d95b3df)
+WORD64(0x650a7354,0x8baf63de, 0x766a0abb,0x3c77b2a8)
+WORD64(0x81c2c92e,0x47edaee6, 0x92722c85,0x1482353b)
+WORD64(0xa2bfe8a1,0x4cf10364, 0xa81a664b,0xbc423001)
+WORD64(0xc24b8b70,0xd0f89791, 0xc76c51a3,0x0654be30)
+WORD64(0xd192e819,0xd6ef5218, 0xd6990624,0x5565a910)
+WORD64(0xf40e3585,0x5771202a, 0x106aa070,0x32bbd1b8)
+WORD64(0x19a4c116,0xb8d2d0c8, 0x1e376c08,0x5141ab53)
+WORD64(0x2748774c,0xdf8eeb99, 0x34b0bcb5,0xe19b48a8)
+WORD64(0x391c0cb3,0xc5c95a63, 0x4ed8aa4a,0xe3418acb)
+WORD64(0x5b9cca4f,0x7763e373, 0x682e6ff3,0xd6b2b8a3)
+WORD64(0x748f82ee,0x5defb2fc, 0x78a5636f,0x43172f60)
+WORD64(0x84c87814,0xa1f0ab72, 0x8cc70208,0x1a6439ec)
+WORD64(0x90befffa,0x23631e28, 0xa4506ceb,0xde82bde9)
+WORD64(0xbef9a3f7,0xb2c67915, 0xc67178f2,0xe372532b)
+WORD64(0xca273ece,0xea26619c, 0xd186b8c7,0x21c0c207)
+WORD64(0xeada7dd6,0xcde0eb1e, 0xf57d4f7f,0xee6ed178)
+WORD64(0x06f067aa,0x72176fba, 0x0a637dc5,0xa2c898a6)
+WORD64(0x113f9804,0xbef90dae, 0x1b710b35,0x131c471b)
+WORD64(0x28db77f5,0x23047d84, 0x32caab7b,0x40c72493)
+WORD64(0x3c9ebe0a,0x15c9bebc, 0x431d67c4,0x9c100d4c)
+WORD64(0x4cc5d4be,0xcb3e42b6, 0x597f299c,0xfc657e2a)
+WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817)
+.size K512,.-K512
+#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
+.LOPENSSL_armcap:
+.word OPENSSL_armcap_P-sha512_block_data_order
+.skip 32-4
+#else
+.skip 32
+#endif
+
+.global sha512_block_data_order
+.type sha512_block_data_order,%function
+sha512_block_data_order:
+#if __ARM_ARCH__<7
+ sub r3,pc,#8 @ sha512_block_data_order
+#else
+ adr r3,sha512_block_data_order
+#endif
+#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
+ ldr r12,.LOPENSSL_armcap
+ ldr r12,[r3,r12] @ OPENSSL_armcap_P
+ tst r12,#1
+ bne .LNEON
+#endif
+ add $len,$inp,$len,lsl#7 @ len to point at the end of inp
+ stmdb sp!,{r4-r12,lr}
+ sub $Ktbl,r3,#672 @ K512
+ sub sp,sp,#9*8
+
+ ldr $Elo,[$ctx,#$Eoff+$lo]
+ ldr $Ehi,[$ctx,#$Eoff+$hi]
+ ldr $t0, [$ctx,#$Goff+$lo]
+ ldr $t1, [$ctx,#$Goff+$hi]
+ ldr $t2, [$ctx,#$Hoff+$lo]
+ ldr $t3, [$ctx,#$Hoff+$hi]
+.Loop:
+ str $t0, [sp,#$Goff+0]
+ str $t1, [sp,#$Goff+4]
+ str $t2, [sp,#$Hoff+0]
+ str $t3, [sp,#$Hoff+4]
+ ldr $Alo,[$ctx,#$Aoff+$lo]
+ ldr $Ahi,[$ctx,#$Aoff+$hi]
+ ldr $Tlo,[$ctx,#$Boff+$lo]
+ ldr $Thi,[$ctx,#$Boff+$hi]
+ ldr $t0, [$ctx,#$Coff+$lo]
+ ldr $t1, [$ctx,#$Coff+$hi]
+ ldr $t2, [$ctx,#$Doff+$lo]
+ ldr $t3, [$ctx,#$Doff+$hi]
+ str $Tlo,[sp,#$Boff+0]
+ str $Thi,[sp,#$Boff+4]
+ str $t0, [sp,#$Coff+0]
+ str $t1, [sp,#$Coff+4]
+ str $t2, [sp,#$Doff+0]
+ str $t3, [sp,#$Doff+4]
+ ldr $Tlo,[$ctx,#$Foff+$lo]
+ ldr $Thi,[$ctx,#$Foff+$hi]
+ str $Tlo,[sp,#$Foff+0]
+ str $Thi,[sp,#$Foff+4]
+
+.L00_15:
+#if __ARM_ARCH__<7
+ ldrb $Tlo,[$inp,#7]
+ ldrb $t0, [$inp,#6]
+ ldrb $t1, [$inp,#5]
+ ldrb $t2, [$inp,#4]
+ ldrb $Thi,[$inp,#3]
+ ldrb $t3, [$inp,#2]
+ orr $Tlo,$Tlo,$t0,lsl#8
+ ldrb $t0, [$inp,#1]
+ orr $Tlo,$Tlo,$t1,lsl#16
+ ldrb $t1, [$inp],#8
+ orr $Tlo,$Tlo,$t2,lsl#24
+ orr $Thi,$Thi,$t3,lsl#8
+ orr $Thi,$Thi,$t0,lsl#16
+ orr $Thi,$Thi,$t1,lsl#24
+#else
+ ldr $Tlo,[$inp,#4]
+ ldr $Thi,[$inp],#8
+#ifdef __ARMEL__
+ rev $Tlo,$Tlo
+ rev $Thi,$Thi
+#endif
+#endif
+___
+ &BODY_00_15(0x94);
+$code.=<<___;
+ tst $Ktbl,#1
+ beq .L00_15
+ ldr $t0,[sp,#`$Xoff+8*(16-1)`+0]
+ ldr $t1,[sp,#`$Xoff+8*(16-1)`+4]
+ bic $Ktbl,$Ktbl,#1
+.L16_79:
+ @ sigma0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7))
+ @ LO lo>>1^hi<<31 ^ lo>>8^hi<<24 ^ lo>>7^hi<<25
+ @ HI hi>>1^lo<<31 ^ hi>>8^lo<<24 ^ hi>>7
+ mov $Tlo,$t0,lsr#1
+ ldr $t2,[sp,#`$Xoff+8*(16-14)`+0]
+ mov $Thi,$t1,lsr#1
+ ldr $t3,[sp,#`$Xoff+8*(16-14)`+4]
+ eor $Tlo,$Tlo,$t1,lsl#31
+ eor $Thi,$Thi,$t0,lsl#31
+ eor $Tlo,$Tlo,$t0,lsr#8
+ eor $Thi,$Thi,$t1,lsr#8
+ eor $Tlo,$Tlo,$t1,lsl#24
+ eor $Thi,$Thi,$t0,lsl#24
+ eor $Tlo,$Tlo,$t0,lsr#7
+ eor $Thi,$Thi,$t1,lsr#7
+ eor $Tlo,$Tlo,$t1,lsl#25
+
+ @ sigma1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6))
+ @ LO lo>>19^hi<<13 ^ hi>>29^lo<<3 ^ lo>>6^hi<<26
+ @ HI hi>>19^lo<<13 ^ lo>>29^hi<<3 ^ hi>>6
+ mov $t0,$t2,lsr#19
+ mov $t1,$t3,lsr#19
+ eor $t0,$t0,$t3,lsl#13
+ eor $t1,$t1,$t2,lsl#13
+ eor $t0,$t0,$t3,lsr#29
+ eor $t1,$t1,$t2,lsr#29
+ eor $t0,$t0,$t2,lsl#3
+ eor $t1,$t1,$t3,lsl#3
+ eor $t0,$t0,$t2,lsr#6
+ eor $t1,$t1,$t3,lsr#6
+ ldr $t2,[sp,#`$Xoff+8*(16-9)`+0]
+ eor $t0,$t0,$t3,lsl#26
+
+ ldr $t3,[sp,#`$Xoff+8*(16-9)`+4]
+ adds $Tlo,$Tlo,$t0
+ ldr $t0,[sp,#`$Xoff+8*16`+0]
+ adc $Thi,$Thi,$t1
+
+ ldr $t1,[sp,#`$Xoff+8*16`+4]
+ adds $Tlo,$Tlo,$t2
+ adc $Thi,$Thi,$t3
+ adds $Tlo,$Tlo,$t0
+ adc $Thi,$Thi,$t1
+___
+ &BODY_00_15(0x17);
+$code.=<<___;
+#if __ARM_ARCH__>=7
+ ittt eq @ Thumb2 thing, sanity check in ARM
+#endif
+ ldreq $t0,[sp,#`$Xoff+8*(16-1)`+0]
+ ldreq $t1,[sp,#`$Xoff+8*(16-1)`+4]
+ beq .L16_79
+ bic $Ktbl,$Ktbl,#1
+
+ ldr $Tlo,[sp,#$Boff+0]
+ ldr $Thi,[sp,#$Boff+4]
+ ldr $t0, [$ctx,#$Aoff+$lo]
+ ldr $t1, [$ctx,#$Aoff+$hi]
+ ldr $t2, [$ctx,#$Boff+$lo]
+ ldr $t3, [$ctx,#$Boff+$hi]
+ adds $t0,$Alo,$t0
+ str $t0, [$ctx,#$Aoff+$lo]
+ adc $t1,$Ahi,$t1
+ str $t1, [$ctx,#$Aoff+$hi]
+ adds $t2,$Tlo,$t2
+ str $t2, [$ctx,#$Boff+$lo]
+ adc $t3,$Thi,$t3
+ str $t3, [$ctx,#$Boff+$hi]
+
+ ldr $Alo,[sp,#$Coff+0]
+ ldr $Ahi,[sp,#$Coff+4]
+ ldr $Tlo,[sp,#$Doff+0]
+ ldr $Thi,[sp,#$Doff+4]
+ ldr $t0, [$ctx,#$Coff+$lo]
+ ldr $t1, [$ctx,#$Coff+$hi]
+ ldr $t2, [$ctx,#$Doff+$lo]
+ ldr $t3, [$ctx,#$Doff+$hi]
+ adds $t0,$Alo,$t0
+ str $t0, [$ctx,#$Coff+$lo]
+ adc $t1,$Ahi,$t1
+ str $t1, [$ctx,#$Coff+$hi]
+ adds $t2,$Tlo,$t2
+ str $t2, [$ctx,#$Doff+$lo]
+ adc $t3,$Thi,$t3
+ str $t3, [$ctx,#$Doff+$hi]
+
+ ldr $Tlo,[sp,#$Foff+0]
+ ldr $Thi,[sp,#$Foff+4]
+ ldr $t0, [$ctx,#$Eoff+$lo]
+ ldr $t1, [$ctx,#$Eoff+$hi]
+ ldr $t2, [$ctx,#$Foff+$lo]
+ ldr $t3, [$ctx,#$Foff+$hi]
+ adds $Elo,$Elo,$t0
+ str $Elo,[$ctx,#$Eoff+$lo]
+ adc $Ehi,$Ehi,$t1
+ str $Ehi,[$ctx,#$Eoff+$hi]
+ adds $t2,$Tlo,$t2
+ str $t2, [$ctx,#$Foff+$lo]
+ adc $t3,$Thi,$t3
+ str $t3, [$ctx,#$Foff+$hi]
+
+ ldr $Alo,[sp,#$Goff+0]
+ ldr $Ahi,[sp,#$Goff+4]
+ ldr $Tlo,[sp,#$Hoff+0]
+ ldr $Thi,[sp,#$Hoff+4]
+ ldr $t0, [$ctx,#$Goff+$lo]
+ ldr $t1, [$ctx,#$Goff+$hi]
+ ldr $t2, [$ctx,#$Hoff+$lo]
+ ldr $t3, [$ctx,#$Hoff+$hi]
+ adds $t0,$Alo,$t0
+ str $t0, [$ctx,#$Goff+$lo]
+ adc $t1,$Ahi,$t1
+ str $t1, [$ctx,#$Goff+$hi]
+ adds $t2,$Tlo,$t2
+ str $t2, [$ctx,#$Hoff+$lo]
+ adc $t3,$Thi,$t3
+ str $t3, [$ctx,#$Hoff+$hi]
+
+ add sp,sp,#640
+ sub $Ktbl,$Ktbl,#640
+
+ teq $inp,$len
+ bne .Loop
+
+ add sp,sp,#8*9 @ destroy frame
+#if __ARM_ARCH__>=5
+ ldmia sp!,{r4-r12,pc}
+#else
+ ldmia sp!,{r4-r12,lr}
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+.size sha512_block_data_order,.-sha512_block_data_order
+___
+
+{
+my @Sigma0=(28,34,39);
+my @Sigma1=(14,18,41);
+my @sigma0=(1, 8, 7);
+my @sigma1=(19,61,6);
+
+my $Ktbl="r3";
+my $cnt="r12"; # volatile register known as ip, intra-procedure-call scratch
+
+my @X=map("d$_",(0..15));
+my @V=($A,$B,$C,$D,$E,$F,$G,$H)=map("d$_",(16..23));
+
+sub NEON_00_15() {
+my $i=shift;
+my ($a,$b,$c,$d,$e,$f,$g,$h)=@_;
+my ($t0,$t1,$t2,$T1,$K,$Ch,$Maj)=map("d$_",(24..31)); # temps
+
+$code.=<<___ if ($i<16 || $i&1);
+ vshr.u64 $t0,$e,#@Sigma1[0] @ $i
+#if $i<16
+ vld1.64 {@X[$i%16]},[$inp]! @ handles unaligned
+#endif
+ vshr.u64 $t1,$e,#@Sigma1[1]
+#if $i>0
+ vadd.i64 $a,$Maj @ h+=Maj from the past
+#endif
+ vshr.u64 $t2,$e,#@Sigma1[2]
+___
+$code.=<<___;
+ vld1.64 {$K},[$Ktbl,:64]! @ K[i++]
+ vsli.64 $t0,$e,#`64-@Sigma1[0]`
+ vsli.64 $t1,$e,#`64-@Sigma1[1]`
+ vmov $Ch,$e
+ vsli.64 $t2,$e,#`64-@Sigma1[2]`
+#if $i<16 && defined(__ARMEL__)
+ vrev64.8 @X[$i],@X[$i]
+#endif
+ veor $t1,$t0
+ vbsl $Ch,$f,$g @ Ch(e,f,g)
+ vshr.u64 $t0,$a,#@Sigma0[0]
+ veor $t2,$t1 @ Sigma1(e)
+ vadd.i64 $T1,$Ch,$h
+ vshr.u64 $t1,$a,#@Sigma0[1]
+ vsli.64 $t0,$a,#`64-@Sigma0[0]`
+ vadd.i64 $T1,$t2
+ vshr.u64 $t2,$a,#@Sigma0[2]
+ vadd.i64 $K,@X[$i%16]
+ vsli.64 $t1,$a,#`64-@Sigma0[1]`
+ veor $Maj,$a,$b
+ vsli.64 $t2,$a,#`64-@Sigma0[2]`
+ veor $h,$t0,$t1
+ vadd.i64 $T1,$K
+ vbsl $Maj,$c,$b @ Maj(a,b,c)
+ veor $h,$t2 @ Sigma0(a)
+ vadd.i64 $d,$T1
+ vadd.i64 $Maj,$T1
+ @ vadd.i64 $h,$Maj
+___
+}
+
+sub NEON_16_79() {
+my $i=shift;
+
+if ($i&1) { &NEON_00_15($i,@_); return; }
+
+# 2x-vectorized, therefore runs every 2nd round
+my @X=map("q$_",(0..7)); # view @X as 128-bit vector
+my ($t0,$t1,$s0,$s1) = map("q$_",(12..15)); # temps
+my ($d0,$d1,$d2) = map("d$_",(24..26)); # temps from NEON_00_15
+my $e=@_[4]; # $e from NEON_00_15
+$i /= 2;
+$code.=<<___;
+ vshr.u64 $t0,@X[($i+7)%8],#@sigma1[0]
+ vshr.u64 $t1,@X[($i+7)%8],#@sigma1[1]
+ vadd.i64 @_[0],d30 @ h+=Maj from the past
+ vshr.u64 $s1,@X[($i+7)%8],#@sigma1[2]
+ vsli.64 $t0,@X[($i+7)%8],#`64-@sigma1[0]`
+ vext.8 $s0,@X[$i%8],@X[($i+1)%8],#8 @ X[i+1]
+ vsli.64 $t1,@X[($i+7)%8],#`64-@sigma1[1]`
+ veor $s1,$t0
+ vshr.u64 $t0,$s0,#@sigma0[0]
+ veor $s1,$t1 @ sigma1(X[i+14])
+ vshr.u64 $t1,$s0,#@sigma0[1]
+ vadd.i64 @X[$i%8],$s1
+ vshr.u64 $s1,$s0,#@sigma0[2]
+ vsli.64 $t0,$s0,#`64-@sigma0[0]`
+ vsli.64 $t1,$s0,#`64-@sigma0[1]`
+ vext.8 $s0,@X[($i+4)%8],@X[($i+5)%8],#8 @ X[i+9]
+ veor $s1,$t0
+ vshr.u64 $d0,$e,#@Sigma1[0] @ from NEON_00_15
+ vadd.i64 @X[$i%8],$s0
+ vshr.u64 $d1,$e,#@Sigma1[1] @ from NEON_00_15
+ veor $s1,$t1 @ sigma0(X[i+1])
+ vshr.u64 $d2,$e,#@Sigma1[2] @ from NEON_00_15
+ vadd.i64 @X[$i%8],$s1
+___
+ &NEON_00_15(2*$i,@_);
+}
+
+$code.=<<___;
+#if __ARM_MAX_ARCH__>=7
+.arch armv7-a
+.fpu neon
+
+.global sha512_block_data_order_neon
+.type sha512_block_data_order_neon,%function
+.align 4
+sha512_block_data_order_neon:
+.LNEON:
+ dmb @ errata #451034 on early Cortex A8
+ add $len,$inp,$len,lsl#7 @ len to point at the end of inp
+ VFP_ABI_PUSH
+ adrl $Ktbl,K512
+ vldmia $ctx,{$A-$H} @ load context
+.Loop_neon:
+___
+for($i=0;$i<16;$i++) { &NEON_00_15($i,@V); unshift(@V,pop(@V)); }
+$code.=<<___;
+ mov $cnt,#4
+.L16_79_neon:
+ subs $cnt,#1
+___
+for(;$i<32;$i++) { &NEON_16_79($i,@V); unshift(@V,pop(@V)); }
+$code.=<<___;
+ bne .L16_79_neon
+
+ vadd.i64 $A,d30 @ h+=Maj from the past
+ vldmia $ctx,{d24-d31} @ load context to temp
+ vadd.i64 q8,q12 @ vectorized accumulate
+ vadd.i64 q9,q13
+ vadd.i64 q10,q14
+ vadd.i64 q11,q15
+ vstmia $ctx,{$A-$H} @ save context
+ teq $inp,$len
+ sub $Ktbl,#640 @ rewind K512
+ bne .Loop_neon
+
+ VFP_ABI_POP
+ ret @ bx lr
+.size sha512_block_data_order_neon,.-sha512_block_data_order_neon
+#endif
+___
+}
+$code.=<<___;
+.asciz "SHA512 block transform for ARMv4/NEON, CRYPTOGAMS by <appro\@openssl.org>"
+.align 2
+#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
+.comm OPENSSL_armcap_P,4,4
+#endif
+___
+
+$code =~ s/\`([^\`]*)\`/eval $1/gem;
+$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4
+$code =~ s/\bret\b/bx lr/gm;
+
+open SELF,$0;
+while(<SELF>) {
+ next if (/^#!/);
+ last if (!s/^#/@/ and !/^$/);
+ print;
+}
+close SELF;
+
+print $code;
+close STDOUT; # enforce flush
diff --git a/arch/arm/crypto/sha512-armv7-neon.S b/arch/arm/crypto/sha512-armv7-neon.S
deleted file mode 100644
index fe99472e507c..000000000000
--- a/arch/arm/crypto/sha512-armv7-neon.S
+++ /dev/null
@@ -1,455 +0,0 @@
-/* sha512-armv7-neon.S - ARM/NEON assembly implementation of SHA-512 transform
- *
- * Copyright © 2013-2014 Jussi Kivilinna <jussi.kivilinna@iki.fi>
- *
- * 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/linkage.h>
-
-
-.syntax unified
-.code 32
-.fpu neon
-
-.text
-
-/* structure of SHA512_CONTEXT */
-#define hd_a 0
-#define hd_b ((hd_a) + 8)
-#define hd_c ((hd_b) + 8)
-#define hd_d ((hd_c) + 8)
-#define hd_e ((hd_d) + 8)
-#define hd_f ((hd_e) + 8)
-#define hd_g ((hd_f) + 8)
-
-/* register macros */
-#define RK %r2
-
-#define RA d0
-#define RB d1
-#define RC d2
-#define RD d3
-#define RE d4
-#define RF d5
-#define RG d6
-#define RH d7
-
-#define RT0 d8
-#define RT1 d9
-#define RT2 d10
-#define RT3 d11
-#define RT4 d12
-#define RT5 d13
-#define RT6 d14
-#define RT7 d15
-
-#define RT01q q4
-#define RT23q q5
-#define RT45q q6
-#define RT67q q7
-
-#define RW0 d16
-#define RW1 d17
-#define RW2 d18
-#define RW3 d19
-#define RW4 d20
-#define RW5 d21
-#define RW6 d22
-#define RW7 d23
-#define RW8 d24
-#define RW9 d25
-#define RW10 d26
-#define RW11 d27
-#define RW12 d28
-#define RW13 d29
-#define RW14 d30
-#define RW15 d31
-
-#define RW01q q8
-#define RW23q q9
-#define RW45q q10
-#define RW67q q11
-#define RW89q q12
-#define RW1011q q13
-#define RW1213q q14
-#define RW1415q q15
-
-/***********************************************************************
- * ARM assembly implementation of sha512 transform
- ***********************************************************************/
-#define rounds2_0_63(ra, rb, rc, rd, re, rf, rg, rh, rw0, rw1, rw01q, rw2, \
- rw23q, rw1415q, rw9, rw10, interleave_op, arg1) \
- /* t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; */ \
- vshr.u64 RT2, re, #14; \
- vshl.u64 RT3, re, #64 - 14; \
- interleave_op(arg1); \
- vshr.u64 RT4, re, #18; \
- vshl.u64 RT5, re, #64 - 18; \
- vld1.64 {RT0}, [RK]!; \
- veor.64 RT23q, RT23q, RT45q; \
- vshr.u64 RT4, re, #41; \
- vshl.u64 RT5, re, #64 - 41; \
- vadd.u64 RT0, RT0, rw0; \
- veor.64 RT23q, RT23q, RT45q; \
- vmov.64 RT7, re; \
- veor.64 RT1, RT2, RT3; \
- vbsl.64 RT7, rf, rg; \
- \
- vadd.u64 RT1, RT1, rh; \
- vshr.u64 RT2, ra, #28; \
- vshl.u64 RT3, ra, #64 - 28; \
- vadd.u64 RT1, RT1, RT0; \
- vshr.u64 RT4, ra, #34; \
- vshl.u64 RT5, ra, #64 - 34; \
- vadd.u64 RT1, RT1, RT7; \
- \
- /* h = Sum0 (a) + Maj (a, b, c); */ \
- veor.64 RT23q, RT23q, RT45q; \
- vshr.u64 RT4, ra, #39; \
- vshl.u64 RT5, ra, #64 - 39; \
- veor.64 RT0, ra, rb; \
- veor.64 RT23q, RT23q, RT45q; \
- vbsl.64 RT0, rc, rb; \
- vadd.u64 rd, rd, RT1; /* d+=t1; */ \
- veor.64 rh, RT2, RT3; \
- \
- /* t1 = g + Sum1 (d) + Ch (d, e, f) + k[t] + w[t]; */ \
- vshr.u64 RT2, rd, #14; \
- vshl.u64 RT3, rd, #64 - 14; \
- vadd.u64 rh, rh, RT0; \
- vshr.u64 RT4, rd, #18; \
- vshl.u64 RT5, rd, #64 - 18; \
- vadd.u64 rh, rh, RT1; /* h+=t1; */ \
- vld1.64 {RT0}, [RK]!; \
- veor.64 RT23q, RT23q, RT45q; \
- vshr.u64 RT4, rd, #41; \
- vshl.u64 RT5, rd, #64 - 41; \
- vadd.u64 RT0, RT0, rw1; \
- veor.64 RT23q, RT23q, RT45q; \
- vmov.64 RT7, rd; \
- veor.64 RT1, RT2, RT3; \
- vbsl.64 RT7, re, rf; \
- \
- vadd.u64 RT1, RT1, rg; \
- vshr.u64 RT2, rh, #28; \
- vshl.u64 RT3, rh, #64 - 28; \
- vadd.u64 RT1, RT1, RT0; \
- vshr.u64 RT4, rh, #34; \
- vshl.u64 RT5, rh, #64 - 34; \
- vadd.u64 RT1, RT1, RT7; \
- \
- /* g = Sum0 (h) + Maj (h, a, b); */ \
- veor.64 RT23q, RT23q, RT45q; \
- vshr.u64 RT4, rh, #39; \
- vshl.u64 RT5, rh, #64 - 39; \
- veor.64 RT0, rh, ra; \
- veor.64 RT23q, RT23q, RT45q; \
- vbsl.64 RT0, rb, ra; \
- vadd.u64 rc, rc, RT1; /* c+=t1; */ \
- veor.64 rg, RT2, RT3; \
- \
- /* w[0] += S1 (w[14]) + w[9] + S0 (w[1]); */ \
- /* w[1] += S1 (w[15]) + w[10] + S0 (w[2]); */ \
- \
- /**** S0(w[1:2]) */ \
- \
- /* w[0:1] += w[9:10] */ \
- /* RT23q = rw1:rw2 */ \
- vext.u64 RT23q, rw01q, rw23q, #1; \
- vadd.u64 rw0, rw9; \
- vadd.u64 rg, rg, RT0; \
- vadd.u64 rw1, rw10;\
- vadd.u64 rg, rg, RT1; /* g+=t1; */ \
- \
- vshr.u64 RT45q, RT23q, #1; \
- vshl.u64 RT67q, RT23q, #64 - 1; \
- vshr.u64 RT01q, RT23q, #8; \
- veor.u64 RT45q, RT45q, RT67q; \
- vshl.u64 RT67q, RT23q, #64 - 8; \
- veor.u64 RT45q, RT45q, RT01q; \
- vshr.u64 RT01q, RT23q, #7; \
- veor.u64 RT45q, RT45q, RT67q; \
- \
- /**** S1(w[14:15]) */ \
- vshr.u64 RT23q, rw1415q, #6; \
- veor.u64 RT01q, RT01q, RT45q; \
- vshr.u64 RT45q, rw1415q, #19; \
- vshl.u64 RT67q, rw1415q, #64 - 19; \
- veor.u64 RT23q, RT23q, RT45q; \
- vshr.u64 RT45q, rw1415q, #61; \
- veor.u64 RT23q, RT23q, RT67q; \
- vshl.u64 RT67q, rw1415q, #64 - 61; \
- veor.u64 RT23q, RT23q, RT45q; \
- vadd.u64 rw01q, RT01q; /* w[0:1] += S(w[1:2]) */ \
- veor.u64 RT01q, RT23q, RT67q;
-#define vadd_RT01q(rw01q) \
- /* w[0:1] += S(w[14:15]) */ \
- vadd.u64 rw01q, RT01q;
-
-#define dummy(_) /*_*/
-
-#define rounds2_64_79(ra, rb, rc, rd, re, rf, rg, rh, rw0, rw1, \
- interleave_op1, arg1, interleave_op2, arg2) \
- /* t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; */ \
- vshr.u64 RT2, re, #14; \
- vshl.u64 RT3, re, #64 - 14; \
- interleave_op1(arg1); \
- vshr.u64 RT4, re, #18; \
- vshl.u64 RT5, re, #64 - 18; \
- interleave_op2(arg2); \
- vld1.64 {RT0}, [RK]!; \
- veor.64 RT23q, RT23q, RT45q; \
- vshr.u64 RT4, re, #41; \
- vshl.u64 RT5, re, #64 - 41; \
- vadd.u64 RT0, RT0, rw0; \
- veor.64 RT23q, RT23q, RT45q; \
- vmov.64 RT7, re; \
- veor.64 RT1, RT2, RT3; \
- vbsl.64 RT7, rf, rg; \
- \
- vadd.u64 RT1, RT1, rh; \
- vshr.u64 RT2, ra, #28; \
- vshl.u64 RT3, ra, #64 - 28; \
- vadd.u64 RT1, RT1, RT0; \
- vshr.u64 RT4, ra, #34; \
- vshl.u64 RT5, ra, #64 - 34; \
- vadd.u64 RT1, RT1, RT7; \
- \
- /* h = Sum0 (a) + Maj (a, b, c); */ \
- veor.64 RT23q, RT23q, RT45q; \
- vshr.u64 RT4, ra, #39; \
- vshl.u64 RT5, ra, #64 - 39; \
- veor.64 RT0, ra, rb; \
- veor.64 RT23q, RT23q, RT45q; \
- vbsl.64 RT0, rc, rb; \
- vadd.u64 rd, rd, RT1; /* d+=t1; */ \
- veor.64 rh, RT2, RT3; \
- \
- /* t1 = g + Sum1 (d) + Ch (d, e, f) + k[t] + w[t]; */ \
- vshr.u64 RT2, rd, #14; \
- vshl.u64 RT3, rd, #64 - 14; \
- vadd.u64 rh, rh, RT0; \
- vshr.u64 RT4, rd, #18; \
- vshl.u64 RT5, rd, #64 - 18; \
- vadd.u64 rh, rh, RT1; /* h+=t1; */ \
- vld1.64 {RT0}, [RK]!; \
- veor.64 RT23q, RT23q, RT45q; \
- vshr.u64 RT4, rd, #41; \
- vshl.u64 RT5, rd, #64 - 41; \
- vadd.u64 RT0, RT0, rw1; \
- veor.64 RT23q, RT23q, RT45q; \
- vmov.64 RT7, rd; \
- veor.64 RT1, RT2, RT3; \
- vbsl.64 RT7, re, rf; \
- \
- vadd.u64 RT1, RT1, rg; \
- vshr.u64 RT2, rh, #28; \
- vshl.u64 RT3, rh, #64 - 28; \
- vadd.u64 RT1, RT1, RT0; \
- vshr.u64 RT4, rh, #34; \
- vshl.u64 RT5, rh, #64 - 34; \
- vadd.u64 RT1, RT1, RT7; \
- \
- /* g = Sum0 (h) + Maj (h, a, b); */ \
- veor.64 RT23q, RT23q, RT45q; \
- vshr.u64 RT4, rh, #39; \
- vshl.u64 RT5, rh, #64 - 39; \
- veor.64 RT0, rh, ra; \
- veor.64 RT23q, RT23q, RT45q; \
- vbsl.64 RT0, rb, ra; \
- vadd.u64 rc, rc, RT1; /* c+=t1; */ \
- veor.64 rg, RT2, RT3;
-#define vadd_rg_RT0(rg) \
- vadd.u64 rg, rg, RT0;
-#define vadd_rg_RT1(rg) \
- vadd.u64 rg, rg, RT1; /* g+=t1; */
-
-.align 3
-ENTRY(sha512_transform_neon)
- /* Input:
- * %r0: SHA512_CONTEXT
- * %r1: data
- * %r2: u64 k[] constants
- * %r3: nblks
- */
- push {%lr};
-
- mov %lr, #0;
-
- /* Load context to d0-d7 */
- vld1.64 {RA-RD}, [%r0]!;
- vld1.64 {RE-RH}, [%r0];
- sub %r0, #(4*8);
-
- /* Load input to w[16], d16-d31 */
- /* NOTE: Assumes that on ARMv7 unaligned accesses are always allowed. */
- vld1.64 {RW0-RW3}, [%r1]!;
- vld1.64 {RW4-RW7}, [%r1]!;
- vld1.64 {RW8-RW11}, [%r1]!;
- vld1.64 {RW12-RW15}, [%r1]!;
-#ifdef __ARMEL__
- /* byteswap */
- vrev64.8 RW01q, RW01q;
- vrev64.8 RW23q, RW23q;
- vrev64.8 RW45q, RW45q;
- vrev64.8 RW67q, RW67q;
- vrev64.8 RW89q, RW89q;
- vrev64.8 RW1011q, RW1011q;
- vrev64.8 RW1213q, RW1213q;
- vrev64.8 RW1415q, RW1415q;
-#endif
-
- /* EABI says that d8-d15 must be preserved by callee. */
- /*vpush {RT0-RT7};*/
-
-.Loop:
- rounds2_0_63(RA, RB, RC, RD, RE, RF, RG, RH, RW0, RW1, RW01q, RW2,
- RW23q, RW1415q, RW9, RW10, dummy, _);
- b .Lenter_rounds;
-
-.Loop_rounds:
- rounds2_0_63(RA, RB, RC, RD, RE, RF, RG, RH, RW0, RW1, RW01q, RW2,
- RW23q, RW1415q, RW9, RW10, vadd_RT01q, RW1415q);
-.Lenter_rounds:
- rounds2_0_63(RG, RH, RA, RB, RC, RD, RE, RF, RW2, RW3, RW23q, RW4,
- RW45q, RW01q, RW11, RW12, vadd_RT01q, RW01q);
- rounds2_0_63(RE, RF, RG, RH, RA, RB, RC, RD, RW4, RW5, RW45q, RW6,
- RW67q, RW23q, RW13, RW14, vadd_RT01q, RW23q);
- rounds2_0_63(RC, RD, RE, RF, RG, RH, RA, RB, RW6, RW7, RW67q, RW8,
- RW89q, RW45q, RW15, RW0, vadd_RT01q, RW45q);
- rounds2_0_63(RA, RB, RC, RD, RE, RF, RG, RH, RW8, RW9, RW89q, RW10,
- RW1011q, RW67q, RW1, RW2, vadd_RT01q, RW67q);
- rounds2_0_63(RG, RH, RA, RB, RC, RD, RE, RF, RW10, RW11, RW1011q, RW12,
- RW1213q, RW89q, RW3, RW4, vadd_RT01q, RW89q);
- add %lr, #16;
- rounds2_0_63(RE, RF, RG, RH, RA, RB, RC, RD, RW12, RW13, RW1213q, RW14,
- RW1415q, RW1011q, RW5, RW6, vadd_RT01q, RW1011q);
- cmp %lr, #64;
- rounds2_0_63(RC, RD, RE, RF, RG, RH, RA, RB, RW14, RW15, RW1415q, RW0,
- RW01q, RW1213q, RW7, RW8, vadd_RT01q, RW1213q);
- bne .Loop_rounds;
-
- subs %r3, #1;
-
- rounds2_64_79(RA, RB, RC, RD, RE, RF, RG, RH, RW0, RW1,
- vadd_RT01q, RW1415q, dummy, _);
- rounds2_64_79(RG, RH, RA, RB, RC, RD, RE, RF, RW2, RW3,
- vadd_rg_RT0, RG, vadd_rg_RT1, RG);
- beq .Lhandle_tail;
- vld1.64 {RW0-RW3}, [%r1]!;
- rounds2_64_79(RE, RF, RG, RH, RA, RB, RC, RD, RW4, RW5,
- vadd_rg_RT0, RE, vadd_rg_RT1, RE);
- rounds2_64_79(RC, RD, RE, RF, RG, RH, RA, RB, RW6, RW7,
- vadd_rg_RT0, RC, vadd_rg_RT1, RC);
-#ifdef __ARMEL__
- vrev64.8 RW01q, RW01q;
- vrev64.8 RW23q, RW23q;
-#endif
- vld1.64 {RW4-RW7}, [%r1]!;
- rounds2_64_79(RA, RB, RC, RD, RE, RF, RG, RH, RW8, RW9,
- vadd_rg_RT0, RA, vadd_rg_RT1, RA);
- rounds2_64_79(RG, RH, RA, RB, RC, RD, RE, RF, RW10, RW11,
- vadd_rg_RT0, RG, vadd_rg_RT1, RG);
-#ifdef __ARMEL__
- vrev64.8 RW45q, RW45q;
- vrev64.8 RW67q, RW67q;
-#endif
- vld1.64 {RW8-RW11}, [%r1]!;
- rounds2_64_79(RE, RF, RG, RH, RA, RB, RC, RD, RW12, RW13,
- vadd_rg_RT0, RE, vadd_rg_RT1, RE);
- rounds2_64_79(RC, RD, RE, RF, RG, RH, RA, RB, RW14, RW15,
- vadd_rg_RT0, RC, vadd_rg_RT1, RC);
-#ifdef __ARMEL__
- vrev64.8 RW89q, RW89q;
- vrev64.8 RW1011q, RW1011q;
-#endif
- vld1.64 {RW12-RW15}, [%r1]!;
- vadd_rg_RT0(RA);
- vadd_rg_RT1(RA);
-
- /* Load context */
- vld1.64 {RT0-RT3}, [%r0]!;
- vld1.64 {RT4-RT7}, [%r0];
- sub %r0, #(4*8);
-
-#ifdef __ARMEL__
- vrev64.8 RW1213q, RW1213q;
- vrev64.8 RW1415q, RW1415q;
-#endif
-
- vadd.u64 RA, RT0;
- vadd.u64 RB, RT1;
- vadd.u64 RC, RT2;
- vadd.u64 RD, RT3;
- vadd.u64 RE, RT4;
- vadd.u64 RF, RT5;
- vadd.u64 RG, RT6;
- vadd.u64 RH, RT7;
-
- /* Store the first half of context */
- vst1.64 {RA-RD}, [%r0]!;
- sub RK, $(8*80);
- vst1.64 {RE-RH}, [%r0]; /* Store the last half of context */
- mov %lr, #0;
- sub %r0, #(4*8);
-
- b .Loop;
-
-.Lhandle_tail:
- rounds2_64_79(RE, RF, RG, RH, RA, RB, RC, RD, RW4, RW5,
- vadd_rg_RT0, RE, vadd_rg_RT1, RE);
- rounds2_64_79(RC, RD, RE, RF, RG, RH, RA, RB, RW6, RW7,
- vadd_rg_RT0, RC, vadd_rg_RT1, RC);
- rounds2_64_79(RA, RB, RC, RD, RE, RF, RG, RH, RW8, RW9,
- vadd_rg_RT0, RA, vadd_rg_RT1, RA);
- rounds2_64_79(RG, RH, RA, RB, RC, RD, RE, RF, RW10, RW11,
- vadd_rg_RT0, RG, vadd_rg_RT1, RG);
- rounds2_64_79(RE, RF, RG, RH, RA, RB, RC, RD, RW12, RW13,
- vadd_rg_RT0, RE, vadd_rg_RT1, RE);
- rounds2_64_79(RC, RD, RE, RF, RG, RH, RA, RB, RW14, RW15,
- vadd_rg_RT0, RC, vadd_rg_RT1, RC);
-
- /* Load context to d16-d23 */
- vld1.64 {RW0-RW3}, [%r0]!;
- vadd_rg_RT0(RA);
- vld1.64 {RW4-RW7}, [%r0];
- vadd_rg_RT1(RA);
- sub %r0, #(4*8);
-
- vadd.u64 RA, RW0;
- vadd.u64 RB, RW1;
- vadd.u64 RC, RW2;
- vadd.u64 RD, RW3;
- vadd.u64 RE, RW4;
- vadd.u64 RF, RW5;
- vadd.u64 RG, RW6;
- vadd.u64 RH, RW7;
-
- /* Store the first half of context */
- vst1.64 {RA-RD}, [%r0]!;
-
- /* Clear used registers */
- /* d16-d31 */
- veor.u64 RW01q, RW01q;
- veor.u64 RW23q, RW23q;
- veor.u64 RW45q, RW45q;
- veor.u64 RW67q, RW67q;
- vst1.64 {RE-RH}, [%r0]; /* Store the last half of context */
- veor.u64 RW89q, RW89q;
- veor.u64 RW1011q, RW1011q;
- veor.u64 RW1213q, RW1213q;
- veor.u64 RW1415q, RW1415q;
- /* d8-d15 */
- /*vpop {RT0-RT7};*/
- /* d0-d7 (q0-q3) */
- veor.u64 %q0, %q0;
- veor.u64 %q1, %q1;
- veor.u64 %q2, %q2;
- veor.u64 %q3, %q3;
-
- pop {%pc};
-ENDPROC(sha512_transform_neon)
diff --git a/arch/arm/crypto/sha512-core.S_shipped b/arch/arm/crypto/sha512-core.S_shipped
new file mode 100644
index 000000000000..3694c4d4ca2b
--- /dev/null
+++ b/arch/arm/crypto/sha512-core.S_shipped
@@ -0,0 +1,1861 @@
+
+@ ====================================================================
+@ Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+@ project. The module is, however, dual licensed under OpenSSL and
+@ CRYPTOGAMS licenses depending on where you obtain it. For further
+@ details see http://www.openssl.org/~appro/cryptogams/.
+@
+@ Permission to use under GPL terms is granted.
+@ ====================================================================
+
+@ SHA512 block procedure for ARMv4. September 2007.
+
+@ This code is ~4.5 (four and a half) times faster than code generated
+@ by gcc 3.4 and it spends ~72 clock cycles per byte [on single-issue
+@ Xscale PXA250 core].
+@
+@ July 2010.
+@
+@ Rescheduling for dual-issue pipeline resulted in 6% improvement on
+@ Cortex A8 core and ~40 cycles per processed byte.
+
+@ February 2011.
+@
+@ Profiler-assisted and platform-specific optimization resulted in 7%
+@ improvement on Coxtex A8 core and ~38 cycles per byte.
+
+@ March 2011.
+@
+@ Add NEON implementation. On Cortex A8 it was measured to process
+@ one byte in 23.3 cycles or ~60% faster than integer-only code.
+
+@ August 2012.
+@
+@ Improve NEON performance by 12% on Snapdragon S4. In absolute
+@ terms it's 22.6 cycles per byte, which is disappointing result.
+@ Technical writers asserted that 3-way S4 pipeline can sustain
+@ multiple NEON instructions per cycle, but dual NEON issue could
+@ not be observed, see http://www.openssl.org/~appro/Snapdragon-S4.html
+@ for further details. On side note Cortex-A15 processes one byte in
+@ 16 cycles.
+
+@ Byte order [in]dependence. =========================================
+@
+@ Originally caller was expected to maintain specific *dword* order in
+@ h[0-7], namely with most significant dword at *lower* address, which
+@ was reflected in below two parameters as 0 and 4. Now caller is
+@ expected to maintain native byte order for whole 64-bit values.
+#ifndef __KERNEL__
+# include "arm_arch.h"
+# define VFP_ABI_PUSH vstmdb sp!,{d8-d15}
+# define VFP_ABI_POP vldmia sp!,{d8-d15}
+#else
+# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+# define __ARM_MAX_ARCH__ 7
+# define VFP_ABI_PUSH
+# define VFP_ABI_POP
+#endif
+
+#ifdef __ARMEL__
+# define LO 0
+# define HI 4
+# define WORD64(hi0,lo0,hi1,lo1) .word lo0,hi0, lo1,hi1
+#else
+# define HI 0
+# define LO 4
+# define WORD64(hi0,lo0,hi1,lo1) .word hi0,lo0, hi1,lo1
+#endif
+
+.text
+#if __ARM_ARCH__<7
+.code 32
+#else
+.syntax unified
+# ifdef __thumb2__
+# define adrl adr
+.thumb
+# else
+.code 32
+# endif
+#endif
+
+.type K512,%object
+.align 5
+K512:
+WORD64(0x428a2f98,0xd728ae22, 0x71374491,0x23ef65cd)
+WORD64(0xb5c0fbcf,0xec4d3b2f, 0xe9b5dba5,0x8189dbbc)
+WORD64(0x3956c25b,0xf348b538, 0x59f111f1,0xb605d019)
+WORD64(0x923f82a4,0xaf194f9b, 0xab1c5ed5,0xda6d8118)
+WORD64(0xd807aa98,0xa3030242, 0x12835b01,0x45706fbe)
+WORD64(0x243185be,0x4ee4b28c, 0x550c7dc3,0xd5ffb4e2)
+WORD64(0x72be5d74,0xf27b896f, 0x80deb1fe,0x3b1696b1)
+WORD64(0x9bdc06a7,0x25c71235, 0xc19bf174,0xcf692694)
+WORD64(0xe49b69c1,0x9ef14ad2, 0xefbe4786,0x384f25e3)
+WORD64(0x0fc19dc6,0x8b8cd5b5, 0x240ca1cc,0x77ac9c65)
+WORD64(0x2de92c6f,0x592b0275, 0x4a7484aa,0x6ea6e483)
+WORD64(0x5cb0a9dc,0xbd41fbd4, 0x76f988da,0x831153b5)
+WORD64(0x983e5152,0xee66dfab, 0xa831c66d,0x2db43210)
+WORD64(0xb00327c8,0x98fb213f, 0xbf597fc7,0xbeef0ee4)
+WORD64(0xc6e00bf3,0x3da88fc2, 0xd5a79147,0x930aa725)
+WORD64(0x06ca6351,0xe003826f, 0x14292967,0x0a0e6e70)
+WORD64(0x27b70a85,0x46d22ffc, 0x2e1b2138,0x5c26c926)
+WORD64(0x4d2c6dfc,0x5ac42aed, 0x53380d13,0x9d95b3df)
+WORD64(0x650a7354,0x8baf63de, 0x766a0abb,0x3c77b2a8)
+WORD64(0x81c2c92e,0x47edaee6, 0x92722c85,0x1482353b)
+WORD64(0xa2bfe8a1,0x4cf10364, 0xa81a664b,0xbc423001)
+WORD64(0xc24b8b70,0xd0f89791, 0xc76c51a3,0x0654be30)
+WORD64(0xd192e819,0xd6ef5218, 0xd6990624,0x5565a910)
+WORD64(0xf40e3585,0x5771202a, 0x106aa070,0x32bbd1b8)
+WORD64(0x19a4c116,0xb8d2d0c8, 0x1e376c08,0x5141ab53)
+WORD64(0x2748774c,0xdf8eeb99, 0x34b0bcb5,0xe19b48a8)
+WORD64(0x391c0cb3,0xc5c95a63, 0x4ed8aa4a,0xe3418acb)
+WORD64(0x5b9cca4f,0x7763e373, 0x682e6ff3,0xd6b2b8a3)
+WORD64(0x748f82ee,0x5defb2fc, 0x78a5636f,0x43172f60)
+WORD64(0x84c87814,0xa1f0ab72, 0x8cc70208,0x1a6439ec)
+WORD64(0x90befffa,0x23631e28, 0xa4506ceb,0xde82bde9)
+WORD64(0xbef9a3f7,0xb2c67915, 0xc67178f2,0xe372532b)
+WORD64(0xca273ece,0xea26619c, 0xd186b8c7,0x21c0c207)
+WORD64(0xeada7dd6,0xcde0eb1e, 0xf57d4f7f,0xee6ed178)
+WORD64(0x06f067aa,0x72176fba, 0x0a637dc5,0xa2c898a6)
+WORD64(0x113f9804,0xbef90dae, 0x1b710b35,0x131c471b)
+WORD64(0x28db77f5,0x23047d84, 0x32caab7b,0x40c72493)
+WORD64(0x3c9ebe0a,0x15c9bebc, 0x431d67c4,0x9c100d4c)
+WORD64(0x4cc5d4be,0xcb3e42b6, 0x597f299c,0xfc657e2a)
+WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817)
+.size K512,.-K512
+#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
+.LOPENSSL_armcap:
+.word OPENSSL_armcap_P-sha512_block_data_order
+.skip 32-4
+#else
+.skip 32
+#endif
+
+.global sha512_block_data_order
+.type sha512_block_data_order,%function
+sha512_block_data_order:
+#if __ARM_ARCH__<7
+ sub r3,pc,#8 @ sha512_block_data_order
+#else
+ adr r3,sha512_block_data_order
+#endif
+#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
+ ldr r12,.LOPENSSL_armcap
+ ldr r12,[r3,r12] @ OPENSSL_armcap_P
+ tst r12,#1
+ bne .LNEON
+#endif
+ add r2,r1,r2,lsl#7 @ len to point at the end of inp
+ stmdb sp!,{r4-r12,lr}
+ sub r14,r3,#672 @ K512
+ sub sp,sp,#9*8
+
+ ldr r7,[r0,#32+LO]
+ ldr r8,[r0,#32+HI]
+ ldr r9, [r0,#48+LO]
+ ldr r10, [r0,#48+HI]
+ ldr r11, [r0,#56+LO]
+ ldr r12, [r0,#56+HI]
+.Loop:
+ str r9, [sp,#48+0]
+ str r10, [sp,#48+4]
+ str r11, [sp,#56+0]
+ str r12, [sp,#56+4]
+ ldr r5,[r0,#0+LO]
+ ldr r6,[r0,#0+HI]
+ ldr r3,[r0,#8+LO]
+ ldr r4,[r0,#8+HI]
+ ldr r9, [r0,#16+LO]
+ ldr r10, [r0,#16+HI]
+ ldr r11, [r0,#24+LO]
+ ldr r12, [r0,#24+HI]
+ str r3,[sp,#8+0]
+ str r4,[sp,#8+4]
+ str r9, [sp,#16+0]
+ str r10, [sp,#16+4]
+ str r11, [sp,#24+0]
+ str r12, [sp,#24+4]
+ ldr r3,[r0,#40+LO]
+ ldr r4,[r0,#40+HI]
+ str r3,[sp,#40+0]
+ str r4,[sp,#40+4]
+
+.L00_15:
+#if __ARM_ARCH__<7
+ ldrb r3,[r1,#7]
+ ldrb r9, [r1,#6]
+ ldrb r10, [r1,#5]
+ ldrb r11, [r1,#4]
+ ldrb r4,[r1,#3]
+ ldrb r12, [r1,#2]
+ orr r3,r3,r9,lsl#8
+ ldrb r9, [r1,#1]
+ orr r3,r3,r10,lsl#16
+ ldrb r10, [r1],#8
+ orr r3,r3,r11,lsl#24
+ orr r4,r4,r12,lsl#8
+ orr r4,r4,r9,lsl#16
+ orr r4,r4,r10,lsl#24
+#else
+ ldr r3,[r1,#4]
+ ldr r4,[r1],#8
+#ifdef __ARMEL__
+ rev r3,r3
+ rev r4,r4
+#endif
+#endif
+ @ Sigma1(x) (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41))
+ @ LO lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23
+ @ HI hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23
+ mov r9,r7,lsr#14
+ str r3,[sp,#64+0]
+ mov r10,r8,lsr#14
+ str r4,[sp,#64+4]
+ eor r9,r9,r8,lsl#18
+ ldr r11,[sp,#56+0] @ h.lo
+ eor r10,r10,r7,lsl#18
+ ldr r12,[sp,#56+4] @ h.hi
+ eor r9,r9,r7,lsr#18
+ eor r10,r10,r8,lsr#18
+ eor r9,r9,r8,lsl#14
+ eor r10,r10,r7,lsl#14
+ eor r9,r9,r8,lsr#9
+ eor r10,r10,r7,lsr#9
+ eor r9,r9,r7,lsl#23
+ eor r10,r10,r8,lsl#23 @ Sigma1(e)
+ adds r3,r3,r9
+ ldr r9,[sp,#40+0] @ f.lo
+ adc r4,r4,r10 @ T += Sigma1(e)
+ ldr r10,[sp,#40+4] @ f.hi
+ adds r3,r3,r11
+ ldr r11,[sp,#48+0] @ g.lo
+ adc r4,r4,r12 @ T += h
+ ldr r12,[sp,#48+4] @ g.hi
+
+ eor r9,r9,r11
+ str r7,[sp,#32+0]
+ eor r10,r10,r12
+ str r8,[sp,#32+4]
+ and r9,r9,r7
+ str r5,[sp,#0+0]
+ and r10,r10,r8
+ str r6,[sp,#0+4]
+ eor r9,r9,r11
+ ldr r11,[r14,#LO] @ K[i].lo
+ eor r10,r10,r12 @ Ch(e,f,g)
+ ldr r12,[r14,#HI] @ K[i].hi
+
+ adds r3,r3,r9
+ ldr r7,[sp,#24+0] @ d.lo
+ adc r4,r4,r10 @ T += Ch(e,f,g)
+ ldr r8,[sp,#24+4] @ d.hi
+ adds r3,r3,r11
+ and r9,r11,#0xff
+ adc r4,r4,r12 @ T += K[i]
+ adds r7,r7,r3
+ ldr r11,[sp,#8+0] @ b.lo
+ adc r8,r8,r4 @ d += T
+ teq r9,#148
+
+ ldr r12,[sp,#16+0] @ c.lo
+#if __ARM_ARCH__>=7
+ it eq @ Thumb2 thing, sanity check in ARM
+#endif
+ orreq r14,r14,#1
+ @ Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39))
+ @ LO lo>>28^hi<<4 ^ hi>>2^lo<<30 ^ hi>>7^lo<<25
+ @ HI hi>>28^lo<<4 ^ lo>>2^hi<<30 ^ lo>>7^hi<<25
+ mov r9,r5,lsr#28
+ mov r10,r6,lsr#28
+ eor r9,r9,r6,lsl#4
+ eor r10,r10,r5,lsl#4
+ eor r9,r9,r6,lsr#2
+ eor r10,r10,r5,lsr#2
+ eor r9,r9,r5,lsl#30
+ eor r10,r10,r6,lsl#30
+ eor r9,r9,r6,lsr#7
+ eor r10,r10,r5,lsr#7
+ eor r9,r9,r5,lsl#25
+ eor r10,r10,r6,lsl#25 @ Sigma0(a)
+ adds r3,r3,r9
+ and r9,r5,r11
+ adc r4,r4,r10 @ T += Sigma0(a)
+
+ ldr r10,[sp,#8+4] @ b.hi
+ orr r5,r5,r11
+ ldr r11,[sp,#16+4] @ c.hi
+ and r5,r5,r12
+ and r12,r6,r10
+ orr r6,r6,r10
+ orr r5,r5,r9 @ Maj(a,b,c).lo
+ and r6,r6,r11
+ adds r5,r5,r3
+ orr r6,r6,r12 @ Maj(a,b,c).hi
+ sub sp,sp,#8
+ adc r6,r6,r4 @ h += T
+ tst r14,#1
+ add r14,r14,#8
+ tst r14,#1
+ beq .L00_15
+ ldr r9,[sp,#184+0]
+ ldr r10,[sp,#184+4]
+ bic r14,r14,#1
+.L16_79:
+ @ sigma0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7))
+ @ LO lo>>1^hi<<31 ^ lo>>8^hi<<24 ^ lo>>7^hi<<25
+ @ HI hi>>1^lo<<31 ^ hi>>8^lo<<24 ^ hi>>7
+ mov r3,r9,lsr#1
+ ldr r11,[sp,#80+0]
+ mov r4,r10,lsr#1
+ ldr r12,[sp,#80+4]
+ eor r3,r3,r10,lsl#31
+ eor r4,r4,r9,lsl#31
+ eor r3,r3,r9,lsr#8
+ eor r4,r4,r10,lsr#8
+ eor r3,r3,r10,lsl#24
+ eor r4,r4,r9,lsl#24
+ eor r3,r3,r9,lsr#7
+ eor r4,r4,r10,lsr#7
+ eor r3,r3,r10,lsl#25
+
+ @ sigma1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6))
+ @ LO lo>>19^hi<<13 ^ hi>>29^lo<<3 ^ lo>>6^hi<<26
+ @ HI hi>>19^lo<<13 ^ lo>>29^hi<<3 ^ hi>>6
+ mov r9,r11,lsr#19
+ mov r10,r12,lsr#19
+ eor r9,r9,r12,lsl#13
+ eor r10,r10,r11,lsl#13
+ eor r9,r9,r12,lsr#29
+ eor r10,r10,r11,lsr#29
+ eor r9,r9,r11,lsl#3
+ eor r10,r10,r12,lsl#3
+ eor r9,r9,r11,lsr#6
+ eor r10,r10,r12,lsr#6
+ ldr r11,[sp,#120+0]
+ eor r9,r9,r12,lsl#26
+
+ ldr r12,[sp,#120+4]
+ adds r3,r3,r9
+ ldr r9,[sp,#192+0]
+ adc r4,r4,r10
+
+ ldr r10,[sp,#192+4]
+ adds r3,r3,r11
+ adc r4,r4,r12
+ adds r3,r3,r9
+ adc r4,r4,r10
+ @ Sigma1(x) (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41))
+ @ LO lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23
+ @ HI hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23
+ mov r9,r7,lsr#14
+ str r3,[sp,#64+0]
+ mov r10,r8,lsr#14
+ str r4,[sp,#64+4]
+ eor r9,r9,r8,lsl#18
+ ldr r11,[sp,#56+0] @ h.lo
+ eor r10,r10,r7,lsl#18
+ ldr r12,[sp,#56+4] @ h.hi
+ eor r9,r9,r7,lsr#18
+ eor r10,r10,r8,lsr#18
+ eor r9,r9,r8,lsl#14
+ eor r10,r10,r7,lsl#14
+ eor r9,r9,r8,lsr#9
+ eor r10,r10,r7,lsr#9
+ eor r9,r9,r7,lsl#23
+ eor r10,r10,r8,lsl#23 @ Sigma1(e)
+ adds r3,r3,r9
+ ldr r9,[sp,#40+0] @ f.lo
+ adc r4,r4,r10 @ T += Sigma1(e)
+ ldr r10,[sp,#40+4] @ f.hi
+ adds r3,r3,r11
+ ldr r11,[sp,#48+0] @ g.lo
+ adc r4,r4,r12 @ T += h
+ ldr r12,[sp,#48+4] @ g.hi
+
+ eor r9,r9,r11
+ str r7,[sp,#32+0]
+ eor r10,r10,r12
+ str r8,[sp,#32+4]
+ and r9,r9,r7
+ str r5,[sp,#0+0]
+ and r10,r10,r8
+ str r6,[sp,#0+4]
+ eor r9,r9,r11
+ ldr r11,[r14,#LO] @ K[i].lo
+ eor r10,r10,r12 @ Ch(e,f,g)
+ ldr r12,[r14,#HI] @ K[i].hi
+
+ adds r3,r3,r9
+ ldr r7,[sp,#24+0] @ d.lo
+ adc r4,r4,r10 @ T += Ch(e,f,g)
+ ldr r8,[sp,#24+4] @ d.hi
+ adds r3,r3,r11
+ and r9,r11,#0xff
+ adc r4,r4,r12 @ T += K[i]
+ adds r7,r7,r3
+ ldr r11,[sp,#8+0] @ b.lo
+ adc r8,r8,r4 @ d += T
+ teq r9,#23
+
+ ldr r12,[sp,#16+0] @ c.lo
+#if __ARM_ARCH__>=7
+ it eq @ Thumb2 thing, sanity check in ARM
+#endif
+ orreq r14,r14,#1
+ @ Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39))
+ @ LO lo>>28^hi<<4 ^ hi>>2^lo<<30 ^ hi>>7^lo<<25
+ @ HI hi>>28^lo<<4 ^ lo>>2^hi<<30 ^ lo>>7^hi<<25
+ mov r9,r5,lsr#28
+ mov r10,r6,lsr#28
+ eor r9,r9,r6,lsl#4
+ eor r10,r10,r5,lsl#4
+ eor r9,r9,r6,lsr#2
+ eor r10,r10,r5,lsr#2
+ eor r9,r9,r5,lsl#30
+ eor r10,r10,r6,lsl#30
+ eor r9,r9,r6,lsr#7
+ eor r10,r10,r5,lsr#7
+ eor r9,r9,r5,lsl#25
+ eor r10,r10,r6,lsl#25 @ Sigma0(a)
+ adds r3,r3,r9
+ and r9,r5,r11
+ adc r4,r4,r10 @ T += Sigma0(a)
+
+ ldr r10,[sp,#8+4] @ b.hi
+ orr r5,r5,r11
+ ldr r11,[sp,#16+4] @ c.hi
+ and r5,r5,r12
+ and r12,r6,r10
+ orr r6,r6,r10
+ orr r5,r5,r9 @ Maj(a,b,c).lo
+ and r6,r6,r11
+ adds r5,r5,r3
+ orr r6,r6,r12 @ Maj(a,b,c).hi
+ sub sp,sp,#8
+ adc r6,r6,r4 @ h += T
+ tst r14,#1
+ add r14,r14,#8
+#if __ARM_ARCH__>=7
+ ittt eq @ Thumb2 thing, sanity check in ARM
+#endif
+ ldreq r9,[sp,#184+0]
+ ldreq r10,[sp,#184+4]
+ beq .L16_79
+ bic r14,r14,#1
+
+ ldr r3,[sp,#8+0]
+ ldr r4,[sp,#8+4]
+ ldr r9, [r0,#0+LO]
+ ldr r10, [r0,#0+HI]
+ ldr r11, [r0,#8+LO]
+ ldr r12, [r0,#8+HI]
+ adds r9,r5,r9
+ str r9, [r0,#0+LO]
+ adc r10,r6,r10
+ str r10, [r0,#0+HI]
+ adds r11,r3,r11
+ str r11, [r0,#8+LO]
+ adc r12,r4,r12
+ str r12, [r0,#8+HI]
+
+ ldr r5,[sp,#16+0]
+ ldr r6,[sp,#16+4]
+ ldr r3,[sp,#24+0]
+ ldr r4,[sp,#24+4]
+ ldr r9, [r0,#16+LO]
+ ldr r10, [r0,#16+HI]
+ ldr r11, [r0,#24+LO]
+ ldr r12, [r0,#24+HI]
+ adds r9,r5,r9
+ str r9, [r0,#16+LO]
+ adc r10,r6,r10
+ str r10, [r0,#16+HI]
+ adds r11,r3,r11
+ str r11, [r0,#24+LO]
+ adc r12,r4,r12
+ str r12, [r0,#24+HI]
+
+ ldr r3,[sp,#40+0]
+ ldr r4,[sp,#40+4]
+ ldr r9, [r0,#32+LO]
+ ldr r10, [r0,#32+HI]
+ ldr r11, [r0,#40+LO]
+ ldr r12, [r0,#40+HI]
+ adds r7,r7,r9
+ str r7,[r0,#32+LO]
+ adc r8,r8,r10
+ str r8,[r0,#32+HI]
+ adds r11,r3,r11
+ str r11, [r0,#40+LO]
+ adc r12,r4,r12
+ str r12, [r0,#40+HI]
+
+ ldr r5,[sp,#48+0]
+ ldr r6,[sp,#48+4]
+ ldr r3,[sp,#56+0]
+ ldr r4,[sp,#56+4]
+ ldr r9, [r0,#48+LO]
+ ldr r10, [r0,#48+HI]
+ ldr r11, [r0,#56+LO]
+ ldr r12, [r0,#56+HI]
+ adds r9,r5,r9
+ str r9, [r0,#48+LO]
+ adc r10,r6,r10
+ str r10, [r0,#48+HI]
+ adds r11,r3,r11
+ str r11, [r0,#56+LO]
+ adc r12,r4,r12
+ str r12, [r0,#56+HI]
+
+ add sp,sp,#640
+ sub r14,r14,#640
+
+ teq r1,r2
+ bne .Loop
+
+ add sp,sp,#8*9 @ destroy frame
+#if __ARM_ARCH__>=5
+ ldmia sp!,{r4-r12,pc}
+#else
+ ldmia sp!,{r4-r12,lr}
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ .word 0xe12fff1e @ interoperable with Thumb ISA:-)
+#endif
+.size sha512_block_data_order,.-sha512_block_data_order
+#if __ARM_MAX_ARCH__>=7
+.arch armv7-a
+.fpu neon
+
+.global sha512_block_data_order_neon
+.type sha512_block_data_order_neon,%function
+.align 4
+sha512_block_data_order_neon:
+.LNEON:
+ dmb @ errata #451034 on early Cortex A8
+ add r2,r1,r2,lsl#7 @ len to point at the end of inp
+ VFP_ABI_PUSH
+ adrl r3,K512
+ vldmia r0,{d16-d23} @ load context
+.Loop_neon:
+ vshr.u64 d24,d20,#14 @ 0
+#if 0<16
+ vld1.64 {d0},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d20,#18
+#if 0>0
+ vadd.i64 d16,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d20,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d20,#50
+ vsli.64 d25,d20,#46
+ vmov d29,d20
+ vsli.64 d26,d20,#23
+#if 0<16 && defined(__ARMEL__)
+ vrev64.8 d0,d0
+#endif
+ veor d25,d24
+ vbsl d29,d21,d22 @ Ch(e,f,g)
+ vshr.u64 d24,d16,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d23
+ vshr.u64 d25,d16,#34
+ vsli.64 d24,d16,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d16,#39
+ vadd.i64 d28,d0
+ vsli.64 d25,d16,#30
+ veor d30,d16,d17
+ vsli.64 d26,d16,#25
+ veor d23,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d18,d17 @ Maj(a,b,c)
+ veor d23,d26 @ Sigma0(a)
+ vadd.i64 d19,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d23,d30
+ vshr.u64 d24,d19,#14 @ 1
+#if 1<16
+ vld1.64 {d1},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d19,#18
+#if 1>0
+ vadd.i64 d23,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d19,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d19,#50
+ vsli.64 d25,d19,#46
+ vmov d29,d19
+ vsli.64 d26,d19,#23
+#if 1<16 && defined(__ARMEL__)
+ vrev64.8 d1,d1
+#endif
+ veor d25,d24
+ vbsl d29,d20,d21 @ Ch(e,f,g)
+ vshr.u64 d24,d23,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d22
+ vshr.u64 d25,d23,#34
+ vsli.64 d24,d23,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d23,#39
+ vadd.i64 d28,d1
+ vsli.64 d25,d23,#30
+ veor d30,d23,d16
+ vsli.64 d26,d23,#25
+ veor d22,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d17,d16 @ Maj(a,b,c)
+ veor d22,d26 @ Sigma0(a)
+ vadd.i64 d18,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d22,d30
+ vshr.u64 d24,d18,#14 @ 2
+#if 2<16
+ vld1.64 {d2},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d18,#18
+#if 2>0
+ vadd.i64 d22,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d18,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d18,#50
+ vsli.64 d25,d18,#46
+ vmov d29,d18
+ vsli.64 d26,d18,#23
+#if 2<16 && defined(__ARMEL__)
+ vrev64.8 d2,d2
+#endif
+ veor d25,d24
+ vbsl d29,d19,d20 @ Ch(e,f,g)
+ vshr.u64 d24,d22,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d21
+ vshr.u64 d25,d22,#34
+ vsli.64 d24,d22,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d22,#39
+ vadd.i64 d28,d2
+ vsli.64 d25,d22,#30
+ veor d30,d22,d23
+ vsli.64 d26,d22,#25
+ veor d21,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d16,d23 @ Maj(a,b,c)
+ veor d21,d26 @ Sigma0(a)
+ vadd.i64 d17,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d21,d30
+ vshr.u64 d24,d17,#14 @ 3
+#if 3<16
+ vld1.64 {d3},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d17,#18
+#if 3>0
+ vadd.i64 d21,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d17,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d17,#50
+ vsli.64 d25,d17,#46
+ vmov d29,d17
+ vsli.64 d26,d17,#23
+#if 3<16 && defined(__ARMEL__)
+ vrev64.8 d3,d3
+#endif
+ veor d25,d24
+ vbsl d29,d18,d19 @ Ch(e,f,g)
+ vshr.u64 d24,d21,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d20
+ vshr.u64 d25,d21,#34
+ vsli.64 d24,d21,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d21,#39
+ vadd.i64 d28,d3
+ vsli.64 d25,d21,#30
+ veor d30,d21,d22
+ vsli.64 d26,d21,#25
+ veor d20,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d23,d22 @ Maj(a,b,c)
+ veor d20,d26 @ Sigma0(a)
+ vadd.i64 d16,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d20,d30
+ vshr.u64 d24,d16,#14 @ 4
+#if 4<16
+ vld1.64 {d4},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d16,#18
+#if 4>0
+ vadd.i64 d20,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d16,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d16,#50
+ vsli.64 d25,d16,#46
+ vmov d29,d16
+ vsli.64 d26,d16,#23
+#if 4<16 && defined(__ARMEL__)
+ vrev64.8 d4,d4
+#endif
+ veor d25,d24
+ vbsl d29,d17,d18 @ Ch(e,f,g)
+ vshr.u64 d24,d20,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d19
+ vshr.u64 d25,d20,#34
+ vsli.64 d24,d20,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d20,#39
+ vadd.i64 d28,d4
+ vsli.64 d25,d20,#30
+ veor d30,d20,d21
+ vsli.64 d26,d20,#25
+ veor d19,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d22,d21 @ Maj(a,b,c)
+ veor d19,d26 @ Sigma0(a)
+ vadd.i64 d23,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d19,d30
+ vshr.u64 d24,d23,#14 @ 5
+#if 5<16
+ vld1.64 {d5},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d23,#18
+#if 5>0
+ vadd.i64 d19,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d23,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d23,#50
+ vsli.64 d25,d23,#46
+ vmov d29,d23
+ vsli.64 d26,d23,#23
+#if 5<16 && defined(__ARMEL__)
+ vrev64.8 d5,d5
+#endif
+ veor d25,d24
+ vbsl d29,d16,d17 @ Ch(e,f,g)
+ vshr.u64 d24,d19,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d18
+ vshr.u64 d25,d19,#34
+ vsli.64 d24,d19,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d19,#39
+ vadd.i64 d28,d5
+ vsli.64 d25,d19,#30
+ veor d30,d19,d20
+ vsli.64 d26,d19,#25
+ veor d18,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d21,d20 @ Maj(a,b,c)
+ veor d18,d26 @ Sigma0(a)
+ vadd.i64 d22,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d18,d30
+ vshr.u64 d24,d22,#14 @ 6
+#if 6<16
+ vld1.64 {d6},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d22,#18
+#if 6>0
+ vadd.i64 d18,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d22,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d22,#50
+ vsli.64 d25,d22,#46
+ vmov d29,d22
+ vsli.64 d26,d22,#23
+#if 6<16 && defined(__ARMEL__)
+ vrev64.8 d6,d6
+#endif
+ veor d25,d24
+ vbsl d29,d23,d16 @ Ch(e,f,g)
+ vshr.u64 d24,d18,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d17
+ vshr.u64 d25,d18,#34
+ vsli.64 d24,d18,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d18,#39
+ vadd.i64 d28,d6
+ vsli.64 d25,d18,#30
+ veor d30,d18,d19
+ vsli.64 d26,d18,#25
+ veor d17,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d20,d19 @ Maj(a,b,c)
+ veor d17,d26 @ Sigma0(a)
+ vadd.i64 d21,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d17,d30
+ vshr.u64 d24,d21,#14 @ 7
+#if 7<16
+ vld1.64 {d7},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d21,#18
+#if 7>0
+ vadd.i64 d17,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d21,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d21,#50
+ vsli.64 d25,d21,#46
+ vmov d29,d21
+ vsli.64 d26,d21,#23
+#if 7<16 && defined(__ARMEL__)
+ vrev64.8 d7,d7
+#endif
+ veor d25,d24
+ vbsl d29,d22,d23 @ Ch(e,f,g)
+ vshr.u64 d24,d17,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d16
+ vshr.u64 d25,d17,#34
+ vsli.64 d24,d17,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d17,#39
+ vadd.i64 d28,d7
+ vsli.64 d25,d17,#30
+ veor d30,d17,d18
+ vsli.64 d26,d17,#25
+ veor d16,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d19,d18 @ Maj(a,b,c)
+ veor d16,d26 @ Sigma0(a)
+ vadd.i64 d20,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d16,d30
+ vshr.u64 d24,d20,#14 @ 8
+#if 8<16
+ vld1.64 {d8},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d20,#18
+#if 8>0
+ vadd.i64 d16,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d20,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d20,#50
+ vsli.64 d25,d20,#46
+ vmov d29,d20
+ vsli.64 d26,d20,#23
+#if 8<16 && defined(__ARMEL__)
+ vrev64.8 d8,d8
+#endif
+ veor d25,d24
+ vbsl d29,d21,d22 @ Ch(e,f,g)
+ vshr.u64 d24,d16,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d23
+ vshr.u64 d25,d16,#34
+ vsli.64 d24,d16,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d16,#39
+ vadd.i64 d28,d8
+ vsli.64 d25,d16,#30
+ veor d30,d16,d17
+ vsli.64 d26,d16,#25
+ veor d23,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d18,d17 @ Maj(a,b,c)
+ veor d23,d26 @ Sigma0(a)
+ vadd.i64 d19,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d23,d30
+ vshr.u64 d24,d19,#14 @ 9
+#if 9<16
+ vld1.64 {d9},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d19,#18
+#if 9>0
+ vadd.i64 d23,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d19,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d19,#50
+ vsli.64 d25,d19,#46
+ vmov d29,d19
+ vsli.64 d26,d19,#23
+#if 9<16 && defined(__ARMEL__)
+ vrev64.8 d9,d9
+#endif
+ veor d25,d24
+ vbsl d29,d20,d21 @ Ch(e,f,g)
+ vshr.u64 d24,d23,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d22
+ vshr.u64 d25,d23,#34
+ vsli.64 d24,d23,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d23,#39
+ vadd.i64 d28,d9
+ vsli.64 d25,d23,#30
+ veor d30,d23,d16
+ vsli.64 d26,d23,#25
+ veor d22,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d17,d16 @ Maj(a,b,c)
+ veor d22,d26 @ Sigma0(a)
+ vadd.i64 d18,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d22,d30
+ vshr.u64 d24,d18,#14 @ 10
+#if 10<16
+ vld1.64 {d10},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d18,#18
+#if 10>0
+ vadd.i64 d22,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d18,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d18,#50
+ vsli.64 d25,d18,#46
+ vmov d29,d18
+ vsli.64 d26,d18,#23
+#if 10<16 && defined(__ARMEL__)
+ vrev64.8 d10,d10
+#endif
+ veor d25,d24
+ vbsl d29,d19,d20 @ Ch(e,f,g)
+ vshr.u64 d24,d22,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d21
+ vshr.u64 d25,d22,#34
+ vsli.64 d24,d22,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d22,#39
+ vadd.i64 d28,d10
+ vsli.64 d25,d22,#30
+ veor d30,d22,d23
+ vsli.64 d26,d22,#25
+ veor d21,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d16,d23 @ Maj(a,b,c)
+ veor d21,d26 @ Sigma0(a)
+ vadd.i64 d17,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d21,d30
+ vshr.u64 d24,d17,#14 @ 11
+#if 11<16
+ vld1.64 {d11},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d17,#18
+#if 11>0
+ vadd.i64 d21,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d17,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d17,#50
+ vsli.64 d25,d17,#46
+ vmov d29,d17
+ vsli.64 d26,d17,#23
+#if 11<16 && defined(__ARMEL__)
+ vrev64.8 d11,d11
+#endif
+ veor d25,d24
+ vbsl d29,d18,d19 @ Ch(e,f,g)
+ vshr.u64 d24,d21,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d20
+ vshr.u64 d25,d21,#34
+ vsli.64 d24,d21,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d21,#39
+ vadd.i64 d28,d11
+ vsli.64 d25,d21,#30
+ veor d30,d21,d22
+ vsli.64 d26,d21,#25
+ veor d20,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d23,d22 @ Maj(a,b,c)
+ veor d20,d26 @ Sigma0(a)
+ vadd.i64 d16,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d20,d30
+ vshr.u64 d24,d16,#14 @ 12
+#if 12<16
+ vld1.64 {d12},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d16,#18
+#if 12>0
+ vadd.i64 d20,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d16,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d16,#50
+ vsli.64 d25,d16,#46
+ vmov d29,d16
+ vsli.64 d26,d16,#23
+#if 12<16 && defined(__ARMEL__)
+ vrev64.8 d12,d12
+#endif
+ veor d25,d24
+ vbsl d29,d17,d18 @ Ch(e,f,g)
+ vshr.u64 d24,d20,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d19
+ vshr.u64 d25,d20,#34
+ vsli.64 d24,d20,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d20,#39
+ vadd.i64 d28,d12
+ vsli.64 d25,d20,#30
+ veor d30,d20,d21
+ vsli.64 d26,d20,#25
+ veor d19,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d22,d21 @ Maj(a,b,c)
+ veor d19,d26 @ Sigma0(a)
+ vadd.i64 d23,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d19,d30
+ vshr.u64 d24,d23,#14 @ 13
+#if 13<16
+ vld1.64 {d13},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d23,#18
+#if 13>0
+ vadd.i64 d19,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d23,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d23,#50
+ vsli.64 d25,d23,#46
+ vmov d29,d23
+ vsli.64 d26,d23,#23
+#if 13<16 && defined(__ARMEL__)
+ vrev64.8 d13,d13
+#endif
+ veor d25,d24
+ vbsl d29,d16,d17 @ Ch(e,f,g)
+ vshr.u64 d24,d19,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d18
+ vshr.u64 d25,d19,#34
+ vsli.64 d24,d19,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d19,#39
+ vadd.i64 d28,d13
+ vsli.64 d25,d19,#30
+ veor d30,d19,d20
+ vsli.64 d26,d19,#25
+ veor d18,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d21,d20 @ Maj(a,b,c)
+ veor d18,d26 @ Sigma0(a)
+ vadd.i64 d22,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d18,d30
+ vshr.u64 d24,d22,#14 @ 14
+#if 14<16
+ vld1.64 {d14},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d22,#18
+#if 14>0
+ vadd.i64 d18,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d22,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d22,#50
+ vsli.64 d25,d22,#46
+ vmov d29,d22
+ vsli.64 d26,d22,#23
+#if 14<16 && defined(__ARMEL__)
+ vrev64.8 d14,d14
+#endif
+ veor d25,d24
+ vbsl d29,d23,d16 @ Ch(e,f,g)
+ vshr.u64 d24,d18,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d17
+ vshr.u64 d25,d18,#34
+ vsli.64 d24,d18,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d18,#39
+ vadd.i64 d28,d14
+ vsli.64 d25,d18,#30
+ veor d30,d18,d19
+ vsli.64 d26,d18,#25
+ veor d17,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d20,d19 @ Maj(a,b,c)
+ veor d17,d26 @ Sigma0(a)
+ vadd.i64 d21,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d17,d30
+ vshr.u64 d24,d21,#14 @ 15
+#if 15<16
+ vld1.64 {d15},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d21,#18
+#if 15>0
+ vadd.i64 d17,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d21,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d21,#50
+ vsli.64 d25,d21,#46
+ vmov d29,d21
+ vsli.64 d26,d21,#23
+#if 15<16 && defined(__ARMEL__)
+ vrev64.8 d15,d15
+#endif
+ veor d25,d24
+ vbsl d29,d22,d23 @ Ch(e,f,g)
+ vshr.u64 d24,d17,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d16
+ vshr.u64 d25,d17,#34
+ vsli.64 d24,d17,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d17,#39
+ vadd.i64 d28,d15
+ vsli.64 d25,d17,#30
+ veor d30,d17,d18
+ vsli.64 d26,d17,#25
+ veor d16,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d19,d18 @ Maj(a,b,c)
+ veor d16,d26 @ Sigma0(a)
+ vadd.i64 d20,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d16,d30
+ mov r12,#4
+.L16_79_neon:
+ subs r12,#1
+ vshr.u64 q12,q7,#19
+ vshr.u64 q13,q7,#61
+ vadd.i64 d16,d30 @ h+=Maj from the past
+ vshr.u64 q15,q7,#6
+ vsli.64 q12,q7,#45
+ vext.8 q14,q0,q1,#8 @ X[i+1]
+ vsli.64 q13,q7,#3
+ veor q15,q12
+ vshr.u64 q12,q14,#1
+ veor q15,q13 @ sigma1(X[i+14])
+ vshr.u64 q13,q14,#8
+ vadd.i64 q0,q15
+ vshr.u64 q15,q14,#7
+ vsli.64 q12,q14,#63
+ vsli.64 q13,q14,#56
+ vext.8 q14,q4,q5,#8 @ X[i+9]
+ veor q15,q12
+ vshr.u64 d24,d20,#14 @ from NEON_00_15
+ vadd.i64 q0,q14
+ vshr.u64 d25,d20,#18 @ from NEON_00_15
+ veor q15,q13 @ sigma0(X[i+1])
+ vshr.u64 d26,d20,#41 @ from NEON_00_15
+ vadd.i64 q0,q15
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d20,#50
+ vsli.64 d25,d20,#46
+ vmov d29,d20
+ vsli.64 d26,d20,#23
+#if 16<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d21,d22 @ Ch(e,f,g)
+ vshr.u64 d24,d16,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d23
+ vshr.u64 d25,d16,#34
+ vsli.64 d24,d16,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d16,#39
+ vadd.i64 d28,d0
+ vsli.64 d25,d16,#30
+ veor d30,d16,d17
+ vsli.64 d26,d16,#25
+ veor d23,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d18,d17 @ Maj(a,b,c)
+ veor d23,d26 @ Sigma0(a)
+ vadd.i64 d19,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d23,d30
+ vshr.u64 d24,d19,#14 @ 17
+#if 17<16
+ vld1.64 {d1},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d19,#18
+#if 17>0
+ vadd.i64 d23,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d19,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d19,#50
+ vsli.64 d25,d19,#46
+ vmov d29,d19
+ vsli.64 d26,d19,#23
+#if 17<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d20,d21 @ Ch(e,f,g)
+ vshr.u64 d24,d23,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d22
+ vshr.u64 d25,d23,#34
+ vsli.64 d24,d23,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d23,#39
+ vadd.i64 d28,d1
+ vsli.64 d25,d23,#30
+ veor d30,d23,d16
+ vsli.64 d26,d23,#25
+ veor d22,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d17,d16 @ Maj(a,b,c)
+ veor d22,d26 @ Sigma0(a)
+ vadd.i64 d18,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d22,d30
+ vshr.u64 q12,q0,#19
+ vshr.u64 q13,q0,#61
+ vadd.i64 d22,d30 @ h+=Maj from the past
+ vshr.u64 q15,q0,#6
+ vsli.64 q12,q0,#45
+ vext.8 q14,q1,q2,#8 @ X[i+1]
+ vsli.64 q13,q0,#3
+ veor q15,q12
+ vshr.u64 q12,q14,#1
+ veor q15,q13 @ sigma1(X[i+14])
+ vshr.u64 q13,q14,#8
+ vadd.i64 q1,q15
+ vshr.u64 q15,q14,#7
+ vsli.64 q12,q14,#63
+ vsli.64 q13,q14,#56
+ vext.8 q14,q5,q6,#8 @ X[i+9]
+ veor q15,q12
+ vshr.u64 d24,d18,#14 @ from NEON_00_15
+ vadd.i64 q1,q14
+ vshr.u64 d25,d18,#18 @ from NEON_00_15
+ veor q15,q13 @ sigma0(X[i+1])
+ vshr.u64 d26,d18,#41 @ from NEON_00_15
+ vadd.i64 q1,q15
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d18,#50
+ vsli.64 d25,d18,#46
+ vmov d29,d18
+ vsli.64 d26,d18,#23
+#if 18<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d19,d20 @ Ch(e,f,g)
+ vshr.u64 d24,d22,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d21
+ vshr.u64 d25,d22,#34
+ vsli.64 d24,d22,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d22,#39
+ vadd.i64 d28,d2
+ vsli.64 d25,d22,#30
+ veor d30,d22,d23
+ vsli.64 d26,d22,#25
+ veor d21,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d16,d23 @ Maj(a,b,c)
+ veor d21,d26 @ Sigma0(a)
+ vadd.i64 d17,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d21,d30
+ vshr.u64 d24,d17,#14 @ 19
+#if 19<16
+ vld1.64 {d3},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d17,#18
+#if 19>0
+ vadd.i64 d21,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d17,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d17,#50
+ vsli.64 d25,d17,#46
+ vmov d29,d17
+ vsli.64 d26,d17,#23
+#if 19<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d18,d19 @ Ch(e,f,g)
+ vshr.u64 d24,d21,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d20
+ vshr.u64 d25,d21,#34
+ vsli.64 d24,d21,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d21,#39
+ vadd.i64 d28,d3
+ vsli.64 d25,d21,#30
+ veor d30,d21,d22
+ vsli.64 d26,d21,#25
+ veor d20,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d23,d22 @ Maj(a,b,c)
+ veor d20,d26 @ Sigma0(a)
+ vadd.i64 d16,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d20,d30
+ vshr.u64 q12,q1,#19
+ vshr.u64 q13,q1,#61
+ vadd.i64 d20,d30 @ h+=Maj from the past
+ vshr.u64 q15,q1,#6
+ vsli.64 q12,q1,#45
+ vext.8 q14,q2,q3,#8 @ X[i+1]
+ vsli.64 q13,q1,#3
+ veor q15,q12
+ vshr.u64 q12,q14,#1
+ veor q15,q13 @ sigma1(X[i+14])
+ vshr.u64 q13,q14,#8
+ vadd.i64 q2,q15
+ vshr.u64 q15,q14,#7
+ vsli.64 q12,q14,#63
+ vsli.64 q13,q14,#56
+ vext.8 q14,q6,q7,#8 @ X[i+9]
+ veor q15,q12
+ vshr.u64 d24,d16,#14 @ from NEON_00_15
+ vadd.i64 q2,q14
+ vshr.u64 d25,d16,#18 @ from NEON_00_15
+ veor q15,q13 @ sigma0(X[i+1])
+ vshr.u64 d26,d16,#41 @ from NEON_00_15
+ vadd.i64 q2,q15
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d16,#50
+ vsli.64 d25,d16,#46
+ vmov d29,d16
+ vsli.64 d26,d16,#23
+#if 20<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d17,d18 @ Ch(e,f,g)
+ vshr.u64 d24,d20,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d19
+ vshr.u64 d25,d20,#34
+ vsli.64 d24,d20,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d20,#39
+ vadd.i64 d28,d4
+ vsli.64 d25,d20,#30
+ veor d30,d20,d21
+ vsli.64 d26,d20,#25
+ veor d19,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d22,d21 @ Maj(a,b,c)
+ veor d19,d26 @ Sigma0(a)
+ vadd.i64 d23,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d19,d30
+ vshr.u64 d24,d23,#14 @ 21
+#if 21<16
+ vld1.64 {d5},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d23,#18
+#if 21>0
+ vadd.i64 d19,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d23,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d23,#50
+ vsli.64 d25,d23,#46
+ vmov d29,d23
+ vsli.64 d26,d23,#23
+#if 21<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d16,d17 @ Ch(e,f,g)
+ vshr.u64 d24,d19,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d18
+ vshr.u64 d25,d19,#34
+ vsli.64 d24,d19,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d19,#39
+ vadd.i64 d28,d5
+ vsli.64 d25,d19,#30
+ veor d30,d19,d20
+ vsli.64 d26,d19,#25
+ veor d18,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d21,d20 @ Maj(a,b,c)
+ veor d18,d26 @ Sigma0(a)
+ vadd.i64 d22,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d18,d30
+ vshr.u64 q12,q2,#19
+ vshr.u64 q13,q2,#61
+ vadd.i64 d18,d30 @ h+=Maj from the past
+ vshr.u64 q15,q2,#6
+ vsli.64 q12,q2,#45
+ vext.8 q14,q3,q4,#8 @ X[i+1]
+ vsli.64 q13,q2,#3
+ veor q15,q12
+ vshr.u64 q12,q14,#1
+ veor q15,q13 @ sigma1(X[i+14])
+ vshr.u64 q13,q14,#8
+ vadd.i64 q3,q15
+ vshr.u64 q15,q14,#7
+ vsli.64 q12,q14,#63
+ vsli.64 q13,q14,#56
+ vext.8 q14,q7,q0,#8 @ X[i+9]
+ veor q15,q12
+ vshr.u64 d24,d22,#14 @ from NEON_00_15
+ vadd.i64 q3,q14
+ vshr.u64 d25,d22,#18 @ from NEON_00_15
+ veor q15,q13 @ sigma0(X[i+1])
+ vshr.u64 d26,d22,#41 @ from NEON_00_15
+ vadd.i64 q3,q15
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d22,#50
+ vsli.64 d25,d22,#46
+ vmov d29,d22
+ vsli.64 d26,d22,#23
+#if 22<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d23,d16 @ Ch(e,f,g)
+ vshr.u64 d24,d18,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d17
+ vshr.u64 d25,d18,#34
+ vsli.64 d24,d18,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d18,#39
+ vadd.i64 d28,d6
+ vsli.64 d25,d18,#30
+ veor d30,d18,d19
+ vsli.64 d26,d18,#25
+ veor d17,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d20,d19 @ Maj(a,b,c)
+ veor d17,d26 @ Sigma0(a)
+ vadd.i64 d21,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d17,d30
+ vshr.u64 d24,d21,#14 @ 23
+#if 23<16
+ vld1.64 {d7},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d21,#18
+#if 23>0
+ vadd.i64 d17,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d21,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d21,#50
+ vsli.64 d25,d21,#46
+ vmov d29,d21
+ vsli.64 d26,d21,#23
+#if 23<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d22,d23 @ Ch(e,f,g)
+ vshr.u64 d24,d17,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d16
+ vshr.u64 d25,d17,#34
+ vsli.64 d24,d17,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d17,#39
+ vadd.i64 d28,d7
+ vsli.64 d25,d17,#30
+ veor d30,d17,d18
+ vsli.64 d26,d17,#25
+ veor d16,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d19,d18 @ Maj(a,b,c)
+ veor d16,d26 @ Sigma0(a)
+ vadd.i64 d20,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d16,d30
+ vshr.u64 q12,q3,#19
+ vshr.u64 q13,q3,#61
+ vadd.i64 d16,d30 @ h+=Maj from the past
+ vshr.u64 q15,q3,#6
+ vsli.64 q12,q3,#45
+ vext.8 q14,q4,q5,#8 @ X[i+1]
+ vsli.64 q13,q3,#3
+ veor q15,q12
+ vshr.u64 q12,q14,#1
+ veor q15,q13 @ sigma1(X[i+14])
+ vshr.u64 q13,q14,#8
+ vadd.i64 q4,q15
+ vshr.u64 q15,q14,#7
+ vsli.64 q12,q14,#63
+ vsli.64 q13,q14,#56
+ vext.8 q14,q0,q1,#8 @ X[i+9]
+ veor q15,q12
+ vshr.u64 d24,d20,#14 @ from NEON_00_15
+ vadd.i64 q4,q14
+ vshr.u64 d25,d20,#18 @ from NEON_00_15
+ veor q15,q13 @ sigma0(X[i+1])
+ vshr.u64 d26,d20,#41 @ from NEON_00_15
+ vadd.i64 q4,q15
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d20,#50
+ vsli.64 d25,d20,#46
+ vmov d29,d20
+ vsli.64 d26,d20,#23
+#if 24<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d21,d22 @ Ch(e,f,g)
+ vshr.u64 d24,d16,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d23
+ vshr.u64 d25,d16,#34
+ vsli.64 d24,d16,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d16,#39
+ vadd.i64 d28,d8
+ vsli.64 d25,d16,#30
+ veor d30,d16,d17
+ vsli.64 d26,d16,#25
+ veor d23,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d18,d17 @ Maj(a,b,c)
+ veor d23,d26 @ Sigma0(a)
+ vadd.i64 d19,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d23,d30
+ vshr.u64 d24,d19,#14 @ 25
+#if 25<16
+ vld1.64 {d9},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d19,#18
+#if 25>0
+ vadd.i64 d23,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d19,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d19,#50
+ vsli.64 d25,d19,#46
+ vmov d29,d19
+ vsli.64 d26,d19,#23
+#if 25<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d20,d21 @ Ch(e,f,g)
+ vshr.u64 d24,d23,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d22
+ vshr.u64 d25,d23,#34
+ vsli.64 d24,d23,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d23,#39
+ vadd.i64 d28,d9
+ vsli.64 d25,d23,#30
+ veor d30,d23,d16
+ vsli.64 d26,d23,#25
+ veor d22,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d17,d16 @ Maj(a,b,c)
+ veor d22,d26 @ Sigma0(a)
+ vadd.i64 d18,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d22,d30
+ vshr.u64 q12,q4,#19
+ vshr.u64 q13,q4,#61
+ vadd.i64 d22,d30 @ h+=Maj from the past
+ vshr.u64 q15,q4,#6
+ vsli.64 q12,q4,#45
+ vext.8 q14,q5,q6,#8 @ X[i+1]
+ vsli.64 q13,q4,#3
+ veor q15,q12
+ vshr.u64 q12,q14,#1
+ veor q15,q13 @ sigma1(X[i+14])
+ vshr.u64 q13,q14,#8
+ vadd.i64 q5,q15
+ vshr.u64 q15,q14,#7
+ vsli.64 q12,q14,#63
+ vsli.64 q13,q14,#56
+ vext.8 q14,q1,q2,#8 @ X[i+9]
+ veor q15,q12
+ vshr.u64 d24,d18,#14 @ from NEON_00_15
+ vadd.i64 q5,q14
+ vshr.u64 d25,d18,#18 @ from NEON_00_15
+ veor q15,q13 @ sigma0(X[i+1])
+ vshr.u64 d26,d18,#41 @ from NEON_00_15
+ vadd.i64 q5,q15
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d18,#50
+ vsli.64 d25,d18,#46
+ vmov d29,d18
+ vsli.64 d26,d18,#23
+#if 26<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d19,d20 @ Ch(e,f,g)
+ vshr.u64 d24,d22,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d21
+ vshr.u64 d25,d22,#34
+ vsli.64 d24,d22,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d22,#39
+ vadd.i64 d28,d10
+ vsli.64 d25,d22,#30
+ veor d30,d22,d23
+ vsli.64 d26,d22,#25
+ veor d21,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d16,d23 @ Maj(a,b,c)
+ veor d21,d26 @ Sigma0(a)
+ vadd.i64 d17,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d21,d30
+ vshr.u64 d24,d17,#14 @ 27
+#if 27<16
+ vld1.64 {d11},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d17,#18
+#if 27>0
+ vadd.i64 d21,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d17,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d17,#50
+ vsli.64 d25,d17,#46
+ vmov d29,d17
+ vsli.64 d26,d17,#23
+#if 27<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d18,d19 @ Ch(e,f,g)
+ vshr.u64 d24,d21,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d20
+ vshr.u64 d25,d21,#34
+ vsli.64 d24,d21,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d21,#39
+ vadd.i64 d28,d11
+ vsli.64 d25,d21,#30
+ veor d30,d21,d22
+ vsli.64 d26,d21,#25
+ veor d20,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d23,d22 @ Maj(a,b,c)
+ veor d20,d26 @ Sigma0(a)
+ vadd.i64 d16,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d20,d30
+ vshr.u64 q12,q5,#19
+ vshr.u64 q13,q5,#61
+ vadd.i64 d20,d30 @ h+=Maj from the past
+ vshr.u64 q15,q5,#6
+ vsli.64 q12,q5,#45
+ vext.8 q14,q6,q7,#8 @ X[i+1]
+ vsli.64 q13,q5,#3
+ veor q15,q12
+ vshr.u64 q12,q14,#1
+ veor q15,q13 @ sigma1(X[i+14])
+ vshr.u64 q13,q14,#8
+ vadd.i64 q6,q15
+ vshr.u64 q15,q14,#7
+ vsli.64 q12,q14,#63
+ vsli.64 q13,q14,#56
+ vext.8 q14,q2,q3,#8 @ X[i+9]
+ veor q15,q12
+ vshr.u64 d24,d16,#14 @ from NEON_00_15
+ vadd.i64 q6,q14
+ vshr.u64 d25,d16,#18 @ from NEON_00_15
+ veor q15,q13 @ sigma0(X[i+1])
+ vshr.u64 d26,d16,#41 @ from NEON_00_15
+ vadd.i64 q6,q15
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d16,#50
+ vsli.64 d25,d16,#46
+ vmov d29,d16
+ vsli.64 d26,d16,#23
+#if 28<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d17,d18 @ Ch(e,f,g)
+ vshr.u64 d24,d20,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d19
+ vshr.u64 d25,d20,#34
+ vsli.64 d24,d20,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d20,#39
+ vadd.i64 d28,d12
+ vsli.64 d25,d20,#30
+ veor d30,d20,d21
+ vsli.64 d26,d20,#25
+ veor d19,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d22,d21 @ Maj(a,b,c)
+ veor d19,d26 @ Sigma0(a)
+ vadd.i64 d23,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d19,d30
+ vshr.u64 d24,d23,#14 @ 29
+#if 29<16
+ vld1.64 {d13},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d23,#18
+#if 29>0
+ vadd.i64 d19,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d23,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d23,#50
+ vsli.64 d25,d23,#46
+ vmov d29,d23
+ vsli.64 d26,d23,#23
+#if 29<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d16,d17 @ Ch(e,f,g)
+ vshr.u64 d24,d19,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d18
+ vshr.u64 d25,d19,#34
+ vsli.64 d24,d19,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d19,#39
+ vadd.i64 d28,d13
+ vsli.64 d25,d19,#30
+ veor d30,d19,d20
+ vsli.64 d26,d19,#25
+ veor d18,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d21,d20 @ Maj(a,b,c)
+ veor d18,d26 @ Sigma0(a)
+ vadd.i64 d22,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d18,d30
+ vshr.u64 q12,q6,#19
+ vshr.u64 q13,q6,#61
+ vadd.i64 d18,d30 @ h+=Maj from the past
+ vshr.u64 q15,q6,#6
+ vsli.64 q12,q6,#45
+ vext.8 q14,q7,q0,#8 @ X[i+1]
+ vsli.64 q13,q6,#3
+ veor q15,q12
+ vshr.u64 q12,q14,#1
+ veor q15,q13 @ sigma1(X[i+14])
+ vshr.u64 q13,q14,#8
+ vadd.i64 q7,q15
+ vshr.u64 q15,q14,#7
+ vsli.64 q12,q14,#63
+ vsli.64 q13,q14,#56
+ vext.8 q14,q3,q4,#8 @ X[i+9]
+ veor q15,q12
+ vshr.u64 d24,d22,#14 @ from NEON_00_15
+ vadd.i64 q7,q14
+ vshr.u64 d25,d22,#18 @ from NEON_00_15
+ veor q15,q13 @ sigma0(X[i+1])
+ vshr.u64 d26,d22,#41 @ from NEON_00_15
+ vadd.i64 q7,q15
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d22,#50
+ vsli.64 d25,d22,#46
+ vmov d29,d22
+ vsli.64 d26,d22,#23
+#if 30<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d23,d16 @ Ch(e,f,g)
+ vshr.u64 d24,d18,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d17
+ vshr.u64 d25,d18,#34
+ vsli.64 d24,d18,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d18,#39
+ vadd.i64 d28,d14
+ vsli.64 d25,d18,#30
+ veor d30,d18,d19
+ vsli.64 d26,d18,#25
+ veor d17,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d20,d19 @ Maj(a,b,c)
+ veor d17,d26 @ Sigma0(a)
+ vadd.i64 d21,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d17,d30
+ vshr.u64 d24,d21,#14 @ 31
+#if 31<16
+ vld1.64 {d15},[r1]! @ handles unaligned
+#endif
+ vshr.u64 d25,d21,#18
+#if 31>0
+ vadd.i64 d17,d30 @ h+=Maj from the past
+#endif
+ vshr.u64 d26,d21,#41
+ vld1.64 {d28},[r3,:64]! @ K[i++]
+ vsli.64 d24,d21,#50
+ vsli.64 d25,d21,#46
+ vmov d29,d21
+ vsli.64 d26,d21,#23
+#if 31<16 && defined(__ARMEL__)
+ vrev64.8 ,
+#endif
+ veor d25,d24
+ vbsl d29,d22,d23 @ Ch(e,f,g)
+ vshr.u64 d24,d17,#28
+ veor d26,d25 @ Sigma1(e)
+ vadd.i64 d27,d29,d16
+ vshr.u64 d25,d17,#34
+ vsli.64 d24,d17,#36
+ vadd.i64 d27,d26
+ vshr.u64 d26,d17,#39
+ vadd.i64 d28,d15
+ vsli.64 d25,d17,#30
+ veor d30,d17,d18
+ vsli.64 d26,d17,#25
+ veor d16,d24,d25
+ vadd.i64 d27,d28
+ vbsl d30,d19,d18 @ Maj(a,b,c)
+ veor d16,d26 @ Sigma0(a)
+ vadd.i64 d20,d27
+ vadd.i64 d30,d27
+ @ vadd.i64 d16,d30
+ bne .L16_79_neon
+
+ vadd.i64 d16,d30 @ h+=Maj from the past
+ vldmia r0,{d24-d31} @ load context to temp
+ vadd.i64 q8,q12 @ vectorized accumulate
+ vadd.i64 q9,q13
+ vadd.i64 q10,q14
+ vadd.i64 q11,q15
+ vstmia r0,{d16-d23} @ save context
+ teq r1,r2
+ sub r3,#640 @ rewind K512
+ bne .Loop_neon
+
+ VFP_ABI_POP
+ bx lr @ .word 0xe12fff1e
+.size sha512_block_data_order_neon,.-sha512_block_data_order_neon
+#endif
+.asciz "SHA512 block transform for ARMv4/NEON, CRYPTOGAMS by <appro@openssl.org>"
+.align 2
+#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
+.comm OPENSSL_armcap_P,4,4
+#endif
diff --git a/arch/arm/crypto/sha512-glue.c b/arch/arm/crypto/sha512-glue.c
new file mode 100644
index 000000000000..269a394e4a53
--- /dev/null
+++ b/arch/arm/crypto/sha512-glue.c
@@ -0,0 +1,121 @@
+/*
+ * sha512-glue.c - accelerated SHA-384/512 for ARM
+ *
+ * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * 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 <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <crypto/sha512_base.h>
+#include <linux/crypto.h>
+#include <linux/module.h>
+
+#include <asm/hwcap.h>
+#include <asm/neon.h>
+
+#include "sha512.h"
+
+MODULE_DESCRIPTION("Accelerated SHA-384/SHA-512 secure hash for ARM");
+MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
+MODULE_LICENSE("GPL v2");
+
+MODULE_ALIAS_CRYPTO("sha384");
+MODULE_ALIAS_CRYPTO("sha512");
+MODULE_ALIAS_CRYPTO("sha384-arm");
+MODULE_ALIAS_CRYPTO("sha512-arm");
+
+asmlinkage void sha512_block_data_order(u64 *state, u8 const *src, int blocks);
+
+int sha512_arm_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ return sha512_base_do_update(desc, data, len,
+ (sha512_block_fn *)sha512_block_data_order);
+}
+
+int sha512_arm_final(struct shash_desc *desc, u8 *out)
+{
+ sha512_base_do_finalize(desc,
+ (sha512_block_fn *)sha512_block_data_order);
+ return sha512_base_finish(desc, out);
+}
+
+int sha512_arm_finup(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ sha512_base_do_update(desc, data, len,
+ (sha512_block_fn *)sha512_block_data_order);
+ return sha512_arm_final(desc, out);
+}
+
+static struct shash_alg sha512_arm_algs[] = { {
+ .init = sha384_base_init,
+ .update = sha512_arm_update,
+ .final = sha512_arm_final,
+ .finup = sha512_arm_finup,
+ .descsize = sizeof(struct sha512_state),
+ .digestsize = SHA384_DIGEST_SIZE,
+ .base = {
+ .cra_name = "sha384",
+ .cra_driver_name = "sha384-arm",
+ .cra_priority = 250,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA512_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ }
+}, {
+ .init = sha512_base_init,
+ .update = sha512_arm_update,
+ .final = sha512_arm_final,
+ .finup = sha512_arm_finup,
+ .descsize = sizeof(struct sha512_state),
+ .digestsize = SHA512_DIGEST_SIZE,
+ .base = {
+ .cra_name = "sha512",
+ .cra_driver_name = "sha512-arm",
+ .cra_priority = 250,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA512_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ }
+} };
+
+static int __init sha512_arm_mod_init(void)
+{
+ int err;
+
+ err = crypto_register_shashes(sha512_arm_algs,
+ ARRAY_SIZE(sha512_arm_algs));
+ if (err)
+ return err;
+
+ if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && cpu_has_neon()) {
+ err = crypto_register_shashes(sha512_neon_algs,
+ ARRAY_SIZE(sha512_neon_algs));
+ if (err)
+ goto err_unregister;
+ }
+ return 0;
+
+err_unregister:
+ crypto_unregister_shashes(sha512_arm_algs,
+ ARRAY_SIZE(sha512_arm_algs));
+
+ return err;
+}
+
+static void __exit sha512_arm_mod_fini(void)
+{
+ crypto_unregister_shashes(sha512_arm_algs,
+ ARRAY_SIZE(sha512_arm_algs));
+ if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && cpu_has_neon())
+ crypto_unregister_shashes(sha512_neon_algs,
+ ARRAY_SIZE(sha512_neon_algs));
+}
+
+module_init(sha512_arm_mod_init);
+module_exit(sha512_arm_mod_fini);
diff --git a/arch/arm/crypto/sha512-neon-glue.c b/arch/arm/crypto/sha512-neon-glue.c
new file mode 100644
index 000000000000..32693684a3ab
--- /dev/null
+++ b/arch/arm/crypto/sha512-neon-glue.c
@@ -0,0 +1,98 @@
+/*
+ * sha512-neon-glue.c - accelerated SHA-384/512 for ARM NEON
+ *
+ * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * 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 <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <crypto/sha512_base.h>
+#include <linux/crypto.h>
+#include <linux/module.h>
+
+#include <asm/simd.h>
+#include <asm/neon.h>
+
+#include "sha512.h"
+
+MODULE_ALIAS_CRYPTO("sha384-neon");
+MODULE_ALIAS_CRYPTO("sha512-neon");
+
+asmlinkage void sha512_block_data_order_neon(u64 *state, u8 const *src,
+ int blocks);
+
+static int sha512_neon_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ struct sha512_state *sctx = shash_desc_ctx(desc);
+
+ if (!may_use_simd() ||
+ (sctx->count[0] % SHA512_BLOCK_SIZE) + len < SHA512_BLOCK_SIZE)
+ return sha512_arm_update(desc, data, len);
+
+ kernel_neon_begin();
+ sha512_base_do_update(desc, data, len,
+ (sha512_block_fn *)sha512_block_data_order_neon);
+ kernel_neon_end();
+
+ return 0;
+}
+
+static int sha512_neon_finup(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ if (!may_use_simd())
+ return sha512_arm_finup(desc, data, len, out);
+
+ kernel_neon_begin();
+ if (len)
+ sha512_base_do_update(desc, data, len,
+ (sha512_block_fn *)sha512_block_data_order_neon);
+ sha512_base_do_finalize(desc,
+ (sha512_block_fn *)sha512_block_data_order_neon);
+ kernel_neon_end();
+
+ return sha512_base_finish(desc, out);
+}
+
+static int sha512_neon_final(struct shash_desc *desc, u8 *out)
+{
+ return sha512_neon_finup(desc, NULL, 0, out);
+}
+
+struct shash_alg sha512_neon_algs[] = { {
+ .init = sha384_base_init,
+ .update = sha512_neon_update,
+ .final = sha512_neon_final,
+ .finup = sha512_neon_finup,
+ .descsize = sizeof(struct sha512_state),
+ .digestsize = SHA384_DIGEST_SIZE,
+ .base = {
+ .cra_name = "sha384",
+ .cra_driver_name = "sha384-neon",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA384_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+
+ }
+}, {
+ .init = sha512_base_init,
+ .update = sha512_neon_update,
+ .final = sha512_neon_final,
+ .finup = sha512_neon_finup,
+ .descsize = sizeof(struct sha512_state),
+ .digestsize = SHA512_DIGEST_SIZE,
+ .base = {
+ .cra_name = "sha512",
+ .cra_driver_name = "sha512-neon",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA512_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ }
+} };
diff --git a/arch/arm/crypto/sha512.h b/arch/arm/crypto/sha512.h
new file mode 100644
index 000000000000..a75d9a82988a
--- /dev/null
+++ b/arch/arm/crypto/sha512.h
@@ -0,0 +1,8 @@
+
+int sha512_arm_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len);
+
+int sha512_arm_finup(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out);
+
+extern struct shash_alg sha512_neon_algs[2];
diff --git a/arch/arm/crypto/sha512_neon_glue.c b/arch/arm/crypto/sha512_neon_glue.c
deleted file mode 100644
index b124dce838d6..000000000000
--- a/arch/arm/crypto/sha512_neon_glue.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Glue code for the SHA512 Secure Hash Algorithm assembly implementation
- * using NEON instructions.
- *
- * Copyright © 2014 Jussi Kivilinna <jussi.kivilinna@iki.fi>
- *
- * This file is based on sha512_ssse3_glue.c:
- * Copyright (C) 2013 Intel Corporation
- * Author: Tim Chen <tim.c.chen@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- */
-
-#include <crypto/internal/hash.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/cryptohash.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <crypto/sha.h>
-#include <asm/byteorder.h>
-#include <asm/simd.h>
-#include <asm/neon.h>
-
-
-static const u64 sha512_k[] = {
- 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
- 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
- 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
- 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
- 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
- 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
- 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
- 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
- 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
- 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
- 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
- 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
- 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
- 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
- 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
- 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
- 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
- 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
- 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
- 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
- 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
- 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
- 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
- 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
- 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
- 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
- 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
- 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
- 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
- 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
- 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
- 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
- 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
- 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
- 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
- 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
- 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
- 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
- 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
- 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
-};
-
-
-asmlinkage void sha512_transform_neon(u64 *digest, const void *data,
- const u64 k[], unsigned int num_blks);
-
-
-static int sha512_neon_init(struct shash_desc *desc)
-{
- struct sha512_state *sctx = shash_desc_ctx(desc);
-
- sctx->state[0] = SHA512_H0;
- sctx->state[1] = SHA512_H1;
- sctx->state[2] = SHA512_H2;
- sctx->state[3] = SHA512_H3;
- sctx->state[4] = SHA512_H4;
- sctx->state[5] = SHA512_H5;
- sctx->state[6] = SHA512_H6;
- sctx->state[7] = SHA512_H7;
- sctx->count[0] = sctx->count[1] = 0;
-
- return 0;
-}
-
-static int __sha512_neon_update(struct shash_desc *desc, const u8 *data,
- unsigned int len, unsigned int partial)
-{
- struct sha512_state *sctx = shash_desc_ctx(desc);
- unsigned int done = 0;
-
- sctx->count[0] += len;
- if (sctx->count[0] < len)
- sctx->count[1]++;
-
- if (partial) {
- done = SHA512_BLOCK_SIZE - partial;
- memcpy(sctx->buf + partial, data, done);
- sha512_transform_neon(sctx->state, sctx->buf, sha512_k, 1);
- }
-
- if (len - done >= SHA512_BLOCK_SIZE) {
- const unsigned int rounds = (len - done) / SHA512_BLOCK_SIZE;
-
- sha512_transform_neon(sctx->state, data + done, sha512_k,
- rounds);
-
- done += rounds * SHA512_BLOCK_SIZE;
- }
-
- memcpy(sctx->buf, data + done, len - done);
-
- return 0;
-}
-
-static int sha512_neon_update(struct shash_desc *desc, const u8 *data,
- unsigned int len)
-{
- struct sha512_state *sctx = shash_desc_ctx(desc);
- unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE;
- int res;
-
- /* Handle the fast case right here */
- if (partial + len < SHA512_BLOCK_SIZE) {
- sctx->count[0] += len;
- if (sctx->count[0] < len)
- sctx->count[1]++;
- memcpy(sctx->buf + partial, data, len);
-
- return 0;
- }
-
- if (!may_use_simd()) {
- res = crypto_sha512_update(desc, data, len);
- } else {
- kernel_neon_begin();
- res = __sha512_neon_update(desc, data, len, partial);
- kernel_neon_end();
- }
-
- return res;
-}
-
-
-/* Add padding and return the message digest. */
-static int sha512_neon_final(struct shash_desc *desc, u8 *out)
-{
- struct sha512_state *sctx = shash_desc_ctx(desc);
- unsigned int i, index, padlen;
- __be64 *dst = (__be64 *)out;
- __be64 bits[2];
- static const u8 padding[SHA512_BLOCK_SIZE] = { 0x80, };
-
- /* save number of bits */
- bits[1] = cpu_to_be64(sctx->count[0] << 3);
- bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61);
-
- /* Pad out to 112 mod 128 and append length */
- index = sctx->count[0] & 0x7f;
- padlen = (index < 112) ? (112 - index) : ((128+112) - index);
-
- if (!may_use_simd()) {
- crypto_sha512_update(desc, padding, padlen);
- crypto_sha512_update(desc, (const u8 *)&bits, sizeof(bits));
- } else {
- kernel_neon_begin();
- /* We need to fill a whole block for __sha512_neon_update() */
- if (padlen <= 112) {
- sctx->count[0] += padlen;
- if (sctx->count[0] < padlen)
- sctx->count[1]++;
- memcpy(sctx->buf + index, padding, padlen);
- } else {
- __sha512_neon_update(desc, padding, padlen, index);
- }
- __sha512_neon_update(desc, (const u8 *)&bits,
- sizeof(bits), 112);
- kernel_neon_end();
- }
-
- /* Store state in digest */
- for (i = 0; i < 8; i++)
- dst[i] = cpu_to_be64(sctx->state[i]);
-
- /* Wipe context */
- memset(sctx, 0, sizeof(*sctx));
-
- return 0;
-}
-
-static int sha512_neon_export(struct shash_desc *desc, void *out)
-{
- struct sha512_state *sctx = shash_desc_ctx(desc);
-
- memcpy(out, sctx, sizeof(*sctx));
-
- return 0;
-}
-
-static int sha512_neon_import(struct shash_desc *desc, const void *in)
-{
- struct sha512_state *sctx = shash_desc_ctx(desc);
-
- memcpy(sctx, in, sizeof(*sctx));
-
- return 0;
-}
-
-static int sha384_neon_init(struct shash_desc *desc)
-{
- struct sha512_state *sctx = shash_desc_ctx(desc);
-
- sctx->state[0] = SHA384_H0;
- sctx->state[1] = SHA384_H1;
- sctx->state[2] = SHA384_H2;
- sctx->state[3] = SHA384_H3;
- sctx->state[4] = SHA384_H4;
- sctx->state[5] = SHA384_H5;
- sctx->state[6] = SHA384_H6;
- sctx->state[7] = SHA384_H7;
-
- sctx->count[0] = sctx->count[1] = 0;
-
- return 0;
-}
-
-static int sha384_neon_final(struct shash_desc *desc, u8 *hash)
-{
- u8 D[SHA512_DIGEST_SIZE];
-
- sha512_neon_final(desc, D);
-
- memcpy(hash, D, SHA384_DIGEST_SIZE);
- memzero_explicit(D, SHA512_DIGEST_SIZE);
-
- return 0;
-}
-
-static struct shash_alg algs[] = { {
- .digestsize = SHA512_DIGEST_SIZE,
- .init = sha512_neon_init,
- .update = sha512_neon_update,
- .final = sha512_neon_final,
- .export = sha512_neon_export,
- .import = sha512_neon_import,
- .descsize = sizeof(struct sha512_state),
- .statesize = sizeof(struct sha512_state),
- .base = {
- .cra_name = "sha512",
- .cra_driver_name = "sha512-neon",
- .cra_priority = 250,
- .cra_flags = CRYPTO_ALG_TYPE_SHASH,
- .cra_blocksize = SHA512_BLOCK_SIZE,
- .cra_module = THIS_MODULE,
- }
-}, {
- .digestsize = SHA384_DIGEST_SIZE,
- .init = sha384_neon_init,
- .update = sha512_neon_update,
- .final = sha384_neon_final,
- .export = sha512_neon_export,
- .import = sha512_neon_import,
- .descsize = sizeof(struct sha512_state),
- .statesize = sizeof(struct sha512_state),
- .base = {
- .cra_name = "sha384",
- .cra_driver_name = "sha384-neon",
- .cra_priority = 250,
- .cra_flags = CRYPTO_ALG_TYPE_SHASH,
- .cra_blocksize = SHA384_BLOCK_SIZE,
- .cra_module = THIS_MODULE,
- }
-} };
-
-static int __init sha512_neon_mod_init(void)
-{
- if (!cpu_has_neon())
- return -ENODEV;
-
- return crypto_register_shashes(algs, ARRAY_SIZE(algs));
-}
-
-static void __exit sha512_neon_mod_fini(void)
-{
- crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
-}
-
-module_init(sha512_neon_mod_init);
-module_exit(sha512_neon_mod_fini);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SHA512 Secure Hash Algorithm, NEON accelerated");
-
-MODULE_ALIAS_CRYPTO("sha512");
-MODULE_ALIAS_CRYPTO("sha384");
diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild
index 3c4596d0ce6c..83c50193626c 100644
--- a/arch/arm/include/asm/Kbuild
+++ b/arch/arm/include/asm/Kbuild
@@ -20,7 +20,6 @@ generic-y += poll.h
generic-y += preempt.h
generic-y += resource.h
generic-y += rwsem.h
-generic-y += scatterlist.h
generic-y += seccomp.h
generic-y += sections.h
generic-y += segment.h
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 186270b3e194..4abe57279c66 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -178,6 +178,21 @@
.endm
/*
+ * Assembly version of "adr rd, BSYM(sym)". This should only be used to
+ * reference local symbols in the same assembly file which are to be
+ * resolved by the assembler. Other usage is undefined.
+ */
+ .irp c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo
+ .macro badr\c, rd, sym
+#ifdef CONFIG_THUMB2_KERNEL
+ adr\c \rd, \sym + 1
+#else
+ adr\c \rd, \sym
+#endif
+ .endm
+ .endr
+
+/*
* Get current thread_info.
*/
.macro get_thread_info, rd
@@ -326,7 +341,7 @@
THUMB( orr \reg , \reg , #PSR_T_BIT )
bne 1f
orr \reg, \reg, #PSR_A_BIT
- adr lr, BSYM(2f)
+ badr lr, 2f
msr spsr_cxsf, \reg
__MSR_ELR_HYP(14)
__ERET
diff --git a/arch/arm/include/asm/barrier.h b/arch/arm/include/asm/barrier.h
index d2f81e6b8c1c..6c2327e1c732 100644
--- a/arch/arm/include/asm/barrier.h
+++ b/arch/arm/include/asm/barrier.h
@@ -81,7 +81,7 @@ do { \
#define read_barrier_depends() do { } while(0)
#define smp_read_barrier_depends() do { } while(0)
-#define set_mb(var, value) do { var = value; smp_mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
#define smp_mb__before_atomic() smp_mb()
#define smp_mb__after_atomic() smp_mb()
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 2d46862e7bef..4812cda8fd17 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -482,10 +482,17 @@ static inline void __sync_cache_range_r(volatile void *p, size_t size)
: : : "r0","r1","r2","r3","r4","r5","r6","r7", \
"r9","r10","lr","memory" )
+#ifdef CONFIG_MMU
int set_memory_ro(unsigned long addr, int numpages);
int set_memory_rw(unsigned long addr, int numpages);
int set_memory_x(unsigned long addr, int numpages);
int set_memory_nx(unsigned long addr, int numpages);
+#else
+static inline int set_memory_ro(unsigned long addr, int numpages) { return 0; }
+static inline int set_memory_rw(unsigned long addr, int numpages) { return 0; }
+static inline int set_memory_x(unsigned long addr, int numpages) { return 0; }
+static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; }
+#endif
#ifdef CONFIG_DEBUG_RODATA
void mark_rodata_ro(void);
diff --git a/arch/arm/include/asm/cmpxchg.h b/arch/arm/include/asm/cmpxchg.h
index abb2c3769b01..1692a05d3207 100644
--- a/arch/arm/include/asm/cmpxchg.h
+++ b/arch/arm/include/asm/cmpxchg.h
@@ -94,6 +94,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
break;
#endif
default:
+ /* Cause a link-time error, the xchg() size is not supported */
__bad_xchg(ptr, size), ret = 0;
break;
}
@@ -102,8 +103,10 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
return ret;
}
-#define xchg(ptr,x) \
- ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+#define xchg(ptr, x) ({ \
+ (__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), \
+ sizeof(*(ptr))); \
+})
#include <asm-generic/cmpxchg-local.h>
@@ -118,14 +121,16 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
* cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
* them available.
*/
-#define cmpxchg_local(ptr, o, n) \
- ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
- (unsigned long)(n), sizeof(*(ptr))))
+#define cmpxchg_local(ptr, o, n) ({ \
+ (__typeof(*ptr))__cmpxchg_local_generic((ptr), \
+ (unsigned long)(o), \
+ (unsigned long)(n), \
+ sizeof(*(ptr))); \
+})
+
#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-#ifndef CONFIG_SMP
#include <asm-generic/cmpxchg.h>
-#endif
#else /* min ARCH >= ARMv6 */
@@ -201,11 +206,12 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
return ret;
}
-#define cmpxchg(ptr,o,n) \
- ((__typeof__(*(ptr)))__cmpxchg_mb((ptr), \
- (unsigned long)(o), \
- (unsigned long)(n), \
- sizeof(*(ptr))))
+#define cmpxchg(ptr,o,n) ({ \
+ (__typeof__(*(ptr)))__cmpxchg_mb((ptr), \
+ (unsigned long)(o), \
+ (unsigned long)(n), \
+ sizeof(*(ptr))); \
+})
static inline unsigned long __cmpxchg_local(volatile void *ptr,
unsigned long old,
@@ -227,6 +233,13 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
return ret;
}
+#define cmpxchg_local(ptr, o, n) ({ \
+ (__typeof(*ptr))__cmpxchg_local((ptr), \
+ (unsigned long)(o), \
+ (unsigned long)(n), \
+ sizeof(*(ptr))); \
+})
+
static inline unsigned long long __cmpxchg64(unsigned long long *ptr,
unsigned long long old,
unsigned long long new)
@@ -252,6 +265,14 @@ static inline unsigned long long __cmpxchg64(unsigned long long *ptr,
return oldval;
}
+#define cmpxchg64_relaxed(ptr, o, n) ({ \
+ (__typeof__(*(ptr)))__cmpxchg64((ptr), \
+ (unsigned long long)(o), \
+ (unsigned long long)(n)); \
+})
+
+#define cmpxchg64_local(ptr, o, n) cmpxchg64_relaxed((ptr), (o), (n))
+
static inline unsigned long long __cmpxchg64_mb(unsigned long long *ptr,
unsigned long long old,
unsigned long long new)
@@ -265,23 +286,11 @@ static inline unsigned long long __cmpxchg64_mb(unsigned long long *ptr,
return ret;
}
-#define cmpxchg_local(ptr,o,n) \
- ((__typeof__(*(ptr)))__cmpxchg_local((ptr), \
- (unsigned long)(o), \
- (unsigned long)(n), \
- sizeof(*(ptr))))
-
-#define cmpxchg64(ptr, o, n) \
- ((__typeof__(*(ptr)))__cmpxchg64_mb((ptr), \
- (unsigned long long)(o), \
- (unsigned long long)(n)))
-
-#define cmpxchg64_relaxed(ptr, o, n) \
- ((__typeof__(*(ptr)))__cmpxchg64((ptr), \
- (unsigned long long)(o), \
- (unsigned long long)(n)))
-
-#define cmpxchg64_local(ptr, o, n) cmpxchg64_relaxed((ptr), (o), (n))
+#define cmpxchg64(ptr, o, n) ({ \
+ (__typeof__(*(ptr)))__cmpxchg64_mb((ptr), \
+ (unsigned long long)(o), \
+ (unsigned long long)(n)); \
+})
#endif /* __LINUX_ARM_ARCH__ >= 6 */
diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h
index 99084431d6ae..bb4fa67da541 100644
--- a/arch/arm/include/asm/dma.h
+++ b/arch/arm/include/asm/dma.h
@@ -19,7 +19,7 @@
* It should not be re-used except for that purpose.
*/
#include <linux/spinlock.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <mach/isa-dma.h>
diff --git a/arch/arm/include/asm/edac.h b/arch/arm/include/asm/edac.h
index 0df7a2c1fc3d..5189fa819b60 100644
--- a/arch/arm/include/asm/edac.h
+++ b/arch/arm/include/asm/edac.h
@@ -18,11 +18,12 @@
#define ASM_EDAC_H
/*
* ECC atomic, DMA, SMP and interrupt safe scrub function.
- * Implements the per arch atomic_scrub() that EDAC use for software
+ * Implements the per arch edac_atomic_scrub() that EDAC use for software
* ECC scrubbing. It reads memory and then writes back the original
* value, allowing the hardware to detect and correct memory errors.
*/
-static inline void atomic_scrub(void *va, u32 size)
+
+static inline void edac_atomic_scrub(void *va, u32 size)
{
#if __LINUX_ARM_ARCH__ >= 6
unsigned int *virt_addr = va;
diff --git a/arch/arm/include/asm/entry-macro-multi.S b/arch/arm/include/asm/entry-macro-multi.S
index 469a2b30fa27..609184f522ee 100644
--- a/arch/arm/include/asm/entry-macro-multi.S
+++ b/arch/arm/include/asm/entry-macro-multi.S
@@ -10,7 +10,7 @@
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
- adrne lr, BSYM(1b)
+ badrne lr, 1b
bne asm_do_IRQ
#ifdef CONFIG_SMP
@@ -23,7 +23,7 @@
ALT_SMP(test_for_ipi r0, r2, r6, lr)
ALT_UP_B(9997f)
movne r1, sp
- adrne lr, BSYM(1b)
+ badrne lr, 1b
bne do_IPI
#endif
9997:
diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h
index 89aefe10d66b..34c1d96ef46d 100644
--- a/arch/arm/include/asm/firmware.h
+++ b/arch/arm/include/asm/firmware.h
@@ -34,6 +34,10 @@ struct firmware_ops {
*/
int (*set_cpu_boot_addr)(int cpu, unsigned long boot_addr);
/*
+ * Gets boot address of specified physical CPU
+ */
+ int (*get_cpu_boot_addr)(int cpu, unsigned long *boot_addr);
+ /*
* Boots specified physical CPU
*/
int (*cpu_boot)(int cpu);
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 4e78065a16aa..5eed82809d82 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -93,6 +93,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;
+ preempt_disable();
__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
"1: " TUSER(ldr) " %1, [%4]\n"
" teq %1, %2\n"
@@ -104,6 +105,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
: "cc", "memory");
*uval = val;
+ preempt_enable();
+
return ret;
}
@@ -124,7 +127,10 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;
- pagefault_disable(); /* implies preempt_disable() */
+#ifndef CONFIG_SMP
+ preempt_disable();
+#endif
+ pagefault_disable();
switch (op) {
case FUTEX_OP_SET:
@@ -146,7 +152,10 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
ret = -ENOSYS;
}
- pagefault_enable(); /* subsumes preempt_enable() */
+ pagefault_enable();
+#ifndef CONFIG_SMP
+ preempt_enable();
+#endif
if (!ret) {
switch (cmp) {
diff --git a/arch/arm/include/asm/hugetlb.h b/arch/arm/include/asm/hugetlb.h
index 1f1b1cd112f3..7d26f6c4f0f5 100644
--- a/arch/arm/include/asm/hugetlb.h
+++ b/arch/arm/include/asm/hugetlb.h
@@ -53,10 +53,6 @@ static inline int prepare_hugepage_range(struct file *file,
return 0;
}
-static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
-{
-}
-
static inline int huge_pte_none(pte_t pte)
{
return pte_none(pte);
@@ -67,15 +63,6 @@ static inline pte_t huge_pte_wrprotect(pte_t pte)
return pte_wrprotect(pte);
}
-static inline int arch_prepare_hugepage(struct page *page)
-{
- return 0;
-}
-
-static inline void arch_release_hugepage(struct page *page)
-{
-}
-
static inline void arch_clear_hugepage_flags(struct page *page)
{
clear_bit(PG_dcache_clean, &page->flags);
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index db58deb00aa7..1c3938f26beb 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -23,6 +23,7 @@
#ifdef __KERNEL__
+#include <linux/string.h>
#include <linux/types.h>
#include <linux/blk_types.h>
#include <asm/byteorder.h>
@@ -73,17 +74,16 @@ void __raw_readsl(const volatile void __iomem *addr, void *data, int longlen);
static inline void __raw_writew(u16 val, volatile void __iomem *addr)
{
asm volatile("strh %1, %0"
- : "+Q" (*(volatile u16 __force *)addr)
- : "r" (val));
+ : : "Q" (*(volatile u16 __force *)addr), "r" (val));
}
#define __raw_readw __raw_readw
static inline u16 __raw_readw(const volatile void __iomem *addr)
{
u16 val;
- asm volatile("ldrh %1, %0"
- : "+Q" (*(volatile u16 __force *)addr),
- "=r" (val));
+ asm volatile("ldrh %0, %1"
+ : "=r" (val)
+ : "Q" (*(volatile u16 __force *)addr));
return val;
}
#endif
@@ -92,25 +92,23 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
{
asm volatile("strb %1, %0"
- : "+Qo" (*(volatile u8 __force *)addr)
- : "r" (val));
+ : : "Qo" (*(volatile u8 __force *)addr), "r" (val));
}
#define __raw_writel __raw_writel
static inline void __raw_writel(u32 val, volatile void __iomem *addr)
{
asm volatile("str %1, %0"
- : "+Qo" (*(volatile u32 __force *)addr)
- : "r" (val));
+ : : "Qo" (*(volatile u32 __force *)addr), "r" (val));
}
#define __raw_readb __raw_readb
static inline u8 __raw_readb(const volatile void __iomem *addr)
{
u8 val;
- asm volatile("ldrb %1, %0"
- : "+Qo" (*(volatile u8 __force *)addr),
- "=r" (val));
+ asm volatile("ldrb %0, %1"
+ : "=r" (val)
+ : "Qo" (*(volatile u8 __force *)addr));
return val;
}
@@ -118,9 +116,9 @@ static inline u8 __raw_readb(const volatile void __iomem *addr)
static inline u32 __raw_readl(const volatile void __iomem *addr)
{
u32 val;
- asm volatile("ldr %1, %0"
- : "+Qo" (*(volatile u32 __force *)addr),
- "=r" (val));
+ asm volatile("ldr %0, %1"
+ : "=r" (val)
+ : "Qo" (*(volatile u32 __force *)addr));
return val;
}
@@ -319,9 +317,33 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
#define writesw(p,d,l) __raw_writesw(p,d,l)
#define writesl(p,d,l) __raw_writesl(p,d,l)
+#ifndef __ARMBE__
+static inline void memset_io(volatile void __iomem *dst, unsigned c,
+ size_t count)
+{
+ memset((void __force *)dst, c, count);
+}
+#define memset_io(dst,c,count) memset_io(dst,c,count)
+
+static inline void memcpy_fromio(void *to, const volatile void __iomem *from,
+ size_t count)
+{
+ memcpy(to, (const void __force *)from, count);
+}
+#define memcpy_fromio(to,from,count) memcpy_fromio(to,from,count)
+
+static inline void memcpy_toio(volatile void __iomem *to, const void *from,
+ size_t count)
+{
+ memcpy((void __force *)to, from, count);
+}
+#define memcpy_toio(to,from,count) memcpy_toio(to,from,count)
+
+#else
#define memset_io(c,v,l) _memset_io(c,(v),(l))
#define memcpy_fromio(a,c,l) _memcpy_fromio((a),c,(l))
#define memcpy_toio(c,a,l) _memcpy_toio(c,(a),(l))
+#endif
#endif /* readl */
@@ -336,6 +358,7 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
#define ioremap_nocache(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_cache(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_CACHED)
#define ioremap_wc(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_WC)
+#define ioremap_wt(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
#define iounmap __arm_iounmap
/*
diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h
index 3b763d6652a0..43908146a5cf 100644
--- a/arch/arm/include/asm/irqflags.h
+++ b/arch/arm/include/asm/irqflags.h
@@ -20,6 +20,7 @@
#if __LINUX_ARM_ARCH__ >= 6
+#define arch_local_irq_save arch_local_irq_save
static inline unsigned long arch_local_irq_save(void)
{
unsigned long flags;
@@ -31,6 +32,7 @@ static inline unsigned long arch_local_irq_save(void)
return flags;
}
+#define arch_local_irq_enable arch_local_irq_enable
static inline void arch_local_irq_enable(void)
{
asm volatile(
@@ -40,6 +42,7 @@ static inline void arch_local_irq_enable(void)
: "memory", "cc");
}
+#define arch_local_irq_disable arch_local_irq_disable
static inline void arch_local_irq_disable(void)
{
asm volatile(
@@ -56,6 +59,7 @@ static inline void arch_local_irq_disable(void)
/*
* Save the current interrupt enable state & disable IRQs
*/
+#define arch_local_irq_save arch_local_irq_save
static inline unsigned long arch_local_irq_save(void)
{
unsigned long flags, temp;
@@ -73,6 +77,7 @@ static inline unsigned long arch_local_irq_save(void)
/*
* Enable IRQs
*/
+#define arch_local_irq_enable arch_local_irq_enable
static inline void arch_local_irq_enable(void)
{
unsigned long temp;
@@ -88,6 +93,7 @@ static inline void arch_local_irq_enable(void)
/*
* Disable IRQs
*/
+#define arch_local_irq_disable arch_local_irq_disable
static inline void arch_local_irq_disable(void)
{
unsigned long temp;
@@ -135,6 +141,7 @@ static inline void arch_local_irq_disable(void)
/*
* Save the current interrupt enable state.
*/
+#define arch_local_save_flags arch_local_save_flags
static inline unsigned long arch_local_save_flags(void)
{
unsigned long flags;
@@ -147,6 +154,7 @@ static inline unsigned long arch_local_save_flags(void)
/*
* restore saved IRQ & FIQ state
*/
+#define arch_local_irq_restore arch_local_irq_restore
static inline void arch_local_irq_restore(unsigned long flags)
{
asm volatile(
@@ -156,10 +164,13 @@ static inline void arch_local_irq_restore(unsigned long flags)
: "memory", "cc");
}
+#define arch_irqs_disabled_flags arch_irqs_disabled_flags
static inline int arch_irqs_disabled_flags(unsigned long flags)
{
return flags & IRQMASK_I_BIT;
}
+#include <asm-generic/irqflags.h>
+
#endif /* ifdef __KERNEL__ */
#endif /* ifndef __ASM_ARM_IRQFLAGS_H */
diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 25410b2d8bc1..194c91b610ff 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -23,7 +23,7 @@
#define c0_MPIDR 1 /* MultiProcessor ID Register */
#define c0_CSSELR 2 /* Cache Size Selection Register */
#define c1_SCTLR 3 /* System Control Register */
-#define c1_ACTLR 4 /* Auxilliary Control Register */
+#define c1_ACTLR 4 /* Auxiliary Control Register */
#define c1_CPACR 5 /* Coprocessor Access Control */
#define c2_TTBR0 6 /* Translation Table Base Register 0 */
#define c2_TTBR0_high 7 /* TTBR0 top 32 bits */
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index d71607c16601..e896d2c196e6 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -218,11 +218,6 @@ static inline int kvm_arch_dev_ioctl_check_extension(long ext)
return 0;
}
-static inline void vgic_arch_setup(const struct vgic_params *vgic)
-{
- BUG_ON(vgic->type != VGIC_V2);
-}
-
int kvm_perf_init(void);
int kvm_perf_teardown(void);
diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h
index 0406cb3f1af7..cb3a40717edd 100644
--- a/arch/arm/include/asm/mach/arch.h
+++ b/arch/arm/include/asm/mach/arch.h
@@ -51,7 +51,7 @@ struct machine_desc {
bool (*smp_init)(void);
void (*fixup)(struct tag *, char **);
void (*dt_fixup)(void);
- void (*init_meminfo)(void);
+ long long (*pv_fixup)(void);
void (*reserve)(void);/* reserve mem blocks */
void (*map_io)(void);/* IO mapping function */
void (*init_early)(void);
diff --git a/arch/arm/include/asm/mcpm.h b/arch/arm/include/asm/mcpm.h
index 50b378f59e08..acd4983d9b1f 100644
--- a/arch/arm/include/asm/mcpm.h
+++ b/arch/arm/include/asm/mcpm.h
@@ -137,17 +137,12 @@ int mcpm_wait_for_cpu_powerdown(unsigned int cpu, unsigned int cluster);
/**
* mcpm_cpu_suspend - bring the calling CPU in a suspended state
*
- * @expected_residency: duration in microseconds the CPU is expected
- * to remain suspended, or 0 if unknown/infinity.
- *
- * The calling CPU is suspended. The expected residency argument is used
- * as a hint by the platform specific backend to implement the appropriate
- * sleep state level according to the knowledge it has on wake-up latency
- * for the given hardware.
+ * The calling CPU is suspended. This is similar to mcpm_cpu_power_down()
+ * except for possible extra platform specific configuration steps to allow
+ * an asynchronous wake-up e.g. with a pending interrupt.
*
* If this CPU is found to be the "last man standing" in the cluster
- * then the cluster may be prepared for power-down too, if the expected
- * residency makes it worthwhile.
+ * then the cluster may be prepared for power-down too.
*
* This must be called with interrupts disabled.
*
@@ -157,7 +152,7 @@ int mcpm_wait_for_cpu_powerdown(unsigned int cpu, unsigned int cluster);
* This will return if mcpm_platform_register() has not been called
* previously in which case the caller should take appropriate action.
*/
-void mcpm_cpu_suspend(u64 expected_residency);
+void mcpm_cpu_suspend(void);
/**
* mcpm_cpu_powered_up - housekeeping workafter a CPU has been powered up
@@ -234,12 +229,6 @@ struct mcpm_platform_ops {
void (*cpu_is_up)(unsigned int cpu, unsigned int cluster);
void (*cluster_is_up)(unsigned int cluster);
int (*wait_for_powerdown)(unsigned int cpu, unsigned int cluster);
-
- /* deprecated callbacks */
- int (*power_up)(unsigned int cpu, unsigned int cluster);
- void (*power_down)(void);
- void (*suspend)(u64);
- void (*powered_up)(void);
};
/**
@@ -251,35 +240,6 @@ struct mcpm_platform_ops {
*/
int __init mcpm_platform_register(const struct mcpm_platform_ops *ops);
-/* Synchronisation structures for coordinating safe cluster setup/teardown: */
-
-/*
- * When modifying this structure, make sure you update the MCPM_SYNC_ defines
- * to match.
- */
-struct mcpm_sync_struct {
- /* individual CPU states */
- struct {
- s8 cpu __aligned(__CACHE_WRITEBACK_GRANULE);
- } cpus[MAX_CPUS_PER_CLUSTER];
-
- /* cluster state */
- s8 cluster __aligned(__CACHE_WRITEBACK_GRANULE);
-
- /* inbound-side state */
- s8 inbound __aligned(__CACHE_WRITEBACK_GRANULE);
-};
-
-struct sync_struct {
- struct mcpm_sync_struct clusters[MAX_NR_CLUSTERS];
-};
-
-void __mcpm_cpu_going_down(unsigned int cpu, unsigned int cluster);
-void __mcpm_cpu_down(unsigned int cpu, unsigned int cluster);
-void __mcpm_outbound_leave_critical(unsigned int cluster, int state);
-bool __mcpm_outbound_enter_critical(unsigned int this_cpu, unsigned int cluster);
-int __mcpm_cluster_state(unsigned int cluster);
-
/**
* mcpm_sync_init - Initialize the cluster synchronization support
*
@@ -318,6 +278,29 @@ int __init mcpm_loopback(void (*cache_disable)(void));
void __init mcpm_smp_set_ops(void);
+/*
+ * Synchronisation structures for coordinating safe cluster setup/teardown.
+ * This is private to the MCPM core code and shared between C and assembly.
+ * When modifying this structure, make sure you update the MCPM_SYNC_ defines
+ * to match.
+ */
+struct mcpm_sync_struct {
+ /* individual CPU states */
+ struct {
+ s8 cpu __aligned(__CACHE_WRITEBACK_GRANULE);
+ } cpus[MAX_CPUS_PER_CLUSTER];
+
+ /* cluster state */
+ s8 cluster __aligned(__CACHE_WRITEBACK_GRANULE);
+
+ /* inbound-side state */
+ s8 inbound __aligned(__CACHE_WRITEBACK_GRANULE);
+};
+
+struct sync_struct {
+ struct mcpm_sync_struct clusters[MAX_NR_CLUSTERS];
+};
+
#else
/*
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 184def0e1652..3a72d69b3255 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -18,8 +18,6 @@
#include <linux/types.h>
#include <linux/sizes.h>
-#include <asm/cache.h>
-
#ifdef CONFIG_NEED_MACH_MEMORY_H
#include <mach/memory.h>
#endif
@@ -133,20 +131,6 @@
#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys)))
/*
- * Minimum guaranted alignment in pgd_alloc(). The page table pointers passed
- * around in head.S and proc-*.S are shifted by this amount, in order to
- * leave spare high bits for systems with physical address extension. This
- * does not fully accomodate the 40-bit addressing capability of ARM LPAE, but
- * gives us about 38-bits or so.
- */
-#ifdef CONFIG_ARM_LPAE
-#define ARCH_PGD_SHIFT L1_CACHE_SHIFT
-#else
-#define ARCH_PGD_SHIFT 0
-#endif
-#define ARCH_PGD_MASK ((1 << ARCH_PGD_SHIFT) - 1)
-
-/*
* PLAT_PHYS_OFFSET is the offset (from zero) of the start of physical
* memory. This is used for XIP and NoMMU kernels, and on platforms that don't
* have CONFIG_ARM_PATCH_PHYS_VIRT. Assembly code must always use
diff --git a/arch/arm/include/asm/mm-arch-hooks.h b/arch/arm/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..7056660c7cc4
--- /dev/null
+++ b/arch/arm/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_ARM_MM_ARCH_HOOKS_H
+#define _ASM_ARM_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_ARM_MM_ARCH_HOOKS_H */
diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h
index ed690c49ef93..e358b7966c06 100644
--- a/arch/arm/include/asm/module.h
+++ b/arch/arm/include/asm/module.h
@@ -16,11 +16,21 @@ enum {
ARM_SEC_UNLIKELY,
ARM_SEC_MAX,
};
+#endif
struct mod_arch_specific {
+#ifdef CONFIG_ARM_UNWIND
struct unwind_table *unwind[ARM_SEC_MAX];
-};
#endif
+#ifdef CONFIG_ARM_MODULE_PLTS
+ struct elf32_shdr *core_plt;
+ struct elf32_shdr *init_plt;
+ int core_plt_count;
+ int init_plt_count;
+#endif
+};
+
+u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val);
/*
* Add the ARM architecture version to the version magic string
diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
index 585dc33a7a24..a5635444ca41 100644
--- a/arch/arm/include/asm/pci.h
+++ b/arch/arm/include/asm/pci.h
@@ -31,16 +31,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)
*/
#define PCI_DMA_BUS_IS_PHYS (1)
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- *strat = PCI_DMA_BURST_INFINITY;
- *strategy_parameter = ~0UL;
-}
-#endif
-
#define HAVE_PCI_MMAP
extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index d9cf138fd7d4..4f9dec489931 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -19,4 +19,11 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs);
#define perf_misc_flags(regs) perf_misc_flags(regs)
#endif
+#define perf_arch_fetch_caller_regs(regs, __ip) { \
+ (regs)->ARM_pc = (__ip); \
+ (regs)->ARM_fp = (unsigned long) __builtin_frame_address(0); \
+ (regs)->ARM_sp = current_stack_pointer; \
+ (regs)->ARM_cpsr = SVC_MODE; \
+}
+
#endif /* __ARM_PERF_EVENT_H__ */
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 675e4ab79f68..3fc87dfd77e6 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -24,22 +24,10 @@
* interrupt and passed the address of the low level handler,
* and can be used to implement any platform specific handling
* before or after calling it.
- * @runtime_resume: an optional handler which will be called by the
- * runtime PM framework following a call to pm_runtime_get().
- * Note that if pm_runtime_get() is called more than once in
- * succession this handler will only be called once.
- * @runtime_suspend: an optional handler which will be called by the
- * runtime PM framework following a call to pm_runtime_put().
- * Note that if pm_runtime_get() is called more than once in
- * succession this handler will only be called following the
- * final call to pm_runtime_put() that actually disables the
- * hardware.
*/
struct arm_pmu_platdata {
irqreturn_t (*handle_irq)(int irq, void *dev,
irq_handler_t pmu_handler);
- int (*runtime_resume)(struct device *dev);
- int (*runtime_suspend)(struct device *dev);
};
#ifdef CONFIG_HW_PERF_EVENTS
@@ -92,6 +80,7 @@ struct pmu_hw_events {
struct arm_pmu {
struct pmu pmu;
cpumask_t active_irqs;
+ cpumask_t supported_cpus;
int *irq_affinity;
char *name;
irqreturn_t (*handle_irq)(int irq_num, void *dev);
@@ -122,8 +111,6 @@ struct arm_pmu {
#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
-extern const struct dev_pm_ops armpmu_dev_pm_ops;
-
int armpmu_register(struct arm_pmu *armpmu, int type);
u64 armpmu_event_update(struct perf_event *event);
@@ -158,6 +145,10 @@ struct pmu_probe_info {
#define XSCALE_PMU_PROBE(_version, _fn) \
PMU_PROBE(ARM_CPU_IMP_INTEL << 24 | _version, ARM_PMU_XSCALE_MASK, _fn)
+int arm_pmu_device_probe(struct platform_device *pdev,
+ const struct of_device_id *of_table,
+ const struct pmu_probe_info *probe_table);
+
#endif /* CONFIG_HW_PERF_EVENTS */
#endif /* __ARM_PMU_H__ */
diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
index 5324c1112f3a..8877ad5ffe10 100644
--- a/arch/arm/include/asm/proc-fns.h
+++ b/arch/arm/include/asm/proc-fns.h
@@ -125,13 +125,6 @@ extern void cpu_resume(void);
ttbr; \
})
-#define cpu_set_ttbr(nr, val) \
- do { \
- u64 ttbr = val; \
- __asm__("mcrr p15, " #nr ", %Q0, %R0, c2" \
- : : "r" (ttbr)); \
- } while (0)
-
#define cpu_get_pgd() \
({ \
u64 pg = cpu_get_ttbr(0); \
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 18f5a554134f..2f3ac1ba6fb4 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -61,7 +61,7 @@ asmlinkage void secondary_start_kernel(void);
struct secondary_data {
union {
unsigned long mpu_rgn_szr;
- unsigned long pgdir;
+ u64 pgdir;
};
unsigned long swapper_pg_dir;
void *stack;
@@ -69,6 +69,7 @@ struct secondary_data {
extern struct secondary_data secondary_data;
extern volatile int pen_release;
extern void secondary_startup(void);
+extern void secondary_startup_arm(void);
extern int __cpu_disable(void);
diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h
index cd20029bcd94..6c7182f32cef 100644
--- a/arch/arm/include/asm/suspend.h
+++ b/arch/arm/include/asm/suspend.h
@@ -7,6 +7,7 @@ struct sleep_save_sp {
};
extern void cpu_resume(void);
+extern void cpu_resume_arm(void);
extern int cpu_suspend(unsigned long, int (*)(unsigned long));
#endif
diff --git a/arch/arm/include/asm/system_info.h b/arch/arm/include/asm/system_info.h
index 720ea0320a6d..3860cbd401ec 100644
--- a/arch/arm/include/asm/system_info.h
+++ b/arch/arm/include/asm/system_info.h
@@ -17,6 +17,7 @@
/* information about the system we're running on */
extern unsigned int system_rev;
+extern const char *system_serial;
extern unsigned int system_serial_low;
extern unsigned int system_serial_high;
extern unsigned int mem_fclk_21285;
diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
index 2fe85fff5cca..370f7a732900 100644
--- a/arch/arm/include/asm/topology.h
+++ b/arch/arm/include/asm/topology.h
@@ -18,7 +18,7 @@ extern struct cputopo_arm cpu_topology[NR_CPUS];
#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
-#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
+#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
void init_cpu_topology(void);
void store_cpu_topology(unsigned int cpuid);
diff --git a/arch/arm/include/asm/unified.h b/arch/arm/include/asm/unified.h
index 200f9a7cd623..a91ae499614c 100644
--- a/arch/arm/include/asm/unified.h
+++ b/arch/arm/include/asm/unified.h
@@ -45,7 +45,6 @@
#define THUMB(x...) x
#ifdef __ASSEMBLY__
#define W(instr) instr.w
-#define BSYM(sym) sym + 1
#else
#define WASM(instr) #instr ".w"
#endif
@@ -59,7 +58,6 @@
#define THUMB(x...)
#ifdef __ASSEMBLY__
#define W(instr) instr
-#define BSYM(sym) sym
#else
#define WASM(instr) #instr
#endif
diff --git a/arch/arm/include/asm/vfp.h b/arch/arm/include/asm/vfp.h
index ee5f3084243c..22e414056a8c 100644
--- a/arch/arm/include/asm/vfp.h
+++ b/arch/arm/include/asm/vfp.h
@@ -5,6 +5,9 @@
* First, the standard VFP set.
*/
+#ifndef __ASM_VFP_H
+#define __ASM_VFP_H
+
#define FPSID cr0
#define FPSCR cr1
#define MVFR1 cr6
@@ -87,3 +90,9 @@
#define VFPOPDESC_UNUSED_BIT (24)
#define VFPOPDESC_UNUSED_MASK (0xFF << VFPOPDESC_UNUSED_BIT)
#define VFPOPDESC_OPDESC_MASK (~(VFPOPDESC_LENGTH_MASK | VFPOPDESC_UNUSED_MASK))
+
+#ifndef __ASSEMBLY__
+void vfp_disable(void);
+#endif
+
+#endif /* __ASM_VFP_H */
diff --git a/arch/arm/include/debug/8250.S b/arch/arm/include/debug/8250.S
index 7a2baf913aa0..7f7446f6f806 100644
--- a/arch/arm/include/debug/8250.S
+++ b/arch/arm/include/debug/8250.S
@@ -16,11 +16,14 @@
#ifdef CONFIG_DEBUG_UART_8250_WORD
.macro store, rd, rx:vararg
+ ARM_BE8(rev \rd, \rd)
str \rd, \rx
+ ARM_BE8(rev \rd, \rd)
.endm
.macro load, rd, rx:vararg
ldr \rd, \rx
+ ARM_BE8(rev \rd, \rd)
.endm
#else
.macro store, rd, rx:vararg
diff --git a/arch/arm/include/debug/efm32.S b/arch/arm/include/debug/efm32.S
index 2265a199280c..660fa1e4b77b 100644
--- a/arch/arm/include/debug/efm32.S
+++ b/arch/arm/include/debug/efm32.S
@@ -16,7 +16,7 @@
#define UARTn_TXDATA 0x0034
- .macro addruart, rx, tmp
+ .macro addruart, rx, tmp, tmp2
ldr \rx, =(CONFIG_DEBUG_UART_PHYS)
/*
diff --git a/arch/arm/include/debug/imx-uart.h b/arch/arm/include/debug/imx-uart.h
index 032a316eb802..66f736f74684 100644
--- a/arch/arm/include/debug/imx-uart.h
+++ b/arch/arm/include/debug/imx-uart.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012-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 version 2 as
@@ -90,6 +90,16 @@
#define IMX6SX_UART_BASE_ADDR(n) IMX6SX_UART##n##_BASE_ADDR
#define IMX6SX_UART_BASE(n) IMX6SX_UART_BASE_ADDR(n)
+#define IMX7D_UART1_BASE_ADDR 0x30860000
+#define IMX7D_UART2_BASE_ADDR 0x30890000
+#define IMX7D_UART3_BASE_ADDR 0x30880000
+#define IMX7D_UART4_BASE_ADDR 0x30a60000
+#define IMX7D_UART5_BASE_ADDR 0x30a70000
+#define IMX7D_UART6_BASE_ADDR 0x30a80000
+#define IMX7D_UART7_BASE_ADDR 0x30a90000
+#define IMX7D_UART_BASE_ADDR(n) IMX7D_UART##n##_BASE_ADDR
+#define IMX7D_UART_BASE(n) IMX7D_UART_BASE_ADDR(n)
+
#define IMX_DEBUG_UART_BASE(soc) soc##_UART_BASE(CONFIG_DEBUG_IMX_UART_PORT)
#ifdef CONFIG_DEBUG_IMX1_UART
@@ -114,6 +124,9 @@
#define UART_PADDR IMX_DEBUG_UART_BASE(IMX6SL)
#elif defined(CONFIG_DEBUG_IMX6SX_UART)
#define UART_PADDR IMX_DEBUG_UART_BASE(IMX6SX)
+#elif defined(CONFIG_DEBUG_IMX7D_UART)
+#define UART_PADDR IMX_DEBUG_UART_BASE(IMX7D)
+
#endif
#endif /* __DEBUG_IMX_UART_H */
diff --git a/arch/arm/include/debug/pl01x.S b/arch/arm/include/debug/pl01x.S
index 92ef808a2337..f7d8323cefcc 100644
--- a/arch/arm/include/debug/pl01x.S
+++ b/arch/arm/include/debug/pl01x.S
@@ -12,6 +12,13 @@
*/
#include <linux/amba/serial.h>
+#ifdef CONFIG_DEBUG_ZTE_ZX
+#undef UART01x_DR
+#undef UART01x_FR
+#define UART01x_DR 0x04
+#define UART01x_FR 0x14
+#endif
+
#ifdef CONFIG_DEBUG_UART_PHYS
.macro addruart, rp, rv, tmp
ldr \rp, =CONFIG_DEBUG_UART_PHYS
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 752725dcbf42..e69f7a19735d 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_ISA_DMA_API) += dma.o
obj-$(CONFIG_FIQ) += fiq.o fiqasm.o
obj-$(CONFIG_MODULES) += armksyms.o module.o
+obj-$(CONFIG_ARM_MODULE_PLTS) += module-plts.o
obj-$(CONFIG_ISA_DMA) += dma-isa.o
obj-$(CONFIG_PCI) += bios32.o isa.o
obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o
@@ -70,7 +71,9 @@ obj-$(CONFIG_CPU_PJ4) += pj4-cp0.o
obj-$(CONFIG_CPU_PJ4B) += pj4-cp0.o
obj-$(CONFIG_IWMMXT) += iwmmxt.o
obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_event_cpu.o
+obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o \
+ perf_event_xscale.o perf_event_v6.o \
+ perf_event_v7.o
CFLAGS_pj4-cp0.o := -marm
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S
index 78c91b5f97d4..ea9646cc2a0e 100644
--- a/arch/arm/kernel/debug.S
+++ b/arch/arm/kernel/debug.S
@@ -35,7 +35,7 @@
#else /* !CONFIG_MMU */
.macro addruart_current, rx, tmp1, tmp2
- addruart \rx, \tmp1
+ addruart \rx, \tmp1, \tmp2
.endm
#endif /* CONFIG_MMU */
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 570306c49406..f8f7398c74c2 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -40,7 +40,7 @@
#ifdef CONFIG_MULTI_IRQ_HANDLER
ldr r1, =handle_arch_irq
mov r0, sp
- adr lr, BSYM(9997f)
+ badr lr, 9997f
ldr pc, [r1]
#else
arch_irq_handler_default
@@ -273,7 +273,7 @@ __und_svc:
str r4, [sp, #S_PC]
orr r0, r9, r0, lsl #16
#endif
- adr r9, BSYM(__und_svc_finish)
+ badr r9, __und_svc_finish
mov r2, r4
bl call_fpe
@@ -469,7 +469,7 @@ __und_usr:
@ instruction, or the more conventional lr if we are to treat
@ this as a real undefined instruction
@
- adr r9, BSYM(ret_from_exception)
+ badr r9, ret_from_exception
@ IRQs must be enabled before attempting to read the instruction from
@ user space since that could cause a page/translation fault if the
@@ -486,7 +486,7 @@ __und_usr:
@ r2 = PC value for the following instruction (:= regs->ARM_pc)
@ r4 = PC value for the faulting instruction
@ lr = 32-bit undefined instruction function
- adr lr, BSYM(__und_usr_fault_32)
+ badr lr, __und_usr_fault_32
b call_fpe
__und_usr_thumb:
@@ -522,7 +522,7 @@ ARM_BE8(rev16 r0, r0) @ little endian instruction
add r2, r2, #2 @ r2 is PC + 2, make it PC + 4
str r2, [sp, #S_PC] @ it's a 2x16bit instr, update
orr r0, r0, r5, lsl #16
- adr lr, BSYM(__und_usr_fault_32)
+ badr lr, __und_usr_fault_32
@ r0 = the two 16-bit Thumb instructions which caused the exception
@ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc)
@ r4 = PC value for the first 16-bit Thumb instruction
@@ -716,7 +716,7 @@ __und_usr_fault_32:
__und_usr_fault_16:
mov r1, #2
1: mov r0, sp
- adr lr, BSYM(ret_from_exception)
+ badr lr, ret_from_exception
b __und_fault
ENDPROC(__und_usr_fault_32)
ENDPROC(__und_usr_fault_16)
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 4e7f40c577e6..92828a1dec80 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -90,7 +90,7 @@ ENTRY(ret_from_fork)
bl schedule_tail
cmp r5, #0
movne r0, r4
- adrne lr, BSYM(1f)
+ badrne lr, 1f
retne r5
1: get_thread_info tsk
b ret_slow_syscall
@@ -198,7 +198,7 @@ local_restart:
bne __sys_trace
cmp scno, #NR_syscalls @ check upper syscall limit
- adr lr, BSYM(ret_fast_syscall) @ return address
+ badr lr, ret_fast_syscall @ return address
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
add r1, sp, #S_OFF
@@ -233,7 +233,7 @@ __sys_trace:
add r0, sp, #S_OFF
bl syscall_trace_enter
- adr lr, BSYM(__sys_trace_return) @ return address
+ badr lr, __sys_trace_return @ return address
mov scno, r0 @ syscall number (possibly new)
add r1, sp, #S_R0 + S_OFF @ pointer to regs
cmp scno, #NR_syscalls @ check upper syscall limit
diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S
index fe57c73e70a4..c73c4030ca5d 100644
--- a/arch/arm/kernel/entry-ftrace.S
+++ b/arch/arm/kernel/entry-ftrace.S
@@ -87,7 +87,7 @@
1: mcount_get_lr r1 @ lr of instrumented func
mcount_adjust_addr r0, lr @ instrumented function
- adr lr, BSYM(2f)
+ badr lr, 2f
mov pc, r2
2: mcount_exit
.endm
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
index 8944f4991c3c..b6c8bb9315e7 100644
--- a/arch/arm/kernel/entry-v7m.S
+++ b/arch/arm/kernel/entry-v7m.S
@@ -117,9 +117,14 @@ ENTRY(__switch_to)
ENDPROC(__switch_to)
.data
- .align 8
+#if CONFIG_CPU_V7M_NUM_IRQ <= 112
+ .align 9
+#else
+ .align 10
+#endif
+
/*
- * Vector table (64 words => 256 bytes natural alignment)
+ * Vector table (Natural alignment need to be ensured)
*/
ENTRY(vector_table)
.long 0 @ 0 - Reset stack pointer
@@ -138,6 +143,6 @@ ENTRY(vector_table)
.long __invalid_entry @ 13 - Reserved
.long __pendsv_entry @ 14 - PendSV
.long __invalid_entry @ 15 - SysTick
- .rept 64 - 16
- .long __irq_entry @ 16..64 - External Interrupts
+ .rept CONFIG_CPU_V7M_NUM_IRQ
+ .long __irq_entry @ External Interrupts
.endr
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index aebfbf79a1a3..9b8c5a113434 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -46,7 +46,7 @@ ENTRY(stext)
.arm
ENTRY(stext)
- THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM.
+ THUMB( badr r9, 1f ) @ Kernel is always entered in ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB(1: )
@@ -77,13 +77,13 @@ ENTRY(stext)
orr r6, r6, #(1 << MPU_RSR_EN) @ Set region enabled bit
bl __setup_mpu
#endif
- ldr r13, =__mmap_switched @ address to jump to after
- @ initialising sctlr
- adr lr, BSYM(1f) @ return (PIC) address
+
+ badr lr, 1f @ return (PIC) address
ldr r12, [r10, #PROCINFO_INITFUNC]
add r12, r12, r10
ret r12
- 1: b __after_proc_init
+1: bl __after_proc_init
+ b __mmap_switched
ENDPROC(stext)
#ifdef CONFIG_SMP
@@ -106,8 +106,7 @@ ENTRY(secondary_startup)
movs r10, r5 @ invalid processor?
beq __error_p @ yes, error 'p'
- adr r4, __secondary_data
- ldmia r4, {r7, r12}
+ ldr r7, __secondary_data
#ifdef CONFIG_ARM_MPU
/* Use MPU region info supplied by __cpu_up */
@@ -115,23 +114,19 @@ ENTRY(secondary_startup)
bl __setup_mpu @ Initialize the MPU
#endif
- adr lr, BSYM(__after_proc_init) @ return address
- mov r13, r12 @ __secondary_switched address
+ badr lr, 1f @ return (PIC) address
ldr r12, [r10, #PROCINFO_INITFUNC]
add r12, r12, r10
ret r12
-ENDPROC(secondary_startup)
-
-ENTRY(__secondary_switched)
- ldr sp, [r7, #8] @ set up the stack pointer
+1: bl __after_proc_init
+ ldr sp, [r7, #12] @ set up the stack pointer
mov fp, #0
b secondary_start_kernel
-ENDPROC(__secondary_switched)
+ENDPROC(secondary_startup)
.type __secondary_data, %object
__secondary_data:
.long secondary_data
- .long __secondary_switched
#endif /* CONFIG_SMP */
/*
@@ -164,7 +159,7 @@ __after_proc_init:
#endif
mcr p15, 0, r0, c1, c0, 0 @ write control reg
#endif /* CONFIG_CPU_CP15 */
- ret r13
+ ret lr
ENDPROC(__after_proc_init)
.ltorg
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 3637973a9708..bd755d97e459 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -80,7 +80,7 @@
ENTRY(stext)
ARM_BE8(setend be ) @ ensure we are in BE8 mode
- THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM.
+ THUMB( badr r9, 1f ) @ Kernel is always entered in ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB(1: )
@@ -131,13 +131,30 @@ ENTRY(stext)
* The following calls CPU specific code in a position independent
* manner. See arch/arm/mm/proc-*.S for details. r10 = base of
* xxx_proc_info structure selected by __lookup_processor_type
- * above. On return, the CPU will be ready for the MMU to be
- * turned on, and r0 will hold the CPU control register value.
+ * above.
+ *
+ * The processor init function will be called with:
+ * r1 - machine type
+ * r2 - boot data (atags/dt) pointer
+ * r4 - translation table base (low word)
+ * r5 - translation table base (high word, if LPAE)
+ * r8 - translation table base 1 (pfn if LPAE)
+ * r9 - cpuid
+ * r13 - virtual address for __enable_mmu -> __turn_mmu_on
+ *
+ * On return, the CPU will be ready for the MMU to be turned on,
+ * r0 will hold the CPU control register value, r1, r2, r4, and
+ * r9 will be preserved. r5 will also be preserved if LPAE.
*/
ldr r13, =__mmap_switched @ address to jump to after
@ mmu has been enabled
- adr lr, BSYM(1f) @ return (PIC) address
+ badr lr, 1f @ return (PIC) address
+#ifdef CONFIG_ARM_LPAE
+ mov r5, #0 @ high TTBR0
+ mov r8, r4, lsr #12 @ TTBR1 is swapper_pg_dir pfn
+#else
mov r8, r4 @ set TTBR1 to swapper_pg_dir
+#endif
ldr r12, [r10, #PROCINFO_INITFUNC]
add r12, r12, r10
ret r12
@@ -158,7 +175,7 @@ ENDPROC(stext)
*
* Returns:
* r0, r3, r5-r7 corrupted
- * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
+ * r4 = physical page table address
*/
__create_page_tables:
pgtbl r4, r8 @ page table address
@@ -333,7 +350,6 @@ __create_page_tables:
#endif
#ifdef CONFIG_ARM_LPAE
sub r4, r4, #0x1000 @ point to the PGD table
- mov r4, r4, lsr #ARCH_PGD_SHIFT
#endif
ret lr
ENDPROC(__create_page_tables)
@@ -346,9 +362,9 @@ __turn_mmu_on_loc:
#if defined(CONFIG_SMP)
.text
-ENTRY(secondary_startup_arm)
.arm
- THUMB( adr r9, BSYM(1f) ) @ Kernel is entered in ARM.
+ENTRY(secondary_startup_arm)
+ THUMB( badr r9, 1f ) @ Kernel is entered in ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB(1: )
@@ -381,10 +397,10 @@ ENTRY(secondary_startup)
adr r4, __secondary_data
ldmia r4, {r5, r7, r12} @ address to jump to after
sub lr, r4, r5 @ mmu has been enabled
- ldr r4, [r7, lr] @ get secondary_data.pgdir
- add r7, r7, #4
- ldr r8, [r7, lr] @ get secondary_data.swapper_pg_dir
- adr lr, BSYM(__enable_mmu) @ return address
+ add r3, r7, lr
+ ldrd r4, [r3, #0] @ get secondary_data.pgdir
+ ldr r8, [r3, #8] @ get secondary_data.swapper_pg_dir
+ badr lr, __enable_mmu @ return address
mov r13, r12 @ __secondary_switched address
ldr r12, [r10, #PROCINFO_INITFUNC]
add r12, r12, r10 @ initialise processor
@@ -397,7 +413,7 @@ ENDPROC(secondary_startup_arm)
* r6 = &secondary_data
*/
ENTRY(__secondary_switched)
- ldr sp, [r7, #4] @ get secondary_data.stack
+ ldr sp, [r7, #12] @ get secondary_data.stack
mov fp, #0
b secondary_start_kernel
ENDPROC(__secondary_switched)
@@ -416,12 +432,14 @@ __secondary_data:
/*
* Setup common bits before finally enabling the MMU. Essentially
* this is just loading the page table pointer and domain access
- * registers.
+ * registers. All these registers need to be preserved by the
+ * processor setup function (or set in the case of r0)
*
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags or dtb pointer
- * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
+ * r4 = TTBR pointer (low word)
+ * r5 = TTBR pointer (high word if LPAE)
* r9 = processor ID
* r13 = *virtual* address to jump to upon completion
*/
@@ -440,7 +458,9 @@ __enable_mmu:
#ifdef CONFIG_CPU_ICACHE_DISABLE
bic r0, r0, #CR_I
#endif
-#ifndef CONFIG_ARM_LPAE
+#ifdef CONFIG_ARM_LPAE
+ mcrr p15, 0, r4, r5, c2 @ load TTBR0
+#else
mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c
new file mode 100644
index 000000000000..097e2e201b9f
--- /dev/null
+++ b/arch/arm/kernel/module-plts.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
+ *
+ * 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/elf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/cache.h>
+#include <asm/opcodes.h>
+
+#define PLT_ENT_STRIDE L1_CACHE_BYTES
+#define PLT_ENT_COUNT (PLT_ENT_STRIDE / sizeof(u32))
+#define PLT_ENT_SIZE (sizeof(struct plt_entries) / PLT_ENT_COUNT)
+
+#ifdef CONFIG_THUMB2_KERNEL
+#define PLT_ENT_LDR __opcode_to_mem_thumb32(0xf8dff000 | \
+ (PLT_ENT_STRIDE - 4))
+#else
+#define PLT_ENT_LDR __opcode_to_mem_arm(0xe59ff000 | \
+ (PLT_ENT_STRIDE - 8))
+#endif
+
+struct plt_entries {
+ u32 ldr[PLT_ENT_COUNT];
+ u32 lit[PLT_ENT_COUNT];
+};
+
+static bool in_init(const struct module *mod, u32 addr)
+{
+ return addr - (u32)mod->module_init < mod->init_size;
+}
+
+u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
+{
+ struct plt_entries *plt, *plt_end;
+ int c, *count;
+
+ if (in_init(mod, loc)) {
+ plt = (void *)mod->arch.init_plt->sh_addr;
+ plt_end = (void *)plt + mod->arch.init_plt->sh_size;
+ count = &mod->arch.init_plt_count;
+ } else {
+ plt = (void *)mod->arch.core_plt->sh_addr;
+ plt_end = (void *)plt + mod->arch.core_plt->sh_size;
+ count = &mod->arch.core_plt_count;
+ }
+
+ /* Look for an existing entry pointing to 'val' */
+ for (c = *count; plt < plt_end; c -= PLT_ENT_COUNT, plt++) {
+ int i;
+
+ if (!c) {
+ /* Populate a new set of entries */
+ *plt = (struct plt_entries){
+ { [0 ... PLT_ENT_COUNT - 1] = PLT_ENT_LDR, },
+ { val, }
+ };
+ ++*count;
+ return (u32)plt->ldr;
+ }
+ for (i = 0; i < PLT_ENT_COUNT; i++) {
+ if (!plt->lit[i]) {
+ plt->lit[i] = val;
+ ++*count;
+ }
+ if (plt->lit[i] == val)
+ return (u32)&plt->ldr[i];
+ }
+ }
+ BUG();
+}
+
+static int duplicate_rel(Elf32_Addr base, const Elf32_Rel *rel, int num,
+ u32 mask)
+{
+ u32 *loc1, *loc2;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ if (rel[i].r_info != rel[num].r_info)
+ continue;
+
+ /*
+ * Identical relocation types against identical symbols can
+ * still result in different PLT entries if the addend in the
+ * place is different. So resolve the target of the relocation
+ * to compare the values.
+ */
+ loc1 = (u32 *)(base + rel[i].r_offset);
+ loc2 = (u32 *)(base + rel[num].r_offset);
+ if (((*loc1 ^ *loc2) & mask) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+/* Count how many PLT entries we may need */
+static unsigned int count_plts(Elf32_Addr base, const Elf32_Rel *rel, int num)
+{
+ unsigned int ret = 0;
+ int i;
+
+ /*
+ * Sure, this is order(n^2), but it's usually short, and not
+ * time critical
+ */
+ for (i = 0; i < num; i++)
+ switch (ELF32_R_TYPE(rel[i].r_info)) {
+ case R_ARM_CALL:
+ case R_ARM_PC24:
+ case R_ARM_JUMP24:
+ if (!duplicate_rel(base, rel, i,
+ __opcode_to_mem_arm(0x00ffffff)))
+ ret++;
+ break;
+#ifdef CONFIG_THUMB2_KERNEL
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24:
+ if (!duplicate_rel(base, rel, i,
+ __opcode_to_mem_thumb32(0x07ff2fff)))
+ ret++;
+#endif
+ }
+ return ret;
+}
+
+int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
+ char *secstrings, struct module *mod)
+{
+ unsigned long core_plts = 0, init_plts = 0;
+ Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum;
+
+ /*
+ * To store the PLTs, we expand the .text section for core module code
+ * and the .init.text section for initialization code.
+ */
+ for (s = sechdrs; s < sechdrs_end; ++s)
+ if (strcmp(".core.plt", secstrings + s->sh_name) == 0)
+ mod->arch.core_plt = s;
+ else if (strcmp(".init.plt", secstrings + s->sh_name) == 0)
+ mod->arch.init_plt = s;
+
+ if (!mod->arch.core_plt || !mod->arch.init_plt) {
+ pr_err("%s: sections missing\n", mod->name);
+ return -ENOEXEC;
+ }
+
+ for (s = sechdrs + 1; s < sechdrs_end; ++s) {
+ const Elf32_Rel *rels = (void *)ehdr + s->sh_offset;
+ int numrels = s->sh_size / sizeof(Elf32_Rel);
+ Elf32_Shdr *dstsec = sechdrs + s->sh_info;
+
+ if (s->sh_type != SHT_REL)
+ continue;
+
+ if (strstr(secstrings + s->sh_name, ".init"))
+ init_plts += count_plts(dstsec->sh_addr, rels, numrels);
+ else
+ core_plts += count_plts(dstsec->sh_addr, rels, numrels);
+ }
+
+ mod->arch.core_plt->sh_type = SHT_NOBITS;
+ mod->arch.core_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+ mod->arch.core_plt->sh_addralign = L1_CACHE_BYTES;
+ mod->arch.core_plt->sh_size = round_up(core_plts * PLT_ENT_SIZE,
+ sizeof(struct plt_entries));
+ mod->arch.core_plt_count = 0;
+
+ mod->arch.init_plt->sh_type = SHT_NOBITS;
+ mod->arch.init_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+ mod->arch.init_plt->sh_addralign = L1_CACHE_BYTES;
+ mod->arch.init_plt->sh_size = round_up(init_plts * PLT_ENT_SIZE,
+ sizeof(struct plt_entries));
+ mod->arch.init_plt_count = 0;
+ pr_debug("%s: core.plt=%x, init.plt=%x\n", __func__,
+ mod->arch.core_plt->sh_size, mod->arch.init_plt->sh_size);
+ return 0;
+}
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index af791f4a6205..efdddcb97dd1 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -40,7 +40,12 @@
#ifdef CONFIG_MMU
void *module_alloc(unsigned long size)
{
- return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
+ void *p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
+ GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
+ __builtin_return_address(0));
+ if (!IS_ENABLED(CONFIG_ARM_MODULE_PLTS) || p)
+ return p;
+ return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
__builtin_return_address(0));
}
@@ -110,6 +115,20 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
offset -= 0x04000000;
offset += sym->st_value - loc;
+
+ /*
+ * Route through a PLT entry if 'offset' exceeds the
+ * supported range. Note that 'offset + loc + 8'
+ * contains the absolute jump target, i.e.,
+ * @sym + addend, corrected for the +8 PC bias.
+ */
+ if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS) &&
+ (offset <= (s32)0xfe000000 ||
+ offset >= (s32)0x02000000))
+ offset = get_module_plt(module, loc,
+ offset + loc + 8)
+ - loc - 8;
+
if (offset <= (s32)0xfe000000 ||
offset >= (s32)0x02000000) {
pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
@@ -203,6 +222,17 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
offset -= 0x02000000;
offset += sym->st_value - loc;
+ /*
+ * Route through a PLT entry if 'offset' exceeds the
+ * supported range.
+ */
+ if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS) &&
+ (offset <= (s32)0xff000000 ||
+ offset >= (s32)0x01000000))
+ offset = get_module_plt(module, loc,
+ offset + loc + 4)
+ - loc - 4;
+
if (offset <= (s32)0xff000000 ||
offset >= (s32)0x01000000) {
pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
diff --git a/arch/arm/kernel/module.lds b/arch/arm/kernel/module.lds
new file mode 100644
index 000000000000..3682fa107918
--- /dev/null
+++ b/arch/arm/kernel/module.lds
@@ -0,0 +1,4 @@
+SECTIONS {
+ .core.plt : { BYTE(0) }
+ .init.plt : { BYTE(0) }
+}
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 4a86a0133ac3..357f57ea83f4 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -11,12 +11,18 @@
*/
#define pr_fmt(fmt) "hw perfevents: " fmt
+#include <linux/bitmap.h>
+#include <linux/cpumask.h>
+#include <linux/export.h>
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
#include <linux/irq.h>
#include <linux/irqdesc.h>
+#include <asm/cputype.h>
#include <asm/irq_regs.h>
#include <asm/pmu.h>
@@ -229,6 +235,10 @@ armpmu_add(struct perf_event *event, int flags)
int idx;
int err = 0;
+ /* An event following a process won't be stopped earlier */
+ if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus))
+ return -ENOENT;
+
perf_pmu_disable(event->pmu);
/* If we don't have a space for the counter then finish early. */
@@ -344,20 +354,12 @@ static void
armpmu_release_hardware(struct arm_pmu *armpmu)
{
armpmu->free_irq(armpmu);
- pm_runtime_put_sync(&armpmu->plat_device->dev);
}
static int
armpmu_reserve_hardware(struct arm_pmu *armpmu)
{
- int err;
- struct platform_device *pmu_device = armpmu->plat_device;
-
- if (!pmu_device)
- return -ENODEV;
-
- pm_runtime_get_sync(&pmu_device->dev);
- err = armpmu->request_irq(armpmu, armpmu_dispatch_irq);
+ int err = armpmu->request_irq(armpmu, armpmu_dispatch_irq);
if (err) {
armpmu_release_hardware(armpmu);
return err;
@@ -454,6 +456,17 @@ static int armpmu_event_init(struct perf_event *event)
int err = 0;
atomic_t *active_events = &armpmu->active_events;
+ /*
+ * Reject CPU-affine events for CPUs that are of a different class to
+ * that which this PMU handles. Process-following events (where
+ * event->cpu == -1) can be migrated between CPUs, and thus we have to
+ * reject them later (in armpmu_add) if they're scheduled on a
+ * different class of CPU.
+ */
+ if (event->cpu != -1 &&
+ !cpumask_test_cpu(event->cpu, &armpmu->supported_cpus))
+ return -ENOENT;
+
/* does not support taken branch sampling */
if (has_branch_stack(event))
return -EOPNOTSUPP;
@@ -489,6 +502,10 @@ static void armpmu_enable(struct pmu *pmu)
struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events);
int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
+ /* For task-bound events we may be called on other CPUs */
+ if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus))
+ return;
+
if (enabled)
armpmu->start(armpmu);
}
@@ -496,34 +513,25 @@ static void armpmu_enable(struct pmu *pmu)
static void armpmu_disable(struct pmu *pmu)
{
struct arm_pmu *armpmu = to_arm_pmu(pmu);
- armpmu->stop(armpmu);
-}
-
-#ifdef CONFIG_PM
-static int armpmu_runtime_resume(struct device *dev)
-{
- struct arm_pmu_platdata *plat = dev_get_platdata(dev);
- if (plat && plat->runtime_resume)
- return plat->runtime_resume(dev);
+ /* For task-bound events we may be called on other CPUs */
+ if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus))
+ return;
- return 0;
+ armpmu->stop(armpmu);
}
-static int armpmu_runtime_suspend(struct device *dev)
+/*
+ * In heterogeneous systems, events are specific to a particular
+ * microarchitecture, and aren't suitable for another. Thus, only match CPUs of
+ * the same microarchitecture.
+ */
+static int armpmu_filter_match(struct perf_event *event)
{
- struct arm_pmu_platdata *plat = dev_get_platdata(dev);
-
- if (plat && plat->runtime_suspend)
- return plat->runtime_suspend(dev);
-
- return 0;
+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+ unsigned int cpu = smp_processor_id();
+ return cpumask_test_cpu(cpu, &armpmu->supported_cpus);
}
-#endif
-
-const struct dev_pm_ops armpmu_dev_pm_ops = {
- SET_RUNTIME_PM_OPS(armpmu_runtime_suspend, armpmu_runtime_resume, NULL)
-};
static void armpmu_init(struct arm_pmu *armpmu)
{
@@ -539,15 +547,349 @@ static void armpmu_init(struct arm_pmu *armpmu)
.start = armpmu_start,
.stop = armpmu_stop,
.read = armpmu_read,
+ .filter_match = armpmu_filter_match,
};
}
int armpmu_register(struct arm_pmu *armpmu, int type)
{
armpmu_init(armpmu);
- pm_runtime_enable(&armpmu->plat_device->dev);
pr_info("enabled with %s PMU driver, %d counters available\n",
armpmu->name, armpmu->num_events);
return perf_pmu_register(&armpmu->pmu, armpmu->name, type);
}
+/* Set at runtime when we know what CPU type we are. */
+static struct arm_pmu *__oprofile_cpu_pmu;
+
+/*
+ * Despite the names, these two functions are CPU-specific and are used
+ * by the OProfile/perf code.
+ */
+const char *perf_pmu_name(void)
+{
+ if (!__oprofile_cpu_pmu)
+ return NULL;
+
+ return __oprofile_cpu_pmu->name;
+}
+EXPORT_SYMBOL_GPL(perf_pmu_name);
+
+int perf_num_counters(void)
+{
+ int max_events = 0;
+
+ if (__oprofile_cpu_pmu != NULL)
+ max_events = __oprofile_cpu_pmu->num_events;
+
+ return max_events;
+}
+EXPORT_SYMBOL_GPL(perf_num_counters);
+
+static void cpu_pmu_enable_percpu_irq(void *data)
+{
+ int irq = *(int *)data;
+
+ enable_percpu_irq(irq, IRQ_TYPE_NONE);
+}
+
+static void cpu_pmu_disable_percpu_irq(void *data)
+{
+ int irq = *(int *)data;
+
+ disable_percpu_irq(irq);
+}
+
+static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu)
+{
+ int i, irq, irqs;
+ struct platform_device *pmu_device = cpu_pmu->plat_device;
+ struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events;
+
+ irqs = min(pmu_device->num_resources, num_possible_cpus());
+
+ irq = platform_get_irq(pmu_device, 0);
+ if (irq >= 0 && irq_is_percpu(irq)) {
+ on_each_cpu(cpu_pmu_disable_percpu_irq, &irq, 1);
+ free_percpu_irq(irq, &hw_events->percpu_pmu);
+ } else {
+ for (i = 0; i < irqs; ++i) {
+ int cpu = i;
+
+ if (cpu_pmu->irq_affinity)
+ cpu = cpu_pmu->irq_affinity[i];
+
+ if (!cpumask_test_and_clear_cpu(cpu, &cpu_pmu->active_irqs))
+ continue;
+ irq = platform_get_irq(pmu_device, i);
+ if (irq >= 0)
+ free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu));
+ }
+ }
+}
+
+static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
+{
+ int i, err, irq, irqs;
+ struct platform_device *pmu_device = cpu_pmu->plat_device;
+ struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events;
+
+ if (!pmu_device)
+ return -ENODEV;
+
+ irqs = min(pmu_device->num_resources, num_possible_cpus());
+ if (irqs < 1) {
+ pr_warn_once("perf/ARM: No irqs for PMU defined, sampling events not supported\n");
+ return 0;
+ }
+
+ irq = platform_get_irq(pmu_device, 0);
+ if (irq >= 0 && irq_is_percpu(irq)) {
+ err = request_percpu_irq(irq, handler, "arm-pmu",
+ &hw_events->percpu_pmu);
+ if (err) {
+ pr_err("unable to request IRQ%d for ARM PMU counters\n",
+ irq);
+ return err;
+ }
+ on_each_cpu(cpu_pmu_enable_percpu_irq, &irq, 1);
+ } else {
+ for (i = 0; i < irqs; ++i) {
+ int cpu = i;
+
+ err = 0;
+ irq = platform_get_irq(pmu_device, i);
+ if (irq < 0)
+ continue;
+
+ if (cpu_pmu->irq_affinity)
+ cpu = cpu_pmu->irq_affinity[i];
+
+ /*
+ * If we have a single PMU interrupt that we can't shift,
+ * assume that we're running on a uniprocessor machine and
+ * continue. Otherwise, continue without this interrupt.
+ */
+ if (irq_set_affinity(irq, cpumask_of(cpu)) && irqs > 1) {
+ pr_warn("unable to set irq affinity (irq=%d, cpu=%u)\n",
+ irq, cpu);
+ continue;
+ }
+
+ err = request_irq(irq, handler,
+ IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu",
+ per_cpu_ptr(&hw_events->percpu_pmu, cpu));
+ if (err) {
+ pr_err("unable to request IRQ%d for ARM PMU counters\n",
+ irq);
+ return err;
+ }
+
+ cpumask_set_cpu(cpu, &cpu_pmu->active_irqs);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * PMU hardware loses all context when a CPU goes offline.
+ * When a CPU is hotplugged back in, since some hardware registers are
+ * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
+ * junk values out of them.
+ */
+static int cpu_pmu_notify(struct notifier_block *b, unsigned long action,
+ void *hcpu)
+{
+ int cpu = (unsigned long)hcpu;
+ struct arm_pmu *pmu = container_of(b, struct arm_pmu, hotplug_nb);
+
+ if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
+ return NOTIFY_DONE;
+
+ if (!cpumask_test_cpu(cpu, &pmu->supported_cpus))
+ return NOTIFY_DONE;
+
+ if (pmu->reset)
+ pmu->reset(pmu);
+ else
+ return NOTIFY_DONE;
+
+ return NOTIFY_OK;
+}
+
+static int cpu_pmu_init(struct arm_pmu *cpu_pmu)
+{
+ int err;
+ int cpu;
+ struct pmu_hw_events __percpu *cpu_hw_events;
+
+ cpu_hw_events = alloc_percpu(struct pmu_hw_events);
+ if (!cpu_hw_events)
+ return -ENOMEM;
+
+ cpu_pmu->hotplug_nb.notifier_call = cpu_pmu_notify;
+ err = register_cpu_notifier(&cpu_pmu->hotplug_nb);
+ if (err)
+ goto out_hw_events;
+
+ for_each_possible_cpu(cpu) {
+ struct pmu_hw_events *events = per_cpu_ptr(cpu_hw_events, cpu);
+ raw_spin_lock_init(&events->pmu_lock);
+ events->percpu_pmu = cpu_pmu;
+ }
+
+ cpu_pmu->hw_events = cpu_hw_events;
+ cpu_pmu->request_irq = cpu_pmu_request_irq;
+ cpu_pmu->free_irq = cpu_pmu_free_irq;
+
+ /* Ensure the PMU has sane values out of reset. */
+ if (cpu_pmu->reset)
+ on_each_cpu_mask(&cpu_pmu->supported_cpus, cpu_pmu->reset,
+ cpu_pmu, 1);
+
+ /* If no interrupts available, set the corresponding capability flag */
+ if (!platform_get_irq(cpu_pmu->plat_device, 0))
+ cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
+
+ return 0;
+
+out_hw_events:
+ free_percpu(cpu_hw_events);
+ return err;
+}
+
+static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
+{
+ unregister_cpu_notifier(&cpu_pmu->hotplug_nb);
+ free_percpu(cpu_pmu->hw_events);
+}
+
+/*
+ * CPU PMU identification and probing.
+ */
+static int probe_current_pmu(struct arm_pmu *pmu,
+ const struct pmu_probe_info *info)
+{
+ int cpu = get_cpu();
+ unsigned int cpuid = read_cpuid_id();
+ int ret = -ENODEV;
+
+ pr_info("probing PMU on CPU %d\n", cpu);
+
+ for (; info->init != NULL; info++) {
+ if ((cpuid & info->mask) != info->cpuid)
+ continue;
+ ret = info->init(pmu);
+ break;
+ }
+
+ put_cpu();
+ return ret;
+}
+
+static int of_pmu_irq_cfg(struct arm_pmu *pmu)
+{
+ int i, irq, *irqs;
+ struct platform_device *pdev = pmu->plat_device;
+
+ /* Don't bother with PPIs; they're already affine */
+ irq = platform_get_irq(pdev, 0);
+ if (irq >= 0 && irq_is_percpu(irq))
+ return 0;
+
+ irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL);
+ if (!irqs)
+ return -ENOMEM;
+
+ for (i = 0; i < pdev->num_resources; ++i) {
+ struct device_node *dn;
+ int cpu;
+
+ dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity",
+ i);
+ if (!dn) {
+ pr_warn("Failed to parse %s/interrupt-affinity[%d]\n",
+ of_node_full_name(pdev->dev.of_node), i);
+ break;
+ }
+
+ for_each_possible_cpu(cpu)
+ if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL))
+ break;
+
+ of_node_put(dn);
+ if (cpu >= nr_cpu_ids) {
+ pr_warn("Failed to find logical CPU for %s\n",
+ dn->name);
+ break;
+ }
+
+ irqs[i] = cpu;
+ cpumask_set_cpu(cpu, &pmu->supported_cpus);
+ }
+
+ if (i == pdev->num_resources) {
+ pmu->irq_affinity = irqs;
+ } else {
+ kfree(irqs);
+ cpumask_setall(&pmu->supported_cpus);
+ }
+
+ return 0;
+}
+
+int arm_pmu_device_probe(struct platform_device *pdev,
+ const struct of_device_id *of_table,
+ const struct pmu_probe_info *probe_table)
+{
+ const struct of_device_id *of_id;
+ const int (*init_fn)(struct arm_pmu *);
+ struct device_node *node = pdev->dev.of_node;
+ struct arm_pmu *pmu;
+ int ret = -ENODEV;
+
+ pmu = kzalloc(sizeof(struct arm_pmu), GFP_KERNEL);
+ if (!pmu) {
+ pr_info("failed to allocate PMU device!\n");
+ return -ENOMEM;
+ }
+
+ if (!__oprofile_cpu_pmu)
+ __oprofile_cpu_pmu = pmu;
+
+ pmu->plat_device = pdev;
+
+ if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) {
+ init_fn = of_id->data;
+
+ ret = of_pmu_irq_cfg(pmu);
+ if (!ret)
+ ret = init_fn(pmu);
+ } else {
+ ret = probe_current_pmu(pmu, probe_table);
+ cpumask_setall(&pmu->supported_cpus);
+ }
+
+ if (ret) {
+ pr_info("failed to probe PMU!\n");
+ goto out_free;
+ }
+
+ ret = cpu_pmu_init(pmu);
+ if (ret)
+ goto out_free;
+
+ ret = armpmu_register(pmu, -1);
+ if (ret)
+ goto out_destroy;
+
+ return 0;
+
+out_destroy:
+ cpu_pmu_destroy(pmu);
+out_free:
+ pr_info("failed to register PMU devices!\n");
+ kfree(pmu);
+ return ret;
+}
diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c
deleted file mode 100644
index 3b8c2833c537..000000000000
--- a/arch/arm/kernel/perf_event_cpu.c
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Copyright (C) 2012 ARM Limited
- *
- * Author: Will Deacon <will.deacon@arm.com>
- */
-#define pr_fmt(fmt) "CPU PMU: " fmt
-
-#include <linux/bitmap.h>
-#include <linux/export.h>
-#include <linux/kernel.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/irq.h>
-#include <linux/irqdesc.h>
-
-#include <asm/cputype.h>
-#include <asm/irq_regs.h>
-#include <asm/pmu.h>
-
-/* Set at runtime when we know what CPU type we are. */
-static struct arm_pmu *cpu_pmu;
-
-/*
- * Despite the names, these two functions are CPU-specific and are used
- * by the OProfile/perf code.
- */
-const char *perf_pmu_name(void)
-{
- if (!cpu_pmu)
- return NULL;
-
- return cpu_pmu->name;
-}
-EXPORT_SYMBOL_GPL(perf_pmu_name);
-
-int perf_num_counters(void)
-{
- int max_events = 0;
-
- if (cpu_pmu != NULL)
- max_events = cpu_pmu->num_events;
-
- return max_events;
-}
-EXPORT_SYMBOL_GPL(perf_num_counters);
-
-/* Include the PMU-specific implementations. */
-#include "perf_event_xscale.c"
-#include "perf_event_v6.c"
-#include "perf_event_v7.c"
-
-static void cpu_pmu_enable_percpu_irq(void *data)
-{
- int irq = *(int *)data;
-
- enable_percpu_irq(irq, IRQ_TYPE_NONE);
-}
-
-static void cpu_pmu_disable_percpu_irq(void *data)
-{
- int irq = *(int *)data;
-
- disable_percpu_irq(irq);
-}
-
-static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu)
-{
- int i, irq, irqs;
- struct platform_device *pmu_device = cpu_pmu->plat_device;
- struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events;
-
- irqs = min(pmu_device->num_resources, num_possible_cpus());
-
- irq = platform_get_irq(pmu_device, 0);
- if (irq >= 0 && irq_is_percpu(irq)) {
- on_each_cpu(cpu_pmu_disable_percpu_irq, &irq, 1);
- free_percpu_irq(irq, &hw_events->percpu_pmu);
- } else {
- for (i = 0; i < irqs; ++i) {
- int cpu = i;
-
- if (cpu_pmu->irq_affinity)
- cpu = cpu_pmu->irq_affinity[i];
-
- if (!cpumask_test_and_clear_cpu(cpu, &cpu_pmu->active_irqs))
- continue;
- irq = platform_get_irq(pmu_device, i);
- if (irq >= 0)
- free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu));
- }
- }
-}
-
-static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
-{
- int i, err, irq, irqs;
- struct platform_device *pmu_device = cpu_pmu->plat_device;
- struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events;
-
- if (!pmu_device)
- return -ENODEV;
-
- irqs = min(pmu_device->num_resources, num_possible_cpus());
- if (irqs < 1) {
- pr_warn_once("perf/ARM: No irqs for PMU defined, sampling events not supported\n");
- return 0;
- }
-
- irq = platform_get_irq(pmu_device, 0);
- if (irq >= 0 && irq_is_percpu(irq)) {
- err = request_percpu_irq(irq, handler, "arm-pmu",
- &hw_events->percpu_pmu);
- if (err) {
- pr_err("unable to request IRQ%d for ARM PMU counters\n",
- irq);
- return err;
- }
- on_each_cpu(cpu_pmu_enable_percpu_irq, &irq, 1);
- } else {
- for (i = 0; i < irqs; ++i) {
- int cpu = i;
-
- err = 0;
- irq = platform_get_irq(pmu_device, i);
- if (irq < 0)
- continue;
-
- if (cpu_pmu->irq_affinity)
- cpu = cpu_pmu->irq_affinity[i];
-
- /*
- * If we have a single PMU interrupt that we can't shift,
- * assume that we're running on a uniprocessor machine and
- * continue. Otherwise, continue without this interrupt.
- */
- if (irq_set_affinity(irq, cpumask_of(cpu)) && irqs > 1) {
- pr_warn("unable to set irq affinity (irq=%d, cpu=%u)\n",
- irq, cpu);
- continue;
- }
-
- err = request_irq(irq, handler,
- IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu",
- per_cpu_ptr(&hw_events->percpu_pmu, cpu));
- if (err) {
- pr_err("unable to request IRQ%d for ARM PMU counters\n",
- irq);
- return err;
- }
-
- cpumask_set_cpu(cpu, &cpu_pmu->active_irqs);
- }
- }
-
- return 0;
-}
-
-/*
- * PMU hardware loses all context when a CPU goes offline.
- * When a CPU is hotplugged back in, since some hardware registers are
- * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
- * junk values out of them.
- */
-static int cpu_pmu_notify(struct notifier_block *b, unsigned long action,
- void *hcpu)
-{
- struct arm_pmu *pmu = container_of(b, struct arm_pmu, hotplug_nb);
-
- if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
- return NOTIFY_DONE;
-
- if (pmu->reset)
- pmu->reset(pmu);
- else
- return NOTIFY_DONE;
-
- return NOTIFY_OK;
-}
-
-static int cpu_pmu_init(struct arm_pmu *cpu_pmu)
-{
- int err;
- int cpu;
- struct pmu_hw_events __percpu *cpu_hw_events;
-
- cpu_hw_events = alloc_percpu(struct pmu_hw_events);
- if (!cpu_hw_events)
- return -ENOMEM;
-
- cpu_pmu->hotplug_nb.notifier_call = cpu_pmu_notify;
- err = register_cpu_notifier(&cpu_pmu->hotplug_nb);
- if (err)
- goto out_hw_events;
-
- for_each_possible_cpu(cpu) {
- struct pmu_hw_events *events = per_cpu_ptr(cpu_hw_events, cpu);
- raw_spin_lock_init(&events->pmu_lock);
- events->percpu_pmu = cpu_pmu;
- }
-
- cpu_pmu->hw_events = cpu_hw_events;
- cpu_pmu->request_irq = cpu_pmu_request_irq;
- cpu_pmu->free_irq = cpu_pmu_free_irq;
-
- /* Ensure the PMU has sane values out of reset. */
- if (cpu_pmu->reset)
- on_each_cpu(cpu_pmu->reset, cpu_pmu, 1);
-
- /* If no interrupts available, set the corresponding capability flag */
- if (!platform_get_irq(cpu_pmu->plat_device, 0))
- cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
-
- return 0;
-
-out_hw_events:
- free_percpu(cpu_hw_events);
- return err;
-}
-
-static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
-{
- unregister_cpu_notifier(&cpu_pmu->hotplug_nb);
- free_percpu(cpu_pmu->hw_events);
-}
-
-/*
- * PMU platform driver and devicetree bindings.
- */
-static const struct of_device_id cpu_pmu_of_device_ids[] = {
- {.compatible = "arm,cortex-a17-pmu", .data = armv7_a17_pmu_init},
- {.compatible = "arm,cortex-a15-pmu", .data = armv7_a15_pmu_init},
- {.compatible = "arm,cortex-a12-pmu", .data = armv7_a12_pmu_init},
- {.compatible = "arm,cortex-a9-pmu", .data = armv7_a9_pmu_init},
- {.compatible = "arm,cortex-a8-pmu", .data = armv7_a8_pmu_init},
- {.compatible = "arm,cortex-a7-pmu", .data = armv7_a7_pmu_init},
- {.compatible = "arm,cortex-a5-pmu", .data = armv7_a5_pmu_init},
- {.compatible = "arm,arm11mpcore-pmu", .data = armv6mpcore_pmu_init},
- {.compatible = "arm,arm1176-pmu", .data = armv6_1176_pmu_init},
- {.compatible = "arm,arm1136-pmu", .data = armv6_1136_pmu_init},
- {.compatible = "qcom,krait-pmu", .data = krait_pmu_init},
- {.compatible = "qcom,scorpion-pmu", .data = scorpion_pmu_init},
- {.compatible = "qcom,scorpion-mp-pmu", .data = scorpion_mp_pmu_init},
- {},
-};
-
-static struct platform_device_id cpu_pmu_plat_device_ids[] = {
- {.name = "arm-pmu"},
- {.name = "armv6-pmu"},
- {.name = "armv7-pmu"},
- {.name = "xscale-pmu"},
- {},
-};
-
-static const struct pmu_probe_info pmu_probe_table[] = {
- ARM_PMU_PROBE(ARM_CPU_PART_ARM1136, armv6_1136_pmu_init),
- ARM_PMU_PROBE(ARM_CPU_PART_ARM1156, armv6_1156_pmu_init),
- ARM_PMU_PROBE(ARM_CPU_PART_ARM1176, armv6_1176_pmu_init),
- ARM_PMU_PROBE(ARM_CPU_PART_ARM11MPCORE, armv6mpcore_pmu_init),
- ARM_PMU_PROBE(ARM_CPU_PART_CORTEX_A8, armv7_a8_pmu_init),
- ARM_PMU_PROBE(ARM_CPU_PART_CORTEX_A9, armv7_a9_pmu_init),
- XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V1, xscale1pmu_init),
- XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V2, xscale2pmu_init),
- { /* sentinel value */ }
-};
-
-/*
- * CPU PMU identification and probing.
- */
-static int probe_current_pmu(struct arm_pmu *pmu)
-{
- int cpu = get_cpu();
- unsigned int cpuid = read_cpuid_id();
- int ret = -ENODEV;
- const struct pmu_probe_info *info;
-
- pr_info("probing PMU on CPU %d\n", cpu);
-
- for (info = pmu_probe_table; info->init != NULL; info++) {
- if ((cpuid & info->mask) != info->cpuid)
- continue;
- ret = info->init(pmu);
- break;
- }
-
- put_cpu();
- return ret;
-}
-
-static int of_pmu_irq_cfg(struct platform_device *pdev)
-{
- int i, irq;
- int *irqs;
-
- /* Don't bother with PPIs; they're already affine */
- irq = platform_get_irq(pdev, 0);
- if (irq >= 0 && irq_is_percpu(irq))
- return 0;
-
- irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL);
- if (!irqs)
- return -ENOMEM;
-
- for (i = 0; i < pdev->num_resources; ++i) {
- struct device_node *dn;
- int cpu;
-
- dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity",
- i);
- if (!dn) {
- pr_warn("Failed to parse %s/interrupt-affinity[%d]\n",
- of_node_full_name(pdev->dev.of_node), i);
- break;
- }
-
- for_each_possible_cpu(cpu)
- if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL))
- break;
-
- of_node_put(dn);
- if (cpu >= nr_cpu_ids) {
- pr_warn("Failed to find logical CPU for %s\n",
- dn->name);
- break;
- }
-
- irqs[i] = cpu;
- }
-
- if (i == pdev->num_resources)
- cpu_pmu->irq_affinity = irqs;
- else
- kfree(irqs);
-
- return 0;
-}
-
-static int cpu_pmu_device_probe(struct platform_device *pdev)
-{
- const struct of_device_id *of_id;
- const int (*init_fn)(struct arm_pmu *);
- struct device_node *node = pdev->dev.of_node;
- struct arm_pmu *pmu;
- int ret = -ENODEV;
-
- if (cpu_pmu) {
- pr_info("attempt to register multiple PMU devices!\n");
- return -ENOSPC;
- }
-
- pmu = kzalloc(sizeof(struct arm_pmu), GFP_KERNEL);
- if (!pmu) {
- pr_info("failed to allocate PMU device!\n");
- return -ENOMEM;
- }
-
- cpu_pmu = pmu;
- cpu_pmu->plat_device = pdev;
-
- if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) {
- init_fn = of_id->data;
-
- ret = of_pmu_irq_cfg(pdev);
- if (!ret)
- ret = init_fn(pmu);
- } else {
- ret = probe_current_pmu(pmu);
- }
-
- if (ret) {
- pr_info("failed to probe PMU!\n");
- goto out_free;
- }
-
- ret = cpu_pmu_init(cpu_pmu);
- if (ret)
- goto out_free;
-
- ret = armpmu_register(cpu_pmu, -1);
- if (ret)
- goto out_destroy;
-
- return 0;
-
-out_destroy:
- cpu_pmu_destroy(cpu_pmu);
-out_free:
- pr_info("failed to register PMU devices!\n");
- kfree(pmu);
- return ret;
-}
-
-static struct platform_driver cpu_pmu_driver = {
- .driver = {
- .name = "arm-pmu",
- .pm = &armpmu_dev_pm_ops,
- .of_match_table = cpu_pmu_of_device_ids,
- },
- .probe = cpu_pmu_device_probe,
- .id_table = cpu_pmu_plat_device_ids,
-};
-
-static int __init register_pmu_driver(void)
-{
- return platform_driver_register(&cpu_pmu_driver);
-}
-device_initcall(register_pmu_driver);
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index f2ffd5c542ed..09f83e414a72 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -31,6 +31,14 @@
*/
#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K)
+
+#include <asm/cputype.h>
+#include <asm/irq_regs.h>
+#include <asm/pmu.h>
+
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
enum armv6_perf_types {
ARMV6_PERFCTR_ICACHE_MISS = 0x0,
ARMV6_PERFCTR_IBUF_STALL = 0x1,
@@ -543,24 +551,39 @@ static int armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu)
return 0;
}
-#else
-static int armv6_1136_pmu_init(struct arm_pmu *cpu_pmu)
-{
- return -ENODEV;
-}
-static int armv6_1156_pmu_init(struct arm_pmu *cpu_pmu)
-{
- return -ENODEV;
-}
+static struct of_device_id armv6_pmu_of_device_ids[] = {
+ {.compatible = "arm,arm11mpcore-pmu", .data = armv6mpcore_pmu_init},
+ {.compatible = "arm,arm1176-pmu", .data = armv6_1176_pmu_init},
+ {.compatible = "arm,arm1136-pmu", .data = armv6_1136_pmu_init},
+ { /* sentinel value */ }
+};
-static int armv6_1176_pmu_init(struct arm_pmu *cpu_pmu)
+static const struct pmu_probe_info armv6_pmu_probe_table[] = {
+ ARM_PMU_PROBE(ARM_CPU_PART_ARM1136, armv6_1136_pmu_init),
+ ARM_PMU_PROBE(ARM_CPU_PART_ARM1156, armv6_1156_pmu_init),
+ ARM_PMU_PROBE(ARM_CPU_PART_ARM1176, armv6_1176_pmu_init),
+ ARM_PMU_PROBE(ARM_CPU_PART_ARM11MPCORE, armv6mpcore_pmu_init),
+ { /* sentinel value */ }
+};
+
+static int armv6_pmu_device_probe(struct platform_device *pdev)
{
- return -ENODEV;
+ return arm_pmu_device_probe(pdev, armv6_pmu_of_device_ids,
+ armv6_pmu_probe_table);
}
-static int armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu)
+static struct platform_driver armv6_pmu_driver = {
+ .driver = {
+ .name = "armv6-pmu",
+ .of_match_table = armv6_pmu_of_device_ids,
+ },
+ .probe = armv6_pmu_device_probe,
+};
+
+static int __init register_armv6_pmu_driver(void)
{
- return -ENODEV;
+ return platform_driver_register(&armv6_pmu_driver);
}
+device_initcall(register_armv6_pmu_driver);
#endif /* CONFIG_CPU_V6 || CONFIG_CPU_V6K */
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index f4207a4dcb01..f9b37f876e20 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -19,9 +19,15 @@
#ifdef CONFIG_CPU_V7
#include <asm/cp15.h>
+#include <asm/cputype.h>
+#include <asm/irq_regs.h>
+#include <asm/pmu.h>
#include <asm/vfp.h>
#include "../vfp/vfpinstr.h"
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
/*
* Common ARMv7 event types
*
@@ -1056,15 +1062,22 @@ static void armv7pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->max_period = (1LLU << 32) - 1;
};
-static u32 armv7_read_num_pmnc_events(void)
+static void armv7_read_num_pmnc_events(void *info)
{
- u32 nb_cnt;
+ int *nb_cnt = info;
/* Read the nb of CNTx counters supported from PMNC */
- nb_cnt = (armv7_pmnc_read() >> ARMV7_PMNC_N_SHIFT) & ARMV7_PMNC_N_MASK;
+ *nb_cnt = (armv7_pmnc_read() >> ARMV7_PMNC_N_SHIFT) & ARMV7_PMNC_N_MASK;
- /* Add the CPU cycles counter and return */
- return nb_cnt + 1;
+ /* Add the CPU cycles counter */
+ *nb_cnt += 1;
+}
+
+static int armv7_probe_num_events(struct arm_pmu *arm_pmu)
+{
+ return smp_call_function_any(&arm_pmu->supported_cpus,
+ armv7_read_num_pmnc_events,
+ &arm_pmu->num_events, 1);
}
static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1072,8 +1085,7 @@ static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_cortex_a8";
cpu_pmu->map_event = armv7_a8_map_event;
- cpu_pmu->num_events = armv7_read_num_pmnc_events();
- return 0;
+ return armv7_probe_num_events(cpu_pmu);
}
static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1081,8 +1093,7 @@ static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_cortex_a9";
cpu_pmu->map_event = armv7_a9_map_event;
- cpu_pmu->num_events = armv7_read_num_pmnc_events();
- return 0;
+ return armv7_probe_num_events(cpu_pmu);
}
static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1090,8 +1101,7 @@ static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_cortex_a5";
cpu_pmu->map_event = armv7_a5_map_event;
- cpu_pmu->num_events = armv7_read_num_pmnc_events();
- return 0;
+ return armv7_probe_num_events(cpu_pmu);
}
static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1099,9 +1109,8 @@ static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_cortex_a15";
cpu_pmu->map_event = armv7_a15_map_event;
- cpu_pmu->num_events = armv7_read_num_pmnc_events();
cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
- return 0;
+ return armv7_probe_num_events(cpu_pmu);
}
static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1109,9 +1118,8 @@ static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_cortex_a7";
cpu_pmu->map_event = armv7_a7_map_event;
- cpu_pmu->num_events = armv7_read_num_pmnc_events();
cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
- return 0;
+ return armv7_probe_num_events(cpu_pmu);
}
static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1119,16 +1127,15 @@ static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu)
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_cortex_a12";
cpu_pmu->map_event = armv7_a12_map_event;
- cpu_pmu->num_events = armv7_read_num_pmnc_events();
cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
- return 0;
+ return armv7_probe_num_events(cpu_pmu);
}
static int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu)
{
- armv7_a12_pmu_init(cpu_pmu);
+ int ret = armv7_a12_pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_cortex_a17";
- return 0;
+ return ret;
}
/*
@@ -1508,14 +1515,13 @@ static int krait_pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->map_event = krait_map_event_no_branch;
else
cpu_pmu->map_event = krait_map_event;
- cpu_pmu->num_events = armv7_read_num_pmnc_events();
cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
cpu_pmu->reset = krait_pmu_reset;
cpu_pmu->enable = krait_pmu_enable_event;
cpu_pmu->disable = krait_pmu_disable_event;
cpu_pmu->get_event_idx = krait_pmu_get_event_idx;
cpu_pmu->clear_event_idx = krait_pmu_clear_event_idx;
- return 0;
+ return armv7_probe_num_events(cpu_pmu);
}
/*
@@ -1833,13 +1839,12 @@ static int scorpion_pmu_init(struct arm_pmu *cpu_pmu)
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_scorpion";
cpu_pmu->map_event = scorpion_map_event;
- cpu_pmu->num_events = armv7_read_num_pmnc_events();
cpu_pmu->reset = scorpion_pmu_reset;
cpu_pmu->enable = scorpion_pmu_enable_event;
cpu_pmu->disable = scorpion_pmu_disable_event;
cpu_pmu->get_event_idx = scorpion_pmu_get_event_idx;
cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx;
- return 0;
+ return armv7_probe_num_events(cpu_pmu);
}
static int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1847,62 +1852,52 @@ static int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu)
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_scorpion_mp";
cpu_pmu->map_event = scorpion_map_event;
- cpu_pmu->num_events = armv7_read_num_pmnc_events();
cpu_pmu->reset = scorpion_pmu_reset;
cpu_pmu->enable = scorpion_pmu_enable_event;
cpu_pmu->disable = scorpion_pmu_disable_event;
cpu_pmu->get_event_idx = scorpion_pmu_get_event_idx;
cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx;
- return 0;
-}
-#else
-static inline int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
-{
- return -ENODEV;
-}
-
-static inline int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)
-{
- return -ENODEV;
-}
-
-static inline int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)
-{
- return -ENODEV;
-}
-
-static inline int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)
-{
- return -ENODEV;
-}
-
-static inline int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
-{
- return -ENODEV;
-}
+ return armv7_probe_num_events(cpu_pmu);
+}
+
+static const struct of_device_id armv7_pmu_of_device_ids[] = {
+ {.compatible = "arm,cortex-a17-pmu", .data = armv7_a17_pmu_init},
+ {.compatible = "arm,cortex-a15-pmu", .data = armv7_a15_pmu_init},
+ {.compatible = "arm,cortex-a12-pmu", .data = armv7_a12_pmu_init},
+ {.compatible = "arm,cortex-a9-pmu", .data = armv7_a9_pmu_init},
+ {.compatible = "arm,cortex-a8-pmu", .data = armv7_a8_pmu_init},
+ {.compatible = "arm,cortex-a7-pmu", .data = armv7_a7_pmu_init},
+ {.compatible = "arm,cortex-a5-pmu", .data = armv7_a5_pmu_init},
+ {.compatible = "qcom,krait-pmu", .data = krait_pmu_init},
+ {.compatible = "qcom,scorpion-pmu", .data = scorpion_pmu_init},
+ {.compatible = "qcom,scorpion-mp-pmu", .data = scorpion_mp_pmu_init},
+ {},
+};
-static inline int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu)
-{
- return -ENODEV;
-}
+static const struct pmu_probe_info armv7_pmu_probe_table[] = {
+ ARM_PMU_PROBE(ARM_CPU_PART_CORTEX_A8, armv7_a8_pmu_init),
+ ARM_PMU_PROBE(ARM_CPU_PART_CORTEX_A9, armv7_a9_pmu_init),
+ { /* sentinel value */ }
+};
-static inline int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu)
-{
- return -ENODEV;
-}
-static inline int krait_pmu_init(struct arm_pmu *cpu_pmu)
+static int armv7_pmu_device_probe(struct platform_device *pdev)
{
- return -ENODEV;
+ return arm_pmu_device_probe(pdev, armv7_pmu_of_device_ids,
+ armv7_pmu_probe_table);
}
-static inline int scorpion_pmu_init(struct arm_pmu *cpu_pmu)
-{
- return -ENODEV;
-}
+static struct platform_driver armv7_pmu_driver = {
+ .driver = {
+ .name = "armv7-pmu",
+ .of_match_table = armv7_pmu_of_device_ids,
+ },
+ .probe = armv7_pmu_device_probe,
+};
-static inline int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu)
+static int __init register_armv7_pmu_driver(void)
{
- return -ENODEV;
+ return platform_driver_register(&armv7_pmu_driver);
}
+device_initcall(register_armv7_pmu_driver);
#endif /* CONFIG_CPU_V7 */
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 8af9f1f82c68..304d056d5b25 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -13,6 +13,14 @@
*/
#ifdef CONFIG_CPU_XSCALE
+
+#include <asm/cputype.h>
+#include <asm/irq_regs.h>
+#include <asm/pmu.h>
+
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
enum xscale_perf_types {
XSCALE_PERFCTR_ICACHE_MISS = 0x00,
XSCALE_PERFCTR_ICACHE_NO_DELIVER = 0x01,
@@ -740,14 +748,28 @@ static int xscale2pmu_init(struct arm_pmu *cpu_pmu)
return 0;
}
-#else
-static inline int xscale1pmu_init(struct arm_pmu *cpu_pmu)
+
+static const struct pmu_probe_info xscale_pmu_probe_table[] = {
+ XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V1, xscale1pmu_init),
+ XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V2, xscale2pmu_init),
+ { /* sentinel value */ }
+};
+
+static int xscale_pmu_device_probe(struct platform_device *pdev)
{
- return -ENODEV;
+ return arm_pmu_device_probe(pdev, NULL, xscale_pmu_probe_table);
}
-static inline int xscale2pmu_init(struct arm_pmu *cpu_pmu)
+static struct platform_driver xscale_pmu_driver = {
+ .driver = {
+ .name = "xscale-pmu",
+ },
+ .probe = xscale_pmu_device_probe,
+};
+
+static int __init register_xscale_pmu_driver(void)
{
- return -ENODEV;
+ return platform_driver_register(&xscale_pmu_driver);
}
+device_initcall(register_xscale_pmu_driver);
#endif /* CONFIG_CPU_XSCALE */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 6c777e908a24..e6d8c7658ffd 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -75,8 +75,7 @@ __setup("fpe=", fpe_setup);
extern void init_default_cache_policy(unsigned long);
extern void paging_init(const struct machine_desc *desc);
-extern void early_paging_init(const struct machine_desc *,
- struct proc_info_list *);
+extern void early_paging_init(const struct machine_desc *);
extern void sanity_check_meminfo(void);
extern enum reboot_mode reboot_mode;
extern void setup_dma_zone(const struct machine_desc *desc);
@@ -93,6 +92,9 @@ unsigned int __atags_pointer __initdata;
unsigned int system_rev;
EXPORT_SYMBOL(system_rev);
+const char *system_serial;
+EXPORT_SYMBOL(system_serial);
+
unsigned int system_serial_low;
EXPORT_SYMBOL(system_serial_low);
@@ -839,8 +841,25 @@ arch_initcall(customize_machine);
static int __init init_machine_late(void)
{
+ struct device_node *root;
+ int ret;
+
if (machine_desc->init_late)
machine_desc->init_late();
+
+ root = of_find_node_by_path("/");
+ if (root) {
+ ret = of_property_read_string(root, "serial-number",
+ &system_serial);
+ if (ret)
+ system_serial = NULL;
+ }
+
+ if (!system_serial)
+ system_serial = kasprintf(GFP_KERNEL, "%08x%08x",
+ system_serial_high,
+ system_serial_low);
+
return 0;
}
late_initcall(init_machine_late);
@@ -936,7 +955,9 @@ void __init setup_arch(char **cmdline_p)
parse_early_param();
- early_paging_init(mdesc, lookup_processor_type(read_cpuid_id()));
+#ifdef CONFIG_MMU
+ early_paging_init(mdesc);
+#endif
setup_dma_zone(mdesc);
sanity_check_meminfo();
arm_memblock_init(mdesc);
@@ -1109,8 +1130,7 @@ static int c_show(struct seq_file *m, void *v)
seq_printf(m, "Hardware\t: %s\n", machine_name);
seq_printf(m, "Revision\t: %04x\n", system_rev);
- seq_printf(m, "Serial\t\t: %08x%08x\n",
- system_serial_high, system_serial_low);
+ seq_printf(m, "Serial\t\t: %s\n", system_serial);
return 0;
}
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S
index 7d37bfc50830..0f6c1000582c 100644
--- a/arch/arm/kernel/sleep.S
+++ b/arch/arm/kernel/sleep.S
@@ -81,7 +81,7 @@ ENTRY(__cpu_suspend)
mov r1, r4 @ size of save block
add r0, sp, #8 @ pointer to save block
bl __cpu_suspend_save
- adr lr, BSYM(cpu_suspend_abort)
+ badr lr, cpu_suspend_abort
ldmfd sp!, {r0, pc} @ call suspend fn
ENDPROC(__cpu_suspend)
.ltorg
@@ -118,6 +118,16 @@ ENDPROC(cpu_resume_after_mmu)
.text
.align
+
+#ifdef CONFIG_MMU
+ .arm
+ENTRY(cpu_resume_arm)
+ THUMB( badr r9, 1f ) @ Kernel is entered in ARM.
+ THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
+ THUMB( .thumb ) @ switch to Thumb now.
+ THUMB(1: )
+#endif
+
ENTRY(cpu_resume)
ARM_BE8(setend be) @ ensure we are in BE mode
#ifdef CONFIG_ARM_VIRT_EXT
@@ -150,6 +160,10 @@ THUMB( mov sp, r2 )
THUMB( bx r3 )
ENDPROC(cpu_resume)
+#ifdef CONFIG_MMU
+ENDPROC(cpu_resume_arm)
+#endif
+
.align 2
_sleep_save_sp:
.long sleep_save_sp - .
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index cca5b8758185..90dfbedfbfb8 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -86,9 +86,11 @@ void __init smp_set_ops(struct smp_operations *ops)
static unsigned long get_arch_pgd(pgd_t *pgd)
{
- phys_addr_t pgdir = virt_to_idmap(pgd);
- BUG_ON(pgdir & ARCH_PGD_MASK);
- return pgdir >> ARCH_PGD_SHIFT;
+#ifdef CONFIG_ARM_LPAE
+ return __phys_to_pfn(virt_to_phys(pgd));
+#else
+ return virt_to_phys(pgd);
+#endif
}
int __cpu_up(unsigned int cpu, struct task_struct *idle)
@@ -108,7 +110,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
#endif
#ifdef CONFIG_MMU
- secondary_data.pgdir = get_arch_pgd(idmap_pgd);
+ secondary_data.pgdir = virt_to_phys(idmap_pgd);
secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
#endif
sync_cache_w(&secondary_data);
diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c
index 7a3be1d4d0b1..b10e1360762e 100644
--- a/arch/arm/kernel/tcm.c
+++ b/arch/arm/kernel/tcm.c
@@ -17,6 +17,9 @@
#include <asm/mach/map.h>
#include <asm/memory.h>
#include <asm/system_info.h>
+#include <asm/traps.h>
+
+#define TCMTR_FORMAT_MASK 0xe0000000U
static struct gen_pool *tcm_pool;
static bool dtcm_present;
@@ -176,6 +179,77 @@ static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks,
}
/*
+ * When we are running in the non-secure world and the secure world
+ * has not explicitly given us access to the TCM we will get an
+ * undefined error when reading the TCM region register in the
+ * setup_tcm_bank function (above).
+ *
+ * There are two variants of this register read that we need to trap,
+ * the read for the data TCM and the read for the instruction TCM:
+ * c0370628: ee196f11 mrc 15, 0, r6, cr9, cr1, {0}
+ * c0370674: ee196f31 mrc 15, 0, r6, cr9, cr1, {1}
+ *
+ * Our undef hook mask explicitly matches all fields of the encoded
+ * instruction other than the destination register. The mask also
+ * only allows operand 2 to have the values 0 or 1.
+ *
+ * The undefined hook is defined as __init and __initdata, and therefore
+ * must be removed before tcm_init returns.
+ *
+ * In this particular case (MRC with ARM condition code ALways) the
+ * Thumb-2 and ARM instruction encoding are identical, so this hook
+ * will work on a Thumb-2 kernel.
+ *
+ * See A8.8.107, DDI0406C_C ARM Architecture Reference Manual, Encoding
+ * T1/A1 for the bit-by-bit details.
+ *
+ * mrc p15, 0, XX, c9, c1, 0
+ * mrc p15, 0, XX, c9, c1, 1
+ * | | | | | | | +---- opc2 0|1 = 000|001
+ * | | | | | | +------- CRm 0 = 0001
+ * | | | | | +----------- CRn 0 = 1001
+ * | | | | +--------------- Rt ? = ????
+ * | | | +------------------- opc1 0 = 000
+ * | | +----------------------- coproc 15 = 1111
+ * | +-------------------------- condition ALways = 1110
+ * +----------------------------- instruction MRC = 1110
+ *
+ * Encoding this as per A8.8.107 of DDI0406C, Encoding T1/A1, yields:
+ * 1111 1111 1111 1111 0000 1111 1101 1111 Required Mask
+ * 1110 1110 0001 1001 ???? 1111 0001 0001 mrc p15, 0, XX, c9, c1, 0
+ * 1110 1110 0001 1001 ???? 1111 0011 0001 mrc p15, 0, XX, c9, c1, 1
+ * [ ] [ ] [ ]| [ ] [ ] [ ] [ ]| +--- CRm
+ * | | | | | | | | +----- SBO
+ * | | | | | | | +------- opc2
+ * | | | | | | +----------- coproc
+ * | | | | | +---------------- Rt
+ * | | | | +--------------------- CRn
+ * | | | +------------------------- SBO
+ * | | +--------------------------- opc1
+ * | +------------------------------- instruction
+ * +------------------------------------ condition
+ */
+#define TCM_REGION_READ_MASK 0xffff0fdf
+#define TCM_REGION_READ_INSTR 0xee190f11
+#define DEST_REG_SHIFT 12
+#define DEST_REG_MASK 0xf
+
+static int __init tcm_handler(struct pt_regs *regs, unsigned int instr)
+{
+ regs->uregs[(instr >> DEST_REG_SHIFT) & DEST_REG_MASK] = 0;
+ regs->ARM_pc += 4;
+ return 0;
+}
+
+static struct undef_hook tcm_hook __initdata = {
+ .instr_mask = TCM_REGION_READ_MASK,
+ .instr_val = TCM_REGION_READ_INSTR,
+ .cpsr_mask = MODE_MASK,
+ .cpsr_val = SVC_MODE,
+ .fn = tcm_handler
+};
+
+/*
* This initializes the TCM memory
*/
void __init tcm_init(void)
@@ -204,9 +278,18 @@ void __init tcm_init(void)
}
tcm_status = read_cpuid_tcmstatus();
+
+ /*
+ * This code only supports v6-compatible TCMTR implementations.
+ */
+ if (tcm_status & TCMTR_FORMAT_MASK)
+ return;
+
dtcm_banks = (tcm_status >> 16) & 0x03;
itcm_banks = (tcm_status & 0x03);
+ register_undef_hook(&tcm_hook);
+
/* Values greater than 2 for D/ITCM banks are "reserved" */
if (dtcm_banks > 2)
dtcm_banks = 0;
@@ -218,7 +301,7 @@ void __init tcm_init(void)
for (i = 0; i < dtcm_banks; i++) {
ret = setup_tcm_bank(0, i, dtcm_banks, &dtcm_end);
if (ret)
- return;
+ goto unregister;
}
/* This means you compiled more code than fits into DTCM */
if (dtcm_code_sz > (dtcm_end - DTCM_OFFSET)) {
@@ -227,6 +310,12 @@ void __init tcm_init(void)
dtcm_code_sz, (dtcm_end - DTCM_OFFSET));
goto no_dtcm;
}
+ /*
+ * This means that the DTCM sizes were 0 or the DTCM banks
+ * were inaccessible due to TrustZone configuration.
+ */
+ if (!(dtcm_end - DTCM_OFFSET))
+ goto no_dtcm;
dtcm_res.end = dtcm_end - 1;
request_resource(&iomem_resource, &dtcm_res);
dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET;
@@ -250,15 +339,21 @@ no_dtcm:
for (i = 0; i < itcm_banks; i++) {
ret = setup_tcm_bank(1, i, itcm_banks, &itcm_end);
if (ret)
- return;
+ goto unregister;
}
/* This means you compiled more code than fits into ITCM */
if (itcm_code_sz > (itcm_end - ITCM_OFFSET)) {
pr_info("CPU ITCM: %u bytes of code compiled to "
"ITCM but only %lu bytes of ITCM present\n",
itcm_code_sz, (itcm_end - ITCM_OFFSET));
- return;
+ goto unregister;
}
+ /*
+ * This means that the ITCM sizes were 0 or the ITCM banks
+ * were inaccessible due to TrustZone configuration.
+ */
+ if (!(itcm_end - ITCM_OFFSET))
+ goto unregister;
itcm_res.end = itcm_end - 1;
request_resource(&iomem_resource, &itcm_res);
itcm_iomap[0].length = itcm_end - ITCM_OFFSET;
@@ -275,6 +370,9 @@ no_dtcm:
pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no "
"ITCM banks present in CPU\n", itcm_code_sz);
}
+
+unregister:
+ unregister_undef_hook(&tcm_hook);
}
/*
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 3dce1a342030..d358226236f2 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -749,14 +749,6 @@ late_initcall(arm_mrc_hook_init);
#endif
-void __bad_xchg(volatile void *ptr, int size)
-{
- pr_err("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
- __builtin_return_address(0), ptr, size);
- BUG();
-}
-EXPORT_SYMBOL(__bad_xchg);
-
/*
* A data abort trap was taken, but we did not handle the instruction.
* Try to abort the user program, or panic if it was the kernel.
diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
index f1f79d104309..bfb915d05665 100644
--- a/arch/arm/kvm/Kconfig
+++ b/arch/arm/kvm/Kconfig
@@ -28,6 +28,7 @@ config KVM
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
select SRCU
select MMU_NOTIFIER
+ select KVM_VFIO
select HAVE_KVM_EVENTFD
select HAVE_KVM_IRQFD
depends on ARM_VIRT_EXT && ARM_LPAE && ARM_ARCH_TIMER
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index 139e46c08b6e..c5eef02c52ba 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -15,7 +15,7 @@ AFLAGS_init.o := -Wa,-march=armv7-a$(plus_virt)
AFLAGS_interrupts.o := -Wa,-march=armv7-a$(plus_virt)
KVM := ../../../virt/kvm
-kvm-arm-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o
+kvm-arm-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o $(KVM)/vfio.o
obj-y += kvm-arm.o init.o interrupts.o
obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index d9631ecddd56..bc738d2b8392 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -171,7 +171,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
int r;
switch (ext) {
case KVM_CAP_IRQCHIP:
- case KVM_CAP_IRQFD:
case KVM_CAP_IOEVENTFD:
case KVM_CAP_DEVICE_CTRL:
case KVM_CAP_USER_MEMORY:
@@ -532,6 +531,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
kvm_vgic_flush_hwstate(vcpu);
kvm_timer_flush_hwstate(vcpu);
+ preempt_disable();
local_irq_disable();
/*
@@ -544,6 +544,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
if (ret <= 0 || need_new_vmid_gen(vcpu->kvm)) {
local_irq_enable();
+ preempt_enable();
kvm_timer_sync_hwstate(vcpu);
kvm_vgic_sync_hwstate(vcpu);
continue;
@@ -553,14 +554,16 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
* Enter the guest
*/
trace_kvm_entry(*vcpu_pc(vcpu));
- kvm_guest_enter();
+ __kvm_guest_enter();
vcpu->mode = IN_GUEST_MODE;
ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
vcpu->mode = OUTSIDE_GUEST_MODE;
- kvm_guest_exit();
- trace_kvm_exit(kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
+ /*
+ * Back from guest
+ *************************************************************/
+
/*
* We may have taken a host interrupt in HYP mode (ie
* while executing the guest). This interrupt is still
@@ -574,8 +577,17 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
local_irq_enable();
/*
- * Back from guest
- *************************************************************/
+ * We do local_irq_enable() before calling kvm_guest_exit() so
+ * that if a timer interrupt hits while running the guest we
+ * account that tick as being spent in the guest. We enable
+ * preemption after calling kvm_guest_exit() so that if we get
+ * preempted we make sure ticks after that is not counted as
+ * guest time.
+ */
+ kvm_guest_exit();
+ trace_kvm_exit(kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
+ preempt_enable();
+
kvm_timer_sync_hwstate(vcpu);
kvm_vgic_sync_hwstate(vcpu);
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
index 79caf79b304a..568494dbbbb5 100644
--- a/arch/arm/kvm/interrupts.S
+++ b/arch/arm/kvm/interrupts.S
@@ -170,13 +170,9 @@ __kvm_vcpu_return:
@ Don't trap coprocessor accesses for host kernel
set_hstr vmexit
set_hdcr vmexit
- set_hcptr vmexit, (HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11))
+ set_hcptr vmexit, (HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11)), after_vfp_restore
#ifdef CONFIG_VFPv3
- @ Save floating point registers we if let guest use them.
- tst r2, #(HCPTR_TCP(10) | HCPTR_TCP(11))
- bne after_vfp_restore
-
@ Switch VFP/NEON hardware state to the host's
add r7, vcpu, #VCPU_VFP_GUEST
store_vfp_state r7
@@ -188,6 +184,8 @@ after_vfp_restore:
@ Restore FPEXC_EN which we clobbered on entry
pop {r2}
VFPFMXR FPEXC, r2
+#else
+after_vfp_restore:
#endif
@ Reset Hyp-role
@@ -309,7 +307,7 @@ ENTRY(kvm_call_hyp)
THUMB( orr r2, r2, #PSR_T_BIT )
msr spsr_cxsf, r2
mrs r1, ELR_hyp
- ldr r2, =BSYM(panic)
+ ldr r2, =panic
msr ELR_hyp, r2
ldr r0, =\panic_str
clrex @ Clear exclusive monitor
@@ -483,7 +481,7 @@ switch_to_guest_vfp:
push {r3-r7}
@ NEON/VFP used. Turn on VFP access.
- set_hcptr vmexit, (HCPTR_TCP(10) | HCPTR_TCP(11))
+ set_hcptr vmtrap, (HCPTR_TCP(10) | HCPTR_TCP(11))
@ Switch VFP/NEON hardware state to the guest's
add r7, r0, #VCPU_VFP_HOST
diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
index 35e4a3a0c476..702740d37465 100644
--- a/arch/arm/kvm/interrupts_head.S
+++ b/arch/arm/kvm/interrupts_head.S
@@ -412,7 +412,6 @@ vcpu .req r0 @ vcpu pointer always in r0
add r11, vcpu, #VCPU_VGIC_CPU
/* Save all interesting registers */
- ldr r3, [r2, #GICH_HCR]
ldr r4, [r2, #GICH_VMCR]
ldr r5, [r2, #GICH_MISR]
ldr r6, [r2, #GICH_EISR0]
@@ -420,7 +419,6 @@ vcpu .req r0 @ vcpu pointer always in r0
ldr r8, [r2, #GICH_ELRSR0]
ldr r9, [r2, #GICH_ELRSR1]
ldr r10, [r2, #GICH_APR]
-ARM_BE8(rev r3, r3 )
ARM_BE8(rev r4, r4 )
ARM_BE8(rev r5, r5 )
ARM_BE8(rev r6, r6 )
@@ -429,7 +427,6 @@ ARM_BE8(rev r8, r8 )
ARM_BE8(rev r9, r9 )
ARM_BE8(rev r10, r10 )
- str r3, [r11, #VGIC_V2_CPU_HCR]
str r4, [r11, #VGIC_V2_CPU_VMCR]
str r5, [r11, #VGIC_V2_CPU_MISR]
#ifdef CONFIG_CPU_ENDIAN_BE8
@@ -591,8 +588,13 @@ ARM_BE8(rev r6, r6 )
.endm
/* Configures the HCPTR (Hyp Coprocessor Trap Register) on entry/return
- * (hardware reset value is 0). Keep previous value in r2. */
-.macro set_hcptr operation, mask
+ * (hardware reset value is 0). Keep previous value in r2.
+ * An ISB is emited on vmexit/vmtrap, but executed on vmexit only if
+ * VFP wasn't already enabled (always executed on vmtrap).
+ * If a label is specified with vmexit, it is branched to if VFP wasn't
+ * enabled.
+ */
+.macro set_hcptr operation, mask, label = none
mrc p15, 4, r2, c1, c1, 2
ldr r3, =\mask
.if \operation == vmentry
@@ -601,6 +603,17 @@ ARM_BE8(rev r6, r6 )
bic r3, r2, r3 @ Don't trap defined coproc-accesses
.endif
mcr p15, 4, r3, c1, c1, 2
+ .if \operation != vmentry
+ .if \operation == vmexit
+ tst r2, #(HCPTR_TCP(10) | HCPTR_TCP(11))
+ beq 1f
+ .endif
+ isb
+ .if \label != none
+ b \label
+ .endif
+1:
+ .endif
.endm
/* Configures the HDCR (Hyp Debug Configuration Register) on entry/return
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 1d5accbd3dcf..7b4201294187 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -691,8 +691,8 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
* work. This is not used by the hardware and we have no
* alignment requirement for this allocation.
*/
- pgd = (pgd_t *)kmalloc(PTRS_PER_S2_PGD * sizeof(pgd_t),
- GFP_KERNEL | __GFP_ZERO);
+ pgd = kmalloc(PTRS_PER_S2_PGD * sizeof(pgd_t),
+ GFP_KERNEL | __GFP_ZERO);
if (!pgd) {
kvm_free_hwpgd(hwpgd);
@@ -1155,7 +1155,8 @@ static void stage2_wp_range(struct kvm *kvm, phys_addr_t addr, phys_addr_t end)
*/
void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot)
{
- struct kvm_memory_slot *memslot = id_to_memslot(kvm->memslots, slot);
+ struct kvm_memslots *slots = kvm_memslots(kvm);
+ struct kvm_memory_slot *memslot = id_to_memslot(slots, slot);
phys_addr_t start = memslot->base_gfn << PAGE_SHIFT;
phys_addr_t end = (memslot->base_gfn + memslot->npages) << PAGE_SHIFT;
@@ -1718,8 +1719,9 @@ out:
}
void kvm_arch_commit_memory_region(struct kvm *kvm,
- struct kvm_userspace_memory_region *mem,
+ const struct kvm_userspace_memory_region *mem,
const struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new,
enum kvm_mr_change change)
{
/*
@@ -1733,7 +1735,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
- struct kvm_userspace_memory_region *mem,
+ const struct kvm_userspace_memory_region *mem,
enum kvm_mr_change change)
{
hva_t hva = mem->userspace_addr;
@@ -1838,7 +1840,7 @@ int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
return 0;
}
-void kvm_arch_memslots_updated(struct kvm *kvm)
+void kvm_arch_memslots_updated(struct kvm *kvm, struct kvm_memslots *slots)
{
}
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c
index 02fa8eff6ae1..4b94b513168d 100644
--- a/arch/arm/kvm/psci.c
+++ b/arch/arm/kvm/psci.c
@@ -24,6 +24,8 @@
#include <asm/kvm_psci.h>
#include <asm/kvm_host.h>
+#include <uapi/linux/psci.h>
+
/*
* This is an implementation of the Power State Coordination Interface
* as described in ARM document number ARM DEN 0022A.
@@ -230,10 +232,6 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
case PSCI_0_2_FN64_AFFINITY_INFO:
val = kvm_psci_vcpu_affinity_info(vcpu);
break;
- case PSCI_0_2_FN_MIGRATE:
- case PSCI_0_2_FN64_MIGRATE:
- val = PSCI_RET_NOT_SUPPORTED;
- break;
case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
/*
* Trusted OS is MP hence does not require migration
@@ -242,10 +240,6 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
*/
val = PSCI_0_2_TOS_MP;
break;
- case PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
- case PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU:
- val = PSCI_RET_NOT_SUPPORTED;
- break;
case PSCI_0_2_FN_SYSTEM_OFF:
kvm_psci_system_off(vcpu);
/*
@@ -271,7 +265,8 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
ret = 0;
break;
default:
- return -EINVAL;
+ val = PSCI_RET_NOT_SUPPORTED;
+ break;
}
*vcpu_reg(vcpu, 0) = val;
@@ -291,12 +286,9 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
case KVM_PSCI_FN_CPU_ON:
val = kvm_psci_vcpu_on(vcpu);
break;
- case KVM_PSCI_FN_CPU_SUSPEND:
- case KVM_PSCI_FN_MIGRATE:
+ default:
val = PSCI_RET_NOT_SUPPORTED;
break;
- default:
- return -EINVAL;
}
*vcpu_reg(vcpu, 0) = val;
diff --git a/arch/arm/lib/call_with_stack.S b/arch/arm/lib/call_with_stack.S
index ed1a421813cb..bf3a40889205 100644
--- a/arch/arm/lib/call_with_stack.S
+++ b/arch/arm/lib/call_with_stack.S
@@ -35,7 +35,7 @@ ENTRY(call_with_stack)
mov r2, r0
mov r0, r1
- adr lr, BSYM(1f)
+ badr lr, 1f
ret r2
1: ldr lr, [sp]
diff --git a/arch/arm/lib/lib1funcs.S b/arch/arm/lib/lib1funcs.S
index 947567ff67f9..af2267f6a529 100644
--- a/arch/arm/lib/lib1funcs.S
+++ b/arch/arm/lib/lib1funcs.S
@@ -167,7 +167,7 @@ Boston, MA 02111-1307, USA. */
#endif
- @ Perform all needed substractions to keep only the reminder.
+ @ Perform all needed subtractions to keep only the reminder.
@ Do comparisons in batch of 4 first.
subs \order, \order, #3 @ yes, 3 is intended here
blt 2f
@@ -189,7 +189,7 @@ Boston, MA 02111-1307, USA. */
teqne \dividend, #0
beq 5f
- @ Either 1, 2 or 3 comparison/substractions are left.
+ @ Either 1, 2 or 3 comparison/subtractions are left.
2: cmn \order, #2
blt 4f
beq 3f
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 4fa8b4541e64..c5bbf8bb8c0f 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -1,13 +1,8 @@
#
# Makefile for the linux kernel.
#
-ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include
-asflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include
-
obj-y := soc.o
-obj-$(CONFIG_SOC_AT91SAM9) += sam9_smc.o
-
# CPU-specific support
obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o
obj-$(CONFIG_SOC_AT91SAM9) += at91sam9.o
diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
deleted file mode 100644
index 29ed0fa374ca..000000000000
--- a/arch/arm/mach-at91/Makefile.boot
+++ /dev/null
@@ -1,8 +0,0 @@
-# Note: the following conditions must always be true:
-# ZRELADDR == virt_to_phys(TEXTADDR)
-# PARAMS_PHYS must be within 4MB of ZRELADDR
-# INITRD_PHYS must be in RAM
-
- zreladdr-y += 0x20008000
-params_phys-y := 0x20000100
-initrd_phys-y := 0x20410000
diff --git a/arch/arm/mach-at91/include/mach/at91_ramc.h b/arch/arm/mach-at91/include/mach/at91_ramc.h
deleted file mode 100644
index 493bc486e858..000000000000
--- a/arch/arm/mach-at91/include/mach/at91_ramc.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Header file for the Atmel RAM Controller
- *
- * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- *
- * Under GPLv2 only
- */
-
-#ifndef __AT91_RAMC_H__
-#define __AT91_RAMC_H__
-
-#ifndef __ASSEMBLY__
-extern void __iomem *at91_ramc_base[];
-
-#define at91_ramc_read(id, field) \
- __raw_readl(at91_ramc_base[id] + field)
-
-#define at91_ramc_write(id, field, value) \
- __raw_writel(value, at91_ramc_base[id] + field)
-#else
-.extern at91_ramc_base
-#endif
-
-#include <soc/at91/at91rm9200_sdramc.h>
-#include <soc/at91/at91sam9_ddrsdr.h>
-#include <soc/at91/at91sam9_sdramc.h>
-
-#endif /* __AT91_RAMC_H__ */
diff --git a/arch/arm/mach-at91/include/mach/at91rm9200_mc.h b/arch/arm/mach-at91/include/mach/at91rm9200_mc.h
deleted file mode 100644
index aeaadfb452af..000000000000
--- a/arch/arm/mach-at91/include/mach/at91rm9200_mc.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91rm9200_mc.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * Memory Controllers (MC, EBI, SMC, SDRAMC, BFC) - System peripherals registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * 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 AT91RM9200_MC_H
-#define AT91RM9200_MC_H
-
-/* Memory Controller */
-#define AT91_MC_RCR 0x00 /* MC Remap Control Register */
-#define AT91_MC_RCB (1 << 0) /* Remap Command Bit */
-
-#define AT91_MC_ASR 0x04 /* MC Abort Status Register */
-#define AT91_MC_UNADD (1 << 0) /* Undefined Address Abort Status */
-#define AT91_MC_MISADD (1 << 1) /* Misaligned Address Abort Status */
-#define AT91_MC_ABTSZ (3 << 8) /* Abort Size Status */
-#define AT91_MC_ABTSZ_BYTE (0 << 8)
-#define AT91_MC_ABTSZ_HALFWORD (1 << 8)
-#define AT91_MC_ABTSZ_WORD (2 << 8)
-#define AT91_MC_ABTTYP (3 << 10) /* Abort Type Status */
-#define AT91_MC_ABTTYP_DATAREAD (0 << 10)
-#define AT91_MC_ABTTYP_DATAWRITE (1 << 10)
-#define AT91_MC_ABTTYP_FETCH (2 << 10)
-#define AT91_MC_MST0 (1 << 16) /* ARM920T Abort Source */
-#define AT91_MC_MST1 (1 << 17) /* PDC Abort Source */
-#define AT91_MC_MST2 (1 << 18) /* UHP Abort Source */
-#define AT91_MC_MST3 (1 << 19) /* EMAC Abort Source */
-#define AT91_MC_SVMST0 (1 << 24) /* Saved ARM920T Abort Source */
-#define AT91_MC_SVMST1 (1 << 25) /* Saved PDC Abort Source */
-#define AT91_MC_SVMST2 (1 << 26) /* Saved UHP Abort Source */
-#define AT91_MC_SVMST3 (1 << 27) /* Saved EMAC Abort Source */
-
-#define AT91_MC_AASR 0x08 /* MC Abort Address Status Register */
-
-#define AT91_MC_MPR 0x0c /* MC Master Priority Register */
-#define AT91_MPR_MSTP0 (7 << 0) /* ARM920T Priority */
-#define AT91_MPR_MSTP1 (7 << 4) /* PDC Priority */
-#define AT91_MPR_MSTP2 (7 << 8) /* UHP Priority */
-#define AT91_MPR_MSTP3 (7 << 12) /* EMAC Priority */
-
-/* External Bus Interface (EBI) registers */
-#define AT91_EBI_CSA 0x60 /* Chip Select Assignment Register */
-#define AT91_EBI_CS0A (1 << 0) /* Chip Select 0 Assignment */
-#define AT91_EBI_CS0A_SMC (0 << 0)
-#define AT91_EBI_CS0A_BFC (1 << 0)
-#define AT91_EBI_CS1A (1 << 1) /* Chip Select 1 Assignment */
-#define AT91_EBI_CS1A_SMC (0 << 1)
-#define AT91_EBI_CS1A_SDRAMC (1 << 1)
-#define AT91_EBI_CS3A (1 << 3) /* Chip Select 2 Assignment */
-#define AT91_EBI_CS3A_SMC (0 << 3)
-#define AT91_EBI_CS3A_SMC_SMARTMEDIA (1 << 3)
-#define AT91_EBI_CS4A (1 << 4) /* Chip Select 3 Assignment */
-#define AT91_EBI_CS4A_SMC (0 << 4)
-#define AT91_EBI_CS4A_SMC_COMPACTFLASH (1 << 4)
-#define AT91_EBI_CFGR (AT91_MC + 0x64) /* Configuration Register */
-#define AT91_EBI_DBPUC (1 << 0) /* Data Bus Pull-Up Configuration */
-
-/* Static Memory Controller (SMC) registers */
-#define AT91_SMC_CSR(n) (0x70 + ((n) * 4)) /* SMC Chip Select Register */
-#define AT91_SMC_NWS (0x7f << 0) /* Number of Wait States */
-#define AT91_SMC_NWS_(x) ((x) << 0)
-#define AT91_SMC_WSEN (1 << 7) /* Wait State Enable */
-#define AT91_SMC_TDF (0xf << 8) /* Data Float Time */
-#define AT91_SMC_TDF_(x) ((x) << 8)
-#define AT91_SMC_BAT (1 << 12) /* Byte Access Type */
-#define AT91_SMC_DBW (3 << 13) /* Data Bus Width */
-#define AT91_SMC_DBW_16 (1 << 13)
-#define AT91_SMC_DBW_8 (2 << 13)
-#define AT91_SMC_DPR (1 << 15) /* Data Read Protocol */
-#define AT91_SMC_ACSS (3 << 16) /* Address to Chip Select Setup */
-#define AT91_SMC_ACSS_STD (0 << 16)
-#define AT91_SMC_ACSS_1 (1 << 16)
-#define AT91_SMC_ACSS_2 (2 << 16)
-#define AT91_SMC_ACSS_3 (3 << 16)
-#define AT91_SMC_RWSETUP (7 << 24) /* Read & Write Signal Time Setup */
-#define AT91_SMC_RWSETUP_(x) ((x) << 24)
-#define AT91_SMC_RWHOLD (7 << 28) /* Read & Write Signal Hold Time */
-#define AT91_SMC_RWHOLD_(x) ((x) << 28)
-
-/* Burst Flash Controller register */
-#define AT91_BFC_MR 0xc0 /* Mode Register */
-#define AT91_BFC_BFCOM (3 << 0) /* Burst Flash Controller Operating Mode */
-#define AT91_BFC_BFCOM_DISABLED (0 << 0)
-#define AT91_BFC_BFCOM_ASYNC (1 << 0)
-#define AT91_BFC_BFCOM_BURST (2 << 0)
-#define AT91_BFC_BFCC (3 << 2) /* Burst Flash Controller Clock */
-#define AT91_BFC_BFCC_MCK (1 << 2)
-#define AT91_BFC_BFCC_DIV2 (2 << 2)
-#define AT91_BFC_BFCC_DIV4 (3 << 2)
-#define AT91_BFC_AVL (0xf << 4) /* Address Valid Latency */
-#define AT91_BFC_PAGES (7 << 8) /* Page Size */
-#define AT91_BFC_PAGES_NO_PAGE (0 << 8)
-#define AT91_BFC_PAGES_16 (1 << 8)
-#define AT91_BFC_PAGES_32 (2 << 8)
-#define AT91_BFC_PAGES_64 (3 << 8)
-#define AT91_BFC_PAGES_128 (4 << 8)
-#define AT91_BFC_PAGES_256 (5 << 8)
-#define AT91_BFC_PAGES_512 (6 << 8)
-#define AT91_BFC_PAGES_1024 (7 << 8)
-#define AT91_BFC_OEL (3 << 12) /* Output Enable Latency */
-#define AT91_BFC_BAAEN (1 << 16) /* Burst Address Advance Enable */
-#define AT91_BFC_BFOEH (1 << 17) /* Burst Flash Output Enable Handling */
-#define AT91_BFC_MUXEN (1 << 18) /* Multiplexed Bus Enable */
-#define AT91_BFC_RDYEN (1 << 19) /* Ready Enable Mode */
-
-#endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9_smc.h b/arch/arm/mach-at91/include/mach/at91sam9_smc.h
deleted file mode 100644
index ff54a0ce90e3..000000000000
--- a/arch/arm/mach-at91/include/mach/at91sam9_smc.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91sam9_smc.h
- *
- * Copyright (C) 2007 Andrew Victor
- * Copyright (C) 2007 Atmel Corporation.
- *
- * Static Memory Controllers (SMC) - System peripherals registers.
- * Based on AT91SAM9261 datasheet revision D.
- *
- * 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 AT91SAM9_SMC_H
-#define AT91SAM9_SMC_H
-
-#ifndef __ASSEMBLY__
-struct sam9_smc_config {
- /* Setup register */
- u8 ncs_read_setup;
- u8 nrd_setup;
- u8 ncs_write_setup;
- u8 nwe_setup;
-
- /* Pulse register */
- u8 ncs_read_pulse;
- u8 nrd_pulse;
- u8 ncs_write_pulse;
- u8 nwe_pulse;
-
- /* Cycle register */
- u16 read_cycle;
- u16 write_cycle;
-
- /* Mode register */
- u32 mode;
- u8 tdf_cycles:4;
-};
-
-extern void sam9_smc_configure(int id, int cs, struct sam9_smc_config *config);
-extern void sam9_smc_read(int id, int cs, struct sam9_smc_config *config);
-extern void sam9_smc_read_mode(int id, int cs, struct sam9_smc_config *config);
-extern void sam9_smc_write_mode(int id, int cs, struct sam9_smc_config *config);
-#endif
-
-#define AT91_SMC_SETUP 0x00 /* Setup Register for CS n */
-#define AT91_SMC_NWESETUP (0x3f << 0) /* NWE Setup Length */
-#define AT91_SMC_NWESETUP_(x) ((x) << 0)
-#define AT91_SMC_NCS_WRSETUP (0x3f << 8) /* NCS Setup Length in Write Access */
-#define AT91_SMC_NCS_WRSETUP_(x) ((x) << 8)
-#define AT91_SMC_NRDSETUP (0x3f << 16) /* NRD Setup Length */
-#define AT91_SMC_NRDSETUP_(x) ((x) << 16)
-#define AT91_SMC_NCS_RDSETUP (0x3f << 24) /* NCS Setup Length in Read Access */
-#define AT91_SMC_NCS_RDSETUP_(x) ((x) << 24)
-
-#define AT91_SMC_PULSE 0x04 /* Pulse Register for CS n */
-#define AT91_SMC_NWEPULSE (0x7f << 0) /* NWE Pulse Length */
-#define AT91_SMC_NWEPULSE_(x) ((x) << 0)
-#define AT91_SMC_NCS_WRPULSE (0x7f << 8) /* NCS Pulse Length in Write Access */
-#define AT91_SMC_NCS_WRPULSE_(x)((x) << 8)
-#define AT91_SMC_NRDPULSE (0x7f << 16) /* NRD Pulse Length */
-#define AT91_SMC_NRDPULSE_(x) ((x) << 16)
-#define AT91_SMC_NCS_RDPULSE (0x7f << 24) /* NCS Pulse Length in Read Access */
-#define AT91_SMC_NCS_RDPULSE_(x)((x) << 24)
-
-#define AT91_SMC_CYCLE 0x08 /* Cycle Register for CS n */
-#define AT91_SMC_NWECYCLE (0x1ff << 0 ) /* Total Write Cycle Length */
-#define AT91_SMC_NWECYCLE_(x) ((x) << 0)
-#define AT91_SMC_NRDCYCLE (0x1ff << 16) /* Total Read Cycle Length */
-#define AT91_SMC_NRDCYCLE_(x) ((x) << 16)
-
-#define AT91_SMC_MODE 0x0c /* Mode Register for CS n */
-#define AT91_SMC_READMODE (1 << 0) /* Read Mode */
-#define AT91_SMC_WRITEMODE (1 << 1) /* Write Mode */
-#define AT91_SMC_EXNWMODE (3 << 4) /* NWAIT Mode */
-#define AT91_SMC_EXNWMODE_DISABLE (0 << 4)
-#define AT91_SMC_EXNWMODE_FROZEN (2 << 4)
-#define AT91_SMC_EXNWMODE_READY (3 << 4)
-#define AT91_SMC_BAT (1 << 8) /* Byte Access Type */
-#define AT91_SMC_BAT_SELECT (0 << 8)
-#define AT91_SMC_BAT_WRITE (1 << 8)
-#define AT91_SMC_DBW (3 << 12) /* Data Bus Width */
-#define AT91_SMC_DBW_8 (0 << 12)
-#define AT91_SMC_DBW_16 (1 << 12)
-#define AT91_SMC_DBW_32 (2 << 12)
-#define AT91_SMC_TDF (0xf << 16) /* Data Float Time. */
-#define AT91_SMC_TDF_(x) ((x) << 16)
-#define AT91_SMC_TDFMODE (1 << 20) /* TDF Optimization - Enabled */
-#define AT91_SMC_PMEN (1 << 24) /* Page Mode Enabled */
-#define AT91_SMC_PS (3 << 28) /* Page Size */
-#define AT91_SMC_PS_4 (0 << 28)
-#define AT91_SMC_PS_8 (1 << 28)
-#define AT91_SMC_PS_16 (2 << 28)
-#define AT91_SMC_PS_32 (3 << 28)
-
-#endif
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 5062699cbb12..1e184767c3be 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -233,7 +233,7 @@ static void at91_pm_set_standby(void (*at91_standby)(void))
*/
static void at91rm9200_standby(void)
{
- u32 lpr = at91_ramc_read(0, AT91RM9200_SDRAMC_LPR);
+ u32 lpr = at91_ramc_read(0, AT91_MC_SDRAMC_LPR);
asm volatile(
"b 1f\n\t"
@@ -244,8 +244,8 @@ static void at91rm9200_standby(void)
" mcr p15, 0, %0, c7, c0, 4\n\t"
" str %5, [%1, %2]"
:
- : "r" (0), "r" (at91_ramc_base[0]), "r" (AT91RM9200_SDRAMC_LPR),
- "r" (1), "r" (AT91RM9200_SDRAMC_SRR),
+ : "r" (0), "r" (at91_ramc_base[0]), "r" (AT91_MC_SDRAMC_LPR),
+ "r" (1), "r" (AT91_MC_SDRAMC_SRR),
"r" (lpr));
}
@@ -414,7 +414,7 @@ void __init at91rm9200_pm_init(void)
/*
* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh.
*/
- at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0);
+ at91_ramc_write(0, AT91_MC_SDRAMC_LPR, 0);
at91_pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP;
at91_pm_data.memctrl = AT91_MEMCTRL_MC;
diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
index ecd875a91d52..3fcf8810f14e 100644
--- a/arch/arm/mach-at91/pm.h
+++ b/arch/arm/mach-at91/pm.h
@@ -13,7 +13,19 @@
#include <asm/proc-fns.h>
-#include <mach/at91_ramc.h>
+#include <linux/mfd/syscon/atmel-mc.h>
+#include <soc/at91/at91sam9_ddrsdr.h>
+#include <soc/at91/at91sam9_sdramc.h>
+
+#ifndef __ASSEMBLY__
+extern void __iomem *at91_ramc_base[];
+
+#define at91_ramc_read(id, field) \
+ __raw_readl(at91_ramc_base[id] + field)
+
+#define at91_ramc_write(id, field, value) \
+ __raw_writel(value, at91_ramc_base[id] + field)
+#endif
#define AT91_MEMCTRL_MC 0
#define AT91_MEMCTRL_SDRAMC 1
diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S
index bd22b2c8a051..0d95f488b47a 100644
--- a/arch/arm/mach-at91/pm_suspend.S
+++ b/arch/arm/mach-at91/pm_suspend.S
@@ -13,7 +13,6 @@
*/
#include <linux/linkage.h>
#include <linux/clk/at91_pmc.h>
-#include <mach/at91_ramc.h>
#include "pm.h"
#define SRAMC_SELF_FRESH_ACTIVE 0x01
@@ -216,7 +215,7 @@ ENTRY(at91_sramc_self_refresh)
/* Active SDRAM self-refresh mode */
mov r3, #1
- str r3, [r2, #AT91RM9200_SDRAMC_SRR]
+ str r3, [r2, #AT91_MC_SDRAMC_SRR]
b exit_sramc_sf
ddrc_sf:
diff --git a/arch/arm/mach-at91/sam9_smc.c b/arch/arm/mach-at91/sam9_smc.c
deleted file mode 100644
index 826315af6d11..000000000000
--- a/arch/arm/mach-at91/sam9_smc.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/sam9_smc.c
- *
- * Copyright (C) 2008 Andrew Victor
- * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.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/io.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-
-#include <mach/at91sam9_smc.h>
-
-#include "sam9_smc.h"
-
-
-#define AT91_SMC_CS(id, n) (smc_base_addr[id] + ((n) * 0x10))
-
-static void __iomem *smc_base_addr[2];
-
-static void sam9_smc_cs_write_mode(void __iomem *base,
- struct sam9_smc_config *config)
-{
- __raw_writel(config->mode
- | AT91_SMC_TDF_(config->tdf_cycles),
- base + AT91_SMC_MODE);
-}
-
-void sam9_smc_write_mode(int id, int cs,
- struct sam9_smc_config *config)
-{
- sam9_smc_cs_write_mode(AT91_SMC_CS(id, cs), config);
-}
-EXPORT_SYMBOL_GPL(sam9_smc_write_mode);
-
-static void sam9_smc_cs_configure(void __iomem *base,
- struct sam9_smc_config *config)
-{
-
- /* Setup register */
- __raw_writel(AT91_SMC_NWESETUP_(config->nwe_setup)
- | AT91_SMC_NCS_WRSETUP_(config->ncs_write_setup)
- | AT91_SMC_NRDSETUP_(config->nrd_setup)
- | AT91_SMC_NCS_RDSETUP_(config->ncs_read_setup),
- base + AT91_SMC_SETUP);
-
- /* Pulse register */
- __raw_writel(AT91_SMC_NWEPULSE_(config->nwe_pulse)
- | AT91_SMC_NCS_WRPULSE_(config->ncs_write_pulse)
- | AT91_SMC_NRDPULSE_(config->nrd_pulse)
- | AT91_SMC_NCS_RDPULSE_(config->ncs_read_pulse),
- base + AT91_SMC_PULSE);
-
- /* Cycle register */
- __raw_writel(AT91_SMC_NWECYCLE_(config->write_cycle)
- | AT91_SMC_NRDCYCLE_(config->read_cycle),
- base + AT91_SMC_CYCLE);
-
- /* Mode register */
- sam9_smc_cs_write_mode(base, config);
-}
-
-void sam9_smc_configure(int id, int cs,
- struct sam9_smc_config *config)
-{
- sam9_smc_cs_configure(AT91_SMC_CS(id, cs), config);
-}
-EXPORT_SYMBOL_GPL(sam9_smc_configure);
-
-static void sam9_smc_cs_read_mode(void __iomem *base,
- struct sam9_smc_config *config)
-{
- u32 val = __raw_readl(base + AT91_SMC_MODE);
-
- config->mode = (val & ~AT91_SMC_NWECYCLE);
- config->tdf_cycles = (val & AT91_SMC_NWECYCLE) >> 16 ;
-}
-
-void sam9_smc_read_mode(int id, int cs,
- struct sam9_smc_config *config)
-{
- sam9_smc_cs_read_mode(AT91_SMC_CS(id, cs), config);
-}
-EXPORT_SYMBOL_GPL(sam9_smc_read_mode);
-
-static void sam9_smc_cs_read(void __iomem *base,
- struct sam9_smc_config *config)
-{
- u32 val;
-
- /* Setup register */
- val = __raw_readl(base + AT91_SMC_SETUP);
-
- config->nwe_setup = val & AT91_SMC_NWESETUP;
- config->ncs_write_setup = (val & AT91_SMC_NCS_WRSETUP) >> 8;
- config->nrd_setup = (val & AT91_SMC_NRDSETUP) >> 16;
- config->ncs_read_setup = (val & AT91_SMC_NCS_RDSETUP) >> 24;
-
- /* Pulse register */
- val = __raw_readl(base + AT91_SMC_PULSE);
-
- config->nwe_pulse = val & AT91_SMC_NWEPULSE;
- config->ncs_write_pulse = (val & AT91_SMC_NCS_WRPULSE) >> 8;
- config->nrd_pulse = (val & AT91_SMC_NRDPULSE) >> 16;
- config->ncs_read_pulse = (val & AT91_SMC_NCS_RDPULSE) >> 24;
-
- /* Cycle register */
- val = __raw_readl(base + AT91_SMC_CYCLE);
-
- config->write_cycle = val & AT91_SMC_NWECYCLE;
- config->read_cycle = (val & AT91_SMC_NRDCYCLE) >> 16;
-
- /* Mode register */
- sam9_smc_cs_read_mode(base, config);
-}
-
-void sam9_smc_read(int id, int cs, struct sam9_smc_config *config)
-{
- sam9_smc_cs_read(AT91_SMC_CS(id, cs), config);
-}
-
-void __init at91sam9_ioremap_smc(int id, u32 addr)
-{
- if (id > 1) {
- pr_warn("%s: id > 2\n", __func__);
- return;
- }
- smc_base_addr[id] = ioremap(addr, 512);
- if (!smc_base_addr[id])
- pr_warn("Impossible to ioremap smc.%d 0x%x\n", id, addr);
-}
diff --git a/arch/arm/mach-at91/sam9_smc.h b/arch/arm/mach-at91/sam9_smc.h
deleted file mode 100644
index 3e52dcd4a59f..000000000000
--- a/arch/arm/mach-at91/sam9_smc.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/sam9_smc.
- *
- * Copyright (C) 2008 Andrew Victor
- *
- * 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.
- */
-
-extern void __init at91sam9_ioremap_smc(int id, u32 addr);
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
index 8b11f44bb36e..e9184feffc4e 100644
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -19,6 +19,7 @@ config ARCH_BCM_IPROC
select ARCH_REQUIRE_GPIOLIB
select ARM_AMBA
select PINCTRL
+ select MTD_NAND_BRCMNAND
help
This enables support for systems based on Broadcom IPROC architected SoCs.
The IPROC complex contains one or more ARM CPUs along with common
@@ -144,6 +145,7 @@ config ARCH_BRCMSTB
select BRCMSTB_GISB_ARB
select BRCMSTB_L2_IRQ
select BCM7120_L2_IRQ
+ select ARCH_WANT_OPTIONAL_GPIOLIB
help
Say Y if you intend to run the kernel on a Broadcom ARM-based STB
chipset.
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index 4c38674c73ec..4fb0da458e91 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -38,10 +38,15 @@ obj-$(CONFIG_ARCH_BCM2835) += board_bcm2835.o
obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o
# BCM63XXx
-obj-$(CONFIG_ARCH_BCM_63XX) := bcm63xx.o
+ifeq ($(CONFIG_ARCH_BCM_63XX),y)
+CFLAGS_bcm63xx_headsmp.o += -march=armv7-a
+obj-y += bcm63xx.o
+obj-$(CONFIG_SMP) += bcm63xx_smp.o bcm63xx_headsmp.o \
+ bcm63xx_pmb.o
+endif
ifeq ($(CONFIG_ARCH_BRCMSTB),y)
CFLAGS_platsmp-brcmstb.o += -march=armv7-a
obj-y += brcmstb.o
-obj-$(CONFIG_SMP) += headsmp-brcmstb.o platsmp-brcmstb.o
+obj-$(CONFIG_SMP) += platsmp-brcmstb.o
endif
diff --git a/arch/arm/mach-bcm/bcm63xx_headsmp.S b/arch/arm/mach-bcm/bcm63xx_headsmp.S
new file mode 100644
index 000000000000..c7af397c7f14
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm63xx_headsmp.S
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015, Broadcom 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.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+
+ENTRY(bcm63138_secondary_startup)
+ ARM_BE8(setend be)
+ /*
+ * L1 cache does have unpredictable contents at power-up clean its
+ * contents without flushing
+ */
+ bl v7_invalidate_l1
+ nop
+
+ b secondary_startup
+ENDPROC(bcm63138_secondary_startup)
diff --git a/arch/arm/mach-bcm/bcm63xx_pmb.c b/arch/arm/mach-bcm/bcm63xx_pmb.c
new file mode 100644
index 000000000000..de061ec5a479
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm63xx_pmb.c
@@ -0,0 +1,221 @@
+/*
+ * Broadcom BCM63138 PMB initialization for secondary CPU(s)
+ *
+ * Copyright (C) 2015 Broadcom Corporation
+ * Author: Florian Fainelli <f.fainelli@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.
+ */
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/reset/bcm63xx_pmb.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "bcm63xx_smp.h"
+
+/* ARM Control register definitions */
+#define CORE_PWR_CTRL_SHIFT 0
+#define CORE_PWR_CTRL_MASK 0x3
+#define PLL_PWR_ON BIT(8)
+#define PLL_LDO_PWR_ON BIT(9)
+#define PLL_CLAMP_ON BIT(10)
+#define CPU_RESET_N(x) BIT(13 + (x))
+#define NEON_RESET_N BIT(15)
+#define PWR_CTRL_STATUS_SHIFT 28
+#define PWR_CTRL_STATUS_MASK 0x3
+#define PWR_DOWN_SHIFT 30
+#define PWR_DOWN_MASK 0x3
+
+/* CPU Power control register definitions */
+#define MEM_PWR_OK BIT(0)
+#define MEM_PWR_ON BIT(1)
+#define MEM_CLAMP_ON BIT(2)
+#define MEM_PWR_OK_STATUS BIT(4)
+#define MEM_PWR_ON_STATUS BIT(5)
+#define MEM_PDA_SHIFT 8
+#define MEM_PDA_MASK 0xf
+#define MEM_PDA_CPU_MASK 0x1
+#define MEM_PDA_NEON_MASK 0xf
+#define CLAMP_ON BIT(15)
+#define PWR_OK_SHIFT 16
+#define PWR_OK_MASK 0xf
+#define PWR_ON_SHIFT 20
+#define PWR_CPU_MASK 0x03
+#define PWR_NEON_MASK 0x01
+#define PWR_ON_MASK 0xf
+#define PWR_OK_STATUS_SHIFT 24
+#define PWR_OK_STATUS_MASK 0xf
+#define PWR_ON_STATUS_SHIFT 28
+#define PWR_ON_STATUS_MASK 0xf
+
+#define ARM_CONTROL 0x30
+#define ARM_PWR_CONTROL_BASE 0x34
+#define ARM_PWR_CONTROL(x) (ARM_PWR_CONTROL_BASE + (x) * 0x4)
+#define ARM_NEON_L2 0x3c
+
+/* Perform a value write, then spin until the value shifted by
+ * shift is seen, masked with mask and is different from cond.
+ */
+static int bpcm_wr_rd_mask(void __iomem *master,
+ unsigned int addr, u32 off, u32 *val,
+ u32 shift, u32 mask, u32 cond)
+{
+ int ret;
+
+ ret = bpcm_wr(master, addr, off, *val);
+ if (ret)
+ return ret;
+
+ do {
+ ret = bpcm_rd(master, addr, off, val);
+ if (ret)
+ return ret;
+
+ cpu_relax();
+ } while (((*val >> shift) & mask) != cond);
+
+ return ret;
+}
+
+/* Global lock to serialize accesses to the PMB registers while we
+ * are bringing up the secondary CPU
+ */
+static DEFINE_SPINLOCK(pmb_lock);
+
+static int bcm63xx_pmb_get_resources(struct device_node *dn,
+ void __iomem **base,
+ unsigned int *cpu,
+ unsigned int *addr)
+{
+ struct device_node *pmb_dn;
+ struct of_phandle_args args;
+ int ret;
+
+ ret = of_property_read_u32(dn, "reg", cpu);
+ if (ret) {
+ pr_err("CPU is missing a reg node\n");
+ return ret;
+ }
+
+ ret = of_parse_phandle_with_args(dn, "resets", "#reset-cells",
+ 0, &args);
+ if (ret) {
+ pr_err("CPU is missing a resets phandle\n");
+ return ret;
+ }
+
+ pmb_dn = args.np;
+ if (args.args_count != 2) {
+ pr_err("reset-controller does not conform to reset-cells\n");
+ return -EINVAL;
+ }
+
+ *base = of_iomap(args.np, 0);
+ if (!*base) {
+ pr_err("failed remapping PMB register\n");
+ return -ENOMEM;
+ }
+
+ /* We do not need the number of zones */
+ *addr = args.args[0];
+
+ return 0;
+}
+
+int bcm63xx_pmb_power_on_cpu(struct device_node *dn)
+{
+ void __iomem *base;
+ unsigned int cpu, addr;
+ unsigned long flags;
+ u32 val, ctrl;
+ int ret;
+
+ ret = bcm63xx_pmb_get_resources(dn, &base, &cpu, &addr);
+ if (ret)
+ return ret;
+
+ /* We would not know how to enable a third and greater CPU */
+ WARN_ON(cpu > 1);
+
+ spin_lock_irqsave(&pmb_lock, flags);
+
+ /* Check if the CPU is already on and save the ARM_CONTROL register
+ * value since we will use it later for CPU de-assert once done with
+ * the CPU-specific power sequence
+ */
+ ret = bpcm_rd(base, addr, ARM_CONTROL, &ctrl);
+ if (ret)
+ goto out;
+
+ if (ctrl & CPU_RESET_N(cpu)) {
+ pr_info("PMB: CPU%d is already powered on\n", cpu);
+ ret = 0;
+ goto out;
+ }
+
+ /* Power on PLL */
+ ret = bpcm_rd(base, addr, ARM_PWR_CONTROL(cpu), &val);
+ if (ret)
+ goto out;
+
+ val |= (PWR_CPU_MASK << PWR_ON_SHIFT);
+
+ ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
+ PWR_ON_STATUS_SHIFT, PWR_CPU_MASK, PWR_CPU_MASK);
+ if (ret)
+ goto out;
+
+ val |= (PWR_CPU_MASK << PWR_OK_SHIFT);
+
+ ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
+ PWR_OK_STATUS_SHIFT, PWR_CPU_MASK, PWR_CPU_MASK);
+ if (ret)
+ goto out;
+
+ val &= ~CLAMP_ON;
+
+ ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
+ if (ret)
+ goto out;
+
+ /* Power on CPU<N> RAM */
+ val &= ~(MEM_PDA_MASK << MEM_PDA_SHIFT);
+
+ ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
+ if (ret)
+ goto out;
+
+ val |= MEM_PWR_ON;
+
+ ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
+ 0, MEM_PWR_ON_STATUS, MEM_PWR_ON_STATUS);
+ if (ret)
+ goto out;
+
+ val |= MEM_PWR_OK;
+
+ ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
+ 0, MEM_PWR_OK_STATUS, MEM_PWR_OK_STATUS);
+ if (ret)
+ goto out;
+
+ val &= ~MEM_CLAMP_ON;
+
+ ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
+ if (ret)
+ goto out;
+
+ /* De-assert CPU reset */
+ ctrl |= CPU_RESET_N(cpu);
+
+ ret = bpcm_wr(base, addr, ARM_CONTROL, ctrl);
+out:
+ spin_unlock_irqrestore(&pmb_lock, flags);
+ iounmap(base);
+ return ret;
+}
diff --git a/arch/arm/mach-bcm/bcm63xx_smp.c b/arch/arm/mach-bcm/bcm63xx_smp.c
new file mode 100644
index 000000000000..3f014f18cea5
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm63xx_smp.c
@@ -0,0 +1,169 @@
+/*
+ * Broadcom BCM63138 DSL SoCs SMP support code
+ *
+ * Copyright (C) 2015, Broadcom Corporation
+ *
+ * Licensed under the terms of the GPLv2
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <asm/cacheflush.h>
+#include <asm/smp_scu.h>
+#include <asm/smp_plat.h>
+#include <asm/vfp.h>
+
+#include "bcm63xx_smp.h"
+
+/* Size of mapped Cortex A9 SCU address space */
+#define CORTEX_A9_SCU_SIZE 0x58
+
+/*
+ * Enable the Cortex A9 Snoop Control Unit
+ *
+ * By the time this is called we already know there are multiple
+ * cores present. We assume we're running on a Cortex A9 processor,
+ * so any trouble getting the base address register or getting the
+ * SCU base is a problem.
+ *
+ * Return 0 if successful or an error code otherwise.
+ */
+static int __init scu_a9_enable(void)
+{
+ unsigned long config_base;
+ void __iomem *scu_base;
+ unsigned int i, ncores;
+
+ if (!scu_a9_has_base()) {
+ pr_err("no configuration base address register!\n");
+ return -ENXIO;
+ }
+
+ /* Config base address register value is zero for uniprocessor */
+ config_base = scu_a9_get_base();
+ if (!config_base) {
+ pr_err("hardware reports only one core\n");
+ return -ENOENT;
+ }
+
+ scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
+ if (!scu_base) {
+ pr_err("failed to remap config base (%lu/%u) for SCU\n",
+ config_base, CORTEX_A9_SCU_SIZE);
+ return -ENOMEM;
+ }
+
+ scu_enable(scu_base);
+
+ ncores = scu_base ? scu_get_core_count(scu_base) : 1;
+
+ if (ncores > nr_cpu_ids) {
+ pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+ ncores, nr_cpu_ids);
+ ncores = nr_cpu_ids;
+ }
+
+ /* The BCM63138 SoC has two Cortex-A9 CPUs, CPU0 features a complete
+ * and fully functional VFP unit that can be used, but CPU1 does not.
+ * Since we will not be able to trap kernel-mode NEON to force
+ * migration to CPU0, just do not advertise VFP support at all.
+ *
+ * This will make vfp_init bail out and do not attempt to use VFP at
+ * all, for kernel-mode NEON, we do not want to introduce any
+ * conditionals in hot-paths, so we just restrict the system to UP.
+ */
+#ifdef CONFIG_VFP
+ if (ncores > 1) {
+ pr_warn("SMP: secondary CPUs lack VFP unit, disabling VFP\n");
+ vfp_disable();
+
+#ifdef CONFIG_KERNEL_MODE_NEON
+ WARN(1, "SMP: kernel-mode NEON enabled, restricting to UP\n");
+ ncores = 1;
+#endif
+ }
+#endif
+
+ for (i = 0; i < ncores; i++)
+ set_cpu_possible(i, true);
+
+ iounmap(scu_base); /* That's the last we'll need of this */
+
+ return 0;
+}
+
+static const struct of_device_id bcm63138_bootlut_ids[] = {
+ { .compatible = "brcm,bcm63138-bootlut", },
+ { /* sentinel */ },
+};
+
+#define BOOTLUT_RESET_VECT 0x20
+
+static int bcm63138_smp_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ void __iomem *bootlut_base;
+ struct device_node *dn;
+ int ret = 0;
+ u32 val;
+
+ dn = of_find_matching_node(NULL, bcm63138_bootlut_ids);
+ if (!dn) {
+ pr_err("SMP: unable to find bcm63138 boot LUT node\n");
+ return -ENODEV;
+ }
+
+ bootlut_base = of_iomap(dn, 0);
+ of_node_put(dn);
+
+ if (!bootlut_base) {
+ pr_err("SMP: unable to remap boot LUT base register\n");
+ return -ENOMEM;
+ }
+
+ /* Locate the secondary CPU node */
+ dn = of_get_cpu_node(cpu_logical_map(cpu), NULL);
+ if (!dn) {
+ pr_err("SMP: failed to locate secondary CPU%d node\n", cpu);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Write the secondary init routine to the BootLUT reset vector */
+ val = virt_to_phys(bcm63138_secondary_startup);
+ writel_relaxed(val, bootlut_base + BOOTLUT_RESET_VECT);
+
+ /* Power up the core, will jump straight to its reset vector when we
+ * return
+ */
+ ret = bcm63xx_pmb_power_on_cpu(dn);
+ if (ret)
+ goto out;
+out:
+ iounmap(bootlut_base);
+
+ return ret;
+}
+
+static void __init bcm63138_smp_prepare_cpus(unsigned int max_cpus)
+{
+ int ret;
+
+ ret = scu_a9_enable();
+ if (ret) {
+ pr_warn("SMP: Cortex-A9 SCU setup failed\n");
+ return;
+ }
+}
+
+struct smp_operations bcm63138_smp_ops __initdata = {
+ .smp_prepare_cpus = bcm63138_smp_prepare_cpus,
+ .smp_boot_secondary = bcm63138_smp_boot_secondary,
+};
+
+CPU_METHOD_OF_DECLARE(bcm63138_smp, "brcm,bcm63138", &bcm63138_smp_ops);
diff --git a/arch/arm/mach-bcm/bcm63xx_smp.h b/arch/arm/mach-bcm/bcm63xx_smp.h
new file mode 100644
index 000000000000..50b76044536e
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm63xx_smp.h
@@ -0,0 +1,9 @@
+#ifndef __BCM63XX_SMP_H
+#define __BCM63XX_SMP_H
+
+struct device_node;
+
+extern void bcm63138_secondary_startup(void);
+extern int bcm63xx_pmb_power_on_cpu(struct device_node *dn);
+
+#endif /* __BCM63XX_SMP_H */
diff --git a/arch/arm/mach-bcm/bcm_5301x.c b/arch/arm/mach-bcm/bcm_5301x.c
index e9bcbdbce555..7aef92720eb4 100644
--- a/arch/arm/mach-bcm/bcm_5301x.c
+++ b/arch/arm/mach-bcm/bcm_5301x.c
@@ -18,15 +18,16 @@ static bool first_fault = true;
static int bcm5301x_abort_handler(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
- if (fsr == 0x1c06 && first_fault) {
+ if ((fsr == 0x1406 || fsr == 0x1c06) && first_fault) {
first_fault = false;
/*
- * These faults with code 0x1c06 happens for no good reason,
- * possibly left over from the CFE boot loader.
+ * 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);
+ addr, fsr);
/* Returning non-zero causes fault display and panic */
return 0;
diff --git a/arch/arm/mach-bcm/board_bcm2835.c b/arch/arm/mach-bcm/board_bcm2835.c
index 70f2f3925f0e..0f7b9eac3d15 100644
--- a/arch/arm/mach-bcm/board_bcm2835.c
+++ b/arch/arm/mach-bcm/board_bcm2835.c
@@ -12,7 +12,6 @@
* GNU General Public License for more details.
*/
-#include <linux/delay.h>
#include <linux/init.h>
#include <linux/irqchip.h>
#include <linux/of_address.h>
@@ -22,97 +21,10 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#define PM_RSTC 0x1c
-#define PM_RSTS 0x20
-#define PM_WDOG 0x24
-
-#define PM_PASSWORD 0x5a000000
-#define PM_RSTC_WRCFG_MASK 0x00000030
-#define PM_RSTC_WRCFG_FULL_RESET 0x00000020
-#define PM_RSTS_HADWRH_SET 0x00000040
-
-#define BCM2835_PERIPH_PHYS 0x20000000
-#define BCM2835_PERIPH_VIRT 0xf0000000
-#define BCM2835_PERIPH_SIZE SZ_16M
-
-static void __iomem *wdt_regs;
-
-/*
- * The machine restart method can be called from an atomic context so we won't
- * be able to ioremap the regs then.
- */
-static void bcm2835_setup_restart(void)
-{
- struct device_node *np = of_find_compatible_node(NULL, NULL,
- "brcm,bcm2835-pm-wdt");
- if (WARN(!np, "unable to setup watchdog restart"))
- return;
-
- wdt_regs = of_iomap(np, 0);
- WARN(!wdt_regs, "failed to remap watchdog regs");
-}
-
-static void bcm2835_restart(enum reboot_mode mode, const char *cmd)
-{
- u32 val;
-
- if (!wdt_regs)
- return;
-
- /* use a timeout of 10 ticks (~150us) */
- writel_relaxed(10 | PM_PASSWORD, wdt_regs + PM_WDOG);
- val = readl_relaxed(wdt_regs + PM_RSTC);
- val &= ~PM_RSTC_WRCFG_MASK;
- val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
- writel_relaxed(val, wdt_regs + PM_RSTC);
-
- /* No sleeping, possibly atomic. */
- mdelay(1);
-}
-
-/*
- * We can't really power off, but if we do the normal reset scheme, and
- * indicate to bootcode.bin not to reboot, then most of the chip will be
- * powered off.
- */
-static void bcm2835_power_off(void)
-{
- u32 val;
-
- /*
- * We set the watchdog hard reset bit here to distinguish this reset
- * from the normal (full) reset. bootcode.bin will not reboot after a
- * hard reset.
- */
- val = readl_relaxed(wdt_regs + PM_RSTS);
- val &= ~PM_RSTC_WRCFG_MASK;
- val |= PM_PASSWORD | PM_RSTS_HADWRH_SET;
- writel_relaxed(val, wdt_regs + PM_RSTS);
-
- /* Continue with normal reset mechanism */
- bcm2835_restart(REBOOT_HARD, "");
-}
-
-static struct map_desc io_map __initdata = {
- .virtual = BCM2835_PERIPH_VIRT,
- .pfn = __phys_to_pfn(BCM2835_PERIPH_PHYS),
- .length = BCM2835_PERIPH_SIZE,
- .type = MT_DEVICE
-};
-
-static void __init bcm2835_map_io(void)
-{
- iotable_init(&io_map, 1);
-}
-
static void __init bcm2835_init(void)
{
int ret;
- bcm2835_setup_restart();
- if (wdt_regs)
- pm_power_off = bcm2835_power_off;
-
bcm2835_init_clocks();
ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
@@ -129,9 +41,6 @@ static const char * const bcm2835_compat[] = {
};
DT_MACHINE_START(BCM2835, "BCM2835")
- .map_io = bcm2835_map_io,
- .init_irq = irqchip_init,
.init_machine = bcm2835_init,
- .restart = bcm2835_restart,
.dt_compat = bcm2835_compat
MACHINE_END
diff --git a/arch/arm/mach-bcm/brcmstb.h b/arch/arm/mach-bcm/brcmstb.h
deleted file mode 100644
index ec0c3d112b36..000000000000
--- a/arch/arm/mach-bcm/brcmstb.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2013-2014 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.
- */
-
-#ifndef __BRCMSTB_H__
-#define __BRCMSTB_H__
-
-void brcmstb_secondary_startup(void);
-
-#endif /* __BRCMSTB_H__ */
diff --git a/arch/arm/mach-bcm/headsmp-brcmstb.S b/arch/arm/mach-bcm/headsmp-brcmstb.S
deleted file mode 100644
index 199c1ea58248..000000000000
--- a/arch/arm/mach-bcm/headsmp-brcmstb.S
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SMP boot code for secondary CPUs
- * Based on arch/arm/mach-tegra/headsmp.S
- *
- * Copyright (C) 2010 NVIDIA, Inc.
- * Copyright (C) 2013-2014 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 <asm/assembler.h>
-#include <linux/linkage.h>
-#include <linux/init.h>
-
- .section ".text.head", "ax"
-
-ENTRY(brcmstb_secondary_startup)
- /*
- * Ensure CPU is in a sane state by disabling all IRQs and switching
- * into SVC mode.
- */
- setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r0
-
- bl v7_invalidate_l1
- b secondary_startup
-ENDPROC(brcmstb_secondary_startup)
diff --git a/arch/arm/mach-bcm/platsmp-brcmstb.c b/arch/arm/mach-bcm/platsmp-brcmstb.c
index e209e6fc7caf..44d6bddf7a4e 100644
--- a/arch/arm/mach-bcm/platsmp-brcmstb.c
+++ b/arch/arm/mach-bcm/platsmp-brcmstb.c
@@ -30,8 +30,6 @@
#include <asm/mach-types.h>
#include <asm/smp_plat.h>
-#include "brcmstb.h"
-
enum {
ZONE_MAN_CLKEN_MASK = BIT(0),
ZONE_MAN_RESET_CNTL_MASK = BIT(1),
@@ -153,7 +151,7 @@ static void brcmstb_cpu_boot(u32 cpu)
* Set the reset vector to point to the secondary_startup
* routine
*/
- cpu_set_boot_addr(cpu, virt_to_phys(brcmstb_secondary_startup));
+ cpu_set_boot_addr(cpu, virt_to_phys(secondary_startup));
/* Unhalt the cpu */
cpu_rst_cfg_set(cpu, 0);
diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig
index 3e40a947f3ea..742d53a5f7f9 100644
--- a/arch/arm/mach-berlin/Kconfig
+++ b/arch/arm/mach-berlin/Kconfig
@@ -6,6 +6,7 @@ menuconfig ARCH_BERLIN
select DW_APB_ICTL
select DW_APB_TIMER_OF
select GENERIC_IRQ_CHIP
+ select MFD_SYSCON
select PINCTRL
if ARCH_BERLIN
diff --git a/arch/arm/mach-berlin/headsmp.S b/arch/arm/mach-berlin/headsmp.S
index 4a4c56a58ad3..dc82a3486b05 100644
--- a/arch/arm/mach-berlin/headsmp.S
+++ b/arch/arm/mach-berlin/headsmp.S
@@ -12,12 +12,6 @@
#include <linux/init.h>
#include <asm/assembler.h>
-ENTRY(berlin_secondary_startup)
- ARM_BE8(setend be)
- bl v7_invalidate_l1
- b secondary_startup
-ENDPROC(berlin_secondary_startup)
-
/*
* If the following instruction is set in the reset exception vector, CPUs
* will fetch the value of the software reset address vector when being
diff --git a/arch/arm/mach-berlin/platsmp.c b/arch/arm/mach-berlin/platsmp.c
index 702e7982015a..34a3753e7356 100644
--- a/arch/arm/mach-berlin/platsmp.c
+++ b/arch/arm/mach-berlin/platsmp.c
@@ -22,7 +22,6 @@
#define RESET_VECT 0x00
#define SW_RESET_ADDR 0x94
-extern void berlin_secondary_startup(void);
extern u32 boot_inst;
static void __iomem *cpu_ctrl;
@@ -85,7 +84,7 @@ static void __init berlin_smp_prepare_cpus(unsigned int max_cpus)
* Write the secondary startup address into the SW reset address
* vector. This is used by boot_inst.
*/
- writel(virt_to_phys(berlin_secondary_startup), vectors_base + SW_RESET_ADDR);
+ writel(virt_to_phys(secondary_startup), vectors_base + SW_RESET_ADDR);
iounmap(vectors_base);
unmap_scu:
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 45ce065e7170..3b8740c083c4 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -11,6 +11,7 @@
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
+#include <linux/clkdev.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/clk.h>
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index 39e58b48e826..f9f9713aacdd 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -36,7 +36,7 @@ extern void __iomem *da8xx_syscfg1_base;
/*
* If the DA850/OMAP-L138/AM18x SoC on board is of a higher speed grade
- * (than the regular 300Mhz variant), the board code should set this up
+ * (than the regular 300MHz variant), the board code should set this up
* with the supported speed before calling da850_register_cpufreq().
*/
extern unsigned int da850_max_speed;
diff --git a/arch/arm/mach-davinci/pm_domain.c b/arch/arm/mach-davinci/pm_domain.c
index 641edc313938..78eac2c0c146 100644
--- a/arch/arm/mach-davinci/pm_domain.c
+++ b/arch/arm/mach-davinci/pm_domain.c
@@ -14,39 +14,9 @@
#include <linux/pm_clock.h>
#include <linux/platform_device.h>
-#ifdef CONFIG_PM
-static int davinci_pm_runtime_suspend(struct device *dev)
-{
- int ret;
-
- dev_dbg(dev, "%s\n", __func__);
-
- ret = pm_generic_runtime_suspend(dev);
- if (ret)
- return ret;
-
- ret = pm_clk_suspend(dev);
- if (ret) {
- pm_generic_runtime_resume(dev);
- return ret;
- }
-
- return 0;
-}
-
-static int davinci_pm_runtime_resume(struct device *dev)
-{
- dev_dbg(dev, "%s\n", __func__);
-
- pm_clk_resume(dev);
- return pm_generic_runtime_resume(dev);
-}
-#endif
-
static struct dev_pm_domain davinci_pm_domain = {
.ops = {
- SET_RUNTIME_PM_OPS(davinci_pm_runtime_suspend,
- davinci_pm_runtime_resume, NULL)
+ USE_PM_CLK_RUNTIME_OPS
USE_PLATFORM_PM_SLEEP_OPS
},
};
diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c
index 36f22c1a31fe..3c950f5864f3 100644
--- a/arch/arm/mach-ep93xx/simone.c
+++ b/arch/arm/mach-ep93xx/simone.c
@@ -20,9 +20,14 @@
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
+#include <linux/mmc/host.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/mmc_spi.h>
+#include <linux/platform_data/video-ep93xx.h>
+#include <linux/platform_data/spi-ep93xx.h>
+#include <linux/gpio.h>
#include <mach/hardware.h>
-#include <linux/platform_data/video-ep93xx.h>
#include <mach/gpio-ep93xx.h>
#include <asm/mach-types.h>
@@ -40,6 +45,132 @@ static struct ep93xxfb_mach_info __initdata simone_fb_info = {
.flags = EP93XXFB_USE_SDCSN0 | EP93XXFB_PCLK_FALLING,
};
+/*
+ * GPIO lines used for MMC card detection.
+ */
+#define MMC_CARD_DETECT_GPIO EP93XX_GPIO_LINE_EGPIO0
+
+/*
+ * Up to v1.3, the Sim.One used SFRMOUT as SD card chip select, but this goes
+ * low between multi-message command blocks. From v1.4, it uses a GPIO instead.
+ * v1.3 parts will still work, since the signal on SFRMOUT is automatic.
+ */
+#define MMC_CHIP_SELECT_GPIO EP93XX_GPIO_LINE_EGPIO1
+
+/*
+ * MMC SPI chip select GPIO handling. If you are using SFRMOUT (SFRM1) signal,
+ * you can leave these empty and pass NULL as .controller_data.
+ */
+
+static int simone_mmc_spi_setup(struct spi_device *spi)
+{
+ unsigned int gpio = MMC_CHIP_SELECT_GPIO;
+ int err;
+
+ err = gpio_request(gpio, spi->modalias);
+ if (err)
+ return err;
+
+ err = gpio_direction_output(gpio, 1);
+ if (err) {
+ gpio_free(gpio);
+ return err;
+ }
+
+ return 0;
+}
+
+static void simone_mmc_spi_cleanup(struct spi_device *spi)
+{
+ unsigned int gpio = MMC_CHIP_SELECT_GPIO;
+
+ gpio_set_value(gpio, 1);
+ gpio_direction_input(gpio);
+ gpio_free(gpio);
+}
+
+static void simone_mmc_spi_cs_control(struct spi_device *spi, int value)
+{
+ gpio_set_value(MMC_CHIP_SELECT_GPIO, value);
+}
+
+static struct ep93xx_spi_chip_ops simone_mmc_spi_ops = {
+ .setup = simone_mmc_spi_setup,
+ .cleanup = simone_mmc_spi_cleanup,
+ .cs_control = simone_mmc_spi_cs_control,
+};
+
+/*
+ * MMC card detection GPIO setup.
+ */
+
+static int simone_mmc_spi_init(struct device *dev,
+ irqreturn_t (*irq_handler)(int, void *), void *mmc)
+{
+ unsigned int gpio = MMC_CARD_DETECT_GPIO;
+ int irq, err;
+
+ err = gpio_request(gpio, dev_name(dev));
+ if (err)
+ return err;
+
+ err = gpio_direction_input(gpio);
+ if (err)
+ goto fail;
+
+ irq = gpio_to_irq(gpio);
+ if (irq < 0)
+ goto fail;
+
+ err = request_irq(irq, irq_handler, IRQF_TRIGGER_FALLING,
+ "MMC card detect", mmc);
+ if (err)
+ goto fail;
+
+ printk(KERN_INFO "%s: using irq %d for MMC card detection\n",
+ dev_name(dev), irq);
+
+ return 0;
+fail:
+ gpio_free(gpio);
+ return err;
+}
+
+static void simone_mmc_spi_exit(struct device *dev, void *mmc)
+{
+ unsigned int gpio = MMC_CARD_DETECT_GPIO;
+
+ free_irq(gpio_to_irq(gpio), mmc);
+ gpio_free(gpio);
+}
+
+static struct mmc_spi_platform_data simone_mmc_spi_data = {
+ .init = simone_mmc_spi_init,
+ .exit = simone_mmc_spi_exit,
+ .detect_delay = 500,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+};
+
+static struct spi_board_info simone_spi_devices[] __initdata = {
+ {
+ .modalias = "mmc_spi",
+ .controller_data = &simone_mmc_spi_ops,
+ .platform_data = &simone_mmc_spi_data,
+ /*
+ * We use 10 MHz even though the maximum is 3.7 MHz. The driver
+ * will limit it automatically to max. frequency.
+ */
+ .max_speed_hz = 10 * 1000 * 1000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .mode = SPI_MODE_3,
+ },
+};
+
+static struct ep93xx_spi_info simone_spi_info __initdata = {
+ .num_chipselect = ARRAY_SIZE(simone_spi_devices),
+};
+
static struct i2c_gpio_platform_data __initdata simone_i2c_gpio_data = {
.sda_pin = EP93XX_GPIO_LINE_EEDAT,
.sda_is_open_drain = 0,
@@ -74,6 +205,8 @@ static void __init simone_init_machine(void)
ep93xx_register_fb(&simone_fb_info);
ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
ARRAY_SIZE(simone_i2c_board_info));
+ ep93xx_register_spi(&simone_spi_info, simone_spi_devices,
+ ARRAY_SIZE(simone_spi_devices));
simone_register_audio();
}
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 5f5cd562c593..e3a9256ed55f 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -163,7 +163,9 @@ extern void exynos_set_delayed_reset_assertion(bool enable);
extern void s5p_init_cpu(void __iomem *cpuid_addr);
extern unsigned int samsung_rev(void);
-extern void __iomem *cpu_boot_reg_base(void);
+extern void exynos_core_restart(u32 core_id);
+extern int exynos_set_boot_addr(u32 core_id, unsigned long boot_addr);
+extern int exynos_get_boot_addr(u32 core_id, unsigned long *boot_addr);
static inline void pmu_raw_writel(u32 val, u32 offset)
{
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
index 5917a30eee33..4bd8b7653817 100644
--- a/arch/arm/mach-exynos/exynos.c
+++ b/arch/arm/mach-exynos/exynos.c
@@ -234,7 +234,8 @@ static void __init exynos_dt_machine_init(void)
exynos_sysram_init();
#if defined(CONFIG_SMP) && defined(CONFIG_ARM_EXYNOS_CPUIDLE)
- if (of_machine_is_compatible("samsung,exynos4210"))
+ if (of_machine_is_compatible("samsung,exynos4210") ||
+ of_machine_is_compatible("samsung,exynos3250"))
exynos_cpuidle.dev.platform_data = &cpuidle_coupled_exynos_data;
#endif
if (of_machine_is_compatible("samsung,exynos4210") ||
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c
index 1bd35763f12e..245f6dec1ded 100644
--- a/arch/arm/mach-exynos/firmware.c
+++ b/arch/arm/mach-exynos/firmware.c
@@ -49,6 +49,7 @@ static int exynos_do_idle(unsigned long mode)
sysram_ns_base_addr + 0x24);
__raw_writel(EXYNOS_AFTR_MAGIC, sysram_ns_base_addr + 0x20);
if (soc_is_exynos3250()) {
+ flush_cache_all();
exynos_smc(SMC_CMD_SAVE, OP_TYPE_CORE,
SMC_POWERSTATE_IDLE, 0);
exynos_smc(SMC_CMD_SHUTDOWN, OP_TYPE_CLUSTER,
@@ -104,6 +105,22 @@ static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr)
return 0;
}
+static int exynos_get_cpu_boot_addr(int cpu, unsigned long *boot_addr)
+{
+ void __iomem *boot_reg;
+
+ if (!sysram_ns_base_addr)
+ return -ENODEV;
+
+ boot_reg = sysram_ns_base_addr + 0x1c;
+
+ if (soc_is_exynos4412())
+ boot_reg += 4 * cpu;
+
+ *boot_addr = __raw_readl(boot_reg);
+ return 0;
+}
+
static int exynos_cpu_suspend(unsigned long arg)
{
flush_cache_all();
@@ -138,6 +155,7 @@ static int exynos_resume(void)
static const struct firmware_ops exynos_firmware_ops = {
.do_idle = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_do_idle : NULL,
.set_cpu_boot_addr = exynos_set_cpu_boot_addr,
+ .get_cpu_boot_addr = exynos_get_cpu_boot_addr,
.cpu_boot = exynos_cpu_boot,
.suspend = IS_ENABLED(CONFIG_PM_SLEEP) ? exynos_suspend : NULL,
.resume = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_resume : NULL,
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index a825bca2a2b6..58e05a2eae57 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -169,7 +169,7 @@ int exynos_cluster_power_state(int cluster)
S5P_CORE_LOCAL_PWR_EN);
}
-void __iomem *cpu_boot_reg_base(void)
+static void __iomem *cpu_boot_reg_base(void)
{
if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_1_1)
return pmu_base_addr + S5P_INFORM5;
@@ -195,7 +195,7 @@ static inline void __iomem *cpu_boot_reg(int cpu)
*
* Currently this is needed only when booting secondary CPU on Exynos3250.
*/
-static void exynos_core_restart(u32 core_id)
+void exynos_core_restart(u32 core_id)
{
u32 val;
@@ -210,7 +210,6 @@ static void exynos_core_restart(u32 core_id)
val |= S5P_CORE_WAKEUP_FROM_LOCAL_CFG;
pmu_raw_writel(val, EXYNOS_ARM_CORE_STATUS(core_id));
- pr_info("CPU%u: Software reset\n", core_id);
pmu_raw_writel(EXYNOS_CORE_PO_RESET(core_id), EXYNOS_SWRESET);
}
@@ -248,6 +247,56 @@ static void exynos_secondary_init(unsigned int cpu)
spin_unlock(&boot_lock);
}
+int exynos_set_boot_addr(u32 core_id, unsigned long boot_addr)
+{
+ int ret;
+
+ /*
+ * Try to set boot address using firmware first
+ * and fall back to boot register if it fails.
+ */
+ ret = call_firmware_op(set_cpu_boot_addr, core_id, boot_addr);
+ if (ret && ret != -ENOSYS)
+ goto fail;
+ if (ret == -ENOSYS) {
+ void __iomem *boot_reg = cpu_boot_reg(core_id);
+
+ if (IS_ERR(boot_reg)) {
+ ret = PTR_ERR(boot_reg);
+ goto fail;
+ }
+ __raw_writel(boot_addr, boot_reg);
+ ret = 0;
+ }
+fail:
+ return ret;
+}
+
+int exynos_get_boot_addr(u32 core_id, unsigned long *boot_addr)
+{
+ int ret;
+
+ /*
+ * Try to get boot address using firmware first
+ * and fall back to boot register if it fails.
+ */
+ ret = call_firmware_op(get_cpu_boot_addr, core_id, boot_addr);
+ if (ret && ret != -ENOSYS)
+ goto fail;
+ if (ret == -ENOSYS) {
+ void __iomem *boot_reg = cpu_boot_reg(core_id);
+
+ if (IS_ERR(boot_reg)) {
+ ret = PTR_ERR(boot_reg);
+ goto fail;
+ }
+ *boot_addr = __raw_readl(boot_reg);
+ ret = 0;
+ }
+fail:
+ return ret;
+}
+
static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
unsigned long timeout;
@@ -307,22 +356,9 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
boot_addr = virt_to_phys(exynos4_secondary_startup);
- /*
- * Try to set boot address using firmware first
- * and fall back to boot register if it fails.
- */
- ret = call_firmware_op(set_cpu_boot_addr, core_id, boot_addr);
- if (ret && ret != -ENOSYS)
+ ret = exynos_set_boot_addr(core_id, boot_addr);
+ if (ret)
goto fail;
- if (ret == -ENOSYS) {
- void __iomem *boot_reg = cpu_boot_reg(core_id);
-
- if (IS_ERR(boot_reg)) {
- ret = PTR_ERR(boot_reg);
- goto fail;
- }
- __raw_writel(boot_addr, boot_reg);
- }
call_firmware_op(cpu_boot, core_id);
@@ -337,6 +373,9 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
udelay(10);
}
+ if (pen_release != -1)
+ ret = -ETIMEDOUT;
+
/*
* now the secondary core is starting up let it run its
* calibrations, then wait for it to finish
@@ -407,16 +446,9 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
boot_addr = virt_to_phys(exynos4_secondary_startup);
- ret = call_firmware_op(set_cpu_boot_addr, core_id, boot_addr);
- if (ret && ret != -ENOSYS)
+ ret = exynos_set_boot_addr(core_id, boot_addr);
+ if (ret)
break;
- if (ret == -ENOSYS) {
- void __iomem *boot_reg = cpu_boot_reg(core_id);
-
- if (IS_ERR(boot_reg))
- break;
- __raw_writel(boot_addr, boot_reg);
- }
}
}
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index cc75ab448be3..9c1506b499bc 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -22,6 +22,7 @@
#include <asm/firmware.h>
#include <asm/smp_scu.h>
#include <asm/suspend.h>
+#include <asm/cacheflush.h>
#include <mach/map.h>
@@ -209,6 +210,8 @@ static int exynos_cpu0_enter_aftr(void)
* sequence, let's wait for one of these to happen
*/
while (exynos_cpu_power_state(1)) {
+ unsigned long boot_addr;
+
/*
* The other cpu may skip idle and boot back
* up again
@@ -221,7 +224,11 @@ static int exynos_cpu0_enter_aftr(void)
* boot back up again, getting stuck in the
* boot rom code
*/
- if (__raw_readl(cpu_boot_reg_base()) == 0)
+ ret = exynos_get_boot_addr(1, &boot_addr);
+ if (ret)
+ goto fail;
+ ret = -1;
+ if (boot_addr == 0)
goto abort;
cpu_relax();
@@ -233,11 +240,14 @@ static int exynos_cpu0_enter_aftr(void)
abort:
if (cpu_online(1)) {
+ unsigned long boot_addr = virt_to_phys(exynos_cpu_resume);
+
/*
* Set the boot vector to something non-zero
*/
- __raw_writel(virt_to_phys(exynos_cpu_resume),
- cpu_boot_reg_base());
+ ret = exynos_set_boot_addr(1, boot_addr);
+ if (ret)
+ goto fail;
dsb();
/*
@@ -247,22 +257,42 @@ abort:
while (exynos_cpu_power_state(1) != S5P_CORE_LOCAL_PWR_EN)
cpu_relax();
+ if (soc_is_exynos3250()) {
+ while (!pmu_raw_readl(S5P_PMU_SPARE2) &&
+ !atomic_read(&cpu1_wakeup))
+ cpu_relax();
+
+ if (!atomic_read(&cpu1_wakeup))
+ exynos_core_restart(1);
+ }
+
while (!atomic_read(&cpu1_wakeup)) {
+ smp_rmb();
+
/*
* Poke cpu1 out of the boot rom
*/
- __raw_writel(virt_to_phys(exynos_cpu_resume),
- cpu_boot_reg_base());
- arch_send_wakeup_ipi_mask(cpumask_of(1));
+ ret = exynos_set_boot_addr(1, boot_addr);
+ if (ret)
+ goto fail;
+
+ call_firmware_op(cpu_boot, 1);
+
+ if (soc_is_exynos3250())
+ dsb_sev();
+ else
+ arch_send_wakeup_ipi_mask(cpumask_of(1));
}
}
-
+fail:
return ret;
}
static int exynos_wfi_finisher(unsigned long flags)
{
+ if (soc_is_exynos3250())
+ flush_cache_all();
cpu_do_idle();
return -1;
@@ -283,6 +313,9 @@ static int exynos_cpu1_powerdown(void)
*/
exynos_cpu_power_down(1);
+ if (soc_is_exynos3250())
+ pmu_raw_writel(0, S5P_PMU_SPARE2);
+
ret = cpu_suspend(0, exynos_wfi_finisher);
cpu_pm_exit();
@@ -299,7 +332,9 @@ cpu1_aborted:
static void exynos_pre_enter_aftr(void)
{
- __raw_writel(virt_to_phys(exynos_cpu_resume), cpu_boot_reg_base());
+ unsigned long boot_addr = virt_to_phys(exynos_cpu_resume);
+
+ (void)exynos_set_boot_addr(1, boot_addr);
}
static void exynos_post_enter_aftr(void)
diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c
index a9686535f9ed..6001f1c9d136 100644
--- a/arch/arm/mach-exynos/pm_domains.c
+++ b/arch/arm/mach-exynos/pm_domains.c
@@ -62,6 +62,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
if (IS_ERR(pd->clk[i]))
break;
+ pd->pclk[i] = clk_get_parent(pd->clk[i]);
if (clk_set_parent(pd->clk[i], pd->oscclk))
pr_err("%s: error setting oscclk as parent to clock %d\n",
pd->name, i);
@@ -90,6 +91,9 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
if (IS_ERR(pd->clk[i]))
break;
+
+ if (IS_ERR(pd->clk[i]))
+ continue; /* Skip on first power up */
if (clk_set_parent(pd->clk[i], pd->pclk[i]))
pr_err("%s: error setting parent to clock%d\n",
pd->name, i);
@@ -117,27 +121,37 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain)
static __init int exynos4_pm_init_power_domain(void)
{
- struct platform_device *pdev;
struct device_node *np;
for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") {
struct exynos_pm_domain *pd;
int on, i;
- struct device *dev;
-
- pdev = of_find_device_by_node(np);
- dev = &pdev->dev;
pd = kzalloc(sizeof(*pd), GFP_KERNEL);
if (!pd) {
pr_err("%s: failed to allocate memory for domain\n",
__func__);
+ of_node_put(np);
+ return -ENOMEM;
+ }
+ pd->pd.name = kstrdup_const(strrchr(np->full_name, '/') + 1,
+ GFP_KERNEL);
+ if (!pd->pd.name) {
+ kfree(pd);
+ of_node_put(np);
return -ENOMEM;
}
- pd->pd.name = kstrdup(dev_name(dev), GFP_KERNEL);
pd->name = pd->pd.name;
pd->base = of_iomap(np, 0);
+ if (!pd->base) {
+ pr_warn("%s: failed to map memory\n", __func__);
+ kfree(pd->pd.name);
+ kfree(pd);
+ of_node_put(np);
+ continue;
+ }
+
pd->pd.power_off = exynos_pd_power_off;
pd->pd.power_on = exynos_pd_power_on;
@@ -145,12 +159,12 @@ static __init int exynos4_pm_init_power_domain(void)
char clk_name[8];
snprintf(clk_name, sizeof(clk_name), "asb%d", i);
- pd->asb_clk[i] = clk_get(dev, clk_name);
+ pd->asb_clk[i] = of_clk_get_by_name(np, clk_name);
if (IS_ERR(pd->asb_clk[i]))
break;
}
- pd->oscclk = clk_get(dev, "oscclk");
+ pd->oscclk = of_clk_get_by_name(np, "oscclk");
if (IS_ERR(pd->oscclk))
goto no_clk;
@@ -158,16 +172,14 @@ static __init int exynos4_pm_init_power_domain(void)
char clk_name[8];
snprintf(clk_name, sizeof(clk_name), "clk%d", i);
- pd->clk[i] = clk_get(dev, clk_name);
+ pd->clk[i] = of_clk_get_by_name(np, clk_name);
if (IS_ERR(pd->clk[i]))
break;
- snprintf(clk_name, sizeof(clk_name), "pclk%d", i);
- pd->pclk[i] = clk_get(dev, clk_name);
- if (IS_ERR(pd->pclk[i])) {
- clk_put(pd->clk[i]);
- pd->clk[i] = ERR_PTR(-EINVAL);
- break;
- }
+ /*
+ * Skip setting parent on first power up.
+ * The parent at this time may not be useful at all.
+ */
+ pd->pclk[i] = ERR_PTR(-EINVAL);
}
if (IS_ERR(pd->clk[0]))
@@ -189,15 +201,15 @@ no_clk:
args.args_count = 0;
child_domain = of_genpd_get_from_provider(&args);
if (IS_ERR(child_domain))
- continue;
+ goto next_pd;
if (of_parse_phandle_with_args(np, "power-domains",
"#power-domain-cells", 0, &args) != 0)
- continue;
+ goto next_pd;
parent_domain = of_genpd_get_from_provider(&args);
if (IS_ERR(parent_domain))
- continue;
+ goto next_pd;
if (pm_genpd_add_subdomain(parent_domain, child_domain))
pr_warn("%s failed to add subdomain: %s\n",
@@ -205,9 +217,10 @@ no_clk:
else
pr_info("%s has as child subdomain: %s.\n",
parent_domain->name, child_domain->name);
+next_pd:
of_node_put(np);
}
return 0;
}
-arch_initcall(exynos4_pm_init_power_domain);
+core_initcall(exynos4_pm_init_power_domain);
diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c
index c15761ca2f18..e812c1c85624 100644
--- a/arch/arm/mach-exynos/pmu.c
+++ b/arch/arm/mach-exynos/pmu.c
@@ -681,7 +681,7 @@ static unsigned int const exynos5420_list_disable_pmu_reg[] = {
EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG,
};
-static void exynos5_power_off(void)
+static void exynos_power_off(void)
{
unsigned int tmp;
@@ -872,8 +872,6 @@ static void exynos5420_pmu_init(void)
EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI);
pmu_raw_writel(0x1, EXYNOS5420_UP_SCHEDULER);
-
- pm_power_off = exynos5_power_off;
pr_info("EXYNOS5420 PMU initialized\n");
}
@@ -984,6 +982,8 @@ static int exynos_pmu_probe(struct platform_device *pdev)
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/suspend.c b/arch/arm/mach-exynos/suspend.c
index 7d23ce04cad5..f572219c7a40 100644
--- a/arch/arm/mach-exynos/suspend.c
+++ b/arch/arm/mach-exynos/suspend.c
@@ -223,7 +223,7 @@ static int exynos_pmu_domain_alloc(struct irq_domain *domain,
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args);
}
-static struct irq_domain_ops exynos_pmu_domain_ops = {
+static const struct irq_domain_ops exynos_pmu_domain_ops = {
.xlate = exynos_pmu_domain_xlate,
.alloc = exynos_pmu_domain_alloc,
.free = irq_domain_free_irqs_common,
@@ -311,13 +311,7 @@ static int exynos5420_cpu_suspend(unsigned long arg)
if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) {
mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume);
-
- /*
- * Residency value passed to mcpm_cpu_suspend back-end
- * has to be given clear semantics. Set to 0 as a
- * temporary value.
- */
- mcpm_cpu_suspend(0);
+ mcpm_cpu_suspend();
}
pr_info("Failed to suspend the system\n");
diff --git a/arch/arm/mach-footbridge/dma.c b/arch/arm/mach-footbridge/dma.c
index e2e0df8bcee2..22536b85a81d 100644
--- a/arch/arm/mach-footbridge/dma.c
+++ b/arch/arm/mach-footbridge/dma.c
@@ -13,9 +13,9 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/spinlock.h>
+#include <linux/scatterlist.h>
#include <asm/dma.h>
-#include <asm/scatterlist.h>
#include <asm/mach/dma.h>
#include <asm/hardware/dec21285.h>
diff --git a/arch/arm/mach-gemini/gpio.c b/arch/arm/mach-gemini/gpio.c
index f8cb5710d6ee..3292f2e6ed6f 100644
--- a/arch/arm/mach-gemini/gpio.c
+++ b/arch/arm/mach-gemini/gpio.c
@@ -223,8 +223,8 @@ void __init gemini_gpio_init(void)
set_irq_flags(j, IRQF_VALID);
}
- irq_set_chained_handler(IRQ_GPIO(i), gpio_irq_handler);
- irq_set_handler_data(IRQ_GPIO(i), (void *)i);
+ irq_set_chained_handler_and_data(IRQ_GPIO(i), gpio_irq_handler,
+ (void *)i);
}
BUG_ON(gpiochip_add(&gemini_gpio_chip));
diff --git a/arch/arm/mach-hisi/Makefile b/arch/arm/mach-hisi/Makefile
index 6b7b3033de0b..659db1933ed3 100644
--- a/arch/arm/mach-hisi/Makefile
+++ b/arch/arm/mach-hisi/Makefile
@@ -6,4 +6,4 @@ CFLAGS_platmcpm.o := -march=armv7-a
obj-y += hisilicon.o
obj-$(CONFIG_MCPM) += platmcpm.o
-obj-$(CONFIG_SMP) += platsmp.o hotplug.o headsmp.o
+obj-$(CONFIG_SMP) += platsmp.o hotplug.o
diff --git a/arch/arm/mach-hisi/core.h b/arch/arm/mach-hisi/core.h
index 92a682d8e939..c7648ef1825c 100644
--- a/arch/arm/mach-hisi/core.h
+++ b/arch/arm/mach-hisi/core.h
@@ -12,7 +12,6 @@ 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 void hisi_secondary_startup(void);
extern struct smp_operations hix5hd2_smp_ops;
extern void hix5hd2_set_cpu(int cpu, bool enable);
extern void hix5hd2_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-hisi/headsmp.S b/arch/arm/mach-hisi/headsmp.S
deleted file mode 100644
index 81e35b159e75..000000000000
--- a/arch/arm/mach-hisi/headsmp.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright (c) 2014 Hisilicon Limited.
- * Copyright (c) 2014 Linaro 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.
- */
-#include <linux/linkage.h>
-#include <linux/init.h>
-
- __CPUINIT
-
-ENTRY(hisi_secondary_startup)
- bl v7_invalidate_l1
- b secondary_startup
diff --git a/arch/arm/mach-hisi/platmcpm.c b/arch/arm/mach-hisi/platmcpm.c
index 280f3f14f77c..b5f8f5ffda79 100644
--- a/arch/arm/mach-hisi/platmcpm.c
+++ b/arch/arm/mach-hisi/platmcpm.c
@@ -6,6 +6,8 @@
* 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/smp.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/memblock.h>
@@ -13,7 +15,9 @@
#include <asm/cputype.h>
#include <asm/cp15.h>
-#include <asm/mcpm.h>
+#include <asm/cacheflush.h>
+#include <asm/smp.h>
+#include <asm/smp_plat.h>
#include "core.h"
@@ -94,11 +98,16 @@ static void hip04_set_snoop_filter(unsigned int cluster, unsigned int on)
} while (data != readl_relaxed(fabric + FAB_SF_MODE));
}
-static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster)
+static int hip04_boot_secondary(unsigned int l_cpu, struct task_struct *idle)
{
+ unsigned int mpidr, cpu, cluster;
unsigned long data;
void __iomem *sys_dreq, *sys_status;
+ mpidr = cpu_logical_map(l_cpu);
+ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
if (!sysctrl)
return -ENODEV;
if (cluster >= HIP04_MAX_CLUSTERS || cpu >= HIP04_MAX_CPUS_PER_CLUSTER)
@@ -118,6 +127,7 @@ static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster)
cpu_relax();
data = readl_relaxed(sys_status);
} while (data & CLUSTER_DEBUG_RESET_STATUS);
+ hip04_set_snoop_filter(cluster, 1);
}
data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
@@ -126,11 +136,15 @@ static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster)
do {
cpu_relax();
} while (data == readl_relaxed(sys_status));
+
/*
* We may fail to power up core again without this delay.
* It's not mentioned in document. It's found by test.
*/
udelay(20);
+
+ arch_send_wakeup_ipi_mask(cpumask_of(l_cpu));
+
out:
hip04_cpu_table[cluster][cpu]++;
spin_unlock_irq(&boot_lock);
@@ -138,31 +152,30 @@ out:
return 0;
}
-static void hip04_mcpm_power_down(void)
+#ifdef CONFIG_HOTPLUG_CPU
+static void hip04_cpu_die(unsigned int l_cpu)
{
unsigned int mpidr, cpu, cluster;
- bool skip_wfi = false, last_man = false;
+ bool last_man;
- mpidr = read_cpuid_mpidr();
+ mpidr = cpu_logical_map(l_cpu);
cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
- __mcpm_cpu_going_down(cpu, cluster);
-
spin_lock(&boot_lock);
- BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
hip04_cpu_table[cluster][cpu]--;
if (hip04_cpu_table[cluster][cpu] == 1) {
/* A power_up request went ahead of us. */
- skip_wfi = true;
+ spin_unlock(&boot_lock);
+ return;
} else if (hip04_cpu_table[cluster][cpu] > 1) {
pr_err("Cluster %d CPU%d boots multiple times\n", cluster, cpu);
BUG();
}
last_man = hip04_cluster_is_down(cluster);
- if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
- spin_unlock(&boot_lock);
+ spin_unlock(&boot_lock);
+ if (last_man) {
/* Since it's Cortex A15, disable L2 prefetching. */
asm volatile(
"mcr p15, 1, %0, c15, c0, 3 \n\t"
@@ -170,34 +183,30 @@ static void hip04_mcpm_power_down(void)
"dsb "
: : "r" (0x400) );
v7_exit_coherency_flush(all);
- hip04_set_snoop_filter(cluster, 0);
- __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
} else {
- spin_unlock(&boot_lock);
v7_exit_coherency_flush(louis);
}
- __mcpm_cpu_down(cpu, cluster);
-
- if (!skip_wfi)
+ for (;;)
wfi();
}
-static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
+static int hip04_cpu_kill(unsigned int l_cpu)
{
+ unsigned int mpidr, cpu, cluster;
unsigned int data, tries, count;
- int ret = -ETIMEDOUT;
+ mpidr = cpu_logical_map(l_cpu);
+ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
BUG_ON(cluster >= HIP04_MAX_CLUSTERS ||
cpu >= HIP04_MAX_CPUS_PER_CLUSTER);
count = TIMEOUT_MSEC / POLL_MSEC;
spin_lock_irq(&boot_lock);
for (tries = 0; tries < count; tries++) {
- if (hip04_cpu_table[cluster][cpu]) {
- ret = -EBUSY;
+ if (hip04_cpu_table[cluster][cpu])
goto err;
- }
cpu_relax();
data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
if (data & CORE_WFI_STATUS(cpu))
@@ -220,64 +229,22 @@ static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
}
if (tries >= count)
goto err;
+ if (hip04_cluster_is_down(cluster))
+ hip04_set_snoop_filter(cluster, 0);
spin_unlock_irq(&boot_lock);
- return 0;
+ return 1;
err:
spin_unlock_irq(&boot_lock);
- return ret;
-}
-
-static void hip04_mcpm_powered_up(void)
-{
- unsigned int mpidr, cpu, cluster;
-
- mpidr = read_cpuid_mpidr();
- cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
- cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
-
- spin_lock(&boot_lock);
- if (!hip04_cpu_table[cluster][cpu])
- hip04_cpu_table[cluster][cpu] = 1;
- spin_unlock(&boot_lock);
-}
-
-static void __naked hip04_mcpm_power_up_setup(unsigned int affinity_level)
-{
- asm volatile (" \n"
-" cmp r0, #0 \n"
-" bxeq lr \n"
- /* calculate fabric phys address */
-" adr r2, 2f \n"
-" ldmia r2, {r1, r3} \n"
-" sub r0, r2, r1 \n"
-" ldr r2, [r0, r3] \n"
- /* get cluster id from MPIDR */
-" mrc p15, 0, r0, c0, c0, 5 \n"
-" ubfx r1, r0, #8, #8 \n"
- /* 1 << cluster id */
-" mov r0, #1 \n"
-" mov r3, r0, lsl r1 \n"
-" ldr r0, [r2, #"__stringify(FAB_SF_MODE)"] \n"
-" tst r0, r3 \n"
-" bxne lr \n"
-" orr r1, r0, r3 \n"
-" str r1, [r2, #"__stringify(FAB_SF_MODE)"] \n"
-"1: ldr r0, [r2, #"__stringify(FAB_SF_MODE)"] \n"
-" tst r0, r3 \n"
-" beq 1b \n"
-" bx lr \n"
-
-" .align 2 \n"
-"2: .word . \n"
-" .word fabric_phys_addr \n"
- );
+ return 0;
}
-
-static const struct mcpm_platform_ops hip04_mcpm_ops = {
- .power_up = hip04_mcpm_power_up,
- .power_down = hip04_mcpm_power_down,
- .wait_for_powerdown = hip04_mcpm_wait_for_powerdown,
- .powered_up = hip04_mcpm_powered_up,
+#endif
+
+static struct smp_operations __initdata hip04_smp_ops = {
+ .smp_boot_secondary = hip04_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = hip04_cpu_die,
+ .cpu_kill = hip04_cpu_kill,
+#endif
};
static bool __init hip04_cpu_table_init(void)
@@ -298,7 +265,7 @@ static bool __init hip04_cpu_table_init(void)
return true;
}
-static int __init hip04_mcpm_init(void)
+static int __init hip04_smp_init(void)
{
struct device_node *np, *np_sctl, *np_fab;
struct resource fab_res;
@@ -353,10 +320,6 @@ static int __init hip04_mcpm_init(void)
ret = -EINVAL;
goto err_table;
}
- ret = mcpm_platform_register(&hip04_mcpm_ops);
- if (ret) {
- goto err_table;
- }
/*
* Fill the instruction address that is used after secondary core
@@ -364,13 +327,11 @@ static int __init hip04_mcpm_init(void)
*/
writel_relaxed(hip04_boot_method[0], relocation);
writel_relaxed(0xa5a5a5a5, relocation + 4); /* magic number */
- writel_relaxed(virt_to_phys(mcpm_entry_point), relocation + 8);
+ writel_relaxed(virt_to_phys(secondary_startup), relocation + 8);
writel_relaxed(0, relocation + 12);
iounmap(relocation);
- mcpm_sync_init(hip04_mcpm_power_up_setup);
- mcpm_smp_set_ops();
- pr_info("HiP04 MCPM initialized\n");
+ smp_set_ops(&hip04_smp_ops);
return ret;
err_table:
iounmap(fabric);
@@ -383,4 +344,4 @@ err_reloc:
err:
return ret;
}
-early_initcall(hip04_mcpm_init);
+early_initcall(hip04_smp_init);
diff --git a/arch/arm/mach-hisi/platsmp.c b/arch/arm/mach-hisi/platsmp.c
index 8880c8e8b296..51744127db66 100644
--- a/arch/arm/mach-hisi/platsmp.c
+++ b/arch/arm/mach-hisi/platsmp.c
@@ -118,7 +118,7 @@ static int hix5hd2_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
phys_addr_t jumpaddr;
- jumpaddr = virt_to_phys(hisi_secondary_startup);
+ jumpaddr = virt_to_phys(secondary_startup);
hix5hd2_set_scu_boot_addr(HIX5HD2_BOOT_ADDRESS, jumpaddr);
hix5hd2_set_cpu(cpu, true);
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
@@ -156,7 +156,7 @@ static int hip01_boot_secondary(unsigned int cpu, struct task_struct *idle)
struct device_node *node;
- jumpaddr = virt_to_phys(hisi_secondary_startup);
+ jumpaddr = virt_to_phys(secondary_startup);
hip01_set_boot_addr(HIP01_BOOT_ADDRESS, jumpaddr);
node = of_find_compatible_node(NULL, NULL, "hisilicon,hip01-sysctrl");
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 3a3d3e9d7bfd..573536f1bb73 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -1,8 +1,8 @@
menuconfig ARCH_MXC
- bool "Freescale i.MX family" if ARCH_MULTI_V4_V5 || ARCH_MULTI_V6_V7
+ bool "Freescale i.MX family" if ARCH_MULTI_V4_V5 || ARCH_MULTI_V6_V7 || ARM_SINGLE_ARMV7M
select ARCH_REQUIRE_GPIOLIB
select ARM_CPU_SUSPEND if PM
- select CLKSRC_MMIO
+ select CLKSRC_IMX_GPT
select GENERIC_IRQ_CHIP
select PINCTRL
select PM_OPP if PM
@@ -444,40 +444,6 @@ config MACH_MX35_3DS
Include support for MX35PDK platform. This includes specific
configurations for the board and its peripherals.
-config MACH_EUKREA_CPUIMX35SD
- bool "Support Eukrea CPUIMX35 Platform"
- select IMX_HAVE_PLATFORM_FLEXCAN
- select IMX_HAVE_PLATFORM_FSL_USB2_UDC
- select IMX_HAVE_PLATFORM_IMX2_WDT
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_MXC_EHCI
- select IMX_HAVE_PLATFORM_MXC_NAND
- select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
- select USB_ULPI_VIEWPORT if USB_ULPI
- select SOC_IMX35
- help
- Include support for Eukrea CPUIMX35 platform. This includes
- specific configurations for the board and its peripherals.
-
-choice
- prompt "Baseboard"
- depends on MACH_EUKREA_CPUIMX35SD
- default MACH_EUKREA_MBIMXSD35_BASEBOARD
-
-config MACH_EUKREA_MBIMXSD35_BASEBOARD
- bool "Eukrea MBIMXSD development board"
- select IMX_HAVE_PLATFORM_GPIO_KEYS
- select IMX_HAVE_PLATFORM_IMX_SSI
- select IMX_HAVE_PLATFORM_IPU_CORE
- select IMX_HAVE_PLATFORM_SPI_IMX
- select LEDS_GPIO_REGISTER
- help
- This adds board specific devices that can be found on Eukrea's
- MBIMXSD evaluation board.
-
-endchoice
-
config MACH_VPR200
bool "Support VPR200 platform"
select IMX_HAVE_PLATFORM_FSL_USB2_UDC
@@ -496,10 +462,10 @@ config MACH_VPR200
endif
-if ARCH_MULTI_V5
-
comment "Device tree only"
+if ARCH_MULTI_V5
+
config SOC_IMX25
bool "i.MX25 support"
select ARCH_MXC_IOMUX_V3
@@ -512,7 +478,7 @@ endif
if ARCH_MULTI_V7
-comment "Device tree only"
+comment "Cortex-A platforms"
config SOC_IMX5
bool
@@ -582,10 +548,33 @@ config SOC_IMX6SX
help
This enables support for Freescale i.MX6 SoloX processor.
+config SOC_IMX7D
+ bool "i.MX7 Dual support"
+ select PINCTRL_IMX7D
+ select ARM_GIC
+ select HAVE_IMX_ANATOP
+ select HAVE_IMX_MMDC
+ help
+ This enables support for Freescale i.MX7 Dual processor.
+
+config SOC_LS1021A
+ bool "Freescale LS1021A support"
+ select ARM_GIC
+ select HAVE_ARM_ARCH_TIMER
+ select PCI_DOMAINS if PCI
+ select ZONE_DMA if ARM_LPAE
+ help
+ This enables support for Freescale LS1021A processor.
+
+endif
+
+comment "Cortex-A/Cortex-M asymmetric multiprocessing platforms"
+
+if ARCH_MULTI_V7 || ARM_SINGLE_ARMV7M
+
config SOC_VF610
bool "Vybrid Family VF610 support"
- select IRQ_DOMAIN_HIERARCHY
- select ARM_GIC
+ select ARM_GIC if ARCH_MULTI_V7
select PINCTRL_VF610
select PL310_ERRATA_769419 if CACHE_L2X0
select SMP_ON_UP if SMP
@@ -599,7 +588,7 @@ choice
default VF_USE_ARM_GLOBAL_TIMER
config VF_USE_ARM_GLOBAL_TIMER
- bool "Use ARM Global Timer"
+ bool "Use ARM Global Timer" if ARCH_MULTI_V7
select ARM_GLOBAL_TIMER
select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
help
@@ -613,16 +602,6 @@ choice
endchoice
-config SOC_LS1021A
- bool "Freescale LS1021A support"
- select ARM_GIC
- select HAVE_ARM_ARCH_TIMER
- select PCI_DOMAINS if PCI
- select ZONE_DMA if ARM_LPAE
-
- help
- This enables support for Freescale LS1021A processor.
-
endif
source "arch/arm/mach-imx/devices/Kconfig"
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 3244cf1d2773..37c502ac9595 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -1,23 +1,18 @@
-obj-y := time.o cpu.o system.o irq-common.o
+obj-y := cpu.o system.o irq-common.o
-obj-$(CONFIG_SOC_IMX1) += clk-imx1.o mm-imx1.o
-obj-$(CONFIG_SOC_IMX21) += clk-imx21.o mm-imx21.o
+obj-$(CONFIG_SOC_IMX1) += mm-imx1.o
+obj-$(CONFIG_SOC_IMX21) += mm-imx21.o
-obj-$(CONFIG_SOC_IMX25) += clk-imx25.o cpu-imx25.o mach-imx25.o
+obj-$(CONFIG_SOC_IMX25) += cpu-imx25.o mach-imx25.o
obj-$(CONFIG_SOC_IMX27) += cpu-imx27.o pm-imx27.o
-obj-$(CONFIG_SOC_IMX27) += clk-imx27.o mm-imx27.o ehci-imx27.o
+obj-$(CONFIG_SOC_IMX27) += mm-imx27.o ehci-imx27.o
-obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clk-imx31.o iomux-imx31.o ehci-imx31.o pm-imx3.o
-obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o
+obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o iomux-imx31.o ehci-imx31.o pm-imx3.o
+obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o ehci-imx35.o pm-imx3.o
imx5-pm-$(CONFIG_PM) += pm-imx5.o
-obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o clk-cpu.o $(imx5-pm-y)
-
-obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \
- clk-pfd.o clk-busy.o clk.o \
- clk-fixup-div.o clk-fixup-mux.o \
- clk-gate-exclusive.o
+obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o $(imx5-pm-y)
obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
@@ -73,8 +68,6 @@ obj-$(CONFIG_MACH_IMX31_DT) += imx31-dt.o
# i.MX35 based machines
obj-$(CONFIG_MACH_PCM043) += mach-pcm043.o
obj-$(CONFIG_MACH_MX35_3DS) += mach-mx35_3ds.o
-obj-$(CONFIG_MACH_EUKREA_CPUIMX35SD) += mach-cpuimx35.o
-obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o
obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o
obj-$(CONFIG_MACH_IMX35_DT) += imx35-dt.o
@@ -87,13 +80,15 @@ AFLAGS_headsmp.o :=-Wa,-march=armv7-a
obj-$(CONFIG_SMP) += headsmp.o platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
endif
-obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o
-obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o
-obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o mach-imx6sx.o
+obj-$(CONFIG_SOC_IMX6Q) += mach-imx6q.o
+obj-$(CONFIG_SOC_IMX6SL) += mach-imx6sl.o
+obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o
+obj-$(CONFIG_SOC_IMX7D) += mach-imx7d.o
ifeq ($(CONFIG_SUSPEND),y)
AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a
obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o
+obj-$(CONFIG_SOC_IMX53) += suspend-imx53.o
endif
obj-$(CONFIG_SOC_IMX6) += pm-imx6.o
@@ -101,7 +96,7 @@ obj-$(CONFIG_SOC_IMX50) += mach-imx50.o
obj-$(CONFIG_SOC_IMX51) += mach-imx51.o
obj-$(CONFIG_SOC_IMX53) += mach-imx53.o
-obj-$(CONFIG_SOC_VF610) += clk-vf610.o mach-vf610.o
+obj-$(CONFIG_SOC_VF610) += mach-vf610.o
obj-$(CONFIG_SOC_LS1021A) += mach-ls1021a.o
diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/arch/arm/mach-imx/Makefile.boot
diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c
index 7f262fe4ba77..231bb250c571 100644
--- a/arch/arm/mach-imx/anatop.c
+++ b/arch/arm/mach-imx/anatop.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -28,6 +28,7 @@
#define ANADIG_USB2_CHRG_DETECT 0x210
#define ANADIG_DIGPROG 0x260
#define ANADIG_DIGPROG_IMX6SL 0x280
+#define ANADIG_DIGPROG_IMX7D 0x800
#define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000
#define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN 0x8
@@ -121,6 +122,8 @@ void __init imx_init_revision_from_anatop(void)
WARN_ON(!anatop_base);
if (of_device_is_compatible(np, "fsl,imx6sl-anatop"))
offset = ANADIG_DIGPROG_IMX6SL;
+ if (of_device_is_compatible(np, "fsl,imx7d-anatop"))
+ offset = ANADIG_DIGPROG_IMX7D;
digprog = readl_relaxed(anatop_base + offset);
iounmap(anatop_base);
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 0f04e30b726d..21e4e8697a58 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -44,7 +44,6 @@ void imx27_soc_init(void);
void imx31_soc_init(void);
void imx35_soc_init(void);
void epit_timer_init(void __iomem *base, int irq);
-void mxc_timer_init(void __iomem *, int);
int mx1_clocks_init(unsigned long fref);
int mx21_clocks_init(unsigned long lref, unsigned long fref);
int mx27_clocks_init(unsigned long fref);
@@ -56,13 +55,10 @@ struct platform_device *mxc_register_gpio(char *name, int id,
void mxc_set_cpu_type(unsigned int type);
void mxc_restart(enum reboot_mode, const char *);
void mxc_arch_reset_init(void __iomem *);
-int mx51_revision(void);
-int mx53_revision(void);
void imx_set_aips(void __iomem *);
void imx_aips_allow_unprivileged_access(const char *compat);
int mxc_device_init(void);
void imx_set_soc_revision(unsigned int rev);
-unsigned int imx_get_soc_revision(void);
void imx_init_revision_from_anatop(void);
struct device *imx_soc_device_init(void);
void imx6_enable_rbc(bool enable);
@@ -87,7 +83,6 @@ enum mx3_cpu_pwr_mode {
};
void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode);
-void imx_print_silicon_rev(const char *cpu, int srev);
void imx_enable_cpu(int cpu, bool enable);
void imx_set_cpu_jump(int cpu, void *jump_addr);
@@ -111,7 +106,7 @@ void imx_gpc_hwirq_unmask(unsigned int hwirq);
void imx_anatop_init(void);
void imx_anatop_pre_suspend(void);
void imx_anatop_post_resume(void);
-int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
+int imx6_set_lpm(enum mxc_cpu_pwr_mode mode);
void imx6q_set_int_mem_clk_lpm(bool enable);
void imx6sl_set_wait_clk(bool enter);
int imx_mmdc_get_ddr_type(void);
@@ -121,26 +116,28 @@ int imx_cpu_kill(unsigned int cpu);
#ifdef CONFIG_SUSPEND
void v7_cpu_resume(void);
+void imx53_suspend(void __iomem *ocram_vbase);
+extern const u32 imx53_suspend_sz;
void imx6_suspend(void __iomem *ocram_vbase);
#else
static inline void v7_cpu_resume(void) {}
+static inline void imx53_suspend(void __iomem *ocram_vbase) {}
+static const u32 imx53_suspend_sz;
static inline void imx6_suspend(void __iomem *ocram_vbase) {}
#endif
+void imx6_pm_ccm_init(const char *ccm_compat);
void imx6q_pm_init(void);
void imx6dl_pm_init(void);
void imx6sl_pm_init(void);
void imx6sx_pm_init(void);
-void imx6q_pm_set_ccm_base(void __iomem *base);
#ifdef CONFIG_PM
void imx51_pm_init(void);
void imx53_pm_init(void);
-void imx5_pm_set_ccm_base(void __iomem *base);
#else
static inline void imx51_pm_init(void) {}
static inline void imx53_pm_init(void) {}
-static inline void imx5_pm_set_ccm_base(void __iomem *base) {}
#endif
#ifdef CONFIG_NEON
diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c
index df42c14ff749..a7fa92a7b1d7 100644
--- a/arch/arm/mach-imx/cpu.c
+++ b/arch/arm/mach-imx/cpu.c
@@ -130,6 +130,9 @@ struct device * __init imx_soc_device_init(void)
case MXC_CPU_IMX6Q:
soc_id = "i.MX6Q";
break;
+ case MXC_CPU_IMX7D:
+ soc_id = "i.MX7D";
+ break;
default:
soc_id = "Unknown";
}
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
index 8e21ccc1eda2..353bb8774112 100644
--- a/arch/arm/mach-imx/cpuidle-imx6q.c
+++ b/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -27,9 +27,9 @@ static int imx6q_enter_wait(struct cpuidle_device *dev,
*/
if (!spin_trylock(&master_lock))
goto idle;
- imx6q_set_lpm(WAIT_UNCLOCKED);
+ imx6_set_lpm(WAIT_UNCLOCKED);
cpu_do_idle();
- imx6q_set_lpm(WAIT_CLOCKED);
+ imx6_set_lpm(WAIT_CLOCKED);
spin_unlock(&master_lock);
goto done;
}
diff --git a/arch/arm/mach-imx/cpuidle-imx6sl.c b/arch/arm/mach-imx/cpuidle-imx6sl.c
index 5742a9fd1ef2..8d866fb674a8 100644
--- a/arch/arm/mach-imx/cpuidle-imx6sl.c
+++ b/arch/arm/mach-imx/cpuidle-imx6sl.c
@@ -16,7 +16,7 @@
static int imx6sl_enter_wait(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
- imx6q_set_lpm(WAIT_UNCLOCKED);
+ imx6_set_lpm(WAIT_UNCLOCKED);
/*
* Software workaround for ERR005311, see function
* description for details.
@@ -24,7 +24,7 @@ static int imx6sl_enter_wait(struct cpuidle_device *dev,
imx6sl_set_wait_clk(true);
cpu_do_idle();
imx6sl_set_wait_clk(false);
- imx6q_set_lpm(WAIT_CLOCKED);
+ imx6_set_lpm(WAIT_CLOCKED);
return index;
}
diff --git a/arch/arm/mach-imx/cpuidle-imx6sx.c b/arch/arm/mach-imx/cpuidle-imx6sx.c
index 2c9f1a8bf245..3c6672b3796b 100644
--- a/arch/arm/mach-imx/cpuidle-imx6sx.c
+++ b/arch/arm/mach-imx/cpuidle-imx6sx.c
@@ -25,7 +25,7 @@ static int imx6sx_idle_finish(unsigned long val)
static int imx6sx_enter_wait(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
- imx6q_set_lpm(WAIT_UNCLOCKED);
+ imx6_set_lpm(WAIT_UNCLOCKED);
switch (index) {
case 1:
@@ -50,7 +50,7 @@ static int imx6sx_enter_wait(struct cpuidle_device *dev,
break;
}
- imx6q_set_lpm(WAIT_CLOCKED);
+ imx6_set_lpm(WAIT_CLOCKED);
return index;
}
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
deleted file mode 100644
index 6edc940e0865..000000000000
--- a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright (C) 2010 Eric Benard - eric@eukrea.com
- *
- * Based on pcm970-baseboard.c which is :
- * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/leds.h>
-#include <linux/platform_device.h>
-#include <linux/input.h>
-#include <linux/spi/spi.h>
-#include <video/platform_lcd.h>
-#include <linux/i2c.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-#include <asm/mach/map.h>
-
-#include "common.h"
-#include "devices-imx35.h"
-#include "hardware.h"
-#include "iomux-mx35.h"
-
-static const struct fb_videomode fb_modedb[] = {
- {
- .name = "CMO-QVGA",
- .refresh = 60,
- .xres = 320,
- .yres = 240,
- .pixclock = KHZ2PICOS(6500),
- .left_margin = 68,
- .right_margin = 20,
- .upper_margin = 15,
- .lower_margin = 4,
- .hsync_len = 30,
- .vsync_len = 3,
- .sync = 0,
- .vmode = FB_VMODE_NONINTERLACED,
- .flag = 0,
- },
- {
- .name = "DVI-VGA",
- .refresh = 60,
- .xres = 640,
- .yres = 480,
- .pixclock = 32000,
- .left_margin = 100,
- .right_margin = 100,
- .upper_margin = 7,
- .lower_margin = 100,
- .hsync_len = 7,
- .vsync_len = 7,
- .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT |
- FB_SYNC_OE_ACT_HIGH | FB_SYNC_CLK_INVERT,
- .vmode = FB_VMODE_NONINTERLACED,
- .flag = 0,
- },
- {
- .name = "DVI-SVGA",
- .refresh = 60,
- .xres = 800,
- .yres = 600,
- .pixclock = 25000,
- .left_margin = 75,
- .right_margin = 75,
- .upper_margin = 7,
- .lower_margin = 75,
- .hsync_len = 7,
- .vsync_len = 7,
- .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT |
- FB_SYNC_OE_ACT_HIGH | FB_SYNC_CLK_INVERT,
- .vmode = FB_VMODE_NONINTERLACED,
- .flag = 0,
- },
-};
-
-static struct mx3fb_platform_data mx3fb_pdata __initdata = {
- .name = "CMO-QVGA",
- .mode = fb_modedb,
- .num_modes = ARRAY_SIZE(fb_modedb),
-};
-
-static const iomux_v3_cfg_t eukrea_mbimxsd_pads[] __initconst = {
- /* LCD */
- MX35_PAD_LD0__IPU_DISPB_DAT_0,
- MX35_PAD_LD1__IPU_DISPB_DAT_1,
- MX35_PAD_LD2__IPU_DISPB_DAT_2,
- MX35_PAD_LD3__IPU_DISPB_DAT_3,
- MX35_PAD_LD4__IPU_DISPB_DAT_4,
- MX35_PAD_LD5__IPU_DISPB_DAT_5,
- MX35_PAD_LD6__IPU_DISPB_DAT_6,
- MX35_PAD_LD7__IPU_DISPB_DAT_7,
- MX35_PAD_LD8__IPU_DISPB_DAT_8,
- MX35_PAD_LD9__IPU_DISPB_DAT_9,
- MX35_PAD_LD10__IPU_DISPB_DAT_10,
- MX35_PAD_LD11__IPU_DISPB_DAT_11,
- MX35_PAD_LD12__IPU_DISPB_DAT_12,
- MX35_PAD_LD13__IPU_DISPB_DAT_13,
- MX35_PAD_LD14__IPU_DISPB_DAT_14,
- MX35_PAD_LD15__IPU_DISPB_DAT_15,
- MX35_PAD_LD16__IPU_DISPB_DAT_16,
- MX35_PAD_LD17__IPU_DISPB_DAT_17,
- MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC,
- MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK,
- MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY,
- MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC,
- /* Backlight */
- MX35_PAD_CONTRAST__IPU_DISPB_CONTR,
- /* LCD_PWR */
- MX35_PAD_D3_CLS__GPIO1_4,
- /* LED */
- MX35_PAD_LD23__GPIO3_29,
- /* SWITCH */
- MX35_PAD_LD19__GPIO3_25,
- /* UART2 */
- MX35_PAD_CTS2__UART2_CTS,
- MX35_PAD_RTS2__UART2_RTS,
- MX35_PAD_TXD2__UART2_TXD_MUX,
- MX35_PAD_RXD2__UART2_RXD_MUX,
- /* I2S */
- MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS,
- MX35_PAD_STXD4__AUDMUX_AUD4_TXD,
- MX35_PAD_SRXD4__AUDMUX_AUD4_RXD,
- MX35_PAD_SCK4__AUDMUX_AUD4_TXC,
- /* CAN2 */
- MX35_PAD_TX5_RX0__CAN2_TXCAN,
- MX35_PAD_TX4_RX1__CAN2_RXCAN,
- /* SDCARD */
- MX35_PAD_SD1_CMD__ESDHC1_CMD,
- MX35_PAD_SD1_CLK__ESDHC1_CLK,
- MX35_PAD_SD1_DATA0__ESDHC1_DAT0,
- MX35_PAD_SD1_DATA1__ESDHC1_DAT1,
- MX35_PAD_SD1_DATA2__ESDHC1_DAT2,
- MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
- /* SD1 CD */
- MX35_PAD_LD18__GPIO3_24,
- /* SPI */
- MX35_PAD_CSPI1_MOSI__CSPI1_MOSI,
- MX35_PAD_CSPI1_MISO__CSPI1_MISO,
- MX35_PAD_CSPI1_SS0__GPIO1_18,
- MX35_PAD_CSPI1_SS1__GPIO1_19,
- MX35_PAD_CSPI1_SCLK__CSPI1_SCLK,
- MX35_PAD_CSPI1_SPI_RDY__GPIO3_5,
-};
-
-#define GPIO_LED1 IMX_GPIO_NR(3, 29)
-#define GPIO_SWITCH1 IMX_GPIO_NR(3, 25)
-#define GPIO_LCDPWR IMX_GPIO_NR(1, 4)
-#define GPIO_SD1CD IMX_GPIO_NR(3, 24)
-#define GPIO_SPI1_SS0 IMX_GPIO_NR(1, 18)
-#define GPIO_SPI1_SS1 IMX_GPIO_NR(1, 19)
-#define GPIO_SPI1_IRQ IMX_GPIO_NR(3, 5)
-
-static void eukrea_mbimxsd_lcd_power_set(struct plat_lcd_data *pd,
- unsigned int power)
-{
- if (power)
- gpio_direction_output(GPIO_LCDPWR, 1);
- else
- gpio_direction_output(GPIO_LCDPWR, 0);
-}
-
-static struct plat_lcd_data eukrea_mbimxsd_lcd_power_data = {
- .set_power = eukrea_mbimxsd_lcd_power_set,
-};
-
-static struct platform_device eukrea_mbimxsd_lcd_powerdev = {
- .name = "platform-lcd",
- .dev.platform_data = &eukrea_mbimxsd_lcd_power_data,
-};
-
-static struct gpio_led eukrea_mbimxsd_leds[] = {
- {
- .name = "led1",
- .default_trigger = "heartbeat",
- .active_low = 1,
- .gpio = GPIO_LED1,
- },
-};
-
-static const struct gpio_led_platform_data
- eukrea_mbimxsd_led_info __initconst = {
- .leds = eukrea_mbimxsd_leds,
- .num_leds = ARRAY_SIZE(eukrea_mbimxsd_leds),
-};
-
-static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = {
- {
- .gpio = GPIO_SWITCH1,
- .code = BTN_0,
- .desc = "BP1",
- .active_low = 1,
- .wakeup = 1,
- },
-};
-
-static const struct gpio_keys_platform_data
- eukrea_mbimxsd_button_data __initconst = {
- .buttons = eukrea_mbimxsd_gpio_buttons,
- .nbuttons = ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons),
-};
-
-static struct platform_device *platform_devices[] __initdata = {
- &eukrea_mbimxsd_lcd_powerdev,
-};
-
-static const struct imxuart_platform_data uart_pdata __initconst = {
- .flags = IMXUART_HAVE_RTSCTS,
-};
-
-static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = {
- {
- I2C_BOARD_INFO("tlv320aic23", 0x1a),
- },
-};
-
-static const
-struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata __initconst = {
- .flags = IMX_SSI_SYN | IMX_SSI_NET | IMX_SSI_USE_I2S_SLAVE,
-};
-
-static struct esdhc_platform_data sd1_pdata = {
- .cd_gpio = GPIO_SD1CD,
- .cd_type = ESDHC_CD_GPIO,
- .wp_type = ESDHC_WP_NONE,
-};
-
-static struct spi_board_info eukrea_mbimxsd35_spi_board_info[] __initdata = {
- {
- .modalias = "spidev",
- .max_speed_hz = 20000000,
- .bus_num = 0,
- .chip_select = 0,
- .mode = SPI_MODE_0,
- },
- {
- .modalias = "spidev",
- .max_speed_hz = 20000000,
- .bus_num = 0,
- .chip_select = 1,
- .mode = SPI_MODE_0,
- },
-};
-
-static int eukrea_mbimxsd35_spi_cs[] = {GPIO_SPI1_SS0, GPIO_SPI1_SS1};
-
-static const struct spi_imx_master eukrea_mbimxsd35_spi0_data __initconst = {
- .chipselect = eukrea_mbimxsd35_spi_cs,
- .num_chipselect = ARRAY_SIZE(eukrea_mbimxsd35_spi_cs),
-};
-
-/*
- * system init for baseboard usage. Will be called by cpuimx35 init.
- *
- * Add platform devices present on this baseboard and init
- * them from CPU side as far as required to use them later on
- */
-void __init eukrea_mbimxsd35_baseboard_init(void)
-{
- if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd_pads,
- ARRAY_SIZE(eukrea_mbimxsd_pads)))
- printk(KERN_ERR "error setting mbimxsd pads !\n");
-
- imx35_add_imx_uart1(&uart_pdata);
- imx35_add_ipu_core();
- imx35_add_mx3_sdc_fb(&mx3fb_pdata);
-
- imx35_add_imx_ssi(0, &eukrea_mbimxsd_ssi_pdata);
-
- imx35_add_flexcan1();
- imx35_add_sdhci_esdhc_imx(0, &sd1_pdata);
-
- gpio_request(GPIO_LED1, "LED1");
- gpio_direction_output(GPIO_LED1, 1);
- gpio_free(GPIO_LED1);
-
- gpio_request(GPIO_SWITCH1, "SWITCH1");
- gpio_direction_input(GPIO_SWITCH1);
- gpio_free(GPIO_SWITCH1);
-
- gpio_request(GPIO_LCDPWR, "LCDPWR");
- gpio_direction_output(GPIO_LCDPWR, 1);
-
- i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
- ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
-
- gpio_request(GPIO_SPI1_IRQ, "SPI1_IRQ");
- gpio_direction_input(GPIO_SPI1_IRQ);
- gpio_free(GPIO_SPI1_IRQ);
- imx35_add_spi_imx0(&eukrea_mbimxsd35_spi0_data);
- spi_register_board_info(eukrea_mbimxsd35_spi_board_info,
- ARRAY_SIZE(eukrea_mbimxsd35_spi_board_info));
-
- platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
- gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
- imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
- imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
-}
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 6d0893a3828e..80bad29d609a 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -227,7 +227,7 @@ static int imx_gpc_domain_alloc(struct irq_domain *domain,
return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, &parent_args);
}
-static struct irq_domain_ops imx_gpc_domain_ops = {
+static const struct irq_domain_ops imx_gpc_domain_ops = {
.xlate = imx_gpc_domain_xlate,
.alloc = imx_gpc_domain_alloc,
.free = irq_domain_free_irqs_common,
@@ -474,7 +474,6 @@ static const struct of_device_id imx_gpc_dt_ids[] = {
static struct platform_driver imx_gpc_driver = {
.driver = {
.name = "imx-gpc",
- .owner = THIS_MODULE,
.of_match_table = imx_gpc_dt_ids,
},
.probe = imx_gpc_probe,
diff --git a/arch/arm/mach-imx/hardware.h b/arch/arm/mach-imx/hardware.h
index 76af2c03c241..d737f95ebb07 100644
--- a/arch/arm/mach-imx/hardware.h
+++ b/arch/arm/mach-imx/hardware.h
@@ -22,6 +22,7 @@
#ifndef __ASSEMBLY__
#include <asm/io.h>
+#include <soc/imx/revision.h>
#endif
#include <asm/sizes.h>
diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S
index de5047c8a6c8..b5e976816b63 100644
--- a/arch/arm/mach-imx/headsmp.S
+++ b/arch/arm/mach-imx/headsmp.S
@@ -25,7 +25,6 @@ diag_reg_offset:
.endm
ENTRY(v7_secondary_startup)
- bl v7_invalidate_l1
set_diag_reg
b secondary_startup
ENDPROC(v7_secondary_startup)
diff --git a/arch/arm/mach-imx/iomux-imx31.c b/arch/arm/mach-imx/iomux-imx31.c
index d6a30753ca7c..6dd22cabf4d3 100644
--- a/arch/arm/mach-imx/iomux-imx31.c
+++ b/arch/arm/mach-imx/iomux-imx31.c
@@ -40,7 +40,7 @@ static DEFINE_SPINLOCK(gpio_mux_lock);
#define IOMUX_REG_MASK (IOMUX_PADNUM_MASK & ~0x3)
-static unsigned long mxc_pin_alloc_map[NB_PORTS * 32 / BITS_PER_LONG];
+static DECLARE_BITMAP(mxc_pin_alloc_map, NB_PORTS * 32);
/*
* set the mode for a IOMUX pin.
*/
diff --git a/arch/arm/mach-imx/mach-cpuimx35.c b/arch/arm/mach-imx/mach-cpuimx35.c
deleted file mode 100644
index 922ffd6ca039..000000000000
--- a/arch/arm/mach-imx/mach-cpuimx35.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2010 Eric Benard - eric@eukrea.com
- * Copyright (C) 2009 Sascha Hauer, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/memory.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/i2c/tsc2007.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/ulpi.h>
-#include <linux/i2c-gpio.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-#include <asm/mach/map.h>
-
-#include "common.h"
-#include "devices-imx35.h"
-#include "ehci.h"
-#include "eukrea-baseboards.h"
-#include "hardware.h"
-#include "iomux-mx35.h"
-
-static const struct imxuart_platform_data uart_pdata __initconst = {
- .flags = IMXUART_HAVE_RTSCTS,
-};
-
-static const struct imxi2c_platform_data
- eukrea_cpuimx35_i2c0_data __initconst = {
- .bitrate = 100000,
-};
-
-#define TSC2007_IRQGPIO IMX_GPIO_NR(3, 2)
-static int tsc2007_get_pendown_state(struct device *dev)
-{
- return !gpio_get_value(TSC2007_IRQGPIO);
-}
-
-static struct tsc2007_platform_data tsc2007_info = {
- .model = 2007,
- .x_plate_ohms = 180,
- .get_pendown_state = tsc2007_get_pendown_state,
-};
-
-static struct i2c_board_info eukrea_cpuimx35_i2c_devices[] = {
- {
- I2C_BOARD_INFO("pcf8563", 0x51),
- }, {
- I2C_BOARD_INFO("tsc2007", 0x48),
- .platform_data = &tsc2007_info,
- /* irq number is run-time assigned */
- },
-};
-
-static const iomux_v3_cfg_t eukrea_cpuimx35_pads[] __initconst = {
- /* UART1 */
- MX35_PAD_CTS1__UART1_CTS,
- MX35_PAD_RTS1__UART1_RTS,
- MX35_PAD_TXD1__UART1_TXD_MUX,
- MX35_PAD_RXD1__UART1_RXD_MUX,
- /* FEC */
- MX35_PAD_FEC_TX_CLK__FEC_TX_CLK,
- MX35_PAD_FEC_RX_CLK__FEC_RX_CLK,
- MX35_PAD_FEC_RX_DV__FEC_RX_DV,
- MX35_PAD_FEC_COL__FEC_COL,
- MX35_PAD_FEC_RDATA0__FEC_RDATA_0,
- MX35_PAD_FEC_TDATA0__FEC_TDATA_0,
- MX35_PAD_FEC_TX_EN__FEC_TX_EN,
- MX35_PAD_FEC_MDC__FEC_MDC,
- MX35_PAD_FEC_MDIO__FEC_MDIO,
- MX35_PAD_FEC_TX_ERR__FEC_TX_ERR,
- MX35_PAD_FEC_RX_ERR__FEC_RX_ERR,
- MX35_PAD_FEC_CRS__FEC_CRS,
- MX35_PAD_FEC_RDATA1__FEC_RDATA_1,
- MX35_PAD_FEC_TDATA1__FEC_TDATA_1,
- MX35_PAD_FEC_RDATA2__FEC_RDATA_2,
- MX35_PAD_FEC_TDATA2__FEC_TDATA_2,
- MX35_PAD_FEC_RDATA3__FEC_RDATA_3,
- MX35_PAD_FEC_TDATA3__FEC_TDATA_3,
- /* I2C1 */
- MX35_PAD_I2C1_CLK__I2C1_SCL,
- MX35_PAD_I2C1_DAT__I2C1_SDA,
- /* TSC2007 IRQ */
- MX35_PAD_ATA_DA2__GPIO3_2,
-};
-
-static const struct mxc_nand_platform_data
- eukrea_cpuimx35_nand_board_info __initconst = {
- .width = 1,
- .hw_ecc = 1,
- .flash_bbt = 1,
-};
-
-static int eukrea_cpuimx35_otg_init(struct platform_device *pdev)
-{
- return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
-}
-
-static const struct mxc_usbh_platform_data otg_pdata __initconst = {
- .init = eukrea_cpuimx35_otg_init,
- .portsc = MXC_EHCI_MODE_UTMI,
-};
-
-static int eukrea_cpuimx35_usbh1_init(struct platform_device *pdev)
-{
- return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_SINGLE_UNI |
- MXC_EHCI_INTERNAL_PHY | MXC_EHCI_IPPUE_DOWN);
-}
-
-static const struct mxc_usbh_platform_data usbh1_pdata __initconst = {
- .init = eukrea_cpuimx35_usbh1_init,
- .portsc = MXC_EHCI_MODE_SERIAL,
-};
-
-static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
- .operating_mode = FSL_USB2_DR_DEVICE,
- .phy_mode = FSL_USB2_PHY_UTMI,
- .workaround = FLS_USB2_WORKAROUND_ENGCM09152,
-};
-
-static bool otg_mode_host __initdata;
-
-static int __init eukrea_cpuimx35_otg_mode(char *options)
-{
- if (!strcmp(options, "host"))
- otg_mode_host = true;
- else if (!strcmp(options, "device"))
- otg_mode_host = false;
- else
- pr_info("otg_mode neither \"host\" nor \"device\". "
- "Defaulting to device\n");
- return 1;
-}
-__setup("otg_mode=", eukrea_cpuimx35_otg_mode);
-
-/*
- * Board specific initialization.
- */
-static void __init eukrea_cpuimx35_init(void)
-{
- imx35_soc_init();
-
- mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx35_pads,
- ARRAY_SIZE(eukrea_cpuimx35_pads));
-
- imx35_add_fec(NULL);
- imx35_add_imx2_wdt();
-
- imx35_add_imx_uart0(&uart_pdata);
- imx35_add_mxc_nand(&eukrea_cpuimx35_nand_board_info);
-
- eukrea_cpuimx35_i2c_devices[1].irq = gpio_to_irq(TSC2007_IRQGPIO);
- i2c_register_board_info(0, eukrea_cpuimx35_i2c_devices,
- ARRAY_SIZE(eukrea_cpuimx35_i2c_devices));
- imx35_add_imx_i2c0(&eukrea_cpuimx35_i2c0_data);
-
- if (otg_mode_host)
- imx35_add_mxc_ehci_otg(&otg_pdata);
- else
- imx35_add_fsl_usb2_udc(&otg_device_pdata);
-
- imx35_add_mxc_ehci_hs(&usbh1_pdata);
-
-#ifdef CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD
- eukrea_mbimxsd35_baseboard_init();
-#endif
-}
-
-static void __init eukrea_cpuimx35_timer_init(void)
-{
- mx35_clocks_init();
-}
-
-MACHINE_START(EUKREA_CPUIMX35SD, "Eukrea CPUIMX35")
- /* Maintainer: Eukrea Electromatique */
- .atag_offset = 0x100,
- .map_io = mx35_map_io,
- .init_early = imx35_init_early,
- .init_irq = mx35_init_irq,
- .init_time = eukrea_cpuimx35_timer_init,
- .init_machine = eukrea_cpuimx35_init,
- .restart = mxc_restart,
-MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 3ab61549ce0f..9602cc12d2f1 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -393,6 +393,7 @@ static void __init imx6q_init_irq(void)
imx_init_l2cache();
imx_src_init();
irqchip_init();
+ imx6_pm_ccm_init("fsl,imx6q-ccm");
}
static const char * const imx6q_dt_compat[] __initconst = {
diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c
index 12a1b098fc6a..300326373166 100644
--- a/arch/arm/mach-imx/mach-imx6sl.c
+++ b/arch/arm/mach-imx/mach-imx6sl.c
@@ -66,6 +66,7 @@ static void __init imx6sl_init_irq(void)
imx_init_l2cache();
imx_src_init();
irqchip_init();
+ imx6_pm_ccm_init("fsl,imx6sl-ccm");
}
static const char * const imx6sl_dt_compat[] __initconst = {
diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c
index f17b7004c24b..6a0b0614de29 100644
--- a/arch/arm/mach-imx/mach-imx6sx.c
+++ b/arch/arm/mach-imx/mach-imx6sx.c
@@ -86,6 +86,7 @@ static void __init imx6sx_init_irq(void)
imx_init_l2cache();
imx_src_init();
irqchip_init();
+ imx6_pm_ccm_init("fsl,imx6sx-ccm");
}
static void __init imx6sx_init_late(void)
diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c
new file mode 100644
index 000000000000..4d4a19099a43
--- /dev/null
+++ b/arch/arm/mach-imx/mach-imx7d.c
@@ -0,0 +1,43 @@
+/*
+ * 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/irqchip.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include "common.h"
+
+static void __init imx7d_init_machine(void)
+{
+ struct device *parent;
+
+ parent = imx_soc_device_init();
+ if (parent == NULL)
+ pr_warn("failed to initialize soc device\n");
+
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ imx_anatop_init();
+}
+
+static void __init imx7d_init_irq(void)
+{
+ imx_init_revision_from_anatop();
+ imx_src_init();
+ irqchip_init();
+}
+
+static const char *imx7d_dt_compat[] __initconst = {
+ "fsl,imx7d",
+ NULL,
+};
+
+DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)")
+ .init_irq = imx7d_init_irq,
+ .init_machine = imx7d_init_machine,
+ .dt_compat = imx7d_dt_compat,
+MACHINE_END
diff --git a/arch/arm/mach-imx/mach-vf610.c b/arch/arm/mach-imx/mach-vf610.c
index 2e7c75b66fe0..b20f6c14eda5 100644
--- a/arch/arm/mach-imx/mach-vf610.c
+++ b/arch/arm/mach-imx/mach-vf610.c
@@ -17,6 +17,7 @@ static const char * const vf610_dt_compat[] __initconst = {
"fsl,vf510",
"fsl,vf600",
"fsl,vf610",
+ "fsl,vf610m4",
NULL,
};
diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c
index 0411f0664c15..db9621c718ec 100644
--- a/arch/arm/mach-imx/mmdc.c
+++ b/arch/arm/mach-imx/mmdc.c
@@ -17,6 +17,8 @@
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include "common.h"
+
#define MMDC_MAPSR 0x404
#define BP_MMDC_MAPSR_PSD 0
#define BP_MMDC_MAPSR_PSS 4
diff --git a/arch/arm/mach-imx/mx27.h b/arch/arm/mach-imx/mx27.h
index 8a65f192e7f3..f96bb2642677 100644
--- a/arch/arm/mach-imx/mx27.h
+++ b/arch/arm/mach-imx/mx27.h
@@ -231,8 +231,4 @@
#define MX27_DMA_REQ_SDHC3 36
#define MX27_DMA_REQ_NFC 37
-#ifndef __ASSEMBLY__
-extern int mx27_revision(void);
-#endif
-
#endif /* ifndef __MACH_MX27_H__ */
diff --git a/arch/arm/mach-imx/mx3x.h b/arch/arm/mach-imx/mx3x.h
index 96fb4fbc8ad7..6fec6114c2f1 100644
--- a/arch/arm/mach-imx/mx3x.h
+++ b/arch/arm/mach-imx/mx3x.h
@@ -185,11 +185,4 @@
#define MX3x_PROD_SIGNATURE 0x1 /* For MX31 */
-/* Mandatory defines used globally */
-
-#if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS)
-extern int mx35_revision(void);
-extern int mx31_revision(void);
-#endif
-
#endif /* ifndef __MACH_MX3x_H__ */
diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h
index 4c1343df2ba4..c4436d4fd6fd 100644
--- a/arch/arm/mach-imx/mxc.h
+++ b/arch/arm/mach-imx/mxc.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2007, 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2007, 2010-2015 Freescale Semiconductor, Inc.
* Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
*
* This program is free software; you can redistribute it and/or
@@ -38,22 +38,7 @@
#define MXC_CPU_IMX6DL 0x61
#define MXC_CPU_IMX6SX 0x62
#define MXC_CPU_IMX6Q 0x63
-
-#define IMX_CHIP_REVISION_1_0 0x10
-#define IMX_CHIP_REVISION_1_1 0x11
-#define IMX_CHIP_REVISION_1_2 0x12
-#define IMX_CHIP_REVISION_1_3 0x13
-#define IMX_CHIP_REVISION_1_4 0x14
-#define IMX_CHIP_REVISION_1_5 0x15
-#define IMX_CHIP_REVISION_2_0 0x20
-#define IMX_CHIP_REVISION_2_1 0x21
-#define IMX_CHIP_REVISION_2_2 0x22
-#define IMX_CHIP_REVISION_2_3 0x23
-#define IMX_CHIP_REVISION_3_0 0x30
-#define IMX_CHIP_REVISION_3_1 0x31
-#define IMX_CHIP_REVISION_3_2 0x32
-#define IMX_CHIP_REVISION_3_3 0x33
-#define IMX_CHIP_REVISION_UNKNOWN 0xff
+#define MXC_CPU_IMX7D 0x72
#define IMX_DDR_TYPE_LPDDR2 1
@@ -185,6 +170,11 @@ static inline bool cpu_is_imx6q(void)
return __mxc_cpu_type == MXC_CPU_IMX6Q;
}
+static inline bool cpu_is_imx7d(void)
+{
+ return __mxc_cpu_type == MXC_CPU_IMX7D;
+}
+
struct cpu_op {
u32 cpu_rate;
};
diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c
index f1f80ab73e69..0309ccda36a9 100644
--- a/arch/arm/mach-imx/pm-imx5.c
+++ b/arch/arm/mach-imx/pm-imx5.c
@@ -13,7 +13,14 @@
#include <linux/io.h>
#include <linux/err.h>
#include <linux/export.h>
+
+#include <linux/genalloc.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
#include <asm/cacheflush.h>
+#include <asm/fncpy.h>
#include <asm/system_misc.h>
#include <asm/tlbflush.h>
@@ -49,29 +56,91 @@
*/
#define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF
+struct imx5_suspend_io_state {
+ u32 offset;
+ u32 clear;
+ u32 set;
+ u32 saved_value;
+};
+
struct imx5_pm_data {
+ phys_addr_t ccm_addr;
phys_addr_t cortex_addr;
phys_addr_t gpc_addr;
+ phys_addr_t m4if_addr;
+ phys_addr_t iomuxc_addr;
+ void (*suspend_asm)(void __iomem *ocram_vbase);
+ const u32 *suspend_asm_sz;
+ const struct imx5_suspend_io_state *suspend_io_config;
+ int suspend_io_count;
+};
+
+static const struct imx5_suspend_io_state imx53_suspend_io_config[] = {
+#define MX53_DSE_HIGHZ_MASK (0x7 << 19)
+ {.offset = 0x584, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM0 */
+ {.offset = 0x594, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM1 */
+ {.offset = 0x560, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM2 */
+ {.offset = 0x554, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM3 */
+ {.offset = 0x574, .clear = MX53_DSE_HIGHZ_MASK}, /* CAS */
+ {.offset = 0x588, .clear = MX53_DSE_HIGHZ_MASK}, /* RAS */
+ {.offset = 0x578, .clear = MX53_DSE_HIGHZ_MASK}, /* SDCLK_0 */
+ {.offset = 0x570, .clear = MX53_DSE_HIGHZ_MASK}, /* SDCLK_1 */
+
+ {.offset = 0x580, .clear = MX53_DSE_HIGHZ_MASK}, /* SDODT0 */
+ {.offset = 0x564, .clear = MX53_DSE_HIGHZ_MASK}, /* SDODT1 */
+ {.offset = 0x57c, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS0 */
+ {.offset = 0x590, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS1 */
+ {.offset = 0x568, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS2 */
+ {.offset = 0x558, .clear = MX53_DSE_HIGHZ_MASK}, /* SDSQ3 */
+ {.offset = 0x6f0, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_ADDS */
+ {.offset = 0x718, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_BODS */
+ {.offset = 0x71c, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B1DS */
+ {.offset = 0x728, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B2DS */
+ {.offset = 0x72c, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B3DS */
+
+ /* Controls the CKE signal which is required to leave self refresh */
+ {.offset = 0x720, .clear = MX53_DSE_HIGHZ_MASK, .set = 1 << 19}, /* CTLDS */
};
static const struct imx5_pm_data imx51_pm_data __initconst = {
+ .ccm_addr = 0x73fd4000,
.cortex_addr = 0x83fa0000,
.gpc_addr = 0x73fd8000,
};
static const struct imx5_pm_data imx53_pm_data __initconst = {
+ .ccm_addr = 0x53fd4000,
.cortex_addr = 0x63fa0000,
.gpc_addr = 0x53fd8000,
+ .m4if_addr = 0x63fd8000,
+ .iomuxc_addr = 0x53fa8000,
+ .suspend_asm = &imx53_suspend,
+ .suspend_asm_sz = &imx53_suspend_sz,
+ .suspend_io_config = imx53_suspend_io_config,
+ .suspend_io_count = ARRAY_SIZE(imx53_suspend_io_config),
};
+#define MX5_MAX_SUSPEND_IOSTATE ARRAY_SIZE(imx53_suspend_io_config)
+
+/*
+ * This structure is for passing necessary data for low level ocram
+ * suspend code(arch/arm/mach-imx/suspend-imx53.S), if this struct
+ * definition is changed, the offset definition in that file
+ * must be also changed accordingly otherwise, the suspend to ocram
+ * function will be broken!
+ */
+struct imx5_cpu_suspend_info {
+ void __iomem *m4if_base;
+ void __iomem *iomuxc_base;
+ u32 io_count;
+ struct imx5_suspend_io_state io_state[MX5_MAX_SUSPEND_IOSTATE];
+} __aligned(8);
+
static void __iomem *ccm_base;
static void __iomem *cortex_base;
static void __iomem *gpc_base;
-
-void __init imx5_pm_set_ccm_base(void __iomem *base)
-{
- ccm_base = base;
-}
+static void __iomem *suspend_ocram_base;
+static void (*imx5_suspend_in_ocram_fn)(void __iomem *ocram_vbase);
/*
* set cpu low power mode before WFI instruction. This function is called
@@ -161,8 +230,15 @@ static int mx5_suspend_enter(suspend_state_t state)
/*clear the EMPGC0/1 bits */
__raw_writel(0, gpc_base + MXC_SRPG_EMPGC0_SRPGCR);
__raw_writel(0, gpc_base + MXC_SRPG_EMPGC1_SRPGCR);
+
+ if (imx5_suspend_in_ocram_fn)
+ imx5_suspend_in_ocram_fn(suspend_ocram_base);
+ else
+ cpu_do_idle();
+
+ } else {
+ cpu_do_idle();
}
- cpu_do_idle();
/* return registers to default idle state */
mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
@@ -194,6 +270,111 @@ static void imx5_pm_idle(void)
imx5_cpu_do_idle();
}
+static int __init imx_suspend_alloc_ocram(
+ size_t size,
+ void __iomem **virt_out,
+ phys_addr_t *phys_out)
+{
+ struct device_node *node;
+ struct platform_device *pdev;
+ struct gen_pool *ocram_pool;
+ unsigned long ocram_base;
+ void __iomem *virt;
+ phys_addr_t phys;
+ int ret = 0;
+
+ /* Copied from imx6: TODO factorize */
+ node = of_find_compatible_node(NULL, NULL, "mmio-sram");
+ if (!node) {
+ pr_warn("%s: failed to find ocram node!\n", __func__);
+ return -ENODEV;
+ }
+
+ pdev = of_find_device_by_node(node);
+ if (!pdev) {
+ pr_warn("%s: failed to find ocram device!\n", __func__);
+ ret = -ENODEV;
+ goto put_node;
+ }
+
+ ocram_pool = dev_get_gen_pool(&pdev->dev);
+ if (!ocram_pool) {
+ pr_warn("%s: ocram pool unavailable!\n", __func__);
+ ret = -ENODEV;
+ goto put_node;
+ }
+
+ ocram_base = gen_pool_alloc(ocram_pool, size);
+ if (!ocram_base) {
+ pr_warn("%s: unable to alloc ocram!\n", __func__);
+ ret = -ENOMEM;
+ goto put_node;
+ }
+
+ phys = gen_pool_virt_to_phys(ocram_pool, ocram_base);
+ virt = __arm_ioremap_exec(phys, size, false);
+ if (phys_out)
+ *phys_out = phys;
+ if (virt_out)
+ *virt_out = virt;
+
+put_node:
+ of_node_put(node);
+
+ return ret;
+}
+
+static int __init imx5_suspend_init(const struct imx5_pm_data *soc_data)
+{
+ struct imx5_cpu_suspend_info *suspend_info;
+ int ret;
+ /* Need this to avoid compile error due to const typeof in fncpy.h */
+ void (*suspend_asm)(void __iomem *) = soc_data->suspend_asm;
+
+ if (!suspend_asm)
+ return 0;
+
+ if (!soc_data->suspend_asm_sz || !*soc_data->suspend_asm_sz)
+ return -EINVAL;
+
+ ret = imx_suspend_alloc_ocram(
+ *soc_data->suspend_asm_sz + sizeof(*suspend_info),
+ &suspend_ocram_base, NULL);
+ if (ret)
+ return ret;
+
+ suspend_info = suspend_ocram_base;
+
+ suspend_info->io_count = soc_data->suspend_io_count;
+ memcpy(suspend_info->io_state, soc_data->suspend_io_config,
+ sizeof(*suspend_info->io_state) * soc_data->suspend_io_count);
+
+ suspend_info->m4if_base = ioremap(soc_data->m4if_addr, SZ_16K);
+ if (!suspend_info->m4if_base) {
+ ret = -ENOMEM;
+ goto failed_map_m4if;
+ }
+
+ suspend_info->iomuxc_base = ioremap(soc_data->iomuxc_addr, SZ_16K);
+ if (!suspend_info->iomuxc_base) {
+ ret = -ENOMEM;
+ goto failed_map_iomuxc;
+ }
+
+ imx5_suspend_in_ocram_fn = fncpy(
+ suspend_ocram_base + sizeof(*suspend_info),
+ suspend_asm,
+ *soc_data->suspend_asm_sz);
+
+ return 0;
+
+failed_map_iomuxc:
+ iounmap(suspend_info->m4if_base);
+
+failed_map_m4if:
+ return ret;
+}
+
static int __init imx5_pm_common_init(const struct imx5_pm_data *data)
{
int ret;
@@ -208,6 +389,7 @@ static int __init imx5_pm_common_init(const struct imx5_pm_data *data)
arm_pm_idle = imx5_pm_idle;
+ ccm_base = ioremap(data->ccm_addr, SZ_16K);
cortex_base = ioremap(data->cortex_addr, SZ_16K);
gpc_base = ioremap(data->gpc_addr, SZ_16K);
WARN_ON(!ccm_base || !cortex_base || !gpc_base);
@@ -219,6 +401,11 @@ static int __init imx5_pm_common_init(const struct imx5_pm_data *data)
if (ret)
pr_warn("%s: cpuidle init failed %d\n", __func__, ret);
+ ret = imx5_suspend_init(data);
+ if (ret)
+ pr_warn("%s: No DDR LPM support with suspend %d!\n",
+ __func__, ret);
+
suspend_set_ops(&mx5_suspend_ops);
return 0;
@@ -226,10 +413,12 @@ static int __init imx5_pm_common_init(const struct imx5_pm_data *data)
void __init imx51_pm_init(void)
{
- imx5_pm_common_init(&imx51_pm_data);
+ if (IS_ENABLED(CONFIG_SOC_IMX51))
+ imx5_pm_common_init(&imx51_pm_data);
}
void __init imx53_pm_init(void)
{
- imx5_pm_common_init(&imx53_pm_data);
+ if (IS_ENABLED(CONFIG_SOC_IMX53))
+ imx5_pm_common_init(&imx53_pm_data);
}
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index 6a7c6fc780cc..b01650d94f91 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -255,7 +255,7 @@ static void imx6q_enable_wb(bool enable)
writel_relaxed(val, ccm_base + CCR);
}
-int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
+int imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
{
u32 val = readl_relaxed(ccm_base + CLPCR);
@@ -340,7 +340,7 @@ static int imx6q_pm_enter(suspend_state_t state)
{
switch (state) {
case PM_SUSPEND_STANDBY:
- imx6q_set_lpm(STOP_POWER_ON);
+ imx6_set_lpm(STOP_POWER_ON);
imx6q_set_int_mem_clk_lpm(true);
imx_gpc_pre_suspend(false);
if (cpu_is_imx6sl())
@@ -350,10 +350,10 @@ static int imx6q_pm_enter(suspend_state_t state)
if (cpu_is_imx6sl())
imx6sl_set_wait_clk(false);
imx_gpc_post_resume();
- imx6q_set_lpm(WAIT_CLOCKED);
+ imx6_set_lpm(WAIT_CLOCKED);
break;
case PM_SUSPEND_MEM:
- imx6q_set_lpm(STOP_POWER_OFF);
+ imx6_set_lpm(STOP_POWER_OFF);
imx6q_set_int_mem_clk_lpm(false);
imx6q_enable_wb(true);
/*
@@ -373,7 +373,7 @@ static int imx6q_pm_enter(suspend_state_t state)
imx6_enable_rbc(false);
imx6q_enable_wb(false);
imx6q_set_int_mem_clk_lpm(true);
- imx6q_set_lpm(WAIT_CLOCKED);
+ imx6_set_lpm(WAIT_CLOCKED);
break;
default:
return -EINVAL;
@@ -392,11 +392,6 @@ static const struct platform_suspend_ops imx6q_pm_ops = {
.valid = imx6q_pm_valid,
};
-void __init imx6q_pm_set_ccm_base(void __iomem *base)
-{
- ccm_base = base;
-}
-
static int __init imx6_pm_get_base(struct imx6_pm_base *base,
const char *compat)
{
@@ -482,8 +477,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
/*
* ccm physical address is not used by asm code currently,
- * so get ccm virtual address directly, as we already have
- * it from ccm driver.
+ * so get ccm virtual address directly.
*/
pm_info->ccm_base.vbase = ccm_base;
@@ -568,7 +562,7 @@ static void __init imx6_pm_common_init(const struct imx6_pm_socdata
/*
* This is for SW workaround step #1 of ERR007265, see comments
- * in imx6q_set_lpm for details of this errata.
+ * in imx6_set_lpm for details of this errata.
* Force IOMUXC irq pending, so that the interrupt to GPC can be
* used to deassert dsm_request signal when the signal gets
* asserted unexpectedly.
@@ -579,6 +573,24 @@ static void __init imx6_pm_common_init(const struct imx6_pm_socdata
IMX6Q_GPR1_GINT);
}
+void __init imx6_pm_ccm_init(const char *ccm_compat)
+{
+ struct device_node *np;
+ u32 val;
+
+ np = of_find_compatible_node(NULL, NULL, ccm_compat);
+ ccm_base = of_iomap(np, 0);
+ BUG_ON(!ccm_base);
+
+ /*
+ * Initialize CCM_CLPCR_LPM into RUN mode to avoid ARM core
+ * clock being shut down unexpectedly by WAIT mode.
+ */
+ val = readl_relaxed(ccm_base + CLPCR);
+ val &= ~BM_CLPCR_LPM;
+ writel_relaxed(val, ccm_base + CLPCR);
+}
+
void __init imx6q_pm_init(void)
{
imx6_pm_common_init(&imx6q_pm_data);
diff --git a/arch/arm/mach-imx/suspend-imx53.S b/arch/arm/mach-imx/suspend-imx53.S
new file mode 100644
index 000000000000..5ed078ad110a
--- /dev/null
+++ b/arch/arm/mach-imx/suspend-imx53.S
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
+ */
+/*
+ * 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/linkage.h>
+
+#define M4IF_MCR0_OFFSET (0x008C)
+#define M4IF_MCR0_FDVFS (0x1 << 11)
+#define M4IF_MCR0_FDVACK (0x1 << 27)
+
+ .align 3
+
+/*
+ * ==================== low level suspend ====================
+ *
+ * On entry
+ * r0: pm_info structure address;
+ *
+ * suspend ocram space layout:
+ * ======================== high address ======================
+ * .
+ * .
+ * .
+ * ^
+ * ^
+ * ^
+ * imx53_suspend code
+ * PM_INFO structure(imx53_suspend_info)
+ * ======================== low address =======================
+ */
+
+/* Offsets of members of struct imx53_suspend_info */
+#define SUSPEND_INFO_MX53_M4IF_V_OFFSET 0x0
+#define SUSPEND_INFO_MX53_IOMUXC_V_OFFSET 0x4
+#define SUSPEND_INFO_MX53_IO_COUNT_OFFSET 0x8
+#define SUSPEND_INFO_MX53_IO_STATE_OFFSET 0xc
+
+ENTRY(imx53_suspend)
+ stmfd sp!, {r4,r5,r6,r7}
+
+ /* Save pad config */
+ ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
+ cmp r1, #0
+ beq skip_pad_conf_1
+
+ add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
+ ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]
+
+1:
+ ldr r5, [r2], #12 /* IOMUXC register offset */
+ ldr r6, [r3, r5] /* current value */
+ str r6, [r2], #4 /* save area */
+ subs r1, r1, #1
+ bne 1b
+
+skip_pad_conf_1:
+ /* Set FDVFS bit of M4IF_MCR0 to request DDR to enter self-refresh */
+ ldr r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET]
+ ldr r2,[r1, #M4IF_MCR0_OFFSET]
+ orr r2, r2, #M4IF_MCR0_FDVFS
+ str r2,[r1, #M4IF_MCR0_OFFSET]
+
+ /* Poll FDVACK bit of M4IF_MCR to wait for DDR to enter self-refresh */
+wait_sr_ack:
+ ldr r2,[r1, #M4IF_MCR0_OFFSET]
+ ands r2, r2, #M4IF_MCR0_FDVACK
+ beq wait_sr_ack
+
+ /* Set pad config */
+ ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
+ cmp r1, #0
+ beq skip_pad_conf_2
+
+ add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
+ ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]
+
+2:
+ ldr r5, [r2], #4 /* IOMUXC register offset */
+ ldr r6, [r2], #4 /* clear */
+ ldr r7, [r3, r5]
+ bic r7, r7, r6
+ ldr r6, [r2], #8 /* set */
+ orr r7, r7, r6
+ str r7, [r3, r5]
+ subs r1, r1, #1
+ bne 2b
+
+skip_pad_conf_2:
+ /* Zzz, enter stop mode */
+ wfi
+ nop
+ nop
+ nop
+ nop
+
+ /* Restore pad config */
+ ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
+ cmp r1, #0
+ beq skip_pad_conf_3
+
+ add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
+ ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]
+
+3:
+ ldr r5, [r2], #12 /* IOMUXC register offset */
+ ldr r6, [r2], #4 /* saved value */
+ str r6, [r3, r5]
+ subs r1, r1, #1
+ bne 3b
+
+skip_pad_conf_3:
+ /* Clear FDVFS bit of M4IF_MCR0 to request DDR to exit self-refresh */
+ ldr r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET]
+ ldr r2,[r1, #M4IF_MCR0_OFFSET]
+ bic r2, r2, #M4IF_MCR0_FDVFS
+ str r2,[r1, #M4IF_MCR0_OFFSET]
+
+ /* Poll FDVACK bit of M4IF_MCR to wait for DDR to exit self-refresh */
+wait_ar_ack:
+ ldr r2,[r1, #M4IF_MCR0_OFFSET]
+ ands r2, r2, #M4IF_MCR0_FDVACK
+ bne wait_ar_ack
+
+ /* Restore registers */
+ ldmfd sp!, {r4,r5,r6,r7}
+ mov pc, lr
+
+ENDPROC(imx53_suspend)
+
+ENTRY(imx53_suspend_sz)
+ .word . - imx53_suspend
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
deleted file mode 100644
index 15d18e198303..000000000000
--- a/arch/arm/mach-imx/time.c
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * linux/arch/arm/plat-mxc/time.c
- *
- * Copyright (C) 2000-2001 Deep Blue Solutions
- * Copyright (C) 2002 Shane Nay (shane@minirl.com)
- * Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
- * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/clockchips.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/sched_clock.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-
-#include <asm/mach/time.h>
-
-#include "common.h"
-#include "hardware.h"
-
-/*
- * There are 2 versions of the timer hardware on Freescale MXC hardware.
- * Version 1: MX1/MXL, MX21, MX27.
- * Version 2: MX25, MX31, MX35, MX37, MX51
- */
-
-/* defines common for all i.MX */
-#define MXC_TCTL 0x00
-#define MXC_TCTL_TEN (1 << 0) /* Enable module */
-#define MXC_TPRER 0x04
-
-/* MX1, MX21, MX27 */
-#define MX1_2_TCTL_CLK_PCLK1 (1 << 1)
-#define MX1_2_TCTL_IRQEN (1 << 4)
-#define MX1_2_TCTL_FRR (1 << 8)
-#define MX1_2_TCMP 0x08
-#define MX1_2_TCN 0x10
-#define MX1_2_TSTAT 0x14
-
-/* MX21, MX27 */
-#define MX2_TSTAT_CAPT (1 << 1)
-#define MX2_TSTAT_COMP (1 << 0)
-
-/* MX31, MX35, MX25, MX5, MX6 */
-#define V2_TCTL_WAITEN (1 << 3) /* Wait enable mode */
-#define V2_TCTL_CLK_IPG (1 << 6)
-#define V2_TCTL_CLK_PER (2 << 6)
-#define V2_TCTL_CLK_OSC_DIV8 (5 << 6)
-#define V2_TCTL_FRR (1 << 9)
-#define V2_TCTL_24MEN (1 << 10)
-#define V2_TPRER_PRE24M 12
-#define V2_IR 0x0c
-#define V2_TSTAT 0x08
-#define V2_TSTAT_OF1 (1 << 0)
-#define V2_TCN 0x24
-#define V2_TCMP 0x10
-
-#define V2_TIMER_RATE_OSC_DIV8 3000000
-
-#define timer_is_v1() (cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
-#define timer_is_v2() (!timer_is_v1())
-
-static struct clock_event_device clockevent_mxc;
-static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
-
-static void __iomem *timer_base;
-
-static inline void gpt_irq_disable(void)
-{
- unsigned int tmp;
-
- if (timer_is_v2())
- __raw_writel(0, timer_base + V2_IR);
- else {
- tmp = __raw_readl(timer_base + MXC_TCTL);
- __raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
- }
-}
-
-static inline void gpt_irq_enable(void)
-{
- if (timer_is_v2())
- __raw_writel(1<<0, timer_base + V2_IR);
- else {
- __raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
- timer_base + MXC_TCTL);
- }
-}
-
-static void gpt_irq_acknowledge(void)
-{
- if (timer_is_v1()) {
- if (cpu_is_mx1())
- __raw_writel(0, timer_base + MX1_2_TSTAT);
- else
- __raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
- timer_base + MX1_2_TSTAT);
- } else if (timer_is_v2())
- __raw_writel(V2_TSTAT_OF1, timer_base + V2_TSTAT);
-}
-
-static void __iomem *sched_clock_reg;
-
-static u64 notrace mxc_read_sched_clock(void)
-{
- return sched_clock_reg ? __raw_readl(sched_clock_reg) : 0;
-}
-
-static struct delay_timer imx_delay_timer;
-
-static unsigned long imx_read_current_timer(void)
-{
- return __raw_readl(sched_clock_reg);
-}
-
-static int __init mxc_clocksource_init(struct clk *timer_clk)
-{
- unsigned int c = clk_get_rate(timer_clk);
- void __iomem *reg = timer_base + (timer_is_v2() ? V2_TCN : MX1_2_TCN);
-
- imx_delay_timer.read_current_timer = &imx_read_current_timer;
- imx_delay_timer.freq = c;
- register_current_timer_delay(&imx_delay_timer);
-
- sched_clock_reg = reg;
-
- sched_clock_register(mxc_read_sched_clock, 32, c);
- return clocksource_mmio_init(reg, "mxc_timer1", c, 200, 32,
- clocksource_mmio_readl_up);
-}
-
-/* clock event */
-
-static int mx1_2_set_next_event(unsigned long evt,
- struct clock_event_device *unused)
-{
- unsigned long tcmp;
-
- tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;
-
- __raw_writel(tcmp, timer_base + MX1_2_TCMP);
-
- return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
- -ETIME : 0;
-}
-
-static int v2_set_next_event(unsigned long evt,
- struct clock_event_device *unused)
-{
- unsigned long tcmp;
-
- tcmp = __raw_readl(timer_base + V2_TCN) + evt;
-
- __raw_writel(tcmp, timer_base + V2_TCMP);
-
- return evt < 0x7fffffff &&
- (int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
- -ETIME : 0;
-}
-
-#ifdef DEBUG
-static const char *clock_event_mode_label[] = {
- [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
- [CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT",
- [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
- [CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED",
- [CLOCK_EVT_MODE_RESUME] = "CLOCK_EVT_MODE_RESUME",
-};
-#endif /* DEBUG */
-
-static void mxc_set_mode(enum clock_event_mode mode,
- struct clock_event_device *evt)
-{
- unsigned long flags;
-
- /*
- * The timer interrupt generation is disabled at least
- * for enough time to call mxc_set_next_event()
- */
- local_irq_save(flags);
-
- /* Disable interrupt in GPT module */
- gpt_irq_disable();
-
- if (mode != clockevent_mode) {
- /* Set event time into far-far future */
- if (timer_is_v2())
- __raw_writel(__raw_readl(timer_base + V2_TCN) - 3,
- timer_base + V2_TCMP);
- else
- __raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
- timer_base + MX1_2_TCMP);
-
- /* Clear pending interrupt */
- gpt_irq_acknowledge();
- }
-
-#ifdef DEBUG
- printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n",
- clock_event_mode_label[clockevent_mode],
- clock_event_mode_label[mode]);
-#endif /* DEBUG */
-
- /* Remember timer mode */
- clockevent_mode = mode;
- local_irq_restore(flags);
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- printk(KERN_ERR"mxc_set_mode: Periodic mode is not "
- "supported for i.MX\n");
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- /*
- * Do not put overhead of interrupt enable/disable into
- * mxc_set_next_event(), the core has about 4 minutes
- * to call mxc_set_next_event() or shutdown clock after
- * mode switching
- */
- local_irq_save(flags);
- gpt_irq_enable();
- local_irq_restore(flags);
- break;
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_RESUME:
- /* Left event sources disabled, no more interrupts appear */
- break;
- }
-}
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
-{
- struct clock_event_device *evt = &clockevent_mxc;
- uint32_t tstat;
-
- if (timer_is_v2())
- tstat = __raw_readl(timer_base + V2_TSTAT);
- else
- tstat = __raw_readl(timer_base + MX1_2_TSTAT);
-
- gpt_irq_acknowledge();
-
- evt->event_handler(evt);
-
- return IRQ_HANDLED;
-}
-
-static struct irqaction mxc_timer_irq = {
- .name = "i.MX Timer Tick",
- .flags = IRQF_TIMER | IRQF_IRQPOLL,
- .handler = mxc_timer_interrupt,
-};
-
-static struct clock_event_device clockevent_mxc = {
- .name = "mxc_timer1",
- .features = CLOCK_EVT_FEAT_ONESHOT,
- .set_mode = mxc_set_mode,
- .set_next_event = mx1_2_set_next_event,
- .rating = 200,
-};
-
-static int __init mxc_clockevent_init(struct clk *timer_clk)
-{
- if (timer_is_v2())
- clockevent_mxc.set_next_event = v2_set_next_event;
-
- clockevent_mxc.cpumask = cpumask_of(0);
- clockevents_config_and_register(&clockevent_mxc,
- clk_get_rate(timer_clk),
- 0xff, 0xfffffffe);
-
- return 0;
-}
-
-static void __init _mxc_timer_init(int irq,
- struct clk *clk_per, struct clk *clk_ipg)
-{
- uint32_t tctl_val;
-
- if (IS_ERR(clk_per)) {
- pr_err("i.MX timer: unable to get clk\n");
- return;
- }
-
- if (!IS_ERR(clk_ipg))
- clk_prepare_enable(clk_ipg);
-
- clk_prepare_enable(clk_per);
-
- /*
- * Initialise to a known state (all timers off, and timing reset)
- */
-
- __raw_writel(0, timer_base + MXC_TCTL);
- __raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
-
- if (timer_is_v2()) {
- tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
- if (clk_get_rate(clk_per) == V2_TIMER_RATE_OSC_DIV8) {
- tctl_val |= V2_TCTL_CLK_OSC_DIV8;
- if (cpu_is_imx6dl() || cpu_is_imx6sx()) {
- /* 24 / 8 = 3 MHz */
- __raw_writel(7 << V2_TPRER_PRE24M,
- timer_base + MXC_TPRER);
- tctl_val |= V2_TCTL_24MEN;
- }
- } else {
- tctl_val |= V2_TCTL_CLK_PER;
- }
- } else {
- tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
- }
-
- __raw_writel(tctl_val, timer_base + MXC_TCTL);
-
- /* init and register the timer to the framework */
- mxc_clocksource_init(clk_per);
- mxc_clockevent_init(clk_per);
-
- /* Make irqs happen */
- setup_irq(irq, &mxc_timer_irq);
-}
-
-void __init mxc_timer_init(void __iomem *base, int irq)
-{
- struct clk *clk_per = clk_get_sys("imx-gpt.0", "per");
- struct clk *clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
-
- timer_base = base;
-
- _mxc_timer_init(irq, clk_per, clk_ipg);
-}
-
-static void __init mxc_timer_init_dt(struct device_node *np)
-{
- struct clk *clk_per, *clk_ipg;
- int irq;
-
- if (timer_base)
- return;
-
- timer_base = of_iomap(np, 0);
- WARN_ON(!timer_base);
- irq = irq_of_parse_and_map(np, 0);
-
- clk_ipg = of_clk_get_by_name(np, "ipg");
-
- /* Try osc_per first, and fall back to per otherwise */
- clk_per = of_clk_get_by_name(np, "osc_per");
- if (IS_ERR(clk_per))
- clk_per = of_clk_get_by_name(np, "per");
-
- _mxc_timer_init(irq, clk_per, clk_ipg);
-}
-CLOCKSOURCE_OF_DECLARE(mx1_timer, "fsl,imx1-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx25_timer, "fsl,imx25-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx50_timer, "fsl,imx50-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx51_timer, "fsl,imx51-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx53_timer, "fsl,imx53-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx6q_timer, "fsl,imx6q-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx6sl_timer, "fsl,imx6sl-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx6sx_timer, "fsl,imx6sx-gpt", mxc_timer_init_dt);
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 30003ba447a5..5b0e363fe5ba 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -37,7 +37,6 @@
#include <linux/stat.h>
#include <linux/termios.h>
-#include <asm/hardware/arm_timer.h>
#include <asm/setup.h>
#include <asm/param.h> /* HZ */
#include <asm/mach-types.h>
diff --git a/arch/arm/mach-iop13xx/include/mach/time.h b/arch/arm/mach-iop13xx/include/mach/time.h
index 15bc9bb78a6b..c871e6874594 100644
--- a/arch/arm/mach-iop13xx/include/mach/time.h
+++ b/arch/arm/mach-iop13xx/include/mach/time.h
@@ -42,7 +42,7 @@ static inline unsigned long iop13xx_core_freq(void)
case IOP13XX_CORE_FREQ_1200:
return 1200000000;
default:
- printk("%s: warning unknown frequency, defaulting to 800Mhz\n",
+ printk("%s: warning unknown frequency, defaulting to 800MHz\n",
__func__);
}
diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h
index 75c4c6572ad0..34b3d3f3f131 100644
--- a/arch/arm/mach-ixp4xx/include/mach/platform.h
+++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
@@ -74,7 +74,7 @@ extern unsigned long ixp4xx_exp_bus_size;
/*
* Clock Speed Definitions.
*/
-#define IXP4XX_PERIPHERAL_BUS_CLOCK (66) /* 66Mhzi APB BUS */
+#define IXP4XX_PERIPHERAL_BUS_CLOCK (66) /* 66MHzi APB BUS */
#define IXP4XX_UART_XTAL 14745600
/*
diff --git a/arch/arm/mach-keystone/keystone.c b/arch/arm/mach-keystone/keystone.c
index 06620875813a..e288010522f9 100644
--- a/arch/arm/mach-keystone/keystone.c
+++ b/arch/arm/mach-keystone/keystone.c
@@ -27,7 +27,6 @@
#include "keystone.h"
-static struct notifier_block platform_nb;
static unsigned long keystone_dma_pfn_offset __read_mostly;
static int keystone_platform_notifier(struct notifier_block *nb,
@@ -49,11 +48,18 @@ static int keystone_platform_notifier(struct notifier_block *nb,
return NOTIFY_OK;
}
+static struct notifier_block platform_nb = {
+ .notifier_call = keystone_platform_notifier,
+};
+
static void __init keystone_init(void)
{
- keystone_pm_runtime_init();
- if (platform_nb.notifier_call)
+ if (PHYS_OFFSET >= KEYSTONE_HIGH_PHYS_START) {
+ keystone_dma_pfn_offset = PFN_DOWN(KEYSTONE_HIGH_PHYS_START -
+ KEYSTONE_LOW_PHYS_START);
bus_register_notifier(&platform_bus_type, &platform_nb);
+ }
+ keystone_pm_runtime_init();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
@@ -62,11 +68,9 @@ static phys_addr_t keystone_virt_to_idmap(unsigned long x)
return (phys_addr_t)(x) - CONFIG_PAGE_OFFSET + KEYSTONE_LOW_PHYS_START;
}
-static void __init keystone_init_meminfo(void)
+static long long __init keystone_pv_fixup(void)
{
- bool lpae = IS_ENABLED(CONFIG_ARM_LPAE);
- bool pvpatch = IS_ENABLED(CONFIG_ARM_PATCH_PHYS_VIRT);
- phys_addr_t offset = PHYS_OFFSET - KEYSTONE_LOW_PHYS_START;
+ long long offset;
phys_addr_t mem_start, mem_end;
mem_start = memblock_start_of_DRAM();
@@ -75,32 +79,21 @@ static void __init keystone_init_meminfo(void)
/* nothing to do if we are running out of the <32-bit space */
if (mem_start >= KEYSTONE_LOW_PHYS_START &&
mem_end <= KEYSTONE_LOW_PHYS_END)
- return;
-
- if (!lpae || !pvpatch) {
- pr_crit("Enable %s%s%s to run outside 32-bit space\n",
- !lpae ? __stringify(CONFIG_ARM_LPAE) : "",
- (!lpae && !pvpatch) ? " and " : "",
- !pvpatch ? __stringify(CONFIG_ARM_PATCH_PHYS_VIRT) : "");
- }
+ return 0;
if (mem_start < KEYSTONE_HIGH_PHYS_START ||
mem_end > KEYSTONE_HIGH_PHYS_END) {
pr_crit("Invalid address space for memory (%08llx-%08llx)\n",
- (u64)mem_start, (u64)mem_end);
+ (u64)mem_start, (u64)mem_end);
+ return 0;
}
- offset += KEYSTONE_HIGH_PHYS_START;
- __pv_phys_pfn_offset = PFN_DOWN(offset);
- __pv_offset = (offset - PAGE_OFFSET);
+ offset = KEYSTONE_HIGH_PHYS_START - KEYSTONE_LOW_PHYS_START;
/* Populate the arch idmap hook */
arch_virt_to_idmap = keystone_virt_to_idmap;
- platform_nb.notifier_call = keystone_platform_notifier;
- keystone_dma_pfn_offset = PFN_DOWN(KEYSTONE_HIGH_PHYS_START -
- KEYSTONE_LOW_PHYS_START);
- pr_info("Switching to high address space at 0x%llx\n", (u64)offset);
+ return offset;
}
static const char *const keystone_match[] __initconst = {
@@ -115,5 +108,5 @@ DT_MACHINE_START(KEYSTONE, "Keystone")
.smp = smp_ops(keystone_smp_ops),
.init_machine = keystone_init,
.dt_compat = keystone_match,
- .init_meminfo = keystone_init_meminfo,
+ .pv_fixup = keystone_pv_fixup,
MACHINE_END
diff --git a/arch/arm/mach-keystone/platsmp.c b/arch/arm/mach-keystone/platsmp.c
index 5f46a7cf907b..4bbb18463bfd 100644
--- a/arch/arm/mach-keystone/platsmp.c
+++ b/arch/arm/mach-keystone/platsmp.c
@@ -39,19 +39,6 @@ static int keystone_smp_boot_secondary(unsigned int cpu,
return error;
}
-#ifdef CONFIG_ARM_LPAE
-static void __cpuinit keystone_smp_secondary_initmem(unsigned int cpu)
-{
- pgd_t *pgd0 = pgd_offset_k(0);
- cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET);
- local_flush_tlb_all();
-}
-#else
-static inline void __cpuinit keystone_smp_secondary_initmem(unsigned int cpu)
-{}
-#endif
-
struct smp_operations keystone_smp_ops __initdata = {
.smp_boot_secondary = keystone_smp_boot_secondary,
- .smp_secondary_init = keystone_smp_secondary_initmem,
};
diff --git a/arch/arm/mach-keystone/pm_domain.c b/arch/arm/mach-keystone/pm_domain.c
index 41bebfd296dc..edea697e8253 100644
--- a/arch/arm/mach-keystone/pm_domain.c
+++ b/arch/arm/mach-keystone/pm_domain.c
@@ -19,40 +19,9 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
-#ifdef CONFIG_PM
-static int keystone_pm_runtime_suspend(struct device *dev)
-{
- int ret;
-
- dev_dbg(dev, "%s\n", __func__);
-
- ret = pm_generic_runtime_suspend(dev);
- if (ret)
- return ret;
-
- ret = pm_clk_suspend(dev);
- if (ret) {
- pm_generic_runtime_resume(dev);
- return ret;
- }
-
- return 0;
-}
-
-static int keystone_pm_runtime_resume(struct device *dev)
-{
- dev_dbg(dev, "%s\n", __func__);
-
- pm_clk_resume(dev);
-
- return pm_generic_runtime_resume(dev);
-}
-#endif
-
static struct dev_pm_domain keystone_pm_domain = {
.ops = {
- SET_RUNTIME_PM_OPS(keystone_pm_runtime_suspend,
- keystone_pm_runtime_resume, NULL)
+ USE_PM_CLK_RUNTIME_OPS
USE_PLATFORM_PM_SLEEP_OPS
},
};
diff --git a/arch/arm/mach-ks8695/include/mach/hardware.h b/arch/arm/mach-ks8695/include/mach/hardware.h
index 5090338c0db2..959c748ee8bb 100644
--- a/arch/arm/mach-ks8695/include/mach/hardware.h
+++ b/arch/arm/mach-ks8695/include/mach/hardware.h
@@ -17,7 +17,7 @@
#include <asm/sizes.h>
/*
- * Clocks are derived from MCLK, which is 25Mhz
+ * Clocks are derived from MCLK, which is 25MHz
*/
#define KS8695_CLOCK_RATE 25000000
diff --git a/arch/arm/mach-lpc18xx/Makefile b/arch/arm/mach-lpc18xx/Makefile
new file mode 100644
index 000000000000..bd0b7b5d6e9d
--- /dev/null
+++ b/arch/arm/mach-lpc18xx/Makefile
@@ -0,0 +1 @@
+obj-y += board-dt.o
diff --git a/arch/arm/mach-lpc18xx/Makefile.boot b/arch/arm/mach-lpc18xx/Makefile.boot
new file mode 100644
index 000000000000..eacfc3f5c33e
--- /dev/null
+++ b/arch/arm/mach-lpc18xx/Makefile.boot
@@ -0,0 +1,3 @@
+# Empty file waiting for deletion once Makefile.boot isn't needed any more.
+# Patch waits for application at
+# http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7889/1 .
diff --git a/arch/arm/mach-lpc18xx/board-dt.c b/arch/arm/mach-lpc18xx/board-dt.c
new file mode 100644
index 000000000000..fdcee78d1bc4
--- /dev/null
+++ b/arch/arm/mach-lpc18xx/board-dt.c
@@ -0,0 +1,22 @@
+/*
+ * Device Tree board file for NXP LPC18xx/43xx
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.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 <asm/mach/arch.h>
+
+static const char *const lpc18xx_43xx_compat[] __initconst = {
+ "nxp,lpc1850",
+ "nxp,lpc4350",
+ "nxp,lpc4370",
+ NULL
+};
+
+DT_MACHINE_START(LPC18XXDT, "NXP LPC18xx/43xx (Device Tree)")
+ .dt_compat = lpc18xx_43xx_compat,
+MACHINE_END
diff --git a/arch/arm/mach-lpc32xx/clock.c b/arch/arm/mach-lpc32xx/clock.c
index dd5d6f532e8c..661c8f4b2310 100644
--- a/arch/arm/mach-lpc32xx/clock.c
+++ b/arch/arm/mach-lpc32xx/clock.c
@@ -1238,10 +1238,7 @@ static struct clk_lookup lookups[] = {
static int __init clk_init(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
/*
* Setup muxed SYSCLK for HCLK PLL base -this selects the
diff --git a/arch/arm/mach-mvebu/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S
index 08d5ed46b996..48e4c4b3cd1c 100644
--- a/arch/arm/mach-mvebu/headsmp-a9.S
+++ b/arch/arm/mach-mvebu/headsmp-a9.S
@@ -21,7 +21,6 @@
ENTRY(mvebu_cortex_a9_secondary_startup)
ARM_BE8(setend be)
- bl v7_invalidate_l1
bl armada_38x_scu_power_up
b secondary_startup
ENDPROC(mvebu_cortex_a9_secondary_startup)
diff --git a/arch/arm/mach-nspire/nspire.c b/arch/arm/mach-nspire/nspire.c
index 3445a5686805..34c2a1b32e7d 100644
--- a/arch/arm/mach-nspire/nspire.c
+++ b/arch/arm/mach-nspire/nspire.c
@@ -22,8 +22,6 @@
#include <asm/mach-types.h>
#include <asm/mach/map.h>
-#include <asm/hardware/timer-sp.h>
-
#include "mmio.h"
#include "clcd.h"
diff --git a/arch/arm/mach-omap1/ams-delta-fiq-handler.S b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
index 3d1e1c250a1a..5d7fb596bf4a 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq-handler.S
+++ b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
@@ -17,11 +17,10 @@
#include <asm/assembler.h>
#include <mach/board-ams-delta.h>
-
-#include <mach/irqs.h>
#include <mach/ams-delta-fiq.h>
#include "iomap.h"
+#include "soc.h"
/*
* GPIO related definitions, copied from arch/arm/plat-omap/gpio.c.
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index 2aab761ee68d..a95499ea8706 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -626,6 +626,7 @@ MACHINE_START(AMS_DELTA, "Amstrad E3 (Delta)")
.map_io = ams_delta_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = ams_delta_init,
.init_late = ams_delta_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index 702d58039cc1..0fb51d22c8b5 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -362,6 +362,7 @@ MACHINE_START(OMAP_FSAMPLE, "OMAP730 F-Sample")
.map_io = omap_fsample_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = omap_fsample_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c
index e1d9171774bc..9708629f8c5f 100644
--- a/arch/arm/mach-omap1/board-generic.c
+++ b/arch/arm/mach-omap1/board-generic.c
@@ -82,6 +82,7 @@ MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
.map_io = omap16xx_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = omap_generic_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 5b45d266d83e..8340d684d8b6 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -426,6 +426,7 @@ MACHINE_START(OMAP_H2, "TI-H2")
.map_io = omap16xx_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = h2_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-h3-mmc.c b/arch/arm/mach-omap1/board-h3-mmc.c
index 17d77914d769..43aab63cbc39 100644
--- a/arch/arm/mach-omap1/board-h3-mmc.c
+++ b/arch/arm/mach-omap1/board-h3-mmc.c
@@ -16,6 +16,7 @@
#include <linux/i2c/tps65010.h>
+#include "common.h"
#include "board-h3.h"
#include "mmc.h"
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index bfed4f928663..086ff34e072b 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -452,6 +452,7 @@ MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
.map_io = omap16xx_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = h3_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-htcherald.c b/arch/arm/mach-omap1/board-htcherald.c
index 35a2379b986f..9525ef9bc6c0 100644
--- a/arch/arm/mach-omap1/board-htcherald.c
+++ b/arch/arm/mach-omap1/board-htcherald.c
@@ -601,6 +601,7 @@ MACHINE_START(HERALD, "HTC Herald")
.map_io = htcherald_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = htcherald_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index c49ce83cc1eb..ed4e045c2ad8 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -456,6 +456,7 @@ MACHINE_START(OMAP_INNOVATOR, "TI-Innovator")
.map_io = innovator_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = innovator_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index 85089d821982..dd3a3ad797ea 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.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/clkdev.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
@@ -14,7 +15,6 @@
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/input.h>
-#include <linux/clk.h>
#include <linux/omapfb.h>
#include <linux/spi/spi.h>
@@ -294,6 +294,7 @@ MACHINE_START(NOKIA770, "Nokia 770")
.map_io = omap16xx_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = omap_nokia770_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 7436d4cf6596..0efd165b8227 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -610,6 +610,7 @@ MACHINE_START(OMAP_OSK, "TI-OSK")
.map_io = omap16xx_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = osk_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
index 3b8e98f4353c..1142ae431fe0 100644
--- a/arch/arm/mach-omap1/board-palmte.c
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -235,6 +235,7 @@ MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E")
.map_io = omap15xx_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = omap_palmte_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c
index ca501208825f..54a547a96950 100644
--- a/arch/arm/mach-omap1/board-palmtt.c
+++ b/arch/arm/mach-omap1/board-palmtt.c
@@ -282,6 +282,7 @@ MACHINE_START(OMAP_PALMTT, "OMAP1510 based Palm Tungsten|T")
.map_io = omap15xx_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = omap_palmtt_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
index 470e12d67360..87ec04ae40dd 100644
--- a/arch/arm/mach-omap1/board-palmz71.c
+++ b/arch/arm/mach-omap1/board-palmz71.c
@@ -297,6 +297,7 @@ MACHINE_START(OMAP_PALMZ71, "OMAP310 based Palm Zire71")
.map_io = omap15xx_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = omap_palmz71_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 8b2f7127f716..3d76f05407f0 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -324,6 +324,7 @@ MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2")
.map_io = omap_perseus2_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = omap_perseus2_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-sx1.c b/arch/arm/mach-omap1/board-sx1.c
index 29e526235dc2..939991ea33d5 100644
--- a/arch/arm/mach-omap1/board-sx1.c
+++ b/arch/arm/mach-omap1/board-sx1.c
@@ -343,6 +343,7 @@ MACHINE_START(SX1, "OMAP310 based Siemens SX1")
.map_io = omap15xx_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = omap_sx1_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index 4677a9ccb3cb..e960687d0cb1 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -288,6 +288,7 @@ MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910")
.map_io = omap15xx_map_io,
.init_early = omap1_init_early,
.init_irq = omap1_init_irq,
+ .handle_irq = omap1_handle_irq,
.init_machine = voiceblue_init,
.init_late = omap1_init_late,
.init_time = omap1_timer_init,
diff --git a/arch/arm/mach-omap1/common.h b/arch/arm/mach-omap1/common.h
index 732f8ee2fcd2..65bb6e8085de 100644
--- a/arch/arm/mach-omap1/common.h
+++ b/arch/arm/mach-omap1/common.h
@@ -30,10 +30,14 @@
#include <linux/i2c-omap.h>
#include <linux/reboot.h>
+#include <asm/exception.h>
+
#include <plat/i2c.h>
#include <mach/irqs.h>
+#include "soc.h"
+
#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
void omap7xx_map_io(void);
#else
@@ -73,6 +77,7 @@ static inline int omap_serial_wakeup_init(void)
void omap1_init_early(void);
void omap1_init_irq(void);
+void __exception_irq_entry omap1_handle_irq(struct pt_regs *regs);
void omap1_init_late(void);
void omap1_restart(enum reboot_mode, const char *);
@@ -91,8 +96,6 @@ static inline int __init omap_32k_timer_init(void)
}
#endif
-extern u32 omap_irq_flags;
-
#ifdef CONFIG_ARCH_OMAP16XX
extern int ocpi_enable(void);
#else
diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c
index 4be601b638d7..7b02ed218a42 100644
--- a/arch/arm/mach-omap1/dma.c
+++ b/arch/arm/mach-omap1/dma.c
@@ -28,7 +28,7 @@
#include <linux/omap-dma.h>
#include <mach/tc.h>
-#include <mach/irqs.h>
+#include "soc.h"
#define OMAP1_DMA_BASE (0xfffed800)
#define OMAP1_LOGICAL_DMA_CH_COUNT 17
diff --git a/arch/arm/mach-omap1/gpio16xx.c b/arch/arm/mach-omap1/gpio16xx.c
index 6e6ec93dcbb3..5b7a29b294d4 100644
--- a/arch/arm/mach-omap1/gpio16xx.c
+++ b/arch/arm/mach-omap1/gpio16xx.c
@@ -21,6 +21,8 @@
#include <mach/irqs.h>
+#include "soc.h"
+
#define OMAP1610_GPIO1_BASE 0xfffbe400
#define OMAP1610_GPIO2_BASE 0xfffbec00
#define OMAP1610_GPIO3_BASE 0xfffbb400
diff --git a/arch/arm/mach-omap1/gpio7xx.c b/arch/arm/mach-omap1/gpio7xx.c
index 4612d2506a2d..0e5f68de23bf 100644
--- a/arch/arm/mach-omap1/gpio7xx.c
+++ b/arch/arm/mach-omap1/gpio7xx.c
@@ -21,6 +21,8 @@
#include <mach/irqs.h>
+#include "soc.h"
+
#define OMAP7XX_GPIO1_BASE 0xfffbc000
#define OMAP7XX_GPIO2_BASE 0xfffbc800
#define OMAP7XX_GPIO3_BASE 0xfffbd000
diff --git a/arch/arm/mach-omap1/i2c.c b/arch/arm/mach-omap1/i2c.c
index 7f5761cffd2e..82887d645a6a 100644
--- a/arch/arm/mach-omap1/i2c.c
+++ b/arch/arm/mach-omap1/i2c.c
@@ -27,7 +27,6 @@
#define OMAP_I2C_SIZE 0x3f
#define OMAP1_I2C_BASE 0xfffb3800
-#define OMAP1_INT_I2C (32 + 4)
static const char name[] = "omap_i2c";
@@ -67,7 +66,7 @@ int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *pdata,
res[0].start = OMAP1_I2C_BASE;
res[0].end = res[0].start + OMAP_I2C_SIZE;
res[0].flags = IORESOURCE_MEM;
- res[1].start = OMAP1_INT_I2C;
+ res[1].start = INT_I2C;
res[1].flags = IORESOURCE_IRQ;
pdev->resource = res;
diff --git a/arch/arm/mach-omap1/include/mach/entry-macro.S b/arch/arm/mach-omap1/include/mach/entry-macro.S
deleted file mode 100644
index 78a8c6c24764..000000000000
--- a/arch/arm/mach-omap1/include/mach/entry-macro.S
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * arch/arm/mach-omap1/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for OMAP-based platforms
- *
- * Copyright (C) 2009 Texas Instruments
- *
- * 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/hardware.h>
-#include <mach/irqs.h>
-
- .macro get_irqnr_preamble, base, tmp
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- ldr \base, =OMAP1_IO_ADDRESS(OMAP_IH1_BASE)
- ldr \irqnr, [\base, #IRQ_ITR_REG_OFFSET]
- ldr \tmp, [\base, #IRQ_MIR_REG_OFFSET]
- mov \irqstat, #0xffffffff
- bic \tmp, \irqstat, \tmp
- tst \irqnr, \tmp
- beq 1510f
-
- ldr \irqnr, [\base, #IRQ_SIR_FIQ_REG_OFFSET]
- ldr \tmp, =omap_irq_flags @ irq flags address
- ldr \tmp, [\tmp, #0] @ irq flags value
- cmp \irqnr, #0
- ldreq \irqnr, [\base, #IRQ_SIR_IRQ_REG_OFFSET]
- cmpeq \irqnr, \tmp
- ldreq \base, =OMAP1_IO_ADDRESS(OMAP_IH2_BASE)
- ldreq \irqnr, [\base, #IRQ_SIR_IRQ_REG_OFFSET]
- addeqs \irqnr, \irqnr, #32
-1510:
- .endm
-
diff --git a/arch/arm/mach-omap1/include/mach/irqs.h b/arch/arm/mach-omap1/include/mach/irqs.h
index 729992d7d26a..9050085271bc 100644
--- a/arch/arm/mach-omap1/include/mach/irqs.h
+++ b/arch/arm/mach-omap1/include/mach/irqs.h
@@ -34,84 +34,84 @@
* NOTE: See also the OMAP-1510 and 1610 specific IRQ numbers below
*
*/
-#define INT_CAMERA 1
-#define INT_FIQ 3
-#define INT_RTDX 6
-#define INT_DSP_MMU_ABORT 7
-#define INT_HOST 8
-#define INT_ABORT 9
-#define INT_BRIDGE_PRIV 13
-#define INT_GPIO_BANK1 14
-#define INT_UART3 15
-#define INT_TIMER3 16
-#define INT_DMA_CH0_6 19
-#define INT_DMA_CH1_7 20
-#define INT_DMA_CH2_8 21
-#define INT_DMA_CH3 22
-#define INT_DMA_CH4 23
-#define INT_DMA_CH5 24
-#define INT_TIMER1 26
-#define INT_WD_TIMER 27
-#define INT_BRIDGE_PUB 28
-#define INT_TIMER2 30
-#define INT_LCD_CTRL 31
+#define INT_CAMERA (NR_IRQS_LEGACY + 1)
+#define INT_FIQ (NR_IRQS_LEGACY + 3)
+#define INT_RTDX (NR_IRQS_LEGACY + 6)
+#define INT_DSP_MMU_ABORT (NR_IRQS_LEGACY + 7)
+#define INT_HOST (NR_IRQS_LEGACY + 8)
+#define INT_ABORT (NR_IRQS_LEGACY + 9)
+#define INT_BRIDGE_PRIV (NR_IRQS_LEGACY + 13)
+#define INT_GPIO_BANK1 (NR_IRQS_LEGACY + 14)
+#define INT_UART3 (NR_IRQS_LEGACY + 15)
+#define INT_TIMER3 (NR_IRQS_LEGACY + 16)
+#define INT_DMA_CH0_6 (NR_IRQS_LEGACY + 19)
+#define INT_DMA_CH1_7 (NR_IRQS_LEGACY + 20)
+#define INT_DMA_CH2_8 (NR_IRQS_LEGACY + 21)
+#define INT_DMA_CH3 (NR_IRQS_LEGACY + 22)
+#define INT_DMA_CH4 (NR_IRQS_LEGACY + 23)
+#define INT_DMA_CH5 (NR_IRQS_LEGACY + 24)
+#define INT_TIMER1 (NR_IRQS_LEGACY + 26)
+#define INT_WD_TIMER (NR_IRQS_LEGACY + 27)
+#define INT_BRIDGE_PUB (NR_IRQS_LEGACY + 28)
+#define INT_TIMER2 (NR_IRQS_LEGACY + 30)
+#define INT_LCD_CTRL (NR_IRQS_LEGACY + 31)
/*
* OMAP-1510 specific IRQ numbers for interrupt handler 1
*/
-#define INT_1510_IH2_IRQ 0
-#define INT_1510_RES2 2
-#define INT_1510_SPI_TX 4
-#define INT_1510_SPI_RX 5
-#define INT_1510_DSP_MAILBOX1 10
-#define INT_1510_DSP_MAILBOX2 11
-#define INT_1510_RES12 12
-#define INT_1510_LB_MMU 17
-#define INT_1510_RES18 18
-#define INT_1510_LOCAL_BUS 29
+#define INT_1510_IH2_IRQ (NR_IRQS_LEGACY + 0)
+#define INT_1510_RES2 (NR_IRQS_LEGACY + 2)
+#define INT_1510_SPI_TX (NR_IRQS_LEGACY + 4)
+#define INT_1510_SPI_RX (NR_IRQS_LEGACY + 5)
+#define INT_1510_DSP_MAILBOX1 (NR_IRQS_LEGACY + 10)
+#define INT_1510_DSP_MAILBOX2 (NR_IRQS_LEGACY + 11)
+#define INT_1510_RES12 (NR_IRQS_LEGACY + 12)
+#define INT_1510_LB_MMU (NR_IRQS_LEGACY + 17)
+#define INT_1510_RES18 (NR_IRQS_LEGACY + 18)
+#define INT_1510_LOCAL_BUS (NR_IRQS_LEGACY + 29)
/*
* OMAP-1610 specific IRQ numbers for interrupt handler 1
*/
#define INT_1610_IH2_IRQ INT_1510_IH2_IRQ
-#define INT_1610_IH2_FIQ 2
-#define INT_1610_McBSP2_TX 4
-#define INT_1610_McBSP2_RX 5
-#define INT_1610_DSP_MAILBOX1 10
-#define INT_1610_DSP_MAILBOX2 11
-#define INT_1610_LCD_LINE 12
-#define INT_1610_GPTIMER1 17
-#define INT_1610_GPTIMER2 18
-#define INT_1610_SSR_FIFO_0 29
+#define INT_1610_IH2_FIQ (NR_IRQS_LEGACY + 2)
+#define INT_1610_McBSP2_TX (NR_IRQS_LEGACY + 4)
+#define INT_1610_McBSP2_RX (NR_IRQS_LEGACY + 5)
+#define INT_1610_DSP_MAILBOX1 (NR_IRQS_LEGACY + 10)
+#define INT_1610_DSP_MAILBOX2 (NR_IRQS_LEGACY + 11)
+#define INT_1610_LCD_LINE (NR_IRQS_LEGACY + 12)
+#define INT_1610_GPTIMER1 (NR_IRQS_LEGACY + 17)
+#define INT_1610_GPTIMER2 (NR_IRQS_LEGACY + 18)
+#define INT_1610_SSR_FIFO_0 (NR_IRQS_LEGACY + 29)
/*
* OMAP-7xx specific IRQ numbers for interrupt handler 1
*/
-#define INT_7XX_IH2_FIQ 0
-#define INT_7XX_IH2_IRQ 1
-#define INT_7XX_USB_NON_ISO 2
-#define INT_7XX_USB_ISO 3
-#define INT_7XX_ICR 4
-#define INT_7XX_EAC 5
-#define INT_7XX_GPIO_BANK1 6
-#define INT_7XX_GPIO_BANK2 7
-#define INT_7XX_GPIO_BANK3 8
-#define INT_7XX_McBSP2TX 10
-#define INT_7XX_McBSP2RX 11
-#define INT_7XX_McBSP2RX_OVF 12
-#define INT_7XX_LCD_LINE 14
-#define INT_7XX_GSM_PROTECT 15
-#define INT_7XX_TIMER3 16
-#define INT_7XX_GPIO_BANK5 17
-#define INT_7XX_GPIO_BANK6 18
-#define INT_7XX_SPGIO_WR 29
+#define INT_7XX_IH2_FIQ (NR_IRQS_LEGACY + 0)
+#define INT_7XX_IH2_IRQ (NR_IRQS_LEGACY + 1)
+#define INT_7XX_USB_NON_ISO (NR_IRQS_LEGACY + 2)
+#define INT_7XX_USB_ISO (NR_IRQS_LEGACY + 3)
+#define INT_7XX_ICR (NR_IRQS_LEGACY + 4)
+#define INT_7XX_EAC (NR_IRQS_LEGACY + 5)
+#define INT_7XX_GPIO_BANK1 (NR_IRQS_LEGACY + 6)
+#define INT_7XX_GPIO_BANK2 (NR_IRQS_LEGACY + 7)
+#define INT_7XX_GPIO_BANK3 (NR_IRQS_LEGACY + 8)
+#define INT_7XX_McBSP2TX (NR_IRQS_LEGACY + 10)
+#define INT_7XX_McBSP2RX (NR_IRQS_LEGACY + 11)
+#define INT_7XX_McBSP2RX_OVF (NR_IRQS_LEGACY + 12)
+#define INT_7XX_LCD_LINE (NR_IRQS_LEGACY + 14)
+#define INT_7XX_GSM_PROTECT (NR_IRQS_LEGACY + 15)
+#define INT_7XX_TIMER3 (NR_IRQS_LEGACY + 16)
+#define INT_7XX_GPIO_BANK5 (NR_IRQS_LEGACY + 17)
+#define INT_7XX_GPIO_BANK6 (NR_IRQS_LEGACY + 18)
+#define INT_7XX_SPGIO_WR (NR_IRQS_LEGACY + 29)
/*
* IRQ numbers for interrupt handler 2
*
* NOTE: See also the OMAP-1510 and 1610 specific IRQ numbers below
*/
-#define IH2_BASE 32
+#define IH2_BASE (NR_IRQS_LEGACY + 32)
#define INT_KEYBOARD (1 + IH2_BASE)
#define INT_uWireTX (2 + IH2_BASE)
@@ -255,11 +255,7 @@
#endif
#define OMAP_FPGA_IRQ_END (OMAP_FPGA_IRQ_BASE + OMAP_FPGA_NR_IRQS)
-#define NR_IRQS OMAP_FPGA_IRQ_END
-
-#define OMAP_IRQ_BIT(irq) (1 << ((irq) % 32))
-
-#include <mach/hardware.h>
+#define OMAP_IRQ_BIT(irq) (1 << ((irq - NR_IRQS_LEGACY) % 32))
#ifdef CONFIG_FIQ
#define FIQ_START 1024
diff --git a/arch/arm/mach-omap1/include/mach/memory.h b/arch/arm/mach-omap1/include/mach/memory.h
index 058a4f7d44c5..d43ff0f1cbf8 100644
--- a/arch/arm/mach-omap1/include/mach/memory.h
+++ b/arch/arm/mach-omap1/include/mach/memory.h
@@ -5,6 +5,9 @@
#ifndef __ASM_ARCH_MEMORY_H
#define __ASM_ARCH_MEMORY_H
+/* REVISIT: omap1 legacy drivers still rely on this */
+#include <mach/soc.h>
+
/*
* Bus address is physical address, except for OMAP-1510 Local Bus.
* OMAP-1510 bus address is translated into a Local Bus address if the
@@ -14,7 +17,6 @@
* because of the strncmp().
*/
#if defined(CONFIG_ARCH_OMAP15XX) && !defined(__ASSEMBLER__)
-#include <mach/soc.h>
/*
* OMAP-1510 Local Bus address offset
diff --git a/arch/arm/mach-omap1/include/mach/serial.h b/arch/arm/mach-omap1/include/mach/serial.h
index 2ce6a2db470b..4700e384c3d9 100644
--- a/arch/arm/mach-omap1/include/mach/serial.h
+++ b/arch/arm/mach-omap1/include/mach/serial.h
@@ -27,11 +27,6 @@
*/
#define OMAP_UART_INFO_OFS 0x3ffc
-/* OMAP1 serial ports */
-#define OMAP1_UART1_BASE 0xfffb0000
-#define OMAP1_UART2_BASE 0xfffb0800
-#define OMAP1_UART3_BASE 0xfffb9800
-
#define OMAP_PORT_SHIFT 2
#define OMAP7XX_PORT_SHIFT 0
diff --git a/arch/arm/mach-omap1/include/mach/soc.h b/arch/arm/mach-omap1/include/mach/soc.h
index 612bd1cc257c..3d935570eb3b 100644
--- a/arch/arm/mach-omap1/include/mach/soc.h
+++ b/arch/arm/mach-omap1/include/mach/soc.h
@@ -28,6 +28,10 @@
#ifndef __ASM_ARCH_OMAP_CPU_H
#define __ASM_ARCH_OMAP_CPU_H
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
#ifndef __ASSEMBLY__
#include <linux/bitops.h>
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index a8a533df24e1..f4d346fda9da 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -43,6 +43,7 @@
#include <linux/io.h>
#include <asm/irq.h>
+#include <asm/exception.h>
#include <asm/mach/irq.h>
#include "soc.h"
@@ -56,66 +57,41 @@
struct omap_irq_bank {
unsigned long base_reg;
+ void __iomem *va;
unsigned long trigger_map;
unsigned long wake_enable;
};
-u32 omap_irq_flags;
+static u32 omap_l2_irq;
static unsigned int irq_bank_count;
static struct omap_irq_bank *irq_banks;
+static struct irq_domain *domain;
-static inline void irq_bank_writel(unsigned long value, int bank, int offset)
-{
- omap_writel(value, irq_banks[bank].base_reg + offset);
-}
-
-static void omap_ack_irq(struct irq_data *d)
+static inline unsigned int irq_bank_readl(int bank, int offset)
{
- if (d->irq > 31)
- omap_writel(0x1, OMAP_IH2_BASE + IRQ_CONTROL_REG_OFFSET);
-
- omap_writel(0x1, OMAP_IH1_BASE + IRQ_CONTROL_REG_OFFSET);
+ return readl_relaxed(irq_banks[bank].va + offset);
}
-
-static void omap_mask_irq(struct irq_data *d)
+static inline void irq_bank_writel(unsigned long value, int bank, int offset)
{
- int bank = IRQ_BANK(d->irq);
- u32 l;
-
- l = omap_readl(irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET);
- l |= 1 << IRQ_BIT(d->irq);
- omap_writel(l, irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET);
+ writel_relaxed(value, irq_banks[bank].va + offset);
}
-static void omap_unmask_irq(struct irq_data *d)
+static void omap_ack_irq(int irq)
{
- int bank = IRQ_BANK(d->irq);
- u32 l;
+ if (irq > 31)
+ writel_relaxed(0x1, irq_banks[1].va + IRQ_CONTROL_REG_OFFSET);
- l = omap_readl(irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET);
- l &= ~(1 << IRQ_BIT(d->irq));
- omap_writel(l, irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET);
+ writel_relaxed(0x1, irq_banks[0].va + IRQ_CONTROL_REG_OFFSET);
}
static void omap_mask_ack_irq(struct irq_data *d)
{
- omap_mask_irq(d);
- omap_ack_irq(d);
-}
-
-static int omap_wake_irq(struct irq_data *d, unsigned int enable)
-{
- int bank = IRQ_BANK(d->irq);
-
- if (enable)
- irq_banks[bank].wake_enable |= IRQ_BIT(d->irq);
- else
- irq_banks[bank].wake_enable &= ~IRQ_BIT(d->irq);
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
- return 0;
+ ct->chip.irq_mask(d);
+ omap_ack_irq(d->irq);
}
-
/*
* Allows tuning the IRQ type and priority
*
@@ -165,46 +141,105 @@ static struct omap_irq_bank omap1610_irq_banks[] = {
};
#endif
-static struct irq_chip omap_irq_chip = {
- .name = "MPU",
- .irq_ack = omap_mask_ack_irq,
- .irq_mask = omap_mask_irq,
- .irq_unmask = omap_unmask_irq,
- .irq_set_wake = omap_wake_irq,
-};
+asmlinkage void __exception_irq_entry omap1_handle_irq(struct pt_regs *regs)
+{
+ void __iomem *l1 = irq_banks[0].va;
+ void __iomem *l2 = irq_banks[1].va;
+ u32 irqnr;
+
+ do {
+ irqnr = readl_relaxed(l1 + IRQ_ITR_REG_OFFSET);
+ irqnr &= ~(readl_relaxed(l1 + IRQ_MIR_REG_OFFSET) & 0xffffffff);
+ if (!irqnr)
+ break;
+
+ irqnr = readl_relaxed(l1 + IRQ_SIR_FIQ_REG_OFFSET);
+ if (irqnr)
+ goto irq;
+
+ irqnr = readl_relaxed(l1 + IRQ_SIR_IRQ_REG_OFFSET);
+ if (irqnr == omap_l2_irq) {
+ irqnr = readl_relaxed(l2 + IRQ_SIR_IRQ_REG_OFFSET);
+ if (irqnr)
+ irqnr += 32;
+ }
+irq:
+ if (irqnr)
+ handle_domain_irq(domain, irqnr, regs);
+ else
+ break;
+ } while (irqnr);
+}
+
+static __init void
+omap_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
+{
+ struct irq_chip_generic *gc;
+ struct irq_chip_type *ct;
+
+ gc = irq_alloc_generic_chip("MPU", 1, irq_start, base,
+ handle_level_irq);
+ ct = gc->chip_types;
+ ct->chip.irq_ack = omap_mask_ack_irq;
+ ct->chip.irq_mask = irq_gc_mask_set_bit;
+ ct->chip.irq_unmask = irq_gc_mask_clr_bit;
+ ct->chip.irq_set_wake = irq_gc_set_wake;
+ ct->regs.mask = IRQ_MIR_REG_OFFSET;
+ irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
+ IRQ_NOREQUEST | IRQ_NOPROBE, 0);
+}
void __init omap1_init_irq(void)
{
- int i, j;
+ struct irq_chip_type *ct;
+ struct irq_data *d = NULL;
+ int i, j, irq_base;
+ unsigned long nr_irqs;
#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
if (cpu_is_omap7xx()) {
- omap_irq_flags = INT_7XX_IH2_IRQ;
irq_banks = omap7xx_irq_banks;
irq_bank_count = ARRAY_SIZE(omap7xx_irq_banks);
}
#endif
#ifdef CONFIG_ARCH_OMAP15XX
if (cpu_is_omap1510()) {
- omap_irq_flags = INT_1510_IH2_IRQ;
irq_banks = omap1510_irq_banks;
irq_bank_count = ARRAY_SIZE(omap1510_irq_banks);
}
if (cpu_is_omap310()) {
- omap_irq_flags = INT_1510_IH2_IRQ;
irq_banks = omap310_irq_banks;
irq_bank_count = ARRAY_SIZE(omap310_irq_banks);
}
#endif
#if defined(CONFIG_ARCH_OMAP16XX)
if (cpu_is_omap16xx()) {
- omap_irq_flags = INT_1510_IH2_IRQ;
irq_banks = omap1610_irq_banks;
irq_bank_count = ARRAY_SIZE(omap1610_irq_banks);
}
#endif
- printk("Total of %i interrupts in %i interrupt banks\n",
- irq_bank_count * 32, irq_bank_count);
+
+ for (i = 0; i < irq_bank_count; i++) {
+ irq_banks[i].va = ioremap(irq_banks[i].base_reg, 0xff);
+ if (WARN_ON(!irq_banks[i].va))
+ return;
+ }
+
+ nr_irqs = irq_bank_count * 32;
+
+ irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+ if (irq_base < 0) {
+ pr_warn("Couldn't allocate IRQ numbers\n");
+ irq_base = 0;
+ }
+ omap_l2_irq = cpu_is_omap7xx() ? irq_base + 1 : irq_base;
+ omap_l2_irq -= NR_IRQS_LEGACY;
+
+ domain = irq_domain_add_legacy(NULL, nr_irqs, irq_base, 0,
+ &irq_domain_simple_ops, NULL);
+
+ pr_info("Total of %lu interrupts in %i interrupt banks\n",
+ nr_irqs, irq_bank_count);
/* Mask and clear all interrupts */
for (i = 0; i < irq_bank_count; i++) {
@@ -227,19 +262,15 @@ void __init omap1_init_irq(void)
irq_trigger = irq_banks[i].trigger_map >> IRQ_BIT(j);
omap_irq_set_cfg(j, 0, 0, irq_trigger);
-
- irq_set_chip_and_handler(j, &omap_irq_chip,
- handle_level_irq);
set_irq_flags(j, IRQF_VALID);
}
+ omap_alloc_gc(irq_banks[i].va, irq_base + i * 32, 32);
}
/* Unmask level 2 handler */
-
- if (cpu_is_omap7xx())
- omap_unmask_irq(irq_get_irq_data(INT_7XX_IH2_IRQ));
- else if (cpu_is_omap15xx())
- omap_unmask_irq(irq_get_irq_data(INT_1510_IH2_IRQ));
- else if (cpu_is_omap16xx())
- omap_unmask_irq(irq_get_irq_data(INT_1610_IH2_IRQ));
+ d = irq_get_irq_data(irq_find_mapping(domain, omap_l2_irq));
+ if (d) {
+ ct = irq_data_get_chip_type(d);
+ ct->chip.irq_unmask(d);
+ }
}
diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c
index 667ce5027f63..599490a596a7 100644
--- a/arch/arm/mach-omap1/mux.c
+++ b/arch/arm/mach-omap1/mux.c
@@ -36,7 +36,7 @@
static struct omap_mux_cfg arch_mux_cfg;
#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
-static struct pin_config __initdata_or_module omap7xx_pins[] = {
+static struct pin_config omap7xx_pins[] = {
MUX_CFG_7XX("E2_7XX_KBR0", 12, 21, 0, 20, 1, 0)
MUX_CFG_7XX("J7_7XX_KBR1", 12, 25, 0, 24, 1, 0)
MUX_CFG_7XX("E1_7XX_KBR2", 12, 29, 0, 28, 1, 0)
@@ -82,7 +82,7 @@ MUX_CFG_7XX("UART_7XX_2", 8, 1, 6, 0, 0, 0)
#endif /* CONFIG_ARCH_OMAP730 || CONFIG_ARCH_OMAP850 */
#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
-static struct pin_config __initdata_or_module omap1xxx_pins[] = {
+static struct pin_config omap1xxx_pins[] = {
/*
* description mux mode mux pull pull pull pu_pd pu dbg
* reg offset mode reg bit ena reg
@@ -343,7 +343,7 @@ MUX_CFG("Y14_1610_CCP_DATAM", 9, 21, 6, 2, 3, 1, 2, 0, 0)
#define OMAP1XXX_PINS_SZ 0
#endif /* CONFIG_ARCH_OMAP15XX || CONFIG_ARCH_OMAP16XX */
-static int __init_or_module omap1_cfg_reg(const struct pin_config *cfg)
+static int omap1_cfg_reg(const struct pin_config *cfg)
{
static DEFINE_SPINLOCK(mux_spin_lock);
unsigned long flags;
@@ -469,7 +469,7 @@ int __init omap_mux_register(struct omap_mux_cfg *arch_mux_cfg)
/*
* Sets the Omap MUX and PULL_DWN registers based on the table
*/
-int __init_or_module omap_cfg_reg(const unsigned long index)
+int omap_cfg_reg(const unsigned long index)
{
struct pin_config *reg;
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index dd94567c3628..ee5460b8ec2e 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -62,6 +62,7 @@
#include "iomap.h"
#include "clock.h"
#include "pm.h"
+#include "soc.h"
#include "sram.h"
static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
diff --git a/arch/arm/mach-omap1/pm_bus.c b/arch/arm/mach-omap1/pm_bus.c
index c40e209de65c..667c1637ff91 100644
--- a/arch/arm/mach-omap1/pm_bus.c
+++ b/arch/arm/mach-omap1/pm_bus.c
@@ -21,48 +21,15 @@
#include "soc.h"
-#ifdef CONFIG_PM
-static int omap1_pm_runtime_suspend(struct device *dev)
-{
- int ret;
-
- dev_dbg(dev, "%s\n", __func__);
-
- ret = pm_generic_runtime_suspend(dev);
- if (ret)
- return ret;
-
- ret = pm_clk_suspend(dev);
- if (ret) {
- pm_generic_runtime_resume(dev);
- return ret;
- }
-
- return 0;
-}
-
-static int omap1_pm_runtime_resume(struct device *dev)
-{
- dev_dbg(dev, "%s\n", __func__);
-
- pm_clk_resume(dev);
- return pm_generic_runtime_resume(dev);
-}
-
static struct dev_pm_domain default_pm_domain = {
.ops = {
- .runtime_suspend = omap1_pm_runtime_suspend,
- .runtime_resume = omap1_pm_runtime_resume,
+ USE_PM_CLK_RUNTIME_OPS
USE_PLATFORM_PM_SLEEP_OPS
},
};
-#define OMAP1_PM_DOMAIN (&default_pm_domain)
-#else
-#define OMAP1_PM_DOMAIN NULL
-#endif /* CONFIG_PM */
static struct pm_clk_notifier_block platform_bus_notifier = {
- .pm_domain = OMAP1_PM_DOMAIN,
+ .pm_domain = &default_pm_domain,
.con_ids = { "ick", "fck", NULL, },
};
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
index d1ac08016f0b..a65bd0c44296 100644
--- a/arch/arm/mach-omap1/serial.c
+++ b/arch/arm/mach-omap1/serial.c
@@ -25,6 +25,7 @@
#include <mach/mux.h>
#include "pm.h"
+#include "soc.h"
static struct clk * uart1_ck;
static struct clk * uart2_ck;
diff --git a/arch/arm/mach-omap1/timer.c b/arch/arm/mach-omap1/timer.c
index bde7a35e5000..06c5ba7574a5 100644
--- a/arch/arm/mach-omap1/timer.c
+++ b/arch/arm/mach-omap1/timer.c
@@ -27,10 +27,10 @@
#include <linux/platform_device.h>
#include <linux/platform_data/dmtimer-omap.h>
-#include <mach/irqs.h>
-
#include <plat/dmtimer.h>
+#include "soc.h"
+
#define OMAP1610_GPTIMER1_BASE 0xfffb1400
#define OMAP1610_GPTIMER2_BASE 0xfffb1c00
#define OMAP1610_GPTIMER3_BASE 0xfffb2400
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 6468f15f060c..ecc04ff13e95 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -171,12 +171,6 @@ config MACH_OMAP2_TUSB6010
depends on ARCH_OMAP2 && SOC_OMAP2420
default y if MACH_NOKIA_N8X0
-config MACH_OMAP3_BEAGLE
- bool "OMAP3 BEAGLE board"
- depends on ARCH_OMAP3
- default y
- select OMAP_PACKAGE_CBB
-
config MACH_OMAP_LDP
bool "OMAP3 LDP board"
depends on ARCH_OMAP3
@@ -203,12 +197,6 @@ config MACH_OMAP3_TORPEDO
for full description please see the products webpage at
http://www.logicpd.com/products/development-kits/zoom-omap35x-torpedo-development-kit
-config MACH_OVERO
- bool "Gumstix Overo board"
- depends on ARCH_OMAP3
- default y
- select OMAP_PACKAGE_CBB
-
config MACH_OMAP3517EVM
bool "OMAP3517/ AM3517 EVM board"
depends on ARCH_OMAP3
@@ -240,16 +228,6 @@ config MACH_NOKIA_RX51
default y
select OMAP_PACKAGE_CBB
-config MACH_CM_T35
- bool "CompuLab CM-T35/CM-T3730 modules"
- depends on ARCH_OMAP3
- default y
- select MACH_CM_T3730
- select OMAP_PACKAGE_CUS
-
-config MACH_CM_T3730
- bool
-
config OMAP3_SDRC_AC_TIMING
bool "Enable SDRC AC timing register changes"
depends on ARCH_OMAP3
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index ec002bd4af77..f1a68c63dc99 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -242,17 +242,14 @@ obj-$(CONFIG_SOC_OMAP2420) += msdi.o
# Specific board support
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o pdata-quirks.o
-obj-$(CONFIG_MACH_OMAP3_BEAGLE) += board-omap3beagle.o
obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o
obj-$(CONFIG_MACH_OMAP3530_LV_SOM) += board-omap3logic.o
obj-$(CONFIG_MACH_OMAP3_TORPEDO) += board-omap3logic.o
-obj-$(CONFIG_MACH_OVERO) += board-overo.o
obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o
obj-$(CONFIG_MACH_NOKIA_N8X0) += board-n8x0.o
obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o sdram-nokia.o
obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51-peripherals.o
obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51-video.o
-obj-$(CONFIG_MACH_CM_T35) += board-cm-t35.o
# Platform specific device init code
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
deleted file mode 100644
index b5dfbc1b1fc6..000000000000
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ /dev/null
@@ -1,769 +0,0 @@
-/*
- * CompuLab CM-T35/CM-T3730 modules support
- *
- * Copyright (C) 2009-2011 CompuLab, Ltd.
- * Authors: Mike Rapoport <mike@compulab.co.il>
- * Igor Grinberg <grinberg@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.
- *
- * 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/clkdev.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/input.h>
-#include <linux/input/matrix_keypad.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/omap-gpmc.h>
-#include <linux/platform_data/gpio-omap.h>
-
-#include <linux/platform_data/at24.h>
-#include <linux/i2c/twl.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/machine.h>
-#include <linux/mmc/host.h>
-#include <linux/usb/phy.h>
-
-#include <linux/spi/spi.h>
-#include <linux/spi/tdo24m.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <linux/platform_data/mtd-nand-omap2.h>
-#include <video/omapdss.h>
-#include <video/omap-panel-data.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
-
-#include "common.h"
-#include "mux.h"
-#include "sdram-micron-mt46h32m32lf-6.h"
-#include "hsmmc.h"
-#include "common-board-devices.h"
-
-#define CM_T35_GPIO_PENDOWN 57
-#define SB_T35_USB_HUB_RESET_GPIO 167
-
-#define CM_T35_SMSC911X_CS 5
-#define CM_T35_SMSC911X_GPIO 163
-#define SB_T35_SMSC911X_CS 4
-#define SB_T35_SMSC911X_GPIO 65
-
-#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
-#include <linux/smsc911x.h>
-#include "gpmc-smsc911x.h"
-
-static struct omap_smsc911x_platform_data cm_t35_smsc911x_cfg = {
- .id = 0,
- .cs = CM_T35_SMSC911X_CS,
- .gpio_irq = CM_T35_SMSC911X_GPIO,
- .gpio_reset = -EINVAL,
- .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
-};
-
-static struct omap_smsc911x_platform_data sb_t35_smsc911x_cfg = {
- .id = 1,
- .cs = SB_T35_SMSC911X_CS,
- .gpio_irq = SB_T35_SMSC911X_GPIO,
- .gpio_reset = -EINVAL,
- .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
-};
-
-static struct regulator_consumer_supply cm_t35_smsc911x_supplies[] = {
- REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
- REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
-};
-
-static struct regulator_consumer_supply sb_t35_smsc911x_supplies[] = {
- REGULATOR_SUPPLY("vddvario", "smsc911x.1"),
- REGULATOR_SUPPLY("vdd33a", "smsc911x.1"),
-};
-
-static void __init cm_t35_init_ethernet(void)
-{
- regulator_register_fixed(0, cm_t35_smsc911x_supplies,
- ARRAY_SIZE(cm_t35_smsc911x_supplies));
- regulator_register_fixed(1, sb_t35_smsc911x_supplies,
- ARRAY_SIZE(sb_t35_smsc911x_supplies));
-
- gpmc_smsc911x_init(&cm_t35_smsc911x_cfg);
- gpmc_smsc911x_init(&sb_t35_smsc911x_cfg);
-}
-#else
-static inline void __init cm_t35_init_ethernet(void) { return; }
-#endif
-
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
-#include <linux/leds.h>
-
-static struct gpio_led cm_t35_leds[] = {
- [0] = {
- .gpio = 186,
- .name = "cm-t35:green",
- .default_trigger = "heartbeat",
- .active_low = 0,
- },
-};
-
-static struct gpio_led_platform_data cm_t35_led_pdata = {
- .num_leds = ARRAY_SIZE(cm_t35_leds),
- .leds = cm_t35_leds,
-};
-
-static struct platform_device cm_t35_led_device = {
- .name = "leds-gpio",
- .id = -1,
- .dev = {
- .platform_data = &cm_t35_led_pdata,
- },
-};
-
-static void __init cm_t35_init_led(void)
-{
- platform_device_register(&cm_t35_led_device);
-}
-#else
-static inline void cm_t35_init_led(void) {}
-#endif
-
-#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
-
-static struct mtd_partition cm_t35_nand_partitions[] = {
- {
- .name = "xloader",
- .offset = 0, /* Offset = 0x00000 */
- .size = 4 * NAND_BLOCK_SIZE,
- .mask_flags = MTD_WRITEABLE
- },
- {
- .name = "uboot",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */
- .size = 15 * NAND_BLOCK_SIZE,
- },
- {
- .name = "uboot environment",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x260000 */
- .size = 2 * NAND_BLOCK_SIZE,
- },
- {
- .name = "linux",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x2A0000 */
- .size = 32 * NAND_BLOCK_SIZE,
- },
- {
- .name = "rootfs",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x6A0000 */
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct omap_nand_platform_data cm_t35_nand_data = {
- .parts = cm_t35_nand_partitions,
- .nr_parts = ARRAY_SIZE(cm_t35_nand_partitions),
- .cs = 0,
-};
-
-static void __init cm_t35_init_nand(void)
-{
- if (gpmc_nand_init(&cm_t35_nand_data, NULL) < 0)
- pr_err("CM-T35: Unable to register NAND device\n");
-}
-#else
-static inline void cm_t35_init_nand(void) {}
-#endif
-
-#define CM_T35_LCD_EN_GPIO 157
-#define CM_T35_LCD_BL_GPIO 58
-#define CM_T35_DVI_EN_GPIO 54
-
-static const struct display_timing cm_t35_lcd_videomode = {
- .pixelclock = { 0, 26000000, 0 },
-
- .hactive = { 0, 480, 0 },
- .hfront_porch = { 0, 104, 0 },
- .hback_porch = { 0, 8, 0 },
- .hsync_len = { 0, 8, 0 },
-
- .vactive = { 0, 640, 0 },
- .vfront_porch = { 0, 4, 0 },
- .vback_porch = { 0, 2, 0 },
- .vsync_len = { 0, 2, 0 },
-
- .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
- DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_NEGEDGE,
-};
-
-static struct panel_dpi_platform_data cm_t35_lcd_pdata = {
- .name = "lcd",
- .source = "dpi.0",
-
- .data_lines = 18,
-
- .display_timing = &cm_t35_lcd_videomode,
-
- .enable_gpio = -1,
- .backlight_gpio = CM_T35_LCD_BL_GPIO,
-};
-
-static struct platform_device cm_t35_lcd_device = {
- .name = "panel-dpi",
- .id = 0,
- .dev.platform_data = &cm_t35_lcd_pdata,
-};
-
-static struct connector_dvi_platform_data cm_t35_dvi_connector_pdata = {
- .name = "dvi",
- .source = "tfp410.0",
- .i2c_bus_num = -1,
-};
-
-static struct platform_device cm_t35_dvi_connector_device = {
- .name = "connector-dvi",
- .id = 0,
- .dev.platform_data = &cm_t35_dvi_connector_pdata,
-};
-
-static struct encoder_tfp410_platform_data cm_t35_tfp410_pdata = {
- .name = "tfp410.0",
- .source = "dpi.0",
- .data_lines = 24,
- .power_down_gpio = CM_T35_DVI_EN_GPIO,
-};
-
-static struct platform_device cm_t35_tfp410_device = {
- .name = "tfp410",
- .id = 0,
- .dev.platform_data = &cm_t35_tfp410_pdata,
-};
-
-static struct connector_atv_platform_data cm_t35_tv_pdata = {
- .name = "tv",
- .source = "venc.0",
- .connector_type = OMAP_DSS_VENC_TYPE_SVIDEO,
- .invert_polarity = false,
-};
-
-static struct platform_device cm_t35_tv_connector_device = {
- .name = "connector-analog-tv",
- .id = 0,
- .dev.platform_data = &cm_t35_tv_pdata,
-};
-
-static struct omap_dss_board_info cm_t35_dss_data = {
- .default_display_name = "dvi",
-};
-
-static struct omap2_mcspi_device_config tdo24m_mcspi_config = {
- .turbo_mode = 0,
-};
-
-static struct tdo24m_platform_data tdo24m_config = {
- .model = TDO35S,
-};
-
-static struct spi_board_info cm_t35_lcd_spi_board_info[] __initdata = {
- {
- .modalias = "tdo24m",
- .bus_num = 4,
- .chip_select = 0,
- .max_speed_hz = 1000000,
- .controller_data = &tdo24m_mcspi_config,
- .platform_data = &tdo24m_config,
- },
-};
-
-static void __init cm_t35_init_display(void)
-{
- int err;
-
- spi_register_board_info(cm_t35_lcd_spi_board_info,
- ARRAY_SIZE(cm_t35_lcd_spi_board_info));
-
-
- err = gpio_request_one(CM_T35_LCD_EN_GPIO, GPIOF_OUT_INIT_LOW,
- "lcd bl enable");
- if (err) {
- pr_err("CM-T35: failed to request LCD EN GPIO\n");
- return;
- }
-
- msleep(50);
- gpio_set_value(CM_T35_LCD_EN_GPIO, 1);
-
- err = omap_display_init(&cm_t35_dss_data);
- if (err) {
- pr_err("CM-T35: failed to register DSS device\n");
- gpio_free(CM_T35_LCD_EN_GPIO);
- }
-
- platform_device_register(&cm_t35_tfp410_device);
- platform_device_register(&cm_t35_dvi_connector_device);
- platform_device_register(&cm_t35_lcd_device);
- platform_device_register(&cm_t35_tv_connector_device);
-}
-
-static struct regulator_consumer_supply cm_t35_vmmc1_supply[] = {
- REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
-};
-
-static struct regulator_consumer_supply cm_t35_vsim_supply[] = {
- REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"),
-};
-
-static struct regulator_consumer_supply cm_t35_vio_supplies[] = {
- REGULATOR_SUPPLY("vcc", "spi1.0"),
- REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
- REGULATOR_SUPPLY("vdds_dsi", "omapdss_dpi.0"),
- REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi.0"),
-};
-
-/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
-static struct regulator_init_data cm_t35_vmmc1 = {
- .constraints = {
- .min_uV = 1850000,
- .max_uV = 3150000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(cm_t35_vmmc1_supply),
- .consumer_supplies = cm_t35_vmmc1_supply,
-};
-
-/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */
-static struct regulator_init_data cm_t35_vsim = {
- .constraints = {
- .min_uV = 1800000,
- .max_uV = 3000000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(cm_t35_vsim_supply),
- .consumer_supplies = cm_t35_vsim_supply,
-};
-
-static struct regulator_init_data cm_t35_vio = {
- .constraints = {
- .min_uV = 1800000,
- .max_uV = 1800000,
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE,
- },
- .num_consumer_supplies = ARRAY_SIZE(cm_t35_vio_supplies),
- .consumer_supplies = cm_t35_vio_supplies,
-};
-
-static uint32_t cm_t35_keymap[] = {
- KEY(0, 0, KEY_A), KEY(0, 1, KEY_B), KEY(0, 2, KEY_LEFT),
- KEY(1, 0, KEY_UP), KEY(1, 1, KEY_ENTER), KEY(1, 2, KEY_DOWN),
- KEY(2, 0, KEY_RIGHT), KEY(2, 1, KEY_C), KEY(2, 2, KEY_D),
-};
-
-static struct matrix_keymap_data cm_t35_keymap_data = {
- .keymap = cm_t35_keymap,
- .keymap_size = ARRAY_SIZE(cm_t35_keymap),
-};
-
-static struct twl4030_keypad_data cm_t35_kp_data = {
- .keymap_data = &cm_t35_keymap_data,
- .rows = 3,
- .cols = 3,
- .rep = 1,
-};
-
-static struct omap2_hsmmc_info mmc[] = {
- {
- .mmc = 1,
- .caps = MMC_CAP_4_BIT_DATA,
- .gpio_cd = -EINVAL,
- .gpio_wp = -EINVAL,
- .deferred = true,
- },
- {
- .mmc = 2,
- .caps = MMC_CAP_4_BIT_DATA,
- .transceiver = 1,
- .gpio_cd = -EINVAL,
- .gpio_wp = -EINVAL,
- .ocr_mask = 0x00100000, /* 3.3V */
- },
- {} /* Terminator */
-};
-
-static struct usbhs_phy_data phy_data[] __initdata = {
- {
- .port = 1,
- .reset_gpio = OMAP_MAX_GPIO_LINES + 6,
- .vcc_gpio = -EINVAL,
- },
- {
- .port = 2,
- .reset_gpio = OMAP_MAX_GPIO_LINES + 7,
- .vcc_gpio = -EINVAL,
- },
-};
-
-static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
- .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
- .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
-};
-
-static void __init cm_t35_init_usbh(void)
-{
- int err;
-
- err = gpio_request_one(SB_T35_USB_HUB_RESET_GPIO,
- GPIOF_OUT_INIT_LOW, "usb hub rst");
- if (err) {
- pr_err("SB-T35: usb hub rst gpio request failed: %d\n", err);
- } else {
- udelay(10);
- gpio_set_value(SB_T35_USB_HUB_RESET_GPIO, 1);
- msleep(1);
- }
-
- usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data));
- usbhs_init(&usbhs_bdata);
-}
-
-static int cm_t35_twl_gpio_setup(struct device *dev, unsigned gpio,
- unsigned ngpio)
-{
- int wlan_rst = gpio + 2;
-
- if (gpio_request_one(wlan_rst, GPIOF_OUT_INIT_HIGH, "WLAN RST") == 0) {
- gpio_export(wlan_rst, 0);
- udelay(10);
- gpio_set_value_cansleep(wlan_rst, 0);
- udelay(10);
- gpio_set_value_cansleep(wlan_rst, 1);
- } else {
- pr_err("CM-T35: could not obtain gpio for WiFi reset\n");
- }
-
- /* gpio + 0 is "mmc0_cd" (input/IRQ) */
- mmc[0].gpio_cd = gpio + 0;
- omap_hsmmc_late_init(mmc);
-
- return 0;
-}
-
-static struct twl4030_gpio_platform_data cm_t35_gpio_data = {
- .setup = cm_t35_twl_gpio_setup,
-};
-
-static struct twl4030_power_data cm_t35_power_data = {
- .use_poweroff = true,
-};
-
-static struct twl4030_platform_data cm_t35_twldata = {
- /* platform_data for children goes here */
- .keypad = &cm_t35_kp_data,
- .gpio = &cm_t35_gpio_data,
- .vmmc1 = &cm_t35_vmmc1,
- .vsim = &cm_t35_vsim,
- .vio = &cm_t35_vio,
- .power = &cm_t35_power_data,
-};
-
-#if defined(CONFIG_VIDEO_OMAP3) || defined(CONFIG_VIDEO_OMAP3_MODULE)
-#include <media/omap3isp.h>
-#include "devices.h"
-
-static struct isp_platform_subdev cm_t35_isp_subdevs[] = {
- {
- .board_info = &(struct i2c_board_info){
- I2C_BOARD_INFO("mt9t001", 0x5d)
- },
- .i2c_adapter_id = 3,
- .bus = &(struct isp_bus_cfg){
- .interface = ISP_INTERFACE_PARALLEL,
- .bus = {
- .parallel = {
- .clk_pol = 1,
- },
- },
- },
- },
- {
- .board_info = &(struct i2c_board_info){
- I2C_BOARD_INFO("tvp5150", 0x5c),
- },
- .i2c_adapter_id = 3,
- .bus = &(struct isp_bus_cfg){
- .interface = ISP_INTERFACE_PARALLEL,
- .bus = {
- .parallel = {
- .clk_pol = 0,
- },
- },
- },
- },
- { 0 },
-};
-
-static struct isp_platform_data cm_t35_isp_pdata = {
- .subdevs = cm_t35_isp_subdevs,
-};
-
-static struct regulator_consumer_supply cm_t35_camera_supplies[] = {
- REGULATOR_SUPPLY("vaa", "3-005d"),
- REGULATOR_SUPPLY("vdd", "3-005d"),
-};
-
-static void __init cm_t35_init_camera(void)
-{
- struct clk *clk;
-
- clk = clk_register_fixed_rate(NULL, "mt9t001-clkin", NULL, CLK_IS_ROOT,
- 48000000);
- clk_register_clkdev(clk, NULL, "3-005d");
-
- regulator_register_fixed(2, cm_t35_camera_supplies,
- ARRAY_SIZE(cm_t35_camera_supplies));
-
- if (omap3_init_camera(&cm_t35_isp_pdata) < 0)
- pr_warn("CM-T3x: Failed registering camera device!\n");
-}
-
-#else
-static inline void cm_t35_init_camera(void) {}
-#endif /* CONFIG_VIDEO_OMAP3 */
-
-static void __init cm_t35_init_i2c(void)
-{
- omap3_pmic_get_config(&cm_t35_twldata, TWL_COMMON_PDATA_USB,
- TWL_COMMON_REGULATOR_VDAC |
- TWL_COMMON_PDATA_AUDIO);
-
- omap3_pmic_init("tps65930", &cm_t35_twldata);
-
- omap_register_i2c_bus(3, 400, NULL, 0);
-}
-
-#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
- /* nCS and IRQ for CM-T35 ethernet */
- OMAP3_MUX(GPMC_NCS5, OMAP_MUX_MODE0),
- OMAP3_MUX(UART3_CTS_RCTX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),
-
- /* nCS and IRQ for SB-T35 ethernet */
- OMAP3_MUX(GPMC_NCS4, OMAP_MUX_MODE0),
- OMAP3_MUX(GPMC_WAIT3, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),
-
- /* PENDOWN GPIO */
- OMAP3_MUX(GPMC_NCS6, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
-
- /* mUSB */
- OMAP3_MUX(HSUSB0_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(HSUSB0_STP, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(HSUSB0_DIR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(HSUSB0_NXT, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(HSUSB0_DATA0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(HSUSB0_DATA1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(HSUSB0_DATA2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(HSUSB0_DATA3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(HSUSB0_DATA4, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(HSUSB0_DATA5, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(HSUSB0_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(HSUSB0_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
-
- /* MMC 2 */
- OMAP3_MUX(SDMMC2_DAT4, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(SDMMC2_DAT5, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(SDMMC2_DAT6, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(SDMMC2_DAT7, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
-
- /* McSPI 1 */
- OMAP3_MUX(MCSPI1_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(MCSPI1_SIMO, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(MCSPI1_SOMI, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(MCSPI1_CS0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
-
- /* McSPI 4 */
- OMAP3_MUX(MCBSP1_CLKR, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
- OMAP3_MUX(MCBSP1_DX, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
- OMAP3_MUX(MCBSP1_DR, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
- OMAP3_MUX(MCBSP1_FSX, OMAP_MUX_MODE1 | OMAP_PIN_INPUT_PULLUP),
-
- /* McBSP 2 */
- OMAP3_MUX(MCBSP2_FSX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(MCBSP2_CLKX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(MCBSP2_DR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(MCBSP2_DX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
-
- /* serial ports */
- OMAP3_MUX(MCBSP3_CLKX, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(MCBSP3_FSX, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
- OMAP3_MUX(UART1_TX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(UART1_RX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
-
- /* common DSS */
- OMAP3_MUX(DSS_PCLK, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_HSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_VSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_ACBIAS, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_DATA8, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_DATA9, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_DATA10, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_DATA11, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_DATA12, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_DATA13, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_DATA14, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_DATA15, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_DATA16, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(DSS_DATA17, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
-
- /* Camera */
- OMAP3_MUX(CAM_HS, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_VS, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_XCLKA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_PCLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_FLD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_D0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_D1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_D2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_D3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_D4, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_D5, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_D6, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_D7, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
- OMAP3_MUX(CAM_D8, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
- OMAP3_MUX(CAM_D9, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
- OMAP3_MUX(CAM_STROBE, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
-
- OMAP3_MUX(CAM_D10, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLDOWN),
- OMAP3_MUX(CAM_D11, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLDOWN),
-
- /* display controls */
- OMAP3_MUX(MCBSP1_FSR, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(GPMC_NCS7, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
- OMAP3_MUX(GPMC_NCS3, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
-
- /* TPS IRQ */
- OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_WAKEUP_EN | \
- OMAP_PIN_INPUT_PULLUP),
-
- { .reg_offset = OMAP_MUX_TERMINATOR },
-};
-
-static void __init cm_t3x_common_dss_mux_init(int mux_mode)
-{
- omap_mux_init_signal("dss_data18", mux_mode);
- omap_mux_init_signal("dss_data19", mux_mode);
- omap_mux_init_signal("dss_data20", mux_mode);
- omap_mux_init_signal("dss_data21", mux_mode);
- omap_mux_init_signal("dss_data22", mux_mode);
- omap_mux_init_signal("dss_data23", mux_mode);
-}
-
-static void __init cm_t35_init_mux(void)
-{
- int mux_mode = OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT;
-
- omap_mux_init_signal("dss_data0.dss_data0", mux_mode);
- omap_mux_init_signal("dss_data1.dss_data1", mux_mode);
- omap_mux_init_signal("dss_data2.dss_data2", mux_mode);
- omap_mux_init_signal("dss_data3.dss_data3", mux_mode);
- omap_mux_init_signal("dss_data4.dss_data4", mux_mode);
- omap_mux_init_signal("dss_data5.dss_data5", mux_mode);
- cm_t3x_common_dss_mux_init(mux_mode);
-}
-
-static void __init cm_t3730_init_mux(void)
-{
- int mux_mode = OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT;
-
- omap_mux_init_signal("sys_boot0", mux_mode);
- omap_mux_init_signal("sys_boot1", mux_mode);
- omap_mux_init_signal("sys_boot3", mux_mode);
- omap_mux_init_signal("sys_boot4", mux_mode);
- omap_mux_init_signal("sys_boot5", mux_mode);
- omap_mux_init_signal("sys_boot6", mux_mode);
- cm_t3x_common_dss_mux_init(mux_mode);
-}
-#else
-static inline void cm_t35_init_mux(void) {}
-static inline void cm_t3730_init_mux(void) {}
-#endif
-
-static void __init cm_t3x_common_init(void)
-{
- omap3_mux_init(board_mux, OMAP_PACKAGE_CUS);
- omap_serial_init();
- omap_sdrc_init(mt46h32m32lf6_sdrc_params,
- mt46h32m32lf6_sdrc_params);
- omap_hsmmc_init(mmc);
- cm_t35_init_i2c();
- omap_ads7846_init(1, CM_T35_GPIO_PENDOWN, 0, NULL);
- cm_t35_init_ethernet();
- cm_t35_init_led();
- cm_t35_init_display();
- omap_twl4030_audio_init("cm-t3x", NULL);
-
- usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
- usb_musb_init(NULL);
- cm_t35_init_usbh();
- cm_t35_init_camera();
-}
-
-static void __init cm_t35_init(void)
-{
- cm_t3x_common_init();
- cm_t35_init_mux();
- cm_t35_init_nand();
-}
-
-static void __init cm_t3730_init(void)
-{
- cm_t3x_common_init();
- cm_t3730_init_mux();
-}
-
-MACHINE_START(CM_T35, "Compulab CM-T35")
- .atag_offset = 0x100,
- .reserve = omap_reserve,
- .map_io = omap3_map_io,
- .init_early = omap35xx_init_early,
- .init_irq = omap3_init_irq,
- .init_machine = cm_t35_init,
- .init_late = omap35xx_init_late,
- .init_time = omap3_sync32k_timer_init,
- .restart = omap3xxx_restart,
-MACHINE_END
-
-MACHINE_START(CM_T3730, "Compulab CM-T3730")
- .atag_offset = 0x100,
- .reserve = omap_reserve,
- .map_io = omap3_map_io,
- .init_early = omap3630_init_early,
- .init_irq = omap3_init_irq,
- .init_machine = cm_t3730_init,
- .init_late = omap3630_init_late,
- .init_time = omap3_sync32k_timer_init,
- .restart = omap3xxx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
deleted file mode 100644
index 81de1c68b360..000000000000
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/board-omap3beagle.c
- *
- * Copyright (C) 2008 Texas Instruments
- *
- * Modified from mach-omap2/board-3430sdp.c
- *
- * Initial code: Syed Mohammed Khasim
- *
- * 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/init.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/leds.h>
-#include <linux/pwm.h>
-#include <linux/leds_pwm.h>
-#include <linux/gpio.h>
-#include <linux/input.h>
-#include <linux/gpio_keys.h>
-#include <linux/pm_opp.h>
-#include <linux/cpu.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/nand.h>
-#include <linux/mmc/host.h>
-#include <linux/usb/phy.h>
-
-#include <linux/regulator/machine.h>
-#include <linux/i2c/twl.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
-
-#include <video/omapdss.h>
-#include <video/omap-panel-data.h>
-#include <linux/platform_data/mtd-nand-omap2.h>
-
-#include "common.h"
-#include "omap_device.h"
-#include "gpmc.h"
-#include "soc.h"
-#include "mux.h"
-#include "hsmmc.h"
-#include "pm.h"
-#include "board-flash.h"
-#include "common-board-devices.h"
-
-#define NAND_CS 0
-
-static struct pwm_lookup pwm_lookup[] = {
- /* LEDB -> PMU_STAT */
- PWM_LOOKUP("twl-pwmled", 1, "leds_pwm", "beagleboard::pmu_stat",
- 7812500, PWM_POLARITY_NORMAL),
-};
-
-static struct led_pwm pwm_leds[] = {
- {
- .name = "beagleboard::pmu_stat",
- .max_brightness = 127,
- .pwm_period_ns = 7812500,
- },
-};
-
-static struct led_pwm_platform_data pwm_data = {
- .num_leds = ARRAY_SIZE(pwm_leds),
- .leds = pwm_leds,
-};
-
-static struct platform_device leds_pwm = {
- .name = "leds_pwm",
- .id = -1,
- .dev = {
- .platform_data = &pwm_data,
- },
-};
-
-/*
- * OMAP3 Beagle revision
- * Run time detection of Beagle revision is done by reading GPIO.
- * GPIO ID -
- * AXBX = GPIO173, GPIO172, GPIO171: 1 1 1
- * C1_3 = GPIO173, GPIO172, GPIO171: 1 1 0
- * C4 = GPIO173, GPIO172, GPIO171: 1 0 1
- * XMA/XMB = GPIO173, GPIO172, GPIO171: 0 0 0
- * XMC = GPIO173, GPIO172, GPIO171: 0 1 0
- */
-enum {
- OMAP3BEAGLE_BOARD_UNKN = 0,
- OMAP3BEAGLE_BOARD_AXBX,
- OMAP3BEAGLE_BOARD_C1_3,
- OMAP3BEAGLE_BOARD_C4,
- OMAP3BEAGLE_BOARD_XM,
- OMAP3BEAGLE_BOARD_XMC,
-};
-
-static u8 omap3_beagle_version;
-
-/*
- * Board-specific configuration
- * Defaults to BeagleBoard-xMC
- */
-static struct {
- int mmc1_gpio_wp;
- bool usb_pwr_level; /* 0 - Active Low, 1 - Active High */
- int dvi_pd_gpio;
- int usr_button_gpio;
- int mmc_caps;
-} beagle_config = {
- .mmc1_gpio_wp = -EINVAL,
- .usb_pwr_level = 0,
- .dvi_pd_gpio = -EINVAL,
- .usr_button_gpio = 4,
- .mmc_caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
-};
-
-static struct gpio omap3_beagle_rev_gpios[] __initdata = {
- { 171, GPIOF_IN, "rev_id_0" },
- { 172, GPIOF_IN, "rev_id_1" },
- { 173, GPIOF_IN, "rev_id_2" },
-};
-
-static void __init omap3_beagle_init_rev(void)
-{
- int ret;
- u16 beagle_rev = 0;
-
- omap_mux_init_gpio(171, OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_gpio(172, OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_gpio(173, OMAP_PIN_INPUT_PULLUP);
-
- ret = gpio_request_array(omap3_beagle_rev_gpios,
- ARRAY_SIZE(omap3_beagle_rev_gpios));
- if (ret < 0) {
- printk(KERN_ERR "Unable to get revision detection GPIO pins\n");
- omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
- return;
- }
-
- beagle_rev = gpio_get_value(171) | (gpio_get_value(172) << 1)
- | (gpio_get_value(173) << 2);
-
- gpio_free_array(omap3_beagle_rev_gpios,
- ARRAY_SIZE(omap3_beagle_rev_gpios));
-
- switch (beagle_rev) {
- case 7:
- printk(KERN_INFO "OMAP3 Beagle Rev: Ax/Bx\n");
- omap3_beagle_version = OMAP3BEAGLE_BOARD_AXBX;
- beagle_config.mmc1_gpio_wp = 29;
- beagle_config.dvi_pd_gpio = 170;
- beagle_config.usr_button_gpio = 7;
- break;
- case 6:
- printk(KERN_INFO "OMAP3 Beagle Rev: C1/C2/C3\n");
- omap3_beagle_version = OMAP3BEAGLE_BOARD_C1_3;
- beagle_config.mmc1_gpio_wp = 23;
- beagle_config.dvi_pd_gpio = 170;
- beagle_config.usr_button_gpio = 7;
- break;
- case 5:
- printk(KERN_INFO "OMAP3 Beagle Rev: C4\n");
- omap3_beagle_version = OMAP3BEAGLE_BOARD_C4;
- beagle_config.mmc1_gpio_wp = 23;
- beagle_config.dvi_pd_gpio = 170;
- beagle_config.usr_button_gpio = 7;
- break;
- case 0:
- printk(KERN_INFO "OMAP3 Beagle Rev: xM Ax/Bx\n");
- omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
- beagle_config.usb_pwr_level = 1;
- beagle_config.mmc_caps &= ~MMC_CAP_8_BIT_DATA;
- break;
- case 2:
- printk(KERN_INFO "OMAP3 Beagle Rev: xM C\n");
- omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC;
- beagle_config.mmc_caps &= ~MMC_CAP_8_BIT_DATA;
- break;
- default:
- printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
- omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
- }
-}
-
-static struct mtd_partition omap3beagle_nand_partitions[] = {
- /* All the partition sizes are listed in terms of NAND block size */
- {
- .name = "X-Loader",
- .offset = 0,
- .size = 4 * NAND_BLOCK_SIZE,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
- .name = "U-Boot",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */
- .size = 15 * NAND_BLOCK_SIZE,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
- .name = "U-Boot Env",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x260000 */
- .size = 1 * NAND_BLOCK_SIZE,
- },
- {
- .name = "Kernel",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */
- .size = 32 * NAND_BLOCK_SIZE,
- },
- {
- .name = "File System",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x680000 */
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-/* DSS */
-
-static struct connector_dvi_platform_data beagle_dvi_connector_pdata = {
- .name = "dvi",
- .source = "tfp410.0",
- .i2c_bus_num = 3,
-};
-
-static struct platform_device beagle_dvi_connector_device = {
- .name = "connector-dvi",
- .id = 0,
- .dev.platform_data = &beagle_dvi_connector_pdata,
-};
-
-static struct encoder_tfp410_platform_data beagle_tfp410_pdata = {
- .name = "tfp410.0",
- .source = "dpi.0",
- .data_lines = 24,
- .power_down_gpio = -1,
-};
-
-static struct platform_device beagle_tfp410_device = {
- .name = "tfp410",
- .id = 0,
- .dev.platform_data = &beagle_tfp410_pdata,
-};
-
-static struct connector_atv_platform_data beagle_tv_pdata = {
- .name = "tv",
- .source = "venc.0",
- .connector_type = OMAP_DSS_VENC_TYPE_SVIDEO,
- .invert_polarity = false,
-};
-
-static struct platform_device beagle_tv_connector_device = {
- .name = "connector-analog-tv",
- .id = 0,
- .dev.platform_data = &beagle_tv_pdata,
-};
-
-static struct omap_dss_board_info beagle_dss_data = {
- .default_display_name = "dvi",
-};
-
-#include "sdram-micron-mt46h32m32lf-6.h"
-
-static struct omap2_hsmmc_info mmc[] = {
- {
- .mmc = 1,
- .caps = MMC_CAP_4_BIT_DATA,
- .gpio_wp = -EINVAL,
- .deferred = true,
- },
- {} /* Terminator */
-};
-
-static struct regulator_consumer_supply beagle_vmmc1_supply[] = {
- REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
-};
-
-static struct regulator_consumer_supply beagle_vsim_supply[] = {
- REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"),
-};
-
-static struct gpio_led gpio_leds[];
-
-static struct usbhs_phy_data phy_data[] = {
- {
- .port = 2,
- .reset_gpio = 147,
- .vcc_gpio = -1, /* updated in beagle_twl_gpio_setup */
- .vcc_polarity = 1, /* updated in beagle_twl_gpio_setup */
- },
-};
-
-static int beagle_twl_gpio_setup(struct device *dev,
- unsigned gpio, unsigned ngpio)
-{
- int r;
-
- mmc[0].gpio_wp = beagle_config.mmc1_gpio_wp;
- /* gpio + 0 is "mmc0_cd" (input/IRQ) */
- mmc[0].gpio_cd = gpio + 0;
- omap_hsmmc_late_init(mmc);
-
- /*
- * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
- * high / others active low)
- * DVI reset GPIO is different between beagle revisions
- */
- /* Valid for all -xM revisions */
- if (cpu_is_omap3630()) {
- /*
- * gpio + 1 on Xm controls the TFP410's enable line (active low)
- * gpio + 2 control varies depending on the board rev as below:
- * P7/P8 revisions(prototype): Camera EN
- * A2+ revisions (production): LDO (DVI, serial, led blocks)
- */
- r = gpio_request_one(gpio + 1, GPIOF_OUT_INIT_LOW,
- "nDVI_PWR_EN");
- if (r)
- pr_err("%s: unable to configure nDVI_PWR_EN\n",
- __func__);
-
- beagle_config.dvi_pd_gpio = gpio + 2;
-
- } else {
- /*
- * REVISIT: need ehci-omap hooks for external VBUS
- * power switch and overcurrent detect
- */
- if (gpio_request_one(gpio + 1, GPIOF_IN, "EHCI_nOC"))
- pr_err("%s: unable to configure EHCI_nOC\n", __func__);
- }
- beagle_tfp410_pdata.power_down_gpio = beagle_config.dvi_pd_gpio;
-
- platform_device_register(&beagle_tfp410_device);
- platform_device_register(&beagle_dvi_connector_device);
- platform_device_register(&beagle_tv_connector_device);
-
- /* TWL4030_GPIO_MAX i.e. LED_GPO controls HS USB Port 2 power */
- phy_data[0].vcc_gpio = gpio + TWL4030_GPIO_MAX;
- phy_data[0].vcc_polarity = beagle_config.usb_pwr_level;
-
- usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data));
- return 0;
-}
-
-static struct twl4030_gpio_platform_data beagle_gpio_data = {
- .use_leds = true,
- .pullups = BIT(1),
- .pulldowns = BIT(2) | BIT(6) | BIT(7) | BIT(8) | BIT(13)
- | BIT(15) | BIT(16) | BIT(17),
- .setup = beagle_twl_gpio_setup,
-};
-
-/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
-static struct regulator_init_data beagle_vmmc1 = {
- .constraints = {
- .min_uV = 1850000,
- .max_uV = 3150000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(beagle_vmmc1_supply),
- .consumer_supplies = beagle_vmmc1_supply,
-};
-
-/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */
-static struct regulator_init_data beagle_vsim = {
- .constraints = {
- .min_uV = 1800000,
- .max_uV = 3000000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(beagle_vsim_supply),
- .consumer_supplies = beagle_vsim_supply,
-};
-
-static struct twl4030_platform_data beagle_twldata = {
- /* platform_data for children goes here */
- .gpio = &beagle_gpio_data,
- .vmmc1 = &beagle_vmmc1,
- .vsim = &beagle_vsim,
-};
-
-static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
- {
- I2C_BOARD_INFO("eeprom", 0x50),
- },
-};
-
-static int __init omap3_beagle_i2c_init(void)
-{
- omap3_pmic_get_config(&beagle_twldata,
- TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_MADC |
- TWL_COMMON_PDATA_AUDIO,
- TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2);
-
- beagle_twldata.vpll2->constraints.name = "VDVI";
-
- omap3_pmic_init("twl4030", &beagle_twldata);
- /* Bus 3 is attached to the DVI port where devices like the pico DLP
- * projector don't work reliably with 400kHz */
- omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom));
- return 0;
-}
-
-static struct gpio_led gpio_leds[] = {
- {
- .name = "beagleboard::usr0",
- .default_trigger = "heartbeat",
- .gpio = 150,
- },
- {
- .name = "beagleboard::usr1",
- .default_trigger = "mmc0",
- .gpio = 149,
- },
-};
-
-static struct gpio_led_platform_data gpio_led_info = {
- .leds = gpio_leds,
- .num_leds = ARRAY_SIZE(gpio_leds),
-};
-
-static struct platform_device leds_gpio = {
- .name = "leds-gpio",
- .id = -1,
- .dev = {
- .platform_data = &gpio_led_info,
- },
-};
-
-static struct gpio_keys_button gpio_buttons[] = {
- {
- .code = BTN_EXTRA,
- /* Dynamically assigned depending on board */
- .gpio = -EINVAL,
- .desc = "user",
- .wakeup = 1,
- },
-};
-
-static struct gpio_keys_platform_data gpio_key_info = {
- .buttons = gpio_buttons,
- .nbuttons = ARRAY_SIZE(gpio_buttons),
-};
-
-static struct platform_device keys_gpio = {
- .name = "gpio-keys",
- .id = -1,
- .dev = {
- .platform_data = &gpio_key_info,
- },
-};
-
-static struct platform_device madc_hwmon = {
- .name = "twl4030_madc_hwmon",
- .id = -1,
-};
-
-static struct platform_device *omap3_beagle_devices[] __initdata = {
- &leds_gpio,
- &keys_gpio,
- &madc_hwmon,
- &leds_pwm,
-};
-
-static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
- .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
-};
-
-#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
- { .reg_offset = OMAP_MUX_TERMINATOR },
-};
-#endif
-
-static int __init beagle_opp_init(void)
-{
- int r = 0;
-
- if (!machine_is_omap3_beagle())
- return 0;
-
- /* Initialize the omap3 opp table if not already created. */
- r = omap3_opp_init();
- if (r < 0 && (r != -EEXIST)) {
- pr_err("%s: opp default init failed\n", __func__);
- return r;
- }
-
- /* Custom OPP enabled for all xM versions */
- if (cpu_is_omap3630()) {
- struct device *mpu_dev, *iva_dev;
-
- mpu_dev = get_cpu_device(0);
- iva_dev = omap_device_get_by_hwmod_name("iva");
-
- if (!mpu_dev || IS_ERR(iva_dev)) {
- pr_err("%s: Aiee.. no mpu/dsp devices? %p %p\n",
- __func__, mpu_dev, iva_dev);
- return -ENODEV;
- }
- /* Enable MPU 1GHz and lower opps */
- r = dev_pm_opp_enable(mpu_dev, 800000000);
- /* TODO: MPU 1GHz needs SR and ABB */
-
- /* Enable IVA 800MHz and lower opps */
- r |= dev_pm_opp_enable(iva_dev, 660000000);
- /* TODO: DSP 800MHz needs SR and ABB */
- if (r) {
- pr_err("%s: failed to enable higher opp %d\n",
- __func__, r);
- /*
- * Cleanup - disable the higher freqs - we dont care
- * about the results
- */
- dev_pm_opp_disable(mpu_dev, 800000000);
- dev_pm_opp_disable(iva_dev, 660000000);
- }
- }
- return 0;
-}
-omap_device_initcall(beagle_opp_init);
-
-static void __init omap3_beagle_init(void)
-{
- omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
- omap3_beagle_init_rev();
-
- if (gpio_is_valid(beagle_config.mmc1_gpio_wp))
- omap_mux_init_gpio(beagle_config.mmc1_gpio_wp, OMAP_PIN_INPUT);
- mmc[0].caps = beagle_config.mmc_caps;
- omap_hsmmc_init(mmc);
-
- omap3_beagle_i2c_init();
-
- gpio_buttons[0].gpio = beagle_config.usr_button_gpio;
-
- platform_add_devices(omap3_beagle_devices,
- ARRAY_SIZE(omap3_beagle_devices));
- if (gpio_is_valid(beagle_config.dvi_pd_gpio))
- omap_mux_init_gpio(beagle_config.dvi_pd_gpio, OMAP_PIN_OUTPUT);
- omap_display_init(&beagle_dss_data);
-
- omap_serial_init();
- omap_sdrc_init(mt46h32m32lf6_sdrc_params,
- mt46h32m32lf6_sdrc_params);
-
- usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
- usb_musb_init(NULL);
-
- usbhs_init(&usbhs_bdata);
-
- board_nand_init(omap3beagle_nand_partitions,
- ARRAY_SIZE(omap3beagle_nand_partitions), NAND_CS,
- NAND_BUSWIDTH_16, NULL);
- omap_twl4030_audio_init("omap3beagle", NULL);
-
- /* Ensure msecure is mux'd to be able to set the RTC. */
- omap_mux_init_signal("sys_drm_msecure", OMAP_PIN_OFF_OUTPUT_HIGH);
-
- /* Ensure SDRC pins are mux'd for self-refresh */
- omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
- omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
-
- pwm_add_table(pwm_lookup, ARRAY_SIZE(pwm_lookup));
-}
-
-MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
- /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
- .atag_offset = 0x100,
- .reserve = omap_reserve,
- .map_io = omap3_map_io,
- .init_early = omap3_init_early,
- .init_irq = omap3_init_irq,
- .init_machine = omap3_beagle_init,
- .init_late = omap3_init_late,
- .init_time = omap3_secure_sync32k_timer_init,
- .restart = omap3xxx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
deleted file mode 100644
index 2dae6ccd39bb..000000000000
--- a/arch/arm/mach-omap2/board-overo.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * board-overo.c (Gumstix Overo)
- *
- * Initial code: 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.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/i2c/twl.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/fixed.h>
-#include <linux/spi/spi.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mmc/host.h>
-#include <linux/usb/phy.h>
-
-#include <linux/platform_data/mtd-nand-omap2.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-#include <asm/mach/map.h>
-
-#include <video/omapdss.h>
-#include <video/omap-panel-data.h>
-
-#include "common.h"
-#include "mux.h"
-#include "sdram-micron-mt46h32m32lf-6.h"
-#include "gpmc.h"
-#include "hsmmc.h"
-#include "board-flash.h"
-#include "common-board-devices.h"
-
-#define NAND_CS 0
-
-#define OVERO_GPIO_BT_XGATE 15
-#define OVERO_GPIO_W2W_NRESET 16
-#define OVERO_GPIO_PENDOWN 114
-#define OVERO_GPIO_BT_NRESET 164
-#define OVERO_GPIO_USBH_CPEN 168
-#define OVERO_GPIO_USBH_NRESET 183
-
-#define OVERO_SMSC911X_CS 5
-#define OVERO_SMSC911X_GPIO 176
-#define OVERO_SMSC911X_NRESET 64
-#define OVERO_SMSC911X2_CS 4
-#define OVERO_SMSC911X2_GPIO 65
-
-/* whether to register LCD35 instead of LCD43 */
-static bool overo_use_lcd35;
-
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
- defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-
-/* fixed regulator for ads7846 */
-static struct regulator_consumer_supply ads7846_supply[] = {
- REGULATOR_SUPPLY("vcc", "spi1.0"),
-};
-
-static struct regulator_init_data vads7846_regulator = {
- .constraints = {
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(ads7846_supply),
- .consumer_supplies = ads7846_supply,
-};
-
-static struct fixed_voltage_config vads7846 = {
- .supply_name = "vads7846",
- .microvolts = 3300000, /* 3.3V */
- .gpio = -EINVAL,
- .startup_delay = 0,
- .init_data = &vads7846_regulator,
-};
-
-static struct platform_device vads7846_device = {
- .name = "reg-fixed-voltage",
- .id = 1,
- .dev = {
- .platform_data = &vads7846,
- },
-};
-
-static void __init overo_ads7846_init(void)
-{
- omap_ads7846_init(1, OVERO_GPIO_PENDOWN, 0, NULL);
- platform_device_register(&vads7846_device);
-}
-
-#else
-static inline void __init overo_ads7846_init(void) { return; }
-#endif
-
-#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
-
-#include <linux/smsc911x.h>
-#include "gpmc-smsc911x.h"
-
-static struct omap_smsc911x_platform_data smsc911x_cfg = {
- .id = 0,
- .cs = OVERO_SMSC911X_CS,
- .gpio_irq = OVERO_SMSC911X_GPIO,
- .gpio_reset = OVERO_SMSC911X_NRESET,
- .flags = SMSC911X_USE_32BIT,
-};
-
-static struct omap_smsc911x_platform_data smsc911x2_cfg = {
- .id = 1,
- .cs = OVERO_SMSC911X2_CS,
- .gpio_irq = OVERO_SMSC911X2_GPIO,
- .gpio_reset = -EINVAL,
- .flags = SMSC911X_USE_32BIT,
-};
-
-static void __init overo_init_smsc911x(void)
-{
- gpmc_smsc911x_init(&smsc911x_cfg);
- gpmc_smsc911x_init(&smsc911x2_cfg);
-}
-
-#else
-static inline void __init overo_init_smsc911x(void) { return; }
-#endif
-
-/* DSS */
-#define OVERO_GPIO_LCD_EN 144
-#define OVERO_GPIO_LCD_BL 145
-
-static struct connector_atv_platform_data overo_tv_pdata = {
- .name = "tv",
- .source = "venc.0",
- .connector_type = OMAP_DSS_VENC_TYPE_SVIDEO,
- .invert_polarity = false,
-};
-
-static struct platform_device overo_tv_connector_device = {
- .name = "connector-analog-tv",
- .id = 0,
- .dev.platform_data = &overo_tv_pdata,
-};
-
-static const struct display_timing overo_lcd43_videomode = {
- .pixelclock = { 0, 9200000, 0 },
-
- .hactive = { 0, 480, 0 },
- .hfront_porch = { 0, 8, 0 },
- .hback_porch = { 0, 4, 0 },
- .hsync_len = { 0, 41, 0 },
-
- .vactive = { 0, 272, 0 },
- .vfront_porch = { 0, 4, 0 },
- .vback_porch = { 0, 2, 0 },
- .vsync_len = { 0, 10, 0 },
-
- .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
- DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE,
-};
-
-static struct panel_dpi_platform_data overo_lcd43_pdata = {
- .name = "lcd43",
- .source = "dpi.0",
-
- .data_lines = 24,
-
- .display_timing = &overo_lcd43_videomode,
-
- .enable_gpio = OVERO_GPIO_LCD_EN,
- .backlight_gpio = OVERO_GPIO_LCD_BL,
-};
-
-static struct platform_device overo_lcd43_device = {
- .name = "panel-dpi",
- .id = 0,
- .dev.platform_data = &overo_lcd43_pdata,
-};
-
-static struct connector_dvi_platform_data overo_dvi_connector_pdata = {
- .name = "dvi",
- .source = "tfp410.0",
- .i2c_bus_num = 3,
-};
-
-static struct platform_device overo_dvi_connector_device = {
- .name = "connector-dvi",
- .id = 0,
- .dev.platform_data = &overo_dvi_connector_pdata,
-};
-
-static struct encoder_tfp410_platform_data overo_tfp410_pdata = {
- .name = "tfp410.0",
- .source = "dpi.0",
- .data_lines = 24,
- .power_down_gpio = -1,
-};
-
-static struct platform_device overo_tfp410_device = {
- .name = "tfp410",
- .id = 0,
- .dev.platform_data = &overo_tfp410_pdata,
-};
-
-static struct omap_dss_board_info overo_dss_data = {
- .default_display_name = "lcd43",
-};
-
-static void __init overo_display_init(void)
-{
- omap_display_init(&overo_dss_data);
-
- if (!overo_use_lcd35)
- platform_device_register(&overo_lcd43_device);
- platform_device_register(&overo_tfp410_device);
- platform_device_register(&overo_dvi_connector_device);
- platform_device_register(&overo_tv_connector_device);
-}
-
-static struct mtd_partition overo_nand_partitions[] = {
- {
- .name = "xloader",
- .offset = 0, /* Offset = 0x00000 */
- .size = 4 * NAND_BLOCK_SIZE,
- .mask_flags = MTD_WRITEABLE
- },
- {
- .name = "uboot",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */
- .size = 14 * NAND_BLOCK_SIZE,
- },
- {
- .name = "uboot environment",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x240000 */
- .size = 2 * NAND_BLOCK_SIZE,
- },
- {
- .name = "linux",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */
- .size = 32 * NAND_BLOCK_SIZE,
- },
- {
- .name = "rootfs",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x680000 */
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct omap2_hsmmc_info mmc[] = {
- {
- .mmc = 1,
- .caps = MMC_CAP_4_BIT_DATA,
- .gpio_cd = -EINVAL,
- .gpio_wp = -EINVAL,
- },
- {
- .mmc = 2,
- .caps = MMC_CAP_4_BIT_DATA,
- .gpio_cd = -EINVAL,
- .gpio_wp = -EINVAL,
- .transceiver = true,
- .ocr_mask = 0x00100000, /* 3.3V */
- },
- {} /* Terminator */
-};
-
-static struct regulator_consumer_supply overo_vmmc1_supply[] = {
- REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
-};
-
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
-#include <linux/leds.h>
-
-static struct gpio_led gpio_leds[] = {
- {
- .name = "overo:red:gpio21",
- .default_trigger = "heartbeat",
- .gpio = 21,
- .active_low = true,
- },
- {
- .name = "overo:blue:gpio22",
- .default_trigger = "none",
- .gpio = 22,
- .active_low = true,
- },
- {
- .name = "overo:blue:COM",
- .default_trigger = "mmc0",
- .gpio = -EINVAL, /* gets replaced */
- .active_low = true,
- },
-};
-
-static struct gpio_led_platform_data gpio_leds_pdata = {
- .leds = gpio_leds,
- .num_leds = ARRAY_SIZE(gpio_leds),
-};
-
-static struct platform_device gpio_leds_device = {
- .name = "leds-gpio",
- .id = -1,
- .dev = {
- .platform_data = &gpio_leds_pdata,
- },
-};
-
-static void __init overo_init_led(void)
-{
- platform_device_register(&gpio_leds_device);
-}
-
-#else
-static inline void __init overo_init_led(void) { return; }
-#endif
-
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-#include <linux/input.h>
-#include <linux/gpio_keys.h>
-
-static struct gpio_keys_button gpio_buttons[] = {
- {
- .code = BTN_0,
- .gpio = 23,
- .desc = "button0",
- .wakeup = 1,
- },
- {
- .code = BTN_1,
- .gpio = 14,
- .desc = "button1",
- .wakeup = 1,
- },
-};
-
-static struct gpio_keys_platform_data gpio_keys_pdata = {
- .buttons = gpio_buttons,
- .nbuttons = ARRAY_SIZE(gpio_buttons),
-};
-
-static struct platform_device gpio_keys_device = {
- .name = "gpio-keys",
- .id = -1,
- .dev = {
- .platform_data = &gpio_keys_pdata,
- },
-};
-
-static void __init overo_init_keys(void)
-{
- platform_device_register(&gpio_keys_device);
-}
-
-#else
-static inline void __init overo_init_keys(void) { return; }
-#endif
-
-static int overo_twl_gpio_setup(struct device *dev,
- unsigned gpio, unsigned ngpio)
-{
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
- /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
- gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
-#endif
-
- return 0;
-}
-
-static struct twl4030_gpio_platform_data overo_gpio_data = {
- .use_leds = true,
- .setup = overo_twl_gpio_setup,
-};
-
-static struct regulator_init_data overo_vmmc1 = {
- .constraints = {
- .min_uV = 1850000,
- .max_uV = 3150000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(overo_vmmc1_supply),
- .consumer_supplies = overo_vmmc1_supply,
-};
-
-static struct twl4030_platform_data overo_twldata = {
- .gpio = &overo_gpio_data,
- .vmmc1 = &overo_vmmc1,
-};
-
-static int __init overo_i2c_init(void)
-{
- omap3_pmic_get_config(&overo_twldata,
- TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_AUDIO,
- TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2);
-
- overo_twldata.vpll2->constraints.name = "VDVI";
-
- omap3_pmic_init("tps65950", &overo_twldata);
- /* i2c2 pins are used for gpio */
- omap_register_i2c_bus(3, 400, NULL, 0);
- return 0;
-}
-
-static struct panel_lb035q02_platform_data overo_lcd35_pdata = {
- .name = "lcd35",
- .source = "dpi.0",
-
- .data_lines = 24,
-
- .enable_gpio = OVERO_GPIO_LCD_EN,
- .backlight_gpio = OVERO_GPIO_LCD_BL,
-};
-
-/*
- * NOTE: We need to add either the lgphilips panel, or the lcd43 panel. The
- * selection is done based on the overo_use_lcd35 field. If new SPI
- * devices are added here, extra work is needed to make only the lgphilips panel
- * affected by the overo_use_lcd35 field.
- */
-static struct spi_board_info overo_spi_board_info[] __initdata = {
- {
- .modalias = "panel_lgphilips_lb035q02",
- .bus_num = 1,
- .chip_select = 1,
- .max_speed_hz = 500000,
- .mode = SPI_MODE_3,
- .platform_data = &overo_lcd35_pdata,
- },
-};
-
-static int __init overo_spi_init(void)
-{
- overo_ads7846_init();
-
- if (overo_use_lcd35) {
- spi_register_board_info(overo_spi_board_info,
- ARRAY_SIZE(overo_spi_board_info));
- }
- return 0;
-}
-
-static struct usbhs_phy_data phy_data[] __initdata = {
- {
- .port = 2,
- .reset_gpio = OVERO_GPIO_USBH_NRESET,
- .vcc_gpio = -EINVAL,
- },
-};
-
-static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
- .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
-};
-
-#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
- { .reg_offset = OMAP_MUX_TERMINATOR },
-};
-#endif
-
-static struct gpio overo_bt_gpios[] __initdata = {
- { OVERO_GPIO_BT_XGATE, GPIOF_OUT_INIT_LOW, "lcd enable" },
- { OVERO_GPIO_BT_NRESET, GPIOF_OUT_INIT_HIGH, "lcd bl enable" },
-};
-
-static struct regulator_consumer_supply dummy_supplies[] = {
- REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
- REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
- REGULATOR_SUPPLY("vddvario", "smsc911x.1"),
- REGULATOR_SUPPLY("vdd33a", "smsc911x.1"),
-};
-
-static void __init overo_init(void)
-{
- int ret;
-
- if (strstr(boot_command_line, "omapdss.def_disp=lcd35"))
- overo_use_lcd35 = true;
-
- regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
- omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
- overo_i2c_init();
- omap_hsmmc_init(mmc);
- omap_serial_init();
- omap_sdrc_init(mt46h32m32lf6_sdrc_params,
- mt46h32m32lf6_sdrc_params);
- board_nand_init(overo_nand_partitions,
- ARRAY_SIZE(overo_nand_partitions), NAND_CS, 0, NULL);
- usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
- usb_musb_init(NULL);
-
- usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data));
- usbhs_init(&usbhs_bdata);
- overo_spi_init();
- overo_init_smsc911x();
- overo_init_led();
- overo_init_keys();
- omap_twl4030_audio_init("overo", NULL);
-
- overo_display_init();
-
- /* Ensure SDRC pins are mux'd for self-refresh */
- omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
- omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
-
- ret = gpio_request_one(OVERO_GPIO_W2W_NRESET, GPIOF_OUT_INIT_HIGH,
- "OVERO_GPIO_W2W_NRESET");
- if (ret == 0) {
- gpio_export(OVERO_GPIO_W2W_NRESET, 0);
- gpio_set_value(OVERO_GPIO_W2W_NRESET, 0);
- udelay(10);
- gpio_set_value(OVERO_GPIO_W2W_NRESET, 1);
- } else {
- pr_err("could not obtain gpio for OVERO_GPIO_W2W_NRESET\n");
- }
-
- ret = gpio_request_array(overo_bt_gpios, ARRAY_SIZE(overo_bt_gpios));
- if (ret) {
- pr_err("%s: could not obtain BT gpios\n", __func__);
- } else {
- gpio_export(OVERO_GPIO_BT_XGATE, 0);
- gpio_export(OVERO_GPIO_BT_NRESET, 0);
- gpio_set_value(OVERO_GPIO_BT_NRESET, 0);
- mdelay(6);
- gpio_set_value(OVERO_GPIO_BT_NRESET, 1);
- }
-
- ret = gpio_request_one(OVERO_GPIO_USBH_CPEN, GPIOF_OUT_INIT_HIGH,
- "OVERO_GPIO_USBH_CPEN");
- if (ret == 0)
- gpio_export(OVERO_GPIO_USBH_CPEN, 0);
- else
- pr_err("could not obtain gpio for OVERO_GPIO_USBH_CPEN\n");
-}
-
-MACHINE_START(OVERO, "Gumstix Overo")
- .atag_offset = 0x100,
- .reserve = omap_reserve,
- .map_io = omap3_map_io,
- .init_early = omap35xx_init_early,
- .init_irq = omap3_init_irq,
- .init_machine = overo_init,
- .init_late = omap35xx_init_late,
- .init_time = omap3_sync32k_timer_init,
- .restart = omap3xxx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c b/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c
index 85e0b0c06718..b64d717bfab6 100644
--- a/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c
+++ b/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c
@@ -232,14 +232,12 @@ void omap2xxx_clkt_vps_init(void)
struct clk_hw_omap *hw = NULL;
struct clk *clk;
const char *parent_name = "mpu_ck";
- struct clk_lookup *lookup = NULL;
omap2xxx_clkt_vps_late_init();
omap2xxx_clkt_vps_check_bootloader_rates();
hw = kzalloc(sizeof(*hw), GFP_KERNEL);
- lookup = kzalloc(sizeof(*lookup), GFP_KERNEL);
- if (!hw || !lookup)
+ if (!hw)
goto cleanup;
init.name = "virt_prcm_set";
init.ops = &virt_prcm_set_ops;
@@ -249,15 +247,9 @@ void omap2xxx_clkt_vps_init(void)
hw->hw.init = &init;
clk = clk_register(NULL, &hw->hw);
-
- lookup->dev_id = NULL;
- lookup->con_id = "cpufreq_ck";
- lookup->clk = clk;
-
- clkdev_add(lookup);
+ clkdev_create(clk, "cpufreq_ck", NULL);
return;
cleanup:
kfree(hw);
- kfree(lookup);
}
#endif
diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index af95a624fe71..f008930277ed 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -112,6 +112,7 @@ struct omap3_control_regs {
u32 csirxfe;
u32 iva2_bootaddr;
u32 iva2_bootmod;
+ u32 wkup_ctrl;
u32 debobs_0;
u32 debobs_1;
u32 debobs_2;
@@ -455,6 +456,7 @@ void omap3_control_save_context(void)
omap_ctrl_readl(OMAP343X_CONTROL_IVA2_BOOTADDR);
control_context.iva2_bootmod =
omap_ctrl_readl(OMAP343X_CONTROL_IVA2_BOOTMOD);
+ control_context.wkup_ctrl = omap_ctrl_readl(OMAP34XX_CONTROL_WKUP_CTRL);
control_context.debobs_0 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(0));
control_context.debobs_1 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(1));
control_context.debobs_2 = omap_ctrl_readl(OMAP343X_CONTROL_DEBOBS(2));
@@ -512,6 +514,7 @@ void omap3_control_restore_context(void)
OMAP343X_CONTROL_IVA2_BOOTADDR);
omap_ctrl_writel(control_context.iva2_bootmod,
OMAP343X_CONTROL_IVA2_BOOTMOD);
+ omap_ctrl_writel(control_context.wkup_ctrl, OMAP34XX_CONTROL_WKUP_CTRL);
omap_ctrl_writel(control_context.debobs_0, OMAP343X_CONTROL_DEBOBS(0));
omap_ctrl_writel(control_context.debobs_1, OMAP343X_CONTROL_DEBOBS(1));
omap_ctrl_writel(control_context.debobs_2, OMAP343X_CONTROL_DEBOBS(2));
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index 80d2b7d8e36e..ec406bc2c6d4 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -231,6 +231,9 @@
#define OMAP343X_PADCONF_ETK_D15 OMAP343X_PADCONF_ETK(17)
/* 34xx GENERAL_WKUP register offsets */
+#define OMAP34XX_CONTROL_WKUP_CTRL (OMAP343X_CONTROL_GENERAL_WKUP - 0x4)
+#define OMAP36XX_GPIO_IO_PWRDNZ BIT(6)
+
#define OMAP343X_CONTROL_WKUP_DEBOBSMUX(i) (OMAP343X_CONTROL_GENERAL_WKUP + \
0x008 + (i))
#define OMAP343X_CONTROL_WKUP_DEBOBS0 (OMAP343X_CONTROL_GENERAL_WKUP + 0x008)
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 990338fbaa59..a69bd67e9028 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -63,7 +63,7 @@ static int __init omap3_l3_init(void)
WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
- return PTR_RET(pdev);
+ return PTR_ERR_OR_ZERO(pdev);
}
omap_postcore_initcall(omap3_l3_init);
@@ -333,6 +333,6 @@ static int __init omap_gpmc_init(void)
pdev = omap_device_build("omap-gpmc", -1, oh, NULL, 0);
WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
- return PTR_RET(pdev);
+ return PTR_ERR_OR_ZERO(pdev);
}
omap_postcore_initcall(omap_gpmc_init);
diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c
index f492ae147c6a..6ab13d18c636 100644
--- a/arch/arm/mach-omap2/display.c
+++ b/arch/arm/mach-omap2/display.c
@@ -287,6 +287,8 @@ static enum omapdss_version __init omap_display_get_version(void)
return OMAPDSS_VER_OMAP5;
else if (soc_is_am43xx())
return OMAPDSS_VER_AM43xx;
+ else if (soc_is_dra7xx())
+ return OMAPDSS_VER_DRA7xx;
else
return OMAPDSS_VER_UNKNOWN;
}
@@ -568,25 +570,25 @@ void __init omapdss_early_init_of(void)
}
+static const char * const omapdss_compat_names[] __initconst = {
+ "ti,omap2-dss",
+ "ti,omap3-dss",
+ "ti,omap4-dss",
+ "ti,omap5-dss",
+ "ti,dra7-dss",
+};
+
struct device_node * __init omapdss_find_dss_of_node(void)
{
struct device_node *node;
+ int i;
- node = of_find_compatible_node(NULL, NULL, "ti,omap2-dss");
- if (node)
- return node;
-
- node = of_find_compatible_node(NULL, NULL, "ti,omap3-dss");
- if (node)
- return node;
-
- node = of_find_compatible_node(NULL, NULL, "ti,omap4-dss");
- if (node)
- return node;
-
- node = of_find_compatible_node(NULL, NULL, "ti,omap5-dss");
- if (node)
- return node;
+ for (i = 0; i < ARRAY_SIZE(omapdss_compat_names); ++i) {
+ node = of_find_compatible_node(NULL, NULL,
+ omapdss_compat_names[i]);
+ if (node)
+ return node;
+ }
return NULL;
}
diff --git a/arch/arm/mach-omap2/fb.c b/arch/arm/mach-omap2/fb.c
index 26e28e94f625..1f1ecf8807eb 100644
--- a/arch/arm/mach-omap2/fb.c
+++ b/arch/arm/mach-omap2/fb.c
@@ -84,7 +84,7 @@ int __init omap_init_vrfb(void)
pdev = platform_device_register_resndata(NULL, "omapvrfb", -1,
res, num_res, NULL, 0);
- return PTR_RET(pdev);
+ return PTR_ERR_OR_ZERO(pdev);
}
#else
int __init omap_init_vrfb(void) { return 0; }
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index f899e77ff5e6..17a6f752a436 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -216,11 +216,11 @@ static void omap2_onenand_calc_sync_timings(struct gpmc_timings *t,
div = gpmc_calc_divider(min_gpmc_clk_period);
gpmc_clk_ns = gpmc_ticks_to_ns(div);
- if (gpmc_clk_ns < 15) /* >66Mhz */
+ if (gpmc_clk_ns < 15) /* >66MHz */
onenand_flags |= ONENAND_FLAG_HF;
else
onenand_flags &= ~ONENAND_FLAG_HF;
- if (gpmc_clk_ns < 12) /* >83Mhz */
+ if (gpmc_clk_ns < 12) /* >83MHz */
onenand_flags |= ONENAND_FLAG_VHF;
else
onenand_flags &= ~ONENAND_FLAG_VHF;
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 9a8611ab5dfa..cff079e563f4 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -70,7 +70,7 @@ static void omap_hsmmc1_before_set_reg(struct device *dev,
reg = omap_ctrl_readl(control_pbias_offset);
if (cpu_is_omap3630()) {
- /* Set MMC I/O to 52Mhz */
+ /* Set MMC I/O to 52MHz */
prog_io = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1);
prog_io |= OMAP3630_PRG_SDMMC1_SPEEDCTRL;
omap_ctrl_writel(prog_io, OMAP343X_CONTROL_PROG_IO1);
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index 3b56722dfd8a..8e52621b5a6b 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -444,7 +444,7 @@ static int wakeupgen_domain_alloc(struct irq_domain *domain,
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args);
}
-static struct irq_domain_ops wakeupgen_domain_ops = {
+static const struct irq_domain_ops wakeupgen_domain_ops = {
.xlate = wakeupgen_domain_xlate,
.alloc = wakeupgen_domain_alloc,
.free = irq_domain_free_irqs_common,
diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c
index 166b18f515a2..4cb8fd9f741f 100644
--- a/arch/arm/mach-omap2/omap_device.c
+++ b/arch/arm/mach-omap2/omap_device.c
@@ -47,7 +47,7 @@ static void _add_clkdev(struct omap_device *od, const char *clk_alias,
const char *clk_name)
{
struct clk *r;
- struct clk_lookup *l;
+ int rc;
if (!clk_alias || !clk_name)
return;
@@ -62,21 +62,15 @@ static void _add_clkdev(struct omap_device *od, const char *clk_alias,
return;
}
- r = clk_get(NULL, clk_name);
- if (IS_ERR(r)) {
- dev_err(&od->pdev->dev,
- "clk_get for %s failed\n", clk_name);
- return;
- }
-
- l = clkdev_alloc(r, clk_alias, dev_name(&od->pdev->dev));
- if (!l) {
- dev_err(&od->pdev->dev,
- "clkdev_alloc for %s failed\n", clk_alias);
- return;
+ rc = clk_add_alias(clk_alias, dev_name(&od->pdev->dev), clk_name, NULL);
+ if (rc) {
+ if (rc == -ENODEV || rc == -ENOMEM)
+ dev_err(&od->pdev->dev,
+ "clkdev_alloc for %s failed\n", clk_alias);
+ else
+ dev_err(&od->pdev->dev,
+ "clk_get for %s failed\n", clk_name);
}
-
- clkdev_add(l);
}
/**
@@ -224,13 +218,13 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
*/
static int _omap_device_enable_hwmods(struct omap_device *od)
{
+ int ret = 0;
int i;
for (i = 0; i < od->hwmods_cnt; i++)
- omap_hwmod_enable(od->hwmods[i]);
+ ret |= omap_hwmod_enable(od->hwmods[i]);
- /* XXX pass along return value here? */
- return 0;
+ return ret;
}
/**
@@ -241,13 +235,13 @@ static int _omap_device_enable_hwmods(struct omap_device *od)
*/
static int _omap_device_idle_hwmods(struct omap_device *od)
{
+ int ret = 0;
int i;
for (i = 0; i < od->hwmods_cnt; i++)
- omap_hwmod_idle(od->hwmods[i]);
+ ret |= omap_hwmod_idle(od->hwmods[i]);
- /* XXX pass along return value here? */
- return 0;
+ return ret;
}
/* Public functions for use by core code */
@@ -595,18 +589,20 @@ static int _od_runtime_suspend(struct device *dev)
int ret;
ret = pm_generic_runtime_suspend(dev);
+ if (ret)
+ return ret;
- if (!ret)
- omap_device_idle(pdev);
-
- return ret;
+ return omap_device_idle(pdev);
}
static int _od_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
+ int ret;
- omap_device_enable(pdev);
+ ret = omap_device_enable(pdev);
+ if (ret)
+ return ret;
return pm_generic_runtime_resume(dev);
}
@@ -688,11 +684,8 @@ struct dev_pm_domain omap_device_pm_domain = {
SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
NULL)
USE_PLATFORM_PM_SLEEP_OPS
- .suspend_noirq = _od_suspend_noirq,
- .resume_noirq = _od_resume_noirq,
- .freeze_noirq = _od_suspend_noirq,
- .thaw_noirq = _od_resume_noirq,
- .restore_noirq = _od_resume_noirq,
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(_od_suspend_noirq,
+ _od_resume_noirq)
}
};
@@ -743,7 +736,8 @@ int omap_device_enable(struct platform_device *pdev)
ret = _omap_device_enable_hwmods(od);
- od->_state = OMAP_DEVICE_STATE_ENABLED;
+ if (ret == 0)
+ od->_state = OMAP_DEVICE_STATE_ENABLED;
return ret;
}
@@ -773,7 +767,8 @@ int omap_device_idle(struct platform_device *pdev)
ret = _omap_device_idle_hwmods(od);
- od->_state = OMAP_DEVICE_STATE_IDLE;
+ if (ret == 0)
+ od->_state = OMAP_DEVICE_STATE_IDLE;
return ret;
}
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 752969ff9de0..d78c12e7cb5e 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -3318,16 +3318,17 @@ int omap_hwmod_enable(struct omap_hwmod *oh)
*/
int omap_hwmod_idle(struct omap_hwmod *oh)
{
+ int r;
unsigned long flags;
if (!oh)
return -EINVAL;
spin_lock_irqsave(&oh->_lock, flags);
- _idle(oh);
+ r = _idle(oh);
spin_unlock_irqrestore(&oh->_lock, flags);
- return 0;
+ return r;
}
/**
@@ -3340,16 +3341,17 @@ int omap_hwmod_idle(struct omap_hwmod *oh)
*/
int omap_hwmod_shutdown(struct omap_hwmod *oh)
{
+ int r;
unsigned long flags;
if (!oh)
return -EINVAL;
spin_lock_irqsave(&oh->_lock, flags);
- _shutdown(oh);
+ r = _shutdown(oh);
spin_unlock_irqrestore(&oh->_lock, flags);
- return 0;
+ return r;
}
/*
diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h
index 9611c91d9b82..b5d27ec81610 100644
--- a/arch/arm/mach-omap2/omap_hwmod.h
+++ b/arch/arm/mach-omap2/omap_hwmod.h
@@ -109,6 +109,12 @@ extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type3;
#define DEBUG_OMAPUART_FLAGS (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET)
+#ifdef CONFIG_OMAP_GPMC_DEBUG
+#define DEBUG_OMAP_GPMC_HWMOD_FLAGS HWMOD_INIT_NO_RESET
+#else
+#define DEBUG_OMAP_GPMC_HWMOD_FLAGS 0
+#endif
+
#if defined(CONFIG_DEBUG_OMAP2UART1)
#undef DEBUG_OMAP2UART1_FLAGS
#define DEBUG_OMAP2UART1_FLAGS DEBUG_OMAPUART_FLAGS
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
index 8821b9d6bae4..6dcfd03ced8f 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
@@ -762,16 +762,8 @@ struct omap_hwmod omap2xxx_gpmc_hwmod = {
.name = "gpmc",
.class = &omap2xxx_gpmc_hwmod_class,
.main_clk = "gpmc_fck",
- /*
- * XXX HWMOD_INIT_NO_RESET should not be needed for this IP
- * block. It is not being added due to any known bugs with
- * resetting the GPMC IP block, but rather because any timings
- * set by the bootloader are not being correctly programmed by
- * the kernel from the board file or DT data.
- * HWMOD_INIT_NO_RESET should be removed ASAP.
- */
- .flags = (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET |
- HWMOD_NO_IDLEST),
+ /* Skip reset for CONFIG_OMAP_GPMC_DEBUG for bootloader timings */
+ .flags = HWMOD_NO_IDLEST | DEBUG_OMAP_GPMC_HWMOD_FLAGS,
.prcm = {
.omap2 = {
.prcm_reg_id = 3,
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_common_data.h b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_common_data.h
index 130332c0534d..7f737965f543 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_common_data.h
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_common_data.h
@@ -145,6 +145,7 @@ extern struct omap_hwmod am33xx_uart5_hwmod;
extern struct omap_hwmod am33xx_uart6_hwmod;
extern struct omap_hwmod am33xx_wd_timer1_hwmod;
+extern struct omap_hwmod_class am33xx_emif_hwmod_class;
extern struct omap_hwmod_class am33xx_l4_hwmod_class;
extern struct omap_hwmod_class am33xx_wkup_m3_hwmod_class;
extern struct omap_hwmod_class am33xx_control_hwmod_class;
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
index cabc5695b504..907a452b78ea 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
@@ -203,6 +203,19 @@ struct omap_hwmod am33xx_prcm_hwmod = {
};
/*
+ * 'emif' class
+ * instance(s): emif
+ */
+static struct omap_hwmod_class_sysconfig am33xx_emif_sysc = {
+ .rev_offs = 0x0000,
+};
+
+struct omap_hwmod_class am33xx_emif_hwmod_class = {
+ .name = "emif",
+ .sysc = &am33xx_emif_sysc,
+};
+
+/*
* 'aes0' class
*/
static struct omap_hwmod_class_sysconfig am33xx_aes0_sysc = {
@@ -668,7 +681,8 @@ struct omap_hwmod am33xx_gpmc_hwmod = {
.name = "gpmc",
.class = &am33xx_gpmc_hwmod_class,
.clkdm_name = "l3s_clkdm",
- .flags = (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+ /* Skip reset for CONFIG_OMAP_GPMC_DEBUG for bootloader timings */
+ .flags = DEBUG_OMAP_GPMC_HWMOD_FLAGS,
.main_clk = "l3s_gclk",
.prcm = {
.omap4 = {
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
index 0cf7b563dcd1..cc0791d9125b 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
@@ -34,19 +34,6 @@
* IP blocks
*/
-/*
- * 'emif' class
- * instance(s): emif
- */
-static struct omap_hwmod_class_sysconfig am33xx_emif_sysc = {
- .rev_offs = 0x0000,
-};
-
-static struct omap_hwmod_class am33xx_emif_hwmod_class = {
- .name = "emif",
- .sysc = &am33xx_emif_sysc,
-};
-
/* emif */
static struct omap_hwmod am33xx_emif_hwmod = {
.name = "emif",
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 4e8e93c398db..dc55f8dedf2c 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -2169,16 +2169,8 @@ static struct omap_hwmod omap3xxx_gpmc_hwmod = {
.clkdm_name = "core_l3_clkdm",
.mpu_irqs = omap3xxx_gpmc_irqs,
.main_clk = "gpmc_fck",
- /*
- * XXX HWMOD_INIT_NO_RESET should not be needed for this IP
- * block. It is not being added due to any known bugs with
- * resetting the GPMC IP block, but rather because any timings
- * set by the bootloader are not being correctly programmed by
- * the kernel from the board file or DT data.
- * HWMOD_INIT_NO_RESET should be removed ASAP.
- */
- .flags = (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET |
- HWMOD_NO_IDLEST),
+ /* Skip reset for CONFIG_OMAP_GPMC_DEBUG for bootloader timings */
+ .flags = HWMOD_NO_IDLEST | DEBUG_OMAP_GPMC_HWMOD_FLAGS,
};
/*
@@ -3744,29 +3736,54 @@ static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = {
/* GP-only hwmod links */
static struct omap_hwmod_ocp_if *omap34xx_gp_hwmod_ocp_ifs[] __initdata = {
&omap3xxx_l4_sec__timer12,
- &omap3xxx_l4_core__sham,
- &omap3xxx_l4_core__aes,
NULL
};
static struct omap_hwmod_ocp_if *omap36xx_gp_hwmod_ocp_ifs[] __initdata = {
&omap3xxx_l4_sec__timer12,
- &omap3xxx_l4_core__sham,
- &omap3xxx_l4_core__aes,
NULL
};
static struct omap_hwmod_ocp_if *am35xx_gp_hwmod_ocp_ifs[] __initdata = {
&omap3xxx_l4_sec__timer12,
- /*
- * Apparently the SHA/MD5 and AES accelerator IP blocks are
- * only present on some AM35xx chips, and no one knows which
- * ones. See
- * http://www.spinics.net/lists/arm-kernel/msg215466.html So
- * if you need these IP blocks on an AM35xx, try uncommenting
- * the following lines.
- */
+ NULL
+};
+
+/* crypto hwmod links */
+static struct omap_hwmod_ocp_if *omap34xx_sham_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_l4_core__sham,
+ NULL
+};
+
+static struct omap_hwmod_ocp_if *omap34xx_aes_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_l4_core__aes,
+ NULL
+};
+
+static struct omap_hwmod_ocp_if *omap36xx_sham_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_l4_core__sham,
+ NULL
+};
+
+static struct omap_hwmod_ocp_if *omap36xx_aes_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_l4_core__aes,
+ NULL
+};
+
+/*
+ * Apparently the SHA/MD5 and AES accelerator IP blocks are
+ * only present on some AM35xx chips, and no one knows which
+ * ones. See
+ * http://www.spinics.net/lists/arm-kernel/msg215466.html So
+ * if you need these IP blocks on an AM35xx, try uncommenting
+ * the following lines.
+ */
+static struct omap_hwmod_ocp_if *am35xx_sham_hwmod_ocp_ifs[] __initdata = {
/* &omap3xxx_l4_core__sham, */
+ NULL
+};
+
+static struct omap_hwmod_ocp_if *am35xx_aes_hwmod_ocp_ifs[] __initdata = {
/* &omap3xxx_l4_core__aes, */
NULL
};
@@ -3868,10 +3885,41 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_hwmod_ocp_ifs[] __initdata = {
NULL
};
+/**
+ * omap3xxx_hwmod_is_hs_ip_block_usable - is a security IP block accessible?
+ * @bus: struct device_node * for the top-level OMAP DT data
+ * @dev_name: device name used in the DT file
+ *
+ * Determine whether a "secure" IP block @dev_name is usable by Linux.
+ * There doesn't appear to be a 100% reliable way to determine this,
+ * so we rely on heuristics. If @bus is null, meaning there's no DT
+ * data, then we only assume the IP block is accessible if the OMAP is
+ * fused as a 'general-purpose' SoC. If however DT data is present,
+ * test to see if the IP block is described in the DT data and set to
+ * 'status = "okay"'. If so then we assume the ODM has configured the
+ * OMAP firewalls to allow access to the IP block.
+ *
+ * Return: 0 if device named @dev_name is not likely to be accessible,
+ * or 1 if it is likely to be accessible.
+ */
+static int __init omap3xxx_hwmod_is_hs_ip_block_usable(struct device_node *bus,
+ const char *dev_name)
+{
+ if (!bus)
+ return (omap_type() == OMAP2_DEVICE_TYPE_GP) ? 1 : 0;
+
+ if (of_device_is_available(of_find_node_by_name(bus, dev_name)))
+ return 1;
+
+ return 0;
+}
+
int __init omap3xxx_hwmod_init(void)
{
int r;
- struct omap_hwmod_ocp_if **h = NULL, **h_gp = NULL;
+ struct omap_hwmod_ocp_if **h = NULL, **h_gp = NULL, **h_sham = NULL;
+ struct omap_hwmod_ocp_if **h_aes = NULL;
+ struct device_node *bus = NULL;
unsigned int rev;
omap_hwmod_init();
@@ -3893,13 +3941,19 @@ int __init omap3xxx_hwmod_init(void)
rev == OMAP3430_REV_ES3_1 || rev == OMAP3430_REV_ES3_1_2) {
h = omap34xx_hwmod_ocp_ifs;
h_gp = omap34xx_gp_hwmod_ocp_ifs;
+ h_sham = omap34xx_sham_hwmod_ocp_ifs;
+ h_aes = omap34xx_aes_hwmod_ocp_ifs;
} else if (rev == AM35XX_REV_ES1_0 || rev == AM35XX_REV_ES1_1) {
h = am35xx_hwmod_ocp_ifs;
h_gp = am35xx_gp_hwmod_ocp_ifs;
+ h_sham = am35xx_sham_hwmod_ocp_ifs;
+ h_aes = am35xx_aes_hwmod_ocp_ifs;
} else if (rev == OMAP3630_REV_ES1_0 || rev == OMAP3630_REV_ES1_1 ||
rev == OMAP3630_REV_ES1_2) {
h = omap36xx_hwmod_ocp_ifs;
h_gp = omap36xx_gp_hwmod_ocp_ifs;
+ h_sham = omap36xx_sham_hwmod_ocp_ifs;
+ h_aes = omap36xx_aes_hwmod_ocp_ifs;
} else {
WARN(1, "OMAP3 hwmod family init: unknown chip type\n");
return -EINVAL;
@@ -3916,6 +3970,25 @@ int __init omap3xxx_hwmod_init(void)
return r;
}
+ /*
+ * Register crypto hwmod links only if they are not disabled in DT.
+ * If DT information is missing, enable them only for GP devices.
+ */
+
+ if (of_have_populated_dt())
+ bus = of_find_node_by_name(NULL, "ocp");
+
+ if (h_sham && omap3xxx_hwmod_is_hs_ip_block_usable(bus, "sham")) {
+ r = omap_hwmod_register_links(h_sham);
+ if (r < 0)
+ return r;
+ }
+
+ if (h_aes && omap3xxx_hwmod_is_hs_ip_block_usable(bus, "aes")) {
+ r = omap_hwmod_register_links(h_aes);
+ if (r < 0)
+ return r;
+ }
/*
* Register hwmod links specific to certain ES levels of a
diff --git a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
index 17e8004fc20f..215d5efa0dba 100644
--- a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
@@ -24,6 +24,20 @@
/* IP blocks */
+static struct omap_hwmod am43xx_emif_hwmod = {
+ .name = "emif",
+ .class = &am33xx_emif_hwmod_class,
+ .clkdm_name = "emif_clkdm",
+ .flags = HWMOD_INIT_NO_IDLE,
+ .main_clk = "dpll_ddr_m2_ck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = AM43XX_CM_PER_EMIF_CLKCTRL_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+};
+
static struct omap_hwmod am43xx_l4_hs_hwmod = {
.name = "l4_hs",
.class = &am33xx_l4_hwmod_class,
@@ -583,6 +597,13 @@ static struct omap_hwmod am43xx_vpfe1_hwmod = {
};
/* Interfaces */
+static struct omap_hwmod_ocp_if am43xx_l3_main__emif = {
+ .master = &am33xx_l3_main_hwmod,
+ .slave = &am43xx_emif_hwmod,
+ .clk = "dpll_core_m4_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
static struct omap_hwmod_ocp_if am43xx_l3_main__l4_hs = {
.master = &am33xx_l3_main_hwmod,
.slave = &am43xx_l4_hs_hwmod,
@@ -918,6 +939,7 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
&am33xx_l3_main__l3_instr,
&am33xx_l3_main__gfx,
&am33xx_l3_s__l3_main,
+ &am43xx_l3_main__emif,
&am33xx_pruss__l3_main,
&am43xx_wkup_m3__l4_wkup,
&am33xx_gfx__l3_main,
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index f5e68a782025..43eebf2c59e2 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -1188,15 +1188,8 @@ static struct omap_hwmod omap44xx_gpmc_hwmod = {
.name = "gpmc",
.class = &omap44xx_gpmc_hwmod_class,
.clkdm_name = "l3_2_clkdm",
- /*
- * XXX HWMOD_INIT_NO_RESET should not be needed for this IP
- * block. It is not being added due to any known bugs with
- * resetting the GPMC IP block, but rather because any timings
- * set by the bootloader are not being correctly programmed by
- * the kernel from the board file or DT data.
- * HWMOD_INIT_NO_RESET should be removed ASAP.
- */
- .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+ /* Skip reset for CONFIG_OMAP_GPMC_DEBUG for bootloader timings */
+ .flags = DEBUG_OMAP_GPMC_HWMOD_FLAGS,
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L3_2_GPMC_CLKCTRL_OFFSET,
diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
index 0e64c2fac0b5..2606c6608bd8 100644
--- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
@@ -49,6 +49,27 @@
*/
/*
+ * 'dmm' class
+ * instance(s): dmm
+ */
+static struct omap_hwmod_class dra7xx_dmm_hwmod_class = {
+ .name = "dmm",
+};
+
+/* dmm */
+static struct omap_hwmod dra7xx_dmm_hwmod = {
+ .name = "dmm",
+ .class = &dra7xx_dmm_hwmod_class,
+ .clkdm_name = "emif_clkdm",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = DRA7XX_CM_EMIF_DMM_CLKCTRL_OFFSET,
+ .context_offs = DRA7XX_RM_EMIF_DMM_CONTEXT_OFFSET,
+ },
+ },
+};
+
+/*
* 'l3' class
* instance(s): l3_instr, l3_main_1, l3_main_2
*/
@@ -438,6 +459,7 @@ static struct omap_hwmod_opt_clk dss_opt_clks[] = {
{ .role = "video2_clk", .clk = "dss_video2_clk" },
{ .role = "video1_clk", .clk = "dss_video1_clk" },
{ .role = "hdmi_clk", .clk = "dss_hdmi_clk" },
+ { .role = "hdcp_clk", .clk = "dss_deshdcp_clk" },
};
static struct omap_hwmod dra7xx_dss_hwmod = {
@@ -500,6 +522,7 @@ static struct omap_hwmod dra7xx_dss_dispc_hwmod = {
},
},
.dev_attr = &dss_dispc_dev_attr,
+ .parent_hwmod = &dra7xx_dss_hwmod,
};
/*
@@ -541,6 +564,7 @@ static struct omap_hwmod dra7xx_dss_hdmi_hwmod = {
},
.opt_clks = dss_hdmi_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_hdmi_opt_clks),
+ .parent_hwmod = &dra7xx_dss_hwmod,
};
/*
@@ -819,8 +843,8 @@ static struct omap_hwmod dra7xx_gpmc_hwmod = {
.name = "gpmc",
.class = &dra7xx_gpmc_hwmod_class,
.clkdm_name = "l3main1_clkdm",
- .flags = (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET |
- HWMOD_SWSUP_SIDLE),
+ /* Skip reset for CONFIG_OMAP_GPMC_DEBUG for bootloader timings */
+ .flags = HWMOD_SWSUP_SIDLE | DEBUG_OMAP_GPMC_HWMOD_FLAGS,
.main_clk = "l3_iclk_div",
.prcm = {
.omap4 = {
@@ -2321,6 +2345,14 @@ static struct omap_hwmod dra7xx_wd_timer2_hwmod = {
* Interfaces
*/
+/* l3_main_1 -> dmm */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__dmm = {
+ .master = &dra7xx_l3_main_1_hwmod,
+ .slave = &dra7xx_dmm_hwmod,
+ .clk = "l3_iclk_div",
+ .user = OCP_USER_SDMA,
+};
+
/* l3_main_2 -> l3_instr */
static struct omap_hwmod_ocp_if dra7xx_l3_main_2__l3_instr = {
.master = &dra7xx_l3_main_2_hwmod,
@@ -3289,6 +3321,7 @@ static struct omap_hwmod_ocp_if dra7xx_l4_wkup__wd_timer2 = {
};
static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
+ &dra7xx_l3_main_1__dmm,
&dra7xx_l3_main_2__l3_instr,
&dra7xx_l4_cfg__l3_main_1,
&dra7xx_mpu__l3_main_1,
diff --git a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
index cab1eb61ac96..c92413769144 100644
--- a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
@@ -478,6 +478,8 @@ static struct omap_hwmod dm81xx_gpmc_hwmod = {
.clkdm_name = "alwon_l3s_clkdm",
.class = &dm81xx_gpmc_hwmod_class,
.main_clk = "sysclk6_ck",
+ /* Skip reset for CONFIG_OMAP_GPMC_DEBUG for bootloader timings */
+ .flags = DEBUG_OMAP_GPMC_HWMOD_FLAGS,
.prcm = {
.omap4 = {
.clkctrl_offs = DM816X_CM_ALWON_GPMC_CLKCTRL,
diff --git a/arch/arm/mach-omap2/opp2430_data.c b/arch/arm/mach-omap2/opp2430_data.c
index 0e75ec3e114b..b2233b72b24d 100644
--- a/arch/arm/mach-omap2/opp2430_data.c
+++ b/arch/arm/mach-omap2/opp2430_data.c
@@ -116,7 +116,7 @@ const struct prcm_config omap2430_rate_table[] = {
RATE_IN_243X},
/* PRCM-boot/bypass */
- {S13M, S13M, S13M, RB_CM_CLKSEL_MPU_VAL, /* 13Mhz */
+ {S13M, S13M, S13M, RB_CM_CLKSEL_MPU_VAL, /* 13MHz */
RB_CM_CLKSEL_DSP_VAL, RB_CM_CLKSEL_GFX_VAL,
RB_CM_CLKSEL1_CORE_VAL, MB_CM_CLKSEL1_PLL_13_VAL,
MX_CLKSEL2_PLL_2x_VAL, RB_CM_CLKSEL_MDM_VAL,
@@ -124,7 +124,7 @@ const struct prcm_config omap2430_rate_table[] = {
RATE_IN_243X},
/* PRCM-boot/bypass */
- {S12M, S12M, S12M, RB_CM_CLKSEL_MPU_VAL, /* 12Mhz */
+ {S12M, S12M, S12M, RB_CM_CLKSEL_MPU_VAL, /* 12MHz */
RB_CM_CLKSEL_DSP_VAL, RB_CM_CLKSEL_GFX_VAL,
RB_CM_CLKSEL1_CORE_VAL, MB_CM_CLKSEL1_PLL_12_VAL,
MX_CLKSEL2_PLL_2x_VAL, RB_CM_CLKSEL_MDM_VAL,
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index af11511dda50..821171cf6b7d 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -44,6 +44,27 @@ static void __init omap2420_n8x0_legacy_init(void)
#endif
#ifdef CONFIG_ARCH_OMAP3
+/*
+ * Configures GPIOs 126, 127 and 129 to 1.8V mode instead of 3.0V
+ * mode for MMC1 in case bootloader did not configure things.
+ * Note that if the pins are used for MMC1, pbias-regulator
+ * manages the IO voltage.
+ */
+static void __init omap3_gpio126_127_129(void)
+{
+ u32 reg;
+
+ reg = omap_ctrl_readl(OMAP343X_CONTROL_PBIAS_LITE);
+ reg &= ~OMAP343X_PBIASLITEVMODE1;
+ reg |= OMAP343X_PBIASLITEPWRDNZ1;
+ omap_ctrl_writel(reg, OMAP343X_CONTROL_PBIAS_LITE);
+ if (cpu_is_omap3630()) {
+ reg = omap_ctrl_readl(OMAP34XX_CONTROL_WKUP_CTRL);
+ reg |= OMAP36XX_GPIO_IO_PWRDNZ;
+ omap_ctrl_writel(reg, OMAP34XX_CONTROL_WKUP_CTRL);
+ }
+}
+
static void __init hsmmc2_internal_input_clk(void)
{
u32 reg;
@@ -356,6 +377,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, },
{ "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/pmu.c b/arch/arm/mach-omap2/pmu.c
index a69e9a33cb6d..d2adfebd3b3f 100644
--- a/arch/arm/mach-omap2/pmu.c
+++ b/arch/arm/mach-omap2/pmu.c
@@ -55,7 +55,7 @@ static int __init omap2_init_pmu(unsigned oh_num, char *oh_names[])
WARN(IS_ERR(omap_pmu_dev), "Can't build omap_device for %s.\n",
dev_name);
- return PTR_RET(omap_pmu_dev);
+ return PTR_ERR_OR_ZERO(omap_pmu_dev);
}
static int __init omap_init_pmu(void)
diff --git a/arch/arm/mach-omap2/prcm43xx.h b/arch/arm/mach-omap2/prcm43xx.h
index d0261996db6d..7eebc27fa892 100644
--- a/arch/arm/mach-omap2/prcm43xx.h
+++ b/arch/arm/mach-omap2/prcm43xx.h
@@ -146,4 +146,6 @@
#define AM43XX_CM_PER_HDQ1W_CLKCTRL_OFFSET 0x04a0
#define AM43XX_CM_PER_VPFE0_CLKCTRL_OFFSET 0x0068
#define AM43XX_CM_PER_VPFE1_CLKCTRL_OFFSET 0x0070
+#define AM43XX_CM_PER_EMIF_CLKCTRL_OFFSET 0x0720
+
#endif
diff --git a/arch/arm/mach-omap2/sdrc2xxx.c b/arch/arm/mach-omap2/sdrc2xxx.c
index ae3f1553158d..339b0ecb7c32 100644
--- a/arch/arm/mach-omap2/sdrc2xxx.c
+++ b/arch/arm/mach-omap2/sdrc2xxx.c
@@ -164,6 +164,6 @@ void omap2xxx_sdrc_init_params(u32 force_lock_to_unlock_mode)
mem_timings.slow_dll_ctrl |=
((mem_timings.fast_dll_ctrl & 0xF) | (1 << 2));
- /* 90 degree phase for anything below 133Mhz + disable DLL filter */
+ /* 90 degree phase for anything below 133MHz + disable DLL filter */
mem_timings.slow_dll_ctrl |= ((1 << 1) | (3 << 8));
}
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 57dee0c7cd2b..5fb50fe54153 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -203,7 +203,7 @@ static int __init omap_serial_early_init(void)
if (cmdline_find_option(uart_name)) {
console_uart_id = uart->num;
- if (console_loglevel >= 10) {
+ if (console_loglevel >= CONSOLE_LOGLEVEL_DEBUG) {
uart_debug = true;
pr_info("%s used as console in debug mode: uart%d clocks will not be gated",
uart_name, uart->num);
diff --git a/arch/arm/mach-omap2/sram242x.S b/arch/arm/mach-omap2/sram242x.S
index 2c88ff2d0236..53a2537cd75a 100644
--- a/arch/arm/mach-omap2/sram242x.S
+++ b/arch/arm/mach-omap2/sram242x.S
@@ -64,7 +64,7 @@ ENTRY(omap242x_sram_ddr_init)
mvn r9, #0x4 @ mask to get clear bit2
and r10, r10, r9 @ clear bit2 for lock mode.
orr r10, r10, #0x8 @ make sure DLL on (es2 bit pos)
- orr r10, r10, #0x2 @ 90 degree phase for all below 133Mhz
+ orr r10, r10, #0x2 @ 90 degree phase for all below 133MHz
str r10, [r11] @ commit to DLLA_CTRL
bl i_dll_wait @ wait for dll to lock
diff --git a/arch/arm/mach-omap2/sram243x.S b/arch/arm/mach-omap2/sram243x.S
index d5deb9761fc7..b3edd6f7f7db 100644
--- a/arch/arm/mach-omap2/sram243x.S
+++ b/arch/arm/mach-omap2/sram243x.S
@@ -64,7 +64,7 @@ ENTRY(omap243x_sram_ddr_init)
mvn r9, #0x4 @ mask to get clear bit2
and r10, r10, r9 @ clear bit2 for lock mode.
orr r10, r10, #0x8 @ make sure DLL on (es2 bit pos)
- orr r10, r10, #0x2 @ 90 degree phase for all below 133Mhz
+ orr r10, r10, #0x2 @ 90 degree phase for all below 133MHz
str r10, [r11] @ commit to DLLA_CTRL
bl i_dll_wait @ wait for dll to lock
diff --git a/arch/arm/mach-prima2/headsmp.S b/arch/arm/mach-prima2/headsmp.S
index d86fe33c5f53..209d9fc5c16c 100644
--- a/arch/arm/mach-prima2/headsmp.S
+++ b/arch/arm/mach-prima2/headsmp.S
@@ -15,7 +15,6 @@
* ready for them to initialise.
*/
ENTRY(sirfsoc_secondary_startup)
- bl v7_invalidate_l1
mrc p15, 0, r0, c0, c0, 5
and r0, r0, #15
adr r4, 1f
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 4087d334ecdf..2ceed407eda9 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -3,16 +3,15 @@
#
# Common support (must be linked before board specific support)
-obj-y += clock.o devices.o generic.o irq.o \
- reset.o
+obj-y += devices.o generic.o irq.o reset.o
obj-$(CONFIG_PM) += pm.o sleep.o standby.o
# Generic drivers that other drivers may depend upon
# SoC-specific code
-obj-$(CONFIG_PXA25x) += mfp-pxa2xx.o clock-pxa2xx.o pxa2xx.o pxa25x.o
-obj-$(CONFIG_PXA27x) += mfp-pxa2xx.o clock-pxa2xx.o pxa2xx.o pxa27x.o
-obj-$(CONFIG_PXA3xx) += mfp-pxa3xx.o clock-pxa3xx.o pxa3xx.o smemc.o pxa3xx-ulpi.o
+obj-$(CONFIG_PXA25x) += mfp-pxa2xx.o pxa2xx.o pxa25x.o
+obj-$(CONFIG_PXA27x) += mfp-pxa2xx.o pxa2xx.o pxa27x.o
+obj-$(CONFIG_PXA3xx) += mfp-pxa3xx.o pxa3xx.o smemc.o pxa3xx-ulpi.o
obj-$(CONFIG_CPU_PXA300) += pxa300.o
obj-$(CONFIG_CPU_PXA320) += pxa320.o
obj-$(CONFIG_CPU_PXA930) += pxa930.o
diff --git a/arch/arm/mach-pxa/clock-pxa2xx.c b/arch/arm/mach-pxa/clock-pxa2xx.c
deleted file mode 100644
index 9ee2ad6a0a07..000000000000
--- a/arch/arm/mach-pxa/clock-pxa2xx.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/clock-pxa2xx.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/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/syscore_ops.h>
-
-#include <mach/pxa2xx-regs.h>
-
-#include "clock.h"
-
-void clk_pxa2xx_cken_enable(struct clk *clk)
-{
- CKEN |= 1 << clk->cken;
-}
-
-void clk_pxa2xx_cken_disable(struct clk *clk)
-{
- CKEN &= ~(1 << clk->cken);
-}
-
-const struct clkops clk_pxa2xx_cken_ops = {
- .enable = clk_pxa2xx_cken_enable,
- .disable = clk_pxa2xx_cken_disable,
-};
-
-#ifdef CONFIG_PM
-static uint32_t saved_cken;
-
-static int pxa2xx_clock_suspend(void)
-{
- saved_cken = CKEN;
- return 0;
-}
-
-static void pxa2xx_clock_resume(void)
-{
- CKEN = saved_cken;
-}
-#else
-#define pxa2xx_clock_suspend NULL
-#define pxa2xx_clock_resume NULL
-#endif
-
-struct syscore_ops pxa2xx_clock_syscore_ops = {
- .suspend = pxa2xx_clock_suspend,
- .resume = pxa2xx_clock_resume,
-};
diff --git a/arch/arm/mach-pxa/clock-pxa3xx.c b/arch/arm/mach-pxa/clock-pxa3xx.c
deleted file mode 100644
index d4e9499832dc..000000000000
--- a/arch/arm/mach-pxa/clock-pxa3xx.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/clock-pxa3xx.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/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/syscore_ops.h>
-
-#include <mach/smemc.h>
-#include <mach/pxa3xx-regs.h>
-
-#include "clock.h"
-
-/* Crystal clock: 13MHz */
-#define BASE_CLK 13000000
-
-/* Ring Oscillator Clock: 60MHz */
-#define RO_CLK 60000000
-
-#define ACCR_D0CS (1 << 26)
-#define ACCR_PCCE (1 << 11)
-
-/* crystal frequency to HSIO bus frequency multiplier (HSS) */
-static unsigned char hss_mult[4] = { 8, 12, 16, 24 };
-
-/*
- * Get the clock frequency as reflected by CCSR and the turbo flag.
- * We assume these values have been applied via a fcs.
- * If info is not 0 we also display the current settings.
- */
-unsigned int pxa3xx_get_clk_frequency_khz(int info)
-{
- unsigned long acsr, xclkcfg;
- unsigned int t, xl, xn, hss, ro, XL, XN, CLK, HSS;
-
- /* Read XCLKCFG register turbo bit */
- __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
- t = xclkcfg & 0x1;
-
- acsr = ACSR;
-
- xl = acsr & 0x1f;
- xn = (acsr >> 8) & 0x7;
- hss = (acsr >> 14) & 0x3;
-
- XL = xl * BASE_CLK;
- XN = xn * XL;
-
- ro = acsr & ACCR_D0CS;
-
- CLK = (ro) ? RO_CLK : ((t) ? XN : XL);
- HSS = (ro) ? RO_CLK : hss_mult[hss] * BASE_CLK;
-
- if (info) {
- pr_info("RO Mode clock: %d.%02dMHz (%sactive)\n",
- RO_CLK / 1000000, (RO_CLK % 1000000) / 10000,
- (ro) ? "" : "in");
- pr_info("Run Mode clock: %d.%02dMHz (*%d)\n",
- XL / 1000000, (XL % 1000000) / 10000, xl);
- pr_info("Turbo Mode clock: %d.%02dMHz (*%d, %sactive)\n",
- XN / 1000000, (XN % 1000000) / 10000, xn,
- (t) ? "" : "in");
- pr_info("HSIO bus clock: %d.%02dMHz\n",
- HSS / 1000000, (HSS % 1000000) / 10000);
- }
-
- return CLK / 1000;
-}
-
-/*
- * Return the current AC97 clock frequency.
- */
-static unsigned long clk_pxa3xx_ac97_getrate(struct clk *clk)
-{
- unsigned long rate = 312000000;
- unsigned long ac97_div;
-
- ac97_div = AC97_DIV;
-
- /* This may loose precision for some rates but won't for the
- * standard 24.576MHz.
- */
- rate /= (ac97_div >> 12) & 0x7fff;
- rate *= (ac97_div & 0xfff);
-
- return rate;
-}
-
-/*
- * Return the current HSIO bus clock frequency
- */
-static unsigned long clk_pxa3xx_hsio_getrate(struct clk *clk)
-{
- unsigned long acsr;
- unsigned int hss, hsio_clk;
-
- acsr = ACSR;
-
- hss = (acsr >> 14) & 0x3;
- hsio_clk = (acsr & ACCR_D0CS) ? RO_CLK : hss_mult[hss] * BASE_CLK;
-
- return hsio_clk;
-}
-
-/* crystal frequency to static memory controller multiplier (SMCFS) */
-static unsigned int smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
-static unsigned int df_clkdiv[4] = { 1, 2, 4, 1 };
-
-static unsigned long clk_pxa3xx_smemc_getrate(struct clk *clk)
-{
- unsigned long acsr = ACSR;
- unsigned long memclkcfg = __raw_readl(MEMCLKCFG);
-
- return BASE_CLK * smcfs_mult[(acsr >> 23) & 0x7] /
- df_clkdiv[(memclkcfg >> 16) & 0x3];
-}
-
-void clk_pxa3xx_cken_enable(struct clk *clk)
-{
- unsigned long mask = 1ul << (clk->cken & 0x1f);
-
- if (clk->cken < 32)
- CKENA |= mask;
- else if (clk->cken < 64)
- CKENB |= mask;
- else
- CKENC |= mask;
-}
-
-void clk_pxa3xx_cken_disable(struct clk *clk)
-{
- unsigned long mask = 1ul << (clk->cken & 0x1f);
-
- if (clk->cken < 32)
- CKENA &= ~mask;
- else if (clk->cken < 64)
- CKENB &= ~mask;
- else
- CKENC &= ~mask;
-}
-
-const struct clkops clk_pxa3xx_cken_ops = {
- .enable = clk_pxa3xx_cken_enable,
- .disable = clk_pxa3xx_cken_disable,
-};
-
-const struct clkops clk_pxa3xx_hsio_ops = {
- .enable = clk_pxa3xx_cken_enable,
- .disable = clk_pxa3xx_cken_disable,
- .getrate = clk_pxa3xx_hsio_getrate,
-};
-
-const struct clkops clk_pxa3xx_ac97_ops = {
- .enable = clk_pxa3xx_cken_enable,
- .disable = clk_pxa3xx_cken_disable,
- .getrate = clk_pxa3xx_ac97_getrate,
-};
-
-const struct clkops clk_pxa3xx_smemc_ops = {
- .enable = clk_pxa3xx_cken_enable,
- .disable = clk_pxa3xx_cken_disable,
- .getrate = clk_pxa3xx_smemc_getrate,
-};
-
-static void clk_pout_enable(struct clk *clk)
-{
- OSCC |= OSCC_PEN;
-}
-
-static void clk_pout_disable(struct clk *clk)
-{
- OSCC &= ~OSCC_PEN;
-}
-
-const struct clkops clk_pxa3xx_pout_ops = {
- .enable = clk_pout_enable,
- .disable = clk_pout_disable,
-};
-
-#ifdef CONFIG_PM
-static uint32_t cken[2];
-static uint32_t accr;
-
-static int pxa3xx_clock_suspend(void)
-{
- cken[0] = CKENA;
- cken[1] = CKENB;
- accr = ACCR;
- return 0;
-}
-
-static void pxa3xx_clock_resume(void)
-{
- ACCR = accr;
- CKENA = cken[0];
- CKENB = cken[1];
-}
-#else
-#define pxa3xx_clock_suspend NULL
-#define pxa3xx_clock_resume NULL
-#endif
-
-struct syscore_ops pxa3xx_clock_syscore_ops = {
- .suspend = pxa3xx_clock_suspend,
- .resume = pxa3xx_clock_resume,
-};
diff --git a/arch/arm/mach-pxa/clock.c b/arch/arm/mach-pxa/clock.c
deleted file mode 100644
index 4d466102a027..000000000000
--- a/arch/arm/mach-pxa/clock.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/clock.c
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/clkdev.h>
-
-#include "clock.h"
-
-static DEFINE_SPINLOCK(clocks_lock);
-
-int clk_enable(struct clk *clk)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&clocks_lock, flags);
- if (clk->enabled++ == 0)
- clk->ops->enable(clk);
- spin_unlock_irqrestore(&clocks_lock, flags);
-
- if (clk->delay)
- udelay(clk->delay);
-
- return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
- unsigned long flags;
-
- WARN_ON(clk->enabled == 0);
-
- spin_lock_irqsave(&clocks_lock, flags);
- if (--clk->enabled == 0)
- clk->ops->disable(clk);
- spin_unlock_irqrestore(&clocks_lock, flags);
-}
-EXPORT_SYMBOL(clk_disable);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
- unsigned long rate;
-
- rate = clk->rate;
- if (clk->ops->getrate)
- rate = clk->ops->getrate(clk);
-
- return rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
- unsigned long flags;
- int ret = -EINVAL;
-
- if (clk->ops->setrate) {
- spin_lock_irqsave(&clocks_lock, flags);
- ret = clk->ops->setrate(clk, rate);
- spin_unlock_irqrestore(&clocks_lock, flags);
- }
-
- return ret;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-void clk_dummy_enable(struct clk *clk)
-{
-}
-
-void clk_dummy_disable(struct clk *clk)
-{
-}
-
-const struct clkops clk_dummy_ops = {
- .enable = clk_dummy_enable,
- .disable = clk_dummy_disable,
-};
-
-struct clk clk_dummy = {
- .ops = &clk_dummy_ops,
-};
diff --git a/arch/arm/mach-pxa/clock.h b/arch/arm/mach-pxa/clock.h
deleted file mode 100644
index 1f65d32c8d5e..000000000000
--- a/arch/arm/mach-pxa/clock.h
+++ /dev/null
@@ -1,80 +0,0 @@
-#include <linux/clkdev.h>
-#include <linux/syscore_ops.h>
-
-struct clkops {
- void (*enable)(struct clk *);
- void (*disable)(struct clk *);
- unsigned long (*getrate)(struct clk *);
- int (*setrate)(struct clk *, unsigned long);
-};
-
-struct clk {
- const struct clkops *ops;
- unsigned long rate;
- unsigned int cken;
- unsigned int delay;
- unsigned int enabled;
-};
-
-void clk_dummy_enable(struct clk *);
-void clk_dummy_disable(struct clk *);
-
-extern const struct clkops clk_dummy_ops;
-extern struct clk clk_dummy;
-
-#define INIT_CLKREG(_clk,_devname,_conname) \
- { \
- .clk = _clk, \
- .dev_id = _devname, \
- .con_id = _conname, \
- }
-
-#define DEFINE_CK(_name, _cken, _ops) \
-struct clk clk_##_name = { \
- .ops = _ops, \
- .cken = CKEN_##_cken, \
- }
-
-#define DEFINE_CLK(_name, _ops, _rate, _delay) \
-struct clk clk_##_name = { \
- .ops = _ops, \
- .rate = _rate, \
- .delay = _delay, \
- }
-
-#define DEFINE_PXA2_CKEN(_name, _cken, _rate, _delay) \
-struct clk clk_##_name = { \
- .ops = &clk_pxa2xx_cken_ops, \
- .rate = _rate, \
- .cken = CKEN_##_cken, \
- .delay = _delay, \
- }
-
-extern const struct clkops clk_pxa2xx_cken_ops;
-
-void clk_pxa2xx_cken_enable(struct clk *clk);
-void clk_pxa2xx_cken_disable(struct clk *clk);
-
-extern struct syscore_ops pxa2xx_clock_syscore_ops;
-
-#if defined(CONFIG_PXA3xx)
-#define DEFINE_PXA3_CKEN(_name, _cken, _rate, _delay) \
-struct clk clk_##_name = { \
- .ops = &clk_pxa3xx_cken_ops, \
- .rate = _rate, \
- .cken = CKEN_##_cken, \
- .delay = _delay, \
- }
-
-extern const struct clkops clk_pxa3xx_cken_ops;
-extern const struct clkops clk_pxa3xx_hsio_ops;
-extern const struct clkops clk_pxa3xx_ac97_ops;
-extern const struct clkops clk_pxa3xx_pout_ops;
-extern const struct clkops clk_pxa3xx_smemc_ops;
-
-extern void clk_pxa3xx_cken_enable(struct clk *);
-extern void clk_pxa3xx_cken_disable(struct clk *);
-
-extern struct syscore_ops pxa3xx_clock_syscore_ops;
-
-#endif
diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c
index cfb864173ce3..16dc95f68125 100644
--- a/arch/arm/mach-pxa/eseries.c
+++ b/arch/arm/mach-pxa/eseries.c
@@ -10,8 +10,10 @@
*
*/
+#include <linux/clkdev.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/clk-provider.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
@@ -39,7 +41,6 @@
#include "devices.h"
#include "generic.h"
-#include "clock.h"
/* Only e800 has 128MB RAM */
void __init eseries_fixup(struct tag *tags, char **cmdline)
@@ -125,27 +126,9 @@ struct resource eseries_tmio_resources[] = {
};
/* Some e-series hardware cannot control the 32K clock */
-static void clk_32k_dummy(struct clk *clk)
-{
-}
-
-static const struct clkops clk_32k_dummy_ops = {
- .enable = clk_32k_dummy,
- .disable = clk_32k_dummy,
-};
-
-static struct clk tmio_dummy_clk = {
- .ops = &clk_32k_dummy_ops,
- .rate = 32768,
-};
-
-static struct clk_lookup eseries_clkregs[] = {
- INIT_CLKREG(&tmio_dummy_clk, NULL, "CLK_CK32K"),
-};
-
static void __init eseries_register_clks(void)
{
- clkdev_add_table(eseries_clkregs, ARRAY_SIZE(eseries_clkregs));
+ clk_register_fixed_rate(NULL, "CLK_CK32K", NULL, CLK_IS_ROOT, 32768);
}
#ifdef CONFIG_MACH_E330
@@ -683,7 +666,7 @@ static unsigned long e750_pin_config[] __initdata = {
/* PC Card */
GPIO8_GPIO, /* CD0 */
GPIO44_GPIO, /* CD1 */
- GPIO11_GPIO, /* IRQ0 */
+ /* GPIO11_GPIO, IRQ0 */
GPIO6_GPIO, /* IRQ1 */
GPIO27_GPIO, /* RST0 */
GPIO24_GPIO, /* RST1 */
@@ -778,6 +761,9 @@ static unsigned long e800_pin_config[] __initdata = {
GPIO29_AC97_SDATA_IN_0,
GPIO30_AC97_SDATA_OUT,
GPIO31_AC97_SYNC,
+
+ /* tc6393xb */
+ GPIO11_3_6MHz,
};
static struct w100_gen_regs e800_lcd_regs = {
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 04b013fbc98f..ec510ecf8370 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -63,6 +63,12 @@ EXPORT_SYMBOL(get_clock_tick_rate);
*/
void __init pxa_timer_init(void)
{
+ if (cpu_is_pxa25x())
+ pxa25x_clocks_init();
+ if (cpu_is_pxa27x())
+ pxa27x_clocks_init();
+ if (cpu_is_pxa3xx())
+ pxa3xx_clocks_init();
pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x40a00000),
get_clock_tick_rate());
}
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index 7a9fa1aa4e41..0b1dbb54871a 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -26,17 +26,20 @@ extern void pxa_timer_init(void);
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
#define pxa25x_handle_irq icip_handle_irq
+extern int __init pxa25x_clocks_init(void);
extern void __init pxa25x_init_irq(void);
extern void __init pxa25x_map_io(void);
extern void __init pxa26x_init_irq(void);
#define pxa27x_handle_irq ichp_handle_irq
+extern int __init pxa27x_clocks_init(void);
extern void __init pxa27x_dt_init_irq(void);
extern unsigned pxa27x_get_clk_frequency_khz(int);
extern void __init pxa27x_init_irq(void);
extern void __init pxa27x_map_io(void);
#define pxa3xx_handle_irq ichp_handle_irq
+extern int __init pxa3xx_clocks_init(void);
extern void __init pxa3xx_dt_init_irq(void);
extern void __init pxa3xx_init_irq(void);
extern void __init pxa3xx_map_io(void);
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index 89a7c06570d3..98608c5575cb 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -138,7 +138,7 @@ static int pxa_irq_map(struct irq_domain *h, unsigned int virq,
return 0;
}
-static struct irq_domain_ops pxa_irq_ops = {
+static const struct irq_domain_ops pxa_irq_ops = {
.map = pxa_irq_map,
.xlate = irq_domain_xlate_onecell,
};
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 4ac9ab80d24b..6de32fa0e251 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -11,6 +11,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/clkdev.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/module.h>
@@ -57,7 +58,6 @@
#include <mach/smemc.h>
#include "generic.h"
-#include "clock.h"
#include "devices.h"
static unsigned long lubbock_pin_config[] __initdata = {
@@ -102,6 +102,9 @@ static unsigned long lubbock_pin_config[] __initdata = {
GPIO6_MMC_CLK,
GPIO8_MMC_CS0,
+ /* SA1111 chip */
+ GPIO11_3_6MHz,
+
/* wakeup */
GPIO1_GPIO | WAKEUP_ON_EDGE_RISE,
};
diff --git a/arch/arm/mach-pxa/mp900.c b/arch/arm/mach-pxa/mp900.c
index 854f1f562d6b..14f6aaf8fcc9 100644
--- a/arch/arm/mach-pxa/mp900.c
+++ b/arch/arm/mach-pxa/mp900.c
@@ -28,7 +28,7 @@
static void isp116x_pfm_delay(struct device *dev, int delay)
{
- /* 400Mhz PXA2 = 2.5ns / instruction */
+ /* 400MHz PXA2 = 2.5ns / instruction */
int cyc = delay / 10;
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 66e4a2b6316e..23a90c62ec11 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -38,187 +38,11 @@
#include "generic.h"
#include "devices.h"
-#include "clock.h"
/*
* Various clock factors driven by the CCCR register.
*/
-/* Crystal Frequency to Memory Frequency Multiplier (L) */
-static unsigned char L_clk_mult[32] = { 0, 27, 32, 36, 40, 45, 0, };
-
-/* Memory Frequency to Run Mode Frequency Multiplier (M) */
-static unsigned char M_clk_mult[4] = { 0, 1, 2, 4 };
-
-/* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */
-/* Note: we store the value N * 2 here. */
-static unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 };
-
-/* Crystal clock */
-#define BASE_CLK 3686400
-
-/*
- * Get the clock frequency as reflected by CCCR and the turbo flag.
- * We assume these values have been applied via a fcs.
- * If info is not 0 we also display the current settings.
- */
-unsigned int pxa25x_get_clk_frequency_khz(int info)
-{
- unsigned long cccr, turbo;
- unsigned int l, L, m, M, n2, N;
-
- cccr = CCCR;
- asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (turbo) );
-
- l = L_clk_mult[(cccr >> 0) & 0x1f];
- m = M_clk_mult[(cccr >> 5) & 0x03];
- n2 = N2_clk_mult[(cccr >> 7) & 0x07];
-
- L = l * BASE_CLK;
- M = m * L;
- N = n2 * M / 2;
-
- if(info)
- {
- L += 5000;
- printk( KERN_INFO "Memory clock: %d.%02dMHz (*%d)\n",
- L / 1000000, (L % 1000000) / 10000, l );
- M += 5000;
- printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n",
- M / 1000000, (M % 1000000) / 10000, m );
- N += 5000;
- printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n",
- N / 1000000, (N % 1000000) / 10000, n2 / 2, (n2 % 2) * 5,
- (turbo & 1) ? "" : "in" );
- }
-
- return (turbo & 1) ? (N/1000) : (M/1000);
-}
-
-static unsigned long clk_pxa25x_mem_getrate(struct clk *clk)
-{
- return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK;
-}
-
-static const struct clkops clk_pxa25x_mem_ops = {
- .enable = clk_dummy_enable,
- .disable = clk_dummy_disable,
- .getrate = clk_pxa25x_mem_getrate,
-};
-
-static const struct clkops clk_pxa25x_lcd_ops = {
- .enable = clk_pxa2xx_cken_enable,
- .disable = clk_pxa2xx_cken_disable,
- .getrate = clk_pxa25x_mem_getrate,
-};
-
-static unsigned long gpio12_config_32k[] = {
- GPIO12_32KHz,
-};
-
-static unsigned long gpio12_config_gpio[] = {
- GPIO12_GPIO,
-};
-
-static void clk_gpio12_enable(struct clk *clk)
-{
- pxa2xx_mfp_config(gpio12_config_32k, 1);
-}
-
-static void clk_gpio12_disable(struct clk *clk)
-{
- pxa2xx_mfp_config(gpio12_config_gpio, 1);
-}
-
-static const struct clkops clk_pxa25x_gpio12_ops = {
- .enable = clk_gpio12_enable,
- .disable = clk_gpio12_disable,
-};
-
-static unsigned long gpio11_config_3m6[] = {
- GPIO11_3_6MHz,
-};
-
-static unsigned long gpio11_config_gpio[] = {
- GPIO11_GPIO,
-};
-
-static void clk_gpio11_enable(struct clk *clk)
-{
- pxa2xx_mfp_config(gpio11_config_3m6, 1);
-}
-
-static void clk_gpio11_disable(struct clk *clk)
-{
- pxa2xx_mfp_config(gpio11_config_gpio, 1);
-}
-
-static const struct clkops clk_pxa25x_gpio11_ops = {
- .enable = clk_gpio11_enable,
- .disable = clk_gpio11_disable,
-};
-
-/*
- * 3.6864MHz -> OST, GPIO, SSP, PWM, PLLs (95.842MHz, 147.456MHz)
- * 95.842MHz -> MMC 19.169MHz, I2C 31.949MHz, FICP 47.923MHz, USB 47.923MHz
- * 147.456MHz -> UART 14.7456MHz, AC97 12.288MHz, I2S 5.672MHz (allegedly)
- */
-
-/*
- * PXA 2xx clock declarations.
- */
-static DEFINE_PXA2_CKEN(pxa25x_hwuart, HWUART, 14745600, 1);
-static DEFINE_PXA2_CKEN(pxa25x_ffuart, FFUART, 14745600, 1);
-static DEFINE_PXA2_CKEN(pxa25x_btuart, BTUART, 14745600, 1);
-static DEFINE_PXA2_CKEN(pxa25x_stuart, STUART, 14745600, 1);
-static DEFINE_PXA2_CKEN(pxa25x_usb, USB, 47923000, 5);
-static DEFINE_PXA2_CKEN(pxa25x_mmc, MMC, 19169000, 0);
-static DEFINE_PXA2_CKEN(pxa25x_i2c, I2C, 31949000, 0);
-static DEFINE_PXA2_CKEN(pxa25x_ssp, SSP, 3686400, 0);
-static DEFINE_PXA2_CKEN(pxa25x_nssp, NSSP, 3686400, 0);
-static DEFINE_PXA2_CKEN(pxa25x_assp, ASSP, 3686400, 0);
-static DEFINE_PXA2_CKEN(pxa25x_pwm0, PWM0, 3686400, 0);
-static DEFINE_PXA2_CKEN(pxa25x_pwm1, PWM1, 3686400, 0);
-static DEFINE_PXA2_CKEN(pxa25x_ac97, AC97, 24576000, 0);
-static DEFINE_PXA2_CKEN(pxa25x_i2s, I2S, 14745600, 0);
-static DEFINE_PXA2_CKEN(pxa25x_ficp, FICP, 47923000, 0);
-
-static DEFINE_CK(pxa25x_lcd, LCD, &clk_pxa25x_lcd_ops);
-static DEFINE_CLK(pxa25x_gpio11, &clk_pxa25x_gpio11_ops, 3686400, 0);
-static DEFINE_CLK(pxa25x_gpio12, &clk_pxa25x_gpio12_ops, 32768, 0);
-static DEFINE_CLK(pxa25x_mem, &clk_pxa25x_mem_ops, 0, 0);
-
-static struct clk_lookup pxa25x_clkregs[] = {
- INIT_CLKREG(&clk_pxa25x_lcd, "pxa2xx-fb", NULL),
- INIT_CLKREG(&clk_pxa25x_ffuart, "pxa2xx-uart.0", NULL),
- INIT_CLKREG(&clk_pxa25x_btuart, "pxa2xx-uart.1", NULL),
- INIT_CLKREG(&clk_pxa25x_stuart, "pxa2xx-uart.2", NULL),
- INIT_CLKREG(&clk_pxa25x_usb, "pxa25x-udc", NULL),
- INIT_CLKREG(&clk_pxa25x_mmc, "pxa2xx-mci.0", NULL),
- INIT_CLKREG(&clk_pxa25x_i2c, "pxa2xx-i2c.0", NULL),
- INIT_CLKREG(&clk_pxa25x_ssp, "pxa25x-ssp.0", NULL),
- INIT_CLKREG(&clk_pxa25x_nssp, "pxa25x-nssp.1", NULL),
- INIT_CLKREG(&clk_pxa25x_assp, "pxa25x-nssp.2", NULL),
- INIT_CLKREG(&clk_pxa25x_pwm0, "pxa25x-pwm.0", NULL),
- INIT_CLKREG(&clk_pxa25x_pwm1, "pxa25x-pwm.1", NULL),
- INIT_CLKREG(&clk_pxa25x_i2s, "pxa2xx-i2s", NULL),
- INIT_CLKREG(&clk_pxa25x_stuart, "pxa2xx-ir", "UARTCLK"),
- INIT_CLKREG(&clk_pxa25x_ficp, "pxa2xx-ir", "FICPCLK"),
- INIT_CLKREG(&clk_pxa25x_ac97, NULL, "AC97CLK"),
- INIT_CLKREG(&clk_pxa25x_gpio11, NULL, "GPIO11_CLK"),
- INIT_CLKREG(&clk_pxa25x_gpio12, NULL, "GPIO12_CLK"),
- INIT_CLKREG(&clk_pxa25x_mem, "pxa2xx-pcmcia", NULL),
-#ifdef CONFIG_CPU_PXA26x
- INIT_CLKREG(&clk_dummy, "pxa26x-gpio", NULL),
-#else
- INIT_CLKREG(&clk_dummy, "pxa25x-gpio", NULL),
-#endif
- INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL),
-};
-
-static struct clk_lookup pxa25x_hwuart_clkreg =
- INIT_CLKREG(&clk_pxa25x_hwuart, "pxa2xx-uart.3", NULL);
-
#ifdef CONFIG_PM
#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
@@ -374,8 +198,6 @@ static int __init pxa25x_init(void)
reset_status = RCSR;
- clkdev_add_table(pxa25x_clkregs, ARRAY_SIZE(pxa25x_clkregs));
-
if ((ret = pxa_init_dma(IRQ_DMA, 16)))
return ret;
@@ -383,7 +205,6 @@ static int __init pxa25x_init(void)
register_syscore_ops(&pxa_irq_syscore_ops);
register_syscore_ops(&pxa2xx_mfp_syscore_ops);
- register_syscore_ops(&pxa2xx_clock_syscore_ops);
pxa_register_device(&pxa25x_device_gpio, &pxa25x_gpio_info);
ret = platform_add_devices(pxa25x_devices,
@@ -392,10 +213,6 @@ static int __init pxa25x_init(void)
return ret;
}
- /* Only add HWUART for PXA255/26x; PXA210/250 do not have it. */
- if (cpu_is_pxa255())
- clkdev_add(&pxa25x_hwuart_clkreg);
-
return ret;
}
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index af423a48c2e3..b5abdeb5bb2d 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -37,7 +37,8 @@
#include "generic.h"
#include "devices.h"
-#include "clock.h"
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
void pxa27x_clear_otgph(void)
{
@@ -73,174 +74,6 @@ void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio)
}
EXPORT_SYMBOL_GPL(pxa27x_configure_ac97reset);
-/* Crystal clock: 13MHz */
-#define BASE_CLK 13000000
-
-/*
- * Get the clock frequency as reflected by CCSR and the turbo flag.
- * We assume these values have been applied via a fcs.
- * If info is not 0 we also display the current settings.
- */
-unsigned int pxa27x_get_clk_frequency_khz(int info)
-{
- unsigned long ccsr, clkcfg;
- unsigned int l, L, m, M, n2, N, S;
- int cccr_a, t, ht, b;
-
- ccsr = CCSR;
- cccr_a = CCCR & (1 << 25);
-
- /* Read clkcfg register: it has turbo, b, half-turbo (and f) */
- asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg) );
- t = clkcfg & (1 << 0);
- ht = clkcfg & (1 << 2);
- b = clkcfg & (1 << 3);
-
- l = ccsr & 0x1f;
- n2 = (ccsr>>7) & 0xf;
- m = (l <= 10) ? 1 : (l <= 20) ? 2 : 4;
-
- L = l * BASE_CLK;
- N = (L * n2) / 2;
- M = (!cccr_a) ? (L/m) : ((b) ? L : (L/2));
- S = (b) ? L : (L/2);
-
- if (info) {
- printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n",
- L / 1000000, (L % 1000000) / 10000, l );
- printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n",
- N / 1000000, (N % 1000000)/10000, n2 / 2, (n2 % 2)*5,
- (t) ? "" : "in" );
- printk( KERN_INFO "Memory clock: %d.%02dMHz (/%d)\n",
- M / 1000000, (M % 1000000) / 10000, m );
- printk( KERN_INFO "System bus clock: %d.%02dMHz \n",
- S / 1000000, (S % 1000000) / 10000 );
- }
-
- return (t) ? (N/1000) : (L/1000);
-}
-
-/*
- * Return the current mem clock frequency as reflected by CCCR[A], B, and L
- */
-static unsigned long clk_pxa27x_mem_getrate(struct clk *clk)
-{
- unsigned long ccsr, clkcfg;
- unsigned int l, L, m, M;
- int cccr_a, b;
-
- ccsr = CCSR;
- cccr_a = CCCR & (1 << 25);
-
- /* Read clkcfg register: it has turbo, b, half-turbo (and f) */
- asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg) );
- b = clkcfg & (1 << 3);
-
- l = ccsr & 0x1f;
- m = (l <= 10) ? 1 : (l <= 20) ? 2 : 4;
-
- L = l * BASE_CLK;
- M = (!cccr_a) ? (L/m) : ((b) ? L : (L/2));
-
- return M;
-}
-
-static const struct clkops clk_pxa27x_mem_ops = {
- .enable = clk_dummy_enable,
- .disable = clk_dummy_disable,
- .getrate = clk_pxa27x_mem_getrate,
-};
-
-/*
- * Return the current LCD clock frequency in units of 10kHz as
- */
-static unsigned int pxa27x_get_lcdclk_frequency_10khz(void)
-{
- unsigned long ccsr;
- unsigned int l, L, k, K;
-
- ccsr = CCSR;
-
- l = ccsr & 0x1f;
- k = (l <= 7) ? 1 : (l <= 16) ? 2 : 4;
-
- L = l * BASE_CLK;
- K = L / k;
-
- return (K / 10000);
-}
-
-static unsigned long clk_pxa27x_lcd_getrate(struct clk *clk)
-{
- return pxa27x_get_lcdclk_frequency_10khz() * 10000;
-}
-
-static const struct clkops clk_pxa27x_lcd_ops = {
- .enable = clk_pxa2xx_cken_enable,
- .disable = clk_pxa2xx_cken_disable,
- .getrate = clk_pxa27x_lcd_getrate,
-};
-
-static DEFINE_PXA2_CKEN(pxa27x_ffuart, FFUART, 14857000, 1);
-static DEFINE_PXA2_CKEN(pxa27x_btuart, BTUART, 14857000, 1);
-static DEFINE_PXA2_CKEN(pxa27x_stuart, STUART, 14857000, 1);
-static DEFINE_PXA2_CKEN(pxa27x_i2s, I2S, 14682000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_i2c, I2C, 32842000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_usb, USB, 48000000, 5);
-static DEFINE_PXA2_CKEN(pxa27x_mmc, MMC, 19500000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_ficp, FICP, 48000000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_usbhost, USBHOST, 48000000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_pwri2c, PWRI2C, 13000000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_keypad, KEYPAD, 32768, 0);
-static DEFINE_PXA2_CKEN(pxa27x_ssp1, SSP1, 13000000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_ssp2, SSP2, 13000000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_ssp3, SSP3, 13000000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_pwm0, PWM0, 13000000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_pwm1, PWM1, 13000000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_ac97, AC97, 24576000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_ac97conf, AC97CONF, 24576000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_msl, MSL, 48000000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_usim, USIM, 48000000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_memstk, MEMSTK, 19500000, 0);
-static DEFINE_PXA2_CKEN(pxa27x_im, IM, 0, 0);
-static DEFINE_PXA2_CKEN(pxa27x_memc, MEMC, 0, 0);
-
-static DEFINE_CK(pxa27x_lcd, LCD, &clk_pxa27x_lcd_ops);
-static DEFINE_CK(pxa27x_camera, CAMERA, &clk_pxa27x_lcd_ops);
-static DEFINE_CLK(pxa27x_mem, &clk_pxa27x_mem_ops, 0, 0);
-
-static struct clk_lookup pxa27x_clkregs[] = {
- INIT_CLKREG(&clk_pxa27x_lcd, "pxa2xx-fb", NULL),
- INIT_CLKREG(&clk_pxa27x_camera, "pxa27x-camera.0", NULL),
- INIT_CLKREG(&clk_pxa27x_ffuart, "pxa2xx-uart.0", NULL),
- INIT_CLKREG(&clk_pxa27x_btuart, "pxa2xx-uart.1", NULL),
- INIT_CLKREG(&clk_pxa27x_stuart, "pxa2xx-uart.2", NULL),
- INIT_CLKREG(&clk_pxa27x_i2s, "pxa2xx-i2s", NULL),
- INIT_CLKREG(&clk_pxa27x_i2c, "pxa2xx-i2c.0", NULL),
- INIT_CLKREG(&clk_pxa27x_usb, "pxa27x-udc", NULL),
- INIT_CLKREG(&clk_pxa27x_mmc, "pxa2xx-mci.0", NULL),
- INIT_CLKREG(&clk_pxa27x_stuart, "pxa2xx-ir", "UARTCLK"),
- INIT_CLKREG(&clk_pxa27x_ficp, "pxa2xx-ir", "FICPCLK"),
- INIT_CLKREG(&clk_pxa27x_usbhost, "pxa27x-ohci", NULL),
- INIT_CLKREG(&clk_pxa27x_pwri2c, "pxa2xx-i2c.1", NULL),
- INIT_CLKREG(&clk_pxa27x_keypad, "pxa27x-keypad", NULL),
- INIT_CLKREG(&clk_pxa27x_ssp1, "pxa27x-ssp.0", NULL),
- INIT_CLKREG(&clk_pxa27x_ssp2, "pxa27x-ssp.1", NULL),
- INIT_CLKREG(&clk_pxa27x_ssp3, "pxa27x-ssp.2", NULL),
- INIT_CLKREG(&clk_pxa27x_pwm0, "pxa27x-pwm.0", NULL),
- INIT_CLKREG(&clk_pxa27x_pwm1, "pxa27x-pwm.1", NULL),
- INIT_CLKREG(&clk_pxa27x_ac97, NULL, "AC97CLK"),
- INIT_CLKREG(&clk_pxa27x_ac97conf, NULL, "AC97CONFCLK"),
- INIT_CLKREG(&clk_pxa27x_msl, NULL, "MSLCLK"),
- INIT_CLKREG(&clk_pxa27x_usim, NULL, "USIMCLK"),
- INIT_CLKREG(&clk_pxa27x_memstk, NULL, "MSTKCLK"),
- INIT_CLKREG(&clk_pxa27x_im, NULL, "IMCLK"),
- INIT_CLKREG(&clk_pxa27x_memc, NULL, "MEMCLK"),
- INIT_CLKREG(&clk_pxa27x_mem, "pxa2xx-pcmcia", NULL),
- INIT_CLKREG(&clk_dummy, "pxa27x-gpio", NULL),
- INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL),
-};
-
#ifdef CONFIG_PM
#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
@@ -466,8 +299,6 @@ static int __init pxa27x_init(void)
reset_status = RCSR;
- clkdev_add_table(pxa27x_clkregs, ARRAY_SIZE(pxa27x_clkregs));
-
if ((ret = pxa_init_dma(IRQ_DMA, 32)))
return ret;
@@ -475,10 +306,13 @@ static int __init pxa27x_init(void)
register_syscore_ops(&pxa_irq_syscore_ops);
register_syscore_ops(&pxa2xx_mfp_syscore_ops);
- register_syscore_ops(&pxa2xx_clock_syscore_ops);
- pxa_register_device(&pxa27x_device_gpio, &pxa27x_gpio_info);
- ret = platform_add_devices(devices, ARRAY_SIZE(devices));
+ if (!of_have_populated_dt()) {
+ pxa_register_device(&pxa27x_device_gpio,
+ &pxa27x_gpio_info);
+ ret = platform_add_devices(devices,
+ ARRAY_SIZE(devices));
+ }
}
return ret;
diff --git a/arch/arm/mach-pxa/pxa300.c b/arch/arm/mach-pxa/pxa300.c
index 17cbc0c7bdb8..28c5b5686638 100644
--- a/arch/arm/mach-pxa/pxa300.c
+++ b/arch/arm/mach-pxa/pxa300.c
@@ -22,7 +22,6 @@
#include "generic.h"
#include "devices.h"
-#include "clock.h"
static struct mfp_addr_map pxa300_mfp_addr_map[] __initdata = {
@@ -84,32 +83,15 @@ static struct mfp_addr_map pxa310_mfp_addr_map[] __initdata = {
MFP_ADDR_END,
};
-static DEFINE_PXA3_CKEN(common_nand, NAND, 156000000, 0);
-static DEFINE_PXA3_CKEN(gcu, PXA300_GCU, 0, 0);
-
-static struct clk_lookup common_clkregs[] = {
- INIT_CLKREG(&clk_common_nand, "pxa3xx-nand", NULL),
- INIT_CLKREG(&clk_gcu, "pxa3xx-gcu", NULL),
-};
-
-static DEFINE_PXA3_CKEN(pxa310_mmc3, MMC3, 19500000, 0);
-
-static struct clk_lookup pxa310_clkregs[] = {
- INIT_CLKREG(&clk_pxa310_mmc3, "pxa2xx-mci.2", NULL),
-};
-
static int __init pxa300_init(void)
{
if (cpu_is_pxa300() || cpu_is_pxa310()) {
mfp_init_base(io_p2v(MFPR_BASE));
mfp_init_addr(pxa300_mfp_addr_map);
- clkdev_add_table(ARRAY_AND_SIZE(common_clkregs));
}
- if (cpu_is_pxa310()) {
+ if (cpu_is_pxa310())
mfp_init_addr(pxa310_mfp_addr_map);
- clkdev_add_table(ARRAY_AND_SIZE(pxa310_clkregs));
- }
return 0;
}
diff --git a/arch/arm/mach-pxa/pxa320.c b/arch/arm/mach-pxa/pxa320.c
index 6dc99d4f2dc6..2f55bb4b9087 100644
--- a/arch/arm/mach-pxa/pxa320.c
+++ b/arch/arm/mach-pxa/pxa320.c
@@ -22,7 +22,6 @@
#include "generic.h"
#include "devices.h"
-#include "clock.h"
static struct mfp_addr_map pxa320_mfp_addr_map[] __initdata = {
@@ -78,20 +77,11 @@ static struct mfp_addr_map pxa320_mfp_addr_map[] __initdata = {
MFP_ADDR_END,
};
-static DEFINE_PXA3_CKEN(pxa320_nand, NAND, 104000000, 0);
-static DEFINE_PXA3_CKEN(gcu, PXA320_GCU, 0, 0);
-
-static struct clk_lookup pxa320_clkregs[] = {
- INIT_CLKREG(&clk_pxa320_nand, "pxa3xx-nand", NULL),
- INIT_CLKREG(&clk_gcu, "pxa3xx-gcu", NULL),
-};
-
static int __init pxa320_init(void)
{
if (cpu_is_pxa320()) {
mfp_init_base(io_p2v(MFPR_BASE));
mfp_init_addr(pxa320_mfp_addr_map);
- clkdev_add_table(ARRAY_AND_SIZE(pxa320_clkregs));
}
return 0;
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index edcbd9c0bcb2..bd4cbef15ccf 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -37,67 +37,11 @@
#include "generic.h"
#include "devices.h"
-#include "clock.h"
#define PECR_IE(n) ((1 << ((n) * 2)) << 28)
#define PECR_IS(n) ((1 << ((n) * 2)) << 29)
extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int));
-
-static DEFINE_PXA3_CKEN(pxa3xx_ffuart, FFUART, 14857000, 1);
-static DEFINE_PXA3_CKEN(pxa3xx_btuart, BTUART, 14857000, 1);
-static DEFINE_PXA3_CKEN(pxa3xx_stuart, STUART, 14857000, 1);
-static DEFINE_PXA3_CKEN(pxa3xx_i2c, I2C, 32842000, 0);
-static DEFINE_PXA3_CKEN(pxa3xx_udc, UDC, 48000000, 5);
-static DEFINE_PXA3_CKEN(pxa3xx_usbh, USBH, 48000000, 0);
-static DEFINE_PXA3_CKEN(pxa3xx_u2d, USB2, 48000000, 0);
-static DEFINE_PXA3_CKEN(pxa3xx_keypad, KEYPAD, 32768, 0);
-static DEFINE_PXA3_CKEN(pxa3xx_ssp1, SSP1, 13000000, 0);
-static DEFINE_PXA3_CKEN(pxa3xx_ssp2, SSP2, 13000000, 0);
-static DEFINE_PXA3_CKEN(pxa3xx_ssp3, SSP3, 13000000, 0);
-static DEFINE_PXA3_CKEN(pxa3xx_ssp4, SSP4, 13000000, 0);
-static DEFINE_PXA3_CKEN(pxa3xx_pwm0, PWM0, 13000000, 0);
-static DEFINE_PXA3_CKEN(pxa3xx_pwm1, PWM1, 13000000, 0);
-static DEFINE_PXA3_CKEN(pxa3xx_mmc1, MMC1, 19500000, 0);
-static DEFINE_PXA3_CKEN(pxa3xx_mmc2, MMC2, 19500000, 0);
-static DEFINE_PXA3_CKEN(pxa3xx_gpio, GPIO, 13000000, 0);
-
-static DEFINE_CK(pxa3xx_lcd, LCD, &clk_pxa3xx_hsio_ops);
-static DEFINE_CK(pxa3xx_smemc, SMC, &clk_pxa3xx_smemc_ops);
-static DEFINE_CK(pxa3xx_camera, CAMERA, &clk_pxa3xx_hsio_ops);
-static DEFINE_CK(pxa3xx_ac97, AC97, &clk_pxa3xx_ac97_ops);
-static DEFINE_CLK(pxa3xx_pout, &clk_pxa3xx_pout_ops, 13000000, 70);
-
-static struct clk_lookup pxa3xx_clkregs[] = {
- INIT_CLKREG(&clk_pxa3xx_pout, NULL, "CLK_POUT"),
- /* Power I2C clock is always on */
- INIT_CLKREG(&clk_dummy, "pxa3xx-pwri2c.1", NULL),
- INIT_CLKREG(&clk_pxa3xx_lcd, "pxa2xx-fb", NULL),
- INIT_CLKREG(&clk_pxa3xx_camera, NULL, "CAMCLK"),
- INIT_CLKREG(&clk_pxa3xx_ac97, NULL, "AC97CLK"),
- INIT_CLKREG(&clk_pxa3xx_ffuart, "pxa2xx-uart.0", NULL),
- INIT_CLKREG(&clk_pxa3xx_btuart, "pxa2xx-uart.1", NULL),
- INIT_CLKREG(&clk_pxa3xx_stuart, "pxa2xx-uart.2", NULL),
- INIT_CLKREG(&clk_pxa3xx_stuart, "pxa2xx-ir", "UARTCLK"),
- INIT_CLKREG(&clk_pxa3xx_i2c, "pxa2xx-i2c.0", NULL),
- INIT_CLKREG(&clk_pxa3xx_udc, "pxa27x-udc", NULL),
- INIT_CLKREG(&clk_pxa3xx_usbh, "pxa27x-ohci", NULL),
- INIT_CLKREG(&clk_pxa3xx_u2d, "pxa3xx-u2d", NULL),
- INIT_CLKREG(&clk_pxa3xx_keypad, "pxa27x-keypad", NULL),
- INIT_CLKREG(&clk_pxa3xx_ssp1, "pxa3xx-ssp.0", NULL),
- INIT_CLKREG(&clk_pxa3xx_ssp2, "pxa3xx-ssp.1", NULL),
- INIT_CLKREG(&clk_pxa3xx_ssp3, "pxa3xx-ssp.2", NULL),
- INIT_CLKREG(&clk_pxa3xx_ssp4, "pxa3xx-ssp.3", NULL),
- INIT_CLKREG(&clk_pxa3xx_pwm0, "pxa27x-pwm.0", NULL),
- INIT_CLKREG(&clk_pxa3xx_pwm1, "pxa27x-pwm.1", NULL),
- INIT_CLKREG(&clk_pxa3xx_mmc1, "pxa2xx-mci.0", NULL),
- INIT_CLKREG(&clk_pxa3xx_mmc2, "pxa2xx-mci.1", NULL),
- INIT_CLKREG(&clk_pxa3xx_smemc, "pxa2xx-pcmcia", NULL),
- INIT_CLKREG(&clk_pxa3xx_gpio, "pxa3xx-gpio", NULL),
- INIT_CLKREG(&clk_pxa3xx_gpio, "pxa93x-gpio", NULL),
- INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL),
-};
-
#ifdef CONFIG_PM
#define ISRAM_START 0x5c000000
@@ -476,8 +420,6 @@ static int __init pxa3xx_init(void)
*/
ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S);
- clkdev_add_table(pxa3xx_clkregs, ARRAY_SIZE(pxa3xx_clkregs));
-
if ((ret = pxa_init_dma(IRQ_DMA, 32)))
return ret;
@@ -485,7 +427,6 @@ static int __init pxa3xx_init(void)
register_syscore_ops(&pxa_irq_syscore_ops);
register_syscore_ops(&pxa3xx_mfp_syscore_ops);
- register_syscore_ops(&pxa3xx_clock_syscore_ops);
if (of_have_populated_dt())
return 0;
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index 6dc4f025e674..88f70c37ad0d 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -56,7 +56,6 @@
#include "generic.h"
#include "devices.h"
-#include "clock.h"
/* common GPIO definitions */
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index 7780d1faa06f..e6e27c0468e4 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -12,6 +12,7 @@
*
*/
+#include <linux/clkdev.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
@@ -58,7 +59,6 @@
#include <asm/mach/sharpsl_param.h>
#include "generic.h"
-#include "clock.h"
#include "devices.h"
static unsigned long tosa_pin_config[] = {
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index c309593abdb2..44575edc44b1 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -35,20 +35,19 @@
#include <linux/mtd/physmap.h>
#include <linux/memblock.h>
+#include <clocksource/timer-sp804.h>
+
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/hardware/arm_timer.h>
#include <asm/hardware/icst.h>
#include <asm/mach/arch.h>
#include <asm/mach/irq.h>
#include <asm/mach/map.h>
-
#include <mach/platform.h>
#include <mach/irqs.h>
-#include <asm/hardware/timer-sp.h>
#include <plat/sched_clock.h>
@@ -381,10 +380,10 @@ void __init realview_timer_init(unsigned int timer_irq)
/*
* Initialise to a known state (all timers off)
*/
- writel(0, timer0_va_base + TIMER_CTRL);
- writel(0, timer1_va_base + TIMER_CTRL);
- writel(0, timer2_va_base + TIMER_CTRL);
- writel(0, timer3_va_base + TIMER_CTRL);
+ 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, timer_irq, "timer0");
diff --git a/arch/arm/mach-rockchip/core.h b/arch/arm/mach-rockchip/core.h
index 39bca96b555a..492c048813da 100644
--- a/arch/arm/mach-rockchip/core.h
+++ b/arch/arm/mach-rockchip/core.h
@@ -17,4 +17,3 @@ extern char rockchip_secondary_trampoline;
extern char rockchip_secondary_trampoline_end;
extern unsigned long rockchip_boot_fn;
-extern void rockchip_secondary_startup(void);
diff --git a/arch/arm/mach-rockchip/headsmp.S b/arch/arm/mach-rockchip/headsmp.S
index 46c22dedf632..d69708b07282 100644
--- a/arch/arm/mach-rockchip/headsmp.S
+++ b/arch/arm/mach-rockchip/headsmp.S
@@ -15,14 +15,6 @@
#include <linux/linkage.h>
#include <linux/init.h>
-ENTRY(rockchip_secondary_startup)
- mrc p15, 0, r0, c0, c0, 0 @ read main ID register
- ldr r1, =0x00000c09 @ Cortex-A9 primary part number
- teq r0, r1
- beq v7_invalidate_l1
- b secondary_startup
-ENDPROC(rockchip_secondary_startup)
-
ENTRY(rockchip_secondary_trampoline)
ldr pc, 1f
ENDPROC(rockchip_secondary_trampoline)
diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c
index 5b4ca3c3c879..2e6ab67e2284 100644
--- a/arch/arm/mach-rockchip/platsmp.c
+++ b/arch/arm/mach-rockchip/platsmp.c
@@ -149,8 +149,7 @@ static int __cpuinit rockchip_boot_secondary(unsigned int cpu,
* sram_base_addr + 8: start address for pc
* */
udelay(10);
- writel(virt_to_phys(rockchip_secondary_startup),
- sram_base_addr + 8);
+ writel(virt_to_phys(secondary_startup), sram_base_addr + 8);
writel(0xDEADBEAF, sram_base_addr + 4);
dsb_sev();
}
@@ -189,7 +188,7 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node)
}
/* set the boot function for the sram code */
- rockchip_boot_fn = virt_to_phys(rockchip_secondary_startup);
+ rockchip_boot_fn = virt_to_phys(secondary_startup);
/* copy the trampoline to sram, that runs during startup of the core */
memcpy(sram_base_addr, &rockchip_secondary_trampoline, trampoline_sz);
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
index 61ff91e76e0a..ebc4d58e1a32 100644
--- a/arch/arm/mach-sa1100/Makefile
+++ b/arch/arm/mach-sa1100/Makefile
@@ -3,7 +3,7 @@
#
# Common support
-obj-y := clock.o generic.o irq.o #nmi-oopser.o
+obj-y := clock.o generic.o #nmi-oopser.o
# Specific board support
obj-$(CONFIG_SA1100_ASSABET) += assabet.o
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index 40e0d8619a2d..345e63f4eb71 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -20,9 +20,12 @@
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
+#include <linux/irqchip/irq-sa11x0.h>
#include <video/sa1100fb.h>
+#include <soc/sa1100/pwer.h>
+
#include <asm/div64.h>
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
@@ -375,6 +378,18 @@ void __init sa1100_timer_init(void)
pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x90000000), 3686400);
}
+static struct resource irq_resource =
+ DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs");
+
+void __init sa1100_init_irq(void)
+{
+ request_resource(&iomem_resource, &irq_resource);
+
+ sa11x0_init_irq_nodt(IRQ_GPIO0_SC, irq_resource.start);
+
+ sa1100_init_gpio();
+}
+
/*
* Disable the memory bus request/grant signals on the SA1110 to
* ensure that we don't receive spurious memory requests. We set
@@ -416,3 +431,25 @@ void sa1110_mb_enable(void)
local_irq_restore(flags);
}
+int sa11x0_gpio_set_wake(unsigned int gpio, unsigned int on)
+{
+ if (on)
+ PWER |= BIT(gpio);
+ else
+ PWER &= ~BIT(gpio);
+
+ return 0;
+}
+
+int sa11x0_sc_set_wake(unsigned int irq, unsigned int on)
+{
+ if (BIT(irq) != IC_RTCAlrm)
+ return -EINVAL;
+
+ if (on)
+ PWER |= PWER_RTC;
+ else
+ PWER &= ~PWER_RTC;
+
+ return 0;
+}
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index af868d258e66..99d9a3b1bf34 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -327,8 +327,7 @@ static int neponset_probe(struct platform_device *dev)
irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip);
irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
- irq_set_handler_data(irq, d);
- irq_set_chained_handler(irq, neponset_irq_handler);
+ irq_set_chained_handler_and_data(irq, neponset_irq_handler, d);
/*
* We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 0fb484221c90..45006479d461 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -139,7 +139,7 @@ config MACH_ARMADILLO800EVA
select ARCH_REQUIRE_GPIOLIB
select REGULATOR_FIXED_VOLTAGE if REGULATOR
select SMSC_PHY if SH_ETH
- select SND_SOC_WM8978 if SND_SIMPLE_CARD
+ select SND_SOC_WM8978 if SND_SIMPLE_CARD && I2C
select USE_OF
config MACH_BOCKW
@@ -148,7 +148,7 @@ config MACH_BOCKW
select ARCH_REQUIRE_GPIOLIB
select REGULATOR_FIXED_VOLTAGE if REGULATOR
select SND_SOC_AK4554 if SND_SIMPLE_CARD
- select SND_SOC_AK4642 if SND_SIMPLE_CARD
+ select SND_SOC_AK4642 if SND_SIMPLE_CARD && I2C
select USE_OF
config MACH_BOCKW_REFERENCE
diff --git a/arch/arm/mach-shmobile/common.h b/arch/arm/mach-shmobile/common.h
index afc60bad6fd6..476092b86c6e 100644
--- a/arch/arm/mach-shmobile/common.h
+++ b/arch/arm/mach-shmobile/common.h
@@ -14,7 +14,6 @@ extern void shmobile_smp_sleep(void);
extern void shmobile_smp_hook(unsigned int cpu, unsigned long fn,
unsigned long arg);
extern int shmobile_smp_cpu_disable(unsigned int cpu);
-extern void shmobile_invalidate_start(void);
extern void shmobile_boot_scu(void);
extern void shmobile_smp_scu_prepare_cpus(unsigned int max_cpus);
extern void shmobile_smp_scu_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-shmobile/headsmp-scu.S b/arch/arm/mach-shmobile/headsmp-scu.S
index 69df8bfac167..fa5248c52399 100644
--- a/arch/arm/mach-shmobile/headsmp-scu.S
+++ b/arch/arm/mach-shmobile/headsmp-scu.S
@@ -22,7 +22,7 @@
* Boot code for secondary CPUs.
*
* First we turn on L1 cache coherency for our CPU. Then we jump to
- * shmobile_invalidate_start that invalidates the cache and hands over control
+ * secondary_startup that invalidates the cache and hands over control
* to the common ARM startup code.
*/
ENTRY(shmobile_boot_scu)
@@ -36,7 +36,7 @@ ENTRY(shmobile_boot_scu)
bic r2, r2, r3 @ Clear bits of our CPU (Run Mode)
str r2, [r0, #8] @ write back
- b shmobile_invalidate_start
+ b secondary_startup
ENDPROC(shmobile_boot_scu)
.text
diff --git a/arch/arm/mach-shmobile/headsmp.S b/arch/arm/mach-shmobile/headsmp.S
index 50c491567e11..330c1fc63197 100644
--- a/arch/arm/mach-shmobile/headsmp.S
+++ b/arch/arm/mach-shmobile/headsmp.S
@@ -16,13 +16,6 @@
#include <asm/assembler.h>
#include <asm/memory.h>
-#ifdef CONFIG_SMP
-ENTRY(shmobile_invalidate_start)
- bl v7_invalidate_l1
- b secondary_startup
-ENDPROC(shmobile_invalidate_start)
-#endif
-
/*
* Reset vector for secondary CPUs.
* This will be mapped at address 0 by SBAR register.
diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c
index f483b560b066..b0790fc32282 100644
--- a/arch/arm/mach-shmobile/platsmp-apmu.c
+++ b/arch/arm/mach-shmobile/platsmp-apmu.c
@@ -133,7 +133,7 @@ void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus,
int shmobile_smp_apmu_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
/* For this particular CPU register boot vector */
- shmobile_smp_hook(cpu, virt_to_phys(shmobile_invalidate_start), 0);
+ shmobile_smp_hook(cpu, virt_to_phys(secondary_startup), 0);
return apmu_wrap(cpu, apmu_power_on);
}
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c
index 9832e48396a4..00291cc1772d 100644
--- a/arch/arm/mach-shmobile/setup-r8a7740.c
+++ b/arch/arm/mach-shmobile/setup-r8a7740.c
@@ -13,7 +13,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -690,56 +689,6 @@ void __init r8a7740_meram_workaround(void)
}
}
-#define ICCR 0x0004
-#define ICSTART 0x0070
-
-#define i2c_read(reg, offset) ioread8(reg + offset)
-#define i2c_write(reg, offset, data) iowrite8(data, reg + offset)
-
-/*
- * r8a7740 chip has lasting errata on I2C I/O pad reset.
- * this is work-around for it.
- */
-static void r8a7740_i2c_workaround(struct platform_device *pdev)
-{
- struct resource *res;
- void __iomem *reg;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(!res)) {
- pr_err("r8a7740 i2c workaround fail (cannot find resource)\n");
- return;
- }
-
- reg = ioremap(res->start, resource_size(res));
- if (unlikely(!reg)) {
- pr_err("r8a7740 i2c workaround fail (cannot map IO)\n");
- return;
- }
-
- i2c_write(reg, ICCR, i2c_read(reg, ICCR) | 0x80);
- i2c_read(reg, ICCR); /* dummy read */
-
- i2c_write(reg, ICSTART, i2c_read(reg, ICSTART) | 0x10);
- i2c_read(reg, ICSTART); /* dummy read */
-
- udelay(10);
-
- i2c_write(reg, ICCR, 0x01);
- i2c_write(reg, ICSTART, 0x00);
-
- udelay(10);
-
- i2c_write(reg, ICCR, 0x10);
- udelay(10);
- i2c_write(reg, ICCR, 0x00);
- udelay(10);
- i2c_write(reg, ICCR, 0x10);
- udelay(10);
-
- iounmap(reg);
-}
-
void __init r8a7740_add_standard_devices(void)
{
static struct pm_domain_device domain_devices[] __initdata = {
@@ -766,10 +715,6 @@ void __init r8a7740_add_standard_devices(void)
{ "A3SP", &usb_dma_device },
};
- /* I2C work-around */
- r8a7740_i2c_workaround(&i2c0_device);
- r8a7740_i2c_workaround(&i2c1_device);
-
r8a7740_init_pm_domains();
/* add devices */
diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index b5f8d75d51a0..90efdeb56be5 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -1,5 +1,6 @@
-config ARCH_SOCFPGA
+menuconfig ARCH_SOCFPGA
bool "Altera SOCFPGA family" if ARCH_MULTI_V7
+ select ARCH_SUPPORTS_BIG_ENDIAN
select ARM_AMBA
select ARM_GIC
select CACHE_L2X0
@@ -8,3 +9,11 @@ config ARCH_SOCFPGA
select HAVE_ARM_SCU
select HAVE_ARM_TWD if SMP
select MFD_SYSCON
+
+if ARCH_SOCFPGA
+config SOCFPGA_SUSPEND
+ bool "Suspend to RAM on SOCFPGA"
+ help
+ Select this if you want to enable Suspend-to-RAM on SOCFPGA
+ platforms.
+endif
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index 6dd7a93a90fe..b8f9e238e4ab 100644
--- a/arch/arm/mach-socfpga/Makefile
+++ b/arch/arm/mach-socfpga/Makefile
@@ -4,3 +4,4 @@
obj-y := socfpga.o
obj-$(CONFIG_SMP) += headsmp.o platsmp.o
+obj-$(CONFIG_SOCFPGA_SUSPEND) += pm.o self-refresh.o
diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h
index a0f3b1cd497c..7259c3732702 100644
--- a/arch/arm/mach-socfpga/core.h
+++ b/arch/arm/mach-socfpga/core.h
@@ -1,6 +1,6 @@
/*
* Copyright 2012 Pavel Machek <pavel@denx.de>
- * Copyright (C) 2012 Altera Corporation
+ * Copyright (C) 2012-2015 Altera 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
@@ -25,22 +25,24 @@
#define SOCFPGA_RSTMGR_MODPERRST 0x14
#define SOCFPGA_RSTMGR_BRGMODRST 0x1c
+#define SOCFPGA_A10_RSTMGR_MODMPURST 0x20
+
/* System Manager bits */
#define RSTMGR_CTRL_SWCOLDRSTREQ 0x1 /* Cold Reset */
#define RSTMGR_CTRL_SWWARMRSTREQ 0x2 /* Warm Reset */
#define RSTMGR_MPUMODRST_CPU1 0x2 /* CPU1 Reset */
-extern void socfpga_secondary_startup(void);
-extern void __iomem *socfpga_scu_base_addr;
-
extern void socfpga_init_clocks(void);
extern void socfpga_sysmgr_init(void);
extern void __iomem *sys_manager_base_addr;
extern void __iomem *rst_manager_base_addr;
+extern void __iomem *sdr_ctl_base_addr;
+
+u32 socfpga_sdram_self_refresh(u32 sdr_base);
+extern unsigned int socfpga_sdram_self_refresh_sz;
-extern struct smp_operations socfpga_smp_ops;
extern char secondary_trampoline, secondary_trampoline_end;
extern unsigned long socfpga_cpu1start_addr;
diff --git a/arch/arm/mach-socfpga/headsmp.S b/arch/arm/mach-socfpga/headsmp.S
index f65ea0af4af3..5d94b7a2fb10 100644
--- a/arch/arm/mach-socfpga/headsmp.S
+++ b/arch/arm/mach-socfpga/headsmp.S
@@ -10,6 +10,7 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/memory.h>
+#include <asm/assembler.h>
.arch armv7-a
@@ -18,20 +19,17 @@ ENTRY(secondary_trampoline)
* Thus, we can just subtract the PAGE_OFFSET to get the physical
* address of &cpu1start_addr. This would not work for platforms
* where the physical memory does not start at 0x0.
- */
+ */
+ARM_BE8(setend be)
adr r0, 1f
ldmia r0, {r1, r2}
sub r2, r2, #PAGE_OFFSET
ldr r3, [r2]
ldr r4, [r3]
+ARM_BE8(rev r4, r4)
bx r4
.align
1: .long .
.long socfpga_cpu1start_addr
ENTRY(secondary_trampoline_end)
-
-ENTRY(socfpga_secondary_startup)
- bl v7_invalidate_l1
- b secondary_startup
-ENDPROC(socfpga_secondary_startup)
diff --git a/arch/arm/mach-socfpga/platsmp.c b/arch/arm/mach-socfpga/platsmp.c
index c64d89b7c0ca..c6f1df89f9af 100644
--- a/arch/arm/mach-socfpga/platsmp.c
+++ b/arch/arm/mach-socfpga/platsmp.c
@@ -40,7 +40,7 @@ static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle)
memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size);
- writel(virt_to_phys(socfpga_secondary_startup),
+ writel(virt_to_phys(secondary_startup),
sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff));
flush_cache_all();
@@ -54,32 +54,43 @@ static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle)
return 0;
}
-/*
- * Initialise the CPU possible map early - this describes the CPUs
- * which may be present or become present in the system.
- */
-static void __init socfpga_smp_init_cpus(void)
+static int socfpga_a10_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
- unsigned int i, ncores;
+ int trampoline_size = &secondary_trampoline_end - &secondary_trampoline;
- ncores = scu_get_core_count(socfpga_scu_base_addr);
+ if (socfpga_cpu1start_addr) {
+ writel(RSTMGR_MPUMODRST_CPU1, rst_manager_base_addr +
+ SOCFPGA_A10_RSTMGR_MODMPURST);
+ memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size);
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ writel(virt_to_phys(secondary_startup),
+ sys_manager_base_addr + (socfpga_cpu1start_addr & 0x00000fff));
- /* sanity check */
- if (ncores > num_possible_cpus()) {
- pr_warn("socfpga: no. of cores (%d) greater than configured"
- "maximum of %d - clipping\n", ncores, num_possible_cpus());
- ncores = num_possible_cpus();
+ flush_cache_all();
+ smp_wmb();
+ outer_clean_range(0, trampoline_size);
+
+ /* This will release CPU #1 out of reset. */
+ writel(0, rst_manager_base_addr + SOCFPGA_A10_RSTMGR_MODMPURST);
}
- for (i = 0; i < ncores; i++)
- set_cpu_possible(i, true);
+ return 0;
}
static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus)
{
+ struct device_node *np;
+ void __iomem *socfpga_scu_base_addr;
+
+ np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
+ if (!np) {
+ pr_err("%s: missing scu\n", __func__);
+ return;
+ }
+
+ socfpga_scu_base_addr = of_iomap(np, 0);
+ if (!socfpga_scu_base_addr)
+ return;
scu_enable(socfpga_scu_base_addr);
}
@@ -95,11 +106,21 @@ static void socfpga_cpu_die(unsigned int cpu)
cpu_do_idle();
}
-struct smp_operations socfpga_smp_ops __initdata = {
- .smp_init_cpus = socfpga_smp_init_cpus,
+static struct smp_operations socfpga_smp_ops __initdata = {
.smp_prepare_cpus = socfpga_smp_prepare_cpus,
.smp_boot_secondary = socfpga_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_die = socfpga_cpu_die,
#endif
};
+
+static struct smp_operations socfpga_a10_smp_ops __initdata = {
+ .smp_prepare_cpus = socfpga_smp_prepare_cpus,
+ .smp_boot_secondary = socfpga_a10_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = socfpga_cpu_die,
+#endif
+};
+
+CPU_METHOD_OF_DECLARE(socfpga_smp, "altr,socfpga-smp", &socfpga_smp_ops);
+CPU_METHOD_OF_DECLARE(socfpga_a10_smp, "altr,socfpga-a10-smp", &socfpga_a10_smp_ops);
diff --git a/arch/arm/mach-socfpga/pm.c b/arch/arm/mach-socfpga/pm.c
new file mode 100644
index 000000000000..1ed89fc2b7a8
--- /dev/null
+++ b/arch/arm/mach-socfpga/pm.c
@@ -0,0 +1,149 @@
+/*
+ * arch/arm/mach-socfpga/pm.c
+ *
+ * Copyright (C) 2014-2015 Altera Corporation. All rights reserved.
+ *
+ * with code from pm-imx6.c
+ * Copyright 2011-2014 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * 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/bitops.h>
+#include <linux/genalloc.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/suspend.h>
+#include <asm/suspend.h>
+#include <asm/fncpy.h>
+#include "core.h"
+
+/* Pointer to function copied to ocram */
+static u32 (*socfpga_sdram_self_refresh_in_ocram)(u32 sdr_base);
+
+static int socfpga_setup_ocram_self_refresh(void)
+{
+ struct platform_device *pdev;
+ phys_addr_t ocram_pbase;
+ struct device_node *np;
+ struct gen_pool *ocram_pool;
+ unsigned long ocram_base;
+ void __iomem *suspend_ocram_base;
+ int ret = 0;
+
+ np = of_find_compatible_node(NULL, NULL, "mmio-sram");
+ if (!np) {
+ pr_err("%s: Unable to find mmio-sram in dtb\n", __func__);
+ return -ENODEV;
+ }
+
+ pdev = of_find_device_by_node(np);
+ if (!pdev) {
+ pr_warn("%s: failed to find ocram device!\n", __func__);
+ ret = -ENODEV;
+ goto put_node;
+ }
+
+ ocram_pool = dev_get_gen_pool(&pdev->dev);
+ if (!ocram_pool) {
+ pr_warn("%s: ocram pool unavailable!\n", __func__);
+ ret = -ENODEV;
+ goto put_node;
+ }
+
+ ocram_base = gen_pool_alloc(ocram_pool, socfpga_sdram_self_refresh_sz);
+ if (!ocram_base) {
+ pr_warn("%s: unable to alloc ocram!\n", __func__);
+ ret = -ENOMEM;
+ goto put_node;
+ }
+
+ ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base);
+
+ suspend_ocram_base = __arm_ioremap_exec(ocram_pbase,
+ socfpga_sdram_self_refresh_sz,
+ false);
+ if (!suspend_ocram_base) {
+ pr_warn("%s: __arm_ioremap_exec failed!\n", __func__);
+ ret = -ENOMEM;
+ goto put_node;
+ }
+
+ /* Copy the code that puts DDR in self refresh to ocram */
+ socfpga_sdram_self_refresh_in_ocram =
+ (void *)fncpy(suspend_ocram_base,
+ &socfpga_sdram_self_refresh,
+ socfpga_sdram_self_refresh_sz);
+
+ WARN(!socfpga_sdram_self_refresh_in_ocram,
+ "could not copy function to ocram");
+ if (!socfpga_sdram_self_refresh_in_ocram)
+ ret = -EFAULT;
+
+put_node:
+ of_node_put(np);
+
+ return ret;
+}
+
+static int socfpga_pm_suspend(unsigned long arg)
+{
+ u32 ret;
+
+ if (!sdr_ctl_base_addr)
+ return -EFAULT;
+
+ ret = socfpga_sdram_self_refresh_in_ocram((u32)sdr_ctl_base_addr);
+
+ pr_debug("%s self-refresh loops request=%d exit=%d\n", __func__,
+ ret & 0xffff, (ret >> 16) & 0xffff);
+
+ return 0;
+}
+
+static int socfpga_pm_enter(suspend_state_t state)
+{
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ outer_disable();
+ cpu_suspend(0, socfpga_pm_suspend);
+ outer_resume();
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct platform_suspend_ops socfpga_pm_ops = {
+ .valid = suspend_valid_only_mem,
+ .enter = socfpga_pm_enter,
+};
+
+static int __init socfpga_pm_init(void)
+{
+ int ret;
+
+ ret = socfpga_setup_ocram_self_refresh();
+ if (ret)
+ return ret;
+
+ suspend_set_ops(&socfpga_pm_ops);
+ pr_info("SoCFPGA initialized for DDR self-refresh during suspend.\n");
+
+ return 0;
+}
+arch_initcall(socfpga_pm_init);
diff --git a/arch/arm/mach-socfpga/self-refresh.S b/arch/arm/mach-socfpga/self-refresh.S
new file mode 100644
index 000000000000..f2d7f883e33d
--- /dev/null
+++ b/arch/arm/mach-socfpga/self-refresh.S
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2014-2015 Altera 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/linkage.h>
+#include <asm/assembler.h>
+
+#define MAX_LOOP_COUNT 1000
+
+/* Register offset */
+#define SDR_CTRLGRP_LOWPWREQ_ADDR 0x54
+#define SDR_CTRLGRP_LOWPWRACK_ADDR 0x58
+
+/* Bitfield positions */
+#define SELFRSHREQ_POS 3
+#define SELFRSHREQ_MASK 0x8
+
+#define SELFRFSHACK_POS 1
+#define SELFRFSHACK_MASK 0x2
+
+ /*
+ * This code assumes that when the bootloader configured
+ * the sdram controller for the DDR on the board it
+ * configured the following fields depending on the DDR
+ * vendor/configuration:
+ *
+ * sdr.ctrlcfg.lowpwreq.selfrfshmask
+ * sdr.ctrlcfg.lowpwrtiming.clkdisablecycles
+ * sdr.ctrlcfg.dramtiming4.selfrfshexit
+ */
+
+ .arch armv7-a
+ .text
+ .align 3
+
+ /*
+ * socfpga_sdram_self_refresh
+ *
+ * r0 : sdr_ctl_base_addr
+ * r1 : temp storage of return value
+ * r2 : temp storage of register values
+ * r3 : loop counter
+ *
+ * return value: lower 16 bits: loop count going into self refresh
+ * upper 16 bits: loop count exiting self refresh
+ */
+ENTRY(socfpga_sdram_self_refresh)
+ /* Enable dynamic clock gating in the Power Control Register. */
+ mrc p15, 0, r2, c15, c0, 0
+ orr r2, r2, #1
+ mcr p15, 0, r2, c15, c0, 0
+
+ /* Enable self refresh: set sdr.ctrlgrp.lowpwreq.selfrshreq = 1 */
+ ldr r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR]
+ orr r2, r2, #SELFRSHREQ_MASK
+ str r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR]
+
+ /* Poll until sdr.ctrlgrp.lowpwrack.selfrfshack == 1 or hit max loops */
+ mov r3, #0
+while_ack_0:
+ ldr r2, [r0, #SDR_CTRLGRP_LOWPWRACK_ADDR]
+ and r2, r2, #SELFRFSHACK_MASK
+ cmp r2, #SELFRFSHACK_MASK
+ beq ack_1
+
+ add r3, #1
+ cmp r3, #MAX_LOOP_COUNT
+ bne while_ack_0
+
+ack_1:
+ mov r1, r3
+
+ /*
+ * Execute an ISB instruction to ensure that all of the
+ * CP15 register changes have been committed.
+ */
+ isb
+
+ /*
+ * Execute a barrier instruction to ensure that all cache,
+ * TLB and branch predictor maintenance operations issued
+ * by any CPU in the cluster have completed.
+ */
+ dsb
+ dmb
+
+ wfi
+
+ /* Disable self-refresh: set sdr.ctrlgrp.lowpwreq.selfrshreq = 0 */
+ ldr r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR]
+ bic r2, r2, #SELFRSHREQ_MASK
+ str r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR]
+
+ /* Poll until sdr.ctrlgrp.lowpwrack.selfrfshack == 0 or hit max loops */
+ mov r3, #0
+while_ack_1:
+ ldr r2, [r0, #SDR_CTRLGRP_LOWPWRACK_ADDR]
+ and r2, r2, #SELFRFSHACK_MASK
+ cmp r2, #SELFRFSHACK_MASK
+ bne ack_0
+
+ add r3, #1
+ cmp r3, #MAX_LOOP_COUNT
+ bne while_ack_1
+
+ack_0:
+ /*
+ * Prepare return value:
+ * Shift loop count for exiting self refresh into upper 16 bits.
+ * Leave loop count for requesting self refresh in lower 16 bits.
+ */
+ mov r3, r3, lsl #16
+ add r1, r1, r3
+
+ /* Disable dynamic clock gating in the Power Control Register. */
+ mrc p15, 0, r2, c15, c0, 0
+ bic r2, r2, #1
+ mcr p15, 0, r2, c15, c0, 0
+
+ mov r0, r1 @ return value
+ bx lr @ return
+
+ENDPROC(socfpga_sdram_self_refresh)
+ENTRY(socfpga_sdram_self_refresh_sz)
+ .word . - socfpga_sdram_self_refresh
diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c
index f5e597c207b9..19643a756c48 100644
--- a/arch/arm/mach-socfpga/socfpga.c
+++ b/arch/arm/mach-socfpga/socfpga.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Altera Corporation
+ * Copyright (C) 2012-2015 Altera 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
@@ -27,43 +27,11 @@
#include "core.h"
-void __iomem *socfpga_scu_base_addr = ((void __iomem *)(SOCFPGA_SCU_VIRT_BASE));
void __iomem *sys_manager_base_addr;
void __iomem *rst_manager_base_addr;
+void __iomem *sdr_ctl_base_addr;
unsigned long socfpga_cpu1start_addr;
-static struct map_desc scu_io_desc __initdata = {
- .virtual = SOCFPGA_SCU_VIRT_BASE,
- .pfn = 0, /* run-time */
- .length = SZ_8K,
- .type = MT_DEVICE,
-};
-
-static struct map_desc uart_io_desc __initdata = {
- .virtual = 0xfec02000,
- .pfn = __phys_to_pfn(0xffc02000),
- .length = SZ_8K,
- .type = MT_DEVICE,
-};
-
-static void __init socfpga_scu_map_io(void)
-{
- unsigned long base;
-
- /* Get SCU base */
- asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
-
- scu_io_desc.pfn = __phys_to_pfn(base);
- iotable_init(&scu_io_desc, 1);
-}
-
-static void __init socfpga_map_io(void)
-{
- socfpga_scu_map_io();
- iotable_init(&uart_io_desc, 1);
- early_printk("Early printk initialized\n");
-}
-
void __init socfpga_sysmgr_init(void)
{
struct device_node *np;
@@ -82,6 +50,9 @@ void __init socfpga_sysmgr_init(void)
np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr");
rst_manager_base_addr = of_iomap(np, 0);
+
+ np = of_find_compatible_node(NULL, NULL, "altr,sdr-ctl");
+ sdr_ctl_base_addr = of_iomap(np, 0);
}
static void __init socfpga_init_irq(void)
@@ -111,8 +82,6 @@ static const char *altera_dt_match[] = {
DT_MACHINE_START(SOCFPGA, "Altera SOCFPGA")
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
- .smp = smp_ops(socfpga_smp_ops),
- .map_io = socfpga_map_io,
.init_irq = socfpga_init_irq,
.restart = socfpga_cyclone5_restart,
.dt_compat = altera_dt_match,
diff --git a/arch/arm/mach-sti/Kconfig b/arch/arm/mach-sti/Kconfig
index 3b1ac463a494..125865daaf17 100644
--- a/arch/arm/mach-sti/Kconfig
+++ b/arch/arm/mach-sti/Kconfig
@@ -1,6 +1,7 @@
menuconfig ARCH_STI
bool "STMicroelectronics Consumer Electronics SOCs" if ARCH_MULTI_V7
select ARM_GIC
+ select ST_IRQCHIP
select ARM_GLOBAL_TIMER
select PINCTRL
select PINCTRL_ST
diff --git a/arch/arm/mach-stm32/Makefile b/arch/arm/mach-stm32/Makefile
new file mode 100644
index 000000000000..bd0b7b5d6e9d
--- /dev/null
+++ b/arch/arm/mach-stm32/Makefile
@@ -0,0 +1 @@
+obj-y += board-dt.o
diff --git a/arch/arm/mach-stm32/Makefile.boot b/arch/arm/mach-stm32/Makefile.boot
new file mode 100644
index 000000000000..eacfc3f5c33e
--- /dev/null
+++ b/arch/arm/mach-stm32/Makefile.boot
@@ -0,0 +1,3 @@
+# Empty file waiting for deletion once Makefile.boot isn't needed any more.
+# Patch waits for application at
+# http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7889/1 .
diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c
new file mode 100644
index 000000000000..f2ad7723d034
--- /dev/null
+++ b/arch/arm/mach-stm32/board-dt.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <asm/v7m.h>
+#include <asm/mach/arch.h>
+
+static const char *const stm32_compat[] __initconst = {
+ "st,stm32f429",
+ NULL
+};
+
+DT_MACHINE_START(STM32DT, "STM32 (Device Tree Support)")
+ .dt_compat = stm32_compat,
+ .restart = armv7m_restart,
+MACHINE_END
diff --git a/arch/arm/mach-sunxi/platsmp.c b/arch/arm/mach-sunxi/platsmp.c
index 587b0468efcc..e8483ec79d67 100644
--- a/arch/arm/mach-sunxi/platsmp.c
+++ b/arch/arm/mach-sunxi/platsmp.c
@@ -121,3 +121,72 @@ static struct smp_operations sun6i_smp_ops __initdata = {
.smp_boot_secondary = sun6i_smp_boot_secondary,
};
CPU_METHOD_OF_DECLARE(sun6i_a31_smp, "allwinner,sun6i-a31", &sun6i_smp_ops);
+
+static void __init sun8i_smp_prepare_cpus(unsigned int max_cpus)
+{
+ struct device_node *node;
+
+ node = of_find_compatible_node(NULL, NULL, "allwinner,sun8i-a23-prcm");
+ if (!node) {
+ pr_err("Missing A23 PRCM node in the device tree\n");
+ return;
+ }
+
+ prcm_membase = of_iomap(node, 0);
+ if (!prcm_membase) {
+ pr_err("Couldn't map A23 PRCM registers\n");
+ return;
+ }
+
+ node = of_find_compatible_node(NULL, NULL,
+ "allwinner,sun8i-a23-cpuconfig");
+ if (!node) {
+ pr_err("Missing A23 CPU config node in the device tree\n");
+ return;
+ }
+
+ cpucfg_membase = of_iomap(node, 0);
+ if (!cpucfg_membase)
+ pr_err("Couldn't map A23 CPU config registers\n");
+
+}
+
+static int sun8i_smp_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ u32 reg;
+
+ if (!(prcm_membase && cpucfg_membase))
+ return -EFAULT;
+
+ spin_lock(&cpu_lock);
+
+ /* Set CPU boot address */
+ writel(virt_to_phys(secondary_startup),
+ cpucfg_membase + CPUCFG_PRIVATE0_REG);
+
+ /* Assert the CPU core in reset */
+ writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
+
+ /* Assert the L1 cache in reset */
+ reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
+ writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
+
+ /* Clear CPU power-off gating */
+ reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
+ writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
+ mdelay(1);
+
+ /* Deassert the CPU core reset */
+ writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
+
+ spin_unlock(&cpu_lock);
+
+ return 0;
+}
+
+struct smp_operations sun8i_smp_ops __initdata = {
+ .smp_prepare_cpus = sun8i_smp_prepare_cpus,
+ .smp_boot_secondary = sun8i_smp_boot_secondary,
+};
+CPU_METHOD_OF_DECLARE(sun8i_a23_smp, "allwinner,sun8i-a23", &sun8i_smp_ops);
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index e48a74458c25..fffad2426ee4 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -19,7 +19,7 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-tegra30.o
ifeq ($(CONFIG_CPU_IDLE),y)
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o
endif
-obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += sleep-tegra30.o
diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c
index 88de2dce2e87..7469347b1749 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra20.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra20.c
@@ -34,6 +34,7 @@
#include "iomap.h"
#include "irq.h"
#include "pm.h"
+#include "reset.h"
#include "sleep.h"
#ifdef CONFIG_PM_SLEEP
@@ -70,15 +71,13 @@ static struct cpuidle_driver tegra_idle_driver = {
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_SMP
-static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
-
static int tegra20_reset_sleeping_cpu_1(void)
{
int ret = 0;
tegra_pen_lock();
- if (readl(pmc + PMC_SCRATCH41) == CPU_RESETTABLE)
+ if (readb(tegra20_cpu1_resettable_status) == CPU_RESETTABLE)
tegra20_cpu_shutdown(1);
else
ret = -EINVAL;
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
deleted file mode 100644
index 2072e7322c39..000000000000
--- a/arch/arm/mach-tegra/headsmp.S
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <linux/linkage.h>
-#include <linux/init.h>
-
-#include "sleep.h"
-
- .section ".text.head", "ax"
-
-ENTRY(tegra_secondary_startup)
- check_cpu_part_num 0xc09, r8, r9
- bleq v7_invalidate_l1
- b secondary_startup
-ENDPROC(tegra_secondary_startup)
diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S
index 71be4af5e975..e3070fdab80b 100644
--- a/arch/arm/mach-tegra/reset-handler.S
+++ b/arch/arm/mach-tegra/reset-handler.S
@@ -169,10 +169,10 @@ after_errata:
cmp r6, #TEGRA20
bne 1f
/* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
- mov32 r5, TEGRA_PMC_BASE
- mov r0, #0
+ mov32 r5, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET
+ mov r0, #CPU_NOT_RESETTABLE
cmp r10, #0
- strne r0, [r5, #PMC_SCRATCH41]
+ strneb r0, [r5, #__tegra20_cpu1_resettable_status_offset]
1:
#endif
@@ -281,6 +281,10 @@ __tegra_cpu_reset_handler_data:
.rept TEGRA_RESET_DATA_SIZE
.long 0
.endr
+ .globl __tegra20_cpu1_resettable_status_offset
+ .equ __tegra20_cpu1_resettable_status_offset, \
+ . - __tegra_cpu_reset_handler_start
+ .byte 0
.align L1_CACHE_SHIFT
ENTRY(__tegra_cpu_reset_handler_end)
diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c
index 894c5c472184..6fd9db54887e 100644
--- a/arch/arm/mach-tegra/reset.c
+++ b/arch/arm/mach-tegra/reset.c
@@ -94,7 +94,7 @@ void __init tegra_cpu_reset_handler_init(void)
__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] =
*((u32 *)cpu_possible_mask);
__tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_SECONDARY] =
- virt_to_phys((void *)tegra_secondary_startup);
+ virt_to_phys((void *)secondary_startup);
#endif
#ifdef CONFIG_PM_SLEEP
diff --git a/arch/arm/mach-tegra/reset.h b/arch/arm/mach-tegra/reset.h
index 76a93434c6ee..9c479c7925b8 100644
--- a/arch/arm/mach-tegra/reset.h
+++ b/arch/arm/mach-tegra/reset.h
@@ -35,8 +35,8 @@ extern unsigned long __tegra_cpu_reset_handler_data[TEGRA_RESET_DATA_SIZE];
void __tegra_cpu_reset_handler_start(void);
void __tegra_cpu_reset_handler(void);
+void __tegra20_cpu1_resettable_status_offset(void);
void __tegra_cpu_reset_handler_end(void);
-void tegra_secondary_startup(void);
#ifdef CONFIG_PM_SLEEP
#define tegra_cpu_lp1_mask \
@@ -47,6 +47,9 @@ void tegra_secondary_startup(void);
(IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP2] - \
(u32)__tegra_cpu_reset_handler_start)))
+#define tegra20_cpu1_resettable_status \
+ (IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
+ (u32)__tegra20_cpu1_resettable_status_offset))
#endif
#define tegra_cpu_reset_handler_offset \
diff --git a/arch/arm/mach-tegra/sleep-tegra20.S b/arch/arm/mach-tegra/sleep-tegra20.S
index be4bc5f853f5..e6b684e14322 100644
--- a/arch/arm/mach-tegra/sleep-tegra20.S
+++ b/arch/arm/mach-tegra/sleep-tegra20.S
@@ -97,9 +97,10 @@ ENDPROC(tegra20_hotplug_shutdown)
ENTRY(tegra20_cpu_shutdown)
cmp r0, #0
reteq lr @ must not be called for CPU 0
- mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
+ mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
+ ldr r2, =__tegra20_cpu1_resettable_status_offset
mov r12, #CPU_RESETTABLE
- str r12, [r1]
+ strb r12, [r1, r2]
cpu_to_halt_reg r1, r0
ldr r3, =TEGRA_FLOW_CTRL_VIRT
@@ -182,38 +183,41 @@ ENDPROC(tegra_pen_unlock)
/*
* tegra20_cpu_clear_resettable(void)
*
- * Called to clear the "resettable soon" flag in PMC_SCRATCH41 when
+ * Called to clear the "resettable soon" flag in IRAM variable when
* it is expected that the secondary CPU will be idle soon.
*/
ENTRY(tegra20_cpu_clear_resettable)
- mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
+ mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
+ ldr r2, =__tegra20_cpu1_resettable_status_offset
mov r12, #CPU_NOT_RESETTABLE
- str r12, [r1]
+ strb r12, [r1, r2]
ret lr
ENDPROC(tegra20_cpu_clear_resettable)
/*
* tegra20_cpu_set_resettable_soon(void)
*
- * Called to set the "resettable soon" flag in PMC_SCRATCH41 when
+ * Called to set the "resettable soon" flag in IRAM variable when
* it is expected that the secondary CPU will be idle soon.
*/
ENTRY(tegra20_cpu_set_resettable_soon)
- mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
+ mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
+ ldr r2, =__tegra20_cpu1_resettable_status_offset
mov r12, #CPU_RESETTABLE_SOON
- str r12, [r1]
+ strb r12, [r1, r2]
ret lr
ENDPROC(tegra20_cpu_set_resettable_soon)
/*
* tegra20_cpu_is_resettable_soon(void)
*
- * Returns true if the "resettable soon" flag in PMC_SCRATCH41 has been
+ * Returns true if the "resettable soon" flag in IRAM variable has been
* set because it is expected that the secondary CPU will be idle soon.
*/
ENTRY(tegra20_cpu_is_resettable_soon)
- mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
- ldr r12, [r1]
+ mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
+ ldr r2, =__tegra20_cpu1_resettable_status_offset
+ ldrb r12, [r1, r2]
cmp r12, #CPU_RESETTABLE_SOON
moveq r0, #1
movne r0, #0
@@ -256,9 +260,10 @@ ENTRY(tegra20_sleep_cpu_secondary_finish)
mov r0, #TEGRA_FLUSH_CACHE_LOUIS
bl tegra_disable_clean_inv_dcache
- mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41
+ mov32 r0, TEGRA_IRAM_RESET_BASE_VIRT
+ ldr r4, =__tegra20_cpu1_resettable_status_offset
mov r3, #CPU_RESETTABLE
- str r3, [r0]
+ strb r3, [r0, r4]
bl tegra_cpu_do_idle
@@ -274,10 +279,10 @@ ENTRY(tegra20_sleep_cpu_secondary_finish)
bl tegra_pen_lock
- mov32 r3, TEGRA_PMC_VIRT
- add r0, r3, #PMC_SCRATCH41
+ mov32 r0, TEGRA_IRAM_RESET_BASE_VIRT
+ ldr r4, =__tegra20_cpu1_resettable_status_offset
mov r3, #CPU_NOT_RESETTABLE
- str r3, [r0]
+ strb r3, [r0, r4]
bl tegra_pen_unlock
diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S
index 5d8d13aeab93..9a2f0b051e10 100644
--- a/arch/arm/mach-tegra/sleep-tegra30.S
+++ b/arch/arm/mach-tegra/sleep-tegra30.S
@@ -223,7 +223,7 @@ wfe_war:
b __cpu_reset_again
/*
- * 38 nop's, which fills reset of wfe cache line and
+ * 38 nop's, which fills rest of wfe cache line and
* 4 more cachelines with nop
*/
.rept 38
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index 92d46ec1361a..0d59360d891d 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -18,6 +18,7 @@
#define __MACH_TEGRA_SLEEP_H
#include "iomap.h"
+#include "irammap.h"
#define TEGRA_ARM_PERIF_VIRT (TEGRA_ARM_PERIF_BASE - IO_CPU_PHYS \
+ IO_CPU_VIRT)
@@ -29,6 +30,9 @@
+ IO_APB_VIRT)
#define TEGRA_PMC_VIRT (TEGRA_PMC_BASE - IO_APB_PHYS + IO_APB_VIRT)
+#define TEGRA_IRAM_RESET_BASE_VIRT (IO_IRAM_VIRT + \
+ TEGRA_IRAM_RESET_HANDLER_OFFSET)
+
/* PMC_SCRATCH37-39 and 41 are used for tegra_pen_lock and idle */
#define PMC_SCRATCH37 0x130
#define PMC_SCRATCH38 0x134
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index 861d88486dbe..2378fa560a21 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -163,6 +163,5 @@ DT_MACHINE_START(TEGRA_DT, "NVIDIA Tegra SoC (Flattened Device Tree)")
.init_irq = tegra_dt_init_irq,
.init_machine = tegra_dt_init,
.init_late = tegra_dt_init_late,
- .restart = tegra_pmc_restart,
.dt_compat = tegra_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-uniphier/Kconfig b/arch/arm/mach-uniphier/Kconfig
new file mode 100644
index 000000000000..b640458fd757
--- /dev/null
+++ b/arch/arm/mach-uniphier/Kconfig
@@ -0,0 +1,11 @@
+config ARCH_UNIPHIER
+ bool "Socionext UniPhier SoCs"
+ depends on ARCH_MULTI_V7
+ select ARM_AMBA
+ select ARM_GLOBAL_TIMER
+ select ARM_GIC
+ select HAVE_ARM_SCU
+ select HAVE_ARM_TWD if SMP
+ 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/Makefile b/arch/arm/mach-uniphier/Makefile
new file mode 100644
index 000000000000..60bd2265f753
--- /dev/null
+++ b/arch/arm/mach-uniphier/Makefile
@@ -0,0 +1,2 @@
+obj-y := uniphier.o
+obj-$(CONFIG_SMP) += platsmp.o
diff --git a/arch/arm/mach-uniphier/platsmp.c b/arch/arm/mach-uniphier/platsmp.c
new file mode 100644
index 000000000000..5943e1cb7fe1
--- /dev/null
+++ b/arch/arm/mach-uniphier/platsmp.c
@@ -0,0 +1,90 @@
+/*
+ * 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/sizes.h>
+#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <asm/smp.h>
+#include <asm/smp_scu.h>
+
+static struct regmap *sbcm_regmap;
+
+static void __init uniphier_smp_prepare_cpus(unsigned int max_cpus)
+{
+ static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
+ unsigned long scu_base_phys = 0;
+ void __iomem *scu_base;
+
+ sbcm_regmap = syscon_regmap_lookup_by_compatible(
+ "socionext,uniphier-system-bus-controller-misc");
+ if (IS_ERR(sbcm_regmap)) {
+ pr_err("failed to regmap system-bus-controller-misc\n");
+ goto err;
+ }
+
+ if (scu_a9_has_base())
+ scu_base_phys = scu_a9_get_base();
+
+ if (!scu_base_phys) {
+ pr_err("failed to get scu base\n");
+ goto err;
+ }
+
+ scu_base = ioremap(scu_base_phys, SZ_128);
+ if (!scu_base) {
+ pr_err("failed to remap scu base (0x%08lx)\n", scu_base_phys);
+ goto err;
+ }
+
+ scu_enable(scu_base);
+ iounmap(scu_base);
+
+ return;
+err:
+ pr_warn("disabling SMP\n");
+ init_cpu_present(&only_cpu_0);
+ sbcm_regmap = NULL;
+}
+
+static void __naked uniphier_secondary_startup(void)
+{
+ asm("bl v7_invalidate_l1\n"
+ "b secondary_startup\n");
+};
+
+static int uniphier_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ int ret;
+
+ if (!sbcm_regmap)
+ return -ENODEV;
+
+ ret = regmap_write(sbcm_regmap, 0x1208,
+ virt_to_phys(uniphier_secondary_startup));
+ if (!ret)
+ asm("sev"); /* wake up secondary CPU */
+
+ return ret;
+}
+
+struct smp_operations uniphier_smp_ops __initdata = {
+ .smp_prepare_cpus = uniphier_smp_prepare_cpus,
+ .smp_boot_secondary = uniphier_boot_secondary,
+};
+CPU_METHOD_OF_DECLARE(uniphier_smp, "socionext,uniphier-smp",
+ &uniphier_smp_ops);
diff --git a/arch/ia64/kernel/paravirt_patchlist.h b/arch/arm/mach-uniphier/uniphier.c
index 67cffc3643a3..9be10efacb7d 100644
--- a/arch/ia64/kernel/paravirt_patchlist.h
+++ b/arch/arm/mach-uniphier/uniphier.c
@@ -1,8 +1,5 @@
-/******************************************************************************
- * linux/arch/ia64/xen/paravirt_patchlist.h
- *
- * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
+/*
+ * 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
@@ -13,12 +10,21 @@
* but WITHOUT 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 <asm/native/patchlist.h>
+#include <asm/mach/arch.h>
+
+static const char * const uniphier_dt_compat[] __initconst = {
+ "socionext,ph1-sld3",
+ "socionext,ph1-ld4",
+ "socionext,ph1-pro4",
+ "socionext,ph1-sld8",
+ "socionext,ph1-pro5",
+ "socionext,proxstream2",
+ "socionext,ph1-ld6b",
+ NULL,
+};
+DT_MACHINE_START(UNIPHIER, "Socionext UniPhier")
+ .dt_compat = uniphier_dt_compat,
+MACHINE_END
diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c
index e97ee556f92f..7557bede7ae6 100644
--- a/arch/arm/mach-ux500/cache-l2x0.c
+++ b/arch/arm/mach-ux500/cache-l2x0.c
@@ -6,6 +6,7 @@
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <asm/hardware/cache-l2x0.h>
@@ -15,7 +16,14 @@
static int __init ux500_l2x0_unlock(void)
{
int i;
- void __iomem *l2x0_base = __io_address(U8500_L2CC_BASE);
+ struct device_node *np;
+ void __iomem *l2x0_base;
+
+ np = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
+ l2x0_base = of_iomap(np, 0);
+ of_node_put(np);
+ if (!l2x0_base)
+ return -ENODEV;
/*
* Unlock Data and Instruction Lock if locked. Ux500 U-Boot versions
@@ -30,6 +38,7 @@ static int __init ux500_l2x0_unlock(void)
writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE +
i * L2X0_LOCKDOWN_STRIDE);
}
+ iounmap(l2x0_base);
return 0;
}
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index 6f63954c8bde..16913800bbf9 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -43,60 +43,10 @@ static struct prcmu_pdata db8500_prcmu_pdata = {
.legacy_offset = DB8500_PRCMU_LEGACY_OFFSET,
};
-/* minimum static i/o mapping required to boot U8500 platforms */
-static struct map_desc u8500_uart_io_desc[] __initdata = {
- __IO_DEV_DESC(U8500_UART0_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_UART2_BASE, SZ_4K),
-};
-/* U8500 and U9540 common io_desc */
-static struct map_desc u8500_common_io_desc[] __initdata = {
- /* SCU base also covers GIC CPU BASE and TWD with its 4K page */
- __IO_DEV_DESC(U8500_SCU_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_L2CC_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_BACKUPRAM0_BASE, SZ_8K),
-
- __IO_DEV_DESC(U8500_CLKRST1_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_CLKRST2_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_CLKRST3_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_CLKRST5_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_CLKRST6_BASE, SZ_4K),
-
- __IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K),
-};
-
-/* U8500 IO map specific description */
-static struct map_desc u8500_io_desc[] __initdata = {
- __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K),
-
-};
-
-/* U9540 IO map specific description */
-static struct map_desc u9540_io_desc[] __initdata = {
- __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K + SZ_8K),
- __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K + SZ_8K),
-};
-
static void __init u8500_map_io(void)
{
- /*
- * Map the UARTs early so that the DEBUG_LL stuff continues to work.
- */
- iotable_init(u8500_uart_io_desc, ARRAY_SIZE(u8500_uart_io_desc));
-
- ux500_map_io();
-
- iotable_init(u8500_common_io_desc, ARRAY_SIZE(u8500_common_io_desc));
-
- if (cpu_is_ux540_family())
- iotable_init(u9540_io_desc, ARRAY_SIZE(u9540_io_desc));
- else
- iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
+ debug_ll_io_init();
+ ux500_setup_id();
}
/*
@@ -125,14 +75,18 @@ static struct arm_pmu_platdata db8500_pmu_platdata = {
static const char *db8500_read_soc_id(void)
{
- void __iomem *uid = __io_address(U8500_BB_UID_BASE);
+ void __iomem *uid;
+ uid = ioremap(U8500_BB_UID_BASE, 0x20);
+ if (!uid)
+ return NULL;
/* Throw these device-specific numbers into the entropy pool */
add_device_randomness(uid, 0x14);
return kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x",
readl((u32 *)uid+0),
readl((u32 *)uid+1), readl((u32 *)uid+2),
readl((u32 *)uid+3), readl((u32 *)uid+4));
+ iounmap(uid);
}
static struct device * __init db8500_soc_device_init(void)
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index 6ced0f680262..e31d3d61c998 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -16,6 +16,7 @@
#include <linux/stat.h>
#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/of_address.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic.h>
@@ -52,31 +53,36 @@ void ux500_restart(enum reboot_mode mode, const char *cmd)
*/
void __init ux500_init_irq(void)
{
+ struct device_node *np;
+ struct resource r;
+
gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND);
irqchip_init();
+ np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu");
+ of_address_to_resource(np, 0, &r);
+ of_node_put(np);
+ if (!r.start) {
+ pr_err("could not find PRCMU base resource\n");
+ return;
+ }
+ prcmu_early_init(r.start, r.end-r.start);
+ ux500_pm_init(r.start, r.end-r.start);
/*
* Init clocks here so that they are available for system timer
* initialization.
*/
if (cpu_is_u8500_family()) {
- prcmu_early_init(U8500_PRCMU_BASE, SZ_8K - 1);
- ux500_pm_init(U8500_PRCMU_BASE, SZ_8K - 1);
-
u8500_of_clk_init(U8500_CLKRST1_BASE,
U8500_CLKRST2_BASE,
U8500_CLKRST3_BASE,
U8500_CLKRST5_BASE,
U8500_CLKRST6_BASE);
} else if (cpu_is_u9540()) {
- prcmu_early_init(U8500_PRCMU_BASE, SZ_8K - 1);
- ux500_pm_init(U8500_PRCMU_BASE, SZ_8K - 1);
u9540_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE,
U8500_CLKRST3_BASE, U8500_CLKRST5_BASE,
U8500_CLKRST6_BASE);
} else if (cpu_is_u8540()) {
- prcmu_early_init(U8500_PRCMU_BASE, SZ_8K + SZ_4K - 1);
- ux500_pm_init(U8500_PRCMU_BASE, SZ_8K + SZ_4K - 1);
u8540_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE,
U8500_CLKRST3_BASE, U8500_CLKRST5_BASE,
U8500_CLKRST6_BASE);
diff --git a/arch/arm/mach-ux500/id.c b/arch/arm/mach-ux500/id.c
index 392f2fdb37d0..1e81e990044b 100644
--- a/arch/arm/mach-ux500/id.c
+++ b/arch/arm/mach-ux500/id.c
@@ -72,7 +72,7 @@ static unsigned int partnumber(unsigned int asicid)
* DB9540 0x413fc090 0xFFFFDBF4 0x009540xx
*/
-void __init ux500_map_io(void)
+void __init ux500_setup_id(void)
{
unsigned int cpuid = read_cpuid_id();
unsigned int asicid = 0;
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index a44967f3168c..62b1de922bd8 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -16,6 +16,8 @@
#include <linux/device.h>
#include <linux/smp.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
@@ -26,6 +28,9 @@
#include "db8500-regs.h"
#include "id.h"
+static void __iomem *scu_base;
+static void __iomem *backupram;
+
/* This is called from headsmp.S to wakeup the secondary core */
extern void u8500_secondary_startup(void);
@@ -41,16 +46,6 @@ static void write_pen_release(int val)
sync_cache_w(&pen_release);
}
-static void __iomem *scu_base_addr(void)
-{
- if (cpu_is_u8500_family() || cpu_is_ux540_family())
- return __io_address(U8500_SCU_BASE);
- else
- ux500_unknown_soc();
-
- return NULL;
-}
-
static DEFINE_SPINLOCK(boot_lock);
static void ux500_secondary_init(unsigned int cpu)
@@ -104,13 +99,6 @@ static int ux500_boot_secondary(unsigned int cpu, struct task_struct *idle)
static void __init wakeup_secondary(void)
{
- void __iomem *backupram;
-
- if (cpu_is_u8500_family() || cpu_is_ux540_family())
- backupram = __io_address(U8500_BACKUPRAM0_BASE);
- else
- ux500_unknown_soc();
-
/*
* write the address of secondary startup into the backup ram register
* at offset 0x1FF4, then write the magic number 0xA1FEED01 to the
@@ -135,10 +123,16 @@ static void __init wakeup_secondary(void)
*/
static void __init ux500_smp_init_cpus(void)
{
- void __iomem *scu_base = scu_base_addr();
unsigned int i, ncores;
+ struct device_node *np;
- ncores = scu_base ? scu_get_core_count(scu_base) : 1;
+ np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
+ scu_base = of_iomap(np, 0);
+ of_node_put(np);
+ if (!scu_base)
+ return;
+ backupram = ioremap(U8500_BACKUPRAM0_BASE, SZ_8K);
+ ncores = scu_get_core_count(scu_base);
/* sanity check */
if (ncores > nr_cpu_ids) {
@@ -153,8 +147,7 @@ static void __init ux500_smp_init_cpus(void)
static void __init ux500_smp_prepare_cpus(unsigned int max_cpus)
{
-
- scu_enable(scu_base_addr());
+ scu_enable(scu_base);
wakeup_secondary();
}
diff --git a/arch/arm/mach-ux500/pm.c b/arch/arm/mach-ux500/pm.c
index 2cb587b50905..8538910db202 100644
--- a/arch/arm/mach-ux500/pm.c
+++ b/arch/arm/mach-ux500/pm.c
@@ -15,6 +15,8 @@
#include <linux/io.h>
#include <linux/suspend.h>
#include <linux/platform_data/arm-ux500-pm.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include "db8500-regs.h"
#include "pm_domains.h"
@@ -42,6 +44,7 @@
#define PRCM_ARMITVAL127TO96 (prcmu_base + 0x26C)
static void __iomem *prcmu_base;
+static void __iomem *dist_base;
/* This function decouple the gic from the prcmu */
int prcmu_gic_decouple(void)
@@ -88,7 +91,6 @@ bool prcmu_gic_pending_irq(void)
{
u32 pr; /* Pending register */
u32 er; /* Enable register */
- void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
int i;
/* 5 registers. STI & PPI not skipped */
@@ -143,7 +145,6 @@ bool prcmu_is_cpu_in_wfi(int cpu)
int prcmu_copy_gic_settings(void)
{
u32 er; /* Enable register */
- void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
int i;
/* We skip the STI and PPI */
@@ -179,11 +180,21 @@ static const struct platform_suspend_ops ux500_suspend_ops = {
void __init ux500_pm_init(u32 phy_base, u32 size)
{
+ struct device_node *np;
+
prcmu_base = ioremap(phy_base, size);
if (!prcmu_base) {
pr_err("could not remap PRCMU for PM functions\n");
return;
}
+ np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic");
+ dist_base = of_iomap(np, 0);
+ of_node_put(np);
+ if (!dist_base) {
+ pr_err("could not remap GIC dist base for PM functions\n");
+ return;
+ }
+
/*
* On watchdog reboot the GIC is in some cases decoupled.
* This will make sure that the GIC is correctly configured.
diff --git a/arch/arm/mach-ux500/setup.h b/arch/arm/mach-ux500/setup.h
index 2dea8b59d222..1fb6ad2789f1 100644
--- a/arch/arm/mach-ux500/setup.h
+++ b/arch/arm/mach-ux500/setup.h
@@ -18,7 +18,7 @@
void ux500_restart(enum reboot_mode mode, const char *cmd);
-void __init ux500_map_io(void);
+void __init ux500_setup_id(void);
extern void __init ux500_init_irq(void);
@@ -26,20 +26,6 @@ extern struct device *ux500_soc_device_init(const char *soc_id);
extern void ux500_timer_init(void);
-#define __IO_DEV_DESC(x, sz) { \
- .virtual = IO_ADDRESS(x), \
- .pfn = __phys_to_pfn(x), \
- .length = sz, \
- .type = MT_DEVICE, \
-}
-
-#define __MEM_DEV_DESC(x, sz) { \
- .virtual = IO_ADDRESS(x), \
- .pfn = __phys_to_pfn(x), \
- .length = sz, \
- .type = MT_MEMORY_RWX, \
-}
-
extern struct smp_operations ux500_smp_ops;
extern void ux500_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 6ea09fe53426..23a04fe5d2ad 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -41,8 +41,9 @@
#include <linux/bitops.h>
#include <linux/reboot.h>
+#include <clocksource/timer-sp804.h>
+
#include <asm/irq.h>
-#include <asm/hardware/arm_timer.h>
#include <asm/hardware/icst.h>
#include <asm/mach-types.h>
@@ -52,7 +53,6 @@
#include <asm/mach/map.h>
#include <mach/hardware.h>
#include <mach/platform.h>
-#include <asm/hardware/timer-sp.h>
#include <plat/sched_clock.h>
@@ -798,10 +798,10 @@ void __init versatile_timer_init(void)
/*
* Initialise to a known state (all timers off)
*/
- writel(0, TIMER0_VA_BASE + TIMER_CTRL);
- writel(0, TIMER1_VA_BASE + TIMER_CTRL);
- writel(0, TIMER2_VA_BASE + TIMER_CTRL);
- writel(0, TIMER3_VA_BASE + TIMER_CTRL);
+ 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-zx/Kconfig b/arch/arm/mach-zx/Kconfig
new file mode 100644
index 000000000000..2a910dc0d15e
--- /dev/null
+++ b/arch/arm/mach-zx/Kconfig
@@ -0,0 +1,18 @@
+menuconfig ARCH_ZX
+ bool "ZTE ZX family" if ARCH_MULTI_V7
+ help
+ Support for ZTE ZX-based family of processors. TV
+ set-top-box processor is supported. More will be
+ added soon.
+
+if ARCH_ZX
+
+config SOC_ZX296702
+ def_bool y
+ select ARM_GIC
+ select ARM_GLOBAL_TIMER
+ select HAVE_ARM_SCU if SMP
+ select HAVE_ARM_TWD if SMP
+ help
+ Support for ZTE ZX296702 SoC which is a dual core CortexA9MP
+endif
diff --git a/arch/arm/mach-zx/Makefile b/arch/arm/mach-zx/Makefile
new file mode 100644
index 000000000000..7c2edf6e5f8b
--- /dev/null
+++ b/arch/arm/mach-zx/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SOC_ZX296702) += zx296702.o
+obj-$(CONFIG_SMP) += headsmp.o platsmp.o
diff --git a/arch/arm/mach-zx/core.h b/arch/arm/mach-zx/core.h
new file mode 100644
index 000000000000..3efe8e038ee4
--- /dev/null
+++ b/arch/arm/mach-zx/core.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014 Linaro Ltd.
+ * Copyright (C) 2014 ZTE 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 __MACH_ZX_CORE_H
+#define __MACH_ZX_CORE_H
+
+extern void zx_resume_jump(void);
+extern size_t zx_suspend_iram_sz;
+extern unsigned long zx_secondary_startup_pa;
+
+void zx_secondary_startup(void);
+
+#endif /* __MACH_ZX_CORE_H */
diff --git a/arch/arm/mach-zx/headsmp.S b/arch/arm/mach-zx/headsmp.S
new file mode 100644
index 000000000000..a1aa4028389f
--- /dev/null
+++ b/arch/arm/mach-zx/headsmp.S
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014 Linaro Ltd.
+ * Copyright (C) 2014 ZTE 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/linkage.h>
+
+ .align 3
+ .arm
+
+/* It runs from physical address */
+ENTRY(zx_resume_jump)
+ adr r1, zx_secondary_startup_pa
+ ldr r0, [r1]
+ bx r0
+ENDPROC(zx_resume_jump)
+
+ENTRY(zx_secondary_startup_pa)
+ .word zx_secondary_startup_pa
+
+ENTRY(zx_suspend_iram_sz)
+ .word . - zx_resume_jump
+ENDPROC(zx_secondary_startup_pa)
+
+
+ENTRY(zx_secondary_startup)
+ bl v7_invalidate_l1
+ b secondary_startup
+ENDPROC(zx_secondary_startup)
diff --git a/arch/arm/mach-zx/platsmp.c b/arch/arm/mach-zx/platsmp.c
new file mode 100644
index 000000000000..a3693982d65d
--- /dev/null
+++ b/arch/arm/mach-zx/platsmp.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2014 Linaro Ltd.
+ * Copyright (C) 2014 ZTE 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/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/smp.h>
+
+#include <asm/cacheflush.h>
+#include <asm/cp15.h>
+#include <asm/fncpy.h>
+#include <asm/proc-fns.h>
+#include <asm/smp_scu.h>
+#include <asm/smp_plat.h>
+
+#include "core.h"
+
+#define AON_SYS_CTRL_RESERVED1 0xa8
+
+#define BUS_MATRIX_REMAP_CONFIG 0x00
+
+#define PCU_CPU0_CTRL 0x00
+#define PCU_CPU1_CTRL 0x04
+#define PCU_CPU1_ST 0x0c
+#define PCU_GLOBAL_CTRL 0x14
+#define PCU_EXPEND_CONTROL 0x34
+
+#define ZX_IRAM_BASE 0x00200000
+
+static void __iomem *pcu_base;
+static void __iomem *matrix_base;
+static void __iomem *scu_base;
+
+void __init zx_smp_prepare_cpus(unsigned int max_cpus)
+{
+ struct device_node *np;
+ unsigned long base = 0;
+ void __iomem *aonsysctrl_base;
+ void __iomem *sys_iram;
+
+ base = scu_a9_get_base();
+ scu_base = ioremap(base, SZ_256);
+ if (!scu_base) {
+ pr_err("%s: failed to map scu\n", __func__);
+ return;
+ }
+
+ scu_enable(scu_base);
+
+ np = of_find_compatible_node(NULL, NULL, "zte,sysctrl");
+ if (!np) {
+ pr_err("%s: failed to find sysctrl node\n", __func__);
+ return;
+ }
+
+ aonsysctrl_base = of_iomap(np, 0);
+ if (!aonsysctrl_base) {
+ pr_err("%s: failed to map aonsysctrl\n", __func__);
+ of_node_put(np);
+ return;
+ }
+
+ /*
+ * Write the address of secondary startup into the
+ * system-wide flags register. The BootMonitor waits
+ * until it receives a soft interrupt, and then the
+ * secondary CPU branches to this address.
+ */
+ __raw_writel(virt_to_phys(zx_secondary_startup),
+ aonsysctrl_base + AON_SYS_CTRL_RESERVED1);
+
+ iounmap(aonsysctrl_base);
+ of_node_put(np);
+
+ np = of_find_compatible_node(NULL, NULL, "zte,zx296702-pcu");
+ pcu_base = of_iomap(np, 0);
+ of_node_put(np);
+ WARN_ON(!pcu_base);
+
+ np = of_find_compatible_node(NULL, NULL, "zte,zx-bus-matrix");
+ matrix_base = of_iomap(np, 0);
+ of_node_put(np);
+ WARN_ON(!matrix_base);
+
+ /* Map the first 4 KB IRAM for suspend usage */
+ sys_iram = __arm_ioremap_exec(ZX_IRAM_BASE, PAGE_SIZE, false);
+ zx_secondary_startup_pa = virt_to_phys(zx_secondary_startup);
+ fncpy(sys_iram, &zx_resume_jump, zx_suspend_iram_sz);
+}
+
+static int zx_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ static bool first_boot = true;
+
+ if (first_boot) {
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+ first_boot = false;
+ return 0;
+ }
+
+ /* Swap the base address mapping between IRAM and IROM */
+ writel_relaxed(0x1, matrix_base + BUS_MATRIX_REMAP_CONFIG);
+
+ /* Power on CPU1 */
+ writel_relaxed(0x0, pcu_base + PCU_CPU1_CTRL);
+
+ /* Wait for power on ack */
+ while (readl_relaxed(pcu_base + PCU_CPU1_ST) & 0x4)
+ cpu_relax();
+
+ /* Swap back the mapping of IRAM and IROM */
+ writel_relaxed(0x0, matrix_base + BUS_MATRIX_REMAP_CONFIG);
+
+ return 0;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static inline void cpu_enter_lowpower(void)
+{
+ unsigned int v;
+
+ asm volatile(
+ "mcr p15, 0, %1, c7, c5, 0\n"
+ " mcr p15, 0, %1, c7, c10, 4\n"
+ /*
+ * Turn off coherency
+ */
+ " mrc p15, 0, %0, c1, c0, 1\n"
+ " bic %0, %0, %3\n"
+ " mcr p15, 0, %0, c1, c0, 1\n"
+ " mrc p15, 0, %0, c1, c0, 0\n"
+ " bic %0, %0, %2\n"
+ " mcr p15, 0, %0, c1, c0, 0\n"
+ : "=&r" (v)
+ : "r" (0), "Ir" (CR_C), "Ir" (0x40)
+ : "cc");
+}
+
+static int zx_cpu_kill(unsigned int cpu)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(2000);
+
+ writel_relaxed(0x2, pcu_base + PCU_CPU1_CTRL);
+
+ while ((readl_relaxed(pcu_base + PCU_CPU1_ST) & 0x3) != 0x0) {
+ if (time_after(jiffies, timeout)) {
+ pr_err("*** cpu1 poweroff timeout\n");
+ break;
+ }
+ }
+ return 1;
+}
+
+static void zx_cpu_die(unsigned int cpu)
+{
+ scu_power_mode(scu_base, SCU_PM_POWEROFF);
+ cpu_enter_lowpower();
+
+ while (1)
+ cpu_do_idle();
+}
+#endif
+
+static void zx_secondary_init(unsigned int cpu)
+{
+ scu_power_mode(scu_base, SCU_PM_NORMAL);
+}
+
+struct smp_operations zx_smp_ops __initdata = {
+ .smp_prepare_cpus = zx_smp_prepare_cpus,
+ .smp_secondary_init = zx_secondary_init,
+ .smp_boot_secondary = zx_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_kill = zx_cpu_kill,
+ .cpu_die = zx_cpu_die,
+#endif
+};
+
+CPU_METHOD_OF_DECLARE(zx_smp, "zte,zx296702-smp", &zx_smp_ops);
diff --git a/arch/arm/mach-zx/zx296702.c b/arch/arm/mach-zx/zx296702.c
new file mode 100644
index 000000000000..60bb1a8e1bf1
--- /dev/null
+++ b/arch/arm/mach-zx/zx296702.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2014 Linaro Ltd.
+ * Copyright (C) 2014 ZTE 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 <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+static const char *zx296702_dt_compat[] __initconst = {
+ "zte,zx296702",
+ NULL,
+};
+
+DT_MACHINE_START(ZX, "ZTE ZX296702 (Device Tree)")
+ .dt_compat = zx296702_dt_compat,
+ .l2c_aux_val = 0,
+ .l2c_aux_mask = ~0,
+MACHINE_END
diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c
index 58ef2a700414..616d5840fc2e 100644
--- a/arch/arm/mach-zynq/common.c
+++ b/arch/arm/mach-zynq/common.c
@@ -190,11 +190,6 @@ static void __init zynq_irq_init(void)
irqchip_init();
}
-static void zynq_system_reset(enum reboot_mode mode, const char *cmd)
-{
- zynq_slcr_system_reset();
-}
-
static const char * const zynq_dt_match[] = {
"xlnx,zynq-7000",
NULL
@@ -212,5 +207,4 @@ DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
.init_time = zynq_timer_init,
.dt_compat = zynq_dt_match,
.reserve = zynq_memory_init,
- .restart = zynq_system_reset,
MACHINE_END
diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h
index 382c60e9aa16..79cda2e5fa4e 100644
--- a/arch/arm/mach-zynq/common.h
+++ b/arch/arm/mach-zynq/common.h
@@ -17,11 +17,8 @@
#ifndef __MACH_ZYNQ_COMMON_H__
#define __MACH_ZYNQ_COMMON_H__
-void zynq_secondary_startup(void);
-
extern int zynq_slcr_init(void);
extern int zynq_early_slcr_init(void);
-extern void zynq_slcr_system_reset(void);
extern void zynq_slcr_cpu_stop(int cpu);
extern void zynq_slcr_cpu_start(int cpu);
extern bool zynq_slcr_cpu_state_read(int cpu);
diff --git a/arch/arm/mach-zynq/headsmp.S b/arch/arm/mach-zynq/headsmp.S
index dd8c071941e7..045c72720a4d 100644
--- a/arch/arm/mach-zynq/headsmp.S
+++ b/arch/arm/mach-zynq/headsmp.S
@@ -22,8 +22,3 @@ zynq_secondary_trampoline_jump:
.globl zynq_secondary_trampoline_end
zynq_secondary_trampoline_end:
ENDPROC(zynq_secondary_trampoline)
-
-ENTRY(zynq_secondary_startup)
- bl v7_invalidate_l1
- b secondary_startup
-ENDPROC(zynq_secondary_startup)
diff --git a/arch/arm/mach-zynq/platsmp.c b/arch/arm/mach-zynq/platsmp.c
index 52d768ff7857..f66816c49186 100644
--- a/arch/arm/mach-zynq/platsmp.c
+++ b/arch/arm/mach-zynq/platsmp.c
@@ -87,10 +87,9 @@ int zynq_cpun_start(u32 address, int cpu)
}
EXPORT_SYMBOL(zynq_cpun_start);
-static int zynq_boot_secondary(unsigned int cpu,
- struct task_struct *idle)
+static int zynq_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
- return zynq_cpun_start(virt_to_phys(zynq_secondary_startup), cpu);
+ return zynq_cpun_start(virt_to_phys(secondary_startup), cpu);
}
/*
diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c
index c3c24fd8b306..26320ebf3493 100644
--- a/arch/arm/mach-zynq/slcr.c
+++ b/arch/arm/mach-zynq/slcr.c
@@ -15,6 +15,7 @@
*/
#include <linux/io.h>
+#include <linux/reboot.h>
#include <linux/mfd/syscon.h>
#include <linux/of_address.h>
#include <linux/regmap.h>
@@ -92,20 +93,21 @@ u32 zynq_slcr_get_device_id(void)
}
/**
- * zynq_slcr_system_reset - Reset the entire system.
+ * zynq_slcr_system_restart - Restart the entire system.
+ *
+ * @nb: Pointer to restart notifier block (unused)
+ * @action: Reboot mode (unused)
+ * @data: Restart handler private data (unused)
+ *
+ * Return: 0 always
*/
-void zynq_slcr_system_reset(void)
+static
+int zynq_slcr_system_restart(struct notifier_block *nb,
+ unsigned long action, void *data)
{
u32 reboot;
/*
- * Unlock the SLCR then reset the system.
- * Note that this seems to require raw i/o
- * functions or there's a lockup?
- */
- zynq_slcr_unlock();
-
- /*
* Clear 0x0F000000 bits of reboot status register to workaround
* the FSBL not loading the bitstream after soft-reboot
* This is a temporary solution until we know more.
@@ -113,8 +115,14 @@ void zynq_slcr_system_reset(void)
zynq_slcr_read(&reboot, SLCR_REBOOT_STATUS_OFFSET);
zynq_slcr_write(reboot & 0xF0FFFFFF, SLCR_REBOOT_STATUS_OFFSET);
zynq_slcr_write(1, SLCR_PS_RST_CTRL_OFFSET);
+ return 0;
}
+static struct notifier_block zynq_slcr_restart_nb = {
+ .notifier_call = zynq_slcr_system_restart,
+ .priority = 192,
+};
+
/**
* zynq_slcr_cpu_start - Start cpu
* @cpu: cpu number
@@ -219,6 +227,8 @@ int __init zynq_early_slcr_init(void)
/* unlock the SLCR so that registers can be changed */
zynq_slcr_unlock();
+ register_restart_handler(&zynq_slcr_restart_nb);
+
pr_info("%s mapped to %p\n", np->name, zynq_slcr_base);
of_node_put(np);
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index b4f92b9a13ac..7c6b976ab8d3 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -6,7 +6,7 @@ comment "Processor Type"
# ARM7TDMI
config CPU_ARM7TDMI
- bool "Support ARM7TDMI processor"
+ bool
depends on !MMU
select CPU_32v4T
select CPU_ABRT_LV4T
@@ -56,7 +56,7 @@ config CPU_ARM740T
# ARM9TDMI
config CPU_ARM9TDMI
- bool "Support ARM9TDMI processor"
+ bool
depends on !MMU
select CPU_32v4T
select CPU_ABRT_NOMMU
@@ -604,6 +604,22 @@ config CPU_USE_DOMAINS
This option enables or disables the use of domain switching
via the set_fs() function.
+config CPU_V7M_NUM_IRQ
+ int "Number of external interrupts connected to the NVIC"
+ depends on CPU_V7M
+ default 90 if ARCH_STM32
+ default 38 if ARCH_EFM32
+ default 112 if SOC_VF610
+ default 240
+ help
+ This option indicates the number of interrupts connected to the NVIC.
+ The value can be larger than the real number of interrupts supported
+ by the system, but must not be lower.
+ The default value is 240, corresponding to the maximum number of
+ interrupts supported by the NVIC on Cortex-M family.
+
+ If unsure, keep default value.
+
#
# CPU supports 36-bit I/O
#
@@ -624,6 +640,10 @@ config ARM_LPAE
If unsure, say N.
+config ARM_PV_FIXUP
+ def_bool y
+ depends on ARM_LPAE && ARM_PATCH_PHYS_VIRT && ARCH_KEYSTONE
+
config ARCH_PHYS_ADDR_T_64BIT
def_bool ARM_LPAE
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index d3afdf9eb65a..57c8df500e8c 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_MODULES) += proc-syms.o
obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o
obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
+obj-$(CONFIG_ARM_PV_FIXUP) += pv-fixup-asm.o
obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o
obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o
@@ -55,6 +56,8 @@ obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o
obj-$(CONFIG_CPU_XSC3) += copypage-xsc3.o
obj-$(CONFIG_CPU_COPY_FA) += copypage-fa.o
+CFLAGS_copypage-feroceon.o := -march=armv5te
+
obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o
obj-$(CONFIG_CPU_TLB_V4WB) += tlb-v4wb.o
obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index e309c8f35af5..71b3d3309024 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -38,10 +38,11 @@ struct l2c_init_data {
unsigned way_size_0;
unsigned num_lock;
void (*of_parse)(const struct device_node *, u32 *, u32 *);
- void (*enable)(void __iomem *, u32, unsigned);
+ void (*enable)(void __iomem *, unsigned);
void (*fixup)(void __iomem *, u32, struct outer_cache_fns *);
void (*save)(void __iomem *);
void (*configure)(void __iomem *);
+ void (*unlock)(void __iomem *, unsigned);
struct outer_cache_fns outer_cache;
};
@@ -110,14 +111,6 @@ static inline void l2c_unlock(void __iomem *base, unsigned num)
static void l2c_configure(void __iomem *base)
{
- if (outer_cache.configure) {
- outer_cache.configure(&l2x0_saved_regs);
- return;
- }
-
- if (l2x0_data->configure)
- l2x0_data->configure(base);
-
l2c_write_sec(l2x0_saved_regs.aux_ctrl, base, L2X0_AUX_CTRL);
}
@@ -125,18 +118,16 @@ static void l2c_configure(void __iomem *base)
* Enable the L2 cache controller. This function must only be
* called when the cache controller is known to be disabled.
*/
-static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock)
+static void l2c_enable(void __iomem *base, unsigned num_lock)
{
unsigned long flags;
- /* Do not touch the controller if already enabled. */
- if (readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)
- return;
-
- l2x0_saved_regs.aux_ctrl = aux;
- l2c_configure(base);
+ if (outer_cache.configure)
+ outer_cache.configure(&l2x0_saved_regs);
+ else
+ l2x0_data->configure(base);
- l2c_unlock(base, num_lock);
+ l2x0_data->unlock(base, num_lock);
local_irq_save(flags);
__l2c_op_way(base + L2X0_INV_WAY);
@@ -163,7 +154,11 @@ static void l2c_save(void __iomem *base)
static void l2c_resume(void)
{
- l2c_enable(l2x0_base, l2x0_saved_regs.aux_ctrl, l2x0_data->num_lock);
+ void __iomem *base = l2x0_base;
+
+ /* Do not touch the controller if already enabled. */
+ if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN))
+ l2c_enable(base, l2x0_data->num_lock);
}
/*
@@ -252,6 +247,8 @@ static const struct l2c_init_data l2c210_data __initconst = {
.num_lock = 1,
.enable = l2c_enable,
.save = l2c_save,
+ .configure = l2c_configure,
+ .unlock = l2c_unlock,
.outer_cache = {
.inv_range = l2c210_inv_range,
.clean_range = l2c210_clean_range,
@@ -391,16 +388,22 @@ static void l2c220_sync(void)
raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
-static void l2c220_enable(void __iomem *base, u32 aux, unsigned num_lock)
+static void l2c220_enable(void __iomem *base, unsigned num_lock)
{
/*
* Always enable non-secure access to the lockdown registers -
* we write to them as part of the L2C enable sequence so they
* need to be accessible.
*/
- aux |= L220_AUX_CTRL_NS_LOCKDOWN;
+ l2x0_saved_regs.aux_ctrl |= L220_AUX_CTRL_NS_LOCKDOWN;
- l2c_enable(base, aux, num_lock);
+ l2c_enable(base, num_lock);
+}
+
+static void l2c220_unlock(void __iomem *base, unsigned num_lock)
+{
+ if (readl_relaxed(base + L2X0_AUX_CTRL) & L220_AUX_CTRL_NS_LOCKDOWN)
+ l2c_unlock(base, num_lock);
}
static const struct l2c_init_data l2c220_data = {
@@ -409,6 +412,8 @@ static const struct l2c_init_data l2c220_data = {
.num_lock = 1,
.enable = l2c220_enable,
.save = l2c_save,
+ .configure = l2c_configure,
+ .unlock = l2c220_unlock,
.outer_cache = {
.inv_range = l2c220_inv_range,
.clean_range = l2c220_clean_range,
@@ -569,6 +574,8 @@ static void l2c310_configure(void __iomem *base)
{
unsigned revision;
+ l2c_configure(base);
+
/* restore pl310 setup */
l2c_write_sec(l2x0_saved_regs.tag_latency, base,
L310_TAG_LATENCY_CTRL);
@@ -603,10 +610,11 @@ static int l2c310_cpu_enable_flz(struct notifier_block *nb, unsigned long act, v
return NOTIFY_OK;
}
-static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock)
+static void __init l2c310_enable(void __iomem *base, unsigned num_lock)
{
unsigned rev = readl_relaxed(base + L2X0_CACHE_ID) & L2X0_CACHE_ID_RTL_MASK;
bool cortex_a9 = read_cpuid_part() == ARM_CPU_PART_CORTEX_A9;
+ u32 aux = l2x0_saved_regs.aux_ctrl;
if (rev >= L310_CACHE_ID_RTL_R2P0) {
if (cortex_a9) {
@@ -649,9 +657,9 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock)
* we write to them as part of the L2C enable sequence so they
* need to be accessible.
*/
- aux |= L310_AUX_CTRL_NS_LOCKDOWN;
+ l2x0_saved_regs.aux_ctrl = aux | L310_AUX_CTRL_NS_LOCKDOWN;
- l2c_enable(base, aux, num_lock);
+ l2c_enable(base, num_lock);
/* Read back resulting AUX_CTRL value as it could have been altered. */
aux = readl_relaxed(base + L2X0_AUX_CTRL);
@@ -755,6 +763,12 @@ static void l2c310_resume(void)
set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
}
+static void l2c310_unlock(void __iomem *base, unsigned num_lock)
+{
+ if (readl_relaxed(base + L2X0_AUX_CTRL) & L310_AUX_CTRL_NS_LOCKDOWN)
+ l2c_unlock(base, num_lock);
+}
+
static const struct l2c_init_data l2c310_init_fns __initconst = {
.type = "L2C-310",
.way_size_0 = SZ_8K,
@@ -763,6 +777,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
.fixup = l2c310_fixup,
.save = l2c310_save,
.configure = l2c310_configure,
+ .unlock = l2c310_unlock,
.outer_cache = {
.inv_range = l2c210_inv_range,
.clean_range = l2c210_clean_range,
@@ -856,8 +871,11 @@ static int __init __l2c_init(const struct l2c_init_data *data,
* Check if l2x0 controller is already enabled. If we are booting
* in non-secure mode accessing the below registers will fault.
*/
- if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN))
- data->enable(l2x0_base, aux, data->num_lock);
+ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
+ l2x0_saved_regs.aux_ctrl = aux;
+
+ data->enable(l2x0_base, data->num_lock);
+ }
outer_cache = fns;
@@ -1066,6 +1084,8 @@ static const struct l2c_init_data of_l2c210_data __initconst = {
.of_parse = l2x0_of_parse,
.enable = l2c_enable,
.save = l2c_save,
+ .configure = l2c_configure,
+ .unlock = l2c_unlock,
.outer_cache = {
.inv_range = l2c210_inv_range,
.clean_range = l2c210_clean_range,
@@ -1084,6 +1104,8 @@ static const struct l2c_init_data of_l2c220_data __initconst = {
.of_parse = l2x0_of_parse,
.enable = l2c220_enable,
.save = l2c_save,
+ .configure = l2c_configure,
+ .unlock = l2c220_unlock,
.outer_cache = {
.inv_range = l2c220_inv_range,
.clean_range = l2c220_clean_range,
@@ -1199,6 +1221,26 @@ static void __init l2c310_of_parse(const struct device_node *np,
pr_err("L2C-310 OF arm,prefetch-offset property value is missing\n");
}
+ ret = of_property_read_u32(np, "prefetch-data", &val);
+ if (ret == 0) {
+ if (val)
+ prefetch |= L310_PREFETCH_CTRL_DATA_PREFETCH;
+ else
+ prefetch &= ~L310_PREFETCH_CTRL_DATA_PREFETCH;
+ } else if (ret != -EINVAL) {
+ pr_err("L2C-310 OF prefetch-data property value is missing\n");
+ }
+
+ ret = of_property_read_u32(np, "prefetch-instr", &val);
+ if (ret == 0) {
+ if (val)
+ prefetch |= L310_PREFETCH_CTRL_INSTR_PREFETCH;
+ else
+ prefetch &= ~L310_PREFETCH_CTRL_INSTR_PREFETCH;
+ } else if (ret != -EINVAL) {
+ pr_err("L2C-310 OF prefetch-instr property value is missing\n");
+ }
+
l2x0_saved_regs.prefetch_ctrl = prefetch;
}
@@ -1211,6 +1253,7 @@ static const struct l2c_init_data of_l2c310_data __initconst = {
.fixup = l2c310_fixup,
.save = l2c310_save,
.configure = l2c310_configure,
+ .unlock = l2c310_unlock,
.outer_cache = {
.inv_range = l2c210_inv_range,
.clean_range = l2c210_clean_range,
@@ -1240,6 +1283,7 @@ static const struct l2c_init_data of_l2c310_coherent_data __initconst = {
.fixup = l2c310_fixup,
.save = l2c310_save,
.configure = l2c310_configure,
+ .unlock = l2c310_unlock,
.outer_cache = {
.inv_range = l2c210_inv_range,
.clean_range = l2c210_clean_range,
@@ -1366,7 +1410,7 @@ static void aurora_save(void __iomem *base)
* For Aurora cache in no outer mode, enable via the CP15 coprocessor
* broadcasting of cache commands to L2.
*/
-static void __init aurora_enable_no_outer(void __iomem *base, u32 aux,
+static void __init aurora_enable_no_outer(void __iomem *base,
unsigned num_lock)
{
u32 u;
@@ -1377,7 +1421,7 @@ static void __init aurora_enable_no_outer(void __iomem *base, u32 aux,
isb();
- l2c_enable(base, aux, num_lock);
+ l2c_enable(base, num_lock);
}
static void __init aurora_fixup(void __iomem *base, u32 cache_id,
@@ -1416,6 +1460,8 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
.enable = l2c_enable,
.fixup = aurora_fixup,
.save = aurora_save,
+ .configure = l2c_configure,
+ .unlock = l2c_unlock,
.outer_cache = {
.inv_range = aurora_inv_range,
.clean_range = aurora_clean_range,
@@ -1435,6 +1481,8 @@ static const struct l2c_init_data of_aurora_no_outer_data __initconst = {
.enable = aurora_enable_no_outer,
.fixup = aurora_fixup,
.save = aurora_save,
+ .configure = l2c_configure,
+ .unlock = l2c_unlock,
.outer_cache = {
.resume = l2c_resume,
},
@@ -1585,6 +1633,7 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
.enable = l2c310_enable,
.save = l2c310_save,
.configure = l2c310_configure,
+ .unlock = l2c310_unlock,
.outer_cache = {
.inv_range = bcm_inv_range,
.clean_range = bcm_clean_range,
@@ -1608,6 +1657,7 @@ static void __init tauros3_save(void __iomem *base)
static void tauros3_configure(void __iomem *base)
{
+ l2c_configure(base);
writel_relaxed(l2x0_saved_regs.aux2_ctrl,
base + TAUROS3_AUX2_CTRL);
writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
@@ -1621,6 +1671,7 @@ static const struct l2c_init_data of_tauros3_data __initconst = {
.enable = l2c_enable,
.save = tauros3_save,
.configure = tauros3_configure,
+ .unlock = l2c_unlock,
/* Tauros3 broadcasts L1 cache operations to L2 */
.outer_cache = {
.resume = l2c_resume,
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 7e7583ddd607..1ced8a0f7a52 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -148,11 +148,14 @@ static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs);
static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t handle, struct dma_attrs *attrs);
+static int arm_coherent_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs);
struct dma_map_ops arm_coherent_dma_ops = {
.alloc = arm_coherent_dma_alloc,
.free = arm_coherent_dma_free,
- .mmap = arm_dma_mmap,
+ .mmap = arm_coherent_dma_mmap,
.get_sgtable = arm_dma_get_sgtable,
.map_page = arm_coherent_dma_map_page,
.map_sg = arm_dma_map_sg,
@@ -690,10 +693,7 @@ static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
attrs, __builtin_return_address(0));
}
-/*
- * Create userspace mapping for the DMA-coherent memory.
- */
-int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+static int __arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size,
struct dma_attrs *attrs)
{
@@ -704,8 +704,6 @@ int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
unsigned long pfn = dma_to_pfn(dev, dma_addr);
unsigned long off = vma->vm_pgoff;
- vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
-
if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
return ret;
@@ -721,6 +719,26 @@ int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
}
/*
+ * Create userspace mapping for the DMA-coherent memory.
+ */
+static int arm_coherent_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs)
+{
+ return __arm_dma_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
+}
+
+int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs)
+{
+#ifdef CONFIG_MMU
+ vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
+#endif /* CONFIG_MMU */
+ return __arm_dma_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
+}
+
+/*
* Free a buffer as defined by the above mapping.
*/
static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 6333d9c17875..0d629b8f973f 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -276,7 +276,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto no_context;
if (user_mode(regs))
diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c
index b98895d9fe57..ee8dfa793989 100644
--- a/arch/arm/mm/highmem.c
+++ b/arch/arm/mm/highmem.c
@@ -59,6 +59,7 @@ void *kmap_atomic(struct page *page)
void *kmap;
int type;
+ preempt_disable();
pagefault_disable();
if (!PageHighMem(page))
return page_address(page);
@@ -121,6 +122,7 @@ void __kunmap_atomic(void *kvaddr)
kunmap_high(pte_page(pkmap_page_table[PKMAP_NR(vaddr)]));
}
pagefault_enable();
+ preempt_enable();
}
EXPORT_SYMBOL(__kunmap_atomic);
@@ -130,6 +132,7 @@ void *kmap_atomic_pfn(unsigned long pfn)
int idx, type;
struct page *page = pfn_to_page(pfn);
+ preempt_disable();
pagefault_disable();
if (!PageHighMem(page))
return page_address(page);
diff --git a/arch/arm/mm/hugetlbpage.c b/arch/arm/mm/hugetlbpage.c
index c72412415093..fcafb521f14e 100644
--- a/arch/arm/mm/hugetlbpage.c
+++ b/arch/arm/mm/hugetlbpage.c
@@ -41,11 +41,6 @@ int pud_huge(pud_t pud)
return 0;
}
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
- return 0;
-}
-
int pmd_huge(pmd_t pmd)
{
return pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index be92fa0f2f35..8a63b4cdc0f2 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -268,6 +268,7 @@ void __init arm_memblock_init(const struct machine_desc *mdesc)
if (mdesc->reserve)
mdesc->reserve();
+ early_init_fdt_reserve_self();
early_init_fdt_scan_reserved_mem();
/* reserve memory for DMA contiguous allocations */
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 7186382672b5..6ca7d9aa896f 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1387,123 +1387,98 @@ static void __init map_lowmem(void)
}
}
-#ifdef CONFIG_ARM_LPAE
+#ifdef CONFIG_ARM_PV_FIXUP
+extern unsigned long __atags_pointer;
+typedef void pgtables_remap(long long offset, unsigned long pgd, void *bdata);
+pgtables_remap lpae_pgtables_remap_asm;
+
/*
* early_paging_init() recreates boot time page table setup, allowing machines
* to switch over to a high (>4G) address space on LPAE systems
*/
-void __init early_paging_init(const struct machine_desc *mdesc,
- struct proc_info_list *procinfo)
+void __init early_paging_init(const struct machine_desc *mdesc)
{
- pmdval_t pmdprot = procinfo->__cpu_mm_mmu_flags;
- unsigned long map_start, map_end;
- pgd_t *pgd0, *pgdk;
- pud_t *pud0, *pudk, *pud_start;
- pmd_t *pmd0, *pmdk;
- phys_addr_t phys;
- int i;
+ pgtables_remap *lpae_pgtables_remap;
+ unsigned long pa_pgd;
+ unsigned int cr, ttbcr;
+ long long offset;
+ void *boot_data;
- if (!(mdesc->init_meminfo))
+ if (!mdesc->pv_fixup)
return;
- /* remap kernel code and data */
- map_start = init_mm.start_code & PMD_MASK;
- map_end = ALIGN(init_mm.brk, PMD_SIZE);
+ offset = mdesc->pv_fixup();
+ if (offset == 0)
+ return;
- /* get a handle on things... */
- pgd0 = pgd_offset_k(0);
- pud_start = pud0 = pud_offset(pgd0, 0);
- pmd0 = pmd_offset(pud0, 0);
+ /*
+ * Get the address of the remap function in the 1:1 identity
+ * mapping setup by the early page table assembly code. We
+ * must get this prior to the pv update. The following barrier
+ * ensures that this is complete before we fixup any P:V offsets.
+ */
+ lpae_pgtables_remap = (pgtables_remap *)(unsigned long)__pa(lpae_pgtables_remap_asm);
+ pa_pgd = __pa(swapper_pg_dir);
+ boot_data = __va(__atags_pointer);
+ barrier();
- pgdk = pgd_offset_k(map_start);
- pudk = pud_offset(pgdk, map_start);
- pmdk = pmd_offset(pudk, map_start);
+ pr_info("Switching physical address space to 0x%08llx\n",
+ (u64)PHYS_OFFSET + offset);
- mdesc->init_meminfo();
+ /* Re-set the phys pfn offset, and the pv offset */
+ __pv_offset += offset;
+ __pv_phys_pfn_offset += PFN_DOWN(offset);
/* Run the patch stub to update the constants */
fixup_pv_table(&__pv_table_begin,
(&__pv_table_end - &__pv_table_begin) << 2);
/*
- * Cache cleaning operations for self-modifying code
- * We should clean the entries by MVA but running a
- * for loop over every pv_table entry pointer would
- * just complicate the code.
- */
- flush_cache_louis();
- dsb(ishst);
- isb();
-
- /*
- * FIXME: This code is not architecturally compliant: we modify
- * the mappings in-place, indeed while they are in use by this
- * very same code. This may lead to unpredictable behaviour of
- * the CPU.
- *
- * Even modifying the mappings in a separate page table does
- * not resolve this.
- *
- * The architecture strongly recommends that when a mapping is
- * changed, that it is changed by first going via an invalid
- * mapping and back to the new mapping. This is to ensure that
- * no TLB conflicts (caused by the TLB having more than one TLB
- * entry match a translation) can occur. However, doing that
- * here will result in unmapping the code we are running.
- */
- pr_warn("WARNING: unsafe modification of in-place page tables - tainting kernel\n");
- add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
-
- /*
- * Remap level 1 table. This changes the physical addresses
- * used to refer to the level 2 page tables to the high
- * physical address alias, leaving everything else the same.
- */
- for (i = 0; i < PTRS_PER_PGD; pud0++, i++) {
- set_pud(pud0,
- __pud(__pa(pmd0) | PMD_TYPE_TABLE | L_PGD_SWAPPER));
- pmd0 += PTRS_PER_PMD;
- }
-
- /*
- * Remap the level 2 table, pointing the mappings at the high
- * physical address alias of these pages.
- */
- phys = __pa(map_start);
- do {
- *pmdk++ = __pmd(phys | pmdprot);
- phys += PMD_SIZE;
- } while (phys < map_end);
-
- /*
- * Ensure that the above updates are flushed out of the cache.
- * This is not strictly correct; on a system where the caches
- * are coherent with each other, but the MMU page table walks
- * may not be coherent, flush_cache_all() may be a no-op, and
- * this will fail.
+ * We changing not only the virtual to physical mapping, but also
+ * the physical addresses used to access memory. We need to flush
+ * all levels of cache in the system with caching disabled to
+ * ensure that all data is written back, and nothing is prefetched
+ * into the caches. We also need to prevent the TLB walkers
+ * allocating into the caches too. Note that this is ARMv7 LPAE
+ * specific.
*/
+ cr = get_cr();
+ set_cr(cr & ~(CR_I | CR_C));
+ asm("mrc p15, 0, %0, c2, c0, 2" : "=r" (ttbcr));
+ asm volatile("mcr p15, 0, %0, c2, c0, 2"
+ : : "r" (ttbcr & ~(3 << 8 | 3 << 10)));
flush_cache_all();
/*
- * Re-write the TTBR values to point them at the high physical
- * alias of the page tables. We expect __va() will work on
- * cpu_get_pgd(), which returns the value of TTBR0.
+ * Fixup the page tables - this must be in the idmap region as
+ * we need to disable the MMU to do this safely, and hence it
+ * needs to be assembly. It's fairly simple, as we're using the
+ * temporary tables setup by the initial assembly code.
*/
- cpu_switch_mm(pgd0, &init_mm);
- cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET);
+ lpae_pgtables_remap(offset, pa_pgd, boot_data);
- /* Finally flush any stale TLB values. */
- local_flush_bp_all();
- local_flush_tlb_all();
+ /* Re-enable the caches and cacheable TLB walks */
+ asm volatile("mcr p15, 0, %0, c2, c0, 2" : : "r" (ttbcr));
+ set_cr(cr);
}
#else
-void __init early_paging_init(const struct machine_desc *mdesc,
- struct proc_info_list *procinfo)
+void __init early_paging_init(const struct machine_desc *mdesc)
{
- if (mdesc->init_meminfo)
- mdesc->init_meminfo();
+ long long offset;
+
+ if (!mdesc->pv_fixup)
+ return;
+
+ offset = mdesc->pv_fixup();
+ if (offset == 0)
+ return;
+
+ pr_crit("Physical address space modification is only to support Keystone2.\n");
+ pr_crit("Please enable ARM_LPAE and ARM_PATCH_PHYS_VIRT support to use this\n");
+ pr_crit("feature. Your kernel may crash now, have a good day.\n");
+ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
}
#endif
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index a014dfacd5ca..afd7e05d95f1 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -304,15 +304,6 @@ void __init sanity_check_meminfo(void)
}
/*
- * early_paging_init() recreates boot time page table setup, allowing machines
- * to switch over to a high (>4G) address space on LPAE systems
- */
-void __init early_paging_init(const struct machine_desc *mdesc,
- struct proc_info_list *procinfo)
-{
-}
-
-/*
* paging_init() sets up the page tables, initialises the zone memory
* maps, and sets up the zero page, bad page and bad page tables.
*/
diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S
index 10405b8d31af..c6141a5435c3 100644
--- a/arch/arm/mm/proc-v7-2level.S
+++ b/arch/arm/mm/proc-v7-2level.S
@@ -36,14 +36,16 @@
*
* It is assumed that:
* - we are not using split page tables
+ *
+ * Note that we always need to flush BTAC/BTB if IBE is set
+ * even on Cortex-A8 revisions not affected by 430973.
+ * If IBE is not set, the flush BTAC/BTB won't do anything.
*/
ENTRY(cpu_ca8_switch_mm)
#ifdef CONFIG_MMU
mov r2, #0
-#ifdef CONFIG_ARM_ERRATA_430973
mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB
#endif
-#endif
ENTRY(cpu_v7_switch_mm)
#ifdef CONFIG_MMU
mmid r1, r1 @ get mm->context.id
@@ -148,10 +150,10 @@ ENDPROC(cpu_v7_set_pte_ext)
* Macro for setting up the TTBRx and TTBCR registers.
* - \ttb0 and \ttb1 updated with the corresponding flags.
*/
- .macro v7_ttb_setup, zero, ttbr0, ttbr1, tmp
+ .macro v7_ttb_setup, zero, ttbr0l, ttbr0h, ttbr1, tmp
mcr p15, 0, \zero, c2, c0, 2 @ TTB control register
- ALT_SMP(orr \ttbr0, \ttbr0, #TTB_FLAGS_SMP)
- ALT_UP(orr \ttbr0, \ttbr0, #TTB_FLAGS_UP)
+ ALT_SMP(orr \ttbr0l, \ttbr0l, #TTB_FLAGS_SMP)
+ ALT_UP(orr \ttbr0l, \ttbr0l, #TTB_FLAGS_UP)
ALT_SMP(orr \ttbr1, \ttbr1, #TTB_FLAGS_SMP)
ALT_UP(orr \ttbr1, \ttbr1, #TTB_FLAGS_UP)
mcr p15, 0, \ttbr1, c2, c0, 1 @ load TTB1
diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
index d3daed0ae0ad..5e5720e8bc5f 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -126,11 +126,10 @@ ENDPROC(cpu_v7_set_pte_ext)
* Macro for setting up the TTBRx and TTBCR registers.
* - \ttbr1 updated.
*/
- .macro v7_ttb_setup, zero, ttbr0, ttbr1, tmp
+ .macro v7_ttb_setup, zero, ttbr0l, ttbr0h, ttbr1, tmp
ldr \tmp, =swapper_pg_dir @ swapper_pg_dir virtual address
- mov \tmp, \tmp, lsr #ARCH_PGD_SHIFT
- cmp \ttbr1, \tmp @ PHYS_OFFSET > PAGE_OFFSET?
- mrc p15, 0, \tmp, c2, c0, 2 @ TTB control register
+ cmp \ttbr1, \tmp, lsr #12 @ PHYS_OFFSET > PAGE_OFFSET?
+ mrc p15, 0, \tmp, c2, c0, 2 @ TTB control egister
orr \tmp, \tmp, #TTB_EAE
ALT_SMP(orr \tmp, \tmp, #TTB_FLAGS_SMP)
ALT_UP(orr \tmp, \tmp, #TTB_FLAGS_UP)
@@ -143,13 +142,10 @@ ENDPROC(cpu_v7_set_pte_ext)
*/
orrls \tmp, \tmp, #TTBR1_SIZE @ TTBCR.T1SZ
mcr p15, 0, \tmp, c2, c0, 2 @ TTBCR
- mov \tmp, \ttbr1, lsr #(32 - ARCH_PGD_SHIFT) @ upper bits
- mov \ttbr1, \ttbr1, lsl #ARCH_PGD_SHIFT @ lower bits
+ mov \tmp, \ttbr1, lsr #20
+ mov \ttbr1, \ttbr1, lsl #12
addls \ttbr1, \ttbr1, #TTBR1_OFFSET
mcrr p15, 1, \ttbr1, \tmp, c2 @ load TTBR1
- mov \tmp, \ttbr0, lsr #(32 - ARCH_PGD_SHIFT) @ upper bits
- mov \ttbr0, \ttbr0, lsl #ARCH_PGD_SHIFT @ lower bits
- mcrr p15, 0, \ttbr0, \tmp, c2 @ load TTBR0
.endm
/*
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 3d1054f11a8a..0716bbe19872 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -252,6 +252,12 @@ ENDPROC(cpu_pj4b_do_resume)
* Initialise TLB, Caches, and MMU state ready to switch the MMU
* on. Return in r0 the new CP15 C1 control register setting.
*
+ * r1, r2, r4, r5, r9, r13 must be preserved - r13 is not a stack
+ * r4: TTBR0 (low word)
+ * r5: TTBR0 (high word if LPAE)
+ * r8: TTBR1
+ * r9: Main ID register
+ *
* This should be able to cover all ARMv7 cores.
*
* It is assumed that:
@@ -279,6 +285,78 @@ __v7_ca17mp_setup:
#endif
b __v7_setup
+/*
+ * Errata:
+ * r0, r10 available for use
+ * r1, r2, r4, r5, r9, r13: must be preserved
+ * r3: contains MIDR rX number in bits 23-20
+ * r6: contains MIDR rXpY as 8-bit XY number
+ * r9: MIDR
+ */
+__ca8_errata:
+#if defined(CONFIG_ARM_ERRATA_430973) && !defined(CONFIG_ARCH_MULTIPLATFORM)
+ teq r3, #0x00100000 @ only present in r1p*
+ mrceq p15, 0, r0, c1, c0, 1 @ read aux control register
+ orreq r0, r0, #(1 << 6) @ set IBE to 1
+ mcreq p15, 0, r0, c1, c0, 1 @ write aux control register
+#endif
+#ifdef CONFIG_ARM_ERRATA_458693
+ teq r6, #0x20 @ only present in r2p0
+ mrceq p15, 0, r0, c1, c0, 1 @ read aux control register
+ orreq r0, r0, #(1 << 5) @ set L1NEON to 1
+ orreq r0, r0, #(1 << 9) @ set PLDNOP to 1
+ mcreq p15, 0, r0, c1, c0, 1 @ write aux control register
+#endif
+#ifdef CONFIG_ARM_ERRATA_460075
+ teq r6, #0x20 @ only present in r2p0
+ mrceq p15, 1, r0, c9, c0, 2 @ read L2 cache aux ctrl register
+ tsteq r0, #1 << 22
+ orreq r0, r0, #(1 << 22) @ set the Write Allocate disable bit
+ mcreq p15, 1, r0, c9, c0, 2 @ write the L2 cache aux ctrl register
+#endif
+ b __errata_finish
+
+__ca9_errata:
+#ifdef CONFIG_ARM_ERRATA_742230
+ cmp r6, #0x22 @ only present up to r2p2
+ mrcle p15, 0, r0, c15, c0, 1 @ read diagnostic register
+ orrle r0, r0, #1 << 4 @ set bit #4
+ mcrle p15, 0, r0, c15, c0, 1 @ write diagnostic register
+#endif
+#ifdef CONFIG_ARM_ERRATA_742231
+ teq r6, #0x20 @ present in r2p0
+ teqne r6, #0x21 @ present in r2p1
+ teqne r6, #0x22 @ present in r2p2
+ mrceq p15, 0, r0, c15, c0, 1 @ read diagnostic register
+ orreq r0, r0, #1 << 12 @ set bit #12
+ orreq r0, r0, #1 << 22 @ set bit #22
+ mcreq p15, 0, r0, c15, c0, 1 @ write diagnostic register
+#endif
+#ifdef CONFIG_ARM_ERRATA_743622
+ teq r3, #0x00200000 @ only present in r2p*
+ mrceq p15, 0, r0, c15, c0, 1 @ read diagnostic register
+ orreq r0, r0, #1 << 6 @ set bit #6
+ mcreq p15, 0, r0, c15, c0, 1 @ write diagnostic register
+#endif
+#if defined(CONFIG_ARM_ERRATA_751472) && defined(CONFIG_SMP)
+ ALT_SMP(cmp r6, #0x30) @ present prior to r3p0
+ ALT_UP_B(1f)
+ mrclt p15, 0, r0, c15, c0, 1 @ read diagnostic register
+ orrlt r0, r0, #1 << 11 @ set bit #11
+ mcrlt p15, 0, r0, c15, c0, 1 @ write diagnostic register
+1:
+#endif
+ b __errata_finish
+
+__ca15_errata:
+#ifdef CONFIG_ARM_ERRATA_773022
+ cmp r6, #0x4 @ only present up to r0p4
+ mrcle p15, 0, r0, c1, c0, 1 @ read aux control register
+ orrle r0, r0, #1 << 1 @ disable loop buffer
+ mcrle p15, 0, r0, c1, c0, 1 @ write aux control register
+#endif
+ b __errata_finish
+
__v7_pj4b_setup:
#ifdef CONFIG_CPU_PJ4B
@@ -336,99 +414,41 @@ __v7_pj4b_setup:
__v7_setup:
adr r12, __v7_setup_stack @ the local stack
stmia r12, {r0-r5, r7, r9, r11, lr}
- bl v7_flush_dcache_louis
+ bl v7_invalidate_l1
ldmia r12, {r0-r5, r7, r9, r11, lr}
- mrc p15, 0, r0, c0, c0, 0 @ read main ID register
- and r10, r0, #0xff000000 @ ARM?
- teq r10, #0x41000000
- bne 3f
- and r5, r0, #0x00f00000 @ variant
- and r6, r0, #0x0000000f @ revision
- orr r6, r6, r5, lsr #20-4 @ combine variant and revision
- ubfx r0, r0, #4, #12 @ primary part number
+ and r0, r9, #0xff000000 @ ARM?
+ teq r0, #0x41000000
+ bne __errata_finish
+ and r3, r9, #0x00f00000 @ variant
+ and r6, r9, #0x0000000f @ revision
+ orr r6, r6, r3, lsr #20-4 @ combine variant and revision
+ ubfx r0, r9, #4, #12 @ primary part number
/* Cortex-A8 Errata */
ldr r10, =0x00000c08 @ Cortex-A8 primary part number
teq r0, r10
- bne 2f
-#if defined(CONFIG_ARM_ERRATA_430973) && !defined(CONFIG_ARCH_MULTIPLATFORM)
-
- teq r5, #0x00100000 @ only present in r1p*
- mrceq p15, 0, r10, c1, c0, 1 @ read aux control register
- orreq r10, r10, #(1 << 6) @ set IBE to 1
- mcreq p15, 0, r10, c1, c0, 1 @ write aux control register
-#endif
-#ifdef CONFIG_ARM_ERRATA_458693
- teq r6, #0x20 @ only present in r2p0
- mrceq p15, 0, r10, c1, c0, 1 @ read aux control register
- orreq r10, r10, #(1 << 5) @ set L1NEON to 1
- orreq r10, r10, #(1 << 9) @ set PLDNOP to 1
- mcreq p15, 0, r10, c1, c0, 1 @ write aux control register
-#endif
-#ifdef CONFIG_ARM_ERRATA_460075
- teq r6, #0x20 @ only present in r2p0
- mrceq p15, 1, r10, c9, c0, 2 @ read L2 cache aux ctrl register
- tsteq r10, #1 << 22
- orreq r10, r10, #(1 << 22) @ set the Write Allocate disable bit
- mcreq p15, 1, r10, c9, c0, 2 @ write the L2 cache aux ctrl register
-#endif
- b 3f
+ beq __ca8_errata
/* Cortex-A9 Errata */
-2: ldr r10, =0x00000c09 @ Cortex-A9 primary part number
+ ldr r10, =0x00000c09 @ Cortex-A9 primary part number
teq r0, r10
- bne 3f
-#ifdef CONFIG_ARM_ERRATA_742230
- cmp r6, #0x22 @ only present up to r2p2
- mrcle p15, 0, r10, c15, c0, 1 @ read diagnostic register
- orrle r10, r10, #1 << 4 @ set bit #4
- mcrle p15, 0, r10, c15, c0, 1 @ write diagnostic register
-#endif
-#ifdef CONFIG_ARM_ERRATA_742231
- teq r6, #0x20 @ present in r2p0
- teqne r6, #0x21 @ present in r2p1
- teqne r6, #0x22 @ present in r2p2
- mrceq p15, 0, r10, c15, c0, 1 @ read diagnostic register
- orreq r10, r10, #1 << 12 @ set bit #12
- orreq r10, r10, #1 << 22 @ set bit #22
- mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register
-#endif
-#ifdef CONFIG_ARM_ERRATA_743622
- teq r5, #0x00200000 @ only present in r2p*
- mrceq p15, 0, r10, c15, c0, 1 @ read diagnostic register
- orreq r10, r10, #1 << 6 @ set bit #6
- mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register
-#endif
-#if defined(CONFIG_ARM_ERRATA_751472) && defined(CONFIG_SMP)
- ALT_SMP(cmp r6, #0x30) @ present prior to r3p0
- ALT_UP_B(1f)
- mrclt p15, 0, r10, c15, c0, 1 @ read diagnostic register
- orrlt r10, r10, #1 << 11 @ set bit #11
- mcrlt p15, 0, r10, c15, c0, 1 @ write diagnostic register
-1:
-#endif
+ beq __ca9_errata
/* Cortex-A15 Errata */
-3: ldr r10, =0x00000c0f @ Cortex-A15 primary part number
+ ldr r10, =0x00000c0f @ Cortex-A15 primary part number
teq r0, r10
- bne 4f
+ beq __ca15_errata
-#ifdef CONFIG_ARM_ERRATA_773022
- cmp r6, #0x4 @ only present up to r0p4
- mrcle p15, 0, r10, c1, c0, 1 @ read aux control register
- orrle r10, r10, #1 << 1 @ disable loop buffer
- mcrle p15, 0, r10, c1, c0, 1 @ write aux control register
-#endif
-
-4: mov r10, #0
+__errata_finish:
+ mov r10, #0
mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate
#ifdef CONFIG_MMU
mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs
- v7_ttb_setup r10, r4, r8, r5 @ TTBCR, TTBRx setup
- ldr r5, =PRRR @ PRRR
+ v7_ttb_setup r10, r4, r5, r8, r3 @ TTBCR, TTBRx setup
+ ldr r3, =PRRR @ PRRR
ldr r6, =NMRR @ NMRR
- mcr p15, 0, r5, c10, c2, 0 @ write PRRR
+ mcr p15, 0, r3, c10, c2, 0 @ write PRRR
mcr p15, 0, r6, c10, c2, 1 @ write NMRR
#endif
dsb @ Complete invalidations
@@ -437,22 +457,22 @@ __v7_setup:
and r0, r0, #(0xf << 12) @ ThumbEE enabled field
teq r0, #(1 << 12) @ check if ThumbEE is present
bne 1f
- mov r5, #0
- mcr p14, 6, r5, c1, c0, 0 @ Initialize TEEHBR to 0
+ mov r3, #0
+ mcr p14, 6, r3, c1, c0, 0 @ Initialize TEEHBR to 0
mrc p14, 6, r0, c0, c0, 0 @ load TEECR
orr r0, r0, #1 @ set the 1st bit in order to
mcr p14, 6, r0, c0, c0, 0 @ stop userspace TEEHBR access
1:
#endif
- adr r5, v7_crval
- ldmia r5, {r5, r6}
+ adr r3, v7_crval
+ ldmia r3, {r3, r6}
ARM_BE8(orr r6, r6, #1 << 25) @ big-endian page tables
#ifdef CONFIG_SWP_EMULATE
- orr r5, r5, #(1 << 10) @ set SW bit in "clear"
+ orr r3, r3, #(1 << 10) @ set SW bit in "clear"
bic r6, r6, #(1 << 10) @ clear it in "mmuset"
#endif
mrc p15, 0, r0, c1, c0, 0 @ read control register
- bic r0, r0, r5 @ clear bits them
+ bic r0, r0, r3 @ clear bits them
orr r0, r0, r6 @ set them
THUMB( orr r0, r0, #1 << 30 ) @ Thumb exceptions
ret lr @ return to head.S:__ret
diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S
index e08e1f2bab76..67d9209077c6 100644
--- a/arch/arm/mm/proc-v7m.S
+++ b/arch/arm/mm/proc-v7m.S
@@ -98,7 +98,7 @@ __v7m_setup:
str r5, [r0, V7M_SCB_SHPR3] @ set PendSV priority
@ SVC to run the kernel in this mode
- adr r1, BSYM(1f)
+ badr r1, 1f
ldr r5, [r12, #11 * 4] @ read the SVC vector entry
str r1, [r12, #11 * 4] @ write the temporary SVC vector entry
mov r6, lr @ save LR
diff --git a/arch/arm/mm/pv-fixup-asm.S b/arch/arm/mm/pv-fixup-asm.S
new file mode 100644
index 000000000000..1867f3e43016
--- /dev/null
+++ b/arch/arm/mm/pv-fixup-asm.S
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 Russell King
+ *
+ * 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 assembly is required to safely remap the physical address space
+ * for Keystone 2
+ */
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/cp15.h>
+#include <asm/memory.h>
+#include <asm/pgtable.h>
+
+ .section ".idmap.text", "ax"
+
+#define L1_ORDER 3
+#define L2_ORDER 3
+
+ENTRY(lpae_pgtables_remap_asm)
+ stmfd sp!, {r4-r8, lr}
+
+ mrc p15, 0, r8, c1, c0, 0 @ read control reg
+ bic ip, r8, #CR_M @ disable caches and MMU
+ mcr p15, 0, ip, c1, c0, 0
+ dsb
+ isb
+
+ /* Update level 2 entries covering the kernel */
+ ldr r6, =(_end - 1)
+ add r7, r2, #0x1000
+ add r6, r7, r6, lsr #SECTION_SHIFT - L2_ORDER
+ add r7, r7, #PAGE_OFFSET >> (SECTION_SHIFT - L2_ORDER)
+1: ldrd r4, [r7]
+ adds r4, r4, r0
+ adc r5, r5, r1
+ strd r4, [r7], #1 << L2_ORDER
+ cmp r7, r6
+ bls 1b
+
+ /* Update level 2 entries for the boot data */
+ add r7, r2, #0x1000
+ add r7, r7, r3, lsr #SECTION_SHIFT - L2_ORDER
+ bic r7, r7, #(1 << L2_ORDER) - 1
+ ldrd r4, [r7]
+ adds r4, r4, r0
+ adc r5, r5, r1
+ strd r4, [r7], #1 << L2_ORDER
+ ldrd r4, [r7]
+ adds r4, r4, r0
+ adc r5, r5, r1
+ strd r4, [r7]
+
+ /* Update level 1 entries */
+ mov r6, #4
+ mov r7, r2
+2: ldrd r4, [r7]
+ adds r4, r4, r0
+ adc r5, r5, r1
+ strd r4, [r7], #1 << L1_ORDER
+ subs r6, r6, #1
+ bne 2b
+
+ mrrc p15, 0, r4, r5, c2 @ read TTBR0
+ adds r4, r4, r0 @ update physical address
+ adc r5, r5, r1
+ mcrr p15, 0, r4, r5, c2 @ write back TTBR0
+ mrrc p15, 1, r4, r5, c2 @ read TTBR1
+ adds r4, r4, r0 @ update physical address
+ adc r5, r5, r1
+ mcrr p15, 1, r4, r5, c2 @ write back TTBR1
+
+ dsb
+
+ mov ip, #0
+ mcr p15, 0, ip, c7, c5, 0 @ I+BTB cache invalidate
+ mcr p15, 0, ip, c8, c7, 0 @ local_flush_tlb_all()
+ dsb
+ isb
+
+ mcr p15, 0, r8, c1, c0, 0 @ re-enable MMU
+ dsb
+ isb
+
+ ldmfd sp!, {r4-r8, pc}
+ENDPROC(lpae_pgtables_remap_asm)
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index e0e23582c8b4..4550d247e308 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -873,6 +873,16 @@ b_epilogue:
off = offsetof(struct sk_buff, queue_mapping);
emit(ARM_LDRH_I(r_A, r_skb, off), ctx);
break;
+ case BPF_LDX | BPF_W | BPF_ABS:
+ /*
+ * load a 32bit word from struct seccomp_data.
+ * seccomp_check_filter() will already have checked
+ * that k is 32bit aligned and lies within the
+ * struct seccomp_data.
+ */
+ ctx->seen |= SEEN_SKB;
+ emit(ARM_LDR_I(r_A, r_skb, k), ctx);
+ break;
default:
return -1;
}
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 6416e03b4482..1e460b4ee3b9 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -38,6 +38,10 @@
#include <linux/omap-dma.h>
+#ifdef CONFIG_ARCH_OMAP1
+#include <mach/soc.h>
+#endif
+
/*
* MAX_LOGICAL_DMA_CH_COUNT: the maximum number of logical DMA
* channels that an instance of the SDMA IP block can support. Used
diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
index f5b00f41c4f6..2235081a04ee 100644
--- a/arch/arm/plat-orion/common.c
+++ b/arch/arm/plat-orion/common.c
@@ -28,11 +28,7 @@
void __init orion_clkdev_add(const char *con_id, const char *dev_id,
struct clk *clk)
{
- struct clk_lookup *cl;
-
- cl = clkdev_alloc(clk, con_id, dev_id);
- if (cl)
- clkdev_add(cl);
+ clkdev_create(clk, con_id, "%s", dev_id);
}
/* Create clkdev entries for all orion platforms except kirkwood.
diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index e2be70df06c6..efa6e85619ad 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -389,7 +389,7 @@ static int s3c_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
- clk_enable(adc->clk);
+ clk_prepare_enable(adc->clk);
tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
@@ -413,7 +413,7 @@ static int s3c_adc_remove(struct platform_device *pdev)
{
struct adc_device *adc = platform_get_drvdata(pdev);
- clk_disable(adc->clk);
+ clk_disable_unprepare(adc->clk);
regulator_disable(adc->vdd);
return 0;
@@ -475,7 +475,7 @@ static int s3c_adc_resume(struct device *dev)
#define s3c_adc_resume NULL
#endif
-static struct platform_device_id s3c_adc_driver_ids[] = {
+static const struct platform_device_id s3c_adc_driver_ids[] = {
{
.name = "s3c24xx-adc",
.driver_data = TYPE_ADCV1,
diff --git a/arch/arm/vdso/Makefile b/arch/arm/vdso/Makefile
index 8aa791051029..9d259d94e429 100644
--- a/arch/arm/vdso/Makefile
+++ b/arch/arm/vdso/Makefile
@@ -6,9 +6,15 @@ obj-vdso := vgettimeofday.o datapage.o
targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.so.raw vdso.lds
obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
-ccflags-y := -shared -fPIC -fno-common -fno-builtin -fno-stack-protector
-ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 -DDISABLE_BRANCH_PROFILING
-ccflags-y += -Wl,--no-undefined $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+ccflags-y := -fPIC -fno-common -fno-builtin -fno-stack-protector
+ccflags-y += -DDISABLE_BRANCH_PROFILING
+
+VDSO_LDFLAGS := -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1
+VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
+VDSO_LDFLAGS += -nostdlib -shared
+VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--build-id)
+VDSO_LDFLAGS += $(call cc-option, -fuse-ld=bfd)
obj-$(CONFIG_VDSO) += vdso.o
extra-$(CONFIG_VDSO) += vdso.lds
@@ -40,10 +46,8 @@ $(obj)/%.so: $(obj)/%.so.dbg FORCE
# Actual build commands
quiet_cmd_vdsold = VDSO $@
- cmd_vdsold = $(CC) $(c_flags) -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) \
- $(call cc-ldoption, -Wl$(comma)--build-id) \
- -Wl,-Bsymbolic -Wl,-z,max-page-size=4096 \
- -Wl,-z,common-page-size=4096 -o $@
+ cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \
+ -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@
quiet_cmd_vdsomunge = MUNGE $@
cmd_vdsomunge = $(objtree)/$(obj)/vdsomunge $< $@
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index f6e4d56eda00..2a61e4b04600 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -445,6 +445,19 @@ static void vfp_enable(void *unused)
set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
}
+/* Called by platforms on which we want to disable VFP because it may not be
+ * present on all CPUs within a SMP complex. Needs to be called prior to
+ * vfp_init().
+ */
+void vfp_disable(void)
+{
+ if (VFP_arch) {
+ pr_debug("%s: should be called prior to vfp_init\n", __func__);
+ return;
+ }
+ VFP_arch = 1;
+}
+
#ifdef CONFIG_CPU_PM
static int vfp_pm_suspend(void)
{
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 7796af4b1d6f..0f6edb14b7e4 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1,5 +1,6 @@
config ARM64
def_bool y
+ select ACPI_CCA_REQUIRED if ACPI
select ACPI_GENERIC_GSI if ACPI
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
@@ -22,6 +23,7 @@ config ARM64
select BUILDTIME_EXTABLE_SORT
select CLONE_BACKWARDS
select COMMON_CLK
+ select EDAC_SUPPORT
select CPU_PM if (SUSPEND || CPU_IDLE)
select DCACHE_WORD_ACCESS
select GENERIC_ALLOCATOR
@@ -71,6 +73,7 @@ config ARM64
select HAVE_RCU_TABLE_FREE
select HAVE_SYSCALL_TRACEPOINTS
select IRQ_DOMAIN
+ select IRQ_FORCED_THREADING
select MODULES_USE_ELF_RELA
select NO_BOOTMEM
select OF
@@ -181,6 +184,11 @@ config ARCH_FSL_LS2085A
help
This enables support for Freescale LS2085A SOC.
+config ARCH_HISI
+ bool "Hisilicon SoC Family"
+ help
+ This enables support for Hisilicon ARMv8 SoC family
+
config ARCH_MEDIATEK
bool "Mediatek MT65xx & MT81xx ARMv8 SoC"
select ARM_GIC
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index ad26a752b976..38913be23695 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -4,6 +4,7 @@ dts-dirs += arm
dts-dirs += cavium
dts-dirs += exynos
dts-dirs += freescale
+dts-dirs += hisilicon
dts-dirs += mediatek
dts-dirs += qcom
dts-dirs += sprd
diff --git a/arch/arm64/boot/dts/apm/apm-storm.dtsi b/arch/arm64/boot/dts/apm/apm-storm.dtsi
index c8d3e0e86678..0bb287ca0a98 100644
--- a/arch/arm64/boot/dts/apm/apm-storm.dtsi
+++ b/arch/arm64/boot/dts/apm/apm-storm.dtsi
@@ -374,6 +374,111 @@
};
};
+ msi: msi@79000000 {
+ compatible = "apm,xgene1-msi";
+ msi-controller;
+ reg = <0x00 0x79000000 0x0 0x900000>;
+ interrupts = < 0x0 0x10 0x4
+ 0x0 0x11 0x4
+ 0x0 0x12 0x4
+ 0x0 0x13 0x4
+ 0x0 0x14 0x4
+ 0x0 0x15 0x4
+ 0x0 0x16 0x4
+ 0x0 0x17 0x4
+ 0x0 0x18 0x4
+ 0x0 0x19 0x4
+ 0x0 0x1a 0x4
+ 0x0 0x1b 0x4
+ 0x0 0x1c 0x4
+ 0x0 0x1d 0x4
+ 0x0 0x1e 0x4
+ 0x0 0x1f 0x4>;
+ };
+
+ 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>;
+ };
+ };
+
pcie0: pcie@1f2b0000 {
status = "disabled";
device_type = "pci";
@@ -395,6 +500,7 @@
0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
dma-coherent;
clocks = <&pcie0clk 0>;
+ msi-parent = <&msi>;
};
pcie1: pcie@1f2c0000 {
@@ -418,6 +524,7 @@
0x0 0x0 0x0 0x4 &gic 0x0 0xcb 0x1>;
dma-coherent;
clocks = <&pcie1clk 0>;
+ msi-parent = <&msi>;
};
pcie2: pcie@1f2d0000 {
@@ -441,6 +548,7 @@
0x0 0x0 0x0 0x4 &gic 0x0 0xd1 0x1>;
dma-coherent;
clocks = <&pcie2clk 0>;
+ msi-parent = <&msi>;
};
pcie3: pcie@1f500000 {
@@ -464,6 +572,7 @@
0x0 0x0 0x0 0x4 &gic 0x0 0xd7 0x1>;
dma-coherent;
clocks = <&pcie3clk 0>;
+ msi-parent = <&msi>;
};
pcie4: pcie@1f510000 {
@@ -487,6 +596,7 @@
0x0 0x0 0x0 0x4 &gic 0x0 0xdd 0x1>;
dma-coherent;
clocks = <&pcie4clk 0>;
+ msi-parent = <&msi>;
};
serial0: serial@1c020000 {
diff --git a/arch/arm64/boot/dts/arm/Makefile b/arch/arm64/boot/dts/arm/Makefile
index 301a0dada1fe..c5c98b91514e 100644
--- a/arch/arm64/boot/dts/arm/Makefile
+++ b/arch/arm64/boot/dts/arm/Makefile
@@ -1,5 +1,5 @@
dtb-$(CONFIG_ARCH_VEXPRESS) += foundation-v8.dtb
-dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb
+dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb juno-r1.dtb
dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb
always := $(dtb-y)
diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi
new file mode 100644
index 000000000000..e3ee96036eca
--- /dev/null
+++ b/arch/arm64/boot/dts/arm/juno-base.dtsi
@@ -0,0 +1,154 @@
+ /*
+ * Devices shared by all Juno boards
+ */
+
+ memtimer: timer@2a810000 {
+ compatible = "arm,armv7-timer-mem";
+ reg = <0x0 0x2a810000 0x0 0x10000>;
+ clock-frequency = <50000000>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ status = "disabled";
+ frame@2a830000 {
+ frame-number = <1>;
+ interrupts = <0 60 4>;
+ reg = <0x0 0x2a830000 0x0 0x10000>;
+ };
+ };
+
+ gic: interrupt-controller@2c010000 {
+ compatible = "arm,gic-400", "arm,cortex-a15-gic";
+ reg = <0x0 0x2c010000 0 0x1000>,
+ <0x0 0x2c02f000 0 0x2000>,
+ <0x0 0x2c04f000 0 0x2000>,
+ <0x0 0x2c06f000 0 0x2000>;
+ #address-cells = <2>;
+ #interrupt-cells = <3>;
+ #size-cells = <2>;
+ interrupt-controller;
+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_HIGH)>;
+ ranges = <0 0 0 0x2c1c0000 0 0x40000>;
+ v2m_0: v2m@0 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0 0 0 0x1000>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+ /include/ "juno-clocks.dtsi"
+
+ dma@7ff00000 {
+ compatible = "arm,pl330", "arm,primecell";
+ reg = <0x0 0x7ff00000 0 0x1000>;
+ #dma-cells = <1>;
+ #dma-channels = <8>;
+ #dma-requests = <32>;
+ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_faxiclk>;
+ clock-names = "apb_pclk";
+ };
+
+ soc_uart0: uart@7ff80000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0x7ff80000 0x0 0x1000>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_uartclk>, <&soc_refclk100mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ i2c@7ffa0000 {
+ compatible = "snps,designware-i2c";
+ reg = <0x0 0x7ffa0000 0x0 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <400000>;
+ i2c-sda-hold-time-ns = <500>;
+ clocks = <&soc_smc50mhz>;
+
+ dvi0: dvi-transmitter@70 {
+ compatible = "nxp,tda998x";
+ reg = <0x70>;
+ };
+
+ dvi1: dvi-transmitter@71 {
+ compatible = "nxp,tda998x";
+ reg = <0x71>;
+ };
+ };
+
+ ohci@7ffb0000 {
+ compatible = "generic-ohci";
+ reg = <0x0 0x7ffb0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_usb48mhz>;
+ };
+
+ ehci@7ffc0000 {
+ compatible = "generic-ehci";
+ reg = <0x0 0x7ffc0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_usb48mhz>;
+ };
+
+ memory-controller@7ffd0000 {
+ compatible = "arm,pl354", "arm,primecell";
+ reg = <0 0x7ffd0000 0 0x1000>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_smc50mhz>;
+ clock-names = "apb_pclk";
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ /* last 16MB of the first memory area is reserved for secure world use by firmware */
+ reg = <0x00000000 0x80000000 0x0 0x7f000000>,
+ <0x00000008 0x80000000 0x1 0x80000000>;
+ };
+
+ smb {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0x08000000 0x04000000>,
+ <1 0 0 0x14000000 0x04000000>,
+ <2 0 0 0x18000000 0x04000000>,
+ <3 0 0 0x1c000000 0x04000000>,
+ <4 0 0 0x0c000000 0x04000000>,
+ <5 0 0 0x10000000 0x04000000>;
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 15>;
+ interrupt-map = <0 0 0 &gic 0 0 0 68 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 1 &gic 0 0 0 69 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 2 &gic 0 0 0 70 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 3 &gic 0 0 0 160 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 4 &gic 0 0 0 161 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 5 &gic 0 0 0 162 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 6 &gic 0 0 0 163 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 7 &gic 0 0 0 164 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 8 &gic 0 0 0 165 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 9 &gic 0 0 0 166 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 10 &gic 0 0 0 167 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 11 &gic 0 0 0 168 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 12 &gic 0 0 0 169 IRQ_TYPE_LEVEL_HIGH>;
+
+ /include/ "juno-motherboard.dtsi"
+ };
diff --git a/arch/arm64/boot/dts/arm/juno-clocks.dtsi b/arch/arm64/boot/dts/arm/juno-clocks.dtsi
index c9b89efe0f56..25352ed943e6 100644
--- a/arch/arm64/boot/dts/arm/juno-clocks.dtsi
+++ b/arch/arm64/boot/dts/arm/juno-clocks.dtsi
@@ -36,9 +36,9 @@
clock-output-names = "apb_pclk";
};
- soc_faxiclk: refclk533mhz {
+ soc_faxiclk: refclk400mhz {
compatible = "fixed-clock";
#clock-cells = <0>;
- clock-frequency = <533000000>;
+ clock-frequency = <400000000>;
clock-output-names = "faxi_clk";
};
diff --git a/arch/arm64/boot/dts/arm/juno-motherboard.dtsi b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi
index 351c95bda89e..021e0f40f419 100644
--- a/arch/arm64/boot/dts/arm/juno-motherboard.dtsi
+++ b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi
@@ -54,6 +54,55 @@
regulator-always-on;
};
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ button@1 {
+ debounce_interval = <50>;
+ wakeup = <1>;
+ linux,code = <116>;
+ label = "POWER";
+ gpios = <&iofpga_gpio0 0 0x4>;
+ };
+ button@2 {
+ debounce_interval = <50>;
+ wakeup = <1>;
+ linux,code = <102>;
+ label = "HOME";
+ gpios = <&iofpga_gpio0 1 0x4>;
+ };
+ button@3 {
+ debounce_interval = <50>;
+ wakeup = <1>;
+ linux,code = <152>;
+ label = "RLOCK";
+ gpios = <&iofpga_gpio0 2 0x4>;
+ };
+ button@4 {
+ debounce_interval = <50>;
+ wakeup = <1>;
+ linux,code = <115>;
+ label = "VOL+";
+ gpios = <&iofpga_gpio0 3 0x4>;
+ };
+ button@5 {
+ debounce_interval = <50>;
+ wakeup = <1>;
+ linux,code = <114>;
+ label = "VOL-";
+ gpios = <&iofpga_gpio0 4 0x4>;
+ };
+ button@6 {
+ debounce_interval = <50>;
+ wakeup = <1>;
+ linux,code = <99>;
+ label = "NMI";
+ gpios = <&iofpga_gpio0 5 0x4>;
+ };
+ };
+
ethernet@2,00000000 {
compatible = "smsc,lan9118", "smsc,lan9115";
reg = <2 0x00000000 0x10000>;
@@ -89,6 +138,74 @@
clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
};
+ apbregs@010000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0x010000 0x1000>;
+
+ led@08.0 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x01>;
+ label = "vexpress:0";
+ linux,default-trigger = "heartbeat";
+ default-state = "on";
+ };
+ led@08.1 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x02>;
+ label = "vexpress:1";
+ linux,default-trigger = "mmc0";
+ default-state = "off";
+ };
+ led@08.2 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x04>;
+ label = "vexpress:2";
+ linux,default-trigger = "cpu0";
+ default-state = "off";
+ };
+ led@08.3 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x08>;
+ label = "vexpress:3";
+ linux,default-trigger = "cpu1";
+ default-state = "off";
+ };
+ led@08.4 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x10>;
+ label = "vexpress:4";
+ linux,default-trigger = "cpu2";
+ default-state = "off";
+ };
+ led@08.5 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x20>;
+ label = "vexpress:5";
+ linux,default-trigger = "cpu3";
+ default-state = "off";
+ };
+ led@08.6 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x40>;
+ label = "vexpress:6";
+ default-state = "off";
+ };
+ led@08.7 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x80>;
+ label = "vexpress:7";
+ default-state = "off";
+ };
+ };
+
mmci@050000 {
compatible = "arm,pl180", "arm,primecell";
reg = <0x050000 0x1000>;
@@ -148,5 +265,17 @@
clocks = <&soc_smc50mhz>;
clock-names = "apb_pclk";
};
+
+ iofpga_gpio0: gpio@1d0000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0x1d0000 0x1000>;
+ interrupts = <6>;
+ clocks = <&soc_smc50mhz>;
+ clock-names = "apb_pclk";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
};
diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts
new file mode 100644
index 000000000000..c62751153a4f
--- /dev/null
+++ b/arch/arm64/boot/dts/arm/juno-r1.dts
@@ -0,0 +1,116 @@
+/*
+ * ARM Ltd. Juno Platform
+ *
+ * Copyright (c) 2015 ARM Ltd.
+ *
+ * This file is licensed under a dual GPLv2 or BSD license.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ model = "ARM Juno development board (r1)";
+ compatible = "arm,juno-r1", "arm,juno", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ aliases {
+ serial0 = &soc_uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ A57_0: cpu@0 {
+ compatible = "arm,cortex-a57","arm,armv8";
+ reg = <0x0 0x0>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&A57_L2>;
+ };
+
+ A57_1: cpu@1 {
+ compatible = "arm,cortex-a57","arm,armv8";
+ reg = <0x0 0x1>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&A57_L2>;
+ };
+
+ A53_0: cpu@100 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&A53_L2>;
+ };
+
+ A53_1: cpu@101 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x101>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&A53_L2>;
+ };
+
+ A53_2: cpu@102 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x102>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&A53_L2>;
+ };
+
+ A53_3: cpu@103 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x103>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&A53_L2>;
+ };
+
+ A57_L2: l2-cache0 {
+ compatible = "cache";
+ };
+
+ A53_L2: l2-cache1 {
+ compatible = "cache";
+ };
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_SPI 02 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 06 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&A57_0>,
+ <&A57_1>,
+ <&A53_0>,
+ <&A53_1>,
+ <&A53_2>,
+ <&A53_3>;
+ };
+
+ #include "juno-base.dtsi"
+
+};
+
+&memtimer {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts
index 5e9110a3353d..d7cbdd482a61 100644
--- a/arch/arm64/boot/dts/arm/juno.dts
+++ b/arch/arm64/boot/dts/arm/juno.dts
@@ -91,33 +91,6 @@
};
};
- memory@80000000 {
- device_type = "memory";
- /* last 16MB of the first memory area is reserved for secure world use by firmware */
- reg = <0x00000000 0x80000000 0x0 0x7f000000>,
- <0x00000008 0x80000000 0x1 0x80000000>;
- };
-
- gic: interrupt-controller@2c001000 {
- compatible = "arm,gic-400", "arm,cortex-a15-gic";
- reg = <0x0 0x2c010000 0 0x1000>,
- <0x0 0x2c02f000 0 0x2000>,
- <0x0 0x2c04f000 0 0x2000>,
- <0x0 0x2c06f000 0 0x2000>;
- #address-cells = <0>;
- #interrupt-cells = <3>;
- interrupt-controller;
- interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_HIGH)>;
- };
-
- timer {
- compatible = "arm,armv8-timer";
- interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
- <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
- <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
- <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>;
- };
-
pmu {
compatible = "arm,armv8-pmuv3";
interrupts = <GIC_SPI 02 IRQ_TYPE_LEVEL_HIGH>,
@@ -134,105 +107,5 @@
<&A53_3>;
};
- /include/ "juno-clocks.dtsi"
-
- dma@7ff00000 {
- compatible = "arm,pl330", "arm,primecell";
- reg = <0x0 0x7ff00000 0 0x1000>;
- #dma-cells = <1>;
- #dma-channels = <8>;
- #dma-requests = <32>;
- interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&soc_faxiclk>;
- clock-names = "apb_pclk";
- };
-
- soc_uart0: uart@7ff80000 {
- compatible = "arm,pl011", "arm,primecell";
- reg = <0x0 0x7ff80000 0x0 0x1000>;
- interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&soc_uartclk>, <&soc_refclk100mhz>;
- clock-names = "uartclk", "apb_pclk";
- };
-
- i2c@7ffa0000 {
- compatible = "snps,designware-i2c";
- reg = <0x0 0x7ffa0000 0x0 0x1000>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
- clock-frequency = <400000>;
- i2c-sda-hold-time-ns = <500>;
- clocks = <&soc_smc50mhz>;
-
- dvi0: dvi-transmitter@70 {
- compatible = "nxp,tda998x";
- reg = <0x70>;
- };
-
- dvi1: dvi-transmitter@71 {
- compatible = "nxp,tda998x";
- reg = <0x71>;
- };
- };
-
- ohci@7ffb0000 {
- compatible = "generic-ohci";
- reg = <0x0 0x7ffb0000 0x0 0x10000>;
- interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&soc_usb48mhz>;
- };
-
- ehci@7ffc0000 {
- compatible = "generic-ehci";
- reg = <0x0 0x7ffc0000 0x0 0x10000>;
- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&soc_usb48mhz>;
- };
-
- memory-controller@7ffd0000 {
- compatible = "arm,pl354", "arm,primecell";
- reg = <0 0x7ffd0000 0 0x1000>;
- interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&soc_smc50mhz>;
- clock-names = "apb_pclk";
- };
-
- smb {
- compatible = "simple-bus";
- #address-cells = <2>;
- #size-cells = <1>;
- ranges = <0 0 0 0x08000000 0x04000000>,
- <1 0 0 0x14000000 0x04000000>,
- <2 0 0 0x18000000 0x04000000>,
- <3 0 0 0x1c000000 0x04000000>,
- <4 0 0 0x0c000000 0x04000000>,
- <5 0 0 0x10000000 0x04000000>;
-
- #interrupt-cells = <1>;
- interrupt-map-mask = <0 0 15>;
- interrupt-map = <0 0 0 &gic 0 68 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 1 &gic 0 69 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 2 &gic 0 70 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 3 &gic 0 160 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 4 &gic 0 161 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 5 &gic 0 162 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 6 &gic 0 163 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 7 &gic 0 164 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 8 &gic 0 165 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 9 &gic 0 166 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 10 &gic 0 167 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 11 &gic 0 168 IRQ_TYPE_LEVEL_HIGH>,
- <0 0 12 &gic 0 169 IRQ_TYPE_LEVEL_HIGH>;
-
- /include/ "juno-motherboard.dtsi"
- };
+ #include "juno-base.dtsi"
};
diff --git a/arch/arm64/boot/dts/hisilicon/Makefile b/arch/arm64/boot/dts/hisilicon/Makefile
new file mode 100644
index 000000000000..fa81a6ee6473
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/Makefile
@@ -0,0 +1,5 @@
+dtb-$(CONFIG_ARCH_HISI) += hi6220-hikey.dtb
+
+always := $(dtb-y)
+subdir-y := $(dts-dirs)
+clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
new file mode 100644
index 000000000000..e36a539468a5
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
@@ -0,0 +1,31 @@
+/*
+ * dts file for Hisilicon HiKey Development Board
+ *
+ * Copyright (C) 2015, Hisilicon Ltd.
+ *
+ */
+
+/dts-v1/;
+
+/*Reserved 1MB memory for MCU*/
+/memreserve/ 0x05e00000 0x00100000;
+
+#include "hi6220.dtsi"
+
+/ {
+ model = "HiKey Development Board";
+ compatible = "hisilicon,hi6220-hikey", "hisilicon,hi6220";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0 0x40000000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
new file mode 100644
index 000000000000..3f03380815b6
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
@@ -0,0 +1,171 @@
+/*
+ * dts file for Hisilicon Hi6220 SoC
+ *
+ * Copyright (C) 2015, Hisilicon Ltd.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ compatible = "hisilicon,hi6220";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu0>;
+ };
+ core1 {
+ cpu = <&cpu1>;
+ };
+ core2 {
+ cpu = <&cpu2>;
+ };
+ core3 {
+ cpu = <&cpu3>;
+ };
+ };
+ cluster1 {
+ core0 {
+ cpu = <&cpu4>;
+ };
+ core1 {
+ cpu = <&cpu5>;
+ };
+ core2 {
+ cpu = <&cpu6>;
+ };
+ core3 {
+ cpu = <&cpu7>;
+ };
+ };
+ };
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x0>;
+ enable-method = "psci";
+ };
+
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x1>;
+ enable-method = "psci";
+ };
+
+ cpu2: cpu@2 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x2>;
+ enable-method = "psci";
+ };
+
+ cpu3: cpu@3 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x3>;
+ enable-method = "psci";
+ };
+
+ cpu4: cpu@100 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x100>;
+ enable-method = "psci";
+ };
+
+ cpu5: cpu@101 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x101>;
+ enable-method = "psci";
+ };
+
+ cpu6: cpu@102 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x102>;
+ enable-method = "psci";
+ };
+
+ cpu7: cpu@103 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x103>;
+ enable-method = "psci";
+ };
+ };
+
+ gic: interrupt-controller@f6801000 {
+ compatible = "arm,gic-400";
+ reg = <0x0 0xf6801000 0 0x1000>, /* GICD */
+ <0x0 0xf6802000 0 0x2000>, /* GICC */
+ <0x0 0xf6804000 0 0x2000>, /* GICH */
+ <0x0 0xf6806000 0 0x2000>; /* GICV */
+ #address-cells = <0>;
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ ao_ctrl: ao_ctrl@f7800000 {
+ compatible = "hisilicon,hi6220-aoctrl", "syscon";
+ reg = <0x0 0xf7800000 0x0 0x2000>;
+ #clock-cells = <1>;
+ };
+
+ sys_ctrl: sys_ctrl@f7030000 {
+ compatible = "hisilicon,hi6220-sysctrl", "syscon";
+ reg = <0x0 0xf7030000 0x0 0x2000>;
+ #clock-cells = <1>;
+ };
+
+ media_ctrl: media_ctrl@f4410000 {
+ compatible = "hisilicon,hi6220-mediactrl", "syscon";
+ reg = <0x0 0xf4410000 0x0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ pm_ctrl: pm_ctrl@f7032000 {
+ compatible = "hisilicon,hi6220-pmctrl", "syscon";
+ reg = <0x0 0xf7032000 0x0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ uart0: uart@f8015000 { /* console */
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0xf8015000 0x0 0x1000>;
+ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ao_ctrl 36>, <&ao_ctrl 36>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 924fdb6673ff..27237a1c1a87 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -91,13 +91,13 @@
compatible = "arm,armv8-timer";
interrupt-parent = <&gic>;
interrupts = <GIC_PPI 13
- (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 14
- (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 11
- (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10
- (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
};
soc {
@@ -106,14 +106,13 @@
compatible = "simple-bus";
ranges;
- syscfg_pctl_a: syscfg_pctl_a@10005000 {
- compatible = "mediatek,mt8173-pctl-a-syscfg", "syscon";
- reg = <0 0x10005000 0 0x1000>;
- };
-
- pio: pinctrl@0x10005000 {
+ /*
+ * Pinctrl access register at 0x10005000 through regmap.
+ * Register 0x1000b000 is used by EINT.
+ */
+ pio: pinctrl@10005000 {
compatible = "mediatek,mt8173-pinctrl";
- reg = <0 0x1000B000 0 0x1000>;
+ reg = <0 0x1000b000 0 0x1000>;
mediatek,pctl-regmap = <&syscfg_pctl_a>;
pins-are-numbered;
gpio-controller;
@@ -121,13 +120,18 @@
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+ <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ syscfg_pctl_a: syscfg_pctl_a@10005000 {
+ compatible = "mediatek,mt8173-pctl-a-syscfg", "syscon";
+ reg = <0 0x10005000 0 0x1000>;
};
sysirq: intpol-controller@10200620 {
compatible = "mediatek,mt8173-sysirq",
- "mediatek,mt6577-sysirq";
+ "mediatek,mt6577-sysirq";
interrupt-controller;
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
@@ -149,7 +153,7 @@
uart0: serial@11002000 {
compatible = "mediatek,mt8173-uart",
- "mediatek,mt6577-uart";
+ "mediatek,mt6577-uart";
reg = <0 0x11002000 0 0x400>;
interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_LOW>;
clocks = <&uart_clk>;
@@ -158,7 +162,7 @@
uart1: serial@11003000 {
compatible = "mediatek,mt8173-uart",
- "mediatek,mt6577-uart";
+ "mediatek,mt6577-uart";
reg = <0 0x11003000 0 0x400>;
interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_LOW>;
clocks = <&uart_clk>;
@@ -167,7 +171,7 @@
uart2: serial@11004000 {
compatible = "mediatek,mt8173-uart",
- "mediatek,mt6577-uart";
+ "mediatek,mt6577-uart";
reg = <0 0x11004000 0 0x400>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_LOW>;
clocks = <&uart_clk>;
@@ -176,13 +180,12 @@
uart3: serial@11005000 {
compatible = "mediatek,mt8173-uart",
- "mediatek,mt6577-uart";
+ "mediatek,mt6577-uart";
reg = <0 0x11005000 0 0x400>;
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_LOW>;
clocks = <&uart_clk>;
status = "disabled";
};
};
-
};
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc-pmic-pins.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc-pmic-pins.dtsi
new file mode 100644
index 000000000000..535532b9287f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc-pmic-pins.dtsi
@@ -0,0 +1,30 @@
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+
+&pm8916_gpios {
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pm8916_gpios_default>;
+
+ pm8916_gpios_default: default {
+ usb_hub_reset_pm {
+ pins = "gpio1";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ output-low;
+ };
+ usb_sw_sel_pm {
+ pins = "gpio2";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ input-disable;
+ };
+ usr_led_3_ctrl {
+ pins = "gpio3";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ output-low;
+ };
+ usr_led_4_ctrl {
+ pins = "gpio4";
+ function = PMIC_GPIO_FUNC_NORMAL;
+ output-low;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi
new file mode 100644
index 000000000000..5f7023f90df7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc-soc-pins.dtsi
@@ -0,0 +1,21 @@
+
+#include <dt-bindings/gpio/gpio.h>
+
+&msmgpio {
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&soc_gpios_default>;
+
+ soc_gpios_default: default {
+ usr_led_1_ctrl_default: usr_led_1_ctrl_default {
+ pins = "gpio21";
+ function = "gpio";
+ output-low;
+ };
+ usr_led_2_ctrl_default: usr_led_2_ctrl_default {
+ pins = "gpio120";
+ function = "gpio";
+ output-low;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
index 703a4f16e711..98abece6b233 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
@@ -12,6 +12,9 @@
*/
#include "msm8916.dtsi"
+#include "pm8916.dtsi"
+#include "apq8016-sbc-soc-pins.dtsi"
+#include "apq8016-sbc-pmic-pins.dtsi"
/ {
aliases {
diff --git a/arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi
index bea871b0df13..a1aa0b201e92 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916-mtp.dtsi
@@ -12,6 +12,7 @@
*/
#include "msm8916.dtsi"
+#include "pm8916.dtsi"
/ {
aliases {
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index f212b8303d04..0f49ebd0aa8b 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -77,7 +77,12 @@
ranges = <0 0 0 0xffffffff>;
compatible = "simple-bus";
- pinctrl@1000000 {
+ restart@4ab000 {
+ compatible = "qcom,pshold";
+ reg = <0x4ab000 0x4>;
+ };
+
+ msmgpio: pinctrl@1000000 {
compatible = "qcom,msm8916-pinctrl";
reg = <0x1000000 0x300000>;
interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
@@ -192,5 +197,23 @@
status = "disabled";
};
};
+
+ spmi_bus: spmi@200f000 {
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0x200f000 0x001000>,
+ <0x2400000 0x400000>,
+ <0x2c00000 0x400000>,
+ <0x3800000 0x200000>,
+ <0x200a000 0x002100>;
+ reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+ interrupt-names = "periph_irq";
+ interrupts = <GIC_SPI 190 IRQ_TYPE_NONE>;
+ qcom,ee = <0>;
+ qcom,channel = <0>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <4>;
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/pm8916.dtsi b/arch/arm64/boot/dts/qcom/pm8916.dtsi
new file mode 100644
index 000000000000..b222ece7e3d2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8916.dtsi
@@ -0,0 +1,99 @@
+#include <dt-bindings/iio/qcom,spmi-vadc.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/spmi/spmi.h>
+
+&spmi_bus {
+
+ usid0: pm8916@0 {
+ compatible = "qcom,spmi-pmic";
+ reg = <0x0 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@6000 {
+ compatible = "qcom,pm8941-rtc";
+ reg = <0x6000 0x6100>;
+ reg-names = "rtc", "alarm";
+ interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>;
+ };
+
+ pwrkey@800 {
+ compatible = "qcom,pm8941-pwrkey";
+ reg = <0x800>;
+ interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>;
+ debounce = <15625>;
+ bias-pull-up;
+ };
+
+ pm8916_gpios: gpios@c000 {
+ compatible = "qcom,pm8916-gpio";
+ reg = <0xc000 0x400>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <0 0xc0 0 IRQ_TYPE_NONE>,
+ <0 0xc1 0 IRQ_TYPE_NONE>,
+ <0 0xc2 0 IRQ_TYPE_NONE>,
+ <0 0xc3 0 IRQ_TYPE_NONE>;
+ };
+
+ pm8916_mpps: mpps@a000 {
+ compatible = "qcom,pm8916-mpp";
+ reg = <0xa000 0x400>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <0 0xa0 0 IRQ_TYPE_NONE>,
+ <0 0xa1 0 IRQ_TYPE_NONE>,
+ <0 0xa2 0 IRQ_TYPE_NONE>,
+ <0 0xa3 0 IRQ_TYPE_NONE>;
+ };
+
+ pm8916_temp: temp-alarm@2400 {
+ compatible = "qcom,spmi-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>;
+ io-channels = <&pm8916_vadc VADC_DIE_TEMP>;
+ io-channel-names = "thermal";
+ #thermal-sensor-cells = <0>;
+ };
+
+ pm8916_vadc: vadc@3100 {
+ compatible = "qcom,spmi-vadc";
+ reg = <0x3100 0x100>;
+ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+
+ usb_in {
+ reg = <VADC_USBIN>;
+ qcom,pre-scaling = <1 10>;
+ };
+ vph_pwr {
+ reg = <VADC_VSYS>;
+ qcom,pre-scaling = <1 3>;
+ };
+ die_temp {
+ reg = <VADC_DIE_TEMP>;
+ };
+ ref_625mv {
+ reg = <VADC_REF_625MV>;
+ };
+ ref_1250v {
+ reg = <VADC_REF_1250MV>;
+ };
+ ref_gnd {
+ reg = <VADC_GND_REF>;
+ };
+ ref_vdd {
+ reg = <VADC_VDD_VADC>;
+ };
+ };
+ };
+
+ usid1: pm8916@1 {
+ compatible = "qcom,spmi-pmic";
+ reg = <0x1 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/skeleton.dtsi b/arch/arm64/boot/dts/skeleton.dtsi
deleted file mode 100644
index 38ead821bb42..000000000000
--- a/arch/arm64/boot/dts/skeleton.dtsi
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Skeleton device tree; the bare minimum needed to boot; just include and
- * add a compatible value. The bootloader will typically populate the memory
- * node.
- */
-
-/ {
- #address-cells = <2>;
- #size-cells = <1>;
- chosen { };
- aliases { };
- memory { device_type = "memory"; reg = <0 0 0>; };
-};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 2ed7449d9273..f38c94f1d898 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -33,6 +33,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_IOSCHED_DEADLINE is not set
CONFIG_ARCH_EXYNOS7=y
CONFIG_ARCH_FSL_LS2085A=y
+CONFIG_ARCH_HISI=y
CONFIG_ARCH_MEDIATEK=y
CONFIG_ARCH_SEATTLE=y
CONFIG_ARCH_TEGRA=y
@@ -94,6 +95,7 @@ CONFIG_SMC91X=y
CONFIG_SMSC911X=y
# CONFIG_WLAN is not set
CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
# CONFIG_SERIO_SERPORT is not set
CONFIG_SERIO_AMBAKMI=y
CONFIG_LEGACY_PTY_COUNT=16
@@ -138,6 +140,12 @@ CONFIG_MMC_ARMMMCI=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SPI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=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_EFI=y
CONFIG_RTC_DRV_XGENE=y
@@ -180,6 +188,7 @@ CONFIG_LOCKUP_DETECTOR=y
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_PREEMPT is not set
# CONFIG_FTRACE is not set
+CONFIG_MEMTEST=y
CONFIG_SECURITY=y
CONFIG_CRYPTO_ANSI_CPRNG=y
CONFIG_ARM64_CRYPTO=y
diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c
index 6c348df5bf36..3303e8a7b837 100644
--- a/arch/arm64/crypto/aes-ce-ccm-glue.c
+++ b/arch/arm64/crypto/aes-ce-ccm-glue.c
@@ -13,7 +13,7 @@
#include <crypto/aes.h>
#include <crypto/algapi.h>
#include <crypto/scatterwalk.h>
-#include <linux/crypto.h>
+#include <crypto/internal/aead.h>
#include <linux/module.h>
#include "aes-ce-setkey.h"
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index 55103e50c51b..b112a39834d0 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -35,7 +35,6 @@ generic-y += poll.h
generic-y += preempt.h
generic-y += resource.h
generic-y += rwsem.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += segment.h
generic-y += sembuf.h
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 59c05d8ea4a0..39248d3adf5d 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -16,6 +16,7 @@
#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/cputype.h>
+#include <asm/psci.h>
#include <asm/smp_plat.h>
/* Basic configuration for ACPI */
@@ -39,18 +40,6 @@ extern int acpi_disabled;
extern int acpi_noirq;
extern int acpi_pci_disabled;
-/* 1 to indicate PSCI 0.2+ is implemented */
-static inline bool acpi_psci_present(void)
-{
- return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT;
-}
-
-/* 1 to indicate HVC must be used instead of SMC as the PSCI conduit */
-static inline bool acpi_psci_use_hvc(void)
-{
- return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC;
-}
-
static inline void disable_acpi(void)
{
acpi_disabled = 1;
@@ -88,9 +77,11 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) { }
void __init acpi_init_cpus(void);
#else
-static inline bool acpi_psci_present(void) { return false; }
-static inline bool acpi_psci_use_hvc(void) { return false; }
static inline void acpi_init_cpus(void) { }
#endif /* CONFIG_ACPI */
+static inline const char *acpi_get_enable_method(int cpu)
+{
+ return acpi_psci_present() ? "psci" : NULL;
+}
#endif /*_ASM_ACPI_H*/
diff --git a/arch/arm64/include/asm/alternative-asm.h b/arch/arm64/include/asm/alternative-asm.h
deleted file mode 100644
index 919a67855b63..000000000000
--- a/arch/arm64/include/asm/alternative-asm.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __ASM_ALTERNATIVE_ASM_H
-#define __ASM_ALTERNATIVE_ASM_H
-
-#ifdef __ASSEMBLY__
-
-.macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len
- .word \orig_offset - .
- .word \alt_offset - .
- .hword \feature
- .byte \orig_len
- .byte \alt_len
-.endm
-
-.macro alternative_insn insn1 insn2 cap
-661: \insn1
-662: .pushsection .altinstructions, "a"
- altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f
- .popsection
- .pushsection .altinstr_replacement, "ax"
-663: \insn2
-664: .popsection
- .if ((664b-663b) != (662b-661b))
- .error "Alternatives instruction length mismatch"
- .endif
-.endm
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* __ASM_ALTERNATIVE_ASM_H */
diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h
index d261f01e2bae..c385a0c4057f 100644
--- a/arch/arm64/include/asm/alternative.h
+++ b/arch/arm64/include/asm/alternative.h
@@ -1,6 +1,8 @@
#ifndef __ASM_ALTERNATIVE_H
#define __ASM_ALTERNATIVE_H
+#ifndef __ASSEMBLY__
+
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/stringify.h>
@@ -24,7 +26,20 @@ void free_alternatives_memory(void);
" .byte 662b-661b\n" /* source len */ \
" .byte 664f-663f\n" /* replacement len */
-/* alternative assembly primitive: */
+/*
+ * alternative assembly primitive:
+ *
+ * If any of these .org directive fail, it means that insn1 and insn2
+ * don't have the same length. This used to be written as
+ *
+ * .if ((664b-663b) != (662b-661b))
+ * .error "Alternatives instruction length mismatch"
+ * .endif
+ *
+ * but most assemblers die if insn1 or insn2 have a .inst. This should
+ * be fixed in a binutils release posterior to 2.25.51.0.2 (anything
+ * containing commit 4e4d08cf7399b606 or c1baaddf8861).
+ */
#define ALTERNATIVE(oldinstr, newinstr, feature) \
"661:\n\t" \
oldinstr "\n" \
@@ -37,8 +52,31 @@ void free_alternatives_memory(void);
newinstr "\n" \
"664:\n\t" \
".popsection\n\t" \
- ".if ((664b-663b) != (662b-661b))\n\t" \
- " .error \"Alternatives instruction length mismatch\"\n\t"\
- ".endif\n"
+ ".org . - (664b-663b) + (662b-661b)\n\t" \
+ ".org . - (662b-661b) + (664b-663b)\n"
+
+#else
+
+.macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len
+ .word \orig_offset - .
+ .word \alt_offset - .
+ .hword \feature
+ .byte \orig_len
+ .byte \alt_len
+.endm
+
+.macro alternative_insn insn1 insn2 cap
+661: \insn1
+662: .pushsection .altinstructions, "a"
+ altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f
+ .popsection
+ .pushsection .altinstr_replacement, "ax"
+663: \insn2
+664: .popsection
+ .org . - (664b-663b) + (662b-661b)
+ .org . - (662b-661b) + (664b-663b)
+.endm
+
+#endif /* __ASSEMBLY__ */
#endif /* __ASM_ALTERNATIVE_H */
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 71f19c4dc0de..0fa47c4275cb 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -114,7 +114,7 @@ do { \
#define read_barrier_depends() do { } while(0)
#define smp_read_barrier_depends() do { } while(0)
-#define set_mb(var, value) do { var = value; smp_mb(); } 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()
diff --git a/arch/arm64/include/asm/boot.h b/arch/arm64/include/asm/boot.h
new file mode 100644
index 000000000000..81151b67b26b
--- /dev/null
+++ b/arch/arm64/include/asm/boot.h
@@ -0,0 +1,14 @@
+
+#ifndef __ASM_BOOT_H
+#define __ASM_BOOT_H
+
+#include <asm/sizes.h>
+
+/*
+ * arm64 requires the DTB to be 8 byte aligned and
+ * not exceed 2MB in size.
+ */
+#define MIN_FDT_ALIGN 8
+#define MAX_FDT_SIZE SZ_2M
+
+#endif
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index 67d309cc3b6b..c75b8d027eb1 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -40,10 +40,6 @@
* the implementation assumes non-aliasing VIPT D-cache and (aliasing)
* VIPT or ASID-tagged VIVT I-cache.
*
- * flush_cache_all()
- *
- * Unconditionally clean and invalidate the entire cache.
- *
* flush_cache_mm(mm)
*
* Clean and invalidate all user space cache entries
@@ -69,7 +65,6 @@
* - kaddr - page address
* - size - region size
*/
-extern void flush_cache_all(void);
extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
extern void flush_icache_range(unsigned long start, unsigned long end);
extern void __flush_dcache_area(void *addr, size_t len);
diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h
index 5a31d6716914..8f03446cf89f 100644
--- a/arch/arm64/include/asm/cpu_ops.h
+++ b/arch/arm64/include/asm/cpu_ops.h
@@ -19,15 +19,15 @@
#include <linux/init.h>
#include <linux/threads.h>
-struct device_node;
-
/**
* struct cpu_operations - Callback operations for hotplugging CPUs.
*
* @name: Name of the property as appears in a devicetree cpu node's
- * enable-method property.
- * @cpu_init: Reads any data necessary for a specific enable-method from the
- * devicetree, for a given cpu node and proposed logical id.
+ * enable-method property. On systems booting with ACPI, @name
+ * identifies the struct cpu_operations entry corresponding to
+ * the boot protocol specified in the ACPI MADT table.
+ * @cpu_init: Reads any data necessary for a specific enable-method for a
+ * proposed logical id.
* @cpu_prepare: Early one-time preparation step for a cpu. If there is a
* mechanism for doing so, tests whether it is possible to boot
* the given CPU.
@@ -40,15 +40,15 @@ struct device_node;
* @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the
* cpu being killed.
* @cpu_kill: Ensures a cpu has left the kernel. Called from another cpu.
- * @cpu_init_idle: Reads any data necessary to initialize CPU idle states from
- * devicetree, for a given cpu node and proposed logical id.
+ * @cpu_init_idle: Reads any data necessary to initialize CPU idle states for
+ * a proposed logical id.
* @cpu_suspend: Suspends a cpu and saves the required context. May fail owing
* to wrong parameters or error conditions. Called from the
* CPU being suspended. Must be called with IRQs disabled.
*/
struct cpu_operations {
const char *name;
- int (*cpu_init)(struct device_node *, unsigned int);
+ int (*cpu_init)(unsigned int);
int (*cpu_prepare)(unsigned int);
int (*cpu_boot)(unsigned int);
void (*cpu_postboot)(void);
@@ -58,14 +58,17 @@ struct cpu_operations {
int (*cpu_kill)(unsigned int cpu);
#endif
#ifdef CONFIG_CPU_IDLE
- int (*cpu_init_idle)(struct device_node *, unsigned int);
+ int (*cpu_init_idle)(unsigned int);
int (*cpu_suspend)(unsigned long);
#endif
};
extern const struct cpu_operations *cpu_ops[NR_CPUS];
-int __init cpu_read_ops(struct device_node *dn, int cpu);
-void __init cpu_read_bootcpu_ops(void);
-const struct cpu_operations *cpu_get_ops(const char *name);
+int __init cpu_read_ops(int cpu);
+
+static inline void __init cpu_read_bootcpu_ops(void)
+{
+ cpu_read_ops(0);
+}
#endif /* ifndef __ASM_CPU_OPS_H */
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 82cb9f98ba1a..c1044218a63a 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -24,8 +24,9 @@
#define ARM64_WORKAROUND_CLEAN_CACHE 0
#define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE 1
#define ARM64_WORKAROUND_845719 2
+#define ARM64_HAS_SYSREG_GIC_CPUIF 3
-#define ARM64_NCAPS 3
+#define ARM64_NCAPS 4
#ifndef __ASSEMBLY__
@@ -38,6 +39,11 @@ struct arm64_cpu_capabilities {
u32 midr_model;
u32 midr_range_min, midr_range_max;
};
+
+ struct { /* Feature register checking */
+ u64 register_mask;
+ u64 register_value;
+ };
};
};
diff --git a/arch/arm64/include/asm/cpuidle.h b/arch/arm64/include/asm/cpuidle.h
index 141b2fcabaa6..0f74f05d662a 100644
--- a/arch/arm64/include/asm/cpuidle.h
+++ b/arch/arm64/include/asm/cpuidle.h
@@ -5,20 +5,16 @@
#ifdef CONFIG_CPU_IDLE
extern int arm_cpuidle_init(unsigned int cpu);
-extern int cpu_suspend(unsigned long arg);
+extern int arm_cpuidle_suspend(int index);
#else
static inline int arm_cpuidle_init(unsigned int cpu)
{
return -EOPNOTSUPP;
}
-static inline int cpu_suspend(unsigned long arg)
+static inline int arm_cpuidle_suspend(int index)
{
return -EOPNOTSUPP;
}
#endif
-static inline int arm_cpuidle_suspend(int index)
-{
- return cpu_suspend(index);
-}
#endif
diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h
index 9437e3dc5833..f0d6d0bfe55c 100644
--- a/arch/arm64/include/asm/dma-mapping.h
+++ b/arch/arm64/include/asm/dma-mapping.h
@@ -18,6 +18,7 @@
#ifdef __KERNEL__
+#include <linux/acpi.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
@@ -28,13 +29,23 @@
#define DMA_ERROR_CODE (~(dma_addr_t)0)
extern struct dma_map_ops *dma_ops;
+extern struct dma_map_ops dummy_dma_ops;
static inline struct dma_map_ops *__generic_dma_ops(struct device *dev)
{
- if (unlikely(!dev) || !dev->archdata.dma_ops)
+ if (unlikely(!dev))
return dma_ops;
- else
+ else if (dev->archdata.dma_ops)
return dev->archdata.dma_ops;
+ else if (acpi_disabled)
+ return dma_ops;
+
+ /*
+ * When ACPI is enabled, if arch_set_dma_ops is not called,
+ * we will disable device DMA capability by setting it
+ * to dummy_dma_ops.
+ */
+ return &dummy_dma_ops;
}
static inline struct dma_map_ops *get_dma_ops(struct device *dev)
@@ -48,6 +59,9 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
struct iommu_ops *iommu, bool coherent)
{
+ if (!acpi_disabled && !dev->archdata.dma_ops)
+ dev->archdata.dma_ops = dma_ops;
+
dev->archdata.dma_coherent = coherent;
}
#define arch_setup_dma_ops arch_setup_dma_ops
diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
index 95e6b6dcbe37..c0739187a920 100644
--- a/arch/arm64/include/asm/fixmap.h
+++ b/arch/arm64/include/asm/fixmap.h
@@ -17,6 +17,7 @@
#ifndef __ASSEMBLY__
#include <linux/kernel.h>
+#include <asm/boot.h>
#include <asm/page.h>
/*
@@ -32,6 +33,20 @@
*/
enum fixed_addresses {
FIX_HOLE,
+
+ /*
+ * Reserve a virtual window for the FDT that is 2 MB larger than the
+ * maximum supported size, and put it at the top of the fixmap region.
+ * The additional space ensures that any FDT that does not exceed
+ * MAX_FDT_SIZE can be mapped regardless of whether it crosses any
+ * 2 MB alignment boundaries.
+ *
+ * Keep this at the top so it remains 2 MB aligned.
+ */
+#define FIX_FDT_SIZE (MAX_FDT_SIZE + SZ_2M)
+ FIX_FDT_END,
+ FIX_FDT = FIX_FDT_END + FIX_FDT_SIZE / PAGE_SIZE - 1,
+
FIX_EARLYCON_MEM_BASE,
FIX_TEXT_POKE0,
__end_of_permanent_fixed_addresses,
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
index 5f750dc96e0f..74069b3bd919 100644
--- a/arch/arm64/include/asm/futex.h
+++ b/arch/arm64/include/asm/futex.h
@@ -58,7 +58,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;
- pagefault_disable(); /* implies preempt_disable() */
+ pagefault_disable();
switch (op) {
case FUTEX_OP_SET:
@@ -85,7 +85,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
ret = -ENOSYS;
}
- pagefault_enable(); /* subsumes preempt_enable() */
+ pagefault_enable();
if (!ret) {
switch (cmp) {
diff --git a/arch/arm64/include/asm/hugetlb.h b/arch/arm64/include/asm/hugetlb.h
index 5b7ca8ace95f..2fd9b14ca295 100644
--- a/arch/arm64/include/asm/hugetlb.h
+++ b/arch/arm64/include/asm/hugetlb.h
@@ -86,10 +86,6 @@ static inline int prepare_hugepage_range(struct file *file,
return 0;
}
-static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
-{
-}
-
static inline int huge_pte_none(pte_t pte)
{
return pte_none(pte);
@@ -100,15 +96,6 @@ static inline pte_t huge_pte_wrprotect(pte_t pte)
return pte_wrprotect(pte);
}
-static inline int arch_prepare_hugepage(struct page *page)
-{
- return 0;
-}
-
-static inline void arch_release_hugepage(struct page *page)
-{
-}
-
static inline void arch_clear_hugepage_flags(struct page *page)
{
clear_bit(PG_dcache_clean, &page->flags);
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index f81b328d9cf4..30e50eb54a67 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -281,6 +281,7 @@ __AARCH64_INSN_FUNCS(ret, 0xFFFFFC1F, 0xD65F0000)
#undef __AARCH64_INSN_FUNCS
bool aarch64_insn_is_nop(u32 insn);
+bool aarch64_insn_is_branch_imm(u32 insn);
int aarch64_insn_read(void *addr, u32 *insnp);
int aarch64_insn_write(void *addr, u32 insn);
@@ -351,6 +352,8 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst,
int shift,
enum aarch64_insn_variant variant,
enum aarch64_insn_logic_type type);
+s32 aarch64_get_branch_offset(u32 insn);
+u32 aarch64_set_branch_offset(u32 insn, s32 offset);
bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 540f7c0aea82..44be1e03ed65 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -117,10 +117,10 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
* ordering rules but do not guarantee any ordering relative to Normal memory
* accesses.
*/
-#define readb_relaxed(c) ({ u8 __v = __raw_readb(c); __v; })
-#define readw_relaxed(c) ({ u16 __v = le16_to_cpu((__force __le16)__raw_readw(c)); __v; })
-#define readl_relaxed(c) ({ u32 __v = le32_to_cpu((__force __le32)__raw_readl(c)); __v; })
-#define readq_relaxed(c) ({ u64 __v = le64_to_cpu((__force __le64)__raw_readq(c)); __v; })
+#define readb_relaxed(c) ({ u8 __r = __raw_readb(c); __r; })
+#define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16)__raw_readw(c)); __r; })
+#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32)__raw_readl(c)); __r; })
+#define readq_relaxed(c) ({ u64 __r = le64_to_cpu((__force __le64)__raw_readq(c)); __r; })
#define writeb_relaxed(v,c) ((void)__raw_writeb((v),(c)))
#define writew_relaxed(v,c) ((void)__raw_writew((__force u16)cpu_to_le16(v),(c)))
@@ -170,6 +170,7 @@ extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size);
#define ioremap(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
#define ioremap_nocache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
#define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
+#define ioremap_wt(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
#define iounmap __iounmap
/*
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 4f7310fa77f0..3c5fe685a2d6 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -27,7 +27,7 @@
#define MPIDR_EL1 1 /* MultiProcessor Affinity Register */
#define CSSELR_EL1 2 /* Cache Size Selection Register */
#define SCTLR_EL1 3 /* System Control Register */
-#define ACTLR_EL1 4 /* Auxilliary Control Register */
+#define ACTLR_EL1 4 /* Auxiliary Control Register */
#define CPACR_EL1 5 /* Coprocessor Access Control */
#define TTBR0_EL1 6 /* Translation Table Base Register 0 */
#define TTBR1_EL1 7 /* Translation Table Base Register 1 */
@@ -132,11 +132,6 @@ extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
extern u64 __vgic_v3_get_ich_vtr_el2(void);
-extern char __save_vgic_v2_state[];
-extern char __restore_vgic_v2_state[];
-extern char __save_vgic_v3_state[];
-extern char __restore_vgic_v3_state[];
-
#endif
#endif /* __ARM_KVM_ASM_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index f0f58c9beec0..2709db2a7eac 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -221,29 +221,6 @@ struct vgic_sr_vectors {
void *restore_vgic;
};
-static inline void vgic_arch_setup(const struct vgic_params *vgic)
-{
- extern struct vgic_sr_vectors __vgic_sr_vectors;
-
- switch(vgic->type)
- {
- case VGIC_V2:
- __vgic_sr_vectors.save_vgic = __save_vgic_v2_state;
- __vgic_sr_vectors.restore_vgic = __restore_vgic_v2_state;
- break;
-
-#ifdef CONFIG_ARM_GIC_V3
- case VGIC_V3:
- __vgic_sr_vectors.save_vgic = __save_vgic_v3_state;
- __vgic_sr_vectors.restore_vgic = __restore_vgic_v3_state;
- break;
-#endif
-
- default:
- BUG();
- }
-}
-
static inline void kvm_arch_hardware_disable(void) {}
static inline void kvm_arch_hardware_unsetup(void) {}
static inline void kvm_arch_sync_events(struct kvm *kvm) {}
diff --git a/arch/arm64/include/asm/mm-arch-hooks.h b/arch/arm64/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..562b655f5ba9
--- /dev/null
+++ b/arch/arm64/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_ARM64_MM_ARCH_HOOKS_H
+#define _ASM_ARM64_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_ARM64_MM_ARCH_HOOKS_H */
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
index 3d311761e3c2..79fcfb048884 100644
--- a/arch/arm64/include/asm/mmu.h
+++ b/arch/arm64/include/asm/mmu.h
@@ -34,5 +34,6 @@ extern void init_mem_pgprot(void);
extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
unsigned long virt, phys_addr_t size,
pgprot_t prot);
+extern void *fixmap_remap_fdt(phys_addr_t dt_phys);
#endif
diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h
index d26d1d53c0d7..6471773db6fd 100644
--- a/arch/arm64/include/asm/perf_event.h
+++ b/arch/arm64/include/asm/perf_event.h
@@ -24,4 +24,11 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs);
#define perf_misc_flags(regs) perf_misc_flags(regs)
#endif
+#define perf_arch_fetch_caller_regs(regs, __ip) { \
+ (regs)->pc = (__ip); \
+ (regs)->regs[29] = (unsigned long) __builtin_frame_address(0); \
+ (regs)->sp = current_stack_pointer; \
+ (regs)->pstate = PSR_MODE_EL1h; \
+}
+
#endif
diff --git a/arch/arm64/include/asm/proc-fns.h b/arch/arm64/include/asm/proc-fns.h
index 220633b791b8..14ad6e4e87d1 100644
--- a/arch/arm64/include/asm/proc-fns.h
+++ b/arch/arm64/include/asm/proc-fns.h
@@ -28,12 +28,8 @@
struct mm_struct;
struct cpu_suspend_ctx;
-extern void cpu_cache_off(void);
extern void cpu_do_idle(void);
extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
-extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
-void cpu_soft_restart(phys_addr_t cpu_reset,
- unsigned long addr) __attribute__((noreturn));
extern void cpu_do_suspend(struct cpu_suspend_ctx *ptr);
extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index d2c37a1df0eb..e4c893e54f01 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -78,13 +78,30 @@ struct cpu_context {
struct thread_struct {
struct cpu_context cpu_context; /* cpu context */
- unsigned long tp_value;
+ unsigned long tp_value; /* TLS register */
+#ifdef CONFIG_COMPAT
+ unsigned long tp2_value;
+#endif
struct fpsimd_state fpsimd_state;
unsigned long fault_address; /* fault info */
unsigned long fault_code; /* ESR_EL1 value */
struct debug_info debug; /* debugging */
};
+#ifdef CONFIG_COMPAT
+#define task_user_tls(t) \
+({ \
+ unsigned long *__tls; \
+ if (is_compat_thread(task_thread_info(t))) \
+ __tls = &(t)->thread.tp2_value; \
+ else \
+ __tls = &(t)->thread.tp_value; \
+ __tls; \
+ })
+#else
+#define task_user_tls(t) (&(t)->thread.tp_value)
+#endif
+
#define INIT_THREAD { }
static inline void start_thread_common(struct pt_regs *regs, unsigned long pc)
diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h
index 2454bc59c916..49d7e1aaebdc 100644
--- a/arch/arm64/include/asm/psci.h
+++ b/arch/arm64/include/asm/psci.h
@@ -14,7 +14,15 @@
#ifndef __ASM_PSCI_H
#define __ASM_PSCI_H
-int psci_dt_init(void);
-int psci_acpi_init(void);
+int __init psci_dt_init(void);
+
+#ifdef CONFIG_ACPI
+int __init psci_acpi_init(void);
+bool __init acpi_psci_present(void);
+bool __init acpi_psci_use_hvc(void);
+#else
+static inline int psci_acpi_init(void) { return 0; }
+static inline bool acpi_psci_present(void) { return false; }
+#endif
#endif /* __ASM_PSCI_H */
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index bf22650b1a78..db02be81b90a 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -42,7 +42,7 @@ extern void handle_IPI(int ipinr, struct pt_regs *regs);
* Discover the set of possible CPUs and determine their
* SMP operations.
*/
-extern void of_smp_init_cpus(void);
+extern void smp_init_cpus(void);
/*
* Provide a function to raise an IPI cross call on CPUs in callmap.
diff --git a/arch/arm64/include/asm/smp_plat.h b/arch/arm64/include/asm/smp_plat.h
index 8dcd61e32176..7abf7570c00f 100644
--- a/arch/arm64/include/asm/smp_plat.h
+++ b/arch/arm64/include/asm/smp_plat.h
@@ -19,6 +19,8 @@
#ifndef __ASM_SMP_PLAT_H
#define __ASM_SMP_PLAT_H
+#include <linux/cpumask.h>
+
#include <asm/types.h>
struct mpidr_hash {
@@ -39,6 +41,20 @@ static inline u32 mpidr_hash_size(void)
*/
extern u64 __cpu_logical_map[NR_CPUS];
#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
+/*
+ * Retrieve logical cpu index corresponding to a given MPIDR.Aff*
+ * - mpidr: MPIDR.Aff* bits to be used for the look-up
+ *
+ * Returns the cpu logical index or -EINVAL on look-up error
+ */
+static inline int get_logical_index(u64 mpidr)
+{
+ int cpu;
+ for (cpu = 0; cpu < nr_cpu_ids; cpu++)
+ if (cpu_logical_map(cpu) == mpidr)
+ return cpu;
+ return -EINVAL;
+}
void __init do_post_cpus_up_work(void);
diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h
index 003802f58963..59a5b0f1e81c 100644
--- a/arch/arm64/include/asm/suspend.h
+++ b/arch/arm64/include/asm/suspend.h
@@ -21,6 +21,6 @@ struct sleep_save_sp {
phys_addr_t save_ptr_stash_phys;
};
-extern int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long));
+extern int cpu_suspend(unsigned long arg, int (*fn)(unsigned long));
extern void cpu_resume(void);
#endif
diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
index 7a18fabbe0f6..57f110bea6a8 100644
--- a/arch/arm64/include/asm/system_misc.h
+++ b/arch/arm64/include/asm/system_misc.h
@@ -23,6 +23,8 @@
#include <linux/compiler.h>
#include <linux/linkage.h>
#include <linux/irqflags.h>
+#include <linux/signal.h>
+#include <linux/ratelimit.h>
#include <linux/reboot.h>
struct pt_regs;
@@ -41,9 +43,19 @@ struct mm_struct;
extern void show_pte(struct mm_struct *mm, unsigned long addr);
extern void __show_regs(struct pt_regs *);
-void soft_restart(unsigned long);
extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
+#define show_unhandled_signals_ratelimited() \
+({ \
+ static DEFINE_RATELIMIT_STATE(_rs, \
+ DEFAULT_RATELIMIT_INTERVAL, \
+ DEFAULT_RATELIMIT_BURST); \
+ bool __show_ratelimited = false; \
+ if (show_unhandled_signals && __ratelimit(&_rs)) \
+ __show_ratelimited = true; \
+ __show_ratelimited; \
+})
+
#define UDBG_UNDEFINED (1 << 0)
#define UDBG_SYSCALL (1 << 1)
#define UDBG_BADABORT (1 << 2)
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index c3bb05b98616..934815d45eda 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -28,8 +28,6 @@
* TLB Management
* ==============
*
- * The arch/arm64/mm/tlb.S files implement these methods.
- *
* The TLB specific code is expected to perform whatever tests it needs
* to determine if it should invalidate the TLB for each call. Start
* addresses are inclusive and end addresses are exclusive; it is safe to
diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
index 7ebcd31ce51c..225ec3524fbf 100644
--- a/arch/arm64/include/asm/topology.h
+++ b/arch/arm64/include/asm/topology.h
@@ -18,7 +18,7 @@ extern struct cpu_topology cpu_topology[NR_CPUS];
#define topology_physical_package_id(cpu) (cpu_topology[cpu].cluster_id)
#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
-#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
+#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
void init_cpu_topology(void);
void store_cpu_topology(unsigned int cpuid);
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 8b839558838e..19de7537e7d3 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -36,12 +36,6 @@ EXPORT_SYMBOL(acpi_disabled);
int acpi_pci_disabled = 1; /* skip ACPI PCI scan and IRQ initialization */
EXPORT_SYMBOL(acpi_pci_disabled);
-/* Processors with enabled flag and sane MPIDR */
-static int enabled_cpus;
-
-/* Boot CPU is valid or not in MADT */
-static bool bootcpu_valid __initdata;
-
static bool param_acpi_off __initdata;
static bool param_acpi_force __initdata;
@@ -95,122 +89,15 @@ void __init __acpi_unmap_table(char *map, unsigned long size)
early_memunmap(map, size);
}
-/**
- * acpi_map_gic_cpu_interface - generates a logical cpu number
- * and map to MPIDR represented by GICC structure
- */
-static void __init
-acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
+bool __init acpi_psci_present(void)
{
- int i;
- u64 mpidr = processor->arm_mpidr & MPIDR_HWID_BITMASK;
- bool enabled = !!(processor->flags & ACPI_MADT_ENABLED);
-
- if (mpidr == INVALID_HWID) {
- pr_info("Skip MADT cpu entry with invalid MPIDR\n");
- return;
- }
-
- total_cpus++;
- if (!enabled)
- return;
-
- if (enabled_cpus >= NR_CPUS) {
- pr_warn("NR_CPUS limit of %d reached, Processor %d/0x%llx ignored.\n",
- NR_CPUS, total_cpus, mpidr);
- return;
- }
-
- /* Check if GICC structure of boot CPU is available in the MADT */
- if (cpu_logical_map(0) == mpidr) {
- if (bootcpu_valid) {
- pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n",
- mpidr);
- return;
- }
-
- bootcpu_valid = true;
- }
-
- /*
- * Duplicate MPIDRs are a recipe for disaster. Scan
- * all initialized entries and check for
- * duplicates. If any is found just ignore the CPU.
- */
- for (i = 1; i < enabled_cpus; i++) {
- if (cpu_logical_map(i) == mpidr) {
- pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n",
- mpidr);
- return;
- }
- }
-
- if (!acpi_psci_present())
- return;
-
- cpu_ops[enabled_cpus] = cpu_get_ops("psci");
- /* CPU 0 was already initialized */
- if (enabled_cpus) {
- if (!cpu_ops[enabled_cpus])
- return;
-
- if (cpu_ops[enabled_cpus]->cpu_init(NULL, enabled_cpus))
- return;
-
- /* map the logical cpu id to cpu MPIDR */
- cpu_logical_map(enabled_cpus) = mpidr;
- }
-
- enabled_cpus++;
+ return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT;
}
-static int __init
-acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
- const unsigned long end)
+/* Whether HVC must be used instead of SMC as the PSCI conduit */
+bool __init acpi_psci_use_hvc(void)
{
- struct acpi_madt_generic_interrupt *processor;
-
- processor = (struct acpi_madt_generic_interrupt *)header;
-
- if (BAD_MADT_ENTRY(processor, end))
- return -EINVAL;
-
- acpi_table_print_madt_entry(header);
- acpi_map_gic_cpu_interface(processor);
- return 0;
-}
-
-/* Parse GIC cpu interface entries in MADT for SMP init */
-void __init acpi_init_cpus(void)
-{
- int count, i;
-
- /*
- * do a partial walk of MADT to determine how many CPUs
- * we have including disabled CPUs, and get information
- * we need for SMP init
- */
- count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
- acpi_parse_gic_cpu_interface, 0);
-
- if (!count) {
- pr_err("No GIC CPU interface entries present\n");
- return;
- } else if (count < 0) {
- pr_err("Error parsing GIC CPU interface entry\n");
- return;
- }
-
- if (!bootcpu_valid) {
- pr_err("MADT missing boot CPU MPIDR, not enabling secondaries\n");
- return;
- }
-
- for (i = 0; i < enabled_cpus; i++)
- set_cpu_possible(i, true);
-
- /* Make boot-up look pretty */
- pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus);
+ return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC;
}
/*
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
index 28f8365edc4c..221b98312f0c 100644
--- a/arch/arm64/kernel/alternative.c
+++ b/arch/arm64/kernel/alternative.c
@@ -24,8 +24,13 @@
#include <asm/cacheflush.h>
#include <asm/alternative.h>
#include <asm/cpufeature.h>
+#include <asm/insn.h>
#include <linux/stop_machine.h>
+#define __ALT_PTR(a,f) (u32 *)((void *)&(a)->f + (a)->f)
+#define ALT_ORIG_PTR(a) __ALT_PTR(a, orig_offset)
+#define ALT_REPL_PTR(a) __ALT_PTR(a, alt_offset)
+
extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
struct alt_region {
@@ -33,13 +38,63 @@ struct alt_region {
struct alt_instr *end;
};
+/*
+ * Check if the target PC is within an alternative block.
+ */
+static bool branch_insn_requires_update(struct alt_instr *alt, unsigned long pc)
+{
+ unsigned long replptr;
+
+ if (kernel_text_address(pc))
+ return 1;
+
+ replptr = (unsigned long)ALT_REPL_PTR(alt);
+ if (pc >= replptr && pc <= (replptr + alt->alt_len))
+ return 0;
+
+ /*
+ * Branching into *another* alternate sequence is doomed, and
+ * we're not even trying to fix it up.
+ */
+ BUG();
+}
+
+static u32 get_alt_insn(struct alt_instr *alt, u32 *insnptr, u32 *altinsnptr)
+{
+ u32 insn;
+
+ insn = le32_to_cpu(*altinsnptr);
+
+ if (aarch64_insn_is_branch_imm(insn)) {
+ s32 offset = aarch64_get_branch_offset(insn);
+ unsigned long target;
+
+ target = (unsigned long)altinsnptr + offset;
+
+ /*
+ * If we're branching inside the alternate sequence,
+ * do not rewrite the instruction, as it is already
+ * correct. Otherwise, generate the new instruction.
+ */
+ if (branch_insn_requires_update(alt, target)) {
+ offset = target - (unsigned long)insnptr;
+ insn = aarch64_set_branch_offset(insn, offset);
+ }
+ }
+
+ return insn;
+}
+
static int __apply_alternatives(void *alt_region)
{
struct alt_instr *alt;
struct alt_region *region = alt_region;
- u8 *origptr, *replptr;
+ u32 *origptr, *replptr;
for (alt = region->begin; alt < region->end; alt++) {
+ u32 insn;
+ int i, nr_inst;
+
if (!cpus_have_cap(alt->cpufeature))
continue;
@@ -47,11 +102,17 @@ static int __apply_alternatives(void *alt_region)
pr_info_once("patching kernel code\n");
- origptr = (u8 *)&alt->orig_offset + alt->orig_offset;
- replptr = (u8 *)&alt->alt_offset + alt->alt_offset;
- memcpy(origptr, replptr, alt->alt_len);
+ origptr = ALT_ORIG_PTR(alt);
+ replptr = ALT_REPL_PTR(alt);
+ nr_inst = alt->alt_len / sizeof(insn);
+
+ for (i = 0; i < nr_inst; i++) {
+ insn = get_alt_insn(alt, origptr + i, replptr + i);
+ *(origptr + i) = cpu_to_le32(insn);
+ }
+
flush_icache_range((uintptr_t)origptr,
- (uintptr_t)(origptr + alt->alt_len));
+ (uintptr_t)(origptr + nr_inst));
}
return 0;
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index da675cc5dfae..c99701a34d7b 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -127,7 +127,6 @@ int main(void)
DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu));
DEFINE(VGIC_SAVE_FN, offsetof(struct vgic_sr_vectors, save_vgic));
DEFINE(VGIC_RESTORE_FN, offsetof(struct vgic_sr_vectors, restore_vgic));
- DEFINE(VGIC_SR_VECTOR_SZ, sizeof(struct vgic_sr_vectors));
DEFINE(VGIC_V2_CPU_HCR, offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
DEFINE(VGIC_V2_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
DEFINE(VGIC_V2_CPU_MISR, offsetof(struct vgic_cpu, vgic_v2.vgic_misr));
diff --git a/arch/arm64/kernel/cpu_ops.c b/arch/arm64/kernel/cpu_ops.c
index fb8ff9ba467a..5ea337dd2f15 100644
--- a/arch/arm64/kernel/cpu_ops.c
+++ b/arch/arm64/kernel/cpu_ops.c
@@ -16,11 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <asm/cpu_ops.h>
-#include <asm/smp_plat.h>
+#include <linux/acpi.h>
#include <linux/errno.h>
#include <linux/of.h>
#include <linux/string.h>
+#include <asm/acpi.h>
+#include <asm/cpu_ops.h>
+#include <asm/smp_plat.h>
extern const struct cpu_operations smp_spin_table_ops;
extern const struct cpu_operations cpu_psci_ops;
@@ -35,7 +37,7 @@ static const struct cpu_operations *supported_cpu_ops[] __initconst = {
NULL,
};
-const struct cpu_operations * __init cpu_get_ops(const char *name)
+static const struct cpu_operations * __init cpu_get_ops(const char *name)
{
const struct cpu_operations **ops = supported_cpu_ops;
@@ -49,39 +51,53 @@ const struct cpu_operations * __init cpu_get_ops(const char *name)
return NULL;
}
+static const char *__init cpu_read_enable_method(int cpu)
+{
+ const char *enable_method;
+
+ if (acpi_disabled) {
+ struct device_node *dn = of_get_cpu_node(cpu, NULL);
+
+ if (!dn) {
+ if (!cpu)
+ pr_err("Failed to find device node for boot cpu\n");
+ return NULL;
+ }
+
+ enable_method = of_get_property(dn, "enable-method", NULL);
+ if (!enable_method) {
+ /*
+ * The boot CPU may not have an enable method (e.g.
+ * when spin-table is used for secondaries).
+ * Don't warn spuriously.
+ */
+ if (cpu != 0)
+ pr_err("%s: missing enable-method property\n",
+ dn->full_name);
+ }
+ } else {
+ enable_method = acpi_get_enable_method(cpu);
+ if (!enable_method)
+ pr_err("Unsupported ACPI enable-method\n");
+ }
+
+ return enable_method;
+}
/*
- * Read a cpu's enable method from the device tree and record it in cpu_ops.
+ * Read a cpu's enable method and record it in cpu_ops.
*/
-int __init cpu_read_ops(struct device_node *dn, int cpu)
+int __init cpu_read_ops(int cpu)
{
- const char *enable_method = of_get_property(dn, "enable-method", NULL);
- if (!enable_method) {
- /*
- * The boot CPU may not have an enable method (e.g. when
- * spin-table is used for secondaries). Don't warn spuriously.
- */
- if (cpu != 0)
- pr_err("%s: missing enable-method property\n",
- dn->full_name);
- return -ENOENT;
- }
+ const char *enable_method = cpu_read_enable_method(cpu);
+
+ if (!enable_method)
+ return -ENODEV;
cpu_ops[cpu] = cpu_get_ops(enable_method);
if (!cpu_ops[cpu]) {
- pr_warn("%s: unsupported enable-method property: %s\n",
- dn->full_name, enable_method);
+ pr_warn("Unsupported enable-method: %s\n", enable_method);
return -EOPNOTSUPP;
}
return 0;
}
-
-void __init cpu_read_bootcpu_ops(void)
-{
- struct device_node *dn = of_get_cpu_node(0, NULL);
- if (!dn) {
- pr_err("Failed to find device node for boot cpu\n");
- return;
- }
- cpu_read_ops(dn, 0);
-}
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 3d9967e43d89..5ad86ceac010 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -22,7 +22,23 @@
#include <asm/cpu.h>
#include <asm/cpufeature.h>
+static bool
+has_id_aa64pfr0_feature(const struct arm64_cpu_capabilities *entry)
+{
+ u64 val;
+
+ val = read_cpuid(id_aa64pfr0_el1);
+ return (val & entry->register_mask) == entry->register_value;
+}
+
static const struct arm64_cpu_capabilities arm64_features[] = {
+ {
+ .desc = "GIC system register CPU interface",
+ .capability = ARM64_HAS_SYSREG_GIC_CPUIF,
+ .matches = has_id_aa64pfr0_feature,
+ .register_mask = (0xf << 24),
+ .register_value = (1 << 24),
+ },
{},
};
diff --git a/arch/arm64/kernel/cpuidle.c b/arch/arm64/kernel/cpuidle.c
index a78143a5c99f..7ce589ca54a4 100644
--- a/arch/arm64/kernel/cpuidle.c
+++ b/arch/arm64/kernel/cpuidle.c
@@ -18,15 +18,10 @@
int arm_cpuidle_init(unsigned int cpu)
{
int ret = -EOPNOTSUPP;
- struct device_node *cpu_node = of_cpu_device_node_get(cpu);
-
- if (!cpu_node)
- return -ENODEV;
if (cpu_ops[cpu] && cpu_ops[cpu]->cpu_init_idle)
- ret = cpu_ops[cpu]->cpu_init_idle(cpu_node, cpu);
+ ret = cpu_ops[cpu]->cpu_init_idle(cpu);
- of_node_put(cpu_node);
return ret;
}
@@ -37,7 +32,7 @@ int arm_cpuidle_init(unsigned int cpu)
* Return: 0 on success, -EOPNOTSUPP if CPU suspend hook not initialized, CPU
* operations back-end error code otherwise.
*/
-int cpu_suspend(unsigned long arg)
+int arm_cpuidle_suspend(int index)
{
int cpu = smp_processor_id();
@@ -47,5 +42,5 @@ int cpu_suspend(unsigned long arg)
*/
if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_suspend)
return -EOPNOTSUPP;
- return cpu_ops[cpu]->cpu_suspend(arg);
+ return cpu_ops[cpu]->cpu_suspend(index);
}
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 959fe8733560..a7691a378668 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -21,7 +21,7 @@
#include <linux/init.h>
#include <linux/linkage.h>
-#include <asm/alternative-asm.h>
+#include <asm/alternative.h>
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/cpufeature.h>
@@ -124,21 +124,24 @@
msr sp_el0, x23
#ifdef CONFIG_ARM64_ERRATUM_845719
- alternative_insn \
- "nop", \
- "tbz x22, #4, 1f", \
- ARM64_WORKAROUND_845719
+
+#undef SEQUENCE_ORG
+#undef SEQUENCE_ALT
+
#ifdef CONFIG_PID_IN_CONTEXTIDR
- alternative_insn \
- "nop; nop", \
- "mrs x29, contextidr_el1; msr contextidr_el1, x29; 1:", \
- ARM64_WORKAROUND_845719
+
+#define SEQUENCE_ORG "nop ; nop ; nop"
+#define SEQUENCE_ALT "tbz x22, #4, 1f ; mrs x29, contextidr_el1; msr contextidr_el1, x29; 1:"
+
#else
- alternative_insn \
- "nop", \
- "msr contextidr_el1, xzr; 1:", \
- ARM64_WORKAROUND_845719
+
+#define SEQUENCE_ORG "nop ; nop"
+#define SEQUENCE_ALT "tbz x22, #4, 1f ; msr contextidr_el1, xzr; 1:"
+
#endif
+
+ alternative_insn SEQUENCE_ORG, SEQUENCE_ALT, ARM64_WORKAROUND_845719
+
#endif
.endif
msr elr_el1, x21 // set up the return data
@@ -517,6 +520,7 @@ el0_sp_pc:
mrs x26, far_el1
// enable interrupts before calling the main handler
enable_dbg_and_irq
+ ct_user_exit
mov x0, x26
mov x1, x25
mov x2, sp
@@ -608,11 +612,16 @@ ENDPROC(cpu_switch_to)
*/
ret_fast_syscall:
disable_irq // disable interrupts
- ldr x1, [tsk, #TI_FLAGS]
+ ldr x1, [tsk, #TI_FLAGS] // re-check for syscall tracing
+ and x2, x1, #_TIF_SYSCALL_WORK
+ cbnz x2, ret_fast_syscall_trace
and x2, x1, #_TIF_WORK_MASK
cbnz x2, fast_work_pending
enable_step_tsk x1, x2
kernel_exit 0, ret = 1
+ret_fast_syscall_trace:
+ enable_irq // enable interrupts
+ b __sys_trace_return
/*
* Ok, we need to do extra processing, enter the slow path.
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 3dca15634e69..44d6f7545505 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/cpu.h>
#include <linux/cpu_pm.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -296,6 +297,35 @@ static void fpsimd_pm_init(void)
static inline void fpsimd_pm_init(void) { }
#endif /* CONFIG_CPU_PM */
+#ifdef CONFIG_HOTPLUG_CPU
+static int fpsimd_cpu_hotplug_notifier(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
+{
+ unsigned int cpu = (long)hcpu;
+
+ switch (action) {
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ per_cpu(fpsimd_last_state, cpu) = NULL;
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block fpsimd_cpu_hotplug_notifier_block = {
+ .notifier_call = fpsimd_cpu_hotplug_notifier,
+};
+
+static inline void fpsimd_hotplug_init(void)
+{
+ register_cpu_notifier(&fpsimd_cpu_hotplug_notifier_block);
+}
+
+#else
+static inline void fpsimd_hotplug_init(void) { }
+#endif
+
/*
* FP/SIMD support code initialisation.
*/
@@ -315,6 +345,7 @@ static int __init fpsimd_init(void)
elf_hwcap |= HWCAP_ASIMD;
fpsimd_pm_init();
+ fpsimd_hotplug_init();
return 0;
}
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 19f915e8f6e0..c0ff3ce4299e 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -237,8 +237,6 @@ ENTRY(stext)
bl el2_setup // Drop to EL1, w20=cpu_boot_mode
adrp x24, __PHYS_OFFSET
bl set_cpu_boot_mode_flag
-
- bl __vet_fdt
bl __create_page_tables // x25=TTBR0, x26=TTBR1
/*
* The following calls CPU setup code, see arch/arm64/mm/proc.S for
@@ -270,24 +268,6 @@ preserve_boot_args:
ENDPROC(preserve_boot_args)
/*
- * Determine validity of the x21 FDT pointer.
- * The dtb must be 8-byte aligned and live in the first 512M of memory.
- */
-__vet_fdt:
- tst x21, #0x7
- b.ne 1f
- cmp x21, x24
- b.lt 1f
- mov x0, #(1 << 29)
- add x0, x0, x24
- cmp x21, x0
- b.ge 1f
- ret
-1:
- mov x21, #0
- ret
-ENDPROC(__vet_fdt)
-/*
* Macro to create a table entry to the next page.
*
* tbl: page table address
@@ -348,8 +328,7 @@ ENDPROC(__vet_fdt)
* required to get the kernel running. The following sections are required:
* - identity mapping to enable the MMU (low address, TTBR0)
* - first few MB of the kernel linear mapping to jump to once the MMU has
- * been enabled, including the FDT blob (TTBR1)
- * - pgd entry for fixed mappings (TTBR1)
+ * been enabled
*/
__create_page_tables:
adrp x25, idmap_pg_dir
@@ -382,7 +361,7 @@ __create_page_tables:
* Create the identity mapping.
*/
mov x0, x25 // idmap_pg_dir
- adrp x3, KERNEL_START // __pa(KERNEL_START)
+ adrp x3, __idmap_text_start // __pa(__idmap_text_start)
#ifndef CONFIG_ARM64_VA_BITS_48
#define EXTRA_SHIFT (PGDIR_SHIFT + PAGE_SHIFT - 3)
@@ -405,11 +384,11 @@ __create_page_tables:
/*
* Calculate the maximum allowed value for TCR_EL1.T0SZ so that the
- * entire kernel image can be ID mapped. As T0SZ == (64 - #bits used),
+ * entire ID map region can be mapped. As T0SZ == (64 - #bits used),
* this number conveniently equals the number of leading zeroes in
- * the physical address of KERNEL_END.
+ * the physical address of __idmap_text_end.
*/
- adrp x5, KERNEL_END
+ adrp x5, __idmap_text_end
clz x5, x5
cmp x5, TCR_T0SZ(VA_BITS) // default T0SZ small enough?
b.ge 1f // .. then skip additional level
@@ -424,8 +403,8 @@ __create_page_tables:
#endif
create_pgd_entry x0, x3, x5, x6
- mov x5, x3 // __pa(KERNEL_START)
- adr_l x6, KERNEL_END // __pa(KERNEL_END)
+ mov x5, x3 // __pa(__idmap_text_start)
+ adr_l x6, __idmap_text_end // __pa(__idmap_text_end)
create_block_map x0, x7, x3, x5, x6
/*
@@ -439,22 +418,6 @@ __create_page_tables:
create_block_map x0, x7, x3, x5, x6
/*
- * Map the FDT blob (maximum 2MB; must be within 512MB of
- * PHYS_OFFSET).
- */
- mov x3, x21 // FDT phys address
- and x3, x3, #~((1 << 21) - 1) // 2MB aligned
- mov x6, #PAGE_OFFSET
- sub x5, x3, x24 // subtract PHYS_OFFSET
- tst x5, #~((1 << 29) - 1) // within 512MB?
- csel x21, xzr, x21, ne // zero the FDT pointer
- b.ne 1f
- add x5, x5, x6 // __va(FDT blob)
- add x6, x5, #1 << 21 // 2MB for the FDT blob
- sub x6, x6, #1 // inclusive range
- create_block_map x0, x7, x3, x5, x6
-1:
- /*
* Since the page tables have been populated with non-cacheable
* accesses (MMU disabled), invalidate the idmap and swapper page
* tables again to remove any speculatively loaded cache lines.
@@ -669,6 +632,7 @@ ENDPROC(__secondary_switched)
*
* other registers depend on the function called upon completion
*/
+ .section ".idmap.text", "ax"
__enable_mmu:
ldr x5, =vectors
msr vbar_el1, x5
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 924902083e47..dd9671cd0bb2 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -77,6 +77,14 @@ bool __kprobes aarch64_insn_is_nop(u32 insn)
}
}
+bool aarch64_insn_is_branch_imm(u32 insn)
+{
+ return (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn) ||
+ aarch64_insn_is_tbz(insn) || aarch64_insn_is_tbnz(insn) ||
+ aarch64_insn_is_cbz(insn) || aarch64_insn_is_cbnz(insn) ||
+ aarch64_insn_is_bcond(insn));
+}
+
static DEFINE_SPINLOCK(patch_lock);
static void __kprobes *patch_map(void *addr, int fixmap)
@@ -1057,6 +1065,58 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst,
return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_6, insn, shift);
}
+/*
+ * Decode the imm field of a branch, and return the byte offset as a
+ * signed value (so it can be used when computing a new branch
+ * target).
+ */
+s32 aarch64_get_branch_offset(u32 insn)
+{
+ s32 imm;
+
+ if (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn)) {
+ imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_26, insn);
+ return (imm << 6) >> 4;
+ }
+
+ if (aarch64_insn_is_cbz(insn) || aarch64_insn_is_cbnz(insn) ||
+ aarch64_insn_is_bcond(insn)) {
+ imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_19, insn);
+ return (imm << 13) >> 11;
+ }
+
+ if (aarch64_insn_is_tbz(insn) || aarch64_insn_is_tbnz(insn)) {
+ imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_14, insn);
+ return (imm << 18) >> 16;
+ }
+
+ /* Unhandled instruction */
+ BUG();
+}
+
+/*
+ * Encode the displacement of a branch in the imm field and return the
+ * updated instruction.
+ */
+u32 aarch64_set_branch_offset(u32 insn, s32 offset)
+{
+ if (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn))
+ return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_26, insn,
+ offset >> 2);
+
+ if (aarch64_insn_is_cbz(insn) || aarch64_insn_is_cbnz(insn) ||
+ aarch64_insn_is_bcond(insn))
+ return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn,
+ offset >> 2);
+
+ if (aarch64_insn_is_tbz(insn) || aarch64_insn_is_tbnz(insn))
+ return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_14, insn,
+ offset >> 2);
+
+ /* Unhandled instruction */
+ BUG();
+}
+
bool aarch32_insn_is_wide(u32 insn)
{
return insn >= 0xe800;
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index cce18c85d2e8..702591f6180a 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -488,7 +488,7 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu)
}
err = request_irq(irq, armpmu->handle_irq,
- IRQF_NOBALANCING,
+ IRQF_NOBALANCING | IRQF_NO_THREAD,
"arm-pmu", armpmu);
if (err) {
pr_err("unable to request IRQ%d for ARM PMU counters\n",
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index c6b1f3b96f45..223b093c9440 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -58,14 +58,6 @@ unsigned long __stack_chk_guard __read_mostly;
EXPORT_SYMBOL(__stack_chk_guard);
#endif
-void soft_restart(unsigned long addr)
-{
- setup_mm_for_reboot();
- cpu_soft_restart(virt_to_phys(cpu_reset), addr);
- /* Should never get here */
- BUG();
-}
-
/*
* Function pointers to optional machine specific functions
*/
@@ -136,9 +128,7 @@ void machine_power_off(void)
/*
* Restart requires that the secondary CPUs stop performing any activity
- * while the primary CPU resets the system. Systems with a single CPU can
- * use soft_restart() as their machine descriptor's .restart hook, since that
- * will cause the only available CPU to reset. Systems with multiple CPUs must
+ * while the primary CPU resets the system. Systems with multiple CPUs must
* provide a HW restart implementation, to ensure that all CPUs reset at once.
* This is required so that any code running after reset on the primary CPU
* doesn't have to co-ordinate with other CPUs to ensure they aren't still
@@ -243,7 +233,8 @@ void release_thread(struct task_struct *dead_task)
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
- fpsimd_preserve_current_state();
+ if (current->mm)
+ fpsimd_preserve_current_state();
*dst = *src;
return 0;
}
@@ -254,35 +245,35 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
unsigned long stk_sz, struct task_struct *p)
{
struct pt_regs *childregs = task_pt_regs(p);
- unsigned long tls = p->thread.tp_value;
memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
if (likely(!(p->flags & PF_KTHREAD))) {
*childregs = *current_pt_regs();
childregs->regs[0] = 0;
- if (is_compat_thread(task_thread_info(p))) {
- if (stack_start)
+
+ /*
+ * Read the current TLS pointer from tpidr_el0 as it may be
+ * out-of-sync with the saved value.
+ */
+ asm("mrs %0, tpidr_el0" : "=r" (*task_user_tls(p)));
+
+ if (stack_start) {
+ if (is_compat_thread(task_thread_info(p)))
childregs->compat_sp = stack_start;
- } else {
- /*
- * Read the current TLS pointer from tpidr_el0 as it may be
- * out-of-sync with the saved value.
- */
- asm("mrs %0, tpidr_el0" : "=r" (tls));
- if (stack_start) {
- /* 16-byte aligned stack mandatory on AArch64 */
- if (stack_start & 15)
- return -EINVAL;
+ /* 16-byte aligned stack mandatory on AArch64 */
+ else if (stack_start & 15)
+ return -EINVAL;
+ else
childregs->sp = stack_start;
- }
}
+
/*
* If a TLS pointer was passed to clone (4th argument), use it
* for the new thread.
*/
if (clone_flags & CLONE_SETTLS)
- tls = childregs->regs[3];
+ p->thread.tp_value = childregs->regs[3];
} else {
memset(childregs, 0, sizeof(struct pt_regs));
childregs->pstate = PSR_MODE_EL1h;
@@ -291,7 +282,6 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
}
p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
p->thread.cpu_context.sp = (unsigned long)childregs;
- p->thread.tp_value = tls;
ptrace_hw_copy_thread(p);
@@ -302,18 +292,12 @@ static void tls_thread_switch(struct task_struct *next)
{
unsigned long tpidr, tpidrro;
- if (!is_compat_task()) {
- asm("mrs %0, tpidr_el0" : "=r" (tpidr));
- current->thread.tp_value = tpidr;
- }
+ asm("mrs %0, tpidr_el0" : "=r" (tpidr));
+ *task_user_tls(current) = tpidr;
- if (is_compat_thread(task_thread_info(next))) {
- tpidr = 0;
- tpidrro = next->thread.tp_value;
- } else {
- tpidr = next->thread.tp_value;
- tpidrro = 0;
- }
+ tpidr = *task_user_tls(next);
+ tpidrro = is_compat_thread(task_thread_info(next)) ?
+ next->thread.tp_value : 0;
asm(
" msr tpidr_el0, %0\n"
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index ea18cb53921e..869f202748e8 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -15,7 +15,6 @@
#define pr_fmt(fmt) "psci: " fmt
-#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/smp.h>
@@ -25,8 +24,8 @@
#include <linux/slab.h>
#include <uapi/linux/psci.h>
-#include <asm/acpi.h>
#include <asm/compiler.h>
+#include <asm/cputype.h>
#include <asm/cpu_ops.h>
#include <asm/errno.h>
#include <asm/psci.h>
@@ -37,16 +36,31 @@
#define PSCI_POWER_STATE_TYPE_STANDBY 0
#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1
-struct psci_power_state {
- u16 id;
- u8 type;
- u8 affinity_level;
-};
+static bool psci_power_state_loses_context(u32 state)
+{
+ return state & PSCI_0_2_POWER_STATE_TYPE_MASK;
+}
+
+static bool psci_power_state_is_valid(u32 state)
+{
+ const u32 valid_mask = PSCI_0_2_POWER_STATE_ID_MASK |
+ PSCI_0_2_POWER_STATE_TYPE_MASK |
+ PSCI_0_2_POWER_STATE_AFFL_MASK;
+
+ return !(state & ~valid_mask);
+}
+
+/*
+ * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF
+ * calls to its resident CPU, so we must avoid issuing those. We never migrate
+ * a Trusted OS even if it claims to be capable of migration -- doing so will
+ * require cooperation with a Trusted OS driver.
+ */
+static int resident_cpu = -1;
struct psci_operations {
- int (*cpu_suspend)(struct psci_power_state state,
- unsigned long entry_point);
- int (*cpu_off)(struct psci_power_state state);
+ int (*cpu_suspend)(u32 state, unsigned long entry_point);
+ int (*cpu_off)(u32 state);
int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
int (*migrate)(unsigned long cpuid);
int (*affinity_info)(unsigned long target_affinity,
@@ -56,23 +70,21 @@ struct psci_operations {
static struct psci_operations psci_ops;
-static int (*invoke_psci_fn)(u64, u64, u64, u64);
-typedef int (*psci_initcall_t)(const struct device_node *);
-
-asmlinkage int __invoke_psci_fn_hvc(u64, u64, u64, u64);
-asmlinkage int __invoke_psci_fn_smc(u64, u64, u64, u64);
+typedef unsigned long (psci_fn)(unsigned long, unsigned long,
+ unsigned long, unsigned long);
+asmlinkage psci_fn __invoke_psci_fn_hvc;
+asmlinkage psci_fn __invoke_psci_fn_smc;
+static psci_fn *invoke_psci_fn;
enum psci_function {
PSCI_FN_CPU_SUSPEND,
PSCI_FN_CPU_ON,
PSCI_FN_CPU_OFF,
PSCI_FN_MIGRATE,
- PSCI_FN_AFFINITY_INFO,
- PSCI_FN_MIGRATE_INFO_TYPE,
PSCI_FN_MAX,
};
-static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state);
+static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
static u32 psci_function_id[PSCI_FN_MAX];
@@ -92,56 +104,28 @@ static int psci_to_linux_errno(int errno)
return -EINVAL;
}
-static u32 psci_power_state_pack(struct psci_power_state state)
-{
- return ((state.id << PSCI_0_2_POWER_STATE_ID_SHIFT)
- & PSCI_0_2_POWER_STATE_ID_MASK) |
- ((state.type << PSCI_0_2_POWER_STATE_TYPE_SHIFT)
- & PSCI_0_2_POWER_STATE_TYPE_MASK) |
- ((state.affinity_level << PSCI_0_2_POWER_STATE_AFFL_SHIFT)
- & PSCI_0_2_POWER_STATE_AFFL_MASK);
-}
-
-static void psci_power_state_unpack(u32 power_state,
- struct psci_power_state *state)
-{
- state->id = (power_state & PSCI_0_2_POWER_STATE_ID_MASK) >>
- PSCI_0_2_POWER_STATE_ID_SHIFT;
- state->type = (power_state & PSCI_0_2_POWER_STATE_TYPE_MASK) >>
- PSCI_0_2_POWER_STATE_TYPE_SHIFT;
- state->affinity_level =
- (power_state & PSCI_0_2_POWER_STATE_AFFL_MASK) >>
- PSCI_0_2_POWER_STATE_AFFL_SHIFT;
-}
-
-static int psci_get_version(void)
+static u32 psci_get_version(void)
{
- int err;
-
- err = invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
- return err;
+ return invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
}
-static int psci_cpu_suspend(struct psci_power_state state,
- unsigned long entry_point)
+static int psci_cpu_suspend(u32 state, unsigned long entry_point)
{
int err;
- u32 fn, power_state;
+ u32 fn;
fn = psci_function_id[PSCI_FN_CPU_SUSPEND];
- power_state = psci_power_state_pack(state);
- err = invoke_psci_fn(fn, power_state, entry_point, 0);
+ err = invoke_psci_fn(fn, state, entry_point, 0);
return psci_to_linux_errno(err);
}
-static int psci_cpu_off(struct psci_power_state state)
+static int psci_cpu_off(u32 state)
{
int err;
- u32 fn, power_state;
+ u32 fn;
fn = psci_function_id[PSCI_FN_CPU_OFF];
- power_state = psci_power_state_pack(state);
- err = invoke_psci_fn(fn, power_state, 0, 0);
+ err = invoke_psci_fn(fn, state, 0, 0);
return psci_to_linux_errno(err);
}
@@ -168,30 +152,29 @@ static int psci_migrate(unsigned long cpuid)
static int psci_affinity_info(unsigned long target_affinity,
unsigned long lowest_affinity_level)
{
- int err;
- u32 fn;
-
- fn = psci_function_id[PSCI_FN_AFFINITY_INFO];
- err = invoke_psci_fn(fn, target_affinity, lowest_affinity_level, 0);
- return err;
+ return invoke_psci_fn(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity,
+ lowest_affinity_level, 0);
}
static int psci_migrate_info_type(void)
{
- int err;
- u32 fn;
+ return invoke_psci_fn(PSCI_0_2_FN_MIGRATE_INFO_TYPE, 0, 0, 0);
+}
- fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE];
- err = invoke_psci_fn(fn, 0, 0, 0);
- return err;
+static unsigned long psci_migrate_info_up_cpu(void)
+{
+ return invoke_psci_fn(PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU, 0, 0, 0);
}
-static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node,
- unsigned int cpu)
+static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu)
{
int i, ret, count = 0;
- struct psci_power_state *psci_states;
- struct device_node *state_node;
+ u32 *psci_states;
+ struct device_node *state_node, *cpu_node;
+
+ cpu_node = of_get_cpu_node(cpu, NULL);
+ if (!cpu_node)
+ return -ENODEV;
/*
* If the PSCI cpu_suspend function hook has not been initialized
@@ -215,13 +198,13 @@ static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node,
return -ENOMEM;
for (i = 0; i < count; i++) {
- u32 psci_power_state;
+ u32 state;
state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
ret = of_property_read_u32(state_node,
"arm,psci-suspend-param",
- &psci_power_state);
+ &state);
if (ret) {
pr_warn(" * %s missing arm,psci-suspend-param property\n",
state_node->full_name);
@@ -230,9 +213,13 @@ static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node,
}
of_node_put(state_node);
- pr_debug("psci-power-state %#x index %d\n", psci_power_state,
- i);
- psci_power_state_unpack(psci_power_state, &psci_states[i]);
+ pr_debug("psci-power-state %#x index %d\n", state, i);
+ if (!psci_power_state_is_valid(state)) {
+ pr_warn("Invalid PSCI power state %#x\n", state);
+ ret = -EINVAL;
+ goto free_mem;
+ }
+ psci_states[i] = state;
}
/* Idle states parsed correctly, initialize per-cpu pointer */
per_cpu(psci_power_state, cpu) = psci_states;
@@ -275,6 +262,46 @@ static void psci_sys_poweroff(void)
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
}
+/*
+ * Detect the presence of a resident Trusted OS which may cause CPU_OFF to
+ * return DENIED (which would be fatal).
+ */
+static void __init psci_init_migrate(void)
+{
+ unsigned long cpuid;
+ int type, cpu;
+
+ type = psci_ops.migrate_info_type();
+
+ if (type == PSCI_0_2_TOS_MP) {
+ pr_info("Trusted OS migration not required\n");
+ return;
+ }
+
+ if (type == PSCI_RET_NOT_SUPPORTED) {
+ pr_info("MIGRATE_INFO_TYPE not supported.\n");
+ return;
+ }
+
+ if (type != PSCI_0_2_TOS_UP_MIGRATE &&
+ type != PSCI_0_2_TOS_UP_NO_MIGRATE) {
+ pr_err("MIGRATE_INFO_TYPE returned unknown type (%d)\n", type);
+ return;
+ }
+
+ cpuid = psci_migrate_info_up_cpu();
+ if (cpuid & ~MPIDR_HWID_BITMASK) {
+ pr_warn("MIGRATE_INFO_UP_CPU reported invalid physical ID (0x%lx)\n",
+ cpuid);
+ return;
+ }
+
+ cpu = get_logical_index(cpuid);
+ resident_cpu = cpu >= 0 ? cpu : -1;
+
+ pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
+}
+
static void __init psci_0_2_set_functions(void)
{
pr_info("Using standard PSCI v0.2 function IDs\n");
@@ -290,11 +317,8 @@ static void __init psci_0_2_set_functions(void)
psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE;
psci_ops.migrate = psci_migrate;
- psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO;
psci_ops.affinity_info = psci_affinity_info;
- psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] =
- PSCI_0_2_FN_MIGRATE_INFO_TYPE;
psci_ops.migrate_info_type = psci_migrate_info_type;
arm_pm_restart = psci_sys_reset;
@@ -307,32 +331,26 @@ static void __init psci_0_2_set_functions(void)
*/
static int __init psci_probe(void)
{
- int ver = psci_get_version();
-
- if (ver == PSCI_RET_NOT_SUPPORTED) {
- /*
- * PSCI versions >=0.2 mandates implementation of
- * PSCI_VERSION.
- */
- pr_err("PSCI firmware does not comply with the v0.2 spec.\n");
- return -EOPNOTSUPP;
- } else {
- pr_info("PSCIv%d.%d detected in firmware.\n",
- PSCI_VERSION_MAJOR(ver),
- PSCI_VERSION_MINOR(ver));
-
- if (PSCI_VERSION_MAJOR(ver) == 0 &&
- PSCI_VERSION_MINOR(ver) < 2) {
- pr_err("Conflicting PSCI version detected.\n");
- return -EINVAL;
- }
+ u32 ver = psci_get_version();
+
+ pr_info("PSCIv%d.%d detected in firmware.\n",
+ PSCI_VERSION_MAJOR(ver),
+ PSCI_VERSION_MINOR(ver));
+
+ if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) {
+ pr_err("Conflicting PSCI version detected.\n");
+ return -EINVAL;
}
psci_0_2_set_functions();
+ psci_init_migrate();
+
return 0;
}
+typedef int (*psci_initcall_t)(const struct device_node *);
+
/*
* PSCI init function for PSCI versions >=0.2
*
@@ -421,6 +439,7 @@ int __init psci_dt_init(void)
return init_fn(np);
}
+#ifdef CONFIG_ACPI
/*
* We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's
* explicitly clarified in SBBR
@@ -441,10 +460,11 @@ int __init psci_acpi_init(void)
return psci_probe();
}
+#endif
#ifdef CONFIG_SMP
-static int __init cpu_psci_cpu_init(struct device_node *dn, unsigned int cpu)
+static int __init cpu_psci_cpu_init(unsigned int cpu)
{
return 0;
}
@@ -469,11 +489,21 @@ static int cpu_psci_cpu_boot(unsigned int cpu)
}
#ifdef CONFIG_HOTPLUG_CPU
+static bool psci_tos_resident_on(int cpu)
+{
+ return cpu == resident_cpu;
+}
+
static int cpu_psci_cpu_disable(unsigned int cpu)
{
/* Fail early if we don't have CPU_OFF support */
if (!psci_ops.cpu_off)
return -EOPNOTSUPP;
+
+ /* Trusted OS will deny CPU_OFF */
+ if (psci_tos_resident_on(cpu))
+ return -EPERM;
+
return 0;
}
@@ -484,9 +514,8 @@ static void cpu_psci_cpu_die(unsigned int cpu)
* There are no known implementations of PSCI actually using the
* power state field, pass a sensible default for now.
*/
- struct psci_power_state state = {
- .type = PSCI_POWER_STATE_TYPE_POWER_DOWN,
- };
+ u32 state = PSCI_POWER_STATE_TYPE_POWER_DOWN <<
+ PSCI_0_2_POWER_STATE_TYPE_SHIFT;
ret = psci_ops.cpu_off(state);
@@ -498,7 +527,7 @@ static int cpu_psci_cpu_kill(unsigned int cpu)
int err, i;
if (!psci_ops.affinity_info)
- return 1;
+ return 0;
/*
* cpu_kill could race with cpu_die and we can
* potentially end up declaring this cpu undead
@@ -509,7 +538,7 @@ static int cpu_psci_cpu_kill(unsigned int cpu)
err = psci_ops.affinity_info(cpu_logical_map(cpu), 0);
if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) {
pr_info("CPU%d killed.\n", cpu);
- return 1;
+ return 0;
}
msleep(10);
@@ -518,15 +547,14 @@ static int cpu_psci_cpu_kill(unsigned int cpu)
pr_warn("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n",
cpu, err);
- /* Make op_cpu_kill() fail. */
- return 0;
+ return -ETIMEDOUT;
}
#endif
#endif
static int psci_suspend_finisher(unsigned long index)
{
- struct psci_power_state *state = __this_cpu_read(psci_power_state);
+ u32 *state = __this_cpu_read(psci_power_state);
return psci_ops.cpu_suspend(state[index - 1],
virt_to_phys(cpu_resume));
@@ -535,7 +563,7 @@ static int psci_suspend_finisher(unsigned long index)
static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index)
{
int ret;
- struct psci_power_state *state = __this_cpu_read(psci_power_state);
+ u32 *state = __this_cpu_read(psci_power_state);
/*
* idle state index 0 corresponds to wfi, should never be called
* from the cpu_suspend operations
@@ -543,10 +571,10 @@ static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index)
if (WARN_ON_ONCE(!index))
return -EINVAL;
- if (state[index - 1].type == PSCI_POWER_STATE_TYPE_STANDBY)
+ if (!psci_power_state_loses_context(state[index - 1]))
ret = psci_ops.cpu_suspend(state[index - 1], 0);
else
- ret = __cpu_suspend(index, psci_suspend_finisher);
+ ret = cpu_suspend(index, psci_suspend_finisher);
return ret;
}
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 74753132c3ac..ffd3970721bf 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -105,18 +105,6 @@ static struct resource mem_res[] = {
#define kernel_code mem_res[0]
#define kernel_data mem_res[1]
-void __init early_print(const char *str, ...)
-{
- char buf[256];
- va_list ap;
-
- va_start(ap, str);
- vsnprintf(buf, sizeof(buf), str, ap);
- va_end(ap);
-
- printk("%s", buf);
-}
-
/*
* The recorded values of x0 .. x3 upon kernel entry.
*/
@@ -326,12 +314,14 @@ static void __init setup_processor(void)
static void __init setup_machine_fdt(phys_addr_t dt_phys)
{
- if (!dt_phys || !early_init_dt_scan(phys_to_virt(dt_phys))) {
- early_print("\n"
- "Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n"
- "The dtb must be 8-byte aligned and passed in the first 512MB of memory\n"
- "\nPlease check your bootloader.\n",
- dt_phys, phys_to_virt(dt_phys));
+ void *dt_virt = fixmap_remap_fdt(dt_phys);
+
+ if (!dt_virt || !early_init_dt_scan(dt_virt)) {
+ pr_crit("\n"
+ "Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n"
+ "The dtb must be 8-byte aligned and must not exceed 2 MB in size\n"
+ "\nPlease check your bootloader.",
+ &dt_phys, dt_virt);
while (true)
cpu_relax();
@@ -374,8 +364,6 @@ void __init setup_arch(char **cmdline_p)
{
setup_processor();
- setup_machine_fdt(__fdt_pointer);
-
init_mm.start_code = (unsigned long) _text;
init_mm.end_code = (unsigned long) _etext;
init_mm.end_data = (unsigned long) _edata;
@@ -386,6 +374,8 @@ void __init setup_arch(char **cmdline_p)
early_fixmap_init();
early_ioremap_init();
+ setup_machine_fdt(__fdt_pointer);
+
parse_early_param();
/*
@@ -408,16 +398,13 @@ void __init setup_arch(char **cmdline_p)
if (acpi_disabled) {
unflatten_device_tree();
psci_dt_init();
- cpu_read_bootcpu_ops();
-#ifdef CONFIG_SMP
- of_smp_init_cpus();
-#endif
} else {
psci_acpi_init();
- acpi_init_cpus();
}
+ cpu_read_bootcpu_ops();
#ifdef CONFIG_SMP
+ smp_init_cpus();
smp_build_mpidr_hash();
#endif
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index d26fcd4cd6e6..1670f15ef69e 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -370,7 +370,7 @@ badframe:
if (show_unhandled_signals)
pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n",
current->comm, task_pid_nr(current), __func__,
- regs->pc, regs->sp);
+ regs->pc, regs->compat_sp);
force_sig(SIGSEGV, current);
return 0;
}
@@ -407,7 +407,7 @@ badframe:
if (show_unhandled_signals)
pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n",
current->comm, task_pid_nr(current), __func__,
- regs->pc, regs->sp);
+ regs->pc, regs->compat_sp);
force_sig(SIGSEGV, current);
return 0;
}
diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S
index ede186cdd452..803cfea41962 100644
--- a/arch/arm64/kernel/sleep.S
+++ b/arch/arm64/kernel/sleep.S
@@ -130,12 +130,14 @@ ENDPROC(__cpu_suspend_enter)
/*
* x0 must contain the sctlr value retrieved from restored context
*/
+ .pushsection ".idmap.text", "ax"
ENTRY(cpu_resume_mmu)
ldr x3, =cpu_resume_after_mmu
msr sctlr_el1, x0 // restore sctlr_el1
isb
br x3 // global jump to virtual address
ENDPROC(cpu_resume_mmu)
+ .popsection
cpu_resume_after_mmu:
mov x0, #0 // return zero on success
ldp x19, x20, [sp, #16]
@@ -162,15 +164,12 @@ ENTRY(cpu_resume)
#else
mov x7, xzr
#endif
- adrp x0, sleep_save_sp
- add x0, x0, #:lo12:sleep_save_sp
- ldr x0, [x0, #SLEEP_SAVE_SP_PHYS]
+ ldr_l x0, sleep_save_sp + SLEEP_SAVE_SP_PHYS
ldr x0, [x0, x7, lsl #3]
/* load sp from context */
ldr x2, [x0, #CPU_CTX_SP]
- adrp x1, sleep_idmap_phys
/* load physical address of identity map page table in x1 */
- ldr x1, [x1, #:lo12:sleep_idmap_phys]
+ adrp x1, idmap_pg_dir
mov sp, x2
/*
* cpu_do_resume expects x0 to contain context physical address
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 2cb008177252..4b2121bd7f9c 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/spinlock.h>
@@ -248,20 +249,20 @@ static int op_cpu_kill(unsigned int cpu)
* time and hope that it's dead, so let's skip the wait and just hope.
*/
if (!cpu_ops[cpu]->cpu_kill)
- return 1;
+ return 0;
return cpu_ops[cpu]->cpu_kill(cpu);
}
-static DECLARE_COMPLETION(cpu_died);
-
/*
* called on the thread which is asking for a CPU to be shutdown -
* waits until shutdown has completed, or it is timed out.
*/
void __cpu_die(unsigned int cpu)
{
- if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) {
+ int err;
+
+ if (!cpu_wait_death(cpu, 5)) {
pr_crit("CPU%u: cpu didn't die\n", cpu);
return;
}
@@ -273,8 +274,10 @@ void __cpu_die(unsigned int cpu)
* verify that it has really left the kernel before we consider
* clobbering anything it might still be using.
*/
- if (!op_cpu_kill(cpu))
- pr_warn("CPU%d may not have shut down cleanly\n", cpu);
+ err = op_cpu_kill(cpu);
+ if (err)
+ pr_warn("CPU%d may not have shut down cleanly: %d\n",
+ cpu, err);
}
/*
@@ -294,7 +297,7 @@ void cpu_die(void)
local_irq_disable();
/* Tell __cpu_die() that this CPU is now safe to dispose of */
- complete(&cpu_died);
+ (void)cpu_report_death();
/*
* Actually shutdown the CPU. This must never fail. The specific hotplug
@@ -318,57 +321,158 @@ void __init smp_prepare_boot_cpu(void)
set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
}
+static u64 __init of_get_cpu_mpidr(struct device_node *dn)
+{
+ const __be32 *cell;
+ u64 hwid;
+
+ /*
+ * A cpu node with missing "reg" property is
+ * considered invalid to build a cpu_logical_map
+ * entry.
+ */
+ cell = of_get_property(dn, "reg", NULL);
+ if (!cell) {
+ pr_err("%s: missing reg property\n", dn->full_name);
+ return INVALID_HWID;
+ }
+
+ hwid = of_read_number(cell, of_n_addr_cells(dn));
+ /*
+ * Non affinity bits must be set to 0 in the DT
+ */
+ if (hwid & ~MPIDR_HWID_BITMASK) {
+ pr_err("%s: invalid reg property\n", dn->full_name);
+ return INVALID_HWID;
+ }
+ return hwid;
+}
+
+/*
+ * Duplicate MPIDRs are a recipe for disaster. Scan all initialized
+ * entries and check for duplicates. If any is found just ignore the
+ * cpu. cpu_logical_map was initialized to INVALID_HWID to avoid
+ * matching valid MPIDR values.
+ */
+static bool __init is_mpidr_duplicate(unsigned int cpu, u64 hwid)
+{
+ unsigned int i;
+
+ for (i = 1; (i < cpu) && (i < NR_CPUS); i++)
+ if (cpu_logical_map(i) == hwid)
+ return true;
+ return false;
+}
+
+/*
+ * Initialize cpu operations for a logical cpu and
+ * set it in the possible mask on success
+ */
+static int __init smp_cpu_setup(int cpu)
+{
+ if (cpu_read_ops(cpu))
+ return -ENODEV;
+
+ if (cpu_ops[cpu]->cpu_init(cpu))
+ return -ENODEV;
+
+ set_cpu_possible(cpu, true);
+
+ return 0;
+}
+
+static bool bootcpu_valid __initdata;
+static unsigned int cpu_count = 1;
+
+#ifdef CONFIG_ACPI
+/*
+ * acpi_map_gic_cpu_interface - parse processor MADT entry
+ *
+ * Carry out sanity checks on MADT processor entry and initialize
+ * cpu_logical_map on success
+ */
+static void __init
+acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
+{
+ u64 hwid = processor->arm_mpidr;
+
+ if (hwid & ~MPIDR_HWID_BITMASK || hwid == INVALID_HWID) {
+ pr_err("skipping CPU entry with invalid MPIDR 0x%llx\n", hwid);
+ return;
+ }
+
+ if (!(processor->flags & ACPI_MADT_ENABLED)) {
+ pr_err("skipping disabled CPU entry with 0x%llx MPIDR\n", hwid);
+ return;
+ }
+
+ if (is_mpidr_duplicate(cpu_count, hwid)) {
+ pr_err("duplicate CPU MPIDR 0x%llx in MADT\n", hwid);
+ return;
+ }
+
+ /* Check if GICC structure of boot CPU is available in the MADT */
+ if (cpu_logical_map(0) == hwid) {
+ if (bootcpu_valid) {
+ pr_err("duplicate boot CPU MPIDR: 0x%llx in MADT\n",
+ hwid);
+ return;
+ }
+ bootcpu_valid = true;
+ return;
+ }
+
+ if (cpu_count >= NR_CPUS)
+ return;
+
+ /* map the logical cpu id to cpu MPIDR */
+ cpu_logical_map(cpu_count) = hwid;
+
+ cpu_count++;
+}
+
+static int __init
+acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_interrupt *processor;
+
+ processor = (struct acpi_madt_generic_interrupt *)header;
+ if (BAD_MADT_ENTRY(processor, end))
+ return -EINVAL;
+
+ acpi_table_print_madt_entry(header);
+
+ acpi_map_gic_cpu_interface(processor);
+
+ return 0;
+}
+#else
+#define acpi_table_parse_madt(...) do { } while (0)
+#endif
+
/*
* Enumerate the possible CPU set from the device tree and build the
* cpu logical map array containing MPIDR values related to logical
* cpus. Assumes that cpu_logical_map(0) has already been initialized.
*/
-void __init of_smp_init_cpus(void)
+void __init of_parse_and_init_cpus(void)
{
struct device_node *dn = NULL;
- unsigned int i, cpu = 1;
- bool bootcpu_valid = false;
while ((dn = of_find_node_by_type(dn, "cpu"))) {
- const u32 *cell;
- u64 hwid;
+ u64 hwid = of_get_cpu_mpidr(dn);
- /*
- * A cpu node with missing "reg" property is
- * considered invalid to build a cpu_logical_map
- * entry.
- */
- cell = of_get_property(dn, "reg", NULL);
- if (!cell) {
- pr_err("%s: missing reg property\n", dn->full_name);
+ if (hwid == INVALID_HWID)
goto next;
- }
- hwid = of_read_number(cell, of_n_addr_cells(dn));
- /*
- * Non affinity bits must be set to 0 in the DT
- */
- if (hwid & ~MPIDR_HWID_BITMASK) {
- pr_err("%s: invalid reg property\n", dn->full_name);
+ if (is_mpidr_duplicate(cpu_count, hwid)) {
+ pr_err("%s: duplicate cpu reg properties in the DT\n",
+ dn->full_name);
goto next;
}
/*
- * Duplicate MPIDRs are a recipe for disaster. Scan
- * all initialized entries and check for
- * duplicates. If any is found just ignore the cpu.
- * cpu_logical_map was initialized to INVALID_HWID to
- * avoid matching valid MPIDR values.
- */
- for (i = 1; (i < cpu) && (i < NR_CPUS); i++) {
- if (cpu_logical_map(i) == hwid) {
- pr_err("%s: duplicate cpu reg properties in the DT\n",
- dn->full_name);
- goto next;
- }
- }
-
- /*
* The numbering scheme requires that the boot CPU
* must be assigned logical id 0. Record it so that
* the logical map built from DT is validated and can
@@ -392,38 +496,58 @@ void __init of_smp_init_cpus(void)
continue;
}
- if (cpu >= NR_CPUS)
- goto next;
-
- if (cpu_read_ops(dn, cpu) != 0)
- goto next;
-
- if (cpu_ops[cpu]->cpu_init(dn, cpu))
+ if (cpu_count >= NR_CPUS)
goto next;
pr_debug("cpu logical map 0x%llx\n", hwid);
- cpu_logical_map(cpu) = hwid;
+ cpu_logical_map(cpu_count) = hwid;
next:
- cpu++;
+ cpu_count++;
}
+}
+
+/*
+ * Enumerate the possible CPU set from the device tree or ACPI and build the
+ * cpu logical map array containing MPIDR values related to logical
+ * cpus. Assumes that cpu_logical_map(0) has already been initialized.
+ */
+void __init smp_init_cpus(void)
+{
+ int i;
- /* sanity check */
- if (cpu > NR_CPUS)
- pr_warning("no. of cores (%d) greater than configured maximum of %d - clipping\n",
- cpu, NR_CPUS);
+ if (acpi_disabled)
+ of_parse_and_init_cpus();
+ else
+ /*
+ * do a walk of MADT to determine how many CPUs
+ * we have including disabled CPUs, and get information
+ * we need for SMP init
+ */
+ acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
+ acpi_parse_gic_cpu_interface, 0);
+
+ if (cpu_count > NR_CPUS)
+ pr_warn("no. of cores (%d) greater than configured maximum of %d - clipping\n",
+ cpu_count, NR_CPUS);
if (!bootcpu_valid) {
- pr_err("DT missing boot CPU MPIDR, not enabling secondaries\n");
+ pr_err("missing boot CPU MPIDR, not enabling secondaries\n");
return;
}
/*
- * All the cpus that made it to the cpu_logical_map have been
- * validated so set them as possible cpus.
+ * We need to set the cpu_logical_map entries before enabling
+ * the cpus so that cpu processor description entries (DT cpu nodes
+ * and ACPI MADT entries) can be retrieved by matching the cpu hwid
+ * with entries in cpu_logical_map while initializing the cpus.
+ * If the cpu set-up fails, invalidate the cpu_logical_map entry.
*/
- for (i = 0; i < NR_CPUS; i++)
- if (cpu_logical_map(i) != INVALID_HWID)
- set_cpu_possible(i, true);
+ for (i = 1; i < NR_CPUS; i++) {
+ if (cpu_logical_map(i) != INVALID_HWID) {
+ if (smp_cpu_setup(i))
+ cpu_logical_map(i) = INVALID_HWID;
+ }
+ }
}
void __init smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c
index 14944e5b28da..aef3605a8c47 100644
--- a/arch/arm64/kernel/smp_spin_table.c
+++ b/arch/arm64/kernel/smp_spin_table.c
@@ -49,8 +49,14 @@ static void write_pen_release(u64 val)
}
-static int smp_spin_table_cpu_init(struct device_node *dn, unsigned int cpu)
+static int smp_spin_table_cpu_init(unsigned int cpu)
{
+ struct device_node *dn;
+
+ dn = of_get_cpu_node(cpu, NULL);
+ if (!dn)
+ return -ENODEV;
+
/*
* Determine the address from which the CPU is polling.
*/
diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c
index d7daf45ae7a2..8297d502217e 100644
--- a/arch/arm64/kernel/suspend.c
+++ b/arch/arm64/kernel/suspend.c
@@ -51,13 +51,13 @@ void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
}
/*
- * __cpu_suspend
+ * cpu_suspend
*
* arg: argument to pass to the finisher function
* fn: finisher function pointer
*
*/
-int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
+int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
{
struct mm_struct *mm = current->active_mm;
int ret;
@@ -82,7 +82,7 @@ int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
* We are resuming from reset with TTBR0_EL1 set to the
* idmap to enable the MMU; restore the active_mm mappings in
* TTBR0_EL1 unless the active_mm == &init_mm, in which case
- * the thread entered __cpu_suspend with TTBR0_EL1 set to
+ * the thread entered cpu_suspend with TTBR0_EL1 set to
* reserved TTBR0 page tables and should be restored as such.
*/
if (mm == &init_mm)
@@ -118,7 +118,6 @@ int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
}
struct sleep_save_sp sleep_save_sp;
-phys_addr_t sleep_idmap_phys;
static int __init cpu_suspend_init(void)
{
@@ -132,9 +131,7 @@ static int __init cpu_suspend_init(void)
sleep_save_sp.save_ptr_stash = ctx_ptr;
sleep_save_sp.save_ptr_stash_phys = virt_to_phys(ctx_ptr);
- sleep_idmap_phys = virt_to_phys(idmap_pg_dir);
__flush_dcache_area(&sleep_save_sp, sizeof(struct sleep_save_sp));
- __flush_dcache_area(&sleep_idmap_phys, sizeof(sleep_idmap_phys));
return 0;
}
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 1ef2940df13c..a12251c074a8 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -335,8 +335,7 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
if (call_undef_hook(regs) == 0)
return;
- if (show_unhandled_signals && unhandled_signal(current, SIGILL) &&
- printk_ratelimit()) {
+ if (show_unhandled_signals_ratelimited() && unhandled_signal(current, SIGILL)) {
pr_info("%s[%d]: undefined instruction: pc=%p\n",
current->comm, task_pid_nr(current), pc);
dump_instr(KERN_INFO, regs);
@@ -363,7 +362,7 @@ asmlinkage long do_ni_syscall(struct pt_regs *regs)
}
#endif
- if (show_unhandled_signals && printk_ratelimit()) {
+ if (show_unhandled_signals_ratelimited()) {
pr_info("%s[%d]: syscall %d\n", current->comm,
task_pid_nr(current), (int)regs->syscallno);
dump_instr("", regs);
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
index ff3bddea482d..f6fe17d88da5 100644
--- a/arch/arm64/kernel/vdso/Makefile
+++ b/arch/arm64/kernel/vdso/Makefile
@@ -15,6 +15,10 @@ ccflags-y := -shared -fno-common -fno-builtin
ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \
$(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+# Workaround for bare-metal (ELF) toolchains that neglect to pass -shared
+# down to collect2, resulting in silent corruption of the vDSO image.
+ccflags-y += -Wl,-shared
+
obj-y += vdso.o
extra-y += vdso.lds vdso-offsets.h
CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index a2c29865c3fe..98073332e2d0 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -38,6 +38,12 @@ jiffies = jiffies_64;
*(.hyp.text) \
VMLINUX_SYMBOL(__hyp_text_end) = .;
+#define IDMAP_TEXT \
+ . = ALIGN(SZ_4K); \
+ VMLINUX_SYMBOL(__idmap_text_start) = .; \
+ *(.idmap.text) \
+ VMLINUX_SYMBOL(__idmap_text_end) = .;
+
/*
* The size of the PE/COFF section that covers the kernel image, which
* runs from stext to _edata, must be a round multiple of the PE/COFF
@@ -95,6 +101,7 @@ SECTIONS
SCHED_TEXT
LOCK_TEXT
HYPERVISOR_TEXT
+ IDMAP_TEXT
*(.fixup)
*(.gnu.warning)
. = ALIGN(16);
@@ -167,11 +174,13 @@ SECTIONS
}
/*
- * The HYP init code can't be more than a page long,
+ * The HYP init code and ID map text can't be longer than a page each,
* and should not cross a page boundary.
*/
ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,
"HYP init code too big or misaligned")
+ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,
+ "ID map text too big or misaligned")
/*
* If padding is applied before .head.text, virt<->phys conversions will fail.
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 5105e297ed5f..bfffe8f4bd53 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -28,6 +28,7 @@ config KVM
select KVM_ARM_HOST
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
select SRCU
+ select KVM_VFIO
select HAVE_KVM_EVENTFD
select HAVE_KVM_IRQFD
---help---
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index d5904f876cdb..f90f4aa7f88d 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -11,7 +11,7 @@ ARM=../../../arch/arm/kvm
obj-$(CONFIG_KVM_ARM_HOST) += kvm.o
-kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o $(KVM)/vfio.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/arm.o $(ARM)/mmu.o $(ARM)/mmio.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/psci.o $(ARM)/perf.o
diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
index 5befd010e232..17a8fb14f428 100644
--- a/arch/arm64/kvm/hyp.S
+++ b/arch/arm64/kvm/hyp.S
@@ -17,8 +17,10 @@
#include <linux/linkage.h>
+#include <asm/alternative.h>
#include <asm/asm-offsets.h>
#include <asm/assembler.h>
+#include <asm/cpufeature.h>
#include <asm/debug-monitors.h>
#include <asm/esr.h>
#include <asm/fpsimdmacros.h>
@@ -50,8 +52,8 @@
stp x29, lr, [x3, #80]
mrs x19, sp_el0
- mrs x20, elr_el2 // EL1 PC
- mrs x21, spsr_el2 // EL1 pstate
+ mrs x20, elr_el2 // pc before entering el2
+ mrs x21, spsr_el2 // pstate before entering el2
stp x19, x20, [x3, #96]
str x21, [x3, #112]
@@ -82,8 +84,8 @@
ldr x21, [x3, #16]
msr sp_el0, x19
- msr elr_el2, x20 // EL1 PC
- msr spsr_el2, x21 // EL1 pstate
+ msr elr_el2, x20 // pc on return from el2
+ msr spsr_el2, x21 // pstate on return from el2
add x3, x2, #CPU_XREG_OFFSET(19)
ldp x19, x20, [x3]
@@ -808,10 +810,7 @@
* Call into the vgic backend for state saving
*/
.macro save_vgic_state
- adr x24, __vgic_sr_vectors
- ldr x24, [x24, VGIC_SAVE_FN]
- kern_hyp_va x24
- blr x24
+ alternative_insn "bl __save_vgic_v2_state", "bl __save_vgic_v3_state", ARM64_HAS_SYSREG_GIC_CPUIF
mrs x24, hcr_el2
mov x25, #HCR_INT_OVERRIDE
neg x25, x25
@@ -828,10 +827,7 @@
orr x24, x24, #HCR_INT_OVERRIDE
orr x24, x24, x25
msr hcr_el2, x24
- adr x24, __vgic_sr_vectors
- ldr x24, [x24, #VGIC_RESTORE_FN]
- kern_hyp_va x24
- blr x24
+ alternative_insn "bl __restore_vgic_v2_state", "bl __restore_vgic_v3_state", ARM64_HAS_SYSREG_GIC_CPUIF
.endm
.macro save_timer_state
@@ -1062,12 +1058,6 @@ ENTRY(__kvm_flush_vm_context)
ret
ENDPROC(__kvm_flush_vm_context)
- // struct vgic_sr_vectors __vgi_sr_vectors;
- .align 3
-ENTRY(__vgic_sr_vectors)
- .skip VGIC_SR_VECTOR_SZ
-ENDPROC(__vgic_sr_vectors)
-
__kvm_hyp_panic:
// Guess the context by looking at VTTBR:
// If zero, then we're already a host.
diff --git a/arch/arm64/kvm/vgic-v2-switch.S b/arch/arm64/kvm/vgic-v2-switch.S
index f002fe1c3700..3f000712a85d 100644
--- a/arch/arm64/kvm/vgic-v2-switch.S
+++ b/arch/arm64/kvm/vgic-v2-switch.S
@@ -47,7 +47,6 @@ __save_vgic_v2_state:
add x3, x0, #VCPU_VGIC_CPU
/* Save all interesting registers */
- ldr w4, [x2, #GICH_HCR]
ldr w5, [x2, #GICH_VMCR]
ldr w6, [x2, #GICH_MISR]
ldr w7, [x2, #GICH_EISR0]
@@ -55,7 +54,6 @@ __save_vgic_v2_state:
ldr w9, [x2, #GICH_ELRSR0]
ldr w10, [x2, #GICH_ELRSR1]
ldr w11, [x2, #GICH_APR]
-CPU_BE( rev w4, w4 )
CPU_BE( rev w5, w5 )
CPU_BE( rev w6, w6 )
CPU_BE( rev w7, w7 )
@@ -64,7 +62,6 @@ CPU_BE( rev w9, w9 )
CPU_BE( rev w10, w10 )
CPU_BE( rev w11, w11 )
- str w4, [x3, #VGIC_V2_CPU_HCR]
str w5, [x3, #VGIC_V2_CPU_VMCR]
str w6, [x3, #VGIC_V2_CPU_MISR]
CPU_LE( str w7, [x3, #VGIC_V2_CPU_EISR] )
diff --git a/arch/arm64/kvm/vgic-v3-switch.S b/arch/arm64/kvm/vgic-v3-switch.S
index 617a012a0107..3c20730ddff5 100644
--- a/arch/arm64/kvm/vgic-v3-switch.S
+++ b/arch/arm64/kvm/vgic-v3-switch.S
@@ -48,13 +48,11 @@
dsb st
// Save all interesting registers
- mrs_s x4, ICH_HCR_EL2
mrs_s x5, ICH_VMCR_EL2
mrs_s x6, ICH_MISR_EL2
mrs_s x7, ICH_EISR_EL2
mrs_s x8, ICH_ELSR_EL2
- str w4, [x3, #VGIC_V3_CPU_HCR]
str w5, [x3, #VGIC_V3_CPU_VMCR]
str w6, [x3, #VGIC_V3_CPU_MISR]
str w7, [x3, #VGIC_V3_CPU_EISR]
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index 773d37a14039..9d84feb41a16 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -4,3 +4,5 @@ obj-y := dma-mapping.o extable.o fault.o init.o \
context.o proc.o pageattr.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
obj-$(CONFIG_ARM64_PTDUMP) += dump.o
+
+CFLAGS_mmu.o := -I$(srctree)/scripts/dtc/libfdt/
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 2560e1e1562e..bdeb5d38c2dd 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -22,84 +22,11 @@
#include <linux/init.h>
#include <asm/assembler.h>
#include <asm/cpufeature.h>
-#include <asm/alternative-asm.h>
+#include <asm/alternative.h>
#include "proc-macros.S"
/*
- * __flush_dcache_all()
- *
- * Flush the whole D-cache.
- *
- * Corrupted registers: x0-x7, x9-x11
- */
-__flush_dcache_all:
- dmb sy // ensure ordering with previous memory accesses
- mrs x0, clidr_el1 // read clidr
- and x3, x0, #0x7000000 // extract loc from clidr
- lsr x3, x3, #23 // left align loc bit field
- cbz x3, finished // if loc is 0, then no need to clean
- mov x10, #0 // start clean at cache level 0
-loop1:
- add x2, x10, x10, lsr #1 // work out 3x current cache level
- lsr x1, x0, x2 // extract cache type bits from clidr
- and x1, x1, #7 // mask of the bits for current cache only
- cmp x1, #2 // see what cache we have at this level
- b.lt skip // skip if no cache, or just i-cache
- save_and_disable_irqs x9 // make CSSELR and CCSIDR access atomic
- msr csselr_el1, x10 // select current cache level in csselr
- isb // isb to sych the new cssr&csidr
- mrs x1, ccsidr_el1 // read the new ccsidr
- restore_irqs x9
- and x2, x1, #7 // extract the length of the cache lines
- add x2, x2, #4 // add 4 (line length offset)
- mov x4, #0x3ff
- and x4, x4, x1, lsr #3 // find maximum number on the way size
- clz w5, w4 // find bit position of way size increment
- mov x7, #0x7fff
- and x7, x7, x1, lsr #13 // extract max number of the index size
-loop2:
- mov x9, x4 // create working copy of max way size
-loop3:
- lsl x6, x9, x5
- orr x11, x10, x6 // factor way and cache number into x11
- lsl x6, x7, x2
- orr x11, x11, x6 // factor index number into x11
- dc cisw, x11 // clean & invalidate by set/way
- subs x9, x9, #1 // decrement the way
- b.ge loop3
- subs x7, x7, #1 // decrement the index
- b.ge loop2
-skip:
- add x10, x10, #2 // increment cache number
- cmp x3, x10
- b.gt loop1
-finished:
- mov x10, #0 // swith back to cache level 0
- msr csselr_el1, x10 // select current cache level in csselr
- dsb sy
- isb
- ret
-ENDPROC(__flush_dcache_all)
-
-/*
- * flush_cache_all()
- *
- * Flush the entire cache system. The data cache flush is now achieved
- * using atomic clean / invalidates working outwards from L1 cache. This
- * is done using Set/Way based cache maintainance instructions. The
- * instruction cache can still be invalidated back to the point of
- * unification in a single instruction.
- */
-ENTRY(flush_cache_all)
- mov x12, lr
- bl __flush_dcache_all
- mov x0, #0
- ic ialluis // I+BTB cache invalidate
- ret x12
-ENDPROC(flush_cache_all)
-
-/*
* flush_icache_range(start,end)
*
* Ensure that the I and D caches are coherent within specified region.
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
index baa758d37021..76c1e6cd36fc 100644
--- a/arch/arm64/mm/context.c
+++ b/arch/arm64/mm/context.c
@@ -92,6 +92,14 @@ static void reset_context(void *info)
unsigned int cpu = smp_processor_id();
struct mm_struct *mm = current->active_mm;
+ /*
+ * current->active_mm could be init_mm for the idle thread immediately
+ * after secondary CPU boot or hotplug. TTBR0_EL1 is already set to
+ * the reserved value, so no need to reset any context.
+ */
+ if (mm == &init_mm)
+ return;
+
smp_rmb();
asid = cpu_last_asid + cpu;
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index b0bd4e5fd5cf..d16a1cead23f 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -414,6 +414,98 @@ out:
return -ENOMEM;
}
+/********************************************
+ * The following APIs are for dummy DMA ops *
+ ********************************************/
+
+static void *__dummy_alloc(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flags,
+ struct dma_attrs *attrs)
+{
+ return NULL;
+}
+
+static void __dummy_free(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
+{
+}
+
+static int __dummy_mmap(struct device *dev,
+ struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs)
+{
+ return -ENXIO;
+}
+
+static dma_addr_t __dummy_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ return DMA_ERROR_CODE;
+}
+
+static void __dummy_unmap_page(struct device *dev, dma_addr_t dev_addr,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+}
+
+static int __dummy_map_sg(struct device *dev, struct scatterlist *sgl,
+ int nelems, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ return 0;
+}
+
+static void __dummy_unmap_sg(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+}
+
+static void __dummy_sync_single(struct device *dev,
+ dma_addr_t dev_addr, size_t size,
+ enum dma_data_direction dir)
+{
+}
+
+static void __dummy_sync_sg(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir)
+{
+}
+
+static int __dummy_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
+{
+ return 1;
+}
+
+static int __dummy_dma_supported(struct device *hwdev, u64 mask)
+{
+ return 0;
+}
+
+struct dma_map_ops dummy_dma_ops = {
+ .alloc = __dummy_alloc,
+ .free = __dummy_free,
+ .mmap = __dummy_mmap,
+ .map_page = __dummy_map_page,
+ .unmap_page = __dummy_unmap_page,
+ .map_sg = __dummy_map_sg,
+ .unmap_sg = __dummy_unmap_sg,
+ .sync_single_for_cpu = __dummy_sync_single,
+ .sync_single_for_device = __dummy_sync_single,
+ .sync_sg_for_cpu = __dummy_sync_sg,
+ .sync_sg_for_device = __dummy_sync_sg,
+ .mapping_error = __dummy_mapping_error,
+ .dma_supported = __dummy_dma_supported,
+};
+EXPORT_SYMBOL(dummy_dma_ops);
+
static int __init arm64_dma_init(void)
{
int ret;
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 96da13167d4a..b1fc69cd1499 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -115,8 +115,7 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
{
struct siginfo si;
- if (show_unhandled_signals && unhandled_signal(tsk, sig) &&
- printk_ratelimit()) {
+ if (show_unhandled_signals_ratelimited() && unhandled_signal(tsk, sig)) {
pr_info("%s[%d]: unhandled %s (%d) at 0x%08lx, esr 0x%03x\n",
tsk->comm, task_pid_nr(tsk), fault_name(esr), sig,
addr, esr);
@@ -211,7 +210,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
* If we're in an interrupt or have no user context, we must not take
* the fault.
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto no_context;
if (user_mode(regs))
@@ -478,12 +477,19 @@ asmlinkage void __exception do_sp_pc_abort(unsigned long addr,
struct pt_regs *regs)
{
struct siginfo info;
+ struct task_struct *tsk = current;
+
+ if (show_unhandled_signals && unhandled_signal(tsk, SIGBUS))
+ pr_info_ratelimited("%s[%d]: %s exception: pc=%p sp=%p\n",
+ tsk->comm, task_pid_nr(tsk),
+ esr_get_class_string(esr), (void *)regs->pc,
+ (void *)regs->sp);
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRALN;
info.si_addr = (void __user *)addr;
- arm64_notify_die("", regs, &info, esr);
+ arm64_notify_die("Oops - SP/PC alignment exception", regs, &info, esr);
}
static struct fault_info debug_fault_info[] = {
diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c
index b6f14e8d2121..4dfa3975ce5b 100644
--- a/arch/arm64/mm/flush.c
+++ b/arch/arm64/mm/flush.c
@@ -102,7 +102,6 @@ EXPORT_SYMBOL(flush_dcache_page);
/*
* Additional functions defined in assembly.
*/
-EXPORT_SYMBOL(flush_cache_all);
EXPORT_SYMBOL(flush_icache_range);
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
index 2de9d2e59d96..cccc4af87a03 100644
--- a/arch/arm64/mm/hugetlbpage.c
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -31,13 +31,6 @@
#include <asm/tlbflush.h>
#include <asm/pgalloc.h>
-#ifndef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
- return 0;
-}
-#endif
-
int pmd_huge(pmd_t pmd)
{
return !(pmd_val(pmd) & PMD_TABLE_BIT);
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 597831bdddf3..ad87ce826cce 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -262,7 +262,7 @@ static void __init free_unused_memmap(void)
* memmap entries are valid from the bank end aligned to
* MAX_ORDER_NR_PAGES.
*/
- prev_end = ALIGN(start + __phys_to_pfn(reg->size),
+ prev_end = ALIGN(__phys_to_pfn(reg->base + reg->size),
MAX_ORDER_NR_PAGES);
}
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 5b8b664422d3..82d3435bf14f 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/libfdt.h>
#include <linux/mman.h>
#include <linux/nodemask.h>
#include <linux/memblock.h>
@@ -643,3 +644,68 @@ void __set_fixmap(enum fixed_addresses idx,
flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
}
}
+
+void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
+{
+ const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
+ pgprot_t prot = PAGE_KERNEL | PTE_RDONLY;
+ int granularity, size, offset;
+ void *dt_virt;
+
+ /*
+ * Check whether the physical FDT address is set and meets the minimum
+ * alignment requirement. Since we are relying on MIN_FDT_ALIGN to be
+ * at least 8 bytes so that we can always access the size field of the
+ * FDT header after mapping the first chunk, double check here if that
+ * is indeed the case.
+ */
+ BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
+ if (!dt_phys || dt_phys % MIN_FDT_ALIGN)
+ return NULL;
+
+ /*
+ * Make sure that the FDT region can be mapped without the need to
+ * allocate additional translation table pages, so that it is safe
+ * to call create_mapping() this early.
+ *
+ * On 64k pages, the FDT will be mapped using PTEs, so we need to
+ * be in the same PMD as the rest of the fixmap.
+ * On 4k pages, we'll use section mappings for the FDT so we only
+ * have to be in the same PUD.
+ */
+ BUILD_BUG_ON(dt_virt_base % SZ_2M);
+
+ if (IS_ENABLED(CONFIG_ARM64_64K_PAGES)) {
+ BUILD_BUG_ON(__fix_to_virt(FIX_FDT_END) >> PMD_SHIFT !=
+ __fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT);
+
+ granularity = PAGE_SIZE;
+ } else {
+ BUILD_BUG_ON(__fix_to_virt(FIX_FDT_END) >> PUD_SHIFT !=
+ __fix_to_virt(FIX_BTMAP_BEGIN) >> PUD_SHIFT);
+
+ granularity = PMD_SIZE;
+ }
+
+ offset = dt_phys % granularity;
+ dt_virt = (void *)dt_virt_base + offset;
+
+ /* map the first chunk so we can read the size from the header */
+ create_mapping(round_down(dt_phys, granularity), dt_virt_base,
+ granularity, prot);
+
+ if (fdt_check_header(dt_virt) != 0)
+ return NULL;
+
+ size = fdt_totalsize(dt_virt);
+ if (size > MAX_FDT_SIZE)
+ return NULL;
+
+ if (offset + size > granularity)
+ create_mapping(round_down(dt_phys, granularity), dt_virt_base,
+ round_up(offset + size, granularity), prot);
+
+ memblock_reserve(dt_phys, size);
+
+ return dt_virt;
+}
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index cdd754e19b9b..39139a3aa16d 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -46,52 +46,6 @@
#define MAIR(attr, mt) ((attr) << ((mt) * 8))
/*
- * cpu_cache_off()
- *
- * Turn the CPU D-cache off.
- */
-ENTRY(cpu_cache_off)
- mrs x0, sctlr_el1
- bic x0, x0, #1 << 2 // clear SCTLR.C
- msr sctlr_el1, x0
- isb
- ret
-ENDPROC(cpu_cache_off)
-
-/*
- * cpu_reset(loc)
- *
- * Perform a soft reset of the system. Put the CPU into the same state
- * as it would be if it had been reset, and branch to what would be the
- * reset vector. It must be executed with the flat identity mapping.
- *
- * - loc - location to jump to for soft reset
- */
- .align 5
-ENTRY(cpu_reset)
- mrs x1, sctlr_el1
- bic x1, x1, #1
- msr sctlr_el1, x1 // disable the MMU
- isb
- ret x0
-ENDPROC(cpu_reset)
-
-ENTRY(cpu_soft_restart)
- /* Save address of cpu_reset() and reset address */
- mov x19, x0
- mov x20, x1
-
- /* Turn D-cache off */
- bl cpu_cache_off
-
- /* Push out all dirty data, and ensure cache is empty */
- bl flush_cache_all
-
- mov x0, x20
- ret x19
-ENDPROC(cpu_soft_restart)
-
-/*
* cpu_do_idle()
*
* Idle the processor (wait for interrupt).
diff --git a/arch/avr32/include/asm/Kbuild b/arch/avr32/include/asm/Kbuild
index 528d70d47a54..1d66afdfac07 100644
--- a/arch/avr32/include/asm/Kbuild
+++ b/arch/avr32/include/asm/Kbuild
@@ -15,7 +15,6 @@ generic-y += mcs_spinlock.h
generic-y += param.h
generic-y += percpu.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += topology.h
generic-y += trace_clock.h
diff --git a/arch/avr32/include/asm/cmpxchg.h b/arch/avr32/include/asm/cmpxchg.h
index 962a6aeab787..366bbeaeb405 100644
--- a/arch/avr32/include/asm/cmpxchg.h
+++ b/arch/avr32/include/asm/cmpxchg.h
@@ -70,8 +70,6 @@ extern unsigned long __cmpxchg_u64_unsupported_on_32bit_kernels(
if something tries to do an invalid cmpxchg(). */
extern void __cmpxchg_called_with_bad_pointer(void);
-#define __HAVE_ARCH_CMPXCHG 1
-
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
unsigned long new, int size)
{
diff --git a/arch/avr32/include/asm/dma-mapping.h b/arch/avr32/include/asm/dma-mapping.h
index b3d18f9f3e8d..ae7ac9205d20 100644
--- a/arch/avr32/include/asm/dma-mapping.h
+++ b/arch/avr32/include/asm/dma-mapping.h
@@ -209,17 +209,18 @@ dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
* the same here.
*/
static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
enum dma_data_direction direction)
{
int i;
+ struct scatterlist *sg;
- for (i = 0; i < nents; i++) {
+ for_each_sg(sglist, sg, nents, i) {
char *virt;
- sg[i].dma_address = page_to_bus(sg_page(&sg[i])) + sg[i].offset;
- virt = sg_virt(&sg[i]);
- dma_cache_sync(dev, virt, sg[i].length, direction);
+ sg->dma_address = page_to_bus(sg_page(sg)) + sg->offset;
+ virt = sg_virt(sg);
+ dma_cache_sync(dev, virt, sg->length, direction);
}
return nents;
@@ -321,14 +322,14 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
}
static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
int nents, enum dma_data_direction direction)
{
int i;
+ struct scatterlist *sg;
- for (i = 0; i < nents; i++) {
- dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, direction);
- }
+ for_each_sg(sglist, sg, nents, i)
+ dma_cache_sync(dev, sg_virt(sg), sg->length, direction);
}
/* Now for the API extensions over the pci_ one */
diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h
index 4f5ec2bb7172..e998ff5d8e1a 100644
--- a/arch/avr32/include/asm/io.h
+++ b/arch/avr32/include/asm/io.h
@@ -296,6 +296,7 @@ extern void __iounmap(void __iomem *addr);
__iounmap(addr)
#define ioremap_wc ioremap_nocache
+#define ioremap_wt ioremap_nocache
#define cached(addr) P1SEGADDR(addr)
#define uncached(addr) P2SEGADDR(addr)
diff --git a/arch/avr32/include/asm/mm-arch-hooks.h b/arch/avr32/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..145452ffbdad
--- /dev/null
+++ b/arch/avr32/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_AVR32_MM_ARCH_HOOKS_H
+#define _ASM_AVR32_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_AVR32_MM_ARCH_HOOKS_H */
diff --git a/arch/avr32/include/asm/uaccess.h b/arch/avr32/include/asm/uaccess.h
index a46f7cf3e1ea..68cf638faf48 100644
--- a/arch/avr32/include/asm/uaccess.h
+++ b/arch/avr32/include/asm/uaccess.h
@@ -97,7 +97,8 @@ static inline __kernel_size_t __copy_from_user(void *to,
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
@@ -116,7 +117,8 @@ static inline __kernel_size_t __copy_from_user(void *to,
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
@@ -136,7 +138,8 @@ static inline __kernel_size_t __copy_from_user(void *to,
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
@@ -158,7 +161,8 @@ static inline __kernel_size_t __copy_from_user(void *to,
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c
index d223a8b57c1e..c03533937a9f 100644
--- a/arch/avr32/mm/fault.c
+++ b/arch/avr32/mm/fault.c
@@ -14,11 +14,11 @@
#include <linux/pagemap.h>
#include <linux/kdebug.h>
#include <linux/kprobes.h>
+#include <linux/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/sysreg.h>
#include <asm/tlb.h>
-#include <asm/uaccess.h>
#ifdef CONFIG_KPROBES
static inline int notify_page_fault(struct pt_regs *regs, int trap)
@@ -81,7 +81,7 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
* If we're in an interrupt or have no user context, we must
* not take the fault...
*/
- if (in_atomic() || !mm || regs->sr & SYSREG_BIT(GM))
+ if (faulthandler_disabled() || !mm || regs->sr & SYSREG_BIT(GM))
goto no_context;
local_irq_enable();
diff --git a/arch/blackfin/include/asm/Kbuild b/arch/blackfin/include/asm/Kbuild
index 4bd3c3cfc9ab..07051a63415d 100644
--- a/arch/blackfin/include/asm/Kbuild
+++ b/arch/blackfin/include/asm/Kbuild
@@ -29,7 +29,6 @@ generic-y += percpu.h
generic-y += pgalloc.h
generic-y += preempt.h
generic-y += resource.h
-generic-y += scatterlist.h
generic-y += sembuf.h
generic-y += serial.h
generic-y += setup.h
diff --git a/arch/blackfin/include/asm/bfin_serial.h b/arch/blackfin/include/asm/bfin_serial.h
index d00d732784b1..b550ada7321b 100644
--- a/arch/blackfin/include/asm/bfin_serial.h
+++ b/arch/blackfin/include/asm/bfin_serial.h
@@ -22,9 +22,9 @@
defined(CONFIG_BFIN_UART2_CTSRTS) || \
defined(CONFIG_BFIN_UART3_CTSRTS)
# if defined(BFIN_UART_BF54X_STYLE) || defined(BFIN_UART_BF60X_STYLE)
-# define CONFIG_SERIAL_BFIN_HARD_CTSRTS
+# define SERIAL_BFIN_HARD_CTSRTS
# else
-# define CONFIG_SERIAL_BFIN_CTSRTS
+# define SERIAL_BFIN_CTSRTS
# endif
#endif
@@ -50,8 +50,8 @@ struct bfin_serial_port {
#elif ANOMALY_05000363
unsigned int anomaly_threshold;
#endif
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
- defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+#if defined(SERIAL_BFIN_CTSRTS) || \
+ defined(SERIAL_BFIN_HARD_CTSRTS)
int cts_pin;
int rts_pin;
#endif
diff --git a/arch/blackfin/include/asm/mm-arch-hooks.h b/arch/blackfin/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..1c5211ec338f
--- /dev/null
+++ b/arch/blackfin/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_BLACKFIN_MM_ARCH_HOOKS_H
+#define _ASM_BLACKFIN_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_BLACKFIN_MM_ARCH_HOOKS_H */
diff --git a/arch/blackfin/include/asm/pci.h b/arch/blackfin/include/asm/pci.h
index c737909fba47..14efc0db1ade 100644
--- a/arch/blackfin/include/asm/pci.h
+++ b/arch/blackfin/include/asm/pci.h
@@ -3,7 +3,7 @@
#ifndef _ASM_BFIN_PCI_H
#define _ASM_BFIN_PCI_H
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <asm-generic/pci-dma-compat.h>
#include <asm-generic/pci.h>
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
index ae0a51f5376c..7aeb32272975 100644
--- a/arch/c6x/include/asm/Kbuild
+++ b/arch/c6x/include/asm/Kbuild
@@ -38,7 +38,6 @@ generic-y += poll.h
generic-y += posix_types.h
generic-y += preempt.h
generic-y += resource.h
-generic-y += scatterlist.h
generic-y += segment.h
generic-y += sembuf.h
generic-y += serial.h
diff --git a/arch/c6x/include/asm/mm-arch-hooks.h b/arch/c6x/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..bb3c4a6ce8e9
--- /dev/null
+++ b/arch/c6x/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_C6X_MM_ARCH_HOOKS_H
+#define _ASM_C6X_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_C6X_MM_ARCH_HOOKS_H */
diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild
index 057e51859b0a..d294f6aaff1d 100644
--- a/arch/cris/include/asm/Kbuild
+++ b/arch/cris/include/asm/Kbuild
@@ -21,7 +21,6 @@ generic-y += mcs_spinlock.h
generic-y += module.h
generic-y += percpu.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += topology.h
generic-y += trace_clock.h
diff --git a/arch/cris/include/asm/dma-mapping.h b/arch/cris/include/asm/dma-mapping.h
index 2f0f654f1b44..57f794ee6039 100644
--- a/arch/cris/include/asm/dma-mapping.h
+++ b/arch/cris/include/asm/dma-mapping.h
@@ -5,10 +5,10 @@
#include <linux/mm.h>
#include <linux/kernel.h>
+#include <linux/scatterlist.h>
#include <asm/cache.h>
#include <asm/io.h>
-#include <asm/scatterlist.h>
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
diff --git a/arch/cris/include/asm/mm-arch-hooks.h b/arch/cris/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..314f774db2b0
--- /dev/null
+++ b/arch/cris/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_CRIS_MM_ARCH_HOOKS_H
+#define _ASM_CRIS_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_CRIS_MM_ARCH_HOOKS_H */
diff --git a/arch/cris/include/asm/pci.h b/arch/cris/include/asm/pci.h
index cc2399c175e9..c15b4b4baafa 100644
--- a/arch/cris/include/asm/pci.h
+++ b/arch/cris/include/asm/pci.h
@@ -29,7 +29,7 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
#include <linux/types.h>
#include <linux/slab.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <linux/string.h>
#include <asm/io.h>
diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c
index 83f12f2ed9e3..3066d40a6db1 100644
--- a/arch/cris/mm/fault.c
+++ b/arch/cris/mm/fault.c
@@ -8,7 +8,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/wait.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <arch/system.h>
extern int find_fixup_code(struct pt_regs *);
@@ -109,11 +109,11 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
info.si_code = SEGV_MAPERR;
/*
- * If we're in an interrupt or "atomic" operation or have no
+ * If we're in an interrupt, have pagefaults disabled or have no
* user context, we must not take the fault.
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto no_context;
if (user_mode(regs))
diff --git a/arch/frv/include/asm/Kbuild b/arch/frv/include/asm/Kbuild
index e3f81b53578e..30edce31e5c2 100644
--- a/arch/frv/include/asm/Kbuild
+++ b/arch/frv/include/asm/Kbuild
@@ -5,5 +5,4 @@ generic-y += exec.h
generic-y += irq_work.h
generic-y += mcs_spinlock.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += trace_clock.h
diff --git a/arch/frv/include/asm/dma-mapping.h b/arch/frv/include/asm/dma-mapping.h
index 1746a2b8e6e7..2840adcd6d92 100644
--- a/arch/frv/include/asm/dma-mapping.h
+++ b/arch/frv/include/asm/dma-mapping.h
@@ -2,9 +2,9 @@
#define _ASM_DMA_MAPPING_H
#include <linux/device.h>
+#include <linux/scatterlist.h>
#include <asm/cache.h>
#include <asm/cacheflush.h>
-#include <asm/scatterlist.h>
#include <asm/io.h>
/*
diff --git a/arch/frv/include/asm/io.h b/arch/frv/include/asm/io.h
index 0b78bc89e840..a31b63ec4930 100644
--- a/arch/frv/include/asm/io.h
+++ b/arch/frv/include/asm/io.h
@@ -17,6 +17,8 @@
#ifdef __KERNEL__
+#define ARCH_HAS_IOREMAP_WT
+
#include <linux/types.h>
#include <asm/virtconvert.h>
#include <asm/string.h>
@@ -265,7 +267,7 @@ static inline void __iomem *ioremap_nocache(unsigned long physaddr, unsigned lon
return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
}
-static inline void __iomem *ioremap_writethrough(unsigned long physaddr, unsigned long size)
+static inline void __iomem *ioremap_wt(unsigned long physaddr, unsigned long size)
{
return __ioremap(physaddr, size, IOMAP_WRITETHROUGH);
}
diff --git a/arch/frv/include/asm/mm-arch-hooks.h b/arch/frv/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..51d13a870404
--- /dev/null
+++ b/arch/frv/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_FRV_MM_ARCH_HOOKS_H
+#define _ASM_FRV_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_FRV_MM_ARCH_HOOKS_H */
diff --git a/arch/frv/include/asm/pci.h b/arch/frv/include/asm/pci.h
index 2035a4d3f9b9..e43d22c58ad5 100644
--- a/arch/frv/include/asm/pci.h
+++ b/arch/frv/include/asm/pci.h
@@ -14,7 +14,7 @@
#define _ASM_FRV_PCI_H
#include <linux/mm.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <asm-generic/pci-dma-compat.h>
#include <asm-generic/pci.h>
@@ -41,16 +41,6 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
/* Return the index of the PCI controller for device PDEV. */
#define pci_controller_num(PDEV) (0)
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- *strat = PCI_DMA_BURST_INFINITY;
- *strategy_parameter = ~0UL;
-}
-#endif
-
/*
* These are pretty much arbitrary with the CoMEM implementation.
* We have the whole address space to ourselves.
diff --git a/arch/frv/include/asm/sections.h b/arch/frv/include/asm/sections.h
index 17d0fb171bba..d03fb64e93e9 100644
--- a/arch/frv/include/asm/sections.h
+++ b/arch/frv/include/asm/sections.h
@@ -35,12 +35,6 @@ extern unsigned long __nongprelbss memory_start;
extern unsigned long __nongprelbss memory_end;
extern unsigned long __nongprelbss rom_length;
-/* determine if we're running from ROM */
-static inline int is_in_rom(unsigned long addr)
-{
- return 0; /* default case: not in ROM */
-}
-
#endif
#endif
#endif /* _ASM_SECTIONS_H */
diff --git a/arch/frv/mb93090-mb00/pci-dma-nommu.c b/arch/frv/mb93090-mb00/pci-dma-nommu.c
index b99c2a7cc7a4..8eeea0d77aad 100644
--- a/arch/frv/mb93090-mb00/pci-dma-nommu.c
+++ b/arch/frv/mb93090-mb00/pci-dma-nommu.c
@@ -119,14 +119,16 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
EXPORT_SYMBOL(dma_map_single);
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
enum dma_data_direction direction)
{
int i;
+ struct scatterlist *sg;
- for (i=0; i<nents; i++)
- frv_cache_wback_inv(sg_dma_address(&sg[i]),
- sg_dma_address(&sg[i]) + sg_dma_len(&sg[i]));
+ for_each_sg(sglist, sg, nents, i) {
+ frv_cache_wback_inv(sg_dma_address(sg),
+ sg_dma_address(sg) + sg_dma_len(sg));
+ }
BUG_ON(direction == DMA_NONE);
diff --git a/arch/frv/mb93090-mb00/pci-dma.c b/arch/frv/mb93090-mb00/pci-dma.c
index 82478979ac9a..4d1f01dc46e5 100644
--- a/arch/frv/mb93090-mb00/pci-dma.c
+++ b/arch/frv/mb93090-mb00/pci-dma.c
@@ -50,19 +50,20 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
EXPORT_SYMBOL(dma_map_single);
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
enum dma_data_direction direction)
{
unsigned long dampr2;
void *vaddr;
int i;
+ struct scatterlist *sg;
BUG_ON(direction == DMA_NONE);
dampr2 = __get_DAMPR(2);
- for (i = 0; i < nents; i++) {
- vaddr = kmap_atomic_primary(sg_page(&sg[i]));
+ for_each_sg(sglist, sg, nents, i) {
+ vaddr = kmap_atomic_primary(sg_page(sg));
frv_dcache_writeback((unsigned long) vaddr,
(unsigned long) vaddr + PAGE_SIZE);
diff --git a/arch/frv/mm/fault.c b/arch/frv/mm/fault.c
index ec4917ddf678..61d99767fe16 100644
--- a/arch/frv/mm/fault.c
+++ b/arch/frv/mm/fault.c
@@ -19,9 +19,9 @@
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <linux/hardirq.h>
+#include <linux/uaccess.h>
#include <asm/pgtable.h>
-#include <asm/uaccess.h>
#include <asm/gdb-stub.h>
/*****************************************************************************/
@@ -78,7 +78,7 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto no_context;
if (user_mode(__frame))
diff --git a/arch/frv/mm/highmem.c b/arch/frv/mm/highmem.c
index bed9a9bd3c10..785344bbdc07 100644
--- a/arch/frv/mm/highmem.c
+++ b/arch/frv/mm/highmem.c
@@ -42,6 +42,7 @@ void *kmap_atomic(struct page *page)
unsigned long paddr;
int type;
+ preempt_disable();
pagefault_disable();
type = kmap_atomic_idx_push();
paddr = page_to_phys(page);
@@ -85,5 +86,6 @@ void __kunmap_atomic(void *kvaddr)
}
kmap_atomic_idx_pop();
pagefault_enable();
+ preempt_enable();
}
EXPORT_SYMBOL(__kunmap_atomic);
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
new file mode 100644
index 000000000000..db589167838c
--- /dev/null
+++ b/arch/h8300/Kconfig
@@ -0,0 +1,76 @@
+config H8300
+ def_bool y
+ select GENERIC_ATOMIC64
+ select HAVE_UID16
+ select VIRT_TO_BUS
+ select GENERIC_IRQ_SHOW
+ select FRAME_POINTER
+ select GENERIC_CPU_DEVICES
+ select MODULES_USE_ELF_RELA
+ select GENERIC_CLOCKEVENTS
+ select CLKDEV_LOOKUP
+ select COMMON_CLK
+ select ARCH_WANT_FRAME_POINTERS
+ select OF
+ select OF_IRQ
+ select OF_EARLY_FLATTREE
+ select HAVE_MEMBLOCK
+ select HAVE_DMA_ATTRS
+
+config RWSEM_GENERIC_SPINLOCK
+ def_bool y
+
+config GENERIC_HWEIGHT
+ def_bool y
+
+config NO_IOPORT_MAP
+ def_bool y
+
+config GENERIC_CSUM
+ def_bool y
+
+config HZ
+ int
+ default 100
+
+config NR_CPUS
+ int
+ default 1
+
+source "init/Kconfig"
+
+source "kernel/Kconfig.freezer"
+
+source "arch/h8300/Kconfig.cpu"
+
+menu "Kernel Features"
+
+source "kernel/Kconfig.preempt"
+
+source "mm/Kconfig"
+
+endmenu
+
+menu "Executable file formats"
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+source "net/Kconfig"
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+endmenu
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
diff --git a/arch/h8300/Kconfig.cpu b/arch/h8300/Kconfig.cpu
new file mode 100644
index 000000000000..8d0ff20c749a
--- /dev/null
+++ b/arch/h8300/Kconfig.cpu
@@ -0,0 +1,99 @@
+config CPU_H8300H
+ bool
+
+config CPU_H8S
+ bool
+
+config H83069
+ bool
+ select CPU_H8300H
+ select H8300_TMR16
+ select RENESAS_H8300H_INTC
+
+config H8S2678
+ bool
+ select CPU_H8S
+ select H8300_TPU
+ select RENESAS_H8S_INTC
+
+config RAMKERNEL
+ bool
+
+config ROMKERNEL
+ bool
+
+menu "Processor type and features"
+
+choice
+prompt "H8/300 platform"
+
+config H8300_AE3068
+ bool "AE-3068/69"
+ select H83069
+ select RAMKERNEL
+ help
+ AKI-H8/3068F / AKI-H8/3069F Flashmicom LAN Board Support
+ More Information. (Japanese Only)
+ <http://akizukidenshi.com/catalog/default.aspx>
+ AE-3068/69 Evaluation Board Support
+ More Information.
+ <http://www.microtronique.com/ae3069lan.htm>
+
+config H8300_H8MAX
+ bool "H8MAX"
+ select H83069
+ select RAMKERNEL
+ select HAVE_IDE
+ help
+ H8MAX Evaluation Board Support
+ More Information. (Japanese Only)
+ <http://strawberry-linux.com/h8/index.html>
+
+config H8300_KANEBEBE
+ bool "KaneBebe"
+ select H83069
+ select RAMKERNEL
+ help
+ KaneBebe Evalition Board Support
+ More Information. (Japanese Only)
+ <http://www.nissin-tech.com/2009/10/uclinuxkane-bebe-h83069f.html>
+
+config H8300H_SIM
+ bool "H8/300H GDB Simulator"
+ select H83069
+ select ROMKERNEL
+ help
+ GDB Simulator Support
+ More Information.
+ <http://sourceware.org/sid/>
+
+config H8S_EDOSK2674
+ bool "EDOSK-2674"
+ select H8S2678
+ select RAMKERNEL
+ help
+ Renesas EDOSK-2674 Evaluation Board Support
+ More Information.
+ <http://www.azpower.com/H8-uClinux/index.html>
+ <http://www.renesas.eu/products/tools/introductory_evaluation_tools/evaluation_development_os_kits/edosk2674r/edosk2674r_software_tools_root.jsp>
+
+config H8S_SIM
+ bool "H8S GDB Simulator"
+ select H8S2678
+ select ROMKERNEL
+ help
+ GDB Simulator Support
+ More Information.
+ <http://sourceware.org/sid/>
+
+endchoice
+
+config H8300_BUILTIN_DTB
+ string "Builtin DTB"
+ default ""
+
+config OFFSET
+ hex "Load offset"
+ default 0
+
+endmenu
diff --git a/arch/h8300/Makefile b/arch/h8300/Makefile
new file mode 100644
index 000000000000..0d2d96e52d9f
--- /dev/null
+++ b/arch/h8300/Makefile
@@ -0,0 +1,55 @@
+#
+# arch/h8300/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# (C) Copyright 2002-2015 Yoshinori Sato <ysato@users.sourceforge.jp>
+#
+
+cflags-$(CONFIG_CPU_H8300H) := -mh
+aflags-$(CONFIG_CPU_H8300H) := -mh -Wa,--mach=h8300h
+ldflags-$(CONFIG_CPU_H8300H) := -mh8300helf_linux
+cflags-$(CONFIG_CPU_H8S) := -ms
+aflags-$(CONFIG_CPU_H8S) := -ms -Wa,--mach=h8300s
+ldflags-$(CONFIG_CPU_H8S) := -mh8300self_linux
+
+KBUILD_CFLAGS += $(cflags-y)
+KBUILD_CFLAGS += -mint32 -fno-builtin
+KBUILD_CFLAGS += -D__linux__
+KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\"
+KBUILD_AFLAGS += $(aflags-y)
+LDFLAGS += $(ldflags-y)
+
+CROSS_COMPILE := h8300-unknown-linux-
+
+core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/
+ifneq '$(CONFIG_H8300_BUILTIN_DTB)' '""'
+core-y += arch/h8300/boot/dts/
+endif
+
+libs-y += arch/$(ARCH)/lib/
+
+boot := arch/h8300/boot
+
+%.dtb %.dtb.S %.dtb.o: | scripts
+ $(Q)$(MAKE) $(build)=arch/h8300/boot/dts arch/h8300/boot/dts/$@
+
+PHONY += dtbs
+dtbs: scripts
+ $(Q)$(MAKE) $(build)=arch/h8300/boot/dts
+
+archmrproper:
+
+archclean:
+ $(Q)$(MAKE) $(clean)=$(boot)
+
+vmlinux.srec vmlinux.bin zImage uImage.bin: vmlinux
+ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
+define archhelp
+ @echo 'vmlinux.bin - Create raw binary'
+ @echo 'vmlinux.srec - Create srec binary'
+ @echo 'zImage - Compressed kernel image'
+endef
diff --git a/arch/h8300/boot/Makefile b/arch/h8300/boot/Makefile
new file mode 100644
index 000000000000..2f6393a5da57
--- /dev/null
+++ b/arch/h8300/boot/Makefile
@@ -0,0 +1,26 @@
+# arch/h8300/boot/Makefile
+
+targets := vmlinux.srec vmlinux.bin zImage
+subdir- := compressed
+
+OBJCOPYFLAGS_vmlinux.srec := -Osrec
+OBJCOPYFLAGS_vmlinux.bin := -Obinary
+OBJCOPYFLAGS_zImage := -O binary -R .note -R .comment -R .stab -R .stabstr -S
+
+UIMAGE_LOADADDR = $(CONFIG_RAMBASE)
+UIMAGE_ENTRYADDR = $(shell /bin/bash -c 'printf "0x%08x" \
+ $$[$(CONFIG_RAMBASE) + $(CONFIG_OFFSET)]')
+
+$(obj)/vmlinux.srec $(obj)/vmlinux.bin: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
+ $(call if_changed,objcopy)
+
+$(obj)/compressed/vmlinux: FORCE
+ $(Q)$(MAKE) $(build)=$(obj)/compressed $@
+
+$(obj)/uImage.bin: $(obj)/vmlinux.bin
+ $(call if_changed,uimage,none)
+
+CLEAN_FILES += arch/$(ARCH)/vmlinux.bin arch/$(ARCH)/vmlinux.srec arch/$(ARCH)/uImage.bin
diff --git a/arch/h8300/boot/compressed/Makefile b/arch/h8300/boot/compressed/Makefile
new file mode 100644
index 000000000000..87d03b7ee97e
--- /dev/null
+++ b/arch/h8300/boot/compressed/Makefile
@@ -0,0 +1,37 @@
+#
+# linux/arch/sh/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
+
+OBJECTS = $(obj)/head.o $(obj)/misc.o
+
+#
+# IMAGE_OFFSET is the load offset of the compression loader
+# Assign dummy values if these 2 variables are not defined,
+# in order to suppress error message.
+#
+CONFIG_MEMORY_START ?= 0x00400000
+CONFIG_BOOT_LINK_OFFSET ?= 0x00140000
+IMAGE_OFFSET := $(shell printf "0x%08x" $$(($(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET))))
+
+LIBGCC := $(shell $(CROSS-COMPILE)$(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
+LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -estartup $(obj)/vmlinux.lds
+
+$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
+ $(call if_changed,ld)
+ @:
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,gzip)
+
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-h8300-linux -T
+OBJCOPYFLAGS := -O binary
+
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
+ $(call if_changed,ld)
diff --git a/arch/h8300/boot/compressed/head.S b/arch/h8300/boot/compressed/head.S
new file mode 100644
index 000000000000..74c0d8cc40ba
--- /dev/null
+++ b/arch/h8300/boot/compressed/head.S
@@ -0,0 +1,48 @@
+/*
+ * linux/arch/h8300/boot/compressed/head.S
+ *
+ * Copyright (C) 2006 Yoshinori Sato
+ */
+
+#include <linux/linkage.h>
+
+ .section .text..startup,"ax"
+ .global startup
+startup:
+ mov.l er0, er4
+ mov.l er0, sp
+ mov.l #__sbss, er0
+ mov.l #__ebss, er1
+ sub.l er0, er1
+ shlr er1
+ shlr er1
+ sub.l er2, er2
+1:
+ mov.l er2, @er0
+ adds #4, er0
+ dec.l #1, er1
+ bne 1b
+ jsr @decompress_kernel
+ mov.l er4, er0
+ jmp @0x400000
+
+ .align 9
+fake_headers_as_bzImage:
+ .word 0
+ .ascii "HdrS" ; header signature
+ .word 0x0202 ; header version number (>= 0x0105)
+ ; or else old loadlin-1.5 will fail)
+ .word 0 ; default_switch
+ .word 0 ; SETUPSEG
+ .word 0x1000
+ .word 0 ; pointing to kernel version string
+ .byte 0 ; = 0, old one (LILO, Loadlin,
+ ; 0xTV: T=0 for LILO
+ ; V = version
+ .byte 1 ; Load flags bzImage=1
+ .word 0x8000 ; size to move, when setup is not
+ .long 0x100000 ; 0x100000 = default for big kernel
+ .long 0 ; address of loaded ramdisk image
+ .long 0 ; its size in bytes
+
+ .end
diff --git a/arch/h8300/boot/compressed/misc.c b/arch/h8300/boot/compressed/misc.c
new file mode 100644
index 000000000000..704274127c07
--- /dev/null
+++ b/arch/h8300/boot/compressed/misc.c
@@ -0,0 +1,74 @@
+/*
+ * arch/h8300/boot/compressed/misc.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ *
+ * Adapted for h8300 by Yoshinori Sato 2006
+ */
+
+#include <asm/uaccess.h>
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args) args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n) memset((s), (0), (n))
+
+extern int _end;
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+
+extern char input_data[];
+extern int input_len;
+static unsigned char *output;
+
+#define HEAP_SIZE 0x10000
+
+#include "../../../../lib/decompress_inflate.c"
+
+void *memset(void *s, int c, size_t n)
+{
+ int i;
+ char *ss = (char *)s;
+
+ for (i = 0; i < n; i++)
+ ss[i] = c;
+ return s;
+}
+
+void *memcpy(void *dest, const void *src, size_t n)
+{
+ int i;
+ char *d = (char *)dest, *s = (char *)src;
+
+ for (i = 0; i < n; i++)
+ d[i] = s[i];
+ return dest;
+}
+
+static void error(char *x)
+{
+
+ while (1)
+ ; /* Halt */
+}
+
+#define STACK_SIZE (4096)
+long user_stack[STACK_SIZE];
+long *stack_start = &user_stack[STACK_SIZE];
+
+void decompress_kernel(void)
+{
+ free_mem_ptr = (unsigned long)&_end;
+ free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
+ decompress(input_data, input_len, NULL, NULL, output, NULL, error);
+}
diff --git a/arch/h8300/boot/compressed/vmlinux.lds b/arch/h8300/boot/compressed/vmlinux.lds
new file mode 100644
index 000000000000..a0a3a0ed54ef
--- /dev/null
+++ b/arch/h8300/boot/compressed/vmlinux.lds
@@ -0,0 +1,32 @@
+SECTIONS
+{
+ .text :
+ {
+ __stext = . ;
+ __text = .;
+ *(.text..startup)
+ *(.text)
+ __etext = . ;
+ }
+
+ .rodata :
+ {
+ *(.rodata)
+ }
+ .data :
+
+ {
+ __sdata = . ;
+ ___data_start = . ;
+ *(.data.*)
+ }
+ .bss :
+ {
+ . = ALIGN(0x4) ;
+ __sbss = . ;
+ *(.bss*)
+ . = ALIGN(0x4) ;
+ __ebss = . ;
+ __end = . ;
+ }
+}
diff --git a/arch/h8300/boot/compressed/vmlinux.scr b/arch/h8300/boot/compressed/vmlinux.scr
new file mode 100644
index 000000000000..a084903603fe
--- /dev/null
+++ b/arch/h8300/boot/compressed/vmlinux.scr
@@ -0,0 +1,9 @@
+SECTIONS
+{
+ .data : {
+ input_len = .;
+ LONG(input_data_end - input_data) input_data = .;
+ *(.data)
+ input_data_end = .;
+ }
+}
diff --git a/arch/h8300/boot/dts/Makefile b/arch/h8300/boot/dts/Makefile
new file mode 100644
index 000000000000..0abaf1ad830e
--- /dev/null
+++ b/arch/h8300/boot/dts/Makefile
@@ -0,0 +1,12 @@
+ifneq '$(CONFIG_H8300_BUILTIN_DTB)' '""'
+BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_H8300_BUILTIN_DTB)).dtb.o
+endif
+
+obj-y += $(BUILTIN_DTB)
+
+dtb-$(CONFIG_H8300H_SIM) := h8300h_sim.dtb
+dtb-$(CONFIG_H8S_SIM) := h8s_sim.dtb
+dtb-$(CONFIG_H8S_EDOSK2674) := edosk2674.dtb
+
+always := $(dtb-y)
+clean-files := *.dtb.S *.dtb
diff --git a/arch/h8300/boot/dts/edosk2674.dts b/arch/h8300/boot/dts/edosk2674.dts
new file mode 100644
index 000000000000..dfb5c102f8da
--- /dev/null
+++ b/arch/h8300/boot/dts/edosk2674.dts
@@ -0,0 +1,107 @@
+/dts-v1/;
+/ {
+ compatible = "renesas,edosk2674";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&h8intc>;
+
+ chosen {
+ bootargs = "console=ttySC2,38400";
+ stdout-path = <&sci2>;
+ };
+ aliases {
+ serial0 = &sci0;
+ serial1 = &sci1;
+ serial2 = &sci2;
+ };
+
+ xclk: oscillator {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <33333333>;
+ clock-output-names = "xtal";
+ };
+ pllclk: pllclk {
+ compatible = "renesas,h8s2678-pll-clock";
+ clocks = <&xclk>;
+ #clock-cells = <0>;
+ reg = <0xfee03b 2>, <0xfee045 2>;
+ };
+ core_clk: core_clk {
+ compatible = "renesas,h8300-div-clock";
+ clocks = <&pllclk>;
+ #clock-cells = <0>;
+ reg = <0xfee03b 2>;
+ renesas,width = <3>;
+ };
+ fclk: fclk {
+ compatible = "fixed-factor-clock";
+ clocks = <&core_clk>;
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <1>;
+ };
+
+ memory@400000 {
+ device_type = "memory";
+ reg = <0x400000 0x800000>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ compatible = "renesas,h8300";
+ clock-frequency = <33333333>;
+ };
+ };
+
+ h8intc: interrupt-controller@fffe00 {
+ compatible = "renesas,h8s-intc", "renesas,h8300-intc";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0xfffe00 24>;
+ };
+
+ bsc: memory-controller@fffec0 {
+ compatible = "renesas,h8s-bsc", "renesas,h8300-bsc";
+ reg = <0xfffec0 24>;
+ };
+
+ tpu: timer@ffffe0 {
+ compatible = "renesas,tpu";
+ reg = <0xffffe0 16>, <0xfffff0 12>;
+ clocks = <&fclk>;
+ clock-names = "fck";
+ };
+
+ timer8: timer@ffffb0 {
+ compatible = "renesas,8bit-timer";
+ reg = <0xffffb0 10>;
+ interrupts = <72 0>;
+ clocks = <&fclk>;
+ clock-names = "fck";
+ };
+
+ sci0: serial@ffff78 {
+ compatible = "renesas,sci";
+ reg = <0xffff78 8>;
+ interrupts = <88 0>, <89 0>, <90 0>, <91 0>;
+ clocks = <&fclk>;
+ clock-names = "sci_ick";
+ };
+ sci1: serial@ffff80 {
+ compatible = "renesas,sci";
+ reg = <0xffff80 8>;
+ interrupts = <92 0>, <93 0>, <94 0>, <95 0>;
+ clocks = <&fclk>;
+ clock-names = "sci_ick";
+ };
+ sci2: serial@ffff88 {
+ compatible = "renesas,sci";
+ reg = <0xffff88 8>;
+ interrupts = <96 0>, <97 0>, <98 0>, <99 0>;
+ clocks = <&fclk>;
+ clock-names = "sci_ick";
+ };
+};
diff --git a/arch/h8300/boot/dts/h8300h_sim.dts b/arch/h8300/boot/dts/h8300h_sim.dts
new file mode 100644
index 000000000000..545bfb57af9a
--- /dev/null
+++ b/arch/h8300/boot/dts/h8300h_sim.dts
@@ -0,0 +1,96 @@
+/dts-v1/;
+/ {
+ compatible = "gnu,gdbsim";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&h8intc>;
+
+ chosen {
+ bootargs = "earlyprintk=h8300-sim";
+ stdout-path = <&sci0>;
+ };
+ aliases {
+ serial0 = &sci0;
+ serial1 = &sci1;
+ };
+
+ xclk: oscillator {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <20000000>;
+ clock-output-names = "xtal";
+ };
+ core_clk: core_clk {
+ compatible = "renesas,h8300-div-clock";
+ clocks = <&xclk>;
+ #clock-cells = <0>;
+ reg = <0xfee01b 2>;
+ renesas,width = <2>;
+ };
+ fclk: fclk {
+ compatible = "fixed-factor-clock";
+ clocks = <&core_clk>;
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <1>;
+ };
+
+ memory@400000 {
+ device_type = "memory";
+ reg = <0x400000 0x400000>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ compatible = "renesas,h8300";
+ clock-frequency = <20000000>;
+ };
+ };
+
+ h8intc: interrupt-controller@fee012 {
+ compatible = "renesas,h8300h-intc", "renesas,h8300-intc";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0xfee012 7>;
+ };
+
+ bsc: memory-controller@fee01e {
+ compatible = "renesas,h8300h-bsc", "renesas,h8300-bsc";
+ reg = <0xfee01e 8>;
+ };
+
+ timer8: timer@ffff80 {
+ compatible = "renesas,8bit-timer";
+ reg = <0xffff80 10>;
+ interrupts = <36 0>;
+ clocks = <&fclk>;
+ clock-names = "fck";
+ };
+
+ timer16: timer@ffff68 {
+ compatible = "renesas,16bit-timer";
+ reg = <0xffff68 8>, <0xffff60 8>;
+ interrupts = <24 0>;
+ renesas,channel = <0>;
+ clocks = <&fclk>;
+ clock-names = "fck";
+ };
+
+ sci0: serial@ffffb0 {
+ compatible = "renesas,sci";
+ reg = <0xffffb0 8>;
+ interrupts = <52 0>, <53 0>, <54 0>, <55 0>;
+ clocks = <&fclk>;
+ clock-names = "sci_ick";
+ };
+
+ sci1: serial@ffffb8 {
+ compatible = "renesas,sci";
+ reg = <0xffffb8 8>;
+ interrupts = <56 0>, <57 0>, <58 0>, <59 0>;
+ clocks = <&fclk>;
+ clock-names = "sci_ick";
+ };
+};
diff --git a/arch/h8300/boot/dts/h8s_sim.dts b/arch/h8300/boot/dts/h8s_sim.dts
new file mode 100644
index 000000000000..bcedba5a3ce7
--- /dev/null
+++ b/arch/h8300/boot/dts/h8s_sim.dts
@@ -0,0 +1,99 @@
+/dts-v1/;
+/ {
+ compatible = "gnu,gdbsim";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&h8intc>;
+
+ chosen {
+ bootargs = "earlyprintk=h8300-sim";
+ stdout-path = <&sci0>;
+ };
+ aliases {
+ serial0 = &sci0;
+ serial1 = &sci1;
+ };
+
+ xclk: oscillator {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <33333333>;
+ clock-output-names = "xtal";
+ };
+ pllclk: pllclk {
+ compatible = "renesas,h8s2678-pll-clock";
+ clocks = <&xclk>;
+ #clock-cells = <0>;
+ reg = <0xfee03b 2>, <0xfee045 2>;
+ };
+ core_clk: core_clk {
+ compatible = "renesas,h8300-div-clock";
+ clocks = <&pllclk>;
+ #clock-cells = <0>;
+ reg = <0xfee03b 2>;
+ renesas,width = <3>;
+ };
+ fclk: fclk {
+ compatible = "fixed-factor-clock";
+ clocks = <&core_clk>;
+ #clock-cells = <0>;
+ clock-div = <1>;
+ clock-mult = <1>;
+ };
+
+ memory@400000 {
+ device_type = "memory";
+ reg = <0x400000 0x800000>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ compatible = "renesas,h8300";
+ clock-frequency = <33333333>;
+ };
+ };
+
+ h8intc: interrupt-controller@fffe00 {
+ compatible = "renesas,h8s-intc", "renesas,h8300-intc";
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0xfffe00 24>;
+ };
+
+ bsc: memory-controller@fffec0 {
+ compatible = "renesas,h8s-bsc", "renesas,h8300-bsc";
+ reg = <0xfffec0 24>;
+ };
+
+ tpu: timer@ffffe0 {
+ compatible = "renesas,tpu";
+ reg = <0xffffe0 16>, <0xfffff0 12>;
+ clocks = <&fclk>;
+ clock-names = "fck";
+ };
+
+ timer8: timer@ffffb0 {
+ compatible = "renesas,8bit-timer";
+ reg = <0xffffb0 10>;
+ interrupts = <72 0>;
+ clocks = <&fclk>;
+ clock-names = "fck";
+ };
+
+ sci0: serial@ffff78 {
+ compatible = "renesas,sci";
+ reg = <0xffff78 8>;
+ interrupts = <88 0>, <89 0>, <90 0>, <91 0>;
+ clocks = <&fclk>;
+ clock-names = "sci_ick";
+ };
+ sci1: serial@ffff80 {
+ compatible = "renesas,sci";
+ reg = <0xffff80 8>;
+ interrupts = <92 0>, <93 0>, <94 0>, <95 0>;
+ clocks = <&fclk>;
+ clock-names = "sci_ick";
+ };
+};
diff --git a/arch/h8300/configs/edosk2674_defconfig b/arch/h8300/configs/edosk2674_defconfig
new file mode 100644
index 000000000000..29fda12d5da9
--- /dev/null
+++ b/arch/h8300/configs/edosk2674_defconfig
@@ -0,0 +1,49 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_USELIB is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_UID16 is not set
+# CONFIG_SYSFS_SYSCALL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_ADVISE_SYSCALLS is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLOB=y
+# CONFIG_BLOCK is not set
+CONFIG_H8S_SIM=y
+CONFIG_H8300_BUILTIN_DTB="h8s_sim"
+# CONFIG_BINFMT_SCRIPT is not set
+CONFIG_BINFMT_FLAT=y
+# CONFIG_COREDUMP is not set
+# CONFIG_UEVENT_HELPER is not set
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_ALLOW_DEV_COREDUMP is not set
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_PROC_FS is not set
+# CONFIG_SYSFS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
diff --git a/arch/h8300/configs/h8300h-sim_defconfig b/arch/h8300/configs/h8300h-sim_defconfig
new file mode 100644
index 000000000000..067bfe9c49b3
--- /dev/null
+++ b/arch/h8300/configs/h8300h-sim_defconfig
@@ -0,0 +1,49 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_USELIB is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_UID16 is not set
+# CONFIG_SYSFS_SYSCALL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_ADVISE_SYSCALLS is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLOB=y
+# CONFIG_BLOCK is not set
+CONFIG_H8300H_SIM=y
+CONFIG_H8300_BUILTIN_DTB="h8300h_sim"
+# CONFIG_BINFMT_SCRIPT is not set
+CONFIG_BINFMT_FLAT=y
+# CONFIG_COREDUMP is not set
+# CONFIG_UEVENT_HELPER is not set
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_ALLOW_DEV_COREDUMP is not set
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_PROC_FS is not set
+# CONFIG_SYSFS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
diff --git a/arch/h8300/configs/h8s-sim_defconfig b/arch/h8300/configs/h8s-sim_defconfig
new file mode 100644
index 000000000000..29fda12d5da9
--- /dev/null
+++ b/arch/h8300/configs/h8s-sim_defconfig
@@ -0,0 +1,49 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_USELIB is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_UID16 is not set
+# CONFIG_SYSFS_SYSCALL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_ADVISE_SYSCALLS is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLOB=y
+# CONFIG_BLOCK is not set
+CONFIG_H8S_SIM=y
+CONFIG_H8300_BUILTIN_DTB="h8s_sim"
+# CONFIG_BINFMT_SCRIPT is not set
+CONFIG_BINFMT_FLAT=y
+# CONFIG_COREDUMP is not set
+# CONFIG_UEVENT_HELPER is not set
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_ALLOW_DEV_COREDUMP is not set
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_PROC_FS is not set
+# CONFIG_SYSFS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
diff --git a/arch/h8300/include/asm/Kbuild b/arch/h8300/include/asm/Kbuild
new file mode 100644
index 000000000000..00379d64f707
--- /dev/null
+++ b/arch/h8300/include/asm/Kbuild
@@ -0,0 +1,75 @@
+generic-y += asm-offsets.h
+generic-y += auxvec.h
+generic-y += barrier.h
+generic-y += bugs.h
+generic-y += cacheflush.h
+generic-y += checksum.h
+generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += current.h
+generic-y += delay.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += dma.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += exec.h
+generic-y += fb.h
+generic-y += fcntl.h
+generic-y += ftrace.h
+generic-y += futex.h
+generic-y += hardirq.h
+generic-y += hash.h
+generic-y += hw_irq.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += irq_regs.h
+generic-y += irq_work.h
+generic-y += kdebug.h
+generic-y += kmap_types.h
+generic-y += kvm_para.h
+generic-y += linkage.h
+generic-y += local.h
+generic-y += local64.h
+generic-y += mcs_spinlock.h
+generic-y += mman.h
+generic-y += mmu.h
+generic-y += mmu_context.h
+generic-y += module.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += parport.h
+generic-y += percpu.h
+generic-y += pgalloc.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += preempt.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += sembuf.h
+generic-y += serial.h
+generic-y += setup.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
+generic-y += siginfo.h
+generic-y += sizes.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += spinlock.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += swab.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += timex.h
+generic-y += tlbflush.h
+generic-y += trace_clock.h
+generic-y += topology.h
+generic-y += types.h
+generic-y += uaccess.h
+generic-y += ucontext.h
+generic-y += unaligned.h
+generic-y += vga.h
+generic-y += xor.h
diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h
new file mode 100644
index 000000000000..7ca73f8546cc
--- /dev/null
+++ b/arch/h8300/include/asm/atomic.h
@@ -0,0 +1,159 @@
+#ifndef __ARCH_H8300_ATOMIC__
+#define __ARCH_H8300_ATOMIC__
+
+#include <linux/types.h>
+#include <asm/cmpxchg.h>
+
+/*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc..
+ */
+
+#define ATOMIC_INIT(i) { (i) }
+
+#define atomic_read(v) ACCESS_ONCE((v)->counter)
+#define atomic_set(v, i) (((v)->counter) = i)
+
+#include <linux/kernel.h>
+
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+ h8300flags flags;
+ int ret;
+
+ flags = arch_local_irq_save();
+ ret = v->counter += i;
+ arch_local_irq_restore(flags);
+ return ret;
+}
+
+#define atomic_add(i, v) atomic_add_return(i, v)
+#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
+
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+ h8300flags flags;
+ int ret;
+
+ flags = arch_local_irq_save();
+ ret = v->counter -= i;
+ arch_local_irq_restore(flags);
+ return ret;
+}
+
+#define atomic_sub(i, v) atomic_sub_return(i, v)
+#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
+
+static inline int atomic_inc_return(atomic_t *v)
+{
+ h8300flags flags;
+ int ret;
+
+ flags = arch_local_irq_save();
+ v->counter++;
+ ret = v->counter;
+ arch_local_irq_restore(flags);
+ return ret;
+}
+
+#define atomic_inc(v) atomic_inc_return(v)
+
+/*
+ * atomic_inc_and_test - increment and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
+
+static inline int atomic_dec_return(atomic_t *v)
+{
+ h8300flags flags;
+ int ret;
+
+ flags = arch_local_irq_save();
+ --v->counter;
+ ret = v->counter;
+ arch_local_irq_restore(flags);
+ return ret;
+}
+
+#define atomic_dec(v) atomic_dec_return(v)
+
+static inline int atomic_dec_and_test(atomic_t *v)
+{
+ h8300flags flags;
+ int ret;
+
+ flags = arch_local_irq_save();
+ --v->counter;
+ ret = v->counter;
+ arch_local_irq_restore(flags);
+ return ret == 0;
+}
+
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+ int ret;
+ h8300flags flags;
+
+ flags = arch_local_irq_save();
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
+ arch_local_irq_restore(flags);
+ return ret;
+}
+
+static inline int __atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int ret;
+ h8300flags flags;
+
+ flags = arch_local_irq_save();
+ ret = v->counter;
+ if (ret != u)
+ v->counter += a;
+ arch_local_irq_restore(flags);
+ return ret;
+}
+
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *v)
+{
+ unsigned char ccr;
+ unsigned long tmp;
+
+ __asm__ __volatile__("stc ccr,%w3\n\t"
+ "orc #0x80,ccr\n\t"
+ "mov.l %0,%1\n\t"
+ "and.l %2,%1\n\t"
+ "mov.l %1,%0\n\t"
+ "ldc %w3,ccr"
+ : "=m"(*v), "=r"(tmp)
+ : "g"(~(mask)), "r"(ccr));
+}
+
+static inline void atomic_set_mask(unsigned long mask, unsigned long *v)
+{
+ unsigned char ccr;
+ unsigned long tmp;
+
+ __asm__ __volatile__("stc ccr,%w3\n\t"
+ "orc #0x80,ccr\n\t"
+ "mov.l %0,%1\n\t"
+ "or.l %2,%1\n\t"
+ "mov.l %1,%0\n\t"
+ "ldc %w3,ccr"
+ : "=m"(*v), "=r"(tmp)
+ : "g"(~(mask)), "r"(ccr));
+}
+
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec() barrier()
+#define smp_mb__after_atomic_dec() barrier()
+#define smp_mb__before_atomic_inc() barrier()
+#define smp_mb__after_atomic_inc() barrier()
+
+#endif /* __ARCH_H8300_ATOMIC __ */
diff --git a/arch/h8300/include/asm/bitops.h b/arch/h8300/include/asm/bitops.h
new file mode 100644
index 000000000000..05999aba1d6a
--- /dev/null
+++ b/arch/h8300/include/asm/bitops.h
@@ -0,0 +1,185 @@
+#ifndef _H8300_BITOPS_H
+#define _H8300_BITOPS_H
+
+/*
+ * Copyright 1992, Linus Torvalds.
+ * Copyright 2002, Yoshinori Sato
+ */
+
+#include <linux/compiler.h>
+
+#ifdef __KERNEL__
+
+#ifndef _LINUX_BITOPS_H
+#error only <linux/bitops.h> can be included directly
+#endif
+
+/*
+ * Function prototypes to keep gcc -Wall happy
+ */
+
+/*
+ * ffz = Find First Zero in word. Undefined if no zero exists,
+ * so code should check against ~0UL first..
+ */
+static inline unsigned long ffz(unsigned long word)
+{
+ unsigned long result;
+
+ result = -1;
+ __asm__("1:\n\t"
+ "shlr.l %2\n\t"
+ "adds #1,%0\n\t"
+ "bcs 1b"
+ : "=r"(result)
+ : "0"(result), "r"(word));
+ return result;
+}
+
+#define H8300_GEN_BITOP(FNAME, OP) \
+static inline void FNAME(int nr, volatile unsigned long *addr) \
+{ \
+ unsigned char *b_addr; \
+ unsigned char bit = nr & 7; \
+ \
+ b_addr = (unsigned char *)addr + ((nr >> 3) ^ 3); \
+ if (__builtin_constant_p(nr)) { \
+ __asm__(OP " %1,%0" : "+WU"(*b_addr) : "i"(nr & 7)); \
+ } else { \
+ __asm__(OP " %s1,%0" : "+WU"(*b_addr) : "r"(bit)); \
+ } \
+}
+
+/*
+ * clear_bit() doesn't provide any barrier for the compiler.
+ */
+#define smp_mb__before_clear_bit() barrier()
+#define smp_mb__after_clear_bit() barrier()
+
+H8300_GEN_BITOP(set_bit, "bset")
+H8300_GEN_BITOP(clear_bit, "bclr")
+H8300_GEN_BITOP(change_bit, "bnot")
+#define __set_bit(nr, addr) set_bit((nr), (addr))
+#define __clear_bit(nr, addr) clear_bit((nr), (addr))
+#define __change_bit(nr, addr) change_bit((nr), (addr))
+
+#undef H8300_GEN_BITOP
+
+static inline int test_bit(int nr, const unsigned long *addr)
+{
+ int ret = 0;
+ unsigned char *b_addr;
+ unsigned char bit = nr & 7;
+
+ b_addr = (unsigned char *)addr + ((nr >> 3) ^ 3);
+ if (__builtin_constant_p(nr)) {
+ __asm__("bld %Z2,%1\n\t"
+ "rotxl %0\n\t"
+ : "=r"(ret)
+ : "WU"(*b_addr), "i"(nr & 7), "0"(ret) : "cc");
+ } else {
+ __asm__("btst %w2,%1\n\t"
+ "beq 1f\n\t"
+ "inc.l #1,%0\n"
+ "1:"
+ : "=r"(ret)
+ : "WU"(*b_addr), "r"(bit), "0"(ret) : "cc");
+ }
+ return ret;
+}
+
+#define __test_bit(nr, addr) test_bit(nr, addr)
+
+#define H8300_GEN_TEST_BITOP(FNNAME, OP) \
+static inline int FNNAME(int nr, void *addr) \
+{ \
+ int retval = 0; \
+ char ccrsave; \
+ unsigned char *b_addr; \
+ unsigned char bit = nr & 7; \
+ \
+ b_addr = (unsigned char *)addr + ((nr >> 3) ^ 3); \
+ if (__builtin_constant_p(nr)) { \
+ __asm__("stc ccr,%s2\n\t" \
+ "orc #0x80,ccr\n\t" \
+ "bld %4,%1\n\t" \
+ OP " %4,%1\n\t" \
+ "rotxl.l %0\n\t" \
+ "ldc %s2,ccr" \
+ : "=r"(retval), "+WU" (*b_addr), "=&r"(ccrsave) \
+ : "0"(retval), "i"(nr & 7) : "cc"); \
+ } else { \
+ __asm__("stc ccr,%t3\n\t" \
+ "orc #0x80,ccr\n\t" \
+ "btst %s3,%1\n\t" \
+ OP " %s3,%1\n\t" \
+ "beq 1f\n\t" \
+ "inc.l #1,%0\n\t" \
+ "1:\n" \
+ "ldc %t3,ccr" \
+ : "=r"(retval), "+WU" (*b_addr) \
+ : "0" (retval), "r"(bit) : "cc"); \
+ } \
+ return retval; \
+} \
+ \
+static inline int __ ## FNNAME(int nr, void *addr) \
+{ \
+ int retval = 0; \
+ unsigned char *b_addr; \
+ unsigned char bit = nr & 7; \
+ \
+ b_addr = (unsigned char *)addr + ((nr >> 3) ^ 3); \
+ if (__builtin_constant_p(nr)) { \
+ __asm__("bld %3,%1\n\t" \
+ OP " %3,%1\n\t" \
+ "rotxl.l %0\n\t" \
+ : "=r"(retval), "+WU"(*b_addr) \
+ : "0" (retval), "i"(nr & 7)); \
+ } else { \
+ __asm__("btst %s3,%1\n\t" \
+ OP " %s3,%1\n\t" \
+ "beq 1f\n\t" \
+ "inc.l #1,%0\n\t" \
+ "1:" \
+ : "=r"(retval), "+WU"(*b_addr) \
+ : "0" (retval), "r"(bit)); \
+ } \
+ return retval; \
+}
+
+H8300_GEN_TEST_BITOP(test_and_set_bit, "bset")
+H8300_GEN_TEST_BITOP(test_and_clear_bit, "bclr")
+H8300_GEN_TEST_BITOP(test_and_change_bit, "bnot")
+#undef H8300_GEN_TEST_BITOP
+
+#include <asm-generic/bitops/ffs.h>
+
+static inline unsigned long __ffs(unsigned long word)
+{
+ unsigned long result;
+
+ result = -1;
+ __asm__("1:\n\t"
+ "shlr.l %2\n\t"
+ "adds #1,%0\n\t"
+ "bcc 1b"
+ : "=r" (result)
+ : "0"(result), "r"(word));
+ return result;
+}
+
+#include <asm-generic/bitops/find.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/lock.h>
+#include <asm-generic/bitops/le.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+
+#endif /* __KERNEL__ */
+
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+
+#endif /* _H8300_BITOPS_H */
diff --git a/arch/h8300/include/asm/bitsperlong.h b/arch/h8300/include/asm/bitsperlong.h
new file mode 100644
index 000000000000..e140e46729ac
--- /dev/null
+++ b/arch/h8300/include/asm/bitsperlong.h
@@ -0,0 +1,14 @@
+#ifndef __ASM_H8300_BITS_PER_LONG
+#define __ASM_H8300_BITS_PER_LONG
+
+#include <asm-generic/bitsperlong.h>
+
+#if !defined(__ASSEMBLY__)
+/* h8300-unknown-linux required long */
+#define __kernel_size_t __kernel_size_t
+typedef unsigned long __kernel_size_t;
+typedef long __kernel_ssize_t;
+typedef long __kernel_ptrdiff_t;
+#endif
+
+#endif /* __ASM_H8300_BITS_PER_LONG */
diff --git a/arch/h8300/include/asm/bug.h b/arch/h8300/include/asm/bug.h
new file mode 100644
index 000000000000..1e1be8119935
--- /dev/null
+++ b/arch/h8300/include/asm/bug.h
@@ -0,0 +1,12 @@
+#ifndef _H8300_BUG_H
+#define _H8300_BUG_H
+
+/* always true */
+#define is_valid_bugaddr(addr) (1)
+
+#include <asm-generic/bug.h>
+
+struct pt_regs;
+extern void die(const char *str, struct pt_regs *fp, unsigned long err);
+
+#endif
diff --git a/arch/h8300/include/asm/byteorder.h b/arch/h8300/include/asm/byteorder.h
new file mode 100644
index 000000000000..888478a38145
--- /dev/null
+++ b/arch/h8300/include/asm/byteorder.h
@@ -0,0 +1,7 @@
+#ifndef __H8300_BYTEORDER_H__
+#define __H8300_BYTEORDER_H__
+
+#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__
+#include <linux/byteorder/big_endian.h>
+
+#endif
diff --git a/arch/h8300/include/asm/cache.h b/arch/h8300/include/asm/cache.h
new file mode 100644
index 000000000000..0ef1edc5a6a6
--- /dev/null
+++ b/arch/h8300/include/asm/cache.h
@@ -0,0 +1,11 @@
+#ifndef __ARCH_H8300_CACHE_H
+#define __ARCH_H8300_CACHE_H
+
+/* bytes per L1 cache line */
+#define L1_CACHE_SHIFT 2
+#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
+
+#define __cacheline_aligned
+#define ____cacheline_aligned
+
+#endif
diff --git a/arch/h8300/include/asm/cmpxchg.h b/arch/h8300/include/asm/cmpxchg.h
new file mode 100644
index 000000000000..95fec4cd1081
--- /dev/null
+++ b/arch/h8300/include/asm/cmpxchg.h
@@ -0,0 +1,65 @@
+#ifndef __ARCH_H8300_CMPXCHG__
+#define __ARCH_H8300_CMPXCHG__
+
+#include <linux/irqflags.h>
+
+#define xchg(ptr, x) \
+ ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), \
+ sizeof(*(ptr))))
+
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((volatile struct __xchg_dummy *)(x))
+
+static inline unsigned long __xchg(unsigned long x,
+ volatile void *ptr, int size)
+{
+ unsigned long tmp, flags;
+
+ local_irq_save(flags);
+
+ switch (size) {
+ case 1:
+ __asm__ __volatile__
+ ("mov.b %2,%0\n\t"
+ "mov.b %1,%2"
+ : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)));
+ break;
+ case 2:
+ __asm__ __volatile__
+ ("mov.w %2,%0\n\t"
+ "mov.w %1,%2"
+ : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)));
+ break;
+ case 4:
+ __asm__ __volatile__
+ ("mov.l %2,%0\n\t"
+ "mov.l %1,%2"
+ : "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)));
+ break;
+ default:
+ tmp = 0;
+ }
+ local_irq_restore(flags);
+ return tmp;
+}
+
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n) \
+ ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), \
+ (unsigned long)(o), \
+ (unsigned long)(n), \
+ sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#ifndef CONFIG_SMP
+#include <asm-generic/cmpxchg.h>
+#endif
+
+#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+
+#endif /* __ARCH_H8300_CMPXCHG__ */
diff --git a/arch/h8300/include/asm/dma-mapping.h b/arch/h8300/include/asm/dma-mapping.h
new file mode 100644
index 000000000000..6e67a90902f2
--- /dev/null
+++ b/arch/h8300/include/asm/dma-mapping.h
@@ -0,0 +1,57 @@
+#ifndef _H8300_DMA_MAPPING_H
+#define _H8300_DMA_MAPPING_H
+
+#include <asm-generic/dma-coherent.h>
+
+extern struct dma_map_ops h8300_dma_map_ops;
+
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+ return &h8300_dma_map_ops;
+}
+
+#include <asm-generic/dma-mapping-common.h>
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+ return 0;
+}
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+ return 0;
+}
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+
+#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ void *memory;
+
+ memory = ops->alloc(dev, size, dma_handle, flag, attrs);
+ return memory;
+}
+
+#define dma_free_coherent(d, s, c, h) dma_free_attrs(d, s, c, h, NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
+ ops->free(dev, size, cpu_addr, dma_handle, attrs);
+}
+
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+ return 0;
+}
+
+#endif
diff --git a/arch/h8300/include/asm/elf.h b/arch/h8300/include/asm/elf.h
new file mode 100644
index 000000000000..09031d0127a3
--- /dev/null
+++ b/arch/h8300/include/asm/elf.h
@@ -0,0 +1,101 @@
+#ifndef __ASM_H8300_ELF_H
+#define __ASM_H8300_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+#include <asm/user.h>
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+typedef unsigned long elf_fpregset_t;
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x)->e_machine == EM_H8_300)
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_H8_300
+#if defined(CONFIG_CPU_H8300H)
+#define ELF_CORE_EFLAGS 0x810000
+#endif
+#if defined(CONFIG_CPU_H8S)
+#define ELF_CORE_EFLAGS 0x820000
+#endif
+
+#define ELF_PLAT_INIT(_r) do { (_r)->er1 = 0; } while (0)
+
+#define ELF_EXEC_PAGESIZE 4096
+
+/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ use of this is to invoke "./ld.so someprog" to test out a new version of
+ 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. */
+
+#define ELF_ET_DYN_BASE 0xD0000000UL
+
+/* This yields a mask that user programs can use to figure out what
+ instruction set this cpu supports. */
+
+#define ELF_HWCAP (0)
+
+/* This yields a string that ld.so will use to load implementation
+ specific libraries for optimization. This is more specific in
+ intent than poking at uname or /proc/cpuinfo. */
+
+#define ELF_PLATFORM (NULL)
+
+#define R_H8_NONE 0
+#define R_H8_DIR32 1
+#define R_H8_DIR32_28 2
+#define R_H8_DIR32_24 3
+#define R_H8_DIR32_16 4
+#define R_H8_DIR32U 6
+#define R_H8_DIR32U_28 7
+#define R_H8_DIR32U_24 8
+#define R_H8_DIR32U_20 9
+#define R_H8_DIR32U_16 10
+#define R_H8_DIR24 11
+#define R_H8_DIR24_20 12
+#define R_H8_DIR24_16 13
+#define R_H8_DIR24U 14
+#define R_H8_DIR24U_20 15
+#define R_H8_DIR24U_16 16
+#define R_H8_DIR16 17
+#define R_H8_DIR16U 18
+#define R_H8_DIR16S_32 19
+#define R_H8_DIR16S_28 20
+#define R_H8_DIR16S_24 21
+#define R_H8_DIR16S_20 22
+#define R_H8_DIR16S 23
+#define R_H8_DIR8 24
+#define R_H8_DIR8U 25
+#define R_H8_DIR8Z_32 26
+#define R_H8_DIR8Z_28 27
+#define R_H8_DIR8Z_24 28
+#define R_H8_DIR8Z_20 29
+#define R_H8_DIR8Z_16 30
+#define R_H8_PCREL16 31
+#define R_H8_PCREL8 32
+#define R_H8_BPOS 33
+#define R_H8_PCREL32 34
+#define R_H8_GOT32O 35
+#define R_H8_GOT16O 36
+#define R_H8_DIR16A8 59
+#define R_H8_DIR16R8 60
+#define R_H8_DIR24A8 61
+#define R_H8_DIR24R8 62
+#define R_H8_DIR32A16 63
+#define R_H8_ABS32 65
+#define R_H8_ABS32A16 127
+
+#endif
diff --git a/arch/h8300/include/asm/flat.h b/arch/h8300/include/asm/flat.h
new file mode 100644
index 000000000000..a4898eccf2bf
--- /dev/null
+++ b/arch/h8300/include/asm/flat.h
@@ -0,0 +1,28 @@
+/*
+ * arch/h8300/asm/include/flat.h -- uClinux flat-format executables
+ */
+
+#ifndef __H8300_FLAT_H__
+#define __H8300_FLAT_H__
+
+#define flat_argvp_envp_on_stack() 1
+#define flat_old_ram_flag(flags) 1
+#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
+#define flat_set_persistent(relval, p) 0
+
+/*
+ * on the H8 a couple of the relocations have an instruction in the
+ * top byte. As there can only be 24bits of address space, we just
+ * always preserve that 8bits at the top, when it isn't an instruction
+ * is is 0 (davidm@snapgear.com)
+ */
+
+#define flat_get_relocate_addr(rel) (rel & ~0x00000001)
+#define flat_get_addr_from_rp(rp, relval, flags, persistent) \
+ ({(void)persistent; \
+ get_unaligned(rp) & (((flags) & FLAT_FLAG_GOTPIC) ? \
+ 0xffffffff : 0x00ffffff); })
+#define flat_put_addr_at_rp(rp, addr, rel) \
+ put_unaligned(((*(char *)(rp)) << 24) | ((addr) & 0x00ffffff), (rp))
+
+#endif /* __H8300_FLAT_H__ */
diff --git a/arch/h8300/include/asm/io.h b/arch/h8300/include/asm/io.h
new file mode 100644
index 000000000000..1d09b2f2e0fe
--- /dev/null
+++ b/arch/h8300/include/asm/io.h
@@ -0,0 +1,57 @@
+#ifndef _H8300_IO_H
+#define _H8300_IO_H
+
+#ifdef __KERNEL__
+
+#include <asm-generic/io.h>
+
+/* H8/300 internal I/O functions */
+static inline unsigned char ctrl_inb(unsigned long addr)
+{
+ return *(volatile unsigned char *)addr;
+}
+
+static inline unsigned short ctrl_inw(unsigned long addr)
+{
+ return *(volatile unsigned short *)addr;
+}
+
+static inline unsigned long ctrl_inl(unsigned long addr)
+{
+ return *(volatile unsigned long *)addr;
+}
+
+static inline void ctrl_outb(unsigned char b, unsigned long addr)
+{
+ *(volatile unsigned char *)addr = b;
+}
+
+static inline void ctrl_outw(unsigned short b, unsigned long addr)
+{
+ *(volatile unsigned short *)addr = b;
+}
+
+static inline void ctrl_outl(unsigned long b, unsigned long addr)
+{
+ *(volatile unsigned long *)addr = b;
+}
+
+static inline void ctrl_bclr(int b, unsigned long addr)
+{
+ if (__builtin_constant_p(b))
+ __asm__("bclr %1,%0" : : "WU"(addr), "i"(b));
+ else
+ __asm__("bclr %w1,%0" : : "WU"(addr), "r"(b));
+}
+
+static inline void ctrl_bset(int b, unsigned long addr)
+{
+ if (__builtin_constant_p(b))
+ __asm__("bset %1,%0" : : "WU"(addr), "i"(b));
+ else
+ __asm__("bset %w1,%0" : : "WU"(addr), "r"(b));
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _H8300_IO_H */
diff --git a/arch/h8300/include/asm/irq.h b/arch/h8300/include/asm/irq.h
new file mode 100644
index 000000000000..69f23f0981b3
--- /dev/null
+++ b/arch/h8300/include/asm/irq.h
@@ -0,0 +1,26 @@
+#ifndef _H8300_IRQ_H_
+#define _H8300_IRQ_H_
+
+#include <linux/irqchip.h>
+
+#if defined(CONFIG_CPU_H8300H)
+#define NR_IRQS 64
+#define IRQ_CHIP h8300h_irq_chip
+#define EXT_IRQ0 12
+#define EXT_IRQS 6
+#elif defined(CONFIG_CPU_H8S)
+#define NR_IRQS 128
+#define IRQ_CHIP h8s_irq_chip
+#define EXT_IRQ0 16
+#define EXT_IRQS 16
+#endif
+
+static inline int irq_canonicalize(int irq)
+{
+ return irq;
+}
+
+void h8300_init_ipr(void);
+extern struct irq_chip h8300h_irq_chip;
+extern struct irq_chip h8s_irq_chip;
+#endif /* _H8300_IRQ_H_ */
diff --git a/arch/h8300/include/asm/irqflags.h b/arch/h8300/include/asm/irqflags.h
new file mode 100644
index 000000000000..5e1e3242e470
--- /dev/null
+++ b/arch/h8300/include/asm/irqflags.h
@@ -0,0 +1,96 @@
+#ifndef _H8300_IRQFLAGS_H
+#define _H8300_IRQFLAGS_H
+
+#ifdef CONFIG_CPU_H8300H
+typedef unsigned char h8300flags;
+
+static inline h8300flags arch_local_save_flags(void)
+{
+ h8300flags flags;
+
+ __asm__ volatile ("stc ccr,%w0" : "=r" (flags));
+ return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+ __asm__ volatile ("orc #0xc0,ccr");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+ __asm__ volatile ("andc #0x3f,ccr");
+}
+
+static inline h8300flags arch_local_irq_save(void)
+{
+ h8300flags flags;
+
+ __asm__ volatile ("stc ccr,%w0\n\t"
+ "orc #0xc0,ccr" : "=r" (flags));
+ return flags;
+}
+
+static inline void arch_local_irq_restore(h8300flags flags)
+{
+ __asm__ volatile ("ldc %w0,ccr" : : "r" (flags) : "cc");
+}
+
+static inline int arch_irqs_disabled_flags(unsigned long flags)
+{
+ return (flags & 0xc0) == 0xc0;
+}
+#endif
+#ifdef CONFIG_CPU_H8S
+typedef unsigned short h8300flags;
+
+static inline h8300flags arch_local_save_flags(void)
+{
+ h8300flags flags;
+
+ __asm__ volatile ("stc ccr,%w0\n\tstc exr,%x0" : "=r" (flags));
+ return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+ __asm__ volatile ("orc #0x80,ccr\n\t");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+ __asm__ volatile ("andc #0x7f,ccr\n\t"
+ "andc #0xf0,exr\n\t");
+}
+
+static inline h8300flags arch_local_irq_save(void)
+{
+ h8300flags flags;
+
+ __asm__ volatile ("stc ccr,%w0\n\t"
+ "stc exr,%x0\n\t"
+ "orc #0x80,ccr\n\t"
+ : "=r" (flags));
+ return flags;
+}
+
+static inline void arch_local_irq_restore(h8300flags flags)
+{
+ __asm__ volatile ("ldc %w0,ccr\n\t"
+ "ldc %x0,exr"
+ : : "r" (flags) : "cc");
+}
+
+static inline int arch_irqs_disabled_flags(h8300flags flags)
+{
+ return (flags & 0x0080) == 0x0080;
+}
+
+#endif
+
+static inline int arch_irqs_disabled(void)
+{
+ return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* _H8300_IRQFLAGS_H */
diff --git a/arch/h8300/include/asm/mc146818rtc.h b/arch/h8300/include/asm/mc146818rtc.h
new file mode 100644
index 000000000000..ab9d9646d241
--- /dev/null
+++ b/arch/h8300/include/asm/mc146818rtc.h
@@ -0,0 +1,9 @@
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+#ifndef _H8300_MC146818RTC_H
+#define _H8300_MC146818RTC_H
+
+/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */
+
+#endif /* _H8300_MC146818RTC_H */
diff --git a/arch/h8300/include/asm/mutex.h b/arch/h8300/include/asm/mutex.h
new file mode 100644
index 000000000000..458c1f7fbc18
--- /dev/null
+++ b/arch/h8300/include/asm/mutex.h
@@ -0,0 +1,9 @@
+/*
+ * Pull in the generic implementation for the mutex fastpath.
+ *
+ * TODO: implement optimized primitives instead, or leave the generic
+ * implementation in place, or pick the atomic_xchg() based generic
+ * implementation. (see asm-generic/mutex-xchg.h for details)
+ */
+
+#include <asm-generic/mutex-dec.h>
diff --git a/arch/h8300/include/asm/page.h b/arch/h8300/include/asm/page.h
new file mode 100644
index 000000000000..3a987a567258
--- /dev/null
+++ b/arch/h8300/include/asm/page.h
@@ -0,0 +1,18 @@
+#ifndef _H8300_PAGE_H
+#define _H8300_PAGE_H
+
+#include <asm-generic/page.h>
+#include <linux/types.h>
+
+#define MAP_NR(addr) (((uintptr_t)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)
+#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#ifndef __ASSEMBLY__
+extern unsigned long rom_length;
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+extern unsigned long _ramend;
+#endif
+
+#endif
diff --git a/arch/h8300/include/asm/page_offset.h b/arch/h8300/include/asm/page_offset.h
new file mode 100644
index 000000000000..888576d7cc2a
--- /dev/null
+++ b/arch/h8300/include/asm/page_offset.h
@@ -0,0 +1,2 @@
+
+#define PAGE_OFFSET_RAW 0x00000000
diff --git a/arch/h8300/include/asm/pci.h b/arch/h8300/include/asm/pci.h
new file mode 100644
index 000000000000..0b2acaa3dd84
--- /dev/null
+++ b/arch/h8300/include/asm/pci.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_H8300_PCI_H
+#define _ASM_H8300_PCI_H
+
+/*
+ * asm-h8300/pci.h - H8/300 specific PCI declarations.
+ *
+ * Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#define pcibios_assign_all_busses() 0
+
+static inline void pcibios_penalize_isa_irq(int irq, int active)
+{
+ /* We don't do dynamic PCI IRQ allocation */
+}
+
+#define PCI_DMA_BUS_IS_PHYS (1)
+
+#endif /* _ASM_H8300_PCI_H */
diff --git a/arch/h8300/include/asm/pgtable.h b/arch/h8300/include/asm/pgtable.h
new file mode 100644
index 000000000000..8341db67821d
--- /dev/null
+++ b/arch/h8300/include/asm/pgtable.h
@@ -0,0 +1,49 @@
+#ifndef _H8300_PGTABLE_H
+#define _H8300_PGTABLE_H
+#include <asm-generic/pgtable-nopud.h>
+#include <asm-generic/pgtable.h>
+#define pgtable_cache_init() do { } while (0)
+extern void paging_init(void);
+#define PAGE_NONE __pgprot(0) /* these mean nothing to NO_MM */
+#define PAGE_SHARED __pgprot(0) /* these mean nothing to NO_MM */
+#define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */
+#define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */
+#define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */
+#define __swp_type(x) (0)
+#define __swp_offset(x) (0)
+#define __swp_entry(typ, off) ((swp_entry_t) { ((typ) | ((off) << 7)) })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
+#define kern_addr_valid(addr) (1)
+#define pgprot_writecombine(prot) (prot)
+#define pgprot_noncached pgprot_writecombine
+
+static inline int pte_file(pte_t pte) { return 0; }
+#define swapper_pg_dir ((pgd_t *) 0)
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+#define ZERO_PAGE(vaddr) (virt_to_page(0))
+
+/*
+ * These would be in other places but having them here reduces the diffs.
+ */
+extern unsigned int kobjsize(const void *objp);
+extern int is_in_rom(unsigned long);
+
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init() do { } while (0)
+
+/*
+ * All 32bit addresses are effectively valid for vmalloc...
+ * Sort of meaningless for non-VM targets.
+ */
+#define VMALLOC_START 0
+#define VMALLOC_END 0xffffffff
+
+#define arch_enter_lazy_cpu_mode() do {} while (0)
+
+#endif /* _H8300_PGTABLE_H */
diff --git a/arch/h8300/include/asm/processor.h b/arch/h8300/include/asm/processor.h
new file mode 100644
index 000000000000..54e3fd83c336
--- /dev/null
+++ b/arch/h8300/include/asm/processor.h
@@ -0,0 +1,144 @@
+/*
+ * include/asm-h8300/processor.h
+ *
+ * Copyright (C) 2002 Yoshinori Sato
+ *
+ * Based on: linux/asm-m68nommu/processor.h
+ *
+ * Copyright (C) 1995 Hamish Macdonald
+ */
+
+#ifndef __ASM_H8300_PROCESSOR_H
+#define __ASM_H8300_PROCESSOR_H
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l; })
+
+#include <linux/compiler.h>
+#include <asm/segment.h>
+#include <asm/ptrace.h>
+#include <asm/current.h>
+
+static inline unsigned long rdusp(void)
+{
+ extern unsigned int _sw_usp;
+
+ return _sw_usp;
+}
+
+static inline void wrusp(unsigned long usp)
+{
+ extern unsigned int _sw_usp;
+
+ _sw_usp = usp;
+}
+
+/*
+ * User space process size: 3.75GB. This is hardcoded into a few places,
+ * so don't change it unless you know what you are doing.
+ */
+#define TASK_SIZE (0xFFFFFFFFUL)
+
+#ifdef __KERNEL__
+#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
+#endif
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's. We won't be using it
+ */
+#define TASK_UNMAPPED_BASE 0
+
+struct thread_struct {
+ unsigned long ksp; /* kernel stack pointer */
+ unsigned long usp; /* user stack pointer */
+ unsigned long ccr; /* saved status register */
+ unsigned long esp0; /* points to SR of stack frame */
+ struct {
+ unsigned short *addr;
+ unsigned short inst;
+ } breakinfo;
+};
+
+#define INIT_THREAD { \
+ .ksp = sizeof(init_stack) + (unsigned long)init_stack, \
+ .usp = 0, \
+ .ccr = PS_S, \
+ .esp0 = 0, \
+ .breakinfo = { \
+ .addr = (unsigned short *)-1, \
+ .inst = 0 \
+ } \
+}
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ *
+ * pass the data segment into user programs if it exists,
+ * it can't hurt anything as far as I can tell
+ */
+#if defined(CONFIG_CPU_H8300H)
+#define start_thread(_regs, _pc, _usp) \
+do { \
+ (_regs)->pc = (_pc); \
+ (_regs)->ccr = 0x00; /* clear all flags */ \
+ (_regs)->er5 = current->mm->start_data; /* GOT base */ \
+ (_regs)->sp = ((unsigned long)(_usp)) - sizeof(unsigned long) * 3; \
+} while (0)
+#endif
+#if defined(CONFIG_CPU_H8S)
+#define start_thread(_regs, _pc, _usp) \
+do { \
+ (_regs)->pc = (_pc); \
+ (_regs)->ccr = 0x00; /* clear kernel flag */ \
+ (_regs)->exr = 0x78; /* enable all interrupts */ \
+ (_regs)->er5 = current->mm->start_data; /* GOT base */ \
+ /* 14 = space for retaddr(4), vector(4), er0(4) and exr(2) on stack */ \
+ (_regs)->sp = ((unsigned long)(_usp)) - 14; \
+} while (0)
+#endif
+
+/* Forward declaration, a strange C thing */
+struct task_struct;
+
+/* Free all resources held by a thread. */
+static inline void release_thread(struct task_struct *dead_task)
+{
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+static inline void exit_thread(void)
+{
+}
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+unsigned long thread_saved_pc(struct task_struct *tsk);
+unsigned long get_wchan(struct task_struct *p);
+
+#define KSTK_EIP(tsk) \
+ ({ \
+ unsigned long eip = 0; \
+ if ((tsk)->thread.esp0 > PAGE_SIZE && \
+ MAP_NR((tsk)->thread.esp0) < max_mapnr) \
+ eip = ((struct pt_regs *) (tsk)->thread.esp0)->pc; \
+ eip; })
+
+#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
+
+#define cpu_relax() barrier()
+#define cpu_relax_lowlatency() cpu_relax()
+
+#define HARD_RESET_NOW() ({ \
+ local_irq_disable(); \
+ asm("jmp @@0"); \
+})
+
+#endif
diff --git a/arch/h8300/include/asm/ptrace.h b/arch/h8300/include/asm/ptrace.h
new file mode 100644
index 000000000000..e693fb463ea8
--- /dev/null
+++ b/arch/h8300/include/asm/ptrace.h
@@ -0,0 +1,36 @@
+#ifndef _H8300_PTRACE_H
+#define _H8300_PTRACE_H
+
+#include <uapi/asm/ptrace.h>
+
+#ifndef __ASSEMBLY__
+#ifndef PS_S
+#define PS_S (0x10)
+#endif
+
+#if defined(CONFIG_CPU_H8300H)
+#define H8300_REGS_NO 11
+#endif
+#if defined(CONFIG_CPU_H8S)
+#define H8300_REGS_NO 12
+#endif
+
+#define arch_has_single_step() (1)
+
+#define user_mode(regs) (!((regs)->ccr & PS_S))
+#define instruction_pointer(regs) ((regs)->pc)
+#define profile_pc(regs) instruction_pointer(regs)
+#define user_stack_pointer(regs) ((regs)->sp)
+#define current_pt_regs() ((struct pt_regs *) \
+ (THREAD_SIZE + (unsigned long)current_thread_info()) - 1)
+#define signal_pt_regs() ((struct pt_regs *)current->thread.esp0)
+#define current_user_stack_pointer() rdusp()
+#define task_pt_regs(task) \
+ ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1)
+
+extern long h8300_get_reg(struct task_struct *task, int regno);
+extern int h8300_put_reg(struct task_struct *task, int regno,
+ unsigned long data);
+
+#endif /* __ASSEMBLY__ */
+#endif /* _H8300_PTRACE_H */
diff --git a/arch/h8300/include/asm/segment.h b/arch/h8300/include/asm/segment.h
new file mode 100644
index 000000000000..48424c6e169f
--- /dev/null
+++ b/arch/h8300/include/asm/segment.h
@@ -0,0 +1,45 @@
+#ifndef _H8300_SEGMENT_H
+#define _H8300_SEGMENT_H
+
+/* define constants */
+#define USER_DATA (1)
+#ifndef __USER_DS
+#define __USER_DS (USER_DATA)
+#endif
+#define USER_PROGRAM (2)
+#define SUPER_DATA (3)
+#ifndef __KERNEL_DS
+#define __KERNEL_DS (SUPER_DATA)
+#endif
+#define SUPER_PROGRAM (4)
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+ unsigned long seg;
+} mm_segment_t;
+
+#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
+#define USER_DS MAKE_MM_SEG(__USER_DS)
+#define KERNEL_DS MAKE_MM_SEG(__KERNEL_DS)
+
+/*
+ * Get/set the SFC/DFC registers for MOVES instructions
+ */
+
+static inline mm_segment_t get_fs(void)
+{
+ return USER_DS;
+}
+
+static inline mm_segment_t get_ds(void)
+{
+ /* return the supervisor data space code */
+ return KERNEL_DS;
+}
+
+#define segment_eq(a, b) ((a).seg == (b).seg)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _H8300_SEGMENT_H */
diff --git a/arch/h8300/include/asm/signal.h b/arch/h8300/include/asm/signal.h
new file mode 100644
index 000000000000..5870835c0470
--- /dev/null
+++ b/arch/h8300/include/asm/signal.h
@@ -0,0 +1,22 @@
+#ifndef _H8300_SIGNAL_H
+#define _H8300_SIGNAL_H
+
+#include <uapi/asm/signal.h>
+
+/* Most things should be clean enough to redefine this at will, if care
+ is taken to make libc match. */
+
+#define _NSIG 64
+#define _NSIG_BPW 32
+#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
+
+typedef unsigned long old_sigset_t; /* at least 32 bits */
+
+typedef struct {
+ unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#define __ARCH_HAS_SA_RESTORER
+#include <asm/sigcontext.h>
+
+#endif /* _H8300_SIGNAL_H */
diff --git a/arch/h8300/include/asm/smp.h b/arch/h8300/include/asm/smp.h
new file mode 100644
index 000000000000..9e9bd7e58922
--- /dev/null
+++ b/arch/h8300/include/asm/smp.h
@@ -0,0 +1 @@
+/* nothing required here yet */
diff --git a/arch/h8300/include/asm/string.h b/arch/h8300/include/asm/string.h
new file mode 100644
index 000000000000..5dc5a8ac0544
--- /dev/null
+++ b/arch/h8300/include/asm/string.h
@@ -0,0 +1,17 @@
+#ifndef _H8300_STRING_H_
+#define _H8300_STRING_H_
+
+#ifdef __KERNEL__ /* only set these up for kernel code */
+
+#include <asm/setup.h>
+#include <asm/page.h>
+
+#define __HAVE_ARCH_MEMSET
+extern void *memset(void *s, int c, size_t count);
+
+#define __HAVE_ARCH_MEMCPY
+extern void *memcpy(void *d, const void *s, size_t count);
+
+#endif /* KERNEL */
+
+#endif
diff --git a/arch/h8300/include/asm/switch_to.h b/arch/h8300/include/asm/switch_to.h
new file mode 100644
index 000000000000..7ad1bf92dbc3
--- /dev/null
+++ b/arch/h8300/include/asm/switch_to.h
@@ -0,0 +1,51 @@
+#ifndef _H8300_SWITCH_TO_H
+#define _H8300_SWITCH_TO_H
+
+/*
+ * switch_to(n) should switch tasks to task ptr, first checking that
+ * ptr isn't the current task, in which case it does nothing. This
+ * also clears the TS-flag if the task we switched to has used the
+ * math co-processor latest.
+ */
+/*
+ * switch_to() saves the extra registers, that are not saved
+ * automatically by SAVE_SWITCH_STACK in resume(), ie. d0-d5 and
+ * a0-a1. Some of these are used by schedule() and its predecessors
+ * and so we might get see unexpected behaviors when a task returns
+ * with unexpected register values.
+ *
+ * syscall stores these registers itself and none of them are used
+ * by syscall after the function in the syscall has been called.
+ *
+ * Beware that resume now expects *next to be in d1 and the offset of
+ * tss to be in a1. This saves a few instructions as we no longer have
+ * to push them onto the stack and read them back right after.
+ *
+ * 02/17/96 - Jes Sorensen (jds@kom.auc.dk)
+ *
+ * Changed 96/09/19 by Andreas Schwab
+ * pass prev in a0, next in a1, offset of tss in d1, and whether
+ * the mm structures are shared in d2 (to avoid atc flushing).
+ *
+ * H8/300 Porting 2002/09/04 Yoshinori Sato
+ */
+
+asmlinkage void resume(void);
+#define switch_to(prev, next, last) \
+do { \
+ void *_last; \
+ __asm__ __volatile__( \
+ "mov.l %1, er0\n\t" \
+ "mov.l %2, er1\n\t" \
+ "mov.l %3, er2\n\t" \
+ "jsr @_resume\n\t" \
+ "mov.l er2,%0\n\t" \
+ : "=r" (_last) \
+ : "r" (&(prev->thread)), \
+ "r" (&(next->thread)), \
+ "g" (prev) \
+ : "cc", "er0", "er1", "er2", "er3"); \
+ (last) = _last; \
+} while (0)
+
+#endif /* _H8300_SWITCH_TO_H */
diff --git a/arch/h8300/include/asm/syscall.h b/arch/h8300/include/asm/syscall.h
new file mode 100644
index 000000000000..b41f688d02cf
--- /dev/null
+++ b/arch/h8300/include/asm/syscall.h
@@ -0,0 +1,56 @@
+#ifndef __ASM_H8300_SYSCALLS_32_H
+#define __ASM_H8300_SYSCALLS_32_H
+
+#ifdef __KERNEL__
+
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+
+static inline int
+syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
+{
+ return regs->orig_er0;
+}
+
+static inline void
+syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
+ unsigned int i, unsigned int n, unsigned long *args)
+{
+ BUG_ON(i + n > 6);
+
+ while (n > 0) {
+ switch (i) {
+ case 0:
+ *args++ = regs->er1;
+ break;
+ case 1:
+ *args++ = regs->er2;
+ break;
+ case 2:
+ *args++ = regs->er3;
+ break;
+ case 3:
+ *args++ = regs->er4;
+ break;
+ case 4:
+ *args++ = regs->er5;
+ break;
+ case 5:
+ *args++ = regs->er6;
+ break;
+ }
+ i++;
+ n--;
+ }
+}
+
+
+
+/* Misc syscall related bits */
+asmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
+asmlinkage void do_syscall_trace_leave(struct pt_regs *regs);
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_H8300_SYSCALLS_32_H */
diff --git a/arch/h8300/include/asm/thread_info.h b/arch/h8300/include/asm/thread_info.h
new file mode 100644
index 000000000000..544c30785ad4
--- /dev/null
+++ b/arch/h8300/include/asm/thread_info.h
@@ -0,0 +1,111 @@
+/* thread_info.h: h8300 low-level thread information
+ * adapted from the i386 and PPC versions by Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * Copyright (C) 2002 David Howells (dhowells@redhat.com)
+ * - Incorporating suggestions made by Linus Torvalds and Dave Miller
+ */
+
+#ifndef _ASM_THREAD_INFO_H
+#define _ASM_THREAD_INFO_H
+
+#include <asm/page.h>
+#include <asm/segment.h>
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+/*
+ * low level task data.
+ * If you change this, change the TI_* offsets below to match.
+ */
+struct thread_info {
+ struct task_struct *task; /* main task structure */
+ unsigned long flags; /* low level flags */
+ int cpu; /* cpu we're on */
+ int preempt_count; /* 0 => preemptable, <0 => BUG */
+ mm_segment_t addr_limit;
+ struct restart_block restart_block;
+};
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ */
+#define INIT_THREAD_INFO(tsk) \
+{ \
+ .task = &tsk, \
+ .flags = 0, \
+ .cpu = 0, \
+ .preempt_count = INIT_PREEMPT_COUNT, \
+ .addr_limit = KERNEL_DS, \
+ .restart_block = { \
+ .fn = do_no_restart_syscall, \
+ }, \
+}
+
+#define init_thread_info (init_thread_union.thread_info)
+#define init_stack (init_thread_union.stack)
+
+
+/*
+ * Size of kernel stack for each process. This must be a power of 2...
+ */
+#define THREAD_SIZE_ORDER 1
+#define THREAD_SIZE 8192 /* 2 pages */
+
+
+/* how to get the thread information struct from C */
+static inline struct thread_info *current_thread_info(void)
+{
+ struct thread_info *ti;
+
+ __asm__("mov.l sp, %0\n\t"
+ "and.w %1, %T0"
+ : "=&r"(ti)
+ : "i" (~(THREAD_SIZE-1) & 0xffff));
+ return ti;
+}
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * thread information flag bit numbers
+ */
+#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
+#define TIF_SIGPENDING 1 /* signal pending */
+#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
+#define TIF_SINGLESTEP 3 /* singlestepping active */
+#define TIF_MEMDIE 4 /* is terminating due to OOM killer */
+#define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */
+#define TIF_NOTIFY_RESUME 6 /* callback before returning to user */
+#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
+#define TIF_SYSCALL_TRACEPOINT 8 /* for ftrace syscall instrumentation */
+#define TIF_POLLING_NRFLAG 9 /* true if poll_idle() is polling TIF_NEED_RESCHED */
+
+/* as above, but as bit values */
+#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
+#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
+#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
+#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
+#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
+#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
+#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
+
+/* work to do in syscall trace */
+#define _TIF_WORK_SYSCALL_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
+ _TIF_SYSCALL_AUDIT | _TIF_SYSCALL_TRACEPOINT)
+
+/* work to do on any return to u-space */
+#define _TIF_ALLWORK_MASK (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING | \
+ _TIF_NEED_RESCHED | _TIF_SYSCALL_AUDIT | \
+ _TIF_SINGLESTEP | _TIF_NOTIFY_RESUME | \
+ _TIF_SYSCALL_TRACEPOINT)
+
+/* work to do on interrupt/exception return */
+#define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \
+ _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP))
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/h8300/include/asm/tlb.h b/arch/h8300/include/asm/tlb.h
new file mode 100644
index 000000000000..2c6fa4eed448
--- /dev/null
+++ b/arch/h8300/include/asm/tlb.h
@@ -0,0 +1,8 @@
+#ifndef __H8300_TLB_H__
+#define __H8300_TLB_H__
+
+#define tlb_flush(tlb) do { } while (0)
+
+#include <asm-generic/tlb.h>
+
+#endif
diff --git a/arch/h8300/include/asm/traps.h b/arch/h8300/include/asm/traps.h
new file mode 100644
index 000000000000..aa34e75fd767
--- /dev/null
+++ b/arch/h8300/include/asm/traps.h
@@ -0,0 +1,41 @@
+/*
+ * linux/include/asm-h8300/traps.h
+ *
+ * Copyright (C) 2003 Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _H8300_TRAPS_H
+#define _H8300_TRAPS_H
+
+extern void _system_call(void);
+extern void _interrupt_entry(void);
+extern void _trace_break(void);
+extern void _nmi(void);
+extern void _interrupt_entry(void);
+
+extern unsigned long *_interrupt_redirect_table;
+
+#define JMP_OP 0x5a000000
+#define JSR_OP 0x5e000000
+#define VECTOR(address) ((JMP_OP)|((unsigned long)address))
+#define REDIRECT(address) ((JSR_OP)|((unsigned long)address))
+#define CPU_VECTOR ((unsigned long *)0x000000)
+#define ADDR_MASK (0xffffff)
+
+#define TRACE_VEC 5
+
+#define TRAP0_VEC 8
+#define TRAP1_VEC 9
+#define TRAP2_VEC 10
+#define TRAP3_VEC 11
+
+extern char _start, _etext;
+#define check_kernel_text(addr) \
+ ((addr >= (unsigned long)(&_start)) && \
+ (addr < (unsigned long)(&_etext)))
+
+#endif /* _H8300_TRAPS_H */
diff --git a/arch/h8300/include/asm/user.h b/arch/h8300/include/asm/user.h
new file mode 100644
index 000000000000..2e3555f451f0
--- /dev/null
+++ b/arch/h8300/include/asm/user.h
@@ -0,0 +1,74 @@
+#ifndef _H8300_USER_H
+#define _H8300_USER_H
+
+#include <asm/page.h>
+
+/* Core file format: The core file is written in such a way that gdb
+ can understand it and provide useful information to the user (under
+ linux we use the 'trad-core' bfd). There are quite a number of
+ obstacles to being able to view the contents of the floating point
+ registers, and until these are solved you will not be able to view the
+ contents of them. Actually, you can read in the core file and look at
+ the contents of the user struct to find out what the floating point
+ registers contain.
+ The actual file contents are as follows:
+ UPAGE: 1 page consisting of a user struct that tells gdb what is present
+ in the file. Directly after this is a copy of the task_struct, which
+ is currently not used by gdb, but it may come in useful at some point.
+ All of the registers are stored as part of the upage. The upage should
+ always be only one page.
+ DATA: The data area is stored. We use current->end_text to
+ current->brk to pick up all of the user variables, plus any memory
+ that may have been malloced. No attempt is made to determine if a page
+ is demand-zero or if a page is totally unused, we just cover the entire
+ range. All of the addresses are rounded in such a way that an integral
+ number of pages is written.
+ STACK: We need the stack information in order to get a meaningful
+ backtrace. We need to write the data from (esp) to
+ current->start_stack, so we round each of these off in order to be able
+ to write an integer number of pages.
+ The minimum core file size is 3 pages, or 12288 bytes.
+*/
+
+/* This is the old layout of "struct pt_regs" as of Linux 1.x, and
+ is still the layout used by user (the new pt_regs doesn't have
+ all registers). */
+struct user_regs_struct {
+ long er1, er2, er3, er4, er5, er6;
+ long er0;
+ long usp;
+ long orig_er0;
+ long ccr;
+ long pc;
+};
+
+/* When the kernel dumps core, it starts by dumping the user struct -
+ this will be used by gdb to figure out where the data and stack segments
+ are within the file, and what virtual addresses to use. */
+struct user {
+/* We start with the registers, to mimic the way that "memory" is returned
+ from the ptrace(3,...) function. */
+ struct user_regs_struct regs; /* Where the registers are actually stored */
+/* ptrace does not yet supply these. Someday.... */
+/* The rest of this junk is to help gdb figure out what goes where */
+ unsigned long int u_tsize; /* Text segment size (pages). */
+ unsigned long int u_dsize; /* Data segment size (pages). */
+ unsigned long int u_ssize; /* Stack segment size (pages). */
+ unsigned long start_code; /* Starting virtual address of text. */
+ unsigned long start_stack; /* Starting virtual address of stack area.
+ This is actually the bottom of the stack,
+ the top of the stack is always found in the
+ esp register. */
+ long int signal; /* Signal that caused the core dump. */
+ int reserved; /* No longer used */
+ unsigned long u_ar0; /* Used by gdb to help find the values for */
+ /* the registers. */
+ unsigned long magic; /* To uniquely identify a core file */
+ char u_comm[32]; /* User command that was responsible */
+};
+#define NBPG PAGE_SIZE
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
+#endif
diff --git a/arch/h8300/include/uapi/asm/Kbuild b/arch/h8300/include/uapi/asm/Kbuild
new file mode 100644
index 000000000000..fb6101a5d4f1
--- /dev/null
+++ b/arch/h8300/include/uapi/asm/Kbuild
@@ -0,0 +1,30 @@
+# UAPI Header export list
+include include/uapi/asm-generic/Kbuild.asm
+
+header-y += auxvec.h
+header-y += bitsperlong.h
+header-y += errno.h
+header-y += fcntl.h
+header-y += ioctl.h
+header-y += ioctls.h
+header-y += ipcbuf.h
+header-y += kvm_para.h
+header-y += mman.h
+header-y += msgbuf.h
+header-y += param.h
+header-y += poll.h
+header-y += posix_types.h
+header-y += resource.h
+header-y += sembuf.h
+header-y += setup.h
+header-y += shmbuf.h
+header-y += siginfo.h
+header-y += socket.h
+header-y += sockios.h
+header-y += stat.h
+header-y += statfs.h
+header-y += swab.h
+header-y += termbits.h
+header-y += termios.h
+header-y += types.h
+header-y += unistd.h
diff --git a/arch/h8300/include/uapi/asm/byteorder.h b/arch/h8300/include/uapi/asm/byteorder.h
new file mode 100644
index 000000000000..13539da99efd
--- /dev/null
+++ b/arch/h8300/include/uapi/asm/byteorder.h
@@ -0,0 +1,6 @@
+#ifndef _H8300_BYTEORDER_H
+#define _H8300_BYTEORDER_H
+
+#include <linux/byteorder/big_endian.h>
+
+#endif /* _H8300_BYTEORDER_H */
diff --git a/arch/h8300/include/uapi/asm/ptrace.h b/arch/h8300/include/uapi/asm/ptrace.h
new file mode 100644
index 000000000000..e132670d70ec
--- /dev/null
+++ b/arch/h8300/include/uapi/asm/ptrace.h
@@ -0,0 +1,42 @@
+#ifndef _UAPI_H8300_PTRACE_H
+#define _UAPI_H8300_PTRACE_H
+
+#ifndef __ASSEMBLY__
+
+#define PT_ER1 0
+#define PT_ER2 1
+#define PT_ER3 2
+#define PT_ER4 3
+#define PT_ER5 4
+#define PT_ER6 5
+#define PT_ER0 6
+#define PT_USP 7
+#define PT_ORIG_ER0 8
+#define PT_CCR 9
+#define PT_PC 10
+#define PT_EXR 11
+
+/* this struct defines the way the registers are stored on the
+ stack during a system call. */
+
+struct pt_regs {
+ long retpc;
+ long er4;
+ long er5;
+ long er6;
+ long er3;
+ long er2;
+ long er1;
+ long orig_er0;
+ long sp;
+ unsigned short ccr;
+ long er0;
+ long vector;
+#if defined(__H8300S__)
+ unsigned short exr;
+#endif
+ unsigned long pc;
+} __attribute__((aligned(2), packed));
+
+#endif /* __ASSEMBLY__ */
+#endif /* _UAPI_H8300_PTRACE_H */
diff --git a/arch/h8300/include/uapi/asm/sigcontext.h b/arch/h8300/include/uapi/asm/sigcontext.h
new file mode 100644
index 000000000000..c41fdaa04657
--- /dev/null
+++ b/arch/h8300/include/uapi/asm/sigcontext.h
@@ -0,0 +1,18 @@
+#ifndef _ASM_H8300_SIGCONTEXT_H
+#define _ASM_H8300_SIGCONTEXT_H
+
+struct sigcontext {
+ unsigned long sc_mask; /* old sigmask */
+ unsigned long sc_usp; /* old user stack pointer */
+ unsigned long sc_er0;
+ unsigned long sc_er1;
+ unsigned long sc_er2;
+ unsigned long sc_er3;
+ unsigned long sc_er4;
+ unsigned long sc_er5;
+ unsigned long sc_er6;
+ unsigned short sc_ccr;
+ unsigned long sc_pc;
+};
+
+#endif
diff --git a/arch/h8300/include/uapi/asm/signal.h b/arch/h8300/include/uapi/asm/signal.h
new file mode 100644
index 000000000000..af3a6c37fee6
--- /dev/null
+++ b/arch/h8300/include/uapi/asm/signal.h
@@ -0,0 +1,115 @@
+#ifndef _UAPI_H8300_SIGNAL_H
+#define _UAPI_H8300_SIGNAL_H
+
+#include <linux/types.h>
+
+/* Avoid too many header ordering problems. */
+struct siginfo;
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers. */
+
+#define NSIG 32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGIO 29
+#define SIGPOLL SIGIO
+/*
+#define SIGLOST 29
+*/
+#define SIGPWR 30
+#define SIGSYS 31
+#define SIGUNUSED 31
+
+/* These should not be considered constants from userland. */
+#define SIGRTMIN 32
+#define SIGRTMAX _NSIG
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP 0x00000001
+#define SA_NOCLDWAIT 0x00000002 /* not supported yet */
+#define SA_SIGINFO 0x00000004
+#define SA_ONSTACK 0x08000000
+#define SA_RESTART 0x10000000
+#define SA_NODEFER 0x40000000
+#define SA_RESETHAND 0x80000000
+
+#define SA_NOMASK SA_NODEFER
+#define SA_ONESHOT SA_RESETHAND
+
+#define SA_RESTORER 0x04000000
+
+#define MINSIGSTKSZ 2048
+#define SIGSTKSZ 8192
+
+#include <asm-generic/signal-defs.h>
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers. */
+
+struct sigaction {
+ union {
+ __sighandler_t _sa_handler;
+ void (*_sa_sigaction)(int, struct siginfo *, void *);
+ } _u;
+ sigset_t sa_mask;
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+};
+
+#define sa_handler _u._sa_handler
+#define sa_sigaction _u._sa_sigaction
+
+#endif /* __KERNEL__ */
+
+typedef struct sigaltstack {
+ void *ss_sp;
+ int ss_flags;
+ size_t ss_size;
+} stack_t;
+
+
+#endif /* _UAPI_H8300_SIGNAL_H */
diff --git a/arch/h8300/include/uapi/asm/unistd.h b/arch/h8300/include/uapi/asm/unistd.h
new file mode 100644
index 000000000000..7a2eb698def3
--- /dev/null
+++ b/arch/h8300/include/uapi/asm/unistd.h
@@ -0,0 +1,3 @@
+#define __ARCH_NOMMU
+
+#include <asm-generic/unistd.h>
diff --git a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile
new file mode 100644
index 000000000000..5bc33f2fcc08
--- /dev/null
+++ b/arch/h8300/kernel/Makefile
@@ -0,0 +1,19 @@
+#
+# Makefile for the linux kernel.
+#
+
+extra-y := vmlinux.lds
+
+obj-y := process.o traps.o ptrace.o \
+ signal.o setup.o syscalls.o \
+ irq.o entry.o dma.o
+
+obj-$(CONFIG_ROMKERNEL) += head_rom.o
+obj-$(CONFIG_RAMKERNEL) += head_ram.o
+
+obj-$(CONFIG_MODULES) += module.o h8300_ksyms.o
+obj-$(CONFIG_H8300H_SIM) += sim-console.o
+obj-$(CONFIG_H8S_SIM) += sim-console.o
+
+obj-$(CONFIG_CPU_H8300H) += ptrace_h.o
+obj-$(CONFIG_CPU_H8S) += ptrace_s.o
diff --git a/arch/h8300/kernel/asm-offsets.c b/arch/h8300/kernel/asm-offsets.c
new file mode 100644
index 000000000000..dc2d16ce8a0d
--- /dev/null
+++ b/arch/h8300/kernel/asm-offsets.c
@@ -0,0 +1,67 @@
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/ptrace.h>
+#include <linux/hardirq.h>
+#include <linux/kbuild.h>
+#include <asm/irq.h>
+#include <asm/ptrace.h>
+
+int main(void)
+{
+ /* offsets into the task struct */
+ OFFSET(TASK_STATE, task_struct, state);
+ OFFSET(TASK_FLAGS, task_struct, flags);
+ OFFSET(TASK_PTRACE, task_struct, ptrace);
+ OFFSET(TASK_BLOCKED, task_struct, blocked);
+ OFFSET(TASK_THREAD, task_struct, thread);
+ OFFSET(TASK_THREAD_INFO, task_struct, stack);
+ OFFSET(TASK_MM, task_struct, mm);
+ OFFSET(TASK_ACTIVE_MM, task_struct, active_mm);
+
+ /* offsets into the irq_cpustat_t struct */
+ DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t,
+ __softirq_pending));
+
+ /* offsets into the thread struct */
+ OFFSET(THREAD_KSP, thread_struct, ksp);
+ OFFSET(THREAD_USP, thread_struct, usp);
+ OFFSET(THREAD_CCR, thread_struct, ccr);
+
+ /* offsets into the pt_regs struct */
+ DEFINE(LER0, offsetof(struct pt_regs, er0) - sizeof(long));
+ DEFINE(LER1, offsetof(struct pt_regs, er1) - sizeof(long));
+ DEFINE(LER2, offsetof(struct pt_regs, er2) - sizeof(long));
+ DEFINE(LER3, offsetof(struct pt_regs, er3) - sizeof(long));
+ DEFINE(LER4, offsetof(struct pt_regs, er4) - sizeof(long));
+ DEFINE(LER5, offsetof(struct pt_regs, er5) - sizeof(long));
+ DEFINE(LER6, offsetof(struct pt_regs, er6) - sizeof(long));
+ DEFINE(LORIG, offsetof(struct pt_regs, orig_er0) - sizeof(long));
+ DEFINE(LSP, offsetof(struct pt_regs, sp) - sizeof(long));
+ DEFINE(LCCR, offsetof(struct pt_regs, ccr) - sizeof(long));
+ DEFINE(LVEC, offsetof(struct pt_regs, vector) - sizeof(long));
+#if defined(CONFIG_CPU_H8S)
+ DEFINE(LEXR, offsetof(struct pt_regs, exr) - sizeof(long));
+#endif
+ DEFINE(LRET, offsetof(struct pt_regs, pc) - sizeof(long));
+
+ DEFINE(PT_PTRACED, PT_PTRACED);
+
+ /* offsets in thread_info structure */
+ OFFSET(TI_TASK, thread_info, task);
+ OFFSET(TI_FLAGS, thread_info, flags);
+ OFFSET(TI_CPU, thread_info, cpu);
+ OFFSET(TI_PRE, thread_info, preempt_count);
+
+ return 0;
+}
diff --git a/arch/h8300/kernel/dma.c b/arch/h8300/kernel/dma.c
new file mode 100644
index 000000000000..eeb13d3f2424
--- /dev/null
+++ b/arch/h8300/kernel/dma.c
@@ -0,0 +1,69 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/scatterlist.h>
+#include <linux/module.h>
+#include <asm/pgalloc.h>
+
+static void *dma_alloc(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp,
+ struct dma_attrs *attrs)
+{
+ void *ret;
+
+ /* ignore region specifiers */
+ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
+
+ if (dev == NULL || (*dev->dma_mask < 0xffffffff))
+ gfp |= GFP_DMA;
+ ret = (void *)__get_free_pages(gfp, get_order(size));
+
+ if (ret != NULL) {
+ memset(ret, 0, size);
+ *dma_handle = virt_to_phys(ret);
+ }
+ return ret;
+}
+
+static void dma_free(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
+
+{
+ free_pages((unsigned long)vaddr, get_order(size));
+}
+
+static dma_addr_t map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+ return page_to_phys(page) + offset;
+}
+
+static int map_sg(struct device *dev, struct scatterlist *sgl,
+ int nents, enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(sgl, sg, nents, i) {
+ sg->dma_address = sg_phys(sg);
+ }
+
+ return nents;
+}
+
+struct dma_map_ops h8300_dma_map_ops = {
+ .alloc = dma_alloc,
+ .free = dma_free,
+ .map_page = map_page,
+ .map_sg = map_sg,
+};
+EXPORT_SYMBOL(h8300_dma_map_ops);
diff --git a/arch/h8300/kernel/entry.S b/arch/h8300/kernel/entry.S
new file mode 100644
index 000000000000..797dfa8ddeb2
--- /dev/null
+++ b/arch/h8300/kernel/entry.S
@@ -0,0 +1,414 @@
+/*
+ *
+ * linux/arch/h8300/kernel/entry.S
+ *
+ * Yoshinori Sato <ysato@users.sourceforge.jp>
+ * David McCullough <davidm@snapgear.com>
+ *
+ */
+
+/*
+ * entry.S
+ * include exception/interrupt gateway
+ * system call entry
+ */
+
+#include <linux/sys.h>
+#include <asm/unistd.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/errno.h>
+
+#if defined(CONFIG_CPU_H8300H)
+#define USERRET 8
+INTERRUPTS = 64
+ .h8300h
+ .macro SHLL2 reg
+ shll.l \reg
+ shll.l \reg
+ .endm
+ .macro SHLR2 reg
+ shlr.l \reg
+ shlr.l \reg
+ .endm
+ .macro SAVEREGS
+ mov.l er0,@-sp
+ mov.l er1,@-sp
+ mov.l er2,@-sp
+ mov.l er3,@-sp
+ .endm
+ .macro RESTOREREGS
+ mov.l @sp+,er3
+ mov.l @sp+,er2
+ .endm
+ .macro SAVEEXR
+ .endm
+ .macro RESTOREEXR
+ .endm
+#endif
+#if defined(CONFIG_CPU_H8S)
+#define USERRET 10
+#define USEREXR 8
+INTERRUPTS = 128
+ .h8300s
+ .macro SHLL2 reg
+ shll.l #2,\reg
+ .endm
+ .macro SHLR2 reg
+ shlr.l #2,\reg
+ .endm
+ .macro SAVEREGS
+ stm.l er0-er3,@-sp
+ .endm
+ .macro RESTOREREGS
+ ldm.l @sp+,er2-er3
+ .endm
+ .macro SAVEEXR
+ mov.w @(USEREXR:16,er0),r1
+ mov.w r1,@(LEXR-LER3:16,sp) /* copy EXR */
+ .endm
+ .macro RESTOREEXR
+ mov.w @(LEXR-LER1:16,sp),r1 /* restore EXR */
+ mov.b r1l,r1h
+ mov.w r1,@(USEREXR:16,er0)
+ .endm
+#endif
+
+
+/* CPU context save/restore macros. */
+
+ .macro SAVE_ALL
+ mov.l er0,@-sp
+ stc ccr,r0l /* check kernel mode */
+ btst #4,r0l
+ bne 5f
+
+ /* user mode */
+ mov.l sp,@_sw_usp
+ mov.l @sp,er0 /* restore saved er0 */
+ orc #0x10,ccr /* switch kernel stack */
+ mov.l @_sw_ksp,sp
+ sub.l #(LRET-LORIG),sp /* allocate LORIG - LRET */
+ SAVEREGS
+ mov.l @_sw_usp,er0
+ mov.l @(USERRET:16,er0),er1 /* copy the RET addr */
+ mov.l er1,@(LRET-LER3:16,sp)
+ SAVEEXR
+
+ mov.l @(LORIG-LER3:16,sp),er0
+ mov.l er0,@(LER0-LER3:16,sp) /* copy ER0 */
+ mov.w e1,r1 /* e1 highbyte = ccr */
+ and #0xef,r1h /* mask mode? flag */
+ bra 6f
+5:
+ /* kernel mode */
+ mov.l @sp,er0 /* restore saved er0 */
+ subs #2,sp /* set dummy ccr */
+ subs #4,sp /* set dummp sp */
+ SAVEREGS
+ mov.w @(LRET-LER3:16,sp),r1 /* copy old ccr */
+6:
+ mov.b r1h,r1l
+ mov.b #0,r1h
+ mov.w r1,@(LCCR-LER3:16,sp) /* set ccr */
+ mov.l @_sw_usp,er2
+ mov.l er2,@(LSP-LER3:16,sp) /* set usp */
+ mov.l er6,@-sp /* syscall arg #6 */
+ mov.l er5,@-sp /* syscall arg #5 */
+ mov.l er4,@-sp /* syscall arg #4 */
+ .endm /* r1 = ccr */
+
+ .macro RESTORE_ALL
+ mov.l @sp+,er4
+ mov.l @sp+,er5
+ mov.l @sp+,er6
+ RESTOREREGS
+ mov.w @(LCCR-LER1:16,sp),r0 /* check kernel mode */
+ btst #4,r0l
+ bne 7f
+
+ orc #0xc0,ccr
+ mov.l @(LSP-LER1:16,sp),er0
+ mov.l @(LER0-LER1:16,sp),er1 /* restore ER0 */
+ mov.l er1,@er0
+ RESTOREEXR
+ mov.w @(LCCR-LER1:16,sp),r1 /* restore the RET addr */
+ mov.b r1l,r1h
+ mov.b @(LRET+1-LER1:16,sp),r1l
+ mov.w r1,e1
+ mov.w @(LRET+2-LER1:16,sp),r1
+ mov.l er1,@(USERRET:16,er0)
+
+ mov.l @sp+,er1
+ add.l #(LRET-LER1),sp /* remove LORIG - LRET */
+ mov.l sp,@_sw_ksp
+ andc #0xef,ccr /* switch to user mode */
+ mov.l er0,sp
+ bra 8f
+7:
+ mov.l @sp+,er1
+ add.l #10,sp
+8:
+ mov.l @sp+,er0
+ adds #4,sp /* remove the sw created LVEC */
+ rte
+ .endm
+
+.globl _system_call
+.globl ret_from_exception
+.globl ret_from_fork
+.globl ret_from_kernel_thread
+.globl ret_from_interrupt
+.globl _interrupt_redirect_table
+.globl _sw_ksp,_sw_usp
+.globl _resume
+.globl _interrupt_entry
+.globl _trace_break
+.globl _nmi
+
+#if defined(CONFIG_ROMKERNEL)
+ .section .int_redirect,"ax"
+_interrupt_redirect_table:
+#if defined(CONFIG_CPU_H8300H)
+ .rept 7
+ .long 0
+ .endr
+#endif
+#if defined(CONFIG_CPU_H8S)
+ .rept 5
+ .long 0
+ .endr
+ jmp @_trace_break
+ .long 0
+#endif
+
+ jsr @_interrupt_entry /* NMI */
+ jmp @_system_call /* TRAPA #0 (System call) */
+ .long 0
+ .long 0
+ jmp @_trace_break /* TRAPA #3 (breakpoint) */
+ .rept INTERRUPTS-12
+ jsr @_interrupt_entry
+ .endr
+#endif
+#if defined(CONFIG_RAMKERNEL)
+.globl _interrupt_redirect_table
+ .section .bss
+_interrupt_redirect_table:
+ .space 4
+#endif
+
+ .section .text
+ .align 2
+_interrupt_entry:
+ SAVE_ALL
+/* r1l is saved ccr */
+ mov.l sp,er0
+ add.l #LVEC,er0
+ btst #4,r1l
+ bne 1f
+ /* user LVEC */
+ mov.l @_sw_usp,er0
+ adds #4,er0
+1:
+ mov.l @er0,er0 /* LVEC address */
+#if defined(CONFIG_ROMKERNEL)
+ sub.l #_interrupt_redirect_table,er0
+#endif
+#if defined(CONFIG_RAMKERNEL)
+ mov.l @_interrupt_redirect_table,er1
+ sub.l er1,er0
+#endif
+ SHLR2 er0
+ dec.l #1,er0
+ mov.l sp,er1
+ subs #4,er1 /* adjust ret_pc */
+#if defined(CONFIG_CPU_H8S)
+ orc #7,exr
+#endif
+ jsr @do_IRQ
+ jmp @ret_from_interrupt
+
+_system_call:
+ subs #4,sp /* dummy LVEC */
+ SAVE_ALL
+ /* er0: syscall nr */
+ andc #0xbf,ccr
+ mov.l er0,er4
+
+ /* save top of frame */
+ mov.l sp,er0
+ jsr @set_esp0
+ mov.l sp,er2
+ and.w #0xe000,r2
+ mov.l @(TI_FLAGS:16,er2),er2
+ and.w #_TIF_WORK_SYSCALL_MASK,r2
+ beq 1f
+ mov.l sp,er0
+ jsr @do_syscall_trace_enter
+1:
+ cmp.l #__NR_syscalls,er4
+ bcc badsys
+ SHLL2 er4
+ mov.l #_sys_call_table,er0
+ add.l er4,er0
+ mov.l @er0,er4
+ beq ret_from_exception:16
+ mov.l @(LER1:16,sp),er0
+ mov.l @(LER2:16,sp),er1
+ mov.l @(LER3:16,sp),er2
+ jsr @er4
+ mov.l er0,@(LER0:16,sp) /* save the return value */
+ mov.l sp,er2
+ and.w #0xe000,r2
+ mov.l @(TI_FLAGS:16,er2),er2
+ and.w #_TIF_WORK_SYSCALL_MASK,r2
+ beq 2f
+ mov.l sp,er0
+ jsr @do_syscall_trace_leave
+2:
+ orc #0xc0,ccr
+ bra resume_userspace
+
+badsys:
+ mov.l #-ENOSYS,er0
+ mov.l er0,@(LER0:16,sp)
+ bra resume_userspace
+
+#if !defined(CONFIG_PREEMPT)
+#define resume_kernel restore_all
+#endif
+
+ret_from_exception:
+#if defined(CONFIG_PREEMPT)
+ orc #0xc0,ccr
+#endif
+ret_from_interrupt:
+ mov.b @(LCCR+1:16,sp),r0l
+ btst #4,r0l
+ bne resume_kernel:16 /* return from kernel */
+resume_userspace:
+ andc #0xbf,ccr
+ mov.l sp,er4
+ and.w #0xe000,r4 /* er4 <- current thread info */
+ mov.l @(TI_FLAGS:16,er4),er1
+ and.l #_TIF_WORK_MASK,er1
+ beq restore_all:8
+work_pending:
+ btst #TIF_NEED_RESCHED,r1l
+ bne work_resched:8
+ /* work notifysig */
+ mov.l sp,er0
+ subs #4,er0 /* er0: pt_regs */
+ jsr @do_notify_resume
+ bra resume_userspace:8
+work_resched:
+ mov.l sp,er0
+ jsr @set_esp0
+ jsr @schedule
+ bra resume_userspace:8
+restore_all:
+ RESTORE_ALL /* Does RTE */
+
+#if defined(CONFIG_PREEMPT)
+resume_kernel:
+ mov.l @(TI_PRE_COUNT:16,er4),er0
+ bne restore_all:8
+need_resched:
+ mov.l @(TI_FLAGS:16,er4),er0
+ btst #TIF_NEED_RESCHED,r0l
+ beq restore_all:8
+ mov.b @(LCCR+1:16,sp),r0l /* Interrupt Enabled? */
+ bmi restore_all:8
+ mov.l sp,er0
+ jsr @set_esp0
+ jsr @preempt_schedule_irq
+ bra need_resched:8
+#endif
+
+ret_from_fork:
+ mov.l er2,er0
+ jsr @schedule_tail
+ jmp @ret_from_exception
+
+ret_from_kernel_thread:
+ mov.l er2,er0
+ jsr @schedule_tail
+ mov.l @(LER4:16,sp),er0
+ mov.l @(LER5:16,sp),er1
+ jsr @er1
+ jmp @ret_from_exception
+
+_resume:
+ /*
+ * Beware - when entering resume, offset of tss is in d1,
+ * prev (the current task) is in a0, next (the new task)
+ * is in a1 and d2.b is non-zero if the mm structure is
+ * shared between the tasks, so don't change these
+ * registers until their contents are no longer needed.
+ */
+
+ /* save sr */
+ sub.w r3,r3
+ stc ccr,r3l
+ mov.w r3,@(THREAD_CCR+2:16,er0)
+
+ /* disable interrupts */
+ orc #0xc0,ccr
+ mov.l @_sw_usp,er3
+ mov.l er3,@(THREAD_USP:16,er0)
+ mov.l sp,@(THREAD_KSP:16,er0)
+
+ /* Skip address space switching if they are the same. */
+ /* FIXME: what did we hack out of here, this does nothing! */
+
+ mov.l @(THREAD_USP:16,er1),er0
+ mov.l er0,@_sw_usp
+ mov.l @(THREAD_KSP:16,er1),sp
+
+ /* restore status register */
+ mov.w @(THREAD_CCR+2:16,er1),r3
+
+ ldc r3l,ccr
+ rts
+
+_trace_break:
+ subs #4,sp
+ SAVE_ALL
+ sub.l er1,er1
+ dec.l #1,er1
+ mov.l er1,@(LORIG,sp)
+ mov.l sp,er0
+ jsr @set_esp0
+ mov.l @_sw_usp,er0
+ mov.l @er0,er1
+ mov.w @(-2:16,er1),r2
+ cmp.w #0x5730,r2
+ beq 1f
+ subs #2,er1
+ mov.l er1,@er0
+1:
+ and.w #0xff,e1
+ mov.l er1,er0
+ jsr @trace_trap
+ jmp @ret_from_exception
+
+_nmi:
+ subs #4, sp
+ mov.l er0, @-sp
+ mov.l @_interrupt_redirect_table, er0
+ add.l #8*4, er0
+ mov.l er0, @(4,sp)
+ mov.l @sp+, er0
+ jmp @_interrupt_entry
+
+ .section .bss
+_sw_ksp:
+ .space 4
+_sw_usp:
+ .space 4
+
+ .end
diff --git a/arch/h8300/kernel/h8300_ksyms.c b/arch/h8300/kernel/h8300_ksyms.c
new file mode 100644
index 000000000000..a9033c838968
--- /dev/null
+++ b/arch/h8300/kernel/h8300_ksyms.c
@@ -0,0 +1,36 @@
+#include <linux/module.h>
+#include <linux/linkage.h>
+
+/*
+ * libgcc functions - functions that are used internally by the
+ * compiler... (prototypes are not correct though, but that
+ * doesn't really matter since they're not versioned).
+ */
+asmlinkage long __ucmpdi2(long long, long long);
+asmlinkage long long __ashldi3(long long, int);
+asmlinkage long long __ashrdi3(long long, int);
+asmlinkage long long __lshrdi3(long long, int);
+asmlinkage long __divsi3(long, long);
+asmlinkage long __modsi3(long, long);
+asmlinkage unsigned long __umodsi3(unsigned long, unsigned long);
+asmlinkage long long __muldi3(long long, long long);
+asmlinkage long __mulsi3(long, long);
+asmlinkage long __udivsi3(long, long);
+asmlinkage void *memcpy(void *, const void *, size_t);
+asmlinkage void *memset(void *, int, size_t);
+asmlinkage long strncpy_from_user(void *to, void *from, size_t n);
+
+ /* gcc lib functions */
+EXPORT_SYMBOL(__ucmpdi2);
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__umodsi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__mulsi3);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(strncpy_from_user);
diff --git a/arch/h8300/kernel/head_ram.S b/arch/h8300/kernel/head_ram.S
new file mode 100644
index 000000000000..84ac5c3ed31a
--- /dev/null
+++ b/arch/h8300/kernel/head_ram.S
@@ -0,0 +1,60 @@
+
+#include <linux/sys.h>
+#include <linux/init.h>
+#include <asm/unistd.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/errno.h>
+
+#if defined(CONFIG_CPU_H8300H)
+ .h8300h
+#define SYSCR 0xfee012
+#define IRAMTOP 0xffff20
+#endif
+#if defined(CONFIG_CPU_H8S)
+ .h8300s
+#define INTCR 0xffff31
+#define IRAMTOP 0xffc000
+#endif
+
+ __HEAD
+ .global _start
+_start:
+ mov.l #IRAMTOP,sp
+ /* .bss clear */
+ mov.l #_sbss,er5
+ mov.l #_ebss,er4
+ sub.l er5,er4
+ shlr er4
+ shlr er4
+ sub.l er2,er2
+1:
+ mov.l er2,@er5
+ adds #4,er5
+ dec.l #1,er4
+ bne 1b
+ jsr @h8300_fdt_init
+
+ /* linux kernel start */
+#if defined(CONFIG_CPU_H8300H)
+ ldc #0xd0,ccr /* running kernel */
+ mov.l #SYSCR,er0
+ bclr #3,@er0
+#endif
+#if defined(CONFIG_CPU_H8S)
+ ldc #0x07,exr
+ bclr #4,@INTCR:8
+ bset #5,@INTCR:8 /* Interrupt mode 2 */
+ ldc #0x90,ccr /* running kernel */
+#endif
+ mov.l #init_thread_union,sp
+ add.l #0x2000,sp
+ jsr @start_kernel
+
+1:
+ bra 1b
+
+ .end
diff --git a/arch/h8300/kernel/head_rom.S b/arch/h8300/kernel/head_rom.S
new file mode 100644
index 000000000000..9868a4121a1f
--- /dev/null
+++ b/arch/h8300/kernel/head_rom.S
@@ -0,0 +1,110 @@
+#include <linux/init.h>
+#include <asm/thread_info.h>
+
+#if defined(CONFIG_CPU_H8300H)
+ .h8300h
+#define SYSCR 0xfee012
+#define IRAMTOP 0xffff20
+#define NR_INT 64
+#endif
+#if defined(CONFIG_CPU_H8S)
+ .h8300s
+#define INTCR 0xffff31
+#define IRAMTOP 0xffc000
+#define NR_INT 128
+#endif
+
+ __HEAD
+ .global _start
+_start:
+ mov.l #IRAMTOP,sp
+#if !defined(CONFIG_H8300H_SIM) && \
+ !defined(CONFIG_H8S_SIM)
+ jsr @lowlevel_init
+
+ /* copy .data */
+ mov.l #_begin_data,er5
+ mov.l #_sdata,er6
+ mov.l #_edata,er4
+ sub.l er6,er4
+ shlr.l er4
+ shlr.l er4
+1:
+ mov.l @er5+,er0
+ mov.l er0,@er6
+ adds #4,er6
+ dec.l #1,er4
+ bne 1b
+ /* .bss clear */
+ mov.l #_sbss,er5
+ mov.l #_ebss,er4
+ sub.l er5,er4
+ shlr er4
+ shlr er4
+ sub.l er0,er0
+1:
+ mov.l er0,@er5
+ adds #4,er5
+ dec.l #1,er4
+ bne 1b
+#else
+ /* get cmdline from gdb */
+ jsr @0xcc
+ ;; er0 - argc
+ ;; er1 - argv
+ mov.l #command_line,er3
+ adds #4,er1
+ dec.l #1,er0
+ beq 4f
+1:
+ mov.l @er1+,er2
+2:
+ mov.b @er2+,r4l
+ beq 3f
+ mov.b r4l,@er3
+ adds #1,er3
+ bra 2b
+3:
+ mov.b #' ',r4l
+ mov.b r4l,@er3
+ adds #1,er3
+ dec.l #1,er0
+ bne 1b
+ subs #1,er3
+ mov.b #0,r4l
+ mov.b r4l,@er3
+4:
+#endif
+ sub.l er0,er0
+ jsr @h8300_fdt_init
+ /* linux kernel start */
+#if defined(CONFIG_CPU_H8300H)
+ ldc #0xd0,ccr /* running kernel */
+ mov.l #SYSCR,er0
+ bclr #3,@er0
+#endif
+#if defined(CONFIG_CPU_H8S)
+ ldc #0x07,exr
+ bclr #4,@INTCR:8
+ bset #5,@INTCR:8 /* Interrupt mode 2 */
+ ldc #0x90,ccr /* running kernel */
+#endif
+ mov.l #init_thread_union,sp
+ add.l #0x2000,sp
+ jsr @start_kernel
+
+1:
+ bra 1b
+
+#if defined(CONFIG_ROMKERNEL)
+ /* interrupt vector */
+ .section .vectors,"ax"
+ .long _start
+ .long _start
+vector = 2
+ .rept NR_INT - 2
+ .long _interrupt_redirect_table+vector*4
+vector = vector + 1
+ .endr
+#endif
+ .end
diff --git a/arch/h8300/kernel/irq.c b/arch/h8300/kernel/irq.c
new file mode 100644
index 000000000000..da79f9521699
--- /dev/null
+++ b/arch/h8300/kernel/irq.c
@@ -0,0 +1,97 @@
+/*
+ * linux/arch/h8300/kernel/irq.c
+ *
+ * Copyright 2014-2015 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <asm/traps.h>
+
+#ifdef CONFIG_RAMKERNEL
+typedef void (*h8300_vector)(void);
+
+static const h8300_vector __initconst trap_table[] = {
+ 0, 0, 0, 0,
+ _trace_break,
+ 0, 0,
+ _nmi,
+ _system_call,
+ 0, 0,
+ _trace_break,
+};
+
+static unsigned long __init *get_vector_address(void)
+{
+ unsigned long *rom_vector = CPU_VECTOR;
+ unsigned long base, tmp;
+ int vec_no;
+
+ base = rom_vector[EXT_IRQ0] & ADDR_MASK;
+
+ /* check romvector format */
+ for (vec_no = EXT_IRQ0 + 1; vec_no <= EXT_IRQ0+EXT_IRQS; vec_no++) {
+ if ((base+(vec_no - EXT_IRQ0)*4) !=
+ (rom_vector[vec_no] & ADDR_MASK))
+ return NULL;
+ }
+
+ /* ramvector base address */
+ base -= EXT_IRQ0*4;
+
+ /* writerble? */
+ tmp = ~(*(volatile unsigned long *)base);
+ (*(volatile unsigned long *)base) = tmp;
+ if ((*(volatile unsigned long *)base) != tmp)
+ return NULL;
+ return (unsigned long *)base;
+}
+
+static void __init setup_vector(void)
+{
+ int i;
+ unsigned long *ramvec, *ramvec_p;
+ const h8300_vector *trap_entry;
+
+ ramvec = get_vector_address();
+ if (ramvec == NULL)
+ panic("interrupt vector serup failed.");
+ else
+ pr_debug("virtual vector at 0x%p\n", ramvec);
+
+ /* create redirect table */
+ ramvec_p = ramvec;
+ trap_entry = trap_table;
+ for (i = 0; i < NR_IRQS; i++) {
+ if (i < 12) {
+ if (*trap_entry)
+ *ramvec_p = VECTOR(*trap_entry);
+ ramvec_p++;
+ trap_entry++;
+ } else
+ *ramvec_p++ = REDIRECT(_interrupt_entry);
+ }
+ _interrupt_redirect_table = ramvec;
+}
+#else
+void setup_vector(void)
+{
+ /* noting do */
+}
+#endif
+
+void __init init_IRQ(void)
+{
+ setup_vector();
+ irqchip_init();
+}
+
+asmlinkage void do_IRQ(int irq)
+{
+ irq_enter();
+ generic_handle_irq(irq);
+ irq_exit();
+}
diff --git a/arch/h8300/kernel/module.c b/arch/h8300/kernel/module.c
new file mode 100644
index 000000000000..515f6c4e8d80
--- /dev/null
+++ b/arch/h8300/kernel/module.c
@@ -0,0 +1,70 @@
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+ const char *strtab,
+ unsigned int symindex,
+ unsigned int relsec,
+ struct module *me)
+{
+ unsigned int i;
+ Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
+
+ pr_debug("Applying relocate section %u to %u\n", relsec,
+ sechdrs[relsec].sh_info);
+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
+ /* This is where to make the change */
+ uint32_t *loc =
+ (uint32_t *)(sechdrs[sechdrs[relsec].sh_info].sh_addr
+ + rela[i].r_offset);
+ /* This is the symbol it is referring to. Note that all
+ undefined symbols have been resolved. */
+ Elf32_Sym *sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ + ELF32_R_SYM(rela[i].r_info);
+ uint32_t v = sym->st_value + rela[i].r_addend;
+
+ switch (ELF32_R_TYPE(rela[i].r_info)) {
+ case R_H8_DIR24R8:
+ loc = (uint32_t *)((uint32_t)loc - 1);
+ *loc = (*loc & 0xff000000) | ((*loc & 0xffffff) + v);
+ break;
+ case R_H8_DIR24A8:
+ if (ELF32_R_SYM(rela[i].r_info))
+ *loc += v;
+ break;
+ case R_H8_DIR32:
+ case R_H8_DIR32A16:
+ *loc += v;
+ break;
+ case R_H8_PCREL16:
+ v -= (unsigned long)loc + 2;
+ if ((Elf32_Sword)v > 0x7fff ||
+ (Elf32_Sword)v < -(Elf32_Sword)0x8000)
+ goto overflow;
+ else
+ *(unsigned short *)loc = v;
+ break;
+ case R_H8_PCREL8:
+ v -= (unsigned long)loc + 1;
+ if ((Elf32_Sword)v > 0x7f ||
+ (Elf32_Sword)v < -(Elf32_Sword)0x80)
+ goto overflow;
+ else
+ *(unsigned char *)loc = v;
+ break;
+ default:
+ pr_err("module %s: Unknown relocation: %u\n",
+ me->name, ELF32_R_TYPE(rela[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+ return 0;
+ overflow:
+ pr_err("module %s: relocation offset overflow: %08x\n",
+ me->name, rela[i].r_offset);
+ return -ENOEXEC;
+}
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
new file mode 100644
index 000000000000..dee41256922c
--- /dev/null
+++ b/arch/h8300/kernel/process.c
@@ -0,0 +1,171 @@
+/*
+ * linux/arch/h8300/kernel/process.c
+ *
+ * Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * Based on:
+ *
+ * linux/arch/m68knommu/kernel/process.c
+ *
+ * Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
+ * Kenneth Albanowski <kjahds@kjahds.com>,
+ * The Silver Hammer Group, Ltd.
+ *
+ * linux/arch/m68k/kernel/process.c
+ *
+ * Copyright (C) 1995 Hamish Macdonald
+ *
+ * 68060 fixes by Jesper Skov
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/rcupdate.h>
+
+#include <asm/uaccess.h>
+#include <asm/traps.h>
+#include <asm/setup.h>
+#include <asm/pgtable.h>
+
+void (*pm_power_off)(void) = NULL;
+EXPORT_SYMBOL(pm_power_off);
+
+asmlinkage void ret_from_fork(void);
+asmlinkage void ret_from_kernel_thread(void);
+
+/*
+ * The idle loop on an H8/300..
+ */
+void arch_cpu_idle(void)
+{
+ local_irq_enable();
+ __asm__("sleep");
+}
+
+void machine_restart(char *__unused)
+{
+ local_irq_disable();
+ __asm__("jmp @@0");
+}
+
+void machine_halt(void)
+{
+ local_irq_disable();
+ __asm__("sleep");
+ for (;;)
+ ;
+}
+
+void machine_power_off(void)
+{
+ local_irq_disable();
+ __asm__("sleep");
+ for (;;)
+ ;
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ show_regs_print_info(KERN_DEFAULT);
+
+ pr_notice("\n");
+ pr_notice("PC: %08lx Status: %02x\n",
+ regs->pc, regs->ccr);
+ pr_notice("ORIG_ER0: %08lx ER0: %08lx ER1: %08lx\n",
+ regs->orig_er0, regs->er0, regs->er1);
+ pr_notice("ER2: %08lx ER3: %08lx ER4: %08lx ER5: %08lx\n",
+ regs->er2, regs->er3, regs->er4, regs->er5);
+ pr_notice("ER6' %08lx ", regs->er6);
+ if (user_mode(regs))
+ printk("USP: %08lx\n", rdusp());
+ else
+ printk("\n");
+}
+
+void flush_thread(void)
+{
+}
+
+int copy_thread(unsigned long clone_flags,
+ unsigned long usp, unsigned long topstk,
+ struct task_struct *p)
+{
+ struct pt_regs *childregs;
+
+ childregs = (struct pt_regs *) (THREAD_SIZE + task_stack_page(p)) - 1;
+
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ memset(childregs, 0, sizeof(struct pt_regs));
+ childregs->retpc = (unsigned long) ret_from_kernel_thread;
+ childregs->er4 = topstk; /* arg */
+ childregs->er5 = usp; /* fn */
+ } else {
+ *childregs = *current_pt_regs();
+ childregs->er0 = 0;
+ childregs->retpc = (unsigned long) ret_from_fork;
+ p->thread.usp = usp ?: rdusp();
+ }
+ p->thread.ksp = (unsigned long)childregs;
+
+ return 0;
+}
+
+unsigned long thread_saved_pc(struct task_struct *tsk)
+{
+ return ((struct pt_regs *)tsk->thread.esp0)->pc;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long fp, pc;
+ unsigned long stack_page;
+ int count = 0;
+
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+
+ stack_page = (unsigned long)p;
+ fp = ((struct pt_regs *)p->thread.ksp)->er6;
+ do {
+ if (fp < stack_page+sizeof(struct thread_info) ||
+ fp >= 8184+stack_page)
+ return 0;
+ pc = ((unsigned long *)fp)[1];
+ if (!in_sched_functions(pc))
+ return pc;
+ fp = *(unsigned long *) fp;
+ } while (count++ < 16);
+ return 0;
+}
+
+/* generic sys_clone is not enough registers */
+asmlinkage int sys_clone(unsigned long __user *args)
+{
+ unsigned long clone_flags;
+ unsigned long newsp;
+ uintptr_t parent_tidptr;
+ uintptr_t child_tidptr;
+
+ get_user(clone_flags, &args[0]);
+ get_user(newsp, &args[1]);
+ get_user(parent_tidptr, &args[2]);
+ get_user(child_tidptr, &args[3]);
+ return do_fork(clone_flags, newsp, 0,
+ (int __user *)parent_tidptr, (int __user *)child_tidptr);
+}
diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c
new file mode 100644
index 000000000000..92075544a19a
--- /dev/null
+++ b/arch/h8300/kernel/ptrace.c
@@ -0,0 +1,203 @@
+/*
+ * linux/arch/h8300/kernel/ptrace.c
+ *
+ * Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of
+ * this archive for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/audit.h>
+#include <linux/tracehook.h>
+#include <linux/regset.h>
+#include <linux/elf.h>
+
+#define CCR_MASK 0x6f /* mode/imask not set */
+#define EXR_MASK 0x80 /* modify only T */
+
+#define PT_REG(r) offsetof(struct pt_regs, r)
+
+extern void user_disable_single_step(struct task_struct *child);
+
+/* Mapping from PT_xxx to the stack offset at which the register is
+ saved. Notice that usp has no stack-slot and needs to be treated
+ specially (see get_reg/put_reg below). */
+static const int register_offset[] = {
+ PT_REG(er1), PT_REG(er2), PT_REG(er3), PT_REG(er4),
+ PT_REG(er5), PT_REG(er6), PT_REG(er0), -1,
+ PT_REG(orig_er0), PT_REG(ccr), PT_REG(pc),
+#if defined(CONFIG_CPU_H8S)
+ PT_REG(exr),
+#endif
+};
+
+/* read register */
+long h8300_get_reg(struct task_struct *task, int regno)
+{
+ switch (regno) {
+ case PT_USP:
+ return task->thread.usp + sizeof(long)*2;
+ case PT_CCR:
+ case PT_EXR:
+ return *(unsigned short *)(task->thread.esp0 +
+ register_offset[regno]);
+ default:
+ return *(unsigned long *)(task->thread.esp0 +
+ register_offset[regno]);
+ }
+}
+
+int h8300_put_reg(struct task_struct *task, int regno, unsigned long data)
+{
+ unsigned short oldccr;
+ unsigned short oldexr;
+
+ switch (regno) {
+ case PT_USP:
+ task->thread.usp = data - sizeof(long)*2;
+ case PT_CCR:
+ oldccr = *(unsigned short *)(task->thread.esp0 +
+ register_offset[regno]);
+ oldccr &= ~CCR_MASK;
+ data &= CCR_MASK;
+ data |= oldccr;
+ *(unsigned short *)(task->thread.esp0 +
+ register_offset[regno]) = data;
+ break;
+ case PT_EXR:
+ oldexr = *(unsigned short *)(task->thread.esp0 +
+ register_offset[regno]);
+ oldccr &= ~EXR_MASK;
+ data &= EXR_MASK;
+ data |= oldexr;
+ *(unsigned short *)(task->thread.esp0 +
+ register_offset[regno]) = data;
+ break;
+ default:
+ *(unsigned long *)(task->thread.esp0 +
+ register_offset[regno]) = data;
+ break;
+ }
+ return 0;
+}
+
+static int regs_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int r;
+ struct user_regs_struct regs;
+ long *reg = (long *)&regs;
+
+ /* build user regs in buffer */
+ for (r = 0; r < ARRAY_SIZE(register_offset); r++)
+ *reg++ = h8300_get_reg(target, r);
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &regs, 0, sizeof(regs));
+}
+
+static int regs_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int r;
+ int ret;
+ struct user_regs_struct regs;
+ long *reg;
+
+ /* build user regs in buffer */
+ for (reg = (long *)&regs, r = 0; r < ARRAY_SIZE(register_offset); r++)
+ *reg++ = h8300_get_reg(target, r);
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &regs, 0, sizeof(regs));
+ if (ret)
+ return ret;
+
+ /* write back to pt_regs */
+ for (reg = (long *)&regs, r = 0; r < ARRAY_SIZE(register_offset); r++)
+ h8300_put_reg(target, r, *reg++);
+ return 0;
+}
+
+enum h8300_regset {
+ REGSET_GENERAL,
+};
+
+static const struct user_regset h8300_regsets[] = {
+ [REGSET_GENERAL] = {
+ .core_note_type = NT_PRSTATUS,
+ .n = ELF_NGREG,
+ .size = sizeof(long),
+ .align = sizeof(long),
+ .get = regs_get,
+ .set = regs_set,
+ },
+};
+
+static const struct user_regset_view user_h8300_native_view = {
+ .name = "h8300",
+ .e_machine = EM_H8_300,
+ .regsets = h8300_regsets,
+ .n = ARRAY_SIZE(h8300_regsets),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+ return &user_h8300_native_view;
+}
+
+void ptrace_disable(struct task_struct *child)
+{
+ user_disable_single_step(child);
+}
+
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
+{
+ int ret;
+
+ switch (request) {
+ default:
+ ret = ptrace_request(child, request, addr, data);
+ break;
+ }
+ return ret;
+}
+
+asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
+{
+ long ret = 0;
+
+ if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+ tracehook_report_syscall_entry(regs))
+ /*
+ * Tracing decided this syscall should not happen.
+ * We'll return a bogus call number to get an ENOSYS
+ * error, but leave the original number in regs->regs[0].
+ */
+ ret = -1L;
+
+ audit_syscall_entry(regs->er1, regs->er2, regs->er3,
+ regs->er4, regs->er5);
+
+ return ret ?: regs->er0;
+}
+
+asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
+{
+ int step;
+
+ audit_syscall_exit(regs);
+
+ step = test_thread_flag(TIF_SINGLESTEP);
+ if (step || test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(regs, step);
+}
diff --git a/arch/h8300/kernel/ptrace_h.c b/arch/h8300/kernel/ptrace_h.c
new file mode 100644
index 000000000000..fe3b5673baba
--- /dev/null
+++ b/arch/h8300/kernel/ptrace_h.c
@@ -0,0 +1,256 @@
+/*
+ * ptrace cpu depend helper functions
+ *
+ * Copyright 2003, 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of
+ * this archive for more details.
+ */
+
+#include <linux/linkage.h>
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+
+#define BREAKINST 0x5730 /* trapa #3 */
+
+/* disable singlestep */
+void user_disable_single_step(struct task_struct *child)
+{
+ if ((long)child->thread.breakinfo.addr != -1L) {
+ *(child->thread.breakinfo.addr) = child->thread.breakinfo.inst;
+ child->thread.breakinfo.addr = (unsigned short *)-1L;
+ }
+}
+
+/* calculate next pc */
+enum jump_type {none, /* normal instruction */
+ jabs, /* absolute address jump */
+ ind, /* indirect address jump */
+ ret, /* return to subrutine */
+ reg, /* register indexed jump */
+ relb, /* pc relative jump (byte offset) */
+ relw, /* pc relative jump (word offset) */
+ };
+
+/* opcode decode table define
+ ptn: opcode pattern
+ msk: opcode bitmask
+ len: instruction length (<0 next table index)
+ jmp: jump operation mode */
+struct optable {
+ unsigned char bitpattern;
+ unsigned char bitmask;
+ signed char length;
+ signed char type;
+} __packed __aligned(1);
+
+#define OPTABLE(ptn, msk, len, jmp) \
+ { \
+ .bitpattern = ptn, \
+ .bitmask = msk, \
+ .length = len, \
+ .type = jmp, \
+ }
+
+static const struct optable optable_0[] = {
+ OPTABLE(0x00, 0xff, 1, none), /* 0x00 */
+ OPTABLE(0x01, 0xff, -1, none), /* 0x01 */
+ OPTABLE(0x02, 0xfe, 1, none), /* 0x02-0x03 */
+ OPTABLE(0x04, 0xee, 1, none), /* 0x04-0x05/0x14-0x15 */
+ OPTABLE(0x06, 0xfe, 1, none), /* 0x06-0x07 */
+ OPTABLE(0x08, 0xea, 1, none), /* 0x08-0x09/0x0c-0x0d/0x18-0x19/0x1c-0x1d */
+ OPTABLE(0x0a, 0xee, 1, none), /* 0x0a-0x0b/0x1a-0x1b */
+ OPTABLE(0x0e, 0xee, 1, none), /* 0x0e-0x0f/0x1e-0x1f */
+ OPTABLE(0x10, 0xfc, 1, none), /* 0x10-0x13 */
+ OPTABLE(0x16, 0xfe, 1, none), /* 0x16-0x17 */
+ OPTABLE(0x20, 0xe0, 1, none), /* 0x20-0x3f */
+ OPTABLE(0x40, 0xf0, 1, relb), /* 0x40-0x4f */
+ OPTABLE(0x50, 0xfc, 1, none), /* 0x50-0x53 */
+ OPTABLE(0x54, 0xfd, 1, ret), /* 0x54/0x56 */
+ OPTABLE(0x55, 0xff, 1, relb), /* 0x55 */
+ OPTABLE(0x57, 0xff, 1, none), /* 0x57 */
+ OPTABLE(0x58, 0xfb, 2, relw), /* 0x58/0x5c */
+ OPTABLE(0x59, 0xfb, 1, reg), /* 0x59/0x5b */
+ OPTABLE(0x5a, 0xfb, 2, jabs), /* 0x5a/0x5e */
+ OPTABLE(0x5b, 0xfb, 2, ind), /* 0x5b/0x5f */
+ OPTABLE(0x60, 0xe8, 1, none), /* 0x60-0x67/0x70-0x77 */
+ OPTABLE(0x68, 0xfa, 1, none), /* 0x68-0x69/0x6c-0x6d */
+ OPTABLE(0x6a, 0xfe, -2, none), /* 0x6a-0x6b */
+ OPTABLE(0x6e, 0xfe, 2, none), /* 0x6e-0x6f */
+ OPTABLE(0x78, 0xff, 4, none), /* 0x78 */
+ OPTABLE(0x79, 0xff, 2, none), /* 0x79 */
+ OPTABLE(0x7a, 0xff, 3, none), /* 0x7a */
+ OPTABLE(0x7b, 0xff, 2, none), /* 0x7b */
+ OPTABLE(0x7c, 0xfc, 2, none), /* 0x7c-0x7f */
+ OPTABLE(0x80, 0x80, 1, none), /* 0x80-0xff */
+};
+
+static const struct optable optable_1[] = {
+ OPTABLE(0x00, 0xff, -3, none), /* 0x0100 */
+ OPTABLE(0x40, 0xf0, -3, none), /* 0x0140-0x14f */
+ OPTABLE(0x80, 0xf0, 1, none), /* 0x0180-0x018f */
+ OPTABLE(0xc0, 0xc0, 2, none), /* 0x01c0-0x01ff */
+};
+
+static const struct optable optable_2[] = {
+ OPTABLE(0x00, 0x20, 2, none), /* 0x6a0?/0x6a8?/0x6b0?/0x6b8? */
+ OPTABLE(0x20, 0x20, 3, none), /* 0x6a2?/0x6aa?/0x6b2?/0x6ba? */
+};
+
+static const struct optable optable_3[] = {
+ OPTABLE(0x69, 0xfb, 2, none), /* 0x010069/0x01006d/014069/0x01406d */
+ OPTABLE(0x6b, 0xff, -4, none), /* 0x01006b/0x01406b */
+ OPTABLE(0x6f, 0xff, 3, none), /* 0x01006f/0x01406f */
+ OPTABLE(0x78, 0xff, 5, none), /* 0x010078/0x014078 */
+};
+
+static const struct optable optable_4[] = {
+/* 0x0100690?/0x01006d0?/0140690?/0x01406d0?/
+ 0x0100698?/0x01006d8?/0140698?/0x01406d8? */
+ OPTABLE(0x00, 0x78, 3, none),
+/* 0x0100692?/0x01006d2?/0140692?/0x01406d2?/
+ 0x010069a?/0x01006da?/014069a?/0x01406da? */
+ OPTABLE(0x20, 0x78, 4, none),
+};
+
+static const struct optables_list {
+ const struct optable *ptr;
+ int size;
+} optables[] = {
+#define OPTABLES(no) \
+ { \
+ .ptr = optable_##no, \
+ .size = sizeof(optable_##no) / sizeof(struct optable), \
+ }
+ OPTABLES(0),
+ OPTABLES(1),
+ OPTABLES(2),
+ OPTABLES(3),
+ OPTABLES(4),
+
+};
+
+const unsigned char condmask[] = {
+ 0x00, 0x40, 0x01, 0x04, 0x02, 0x08, 0x10, 0x20
+};
+
+static int isbranch(struct task_struct *task, int reson)
+{
+ unsigned char cond = h8300_get_reg(task, PT_CCR);
+
+ /* encode complex conditions */
+ /* B4: N^V
+ B5: Z|(N^V)
+ B6: C|Z */
+ __asm__("bld #3,%w0\n\t"
+ "bxor #1,%w0\n\t"
+ "bst #4,%w0\n\t"
+ "bor #2,%w0\n\t"
+ "bst #5,%w0\n\t"
+ "bld #2,%w0\n\t"
+ "bor #0,%w0\n\t"
+ "bst #6,%w0\n\t"
+ : "=&r"(cond) : "0"(cond) : "cc");
+ cond &= condmask[reson >> 1];
+ if (!(reson & 1))
+ return cond == 0;
+ else
+ return cond != 0;
+}
+
+static unsigned short *decode(struct task_struct *child,
+ const struct optable *op,
+ char *fetch_p, unsigned short *pc,
+ unsigned char inst)
+{
+ unsigned long addr;
+ unsigned long *sp;
+ int regno;
+
+ switch (op->type) {
+ case none:
+ return (unsigned short *)pc + op->length;
+ case jabs:
+ addr = *(unsigned long *)pc;
+ return (unsigned short *)(addr & 0x00ffffff);
+ case ind:
+ addr = *pc & 0xff;
+ return (unsigned short *)(*(unsigned long *)addr);
+ case ret:
+ sp = (unsigned long *)h8300_get_reg(child, PT_USP);
+ /* user stack frames
+ | er0 | temporary saved
+ +--------+
+ | exp | exception stack frames
+ +--------+
+ | ret pc | userspace return address
+ */
+ return (unsigned short *)(*(sp+2) & 0x00ffffff);
+ case reg:
+ regno = (*pc >> 4) & 0x07;
+ if (regno == 0)
+ addr = h8300_get_reg(child, PT_ER0);
+ else
+ addr = h8300_get_reg(child, regno-1 + PT_ER1);
+ return (unsigned short *)addr;
+ case relb:
+ if (inst == 0x55 || isbranch(child, inst & 0x0f))
+ pc = (unsigned short *)((unsigned long)pc +
+ ((signed char)(*fetch_p)));
+ return pc+1; /* skip myself */
+ case relw:
+ if (inst == 0x5c || isbranch(child, (*fetch_p & 0xf0) >> 4))
+ pc = (unsigned short *)((unsigned long)pc +
+ ((signed short)(*(pc+1))));
+ return pc+2; /* skip myself */
+ default:
+ return NULL;
+ }
+}
+
+static unsigned short *nextpc(struct task_struct *child, unsigned short *pc)
+{
+ const struct optable *op;
+ unsigned char *fetch_p;
+ int op_len;
+ unsigned char inst;
+
+ op = optables[0].ptr;
+ op_len = optables[0].size;
+ fetch_p = (unsigned char *)pc;
+ inst = *fetch_p++;
+ do {
+ if ((inst & op->bitmask) == op->bitpattern) {
+ if (op->length < 0) {
+ op = optables[-op->length].ptr;
+ op_len = optables[-op->length].size + 1;
+ inst = *fetch_p++;
+ } else
+ return decode(child, op, fetch_p, pc, inst);
+ } else
+ op++;
+ } while (--op_len > 0);
+ return NULL;
+}
+
+/* Set breakpoint(s) to simulate a single step from the current PC. */
+
+void user_enable_single_step(struct task_struct *child)
+{
+ unsigned short *next;
+
+ next = nextpc(child, (unsigned short *)h8300_get_reg(child, PT_PC));
+ child->thread.breakinfo.addr = next;
+ child->thread.breakinfo.inst = *next;
+ *next = BREAKINST;
+}
+
+asmlinkage void trace_trap(unsigned long bp)
+{
+ if ((unsigned long)current->thread.breakinfo.addr == bp) {
+ user_disable_single_step(current);
+ force_sig(SIGTRAP, current);
+ } else
+ force_sig(SIGILL, current);
+}
diff --git a/arch/h8300/kernel/ptrace_s.c b/arch/h8300/kernel/ptrace_s.c
new file mode 100644
index 000000000000..ef5a9c13e76d
--- /dev/null
+++ b/arch/h8300/kernel/ptrace_s.c
@@ -0,0 +1,44 @@
+/*
+ * linux/arch/h8300/kernel/ptrace_h8s.c
+ * ptrace cpu depend helper functions
+ *
+ * Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of
+ * this archive for more details.
+ */
+
+#include <linux/linkage.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <asm/ptrace.h>
+
+#define CCR_MASK 0x6f
+#define EXR_TRACE 0x80
+
+/* disable singlestep */
+void user_disable_single_step(struct task_struct *child)
+{
+ unsigned char exr;
+
+ exr = h8300_get_reg(child, PT_EXR);
+ exr &= ~EXR_TRACE;
+ h8300_put_reg(child, PT_EXR, exr);
+}
+
+/* enable singlestep */
+void user_enable_single_step(struct task_struct *child)
+{
+ unsigned char exr;
+
+ exr = h8300_get_reg(child, PT_EXR);
+ exr |= EXR_TRACE;
+ h8300_put_reg(child, PT_EXR, exr);
+}
+
+asmlinkage void trace_trap(unsigned long bp)
+{
+ (void)bp;
+ force_sig(SIGTRAP, current);
+}
diff --git a/arch/h8300/kernel/setup.c b/arch/h8300/kernel/setup.c
new file mode 100644
index 000000000000..0fd1fe65c0b8
--- /dev/null
+++ b/arch/h8300/kernel/setup.c
@@ -0,0 +1,255 @@
+/*
+ * linux/arch/h8300/kernel/setup.c
+ *
+ * Copyright (C) 2001-2014 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+/*
+ * This file handles the architecture-dependent parts of system setup
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/console.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/clk-provider.h>
+#include <linux/memblock.h>
+#include <linux/screen_info.h>
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
+#include <asm/page.h>
+
+#if defined(CONFIG_CPU_H8300H)
+#define CPU "H8/300H"
+#elif defined(CONFIG_CPU_H8S)
+#define CPU "H8S"
+#else
+#define CPU "Unknown"
+#endif
+
+unsigned long memory_start;
+unsigned long memory_end;
+EXPORT_SYMBOL(memory_end);
+static unsigned long freq;
+extern char __dtb_start[];
+
+#ifdef CONFIG_VT
+struct screen_info screen_info;
+#endif
+
+char __initdata command_line[COMMAND_LINE_SIZE];
+
+void sim_console_register(void);
+
+void __init h8300_fdt_init(void *fdt, char *bootargs)
+{
+ if (!fdt)
+ fdt = __dtb_start;
+ else
+ strcpy(command_line, bootargs);
+
+ early_init_dt_scan(fdt);
+ memblock_allow_resize();
+}
+
+static void __init bootmem_init(void)
+{
+ int bootmap_size;
+ unsigned long ram_start_pfn;
+ unsigned long free_ram_start_pfn;
+ unsigned long ram_end_pfn;
+ struct memblock_region *region;
+
+ memory_end = memory_start = 0;
+
+ /* Find main memory where is the kernel */
+ for_each_memblock(memory, region) {
+ memory_start = region->base;
+ memory_end = region->base + region->size;
+ }
+
+ if (!memory_end)
+ panic("No memory!");
+
+ ram_start_pfn = PFN_UP(memory_start);
+ /* free_ram_start_pfn is first page after kernel */
+ free_ram_start_pfn = PFN_UP(__pa(_end));
+ ram_end_pfn = PFN_DOWN(memblock_end_of_DRAM());
+
+ max_pfn = ram_end_pfn;
+
+ /*
+ * give all the memory to the bootmap allocator, tell it to put the
+ * boot mem_map at the start of memory
+ */
+ bootmap_size = init_bootmem_node(NODE_DATA(0),
+ free_ram_start_pfn,
+ 0,
+ ram_end_pfn);
+ /*
+ * free the usable memory, we have to make sure we do not free
+ * the bootmem bitmap so we then reserve it after freeing it :-)
+ */
+ free_bootmem(PFN_PHYS(free_ram_start_pfn),
+ (ram_end_pfn - free_ram_start_pfn) << PAGE_SHIFT);
+ reserve_bootmem(PFN_PHYS(free_ram_start_pfn), bootmap_size,
+ BOOTMEM_DEFAULT);
+
+ for_each_memblock(reserved, region) {
+ reserve_bootmem(region->base, region->size, BOOTMEM_DEFAULT);
+ }
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+ unflatten_and_copy_device_tree();
+
+ init_mm.start_code = (unsigned long) _stext;
+ init_mm.end_code = (unsigned long) _etext;
+ init_mm.end_data = (unsigned long) _edata;
+ init_mm.brk = (unsigned long) 0;
+
+ pr_notice("\r\n\nuClinux " CPU "\n");
+ pr_notice("Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne\n");
+
+ if (*command_line)
+ strcpy(boot_command_line, command_line);
+ *cmdline_p = boot_command_line;
+
+ parse_early_param();
+
+ bootmem_init();
+#if defined(CONFIG_H8300H_SIM) || defined(CONFIG_H8S_SIM)
+ sim_console_register();
+#endif
+
+ early_platform_driver_probe("earlyprintk", 1, 0);
+ /*
+ * get kmalloc into gear
+ */
+ paging_init();
+}
+
+/*
+ * Get CPU information for use by the procfs.
+ */
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+ char *cpu;
+
+ cpu = CPU;
+
+ seq_printf(m, "CPU:\t\t%s\n"
+ "Clock:\t\t%lu.%1luMHz\n"
+ "BogoMips:\t%lu.%02lu\n"
+ "Calibration:\t%lu loops\n",
+ cpu,
+ freq/1000, freq%1000,
+ (loops_per_jiffy*HZ)/500000,
+ ((loops_per_jiffy*HZ)/5000)%100,
+ (loops_per_jiffy*HZ));
+
+ return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+ return *pos < num_possible_cpus() ?
+ ((void *) 0x12345678) : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ ++*pos;
+ return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+const struct seq_operations cpuinfo_op = {
+ .start = c_start,
+ .next = c_next,
+ .stop = c_stop,
+ .show = show_cpuinfo,
+};
+
+static int __init device_probe(void)
+{
+ of_platform_populate(NULL, NULL, NULL, NULL);
+
+ return 0;
+}
+
+device_initcall(device_probe);
+
+#if defined(CONFIG_CPU_H8300H)
+#define get_wait(base, addr) ({ \
+ int baddr; \
+ baddr = ((addr) / 0x200000 * 2); \
+ w *= (ctrl_inw((unsigned long)(base) + 2) & (3 << baddr)) + 1; \
+ })
+#endif
+#if defined(CONFIG_CPU_H8S)
+#define get_wait(base, addr) ({ \
+ int baddr; \
+ baddr = ((addr) / 0x200000 * 16); \
+ w *= (ctrl_inl((unsigned long)(base) + 2) & (7 << baddr)) + 1; \
+ })
+#endif
+
+static __init int access_timing(void)
+{
+ struct device_node *bsc;
+ void __iomem *base;
+ unsigned long addr = (unsigned long)&__delay;
+ int bit = 1 << (addr / 0x200000);
+ int w;
+
+ bsc = of_find_compatible_node(NULL, NULL, "renesas,h8300-bsc");
+ base = of_iomap(bsc, 0);
+ w = (ctrl_inb((unsigned long)base + 0) & bit)?2:1;
+ if (ctrl_inb((unsigned long)base + 1) & bit)
+ w *= get_wait(base, addr);
+ else
+ w *= 2;
+ return w * 3 / 2;
+}
+
+void __init calibrate_delay(void)
+{
+ struct device_node *cpu;
+ int freq;
+
+ cpu = of_find_compatible_node(NULL, NULL, "renesas,h8300");
+ of_property_read_s32(cpu, "clock-frequency", &freq);
+ loops_per_jiffy = freq / HZ / (access_timing() * 2);
+ pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
+ loops_per_jiffy / (500000 / HZ),
+ (loops_per_jiffy / (5000 / HZ)) % 100, loops_per_jiffy);
+}
+
+
+void __init time_init(void)
+{
+ of_clk_init(NULL);
+}
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
new file mode 100644
index 000000000000..380fffd081b2
--- /dev/null
+++ b/arch/h8300/kernel/signal.c
@@ -0,0 +1,289 @@
+/*
+ * linux/arch/h8300/kernel/signal.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * uClinux H8/300 support by Yoshinori Sato <ysato@users.sourceforge.jp>
+ * and David McCullough <davidm@snapgear.com>
+ *
+ * Based on
+ * Linux/m68k by Hamish Macdonald
+ */
+
+/*
+ * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
+ * Atari :-) Current limitation: Only one sigstack can be active at one time.
+ * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
+ * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
+ * signal handlers!
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/syscalls.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/highuid.h>
+#include <linux/personality.h>
+#include <linux/tty.h>
+#include <linux/binfmts.h>
+#include <linux/tracehook.h>
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/traps.h>
+#include <asm/ucontext.h>
+
+/*
+ * Do a signal return; undo the signal stack.
+ *
+ * Keep the return code on the stack quadword aligned!
+ * That makes the cache flush below easier.
+ */
+
+struct rt_sigframe {
+ long dummy_er0;
+ long dummy_vector;
+#if defined(CONFIG_CPU_H8S)
+ short dummy_exr;
+#endif
+ long dummy_pc;
+ char *pretcode;
+ struct siginfo *pinfo;
+ void *puc;
+ unsigned char retcode[8];
+ struct siginfo info;
+ struct ucontext uc;
+ int sig;
+} __packed __aligned(2);
+
+static inline int
+restore_sigcontext(struct sigcontext *usc, int *pd0)
+{
+ struct pt_regs *regs = current_pt_regs();
+ int err = 0;
+ unsigned int ccr;
+ unsigned int usp;
+ unsigned int er0;
+
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+ /* restore passed registers */
+#define COPY(r) do { err |= get_user(regs->r, &usc->sc_##r); } while (0)
+ COPY(er1);
+ COPY(er2);
+ COPY(er3);
+ COPY(er5);
+ COPY(pc);
+ ccr = regs->ccr & 0x10;
+ COPY(ccr);
+#undef COPY
+ regs->ccr &= 0xef;
+ regs->ccr |= ccr;
+ regs->orig_er0 = -1; /* disable syscall checks */
+ err |= __get_user(usp, &usc->sc_usp);
+ wrusp(usp);
+
+ err |= __get_user(er0, &usc->sc_er0);
+ *pd0 = er0;
+ return err;
+}
+
+asmlinkage int sys_rt_sigreturn(void)
+{
+ unsigned long usp = rdusp();
+ struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
+ sigset_t set;
+ int er0;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto badframe;
+
+ set_current_blocked(&set);
+
+ if (restore_sigcontext(&frame->uc.uc_mcontext, &er0))
+ goto badframe;
+
+ if (restore_altstack(&frame->uc.uc_stack))
+ goto badframe;
+
+ return er0;
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
+ unsigned long mask)
+{
+ int err = 0;
+
+ err |= __put_user(regs->er0, &sc->sc_er0);
+ err |= __put_user(regs->er1, &sc->sc_er1);
+ err |= __put_user(regs->er2, &sc->sc_er2);
+ err |= __put_user(regs->er3, &sc->sc_er3);
+ err |= __put_user(regs->er4, &sc->sc_er4);
+ err |= __put_user(regs->er5, &sc->sc_er5);
+ err |= __put_user(regs->er6, &sc->sc_er6);
+ err |= __put_user(rdusp(), &sc->sc_usp);
+ err |= __put_user(regs->pc, &sc->sc_pc);
+ err |= __put_user(regs->ccr, &sc->sc_ccr);
+ err |= __put_user(mask, &sc->sc_mask);
+
+ return err;
+}
+
+static inline void __user *
+get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size)
+{
+ return (void __user *)((sigsp(rdusp(), ksig) - frame_size) & -8UL);
+}
+
+static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
+ struct pt_regs *regs)
+{
+ struct rt_sigframe *frame;
+ int err = 0;
+ unsigned char *ret;
+
+ frame = get_sigframe(ksig, regs, sizeof(*frame));
+
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ return -EFAULT;
+
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
+ err |= copy_siginfo_to_user(&frame->info, &ksig->info);
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __save_altstack(&frame->uc.uc_stack, rdusp());
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
+ err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ if (err)
+ return -EFAULT;
+
+ /* Set up to return from userspace. */
+ ret = frame->retcode;
+ if (ksig->ka.sa.sa_flags & SA_RESTORER)
+ ret = (unsigned char *)(ksig->ka.sa.sa_restorer);
+ else {
+ /* sub.l er0,er0; mov.b #__NR_rt_sigreturn,r0l; trapa #0 */
+ err |= __put_user(0x1a80f800 + (__NR_rt_sigreturn & 0xff),
+ (unsigned long *)(frame->retcode + 0));
+ err |= __put_user(0x5700,
+ (unsigned short *)(frame->retcode + 4));
+ }
+ err |= __put_user(ret, &frame->pretcode);
+
+ if (err)
+ return -EFAULT;
+
+ /* Set up registers for signal handler */
+ wrusp((unsigned long) frame);
+ regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
+ regs->er0 = ksig->sig;
+ regs->er1 = (unsigned long)&(frame->info);
+ regs->er2 = (unsigned long)&frame->uc;
+ regs->er5 = current->mm->start_data; /* GOT base */
+
+ return 0;
+}
+
+static void
+handle_restart(struct pt_regs *regs, struct k_sigaction *ka)
+{
+ switch (regs->er0) {
+ case -ERESTARTNOHAND:
+ if (!ka)
+ goto do_restart;
+ regs->er0 = -EINTR;
+ break;
+ case -ERESTART_RESTARTBLOCK:
+ if (!ka) {
+ regs->er0 = __NR_restart_syscall;
+ regs->pc -= 2;
+ } else
+ regs->er0 = -EINTR;
+ break;
+ case -ERESTARTSYS:
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
+ regs->er0 = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+do_restart:
+ regs->er0 = regs->orig_er0;
+ regs->pc -= 2;
+ break;
+ }
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+static void
+handle_signal(struct ksignal *ksig, struct pt_regs *regs)
+{
+ sigset_t *oldset = sigmask_to_save();
+ int ret;
+ /* are we from a system call? */
+ if (regs->orig_er0 >= 0)
+ handle_restart(regs, &ksig->ka);
+
+ ret = setup_rt_frame(ksig, oldset, regs);
+
+ signal_setup_done(ret, ksig, 0);
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+static void do_signal(struct pt_regs *regs)
+{
+ struct ksignal ksig;
+
+ current->thread.esp0 = (unsigned long) regs;
+
+ if (get_signal(&ksig)) {
+ /* Whee! Actually deliver the signal. */
+ handle_signal(&ksig, regs);
+ return;
+ }
+ /* Did we come from a system call? */
+ if (regs->orig_er0 >= 0)
+ handle_restart(regs, NULL);
+
+ /* If there's no signal to deliver, we just restore the saved mask. */
+ restore_saved_sigmask();
+}
+
+asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
+{
+ 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);
+ }
+}
diff --git a/arch/h8300/kernel/sim-console.c b/arch/h8300/kernel/sim-console.c
new file mode 100644
index 000000000000..a15edf0565d9
--- /dev/null
+++ b/arch/h8300/kernel/sim-console.c
@@ -0,0 +1,79 @@
+/*
+ * arch/h8300/kernel/early_printk.c
+ *
+ * Copyright (C) 2009 Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+static void sim_write(struct console *co, const char *ptr,
+ unsigned len)
+{
+ register const int fd __asm__("er0") = 1; /* stdout */
+ register const char *_ptr __asm__("er1") = ptr;
+ register const unsigned _len __asm__("er2") = len;
+
+ __asm__(".byte 0x5e,0x00,0x00,0xc7\n\t" /* jsr @0xc7 (sys_write) */
+ : : "g"(fd), "g"(_ptr), "g"(_len));
+}
+
+static struct console sim_console = {
+ .name = "sim_console",
+ .write = sim_write,
+ .setup = NULL,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+static char sim_console_buf[32];
+
+static int sim_probe(struct platform_device *pdev)
+{
+ if (sim_console.data)
+ return -EEXIST;
+
+ if (!strstr(sim_console_buf, "keep"))
+ sim_console.flags |= CON_BOOT;
+
+ register_console(&sim_console);
+ return 0;
+}
+
+static int sim_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver sim_driver = {
+ .probe = sim_probe,
+ .remove = sim_remove,
+ .driver = {
+ .name = "h8300-sim",
+ .owner = THIS_MODULE,
+ },
+};
+
+early_platform_init_buffer("earlyprintk", &sim_driver,
+ sim_console_buf, ARRAY_SIZE(sim_console_buf));
+
+static struct platform_device sim_console_device = {
+ .name = "h8300-sim",
+ .id = 0,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &sim_console_device,
+};
+
+void __init sim_console_register(void)
+{
+ early_platform_add_devices(devices,
+ ARRAY_SIZE(devices));
+}
diff --git a/arch/h8300/kernel/syscalls.c b/arch/h8300/kernel/syscalls.c
new file mode 100644
index 000000000000..1f9123a013d3
--- /dev/null
+++ b/arch/h8300/kernel/syscalls.c
@@ -0,0 +1,14 @@
+#include <linux/syscalls.h>
+#include <linux/signal.h>
+#include <linux/unistd.h>
+
+#undef __SYSCALL
+#define __SYSCALL(nr, call) [nr] = (call),
+
+#define sys_mmap2 sys_mmap_pgoff
+
+asmlinkage int sys_rt_sigreturn(void);
+
+void *_sys_call_table[__NR_syscalls] = {
+#include <asm/unistd.h>
+};
diff --git a/arch/h8300/kernel/traps.c b/arch/h8300/kernel/traps.c
new file mode 100644
index 000000000000..1b2d7cdd6591
--- /dev/null
+++ b/arch/h8300/kernel/traps.c
@@ -0,0 +1,161 @@
+/*
+ * linux/arch/h8300/boot/traps.c -- general exception handling code
+ * H8/300 support Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * Cloned from Linux/m68k.
+ *
+ * No original Copyright holder listed,
+ * Probable original (C) Roman Zippel (assigned DJD, 1999)
+ *
+ * Copyright 1999-2000 D. Jeff Dionne, <jeff@rt-control.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/bug.h>
+
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/page.h>
+
+static DEFINE_SPINLOCK(die_lock);
+
+/*
+ * this must be called very early as the kernel might
+ * use some instruction that are emulated on the 060
+ */
+
+void __init base_trap_init(void)
+{
+}
+
+void __init trap_init(void)
+{
+}
+
+asmlinkage void set_esp0(unsigned long ssp)
+{
+ current->thread.esp0 = ssp;
+}
+
+/*
+ * Generic dumping code. Used for panic and debug.
+ */
+
+static void dump(struct pt_regs *fp)
+{
+ unsigned long *sp;
+ unsigned char *tp;
+ int i;
+
+ pr_info("\nCURRENT PROCESS:\n\n");
+ pr_info("COMM=%s PID=%d\n", current->comm, current->pid);
+ if (current->mm) {
+ pr_info("TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
+ (int) current->mm->start_code,
+ (int) current->mm->end_code,
+ (int) current->mm->start_data,
+ (int) current->mm->end_data,
+ (int) current->mm->end_data,
+ (int) current->mm->brk);
+ pr_info("USER-STACK=%08x KERNEL-STACK=%08lx\n\n",
+ (int) current->mm->start_stack,
+ (int) PAGE_SIZE+(unsigned long)current);
+ }
+
+ show_regs(fp);
+ pr_info("\nCODE:");
+ tp = ((unsigned char *) fp->pc) - 0x20;
+ for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) {
+ if ((i % 0x10) == 0)
+ pr_info("\n%08x: ", (int) (tp + i));
+ pr_info("%08x ", (int) *sp++);
+ }
+ pr_info("\n");
+
+ pr_info("\nKERNEL STACK:");
+ tp = ((unsigned char *) fp) - 0x40;
+ for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
+ if ((i % 0x10) == 0)
+ pr_info("\n%08x: ", (int) (tp + i));
+ pr_info("%08x ", (int) *sp++);
+ }
+ pr_info("\n");
+ if (STACK_MAGIC != *(unsigned long *)((unsigned long)current+PAGE_SIZE))
+ pr_info("(Possibly corrupted stack page??)\n");
+
+ pr_info("\n\n");
+}
+
+void die(const char *str, struct pt_regs *fp, unsigned long err)
+{
+ static int diecount;
+
+ oops_enter();
+
+ console_verbose();
+ spin_lock_irq(&die_lock);
+ report_bug(fp->pc, fp);
+ pr_crit("%s: %04lx [#%d] ", str, err & 0xffff, ++diecount);
+ dump(fp);
+
+ spin_unlock_irq(&die_lock);
+ do_exit(SIGSEGV);
+}
+
+static int kstack_depth_to_print = 24;
+
+void show_stack(struct task_struct *task, unsigned long *esp)
+{
+ unsigned long *stack, addr;
+ int i;
+
+ if (esp == NULL)
+ esp = (unsigned long *) &esp;
+
+ stack = esp;
+
+ pr_info("Stack from %08lx:", (unsigned long)stack);
+ for (i = 0; i < kstack_depth_to_print; i++) {
+ if (((unsigned long)stack & (THREAD_SIZE - 1)) == 0)
+ break;
+ if (i % 8 == 0)
+ pr_info("\n ");
+ pr_info(" %08lx", *stack++);
+ }
+
+ pr_info("\nCall Trace:");
+ i = 0;
+ stack = esp;
+ while (((unsigned long)stack & (THREAD_SIZE - 1)) != 0) {
+ addr = *stack++;
+ /*
+ * If the address is either in the text segment of the
+ * kernel, or in the region which contains vmalloc'ed
+ * memory, it *may* be the address of a calling
+ * routine; if so, print it so that someone tracing
+ * down the cause of the crash will be able to figure
+ * out the call path that was taken.
+ */
+ if (check_kernel_text(addr)) {
+ if (i % 4 == 0)
+ pr_info("\n ");
+ pr_info(" [<%08lx>]", addr);
+ i++;
+ }
+ }
+ pr_info("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+ show_stack(tsk, (unsigned long *)tsk->thread.esp0);
+}
diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S
new file mode 100644
index 000000000000..7c302dcf5249
--- /dev/null
+++ b/arch/h8300/kernel/vmlinux.lds.S
@@ -0,0 +1,67 @@
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
+
+#define ROMTOP 0x000000
+#define RAMTOP 0x400000
+
+jiffies = jiffies_64 + 4;
+
+ENTRY(_start)
+
+SECTIONS
+{
+#if defined(CONFIG_ROMKERNEL)
+ . = ROMTOP;
+ .vectors :
+ {
+ _vector = . ;
+ *(.vector*)
+ }
+#else
+ . = RAMTOP;
+ _ramstart = .;
+ . = . + CONFIG_OFFSET;
+#endif
+ _text = .;
+ HEAD_TEXT_SECTION
+ .text : {
+ _stext = . ;
+ TEXT_TEXT
+ SCHED_TEXT
+ LOCK_TEXT
+#if defined(CONFIG_ROMKERNEL)
+ *(.int_redirect)
+#endif
+ _etext = . ;
+ }
+ EXCEPTION_TABLE(16)
+ NOTES
+ RO_DATA_SECTION(4)
+ ROMEND = .;
+#if defined(CONFIG_ROMKERNEL)
+ . = RAMTOP;
+ _ramstart = .;
+#define ADDR(x) ROMEND
+#else
+#endif
+ _sdata = . ;
+ __data_start = . ;
+ RW_DATA_SECTION(0,0,0)
+#if defined(CONFIG_ROMKERNEL)
+#undef ADDR
+#endif
+ . = ALIGN(0x4) ;
+ __init_begin = .;
+ INIT_TEXT_SECTION(4)
+ INIT_DATA_SECTION(4)
+ SECURITY_INIT
+ __init_end = .;
+ _edata = . ;
+ _begin_data = LOADADDR(.data);
+ _sbss =.;
+ BSS_SECTION(0, 0 ,0)
+ _ebss =.;
+ _ramend = .;
+ _end = .;
+ DISCARDS
+}
diff --git a/arch/h8300/lib/Makefile b/arch/h8300/lib/Makefile
new file mode 100644
index 000000000000..28ff560d825f
--- /dev/null
+++ b/arch/h8300/lib/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for H8/300-specific library files..
+#
+
+lib-y = memcpy.o memset.o abs.o strncpy.o \
+ mulsi3.o udivsi3.o muldi3.o moddivsi3.o \
+ ashldi3.o lshrdi3.o ashrdi3.o ucmpdi2.o \
+ delay.o
diff --git a/arch/h8300/lib/abs.S b/arch/h8300/lib/abs.S
new file mode 100644
index 000000000000..efda749db03e
--- /dev/null
+++ b/arch/h8300/lib/abs.S
@@ -0,0 +1,20 @@
+;;; abs.S
+
+#include <asm/linkage.h>
+
+#if defined(CONFIG_CPU_H8300H)
+ .h8300h
+#endif
+#if defined(CONFIG_CPU_H8S)
+ .h8300s
+#endif
+ .text
+.global _abs
+
+;;; int abs(int n)
+_abs:
+ mov.l er0,er0
+ bpl 1f
+ neg.l er0
+1:
+ rts
diff --git a/arch/h8300/lib/ashldi3.c b/arch/h8300/lib/ashldi3.c
new file mode 100644
index 000000000000..c6aa8ea5f4be
--- /dev/null
+++ b/arch/h8300/lib/ashldi3.c
@@ -0,0 +1,24 @@
+#include "libgcc.h"
+
+DWtype
+__ashldi3(DWtype u, word_type b)
+{
+ const DWunion uu = {.ll = u};
+ const word_type bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
+ DWunion w;
+
+ if (b == 0)
+ return u;
+
+ if (bm <= 0) {
+ w.s.low = 0;
+ w.s.high = (UWtype) uu.s.low << -bm;
+ } else {
+ const UWtype carries = (UWtype) uu.s.low >> bm;
+
+ w.s.low = (UWtype) uu.s.low << b;
+ w.s.high = ((UWtype) uu.s.high << b) | carries;
+ }
+
+ return w.ll;
+}
diff --git a/arch/h8300/lib/ashrdi3.c b/arch/h8300/lib/ashrdi3.c
new file mode 100644
index 000000000000..070adf96d3b6
--- /dev/null
+++ b/arch/h8300/lib/ashrdi3.c
@@ -0,0 +1,24 @@
+#include "libgcc.h"
+
+DWtype __ashrdi3(DWtype u, word_type b)
+{
+ const DWunion uu = {.ll = u};
+ const word_type bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
+ DWunion w;
+
+ if (b == 0)
+ return u;
+
+ if (bm <= 0) {
+ /* w.s.high = 1..1 or 0..0 */
+ w.s.high = uu.s.high >> (sizeof (Wtype) * BITS_PER_UNIT - 1);
+ w.s.low = uu.s.high >> -bm;
+ } else {
+ const UWtype carries = (UWtype) uu.s.high << bm;
+
+ w.s.high = uu.s.high >> b;
+ w.s.low = ((UWtype) uu.s.low >> b) | carries;
+ }
+
+ return w.ll;
+}
diff --git a/arch/h8300/lib/delay.c b/arch/h8300/lib/delay.c
new file mode 100644
index 000000000000..463f6b3afb52
--- /dev/null
+++ b/arch/h8300/lib/delay.c
@@ -0,0 +1,40 @@
+/*
+ * delay loops
+ *
+ * Copyright (C) 2015 Yoshinori Sato
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <asm/param.h>
+#include <asm/processor.h>
+#include <asm/timex.h>
+
+void __delay(unsigned long cycles)
+{
+ __asm__ volatile ("1: dec.l #1,%0\n\t"
+ "bne 1b":"=r"(cycles):"0"(cycles));
+}
+EXPORT_SYMBOL(__delay);
+
+void __const_udelay(unsigned long xloops)
+{
+ u64 loops;
+
+ loops = (u64)xloops * loops_per_jiffy * HZ;
+
+ __delay(loops >> 32);
+}
+EXPORT_SYMBOL(__const_udelay);
+
+void __udelay(unsigned long usecs)
+{
+ __const_udelay(usecs * 0x10C7UL); /* 2**32 / 1000000 (rounded up) */
+}
+EXPORT_SYMBOL(__udelay);
+
+void __ndelay(unsigned long nsecs)
+{
+ __const_udelay(nsecs * 0x5UL); /* 2**32 / 1000000000 (rounded up) */
+}
+EXPORT_SYMBOL(__ndelay);
diff --git a/arch/h8300/lib/libgcc.h b/arch/h8300/lib/libgcc.h
new file mode 100644
index 000000000000..468a8f78197a
--- /dev/null
+++ b/arch/h8300/lib/libgcc.h
@@ -0,0 +1,77 @@
+#ifndef __H8300_LIBGCC_H__
+#define __H8300_LIBGCC_H__
+
+#ifdef __ASSEMBLY__
+#define A0 r0
+#define A0L r0l
+#define A0H r0h
+
+#define A1 r1
+#define A1L r1l
+#define A1H r1h
+
+#define A2 r2
+#define A2L r2l
+#define A2H r2h
+
+#define A3 r3
+#define A3L r3l
+#define A3H r3h
+
+#define S0 r4
+#define S0L r4l
+#define S0H r4h
+
+#define S1 r5
+#define S1L r5l
+#define S1H r5h
+
+#define S2 r6
+#define S2L r6l
+#define S2H r6h
+
+#define PUSHP push.l
+#define POPP pop.l
+
+#define A0P er0
+#define A1P er1
+#define A2P er2
+#define A3P er3
+#define S0P er4
+#define S1P er5
+#define S2P er6
+
+#define A0E e0
+#define A1E e1
+#define A2E e2
+#define A3E e3
+#else
+#define Wtype SItype
+#define UWtype USItype
+#define HWtype SItype
+#define UHWtype USItype
+#define DWtype DItype
+#define UDWtype UDItype
+#define UWtype USItype
+#define Wtype SItype
+#define UWtype USItype
+#define W_TYPE_SIZE (4 * BITS_PER_UNIT)
+#define BITS_PER_UNIT (8)
+
+typedef int SItype __attribute__ ((mode (SI)));
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef int DItype __attribute__ ((mode (DI)));
+typedef unsigned int UDItype __attribute__ ((mode (DI)));
+struct DWstruct {
+ Wtype high, low;
+};
+typedef union {
+ struct DWstruct s;
+ DWtype ll;
+} DWunion;
+
+typedef int word_type __attribute__ ((mode (__word__)));
+
+#endif
+
+#endif
diff --git a/arch/h8300/lib/lshrdi3.c b/arch/h8300/lib/lshrdi3.c
new file mode 100644
index 000000000000..a86bbe395f17
--- /dev/null
+++ b/arch/h8300/lib/lshrdi3.c
@@ -0,0 +1,23 @@
+#include "libgcc.h"
+
+DWtype __lshrdi3(DWtype u, word_type b)
+{
+ const DWunion uu = {.ll = u};
+ const word_type bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
+ DWunion w;
+
+ if (b == 0)
+ return u;
+
+ if (bm <= 0) {
+ w.s.high = 0;
+ w.s.low = (UWtype) uu.s.high >> -bm;
+ } else {
+ const UWtype carries = (UWtype) uu.s.high << bm;
+
+ w.s.high = (UWtype) uu.s.high >> b;
+ w.s.low = ((UWtype) uu.s.low >> b) | carries;
+ }
+
+ return w.ll;
+}
diff --git a/arch/h8300/lib/memcpy.S b/arch/h8300/lib/memcpy.S
new file mode 100644
index 000000000000..0c9a51fcdea1
--- /dev/null
+++ b/arch/h8300/lib/memcpy.S
@@ -0,0 +1,85 @@
+;;; memcpy.S
+
+#include <asm/linkage.h>
+
+#if defined(CONFIG_CPU_H8300H)
+ .h8300h
+#endif
+#if defined(CONFIG_CPU_H8S)
+ .h8300s
+#endif
+ .text
+.global memcpy
+
+;;; void *memcpy(void *to, void *from, size_t n)
+memcpy:
+ mov.l er2,er2
+ bne 1f
+ rts
+1:
+ ;; address check
+ bld #0,r0l
+ bxor #0,r1l
+ bcs 4f
+ mov.l er4,@-sp
+ mov.l er0,@-sp
+ btst #0,r0l
+ beq 1f
+ ;; (aligned even) odd address
+ mov.b @er1,r3l
+ mov.b r3l,@er0
+ adds #1,er1
+ adds #1,er0
+ dec.l #1,er2
+ beq 3f
+1:
+ ;; n < sizeof(unsigned long) check
+ sub.l er4,er4
+ adds #4,er4 ; loop count check value
+ cmp.l er4,er2
+ blo 2f
+ ;; unsigned long copy
+1:
+ mov.l @er1,er3
+ mov.l er3,@er0
+ adds #4,er0
+ adds #4,er1
+ subs #4,er2
+ cmp.l er4,er2
+ bcc 1b
+ ;; rest
+2:
+ mov.l er2,er2
+ beq 3f
+1:
+ mov.b @er1,r3l
+ mov.b r3l,@er0
+ adds #1,er1
+ adds #1,er0
+ dec.l #1,er2
+ bne 1b
+3:
+ mov.l @sp+,er0
+ mov.l @sp+,er4
+ rts
+
+ ;; odd <- even / even <- odd
+4:
+ mov.l er4,er3
+ mov.l er2,er4
+ mov.l er5,er2
+ mov.l er1,er5
+ mov.l er6,er1
+ mov.l er0,er6
+1:
+ eepmov.w
+ mov.w r4,r4
+ bne 1b
+ dec.w #1,e4
+ bpl 1b
+ mov.l er1,er6
+ mov.l er2,er5
+ mov.l er3,er4
+ rts
+
+ .end
diff --git a/arch/h8300/lib/memset.S b/arch/h8300/lib/memset.S
new file mode 100644
index 000000000000..18d4e709b5f4
--- /dev/null
+++ b/arch/h8300/lib/memset.S
@@ -0,0 +1,69 @@
+/* memset.S */
+
+#include <asm/linkage.h>
+
+#if defined(CONFIG_CPU_H8300H)
+ .h8300h
+#endif
+#if defined(CONFIG_CPU_H8S)
+ .h8300s
+#endif
+ .text
+
+.global memset
+.global clear_user
+
+;;void *memset(*ptr, int c, size_t count)
+;; ptr = er0
+;; c = er1(r1l)
+;; count = er2
+memset:
+ btst #0,r0l
+ beq 2f
+
+ ;; odd address
+1:
+ mov.b r1l,@er0
+ adds #1,er0
+ dec.l #1,er2
+ beq 6f
+
+ ;; even address
+2:
+ mov.l er2,er3
+ cmp.l #4,er2
+ blo 4f
+ ;; count>=4 -> count/4
+#if defined(CONFIG_CPU_H8300H)
+ shlr.l er2
+ shlr.l er2
+#endif
+#if defined(CONFIG_CPU_H8S)
+ shlr.l #2,er2
+#endif
+ ;; byte -> long
+ mov.b r1l,r1h
+ mov.w r1,e1
+3:
+ mov.l er1,@er0
+ adds #4,er0
+ dec.l #1,er2
+ bne 3b
+4:
+ ;; count % 4
+ and.b #3,r3l
+ beq 6f
+5:
+ mov.b r1l,@er0
+ adds #1,er0
+ dec.b r3l
+ bne 5b
+6:
+ rts
+
+clear_user:
+ mov.l er1, er2
+ sub.l er1, er1
+ bra memset
+
+ .end
diff --git a/arch/h8300/lib/moddivsi3.S b/arch/h8300/lib/moddivsi3.S
new file mode 100644
index 000000000000..c803129e877f
--- /dev/null
+++ b/arch/h8300/lib/moddivsi3.S
@@ -0,0 +1,72 @@
+#include "libgcc.h"
+
+; numerator in A0/A1
+; denominator in A2/A3
+ .global __modsi3
+__modsi3:
+ PUSHP S2P
+ bsr modnorm
+ bsr __divsi3
+ mov.l er3,er0
+ bra exitdiv
+
+ .global __umodsi3
+__umodsi3:
+ bsr __udivsi3:16
+ mov.l er3,er0
+ rts
+
+ .global __divsi3
+__divsi3:
+ PUSHP S2P
+ bsr divnorm
+ bsr __udivsi3:16
+
+ ; examine what the sign should be
+exitdiv:
+ btst #3,S2L
+ beq reti
+
+ ; should be -ve
+ neg.l A0P
+
+reti:
+ POPP S2P
+ rts
+
+divnorm:
+ mov.l A0P,A0P ; is the numerator -ve
+ stc ccr,S2L ; keep the sign in bit 3 of S2L
+ bge postive
+
+ neg.l A0P ; negate arg
+
+postive:
+ mov.l A1P,A1P ; is the denominator -ve
+ bge postive2
+
+ neg.l A1P ; negate arg
+ xor.b #0x08,S2L ; toggle the result sign
+
+postive2:
+ rts
+
+;; Basically the same, except that the sign of the divisor determines
+;; the sign.
+modnorm:
+ mov.l A0P,A0P ; is the numerator -ve
+ stc ccr,S2L ; keep the sign in bit 3 of S2L
+ bge mpostive
+
+ neg.l A0P ; negate arg
+
+mpostive:
+ mov.l A1P,A1P ; is the denominator -ve
+ bge mpostive2
+
+ neg.l A1P ; negate arg
+
+mpostive2:
+ rts
+
+ .end
diff --git a/arch/h8300/lib/modsi3.S b/arch/h8300/lib/modsi3.S
new file mode 100644
index 000000000000..68b1dfc32824
--- /dev/null
+++ b/arch/h8300/lib/modsi3.S
@@ -0,0 +1,72 @@
+#include "libgcc.h"
+
+; numerator in A0/A1
+; denominator in A2/A3
+ .global __modsi3
+__modsi3:
+ PUSHP S2P
+ bsr modnorm
+ bsr __divsi3
+ mov.l er3,er0
+ bra exitdiv
+
+ .global __umodsi3
+__umodsi3:
+ bsr __udivsi3
+ mov.l er3,er0
+ rts
+
+ .global __divsi3
+__divsi3:
+ PUSHP S2P
+ jsr divnorm
+ bsr __udivsi3
+
+ ; examine what the sign should be
+exitdiv:
+ btst #3,S2L
+ beq reti
+
+ ; should be -ve
+ neg.l A0P
+
+reti:
+ POPP S2P
+ rts
+
+divnorm:
+ mov.l A0P,A0P ; is the numerator -ve
+ stc ccr,S2L ; keep the sign in bit 3 of S2L
+ bge postive
+
+ neg.l A0P ; negate arg
+
+postive:
+ mov.l A1P,A1P ; is the denominator -ve
+ bge postive2
+
+ neg.l A1P ; negate arg
+ xor.b #0x08,S2L ; toggle the result sign
+
+postive2:
+ rts
+
+;; Basically the same, except that the sign of the divisor determines
+;; the sign.
+modnorm:
+ mov.l A0P,A0P ; is the numerator -ve
+ stc ccr,S2L ; keep the sign in bit 3 of S2L
+ bge mpostive
+
+ neg.l A0P ; negate arg
+
+mpostive:
+ mov.l A1P,A1P ; is the denominator -ve
+ bge mpostive2
+
+ neg.l A1P ; negate arg
+
+mpostive2:
+ rts
+
+ .end
diff --git a/arch/h8300/lib/muldi3.c b/arch/h8300/lib/muldi3.c
new file mode 100644
index 000000000000..790512243531
--- /dev/null
+++ b/arch/h8300/lib/muldi3.c
@@ -0,0 +1,44 @@
+#include "libgcc.h"
+
+#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
+#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
+
+#define umul_ppmm(w1, w0, u, v) \
+ do { \
+ UWtype __x0, __x1, __x2, __x3; \
+ UHWtype __ul, __vl, __uh, __vh; \
+ __ul = __ll_lowpart(u); \
+ __uh = __ll_highpart(u); \
+ __vl = __ll_lowpart(v); \
+ __vh = __ll_highpart(v); \
+ __x0 = (UWtype) __ul * __vl; \
+ __x1 = (UWtype) __ul * __vh; \
+ __x2 = (UWtype) __uh * __vl; \
+ __x3 = (UWtype) __uh * __vh; \
+ __x1 += __ll_highpart(__x0); \
+ __x1 += __x2; \
+ if (__x1 < __x2) \
+ __x3 += __ll_B; \
+ (w1) = __x3 + __ll_highpart(__x1); \
+ (w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0); \
+ } while (0)
+
+#define __umulsidi3(u, v) ( \
+ { \
+ DWunion __w; \
+ umul_ppmm(__w.s.high, __w.s.low, u, v); \
+ __w.ll; } \
+ )
+
+DWtype __muldi3(DWtype u, DWtype v)
+{
+ const DWunion uu = {.ll = u};
+ const DWunion vv = {.ll = v};
+ DWunion w = {.ll = __umulsidi3(uu.s.low, vv.s.low)};
+
+ w.s.high += ((UWtype) uu.s.low * (UWtype) vv.s.high
+ + (UWtype) uu.s.high * (UWtype) vv.s.low);
+
+ return w.ll;
+}
diff --git a/arch/h8300/lib/mulsi3.S b/arch/h8300/lib/mulsi3.S
new file mode 100644
index 000000000000..451f0e0538ee
--- /dev/null
+++ b/arch/h8300/lib/mulsi3.S
@@ -0,0 +1,38 @@
+;
+; mulsi3 for H8/300H - based on Renesas SH implementation
+;
+; by Toshiyasu Morita
+;
+; Old code:
+;
+; 16b * 16b = 372 states (worst case)
+; 32b * 32b = 724 states (worst case)
+;
+; New code:
+;
+; 16b * 16b = 48 states
+; 16b * 32b = 72 states
+; 32b * 32b = 92 states
+;
+
+ .global __mulsi3
+__mulsi3:
+ mov.w r1,r2 ; ( 2 states) b * d
+ mulxu r0,er2 ; (22 states)
+
+ mov.w e0,r3 ; ( 2 states) a * d
+ beq L_skip1 ; ( 4 states)
+ mulxu r1,er3 ; (22 states)
+ add.w r3,e2 ; ( 2 states)
+
+L_skip1:
+ mov.w e1,r3 ; ( 2 states) c * b
+ beq L_skip2 ; ( 4 states)
+ mulxu r0,er3 ; (22 states)
+ add.w r3,e2 ; ( 2 states)
+
+L_skip2:
+ mov.l er2,er0 ; ( 2 states)
+ rts ; (10 states)
+
+ .end
diff --git a/arch/h8300/lib/strncpy.S b/arch/h8300/lib/strncpy.S
new file mode 100644
index 000000000000..d00396a378f4
--- /dev/null
+++ b/arch/h8300/lib/strncpy.S
@@ -0,0 +1,34 @@
+;;; strncpy.S
+
+#include <asm/linkage.h>
+
+ .text
+.global strncpy_from_user
+
+;;; long strncpy_from_user(void *to, void *from, size_t n)
+strncpy_from_user:
+ mov.l er2,er2
+ bne 1f
+ sub.l er0,er0
+ rts
+1:
+ mov.l er4,@-sp
+ sub.l er3,er3
+2:
+ mov.b @er1+,r4l
+ mov.b r4l,@er0
+ adds #1,er0
+ beq 3f
+ inc.l #1,er3
+ dec.l #1,er2
+ bne 2b
+3:
+ dec.l #1,er2
+4:
+ mov.b r4l,@er0
+ adds #1,er0
+ dec.l #1,er2
+ bne 4b
+ mov.l er3,er0
+ mov.l @sp+,er4
+ rts
diff --git a/arch/h8300/lib/ucmpdi2.c b/arch/h8300/lib/ucmpdi2.c
new file mode 100644
index 000000000000..772399d705cb
--- /dev/null
+++ b/arch/h8300/lib/ucmpdi2.c
@@ -0,0 +1,17 @@
+#include "libgcc.h"
+
+word_type __ucmpdi2(DWtype a, DWtype b)
+{
+ const DWunion au = {.ll = a};
+ const DWunion bu = {.ll = b};
+
+ if ((UWtype) au.s.high < (UWtype) bu.s.high)
+ return 0;
+ else if ((UWtype) au.s.high > (UWtype) bu.s.high)
+ return 2;
+ if ((UWtype) au.s.low < (UWtype) bu.s.low)
+ return 0;
+ else if ((UWtype) au.s.low > (UWtype) bu.s.low)
+ return 2;
+ return 1;
+}
diff --git a/arch/h8300/lib/udivsi3.S b/arch/h8300/lib/udivsi3.S
new file mode 100644
index 000000000000..bbe65610f316
--- /dev/null
+++ b/arch/h8300/lib/udivsi3.S
@@ -0,0 +1,76 @@
+#include "libgcc.h"
+
+ ;; This function also computes the remainder and stores it in er3.
+ .global __udivsi3
+__udivsi3:
+ mov.w A1E,A1E ; denominator top word 0?
+ bne DenHighNonZero
+
+ ; do it the easy way, see page 107 in manual
+ mov.w A0E,A2
+ extu.l A2P
+ divxu.w A1,A2P
+ mov.w A2E,A0E
+ divxu.w A1,A0P
+ mov.w A0E,A3
+ mov.w A2,A0E
+ extu.l A3P
+ rts
+
+ ; er0 = er0 / er1
+ ; er3 = er0 % er1
+ ; trashes er1 er2
+ ; expects er1 >= 2^16
+DenHighNonZero:
+ mov.l er0,er3
+ mov.l er1,er2
+#ifdef CONFIG_CPU_H8300H
+divmod_L21:
+ shlr.l er0
+ shlr.l er2 ; make divisor < 2^16
+ mov.w e2,e2
+ bne divmod_L21
+#else
+ shlr.l #2,er2 ; make divisor < 2^16
+ mov.w e2,e2
+ beq divmod_L22A
+divmod_L21:
+ shlr.l #2,er0
+divmod_L22:
+ shlr.l #2,er2 ; make divisor < 2^16
+ mov.w e2,e2
+ bne divmod_L21
+divmod_L22A:
+ rotxl.w r2
+ bcs divmod_L23
+ shlr.l er0
+ bra divmod_L24
+divmod_L23:
+ rotxr.w r2
+ shlr.l #2,er0
+divmod_L24:
+#endif
+ ;; At this point,
+ ;; er0 contains shifted dividend
+ ;; er1 contains divisor
+ ;; er2 contains shifted divisor
+ ;; er3 contains dividend, later remainder
+ divxu.w r2,er0 ; r0 now contains the approximate quotient (AQ)
+ extu.l er0
+ beq divmod_L25
+ subs #1,er0 ; er0 = AQ - 1
+ mov.w e1,r2
+ mulxu.w r0,er2 ; er2 = upper (AQ - 1) * divisor
+ sub.w r2,e3 ; dividend - 65536 * er2
+ mov.w r1,r2
+ mulxu.w r0,er2 ; compute er3 = remainder (tentative)
+ sub.l er2,er3 ; er3 = dividend - (AQ - 1) * divisor
+divmod_L25:
+ cmp.l er1,er3 ; is divisor < remainder?
+ blo divmod_L26
+ adds #1,er0
+ sub.l er1,er3 ; correct the remainder
+divmod_L26:
+ rts
+
+ .end
diff --git a/arch/h8300/mm/Makefile b/arch/h8300/mm/Makefile
new file mode 100644
index 000000000000..508697f0d97c
--- /dev/null
+++ b/arch/h8300/mm/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the linux h8300-specific parts of the memory manager.
+#
+
+obj-y := init.o fault.o memory.o
diff --git a/arch/h8300/mm/fault.c b/arch/h8300/mm/fault.c
new file mode 100644
index 000000000000..5924ff555ded
--- /dev/null
+++ b/arch/h8300/mm/fault.c
@@ -0,0 +1,57 @@
+/*
+ * linux/arch/h8300/mm/fault.c
+ *
+ * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
+ * Copyright (C) 2000 Lineo, Inc. (www.lineo.com)
+ *
+ * Based on:
+ *
+ * linux/arch/m68knommu/mm/fault.c
+ * linux/arch/m68k/mm/fault.c
+ *
+ * Copyright (C) 1995 Hamish Macdonald
+ */
+
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+
+#include <asm/pgtable.h>
+
+void die(const char *str, struct pt_regs *fp, unsigned long err);
+
+/*
+ * This routine handles page faults. It determines the problem, and
+ * then passes it off to one of the appropriate routines.
+ *
+ * error_code:
+ * bit 0 == 0 means no page found, 1 means protection fault
+ * bit 1 == 0 means read, 1 means write
+ *
+ * If this routine detects a bad access, it returns 1, otherwise it
+ * returns 0.
+ */
+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code)
+{
+#ifdef DEBUG
+ pr_debug("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld\n",
+ regs->sr, regs->pc, address, error_code);
+#endif
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ if ((unsigned long) address < PAGE_SIZE)
+ pr_alert("Unable to handle kernel NULL pointer dereference");
+ else
+ pr_alert("Unable to handle kernel access");
+ printk(" at virtual address %08lx\n", address);
+ if (!user_mode(regs))
+ die("Oops", regs, error_code);
+ do_exit(SIGKILL);
+
+ return 1;
+}
diff --git a/arch/h8300/mm/init.c b/arch/h8300/mm/init.c
new file mode 100644
index 000000000000..495a3d6b539b
--- /dev/null
+++ b/arch/h8300/mm/init.c
@@ -0,0 +1,128 @@
+/*
+ * linux/arch/h8300/mm/init.c
+ *
+ * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
+ * Kenneth Albanowski <kjahds@kjahds.com>,
+ * Copyright (C) 2000 Lineo, Inc. (www.lineo.com)
+ *
+ * Based on:
+ *
+ * linux/arch/m68knommu/mm/init.c
+ * linux/arch/m68k/mm/init.c
+ *
+ * Copyright (C) 1995 Hamish Macdonald
+ *
+ * JAN/1999 -- hacked to support ColdFire (gerg@snapgear.com)
+ * DEC/2000 -- linux 2.4 support <davidm@snapgear.com>
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/bootmem.h>
+#include <linux/gfp.h>
+
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
+
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+static unsigned long empty_bad_page_table;
+static unsigned long empty_bad_page;
+unsigned long empty_zero_page;
+
+/*
+ * paging_init() continues the virtual memory environment setup which
+ * was begun by the code in arch/head.S.
+ * The parameters are pointers to where to stick the starting and ending
+ * addresses of available kernel virtual memory.
+ */
+void __init paging_init(void)
+{
+ /*
+ * Make sure start_mem is page aligned, otherwise bootmem and
+ * page_alloc get different views og the world.
+ */
+ unsigned long start_mem = PAGE_ALIGN(memory_start);
+ unsigned long end_mem = memory_end & PAGE_MASK;
+
+ pr_debug("start_mem is %#lx\nvirtual_end is %#lx\n",
+ start_mem, end_mem);
+
+ /*
+ * Initialize the bad page table and bad page to point
+ * to a couple of allocated pages.
+ */
+ empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+ empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+ empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+ memset((void *)empty_zero_page, 0, PAGE_SIZE);
+
+ /*
+ * Set up SFC/DFC registers (user data space).
+ */
+ set_fs(USER_DS);
+
+ pr_debug("before free_area_init\n");
+
+ pr_debug("free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n",
+ start_mem, end_mem);
+
+ {
+ unsigned long zones_size[MAX_NR_ZONES] = {0, };
+
+ zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+ free_area_init(zones_size);
+ }
+}
+
+void __init mem_init(void)
+{
+ pr_devel("Mem_init: start=%lx, end=%lx\n", memory_start, memory_end);
+
+ high_memory = (void *) (memory_end & PAGE_MASK);
+ max_mapnr = MAP_NR(high_memory);
+
+ /* this will put all low memory onto the freelists */
+ free_all_bootmem();
+
+ mem_init_print_info(NULL);
+}
+
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
+}
+#endif
+
+void
+free_initmem(void)
+{
+ free_initmem_default(-1);
+}
diff --git a/arch/h8300/mm/memory.c b/arch/h8300/mm/memory.c
new file mode 100644
index 000000000000..4974aa40bcb8
--- /dev/null
+++ b/arch/h8300/mm/memory.c
@@ -0,0 +1,53 @@
+/*
+ * linux/arch/h8300/mm/memory.c
+ *
+ * Copyright (C) 2002 Yoshinori Sato <ysato@users.sourceforge.jp>,
+ *
+ * Based on:
+ *
+ * linux/arch/m68knommu/mm/memory.c
+ *
+ * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
+ * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *
+ * Based on:
+ *
+ * linux/arch/m68k/mm/memory.c
+ *
+ * Copyright (C) 1995 Hamish Macdonald
+ */
+
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/traps.h>
+#include <asm/io.h>
+
+void cache_clear(unsigned long paddr, int len)
+{
+}
+
+
+void cache_push(unsigned long paddr, int len)
+{
+}
+
+void cache_push_v(unsigned long vaddr, int len)
+{
+}
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+
+unsigned long kernel_map(unsigned long paddr, unsigned long size,
+ int nocacheflag, unsigned long *memavailp)
+{
+ return paddr;
+}
diff --git a/arch/hexagon/include/asm/Kbuild b/arch/hexagon/include/asm/Kbuild
index c7a99f860b40..5ade4a163558 100644
--- a/arch/hexagon/include/asm/Kbuild
+++ b/arch/hexagon/include/asm/Kbuild
@@ -37,7 +37,6 @@ generic-y += posix_types.h
generic-y += preempt.h
generic-y += resource.h
generic-y += rwsem.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += segment.h
generic-y += sembuf.h
diff --git a/arch/hexagon/include/asm/cmpxchg.h b/arch/hexagon/include/asm/cmpxchg.h
index 9e7802911a57..a6e34e2acbba 100644
--- a/arch/hexagon/include/asm/cmpxchg.h
+++ b/arch/hexagon/include/asm/cmpxchg.h
@@ -64,7 +64,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
* looks just like atomic_cmpxchg on our arch currently with a bunch of
* variable casting.
*/
-#define __HAVE_ARCH_CMPXCHG 1
#define cmpxchg(ptr, old, new) \
({ \
diff --git a/arch/hexagon/include/asm/mm-arch-hooks.h b/arch/hexagon/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..05e8b939e416
--- /dev/null
+++ b/arch/hexagon/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_HEXAGON_MM_ARCH_HOOKS_H
+#define _ASM_HEXAGON_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_HEXAGON_MM_ARCH_HOOKS_H */
diff --git a/arch/hexagon/include/asm/uaccess.h b/arch/hexagon/include/asm/uaccess.h
index e4127e4d6a5b..f000a382bc7f 100644
--- a/arch/hexagon/include/asm/uaccess.h
+++ b/arch/hexagon/include/asm/uaccess.h
@@ -36,7 +36,8 @@
* @addr: User space pointer to start of block to check
* @size: Size of block to check
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Checks if a pointer to a block of memory in user space is valid.
*
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 76d25b2cfbbe..42a91a7aa2b0 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -137,29 +137,6 @@ config AUDIT_ARCH
bool
default y
-menuconfig PARAVIRT_GUEST
- bool "Paravirtualized guest support"
- depends on BROKEN
- help
- Say Y here to get to see options related to running Linux under
- various hypervisors. This option alone does not add any kernel code.
-
- If you say N, all options in this submenu will be skipped and disabled.
-
-if PARAVIRT_GUEST
-
-config PARAVIRT
- bool "Enable paravirtualization code"
- depends on PARAVIRT_GUEST
- default y
- help
- This changes the kernel so it can modify itself when it is run
- under a hypervisor, potentially improving performance significantly
- over full virtualization. However, when run without a hypervisor
- the kernel is theoretically slower and slightly larger.
-
-endif
-
choice
prompt "System type"
default IA64_GENERIC
diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild
index 9b41b4bcc073..ccff13d33fa2 100644
--- a/arch/ia64/include/asm/Kbuild
+++ b/arch/ia64/include/asm/Kbuild
@@ -5,6 +5,5 @@ generic-y += irq_work.h
generic-y += kvm_para.h
generic-y += mcs_spinlock.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += trace_clock.h
generic-y += vtime.h
diff --git a/arch/ia64/include/asm/barrier.h b/arch/ia64/include/asm/barrier.h
index f6769eb2bbf9..843ba435e43b 100644
--- a/arch/ia64/include/asm/barrier.h
+++ b/arch/ia64/include/asm/barrier.h
@@ -77,12 +77,7 @@ do { \
___p1; \
})
-/*
- * XXX check on this ---I suspect what Linus really wants here is
- * acquire vs release semantics but we can't discuss this stuff with
- * Linus just yet. Grrr...
- */
-#define set_mb(var, value) do { (var) = (value); mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); mb(); } while (0)
/*
* The group barrier in front of the rsm & ssm are necessary to ensure
diff --git a/arch/ia64/include/asm/hugetlb.h b/arch/ia64/include/asm/hugetlb.h
index aa910054b8e7..ef65f026b11e 100644
--- a/arch/ia64/include/asm/hugetlb.h
+++ b/arch/ia64/include/asm/hugetlb.h
@@ -20,10 +20,6 @@ static inline int is_hugepage_only_range(struct mm_struct *mm,
REGION_NUMBER((addr)+(len)-1) == RGN_HPAGE);
}
-static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
-{
-}
-
static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte)
{
@@ -69,15 +65,6 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
return *ptep;
}
-static inline int arch_prepare_hugepage(struct page *page)
-{
- return 0;
-}
-
-static inline void arch_release_hugepage(struct page *page)
-{
-}
-
static inline void arch_clear_hugepage_flags(struct page *page)
{
}
diff --git a/arch/ia64/include/asm/hw_irq.h b/arch/ia64/include/asm/hw_irq.h
index 668786e84af8..74347ebf7d68 100644
--- a/arch/ia64/include/asm/hw_irq.h
+++ b/arch/ia64/include/asm/hw_irq.h
@@ -15,11 +15,7 @@
#include <asm/ptrace.h>
#include <asm/smp.h>
-#ifndef CONFIG_PARAVIRT
typedef u8 ia64_vector;
-#else
-typedef u16 ia64_vector;
-#endif
/*
* 0 special
@@ -114,15 +110,11 @@ DECLARE_PER_CPU(int[IA64_NUM_VECTORS], vector_irq);
extern struct irq_chip irq_type_ia64_lsapic; /* CPU-internal interrupt controller */
-#ifdef CONFIG_PARAVIRT_GUEST
-#include <asm/paravirt.h>
-#else
#define ia64_register_ipi ia64_native_register_ipi
#define assign_irq_vector ia64_native_assign_irq_vector
#define free_irq_vector ia64_native_free_irq_vector
#define register_percpu_irq ia64_native_register_percpu_irq
#define ia64_resend_irq ia64_native_resend_irq
-#endif
extern void ia64_native_register_ipi(void);
extern int bind_irq_vector(int irq, int vector, cpumask_t domain);
diff --git a/arch/ia64/include/asm/intrinsics.h b/arch/ia64/include/asm/intrinsics.h
index 20477ea111ba..ec970a920132 100644
--- a/arch/ia64/include/asm/intrinsics.h
+++ b/arch/ia64/include/asm/intrinsics.h
@@ -7,19 +7,6 @@
#ifndef _ASM_IA64_INTRINSICS_H
#define _ASM_IA64_INTRINSICS_H
-#include <asm/paravirt_privop.h>
#include <uapi/asm/intrinsics.h>
-#ifndef __ASSEMBLY__
-#if defined(CONFIG_PARAVIRT)
-# undef IA64_INTRINSIC_API
-# undef IA64_INTRINSIC_MACRO
-# ifdef ASM_SUPPORTED
-# define IA64_INTRINSIC_API(name) paravirt_ ## name
-# else
-# define IA64_INTRINSIC_API(name) pv_cpu_ops.name
-# endif
-#define IA64_INTRINSIC_MACRO(name) paravirt_ ## name
-#endif
-#endif /* !__ASSEMBLY__ */
#endif /* _ASM_IA64_INTRINSICS_H */
diff --git a/arch/ia64/include/asm/iosapic.h b/arch/ia64/include/asm/iosapic.h
index 94c89a2d97fe..4ae1fbd7f10e 100644
--- a/arch/ia64/include/asm/iosapic.h
+++ b/arch/ia64/include/asm/iosapic.h
@@ -55,14 +55,10 @@
#define NR_IOSAPICS 256
-#ifdef CONFIG_PARAVIRT_GUEST
-#include <asm/paravirt.h>
-#else
#define iosapic_pcat_compat_init ia64_native_iosapic_pcat_compat_init
#define __iosapic_read __ia64_native_iosapic_read
#define __iosapic_write __ia64_native_iosapic_write
#define iosapic_get_irq_chip ia64_native_iosapic_get_irq_chip
-#endif
extern void __init ia64_native_iosapic_pcat_compat_init(void);
extern struct irq_chip *ia64_native_iosapic_get_irq_chip(unsigned long trigger);
diff --git a/arch/ia64/include/asm/irq_remapping.h b/arch/ia64/include/asm/irq_remapping.h
index e3b3556e2e1b..a8687b1d8906 100644
--- a/arch/ia64/include/asm/irq_remapping.h
+++ b/arch/ia64/include/asm/irq_remapping.h
@@ -1,6 +1,4 @@
#ifndef __IA64_INTR_REMAPPING_H
#define __IA64_INTR_REMAPPING_H
#define irq_remapping_enabled 0
-#define dmar_alloc_hwirq create_irq
-#define dmar_free_hwirq destroy_irq
#endif
diff --git a/arch/ia64/include/asm/mm-arch-hooks.h b/arch/ia64/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..ab4b5c698322
--- /dev/null
+++ b/arch/ia64/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_IA64_MM_ARCH_HOOKS_H
+#define _ASM_IA64_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_IA64_MM_ARCH_HOOKS_H */
diff --git a/arch/ia64/include/asm/module.h b/arch/ia64/include/asm/module.h
index dfba22a872c3..f31894b2a354 100644
--- a/arch/ia64/include/asm/module.h
+++ b/arch/ia64/include/asm/module.h
@@ -18,12 +18,6 @@ struct mod_arch_specific {
struct elf64_shdr *got; /* global offset table */
struct elf64_shdr *opd; /* official procedure descriptors */
struct elf64_shdr *unwind; /* unwind-table section */
-#ifdef CONFIG_PARAVIRT
- struct elf64_shdr *paravirt_bundles;
- /* paravirt_alt_bundle_patch table */
- struct elf64_shdr *paravirt_insts;
- /* paravirt_alt_inst_patch table */
-#endif
unsigned long gp; /* global-pointer for module */
void *core_unw_table; /* core unwind-table cookie returned by unwinder */
diff --git a/arch/ia64/include/asm/native/inst.h b/arch/ia64/include/asm/native/inst.h
index d2d46efb3e6e..7e08f17accd5 100644
--- a/arch/ia64/include/asm/native/inst.h
+++ b/arch/ia64/include/asm/native/inst.h
@@ -22,32 +22,6 @@
#define DO_SAVE_MIN IA64_NATIVE_DO_SAVE_MIN
-#define __paravirt_switch_to ia64_native_switch_to
-#define __paravirt_leave_syscall ia64_native_leave_syscall
-#define __paravirt_work_processed_syscall ia64_native_work_processed_syscall
-#define __paravirt_leave_kernel ia64_native_leave_kernel
-#define __paravirt_pending_syscall_end ia64_work_pending_syscall_end
-#define __paravirt_work_processed_syscall_target \
- ia64_work_processed_syscall
-
-#define paravirt_fsyscall_table ia64_native_fsyscall_table
-#define paravirt_fsys_bubble_down ia64_native_fsys_bubble_down
-
-#ifdef CONFIG_PARAVIRT_GUEST_ASM_CLOBBER_CHECK
-# define PARAVIRT_POISON 0xdeadbeefbaadf00d
-# define CLOBBER(clob) \
- ;; \
- movl clob = PARAVIRT_POISON; \
- ;;
-# define CLOBBER_PRED(pred_clob) \
- ;; \
- cmp.eq pred_clob, p0 = r0, r0 \
- ;;
-#else
-# define CLOBBER(clob) /* nothing */
-# define CLOBBER_PRED(pred_clob) /* nothing */
-#endif
-
#define MOV_FROM_IFA(reg) \
mov reg = cr.ifa
@@ -70,106 +44,76 @@
mov reg = cr.iip
#define MOV_FROM_IVR(reg, clob) \
- mov reg = cr.ivr \
- CLOBBER(clob)
+ mov reg = cr.ivr
#define MOV_FROM_PSR(pred, reg, clob) \
-(pred) mov reg = psr \
- CLOBBER(clob)
+(pred) mov reg = psr
#define MOV_FROM_ITC(pred, pred_clob, reg, clob) \
-(pred) mov reg = ar.itc \
- CLOBBER(clob) \
- CLOBBER_PRED(pred_clob)
+(pred) mov reg = ar.itc
#define MOV_TO_IFA(reg, clob) \
- mov cr.ifa = reg \
- CLOBBER(clob)
+ mov cr.ifa = reg
#define MOV_TO_ITIR(pred, reg, clob) \
-(pred) mov cr.itir = reg \
- CLOBBER(clob)
+(pred) mov cr.itir = reg
#define MOV_TO_IHA(pred, reg, clob) \
-(pred) mov cr.iha = reg \
- CLOBBER(clob)
+(pred) mov cr.iha = reg
#define MOV_TO_IPSR(pred, reg, clob) \
-(pred) mov cr.ipsr = reg \
- CLOBBER(clob)
+(pred) mov cr.ipsr = reg
#define MOV_TO_IFS(pred, reg, clob) \
-(pred) mov cr.ifs = reg \
- CLOBBER(clob)
+(pred) mov cr.ifs = reg
#define MOV_TO_IIP(reg, clob) \
- mov cr.iip = reg \
- CLOBBER(clob)
+ mov cr.iip = reg
#define MOV_TO_KR(kr, reg, clob0, clob1) \
- mov IA64_KR(kr) = reg \
- CLOBBER(clob0) \
- CLOBBER(clob1)
+ mov IA64_KR(kr) = reg
#define ITC_I(pred, reg, clob) \
-(pred) itc.i reg \
- CLOBBER(clob)
+(pred) itc.i reg
#define ITC_D(pred, reg, clob) \
-(pred) itc.d reg \
- CLOBBER(clob)
+(pred) itc.d reg
#define ITC_I_AND_D(pred_i, pred_d, reg, clob) \
(pred_i) itc.i reg; \
-(pred_d) itc.d reg \
- CLOBBER(clob)
+(pred_d) itc.d reg
#define THASH(pred, reg0, reg1, clob) \
-(pred) thash reg0 = reg1 \
- CLOBBER(clob)
+(pred) thash reg0 = reg1
#define SSM_PSR_IC_AND_DEFAULT_BITS_AND_SRLZ_I(clob0, clob1) \
ssm psr.ic | PSR_DEFAULT_BITS \
- CLOBBER(clob0) \
- CLOBBER(clob1) \
;; \
srlz.i /* guarantee that interruption collectin is on */ \
;;
#define SSM_PSR_IC_AND_SRLZ_D(clob0, clob1) \
ssm psr.ic \
- CLOBBER(clob0) \
- CLOBBER(clob1) \
;; \
srlz.d
#define RSM_PSR_IC(clob) \
- rsm psr.ic \
- CLOBBER(clob)
+ rsm psr.ic
#define SSM_PSR_I(pred, pred_clob, clob) \
-(pred) ssm psr.i \
- CLOBBER(clob) \
- CLOBBER_PRED(pred_clob)
+(pred) ssm psr.i
#define RSM_PSR_I(pred, clob0, clob1) \
-(pred) rsm psr.i \
- CLOBBER(clob0) \
- CLOBBER(clob1)
+(pred) rsm psr.i
#define RSM_PSR_I_IC(clob0, clob1, clob2) \
- rsm psr.i | psr.ic \
- CLOBBER(clob0) \
- CLOBBER(clob1) \
- CLOBBER(clob2)
+ rsm psr.i | psr.ic
#define RSM_PSR_DT \
rsm psr.dt
#define RSM_PSR_BE_I(clob0, clob1) \
- rsm psr.be | psr.i \
- CLOBBER(clob0) \
- CLOBBER(clob1)
+ rsm psr.be | psr.i
#define SSM_PSR_DT_AND_SRLZ_I \
ssm psr.dt \
@@ -177,15 +121,10 @@
srlz.i
#define BSW_0(clob0, clob1, clob2) \
- bsw.0 \
- CLOBBER(clob0) \
- CLOBBER(clob1) \
- CLOBBER(clob2)
+ bsw.0
#define BSW_1(clob0, clob1) \
- bsw.1 \
- CLOBBER(clob0) \
- CLOBBER(clob1)
+ bsw.1
#define COVER \
cover
diff --git a/arch/ia64/include/asm/native/pvchk_inst.h b/arch/ia64/include/asm/native/pvchk_inst.h
deleted file mode 100644
index 8d72962ec838..000000000000
--- a/arch/ia64/include/asm/native/pvchk_inst.h
+++ /dev/null
@@ -1,271 +0,0 @@
-#ifndef _ASM_NATIVE_PVCHK_INST_H
-#define _ASM_NATIVE_PVCHK_INST_H
-
-/******************************************************************************
- * arch/ia64/include/asm/native/pvchk_inst.h
- * Checker for paravirtualizations of privileged operations.
- *
- * Copyright (C) 2005 Hewlett-Packard Co
- * Dan Magenheimer <dan.magenheimer@hp.com>
- *
- * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * 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
- *
- */
-
-/**********************************************
- * Instructions paravirtualized for correctness
- **********************************************/
-
-/* "fc" and "thash" are privilege-sensitive instructions, meaning they
- * may have different semantics depending on whether they are executed
- * at PL0 vs PL!=0. When paravirtualized, these instructions mustn't
- * be allowed to execute directly, lest incorrect semantics result.
- */
-
-#define fc .error "fc should not be used directly."
-#define thash .error "thash should not be used directly."
-
-/* Note that "ttag" and "cover" are also privilege-sensitive; "ttag"
- * is not currently used (though it may be in a long-format VHPT system!)
- * and the semantics of cover only change if psr.ic is off which is very
- * rare (and currently non-existent outside of assembly code
- */
-#define ttag .error "ttag should not be used directly."
-#define cover .error "cover should not be used directly."
-
-/* There are also privilege-sensitive registers. These registers are
- * readable at any privilege level but only writable at PL0.
- */
-#define cpuid .error "cpuid should not be used directly."
-#define pmd .error "pmd should not be used directly."
-
-/*
- * mov ar.eflag =
- * mov = ar.eflag
- */
-
-/**********************************************
- * Instructions paravirtualized for performance
- **********************************************/
-/*
- * Those instructions include '.' which can't be handled by cpp.
- * or can't be handled by cpp easily.
- * They are handled by sed instead of cpp.
- */
-
-/* for .S
- * itc.i
- * itc.d
- *
- * bsw.0
- * bsw.1
- *
- * ssm psr.ic | PSR_DEFAULT_BITS
- * ssm psr.ic
- * rsm psr.ic
- * ssm psr.i
- * rsm psr.i
- * rsm psr.i | psr.ic
- * rsm psr.dt
- * ssm psr.dt
- *
- * mov = cr.ifa
- * mov = cr.itir
- * mov = cr.isr
- * mov = cr.iha
- * mov = cr.ipsr
- * mov = cr.iim
- * mov = cr.iip
- * mov = cr.ivr
- * mov = psr
- *
- * mov cr.ifa =
- * mov cr.itir =
- * mov cr.iha =
- * mov cr.ipsr =
- * mov cr.ifs =
- * mov cr.iip =
- * mov cr.kr =
- */
-
-/* for intrinsics
- * ssm psr.i
- * rsm psr.i
- * mov = psr
- * mov = ivr
- * mov = tpr
- * mov cr.itm =
- * mov eoi =
- * mov rr[] =
- * mov = rr[]
- * mov = kr
- * mov kr =
- * ptc.ga
- */
-
-/*************************************************************
- * define paravirtualized instrcution macros as nop to ingore.
- * and check whether arguments are appropriate.
- *************************************************************/
-
-/* check whether reg is a regular register */
-.macro is_rreg_in reg
- .ifc "\reg", "r0"
- nop 0
- .exitm
- .endif
- ;;
- mov \reg = r0
- ;;
-.endm
-#define IS_RREG_IN(reg) is_rreg_in reg ;
-
-#define IS_RREG_OUT(reg) \
- ;; \
- mov reg = r0 \
- ;;
-
-#define IS_RREG_CLOB(reg) IS_RREG_OUT(reg)
-
-/* check whether pred is a predicate register */
-#define IS_PRED_IN(pred) \
- ;; \
- (pred) nop 0 \
- ;;
-
-#define IS_PRED_OUT(pred) \
- ;; \
- cmp.eq pred, p0 = r0, r0 \
- ;;
-
-#define IS_PRED_CLOB(pred) IS_PRED_OUT(pred)
-
-
-#define DO_SAVE_MIN(__COVER, SAVE_IFS, EXTRA, WORKAROUND) \
- nop 0
-#define MOV_FROM_IFA(reg) \
- IS_RREG_OUT(reg)
-#define MOV_FROM_ITIR(reg) \
- IS_RREG_OUT(reg)
-#define MOV_FROM_ISR(reg) \
- IS_RREG_OUT(reg)
-#define MOV_FROM_IHA(reg) \
- IS_RREG_OUT(reg)
-#define MOV_FROM_IPSR(pred, reg) \
- IS_PRED_IN(pred) \
- IS_RREG_OUT(reg)
-#define MOV_FROM_IIM(reg) \
- IS_RREG_OUT(reg)
-#define MOV_FROM_IIP(reg) \
- IS_RREG_OUT(reg)
-#define MOV_FROM_IVR(reg, clob) \
- IS_RREG_OUT(reg) \
- IS_RREG_CLOB(clob)
-#define MOV_FROM_PSR(pred, reg, clob) \
- IS_PRED_IN(pred) \
- IS_RREG_OUT(reg) \
- IS_RREG_CLOB(clob)
-#define MOV_FROM_ITC(pred, pred_clob, reg, clob) \
- IS_PRED_IN(pred) \
- IS_PRED_CLOB(pred_clob) \
- IS_RREG_OUT(reg) \
- IS_RREG_CLOB(clob)
-#define MOV_TO_IFA(reg, clob) \
- IS_RREG_IN(reg) \
- IS_RREG_CLOB(clob)
-#define MOV_TO_ITIR(pred, reg, clob) \
- IS_PRED_IN(pred) \
- IS_RREG_IN(reg) \
- IS_RREG_CLOB(clob)
-#define MOV_TO_IHA(pred, reg, clob) \
- IS_PRED_IN(pred) \
- IS_RREG_IN(reg) \
- IS_RREG_CLOB(clob)
-#define MOV_TO_IPSR(pred, reg, clob) \
- IS_PRED_IN(pred) \
- IS_RREG_IN(reg) \
- IS_RREG_CLOB(clob)
-#define MOV_TO_IFS(pred, reg, clob) \
- IS_PRED_IN(pred) \
- IS_RREG_IN(reg) \
- IS_RREG_CLOB(clob)
-#define MOV_TO_IIP(reg, clob) \
- IS_RREG_IN(reg) \
- IS_RREG_CLOB(clob)
-#define MOV_TO_KR(kr, reg, clob0, clob1) \
- IS_RREG_IN(reg) \
- IS_RREG_CLOB(clob0) \
- IS_RREG_CLOB(clob1)
-#define ITC_I(pred, reg, clob) \
- IS_PRED_IN(pred) \
- IS_RREG_IN(reg) \
- IS_RREG_CLOB(clob)
-#define ITC_D(pred, reg, clob) \
- IS_PRED_IN(pred) \
- IS_RREG_IN(reg) \
- IS_RREG_CLOB(clob)
-#define ITC_I_AND_D(pred_i, pred_d, reg, clob) \
- IS_PRED_IN(pred_i) \
- IS_PRED_IN(pred_d) \
- IS_RREG_IN(reg) \
- IS_RREG_CLOB(clob)
-#define THASH(pred, reg0, reg1, clob) \
- IS_PRED_IN(pred) \
- IS_RREG_OUT(reg0) \
- IS_RREG_IN(reg1) \
- IS_RREG_CLOB(clob)
-#define SSM_PSR_IC_AND_DEFAULT_BITS_AND_SRLZ_I(clob0, clob1) \
- IS_RREG_CLOB(clob0) \
- IS_RREG_CLOB(clob1)
-#define SSM_PSR_IC_AND_SRLZ_D(clob0, clob1) \
- IS_RREG_CLOB(clob0) \
- IS_RREG_CLOB(clob1)
-#define RSM_PSR_IC(clob) \
- IS_RREG_CLOB(clob)
-#define SSM_PSR_I(pred, pred_clob, clob) \
- IS_PRED_IN(pred) \
- IS_PRED_CLOB(pred_clob) \
- IS_RREG_CLOB(clob)
-#define RSM_PSR_I(pred, clob0, clob1) \
- IS_PRED_IN(pred) \
- IS_RREG_CLOB(clob0) \
- IS_RREG_CLOB(clob1)
-#define RSM_PSR_I_IC(clob0, clob1, clob2) \
- IS_RREG_CLOB(clob0) \
- IS_RREG_CLOB(clob1) \
- IS_RREG_CLOB(clob2)
-#define RSM_PSR_DT \
- nop 0
-#define RSM_PSR_BE_I(clob0, clob1) \
- IS_RREG_CLOB(clob0) \
- IS_RREG_CLOB(clob1)
-#define SSM_PSR_DT_AND_SRLZ_I \
- nop 0
-#define BSW_0(clob0, clob1, clob2) \
- IS_RREG_CLOB(clob0) \
- IS_RREG_CLOB(clob1) \
- IS_RREG_CLOB(clob2)
-#define BSW_1(clob0, clob1) \
- IS_RREG_CLOB(clob0) \
- IS_RREG_CLOB(clob1)
-#define COVER \
- nop 0
-#define RFI \
- br.ret.sptk.many rp /* defining nop causes dependency error */
-
-#endif /* _ASM_NATIVE_PVCHK_INST_H */
diff --git a/arch/ia64/include/asm/paravirt.h b/arch/ia64/include/asm/paravirt.h
deleted file mode 100644
index b53518a98026..000000000000
--- a/arch/ia64/include/asm/paravirt.h
+++ /dev/null
@@ -1,321 +0,0 @@
-/******************************************************************************
- * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * 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_PARAVIRT_H
-#define __ASM_PARAVIRT_H
-
-#ifndef __ASSEMBLY__
-/******************************************************************************
- * fsys related addresses
- */
-struct pv_fsys_data {
- unsigned long *fsyscall_table;
- void *fsys_bubble_down;
-};
-
-extern struct pv_fsys_data pv_fsys_data;
-
-unsigned long *paravirt_get_fsyscall_table(void);
-char *paravirt_get_fsys_bubble_down(void);
-
-/******************************************************************************
- * patchlist addresses for gate page
- */
-enum pv_gate_patchlist {
- PV_GATE_START_FSYSCALL,
- PV_GATE_END_FSYSCALL,
-
- PV_GATE_START_BRL_FSYS_BUBBLE_DOWN,
- PV_GATE_END_BRL_FSYS_BUBBLE_DOWN,
-
- PV_GATE_START_VTOP,
- PV_GATE_END_VTOP,
-
- PV_GATE_START_MCKINLEY_E9,
- PV_GATE_END_MCKINLEY_E9,
-};
-
-struct pv_patchdata {
- unsigned long start_fsyscall_patchlist;
- unsigned long end_fsyscall_patchlist;
- unsigned long start_brl_fsys_bubble_down_patchlist;
- unsigned long end_brl_fsys_bubble_down_patchlist;
- unsigned long start_vtop_patchlist;
- unsigned long end_vtop_patchlist;
- unsigned long start_mckinley_e9_patchlist;
- unsigned long end_mckinley_e9_patchlist;
-
- void *gate_section;
-};
-
-extern struct pv_patchdata pv_patchdata;
-
-unsigned long paravirt_get_gate_patchlist(enum pv_gate_patchlist type);
-void *paravirt_get_gate_section(void);
-#endif
-
-#ifdef CONFIG_PARAVIRT_GUEST
-
-#define PARAVIRT_HYPERVISOR_TYPE_DEFAULT 0
-
-#ifndef __ASSEMBLY__
-
-#include <asm/hw_irq.h>
-#include <asm/meminit.h>
-
-/******************************************************************************
- * general info
- */
-struct pv_info {
- unsigned int kernel_rpl;
- int paravirt_enabled;
- const char *name;
-};
-
-extern struct pv_info pv_info;
-
-static inline int paravirt_enabled(void)
-{
- return pv_info.paravirt_enabled;
-}
-
-static inline unsigned int get_kernel_rpl(void)
-{
- return pv_info.kernel_rpl;
-}
-
-/******************************************************************************
- * initialization hooks.
- */
-struct rsvd_region;
-
-struct pv_init_ops {
- void (*banner)(void);
-
- int (*reserve_memory)(struct rsvd_region *region);
-
- void (*arch_setup_early)(void);
- void (*arch_setup_console)(char **cmdline_p);
- int (*arch_setup_nomca)(void);
-
- void (*post_smp_prepare_boot_cpu)(void);
-
-#ifdef ASM_SUPPORTED
- unsigned long (*patch_bundle)(void *sbundle, void *ebundle,
- unsigned long type);
- unsigned long (*patch_inst)(unsigned long stag, unsigned long etag,
- unsigned long type);
-#endif
- void (*patch_branch)(unsigned long tag, unsigned long type);
-};
-
-extern struct pv_init_ops pv_init_ops;
-
-static inline void paravirt_banner(void)
-{
- if (pv_init_ops.banner)
- pv_init_ops.banner();
-}
-
-static inline int paravirt_reserve_memory(struct rsvd_region *region)
-{
- if (pv_init_ops.reserve_memory)
- return pv_init_ops.reserve_memory(region);
- return 0;
-}
-
-static inline void paravirt_arch_setup_early(void)
-{
- if (pv_init_ops.arch_setup_early)
- pv_init_ops.arch_setup_early();
-}
-
-static inline void paravirt_arch_setup_console(char **cmdline_p)
-{
- if (pv_init_ops.arch_setup_console)
- pv_init_ops.arch_setup_console(cmdline_p);
-}
-
-static inline int paravirt_arch_setup_nomca(void)
-{
- if (pv_init_ops.arch_setup_nomca)
- return pv_init_ops.arch_setup_nomca();
- return 0;
-}
-
-static inline void paravirt_post_smp_prepare_boot_cpu(void)
-{
- if (pv_init_ops.post_smp_prepare_boot_cpu)
- pv_init_ops.post_smp_prepare_boot_cpu();
-}
-
-/******************************************************************************
- * replacement of iosapic operations.
- */
-
-struct pv_iosapic_ops {
- void (*pcat_compat_init)(void);
-
- struct irq_chip *(*__get_irq_chip)(unsigned long trigger);
-
- unsigned int (*__read)(char __iomem *iosapic, unsigned int reg);
- void (*__write)(char __iomem *iosapic, unsigned int reg, u32 val);
-};
-
-extern struct pv_iosapic_ops pv_iosapic_ops;
-
-static inline void
-iosapic_pcat_compat_init(void)
-{
- if (pv_iosapic_ops.pcat_compat_init)
- pv_iosapic_ops.pcat_compat_init();
-}
-
-static inline struct irq_chip*
-iosapic_get_irq_chip(unsigned long trigger)
-{
- return pv_iosapic_ops.__get_irq_chip(trigger);
-}
-
-static inline unsigned int
-__iosapic_read(char __iomem *iosapic, unsigned int reg)
-{
- return pv_iosapic_ops.__read(iosapic, reg);
-}
-
-static inline void
-__iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
-{
- return pv_iosapic_ops.__write(iosapic, reg, val);
-}
-
-/******************************************************************************
- * replacement of irq operations.
- */
-
-struct pv_irq_ops {
- void (*register_ipi)(void);
-
- int (*assign_irq_vector)(int irq);
- void (*free_irq_vector)(int vector);
-
- void (*register_percpu_irq)(ia64_vector vec,
- struct irqaction *action);
-
- void (*resend_irq)(unsigned int vector);
-};
-
-extern struct pv_irq_ops pv_irq_ops;
-
-static inline void
-ia64_register_ipi(void)
-{
- pv_irq_ops.register_ipi();
-}
-
-static inline int
-assign_irq_vector(int irq)
-{
- return pv_irq_ops.assign_irq_vector(irq);
-}
-
-static inline void
-free_irq_vector(int vector)
-{
- return pv_irq_ops.free_irq_vector(vector);
-}
-
-static inline void
-register_percpu_irq(ia64_vector vec, struct irqaction *action)
-{
- pv_irq_ops.register_percpu_irq(vec, action);
-}
-
-static inline void
-ia64_resend_irq(unsigned int vector)
-{
- pv_irq_ops.resend_irq(vector);
-}
-
-/******************************************************************************
- * replacement of time operations.
- */
-
-extern struct itc_jitter_data_t itc_jitter_data;
-extern volatile int time_keeper_id;
-
-struct pv_time_ops {
- void (*init_missing_ticks_accounting)(int cpu);
- int (*do_steal_accounting)(unsigned long *new_itm);
-
- void (*clocksource_resume)(void);
-
- unsigned long long (*sched_clock)(void);
-};
-
-extern struct pv_time_ops pv_time_ops;
-
-static inline void
-paravirt_init_missing_ticks_accounting(int cpu)
-{
- if (pv_time_ops.init_missing_ticks_accounting)
- pv_time_ops.init_missing_ticks_accounting(cpu);
-}
-
-struct static_key;
-extern struct static_key paravirt_steal_enabled;
-extern struct static_key paravirt_steal_rq_enabled;
-
-static inline int
-paravirt_do_steal_accounting(unsigned long *new_itm)
-{
- return pv_time_ops.do_steal_accounting(new_itm);
-}
-
-static inline unsigned long long paravirt_sched_clock(void)
-{
- return pv_time_ops.sched_clock();
-}
-
-#endif /* !__ASSEMBLY__ */
-
-#else
-/* fallback for native case */
-
-#ifndef __ASSEMBLY__
-
-#define paravirt_banner() do { } while (0)
-#define paravirt_reserve_memory(region) 0
-
-#define paravirt_arch_setup_early() do { } while (0)
-#define paravirt_arch_setup_console(cmdline_p) do { } while (0)
-#define paravirt_arch_setup_nomca() 0
-#define paravirt_post_smp_prepare_boot_cpu() do { } while (0)
-
-#define paravirt_init_missing_ticks_accounting(cpu) do { } while (0)
-#define paravirt_do_steal_accounting(new_itm) 0
-
-#endif /* __ASSEMBLY__ */
-
-
-#endif /* CONFIG_PARAVIRT_GUEST */
-
-#endif /* __ASM_PARAVIRT_H */
diff --git a/arch/ia64/include/asm/paravirt_patch.h b/arch/ia64/include/asm/paravirt_patch.h
deleted file mode 100644
index 128ff5db6e67..000000000000
--- a/arch/ia64/include/asm/paravirt_patch.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/******************************************************************************
- * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * 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_PARAVIRT_PATCH_H
-#define __ASM_PARAVIRT_PATCH_H
-
-#ifdef __ASSEMBLY__
-
- .section .paravirt_branches, "a"
- .previous
-#define PARAVIRT_PATCH_SITE_BR(type) \
- { \
- [1:] ; \
- br.cond.sptk.many 2f ; \
- nop.b 0 ; \
- nop.b 0;; ; \
- } ; \
- 2: \
- .xdata8 ".paravirt_branches", 1b, type
-
-#else
-
-#include <linux/stringify.h>
-#include <asm/intrinsics.h>
-
-/* for binary patch */
-struct paravirt_patch_site_bundle {
- void *sbundle;
- void *ebundle;
- unsigned long type;
-};
-
-/* label means the beginning of new bundle */
-#define paravirt_alt_bundle(instr, privop) \
- "\t998:\n" \
- "\t" instr "\n" \
- "\t999:\n" \
- "\t.pushsection .paravirt_bundles, \"a\"\n" \
- "\t.popsection\n" \
- "\t.xdata8 \".paravirt_bundles\", 998b, 999b, " \
- __stringify(privop) "\n"
-
-
-struct paravirt_patch_bundle_elem {
- const void *sbundle;
- const void *ebundle;
- unsigned long type;
-};
-
-
-struct paravirt_patch_site_inst {
- unsigned long stag;
- unsigned long etag;
- unsigned long type;
-};
-
-#define paravirt_alt_inst(instr, privop) \
- "\t[998:]\n" \
- "\t" instr "\n" \
- "\t[999:]\n" \
- "\t.pushsection .paravirt_insts, \"a\"\n" \
- "\t.popsection\n" \
- "\t.xdata8 \".paravirt_insts\", 998b, 999b, " \
- __stringify(privop) "\n"
-
-struct paravirt_patch_site_branch {
- unsigned long tag;
- unsigned long type;
-};
-
-struct paravirt_patch_branch_target {
- const void *entry;
- unsigned long type;
-};
-
-void
-__paravirt_patch_apply_branch(
- unsigned long tag, unsigned long type,
- const struct paravirt_patch_branch_target *entries,
- unsigned int nr_entries);
-
-void
-paravirt_patch_reloc_br(unsigned long tag, const void *target);
-
-void
-paravirt_patch_reloc_brl(unsigned long tag, const void *target);
-
-
-#if defined(ASM_SUPPORTED) && defined(CONFIG_PARAVIRT)
-unsigned long
-ia64_native_patch_bundle(void *sbundle, void *ebundle, unsigned long type);
-
-unsigned long
-__paravirt_patch_apply_bundle(void *sbundle, void *ebundle, unsigned long type,
- const struct paravirt_patch_bundle_elem *elems,
- unsigned long nelems,
- const struct paravirt_patch_bundle_elem **found);
-
-void
-paravirt_patch_apply_bundle(const struct paravirt_patch_site_bundle *start,
- const struct paravirt_patch_site_bundle *end);
-
-void
-paravirt_patch_apply_inst(const struct paravirt_patch_site_inst *start,
- const struct paravirt_patch_site_inst *end);
-
-void paravirt_patch_apply(void);
-#else
-#define paravirt_patch_apply_bundle(start, end) do { } while (0)
-#define paravirt_patch_apply_inst(start, end) do { } while (0)
-#define paravirt_patch_apply() do { } while (0)
-#endif
-
-#endif /* !__ASSEMBLEY__ */
-
-#endif /* __ASM_PARAVIRT_PATCH_H */
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "linux"
- * c-basic-offset: 8
- * tab-width: 8
- * indent-tabs-mode: t
- * End:
- */
diff --git a/arch/ia64/include/asm/paravirt_privop.h b/arch/ia64/include/asm/paravirt_privop.h
deleted file mode 100644
index 8f6cb11c9fae..000000000000
--- a/arch/ia64/include/asm/paravirt_privop.h
+++ /dev/null
@@ -1,479 +0,0 @@
-/******************************************************************************
- * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * 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_IA64_PARAVIRT_PRIVOP_H
-#define _ASM_IA64_PARAVIRT_PRIVOP_H
-
-#ifdef CONFIG_PARAVIRT
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-#include <asm/kregs.h> /* for IA64_PSR_I */
-
-/******************************************************************************
- * replacement of intrinsics operations.
- */
-
-struct pv_cpu_ops {
- void (*fc)(void *addr);
- unsigned long (*thash)(unsigned long addr);
- unsigned long (*get_cpuid)(int index);
- unsigned long (*get_pmd)(int index);
- unsigned long (*getreg)(int reg);
- void (*setreg)(int reg, unsigned long val);
- void (*ptcga)(unsigned long addr, unsigned long size);
- unsigned long (*get_rr)(unsigned long index);
- void (*set_rr)(unsigned long index, unsigned long val);
- void (*set_rr0_to_rr4)(unsigned long val0, unsigned long val1,
- unsigned long val2, unsigned long val3,
- unsigned long val4);
- void (*ssm_i)(void);
- void (*rsm_i)(void);
- unsigned long (*get_psr_i)(void);
- void (*intrin_local_irq_restore)(unsigned long flags);
-};
-
-extern struct pv_cpu_ops pv_cpu_ops;
-
-extern void ia64_native_setreg_func(int regnum, unsigned long val);
-extern unsigned long ia64_native_getreg_func(int regnum);
-
-/************************************************/
-/* Instructions paravirtualized for performance */
-/************************************************/
-
-#ifndef ASM_SUPPORTED
-#define paravirt_ssm_i() pv_cpu_ops.ssm_i()
-#define paravirt_rsm_i() pv_cpu_ops.rsm_i()
-#define __paravirt_getreg() pv_cpu_ops.getreg()
-#endif
-
-/* mask for ia64_native_ssm/rsm() must be constant.("i" constraing).
- * static inline function doesn't satisfy it. */
-#define paravirt_ssm(mask) \
- do { \
- if ((mask) == IA64_PSR_I) \
- paravirt_ssm_i(); \
- else \
- ia64_native_ssm(mask); \
- } while (0)
-
-#define paravirt_rsm(mask) \
- do { \
- if ((mask) == IA64_PSR_I) \
- paravirt_rsm_i(); \
- else \
- ia64_native_rsm(mask); \
- } while (0)
-
-/* returned ip value should be the one in the caller,
- * not in __paravirt_getreg() */
-#define paravirt_getreg(reg) \
- ({ \
- unsigned long res; \
- if ((reg) == _IA64_REG_IP) \
- res = ia64_native_getreg(_IA64_REG_IP); \
- else \
- res = __paravirt_getreg(reg); \
- res; \
- })
-
-/******************************************************************************
- * replacement of hand written assembly codes.
- */
-struct pv_cpu_asm_switch {
- unsigned long switch_to;
- unsigned long leave_syscall;
- unsigned long work_processed_syscall;
- unsigned long leave_kernel;
-};
-void paravirt_cpu_asm_init(const struct pv_cpu_asm_switch *cpu_asm_switch);
-
-#endif /* __ASSEMBLY__ */
-
-#define IA64_PARAVIRT_ASM_FUNC(name) paravirt_ ## name
-
-#else
-
-/* fallback for native case */
-#define IA64_PARAVIRT_ASM_FUNC(name) ia64_native_ ## name
-
-#endif /* CONFIG_PARAVIRT */
-
-#if defined(CONFIG_PARAVIRT) && defined(ASM_SUPPORTED)
-#define paravirt_dv_serialize_data() ia64_dv_serialize_data()
-#else
-#define paravirt_dv_serialize_data() /* nothing */
-#endif
-
-/* these routines utilize privilege-sensitive or performance-sensitive
- * privileged instructions so the code must be replaced with
- * paravirtualized versions */
-#define ia64_switch_to IA64_PARAVIRT_ASM_FUNC(switch_to)
-#define ia64_leave_syscall IA64_PARAVIRT_ASM_FUNC(leave_syscall)
-#define ia64_work_processed_syscall \
- IA64_PARAVIRT_ASM_FUNC(work_processed_syscall)
-#define ia64_leave_kernel IA64_PARAVIRT_ASM_FUNC(leave_kernel)
-
-
-#if defined(CONFIG_PARAVIRT)
-/******************************************************************************
- * binary patching infrastructure
- */
-#define PARAVIRT_PATCH_TYPE_FC 1
-#define PARAVIRT_PATCH_TYPE_THASH 2
-#define PARAVIRT_PATCH_TYPE_GET_CPUID 3
-#define PARAVIRT_PATCH_TYPE_GET_PMD 4
-#define PARAVIRT_PATCH_TYPE_PTCGA 5
-#define PARAVIRT_PATCH_TYPE_GET_RR 6
-#define PARAVIRT_PATCH_TYPE_SET_RR 7
-#define PARAVIRT_PATCH_TYPE_SET_RR0_TO_RR4 8
-#define PARAVIRT_PATCH_TYPE_SSM_I 9
-#define PARAVIRT_PATCH_TYPE_RSM_I 10
-#define PARAVIRT_PATCH_TYPE_GET_PSR_I 11
-#define PARAVIRT_PATCH_TYPE_INTRIN_LOCAL_IRQ_RESTORE 12
-
-/* PARAVIRT_PATY_TYPE_[GS]ETREG + _IA64_REG_xxx */
-#define PARAVIRT_PATCH_TYPE_GETREG 0x10000000
-#define PARAVIRT_PATCH_TYPE_SETREG 0x20000000
-
-/*
- * struct task_struct* (*ia64_switch_to)(void* next_task);
- * void *ia64_leave_syscall;
- * void *ia64_work_processed_syscall
- * void *ia64_leave_kernel;
- */
-
-#define PARAVIRT_PATCH_TYPE_BR_START 0x30000000
-#define PARAVIRT_PATCH_TYPE_BR_SWITCH_TO \
- (PARAVIRT_PATCH_TYPE_BR_START + 0)
-#define PARAVIRT_PATCH_TYPE_BR_LEAVE_SYSCALL \
- (PARAVIRT_PATCH_TYPE_BR_START + 1)
-#define PARAVIRT_PATCH_TYPE_BR_WORK_PROCESSED_SYSCALL \
- (PARAVIRT_PATCH_TYPE_BR_START + 2)
-#define PARAVIRT_PATCH_TYPE_BR_LEAVE_KERNEL \
- (PARAVIRT_PATCH_TYPE_BR_START + 3)
-
-#ifdef ASM_SUPPORTED
-#include <asm/paravirt_patch.h>
-
-/*
- * pv_cpu_ops calling stub.
- * normal function call convension can't be written by gcc
- * inline assembly.
- *
- * from the caller's point of view,
- * the following registers will be clobbered.
- * r2, r3
- * r8-r15
- * r16, r17
- * b6, b7
- * p6-p15
- * ar.ccv
- *
- * from the callee's point of view ,
- * the following registers can be used.
- * r2, r3: scratch
- * r8: scratch, input argument0 and return value
- * r0-r15: scratch, input argument1-5
- * b6: return pointer
- * b7: scratch
- * p6-p15: scratch
- * ar.ccv: scratch
- *
- * other registers must not be changed. especially
- * b0: rp: preserved. gcc ignores b0 in clobbered register.
- * r16: saved gp
- */
-/* 5 bundles */
-#define __PARAVIRT_BR \
- ";;\n" \
- "{ .mlx\n" \
- "nop 0\n" \
- "movl r2 = %[op_addr]\n"/* get function pointer address */ \
- ";;\n" \
- "}\n" \
- "1:\n" \
- "{ .mii\n" \
- "ld8 r2 = [r2]\n" /* load function descriptor address */ \
- "mov r17 = ip\n" /* get ip to calc return address */ \
- "mov r16 = gp\n" /* save gp */ \
- ";;\n" \
- "}\n" \
- "{ .mii\n" \
- "ld8 r3 = [r2], 8\n" /* load entry address */ \
- "adds r17 = 1f - 1b, r17\n" /* calculate return address */ \
- ";;\n" \
- "mov b7 = r3\n" /* set entry address */ \
- "}\n" \
- "{ .mib\n" \
- "ld8 gp = [r2]\n" /* load gp value */ \
- "mov b6 = r17\n" /* set return address */ \
- "br.cond.sptk.few b7\n" /* intrinsics are very short isns */ \
- "}\n" \
- "1:\n" \
- "{ .mii\n" \
- "mov gp = r16\n" /* restore gp value */ \
- "nop 0\n" \
- "nop 0\n" \
- ";;\n" \
- "}\n"
-
-#define PARAVIRT_OP(op) \
- [op_addr] "i"(&pv_cpu_ops.op)
-
-#define PARAVIRT_TYPE(type) \
- PARAVIRT_PATCH_TYPE_ ## type
-
-#define PARAVIRT_REG_CLOBBERS0 \
- "r2", "r3", /*"r8",*/ "r9", "r10", "r11", "r14", \
- "r15", "r16", "r17"
-
-#define PARAVIRT_REG_CLOBBERS1 \
- "r2","r3", /*"r8",*/ "r9", "r10", "r11", "r14", \
- "r15", "r16", "r17"
-
-#define PARAVIRT_REG_CLOBBERS2 \
- "r2", "r3", /*"r8", "r9",*/ "r10", "r11", "r14", \
- "r15", "r16", "r17"
-
-#define PARAVIRT_REG_CLOBBERS5 \
- "r2", "r3", /*"r8", "r9", "r10", "r11", "r14",*/ \
- "r15", "r16", "r17"
-
-#define PARAVIRT_BR_CLOBBERS \
- "b6", "b7"
-
-#define PARAVIRT_PR_CLOBBERS \
- "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15"
-
-#define PARAVIRT_AR_CLOBBERS \
- "ar.ccv"
-
-#define PARAVIRT_CLOBBERS0 \
- PARAVIRT_REG_CLOBBERS0, \
- PARAVIRT_BR_CLOBBERS, \
- PARAVIRT_PR_CLOBBERS, \
- PARAVIRT_AR_CLOBBERS, \
- "memory"
-
-#define PARAVIRT_CLOBBERS1 \
- PARAVIRT_REG_CLOBBERS1, \
- PARAVIRT_BR_CLOBBERS, \
- PARAVIRT_PR_CLOBBERS, \
- PARAVIRT_AR_CLOBBERS, \
- "memory"
-
-#define PARAVIRT_CLOBBERS2 \
- PARAVIRT_REG_CLOBBERS2, \
- PARAVIRT_BR_CLOBBERS, \
- PARAVIRT_PR_CLOBBERS, \
- PARAVIRT_AR_CLOBBERS, \
- "memory"
-
-#define PARAVIRT_CLOBBERS5 \
- PARAVIRT_REG_CLOBBERS5, \
- PARAVIRT_BR_CLOBBERS, \
- PARAVIRT_PR_CLOBBERS, \
- PARAVIRT_AR_CLOBBERS, \
- "memory"
-
-#define PARAVIRT_BR0(op, type) \
- register unsigned long ia64_clobber asm ("r8"); \
- asm volatile (paravirt_alt_bundle(__PARAVIRT_BR, \
- PARAVIRT_TYPE(type)) \
- : "=r"(ia64_clobber) \
- : PARAVIRT_OP(op) \
- : PARAVIRT_CLOBBERS0)
-
-#define PARAVIRT_BR0_RET(op, type) \
- register unsigned long ia64_intri_res asm ("r8"); \
- asm volatile (paravirt_alt_bundle(__PARAVIRT_BR, \
- PARAVIRT_TYPE(type)) \
- : "=r"(ia64_intri_res) \
- : PARAVIRT_OP(op) \
- : PARAVIRT_CLOBBERS0)
-
-#define PARAVIRT_BR1(op, type, arg1) \
- register unsigned long __##arg1 asm ("r8") = arg1; \
- register unsigned long ia64_clobber asm ("r8"); \
- asm volatile (paravirt_alt_bundle(__PARAVIRT_BR, \
- PARAVIRT_TYPE(type)) \
- : "=r"(ia64_clobber) \
- : PARAVIRT_OP(op), "0"(__##arg1) \
- : PARAVIRT_CLOBBERS1)
-
-#define PARAVIRT_BR1_RET(op, type, arg1) \
- register unsigned long ia64_intri_res asm ("r8"); \
- register unsigned long __##arg1 asm ("r8") = arg1; \
- asm volatile (paravirt_alt_bundle(__PARAVIRT_BR, \
- PARAVIRT_TYPE(type)) \
- : "=r"(ia64_intri_res) \
- : PARAVIRT_OP(op), "0"(__##arg1) \
- : PARAVIRT_CLOBBERS1)
-
-#define PARAVIRT_BR1_VOID(op, type, arg1) \
- register void *__##arg1 asm ("r8") = arg1; \
- register unsigned long ia64_clobber asm ("r8"); \
- asm volatile (paravirt_alt_bundle(__PARAVIRT_BR, \
- PARAVIRT_TYPE(type)) \
- : "=r"(ia64_clobber) \
- : PARAVIRT_OP(op), "0"(__##arg1) \
- : PARAVIRT_CLOBBERS1)
-
-#define PARAVIRT_BR2(op, type, arg1, arg2) \
- register unsigned long __##arg1 asm ("r8") = arg1; \
- register unsigned long __##arg2 asm ("r9") = arg2; \
- register unsigned long ia64_clobber1 asm ("r8"); \
- register unsigned long ia64_clobber2 asm ("r9"); \
- asm volatile (paravirt_alt_bundle(__PARAVIRT_BR, \
- PARAVIRT_TYPE(type)) \
- : "=r"(ia64_clobber1), "=r"(ia64_clobber2) \
- : PARAVIRT_OP(op), "0"(__##arg1), "1"(__##arg2) \
- : PARAVIRT_CLOBBERS2)
-
-
-#define PARAVIRT_DEFINE_CPU_OP0(op, type) \
- static inline void \
- paravirt_ ## op (void) \
- { \
- PARAVIRT_BR0(op, type); \
- }
-
-#define PARAVIRT_DEFINE_CPU_OP0_RET(op, type) \
- static inline unsigned long \
- paravirt_ ## op (void) \
- { \
- PARAVIRT_BR0_RET(op, type); \
- return ia64_intri_res; \
- }
-
-#define PARAVIRT_DEFINE_CPU_OP1_VOID(op, type) \
- static inline void \
- paravirt_ ## op (void *arg1) \
- { \
- PARAVIRT_BR1_VOID(op, type, arg1); \
- }
-
-#define PARAVIRT_DEFINE_CPU_OP1(op, type) \
- static inline void \
- paravirt_ ## op (unsigned long arg1) \
- { \
- PARAVIRT_BR1(op, type, arg1); \
- }
-
-#define PARAVIRT_DEFINE_CPU_OP1_RET(op, type) \
- static inline unsigned long \
- paravirt_ ## op (unsigned long arg1) \
- { \
- PARAVIRT_BR1_RET(op, type, arg1); \
- return ia64_intri_res; \
- }
-
-#define PARAVIRT_DEFINE_CPU_OP2(op, type) \
- static inline void \
- paravirt_ ## op (unsigned long arg1, \
- unsigned long arg2) \
- { \
- PARAVIRT_BR2(op, type, arg1, arg2); \
- }
-
-
-PARAVIRT_DEFINE_CPU_OP1_VOID(fc, FC);
-PARAVIRT_DEFINE_CPU_OP1_RET(thash, THASH)
-PARAVIRT_DEFINE_CPU_OP1_RET(get_cpuid, GET_CPUID)
-PARAVIRT_DEFINE_CPU_OP1_RET(get_pmd, GET_PMD)
-PARAVIRT_DEFINE_CPU_OP2(ptcga, PTCGA)
-PARAVIRT_DEFINE_CPU_OP1_RET(get_rr, GET_RR)
-PARAVIRT_DEFINE_CPU_OP2(set_rr, SET_RR)
-PARAVIRT_DEFINE_CPU_OP0(ssm_i, SSM_I)
-PARAVIRT_DEFINE_CPU_OP0(rsm_i, RSM_I)
-PARAVIRT_DEFINE_CPU_OP0_RET(get_psr_i, GET_PSR_I)
-PARAVIRT_DEFINE_CPU_OP1(intrin_local_irq_restore, INTRIN_LOCAL_IRQ_RESTORE)
-
-static inline void
-paravirt_set_rr0_to_rr4(unsigned long val0, unsigned long val1,
- unsigned long val2, unsigned long val3,
- unsigned long val4)
-{
- register unsigned long __val0 asm ("r8") = val0;
- register unsigned long __val1 asm ("r9") = val1;
- register unsigned long __val2 asm ("r10") = val2;
- register unsigned long __val3 asm ("r11") = val3;
- register unsigned long __val4 asm ("r14") = val4;
-
- register unsigned long ia64_clobber0 asm ("r8");
- register unsigned long ia64_clobber1 asm ("r9");
- register unsigned long ia64_clobber2 asm ("r10");
- register unsigned long ia64_clobber3 asm ("r11");
- register unsigned long ia64_clobber4 asm ("r14");
-
- asm volatile (paravirt_alt_bundle(__PARAVIRT_BR,
- PARAVIRT_TYPE(SET_RR0_TO_RR4))
- : "=r"(ia64_clobber0),
- "=r"(ia64_clobber1),
- "=r"(ia64_clobber2),
- "=r"(ia64_clobber3),
- "=r"(ia64_clobber4)
- : PARAVIRT_OP(set_rr0_to_rr4),
- "0"(__val0), "1"(__val1), "2"(__val2),
- "3"(__val3), "4"(__val4)
- : PARAVIRT_CLOBBERS5);
-}
-
-/* unsigned long paravirt_getreg(int reg) */
-#define __paravirt_getreg(reg) \
- ({ \
- register unsigned long ia64_intri_res asm ("r8"); \
- register unsigned long __reg asm ("r8") = (reg); \
- \
- asm volatile (paravirt_alt_bundle(__PARAVIRT_BR, \
- PARAVIRT_TYPE(GETREG) \
- + (reg)) \
- : "=r"(ia64_intri_res) \
- : PARAVIRT_OP(getreg), "0"(__reg) \
- : PARAVIRT_CLOBBERS1); \
- \
- ia64_intri_res; \
- })
-
-/* void paravirt_setreg(int reg, unsigned long val) */
-#define paravirt_setreg(reg, val) \
- do { \
- register unsigned long __val asm ("r8") = val; \
- register unsigned long __reg asm ("r9") = reg; \
- register unsigned long ia64_clobber1 asm ("r8"); \
- register unsigned long ia64_clobber2 asm ("r9"); \
- \
- asm volatile (paravirt_alt_bundle(__PARAVIRT_BR, \
- PARAVIRT_TYPE(SETREG) \
- + (reg)) \
- : "=r"(ia64_clobber1), \
- "=r"(ia64_clobber2) \
- : PARAVIRT_OP(setreg), \
- "1"(__reg), "0"(__val) \
- : PARAVIRT_CLOBBERS2); \
- } while (0)
-
-#endif /* ASM_SUPPORTED */
-#endif /* CONFIG_PARAVIRT && ASM_SUPPOTED */
-
-#endif /* _ASM_IA64_PARAVIRT_PRIVOP_H */
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index 52af5ed9f60b..36d2c1e3928b 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -6,9 +6,9 @@
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/scatterlist.h>
#include <asm/io.h>
-#include <asm/scatterlist.h>
#include <asm/hw_irq.h>
struct pci_vector_struct {
@@ -52,25 +52,6 @@ extern unsigned long ia64_max_iommu_merge_mask;
#include <asm-generic/pci-dma-compat.h>
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- unsigned long cacheline_size;
- u8 byte;
-
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
- if (byte == 0)
- cacheline_size = 1024;
- else
- cacheline_size = (int) byte * 4;
-
- *strat = PCI_DMA_BURST_MULTIPLE;
- *strategy_parameter = cacheline_size;
-}
-#endif
-
#define HAVE_PCI_MMAP
extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
@@ -108,19 +89,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)
return (pci_domain_nr(bus) != 0);
}
-static inline struct resource *
-pcibios_select_root(struct pci_dev *pdev, struct resource *res)
-{
- struct resource *root = NULL;
-
- if (res->flags & IORESOURCE_IO)
- root = &ioport_resource;
- if (res->flags & IORESOURCE_MEM)
- root = &iomem_resource;
-
- return root;
-}
-
#define HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ
static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
{
diff --git a/arch/ia64/include/asm/topology.h b/arch/ia64/include/asm/topology.h
index 6437ca21f61b..3ad8f6988363 100644
--- a/arch/ia64/include/asm/topology.h
+++ b/arch/ia64/include/asm/topology.h
@@ -53,7 +53,7 @@ void build_cpu_to_node_map(void);
#define topology_physical_package_id(cpu) (cpu_data(cpu)->socket_id)
#define topology_core_id(cpu) (cpu_data(cpu)->core_id)
#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
-#define topology_thread_cpumask(cpu) (&per_cpu(cpu_sibling_map, cpu))
+#define topology_sibling_cpumask(cpu) (&per_cpu(cpu_sibling_map, cpu))
#endif
extern void arch_fix_phys_package_id(int num, u32 slot);
diff --git a/arch/ia64/include/uapi/asm/cmpxchg.h b/arch/ia64/include/uapi/asm/cmpxchg.h
index f35109b1d907..a0e3620f8f13 100644
--- a/arch/ia64/include/uapi/asm/cmpxchg.h
+++ b/arch/ia64/include/uapi/asm/cmpxchg.h
@@ -61,8 +61,6 @@ extern void ia64_xchg_called_with_bad_pointer(void);
* indicated by comparing RETURN with OLD.
*/
-#define __HAVE_ARCH_CMPXCHG 1
-
/*
* This function doesn't exist, so you'll get a linker error
* if something tries to do an invalid cmpxchg().
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index d68b5cf81e31..3686d6abafde 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -9,7 +9,7 @@ endif
extra-y := head.o init_task.o vmlinux.lds
obj-y := entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \
- irq_lsapic.o ivt.o machvec.o pal.o paravirt_patchlist.o patch.o process.o perfmon.o ptrace.o sal.o \
+ irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \
salinfo.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
unwind.o mca.o mca_asm.o topology.o dma-mapping.o
@@ -35,9 +35,6 @@ mca_recovery-y += mca_drv.o mca_drv_asm.o
obj-$(CONFIG_IA64_MC_ERR_INJECT)+= err_inject.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
-obj-$(CONFIG_PARAVIRT) += paravirt.o paravirtentry.o \
- paravirt_patch.o
-
obj-$(CONFIG_IA64_ESI) += esi.o
ifneq ($(CONFIG_IA64_ESI),)
obj-y += esi_stub.o # must be in kernel proper
@@ -52,8 +49,6 @@ CFLAGS_traps.o += -mfixed-range=f2-f5,f16-f31
# The gate DSO image is built using a special linker script.
include $(src)/Makefile.gate
-# tell compiled for native
-CPPFLAGS_gate.lds += -D__IA64_GATE_PARAVIRTUALIZED_NATIVE
# Calculate NR_IRQ = max(IA64_NATIVE_NR_IRQS, XEN_NR_IRQS, ...) based on config
define sed-y
@@ -84,30 +79,3 @@ arch/$(SRCARCH)/kernel/nr-irqs.s: arch/$(SRCARCH)/kernel/nr-irqs.c
include/generated/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s
$(Q)mkdir -p $(dir $@)
$(call cmd,nr_irqs)
-
-#
-# native ivt.S, entry.S and fsys.S
-#
-ASM_PARAVIRT_OBJS = ivt.o entry.o fsys.o
-define paravirtualized_native
-AFLAGS_$(1) += -D__IA64_ASM_PARAVIRTUALIZED_NATIVE
-AFLAGS_pvchk-sed-$(1) += -D__IA64_ASM_PARAVIRTUALIZED_PVCHECK
-extra-y += pvchk-$(1)
-endef
-$(foreach obj,$(ASM_PARAVIRT_OBJS),$(eval $(call paravirtualized_native,$(obj))))
-
-#
-# Checker for paravirtualizations of privileged operations.
-#
-quiet_cmd_pv_check_sed = PVCHK $@
-define cmd_pv_check_sed
- sed -f $(srctree)/arch/$(SRCARCH)/scripts/pvcheck.sed $< > $@
-endef
-
-$(obj)/pvchk-sed-%.s: $(src)/%.S $(srctree)/arch/$(SRCARCH)/scripts/pvcheck.sed FORCE
- $(call if_changed_dep,as_s_S)
-$(obj)/pvchk-%.s: $(obj)/pvchk-sed-%.s FORCE
- $(call if_changed,pv_check_sed)
-$(obj)/pvchk-%.o: $(obj)/pvchk-%.s FORCE
- $(call if_changed,as_o_S)
-.PRECIOUS: $(obj)/pvchk-sed-%.s $(obj)/pvchk-%.s $(obj)/pvchk-%.o
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index c52d7540dc05..47e962f7ed5a 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -464,7 +464,6 @@ efi_map_pal_code (void)
GRANULEROUNDDOWN((unsigned long) pal_vaddr),
pte_val(pfn_pte(__pa(pal_vaddr) >> PAGE_SHIFT, PAGE_KERNEL)),
IA64_GRANULE_SHIFT);
- paravirt_dv_serialize_data();
ia64_set_psr(psr); /* restore psr */
}
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index fcf8b8cbca0b..ae0de7bf5525 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -51,7 +51,6 @@
#include "minstate.h"
-#ifdef __IA64_ASM_PARAVIRTUALIZED_NATIVE
/*
* execve() is special because in case of success, we need to
* setup a null register window frame.
@@ -161,7 +160,6 @@ GLOBAL_ENTRY(sys_clone)
mov rp=loc0
br.ret.sptk.many rp
END(sys_clone)
-#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
/*
* prev_task <- ia64_switch_to(struct task_struct *next)
@@ -169,7 +167,7 @@ END(sys_clone)
* called. The code starting at .map relies on this. The rest of the code
* doesn't care about the interrupt masking status.
*/
-GLOBAL_ENTRY(__paravirt_switch_to)
+GLOBAL_ENTRY(ia64_switch_to)
.prologue
alloc r16=ar.pfs,1,0,0,0
DO_SAVE_SWITCH_STACK
@@ -221,9 +219,8 @@ GLOBAL_ENTRY(__paravirt_switch_to)
itr.d dtr[r25]=r23 // wire in new mapping...
SSM_PSR_IC_AND_SRLZ_D(r8, r9) // reenable the psr.ic bit
br.cond.sptk .done
-END(__paravirt_switch_to)
+END(ia64_switch_to)
-#ifdef __IA64_ASM_PARAVIRTUALIZED_NATIVE
/*
* Note that interrupts are enabled during save_switch_stack and load_switch_stack. This
* means that we may get an interrupt with "sp" pointing to the new kernel stack while
@@ -639,16 +636,8 @@ GLOBAL_ENTRY(ia64_ret_from_syscall)
adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8
mov r10=r0 // clear error indication in r10
(p7) br.cond.spnt handle_syscall_error // handle potential syscall failure
-#ifdef CONFIG_PARAVIRT
- ;;
- br.cond.sptk.few ia64_leave_syscall
- ;;
-#endif /* CONFIG_PARAVIRT */
END(ia64_ret_from_syscall)
-#ifndef CONFIG_PARAVIRT
// fall through
-#endif
-#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
/*
* ia64_leave_syscall(): Same as ia64_leave_kernel, except that it doesn't
@@ -694,7 +683,7 @@ END(ia64_ret_from_syscall)
* ar.csd: cleared
* ar.ssd: cleared
*/
-GLOBAL_ENTRY(__paravirt_leave_syscall)
+GLOBAL_ENTRY(ia64_leave_syscall)
PT_REGS_UNWIND_INFO(0)
/*
* work.need_resched etc. mustn't get changed by this CPU before it returns to
@@ -722,8 +711,8 @@ GLOBAL_ENTRY(__paravirt_leave_syscall)
cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall
(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk
#endif
-.global __paravirt_work_processed_syscall;
-__paravirt_work_processed_syscall:
+.global ia64_work_processed_syscall;
+ia64_work_processed_syscall:
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
adds r2=PT(LOADRS)+16,r12
MOV_FROM_ITC(pUStk, p9, r22, r19) // fetch time at leave
@@ -836,9 +825,9 @@ __paravirt_work_processed_syscall:
mov.m ar.ssd=r0 // M2 clear ar.ssd
mov f11=f0 // F clear f11
br.cond.sptk.many rbs_switch // B
-END(__paravirt_leave_syscall)
+END(ia64_leave_syscall)
-GLOBAL_ENTRY(__paravirt_leave_kernel)
+GLOBAL_ENTRY(ia64_leave_kernel)
PT_REGS_UNWIND_INFO(0)
/*
* work.need_resched etc. mustn't get changed by this CPU before it returns to
@@ -1171,26 +1160,25 @@ skip_rbs_switch:
(p6) br.cond.sptk.few .notify
br.call.spnt.many rp=preempt_schedule_irq
.ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1 (re-check)
-(pLvSys)br.cond.sptk.few __paravirt_pending_syscall_end
+(pLvSys)br.cond.sptk.few ia64_work_pending_syscall_end
br.cond.sptk.many .work_processed_kernel
.notify:
(pUStk) br.call.spnt.many rp=notify_resume_user
.ret10: cmp.ne p6,p0=r0,r0 // p6 <- 0 (don't re-check)
-(pLvSys)br.cond.sptk.few __paravirt_pending_syscall_end
+(pLvSys)br.cond.sptk.few ia64_work_pending_syscall_end
br.cond.sptk.many .work_processed_kernel
-.global __paravirt_pending_syscall_end;
-__paravirt_pending_syscall_end:
+.global ia64_work_pending_syscall_end;
+ia64_work_pending_syscall_end:
adds r2=PT(R8)+16,r12
adds r3=PT(R10)+16,r12
;;
ld8 r8=[r2]
ld8 r10=[r3]
- br.cond.sptk.many __paravirt_work_processed_syscall_target
-END(__paravirt_leave_kernel)
+ br.cond.sptk.many ia64_work_processed_syscall
+END(ia64_leave_kernel)
-#ifdef __IA64_ASM_PARAVIRTUALIZED_NATIVE
ENTRY(handle_syscall_error)
/*
* Some system calls (e.g., ptrace, mmap) can return arbitrary values which could
@@ -1294,7 +1282,7 @@ ENTRY(sys_rt_sigreturn)
adds sp=16,sp
;;
ld8 r9=[sp] // load new ar.unat
- mov.sptk b7=r8,ia64_native_leave_kernel
+ mov.sptk b7=r8,ia64_leave_kernel
;;
mov ar.unat=r9
br.many b7
@@ -1782,4 +1770,3 @@ sys_call_table:
data8 sys_execveat
.org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
-#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index abc6dee3799c..edbf7af95849 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -24,7 +24,7 @@
#include <asm/unistd.h>
#include "entry.h"
-#include "paravirt_inst.h"
+#include <asm/native/inst.h>
/*
* See Documentation/ia64/fsys.txt for details on fsyscalls.
@@ -402,7 +402,7 @@ ENTRY(fsys_fallback_syscall)
mov r26=ar.pfs
END(fsys_fallback_syscall)
/* FALL THROUGH */
-GLOBAL_ENTRY(paravirt_fsys_bubble_down)
+GLOBAL_ENTRY(fsys_bubble_down)
.prologue
.altrp b6
.body
@@ -440,7 +440,7 @@ GLOBAL_ENTRY(paravirt_fsys_bubble_down)
*
* PSR.BE : already is turned off in __kernel_syscall_via_epc()
* PSR.AC : don't care (kernel normally turns PSR.AC on)
- * PSR.I : already turned off by the time paravirt_fsys_bubble_down gets
+ * PSR.I : already turned off by the time fsys_bubble_down gets
* invoked
* PSR.DFL: always 0 (kernel never turns it on)
* PSR.DFH: don't care --- kernel never touches f32-f127 on its own
@@ -450,7 +450,7 @@ GLOBAL_ENTRY(paravirt_fsys_bubble_down)
* PSR.DB : don't care --- kernel never enables kernel-level
* breakpoints
* PSR.TB : must be 0 already; if it wasn't zero on entry to
- * __kernel_syscall_via_epc, the branch to paravirt_fsys_bubble_down
+ * __kernel_syscall_via_epc, the branch to fsys_bubble_down
* will trigger a taken branch; the taken-trap-handler then
* converts the syscall into a break-based system-call.
*/
@@ -541,14 +541,14 @@ GLOBAL_ENTRY(paravirt_fsys_bubble_down)
nop.m 0
(p8) br.call.sptk.many b6=b6 // B (ignore return address)
br.cond.spnt ia64_trace_syscall // B
-END(paravirt_fsys_bubble_down)
+END(fsys_bubble_down)
.rodata
.align 8
- .globl paravirt_fsyscall_table
+ .globl fsyscall_table
- data8 paravirt_fsys_bubble_down
-paravirt_fsyscall_table:
+ data8 fsys_bubble_down
+fsyscall_table:
data8 fsys_ni_syscall
data8 0 // exit // 1025
data8 0 // read
@@ -833,4 +833,4 @@ paravirt_fsyscall_table:
// fill in zeros for the remaining entries
.zero:
- .space paravirt_fsyscall_table + 8*NR_syscalls - .zero, 0
+ .space fsyscall_table + 8*NR_syscalls - .zero, 0
diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S
index b5f8bdd8618e..0bd1b3bfaf1c 100644
--- a/arch/ia64/kernel/gate.S
+++ b/arch/ia64/kernel/gate.S
@@ -14,7 +14,7 @@
#include <asm/unistd.h>
#include <asm/kregs.h>
#include <asm/page.h>
-#include "paravirt_inst.h"
+#include <asm/native/inst.h>
/*
* We can't easily refer to symbols inside the kernel. To avoid full runtime relocation,
@@ -376,11 +376,4 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc)
(p9) mov r8=ENOSYS
FSYS_RETURN
-#ifdef CONFIG_PARAVIRT
- /*
- * padd to make the size of this symbol constant
- * independent of paravirtualization.
- */
- .align PAGE_SIZE / 8
-#endif
END(__kernel_syscall_via_epc)
diff --git a/arch/ia64/kernel/gate.lds.S b/arch/ia64/kernel/gate.lds.S
index e518f7902af6..3e8271e85a1e 100644
--- a/arch/ia64/kernel/gate.lds.S
+++ b/arch/ia64/kernel/gate.lds.S
@@ -6,7 +6,6 @@
*/
#include <asm/page.h>
-#include "paravirt_patchlist.h"
SECTIONS
{
@@ -33,21 +32,21 @@ SECTIONS
. = GATE_ADDR + 0x600;
.data..patch : {
- __paravirt_start_gate_mckinley_e9_patchlist = .;
+ __start_gate_mckinley_e9_patchlist = .;
*(.data..patch.mckinley_e9)
- __paravirt_end_gate_mckinley_e9_patchlist = .;
+ __end_gate_mckinley_e9_patchlist = .;
- __paravirt_start_gate_vtop_patchlist = .;
+ __start_gate_vtop_patchlist = .;
*(.data..patch.vtop)
- __paravirt_end_gate_vtop_patchlist = .;
+ __end_gate_vtop_patchlist = .;
- __paravirt_start_gate_fsyscall_patchlist = .;
+ __start_gate_fsyscall_patchlist = .;
*(.data..patch.fsyscall_table)
- __paravirt_end_gate_fsyscall_patchlist = .;
+ __end_gate_fsyscall_patchlist = .;
- __paravirt_start_gate_brl_fsys_bubble_down_patchlist = .;
+ __start_gate_brl_fsys_bubble_down_patchlist = .;
*(.data..patch.brl_fsys_bubble_down)
- __paravirt_end_gate_brl_fsys_bubble_down_patchlist = .;
+ __end_gate_brl_fsys_bubble_down_patchlist = .;
} :readable
.IA_64.unwind_info : { *(.IA_64.unwind_info*) }
diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
index a4acddad0c78..bb748c596443 100644
--- a/arch/ia64/kernel/head.S
+++ b/arch/ia64/kernel/head.S
@@ -26,7 +26,6 @@
#include <asm/mmu_context.h>
#include <asm/asm-offsets.h>
#include <asm/pal.h>
-#include <asm/paravirt.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/ptrace.h>
@@ -394,41 +393,6 @@ start_ap:
;;
(isBP) st8 [r2]=r28 // save the address of the boot param area passed by the bootloader
-#ifdef CONFIG_PARAVIRT
-
- movl r14=hypervisor_setup_hooks
- movl r15=hypervisor_type
- mov r16=num_hypervisor_hooks
- ;;
- ld8 r2=[r15]
- ;;
- cmp.ltu p7,p0=r2,r16 // array size check
- shladd r8=r2,3,r14
- ;;
-(p7) ld8 r9=[r8]
- ;;
-(p7) mov b1=r9
-(p7) cmp.ne.unc p7,p0=r9,r0 // no actual branch to NULL
- ;;
-(p7) br.call.sptk.many rp=b1
-
- __INITDATA
-
-default_setup_hook = 0 // Currently nothing needs to be done.
-
- .global hypervisor_type
-hypervisor_type:
- data8 PARAVIRT_HYPERVISOR_TYPE_DEFAULT
-
- // must have the same order with PARAVIRT_HYPERVISOR_TYPE_xxx
-
-hypervisor_setup_hooks:
- data8 default_setup_hook
-num_hypervisor_hooks = (. - hypervisor_setup_hooks) / 8
- .previous
-
-#endif
-
#ifdef CONFIG_SMP
(isAP) br.call.sptk.many rp=start_secondary
.ret0:
@@ -1063,12 +1027,6 @@ GLOBAL_ENTRY(ia64_native_sched_clock)
shrp r8=r9,r8,IA64_NSEC_PER_CYC_SHIFT
br.ret.sptk.many rp
END(ia64_native_sched_clock)
-#ifndef CONFIG_PARAVIRT
- //unsigned long long
- //sched_clock(void) __attribute__((alias("ia64_native_sched_clock")));
- .global sched_clock
-sched_clock = ia64_native_sched_clock
-#endif
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
GLOBAL_ENTRY(cycle_to_cputime)
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
index e42bf7a913f3..b1c3cfc93e71 100644
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -937,7 +937,6 @@ END(interrupt)
* - ar.fpsr: set to kernel settings
* - b6: preserved (same as on entry)
*/
-#ifdef __IA64_ASM_PARAVIRTUALIZED_NATIVE
GLOBAL_ENTRY(ia64_syscall_setup)
#if PT(B6) != 0
# error This code assumes that b6 is the first field in pt_regs.
@@ -1029,7 +1028,6 @@ GLOBAL_ENTRY(ia64_syscall_setup)
(p10) mov r8=-EINVAL
br.ret.sptk.many b7
END(ia64_syscall_setup)
-#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
.org ia64_ivt+0x3c00
/////////////////////////////////////////////////////////////////////////////////////////
@@ -1043,7 +1041,7 @@ END(ia64_syscall_setup)
DBG_FAULT(16)
FAULT(16)
-#if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && defined(__IA64_ASM_PARAVIRTUALIZED_NATIVE)
+#if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE)
/*
* There is no particular reason for this code to be here, other than
* that there happens to be space here that would go unused otherwise.
diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h
index cc82a7d744c9..5704700fb703 100644
--- a/arch/ia64/kernel/minstate.h
+++ b/arch/ia64/kernel/minstate.h
@@ -2,7 +2,7 @@
#include <asm/cache.h>
#include "entry.h"
-#include "paravirt_inst.h"
+#include <asm/native/inst.h>
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
/* read ar.itc in advance, and use it before leaving bank 0 */
diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c
index 29754aae5177..b15933c31b2f 100644
--- a/arch/ia64/kernel/module.c
+++ b/arch/ia64/kernel/module.c
@@ -439,14 +439,6 @@ module_frob_arch_sections (Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings,
mod->arch.opd = s;
else if (strcmp(".IA_64.unwind", secstrings + s->sh_name) == 0)
mod->arch.unwind = s;
-#ifdef CONFIG_PARAVIRT
- else if (strcmp(".paravirt_bundles",
- secstrings + s->sh_name) == 0)
- mod->arch.paravirt_bundles = s;
- else if (strcmp(".paravirt_insts",
- secstrings + s->sh_name) == 0)
- mod->arch.paravirt_insts = s;
-#endif
if (!mod->arch.core_plt || !mod->arch.init_plt || !mod->arch.got || !mod->arch.opd) {
printk(KERN_ERR "%s: sections missing\n", mod->name);
@@ -914,30 +906,6 @@ module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mo
DEBUGP("%s: init: entry=%p\n", __func__, mod->init);
if (mod->arch.unwind)
register_unwind_table(mod);
-#ifdef CONFIG_PARAVIRT
- if (mod->arch.paravirt_bundles) {
- struct paravirt_patch_site_bundle *start =
- (struct paravirt_patch_site_bundle *)
- mod->arch.paravirt_bundles->sh_addr;
- struct paravirt_patch_site_bundle *end =
- (struct paravirt_patch_site_bundle *)
- (mod->arch.paravirt_bundles->sh_addr +
- mod->arch.paravirt_bundles->sh_size);
-
- paravirt_patch_apply_bundle(start, end);
- }
- if (mod->arch.paravirt_insts) {
- struct paravirt_patch_site_inst *start =
- (struct paravirt_patch_site_inst *)
- mod->arch.paravirt_insts->sh_addr;
- struct paravirt_patch_site_inst *end =
- (struct paravirt_patch_site_inst *)
- (mod->arch.paravirt_insts->sh_addr +
- mod->arch.paravirt_insts->sh_size);
-
- paravirt_patch_apply_inst(start, end);
- }
-#endif
return 0;
}
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index 9dd7464f8c17..d70bf15c690a 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -165,7 +165,7 @@ static struct irq_chip dmar_msi_type = {
.irq_retrigger = ia64_msi_retrigger_irq,
};
-static int
+static void
msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
{
struct irq_cfg *cfg = irq_cfg + irq;
@@ -186,21 +186,29 @@ msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
MSI_DATA_LEVEL_ASSERT |
MSI_DATA_DELIVERY_FIXED |
MSI_DATA_VECTOR(cfg->vector);
- return 0;
}
-int arch_setup_dmar_msi(unsigned int irq)
+int dmar_alloc_hwirq(int id, int node, void *arg)
{
- int ret;
+ int irq;
struct msi_msg msg;
- ret = msi_compose_msg(NULL, irq, &msg);
- if (ret < 0)
- return ret;
- dmar_msi_write(irq, &msg);
- irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
- "edge");
- return 0;
+ irq = create_irq();
+ if (irq > 0) {
+ irq_set_handler_data(irq, arg);
+ irq_set_chip_and_handler_name(irq, &dmar_msi_type,
+ handle_edge_irq, "edge");
+ msi_compose_msg(NULL, irq, &msg);
+ dmar_msi_write(irq, &msg);
+ }
+
+ return irq;
+}
+
+void dmar_free_hwirq(int irq)
+{
+ irq_set_handler_data(irq, NULL);
+ destroy_irq(irq);
}
#endif /* CONFIG_INTEL_IOMMU */
diff --git a/arch/ia64/kernel/paravirt.c b/arch/ia64/kernel/paravirt.c
deleted file mode 100644
index 1b22f6de2932..000000000000
--- a/arch/ia64/kernel/paravirt.c
+++ /dev/null
@@ -1,902 +0,0 @@
-/******************************************************************************
- * arch/ia64/kernel/paravirt.c
- *
- * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- * Yaozu (Eddie) Dong <eddie.dong@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; 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/compiler.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/types.h>
-
-#include <asm/iosapic.h>
-#include <asm/paravirt.h>
-
-/***************************************************************************
- * general info
- */
-struct pv_info pv_info = {
- .kernel_rpl = 0,
- .paravirt_enabled = 0,
- .name = "bare hardware"
-};
-
-/***************************************************************************
- * pv_init_ops
- * initialization hooks.
- */
-
-static void __init
-ia64_native_patch_branch(unsigned long tag, unsigned long type);
-
-struct pv_init_ops pv_init_ops =
-{
-#ifdef ASM_SUPPORTED
- .patch_bundle = ia64_native_patch_bundle,
-#endif
- .patch_branch = ia64_native_patch_branch,
-};
-
-/***************************************************************************
- * pv_cpu_ops
- * intrinsics hooks.
- */
-
-#ifndef ASM_SUPPORTED
-/* ia64_native_xxx are macros so that we have to make them real functions */
-
-#define DEFINE_VOID_FUNC1(name) \
- static void \
- ia64_native_ ## name ## _func(unsigned long arg) \
- { \
- ia64_native_ ## name(arg); \
- }
-
-#define DEFINE_VOID_FUNC1_VOID(name) \
- static void \
- ia64_native_ ## name ## _func(void *arg) \
- { \
- ia64_native_ ## name(arg); \
- }
-
-#define DEFINE_VOID_FUNC2(name) \
- static void \
- ia64_native_ ## name ## _func(unsigned long arg0, \
- unsigned long arg1) \
- { \
- ia64_native_ ## name(arg0, arg1); \
- }
-
-#define DEFINE_FUNC0(name) \
- static unsigned long \
- ia64_native_ ## name ## _func(void) \
- { \
- return ia64_native_ ## name(); \
- }
-
-#define DEFINE_FUNC1(name, type) \
- static unsigned long \
- ia64_native_ ## name ## _func(type arg) \
- { \
- return ia64_native_ ## name(arg); \
- } \
-
-DEFINE_VOID_FUNC1_VOID(fc);
-DEFINE_VOID_FUNC1(intrin_local_irq_restore);
-
-DEFINE_VOID_FUNC2(ptcga);
-DEFINE_VOID_FUNC2(set_rr);
-
-DEFINE_FUNC0(get_psr_i);
-
-DEFINE_FUNC1(thash, unsigned long);
-DEFINE_FUNC1(get_cpuid, int);
-DEFINE_FUNC1(get_pmd, int);
-DEFINE_FUNC1(get_rr, unsigned long);
-
-static void
-ia64_native_ssm_i_func(void)
-{
- ia64_native_ssm(IA64_PSR_I);
-}
-
-static void
-ia64_native_rsm_i_func(void)
-{
- ia64_native_rsm(IA64_PSR_I);
-}
-
-static void
-ia64_native_set_rr0_to_rr4_func(unsigned long val0, unsigned long val1,
- unsigned long val2, unsigned long val3,
- unsigned long val4)
-{
- ia64_native_set_rr0_to_rr4(val0, val1, val2, val3, val4);
-}
-
-#define CASE_GET_REG(id) \
- case _IA64_REG_ ## id: \
- res = ia64_native_getreg(_IA64_REG_ ## id); \
- break;
-#define CASE_GET_AR(id) CASE_GET_REG(AR_ ## id)
-#define CASE_GET_CR(id) CASE_GET_REG(CR_ ## id)
-
-unsigned long
-ia64_native_getreg_func(int regnum)
-{
- unsigned long res = -1;
- switch (regnum) {
- CASE_GET_REG(GP);
- /*CASE_GET_REG(IP);*/ /* returned ip value shouldn't be constant */
- CASE_GET_REG(PSR);
- CASE_GET_REG(TP);
- CASE_GET_REG(SP);
-
- CASE_GET_AR(KR0);
- CASE_GET_AR(KR1);
- CASE_GET_AR(KR2);
- CASE_GET_AR(KR3);
- CASE_GET_AR(KR4);
- CASE_GET_AR(KR5);
- CASE_GET_AR(KR6);
- CASE_GET_AR(KR7);
- CASE_GET_AR(RSC);
- CASE_GET_AR(BSP);
- CASE_GET_AR(BSPSTORE);
- CASE_GET_AR(RNAT);
- CASE_GET_AR(FCR);
- CASE_GET_AR(EFLAG);
- CASE_GET_AR(CSD);
- CASE_GET_AR(SSD);
- CASE_GET_AR(CFLAG);
- CASE_GET_AR(FSR);
- CASE_GET_AR(FIR);
- CASE_GET_AR(FDR);
- CASE_GET_AR(CCV);
- CASE_GET_AR(UNAT);
- CASE_GET_AR(FPSR);
- CASE_GET_AR(ITC);
- CASE_GET_AR(PFS);
- CASE_GET_AR(LC);
- CASE_GET_AR(EC);
-
- CASE_GET_CR(DCR);
- CASE_GET_CR(ITM);
- CASE_GET_CR(IVA);
- CASE_GET_CR(PTA);
- CASE_GET_CR(IPSR);
- CASE_GET_CR(ISR);
- CASE_GET_CR(IIP);
- CASE_GET_CR(IFA);
- CASE_GET_CR(ITIR);
- CASE_GET_CR(IIPA);
- CASE_GET_CR(IFS);
- CASE_GET_CR(IIM);
- CASE_GET_CR(IHA);
- CASE_GET_CR(LID);
- CASE_GET_CR(IVR);
- CASE_GET_CR(TPR);
- CASE_GET_CR(EOI);
- CASE_GET_CR(IRR0);
- CASE_GET_CR(IRR1);
- CASE_GET_CR(IRR2);
- CASE_GET_CR(IRR3);
- CASE_GET_CR(ITV);
- CASE_GET_CR(PMV);
- CASE_GET_CR(CMCV);
- CASE_GET_CR(LRR0);
- CASE_GET_CR(LRR1);
-
- default:
- printk(KERN_CRIT "wrong_getreg %d\n", regnum);
- break;
- }
- return res;
-}
-
-#define CASE_SET_REG(id) \
- case _IA64_REG_ ## id: \
- ia64_native_setreg(_IA64_REG_ ## id, val); \
- break;
-#define CASE_SET_AR(id) CASE_SET_REG(AR_ ## id)
-#define CASE_SET_CR(id) CASE_SET_REG(CR_ ## id)
-
-void
-ia64_native_setreg_func(int regnum, unsigned long val)
-{
- switch (regnum) {
- case _IA64_REG_PSR_L:
- ia64_native_setreg(_IA64_REG_PSR_L, val);
- ia64_dv_serialize_data();
- break;
- CASE_SET_REG(SP);
- CASE_SET_REG(GP);
-
- CASE_SET_AR(KR0);
- CASE_SET_AR(KR1);
- CASE_SET_AR(KR2);
- CASE_SET_AR(KR3);
- CASE_SET_AR(KR4);
- CASE_SET_AR(KR5);
- CASE_SET_AR(KR6);
- CASE_SET_AR(KR7);
- CASE_SET_AR(RSC);
- CASE_SET_AR(BSP);
- CASE_SET_AR(BSPSTORE);
- CASE_SET_AR(RNAT);
- CASE_SET_AR(FCR);
- CASE_SET_AR(EFLAG);
- CASE_SET_AR(CSD);
- CASE_SET_AR(SSD);
- CASE_SET_AR(CFLAG);
- CASE_SET_AR(FSR);
- CASE_SET_AR(FIR);
- CASE_SET_AR(FDR);
- CASE_SET_AR(CCV);
- CASE_SET_AR(UNAT);
- CASE_SET_AR(FPSR);
- CASE_SET_AR(ITC);
- CASE_SET_AR(PFS);
- CASE_SET_AR(LC);
- CASE_SET_AR(EC);
-
- CASE_SET_CR(DCR);
- CASE_SET_CR(ITM);
- CASE_SET_CR(IVA);
- CASE_SET_CR(PTA);
- CASE_SET_CR(IPSR);
- CASE_SET_CR(ISR);
- CASE_SET_CR(IIP);
- CASE_SET_CR(IFA);
- CASE_SET_CR(ITIR);
- CASE_SET_CR(IIPA);
- CASE_SET_CR(IFS);
- CASE_SET_CR(IIM);
- CASE_SET_CR(IHA);
- CASE_SET_CR(LID);
- CASE_SET_CR(IVR);
- CASE_SET_CR(TPR);
- CASE_SET_CR(EOI);
- CASE_SET_CR(IRR0);
- CASE_SET_CR(IRR1);
- CASE_SET_CR(IRR2);
- CASE_SET_CR(IRR3);
- CASE_SET_CR(ITV);
- CASE_SET_CR(PMV);
- CASE_SET_CR(CMCV);
- CASE_SET_CR(LRR0);
- CASE_SET_CR(LRR1);
- default:
- printk(KERN_CRIT "wrong setreg %d\n", regnum);
- break;
- }
-}
-#else
-
-#define __DEFINE_FUNC(name, code) \
- extern const char ia64_native_ ## name ## _direct_start[]; \
- extern const char ia64_native_ ## name ## _direct_end[]; \
- asm (".align 32\n" \
- ".proc ia64_native_" #name "_func\n" \
- "ia64_native_" #name "_func:\n" \
- "ia64_native_" #name "_direct_start:\n" \
- code \
- "ia64_native_" #name "_direct_end:\n" \
- "br.cond.sptk.many b6\n" \
- ".endp ia64_native_" #name "_func\n")
-
-#define DEFINE_VOID_FUNC0(name, code) \
- extern void \
- ia64_native_ ## name ## _func(void); \
- __DEFINE_FUNC(name, code)
-
-#define DEFINE_VOID_FUNC1(name, code) \
- extern void \
- ia64_native_ ## name ## _func(unsigned long arg); \
- __DEFINE_FUNC(name, code)
-
-#define DEFINE_VOID_FUNC1_VOID(name, code) \
- extern void \
- ia64_native_ ## name ## _func(void *arg); \
- __DEFINE_FUNC(name, code)
-
-#define DEFINE_VOID_FUNC2(name, code) \
- extern void \
- ia64_native_ ## name ## _func(unsigned long arg0, \
- unsigned long arg1); \
- __DEFINE_FUNC(name, code)
-
-#define DEFINE_FUNC0(name, code) \
- extern unsigned long \
- ia64_native_ ## name ## _func(void); \
- __DEFINE_FUNC(name, code)
-
-#define DEFINE_FUNC1(name, type, code) \
- extern unsigned long \
- ia64_native_ ## name ## _func(type arg); \
- __DEFINE_FUNC(name, code)
-
-DEFINE_VOID_FUNC1_VOID(fc,
- "fc r8\n");
-DEFINE_VOID_FUNC1(intrin_local_irq_restore,
- ";;\n"
- " cmp.ne p6, p7 = r8, r0\n"
- ";;\n"
- "(p6) ssm psr.i\n"
- "(p7) rsm psr.i\n"
- ";;\n"
- "(p6) srlz.d\n");
-
-DEFINE_VOID_FUNC2(ptcga,
- "ptc.ga r8, r9\n");
-DEFINE_VOID_FUNC2(set_rr,
- "mov rr[r8] = r9\n");
-
-/* ia64_native_getreg(_IA64_REG_PSR) & IA64_PSR_I */
-DEFINE_FUNC0(get_psr_i,
- "mov r2 = " __stringify(1 << IA64_PSR_I_BIT) "\n"
- "mov r8 = psr\n"
- ";;\n"
- "and r8 = r2, r8\n");
-
-DEFINE_FUNC1(thash, unsigned long,
- "thash r8 = r8\n");
-DEFINE_FUNC1(get_cpuid, int,
- "mov r8 = cpuid[r8]\n");
-DEFINE_FUNC1(get_pmd, int,
- "mov r8 = pmd[r8]\n");
-DEFINE_FUNC1(get_rr, unsigned long,
- "mov r8 = rr[r8]\n");
-
-DEFINE_VOID_FUNC0(ssm_i,
- "ssm psr.i\n");
-DEFINE_VOID_FUNC0(rsm_i,
- "rsm psr.i\n");
-
-extern void
-ia64_native_set_rr0_to_rr4_func(unsigned long val0, unsigned long val1,
- unsigned long val2, unsigned long val3,
- unsigned long val4);
-__DEFINE_FUNC(set_rr0_to_rr4,
- "mov rr[r0] = r8\n"
- "movl r2 = 0x2000000000000000\n"
- ";;\n"
- "mov rr[r2] = r9\n"
- "shl r3 = r2, 1\n" /* movl r3 = 0x4000000000000000 */
- ";;\n"
- "add r2 = r2, r3\n" /* movl r2 = 0x6000000000000000 */
- "mov rr[r3] = r10\n"
- ";;\n"
- "mov rr[r2] = r11\n"
- "shl r3 = r3, 1\n" /* movl r3 = 0x8000000000000000 */
- ";;\n"
- "mov rr[r3] = r14\n");
-
-extern unsigned long ia64_native_getreg_func(int regnum);
-asm(".global ia64_native_getreg_func\n");
-#define __DEFINE_GET_REG(id, reg) \
- "mov r2 = " __stringify(_IA64_REG_ ## id) "\n" \
- ";;\n" \
- "cmp.eq p6, p0 = r2, r8\n" \
- ";;\n" \
- "(p6) mov r8 = " #reg "\n" \
- "(p6) br.cond.sptk.many b6\n" \
- ";;\n"
-#define __DEFINE_GET_AR(id, reg) __DEFINE_GET_REG(AR_ ## id, ar.reg)
-#define __DEFINE_GET_CR(id, reg) __DEFINE_GET_REG(CR_ ## id, cr.reg)
-
-__DEFINE_FUNC(getreg,
- __DEFINE_GET_REG(GP, gp)
- /*__DEFINE_GET_REG(IP, ip)*/ /* returned ip value shouldn't be constant */
- __DEFINE_GET_REG(PSR, psr)
- __DEFINE_GET_REG(TP, tp)
- __DEFINE_GET_REG(SP, sp)
-
- __DEFINE_GET_REG(AR_KR0, ar0)
- __DEFINE_GET_REG(AR_KR1, ar1)
- __DEFINE_GET_REG(AR_KR2, ar2)
- __DEFINE_GET_REG(AR_KR3, ar3)
- __DEFINE_GET_REG(AR_KR4, ar4)
- __DEFINE_GET_REG(AR_KR5, ar5)
- __DEFINE_GET_REG(AR_KR6, ar6)
- __DEFINE_GET_REG(AR_KR7, ar7)
- __DEFINE_GET_AR(RSC, rsc)
- __DEFINE_GET_AR(BSP, bsp)
- __DEFINE_GET_AR(BSPSTORE, bspstore)
- __DEFINE_GET_AR(RNAT, rnat)
- __DEFINE_GET_AR(FCR, fcr)
- __DEFINE_GET_AR(EFLAG, eflag)
- __DEFINE_GET_AR(CSD, csd)
- __DEFINE_GET_AR(SSD, ssd)
- __DEFINE_GET_REG(AR_CFLAG, ar27)
- __DEFINE_GET_AR(FSR, fsr)
- __DEFINE_GET_AR(FIR, fir)
- __DEFINE_GET_AR(FDR, fdr)
- __DEFINE_GET_AR(CCV, ccv)
- __DEFINE_GET_AR(UNAT, unat)
- __DEFINE_GET_AR(FPSR, fpsr)
- __DEFINE_GET_AR(ITC, itc)
- __DEFINE_GET_AR(PFS, pfs)
- __DEFINE_GET_AR(LC, lc)
- __DEFINE_GET_AR(EC, ec)
-
- __DEFINE_GET_CR(DCR, dcr)
- __DEFINE_GET_CR(ITM, itm)
- __DEFINE_GET_CR(IVA, iva)
- __DEFINE_GET_CR(PTA, pta)
- __DEFINE_GET_CR(IPSR, ipsr)
- __DEFINE_GET_CR(ISR, isr)
- __DEFINE_GET_CR(IIP, iip)
- __DEFINE_GET_CR(IFA, ifa)
- __DEFINE_GET_CR(ITIR, itir)
- __DEFINE_GET_CR(IIPA, iipa)
- __DEFINE_GET_CR(IFS, ifs)
- __DEFINE_GET_CR(IIM, iim)
- __DEFINE_GET_CR(IHA, iha)
- __DEFINE_GET_CR(LID, lid)
- __DEFINE_GET_CR(IVR, ivr)
- __DEFINE_GET_CR(TPR, tpr)
- __DEFINE_GET_CR(EOI, eoi)
- __DEFINE_GET_CR(IRR0, irr0)
- __DEFINE_GET_CR(IRR1, irr1)
- __DEFINE_GET_CR(IRR2, irr2)
- __DEFINE_GET_CR(IRR3, irr3)
- __DEFINE_GET_CR(ITV, itv)
- __DEFINE_GET_CR(PMV, pmv)
- __DEFINE_GET_CR(CMCV, cmcv)
- __DEFINE_GET_CR(LRR0, lrr0)
- __DEFINE_GET_CR(LRR1, lrr1)
-
- "mov r8 = -1\n" /* unsupported case */
- );
-
-extern void ia64_native_setreg_func(int regnum, unsigned long val);
-asm(".global ia64_native_setreg_func\n");
-#define __DEFINE_SET_REG(id, reg) \
- "mov r2 = " __stringify(_IA64_REG_ ## id) "\n" \
- ";;\n" \
- "cmp.eq p6, p0 = r2, r9\n" \
- ";;\n" \
- "(p6) mov " #reg " = r8\n" \
- "(p6) br.cond.sptk.many b6\n" \
- ";;\n"
-#define __DEFINE_SET_AR(id, reg) __DEFINE_SET_REG(AR_ ## id, ar.reg)
-#define __DEFINE_SET_CR(id, reg) __DEFINE_SET_REG(CR_ ## id, cr.reg)
-__DEFINE_FUNC(setreg,
- "mov r2 = " __stringify(_IA64_REG_PSR_L) "\n"
- ";;\n"
- "cmp.eq p6, p0 = r2, r9\n"
- ";;\n"
- "(p6) mov psr.l = r8\n"
-#ifdef HAVE_SERIALIZE_DIRECTIVE
- ".serialize.data\n"
-#endif
- "(p6) br.cond.sptk.many b6\n"
- __DEFINE_SET_REG(GP, gp)
- __DEFINE_SET_REG(SP, sp)
-
- __DEFINE_SET_REG(AR_KR0, ar0)
- __DEFINE_SET_REG(AR_KR1, ar1)
- __DEFINE_SET_REG(AR_KR2, ar2)
- __DEFINE_SET_REG(AR_KR3, ar3)
- __DEFINE_SET_REG(AR_KR4, ar4)
- __DEFINE_SET_REG(AR_KR5, ar5)
- __DEFINE_SET_REG(AR_KR6, ar6)
- __DEFINE_SET_REG(AR_KR7, ar7)
- __DEFINE_SET_AR(RSC, rsc)
- __DEFINE_SET_AR(BSP, bsp)
- __DEFINE_SET_AR(BSPSTORE, bspstore)
- __DEFINE_SET_AR(RNAT, rnat)
- __DEFINE_SET_AR(FCR, fcr)
- __DEFINE_SET_AR(EFLAG, eflag)
- __DEFINE_SET_AR(CSD, csd)
- __DEFINE_SET_AR(SSD, ssd)
- __DEFINE_SET_REG(AR_CFLAG, ar27)
- __DEFINE_SET_AR(FSR, fsr)
- __DEFINE_SET_AR(FIR, fir)
- __DEFINE_SET_AR(FDR, fdr)
- __DEFINE_SET_AR(CCV, ccv)
- __DEFINE_SET_AR(UNAT, unat)
- __DEFINE_SET_AR(FPSR, fpsr)
- __DEFINE_SET_AR(ITC, itc)
- __DEFINE_SET_AR(PFS, pfs)
- __DEFINE_SET_AR(LC, lc)
- __DEFINE_SET_AR(EC, ec)
-
- __DEFINE_SET_CR(DCR, dcr)
- __DEFINE_SET_CR(ITM, itm)
- __DEFINE_SET_CR(IVA, iva)
- __DEFINE_SET_CR(PTA, pta)
- __DEFINE_SET_CR(IPSR, ipsr)
- __DEFINE_SET_CR(ISR, isr)
- __DEFINE_SET_CR(IIP, iip)
- __DEFINE_SET_CR(IFA, ifa)
- __DEFINE_SET_CR(ITIR, itir)
- __DEFINE_SET_CR(IIPA, iipa)
- __DEFINE_SET_CR(IFS, ifs)
- __DEFINE_SET_CR(IIM, iim)
- __DEFINE_SET_CR(IHA, iha)
- __DEFINE_SET_CR(LID, lid)
- __DEFINE_SET_CR(IVR, ivr)
- __DEFINE_SET_CR(TPR, tpr)
- __DEFINE_SET_CR(EOI, eoi)
- __DEFINE_SET_CR(IRR0, irr0)
- __DEFINE_SET_CR(IRR1, irr1)
- __DEFINE_SET_CR(IRR2, irr2)
- __DEFINE_SET_CR(IRR3, irr3)
- __DEFINE_SET_CR(ITV, itv)
- __DEFINE_SET_CR(PMV, pmv)
- __DEFINE_SET_CR(CMCV, cmcv)
- __DEFINE_SET_CR(LRR0, lrr0)
- __DEFINE_SET_CR(LRR1, lrr1)
- );
-#endif
-
-struct pv_cpu_ops pv_cpu_ops = {
- .fc = ia64_native_fc_func,
- .thash = ia64_native_thash_func,
- .get_cpuid = ia64_native_get_cpuid_func,
- .get_pmd = ia64_native_get_pmd_func,
- .ptcga = ia64_native_ptcga_func,
- .get_rr = ia64_native_get_rr_func,
- .set_rr = ia64_native_set_rr_func,
- .set_rr0_to_rr4 = ia64_native_set_rr0_to_rr4_func,
- .ssm_i = ia64_native_ssm_i_func,
- .getreg = ia64_native_getreg_func,
- .setreg = ia64_native_setreg_func,
- .rsm_i = ia64_native_rsm_i_func,
- .get_psr_i = ia64_native_get_psr_i_func,
- .intrin_local_irq_restore
- = ia64_native_intrin_local_irq_restore_func,
-};
-EXPORT_SYMBOL(pv_cpu_ops);
-
-/******************************************************************************
- * replacement of hand written assembly codes.
- */
-
-void
-paravirt_cpu_asm_init(const struct pv_cpu_asm_switch *cpu_asm_switch)
-{
- extern unsigned long paravirt_switch_to_targ;
- extern unsigned long paravirt_leave_syscall_targ;
- extern unsigned long paravirt_work_processed_syscall_targ;
- extern unsigned long paravirt_leave_kernel_targ;
-
- paravirt_switch_to_targ = cpu_asm_switch->switch_to;
- paravirt_leave_syscall_targ = cpu_asm_switch->leave_syscall;
- paravirt_work_processed_syscall_targ =
- cpu_asm_switch->work_processed_syscall;
- paravirt_leave_kernel_targ = cpu_asm_switch->leave_kernel;
-}
-
-/***************************************************************************
- * pv_iosapic_ops
- * iosapic read/write hooks.
- */
-
-static unsigned int
-ia64_native_iosapic_read(char __iomem *iosapic, unsigned int reg)
-{
- return __ia64_native_iosapic_read(iosapic, reg);
-}
-
-static void
-ia64_native_iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
-{
- __ia64_native_iosapic_write(iosapic, reg, val);
-}
-
-struct pv_iosapic_ops pv_iosapic_ops = {
- .pcat_compat_init = ia64_native_iosapic_pcat_compat_init,
- .__get_irq_chip = ia64_native_iosapic_get_irq_chip,
-
- .__read = ia64_native_iosapic_read,
- .__write = ia64_native_iosapic_write,
-};
-
-/***************************************************************************
- * pv_irq_ops
- * irq operations
- */
-
-struct pv_irq_ops pv_irq_ops = {
- .register_ipi = ia64_native_register_ipi,
-
- .assign_irq_vector = ia64_native_assign_irq_vector,
- .free_irq_vector = ia64_native_free_irq_vector,
- .register_percpu_irq = ia64_native_register_percpu_irq,
-
- .resend_irq = ia64_native_resend_irq,
-};
-
-/***************************************************************************
- * pv_time_ops
- * time operations
- */
-struct static_key paravirt_steal_enabled;
-struct static_key paravirt_steal_rq_enabled;
-
-static int
-ia64_native_do_steal_accounting(unsigned long *new_itm)
-{
- return 0;
-}
-
-struct pv_time_ops pv_time_ops = {
- .do_steal_accounting = ia64_native_do_steal_accounting,
- .sched_clock = ia64_native_sched_clock,
-};
-
-/***************************************************************************
- * binary pacthing
- * pv_init_ops.patch_bundle
- */
-
-#ifdef ASM_SUPPORTED
-#define IA64_NATIVE_PATCH_DEFINE_GET_REG(name, reg) \
- __DEFINE_FUNC(get_ ## name, \
- ";;\n" \
- "mov r8 = " #reg "\n" \
- ";;\n")
-
-#define IA64_NATIVE_PATCH_DEFINE_SET_REG(name, reg) \
- __DEFINE_FUNC(set_ ## name, \
- ";;\n" \
- "mov " #reg " = r8\n" \
- ";;\n")
-
-#define IA64_NATIVE_PATCH_DEFINE_REG(name, reg) \
- IA64_NATIVE_PATCH_DEFINE_GET_REG(name, reg); \
- IA64_NATIVE_PATCH_DEFINE_SET_REG(name, reg) \
-
-#define IA64_NATIVE_PATCH_DEFINE_AR(name, reg) \
- IA64_NATIVE_PATCH_DEFINE_REG(ar_ ## name, ar.reg)
-
-#define IA64_NATIVE_PATCH_DEFINE_CR(name, reg) \
- IA64_NATIVE_PATCH_DEFINE_REG(cr_ ## name, cr.reg)
-
-
-IA64_NATIVE_PATCH_DEFINE_GET_REG(psr, psr);
-IA64_NATIVE_PATCH_DEFINE_GET_REG(tp, tp);
-
-/* IA64_NATIVE_PATCH_DEFINE_SET_REG(psr_l, psr.l); */
-__DEFINE_FUNC(set_psr_l,
- ";;\n"
- "mov psr.l = r8\n"
-#ifdef HAVE_SERIALIZE_DIRECTIVE
- ".serialize.data\n"
-#endif
- ";;\n");
-
-IA64_NATIVE_PATCH_DEFINE_REG(gp, gp);
-IA64_NATIVE_PATCH_DEFINE_REG(sp, sp);
-
-IA64_NATIVE_PATCH_DEFINE_REG(kr0, ar0);
-IA64_NATIVE_PATCH_DEFINE_REG(kr1, ar1);
-IA64_NATIVE_PATCH_DEFINE_REG(kr2, ar2);
-IA64_NATIVE_PATCH_DEFINE_REG(kr3, ar3);
-IA64_NATIVE_PATCH_DEFINE_REG(kr4, ar4);
-IA64_NATIVE_PATCH_DEFINE_REG(kr5, ar5);
-IA64_NATIVE_PATCH_DEFINE_REG(kr6, ar6);
-IA64_NATIVE_PATCH_DEFINE_REG(kr7, ar7);
-
-IA64_NATIVE_PATCH_DEFINE_AR(rsc, rsc);
-IA64_NATIVE_PATCH_DEFINE_AR(bsp, bsp);
-IA64_NATIVE_PATCH_DEFINE_AR(bspstore, bspstore);
-IA64_NATIVE_PATCH_DEFINE_AR(rnat, rnat);
-IA64_NATIVE_PATCH_DEFINE_AR(fcr, fcr);
-IA64_NATIVE_PATCH_DEFINE_AR(eflag, eflag);
-IA64_NATIVE_PATCH_DEFINE_AR(csd, csd);
-IA64_NATIVE_PATCH_DEFINE_AR(ssd, ssd);
-IA64_NATIVE_PATCH_DEFINE_REG(ar27, ar27);
-IA64_NATIVE_PATCH_DEFINE_AR(fsr, fsr);
-IA64_NATIVE_PATCH_DEFINE_AR(fir, fir);
-IA64_NATIVE_PATCH_DEFINE_AR(fdr, fdr);
-IA64_NATIVE_PATCH_DEFINE_AR(ccv, ccv);
-IA64_NATIVE_PATCH_DEFINE_AR(unat, unat);
-IA64_NATIVE_PATCH_DEFINE_AR(fpsr, fpsr);
-IA64_NATIVE_PATCH_DEFINE_AR(itc, itc);
-IA64_NATIVE_PATCH_DEFINE_AR(pfs, pfs);
-IA64_NATIVE_PATCH_DEFINE_AR(lc, lc);
-IA64_NATIVE_PATCH_DEFINE_AR(ec, ec);
-
-IA64_NATIVE_PATCH_DEFINE_CR(dcr, dcr);
-IA64_NATIVE_PATCH_DEFINE_CR(itm, itm);
-IA64_NATIVE_PATCH_DEFINE_CR(iva, iva);
-IA64_NATIVE_PATCH_DEFINE_CR(pta, pta);
-IA64_NATIVE_PATCH_DEFINE_CR(ipsr, ipsr);
-IA64_NATIVE_PATCH_DEFINE_CR(isr, isr);
-IA64_NATIVE_PATCH_DEFINE_CR(iip, iip);
-IA64_NATIVE_PATCH_DEFINE_CR(ifa, ifa);
-IA64_NATIVE_PATCH_DEFINE_CR(itir, itir);
-IA64_NATIVE_PATCH_DEFINE_CR(iipa, iipa);
-IA64_NATIVE_PATCH_DEFINE_CR(ifs, ifs);
-IA64_NATIVE_PATCH_DEFINE_CR(iim, iim);
-IA64_NATIVE_PATCH_DEFINE_CR(iha, iha);
-IA64_NATIVE_PATCH_DEFINE_CR(lid, lid);
-IA64_NATIVE_PATCH_DEFINE_CR(ivr, ivr);
-IA64_NATIVE_PATCH_DEFINE_CR(tpr, tpr);
-IA64_NATIVE_PATCH_DEFINE_CR(eoi, eoi);
-IA64_NATIVE_PATCH_DEFINE_CR(irr0, irr0);
-IA64_NATIVE_PATCH_DEFINE_CR(irr1, irr1);
-IA64_NATIVE_PATCH_DEFINE_CR(irr2, irr2);
-IA64_NATIVE_PATCH_DEFINE_CR(irr3, irr3);
-IA64_NATIVE_PATCH_DEFINE_CR(itv, itv);
-IA64_NATIVE_PATCH_DEFINE_CR(pmv, pmv);
-IA64_NATIVE_PATCH_DEFINE_CR(cmcv, cmcv);
-IA64_NATIVE_PATCH_DEFINE_CR(lrr0, lrr0);
-IA64_NATIVE_PATCH_DEFINE_CR(lrr1, lrr1);
-
-static const struct paravirt_patch_bundle_elem ia64_native_patch_bundle_elems[]
-__initdata_or_module =
-{
-#define IA64_NATIVE_PATCH_BUNDLE_ELEM(name, type) \
- { \
- (void*)ia64_native_ ## name ## _direct_start, \
- (void*)ia64_native_ ## name ## _direct_end, \
- PARAVIRT_PATCH_TYPE_ ## type, \
- }
-
- IA64_NATIVE_PATCH_BUNDLE_ELEM(fc, FC),
- IA64_NATIVE_PATCH_BUNDLE_ELEM(thash, THASH),
- IA64_NATIVE_PATCH_BUNDLE_ELEM(get_cpuid, GET_CPUID),
- IA64_NATIVE_PATCH_BUNDLE_ELEM(get_pmd, GET_PMD),
- IA64_NATIVE_PATCH_BUNDLE_ELEM(ptcga, PTCGA),
- IA64_NATIVE_PATCH_BUNDLE_ELEM(get_rr, GET_RR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM(set_rr, SET_RR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM(set_rr0_to_rr4, SET_RR0_TO_RR4),
- IA64_NATIVE_PATCH_BUNDLE_ELEM(ssm_i, SSM_I),
- IA64_NATIVE_PATCH_BUNDLE_ELEM(rsm_i, RSM_I),
- IA64_NATIVE_PATCH_BUNDLE_ELEM(get_psr_i, GET_PSR_I),
- IA64_NATIVE_PATCH_BUNDLE_ELEM(intrin_local_irq_restore,
- INTRIN_LOCAL_IRQ_RESTORE),
-
-#define IA64_NATIVE_PATCH_BUNDLE_ELEM_GETREG(name, reg) \
- { \
- (void*)ia64_native_get_ ## name ## _direct_start, \
- (void*)ia64_native_get_ ## name ## _direct_end, \
- PARAVIRT_PATCH_TYPE_GETREG + _IA64_REG_ ## reg, \
- }
-
-#define IA64_NATIVE_PATCH_BUNDLE_ELEM_SETREG(name, reg) \
- { \
- (void*)ia64_native_set_ ## name ## _direct_start, \
- (void*)ia64_native_set_ ## name ## _direct_end, \
- PARAVIRT_PATCH_TYPE_SETREG + _IA64_REG_ ## reg, \
- }
-
-#define IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(name, reg) \
- IA64_NATIVE_PATCH_BUNDLE_ELEM_GETREG(name, reg), \
- IA64_NATIVE_PATCH_BUNDLE_ELEM_SETREG(name, reg) \
-
-#define IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(name, reg) \
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(ar_ ## name, AR_ ## reg)
-
-#define IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(name, reg) \
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(cr_ ## name, CR_ ## reg)
-
- IA64_NATIVE_PATCH_BUNDLE_ELEM_GETREG(psr, PSR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_GETREG(tp, TP),
-
- IA64_NATIVE_PATCH_BUNDLE_ELEM_SETREG(psr_l, PSR_L),
-
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(gp, GP),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(sp, SP),
-
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr0, AR_KR0),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr1, AR_KR1),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr2, AR_KR2),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr3, AR_KR3),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr4, AR_KR4),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr5, AR_KR5),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr6, AR_KR6),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(kr7, AR_KR7),
-
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(rsc, RSC),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(bsp, BSP),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(bspstore, BSPSTORE),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(rnat, RNAT),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fcr, FCR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(eflag, EFLAG),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(csd, CSD),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(ssd, SSD),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_REG(ar27, AR_CFLAG),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fsr, FSR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fir, FIR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fdr, FDR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(ccv, CCV),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(unat, UNAT),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(fpsr, FPSR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(itc, ITC),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(pfs, PFS),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(lc, LC),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_AR(ec, EC),
-
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(dcr, DCR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(itm, ITM),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iva, IVA),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(pta, PTA),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(ipsr, IPSR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(isr, ISR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iip, IIP),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(ifa, IFA),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(itir, ITIR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iipa, IIPA),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(ifs, IFS),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iim, IIM),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(iha, IHA),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(lid, LID),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(ivr, IVR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(tpr, TPR),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(eoi, EOI),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(irr0, IRR0),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(irr1, IRR1),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(irr2, IRR2),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(irr3, IRR3),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(itv, ITV),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(pmv, PMV),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(cmcv, CMCV),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(lrr0, LRR0),
- IA64_NATIVE_PATCH_BUNDLE_ELEM_CR(lrr1, LRR1),
-};
-
-unsigned long __init_or_module
-ia64_native_patch_bundle(void *sbundle, void *ebundle, unsigned long type)
-{
- const unsigned long nelems = sizeof(ia64_native_patch_bundle_elems) /
- sizeof(ia64_native_patch_bundle_elems[0]);
-
- return __paravirt_patch_apply_bundle(sbundle, ebundle, type,
- ia64_native_patch_bundle_elems,
- nelems, NULL);
-}
-#endif /* ASM_SUPPOTED */
-
-extern const char ia64_native_switch_to[];
-extern const char ia64_native_leave_syscall[];
-extern const char ia64_native_work_processed_syscall[];
-extern const char ia64_native_leave_kernel[];
-
-const struct paravirt_patch_branch_target ia64_native_branch_target[]
-__initconst = {
-#define PARAVIRT_BR_TARGET(name, type) \
- { \
- ia64_native_ ## name, \
- PARAVIRT_PATCH_TYPE_BR_ ## type, \
- }
- PARAVIRT_BR_TARGET(switch_to, SWITCH_TO),
- PARAVIRT_BR_TARGET(leave_syscall, LEAVE_SYSCALL),
- PARAVIRT_BR_TARGET(work_processed_syscall, WORK_PROCESSED_SYSCALL),
- PARAVIRT_BR_TARGET(leave_kernel, LEAVE_KERNEL),
-};
-
-static void __init
-ia64_native_patch_branch(unsigned long tag, unsigned long type)
-{
- const unsigned long nelem =
- sizeof(ia64_native_branch_target) /
- sizeof(ia64_native_branch_target[0]);
- __paravirt_patch_apply_branch(tag, type,
- ia64_native_branch_target, nelem);
-}
diff --git a/arch/ia64/kernel/paravirt_inst.h b/arch/ia64/kernel/paravirt_inst.h
deleted file mode 100644
index 1ad7512b5f65..000000000000
--- a/arch/ia64/kernel/paravirt_inst.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/******************************************************************************
- * linux/arch/ia64/xen/paravirt_inst.h
- *
- * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * 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
- *
- */
-
-#ifdef __IA64_ASM_PARAVIRTUALIZED_PVCHECK
-#include <asm/native/pvchk_inst.h>
-#else
-#include <asm/native/inst.h>
-#endif
-
diff --git a/arch/ia64/kernel/paravirt_patch.c b/arch/ia64/kernel/paravirt_patch.c
deleted file mode 100644
index bfdfef1b1ffd..000000000000
--- a/arch/ia64/kernel/paravirt_patch.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/******************************************************************************
- * linux/arch/ia64/xen/paravirt_patch.c
- *
- * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * 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 <asm/intrinsics.h>
-#include <asm/kprobes.h>
-#include <asm/paravirt.h>
-#include <asm/paravirt_patch.h>
-
-typedef union ia64_inst {
- struct {
- unsigned long long qp : 6;
- unsigned long long : 31;
- unsigned long long opcode : 4;
- unsigned long long reserved : 23;
- } generic;
- unsigned long long l;
-} ia64_inst_t;
-
-/*
- * flush_icache_range() can't be used here.
- * we are here before cpu_init() which initializes
- * ia64_i_cache_stride_shift. flush_icache_range() uses it.
- */
-void __init_or_module
-paravirt_flush_i_cache_range(const void *instr, unsigned long size)
-{
- extern void paravirt_fc_i(const void *addr);
- unsigned long i;
-
- for (i = 0; i < size; i += sizeof(bundle_t))
- paravirt_fc_i(instr + i);
-}
-
-bundle_t* __init_or_module
-paravirt_get_bundle(unsigned long tag)
-{
- return (bundle_t *)(tag & ~3UL);
-}
-
-unsigned long __init_or_module
-paravirt_get_slot(unsigned long tag)
-{
- return tag & 3UL;
-}
-
-unsigned long __init_or_module
-paravirt_get_num_inst(unsigned long stag, unsigned long etag)
-{
- bundle_t *sbundle = paravirt_get_bundle(stag);
- unsigned long sslot = paravirt_get_slot(stag);
- bundle_t *ebundle = paravirt_get_bundle(etag);
- unsigned long eslot = paravirt_get_slot(etag);
-
- return (ebundle - sbundle) * 3 + eslot - sslot + 1;
-}
-
-unsigned long __init_or_module
-paravirt_get_next_tag(unsigned long tag)
-{
- unsigned long slot = paravirt_get_slot(tag);
-
- switch (slot) {
- case 0:
- case 1:
- return tag + 1;
- case 2: {
- bundle_t *bundle = paravirt_get_bundle(tag);
- return (unsigned long)(bundle + 1);
- }
- default:
- BUG();
- }
- /* NOTREACHED */
-}
-
-ia64_inst_t __init_or_module
-paravirt_read_slot0(const bundle_t *bundle)
-{
- ia64_inst_t inst;
- inst.l = bundle->quad0.slot0;
- return inst;
-}
-
-ia64_inst_t __init_or_module
-paravirt_read_slot1(const bundle_t *bundle)
-{
- ia64_inst_t inst;
- inst.l = bundle->quad0.slot1_p0 |
- ((unsigned long long)bundle->quad1.slot1_p1 << 18UL);
- return inst;
-}
-
-ia64_inst_t __init_or_module
-paravirt_read_slot2(const bundle_t *bundle)
-{
- ia64_inst_t inst;
- inst.l = bundle->quad1.slot2;
- return inst;
-}
-
-ia64_inst_t __init_or_module
-paravirt_read_inst(unsigned long tag)
-{
- bundle_t *bundle = paravirt_get_bundle(tag);
- unsigned long slot = paravirt_get_slot(tag);
-
- switch (slot) {
- case 0:
- return paravirt_read_slot0(bundle);
- case 1:
- return paravirt_read_slot1(bundle);
- case 2:
- return paravirt_read_slot2(bundle);
- default:
- BUG();
- }
- /* NOTREACHED */
-}
-
-void __init_or_module
-paravirt_write_slot0(bundle_t *bundle, ia64_inst_t inst)
-{
- bundle->quad0.slot0 = inst.l;
-}
-
-void __init_or_module
-paravirt_write_slot1(bundle_t *bundle, ia64_inst_t inst)
-{
- bundle->quad0.slot1_p0 = inst.l;
- bundle->quad1.slot1_p1 = inst.l >> 18UL;
-}
-
-void __init_or_module
-paravirt_write_slot2(bundle_t *bundle, ia64_inst_t inst)
-{
- bundle->quad1.slot2 = inst.l;
-}
-
-void __init_or_module
-paravirt_write_inst(unsigned long tag, ia64_inst_t inst)
-{
- bundle_t *bundle = paravirt_get_bundle(tag);
- unsigned long slot = paravirt_get_slot(tag);
-
- switch (slot) {
- case 0:
- paravirt_write_slot0(bundle, inst);
- break;
- case 1:
- paravirt_write_slot1(bundle, inst);
- break;
- case 2:
- paravirt_write_slot2(bundle, inst);
- break;
- default:
- BUG();
- break;
- }
- paravirt_flush_i_cache_range(bundle, sizeof(*bundle));
-}
-
-/* for debug */
-void
-paravirt_print_bundle(const bundle_t *bundle)
-{
- const unsigned long *quad = (const unsigned long *)bundle;
- ia64_inst_t slot0 = paravirt_read_slot0(bundle);
- ia64_inst_t slot1 = paravirt_read_slot1(bundle);
- ia64_inst_t slot2 = paravirt_read_slot2(bundle);
-
- printk(KERN_DEBUG
- "bundle 0x%p 0x%016lx 0x%016lx\n", bundle, quad[0], quad[1]);
- printk(KERN_DEBUG
- "bundle template 0x%x\n",
- bundle->quad0.template);
- printk(KERN_DEBUG
- "slot0 0x%lx slot1_p0 0x%lx slot1_p1 0x%lx slot2 0x%lx\n",
- (unsigned long)bundle->quad0.slot0,
- (unsigned long)bundle->quad0.slot1_p0,
- (unsigned long)bundle->quad1.slot1_p1,
- (unsigned long)bundle->quad1.slot2);
- printk(KERN_DEBUG
- "slot0 0x%016llx slot1 0x%016llx slot2 0x%016llx\n",
- slot0.l, slot1.l, slot2.l);
-}
-
-static int noreplace_paravirt __init_or_module = 0;
-
-static int __init setup_noreplace_paravirt(char *str)
-{
- noreplace_paravirt = 1;
- return 1;
-}
-__setup("noreplace-paravirt", setup_noreplace_paravirt);
-
-#ifdef ASM_SUPPORTED
-static void __init_or_module
-fill_nop_bundle(void *sbundle, void *ebundle)
-{
- extern const char paravirt_nop_bundle[];
- extern const unsigned long paravirt_nop_bundle_size;
-
- void *bundle = sbundle;
-
- BUG_ON((((unsigned long)sbundle) % sizeof(bundle_t)) != 0);
- BUG_ON((((unsigned long)ebundle) % sizeof(bundle_t)) != 0);
-
- while (bundle < ebundle) {
- memcpy(bundle, paravirt_nop_bundle, paravirt_nop_bundle_size);
-
- bundle += paravirt_nop_bundle_size;
- }
-}
-
-/* helper function */
-unsigned long __init_or_module
-__paravirt_patch_apply_bundle(void *sbundle, void *ebundle, unsigned long type,
- const struct paravirt_patch_bundle_elem *elems,
- unsigned long nelems,
- const struct paravirt_patch_bundle_elem **found)
-{
- unsigned long used = 0;
- unsigned long i;
-
- BUG_ON((((unsigned long)sbundle) % sizeof(bundle_t)) != 0);
- BUG_ON((((unsigned long)ebundle) % sizeof(bundle_t)) != 0);
-
- found = NULL;
- for (i = 0; i < nelems; i++) {
- const struct paravirt_patch_bundle_elem *p = &elems[i];
- if (p->type == type) {
- unsigned long need = p->ebundle - p->sbundle;
- unsigned long room = ebundle - sbundle;
-
- if (found != NULL)
- *found = p;
-
- if (room < need) {
- /* no room to replace. skip it */
- printk(KERN_DEBUG
- "the space is too small to put "
- "bundles. type %ld need %ld room %ld\n",
- type, need, room);
- break;
- }
-
- used = need;
- memcpy(sbundle, p->sbundle, used);
- break;
- }
- }
-
- return used;
-}
-
-void __init_or_module
-paravirt_patch_apply_bundle(const struct paravirt_patch_site_bundle *start,
- const struct paravirt_patch_site_bundle *end)
-{
- const struct paravirt_patch_site_bundle *p;
-
- if (noreplace_paravirt)
- return;
- if (pv_init_ops.patch_bundle == NULL)
- return;
-
- for (p = start; p < end; p++) {
- unsigned long used;
-
- used = (*pv_init_ops.patch_bundle)(p->sbundle, p->ebundle,
- p->type);
- if (used == 0)
- continue;
-
- fill_nop_bundle(p->sbundle + used, p->ebundle);
- paravirt_flush_i_cache_range(p->sbundle,
- p->ebundle - p->sbundle);
- }
- ia64_sync_i();
- ia64_srlz_i();
-}
-
-/*
- * nop.i, nop.m, nop.f instruction are same format.
- * but nop.b has differennt format.
- * This doesn't support nop.b for now.
- */
-static void __init_or_module
-fill_nop_inst(unsigned long stag, unsigned long etag)
-{
- extern const bundle_t paravirt_nop_mfi_inst_bundle[];
- unsigned long tag;
- const ia64_inst_t nop_inst =
- paravirt_read_slot0(paravirt_nop_mfi_inst_bundle);
-
- for (tag = stag; tag < etag; tag = paravirt_get_next_tag(tag))
- paravirt_write_inst(tag, nop_inst);
-}
-
-void __init_or_module
-paravirt_patch_apply_inst(const struct paravirt_patch_site_inst *start,
- const struct paravirt_patch_site_inst *end)
-{
- const struct paravirt_patch_site_inst *p;
-
- if (noreplace_paravirt)
- return;
- if (pv_init_ops.patch_inst == NULL)
- return;
-
- for (p = start; p < end; p++) {
- unsigned long tag;
- bundle_t *sbundle;
- bundle_t *ebundle;
-
- tag = (*pv_init_ops.patch_inst)(p->stag, p->etag, p->type);
- if (tag == p->stag)
- continue;
-
- fill_nop_inst(tag, p->etag);
- sbundle = paravirt_get_bundle(p->stag);
- ebundle = paravirt_get_bundle(p->etag) + 1;
- paravirt_flush_i_cache_range(sbundle, (ebundle - sbundle) *
- sizeof(bundle_t));
- }
- ia64_sync_i();
- ia64_srlz_i();
-}
-#endif /* ASM_SUPPOTED */
-
-/* brl.cond.sptk.many <target64> X3 */
-typedef union inst_x3_op {
- ia64_inst_t inst;
- struct {
- unsigned long qp: 6;
- unsigned long btyp: 3;
- unsigned long unused: 3;
- unsigned long p: 1;
- unsigned long imm20b: 20;
- unsigned long wh: 2;
- unsigned long d: 1;
- unsigned long i: 1;
- unsigned long opcode: 4;
- };
- unsigned long l;
-} inst_x3_op_t;
-
-typedef union inst_x3_imm {
- ia64_inst_t inst;
- struct {
- unsigned long unused: 2;
- unsigned long imm39: 39;
- };
- unsigned long l;
-} inst_x3_imm_t;
-
-void __init_or_module
-paravirt_patch_reloc_brl(unsigned long tag, const void *target)
-{
- unsigned long tag_op = paravirt_get_next_tag(tag);
- unsigned long tag_imm = tag;
- bundle_t *bundle = paravirt_get_bundle(tag);
-
- ia64_inst_t inst_op = paravirt_read_inst(tag_op);
- ia64_inst_t inst_imm = paravirt_read_inst(tag_imm);
-
- inst_x3_op_t inst_x3_op = { .l = inst_op.l };
- inst_x3_imm_t inst_x3_imm = { .l = inst_imm.l };
-
- unsigned long imm60 =
- ((unsigned long)target - (unsigned long)bundle) >> 4;
-
- BUG_ON(paravirt_get_slot(tag) != 1); /* MLX */
- BUG_ON(((unsigned long)target & (sizeof(bundle_t) - 1)) != 0);
-
- /* imm60[59] 1bit */
- inst_x3_op.i = (imm60 >> 59) & 1;
- /* imm60[19:0] 20bit */
- inst_x3_op.imm20b = imm60 & ((1UL << 20) - 1);
- /* imm60[58:20] 39bit */
- inst_x3_imm.imm39 = (imm60 >> 20) & ((1UL << 39) - 1);
-
- inst_op.l = inst_x3_op.l;
- inst_imm.l = inst_x3_imm.l;
-
- paravirt_write_inst(tag_op, inst_op);
- paravirt_write_inst(tag_imm, inst_imm);
-}
-
-/* br.cond.sptk.many <target25> B1 */
-typedef union inst_b1 {
- ia64_inst_t inst;
- struct {
- unsigned long qp: 6;
- unsigned long btype: 3;
- unsigned long unused: 3;
- unsigned long p: 1;
- unsigned long imm20b: 20;
- unsigned long wh: 2;
- unsigned long d: 1;
- unsigned long s: 1;
- unsigned long opcode: 4;
- };
- unsigned long l;
-} inst_b1_t;
-
-void __init
-paravirt_patch_reloc_br(unsigned long tag, const void *target)
-{
- bundle_t *bundle = paravirt_get_bundle(tag);
- ia64_inst_t inst = paravirt_read_inst(tag);
- unsigned long target25 = (unsigned long)target - (unsigned long)bundle;
- inst_b1_t inst_b1;
-
- BUG_ON(((unsigned long)target & (sizeof(bundle_t) - 1)) != 0);
-
- inst_b1.l = inst.l;
- if (target25 & (1UL << 63))
- inst_b1.s = 1;
- else
- inst_b1.s = 0;
-
- inst_b1.imm20b = target25 >> 4;
- inst.l = inst_b1.l;
-
- paravirt_write_inst(tag, inst);
-}
-
-void __init
-__paravirt_patch_apply_branch(
- unsigned long tag, unsigned long type,
- const struct paravirt_patch_branch_target *entries,
- unsigned int nr_entries)
-{
- unsigned int i;
- for (i = 0; i < nr_entries; i++) {
- if (entries[i].type == type) {
- paravirt_patch_reloc_br(tag, entries[i].entry);
- break;
- }
- }
-}
-
-static void __init
-paravirt_patch_apply_branch(const struct paravirt_patch_site_branch *start,
- const struct paravirt_patch_site_branch *end)
-{
- const struct paravirt_patch_site_branch *p;
-
- if (noreplace_paravirt)
- return;
- if (pv_init_ops.patch_branch == NULL)
- return;
-
- for (p = start; p < end; p++)
- (*pv_init_ops.patch_branch)(p->tag, p->type);
-
- ia64_sync_i();
- ia64_srlz_i();
-}
-
-void __init
-paravirt_patch_apply(void)
-{
- extern const char __start_paravirt_bundles[];
- extern const char __stop_paravirt_bundles[];
- extern const char __start_paravirt_insts[];
- extern const char __stop_paravirt_insts[];
- extern const char __start_paravirt_branches[];
- extern const char __stop_paravirt_branches[];
-
- paravirt_patch_apply_bundle((const struct paravirt_patch_site_bundle *)
- __start_paravirt_bundles,
- (const struct paravirt_patch_site_bundle *)
- __stop_paravirt_bundles);
- paravirt_patch_apply_inst((const struct paravirt_patch_site_inst *)
- __start_paravirt_insts,
- (const struct paravirt_patch_site_inst *)
- __stop_paravirt_insts);
- paravirt_patch_apply_branch((const struct paravirt_patch_site_branch *)
- __start_paravirt_branches,
- (const struct paravirt_patch_site_branch *)
- __stop_paravirt_branches);
-}
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "linux"
- * c-basic-offset: 8
- * tab-width: 8
- * indent-tabs-mode: t
- * End:
- */
diff --git a/arch/ia64/kernel/paravirt_patchlist.c b/arch/ia64/kernel/paravirt_patchlist.c
deleted file mode 100644
index 0a70720662ed..000000000000
--- a/arch/ia64/kernel/paravirt_patchlist.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/******************************************************************************
- * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * 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/bug.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/paravirt.h>
-
-#define DECLARE(name) \
- extern unsigned long \
- __ia64_native_start_gate_##name##_patchlist[]; \
- extern unsigned long \
- __ia64_native_end_gate_##name##_patchlist[]
-
-DECLARE(fsyscall);
-DECLARE(brl_fsys_bubble_down);
-DECLARE(vtop);
-DECLARE(mckinley_e9);
-
-extern unsigned long __start_gate_section[];
-
-#define ASSIGN(name) \
- .start_##name##_patchlist = \
- (unsigned long)__ia64_native_start_gate_##name##_patchlist, \
- .end_##name##_patchlist = \
- (unsigned long)__ia64_native_end_gate_##name##_patchlist
-
-struct pv_patchdata pv_patchdata __initdata = {
- ASSIGN(fsyscall),
- ASSIGN(brl_fsys_bubble_down),
- ASSIGN(vtop),
- ASSIGN(mckinley_e9),
-
- .gate_section = (void*)__start_gate_section,
-};
-
-
-unsigned long __init
-paravirt_get_gate_patchlist(enum pv_gate_patchlist type)
-{
-
-#define CASE(NAME, name) \
- case PV_GATE_START_##NAME: \
- return pv_patchdata.start_##name##_patchlist; \
- case PV_GATE_END_##NAME: \
- return pv_patchdata.end_##name##_patchlist; \
-
- switch (type) {
- CASE(FSYSCALL, fsyscall);
- CASE(BRL_FSYS_BUBBLE_DOWN, brl_fsys_bubble_down);
- CASE(VTOP, vtop);
- CASE(MCKINLEY_E9, mckinley_e9);
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-void * __init
-paravirt_get_gate_section(void)
-{
- return pv_patchdata.gate_section;
-}
diff --git a/arch/ia64/kernel/paravirtentry.S b/arch/ia64/kernel/paravirtentry.S
deleted file mode 100644
index 92d880c4d3d1..000000000000
--- a/arch/ia64/kernel/paravirtentry.S
+++ /dev/null
@@ -1,121 +0,0 @@
-/******************************************************************************
- * linux/arch/ia64/xen/paravirtentry.S
- *
- * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
- * VA Linux Systems Japan K.K.
- *
- * 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 <asm/asmmacro.h>
-#include <asm/asm-offsets.h>
-#include <asm/paravirt_privop.h>
-#include <asm/paravirt_patch.h>
-#include "entry.h"
-
-#define DATA8(sym, init_value) \
- .pushsection .data..read_mostly ; \
- .align 8 ; \
- .global sym ; \
- sym: ; \
- data8 init_value ; \
- .popsection
-
-#define BRANCH(targ, reg, breg, type) \
- PARAVIRT_PATCH_SITE_BR(PARAVIRT_PATCH_TYPE_BR_ ## type) ; \
- ;; \
- movl reg=targ ; \
- ;; \
- ld8 reg=[reg] ; \
- ;; \
- mov breg=reg ; \
- br.cond.sptk.many breg
-
-#define BRANCH_PROC(sym, reg, breg, type) \
- DATA8(paravirt_ ## sym ## _targ, ia64_native_ ## sym) ; \
- GLOBAL_ENTRY(paravirt_ ## sym) ; \
- BRANCH(paravirt_ ## sym ## _targ, reg, breg, type) ; \
- END(paravirt_ ## sym)
-
-#define BRANCH_PROC_UNWINFO(sym, reg, breg, type) \
- DATA8(paravirt_ ## sym ## _targ, ia64_native_ ## sym) ; \
- GLOBAL_ENTRY(paravirt_ ## sym) ; \
- PT_REGS_UNWIND_INFO(0) ; \
- BRANCH(paravirt_ ## sym ## _targ, reg, breg, type) ; \
- END(paravirt_ ## sym)
-
-
-BRANCH_PROC(switch_to, r22, b7, SWITCH_TO)
-BRANCH_PROC_UNWINFO(leave_syscall, r22, b7, LEAVE_SYSCALL)
-BRANCH_PROC(work_processed_syscall, r2, b7, WORK_PROCESSED_SYSCALL)
-BRANCH_PROC_UNWINFO(leave_kernel, r22, b7, LEAVE_KERNEL)
-
-
-#ifdef CONFIG_MODULES
-#define __INIT_OR_MODULE .text
-#define __INITDATA_OR_MODULE .data
-#else
-#define __INIT_OR_MODULE __INIT
-#define __INITDATA_OR_MODULE __INITDATA
-#endif /* CONFIG_MODULES */
-
- __INIT_OR_MODULE
- GLOBAL_ENTRY(paravirt_fc_i)
- fc.i r32
- br.ret.sptk.many rp
- END(paravirt_fc_i)
- __FINIT
-
- __INIT_OR_MODULE
- .align 32
- GLOBAL_ENTRY(paravirt_nop_b_inst_bundle)
- {
- nop.b 0
- nop.b 0
- nop.b 0
- }
- END(paravirt_nop_b_inst_bundle)
- __FINIT
-
- /* NOTE: nop.[mfi] has same format */
- __INIT_OR_MODULE
- GLOBAL_ENTRY(paravirt_nop_mfi_inst_bundle)
- {
- nop.m 0
- nop.f 0
- nop.i 0
- }
- END(paravirt_nop_mfi_inst_bundle)
- __FINIT
-
- __INIT_OR_MODULE
- GLOBAL_ENTRY(paravirt_nop_bundle)
-paravirt_nop_bundle_start:
- {
- nop 0
- nop 0
- nop 0
- }
-paravirt_nop_bundle_end:
- END(paravirt_nop_bundle)
- __FINIT
-
- __INITDATA_OR_MODULE
- .align 8
- .global paravirt_nop_bundle_size
-paravirt_nop_bundle_size:
- data8 paravirt_nop_bundle_end - paravirt_nop_bundle_start
diff --git a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c
index 1cf091793714..944a8e2438a6 100644
--- a/arch/ia64/kernel/patch.c
+++ b/arch/ia64/kernel/patch.c
@@ -7,7 +7,6 @@
#include <linux/init.h>
#include <linux/string.h>
-#include <asm/paravirt.h>
#include <asm/patch.h>
#include <asm/processor.h>
#include <asm/sections.h>
@@ -169,35 +168,16 @@ ia64_patch_mckinley_e9 (unsigned long start, unsigned long end)
ia64_srlz_i();
}
-extern unsigned long ia64_native_fsyscall_table[NR_syscalls];
-extern char ia64_native_fsys_bubble_down[];
-struct pv_fsys_data pv_fsys_data __initdata = {
- .fsyscall_table = (unsigned long *)ia64_native_fsyscall_table,
- .fsys_bubble_down = (void *)ia64_native_fsys_bubble_down,
-};
-
-unsigned long * __init
-paravirt_get_fsyscall_table(void)
-{
- return pv_fsys_data.fsyscall_table;
-}
-
-char * __init
-paravirt_get_fsys_bubble_down(void)
-{
- return pv_fsys_data.fsys_bubble_down;
-}
-
static void __init
patch_fsyscall_table (unsigned long start, unsigned long end)
{
- u64 fsyscall_table = (u64)paravirt_get_fsyscall_table();
+ extern unsigned long fsyscall_table[NR_syscalls];
s32 *offp = (s32 *) start;
u64 ip;
while (offp < (s32 *) end) {
ip = (u64) ia64_imva((char *) offp + *offp);
- ia64_patch_imm64(ip, fsyscall_table);
+ ia64_patch_imm64(ip, (u64) fsyscall_table);
ia64_fc((void *) ip);
++offp;
}
@@ -208,7 +188,7 @@ patch_fsyscall_table (unsigned long start, unsigned long end)
static void __init
patch_brl_fsys_bubble_down (unsigned long start, unsigned long end)
{
- u64 fsys_bubble_down = (u64)paravirt_get_fsys_bubble_down();
+ extern char fsys_bubble_down[];
s32 *offp = (s32 *) start;
u64 ip;
@@ -226,13 +206,13 @@ patch_brl_fsys_bubble_down (unsigned long start, unsigned long end)
void __init
ia64_patch_gate (void)
{
-# define START(name) paravirt_get_gate_patchlist(PV_GATE_START_##name)
-# define END(name) paravirt_get_gate_patchlist(PV_GATE_END_##name)
+# define START(name) ((unsigned long) __start_gate_##name##_patchlist)
+# define END(name) ((unsigned long)__end_gate_##name##_patchlist)
- patch_fsyscall_table(START(FSYSCALL), END(FSYSCALL));
- patch_brl_fsys_bubble_down(START(BRL_FSYS_BUBBLE_DOWN), END(BRL_FSYS_BUBBLE_DOWN));
- ia64_patch_vtop(START(VTOP), END(VTOP));
- ia64_patch_mckinley_e9(START(MCKINLEY_E9), END(MCKINLEY_E9));
+ patch_fsyscall_table(START(fsyscall), END(fsyscall));
+ patch_brl_fsys_bubble_down(START(brl_fsys_bubble_down), END(brl_fsys_bubble_down));
+ ia64_patch_vtop(START(vtop), END(vtop));
+ ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9));
}
void ia64_patch_phys_stack_reg(unsigned long val)
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index b9761389cb8d..4f118b0d3091 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -50,8 +50,6 @@
#include <asm/mca.h>
#include <asm/meminit.h>
#include <asm/page.h>
-#include <asm/paravirt.h>
-#include <asm/paravirt_patch.h>
#include <asm/patch.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
@@ -360,8 +358,6 @@ reserve_memory (void)
rsvd_region[n].end = (unsigned long) ia64_imva(_end);
n++;
- n += paravirt_reserve_memory(&rsvd_region[n]);
-
#ifdef CONFIG_BLK_DEV_INITRD
if (ia64_boot_param->initrd_start) {
rsvd_region[n].start = (unsigned long)__va(ia64_boot_param->initrd_start);
@@ -528,10 +524,7 @@ setup_arch (char **cmdline_p)
{
unw_init();
- paravirt_arch_setup_early();
-
ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end___vtop_patchlist);
- paravirt_patch_apply();
*cmdline_p = __va(ia64_boot_param->command_line);
strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE);
@@ -594,9 +587,6 @@ setup_arch (char **cmdline_p)
cpu_init(); /* initialize the bootstrap CPU */
mmu_context_init(); /* initialize context_id bitmap */
- paravirt_banner();
- paravirt_arch_setup_console(cmdline_p);
-
#ifdef CONFIG_VT
if (!conswitchp) {
# if defined(CONFIG_DUMMY_CONSOLE)
@@ -616,8 +606,6 @@ setup_arch (char **cmdline_p)
#endif
/* enable IA-64 Machine Check Abort Handling unless disabled */
- if (paravirt_arch_setup_nomca())
- nomca = 1;
if (!nomca)
ia64_mca_init();
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index b054c5c6e713..0e76fad27975 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -49,7 +49,6 @@
#include <asm/machvec.h>
#include <asm/mca.h>
#include <asm/page.h>
-#include <asm/paravirt.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
@@ -569,7 +568,6 @@ void smp_prepare_boot_cpu(void)
cpumask_set_cpu(smp_processor_id(), &cpu_callin_map);
set_numa_node(cpu_to_node_map[smp_processor_id()]);
per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
- paravirt_post_smp_prepare_boot_cpu();
}
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 9a0104a38cd3..c8dbe2acd735 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -25,7 +25,6 @@
#include <asm/machvec.h>
#include <asm/delay.h>
#include <asm/hw_irq.h>
-#include <asm/paravirt.h>
#include <asm/ptrace.h>
#include <asm/sal.h>
#include <asm/sections.h>
@@ -47,33 +46,12 @@ EXPORT_SYMBOL(last_cli_ip);
#endif
-#ifdef CONFIG_PARAVIRT
-/* We need to define a real function for sched_clock, to override the
- weak default version */
-unsigned long long sched_clock(void)
-{
- return paravirt_sched_clock();
-}
-#endif
-
-#ifdef CONFIG_PARAVIRT
-static void
-paravirt_clocksource_resume(struct clocksource *cs)
-{
- if (pv_time_ops.clocksource_resume)
- pv_time_ops.clocksource_resume();
-}
-#endif
-
static struct clocksource clocksource_itc = {
.name = "itc",
.rating = 350,
.read = itc_get_cycles,
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
-#ifdef CONFIG_PARAVIRT
- .resume = paravirt_clocksource_resume,
-#endif
};
static struct clocksource *itc_clocksource;
@@ -164,9 +142,6 @@ timer_interrupt (int irq, void *dev_id)
profile_tick(CPU_PROFILING);
- if (paravirt_do_steal_accounting(&new_itm))
- goto skip_process_time_accounting;
-
while (1) {
update_process_times(user_mode(get_irq_regs()));
@@ -187,8 +162,6 @@ timer_interrupt (int irq, void *dev_id)
local_irq_disable();
}
-skip_process_time_accounting:
-
do {
/*
* If we're too close to the next clock tick for
@@ -337,8 +310,6 @@ void ia64_init_itm(void)
*/
clocksource_itc.rating = 50;
- paravirt_init_missing_ticks_accounting(smp_processor_id());
-
/* avoid softlock up message when cpu is unplug and plugged again. */
touch_softlockup_watchdog();
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 84f8a52ac5ae..dc506b05ffbd 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -136,27 +136,6 @@ SECTIONS {
__end___mckinley_e9_bundles = .;
}
-#if defined(CONFIG_PARAVIRT)
- . = ALIGN(16);
- .paravirt_bundles : AT(ADDR(.paravirt_bundles) - LOAD_OFFSET) {
- __start_paravirt_bundles = .;
- *(.paravirt_bundles)
- __stop_paravirt_bundles = .;
- }
- . = ALIGN(16);
- .paravirt_insts : AT(ADDR(.paravirt_insts) - LOAD_OFFSET) {
- __start_paravirt_insts = .;
- *(.paravirt_insts)
- __stop_paravirt_insts = .;
- }
- . = ALIGN(16);
- .paravirt_branches : AT(ADDR(.paravirt_branches) - LOAD_OFFSET) {
- __start_paravirt_branches = .;
- *(.paravirt_branches)
- __stop_paravirt_branches = .;
- }
-#endif
-
#if defined(CONFIG_IA64_GENERIC)
/* Machine Vector */
. = ALIGN(16);
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index ba5ba7accd0d..70b40d1205a6 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -11,10 +11,10 @@
#include <linux/kprobes.h>
#include <linux/kdebug.h>
#include <linux/prefetch.h>
+#include <linux/uaccess.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
-#include <asm/uaccess.h>
extern int die(char *, struct pt_regs *, long);
@@ -96,7 +96,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
/*
* If we're in an interrupt or have no user context, we must not take the fault..
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto no_context;
#ifdef CONFIG_VIRTUAL_MEM_MAP
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
index 52b7604b5215..f50d4b3f501a 100644
--- a/arch/ia64/mm/hugetlbpage.c
+++ b/arch/ia64/mm/hugetlbpage.c
@@ -65,11 +65,6 @@ huge_pte_offset (struct mm_struct *mm, unsigned long addr)
return pte;
}
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
- return 0;
-}
-
#define mk_pte_huge(entry) { pte_val(entry) |= _PAGE_P; }
/*
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index a9b65cf7b34a..7f3028965064 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -34,7 +34,6 @@
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/mca.h>
-#include <asm/paravirt.h>
extern void ia64_tlb_init (void);
@@ -244,7 +243,6 @@ put_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot)
static void __init
setup_gate (void)
{
- void *gate_section;
struct page *page;
/*
@@ -252,11 +250,10 @@ setup_gate (void)
* headers etc. and once execute-only page to enable
* privilege-promotion via "epc":
*/
- gate_section = paravirt_get_gate_section();
- page = virt_to_page(ia64_imva(gate_section));
+ page = virt_to_page(ia64_imva(__start_gate_section));
put_kernel_page(page, GATE_ADDR, PAGE_READONLY);
#ifdef HAVE_BUGGY_SEGREL
- page = virt_to_page(ia64_imva(gate_section + PAGE_SIZE));
+ page = virt_to_page(ia64_imva(__start_gate_section + PAGE_SIZE));
put_kernel_page(page, GATE_ADDR + PAGE_SIZE, PAGE_GATE);
#else
put_kernel_page(page, GATE_ADDR + PERCPU_PAGE_SIZE, PAGE_GATE);
@@ -642,8 +639,8 @@ mem_init (void)
* code can tell them apart.
*/
for (i = 0; i < NR_syscalls; ++i) {
+ extern unsigned long fsyscall_table[NR_syscalls];
extern unsigned long sys_call_table[NR_syscalls];
- unsigned long *fsyscall_table = paravirt_get_fsyscall_table();
if (!fsyscall_table[i] || nolwsys)
fsyscall_table[i] = sys_call_table[i] | 1;
diff --git a/arch/ia64/scripts/pvcheck.sed b/arch/ia64/scripts/pvcheck.sed
deleted file mode 100644
index e59809a3fc01..000000000000
--- a/arch/ia64/scripts/pvcheck.sed
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Checker for paravirtualizations of privileged operations.
-#
-s/ssm.*psr\.ic.*/.warning \"ssm psr.ic should not be used directly\"/g
-s/rsm.*psr\.ic.*/.warning \"rsm psr.ic should not be used directly\"/g
-s/ssm.*psr\.i.*/.warning \"ssm psr.i should not be used directly\"/g
-s/rsm.*psr\.i.*/.warning \"rsm psr.i should not be used directly\"/g
-s/ssm.*psr\.dt.*/.warning \"ssm psr.dt should not be used directly\"/g
-s/rsm.*psr\.dt.*/.warning \"rsm psr.dt should not be used directly\"/g
-s/mov.*=.*cr\.ifa/.warning \"cr.ifa should not used directly\"/g
-s/mov.*=.*cr\.itir/.warning \"cr.itir should not used directly\"/g
-s/mov.*=.*cr\.isr/.warning \"cr.isr should not used directly\"/g
-s/mov.*=.*cr\.iha/.warning \"cr.iha should not used directly\"/g
-s/mov.*=.*cr\.ipsr/.warning \"cr.ipsr should not used directly\"/g
-s/mov.*=.*cr\.iim/.warning \"cr.iim should not used directly\"/g
-s/mov.*=.*cr\.iip/.warning \"cr.iip should not used directly\"/g
-s/mov.*=.*cr\.ivr/.warning \"cr.ivr should not used directly\"/g
-s/mov.*=[^\.]*psr/.warning \"psr should not used directly\"/g # avoid ar.fpsr
-s/mov.*=.*ar\.eflags/.warning \"ar.eflags should not used directly\"/g
-s/mov.*=.*ar\.itc.*/.warning \"ar.itc should not used directly\"/g
-s/mov.*cr\.ifa.*=.*/.warning \"cr.ifa should not used directly\"/g
-s/mov.*cr\.itir.*=.*/.warning \"cr.itir should not used directly\"/g
-s/mov.*cr\.iha.*=.*/.warning \"cr.iha should not used directly\"/g
-s/mov.*cr\.ipsr.*=.*/.warning \"cr.ipsr should not used directly\"/g
-s/mov.*cr\.ifs.*=.*/.warning \"cr.ifs should not used directly\"/g
-s/mov.*cr\.iip.*=.*/.warning \"cr.iip should not used directly\"/g
-s/mov.*cr\.kr.*=.*/.warning \"cr.kr should not used directly\"/g
-s/mov.*ar\.eflags.*=.*/.warning \"ar.eflags should not used directly\"/g
-s/itc\.i.*/.warning \"itc.i should not be used directly.\"/g
-s/itc\.d.*/.warning \"itc.d should not be used directly.\"/g
-s/bsw\.0/.warning \"bsw.0 should not be used directly.\"/g
-s/bsw\.1/.warning \"bsw.1 should not be used directly.\"/g
-s/ptc\.ga.*/.warning \"ptc.ga should not be used directly.\"/g
diff --git a/arch/m32r/include/asm/Kbuild b/arch/m32r/include/asm/Kbuild
index 2edc793372fc..ba1cdc018731 100644
--- a/arch/m32r/include/asm/Kbuild
+++ b/arch/m32r/include/asm/Kbuild
@@ -6,6 +6,5 @@ generic-y += irq_work.h
generic-y += mcs_spinlock.h
generic-y += module.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += trace_clock.h
diff --git a/arch/m32r/include/asm/cmpxchg.h b/arch/m32r/include/asm/cmpxchg.h
index de651db20b43..14bf9b739dd2 100644
--- a/arch/m32r/include/asm/cmpxchg.h
+++ b/arch/m32r/include/asm/cmpxchg.h
@@ -107,8 +107,6 @@ __xchg_local(unsigned long x, volatile void *ptr, int size)
((__typeof__(*(ptr)))__xchg_local((unsigned long)(x), (ptr), \
sizeof(*(ptr))))
-#define __HAVE_ARCH_CMPXCHG 1
-
static inline unsigned long
__cmpxchg_u32(volatile unsigned int *p, unsigned int old, unsigned int new)
{
diff --git a/arch/m32r/include/asm/io.h b/arch/m32r/include/asm/io.h
index 9cc00dbd59ce..0c3f25ee3381 100644
--- a/arch/m32r/include/asm/io.h
+++ b/arch/m32r/include/asm/io.h
@@ -68,6 +68,7 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
extern void iounmap(volatile void __iomem *addr);
#define ioremap_nocache(off,size) ioremap(off,size)
#define ioremap_wc ioremap_nocache
+#define ioremap_wt ioremap_nocache
/*
* IO bus memory addresses are also 1:1 with the physical address
diff --git a/arch/m32r/include/asm/mm-arch-hooks.h b/arch/m32r/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..6d60b4750f41
--- /dev/null
+++ b/arch/m32r/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_M32R_MM_ARCH_HOOKS_H
+#define _ASM_M32R_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_M32R_MM_ARCH_HOOKS_H */
diff --git a/arch/m32r/include/asm/uaccess.h b/arch/m32r/include/asm/uaccess.h
index 71adff209405..cac7014daef3 100644
--- a/arch/m32r/include/asm/uaccess.h
+++ b/arch/m32r/include/asm/uaccess.h
@@ -91,7 +91,8 @@ static inline void set_fs(mm_segment_t s)
* @addr: User space pointer to start of block to check
* @size: Size of block to check
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Checks if a pointer to a block of memory in user space is valid.
*
@@ -155,7 +156,8 @@ extern int fixup_exception(struct pt_regs *regs);
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
@@ -175,7 +177,8 @@ extern int fixup_exception(struct pt_regs *regs);
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
@@ -194,7 +197,8 @@ extern int fixup_exception(struct pt_regs *regs);
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
@@ -274,7 +278,8 @@ do { \
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
@@ -568,7 +573,8 @@ unsigned long __generic_copy_from_user(void *, const void __user *, unsigned lon
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from kernel space to user space. Caller must check
* the specified block with access_ok() before calling this function.
@@ -588,7 +594,8 @@ unsigned long __generic_copy_from_user(void *, const void __user *, unsigned lon
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from kernel space to user space.
*
@@ -606,7 +613,8 @@ unsigned long __generic_copy_from_user(void *, const void __user *, unsigned lon
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from user space to kernel space. Caller must check
* the specified block with access_ok() before calling this function.
@@ -626,7 +634,8 @@ unsigned long __generic_copy_from_user(void *, const void __user *, unsigned lon
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from user space to kernel space.
*
@@ -677,7 +686,8 @@ unsigned long clear_user(void __user *mem, unsigned long len);
* strlen_user: - Get the size of a string in user space.
* @str: The string to measure.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Get the size of a NUL-terminated string in user space.
*
diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c
index e3d4d4890104..8f9875b7933d 100644
--- a/arch/m32r/mm/fault.c
+++ b/arch/m32r/mm/fault.c
@@ -24,9 +24,9 @@
#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/highmem.h>
#include <linux/module.h>
+#include <linux/uaccess.h>
#include <asm/m32r.h>
-#include <asm/uaccess.h>
#include <asm/hardirq.h>
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
@@ -111,10 +111,10 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
mm = tsk->mm;
/*
- * If we're in an interrupt or have no user context or are running in an
- * atomic region then we must not take the fault..
+ * If we're in an interrupt or have no user context or have pagefaults
+ * disabled then we must not take the fault.
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto bad_area_nosemaphore;
if (error_code & ACE_USERMODE)
diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig
index ed1643b4c678..753a6237f99a 100644
--- a/arch/m68k/configs/amiga_defconfig
+++ b/arch/m68k/configs/amiga_defconfig
@@ -177,9 +177,9 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
@@ -267,7 +267,9 @@ CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
+CONFIG_MPLS_ROUTING=m
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -285,6 +287,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_PMEM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_DUMMY_IRQ=m
@@ -324,6 +327,7 @@ CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_UEVENT=y
+CONFIG_DM_LOG_WRITES=m
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
@@ -348,6 +352,7 @@ CONFIG_VETH=m
CONFIG_A2065=y
CONFIG_ARIADNE=y
# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_CIRRUS is not set
# CONFIG_NET_VENDOR_HP is not set
@@ -414,7 +419,6 @@ CONFIG_HID=m
CONFIG_HIDRAW=y
CONFIG_UHID=m
# CONFIG_HID_GENERIC is not set
-# CONFIG_HID_PLANTRONICS is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_MSM6242=m
diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig
index d38822b1847e..1f93dcaf02e5 100644
--- a/arch/m68k/configs/apollo_defconfig
+++ b/arch/m68k/configs/apollo_defconfig
@@ -175,9 +175,9 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
@@ -265,7 +265,9 @@ CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
+CONFIG_MPLS_ROUTING=m
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -277,6 +279,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_PMEM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_DUMMY_IRQ=m
@@ -306,6 +309,7 @@ CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_UEVENT=y
+CONFIG_DM_LOG_WRITES=m
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
@@ -327,6 +331,7 @@ CONFIG_NETCONSOLE=m
CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_VETH=m
# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
@@ -375,7 +380,6 @@ CONFIG_HID=m
CONFIG_HIDRAW=y
CONFIG_UHID=m
# CONFIG_HID_GENERIC is not set
-# CONFIG_HID_PLANTRONICS is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GENERIC=m
diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig
index c429199cf4a9..831b8b8b92ad 100644
--- a/arch/m68k/configs/atari_defconfig
+++ b/arch/m68k/configs/atari_defconfig
@@ -175,9 +175,9 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
@@ -265,7 +265,9 @@ CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
+CONFIG_MPLS_ROUTING=m
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -281,6 +283,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_PMEM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_DUMMY_IRQ=m
@@ -315,6 +318,7 @@ CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_UEVENT=y
+CONFIG_DM_LOG_WRITES=m
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
@@ -337,6 +341,7 @@ CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_VETH=m
CONFIG_ATARILANCE=y
# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
@@ -391,7 +396,6 @@ CONFIG_DMASOUND_ATARI=m
CONFIG_HID=m
CONFIG_HIDRAW=y
CONFIG_UHID=m
-# CONFIG_HID_PLANTRONICS is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GENERIC=m
# CONFIG_IOMMU_SUPPORT is not set
diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig
index 9b880371d642..91fd187c16d5 100644
--- a/arch/m68k/configs/bvme6000_defconfig
+++ b/arch/m68k/configs/bvme6000_defconfig
@@ -173,9 +173,9 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
@@ -263,7 +263,9 @@ CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
+CONFIG_MPLS_ROUTING=m
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -275,6 +277,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_PMEM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_DUMMY_IRQ=m
@@ -305,6 +308,7 @@ CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_UEVENT=y
+CONFIG_DM_LOG_WRITES=m
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
@@ -326,6 +330,7 @@ CONFIG_NETCONSOLE=m
CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_VETH=m
# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
CONFIG_BVME6000_NET=y
# CONFIG_NET_VENDOR_MARVELL is not set
@@ -369,7 +374,6 @@ CONFIG_HID=m
CONFIG_HIDRAW=y
CONFIG_UHID=m
# CONFIG_HID_GENERIC is not set
-# CONFIG_HID_PLANTRONICS is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GENERIC=m
diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig
index 49ae3376e993..9d4934f1d2c3 100644
--- a/arch/m68k/configs/hp300_defconfig
+++ b/arch/m68k/configs/hp300_defconfig
@@ -175,9 +175,9 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
@@ -265,7 +265,9 @@ CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
+CONFIG_MPLS_ROUTING=m
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -277,6 +279,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_PMEM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_DUMMY_IRQ=m
@@ -306,6 +309,7 @@ CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_UEVENT=y
+CONFIG_DM_LOG_WRITES=m
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
@@ -328,6 +332,7 @@ CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_VETH=m
CONFIG_HPLANCE=y
# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
@@ -378,7 +383,6 @@ CONFIG_HID=m
CONFIG_HIDRAW=y
CONFIG_UHID=m
# CONFIG_HID_GENERIC is not set
-# CONFIG_HID_PLANTRONICS is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GENERIC=m
diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig
index ee143a57058c..72bc187ca995 100644
--- a/arch/m68k/configs/mac_defconfig
+++ b/arch/m68k/configs/mac_defconfig
@@ -174,9 +174,9 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
@@ -267,7 +267,9 @@ CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
+CONFIG_MPLS_ROUTING=m
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -280,6 +282,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_PMEM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_DUMMY_IRQ=m
@@ -315,6 +318,7 @@ CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_UEVENT=y
+CONFIG_DM_LOG_WRITES=m
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
@@ -344,6 +348,7 @@ CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_VETH=m
CONFIG_MACMACE=y
# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
CONFIG_MAC89x0=y
# CONFIG_NET_VENDOR_INTEL is not set
@@ -400,7 +405,6 @@ CONFIG_HID=m
CONFIG_HIDRAW=y
CONFIG_UHID=m
# CONFIG_HID_GENERIC is not set
-# CONFIG_HID_PLANTRONICS is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GENERIC=m
diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig
index c777aa05048f..8fb65535597f 100644
--- a/arch/m68k/configs/multi_defconfig
+++ b/arch/m68k/configs/multi_defconfig
@@ -184,9 +184,9 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
@@ -277,7 +277,9 @@ CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
+CONFIG_MPLS_ROUTING=m
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -299,6 +301,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_PMEM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_DUMMY_IRQ=m
@@ -348,6 +351,7 @@ CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_UEVENT=y
+CONFIG_DM_LOG_WRITES=m
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
@@ -384,6 +388,7 @@ CONFIG_MVME147_NET=y
CONFIG_SUN3LANCE=y
CONFIG_MACMACE=y
# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
CONFIG_MAC89x0=y
# CONFIG_NET_VENDOR_HP is not set
@@ -468,7 +473,6 @@ CONFIG_HID=m
CONFIG_HIDRAW=y
CONFIG_UHID=m
# CONFIG_HID_GENERIC is not set
-# CONFIG_HID_PLANTRONICS is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_MSM6242=m
diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig
index a7628a85e260..f34491ec0126 100644
--- a/arch/m68k/configs/mvme147_defconfig
+++ b/arch/m68k/configs/mvme147_defconfig
@@ -172,9 +172,9 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
@@ -262,7 +262,9 @@ CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
+CONFIG_MPLS_ROUTING=m
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -274,6 +276,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_PMEM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_DUMMY_IRQ=m
@@ -304,6 +307,7 @@ CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_UEVENT=y
+CONFIG_DM_LOG_WRITES=m
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
@@ -326,6 +330,7 @@ CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_VETH=m
CONFIG_MVME147_NET=y
# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
@@ -369,7 +374,6 @@ CONFIG_HID=m
CONFIG_HIDRAW=y
CONFIG_UHID=m
# CONFIG_HID_GENERIC is not set
-# CONFIG_HID_PLANTRONICS is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GENERIC=m
diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig
index ebaa68268a4a..3d3614d1b041 100644
--- a/arch/m68k/configs/mvme16x_defconfig
+++ b/arch/m68k/configs/mvme16x_defconfig
@@ -173,9 +173,9 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
@@ -263,7 +263,9 @@ CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
+CONFIG_MPLS_ROUTING=m
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -275,6 +277,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_PMEM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_DUMMY_IRQ=m
@@ -305,6 +308,7 @@ CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_UEVENT=y
+CONFIG_DM_LOG_WRITES=m
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
@@ -326,6 +330,7 @@ CONFIG_NETCONSOLE=m
CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_VETH=m
# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
CONFIG_MVME16x_NET=y
# CONFIG_NET_VENDOR_MARVELL is not set
@@ -369,7 +374,6 @@ CONFIG_HID=m
CONFIG_HIDRAW=y
CONFIG_UHID=m
# CONFIG_HID_GENERIC is not set
-# CONFIG_HID_PLANTRONICS is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GENERIC=m
diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig
index 2c16853aedd3..643e9c93bea7 100644
--- a/arch/m68k/configs/q40_defconfig
+++ b/arch/m68k/configs/q40_defconfig
@@ -173,9 +173,9 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
@@ -263,7 +263,9 @@ CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
+CONFIG_MPLS_ROUTING=m
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -278,6 +280,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_PMEM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_DUMMY_IRQ=m
@@ -311,6 +314,7 @@ CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_UEVENT=y
+CONFIG_DM_LOG_WRITES=m
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
@@ -334,6 +338,7 @@ CONFIG_VETH=m
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_AMD is not set
# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_CIRRUS is not set
# CONFIG_NET_VENDOR_HP is not set
@@ -390,7 +395,6 @@ CONFIG_HID=m
CONFIG_HIDRAW=y
CONFIG_UHID=m
# CONFIG_HID_GENERIC is not set
-# CONFIG_HID_PLANTRONICS is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GENERIC=m
diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig
index e3056bf0f65b..8fecc5aa166c 100644
--- a/arch/m68k/configs/sun3_defconfig
+++ b/arch/m68k/configs/sun3_defconfig
@@ -170,9 +170,9 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
@@ -260,7 +260,9 @@ CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
+CONFIG_MPLS_ROUTING=m
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -272,6 +274,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_PMEM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_DUMMY_IRQ=m
@@ -302,6 +305,7 @@ CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_UEVENT=y
+CONFIG_DM_LOG_WRITES=m
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
@@ -324,6 +328,7 @@ CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_VETH=m
CONFIG_SUN3LANCE=y
# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
CONFIG_SUN3_82586=y
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MICREL is not set
@@ -370,7 +375,6 @@ CONFIG_HID=m
CONFIG_HIDRAW=y
CONFIG_UHID=m
# CONFIG_HID_GENERIC is not set
-# CONFIG_HID_PLANTRONICS is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GENERIC=m
diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig
index 73c36b7a0009..9902c5bfbdc8 100644
--- a/arch/m68k/configs/sun3x_defconfig
+++ b/arch/m68k/configs/sun3x_defconfig
@@ -170,9 +170,9 @@ CONFIG_IP_SET_HASH_NETPORT=m
CONFIG_IP_SET_HASH_NETIFACE=m
CONFIG_IP_SET_LIST_SET=m
CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_LOG_ARP=m
CONFIG_NFT_CHAIN_NAT_IPV4=m
CONFIG_NFT_MASQ_IPV4=m
CONFIG_NFT_REDIR_IPV4=m
@@ -260,7 +260,9 @@ CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_NC=y
CONFIG_BATMAN_ADV_MCAST=y
CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
+CONFIG_MPLS_ROUTING=m
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -272,6 +274,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_PMEM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_DUMMY_IRQ=m
@@ -302,6 +305,7 @@ CONFIG_DM_RAID=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
CONFIG_DM_UEVENT=y
+CONFIG_DM_LOG_WRITES=m
CONFIG_TARGET_CORE=m
CONFIG_TCM_IBLOCK=m
CONFIG_TCM_FILEIO=m
@@ -324,6 +328,7 @@ CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_VETH=m
CONFIG_SUN3LANCE=y
# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
@@ -370,7 +375,6 @@ CONFIG_HID=m
CONFIG_HIDRAW=y
CONFIG_UHID=m
# CONFIG_HID_GENERIC is not set
-# CONFIG_HID_PLANTRONICS is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GENERIC=m
diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild
index 1517ed1c6471..1555bc189c7d 100644
--- a/arch/m68k/include/asm/Kbuild
+++ b/arch/m68k/include/asm/Kbuild
@@ -23,7 +23,6 @@ generic-y += mutex.h
generic-y += percpu.h
generic-y += preempt.h
generic-y += resource.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += shmparam.h
generic-y += siginfo.h
diff --git a/arch/m68k/include/asm/cmpxchg.h b/arch/m68k/include/asm/cmpxchg.h
index bc755bc620ad..83b1df80f0ac 100644
--- a/arch/m68k/include/asm/cmpxchg.h
+++ b/arch/m68k/include/asm/cmpxchg.h
@@ -90,7 +90,6 @@ extern unsigned long __invalid_cmpxchg_size(volatile void *,
* indicated by comparing RETURN with OLD.
*/
#ifdef CONFIG_RMW_INSNS
-#define __HAVE_ARCH_CMPXCHG 1
static inline unsigned long __cmpxchg(volatile void *p, unsigned long old,
unsigned long new, int size)
diff --git a/arch/m68k/include/asm/io_mm.h b/arch/m68k/include/asm/io_mm.h
index 8955b40a5dc4..618c85d3c786 100644
--- a/arch/m68k/include/asm/io_mm.h
+++ b/arch/m68k/include/asm/io_mm.h
@@ -20,6 +20,8 @@
#ifdef __KERNEL__
+#define ARCH_HAS_IOREMAP_WT
+
#include <linux/compiler.h>
#include <asm/raw_io.h>
#include <asm/virtconvert.h>
@@ -465,7 +467,7 @@ static inline void __iomem *ioremap_nocache(unsigned long physaddr, unsigned lon
{
return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
}
-static inline void __iomem *ioremap_writethrough(unsigned long physaddr,
+static inline void __iomem *ioremap_wt(unsigned long physaddr,
unsigned long size)
{
return __ioremap(physaddr, size, IOMAP_WRITETHROUGH);
diff --git a/arch/m68k/include/asm/io_no.h b/arch/m68k/include/asm/io_no.h
index a93c8cde4d38..ad7bd40e6742 100644
--- a/arch/m68k/include/asm/io_no.h
+++ b/arch/m68k/include/asm/io_no.h
@@ -3,6 +3,8 @@
#ifdef __KERNEL__
+#define ARCH_HAS_IOREMAP_WT
+
#include <asm/virtconvert.h>
#include <asm-generic/iomap.h>
@@ -153,7 +155,7 @@ static inline void *ioremap_nocache(unsigned long physaddr, unsigned long size)
{
return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
}
-static inline void *ioremap_writethrough(unsigned long physaddr, unsigned long size)
+static inline void *ioremap_wt(unsigned long physaddr, unsigned long size)
{
return __ioremap(physaddr, size, IOMAP_WRITETHROUGH);
}
diff --git a/arch/m68k/include/asm/irqflags.h b/arch/m68k/include/asm/irqflags.h
index a823cd73dc09..b5941818346f 100644
--- a/arch/m68k/include/asm/irqflags.h
+++ b/arch/m68k/include/asm/irqflags.h
@@ -2,9 +2,6 @@
#define _M68K_IRQFLAGS_H
#include <linux/types.h>
-#ifdef CONFIG_MMU
-#include <linux/preempt_mask.h>
-#endif
#include <linux/preempt.h>
#include <asm/thread_info.h>
#include <asm/entry.h>
diff --git a/arch/m68k/include/asm/mm-arch-hooks.h b/arch/m68k/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..7e8709bc90ae
--- /dev/null
+++ b/arch/m68k/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_M68K_MM_ARCH_HOOKS_H
+#define _ASM_M68K_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_M68K_MM_ARCH_HOOKS_H */
diff --git a/arch/m68k/include/asm/serial.h b/arch/m68k/include/asm/serial.h
index 7267536adbcc..06d0cb19b4e1 100644
--- a/arch/m68k/include/asm/serial.h
+++ b/arch/m68k/include/asm/serial.h
@@ -17,7 +17,7 @@
#define BASE_BAUD ( 1843200 / 16 )
/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
#else
diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c
index e546a5534dd4..564665f9af30 100644
--- a/arch/m68k/kernel/dma.c
+++ b/arch/m68k/kernel/dma.c
@@ -120,13 +120,16 @@ void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
}
EXPORT_SYMBOL(dma_sync_single_for_device);
-void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction dir)
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
+ int nents, enum dma_data_direction dir)
{
int i;
+ struct scatterlist *sg;
- for (i = 0; i < nents; sg++, i++)
- dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
+ for_each_sg(sglist, sg, nents, i) {
+ dma_sync_single_for_device(dev, sg->dma_address, sg->length,
+ dir);
+ }
}
EXPORT_SYMBOL(dma_sync_sg_for_device);
@@ -151,14 +154,16 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page,
}
EXPORT_SYMBOL(dma_map_page);
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
enum dma_data_direction dir)
{
int i;
+ struct scatterlist *sg;
- for (i = 0; i < nents; sg++, i++) {
+ for_each_sg(sglist, sg, nents, i) {
sg->dma_address = sg_phys(sg);
- dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
+ dma_sync_single_for_device(dev, sg->dma_address, sg->length,
+ dir);
}
return nents;
}
diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c
index b2f04aee46ec..6a94cdd0c830 100644
--- a/arch/m68k/mm/fault.c
+++ b/arch/m68k/mm/fault.c
@@ -10,10 +10,10 @@
#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/uaccess.h>
#include <asm/setup.h>
#include <asm/traps.h>
-#include <asm/uaccess.h>
#include <asm/pgalloc.h>
extern void die_if_kernel(char *, struct pt_regs *, long);
@@ -81,7 +81,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto no_context;
if (user_mode(regs))
diff --git a/arch/metag/include/asm/Kbuild b/arch/metag/include/asm/Kbuild
index 0bf5d525b945..199320f3c345 100644
--- a/arch/metag/include/asm/Kbuild
+++ b/arch/metag/include/asm/Kbuild
@@ -33,7 +33,6 @@ generic-y += percpu.h
generic-y += poll.h
generic-y += posix_types.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += sembuf.h
generic-y += serial.h
diff --git a/arch/metag/include/asm/barrier.h b/arch/metag/include/asm/barrier.h
index d703d8e26a65..5a696e507930 100644
--- a/arch/metag/include/asm/barrier.h
+++ b/arch/metag/include/asm/barrier.h
@@ -84,7 +84,7 @@ static inline void fence(void)
#define read_barrier_depends() do { } while (0)
#define smp_read_barrier_depends() do { } while (0)
-#define set_mb(var, value) do { var = value; smp_mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
#define smp_store_release(p, v) \
do { \
diff --git a/arch/metag/include/asm/cmpxchg.h b/arch/metag/include/asm/cmpxchg.h
index b1bc1be8540f..be29e3e44321 100644
--- a/arch/metag/include/asm/cmpxchg.h
+++ b/arch/metag/include/asm/cmpxchg.h
@@ -51,8 +51,6 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
return old;
}
-#define __HAVE_ARCH_CMPXCHG 1
-
#define cmpxchg(ptr, o, n) \
({ \
__typeof__(*(ptr)) _o_ = (o); \
diff --git a/arch/metag/include/asm/dma-mapping.h b/arch/metag/include/asm/dma-mapping.h
index 14b23efd9b7a..eb5cdec94be0 100644
--- a/arch/metag/include/asm/dma-mapping.h
+++ b/arch/metag/include/asm/dma-mapping.h
@@ -134,20 +134,24 @@ dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
}
static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nelems,
enum dma_data_direction direction)
{
int i;
- for (i = 0; i < nelems; i++, sg++)
+ struct scatterlist *sg;
+
+ for_each_sg(sglist, sg, nelems, i)
dma_sync_for_cpu(sg_virt(sg), sg->length, direction);
}
static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
- enum dma_data_direction direction)
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction direction)
{
int i;
- for (i = 0; i < nelems; i++, sg++)
+ struct scatterlist *sg;
+
+ for_each_sg(sglist, sg, nelems, i)
dma_sync_for_device(sg_virt(sg), sg->length, direction);
}
diff --git a/arch/metag/include/asm/hugetlb.h b/arch/metag/include/asm/hugetlb.h
index 471f481e67f3..905ed422dbeb 100644
--- a/arch/metag/include/asm/hugetlb.h
+++ b/arch/metag/include/asm/hugetlb.h
@@ -14,10 +14,6 @@ static inline int is_hugepage_only_range(struct mm_struct *mm,
int prepare_hugepage_range(struct file *file, unsigned long addr,
unsigned long len);
-static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
-{
-}
-
static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
unsigned long addr, unsigned long end,
unsigned long floor,
@@ -71,15 +67,6 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
return *ptep;
}
-static inline int arch_prepare_hugepage(struct page *page)
-{
- return 0;
-}
-
-static inline void arch_release_hugepage(struct page *page)
-{
-}
-
static inline void arch_clear_hugepage_flags(struct page *page)
{
}
diff --git a/arch/metag/include/asm/io.h b/arch/metag/include/asm/io.h
index d5779b0ec573..9890f21eadbe 100644
--- a/arch/metag/include/asm/io.h
+++ b/arch/metag/include/asm/io.h
@@ -160,6 +160,9 @@ extern void __iounmap(void __iomem *addr);
#define ioremap_wc(offset, size) \
__ioremap((offset), (size), _PAGE_WR_COMBINE)
+#define ioremap_wt(offset, size) \
+ __ioremap((offset), (size), 0)
+
#define iounmap(addr) \
__iounmap(addr)
diff --git a/arch/metag/include/asm/mm-arch-hooks.h b/arch/metag/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..b0072b2eb0de
--- /dev/null
+++ b/arch/metag/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_METAG_MM_ARCH_HOOKS_H
+#define _ASM_METAG_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_METAG_MM_ARCH_HOOKS_H */
diff --git a/arch/metag/mm/fault.c b/arch/metag/mm/fault.c
index 2de5dc695a87..f57edca63609 100644
--- a/arch/metag/mm/fault.c
+++ b/arch/metag/mm/fault.c
@@ -105,7 +105,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
mm = tsk->mm;
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto no_context;
if (user_mode(regs))
diff --git a/arch/metag/mm/highmem.c b/arch/metag/mm/highmem.c
index d71f621a2c0b..807f1b1c4e65 100644
--- a/arch/metag/mm/highmem.c
+++ b/arch/metag/mm/highmem.c
@@ -43,7 +43,7 @@ void *kmap_atomic(struct page *page)
unsigned long vaddr;
int type;
- /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+ preempt_disable();
pagefault_disable();
if (!PageHighMem(page))
return page_address(page);
@@ -82,6 +82,7 @@ void __kunmap_atomic(void *kvaddr)
}
pagefault_enable();
+ preempt_enable();
}
EXPORT_SYMBOL(__kunmap_atomic);
@@ -95,6 +96,7 @@ void *kmap_atomic_pfn(unsigned long pfn)
unsigned long vaddr;
int type;
+ preempt_disable();
pagefault_disable();
type = kmap_atomic_idx_push();
diff --git a/arch/metag/mm/hugetlbpage.c b/arch/metag/mm/hugetlbpage.c
index 7ca80ac42ed5..53f0f6c47027 100644
--- a/arch/metag/mm/hugetlbpage.c
+++ b/arch/metag/mm/hugetlbpage.c
@@ -89,11 +89,6 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
return pte;
}
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
- return 0;
-}
-
int pmd_huge(pmd_t pmd)
{
return pmd_page_shift(pmd) > PAGE_SHIFT;
diff --git a/arch/microblaze/include/asm/Kbuild b/arch/microblaze/include/asm/Kbuild
index ab564a6db5c3..9989ddb169ca 100644
--- a/arch/microblaze/include/asm/Kbuild
+++ b/arch/microblaze/include/asm/Kbuild
@@ -7,6 +7,5 @@ generic-y += exec.h
generic-y += irq_work.h
generic-y += mcs_spinlock.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += syscalls.h
generic-y += trace_clock.h
diff --git a/arch/microblaze/include/asm/io.h b/arch/microblaze/include/asm/io.h
index 940f5fc1d1da..39b6315db82e 100644
--- a/arch/microblaze/include/asm/io.h
+++ b/arch/microblaze/include/asm/io.h
@@ -39,10 +39,10 @@ extern resource_size_t isa_mem_base;
extern void iounmap(void __iomem *addr);
extern void __iomem *ioremap(phys_addr_t address, unsigned long size);
-#define ioremap_writethrough(addr, size) ioremap((addr), (size))
#define ioremap_nocache(addr, size) ioremap((addr), (size))
#define ioremap_fullcache(addr, size) ioremap((addr), (size))
#define ioremap_wc(addr, size) ioremap((addr), (size))
+#define ioremap_wt(addr, size) ioremap((addr), (size))
#endif /* CONFIG_MMU */
diff --git a/arch/microblaze/include/asm/mm-arch-hooks.h b/arch/microblaze/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..5c4065911bda
--- /dev/null
+++ b/arch/microblaze/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_MICROBLAZE_MM_ARCH_HOOKS_H
+#define _ASM_MICROBLAZE_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_MICROBLAZE_MM_ARCH_HOOKS_H */
diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h
index 468aca8cec0d..dc9eb6657e3a 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -16,8 +16,8 @@
#include <linux/string.h>
#include <linux/dma-mapping.h>
#include <linux/pci.h>
+#include <linux/scatterlist.h>
-#include <asm/scatterlist.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
@@ -27,8 +27,6 @@
#define PCIBIOS_MIN_IO 0x1000
#define PCIBIOS_MIN_MEM 0x10000000
-struct pci_dev;
-
/* Values for the `which' argument to sys_pciconfig_iobase syscall. */
#define IOBASE_BRIDGE_NUMBER 0
#define IOBASE_MEMORY 1
@@ -44,16 +42,6 @@ struct pci_dev;
*/
#define pcibios_assign_all_busses() 0
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- *strat = PCI_DMA_BURST_INFINITY;
- *strategy_parameter = ~0UL;
-}
-#endif
-
extern int pci_domain_nr(struct pci_bus *bus);
/* Decide whether to display the domain number in /proc */
@@ -83,40 +71,12 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
*/
#define PCI_DMA_BUS_IS_PHYS (1)
-static inline struct resource *pcibios_select_root(struct pci_dev *pdev,
- struct resource *res)
-{
- struct resource *root = NULL;
-
- if (res->flags & IORESOURCE_IO)
- root = &ioport_resource;
- if (res->flags & IORESOURCE_MEM)
- root = &iomem_resource;
-
- return root;
-}
-
extern void pcibios_claim_one_bus(struct pci_bus *b);
extern void pcibios_finish_adding_to_bus(struct pci_bus *bus);
extern void pcibios_resource_survey(void);
-extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
-extern int remove_phb_dynamic(struct pci_controller *phb);
-
-extern struct pci_dev *of_create_pci_dev(struct device_node *node,
- struct pci_bus *bus, int devfn);
-
-extern void of_scan_pci_bridge(struct device_node *node,
- struct pci_dev *dev);
-
-extern void of_scan_bus(struct device_node *node, struct pci_bus *bus);
-extern void of_rescan_bus(struct device_node *node, struct pci_bus *bus);
-
-extern int pci_bus_find_capability(struct pci_bus *bus,
- unsigned int devfn, int cap);
-
struct file;
extern pgprot_t pci_phys_mem_access_prot(struct file *file,
unsigned long pfn,
diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h
index 62942fd12672..331b0d35f89c 100644
--- a/arch/microblaze/include/asm/uaccess.h
+++ b/arch/microblaze/include/asm/uaccess.h
@@ -178,7 +178,8 @@ extern long __user_bad(void);
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
@@ -290,7 +291,8 @@ extern long __user_bad(void);
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c
index d1dd6e83d59b..b70bb538f001 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo.c
@@ -47,6 +47,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
{"9.1", 0x1d},
{"9.2", 0x1f},
{"9.3", 0x20},
+ {"9.4", 0x21},
+ {"9.5", 0x22},
{NULL, 0},
};
diff --git a/arch/microblaze/kernel/dma.c b/arch/microblaze/kernel/dma.c
index ed7ba8a11822..bf4dec229437 100644
--- a/arch/microblaze/kernel/dma.c
+++ b/arch/microblaze/kernel/dma.c
@@ -154,6 +154,7 @@ dma_direct_sync_sg_for_device(struct device *dev,
__dma_sync(sg->dma_address, sg->length, direction);
}
+static
int dma_direct_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t handle, size_t size,
struct dma_attrs *attrs)
diff --git a/arch/microblaze/kernel/kgdb.c b/arch/microblaze/kernel/kgdb.c
index 8736af5806ae..6366f69d118e 100644
--- a/arch/microblaze/kernel/kgdb.c
+++ b/arch/microblaze/kernel/kgdb.c
@@ -32,7 +32,7 @@
#define GDB_RTLBHI 56
/* keep pvr separately because it is unchangeble */
-struct pvr_s pvr;
+static struct pvr_s pvr;
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{
diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c
index d46a5ebb7570..177dfc003643 100644
--- a/arch/microblaze/mm/fault.c
+++ b/arch/microblaze/mm/fault.c
@@ -107,14 +107,14 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
if ((error_code & 0x13) == 0x13 || (error_code & 0x11) == 0x11)
is_write = 0;
- if (unlikely(in_atomic() || !mm)) {
+ if (unlikely(faulthandler_disabled() || !mm)) {
if (kernel_mode(regs))
goto bad_area_nosemaphore;
- /* in_atomic() in user mode is really bad,
+ /* faulthandler_disabled() in user mode is really bad,
as is current->mm == NULL. */
- pr_emerg("Page fault in user mode with in_atomic(), mm = %p\n",
- mm);
+ pr_emerg("Page fault in user mode with faulthandler_disabled(), mm = %p\n",
+ mm);
pr_emerg("r15 = %lx MSR = %lx\n",
regs->r15, regs->msr);
die("Weird page fault", regs, SIGSEGV);
diff --git a/arch/microblaze/mm/highmem.c b/arch/microblaze/mm/highmem.c
index 5a92576fad92..2fcc5a52d84d 100644
--- a/arch/microblaze/mm/highmem.c
+++ b/arch/microblaze/mm/highmem.c
@@ -37,7 +37,7 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot)
unsigned long vaddr;
int idx, type;
- /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+ preempt_disable();
pagefault_disable();
if (!PageHighMem(page))
return page_address(page);
@@ -63,6 +63,7 @@ void __kunmap_atomic(void *kvaddr)
if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
pagefault_enable();
+ preempt_enable();
return;
}
@@ -84,5 +85,6 @@ void __kunmap_atomic(void *kvaddr)
#endif
kmap_atomic_idx_pop();
pagefault_enable();
+ preempt_enable();
}
EXPORT_SYMBOL(__kunmap_atomic);
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index dbb1a1d0f9b3..2a14585c90d2 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -832,6 +832,7 @@ config CAVIUM_OCTEON_SOC
select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_BIG_ENDIAN
select EDAC_SUPPORT
+ select EDAC_ATOMIC_SCRUB
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_HOTPLUG_CPU if CPU_BIG_ENDIAN
select SYS_HAS_EARLY_PRINTK
diff --git a/arch/mips/cavium-octeon/crypto/octeon-md5.c b/arch/mips/cavium-octeon/crypto/octeon-md5.c
index 12dccdb38286..af4c712f7afc 100644
--- a/arch/mips/cavium-octeon/crypto/octeon-md5.c
+++ b/arch/mips/cavium-octeon/crypto/octeon-md5.c
@@ -69,10 +69,10 @@ static int octeon_md5_init(struct shash_desc *desc)
{
struct md5_state *mctx = shash_desc_ctx(desc);
- mctx->hash[0] = cpu_to_le32(0x67452301);
- mctx->hash[1] = cpu_to_le32(0xefcdab89);
- mctx->hash[2] = cpu_to_le32(0x98badcfe);
- mctx->hash[3] = cpu_to_le32(0x10325476);
+ mctx->hash[0] = cpu_to_le32(MD5_H0);
+ mctx->hash[1] = cpu_to_le32(MD5_H1);
+ mctx->hash[2] = cpu_to_le32(MD5_H2);
+ mctx->hash[3] = cpu_to_le32(MD5_H3);
mctx->byte_count = 0;
return 0;
diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild
index 526539cbc99f..7fe5c61a3cb8 100644
--- a/arch/mips/include/asm/Kbuild
+++ b/arch/mips/include/asm/Kbuild
@@ -11,7 +11,6 @@ generic-y += mutex.h
generic-y += parport.h
generic-y += percpu.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += segment.h
generic-y += serial.h
diff --git a/arch/mips/include/asm/barrier.h b/arch/mips/include/asm/barrier.h
index 2b8bbbcb9be0..7ecba84656d4 100644
--- a/arch/mips/include/asm/barrier.h
+++ b/arch/mips/include/asm/barrier.h
@@ -112,8 +112,8 @@
#define __WEAK_LLSC_MB " \n"
#endif
-#define set_mb(var, value) \
- do { var = value; smp_mb(); } while (0)
+#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")
diff --git a/arch/mips/include/asm/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h
index 412f945f1f5e..b71ab4a5fd50 100644
--- a/arch/mips/include/asm/cmpxchg.h
+++ b/arch/mips/include/asm/cmpxchg.h
@@ -138,8 +138,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))); \
})
-#define __HAVE_ARCH_CMPXCHG 1
-
#define __cmpxchg_asm(ld, st, m, old, new) \
({ \
__typeof(*(m)) __ret; \
diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h
index fd1b4a150759..360b3387182a 100644
--- a/arch/mips/include/asm/dma-mapping.h
+++ b/arch/mips/include/asm/dma-mapping.h
@@ -1,7 +1,7 @@
#ifndef _ASM_DMA_MAPPING_H
#define _ASM_DMA_MAPPING_H
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <asm/dma-coherence.h>
#include <asm/cache.h>
#include <asm-generic/dma-coherent.h>
diff --git a/arch/mips/include/asm/edac.h b/arch/mips/include/asm/edac.h
index 94105d3f58f4..980b16527374 100644
--- a/arch/mips/include/asm/edac.h
+++ b/arch/mips/include/asm/edac.h
@@ -5,7 +5,7 @@
/* ECC atomic, DMA, SMP and interrupt safe scrub function */
-static inline void atomic_scrub(void *va, u32 size)
+static inline void edac_atomic_scrub(void *va, u32 size)
{
unsigned long *virt_addr = va;
unsigned long temp;
@@ -21,7 +21,7 @@ static inline void atomic_scrub(void *va, u32 size)
__asm__ __volatile__ (
" .set mips2 \n"
- "1: ll %0, %1 # atomic_scrub \n"
+ "1: ll %0, %1 # edac_atomic_scrub \n"
" addu %0, $0 \n"
" sc %0, %1 \n"
" beqz %0, 1b \n"
diff --git a/arch/mips/include/asm/hugetlb.h b/arch/mips/include/asm/hugetlb.h
index fe0d15d32660..982bc0685330 100644
--- a/arch/mips/include/asm/hugetlb.h
+++ b/arch/mips/include/asm/hugetlb.h
@@ -38,10 +38,6 @@ static inline int prepare_hugepage_range(struct file *file,
return 0;
}
-static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
-{
-}
-
static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
unsigned long addr,
unsigned long end,
@@ -114,15 +110,6 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
return *ptep;
}
-static inline int arch_prepare_hugepage(struct page *page)
-{
- return 0;
-}
-
-static inline void arch_release_hugepage(struct page *page)
-{
-}
-
static inline void arch_clear_hugepage_flags(struct page *page)
{
}
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index 4c25823563fe..e8c8d9d0c45f 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -839,7 +839,7 @@ static inline void kvm_arch_hardware_unsetup(void) {}
static inline void kvm_arch_sync_events(struct kvm *kvm) {}
static inline void kvm_arch_free_memslot(struct kvm *kvm,
struct kvm_memory_slot *free, struct kvm_memory_slot *dont) {}
-static inline void kvm_arch_memslots_updated(struct kvm *kvm) {}
+static inline void kvm_arch_memslots_updated(struct kvm *kvm, struct kvm_memslots *slots) {}
static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {}
static inline void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
struct kvm_memory_slot *slot) {}
diff --git a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
index aa2283e602fc..aa71216edf99 100644
--- a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
+++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
@@ -16,8 +16,4 @@ struct ath79_spi_platform_data {
unsigned num_chipselect;
};
-struct ath79_spi_controller_data {
- unsigned gpio;
-};
-
#endif /* _ATH79_SPI_PLATFORM_H */
diff --git a/arch/mips/include/asm/mm-arch-hooks.h b/arch/mips/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..b5609fe8e475
--- /dev/null
+++ b/arch/mips/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_MIPS_MM_ARCH_HOOKS_H
+#define _ASM_MIPS_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_MIPS_MM_ARCH_HOOKS_H */
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index d9692993fc83..98c31e5d9579 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -99,7 +99,7 @@ static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
#include <linux/types.h>
#include <linux/slab.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <linux/string.h>
#include <asm/io.h>
#include <asm-generic/pci-bridge.h>
@@ -113,16 +113,6 @@ struct pci_dev;
*/
extern unsigned int PCI_DMA_BUS_IS_PHYS;
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- *strat = PCI_DMA_BURST_INFINITY;
- *strategy_parameter = ~0UL;
-}
-#endif
-
#ifdef CONFIG_PCI_DOMAINS
#define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index 819af9d057a8..9d8106758142 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -568,12 +568,12 @@ static inline pmd_t pmd_mknotpresent(pmd_t pmd)
}
/*
- * The generic version pmdp_get_and_clear uses a version of pmd_clear() with a
+ * The generic version pmdp_huge_get_and_clear uses a version of pmd_clear() with a
* different prototype.
*/
-#define __HAVE_ARCH_PMDP_GET_AND_CLEAR
-static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
- unsigned long address, pmd_t *pmdp)
+#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
+static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
+ unsigned long address, pmd_t *pmdp)
{
pmd_t old = *pmdp;
diff --git a/arch/mips/include/asm/topology.h b/arch/mips/include/asm/topology.h
index 3e307ec2afba..7afda4150a59 100644
--- a/arch/mips/include/asm/topology.h
+++ b/arch/mips/include/asm/topology.h
@@ -15,7 +15,7 @@
#define topology_physical_package_id(cpu) (cpu_data[cpu].package)
#define topology_core_id(cpu) (cpu_data[cpu].core)
#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
-#define topology_thread_cpumask(cpu) (&cpu_sibling_map[cpu])
+#define topology_sibling_cpumask(cpu) (&cpu_sibling_map[cpu])
#endif
#endif /* __ASM_TOPOLOGY_H */
diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index 6ed061dfa3ee..5305d694ffe5 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -118,7 +118,8 @@ static inline bool eva_kernel_access(void)
* @addr: User space pointer to start of block to check
* @size: Size of block to check
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Checks if a pointer to a block of memory in user space is valid.
*
@@ -153,7 +154,8 @@ static inline bool eva_kernel_access(void)
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
@@ -172,7 +174,8 @@ static inline bool eva_kernel_access(void)
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
@@ -192,7 +195,8 @@ static inline bool eva_kernel_access(void)
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
@@ -214,7 +218,8 @@ static inline bool eva_kernel_access(void)
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
@@ -513,7 +518,8 @@ extern void __put_user_unknown(void);
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
@@ -532,7 +538,8 @@ extern void __put_user_unknown(void);
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
@@ -552,7 +559,8 @@ extern void __put_user_unknown(void);
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
@@ -574,7 +582,8 @@ extern void __put_user_unknown(void);
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
@@ -830,7 +839,8 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n);
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from kernel space to user space. Caller must check
* the specified block with access_ok() before calling this function.
@@ -903,7 +913,8 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from kernel space to user space.
*
@@ -1090,7 +1101,8 @@ extern size_t __copy_in_user_eva(void *__to, const void *__from, size_t __n);
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from user space to kernel space. Caller must check
* the specified block with access_ok() before calling this function.
@@ -1122,7 +1134,8 @@ extern size_t __copy_in_user_eva(void *__to, const void *__from, size_t __n);
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from user space to kernel space.
*
@@ -1344,7 +1357,8 @@ strncpy_from_user(char *__to, const char __user *__from, long __len)
* strlen_user: - Get the size of a string in user space.
* @str: The string to measure.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Get the size of a NUL-terminated string in user space.
*
@@ -1413,7 +1427,8 @@ static inline long __strnlen_user(const char __user *s, long n)
* strnlen_user: - Get the size of a string in user space.
* @str: The string to measure.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Get the size of a NUL-terminated string in user space.
*
diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h
index 06805e09bcd3..0b85f827cd18 100644
--- a/arch/mips/kernel/signal-common.h
+++ b/arch/mips/kernel/signal-common.h
@@ -28,12 +28,7 @@ extern void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
extern int fpcsr_pending(unsigned int __user *fpcsr);
/* Make sure we will not lose FPU ownership */
-#ifdef CONFIG_PREEMPT
-#define lock_fpu_owner() preempt_disable()
-#define unlock_fpu_owner() preempt_enable()
-#else
-#define lock_fpu_owner() pagefault_disable()
-#define unlock_fpu_owner() pagefault_enable()
-#endif
+#define lock_fpu_owner() ({ preempt_disable(); pagefault_disable(); })
+#define unlock_fpu_owner() ({ pagefault_enable(); preempt_enable(); })
#endif /* __SIGNAL_COMMON_H */
diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
index bb68e8d520e8..cd4c129ce743 100644
--- a/arch/mips/kvm/mips.c
+++ b/arch/mips/kvm/mips.c
@@ -198,15 +198,16 @@ int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
- struct kvm_userspace_memory_region *mem,
+ const struct kvm_userspace_memory_region *mem,
enum kvm_mr_change change)
{
return 0;
}
void kvm_arch_commit_memory_region(struct kvm *kvm,
- struct kvm_userspace_memory_region *mem,
+ const struct kvm_userspace_memory_region *mem,
const struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new,
enum kvm_mr_change change)
{
unsigned long npages = 0;
@@ -393,7 +394,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
kvm_mips_deliver_interrupts(vcpu,
kvm_read_c0_guest_cause(vcpu->arch.cop0));
- kvm_guest_enter();
+ __kvm_guest_enter();
/* Disable hardware page table walking while in guest */
htw_stop();
@@ -403,7 +404,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
/* Re-enable HTW before enabling interrupts */
htw_start();
- kvm_guest_exit();
+ __kvm_guest_exit();
local_irq_enable();
if (vcpu->sigset_active)
@@ -968,6 +969,7 @@ out:
/* Get (and clear) the dirty memory log for a memory slot. */
int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
{
+ struct kvm_memslots *slots;
struct kvm_memory_slot *memslot;
unsigned long ga, ga_end;
int is_dirty = 0;
@@ -982,7 +984,8 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
/* If nothing is dirty, don't bother messing with page tables. */
if (is_dirty) {
- memslot = &kvm->memslots->memslots[log->slot];
+ slots = kvm_memslots(kvm);
+ memslot = id_to_memslot(slots, log->slot);
ga = memslot->base_gfn << PAGE_SHIFT;
ga_end = ga + (memslot->npages << PAGE_SHIFT);
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index 7ff8637e530d..36c0f26fac6b 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -21,10 +21,10 @@
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/perf_event.h>
+#include <linux/uaccess.h>
#include <asm/branch.h>
#include <asm/mmu_context.h>
-#include <asm/uaccess.h>
#include <asm/ptrace.h>
#include <asm/highmem.h> /* For VMALLOC_END */
#include <linux/kdebug.h>
@@ -94,7 +94,7 @@ static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write,
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto bad_area_nosemaphore;
if (user_mode(regs))
diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c
index da815d295239..11661cbc11a8 100644
--- a/arch/mips/mm/highmem.c
+++ b/arch/mips/mm/highmem.c
@@ -47,7 +47,7 @@ void *kmap_atomic(struct page *page)
unsigned long vaddr;
int idx, type;
- /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+ preempt_disable();
pagefault_disable();
if (!PageHighMem(page))
return page_address(page);
@@ -72,6 +72,7 @@ void __kunmap_atomic(void *kvaddr)
if (vaddr < FIXADDR_START) { // FIXME
pagefault_enable();
+ preempt_enable();
return;
}
@@ -92,6 +93,7 @@ void __kunmap_atomic(void *kvaddr)
#endif
kmap_atomic_idx_pop();
pagefault_enable();
+ preempt_enable();
}
EXPORT_SYMBOL(__kunmap_atomic);
@@ -104,6 +106,7 @@ void *kmap_atomic_pfn(unsigned long pfn)
unsigned long vaddr;
int idx, type;
+ preempt_disable();
pagefault_disable();
type = kmap_atomic_idx_push();
diff --git a/arch/mips/mm/hugetlbpage.c b/arch/mips/mm/hugetlbpage.c
index 06e0f421b41b..74aa6f62468f 100644
--- a/arch/mips/mm/hugetlbpage.c
+++ b/arch/mips/mm/hugetlbpage.c
@@ -51,11 +51,6 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
return (pte_t *) pmd;
}
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
- return 0;
-}
-
/*
* This function checks for proper alignment of input addr and len parameters.
*/
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index faa5c9822ecc..198a3147dd7d 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -90,6 +90,7 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot)
BUG_ON(Page_dcache_dirty(page));
+ preempt_disable();
pagefault_disable();
idx = (addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
idx += in_interrupt() ? FIX_N_COLOURS : 0;
@@ -152,6 +153,7 @@ void kunmap_coherent(void)
write_c0_entryhi(old_ctx);
local_irq_restore(flags);
pagefault_enable();
+ preempt_enable();
}
void copy_user_highpage(struct page *to, struct page *from,
diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c
index a138e8ee5cfc..b3ab59318d91 100644
--- a/arch/mips/pci/fixup-cobalt.c
+++ b/arch/mips/pci/fixup-cobalt.c
@@ -13,7 +13,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <asm/pci.h>
#include <asm/io.h>
#include <asm/gt64120.h>
diff --git a/arch/mips/pci/ops-mace.c b/arch/mips/pci/ops-mace.c
index 6b5821febc38..951d8070fb48 100644
--- a/arch/mips/pci/ops-mace.c
+++ b/arch/mips/pci/ops-mace.c
@@ -8,7 +8,6 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/types.h>
-#include <asm/pci.h>
#include <asm/ip32/mace.h>
#if 0
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
index 8b117e638306..c5347d99cf3a 100644
--- a/arch/mips/pci/pci-lantiq.c
+++ b/arch/mips/pci/pci-lantiq.c
@@ -20,7 +20,6 @@
#include <linux/of_irq.h>
#include <linux/of_pci.h>
-#include <asm/pci.h>
#include <asm/gpio.h>
#include <asm/addrspace.h>
diff --git a/arch/mn10300/include/asm/Kbuild b/arch/mn10300/include/asm/Kbuild
index f892d9de47d9..de30b0c88796 100644
--- a/arch/mn10300/include/asm/Kbuild
+++ b/arch/mn10300/include/asm/Kbuild
@@ -6,6 +6,5 @@ generic-y += exec.h
generic-y += irq_work.h
generic-y += mcs_spinlock.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += trace_clock.h
diff --git a/arch/mn10300/include/asm/highmem.h b/arch/mn10300/include/asm/highmem.h
index 2fbbe4d920aa..1ddea5afba09 100644
--- a/arch/mn10300/include/asm/highmem.h
+++ b/arch/mn10300/include/asm/highmem.h
@@ -75,6 +75,7 @@ static inline void *kmap_atomic(struct page *page)
unsigned long vaddr;
int idx, type;
+ preempt_disable();
pagefault_disable();
if (page < highmem_start_page)
return page_address(page);
@@ -98,6 +99,7 @@ static inline void __kunmap_atomic(unsigned long vaddr)
if (vaddr < FIXADDR_START) { /* FIXME */
pagefault_enable();
+ preempt_enable();
return;
}
@@ -122,6 +124,7 @@ static inline void __kunmap_atomic(unsigned long vaddr)
kmap_atomic_idx_pop();
pagefault_enable();
+ preempt_enable();
}
#endif /* __KERNEL__ */
diff --git a/arch/mn10300/include/asm/io.h b/arch/mn10300/include/asm/io.h
index cc4a2ba9e228..07c5b4a3903b 100644
--- a/arch/mn10300/include/asm/io.h
+++ b/arch/mn10300/include/asm/io.h
@@ -282,6 +282,7 @@ static inline void __iomem *ioremap_nocache(unsigned long offset, unsigned long
}
#define ioremap_wc ioremap_nocache
+#define ioremap_wt ioremap_nocache
static inline void iounmap(void __iomem *addr)
{
diff --git a/arch/mn10300/include/asm/mm-arch-hooks.h b/arch/mn10300/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..e2029a652f4c
--- /dev/null
+++ b/arch/mn10300/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_MN10300_MM_ARCH_HOOKS_H
+#define _ASM_MN10300_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_MN10300_MM_ARCH_HOOKS_H */
diff --git a/arch/mn10300/include/asm/pci.h b/arch/mn10300/include/asm/pci.h
index 5f70af25c7d0..be3debb8fc02 100644
--- a/arch/mn10300/include/asm/pci.h
+++ b/arch/mn10300/include/asm/pci.h
@@ -55,7 +55,7 @@ void pcibios_set_master(struct pci_dev *dev);
#include <linux/types.h>
#include <linux/slab.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <linux/string.h>
#include <asm/io.h>
@@ -83,19 +83,6 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
/* implement the pci_ DMA API in terms of the generic device dma_ one */
#include <asm-generic/pci-dma-compat.h>
-static inline struct resource *
-pcibios_select_root(struct pci_dev *pdev, struct resource *res)
-{
- struct resource *root = NULL;
-
- if (res->flags & IORESOURCE_IO)
- root = &ioport_resource;
- if (res->flags & IORESOURCE_MEM)
- root = &iomem_resource;
-
- return root;
-}
-
static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
{
return channel ? 15 : 14;
diff --git a/arch/mn10300/include/asm/serial.h b/arch/mn10300/include/asm/serial.h
index 23a799293599..c1990218f18c 100644
--- a/arch/mn10300/include/asm/serial.h
+++ b/arch/mn10300/include/asm/serial.h
@@ -13,7 +13,7 @@
#define _ASM_SERIAL_H
/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
#else
@@ -21,7 +21,7 @@
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
#endif
-#ifdef CONFIG_SERIAL_MANY_PORTS
+#ifdef CONFIG_SERIAL_8250_MANY_PORTS
#define FOURPORT_FLAGS ASYNC_FOURPORT
#define ACCENT_FLAGS 0
#define BOCA_FLAGS 0
diff --git a/arch/mn10300/mm/fault.c b/arch/mn10300/mm/fault.c
index 0c2cc5d39c8e..4a1d181ed32f 100644
--- a/arch/mn10300/mm/fault.c
+++ b/arch/mn10300/mm/fault.c
@@ -23,8 +23,8 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/vt_kern.h> /* For unblank_screen() */
+#include <linux/uaccess.h>
-#include <asm/uaccess.h>
#include <asm/pgalloc.h>
#include <asm/hardirq.h>
#include <asm/cpu-regs.h>
@@ -168,7 +168,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long fault_code,
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto no_context;
if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR)
diff --git a/arch/nios2/include/asm/Kbuild b/arch/nios2/include/asm/Kbuild
index 24b3d8999ac7..434639d510b3 100644
--- a/arch/nios2/include/asm/Kbuild
+++ b/arch/nios2/include/asm/Kbuild
@@ -40,7 +40,6 @@ generic-y += poll.h
generic-y += posix_types.h
generic-y += preempt.h
generic-y += resource.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += segment.h
generic-y += sembuf.h
diff --git a/arch/nios2/include/asm/io.h b/arch/nios2/include/asm/io.h
index 6e24d7cceb0c..c5a62da22cd2 100644
--- a/arch/nios2/include/asm/io.h
+++ b/arch/nios2/include/asm/io.h
@@ -46,6 +46,7 @@ static inline void iounmap(void __iomem *addr)
}
#define ioremap_wc ioremap_nocache
+#define ioremap_wt ioremap_nocache
/* Pages to physical address... */
#define page_to_phys(page) virt_to_phys(page_to_virt(page))
diff --git a/arch/nios2/include/asm/mm-arch-hooks.h b/arch/nios2/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..d7290dc68558
--- /dev/null
+++ b/arch/nios2/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_NIOS2_MM_ARCH_HOOKS_H
+#define _ASM_NIOS2_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_NIOS2_MM_ARCH_HOOKS_H */
diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c
index 7f4547418ee1..be186a75f622 100644
--- a/arch/nios2/kernel/time.c
+++ b/arch/nios2/kernel/time.c
@@ -8,6 +8,7 @@
* for more details.
*/
+#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
@@ -106,6 +107,7 @@ cycles_t get_cycles(void)
{
return nios2_timer_read(&nios2_cs.cs);
}
+EXPORT_SYMBOL(get_cycles);
static void nios2_timer_start(struct nios2_timer *timer)
{
diff --git a/arch/nios2/mm/fault.c b/arch/nios2/mm/fault.c
index 0c9b6afe69e9..b51878b0c6b8 100644
--- a/arch/nios2/mm/fault.c
+++ b/arch/nios2/mm/fault.c
@@ -77,7 +77,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long cause,
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto bad_area_nosemaphore;
if (user_mode(regs))
diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild
index 91f1f360a7c4..2a2e39b8109a 100644
--- a/arch/openrisc/include/asm/Kbuild
+++ b/arch/openrisc/include/asm/Kbuild
@@ -45,7 +45,6 @@ generic-y += poll.h
generic-y += posix_types.h
generic-y += preempt.h
generic-y += resource.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += segment.h
generic-y += sembuf.h
diff --git a/arch/openrisc/include/asm/mm-arch-hooks.h b/arch/openrisc/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..6d33cb555fe1
--- /dev/null
+++ b/arch/openrisc/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_OPENRISC_MM_ARCH_HOOKS_H
+#define _ASM_OPENRISC_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_OPENRISC_MM_ARCH_HOOKS_H */
diff --git a/arch/parisc/include/asm/Kbuild b/arch/parisc/include/asm/Kbuild
index 7a4bcc36303d..12b341d04f88 100644
--- a/arch/parisc/include/asm/Kbuild
+++ b/arch/parisc/include/asm/Kbuild
@@ -20,7 +20,6 @@ generic-y += param.h
generic-y += percpu.h
generic-y += poll.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += seccomp.h
generic-y += segment.h
generic-y += topology.h
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
index de65f66ea64e..ec2df4bab302 100644
--- a/arch/parisc/include/asm/cacheflush.h
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -142,6 +142,7 @@ static inline void kunmap(struct page *page)
static inline void *kmap_atomic(struct page *page)
{
+ preempt_disable();
pagefault_disable();
return page_address(page);
}
@@ -150,6 +151,7 @@ static inline void __kunmap_atomic(void *addr)
{
flush_kernel_dcache_page_addr(addr);
pagefault_enable();
+ preempt_enable();
}
#define kmap_atomic_prot(page, prot) kmap_atomic(page)
diff --git a/arch/parisc/include/asm/cmpxchg.h b/arch/parisc/include/asm/cmpxchg.h
index dbd13354ec41..0a90b965cccb 100644
--- a/arch/parisc/include/asm/cmpxchg.h
+++ b/arch/parisc/include/asm/cmpxchg.h
@@ -46,8 +46,6 @@ __xchg(unsigned long x, __volatile__ void *ptr, int size)
#define xchg(ptr, x) \
((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
-#define __HAVE_ARCH_CMPXCHG 1
-
/* bug catcher for when unsupported size is used - won't link */
extern void __cmpxchg_called_with_bad_pointer(void);
diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h
index d0eae5f2bd87..d8d60a57183f 100644
--- a/arch/parisc/include/asm/dma-mapping.h
+++ b/arch/parisc/include/asm/dma-mapping.h
@@ -2,8 +2,8 @@
#define _PARISC_DMA_MAPPING_H
#include <linux/mm.h>
+#include <linux/scatterlist.h>
#include <asm/cacheflush.h>
-#include <asm/scatterlist.h>
/* See Documentation/DMA-API-HOWTO.txt */
struct hppa_dma_ops {
diff --git a/arch/parisc/include/asm/mm-arch-hooks.h b/arch/parisc/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..654ec63b0ee9
--- /dev/null
+++ b/arch/parisc/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_PARISC_MM_ARCH_HOOKS_H
+#define _ASM_PARISC_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_PARISC_MM_ARCH_HOOKS_H */
diff --git a/arch/parisc/include/asm/pci.h b/arch/parisc/include/asm/pci.h
index 20df2b04fc09..71889ea72740 100644
--- a/arch/parisc/include/asm/pci.h
+++ b/arch/parisc/include/asm/pci.h
@@ -1,7 +1,7 @@
#ifndef __ASM_PARISC_PCI_H
#define __ASM_PARISC_PCI_H
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
@@ -196,25 +196,6 @@ static inline void pcibios_register_hba(struct pci_hba_data *x)
/* export the pci_ DMA API in terms of the dma_ one */
#include <asm-generic/pci-dma-compat.h>
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- unsigned long cacheline_size;
- u8 byte;
-
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
- if (byte == 0)
- cacheline_size = 1024;
- else
- cacheline_size = (int) byte * 4;
-
- *strat = PCI_DMA_BURST_MULTIPLE;
- *strategy_parameter = cacheline_size;
-}
-#endif
-
static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
{
return channel ? 15 : 14;
diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c
index ff834fd67478..b9402c9b3454 100644
--- a/arch/parisc/kernel/pci-dma.c
+++ b/arch/parisc/kernel/pci-dma.c
@@ -478,14 +478,16 @@ static void pa11_dma_unmap_single(struct device *dev, dma_addr_t dma_handle, siz
static int pa11_dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction)
{
int i;
+ struct scatterlist *sg;
BUG_ON(direction == DMA_NONE);
- for (i = 0; i < nents; i++, sglist++ ) {
- unsigned long vaddr = (unsigned long)sg_virt(sglist);
- sg_dma_address(sglist) = (dma_addr_t) virt_to_phys(vaddr);
- sg_dma_len(sglist) = sglist->length;
- flush_kernel_dcache_range(vaddr, sglist->length);
+ for_each_sg(sglist, sg, nents, i) {
+ unsigned long vaddr = (unsigned long)sg_virt(sg);
+
+ sg_dma_address(sg) = (dma_addr_t) virt_to_phys(vaddr);
+ sg_dma_len(sg) = sg->length;
+ flush_kernel_dcache_range(vaddr, sg->length);
}
return nents;
}
@@ -493,6 +495,7 @@ static int pa11_dma_map_sg(struct device *dev, struct scatterlist *sglist, int n
static void pa11_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction)
{
int i;
+ struct scatterlist *sg;
BUG_ON(direction == DMA_NONE);
@@ -501,8 +504,8 @@ static void pa11_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, in
/* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */
- for (i = 0; i < nents; i++, sglist++ )
- flush_kernel_vmap_range(sg_virt(sglist), sglist->length);
+ for_each_sg(sglist, sg, nents, i)
+ flush_kernel_vmap_range(sg_virt(sg), sg->length);
return;
}
@@ -523,21 +526,23 @@ static void pa11_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_h
static void pa11_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction)
{
int i;
+ struct scatterlist *sg;
/* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */
- for (i = 0; i < nents; i++, sglist++ )
- flush_kernel_vmap_range(sg_virt(sglist), sglist->length);
+ for_each_sg(sglist, sg, nents, i)
+ flush_kernel_vmap_range(sg_virt(sg), sg->length);
}
static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction)
{
int i;
+ struct scatterlist *sg;
/* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */
- for (i = 0; i < nents; i++, sglist++ )
- flush_kernel_vmap_range(sg_virt(sglist), sglist->length);
+ for_each_sg(sglist, sg, nents, i)
+ flush_kernel_vmap_range(sg_virt(sg), sg->length);
}
struct hppa_dma_ops pcxl_dma_ops = {
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 47ee620d15d2..6548fd1d2e62 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -26,9 +26,9 @@
#include <linux/console.h>
#include <linux/bug.h>
#include <linux/ratelimit.h>
+#include <linux/uaccess.h>
#include <asm/assembly.h>
-#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/traps.h>
@@ -800,7 +800,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
* unless pagefault_disable() was called before.
*/
- if (fault_space == 0 && !in_atomic())
+ if (fault_space == 0 && !faulthandler_disabled())
{
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
parisc_terminate("Kernel Fault", regs, code, fault_address);
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c
index e5120e653240..15503adddf4f 100644
--- a/arch/parisc/mm/fault.c
+++ b/arch/parisc/mm/fault.c
@@ -15,8 +15,8 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/uaccess.h>
-#include <asm/uaccess.h>
#include <asm/traps.h>
/* Various important other fields */
@@ -207,7 +207,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
int fault;
unsigned int flags;
- if (in_atomic())
+ if (pagefault_disabled())
goto no_context;
tsk = current;
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 190cc48abc0c..5ef27113b898 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -153,6 +153,8 @@ config PPC
select NO_BOOTMEM
select HAVE_GENERIC_RCU_GUP
select HAVE_PERF_EVENTS_NMI if PPC64
+ select EDAC_SUPPORT
+ select EDAC_ATOMIC_SCRUB
config GENERIC_CSUM
def_bool CPU_LITTLE_ENDIAN
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index 0efa8f90a8f1..3a510f4a6b68 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -19,6 +19,14 @@ config PPC_WERROR
depends on !PPC_DISABLE_WERROR
default y
+config STRICT_MM_TYPECHECKS
+ bool "Do extra type checking on mm types"
+ default n
+ help
+ This option turns on extra type checking for some mm related types.
+
+ If you don't know what this means, say N.
+
config PRINT_STACK_DEPTH
int "Stack depth to print" if DEBUG_KERNEL
default 64
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 07a480861f78..05f464eb6952 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -66,7 +66,10 @@ endif
UTS_MACHINE := $(OLDARCH)
ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y)
-override CC += -mlittle-endian -mno-strict-align
+override CC += -mlittle-endian
+ifneq ($(COMPILER),clang)
+override CC += -mno-strict-align
+endif
override AS += -mlittle-endian
override LD += -EL
override CROSS32CC += -mlittle-endian
@@ -113,14 +116,14 @@ else
endif
endif
-CFLAGS-$(CONFIG_PPC64) := -mtraceback=no
+CFLAGS-$(CONFIG_PPC64) := $(call cc-option,-mtraceback=no)
ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y)
-CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2,-mcall-aixdesc)
+CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2,$(call cc-option,-mcall-aixdesc))
AFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2)
else
-CFLAGS-$(CONFIG_PPC64) += -mcall-aixdesc
+CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcall-aixdesc)
endif
-CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcmodel=medium,-mminimal-toc)
+CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcmodel=medium,$(call cc-option,-mminimal-toc))
CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mno-pointers-to-nested-functions)
CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 $(MULTIPLEWORD)
@@ -160,7 +163,8 @@ asinstr := $(call as-instr,lis 9$(comma)foo@high,-DHAVE_AS_ATHIGH=1)
KBUILD_CPPFLAGS += -Iarch/$(ARCH) $(asinstr)
KBUILD_AFLAGS += -Iarch/$(ARCH) $(AFLAGS-y)
-KBUILD_CFLAGS += -msoft-float -pipe -Iarch/$(ARCH) $(CFLAGS-y)
+KBUILD_CFLAGS += $(call cc-option,-msoft-float)
+KBUILD_CFLAGS += -pipe -Iarch/$(ARCH) $(CFLAGS-y)
CPP = $(CC) -E $(KBUILD_CFLAGS)
CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
@@ -192,7 +196,7 @@ KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm)
# Never use string load/store instructions as they are
# often slow when they are implemented at all
-KBUILD_CFLAGS += -mno-string
+KBUILD_CFLAGS += $(call cc-option,-mno-string)
ifeq ($(CONFIG_6xx),y)
KBUILD_CFLAGS += -mcpu=powerpc
@@ -269,6 +273,21 @@ bootwrapper_install:
%.dtb: scripts
$(Q)$(MAKE) ARCH=ppc64 $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
+# Used to create 'merged defconfigs'
+# To use it $(call) it with the first argument as the base defconfig
+# and the second argument as a space separated list of .config files to merge,
+# without the .config suffix.
+define merge_into_defconfig
+ $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \
+ -m -O $(objtree) $(srctree)/arch/$(ARCH)/configs/$(1) \
+ $(foreach config,$(2),$(srctree)/arch/$(ARCH)/configs/$(config).config)
+ +$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig
+endef
+
+PHONY += pseries_le_defconfig
+pseries_le_defconfig:
+ $(call merge_into_defconfig,pseries_defconfig,le)
+
define archhelp
@echo '* zImage - Build default images selected by kernel config'
@echo ' zImage.* - Compressed kernel image (arch/$(ARCH)/boot/zImage.*)'
@@ -314,7 +333,8 @@ TOUT := .tmp_gas_check
# - Require gcc 4.0 or above on 64-bit
# - gcc-4.2.0 has issues compiling modules on 64-bit
checkbin:
- @if test "$(cc-version)" = "0304" ; then \
+ @if test "${COMPILER}" != "clang" \
+ && test "$(cc-version)" = "0304" ; then \
if ! /bin/echo mftb 5 | $(AS) -v -mppc -many -o $(TOUT) >/dev/null 2>&1 ; then \
echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build '; \
echo 'correctly with gcc-3.4 and your version of binutils.'; \
@@ -322,13 +342,15 @@ checkbin:
false; \
fi ; \
fi
- @if test "$(cc-version)" -lt "0400" \
+ @if test "${COMPILER}" != "clang" \
+ && test "$(cc-version)" -lt "0400" \
&& test "x${CONFIG_PPC64}" = "xy" ; then \
echo -n "Sorry, GCC v4.0 or above is required to build " ; \
echo "the 64-bit powerpc kernel." ; \
false ; \
fi
- @if test "$(cc-fullversion)" = "040200" \
+ @if test "${COMPILER}" != "clang" \
+ && test "$(cc-fullversion)" = "040200" \
&& test "x${CONFIG_MODULES}${CONFIG_PPC64}" = "xyy" ; then \
echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ; \
echo 'kernel with modules enabled.' ; \
@@ -336,6 +358,14 @@ checkbin:
echo 'disable kernel modules' ; \
false ; \
fi
+ @if test "x${CONFIG_CPU_LITTLE_ENDIAN}" = "xy" \
+ && $(LD) --version | head -1 | grep ' 2\.24$$' >/dev/null ; then \
+ echo -n '*** binutils 2.24 miscompiles weak symbols ' ; \
+ echo 'in some circumstances.' ; \
+ echo -n '*** Please use a different binutils version.' ; \
+ false ; \
+ fi
+
CLEAN_FILES += $(TOUT)
diff --git a/arch/powerpc/boot/dts/b4qds.dtsi b/arch/powerpc/boot/dts/b4qds.dtsi
index 24ed80dc2120..559d00657fb5 100644
--- a/arch/powerpc/boot/dts/b4qds.dtsi
+++ b/arch/powerpc/boot/dts/b4qds.dtsi
@@ -106,6 +106,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
dcsr: dcsr@f00000000 {
@@ -116,6 +124,10 @@
ranges = <0x0 0xf 0xf4000000 0x2000000>;
};
+ qportals: qman-portals@ff6000000 {
+ ranges = <0x0 0xf 0xf6000000 0x2000000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/fsl/b4420si-post.dtsi b/arch/powerpc/boot/dts/fsl/b4420si-post.dtsi
index 86161ae6c966..1ea8602e4345 100644
--- a/arch/powerpc/boot/dts/fsl/b4420si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4420si-post.dtsi
@@ -80,20 +80,9 @@
compatible = "fsl,b4420-device-config", "fsl,qoriq-device-config-2.0";
};
-/include/ "qoriq-clockgen2.dtsi"
global-utilities@e1000 {
- compatible = "fsl,b4420-clockgen", "fsl,qoriq-clockgen-2.0";
-
- mux0: mux0@0 {
- #clock-cells = <0>;
- reg = <0x0 0x4>;
- compatible = "fsl,qoriq-core-mux-2.0";
- clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
- <&pll1 0>, <&pll1 1>, <&pll1 2>;
- clock-names = "pll0", "pll0-div2", "pll0-div4",
- "pll1", "pll1-div2", "pll1-div4";
- clock-output-names = "cmux0";
- };
+ compatible = "fsl,b4420-clockgen", "fsl,b4-clockgen",
+ "fsl,qoriq-clockgen-2.0";
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/b4860si-post.dtsi b/arch/powerpc/boot/dts/fsl/b4860si-post.dtsi
index f35e9e0a5445..9ba904be39ee 100644
--- a/arch/powerpc/boot/dts/fsl/b4860si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4860si-post.dtsi
@@ -167,6 +167,75 @@
};
};
+&qportals {
+ qportal14: qman-portal@38000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x38000 0x4000>, <0x100e000 0x1000>;
+ interrupts = <132 0x2 0 0>;
+ cell-index = <0xe>;
+ };
+ qportal15: qman-portal@3c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x3c000 0x4000>, <0x100f000 0x1000>;
+ interrupts = <134 0x2 0 0>;
+ cell-index = <0xf>;
+ };
+ qportal16: qman-portal@40000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x40000 0x4000>, <0x1010000 0x1000>;
+ interrupts = <136 0x2 0 0>;
+ cell-index = <0x10>;
+ };
+ qportal17: qman-portal@44000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x44000 0x4000>, <0x1011000 0x1000>;
+ interrupts = <138 0x2 0 0>;
+ cell-index = <0x11>;
+ };
+ qportal18: qman-portal@48000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x48000 0x4000>, <0x1012000 0x1000>;
+ interrupts = <140 0x2 0 0>;
+ cell-index = <0x12>;
+ };
+ qportal19: qman-portal@4c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x4c000 0x4000>, <0x1013000 0x1000>;
+ interrupts = <142 0x2 0 0>;
+ cell-index = <0x13>;
+ };
+ qportal20: qman-portal@50000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x50000 0x4000>, <0x1014000 0x1000>;
+ interrupts = <144 0x2 0 0>;
+ cell-index = <0x14>;
+ };
+ qportal21: qman-portal@54000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x54000 0x4000>, <0x1015000 0x1000>;
+ interrupts = <146 0x2 0 0>;
+ cell-index = <0x15>;
+ };
+ qportal22: qman-portal@58000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x58000 0x4000>, <0x1016000 0x1000>;
+ interrupts = <148 0x2 0 0>;
+ cell-index = <0x16>;
+ };
+ qportal23: qman-portal@5c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x5c000 0x4000>, <0x1017000 0x1000>;
+ interrupts = <150 0x2 0 0>;
+ cell-index = <0x17>;
+ };
+ qportal24: qman-portal@60000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x60000 0x4000>, <0x1018000 0x1000>;
+ interrupts = <152 0x2 0 0>;
+ cell-index = <0x18>;
+ };
+};
+
&soc {
ddr2: memory-controller@9000 {
compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller";
@@ -182,20 +251,9 @@
compatible = "fsl,b4860-device-config", "fsl,qoriq-device-config-2.0";
};
-/include/ "qoriq-clockgen2.dtsi"
global-utilities@e1000 {
- compatible = "fsl,b4860-clockgen", "fsl,qoriq-clockgen-2.0";
-
- mux0: mux0@0 {
- #clock-cells = <0>;
- reg = <0x0 0x4>;
- compatible = "fsl,qoriq-core-mux-2.0";
- clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
- <&pll1 0>, <&pll1 1>, <&pll1 2>;
- clock-names = "pll0", "pll0-div2", "pll0-div4",
- "pll1", "pll1-div2", "pll1-div4";
- clock-output-names = "cmux0";
- };
+ compatible = "fsl,b4860-clockgen", "fsl,b4-clockgen",
+ "fsl,qoriq-clockgen-2.0";
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/b4si-post.dtsi b/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
index 73136c0029d2..603910ac1db0 100644
--- a/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
@@ -37,6 +37,16 @@
alloc-ranges = <0 0 0x10000 0>;
};
+&qman_fqd {
+ compatible = "fsl,qman-fqd";
+ alloc-ranges = <0 0 0x10000 0>;
+};
+
+&qman_pfdr {
+ compatible = "fsl,qman-pfdr";
+ alloc-ranges = <0 0 0x10000 0>;
+};
+
&ifc {
#address-cells = <2>;
#size-cells = <1>;
@@ -210,6 +220,97 @@
};
};
+&qportals {
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ compatible = "simple-bus";
+
+ qportal0: qman-portal@0 {
+ compatible = "fsl,qman-portal";
+ reg = <0x0 0x4000>, <0x1000000 0x1000>;
+ interrupts = <104 0x2 0 0>;
+ cell-index = <0x0>;
+ };
+ qportal1: qman-portal@4000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x4000 0x4000>, <0x1001000 0x1000>;
+ interrupts = <106 0x2 0 0>;
+ cell-index = <0x1>;
+ };
+ qportal2: qman-portal@8000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x8000 0x4000>, <0x1002000 0x1000>;
+ interrupts = <108 0x2 0 0>;
+ cell-index = <0x2>;
+ };
+ qportal3: qman-portal@c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xc000 0x4000>, <0x1003000 0x1000>;
+ interrupts = <110 0x2 0 0>;
+ cell-index = <0x3>;
+ };
+ qportal4: qman-portal@10000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x10000 0x4000>, <0x1004000 0x1000>;
+ interrupts = <112 0x2 0 0>;
+ cell-index = <0x4>;
+ };
+ qportal5: qman-portal@14000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x14000 0x4000>, <0x1005000 0x1000>;
+ interrupts = <114 0x2 0 0>;
+ cell-index = <0x5>;
+ };
+ qportal6: qman-portal@18000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x18000 0x4000>, <0x1006000 0x1000>;
+ interrupts = <116 0x2 0 0>;
+ cell-index = <0x6>;
+ };
+ qportal7: qman-portal@1c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x1c000 0x4000>, <0x1007000 0x1000>;
+ interrupts = <118 0x2 0 0>;
+ cell-index = <0x7>;
+ };
+ qportal8: qman-portal@20000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x20000 0x4000>, <0x1008000 0x1000>;
+ interrupts = <120 0x2 0 0>;
+ cell-index = <0x8>;
+ };
+ qportal9: qman-portal@24000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x24000 0x4000>, <0x1009000 0x1000>;
+ interrupts = <122 0x2 0 0>;
+ cell-index = <0x9>;
+ };
+ qportal10: qman-portal@28000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x28000 0x4000>, <0x100a000 0x1000>;
+ interrupts = <124 0x2 0 0>;
+ cell-index = <0xa>;
+ };
+ qportal11: qman-portal@2c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x2c000 0x4000>, <0x100b000 0x1000>;
+ interrupts = <126 0x2 0 0>;
+ cell-index = <0xb>;
+ };
+ qportal12: qman-portal@30000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x30000 0x4000>, <0x100c000 0x1000>;
+ interrupts = <128 0x2 0 0>;
+ cell-index = <0xc>;
+ };
+ qportal13: qman-portal@34000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x34000 0x4000>, <0x100d000 0x1000>;
+ interrupts = <130 0x2 0 0>;
+ cell-index = <0xd>;
+ };
+};
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -296,9 +397,21 @@
fsl,liodn-bits = <12>;
};
+/include/ "qoriq-clockgen2.dtsi"
clockgen: global-utilities@e1000 {
compatible = "fsl,b4-clockgen", "fsl,qoriq-clockgen-2.0";
reg = <0xe1000 0x1000>;
+
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 0x4>;
+ compatible = "fsl,qoriq-core-mux-2.0";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0", "pll0-div2", "pll0-div4",
+ "pll1", "pll1-div2", "pll1-div4";
+ clock-output-names = "cmux0";
+ };
};
rcpm: global-utilities@e2000 {
@@ -343,6 +456,11 @@
/include/ "qoriq-duart-1.dtsi"
/include/ "qoriq-sec5.3-0.dtsi"
+/include/ "qoriq-qman3.dtsi"
+ qman: qman@318000 {
+ interrupts = <16 2 1 28>;
+ };
+
/include/ "qoriq-bman1.dtsi"
bman: bman@31a000 {
interrupts = <16 2 1 29>;
diff --git a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi
index 7780f21430cb..da6d3fc6ba41 100644
--- a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi
@@ -37,6 +37,16 @@
alloc-ranges = <0 0 0x10 0>;
};
+&qman_fqd {
+ compatible = "fsl,qman-fqd";
+ alloc-ranges = <0 0 0x10 0>;
+};
+
+&qman_pfdr {
+ compatible = "fsl,qman-pfdr";
+ alloc-ranges = <0 0 0x10 0>;
+};
+
&lbc {
#address-cells = <2>;
#size-cells = <1>;
@@ -102,6 +112,31 @@
};
};
+&qportals {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+
+ qportal0: qman-portal@0 {
+ compatible = "fsl,qman-portal";
+ reg = <0x0 0x4000>, <0x100000 0x1000>;
+ interrupts = <29 2 0 0>;
+ cell-index = <0>;
+ };
+ qportal1: qman-portal@4000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x4000 0x4000>, <0x101000 0x1000>;
+ interrupts = <31 2 0 0>;
+ cell-index = <1>;
+ };
+ qportal2: qman-portal@8000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x8000 0x4000>, <0x102000 0x1000>;
+ interrupts = <33 2 0 0>;
+ cell-index = <2>;
+ };
+};
+
&bportals {
#address-cells = <1>;
#size-cells = <1>;
@@ -248,6 +283,14 @@
/include/ "pq3-mpic.dtsi"
/include/ "pq3-mpic-timer-B.dtsi"
+ qman: qman@88000 {
+ compatible = "fsl,qman";
+ reg = <0x88000 0x1000>;
+ interrupts = <16 2 0 0>;
+ fsl,qman-portals = <&qportals>;
+ memory-region = <&qman_fqd &qman_pfdr>;
+ };
+
bman: bman@8a000 {
compatible = "fsl,bman";
reg = <0x8a000 0x1000>;
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
index f2feacfd9a25..04ad177b6a12 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
@@ -37,6 +37,16 @@
alloc-ranges = <0 0 0x10 0>;
};
+&qman_fqd {
+ compatible = "fsl,qman-fqd";
+ alloc-ranges = <0 0 0x10 0>;
+};
+
+&qman_pfdr {
+ compatible = "fsl,qman-pfdr";
+ alloc-ranges = <0 0 0x10 0>;
+};
+
&lbc {
compatible = "fsl,p2041-elbc", "fsl,elbc", "simple-bus";
interrupts = <25 2 0 0>;
@@ -223,6 +233,8 @@
/include/ "qoriq-bman1-portals.dtsi"
+/include/ "qoriq-qman1-portals.dtsi"
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -370,6 +382,7 @@
/include/ "qoriq-esdhc-0.dtsi"
sdhc@114000 {
+ compatible = "fsl,p2041-esdhc", "fsl,esdhc";
fsl,iommu-parent = <&pamu1>;
fsl,liodn-reg = <&guts 0x530>; /* eSDHCLIODNR */
sdhci,auto-cmd12;
@@ -415,5 +428,6 @@ crypto: crypto@300000 {
fsl,iommu-parent = <&pamu1>;
};
+/include/ "qoriq-qman1.dtsi"
/include/ "qoriq-bman1.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
index d6fea37395ad..2cab18af6df2 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
@@ -37,6 +37,16 @@
alloc-ranges = <0 0 0x10 0>;
};
+&qman_fqd {
+ compatible = "fsl,qman-fqd";
+ alloc-ranges = <0 0 0x10 0>;
+};
+
+&qman_pfdr {
+ compatible = "fsl,qman-pfdr";
+ alloc-ranges = <0 0 0x10 0>;
+};
+
&lbc {
compatible = "fsl,p3041-elbc", "fsl,elbc", "simple-bus";
interrupts = <25 2 0 0>;
@@ -250,6 +260,8 @@
/include/ "qoriq-bman1-portals.dtsi"
+/include/ "qoriq-qman1-portals.dtsi"
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -397,6 +409,7 @@
/include/ "qoriq-esdhc-0.dtsi"
sdhc@114000 {
+ compatible = "fsl,p3041-esdhc", "fsl,esdhc";
fsl,iommu-parent = <&pamu1>;
fsl,liodn-reg = <&guts 0x530>; /* eSDHCLIODNR */
sdhci,auto-cmd12;
@@ -442,5 +455,6 @@ crypto: crypto@300000 {
fsl,iommu-parent = <&pamu1>;
};
+/include/ "qoriq-qman1.dtsi"
/include/ "qoriq-bman1.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
index 89482c9b2301..dfc76bc41cb2 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
@@ -37,6 +37,16 @@
alloc-ranges = <0 0 0x10 0>;
};
+&qman_fqd {
+ compatible = "fsl,qman-fqd";
+ alloc-ranges = <0 0 0x10 0>;
+};
+
+&qman_pfdr {
+ compatible = "fsl,qman-pfdr";
+ alloc-ranges = <0 0 0x10 0>;
+};
+
&lbc {
compatible = "fsl,p4080-elbc", "fsl,elbc", "simple-bus";
interrupts = <25 2 0 0>;
@@ -250,6 +260,8 @@
/include/ "qoriq-bman1-portals.dtsi"
+/include/ "qoriq-qman1-portals.dtsi"
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -469,6 +481,7 @@
/include/ "qoriq-esdhc-0.dtsi"
sdhc@114000 {
+ compatible = "fsl,p4080-esdhc", "fsl,esdhc";
fsl,iommu-parent = <&pamu1>;
fsl,liodn-reg = <&guts 0x530>; /* eSDHCLIODNR */
voltage-ranges = <3300 3300>;
@@ -498,5 +511,6 @@ crypto: crypto@300000 {
fsl,iommu-parent = <&pamu1>;
};
+/include/ "qoriq-qman1.dtsi"
/include/ "qoriq-bman1.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
index 6e04851e2fc9..b77923ad72cf 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
@@ -37,6 +37,16 @@
alloc-ranges = <0 0 0x10000 0>;
};
+&qman_fqd {
+ compatible = "fsl,qman-fqd";
+ alloc-ranges = <0 0 0x10000 0>;
+};
+
+&qman_pfdr {
+ compatible = "fsl,qman-pfdr";
+ alloc-ranges = <0 0 0x10000 0>;
+};
+
&lbc {
compatible = "fsl,p5020-elbc", "fsl,elbc", "simple-bus";
interrupts = <25 2 0 0>;
@@ -247,6 +257,8 @@
/include/ "qoriq-bman1-portals.dtsi"
+/include/ "qoriq-qman1-portals.dtsi"
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -384,6 +396,7 @@
/include/ "qoriq-esdhc-0.dtsi"
sdhc@114000 {
+ compatible = "fsl,p5020-esdhc", "fsl,esdhc";
fsl,iommu-parent = <&pamu1>;
fsl,liodn-reg = <&guts 0x530>; /* eSDHCLIODNR */
sdhci,auto-cmd12;
@@ -428,6 +441,7 @@
fsl,iommu-parent = <&pamu1>;
};
+/include/ "qoriq-qman1.dtsi"
/include/ "qoriq-bman1.dtsi"
/include/ "qoriq-raid1.0-0.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
index 5e44dfa1e1a5..6d214526b81b 100644
--- a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
@@ -37,6 +37,16 @@
alloc-ranges = <0 0 0x10000 0>;
};
+&qman_fqd {
+ compatible = "fsl,qman-fqd";
+ alloc-ranges = <0 0 0x10000 0>;
+};
+
+&qman_pfdr {
+ compatible = "fsl,qman-pfdr";
+ alloc-ranges = <0 0 0x10000 0>;
+};
+
&lbc {
compatible = "fsl,p5040-elbc", "fsl,elbc", "simple-bus";
interrupts = <25 2 0 0>;
@@ -202,6 +212,8 @@
/include/ "qoriq-bman1-portals.dtsi"
+/include/ "qoriq-qman1-portals.dtsi"
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -362,6 +374,7 @@
/include/ "qoriq-esdhc-0.dtsi"
sdhc@114000 {
+ compatible = "fsl,p5040-esdhc", "fsl,esdhc";
fsl,iommu-parent = <&pamu2>;
fsl,liodn-reg = <&guts 0x530>; /* eSDHCLIODNR */
sdhci,auto-cmd12;
@@ -407,5 +420,6 @@
fsl,iommu-parent = <&pamu4>;
};
+/include/ "qoriq-qman1.dtsi"
/include/ "qoriq-bman1.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-qman1-portals.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-qman1-portals.dtsi
index 05d51acafa67..e77e4b4ed53b 100644
--- a/arch/powerpc/boot/dts/fsl/qoriq-qman1-portals.dtsi
+++ b/arch/powerpc/boot/dts/fsl/qoriq-qman1-portals.dtsi
@@ -41,61 +41,61 @@
compatible = "fsl,qman-portal";
reg = <0x0 0x4000>, <0x100000 0x1000>;
interrupts = <104 2 0 0>;
- fsl,qman-channel-id = <0x0>;
+ cell-index = <0x0>;
};
qportal1: qman-portal@4000 {
compatible = "fsl,qman-portal";
reg = <0x4000 0x4000>, <0x101000 0x1000>;
interrupts = <106 2 0 0>;
- fsl,qman-channel-id = <1>;
+ cell-index = <1>;
};
qportal2: qman-portal@8000 {
compatible = "fsl,qman-portal";
reg = <0x8000 0x4000>, <0x102000 0x1000>;
interrupts = <108 2 0 0>;
- fsl,qman-channel-id = <2>;
+ cell-index = <2>;
};
qportal3: qman-portal@c000 {
compatible = "fsl,qman-portal";
reg = <0xc000 0x4000>, <0x103000 0x1000>;
interrupts = <110 2 0 0>;
- fsl,qman-channel-id = <3>;
+ cell-index = <3>;
};
qportal4: qman-portal@10000 {
compatible = "fsl,qman-portal";
reg = <0x10000 0x4000>, <0x104000 0x1000>;
interrupts = <112 2 0 0>;
- fsl,qman-channel-id = <4>;
+ cell-index = <4>;
};
qportal5: qman-portal@14000 {
compatible = "fsl,qman-portal";
reg = <0x14000 0x4000>, <0x105000 0x1000>;
interrupts = <114 2 0 0>;
- fsl,qman-channel-id = <5>;
+ cell-index = <5>;
};
qportal6: qman-portal@18000 {
compatible = "fsl,qman-portal";
reg = <0x18000 0x4000>, <0x106000 0x1000>;
interrupts = <116 2 0 0>;
- fsl,qman-channel-id = <6>;
+ cell-index = <6>;
};
qportal7: qman-portal@1c000 {
compatible = "fsl,qman-portal";
reg = <0x1c000 0x4000>, <0x107000 0x1000>;
interrupts = <118 2 0 0>;
- fsl,qman-channel-id = <7>;
+ cell-index = <7>;
};
qportal8: qman-portal@20000 {
compatible = "fsl,qman-portal";
reg = <0x20000 0x4000>, <0x108000 0x1000>;
interrupts = <120 2 0 0>;
- fsl,qman-channel-id = <8>;
+ cell-index = <8>;
};
qportal9: qman-portal@24000 {
compatible = "fsl,qman-portal";
reg = <0x24000 0x4000>, <0x109000 0x1000>;
interrupts = <122 2 0 0>;
- fsl,qman-channel-id = <9>;
+ cell-index = <9>;
};
};
diff --git a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi
new file mode 100644
index 000000000000..df1f068a5376
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi
@@ -0,0 +1,330 @@
+/*
+ * T1023 Silicon/SoC Device Tree Source (post include)
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+&ifc {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "fsl,ifc", "simple-bus";
+ interrupts = <25 2 0 0>;
+};
+
+&pci0 {
+ compatible = "fsl,t1023-pcie", "fsl,qoriq-pcie-v2.4", "fsl,qoriq-pcie";
+ device_type = "pci";
+ #size-cells = <2>;
+ #address-cells = <3>;
+ bus-range = <0x0 0xff>;
+ interrupts = <20 2 0 0>;
+ fsl,iommu-parent = <&pamu0>;
+ pcie@0 {
+ reg = <0 0 0 0 0>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ interrupts = <20 2 0 0>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0 0 1 &mpic 40 1 0 0
+ 0000 0 0 2 &mpic 1 1 0 0
+ 0000 0 0 3 &mpic 2 1 0 0
+ 0000 0 0 4 &mpic 3 1 0 0
+ >;
+ };
+};
+
+&pci1 {
+ compatible = "fsl,t1023-pcie", "fsl,qoriq-pcie-v2.4", "fsl,qoriq-pcie";
+ device_type = "pci";
+ #size-cells = <2>;
+ #address-cells = <3>;
+ bus-range = <0 0xff>;
+ interrupts = <21 2 0 0>;
+ fsl,iommu-parent = <&pamu0>;
+ pcie@0 {
+ reg = <0 0 0 0 0>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ interrupts = <21 2 0 0>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0 0 1 &mpic 41 1 0 0
+ 0000 0 0 2 &mpic 5 1 0 0
+ 0000 0 0 3 &mpic 6 1 0 0
+ 0000 0 0 4 &mpic 7 1 0 0
+ >;
+ };
+};
+
+&pci2 {
+ compatible = "fsl,t1023-pcie", "fsl,qoriq-pcie-v2.4", "fsl,qoriq-pcie";
+ device_type = "pci";
+ #size-cells = <2>;
+ #address-cells = <3>;
+ bus-range = <0x0 0xff>;
+ interrupts = <22 2 0 0>;
+ fsl,iommu-parent = <&pamu0>;
+ pcie@0 {
+ reg = <0 0 0 0 0>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ interrupts = <22 2 0 0>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0 0 1 &mpic 42 1 0 0
+ 0000 0 0 2 &mpic 9 1 0 0
+ 0000 0 0 3 &mpic 10 1 0 0
+ 0000 0 0 4 &mpic 11 1 0 0
+ >;
+ };
+};
+
+&dcsr {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,dcsr", "simple-bus";
+
+ dcsr-epu@0 {
+ compatible = "fsl,t1023-dcsr-epu", "fsl,dcsr-epu";
+ interrupts = <52 2 0 0
+ 84 2 0 0
+ 85 2 0 0>;
+ reg = <0x0 0x1000>;
+ };
+ dcsr-npc {
+ compatible = "fsl,t1023-dcsr-cnpc", "fsl,dcsr-cnpc";
+ reg = <0x1000 0x1000 0x1002000 0x10000>;
+ };
+ dcsr-nxc@2000 {
+ compatible = "fsl,dcsr-nxc";
+ reg = <0x2000 0x1000>;
+ };
+ dcsr-corenet {
+ compatible = "fsl,dcsr-corenet";
+ reg = <0x8000 0x1000 0x1A000 0x1000>;
+ };
+ dcsr-ocn@11000 {
+ compatible = "fsl,t1023-dcsr-ocn", "fsl,dcsr-ocn";
+ reg = <0x11000 0x1000>;
+ };
+ dcsr-ddr@12000 {
+ compatible = "fsl,dcsr-ddr";
+ dev-handle = <&ddr1>;
+ reg = <0x12000 0x1000>;
+ };
+ dcsr-nal@18000 {
+ compatible = "fsl,t1023-dcsr-nal", "fsl,dcsr-nal";
+ reg = <0x18000 0x1000>;
+ };
+ dcsr-rcpm@22000 {
+ compatible = "fsl,t1023-dcsr-rcpm", "fsl,dcsr-rcpm";
+ reg = <0x22000 0x1000>;
+ };
+ dcsr-snpc@30000 {
+ compatible = "fsl,t1023-dcsr-snpc", "fsl,dcsr-snpc";
+ reg = <0x30000 0x1000 0x1022000 0x10000>;
+ };
+ dcsr-snpc@31000 {
+ compatible = "fsl,t1023-dcsr-snpc", "fsl,dcsr-snpc";
+ reg = <0x31000 0x1000 0x1042000 0x10000>;
+ };
+ dcsr-cpu-sb-proxy@100000 {
+ compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+ cpu-handle = <&cpu0>;
+ reg = <0x100000 0x1000 0x101000 0x1000>;
+ };
+ dcsr-cpu-sb-proxy@108000 {
+ compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+ cpu-handle = <&cpu1>;
+ reg = <0x108000 0x1000 0x109000 0x1000>;
+ };
+};
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ compatible = "simple-bus";
+
+ soc-sram-error {
+ compatible = "fsl,soc-sram-error";
+ interrupts = <16 2 1 29>;
+ };
+
+ corenet-law@0 {
+ compatible = "fsl,corenet-law";
+ reg = <0x0 0x1000>;
+ fsl,num-laws = <16>;
+ };
+
+ ddr1: memory-controller@8000 {
+ compatible = "fsl,qoriq-memory-controller-v5.0",
+ "fsl,qoriq-memory-controller";
+ reg = <0x8000 0x1000>;
+ interrupts = <16 2 1 23>;
+ };
+
+ cpc: l3-cache-controller@10000 {
+ compatible = "fsl,t1023-l3-cache-controller", "cache";
+ reg = <0x10000 0x1000>;
+ interrupts = <16 2 1 27>;
+ };
+
+ corenet-cf@18000 {
+ compatible = "fsl,corenet2-cf";
+ reg = <0x18000 0x1000>;
+ interrupts = <16 2 1 31>;
+ };
+
+ iommu@20000 {
+ compatible = "fsl,pamu-v1.0", "fsl,pamu";
+ reg = <0x20000 0x1000>;
+ ranges = <0 0x20000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupts = <
+ 24 2 0 0
+ 16 2 1 30>;
+ pamu0: pamu@0 {
+ reg = <0 0x1000>;
+ fsl,primary-cache-geometry = <128 1>;
+ fsl,secondary-cache-geometry = <32 2>;
+ };
+ };
+
+/include/ "qoriq-mpic.dtsi"
+
+ guts: global-utilities@e0000 {
+ compatible = "fsl,t1023-device-config", "fsl,qoriq-device-config-2.0";
+ reg = <0xe0000 0xe00>;
+ fsl,has-rstcr;
+ fsl,liodn-bits = <12>;
+ };
+
+/include/ "qoriq-clockgen2.dtsi"
+ global-utilities@e1000 {
+ compatible = "fsl,t1023-clockgen", "fsl,qoriq-clockgen-2.0";
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0 4>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>;
+ clock-names = "pll0_0", "pll0_1";
+ clock-output-names = "cmux0";
+ };
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20 4>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>;
+ clock-names = "pll0_0", "pll0_1";
+ clock-output-names = "cmux1";
+ };
+ };
+
+ rcpm: global-utilities@e2000 {
+ compatible = "fsl,t1023-rcpm", "fsl,qoriq-rcpm-2.0";
+ reg = <0xe2000 0x1000>;
+ };
+
+ sfp: sfp@e8000 {
+ compatible = "fsl,t1023-sfp";
+ reg = <0xe8000 0x1000>;
+ };
+
+ serdes: serdes@ea000 {
+ compatible = "fsl,t1023-serdes";
+ reg = <0xea000 0x4000>;
+ };
+
+ scfg: global-utilities@fc000 {
+ compatible = "fsl,t1023-scfg";
+ reg = <0xfc000 0x1000>;
+ };
+
+/include/ "elo3-dma-0.dtsi"
+/include/ "elo3-dma-1.dtsi"
+
+/include/ "qoriq-espi-0.dtsi"
+ spi@110000 {
+ fsl,espi-num-chipselects = <4>;
+ };
+
+/include/ "qoriq-esdhc-0.dtsi"
+ sdhc@114000 {
+ compatible = "fsl,t1023-esdhc", "fsl,esdhc";
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x530>; /* eSDHCLIODNR */
+ sdhci,auto-cmd12;
+ no-1-8-v;
+ };
+/include/ "qoriq-i2c-0.dtsi"
+/include/ "qoriq-i2c-1.dtsi"
+/include/ "qoriq-duart-0.dtsi"
+/include/ "qoriq-duart-1.dtsi"
+/include/ "qoriq-gpio-0.dtsi"
+/include/ "qoriq-gpio-1.dtsi"
+/include/ "qoriq-gpio-2.dtsi"
+/include/ "qoriq-gpio-3.dtsi"
+/include/ "qoriq-usb2-mph-0.dtsi"
+ usb0: usb@210000 {
+ compatible = "fsl-usb2-mph-v2.5", "fsl-usb2-mph";
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x520>; /* USB1LIODNR */
+ phy_type = "utmi";
+ port0;
+ };
+/include/ "qoriq-usb2-dr-0.dtsi"
+ usb1: usb@211000 {
+ compatible = "fsl-usb2-dr-v2.5", "fsl-usb2-dr";
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x524>; /* USB2LIODNR */
+ dr_mode = "host";
+ phy_type = "utmi";
+ };
+/include/ "qoriq-sata2-0.dtsi"
+ sata@220000 {
+ fsl,iommu-parent = <&pamu0>;
+ fsl,liodn-reg = <&guts 0x550>; /* SATA1LIODNR */
+ };
+
+/include/ "qoriq-sec5.0-0.dtsi"
+};
diff --git a/arch/powerpc/boot/dts/fsl/t1024si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1024si-post.dtsi
new file mode 100644
index 000000000000..95e3af8d768e
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/t1024si-post.dtsi
@@ -0,0 +1,100 @@
+/*
+ * T1024 Silicon/SoC Device Tree Source (post include)
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor 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/ "t1023si-post.dtsi"
+
+/ {
+ aliases {
+ vga = &display;
+ display = &display;
+ };
+
+ qe:qe@ffe140000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "qe";
+ compatible = "fsl,qe";
+ ranges = <0x0 0xf 0xfe140000 0x40000>;
+ reg = <0xf 0xfe140000 0 0x480>;
+ fsl,qe-num-riscs = <1>;
+ fsl,qe-num-snums = <28>;
+ brg-frequency = <0>;
+ bus-frequency = <0>;
+ };
+};
+
+&soc {
+ display:display@180000 {
+ compatible = "fsl,t1024-diu", "fsl,diu";
+ reg = <0x180000 1000>;
+ interrupts = <74 2 0 0>;
+ };
+};
+
+&qe {
+ qeic: interrupt-controller@80 {
+ interrupt-controller;
+ compatible = "fsl,qe-ic";
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x80 0x80>;
+ interrupts = <95 2 0 0 94 2 0 0>; //high:79 low:78
+ };
+
+ ucc@2000 {
+ cell-index = <1>;
+ reg = <0x2000 0x200>;
+ interrupts = <32>;
+ interrupt-parent = <&qeic>;
+ };
+
+ ucc@2200 {
+ cell-index = <3>;
+ reg = <0x2200 0x200>;
+ interrupts = <34>;
+ interrupt-parent = <&qeic>;
+ };
+
+ muram@10000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,qe-muram", "fsl,cpm-muram";
+ ranges = <0x0 0x10000 0x6000>;
+
+ data-only@0 {
+ compatible = "fsl,qe-muram-data", "fsl,cpm-muram-data";
+ reg = <0x0 0x6000>;
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/fsl/t102xsi-pre.dtsi b/arch/powerpc/boot/dts/fsl/t102xsi-pre.dtsi
new file mode 100644
index 000000000000..1f1a9f8474d5
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/t102xsi-pre.dtsi
@@ -0,0 +1,87 @@
+/*
+ * T1024/T1023 Silicon/SoC Device Tree Source (pre include)
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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/ "e5500_power_isa.dtsi"
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&mpic>;
+
+ aliases {
+ ccsr = &soc;
+ dcsr = &dcsr;
+
+ dma0 = &dma0;
+ dma1 = &dma1;
+ serial0 = &serial0;
+ serial1 = &serial1;
+ serial2 = &serial2;
+ serial3 = &serial3;
+ pci0 = &pci0;
+ pci1 = &pci1;
+ pci2 = &pci2;
+ usb0 = &usb0;
+ usb1 = &usb1;
+ sdhc = &sdhc;
+
+ crypto = &crypto;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: PowerPC,e5500@0 {
+ device_type = "cpu";
+ reg = <0>;
+ clocks = <&mux0>;
+ next-level-cache = <&L2_1>;
+ L2_1: l2-cache {
+ next-level-cache = <&cpc>;
+ };
+ };
+ cpu1: PowerPC,e5500@1 {
+ device_type = "cpu";
+ reg = <1>;
+ clocks = <&mux1>;
+ next-level-cache = <&L2_2>;
+ L2_2: l2-cache {
+ next-level-cache = <&cpc>;
+ };
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
index 5cc01be5b152..9e9f7e201d43 100644
--- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
@@ -37,6 +37,16 @@
alloc-ranges = <0 0 0x10000 0>;
};
+&qman_fqd {
+ compatible = "fsl,qman-fqd";
+ alloc-ranges = <0 0 0x10000 0>;
+};
+
+&qman_pfdr {
+ compatible = "fsl,qman-pfdr";
+ alloc-ranges = <0 0 0x10000 0>;
+};
+
&ifc {
#address-cells = <2>;
#size-cells = <1>;
@@ -280,6 +290,73 @@
};
};
+&qportals {
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ compatible = "simple-bus";
+
+ qportal0: qman-portal@0 {
+ compatible = "fsl,qman-portal";
+ reg = <0x0 0x4000>, <0x1000000 0x1000>;
+ interrupts = <104 0x2 0 0>;
+ cell-index = <0x0>;
+ };
+ qportal1: qman-portal@4000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x4000 0x4000>, <0x1001000 0x1000>;
+ interrupts = <106 0x2 0 0>;
+ cell-index = <0x1>;
+ };
+ qportal2: qman-portal@8000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x8000 0x4000>, <0x1002000 0x1000>;
+ interrupts = <108 0x2 0 0>;
+ cell-index = <0x2>;
+ };
+ qportal3: qman-portal@c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xc000 0x4000>, <0x1003000 0x1000>;
+ interrupts = <110 0x2 0 0>;
+ cell-index = <0x3>;
+ };
+ qportal4: qman-portal@10000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x10000 0x4000>, <0x1004000 0x1000>;
+ interrupts = <112 0x2 0 0>;
+ cell-index = <0x4>;
+ };
+ qportal5: qman-portal@14000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x14000 0x4000>, <0x1005000 0x1000>;
+ interrupts = <114 0x2 0 0>;
+ cell-index = <0x5>;
+ };
+ qportal6: qman-portal@18000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x18000 0x4000>, <0x1006000 0x1000>;
+ interrupts = <116 0x2 0 0>;
+ cell-index = <0x6>;
+ };
+ qportal7: qman-portal@1c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x1c000 0x4000>, <0x1007000 0x1000>;
+ interrupts = <118 0x2 0 0>;
+ cell-index = <0x7>;
+ };
+ qportal8: qman-portal@20000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x20000 0x4000>, <0x1008000 0x1000>;
+ interrupts = <120 0x2 0 0>;
+ cell-index = <0x8>;
+ };
+ qportal9: qman-portal@24000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x24000 0x4000>, <0x1009000 0x1000>;
+ interrupts = <122 0x2 0 0>;
+ cell-index = <0x9>;
+ };
+};
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -463,5 +540,6 @@
fsl,liodn-reg = <&guts 0x554>; /* SATA2LIODNR */
};
/include/ "qoriq-sec5.0-0.dtsi"
+/include/ "qoriq-qman3.dtsi"
/include/ "qoriq-bman1.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/t2081si-post.dtsi b/arch/powerpc/boot/dts/fsl/t2081si-post.dtsi
index 86bdaf6cbd14..32c790ae7fde 100644
--- a/arch/powerpc/boot/dts/fsl/t2081si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t2081si-post.dtsi
@@ -37,6 +37,16 @@
alloc-ranges = <0 0 0x10000 0>;
};
+&qman_fqd {
+ compatible = "fsl,qman-fqd";
+ alloc-ranges = <0 0 0x10000 0>;
+};
+
+&qman_pfdr {
+ compatible = "fsl,qman-pfdr";
+ alloc-ranges = <0 0 0x10000 0>;
+};
+
&ifc {
#address-cells = <2>;
#size-cells = <1>;
@@ -326,6 +336,121 @@
};
};
+&qportals {
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ compatible = "simple-bus";
+
+ qportal0: qman-portal@0 {
+ compatible = "fsl,qman-portal";
+ reg = <0x0 0x4000>, <0x1000000 0x1000>;
+ interrupts = <104 0x2 0 0>;
+ cell-index = <0x0>;
+ };
+ qportal1: qman-portal@4000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x4000 0x4000>, <0x1001000 0x1000>;
+ interrupts = <106 0x2 0 0>;
+ cell-index = <0x1>;
+ };
+ qportal2: qman-portal@8000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x8000 0x4000>, <0x1002000 0x1000>;
+ interrupts = <108 0x2 0 0>;
+ cell-index = <0x2>;
+ };
+ qportal3: qman-portal@c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xc000 0x4000>, <0x1003000 0x1000>;
+ interrupts = <110 0x2 0 0>;
+ cell-index = <0x3>;
+ };
+ qportal4: qman-portal@10000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x10000 0x4000>, <0x1004000 0x1000>;
+ interrupts = <112 0x2 0 0>;
+ cell-index = <0x4>;
+ };
+ qportal5: qman-portal@14000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x14000 0x4000>, <0x1005000 0x1000>;
+ interrupts = <114 0x2 0 0>;
+ cell-index = <0x5>;
+ };
+ qportal6: qman-portal@18000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x18000 0x4000>, <0x1006000 0x1000>;
+ interrupts = <116 0x2 0 0>;
+ cell-index = <0x6>;
+ };
+ qportal7: qman-portal@1c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x1c000 0x4000>, <0x1007000 0x1000>;
+ interrupts = <118 0x2 0 0>;
+ cell-index = <0x7>;
+ };
+ qportal8: qman-portal@20000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x20000 0x4000>, <0x1008000 0x1000>;
+ interrupts = <120 0x2 0 0>;
+ cell-index = <0x8>;
+ };
+ qportal9: qman-portal@24000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x24000 0x4000>, <0x1009000 0x1000>;
+ interrupts = <122 0x2 0 0>;
+ cell-index = <0x9>;
+ };
+ qportal10: qman-portal@28000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x28000 0x4000>, <0x100a000 0x1000>;
+ interrupts = <124 0x2 0 0>;
+ cell-index = <0xa>;
+ };
+ qportal11: qman-portal@2c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x2c000 0x4000>, <0x100b000 0x1000>;
+ interrupts = <126 0x2 0 0>;
+ cell-index = <0xb>;
+ };
+ qportal12: qman-portal@30000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x30000 0x4000>, <0x100c000 0x1000>;
+ interrupts = <128 0x2 0 0>;
+ cell-index = <0xc>;
+ };
+ qportal13: qman-portal@34000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x34000 0x4000>, <0x100d000 0x1000>;
+ interrupts = <130 0x2 0 0>;
+ cell-index = <0xd>;
+ };
+ qportal14: qman-portal@38000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x38000 0x4000>, <0x100e000 0x1000>;
+ interrupts = <132 0x2 0 0>;
+ cell-index = <0xe>;
+ };
+ qportal15: qman-portal@3c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x3c000 0x4000>, <0x100f000 0x1000>;
+ interrupts = <134 0x2 0 0>;
+ cell-index = <0xf>;
+ };
+ qportal16: qman-portal@40000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x40000 0x4000>, <0x1010000 0x1000>;
+ interrupts = <136 0x2 0 0>;
+ cell-index = <0x10>;
+ };
+ qportal17: qman-portal@44000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x44000 0x4000>, <0x1011000 0x1000>;
+ interrupts = <138 0x2 0 0>;
+ cell-index = <0x11>;
+ };
+};
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -417,7 +542,7 @@
compatible = "fsl,qoriq-core-mux-2.0";
clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
<&pll1 0>, <&pll1 1>, <&pll1 2>;
- clock-names = "pll0", "pll0-div2", "pll1-div4",
+ clock-names = "pll0", "pll0-div2", "pll0-div4",
"pll1", "pll1-div2", "pll1-div4";
clock-output-names = "cmux0";
};
@@ -428,7 +553,7 @@
compatible = "fsl,qoriq-core-mux-2.0";
clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
<&pll1 0>, <&pll1 1>, <&pll1 2>;
- clock-names = "pll0", "pll0-div2", "pll1-div4",
+ clock-names = "pll0", "pll0-div2", "pll0-div4",
"pll1", "pll1-div2", "pll1-div4";
clock-output-names = "cmux1";
};
@@ -502,6 +627,7 @@
phy_type = "utmi";
};
/include/ "qoriq-sec5.2-0.dtsi"
+/include/ "qoriq-qman3.dtsi"
/include/ "qoriq-bman1.dtsi"
L2_1: l2-cache-controller@c20000 {
diff --git a/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi b/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
index 4d4f25895d8c..d806360d0f64 100644
--- a/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
@@ -37,6 +37,16 @@
alloc-ranges = <0 0 0x10000 0>;
};
+&qman_fqd {
+ compatible = "fsl,qman-fqd";
+ alloc-ranges = <0 0 0x10000 0>;
+};
+
+&qman_pfdr {
+ compatible = "fsl,qman-pfdr";
+ alloc-ranges = <0 0 0x10000 0>;
+};
+
&ifc {
#address-cells = <2>;
#size-cells = <1>;
@@ -556,6 +566,313 @@
};
};
+&qportals {
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ compatible = "simple-bus";
+
+ qportal0: qman-portal@0 {
+ compatible = "fsl,qman-portal";
+ reg = <0x0 0x4000>, <0x1000000 0x1000>;
+ interrupts = <104 0x2 0 0>;
+ cell-index = <0x0>;
+ };
+ qportal1: qman-portal@4000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x4000 0x4000>, <0x1001000 0x1000>;
+ interrupts = <106 0x2 0 0>;
+ cell-index = <0x1>;
+ };
+ qportal2: qman-portal@8000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x8000 0x4000>, <0x1002000 0x1000>;
+ interrupts = <108 0x2 0 0>;
+ cell-index = <0x2>;
+ };
+ qportal3: qman-portal@c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xc000 0x4000>, <0x1003000 0x1000>;
+ interrupts = <110 0x2 0 0>;
+ cell-index = <0x3>;
+ };
+ qportal4: qman-portal@10000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x10000 0x4000>, <0x1004000 0x1000>;
+ interrupts = <112 0x2 0 0>;
+ cell-index = <0x4>;
+ };
+ qportal5: qman-portal@14000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x14000 0x4000>, <0x1005000 0x1000>;
+ interrupts = <114 0x2 0 0>;
+ cell-index = <0x5>;
+ };
+ qportal6: qman-portal@18000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x18000 0x4000>, <0x1006000 0x1000>;
+ interrupts = <116 0x2 0 0>;
+ cell-index = <0x6>;
+ };
+ qportal7: qman-portal@1c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x1c000 0x4000>, <0x1007000 0x1000>;
+ interrupts = <118 0x2 0 0>;
+ cell-index = <0x7>;
+ };
+ qportal8: qman-portal@20000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x20000 0x4000>, <0x1008000 0x1000>;
+ interrupts = <120 0x2 0 0>;
+ cell-index = <0x8>;
+ };
+ qportal9: qman-portal@24000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x24000 0x4000>, <0x1009000 0x1000>;
+ interrupts = <122 0x2 0 0>;
+ cell-index = <0x9>;
+ };
+ qportal10: qman-portal@28000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x28000 0x4000>, <0x100a000 0x1000>;
+ interrupts = <124 0x2 0 0>;
+ cell-index = <0xa>;
+ };
+ qportal11: qman-portal@2c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x2c000 0x4000>, <0x100b000 0x1000>;
+ interrupts = <126 0x2 0 0>;
+ cell-index = <0xb>;
+ };
+ qportal12: qman-portal@30000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x30000 0x4000>, <0x100c000 0x1000>;
+ interrupts = <128 0x2 0 0>;
+ cell-index = <0xc>;
+ };
+ qportal13: qman-portal@34000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x34000 0x4000>, <0x100d000 0x1000>;
+ interrupts = <130 0x2 0 0>;
+ cell-index = <0xd>;
+ };
+ qportal14: qman-portal@38000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x38000 0x4000>, <0x100e000 0x1000>;
+ interrupts = <132 0x2 0 0>;
+ cell-index = <0xe>;
+ };
+ qportal15: qman-portal@3c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x3c000 0x4000>, <0x100f000 0x1000>;
+ interrupts = <134 0x2 0 0>;
+ cell-index = <0xf>;
+ };
+ qportal16: qman-portal@40000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x40000 0x4000>, <0x1010000 0x1000>;
+ interrupts = <136 0x2 0 0>;
+ cell-index = <0x10>;
+ };
+ qportal17: qman-portal@44000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x44000 0x4000>, <0x1011000 0x1000>;
+ interrupts = <138 0x2 0 0>;
+ cell-index = <0x11>;
+ };
+ qportal18: qman-portal@48000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x48000 0x4000>, <0x1012000 0x1000>;
+ interrupts = <140 0x2 0 0>;
+ cell-index = <0x12>;
+ };
+ qportal19: qman-portal@4c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x4c000 0x4000>, <0x1013000 0x1000>;
+ interrupts = <142 0x2 0 0>;
+ cell-index = <0x13>;
+ };
+ qportal20: qman-portal@50000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x50000 0x4000>, <0x1014000 0x1000>;
+ interrupts = <144 0x2 0 0>;
+ cell-index = <0x14>;
+ };
+ qportal21: qman-portal@54000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x54000 0x4000>, <0x1015000 0x1000>;
+ interrupts = <146 0x2 0 0>;
+ cell-index = <0x15>;
+ };
+ qportal22: qman-portal@58000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x58000 0x4000>, <0x1016000 0x1000>;
+ interrupts = <148 0x2 0 0>;
+ cell-index = <0x16>;
+ };
+ qportal23: qman-portal@5c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x5c000 0x4000>, <0x1017000 0x1000>;
+ interrupts = <150 0x2 0 0>;
+ cell-index = <0x17>;
+ };
+ qportal24: qman-portal@60000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x60000 0x4000>, <0x1018000 0x1000>;
+ interrupts = <152 0x2 0 0>;
+ cell-index = <0x18>;
+ };
+ qportal25: qman-portal@64000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x64000 0x4000>, <0x1019000 0x1000>;
+ interrupts = <154 0x2 0 0>;
+ cell-index = <0x19>;
+ };
+ qportal26: qman-portal@68000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x68000 0x4000>, <0x101a000 0x1000>;
+ interrupts = <156 0x2 0 0>;
+ cell-index = <0x1a>;
+ };
+ qportal27: qman-portal@6c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x6c000 0x4000>, <0x101b000 0x1000>;
+ interrupts = <158 0x2 0 0>;
+ cell-index = <0x1b>;
+ };
+ qportal28: qman-portal@70000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x70000 0x4000>, <0x101c000 0x1000>;
+ interrupts = <160 0x2 0 0>;
+ cell-index = <0x1c>;
+ };
+ qportal29: qman-portal@74000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x74000 0x4000>, <0x101d000 0x1000>;
+ interrupts = <162 0x2 0 0>;
+ cell-index = <0x1d>;
+ };
+ qportal30: qman-portal@78000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x78000 0x4000>, <0x101e000 0x1000>;
+ interrupts = <164 0x2 0 0>;
+ cell-index = <0x1e>;
+ };
+ qportal31: qman-portal@7c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x7c000 0x4000>, <0x101f000 0x1000>;
+ interrupts = <166 0x2 0 0>;
+ cell-index = <0x1f>;
+ };
+ qportal32: qman-portal@80000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x80000 0x4000>, <0x1020000 0x1000>;
+ interrupts = <168 0x2 0 0>;
+ cell-index = <0x20>;
+ };
+ qportal33: qman-portal@84000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x84000 0x4000>, <0x1021000 0x1000>;
+ interrupts = <170 0x2 0 0>;
+ cell-index = <0x21>;
+ };
+ qportal34: qman-portal@88000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x88000 0x4000>, <0x1022000 0x1000>;
+ interrupts = <172 0x2 0 0>;
+ cell-index = <0x22>;
+ };
+ qportal35: qman-portal@8c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x8c000 0x4000>, <0x1023000 0x1000>;
+ interrupts = <174 0x2 0 0>;
+ cell-index = <0x23>;
+ };
+ qportal36: qman-portal@90000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x90000 0x4000>, <0x1024000 0x1000>;
+ interrupts = <384 0x2 0 0>;
+ cell-index = <0x24>;
+ };
+ qportal37: qman-portal@94000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x94000 0x4000>, <0x1025000 0x1000>;
+ interrupts = <386 0x2 0 0>;
+ cell-index = <0x25>;
+ };
+ qportal38: qman-portal@98000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x98000 0x4000>, <0x1026000 0x1000>;
+ interrupts = <388 0x2 0 0>;
+ cell-index = <0x26>;
+ };
+ qportal39: qman-portal@9c000 {
+ compatible = "fsl,qman-portal";
+ reg = <0x9c000 0x4000>, <0x1027000 0x1000>;
+ interrupts = <390 0x2 0 0>;
+ cell-index = <0x27>;
+ };
+ qportal40: qman-portal@a0000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xa0000 0x4000>, <0x1028000 0x1000>;
+ interrupts = <392 0x2 0 0>;
+ cell-index = <0x28>;
+ };
+ qportal41: qman-portal@a4000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xa4000 0x4000>, <0x1029000 0x1000>;
+ interrupts = <394 0x2 0 0>;
+ cell-index = <0x29>;
+ };
+ qportal42: qman-portal@a8000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xa8000 0x4000>, <0x102a000 0x1000>;
+ interrupts = <396 0x2 0 0>;
+ cell-index = <0x2a>;
+ };
+ qportal43: qman-portal@ac000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xac000 0x4000>, <0x102b000 0x1000>;
+ interrupts = <398 0x2 0 0>;
+ cell-index = <0x2b>;
+ };
+ qportal44: qman-portal@b0000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xb0000 0x4000>, <0x102c000 0x1000>;
+ interrupts = <400 0x2 0 0>;
+ cell-index = <0x2c>;
+ };
+ qportal45: qman-portal@b4000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xb4000 0x4000>, <0x102d000 0x1000>;
+ interrupts = <402 0x2 0 0>;
+ cell-index = <0x2d>;
+ };
+ qportal46: qman-portal@b8000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xb8000 0x4000>, <0x102e000 0x1000>;
+ interrupts = <404 0x2 0 0>;
+ cell-index = <0x2e>;
+ };
+ qportal47: qman-portal@bc000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xbc000 0x4000>, <0x102f000 0x1000>;
+ interrupts = <406 0x2 0 0>;
+ cell-index = <0x2f>;
+ };
+ qportal48: qman-portal@c0000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xc0000 0x4000>, <0x1030000 0x1000>;
+ interrupts = <408 0x2 0 0>;
+ cell-index = <0x30>;
+ };
+ qportal49: qman-portal@c4000 {
+ compatible = "fsl,qman-portal";
+ reg = <0xc4000 0x4000>, <0x1031000 0x1000>;
+ interrupts = <410 0x2 0 0>;
+ cell-index = <0x31>;
+ };
+};
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -748,6 +1065,7 @@
/include/ "qoriq-sata2-0.dtsi"
/include/ "qoriq-sata2-1.dtsi"
/include/ "qoriq-sec5.0-0.dtsi"
+/include/ "qoriq-qman3.dtsi"
/include/ "qoriq-bman1.dtsi"
L2_1: l2-cache-controller@c20000 {
diff --git a/arch/powerpc/boot/dts/kmcoge4.dts b/arch/powerpc/boot/dts/kmcoge4.dts
index 97e6d11d1e6d..48dab6a50437 100644
--- a/arch/powerpc/boot/dts/kmcoge4.dts
+++ b/arch/powerpc/boot/dts/kmcoge4.dts
@@ -34,6 +34,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
dcsr: dcsr@f00000000 {
@@ -44,6 +52,10 @@
ranges = <0x0 0xf 0xf4000000 0x200000>;
};
+ qportals: qman-portals@ff4200000 {
+ ranges = <0x0 0xf 0xf4200000 0x200000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/oca4080.dts b/arch/powerpc/boot/dts/oca4080.dts
index eb76caae11d9..42796c5b0561 100644
--- a/arch/powerpc/boot/dts/oca4080.dts
+++ b/arch/powerpc/boot/dts/oca4080.dts
@@ -58,6 +58,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
dcsr: dcsr@f00000000 {
@@ -68,6 +76,10 @@
ranges = <0x0 0xf 0xf4000000 0x200000>;
};
+ qportals: qman-portals@ff4200000 {
+ ranges = <0x0 0xf 0xf4200000 0x200000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/p1023rdb.dts b/arch/powerpc/boot/dts/p1023rdb.dts
index 9236e3742a23..05a00a4d2861 100644
--- a/arch/powerpc/boot/dts/p1023rdb.dts
+++ b/arch/powerpc/boot/dts/p1023rdb.dts
@@ -56,6 +56,18 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
+ };
+
+ qportals: qman-portals@ff000000 {
+ ranges = <0x0 0xf 0xff000000 0x200000>;
};
bportals: bman-portals@ff200000 {
diff --git a/arch/powerpc/boot/dts/p2041rdb.dts b/arch/powerpc/boot/dts/p2041rdb.dts
index c1e69dc7188e..d2bb0765bd5a 100644
--- a/arch/powerpc/boot/dts/p2041rdb.dts
+++ b/arch/powerpc/boot/dts/p2041rdb.dts
@@ -54,6 +54,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
dcsr: dcsr@f00000000 {
@@ -64,6 +72,10 @@
ranges = <0x0 0xf 0xf4000000 0x200000>;
};
+ qportals: qman-portals@ff4200000 {
+ ranges = <0x0 0xf 0xf4200000 0x200000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/p3041ds.dts b/arch/powerpc/boot/dts/p3041ds.dts
index 2192fe94866d..eca6c697cfd7 100644
--- a/arch/powerpc/boot/dts/p3041ds.dts
+++ b/arch/powerpc/boot/dts/p3041ds.dts
@@ -54,6 +54,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
dcsr: dcsr@f00000000 {
@@ -64,6 +72,10 @@
ranges = <0x0 0xf 0xf4000000 0x200000>;
};
+ qportals: qman-portals@ff4200000 {
+ ranges = <0x0 0xf 0xf4200000 0x200000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts
index fad441654642..4f80c9d02c27 100644
--- a/arch/powerpc/boot/dts/p4080ds.dts
+++ b/arch/powerpc/boot/dts/p4080ds.dts
@@ -54,6 +54,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
dcsr: dcsr@f00000000 {
@@ -64,6 +72,10 @@
ranges = <0x0 0xf 0xf4000000 0x200000>;
};
+ qportals: qman-portals@ff4200000 {
+ ranges = <0x0 0xf 0xf4200000 0x200000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/p5020ds.dts b/arch/powerpc/boot/dts/p5020ds.dts
index 7382636dc560..d0309a8b9749 100644
--- a/arch/powerpc/boot/dts/p5020ds.dts
+++ b/arch/powerpc/boot/dts/p5020ds.dts
@@ -54,6 +54,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
dcsr: dcsr@f00000000 {
@@ -64,6 +72,10 @@
ranges = <0x0 0xf 0xf4000000 0x200000>;
};
+ qportals: qman-portals@ff4200000 {
+ ranges = <0x0 0xf 0xf4200000 0x200000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/p5040ds.dts b/arch/powerpc/boot/dts/p5040ds.dts
index 35dabf5b6098..05168236d3ab 100644
--- a/arch/powerpc/boot/dts/p5040ds.dts
+++ b/arch/powerpc/boot/dts/p5040ds.dts
@@ -54,6 +54,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
dcsr: dcsr@f00000000 {
@@ -64,6 +72,10 @@
ranges = <0x0 0xf 0xf4000000 0x200000>;
};
+ qportals: qman-portals@ff4200000 {
+ ranges = <0x0 0xf 0xf4200000 0x200000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/t1023rdb.dts b/arch/powerpc/boot/dts/t1023rdb.dts
new file mode 100644
index 000000000000..06b090aba066
--- /dev/null
+++ b/arch/powerpc/boot/dts/t1023rdb.dts
@@ -0,0 +1,151 @@
+/*
+ * T1023 RDB Device Tree Source
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor 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/ "fsl/t102xsi-pre.dtsi"
+
+/ {
+ model = "fsl,T1023RDB";
+ compatible = "fsl,T1023RDB";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&mpic>;
+
+ ifc: localbus@ffe124000 {
+ reg = <0xf 0xfe124000 0 0x2000>;
+ ranges = <0 0 0xf 0xe8000000 0x08000000
+ 1 0 0xf 0xff800000 0x00010000>;
+
+ nor@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x8000000>;
+ bank-width = <2>;
+ device-width = <1>;
+ };
+
+ nand@1,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,ifc-nand";
+ reg = <0x2 0x0 0x10000>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ };
+
+ dcsr: dcsr@f00000000 {
+ ranges = <0x00000000 0xf 0x00000000 0x01072000>;
+ };
+
+ soc: soc@ffe000000 {
+ ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
+ reg = <0xf 0xfe000000 0 0x00001000>;
+ spi@110000 {
+ flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spansion,s25fl512s";
+ reg = <0>;
+ spi-max-frequency = <10000000>; /* input clk */
+ };
+ };
+
+ i2c@118000 {
+ eeprom@50 {
+ compatible = "st,m24256";
+ reg = <0x50>;
+ };
+
+ rtc@68 {
+ compatible = "dallas,ds1339";
+ reg = <0x68>;
+ interrupts = <0x5 0x1 0 0>;
+ };
+ };
+
+ i2c@118100 {
+ };
+ };
+
+ pci0: pcie@ffe240000 {
+ reg = <0xf 0xfe240000 0 0x10000>;
+ ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xf 0xf8000000 0 0x00010000>;
+ pcie@0 {
+ ranges = <0x02000000 0 0xe0000000
+ 0x02000000 0 0xe0000000
+ 0 0x10000000
+
+ 0x01000000 0 0x00000000
+ 0x01000000 0 0x00000000
+ 0 0x00010000>;
+ };
+ };
+
+ pci1: pcie@ffe250000 {
+ reg = <0xf 0xfe250000 0 0x10000>;
+ ranges = <0x02000000 0 0xe0000000 0xc 0x10000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xf 0xf8010000 0 0x00010000>;
+ pcie@0 {
+ ranges = <0x02000000 0 0xe0000000
+ 0x02000000 0 0xe0000000
+ 0 0x10000000
+
+ 0x01000000 0 0x00000000
+ 0x01000000 0 0x00000000
+ 0 0x00010000>;
+ };
+ };
+
+ pci2: pcie@ffe260000 {
+ reg = <0xf 0xfe260000 0 0x10000>;
+ ranges = <0x02000000 0 0xe0000000 0xc 0x20000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
+ pcie@0 {
+ ranges = <0x02000000 0 0xe0000000
+ 0x02000000 0 0xe0000000
+ 0 0x10000000
+
+ 0x01000000 0 0x00000000
+ 0x01000000 0 0x00000000
+ 0 0x00010000>;
+ };
+ };
+};
+
+/include/ "fsl/t1023si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/t1024qds.dts b/arch/powerpc/boot/dts/t1024qds.dts
new file mode 100644
index 000000000000..f31fabb383b9
--- /dev/null
+++ b/arch/powerpc/boot/dts/t1024qds.dts
@@ -0,0 +1,251 @@
+/*
+ * T1024 QDS Device Tree Source
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor 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/ "fsl/t102xsi-pre.dtsi"
+
+/ {
+ model = "fsl,T1024QDS";
+ compatible = "fsl,T1024QDS";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&mpic>;
+
+ ifc: localbus@ffe124000 {
+ reg = <0xf 0xfe124000 0 0x2000>;
+ ranges = <0 0 0xf 0xe8000000 0x08000000
+ 2 0 0xf 0xff800000 0x00010000
+ 3 0 0xf 0xffdf0000 0x00008000>;
+
+ nor@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x8000000>;
+ bank-width = <2>;
+ device-width = <1>;
+ };
+
+ nand@2,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,ifc-nand";
+ reg = <0x2 0x0 0x10000>;
+ };
+
+ board-control@3,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,tetra-fpga", "fsl,fpga-qixis";
+ reg = <3 0 0x300>;
+ ranges = <0 3 0 0x300>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ };
+
+ dcsr: dcsr@f00000000 {
+ ranges = <0x00000000 0xf 0x00000000 0x01072000>;
+ };
+
+ soc: soc@ffe000000 {
+ ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
+ reg = <0xf 0xfe000000 0 0x00001000>;
+ spi@110000 {
+ flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "micron,n25q128a11"; /* 16MB */
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+ };
+
+ flash@1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "sst,sst25wf040"; /* 512KB */
+ reg = <1>;
+ spi-max-frequency = <10000000>;
+ };
+
+ flash@2 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "eon,en25s64"; /* 8MB */
+ reg = <2>;
+ spi-max-frequency = <10000000>;
+ };
+
+ slic@2 {
+ compatible = "maxim,ds26522";
+ reg = <2>;
+ spi-max-frequency = <2000000>;
+ };
+
+ slic@3 {
+ compatible = "maxim,ds26522";
+ reg = <3>;
+ spi-max-frequency = <2000000>;
+ };
+ };
+
+ i2c@118000 {
+ pca9547@77 {
+ compatible = "nxp,pca9547";
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0>;
+
+ eeprom@50 {
+ compatible = "atmel,24c512";
+ reg = <0x50>;
+ };
+
+ eeprom@51 {
+ compatible = "atmel,24c02";
+ reg = <0x51>;
+ };
+
+ eeprom@57 {
+ compatible = "atmel,24c02";
+ reg = <0x57>;
+ };
+ };
+
+ i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x2>;
+
+ ina220@40 {
+ compatible = "ti,ina220";
+ reg = <0x40>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@41 {
+ compatible = "ti,ina220";
+ reg = <0x41>;
+ shunt-resistor = <1000>;
+ };
+ };
+
+ i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x3>;
+
+ adt7461@4c {
+ /* Thermal Monitor */
+ compatible = "adi,adt7461";
+ reg = <0x4c>;
+ };
+
+ eeprom@55 {
+ compatible = "atmel,24c02";
+ reg = <0x55>;
+ };
+
+ eeprom@56 {
+ compatible = "atmel,24c512";
+ reg = <0x56>;
+ };
+
+ eeprom@57 {
+ compatible = "atmel,24c512";
+ reg = <0x57>;
+ };
+ };
+ };
+ rtc@68 {
+ compatible = "dallas,ds3232";
+ reg = <0x68>;
+ interrupts = <0x5 0x1 0 0>;
+ };
+ };
+ };
+
+ pci0: pcie@ffe240000 {
+ reg = <0xf 0xfe240000 0 0x10000>;
+ ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xf 0xf8000000 0 0x00010000>;
+ pcie@0 {
+ ranges = <0x02000000 0 0xe0000000
+ 0x02000000 0 0xe0000000
+ 0 0x10000000
+
+ 0x01000000 0 0x00000000
+ 0x01000000 0 0x00000000
+ 0 0x00010000>;
+ };
+ };
+
+ pci1: pcie@ffe250000 {
+ reg = <0xf 0xfe250000 0 0x10000>;
+ ranges = <0x02000000 0 0xe0000000 0xc 0x10000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xf 0xf8010000 0 0x00010000>;
+ pcie@0 {
+ ranges = <0x02000000 0 0xe0000000
+ 0x02000000 0 0xe0000000
+ 0 0x10000000
+
+ 0x01000000 0 0x00000000
+ 0x01000000 0 0x00000000
+ 0 0x00010000>;
+ };
+ };
+
+ pci2: pcie@ffe260000 {
+ reg = <0xf 0xfe260000 0 0x10000>;
+ ranges = <0x02000000 0 0xe0000000 0xc 0x20000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
+ pcie@0 {
+ ranges = <0x02000000 0 0xe0000000
+ 0x02000000 0 0xe0000000
+ 0 0x10000000
+
+ 0x01000000 0 0x00000000
+ 0x01000000 0 0x00000000
+ 0 0x00010000>;
+ };
+ };
+};
+
+/include/ "fsl/t1024si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/t1024rdb.dts b/arch/powerpc/boot/dts/t1024rdb.dts
new file mode 100644
index 000000000000..733e723ffed6
--- /dev/null
+++ b/arch/powerpc/boot/dts/t1024rdb.dts
@@ -0,0 +1,185 @@
+/*
+ * T1024 RDB Device Tree Source
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * 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 Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor 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/ "fsl/t102xsi-pre.dtsi"
+
+/ {
+ model = "fsl,T1024RDB";
+ compatible = "fsl,T1024RDB";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&mpic>;
+
+ ifc: localbus@ffe124000 {
+ reg = <0xf 0xfe124000 0 0x2000>;
+ ranges = <0 0 0xf 0xe8000000 0x08000000
+ 2 0 0xf 0xff800000 0x00010000
+ 3 0 0xf 0xffdf0000 0x00008000>;
+
+ nor@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x8000000>;
+ bank-width = <2>;
+ device-width = <1>;
+ };
+
+ nand@1,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,ifc-nand";
+ reg = <0x2 0x0 0x10000>;
+ };
+
+ board-control@2,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,t1024-cpld";
+ reg = <3 0 0x300>;
+ ranges = <0 3 0 0x300>;
+ bank-width = <1>;
+ device-width = <1>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ };
+
+ dcsr: dcsr@f00000000 {
+ ranges = <0x00000000 0xf 0x00000000 0x01072000>;
+ };
+
+ soc: soc@ffe000000 {
+ ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
+ reg = <0xf 0xfe000000 0 0x00001000>;
+ spi@110000 {
+ flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "micron,n25q512ax3";
+ reg = <0>;
+ spi-max-frequency = <10000000>; /* input clk */
+ };
+
+ slic@1 {
+ compatible = "maxim,ds26522";
+ reg = <1>;
+ spi-max-frequency = <2000000>;
+ };
+
+ slic@2 {
+ compatible = "maxim,ds26522";
+ reg = <2>;
+ spi-max-frequency = <2000000>;
+ };
+ };
+
+ i2c@118000 {
+ adt7461@4c {
+ /* Thermal Monitor */
+ compatible = "adi,adt7461";
+ reg = <0x4c>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c256";
+ reg = <0x50>;
+ };
+
+ rtc@68 {
+ compatible = "dallas,ds1339";
+ reg = <0x68>;
+ interrupts = <0x1 0x1 0 0>;
+ };
+ };
+
+ i2c@118100 {
+ pca9546@77 {
+ compatible = "nxp,pca9546";
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+
+ pci0: pcie@ffe240000 {
+ reg = <0xf 0xfe240000 0 0x10000>;
+ ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xf 0xf8000000 0 0x00010000>;
+ pcie@0 {
+ ranges = <0x02000000 0 0xe0000000
+ 0x02000000 0 0xe0000000
+ 0 0x10000000
+
+ 0x01000000 0 0x00000000
+ 0x01000000 0 0x00000000
+ 0 0x00010000>;
+ };
+ };
+
+ pci1: pcie@ffe250000 {
+ reg = <0xf 0xfe250000 0 0x10000>;
+ ranges = <0x02000000 0 0xe0000000 0xc 0x10000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xf 0xf8010000 0 0x00010000>;
+ pcie@0 {
+ ranges = <0x02000000 0 0xe0000000
+ 0x02000000 0 0xe0000000
+ 0 0x10000000
+
+ 0x01000000 0 0x00000000
+ 0x01000000 0 0x00000000
+ 0 0x00010000>;
+ };
+ };
+
+ pci2: pcie@ffe260000 {
+ reg = <0xf 0xfe260000 0 0x10000>;
+ ranges = <0x02000000 0 0xe0000000 0xc 0x20000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
+ pcie@0 {
+ ranges = <0x02000000 0 0xe0000000
+ 0x02000000 0 0xe0000000
+ 0 0x10000000
+
+ 0x01000000 0 0x00000000
+ 0x01000000 0 0x00000000
+ 0 0x00010000>;
+ };
+ };
+};
+
+/include/ "fsl/t1024si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/t104xqds.dtsi b/arch/powerpc/boot/dts/t104xqds.dtsi
index f7e9bfbeefc7..1498d1e4aecf 100644
--- a/arch/powerpc/boot/dts/t104xqds.dtsi
+++ b/arch/powerpc/boot/dts/t104xqds.dtsi
@@ -47,6 +47,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
ifc: localbus@ffe124000 {
@@ -92,6 +100,10 @@
ranges = <0x0 0xf 0xf4000000 0x2000000>;
};
+ qportals: qman-portals@ff6000000 {
+ ranges = <0x0 0xf 0xf6000000 0x2000000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/t104xrdb.dtsi b/arch/powerpc/boot/dts/t104xrdb.dtsi
index 76e07a3f2ca8..830ea484295b 100644
--- a/arch/powerpc/boot/dts/t104xrdb.dtsi
+++ b/arch/powerpc/boot/dts/t104xrdb.dtsi
@@ -42,6 +42,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
ifc: localbus@ffe124000 {
@@ -83,6 +91,10 @@
ranges = <0x0 0xf 0xf4000000 0x2000000>;
};
+ qportals: qman-portals@ff6000000 {
+ ranges = <0x0 0xf 0xf6000000 0x2000000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/t208xqds.dtsi b/arch/powerpc/boot/dts/t208xqds.dtsi
index c42e07f4f648..869f9159b4d1 100644
--- a/arch/powerpc/boot/dts/t208xqds.dtsi
+++ b/arch/powerpc/boot/dts/t208xqds.dtsi
@@ -48,6 +48,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
ifc: localbus@ffe124000 {
@@ -93,6 +101,10 @@
ranges = <0x0 0xf 0xf4000000 0x2000000>;
};
+ qportals: qman-portals@ff6000000 {
+ ranges = <0x0 0xf 0xf6000000 0x2000000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/t208xrdb.dtsi b/arch/powerpc/boot/dts/t208xrdb.dtsi
index e1463b165d0e..693d2a8fa01c 100644
--- a/arch/powerpc/boot/dts/t208xrdb.dtsi
+++ b/arch/powerpc/boot/dts/t208xrdb.dtsi
@@ -48,6 +48,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
ifc: localbus@ffe124000 {
@@ -94,6 +102,10 @@
ranges = <0x0 0xf 0xf4000000 0x2000000>;
};
+ qportals: qman-portals@ff6000000 {
+ ranges = <0x0 0xf 0xf6000000 0x2000000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/t4240qds.dts b/arch/powerpc/boot/dts/t4240qds.dts
index 6df77766410b..93722da10e16 100644
--- a/arch/powerpc/boot/dts/t4240qds.dts
+++ b/arch/powerpc/boot/dts/t4240qds.dts
@@ -109,6 +109,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
dcsr: dcsr@f00000000 {
@@ -119,6 +127,10 @@
ranges = <0x0 0xf 0xf4000000 0x2000000>;
};
+ qportals: qman-portals@ff6000000 {
+ ranges = <0x0 0xf 0xf6000000 0x2000000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/boot/dts/t4240rdb.dts b/arch/powerpc/boot/dts/t4240rdb.dts
index 46049cf37f02..993eb4b8a487 100644
--- a/arch/powerpc/boot/dts/t4240rdb.dts
+++ b/arch/powerpc/boot/dts/t4240rdb.dts
@@ -78,6 +78,14 @@
size = <0 0x1000000>;
alignment = <0 0x1000000>;
};
+ qman_fqd: qman-fqd {
+ size = <0 0x400000>;
+ alignment = <0 0x400000>;
+ };
+ qman_pfdr: qman-pfdr {
+ size = <0 0x2000000>;
+ alignment = <0 0x2000000>;
+ };
};
dcsr: dcsr@f00000000 {
@@ -88,6 +96,10 @@
ranges = <0x0 0xf 0xf4000000 0x2000000>;
};
+ qportals: qman-portals@ff6000000 {
+ ranges = <0x0 0xf 0xf6000000 0x2000000>;
+ };
+
soc: soc@ffe000000 {
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
diff --git a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
index 34f3ea1729e0..858b539d004b 100644
--- a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
+++ b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
@@ -108,7 +108,7 @@ CONFIG_SENSORS_LM90=y
CONFIG_WATCHDOG=y
CONFIG_USB=y
CONFIG_USB_MON=y
-CONFIG_USB_ISP1760_HCD=y
+CONFIG_USB_ISP1760=y
CONFIG_USB_STORAGE=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
diff --git a/arch/powerpc/configs/le.config b/arch/powerpc/configs/le.config
new file mode 100644
index 000000000000..ee43fdb3b8f4
--- /dev/null
+++ b/arch/powerpc/configs/le.config
@@ -0,0 +1 @@
+CONFIG_CPU_LITTLE_ENDIAN=y
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index aad501ae3834..a97efc2146fd 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -155,6 +155,7 @@ CONFIG_ACENIC=m
CONFIG_ACENIC_OMIT_TIGON_I=y
CONFIG_PCNET32=y
CONFIG_TIGON3=y
+CONFIG_BNX2X=m
CONFIG_CHELSIO_T1=m
CONFIG_BE2NET=m
CONFIG_S2IO=m
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index c2e39f66b182..0d9efcedaf34 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -154,6 +154,7 @@ CONFIG_ACENIC=m
CONFIG_ACENIC_OMIT_TIGON_I=y
CONFIG_PCNET32=y
CONFIG_TIGON3=y
+CONFIG_BNX2X=m
CONFIG_CHELSIO_T1=m
CONFIG_BE2NET=m
CONFIG_S2IO=m
@@ -297,7 +298,6 @@ CONFIG_CODE_PATCHING_SELFTEST=y
CONFIG_FTR_FIXUP_SELFTEST=y
CONFIG_MSI_BITMAP_SELFTEST=y
CONFIG_XMON=y
-CONFIG_XMON_DEFAULT=y
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
diff --git a/arch/powerpc/configs/pseries_le_defconfig b/arch/powerpc/configs/pseries_le_defconfig
deleted file mode 100644
index 09bc96e792cd..000000000000
--- a/arch/powerpc/configs/pseries_le_defconfig
+++ /dev/null
@@ -1,319 +0,0 @@
-CONFIG_PPC64=y
-CONFIG_SMP=y
-CONFIG_NR_CPUS=2048
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_FHANDLE=y
-CONFIG_AUDIT=y
-CONFIG_AUDITSYSCALL=y
-CONFIG_IRQ_DOMAIN_DEBUG=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_TASKSTATS=y
-CONFIG_TASK_DELAY_ACCT=y
-CONFIG_TASK_XACCT=y
-CONFIG_TASK_IO_ACCOUNTING=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_NUMA_BALANCING=y
-CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_FREEZER=y
-CONFIG_CGROUP_DEVICE=y
-CONFIG_CPUSETS=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_MEMCG=y
-CONFIG_MEMCG_SWAP=y
-CONFIG_CGROUP_PERF=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_USER_NS=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
-CONFIG_KPROBES=y
-CONFIG_JUMP_LABEL=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_PPC_SPLPAR=y
-CONFIG_SCANLOG=m
-CONFIG_PPC_SMLPAR=y
-CONFIG_DTL=y
-# CONFIG_PPC_PMAC is not set
-CONFIG_RTAS_FLASH=m
-CONFIG_IBMEBUS=y
-CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
-CONFIG_HZ_100=y
-CONFIG_BINFMT_MISC=m
-CONFIG_PPC_TRANSACTIONAL_MEM=y
-CONFIG_KEXEC=y
-CONFIG_IRQ_ALL_CPUS=y
-CONFIG_MEMORY_HOTPLUG=y
-CONFIG_MEMORY_HOTREMOVE=y
-CONFIG_KSM=y
-CONFIG_TRANSPARENT_HUGEPAGE=y
-CONFIG_PPC_64K_PAGES=y
-CONFIG_PPC_SUBPAGE_PROT=y
-CONFIG_SCHED_SMT=y
-CONFIG_HOTPLUG_PCI=y
-CONFIG_HOTPLUG_PCI_RPA=m
-CONFIG_HOTPLUG_PCI_RPA_DLPAR=m
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_XFRM_USER=m
-CONFIG_NET_KEY=m
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_NET_IPIP=y
-CONFIG_SYN_COOKIES=y
-CONFIG_INET_AH=m
-CONFIG_INET_ESP=m
-CONFIG_INET_IPCOMP=m
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_ADVANCED is not set
-CONFIG_BRIDGE=m
-CONFIG_VLAN_8021Q=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_PARPORT=m
-CONFIG_PARPORT_PC=m
-CONFIG_BLK_DEV_FD=m
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=65536
-CONFIG_VIRTIO_BLK=m
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_AMD74XX=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_FC_ATTRS=y
-CONFIG_SCSI_CXGB3_ISCSI=m
-CONFIG_SCSI_CXGB4_ISCSI=m
-CONFIG_SCSI_BNX2_ISCSI=m
-CONFIG_BE2ISCSI=m
-CONFIG_SCSI_MPT2SAS=m
-CONFIG_SCSI_IBMVSCSI=y
-CONFIG_SCSI_IBMVFC=m
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
-CONFIG_SCSI_IPR=y
-CONFIG_SCSI_QLA_FC=m
-CONFIG_SCSI_QLA_ISCSI=m
-CONFIG_SCSI_LPFC=m
-CONFIG_SCSI_VIRTIO=m
-CONFIG_SCSI_DH=m
-CONFIG_SCSI_DH_RDAC=m
-CONFIG_SCSI_DH_ALUA=m
-CONFIG_ATA=y
-CONFIG_SATA_AHCI=y
-# CONFIG_ATA_SFF is not set
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=y
-CONFIG_MD_RAID0=y
-CONFIG_MD_RAID1=y
-CONFIG_MD_RAID10=m
-CONFIG_MD_RAID456=m
-CONFIG_MD_MULTIPATH=m
-CONFIG_MD_FAULTY=m
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=m
-CONFIG_DM_SNAPSHOT=m
-CONFIG_DM_THIN_PROVISIONING=m
-CONFIG_DM_MIRROR=m
-CONFIG_DM_ZERO=m
-CONFIG_DM_MULTIPATH=m
-CONFIG_DM_MULTIPATH_QL=m
-CONFIG_DM_MULTIPATH_ST=m
-CONFIG_DM_UEVENT=y
-CONFIG_BONDING=m
-CONFIG_DUMMY=m
-CONFIG_MACVLAN=m
-CONFIG_MACVTAP=m
-CONFIG_VXLAN=m
-CONFIG_NETCONSOLE=y
-CONFIG_TUN=m
-CONFIG_VETH=m
-CONFIG_VIRTIO_NET=m
-CONFIG_VHOST_NET=m
-CONFIG_VORTEX=y
-CONFIG_ACENIC=m
-CONFIG_ACENIC_OMIT_TIGON_I=y
-CONFIG_PCNET32=y
-CONFIG_TIGON3=y
-CONFIG_CHELSIO_T1=m
-CONFIG_BE2NET=m
-CONFIG_S2IO=m
-CONFIG_IBMVETH=y
-CONFIG_EHEA=y
-CONFIG_E100=y
-CONFIG_E1000=y
-CONFIG_E1000E=y
-CONFIG_IXGB=m
-CONFIG_IXGBE=m
-CONFIG_MLX4_EN=m
-CONFIG_MYRI10GE=m
-CONFIG_QLGE=m
-CONFIG_NETXEN_NIC=m
-CONFIG_PPP=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPPOE=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_EVDEV=m
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_PCSPKR=m
-# CONFIG_SERIO_SERPORT is not set
-CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_ICOM=m
-CONFIG_SERIAL_JSM=m
-CONFIG_HVC_CONSOLE=y
-CONFIG_HVC_RTAS=y
-CONFIG_HVCS=m
-CONFIG_VIRTIO_CONSOLE=m
-CONFIG_IBM_BSR=m
-CONFIG_GEN_RTC=y
-CONFIG_RAW_DRIVER=y
-CONFIG_MAX_RAW_DEVS=1024
-CONFIG_FB=y
-CONFIG_FIRMWARE_EDID=y
-CONFIG_FB_OF=y
-CONFIG_FB_MATROX=y
-CONFIG_FB_MATROX_MILLENIUM=y
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G=y
-CONFIG_FB_RADEON=y
-CONFIG_FB_IBM_GXT4500=y
-CONFIG_LCD_PLATFORM=m
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_LOGO=y
-CONFIG_HID_GYRATION=y
-CONFIG_HID_PANTHERLORD=y
-CONFIG_HID_PETALYNX=y
-CONFIG_HID_SAMSUNG=y
-CONFIG_HID_SUNPLUS=y
-CONFIG_USB_HIDDEV=y
-CONFIG_USB=y
-CONFIG_USB_MON=m
-CONFIG_USB_EHCI_HCD=y
-# CONFIG_USB_EHCI_HCD_PPC_OF is not set
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=m
-CONFIG_INFINIBAND=m
-CONFIG_INFINIBAND_USER_MAD=m
-CONFIG_INFINIBAND_USER_ACCESS=m
-CONFIG_INFINIBAND_MTHCA=m
-CONFIG_INFINIBAND_EHCA=m
-CONFIG_INFINIBAND_CXGB3=m
-CONFIG_INFINIBAND_CXGB4=m
-CONFIG_MLX4_INFINIBAND=m
-CONFIG_INFINIBAND_IPOIB=m
-CONFIG_INFINIBAND_IPOIB_CM=y
-CONFIG_INFINIBAND_SRP=m
-CONFIG_INFINIBAND_ISER=m
-CONFIG_VIRTIO_PCI=m
-CONFIG_VIRTIO_BALLOON=m
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-CONFIG_EXT2_FS_XIP=y
-CONFIG_EXT3_FS=y
-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_REISERFS_FS=y
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-CONFIG_REISERFS_FS_SECURITY=y
-CONFIG_JFS_FS=m
-CONFIG_JFS_POSIX_ACL=y
-CONFIG_JFS_SECURITY=y
-CONFIG_XFS_FS=m
-CONFIG_XFS_POSIX_ACL=y
-CONFIG_BTRFS_FS=m
-CONFIG_BTRFS_FS_POSIX_ACL=y
-CONFIG_NILFS2_FS=m
-CONFIG_AUTOFS4_FS=m
-CONFIG_FUSE_FS=m
-CONFIG_OVERLAY_FS=m
-CONFIG_ISO9660_FS=y
-CONFIG_UDF_FS=m
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_HUGETLBFS=y
-CONFIG_CRAMFS=m
-CONFIG_SQUASHFS=m
-CONFIG_SQUASHFS_XATTR=y
-CONFIG_SQUASHFS_LZO=y
-CONFIG_SQUASHFS_XZ=y
-CONFIG_PSTORE=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3_ACL=y
-CONFIG_NFSD_V4=y
-CONFIG_CIFS=m
-CONFIG_CIFS_XATTR=y
-CONFIG_CIFS_POSIX=y
-CONFIG_NLS_DEFAULT="utf8"
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_UTF8=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_STACK_USAGE=y
-CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_LOCKUP_DETECTOR=y
-CONFIG_LATENCYTOP=y
-CONFIG_SCHED_TRACER=y
-CONFIG_BLK_DEV_IO_TRACE=y
-CONFIG_CODE_PATCHING_SELFTEST=y
-CONFIG_FTR_FIXUP_SELFTEST=y
-CONFIG_MSI_BITMAP_SELFTEST=y
-CONFIG_XMON=y
-CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_SALSA20=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_LZO=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_VIRTUALIZATION=y
-CONFIG_KVM_BOOK3S_64=m
-CONFIG_KVM_BOOK3S_64_HV=m
diff --git a/arch/powerpc/crypto/md5-glue.c b/arch/powerpc/crypto/md5-glue.c
index 452fb4dc575f..92289679b4c4 100644
--- a/arch/powerpc/crypto/md5-glue.c
+++ b/arch/powerpc/crypto/md5-glue.c
@@ -37,10 +37,10 @@ static int ppc_md5_init(struct shash_desc *desc)
{
struct md5_state *sctx = shash_desc_ctx(desc);
- sctx->hash[0] = 0x67452301;
- sctx->hash[1] = 0xefcdab89;
- sctx->hash[2] = 0x98badcfe;
- sctx->hash[3] = 0x10325476;
+ sctx->hash[0] = MD5_H0;
+ sctx->hash[1] = MD5_H1;
+ sctx->hash[2] = MD5_H2;
+ sctx->hash[3] = MD5_H3;
sctx->byte_count = 0;
return 0;
diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild
index 4b87205c230c..050712e1ce41 100644
--- a/arch/powerpc/include/asm/Kbuild
+++ b/arch/powerpc/include/asm/Kbuild
@@ -6,6 +6,5 @@ generic-y += local64.h
generic-y += mcs_spinlock.h
generic-y += preempt.h
generic-y += rwsem.h
-generic-y += scatterlist.h
generic-y += trace_clock.h
generic-y += vtime.h
diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h
index a3bf5be111ff..51ccc7232042 100644
--- a/arch/powerpc/include/asm/barrier.h
+++ b/arch/powerpc/include/asm/barrier.h
@@ -34,7 +34,7 @@
#define rmb() __asm__ __volatile__ ("sync" : : : "memory")
#define wmb() __asm__ __volatile__ ("sync" : : : "memory")
-#define set_mb(var, value) do { var = value; mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); mb(); } while (0)
#ifdef __SUBARCH_HAS_LWSYNC
# define SMPWMB LWSYNC
@@ -89,5 +89,6 @@ do { \
#define smp_mb__before_atomic() smp_mb()
#define smp_mb__after_atomic() smp_mb()
+#define smp_mb__before_spinlock() smp_mb()
#endif /* _ASM_POWERPC_BARRIER_H */
diff --git a/arch/powerpc/include/asm/cmpxchg.h b/arch/powerpc/include/asm/cmpxchg.h
index d463c68fe7f0..ad6263cffb0f 100644
--- a/arch/powerpc/include/asm/cmpxchg.h
+++ b/arch/powerpc/include/asm/cmpxchg.h
@@ -144,7 +144,6 @@ __xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
* Compare and exchange - if *p == old, set it to new,
* and return the old value of *p.
*/
-#define __HAVE_ARCH_CMPXCHG 1
static __always_inline unsigned long
__cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 6367b8347dad..b118072670fb 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -242,11 +242,13 @@ enum {
/* We only set the TM feature if the kernel was compiled with TM supprt */
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-#define CPU_FTR_TM_COMP CPU_FTR_TM
-#define PPC_FEATURE2_HTM_COMP PPC_FEATURE2_HTM
+#define CPU_FTR_TM_COMP CPU_FTR_TM
+#define PPC_FEATURE2_HTM_COMP PPC_FEATURE2_HTM
+#define PPC_FEATURE2_HTM_NOSC_COMP PPC_FEATURE2_HTM_NOSC
#else
-#define CPU_FTR_TM_COMP 0
-#define PPC_FEATURE2_HTM_COMP 0
+#define CPU_FTR_TM_COMP 0
+#define PPC_FEATURE2_HTM_COMP 0
+#define PPC_FEATURE2_HTM_NOSC_COMP 0
#endif
/* We need to mark all pages as being coherent if we're SMP or we have a
@@ -366,7 +368,7 @@ enum {
CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | \
CPU_FTR_COMMON | CPU_FTR_FPU_UNAVAILABLE)
#define CPU_FTRS_CLASSIC32 (CPU_FTR_COMMON | CPU_FTR_USE_TB)
-#define CPU_FTRS_8XX (CPU_FTR_USE_TB)
+#define CPU_FTRS_8XX (CPU_FTR_USE_TB | CPU_FTR_NOEXECUTE)
#define CPU_FTRS_40X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
#define CPU_FTRS_44X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
#define CPU_FTRS_440x6 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE | \
diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h
index 5be6c4753667..ba42e46ea58e 100644
--- a/arch/powerpc/include/asm/cputhreads.h
+++ b/arch/powerpc/include/asm/cputhreads.h
@@ -31,9 +31,9 @@ extern cpumask_t threads_core_mask;
/* cpu_thread_mask_to_cores - Return a cpumask of one per cores
* hit by the argument
*
- * @threads: a cpumask of threads
+ * @threads: a cpumask of online threads
*
- * This function returns a cpumask which will have one "cpu" (or thread)
+ * This function returns a cpumask which will have one online cpu's
* bit set for each core that has at least one thread set in the argument.
*
* This can typically be used for things like IPI for tlb invalidations
@@ -42,13 +42,16 @@ extern cpumask_t threads_core_mask;
static inline cpumask_t cpu_thread_mask_to_cores(const struct cpumask *threads)
{
cpumask_t tmp, res;
- int i;
+ int i, cpu;
cpumask_clear(&res);
for (i = 0; i < NR_CPUS; i += threads_per_core) {
cpumask_shift_left(&tmp, &threads_core_mask, i);
- if (cpumask_intersects(threads, &tmp))
- cpumask_set_cpu(i, &res);
+ if (cpumask_intersects(threads, &tmp)) {
+ cpu = cpumask_next_and(-1, &tmp, cpu_online_mask);
+ if (cpu < nr_cpu_ids)
+ cpumask_set_cpu(cpu, &res);
+ }
}
return res;
}
diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h
index 9f1371bab5fc..e9bdda88f1fb 100644
--- a/arch/powerpc/include/asm/device.h
+++ b/arch/powerpc/include/asm/device.h
@@ -46,6 +46,9 @@ struct dev_archdata {
#ifdef CONFIG_FAIL_IOMMU
int fail_iommu;
#endif
+#ifdef CONFIG_CXL_BASE
+ struct cxl_context *cxl_ctx;
+#endif
};
struct pdev_archdata {
diff --git a/arch/powerpc/include/asm/edac.h b/arch/powerpc/include/asm/edac.h
index 6ead88bbfbb8..5571e23d253e 100644
--- a/arch/powerpc/include/asm/edac.h
+++ b/arch/powerpc/include/asm/edac.h
@@ -12,11 +12,11 @@
#define ASM_EDAC_H
/*
* ECC atomic, DMA, SMP and interrupt safe scrub function.
- * Implements the per arch atomic_scrub() that EDAC use for software
+ * Implements the per arch edac_atomic_scrub() that EDAC use for software
* ECC scrubbing. It reads memory and then writes back the original
* value, allowing the hardware to detect and correct memory errors.
*/
-static __inline__ void atomic_scrub(void *va, u32 size)
+static __inline__ void edac_atomic_scrub(void *va, u32 size)
{
unsigned int *virt_addr = va;
unsigned int temp;
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index a52db28ecc1e..c5eb86f3d452 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -27,6 +27,8 @@
#include <linux/time.h>
#include <linux/atomic.h>
+#include <uapi/asm/eeh.h>
+
struct pci_dev;
struct pci_bus;
struct pci_dn;
@@ -185,11 +187,6 @@ enum {
#define EEH_STATE_DMA_ACTIVE (1 << 4) /* Active DMA */
#define EEH_STATE_MMIO_ENABLED (1 << 5) /* MMIO enabled */
#define EEH_STATE_DMA_ENABLED (1 << 6) /* DMA enabled */
-#define EEH_PE_STATE_NORMAL 0 /* Normal state */
-#define EEH_PE_STATE_RESET 1 /* PE reset asserted */
-#define EEH_PE_STATE_STOPPED_IO_DMA 2 /* Frozen PE */
-#define EEH_PE_STATE_STOPPED_DMA 4 /* Stopped DMA, Enabled IO */
-#define EEH_PE_STATE_UNAVAIL 5 /* Unavailable */
#define EEH_RESET_DEACTIVATE 0 /* Deactivate the PE reset */
#define EEH_RESET_HOT 1 /* Hot reset */
#define EEH_RESET_FUNDAMENTAL 3 /* Fundamental reset */
@@ -294,6 +291,8 @@ int eeh_pe_set_option(struct eeh_pe *pe, int option);
int eeh_pe_get_state(struct eeh_pe *pe);
int eeh_pe_reset(struct eeh_pe *pe, int option);
int eeh_pe_configure(struct eeh_pe *pe);
+int eeh_pe_inject_err(struct eeh_pe *pe, int type, int func,
+ unsigned long addr, unsigned long mask);
/**
* EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h
index 1d53a65b4ec1..7eac89b9f02e 100644
--- a/arch/powerpc/include/asm/hugetlb.h
+++ b/arch/powerpc/include/asm/hugetlb.h
@@ -112,11 +112,6 @@ static inline int prepare_hugepage_range(struct file *file,
return 0;
}
-static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
-{
-}
-
-
static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte)
{
@@ -173,15 +168,6 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
return *ptep;
}
-static inline int arch_prepare_hugepage(struct page *page)
-{
- return 0;
-}
-
-static inline void arch_release_hugepage(struct page *page)
-{
-}
-
static inline void arch_clear_hugepage_flags(struct page *page)
{
}
diff --git a/arch/powerpc/include/asm/icswx.h b/arch/powerpc/include/asm/icswx.h
new file mode 100644
index 000000000000..9f8402b35115
--- /dev/null
+++ b/arch/powerpc/include/asm/icswx.h
@@ -0,0 +1,184 @@
+/*
+ * ICSWX api
+ *
+ * Copyright (C) 2015 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.
+ *
+ * This provides the Initiate Coprocessor Store Word Indexed (ICSWX)
+ * instruction. This instruction is used to communicate with PowerPC
+ * coprocessors. This also provides definitions of the structures used
+ * to communicate with the coprocessor.
+ *
+ * The RFC02130: Coprocessor Architecture document is the reference for
+ * everything in this file unless otherwise noted.
+ */
+#ifndef _ARCH_POWERPC_INCLUDE_ASM_ICSWX_H_
+#define _ARCH_POWERPC_INCLUDE_ASM_ICSWX_H_
+
+#include <asm/ppc-opcode.h> /* for PPC_ICSWX */
+
+/* Chapter 6.5.8 Coprocessor-Completion Block (CCB) */
+
+#define CCB_VALUE (0x3fffffffffffffff)
+#define CCB_ADDRESS (0xfffffffffffffff8)
+#define CCB_CM (0x0000000000000007)
+#define CCB_CM0 (0x0000000000000004)
+#define CCB_CM12 (0x0000000000000003)
+
+#define CCB_CM0_ALL_COMPLETIONS (0x0)
+#define CCB_CM0_LAST_IN_CHAIN (0x4)
+#define CCB_CM12_STORE (0x0)
+#define CCB_CM12_INTERRUPT (0x1)
+
+#define CCB_SIZE (0x10)
+#define CCB_ALIGN CCB_SIZE
+
+struct coprocessor_completion_block {
+ __be64 value;
+ __be64 address;
+} __packed __aligned(CCB_ALIGN);
+
+
+/* Chapter 6.5.7 Coprocessor-Status Block (CSB) */
+
+#define CSB_V (0x80)
+#define CSB_F (0x04)
+#define CSB_CH (0x03)
+#define CSB_CE_INCOMPLETE (0x80)
+#define CSB_CE_TERMINATION (0x40)
+#define CSB_CE_TPBC (0x20)
+
+#define CSB_CC_SUCCESS (0)
+#define CSB_CC_INVALID_ALIGN (1)
+#define CSB_CC_OPERAND_OVERLAP (2)
+#define CSB_CC_DATA_LENGTH (3)
+#define CSB_CC_TRANSLATION (5)
+#define CSB_CC_PROTECTION (6)
+#define CSB_CC_RD_EXTERNAL (7)
+#define CSB_CC_INVALID_OPERAND (8)
+#define CSB_CC_PRIVILEGE (9)
+#define CSB_CC_INTERNAL (10)
+#define CSB_CC_WR_EXTERNAL (12)
+#define CSB_CC_NOSPC (13)
+#define CSB_CC_EXCESSIVE_DDE (14)
+#define CSB_CC_WR_TRANSLATION (15)
+#define CSB_CC_WR_PROTECTION (16)
+#define CSB_CC_UNKNOWN_CODE (17)
+#define CSB_CC_ABORT (18)
+#define CSB_CC_TRANSPORT (20)
+#define CSB_CC_SEGMENTED_DDL (31)
+#define CSB_CC_PROGRESS_POINT (32)
+#define CSB_CC_DDE_OVERFLOW (33)
+#define CSB_CC_SESSION (34)
+#define CSB_CC_PROVISION (36)
+#define CSB_CC_CHAIN (37)
+#define CSB_CC_SEQUENCE (38)
+#define CSB_CC_HW (39)
+
+#define CSB_SIZE (0x10)
+#define CSB_ALIGN CSB_SIZE
+
+struct coprocessor_status_block {
+ u8 flags;
+ u8 cs;
+ u8 cc;
+ u8 ce;
+ __be32 count;
+ __be64 address;
+} __packed __aligned(CSB_ALIGN);
+
+
+/* Chapter 6.5.10 Data-Descriptor List (DDL)
+ * each list contains one or more Data-Descriptor Entries (DDE)
+ */
+
+#define DDE_P (0x8000)
+
+#define DDE_SIZE (0x10)
+#define DDE_ALIGN DDE_SIZE
+
+struct data_descriptor_entry {
+ __be16 flags;
+ u8 count;
+ u8 index;
+ __be32 length;
+ __be64 address;
+} __packed __aligned(DDE_ALIGN);
+
+
+/* Chapter 6.5.2 Coprocessor-Request Block (CRB) */
+
+#define CRB_SIZE (0x80)
+#define CRB_ALIGN (0x100) /* Errata: requires 256 alignment */
+
+/* Coprocessor Status Block field
+ * ADDRESS address of CSB
+ * C CCB is valid
+ * AT 0 = addrs are virtual, 1 = addrs are phys
+ * M enable perf monitor
+ */
+#define CRB_CSB_ADDRESS (0xfffffffffffffff0)
+#define CRB_CSB_C (0x0000000000000008)
+#define CRB_CSB_AT (0x0000000000000002)
+#define CRB_CSB_M (0x0000000000000001)
+
+struct coprocessor_request_block {
+ __be32 ccw;
+ __be32 flags;
+ __be64 csb_addr;
+
+ struct data_descriptor_entry source;
+ struct data_descriptor_entry target;
+
+ struct coprocessor_completion_block ccb;
+
+ u8 reserved[48];
+
+ struct coprocessor_status_block csb;
+} __packed __aligned(CRB_ALIGN);
+
+
+/* RFC02167 Initiate Coprocessor Instructions document
+ * Chapter 8.2.1.1.1 RS
+ * Chapter 8.2.3 Coprocessor Directive
+ * Chapter 8.2.4 Execution
+ *
+ * The CCW must be converted to BE before passing to icswx()
+ */
+
+#define CCW_PS (0xff000000)
+#define CCW_CT (0x00ff0000)
+#define CCW_CD (0x0000ffff)
+#define CCW_CL (0x0000c000)
+
+
+/* RFC02167 Initiate Coprocessor Instructions document
+ * Chapter 8.2.1 Initiate Coprocessor Store Word Indexed (ICSWX)
+ * Chapter 8.2.4.1 Condition Register 0
+ */
+
+#define ICSWX_INITIATED (0x8)
+#define ICSWX_BUSY (0x4)
+#define ICSWX_REJECTED (0x2)
+
+static inline int icswx(__be32 ccw, struct coprocessor_request_block *crb)
+{
+ __be64 ccw_reg = ccw;
+ u32 cr;
+
+ __asm__ __volatile__(
+ PPC_ICSWX(%1,0,%2) "\n"
+ "mfcr %0\n"
+ : "=r" (cr)
+ : "r" (ccw_reg), "r" (crb)
+ : "cr0", "memory");
+
+ return (int)((cr >> 28) & 0xf);
+}
+
+
+#endif /* _ARCH_POWERPC_INCLUDE_ASM_ICSWX_H_ */
diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index 1e27d6338565..ca18cff90900 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -44,6 +44,39 @@
extern int iommu_is_off;
extern int iommu_force_on;
+struct iommu_table_ops {
+ /*
+ * When called with direction==DMA_NONE, it is equal to clear().
+ * uaddr is a linear map address.
+ */
+ int (*set)(struct iommu_table *tbl,
+ long index, long npages,
+ unsigned long uaddr,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs);
+#ifdef CONFIG_IOMMU_API
+ /*
+ * Exchanges existing TCE with new TCE plus direction bits;
+ * returns old TCE and DMA direction mask.
+ * @tce is a physical address.
+ */
+ int (*exchange)(struct iommu_table *tbl,
+ long index,
+ unsigned long *hpa,
+ enum dma_data_direction *direction);
+#endif
+ void (*clear)(struct iommu_table *tbl,
+ long index, long npages);
+ /* get() returns a physical address */
+ unsigned long (*get)(struct iommu_table *tbl, long index);
+ void (*flush)(struct iommu_table *tbl);
+ void (*free)(struct iommu_table *tbl);
+};
+
+/* These are used by VIO */
+extern struct iommu_table_ops iommu_table_lpar_multi_ops;
+extern struct iommu_table_ops iommu_table_pseries_ops;
+
/*
* IOMAP_MAX_ORDER defines the largest contiguous block
* of dma space we can get. IOMAP_MAX_ORDER = 13
@@ -64,6 +97,9 @@ struct iommu_pool {
struct iommu_table {
unsigned long it_busno; /* Bus number this table belongs to */
unsigned long it_size; /* Size of iommu table in entries */
+ unsigned long it_indirect_levels;
+ unsigned long it_level_size;
+ unsigned long it_allocated_size;
unsigned long it_offset; /* Offset into global table */
unsigned long it_base; /* mapped address of tce table */
unsigned long it_index; /* which iommu table this is */
@@ -75,15 +111,16 @@ struct iommu_table {
struct iommu_pool pools[IOMMU_NR_POOLS];
unsigned long *it_map; /* A simple allocation bitmap for now */
unsigned long it_page_shift;/* table iommu page size */
-#ifdef CONFIG_IOMMU_API
- struct iommu_group *it_group;
-#endif
- void (*set_bypass)(struct iommu_table *tbl, bool enable);
-#ifdef CONFIG_PPC_POWERNV
- void *data;
-#endif
+ struct list_head it_group_list;/* List of iommu_table_group_link */
+ unsigned long *it_userspace; /* userspace view of the table */
+ struct iommu_table_ops *it_ops;
};
+#define IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry) \
+ ((tbl)->it_userspace ? \
+ &((tbl)->it_userspace[(entry) - (tbl)->it_offset]) : \
+ NULL)
+
/* Pure 2^n version of get_order */
static inline __attribute_const__
int get_iommu_order(unsigned long size, struct iommu_table *tbl)
@@ -112,14 +149,62 @@ extern void iommu_free_table(struct iommu_table *tbl, const char *node_name);
*/
extern struct iommu_table *iommu_init_table(struct iommu_table * tbl,
int nid);
+#define IOMMU_TABLE_GROUP_MAX_TABLES 2
+
+struct iommu_table_group;
+
+struct iommu_table_group_ops {
+ unsigned long (*get_table_size)(
+ __u32 page_shift,
+ __u64 window_size,
+ __u32 levels);
+ long (*create_table)(struct iommu_table_group *table_group,
+ int num,
+ __u32 page_shift,
+ __u64 window_size,
+ __u32 levels,
+ struct iommu_table **ptbl);
+ long (*set_window)(struct iommu_table_group *table_group,
+ int num,
+ struct iommu_table *tblnew);
+ long (*unset_window)(struct iommu_table_group *table_group,
+ int num);
+ /* Switch ownership from platform code to external user (e.g. VFIO) */
+ void (*take_ownership)(struct iommu_table_group *table_group);
+ /* Switch ownership from external user (e.g. VFIO) back to core */
+ void (*release_ownership)(struct iommu_table_group *table_group);
+};
+
+struct iommu_table_group_link {
+ struct list_head next;
+ struct rcu_head rcu;
+ struct iommu_table_group *table_group;
+};
+
+struct iommu_table_group {
+ /* IOMMU properties */
+ __u32 tce32_start;
+ __u32 tce32_size;
+ __u64 pgsizes; /* Bitmap of supported page sizes */
+ __u32 max_dynamic_windows_supported;
+ __u32 max_levels;
+
+ struct iommu_group *group;
+ struct iommu_table *tables[IOMMU_TABLE_GROUP_MAX_TABLES];
+ struct iommu_table_group_ops *ops;
+};
+
#ifdef CONFIG_IOMMU_API
-extern void iommu_register_group(struct iommu_table *tbl,
+
+extern void iommu_register_group(struct iommu_table_group *table_group,
int pci_domain_number, unsigned long pe_num);
extern int iommu_add_device(struct device *dev);
extern void iommu_del_device(struct device *dev);
extern int __init tce_iommu_bus_notifier_init(void);
+extern long iommu_tce_xchg(struct iommu_table *tbl, unsigned long entry,
+ unsigned long *hpa, enum dma_data_direction *direction);
#else
-static inline void iommu_register_group(struct iommu_table *tbl,
+static inline void iommu_register_group(struct iommu_table_group *table_group,
int pci_domain_number,
unsigned long pe_num)
{
@@ -140,13 +225,6 @@ static inline int __init tce_iommu_bus_notifier_init(void)
}
#endif /* !CONFIG_IOMMU_API */
-static inline void set_iommu_table_base_and_group(struct device *dev,
- void *base)
-{
- set_iommu_table_base(dev, base);
- iommu_add_device(dev);
-}
-
extern int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
struct scatterlist *sglist, int nelems,
unsigned long mask,
@@ -197,20 +275,13 @@ extern int iommu_tce_clear_param_check(struct iommu_table *tbl,
unsigned long npages);
extern int iommu_tce_put_param_check(struct iommu_table *tbl,
unsigned long ioba, unsigned long tce);
-extern int iommu_tce_build(struct iommu_table *tbl, unsigned long entry,
- unsigned long hwaddr, enum dma_data_direction direction);
-extern unsigned long iommu_clear_tce(struct iommu_table *tbl,
- unsigned long entry);
-extern int iommu_clear_tces_and_put_pages(struct iommu_table *tbl,
- unsigned long entry, unsigned long pages);
-extern int iommu_put_tce_user_mode(struct iommu_table *tbl,
- unsigned long entry, unsigned long tce);
extern void iommu_flush_tce(struct iommu_table *tbl);
extern int iommu_take_ownership(struct iommu_table *tbl);
extern void iommu_release_ownership(struct iommu_table *tbl);
extern enum dma_data_direction iommu_tce_direction(unsigned long tce);
+extern unsigned long iommu_direction_to_tce_perm(enum dma_data_direction dir);
#endif /* __KERNEL__ */
#endif /* _ASM_IOMMU_H */
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index 3536d12eb798..2aa79c864e91 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -430,7 +430,7 @@ static inline void note_hpte_modification(struct kvm *kvm,
*/
static inline struct kvm_memslots *kvm_memslots_raw(struct kvm *kvm)
{
- return rcu_dereference_raw_notrace(kvm->memslots);
+ return rcu_dereference_raw_notrace(kvm->memslots[0]);
}
extern void kvmppc_mmu_debugfs_init(struct kvm *kvm);
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index a193a13cf08b..d91f65b28e32 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -698,7 +698,7 @@ struct kvm_vcpu_arch {
static inline void kvm_arch_hardware_disable(void) {}
static inline void kvm_arch_hardware_unsetup(void) {}
static inline void kvm_arch_sync_events(struct kvm *kvm) {}
-static inline void kvm_arch_memslots_updated(struct kvm *kvm) {}
+static inline void kvm_arch_memslots_updated(struct kvm *kvm, struct kvm_memslots *slots) {}
static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {}
static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
static inline void kvm_arch_exit(void) {}
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index b8475daad884..c6ef05bd0765 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -182,10 +182,11 @@ extern int kvmppc_core_create_memslot(struct kvm *kvm,
unsigned long npages);
extern int kvmppc_core_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
- struct kvm_userspace_memory_region *mem);
+ const struct kvm_userspace_memory_region *mem);
extern void kvmppc_core_commit_memory_region(struct kvm *kvm,
- struct kvm_userspace_memory_region *mem,
- const struct kvm_memory_slot *old);
+ const struct kvm_userspace_memory_region *mem,
+ const struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new);
extern int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm,
struct kvm_ppc_smmu_info *info);
extern void kvmppc_core_flush_memslot(struct kvm *kvm,
@@ -243,10 +244,11 @@ struct kvmppc_ops {
void (*flush_memslot)(struct kvm *kvm, struct kvm_memory_slot *memslot);
int (*prepare_memory_region)(struct kvm *kvm,
struct kvm_memory_slot *memslot,
- struct kvm_userspace_memory_region *mem);
+ const struct kvm_userspace_memory_region *mem);
void (*commit_memory_region)(struct kvm *kvm,
- struct kvm_userspace_memory_region *mem,
- const struct kvm_memory_slot *old);
+ const struct kvm_userspace_memory_region *mem,
+ const struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new);
int (*unmap_hva)(struct kvm *kvm, unsigned long hva);
int (*unmap_hva_range)(struct kvm *kvm, unsigned long start,
unsigned long end);
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index ef8899432ae7..952579f5e79a 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -65,31 +65,6 @@ struct machdep_calls {
* destroyed as well */
void (*hpte_clear_all)(void);
- int (*tce_build)(struct iommu_table *tbl,
- long index,
- long npages,
- unsigned long uaddr,
- enum dma_data_direction direction,
- struct dma_attrs *attrs);
- void (*tce_free)(struct iommu_table *tbl,
- long index,
- long npages);
- unsigned long (*tce_get)(struct iommu_table *tbl,
- long index);
- void (*tce_flush)(struct iommu_table *tbl);
-
- /* _rm versions are for real mode use only */
- int (*tce_build_rm)(struct iommu_table *tbl,
- long index,
- long npages,
- unsigned long uaddr,
- enum dma_data_direction direction,
- struct dma_attrs *attrs);
- void (*tce_free_rm)(struct iommu_table *tbl,
- long index,
- long npages);
- void (*tce_flush_rm)(struct iommu_table *tbl);
-
void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size,
unsigned long flags, void *caller);
void (*iounmap)(volatile void __iomem *token);
@@ -131,12 +106,6 @@ struct machdep_calls {
/* To setup PHBs when using automatic OF platform driver for PCI */
int (*pci_setup_phb)(struct pci_controller *host);
-#ifdef CONFIG_PCI_MSI
- int (*setup_msi_irqs)(struct pci_dev *dev,
- int nvec, int type);
- void (*teardown_msi_irqs)(struct pci_dev *dev);
-#endif
-
void (*restart)(char *cmd);
void (*halt)(void);
void (*panic)(char *str);
diff --git a/arch/powerpc/include/asm/mm-arch-hooks.h b/arch/powerpc/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..f2a2da895897
--- /dev/null
+++ b/arch/powerpc/include/asm/mm-arch-hooks.h
@@ -0,0 +1,28 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_POWERPC_MM_ARCH_HOOKS_H
+#define _ASM_POWERPC_MM_ARCH_HOOKS_H
+
+static inline void arch_remap(struct mm_struct *mm,
+ unsigned long old_start, unsigned long old_end,
+ unsigned long new_start, unsigned long new_end)
+{
+ /*
+ * mremap() doesn't allow moving multiple vmas so we can limit the
+ * check to old_start == vdso_base.
+ */
+ if (old_start == mm->context.vdso_base)
+ mm->context.vdso_base = new_start;
+}
+#define arch_remap arch_remap
+
+#endif /* _ASM_POWERPC_MM_ARCH_HOOKS_H */
diff --git a/arch/powerpc/include/asm/mmu-8xx.h b/arch/powerpc/include/asm/mmu-8xx.h
index 986b9e1e1044..f05500a29a60 100644
--- a/arch/powerpc/include/asm/mmu-8xx.h
+++ b/arch/powerpc/include/asm/mmu-8xx.h
@@ -27,6 +27,19 @@
#define MI_Ks 0x80000000 /* Should not be set */
#define MI_Kp 0x40000000 /* Should always be set */
+/*
+ * All pages' PP exec bits are set to 000, which means Execute for Supervisor
+ * and no Execute for User.
+ * Then we use the APG to say whether accesses are according to Page rules,
+ * "all Supervisor" rules (Exec for all) and "all User" rules (Exec for noone)
+ * Therefore, we define 4 APG groups. msb is _PAGE_EXEC, lsb is _PAGE_USER
+ * 0 (00) => Not User, no exec => 11 (all accesses performed as user)
+ * 1 (01) => User but no exec => 11 (all accesses performed as user)
+ * 2 (10) => Not User, exec => 01 (rights according to page definition)
+ * 3 (11) => User, exec => 00 (all accesses performed as supervisor)
+ */
+#define MI_APG_INIT 0xf4ffffff
+
/* The effective page number register. When read, contains the information
* about the last instruction TLB miss. When MI_RPN is written, bits in
* this register are used to create the TLB entry.
@@ -87,6 +100,19 @@
#define MD_Ks 0x80000000 /* Should not be set */
#define MD_Kp 0x40000000 /* Should always be set */
+/*
+ * All pages' PP data bits are set to either 000 or 011, which means
+ * respectively RW for Supervisor and no access for User, or RO for
+ * Supervisor and no access for user.
+ * Then we use the APG to say whether accesses are according to Page rules or
+ * "all Supervisor" rules (Access to all)
+ * Therefore, we define 2 APG groups. lsb is _PAGE_USER
+ * 0 => No user => 01 (all accesses performed according to page definition)
+ * 1 => User => 00 (all accesses performed as supervisor
+ * according to page definition)
+ */
+#define MD_APG_INIT 0x4fffffff
+
/* The effective page number register. When read, contains the information
* about the last instruction TLB miss. When MD_RPN is written, bits in
* this register are used to create the TLB entry.
@@ -145,7 +171,14 @@ typedef struct {
} mm_context_t;
#endif /* !__ASSEMBLY__ */
+#if (PAGE_SHIFT == 12)
#define mmu_virtual_psize MMU_PAGE_4K
+#elif (PAGE_SHIFT == 14)
+#define mmu_virtual_psize MMU_PAGE_16K
+#else
+#error "Unsupported PAGE_SIZE"
+#endif
+
#define mmu_linear_psize MMU_PAGE_8M
#endif /* _ASM_POWERPC_MMU_8XX_H_ */
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
index 1da6a81ce541..a82f5347540a 100644
--- a/arch/powerpc/include/asm/mmu-hash64.h
+++ b/arch/powerpc/include/asm/mmu-hash64.h
@@ -536,6 +536,9 @@ typedef struct {
/* for 4K PTE fragment support */
void *pte_frag;
#endif
+#ifdef CONFIG_SPAPR_TCE_IOMMU
+ struct list_head iommu_group_mem_list;
+#endif
} mm_context_t;
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h
index 73382eba02dc..878c27771717 100644
--- a/arch/powerpc/include/asm/mmu_context.h
+++ b/arch/powerpc/include/asm/mmu_context.h
@@ -8,7 +8,6 @@
#include <linux/spinlock.h>
#include <asm/mmu.h>
#include <asm/cputable.h>
-#include <asm-generic/mm_hooks.h>
#include <asm/cputhreads.h>
/*
@@ -16,6 +15,24 @@
*/
extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
extern void destroy_context(struct mm_struct *mm);
+#ifdef CONFIG_SPAPR_TCE_IOMMU
+struct mm_iommu_table_group_mem_t;
+
+extern bool mm_iommu_preregistered(void);
+extern long mm_iommu_get(unsigned long ua, unsigned long entries,
+ struct mm_iommu_table_group_mem_t **pmem);
+extern long mm_iommu_put(struct mm_iommu_table_group_mem_t *mem);
+extern void mm_iommu_init(mm_context_t *ctx);
+extern void mm_iommu_cleanup(mm_context_t *ctx);
+extern struct mm_iommu_table_group_mem_t *mm_iommu_lookup(unsigned long ua,
+ unsigned long size);
+extern struct mm_iommu_table_group_mem_t *mm_iommu_find(unsigned long ua,
+ unsigned long entries);
+extern long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem,
+ unsigned long ua, unsigned long *hpa);
+extern long mm_iommu_mapped_inc(struct mm_iommu_table_group_mem_t *mem);
+extern void mm_iommu_mapped_dec(struct mm_iommu_table_group_mem_t *mem);
+#endif
extern void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next);
extern void switch_slb(struct task_struct *tsk, struct mm_struct *mm);
@@ -109,5 +126,27 @@ static inline void enter_lazy_tlb(struct mm_struct *mm,
#endif
}
+static inline void arch_dup_mmap(struct mm_struct *oldmm,
+ struct mm_struct *mm)
+{
+}
+
+static inline void arch_exit_mmap(struct mm_struct *mm)
+{
+}
+
+static inline void arch_unmap(struct mm_struct *mm,
+ struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ if (start <= mm->context.vdso_base && mm->context.vdso_base < end)
+ mm->context.vdso_base = 0;
+}
+
+static inline void arch_bprm_mm_init(struct mm_struct *mm,
+ struct vm_area_struct *vma)
+{
+}
+
#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_MMU_CONTEXT_H */
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 0321a909e663..e9e4c52f3685 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -153,7 +153,8 @@
#define OPAL_FLASH_READ 110
#define OPAL_FLASH_WRITE 111
#define OPAL_FLASH_ERASE 112
-#define OPAL_LAST 112
+#define OPAL_PRD_MSG 113
+#define OPAL_LAST 113
/* Device tree flags */
@@ -165,6 +166,13 @@
#define OPAL_PM_WINKLE_ENABLED 0x00040000
#define OPAL_PM_SLEEP_ENABLED_ER1 0x00080000 /* with workaround */
+/*
+ * OPAL_CONFIG_CPU_IDLE_STATE parameters
+ */
+#define OPAL_CONFIG_IDLE_FASTSLEEP 1
+#define OPAL_CONFIG_IDLE_UNDO 0
+#define OPAL_CONFIG_IDLE_APPLY 1
+
#ifndef __ASSEMBLY__
/* Other enums */
@@ -352,6 +360,7 @@ enum opal_msg_type {
OPAL_MSG_SHUTDOWN, /* params[0] = 1 reboot, 0 shutdown */
OPAL_MSG_HMI_EVT,
OPAL_MSG_DPO,
+ OPAL_MSG_PRD,
OPAL_MSG_TYPE_MAX,
};
@@ -674,6 +683,23 @@ typedef struct oppanel_line {
__be64 line_len;
} oppanel_line_t;
+enum opal_prd_msg_type {
+ OPAL_PRD_MSG_TYPE_INIT = 0, /* HBRT --> OPAL */
+ OPAL_PRD_MSG_TYPE_FINI, /* HBRT/kernel --> OPAL */
+ OPAL_PRD_MSG_TYPE_ATTN, /* HBRT <-- OPAL */
+ OPAL_PRD_MSG_TYPE_ATTN_ACK, /* HBRT --> OPAL */
+ OPAL_PRD_MSG_TYPE_OCC_ERROR, /* HBRT <-- OPAL */
+ OPAL_PRD_MSG_TYPE_OCC_RESET, /* HBRT <-- OPAL */
+};
+
+struct opal_prd_msg_header {
+ uint8_t type;
+ uint8_t pad[1];
+ __be16 size;
+};
+
+struct opal_prd_msg;
+
/*
* SG entries
*
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 042af1abfc4d..958e941c0cda 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -186,6 +186,7 @@ int64_t opal_handle_hmi(void);
int64_t opal_register_dump_region(uint32_t id, uint64_t start, uint64_t end);
int64_t opal_unregister_dump_region(uint32_t id);
int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val);
+int64_t opal_config_cpu_idle_state(uint64_t state, uint64_t flag);
int64_t opal_pci_set_phb_cxl_mode(uint64_t phb_id, uint64_t mode, uint64_t pe_number);
int64_t opal_ipmi_send(uint64_t interface, struct opal_ipmi_msg *msg,
uint64_t msg_len);
@@ -193,6 +194,7 @@ int64_t opal_ipmi_recv(uint64_t interface, struct opal_ipmi_msg *msg,
uint64_t *msg_len);
int64_t opal_i2c_request(uint64_t async_token, uint32_t bus_id,
struct opal_i2c_request *oreq);
+int64_t opal_prd_msg(struct opal_prd_msg *msg);
int64_t opal_flash_read(uint64_t id, uint64_t offset, uint64_t buf,
uint64_t size, uint64_t token);
@@ -239,6 +241,10 @@ extern int opal_elog_init(void);
extern void opal_platform_dump_init(void);
extern void opal_sys_param_init(void);
extern void opal_msglog_init(void);
+extern int opal_async_comp_init(void);
+extern int opal_sensor_init(void);
+extern int opal_hmi_handler_init(void);
+extern int opal_event_init(void);
extern int opal_machine_check(struct pt_regs *regs);
extern bool opal_mce_check_early_recovery(struct pt_regs *regs);
@@ -250,6 +256,8 @@ extern int opal_resync_timebase(void);
extern void opal_lpc_init(void);
+extern int opal_event_request(unsigned int opal_event_nr);
+
struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
unsigned long vmalloc_size);
void opal_free_sg_list(struct opal_sg_list *sg);
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index 69c059887a2c..71294a6e976e 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -278,9 +278,7 @@ extern long long virt_phys_offset;
#ifndef __ASSEMBLY__
-#undef STRICT_MM_TYPECHECKS
-
-#ifdef STRICT_MM_TYPECHECKS
+#ifdef CONFIG_STRICT_MM_TYPECHECKS
/* These are used to make use of C type-checking. */
/* PTE level */
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 1811c44bf34b..712add590445 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -27,9 +27,23 @@ struct pci_controller_ops {
* allow assignment/enabling of the device. */
bool (*enable_device_hook)(struct pci_dev *);
+ void (*disable_device)(struct pci_dev *);
+
+ void (*release_device)(struct pci_dev *);
+
/* Called during PCI resource reassignment */
resource_size_t (*window_alignment)(struct pci_bus *, unsigned long type);
void (*reset_secondary_bus)(struct pci_dev *dev);
+
+#ifdef CONFIG_PCI_MSI
+ int (*setup_msi_irqs)(struct pci_dev *dev,
+ int nvec, int type);
+ void (*teardown_msi_irqs)(struct pci_dev *dev);
+#endif
+
+ int (*dma_set_mask)(struct pci_dev *dev, u64 dma_mask);
+
+ void (*shutdown)(struct pci_controller *);
};
/*
@@ -185,7 +199,7 @@ struct pci_dn {
struct pci_dn *parent;
struct pci_controller *phb; /* for pci devices */
- struct iommu_table *iommu_table; /* for phb's or bridges */
+ struct iommu_table_group *table_group; /* for phb's or bridges */
struct device_node *node; /* back-pointer to the device_node */
int pci_ext_config_space; /* for pci devices */
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 4aef8d660999..3453bd8dc18f 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -13,9 +13,9 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
#include <asm/machdep.h>
-#include <asm/scatterlist.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
@@ -71,36 +71,6 @@ extern struct dma_map_ops *get_pci_dma_ops(void);
*/
#define PCI_DISABLE_MWI
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- unsigned long cacheline_size;
- u8 byte;
-
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
- if (byte == 0)
- cacheline_size = 1024;
- else
- cacheline_size = (int) byte * 4;
-
- *strat = PCI_DMA_BURST_MULTIPLE;
- *strategy_parameter = cacheline_size;
-}
-#endif
-
-#else /* 32-bit */
-
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- *strat = PCI_DMA_BURST_INFINITY;
- *strategy_parameter = ~0UL;
-}
-#endif
#endif /* CONFIG_PPC64 */
extern int pci_domain_nr(struct pci_bus *bus);
diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h
index 64b52b1cf542..9c326565d498 100644
--- a/arch/powerpc/include/asm/pgtable-ppc32.h
+++ b/arch/powerpc/include/asm/pgtable-ppc32.h
@@ -170,24 +170,6 @@ static inline unsigned long pte_update(pte_t *p,
#ifdef PTE_ATOMIC_UPDATES
unsigned long old, tmp;
-#ifdef CONFIG_PPC_8xx
- unsigned long tmp2;
-
- __asm__ __volatile__("\
-1: lwarx %0,0,%4\n\
- andc %1,%0,%5\n\
- or %1,%1,%6\n\
- /* 0x200 == Extended encoding, bit 22 */ \
- /* Bit 22 has to be 1 when _PAGE_USER is unset and _PAGE_RO is set */ \
- rlwimi %1,%1,32-1,0x200\n /* get _PAGE_RO */ \
- rlwinm %3,%1,32-2,0x200\n /* get _PAGE_USER */ \
- andc %1,%1,%3\n\
- stwcx. %1,0,%4\n\
- bne- 1b"
- : "=&r" (old), "=&r" (tmp), "=m" (*p), "=&r" (tmp2)
- : "r" (p), "r" (clr), "r" (set), "m" (*p)
- : "cc" );
-#else /* CONFIG_PPC_8xx */
__asm__ __volatile__("\
1: lwarx %0,0,%3\n\
andc %1,%0,%4\n\
@@ -198,7 +180,6 @@ static inline unsigned long pte_update(pte_t *p,
: "=&r" (old), "=&r" (tmp), "=m" (*p)
: "r" (p), "r" (clr), "r" (set), "m" (*p)
: "cc" );
-#endif /* CONFIG_PPC_8xx */
#else /* PTE_ATOMIC_UPDATES */
unsigned long old = pte_val(*p);
*p = __pte((old & ~clr) | set);
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index 43e6ad424c7f..3bb7488bd24b 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -118,7 +118,7 @@
*/
#ifndef __real_pte
-#ifdef STRICT_MM_TYPECHECKS
+#ifdef CONFIG_STRICT_MM_TYPECHECKS
#define __real_pte(e,p) ((real_pte_t){(e)})
#define __rpte_to_pte(r) ((r).pte)
#else
@@ -347,11 +347,27 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
pr_err("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
/* Encode and de-code a swap entry */
-#define __swp_type(entry) (((entry).val >> 1) & 0x3f)
-#define __swp_offset(entry) ((entry).val >> 8)
-#define __swp_entry(type, offset) ((swp_entry_t){((type)<< 1)|((offset)<<8)})
-#define __pte_to_swp_entry(pte) ((swp_entry_t){pte_val(pte) >> PTE_RPN_SHIFT})
-#define __swp_entry_to_pte(x) ((pte_t) { (x).val << PTE_RPN_SHIFT })
+#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)); \
+ } 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) })
+
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val((pte)) })
+#define __swp_entry_to_pte(x) __pte((x).val)
void pgtable_cache_add(unsigned shift, void (*ctor)(void *));
void pgtable_cache_init(void);
@@ -553,13 +569,9 @@ extern int pmdp_test_and_clear_young(struct vm_area_struct *vma,
extern int pmdp_clear_flush_young(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmdp);
-#define __HAVE_ARCH_PMDP_GET_AND_CLEAR
-extern pmd_t pmdp_get_and_clear(struct mm_struct *mm,
- unsigned long addr, pmd_t *pmdp);
-
-#define __HAVE_ARCH_PMDP_CLEAR_FLUSH
-extern pmd_t pmdp_clear_flush(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,
@@ -576,6 +588,10 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr,
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);
diff --git a/arch/powerpc/include/asm/pnv-pci.h b/arch/powerpc/include/asm/pnv-pci.h
index f9b498292a5c..6f77f71ee964 100644
--- a/arch/powerpc/include/asm/pnv-pci.h
+++ b/arch/powerpc/include/asm/pnv-pci.h
@@ -11,7 +11,7 @@
#define _ASM_PNV_PCI_H
#include <linux/pci.h>
-#include <misc/cxl.h>
+#include <misc/cxl-base.h>
int pnv_phb_to_cxl_mode(struct pci_dev *dev, uint64_t mode);
int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq,
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 5c93f691b495..8452335661a5 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -136,6 +136,8 @@
#define PPC_INST_DCBAL 0x7c2005ec
#define PPC_INST_DCBZL 0x7c2007ec
#define PPC_INST_ICBT 0x7c00002c
+#define PPC_INST_ICSWX 0x7c00032d
+#define PPC_INST_ICSWEPX 0x7c00076d
#define PPC_INST_ISEL 0x7c00001e
#define PPC_INST_ISEL_MASK 0xfc00003e
#define PPC_INST_LDARX 0x7c0000a8
@@ -403,4 +405,15 @@
#define MFTMR(tmr, r) stringify_in_c(.long PPC_INST_MFTMR | \
TMRN(tmr) | ___PPC_RT(r))
+/* Coprocessor instructions */
+#define PPC_ICSWX(s, a, b) stringify_in_c(.long PPC_INST_ICSWX | \
+ ___PPC_RS(s) | \
+ ___PPC_RA(a) | \
+ ___PPC_RB(b))
+#define PPC_ICSWEPX(s, a, b) stringify_in_c(.long PPC_INST_ICSWEPX | \
+ ___PPC_RS(s) | \
+ ___PPC_RA(a) | \
+ ___PPC_RB(b))
+
+
#endif /* _ASM_POWERPC_PPC_OPCODE_H */
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index bf117d8fb45f..28ded5d9b579 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -295,6 +295,15 @@ struct thread_struct {
#endif
#ifdef CONFIG_PPC64
unsigned long dscr;
+ /*
+ * This member element dscr_inherit indicates that the process
+ * has explicitly attempted and changed the DSCR register value
+ * for itself. Hence kernel wont use the default CPU DSCR value
+ * contained in the PACA structure anymore during process context
+ * switch. Once this variable is set, this behaviour will also be
+ * inherited to all the children of this process from that point
+ * onwards.
+ */
int dscr_inherit;
unsigned long ppr; /* used to save/restore SMT priority */
#endif
diff --git a/arch/powerpc/include/asm/pte-8xx.h b/arch/powerpc/include/asm/pte-8xx.h
index 97bae64afdaa..a0e2ba960976 100644
--- a/arch/powerpc/include/asm/pte-8xx.h
+++ b/arch/powerpc/include/asm/pte-8xx.h
@@ -34,35 +34,32 @@
#define _PAGE_SPECIAL 0x0008 /* SW entry, forced to 0 by the TLB miss */
#define _PAGE_DIRTY 0x0100 /* C: page changed */
-/* These 4 software bits must be masked out when the entry is loaded
- * into the TLB, 1 SW bit left(0x0080).
+/* These 4 software bits must be masked out when the L2 entry is loaded
+ * into the TLB.
*/
-#define _PAGE_GUARDED 0x0010 /* software: guarded access */
-#define _PAGE_ACCESSED 0x0020 /* software: page referenced */
-#define _PAGE_WRITETHRU 0x0040 /* software: caching is write through */
+#define _PAGE_GUARDED 0x0010 /* Copied to L1 G entry in DTLB */
+#define _PAGE_USER 0x0020 /* Copied to L1 APG lsb */
+#define _PAGE_EXEC 0x0040 /* Copied to L1 APG */
+#define _PAGE_WRITETHRU 0x0080 /* software: caching is write through */
+#define _PAGE_ACCESSED 0x0800 /* software: page referenced */
-/* Setting any bits in the nibble with the follow two controls will
- * require a TLB exception handler change. It is assumed unused bits
- * are always zero.
- */
-#define _PAGE_RO 0x0400 /* lsb PP bits */
-#define _PAGE_USER 0x0800 /* msb PP bits */
-/* set when _PAGE_USER is unset and _PAGE_RO is set */
-#define _PAGE_KNLRO 0x0200
+#define _PAGE_RO 0x0600 /* Supervisor RO, User no access */
#define _PMD_PRESENT 0x0001
#define _PMD_BAD 0x0ff0
#define _PMD_PAGE_MASK 0x000c
#define _PMD_PAGE_8M 0x000c
-#define _PTE_NONE_MASK _PAGE_KNLRO
-
/* Until my rework is finished, 8xx still needs atomic PTE updates */
#define PTE_ATOMIC_UPDATES 1
/* We need to add _PAGE_SHARED to kernel pages */
-#define _PAGE_KERNEL_RO (_PAGE_SHARED | _PAGE_RO | _PAGE_KNLRO)
-#define _PAGE_KERNEL_ROX (_PAGE_EXEC | _PAGE_RO | _PAGE_KNLRO)
+#define _PAGE_KERNEL_RO (_PAGE_SHARED | _PAGE_RO)
+#define _PAGE_KERNEL_ROX (_PAGE_SHARED | _PAGE_RO | _PAGE_EXEC)
+#define _PAGE_KERNEL_RW (_PAGE_SHARED | _PAGE_DIRTY | _PAGE_RW | \
+ _PAGE_HWWRITE)
+#define _PAGE_KERNEL_RWX (_PAGE_SHARED | _PAGE_DIRTY | _PAGE_RW | \
+ _PAGE_HWWRITE | _PAGE_EXEC)
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PTE_8xx_H */
diff --git a/arch/powerpc/include/asm/pte-book3e.h b/arch/powerpc/include/asm/pte-book3e.h
index 91a704952ca1..8d8473278d91 100644
--- a/arch/powerpc/include/asm/pte-book3e.h
+++ b/arch/powerpc/include/asm/pte-book3e.h
@@ -11,6 +11,7 @@
/* Architected bits */
#define _PAGE_PRESENT 0x000001 /* software: pte contains a translation */
#define _PAGE_SW1 0x000002
+#define _PAGE_BIT_SWAP_TYPE 2
#define _PAGE_BAP_SR 0x000004
#define _PAGE_BAP_UR 0x000008
#define _PAGE_BAP_SW 0x000010
diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h
index c5a755ef7011..b7c8d079c121 100644
--- a/arch/powerpc/include/asm/pte-common.h
+++ b/arch/powerpc/include/asm/pte-common.h
@@ -85,10 +85,8 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
* 64-bit PTEs
*/
#if defined(CONFIG_PPC32) && defined(CONFIG_PTE_64BIT)
-#define PTE_RPN_MAX (1ULL << (64 - PTE_RPN_SHIFT))
#define PTE_RPN_MASK (~((1ULL<<PTE_RPN_SHIFT)-1))
#else
-#define PTE_RPN_MAX (1UL << (32 - PTE_RPN_SHIFT))
#define PTE_RPN_MASK (~((1UL<<PTE_RPN_SHIFT)-1))
#endif
diff --git a/arch/powerpc/include/asm/pte-hash64.h b/arch/powerpc/include/asm/pte-hash64.h
index fc852f7e7b3a..ef612c160da7 100644
--- a/arch/powerpc/include/asm/pte-hash64.h
+++ b/arch/powerpc/include/asm/pte-hash64.h
@@ -16,6 +16,7 @@
*/
#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 */
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h
index f1863a138b4a..71f2b3f02cf8 100644
--- a/arch/powerpc/include/asm/systbl.h
+++ b/arch/powerpc/include/asm/systbl.h
@@ -358,7 +358,7 @@ SYSCALL_SPU(setns)
COMPAT_SYS(process_vm_readv)
COMPAT_SYS(process_vm_writev)
SYSCALL(finit_module)
-SYSCALL(ni_syscall) /* sys_kcmp */
+SYSCALL(kcmp) /* sys_kcmp */
SYSCALL_SPU(sched_setattr)
SYSCALL_SPU(sched_getattr)
SYSCALL_SPU(renameat2)
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index 5f1048eaa5b6..8b3b46b7b0f2 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -87,7 +87,7 @@ static inline int prrn_is_enabled(void)
#include <asm/smp.h>
#define topology_physical_package_id(cpu) (cpu_to_chip_id(cpu))
-#define topology_thread_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu))
+#define topology_sibling_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu))
#define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu))
#define topology_core_id(cpu) (cpu_to_core_id(cpu))
#endif
diff --git a/arch/powerpc/include/asm/trace.h b/arch/powerpc/include/asm/trace.h
index c15da6073cb8..8e86b48d0369 100644
--- a/arch/powerpc/include/asm/trace.h
+++ b/arch/powerpc/include/asm/trace.h
@@ -144,6 +144,26 @@ TRACE_EVENT_FN(opal_exit,
);
#endif
+TRACE_EVENT(hash_fault,
+
+ TP_PROTO(unsigned long addr, unsigned long access, unsigned long trap),
+ TP_ARGS(addr, access, trap),
+ TP_STRUCT__entry(
+ __field(unsigned long, addr)
+ __field(unsigned long, access)
+ __field(unsigned long, trap)
+ ),
+
+ TP_fast_assign(
+ __entry->addr = addr;
+ __entry->access = access;
+ __entry->trap = trap;
+ ),
+
+ TP_printk("hash fault with addr 0x%lx and access = 0x%lx trap = 0x%lx",
+ __entry->addr, __entry->access, __entry->trap)
+);
+
#endif /* _TRACE_POWERPC_H */
#undef TRACE_INCLUDE_PATH
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index a0c071d24e0e..2a8ebae0936b 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -265,7 +265,7 @@ do { \
({ \
long __gu_err; \
unsigned long __gu_val; \
- const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
+ __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
__chk_user_ptr(ptr); \
if (!is_kernel_addr((unsigned long)__gu_addr)) \
might_fault(); \
@@ -279,7 +279,7 @@ do { \
({ \
long __gu_err; \
long long __gu_val; \
- const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
+ __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
__chk_user_ptr(ptr); \
if (!is_kernel_addr((unsigned long)__gu_addr)) \
might_fault(); \
@@ -293,7 +293,7 @@ do { \
({ \
long __gu_err = -EFAULT; \
unsigned long __gu_val = 0; \
- const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
+ __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
might_fault(); \
if (access_ok(VERIFY_READ, __gu_addr, (size))) \
__get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
@@ -305,7 +305,7 @@ do { \
({ \
long __gu_err; \
unsigned long __gu_val; \
- const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
+ __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
__chk_user_ptr(ptr); \
__get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
(x) = (__force __typeof__(*(ptr)))__gu_val; \
diff --git a/arch/powerpc/include/asm/vio.h b/arch/powerpc/include/asm/vio.h
index 4f9b7ca0710f..84286ec77b12 100644
--- a/arch/powerpc/include/asm/vio.h
+++ b/arch/powerpc/include/asm/vio.h
@@ -19,9 +19,9 @@
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/mod_devicetable.h>
+#include <linux/scatterlist.h>
#include <asm/hvcall.h>
-#include <asm/scatterlist.h>
/*
* Architecture-specific constants for drivers to
diff --git a/arch/powerpc/include/uapi/asm/Kbuild b/arch/powerpc/include/uapi/asm/Kbuild
index 79c4068be278..f44a027818af 100644
--- a/arch/powerpc/include/uapi/asm/Kbuild
+++ b/arch/powerpc/include/uapi/asm/Kbuild
@@ -18,6 +18,7 @@ header-y += kvm_para.h
header-y += mman.h
header-y += msgbuf.h
header-y += nvram.h
+header-y += opal-prd.h
header-y += param.h
header-y += perf_event.h
header-y += poll.h
diff --git a/arch/powerpc/include/uapi/asm/cputable.h b/arch/powerpc/include/uapi/asm/cputable.h
index de2c0e4ee1aa..43686043e297 100644
--- a/arch/powerpc/include/uapi/asm/cputable.h
+++ b/arch/powerpc/include/uapi/asm/cputable.h
@@ -42,5 +42,6 @@
#define PPC_FEATURE2_ISEL 0x08000000
#define PPC_FEATURE2_TAR 0x04000000
#define PPC_FEATURE2_VEC_CRYPTO 0x02000000
+#define PPC_FEATURE2_HTM_NOSC 0x01000000
#endif /* _UAPI__ASM_POWERPC_CPUTABLE_H */
diff --git a/arch/powerpc/include/uapi/asm/eeh.h b/arch/powerpc/include/uapi/asm/eeh.h
new file mode 100644
index 000000000000..291b7d1814a6
--- /dev/null
+++ b/arch/powerpc/include/uapi/asm/eeh.h
@@ -0,0 +1,56 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2015
+ *
+ * Authors: Gavin Shan <gwshan@linux.vnet.ibm.com>
+ */
+
+#ifndef _ASM_POWERPC_EEH_H
+#define _ASM_POWERPC_EEH_H
+
+/* PE states */
+#define EEH_PE_STATE_NORMAL 0 /* Normal state */
+#define EEH_PE_STATE_RESET 1 /* PE reset asserted */
+#define EEH_PE_STATE_STOPPED_IO_DMA 2 /* Frozen PE */
+#define EEH_PE_STATE_STOPPED_DMA 4 /* Stopped DMA only */
+#define EEH_PE_STATE_UNAVAIL 5 /* Unavailable */
+
+/* EEH error types and functions */
+#define EEH_ERR_TYPE_32 0 /* 32-bits error */
+#define EEH_ERR_TYPE_64 1 /* 64-bits error */
+#define EEH_ERR_FUNC_MIN 0
+#define EEH_ERR_FUNC_LD_MEM_ADDR 0 /* Memory load */
+#define EEH_ERR_FUNC_LD_MEM_DATA 1
+#define EEH_ERR_FUNC_LD_IO_ADDR 2 /* IO load */
+#define EEH_ERR_FUNC_LD_IO_DATA 3
+#define EEH_ERR_FUNC_LD_CFG_ADDR 4 /* Config load */
+#define EEH_ERR_FUNC_LD_CFG_DATA 5
+#define EEH_ERR_FUNC_ST_MEM_ADDR 6 /* Memory store */
+#define EEH_ERR_FUNC_ST_MEM_DATA 7
+#define EEH_ERR_FUNC_ST_IO_ADDR 8 /* IO store */
+#define EEH_ERR_FUNC_ST_IO_DATA 9
+#define EEH_ERR_FUNC_ST_CFG_ADDR 10 /* Config store */
+#define EEH_ERR_FUNC_ST_CFG_DATA 11
+#define EEH_ERR_FUNC_DMA_RD_ADDR 12 /* DMA read */
+#define EEH_ERR_FUNC_DMA_RD_DATA 13
+#define EEH_ERR_FUNC_DMA_RD_MASTER 14
+#define EEH_ERR_FUNC_DMA_RD_TARGET 15
+#define EEH_ERR_FUNC_DMA_WR_ADDR 16 /* DMA write */
+#define EEH_ERR_FUNC_DMA_WR_DATA 17
+#define EEH_ERR_FUNC_DMA_WR_MASTER 18
+#define EEH_ERR_FUNC_DMA_WR_TARGET 19
+#define EEH_ERR_FUNC_MAX 19
+
+#endif /* _ASM_POWERPC_EEH_H */
diff --git a/arch/powerpc/include/uapi/asm/opal-prd.h b/arch/powerpc/include/uapi/asm/opal-prd.h
new file mode 100644
index 000000000000..319ff4a26158
--- /dev/null
+++ b/arch/powerpc/include/uapi/asm/opal-prd.h
@@ -0,0 +1,58 @@
+/*
+ * OPAL Runtime Diagnostics interface driver
+ * Supported on POWERNV platform
+ *
+ * (C) Copyright IBM 2015
+ *
+ * Author: Vaidyanathan Srinivasan <svaidy at linux.vnet.ibm.com>
+ * Author: Jeremy Kerr <jk@ozlabs.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, 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 _UAPI_ASM_POWERPC_OPAL_PRD_H_
+#define _UAPI_ASM_POWERPC_OPAL_PRD_H_
+
+#include <linux/types.h>
+
+/**
+ * The version of the kernel interface of the PRD system. This describes the
+ * interface available for the /dev/opal-prd device. The actual PRD message
+ * layout and content is private to the firmware <--> userspace interface, so
+ * is not covered by this versioning.
+ *
+ * Future interface versions are backwards-compatible; if a later kernel
+ * version is encountered, functionality provided in earlier versions
+ * will work.
+ */
+#define OPAL_PRD_KERNEL_VERSION 1
+
+#define OPAL_PRD_GET_INFO _IOR('o', 0x01, struct opal_prd_info)
+#define OPAL_PRD_SCOM_READ _IOR('o', 0x02, struct opal_prd_scom)
+#define OPAL_PRD_SCOM_WRITE _IOW('o', 0x03, struct opal_prd_scom)
+
+#ifndef __ASSEMBLY__
+
+struct opal_prd_info {
+ __u64 version;
+ __u64 reserved[3];
+};
+
+struct opal_prd_scom {
+ __u64 chip;
+ __u64 addr;
+ __u64 data;
+ __s64 rc;
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _UAPI_ASM_POWERPC_OPAL_PRD_H */
diff --git a/arch/powerpc/include/uapi/asm/tm.h b/arch/powerpc/include/uapi/asm/tm.h
index 5d836b7c1176..5047659815a5 100644
--- a/arch/powerpc/include/uapi/asm/tm.h
+++ b/arch/powerpc/include/uapi/asm/tm.h
@@ -11,7 +11,7 @@
#define TM_CAUSE_RESCHED 0xde
#define TM_CAUSE_TLBI 0xdc
#define TM_CAUSE_FAC_UNAV 0xda
-#define TM_CAUSE_SYSCALL 0xd8 /* future use */
+#define TM_CAUSE_SYSCALL 0xd8
#define TM_CAUSE_MISC 0xd6 /* future use */
#define TM_CAUSE_SIGNAL 0xd4
#define TM_CAUSE_ALIGNMENT 0xd2
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index c1ebbdaac28f..87c7d1473488 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -33,11 +33,12 @@ obj-y := cputable.o ptrace.o syscalls.o \
signal.o sysfs.o cacheinfo.o time.o \
prom.o traps.o setup-common.o \
udbg.o misc.o io.o dma.o \
- misc_$(CONFIG_WORD_SIZE).o vdso32/ \
+ misc_$(CONFIG_WORD_SIZE).o \
of_platform.o prom_parse.o
obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
signal_64.o ptrace32.o \
paca.o nvram_64.o firmware.o
+obj-$(CONFIG_VDSO32) += vdso32/
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o
obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 0034b6b3556a..98230579d99c 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -247,7 +247,7 @@ int main(void)
#endif
DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state));
- DEFINE(PACA_DSCR, offsetof(struct paca_struct, dscr_default));
+ DEFINE(PACA_DSCR_DEFAULT, offsetof(struct paca_struct, dscr_default));
DEFINE(PACA_STARTTIME, offsetof(struct paca_struct, starttime));
DEFINE(PACA_STARTTIME_USER, offsetof(struct paca_struct, starttime_user));
DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time));
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 60262fdf35ba..7d80bfdfb15e 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -108,7 +108,9 @@ extern void __restore_cpu_e6500(void);
PPC_FEATURE_TRUE_LE | \
PPC_FEATURE_PSERIES_PERFMON_COMPAT)
#define COMMON_USER2_POWER8 (PPC_FEATURE2_ARCH_2_07 | \
- PPC_FEATURE2_HTM_COMP | PPC_FEATURE2_DSCR | \
+ PPC_FEATURE2_HTM_COMP | \
+ PPC_FEATURE2_HTM_NOSC_COMP | \
+ PPC_FEATURE2_DSCR | \
PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR | \
PPC_FEATURE2_VEC_CRYPTO)
#define COMMON_USER_PA6T (COMMON_USER_PPC64 | PPC_FEATURE_PA6T |\
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index 484b2d4462c1..35e4dcc5dce3 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -248,6 +248,14 @@ int dma_set_mask(struct device *dev, u64 dma_mask)
{
if (ppc_md.dma_set_mask)
return ppc_md.dma_set_mask(dev, dma_mask);
+
+ if (dev_is_pci(dev)) {
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct pci_controller *phb = pci_bus_to_host(pdev->bus);
+ if (phb->controller_ops.dma_set_mask)
+ return phb->controller_ops.dma_set_mask(pdev, dma_mask);
+ }
+
return __dma_set_mask(dev, dma_mask);
}
EXPORT_SYMBOL(dma_set_mask);
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 9ee61d15653d..af9b597b10af 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -144,8 +144,6 @@ struct eeh_stats {
static struct eeh_stats eeh_stats;
-#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE)
-
static int __init eeh_setup(char *str)
{
if (!strcmp(str, "off"))
@@ -719,7 +717,7 @@ static void *eeh_restore_dev_state(void *data, void *userdata)
/* The caller should restore state for the specified device */
if (pdev != dev)
- pci_save_state(pdev);
+ pci_restore_state(pdev);
return NULL;
}
@@ -1412,13 +1410,11 @@ static int dev_has_iommu_table(struct device *dev, void *data)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct pci_dev **ppdev = data;
- struct iommu_table *tbl;
if (!dev)
return 0;
- tbl = get_iommu_table_base(dev);
- if (tbl && tbl->it_group) {
+ if (dev->iommu_group) {
*ppdev = pdev;
return 1;
}
@@ -1647,6 +1643,41 @@ int eeh_pe_configure(struct eeh_pe *pe)
}
EXPORT_SYMBOL_GPL(eeh_pe_configure);
+/**
+ * eeh_pe_inject_err - Injecting the specified PCI error to the indicated PE
+ * @pe: the indicated PE
+ * @type: error type
+ * @function: error function
+ * @addr: address
+ * @mask: address mask
+ *
+ * The routine is called to inject the specified PCI error, which
+ * is determined by @type and @function, to the indicated PE for
+ * testing purpose.
+ */
+int eeh_pe_inject_err(struct eeh_pe *pe, int type, int func,
+ unsigned long addr, unsigned long mask)
+{
+ /* Invalid PE ? */
+ if (!pe)
+ return -ENODEV;
+
+ /* Unsupported operation ? */
+ if (!eeh_ops || !eeh_ops->err_inject)
+ return -ENOENT;
+
+ /* Check on PCI error type */
+ if (type != EEH_ERR_TYPE_32 && type != EEH_ERR_TYPE_64)
+ return -EINVAL;
+
+ /* Check on PCI error function */
+ if (func < EEH_ERR_FUNC_MIN || func > EEH_ERR_FUNC_MAX)
+ return -EINVAL;
+
+ return eeh_ops->err_inject(pe, type, func, addr, mask);
+}
+EXPORT_SYMBOL_GPL(eeh_pe_inject_err);
+
static int proc_eeh_show(struct seq_file *m, void *v)
{
if (!eeh_enabled()) {
diff --git a/arch/powerpc/kernel/eeh_cache.c b/arch/powerpc/kernel/eeh_cache.c
index eeabeabea49c..a1e86e172e3c 100644
--- a/arch/powerpc/kernel/eeh_cache.c
+++ b/arch/powerpc/kernel/eeh_cache.c
@@ -48,11 +48,11 @@
*/
struct pci_io_addr_range {
struct rb_node rb_node;
- unsigned long addr_lo;
- unsigned long addr_hi;
+ resource_size_t addr_lo;
+ resource_size_t addr_hi;
struct eeh_dev *edev;
struct pci_dev *pcidev;
- unsigned int flags;
+ unsigned long flags;
};
static struct pci_io_addr_cache {
@@ -125,8 +125,8 @@ static void eeh_addr_cache_print(struct pci_io_addr_cache *cache)
/* Insert address range into the rb tree. */
static struct pci_io_addr_range *
-eeh_addr_cache_insert(struct pci_dev *dev, unsigned long alo,
- unsigned long ahi, unsigned int flags)
+eeh_addr_cache_insert(struct pci_dev *dev, resource_size_t alo,
+ resource_size_t ahi, unsigned long flags)
{
struct rb_node **p = &pci_io_addr_cache_root.rb_root.rb_node;
struct rb_node *parent = NULL;
@@ -197,9 +197,9 @@ static void __eeh_addr_cache_insert_dev(struct pci_dev *dev)
/* Walk resources on this device, poke them into the tree */
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
- unsigned long start = pci_resource_start(dev,i);
- unsigned long end = pci_resource_end(dev,i);
- unsigned int flags = pci_resource_flags(dev,i);
+ resource_size_t start = pci_resource_start(dev,i);
+ resource_size_t end = pci_resource_end(dev,i);
+ unsigned long flags = pci_resource_flags(dev,i);
/* We are interested only bus addresses, not dma or other stuff */
if (0 == (flags & (IORESOURCE_IO | IORESOURCE_MEM)))
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index 24768ff3cb73..89eb4bc34d3a 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -660,7 +660,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
eeh_pe_dev_traverse(pe, eeh_report_error, &result);
/* Get the current PCI slot state. This can take a long time,
- * sometimes over 3 seconds for certain systems.
+ * sometimes over 300 seconds for certain systems.
*/
rc = eeh_ops->wait_state(pe, MAX_WAIT_FOR_RECOVERY*1000);
if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) {
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index afbc20019c2e..579e0f9a2d57 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -34,6 +34,7 @@
#include <asm/ftrace.h>
#include <asm/hw_irq.h>
#include <asm/context_tracking.h>
+#include <asm/tm.h>
/*
* System calls.
@@ -51,6 +52,12 @@ exception_marker:
.globl system_call_common
system_call_common:
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+ extrdi. r10, r12, 1, (63-MSR_TS_T_LG) /* transaction active? */
+ bne tabort_syscall
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
+#endif
andi. r10,r12,MSR_PR
mr r10,r1
addi r1,r1,-INT_FRAME_SIZE
@@ -311,6 +318,34 @@ syscall_exit_work:
bl do_syscall_trace_leave
b ret_from_except
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+tabort_syscall:
+ /* Firstly we need to enable TM in the kernel */
+ mfmsr r10
+ li r13, 1
+ rldimi r10, r13, MSR_TM_LG, 63-MSR_TM_LG
+ mtmsrd r10, 0
+
+ /* tabort, this dooms the transaction, nothing else */
+ li r13, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT)
+ TABORT(R13)
+
+ /*
+ * Return directly to userspace. We have corrupted user register state,
+ * but userspace will never see that register state. Execution will
+ * resume after the tbegin of the aborted transaction with the
+ * checkpointed register state.
+ */
+ li r13, MSR_RI
+ andc r10, r10, r13
+ mtmsrd r10, 1
+ mtspr SPRN_SRR0, r11
+ mtspr SPRN_SRR1, r12
+
+ rfid
+ b . /* prevent speculative execution */
+#endif
+
/* Save non-volatile GPRs, if not already saved. */
_GLOBAL(save_nvgprs)
ld r11,_TRAP(r1)
@@ -556,7 +591,7 @@ BEGIN_FTR_SECTION
ld r0,THREAD_DSCR(r4)
cmpwi r6,0
bne 1f
- ld r0,PACA_DSCR(r13)
+ ld r0,PACA_DSCR_DEFAULT(r13)
1:
BEGIN_FTR_SECTION_NESTED(70)
mfspr r8, SPRN_FSCR
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 9519e6bdc6d7..0a0399c2af11 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -59,14 +59,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \
#if defined(CONFIG_RELOCATABLE)
/*
- * We can't branch directly; in the direct case we use LR
- * and system_call_entry restores LR. (We thus need to move
- * LR to r10 in the RFID case too.)
+ * We can't branch directly so we do it via the CTR which
+ * is volatile across system calls.
*/
#define SYSCALL_PSERIES_2_DIRECT \
mflr r10 ; \
ld r12,PACAKBASE(r13) ; \
- LOAD_HANDLER(r12, system_call_entry_direct) ; \
+ LOAD_HANDLER(r12, system_call_entry) ; \
mtctr r12 ; \
mfspr r12,SPRN_SRR1 ; \
/* Re-use of r13... No spare regs to do this */ \
@@ -80,7 +79,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \
mfspr r12,SPRN_SRR1 ; \
li r10,MSR_RI ; \
mtmsrd r10,1 ; /* Set RI (EE=0) */ \
- b system_call_entry_direct ;
+ b system_call_common ;
#endif
/*
@@ -969,13 +968,6 @@ hv_facility_unavailable_relon_trampoline:
__end_interrupts:
.align 7
-system_call_entry_direct:
-#if defined(CONFIG_RELOCATABLE)
- /* The first level prologue may have used LR to get here, saving
- * orig in r10. To save hacking/ifdeffing common code, restore here.
- */
- mtlr r10
-#endif
system_call_entry:
b system_call_common
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 9b53fe139bf6..78c1eba4c04a 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -48,6 +48,19 @@
mtspr spr, reg
#endif
+/* Macro to test if an address is a kernel address */
+#if CONFIG_TASK_SIZE <= 0x80000000 && CONFIG_PAGE_OFFSET >= 0x80000000
+#define IS_KERNEL(tmp, addr) \
+ andis. tmp, addr, 0x8000 /* Address >= 0x80000000 */
+#define BRANCH_UNLESS_KERNEL(label) beq label
+#else
+#define IS_KERNEL(tmp, addr) \
+ rlwinm tmp, addr, 16, 16, 31; \
+ cmpli cr0, tmp, PAGE_OFFSET >> 16
+#define BRANCH_UNLESS_KERNEL(label) blt label
+#endif
+
+
/*
* Value for the bits that have fixed value in RPN entries.
* Also used for tagging DAR for DTLBerror.
@@ -116,13 +129,13 @@ turn_on_mmu:
*/
#define EXCEPTION_PROLOG \
EXCEPTION_PROLOG_0; \
+ mfcr r10; \
EXCEPTION_PROLOG_1; \
EXCEPTION_PROLOG_2
#define EXCEPTION_PROLOG_0 \
mtspr SPRN_SPRG_SCRATCH0,r10; \
- mtspr SPRN_SPRG_SCRATCH1,r11; \
- mfcr r10
+ mtspr SPRN_SPRG_SCRATCH1,r11
#define EXCEPTION_PROLOG_1 \
mfspr r11,SPRN_SRR1; /* check whether user or kernel */ \
@@ -162,7 +175,6 @@ turn_on_mmu:
* Exception exit code.
*/
#define EXCEPTION_EPILOG_0 \
- mtcr r10; \
mfspr r10,SPRN_SPRG_SCRATCH0; \
mfspr r11,SPRN_SPRG_SCRATCH1
@@ -297,19 +309,22 @@ SystemCall:
* We have to use the MD_xxx registers for the tablewalk because the
* equivalent MI_xxx registers only perform the attribute functions.
*/
+
+#ifdef CONFIG_8xx_CPU15
+#define INVALIDATE_ADJACENT_PAGES_CPU15(tmp, addr) \
+ addi tmp, addr, PAGE_SIZE; \
+ tlbie tmp; \
+ addi tmp, addr, -PAGE_SIZE; \
+ tlbie tmp
+#else
+#define INVALIDATE_ADJACENT_PAGES_CPU15(tmp, addr)
+#endif
+
InstructionTLBMiss:
#ifdef CONFIG_8xx_CPU6
- mtspr SPRN_DAR, r3
+ mtspr SPRN_SPRG_SCRATCH2, r3
#endif
EXCEPTION_PROLOG_0
- mtspr SPRN_SPRG_SCRATCH2, r10
- mfspr r10, SPRN_SRR0 /* Get effective address of fault */
-#ifdef CONFIG_8xx_CPU15
- addi r11, r10, PAGE_SIZE
- tlbie r11
- addi r11, r10, -PAGE_SIZE
- tlbie r11
-#endif
/* If we are faulting a kernel address, we have to use the
* kernel page tables.
@@ -317,24 +332,34 @@ InstructionTLBMiss:
#ifdef CONFIG_MODULES
/* Only modules will cause ITLB Misses as we always
* pin the first 8MB of kernel memory */
- andis. r11, r10, 0x8000 /* Address >= 0x80000000 */
-#endif
+ mfspr r11, SPRN_SRR0 /* Get effective address of fault */
+ INVALIDATE_ADJACENT_PAGES_CPU15(r10, r11)
+ mfcr r10
+ IS_KERNEL(r11, r11)
mfspr r11, SPRN_M_TW /* Get level 1 table */
-#ifdef CONFIG_MODULES
- beq 3f
+ BRANCH_UNLESS_KERNEL(3f)
lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha
3:
+ mtcr r10
+ mfspr r10, SPRN_SRR0 /* Get effective address of fault */
+#else
+ mfspr r10, SPRN_SRR0 /* Get effective address of fault */
+ INVALIDATE_ADJACENT_PAGES_CPU15(r11, r10)
+ mfspr r11, SPRN_M_TW /* Get level 1 table base address */
#endif
/* Insert level 1 index */
rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
lwz r11, (swapper_pg_dir-PAGE_OFFSET)@l(r11) /* Get the level 1 entry */
- /* Load the MI_TWC with the attributes for this "segment." */
- MTSPR_CPU6(SPRN_MI_TWC, r11, r3) /* Set segment attributes */
- rlwinm r11, r11,0,0,19 /* Extract page descriptor page address */
/* Extract level 2 index */
rlwinm r10, r10, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29
- lwzx r10, r10, r11 /* Get the pte */
+ rlwimi r10, r11, 0, 0, 32 - PAGE_SHIFT - 1 /* Add level 2 base */
+ lwz r10, 0(r10) /* Get the pte */
+
+ /* Insert the APG into the TWC from the Linux PTE. */
+ rlwimi r11, r10, 0, 25, 26
+ /* Load the MI_TWC with the attributes for this "segment." */
+ MTSPR_CPU6(SPRN_MI_TWC, r11, r3) /* Set segment attributes */
#ifdef CONFIG_SWAP
rlwinm r11, r10, 32-5, _PAGE_PRESENT
@@ -343,40 +368,41 @@ InstructionTLBMiss:
#endif
li r11, RPN_PATTERN
/* The Linux PTE won't go exactly into the MMU TLB.
- * Software indicator bits 21 and 28 must be clear.
+ * Software indicator bits 20-23 and 28 must be clear.
* Software indicator bits 24, 25, 26, and 27 must be
* set. All other Linux PTE bits control the behavior
* of the MMU.
*/
- rlwimi r10, r11, 0, 0x07f8 /* Set 24-27, clear 21-23,28 */
+ rlwimi r10, r11, 0, 0x0ff8 /* Set 24-27, clear 20-23,28 */
MTSPR_CPU6(SPRN_MI_RPN, r10, r3) /* Update TLB entry */
/* Restore registers */
#ifdef CONFIG_8xx_CPU6
- mfspr r3, SPRN_DAR
- mtspr SPRN_DAR, r11 /* Tag DAR */
+ mfspr r3, SPRN_SPRG_SCRATCH2
#endif
- mfspr r10, SPRN_SPRG_SCRATCH2
EXCEPTION_EPILOG_0
rfi
. = 0x1200
DataStoreTLBMiss:
#ifdef CONFIG_8xx_CPU6
- mtspr SPRN_DAR, r3
+ mtspr SPRN_SPRG_SCRATCH2, r3
#endif
EXCEPTION_PROLOG_0
- mtspr SPRN_SPRG_SCRATCH2, r10
- mfspr r10, SPRN_MD_EPN
+ mfcr r10
/* If we are faulting a kernel address, we have to use the
* kernel page tables.
*/
- andis. r11, r10, 0x8000
+ mfspr r11, SPRN_MD_EPN
+ IS_KERNEL(r11, r11)
mfspr r11, SPRN_M_TW /* Get level 1 table */
- beq 3f
+ BRANCH_UNLESS_KERNEL(3f)
lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha
3:
+ mtcr r10
+ mfspr r10, SPRN_MD_EPN
+
/* Insert level 1 index */
rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
lwz r11, (swapper_pg_dir-PAGE_OFFSET)@l(r11) /* Get the level 1 entry */
@@ -388,13 +414,13 @@ DataStoreTLBMiss:
rlwimi r10, r11, 0, 0, 32 - PAGE_SHIFT - 1 /* Add level 2 base */
lwz r10, 0(r10) /* Get the pte */
- /* Insert the Guarded flag into the TWC from the Linux PTE.
- * It is bit 27 of both the Linux PTE and the TWC (at least
+ /* Insert the Guarded flag and APG into the TWC from the Linux PTE.
+ * It is bit 26-27 of both the Linux PTE and the TWC (at least
* I got that right :-). It will be better when we can put
* this into the Linux pgd/pmd and load it in the operation
* above.
*/
- rlwimi r11, r10, 0, 27, 27
+ rlwimi r11, r10, 0, 26, 27
/* Insert the WriteThru flag into the TWC from the Linux PTE.
* It is bit 25 in the Linux PTE and bit 30 in the TWC
*/
@@ -423,14 +449,14 @@ DataStoreTLBMiss:
*/
li r11, RPN_PATTERN
rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */
+ rlwimi r10, r11, 0, 20, 20 /* clear 20 */
MTSPR_CPU6(SPRN_MD_RPN, r10, r3) /* Update TLB entry */
/* Restore registers */
#ifdef CONFIG_8xx_CPU6
- mfspr r3, SPRN_DAR
+ mfspr r3, SPRN_SPRG_SCRATCH2
#endif
mtspr SPRN_DAR, r11 /* Tag DAR */
- mfspr r10, SPRN_SPRG_SCRATCH2
EXCEPTION_EPILOG_0
rfi
@@ -456,6 +482,7 @@ InstructionTLBError:
. = 0x1400
DataTLBError:
EXCEPTION_PROLOG_0
+ mfcr r10
mfspr r11, SPRN_DAR
cmpwi cr0, r11, RPN_PATTERN
@@ -503,9 +530,9 @@ FixupDAR:/* Entry point for dcbx workaround. */
mtspr SPRN_SPRG_SCRATCH2, r10
/* fetch instruction from memory. */
mfspr r10, SPRN_SRR0
- andis. r11, r10, 0x8000 /* Address >= 0x80000000 */
+ IS_KERNEL(r11, r10)
mfspr r11, SPRN_M_TW /* Get level 1 table */
- beq 3f
+ BRANCH_UNLESS_KERNEL(3f)
lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha
/* Insert level 1 index */
3: rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29
@@ -743,15 +770,20 @@ initial_mmu:
ori r8, r8, MI_EVALID /* Mark it valid */
mtspr SPRN_MI_EPN, r8
mtspr SPRN_MD_EPN, r8
- li r8, MI_PS8MEG /* Set 8M byte page */
+ li r8, MI_PS8MEG | (2 << 5) /* Set 8M byte page, APG 2 */
ori r8, r8, MI_SVALID /* Make it valid */
mtspr SPRN_MI_TWC, r8
+ li r8, MI_PS8MEG /* Set 8M byte page, APG 0 */
+ ori r8, r8, MI_SVALID /* Make it valid */
mtspr SPRN_MD_TWC, r8
li r8, MI_BOOTINIT /* Create RPN for address 0 */
mtspr SPRN_MI_RPN, r8 /* Store TLB entry */
mtspr SPRN_MD_RPN, r8
- lis r8, MI_Kp@h /* Set the protection mode */
+ lis r8, MI_APG_INIT@h /* Set protection modes */
+ ori r8, r8, MI_APG_INIT@l
mtspr SPRN_MI_AP, r8
+ lis r8, MD_APG_INIT@h
+ ori r8, r8, MD_APG_INIT@l
mtspr SPRN_MD_AP, r8
/* Map another 8 MByte at the IMMR to get the processor
diff --git a/arch/powerpc/kernel/idle_e500.S b/arch/powerpc/kernel/idle_e500.S
index 15448668988d..b9b6ef510be1 100644
--- a/arch/powerpc/kernel/idle_e500.S
+++ b/arch/powerpc/kernel/idle_e500.S
@@ -58,15 +58,6 @@ BEGIN_FTR_SECTION
mtlr r0
lis r3,HID0_NAP@h
END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
-BEGIN_FTR_SECTION
- msync
- li r7,L2CSR0_L2FL@l
- mtspr SPRN_L2CSR0,r7
-2:
- mfspr r7,SPRN_L2CSR0
- andi. r4,r7,L2CSR0_L2FL@l
- bne 2b
-END_FTR_SECTION_IFSET(CPU_FTR_L2CSR|CPU_FTR_CAN_NAP)
1:
/* Go to NAP or DOZE now */
mfspr r4,SPRN_HID0
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index b054f33ab1fb..a8e3490b54e3 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -322,11 +322,11 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
ret = entry << tbl->it_page_shift; /* Set the return dma address */
/* Put the TCEs in the HW table */
- build_fail = ppc_md.tce_build(tbl, entry, npages,
+ build_fail = tbl->it_ops->set(tbl, entry, npages,
(unsigned long)page &
IOMMU_PAGE_MASK(tbl), direction, attrs);
- /* ppc_md.tce_build() only returns non-zero for transient errors.
+ /* tbl->it_ops->set() only returns non-zero for transient errors.
* Clean up the table bitmap in this case and return
* DMA_ERROR_CODE. For all other errors the functionality is
* not altered.
@@ -337,8 +337,8 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
}
/* Flush/invalidate TLB caches if necessary */
- if (ppc_md.tce_flush)
- ppc_md.tce_flush(tbl);
+ if (tbl->it_ops->flush)
+ tbl->it_ops->flush(tbl);
/* Make sure updates are seen by hardware */
mb();
@@ -408,7 +408,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
if (!iommu_free_check(tbl, dma_addr, npages))
return;
- ppc_md.tce_free(tbl, entry, npages);
+ tbl->it_ops->clear(tbl, entry, npages);
spin_lock_irqsave(&(pool->lock), flags);
bitmap_clear(tbl->it_map, free_entry, npages);
@@ -424,8 +424,8 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
* not do an mb() here on purpose, it is not needed on any of
* the current platforms.
*/
- if (ppc_md.tce_flush)
- ppc_md.tce_flush(tbl);
+ if (tbl->it_ops->flush)
+ tbl->it_ops->flush(tbl);
}
int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
@@ -495,7 +495,7 @@ int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
npages, entry, dma_addr);
/* Insert into HW table */
- build_fail = ppc_md.tce_build(tbl, entry, npages,
+ build_fail = tbl->it_ops->set(tbl, entry, npages,
vaddr & IOMMU_PAGE_MASK(tbl),
direction, attrs);
if(unlikely(build_fail))
@@ -534,8 +534,8 @@ int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
}
/* Flush/invalidate TLB caches if necessary */
- if (ppc_md.tce_flush)
- ppc_md.tce_flush(tbl);
+ if (tbl->it_ops->flush)
+ tbl->it_ops->flush(tbl);
DBG("mapped %d elements:\n", outcount);
@@ -600,8 +600,8 @@ void ppc_iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
* do not do an mb() here, the affected platforms do not need it
* when freeing.
*/
- if (ppc_md.tce_flush)
- ppc_md.tce_flush(tbl);
+ if (tbl->it_ops->flush)
+ tbl->it_ops->flush(tbl);
}
static void iommu_table_clear(struct iommu_table *tbl)
@@ -613,17 +613,17 @@ static void iommu_table_clear(struct iommu_table *tbl)
*/
if (!is_kdump_kernel() || is_fadump_active()) {
/* Clear the table in case firmware left allocations in it */
- ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
+ tbl->it_ops->clear(tbl, tbl->it_offset, tbl->it_size);
return;
}
#ifdef CONFIG_CRASH_DUMP
- if (ppc_md.tce_get) {
+ if (tbl->it_ops->get) {
unsigned long index, tceval, tcecount = 0;
/* Reserve the existing mappings left by the first kernel. */
for (index = 0; index < tbl->it_size; index++) {
- tceval = ppc_md.tce_get(tbl, index + tbl->it_offset);
+ tceval = tbl->it_ops->get(tbl, index + tbl->it_offset);
/*
* Freed TCE entry contains 0x7fffffffffffffff on JS20
*/
@@ -657,6 +657,8 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
unsigned int i;
struct iommu_pool *p;
+ BUG_ON(!tbl->it_ops);
+
/* number of bytes needed for the bitmap */
sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long);
@@ -713,9 +715,11 @@ void iommu_free_table(struct iommu_table *tbl, const char *node_name)
unsigned long bitmap_sz;
unsigned int order;
- if (!tbl || !tbl->it_map) {
- printk(KERN_ERR "%s: expected TCE map for %s\n", __func__,
- node_name);
+ if (!tbl)
+ return;
+
+ if (!tbl->it_map) {
+ kfree(tbl);
return;
}
@@ -726,13 +730,6 @@ void iommu_free_table(struct iommu_table *tbl, const char *node_name)
if (tbl->it_offset == 0)
clear_bit(0, tbl->it_map);
-#ifdef CONFIG_IOMMU_API
- if (tbl->it_group) {
- iommu_group_put(tbl->it_group);
- BUG_ON(tbl->it_group);
- }
-#endif
-
/* verify that table contains no entries */
if (!bitmap_empty(tbl->it_map, tbl->it_size))
pr_warn("%s: Unexpected TCEs for %s\n", __func__, node_name);
@@ -871,17 +868,33 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size,
}
}
+unsigned long iommu_direction_to_tce_perm(enum dma_data_direction dir)
+{
+ switch (dir) {
+ case DMA_BIDIRECTIONAL:
+ return TCE_PCI_READ | TCE_PCI_WRITE;
+ case DMA_FROM_DEVICE:
+ return TCE_PCI_WRITE;
+ case DMA_TO_DEVICE:
+ return TCE_PCI_READ;
+ default:
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(iommu_direction_to_tce_perm);
+
#ifdef CONFIG_IOMMU_API
/*
* SPAPR TCE API
*/
static void group_release(void *iommu_data)
{
- struct iommu_table *tbl = iommu_data;
- tbl->it_group = NULL;
+ struct iommu_table_group *table_group = iommu_data;
+
+ table_group->group = NULL;
}
-void iommu_register_group(struct iommu_table *tbl,
+void iommu_register_group(struct iommu_table_group *table_group,
int pci_domain_number, unsigned long pe_num)
{
struct iommu_group *grp;
@@ -893,8 +906,8 @@ void iommu_register_group(struct iommu_table *tbl,
PTR_ERR(grp));
return;
}
- tbl->it_group = grp;
- iommu_group_set_iommudata(grp, tbl, group_release);
+ table_group->group = grp;
+ iommu_group_set_iommudata(grp, table_group, group_release);
name = kasprintf(GFP_KERNEL, "domain%d-pe%lx",
pci_domain_number, pe_num);
if (!name)
@@ -919,8 +932,8 @@ EXPORT_SYMBOL_GPL(iommu_tce_direction);
void iommu_flush_tce(struct iommu_table *tbl)
{
/* Flush/invalidate TLB caches if necessary */
- if (ppc_md.tce_flush)
- ppc_md.tce_flush(tbl);
+ if (tbl->it_ops->flush)
+ tbl->it_ops->flush(tbl);
/* Make sure updates are seen by hardware */
mb();
@@ -931,7 +944,7 @@ int iommu_tce_clear_param_check(struct iommu_table *tbl,
unsigned long ioba, unsigned long tce_value,
unsigned long npages)
{
- /* ppc_md.tce_free() does not support any value but 0 */
+ /* tbl->it_ops->clear() does not support any value but 0 */
if (tce_value)
return -EINVAL;
@@ -952,10 +965,7 @@ EXPORT_SYMBOL_GPL(iommu_tce_clear_param_check);
int iommu_tce_put_param_check(struct iommu_table *tbl,
unsigned long ioba, unsigned long tce)
{
- if (!(tce & (TCE_PCI_WRITE | TCE_PCI_READ)))
- return -EINVAL;
-
- if (tce & ~(IOMMU_PAGE_MASK(tbl) | TCE_PCI_WRITE | TCE_PCI_READ))
+ if (tce & ~IOMMU_PAGE_MASK(tbl))
return -EINVAL;
if (ioba & ~IOMMU_PAGE_MASK(tbl))
@@ -972,68 +982,16 @@ int iommu_tce_put_param_check(struct iommu_table *tbl,
}
EXPORT_SYMBOL_GPL(iommu_tce_put_param_check);
-unsigned long iommu_clear_tce(struct iommu_table *tbl, unsigned long entry)
-{
- unsigned long oldtce;
- struct iommu_pool *pool = get_pool(tbl, entry);
-
- spin_lock(&(pool->lock));
-
- oldtce = ppc_md.tce_get(tbl, entry);
- if (oldtce & (TCE_PCI_WRITE | TCE_PCI_READ))
- ppc_md.tce_free(tbl, entry, 1);
- else
- oldtce = 0;
-
- spin_unlock(&(pool->lock));
-
- return oldtce;
-}
-EXPORT_SYMBOL_GPL(iommu_clear_tce);
-
-int iommu_clear_tces_and_put_pages(struct iommu_table *tbl,
- unsigned long entry, unsigned long pages)
-{
- unsigned long oldtce;
- struct page *page;
-
- for ( ; pages; --pages, ++entry) {
- oldtce = iommu_clear_tce(tbl, entry);
- if (!oldtce)
- continue;
-
- page = pfn_to_page(oldtce >> PAGE_SHIFT);
- WARN_ON(!page);
- if (page) {
- if (oldtce & TCE_PCI_WRITE)
- SetPageDirty(page);
- put_page(page);
- }
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(iommu_clear_tces_and_put_pages);
-
-/*
- * hwaddr is a kernel virtual address here (0xc... bazillion),
- * tce_build converts it to a physical address.
- */
-int iommu_tce_build(struct iommu_table *tbl, unsigned long entry,
- unsigned long hwaddr, enum dma_data_direction direction)
+long iommu_tce_xchg(struct iommu_table *tbl, unsigned long entry,
+ unsigned long *hpa, enum dma_data_direction *direction)
{
- int ret = -EBUSY;
- unsigned long oldtce;
- struct iommu_pool *pool = get_pool(tbl, entry);
-
- spin_lock(&(pool->lock));
+ long ret;
- oldtce = ppc_md.tce_get(tbl, entry);
- /* Add new entry if it is not busy */
- if (!(oldtce & (TCE_PCI_WRITE | TCE_PCI_READ)))
- ret = ppc_md.tce_build(tbl, entry, 1, hwaddr, direction, NULL);
+ ret = tbl->it_ops->exchange(tbl, entry, hpa, direction);
- spin_unlock(&(pool->lock));
+ if (!ret && ((*direction == DMA_FROM_DEVICE) ||
+ (*direction == DMA_BIDIRECTIONAL)))
+ SetPageDirty(pfn_to_page(*hpa >> PAGE_SHIFT));
/* if (unlikely(ret))
pr_err("iommu_tce: %s failed on hwaddr=%lx ioba=%lx kva=%lx ret=%d\n",
@@ -1042,84 +1000,72 @@ int iommu_tce_build(struct iommu_table *tbl, unsigned long entry,
return ret;
}
-EXPORT_SYMBOL_GPL(iommu_tce_build);
+EXPORT_SYMBOL_GPL(iommu_tce_xchg);
-int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry,
- unsigned long tce)
+int iommu_take_ownership(struct iommu_table *tbl)
{
- int ret;
- struct page *page = NULL;
- unsigned long hwaddr, offset = tce & IOMMU_PAGE_MASK(tbl) & ~PAGE_MASK;
- enum dma_data_direction direction = iommu_tce_direction(tce);
-
- ret = get_user_pages_fast(tce & PAGE_MASK, 1,
- direction != DMA_TO_DEVICE, &page);
- if (unlikely(ret != 1)) {
- /* pr_err("iommu_tce: get_user_pages_fast failed tce=%lx ioba=%lx ret=%d\n",
- tce, entry << tbl->it_page_shift, ret); */
- return -EFAULT;
- }
- hwaddr = (unsigned long) page_address(page) + offset;
-
- ret = iommu_tce_build(tbl, entry, hwaddr, direction);
- if (ret)
- put_page(page);
-
- if (ret < 0)
- pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%d\n",
- __func__, entry << tbl->it_page_shift, tce, ret);
+ unsigned long flags, i, sz = (tbl->it_size + 7) >> 3;
+ int ret = 0;
- return ret;
-}
-EXPORT_SYMBOL_GPL(iommu_put_tce_user_mode);
+ /*
+ * VFIO does not control TCE entries allocation and the guest
+ * can write new TCEs on top of existing ones so iommu_tce_build()
+ * must be able to release old pages. This functionality
+ * requires exchange() callback defined so if it is not
+ * implemented, we disallow taking ownership over the table.
+ */
+ if (!tbl->it_ops->exchange)
+ return -EINVAL;
-int iommu_take_ownership(struct iommu_table *tbl)
-{
- unsigned long sz = (tbl->it_size + 7) >> 3;
+ spin_lock_irqsave(&tbl->large_pool.lock, flags);
+ for (i = 0; i < tbl->nr_pools; i++)
+ spin_lock(&tbl->pools[i].lock);
if (tbl->it_offset == 0)
clear_bit(0, tbl->it_map);
if (!bitmap_empty(tbl->it_map, tbl->it_size)) {
pr_err("iommu_tce: it_map is not empty");
- return -EBUSY;
+ ret = -EBUSY;
+ /* Restore bit#0 set by iommu_init_table() */
+ if (tbl->it_offset == 0)
+ set_bit(0, tbl->it_map);
+ } else {
+ memset(tbl->it_map, 0xff, sz);
}
- memset(tbl->it_map, 0xff, sz);
- iommu_clear_tces_and_put_pages(tbl, tbl->it_offset, tbl->it_size);
+ for (i = 0; i < tbl->nr_pools; i++)
+ spin_unlock(&tbl->pools[i].lock);
+ spin_unlock_irqrestore(&tbl->large_pool.lock, flags);
- /*
- * Disable iommu bypass, otherwise the user can DMA to all of
- * our physical memory via the bypass window instead of just
- * the pages that has been explicitly mapped into the iommu
- */
- if (tbl->set_bypass)
- tbl->set_bypass(tbl, false);
-
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(iommu_take_ownership);
void iommu_release_ownership(struct iommu_table *tbl)
{
- unsigned long sz = (tbl->it_size + 7) >> 3;
+ unsigned long flags, i, sz = (tbl->it_size + 7) >> 3;
+
+ spin_lock_irqsave(&tbl->large_pool.lock, flags);
+ for (i = 0; i < tbl->nr_pools; i++)
+ spin_lock(&tbl->pools[i].lock);
- iommu_clear_tces_and_put_pages(tbl, tbl->it_offset, tbl->it_size);
memset(tbl->it_map, 0, sz);
/* Restore bit#0 set by iommu_init_table() */
if (tbl->it_offset == 0)
set_bit(0, tbl->it_map);
- /* The kernel owns the device now, we can restore the iommu bypass */
- if (tbl->set_bypass)
- tbl->set_bypass(tbl, true);
+ for (i = 0; i < tbl->nr_pools; i++)
+ spin_unlock(&tbl->pools[i].lock);
+ spin_unlock_irqrestore(&tbl->large_pool.lock, flags);
}
EXPORT_SYMBOL_GPL(iommu_release_ownership);
int iommu_add_device(struct device *dev)
{
struct iommu_table *tbl;
+ struct iommu_table_group_link *tgl;
/*
* The sysfs entries should be populated before
@@ -1137,15 +1083,22 @@ int iommu_add_device(struct device *dev)
}
tbl = get_iommu_table_base(dev);
- if (!tbl || !tbl->it_group) {
+ if (!tbl) {
pr_debug("%s: Skipping device %s with no tbl\n",
__func__, dev_name(dev));
return 0;
}
+ tgl = list_first_entry_or_null(&tbl->it_group_list,
+ struct iommu_table_group_link, next);
+ if (!tgl) {
+ pr_debug("%s: Skipping device %s with no group\n",
+ __func__, dev_name(dev));
+ return 0;
+ }
pr_debug("%s: Adding %s to iommu group %d\n",
__func__, dev_name(dev),
- iommu_group_id(tbl->it_group));
+ iommu_group_id(tgl->table_group->group));
if (PAGE_SIZE < IOMMU_PAGE_SIZE(tbl)) {
pr_err("%s: Invalid IOMMU page size %lx (%lx) on %s\n",
@@ -1154,7 +1107,7 @@ int iommu_add_device(struct device *dev)
return -EINVAL;
}
- return iommu_group_add_device(tbl->it_group, dev);
+ return iommu_group_add_device(tgl->table_group->group, dev);
}
EXPORT_SYMBOL_GPL(iommu_add_device);
diff --git a/arch/powerpc/kernel/msi.c b/arch/powerpc/kernel/msi.c
index 71bd161640cf..dab616a33b8d 100644
--- a/arch/powerpc/kernel/msi.c
+++ b/arch/powerpc/kernel/msi.c
@@ -15,7 +15,10 @@
int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
- if (!ppc_md.setup_msi_irqs || !ppc_md.teardown_msi_irqs) {
+ struct pci_controller *phb = pci_bus_to_host(dev->bus);
+
+ if (!phb->controller_ops.setup_msi_irqs ||
+ !phb->controller_ops.teardown_msi_irqs) {
pr_debug("msi: Platform doesn't provide MSI callbacks.\n");
return -ENOSYS;
}
@@ -24,10 +27,12 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
if (type == PCI_CAP_ID_MSI && nvec > 1)
return 1;
- return ppc_md.setup_msi_irqs(dev, nvec, type);
+ return phb->controller_ops.setup_msi_irqs(dev, nvec, type);
}
void arch_teardown_msi_irqs(struct pci_dev *dev)
{
- ppc_md.teardown_msi_irqs(dev);
+ struct pci_controller *phb = pci_bus_to_host(dev->bus);
+
+ phb->controller_ops.teardown_msi_irqs(dev);
}
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 0d054068a21d..b9de34d44fcb 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -89,6 +89,7 @@ struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
#endif
return phb;
}
+EXPORT_SYMBOL_GPL(pcibios_alloc_controller);
void pcibios_free_controller(struct pci_controller *phb)
{
@@ -1447,6 +1448,7 @@ void pcibios_claim_one_bus(struct pci_bus *bus)
list_for_each_entry(child_bus, &bus->children, node)
pcibios_claim_one_bus(child_bus);
}
+EXPORT_SYMBOL_GPL(pcibios_claim_one_bus);
/* pcibios_finish_adding_to_bus
@@ -1488,6 +1490,14 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
return pci_enable_resources(dev, mask);
}
+void pcibios_disable_device(struct pci_dev *dev)
+{
+ struct pci_controller *phb = pci_bus_to_host(dev->bus);
+
+ if (phb->controller_ops.disable_device)
+ phb->controller_ops.disable_device(dev);
+}
+
resource_size_t pcibios_io_space_offset(struct pci_controller *hose)
{
return (unsigned long) hose->io_base_virt - _IO_BASE;
@@ -1680,6 +1690,7 @@ void pcibios_scan_phb(struct pci_controller *hose)
pcie_bus_configure_settings(child);
}
}
+EXPORT_SYMBOL_GPL(pcibios_scan_phb);
static void fixup_hide_host_resource_fsl(struct pci_dev *dev)
{
diff --git a/arch/powerpc/kernel/pci-hotplug.c b/arch/powerpc/kernel/pci-hotplug.c
index 7ed85a69a9c2..7f9ed0c1f6b9 100644
--- a/arch/powerpc/kernel/pci-hotplug.c
+++ b/arch/powerpc/kernel/pci-hotplug.c
@@ -29,7 +29,12 @@
*/
void pcibios_release_device(struct pci_dev *dev)
{
+ struct pci_controller *phb = pci_bus_to_host(dev->bus);
+
eeh_remove_device(dev);
+
+ if (phb->controller_ops.release_device)
+ phb->controller_ops.release_device(dev);
}
/**
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index febb50dd5328..8005e18d1b40 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1112,7 +1112,6 @@ static void setup_ksp_vsid(struct task_struct *p, unsigned long sp)
/*
* Copy a thread..
*/
-extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */
/*
* Copy architecture-specific thread state
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 308c5e15676b..8b888b12a475 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -46,7 +46,6 @@
#include <asm/mmu.h>
#include <asm/paca.h>
#include <asm/pgtable.h>
-#include <asm/pci.h>
#include <asm/iommu.h>
#include <asm/btext.h>
#include <asm/sections.h>
@@ -573,6 +572,7 @@ static void __init early_reserve_mem_dt(void)
int len;
const __be32 *prop;
+ early_init_fdt_reserve_self();
early_init_fdt_scan_reserved_mem();
dt_root = of_get_flat_dt_root();
@@ -800,6 +800,7 @@ int of_get_ibm_chip_id(struct device_node *np)
}
return -1;
}
+EXPORT_SYMBOL(of_get_ibm_chip_id);
/**
* cpu_to_chip_id - Return the cpus chip-id
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index fd1fe4c37599..fcca8077e6a2 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -37,7 +37,6 @@
#include <asm/smp.h>
#include <asm/mmu.h>
#include <asm/pgtable.h>
-#include <asm/pci.h>
#include <asm/iommu.h>
#include <asm/btext.h>
#include <asm/sections.h>
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index c69671c03c3b..bdcbb716f4d6 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -523,7 +523,8 @@ void __init setup_system(void)
smp_release_cpus();
#endif
- pr_info("Starting Linux PPC64 %s\n", init_utsname()->version);
+ pr_info("Starting Linux %s %s\n", init_utsname()->machine,
+ init_utsname()->version);
pr_info("-----------------------------------------------------\n");
pr_info("ppc64_pft_size = 0x%llx\n", ppc64_pft_size);
@@ -686,6 +687,9 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_PPC_64K_PAGES
init_mm.context.pte_frag = NULL;
#endif
+#ifdef CONFIG_SPAPR_TCE_IOMMU
+ mm_iommu_init(&init_mm.context);
+#endif
irqstack_early_init();
exc_lvl_early_init();
emergency_stack_init();
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index fa1fd8a0c867..692873bff334 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -496,13 +496,34 @@ static DEVICE_ATTR(spurr, 0400, show_spurr, NULL);
static DEVICE_ATTR(purr, 0400, show_purr, store_purr);
static DEVICE_ATTR(pir, 0400, show_pir, NULL);
+/*
+ * This is the system wide DSCR register default value. Any
+ * change to this default value through the sysfs interface
+ * will update all per cpu DSCR default values across the
+ * system stored in their respective PACA structures.
+ */
static unsigned long dscr_default;
+/**
+ * read_dscr() - Fetch the cpu specific DSCR default
+ * @val: Returned cpu specific DSCR default value
+ *
+ * This function returns the per cpu DSCR default value
+ * for any cpu which is contained in it's PACA structure.
+ */
static void read_dscr(void *val)
{
*(unsigned long *)val = get_paca()->dscr_default;
}
+
+/**
+ * write_dscr() - Update the cpu specific DSCR default
+ * @val: New cpu specific DSCR default value to update
+ *
+ * This function updates the per cpu DSCR default value
+ * for any cpu which is contained in it's PACA structure.
+ */
static void write_dscr(void *val)
{
get_paca()->dscr_default = *(unsigned long *)val;
@@ -520,12 +541,29 @@ static void add_write_permission_dev_attr(struct device_attribute *attr)
attr->attr.mode |= 0200;
}
+/**
+ * show_dscr_default() - Fetch the system wide DSCR default
+ * @dev: Device structure
+ * @attr: Device attribute structure
+ * @buf: Interface buffer
+ *
+ * This function returns the system wide DSCR default value.
+ */
static ssize_t show_dscr_default(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%lx\n", dscr_default);
}
+/**
+ * store_dscr_default() - Update the system wide DSCR default
+ * @dev: Device structure
+ * @attr: Device attribute structure
+ * @buf: Interface buffer
+ * @count: Size of the update
+ *
+ * This function updates the system wide DSCR default value.
+ */
static ssize_t __used store_dscr_default(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S
index 5754b226da7e..bf8f34a58670 100644
--- a/arch/powerpc/kernel/tm.S
+++ b/arch/powerpc/kernel/tm.S
@@ -293,7 +293,7 @@ dont_backup_fp:
ld r2, STK_GOT(r1)
/* Load CPU's default DSCR */
- ld r0, PACA_DSCR(r13)
+ ld r0, PACA_DSCR_DEFAULT(r13)
mtspr SPRN_DSCR, r0
blr
@@ -473,7 +473,7 @@ restore_gprs:
ld r2, STK_GOT(r1)
/* Load CPU's default DSCR */
- ld r0, PACA_DSCR(r13)
+ ld r0, PACA_DSCR_DEFAULT(r13)
mtspr SPRN_DSCR, r0
blr
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 19e4744b6eba..6530f1b8874d 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1377,6 +1377,7 @@ void facility_unavailable_exception(struct pt_regs *regs)
};
char *facility = "unknown";
u64 value;
+ u32 instword, rd;
u8 status;
bool hv;
@@ -1388,12 +1389,46 @@ void facility_unavailable_exception(struct pt_regs *regs)
status = value >> 56;
if (status == FSCR_DSCR_LG) {
- /* User is acessing the DSCR. Set the inherit bit and allow
- * the user to set it directly in future by setting via the
- * FSCR DSCR bit. We always leave HFSCR DSCR set.
+ /*
+ * User is accessing the DSCR register using the problem
+ * state only SPR number (0x03) either through a mfspr or
+ * a mtspr instruction. If it is a write attempt through
+ * a mtspr, then we set the inherit bit. This also allows
+ * the user to write or read the register directly in the
+ * future by setting via the FSCR DSCR bit. But in case it
+ * is a read DSCR attempt through a mfspr instruction, we
+ * just emulate the instruction instead. This code path will
+ * always emulate all the mfspr instructions till the user
+ * has attempted atleast one mtspr instruction. This way it
+ * preserves the same behaviour when the user is accessing
+ * the DSCR through privilege level only SPR number (0x11)
+ * which is emulated through illegal instruction exception.
+ * We always leave HFSCR DSCR set.
*/
- current->thread.dscr_inherit = 1;
- mtspr(SPRN_FSCR, value | FSCR_DSCR);
+ if (get_user(instword, (u32 __user *)(regs->nip))) {
+ pr_err("Failed to fetch the user instruction\n");
+ return;
+ }
+
+ /* Write into DSCR (mtspr 0x03, RS) */
+ if ((instword & PPC_INST_MTSPR_DSCR_USER_MASK)
+ == PPC_INST_MTSPR_DSCR_USER) {
+ rd = (instword >> 21) & 0x1f;
+ current->thread.dscr = regs->gpr[rd];
+ current->thread.dscr_inherit = 1;
+ mtspr(SPRN_FSCR, value | FSCR_DSCR);
+ }
+
+ /* Read from DSCR (mfspr RT, 0x03) */
+ if ((instword & PPC_INST_MFSPR_DSCR_USER_MASK)
+ == PPC_INST_MFSPR_DSCR_USER) {
+ if (emulate_instruction(regs)) {
+ pr_err("DSCR based mfspr emulation failed\n");
+ return;
+ }
+ regs->nip += 4;
+ emulate_single_step(regs);
+ }
return;
}
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 305eb0d9b768..b457bfa28436 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -49,13 +49,16 @@
/* The alignment of the vDSO */
#define VDSO_ALIGNMENT (1 << 16)
-extern char vdso32_start, vdso32_end;
-static void *vdso32_kbase = &vdso32_start;
static unsigned int vdso32_pages;
+static void *vdso32_kbase;
static struct page **vdso32_pagelist;
unsigned long vdso32_sigtramp;
unsigned long vdso32_rt_sigtramp;
+#ifdef CONFIG_VDSO32
+extern char vdso32_start, vdso32_end;
+#endif
+
#ifdef CONFIG_PPC64
extern char vdso64_start, vdso64_end;
static void *vdso64_kbase = &vdso64_start;
@@ -140,50 +143,6 @@ struct lib64_elfinfo
};
-#ifdef __DEBUG
-static void dump_one_vdso_page(struct page *pg, struct page *upg)
-{
- printk("kpg: %p (c:%d,f:%08lx)", __va(page_to_pfn(pg) << PAGE_SHIFT),
- page_count(pg),
- pg->flags);
- if (upg && !IS_ERR(upg) /* && pg != upg*/) {
- printk(" upg: %p (c:%d,f:%08lx)", __va(page_to_pfn(upg)
- << PAGE_SHIFT),
- page_count(upg),
- upg->flags);
- }
- printk("\n");
-}
-
-static void dump_vdso_pages(struct vm_area_struct * vma)
-{
- int i;
-
- if (!vma || is_32bit_task()) {
- printk("vDSO32 @ %016lx:\n", (unsigned long)vdso32_kbase);
- for (i=0; i<vdso32_pages; i++) {
- struct page *pg = virt_to_page(vdso32_kbase +
- i*PAGE_SIZE);
- struct page *upg = (vma && vma->vm_mm) ?
- follow_page(vma, vma->vm_start + i*PAGE_SIZE, 0)
- : NULL;
- dump_one_vdso_page(pg, upg);
- }
- }
- if (!vma || !is_32bit_task()) {
- printk("vDSO64 @ %016lx:\n", (unsigned long)vdso64_kbase);
- for (i=0; i<vdso64_pages; i++) {
- struct page *pg = virt_to_page(vdso64_kbase +
- i*PAGE_SIZE);
- struct page *upg = (vma && vma->vm_mm) ?
- follow_page(vma, vma->vm_start + i*PAGE_SIZE, 0)
- : NULL;
- dump_one_vdso_page(pg, upg);
- }
- }
-}
-#endif /* DEBUG */
-
/*
* This is called from binfmt_elf, we create the special vma for the
* vDSO and insert it into the mm struct tree
@@ -292,6 +251,7 @@ const char *arch_vma_name(struct vm_area_struct *vma)
+#ifdef CONFIG_VDSO32
static void * __init find_section32(Elf32_Ehdr *ehdr, const char *secname,
unsigned long *size)
{
@@ -379,6 +339,20 @@ static int __init vdso_do_func_patch32(struct lib32_elfinfo *v32,
return 0;
}
+#else /* !CONFIG_VDSO32 */
+static unsigned long __init find_function32(struct lib32_elfinfo *lib,
+ const char *symname)
+{
+ return 0;
+}
+
+static int __init vdso_do_func_patch32(struct lib32_elfinfo *v32,
+ struct lib64_elfinfo *v64,
+ const char *orig, const char *fix)
+{
+ return 0;
+}
+#endif /* CONFIG_VDSO32 */
#ifdef CONFIG_PPC64
@@ -489,6 +463,7 @@ static __init int vdso_do_find_sections(struct lib32_elfinfo *v32,
* Locate symbol tables & text section
*/
+#ifdef CONFIG_VDSO32
v32->dynsym = find_section32(v32->hdr, ".dynsym", &v32->dynsymsize);
v32->dynstr = find_section32(v32->hdr, ".dynstr", NULL);
if (v32->dynsym == NULL || v32->dynstr == NULL) {
@@ -501,6 +476,7 @@ static __init int vdso_do_find_sections(struct lib32_elfinfo *v32,
return -1;
}
v32->text = sect - vdso32_kbase;
+#endif
#ifdef CONFIG_PPC64
v64->dynsym = find_section64(v64->hdr, ".dynsym", &v64->dynsymsize);
@@ -537,7 +513,9 @@ static __init void vdso_setup_trampolines(struct lib32_elfinfo *v32,
static __init int vdso_fixup_datapage(struct lib32_elfinfo *v32,
struct lib64_elfinfo *v64)
{
+#ifdef CONFIG_VDSO32
Elf32_Sym *sym32;
+#endif
#ifdef CONFIG_PPC64
Elf64_Sym *sym64;
@@ -552,6 +530,7 @@ static __init int vdso_fixup_datapage(struct lib32_elfinfo *v32,
(sym64->st_value - VDSO64_LBASE);
#endif /* CONFIG_PPC64 */
+#ifdef CONFIG_VDSO32
sym32 = find_symbol32(v32, "__kernel_datapage_offset");
if (sym32 == NULL) {
printk(KERN_ERR "vDSO32: Can't find symbol "
@@ -561,6 +540,7 @@ static __init int vdso_fixup_datapage(struct lib32_elfinfo *v32,
*((int *)(vdso32_kbase + (sym32->st_value - VDSO32_LBASE))) =
(vdso32_pages << PAGE_SHIFT) -
(sym32->st_value - VDSO32_LBASE);
+#endif
return 0;
}
@@ -569,55 +549,54 @@ static __init int vdso_fixup_datapage(struct lib32_elfinfo *v32,
static __init int vdso_fixup_features(struct lib32_elfinfo *v32,
struct lib64_elfinfo *v64)
{
- void *start32;
- unsigned long size32;
+ unsigned long size;
+ void *start;
#ifdef CONFIG_PPC64
- void *start64;
- unsigned long size64;
-
- start64 = find_section64(v64->hdr, "__ftr_fixup", &size64);
- if (start64)
+ start = find_section64(v64->hdr, "__ftr_fixup", &size);
+ if (start)
do_feature_fixups(cur_cpu_spec->cpu_features,
- start64, start64 + size64);
+ start, start + size);
- start64 = find_section64(v64->hdr, "__mmu_ftr_fixup", &size64);
- if (start64)
+ start = find_section64(v64->hdr, "__mmu_ftr_fixup", &size);
+ if (start)
do_feature_fixups(cur_cpu_spec->mmu_features,
- start64, start64 + size64);
+ start, start + size);
- start64 = find_section64(v64->hdr, "__fw_ftr_fixup", &size64);
- if (start64)
+ start = find_section64(v64->hdr, "__fw_ftr_fixup", &size);
+ if (start)
do_feature_fixups(powerpc_firmware_features,
- start64, start64 + size64);
+ start, start + size);
- start64 = find_section64(v64->hdr, "__lwsync_fixup", &size64);
- if (start64)
+ start = find_section64(v64->hdr, "__lwsync_fixup", &size);
+ if (start)
do_lwsync_fixups(cur_cpu_spec->cpu_features,
- start64, start64 + size64);
+ start, start + size);
#endif /* CONFIG_PPC64 */
- start32 = find_section32(v32->hdr, "__ftr_fixup", &size32);
- if (start32)
+#ifdef CONFIG_VDSO32
+ start = find_section32(v32->hdr, "__ftr_fixup", &size);
+ if (start)
do_feature_fixups(cur_cpu_spec->cpu_features,
- start32, start32 + size32);
+ start, start + size);
- start32 = find_section32(v32->hdr, "__mmu_ftr_fixup", &size32);
- if (start32)
+ start = find_section32(v32->hdr, "__mmu_ftr_fixup", &size);
+ if (start)
do_feature_fixups(cur_cpu_spec->mmu_features,
- start32, start32 + size32);
+ start, start + size);
#ifdef CONFIG_PPC64
- start32 = find_section32(v32->hdr, "__fw_ftr_fixup", &size32);
- if (start32)
+ start = find_section32(v32->hdr, "__fw_ftr_fixup", &size);
+ if (start)
do_feature_fixups(powerpc_firmware_features,
- start32, start32 + size32);
+ start, start + size);
#endif /* CONFIG_PPC64 */
- start32 = find_section32(v32->hdr, "__lwsync_fixup", &size32);
- if (start32)
+ start = find_section32(v32->hdr, "__lwsync_fixup", &size);
+ if (start)
do_lwsync_fixups(cur_cpu_spec->cpu_features,
- start32, start32 + size32);
+ start, start + size);
+#endif
return 0;
}
@@ -779,11 +758,15 @@ static int __init vdso_init(void)
#endif /* CONFIG_PPC64 */
+#ifdef CONFIG_VDSO32
+ vdso32_kbase = &vdso32_start;
+
/*
* Calculate the size of the 32 bits vDSO
*/
vdso32_pages = (&vdso32_end - &vdso32_start) >> PAGE_SHIFT;
DBG("vdso32_kbase: %p, 0x%x pages\n", vdso32_kbase, vdso32_pages);
+#endif
/*
@@ -804,6 +787,7 @@ static int __init vdso_init(void)
return 0;
}
+#ifdef CONFIG_VDSO32
/* Make sure pages are in the correct state */
vdso32_pagelist = kzalloc(sizeof(struct page *) * (vdso32_pages + 2),
GFP_KERNEL);
@@ -816,6 +800,7 @@ static int __init vdso_init(void)
}
vdso32_pagelist[i++] = virt_to_page(vdso_data);
vdso32_pagelist[i] = NULL;
+#endif
#ifdef CONFIG_PPC64
vdso64_pagelist = kzalloc(sizeof(struct page *) * (vdso64_pages + 2),
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 5bfdab9047be..5f8dcdaa2820 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -557,11 +557,11 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
struct vio_dev *viodev = to_vio_dev(dev);
struct iommu_table *tbl;
struct scatterlist *sgl;
- int ret, count = 0;
+ int ret, count;
size_t alloc_size = 0;
tbl = get_iommu_table_base(dev);
- for (sgl = sglist; count < nelems; count++, sgl++)
+ for_each_sg(sglist, sgl, nelems, count)
alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE(tbl));
if (vio_cmo_alloc(viodev, alloc_size)) {
@@ -577,7 +577,7 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
return ret;
}
- for (sgl = sglist, count = 0; count < ret; count++, sgl++)
+ for_each_sg(sglist, sgl, ret, count)
alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl));
if (alloc_size)
vio_cmo_dealloc(viodev, alloc_size);
@@ -594,10 +594,10 @@ static void vio_dma_iommu_unmap_sg(struct device *dev,
struct iommu_table *tbl;
struct scatterlist *sgl;
size_t alloc_size = 0;
- int count = 0;
+ int count;
tbl = get_iommu_table_base(dev);
- for (sgl = sglist; count < nelems; count++, sgl++)
+ for_each_sg(sglist, sgl, nelems, count)
alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl));
dma_iommu_ops.unmap_sg(dev, sglist, nelems, direction, attrs);
@@ -1196,6 +1196,11 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
tbl->it_type = TCE_VB;
tbl->it_blocksize = 16;
+ if (firmware_has_feature(FW_FEATURE_LPAR))
+ tbl->it_ops = &iommu_table_lpar_multi_ops;
+ else
+ tbl->it_ops = &iommu_table_pseries_ops;
+
return iommu_init_table(tbl, -1);
}
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index 453a8a47a467..05ea8fc7f829 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -757,16 +757,17 @@ void kvmppc_core_flush_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot)
int kvmppc_core_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
- struct kvm_userspace_memory_region *mem)
+ const struct kvm_userspace_memory_region *mem)
{
return kvm->arch.kvm_ops->prepare_memory_region(kvm, memslot, mem);
}
void kvmppc_core_commit_memory_region(struct kvm *kvm,
- struct kvm_userspace_memory_region *mem,
- const struct kvm_memory_slot *old)
+ const struct kvm_userspace_memory_region *mem,
+ const struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new)
{
- kvm->arch.kvm_ops->commit_memory_region(kvm, mem, old);
+ kvm->arch.kvm_ops->commit_memory_region(kvm, mem, old, new);
}
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 1a4acf8bf4f4..dab68b7af3f2 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -650,7 +650,7 @@ static void kvmppc_rmap_reset(struct kvm *kvm)
int srcu_idx;
srcu_idx = srcu_read_lock(&kvm->srcu);
- slots = kvm->memslots;
+ slots = kvm_memslots(kvm);
kvm_for_each_memslot(memslot, slots) {
/*
* This assumes it is acceptable to lose reference and
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index df81caab7383..68d067ad4222 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -2321,6 +2321,7 @@ static int kvm_vm_ioctl_get_smmu_info_hv(struct kvm *kvm,
static int kvm_vm_ioctl_get_dirty_log_hv(struct kvm *kvm,
struct kvm_dirty_log *log)
{
+ struct kvm_memslots *slots;
struct kvm_memory_slot *memslot;
int r;
unsigned long n;
@@ -2331,7 +2332,8 @@ static int kvm_vm_ioctl_get_dirty_log_hv(struct kvm *kvm,
if (log->slot >= KVM_USER_MEM_SLOTS)
goto out;
- memslot = id_to_memslot(kvm->memslots, log->slot);
+ slots = kvm_memslots(kvm);
+ memslot = id_to_memslot(slots, log->slot);
r = -ENOENT;
if (!memslot->dirty_bitmap)
goto out;
@@ -2374,16 +2376,18 @@ static int kvmppc_core_create_memslot_hv(struct kvm_memory_slot *slot,
static int kvmppc_core_prepare_memory_region_hv(struct kvm *kvm,
struct kvm_memory_slot *memslot,
- struct kvm_userspace_memory_region *mem)
+ const struct kvm_userspace_memory_region *mem)
{
return 0;
}
static void kvmppc_core_commit_memory_region_hv(struct kvm *kvm,
- struct kvm_userspace_memory_region *mem,
- const struct kvm_memory_slot *old)
+ const struct kvm_userspace_memory_region *mem,
+ const struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new)
{
unsigned long npages = mem->memory_size >> PAGE_SHIFT;
+ struct kvm_memslots *slots;
struct kvm_memory_slot *memslot;
if (npages && old->npages) {
@@ -2393,7 +2397,8 @@ static void kvmppc_core_commit_memory_region_hv(struct kvm *kvm,
* since the rmap array starts out as all zeroes,
* i.e. no pages are dirty.
*/
- memslot = id_to_memslot(kvm->memslots, mem->slot);
+ slots = kvm_memslots(kvm);
+ memslot = id_to_memslot(slots, mem->slot);
kvmppc_hv_get_dirty_log(kvm, memslot, NULL);
}
}
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 4d70df26c402..faa86e9c0551 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -324,7 +324,7 @@ kvm_start_guest:
kvm_secondary_got_guest:
/* Set HSTATE_DSCR(r13) to something sensible */
- ld r6, PACA_DSCR(r13)
+ ld r6, PACA_DSCR_DEFAULT(r13)
std r6, HSTATE_DSCR(r13)
/* Order load of vcore, ptid etc. after load of vcpu */
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index f57383941d03..64891b081ad5 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -1530,6 +1530,7 @@ out:
static int kvm_vm_ioctl_get_dirty_log_pr(struct kvm *kvm,
struct kvm_dirty_log *log)
{
+ struct kvm_memslots *slots;
struct kvm_memory_slot *memslot;
struct kvm_vcpu *vcpu;
ulong ga, ga_end;
@@ -1545,7 +1546,8 @@ static int kvm_vm_ioctl_get_dirty_log_pr(struct kvm *kvm,
/* If nothing is dirty, don't bother messing with page tables. */
if (is_dirty) {
- memslot = id_to_memslot(kvm->memslots, log->slot);
+ slots = kvm_memslots(kvm);
+ memslot = id_to_memslot(slots, log->slot);
ga = memslot->base_gfn << PAGE_SHIFT;
ga_end = ga + (memslot->npages << PAGE_SHIFT);
@@ -1571,14 +1573,15 @@ static void kvmppc_core_flush_memslot_pr(struct kvm *kvm,
static int kvmppc_core_prepare_memory_region_pr(struct kvm *kvm,
struct kvm_memory_slot *memslot,
- struct kvm_userspace_memory_region *mem)
+ const struct kvm_userspace_memory_region *mem)
{
return 0;
}
static void kvmppc_core_commit_memory_region_pr(struct kvm *kvm,
- struct kvm_userspace_memory_region *mem,
- const struct kvm_memory_slot *old)
+ const struct kvm_userspace_memory_region *mem,
+ const struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new)
{
return;
}
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 6c1316a15a27..cc5842657161 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -1004,10 +1004,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
break;
}
- local_irq_enable();
-
trace_kvm_exit(exit_nr, vcpu);
- kvm_guest_exit();
+ __kvm_guest_exit();
+
+ local_irq_enable();
run->exit_reason = KVM_EXIT_UNKNOWN;
run->ready_for_interrupt_injection = 1;
@@ -1784,14 +1784,15 @@ int kvmppc_core_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
int kvmppc_core_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
- struct kvm_userspace_memory_region *mem)
+ const struct kvm_userspace_memory_region *mem)
{
return 0;
}
void kvmppc_core_commit_memory_region(struct kvm *kvm,
- struct kvm_userspace_memory_region *mem,
- const struct kvm_memory_slot *old)
+ const struct kvm_userspace_memory_region *mem,
+ const struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new)
{
}
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index ac3ddf115f3d..e5dde32fe71f 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -115,7 +115,7 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
continue;
}
- kvm_guest_enter();
+ __kvm_guest_enter();
return 1;
}
@@ -595,18 +595,19 @@ int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
- struct kvm_userspace_memory_region *mem,
+ const struct kvm_userspace_memory_region *mem,
enum kvm_mr_change change)
{
return kvmppc_core_prepare_memory_region(kvm, memslot, mem);
}
void kvm_arch_commit_memory_region(struct kvm *kvm,
- struct kvm_userspace_memory_region *mem,
+ const struct kvm_userspace_memory_region *mem,
const struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new,
enum kvm_mr_change change)
{
- kvmppc_core_commit_memory_region(kvm, mem, old);
+ kvmppc_core_commit_memory_region(kvm, mem, old, new);
}
void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 7902802a19a5..a47e14277fd8 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -33,6 +33,6 @@ obj-$(CONFIG_PPC_LIB_RHEAP) += rheap.o
obj-$(CONFIG_FTR_FIXUP_SELFTEST) += feature-fixups-test.o
obj-$(CONFIG_ALTIVEC) += xor_vmx.o
-CFLAGS_xor_vmx.o += -maltivec -mabi=altivec
+CFLAGS_xor_vmx.o += -maltivec $(call cc-option,-mabi=altivec)
obj-$(CONFIG_PPC64) += $(obj64-y)
diff --git a/arch/powerpc/lib/vmx-helper.c b/arch/powerpc/lib/vmx-helper.c
index 3cf529ceec5b..ac93a3bd2730 100644
--- a/arch/powerpc/lib/vmx-helper.c
+++ b/arch/powerpc/lib/vmx-helper.c
@@ -27,11 +27,11 @@ int enter_vmx_usercopy(void)
if (in_interrupt())
return 0;
- /* This acts as preempt_disable() as well and will make
- * enable_kernel_altivec(). We need to disable page faults
- * as they can call schedule and thus make us lose the VMX
- * context. So on page faults, we just fail which will cause
- * a fallback to the normal non-vmx copy.
+ preempt_disable();
+ /*
+ * We need to disable page faults as they can call schedule and
+ * thus make us lose the VMX context. So on page faults, we just
+ * fail which will cause a fallback to the normal non-vmx copy.
*/
pagefault_disable();
@@ -47,6 +47,7 @@ int enter_vmx_usercopy(void)
int exit_vmx_usercopy(void)
{
pagefault_enable();
+ preempt_enable();
return 0;
}
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 9c8770b5f96f..3eb73a38220d 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -36,3 +36,4 @@ obj-$(CONFIG_PPC_SUBPAGE_PROT) += subpage-prot.o
obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o
obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_PPC_COPRO_BASE) += copro_fault.o
+obj-$(CONFIG_SPAPR_TCE_IOMMU) += mmu_context_iommu.o
diff --git a/arch/powerpc/mm/copro_fault.c b/arch/powerpc/mm/copro_fault.c
index f031a47d7701..6527882ce05e 100644
--- a/arch/powerpc/mm/copro_fault.c
+++ b/arch/powerpc/mm/copro_fault.c
@@ -26,7 +26,7 @@
#include <asm/reg.h>
#include <asm/copro.h>
#include <asm/spu.h>
-#include <misc/cxl.h>
+#include <misc/cxl-base.h>
/*
* This ought to be kept in sync with the powerpc specific do_page_fault
@@ -100,7 +100,7 @@ EXPORT_SYMBOL_GPL(copro_handle_mm_fault);
int copro_calculate_slb(struct mm_struct *mm, u64 ea, struct copro_slb *slb)
{
- u64 vsid;
+ u64 vsid, vsidkey;
int psize, ssize;
switch (REGION_ID(ea)) {
@@ -109,6 +109,7 @@ int copro_calculate_slb(struct mm_struct *mm, u64 ea, struct copro_slb *slb)
psize = get_slice_psize(mm, ea);
ssize = user_segment_size(ea);
vsid = get_vsid(mm->context.id, ea, ssize);
+ vsidkey = SLB_VSID_USER;
break;
case VMALLOC_REGION_ID:
pr_devel("%s: 0x%llx -- VMALLOC_REGION_ID\n", __func__, ea);
@@ -118,19 +119,21 @@ int copro_calculate_slb(struct mm_struct *mm, u64 ea, struct copro_slb *slb)
psize = mmu_io_psize;
ssize = mmu_kernel_ssize;
vsid = get_kernel_vsid(ea, mmu_kernel_ssize);
+ vsidkey = SLB_VSID_KERNEL;
break;
case KERNEL_REGION_ID:
pr_devel("%s: 0x%llx -- KERNEL_REGION_ID\n", __func__, ea);
psize = mmu_linear_psize;
ssize = mmu_kernel_ssize;
vsid = get_kernel_vsid(ea, mmu_kernel_ssize);
+ vsidkey = SLB_VSID_KERNEL;
break;
default:
pr_debug("%s: invalid region access at %016llx\n", __func__, ea);
return 1;
}
- vsid = (vsid << slb_vsid_shift(ssize)) | SLB_VSID_USER;
+ vsid = (vsid << slb_vsid_shift(ssize)) | vsidkey;
vsid |= mmu_psize_defs[psize].sllp |
((ssize == MMU_SEGSIZE_1T) ? SLB_VSID_B_1T : 0);
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index b396868d2aa7..6d535973b200 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -33,13 +33,13 @@
#include <linux/ratelimit.h>
#include <linux/context_tracking.h>
#include <linux/hugetlb.h>
+#include <linux/uaccess.h>
#include <asm/firmware.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/mmu.h>
#include <asm/mmu_context.h>
-#include <asm/uaccess.h>
#include <asm/tlbflush.h>
#include <asm/siginfo.h>
#include <asm/debug.h>
@@ -272,15 +272,16 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
if (!arch_irq_disabled_regs(regs))
local_irq_enable();
- if (in_atomic() || mm == NULL) {
+ if (faulthandler_disabled() || mm == NULL) {
if (!user_mode(regs)) {
rc = SIGSEGV;
goto bail;
}
- /* in_atomic() in user mode is really bad,
+ /* faulthandler_disabled() in user mode is really bad,
as is current->mm == NULL. */
printk(KERN_EMERG "Page fault in user mode with "
- "in_atomic() = %d mm = %p\n", in_atomic(), mm);
+ "faulthandler_disabled() = %d mm = %p\n",
+ faulthandler_disabled(), mm);
printk(KERN_EMERG "NIP = %lx MSR = %lx\n",
regs->nip, regs->msr);
die("Weird page fault", regs, SIGSEGV);
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 9c4880ddecd6..13befa35d8a8 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -29,7 +29,7 @@
#include <asm/kexec.h>
#include <asm/ppc-opcode.h>
-#include <misc/cxl.h>
+#include <misc/cxl-base.h>
#ifdef DEBUG_LOW
#define DBG_LOW(fmt...) udbg_printf(fmt)
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index fda236f908eb..5ec987f65b2c 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -57,6 +57,7 @@
#include <asm/fadump.h>
#include <asm/firmware.h>
#include <asm/tm.h>
+#include <asm/trace.h>
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -1004,6 +1005,7 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea,
DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n",
ea, access, trap);
+ trace_hash_fault(ea, access, trap);
/* Get region & vsid */
switch (REGION_ID(ea)) {
@@ -1475,7 +1477,7 @@ static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi)
unsigned long hash;
unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize);
unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize);
- unsigned long mode = htab_convert_pte_flags(PAGE_KERNEL);
+ unsigned long mode = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL));
long ret;
hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize);
diff --git a/arch/powerpc/mm/highmem.c b/arch/powerpc/mm/highmem.c
index e7450bdbe83a..e292c8a60952 100644
--- a/arch/powerpc/mm/highmem.c
+++ b/arch/powerpc/mm/highmem.c
@@ -34,7 +34,7 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot)
unsigned long vaddr;
int idx, type;
- /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+ preempt_disable();
pagefault_disable();
if (!PageHighMem(page))
return page_address(page);
@@ -59,6 +59,7 @@ void __kunmap_atomic(void *kvaddr)
if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
pagefault_enable();
+ preempt_enable();
return;
}
@@ -82,5 +83,6 @@ void __kunmap_atomic(void *kvaddr)
kmap_atomic_idx_pop();
pagefault_enable();
+ preempt_enable();
}
EXPORT_SYMBOL(__kunmap_atomic);
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 3385e3d0506e..1f614d778a8b 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -336,7 +336,7 @@ int alloc_bootmem_huge_page(struct hstate *hstate)
unsigned long gpage_npages[MMU_PAGE_COUNT];
static int __init do_gpage_early_setup(char *param, char *val,
- const char *unused)
+ const char *unused, void *arg)
{
static phys_addr_t size;
unsigned long npages;
@@ -385,7 +385,7 @@ void __init reserve_hugetlb_gpages(void)
strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE);
parse_args("hugetlb gpages", cmdline, NULL, 0, 0, 0,
- &do_gpage_early_setup);
+ NULL, &do_gpage_early_setup);
/*
* Walk gpage list in reverse, allocating larger page sizes first.
@@ -439,11 +439,6 @@ int alloc_bootmem_huge_page(struct hstate *hstate)
}
#endif
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
- return 0;
-}
-
#ifdef CONFIG_PPC_FSL_BOOK3E
#define HUGEPD_FREELIST_SIZE \
((PAGE_SIZE - sizeof(struct hugepd_freelist)) / sizeof(pte_t))
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 45fda71feb27..0f11819d8f1d 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -560,7 +560,7 @@ subsys_initcall(add_system_ram_resources);
*/
int devmem_is_allowed(unsigned long pfn)
{
- if (iomem_is_exclusive(pfn << PAGE_SHIFT))
+ if (iomem_is_exclusive(PFN_PHYS(pfn)))
return 0;
if (!page_is_ram(pfn))
return 1;
diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c
index 178876aef40f..4e4efbc2658e 100644
--- a/arch/powerpc/mm/mmu_context_hash64.c
+++ b/arch/powerpc/mm/mmu_context_hash64.c
@@ -89,6 +89,9 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
#ifdef CONFIG_PPC_64K_PAGES
mm->context.pte_frag = NULL;
#endif
+#ifdef CONFIG_SPAPR_TCE_IOMMU
+ mm_iommu_init(&mm->context);
+#endif
return 0;
}
@@ -132,6 +135,9 @@ static inline void destroy_pagetable_page(struct mm_struct *mm)
void destroy_context(struct mm_struct *mm)
{
+#ifdef CONFIG_SPAPR_TCE_IOMMU
+ mm_iommu_cleanup(&mm->context);
+#endif
#ifdef CONFIG_PPC_ICSWX
drop_cop(mm->context.acop, mm);
diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c
new file mode 100644
index 000000000000..da6a2168ae9e
--- /dev/null
+++ b/arch/powerpc/mm/mmu_context_iommu.c
@@ -0,0 +1,316 @@
+/*
+ * IOMMU helpers in MMU context.
+ *
+ * Copyright (C) 2015 IBM Corp. <aik@ozlabs.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/rculist.h>
+#include <linux/vmalloc.h>
+#include <linux/mutex.h>
+#include <asm/mmu_context.h>
+
+static DEFINE_MUTEX(mem_list_mutex);
+
+struct mm_iommu_table_group_mem_t {
+ struct list_head next;
+ struct rcu_head rcu;
+ unsigned long used;
+ atomic64_t mapped;
+ u64 ua; /* userspace address */
+ u64 entries; /* number of entries in hpas[] */
+ u64 *hpas; /* vmalloc'ed */
+};
+
+static long mm_iommu_adjust_locked_vm(struct mm_struct *mm,
+ unsigned long npages, bool incr)
+{
+ long ret = 0, locked, lock_limit;
+
+ if (!npages)
+ return 0;
+
+ down_write(&mm->mmap_sem);
+
+ if (incr) {
+ locked = mm->locked_vm + npages;
+ lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+ if (locked > lock_limit && !capable(CAP_IPC_LOCK))
+ ret = -ENOMEM;
+ else
+ mm->locked_vm += npages;
+ } else {
+ if (WARN_ON_ONCE(npages > mm->locked_vm))
+ npages = mm->locked_vm;
+ mm->locked_vm -= npages;
+ }
+
+ pr_debug("[%d] RLIMIT_MEMLOCK HASH64 %c%ld %ld/%ld\n",
+ current->pid,
+ incr ? '+' : '-',
+ npages << PAGE_SHIFT,
+ mm->locked_vm << PAGE_SHIFT,
+ rlimit(RLIMIT_MEMLOCK));
+ up_write(&mm->mmap_sem);
+
+ return ret;
+}
+
+bool mm_iommu_preregistered(void)
+{
+ if (!current || !current->mm)
+ return false;
+
+ return !list_empty(&current->mm->context.iommu_group_mem_list);
+}
+EXPORT_SYMBOL_GPL(mm_iommu_preregistered);
+
+long mm_iommu_get(unsigned long ua, unsigned long entries,
+ struct mm_iommu_table_group_mem_t **pmem)
+{
+ struct mm_iommu_table_group_mem_t *mem;
+ long i, j, ret = 0, locked_entries = 0;
+ struct page *page = NULL;
+
+ if (!current || !current->mm)
+ return -ESRCH; /* process exited */
+
+ mutex_lock(&mem_list_mutex);
+
+ list_for_each_entry_rcu(mem, &current->mm->context.iommu_group_mem_list,
+ next) {
+ if ((mem->ua == ua) && (mem->entries == entries)) {
+ ++mem->used;
+ *pmem = mem;
+ goto unlock_exit;
+ }
+
+ /* Overlap? */
+ if ((mem->ua < (ua + (entries << PAGE_SHIFT))) &&
+ (ua < (mem->ua +
+ (mem->entries << PAGE_SHIFT)))) {
+ ret = -EINVAL;
+ goto unlock_exit;
+ }
+
+ }
+
+ ret = mm_iommu_adjust_locked_vm(current->mm, entries, true);
+ if (ret)
+ goto unlock_exit;
+
+ locked_entries = entries;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem) {
+ ret = -ENOMEM;
+ goto unlock_exit;
+ }
+
+ mem->hpas = vzalloc(entries * sizeof(mem->hpas[0]));
+ if (!mem->hpas) {
+ kfree(mem);
+ ret = -ENOMEM;
+ goto unlock_exit;
+ }
+
+ for (i = 0; i < entries; ++i) {
+ if (1 != get_user_pages_fast(ua + (i << PAGE_SHIFT),
+ 1/* pages */, 1/* iswrite */, &page)) {
+ for (j = 0; j < i; ++j)
+ put_page(pfn_to_page(
+ mem->hpas[j] >> PAGE_SHIFT));
+ vfree(mem->hpas);
+ kfree(mem);
+ ret = -EFAULT;
+ goto unlock_exit;
+ }
+
+ mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT;
+ }
+
+ atomic64_set(&mem->mapped, 1);
+ mem->used = 1;
+ mem->ua = ua;
+ mem->entries = entries;
+ *pmem = mem;
+
+ list_add_rcu(&mem->next, &current->mm->context.iommu_group_mem_list);
+
+unlock_exit:
+ if (locked_entries && ret)
+ mm_iommu_adjust_locked_vm(current->mm, locked_entries, false);
+
+ mutex_unlock(&mem_list_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mm_iommu_get);
+
+static void mm_iommu_unpin(struct mm_iommu_table_group_mem_t *mem)
+{
+ long i;
+ struct page *page = NULL;
+
+ for (i = 0; i < mem->entries; ++i) {
+ if (!mem->hpas[i])
+ continue;
+
+ page = pfn_to_page(mem->hpas[i] >> PAGE_SHIFT);
+ if (!page)
+ continue;
+
+ put_page(page);
+ mem->hpas[i] = 0;
+ }
+}
+
+static void mm_iommu_do_free(struct mm_iommu_table_group_mem_t *mem)
+{
+
+ mm_iommu_unpin(mem);
+ vfree(mem->hpas);
+ kfree(mem);
+}
+
+static void mm_iommu_free(struct rcu_head *head)
+{
+ struct mm_iommu_table_group_mem_t *mem = container_of(head,
+ struct mm_iommu_table_group_mem_t, rcu);
+
+ mm_iommu_do_free(mem);
+}
+
+static void mm_iommu_release(struct mm_iommu_table_group_mem_t *mem)
+{
+ list_del_rcu(&mem->next);
+ mm_iommu_adjust_locked_vm(current->mm, mem->entries, false);
+ call_rcu(&mem->rcu, mm_iommu_free);
+}
+
+long mm_iommu_put(struct mm_iommu_table_group_mem_t *mem)
+{
+ long ret = 0;
+
+ if (!current || !current->mm)
+ return -ESRCH; /* process exited */
+
+ mutex_lock(&mem_list_mutex);
+
+ if (mem->used == 0) {
+ ret = -ENOENT;
+ goto unlock_exit;
+ }
+
+ --mem->used;
+ /* There are still users, exit */
+ if (mem->used)
+ goto unlock_exit;
+
+ /* Are there still mappings? */
+ if (atomic_cmpxchg(&mem->mapped, 1, 0) != 1) {
+ ++mem->used;
+ ret = -EBUSY;
+ goto unlock_exit;
+ }
+
+ /* @mapped became 0 so now mappings are disabled, release the region */
+ mm_iommu_release(mem);
+
+unlock_exit:
+ mutex_unlock(&mem_list_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mm_iommu_put);
+
+struct mm_iommu_table_group_mem_t *mm_iommu_lookup(unsigned long ua,
+ unsigned long size)
+{
+ struct mm_iommu_table_group_mem_t *mem, *ret = NULL;
+
+ list_for_each_entry_rcu(mem,
+ &current->mm->context.iommu_group_mem_list,
+ next) {
+ if ((mem->ua <= ua) &&
+ (ua + size <= mem->ua +
+ (mem->entries << PAGE_SHIFT))) {
+ ret = mem;
+ break;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mm_iommu_lookup);
+
+struct mm_iommu_table_group_mem_t *mm_iommu_find(unsigned long ua,
+ unsigned long entries)
+{
+ struct mm_iommu_table_group_mem_t *mem, *ret = NULL;
+
+ list_for_each_entry_rcu(mem,
+ &current->mm->context.iommu_group_mem_list,
+ next) {
+ if ((mem->ua == ua) && (mem->entries == entries)) {
+ ret = mem;
+ break;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mm_iommu_find);
+
+long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem,
+ unsigned long ua, unsigned long *hpa)
+{
+ const long entry = (ua - mem->ua) >> PAGE_SHIFT;
+ u64 *va = &mem->hpas[entry];
+
+ if (entry >= mem->entries)
+ return -EFAULT;
+
+ *hpa = *va | (ua & ~PAGE_MASK);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mm_iommu_ua_to_hpa);
+
+long mm_iommu_mapped_inc(struct mm_iommu_table_group_mem_t *mem)
+{
+ if (atomic64_inc_not_zero(&mem->mapped))
+ return 0;
+
+ /* Last mm_iommu_put() has been called, no more mappings allowed() */
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(mm_iommu_mapped_inc);
+
+void mm_iommu_mapped_dec(struct mm_iommu_table_group_mem_t *mem)
+{
+ atomic64_add_unless(&mem->mapped, -1, 1);
+}
+EXPORT_SYMBOL_GPL(mm_iommu_mapped_dec);
+
+void mm_iommu_init(mm_context_t *ctx)
+{
+ INIT_LIST_HEAD_RCU(&ctx->iommu_group_mem_list);
+}
+
+void mm_iommu_cleanup(mm_context_t *ctx)
+{
+ struct mm_iommu_table_group_mem_t *mem, *tmp;
+
+ list_for_each_entry_safe(mem, tmp, &ctx->iommu_group_mem_list, next) {
+ list_del_rcu(&mem->next);
+ mm_iommu_do_free(mem);
+ }
+}
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 6bfadf1aa5cb..876232d64126 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -554,47 +554,42 @@ unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr,
return old;
}
-pmd_t pmdp_clear_flush(struct vm_area_struct *vma, unsigned long address,
- pmd_t *pmdp)
+pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, unsigned long address,
+ pmd_t *pmdp)
{
pmd_t pmd;
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
- if (pmd_trans_huge(*pmdp)) {
- pmd = pmdp_get_and_clear(vma->vm_mm, address, pmdp);
- } else {
- /*
- * khugepaged calls this for normal pmd
- */
- pmd = *pmdp;
- pmd_clear(pmdp);
- /*
- * Wait for all pending hash_page to finish. This is needed
- * in case of subpage collapse. When we collapse normal pages
- * to hugepage, we first clear the pmd, then invalidate all
- * the PTE entries. The assumption here is that any low level
- * page fault will see a none pmd and take the slow path that
- * will wait on mmap_sem. But we could very well be in a
- * hash_page with local ptep pointer value. Such a hash page
- * can result in adding new HPTE entries for normal subpages.
- * That means we could be modifying the page content as we
- * copy them to a huge page. So wait for parallel hash_page
- * to finish before invalidating HPTE entries. We can do this
- * by sending an IPI to all the cpus and executing a dummy
- * function there.
- */
- kick_all_cpus_sync();
- /*
- * Now invalidate the hpte entries in the range
- * covered by pmd. This make sure we take a
- * fault and will find the pmd as none, which will
- * result in a major fault which takes mmap_sem and
- * hence wait for collapse to complete. Without this
- * the __collapse_huge_page_copy can result in copying
- * the old content.
- */
- flush_tlb_pmd_range(vma->vm_mm, &pmd, address);
- }
+ VM_BUG_ON(pmd_trans_huge(*pmdp));
+
+ pmd = *pmdp;
+ pmd_clear(pmdp);
+ /*
+ * Wait for all pending hash_page to finish. This is needed
+ * in case of subpage collapse. When we collapse normal pages
+ * to hugepage, we first clear the pmd, then invalidate all
+ * the PTE entries. The assumption here is that any low level
+ * page fault will see a none pmd and take the slow path that
+ * will wait on mmap_sem. But we could very well be in a
+ * hash_page with local ptep pointer value. Such a hash page
+ * can result in adding new HPTE entries for normal subpages.
+ * That means we could be modifying the page content as we
+ * copy them to a huge page. So wait for parallel hash_page
+ * to finish before invalidating HPTE entries. We can do this
+ * by sending an IPI to all the cpus and executing a dummy
+ * function there.
+ */
+ kick_all_cpus_sync();
+ /*
+ * Now invalidate the hpte entries in the range
+ * covered by pmd. This make sure we take a
+ * fault and will find the pmd as none, which will
+ * result in a major fault which takes mmap_sem and
+ * hence wait for collapse to complete. Without this
+ * the __collapse_huge_page_copy can result in copying
+ * the old content.
+ */
+ flush_tlb_pmd_range(vma->vm_mm, &pmd, address);
return pmd;
}
@@ -817,8 +812,8 @@ void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr,
return;
}
-pmd_t pmdp_get_and_clear(struct mm_struct *mm,
- unsigned long addr, pmd_t *pmdp)
+pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pmd_t *pmdp)
{
pmd_t old_pmd;
pgtable_t pgtable;
diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S
index 89bf95bd63b1..765b419883f2 100644
--- a/arch/powerpc/mm/tlb_low_64e.S
+++ b/arch/powerpc/mm/tlb_low_64e.S
@@ -398,18 +398,18 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_SMT)
rldicl r15,r16,64-PUD_SHIFT+3,64-PUD_INDEX_SIZE-3
clrrdi r15,r15,3
cmpdi cr0,r14,0
- bge tlb_miss_fault_e6500 /* Bad pgd entry or hugepage; bail */
+ bge tlb_miss_huge_e6500 /* Bad pgd entry or hugepage; bail */
ldx r14,r14,r15 /* grab pud entry */
rldicl r15,r16,64-PMD_SHIFT+3,64-PMD_INDEX_SIZE-3
clrrdi r15,r15,3
cmpdi cr0,r14,0
- bge tlb_miss_fault_e6500
+ bge tlb_miss_huge_e6500
ldx r14,r14,r15 /* Grab pmd entry */
mfspr r10,SPRN_MAS0
cmpdi cr0,r14,0
- bge tlb_miss_fault_e6500
+ bge tlb_miss_huge_e6500
/* Now we build the MAS for a 2M indirect page:
*
@@ -428,6 +428,7 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_SMT)
clrrdi r15,r16,21 /* make EA 2M-aligned */
mtspr SPRN_MAS2,r15
+tlb_miss_huge_done_e6500:
lbz r15,TCD_ESEL_NEXT(r11)
lbz r16,TCD_ESEL_MAX(r11)
lbz r14,TCD_ESEL_FIRST(r11)
@@ -456,6 +457,50 @@ END_FTR_SECTION_IFSET(CPU_FTR_SMT)
tlb_epilog_bolted
rfi
+tlb_miss_huge_e6500:
+ beq tlb_miss_fault_e6500
+ li r10,1
+ andi. r15,r14,HUGEPD_SHIFT_MASK@l /* r15 = psize */
+ rldimi r14,r10,63,0 /* Set PD_HUGE */
+ xor r14,r14,r15 /* Clear size bits */
+ ldx r14,0,r14
+
+ /*
+ * Now we build the MAS for a huge page.
+ *
+ * MAS 0 : ESEL needs to be filled by software round-robin
+ * - can be handled by indirect code
+ * MAS 1 : Need to clear IND and set TSIZE
+ * MAS 2,3+7: Needs to be redone similar to non-tablewalk handler
+ */
+
+ subi r15,r15,10 /* Convert psize to tsize */
+ mfspr r10,SPRN_MAS1
+ rlwinm r10,r10,0,~MAS1_IND
+ rlwimi r10,r15,MAS1_TSIZE_SHIFT,MAS1_TSIZE_MASK
+ mtspr SPRN_MAS1,r10
+
+ li r10,-0x400
+ sld r15,r10,r15 /* Generate mask based on size */
+ and r10,r16,r15
+ rldicr r15,r14,64-(PTE_RPN_SHIFT-PAGE_SHIFT),63-PAGE_SHIFT
+ rlwimi r10,r14,32-19,27,31 /* Insert WIMGE */
+ clrldi r15,r15,PAGE_SHIFT /* Clear crap at the top */
+ rlwimi r15,r14,32-8,22,25 /* Move in U bits */
+ mtspr SPRN_MAS2,r10
+ andi. r10,r14,_PAGE_DIRTY
+ rlwimi r15,r14,32-2,26,31 /* Move in BAP bits */
+
+ /* Mask out SW and UW if !DIRTY (XXX optimize this !) */
+ bne 1f
+ li r10,MAS3_SW|MAS3_UW
+ andc r15,r15,r10
+1:
+ mtspr SPRN_MAS7_MAS3,r15
+
+ mfspr r10,SPRN_MAS0
+ b tlb_miss_huge_done_e6500
+
tlb_miss_kernel_e6500:
ld r14,PACA_KERNELPGD(r13)
cmpldi cr1,r15,8 /* Check for vmalloc region */
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index cbd3d069897f..723a099f6be3 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -217,7 +217,7 @@ static DEFINE_RAW_SPINLOCK(tlbivax_lock);
static int mm_is_core_local(struct mm_struct *mm)
{
return cpumask_subset(mm_cpumask(mm),
- topology_thread_cpumask(smp_processor_id()));
+ topology_sibling_cpumask(smp_processor_id()));
}
struct tlb_flush_param {
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 12b638425bb9..d90893b76e7c 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -131,7 +131,16 @@ static void pmao_restore_workaround(bool ebb) { }
static bool regs_use_siar(struct pt_regs *regs)
{
- return !!regs->result;
+ /*
+ * When we take a performance monitor exception the regs are setup
+ * using perf_read_regs() which overloads some fields, in particular
+ * regs->result to tell us whether to use SIAR.
+ *
+ * However if the regs are from another exception, eg. a syscall, then
+ * they have not been setup using perf_read_regs() and so regs->result
+ * is something random.
+ */
+ return ((TRAP(regs) == 0xf00) && regs->result);
}
/*
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
index c949ca055712..63016621aff8 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
@@ -193,7 +193,7 @@ static struct irq_chip mpc52xx_gpt_irq_chip = {
void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc)
{
- struct mpc52xx_gpt_priv *gpt = irq_get_handler_data(virq);
+ struct mpc52xx_gpt_priv *gpt = irq_desc_get_handler_data(desc);
int sub_virq;
u32 status;
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
index e2d401ad8fbb..6eb3b2abae90 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -12,7 +12,7 @@
#undef DEBUG
-#include <asm/pci.h>
+#include <linux/pci.h>
#include <asm/mpc52xx.h>
#include <asm/delay.h>
#include <asm/machdep.h>
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 2fb4b24368a6..97915feffd42 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -282,7 +282,7 @@ config CORENET_GENERIC
For 64bit kernel, the following boards are supported:
T208x QDS/RDB, T4240 QDS/RDB and B4 QDS
The following boards are supported for both 32bit and 64bit kernel:
- P5020 DS, P5040 DS and T104xQDS/RDB
+ P5020 DS, P5040 DS, T102x QDS/RDB, T104x QDS/RDB
endif # FSL_SOC_BOOKE
diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
index 9824d2cf79bd..bd839dc287fe 100644
--- a/arch/powerpc/platforms/85xx/corenet_generic.c
+++ b/arch/powerpc/platforms/85xx/corenet_generic.c
@@ -150,6 +150,9 @@ static const char * const boards[] __initconst = {
"fsl,B4860QDS",
"fsl,B4420QDS",
"fsl,B4220QDS",
+ "fsl,T1023RDB",
+ "fsl,T1024QDS",
+ "fsl,T1024RDB",
"fsl,T1040QDS",
"fsl,T1042QDS",
"fsl,T1040RDB",
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 8631ac5f0e57..b8b821697910 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -345,6 +345,7 @@ void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary)
local_irq_disable();
if (secondary) {
+ __flush_disable_L1();
atomic_inc(&kexec_down_cpus);
/* loop forever */
while (1);
@@ -357,61 +358,11 @@ static void mpc85xx_smp_kexec_down(void *arg)
ppc_md.kexec_cpu_down(0,1);
}
-static void map_and_flush(unsigned long paddr)
-{
- struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
- unsigned long kaddr = (unsigned long)kmap_atomic(page);
-
- flush_dcache_range(kaddr, kaddr + PAGE_SIZE);
- kunmap_atomic((void *)kaddr);
-}
-
-/**
- * Before we reset the other cores, we need to flush relevant cache
- * out to memory so we don't get anything corrupted, some of these flushes
- * are performed out of an overabundance of caution as interrupts are not
- * disabled yet and we can switch cores
- */
-static void mpc85xx_smp_flush_dcache_kexec(struct kimage *image)
-{
- kimage_entry_t *ptr, entry;
- unsigned long paddr;
- int i;
-
- if (image->type == KEXEC_TYPE_DEFAULT) {
- /* normal kexec images are stored in temporary pages */
- for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE);
- ptr = (entry & IND_INDIRECTION) ?
- phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
- if (!(entry & IND_DESTINATION)) {
- map_and_flush(entry);
- }
- }
- /* flush out last IND_DONE page */
- map_and_flush(entry);
- } else {
- /* crash type kexec images are copied to the crash region */
- for (i = 0; i < image->nr_segments; i++) {
- struct kexec_segment *seg = &image->segment[i];
- for (paddr = seg->mem; paddr < seg->mem + seg->memsz;
- paddr += PAGE_SIZE) {
- map_and_flush(paddr);
- }
- }
- }
-
- /* also flush the kimage struct to be passed in as well */
- flush_dcache_range((unsigned long)image,
- (unsigned long)image + sizeof(*image));
-}
-
static void mpc85xx_smp_machine_kexec(struct kimage *image)
{
int timeout = INT_MAX;
int i, num_cpus = num_present_cpus();
- mpc85xx_smp_flush_dcache_kexec(image);
-
if (image->type == KEXEC_TYPE_DEFAULT)
smp_call_function(mpc85xx_smp_kexec_down, NULL, 0);
diff --git a/arch/powerpc/platforms/85xx/twr_p102x.c b/arch/powerpc/platforms/85xx/twr_p102x.c
index 1eadb6d0dc64..30e002f4648c 100644
--- a/arch/powerpc/platforms/85xx/twr_p102x.c
+++ b/arch/powerpc/platforms/85xx/twr_p102x.c
@@ -79,7 +79,7 @@ static void __init twr_p1025_setup_arch(void)
mpc85xx_qe_init();
mpc85xx_qe_par_io_init();
-#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE)
+#if IS_ENABLED(CONFIG_UCC_GETH) || IS_ENABLED(CONFIG_SERIAL_QE)
if (machine_is(twr_p1025)) {
struct ccsr_guts __iomem *guts;
@@ -101,7 +101,7 @@ static void __init twr_p1025_setup_arch(void)
MPC85xx_PMUXCR_QE(12));
iounmap(guts);
-#if defined(CONFIG_SERIAL_QE)
+#if IS_ENABLED(CONFIG_SERIAL_QE)
/* On P1025TWR board, the UCC7 acted as UART port.
* However, The UCC7's CTS pin is low level in default,
* it will impact the transmission in full duplex
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 7264e91190be..c140e94c7c72 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -405,6 +405,16 @@ config PPC_DOORBELL
endmenu
+config VDSO32
+ def_bool y
+ depends on PPC32 || CPU_BIG_ENDIAN
+ help
+ This symbol controls whether we build the 32-bit VDSO. We obviously
+ want to do that if we're building a 32-bit kernel. If we're building
+ a 64-bit kernel then we only want a 32-bit VDSO if we're building for
+ big endian. That is because the only little endian configuration we
+ support is ppc64le which is 64-bit only.
+
choice
prompt "Endianness selection"
default CPU_BIG_ENDIAN
@@ -421,6 +431,7 @@ config CPU_BIG_ENDIAN
config CPU_LITTLE_ENDIAN
bool "Build little endian kernel"
+ depends on PPC_BOOK3S_64
select PPC64_BOOT_WRAPPER
help
Build a little endian kernel.
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index 623bd961465a..fe51de4fcf13 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -22,6 +22,7 @@
#include <asm/machdep.h>
#include <asm/prom.h>
+#include "cell.h"
/*
* MSIC registers, specified as offsets from dcr_base
@@ -95,7 +96,7 @@ static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
- struct axon_msic *msic = irq_get_handler_data(irq);
+ struct axon_msic *msic = irq_desc_get_handler_data(desc);
u32 write_offset, msi;
int idx;
int retry = 0;
@@ -406,8 +407,8 @@ static int axon_msi_probe(struct platform_device *device)
dev_set_drvdata(&device->dev, msic);
- ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
+ cell_pci_controller_ops.setup_msi_irqs = axon_msi_setup_msi_irqs;
+ cell_pci_controller_ops.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
axon_msi_debug_setup(dn, msic);
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 21b502398bf3..14a582b21274 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -466,6 +466,11 @@ static inline u32 cell_iommu_get_ioid(struct device_node *np)
return *ioid;
}
+static struct iommu_table_ops cell_iommu_ops = {
+ .set = tce_build_cell,
+ .clear = tce_free_cell
+};
+
static struct iommu_window * __init
cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
unsigned long offset, unsigned long size,
@@ -492,6 +497,7 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
window->table.it_offset =
(offset >> window->table.it_page_shift) + pte_offset;
window->table.it_size = size >> window->table.it_page_shift;
+ window->table.it_ops = &cell_iommu_ops;
iommu_init_table(&window->table, iommu->nid);
@@ -1201,8 +1207,6 @@ static int __init cell_iommu_init(void)
/* Setup various callbacks */
cell_pci_controller_ops.dma_dev_setup = cell_pci_dma_dev_setup;
ppc_md.dma_get_required_mask = cell_dma_get_required_mask;
- ppc_md.tce_build = tce_build_cell;
- ppc_md.tce_free = tce_free_cell;
if (!iommu_fixed_disabled && cell_iommu_fixed_mapping_init() == 0)
goto bail;
diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
index c269caee58f9..9dd154d6f89a 100644
--- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
+++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
@@ -124,7 +124,7 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq,
struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
- struct irq_domain *irq_domain = irq_get_handler_data(cascade_virq);
+ struct irq_domain *irq_domain = irq_desc_get_handler_data(desc);
unsigned int virq;
raw_spin_lock(&desc->lock);
diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile
index 8e8d4cae5ebe..60b4e0fd9808 100644
--- a/arch/powerpc/platforms/pasemi/Makefile
+++ b/arch/powerpc/platforms/pasemi/Makefile
@@ -1,2 +1,3 @@
obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o dma_lib.o misc.o
obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o
+obj-$(CONFIG_PCI_MSI) += msi.o
diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c
index b8f567b2ea19..c929644e74a6 100644
--- a/arch/powerpc/platforms/pasemi/iommu.c
+++ b/arch/powerpc/platforms/pasemi/iommu.c
@@ -134,6 +134,10 @@ static void iobmap_free(struct iommu_table *tbl, long index,
}
}
+static struct iommu_table_ops iommu_table_iobmap_ops = {
+ .set = iobmap_build,
+ .clear = iobmap_free
+};
static void iommu_table_iobmap_setup(void)
{
@@ -153,6 +157,7 @@ static void iommu_table_iobmap_setup(void)
* Should probably be 8 (64 bytes)
*/
iommu_table_iobmap.it_blocksize = 4;
+ iommu_table_iobmap.it_ops = &iommu_table_iobmap_ops;
iommu_init_table(&iommu_table_iobmap, 0);
pr_debug(" <- %s\n", __func__);
}
@@ -252,8 +257,6 @@ void __init iommu_init_early_pasemi(void)
pasemi_pci_controller_ops.dma_dev_setup = pci_dma_dev_setup_pasemi;
pasemi_pci_controller_ops.dma_bus_setup = pci_dma_bus_setup_pasemi;
- ppc_md.tce_build = iobmap_build;
- ppc_md.tce_free = iobmap_free;
set_pci_dma_ops(&dma_iommu_ops);
}
diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/platforms/pasemi/msi.c
index a3f660eed6de..27f2b187a91b 100644
--- a/arch/powerpc/sysdev/mpic_pasemi_msi.c
+++ b/arch/powerpc/platforms/pasemi/msi.c
@@ -13,8 +13,6 @@
*
*/
-#undef DEBUG
-
#include <linux/irq.h>
#include <linux/msi.h>
#include <asm/mpic.h>
@@ -23,7 +21,7 @@
#include <asm/ppc-pci.h>
#include <asm/msi_bitmap.h>
-#include "mpic.h"
+#include <sysdev/mpic.h>
/* Allocate 16 interrupts per device, to give an alignment of 16,
* since that's the size of the grouping w.r.t. affinity. If someone
@@ -144,6 +142,7 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
int mpic_pasemi_msi_init(struct mpic *mpic)
{
int rc;
+ struct pci_controller *phb;
if (!mpic->irqhost->of_node ||
!of_device_is_compatible(mpic->irqhost->of_node,
@@ -159,9 +158,11 @@ int mpic_pasemi_msi_init(struct mpic *mpic)
pr_debug("pasemi_msi: Registering PA Semi MPIC MSI callbacks\n");
msi_mpic = mpic;
- WARN_ON(ppc_md.setup_msi_irqs);
- ppc_md.setup_msi_irqs = pasemi_msi_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = pasemi_msi_teardown_msi_irqs;
+ list_for_each_entry(phb, &hose_list, list_node) {
+ WARN_ON(phb->controller_ops.setup_msi_irqs);
+ phb->controller_ops.setup_msi_irqs = pasemi_msi_setup_msi_irqs;
+ phb->controller_ops.teardown_msi_irqs = pasemi_msi_teardown_msi_irqs;
+ }
return 0;
}
diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig
index 4b044d8cb49a..604190cab522 100644
--- a/arch/powerpc/platforms/powernv/Kconfig
+++ b/arch/powerpc/platforms/powernv/Kconfig
@@ -19,3 +19,10 @@ config PPC_POWERNV
select CPU_FREQ_GOV_CONSERVATIVE
select PPC_DOORBELL
default y
+
+config OPAL_PRD
+ tristate 'OPAL PRD driver'
+ depends on PPC_POWERNV
+ help
+ This enables the opal-prd driver, a facility to run processor
+ recovery diagnostics on OpenPower machines
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index 33e44f37212f..1c8cdb6250e7 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -1,7 +1,7 @@
-obj-y += setup.o opal-wrappers.o opal.o opal-async.o
+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
+obj-y += opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
obj-$(CONFIG_SMP) += smp.o subcore.o subcore-asm.o
obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o
@@ -9,3 +9,4 @@ obj-$(CONFIG_EEH) += eeh-powernv.o
obj-$(CONFIG_PPC_SCOM) += opal-xscom.o
obj-$(CONFIG_MEMORY_FAILURE) += opal-memory-errors.o
obj-$(CONFIG_TRACEPOINTS) += opal-tracepoints.o
+obj-$(CONFIG_OPAL_PRD) += opal-prd.o
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
index ce738ab3d5a9..5cf5e6ea213b 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/msi.h>
#include <linux/of.h>
@@ -40,6 +41,7 @@
#include "pci.h"
static bool pnv_eeh_nb_init = false;
+static int eeh_event_irq = -EINVAL;
/**
* pnv_eeh_init - EEH platform dependent initialization
@@ -88,34 +90,22 @@ static int pnv_eeh_init(void)
return 0;
}
-static int pnv_eeh_event(struct notifier_block *nb,
- unsigned long events, void *change)
+static irqreturn_t pnv_eeh_event(int irq, void *data)
{
- uint64_t changed_evts = (uint64_t)change;
-
/*
- * We simply send special EEH event if EEH has
- * been enabled, or clear pending events in
- * case that we enable EEH soon
+ * We simply send a special EEH event if EEH has been
+ * enabled. We don't care about EEH events until we've
+ * finished processing the outstanding ones. Event processing
+ * gets unmasked in next_error() if EEH is enabled.
*/
- if (!(changed_evts & OPAL_EVENT_PCI_ERROR) ||
- !(events & OPAL_EVENT_PCI_ERROR))
- return 0;
+ disable_irq_nosync(irq);
if (eeh_enabled())
eeh_send_failure_event(NULL);
- else
- opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul);
- return 0;
+ return IRQ_HANDLED;
}
-static struct notifier_block pnv_eeh_nb = {
- .notifier_call = pnv_eeh_event,
- .next = NULL,
- .priority = 0
-};
-
#ifdef CONFIG_DEBUG_FS
static ssize_t pnv_eeh_ei_write(struct file *filp,
const char __user *user_buf,
@@ -237,16 +227,28 @@ static int pnv_eeh_post_init(void)
/* Register OPAL event notifier */
if (!pnv_eeh_nb_init) {
- ret = opal_notifier_register(&pnv_eeh_nb);
- if (ret) {
- pr_warn("%s: Can't register OPAL event notifier (%d)\n",
- __func__, ret);
+ eeh_event_irq = opal_event_request(ilog2(OPAL_EVENT_PCI_ERROR));
+ if (eeh_event_irq < 0) {
+ pr_err("%s: Can't register OPAL event interrupt (%d)\n",
+ __func__, eeh_event_irq);
+ return eeh_event_irq;
+ }
+
+ ret = request_irq(eeh_event_irq, pnv_eeh_event,
+ IRQ_TYPE_LEVEL_HIGH, "opal-eeh", NULL);
+ if (ret < 0) {
+ irq_dispose_mapping(eeh_event_irq);
+ pr_err("%s: Can't request OPAL event interrupt (%d)\n",
+ __func__, eeh_event_irq);
return ret;
}
pnv_eeh_nb_init = true;
}
+ if (!eeh_enabled())
+ disable_irq(eeh_event_irq);
+
list_for_each_entry(hose, &hose_list, list_node) {
phb = hose->private_data;
@@ -979,7 +981,7 @@ static int pnv_eeh_reset(struct eeh_pe *pe, int option)
/**
* pnv_eeh_wait_state - Wait for PE state
* @pe: EEH PE
- * @max_wait: maximal period in microsecond
+ * @max_wait: maximal period in millisecond
*
* Wait for the state of associated PE. It might take some time
* to retrieve the PE's state.
@@ -1000,13 +1002,13 @@ static int pnv_eeh_wait_state(struct eeh_pe *pe, int max_wait)
if (ret != EEH_STATE_UNAVAILABLE)
return ret;
- max_wait -= mwait;
if (max_wait <= 0) {
pr_warn("%s: Timeout getting PE#%x's state (%d)\n",
__func__, pe->addr, max_wait);
return EEH_STATE_NOT_SUPPORT;
}
+ max_wait -= mwait;
msleep(mwait);
}
@@ -1303,12 +1305,10 @@ static int pnv_eeh_next_error(struct eeh_pe **pe)
int state, ret = EEH_NEXT_ERR_NONE;
/*
- * While running here, it's safe to purge the event queue.
- * And we should keep the cached OPAL notifier event sychronized
- * between the kernel and firmware.
+ * While running here, it's safe to purge the event queue. The
+ * event should still be masked.
*/
eeh_remove_event(NULL, false);
- opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul);
list_for_each_entry(hose, &hose_list, list_node) {
/*
@@ -1477,6 +1477,10 @@ static int pnv_eeh_next_error(struct eeh_pe **pe)
break;
}
+ /* Unmask the event */
+ if (eeh_enabled())
+ enable_irq(eeh_event_irq);
+
return ret;
}
diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c
new file mode 100644
index 000000000000..59d735d2e5c0
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/idle.c
@@ -0,0 +1,293 @@
+/*
+ * PowerNV cpuidle code
+ *
+ * Copyright 2015 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/types.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/device.h>
+#include <linux/cpu.h>
+
+#include <asm/firmware.h>
+#include <asm/machdep.h>
+#include <asm/opal.h>
+#include <asm/cputhreads.h>
+#include <asm/cpuidle.h>
+#include <asm/code-patching.h>
+#include <asm/smp.h>
+
+#include "powernv.h"
+#include "subcore.h"
+
+static u32 supported_cpuidle_states;
+
+int pnv_save_sprs_for_winkle(void)
+{
+ int cpu;
+ int rc;
+
+ /*
+ * hid0, hid1, hid4, hid5, hmeer and lpcr values are symmetric accross
+ * all cpus at boot. Get these reg values of current cpu and use the
+ * same accross all cpus.
+ */
+ uint64_t lpcr_val = mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1;
+ uint64_t hid0_val = mfspr(SPRN_HID0);
+ uint64_t hid1_val = mfspr(SPRN_HID1);
+ uint64_t hid4_val = mfspr(SPRN_HID4);
+ uint64_t hid5_val = mfspr(SPRN_HID5);
+ uint64_t hmeer_val = mfspr(SPRN_HMEER);
+
+ for_each_possible_cpu(cpu) {
+ uint64_t pir = get_hard_smp_processor_id(cpu);
+ uint64_t hsprg0_val = (uint64_t)&paca[cpu];
+
+ /*
+ * HSPRG0 is used to store the cpu's pointer to paca. Hence last
+ * 3 bits are guaranteed to be 0. Program slw to restore HSPRG0
+ * with 63rd bit set, so that when a thread wakes up at 0x100 we
+ * can use this bit to distinguish between fastsleep and
+ * deep winkle.
+ */
+ hsprg0_val |= 1;
+
+ rc = opal_slw_set_reg(pir, SPRN_HSPRG0, hsprg0_val);
+ if (rc != 0)
+ return rc;
+
+ rc = opal_slw_set_reg(pir, SPRN_LPCR, lpcr_val);
+ if (rc != 0)
+ return rc;
+
+ /* HIDs are per core registers */
+ if (cpu_thread_in_core(cpu) == 0) {
+
+ rc = opal_slw_set_reg(pir, SPRN_HMEER, hmeer_val);
+ if (rc != 0)
+ return rc;
+
+ rc = opal_slw_set_reg(pir, SPRN_HID0, hid0_val);
+ if (rc != 0)
+ return rc;
+
+ rc = opal_slw_set_reg(pir, SPRN_HID1, hid1_val);
+ if (rc != 0)
+ return rc;
+
+ rc = opal_slw_set_reg(pir, SPRN_HID4, hid4_val);
+ if (rc != 0)
+ return rc;
+
+ rc = opal_slw_set_reg(pir, SPRN_HID5, hid5_val);
+ if (rc != 0)
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static void pnv_alloc_idle_core_states(void)
+{
+ int i, j;
+ int nr_cores = cpu_nr_cores();
+ u32 *core_idle_state;
+
+ /*
+ * core_idle_state - First 8 bits track the idle state of each thread
+ * of the core. The 8th bit is the lock bit. Initially all thread bits
+ * are set. They are cleared when the thread enters deep idle state
+ * like sleep and winkle. Initially the lock bit is cleared.
+ * The lock bit has 2 purposes
+ * a. While the first thread is restoring core state, it prevents
+ * other threads in the core from switching to process context.
+ * b. While the last thread in the core is saving the core state, it
+ * prevents a different thread from waking up.
+ */
+ for (i = 0; i < nr_cores; i++) {
+ int first_cpu = i * threads_per_core;
+ int node = cpu_to_node(first_cpu);
+
+ core_idle_state = kmalloc_node(sizeof(u32), GFP_KERNEL, node);
+ *core_idle_state = PNV_CORE_IDLE_THREAD_BITS;
+
+ for (j = 0; j < threads_per_core; j++) {
+ int cpu = first_cpu + j;
+
+ paca[cpu].core_idle_state_ptr = core_idle_state;
+ paca[cpu].thread_idle_state = PNV_THREAD_RUNNING;
+ paca[cpu].thread_mask = 1 << j;
+ }
+ }
+
+ update_subcore_sibling_mask();
+
+ if (supported_cpuidle_states & OPAL_PM_WINKLE_ENABLED)
+ pnv_save_sprs_for_winkle();
+}
+
+u32 pnv_get_supported_cpuidle_states(void)
+{
+ return supported_cpuidle_states;
+}
+EXPORT_SYMBOL_GPL(pnv_get_supported_cpuidle_states);
+
+
+static void pnv_fastsleep_workaround_apply(void *info)
+
+{
+ int rc;
+ int *err = info;
+
+ rc = opal_config_cpu_idle_state(OPAL_CONFIG_IDLE_FASTSLEEP,
+ OPAL_CONFIG_IDLE_APPLY);
+ if (rc)
+ *err = 1;
+}
+
+/*
+ * Used to store fastsleep workaround state
+ * 0 - Workaround applied/undone at fastsleep entry/exit path (Default)
+ * 1 - Workaround applied once, never undone.
+ */
+static u8 fastsleep_workaround_applyonce;
+
+static ssize_t show_fastsleep_workaround_applyonce(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", fastsleep_workaround_applyonce);
+}
+
+static ssize_t store_fastsleep_workaround_applyonce(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ cpumask_t primary_thread_mask;
+ int err;
+ u8 val;
+
+ if (kstrtou8(buf, 0, &val) || val != 1)
+ return -EINVAL;
+
+ if (fastsleep_workaround_applyonce == 1)
+ return count;
+
+ /*
+ * fastsleep_workaround_applyonce = 1 implies
+ * fastsleep workaround needs to be left in 'applied' state on all
+ * the cores. Do this by-
+ * 1. Patching out the call to 'undo' workaround in fastsleep exit path
+ * 2. Sending ipi to all the cores which have atleast one online thread
+ * 3. Patching out the call to 'apply' workaround in fastsleep entry
+ * path
+ * There is no need to send ipi to cores which have all threads
+ * offlined, as last thread of the core entering fastsleep or deeper
+ * state would have applied workaround.
+ */
+ err = patch_instruction(
+ (unsigned int *)pnv_fastsleep_workaround_at_exit,
+ PPC_INST_NOP);
+ if (err) {
+ pr_err("fastsleep_workaround_applyonce change failed while patching pnv_fastsleep_workaround_at_exit");
+ goto fail;
+ }
+
+ get_online_cpus();
+ primary_thread_mask = cpu_online_cores_map();
+ on_each_cpu_mask(&primary_thread_mask,
+ pnv_fastsleep_workaround_apply,
+ &err, 1);
+ put_online_cpus();
+ if (err) {
+ pr_err("fastsleep_workaround_applyonce change failed while running pnv_fastsleep_workaround_apply");
+ goto fail;
+ }
+
+ err = patch_instruction(
+ (unsigned int *)pnv_fastsleep_workaround_at_entry,
+ PPC_INST_NOP);
+ if (err) {
+ pr_err("fastsleep_workaround_applyonce change failed while patching pnv_fastsleep_workaround_at_entry");
+ goto fail;
+ }
+
+ fastsleep_workaround_applyonce = 1;
+
+ return count;
+fail:
+ return -EIO;
+}
+
+static DEVICE_ATTR(fastsleep_workaround_applyonce, 0600,
+ show_fastsleep_workaround_applyonce,
+ store_fastsleep_workaround_applyonce);
+
+static int __init pnv_init_idle_states(void)
+{
+ struct device_node *power_mgt;
+ int dt_idle_states;
+ u32 *flags;
+ int i;
+
+ supported_cpuidle_states = 0;
+
+ if (cpuidle_disable != IDLE_NO_OVERRIDE)
+ goto out;
+
+ if (!firmware_has_feature(FW_FEATURE_OPALv3))
+ goto out;
+
+ power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
+ if (!power_mgt) {
+ pr_warn("opal: PowerMgmt Node not found\n");
+ goto out;
+ }
+ dt_idle_states = of_property_count_u32_elems(power_mgt,
+ "ibm,cpu-idle-state-flags");
+ if (dt_idle_states < 0) {
+ pr_warn("cpuidle-powernv: no idle states found in the DT\n");
+ goto out;
+ }
+
+ flags = kzalloc(sizeof(*flags) * dt_idle_states, GFP_KERNEL);
+ if (of_property_read_u32_array(power_mgt,
+ "ibm,cpu-idle-state-flags", flags, dt_idle_states)) {
+ pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-flags in DT\n");
+ goto out_free;
+ }
+
+ for (i = 0; i < dt_idle_states; i++)
+ supported_cpuidle_states |= flags[i];
+
+ if (!(supported_cpuidle_states & OPAL_PM_SLEEP_ENABLED_ER1)) {
+ patch_instruction(
+ (unsigned int *)pnv_fastsleep_workaround_at_entry,
+ PPC_INST_NOP);
+ patch_instruction(
+ (unsigned int *)pnv_fastsleep_workaround_at_exit,
+ PPC_INST_NOP);
+ } else {
+ /*
+ * OPAL_PM_SLEEP_ENABLED_ER1 is set. It indicates that
+ * workaround is needed to use fastsleep. Provide sysfs
+ * control to choose how this workaround has to be applied.
+ */
+ device_create_file(cpu_subsys.dev_root,
+ &dev_attr_fastsleep_workaround_applyonce);
+ }
+
+ pnv_alloc_idle_core_states();
+out_free:
+ kfree(flags);
+out:
+ return 0;
+}
+machine_subsys_initcall(powernv, pnv_init_idle_states);
diff --git a/arch/powerpc/platforms/powernv/opal-async.c b/arch/powerpc/platforms/powernv/opal-async.c
index 693b6cdac691..bdc8c0c71d15 100644
--- a/arch/powerpc/platforms/powernv/opal-async.c
+++ b/arch/powerpc/platforms/powernv/opal-async.c
@@ -151,7 +151,7 @@ static struct notifier_block opal_async_comp_nb = {
.priority = 0,
};
-static int __init opal_async_comp_init(void)
+int __init opal_async_comp_init(void)
{
struct device_node *opal_node;
const __be32 *async;
@@ -205,4 +205,3 @@ out_opal_node:
out:
return err;
}
-machine_subsys_initcall(powernv, opal_async_comp_init);
diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c
index 5aa9c1ce4de3..2ee96431f736 100644
--- a/arch/powerpc/platforms/powernv/opal-dump.c
+++ b/arch/powerpc/platforms/powernv/opal-dump.c
@@ -15,6 +15,7 @@
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <asm/opal.h>
@@ -60,7 +61,7 @@ static ssize_t dump_type_show(struct dump_obj *dump_obj,
struct dump_attribute *attr,
char *buf)
{
-
+
return sprintf(buf, "0x%x %s\n", dump_obj->type,
dump_type_to_string(dump_obj->type));
}
@@ -363,7 +364,7 @@ static struct dump_obj *create_dump_obj(uint32_t id, size_t size,
return dump;
}
-static int process_dump(void)
+static irqreturn_t process_dump(int irq, void *data)
{
int rc;
uint32_t dump_id, dump_size, dump_type;
@@ -387,45 +388,13 @@ static int process_dump(void)
if (!dump)
return -1;
- return 0;
-}
-
-static void dump_work_fn(struct work_struct *work)
-{
- process_dump();
+ return IRQ_HANDLED;
}
-static DECLARE_WORK(dump_work, dump_work_fn);
-
-static void schedule_process_dump(void)
-{
- schedule_work(&dump_work);
-}
-
-/*
- * New dump available notification
- *
- * Once we get notification, we add sysfs entries for it.
- * We only fetch the dump on demand, and create sysfs asynchronously.
- */
-static int dump_event(struct notifier_block *nb,
- unsigned long events, void *change)
-{
- if (events & OPAL_EVENT_DUMP_AVAIL)
- schedule_process_dump();
-
- return 0;
-}
-
-static struct notifier_block dump_nb = {
- .notifier_call = dump_event,
- .next = NULL,
- .priority = 0
-};
-
void __init opal_platform_dump_init(void)
{
int rc;
+ int dump_irq;
/* ELOG not supported by firmware */
if (!opal_check_token(OPAL_DUMP_READ))
@@ -445,10 +414,19 @@ void __init opal_platform_dump_init(void)
return;
}
- rc = opal_notifier_register(&dump_nb);
+ dump_irq = opal_event_request(ilog2(OPAL_EVENT_DUMP_AVAIL));
+ if (!dump_irq) {
+ pr_err("%s: Can't register OPAL event irq (%d)\n",
+ __func__, dump_irq);
+ return;
+ }
+
+ rc = request_threaded_irq(dump_irq, NULL, process_dump,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "opal-dump", NULL);
if (rc) {
- pr_warn("%s: Can't register OPAL event notifier (%d)\n",
- __func__, rc);
+ pr_err("%s: Can't request OPAL event irq (%d)\n",
+ __func__, rc);
return;
}
diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c
index 38ce757e5e2a..4949ef0d9400 100644
--- a/arch/powerpc/platforms/powernv/opal-elog.c
+++ b/arch/powerpc/platforms/powernv/opal-elog.c
@@ -10,6 +10,7 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
@@ -276,24 +277,15 @@ static void elog_work_fn(struct work_struct *work)
static DECLARE_WORK(elog_work, elog_work_fn);
-static int elog_event(struct notifier_block *nb,
- unsigned long events, void *change)
+static irqreturn_t elog_event(int irq, void *data)
{
- /* check for error log event */
- if (events & OPAL_EVENT_ERROR_LOG_AVAIL)
- schedule_work(&elog_work);
- return 0;
+ schedule_work(&elog_work);
+ return IRQ_HANDLED;
}
-static struct notifier_block elog_nb = {
- .notifier_call = elog_event,
- .next = NULL,
- .priority = 0
-};
-
int __init opal_elog_init(void)
{
- int rc = 0;
+ int rc = 0, irq;
/* ELOG not supported by firmware */
if (!opal_check_token(OPAL_ELOG_READ))
@@ -305,10 +297,18 @@ int __init opal_elog_init(void)
return -1;
}
- rc = opal_notifier_register(&elog_nb);
+ irq = opal_event_request(ilog2(OPAL_EVENT_ERROR_LOG_AVAIL));
+ if (!irq) {
+ pr_err("%s: Can't register OPAL event irq (%d)\n",
+ __func__, irq);
+ return irq;
+ }
+
+ rc = request_irq(irq, elog_event,
+ IRQ_TYPE_LEVEL_HIGH, "opal-elog", NULL);
if (rc) {
- pr_err("%s: Can't register OPAL event notifier (%d)\n",
- __func__, rc);
+ pr_err("%s: Can't request OPAL event irq (%d)\n",
+ __func__, rc);
return rc;
}
diff --git a/arch/powerpc/platforms/powernv/opal-hmi.c b/arch/powerpc/platforms/powernv/opal-hmi.c
index b322bfb51343..a8f49d380449 100644
--- a/arch/powerpc/platforms/powernv/opal-hmi.c
+++ b/arch/powerpc/platforms/powernv/opal-hmi.c
@@ -170,7 +170,7 @@ static struct notifier_block opal_hmi_handler_nb = {
.priority = 0,
};
-static int __init opal_hmi_handler_init(void)
+int __init opal_hmi_handler_init(void)
{
int ret;
@@ -186,4 +186,3 @@ static int __init opal_hmi_handler_init(void)
}
return 0;
}
-machine_subsys_initcall(powernv, opal_hmi_handler_init);
diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c
new file mode 100644
index 000000000000..e2e7d75f52f3
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-irqchip.c
@@ -0,0 +1,253 @@
+/*
+ * This file implements an irqchip for OPAL events. Whenever there is
+ * an interrupt that is handled by OPAL we get passed a list of events
+ * that Linux needs to do something about. These basically look like
+ * interrupts to Linux so we implement an irqchip to handle them.
+ *
+ * Copyright Alistair Popple, IBM Corporation 2014.
+ *
+ * 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/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/irq_work.h>
+
+#include <asm/machdep.h>
+#include <asm/opal.h>
+
+#include "powernv.h"
+
+/* Maximum number of events supported by OPAL firmware */
+#define MAX_NUM_EVENTS 64
+
+struct opal_event_irqchip {
+ struct irq_chip irqchip;
+ struct irq_domain *domain;
+ unsigned long mask;
+};
+static struct opal_event_irqchip opal_event_irqchip;
+
+static unsigned int opal_irq_count;
+static unsigned int *opal_irqs;
+
+static void opal_handle_irq_work(struct irq_work *work);
+static __be64 last_outstanding_events;
+static struct irq_work opal_event_irq_work = {
+ .func = opal_handle_irq_work,
+};
+
+static void opal_event_mask(struct irq_data *d)
+{
+ clear_bit(d->hwirq, &opal_event_irqchip.mask);
+}
+
+static void opal_event_unmask(struct irq_data *d)
+{
+ set_bit(d->hwirq, &opal_event_irqchip.mask);
+
+ opal_poll_events(&last_outstanding_events);
+ if (last_outstanding_events & opal_event_irqchip.mask)
+ /* Need to retrigger the interrupt */
+ irq_work_queue(&opal_event_irq_work);
+}
+
+static int opal_event_set_type(struct irq_data *d, unsigned int flow_type)
+{
+ /*
+ * For now we only support level triggered events. The irq
+ * handler will be called continuously until the event has
+ * been cleared in OPAL.
+ */
+ if (flow_type != IRQ_TYPE_LEVEL_HIGH)
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct opal_event_irqchip opal_event_irqchip = {
+ .irqchip = {
+ .name = "OPAL EVT",
+ .irq_mask = opal_event_mask,
+ .irq_unmask = opal_event_unmask,
+ .irq_set_type = opal_event_set_type,
+ },
+ .mask = 0,
+};
+
+static int opal_event_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ irq_set_chip_data(irq, &opal_event_irqchip);
+ irq_set_chip_and_handler(irq, &opal_event_irqchip.irqchip,
+ handle_level_irq);
+
+ return 0;
+}
+
+void opal_handle_events(uint64_t events)
+{
+ int virq, hwirq = 0;
+ u64 mask = opal_event_irqchip.mask;
+
+ if (!in_irq() && (events & mask)) {
+ last_outstanding_events = events;
+ irq_work_queue(&opal_event_irq_work);
+ return;
+ }
+
+ while (events & mask) {
+ hwirq = fls64(events) - 1;
+ if (BIT_ULL(hwirq) & mask) {
+ virq = irq_find_mapping(opal_event_irqchip.domain,
+ hwirq);
+ if (virq)
+ generic_handle_irq(virq);
+ }
+ events &= ~BIT_ULL(hwirq);
+ }
+}
+
+static irqreturn_t opal_interrupt(int irq, void *data)
+{
+ __be64 events;
+
+ opal_handle_interrupt(virq_to_hw(irq), &events);
+ opal_handle_events(be64_to_cpu(events));
+
+ return IRQ_HANDLED;
+}
+
+static void opal_handle_irq_work(struct irq_work *work)
+{
+ opal_handle_events(be64_to_cpu(last_outstanding_events));
+}
+
+static int opal_event_match(struct irq_domain *h, struct device_node *node)
+{
+ return h->of_node == node;
+}
+
+static int opal_event_xlate(struct irq_domain *h, struct device_node *np,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+{
+ *out_hwirq = intspec[0];
+ *out_flags = IRQ_TYPE_LEVEL_HIGH;
+
+ return 0;
+}
+
+static const struct irq_domain_ops opal_event_domain_ops = {
+ .match = opal_event_match,
+ .map = opal_event_map,
+ .xlate = opal_event_xlate,
+};
+
+void opal_event_shutdown(void)
+{
+ unsigned int i;
+
+ /* First free interrupts, which will also mask them */
+ for (i = 0; i < opal_irq_count; i++) {
+ if (opal_irqs[i])
+ free_irq(opal_irqs[i], NULL);
+ opal_irqs[i] = 0;
+ }
+}
+
+int __init opal_event_init(void)
+{
+ struct device_node *dn, *opal_node;
+ const __be32 *irqs;
+ int i, irqlen, rc = 0;
+
+ opal_node = of_find_node_by_path("/ibm,opal");
+ if (!opal_node) {
+ pr_warn("opal: Node not found\n");
+ return -ENODEV;
+ }
+
+ /* If dn is NULL it means the domain won't be linked to a DT
+ * node so therefore irq_of_parse_and_map(...) wont work. But
+ * that shouldn't be problem because if we're running a
+ * version of skiboot that doesn't have the dn then the
+ * devices won't have the correct properties and will have to
+ * fall back to the legacy method (opal_event_request(...))
+ * anyway. */
+ dn = of_find_compatible_node(NULL, NULL, "ibm,opal-event");
+ opal_event_irqchip.domain = irq_domain_add_linear(dn, MAX_NUM_EVENTS,
+ &opal_event_domain_ops, &opal_event_irqchip);
+ of_node_put(dn);
+ if (!opal_event_irqchip.domain) {
+ pr_warn("opal: Unable to create irq domain\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Get interrupt property */
+ irqs = of_get_property(opal_node, "opal-interrupts", &irqlen);
+ opal_irq_count = irqs ? (irqlen / 4) : 0;
+ pr_debug("Found %d interrupts reserved for OPAL\n", opal_irq_count);
+
+ /* Install interrupt handlers */
+ opal_irqs = kcalloc(opal_irq_count, sizeof(*opal_irqs), GFP_KERNEL);
+ for (i = 0; irqs && i < opal_irq_count; i++, irqs++) {
+ unsigned int irq, virq;
+
+ /* Get hardware and virtual IRQ */
+ irq = be32_to_cpup(irqs);
+ virq = irq_create_mapping(NULL, irq);
+ if (virq == NO_IRQ) {
+ pr_warn("Failed to map irq 0x%x\n", irq);
+ continue;
+ }
+
+ /* Install interrupt handler */
+ rc = request_irq(virq, opal_interrupt, 0, "opal", NULL);
+ if (rc) {
+ irq_dispose_mapping(virq);
+ pr_warn("Error %d requesting irq %d (0x%x)\n",
+ rc, virq, irq);
+ continue;
+ }
+
+ /* Cache IRQ */
+ opal_irqs[i] = virq;
+ }
+
+out:
+ of_node_put(opal_node);
+ return rc;
+}
+machine_arch_initcall(powernv, opal_event_init);
+
+/**
+ * opal_event_request(unsigned int opal_event_nr) - Request an event
+ * @opal_event_nr: the opal event number to request
+ *
+ * This routine can be used to find the linux virq number which can
+ * then be passed to request_irq to assign a handler for a particular
+ * opal event. This should only be used by legacy devices which don't
+ * have proper device tree bindings. Most devices should use
+ * irq_of_parse_and_map() instead.
+ */
+int opal_event_request(unsigned int opal_event_nr)
+{
+ if (WARN_ON_ONCE(!opal_event_irqchip.domain))
+ return NO_IRQ;
+
+ return irq_create_mapping(opal_event_irqchip.domain, opal_event_nr);
+}
+EXPORT_SYMBOL(opal_event_request);
diff --git a/arch/powerpc/platforms/powernv/opal-memory-errors.c b/arch/powerpc/platforms/powernv/opal-memory-errors.c
index 43db2136dbff..00a29432be39 100644
--- a/arch/powerpc/platforms/powernv/opal-memory-errors.c
+++ b/arch/powerpc/platforms/powernv/opal-memory-errors.c
@@ -144,4 +144,4 @@ static int __init opal_mem_err_init(void)
}
return 0;
}
-machine_subsys_initcall(powernv, opal_mem_err_init);
+machine_device_initcall(powernv, opal_mem_err_init);
diff --git a/arch/powerpc/platforms/powernv/opal-prd.c b/arch/powerpc/platforms/powernv/opal-prd.c
new file mode 100644
index 000000000000..46cb3feb0a13
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-prd.c
@@ -0,0 +1,449 @@
+/*
+ * OPAL Runtime Diagnostics interface driver
+ * Supported on POWERNV platform
+ *
+ * Copyright IBM Corporation 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "opal-prd: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/poll.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/opal-prd.h>
+#include <asm/opal.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+/**
+ * The msg member must be at the end of the struct, as it's followed by the
+ * message data.
+ */
+struct opal_prd_msg_queue_item {
+ struct list_head list;
+ struct opal_prd_msg_header msg;
+};
+
+static struct device_node *prd_node;
+static LIST_HEAD(opal_prd_msg_queue);
+static DEFINE_SPINLOCK(opal_prd_msg_queue_lock);
+static DECLARE_WAIT_QUEUE_HEAD(opal_prd_msg_wait);
+static atomic_t prd_usage;
+
+static bool opal_prd_range_is_valid(uint64_t addr, uint64_t size)
+{
+ struct device_node *parent, *node;
+ bool found;
+
+ if (addr + size < addr)
+ return false;
+
+ parent = of_find_node_by_path("/reserved-memory");
+ if (!parent)
+ return false;
+
+ found = false;
+
+ for_each_child_of_node(parent, node) {
+ uint64_t range_addr, range_size, range_end;
+ const __be32 *addrp;
+ const char *label;
+
+ addrp = of_get_address(node, 0, &range_size, NULL);
+
+ range_addr = of_read_number(addrp, 2);
+ range_end = range_addr + range_size;
+
+ label = of_get_property(node, "ibm,prd-label", NULL);
+
+ /* PRD ranges need a label */
+ if (!label)
+ continue;
+
+ if (range_end <= range_addr)
+ continue;
+
+ if (addr >= range_addr && addr + size <= range_end) {
+ found = true;
+ of_node_put(node);
+ break;
+ }
+ }
+
+ of_node_put(parent);
+ return found;
+}
+
+static int opal_prd_open(struct inode *inode, struct file *file)
+{
+ /*
+ * Prevent multiple (separate) processes from concurrent interactions
+ * with the FW PRD channel
+ */
+ if (atomic_xchg(&prd_usage, 1) == 1)
+ return -EBUSY;
+
+ return 0;
+}
+
+/*
+ * opal_prd_mmap - maps firmware-provided ranges into userspace
+ * @file: file structure for the device
+ * @vma: VMA to map the registers into
+ */
+
+static int opal_prd_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ size_t addr, size;
+ int rc;
+
+ pr_devel("opal_prd_mmap(0x%016lx, 0x%016lx, 0x%lx, 0x%lx)\n",
+ vma->vm_start, vma->vm_end, vma->vm_pgoff,
+ vma->vm_flags);
+
+ addr = vma->vm_pgoff << PAGE_SHIFT;
+ size = vma->vm_end - vma->vm_start;
+
+ /* ensure we're mapping within one of the allowable ranges */
+ if (!opal_prd_range_is_valid(addr, size))
+ return -EINVAL;
+
+ vma->vm_page_prot = __pgprot(pgprot_val(phys_mem_access_prot(file,
+ vma->vm_pgoff,
+ size, vma->vm_page_prot))
+ | _PAGE_SPECIAL);
+
+ rc = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, size,
+ vma->vm_page_prot);
+
+ return rc;
+}
+
+static bool opal_msg_queue_empty(void)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&opal_prd_msg_queue_lock, flags);
+ ret = list_empty(&opal_prd_msg_queue);
+ spin_unlock_irqrestore(&opal_prd_msg_queue_lock, flags);
+
+ return ret;
+}
+
+static unsigned int opal_prd_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ poll_wait(file, &opal_prd_msg_wait, wait);
+
+ if (!opal_msg_queue_empty())
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static ssize_t opal_prd_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct opal_prd_msg_queue_item *item;
+ unsigned long flags;
+ ssize_t size, err;
+ int rc;
+
+ /* we need at least a header's worth of data */
+ if (count < sizeof(item->msg))
+ return -EINVAL;
+
+ if (*ppos)
+ return -ESPIPE;
+
+ item = NULL;
+
+ for (;;) {
+
+ spin_lock_irqsave(&opal_prd_msg_queue_lock, flags);
+ if (!list_empty(&opal_prd_msg_queue)) {
+ item = list_first_entry(&opal_prd_msg_queue,
+ struct opal_prd_msg_queue_item, list);
+ list_del(&item->list);
+ }
+ spin_unlock_irqrestore(&opal_prd_msg_queue_lock, flags);
+
+ if (item)
+ break;
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ rc = wait_event_interruptible(opal_prd_msg_wait,
+ !opal_msg_queue_empty());
+ if (rc)
+ return -EINTR;
+ }
+
+ size = be16_to_cpu(item->msg.size);
+ if (size > count) {
+ err = -EINVAL;
+ goto err_requeue;
+ }
+
+ rc = copy_to_user(buf, &item->msg, size);
+ if (rc) {
+ err = -EFAULT;
+ goto err_requeue;
+ }
+
+ kfree(item);
+
+ return size;
+
+err_requeue:
+ /* eep! re-queue at the head of the list */
+ spin_lock_irqsave(&opal_prd_msg_queue_lock, flags);
+ list_add(&item->list, &opal_prd_msg_queue);
+ spin_unlock_irqrestore(&opal_prd_msg_queue_lock, flags);
+ return err;
+}
+
+static ssize_t opal_prd_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct opal_prd_msg_header hdr;
+ ssize_t size;
+ void *msg;
+ int rc;
+
+ size = sizeof(hdr);
+
+ if (count < size)
+ return -EINVAL;
+
+ /* grab the header */
+ rc = copy_from_user(&hdr, buf, sizeof(hdr));
+ if (rc)
+ return -EFAULT;
+
+ size = be16_to_cpu(hdr.size);
+
+ msg = kmalloc(size, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ rc = copy_from_user(msg, buf, size);
+ if (rc) {
+ size = -EFAULT;
+ goto out_free;
+ }
+
+ rc = opal_prd_msg(msg);
+ if (rc) {
+ pr_warn("write: opal_prd_msg returned %d\n", rc);
+ size = -EIO;
+ }
+
+out_free:
+ kfree(msg);
+
+ return size;
+}
+
+static int opal_prd_release(struct inode *inode, struct file *file)
+{
+ struct opal_prd_msg_header msg;
+
+ msg.size = cpu_to_be16(sizeof(msg));
+ msg.type = OPAL_PRD_MSG_TYPE_FINI;
+
+ opal_prd_msg((struct opal_prd_msg *)&msg);
+
+ atomic_xchg(&prd_usage, 0);
+
+ return 0;
+}
+
+static long opal_prd_ioctl(struct file *file, unsigned int cmd,
+ unsigned long param)
+{
+ struct opal_prd_info info;
+ struct opal_prd_scom scom;
+ int rc = 0;
+
+ switch (cmd) {
+ case OPAL_PRD_GET_INFO:
+ memset(&info, 0, sizeof(info));
+ info.version = OPAL_PRD_KERNEL_VERSION;
+ rc = copy_to_user((void __user *)param, &info, sizeof(info));
+ if (rc)
+ return -EFAULT;
+ break;
+
+ case OPAL_PRD_SCOM_READ:
+ rc = copy_from_user(&scom, (void __user *)param, sizeof(scom));
+ if (rc)
+ return -EFAULT;
+
+ scom.rc = opal_xscom_read(scom.chip, scom.addr,
+ (__be64 *)&scom.data);
+ scom.data = be64_to_cpu(scom.data);
+ pr_devel("ioctl SCOM_READ: chip %llx addr %016llx data %016llx rc %lld\n",
+ scom.chip, scom.addr, scom.data, scom.rc);
+
+ rc = copy_to_user((void __user *)param, &scom, sizeof(scom));
+ if (rc)
+ return -EFAULT;
+ break;
+
+ case OPAL_PRD_SCOM_WRITE:
+ rc = copy_from_user(&scom, (void __user *)param, sizeof(scom));
+ if (rc)
+ return -EFAULT;
+
+ scom.rc = opal_xscom_write(scom.chip, scom.addr, scom.data);
+ pr_devel("ioctl SCOM_WRITE: chip %llx addr %016llx data %016llx rc %lld\n",
+ scom.chip, scom.addr, scom.data, scom.rc);
+
+ rc = copy_to_user((void __user *)param, &scom, sizeof(scom));
+ if (rc)
+ return -EFAULT;
+ break;
+
+ default:
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static const struct file_operations opal_prd_fops = {
+ .open = opal_prd_open,
+ .mmap = opal_prd_mmap,
+ .poll = opal_prd_poll,
+ .read = opal_prd_read,
+ .write = opal_prd_write,
+ .unlocked_ioctl = opal_prd_ioctl,
+ .release = opal_prd_release,
+ .owner = THIS_MODULE,
+};
+
+static struct miscdevice opal_prd_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "opal-prd",
+ .fops = &opal_prd_fops,
+};
+
+/* opal interface */
+static int opal_prd_msg_notifier(struct notifier_block *nb,
+ unsigned long msg_type, void *_msg)
+{
+ struct opal_prd_msg_queue_item *item;
+ struct opal_prd_msg_header *hdr;
+ struct opal_msg *msg = _msg;
+ int msg_size, item_size;
+ unsigned long flags;
+
+ if (msg_type != OPAL_MSG_PRD)
+ return 0;
+
+ /* Calculate total size of the message and item we need to store. The
+ * 'size' field in the header includes the header itself. */
+ hdr = (void *)msg->params;
+ msg_size = be16_to_cpu(hdr->size);
+ item_size = msg_size + sizeof(*item) - sizeof(item->msg);
+
+ item = kzalloc(item_size, GFP_ATOMIC);
+ if (!item)
+ return -ENOMEM;
+
+ memcpy(&item->msg, msg->params, msg_size);
+
+ spin_lock_irqsave(&opal_prd_msg_queue_lock, flags);
+ list_add_tail(&item->list, &opal_prd_msg_queue);
+ spin_unlock_irqrestore(&opal_prd_msg_queue_lock, flags);
+
+ wake_up_interruptible(&opal_prd_msg_wait);
+
+ return 0;
+}
+
+static struct notifier_block opal_prd_event_nb = {
+ .notifier_call = opal_prd_msg_notifier,
+ .next = NULL,
+ .priority = 0,
+};
+
+static int opal_prd_probe(struct platform_device *pdev)
+{
+ int rc;
+
+ if (!pdev || !pdev->dev.of_node)
+ return -ENODEV;
+
+ /* We should only have one prd driver instance per machine; ensure
+ * that we only get a valid probe on a single OF node.
+ */
+ if (prd_node)
+ return -EBUSY;
+
+ prd_node = pdev->dev.of_node;
+
+ rc = opal_message_notifier_register(OPAL_MSG_PRD, &opal_prd_event_nb);
+ if (rc) {
+ pr_err("Couldn't register event notifier\n");
+ return rc;
+ }
+
+ rc = misc_register(&opal_prd_dev);
+ if (rc) {
+ pr_err("failed to register miscdev\n");
+ opal_message_notifier_unregister(OPAL_MSG_PRD,
+ &opal_prd_event_nb);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int opal_prd_remove(struct platform_device *pdev)
+{
+ misc_deregister(&opal_prd_dev);
+ opal_message_notifier_unregister(OPAL_MSG_PRD, &opal_prd_event_nb);
+ return 0;
+}
+
+static const struct of_device_id opal_prd_match[] = {
+ { .compatible = "ibm,opal-prd" },
+ { },
+};
+
+static struct platform_driver opal_prd_driver = {
+ .driver = {
+ .name = "opal-prd",
+ .owner = THIS_MODULE,
+ .of_match_table = opal_prd_match,
+ },
+ .probe = opal_prd_probe,
+ .remove = opal_prd_remove,
+};
+
+module_platform_driver(opal_prd_driver);
+
+MODULE_DEVICE_TABLE(of, opal_prd_match);
+MODULE_DESCRIPTION("PowerNV OPAL runtime diagnostic driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/platforms/powernv/opal-sensor.c b/arch/powerpc/platforms/powernv/opal-sensor.c
index 655250499d18..a06059df9239 100644
--- a/arch/powerpc/platforms/powernv/opal-sensor.c
+++ b/arch/powerpc/platforms/powernv/opal-sensor.c
@@ -77,7 +77,7 @@ out:
}
EXPORT_SYMBOL_GPL(opal_get_sensor_data);
-static __init int opal_sensor_init(void)
+int __init opal_sensor_init(void)
{
struct platform_device *pdev;
struct device_node *sensor;
@@ -93,4 +93,3 @@ static __init int opal_sensor_init(void)
return PTR_ERR_OR_ZERO(pdev);
}
-machine_subsys_initcall(powernv, opal_sensor_init);
diff --git a/arch/powerpc/platforms/powernv/opal-sysparam.c b/arch/powerpc/platforms/powernv/opal-sysparam.c
index 9d1acf22a099..afe66c576a38 100644
--- a/arch/powerpc/platforms/powernv/opal-sysparam.c
+++ b/arch/powerpc/platforms/powernv/opal-sysparam.c
@@ -55,8 +55,10 @@ static ssize_t opal_get_sys_param(u32 param_id, u32 length, void *buffer)
}
ret = opal_get_param(token, param_id, (u64)buffer, length);
- if (ret != OPAL_ASYNC_COMPLETION)
+ if (ret != OPAL_ASYNC_COMPLETION) {
+ ret = opal_error_code(ret);
goto out_token;
+ }
ret = opal_async_wait_response(token, &msg);
if (ret) {
@@ -65,7 +67,7 @@ static ssize_t opal_get_sys_param(u32 param_id, u32 length, void *buffer)
goto out_token;
}
- ret = be64_to_cpu(msg.params[1]);
+ ret = opal_error_code(be64_to_cpu(msg.params[1]));
out_token:
opal_async_release_token(token);
@@ -89,8 +91,10 @@ static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
ret = opal_set_param(token, param_id, (u64)buffer, length);
- if (ret != OPAL_ASYNC_COMPLETION)
+ if (ret != OPAL_ASYNC_COMPLETION) {
+ ret = opal_error_code(ret);
goto out_token;
+ }
ret = opal_async_wait_response(token, &msg);
if (ret) {
@@ -99,7 +103,7 @@ static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
goto out_token;
}
- ret = be64_to_cpu(msg.params[1]);
+ ret = opal_error_code(be64_to_cpu(msg.params[1]));
out_token:
opal_async_release_token(token);
@@ -162,10 +166,20 @@ void __init opal_sys_param_init(void)
goto out;
}
+ /* Some systems do not use sysparams; this is not an error */
+ sysparam = of_find_node_by_path("/ibm,opal/sysparams");
+ if (!sysparam)
+ goto out;
+
+ if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
+ pr_err("SYSPARAM: Opal sysparam node not compatible\n");
+ goto out_node_put;
+ }
+
sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);
if (!sysparam_kobj) {
pr_err("SYSPARAM: Failed to create sysparam kobject\n");
- goto out;
+ goto out_node_put;
}
/* Allocate big enough buffer for any get/set transactions */
@@ -176,30 +190,19 @@ void __init opal_sys_param_init(void)
goto out_kobj_put;
}
- sysparam = of_find_node_by_path("/ibm,opal/sysparams");
- if (!sysparam) {
- pr_err("SYSPARAM: Opal sysparam node not found\n");
- goto out_param_buf;
- }
-
- if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
- pr_err("SYSPARAM: Opal sysparam node not compatible\n");
- goto out_node_put;
- }
-
/* Number of parameters exposed through DT */
count = of_property_count_strings(sysparam, "param-name");
if (count < 0) {
pr_err("SYSPARAM: No string found of property param-name in "
"the node %s\n", sysparam->name);
- goto out_node_put;
+ goto out_param_buf;
}
id = kzalloc(sizeof(*id) * count, GFP_KERNEL);
if (!id) {
pr_err("SYSPARAM: Failed to allocate memory to read parameter "
"id\n");
- goto out_node_put;
+ goto out_param_buf;
}
size = kzalloc(sizeof(*size) * count, GFP_KERNEL);
@@ -293,12 +296,12 @@ out_free_size:
kfree(size);
out_free_id:
kfree(id);
-out_node_put:
- of_node_put(sysparam);
out_param_buf:
kfree(param_data_buf);
out_kobj_put:
kobject_put(sysparam_kobj);
+out_node_put:
+ of_node_put(sysparam);
out:
return;
}
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index a7ade94cdf87..d6a7b8252e4d 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -283,6 +283,7 @@ OPAL_CALL(opal_sensor_read, OPAL_SENSOR_READ);
OPAL_CALL(opal_get_param, OPAL_GET_PARAM);
OPAL_CALL(opal_set_param, OPAL_SET_PARAM);
OPAL_CALL(opal_handle_hmi, OPAL_HANDLE_HMI);
+OPAL_CALL(opal_config_cpu_idle_state, OPAL_CONFIG_CPU_IDLE_STATE);
OPAL_CALL(opal_slw_set_reg, OPAL_SLW_SET_REG);
OPAL_CALL(opal_register_dump_region, OPAL_REGISTER_DUMP_REGION);
OPAL_CALL(opal_unregister_dump_region, OPAL_UNREGISTER_DUMP_REGION);
@@ -295,3 +296,4 @@ OPAL_CALL(opal_i2c_request, OPAL_I2C_REQUEST);
OPAL_CALL(opal_flash_read, OPAL_FLASH_READ);
OPAL_CALL(opal_flash_write, OPAL_FLASH_WRITE);
OPAL_CALL(opal_flash_erase, OPAL_FLASH_ERASE);
+OPAL_CALL(opal_prd_msg, OPAL_PRD_MSG);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 2241565b0739..f084afa0e3ba 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -53,13 +53,7 @@ static int mc_recoverable_range_len;
struct device_node *opal_node;
static DEFINE_SPINLOCK(opal_write_lock);
-static unsigned int *opal_irqs;
-static unsigned int opal_irq_count;
-static ATOMIC_NOTIFIER_HEAD(opal_notifier_head);
static struct atomic_notifier_head opal_msg_notifier_head[OPAL_MSG_TYPE_MAX];
-static DEFINE_SPINLOCK(opal_notifier_lock);
-static uint64_t last_notified_mask = 0x0ul;
-static atomic_t opal_notifier_hold = ATOMIC_INIT(0);
static uint32_t opal_heartbeat;
static void opal_reinit_cores(void)
@@ -225,82 +219,6 @@ static int __init opal_register_exception_handlers(void)
}
machine_early_initcall(powernv, opal_register_exception_handlers);
-int opal_notifier_register(struct notifier_block *nb)
-{
- if (!nb) {
- pr_warning("%s: Invalid argument (%p)\n",
- __func__, nb);
- return -EINVAL;
- }
-
- atomic_notifier_chain_register(&opal_notifier_head, nb);
- return 0;
-}
-EXPORT_SYMBOL_GPL(opal_notifier_register);
-
-int opal_notifier_unregister(struct notifier_block *nb)
-{
- if (!nb) {
- pr_warning("%s: Invalid argument (%p)\n",
- __func__, nb);
- return -EINVAL;
- }
-
- atomic_notifier_chain_unregister(&opal_notifier_head, nb);
- return 0;
-}
-EXPORT_SYMBOL_GPL(opal_notifier_unregister);
-
-static void opal_do_notifier(uint64_t events)
-{
- unsigned long flags;
- uint64_t changed_mask;
-
- if (atomic_read(&opal_notifier_hold))
- return;
-
- spin_lock_irqsave(&opal_notifier_lock, flags);
- changed_mask = last_notified_mask ^ events;
- last_notified_mask = events;
- spin_unlock_irqrestore(&opal_notifier_lock, flags);
-
- /*
- * We feed with the event bits and changed bits for
- * enough information to the callback.
- */
- atomic_notifier_call_chain(&opal_notifier_head,
- events, (void *)changed_mask);
-}
-
-void opal_notifier_update_evt(uint64_t evt_mask,
- uint64_t evt_val)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&opal_notifier_lock, flags);
- last_notified_mask &= ~evt_mask;
- last_notified_mask |= evt_val;
- spin_unlock_irqrestore(&opal_notifier_lock, flags);
-}
-
-void opal_notifier_enable(void)
-{
- int64_t rc;
- __be64 evt = 0;
-
- atomic_set(&opal_notifier_hold, 0);
-
- /* Process pending events */
- rc = opal_poll_events(&evt);
- if (rc == OPAL_SUCCESS && evt)
- opal_do_notifier(be64_to_cpu(evt));
-}
-
-void opal_notifier_disable(void)
-{
- atomic_set(&opal_notifier_hold, 1);
-}
-
/*
* Opal message notifier based on message type. Allow subscribers to get
* notified for specific messgae type.
@@ -317,6 +235,7 @@ int opal_message_notifier_register(enum opal_msg_type msg_type,
return atomic_notifier_chain_register(
&opal_msg_notifier_head[msg_type], nb);
}
+EXPORT_SYMBOL_GPL(opal_message_notifier_register);
int opal_message_notifier_unregister(enum opal_msg_type msg_type,
struct notifier_block *nb)
@@ -324,6 +243,7 @@ int opal_message_notifier_unregister(enum opal_msg_type msg_type,
return atomic_notifier_chain_unregister(
&opal_msg_notifier_head[msg_type], nb);
}
+EXPORT_SYMBOL_GPL(opal_message_notifier_unregister);
static void opal_message_do_notify(uint32_t msg_type, void *msg)
{
@@ -364,36 +284,36 @@ static void opal_handle_message(void)
opal_message_do_notify(type, (void *)&msg);
}
-static int opal_message_notify(struct notifier_block *nb,
- unsigned long events, void *change)
+static irqreturn_t opal_message_notify(int irq, void *data)
{
- if (events & OPAL_EVENT_MSG_PENDING)
- opal_handle_message();
- return 0;
+ opal_handle_message();
+ return IRQ_HANDLED;
}
-static struct notifier_block opal_message_nb = {
- .notifier_call = opal_message_notify,
- .next = NULL,
- .priority = 0,
-};
-
static int __init opal_message_init(void)
{
- int ret, i;
+ int ret, i, irq;
for (i = 0; i < OPAL_MSG_TYPE_MAX; i++)
ATOMIC_INIT_NOTIFIER_HEAD(&opal_msg_notifier_head[i]);
- ret = opal_notifier_register(&opal_message_nb);
+ irq = opal_event_request(ilog2(OPAL_EVENT_MSG_PENDING));
+ if (!irq) {
+ pr_err("%s: Can't register OPAL event irq (%d)\n",
+ __func__, irq);
+ return irq;
+ }
+
+ ret = request_irq(irq, opal_message_notify,
+ IRQ_TYPE_LEVEL_HIGH, "opal-msg", NULL);
if (ret) {
- pr_err("%s: Can't register OPAL event notifier (%d)\n",
+ pr_err("%s: Can't request OPAL event irq (%d)\n",
__func__, ret);
return ret;
}
+
return 0;
}
-machine_early_initcall(powernv, opal_message_init);
int opal_get_chars(uint32_t vtermno, char *buf, int count)
{
@@ -573,7 +493,7 @@ int opal_handle_hmi_exception(struct pt_regs *regs)
local_paca->hmi_event_available = 0;
rc = opal_poll_events(&evt);
if (rc == OPAL_SUCCESS && evt)
- opal_do_notifier(be64_to_cpu(evt));
+ opal_handle_events(be64_to_cpu(evt));
return 1;
}
@@ -610,17 +530,6 @@ out:
return !!recover_addr;
}
-static irqreturn_t opal_interrupt(int irq, void *data)
-{
- __be64 events;
-
- opal_handle_interrupt(virq_to_hw(irq), &events);
-
- opal_do_notifier(be64_to_cpu(events));
-
- return IRQ_HANDLED;
-}
-
static int opal_sysfs_init(void)
{
opal_kobj = kobject_create_and_add("opal", firmware_kobj);
@@ -693,21 +602,13 @@ static void __init opal_dump_region_init(void)
"rc = %d\n", rc);
}
-static void opal_flash_init(struct device_node *opal_node)
-{
- struct device_node *np;
-
- for_each_child_of_node(opal_node, np)
- if (of_device_is_compatible(np, "ibm,opal-flash"))
- of_platform_device_create(np, NULL, NULL);
-}
-
-static void opal_ipmi_init(struct device_node *opal_node)
+static void opal_pdev_init(struct device_node *opal_node,
+ const char *compatible)
{
struct device_node *np;
for_each_child_of_node(opal_node, np)
- if (of_device_is_compatible(np, "ibm,opal-ipmi"))
+ if (of_device_is_compatible(np, compatible))
of_platform_device_create(np, NULL, NULL);
}
@@ -719,52 +620,15 @@ static void opal_i2c_create_devs(void)
of_platform_device_create(np, NULL, NULL);
}
-static void __init opal_irq_init(struct device_node *dn)
-{
- const __be32 *irqs;
- int i, irqlen;
-
- /* Get interrupt property */
- irqs = of_get_property(opal_node, "opal-interrupts", &irqlen);
- opal_irq_count = irqs ? (irqlen / 4) : 0;
- pr_debug("Found %d interrupts reserved for OPAL\n", opal_irq_count);
- if (!opal_irq_count)
- return;
-
- /* Install interrupt handlers */
- opal_irqs = kzalloc(opal_irq_count * sizeof(unsigned int), GFP_KERNEL);
- for (i = 0; irqs && i < opal_irq_count; i++, irqs++) {
- unsigned int irq, virq;
- int rc;
-
- /* Get hardware and virtual IRQ */
- irq = be32_to_cpup(irqs);
- virq = irq_create_mapping(NULL, irq);
- if (virq == NO_IRQ) {
- pr_warn("Failed to map irq 0x%x\n", irq);
- continue;
- }
-
- /* Install interrupt handler */
- rc = request_irq(virq, opal_interrupt, 0, "opal", NULL);
- if (rc) {
- irq_dispose_mapping(virq);
- pr_warn("Error %d requesting irq %d (0x%x)\n",
- rc, virq, irq);
- continue;
- }
-
- /* Cache IRQ */
- opal_irqs[i] = virq;
- }
-}
-
static int kopald(void *unused)
{
+ __be64 events;
+
set_freezable();
do {
try_to_freeze();
- opal_poll_events(NULL);
+ opal_poll_events(&events);
+ opal_handle_events(be64_to_cpu(events));
msleep_interruptible(opal_heartbeat);
} while (!kthread_should_stop());
@@ -807,15 +671,24 @@ static int __init opal_init(void)
of_node_put(consoles);
}
+ /* Initialise OPAL messaging system */
+ opal_message_init();
+
+ /* Initialise OPAL asynchronous completion interface */
+ opal_async_comp_init();
+
+ /* Initialise OPAL sensor interface */
+ opal_sensor_init();
+
+ /* Initialise OPAL hypervisor maintainence interrupt handling */
+ opal_hmi_handler_init();
+
/* Create i2c platform devices */
opal_i2c_create_devs();
/* Setup a heatbeat thread if requested by OPAL */
opal_init_heartbeat();
- /* Find all OPAL interrupts and request them */
- opal_irq_init(opal_node);
-
/* Create "opal" kobject under /sys/firmware */
rc = opal_sysfs_init();
if (rc == 0) {
@@ -835,10 +708,10 @@ static int __init opal_init(void)
opal_msglog_init();
}
- /* Initialize OPAL IPMI backend */
- opal_ipmi_init(opal_node);
-
- opal_flash_init(opal_node);
+ /* Initialize platform devices: IPMI backend, PRD & flash interface */
+ opal_pdev_init(opal_node, "ibm,opal-ipmi");
+ opal_pdev_init(opal_node, "ibm,opal-flash");
+ opal_pdev_init(opal_node, "ibm,opal-prd");
return 0;
}
@@ -846,15 +719,9 @@ machine_subsys_initcall(powernv, opal_init);
void opal_shutdown(void)
{
- unsigned int i;
long rc = OPAL_BUSY;
- /* First free interrupts, which will also mask them */
- for (i = 0; i < opal_irq_count; i++) {
- if (opal_irqs[i])
- free_irq(opal_irqs[i], NULL);
- opal_irqs[i] = 0;
- }
+ opal_event_shutdown();
/*
* Then sync with OPAL which ensure anything that can
@@ -876,11 +743,14 @@ void opal_shutdown(void)
/* Export this so that test modules can use it */
EXPORT_SYMBOL_GPL(opal_invalid_call);
+EXPORT_SYMBOL_GPL(opal_xscom_read);
+EXPORT_SYMBOL_GPL(opal_xscom_write);
EXPORT_SYMBOL_GPL(opal_ipmi_send);
EXPORT_SYMBOL_GPL(opal_ipmi_recv);
EXPORT_SYMBOL_GPL(opal_flash_read);
EXPORT_SYMBOL_GPL(opal_flash_write);
EXPORT_SYMBOL_GPL(opal_flash_erase);
+EXPORT_SYMBOL_GPL(opal_prd_msg);
/* Convert a region of vmalloc memory to an opal sg list */
struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
@@ -954,6 +824,7 @@ int opal_error_code(int rc)
case OPAL_ASYNC_COMPLETION: return -EINPROGRESS;
case OPAL_BUSY_EVENT: return -EBUSY;
case OPAL_NO_MEM: return -ENOMEM;
+ case OPAL_PERMISSION: return -EPERM;
case OPAL_UNSUPPORTED: return -EIO;
case OPAL_HARDWARE: return -EIO;
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index f8bc950efcae..5738d315248b 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -23,6 +23,9 @@
#include <linux/io.h>
#include <linux/msi.h>
#include <linux/memblock.h>
+#include <linux/iommu.h>
+#include <linux/rculist.h>
+#include <linux/sizes.h>
#include <asm/sections.h>
#include <asm/io.h>
@@ -38,8 +41,9 @@
#include <asm/debug.h>
#include <asm/firmware.h>
#include <asm/pnv-pci.h>
+#include <asm/mmzone.h>
-#include <misc/cxl.h>
+#include <misc/cxl-base.h>
#include "powernv.h"
#include "pci.h"
@@ -47,6 +51,11 @@
/* 256M DMA window, 4K TCE pages, 8 bytes TCE */
#define TCE32_TABLE_SIZE ((0x10000000 / 0x1000) * 8)
+#define POWERNV_IOMMU_DEFAULT_LEVELS 1
+#define POWERNV_IOMMU_MAX_LEVELS 5
+
+static void pnv_pci_ioda2_table_free_pages(struct iommu_table *tbl);
+
static void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level,
const char *fmt, ...)
{
@@ -1086,10 +1095,6 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, int all)
return;
}
- pe->tce32_table = kzalloc_node(sizeof(struct iommu_table),
- GFP_KERNEL, hose->node);
- pe->tce32_table->data = pe;
-
/* Associate it with all child devices */
pnv_ioda_setup_same_PE(bus, pe);
@@ -1283,36 +1288,27 @@ m64_failed:
return -EBUSY;
}
+static long pnv_pci_ioda2_unset_window(struct iommu_table_group *table_group,
+ int num);
+static void pnv_pci_ioda2_set_bypass(struct pnv_ioda_pe *pe, bool enable);
+
static void pnv_pci_ioda2_release_dma_pe(struct pci_dev *dev, struct pnv_ioda_pe *pe)
{
- struct pci_bus *bus;
- struct pci_controller *hose;
- struct pnv_phb *phb;
struct iommu_table *tbl;
- unsigned long addr;
int64_t rc;
- bus = dev->bus;
- hose = pci_bus_to_host(bus);
- phb = hose->private_data;
- tbl = pe->tce32_table;
- addr = tbl->it_base;
-
- opal_pci_map_pe_dma_window(phb->opal_id, pe->pe_number,
- pe->pe_number << 1, 1, __pa(addr),
- 0, 0x1000);
-
- rc = opal_pci_map_pe_dma_window_real(pe->phb->opal_id,
- pe->pe_number,
- (pe->pe_number << 1) + 1,
- pe->tce_bypass_base,
- 0);
+ tbl = pe->table_group.tables[0];
+ rc = pnv_pci_ioda2_unset_window(&pe->table_group, 0);
if (rc)
pe_warn(pe, "OPAL error %ld release DMA window\n", rc);
+ pnv_pci_ioda2_set_bypass(pe, false);
+ if (pe->table_group.group) {
+ iommu_group_put(pe->table_group.group);
+ BUG_ON(pe->table_group.group);
+ }
+ pnv_pci_ioda2_table_free_pages(tbl);
iommu_free_table(tbl, of_node_full_name(dev->dev.of_node));
- free_pages(addr, get_order(TCE32_TABLE_SIZE));
- pe->tce32_table = NULL;
}
static void pnv_ioda_release_vf_PE(struct pci_dev *pdev, u16 num_vfs)
@@ -1460,10 +1456,6 @@ static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 num_vfs)
continue;
}
- pe->tce32_table = kzalloc_node(sizeof(struct iommu_table),
- GFP_KERNEL, hose->node);
- pe->tce32_table->data = pe;
-
/* Put PE to the list */
mutex_lock(&phb->ioda.pe_list_mutex);
list_add_tail(&pe->list, &phb->ioda.pe_list);
@@ -1598,12 +1590,19 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev
pe = &phb->ioda.pe_array[pdn->pe_number];
WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops);
- set_iommu_table_base_and_group(&pdev->dev, pe->tce32_table);
+ set_iommu_table_base(&pdev->dev, pe->table_group.tables[0]);
+ /*
+ * Note: iommu_add_device() will fail here as
+ * for physical PE: the device is already added by now;
+ * for virtual PE: sysfs entries are not ready yet and
+ * tce_iommu_bus_notifier will add the device to a group later.
+ */
}
-static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,
- struct pci_dev *pdev, u64 dma_mask)
+static int pnv_pci_ioda_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
{
+ struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+ struct pnv_phb *phb = hose->private_data;
struct pci_dn *pdn = pci_get_pdn(pdev);
struct pnv_ioda_pe *pe;
uint64_t top;
@@ -1625,7 +1624,7 @@ static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,
} else {
dev_info(&pdev->dev, "Using 32-bit DMA via iommu\n");
set_dma_ops(&pdev->dev, &dma_iommu_ops);
- set_iommu_table_base(&pdev->dev, pe->tce32_table);
+ set_iommu_table_base(&pdev->dev, pe->table_group.tables[0]);
}
*pdev->dev.dma_mask = dma_mask;
return 0;
@@ -1654,36 +1653,36 @@ static u64 pnv_pci_ioda_dma_get_required_mask(struct pnv_phb *phb,
}
static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe,
- struct pci_bus *bus,
- bool add_to_iommu_group)
+ struct pci_bus *bus)
{
struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) {
- if (add_to_iommu_group)
- set_iommu_table_base_and_group(&dev->dev,
- pe->tce32_table);
- else
- set_iommu_table_base(&dev->dev, pe->tce32_table);
+ set_iommu_table_base(&dev->dev, pe->table_group.tables[0]);
+ iommu_add_device(&dev->dev);
- if (dev->subordinate)
- pnv_ioda_setup_bus_dma(pe, dev->subordinate,
- add_to_iommu_group);
+ if ((pe->flags & PNV_IODA_PE_BUS_ALL) && dev->subordinate)
+ pnv_ioda_setup_bus_dma(pe, dev->subordinate);
}
}
-static void pnv_pci_ioda1_tce_invalidate(struct pnv_ioda_pe *pe,
- struct iommu_table *tbl,
- __be64 *startp, __be64 *endp, bool rm)
+static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl,
+ unsigned long index, unsigned long npages, bool rm)
{
+ struct iommu_table_group_link *tgl = list_first_entry_or_null(
+ &tbl->it_group_list, struct iommu_table_group_link,
+ next);
+ struct pnv_ioda_pe *pe = container_of(tgl->table_group,
+ struct pnv_ioda_pe, table_group);
__be64 __iomem *invalidate = rm ?
- (__be64 __iomem *)pe->tce_inval_reg_phys :
- (__be64 __iomem *)tbl->it_index;
+ (__be64 __iomem *)pe->phb->ioda.tce_inval_reg_phys :
+ pe->phb->ioda.tce_inval_reg;
unsigned long start, end, inc;
const unsigned shift = tbl->it_page_shift;
- start = __pa(startp);
- end = __pa(endp);
+ start = __pa(((__be64 *)tbl->it_base) + index - tbl->it_offset);
+ end = __pa(((__be64 *)tbl->it_base) + index - tbl->it_offset +
+ npages - 1);
/* BML uses this case for p6/p7/galaxy2: Shift addr and put in node */
if (tbl->it_busno) {
@@ -1719,26 +1718,79 @@ static void pnv_pci_ioda1_tce_invalidate(struct pnv_ioda_pe *pe,
*/
}
-static void pnv_pci_ioda2_tce_invalidate(struct pnv_ioda_pe *pe,
- struct iommu_table *tbl,
- __be64 *startp, __be64 *endp, bool rm)
+static int pnv_ioda1_tce_build(struct iommu_table *tbl, long index,
+ long npages, unsigned long uaddr,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+ int ret = pnv_tce_build(tbl, index, npages, uaddr, direction,
+ attrs);
+
+ if (!ret && (tbl->it_type & TCE_PCI_SWINV_CREATE))
+ pnv_pci_ioda1_tce_invalidate(tbl, index, npages, false);
+
+ return ret;
+}
+
+#ifdef CONFIG_IOMMU_API
+static int pnv_ioda1_tce_xchg(struct iommu_table *tbl, long index,
+ unsigned long *hpa, enum dma_data_direction *direction)
+{
+ long ret = pnv_tce_xchg(tbl, index, hpa, direction);
+
+ if (!ret && (tbl->it_type &
+ (TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE)))
+ pnv_pci_ioda1_tce_invalidate(tbl, index, 1, false);
+
+ return ret;
+}
+#endif
+
+static void pnv_ioda1_tce_free(struct iommu_table *tbl, long index,
+ long npages)
+{
+ pnv_tce_free(tbl, index, npages);
+
+ if (tbl->it_type & TCE_PCI_SWINV_FREE)
+ pnv_pci_ioda1_tce_invalidate(tbl, index, npages, false);
+}
+
+static struct iommu_table_ops pnv_ioda1_iommu_ops = {
+ .set = pnv_ioda1_tce_build,
+#ifdef CONFIG_IOMMU_API
+ .exchange = pnv_ioda1_tce_xchg,
+#endif
+ .clear = pnv_ioda1_tce_free,
+ .get = pnv_tce_get,
+};
+
+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;
+
+ if (!phb->ioda.tce_inval_reg)
+ return;
+
+ mb(); /* Ensure above stores are visible */
+ __raw_writeq(cpu_to_be64(val), phb->ioda.tce_inval_reg);
+}
+
+static void pnv_pci_ioda2_do_tce_invalidate(unsigned pe_number, bool rm,
+ __be64 __iomem *invalidate, unsigned shift,
+ unsigned long index, unsigned long npages)
{
unsigned long start, end, inc;
- __be64 __iomem *invalidate = rm ?
- (__be64 __iomem *)pe->tce_inval_reg_phys :
- (__be64 __iomem *)tbl->it_index;
- const unsigned shift = tbl->it_page_shift;
/* We'll invalidate DMA address in PE scope */
start = 0x2ull << 60;
- start |= (pe->pe_number & 0xFF);
+ start |= (pe_number & 0xFF);
end = start;
/* Figure out the start, end and step */
- inc = tbl->it_offset + (((u64)startp - tbl->it_base) / sizeof(u64));
- start |= (inc << shift);
- inc = tbl->it_offset + (((u64)endp - tbl->it_base) / sizeof(u64));
- end |= (inc << shift);
+ start |= (index << shift);
+ end |= ((index + npages - 1) << shift);
inc = (0x1ull << shift);
mb();
@@ -1751,25 +1803,83 @@ static void pnv_pci_ioda2_tce_invalidate(struct pnv_ioda_pe *pe,
}
}
-void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl,
- __be64 *startp, __be64 *endp, bool rm)
+static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,
+ unsigned long index, unsigned long npages, bool rm)
{
- struct pnv_ioda_pe *pe = tbl->data;
- struct pnv_phb *phb = pe->phb;
+ struct iommu_table_group_link *tgl;
- if (phb->type == PNV_PHB_IODA1)
- pnv_pci_ioda1_tce_invalidate(pe, tbl, startp, endp, rm);
- else
- pnv_pci_ioda2_tce_invalidate(pe, tbl, startp, endp, rm);
+ list_for_each_entry_rcu(tgl, &tbl->it_group_list, next) {
+ 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;
+
+ pnv_pci_ioda2_do_tce_invalidate(pe->pe_number, rm,
+ invalidate, tbl->it_page_shift,
+ index, npages);
+ }
+}
+
+static int pnv_ioda2_tce_build(struct iommu_table *tbl, long index,
+ long npages, unsigned long uaddr,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+ int ret = pnv_tce_build(tbl, index, npages, uaddr, direction,
+ attrs);
+
+ if (!ret && (tbl->it_type & TCE_PCI_SWINV_CREATE))
+ pnv_pci_ioda2_tce_invalidate(tbl, index, npages, false);
+
+ return ret;
+}
+
+#ifdef CONFIG_IOMMU_API
+static int pnv_ioda2_tce_xchg(struct iommu_table *tbl, long index,
+ unsigned long *hpa, enum dma_data_direction *direction)
+{
+ long ret = pnv_tce_xchg(tbl, index, hpa, direction);
+
+ if (!ret && (tbl->it_type &
+ (TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE)))
+ pnv_pci_ioda2_tce_invalidate(tbl, index, 1, false);
+
+ return ret;
+}
+#endif
+
+static void pnv_ioda2_tce_free(struct iommu_table *tbl, long index,
+ long npages)
+{
+ pnv_tce_free(tbl, index, npages);
+
+ if (tbl->it_type & TCE_PCI_SWINV_FREE)
+ pnv_pci_ioda2_tce_invalidate(tbl, index, npages, false);
+}
+
+static void pnv_ioda2_table_free(struct iommu_table *tbl)
+{
+ pnv_pci_ioda2_table_free_pages(tbl);
+ iommu_free_table(tbl, "pnv");
}
+static struct iommu_table_ops pnv_ioda2_iommu_ops = {
+ .set = pnv_ioda2_tce_build,
+#ifdef CONFIG_IOMMU_API
+ .exchange = pnv_ioda2_tce_xchg,
+#endif
+ .clear = pnv_ioda2_tce_free,
+ .get = pnv_tce_get,
+ .free = pnv_ioda2_table_free,
+};
+
static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
struct pnv_ioda_pe *pe, unsigned int base,
unsigned int segs)
{
struct page *tce_mem = NULL;
- const __be64 *swinvp;
struct iommu_table *tbl;
unsigned int i;
int64_t rc;
@@ -1783,6 +1893,11 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
if (WARN_ON(pe->tce32_seg >= 0))
return;
+ tbl = pnv_pci_table_alloc(phb->hose->node);
+ iommu_register_group(&pe->table_group, phb->hose->global_number,
+ pe->pe_number);
+ pnv_pci_link_table_and_group(phb->hose->node, 0, tbl, &pe->table_group);
+
/* Grab a 32-bit TCE table */
pe->tce32_seg = base;
pe_info(pe, " Setting up 32-bit TCE table at %08x..%08x\n",
@@ -1817,39 +1932,30 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
}
/* Setup linux iommu table */
- tbl = pe->tce32_table;
pnv_pci_setup_iommu_table(tbl, addr, TCE32_TABLE_SIZE * segs,
base << 28, IOMMU_PAGE_SHIFT_4K);
/* OPAL variant of P7IOC SW invalidated TCEs */
- swinvp = of_get_property(phb->hose->dn, "ibm,opal-tce-kill", NULL);
- if (swinvp) {
- /* We need a couple more fields -- an address and a data
- * to or. Since the bus is only printed out on table free
- * errors, and on the first pass the data will be a relative
- * bus number, print that out instead.
- */
- pe->tce_inval_reg_phys = be64_to_cpup(swinvp);
- tbl->it_index = (unsigned long)ioremap(pe->tce_inval_reg_phys,
- 8);
+ if (phb->ioda.tce_inval_reg)
tbl->it_type |= (TCE_PCI_SWINV_CREATE |
TCE_PCI_SWINV_FREE |
TCE_PCI_SWINV_PAIR);
- }
+
+ tbl->it_ops = &pnv_ioda1_iommu_ops;
+ pe->table_group.tce32_start = tbl->it_offset << tbl->it_page_shift;
+ pe->table_group.tce32_size = tbl->it_size << tbl->it_page_shift;
iommu_init_table(tbl, phb->hose->node);
if (pe->flags & PNV_IODA_PE_DEV) {
- iommu_register_group(tbl, phb->hose->global_number,
- pe->pe_number);
- set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
- } else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL)) {
- iommu_register_group(tbl, phb->hose->global_number,
- pe->pe_number);
- pnv_ioda_setup_bus_dma(pe, pe->pbus, true);
- } else if (pe->flags & PNV_IODA_PE_VF) {
- iommu_register_group(tbl, phb->hose->global_number,
- pe->pe_number);
- }
+ /*
+ * Setting table base here only for carrying iommu_group
+ * further down to let iommu_add_device() do the job.
+ * pnv_pci_ioda_dma_dev_setup will override it later anyway.
+ */
+ set_iommu_table_base(&pe->pdev->dev, tbl);
+ iommu_add_device(&pe->pdev->dev);
+ } else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL))
+ pnv_ioda_setup_bus_dma(pe, pe->pbus);
return;
fail:
@@ -1858,11 +1964,53 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
pe->tce32_seg = -1;
if (tce_mem)
__free_pages(tce_mem, get_order(TCE32_TABLE_SIZE * segs));
+ if (tbl) {
+ pnv_pci_unlink_table_and_group(tbl, &pe->table_group);
+ iommu_free_table(tbl, "pnv");
+ }
}
-static void pnv_pci_ioda2_set_bypass(struct iommu_table *tbl, bool enable)
+static long pnv_pci_ioda2_set_window(struct iommu_table_group *table_group,
+ int num, struct iommu_table *tbl)
+{
+ struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
+ table_group);
+ struct pnv_phb *phb = pe->phb;
+ int64_t rc;
+ const unsigned long size = tbl->it_indirect_levels ?
+ tbl->it_level_size : tbl->it_size;
+ const __u64 start_addr = tbl->it_offset << tbl->it_page_shift;
+ const __u64 win_size = tbl->it_size << tbl->it_page_shift;
+
+ pe_info(pe, "Setting up window#%d %llx..%llx pg=%x\n", num,
+ start_addr, start_addr + win_size - 1,
+ IOMMU_PAGE_SIZE(tbl));
+
+ /*
+ * Map TCE table through TVT. The TVE index is the PE number
+ * shifted by 1 bit for 32-bits DMA space.
+ */
+ rc = opal_pci_map_pe_dma_window(phb->opal_id,
+ pe->pe_number,
+ (pe->pe_number << 1) + num,
+ tbl->it_indirect_levels + 1,
+ __pa(tbl->it_base),
+ size << 3,
+ IOMMU_PAGE_SIZE(tbl));
+ if (rc) {
+ pe_err(pe, "Failed to configure TCE table, err %ld\n", rc);
+ return rc;
+ }
+
+ pnv_pci_link_table_and_group(phb->hose->node, num,
+ tbl, &pe->table_group);
+ pnv_pci_ioda2_tce_invalidate_entire(pe);
+
+ return 0;
+}
+
+static void pnv_pci_ioda2_set_bypass(struct pnv_ioda_pe *pe, bool enable)
{
- struct pnv_ioda_pe *pe = tbl->data;
uint16_t window_id = (pe->pe_number << 1 ) + 1;
int64_t rc;
@@ -1882,17 +2030,6 @@ static void pnv_pci_ioda2_set_bypass(struct iommu_table *tbl, bool enable)
window_id,
pe->tce_bypass_base,
0);
-
- /*
- * EEH needs the mapping between IOMMU table and group
- * of those VFIO/KVM pass-through devices. We can postpone
- * resetting DMA ops until the DMA mask is configured in
- * host side.
- */
- if (pe->pdev)
- set_iommu_table_base(&pe->pdev->dev, tbl);
- else
- pnv_ioda_setup_bus_dma(pe, pe->pbus, false);
}
if (rc)
pe_err(pe, "OPAL error %lld configuring bypass window\n", rc);
@@ -1900,106 +2037,363 @@ static void pnv_pci_ioda2_set_bypass(struct iommu_table *tbl, bool enable)
pe->tce_bypass_enabled = enable;
}
-static void pnv_pci_ioda2_setup_bypass_pe(struct pnv_phb *phb,
- struct pnv_ioda_pe *pe)
+static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
+ __u32 page_shift, __u64 window_size, __u32 levels,
+ struct iommu_table *tbl);
+
+static long pnv_pci_ioda2_create_table(struct iommu_table_group *table_group,
+ int num, __u32 page_shift, __u64 window_size, __u32 levels,
+ struct iommu_table **ptbl)
{
- /* TVE #1 is selected by PCI address bit 59 */
- pe->tce_bypass_base = 1ull << 59;
+ struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
+ table_group);
+ int nid = pe->phb->hose->node;
+ __u64 bus_offset = num ? pe->tce_bypass_base : table_group->tce32_start;
+ long ret;
+ struct iommu_table *tbl;
- /* Install set_bypass callback for VFIO */
- pe->tce32_table->set_bypass = pnv_pci_ioda2_set_bypass;
+ tbl = pnv_pci_table_alloc(nid);
+ if (!tbl)
+ return -ENOMEM;
- /* Enable bypass by default */
- pnv_pci_ioda2_set_bypass(pe->tce32_table, true);
+ ret = pnv_pci_ioda2_table_alloc_pages(nid,
+ bus_offset, page_shift, window_size,
+ levels, tbl);
+ if (ret) {
+ iommu_free_table(tbl, "pnv");
+ return ret;
+ }
+
+ tbl->it_ops = &pnv_ioda2_iommu_ops;
+ if (pe->phb->ioda.tce_inval_reg)
+ tbl->it_type |= (TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE);
+
+ *ptbl = tbl;
+
+ return 0;
}
-static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
- struct pnv_ioda_pe *pe)
+static long pnv_pci_ioda2_setup_default_config(struct pnv_ioda_pe *pe)
+{
+ struct iommu_table *tbl = NULL;
+ long rc;
+
+ rc = pnv_pci_ioda2_create_table(&pe->table_group, 0,
+ IOMMU_PAGE_SHIFT_4K,
+ pe->table_group.tce32_size,
+ POWERNV_IOMMU_DEFAULT_LEVELS, &tbl);
+ if (rc) {
+ pe_err(pe, "Failed to create 32-bit TCE table, err %ld",
+ rc);
+ return rc;
+ }
+
+ iommu_init_table(tbl, pe->phb->hose->node);
+
+ rc = pnv_pci_ioda2_set_window(&pe->table_group, 0, tbl);
+ if (rc) {
+ pe_err(pe, "Failed to configure 32-bit TCE table, err %ld\n",
+ rc);
+ pnv_ioda2_table_free(tbl);
+ return rc;
+ }
+
+ if (!pnv_iommu_bypass_disabled)
+ pnv_pci_ioda2_set_bypass(pe, true);
+
+ /* OPAL variant of PHB3 invalidated TCEs */
+ if (pe->phb->ioda.tce_inval_reg)
+ tbl->it_type |= (TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE);
+
+ /*
+ * Setting table base here only for carrying iommu_group
+ * further down to let iommu_add_device() do the job.
+ * pnv_pci_ioda_dma_dev_setup will override it later anyway.
+ */
+ if (pe->flags & PNV_IODA_PE_DEV)
+ set_iommu_table_base(&pe->pdev->dev, tbl);
+
+ return 0;
+}
+
+#if defined(CONFIG_IOMMU_API) || defined(CONFIG_PCI_IOV)
+static long pnv_pci_ioda2_unset_window(struct iommu_table_group *table_group,
+ int num)
+{
+ struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
+ table_group);
+ struct pnv_phb *phb = pe->phb;
+ long ret;
+
+ pe_info(pe, "Removing DMA window #%d\n", num);
+
+ ret = opal_pci_map_pe_dma_window(phb->opal_id, pe->pe_number,
+ (pe->pe_number << 1) + num,
+ 0/* levels */, 0/* table address */,
+ 0/* table size */, 0/* page size */);
+ if (ret)
+ pe_warn(pe, "Unmapping failed, ret = %ld\n", ret);
+ else
+ pnv_pci_ioda2_tce_invalidate_entire(pe);
+
+ pnv_pci_unlink_table_and_group(table_group->tables[num], table_group);
+
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_IOMMU_API
+static unsigned long pnv_pci_ioda2_get_table_size(__u32 page_shift,
+ __u64 window_size, __u32 levels)
+{
+ unsigned long bytes = 0;
+ const unsigned window_shift = ilog2(window_size);
+ unsigned entries_shift = window_shift - page_shift;
+ unsigned table_shift = entries_shift + 3;
+ unsigned long tce_table_size = max(0x1000UL, 1UL << table_shift);
+ unsigned long direct_table_size;
+
+ if (!levels || (levels > POWERNV_IOMMU_MAX_LEVELS) ||
+ (window_size > memory_hotplug_max()) ||
+ !is_power_of_2(window_size))
+ return 0;
+
+ /* Calculate a direct table size from window_size and levels */
+ entries_shift = (entries_shift + levels - 1) / levels;
+ table_shift = entries_shift + 3;
+ table_shift = max_t(unsigned, table_shift, PAGE_SHIFT);
+ direct_table_size = 1UL << table_shift;
+
+ for ( ; levels; --levels) {
+ bytes += _ALIGN_UP(tce_table_size, direct_table_size);
+
+ tce_table_size /= direct_table_size;
+ tce_table_size <<= 3;
+ tce_table_size = _ALIGN_UP(tce_table_size, direct_table_size);
+ }
+
+ return bytes;
+}
+
+static void pnv_ioda2_take_ownership(struct iommu_table_group *table_group)
+{
+ struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
+ table_group);
+ /* Store @tbl as pnv_pci_ioda2_unset_window() resets it */
+ struct iommu_table *tbl = pe->table_group.tables[0];
+
+ pnv_pci_ioda2_set_bypass(pe, false);
+ pnv_pci_ioda2_unset_window(&pe->table_group, 0);
+ pnv_ioda2_table_free(tbl);
+}
+
+static void pnv_ioda2_release_ownership(struct iommu_table_group *table_group)
+{
+ struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
+ table_group);
+
+ pnv_pci_ioda2_setup_default_config(pe);
+}
+
+static struct iommu_table_group_ops pnv_pci_ioda2_ops = {
+ .get_table_size = pnv_pci_ioda2_get_table_size,
+ .create_table = pnv_pci_ioda2_create_table,
+ .set_window = pnv_pci_ioda2_set_window,
+ .unset_window = pnv_pci_ioda2_unset_window,
+ .take_ownership = pnv_ioda2_take_ownership,
+ .release_ownership = pnv_ioda2_release_ownership,
+};
+#endif
+
+static void pnv_pci_ioda_setup_opal_tce_kill(struct pnv_phb *phb)
{
- struct page *tce_mem = NULL;
- void *addr;
const __be64 *swinvp;
- struct iommu_table *tbl;
- unsigned int tce_table_size, end;
- int64_t rc;
- /* We shouldn't already have a 32-bit DMA associated */
- if (WARN_ON(pe->tce32_seg >= 0))
+ /* OPAL variant of PHB3 invalidated TCEs */
+ swinvp = of_get_property(phb->hose->dn, "ibm,opal-tce-kill", NULL);
+ if (!swinvp)
return;
- /* The PE will reserve all possible 32-bits space */
- pe->tce32_seg = 0;
- end = (1 << ilog2(phb->ioda.m32_pci_base));
- tce_table_size = (end / 0x1000) * 8;
- pe_info(pe, "Setting up 32-bit TCE table at 0..%08x\n",
- end);
+ phb->ioda.tce_inval_reg_phys = be64_to_cpup(swinvp);
+ phb->ioda.tce_inval_reg = ioremap(phb->ioda.tce_inval_reg_phys, 8);
+}
- /* Allocate TCE table */
- tce_mem = alloc_pages_node(phb->hose->node, GFP_KERNEL,
- get_order(tce_table_size));
+static __be64 *pnv_pci_ioda2_table_do_alloc_pages(int nid, unsigned shift,
+ unsigned levels, unsigned long limit,
+ unsigned long *current_offset)
+{
+ struct page *tce_mem = NULL;
+ __be64 *addr, *tmp;
+ unsigned order = max_t(unsigned, shift, PAGE_SHIFT) - PAGE_SHIFT;
+ unsigned long allocated = 1UL << (order + PAGE_SHIFT);
+ unsigned entries = 1UL << (shift - 3);
+ long i;
+
+ tce_mem = alloc_pages_node(nid, GFP_KERNEL, order);
if (!tce_mem) {
- pe_err(pe, "Failed to allocate a 32-bit TCE memory\n");
- goto fail;
+ pr_err("Failed to allocate a TCE memory, order=%d\n", order);
+ return NULL;
}
addr = page_address(tce_mem);
- memset(addr, 0, tce_table_size);
+ memset(addr, 0, allocated);
+
+ --levels;
+ if (!levels) {
+ *current_offset += allocated;
+ return addr;
+ }
+
+ for (i = 0; i < entries; ++i) {
+ tmp = pnv_pci_ioda2_table_do_alloc_pages(nid, shift,
+ levels, limit, current_offset);
+ if (!tmp)
+ break;
+
+ addr[i] = cpu_to_be64(__pa(tmp) |
+ TCE_PCI_READ | TCE_PCI_WRITE);
+
+ if (*current_offset >= limit)
+ break;
+ }
+
+ return addr;
+}
+
+static void pnv_pci_ioda2_table_do_free_pages(__be64 *addr,
+ unsigned long size, unsigned level);
+
+static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
+ __u32 page_shift, __u64 window_size, __u32 levels,
+ struct iommu_table *tbl)
+{
+ void *addr;
+ unsigned long offset = 0, level_shift;
+ const unsigned window_shift = ilog2(window_size);
+ unsigned entries_shift = window_shift - page_shift;
+ unsigned table_shift = max_t(unsigned, entries_shift + 3, PAGE_SHIFT);
+ const unsigned long tce_table_size = 1UL << table_shift;
+
+ if (!levels || (levels > POWERNV_IOMMU_MAX_LEVELS))
+ return -EINVAL;
+
+ if ((window_size > memory_hotplug_max()) || !is_power_of_2(window_size))
+ return -EINVAL;
+
+ /* Adjust direct table size from window_size and levels */
+ entries_shift = (entries_shift + levels - 1) / levels;
+ level_shift = entries_shift + 3;
+ level_shift = max_t(unsigned, level_shift, PAGE_SHIFT);
+
+ /* Allocate TCE table */
+ addr = pnv_pci_ioda2_table_do_alloc_pages(nid, level_shift,
+ levels, tce_table_size, &offset);
+
+ /* addr==NULL means that the first level allocation failed */
+ if (!addr)
+ return -ENOMEM;
/*
- * Map TCE table through TVT. The TVE index is the PE number
- * shifted by 1 bit for 32-bits DMA space.
+ * First level was allocated but some lower level failed as
+ * we did not allocate as much as we wanted,
+ * release partially allocated table.
*/
- rc = opal_pci_map_pe_dma_window(phb->opal_id, pe->pe_number,
- pe->pe_number << 1, 1, __pa(addr),
- tce_table_size, 0x1000);
- if (rc) {
- pe_err(pe, "Failed to configure 32-bit TCE table,"
- " err %ld\n", rc);
- goto fail;
+ if (offset < tce_table_size) {
+ pnv_pci_ioda2_table_do_free_pages(addr,
+ 1ULL << (level_shift - 3), levels - 1);
+ return -ENOMEM;
}
/* Setup linux iommu table */
- tbl = pe->tce32_table;
- pnv_pci_setup_iommu_table(tbl, addr, tce_table_size, 0,
- IOMMU_PAGE_SHIFT_4K);
+ pnv_pci_setup_iommu_table(tbl, addr, tce_table_size, bus_offset,
+ page_shift);
+ tbl->it_level_size = 1ULL << (level_shift - 3);
+ tbl->it_indirect_levels = levels - 1;
+ tbl->it_allocated_size = offset;
- /* OPAL variant of PHB3 invalidated TCEs */
- swinvp = of_get_property(phb->hose->dn, "ibm,opal-tce-kill", NULL);
- if (swinvp) {
- /* We need a couple more fields -- an address and a data
- * to or. Since the bus is only printed out on table free
- * errors, and on the first pass the data will be a relative
- * bus number, print that out instead.
- */
- pe->tce_inval_reg_phys = be64_to_cpup(swinvp);
- tbl->it_index = (unsigned long)ioremap(pe->tce_inval_reg_phys,
- 8);
- tbl->it_type |= (TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE);
+ pr_devel("Created TCE table: ws=%08llx ts=%lx @%08llx\n",
+ window_size, tce_table_size, bus_offset);
+
+ return 0;
+}
+
+static void pnv_pci_ioda2_table_do_free_pages(__be64 *addr,
+ unsigned long size, unsigned level)
+{
+ const unsigned long addr_ul = (unsigned long) addr &
+ ~(TCE_PCI_READ | TCE_PCI_WRITE);
+
+ if (level) {
+ long i;
+ u64 *tmp = (u64 *) addr_ul;
+
+ for (i = 0; i < size; ++i) {
+ unsigned long hpa = be64_to_cpu(tmp[i]);
+
+ if (!(hpa & (TCE_PCI_READ | TCE_PCI_WRITE)))
+ continue;
+
+ pnv_pci_ioda2_table_do_free_pages(__va(hpa), size,
+ level - 1);
+ }
}
- iommu_init_table(tbl, phb->hose->node);
- if (pe->flags & PNV_IODA_PE_DEV) {
- iommu_register_group(tbl, phb->hose->global_number,
- pe->pe_number);
- set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
- } else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL)) {
- iommu_register_group(tbl, phb->hose->global_number,
- pe->pe_number);
- pnv_ioda_setup_bus_dma(pe, pe->pbus, true);
- } else if (pe->flags & PNV_IODA_PE_VF) {
- iommu_register_group(tbl, phb->hose->global_number,
- pe->pe_number);
- }
-
- /* Also create a bypass window */
- if (!pnv_iommu_bypass_disabled)
- pnv_pci_ioda2_setup_bypass_pe(phb, pe);
+ free_pages(addr_ul, get_order(size << 3));
+}
- return;
-fail:
- if (pe->tce32_seg >= 0)
- pe->tce32_seg = -1;
- if (tce_mem)
- __free_pages(tce_mem, get_order(tce_table_size));
+static void pnv_pci_ioda2_table_free_pages(struct iommu_table *tbl)
+{
+ const unsigned long size = tbl->it_indirect_levels ?
+ tbl->it_level_size : tbl->it_size;
+
+ if (!tbl->it_size)
+ return;
+
+ pnv_pci_ioda2_table_do_free_pages((__be64 *)tbl->it_base, size,
+ tbl->it_indirect_levels);
+}
+
+static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
+ struct pnv_ioda_pe *pe)
+{
+ int64_t rc;
+
+ /* We shouldn't already have a 32-bit DMA associated */
+ if (WARN_ON(pe->tce32_seg >= 0))
+ return;
+
+ /* TVE #1 is selected by PCI address bit 59 */
+ pe->tce_bypass_base = 1ull << 59;
+
+ iommu_register_group(&pe->table_group, phb->hose->global_number,
+ pe->pe_number);
+
+ /* The PE will reserve all possible 32-bits space */
+ pe->tce32_seg = 0;
+ pe_info(pe, "Setting up 32-bit TCE table at 0..%08x\n",
+ phb->ioda.m32_pci_base);
+
+ /* Setup linux iommu table */
+ pe->table_group.tce32_start = 0;
+ pe->table_group.tce32_size = phb->ioda.m32_pci_base;
+ pe->table_group.max_dynamic_windows_supported =
+ IOMMU_TABLE_GROUP_MAX_TABLES;
+ pe->table_group.max_levels = POWERNV_IOMMU_MAX_LEVELS;
+ pe->table_group.pgsizes = SZ_4K | SZ_64K | SZ_16M;
+#ifdef CONFIG_IOMMU_API
+ pe->table_group.ops = &pnv_pci_ioda2_ops;
+#endif
+
+ rc = pnv_pci_ioda2_setup_default_config(pe);
+ if (rc) {
+ if (pe->tce32_seg >= 0)
+ pe->tce32_seg = -1;
+ return;
+ }
+
+ if (pe->flags & PNV_IODA_PE_DEV)
+ iommu_add_device(&pe->pdev->dev);
+ else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL))
+ pnv_ioda_setup_bus_dma(pe, pe->pbus);
}
static void pnv_ioda_setup_dma(struct pnv_phb *phb)
@@ -2024,6 +2418,8 @@ static void pnv_ioda_setup_dma(struct pnv_phb *phb)
pr_info("PCI: %d PE# for a total weight of %d\n",
phb->ioda.dma_pe_count, phb->ioda.dma_weight);
+ pnv_pci_ioda_setup_opal_tce_kill(phb);
+
/* Walk our PE list and configure their DMA segments, hand them
* out one base segment plus any residual segments based on
* weight
@@ -2642,12 +3038,27 @@ static u32 pnv_ioda_bdfn_to_pe(struct pnv_phb *phb, struct pci_bus *bus,
return phb->ioda.pe_rmap[(bus->number << 8) | devfn];
}
-static void pnv_pci_ioda_shutdown(struct pnv_phb *phb)
+static void pnv_pci_ioda_shutdown(struct pci_controller *hose)
{
+ struct pnv_phb *phb = hose->private_data;
+
opal_pci_reset(phb->opal_id, OPAL_RESET_PCI_IODA_TABLE,
OPAL_ASSERT_RESET);
}
+static const struct pci_controller_ops pnv_pci_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_pci_ioda_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)
{
@@ -2791,12 +3202,8 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
/* Setup TCEs */
phb->dma_dev_setup = pnv_pci_ioda_dma_dev_setup;
- phb->dma_set_mask = pnv_pci_ioda_dma_set_mask;
phb->dma_get_required_mask = pnv_pci_ioda_dma_get_required_mask;
- /* Setup shutdown function for kexec */
- phb->shutdown = pnv_pci_ioda_shutdown;
-
/* Setup MSI support */
pnv_pci_init_ioda_msis(phb);
@@ -2808,10 +3215,7 @@ 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;
- pnv_pci_controller_ops.enable_device_hook = pnv_pci_enable_device_hook;
- pnv_pci_controller_ops.window_alignment = pnv_pci_window_alignment;
- pnv_pci_controller_ops.reset_secondary_bus = pnv_pci_reset_secondary_bus;
- hose->controller_ops = pnv_pci_controller_ops;
+ hose->controller_ops = pnv_pci_ioda_controller_ops;
#ifdef CONFIG_PCI_IOV
ppc_md.pcibios_fixup_sriov = pnv_pci_ioda_fixup_iov_resources;
diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c
index 4729ca793813..f2bdfea3b68d 100644
--- a/arch/powerpc/platforms/powernv/pci-p5ioc2.c
+++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c
@@ -83,18 +83,42 @@ static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb)
static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) { }
#endif /* CONFIG_PCI_MSI */
+static struct iommu_table_ops pnv_p5ioc2_iommu_ops = {
+ .set = pnv_tce_build,
+#ifdef CONFIG_IOMMU_API
+ .exchange = pnv_tce_xchg,
+#endif
+ .clear = pnv_tce_free,
+ .get = pnv_tce_get,
+};
+
static void pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb,
struct pci_dev *pdev)
{
- if (phb->p5ioc2.iommu_table.it_map == NULL) {
- iommu_init_table(&phb->p5ioc2.iommu_table, phb->hose->node);
- iommu_register_group(&phb->p5ioc2.iommu_table,
+ struct iommu_table *tbl = phb->p5ioc2.table_group.tables[0];
+
+ if (!tbl->it_map) {
+ tbl->it_ops = &pnv_p5ioc2_iommu_ops;
+ iommu_init_table(tbl, phb->hose->node);
+ iommu_register_group(&phb->p5ioc2.table_group,
pci_domain_nr(phb->hose->bus), phb->opal_id);
+ INIT_LIST_HEAD_RCU(&tbl->it_group_list);
+ pnv_pci_link_table_and_group(phb->hose->node, 0,
+ tbl, &phb->p5ioc2.table_group);
}
- set_iommu_table_base_and_group(&pdev->dev, &phb->p5ioc2.iommu_table);
+ set_iommu_table_base(&pdev->dev, tbl);
+ iommu_add_device(&pdev->dev);
}
+static const struct pci_controller_ops pnv_pci_p5ioc2_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
+};
+
static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, u64 hub_id,
void *tce_mem, u64 tce_size)
{
@@ -103,6 +127,8 @@ static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, u64 hub_id,
u64 phb_id;
int64_t rc;
static int primary = 1;
+ struct iommu_table_group *table_group;
+ struct iommu_table *tbl;
pr_info(" Initializing p5ioc2 PHB %s\n", np->full_name);
@@ -133,7 +159,7 @@ static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, u64 hub_id,
phb->hose->first_busno = 0;
phb->hose->last_busno = 0xff;
phb->hose->private_data = phb;
- phb->hose->controller_ops = pnv_pci_controller_ops;
+ phb->hose->controller_ops = pnv_pci_p5ioc2_controller_ops;
phb->hub_id = hub_id;
phb->opal_id = phb_id;
phb->type = PNV_PHB_P5IOC2;
@@ -172,6 +198,15 @@ static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, u64 hub_id,
pnv_pci_setup_iommu_table(&phb->p5ioc2.iommu_table,
tce_mem, tce_size, 0,
IOMMU_PAGE_SHIFT_4K);
+ /*
+ * We do not allocate iommu_table as we do not support
+ * hotplug or SRIOV on P5IOC2 and therefore iommu_free_table()
+ * should not be called for phb->p5ioc2.table_group.tables[0] ever.
+ */
+ tbl = phb->p5ioc2.table_group.tables[0] = &phb->p5ioc2.iommu_table;
+ table_group = &phb->p5ioc2.table_group;
+ table_group->tce32_start = tbl->it_offset << tbl->it_page_shift;
+ table_group->tce32_size = tbl->it_size << tbl->it_page_shift;
}
void __init pnv_pci_init_p5ioc2_hub(struct device_node *np)
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index bca2aeb6e4b6..765d8ed558d0 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -45,7 +45,7 @@
//#define cfg_dbg(fmt...) printk(fmt)
#ifdef CONFIG_PCI_MSI
-static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
+int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
struct pnv_phb *phb = hose->private_data;
@@ -94,7 +94,7 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
return 0;
}
-static void pnv_teardown_msi_irqs(struct pci_dev *pdev)
+void pnv_teardown_msi_irqs(struct pci_dev *pdev)
{
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
struct pnv_phb *phb = hose->private_data;
@@ -572,80 +572,152 @@ struct pci_ops pnv_pci_ops = {
.write = pnv_pci_write_config,
};
-static int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
- unsigned long uaddr, enum dma_data_direction direction,
- struct dma_attrs *attrs, bool rm)
+static __be64 *pnv_tce(struct iommu_table *tbl, long idx)
{
- u64 proto_tce;
- __be64 *tcep, *tces;
- u64 rpn;
-
- proto_tce = TCE_PCI_READ; // Read allowed
+ __be64 *tmp = ((__be64 *)tbl->it_base);
+ int level = tbl->it_indirect_levels;
+ const long shift = ilog2(tbl->it_level_size);
+ unsigned long mask = (tbl->it_level_size - 1) << (level * shift);
+
+ while (level) {
+ int n = (idx & mask) >> (level * shift);
+ unsigned long tce = be64_to_cpu(tmp[n]);
+
+ tmp = __va(tce & ~(TCE_PCI_READ | TCE_PCI_WRITE));
+ idx &= ~mask;
+ mask >>= shift;
+ --level;
+ }
- if (direction != DMA_TO_DEVICE)
- proto_tce |= TCE_PCI_WRITE;
+ return tmp + idx;
+}
- tces = tcep = ((__be64 *)tbl->it_base) + index - tbl->it_offset;
- rpn = __pa(uaddr) >> tbl->it_page_shift;
+int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
+ unsigned long uaddr, enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+ u64 proto_tce = iommu_direction_to_tce_perm(direction);
+ u64 rpn = __pa(uaddr) >> tbl->it_page_shift;
+ long i;
- while (npages--)
- *(tcep++) = cpu_to_be64(proto_tce |
- (rpn++ << tbl->it_page_shift));
+ for (i = 0; i < npages; i++) {
+ unsigned long newtce = proto_tce |
+ ((rpn + i) << tbl->it_page_shift);
+ unsigned long idx = index - tbl->it_offset + i;
- /* Some implementations won't cache invalid TCEs and thus may not
- * need that flush. We'll probably turn it_type into a bit mask
- * of flags if that becomes the case
- */
- if (tbl->it_type & TCE_PCI_SWINV_CREATE)
- pnv_pci_ioda_tce_invalidate(tbl, tces, tcep - 1, rm);
+ *(pnv_tce(tbl, idx)) = cpu_to_be64(newtce);
+ }
return 0;
}
-static int pnv_tce_build_vm(struct iommu_table *tbl, long index, long npages,
- unsigned long uaddr,
- enum dma_data_direction direction,
- struct dma_attrs *attrs)
+#ifdef CONFIG_IOMMU_API
+int pnv_tce_xchg(struct iommu_table *tbl, long index,
+ unsigned long *hpa, enum dma_data_direction *direction)
{
- return pnv_tce_build(tbl, index, npages, uaddr, direction, attrs,
- false);
+ u64 proto_tce = iommu_direction_to_tce_perm(*direction);
+ unsigned long newtce = *hpa | proto_tce, oldtce;
+ unsigned long idx = index - tbl->it_offset;
+
+ BUG_ON(*hpa & ~IOMMU_PAGE_MASK(tbl));
+
+ oldtce = xchg(pnv_tce(tbl, idx), cpu_to_be64(newtce));
+ *hpa = be64_to_cpu(oldtce) & ~(TCE_PCI_READ | TCE_PCI_WRITE);
+ *direction = iommu_tce_direction(oldtce);
+
+ return 0;
}
+#endif
-static void pnv_tce_free(struct iommu_table *tbl, long index, long npages,
- bool rm)
+void pnv_tce_free(struct iommu_table *tbl, long index, long npages)
{
- __be64 *tcep, *tces;
+ long i;
- tces = tcep = ((__be64 *)tbl->it_base) + index - tbl->it_offset;
+ for (i = 0; i < npages; i++) {
+ unsigned long idx = index - tbl->it_offset + i;
- while (npages--)
- *(tcep++) = cpu_to_be64(0);
+ *(pnv_tce(tbl, idx)) = cpu_to_be64(0);
+ }
+}
- if (tbl->it_type & TCE_PCI_SWINV_FREE)
- pnv_pci_ioda_tce_invalidate(tbl, tces, tcep - 1, rm);
+unsigned long pnv_tce_get(struct iommu_table *tbl, long index)
+{
+ return *(pnv_tce(tbl, index - tbl->it_offset));
}
-static void pnv_tce_free_vm(struct iommu_table *tbl, long index, long npages)
+struct iommu_table *pnv_pci_table_alloc(int nid)
{
- pnv_tce_free(tbl, index, npages, false);
+ struct iommu_table *tbl;
+
+ tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, nid);
+ INIT_LIST_HEAD_RCU(&tbl->it_group_list);
+
+ return tbl;
}
-static unsigned long pnv_tce_get(struct iommu_table *tbl, long index)
+long pnv_pci_link_table_and_group(int node, int num,
+ struct iommu_table *tbl,
+ struct iommu_table_group *table_group)
{
- return ((u64 *)tbl->it_base)[index - tbl->it_offset];
+ struct iommu_table_group_link *tgl = NULL;
+
+ if (WARN_ON(!tbl || !table_group))
+ return -EINVAL;
+
+ tgl = kzalloc_node(sizeof(struct iommu_table_group_link), GFP_KERNEL,
+ node);
+ if (!tgl)
+ return -ENOMEM;
+
+ tgl->table_group = table_group;
+ list_add_rcu(&tgl->next, &tbl->it_group_list);
+
+ table_group->tables[num] = tbl;
+
+ return 0;
}
-static int pnv_tce_build_rm(struct iommu_table *tbl, long index, long npages,
- unsigned long uaddr,
- enum dma_data_direction direction,
- struct dma_attrs *attrs)
+static void pnv_iommu_table_group_link_free(struct rcu_head *head)
{
- return pnv_tce_build(tbl, index, npages, uaddr, direction, attrs, true);
+ struct iommu_table_group_link *tgl = container_of(head,
+ struct iommu_table_group_link, rcu);
+
+ kfree(tgl);
}
-static void pnv_tce_free_rm(struct iommu_table *tbl, long index, long npages)
+void pnv_pci_unlink_table_and_group(struct iommu_table *tbl,
+ struct iommu_table_group *table_group)
{
- pnv_tce_free(tbl, index, npages, true);
+ long i;
+ bool found;
+ struct iommu_table_group_link *tgl;
+
+ if (!tbl || !table_group)
+ return;
+
+ /* Remove link to a group from table's list of attached groups */
+ found = false;
+ list_for_each_entry_rcu(tgl, &tbl->it_group_list, next) {
+ if (tgl->table_group == table_group) {
+ list_del_rcu(&tgl->next);
+ call_rcu(&tgl->rcu, pnv_iommu_table_group_link_free);
+ found = true;
+ break;
+ }
+ }
+ if (WARN_ON(!found))
+ return;
+
+ /* Clean a pointer to iommu_table in iommu_table_group::tables[] */
+ found = false;
+ for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
+ if (table_group->tables[i] == tbl) {
+ table_group->tables[i] = NULL;
+ found = true;
+ break;
+ }
+ }
+ WARN_ON(!found);
}
void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
@@ -662,7 +734,7 @@ void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
tbl->it_type = TCE_PCI;
}
-static void pnv_pci_dma_dev_setup(struct pci_dev *pdev)
+void pnv_pci_dma_dev_setup(struct pci_dev *pdev)
{
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
struct pnv_phb *phb = hose->private_data;
@@ -689,16 +761,6 @@ static void pnv_pci_dma_dev_setup(struct pci_dev *pdev)
phb->dma_dev_setup(phb, pdev);
}
-int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
-{
- struct pci_controller *hose = pci_bus_to_host(pdev->bus);
- struct pnv_phb *phb = hose->private_data;
-
- if (phb && phb->dma_set_mask)
- return phb->dma_set_mask(phb, pdev, dma_mask);
- return __dma_set_mask(&pdev->dev, dma_mask);
-}
-
u64 pnv_pci_dma_get_required_mask(struct pci_dev *pdev)
{
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
@@ -714,12 +776,9 @@ void pnv_pci_shutdown(void)
{
struct pci_controller *hose;
- list_for_each_entry(hose, &hose_list, list_node) {
- struct pnv_phb *phb = hose->private_data;
-
- if (phb && phb->shutdown)
- phb->shutdown(phb);
- }
+ list_for_each_entry(hose, &hose_list, list_node)
+ if (hose->controller_ops.shutdown)
+ hose->controller_ops.shutdown(hose);
}
/* Fixup wrong class code in p7ioc and p8 root complex */
@@ -762,22 +821,7 @@ void __init pnv_pci_init(void)
pci_devs_phb_init();
/* Configure IOMMU DMA hooks */
- ppc_md.tce_build = pnv_tce_build_vm;
- ppc_md.tce_free = pnv_tce_free_vm;
- ppc_md.tce_build_rm = pnv_tce_build_rm;
- ppc_md.tce_free_rm = pnv_tce_free_rm;
- ppc_md.tce_get = pnv_tce_get;
set_pci_dma_ops(&dma_iommu_ops);
-
- /* Configure MSIs */
-#ifdef CONFIG_PCI_MSI
- ppc_md.setup_msi_irqs = pnv_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs;
-#endif
}
machine_subsys_initcall_sync(powernv, tce_iommu_bus_notifier_init);
-
-struct pci_controller_ops pnv_pci_controller_ops = {
- .dma_dev_setup = pnv_pci_dma_dev_setup,
-};
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index 070ee888fc95..8ef2d28aded0 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -57,8 +57,7 @@ struct pnv_ioda_pe {
/* "Base" iommu table, ie, 4K TCEs, 32-bit DMA */
int tce32_seg;
int tce32_segcount;
- struct iommu_table *tce32_table;
- phys_addr_t tce_inval_reg_phys;
+ struct iommu_table_group table_group;
/* 64-bit TCE bypass region */
bool tce_bypass_enabled;
@@ -106,13 +105,10 @@ struct pnv_phb {
unsigned int hwirq, unsigned int virq,
unsigned int is_64, struct msi_msg *msg);
void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev);
- int (*dma_set_mask)(struct pnv_phb *phb, struct pci_dev *pdev,
- u64 dma_mask);
u64 (*dma_get_required_mask)(struct pnv_phb *phb,
struct pci_dev *pdev);
void (*fixup_phb)(struct pci_controller *hose);
u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn);
- void (*shutdown)(struct pnv_phb *phb);
int (*init_m64)(struct pnv_phb *phb);
void (*reserve_m64_pe)(struct pnv_phb *phb);
int (*pick_m64_pe)(struct pnv_phb *phb, struct pci_bus *bus, int all);
@@ -123,6 +119,7 @@ struct pnv_phb {
union {
struct {
struct iommu_table iommu_table;
+ struct iommu_table_group table_group;
} p5ioc2;
struct {
@@ -186,6 +183,12 @@ struct pnv_phb {
* boot for resource allocation purposes
*/
struct list_head pe_dma_list;
+
+ /* TCE cache invalidate registers (physical and
+ * remapped)
+ */
+ phys_addr_t tce_inval_reg_phys;
+ __be64 __iomem *tce_inval_reg;
} ioda;
};
@@ -200,6 +203,13 @@ struct pnv_phb {
};
extern struct pci_ops pnv_pci_ops;
+extern int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
+ unsigned long uaddr, enum dma_data_direction direction,
+ struct dma_attrs *attrs);
+extern void pnv_tce_free(struct iommu_table *tbl, long index, long npages);
+extern int pnv_tce_xchg(struct iommu_table *tbl, long index,
+ unsigned long *hpa, enum dma_data_direction *direction);
+extern unsigned long pnv_tce_get(struct iommu_table *tbl, long index);
void pnv_pci_dump_phb_diag_data(struct pci_controller *hose,
unsigned char *log_buff);
@@ -207,6 +217,13 @@ int pnv_pci_cfg_read(struct pci_dn *pdn,
int where, int size, u32 *val);
int pnv_pci_cfg_write(struct pci_dn *pdn,
int where, int size, u32 val);
+extern struct iommu_table *pnv_pci_table_alloc(int nid);
+
+extern long pnv_pci_link_table_and_group(int node, int num,
+ struct iommu_table *tbl,
+ struct iommu_table_group *table_group);
+extern void pnv_pci_unlink_table_and_group(struct iommu_table *tbl,
+ struct iommu_table_group *table_group);
extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
void *tce_mem, u64 tce_size,
u64 dma_offset, unsigned page_shift);
@@ -218,4 +235,8 @@ extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl,
extern void pnv_pci_reset_secondary_bus(struct pci_dev *dev);
extern int pnv_eeh_phb_reset(struct pci_controller *hose, int option);
+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);
+
#endif /* __POWERNV_PCI_H */
diff --git a/arch/powerpc/platforms/powernv/powernv.h b/arch/powerpc/platforms/powernv/powernv.h
index 826d2c9bea56..9269e30e4ca0 100644
--- a/arch/powerpc/platforms/powernv/powernv.h
+++ b/arch/powerpc/platforms/powernv/powernv.h
@@ -12,29 +12,24 @@ struct pci_dev;
#ifdef CONFIG_PCI
extern void pnv_pci_init(void);
extern void pnv_pci_shutdown(void);
-extern int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask);
extern u64 pnv_pci_dma_get_required_mask(struct pci_dev *pdev);
#else
static inline void pnv_pci_init(void) { }
static inline void pnv_pci_shutdown(void) { }
-static inline int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
-{
- return -ENODEV;
-}
-
static inline u64 pnv_pci_dma_get_required_mask(struct pci_dev *pdev)
{
return 0;
}
#endif
-extern struct pci_controller_ops pnv_pci_controller_ops;
-
extern u32 pnv_get_supported_cpuidle_states(void);
extern void pnv_lpc_init(void);
+extern void opal_handle_events(uint64_t events);
+extern void opal_event_shutdown(void);
+
bool cpu_core_split_required(void);
#endif /* _POWERNV_H */
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index 16fdcb23f4c3..53737e019ae3 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -35,12 +35,8 @@
#include <asm/opal.h>
#include <asm/kexec.h>
#include <asm/smp.h>
-#include <asm/cputhreads.h>
-#include <asm/cpuidle.h>
-#include <asm/code-patching.h>
#include "powernv.h"
-#include "subcore.h"
static void __init pnv_setup_arch(void)
{
@@ -111,7 +107,7 @@ static void pnv_prepare_going_down(void)
* Disable all notifiers from OPAL, we can't
* service interrupts anymore anyway
*/
- opal_notifier_disable();
+ opal_event_shutdown();
/* Soft disable interrupts */
local_irq_disable();
@@ -169,13 +165,6 @@ static void pnv_progress(char *s, unsigned short hex)
{
}
-static int pnv_dma_set_mask(struct device *dev, u64 dma_mask)
-{
- if (dev_is_pci(dev))
- return pnv_pci_dma_set_mask(to_pci_dev(dev), dma_mask);
- return __dma_set_mask(dev, dma_mask);
-}
-
static u64 pnv_dma_get_required_mask(struct device *dev)
{
if (dev_is_pci(dev))
@@ -277,173 +266,6 @@ static void __init pnv_setup_machdep_opal(void)
ppc_md.handle_hmi_exception = opal_handle_hmi_exception;
}
-static u32 supported_cpuidle_states;
-
-int pnv_save_sprs_for_winkle(void)
-{
- int cpu;
- int rc;
-
- /*
- * hid0, hid1, hid4, hid5, hmeer and lpcr values are symmetric accross
- * all cpus at boot. Get these reg values of current cpu and use the
- * same accross all cpus.
- */
- uint64_t lpcr_val = mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1;
- uint64_t hid0_val = mfspr(SPRN_HID0);
- uint64_t hid1_val = mfspr(SPRN_HID1);
- uint64_t hid4_val = mfspr(SPRN_HID4);
- uint64_t hid5_val = mfspr(SPRN_HID5);
- uint64_t hmeer_val = mfspr(SPRN_HMEER);
-
- for_each_possible_cpu(cpu) {
- uint64_t pir = get_hard_smp_processor_id(cpu);
- uint64_t hsprg0_val = (uint64_t)&paca[cpu];
-
- /*
- * HSPRG0 is used to store the cpu's pointer to paca. Hence last
- * 3 bits are guaranteed to be 0. Program slw to restore HSPRG0
- * with 63rd bit set, so that when a thread wakes up at 0x100 we
- * can use this bit to distinguish between fastsleep and
- * deep winkle.
- */
- hsprg0_val |= 1;
-
- rc = opal_slw_set_reg(pir, SPRN_HSPRG0, hsprg0_val);
- if (rc != 0)
- return rc;
-
- rc = opal_slw_set_reg(pir, SPRN_LPCR, lpcr_val);
- if (rc != 0)
- return rc;
-
- /* HIDs are per core registers */
- if (cpu_thread_in_core(cpu) == 0) {
-
- rc = opal_slw_set_reg(pir, SPRN_HMEER, hmeer_val);
- if (rc != 0)
- return rc;
-
- rc = opal_slw_set_reg(pir, SPRN_HID0, hid0_val);
- if (rc != 0)
- return rc;
-
- rc = opal_slw_set_reg(pir, SPRN_HID1, hid1_val);
- if (rc != 0)
- return rc;
-
- rc = opal_slw_set_reg(pir, SPRN_HID4, hid4_val);
- if (rc != 0)
- return rc;
-
- rc = opal_slw_set_reg(pir, SPRN_HID5, hid5_val);
- if (rc != 0)
- return rc;
- }
- }
-
- return 0;
-}
-
-static void pnv_alloc_idle_core_states(void)
-{
- int i, j;
- int nr_cores = cpu_nr_cores();
- u32 *core_idle_state;
-
- /*
- * core_idle_state - First 8 bits track the idle state of each thread
- * of the core. The 8th bit is the lock bit. Initially all thread bits
- * are set. They are cleared when the thread enters deep idle state
- * like sleep and winkle. Initially the lock bit is cleared.
- * The lock bit has 2 purposes
- * a. While the first thread is restoring core state, it prevents
- * other threads in the core from switching to process context.
- * b. While the last thread in the core is saving the core state, it
- * prevents a different thread from waking up.
- */
- for (i = 0; i < nr_cores; i++) {
- int first_cpu = i * threads_per_core;
- int node = cpu_to_node(first_cpu);
-
- core_idle_state = kmalloc_node(sizeof(u32), GFP_KERNEL, node);
- *core_idle_state = PNV_CORE_IDLE_THREAD_BITS;
-
- for (j = 0; j < threads_per_core; j++) {
- int cpu = first_cpu + j;
-
- paca[cpu].core_idle_state_ptr = core_idle_state;
- paca[cpu].thread_idle_state = PNV_THREAD_RUNNING;
- paca[cpu].thread_mask = 1 << j;
- }
- }
-
- update_subcore_sibling_mask();
-
- if (supported_cpuidle_states & OPAL_PM_WINKLE_ENABLED)
- pnv_save_sprs_for_winkle();
-}
-
-u32 pnv_get_supported_cpuidle_states(void)
-{
- return supported_cpuidle_states;
-}
-EXPORT_SYMBOL_GPL(pnv_get_supported_cpuidle_states);
-
-static int __init pnv_init_idle_states(void)
-{
- struct device_node *power_mgt;
- int dt_idle_states;
- u32 *flags;
- int i;
-
- supported_cpuidle_states = 0;
-
- if (cpuidle_disable != IDLE_NO_OVERRIDE)
- goto out;
-
- if (!firmware_has_feature(FW_FEATURE_OPALv3))
- goto out;
-
- power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
- if (!power_mgt) {
- pr_warn("opal: PowerMgmt Node not found\n");
- goto out;
- }
- dt_idle_states = of_property_count_u32_elems(power_mgt,
- "ibm,cpu-idle-state-flags");
- if (dt_idle_states < 0) {
- pr_warn("cpuidle-powernv: no idle states found in the DT\n");
- goto out;
- }
-
- flags = kzalloc(sizeof(*flags) * dt_idle_states, GFP_KERNEL);
- if (of_property_read_u32_array(power_mgt,
- "ibm,cpu-idle-state-flags", flags, dt_idle_states)) {
- pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-flags in DT\n");
- goto out_free;
- }
-
- for (i = 0; i < dt_idle_states; i++)
- supported_cpuidle_states |= flags[i];
-
- if (!(supported_cpuidle_states & OPAL_PM_SLEEP_ENABLED_ER1)) {
- patch_instruction(
- (unsigned int *)pnv_fastsleep_workaround_at_entry,
- PPC_INST_NOP);
- patch_instruction(
- (unsigned int *)pnv_fastsleep_workaround_at_exit,
- PPC_INST_NOP);
- }
- pnv_alloc_idle_core_states();
-out_free:
- kfree(flags);
-out:
- return 0;
-}
-
-subsys_initcall(pnv_init_idle_states);
-
static int __init pnv_probe(void)
{
unsigned long root = of_get_flat_dt_root();
@@ -492,7 +314,6 @@ define_machine(powernv) {
.machine_shutdown = pnv_shutdown,
.power_save = power7_idle,
.calibrate_decr = generic_calibrate_decr,
- .dma_set_mask = pnv_dma_set_mask,
.dma_get_required_mask = pnv_dma_get_required_mask,
#ifdef CONFIG_KEXEC
.kexec_cpu_down = pnv_kexec_cpu_down,
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 019d34aaf054..47d9cebe7159 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -421,11 +421,10 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
return -ENODEV;
dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent);
+ of_node_put(parent);
if (!dn)
return -EINVAL;
- of_node_put(parent);
-
rc = dlpar_attach_node(dn);
if (rc) {
dlpar_release_drc(drc_index);
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 2039397cc75d..1ba55d0bb449 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -519,7 +519,7 @@ static int pseries_eeh_reset(struct eeh_pe *pe, int option)
/**
* pseries_eeh_wait_state - Wait for PE state
* @pe: EEH PE
- * @max_wait: maximal period in microsecond
+ * @max_wait: maximal period in millisecond
*
* Wait for the state of associated PE. It might take some time
* to retrieve the PE's state.
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 61d5a17f45c0..10510dea16b3 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -36,6 +36,8 @@
#include <linux/crash_dump.h>
#include <linux/memory.h>
#include <linux/of.h>
+#include <linux/iommu.h>
+#include <linux/rculist.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@@ -51,6 +53,73 @@
#include "pseries.h"
+static struct iommu_table_group *iommu_pseries_alloc_group(int node)
+{
+ struct iommu_table_group *table_group = NULL;
+ struct iommu_table *tbl = NULL;
+ struct iommu_table_group_link *tgl = NULL;
+
+ table_group = kzalloc_node(sizeof(struct iommu_table_group), GFP_KERNEL,
+ node);
+ if (!table_group)
+ goto fail_exit;
+
+ tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, node);
+ if (!tbl)
+ goto fail_exit;
+
+ tgl = kzalloc_node(sizeof(struct iommu_table_group_link), GFP_KERNEL,
+ node);
+ if (!tgl)
+ goto fail_exit;
+
+ INIT_LIST_HEAD_RCU(&tbl->it_group_list);
+ tgl->table_group = table_group;
+ list_add_rcu(&tgl->next, &tbl->it_group_list);
+
+ table_group->tables[0] = tbl;
+
+ return table_group;
+
+fail_exit:
+ kfree(tgl);
+ kfree(table_group);
+ kfree(tbl);
+
+ return NULL;
+}
+
+static void iommu_pseries_free_group(struct iommu_table_group *table_group,
+ const char *node_name)
+{
+ struct iommu_table *tbl;
+#ifdef CONFIG_IOMMU_API
+ struct iommu_table_group_link *tgl;
+#endif
+
+ if (!table_group)
+ return;
+
+ tbl = table_group->tables[0];
+#ifdef CONFIG_IOMMU_API
+ tgl = list_first_entry_or_null(&tbl->it_group_list,
+ struct iommu_table_group_link, next);
+
+ WARN_ON_ONCE(!tgl);
+ if (tgl) {
+ list_del_rcu(&tgl->next);
+ kfree(tgl);
+ }
+ if (table_group->group) {
+ iommu_group_put(table_group->group);
+ BUG_ON(table_group->group);
+ }
+#endif
+ iommu_free_table(tbl, node_name);
+
+ kfree(table_group);
+}
+
static void tce_invalidate_pSeries_sw(struct iommu_table *tbl,
__be64 *startp, __be64 *endp)
{
@@ -193,7 +262,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
int ret = 0;
unsigned long flags;
- if (npages == 1) {
+ if ((npages == 1) || !firmware_has_feature(FW_FEATURE_MULTITCE)) {
return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
direction, attrs);
}
@@ -285,6 +354,9 @@ static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long n
{
u64 rc;
+ if (!firmware_has_feature(FW_FEATURE_MULTITCE))
+ return tce_free_pSeriesLP(tbl, tcenum, npages);
+
rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages);
if (rc && printk_ratelimit()) {
@@ -460,7 +532,6 @@ static int tce_setrange_multi_pSeriesLP_walk(unsigned long start_pfn,
return tce_setrange_multi_pSeriesLP(start_pfn, num_pfn, arg);
}
-
#ifdef CONFIG_PCI
static void iommu_table_setparms(struct pci_controller *phb,
struct device_node *dn,
@@ -546,6 +617,12 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb,
tbl->it_size = size >> tbl->it_page_shift;
}
+struct iommu_table_ops iommu_table_pseries_ops = {
+ .set = tce_build_pSeries,
+ .clear = tce_free_pSeries,
+ .get = tce_get_pseries
+};
+
static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
{
struct device_node *dn;
@@ -610,12 +687,13 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
pci->phb->dma_window_size = 0x8000000ul;
pci->phb->dma_window_base_cur = 0x8000000ul;
- tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
- pci->phb->node);
+ pci->table_group = iommu_pseries_alloc_group(pci->phb->node);
+ tbl = pci->table_group->tables[0];
iommu_table_setparms(pci->phb, dn, tbl);
- pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
- iommu_register_group(tbl, pci_domain_nr(bus), 0);
+ tbl->it_ops = &iommu_table_pseries_ops;
+ iommu_init_table(tbl, pci->phb->node);
+ iommu_register_group(pci->table_group, pci_domain_nr(bus), 0);
/* Divide the rest (1.75GB) among the children */
pci->phb->dma_window_size = 0x80000000ul;
@@ -625,6 +703,11 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
pr_debug("ISA/IDE, window size is 0x%llx\n", pci->phb->dma_window_size);
}
+struct iommu_table_ops iommu_table_lpar_multi_ops = {
+ .set = tce_buildmulti_pSeriesLP,
+ .clear = tce_freemulti_pSeriesLP,
+ .get = tce_get_pSeriesLP
+};
static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
{
@@ -653,15 +736,17 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
ppci = PCI_DN(pdn);
pr_debug(" parent is %s, iommu_table: 0x%p\n",
- pdn->full_name, ppci->iommu_table);
+ pdn->full_name, ppci->table_group);
- if (!ppci->iommu_table) {
- tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
- ppci->phb->node);
+ if (!ppci->table_group) {
+ ppci->table_group = iommu_pseries_alloc_group(ppci->phb->node);
+ tbl = ppci->table_group->tables[0];
iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window);
- ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node);
- iommu_register_group(tbl, pci_domain_nr(bus), 0);
- pr_debug(" created table: %p\n", ppci->iommu_table);
+ tbl->it_ops = &iommu_table_lpar_multi_ops;
+ iommu_init_table(tbl, ppci->phb->node);
+ iommu_register_group(ppci->table_group,
+ pci_domain_nr(bus), 0);
+ pr_debug(" created table: %p\n", ppci->table_group);
}
}
@@ -683,13 +768,15 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
struct pci_controller *phb = PCI_DN(dn)->phb;
pr_debug(" --> first child, no bridge. Allocating iommu table.\n");
- tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
- phb->node);
+ PCI_DN(dn)->table_group = iommu_pseries_alloc_group(phb->node);
+ tbl = PCI_DN(dn)->table_group->tables[0];
iommu_table_setparms(phb, dn, tbl);
- PCI_DN(dn)->iommu_table = iommu_init_table(tbl, phb->node);
- iommu_register_group(tbl, pci_domain_nr(phb->bus), 0);
- set_iommu_table_base_and_group(&dev->dev,
- PCI_DN(dn)->iommu_table);
+ tbl->it_ops = &iommu_table_pseries_ops;
+ iommu_init_table(tbl, phb->node);
+ iommu_register_group(PCI_DN(dn)->table_group,
+ pci_domain_nr(phb->bus), 0);
+ set_iommu_table_base(&dev->dev, tbl);
+ iommu_add_device(&dev->dev);
return;
}
@@ -697,13 +784,14 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
* an already allocated iommu table is found and use that.
*/
- while (dn && PCI_DN(dn) && PCI_DN(dn)->iommu_table == NULL)
+ while (dn && PCI_DN(dn) && PCI_DN(dn)->table_group == NULL)
dn = dn->parent;
- if (dn && PCI_DN(dn))
- set_iommu_table_base_and_group(&dev->dev,
- PCI_DN(dn)->iommu_table);
- else
+ if (dn && PCI_DN(dn)) {
+ set_iommu_table_base(&dev->dev,
+ PCI_DN(dn)->table_group->tables[0]);
+ iommu_add_device(&dev->dev);
+ } else
printk(KERN_WARNING "iommu: Device %s has no iommu table\n",
pci_name(dev));
}
@@ -1088,7 +1176,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
dn = pci_device_to_OF_node(dev);
pr_debug(" node is %s\n", dn->full_name);
- for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
+ for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->table_group;
pdn = pdn->parent) {
dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
if (dma_window)
@@ -1104,18 +1192,21 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
pr_debug(" parent is %s\n", pdn->full_name);
pci = PCI_DN(pdn);
- if (!pci->iommu_table) {
- tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
- pci->phb->node);
+ if (!pci->table_group) {
+ pci->table_group = iommu_pseries_alloc_group(pci->phb->node);
+ tbl = pci->table_group->tables[0];
iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window);
- pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
- iommu_register_group(tbl, pci_domain_nr(pci->phb->bus), 0);
- pr_debug(" created table: %p\n", pci->iommu_table);
+ tbl->it_ops = &iommu_table_lpar_multi_ops;
+ iommu_init_table(tbl, pci->phb->node);
+ iommu_register_group(pci->table_group,
+ pci_domain_nr(pci->phb->bus), 0);
+ pr_debug(" created table: %p\n", pci->table_group);
} else {
- pr_debug(" found DMA window, table: %p\n", pci->iommu_table);
+ pr_debug(" found DMA window, table: %p\n", pci->table_group);
}
- set_iommu_table_base_and_group(&dev->dev, pci->iommu_table);
+ set_iommu_table_base(&dev->dev, pci->table_group->tables[0]);
+ iommu_add_device(&dev->dev);
}
static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask)
@@ -1145,7 +1236,7 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask)
* search upwards in the tree until we either hit a dma-window
* property, OR find a parent with a table already allocated.
*/
- for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
+ for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->table_group;
pdn = pdn->parent) {
dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
if (dma_window)
@@ -1189,7 +1280,7 @@ static u64 dma_get_required_mask_pSeriesLP(struct device *dev)
dn = pci_device_to_OF_node(pdev);
/* search upwards for ibm,dma-window */
- for (; dn && PCI_DN(dn) && !PCI_DN(dn)->iommu_table;
+ for (; dn && PCI_DN(dn) && !PCI_DN(dn)->table_group;
dn = dn->parent)
if (of_get_property(dn, "ibm,dma-window", NULL))
break;
@@ -1269,8 +1360,9 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
* the device node.
*/
remove_ddw(np, false);
- if (pci && pci->iommu_table)
- iommu_free_table(pci->iommu_table, np->full_name);
+ if (pci && pci->table_group)
+ iommu_pseries_free_group(pci->table_group,
+ np->full_name);
spin_lock(&direct_window_list_lock);
list_for_each_entry(window, &direct_window_list, list) {
@@ -1300,22 +1392,11 @@ void iommu_init_early_pSeries(void)
return;
if (firmware_has_feature(FW_FEATURE_LPAR)) {
- if (firmware_has_feature(FW_FEATURE_MULTITCE)) {
- ppc_md.tce_build = tce_buildmulti_pSeriesLP;
- ppc_md.tce_free = tce_freemulti_pSeriesLP;
- } else {
- ppc_md.tce_build = tce_build_pSeriesLP;
- ppc_md.tce_free = tce_free_pSeriesLP;
- }
- ppc_md.tce_get = tce_get_pSeriesLP;
pseries_pci_controller_ops.dma_bus_setup = pci_dma_bus_setup_pSeriesLP;
pseries_pci_controller_ops.dma_dev_setup = pci_dma_dev_setup_pSeriesLP;
ppc_md.dma_set_mask = dma_set_mask_pSeriesLP;
ppc_md.dma_get_required_mask = dma_get_required_mask_pSeriesLP;
} else {
- ppc_md.tce_build = tce_build_pSeries;
- ppc_md.tce_free = tce_free_pSeries;
- ppc_md.tce_get = tce_get_pseries;
pseries_pci_controller_ops.dma_bus_setup = pci_dma_bus_setup_pSeries;
pseries_pci_controller_ops.dma_dev_setup = pci_dma_dev_setup_pSeries;
}
@@ -1333,8 +1414,6 @@ static int __init disable_multitce(char *str)
firmware_has_feature(FW_FEATURE_LPAR) &&
firmware_has_feature(FW_FEATURE_MULTITCE)) {
printk(KERN_INFO "Disabling MULTITCE firmware feature\n");
- ppc_md.tce_build = tce_build_pSeriesLP;
- ppc_md.tce_free = tce_free_pSeriesLP;
powerpc_firmware_features &= ~FW_FEATURE_MULTITCE;
}
return 1;
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c
index c8d24f9a6948..c22bb647cce6 100644
--- a/arch/powerpc/platforms/pseries/msi.c
+++ b/arch/powerpc/platforms/pseries/msi.c
@@ -18,6 +18,8 @@
#include <asm/ppc-pci.h>
#include <asm/machdep.h>
+#include "pseries.h"
+
static int query_token, change_token;
#define RTAS_QUERY_FN 0
@@ -505,6 +507,8 @@ static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev)
static int rtas_msi_init(void)
{
+ struct pci_controller *phb;
+
query_token = rtas_token("ibm,query-interrupt-source-number");
change_token = rtas_token("ibm,change-msi");
@@ -516,9 +520,15 @@ static int rtas_msi_init(void)
pr_debug("rtas_msi: Registering RTAS MSI callbacks.\n");
- WARN_ON(ppc_md.setup_msi_irqs);
- ppc_md.setup_msi_irqs = rtas_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = rtas_teardown_msi_irqs;
+ WARN_ON(pseries_pci_controller_ops.setup_msi_irqs);
+ pseries_pci_controller_ops.setup_msi_irqs = rtas_setup_msi_irqs;
+ pseries_pci_controller_ops.teardown_msi_irqs = rtas_teardown_msi_irqs;
+
+ list_for_each_entry(phb, &hose_list, list_node) {
+ WARN_ON(phb->controller_ops.setup_msi_irqs);
+ phb->controller_ops.setup_msi_irqs = rtas_setup_msi_irqs;
+ phb->controller_ops.teardown_msi_irqs = rtas_teardown_msi_irqs;
+ }
WARN_ON(ppc_md.pci_irq_fixup);
ppc_md.pci_irq_fixup = rtas_msi_pci_irq_fixup;
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index f7cb2a1b01fa..5b492a6438ff 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -2,7 +2,7 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
-mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
+mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o
obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y)
obj-$(CONFIG_MPIC_TIMER) += mpic_timer.o
obj-$(CONFIG_FSL_MPIC_TIMER_WAKEUP) += fsl_mpic_timer_wakeup.o
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index d00a5663e312..90bcdfeedf48 100644
--- a/arch/powerpc/sysdev/dart_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -286,6 +286,12 @@ static int __init dart_init(struct device_node *dart_node)
return 0;
}
+static struct iommu_table_ops iommu_dart_ops = {
+ .set = dart_build,
+ .clear = dart_free,
+ .flush = dart_flush,
+};
+
static void iommu_table_dart_setup(void)
{
iommu_table_dart.it_busno = 0;
@@ -298,6 +304,7 @@ static void iommu_table_dart_setup(void)
iommu_table_dart.it_base = (unsigned long)dart_vbase;
iommu_table_dart.it_index = 0;
iommu_table_dart.it_blocksize = 1;
+ iommu_table_dart.it_ops = &iommu_dart_ops;
iommu_init_table(&iommu_table_dart, -1);
/* Reserve the last page of the DART to avoid possible prefetch
@@ -386,11 +393,6 @@ void __init iommu_init_early_dart(struct pci_controller_ops *controller_ops)
if (dart_init(dn) != 0)
goto bail;
- /* Setup low level TCE operations for the core IOMMU code */
- ppc_md.tce_build = dart_build;
- ppc_md.tce_free = dart_free;
- ppc_md.tce_flush = dart_flush;
-
/* Setup bypass if supported */
if (dart_is_u4)
ppc_md.dma_set_mask = dart_dma_set_mask;
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index f086c6f22dc9..5236e5427c38 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -405,6 +405,7 @@ static int fsl_of_msi_probe(struct platform_device *dev)
const struct fsl_msi_feature *features;
int len;
u32 offset;
+ struct pci_controller *phb;
match = of_match_device(fsl_of_msi_ids, &dev->dev);
if (!match)
@@ -541,14 +542,20 @@ static int fsl_of_msi_probe(struct platform_device *dev)
list_add_tail(&msi->list, &msi_head);
- /* The multiple setting ppc_md.setup_msi_irqs will not harm things */
- if (!ppc_md.setup_msi_irqs) {
- ppc_md.setup_msi_irqs = fsl_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs;
- } else if (ppc_md.setup_msi_irqs != fsl_setup_msi_irqs) {
- dev_err(&dev->dev, "Different MSI driver already installed!\n");
- err = -ENODEV;
- goto error_out;
+ /*
+ * Apply the MSI ops to all the controllers.
+ * It doesn't hurt to reassign the same ops,
+ * but bail out if we find another MSI driver.
+ */
+ list_for_each_entry(phb, &hose_list, list_node) {
+ if (!phb->controller_ops.setup_msi_irqs) {
+ phb->controller_ops.setup_msi_irqs = fsl_setup_msi_irqs;
+ phb->controller_ops.teardown_msi_irqs = fsl_teardown_msi_irqs;
+ } else if (phb->controller_ops.setup_msi_irqs != fsl_setup_msi_irqs) {
+ dev_err(&dev->dev, "Different MSI driver already installed!\n");
+ err = -ENODEV;
+ goto error_out;
+ }
}
return 0;
error_out:
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
index 45598da0b321..31c33475c7b7 100644
--- a/arch/powerpc/sysdev/i8259.c
+++ b/arch/powerpc/sysdev/i8259.c
@@ -204,7 +204,7 @@ static int i8259_host_xlate(struct irq_domain *h, struct device_node *ct,
return 0;
}
-static struct irq_domain_ops i8259_host_ops = {
+static const struct irq_domain_ops i8259_host_ops = {
.match = i8259_host_match,
.map = i8259_host_map,
.xlate = i8259_host_xlate,
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index b28733727ed3..d78f1364b639 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -691,7 +691,7 @@ static int ipic_host_map(struct irq_domain *h, unsigned int virq,
return 0;
}
-static struct irq_domain_ops ipic_host_ops = {
+static const struct irq_domain_ops ipic_host_ops = {
.match = ipic_host_match,
.map = ipic_host_map,
.xlate = irq_domain_xlate_onetwocell,
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
index c4828c0be5bd..d93a78be4346 100644
--- a/arch/powerpc/sysdev/mpc8xx_pic.c
+++ b/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -120,7 +120,7 @@ static int mpc8xx_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
}
-static struct irq_domain_ops mpc8xx_pic_host_ops = {
+static const struct irq_domain_ops mpc8xx_pic_host_ops = {
.map = mpc8xx_pic_host_map,
.xlate = mpc8xx_pic_host_xlate,
};
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index b2b8447a227a..c8e73332eaad 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -1195,7 +1195,7 @@ static void mpic_cascade(unsigned int irq, struct irq_desc *desc)
chip->irq_eoi(&desc->irq_data);
}
-static struct irq_domain_ops mpic_host_ops = {
+static const struct irq_domain_ops mpic_host_ops = {
.match = mpic_host_match,
.map = mpic_host_map,
.xlate = mpic_host_xlate,
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h
index 24bf07a63924..32971a41853b 100644
--- a/arch/powerpc/sysdev/mpic.h
+++ b/arch/powerpc/sysdev/mpic.h
@@ -15,7 +15,6 @@
extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq);
extern int mpic_msi_init_allocator(struct mpic *mpic);
extern int mpic_u3msi_init(struct mpic *mpic);
-extern int mpic_pasemi_msi_init(struct mpic *mpic);
#else
static inline void mpic_msi_reserve_hwirq(struct mpic *mpic,
irq_hw_number_t hwirq)
@@ -27,11 +26,12 @@ static inline int mpic_u3msi_init(struct mpic *mpic)
{
return -1;
}
+#endif
-static inline int mpic_pasemi_msi_init(struct mpic *mpic)
-{
- return -1;
-}
+#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PPC_PASEMI)
+int mpic_pasemi_msi_init(struct mpic *mpic);
+#else
+static inline int mpic_pasemi_msi_init(struct mpic *mpic) { return -1; }
#endif
extern int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type);
diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c
index b2cef1809389..fc46ef3b816e 100644
--- a/arch/powerpc/sysdev/mpic_u3msi.c
+++ b/arch/powerpc/sysdev/mpic_u3msi.c
@@ -181,6 +181,7 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
int mpic_u3msi_init(struct mpic *mpic)
{
int rc;
+ struct pci_controller *phb;
rc = mpic_msi_init_allocator(mpic);
if (rc) {
@@ -193,9 +194,11 @@ int mpic_u3msi_init(struct mpic *mpic)
BUG_ON(msi_mpic);
msi_mpic = mpic;
- WARN_ON(ppc_md.setup_msi_irqs);
- ppc_md.setup_msi_irqs = u3msi_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = u3msi_teardown_msi_irqs;
+ list_for_each_entry(phb, &hose_list, list_node) {
+ WARN_ON(phb->controller_ops.setup_msi_irqs);
+ phb->controller_ops.setup_msi_irqs = u3msi_setup_msi_irqs;
+ phb->controller_ops.teardown_msi_irqs = u3msi_teardown_msi_irqs;
+ }
return 0;
}
diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c
index 8848e99a83f2..0f842dd16bcd 100644
--- a/arch/powerpc/sysdev/mv64x60_pic.c
+++ b/arch/powerpc/sysdev/mv64x60_pic.c
@@ -223,7 +223,7 @@ static int mv64x60_host_map(struct irq_domain *h, unsigned int virq,
return 0;
}
-static struct irq_domain_ops mv64x60_host_ops = {
+static const struct irq_domain_ops mv64x60_host_ops = {
.map = mv64x60_host_map,
};
diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
index f366d2d4c079..2bc33674ebfc 100644
--- a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
+++ b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
@@ -128,6 +128,7 @@ static int hsta_msi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct resource *mem;
int irq, ret, irq_count;
+ struct pci_controller *phb;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (IS_ERR(mem)) {
@@ -171,8 +172,10 @@ static int hsta_msi_probe(struct platform_device *pdev)
}
}
- ppc_md.setup_msi_irqs = hsta_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = hsta_teardown_msi_irqs;
+ list_for_each_entry(phb, &hose_list, list_node) {
+ phb->controller_ops.setup_msi_irqs = hsta_setup_msi_irqs;
+ phb->controller_ops.teardown_msi_irqs = hsta_teardown_msi_irqs;
+ }
return 0;
out2:
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
index 6e2e6aa378bb..6eb21f2ea585 100644
--- a/arch/powerpc/sysdev/ppc4xx_msi.c
+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
@@ -218,6 +218,7 @@ static int ppc4xx_msi_probe(struct platform_device *dev)
struct ppc4xx_msi *msi;
struct resource res;
int err = 0;
+ struct pci_controller *phb;
dev_dbg(&dev->dev, "PCIE-MSI: Setting up MSI support...\n");
@@ -250,8 +251,10 @@ static int ppc4xx_msi_probe(struct platform_device *dev)
}
ppc4xx_msi = *msi;
- ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
+ list_for_each_entry(phb, &hose_list, list_node) {
+ phb->controller_ops.setup_msi_irqs = ppc4xx_setup_msi_irqs;
+ phb->controller_ops.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
+ }
return err;
error_out:
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
index 543765e1ef14..6512cd8caa51 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
@@ -271,7 +271,7 @@ static int qe_ic_host_map(struct irq_domain *h, unsigned int virq,
return 0;
}
-static struct irq_domain_ops qe_ic_host_ops = {
+static const struct irq_domain_ops qe_ic_host_ops = {
.match = qe_ic_host_match,
.map = qe_ic_host_map,
.xlate = irq_domain_xlate_onetwocell,
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
index 188012c58f7f..57b54476e747 100644
--- a/arch/powerpc/sysdev/tsi108_pci.c
+++ b/arch/powerpc/sysdev/tsi108_pci.c
@@ -397,7 +397,7 @@ static int pci_irq_host_map(struct irq_domain *h, unsigned int virq,
return 0;
}
-static struct irq_domain_ops pci_irq_domain_ops = {
+static const struct irq_domain_ops pci_irq_domain_ops = {
.map = pci_irq_host_map,
.xlate = pci_irq_host_xlate,
};
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
index 7c37157d4c24..d77345338671 100644
--- a/arch/powerpc/sysdev/uic.c
+++ b/arch/powerpc/sysdev/uic.c
@@ -189,7 +189,7 @@ static int uic_host_map(struct irq_domain *h, unsigned int virq,
return 0;
}
-static struct irq_domain_ops uic_host_ops = {
+static const struct irq_domain_ops uic_host_ops = {
.map = uic_host_map,
.xlate = irq_domain_xlate_twocell,
};
@@ -198,7 +198,7 @@ void uic_irq_cascade(unsigned int virq, struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct irq_data *idata = irq_desc_get_irq_data(desc);
- struct uic *uic = irq_get_handler_data(virq);
+ struct uic *uic = irq_desc_get_handler_data(desc);
u32 msr;
int src;
int subvirq;
diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c
index 2fc4cf1b7557..eae32654bdf2 100644
--- a/arch/powerpc/sysdev/xics/icp-native.c
+++ b/arch/powerpc/sysdev/xics/icp-native.c
@@ -147,12 +147,16 @@ static void icp_native_cause_ipi(int cpu, unsigned long data)
{
kvmppc_set_host_ipi(cpu, 1);
#ifdef CONFIG_PPC_DOORBELL
- if (cpu_has_feature(CPU_FTR_DBELL) &&
- (cpumask_test_cpu(cpu, cpu_sibling_mask(smp_processor_id()))))
- doorbell_cause_ipi(cpu, data);
- else
+ if (cpu_has_feature(CPU_FTR_DBELL)) {
+ if (cpumask_test_cpu(cpu, cpu_sibling_mask(get_cpu()))) {
+ doorbell_cause_ipi(cpu, data);
+ put_cpu();
+ return;
+ }
+ put_cpu();
+ }
#endif
- icp_native_set_qirr(cpu, IPI_PRIORITY);
+ icp_native_set_qirr(cpu, IPI_PRIORITY);
}
/*
diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c
index 878a54036a25..08c248eb491b 100644
--- a/arch/powerpc/sysdev/xics/xics-common.c
+++ b/arch/powerpc/sysdev/xics/xics-common.c
@@ -227,7 +227,7 @@ void xics_migrate_irqs_away(void)
/* Locate interrupt server */
server = -1;
- ics = irq_get_chip_data(virq);
+ ics = irq_desc_get_chip_data(desc);
if (ics)
server = ics->get_server(ics, irq);
if (server < 0) {
@@ -360,7 +360,7 @@ static int xics_host_xlate(struct irq_domain *h, struct device_node *ct,
return 0;
}
-static struct irq_domain_ops xics_host_ops = {
+static const struct irq_domain_ops xics_host_ops = {
.match = xics_host_match,
.map = xics_host_map,
.xlate = xics_host_xlate,
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
index 56f0524e47a6..43b8b275bc5c 100644
--- a/arch/powerpc/sysdev/xilinx_intc.c
+++ b/arch/powerpc/sysdev/xilinx_intc.c
@@ -179,7 +179,7 @@ static int xilinx_intc_map(struct irq_domain *h, unsigned int virq,
return 0;
}
-static struct irq_domain_ops xilinx_intc_ops = {
+static const struct irq_domain_ops xilinx_intc_ops = {
.map = xilinx_intc_map,
.xlate = xilinx_intc_xlate,
};
diff --git a/arch/s390/hypfs/hypfs_sprp.c b/arch/s390/hypfs/hypfs_sprp.c
index f043c3c7e73c..dd42a26d049d 100644
--- a/arch/s390/hypfs/hypfs_sprp.c
+++ b/arch/s390/hypfs/hypfs_sprp.c
@@ -128,14 +128,14 @@ static struct hypfs_dbfs_file hypfs_sprp_file = {
int hypfs_sprp_init(void)
{
- if (!sclp_has_sprp())
+ if (!sclp.has_sprp)
return 0;
return hypfs_dbfs_create_file(&hypfs_sprp_file);
}
void hypfs_sprp_exit(void)
{
- if (!sclp_has_sprp())
+ if (!sclp.has_sprp)
return;
hypfs_dbfs_remove_file(&hypfs_sprp_file);
}
diff --git a/arch/s390/include/asm/Kbuild b/arch/s390/include/asm/Kbuild
index c631f98fd524..dc5385ebb071 100644
--- a/arch/s390/include/asm/Kbuild
+++ b/arch/s390/include/asm/Kbuild
@@ -4,5 +4,4 @@ generic-y += clkdev.h
generic-y += irq_work.h
generic-y += mcs_spinlock.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += trace_clock.h
diff --git a/arch/s390/include/asm/barrier.h b/arch/s390/include/asm/barrier.h
index 8d724718ec21..e6f8615a11eb 100644
--- a/arch/s390/include/asm/barrier.h
+++ b/arch/s390/include/asm/barrier.h
@@ -36,7 +36,7 @@
#define smp_mb__before_atomic() smp_mb()
#define smp_mb__after_atomic() smp_mb()
-#define set_mb(var, value) do { var = value; mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); mb(); } while (0)
#define smp_store_release(p, v) \
do { \
diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h
index 4eadec466b8c..411464f4c97a 100644
--- a/arch/s390/include/asm/cmpxchg.h
+++ b/arch/s390/include/asm/cmpxchg.h
@@ -32,8 +32,6 @@
__old; \
})
-#define __HAVE_ARCH_CMPXCHG
-
#define __cmpxchg_double_op(p1, p2, o1, o2, n1, n2, insn) \
({ \
register __typeof__(*(p1)) __old1 asm("2") = (o1); \
diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h
index 11eae5f55b70..0130d0379edd 100644
--- a/arch/s390/include/asm/hugetlb.h
+++ b/arch/s390/include/asm/hugetlb.h
@@ -35,12 +35,8 @@ static inline int prepare_hugepage_range(struct file *file,
return 0;
}
-#define hugetlb_prefault_arch_hook(mm) do { } while (0)
#define arch_clear_hugepage_flags(page) do { } while (0)
-int arch_prepare_hugepage(struct page *page);
-void arch_release_hugepage(struct page *page);
-
static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
{
diff --git a/arch/s390/include/asm/io.h b/arch/s390/include/asm/io.h
index 30fd5c84680e..cb5fdf3a78fc 100644
--- a/arch/s390/include/asm/io.h
+++ b/arch/s390/include/asm/io.h
@@ -29,6 +29,7 @@ void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr);
#define ioremap_nocache(addr, size) ioremap(addr, size)
#define ioremap_wc ioremap_nocache
+#define ioremap_wt ioremap_nocache
static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
{
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index d01fc588b5c3..3024acbe1f9d 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -80,6 +80,7 @@ struct sca_block {
#define CPUSTAT_MCDS 0x00000100
#define CPUSTAT_SM 0x00000080
#define CPUSTAT_IBS 0x00000040
+#define CPUSTAT_GED2 0x00000010
#define CPUSTAT_G 0x00000008
#define CPUSTAT_GED 0x00000004
#define CPUSTAT_J 0x00000002
@@ -95,7 +96,8 @@ struct kvm_s390_sie_block {
#define PROG_IN_SIE (1<<0)
__u32 prog0c; /* 0x000c */
__u8 reserved10[16]; /* 0x0010 */
-#define PROG_BLOCK_SIE 0x00000001
+#define PROG_BLOCK_SIE (1<<0)
+#define PROG_REQUEST (1<<1)
atomic_t prog20; /* 0x0020 */
__u8 reserved24[4]; /* 0x0024 */
__u64 cputm; /* 0x0028 */
@@ -634,7 +636,7 @@ static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
static inline void kvm_arch_free_memslot(struct kvm *kvm,
struct kvm_memory_slot *free, struct kvm_memory_slot *dont) {}
-static inline void kvm_arch_memslots_updated(struct kvm *kvm) {}
+static inline void kvm_arch_memslots_updated(struct kvm *kvm, struct kvm_memslots *slots) {}
static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {}
static inline void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
struct kvm_memory_slot *slot) {}
diff --git a/arch/s390/include/asm/mm-arch-hooks.h b/arch/s390/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..07680b2f3c59
--- /dev/null
+++ b/arch/s390/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_S390_MM_ARCH_HOOKS_H
+#define _ASM_S390_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_S390_MM_ARCH_HOOKS_H */
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 53eacbd4f09b..dd345238d9a7 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -17,7 +17,10 @@
#define PAGE_DEFAULT_ACC 0
#define PAGE_DEFAULT_KEY (PAGE_DEFAULT_ACC << 4)
-#define HPAGE_SHIFT 20
+#include <asm/setup.h>
+#ifndef __ASSEMBLY__
+
+extern int HPAGE_SHIFT;
#define HPAGE_SIZE (1UL << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
@@ -27,9 +30,6 @@
#define ARCH_HAS_PREPARE_HUGEPAGE
#define ARCH_HAS_HUGEPAGE_CLEAR_FLUSH
-#include <asm/setup.h>
-#ifndef __ASSEMBLY__
-
static inline void storage_key_init_range(unsigned long start, unsigned long end)
{
#if PAGE_DEFAULT_KEY
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index ef24a212eeb7..f66d82798a6a 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -1498,9 +1498,9 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
return pmd_young(pmd);
}
-#define __HAVE_ARCH_PMDP_GET_AND_CLEAR
-static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
- unsigned long address, pmd_t *pmdp)
+#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
+static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
+ unsigned long address, pmd_t *pmdp)
{
pmd_t pmd = *pmdp;
@@ -1509,10 +1509,10 @@ static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
return pmd;
}
-#define __HAVE_ARCH_PMDP_GET_AND_CLEAR_FULL
-static inline pmd_t pmdp_get_and_clear_full(struct mm_struct *mm,
- unsigned long address,
- pmd_t *pmdp, int full)
+#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR_FULL
+static inline pmd_t pmdp_huge_get_and_clear_full(struct mm_struct *mm,
+ unsigned long address,
+ pmd_t *pmdp, int full)
{
pmd_t pmd = *pmdp;
@@ -1522,11 +1522,11 @@ static inline pmd_t pmdp_get_and_clear_full(struct mm_struct *mm,
return pmd;
}
-#define __HAVE_ARCH_PMDP_CLEAR_FLUSH
-static inline pmd_t pmdp_clear_flush(struct vm_area_struct *vma,
- unsigned long address, pmd_t *pmdp)
+#define __HAVE_ARCH_PMDP_HUGE_CLEAR_FLUSH
+static inline pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp)
{
- return pmdp_get_and_clear(vma->vm_mm, address, pmdp);
+ return pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp);
}
#define __HAVE_ARCH_PMDP_INVALIDATE
@@ -1548,6 +1548,14 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
}
}
+static inline pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
+ unsigned long address,
+ pmd_t *pmdp)
+{
+ return pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp);
+}
+#define pmdp_collapse_flush pmdp_collapse_flush
+
#define pfn_pmd(pfn, pgprot) mk_pmd_phys(__pa((pfn) << PAGE_SHIFT), (pgprot))
#define mk_pmd(page, pgprot) pfn_pmd(page_to_pfn(page), (pgprot))
@@ -1565,9 +1573,9 @@ static inline int has_transparent_hugepage(void)
/*
* 64 bit swap entry format:
* A page-table entry has some bits we have to treat in a special way.
- * Bits 52 and bit 55 have to be zero, otherwise an specification
+ * Bits 52 and bit 55 have to be zero, otherwise a specification
* exception will occur instead of a page translation exception. The
- * specifiation exception has the bad habit not to store necessary
+ * specification exception has the bad habit not to store necessary
* information in the lowcore.
* Bits 54 and 63 are used to indicate the page type.
* A swap pte is indicated by bit pattern (pte & 0x201) == 0x200
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index f1096bab5199..c891f41b2753 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -46,33 +46,39 @@ struct sclp_cpu_info {
struct sclp_cpu_entry cpu[MAX_CPU_ADDRESS + 1];
};
+struct sclp_info {
+ unsigned char has_linemode : 1;
+ unsigned char has_vt220 : 1;
+ unsigned char has_siif : 1;
+ unsigned char has_sigpif : 1;
+ unsigned char has_cpu_type : 1;
+ unsigned char has_sprp : 1;
+ unsigned int ibc;
+ unsigned int mtid;
+ unsigned int mtid_cp;
+ unsigned int mtid_prev;
+ unsigned long long rzm;
+ unsigned long long rnmax;
+ unsigned long long hamax;
+ unsigned int max_cpu;
+ unsigned long hsa_size;
+ unsigned long long facilities;
+};
+extern struct sclp_info sclp;
+
int sclp_get_cpu_info(struct sclp_cpu_info *info);
int sclp_cpu_configure(u8 cpu);
int sclp_cpu_deconfigure(u8 cpu);
-unsigned long long sclp_get_rnmax(void);
-unsigned long long sclp_get_rzm(void);
-unsigned int sclp_get_max_cpu(void);
-unsigned int sclp_get_mtid(u8 cpu_type);
-unsigned int sclp_get_mtid_max(void);
-unsigned int sclp_get_mtid_prev(void);
int sclp_sdias_blk_count(void);
int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
int sclp_chp_configure(struct chp_id chpid);
int sclp_chp_deconfigure(struct chp_id chpid);
int sclp_chp_read_info(struct sclp_chp_info *info);
void sclp_get_ipl_info(struct sclp_ipl_info *info);
-bool __init sclp_has_linemode(void);
-bool __init sclp_has_vt220(void);
-bool sclp_has_sprp(void);
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);
-unsigned long sclp_get_hsa_size(void);
void sclp_early_detect(void);
-int sclp_has_siif(void);
-int sclp_has_sigpif(void);
-unsigned int sclp_get_ibc(void);
-
long _sclp_print_early(const char *);
#endif /* _ASM_S390_SCLP_H */
diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h
index 98eb2a579223..dcb6312a0b91 100644
--- a/arch/s390/include/asm/timex.h
+++ b/arch/s390/include/asm/timex.h
@@ -10,6 +10,7 @@
#define _ASM_S390_TIMEX_H
#include <asm/lowcore.h>
+#include <linux/time64.h>
/* The value of the TOD clock for 1.1.1970. */
#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
@@ -108,10 +109,10 @@ int get_sync_clock(unsigned long long *clock);
void init_cpu_timer(void);
unsigned long long monotonic_clock(void);
-void tod_to_timeval(__u64, struct timespec *);
+void tod_to_timeval(__u64 todval, struct timespec64 *xt);
static inline
-void stck_to_timespec(unsigned long long stck, struct timespec *ts)
+void stck_to_timespec64(unsigned long long stck, struct timespec64 *ts)
{
tod_to_timeval(stck - TOD_UNIX_EPOCH, ts);
}
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h
index b1453a2ae1ca..4990f6c66288 100644
--- a/arch/s390/include/asm/topology.h
+++ b/arch/s390/include/asm/topology.h
@@ -22,7 +22,8 @@ DECLARE_PER_CPU(struct cpu_topology_s390, cpu_topology);
#define topology_physical_package_id(cpu) (per_cpu(cpu_topology, cpu).socket_id)
#define topology_thread_id(cpu) (per_cpu(cpu_topology, cpu).thread_id)
-#define topology_thread_cpumask(cpu) (&per_cpu(cpu_topology, cpu).thread_mask)
+#define topology_sibling_cpumask(cpu) \
+ (&per_cpu(cpu_topology, cpu).thread_mask)
#define topology_core_id(cpu) (per_cpu(cpu_topology, cpu).core_id)
#define topology_core_cpumask(cpu) (&per_cpu(cpu_topology, cpu).core_mask)
#define topology_book_id(cpu) (per_cpu(cpu_topology, cpu).book_id)
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index d64a7a62164f..9dd4cc47ddc7 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -98,7 +98,8 @@ static inline unsigned long extable_fixup(const struct exception_table_entry *x)
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from user space to kernel space. Caller must check
* the specified block with access_ok() before calling this function.
@@ -118,7 +119,8 @@ unsigned long __must_check __copy_from_user(void *to, const void __user *from,
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from kernel space to user space. Caller must check
* the specified block with access_ok() before calling this function.
@@ -264,7 +266,8 @@ int __get_user_bad(void) __attribute__((noreturn));
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from kernel space to user space.
*
@@ -290,7 +293,8 @@ __compiletime_warning("copy_from_user() buffer size is not provably correct")
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from user space to kernel space.
*
@@ -348,7 +352,8 @@ static inline unsigned long strnlen_user(const char __user *src, unsigned long n
* strlen_user: - Get the size of a string in user space.
* @str: The string to measure.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Get the size of a NUL-terminated string in user space.
*
diff --git a/arch/s390/kernel/compat_wrapper.c b/arch/s390/kernel/compat_wrapper.c
index d7fa2f0f1425..f8498dde67b1 100644
--- a/arch/s390/kernel/compat_wrapper.c
+++ b/arch/s390/kernel/compat_wrapper.c
@@ -202,7 +202,7 @@ COMPAT_SYSCALL_WRAP1(epoll_create1, int, flags);
COMPAT_SYSCALL_WRAP2(tkill, int, pid, int, sig);
COMPAT_SYSCALL_WRAP3(tgkill, int, tgid, int, pid, int, sig);
COMPAT_SYSCALL_WRAP5(perf_event_open, struct perf_event_attr __user *, attr_uptr, pid_t, pid, int, cpu, int, group_fd, unsigned long, flags);
-COMPAT_SYSCALL_WRAP5(clone, unsigned long, newsp, unsigned long, clone_flags, int __user *, parent_tidptr, int __user *, child_tidptr, int, tls_val);
+COMPAT_SYSCALL_WRAP5(clone, unsigned long, newsp, unsigned long, clone_flags, int __user *, parent_tidptr, int __user *, child_tidptr, unsigned long, tls);
COMPAT_SYSCALL_WRAP2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags);
COMPAT_SYSCALL_WRAP4(prlimit64, pid_t, pid, unsigned int, resource, const struct rlimit64 __user *, new_rlim, struct rlimit64 __user *, old_rlim);
COMPAT_SYSCALL_WRAP5(name_to_handle_at, int, dfd, const char __user *, name, struct file_handle __user *, handle, int __user *, mnt_id, int, flag);
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index 9f73c8059022..7a75ad4594e3 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -33,11 +33,12 @@ static struct memblock_type oldmem_type = {
};
#define for_each_dump_mem_range(i, nid, p_start, p_end, p_nid) \
- for (i = 0, __next_mem_range(&i, nid, &memblock.physmem, \
+ for (i = 0, __next_mem_range(&i, nid, MEMBLOCK_NONE, \
+ &memblock.physmem, \
&oldmem_type, p_start, \
p_end, p_nid); \
i != (u64)ULLONG_MAX; \
- __next_mem_range(&i, nid, &memblock.physmem, \
+ __next_mem_range(&i, nid, MEMBLOCK_NONE, &memblock.physmem,\
&oldmem_type, \
p_start, p_end, p_nid))
@@ -122,7 +123,7 @@ static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize,
{
int rc;
- if (src < sclp_get_hsa_size()) {
+ if (src < sclp.hsa_size) {
rc = memcpy_hsa(buf, src, csize, userbuf);
} else {
if (userbuf)
@@ -215,7 +216,7 @@ static int remap_oldmem_pfn_range_zfcpdump(struct vm_area_struct *vma,
unsigned long pfn,
unsigned long size, pgprot_t prot)
{
- unsigned long hsa_end = sclp_get_hsa_size();
+ unsigned long hsa_end = sclp.hsa_size;
unsigned long size_hsa;
if (pfn < hsa_end >> PAGE_SHIFT) {
@@ -258,7 +259,7 @@ int copy_from_oldmem(void *dest, void *src, size_t count)
return rc;
}
} else {
- unsigned long hsa_end = sclp_get_hsa_size();
+ 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);
@@ -609,7 +610,7 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
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_get_hsa_size())
+ if (ipl_info.type == IPL_TYPE_FCP_DUMP && !sclp.hsa_size)
return -ENODEV;
/* For kdump, exclude previous crashkernel memory */
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
index c1f21aca76e7..6fca0e46464e 100644
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -1457,23 +1457,24 @@ int
debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
int area, debug_entry_t * entry, char *out_buf)
{
- struct timespec time_spec;
+ struct timespec64 time_spec;
char *except_str;
unsigned long caller;
int rc = 0;
unsigned int level;
level = entry->id.fields.level;
- stck_to_timespec(entry->id.stck, &time_spec);
+ stck_to_timespec64(entry->id.stck, &time_spec);
if (entry->id.fields.exception)
except_str = "*";
else
except_str = "-";
caller = ((unsigned long) entry->caller) & PSW_ADDR_INSN;
- rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %p ",
- area, time_spec.tv_sec, time_spec.tv_nsec / 1000, level,
- except_str, entry->id.fields.cpuid, (void *) caller);
+ rc += sprintf(out_buf, "%02i %011lld:%06lu %1u %1s %02i %p ",
+ area, (long long)time_spec.tv_sec,
+ time_spec.tv_nsec / 1000, level, except_str,
+ entry->id.fields.cpuid, (void *)caller);
return rc;
}
EXPORT_SYMBOL(debug_dflt_header_fn);
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 99b44acbfcc7..3238893c9d4f 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -1005,7 +1005,7 @@ ENTRY(sie64a)
.Lsie_gmap:
lg %r14,__SF_EMPTY(%r15) # get control block pointer
oi __SIE_PROG0C+3(%r14),1 # we are going into SIE now
- tm __SIE_PROG20+3(%r14),1 # last exit...
+ tm __SIE_PROG20+3(%r14),3 # last exit...
jnz .Lsie_done
LPP __SF_EMPTY(%r15) # set guest id
sie 0(%r14)
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 7262fe438c99..73941bf42350 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -128,9 +128,9 @@ __setup("condev=", condev_setup);
static void __init set_preferred_console(void)
{
if (MACHINE_IS_KVM) {
- if (sclp_has_vt220())
+ if (sclp.has_vt220)
add_preferred_console("ttyS", 1, NULL);
- else if (sclp_has_linemode())
+ else if (sclp.has_linemode)
add_preferred_console("ttyS", 0, NULL);
else
add_preferred_console("hvc", 0, NULL);
@@ -510,8 +510,8 @@ static void reserve_memory_end(void)
{
#ifdef CONFIG_CRASH_DUMP
if (ipl_info.type == IPL_TYPE_FCP_DUMP &&
- !OLDMEM_BASE && sclp_get_hsa_size()) {
- memory_end = sclp_get_hsa_size();
+ !OLDMEM_BASE && sclp.hsa_size) {
+ memory_end = sclp.hsa_size;
memory_end &= PAGE_MASK;
memory_end_set = 1;
}
@@ -576,7 +576,7 @@ static void __init reserve_crashkernel(void)
crash_base = low;
} else {
/* Find suitable area in free memory */
- low = max_t(unsigned long, crash_size, sclp_get_hsa_size());
+ low = max_t(unsigned long, crash_size, sclp.hsa_size);
high = crash_base ? crash_base + crash_size : ULONG_MAX;
if (crash_base && crash_base < low) {
@@ -640,19 +640,24 @@ static void __init check_initrd(void)
}
/*
- * Reserve all kernel text
+ * Reserve memory used for lowcore/command line/kernel image.
*/
static void __init reserve_kernel(void)
{
- unsigned long start_pfn;
- start_pfn = PFN_UP(__pa(&_end));
+ unsigned long start_pfn = PFN_UP(__pa(&_end));
+#ifdef CONFIG_DMA_API_DEBUG
/*
- * Reserve memory used for lowcore/command line/kernel image.
+ * DMA_API_DEBUG code stumbles over addresses from the
+ * range [_ehead, _stext]. Mark the memory as reserved
+ * so it is not used for CONFIG_DMA_API_DEBUG=y.
*/
+ memblock_reserve(0, PFN_PHYS(start_pfn));
+#else
memblock_reserve(0, (unsigned long)_ehead);
memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn)
- (unsigned long)_stext);
+#endif
}
static void __init reserve_elfcorehdr(void)
@@ -875,6 +880,8 @@ void __init setup_arch(char **cmdline_p)
*/
setup_hwcaps();
+ HPAGE_SHIFT = MACHINE_HAS_HPAGE ? 20 : 0;
+
/*
* Create kernel page tables and switch to virtual addressing.
*/
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index efd2c1968000..0d9d59d4710e 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -601,7 +601,7 @@ static void __init smp_store_cpu_states(struct sclp_cpu_info *info)
/* No previous system present, normal boot. */
return;
/* Set multi-threading state to the previous system. */
- pcpu_set_smt(sclp_get_mtid_prev());
+ pcpu_set_smt(sclp.mtid_prev);
/* Collect CPU states. */
cpu = 0;
for (i = 0; i < info->configured; i++) {
@@ -740,7 +740,7 @@ static void __init smp_detect_cpus(void)
#endif
/* Set multi-threading state for the current system */
- mtid = sclp_get_mtid(boot_cpu_type);
+ mtid = boot_cpu_type ? sclp.mtid : sclp.mtid_cp;
mtid = (mtid < smp_max_threads) ? mtid : smp_max_threads - 1;
pcpu_set_smt(mtid);
@@ -880,12 +880,13 @@ void __noreturn cpu_die(void)
void __init smp_fill_possible_mask(void)
{
- unsigned int possible, sclp, cpu;
+ unsigned int possible, sclp_max, cpu;
- sclp = min(smp_max_threads, sclp_get_mtid_max() + 1);
- sclp = sclp_get_max_cpu()*sclp ?: nr_cpu_ids;
+ sclp_max = max(sclp.mtid, sclp.mtid_cp) + 1;
+ sclp_max = min(smp_max_threads, sclp_max);
+ sclp_max = sclp.max_cpu * sclp_max ?: nr_cpu_ids;
possible = setup_possible_cpus ?: nr_cpu_ids;
- possible = min(possible, sclp);
+ possible = min(possible, sclp_max);
for (cpu = 0; cpu < possible && cpu < nr_cpu_ids; cpu++)
set_cpu_possible(cpu, true);
}
diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c
index d3236c9e226b..39e2f41b6cf0 100644
--- a/arch/s390/kernel/suspend.c
+++ b/arch/s390/kernel/suspend.c
@@ -9,10 +9,10 @@
#include <linux/pfn.h>
#include <linux/suspend.h>
#include <linux/mm.h>
+#include <linux/pci.h>
#include <asm/ctl_reg.h>
#include <asm/ipl.h>
#include <asm/cio.h>
-#include <asm/pci.h>
#include <asm/sections.h>
#include "entry.h"
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 170ddd2018b3..9e733d965e08 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -76,7 +76,7 @@ unsigned long long monotonic_clock(void)
}
EXPORT_SYMBOL(monotonic_clock);
-void tod_to_timeval(__u64 todval, struct timespec *xt)
+void tod_to_timeval(__u64 todval, struct timespec64 *xt)
{
unsigned long long sec;
@@ -181,12 +181,12 @@ static void timing_alert_interrupt(struct ext_code ext_code,
static void etr_reset(void);
static void stp_reset(void);
-void read_persistent_clock(struct timespec *ts)
+void read_persistent_clock64(struct timespec64 *ts)
{
tod_to_timeval(get_tod_clock() - TOD_UNIX_EPOCH, ts);
}
-void read_boot_clock(struct timespec *ts)
+void read_boot_clock64(struct timespec64 *ts)
{
tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, ts);
}
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 9e3779e3e496..7365e8a46032 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -241,21 +241,6 @@ static int handle_prog(struct kvm_vcpu *vcpu)
return kvm_s390_inject_prog_irq(vcpu, &pgm_info);
}
-static int handle_instruction_and_prog(struct kvm_vcpu *vcpu)
-{
- int rc, rc2;
-
- vcpu->stat.exit_instr_and_program++;
- rc = handle_instruction(vcpu);
- rc2 = handle_prog(vcpu);
-
- if (rc == -EOPNOTSUPP)
- vcpu->arch.sie_block->icptcode = 0x04;
- if (rc)
- return rc;
- return rc2;
-}
-
/**
* handle_external_interrupt - used for external interruption interceptions
*
@@ -355,7 +340,6 @@ static const intercept_handler_t intercept_funcs[] = {
[0x00 >> 2] = handle_noop,
[0x04 >> 2] = handle_instruction,
[0x08 >> 2] = handle_prog,
- [0x0C >> 2] = handle_instruction_and_prog,
[0x10 >> 2] = handle_noop,
[0x14 >> 2] = handle_external_interrupt,
[0x18 >> 2] = handle_noop,
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 9de47265ef73..c98d89708e99 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -134,6 +134,8 @@ static unsigned long deliverable_irqs(struct kvm_vcpu *vcpu)
active_mask = pending_local_irqs(vcpu);
active_mask |= pending_floating_irqs(vcpu);
+ if (!active_mask)
+ return 0;
if (psw_extint_disabled(vcpu))
active_mask &= ~IRQ_PEND_EXT_MASK;
@@ -799,7 +801,7 @@ int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu)
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
uint8_t sigp_ctrl = vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
- if (!sclp_has_sigpif())
+ if (!sclp.has_sigpif)
return test_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs);
return (sigp_ctrl & SIGP_CTRL_C) &&
@@ -941,12 +943,9 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
if (cpu_timer_irq_pending(vcpu))
set_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs);
- do {
- irqs = deliverable_irqs(vcpu);
+ while ((irqs = deliverable_irqs(vcpu)) && !rc) {
/* bits are in the order of interrupt priority */
irq_type = find_first_bit(&irqs, IRQ_PEND_COUNT);
- if (irq_type == IRQ_PEND_COUNT)
- break;
if (is_ioirq(irq_type)) {
rc = __deliver_io(vcpu, irq_type);
} else {
@@ -958,9 +957,7 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
}
rc = func(vcpu);
}
- if (rc)
- break;
- } while (!rc);
+ }
set_intercept_indicators(vcpu);
@@ -1058,10 +1055,10 @@ static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
kvm_get_vcpu(vcpu->kvm, src_id) == NULL)
return -EINVAL;
- if (sclp_has_sigpif())
+ if (sclp.has_sigpif)
return __inject_extcall_sigpif(vcpu, src_id);
- if (!test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs))
+ if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs))
return -EBUSY;
*extcall = irq->u.extcall;
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
@@ -1340,12 +1337,54 @@ static int __inject_io(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
return 0;
}
-static int __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
+/*
+ * Find a destination VCPU for a floating irq and kick it.
+ */
+static void __floating_irq_kick(struct kvm *kvm, u64 type)
{
+ struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int;
struct kvm_s390_local_interrupt *li;
+ struct kvm_vcpu *dst_vcpu;
+ int sigcpu, online_vcpus, nr_tries = 0;
+
+ online_vcpus = atomic_read(&kvm->online_vcpus);
+ if (!online_vcpus)
+ return;
+
+ /* find idle VCPUs first, then round robin */
+ sigcpu = find_first_bit(fi->idle_mask, online_vcpus);
+ if (sigcpu == online_vcpus) {
+ do {
+ sigcpu = fi->next_rr_cpu;
+ fi->next_rr_cpu = (fi->next_rr_cpu + 1) % online_vcpus;
+ /* avoid endless loops if all vcpus are stopped */
+ if (nr_tries++ >= online_vcpus)
+ return;
+ } while (is_vcpu_stopped(kvm_get_vcpu(kvm, sigcpu)));
+ }
+ dst_vcpu = kvm_get_vcpu(kvm, sigcpu);
+
+ /* make the VCPU drop out of the SIE, or wake it up if sleeping */
+ li = &dst_vcpu->arch.local_int;
+ spin_lock(&li->lock);
+ switch (type) {
+ case KVM_S390_MCHK:
+ atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
+ break;
+ case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
+ atomic_set_mask(CPUSTAT_IO_INT, li->cpuflags);
+ break;
+ default:
+ atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+ break;
+ }
+ spin_unlock(&li->lock);
+ kvm_s390_vcpu_wakeup(dst_vcpu);
+}
+
+static int __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
+{
struct kvm_s390_float_interrupt *fi;
- struct kvm_vcpu *dst_vcpu = NULL;
- int sigcpu;
u64 type = READ_ONCE(inti->type);
int rc;
@@ -1373,32 +1412,8 @@ static int __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
if (rc)
return rc;
- sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);
- if (sigcpu == KVM_MAX_VCPUS) {
- do {
- sigcpu = fi->next_rr_cpu++;
- if (sigcpu == KVM_MAX_VCPUS)
- sigcpu = fi->next_rr_cpu = 0;
- } while (kvm_get_vcpu(kvm, sigcpu) == NULL);
- }
- dst_vcpu = kvm_get_vcpu(kvm, sigcpu);
- li = &dst_vcpu->arch.local_int;
- spin_lock(&li->lock);
- switch (type) {
- case KVM_S390_MCHK:
- atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
- break;
- case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
- atomic_set_mask(CPUSTAT_IO_INT, li->cpuflags);
- break;
- default:
- atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
- break;
- }
- spin_unlock(&li->lock);
- kvm_s390_vcpu_wakeup(kvm_get_vcpu(kvm, sigcpu));
+ __floating_irq_kick(kvm, type);
return 0;
-
}
int kvm_s390_inject_vm(struct kvm *kvm,
@@ -1606,6 +1621,9 @@ void kvm_s390_clear_float_irqs(struct kvm *kvm)
int i;
spin_lock(&fi->lock);
+ fi->pending_irqs = 0;
+ memset(&fi->srv_signal, 0, sizeof(fi->srv_signal));
+ memset(&fi->mchk, 0, sizeof(fi->mchk));
for (i = 0; i < FIRQ_LIST_COUNT; i++)
clear_irq_list(&fi->lists[i]);
for (i = 0; i < FIRQ_MAX_COUNT; i++)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 8cd8e7b288c5..2078f92d15ac 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -36,6 +36,10 @@
#include "kvm-s390.h"
#include "gaccess.h"
+#define KMSG_COMPONENT "kvm-s390"
+#undef pr_fmt
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
#define CREATE_TRACE_POINTS
#include "trace.h"
#include "trace-s390.h"
@@ -110,7 +114,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
/* upper facilities limit for kvm */
unsigned long kvm_s390_fac_list_mask[] = {
0xffe6fffbfcfdfc40UL,
- 0x005c800000000000UL,
+ 0x005e800000000000UL,
};
unsigned long kvm_s390_fac_list_mask_size(void)
@@ -236,6 +240,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
{
int r;
unsigned long n;
+ struct kvm_memslots *slots;
struct kvm_memory_slot *memslot;
int is_dirty = 0;
@@ -245,7 +250,8 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
if (log->slot >= KVM_USER_MEM_SLOTS)
goto out;
- memslot = id_to_memslot(kvm->memslots, log->slot);
+ slots = kvm_memslots(kvm);
+ memslot = id_to_memslot(slots, log->slot);
r = -ENOENT;
if (!memslot->dirty_bitmap)
goto out;
@@ -454,10 +460,10 @@ static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
mutex_lock(&kvm->lock);
kvm->arch.epoch = gtod - host_tod;
- kvm_for_each_vcpu(vcpu_idx, cur_vcpu, kvm) {
+ kvm_s390_vcpu_block_all(kvm);
+ kvm_for_each_vcpu(vcpu_idx, cur_vcpu, kvm)
cur_vcpu->arch.sie_block->epoch = kvm->arch.epoch;
- exit_sie(cur_vcpu);
- }
+ kvm_s390_vcpu_unblock_all(kvm);
mutex_unlock(&kvm->lock);
return 0;
}
@@ -604,7 +610,7 @@ static int kvm_s390_get_machine(struct kvm *kvm, struct kvm_device_attr *attr)
goto out;
}
get_cpu_id((struct cpuid *) &mach->cpuid);
- mach->ibc = sclp_get_ibc();
+ mach->ibc = sclp.ibc;
memcpy(&mach->fac_mask, kvm->arch.model.fac->mask,
S390_ARCH_FAC_LIST_SIZE_BYTE);
memcpy((unsigned long *)&mach->fac_list, S390_lowcore.stfle_fac_list,
@@ -1068,7 +1074,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
S390_ARCH_FAC_LIST_SIZE_BYTE);
kvm_s390_get_cpu_id(&kvm->arch.model.cpu_id);
- kvm->arch.model.ibc = sclp_get_ibc() & 0x0fff;
+ kvm->arch.model.ibc = sclp.ibc & 0x0fff;
if (kvm_s390_crypto_init(kvm) < 0)
goto out_err;
@@ -1311,8 +1317,13 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
CPUSTAT_SM |
- CPUSTAT_STOPPED |
- CPUSTAT_GED);
+ CPUSTAT_STOPPED);
+
+ if (test_kvm_facility(vcpu->kvm, 78))
+ atomic_set_mask(CPUSTAT_GED2, &vcpu->arch.sie_block->cpuflags);
+ else if (test_kvm_facility(vcpu->kvm, 8))
+ atomic_set_mask(CPUSTAT_GED, &vcpu->arch.sie_block->cpuflags);
+
kvm_s390_vcpu_setup_model(vcpu);
vcpu->arch.sie_block->ecb = 6;
@@ -1321,9 +1332,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
vcpu->arch.sie_block->ecb2 = 8;
vcpu->arch.sie_block->eca = 0xC1002000U;
- if (sclp_has_siif())
+ if (sclp.has_siif)
vcpu->arch.sie_block->eca |= 1;
- if (sclp_has_sigpif())
+ if (sclp.has_sigpif)
vcpu->arch.sie_block->eca |= 0x10000000U;
if (test_kvm_facility(vcpu->kvm, 129)) {
vcpu->arch.sie_block->eca |= 0x00020000;
@@ -1409,16 +1420,28 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
return kvm_s390_vcpu_has_irq(vcpu, 0);
}
-void s390_vcpu_block(struct kvm_vcpu *vcpu)
+void kvm_s390_vcpu_block(struct kvm_vcpu *vcpu)
{
atomic_set_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20);
+ exit_sie(vcpu);
}
-void s390_vcpu_unblock(struct kvm_vcpu *vcpu)
+void kvm_s390_vcpu_unblock(struct kvm_vcpu *vcpu)
{
atomic_clear_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20);
}
+static void kvm_s390_vcpu_request(struct kvm_vcpu *vcpu)
+{
+ atomic_set_mask(PROG_REQUEST, &vcpu->arch.sie_block->prog20);
+ exit_sie(vcpu);
+}
+
+static void kvm_s390_vcpu_request_handled(struct kvm_vcpu *vcpu)
+{
+ atomic_clear_mask(PROG_REQUEST, &vcpu->arch.sie_block->prog20);
+}
+
/*
* Kick a guest cpu out of SIE and wait until SIE is not running.
* If the CPU is not running (e.g. waiting as idle) the function will
@@ -1430,11 +1453,11 @@ void exit_sie(struct kvm_vcpu *vcpu)
cpu_relax();
}
-/* Kick a guest cpu out of SIE and prevent SIE-reentry */
-void exit_sie_sync(struct kvm_vcpu *vcpu)
+/* Kick a guest cpu out of SIE to process a request synchronously */
+void kvm_s390_sync_request(int req, struct kvm_vcpu *vcpu)
{
- s390_vcpu_block(vcpu);
- exit_sie(vcpu);
+ kvm_make_request(req, vcpu);
+ kvm_s390_vcpu_request(vcpu);
}
static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address)
@@ -1447,8 +1470,7 @@ static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address)
/* match against both prefix pages */
if (kvm_s390_get_prefix(vcpu) == (address & ~0x1000UL)) {
VCPU_EVENT(vcpu, 2, "gmap notifier for %lx", address);
- kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu);
- exit_sie_sync(vcpu);
+ kvm_s390_sync_request(KVM_REQ_MMU_RELOAD, vcpu);
}
}
}
@@ -1720,8 +1742,10 @@ static bool ibs_enabled(struct kvm_vcpu *vcpu)
static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
{
+ if (!vcpu->requests)
+ return 0;
retry:
- s390_vcpu_unblock(vcpu);
+ kvm_s390_vcpu_request_handled(vcpu);
/*
* We use MMU_RELOAD just to re-arm the ipte notifier for the
* guest prefix page. gmap_ipte_notify will wait on the ptl lock.
@@ -1993,12 +2017,14 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
* As PF_VCPU will be used in fault handler, between
* guest_enter and guest_exit should be no uaccess.
*/
- preempt_disable();
- kvm_guest_enter();
- preempt_enable();
+ local_irq_disable();
+ __kvm_guest_enter();
+ local_irq_enable();
exit_reason = sie64a(vcpu->arch.sie_block,
vcpu->run->s.regs.gprs);
- kvm_guest_exit();
+ local_irq_disable();
+ __kvm_guest_exit();
+ local_irq_enable();
vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
rc = vcpu_post_run(vcpu, exit_reason);
@@ -2068,7 +2094,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) {
kvm_s390_vcpu_start(vcpu);
} else if (is_vcpu_stopped(vcpu)) {
- pr_err_ratelimited("kvm-s390: can't run stopped vcpu %d\n",
+ pr_err_ratelimited("can't run stopped vcpu %d\n",
vcpu->vcpu_id);
return -EINVAL;
}
@@ -2206,8 +2232,7 @@ int kvm_s390_vcpu_store_adtl_status(struct kvm_vcpu *vcpu, unsigned long addr)
static void __disable_ibs_on_vcpu(struct kvm_vcpu *vcpu)
{
kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu);
- kvm_make_request(KVM_REQ_DISABLE_IBS, vcpu);
- exit_sie_sync(vcpu);
+ kvm_s390_sync_request(KVM_REQ_DISABLE_IBS, vcpu);
}
static void __disable_ibs_on_all_vcpus(struct kvm *kvm)
@@ -2223,8 +2248,7 @@ static void __disable_ibs_on_all_vcpus(struct kvm *kvm)
static void __enable_ibs_on_vcpu(struct kvm_vcpu *vcpu)
{
kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu);
- kvm_make_request(KVM_REQ_ENABLE_IBS, vcpu);
- exit_sie_sync(vcpu);
+ kvm_s390_sync_request(KVM_REQ_ENABLE_IBS, vcpu);
}
void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu)
@@ -2563,7 +2587,7 @@ int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
/* Section: memory related */
int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
- struct kvm_userspace_memory_region *mem,
+ const struct kvm_userspace_memory_region *mem,
enum kvm_mr_change change)
{
/* A few sanity checks. We can have memory slots which have to be
@@ -2581,8 +2605,9 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
}
void kvm_arch_commit_memory_region(struct kvm *kvm,
- struct kvm_userspace_memory_region *mem,
+ const struct kvm_userspace_memory_region *mem,
const struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new,
enum kvm_mr_change change)
{
int rc;
@@ -2601,7 +2626,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
rc = gmap_map_segment(kvm->arch.gmap, mem->userspace_addr,
mem->guest_phys_addr, mem->memory_size);
if (rc)
- printk(KERN_WARNING "kvm-s390: failed to commit memory region\n");
+ pr_warn("failed to commit memory region\n");
return;
}
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index ca108b90ae56..c5704786e473 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -211,10 +211,10 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr);
int kvm_s390_vcpu_store_adtl_status(struct kvm_vcpu *vcpu, unsigned long addr);
void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu);
void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu);
-void s390_vcpu_block(struct kvm_vcpu *vcpu);
-void s390_vcpu_unblock(struct kvm_vcpu *vcpu);
+void kvm_s390_vcpu_block(struct kvm_vcpu *vcpu);
+void kvm_s390_vcpu_unblock(struct kvm_vcpu *vcpu);
void exit_sie(struct kvm_vcpu *vcpu);
-void exit_sie_sync(struct kvm_vcpu *vcpu);
+void kvm_s390_sync_request(int req, struct kvm_vcpu *vcpu);
int kvm_s390_vcpu_setup_cmma(struct kvm_vcpu *vcpu);
void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu);
/* is cmma enabled */
@@ -228,6 +228,25 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu,
struct kvm_s390_pgm_info *pgm_info);
+static inline void kvm_s390_vcpu_block_all(struct kvm *kvm)
+{
+ int i;
+ struct kvm_vcpu *vcpu;
+
+ WARN_ON(!mutex_is_locked(&kvm->lock));
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ kvm_s390_vcpu_block(vcpu);
+}
+
+static inline void kvm_s390_vcpu_unblock_all(struct kvm *kvm)
+{
+ int i;
+ struct kvm_vcpu *vcpu;
+
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ kvm_s390_vcpu_unblock(vcpu);
+}
+
/**
* kvm_s390_inject_prog_cond - conditionally inject a program check
* @vcpu: virtual cpu
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index d22d8ee1ff9d..ad4242245771 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -698,10 +698,14 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
case 0x00001000:
end = (start + (1UL << 20)) & ~((1UL << 20) - 1);
break;
- /* We dont support EDAT2
case 0x00002000:
+ /* only support 2G frame size if EDAT2 is available and we are
+ not in 24-bit addressing mode */
+ if (!test_kvm_facility(vcpu->kvm, 78) ||
+ psw_bits(vcpu->arch.sie_block->gpsw).eaba == PSW_AMODE_24BIT)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
end = (start + (1UL << 31)) & ~((1UL << 31) - 1);
- break;*/
+ break;
default:
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
}
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 76515bcea2f1..4c8f5d7f9c23 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -399,7 +399,7 @@ static inline int do_exception(struct pt_regs *regs, int access)
* user context.
*/
fault = VM_FAULT_BADCONTEXT;
- if (unlikely(!user_space_fault(regs) || in_atomic() || !mm))
+ if (unlikely(!user_space_fault(regs) || faulthandler_disabled() || !mm))
goto out;
address = trans_exc_code & __FAIL_ADDR_MASK;
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c
index e617e74b7be2..fb4bf2c4379e 100644
--- a/arch/s390/mm/hugetlbpage.c
+++ b/arch/s390/mm/hugetlbpage.c
@@ -86,31 +86,16 @@ static inline pte_t __pmd_to_pte(pmd_t pmd)
void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte)
{
- pmd_t pmd;
+ pmd_t pmd = __pte_to_pmd(pte);
- pmd = __pte_to_pmd(pte);
- if (!MACHINE_HAS_HPAGE) {
- /* Emulated huge ptes loose the dirty and young bit */
- pmd_val(pmd) &= ~_SEGMENT_ENTRY_ORIGIN;
- pmd_val(pmd) |= pte_page(pte)[1].index;
- } else
- pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE;
+ pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE;
*(pmd_t *) ptep = pmd;
}
pte_t huge_ptep_get(pte_t *ptep)
{
- unsigned long origin;
- pmd_t pmd;
+ pmd_t pmd = *(pmd_t *) ptep;
- pmd = *(pmd_t *) ptep;
- if (!MACHINE_HAS_HPAGE && pmd_present(pmd)) {
- origin = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN;
- pmd_val(pmd) &= ~_SEGMENT_ENTRY_ORIGIN;
- pmd_val(pmd) |= *(unsigned long *) origin;
- /* Emulated huge ptes are young and dirty by definition */
- pmd_val(pmd) |= _SEGMENT_ENTRY_YOUNG | _SEGMENT_ENTRY_DIRTY;
- }
return __pmd_to_pte(pmd);
}
@@ -125,45 +110,6 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
return pte;
}
-int arch_prepare_hugepage(struct page *page)
-{
- unsigned long addr = page_to_phys(page);
- pte_t pte;
- pte_t *ptep;
- int i;
-
- if (MACHINE_HAS_HPAGE)
- return 0;
-
- ptep = (pte_t *) pte_alloc_one(&init_mm, addr);
- if (!ptep)
- return -ENOMEM;
-
- pte_val(pte) = addr;
- for (i = 0; i < PTRS_PER_PTE; i++) {
- set_pte_at(&init_mm, addr + i * PAGE_SIZE, ptep + i, pte);
- pte_val(pte) += PAGE_SIZE;
- }
- page[1].index = (unsigned long) ptep;
- return 0;
-}
-
-void arch_release_hugepage(struct page *page)
-{
- pte_t *ptep;
-
- if (MACHINE_HAS_HPAGE)
- return;
-
- ptep = (pte_t *) page[1].index;
- if (!ptep)
- return;
- clear_table((unsigned long *) ptep, _PAGE_INVALID,
- PTRS_PER_PTE * sizeof(pte_t));
- page_table_free(&init_mm, (unsigned long *) ptep);
- page[1].index = 0;
-}
-
pte_t *huge_pte_alloc(struct mm_struct *mm,
unsigned long addr, unsigned long sz)
{
@@ -193,17 +139,9 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
return (pte_t *) pmdp;
}
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
- return 0;
-}
-
int pmd_huge(pmd_t pmd)
{
- if (!MACHINE_HAS_HPAGE)
- return 0;
-
- return !!(pmd_val(pmd) & _SEGMENT_ENTRY_LARGE);
+ return pmd_large(pmd);
}
int pud_huge(pud_t pud)
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 80875c43a4a4..76e873748b56 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -213,7 +213,7 @@ unsigned long memory_block_size_bytes(void)
* Make sure the memory block size is always greater
* or equal than the memory increment size.
*/
- return max_t(unsigned long, MIN_MEMORY_BLOCK_SIZE, sclp_get_rzm());
+ return max_t(unsigned long, MIN_MEMORY_BLOCK_SIZE, sclp.rzm);
}
#ifdef CONFIG_MEMORY_HOTREMOVE
diff --git a/arch/s390/mm/mem_detect.c b/arch/s390/mm/mem_detect.c
index 0f3604395805..e00f0d5d296d 100644
--- a/arch/s390/mm/mem_detect.c
+++ b/arch/s390/mm/mem_detect.c
@@ -31,8 +31,8 @@ void __init detect_memory_memblock(void)
unsigned long addr, size;
int type;
- rzm = sclp_get_rzm();
- rnmax = sclp_get_rnmax();
+ rzm = sclp.rzm;
+ rnmax = sclp.rnmax;
memsize = rzm * rnmax;
if (!rzm)
rzm = 1ULL << 17;
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index b33f66110ca9..33082d0d101b 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -31,6 +31,8 @@
#define ALLOC_ORDER 2
#define FRAG_MASK 0x03
+int HPAGE_SHIFT;
+
unsigned long *crst_table_alloc(struct mm_struct *mm)
{
struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
diff --git a/arch/s390/net/bpf_jit.h b/arch/s390/net/bpf_jit.h
index de156ba3bd71..f6498eec9ee1 100644
--- a/arch/s390/net/bpf_jit.h
+++ b/arch/s390/net/bpf_jit.h
@@ -28,6 +28,9 @@ extern u8 sk_load_word[], sk_load_half[], sk_load_byte[];
* | old backchain | |
* +---------------+ |
* | r15 - r6 | |
+ * +---------------+ |
+ * | 4 byte align | |
+ * | tail_call_cnt | |
* BFP -> +===============+ |
* | | |
* | BPF stack | |
@@ -46,14 +49,17 @@ extern u8 sk_load_word[], sk_load_half[], sk_load_byte[];
* R15 -> +---------------+ + low
*
* We get 160 bytes stack space from calling function, but only use
- * 11 * 8 byte (old backchain + r15 - r6) for storing registers.
+ * 12 * 8 byte for old backchain, r15..r6, and tail_call_cnt.
*/
#define STK_SPACE (MAX_BPF_STACK + 8 + 4 + 4 + 160)
-#define STK_160_UNUSED (160 - 11 * 8)
+#define STK_160_UNUSED (160 - 12 * 8)
#define STK_OFF (STK_SPACE - STK_160_UNUSED)
#define STK_OFF_TMP 160 /* Offset of tmp buffer on stack */
#define STK_OFF_HLEN 168 /* Offset of SKB header length on stack */
+#define STK_OFF_R6 (160 - 11 * 8) /* Offset of r6 on stack */
+#define STK_OFF_TCCNT (160 - 12 * 8) /* Offset of tail_call_cnt on stack */
+
/* Offset to skip condition code check */
#define OFF_OK 4
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index 55423d8be580..d3766dd67e23 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -21,6 +21,7 @@
#include <linux/netdevice.h>
#include <linux/filter.h>
#include <linux/init.h>
+#include <linux/bpf.h>
#include <asm/cacheflush.h>
#include <asm/dis.h>
#include "bpf_jit.h"
@@ -40,6 +41,8 @@ struct bpf_jit {
int base_ip; /* Base address for literal pool */
int ret0_ip; /* Address of return 0 */
int exit_ip; /* Address of exit */
+ int tail_call_start; /* Tail call start offset */
+ int labels[1]; /* Labels for local jumps */
};
#define BPF_SIZE_MAX 4096 /* Max size for program */
@@ -49,6 +52,7 @@ struct bpf_jit {
#define SEEN_RET0 4 /* ret0_ip points to a valid return 0 */
#define SEEN_LITERAL 8 /* code uses literals */
#define SEEN_FUNC 16 /* calls C functions */
+#define SEEN_TAIL_CALL 32 /* code uses tail calls */
#define SEEN_STACK (SEEN_FUNC | SEEN_MEM | SEEN_SKB)
/*
@@ -60,6 +64,7 @@ struct bpf_jit {
#define REG_L (__MAX_BPF_REG+3) /* Literal pool register */
#define REG_15 (__MAX_BPF_REG+4) /* Register 15 */
#define REG_0 REG_W0 /* Register 0 */
+#define REG_1 REG_W1 /* Register 1 */
#define REG_2 BPF_REG_1 /* Register 2 */
#define REG_14 BPF_REG_0 /* Register 14 */
@@ -223,6 +228,24 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1)
REG_SET_SEEN(b3); \
})
+#define EMIT6_PCREL_LABEL(op1, op2, b1, b2, label, mask) \
+({ \
+ int rel = (jit->labels[label] - jit->prg) >> 1; \
+ _EMIT6(op1 | reg(b1, b2) << 16 | (rel & 0xffff), \
+ op2 | mask << 12); \
+ REG_SET_SEEN(b1); \
+ REG_SET_SEEN(b2); \
+})
+
+#define EMIT6_PCREL_IMM_LABEL(op1, op2, b1, imm, label, mask) \
+({ \
+ int rel = (jit->labels[label] - jit->prg) >> 1; \
+ _EMIT6(op1 | (reg_high(b1) | mask) << 16 | \
+ (rel & 0xffff), op2 | (imm & 0xff) << 8); \
+ REG_SET_SEEN(b1); \
+ BUILD_BUG_ON(((unsigned long) imm) > 0xff); \
+})
+
#define EMIT6_PCREL(op1, op2, b1, b2, i, off, mask) \
({ \
/* Branch instruction needs 6 bytes */ \
@@ -286,7 +309,7 @@ static void jit_fill_hole(void *area, unsigned int size)
*/
static void save_regs(struct bpf_jit *jit, u32 rs, u32 re)
{
- u32 off = 72 + (rs - 6) * 8;
+ u32 off = STK_OFF_R6 + (rs - 6) * 8;
if (rs == re)
/* stg %rs,off(%r15) */
@@ -301,7 +324,7 @@ static void save_regs(struct bpf_jit *jit, u32 rs, u32 re)
*/
static void restore_regs(struct bpf_jit *jit, u32 rs, u32 re)
{
- u32 off = 72 + (rs - 6) * 8;
+ u32 off = STK_OFF_R6 + (rs - 6) * 8;
if (jit->seen & SEEN_STACK)
off += STK_OFF;
@@ -374,6 +397,16 @@ static void save_restore_regs(struct bpf_jit *jit, int op)
*/
static void bpf_jit_prologue(struct bpf_jit *jit)
{
+ if (jit->seen & SEEN_TAIL_CALL) {
+ /* xc STK_OFF_TCCNT(4,%r15),STK_OFF_TCCNT(%r15) */
+ _EMIT6(0xd703f000 | STK_OFF_TCCNT, 0xf000 | STK_OFF_TCCNT);
+ } else {
+ /* j tail_call_start: NOP if no tail calls are used */
+ EMIT4_PCREL(0xa7f40000, 6);
+ _EMIT2(0);
+ }
+ /* Tail calls have to skip above initialization */
+ jit->tail_call_start = jit->prg;
/* Save registers */
save_restore_regs(jit, REGS_SAVE);
/* Setup literal pool */
@@ -951,6 +984,75 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i
EMIT4(0xb9040000, BPF_REG_0, REG_2);
break;
}
+ case BPF_JMP | BPF_CALL | BPF_X:
+ /*
+ * Implicit input:
+ * B1: pointer to ctx
+ * B2: pointer to bpf_array
+ * B3: index in bpf_array
+ */
+ jit->seen |= SEEN_TAIL_CALL;
+
+ /*
+ * if (index >= array->map.max_entries)
+ * goto out;
+ */
+
+ /* llgf %w1,map.max_entries(%b2) */
+ EMIT6_DISP_LH(0xe3000000, 0x0016, REG_W1, REG_0, BPF_REG_2,
+ offsetof(struct bpf_array, map.max_entries));
+ /* clgrj %b3,%w1,0xa,label0: if %b3 >= %w1 goto out */
+ EMIT6_PCREL_LABEL(0xec000000, 0x0065, BPF_REG_3,
+ REG_W1, 0, 0xa);
+
+ /*
+ * if (tail_call_cnt++ > MAX_TAIL_CALL_CNT)
+ * goto out;
+ */
+
+ if (jit->seen & SEEN_STACK)
+ off = STK_OFF_TCCNT + STK_OFF;
+ else
+ off = STK_OFF_TCCNT;
+ /* lhi %w0,1 */
+ EMIT4_IMM(0xa7080000, REG_W0, 1);
+ /* laal %w1,%w0,off(%r15) */
+ EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W1, REG_W0, REG_15, off);
+ /* clij %w1,MAX_TAIL_CALL_CNT,0x2,label0 */
+ EMIT6_PCREL_IMM_LABEL(0xec000000, 0x007f, REG_W1,
+ MAX_TAIL_CALL_CNT, 0, 0x2);
+
+ /*
+ * prog = array->prog[index];
+ * if (prog == NULL)
+ * goto out;
+ */
+
+ /* sllg %r1,%b3,3: %r1 = index * 8 */
+ EMIT6_DISP_LH(0xeb000000, 0x000d, REG_1, BPF_REG_3, REG_0, 3);
+ /* lg %r1,prog(%b2,%r1) */
+ EMIT6_DISP_LH(0xe3000000, 0x0004, REG_1, BPF_REG_2,
+ REG_1, offsetof(struct bpf_array, prog));
+ /* clgij %r1,0,0x8,label0 */
+ EMIT6_PCREL_IMM_LABEL(0xec000000, 0x007d, REG_1, 0, 0, 0x8);
+
+ /*
+ * Restore registers before calling function
+ */
+ save_restore_regs(jit, REGS_RESTORE);
+
+ /*
+ * goto *(prog->bpf_func + tail_call_start);
+ */
+
+ /* lg %r1,bpf_func(%r1) */
+ EMIT6_DISP_LH(0xe3000000, 0x0004, REG_1, REG_1, REG_0,
+ offsetof(struct bpf_prog, bpf_func));
+ /* bc 0xf,tail_call_start(%r1) */
+ _EMIT4(0x47f01000 + jit->tail_call_start);
+ /* out: */
+ jit->labels[0] = jit->prg;
+ break;
case BPF_JMP | BPF_EXIT: /* return b0 */
last = (i == fp->len - 1) ? 1 : 0;
if (last && !(jit->seen & SEEN_RET0))
diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c
index 460fdb21cf61..ed2394dd14e9 100644
--- a/arch/s390/pci/pci_event.c
+++ b/arch/s390/pci/pci_event.c
@@ -75,7 +75,13 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
zpci_err_hex(ccdf, sizeof(*ccdf));
switch (ccdf->pec) {
- case 0x0301: /* Standby -> Configured */
+ case 0x0301: /* Reserved|Standby -> Configured */
+ if (!zdev) {
+ ret = clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
+ if (ret)
+ break;
+ zdev = get_zdev_by_fid(ccdf->fid);
+ }
if (!zdev || zdev->state != ZPCI_FN_STATE_STANDBY)
break;
zdev->state = ZPCI_FN_STATE_CONFIGURED;
diff --git a/arch/score/include/asm/Kbuild b/arch/score/include/asm/Kbuild
index 83ed116d414c..138fb3db45ba 100644
--- a/arch/score/include/asm/Kbuild
+++ b/arch/score/include/asm/Kbuild
@@ -8,7 +8,6 @@ generic-y += cputime.h
generic-y += irq_work.h
generic-y += mcs_spinlock.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += trace_clock.h
generic-y += xor.h
diff --git a/arch/score/include/asm/cmpxchg.h b/arch/score/include/asm/cmpxchg.h
index f384839c3ee5..cc3f6420b71c 100644
--- a/arch/score/include/asm/cmpxchg.h
+++ b/arch/score/include/asm/cmpxchg.h
@@ -42,8 +42,6 @@ static inline unsigned long __cmpxchg(volatile unsigned long *m,
(unsigned long)(o), \
(unsigned long)(n)))
-#define __HAVE_ARCH_CMPXCHG 1
-
#include <asm-generic/cmpxchg-local.h>
#endif /* _ASM_SCORE_CMPXCHG_H */
diff --git a/arch/score/include/asm/mm-arch-hooks.h b/arch/score/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..5e38689f189a
--- /dev/null
+++ b/arch/score/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_SCORE_MM_ARCH_HOOKS_H
+#define _ASM_SCORE_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_SCORE_MM_ARCH_HOOKS_H */
diff --git a/arch/score/include/asm/uaccess.h b/arch/score/include/asm/uaccess.h
index ab66ddde777b..20a3591225cc 100644
--- a/arch/score/include/asm/uaccess.h
+++ b/arch/score/include/asm/uaccess.h
@@ -36,7 +36,8 @@
* @addr: User space pointer to start of block to check
* @size: Size of block to check
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Checks if a pointer to a block of memory in user space is valid.
*
@@ -61,7 +62,8 @@
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
@@ -79,7 +81,8 @@
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
@@ -98,7 +101,8 @@
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
@@ -119,7 +123,8 @@
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
diff --git a/arch/score/mm/fault.c b/arch/score/mm/fault.c
index 6860beb2a280..37a6c2e0e969 100644
--- a/arch/score/mm/fault.c
+++ b/arch/score/mm/fault.c
@@ -34,6 +34,7 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/ptrace.h>
+#include <linux/uaccess.h>
/*
* This routine handles page faults. It determines the address,
@@ -73,7 +74,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write,
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm)
+ if (pagefault_disabled() || !mm)
goto bad_area_nosemaphore;
if (user_mode(regs))
diff --git a/arch/sh/drivers/pci/ops-sh5.c b/arch/sh/drivers/pci/ops-sh5.c
index 4ce95a001b80..45361946460f 100644
--- a/arch/sh/drivers/pci/ops-sh5.c
+++ b/arch/sh/drivers/pci/ops-sh5.c
@@ -18,7 +18,6 @@
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/irq.h>
-#include <asm/pci.h>
#include <asm/io.h>
#include "pci-sh5.h"
diff --git a/arch/sh/drivers/pci/pci-sh5.c b/arch/sh/drivers/pci/pci-sh5.c
index 16c1e721bf54..8229114c6a58 100644
--- a/arch/sh/drivers/pci/pci-sh5.c
+++ b/arch/sh/drivers/pci/pci-sh5.c
@@ -20,7 +20,6 @@
#include <linux/types.h>
#include <linux/irq.h>
#include <cpu/irq.h>
-#include <asm/pci.h>
#include <asm/io.h>
#include "pci-sh5.h"
diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild
index 654ebb6bd5d8..9ac4626e7284 100644
--- a/arch/sh/include/asm/Kbuild
+++ b/arch/sh/include/asm/Kbuild
@@ -24,7 +24,6 @@ generic-y += percpu.h
generic-y += poll.h
generic-y += preempt.h
generic-y += resource.h
-generic-y += scatterlist.h
generic-y += sembuf.h
generic-y += serial.h
generic-y += shmbuf.h
diff --git a/arch/sh/include/asm/barrier.h b/arch/sh/include/asm/barrier.h
index 43715308b068..bf91037db4e0 100644
--- a/arch/sh/include/asm/barrier.h
+++ b/arch/sh/include/asm/barrier.h
@@ -32,7 +32,7 @@
#define ctrl_barrier() __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop")
#endif
-#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
+#define smp_store_mb(var, value) do { (void)xchg(&var, value); } while (0)
#include <asm-generic/barrier.h>
diff --git a/arch/sh/include/asm/cmpxchg.h b/arch/sh/include/asm/cmpxchg.h
index f6bd1406b897..85c97b188d71 100644
--- a/arch/sh/include/asm/cmpxchg.h
+++ b/arch/sh/include/asm/cmpxchg.h
@@ -46,8 +46,6 @@ extern void __xchg_called_with_bad_pointer(void);
* if something tries to do an invalid cmpxchg(). */
extern void __cmpxchg_called_with_bad_pointer(void);
-#define __HAVE_ARCH_CMPXCHG 1
-
static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
unsigned long new, int size)
{
diff --git a/arch/sh/include/asm/hugetlb.h b/arch/sh/include/asm/hugetlb.h
index 699255d6d1c6..ef489a56fcce 100644
--- a/arch/sh/include/asm/hugetlb.h
+++ b/arch/sh/include/asm/hugetlb.h
@@ -26,9 +26,6 @@ static inline int prepare_hugepage_range(struct file *file,
return 0;
}
-static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm) {
-}
-
static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
unsigned long addr, unsigned long end,
unsigned long floor,
@@ -82,15 +79,6 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
return *ptep;
}
-static inline int arch_prepare_hugepage(struct page *page)
-{
- return 0;
-}
-
-static inline void arch_release_hugepage(struct page *page)
-{
-}
-
static inline void arch_clear_hugepage_flags(struct page *page)
{
clear_bit(PG_dcache_clean, &page->flags);
diff --git a/arch/sh/include/asm/mm-arch-hooks.h b/arch/sh/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..18087298b728
--- /dev/null
+++ b/arch/sh/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_SH_MM_ARCH_HOOKS_H
+#define _ASM_SH_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_SH_MM_ARCH_HOOKS_H */
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 5b4511552998..e343dbd02e41 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -86,24 +86,6 @@ extern void pcibios_set_master(struct pci_dev *dev);
* direct memory write.
*/
#define PCI_DISABLE_MWI
-
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- unsigned long cacheline_size;
- u8 byte;
-
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
-
- if (byte == 0)
- cacheline_size = L1_CACHE_BYTES;
- else
- cacheline_size = byte << 2;
-
- *strat = PCI_DMA_BURST_MULTIPLE;
- *strategy_parameter = cacheline_size;
-}
#endif
/* Board-specific fixup routines. */
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7734.c b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
index 1fdf1ee672de..7f54bf2f453d 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
@@ -246,8 +246,7 @@ int __init arch_clk_init(void)
for (i = 0; i < ARRAY_SIZE(main_clks); i++)
ret |= clk_register(main_clks[i]);
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
index 9a28fdb36387..e40ec2c97ad1 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
@@ -141,8 +141,8 @@ int __init arch_clk_init(void)
for (i = 0; i < ARRAY_SIZE(clks); i++)
ret |= clk_register(clks[i]);
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
index 17d0ea55a5a2..8eb6e62340c9 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
@@ -164,8 +164,8 @@ int __init arch_clk_init(void)
for (i = 0; i < ARRAY_SIZE(clks); i++)
ret |= clk_register(clks[i]);
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
index bec2a83f1ba5..5e50e7ebeff0 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
@@ -179,8 +179,8 @@ int __init arch_clk_init(void)
for (i = 0; i < ARRAY_SIZE(clks); i++)
ret |= clk_register(clks[i]);
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-shx3.c b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
index 9a49a44f6f94..605221d1448a 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
@@ -138,8 +138,8 @@ int __init arch_clk_init(void)
for (i = 0; i < ARRAY_SIZE(clks); i++)
ret |= clk_register(clks[i]);
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index a58fec9b55e0..79d8276377d1 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault.c
@@ -17,6 +17,7 @@
#include <linux/kprobes.h>
#include <linux/perf_event.h>
#include <linux/kdebug.h>
+#include <linux/uaccess.h>
#include <asm/io_trapped.h>
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
@@ -438,9 +439,9 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
/*
* If we're in an interrupt, have no user context or are running
- * in an atomic region then we must not take the fault:
+ * with pagefaults disabled then we must not take the fault:
*/
- if (unlikely(in_atomic() || !mm)) {
+ if (unlikely(faulthandler_disabled() || !mm)) {
bad_area_nosemaphore(regs, error_code, address);
return;
}
diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c
index 534bc978af8a..6385f60209b6 100644
--- a/arch/sh/mm/hugetlbpage.c
+++ b/arch/sh/mm/hugetlbpage.c
@@ -62,11 +62,6 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
return pte;
}
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
- return 0;
-}
-
int pmd_huge(pmd_t pmd)
{
return 0;
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index e49502acbab4..56442d2d7bbc 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -25,6 +25,7 @@ config SPARC
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select RTC_CLASS
select RTC_DRV_M48T59
+ select RTC_SYSTOHC
select HAVE_DMA_ATTRS
select HAVE_DMA_API_DEBUG
select HAVE_ARCH_JUMP_LABEL if SPARC64
@@ -35,7 +36,6 @@ config SPARC
select HAVE_BPF_JIT
select HAVE_DEBUG_BUGVERBOSE
select GENERIC_SMP_IDLE_THREAD
- select GENERIC_CMOS_UPDATE
select GENERIC_CLOCKEVENTS
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
diff --git a/arch/sparc/crypto/md5_glue.c b/arch/sparc/crypto/md5_glue.c
index b688731d7ede..c9d2b922734b 100644
--- a/arch/sparc/crypto/md5_glue.c
+++ b/arch/sparc/crypto/md5_glue.c
@@ -33,10 +33,10 @@ static int md5_sparc64_init(struct shash_desc *desc)
{
struct md5_state *mctx = shash_desc_ctx(desc);
- mctx->hash[0] = cpu_to_le32(0x67452301);
- mctx->hash[1] = cpu_to_le32(0xefcdab89);
- mctx->hash[2] = cpu_to_le32(0x98badcfe);
- mctx->hash[3] = cpu_to_le32(0x10325476);
+ mctx->hash[0] = cpu_to_le32(MD5_H0);
+ mctx->hash[1] = cpu_to_le32(MD5_H1);
+ mctx->hash[2] = cpu_to_le32(MD5_H2);
+ mctx->hash[3] = cpu_to_le32(MD5_H3);
mctx->byte_count = 0;
return 0;
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index 94f36e7086a7..2b2a69dcc467 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -15,7 +15,6 @@ generic-y += mcs_spinlock.h
generic-y += module.h
generic-y += mutex.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += serial.h
generic-y += trace_clock.h
generic-y += types.h
diff --git a/arch/sparc/include/asm/barrier_64.h b/arch/sparc/include/asm/barrier_64.h
index 76648941fea7..809941e33e12 100644
--- a/arch/sparc/include/asm/barrier_64.h
+++ b/arch/sparc/include/asm/barrier_64.h
@@ -40,8 +40,8 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
#define dma_rmb() rmb()
#define dma_wmb() wmb()
-#define set_mb(__var, __value) \
- do { __var = __value; membar_safe("#StoreLoad"); } while(0)
+#define smp_store_mb(__var, __value) \
+ do { WRITE_ONCE(__var, __value); membar_safe("#StoreLoad"); } while(0)
#ifdef CONFIG_SMP
#define smp_mb() mb()
diff --git a/arch/sparc/include/asm/cmpxchg_32.h b/arch/sparc/include/asm/cmpxchg_32.h
index d38b52dca216..83ffb83c5397 100644
--- a/arch/sparc/include/asm/cmpxchg_32.h
+++ b/arch/sparc/include/asm/cmpxchg_32.h
@@ -34,7 +34,6 @@ static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int
*
* Cribbed from <asm-parisc/atomic.h>
*/
-#define __HAVE_ARCH_CMPXCHG 1
/* bug catcher for when unsupported size is used - won't link */
void __cmpxchg_called_with_bad_pointer(void);
diff --git a/arch/sparc/include/asm/cmpxchg_64.h b/arch/sparc/include/asm/cmpxchg_64.h
index 0e1ed6cfbf68..faa2f61058c2 100644
--- a/arch/sparc/include/asm/cmpxchg_64.h
+++ b/arch/sparc/include/asm/cmpxchg_64.h
@@ -65,8 +65,6 @@ static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
#include <asm-generic/cmpxchg-local.h>
-#define __HAVE_ARCH_CMPXCHG 1
-
static inline unsigned long
__cmpxchg_u32(volatile int *m, int old, int new)
{
diff --git a/arch/sparc/include/asm/hugetlb.h b/arch/sparc/include/asm/hugetlb.h
index e4cab465b81f..139e711ff80c 100644
--- a/arch/sparc/include/asm/hugetlb.h
+++ b/arch/sparc/include/asm/hugetlb.h
@@ -11,10 +11,6 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep);
-static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
-{
-}
-
static inline int is_hugepage_only_range(struct mm_struct *mm,
unsigned long addr,
unsigned long len) {
@@ -82,15 +78,6 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
return *ptep;
}
-static inline int arch_prepare_hugepage(struct page *page)
-{
- return 0;
-}
-
-static inline void arch_release_hugepage(struct page *page)
-{
-}
-
static inline void arch_clear_hugepage_flags(struct page *page)
{
}
diff --git a/arch/sparc/include/asm/io_32.h b/arch/sparc/include/asm/io_32.h
index 407ac14295f4..57f26c398dc9 100644
--- a/arch/sparc/include/asm/io_32.h
+++ b/arch/sparc/include/asm/io_32.h
@@ -129,6 +129,7 @@ static inline void sbus_memcpy_toio(volatile void __iomem *dst,
void __iomem *ioremap(unsigned long offset, unsigned long size);
#define ioremap_nocache(X,Y) ioremap((X),(Y))
#define ioremap_wc(X,Y) ioremap((X),(Y))
+#define ioremap_wt(X,Y) ioremap((X),(Y))
void iounmap(volatile void __iomem *addr);
/* Create a virtual mapping cookie for an IO port range */
diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h
index 50d4840d9aeb..c32fa3f752c8 100644
--- a/arch/sparc/include/asm/io_64.h
+++ b/arch/sparc/include/asm/io_64.h
@@ -402,6 +402,7 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
#define ioremap_nocache(X,Y) ioremap((X),(Y))
#define ioremap_wc(X,Y) ioremap((X),(Y))
+#define ioremap_wt(X,Y) ioremap((X),(Y))
static inline void iounmap(volatile void __iomem *addr)
{
diff --git a/arch/sparc/include/asm/mm-arch-hooks.h b/arch/sparc/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..b89ba44c16f1
--- /dev/null
+++ b/arch/sparc/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_SPARC_MM_ARCH_HOOKS_H
+#define _ASM_SPARC_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_SPARC_MM_ARCH_HOOKS_H */
diff --git a/arch/sparc/include/asm/pci_32.h b/arch/sparc/include/asm/pci_32.h
index 53e9b4987db0..b7c092df3134 100644
--- a/arch/sparc/include/asm/pci_32.h
+++ b/arch/sparc/include/asm/pci_32.h
@@ -22,16 +22,6 @@
struct pci_dev;
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- *strat = PCI_DMA_BURST_INFINITY;
- *strategy_parameter = ~0UL;
-}
-#endif
-
#endif /* __KERNEL__ */
#ifndef CONFIG_LEON_PCI
diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h
index bd00a6226169..022d16008a00 100644
--- a/arch/sparc/include/asm/pci_64.h
+++ b/arch/sparc/include/asm/pci_64.h
@@ -31,25 +31,6 @@
#define PCI64_REQUIRED_MASK (~(u64)0)
#define PCI64_ADDR_BASE 0xfffc000000000000UL
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- unsigned long cacheline_size;
- u8 byte;
-
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
- if (byte == 0)
- cacheline_size = 1024;
- else
- cacheline_size = (int) byte * 4;
-
- *strat = PCI_DMA_BURST_BOUNDARY;
- *strategy_parameter = cacheline_size;
-}
-#endif
-
/* Return the index of the PCI controller for device PDEV. */
int pci_domain_nr(struct pci_bus *bus);
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 2a52c91d2c8a..131d36fcd07a 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -865,10 +865,10 @@ static inline unsigned long pud_pfn(pud_t pud)
void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
pte_t *ptep, pte_t orig, int fullmm);
-#define __HAVE_ARCH_PMDP_GET_AND_CLEAR
-static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
- unsigned long addr,
- pmd_t *pmdp)
+#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
+static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
+ unsigned long addr,
+ pmd_t *pmdp)
{
pmd_t pmd = *pmdp;
set_pmd_at(mm, addr, pmdp, __pmd(0UL));
diff --git a/arch/sparc/include/asm/topology_64.h b/arch/sparc/include/asm/topology_64.h
index d1761df5cca6..01d17046225a 100644
--- a/arch/sparc/include/asm/topology_64.h
+++ b/arch/sparc/include/asm/topology_64.h
@@ -41,7 +41,7 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
#define topology_physical_package_id(cpu) (cpu_data(cpu).proc_id)
#define topology_core_id(cpu) (cpu_data(cpu).core_id)
#define topology_core_cpumask(cpu) (&cpu_core_sib_map[cpu])
-#define topology_thread_cpumask(cpu) (&per_cpu(cpu_sibling_map, cpu))
+#define topology_sibling_cpumask(cpu) (&per_cpu(cpu_sibling_map, cpu))
#endif /* CONFIG_SMP */
extern cpumask_t cpu_core_map[NR_CPUS];
diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h
index a35194b7dba0..ea6e9a20f3ff 100644
--- a/arch/sparc/include/asm/uaccess_64.h
+++ b/arch/sparc/include/asm/uaccess_64.h
@@ -49,6 +49,28 @@ do { \
__asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" ((val).seg)); \
} while(0)
+/*
+ * Test whether a block of memory is a valid user space address.
+ * Returns 0 if the range is valid, nonzero otherwise.
+ */
+static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, unsigned long limit)
+{
+ if (__builtin_constant_p(size))
+ return addr > limit - size;
+
+ addr += size;
+ if (addr < size)
+ return true;
+
+ return addr > limit;
+}
+
+#define __range_not_ok(addr, size, limit) \
+({ \
+ __chk_user_ptr(addr); \
+ __chk_range_not_ok((unsigned long __force)(addr), size, limit); \
+})
+
static inline int __access_ok(const void __user * addr, unsigned long size)
{
return 1;
diff --git a/arch/sparc/kernel/iommu_common.h b/arch/sparc/kernel/iommu_common.h
index f4be0d724fc6..b40cec252905 100644
--- a/arch/sparc/kernel/iommu_common.h
+++ b/arch/sparc/kernel/iommu_common.h
@@ -13,9 +13,9 @@
#include <linux/scatterlist.h>
#include <linux/device.h>
#include <linux/iommu-helper.h>
+#include <linux/scatterlist.h>
#include <asm/iommu.h>
-#include <asm/scatterlist.h>
/*
* These give mapping size of each iommu pte/tlb.
diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c
index 7d3ca30fcd15..1ae5eb1bb045 100644
--- a/arch/sparc/kernel/ldc.c
+++ b/arch/sparc/kernel/ldc.c
@@ -2086,6 +2086,7 @@ int ldc_map_sg(struct ldc_channel *lp,
struct cookie_state state;
struct ldc_iommu *iommu;
int err;
+ struct scatterlist *s;
if (map_perm & ~LDC_MAP_ALL)
return -EINVAL;
@@ -2112,9 +2113,10 @@ int ldc_map_sg(struct ldc_channel *lp,
state.pte_idx = (base - iommu->page_table);
state.nc = 0;
- for (i = 0; i < num_sg; i++)
- fill_cookies(&state, page_to_pfn(sg_page(&sg[i])) << PAGE_SHIFT,
- sg[i].offset, sg[i].length);
+ for_each_sg(sg, s, num_sg, i) {
+ fill_cookies(&state, page_to_pfn(sg_page(s)) << PAGE_SHIFT,
+ s->offset, s->length);
+ }
return state.nc;
}
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index 59cf917a77b5..689db65f8529 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -21,7 +21,7 @@
#include <asm/stacktrace.h>
#include <asm/cpudata.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/atomic.h>
#include <asm/nmi.h>
#include <asm/pcr.h>
@@ -1741,18 +1741,31 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
} while (entry->nr < PERF_MAX_STACK_DEPTH);
}
+static inline int
+valid_user_frame(const void __user *fp, unsigned long size)
+{
+ /* addresses should be at least 4-byte aligned */
+ if (((unsigned long) fp) & 3)
+ return 0;
+
+ return (__range_not_ok(fp, size, TASK_SIZE) == 0);
+}
+
static void perf_callchain_user_64(struct perf_callchain_entry *entry,
struct pt_regs *regs)
{
unsigned long ufp;
- ufp = regs->u_regs[UREG_I6] + STACK_BIAS;
+ ufp = regs->u_regs[UREG_FP] + STACK_BIAS;
do {
struct sparc_stackf __user *usf;
struct sparc_stackf sf;
unsigned long pc;
usf = (struct sparc_stackf __user *)ufp;
+ if (!valid_user_frame(usf, sizeof(sf)))
+ break;
+
if (__copy_from_user_inatomic(&sf, usf, sizeof(sf)))
break;
@@ -1767,7 +1780,7 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry,
{
unsigned long ufp;
- ufp = regs->u_regs[UREG_I6] & 0xffffffffUL;
+ ufp = regs->u_regs[UREG_FP] & 0xffffffffUL;
do {
unsigned long pc;
@@ -1803,8 +1816,13 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
return;
flushw_user();
+
+ pagefault_disable();
+
if (test_thread_flag(TIF_32BIT))
perf_callchain_user_32(entry, regs);
else
perf_callchain_user_64(entry, regs);
+
+ pagefault_enable();
}
diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c
index 8caf45ee81d9..c9692f387cee 100644
--- a/arch/sparc/kernel/time_32.c
+++ b/arch/sparc/kernel/time_32.c
@@ -23,7 +23,6 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/time.h>
-#include <linux/rtc.h>
#include <linux/rtc/m48t59.h>
#include <linux/timex.h>
#include <linux/clocksource.h>
@@ -65,8 +64,6 @@ DEFINE_PER_CPU(struct clock_event_device, sparc32_clockevent);
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);
-static int set_rtc_mmss(unsigned long);
-
unsigned long profile_pc(struct pt_regs *regs)
{
extern char __copy_user_begin[], __copy_user_end[];
@@ -87,11 +84,6 @@ EXPORT_SYMBOL(profile_pc);
volatile u32 __iomem *master_l10_counter;
-int update_persistent_clock(struct timespec now)
-{
- return set_rtc_mmss(now.tv_sec);
-}
-
irqreturn_t notrace timer_interrupt(int dummy, void *dev_id)
{
if (timer_cs_enabled) {
@@ -362,16 +354,3 @@ void __init time_init(void)
sbus_time_init();
}
-
-static int set_rtc_mmss(unsigned long secs)
-{
- struct rtc_device *rtc = rtc_class_open("rtc0");
- int err = -1;
-
- if (rtc) {
- err = rtc_set_mmss(rtc, secs);
- rtc_class_close(rtc);
- }
-
- return err;
-}
diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c
index edbbeb157d46..2e6035c0a8ca 100644
--- a/arch/sparc/kernel/time_64.c
+++ b/arch/sparc/kernel/time_64.c
@@ -28,7 +28,6 @@
#include <linux/cpufreq.h>
#include <linux/percpu.h>
#include <linux/miscdevice.h>
-#include <linux/rtc.h>
#include <linux/rtc/m48t59.h>
#include <linux/kernel_stat.h>
#include <linux/clockchips.h>
@@ -394,19 +393,6 @@ static struct sparc64_tick_ops hbtick_operations __read_mostly = {
static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
-int update_persistent_clock(struct timespec now)
-{
- struct rtc_device *rtc = rtc_class_open("rtc0");
- int err = -1;
-
- if (rtc) {
- err = rtc_set_mmss(rtc, now.tv_sec);
- rtc_class_close(rtc);
- }
-
- return err;
-}
-
unsigned long cmos_regs;
EXPORT_SYMBOL(cmos_regs);
diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c
index 70d817154fe8..c399e7b3b035 100644
--- a/arch/sparc/mm/fault_32.c
+++ b/arch/sparc/mm/fault_32.c
@@ -21,6 +21,7 @@
#include <linux/perf_event.h>
#include <linux/interrupt.h>
#include <linux/kdebug.h>
+#include <linux/uaccess.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -29,7 +30,6 @@
#include <asm/setup.h>
#include <asm/smp.h>
#include <asm/traps.h>
-#include <asm/uaccess.h>
#include "mm_32.h"
@@ -196,7 +196,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm)
+ if (pagefault_disabled() || !mm)
goto no_context;
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c
index 479823249429..dbabe5713a15 100644
--- a/arch/sparc/mm/fault_64.c
+++ b/arch/sparc/mm/fault_64.c
@@ -22,12 +22,12 @@
#include <linux/kdebug.h>
#include <linux/percpu.h>
#include <linux/context_tracking.h>
+#include <linux/uaccess.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
-#include <asm/uaccess.h>
#include <asm/asi.h>
#include <asm/lsu.h>
#include <asm/sections.h>
@@ -330,7 +330,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto intr_or_no_mm;
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
@@ -413,8 +413,9 @@ good_area:
* that here.
*/
if ((fault_code & FAULT_CODE_ITLB) && !(vma->vm_flags & VM_EXEC)) {
- BUG_ON(address != regs->tpc);
- BUG_ON(regs->tstate & TSTATE_PRIV);
+ WARN(address != regs->tpc,
+ "address (%lx) != regs->tpc (%lx)\n", address, regs->tpc);
+ WARN_ON(regs->tstate & TSTATE_PRIV);
goto bad_area;
}
diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c
index 449f864f0cef..a454ec5ff07a 100644
--- a/arch/sparc/mm/highmem.c
+++ b/arch/sparc/mm/highmem.c
@@ -53,7 +53,7 @@ void *kmap_atomic(struct page *page)
unsigned long vaddr;
long idx, type;
- /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+ preempt_disable();
pagefault_disable();
if (!PageHighMem(page))
return page_address(page);
@@ -91,6 +91,7 @@ void __kunmap_atomic(void *kvaddr)
if (vaddr < FIXADDR_START) { // FIXME
pagefault_enable();
+ preempt_enable();
return;
}
@@ -126,5 +127,6 @@ void __kunmap_atomic(void *kvaddr)
kmap_atomic_idx_pop();
pagefault_enable();
+ preempt_enable();
}
EXPORT_SYMBOL(__kunmap_atomic);
diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c
index 4242eab12e10..131eaf4ad7f5 100644
--- a/arch/sparc/mm/hugetlbpage.c
+++ b/arch/sparc/mm/hugetlbpage.c
@@ -172,11 +172,6 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
return pte;
}
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
- return 0;
-}
-
void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t entry)
{
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 559cb744112c..4ac88b757514 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -1966,7 +1966,8 @@ static phys_addr_t __init available_memory(void)
phys_addr_t pa_start, pa_end;
u64 i;
- for_each_free_mem_range(i, NUMA_NO_NODE, &pa_start, &pa_end, NULL)
+ for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &pa_start,
+ &pa_end, NULL)
available = available + (pa_end - pa_start);
return available;
@@ -1992,7 +1993,8 @@ static void __init reduce_memory(phys_addr_t limit_ram)
if (limit_ram >= avail_ram)
return;
- for_each_free_mem_range(i, NUMA_NO_NODE, &pa_start, &pa_end, NULL) {
+ for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &pa_start,
+ &pa_end, NULL) {
phys_addr_t region_size = pa_end - pa_start;
phys_addr_t clip_start = pa_start;
@@ -2738,7 +2740,7 @@ void hugetlb_setup(struct pt_regs *regs)
struct mm_struct *mm = current->mm;
struct tsb_config *tp;
- if (in_atomic() || !mm) {
+ if (faulthandler_disabled() || !mm) {
const struct exception_table_entry *entry;
entry = search_exception_tables(regs->tpc);
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index a07e31b50d3f..59cf0b911898 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -28,6 +28,7 @@ config TILE
select HAVE_DEBUG_STACKOVERFLOW
select ARCH_WANT_FRAME_POINTERS
select HAVE_CONTEXT_TRACKING
+ select EDAC_SUPPORT
# FIXME: investigate whether we need/want these options.
# select HAVE_IOREMAP_PROT
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild
index f5433e0e34e0..d53654488c2c 100644
--- a/arch/tile/include/asm/Kbuild
+++ b/arch/tile/include/asm/Kbuild
@@ -27,7 +27,6 @@ generic-y += poll.h
generic-y += posix_types.h
generic-y += preempt.h
generic-y += resource.h
-generic-y += scatterlist.h
generic-y += sembuf.h
generic-y += serial.h
generic-y += shmbuf.h
diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h
index 7b11c5fadd42..0496970cef82 100644
--- a/arch/tile/include/asm/atomic_64.h
+++ b/arch/tile/include/asm/atomic_64.h
@@ -105,9 +105,6 @@ static inline long atomic64_add_unless(atomic64_t *v, long a, long u)
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
-/* Define this to indicate that cmpxchg is an efficient operation. */
-#define __HAVE_ARCH_CMPXCHG
-
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_TILE_ATOMIC_64_H */
diff --git a/arch/tile/include/asm/edac.h b/arch/tile/include/asm/edac.h
deleted file mode 100644
index 87fc83eeaffd..000000000000
--- a/arch/tile/include/asm/edac.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2011 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_EDAC_H
-#define _ASM_TILE_EDAC_H
-
-/* ECC atomic, DMA, SMP and interrupt safe scrub function */
-
-static inline void atomic_scrub(void *va, u32 size)
-{
- /*
- * These is nothing to be done here because CE is
- * corrected by the mshim.
- */
- return;
-}
-
-#endif /* _ASM_TILE_EDAC_H */
diff --git a/arch/tile/include/asm/hugetlb.h b/arch/tile/include/asm/hugetlb.h
index 3257733003f8..2fac5be4de26 100644
--- a/arch/tile/include/asm/hugetlb.h
+++ b/arch/tile/include/asm/hugetlb.h
@@ -40,10 +40,6 @@ static inline int prepare_hugepage_range(struct file *file,
return 0;
}
-static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
-{
-}
-
static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
unsigned long addr, unsigned long end,
unsigned long floor,
@@ -98,15 +94,6 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
return *ptep;
}
-static inline int arch_prepare_hugepage(struct page *page)
-{
- return 0;
-}
-
-static inline void arch_release_hugepage(struct page *page)
-{
-}
-
static inline void arch_clear_hugepage_flags(struct page *page)
{
}
diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h
index 6ef4ecab1df2..dc61de15c1f9 100644
--- a/arch/tile/include/asm/io.h
+++ b/arch/tile/include/asm/io.h
@@ -54,7 +54,7 @@ extern void iounmap(volatile void __iomem *addr);
#define ioremap_nocache(physaddr, size) ioremap(physaddr, size)
#define ioremap_wc(physaddr, size) ioremap(physaddr, size)
-#define ioremap_writethrough(physaddr, size) ioremap(physaddr, size)
+#define ioremap_wt(physaddr, size) ioremap(physaddr, size)
#define ioremap_fullcache(physaddr, size) ioremap(physaddr, size)
#define mmiowb()
diff --git a/arch/tile/include/asm/mm-arch-hooks.h b/arch/tile/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..d1709ea774f7
--- /dev/null
+++ b/arch/tile/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_TILE_MM_ARCH_HOOKS_H
+#define _ASM_TILE_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_TILE_MM_ARCH_HOOKS_H */
diff --git a/arch/tile/include/asm/pgtable.h b/arch/tile/include/asm/pgtable.h
index 95a4f19d16c5..2b05ccbebed9 100644
--- a/arch/tile/include/asm/pgtable.h
+++ b/arch/tile/include/asm/pgtable.h
@@ -414,10 +414,10 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
}
-#define __HAVE_ARCH_PMDP_GET_AND_CLEAR
-static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
- unsigned long address,
- pmd_t *pmdp)
+#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
+static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
+ unsigned long address,
+ pmd_t *pmdp)
{
return pte_pmd(ptep_get_and_clear(mm, address, pmdp_ptep(pmdp)));
}
diff --git a/arch/tile/include/asm/topology.h b/arch/tile/include/asm/topology.h
index 938311844233..76b0d0ebb244 100644
--- a/arch/tile/include/asm/topology.h
+++ b/arch/tile/include/asm/topology.h
@@ -55,7 +55,7 @@ static inline const struct cpumask *cpumask_of_node(int node)
#define topology_physical_package_id(cpu) ((void)(cpu), 0)
#define topology_core_id(cpu) (cpu)
#define topology_core_cpumask(cpu) ((void)(cpu), cpu_online_mask)
-#define topology_thread_cpumask(cpu) cpumask_of(cpu)
+#define topology_sibling_cpumask(cpu) cpumask_of(cpu)
#endif
#endif /* _ASM_TILE_TOPOLOGY_H */
diff --git a/arch/tile/include/asm/uaccess.h b/arch/tile/include/asm/uaccess.h
index f41cb53cf645..a33276bf5ca1 100644
--- a/arch/tile/include/asm/uaccess.h
+++ b/arch/tile/include/asm/uaccess.h
@@ -78,7 +78,8 @@ int __range_ok(unsigned long addr, unsigned long size);
* @addr: User space pointer to start of block to check
* @size: Size of block to check
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Checks if a pointer to a block of memory in user space is valid.
*
@@ -192,7 +193,8 @@ extern int __get_user_bad(void)
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
@@ -274,7 +276,8 @@ extern int __put_user_bad(void)
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
@@ -330,7 +333,8 @@ extern int __put_user_bad(void)
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from kernel space to user space. Caller must check
* the specified block with access_ok() before calling this function.
@@ -366,7 +370,8 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from user space to kernel space. Caller must check
* the specified block with access_ok() before calling this function.
@@ -437,7 +442,8 @@ static inline unsigned long __must_check copy_from_user(void *to,
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from user space to user space. Caller must check
* the specified blocks with access_ok() before calling this function.
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c
index e83cc999da02..3f4f58d34a92 100644
--- a/arch/tile/mm/fault.c
+++ b/arch/tile/mm/fault.c
@@ -354,9 +354,9 @@ static int handle_page_fault(struct pt_regs *regs,
/*
* If we're in an interrupt, have no user context or are running in an
- * atomic region then we must not take the fault.
+ * region with pagefaults disabled then we must not take the fault.
*/
- if (in_atomic() || !mm) {
+ if (pagefault_disabled() || !mm) {
vma = NULL; /* happy compiler */
goto bad_area_nosemaphore;
}
diff --git a/arch/tile/mm/highmem.c b/arch/tile/mm/highmem.c
index 6aa2f2625447..fcd545014e79 100644
--- a/arch/tile/mm/highmem.c
+++ b/arch/tile/mm/highmem.c
@@ -201,7 +201,7 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot)
int idx, type;
pte_t *pte;
- /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+ preempt_disable();
pagefault_disable();
/* Avoid icache flushes by disallowing atomic executable mappings. */
@@ -259,6 +259,7 @@ void __kunmap_atomic(void *kvaddr)
}
pagefault_enable();
+ preempt_enable();
}
EXPORT_SYMBOL(__kunmap_atomic);
diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c
index 8416240c322c..c034dc3fe2d4 100644
--- a/arch/tile/mm/hugetlbpage.c
+++ b/arch/tile/mm/hugetlbpage.c
@@ -160,11 +160,6 @@ int pud_huge(pud_t pud)
return !!(pud_val(pud) & _PAGE_HUGE_PAGE);
}
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
- return 0;
-}
-
#ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file,
unsigned long addr, unsigned long len,
diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild
index 9176fa11d49b..b7df3ae9be51 100644
--- a/arch/um/include/asm/Kbuild
+++ b/arch/um/include/asm/Kbuild
@@ -21,7 +21,6 @@ generic-y += param.h
generic-y += pci.h
generic-y += percpu.h
generic-y += preempt.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += switch_to.h
generic-y += topology.h
diff --git a/arch/um/include/asm/mm-arch-hooks.h b/arch/um/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..a7c8b0dfdd4e
--- /dev/null
+++ b/arch/um/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_UM_MM_ARCH_HOOKS_H
+#define _ASM_UM_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_UM_MM_ARCH_HOOKS_H */
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index 8e4daf44e980..47ff9b7f3e5d 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -7,6 +7,7 @@
#include <linux/sched.h>
#include <linux/hardirq.h>
#include <linux/module.h>
+#include <linux/uaccess.h>
#include <asm/current.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
@@ -35,10 +36,10 @@ int handle_page_fault(unsigned long address, unsigned long ip,
*code_out = SEGV_MAPERR;
/*
- * If the fault was during atomic operation, don't take the fault, just
+ * If the fault was with pagefaults disabled, don't take the fault, just
* fail.
*/
- if (in_atomic())
+ if (faulthandler_disabled())
goto out_nosemaphore;
if (is_user)
diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
index b39b6696ac58..6d4918246ffe 100644
--- a/arch/um/os-Linux/drivers/ethertap_user.c
+++ b/arch/um/os-Linux/drivers/ethertap_user.c
@@ -105,7 +105,7 @@ static int etap_tramp(char *dev, char *gate, int control_me,
sprintf(data_fd_buf, "%d", data_remote);
sprintf(version_buf, "%d", UML_NET_VERSION);
if (gate != NULL) {
- strcpy(gate_buf, gate);
+ strncpy(gate_buf, gate, 15);
args = setup_args;
}
else args = nosetup_args;
diff --git a/arch/unicore32/include/asm/Kbuild b/arch/unicore32/include/asm/Kbuild
index 3e0c19d0f4c5..d12b377b5a8b 100644
--- a/arch/unicore32/include/asm/Kbuild
+++ b/arch/unicore32/include/asm/Kbuild
@@ -36,7 +36,6 @@ generic-y += poll.h
generic-y += posix_types.h
generic-y += preempt.h
generic-y += resource.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += segment.h
generic-y += sembuf.h
diff --git a/arch/unicore32/include/asm/mm-arch-hooks.h b/arch/unicore32/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..4d79a850c509
--- /dev/null
+++ b/arch/unicore32/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_UNICORE32_MM_ARCH_HOOKS_H
+#define _ASM_UNICORE32_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_UNICORE32_MM_ARCH_HOOKS_H */
diff --git a/arch/unicore32/include/asm/pci.h b/arch/unicore32/include/asm/pci.h
index 654407e98619..38b3f3785c3c 100644
--- a/arch/unicore32/include/asm/pci.h
+++ b/arch/unicore32/include/asm/pci.h
@@ -18,16 +18,6 @@
#include <asm-generic/pci.h>
#include <mach/hardware.h> /* for PCIBIOS_MIN_* */
-#ifdef CONFIG_PCI
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- *strat = PCI_DMA_BURST_INFINITY;
- *strategy_parameter = ~0UL;
-}
-#endif
-
#define HAVE_PCI_MMAP
extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
diff --git a/arch/unicore32/mm/fault.c b/arch/unicore32/mm/fault.c
index 0dc922dba915..afccef5529cc 100644
--- a/arch/unicore32/mm/fault.c
+++ b/arch/unicore32/mm/fault.c
@@ -218,7 +218,7 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm)
+ if (faulthandler_disabled() || !mm)
goto no_context;
if (user_mode(regs))
diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild
index 3942f74c92d7..1538562cc720 100644
--- a/arch/x86/Kbuild
+++ b/arch/x86/Kbuild
@@ -1,3 +1,6 @@
+
+obj-y += entry/
+
obj-$(CONFIG_KVM) += kvm/
# Xen paravirtualization support
@@ -11,7 +14,7 @@ obj-y += kernel/
obj-y += mm/
obj-y += crypto/
-obj-y += vdso/
+
obj-$(CONFIG_IA32_EMULATION) += ia32/
obj-y += platform/
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 226d5696e1d1..4fcf0ade7e91 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -9,140 +9,143 @@ config 64BIT
config X86_32
def_bool y
depends on !64BIT
- select CLKSRC_I8253
- select HAVE_UID16
config X86_64
def_bool y
depends on 64BIT
- select X86_DEV_DMA_OPS
- select ARCH_USE_CMPXCHG_LOCKREF
- select HAVE_LIVEPATCH
### Arch settings
config X86
def_bool y
- select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
- select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI
+ select ACPI_LEGACY_TABLES_LOOKUP if ACPI
+ select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
+ select ANON_INODES
+ select ARCH_CLOCKSOURCE_DATA
+ select ARCH_DISCARD_MEMBLOCK
+ select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
+ select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_FAST_MULTIPLIER
select ARCH_HAS_GCOV_PROFILE_ALL
+ select ARCH_HAS_SG_CHAIN
+ select ARCH_HAVE_NMI_SAFE_CMPXCHG
+ select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI
select ARCH_MIGHT_HAVE_PC_PARPORT
select ARCH_MIGHT_HAVE_PC_SERIO
- select HAVE_AOUT if X86_32
- select HAVE_UNSTABLE_SCHED_CLOCK
- select ARCH_SUPPORTS_NUMA_BALANCING if X86_64
- select ARCH_SUPPORTS_INT128 if X86_64
- select HAVE_IDE
- select HAVE_OPROFILE
- select HAVE_PCSPKR_PLATFORM
- select HAVE_PERF_EVENTS
- select HAVE_IOREMAP_PROT
- select HAVE_KPROBES
- select HAVE_MEMBLOCK
- select HAVE_MEMBLOCK_NODE_MAP
- select ARCH_DISCARD_MEMBLOCK
- select ARCH_WANT_OPTIONAL_GPIOLIB
+ select ARCH_SUPPORTS_ATOMIC_RMW
+ select ARCH_SUPPORTS_INT128 if X86_64
+ select ARCH_SUPPORTS_NUMA_BALANCING if X86_64
+ select ARCH_USE_BUILTIN_BSWAP
+ select ARCH_USE_CMPXCHG_LOCKREF if X86_64
+ select ARCH_USE_QUEUED_RWLOCKS
+ select ARCH_USE_QUEUED_SPINLOCKS
select ARCH_WANT_FRAME_POINTERS
- select HAVE_DMA_ATTRS
- select HAVE_DMA_CONTIGUOUS
- select HAVE_KRETPROBES
+ select ARCH_WANT_IPC_PARSE_VERSION if X86_32
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select BUILDTIME_EXTABLE_SORT
+ select CLKEVT_I8253
+ select CLKSRC_I8253 if X86_32
+ select CLOCKSOURCE_VALIDATE_LAST_CYCLE
+ select CLOCKSOURCE_WATCHDOG
+ select CLONE_BACKWARDS if X86_32
+ select COMPAT_OLD_SIGACTION if IA32_EMULATION
+ select DCACHE_WORD_ACCESS
+ select EDAC_ATOMIC_SCRUB
+ select EDAC_SUPPORT
+ select GENERIC_CLOCKEVENTS
+ select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC)
+ select GENERIC_CLOCKEVENTS_MIN_ADJUST
+ select GENERIC_CMOS_UPDATE
+ select GENERIC_CPU_AUTOPROBE
select GENERIC_EARLY_IOREMAP
- select HAVE_OPTPROBES
- select HAVE_KPROBES_ON_FTRACE
- select HAVE_FTRACE_MCOUNT_RECORD
- select HAVE_FENTRY if X86_64
+ select GENERIC_FIND_FIRST_BIT
+ select GENERIC_IOMAP
+ select GENERIC_IRQ_PROBE
+ select GENERIC_IRQ_SHOW
+ select GENERIC_PENDING_IRQ if SMP
+ select GENERIC_SMP_IDLE_THREAD
+ select GENERIC_STRNCPY_FROM_USER
+ select GENERIC_STRNLEN_USER
+ select GENERIC_TIME_VSYSCALL
+ select HAVE_ACPI_APEI if ACPI
+ select HAVE_ACPI_APEI_NMI if ACPI
+ select HAVE_ALIGNED_STRUCT_PAGE if SLUB
+ select HAVE_AOUT if X86_32
+ select HAVE_ARCH_AUDITSYSCALL
+ select HAVE_ARCH_HUGE_VMAP if X86_64 || X86_PAE
+ select HAVE_ARCH_JUMP_LABEL
+ select HAVE_ARCH_KASAN if X86_64 && SPARSEMEM_VMEMMAP
+ select HAVE_ARCH_KGDB
+ select HAVE_ARCH_KMEMCHECK
+ select HAVE_ARCH_SECCOMP_FILTER
+ select HAVE_ARCH_SOFT_DIRTY if X86_64
+ select HAVE_ARCH_TRACEHOOK
+ select HAVE_ARCH_TRANSPARENT_HUGEPAGE
+ select HAVE_BPF_JIT if X86_64
+ select HAVE_CC_STACKPROTECTOR
+ select HAVE_CMPXCHG_DOUBLE
+ select HAVE_CMPXCHG_LOCAL
+ select HAVE_CONTEXT_TRACKING if X86_64
select HAVE_C_RECORDMCOUNT
+ select HAVE_DEBUG_KMEMLEAK
+ select HAVE_DEBUG_STACKOVERFLOW
+ select HAVE_DMA_API_DEBUG
+ select HAVE_DMA_ATTRS
+ select HAVE_DMA_CONTIGUOUS
select HAVE_DYNAMIC_FTRACE
select HAVE_DYNAMIC_FTRACE_WITH_REGS
- select HAVE_FUNCTION_TRACER
- select HAVE_FUNCTION_GRAPH_TRACER
- select HAVE_FUNCTION_GRAPH_FP_TEST
- select HAVE_SYSCALL_TRACEPOINTS
- select SYSCTL_EXCEPTION_TRACE
- select HAVE_KVM
- select HAVE_ARCH_KGDB
- select HAVE_ARCH_TRACEHOOK
- select HAVE_GENERIC_DMA_COHERENT if X86_32
select HAVE_EFFICIENT_UNALIGNED_ACCESS
- select USER_STACKTRACE_SUPPORT
- select HAVE_REGS_AND_STACK_ACCESS_API
- select HAVE_DMA_API_DEBUG
- select HAVE_KERNEL_GZIP
+ select HAVE_FENTRY if X86_64
+ select HAVE_FTRACE_MCOUNT_RECORD
+ select HAVE_FUNCTION_GRAPH_FP_TEST
+ select HAVE_FUNCTION_GRAPH_TRACER
+ select HAVE_FUNCTION_TRACER
+ select HAVE_GENERIC_DMA_COHERENT if X86_32
+ select HAVE_HW_BREAKPOINT
+ select HAVE_IDE
+ select HAVE_IOREMAP_PROT
+ select HAVE_IRQ_EXIT_ON_IRQ_STACK if X86_64
+ select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_KERNEL_BZIP2
+ select HAVE_KERNEL_GZIP
+ select HAVE_KERNEL_LZ4
select HAVE_KERNEL_LZMA
- select HAVE_KERNEL_XZ
select HAVE_KERNEL_LZO
- select HAVE_KERNEL_LZ4
- select HAVE_HW_BREAKPOINT
+ select HAVE_KERNEL_XZ
+ select HAVE_KPROBES
+ select HAVE_KPROBES_ON_FTRACE
+ select HAVE_KRETPROBES
+ select HAVE_KVM
+ select HAVE_LIVEPATCH if X86_64
+ select HAVE_MEMBLOCK
+ select HAVE_MEMBLOCK_NODE_MAP
select HAVE_MIXED_BREAKPOINTS_REGS
- select PERF_EVENTS
+ select HAVE_OPROFILE
+ select HAVE_OPTPROBES
+ select HAVE_PCSPKR_PLATFORM
+ select HAVE_PERF_EVENTS
select HAVE_PERF_EVENTS_NMI
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP
- select HAVE_DEBUG_KMEMLEAK
- select ANON_INODES
- select HAVE_ALIGNED_STRUCT_PAGE if SLUB
- select HAVE_CMPXCHG_LOCAL
- select HAVE_CMPXCHG_DOUBLE
- select HAVE_ARCH_KMEMCHECK
- select HAVE_ARCH_KASAN if X86_64 && SPARSEMEM_VMEMMAP
+ select HAVE_REGS_AND_STACK_ACCESS_API
+ select HAVE_SYSCALL_TRACEPOINTS
+ select HAVE_UID16 if X86_32
+ select HAVE_UNSTABLE_SCHED_CLOCK
select HAVE_USER_RETURN_NOTIFIER
- select ARCH_HAS_ELF_RANDOMIZE
- select HAVE_ARCH_JUMP_LABEL
- select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
- select SPARSE_IRQ
- select GENERIC_FIND_FIRST_BIT
- select GENERIC_IRQ_PROBE
- select GENERIC_PENDING_IRQ if SMP
- select GENERIC_IRQ_SHOW
- select GENERIC_CLOCKEVENTS_MIN_ADJUST
select IRQ_FORCED_THREADING
- select HAVE_BPF_JIT if X86_64
- select HAVE_ARCH_TRANSPARENT_HUGEPAGE
- select HAVE_ARCH_HUGE_VMAP if X86_64 || (X86_32 && X86_PAE)
- select ARCH_HAS_SG_CHAIN
- select CLKEVT_I8253
- select ARCH_HAVE_NMI_SAFE_CMPXCHG
- select GENERIC_IOMAP
- select DCACHE_WORD_ACCESS
- select GENERIC_SMP_IDLE_THREAD
- select ARCH_WANT_IPC_PARSE_VERSION if X86_32
- select HAVE_ARCH_SECCOMP_FILTER
- select BUILDTIME_EXTABLE_SORT
- select GENERIC_CMOS_UPDATE
- select HAVE_ARCH_SOFT_DIRTY if X86_64
- select CLOCKSOURCE_WATCHDOG
- select GENERIC_CLOCKEVENTS
- select ARCH_CLOCKSOURCE_DATA
- select CLOCKSOURCE_VALIDATE_LAST_CYCLE
- select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC)
- select GENERIC_TIME_VSYSCALL
- select GENERIC_STRNCPY_FROM_USER
- select GENERIC_STRNLEN_USER
- select HAVE_CONTEXT_TRACKING if X86_64
- select HAVE_IRQ_TIME_ACCOUNTING
- select VIRT_TO_BUS
- select MODULES_USE_ELF_REL if X86_32
- select MODULES_USE_ELF_RELA if X86_64
- select CLONE_BACKWARDS if X86_32
- select ARCH_USE_BUILTIN_BSWAP
- select ARCH_USE_QUEUE_RWLOCK
- select OLD_SIGSUSPEND3 if X86_32 || IA32_EMULATION
- select OLD_SIGACTION if X86_32
- select COMPAT_OLD_SIGACTION if IA32_EMULATION
+ select MODULES_USE_ELF_RELA if X86_64
+ select MODULES_USE_ELF_REL if X86_32
+ select OLD_SIGACTION if X86_32
+ select OLD_SIGSUSPEND3 if X86_32 || IA32_EMULATION
+ select PERF_EVENTS
select RTC_LIB
- select HAVE_DEBUG_STACKOVERFLOW
- select HAVE_IRQ_EXIT_ON_IRQ_STACK if X86_64
- select HAVE_CC_STACKPROTECTOR
- select GENERIC_CPU_AUTOPROBE
- select HAVE_ARCH_AUDITSYSCALL
- select ARCH_SUPPORTS_ATOMIC_RMW
- select HAVE_ACPI_APEI if ACPI
- select HAVE_ACPI_APEI_NMI if ACPI
- select ACPI_LEGACY_TABLES_LOOKUP if ACPI
- select X86_FEATURE_NAMES if PROC_FS
+ select SPARSE_IRQ
select SRCU
+ select SYSCTL_EXCEPTION_TRACE
+ select USER_STACKTRACE_SUPPORT
+ select VIRT_TO_BUS
+ select X86_DEV_DMA_OPS if X86_64
+ select X86_FEATURE_NAMES if PROC_FS
config INSTRUCTION_DECODER
def_bool y
@@ -260,10 +263,6 @@ config X86_64_SMP
def_bool y
depends on X86_64 && SMP
-config X86_HT
- def_bool y
- depends on SMP
-
config X86_32_LAZY_GS
def_bool y
depends on X86_32 && !CC_STACKPROTECTOR
@@ -341,7 +340,7 @@ config X86_FEATURE_NAMES
config X86_X2APIC
bool "Support x2apic"
- depends on X86_LOCAL_APIC && X86_64 && IRQ_REMAP
+ depends on X86_LOCAL_APIC && X86_64 && (IRQ_REMAP || HYPERVISOR_GUEST)
---help---
This enables x2apic support on CPUs that have this feature.
@@ -441,6 +440,7 @@ config X86_UV
depends on X86_EXTENDED_PLATFORM
depends on NUMA
depends on X86_X2APIC
+ depends on PCI
---help---
This option is needed in order to support SGI Ultraviolet systems.
If you don't have one of these, you should say N here.
@@ -466,7 +466,6 @@ config X86_INTEL_CE
select X86_REBOOTFIXUPS
select OF
select OF_EARLY_FLATTREE
- select IRQ_DOMAIN
---help---
Select for the Intel CE media processor (CE4100) SOC.
This option compiles in support for the CE4100 SOC for settop
@@ -666,7 +665,7 @@ config PARAVIRT_DEBUG
config PARAVIRT_SPINLOCKS
bool "Paravirtualization layer for spinlocks"
depends on PARAVIRT && SMP
- select UNINLINE_SPIN_UNLOCK
+ select UNINLINE_SPIN_UNLOCK if !QUEUED_SPINLOCKS
---help---
Paravirtualized spinlocks allow a pvops backend to replace the
spinlock implementation with something virtualization-friendly
@@ -851,11 +850,12 @@ config NR_CPUS
default "1" if !SMP
default "8192" if MAXSMP
default "32" if SMP && X86_BIGSMP
- default "8" if SMP
+ default "8" if SMP && X86_32
+ default "64" if SMP
---help---
This allows you to specify the maximum number of CPUs which this
kernel will support. If CPUMASK_OFFSTACK is enabled, the maximum
- supported value is 4096, otherwise the maximum value is 512. The
+ supported value is 8192, otherwise the maximum value is 512. The
minimum value which makes sense is 2.
This is purely to save memory - each supported CPU adds
@@ -863,7 +863,7 @@ config NR_CPUS
config SCHED_SMT
bool "SMT (Hyperthreading) scheduler support"
- depends on X86_HT
+ depends on SMP
---help---
SMT scheduler support improves the CPU scheduler's decision making
when dealing with Intel Pentium 4 chips with HyperThreading at a
@@ -873,7 +873,7 @@ config SCHED_SMT
config SCHED_MC
def_bool y
prompt "Multi-core scheduler support"
- depends on X86_HT
+ depends on SMP
---help---
Multi-core scheduler support improves the CPU scheduler's decision
making when dealing with multi-core CPU chips at a cost of slightly
@@ -914,12 +914,12 @@ config X86_UP_IOAPIC
config X86_LOCAL_APIC
def_bool y
depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
- select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ
+ select IRQ_DOMAIN_HIERARCHY
+ select PCI_MSI_IRQ_DOMAIN if PCI_MSI
config X86_IO_APIC
def_bool y
depends on X86_LOCAL_APIC || X86_UP_IOAPIC
- select IRQ_DOMAIN
config X86_REROUTE_FOR_BROKEN_BOOT_IRQS
bool "Reroute for broken boot IRQs"
@@ -1055,24 +1055,19 @@ config TOSHIBA
Say N otherwise.
config I8K
- tristate "Dell laptop support"
+ tristate "Dell i8k legacy laptop support"
select HWMON
+ select SENSORS_DELL_SMM
---help---
- This adds a driver to safely access the System Management Mode
- of the CPU on the Dell Inspiron 8000. The System Management Mode
- is used to read cpu temperature and cooling fan status and to
- control the fans on the I8K portables.
-
- This driver has been tested only on the Inspiron 8000 but it may
- also work with other Dell laptops. You can force loading on other
- models by passing the parameter `force=1' to the module. Use at
- your own risk.
-
- For information on utilities to make use of this driver see the
- I8K Linux utilities web site at:
- <http://people.debian.org/~dz/i8k/>
+ This option enables legacy /proc/i8k userspace interface in hwmon
+ dell-smm-hwmon driver. Character file /proc/i8k reports bios version,
+ temperature and allows controlling fan speeds of Dell laptops via
+ System Management Mode. For old Dell laptops (like Dell Inspiron 8000)
+ it reports also power and hotkey status. For fan speed control is
+ needed userspace package i8kutils.
- Say Y if you intend to run this kernel on a Dell Inspiron 8000.
+ Say Y if you intend to run this kernel on old Dell laptops or want to
+ use userspace package i8kutils.
Say N otherwise.
config X86_REBOOTFIXUPS
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 72484a645f05..a15893d17c55 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -332,4 +332,27 @@ config X86_DEBUG_STATIC_CPU_HAS
If unsure, say N.
+config X86_DEBUG_FPU
+ bool "Debug the x86 FPU code"
+ depends on DEBUG_KERNEL
+ default y
+ ---help---
+ If this option is enabled then there will be extra sanity
+ checks and (boot time) debug printouts added to the kernel.
+ This debugging adds some small amount of runtime overhead
+ to the kernel.
+
+ If unsure, say N.
+
+config PUNIT_ATOM_DEBUG
+ tristate "ATOM Punit debug driver"
+ select DEBUG_FS
+ select IOSF_MBI
+ ---help---
+ This is a debug driver, which gets the power states
+ of all Punit North Complex devices. The power states of
+ each device is exposed as part of the debugfs interface.
+ The current power state can be read from
+ /sys/kernel/debug/punit_atom/dev_power_state
+
endmenu
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 2fda005bb334..118e6debc483 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -77,6 +77,12 @@ else
KBUILD_AFLAGS += -m64
KBUILD_CFLAGS += -m64
+ # Align jump targets to 1 byte, not the default 16 bytes:
+ KBUILD_CFLAGS += -falign-jumps=1
+
+ # Pack loops tightly as well:
+ KBUILD_CFLAGS += -falign-loops=1
+
# Don't autogenerate traditional x87 instructions
KBUILD_CFLAGS += $(call cc-option,-mno-80387)
KBUILD_CFLAGS += $(call cc-option,-mno-fp-ret-in-387)
@@ -84,6 +90,9 @@ else
# Use -mpreferred-stack-boundary=3 if supported.
KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=3)
+ # Use -mskip-rax-setup if supported.
+ KBUILD_CFLAGS += $(call cc-option,-mskip-rax-setup)
+
# FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu)
cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8)
cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona)
@@ -140,12 +149,6 @@ endif
sp-$(CONFIG_X86_32) := esp
sp-$(CONFIG_X86_64) := rsp
-# do binutils support CFI?
-cfi := $(call as-instr,.cfi_startproc\n.cfi_rel_offset $(sp-y)$(comma)0\n.cfi_endproc,-DCONFIG_AS_CFI=1)
-# is .cfi_signal_frame supported too?
-cfi-sigframe := $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1)
-cfi-sections := $(call as-instr,.cfi_sections .debug_frame,-DCONFIG_AS_CFI_SECTIONS=1)
-
# does binutils support specific instructions?
asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=1)
asinstr += $(call as-instr,pshufb %xmm0$(comma)%xmm0,-DCONFIG_AS_SSSE3=1)
@@ -153,8 +156,8 @@ asinstr += $(call as-instr,crc32l %eax$(comma)%eax,-DCONFIG_AS_CRC32=1)
avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1)
avx2_instr :=$(call as-instr,vpbroadcastb %xmm0$(comma)%ymm1,-DCONFIG_AS_AVX2=1)
-KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr)
-KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr)
+KBUILD_AFLAGS += $(asinstr) $(avx_instr) $(avx2_instr)
+KBUILD_CFLAGS += $(asinstr) $(avx_instr) $(avx2_instr)
LDFLAGS := -m elf_$(UTS_MACHINE)
@@ -178,7 +181,7 @@ archscripts: scripts_basic
# Syscall table generation
archheaders:
- $(Q)$(MAKE) $(build)=arch/x86/syscalls all
+ $(Q)$(MAKE) $(build)=arch/x86/entry/syscalls all
archprepare:
ifeq ($(CONFIG_KEXEC_FILE),y)
@@ -241,7 +244,7 @@ install:
PHONY += vdso_install
vdso_install:
- $(Q)$(MAKE) $(build)=arch/x86/vdso $@
+ $(Q)$(MAKE) $(build)=arch/x86/entry/vdso $@
archclean:
$(Q)rm -rf $(objtree)/arch/i386
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index 112cefacf2af..2bfc8a7c88c1 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -32,7 +32,7 @@
#include <crypto/lrw.h>
#include <crypto/xts.h>
#include <asm/cpu_device_id.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
#include <asm/crypto/aes.h>
#include <crypto/ablk_helper.h>
#include <crypto/scatterwalk.h>
@@ -44,15 +44,19 @@
#endif
+#define AESNI_ALIGN 16
+#define AES_BLOCK_MASK (~(AES_BLOCK_SIZE - 1))
+#define RFC4106_HASH_SUBKEY_SIZE 16
+
/* This data is stored at the end of the crypto_tfm struct.
* It's a type of per "session" data storage location.
* This needs to be 16 byte aligned.
*/
struct aesni_rfc4106_gcm_ctx {
- u8 hash_subkey[16];
- struct crypto_aes_ctx aes_key_expanded;
+ u8 hash_subkey[16] __attribute__ ((__aligned__(AESNI_ALIGN)));
+ struct crypto_aes_ctx aes_key_expanded
+ __attribute__ ((__aligned__(AESNI_ALIGN)));
u8 nonce[4];
- struct cryptd_aead *cryptd_tfm;
};
struct aesni_gcm_set_hash_subkey_result {
@@ -66,10 +70,6 @@ struct aesni_hash_subkey_req_data {
struct scatterlist sg;
};
-#define AESNI_ALIGN (16)
-#define AES_BLOCK_MASK (~(AES_BLOCK_SIZE-1))
-#define RFC4106_HASH_SUBKEY_SIZE 16
-
struct aesni_lrw_ctx {
struct lrw_table_ctx lrw_table;
u8 raw_aes_ctx[sizeof(struct crypto_aes_ctx) + AESNI_ALIGN - 1];
@@ -283,10 +283,11 @@ static void (*aesni_gcm_dec_tfm)(void *ctx, u8 *out,
static inline struct
aesni_rfc4106_gcm_ctx *aesni_rfc4106_gcm_ctx_get(struct crypto_aead *tfm)
{
- return
- (struct aesni_rfc4106_gcm_ctx *)
- PTR_ALIGN((u8 *)
- crypto_tfm_ctx(crypto_aead_tfm(tfm)), AESNI_ALIGN);
+ unsigned long align = AESNI_ALIGN;
+
+ if (align <= crypto_tfm_ctx_alignment())
+ align = 1;
+ return PTR_ALIGN(crypto_aead_ctx(tfm), align);
}
#endif
@@ -790,36 +791,30 @@ static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
#endif
#ifdef CONFIG_X86_64
-static int rfc4106_init(struct crypto_tfm *tfm)
+static int rfc4106_init(struct crypto_aead *aead)
{
struct cryptd_aead *cryptd_tfm;
- struct aesni_rfc4106_gcm_ctx *ctx = (struct aesni_rfc4106_gcm_ctx *)
- PTR_ALIGN((u8 *)crypto_tfm_ctx(tfm), AESNI_ALIGN);
- struct crypto_aead *cryptd_child;
- struct aesni_rfc4106_gcm_ctx *child_ctx;
+ struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+
cryptd_tfm = cryptd_alloc_aead("__driver-gcm-aes-aesni",
CRYPTO_ALG_INTERNAL,
CRYPTO_ALG_INTERNAL);
if (IS_ERR(cryptd_tfm))
return PTR_ERR(cryptd_tfm);
- cryptd_child = cryptd_aead_child(cryptd_tfm);
- child_ctx = aesni_rfc4106_gcm_ctx_get(cryptd_child);
- memcpy(child_ctx, ctx, sizeof(*ctx));
- ctx->cryptd_tfm = cryptd_tfm;
- tfm->crt_aead.reqsize = sizeof(struct aead_request)
- + crypto_aead_reqsize(&cryptd_tfm->base);
+ *ctx = cryptd_tfm;
+ crypto_aead_set_reqsize(
+ aead,
+ sizeof(struct aead_request) +
+ crypto_aead_reqsize(&cryptd_tfm->base));
return 0;
}
-static void rfc4106_exit(struct crypto_tfm *tfm)
+static void rfc4106_exit(struct crypto_aead *aead)
{
- struct aesni_rfc4106_gcm_ctx *ctx =
- (struct aesni_rfc4106_gcm_ctx *)
- PTR_ALIGN((u8 *)crypto_tfm_ctx(tfm), AESNI_ALIGN);
- if (!IS_ERR(ctx->cryptd_tfm))
- cryptd_free_aead(ctx->cryptd_tfm);
- return;
+ struct cryptd_aead **ctx = crypto_aead_ctx(aead);
+
+ cryptd_free_aead(*ctx);
}
static void
@@ -845,8 +840,6 @@ rfc4106_set_hash_subkey(u8 *hash_subkey, const u8 *key, unsigned int key_len)
if (IS_ERR(ctr_tfm))
return PTR_ERR(ctr_tfm);
- crypto_ablkcipher_clear_flags(ctr_tfm, ~0);
-
ret = crypto_ablkcipher_setkey(ctr_tfm, key, key_len);
if (ret)
goto out_free_ablkcipher;
@@ -895,73 +888,29 @@ out_free_ablkcipher:
static int common_rfc4106_set_key(struct crypto_aead *aead, const u8 *key,
unsigned int key_len)
{
- int ret = 0;
- struct crypto_tfm *tfm = crypto_aead_tfm(aead);
struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(aead);
- u8 *new_key_align, *new_key_mem = NULL;
if (key_len < 4) {
- crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
return -EINVAL;
}
/*Account for 4 byte nonce at the end.*/
key_len -= 4;
- if (key_len != AES_KEYSIZE_128 && key_len != AES_KEYSIZE_192 &&
- key_len != AES_KEYSIZE_256) {
- crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
- return -EINVAL;
- }
memcpy(ctx->nonce, key + key_len, sizeof(ctx->nonce));
- /*This must be on a 16 byte boundary!*/
- if ((unsigned long)(&(ctx->aes_key_expanded.key_enc[0])) % AESNI_ALIGN)
- return -EINVAL;
-
- if ((unsigned long)key % AESNI_ALIGN) {
- /*key is not aligned: use an auxuliar aligned pointer*/
- new_key_mem = kmalloc(key_len+AESNI_ALIGN, GFP_KERNEL);
- if (!new_key_mem)
- return -ENOMEM;
-
- new_key_align = PTR_ALIGN(new_key_mem, AESNI_ALIGN);
- memcpy(new_key_align, key, key_len);
- key = new_key_align;
- }
- if (!irq_fpu_usable())
- ret = crypto_aes_expand_key(&(ctx->aes_key_expanded),
- key, key_len);
- else {
- kernel_fpu_begin();
- ret = aesni_set_key(&(ctx->aes_key_expanded), key, key_len);
- kernel_fpu_end();
- }
- /*This must be on a 16 byte boundary!*/
- if ((unsigned long)(&(ctx->hash_subkey[0])) % AESNI_ALIGN) {
- ret = -EINVAL;
- goto exit;
- }
- ret = rfc4106_set_hash_subkey(ctx->hash_subkey, key, key_len);
-exit:
- kfree(new_key_mem);
- return ret;
+ return aes_set_key_common(crypto_aead_tfm(aead),
+ &ctx->aes_key_expanded, key, key_len) ?:
+ rfc4106_set_hash_subkey(ctx->hash_subkey, key, key_len);
}
static int rfc4106_set_key(struct crypto_aead *parent, const u8 *key,
unsigned int key_len)
{
- struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(parent);
- struct crypto_aead *child = cryptd_aead_child(ctx->cryptd_tfm);
- struct aesni_rfc4106_gcm_ctx *c_ctx = aesni_rfc4106_gcm_ctx_get(child);
- struct cryptd_aead *cryptd_tfm = ctx->cryptd_tfm;
- int ret;
+ struct cryptd_aead **ctx = crypto_aead_ctx(parent);
+ struct cryptd_aead *cryptd_tfm = *ctx;
- ret = crypto_aead_setkey(child, key, key_len);
- if (!ret) {
- memcpy(ctx, c_ctx, sizeof(*ctx));
- ctx->cryptd_tfm = cryptd_tfm;
- }
- return ret;
+ return crypto_aead_setkey(&cryptd_tfm->base, key, key_len);
}
static int common_rfc4106_set_authsize(struct crypto_aead *aead,
@@ -975,7 +924,7 @@ static int common_rfc4106_set_authsize(struct crypto_aead *aead,
default:
return -EINVAL;
}
- crypto_aead_crt(aead)->authsize = authsize;
+
return 0;
}
@@ -984,30 +933,23 @@ static int common_rfc4106_set_authsize(struct crypto_aead *aead,
static int rfc4106_set_authsize(struct crypto_aead *parent,
unsigned int authsize)
{
- struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(parent);
- struct crypto_aead *child = cryptd_aead_child(ctx->cryptd_tfm);
- int ret;
+ struct cryptd_aead **ctx = crypto_aead_ctx(parent);
+ struct cryptd_aead *cryptd_tfm = *ctx;
- ret = crypto_aead_setauthsize(child, authsize);
- if (!ret)
- crypto_aead_crt(parent)->authsize = authsize;
- return ret;
+ return crypto_aead_setauthsize(&cryptd_tfm->base, authsize);
}
-static int __driver_rfc4106_encrypt(struct aead_request *req)
+static int helper_rfc4106_encrypt(struct aead_request *req)
{
u8 one_entry_in_sg = 0;
u8 *src, *dst, *assoc;
__be32 counter = cpu_to_be32(1);
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(tfm);
- u32 key_len = ctx->aes_key_expanded.key_length;
void *aes_ctx = &(ctx->aes_key_expanded);
unsigned long auth_tag_len = crypto_aead_authsize(tfm);
- u8 iv_tab[16+AESNI_ALIGN];
- u8* iv = (u8 *) PTR_ALIGN((u8 *)iv_tab, AESNI_ALIGN);
+ u8 iv[16] __attribute__ ((__aligned__(AESNI_ALIGN)));
struct scatter_walk src_sg_walk;
- struct scatter_walk assoc_sg_walk;
struct scatter_walk dst_sg_walk;
unsigned int i;
@@ -1016,12 +958,6 @@ static int __driver_rfc4106_encrypt(struct aead_request *req)
/* to 8 or 12 bytes */
if (unlikely(req->assoclen != 8 && req->assoclen != 12))
return -EINVAL;
- if (unlikely(auth_tag_len != 8 && auth_tag_len != 12 && auth_tag_len != 16))
- return -EINVAL;
- if (unlikely(key_len != AES_KEYSIZE_128 &&
- key_len != AES_KEYSIZE_192 &&
- key_len != AES_KEYSIZE_256))
- return -EINVAL;
/* IV below built */
for (i = 0; i < 4; i++)
@@ -1030,55 +966,57 @@ static int __driver_rfc4106_encrypt(struct aead_request *req)
*(iv+4+i) = req->iv[i];
*((__be32 *)(iv+12)) = counter;
- if ((sg_is_last(req->src)) && (sg_is_last(req->assoc))) {
+ if (sg_is_last(req->src) &&
+ req->src->offset + req->src->length <= PAGE_SIZE &&
+ sg_is_last(req->dst) &&
+ req->dst->offset + req->dst->length <= PAGE_SIZE) {
one_entry_in_sg = 1;
scatterwalk_start(&src_sg_walk, req->src);
- scatterwalk_start(&assoc_sg_walk, req->assoc);
- src = scatterwalk_map(&src_sg_walk);
- assoc = scatterwalk_map(&assoc_sg_walk);
+ assoc = scatterwalk_map(&src_sg_walk);
+ src = assoc + req->assoclen;
dst = src;
if (unlikely(req->src != req->dst)) {
scatterwalk_start(&dst_sg_walk, req->dst);
- dst = scatterwalk_map(&dst_sg_walk);
+ dst = scatterwalk_map(&dst_sg_walk) + req->assoclen;
}
-
} else {
/* Allocate memory for src, dst, assoc */
- src = kmalloc(req->cryptlen + auth_tag_len + req->assoclen,
+ assoc = kmalloc(req->cryptlen + auth_tag_len + req->assoclen,
GFP_ATOMIC);
- if (unlikely(!src))
+ if (unlikely(!assoc))
return -ENOMEM;
- assoc = (src + req->cryptlen + auth_tag_len);
- scatterwalk_map_and_copy(src, req->src, 0, req->cryptlen, 0);
- scatterwalk_map_and_copy(assoc, req->assoc, 0,
- req->assoclen, 0);
+ scatterwalk_map_and_copy(assoc, req->src, 0,
+ req->assoclen + req->cryptlen, 0);
+ src = assoc + req->assoclen;
dst = src;
}
+ kernel_fpu_begin();
aesni_gcm_enc_tfm(aes_ctx, dst, src, (unsigned long)req->cryptlen, iv,
ctx->hash_subkey, assoc, (unsigned long)req->assoclen, dst
+ ((unsigned long)req->cryptlen), auth_tag_len);
+ kernel_fpu_end();
/* The authTag (aka the Integrity Check Value) needs to be written
* back to the packet. */
if (one_entry_in_sg) {
if (unlikely(req->src != req->dst)) {
- scatterwalk_unmap(dst);
- scatterwalk_done(&dst_sg_walk, 0, 0);
+ scatterwalk_unmap(dst - req->assoclen);
+ scatterwalk_advance(&dst_sg_walk, req->dst->length);
+ scatterwalk_done(&dst_sg_walk, 1, 0);
}
- scatterwalk_unmap(src);
scatterwalk_unmap(assoc);
- scatterwalk_done(&src_sg_walk, 0, 0);
- scatterwalk_done(&assoc_sg_walk, 0, 0);
+ scatterwalk_advance(&src_sg_walk, req->src->length);
+ scatterwalk_done(&src_sg_walk, req->src == req->dst, 0);
} else {
- scatterwalk_map_and_copy(dst, req->dst, 0,
- req->cryptlen + auth_tag_len, 1);
- kfree(src);
+ scatterwalk_map_and_copy(dst, req->dst, req->assoclen,
+ req->cryptlen + auth_tag_len, 1);
+ kfree(assoc);
}
return 0;
}
-static int __driver_rfc4106_decrypt(struct aead_request *req)
+static int helper_rfc4106_decrypt(struct aead_request *req)
{
u8 one_entry_in_sg = 0;
u8 *src, *dst, *assoc;
@@ -1087,26 +1025,16 @@ static int __driver_rfc4106_decrypt(struct aead_request *req)
int retval = 0;
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(tfm);
- u32 key_len = ctx->aes_key_expanded.key_length;
void *aes_ctx = &(ctx->aes_key_expanded);
unsigned long auth_tag_len = crypto_aead_authsize(tfm);
- u8 iv_and_authTag[32+AESNI_ALIGN];
- u8 *iv = (u8 *) PTR_ALIGN((u8 *)iv_and_authTag, AESNI_ALIGN);
- u8 *authTag = iv + 16;
+ u8 iv[16] __attribute__ ((__aligned__(AESNI_ALIGN)));
+ u8 authTag[16];
struct scatter_walk src_sg_walk;
- struct scatter_walk assoc_sg_walk;
struct scatter_walk dst_sg_walk;
unsigned int i;
- if (unlikely((req->cryptlen < auth_tag_len) ||
- (req->assoclen != 8 && req->assoclen != 12)))
+ if (unlikely(req->assoclen != 8 && req->assoclen != 12))
return -EINVAL;
- if (unlikely(auth_tag_len != 8 && auth_tag_len != 12 && auth_tag_len != 16))
- return -EINVAL;
- if (unlikely(key_len != AES_KEYSIZE_128 &&
- key_len != AES_KEYSIZE_192 &&
- key_len != AES_KEYSIZE_256))
- return -EINVAL;
/* Assuming we are supporting rfc4106 64-bit extended */
/* sequence numbers We need to have the AAD length */
@@ -1120,33 +1048,36 @@ static int __driver_rfc4106_decrypt(struct aead_request *req)
*(iv+4+i) = req->iv[i];
*((__be32 *)(iv+12)) = counter;
- if ((sg_is_last(req->src)) && (sg_is_last(req->assoc))) {
+ if (sg_is_last(req->src) &&
+ req->src->offset + req->src->length <= PAGE_SIZE &&
+ sg_is_last(req->dst) &&
+ req->dst->offset + req->dst->length <= PAGE_SIZE) {
one_entry_in_sg = 1;
scatterwalk_start(&src_sg_walk, req->src);
- scatterwalk_start(&assoc_sg_walk, req->assoc);
- src = scatterwalk_map(&src_sg_walk);
- assoc = scatterwalk_map(&assoc_sg_walk);
+ assoc = scatterwalk_map(&src_sg_walk);
+ src = assoc + req->assoclen;
dst = src;
if (unlikely(req->src != req->dst)) {
scatterwalk_start(&dst_sg_walk, req->dst);
- dst = scatterwalk_map(&dst_sg_walk);
+ dst = scatterwalk_map(&dst_sg_walk) + req->assoclen;
}
} else {
/* Allocate memory for src, dst, assoc */
- src = kmalloc(req->cryptlen + req->assoclen, GFP_ATOMIC);
- if (!src)
+ assoc = kmalloc(req->cryptlen + req->assoclen, GFP_ATOMIC);
+ if (!assoc)
return -ENOMEM;
- assoc = (src + req->cryptlen);
- scatterwalk_map_and_copy(src, req->src, 0, req->cryptlen, 0);
- scatterwalk_map_and_copy(assoc, req->assoc, 0,
- req->assoclen, 0);
+ scatterwalk_map_and_copy(assoc, req->src, 0,
+ req->assoclen + req->cryptlen, 0);
+ src = assoc + req->assoclen;
dst = src;
}
+ kernel_fpu_begin();
aesni_gcm_dec_tfm(aes_ctx, dst, src, tempCipherLen, iv,
ctx->hash_subkey, assoc, (unsigned long)req->assoclen,
authTag, auth_tag_len);
+ kernel_fpu_end();
/* Compare generated tag with passed in tag. */
retval = crypto_memneq(src + tempCipherLen, authTag, auth_tag_len) ?
@@ -1154,90 +1085,59 @@ static int __driver_rfc4106_decrypt(struct aead_request *req)
if (one_entry_in_sg) {
if (unlikely(req->src != req->dst)) {
- scatterwalk_unmap(dst);
- scatterwalk_done(&dst_sg_walk, 0, 0);
+ scatterwalk_unmap(dst - req->assoclen);
+ scatterwalk_advance(&dst_sg_walk, req->dst->length);
+ scatterwalk_done(&dst_sg_walk, 1, 0);
}
- scatterwalk_unmap(src);
scatterwalk_unmap(assoc);
- scatterwalk_done(&src_sg_walk, 0, 0);
- scatterwalk_done(&assoc_sg_walk, 0, 0);
+ scatterwalk_advance(&src_sg_walk, req->src->length);
+ scatterwalk_done(&src_sg_walk, req->src == req->dst, 0);
} else {
- scatterwalk_map_and_copy(dst, req->dst, 0, tempCipherLen, 1);
- kfree(src);
+ scatterwalk_map_and_copy(dst, req->dst, req->assoclen,
+ tempCipherLen, 1);
+ kfree(assoc);
}
return retval;
}
static int rfc4106_encrypt(struct aead_request *req)
{
- int ret;
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
- struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(tfm);
+ struct cryptd_aead **ctx = crypto_aead_ctx(tfm);
+ struct cryptd_aead *cryptd_tfm = *ctx;
+ struct aead_request *subreq = aead_request_ctx(req);
- if (!irq_fpu_usable()) {
- struct aead_request *cryptd_req =
- (struct aead_request *) aead_request_ctx(req);
+ aead_request_set_tfm(subreq, irq_fpu_usable() ?
+ cryptd_aead_child(cryptd_tfm) :
+ &cryptd_tfm->base);
- memcpy(cryptd_req, req, sizeof(*req));
- aead_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
- ret = crypto_aead_encrypt(cryptd_req);
- } else {
- kernel_fpu_begin();
- ret = __driver_rfc4106_encrypt(req);
- kernel_fpu_end();
- }
- return ret;
+ aead_request_set_callback(subreq, req->base.flags,
+ req->base.complete, req->base.data);
+ aead_request_set_crypt(subreq, req->src, req->dst,
+ req->cryptlen, req->iv);
+ aead_request_set_ad(subreq, req->assoclen);
+
+ return crypto_aead_encrypt(subreq);
}
static int rfc4106_decrypt(struct aead_request *req)
{
- int ret;
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
- struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(tfm);
+ struct cryptd_aead **ctx = crypto_aead_ctx(tfm);
+ struct cryptd_aead *cryptd_tfm = *ctx;
+ struct aead_request *subreq = aead_request_ctx(req);
- if (!irq_fpu_usable()) {
- struct aead_request *cryptd_req =
- (struct aead_request *) aead_request_ctx(req);
+ aead_request_set_tfm(subreq, irq_fpu_usable() ?
+ cryptd_aead_child(cryptd_tfm) :
+ &cryptd_tfm->base);
- memcpy(cryptd_req, req, sizeof(*req));
- aead_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
- ret = crypto_aead_decrypt(cryptd_req);
- } else {
- kernel_fpu_begin();
- ret = __driver_rfc4106_decrypt(req);
- kernel_fpu_end();
- }
- return ret;
-}
-
-static int helper_rfc4106_encrypt(struct aead_request *req)
-{
- int ret;
-
- if (unlikely(!irq_fpu_usable())) {
- WARN_ONCE(1, "__gcm-aes-aesni alg used in invalid context");
- ret = -EINVAL;
- } else {
- kernel_fpu_begin();
- ret = __driver_rfc4106_encrypt(req);
- kernel_fpu_end();
- }
- return ret;
-}
-
-static int helper_rfc4106_decrypt(struct aead_request *req)
-{
- int ret;
+ aead_request_set_callback(subreq, req->base.flags,
+ req->base.complete, req->base.data);
+ aead_request_set_crypt(subreq, req->src, req->dst,
+ req->cryptlen, req->iv);
+ aead_request_set_ad(subreq, req->assoclen);
- if (unlikely(!irq_fpu_usable())) {
- WARN_ONCE(1, "__gcm-aes-aesni alg used in invalid context");
- ret = -EINVAL;
- } else {
- kernel_fpu_begin();
- ret = __driver_rfc4106_decrypt(req);
- kernel_fpu_end();
- }
- return ret;
+ return crypto_aead_decrypt(subreq);
}
#endif
@@ -1410,51 +1310,6 @@ static struct crypto_alg aesni_algs[] = { {
.geniv = "chainiv",
},
},
-}, {
- .cra_name = "__gcm-aes-aesni",
- .cra_driver_name = "__driver-gcm-aes-aesni",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_INTERNAL,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct aesni_rfc4106_gcm_ctx) +
- AESNI_ALIGN,
- .cra_alignmask = 0,
- .cra_type = &crypto_aead_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .aead = {
- .setkey = common_rfc4106_set_key,
- .setauthsize = common_rfc4106_set_authsize,
- .encrypt = helper_rfc4106_encrypt,
- .decrypt = helper_rfc4106_decrypt,
- .ivsize = 8,
- .maxauthsize = 16,
- },
- },
-}, {
- .cra_name = "rfc4106(gcm(aes))",
- .cra_driver_name = "rfc4106-gcm-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct aesni_rfc4106_gcm_ctx) +
- AESNI_ALIGN,
- .cra_alignmask = 0,
- .cra_type = &crypto_nivaead_type,
- .cra_module = THIS_MODULE,
- .cra_init = rfc4106_init,
- .cra_exit = rfc4106_exit,
- .cra_u = {
- .aead = {
- .setkey = rfc4106_set_key,
- .setauthsize = rfc4106_set_authsize,
- .encrypt = rfc4106_encrypt,
- .decrypt = rfc4106_decrypt,
- .geniv = "seqiv",
- .ivsize = 8,
- .maxauthsize = 16,
- },
- },
#endif
#if IS_ENABLED(CONFIG_CRYPTO_PCBC)
}, {
@@ -1569,6 +1424,46 @@ static struct crypto_alg aesni_algs[] = { {
},
} };
+#ifdef CONFIG_X86_64
+static struct aead_alg aesni_aead_algs[] = { {
+ .setkey = common_rfc4106_set_key,
+ .setauthsize = common_rfc4106_set_authsize,
+ .encrypt = helper_rfc4106_encrypt,
+ .decrypt = helper_rfc4106_decrypt,
+ .ivsize = 8,
+ .maxauthsize = 16,
+ .base = {
+ .cra_name = "__gcm-aes-aesni",
+ .cra_driver_name = "__driver-gcm-aes-aesni",
+ .cra_flags = CRYPTO_ALG_INTERNAL,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct aesni_rfc4106_gcm_ctx),
+ .cra_alignmask = AESNI_ALIGN - 1,
+ .cra_module = THIS_MODULE,
+ },
+}, {
+ .init = rfc4106_init,
+ .exit = rfc4106_exit,
+ .setkey = rfc4106_set_key,
+ .setauthsize = rfc4106_set_authsize,
+ .encrypt = rfc4106_encrypt,
+ .decrypt = rfc4106_decrypt,
+ .ivsize = 8,
+ .maxauthsize = 16,
+ .base = {
+ .cra_name = "rfc4106(gcm(aes))",
+ .cra_driver_name = "rfc4106-gcm-aesni",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct cryptd_aead *),
+ .cra_module = THIS_MODULE,
+ },
+} };
+#else
+static struct aead_alg aesni_aead_algs[0];
+#endif
+
static const struct x86_cpu_id aesni_cpu_id[] = {
X86_FEATURE_MATCH(X86_FEATURE_AES),
@@ -1616,11 +1511,27 @@ static int __init aesni_init(void)
if (err)
return err;
- return crypto_register_algs(aesni_algs, ARRAY_SIZE(aesni_algs));
+ err = crypto_register_algs(aesni_algs, ARRAY_SIZE(aesni_algs));
+ if (err)
+ goto fpu_exit;
+
+ err = crypto_register_aeads(aesni_aead_algs,
+ ARRAY_SIZE(aesni_aead_algs));
+ if (err)
+ goto unregister_algs;
+
+ return err;
+
+unregister_algs:
+ crypto_unregister_algs(aesni_algs, ARRAY_SIZE(aesni_algs));
+fpu_exit:
+ crypto_fpu_exit();
+ return err;
}
static void __exit aesni_exit(void)
{
+ crypto_unregister_aeads(aesni_aead_algs, ARRAY_SIZE(aesni_aead_algs));
crypto_unregister_algs(aesni_algs, ARRAY_SIZE(aesni_algs));
crypto_fpu_exit();
diff --git a/arch/x86/crypto/camellia_aesni_avx2_glue.c b/arch/x86/crypto/camellia_aesni_avx2_glue.c
index baf0ac21ace5..4c65c70e628b 100644
--- a/arch/x86/crypto/camellia_aesni_avx2_glue.c
+++ b/arch/x86/crypto/camellia_aesni_avx2_glue.c
@@ -19,8 +19,7 @@
#include <crypto/ctr.h>
#include <crypto/lrw.h>
#include <crypto/xts.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
+#include <asm/fpu/api.h>
#include <asm/crypto/camellia.h>
#include <asm/crypto/glue_helper.h>
@@ -561,16 +560,15 @@ static struct crypto_alg cmll_algs[10] = { {
static int __init camellia_aesni_init(void)
{
- u64 xcr0;
+ const char *feature_name;
if (!cpu_has_avx2 || !cpu_has_avx || !cpu_has_aes || !cpu_has_osxsave) {
pr_info("AVX2 or AES-NI instructions are not detected.\n");
return -ENODEV;
}
- xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
- if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
- pr_info("AVX2 detected but unusable.\n");
+ if (!cpu_has_xfeatures(XSTATE_SSE | XSTATE_YMM, &feature_name)) {
+ pr_info("CPU feature '%s' is not supported.\n", feature_name);
return -ENODEV;
}
diff --git a/arch/x86/crypto/camellia_aesni_avx_glue.c b/arch/x86/crypto/camellia_aesni_avx_glue.c
index 78818a1e73e3..80a0e4389c9a 100644
--- a/arch/x86/crypto/camellia_aesni_avx_glue.c
+++ b/arch/x86/crypto/camellia_aesni_avx_glue.c
@@ -19,8 +19,7 @@
#include <crypto/ctr.h>
#include <crypto/lrw.h>
#include <crypto/xts.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
+#include <asm/fpu/api.h>
#include <asm/crypto/camellia.h>
#include <asm/crypto/glue_helper.h>
@@ -553,16 +552,10 @@ static struct crypto_alg cmll_algs[10] = { {
static int __init camellia_aesni_init(void)
{
- u64 xcr0;
+ const char *feature_name;
- if (!cpu_has_avx || !cpu_has_aes || !cpu_has_osxsave) {
- pr_info("AVX or AES-NI instructions are not detected.\n");
- return -ENODEV;
- }
-
- xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
- if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
- pr_info("AVX detected but unusable.\n");
+ if (!cpu_has_xfeatures(XSTATE_SSE | XSTATE_YMM, &feature_name)) {
+ pr_info("CPU feature '%s' is not supported.\n", feature_name);
return -ENODEV;
}
diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c
index 236c80974457..be00aa48b2b5 100644
--- a/arch/x86/crypto/cast5_avx_glue.c
+++ b/arch/x86/crypto/cast5_avx_glue.c
@@ -31,8 +31,7 @@
#include <crypto/cast5.h>
#include <crypto/cryptd.h>
#include <crypto/ctr.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
+#include <asm/fpu/api.h>
#include <asm/crypto/glue_helper.h>
#define CAST5_PARALLEL_BLOCKS 16
@@ -468,16 +467,10 @@ static struct crypto_alg cast5_algs[6] = { {
static int __init cast5_init(void)
{
- u64 xcr0;
+ const char *feature_name;
- if (!cpu_has_avx || !cpu_has_osxsave) {
- pr_info("AVX instructions are not detected.\n");
- return -ENODEV;
- }
-
- xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
- if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
- pr_info("AVX detected but unusable.\n");
+ if (!cpu_has_xfeatures(XSTATE_SSE | XSTATE_YMM, &feature_name)) {
+ pr_info("CPU feature '%s' is not supported.\n", feature_name);
return -ENODEV;
}
diff --git a/arch/x86/crypto/cast6_avx_glue.c b/arch/x86/crypto/cast6_avx_glue.c
index f448810ca4ac..5dbba7224221 100644
--- a/arch/x86/crypto/cast6_avx_glue.c
+++ b/arch/x86/crypto/cast6_avx_glue.c
@@ -36,8 +36,7 @@
#include <crypto/ctr.h>
#include <crypto/lrw.h>
#include <crypto/xts.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
+#include <asm/fpu/api.h>
#include <asm/crypto/glue_helper.h>
#define CAST6_PARALLEL_BLOCKS 8
@@ -590,16 +589,10 @@ static struct crypto_alg cast6_algs[10] = { {
static int __init cast6_init(void)
{
- u64 xcr0;
+ const char *feature_name;
- if (!cpu_has_avx || !cpu_has_osxsave) {
- pr_info("AVX instructions are not detected.\n");
- return -ENODEV;
- }
-
- xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
- if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
- pr_info("AVX detected but unusable.\n");
+ if (!cpu_has_xfeatures(XSTATE_SSE | XSTATE_YMM, &feature_name)) {
+ pr_info("CPU feature '%s' is not supported.\n", feature_name);
return -ENODEV;
}
diff --git a/arch/x86/crypto/crc32-pclmul_glue.c b/arch/x86/crypto/crc32-pclmul_glue.c
index 1937fc1d8763..07d2c6c86a54 100644
--- a/arch/x86/crypto/crc32-pclmul_glue.c
+++ b/arch/x86/crypto/crc32-pclmul_glue.c
@@ -35,7 +35,7 @@
#include <asm/cpufeature.h>
#include <asm/cpu_device_id.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
#define CHKSUM_BLOCK_SIZE 1
#define CHKSUM_DIGEST_SIZE 4
diff --git a/arch/x86/crypto/crc32c-intel_glue.c b/arch/x86/crypto/crc32c-intel_glue.c
index 28640c3d6af7..81a595d75cf5 100644
--- a/arch/x86/crypto/crc32c-intel_glue.c
+++ b/arch/x86/crypto/crc32c-intel_glue.c
@@ -32,8 +32,7 @@
#include <asm/cpufeature.h>
#include <asm/cpu_device_id.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h>
+#include <asm/fpu/internal.h>
#define CHKSUM_BLOCK_SIZE 1
#define CHKSUM_DIGEST_SIZE 4
diff --git a/arch/x86/crypto/crct10dif-pclmul_glue.c b/arch/x86/crypto/crct10dif-pclmul_glue.c
index b6c67bf30fdf..a3fcfc97a311 100644
--- a/arch/x86/crypto/crct10dif-pclmul_glue.c
+++ b/arch/x86/crypto/crct10dif-pclmul_glue.c
@@ -29,7 +29,7 @@
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
#include <asm/cpufeature.h>
#include <asm/cpu_device_id.h>
diff --git a/arch/x86/crypto/fpu.c b/arch/x86/crypto/fpu.c
index f368ba261739..e7d679e2a018 100644
--- a/arch/x86/crypto/fpu.c
+++ b/arch/x86/crypto/fpu.c
@@ -18,7 +18,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/crypto.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
struct crypto_fpu_ctx {
struct crypto_blkcipher *child;
@@ -156,7 +156,7 @@ int __init crypto_fpu_init(void)
return crypto_register_template(&crypto_fpu_tmpl);
}
-void __exit crypto_fpu_exit(void)
+void crypto_fpu_exit(void)
{
crypto_unregister_template(&crypto_fpu_tmpl);
}
diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c
index 2079baf06bdd..64d7cf1b50e1 100644
--- a/arch/x86/crypto/ghash-clmulni-intel_glue.c
+++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c
@@ -19,7 +19,7 @@
#include <crypto/cryptd.h>
#include <crypto/gf128mul.h>
#include <crypto/internal/hash.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
#include <asm/cpu_device_id.h>
#define GHASH_BLOCK_SIZE 16
diff --git a/arch/x86/crypto/serpent_avx2_glue.c b/arch/x86/crypto/serpent_avx2_glue.c
index 2f63dc89e7a9..7d838dc4d888 100644
--- a/arch/x86/crypto/serpent_avx2_glue.c
+++ b/arch/x86/crypto/serpent_avx2_glue.c
@@ -20,8 +20,7 @@
#include <crypto/lrw.h>
#include <crypto/xts.h>
#include <crypto/serpent.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
+#include <asm/fpu/api.h>
#include <asm/crypto/serpent-avx.h>
#include <asm/crypto/glue_helper.h>
@@ -537,16 +536,14 @@ static struct crypto_alg srp_algs[10] = { {
static int __init init(void)
{
- u64 xcr0;
+ const char *feature_name;
if (!cpu_has_avx2 || !cpu_has_osxsave) {
pr_info("AVX2 instructions are not detected.\n");
return -ENODEV;
}
-
- xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
- if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
- pr_info("AVX detected but unusable.\n");
+ if (!cpu_has_xfeatures(XSTATE_SSE | XSTATE_YMM, &feature_name)) {
+ pr_info("CPU feature '%s' is not supported.\n", feature_name);
return -ENODEV;
}
diff --git a/arch/x86/crypto/serpent_avx_glue.c b/arch/x86/crypto/serpent_avx_glue.c
index c8d478af8456..da7dafc9b16d 100644
--- a/arch/x86/crypto/serpent_avx_glue.c
+++ b/arch/x86/crypto/serpent_avx_glue.c
@@ -36,8 +36,7 @@
#include <crypto/ctr.h>
#include <crypto/lrw.h>
#include <crypto/xts.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
+#include <asm/fpu/api.h>
#include <asm/crypto/serpent-avx.h>
#include <asm/crypto/glue_helper.h>
@@ -596,16 +595,10 @@ static struct crypto_alg serpent_algs[10] = { {
static int __init serpent_init(void)
{
- u64 xcr0;
+ const char *feature_name;
- if (!cpu_has_avx || !cpu_has_osxsave) {
- printk(KERN_INFO "AVX instructions are not detected.\n");
- return -ENODEV;
- }
-
- xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
- if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
- printk(KERN_INFO "AVX detected but unusable.\n");
+ if (!cpu_has_xfeatures(XSTATE_SSE | XSTATE_YMM, &feature_name)) {
+ pr_info("CPU feature '%s' is not supported.\n", feature_name);
return -ENODEV;
}
diff --git a/arch/x86/crypto/sha-mb/sha1_mb.c b/arch/x86/crypto/sha-mb/sha1_mb.c
index e510b1c5d690..a841e9765bd6 100644
--- a/arch/x86/crypto/sha-mb/sha1_mb.c
+++ b/arch/x86/crypto/sha-mb/sha1_mb.c
@@ -65,11 +65,8 @@
#include <crypto/mcryptd.h>
#include <crypto/crypto_wq.h>
#include <asm/byteorder.h>
-#include <asm/i387.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
#include <linux/hardirq.h>
-#include <asm/fpu-internal.h>
+#include <asm/fpu/api.h>
#include "sha_mb_ctx.h"
#define FLUSH_INTERVAL 1000 /* in usec */
@@ -885,7 +882,8 @@ static int __init sha1_mb_mod_init(void)
INIT_DELAYED_WORK(&cpu_state->flush, mcryptd_flusher);
cpu_state->cpu = cpu;
cpu_state->alg_state = &sha1_mb_alg_state;
- cpu_state->mgr = (struct sha1_ctx_mgr *) kzalloc(sizeof(struct sha1_ctx_mgr), GFP_KERNEL);
+ cpu_state->mgr = kzalloc(sizeof(struct sha1_ctx_mgr),
+ GFP_KERNEL);
if (!cpu_state->mgr)
goto err2;
sha1_ctx_mgr_init(cpu_state->mgr);
diff --git a/arch/x86/crypto/sha1_ssse3_glue.c b/arch/x86/crypto/sha1_ssse3_glue.c
index 33d1b9dc14cc..7c48e8b20848 100644
--- a/arch/x86/crypto/sha1_ssse3_glue.c
+++ b/arch/x86/crypto/sha1_ssse3_glue.c
@@ -29,9 +29,7 @@
#include <linux/types.h>
#include <crypto/sha.h>
#include <crypto/sha1_base.h>
-#include <asm/i387.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
+#include <asm/fpu/api.h>
asmlinkage void sha1_transform_ssse3(u32 *digest, const char *data,
@@ -123,15 +121,9 @@ static struct shash_alg alg = {
#ifdef CONFIG_AS_AVX
static bool __init avx_usable(void)
{
- u64 xcr0;
-
- if (!cpu_has_avx || !cpu_has_osxsave)
- return false;
-
- xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
- if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
- pr_info("AVX detected but unusable.\n");
-
+ if (!cpu_has_xfeatures(XSTATE_SSE | XSTATE_YMM, NULL)) {
+ if (cpu_has_avx)
+ pr_info("AVX detected but unusable.\n");
return false;
}
diff --git a/arch/x86/crypto/sha256_ssse3_glue.c b/arch/x86/crypto/sha256_ssse3_glue.c
index ccc338881ee8..f8097fc0d1d1 100644
--- a/arch/x86/crypto/sha256_ssse3_glue.c
+++ b/arch/x86/crypto/sha256_ssse3_glue.c
@@ -37,9 +37,7 @@
#include <linux/types.h>
#include <crypto/sha.h>
#include <crypto/sha256_base.h>
-#include <asm/i387.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
+#include <asm/fpu/api.h>
#include <linux/string.h>
asmlinkage void sha256_transform_ssse3(u32 *digest, const char *data,
@@ -132,15 +130,9 @@ static struct shash_alg algs[] = { {
#ifdef CONFIG_AS_AVX
static bool __init avx_usable(void)
{
- u64 xcr0;
-
- if (!cpu_has_avx || !cpu_has_osxsave)
- return false;
-
- xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
- if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
- pr_info("AVX detected but unusable.\n");
-
+ if (!cpu_has_xfeatures(XSTATE_SSE | XSTATE_YMM, NULL)) {
+ if (cpu_has_avx)
+ pr_info("AVX detected but unusable.\n");
return false;
}
diff --git a/arch/x86/crypto/sha512_ssse3_glue.c b/arch/x86/crypto/sha512_ssse3_glue.c
index d9fa4c1e063f..2edad7b81870 100644
--- a/arch/x86/crypto/sha512_ssse3_glue.c
+++ b/arch/x86/crypto/sha512_ssse3_glue.c
@@ -35,9 +35,7 @@
#include <linux/types.h>
#include <crypto/sha.h>
#include <crypto/sha512_base.h>
-#include <asm/i387.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
+#include <asm/fpu/api.h>
#include <linux/string.h>
@@ -131,15 +129,9 @@ static struct shash_alg algs[] = { {
#ifdef CONFIG_AS_AVX
static bool __init avx_usable(void)
{
- u64 xcr0;
-
- if (!cpu_has_avx || !cpu_has_osxsave)
- return false;
-
- xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
- if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
- pr_info("AVX detected but unusable.\n");
-
+ if (!cpu_has_xfeatures(XSTATE_SSE | XSTATE_YMM, NULL)) {
+ if (cpu_has_avx)
+ pr_info("AVX detected but unusable.\n");
return false;
}
diff --git a/arch/x86/crypto/twofish_avx_glue.c b/arch/x86/crypto/twofish_avx_glue.c
index b5e2d5651851..c2bd0ce718ee 100644
--- a/arch/x86/crypto/twofish_avx_glue.c
+++ b/arch/x86/crypto/twofish_avx_glue.c
@@ -36,9 +36,7 @@
#include <crypto/ctr.h>
#include <crypto/lrw.h>
#include <crypto/xts.h>
-#include <asm/i387.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
+#include <asm/fpu/api.h>
#include <asm/crypto/twofish.h>
#include <asm/crypto/glue_helper.h>
#include <crypto/scatterwalk.h>
@@ -558,16 +556,10 @@ static struct crypto_alg twofish_algs[10] = { {
static int __init twofish_init(void)
{
- u64 xcr0;
+ const char *feature_name;
- if (!cpu_has_avx || !cpu_has_osxsave) {
- printk(KERN_INFO "AVX instructions are not detected.\n");
- return -ENODEV;
- }
-
- xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
- if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
- printk(KERN_INFO "AVX detected but unusable.\n");
+ if (!cpu_has_xfeatures(XSTATE_SSE | XSTATE_YMM, &feature_name)) {
+ pr_info("CPU feature '%s' is not supported.\n", feature_name);
return -ENODEV;
}
diff --git a/arch/x86/entry/Makefile b/arch/x86/entry/Makefile
new file mode 100644
index 000000000000..7a144971db79
--- /dev/null
+++ b/arch/x86/entry/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the x86 low level entry code
+#
+obj-y := entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o
+
+obj-y += vdso/
+obj-y += vsyscall/
+
+obj-$(CONFIG_IA32_EMULATION) += entry_64_compat.o syscall_32.o
+
diff --git a/arch/x86/include/asm/calling.h b/arch/x86/entry/calling.h
index 1c8b50edb2db..f4e6308c4200 100644
--- a/arch/x86/include/asm/calling.h
+++ b/arch/x86/entry/calling.h
@@ -46,8 +46,6 @@ For 32-bit we have the following conventions - kernel is built with
*/
-#include <asm/dwarf2.h>
-
#ifdef CONFIG_X86_64
/*
@@ -91,28 +89,27 @@ For 32-bit we have the following conventions - kernel is built with
#define SIZEOF_PTREGS 21*8
.macro ALLOC_PT_GPREGS_ON_STACK addskip=0
- subq $15*8+\addskip, %rsp
- CFI_ADJUST_CFA_OFFSET 15*8+\addskip
+ addq $-(15*8+\addskip), %rsp
.endm
.macro SAVE_C_REGS_HELPER offset=0 rax=1 rcx=1 r8910=1 r11=1
.if \r11
- movq_cfi r11, 6*8+\offset
+ movq %r11, 6*8+\offset(%rsp)
.endif
.if \r8910
- movq_cfi r10, 7*8+\offset
- movq_cfi r9, 8*8+\offset
- movq_cfi r8, 9*8+\offset
+ movq %r10, 7*8+\offset(%rsp)
+ movq %r9, 8*8+\offset(%rsp)
+ movq %r8, 9*8+\offset(%rsp)
.endif
.if \rax
- movq_cfi rax, 10*8+\offset
+ movq %rax, 10*8+\offset(%rsp)
.endif
.if \rcx
- movq_cfi rcx, 11*8+\offset
+ movq %rcx, 11*8+\offset(%rsp)
.endif
- movq_cfi rdx, 12*8+\offset
- movq_cfi rsi, 13*8+\offset
- movq_cfi rdi, 14*8+\offset
+ movq %rdx, 12*8+\offset(%rsp)
+ movq %rsi, 13*8+\offset(%rsp)
+ movq %rdi, 14*8+\offset(%rsp)
.endm
.macro SAVE_C_REGS offset=0
SAVE_C_REGS_HELPER \offset, 1, 1, 1, 1
@@ -131,24 +128,24 @@ For 32-bit we have the following conventions - kernel is built with
.endm
.macro SAVE_EXTRA_REGS offset=0
- movq_cfi r15, 0*8+\offset
- movq_cfi r14, 1*8+\offset
- movq_cfi r13, 2*8+\offset
- movq_cfi r12, 3*8+\offset
- movq_cfi rbp, 4*8+\offset
- movq_cfi rbx, 5*8+\offset
+ movq %r15, 0*8+\offset(%rsp)
+ movq %r14, 1*8+\offset(%rsp)
+ movq %r13, 2*8+\offset(%rsp)
+ movq %r12, 3*8+\offset(%rsp)
+ movq %rbp, 4*8+\offset(%rsp)
+ movq %rbx, 5*8+\offset(%rsp)
.endm
.macro SAVE_EXTRA_REGS_RBP offset=0
- movq_cfi rbp, 4*8+\offset
+ movq %rbp, 4*8+\offset(%rsp)
.endm
.macro RESTORE_EXTRA_REGS offset=0
- movq_cfi_restore 0*8+\offset, r15
- movq_cfi_restore 1*8+\offset, r14
- movq_cfi_restore 2*8+\offset, r13
- movq_cfi_restore 3*8+\offset, r12
- movq_cfi_restore 4*8+\offset, rbp
- movq_cfi_restore 5*8+\offset, rbx
+ movq 0*8+\offset(%rsp), %r15
+ movq 1*8+\offset(%rsp), %r14
+ movq 2*8+\offset(%rsp), %r13
+ movq 3*8+\offset(%rsp), %r12
+ movq 4*8+\offset(%rsp), %rbp
+ movq 5*8+\offset(%rsp), %rbx
.endm
.macro ZERO_EXTRA_REGS
@@ -162,24 +159,24 @@ For 32-bit we have the following conventions - kernel is built with
.macro RESTORE_C_REGS_HELPER rstor_rax=1, rstor_rcx=1, rstor_r11=1, rstor_r8910=1, rstor_rdx=1
.if \rstor_r11
- movq_cfi_restore 6*8, r11
+ movq 6*8(%rsp), %r11
.endif
.if \rstor_r8910
- movq_cfi_restore 7*8, r10
- movq_cfi_restore 8*8, r9
- movq_cfi_restore 9*8, r8
+ movq 7*8(%rsp), %r10
+ movq 8*8(%rsp), %r9
+ movq 9*8(%rsp), %r8
.endif
.if \rstor_rax
- movq_cfi_restore 10*8, rax
+ movq 10*8(%rsp), %rax
.endif
.if \rstor_rcx
- movq_cfi_restore 11*8, rcx
+ movq 11*8(%rsp), %rcx
.endif
.if \rstor_rdx
- movq_cfi_restore 12*8, rdx
+ movq 12*8(%rsp), %rdx
.endif
- movq_cfi_restore 13*8, rsi
- movq_cfi_restore 14*8, rdi
+ movq 13*8(%rsp), %rsi
+ movq 14*8(%rsp), %rdi
.endm
.macro RESTORE_C_REGS
RESTORE_C_REGS_HELPER 1,1,1,1,1
@@ -204,8 +201,7 @@ For 32-bit we have the following conventions - kernel is built with
.endm
.macro REMOVE_PT_GPREGS_FROM_STACK addskip=0
- addq $15*8+\addskip, %rsp
- CFI_ADJUST_CFA_OFFSET -(15*8+\addskip)
+ subq $-(15*8+\addskip), %rsp
.endm
.macro icebp
@@ -224,23 +220,23 @@ For 32-bit we have the following conventions - kernel is built with
*/
.macro SAVE_ALL
- pushl_cfi_reg eax
- pushl_cfi_reg ebp
- pushl_cfi_reg edi
- pushl_cfi_reg esi
- pushl_cfi_reg edx
- pushl_cfi_reg ecx
- pushl_cfi_reg ebx
+ pushl %eax
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
.endm
.macro RESTORE_ALL
- popl_cfi_reg ebx
- popl_cfi_reg ecx
- popl_cfi_reg edx
- popl_cfi_reg esi
- popl_cfi_reg edi
- popl_cfi_reg ebp
- popl_cfi_reg eax
+ popl %ebx
+ popl %ecx
+ popl %edx
+ popl %esi
+ popl %edi
+ popl %ebp
+ popl %eax
.endm
#endif /* CONFIG_X86_64 */
diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S
new file mode 100644
index 000000000000..21dc60a60b5f
--- /dev/null
+++ b/arch/x86/entry/entry_32.S
@@ -0,0 +1,1248 @@
+/*
+ * Copyright (C) 1991,1992 Linus Torvalds
+ *
+ * entry_32.S contains the system-call and low-level fault and trap handling routines.
+ *
+ * Stack layout in 'syscall_exit':
+ * ptrace needs to have all registers on the stack.
+ * If the order here is changed, it needs to be
+ * updated in fork.c:copy_process(), signal.c:do_signal(),
+ * ptrace.c and ptrace.h
+ *
+ * 0(%esp) - %ebx
+ * 4(%esp) - %ecx
+ * 8(%esp) - %edx
+ * C(%esp) - %esi
+ * 10(%esp) - %edi
+ * 14(%esp) - %ebp
+ * 18(%esp) - %eax
+ * 1C(%esp) - %ds
+ * 20(%esp) - %es
+ * 24(%esp) - %fs
+ * 28(%esp) - %gs saved iff !CONFIG_X86_32_LAZY_GS
+ * 2C(%esp) - orig_eax
+ * 30(%esp) - %eip
+ * 34(%esp) - %cs
+ * 38(%esp) - %eflags
+ * 3C(%esp) - %oldesp
+ * 40(%esp) - %oldss
+ */
+
+#include <linux/linkage.h>
+#include <linux/err.h>
+#include <asm/thread_info.h>
+#include <asm/irqflags.h>
+#include <asm/errno.h>
+#include <asm/segment.h>
+#include <asm/smp.h>
+#include <asm/page_types.h>
+#include <asm/percpu.h>
+#include <asm/processor-flags.h>
+#include <asm/ftrace.h>
+#include <asm/irq_vectors.h>
+#include <asm/cpufeature.h>
+#include <asm/alternative-asm.h>
+#include <asm/asm.h>
+#include <asm/smap.h>
+
+/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
+#include <linux/elf-em.h>
+#define AUDIT_ARCH_I386 (EM_386|__AUDIT_ARCH_LE)
+#define __AUDIT_ARCH_LE 0x40000000
+
+#ifndef CONFIG_AUDITSYSCALL
+# define sysenter_audit syscall_trace_entry
+# define sysexit_audit syscall_exit_work
+#endif
+
+ .section .entry.text, "ax"
+
+/*
+ * We use macros for low-level operations which need to be overridden
+ * for paravirtualization. The following will never clobber any registers:
+ * INTERRUPT_RETURN (aka. "iret")
+ * GET_CR0_INTO_EAX (aka. "movl %cr0, %eax")
+ * ENABLE_INTERRUPTS_SYSEXIT (aka "sti; sysexit").
+ *
+ * For DISABLE_INTERRUPTS/ENABLE_INTERRUPTS (aka "cli"/"sti"), you must
+ * specify what registers can be overwritten (CLBR_NONE, CLBR_EAX/EDX/ECX/ANY).
+ * Allowing a register to be clobbered can shrink the paravirt replacement
+ * enough to patch inline, increasing performance.
+ */
+
+#ifdef CONFIG_PREEMPT
+# define preempt_stop(clobbers) DISABLE_INTERRUPTS(clobbers); TRACE_IRQS_OFF
+#else
+# define preempt_stop(clobbers)
+# define resume_kernel restore_all
+#endif
+
+.macro TRACE_IRQS_IRET
+#ifdef CONFIG_TRACE_IRQFLAGS
+ testl $X86_EFLAGS_IF, PT_EFLAGS(%esp) # interrupts off?
+ jz 1f
+ TRACE_IRQS_ON
+1:
+#endif
+.endm
+
+/*
+ * User gs save/restore
+ *
+ * %gs is used for userland TLS and kernel only uses it for stack
+ * canary which is required to be at %gs:20 by gcc. Read the comment
+ * at the top of stackprotector.h for more info.
+ *
+ * Local labels 98 and 99 are used.
+ */
+#ifdef CONFIG_X86_32_LAZY_GS
+
+ /* unfortunately push/pop can't be no-op */
+.macro PUSH_GS
+ pushl $0
+.endm
+.macro POP_GS pop=0
+ addl $(4 + \pop), %esp
+.endm
+.macro POP_GS_EX
+.endm
+
+ /* all the rest are no-op */
+.macro PTGS_TO_GS
+.endm
+.macro PTGS_TO_GS_EX
+.endm
+.macro GS_TO_REG reg
+.endm
+.macro REG_TO_PTGS reg
+.endm
+.macro SET_KERNEL_GS reg
+.endm
+
+#else /* CONFIG_X86_32_LAZY_GS */
+
+.macro PUSH_GS
+ pushl %gs
+.endm
+
+.macro POP_GS pop=0
+98: popl %gs
+ .if \pop <> 0
+ add $\pop, %esp
+ .endif
+.endm
+.macro POP_GS_EX
+.pushsection .fixup, "ax"
+99: movl $0, (%esp)
+ jmp 98b
+.popsection
+ _ASM_EXTABLE(98b, 99b)
+.endm
+
+.macro PTGS_TO_GS
+98: mov PT_GS(%esp), %gs
+.endm
+.macro PTGS_TO_GS_EX
+.pushsection .fixup, "ax"
+99: movl $0, PT_GS(%esp)
+ jmp 98b
+.popsection
+ _ASM_EXTABLE(98b, 99b)
+.endm
+
+.macro GS_TO_REG reg
+ movl %gs, \reg
+.endm
+.macro REG_TO_PTGS reg
+ movl \reg, PT_GS(%esp)
+.endm
+.macro SET_KERNEL_GS reg
+ movl $(__KERNEL_STACK_CANARY), \reg
+ movl \reg, %gs
+.endm
+
+#endif /* CONFIG_X86_32_LAZY_GS */
+
+.macro SAVE_ALL
+ cld
+ PUSH_GS
+ pushl %fs
+ pushl %es
+ pushl %ds
+ pushl %eax
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+ movl $(__USER_DS), %edx
+ movl %edx, %ds
+ movl %edx, %es
+ movl $(__KERNEL_PERCPU), %edx
+ movl %edx, %fs
+ SET_KERNEL_GS %edx
+.endm
+
+.macro RESTORE_INT_REGS
+ popl %ebx
+ popl %ecx
+ popl %edx
+ popl %esi
+ popl %edi
+ popl %ebp
+ popl %eax
+.endm
+
+.macro RESTORE_REGS pop=0
+ RESTORE_INT_REGS
+1: popl %ds
+2: popl %es
+3: popl %fs
+ POP_GS \pop
+.pushsection .fixup, "ax"
+4: movl $0, (%esp)
+ jmp 1b
+5: movl $0, (%esp)
+ jmp 2b
+6: movl $0, (%esp)
+ jmp 3b
+.popsection
+ _ASM_EXTABLE(1b, 4b)
+ _ASM_EXTABLE(2b, 5b)
+ _ASM_EXTABLE(3b, 6b)
+ POP_GS_EX
+.endm
+
+ENTRY(ret_from_fork)
+ pushl %eax
+ call schedule_tail
+ GET_THREAD_INFO(%ebp)
+ popl %eax
+ pushl $0x0202 # Reset kernel eflags
+ popfl
+ jmp syscall_exit
+END(ret_from_fork)
+
+ENTRY(ret_from_kernel_thread)
+ pushl %eax
+ call schedule_tail
+ GET_THREAD_INFO(%ebp)
+ popl %eax
+ pushl $0x0202 # Reset kernel eflags
+ popfl
+ movl PT_EBP(%esp), %eax
+ call *PT_EBX(%esp)
+ movl $0, PT_EAX(%esp)
+ jmp syscall_exit
+ENDPROC(ret_from_kernel_thread)
+
+/*
+ * Return to user mode is not as complex as all this looks,
+ * but we want the default path for a system call return to
+ * go as quickly as possible which is why some of this is
+ * less clear than it otherwise should be.
+ */
+
+ # userspace resumption stub bypassing syscall exit tracing
+ ALIGN
+ret_from_exception:
+ preempt_stop(CLBR_ANY)
+ret_from_intr:
+ GET_THREAD_INFO(%ebp)
+#ifdef CONFIG_VM86
+ movl PT_EFLAGS(%esp), %eax # mix EFLAGS and CS
+ movb PT_CS(%esp), %al
+ andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax
+#else
+ /*
+ * We can be coming here from child spawned by kernel_thread().
+ */
+ movl PT_CS(%esp), %eax
+ andl $SEGMENT_RPL_MASK, %eax
+#endif
+ cmpl $USER_RPL, %eax
+ jb resume_kernel # not returning to v8086 or userspace
+
+ENTRY(resume_userspace)
+ LOCKDEP_SYS_EXIT
+ DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
+ # setting need_resched or sigpending
+ # between sampling and the iret
+ TRACE_IRQS_OFF
+ movl TI_flags(%ebp), %ecx
+ andl $_TIF_WORK_MASK, %ecx # is there any work to be done on
+ # int/exception return?
+ jne work_pending
+ jmp restore_all
+END(ret_from_exception)
+
+#ifdef CONFIG_PREEMPT
+ENTRY(resume_kernel)
+ DISABLE_INTERRUPTS(CLBR_ANY)
+need_resched:
+ cmpl $0, PER_CPU_VAR(__preempt_count)
+ jnz restore_all
+ testl $X86_EFLAGS_IF, PT_EFLAGS(%esp) # interrupts off (exception path) ?
+ jz restore_all
+ call preempt_schedule_irq
+ jmp need_resched
+END(resume_kernel)
+#endif
+
+/*
+ * SYSENTER_RETURN points to after the SYSENTER instruction
+ * in the vsyscall page. See vsyscall-sysentry.S, which defines
+ * the symbol.
+ */
+
+ # SYSENTER call handler stub
+ENTRY(entry_SYSENTER_32)
+ movl TSS_sysenter_sp0(%esp), %esp
+sysenter_past_esp:
+ /*
+ * Interrupts are disabled here, but we can't trace it until
+ * enough kernel state to call TRACE_IRQS_OFF can be called - but
+ * we immediately enable interrupts at that point anyway.
+ */
+ pushl $__USER_DS
+ pushl %ebp
+ pushfl
+ orl $X86_EFLAGS_IF, (%esp)
+ pushl $__USER_CS
+ /*
+ * Push current_thread_info()->sysenter_return to the stack.
+ * A tiny bit of offset fixup is necessary: TI_sysenter_return
+ * is relative to thread_info, which is at the bottom of the
+ * kernel stack page. 4*4 means the 4 words pushed above;
+ * TOP_OF_KERNEL_STACK_PADDING takes us to the top of the stack;
+ * and THREAD_SIZE takes us to the bottom.
+ */
+ pushl ((TI_sysenter_return) - THREAD_SIZE + TOP_OF_KERNEL_STACK_PADDING + 4*4)(%esp)
+
+ pushl %eax
+ SAVE_ALL
+ ENABLE_INTERRUPTS(CLBR_NONE)
+
+/*
+ * Load the potential sixth argument from user stack.
+ * Careful about security.
+ */
+ cmpl $__PAGE_OFFSET-3, %ebp
+ jae syscall_fault
+ ASM_STAC
+1: movl (%ebp), %ebp
+ ASM_CLAC
+ movl %ebp, PT_EBP(%esp)
+ _ASM_EXTABLE(1b, syscall_fault)
+
+ GET_THREAD_INFO(%ebp)
+
+ testl $_TIF_WORK_SYSCALL_ENTRY, TI_flags(%ebp)
+ jnz sysenter_audit
+sysenter_do_call:
+ cmpl $(NR_syscalls), %eax
+ jae sysenter_badsys
+ call *sys_call_table(, %eax, 4)
+sysenter_after_call:
+ movl %eax, PT_EAX(%esp)
+ LOCKDEP_SYS_EXIT
+ DISABLE_INTERRUPTS(CLBR_ANY)
+ TRACE_IRQS_OFF
+ movl TI_flags(%ebp), %ecx
+ testl $_TIF_ALLWORK_MASK, %ecx
+ jnz sysexit_audit
+sysenter_exit:
+/* if something modifies registers it must also disable sysexit */
+ movl PT_EIP(%esp), %edx
+ movl PT_OLDESP(%esp), %ecx
+ xorl %ebp, %ebp
+ TRACE_IRQS_ON
+1: mov PT_FS(%esp), %fs
+ PTGS_TO_GS
+ ENABLE_INTERRUPTS_SYSEXIT
+
+#ifdef CONFIG_AUDITSYSCALL
+sysenter_audit:
+ testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), TI_flags(%ebp)
+ jnz syscall_trace_entry
+ /* movl PT_EAX(%esp), %eax already set, syscall number: 1st arg to audit */
+ movl PT_EBX(%esp), %edx /* ebx/a0: 2nd arg to audit */
+ /* movl PT_ECX(%esp), %ecx already set, a1: 3nd arg to audit */
+ pushl PT_ESI(%esp) /* a3: 5th arg */
+ pushl PT_EDX+4(%esp) /* a2: 4th arg */
+ call __audit_syscall_entry
+ popl %ecx /* get that remapped edx off the stack */
+ popl %ecx /* get that remapped esi off the stack */
+ movl PT_EAX(%esp), %eax /* reload syscall number */
+ jmp sysenter_do_call
+
+sysexit_audit:
+ testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %ecx
+ jnz syscall_exit_work
+ TRACE_IRQS_ON
+ ENABLE_INTERRUPTS(CLBR_ANY)
+ movl %eax, %edx /* second arg, syscall return value */
+ cmpl $-MAX_ERRNO, %eax /* is it an error ? */
+ setbe %al /* 1 if so, 0 if not */
+ movzbl %al, %eax /* zero-extend that */
+ call __audit_syscall_exit
+ DISABLE_INTERRUPTS(CLBR_ANY)
+ TRACE_IRQS_OFF
+ movl TI_flags(%ebp), %ecx
+ testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %ecx
+ jnz syscall_exit_work
+ movl PT_EAX(%esp), %eax /* reload syscall return value */
+ jmp sysenter_exit
+#endif
+
+.pushsection .fixup, "ax"
+2: movl $0, PT_FS(%esp)
+ jmp 1b
+.popsection
+ _ASM_EXTABLE(1b, 2b)
+ PTGS_TO_GS_EX
+ENDPROC(entry_SYSENTER_32)
+
+ # system call handler stub
+ENTRY(entry_INT80_32)
+ ASM_CLAC
+ pushl %eax # save orig_eax
+ SAVE_ALL
+ GET_THREAD_INFO(%ebp)
+ # system call tracing in operation / emulation
+ testl $_TIF_WORK_SYSCALL_ENTRY, TI_flags(%ebp)
+ jnz syscall_trace_entry
+ cmpl $(NR_syscalls), %eax
+ jae syscall_badsys
+syscall_call:
+ call *sys_call_table(, %eax, 4)
+syscall_after_call:
+ movl %eax, PT_EAX(%esp) # store the return value
+syscall_exit:
+ LOCKDEP_SYS_EXIT
+ DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
+ # setting need_resched or sigpending
+ # between sampling and the iret
+ TRACE_IRQS_OFF
+ movl TI_flags(%ebp), %ecx
+ testl $_TIF_ALLWORK_MASK, %ecx # current->work
+ jnz syscall_exit_work
+
+restore_all:
+ TRACE_IRQS_IRET
+restore_all_notrace:
+#ifdef CONFIG_X86_ESPFIX32
+ movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
+ /*
+ * Warning: PT_OLDSS(%esp) contains the wrong/random values if we
+ * are returning to the kernel.
+ * See comments in process.c:copy_thread() for details.
+ */
+ movb PT_OLDSS(%esp), %ah
+ movb PT_CS(%esp), %al
+ andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
+ cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
+ je ldt_ss # returning to user-space with LDT SS
+#endif
+restore_nocheck:
+ RESTORE_REGS 4 # skip orig_eax/error_code
+irq_return:
+ INTERRUPT_RETURN
+.section .fixup, "ax"
+ENTRY(iret_exc )
+ pushl $0 # no error code
+ pushl $do_iret_error
+ jmp error_code
+.previous
+ _ASM_EXTABLE(irq_return, iret_exc)
+
+#ifdef CONFIG_X86_ESPFIX32
+ldt_ss:
+#ifdef CONFIG_PARAVIRT
+ /*
+ * The kernel can't run on a non-flat stack if paravirt mode
+ * is active. Rather than try to fixup the high bits of
+ * ESP, bypass this code entirely. This may break DOSemu
+ * and/or Wine support in a paravirt VM, although the option
+ * is still available to implement the setting of the high
+ * 16-bits in the INTERRUPT_RETURN paravirt-op.
+ */
+ cmpl $0, pv_info+PARAVIRT_enabled
+ jne restore_nocheck
+#endif
+
+/*
+ * Setup and switch to ESPFIX stack
+ *
+ * We're returning to userspace with a 16 bit stack. The CPU will not
+ * restore the high word of ESP for us on executing iret... This is an
+ * "official" bug of all the x86-compatible CPUs, which we can work
+ * around to make dosemu and wine happy. We do this by preloading the
+ * high word of ESP with the high word of the userspace ESP while
+ * compensating for the offset by changing to the ESPFIX segment with
+ * a base address that matches for the difference.
+ */
+#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + (GDT_ENTRY_ESPFIX_SS * 8)
+ mov %esp, %edx /* load kernel esp */
+ mov PT_OLDESP(%esp), %eax /* load userspace esp */
+ mov %dx, %ax /* eax: new kernel esp */
+ sub %eax, %edx /* offset (low word is 0) */
+ shr $16, %edx
+ mov %dl, GDT_ESPFIX_SS + 4 /* bits 16..23 */
+ mov %dh, GDT_ESPFIX_SS + 7 /* bits 24..31 */
+ pushl $__ESPFIX_SS
+ pushl %eax /* new kernel esp */
+ /*
+ * Disable interrupts, but do not irqtrace this section: we
+ * will soon execute iret and the tracer was already set to
+ * the irqstate after the IRET:
+ */
+ DISABLE_INTERRUPTS(CLBR_EAX)
+ lss (%esp), %esp /* switch to espfix segment */
+ jmp restore_nocheck
+#endif
+ENDPROC(entry_INT80_32)
+
+ # perform work that needs to be done immediately before resumption
+ ALIGN
+work_pending:
+ testb $_TIF_NEED_RESCHED, %cl
+ jz work_notifysig
+work_resched:
+ call schedule
+ LOCKDEP_SYS_EXIT
+ DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
+ # setting need_resched or sigpending
+ # between sampling and the iret
+ TRACE_IRQS_OFF
+ movl TI_flags(%ebp), %ecx
+ andl $_TIF_WORK_MASK, %ecx # is there any work to be done other
+ # than syscall tracing?
+ jz restore_all
+ testb $_TIF_NEED_RESCHED, %cl
+ jnz work_resched
+
+work_notifysig: # deal with pending signals and
+ # notify-resume requests
+#ifdef CONFIG_VM86
+ testl $X86_EFLAGS_VM, PT_EFLAGS(%esp)
+ movl %esp, %eax
+ jnz work_notifysig_v86 # returning to kernel-space or
+ # vm86-space
+1:
+#else
+ movl %esp, %eax
+#endif
+ TRACE_IRQS_ON
+ ENABLE_INTERRUPTS(CLBR_NONE)
+ movb PT_CS(%esp), %bl
+ andb $SEGMENT_RPL_MASK, %bl
+ cmpb $USER_RPL, %bl
+ jb resume_kernel
+ xorl %edx, %edx
+ call do_notify_resume
+ jmp resume_userspace
+
+#ifdef CONFIG_VM86
+ ALIGN
+work_notifysig_v86:
+ pushl %ecx # save ti_flags for do_notify_resume
+ call save_v86_state # %eax contains pt_regs pointer
+ popl %ecx
+ movl %eax, %esp
+ jmp 1b
+#endif
+END(work_pending)
+
+ # perform syscall exit tracing
+ ALIGN
+syscall_trace_entry:
+ movl $-ENOSYS, PT_EAX(%esp)
+ movl %esp, %eax
+ call syscall_trace_enter
+ /* What it returned is what we'll actually use. */
+ cmpl $(NR_syscalls), %eax
+ jnae syscall_call
+ jmp syscall_exit
+END(syscall_trace_entry)
+
+ # perform syscall exit tracing
+ ALIGN
+syscall_exit_work:
+ testl $_TIF_WORK_SYSCALL_EXIT, %ecx
+ jz work_pending
+ TRACE_IRQS_ON
+ ENABLE_INTERRUPTS(CLBR_ANY) # could let syscall_trace_leave() call
+ # schedule() instead
+ movl %esp, %eax
+ call syscall_trace_leave
+ jmp resume_userspace
+END(syscall_exit_work)
+
+syscall_fault:
+ ASM_CLAC
+ GET_THREAD_INFO(%ebp)
+ movl $-EFAULT, PT_EAX(%esp)
+ jmp resume_userspace
+END(syscall_fault)
+
+syscall_badsys:
+ movl $-ENOSYS, %eax
+ jmp syscall_after_call
+END(syscall_badsys)
+
+sysenter_badsys:
+ movl $-ENOSYS, %eax
+ jmp sysenter_after_call
+END(sysenter_badsys)
+
+.macro FIXUP_ESPFIX_STACK
+/*
+ * Switch back for ESPFIX stack to the normal zerobased stack
+ *
+ * We can't call C functions using the ESPFIX stack. This code reads
+ * the high word of the segment base from the GDT and swiches to the
+ * normal stack and adjusts ESP with the matching offset.
+ */
+#ifdef CONFIG_X86_ESPFIX32
+ /* fixup the stack */
+ mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */
+ mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
+ shl $16, %eax
+ addl %esp, %eax /* the adjusted stack pointer */
+ pushl $__KERNEL_DS
+ pushl %eax
+ lss (%esp), %esp /* switch to the normal stack segment */
+#endif
+.endm
+.macro UNWIND_ESPFIX_STACK
+#ifdef CONFIG_X86_ESPFIX32
+ movl %ss, %eax
+ /* see if on espfix stack */
+ cmpw $__ESPFIX_SS, %ax
+ jne 27f
+ movl $__KERNEL_DS, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ /* switch to normal stack */
+ FIXUP_ESPFIX_STACK
+27:
+#endif
+.endm
+
+/*
+ * Build the entry stubs with some assembler magic.
+ * We pack 1 stub into every 8-byte block.
+ */
+ .align 8
+ENTRY(irq_entries_start)
+ vector=FIRST_EXTERNAL_VECTOR
+ .rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
+ pushl $(~vector+0x80) /* Note: always in signed byte range */
+ vector=vector+1
+ jmp common_interrupt
+ .align 8
+ .endr
+END(irq_entries_start)
+
+/*
+ * the CPU automatically disables interrupts when executing an IRQ vector,
+ * so IRQ-flags tracing has to follow that:
+ */
+ .p2align CONFIG_X86_L1_CACHE_SHIFT
+common_interrupt:
+ ASM_CLAC
+ addl $-0x80, (%esp) /* Adjust vector into the [-256, -1] range */
+ SAVE_ALL
+ TRACE_IRQS_OFF
+ movl %esp, %eax
+ call do_IRQ
+ jmp ret_from_intr
+ENDPROC(common_interrupt)
+
+#define BUILD_INTERRUPT3(name, nr, fn) \
+ENTRY(name) \
+ ASM_CLAC; \
+ pushl $~(nr); \
+ SAVE_ALL; \
+ TRACE_IRQS_OFF \
+ movl %esp, %eax; \
+ call fn; \
+ jmp ret_from_intr; \
+ENDPROC(name)
+
+
+#ifdef CONFIG_TRACING
+# define TRACE_BUILD_INTERRUPT(name, nr) BUILD_INTERRUPT3(trace_##name, nr, smp_trace_##name)
+#else
+# define TRACE_BUILD_INTERRUPT(name, nr)
+#endif
+
+#define BUILD_INTERRUPT(name, nr) \
+ BUILD_INTERRUPT3(name, nr, smp_##name); \
+ TRACE_BUILD_INTERRUPT(name, nr)
+
+/* The include is where all of the SMP etc. interrupts come from */
+#include <asm/entry_arch.h>
+
+ENTRY(coprocessor_error)
+ ASM_CLAC
+ pushl $0
+ pushl $do_coprocessor_error
+ jmp error_code
+END(coprocessor_error)
+
+ENTRY(simd_coprocessor_error)
+ ASM_CLAC
+ pushl $0
+#ifdef CONFIG_X86_INVD_BUG
+ /* AMD 486 bug: invd from userspace calls exception 19 instead of #GP */
+ ALTERNATIVE "pushl $do_general_protection", \
+ "pushl $do_simd_coprocessor_error", \
+ X86_FEATURE_XMM
+#else
+ pushl $do_simd_coprocessor_error
+#endif
+ jmp error_code
+END(simd_coprocessor_error)
+
+ENTRY(device_not_available)
+ ASM_CLAC
+ pushl $-1 # mark this as an int
+ pushl $do_device_not_available
+ jmp error_code
+END(device_not_available)
+
+#ifdef CONFIG_PARAVIRT
+ENTRY(native_iret)
+ iret
+ _ASM_EXTABLE(native_iret, iret_exc)
+END(native_iret)
+
+ENTRY(native_irq_enable_sysexit)
+ sti
+ sysexit
+END(native_irq_enable_sysexit)
+#endif
+
+ENTRY(overflow)
+ ASM_CLAC
+ pushl $0
+ pushl $do_overflow
+ jmp error_code
+END(overflow)
+
+ENTRY(bounds)
+ ASM_CLAC
+ pushl $0
+ pushl $do_bounds
+ jmp error_code
+END(bounds)
+
+ENTRY(invalid_op)
+ ASM_CLAC
+ pushl $0
+ pushl $do_invalid_op
+ jmp error_code
+END(invalid_op)
+
+ENTRY(coprocessor_segment_overrun)
+ ASM_CLAC
+ pushl $0
+ pushl $do_coprocessor_segment_overrun
+ jmp error_code
+END(coprocessor_segment_overrun)
+
+ENTRY(invalid_TSS)
+ ASM_CLAC
+ pushl $do_invalid_TSS
+ jmp error_code
+END(invalid_TSS)
+
+ENTRY(segment_not_present)
+ ASM_CLAC
+ pushl $do_segment_not_present
+ jmp error_code
+END(segment_not_present)
+
+ENTRY(stack_segment)
+ ASM_CLAC
+ pushl $do_stack_segment
+ jmp error_code
+END(stack_segment)
+
+ENTRY(alignment_check)
+ ASM_CLAC
+ pushl $do_alignment_check
+ jmp error_code
+END(alignment_check)
+
+ENTRY(divide_error)
+ ASM_CLAC
+ pushl $0 # no error code
+ pushl $do_divide_error
+ jmp error_code
+END(divide_error)
+
+#ifdef CONFIG_X86_MCE
+ENTRY(machine_check)
+ ASM_CLAC
+ pushl $0
+ pushl machine_check_vector
+ jmp error_code
+END(machine_check)
+#endif
+
+ENTRY(spurious_interrupt_bug)
+ ASM_CLAC
+ pushl $0
+ pushl $do_spurious_interrupt_bug
+ jmp error_code
+END(spurious_interrupt_bug)
+
+#ifdef CONFIG_XEN
+/*
+ * Xen doesn't set %esp to be precisely what the normal SYSENTER
+ * entry point expects, so fix it up before using the normal path.
+ */
+ENTRY(xen_sysenter_target)
+ addl $5*4, %esp /* remove xen-provided frame */
+ jmp sysenter_past_esp
+
+ENTRY(xen_hypervisor_callback)
+ pushl $-1 /* orig_ax = -1 => not a system call */
+ SAVE_ALL
+ TRACE_IRQS_OFF
+
+ /*
+ * Check to see if we got the event in the critical
+ * region in xen_iret_direct, after we've reenabled
+ * events and checked for pending events. This simulates
+ * iret instruction's behaviour where it delivers a
+ * pending interrupt when enabling interrupts:
+ */
+ movl PT_EIP(%esp), %eax
+ cmpl $xen_iret_start_crit, %eax
+ jb 1f
+ cmpl $xen_iret_end_crit, %eax
+ jae 1f
+
+ jmp xen_iret_crit_fixup
+
+ENTRY(xen_do_upcall)
+1: mov %esp, %eax
+ call xen_evtchn_do_upcall
+#ifndef CONFIG_PREEMPT
+ call xen_maybe_preempt_hcall
+#endif
+ jmp ret_from_intr
+ENDPROC(xen_hypervisor_callback)
+
+/*
+ * Hypervisor uses this for application faults while it executes.
+ * We get here for two reasons:
+ * 1. Fault while reloading DS, ES, FS or GS
+ * 2. Fault while executing IRET
+ * Category 1 we fix up by reattempting the load, and zeroing the segment
+ * register if the load fails.
+ * Category 2 we fix up by jumping to do_iret_error. We cannot use the
+ * normal Linux return path in this case because if we use the IRET hypercall
+ * to pop the stack frame we end up in an infinite loop of failsafe callbacks.
+ * We distinguish between categories by maintaining a status value in EAX.
+ */
+ENTRY(xen_failsafe_callback)
+ pushl %eax
+ movl $1, %eax
+1: mov 4(%esp), %ds
+2: mov 8(%esp), %es
+3: mov 12(%esp), %fs
+4: mov 16(%esp), %gs
+ /* EAX == 0 => Category 1 (Bad segment)
+ EAX != 0 => Category 2 (Bad IRET) */
+ testl %eax, %eax
+ popl %eax
+ lea 16(%esp), %esp
+ jz 5f
+ jmp iret_exc
+5: pushl $-1 /* orig_ax = -1 => not a system call */
+ SAVE_ALL
+ jmp ret_from_exception
+
+.section .fixup, "ax"
+6: xorl %eax, %eax
+ movl %eax, 4(%esp)
+ jmp 1b
+7: xorl %eax, %eax
+ movl %eax, 8(%esp)
+ jmp 2b
+8: xorl %eax, %eax
+ movl %eax, 12(%esp)
+ jmp 3b
+9: xorl %eax, %eax
+ movl %eax, 16(%esp)
+ jmp 4b
+.previous
+ _ASM_EXTABLE(1b, 6b)
+ _ASM_EXTABLE(2b, 7b)
+ _ASM_EXTABLE(3b, 8b)
+ _ASM_EXTABLE(4b, 9b)
+ENDPROC(xen_failsafe_callback)
+
+BUILD_INTERRUPT3(xen_hvm_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
+ xen_evtchn_do_upcall)
+
+#endif /* CONFIG_XEN */
+
+#if IS_ENABLED(CONFIG_HYPERV)
+
+BUILD_INTERRUPT3(hyperv_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
+ hyperv_vector_handler)
+
+#endif /* CONFIG_HYPERV */
+
+#ifdef CONFIG_FUNCTION_TRACER
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+ENTRY(mcount)
+ ret
+END(mcount)
+
+ENTRY(ftrace_caller)
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ pushl $0 /* Pass NULL as regs pointer */
+ movl 4*4(%esp), %eax
+ movl 0x4(%ebp), %edx
+ movl function_trace_op, %ecx
+ subl $MCOUNT_INSN_SIZE, %eax
+
+.globl ftrace_call
+ftrace_call:
+ call ftrace_stub
+
+ addl $4, %esp /* skip NULL pointer */
+ popl %edx
+ popl %ecx
+ popl %eax
+ftrace_ret:
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+.globl ftrace_graph_call
+ftrace_graph_call:
+ jmp ftrace_stub
+#endif
+
+.globl ftrace_stub
+ftrace_stub:
+ ret
+END(ftrace_caller)
+
+ENTRY(ftrace_regs_caller)
+ pushf /* push flags before compare (in cs location) */
+
+ /*
+ * i386 does not save SS and ESP when coming from kernel.
+ * Instead, to get sp, &regs->sp is used (see ptrace.h).
+ * Unfortunately, that means eflags must be at the same location
+ * as the current return ip is. We move the return ip into the
+ * ip location, and move flags into the return ip location.
+ */
+ pushl 4(%esp) /* save return ip into ip slot */
+
+ pushl $0 /* Load 0 into orig_ax */
+ pushl %gs
+ pushl %fs
+ pushl %es
+ pushl %ds
+ pushl %eax
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+
+ movl 13*4(%esp), %eax /* Get the saved flags */
+ movl %eax, 14*4(%esp) /* Move saved flags into regs->flags location */
+ /* clobbering return ip */
+ movl $__KERNEL_CS, 13*4(%esp)
+
+ movl 12*4(%esp), %eax /* Load ip (1st parameter) */
+ subl $MCOUNT_INSN_SIZE, %eax /* Adjust ip */
+ movl 0x4(%ebp), %edx /* Load parent ip (2nd parameter) */
+ movl function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */
+ pushl %esp /* Save pt_regs as 4th parameter */
+
+GLOBAL(ftrace_regs_call)
+ call ftrace_stub
+
+ addl $4, %esp /* Skip pt_regs */
+ movl 14*4(%esp), %eax /* Move flags back into cs */
+ movl %eax, 13*4(%esp) /* Needed to keep addl from modifying flags */
+ movl 12*4(%esp), %eax /* Get return ip from regs->ip */
+ movl %eax, 14*4(%esp) /* Put return ip back for ret */
+
+ popl %ebx
+ popl %ecx
+ popl %edx
+ popl %esi
+ popl %edi
+ popl %ebp
+ popl %eax
+ popl %ds
+ popl %es
+ popl %fs
+ popl %gs
+ addl $8, %esp /* Skip orig_ax and ip */
+ popf /* Pop flags at end (no addl to corrupt flags) */
+ jmp ftrace_ret
+
+ popf
+ jmp ftrace_stub
+#else /* ! CONFIG_DYNAMIC_FTRACE */
+
+ENTRY(mcount)
+ cmpl $__PAGE_OFFSET, %esp
+ jb ftrace_stub /* Paging not enabled yet? */
+
+ cmpl $ftrace_stub, ftrace_trace_function
+ jnz trace
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ cmpl $ftrace_stub, ftrace_graph_return
+ jnz ftrace_graph_caller
+
+ cmpl $ftrace_graph_entry_stub, ftrace_graph_entry
+ jnz ftrace_graph_caller
+#endif
+.globl ftrace_stub
+ftrace_stub:
+ ret
+
+ /* taken from glibc */
+trace:
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ movl 0xc(%esp), %eax
+ movl 0x4(%ebp), %edx
+ subl $MCOUNT_INSN_SIZE, %eax
+
+ call *ftrace_trace_function
+
+ popl %edx
+ popl %ecx
+ popl %eax
+ jmp ftrace_stub
+END(mcount)
+#endif /* CONFIG_DYNAMIC_FTRACE */
+#endif /* CONFIG_FUNCTION_TRACER */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ENTRY(ftrace_graph_caller)
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ movl 0xc(%esp), %eax
+ lea 0x4(%ebp), %edx
+ movl (%ebp), %ecx
+ subl $MCOUNT_INSN_SIZE, %eax
+ call prepare_ftrace_return
+ popl %edx
+ popl %ecx
+ popl %eax
+ ret
+END(ftrace_graph_caller)
+
+.globl return_to_handler
+return_to_handler:
+ pushl %eax
+ pushl %edx
+ movl %ebp, %eax
+ call ftrace_return_to_handler
+ movl %eax, %ecx
+ popl %edx
+ popl %eax
+ jmp *%ecx
+#endif
+
+#ifdef CONFIG_TRACING
+ENTRY(trace_page_fault)
+ ASM_CLAC
+ pushl $trace_do_page_fault
+ jmp error_code
+END(trace_page_fault)
+#endif
+
+ENTRY(page_fault)
+ ASM_CLAC
+ pushl $do_page_fault
+ ALIGN
+error_code:
+ /* the function address is in %gs's slot on the stack */
+ pushl %fs
+ pushl %es
+ pushl %ds
+ pushl %eax
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+ cld
+ movl $(__KERNEL_PERCPU), %ecx
+ movl %ecx, %fs
+ UNWIND_ESPFIX_STACK
+ GS_TO_REG %ecx
+ movl PT_GS(%esp), %edi # get the function address
+ movl PT_ORIG_EAX(%esp), %edx # get the error code
+ movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart
+ REG_TO_PTGS %ecx
+ SET_KERNEL_GS %ecx
+ movl $(__USER_DS), %ecx
+ movl %ecx, %ds
+ movl %ecx, %es
+ TRACE_IRQS_OFF
+ movl %esp, %eax # pt_regs pointer
+ call *%edi
+ jmp ret_from_exception
+END(page_fault)
+
+/*
+ * Debug traps and NMI can happen at the one SYSENTER instruction
+ * that sets up the real kernel stack. Check here, since we can't
+ * allow the wrong stack to be used.
+ *
+ * "TSS_sysenter_sp0+12" is because the NMI/debug handler will have
+ * already pushed 3 words if it hits on the sysenter instruction:
+ * eflags, cs and eip.
+ *
+ * We just load the right stack, and push the three (known) values
+ * by hand onto the new stack - while updating the return eip past
+ * the instruction that would have done it for sysenter.
+ */
+.macro FIX_STACK offset ok label
+ cmpw $__KERNEL_CS, 4(%esp)
+ jne \ok
+\label:
+ movl TSS_sysenter_sp0 + \offset(%esp), %esp
+ pushfl
+ pushl $__KERNEL_CS
+ pushl $sysenter_past_esp
+.endm
+
+ENTRY(debug)
+ ASM_CLAC
+ cmpl $entry_SYSENTER_32, (%esp)
+ jne debug_stack_correct
+ FIX_STACK 12, debug_stack_correct, debug_esp_fix_insn
+debug_stack_correct:
+ pushl $-1 # mark this as an int
+ SAVE_ALL
+ TRACE_IRQS_OFF
+ xorl %edx, %edx # error code 0
+ movl %esp, %eax # pt_regs pointer
+ call do_debug
+ jmp ret_from_exception
+END(debug)
+
+/*
+ * NMI is doubly nasty. It can happen _while_ we're handling
+ * a debug fault, and the debug fault hasn't yet been able to
+ * clear up the stack. So we first check whether we got an
+ * NMI on the sysenter entry path, but after that we need to
+ * check whether we got an NMI on the debug path where the debug
+ * fault happened on the sysenter path.
+ */
+ENTRY(nmi)
+ ASM_CLAC
+#ifdef CONFIG_X86_ESPFIX32
+ pushl %eax
+ movl %ss, %eax
+ cmpw $__ESPFIX_SS, %ax
+ popl %eax
+ je nmi_espfix_stack
+#endif
+ cmpl $entry_SYSENTER_32, (%esp)
+ je nmi_stack_fixup
+ pushl %eax
+ movl %esp, %eax
+ /*
+ * Do not access memory above the end of our stack page,
+ * it might not exist.
+ */
+ andl $(THREAD_SIZE-1), %eax
+ cmpl $(THREAD_SIZE-20), %eax
+ popl %eax
+ jae nmi_stack_correct
+ cmpl $entry_SYSENTER_32, 12(%esp)
+ je nmi_debug_stack_check
+nmi_stack_correct:
+ pushl %eax
+ SAVE_ALL
+ xorl %edx, %edx # zero error code
+ movl %esp, %eax # pt_regs pointer
+ call do_nmi
+ jmp restore_all_notrace
+
+nmi_stack_fixup:
+ FIX_STACK 12, nmi_stack_correct, 1
+ jmp nmi_stack_correct
+
+nmi_debug_stack_check:
+ cmpw $__KERNEL_CS, 16(%esp)
+ jne nmi_stack_correct
+ cmpl $debug, (%esp)
+ jb nmi_stack_correct
+ cmpl $debug_esp_fix_insn, (%esp)
+ ja nmi_stack_correct
+ FIX_STACK 24, nmi_stack_correct, 1
+ jmp nmi_stack_correct
+
+#ifdef CONFIG_X86_ESPFIX32
+nmi_espfix_stack:
+ /*
+ * create the pointer to lss back
+ */
+ pushl %ss
+ pushl %esp
+ addl $4, (%esp)
+ /* copy the iret frame of 12 bytes */
+ .rept 3
+ pushl 16(%esp)
+ .endr
+ pushl %eax
+ SAVE_ALL
+ FIXUP_ESPFIX_STACK # %eax == %esp
+ xorl %edx, %edx # zero error code
+ call do_nmi
+ RESTORE_REGS
+ lss 12+4(%esp), %esp # back to espfix stack
+ jmp irq_return
+#endif
+END(nmi)
+
+ENTRY(int3)
+ ASM_CLAC
+ pushl $-1 # mark this as an int
+ SAVE_ALL
+ TRACE_IRQS_OFF
+ xorl %edx, %edx # zero error code
+ movl %esp, %eax # pt_regs pointer
+ call do_int3
+ jmp ret_from_exception
+END(int3)
+
+ENTRY(general_protection)
+ pushl $do_general_protection
+ jmp error_code
+END(general_protection)
+
+#ifdef CONFIG_KVM_GUEST
+ENTRY(async_page_fault)
+ ASM_CLAC
+ pushl $do_async_page_fault
+ jmp error_code
+END(async_page_fault)
+#endif
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/entry/entry_64.S
index 02c2eff7478d..3bb2c4302df1 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -4,34 +4,25 @@
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs
* Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
- */
-
-/*
+ *
* entry.S contains the system-call and fault low-level handling routines.
*
* Some of this is documented in Documentation/x86/entry_64.txt
*
- * NOTE: This code handles signal-recognition, which happens every time
- * after an interrupt and after each system call.
- *
* A note on terminology:
- * - iret frame: Architecture defined interrupt frame from SS to RIP
- * at the top of the kernel process stack.
+ * - iret frame: Architecture defined interrupt frame from SS to RIP
+ * at the top of the kernel process stack.
*
* Some macro usage:
- * - CFI macros are used to generate dwarf2 unwind information for better
- * backtraces. They don't change any code.
- * - ENTRY/END Define functions in the symbol table.
- * - TRACE_IRQ_* - Trace hard interrupt state for lock debugging.
- * - idtentry - Define exception entry points.
+ * - ENTRY/END: Define functions in the symbol table.
+ * - TRACE_IRQ_*: Trace hardirq state for lock debugging.
+ * - idtentry: Define exception entry points.
*/
-
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/cache.h>
#include <asm/errno.h>
-#include <asm/dwarf2.h>
-#include <asm/calling.h>
+#include "calling.h"
#include <asm/asm-offsets.h>
#include <asm/msr.h>
#include <asm/unistd.h>
@@ -49,13 +40,12 @@
/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
#include <linux/elf-em.h>
-#define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
-#define __AUDIT_ARCH_64BIT 0x80000000
-#define __AUDIT_ARCH_LE 0x40000000
-
- .code64
- .section .entry.text, "ax"
+#define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#define __AUDIT_ARCH_64BIT 0x80000000
+#define __AUDIT_ARCH_LE 0x40000000
+.code64
+.section .entry.text, "ax"
#ifdef CONFIG_PARAVIRT
ENTRY(native_usergs_sysret64)
@@ -64,11 +54,10 @@ ENTRY(native_usergs_sysret64)
ENDPROC(native_usergs_sysret64)
#endif /* CONFIG_PARAVIRT */
-
.macro TRACE_IRQS_IRETQ
#ifdef CONFIG_TRACE_IRQFLAGS
- bt $9,EFLAGS(%rsp) /* interrupts off? */
- jnc 1f
+ bt $9, EFLAGS(%rsp) /* interrupts off? */
+ jnc 1f
TRACE_IRQS_ON
1:
#endif
@@ -88,89 +77,34 @@ ENDPROC(native_usergs_sysret64)
#if defined(CONFIG_DYNAMIC_FTRACE) && defined(CONFIG_TRACE_IRQFLAGS)
.macro TRACE_IRQS_OFF_DEBUG
- call debug_stack_set_zero
+ call debug_stack_set_zero
TRACE_IRQS_OFF
- call debug_stack_reset
+ call debug_stack_reset
.endm
.macro TRACE_IRQS_ON_DEBUG
- call debug_stack_set_zero
+ call debug_stack_set_zero
TRACE_IRQS_ON
- call debug_stack_reset
+ call debug_stack_reset
.endm
.macro TRACE_IRQS_IRETQ_DEBUG
- bt $9,EFLAGS(%rsp) /* interrupts off? */
- jnc 1f
+ bt $9, EFLAGS(%rsp) /* interrupts off? */
+ jnc 1f
TRACE_IRQS_ON_DEBUG
1:
.endm
#else
-# define TRACE_IRQS_OFF_DEBUG TRACE_IRQS_OFF
-# define TRACE_IRQS_ON_DEBUG TRACE_IRQS_ON
-# define TRACE_IRQS_IRETQ_DEBUG TRACE_IRQS_IRETQ
+# define TRACE_IRQS_OFF_DEBUG TRACE_IRQS_OFF
+# define TRACE_IRQS_ON_DEBUG TRACE_IRQS_ON
+# define TRACE_IRQS_IRETQ_DEBUG TRACE_IRQS_IRETQ
#endif
/*
- * empty frame
- */
- .macro EMPTY_FRAME start=1 offset=0
- .if \start
- CFI_STARTPROC simple
- CFI_SIGNAL_FRAME
- CFI_DEF_CFA rsp,8+\offset
- .else
- CFI_DEF_CFA_OFFSET 8+\offset
- .endif
- .endm
-
-/*
- * initial frame state for interrupts (and exceptions without error code)
- */
- .macro INTR_FRAME start=1 offset=0
- EMPTY_FRAME \start, 5*8+\offset
- /*CFI_REL_OFFSET ss, 4*8+\offset*/
- CFI_REL_OFFSET rsp, 3*8+\offset
- /*CFI_REL_OFFSET rflags, 2*8+\offset*/
- /*CFI_REL_OFFSET cs, 1*8+\offset*/
- CFI_REL_OFFSET rip, 0*8+\offset
- .endm
-
-/*
- * initial frame state for exceptions with error code (and interrupts
- * with vector already pushed)
- */
- .macro XCPT_FRAME start=1 offset=0
- INTR_FRAME \start, 1*8+\offset
- .endm
-
-/*
- * frame that enables passing a complete pt_regs to a C function.
- */
- .macro DEFAULT_FRAME start=1 offset=0
- XCPT_FRAME \start, ORIG_RAX+\offset
- CFI_REL_OFFSET rdi, RDI+\offset
- CFI_REL_OFFSET rsi, RSI+\offset
- CFI_REL_OFFSET rdx, RDX+\offset
- CFI_REL_OFFSET rcx, RCX+\offset
- CFI_REL_OFFSET rax, RAX+\offset
- CFI_REL_OFFSET r8, R8+\offset
- CFI_REL_OFFSET r9, R9+\offset
- CFI_REL_OFFSET r10, R10+\offset
- CFI_REL_OFFSET r11, R11+\offset
- CFI_REL_OFFSET rbx, RBX+\offset
- CFI_REL_OFFSET rbp, RBP+\offset
- CFI_REL_OFFSET r12, R12+\offset
- CFI_REL_OFFSET r13, R13+\offset
- CFI_REL_OFFSET r14, R14+\offset
- CFI_REL_OFFSET r15, R15+\offset
- .endm
-
-/*
- * 64bit SYSCALL instruction entry. Up to 6 arguments in registers.
+ * 64-bit SYSCALL instruction entry. Up to 6 arguments in registers.
*
- * 64bit SYSCALL saves rip to rcx, clears rflags.RF, then saves rflags to r11,
+ * 64-bit SYSCALL saves rip to rcx, clears rflags.RF, then saves rflags to r11,
* then loads new ss, cs, and rip from previously programmed MSRs.
* rflags gets masked by a value from another MSR (so CLD and CLAC
* are not needed). SYSCALL does not save anything on the stack
@@ -186,7 +120,7 @@ ENDPROC(native_usergs_sysret64)
* r10 arg3 (needs to be moved to rcx to conform to C ABI)
* r8 arg4
* r9 arg5
- * (note: r12-r15,rbp,rbx are callee-preserved in C ABI)
+ * (note: r12-r15, rbp, rbx are callee-preserved in C ABI)
*
* Only called from user space.
*
@@ -195,13 +129,7 @@ ENDPROC(native_usergs_sysret64)
* with them due to bugs in both AMD and Intel CPUs.
*/
-ENTRY(system_call)
- CFI_STARTPROC simple
- CFI_SIGNAL_FRAME
- CFI_DEF_CFA rsp,0
- CFI_REGISTER rip,rcx
- /*CFI_REGISTER rflags,r11*/
-
+ENTRY(entry_SYSCALL_64)
/*
* Interrupts are off on entry.
* We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON,
@@ -213,14 +141,14 @@ ENTRY(system_call)
* after the swapgs, so that it can do the swapgs
* for the guest and jump here on syscall.
*/
-GLOBAL(system_call_after_swapgs)
+GLOBAL(entry_SYSCALL_64_after_swapgs)
- movq %rsp,PER_CPU_VAR(rsp_scratch)
- movq PER_CPU_VAR(kernel_stack),%rsp
+ movq %rsp, PER_CPU_VAR(rsp_scratch)
+ movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
/* Construct struct pt_regs on stack */
- pushq_cfi $__USER_DS /* pt_regs->ss */
- pushq_cfi PER_CPU_VAR(rsp_scratch) /* pt_regs->sp */
+ pushq $__USER_DS /* pt_regs->ss */
+ pushq PER_CPU_VAR(rsp_scratch) /* pt_regs->sp */
/*
* Re-enable interrupts.
* We use 'rsp_scratch' as a scratch space, hence irq-off block above
@@ -229,36 +157,34 @@ GLOBAL(system_call_after_swapgs)
* with using rsp_scratch:
*/
ENABLE_INTERRUPTS(CLBR_NONE)
- pushq_cfi %r11 /* pt_regs->flags */
- pushq_cfi $__USER_CS /* pt_regs->cs */
- pushq_cfi %rcx /* pt_regs->ip */
- CFI_REL_OFFSET rip,0
- pushq_cfi_reg rax /* pt_regs->orig_ax */
- pushq_cfi_reg rdi /* pt_regs->di */
- pushq_cfi_reg rsi /* pt_regs->si */
- pushq_cfi_reg rdx /* pt_regs->dx */
- pushq_cfi_reg rcx /* pt_regs->cx */
- pushq_cfi $-ENOSYS /* pt_regs->ax */
- pushq_cfi_reg r8 /* pt_regs->r8 */
- pushq_cfi_reg r9 /* pt_regs->r9 */
- pushq_cfi_reg r10 /* pt_regs->r10 */
- pushq_cfi_reg r11 /* pt_regs->r11 */
- sub $(6*8),%rsp /* pt_regs->bp,bx,r12-15 not saved */
- CFI_ADJUST_CFA_OFFSET 6*8
-
- testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
- jnz tracesys
-system_call_fastpath:
+ pushq %r11 /* pt_regs->flags */
+ pushq $__USER_CS /* pt_regs->cs */
+ pushq %rcx /* pt_regs->ip */
+ pushq %rax /* pt_regs->orig_ax */
+ pushq %rdi /* pt_regs->di */
+ pushq %rsi /* pt_regs->si */
+ pushq %rdx /* pt_regs->dx */
+ pushq %rcx /* pt_regs->cx */
+ pushq $-ENOSYS /* pt_regs->ax */
+ pushq %r8 /* pt_regs->r8 */
+ pushq %r9 /* pt_regs->r9 */
+ pushq %r10 /* pt_regs->r10 */
+ pushq %r11 /* pt_regs->r11 */
+ sub $(6*8), %rsp /* pt_regs->bp, bx, r12-15 not saved */
+
+ testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
+ jnz tracesys
+entry_SYSCALL_64_fastpath:
#if __SYSCALL_MASK == ~0
- cmpq $__NR_syscall_max,%rax
+ cmpq $__NR_syscall_max, %rax
#else
- andl $__SYSCALL_MASK,%eax
- cmpl $__NR_syscall_max,%eax
+ andl $__SYSCALL_MASK, %eax
+ cmpl $__NR_syscall_max, %eax
#endif
- ja 1f /* return -ENOSYS (already in pt_regs->ax) */
- movq %r10,%rcx
- call *sys_call_table(,%rax,8)
- movq %rax,RAX(%rsp)
+ ja 1f /* return -ENOSYS (already in pt_regs->ax) */
+ movq %r10, %rcx
+ call *sys_call_table(, %rax, 8)
+ movq %rax, RAX(%rsp)
1:
/*
* Syscall return path ending with SYSRET (fast path).
@@ -279,19 +205,15 @@ system_call_fastpath:
* flags (TIF_NOTIFY_RESUME, TIF_USER_RETURN_NOTIFY, etc) set is
* very bad.
*/
- testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
- jnz int_ret_from_sys_call_irqs_off /* Go to the slow path */
-
- CFI_REMEMBER_STATE
+ testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
+ jnz int_ret_from_sys_call_irqs_off /* Go to the slow path */
RESTORE_C_REGS_EXCEPT_RCX_R11
- movq RIP(%rsp),%rcx
- CFI_REGISTER rip,rcx
- movq EFLAGS(%rsp),%r11
- /*CFI_REGISTER rflags,r11*/
- movq RSP(%rsp),%rsp
+ movq RIP(%rsp), %rcx
+ movq EFLAGS(%rsp), %r11
+ movq RSP(%rsp), %rsp
/*
- * 64bit SYSRET restores rip from rcx,
+ * 64-bit SYSRET restores rip from rcx,
* rflags from r11 (but RF and VM bits are forced to 0),
* cs and ss are loaded from MSRs.
* Restoration of rflags re-enables interrupts.
@@ -307,25 +229,23 @@ system_call_fastpath:
*/
USERGS_SYSRET64
- CFI_RESTORE_STATE
-
/* Do syscall entry tracing */
tracesys:
- movq %rsp, %rdi
- movl $AUDIT_ARCH_X86_64, %esi
- call syscall_trace_enter_phase1
- test %rax, %rax
- jnz tracesys_phase2 /* if needed, run the slow path */
- RESTORE_C_REGS_EXCEPT_RAX /* else restore clobbered regs */
- movq ORIG_RAX(%rsp), %rax
- jmp system_call_fastpath /* and return to the fast path */
+ movq %rsp, %rdi
+ movl $AUDIT_ARCH_X86_64, %esi
+ call syscall_trace_enter_phase1
+ test %rax, %rax
+ jnz tracesys_phase2 /* if needed, run the slow path */
+ RESTORE_C_REGS_EXCEPT_RAX /* else restore clobbered regs */
+ movq ORIG_RAX(%rsp), %rax
+ jmp entry_SYSCALL_64_fastpath /* and return to the fast path */
tracesys_phase2:
SAVE_EXTRA_REGS
- movq %rsp, %rdi
- movl $AUDIT_ARCH_X86_64, %esi
- movq %rax,%rdx
- call syscall_trace_enter_phase2
+ movq %rsp, %rdi
+ movl $AUDIT_ARCH_X86_64, %esi
+ movq %rax, %rdx
+ call syscall_trace_enter_phase2
/*
* Reload registers from stack in case ptrace changed them.
@@ -335,15 +255,15 @@ tracesys_phase2:
RESTORE_C_REGS_EXCEPT_RAX
RESTORE_EXTRA_REGS
#if __SYSCALL_MASK == ~0
- cmpq $__NR_syscall_max,%rax
+ cmpq $__NR_syscall_max, %rax
#else
- andl $__SYSCALL_MASK,%eax
- cmpl $__NR_syscall_max,%eax
+ andl $__SYSCALL_MASK, %eax
+ cmpl $__NR_syscall_max, %eax
#endif
- ja 1f /* return -ENOSYS (already in pt_regs->ax) */
- movq %r10,%rcx /* fixup for C */
- call *sys_call_table(,%rax,8)
- movq %rax,RAX(%rsp)
+ ja 1f /* return -ENOSYS (already in pt_regs->ax) */
+ movq %r10, %rcx /* fixup for C */
+ call *sys_call_table(, %rax, 8)
+ movq %rax, RAX(%rsp)
1:
/* Use IRET because user could have changed pt_regs->foo */
@@ -355,31 +275,33 @@ GLOBAL(int_ret_from_sys_call)
DISABLE_INTERRUPTS(CLBR_NONE)
int_ret_from_sys_call_irqs_off: /* jumps come here from the irqs-off SYSRET path */
TRACE_IRQS_OFF
- movl $_TIF_ALLWORK_MASK,%edi
+ movl $_TIF_ALLWORK_MASK, %edi
/* edi: mask to check */
GLOBAL(int_with_check)
LOCKDEP_SYS_EXIT_IRQ
GET_THREAD_INFO(%rcx)
- movl TI_flags(%rcx),%edx
- andl %edi,%edx
- jnz int_careful
- andl $~TS_COMPAT,TI_status(%rcx)
+ movl TI_flags(%rcx), %edx
+ andl %edi, %edx
+ jnz int_careful
+ andl $~TS_COMPAT, TI_status(%rcx)
jmp syscall_return
- /* Either reschedule or signal or syscall exit tracking needed. */
- /* First do a reschedule test. */
- /* edx: work, edi: workmask */
+ /*
+ * Either reschedule or signal or syscall exit tracking needed.
+ * First do a reschedule test.
+ * edx: work, edi: workmask
+ */
int_careful:
- bt $TIF_NEED_RESCHED,%edx
- jnc int_very_careful
+ bt $TIF_NEED_RESCHED, %edx
+ jnc int_very_careful
TRACE_IRQS_ON
ENABLE_INTERRUPTS(CLBR_NONE)
- pushq_cfi %rdi
+ pushq %rdi
SCHEDULE_USER
- popq_cfi %rdi
+ popq %rdi
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF
- jmp int_with_check
+ jmp int_with_check
/* handle signals and tracing -- both require a full pt_regs */
int_very_careful:
@@ -387,27 +309,27 @@ int_very_careful:
ENABLE_INTERRUPTS(CLBR_NONE)
SAVE_EXTRA_REGS
/* Check for syscall exit trace */
- testl $_TIF_WORK_SYSCALL_EXIT,%edx
- jz int_signal
- pushq_cfi %rdi
- leaq 8(%rsp),%rdi # &ptregs -> arg1
- call syscall_trace_leave
- popq_cfi %rdi
- andl $~(_TIF_WORK_SYSCALL_EXIT|_TIF_SYSCALL_EMU),%edi
- jmp int_restore_rest
+ testl $_TIF_WORK_SYSCALL_EXIT, %edx
+ jz int_signal
+ pushq %rdi
+ leaq 8(%rsp), %rdi /* &ptregs -> arg1 */
+ call syscall_trace_leave
+ popq %rdi
+ andl $~(_TIF_WORK_SYSCALL_EXIT|_TIF_SYSCALL_EMU), %edi
+ jmp int_restore_rest
int_signal:
- testl $_TIF_DO_NOTIFY_MASK,%edx
- jz 1f
- movq %rsp,%rdi # &ptregs -> arg1
- xorl %esi,%esi # oldset -> arg2
- call do_notify_resume
-1: movl $_TIF_WORK_MASK,%edi
+ testl $_TIF_DO_NOTIFY_MASK, %edx
+ jz 1f
+ movq %rsp, %rdi /* &ptregs -> arg1 */
+ xorl %esi, %esi /* oldset -> arg2 */
+ call do_notify_resume
+1: movl $_TIF_WORK_MASK, %edi
int_restore_rest:
RESTORE_EXTRA_REGS
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF
- jmp int_with_check
+ jmp int_with_check
syscall_return:
/* The IRETQ could re-enable interrupts: */
@@ -418,34 +340,37 @@ syscall_return:
* Try to use SYSRET instead of IRET if we're returning to
* a completely clean 64-bit userspace context.
*/
- movq RCX(%rsp),%rcx
- cmpq %rcx,RIP(%rsp) /* RCX == RIP */
- jne opportunistic_sysret_failed
+ movq RCX(%rsp), %rcx
+ movq RIP(%rsp), %r11
+ cmpq %rcx, %r11 /* RCX == RIP */
+ jne opportunistic_sysret_failed
/*
* On Intel CPUs, SYSRET with non-canonical RCX/RIP will #GP
* in kernel space. This essentially lets the user take over
- * the kernel, since userspace controls RSP. It's not worth
- * testing for canonicalness exactly -- this check detects any
- * of the 17 high bits set, which is true for non-canonical
- * or kernel addresses. (This will pessimize vsyscall=native.
- * Big deal.)
+ * the kernel, since userspace controls RSP.
*
- * If virtual addresses ever become wider, this will need
+ * If width of "canonical tail" ever becomes variable, this will need
* to be updated to remain correct on both old and new CPUs.
*/
.ifne __VIRTUAL_MASK_SHIFT - 47
.error "virtual address width changed -- SYSRET checks need update"
.endif
- shr $__VIRTUAL_MASK_SHIFT, %rcx
- jnz opportunistic_sysret_failed
- cmpq $__USER_CS,CS(%rsp) /* CS must match SYSRET */
- jne opportunistic_sysret_failed
+ /* Change top 16 bits to be the sign-extension of 47th bit */
+ shl $(64 - (__VIRTUAL_MASK_SHIFT+1)), %rcx
+ sar $(64 - (__VIRTUAL_MASK_SHIFT+1)), %rcx
- movq R11(%rsp),%r11
- cmpq %r11,EFLAGS(%rsp) /* R11 == RFLAGS */
- jne opportunistic_sysret_failed
+ /* If this changed %rcx, it was not canonical */
+ cmpq %rcx, %r11
+ jne opportunistic_sysret_failed
+
+ cmpq $__USER_CS, CS(%rsp) /* CS must match SYSRET */
+ jne opportunistic_sysret_failed
+
+ movq R11(%rsp), %r11
+ cmpq %r11, EFLAGS(%rsp) /* R11 == RFLAGS */
+ jne opportunistic_sysret_failed
/*
* SYSRET can't restore RF. SYSRET can restore TF, but unlike IRET,
@@ -454,47 +379,41 @@ syscall_return:
* with register state that satisfies the opportunistic SYSRET
* conditions. For example, single-stepping this user code:
*
- * movq $stuck_here,%rcx
+ * movq $stuck_here, %rcx
* pushfq
* popq %r11
* stuck_here:
*
* would never get past 'stuck_here'.
*/
- testq $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11
- jnz opportunistic_sysret_failed
+ testq $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11
+ jnz opportunistic_sysret_failed
/* nothing to check for RSP */
- cmpq $__USER_DS,SS(%rsp) /* SS must match SYSRET */
- jne opportunistic_sysret_failed
+ cmpq $__USER_DS, SS(%rsp) /* SS must match SYSRET */
+ jne opportunistic_sysret_failed
/*
- * We win! This label is here just for ease of understanding
- * perf profiles. Nothing jumps here.
+ * We win! This label is here just for ease of understanding
+ * perf profiles. Nothing jumps here.
*/
syscall_return_via_sysret:
- CFI_REMEMBER_STATE
- /* r11 is already restored (see code above) */
- RESTORE_C_REGS_EXCEPT_R11
- movq RSP(%rsp),%rsp
+ /* rcx and r11 are already restored (see code above) */
+ RESTORE_C_REGS_EXCEPT_RCX_R11
+ movq RSP(%rsp), %rsp
USERGS_SYSRET64
- CFI_RESTORE_STATE
opportunistic_sysret_failed:
SWAPGS
jmp restore_c_regs_and_iret
- CFI_ENDPROC
-END(system_call)
+END(entry_SYSCALL_64)
.macro FORK_LIKE func
ENTRY(stub_\func)
- CFI_STARTPROC
- DEFAULT_FRAME 0, 8 /* offset 8: return address */
SAVE_EXTRA_REGS 8
- jmp sys_\func
- CFI_ENDPROC
+ jmp sys_\func
END(stub_\func)
.endm
@@ -503,8 +422,6 @@ END(stub_\func)
FORK_LIKE vfork
ENTRY(stub_execve)
- CFI_STARTPROC
- DEFAULT_FRAME 0, 8
call sys_execve
return_from_execve:
testl %eax, %eax
@@ -514,11 +431,9 @@ return_from_execve:
1:
/* must use IRET code path (pt_regs->cs may have changed) */
addq $8, %rsp
- CFI_ADJUST_CFA_OFFSET -8
ZERO_EXTRA_REGS
- movq %rax,RAX(%rsp)
+ movq %rax, RAX(%rsp)
jmp int_ret_from_sys_call
- CFI_ENDPROC
END(stub_execve)
/*
* Remaining execve stubs are only 7 bytes long.
@@ -526,47 +441,25 @@ END(stub_execve)
*/
.align 8
GLOBAL(stub_execveat)
- CFI_STARTPROC
- DEFAULT_FRAME 0, 8
call sys_execveat
jmp return_from_execve
- CFI_ENDPROC
END(stub_execveat)
-#ifdef CONFIG_X86_X32_ABI
+#if defined(CONFIG_X86_X32_ABI) || defined(CONFIG_IA32_EMULATION)
.align 8
GLOBAL(stub_x32_execve)
- CFI_STARTPROC
- DEFAULT_FRAME 0, 8
- call compat_sys_execve
- jmp return_from_execve
- CFI_ENDPROC
-END(stub_x32_execve)
- .align 8
-GLOBAL(stub_x32_execveat)
- CFI_STARTPROC
- DEFAULT_FRAME 0, 8
- call compat_sys_execveat
- jmp return_from_execve
- CFI_ENDPROC
-END(stub_x32_execveat)
-#endif
-
-#ifdef CONFIG_IA32_EMULATION
- .align 8
GLOBAL(stub32_execve)
- CFI_STARTPROC
call compat_sys_execve
jmp return_from_execve
- CFI_ENDPROC
END(stub32_execve)
+END(stub_x32_execve)
.align 8
+GLOBAL(stub_x32_execveat)
GLOBAL(stub32_execveat)
- CFI_STARTPROC
call compat_sys_execveat
jmp return_from_execve
- CFI_ENDPROC
END(stub32_execveat)
+END(stub_x32_execveat)
#endif
/*
@@ -574,8 +467,6 @@ END(stub32_execveat)
* This cannot be done with SYSRET, so use the IRET return path instead.
*/
ENTRY(stub_rt_sigreturn)
- CFI_STARTPROC
- DEFAULT_FRAME 0, 8
/*
* SAVE_EXTRA_REGS result is not normally needed:
* sigreturn overwrites all pt_regs->GPREGS.
@@ -584,24 +475,19 @@ ENTRY(stub_rt_sigreturn)
* we SAVE_EXTRA_REGS here.
*/
SAVE_EXTRA_REGS 8
- call sys_rt_sigreturn
+ call sys_rt_sigreturn
return_from_stub:
addq $8, %rsp
- CFI_ADJUST_CFA_OFFSET -8
RESTORE_EXTRA_REGS
- movq %rax,RAX(%rsp)
- jmp int_ret_from_sys_call
- CFI_ENDPROC
+ movq %rax, RAX(%rsp)
+ jmp int_ret_from_sys_call
END(stub_rt_sigreturn)
#ifdef CONFIG_X86_X32_ABI
ENTRY(stub_x32_rt_sigreturn)
- CFI_STARTPROC
- DEFAULT_FRAME 0, 8
SAVE_EXTRA_REGS 8
- call sys32_x32_rt_sigreturn
- jmp return_from_stub
- CFI_ENDPROC
+ call sys32_x32_rt_sigreturn
+ jmp return_from_stub
END(stub_x32_rt_sigreturn)
#endif
@@ -611,36 +497,36 @@ END(stub_x32_rt_sigreturn)
* rdi: prev task we switched from
*/
ENTRY(ret_from_fork)
- DEFAULT_FRAME
- LOCK ; btr $TIF_FORK,TI_flags(%r8)
+ LOCK ; btr $TIF_FORK, TI_flags(%r8)
- pushq_cfi $0x0002
- popfq_cfi # reset kernel eflags
+ pushq $0x0002
+ popfq /* reset kernel eflags */
- call schedule_tail # rdi: 'prev' task parameter
+ call schedule_tail /* rdi: 'prev' task parameter */
RESTORE_EXTRA_REGS
- testl $3,CS(%rsp) # from kernel_thread?
+ testb $3, CS(%rsp) /* from kernel_thread? */
/*
* By the time we get here, we have no idea whether our pt_regs,
* ti flags, and ti status came from the 64-bit SYSCALL fast path,
- * the slow path, or one of the ia32entry paths.
+ * the slow path, or one of the 32-bit compat paths.
* Use IRET code path to return, since it can safely handle
* all of the above.
*/
jnz int_ret_from_sys_call
- /* We came from kernel_thread */
- /* nb: we depend on RESTORE_EXTRA_REGS above */
- movq %rbp, %rdi
- call *%rbx
- movl $0, RAX(%rsp)
+ /*
+ * We came from kernel_thread
+ * nb: we depend on RESTORE_EXTRA_REGS above
+ */
+ movq %rbp, %rdi
+ call *%rbx
+ movl $0, RAX(%rsp)
RESTORE_EXTRA_REGS
- jmp int_ret_from_sys_call
- CFI_ENDPROC
+ jmp int_ret_from_sys_call
END(ret_from_fork)
/*
@@ -649,16 +535,13 @@ END(ret_from_fork)
*/
.align 8
ENTRY(irq_entries_start)
- INTR_FRAME
vector=FIRST_EXTERNAL_VECTOR
.rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
- pushq_cfi $(~vector+0x80) /* Note: always in signed byte range */
+ pushq $(~vector+0x80) /* Note: always in signed byte range */
vector=vector+1
jmp common_interrupt
- CFI_ADJUST_CFA_OFFSET -8
.align 8
.endr
- CFI_ENDPROC
END(irq_entries_start)
/*
@@ -684,10 +567,10 @@ END(irq_entries_start)
/* this goes to 0(%rsp) for unwinder, not for saving the value: */
SAVE_EXTRA_REGS_RBP -RBP
- leaq -RBP(%rsp),%rdi /* arg1 for \func (pointer to pt_regs) */
+ leaq -RBP(%rsp), %rdi /* arg1 for \func (pointer to pt_regs) */
- testl $3, CS-RBP(%rsp)
- je 1f
+ testb $3, CS-RBP(%rsp)
+ jz 1f
SWAPGS
1:
/*
@@ -697,24 +580,14 @@ END(irq_entries_start)
* a little cheaper to use a separate counter in the PDA (short of
* moving irq_enter into assembly, which would be too much work)
*/
- movq %rsp, %rsi
- incl PER_CPU_VAR(irq_count)
- cmovzq PER_CPU_VAR(irq_stack_ptr),%rsp
- CFI_DEF_CFA_REGISTER rsi
- pushq %rsi
- /*
- * For debugger:
- * "CFA (Current Frame Address) is the value on stack + offset"
- */
- CFI_ESCAPE 0x0f /* DW_CFA_def_cfa_expression */, 6, \
- 0x77 /* DW_OP_breg7 (rsp) */, 0, \
- 0x06 /* DW_OP_deref */, \
- 0x08 /* DW_OP_const1u */, SIZEOF_PTREGS-RBP, \
- 0x22 /* DW_OP_plus */
+ movq %rsp, %rsi
+ incl PER_CPU_VAR(irq_count)
+ cmovzq PER_CPU_VAR(irq_stack_ptr), %rsp
+ pushq %rsi
/* We entered an interrupt context - irqs are off: */
TRACE_IRQS_OFF
- call \func
+ call \func
.endm
/*
@@ -723,42 +596,36 @@ END(irq_entries_start)
*/
.p2align CONFIG_X86_L1_CACHE_SHIFT
common_interrupt:
- XCPT_FRAME
ASM_CLAC
- addq $-0x80,(%rsp) /* Adjust vector to [-256,-1] range */
+ addq $-0x80, (%rsp) /* Adjust vector to [-256, -1] range */
interrupt do_IRQ
/* 0(%rsp): old RSP */
ret_from_intr:
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF
- decl PER_CPU_VAR(irq_count)
+ decl PER_CPU_VAR(irq_count)
/* Restore saved previous stack */
- popq %rsi
- CFI_DEF_CFA rsi,SIZEOF_PTREGS-RBP /* reg/off reset after def_cfa_expr */
+ popq %rsi
/* return code expects complete pt_regs - adjust rsp accordingly: */
- leaq -RBP(%rsi),%rsp
- CFI_DEF_CFA_REGISTER rsp
- CFI_ADJUST_CFA_OFFSET RBP
+ leaq -RBP(%rsi), %rsp
- testl $3,CS(%rsp)
- je retint_kernel
+ testb $3, CS(%rsp)
+ jz retint_kernel
/* Interrupt came from user space */
-
+retint_user:
GET_THREAD_INFO(%rcx)
- /*
- * %rcx: thread info. Interrupts off.
- */
+
+ /* %rcx: thread info. Interrupts are off. */
retint_with_reschedule:
- movl $_TIF_WORK_MASK,%edi
+ movl $_TIF_WORK_MASK, %edi
retint_check:
LOCKDEP_SYS_EXIT_IRQ
- movl TI_flags(%rcx),%edx
- andl %edi,%edx
- CFI_REMEMBER_STATE
- jnz retint_careful
+ movl TI_flags(%rcx), %edx
+ andl %edi, %edx
+ jnz retint_careful
-retint_swapgs: /* return to user-space */
+retint_swapgs: /* return to user-space */
/*
* The iretq could re-enable interrupts:
*/
@@ -773,9 +640,9 @@ retint_kernel:
#ifdef CONFIG_PREEMPT
/* Interrupts are off */
/* Check if we need preemption */
- bt $9,EFLAGS(%rsp) /* interrupts were off? */
+ bt $9, EFLAGS(%rsp) /* were interrupts off? */
jnc 1f
-0: cmpl $0,PER_CPU_VAR(__preempt_count)
+0: cmpl $0, PER_CPU_VAR(__preempt_count)
jnz 1f
call preempt_schedule_irq
jmp 0b
@@ -793,8 +660,6 @@ retint_kernel:
restore_c_regs_and_iret:
RESTORE_C_REGS
REMOVE_PT_GPREGS_FROM_STACK 8
-
-irq_return:
INTERRUPT_RETURN
ENTRY(native_iret)
@@ -803,8 +668,8 @@ ENTRY(native_iret)
* 64-bit mode SS:RSP on the exception stack is always valid.
*/
#ifdef CONFIG_X86_ESPFIX64
- testb $4,(SS-RIP)(%rsp)
- jnz native_irq_return_ldt
+ testb $4, (SS-RIP)(%rsp)
+ jnz native_irq_return_ldt
#endif
.global native_irq_return_iret
@@ -819,62 +684,60 @@ native_irq_return_iret:
#ifdef CONFIG_X86_ESPFIX64
native_irq_return_ldt:
- pushq_cfi %rax
- pushq_cfi %rdi
+ pushq %rax
+ pushq %rdi
SWAPGS
- movq PER_CPU_VAR(espfix_waddr),%rdi
- movq %rax,(0*8)(%rdi) /* RAX */
- movq (2*8)(%rsp),%rax /* RIP */
- movq %rax,(1*8)(%rdi)
- movq (3*8)(%rsp),%rax /* CS */
- movq %rax,(2*8)(%rdi)
- movq (4*8)(%rsp),%rax /* RFLAGS */
- movq %rax,(3*8)(%rdi)
- movq (6*8)(%rsp),%rax /* SS */
- movq %rax,(5*8)(%rdi)
- movq (5*8)(%rsp),%rax /* RSP */
- movq %rax,(4*8)(%rdi)
- andl $0xffff0000,%eax
- popq_cfi %rdi
- orq PER_CPU_VAR(espfix_stack),%rax
+ movq PER_CPU_VAR(espfix_waddr), %rdi
+ movq %rax, (0*8)(%rdi) /* RAX */
+ movq (2*8)(%rsp), %rax /* RIP */
+ movq %rax, (1*8)(%rdi)
+ movq (3*8)(%rsp), %rax /* CS */
+ movq %rax, (2*8)(%rdi)
+ movq (4*8)(%rsp), %rax /* RFLAGS */
+ movq %rax, (3*8)(%rdi)
+ movq (6*8)(%rsp), %rax /* SS */
+ movq %rax, (5*8)(%rdi)
+ movq (5*8)(%rsp), %rax /* RSP */
+ movq %rax, (4*8)(%rdi)
+ andl $0xffff0000, %eax
+ popq %rdi
+ orq PER_CPU_VAR(espfix_stack), %rax
SWAPGS
- movq %rax,%rsp
- popq_cfi %rax
- jmp native_irq_return_iret
+ movq %rax, %rsp
+ popq %rax
+ jmp native_irq_return_iret
#endif
/* edi: workmask, edx: work */
retint_careful:
- CFI_RESTORE_STATE
- bt $TIF_NEED_RESCHED,%edx
- jnc retint_signal
+ bt $TIF_NEED_RESCHED, %edx
+ jnc retint_signal
TRACE_IRQS_ON
ENABLE_INTERRUPTS(CLBR_NONE)
- pushq_cfi %rdi
+ pushq %rdi
SCHEDULE_USER
- popq_cfi %rdi
+ popq %rdi
GET_THREAD_INFO(%rcx)
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF
- jmp retint_check
+ jmp retint_check
retint_signal:
- testl $_TIF_DO_NOTIFY_MASK,%edx
- jz retint_swapgs
+ testl $_TIF_DO_NOTIFY_MASK, %edx
+ jz retint_swapgs
TRACE_IRQS_ON
ENABLE_INTERRUPTS(CLBR_NONE)
SAVE_EXTRA_REGS
- movq $-1,ORIG_RAX(%rsp)
- xorl %esi,%esi # oldset
- movq %rsp,%rdi # &pt_regs
- call do_notify_resume
+ movq $-1, ORIG_RAX(%rsp)
+ xorl %esi, %esi /* oldset */
+ movq %rsp, %rdi /* &pt_regs */
+ call do_notify_resume
RESTORE_EXTRA_REGS
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF
GET_THREAD_INFO(%rcx)
- jmp retint_with_reschedule
+ jmp retint_with_reschedule
- CFI_ENDPROC
END(common_interrupt)
/*
@@ -882,13 +745,11 @@ END(common_interrupt)
*/
.macro apicinterrupt3 num sym do_sym
ENTRY(\sym)
- INTR_FRAME
ASM_CLAC
- pushq_cfi $~(\num)
+ pushq $~(\num)
.Lcommon_\sym:
interrupt \do_sym
- jmp ret_from_intr
- CFI_ENDPROC
+ jmp ret_from_intr
END(\sym)
.endm
@@ -910,53 +771,45 @@ trace_apicinterrupt \num \sym
.endm
#ifdef CONFIG_SMP
-apicinterrupt3 IRQ_MOVE_CLEANUP_VECTOR \
- irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt
-apicinterrupt3 REBOOT_VECTOR \
- reboot_interrupt smp_reboot_interrupt
+apicinterrupt3 IRQ_MOVE_CLEANUP_VECTOR irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt
+apicinterrupt3 REBOOT_VECTOR reboot_interrupt smp_reboot_interrupt
#endif
#ifdef CONFIG_X86_UV
-apicinterrupt3 UV_BAU_MESSAGE \
- uv_bau_message_intr1 uv_bau_message_interrupt
+apicinterrupt3 UV_BAU_MESSAGE uv_bau_message_intr1 uv_bau_message_interrupt
#endif
-apicinterrupt LOCAL_TIMER_VECTOR \
- apic_timer_interrupt smp_apic_timer_interrupt
-apicinterrupt X86_PLATFORM_IPI_VECTOR \
- x86_platform_ipi smp_x86_platform_ipi
+
+apicinterrupt LOCAL_TIMER_VECTOR apic_timer_interrupt smp_apic_timer_interrupt
+apicinterrupt X86_PLATFORM_IPI_VECTOR x86_platform_ipi smp_x86_platform_ipi
#ifdef CONFIG_HAVE_KVM
-apicinterrupt3 POSTED_INTR_VECTOR \
- kvm_posted_intr_ipi smp_kvm_posted_intr_ipi
+apicinterrupt3 POSTED_INTR_VECTOR kvm_posted_intr_ipi smp_kvm_posted_intr_ipi
+apicinterrupt3 POSTED_INTR_WAKEUP_VECTOR kvm_posted_intr_wakeup_ipi smp_kvm_posted_intr_wakeup_ipi
#endif
#ifdef CONFIG_X86_MCE_THRESHOLD
-apicinterrupt THRESHOLD_APIC_VECTOR \
- threshold_interrupt smp_threshold_interrupt
+apicinterrupt THRESHOLD_APIC_VECTOR threshold_interrupt smp_threshold_interrupt
+#endif
+
+#ifdef CONFIG_X86_MCE_AMD
+apicinterrupt DEFERRED_ERROR_VECTOR deferred_error_interrupt smp_deferred_error_interrupt
#endif
#ifdef CONFIG_X86_THERMAL_VECTOR
-apicinterrupt THERMAL_APIC_VECTOR \
- thermal_interrupt smp_thermal_interrupt
+apicinterrupt THERMAL_APIC_VECTOR thermal_interrupt smp_thermal_interrupt
#endif
#ifdef CONFIG_SMP
-apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \
- call_function_single_interrupt smp_call_function_single_interrupt
-apicinterrupt CALL_FUNCTION_VECTOR \
- call_function_interrupt smp_call_function_interrupt
-apicinterrupt RESCHEDULE_VECTOR \
- reschedule_interrupt smp_reschedule_interrupt
+apicinterrupt CALL_FUNCTION_SINGLE_VECTOR call_function_single_interrupt smp_call_function_single_interrupt
+apicinterrupt CALL_FUNCTION_VECTOR call_function_interrupt smp_call_function_interrupt
+apicinterrupt RESCHEDULE_VECTOR reschedule_interrupt smp_reschedule_interrupt
#endif
-apicinterrupt ERROR_APIC_VECTOR \
- error_interrupt smp_error_interrupt
-apicinterrupt SPURIOUS_APIC_VECTOR \
- spurious_interrupt smp_spurious_interrupt
+apicinterrupt ERROR_APIC_VECTOR error_interrupt smp_error_interrupt
+apicinterrupt SPURIOUS_APIC_VECTOR spurious_interrupt smp_spurious_interrupt
#ifdef CONFIG_IRQ_WORK
-apicinterrupt IRQ_WORK_VECTOR \
- irq_work_interrupt smp_irq_work_interrupt
+apicinterrupt IRQ_WORK_VECTOR irq_work_interrupt smp_irq_work_interrupt
#endif
/*
@@ -971,100 +824,87 @@ ENTRY(\sym)
.error "using shift_ist requires paranoid=1"
.endif
- .if \has_error_code
- XCPT_FRAME
- .else
- INTR_FRAME
- .endif
-
ASM_CLAC
PARAVIRT_ADJUST_EXCEPTION_FRAME
.ifeq \has_error_code
- pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */
+ pushq $-1 /* ORIG_RAX: no syscall to restart */
.endif
ALLOC_PT_GPREGS_ON_STACK
.if \paranoid
.if \paranoid == 1
- CFI_REMEMBER_STATE
- testl $3, CS(%rsp) /* If coming from userspace, switch */
- jnz 1f /* stacks. */
+ testb $3, CS(%rsp) /* If coming from userspace, switch stacks */
+ jnz 1f
.endif
- call paranoid_entry
+ call paranoid_entry
.else
- call error_entry
+ call error_entry
.endif
/* returned flag: ebx=0: need swapgs on exit, ebx=1: don't need it */
- DEFAULT_FRAME 0
-
.if \paranoid
.if \shift_ist != -1
- TRACE_IRQS_OFF_DEBUG /* reload IDT in case of recursion */
+ TRACE_IRQS_OFF_DEBUG /* reload IDT in case of recursion */
.else
TRACE_IRQS_OFF
.endif
.endif
- movq %rsp,%rdi /* pt_regs pointer */
+ movq %rsp, %rdi /* pt_regs pointer */
.if \has_error_code
- movq ORIG_RAX(%rsp),%rsi /* get error code */
- movq $-1,ORIG_RAX(%rsp) /* no syscall to restart */
+ movq ORIG_RAX(%rsp), %rsi /* get error code */
+ movq $-1, ORIG_RAX(%rsp) /* no syscall to restart */
.else
- xorl %esi,%esi /* no error code */
+ xorl %esi, %esi /* no error code */
.endif
.if \shift_ist != -1
- subq $EXCEPTION_STKSZ, CPU_TSS_IST(\shift_ist)
+ subq $EXCEPTION_STKSZ, CPU_TSS_IST(\shift_ist)
.endif
- call \do_sym
+ call \do_sym
.if \shift_ist != -1
- addq $EXCEPTION_STKSZ, CPU_TSS_IST(\shift_ist)
+ addq $EXCEPTION_STKSZ, CPU_TSS_IST(\shift_ist)
.endif
/* these procedures expect "no swapgs" flag in ebx */
.if \paranoid
- jmp paranoid_exit
+ jmp paranoid_exit
.else
- jmp error_exit
+ jmp error_exit
.endif
.if \paranoid == 1
- CFI_RESTORE_STATE
/*
* Paranoid entry from userspace. Switch stacks and treat it
* as a normal entry. This means that paranoid handlers
* run in real process context if user_mode(regs).
*/
1:
- call error_entry
+ call error_entry
- DEFAULT_FRAME 0
- movq %rsp,%rdi /* pt_regs pointer */
- call sync_regs
- movq %rax,%rsp /* switch stack */
+ movq %rsp, %rdi /* pt_regs pointer */
+ call sync_regs
+ movq %rax, %rsp /* switch stack */
- movq %rsp,%rdi /* pt_regs pointer */
+ movq %rsp, %rdi /* pt_regs pointer */
.if \has_error_code
- movq ORIG_RAX(%rsp),%rsi /* get error code */
- movq $-1,ORIG_RAX(%rsp) /* no syscall to restart */
+ movq ORIG_RAX(%rsp), %rsi /* get error code */
+ movq $-1, ORIG_RAX(%rsp) /* no syscall to restart */
.else
- xorl %esi,%esi /* no error code */
+ xorl %esi, %esi /* no error code */
.endif
- call \do_sym
+ call \do_sym
- jmp error_exit /* %ebx: no swapgs flag */
+ jmp error_exit /* %ebx: no swapgs flag */
.endif
-
- CFI_ENDPROC
END(\sym)
.endm
@@ -1079,65 +919,58 @@ idtentry \sym \do_sym has_error_code=\has_error_code
.endm
#endif
-idtentry divide_error do_divide_error has_error_code=0
-idtentry overflow do_overflow has_error_code=0
-idtentry bounds do_bounds has_error_code=0
-idtentry invalid_op do_invalid_op has_error_code=0
-idtentry device_not_available do_device_not_available has_error_code=0
-idtentry double_fault do_double_fault has_error_code=1 paranoid=2
-idtentry coprocessor_segment_overrun do_coprocessor_segment_overrun has_error_code=0
-idtentry invalid_TSS do_invalid_TSS has_error_code=1
-idtentry segment_not_present do_segment_not_present has_error_code=1
-idtentry spurious_interrupt_bug do_spurious_interrupt_bug has_error_code=0
-idtentry coprocessor_error do_coprocessor_error has_error_code=0
-idtentry alignment_check do_alignment_check has_error_code=1
-idtentry simd_coprocessor_error do_simd_coprocessor_error has_error_code=0
-
-
- /* Reload gs selector with exception handling */
- /* edi: new selector */
+idtentry divide_error do_divide_error has_error_code=0
+idtentry overflow do_overflow has_error_code=0
+idtentry bounds do_bounds has_error_code=0
+idtentry invalid_op do_invalid_op has_error_code=0
+idtentry device_not_available do_device_not_available has_error_code=0
+idtentry double_fault do_double_fault has_error_code=1 paranoid=2
+idtentry coprocessor_segment_overrun do_coprocessor_segment_overrun has_error_code=0
+idtentry invalid_TSS do_invalid_TSS has_error_code=1
+idtentry segment_not_present do_segment_not_present has_error_code=1
+idtentry spurious_interrupt_bug do_spurious_interrupt_bug has_error_code=0
+idtentry coprocessor_error do_coprocessor_error has_error_code=0
+idtentry alignment_check do_alignment_check has_error_code=1
+idtentry simd_coprocessor_error do_simd_coprocessor_error has_error_code=0
+
+
+ /*
+ * Reload gs selector with exception handling
+ * edi: new selector
+ */
ENTRY(native_load_gs_index)
- CFI_STARTPROC
- pushfq_cfi
+ pushfq
DISABLE_INTERRUPTS(CLBR_ANY & ~CLBR_RDI)
SWAPGS
gs_change:
- movl %edi,%gs
-2: mfence /* workaround */
+ movl %edi, %gs
+2: mfence /* workaround */
SWAPGS
- popfq_cfi
+ popfq
ret
- CFI_ENDPROC
END(native_load_gs_index)
- _ASM_EXTABLE(gs_change,bad_gs)
- .section .fixup,"ax"
+ _ASM_EXTABLE(gs_change, bad_gs)
+ .section .fixup, "ax"
/* running with kernelgs */
bad_gs:
- SWAPGS /* switch back to user gs */
- xorl %eax,%eax
- movl %eax,%gs
- jmp 2b
+ SWAPGS /* switch back to user gs */
+ xorl %eax, %eax
+ movl %eax, %gs
+ jmp 2b
.previous
/* Call softirq on interrupt stack. Interrupts are off. */
ENTRY(do_softirq_own_stack)
- CFI_STARTPROC
- pushq_cfi %rbp
- CFI_REL_OFFSET rbp,0
- mov %rsp,%rbp
- CFI_DEF_CFA_REGISTER rbp
- incl PER_CPU_VAR(irq_count)
- cmove PER_CPU_VAR(irq_stack_ptr),%rsp
- push %rbp # backlink for old unwinder
- call __do_softirq
+ pushq %rbp
+ mov %rsp, %rbp
+ incl PER_CPU_VAR(irq_count)
+ cmove PER_CPU_VAR(irq_stack_ptr), %rsp
+ push %rbp /* frame pointer backlink */
+ call __do_softirq
leaveq
- CFI_RESTORE rbp
- CFI_DEF_CFA_REGISTER rsp
- CFI_ADJUST_CFA_OFFSET -8
- decl PER_CPU_VAR(irq_count)
+ decl PER_CPU_VAR(irq_count)
ret
- CFI_ENDPROC
END(do_softirq_own_stack)
#ifdef CONFIG_XEN
@@ -1156,29 +989,24 @@ idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0
* existing activation in its critical region -- if so, we pop the current
* activation and restart the handler using the previous one.
*/
-ENTRY(xen_do_hypervisor_callback) # do_hypervisor_callback(struct *pt_regs)
- CFI_STARTPROC
+ENTRY(xen_do_hypervisor_callback) /* do_hypervisor_callback(struct *pt_regs) */
+
/*
* Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will
* see the correct pointer to the pt_regs
*/
- movq %rdi, %rsp # we don't return, adjust the stack frame
- CFI_ENDPROC
- DEFAULT_FRAME
-11: incl PER_CPU_VAR(irq_count)
- movq %rsp,%rbp
- CFI_DEF_CFA_REGISTER rbp
- cmovzq PER_CPU_VAR(irq_stack_ptr),%rsp
- pushq %rbp # backlink for old unwinder
- call xen_evtchn_do_upcall
- popq %rsp
- CFI_DEF_CFA_REGISTER rsp
- decl PER_CPU_VAR(irq_count)
+ movq %rdi, %rsp /* we don't return, adjust the stack frame */
+11: incl PER_CPU_VAR(irq_count)
+ movq %rsp, %rbp
+ cmovzq PER_CPU_VAR(irq_stack_ptr), %rsp
+ pushq %rbp /* frame pointer backlink */
+ call xen_evtchn_do_upcall
+ popq %rsp
+ decl PER_CPU_VAR(irq_count)
#ifndef CONFIG_PREEMPT
- call xen_maybe_preempt_hcall
+ call xen_maybe_preempt_hcall
#endif
- jmp error_exit
- CFI_ENDPROC
+ jmp error_exit
END(xen_do_hypervisor_callback)
/*
@@ -1195,51 +1023,35 @@ END(xen_do_hypervisor_callback)
* with its current contents: any discrepancy means we in category 1.
*/
ENTRY(xen_failsafe_callback)
- INTR_FRAME 1 (6*8)
- /*CFI_REL_OFFSET gs,GS*/
- /*CFI_REL_OFFSET fs,FS*/
- /*CFI_REL_OFFSET es,ES*/
- /*CFI_REL_OFFSET ds,DS*/
- CFI_REL_OFFSET r11,8
- CFI_REL_OFFSET rcx,0
- movw %ds,%cx
- cmpw %cx,0x10(%rsp)
- CFI_REMEMBER_STATE
- jne 1f
- movw %es,%cx
- cmpw %cx,0x18(%rsp)
- jne 1f
- movw %fs,%cx
- cmpw %cx,0x20(%rsp)
- jne 1f
- movw %gs,%cx
- cmpw %cx,0x28(%rsp)
- jne 1f
+ movl %ds, %ecx
+ cmpw %cx, 0x10(%rsp)
+ jne 1f
+ movl %es, %ecx
+ cmpw %cx, 0x18(%rsp)
+ jne 1f
+ movl %fs, %ecx
+ cmpw %cx, 0x20(%rsp)
+ jne 1f
+ movl %gs, %ecx
+ cmpw %cx, 0x28(%rsp)
+ jne 1f
/* All segments match their saved values => Category 2 (Bad IRET). */
- movq (%rsp),%rcx
- CFI_RESTORE rcx
- movq 8(%rsp),%r11
- CFI_RESTORE r11
- addq $0x30,%rsp
- CFI_ADJUST_CFA_OFFSET -0x30
- pushq_cfi $0 /* RIP */
- pushq_cfi %r11
- pushq_cfi %rcx
- jmp general_protection
- CFI_RESTORE_STATE
+ movq (%rsp), %rcx
+ movq 8(%rsp), %r11
+ addq $0x30, %rsp
+ pushq $0 /* RIP */
+ pushq %r11
+ pushq %rcx
+ jmp general_protection
1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */
- movq (%rsp),%rcx
- CFI_RESTORE rcx
- movq 8(%rsp),%r11
- CFI_RESTORE r11
- addq $0x30,%rsp
- CFI_ADJUST_CFA_OFFSET -0x30
- pushq_cfi $-1 /* orig_ax = -1 => not a system call */
+ movq (%rsp), %rcx
+ movq 8(%rsp), %r11
+ addq $0x30, %rsp
+ pushq $-1 /* orig_ax = -1 => not a system call */
ALLOC_PT_GPREGS_ON_STACK
SAVE_C_REGS
SAVE_EXTRA_REGS
- jmp error_exit
- CFI_ENDPROC
+ jmp error_exit
END(xen_failsafe_callback)
apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \
@@ -1252,21 +1064,25 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \
hyperv_callback_vector hyperv_vector_handler
#endif /* CONFIG_HYPERV */
-idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
-idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
-idtentry stack_segment do_stack_segment has_error_code=1
+idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
+idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
+idtentry stack_segment do_stack_segment has_error_code=1
+
#ifdef CONFIG_XEN
-idtentry xen_debug do_debug has_error_code=0
-idtentry xen_int3 do_int3 has_error_code=0
-idtentry xen_stack_segment do_stack_segment has_error_code=1
+idtentry xen_debug do_debug has_error_code=0
+idtentry xen_int3 do_int3 has_error_code=0
+idtentry xen_stack_segment do_stack_segment has_error_code=1
#endif
-idtentry general_protection do_general_protection has_error_code=1
-trace_idtentry page_fault do_page_fault has_error_code=1
+
+idtentry general_protection do_general_protection has_error_code=1
+trace_idtentry page_fault do_page_fault has_error_code=1
+
#ifdef CONFIG_KVM_GUEST
-idtentry async_page_fault do_async_page_fault has_error_code=1
+idtentry async_page_fault do_async_page_fault has_error_code=1
#endif
+
#ifdef CONFIG_X86_MCE
-idtentry machine_check has_error_code=0 paranoid=1 do_sym=*machine_check_vector(%rip)
+idtentry machine_check has_error_code=0 paranoid=1 do_sym=*machine_check_vector(%rip)
#endif
/*
@@ -1275,19 +1091,17 @@ idtentry machine_check has_error_code=0 paranoid=1 do_sym=*machine_check_vector(
* Return: ebx=0: need swapgs on exit, ebx=1: otherwise
*/
ENTRY(paranoid_entry)
- XCPT_FRAME 1 15*8
cld
SAVE_C_REGS 8
SAVE_EXTRA_REGS 8
- movl $1,%ebx
- movl $MSR_GS_BASE,%ecx
+ movl $1, %ebx
+ movl $MSR_GS_BASE, %ecx
rdmsr
- testl %edx,%edx
- js 1f /* negative -> in kernel */
+ testl %edx, %edx
+ js 1f /* negative -> in kernel */
SWAPGS
- xorl %ebx,%ebx
+ xorl %ebx, %ebx
1: ret
- CFI_ENDPROC
END(paranoid_entry)
/*
@@ -1299,17 +1113,17 @@ END(paranoid_entry)
* in syscall entry), so checking for preemption here would
* be complicated. Fortunately, we there's no good reason
* to try to handle preemption here.
+ *
+ * On entry, ebx is "no swapgs" flag (1: don't need swapgs, 0: need it)
*/
-/* On entry, ebx is "no swapgs" flag (1: don't need swapgs, 0: need it) */
ENTRY(paranoid_exit)
- DEFAULT_FRAME
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF_DEBUG
- testl %ebx,%ebx /* swapgs needed? */
- jnz paranoid_exit_no_swapgs
+ testl %ebx, %ebx /* swapgs needed? */
+ jnz paranoid_exit_no_swapgs
TRACE_IRQS_IRETQ
SWAPGS_UNSAFE_STACK
- jmp paranoid_exit_restore
+ jmp paranoid_exit_restore
paranoid_exit_no_swapgs:
TRACE_IRQS_IRETQ_DEBUG
paranoid_exit_restore:
@@ -1317,24 +1131,24 @@ paranoid_exit_restore:
RESTORE_C_REGS
REMOVE_PT_GPREGS_FROM_STACK 8
INTERRUPT_RETURN
- CFI_ENDPROC
END(paranoid_exit)
/*
* Save all registers in pt_regs, and switch gs if needed.
- * Return: ebx=0: need swapgs on exit, ebx=1: otherwise
+ * Return: EBX=0: came from user mode; EBX=1: otherwise
*/
ENTRY(error_entry)
- XCPT_FRAME 1 15*8
cld
SAVE_C_REGS 8
SAVE_EXTRA_REGS 8
- xorl %ebx,%ebx
- testl $3,CS+8(%rsp)
- je error_kernelspace
-error_swapgs:
+ xorl %ebx, %ebx
+ testb $3, CS+8(%rsp)
+ jz error_kernelspace
+
+ /* We entered from user mode */
SWAPGS
-error_sti:
+
+error_entry_done:
TRACE_IRQS_OFF
ret
@@ -1345,56 +1159,66 @@ error_sti:
* for these here too.
*/
error_kernelspace:
- CFI_REL_OFFSET rcx, RCX+8
- incl %ebx
- leaq native_irq_return_iret(%rip),%rcx
- cmpq %rcx,RIP+8(%rsp)
- je error_bad_iret
- movl %ecx,%eax /* zero extend */
- cmpq %rax,RIP+8(%rsp)
- je bstep_iret
- cmpq $gs_change,RIP+8(%rsp)
- je error_swapgs
- jmp error_sti
+ incl %ebx
+ leaq native_irq_return_iret(%rip), %rcx
+ cmpq %rcx, RIP+8(%rsp)
+ je error_bad_iret
+ movl %ecx, %eax /* zero extend */
+ cmpq %rax, RIP+8(%rsp)
+ je bstep_iret
+ cmpq $gs_change, RIP+8(%rsp)
+ jne error_entry_done
+
+ /*
+ * hack: gs_change can fail with user gsbase. If this happens, fix up
+ * gsbase and proceed. We'll fix up the exception and land in
+ * gs_change's error handler with kernel gsbase.
+ */
+ SWAPGS
+ jmp error_entry_done
bstep_iret:
/* Fix truncated RIP */
- movq %rcx,RIP+8(%rsp)
+ movq %rcx, RIP+8(%rsp)
/* fall through */
error_bad_iret:
+ /*
+ * We came from an IRET to user mode, so we have user gsbase.
+ * Switch to kernel gsbase:
+ */
SWAPGS
- mov %rsp,%rdi
- call fixup_bad_iret
- mov %rax,%rsp
- decl %ebx /* Return to usergs */
- jmp error_sti
- CFI_ENDPROC
+
+ /*
+ * Pretend that the exception came from user mode: set up pt_regs
+ * as if we faulted immediately after IRET and clear EBX so that
+ * error_exit knows that we will be returning to user mode.
+ */
+ mov %rsp, %rdi
+ call fixup_bad_iret
+ mov %rax, %rsp
+ decl %ebx
+ jmp error_entry_done
END(error_entry)
-/* On entry, ebx is "no swapgs" flag (1: don't need swapgs, 0: need it) */
+/*
+ * On entry, EBS is a "return to kernel mode" flag:
+ * 1: already in kernel mode, don't need SWAPGS
+ * 0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode
+ */
ENTRY(error_exit)
- DEFAULT_FRAME
- movl %ebx,%eax
+ movl %ebx, %eax
RESTORE_EXTRA_REGS
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF
- GET_THREAD_INFO(%rcx)
- testl %eax,%eax
- jne retint_kernel
- LOCKDEP_SYS_EXIT_IRQ
- movl TI_flags(%rcx),%edx
- movl $_TIF_WORK_MASK,%edi
- andl %edi,%edx
- jnz retint_careful
- jmp retint_swapgs
- CFI_ENDPROC
+ testl %eax, %eax
+ jnz retint_kernel
+ jmp retint_user
END(error_exit)
/* Runs on exception stack */
ENTRY(nmi)
- INTR_FRAME
PARAVIRT_ADJUST_EXCEPTION_FRAME
/*
* We allow breakpoints in NMIs. If a breakpoint occurs, then
@@ -1429,22 +1253,21 @@ ENTRY(nmi)
*/
/* Use %rdx as our temp variable throughout */
- pushq_cfi %rdx
- CFI_REL_OFFSET rdx, 0
+ pushq %rdx
/*
* If %cs was not the kernel segment, then the NMI triggered in user
* space, which means it is definitely not nested.
*/
- cmpl $__KERNEL_CS, 16(%rsp)
- jne first_nmi
+ cmpl $__KERNEL_CS, 16(%rsp)
+ jne first_nmi
/*
* Check the special variable on the stack to see if NMIs are
* executing.
*/
- cmpl $1, -8(%rsp)
- je nested_nmi
+ cmpl $1, -8(%rsp)
+ je nested_nmi
/*
* Now test if the previous stack was an NMI stack.
@@ -1458,51 +1281,46 @@ ENTRY(nmi)
cmpq %rdx, 4*8(%rsp)
/* If the stack pointer is above the NMI stack, this is a normal NMI */
ja first_nmi
+
subq $EXCEPTION_STKSZ, %rdx
cmpq %rdx, 4*8(%rsp)
/* If it is below the NMI stack, it is a normal NMI */
jb first_nmi
/* Ah, it is within the NMI stack, treat it as nested */
- CFI_REMEMBER_STATE
-
nested_nmi:
/*
* Do nothing if we interrupted the fixup in repeat_nmi.
* It's about to repeat the NMI handler, so we are fine
* with ignoring this one.
*/
- movq $repeat_nmi, %rdx
- cmpq 8(%rsp), %rdx
- ja 1f
- movq $end_repeat_nmi, %rdx
- cmpq 8(%rsp), %rdx
- ja nested_nmi_out
+ movq $repeat_nmi, %rdx
+ cmpq 8(%rsp), %rdx
+ ja 1f
+ movq $end_repeat_nmi, %rdx
+ cmpq 8(%rsp), %rdx
+ ja nested_nmi_out
1:
/* Set up the interrupted NMIs stack to jump to repeat_nmi */
- leaq -1*8(%rsp), %rdx
- movq %rdx, %rsp
- CFI_ADJUST_CFA_OFFSET 1*8
- leaq -10*8(%rsp), %rdx
- pushq_cfi $__KERNEL_DS
- pushq_cfi %rdx
- pushfq_cfi
- pushq_cfi $__KERNEL_CS
- pushq_cfi $repeat_nmi
+ leaq -1*8(%rsp), %rdx
+ movq %rdx, %rsp
+ leaq -10*8(%rsp), %rdx
+ pushq $__KERNEL_DS
+ pushq %rdx
+ pushfq
+ pushq $__KERNEL_CS
+ pushq $repeat_nmi
/* Put stack back */
- addq $(6*8), %rsp
- CFI_ADJUST_CFA_OFFSET -6*8
+ addq $(6*8), %rsp
nested_nmi_out:
- popq_cfi %rdx
- CFI_RESTORE rdx
+ popq %rdx
/* No need to check faults here */
INTERRUPT_RETURN
- CFI_RESTORE_STATE
first_nmi:
/*
* Because nested NMIs will use the pushed location that we
@@ -1540,23 +1358,18 @@ first_nmi:
* is also used by nested NMIs and can not be trusted on exit.
*/
/* Do not pop rdx, nested NMIs will corrupt that part of the stack */
- movq (%rsp), %rdx
- CFI_RESTORE rdx
+ movq (%rsp), %rdx
/* Set the NMI executing variable on the stack. */
- pushq_cfi $1
+ pushq $1
- /*
- * Leave room for the "copied" frame
- */
- subq $(5*8), %rsp
- CFI_ADJUST_CFA_OFFSET 5*8
+ /* Leave room for the "copied" frame */
+ subq $(5*8), %rsp
/* Copy the stack frame to the Saved frame */
.rept 5
- pushq_cfi 11*8(%rsp)
+ pushq 11*8(%rsp)
.endr
- CFI_DEF_CFA_OFFSET 5*8
/* Everything up to here is safe from nested NMIs */
@@ -1575,16 +1388,14 @@ repeat_nmi:
* is benign for the non-repeat case, where 1 was pushed just above
* to this very stack slot).
*/
- movq $1, 10*8(%rsp)
+ movq $1, 10*8(%rsp)
/* Make another copy, this one may be modified by nested NMIs */
- addq $(10*8), %rsp
- CFI_ADJUST_CFA_OFFSET -10*8
+ addq $(10*8), %rsp
.rept 5
- pushq_cfi -6*8(%rsp)
+ pushq -6*8(%rsp)
.endr
- subq $(5*8), %rsp
- CFI_DEF_CFA_OFFSET 5*8
+ subq $(5*8), %rsp
end_repeat_nmi:
/*
@@ -1592,7 +1403,7 @@ end_repeat_nmi:
* NMI if the first NMI took an exception and reset our iret stack
* so that we repeat another NMI.
*/
- pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */
+ pushq $-1 /* ORIG_RAX: no syscall to restart */
ALLOC_PT_GPREGS_ON_STACK
/*
@@ -1602,8 +1413,7 @@ end_repeat_nmi:
* setting NEED_RESCHED or anything that normal interrupts and
* exceptions might do.
*/
- call paranoid_entry
- DEFAULT_FRAME 0
+ call paranoid_entry
/*
* Save off the CR2 register. If we take a page fault in the NMI then
@@ -1614,22 +1424,21 @@ end_repeat_nmi:
* origin fault. Save it off and restore it if it changes.
* Use the r12 callee-saved register.
*/
- movq %cr2, %r12
+ movq %cr2, %r12
/* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
- movq %rsp,%rdi
- movq $-1,%rsi
- call do_nmi
+ movq %rsp, %rdi
+ movq $-1, %rsi
+ call do_nmi
/* Did the NMI take a page fault? Restore cr2 if it did */
- movq %cr2, %rcx
- cmpq %rcx, %r12
- je 1f
- movq %r12, %cr2
+ movq %cr2, %rcx
+ cmpq %rcx, %r12
+ je 1f
+ movq %r12, %cr2
1:
-
- testl %ebx,%ebx /* swapgs needed? */
- jnz nmi_restore
+ testl %ebx, %ebx /* swapgs needed? */
+ jnz nmi_restore
nmi_swapgs:
SWAPGS_UNSAFE_STACK
nmi_restore:
@@ -1639,15 +1448,11 @@ nmi_restore:
REMOVE_PT_GPREGS_FROM_STACK 6*8
/* Clear the NMI executing stack variable */
- movq $0, 5*8(%rsp)
- jmp irq_return
- CFI_ENDPROC
+ movq $0, 5*8(%rsp)
+ INTERRUPT_RETURN
END(nmi)
ENTRY(ignore_sysret)
- CFI_STARTPROC
- mov $-ENOSYS,%eax
+ mov $-ENOSYS, %eax
sysret
- CFI_ENDPROC
END(ignore_sysret)
-
diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S
new file mode 100644
index 000000000000..bb187a6a877c
--- /dev/null
+++ b/arch/x86/entry/entry_64_compat.S
@@ -0,0 +1,556 @@
+/*
+ * Compatibility mode system call entry point for x86-64.
+ *
+ * Copyright 2000-2002 Andi Kleen, SuSE Labs.
+ */
+#include "calling.h"
+#include <asm/asm-offsets.h>
+#include <asm/current.h>
+#include <asm/errno.h>
+#include <asm/ia32_unistd.h>
+#include <asm/thread_info.h>
+#include <asm/segment.h>
+#include <asm/irqflags.h>
+#include <asm/asm.h>
+#include <asm/smap.h>
+#include <linux/linkage.h>
+#include <linux/err.h>
+
+/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
+#include <linux/elf-em.h>
+#define AUDIT_ARCH_I386 (EM_386|__AUDIT_ARCH_LE)
+#define __AUDIT_ARCH_LE 0x40000000
+
+#ifndef CONFIG_AUDITSYSCALL
+# define sysexit_audit ia32_ret_from_sys_call
+# define sysretl_audit ia32_ret_from_sys_call
+#endif
+
+ .section .entry.text, "ax"
+
+#ifdef CONFIG_PARAVIRT
+ENTRY(native_usergs_sysret32)
+ swapgs
+ sysretl
+ENDPROC(native_usergs_sysret32)
+#endif
+
+/*
+ * 32-bit SYSENTER instruction entry.
+ *
+ * SYSENTER loads ss, rsp, cs, and rip from previously programmed MSRs.
+ * IF and VM in rflags are cleared (IOW: interrupts are off).
+ * SYSENTER does not save anything on the stack,
+ * and does not save old rip (!!!) and rflags.
+ *
+ * Arguments:
+ * eax system call number
+ * ebx arg1
+ * ecx arg2
+ * edx arg3
+ * esi arg4
+ * edi arg5
+ * ebp user stack
+ * 0(%ebp) arg6
+ *
+ * This is purely a fast path. For anything complicated we use the int 0x80
+ * path below. We set up a complete hardware stack frame to share code
+ * with the int 0x80 path.
+ */
+ENTRY(entry_SYSENTER_compat)
+ /*
+ * Interrupts are off on entry.
+ * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON,
+ * it is too small to ever cause noticeable irq latency.
+ */
+ SWAPGS_UNSAFE_STACK
+ movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
+ ENABLE_INTERRUPTS(CLBR_NONE)
+
+ /* Zero-extending 32-bit regs, do not remove */
+ movl %ebp, %ebp
+ movl %eax, %eax
+
+ movl ASM_THREAD_INFO(TI_sysenter_return, %rsp, 0), %r10d
+
+ /* Construct struct pt_regs on stack */
+ pushq $__USER32_DS /* pt_regs->ss */
+ pushq %rbp /* pt_regs->sp */
+ pushfq /* pt_regs->flags */
+ pushq $__USER32_CS /* pt_regs->cs */
+ pushq %r10 /* pt_regs->ip = thread_info->sysenter_return */
+ pushq %rax /* pt_regs->orig_ax */
+ pushq %rdi /* pt_regs->di */
+ pushq %rsi /* pt_regs->si */
+ pushq %rdx /* pt_regs->dx */
+ pushq %rcx /* pt_regs->cx */
+ pushq $-ENOSYS /* pt_regs->ax */
+ cld
+ sub $(10*8), %rsp /* pt_regs->r8-11, bp, bx, r12-15 not saved */
+
+ /*
+ * no need to do an access_ok check here because rbp has been
+ * 32-bit zero extended
+ */
+ ASM_STAC
+1: movl (%rbp), %ebp
+ _ASM_EXTABLE(1b, ia32_badarg)
+ ASM_CLAC
+
+ /*
+ * Sysenter doesn't filter flags, so we need to clear NT
+ * ourselves. To save a few cycles, we can check whether
+ * NT was set instead of doing an unconditional popfq.
+ */
+ testl $X86_EFLAGS_NT, EFLAGS(%rsp)
+ jnz sysenter_fix_flags
+sysenter_flags_fixed:
+
+ orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
+ testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
+ jnz sysenter_tracesys
+
+sysenter_do_call:
+ /* 32-bit syscall -> 64-bit C ABI argument conversion */
+ movl %edi, %r8d /* arg5 */
+ movl %ebp, %r9d /* arg6 */
+ xchg %ecx, %esi /* rsi:arg2, rcx:arg4 */
+ movl %ebx, %edi /* arg1 */
+ movl %edx, %edx /* arg3 (zero extension) */
+sysenter_dispatch:
+ cmpq $(IA32_NR_syscalls-1), %rax
+ ja 1f
+ call *ia32_sys_call_table(, %rax, 8)
+ movq %rax, RAX(%rsp)
+1:
+ DISABLE_INTERRUPTS(CLBR_NONE)
+ TRACE_IRQS_OFF
+ testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
+ jnz sysexit_audit
+sysexit_from_sys_call:
+ /*
+ * NB: SYSEXIT is not obviously safe for 64-bit kernels -- an
+ * NMI between STI and SYSEXIT has poorly specified behavior,
+ * and and NMI followed by an IRQ with usergs is fatal. So
+ * we just pretend we're using SYSEXIT but we really use
+ * SYSRETL instead.
+ *
+ * This code path is still called 'sysexit' because it pairs
+ * with 'sysenter' and it uses the SYSENTER calling convention.
+ */
+ andl $~TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
+ movl RIP(%rsp), %ecx /* User %eip */
+ RESTORE_RSI_RDI
+ xorl %edx, %edx /* Do not leak kernel information */
+ xorq %r8, %r8
+ xorq %r9, %r9
+ xorq %r10, %r10
+ movl EFLAGS(%rsp), %r11d /* User eflags */
+ TRACE_IRQS_ON
+
+ /*
+ * SYSRETL works even on Intel CPUs. Use it in preference to SYSEXIT,
+ * since it avoids a dicey window with interrupts enabled.
+ */
+ movl RSP(%rsp), %esp
+
+ /*
+ * USERGS_SYSRET32 does:
+ * gsbase = user's gs base
+ * eip = ecx
+ * rflags = r11
+ * cs = __USER32_CS
+ * ss = __USER_DS
+ *
+ * The prologue set RIP(%rsp) to VDSO32_SYSENTER_RETURN, which does:
+ *
+ * pop %ebp
+ * pop %edx
+ * pop %ecx
+ *
+ * Therefore, we invoke SYSRETL with EDX and R8-R10 zeroed to
+ * avoid info leaks. R11 ends up with VDSO32_SYSENTER_RETURN's
+ * address (already known to user code), and R12-R15 are
+ * callee-saved and therefore don't contain any interesting
+ * kernel data.
+ */
+ USERGS_SYSRET32
+
+#ifdef CONFIG_AUDITSYSCALL
+ .macro auditsys_entry_common
+ /*
+ * At this point, registers hold syscall args in the 32-bit syscall ABI:
+ * EAX is syscall number, the 6 args are in EBX,ECX,EDX,ESI,EDI,EBP.
+ *
+ * We want to pass them to __audit_syscall_entry(), which is a 64-bit
+ * C function with 5 parameters, so shuffle them to match what
+ * the function expects: RDI,RSI,RDX,RCX,R8.
+ */
+ movl %esi, %r8d /* arg5 (R8 ) <= 4th syscall arg (ESI) */
+ xchg %ecx, %edx /* arg4 (RCX) <= 3rd syscall arg (EDX) */
+ /* arg3 (RDX) <= 2nd syscall arg (ECX) */
+ movl %ebx, %esi /* arg2 (RSI) <= 1st syscall arg (EBX) */
+ movl %eax, %edi /* arg1 (RDI) <= syscall number (EAX) */
+ call __audit_syscall_entry
+
+ /*
+ * We are going to jump back to the syscall dispatch code.
+ * Prepare syscall args as required by the 64-bit C ABI.
+ * Registers clobbered by __audit_syscall_entry() are
+ * loaded from pt_regs on stack:
+ */
+ movl ORIG_RAX(%rsp), %eax /* syscall number */
+ movl %ebx, %edi /* arg1 */
+ movl RCX(%rsp), %esi /* arg2 */
+ movl RDX(%rsp), %edx /* arg3 */
+ movl RSI(%rsp), %ecx /* arg4 */
+ movl RDI(%rsp), %r8d /* arg5 */
+ movl %ebp, %r9d /* arg6 */
+ .endm
+
+ .macro auditsys_exit exit
+ testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
+ jnz ia32_ret_from_sys_call
+ TRACE_IRQS_ON
+ ENABLE_INTERRUPTS(CLBR_NONE)
+ movl %eax, %esi /* second arg, syscall return value */
+ cmpl $-MAX_ERRNO, %eax /* is it an error ? */
+ jbe 1f
+ movslq %eax, %rsi /* if error sign extend to 64 bits */
+1: setbe %al /* 1 if error, 0 if not */
+ movzbl %al, %edi /* zero-extend that into %edi */
+ call __audit_syscall_exit
+ movq RAX(%rsp), %rax /* reload syscall return value */
+ movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %edi
+ DISABLE_INTERRUPTS(CLBR_NONE)
+ TRACE_IRQS_OFF
+ testl %edi, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
+ jz \exit
+ xorl %eax, %eax /* Do not leak kernel information */
+ movq %rax, R11(%rsp)
+ movq %rax, R10(%rsp)
+ movq %rax, R9(%rsp)
+ movq %rax, R8(%rsp)
+ jmp int_with_check
+ .endm
+
+sysenter_auditsys:
+ auditsys_entry_common
+ jmp sysenter_dispatch
+
+sysexit_audit:
+ auditsys_exit sysexit_from_sys_call
+#endif
+
+sysenter_fix_flags:
+ pushq $(X86_EFLAGS_IF|X86_EFLAGS_FIXED)
+ popfq
+ jmp sysenter_flags_fixed
+
+sysenter_tracesys:
+#ifdef CONFIG_AUDITSYSCALL
+ testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
+ jz sysenter_auditsys
+#endif
+ SAVE_EXTRA_REGS
+ xorl %eax, %eax /* Do not leak kernel information */
+ movq %rax, R11(%rsp)
+ movq %rax, R10(%rsp)
+ movq %rax, R9(%rsp)
+ movq %rax, R8(%rsp)
+ movq %rsp, %rdi /* &pt_regs -> arg1 */
+ call syscall_trace_enter
+
+ /* Reload arg registers from stack. (see sysenter_tracesys) */
+ movl RCX(%rsp), %ecx
+ movl RDX(%rsp), %edx
+ movl RSI(%rsp), %esi
+ movl RDI(%rsp), %edi
+ movl %eax, %eax /* zero extension */
+
+ RESTORE_EXTRA_REGS
+ jmp sysenter_do_call
+ENDPROC(entry_SYSENTER_compat)
+
+/*
+ * 32-bit SYSCALL instruction entry.
+ *
+ * 32-bit SYSCALL saves rip to rcx, clears rflags.RF, then saves rflags to r11,
+ * then loads new ss, cs, and rip from previously programmed MSRs.
+ * rflags gets masked by a value from another MSR (so CLD and CLAC
+ * are not needed). SYSCALL does not save anything on the stack
+ * and does not change rsp.
+ *
+ * Note: rflags saving+masking-with-MSR happens only in Long mode
+ * (in legacy 32-bit mode, IF, RF and VM bits are cleared and that's it).
+ * Don't get confused: rflags saving+masking depends on Long Mode Active bit
+ * (EFER.LMA=1), NOT on bitness of userspace where SYSCALL executes
+ * or target CS descriptor's L bit (SYSCALL does not read segment descriptors).
+ *
+ * Arguments:
+ * eax system call number
+ * ecx return address
+ * ebx arg1
+ * ebp arg2 (note: not saved in the stack frame, should not be touched)
+ * edx arg3
+ * esi arg4
+ * edi arg5
+ * esp user stack
+ * 0(%esp) arg6
+ *
+ * This is purely a fast path. For anything complicated we use the int 0x80
+ * path below. We set up a complete hardware stack frame to share code
+ * with the int 0x80 path.
+ */
+ENTRY(entry_SYSCALL_compat)
+ /*
+ * Interrupts are off on entry.
+ * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON,
+ * it is too small to ever cause noticeable irq latency.
+ */
+ SWAPGS_UNSAFE_STACK
+ movl %esp, %r8d
+ movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
+ ENABLE_INTERRUPTS(CLBR_NONE)
+
+ /* Zero-extending 32-bit regs, do not remove */
+ movl %eax, %eax
+
+ /* Construct struct pt_regs on stack */
+ pushq $__USER32_DS /* pt_regs->ss */
+ pushq %r8 /* pt_regs->sp */
+ pushq %r11 /* pt_regs->flags */
+ pushq $__USER32_CS /* pt_regs->cs */
+ pushq %rcx /* pt_regs->ip */
+ pushq %rax /* pt_regs->orig_ax */
+ pushq %rdi /* pt_regs->di */
+ pushq %rsi /* pt_regs->si */
+ pushq %rdx /* pt_regs->dx */
+ pushq %rbp /* pt_regs->cx */
+ movl %ebp, %ecx
+ pushq $-ENOSYS /* pt_regs->ax */
+ sub $(10*8), %rsp /* pt_regs->r8-11, bp, bx, r12-15 not saved */
+
+ /*
+ * No need to do an access_ok check here because r8 has been
+ * 32-bit zero extended:
+ */
+ ASM_STAC
+1: movl (%r8), %ebp
+ _ASM_EXTABLE(1b, ia32_badarg)
+ ASM_CLAC
+ orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
+ testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
+ jnz cstar_tracesys
+
+cstar_do_call:
+ /* 32-bit syscall -> 64-bit C ABI argument conversion */
+ movl %edi, %r8d /* arg5 */
+ movl %ebp, %r9d /* arg6 */
+ xchg %ecx, %esi /* rsi:arg2, rcx:arg4 */
+ movl %ebx, %edi /* arg1 */
+ movl %edx, %edx /* arg3 (zero extension) */
+
+cstar_dispatch:
+ cmpq $(IA32_NR_syscalls-1), %rax
+ ja 1f
+
+ call *ia32_sys_call_table(, %rax, 8)
+ movq %rax, RAX(%rsp)
+1:
+ movl RCX(%rsp), %ebp
+ DISABLE_INTERRUPTS(CLBR_NONE)
+ TRACE_IRQS_OFF
+ testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
+ jnz sysretl_audit
+
+sysretl_from_sys_call:
+ andl $~TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
+ RESTORE_RSI_RDI_RDX
+ movl RIP(%rsp), %ecx
+ movl EFLAGS(%rsp), %r11d
+ xorq %r10, %r10
+ xorq %r9, %r9
+ xorq %r8, %r8
+ TRACE_IRQS_ON
+ movl RSP(%rsp), %esp
+ /*
+ * 64-bit->32-bit SYSRET restores eip from ecx,
+ * eflags from r11 (but RF and VM bits are forced to 0),
+ * cs and ss are loaded from MSRs.
+ * (Note: 32-bit->32-bit SYSRET is different: since r11
+ * does not exist, it merely sets eflags.IF=1).
+ *
+ * NB: On AMD CPUs with the X86_BUG_SYSRET_SS_ATTRS bug, the ss
+ * descriptor is not reinitialized. This means that we must
+ * avoid SYSRET with SS == NULL, which could happen if we schedule,
+ * exit the kernel, and re-enter using an interrupt vector. (All
+ * interrupt entries on x86_64 set SS to NULL.) We prevent that
+ * from happening by reloading SS in __switch_to.
+ */
+ USERGS_SYSRET32
+
+#ifdef CONFIG_AUDITSYSCALL
+cstar_auditsys:
+ auditsys_entry_common
+ jmp cstar_dispatch
+
+sysretl_audit:
+ auditsys_exit sysretl_from_sys_call
+#endif
+
+cstar_tracesys:
+#ifdef CONFIG_AUDITSYSCALL
+ testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
+ jz cstar_auditsys
+#endif
+ SAVE_EXTRA_REGS
+ xorl %eax, %eax /* Do not leak kernel information */
+ movq %rax, R11(%rsp)
+ movq %rax, R10(%rsp)
+ movq %rax, R9(%rsp)
+ movq %rax, R8(%rsp)
+ movq %rsp, %rdi /* &pt_regs -> arg1 */
+ call syscall_trace_enter
+
+ /* Reload arg registers from stack. (see sysenter_tracesys) */
+ movl RCX(%rsp), %ecx
+ movl RDX(%rsp), %edx
+ movl RSI(%rsp), %esi
+ movl RDI(%rsp), %edi
+ movl %eax, %eax /* zero extension */
+
+ RESTORE_EXTRA_REGS
+ jmp cstar_do_call
+END(entry_SYSCALL_compat)
+
+ia32_badarg:
+ ASM_CLAC
+ movq $-EFAULT, RAX(%rsp)
+ia32_ret_from_sys_call:
+ xorl %eax, %eax /* Do not leak kernel information */
+ movq %rax, R11(%rsp)
+ movq %rax, R10(%rsp)
+ movq %rax, R9(%rsp)
+ movq %rax, R8(%rsp)
+ jmp int_ret_from_sys_call
+
+/*
+ * Emulated IA32 system calls via int 0x80.
+ *
+ * Arguments:
+ * eax system call number
+ * ebx arg1
+ * ecx arg2
+ * edx arg3
+ * esi arg4
+ * edi arg5
+ * ebp arg6 (note: not saved in the stack frame, should not be touched)
+ *
+ * Notes:
+ * Uses the same stack frame as the x86-64 version.
+ * All registers except eax must be saved (but ptrace may violate that).
+ * Arguments are zero extended. For system calls that want sign extension and
+ * take long arguments a wrapper is needed. Most calls can just be called
+ * directly.
+ * Assumes it is only called from user space and entered with interrupts off.
+ */
+
+ENTRY(entry_INT80_compat)
+ /*
+ * Interrupts are off on entry.
+ * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON,
+ * it is too small to ever cause noticeable irq latency.
+ */
+ PARAVIRT_ADJUST_EXCEPTION_FRAME
+ SWAPGS
+ ENABLE_INTERRUPTS(CLBR_NONE)
+
+ /* Zero-extending 32-bit regs, do not remove */
+ movl %eax, %eax
+
+ /* Construct struct pt_regs on stack (iret frame is already on stack) */
+ pushq %rax /* pt_regs->orig_ax */
+ pushq %rdi /* pt_regs->di */
+ pushq %rsi /* pt_regs->si */
+ pushq %rdx /* pt_regs->dx */
+ pushq %rcx /* pt_regs->cx */
+ pushq $-ENOSYS /* pt_regs->ax */
+ pushq $0 /* pt_regs->r8 */
+ pushq $0 /* pt_regs->r9 */
+ pushq $0 /* pt_regs->r10 */
+ pushq $0 /* pt_regs->r11 */
+ cld
+ sub $(6*8), %rsp /* pt_regs->bp, bx, r12-15 not saved */
+
+ orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
+ testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
+ jnz ia32_tracesys
+
+ia32_do_call:
+ /* 32-bit syscall -> 64-bit C ABI argument conversion */
+ movl %edi, %r8d /* arg5 */
+ movl %ebp, %r9d /* arg6 */
+ xchg %ecx, %esi /* rsi:arg2, rcx:arg4 */
+ movl %ebx, %edi /* arg1 */
+ movl %edx, %edx /* arg3 (zero extension) */
+ cmpq $(IA32_NR_syscalls-1), %rax
+ ja 1f
+
+ call *ia32_sys_call_table(, %rax, 8)
+ movq %rax, RAX(%rsp)
+1:
+ jmp int_ret_from_sys_call
+
+ia32_tracesys:
+ SAVE_EXTRA_REGS
+ movq %rsp, %rdi /* &pt_regs -> arg1 */
+ call syscall_trace_enter
+ /*
+ * Reload arg registers from stack in case ptrace changed them.
+ * Don't reload %eax because syscall_trace_enter() returned
+ * the %rax value we should see. But do truncate it to 32 bits.
+ * If it's -1 to make us punt the syscall, then (u32)-1 is still
+ * an appropriately invalid value.
+ */
+ movl RCX(%rsp), %ecx
+ movl RDX(%rsp), %edx
+ movl RSI(%rsp), %esi
+ movl RDI(%rsp), %edi
+ movl %eax, %eax /* zero extension */
+ RESTORE_EXTRA_REGS
+ jmp ia32_do_call
+END(entry_INT80_compat)
+
+ .macro PTREGSCALL label, func
+ ALIGN
+GLOBAL(\label)
+ leaq \func(%rip), %rax
+ jmp ia32_ptregs_common
+ .endm
+
+ PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn
+ PTREGSCALL stub32_sigreturn, sys32_sigreturn
+ PTREGSCALL stub32_fork, sys_fork
+ PTREGSCALL stub32_vfork, sys_vfork
+
+ ALIGN
+GLOBAL(stub32_clone)
+ leaq sys_clone(%rip), %rax
+ /*
+ * The 32-bit clone ABI is: clone(..., int tls_val, int *child_tidptr).
+ * The 64-bit clone ABI is: clone(..., int *child_tidptr, int tls_val).
+ *
+ * The native 64-bit kernel's sys_clone() implements the latter,
+ * so we need to swap arguments here before calling it:
+ */
+ xchg %r8, %rcx
+ jmp ia32_ptregs_common
+
+ ALIGN
+ia32_ptregs_common:
+ SAVE_EXTRA_REGS 8
+ call *%rax
+ RESTORE_EXTRA_REGS 8
+ ret
+END(ia32_ptregs_common)
diff --git a/arch/x86/kernel/syscall_32.c b/arch/x86/entry/syscall_32.c
index 3777189c4a19..8ea34f94e973 100644
--- a/arch/x86/kernel/syscall_32.c
+++ b/arch/x86/entry/syscall_32.c
@@ -10,7 +10,7 @@
#else
#define SYM(sym, compat) sym
#define ia32_sys_call_table sys_call_table
-#define __NR_ia32_syscall_max __NR_syscall_max
+#define __NR_syscall_compat_max __NR_syscall_max
#endif
#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void SYM(sym, compat)(void) ;
@@ -23,11 +23,11 @@ typedef asmlinkage void (*sys_call_ptr_t)(void);
extern asmlinkage void sys_ni_syscall(void);
-__visible const sys_call_ptr_t ia32_sys_call_table[__NR_ia32_syscall_max+1] = {
+__visible const sys_call_ptr_t ia32_sys_call_table[__NR_syscall_compat_max+1] = {
/*
* Smells like a compiler bug -- it doesn't work
* when the & below is removed.
*/
- [0 ... __NR_ia32_syscall_max] = &sys_ni_syscall,
+ [0 ... __NR_syscall_compat_max] = &sys_ni_syscall,
#include <asm/syscalls_32.h>
};
diff --git a/arch/x86/kernel/syscall_64.c b/arch/x86/entry/syscall_64.c
index 4ac730b37f0b..4ac730b37f0b 100644
--- a/arch/x86/kernel/syscall_64.c
+++ b/arch/x86/entry/syscall_64.c
diff --git a/arch/x86/syscalls/Makefile b/arch/x86/entry/syscalls/Makefile
index a55abb9f6c5e..57aa59fd140c 100644
--- a/arch/x86/syscalls/Makefile
+++ b/arch/x86/entry/syscalls/Makefile
@@ -1,5 +1,5 @@
-out := $(obj)/../include/generated/asm
-uapi := $(obj)/../include/generated/uapi/asm
+out := $(obj)/../../include/generated/asm
+uapi := $(obj)/../../include/generated/uapi/asm
# Create output directory if not already present
_dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') \
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index ef8187f9d28d..ef8187f9d28d 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 9ef32d5f1b19..9ef32d5f1b19 100644
--- a/arch/x86/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
diff --git a/arch/x86/syscalls/syscallhdr.sh b/arch/x86/entry/syscalls/syscallhdr.sh
index 31fd5f1f38f7..31fd5f1f38f7 100644
--- a/arch/x86/syscalls/syscallhdr.sh
+++ b/arch/x86/entry/syscalls/syscallhdr.sh
diff --git a/arch/x86/syscalls/syscalltbl.sh b/arch/x86/entry/syscalls/syscalltbl.sh
index 0e7f8ec071e7..0e7f8ec071e7 100644
--- a/arch/x86/syscalls/syscalltbl.sh
+++ b/arch/x86/entry/syscalls/syscalltbl.sh
diff --git a/arch/x86/lib/thunk_32.S b/arch/x86/entry/thunk_32.S
index 5eb715087b80..e5a17114a8c4 100644
--- a/arch/x86/lib/thunk_32.S
+++ b/arch/x86/entry/thunk_32.S
@@ -6,16 +6,14 @@
*/
#include <linux/linkage.h>
#include <asm/asm.h>
- #include <asm/dwarf2.h>
/* put return address in eax (arg1) */
.macro THUNK name, func, put_ret_addr_in_eax=0
.globl \name
\name:
- CFI_STARTPROC
- pushl_cfi_reg eax
- pushl_cfi_reg ecx
- pushl_cfi_reg edx
+ pushl %eax
+ pushl %ecx
+ pushl %edx
.if \put_ret_addr_in_eax
/* Place EIP in the arg1 */
@@ -23,11 +21,10 @@
.endif
call \func
- popl_cfi_reg edx
- popl_cfi_reg ecx
- popl_cfi_reg eax
+ popl %edx
+ popl %ecx
+ popl %eax
ret
- CFI_ENDPROC
_ASM_NOKPROBE(\name)
.endm
@@ -38,8 +35,6 @@
#ifdef CONFIG_PREEMPT
THUNK ___preempt_schedule, preempt_schedule
-#ifdef CONFIG_CONTEXT_TRACKING
- THUNK ___preempt_schedule_context, preempt_schedule_context
-#endif
+ THUNK ___preempt_schedule_notrace, preempt_schedule_notrace
#endif
diff --git a/arch/x86/lib/thunk_64.S b/arch/x86/entry/thunk_64.S
index f89ba4e93025..efb2b932b748 100644
--- a/arch/x86/lib/thunk_64.S
+++ b/arch/x86/entry/thunk_64.S
@@ -6,35 +6,32 @@
* Subject to the GNU public license, v.2. No warranty of any kind.
*/
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
-#include <asm/calling.h>
+#include "calling.h"
#include <asm/asm.h>
/* rdi: arg1 ... normal C conventions. rax is saved/restored. */
.macro THUNK name, func, put_ret_addr_in_rdi=0
.globl \name
\name:
- CFI_STARTPROC
/* this one pushes 9 elems, the next one would be %rIP */
- pushq_cfi_reg rdi
- pushq_cfi_reg rsi
- pushq_cfi_reg rdx
- pushq_cfi_reg rcx
- pushq_cfi_reg rax
- pushq_cfi_reg r8
- pushq_cfi_reg r9
- pushq_cfi_reg r10
- pushq_cfi_reg r11
+ pushq %rdi
+ pushq %rsi
+ pushq %rdx
+ pushq %rcx
+ pushq %rax
+ pushq %r8
+ pushq %r9
+ pushq %r10
+ pushq %r11
.if \put_ret_addr_in_rdi
/* 9*8(%rsp) is return addr on stack */
- movq_cfi_restore 9*8, rdi
+ movq 9*8(%rsp), %rdi
.endif
call \func
jmp restore
- CFI_ENDPROC
_ASM_NOKPROBE(\name)
.endm
@@ -49,27 +46,22 @@
#ifdef CONFIG_PREEMPT
THUNK ___preempt_schedule, preempt_schedule
-#ifdef CONFIG_CONTEXT_TRACKING
- THUNK ___preempt_schedule_context, preempt_schedule_context
-#endif
+ THUNK ___preempt_schedule_notrace, preempt_schedule_notrace
#endif
#if defined(CONFIG_TRACE_IRQFLAGS) \
|| defined(CONFIG_DEBUG_LOCK_ALLOC) \
|| defined(CONFIG_PREEMPT)
- CFI_STARTPROC
- CFI_ADJUST_CFA_OFFSET 9*8
restore:
- popq_cfi_reg r11
- popq_cfi_reg r10
- popq_cfi_reg r9
- popq_cfi_reg r8
- popq_cfi_reg rax
- popq_cfi_reg rcx
- popq_cfi_reg rdx
- popq_cfi_reg rsi
- popq_cfi_reg rdi
+ popq %r11
+ popq %r10
+ popq %r9
+ popq %r8
+ popq %rax
+ popq %rcx
+ popq %rdx
+ popq %rsi
+ popq %rdi
ret
- CFI_ENDPROC
_ASM_NOKPROBE(restore)
#endif
diff --git a/arch/x86/vdso/.gitignore b/arch/x86/entry/vdso/.gitignore
index aae8ffdd5880..aae8ffdd5880 100644
--- a/arch/x86/vdso/.gitignore
+++ b/arch/x86/entry/vdso/.gitignore
diff --git a/arch/x86/vdso/Makefile b/arch/x86/entry/vdso/Makefile
index e97032069f88..e97032069f88 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/entry/vdso/Makefile
diff --git a/arch/x86/vdso/checkundef.sh b/arch/x86/entry/vdso/checkundef.sh
index 7ee90a9b549d..7ee90a9b549d 100755
--- a/arch/x86/vdso/checkundef.sh
+++ b/arch/x86/entry/vdso/checkundef.sh
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c
index 9793322751e0..9793322751e0 100644
--- a/arch/x86/vdso/vclock_gettime.c
+++ b/arch/x86/entry/vdso/vclock_gettime.c
diff --git a/arch/x86/vdso/vdso-layout.lds.S b/arch/x86/entry/vdso/vdso-layout.lds.S
index de2c921025f5..de2c921025f5 100644
--- a/arch/x86/vdso/vdso-layout.lds.S
+++ b/arch/x86/entry/vdso/vdso-layout.lds.S
diff --git a/arch/x86/vdso/vdso-note.S b/arch/x86/entry/vdso/vdso-note.S
index 79a071e4357e..79a071e4357e 100644
--- a/arch/x86/vdso/vdso-note.S
+++ b/arch/x86/entry/vdso/vdso-note.S
diff --git a/arch/x86/vdso/vdso.lds.S b/arch/x86/entry/vdso/vdso.lds.S
index 6807932643c2..6807932643c2 100644
--- a/arch/x86/vdso/vdso.lds.S
+++ b/arch/x86/entry/vdso/vdso.lds.S
diff --git a/arch/x86/vdso/vdso2c.c b/arch/x86/entry/vdso/vdso2c.c
index 8627db24a7f6..8627db24a7f6 100644
--- a/arch/x86/vdso/vdso2c.c
+++ b/arch/x86/entry/vdso/vdso2c.c
diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/entry/vdso/vdso2c.h
index 0224987556ce..0224987556ce 100644
--- a/arch/x86/vdso/vdso2c.h
+++ b/arch/x86/entry/vdso/vdso2c.h
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/entry/vdso/vdso32-setup.c
index e904c270573b..e904c270573b 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/entry/vdso/vdso32-setup.c
diff --git a/arch/x86/vdso/vdso32/.gitignore b/arch/x86/entry/vdso/vdso32/.gitignore
index e45fba9d0ced..e45fba9d0ced 100644
--- a/arch/x86/vdso/vdso32/.gitignore
+++ b/arch/x86/entry/vdso/vdso32/.gitignore
diff --git a/arch/x86/vdso/vdso32/int80.S b/arch/x86/entry/vdso/vdso32/int80.S
index b15b7c01aedb..b15b7c01aedb 100644
--- a/arch/x86/vdso/vdso32/int80.S
+++ b/arch/x86/entry/vdso/vdso32/int80.S
diff --git a/arch/x86/vdso/vdso32/note.S b/arch/x86/entry/vdso/vdso32/note.S
index c83f25734696..c83f25734696 100644
--- a/arch/x86/vdso/vdso32/note.S
+++ b/arch/x86/entry/vdso/vdso32/note.S
diff --git a/arch/x86/vdso/vdso32/sigreturn.S b/arch/x86/entry/vdso/vdso32/sigreturn.S
index d7ec4e251c0a..d7ec4e251c0a 100644
--- a/arch/x86/vdso/vdso32/sigreturn.S
+++ b/arch/x86/entry/vdso/vdso32/sigreturn.S
diff --git a/arch/x86/vdso/vdso32/syscall.S b/arch/x86/entry/vdso/vdso32/syscall.S
index 6b286bb5251c..6b286bb5251c 100644
--- a/arch/x86/vdso/vdso32/syscall.S
+++ b/arch/x86/entry/vdso/vdso32/syscall.S
diff --git a/arch/x86/vdso/vdso32/sysenter.S b/arch/x86/entry/vdso/vdso32/sysenter.S
index e354bceee0e0..e354bceee0e0 100644
--- a/arch/x86/vdso/vdso32/sysenter.S
+++ b/arch/x86/entry/vdso/vdso32/sysenter.S
diff --git a/arch/x86/vdso/vdso32/vclock_gettime.c b/arch/x86/entry/vdso/vdso32/vclock_gettime.c
index 175cc72c0f68..175cc72c0f68 100644
--- a/arch/x86/vdso/vdso32/vclock_gettime.c
+++ b/arch/x86/entry/vdso/vdso32/vclock_gettime.c
diff --git a/arch/x86/vdso/vdso32/vdso-fakesections.c b/arch/x86/entry/vdso/vdso32/vdso-fakesections.c
index 541468e25265..541468e25265 100644
--- a/arch/x86/vdso/vdso32/vdso-fakesections.c
+++ b/arch/x86/entry/vdso/vdso32/vdso-fakesections.c
diff --git a/arch/x86/vdso/vdso32/vdso32.lds.S b/arch/x86/entry/vdso/vdso32/vdso32.lds.S
index 31056cf294bf..31056cf294bf 100644
--- a/arch/x86/vdso/vdso32/vdso32.lds.S
+++ b/arch/x86/entry/vdso/vdso32/vdso32.lds.S
diff --git a/arch/x86/vdso/vdsox32.lds.S b/arch/x86/entry/vdso/vdsox32.lds.S
index 697c11ece90c..697c11ece90c 100644
--- a/arch/x86/vdso/vdsox32.lds.S
+++ b/arch/x86/entry/vdso/vdsox32.lds.S
diff --git a/arch/x86/vdso/vgetcpu.c b/arch/x86/entry/vdso/vgetcpu.c
index 8ec3d1f4ce9a..8ec3d1f4ce9a 100644
--- a/arch/x86/vdso/vgetcpu.c
+++ b/arch/x86/entry/vdso/vgetcpu.c
diff --git a/arch/x86/vdso/vma.c b/arch/x86/entry/vdso/vma.c
index 1c9f750c3859..1c9f750c3859 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/entry/vdso/vma.c
diff --git a/arch/x86/entry/vsyscall/Makefile b/arch/x86/entry/vsyscall/Makefile
new file mode 100644
index 000000000000..a9f4856f622a
--- /dev/null
+++ b/arch/x86/entry/vsyscall/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the x86 low level vsyscall code
+#
+obj-y := vsyscall_gtod.o
+
+obj-$(CONFIG_X86_VSYSCALL_EMULATION) += vsyscall_64.o vsyscall_emu_64.o
+
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c
index 2dcc6ff6fdcc..2dcc6ff6fdcc 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/entry/vsyscall/vsyscall_64.c
diff --git a/arch/x86/kernel/vsyscall_emu_64.S b/arch/x86/entry/vsyscall/vsyscall_emu_64.S
index c9596a9af159..c9596a9af159 100644
--- a/arch/x86/kernel/vsyscall_emu_64.S
+++ b/arch/x86/entry/vsyscall/vsyscall_emu_64.S
diff --git a/arch/x86/kernel/vsyscall_gtod.c b/arch/x86/entry/vsyscall/vsyscall_gtod.c
index 51e330416995..51e330416995 100644
--- a/arch/x86/kernel/vsyscall_gtod.c
+++ b/arch/x86/entry/vsyscall/vsyscall_gtod.c
diff --git a/arch/x86/kernel/vsyscall_trace.h b/arch/x86/entry/vsyscall/vsyscall_trace.h
index a8b2edec54fe..9dd7359a38a8 100644
--- a/arch/x86/kernel/vsyscall_trace.h
+++ b/arch/x86/entry/vsyscall/vsyscall_trace.h
@@ -24,6 +24,6 @@ TRACE_EVENT(emulate_vsyscall,
#endif
#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH ../../arch/x86/kernel
+#define TRACE_INCLUDE_PATH ../../arch/x86/entry/vsyscall/
#define TRACE_INCLUDE_FILE vsyscall_trace
#include <trace/define_trace.h>
diff --git a/arch/x86/ia32/Makefile b/arch/x86/ia32/Makefile
index bb635c641869..cd4339bae066 100644
--- a/arch/x86/ia32/Makefile
+++ b/arch/x86/ia32/Makefile
@@ -2,7 +2,7 @@
# Makefile for the ia32 kernel emulation subsystem.
#
-obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_signal.o
+obj-$(CONFIG_IA32_EMULATION) := sys_ia32.o ia32_signal.o
obj-$(CONFIG_IA32_AOUT) += ia32_aout.o
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index c81d35e6c7f1..ae3a29ae875b 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -21,8 +21,8 @@
#include <linux/binfmts.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h>
+#include <asm/fpu/internal.h>
+#include <asm/fpu/signal.h>
#include <asm/ptrace.h>
#include <asm/ia32_unistd.h>
#include <asm/user32.h>
@@ -198,7 +198,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
buf = compat_ptr(tmp);
} get_user_catch(err);
- err |= restore_xstate_sig(buf, 1);
+ err |= fpu__restore_sig(buf, 1);
force_iret();
@@ -308,6 +308,7 @@ static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
size_t frame_size,
void __user **fpstate)
{
+ struct fpu *fpu = &current->thread.fpu;
unsigned long sp;
/* Default to using normal stack */
@@ -322,12 +323,12 @@ static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
ksig->ka.sa.sa_restorer)
sp = (unsigned long) ksig->ka.sa.sa_restorer;
- if (used_math()) {
+ if (fpu->fpstate_active) {
unsigned long fx_aligned, math_size;
- sp = alloc_mathframe(sp, 1, &fx_aligned, &math_size);
+ sp = fpu__alloc_mathframe(sp, 1, &fx_aligned, &math_size);
*fpstate = (struct _fpstate_ia32 __user *) sp;
- if (save_xstate_sig(*fpstate, (void __user *)fx_aligned,
+ if (copy_fpstate_to_sigframe(*fpstate, (void __user *)fx_aligned,
math_size) < 0)
return (void __user *) -1L;
}
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
deleted file mode 100644
index 72bf2680f819..000000000000
--- a/arch/x86/ia32/ia32entry.S
+++ /dev/null
@@ -1,611 +0,0 @@
-/*
- * Compatibility mode system call entry point for x86-64.
- *
- * Copyright 2000-2002 Andi Kleen, SuSE Labs.
- */
-
-#include <asm/dwarf2.h>
-#include <asm/calling.h>
-#include <asm/asm-offsets.h>
-#include <asm/current.h>
-#include <asm/errno.h>
-#include <asm/ia32_unistd.h>
-#include <asm/thread_info.h>
-#include <asm/segment.h>
-#include <asm/irqflags.h>
-#include <asm/asm.h>
-#include <asm/smap.h>
-#include <linux/linkage.h>
-#include <linux/err.h>
-
-/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
-#include <linux/elf-em.h>
-#define AUDIT_ARCH_I386 (EM_386|__AUDIT_ARCH_LE)
-#define __AUDIT_ARCH_LE 0x40000000
-
-#ifndef CONFIG_AUDITSYSCALL
-#define sysexit_audit ia32_ret_from_sys_call
-#define sysretl_audit ia32_ret_from_sys_call
-#endif
-
- .section .entry.text, "ax"
-
- /* clobbers %rax */
- .macro CLEAR_RREGS _r9=rax
- xorl %eax,%eax
- movq %rax,R11(%rsp)
- movq %rax,R10(%rsp)
- movq %\_r9,R9(%rsp)
- movq %rax,R8(%rsp)
- .endm
-
- /*
- * Reload arg registers from stack in case ptrace changed them.
- * We don't reload %eax because syscall_trace_enter() returned
- * the %rax value we should see. Instead, we just truncate that
- * value to 32 bits again as we did on entry from user mode.
- * If it's a new value set by user_regset during entry tracing,
- * this matches the normal truncation of the user-mode value.
- * If it's -1 to make us punt the syscall, then (u32)-1 is still
- * an appropriately invalid value.
- */
- .macro LOAD_ARGS32 _r9=0
- .if \_r9
- movl R9(%rsp),%r9d
- .endif
- movl RCX(%rsp),%ecx
- movl RDX(%rsp),%edx
- movl RSI(%rsp),%esi
- movl RDI(%rsp),%edi
- movl %eax,%eax /* zero extension */
- .endm
-
- .macro CFI_STARTPROC32 simple
- CFI_STARTPROC \simple
- CFI_UNDEFINED r8
- CFI_UNDEFINED r9
- CFI_UNDEFINED r10
- CFI_UNDEFINED r11
- CFI_UNDEFINED r12
- CFI_UNDEFINED r13
- CFI_UNDEFINED r14
- CFI_UNDEFINED r15
- .endm
-
-#ifdef CONFIG_PARAVIRT
-ENTRY(native_usergs_sysret32)
- swapgs
- sysretl
-ENDPROC(native_usergs_sysret32)
-
-ENTRY(native_irq_enable_sysexit)
- swapgs
- sti
- sysexit
-ENDPROC(native_irq_enable_sysexit)
-#endif
-
-/*
- * 32bit SYSENTER instruction entry.
- *
- * SYSENTER loads ss, rsp, cs, and rip from previously programmed MSRs.
- * IF and VM in rflags are cleared (IOW: interrupts are off).
- * SYSENTER does not save anything on the stack,
- * and does not save old rip (!!!) and rflags.
- *
- * Arguments:
- * eax system call number
- * ebx arg1
- * ecx arg2
- * edx arg3
- * esi arg4
- * edi arg5
- * ebp user stack
- * 0(%ebp) arg6
- *
- * This is purely a fast path. For anything complicated we use the int 0x80
- * path below. We set up a complete hardware stack frame to share code
- * with the int 0x80 path.
- */
-ENTRY(ia32_sysenter_target)
- CFI_STARTPROC32 simple
- CFI_SIGNAL_FRAME
- CFI_DEF_CFA rsp,0
- CFI_REGISTER rsp,rbp
-
- /*
- * Interrupts are off on entry.
- * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON,
- * it is too small to ever cause noticeable irq latency.
- */
- SWAPGS_UNSAFE_STACK
- movq PER_CPU_VAR(cpu_tss + TSS_sp0), %rsp
- ENABLE_INTERRUPTS(CLBR_NONE)
-
- /* Zero-extending 32-bit regs, do not remove */
- movl %ebp, %ebp
- movl %eax, %eax
-
- movl ASM_THREAD_INFO(TI_sysenter_return, %rsp, 0), %r10d
- CFI_REGISTER rip,r10
-
- /* Construct struct pt_regs on stack */
- pushq_cfi $__USER32_DS /* pt_regs->ss */
- pushq_cfi %rbp /* pt_regs->sp */
- CFI_REL_OFFSET rsp,0
- pushfq_cfi /* pt_regs->flags */
- pushq_cfi $__USER32_CS /* pt_regs->cs */
- pushq_cfi %r10 /* pt_regs->ip = thread_info->sysenter_return */
- CFI_REL_OFFSET rip,0
- pushq_cfi_reg rax /* pt_regs->orig_ax */
- pushq_cfi_reg rdi /* pt_regs->di */
- pushq_cfi_reg rsi /* pt_regs->si */
- pushq_cfi_reg rdx /* pt_regs->dx */
- pushq_cfi_reg rcx /* pt_regs->cx */
- pushq_cfi_reg rax /* pt_regs->ax */
- cld
- sub $(10*8),%rsp /* pt_regs->r8-11,bp,bx,r12-15 not saved */
- CFI_ADJUST_CFA_OFFSET 10*8
-
- /*
- * no need to do an access_ok check here because rbp has been
- * 32bit zero extended
- */
- ASM_STAC
-1: movl (%rbp),%ebp
- _ASM_EXTABLE(1b,ia32_badarg)
- ASM_CLAC
-
- /*
- * Sysenter doesn't filter flags, so we need to clear NT
- * ourselves. To save a few cycles, we can check whether
- * NT was set instead of doing an unconditional popfq.
- */
- testl $X86_EFLAGS_NT,EFLAGS(%rsp)
- jnz sysenter_fix_flags
-sysenter_flags_fixed:
-
- orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
- testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
- CFI_REMEMBER_STATE
- jnz sysenter_tracesys
- cmpq $(IA32_NR_syscalls-1),%rax
- ja ia32_badsys
-sysenter_do_call:
- /* 32bit syscall -> 64bit C ABI argument conversion */
- movl %edi,%r8d /* arg5 */
- movl %ebp,%r9d /* arg6 */
- xchg %ecx,%esi /* rsi:arg2, rcx:arg4 */
- movl %ebx,%edi /* arg1 */
- movl %edx,%edx /* arg3 (zero extension) */
-sysenter_dispatch:
- call *ia32_sys_call_table(,%rax,8)
- movq %rax,RAX(%rsp)
- DISABLE_INTERRUPTS(CLBR_NONE)
- TRACE_IRQS_OFF
- testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
- jnz sysexit_audit
-sysexit_from_sys_call:
- /*
- * NB: SYSEXIT is not obviously safe for 64-bit kernels -- an
- * NMI between STI and SYSEXIT has poorly specified behavior,
- * and and NMI followed by an IRQ with usergs is fatal. So
- * we just pretend we're using SYSEXIT but we really use
- * SYSRETL instead.
- *
- * This code path is still called 'sysexit' because it pairs
- * with 'sysenter' and it uses the SYSENTER calling convention.
- */
- andl $~TS_COMPAT,ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
- movl RIP(%rsp),%ecx /* User %eip */
- CFI_REGISTER rip,rcx
- RESTORE_RSI_RDI
- xorl %edx,%edx /* avoid info leaks */
- xorq %r8,%r8
- xorq %r9,%r9
- xorq %r10,%r10
- movl EFLAGS(%rsp),%r11d /* User eflags */
- /*CFI_RESTORE rflags*/
- TRACE_IRQS_ON
-
- /*
- * SYSRETL works even on Intel CPUs. Use it in preference to SYSEXIT,
- * since it avoids a dicey window with interrupts enabled.
- */
- movl RSP(%rsp),%esp
-
- /*
- * USERGS_SYSRET32 does:
- * gsbase = user's gs base
- * eip = ecx
- * rflags = r11
- * cs = __USER32_CS
- * ss = __USER_DS
- *
- * The prologue set RIP(%rsp) to VDSO32_SYSENTER_RETURN, which does:
- *
- * pop %ebp
- * pop %edx
- * pop %ecx
- *
- * Therefore, we invoke SYSRETL with EDX and R8-R10 zeroed to
- * avoid info leaks. R11 ends up with VDSO32_SYSENTER_RETURN's
- * address (already known to user code), and R12-R15 are
- * callee-saved and therefore don't contain any interesting
- * kernel data.
- */
- USERGS_SYSRET32
-
- CFI_RESTORE_STATE
-
-#ifdef CONFIG_AUDITSYSCALL
- .macro auditsys_entry_common
- movl %esi,%r8d /* 5th arg: 4th syscall arg */
- movl %ecx,%r9d /*swap with edx*/
- movl %edx,%ecx /* 4th arg: 3rd syscall arg */
- movl %r9d,%edx /* 3rd arg: 2nd syscall arg */
- movl %ebx,%esi /* 2nd arg: 1st syscall arg */
- movl %eax,%edi /* 1st arg: syscall number */
- call __audit_syscall_entry
- movl RAX(%rsp),%eax /* reload syscall number */
- cmpq $(IA32_NR_syscalls-1),%rax
- ja ia32_badsys
- movl %ebx,%edi /* reload 1st syscall arg */
- movl RCX(%rsp),%esi /* reload 2nd syscall arg */
- movl RDX(%rsp),%edx /* reload 3rd syscall arg */
- movl RSI(%rsp),%ecx /* reload 4th syscall arg */
- movl RDI(%rsp),%r8d /* reload 5th syscall arg */
- .endm
-
- .macro auditsys_exit exit
- testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
- jnz ia32_ret_from_sys_call
- TRACE_IRQS_ON
- ENABLE_INTERRUPTS(CLBR_NONE)
- movl %eax,%esi /* second arg, syscall return value */
- cmpl $-MAX_ERRNO,%eax /* is it an error ? */
- jbe 1f
- movslq %eax, %rsi /* if error sign extend to 64 bits */
-1: setbe %al /* 1 if error, 0 if not */
- movzbl %al,%edi /* zero-extend that into %edi */
- call __audit_syscall_exit
- movq RAX(%rsp),%rax /* reload syscall return value */
- movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi
- DISABLE_INTERRUPTS(CLBR_NONE)
- TRACE_IRQS_OFF
- testl %edi, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
- jz \exit
- CLEAR_RREGS
- jmp int_with_check
- .endm
-
-sysenter_auditsys:
- auditsys_entry_common
- movl %ebp,%r9d /* reload 6th syscall arg */
- jmp sysenter_dispatch
-
-sysexit_audit:
- auditsys_exit sysexit_from_sys_call
-#endif
-
-sysenter_fix_flags:
- pushq_cfi $(X86_EFLAGS_IF|X86_EFLAGS_FIXED)
- popfq_cfi
- jmp sysenter_flags_fixed
-
-sysenter_tracesys:
-#ifdef CONFIG_AUDITSYSCALL
- testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
- jz sysenter_auditsys
-#endif
- SAVE_EXTRA_REGS
- CLEAR_RREGS
- movq $-ENOSYS,RAX(%rsp)/* ptrace can change this for a bad syscall */
- movq %rsp,%rdi /* &pt_regs -> arg1 */
- call syscall_trace_enter
- LOAD_ARGS32 /* reload args from stack in case ptrace changed it */
- RESTORE_EXTRA_REGS
- cmpq $(IA32_NR_syscalls-1),%rax
- ja int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */
- jmp sysenter_do_call
- CFI_ENDPROC
-ENDPROC(ia32_sysenter_target)
-
-/*
- * 32bit SYSCALL instruction entry.
- *
- * 32bit SYSCALL saves rip to rcx, clears rflags.RF, then saves rflags to r11,
- * then loads new ss, cs, and rip from previously programmed MSRs.
- * rflags gets masked by a value from another MSR (so CLD and CLAC
- * are not needed). SYSCALL does not save anything on the stack
- * and does not change rsp.
- *
- * Note: rflags saving+masking-with-MSR happens only in Long mode
- * (in legacy 32bit mode, IF, RF and VM bits are cleared and that's it).
- * Don't get confused: rflags saving+masking depends on Long Mode Active bit
- * (EFER.LMA=1), NOT on bitness of userspace where SYSCALL executes
- * or target CS descriptor's L bit (SYSCALL does not read segment descriptors).
- *
- * Arguments:
- * eax system call number
- * ecx return address
- * ebx arg1
- * ebp arg2 (note: not saved in the stack frame, should not be touched)
- * edx arg3
- * esi arg4
- * edi arg5
- * esp user stack
- * 0(%esp) arg6
- *
- * This is purely a fast path. For anything complicated we use the int 0x80
- * path below. We set up a complete hardware stack frame to share code
- * with the int 0x80 path.
- */
-ENTRY(ia32_cstar_target)
- CFI_STARTPROC32 simple
- CFI_SIGNAL_FRAME
- CFI_DEF_CFA rsp,0
- CFI_REGISTER rip,rcx
- /*CFI_REGISTER rflags,r11*/
-
- /*
- * Interrupts are off on entry.
- * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON,
- * it is too small to ever cause noticeable irq latency.
- */
- SWAPGS_UNSAFE_STACK
- movl %esp,%r8d
- CFI_REGISTER rsp,r8
- movq PER_CPU_VAR(kernel_stack),%rsp
- ENABLE_INTERRUPTS(CLBR_NONE)
-
- /* Zero-extending 32-bit regs, do not remove */
- movl %eax,%eax
-
- /* Construct struct pt_regs on stack */
- pushq_cfi $__USER32_DS /* pt_regs->ss */
- pushq_cfi %r8 /* pt_regs->sp */
- CFI_REL_OFFSET rsp,0
- pushq_cfi %r11 /* pt_regs->flags */
- pushq_cfi $__USER32_CS /* pt_regs->cs */
- pushq_cfi %rcx /* pt_regs->ip */
- CFI_REL_OFFSET rip,0
- pushq_cfi_reg rax /* pt_regs->orig_ax */
- pushq_cfi_reg rdi /* pt_regs->di */
- pushq_cfi_reg rsi /* pt_regs->si */
- pushq_cfi_reg rdx /* pt_regs->dx */
- pushq_cfi_reg rbp /* pt_regs->cx */
- movl %ebp,%ecx
- pushq_cfi_reg rax /* pt_regs->ax */
- sub $(10*8),%rsp /* pt_regs->r8-11,bp,bx,r12-15 not saved */
- CFI_ADJUST_CFA_OFFSET 10*8
-
- /*
- * no need to do an access_ok check here because r8 has been
- * 32bit zero extended
- */
- ASM_STAC
-1: movl (%r8),%r9d
- _ASM_EXTABLE(1b,ia32_badarg)
- ASM_CLAC
- orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
- testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
- CFI_REMEMBER_STATE
- jnz cstar_tracesys
- cmpq $IA32_NR_syscalls-1,%rax
- ja ia32_badsys
-cstar_do_call:
- /* 32bit syscall -> 64bit C ABI argument conversion */
- movl %edi,%r8d /* arg5 */
- /* r9 already loaded */ /* arg6 */
- xchg %ecx,%esi /* rsi:arg2, rcx:arg4 */
- movl %ebx,%edi /* arg1 */
- movl %edx,%edx /* arg3 (zero extension) */
-cstar_dispatch:
- call *ia32_sys_call_table(,%rax,8)
- movq %rax,RAX(%rsp)
- DISABLE_INTERRUPTS(CLBR_NONE)
- TRACE_IRQS_OFF
- testl $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
- jnz sysretl_audit
-sysretl_from_sys_call:
- andl $~TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
- RESTORE_RSI_RDI_RDX
- movl RIP(%rsp),%ecx
- CFI_REGISTER rip,rcx
- movl EFLAGS(%rsp),%r11d
- /*CFI_REGISTER rflags,r11*/
- xorq %r10,%r10
- xorq %r9,%r9
- xorq %r8,%r8
- TRACE_IRQS_ON
- movl RSP(%rsp),%esp
- CFI_RESTORE rsp
- /*
- * 64bit->32bit SYSRET restores eip from ecx,
- * eflags from r11 (but RF and VM bits are forced to 0),
- * cs and ss are loaded from MSRs.
- * (Note: 32bit->32bit SYSRET is different: since r11
- * does not exist, it merely sets eflags.IF=1).
- *
- * NB: On AMD CPUs with the X86_BUG_SYSRET_SS_ATTRS bug, the ss
- * descriptor is not reinitialized. This means that we must
- * avoid SYSRET with SS == NULL, which could happen if we schedule,
- * exit the kernel, and re-enter using an interrupt vector. (All
- * interrupt entries on x86_64 set SS to NULL.) We prevent that
- * from happening by reloading SS in __switch_to.
- */
- USERGS_SYSRET32
-
-#ifdef CONFIG_AUDITSYSCALL
-cstar_auditsys:
- CFI_RESTORE_STATE
- movl %r9d,R9(%rsp) /* register to be clobbered by call */
- auditsys_entry_common
- movl R9(%rsp),%r9d /* reload 6th syscall arg */
- jmp cstar_dispatch
-
-sysretl_audit:
- auditsys_exit sysretl_from_sys_call
-#endif
-
-cstar_tracesys:
-#ifdef CONFIG_AUDITSYSCALL
- testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
- jz cstar_auditsys
-#endif
- xchgl %r9d,%ebp
- SAVE_EXTRA_REGS
- CLEAR_RREGS r9
- movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */
- movq %rsp,%rdi /* &pt_regs -> arg1 */
- call syscall_trace_enter
- LOAD_ARGS32 1 /* reload args from stack in case ptrace changed it */
- RESTORE_EXTRA_REGS
- xchgl %ebp,%r9d
- cmpq $(IA32_NR_syscalls-1),%rax
- ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */
- jmp cstar_do_call
-END(ia32_cstar_target)
-
-ia32_badarg:
- ASM_CLAC
- movq $-EFAULT,%rax
- jmp ia32_sysret
- CFI_ENDPROC
-
-/*
- * Emulated IA32 system calls via int 0x80.
- *
- * Arguments:
- * eax system call number
- * ebx arg1
- * ecx arg2
- * edx arg3
- * esi arg4
- * edi arg5
- * ebp arg6 (note: not saved in the stack frame, should not be touched)
- *
- * Notes:
- * Uses the same stack frame as the x86-64 version.
- * All registers except eax must be saved (but ptrace may violate that).
- * Arguments are zero extended. For system calls that want sign extension and
- * take long arguments a wrapper is needed. Most calls can just be called
- * directly.
- * Assumes it is only called from user space and entered with interrupts off.
- */
-
-ENTRY(ia32_syscall)
- CFI_STARTPROC32 simple
- CFI_SIGNAL_FRAME
- CFI_DEF_CFA rsp,5*8
- /*CFI_REL_OFFSET ss,4*8 */
- CFI_REL_OFFSET rsp,3*8
- /*CFI_REL_OFFSET rflags,2*8 */
- /*CFI_REL_OFFSET cs,1*8 */
- CFI_REL_OFFSET rip,0*8
-
- /*
- * Interrupts are off on entry.
- * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON,
- * it is too small to ever cause noticeable irq latency.
- */
- PARAVIRT_ADJUST_EXCEPTION_FRAME
- SWAPGS
- ENABLE_INTERRUPTS(CLBR_NONE)
-
- /* Zero-extending 32-bit regs, do not remove */
- movl %eax,%eax
-
- /* Construct struct pt_regs on stack (iret frame is already on stack) */
- pushq_cfi_reg rax /* pt_regs->orig_ax */
- pushq_cfi_reg rdi /* pt_regs->di */
- pushq_cfi_reg rsi /* pt_regs->si */
- pushq_cfi_reg rdx /* pt_regs->dx */
- pushq_cfi_reg rcx /* pt_regs->cx */
- pushq_cfi_reg rax /* pt_regs->ax */
- cld
- sub $(10*8),%rsp /* pt_regs->r8-11,bp,bx,r12-15 not saved */
- CFI_ADJUST_CFA_OFFSET 10*8
-
- orl $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
- testl $_TIF_WORK_SYSCALL_ENTRY, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
- jnz ia32_tracesys
- cmpq $(IA32_NR_syscalls-1),%rax
- ja ia32_badsys
-ia32_do_call:
- /* 32bit syscall -> 64bit C ABI argument conversion */
- movl %edi,%r8d /* arg5 */
- movl %ebp,%r9d /* arg6 */
- xchg %ecx,%esi /* rsi:arg2, rcx:arg4 */
- movl %ebx,%edi /* arg1 */
- movl %edx,%edx /* arg3 (zero extension) */
- call *ia32_sys_call_table(,%rax,8) # xxx: rip relative
-ia32_sysret:
- movq %rax,RAX(%rsp)
-ia32_ret_from_sys_call:
- CLEAR_RREGS
- jmp int_ret_from_sys_call
-
-ia32_tracesys:
- SAVE_EXTRA_REGS
- CLEAR_RREGS
- movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */
- movq %rsp,%rdi /* &pt_regs -> arg1 */
- call syscall_trace_enter
- LOAD_ARGS32 /* reload args from stack in case ptrace changed it */
- RESTORE_EXTRA_REGS
- cmpq $(IA32_NR_syscalls-1),%rax
- ja int_ret_from_sys_call /* ia32_tracesys has set RAX(%rsp) */
- jmp ia32_do_call
-END(ia32_syscall)
-
-ia32_badsys:
- movq $0,ORIG_RAX(%rsp)
- movq $-ENOSYS,%rax
- jmp ia32_sysret
-
- CFI_ENDPROC
-
- .macro PTREGSCALL label, func
- ALIGN
-GLOBAL(\label)
- leaq \func(%rip),%rax
- jmp ia32_ptregs_common
- .endm
-
- CFI_STARTPROC32
-
- PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn
- PTREGSCALL stub32_sigreturn, sys32_sigreturn
- PTREGSCALL stub32_fork, sys_fork
- PTREGSCALL stub32_vfork, sys_vfork
-
- ALIGN
-GLOBAL(stub32_clone)
- leaq sys_clone(%rip),%rax
- mov %r8, %rcx
- jmp ia32_ptregs_common
-
- ALIGN
-ia32_ptregs_common:
- CFI_ENDPROC
- CFI_STARTPROC32 simple
- CFI_SIGNAL_FRAME
- CFI_DEF_CFA rsp,SIZEOF_PTREGS
- CFI_REL_OFFSET rax,RAX
- CFI_REL_OFFSET rcx,RCX
- CFI_REL_OFFSET rdx,RDX
- CFI_REL_OFFSET rsi,RSI
- CFI_REL_OFFSET rdi,RDI
- CFI_REL_OFFSET rip,RIP
-/* CFI_REL_OFFSET cs,CS*/
-/* CFI_REL_OFFSET rflags,EFLAGS*/
- CFI_REL_OFFSET rsp,RSP
-/* CFI_REL_OFFSET ss,SS*/
- SAVE_EXTRA_REGS 8
- call *%rax
- RESTORE_EXTRA_REGS 8
- ret
- CFI_ENDPROC
-END(ia32_ptregs_common)
diff --git a/arch/x86/include/asm/Kbuild b/arch/x86/include/asm/Kbuild
index d55a210a49bf..4dd1f2d770af 100644
--- a/arch/x86/include/asm/Kbuild
+++ b/arch/x86/include/asm/Kbuild
@@ -9,4 +9,3 @@ generic-y += cputime.h
generic-y += dma-contiguous.h
generic-y += early_ioremap.h
generic-y += mcs_spinlock.h
-generic-y += scatterlist.h
diff --git a/arch/x86/include/asm/alternative-asm.h b/arch/x86/include/asm/alternative-asm.h
index bdf02eeee765..e7636bac7372 100644
--- a/arch/x86/include/asm/alternative-asm.h
+++ b/arch/x86/include/asm/alternative-asm.h
@@ -18,6 +18,12 @@
.endm
#endif
+/*
+ * Issue one struct alt_instr descriptor entry (need to put it into
+ * the section .altinstructions, see below). This entry contains
+ * enough information for the alternatives patching code to patch an
+ * instruction. See apply_alternatives().
+ */
.macro altinstruction_entry orig alt feature orig_len alt_len pad_len
.long \orig - .
.long \alt - .
@@ -27,6 +33,12 @@
.byte \pad_len
.endm
+/*
+ * Define an alternative between two instructions. If @feature is
+ * present, early code in apply_alternatives() replaces @oldinstr with
+ * @newinstr. ".skip" directive takes care of proper instruction padding
+ * in case @newinstr is longer than @oldinstr.
+ */
.macro ALTERNATIVE oldinstr, newinstr, feature
140:
\oldinstr
@@ -55,6 +67,12 @@
*/
#define alt_max_short(a, b) ((a) ^ (((a) ^ (b)) & -(-((a) < (b)))))
+
+/*
+ * Same as ALTERNATIVE macro above but for two alternatives. If CPU
+ * has @feature1, it replaces @oldinstr with @newinstr1. If CPU has
+ * @feature2, it replaces @oldinstr with @feature2.
+ */
.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
140:
\oldinstr
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
index ba32af062f61..7bfc85bbb8ff 100644
--- a/arch/x86/include/asm/alternative.h
+++ b/arch/x86/include/asm/alternative.h
@@ -52,6 +52,12 @@ struct alt_instr {
u8 padlen; /* length of build-time padding */
} __packed;
+/*
+ * Debug flag that can be tested to see whether alternative
+ * instructions were patched in already:
+ */
+extern int alternatives_patched;
+
extern void alternative_instructions(void);
extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h
index aaac3b2fb746..1a5da2e63aee 100644
--- a/arch/x86/include/asm/amd_nb.h
+++ b/arch/x86/include/asm/amd_nb.h
@@ -98,11 +98,22 @@ static inline u16 amd_get_node_id(struct pci_dev *pdev)
return 0;
}
+static inline bool amd_gart_present(void)
+{
+ /* GART present only on Fam15h, upto model 0fh */
+ if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
+ (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model < 0x10))
+ return true;
+
+ return false;
+}
+
#else
#define amd_nb_num(x) 0
#define amd_nb_has_feature(x) false
#define node_to_amd_nb(x) NULL
+#define amd_gart_present(x) false
#endif
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 976b86a325e5..c8393634ca0c 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -644,6 +644,12 @@ static inline void entering_ack_irq(void)
entering_irq();
}
+static inline void ipi_entering_ack_irq(void)
+{
+ ack_APIC_irq();
+ irq_enter();
+}
+
static inline void exiting_irq(void)
{
irq_exit();
diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h
index 7730c1c5c83a..189679aba703 100644
--- a/arch/x86/include/asm/asm.h
+++ b/arch/x86/include/asm/asm.h
@@ -63,6 +63,31 @@
_ASM_ALIGN ; \
_ASM_PTR (entry); \
.popsection
+
+.macro ALIGN_DESTINATION
+ /* check for bad alignment of destination */
+ movl %edi,%ecx
+ andl $7,%ecx
+ jz 102f /* already aligned */
+ subl $8,%ecx
+ negl %ecx
+ subl %ecx,%edx
+100: movb (%rsi),%al
+101: movb %al,(%rdi)
+ incq %rsi
+ incq %rdi
+ decl %ecx
+ jnz 100b
+102:
+ .section .fixup,"ax"
+103: addl %ecx,%edx /* ecx is zerorest also */
+ jmp copy_user_handle_tail
+ .previous
+
+ _ASM_EXTABLE(100b,103b)
+ _ASM_EXTABLE(101b,103b)
+ .endm
+
#else
# define _ASM_EXTABLE(from,to) \
" .pushsection \"__ex_table\",\"a\"\n" \
diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h
index 5e5cd123fdfb..e9168955c42f 100644
--- a/arch/x86/include/asm/atomic.h
+++ b/arch/x86/include/asm/atomic.h
@@ -22,7 +22,7 @@
*
* Atomically reads the value of @v.
*/
-static inline int atomic_read(const atomic_t *v)
+static __always_inline int atomic_read(const atomic_t *v)
{
return ACCESS_ONCE((v)->counter);
}
@@ -34,7 +34,7 @@ static inline int atomic_read(const atomic_t *v)
*
* Atomically sets the value of @v to @i.
*/
-static inline void atomic_set(atomic_t *v, int i)
+static __always_inline void atomic_set(atomic_t *v, int i)
{
v->counter = i;
}
@@ -46,7 +46,7 @@ static inline void atomic_set(atomic_t *v, int i)
*
* Atomically adds @i to @v.
*/
-static inline void atomic_add(int i, atomic_t *v)
+static __always_inline void atomic_add(int i, atomic_t *v)
{
asm volatile(LOCK_PREFIX "addl %1,%0"
: "+m" (v->counter)
@@ -60,7 +60,7 @@ static inline void atomic_add(int i, atomic_t *v)
*
* Atomically subtracts @i from @v.
*/
-static inline void atomic_sub(int i, atomic_t *v)
+static __always_inline void atomic_sub(int i, atomic_t *v)
{
asm volatile(LOCK_PREFIX "subl %1,%0"
: "+m" (v->counter)
@@ -76,7 +76,7 @@ static inline void atomic_sub(int i, atomic_t *v)
* true if the result is zero, or false for all
* other cases.
*/
-static inline int atomic_sub_and_test(int i, atomic_t *v)
+static __always_inline int atomic_sub_and_test(int i, atomic_t *v)
{
GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, "er", i, "%0", "e");
}
@@ -87,7 +87,7 @@ static inline int atomic_sub_and_test(int i, atomic_t *v)
*
* Atomically increments @v by 1.
*/
-static inline void atomic_inc(atomic_t *v)
+static __always_inline void atomic_inc(atomic_t *v)
{
asm volatile(LOCK_PREFIX "incl %0"
: "+m" (v->counter));
@@ -99,7 +99,7 @@ static inline void atomic_inc(atomic_t *v)
*
* Atomically decrements @v by 1.
*/
-static inline void atomic_dec(atomic_t *v)
+static __always_inline void atomic_dec(atomic_t *v)
{
asm volatile(LOCK_PREFIX "decl %0"
: "+m" (v->counter));
@@ -113,7 +113,7 @@ static inline void atomic_dec(atomic_t *v)
* returns true if the result is 0, or false for all other
* cases.
*/
-static inline int atomic_dec_and_test(atomic_t *v)
+static __always_inline int atomic_dec_and_test(atomic_t *v)
{
GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e");
}
@@ -126,7 +126,7 @@ static inline int atomic_dec_and_test(atomic_t *v)
* and returns true if the result is zero, or false for all
* other cases.
*/
-static inline int atomic_inc_and_test(atomic_t *v)
+static __always_inline int atomic_inc_and_test(atomic_t *v)
{
GEN_UNARY_RMWcc(LOCK_PREFIX "incl", v->counter, "%0", "e");
}
@@ -140,7 +140,7 @@ static inline int atomic_inc_and_test(atomic_t *v)
* if the result is negative, or false when
* result is greater than or equal to zero.
*/
-static inline int atomic_add_negative(int i, atomic_t *v)
+static __always_inline int atomic_add_negative(int i, atomic_t *v)
{
GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, "er", i, "%0", "s");
}
@@ -152,7 +152,7 @@ static inline int atomic_add_negative(int i, atomic_t *v)
*
* Atomically adds @i to @v and returns @i + @v
*/
-static inline int atomic_add_return(int i, atomic_t *v)
+static __always_inline int atomic_add_return(int i, atomic_t *v)
{
return i + xadd(&v->counter, i);
}
@@ -164,7 +164,7 @@ static inline int atomic_add_return(int i, atomic_t *v)
*
* Atomically subtracts @i from @v and returns @v - @i
*/
-static inline int atomic_sub_return(int i, atomic_t *v)
+static __always_inline int atomic_sub_return(int i, atomic_t *v)
{
return atomic_add_return(-i, v);
}
@@ -172,7 +172,7 @@ static inline int atomic_sub_return(int i, atomic_t *v)
#define atomic_inc_return(v) (atomic_add_return(1, v))
#define atomic_dec_return(v) (atomic_sub_return(1, v))
-static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new)
{
return cmpxchg(&v->counter, old, new);
}
@@ -191,7 +191,7 @@ static inline int atomic_xchg(atomic_t *v, int new)
* Atomically adds @a to @v, so long as @v was not already @u.
* Returns the old value of @v.
*/
-static inline int __atomic_add_unless(atomic_t *v, int a, int u)
+static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u)
{
int c, old;
c = atomic_read(v);
@@ -213,7 +213,7 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
* Atomically adds 1 to @v
* Returns the new value of @u
*/
-static inline short int atomic_inc_short(short int *v)
+static __always_inline short int atomic_inc_short(short int *v)
{
asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v));
return *v;
diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h
index f8d273e18516..b965f9e03f2a 100644
--- a/arch/x86/include/asm/atomic64_64.h
+++ b/arch/x86/include/asm/atomic64_64.h
@@ -40,7 +40,7 @@ static inline void atomic64_set(atomic64_t *v, long i)
*
* Atomically adds @i to @v.
*/
-static inline void atomic64_add(long i, atomic64_t *v)
+static __always_inline void atomic64_add(long i, atomic64_t *v)
{
asm volatile(LOCK_PREFIX "addq %1,%0"
: "=m" (v->counter)
@@ -81,7 +81,7 @@ static inline int atomic64_sub_and_test(long i, atomic64_t *v)
*
* Atomically increments @v by 1.
*/
-static inline void atomic64_inc(atomic64_t *v)
+static __always_inline void atomic64_inc(atomic64_t *v)
{
asm volatile(LOCK_PREFIX "incq %0"
: "=m" (v->counter)
@@ -94,7 +94,7 @@ static inline void atomic64_inc(atomic64_t *v)
*
* Atomically decrements @v by 1.
*/
-static inline void atomic64_dec(atomic64_t *v)
+static __always_inline void atomic64_dec(atomic64_t *v)
{
asm volatile(LOCK_PREFIX "decq %0"
: "=m" (v->counter)
@@ -148,7 +148,7 @@ static inline int atomic64_add_negative(long i, atomic64_t *v)
*
* Atomically adds @i to @v and returns @i + @v
*/
-static inline long atomic64_add_return(long i, atomic64_t *v)
+static __always_inline long atomic64_add_return(long i, atomic64_t *v)
{
return i + xadd(&v->counter, i);
}
diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h
index 959e45b81fe2..e51a8f803f55 100644
--- a/arch/x86/include/asm/barrier.h
+++ b/arch/x86/include/asm/barrier.h
@@ -35,12 +35,12 @@
#define smp_mb() mb()
#define smp_rmb() dma_rmb()
#define smp_wmb() barrier()
-#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
+#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 set_mb(var, value) do { var = value; barrier(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); barrier(); } while (0)
#endif /* SMP */
#define read_barrier_depends() do { } while (0)
diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h
index 47c8e32f621a..b6f7457d12e4 100644
--- a/arch/x86/include/asm/cacheflush.h
+++ b/arch/x86/include/asm/cacheflush.h
@@ -8,7 +8,7 @@
/*
* The set_memory_* API can be used to change various attributes of a virtual
* address range. The attributes include:
- * Cachability : UnCached, WriteCombining, WriteBack
+ * Cachability : UnCached, WriteCombining, WriteThrough, WriteBack
* Executability : eXeutable, NoteXecutable
* Read/Write : ReadOnly, ReadWrite
* Presence : NotPresent
@@ -35,9 +35,11 @@
int _set_memory_uc(unsigned long addr, int numpages);
int _set_memory_wc(unsigned long addr, int numpages);
+int _set_memory_wt(unsigned long addr, int numpages);
int _set_memory_wb(unsigned long addr, int numpages);
int set_memory_uc(unsigned long addr, int numpages);
int set_memory_wc(unsigned long addr, int numpages);
+int set_memory_wt(unsigned long addr, int numpages);
int set_memory_wb(unsigned long addr, int numpages);
int set_memory_x(unsigned long addr, int numpages);
int set_memory_nx(unsigned long addr, int numpages);
@@ -48,10 +50,12 @@ int set_memory_4k(unsigned long addr, int numpages);
int set_memory_array_uc(unsigned long *addr, int addrinarray);
int set_memory_array_wc(unsigned long *addr, int addrinarray);
+int set_memory_array_wt(unsigned long *addr, int addrinarray);
int set_memory_array_wb(unsigned long *addr, int addrinarray);
int set_pages_array_uc(struct page **pages, int addrinarray);
int set_pages_array_wc(struct page **pages, int addrinarray);
+int set_pages_array_wt(struct page **pages, int addrinarray);
int set_pages_array_wb(struct page **pages, int addrinarray);
/*
diff --git a/arch/x86/include/asm/cmpxchg.h b/arch/x86/include/asm/cmpxchg.h
index 99c105d78b7e..ad19841eddfe 100644
--- a/arch/x86/include/asm/cmpxchg.h
+++ b/arch/x86/include/asm/cmpxchg.h
@@ -4,8 +4,6 @@
#include <linux/compiler.h>
#include <asm/alternative.h> /* Provides LOCK_PREFIX */
-#define __HAVE_ARCH_CMPXCHG 1
-
/*
* Non-existant functions to indicate usage errors at link time
* (or compile-time if the compiler implements __compiletime_error().
diff --git a/arch/x86/include/asm/crypto/glue_helper.h b/arch/x86/include/asm/crypto/glue_helper.h
index 1eef55596e82..03bb1065c335 100644
--- a/arch/x86/include/asm/crypto/glue_helper.h
+++ b/arch/x86/include/asm/crypto/glue_helper.h
@@ -7,7 +7,7 @@
#include <linux/kernel.h>
#include <linux/crypto.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
#include <crypto/b128ops.h>
typedef void (*common_glue_func_t)(void *ctx, u8 *dst, const u8 *src);
diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h
index 808dae63eeea..1f5b7287d1ad 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -127,50 +127,14 @@ static inline gfp_t dma_alloc_coherent_gfp_flags(struct device *dev, gfp_t gfp)
#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL)
-static inline void *
+void *
dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
- gfp_t gfp, struct dma_attrs *attrs)
-{
- struct dma_map_ops *ops = get_dma_ops(dev);
- void *memory;
-
- gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
-
- if (dma_alloc_from_coherent(dev, size, dma_handle, &memory))
- return memory;
-
- if (!dev)
- dev = &x86_dma_fallback_dev;
-
- if (!is_device_dma_capable(dev))
- return NULL;
-
- if (!ops->alloc)
- return NULL;
-
- memory = ops->alloc(dev, size, dma_handle,
- dma_alloc_coherent_gfp_flags(dev, gfp), attrs);
- debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
-
- return memory;
-}
+ gfp_t gfp, struct dma_attrs *attrs);
#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL)
-static inline void dma_free_attrs(struct device *dev, size_t size,
- void *vaddr, dma_addr_t bus,
- struct dma_attrs *attrs)
-{
- struct dma_map_ops *ops = get_dma_ops(dev);
-
- WARN_ON(irqs_disabled()); /* for portability */
-
- if (dma_release_from_coherent(dev, get_order(size), vaddr))
- return;
-
- debug_dma_free_coherent(dev, size, vaddr, bus);
- if (ops->free)
- ops->free(dev, size, vaddr, bus, attrs);
-}
+void dma_free_attrs(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t bus,
+ struct dma_attrs *attrs);
#endif
diff --git a/arch/x86/include/asm/dwarf2.h b/arch/x86/include/asm/dwarf2.h
deleted file mode 100644
index de1cdaf4d743..000000000000
--- a/arch/x86/include/asm/dwarf2.h
+++ /dev/null
@@ -1,170 +0,0 @@
-#ifndef _ASM_X86_DWARF2_H
-#define _ASM_X86_DWARF2_H
-
-#ifndef __ASSEMBLY__
-#warning "asm/dwarf2.h should be only included in pure assembly files"
-#endif
-
-/*
- * Macros for dwarf2 CFI unwind table entries.
- * See "as.info" for details on these pseudo ops. Unfortunately
- * they are only supported in very new binutils, so define them
- * away for older version.
- */
-
-#ifdef CONFIG_AS_CFI
-
-#define CFI_STARTPROC .cfi_startproc
-#define CFI_ENDPROC .cfi_endproc
-#define CFI_DEF_CFA .cfi_def_cfa
-#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register
-#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset
-#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset
-#define CFI_OFFSET .cfi_offset
-#define CFI_REL_OFFSET .cfi_rel_offset
-#define CFI_REGISTER .cfi_register
-#define CFI_RESTORE .cfi_restore
-#define CFI_REMEMBER_STATE .cfi_remember_state
-#define CFI_RESTORE_STATE .cfi_restore_state
-#define CFI_UNDEFINED .cfi_undefined
-#define CFI_ESCAPE .cfi_escape
-
-#ifdef CONFIG_AS_CFI_SIGNAL_FRAME
-#define CFI_SIGNAL_FRAME .cfi_signal_frame
-#else
-#define CFI_SIGNAL_FRAME
-#endif
-
-#if defined(CONFIG_AS_CFI_SECTIONS) && defined(__ASSEMBLY__)
- /*
- * Emit CFI data in .debug_frame sections, not .eh_frame sections.
- * The latter we currently just discard since we don't do DWARF
- * unwinding at runtime. So only the offline DWARF information is
- * useful to anyone. Note we should not use this directive if this
- * file is used in the vDSO assembly, or if vmlinux.lds.S gets
- * changed so it doesn't discard .eh_frame.
- */
- .cfi_sections .debug_frame
-#endif
-
-#else
-
-/*
- * Due to the structure of pre-exisiting code, don't use assembler line
- * comment character # to ignore the arguments. Instead, use a dummy macro.
- */
-.macro cfi_ignore a=0, b=0, c=0, d=0
-.endm
-
-#define CFI_STARTPROC cfi_ignore
-#define CFI_ENDPROC cfi_ignore
-#define CFI_DEF_CFA cfi_ignore
-#define CFI_DEF_CFA_REGISTER cfi_ignore
-#define CFI_DEF_CFA_OFFSET cfi_ignore
-#define CFI_ADJUST_CFA_OFFSET cfi_ignore
-#define CFI_OFFSET cfi_ignore
-#define CFI_REL_OFFSET cfi_ignore
-#define CFI_REGISTER cfi_ignore
-#define CFI_RESTORE cfi_ignore
-#define CFI_REMEMBER_STATE cfi_ignore
-#define CFI_RESTORE_STATE cfi_ignore
-#define CFI_UNDEFINED cfi_ignore
-#define CFI_ESCAPE cfi_ignore
-#define CFI_SIGNAL_FRAME cfi_ignore
-
-#endif
-
-/*
- * An attempt to make CFI annotations more or less
- * correct and shorter. It is implied that you know
- * what you're doing if you use them.
- */
-#ifdef __ASSEMBLY__
-#ifdef CONFIG_X86_64
- .macro pushq_cfi reg
- pushq \reg
- CFI_ADJUST_CFA_OFFSET 8
- .endm
-
- .macro pushq_cfi_reg reg
- pushq %\reg
- CFI_ADJUST_CFA_OFFSET 8
- CFI_REL_OFFSET \reg, 0
- .endm
-
- .macro popq_cfi reg
- popq \reg
- CFI_ADJUST_CFA_OFFSET -8
- .endm
-
- .macro popq_cfi_reg reg
- popq %\reg
- CFI_ADJUST_CFA_OFFSET -8
- CFI_RESTORE \reg
- .endm
-
- .macro pushfq_cfi
- pushfq
- CFI_ADJUST_CFA_OFFSET 8
- .endm
-
- .macro popfq_cfi
- popfq
- CFI_ADJUST_CFA_OFFSET -8
- .endm
-
- .macro movq_cfi reg offset=0
- movq %\reg, \offset(%rsp)
- CFI_REL_OFFSET \reg, \offset
- .endm
-
- .macro movq_cfi_restore offset reg
- movq \offset(%rsp), %\reg
- CFI_RESTORE \reg
- .endm
-#else /*!CONFIG_X86_64*/
- .macro pushl_cfi reg
- pushl \reg
- CFI_ADJUST_CFA_OFFSET 4
- .endm
-
- .macro pushl_cfi_reg reg
- pushl %\reg
- CFI_ADJUST_CFA_OFFSET 4
- CFI_REL_OFFSET \reg, 0
- .endm
-
- .macro popl_cfi reg
- popl \reg
- CFI_ADJUST_CFA_OFFSET -4
- .endm
-
- .macro popl_cfi_reg reg
- popl %\reg
- CFI_ADJUST_CFA_OFFSET -4
- CFI_RESTORE \reg
- .endm
-
- .macro pushfl_cfi
- pushfl
- CFI_ADJUST_CFA_OFFSET 4
- .endm
-
- .macro popfl_cfi
- popfl
- CFI_ADJUST_CFA_OFFSET -4
- .endm
-
- .macro movl_cfi reg offset=0
- movl %\reg, \offset(%esp)
- CFI_REL_OFFSET \reg, \offset
- .endm
-
- .macro movl_cfi_restore offset reg
- movl \offset(%esp), %\reg
- CFI_RESTORE \reg
- .endm
-#endif /*!CONFIG_X86_64*/
-#endif /*__ASSEMBLY__*/
-
-#endif /* _ASM_X86_DWARF2_H */
diff --git a/arch/x86/include/asm/edac.h b/arch/x86/include/asm/edac.h
index e9b57ecc70c5..cf8fdf83b231 100644
--- a/arch/x86/include/asm/edac.h
+++ b/arch/x86/include/asm/edac.h
@@ -3,7 +3,7 @@
/* ECC atomic, DMA, SMP and interrupt safe scrub function */
-static inline void atomic_scrub(void *va, u32 size)
+static inline void edac_atomic_scrub(void *va, u32 size)
{
u32 i, *virt_addr = va;
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 3738b138b843..155162ea0e00 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -1,7 +1,7 @@
#ifndef _ASM_X86_EFI_H
#define _ASM_X86_EFI_H
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
#include <asm/pgtable.h>
/*
diff --git a/arch/x86/include/asm/entry_arch.h b/arch/x86/include/asm/entry_arch.h
index dc5fa661465f..df002992d8fd 100644
--- a/arch/x86/include/asm/entry_arch.h
+++ b/arch/x86/include/asm/entry_arch.h
@@ -23,6 +23,8 @@ BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR)
#ifdef CONFIG_HAVE_KVM
BUILD_INTERRUPT3(kvm_posted_intr_ipi, POSTED_INTR_VECTOR,
smp_kvm_posted_intr_ipi)
+BUILD_INTERRUPT3(kvm_posted_intr_wakeup_ipi, POSTED_INTR_WAKEUP_VECTOR,
+ smp_kvm_posted_intr_wakeup_ipi)
#endif
/*
@@ -50,4 +52,7 @@ BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR)
BUILD_INTERRUPT(threshold_interrupt,THRESHOLD_APIC_VECTOR)
#endif
+#ifdef CONFIG_X86_MCE_AMD
+BUILD_INTERRUPT(deferred_error_interrupt, DEFERRED_ERROR_VECTOR)
+#endif
#endif
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
deleted file mode 100644
index da5e96756570..000000000000
--- a/arch/x86/include/asm/fpu-internal.h
+++ /dev/null
@@ -1,626 +0,0 @@
-/*
- * Copyright (C) 1994 Linus Torvalds
- *
- * Pentium III FXSR, SSE support
- * General FPU state handling cleanups
- * Gareth Hughes <gareth@valinux.com>, May 2000
- * x86-64 work by Andi Kleen 2002
- */
-
-#ifndef _FPU_INTERNAL_H
-#define _FPU_INTERNAL_H
-
-#include <linux/kernel_stat.h>
-#include <linux/regset.h>
-#include <linux/compat.h>
-#include <linux/slab.h>
-#include <asm/asm.h>
-#include <asm/cpufeature.h>
-#include <asm/processor.h>
-#include <asm/sigcontext.h>
-#include <asm/user.h>
-#include <asm/uaccess.h>
-#include <asm/xsave.h>
-#include <asm/smap.h>
-
-#ifdef CONFIG_X86_64
-# include <asm/sigcontext32.h>
-# include <asm/user32.h>
-struct ksignal;
-int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
- compat_sigset_t *set, struct pt_regs *regs);
-int ia32_setup_frame(int sig, struct ksignal *ksig,
- compat_sigset_t *set, struct pt_regs *regs);
-#else
-# define user_i387_ia32_struct user_i387_struct
-# define user32_fxsr_struct user_fxsr_struct
-# define ia32_setup_frame __setup_frame
-# define ia32_setup_rt_frame __setup_rt_frame
-#endif
-
-extern unsigned int mxcsr_feature_mask;
-extern void fpu_init(void);
-extern void eager_fpu_init(void);
-
-DECLARE_PER_CPU(struct task_struct *, fpu_owner_task);
-
-extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
- struct task_struct *tsk);
-extern void convert_to_fxsr(struct task_struct *tsk,
- const struct user_i387_ia32_struct *env);
-
-extern user_regset_active_fn fpregs_active, xfpregs_active;
-extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
- xstateregs_get;
-extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
- xstateregs_set;
-
-/*
- * xstateregs_active == fpregs_active. Please refer to the comment
- * at the definition of fpregs_active.
- */
-#define xstateregs_active fpregs_active
-
-#ifdef CONFIG_MATH_EMULATION
-extern void finit_soft_fpu(struct i387_soft_struct *soft);
-#else
-static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
-#endif
-
-/*
- * Must be run with preemption disabled: this clears the fpu_owner_task,
- * on this CPU.
- *
- * This will disable any lazy FPU state restore of the current FPU state,
- * but if the current thread owns the FPU, it will still be saved by.
- */
-static inline void __cpu_disable_lazy_restore(unsigned int cpu)
-{
- per_cpu(fpu_owner_task, cpu) = NULL;
-}
-
-/*
- * Used to indicate that the FPU state in memory is newer than the FPU
- * state in registers, and the FPU state should be reloaded next time the
- * task is run. Only safe on the current task, or non-running tasks.
- */
-static inline void task_disable_lazy_fpu_restore(struct task_struct *tsk)
-{
- tsk->thread.fpu.last_cpu = ~0;
-}
-
-static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
-{
- return new == this_cpu_read_stable(fpu_owner_task) &&
- cpu == new->thread.fpu.last_cpu;
-}
-
-static inline int is_ia32_compat_frame(void)
-{
- return config_enabled(CONFIG_IA32_EMULATION) &&
- test_thread_flag(TIF_IA32);
-}
-
-static inline int is_ia32_frame(void)
-{
- return config_enabled(CONFIG_X86_32) || is_ia32_compat_frame();
-}
-
-static inline int is_x32_frame(void)
-{
- return config_enabled(CONFIG_X86_X32_ABI) && test_thread_flag(TIF_X32);
-}
-
-#define X87_FSW_ES (1 << 7) /* Exception Summary */
-
-static __always_inline __pure bool use_eager_fpu(void)
-{
- return static_cpu_has_safe(X86_FEATURE_EAGER_FPU);
-}
-
-static __always_inline __pure bool use_xsaveopt(void)
-{
- return static_cpu_has_safe(X86_FEATURE_XSAVEOPT);
-}
-
-static __always_inline __pure bool use_xsave(void)
-{
- return static_cpu_has_safe(X86_FEATURE_XSAVE);
-}
-
-static __always_inline __pure bool use_fxsr(void)
-{
- return static_cpu_has_safe(X86_FEATURE_FXSR);
-}
-
-static inline void fx_finit(struct i387_fxsave_struct *fx)
-{
- fx->cwd = 0x37f;
- fx->mxcsr = MXCSR_DEFAULT;
-}
-
-extern void __sanitize_i387_state(struct task_struct *);
-
-static inline void sanitize_i387_state(struct task_struct *tsk)
-{
- if (!use_xsaveopt())
- return;
- __sanitize_i387_state(tsk);
-}
-
-#define user_insn(insn, output, input...) \
-({ \
- int err; \
- asm volatile(ASM_STAC "\n" \
- "1:" #insn "\n\t" \
- "2: " ASM_CLAC "\n" \
- ".section .fixup,\"ax\"\n" \
- "3: movl $-1,%[err]\n" \
- " jmp 2b\n" \
- ".previous\n" \
- _ASM_EXTABLE(1b, 3b) \
- : [err] "=r" (err), output \
- : "0"(0), input); \
- err; \
-})
-
-#define check_insn(insn, output, input...) \
-({ \
- int err; \
- asm volatile("1:" #insn "\n\t" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "3: movl $-1,%[err]\n" \
- " jmp 2b\n" \
- ".previous\n" \
- _ASM_EXTABLE(1b, 3b) \
- : [err] "=r" (err), output \
- : "0"(0), input); \
- err; \
-})
-
-static inline int fsave_user(struct i387_fsave_struct __user *fx)
-{
- return user_insn(fnsave %[fx]; fwait, [fx] "=m" (*fx), "m" (*fx));
-}
-
-static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
-{
- if (config_enabled(CONFIG_X86_32))
- return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
- else if (config_enabled(CONFIG_AS_FXSAVEQ))
- return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx));
-
- /* See comment in fpu_fxsave() below. */
- return user_insn(rex64/fxsave (%[fx]), "=m" (*fx), [fx] "R" (fx));
-}
-
-static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
-{
- if (config_enabled(CONFIG_X86_32))
- return check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
- else if (config_enabled(CONFIG_AS_FXSAVEQ))
- return check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
-
- /* See comment in fpu_fxsave() below. */
- return check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx),
- "m" (*fx));
-}
-
-static inline int fxrstor_user(struct i387_fxsave_struct __user *fx)
-{
- if (config_enabled(CONFIG_X86_32))
- return user_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
- else if (config_enabled(CONFIG_AS_FXSAVEQ))
- return user_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
-
- /* See comment in fpu_fxsave() below. */
- return user_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx),
- "m" (*fx));
-}
-
-static inline int frstor_checking(struct i387_fsave_struct *fx)
-{
- return check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
-}
-
-static inline int frstor_user(struct i387_fsave_struct __user *fx)
-{
- return user_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
-}
-
-static inline void fpu_fxsave(struct fpu *fpu)
-{
- if (config_enabled(CONFIG_X86_32))
- asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state->fxsave));
- else if (config_enabled(CONFIG_AS_FXSAVEQ))
- asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state->fxsave));
- else {
- /* Using "rex64; fxsave %0" is broken because, if the memory
- * operand uses any extended registers for addressing, a second
- * REX prefix will be generated (to the assembler, rex64
- * followed by semicolon is a separate instruction), and hence
- * the 64-bitness is lost.
- *
- * Using "fxsaveq %0" would be the ideal choice, but is only
- * supported starting with gas 2.16.
- *
- * Using, as a workaround, the properly prefixed form below
- * isn't accepted by any binutils version so far released,
- * complaining that the same type of prefix is used twice if
- * an extended register is needed for addressing (fix submitted
- * to mainline 2005-11-21).
- *
- * asm volatile("rex64/fxsave %0" : "=m" (fpu->state->fxsave));
- *
- * This, however, we can work around by forcing the compiler to
- * select an addressing mode that doesn't require extended
- * registers.
- */
- asm volatile( "rex64/fxsave (%[fx])"
- : "=m" (fpu->state->fxsave)
- : [fx] "R" (&fpu->state->fxsave));
- }
-}
-
-/*
- * These must be called with preempt disabled. Returns
- * 'true' if the FPU state is still intact.
- */
-static inline int fpu_save_init(struct fpu *fpu)
-{
- if (use_xsave()) {
- fpu_xsave(fpu);
-
- /*
- * xsave header may indicate the init state of the FP.
- */
- if (!(fpu->state->xsave.xsave_hdr.xstate_bv & XSTATE_FP))
- return 1;
- } else if (use_fxsr()) {
- fpu_fxsave(fpu);
- } else {
- asm volatile("fnsave %[fx]; fwait"
- : [fx] "=m" (fpu->state->fsave));
- return 0;
- }
-
- /*
- * If exceptions are pending, we need to clear them so
- * that we don't randomly get exceptions later.
- *
- * FIXME! Is this perhaps only true for the old-style
- * irq13 case? Maybe we could leave the x87 state
- * intact otherwise?
- */
- if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES)) {
- asm volatile("fnclex");
- return 0;
- }
- return 1;
-}
-
-static inline int __save_init_fpu(struct task_struct *tsk)
-{
- return fpu_save_init(&tsk->thread.fpu);
-}
-
-static inline int fpu_restore_checking(struct fpu *fpu)
-{
- if (use_xsave())
- return fpu_xrstor_checking(&fpu->state->xsave);
- else if (use_fxsr())
- return fxrstor_checking(&fpu->state->fxsave);
- else
- return frstor_checking(&fpu->state->fsave);
-}
-
-static inline int restore_fpu_checking(struct task_struct *tsk)
-{
- /*
- * AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception is
- * pending. Clear the x87 state here by setting it to fixed values.
- * "m" is a random variable that should be in L1.
- */
- if (unlikely(static_cpu_has_bug_safe(X86_BUG_FXSAVE_LEAK))) {
- asm volatile(
- "fnclex\n\t"
- "emms\n\t"
- "fildl %P[addr]" /* set F?P to defined value */
- : : [addr] "m" (tsk->thread.fpu.has_fpu));
- }
-
- return fpu_restore_checking(&tsk->thread.fpu);
-}
-
-/*
- * Software FPU state helpers. Careful: these need to
- * be preemption protection *and* they need to be
- * properly paired with the CR0.TS changes!
- */
-static inline int __thread_has_fpu(struct task_struct *tsk)
-{
- return tsk->thread.fpu.has_fpu;
-}
-
-/* Must be paired with an 'stts' after! */
-static inline void __thread_clear_has_fpu(struct task_struct *tsk)
-{
- tsk->thread.fpu.has_fpu = 0;
- this_cpu_write(fpu_owner_task, NULL);
-}
-
-/* Must be paired with a 'clts' before! */
-static inline void __thread_set_has_fpu(struct task_struct *tsk)
-{
- tsk->thread.fpu.has_fpu = 1;
- this_cpu_write(fpu_owner_task, tsk);
-}
-
-/*
- * Encapsulate the CR0.TS handling together with the
- * software flag.
- *
- * These generally need preemption protection to work,
- * do try to avoid using these on their own.
- */
-static inline void __thread_fpu_end(struct task_struct *tsk)
-{
- __thread_clear_has_fpu(tsk);
- if (!use_eager_fpu())
- stts();
-}
-
-static inline void __thread_fpu_begin(struct task_struct *tsk)
-{
- if (!use_eager_fpu())
- clts();
- __thread_set_has_fpu(tsk);
-}
-
-static inline void drop_fpu(struct task_struct *tsk)
-{
- /*
- * Forget coprocessor state..
- */
- preempt_disable();
- tsk->thread.fpu_counter = 0;
-
- if (__thread_has_fpu(tsk)) {
- /* Ignore delayed exceptions from user space */
- asm volatile("1: fwait\n"
- "2:\n"
- _ASM_EXTABLE(1b, 2b));
- __thread_fpu_end(tsk);
- }
-
- clear_stopped_child_used_math(tsk);
- preempt_enable();
-}
-
-static inline void restore_init_xstate(void)
-{
- if (use_xsave())
- xrstor_state(init_xstate_buf, -1);
- else
- fxrstor_checking(&init_xstate_buf->i387);
-}
-
-/*
- * Reset the FPU state in the eager case and drop it in the lazy case (later use
- * will reinit it).
- */
-static inline void fpu_reset_state(struct task_struct *tsk)
-{
- if (!use_eager_fpu())
- drop_fpu(tsk);
- else
- restore_init_xstate();
-}
-
-/*
- * FPU state switching for scheduling.
- *
- * This is a two-stage process:
- *
- * - switch_fpu_prepare() saves the old state and
- * sets the new state of the CR0.TS bit. This is
- * done within the context of the old process.
- *
- * - switch_fpu_finish() restores the new state as
- * necessary.
- */
-typedef struct { int preload; } fpu_switch_t;
-
-static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct task_struct *new, int cpu)
-{
- fpu_switch_t fpu;
-
- /*
- * If the task has used the math, pre-load the FPU on xsave processors
- * or if the past 5 consecutive context-switches used math.
- */
- fpu.preload = tsk_used_math(new) &&
- (use_eager_fpu() || new->thread.fpu_counter > 5);
-
- if (__thread_has_fpu(old)) {
- if (!__save_init_fpu(old))
- task_disable_lazy_fpu_restore(old);
- else
- old->thread.fpu.last_cpu = cpu;
-
- /* But leave fpu_owner_task! */
- old->thread.fpu.has_fpu = 0;
-
- /* Don't change CR0.TS if we just switch! */
- if (fpu.preload) {
- new->thread.fpu_counter++;
- __thread_set_has_fpu(new);
- prefetch(new->thread.fpu.state);
- } else if (!use_eager_fpu())
- stts();
- } else {
- old->thread.fpu_counter = 0;
- task_disable_lazy_fpu_restore(old);
- if (fpu.preload) {
- new->thread.fpu_counter++;
- if (fpu_lazy_restore(new, cpu))
- fpu.preload = 0;
- else
- prefetch(new->thread.fpu.state);
- __thread_fpu_begin(new);
- }
- }
- return fpu;
-}
-
-/*
- * By the time this gets called, we've already cleared CR0.TS and
- * given the process the FPU if we are going to preload the FPU
- * state - all we need to do is to conditionally restore the register
- * state itself.
- */
-static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu)
-{
- if (fpu.preload) {
- if (unlikely(restore_fpu_checking(new)))
- fpu_reset_state(new);
- }
-}
-
-/*
- * Signal frame handlers...
- */
-extern int save_xstate_sig(void __user *buf, void __user *fx, int size);
-extern int __restore_xstate_sig(void __user *buf, void __user *fx, int size);
-
-static inline int xstate_sigframe_size(void)
-{
- return use_xsave() ? xstate_size + FP_XSTATE_MAGIC2_SIZE : xstate_size;
-}
-
-static inline int restore_xstate_sig(void __user *buf, int ia32_frame)
-{
- void __user *buf_fx = buf;
- int size = xstate_sigframe_size();
-
- if (ia32_frame && use_fxsr()) {
- buf_fx = buf + sizeof(struct i387_fsave_struct);
- size += sizeof(struct i387_fsave_struct);
- }
-
- return __restore_xstate_sig(buf, buf_fx, size);
-}
-
-/*
- * Needs to be preemption-safe.
- *
- * NOTE! user_fpu_begin() must be used only immediately before restoring
- * the save state. It does not do any saving/restoring on its own. In
- * lazy FPU mode, it is just an optimization to avoid a #NM exception,
- * the task can lose the FPU right after preempt_enable().
- */
-static inline void user_fpu_begin(void)
-{
- preempt_disable();
- if (!user_has_fpu())
- __thread_fpu_begin(current);
- preempt_enable();
-}
-
-static inline void __save_fpu(struct task_struct *tsk)
-{
- if (use_xsave()) {
- if (unlikely(system_state == SYSTEM_BOOTING))
- xsave_state_booting(&tsk->thread.fpu.state->xsave, -1);
- else
- xsave_state(&tsk->thread.fpu.state->xsave, -1);
- } else
- fpu_fxsave(&tsk->thread.fpu);
-}
-
-/*
- * i387 state interaction
- */
-static inline unsigned short get_fpu_cwd(struct task_struct *tsk)
-{
- if (cpu_has_fxsr) {
- return tsk->thread.fpu.state->fxsave.cwd;
- } else {
- return (unsigned short)tsk->thread.fpu.state->fsave.cwd;
- }
-}
-
-static inline unsigned short get_fpu_swd(struct task_struct *tsk)
-{
- if (cpu_has_fxsr) {
- return tsk->thread.fpu.state->fxsave.swd;
- } else {
- return (unsigned short)tsk->thread.fpu.state->fsave.swd;
- }
-}
-
-static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk)
-{
- if (cpu_has_xmm) {
- return tsk->thread.fpu.state->fxsave.mxcsr;
- } else {
- return MXCSR_DEFAULT;
- }
-}
-
-static bool fpu_allocated(struct fpu *fpu)
-{
- return fpu->state != NULL;
-}
-
-static inline int fpu_alloc(struct fpu *fpu)
-{
- if (fpu_allocated(fpu))
- return 0;
- fpu->state = kmem_cache_alloc(task_xstate_cachep, GFP_KERNEL);
- if (!fpu->state)
- return -ENOMEM;
- WARN_ON((unsigned long)fpu->state & 15);
- return 0;
-}
-
-static inline void fpu_free(struct fpu *fpu)
-{
- if (fpu->state) {
- kmem_cache_free(task_xstate_cachep, fpu->state);
- fpu->state = NULL;
- }
-}
-
-static inline void fpu_copy(struct task_struct *dst, struct task_struct *src)
-{
- if (use_eager_fpu()) {
- memset(&dst->thread.fpu.state->xsave, 0, xstate_size);
- __save_fpu(dst);
- } else {
- struct fpu *dfpu = &dst->thread.fpu;
- struct fpu *sfpu = &src->thread.fpu;
-
- unlazy_fpu(src);
- memcpy(dfpu->state, sfpu->state, xstate_size);
- }
-}
-
-static inline unsigned long
-alloc_mathframe(unsigned long sp, int ia32_frame, unsigned long *buf_fx,
- unsigned long *size)
-{
- unsigned long frame_size = xstate_sigframe_size();
-
- *buf_fx = sp = round_down(sp - frame_size, 64);
- if (ia32_frame && use_fxsr()) {
- frame_size += sizeof(struct i387_fsave_struct);
- sp -= sizeof(struct i387_fsave_struct);
- }
-
- *size = frame_size;
- return sp;
-}
-
-#endif
diff --git a/arch/x86/include/asm/fpu/api.h b/arch/x86/include/asm/fpu/api.h
new file mode 100644
index 000000000000..1429a7c736db
--- /dev/null
+++ b/arch/x86/include/asm/fpu/api.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 1994 Linus Torvalds
+ *
+ * Pentium III FXSR, SSE support
+ * General FPU state handling cleanups
+ * Gareth Hughes <gareth@valinux.com>, May 2000
+ * x86-64 work by Andi Kleen 2002
+ */
+
+#ifndef _ASM_X86_FPU_API_H
+#define _ASM_X86_FPU_API_H
+
+/*
+ * Careful: __kernel_fpu_begin/end() must be called with preempt disabled
+ * and they don't touch the preempt state on their own.
+ * If you enable preemption after __kernel_fpu_begin(), preempt notifier
+ * should call the __kernel_fpu_end() to prevent the kernel/user FPU
+ * state from getting corrupted. KVM for example uses this model.
+ *
+ * All other cases use kernel_fpu_begin/end() which disable preemption
+ * during kernel FPU usage.
+ */
+extern void __kernel_fpu_begin(void);
+extern void __kernel_fpu_end(void);
+extern void kernel_fpu_begin(void);
+extern void kernel_fpu_end(void);
+extern bool irq_fpu_usable(void);
+
+/*
+ * Some instructions like VIA's padlock instructions generate a spurious
+ * DNA fault but don't modify SSE registers. And these instructions
+ * get used from interrupt context as well. To prevent these kernel instructions
+ * in interrupt context interacting wrongly with other user/kernel fpu usage, we
+ * should use them only in the context of irq_ts_save/restore()
+ */
+extern int irq_ts_save(void);
+extern void irq_ts_restore(int TS_state);
+
+/*
+ * Query the presence of one or more xfeatures. Works on any legacy CPU as well.
+ *
+ * If 'feature_name' is set then put a human-readable description of
+ * the feature there as well - this can be used to print error (or success)
+ * messages.
+ */
+extern int cpu_has_xfeatures(u64 xfeatures_mask, const char **feature_name);
+
+#endif /* _ASM_X86_FPU_API_H */
diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h
new file mode 100644
index 000000000000..3c3550c3a4a3
--- /dev/null
+++ b/arch/x86/include/asm/fpu/internal.h
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 1994 Linus Torvalds
+ *
+ * Pentium III FXSR, SSE support
+ * General FPU state handling cleanups
+ * Gareth Hughes <gareth@valinux.com>, May 2000
+ * x86-64 work by Andi Kleen 2002
+ */
+
+#ifndef _ASM_X86_FPU_INTERNAL_H
+#define _ASM_X86_FPU_INTERNAL_H
+
+#include <linux/compat.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <asm/user.h>
+#include <asm/fpu/api.h>
+#include <asm/fpu/xstate.h>
+
+/*
+ * High level FPU state handling functions:
+ */
+extern void fpu__activate_curr(struct fpu *fpu);
+extern void fpu__activate_fpstate_read(struct fpu *fpu);
+extern void fpu__activate_fpstate_write(struct fpu *fpu);
+extern void fpu__save(struct fpu *fpu);
+extern void fpu__restore(struct fpu *fpu);
+extern int fpu__restore_sig(void __user *buf, int ia32_frame);
+extern void fpu__drop(struct fpu *fpu);
+extern int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu);
+extern void fpu__clear(struct fpu *fpu);
+extern int fpu__exception_code(struct fpu *fpu, int trap_nr);
+extern int dump_fpu(struct pt_regs *ptregs, struct user_i387_struct *fpstate);
+
+/*
+ * Boot time FPU initialization functions:
+ */
+extern void fpu__init_cpu(void);
+extern void fpu__init_system_xstate(void);
+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);
+
+/*
+ * Debugging facility:
+ */
+#ifdef CONFIG_X86_DEBUG_FPU
+# define WARN_ON_FPU(x) WARN_ON_ONCE(x)
+#else
+# define WARN_ON_FPU(x) ({ (void)(x); 0; })
+#endif
+
+/*
+ * FPU related CPU feature flag helper routines:
+ */
+static __always_inline __pure bool use_eager_fpu(void)
+{
+ return static_cpu_has_safe(X86_FEATURE_EAGER_FPU);
+}
+
+static __always_inline __pure bool use_xsaveopt(void)
+{
+ return static_cpu_has_safe(X86_FEATURE_XSAVEOPT);
+}
+
+static __always_inline __pure bool use_xsave(void)
+{
+ return static_cpu_has_safe(X86_FEATURE_XSAVE);
+}
+
+static __always_inline __pure bool use_fxsr(void)
+{
+ return static_cpu_has_safe(X86_FEATURE_FXSR);
+}
+
+/*
+ * fpstate handling functions:
+ */
+
+extern union fpregs_state init_fpstate;
+
+extern void fpstate_init(union fpregs_state *state);
+#ifdef CONFIG_MATH_EMULATION
+extern void fpstate_init_soft(struct swregs_state *soft);
+#else
+static inline void fpstate_init_soft(struct swregs_state *soft) {}
+#endif
+static inline void fpstate_init_fxstate(struct fxregs_state *fx)
+{
+ fx->cwd = 0x37f;
+ fx->mxcsr = MXCSR_DEFAULT;
+}
+extern void fpstate_sanitize_xstate(struct fpu *fpu);
+
+#define user_insn(insn, output, input...) \
+({ \
+ int err; \
+ asm volatile(ASM_STAC "\n" \
+ "1:" #insn "\n\t" \
+ "2: " ASM_CLAC "\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: movl $-1,%[err]\n" \
+ " jmp 2b\n" \
+ ".previous\n" \
+ _ASM_EXTABLE(1b, 3b) \
+ : [err] "=r" (err), output \
+ : "0"(0), input); \
+ err; \
+})
+
+#define check_insn(insn, output, input...) \
+({ \
+ int err; \
+ asm volatile("1:" #insn "\n\t" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: movl $-1,%[err]\n" \
+ " jmp 2b\n" \
+ ".previous\n" \
+ _ASM_EXTABLE(1b, 3b) \
+ : [err] "=r" (err), output \
+ : "0"(0), input); \
+ err; \
+})
+
+static inline int copy_fregs_to_user(struct fregs_state __user *fx)
+{
+ return user_insn(fnsave %[fx]; fwait, [fx] "=m" (*fx), "m" (*fx));
+}
+
+static inline int copy_fxregs_to_user(struct fxregs_state __user *fx)
+{
+ if (config_enabled(CONFIG_X86_32))
+ return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
+ else if (config_enabled(CONFIG_AS_FXSAVEQ))
+ return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx));
+
+ /* See comment in copy_fxregs_to_kernel() below. */
+ return user_insn(rex64/fxsave (%[fx]), "=m" (*fx), [fx] "R" (fx));
+}
+
+static inline void copy_kernel_to_fxregs(struct fxregs_state *fx)
+{
+ int err;
+
+ if (config_enabled(CONFIG_X86_32)) {
+ err = check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
+ } else {
+ if (config_enabled(CONFIG_AS_FXSAVEQ)) {
+ err = check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
+ } else {
+ /* See comment in copy_fxregs_to_kernel() below. */
+ err = check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), "m" (*fx));
+ }
+ }
+ /* Copying from a kernel buffer to FPU registers should never fail: */
+ WARN_ON_FPU(err);
+}
+
+static inline int copy_user_to_fxregs(struct fxregs_state __user *fx)
+{
+ if (config_enabled(CONFIG_X86_32))
+ return user_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
+ else if (config_enabled(CONFIG_AS_FXSAVEQ))
+ return user_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
+
+ /* See comment in copy_fxregs_to_kernel() below. */
+ return user_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx),
+ "m" (*fx));
+}
+
+static inline void copy_kernel_to_fregs(struct fregs_state *fx)
+{
+ int err = check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
+
+ WARN_ON_FPU(err);
+}
+
+static inline int copy_user_to_fregs(struct fregs_state __user *fx)
+{
+ return user_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
+}
+
+static inline void copy_fxregs_to_kernel(struct fpu *fpu)
+{
+ if (config_enabled(CONFIG_X86_32))
+ asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state.fxsave));
+ else if (config_enabled(CONFIG_AS_FXSAVEQ))
+ asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave));
+ else {
+ /* Using "rex64; fxsave %0" is broken because, if the memory
+ * operand uses any extended registers for addressing, a second
+ * REX prefix will be generated (to the assembler, rex64
+ * followed by semicolon is a separate instruction), and hence
+ * the 64-bitness is lost.
+ *
+ * Using "fxsaveq %0" would be the ideal choice, but is only
+ * supported starting with gas 2.16.
+ *
+ * Using, as a workaround, the properly prefixed form below
+ * isn't accepted by any binutils version so far released,
+ * complaining that the same type of prefix is used twice if
+ * an extended register is needed for addressing (fix submitted
+ * to mainline 2005-11-21).
+ *
+ * asm volatile("rex64/fxsave %0" : "=m" (fpu->state.fxsave));
+ *
+ * This, however, we can work around by forcing the compiler to
+ * select an addressing mode that doesn't require extended
+ * registers.
+ */
+ asm volatile( "rex64/fxsave (%[fx])"
+ : "=m" (fpu->state.fxsave)
+ : [fx] "R" (&fpu->state.fxsave));
+ }
+}
+
+/* These macros all use (%edi)/(%rdi) as the single memory argument. */
+#define XSAVE ".byte " REX_PREFIX "0x0f,0xae,0x27"
+#define XSAVEOPT ".byte " REX_PREFIX "0x0f,0xae,0x37"
+#define XSAVES ".byte " REX_PREFIX "0x0f,0xc7,0x2f"
+#define XRSTOR ".byte " REX_PREFIX "0x0f,0xae,0x2f"
+#define XRSTORS ".byte " REX_PREFIX "0x0f,0xc7,0x1f"
+
+/* xstate instruction fault handler: */
+#define xstate_fault(__err) \
+ \
+ ".section .fixup,\"ax\"\n" \
+ \
+ "3: movl $-2,%[_err]\n" \
+ " jmp 2b\n" \
+ \
+ ".previous\n" \
+ \
+ _ASM_EXTABLE(1b, 3b) \
+ : [_err] "=r" (__err)
+
+/*
+ * This function is called only during boot time when x86 caps are not set
+ * up and alternative can not be used yet.
+ */
+static inline void copy_xregs_to_kernel_booting(struct xregs_state *xstate)
+{
+ u64 mask = -1;
+ u32 lmask = mask;
+ u32 hmask = mask >> 32;
+ int err = 0;
+
+ WARN_ON(system_state != SYSTEM_BOOTING);
+
+ if (boot_cpu_has(X86_FEATURE_XSAVES))
+ asm volatile("1:"XSAVES"\n\t"
+ "2:\n\t"
+ xstate_fault(err)
+ : "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
+ : "memory");
+ else
+ asm volatile("1:"XSAVE"\n\t"
+ "2:\n\t"
+ xstate_fault(err)
+ : "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
+ : "memory");
+
+ /* We should never fault when copying to a kernel buffer: */
+ WARN_ON_FPU(err);
+}
+
+/*
+ * This function is called only during boot time when x86 caps are not set
+ * up and alternative can not be used yet.
+ */
+static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate)
+{
+ u64 mask = -1;
+ u32 lmask = mask;
+ u32 hmask = mask >> 32;
+ int err = 0;
+
+ WARN_ON(system_state != SYSTEM_BOOTING);
+
+ if (boot_cpu_has(X86_FEATURE_XSAVES))
+ asm volatile("1:"XRSTORS"\n\t"
+ "2:\n\t"
+ xstate_fault(err)
+ : "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
+ : "memory");
+ else
+ asm volatile("1:"XRSTOR"\n\t"
+ "2:\n\t"
+ xstate_fault(err)
+ : "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
+ : "memory");
+
+ /* We should never fault when copying from a kernel buffer: */
+ WARN_ON_FPU(err);
+}
+
+/*
+ * Save processor xstate to xsave area.
+ */
+static inline void copy_xregs_to_kernel(struct xregs_state *xstate)
+{
+ u64 mask = -1;
+ u32 lmask = mask;
+ u32 hmask = mask >> 32;
+ int err = 0;
+
+ WARN_ON(!alternatives_patched);
+
+ /*
+ * If xsaves is enabled, xsaves replaces xsaveopt because
+ * it supports compact format and supervisor states in addition to
+ * modified optimization in xsaveopt.
+ *
+ * Otherwise, if xsaveopt is enabled, xsaveopt replaces xsave
+ * because xsaveopt supports modified optimization which is not
+ * supported by xsave.
+ *
+ * If none of xsaves and xsaveopt is enabled, use xsave.
+ */
+ alternative_input_2(
+ "1:"XSAVE,
+ XSAVEOPT,
+ X86_FEATURE_XSAVEOPT,
+ XSAVES,
+ X86_FEATURE_XSAVES,
+ [xstate] "D" (xstate), "a" (lmask), "d" (hmask) :
+ "memory");
+ asm volatile("2:\n\t"
+ xstate_fault(err)
+ : "0" (err)
+ : "memory");
+
+ /* We should never fault when copying to a kernel buffer: */
+ WARN_ON_FPU(err);
+}
+
+/*
+ * Restore processor xstate from xsave area.
+ */
+static inline void copy_kernel_to_xregs(struct xregs_state *xstate, u64 mask)
+{
+ u32 lmask = mask;
+ u32 hmask = mask >> 32;
+ int err = 0;
+
+ /*
+ * Use xrstors to restore context if it is enabled. xrstors supports
+ * compacted format of xsave area which is not supported by xrstor.
+ */
+ alternative_input(
+ "1: " XRSTOR,
+ XRSTORS,
+ X86_FEATURE_XSAVES,
+ "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask)
+ : "memory");
+
+ asm volatile("2:\n"
+ xstate_fault(err)
+ : "0" (err)
+ : "memory");
+
+ /* We should never fault when copying from a kernel buffer: */
+ WARN_ON_FPU(err);
+}
+
+/*
+ * Save xstate to user space xsave area.
+ *
+ * We don't use modified optimization because xrstor/xrstors might track
+ * a different application.
+ *
+ * We don't use compacted format xsave area for
+ * backward compatibility for old applications which don't understand
+ * compacted format of xsave area.
+ */
+static inline int copy_xregs_to_user(struct xregs_state __user *buf)
+{
+ int err;
+
+ /*
+ * Clear the xsave header first, so that reserved fields are
+ * initialized to zero.
+ */
+ err = __clear_user(&buf->header, sizeof(buf->header));
+ if (unlikely(err))
+ return -EFAULT;
+
+ __asm__ __volatile__(ASM_STAC "\n"
+ "1:"XSAVE"\n"
+ "2: " ASM_CLAC "\n"
+ xstate_fault(err)
+ : "D" (buf), "a" (-1), "d" (-1), "0" (err)
+ : "memory");
+ return err;
+}
+
+/*
+ * Restore xstate from user space xsave area.
+ */
+static inline int copy_user_to_xregs(struct xregs_state __user *buf, u64 mask)
+{
+ struct xregs_state *xstate = ((__force struct xregs_state *)buf);
+ u32 lmask = mask;
+ u32 hmask = mask >> 32;
+ int err = 0;
+
+ __asm__ __volatile__(ASM_STAC "\n"
+ "1:"XRSTOR"\n"
+ "2: " ASM_CLAC "\n"
+ xstate_fault(err)
+ : "D" (xstate), "a" (lmask), "d" (hmask), "0" (err)
+ : "memory"); /* memory required? */
+ return err;
+}
+
+/*
+ * These must be called with preempt disabled. Returns
+ * 'true' if the FPU state is still intact and we can
+ * keep registers active.
+ *
+ * The legacy FNSAVE instruction cleared all FPU state
+ * unconditionally, so registers are essentially destroyed.
+ * Modern FPU state can be kept in registers, if there are
+ * no pending FP exceptions.
+ */
+static inline int copy_fpregs_to_fpstate(struct fpu *fpu)
+{
+ if (likely(use_xsave())) {
+ copy_xregs_to_kernel(&fpu->state.xsave);
+ return 1;
+ }
+
+ if (likely(use_fxsr())) {
+ copy_fxregs_to_kernel(fpu);
+ return 1;
+ }
+
+ /*
+ * Legacy FPU register saving, FNSAVE always clears FPU registers,
+ * so we have to mark them inactive:
+ */
+ asm volatile("fnsave %[fp]; fwait" : [fp] "=m" (fpu->state.fsave));
+
+ return 0;
+}
+
+static inline void __copy_kernel_to_fpregs(union fpregs_state *fpstate)
+{
+ if (use_xsave()) {
+ copy_kernel_to_xregs(&fpstate->xsave, -1);
+ } else {
+ if (use_fxsr())
+ copy_kernel_to_fxregs(&fpstate->fxsave);
+ else
+ copy_kernel_to_fregs(&fpstate->fsave);
+ }
+}
+
+static inline void copy_kernel_to_fpregs(union fpregs_state *fpstate)
+{
+ /*
+ * AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception is
+ * pending. Clear the x87 state here by setting it to fixed values.
+ * "m" is a random variable that should be in L1.
+ */
+ if (unlikely(static_cpu_has_bug_safe(X86_BUG_FXSAVE_LEAK))) {
+ asm volatile(
+ "fnclex\n\t"
+ "emms\n\t"
+ "fildl %P[addr]" /* set F?P to defined value */
+ : : [addr] "m" (fpstate));
+ }
+
+ __copy_kernel_to_fpregs(fpstate);
+}
+
+extern int copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size);
+
+/*
+ * FPU context switch related helper methods:
+ */
+
+DECLARE_PER_CPU(struct fpu *, fpu_fpregs_owner_ctx);
+
+/*
+ * Must be run with preemption disabled: this clears the fpu_fpregs_owner_ctx,
+ * on this CPU.
+ *
+ * This will disable any lazy FPU state restore of the current FPU state,
+ * but if the current thread owns the FPU, it will still be saved by.
+ */
+static inline void __cpu_disable_lazy_restore(unsigned int cpu)
+{
+ per_cpu(fpu_fpregs_owner_ctx, cpu) = NULL;
+}
+
+static inline int fpu_want_lazy_restore(struct fpu *fpu, unsigned int cpu)
+{
+ return fpu == this_cpu_read_stable(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
+}
+
+
+/*
+ * Wrap lazy FPU TS handling in a 'hw fpregs activation/deactivation'
+ * idiom, which is then paired with the sw-flag (fpregs_active) later on:
+ */
+
+static inline void __fpregs_activate_hw(void)
+{
+ if (!use_eager_fpu())
+ clts();
+}
+
+static inline void __fpregs_deactivate_hw(void)
+{
+ if (!use_eager_fpu())
+ stts();
+}
+
+/* Must be paired with an 'stts' (fpregs_deactivate_hw()) after! */
+static inline void __fpregs_deactivate(struct fpu *fpu)
+{
+ WARN_ON_FPU(!fpu->fpregs_active);
+
+ fpu->fpregs_active = 0;
+ this_cpu_write(fpu_fpregs_owner_ctx, NULL);
+}
+
+/* Must be paired with a 'clts' (fpregs_activate_hw()) before! */
+static inline void __fpregs_activate(struct fpu *fpu)
+{
+ WARN_ON_FPU(fpu->fpregs_active);
+
+ fpu->fpregs_active = 1;
+ this_cpu_write(fpu_fpregs_owner_ctx, fpu);
+}
+
+/*
+ * The question "does this thread have fpu access?"
+ * is slightly racy, since preemption could come in
+ * and revoke it immediately after the test.
+ *
+ * However, even in that very unlikely scenario,
+ * we can just assume we have FPU access - typically
+ * to save the FP state - we'll just take a #NM
+ * fault and get the FPU access back.
+ */
+static inline int fpregs_active(void)
+{
+ return current->thread.fpu.fpregs_active;
+}
+
+/*
+ * Encapsulate the CR0.TS handling together with the
+ * software flag.
+ *
+ * These generally need preemption protection to work,
+ * do try to avoid using these on their own.
+ */
+static inline void fpregs_activate(struct fpu *fpu)
+{
+ __fpregs_activate_hw();
+ __fpregs_activate(fpu);
+}
+
+static inline void fpregs_deactivate(struct fpu *fpu)
+{
+ __fpregs_deactivate(fpu);
+ __fpregs_deactivate_hw();
+}
+
+/*
+ * FPU state switching for scheduling.
+ *
+ * This is a two-stage process:
+ *
+ * - switch_fpu_prepare() saves the old state and
+ * sets the new state of the CR0.TS bit. This is
+ * done within the context of the old process.
+ *
+ * - switch_fpu_finish() restores the new state as
+ * necessary.
+ */
+typedef struct { int preload; } fpu_switch_t;
+
+static inline fpu_switch_t
+switch_fpu_prepare(struct fpu *old_fpu, struct fpu *new_fpu, int cpu)
+{
+ fpu_switch_t fpu;
+
+ /*
+ * If the task has used the math, pre-load the FPU on xsave processors
+ * or if the past 5 consecutive context-switches used math.
+ */
+ fpu.preload = new_fpu->fpstate_active &&
+ (use_eager_fpu() || new_fpu->counter > 5);
+
+ if (old_fpu->fpregs_active) {
+ if (!copy_fpregs_to_fpstate(old_fpu))
+ old_fpu->last_cpu = -1;
+ else
+ old_fpu->last_cpu = cpu;
+
+ /* But leave fpu_fpregs_owner_ctx! */
+ old_fpu->fpregs_active = 0;
+
+ /* Don't change CR0.TS if we just switch! */
+ if (fpu.preload) {
+ new_fpu->counter++;
+ __fpregs_activate(new_fpu);
+ prefetch(&new_fpu->state);
+ } else {
+ __fpregs_deactivate_hw();
+ }
+ } else {
+ old_fpu->counter = 0;
+ old_fpu->last_cpu = -1;
+ if (fpu.preload) {
+ new_fpu->counter++;
+ if (fpu_want_lazy_restore(new_fpu, cpu))
+ fpu.preload = 0;
+ else
+ prefetch(&new_fpu->state);
+ fpregs_activate(new_fpu);
+ }
+ }
+ return fpu;
+}
+
+/*
+ * Misc helper functions:
+ */
+
+/*
+ * By the time this gets called, we've already cleared CR0.TS and
+ * given the process the FPU if we are going to preload the FPU
+ * state - all we need to do is to conditionally restore the register
+ * state itself.
+ */
+static inline void switch_fpu_finish(struct fpu *new_fpu, fpu_switch_t fpu_switch)
+{
+ if (fpu_switch.preload)
+ copy_kernel_to_fpregs(&new_fpu->state);
+}
+
+/*
+ * Needs to be preemption-safe.
+ *
+ * NOTE! user_fpu_begin() must be used only immediately before restoring
+ * the save state. It does not do any saving/restoring on its own. In
+ * lazy FPU mode, it is just an optimization to avoid a #NM exception,
+ * the task can lose the FPU right after preempt_enable().
+ */
+static inline void user_fpu_begin(void)
+{
+ struct fpu *fpu = &current->thread.fpu;
+
+ preempt_disable();
+ if (!fpregs_active())
+ fpregs_activate(fpu);
+ preempt_enable();
+}
+
+/*
+ * MXCSR and XCR definitions:
+ */
+
+extern unsigned int mxcsr_feature_mask;
+
+#define XCR_XFEATURE_ENABLED_MASK 0x00000000
+
+static inline u64 xgetbv(u32 index)
+{
+ u32 eax, edx;
+
+ asm volatile(".byte 0x0f,0x01,0xd0" /* xgetbv */
+ : "=a" (eax), "=d" (edx)
+ : "c" (index));
+ return eax + ((u64)edx << 32);
+}
+
+static inline void xsetbv(u32 index, u64 value)
+{
+ u32 eax = value;
+ u32 edx = value >> 32;
+
+ asm volatile(".byte 0x0f,0x01,0xd1" /* xsetbv */
+ : : "a" (eax), "d" (edx), "c" (index));
+}
+
+#endif /* _ASM_X86_FPU_INTERNAL_H */
diff --git a/arch/x86/include/asm/fpu/regset.h b/arch/x86/include/asm/fpu/regset.h
new file mode 100644
index 000000000000..39d3107ac6c7
--- /dev/null
+++ b/arch/x86/include/asm/fpu/regset.h
@@ -0,0 +1,21 @@
+/*
+ * FPU regset handling methods:
+ */
+#ifndef _ASM_X86_FPU_REGSET_H
+#define _ASM_X86_FPU_REGSET_H
+
+#include <linux/regset.h>
+
+extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active;
+extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
+ xstateregs_get;
+extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
+ xstateregs_set;
+
+/*
+ * xstateregs_active == regset_fpregs_active. Please refer to the comment
+ * at the definition of regset_fpregs_active.
+ */
+#define xstateregs_active regset_fpregs_active
+
+#endif /* _ASM_X86_FPU_REGSET_H */
diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/signal.h
new file mode 100644
index 000000000000..7358e9d61f1e
--- /dev/null
+++ b/arch/x86/include/asm/fpu/signal.h
@@ -0,0 +1,33 @@
+/*
+ * x86 FPU signal frame handling methods:
+ */
+#ifndef _ASM_X86_FPU_SIGNAL_H
+#define _ASM_X86_FPU_SIGNAL_H
+
+#ifdef CONFIG_X86_64
+# include <asm/sigcontext32.h>
+# include <asm/user32.h>
+struct ksignal;
+int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
+ compat_sigset_t *set, struct pt_regs *regs);
+int ia32_setup_frame(int sig, struct ksignal *ksig,
+ compat_sigset_t *set, struct pt_regs *regs);
+#else
+# define user_i387_ia32_struct user_i387_struct
+# define user32_fxsr_struct user_fxsr_struct
+# define ia32_setup_frame __setup_frame
+# define ia32_setup_rt_frame __setup_rt_frame
+#endif
+
+extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
+ struct task_struct *tsk);
+extern void convert_to_fxsr(struct task_struct *tsk,
+ const struct user_i387_ia32_struct *env);
+
+unsigned long
+fpu__alloc_mathframe(unsigned long sp, int ia32_frame,
+ unsigned long *buf_fx, unsigned long *size);
+
+extern void fpu__init_prepare_fx_sw_frame(void);
+
+#endif /* _ASM_X86_FPU_SIGNAL_H */
diff --git a/arch/x86/include/asm/fpu/types.h b/arch/x86/include/asm/fpu/types.h
new file mode 100644
index 000000000000..0637826292de
--- /dev/null
+++ b/arch/x86/include/asm/fpu/types.h
@@ -0,0 +1,293 @@
+/*
+ * FPU data structures:
+ */
+#ifndef _ASM_X86_FPU_H
+#define _ASM_X86_FPU_H
+
+/*
+ * The legacy x87 FPU state format, as saved by FSAVE and
+ * restored by the FRSTOR instructions:
+ */
+struct fregs_state {
+ u32 cwd; /* FPU Control Word */
+ u32 swd; /* FPU Status Word */
+ u32 twd; /* FPU Tag Word */
+ u32 fip; /* FPU IP Offset */
+ u32 fcs; /* FPU IP Selector */
+ u32 foo; /* FPU Operand Pointer Offset */
+ u32 fos; /* FPU Operand Pointer Selector */
+
+ /* 8*10 bytes for each FP-reg = 80 bytes: */
+ u32 st_space[20];
+
+ /* Software status information [not touched by FSAVE]: */
+ u32 status;
+};
+
+/*
+ * The legacy fx SSE/MMX FPU state format, as saved by FXSAVE and
+ * restored by the FXRSTOR instructions. It's similar to the FSAVE
+ * format, but differs in some areas, plus has extensions at
+ * the end for the XMM registers.
+ */
+struct fxregs_state {
+ u16 cwd; /* Control Word */
+ u16 swd; /* Status Word */
+ u16 twd; /* Tag Word */
+ u16 fop; /* Last Instruction Opcode */
+ union {
+ struct {
+ u64 rip; /* Instruction Pointer */
+ u64 rdp; /* Data Pointer */
+ };
+ struct {
+ u32 fip; /* FPU IP Offset */
+ u32 fcs; /* FPU IP Selector */
+ u32 foo; /* FPU Operand Offset */
+ u32 fos; /* FPU Operand Selector */
+ };
+ };
+ u32 mxcsr; /* MXCSR Register State */
+ u32 mxcsr_mask; /* MXCSR Mask */
+
+ /* 8*16 bytes for each FP-reg = 128 bytes: */
+ u32 st_space[32];
+
+ /* 16*16 bytes for each XMM-reg = 256 bytes: */
+ u32 xmm_space[64];
+
+ u32 padding[12];
+
+ union {
+ u32 padding1[12];
+ u32 sw_reserved[12];
+ };
+
+} __attribute__((aligned(16)));
+
+/* Default value for fxregs_state.mxcsr: */
+#define MXCSR_DEFAULT 0x1f80
+
+/*
+ * Software based FPU emulation state. This is arbitrary really,
+ * it matches the x87 format to make it easier to understand:
+ */
+struct swregs_state {
+ u32 cwd;
+ u32 swd;
+ u32 twd;
+ u32 fip;
+ u32 fcs;
+ u32 foo;
+ u32 fos;
+ /* 8*10 bytes for each FP-reg = 80 bytes: */
+ u32 st_space[20];
+ u8 ftop;
+ u8 changed;
+ u8 lookahead;
+ u8 no_update;
+ u8 rm;
+ u8 alimit;
+ struct math_emu_info *info;
+ u32 entry_eip;
+};
+
+/*
+ * List of XSAVE features Linux knows about:
+ */
+enum xfeature_bit {
+ XSTATE_BIT_FP,
+ XSTATE_BIT_SSE,
+ XSTATE_BIT_YMM,
+ XSTATE_BIT_BNDREGS,
+ XSTATE_BIT_BNDCSR,
+ XSTATE_BIT_OPMASK,
+ XSTATE_BIT_ZMM_Hi256,
+ XSTATE_BIT_Hi16_ZMM,
+
+ XFEATURES_NR_MAX,
+};
+
+#define XSTATE_FP (1 << XSTATE_BIT_FP)
+#define XSTATE_SSE (1 << XSTATE_BIT_SSE)
+#define XSTATE_YMM (1 << XSTATE_BIT_YMM)
+#define XSTATE_BNDREGS (1 << XSTATE_BIT_BNDREGS)
+#define XSTATE_BNDCSR (1 << XSTATE_BIT_BNDCSR)
+#define XSTATE_OPMASK (1 << XSTATE_BIT_OPMASK)
+#define XSTATE_ZMM_Hi256 (1 << XSTATE_BIT_ZMM_Hi256)
+#define XSTATE_Hi16_ZMM (1 << XSTATE_BIT_Hi16_ZMM)
+
+#define XSTATE_FPSSE (XSTATE_FP | XSTATE_SSE)
+#define XSTATE_AVX512 (XSTATE_OPMASK | XSTATE_ZMM_Hi256 | XSTATE_Hi16_ZMM)
+
+/*
+ * There are 16x 256-bit AVX registers named YMM0-YMM15.
+ * The low 128 bits are aliased to the 16 SSE registers (XMM0-XMM15)
+ * and are stored in 'struct fxregs_state::xmm_space[]'.
+ *
+ * The high 128 bits are stored here:
+ * 16x 128 bits == 256 bytes.
+ */
+struct ymmh_struct {
+ u8 ymmh_space[256];
+};
+
+/* We don't support LWP yet: */
+struct lwp_struct {
+ u8 reserved[128];
+};
+
+/* Intel MPX support: */
+struct bndreg {
+ u64 lower_bound;
+ u64 upper_bound;
+} __packed;
+
+struct bndcsr {
+ u64 bndcfgu;
+ u64 bndstatus;
+} __packed;
+
+struct mpx_struct {
+ struct bndreg bndreg[4];
+ struct bndcsr bndcsr;
+};
+
+struct xstate_header {
+ u64 xfeatures;
+ u64 xcomp_bv;
+ u64 reserved[6];
+} __attribute__((packed));
+
+/* New processor state extensions should be added here: */
+#define XSTATE_RESERVE (sizeof(struct ymmh_struct) + \
+ sizeof(struct lwp_struct) + \
+ sizeof(struct mpx_struct) )
+/*
+ * This is our most modern FPU state format, as saved by the XSAVE
+ * and restored by the XRSTOR instructions.
+ *
+ * It consists of a legacy fxregs portion, an xstate header and
+ * subsequent fixed size areas as defined by the xstate header.
+ * Not all CPUs support all the extensions.
+ */
+struct xregs_state {
+ struct fxregs_state i387;
+ struct xstate_header header;
+ u8 __reserved[XSTATE_RESERVE];
+} __attribute__ ((packed, aligned (64)));
+
+/*
+ * This is a union of all the possible FPU state formats
+ * put together, so that we can pick the right one runtime.
+ *
+ * The size of the structure is determined by the largest
+ * member - which is the xsave area:
+ */
+union fpregs_state {
+ struct fregs_state fsave;
+ struct fxregs_state fxsave;
+ struct swregs_state soft;
+ struct xregs_state xsave;
+};
+
+/*
+ * Highest level per task FPU state data structure that
+ * contains the FPU register state plus various FPU
+ * state fields:
+ */
+struct fpu {
+ /*
+ * @state:
+ *
+ * In-memory copy of all FPU registers that we save/restore
+ * over context switches. If the task is using the FPU then
+ * the registers in the FPU are more recent than this state
+ * copy. If the task context-switches away then they get
+ * saved here and represent the FPU state.
+ *
+ * After context switches there may be a (short) time period
+ * during which the in-FPU hardware registers are unchanged
+ * and still perfectly match this state, if the tasks
+ * scheduled afterwards are not using the FPU.
+ *
+ * This is the 'lazy restore' window of optimization, which
+ * we track though 'fpu_fpregs_owner_ctx' and 'fpu->last_cpu'.
+ *
+ * We detect whether a subsequent task uses the FPU via setting
+ * CR0::TS to 1, which causes any FPU use to raise a #NM fault.
+ *
+ * During this window, if the task gets scheduled again, we
+ * might be able to skip having to do a restore from this
+ * memory buffer to the hardware registers - at the cost of
+ * incurring the overhead of #NM fault traps.
+ *
+ * Note that on modern CPUs that support the XSAVEOPT (or other
+ * optimized XSAVE instructions), we don't use #NM traps anymore,
+ * as the hardware can track whether FPU registers need saving
+ * or not. On such CPUs we activate the non-lazy ('eagerfpu')
+ * logic, which unconditionally saves/restores all FPU state
+ * across context switches. (if FPU state exists.)
+ */
+ union fpregs_state state;
+
+ /*
+ * @last_cpu:
+ *
+ * Records the last CPU on which this context was loaded into
+ * FPU registers. (In the lazy-restore case we might be
+ * able to reuse FPU registers across multiple context switches
+ * this way, if no intermediate task used the FPU.)
+ *
+ * A value of -1 is used to indicate that the FPU state in context
+ * memory is newer than the FPU state in registers, and that the
+ * FPU state should be reloaded next time the task is run.
+ */
+ unsigned int last_cpu;
+
+ /*
+ * @fpstate_active:
+ *
+ * This flag indicates whether this context is active: if the task
+ * is not running then we can restore from this context, if the task
+ * is running then we should save into this context.
+ */
+ unsigned char fpstate_active;
+
+ /*
+ * @fpregs_active:
+ *
+ * This flag determines whether a given context is actively
+ * loaded into the FPU's registers and that those registers
+ * represent the task's current FPU state.
+ *
+ * Note the interaction with fpstate_active:
+ *
+ * # task does not use the FPU:
+ * fpstate_active == 0
+ *
+ * # task uses the FPU and regs are active:
+ * fpstate_active == 1 && fpregs_active == 1
+ *
+ * # the regs are inactive but still match fpstate:
+ * fpstate_active == 1 && fpregs_active == 0 && fpregs_owner == fpu
+ *
+ * The third state is what we use for the lazy restore optimization
+ * on lazy-switching CPUs.
+ */
+ unsigned char fpregs_active;
+
+ /*
+ * @counter:
+ *
+ * This counter contains the number of consecutive context switches
+ * during which the FPU stays used. If this is over a threshold, the
+ * lazy FPU restore logic becomes eager, to save the trap overhead.
+ * This is an unsigned char so that after 256 iterations the counter
+ * wraps and the context switch behavior turns lazy again; this is to
+ * deal with bursty apps that only use the FPU for a short time:
+ */
+ unsigned char counter;
+};
+
+#endif /* _ASM_X86_FPU_H */
diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h
new file mode 100644
index 000000000000..4656b25bb9a7
--- /dev/null
+++ b/arch/x86/include/asm/fpu/xstate.h
@@ -0,0 +1,46 @@
+#ifndef __ASM_X86_XSAVE_H
+#define __ASM_X86_XSAVE_H
+
+#include <linux/types.h>
+#include <asm/processor.h>
+#include <linux/uaccess.h>
+
+/* Bit 63 of XCR0 is reserved for future expansion */
+#define XSTATE_EXTEND_MASK (~(XSTATE_FPSSE | (1ULL << 63)))
+
+#define XSTATE_CPUID 0x0000000d
+
+#define FXSAVE_SIZE 512
+
+#define XSAVE_HDR_SIZE 64
+#define XSAVE_HDR_OFFSET FXSAVE_SIZE
+
+#define XSAVE_YMM_SIZE 256
+#define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET)
+
+/* Supported features which support lazy state saving */
+#define XSTATE_LAZY (XSTATE_FP | XSTATE_SSE | XSTATE_YMM \
+ | XSTATE_OPMASK | XSTATE_ZMM_Hi256 | XSTATE_Hi16_ZMM)
+
+/* Supported features which require eager state saving */
+#define XSTATE_EAGER (XSTATE_BNDREGS | XSTATE_BNDCSR)
+
+/* All currently supported features */
+#define XCNTXT_MASK (XSTATE_LAZY | XSTATE_EAGER)
+
+#ifdef CONFIG_X86_64
+#define REX_PREFIX "0x48, "
+#else
+#define REX_PREFIX
+#endif
+
+extern unsigned int xstate_size;
+extern u64 xfeatures_mask;
+extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
+
+extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask);
+
+void *get_xsave_addr(struct xregs_state *xsave, int xstate);
+const void *get_xsave_field_ptr(int xstate_field);
+
+#endif
diff --git a/arch/x86/include/asm/frame.h b/arch/x86/include/asm/frame.h
index 3b629f47eb65..793179cf8e21 100644
--- a/arch/x86/include/asm/frame.h
+++ b/arch/x86/include/asm/frame.h
@@ -1,20 +1,17 @@
#ifdef __ASSEMBLY__
#include <asm/asm.h>
-#include <asm/dwarf2.h>
/* The annotation hides the frame from the unwinder and makes it look
like a ordinary ebp save/restore. This avoids some special cases for
frame pointer later */
#ifdef CONFIG_FRAME_POINTER
.macro FRAME
- __ASM_SIZE(push,_cfi) %__ASM_REG(bp)
- CFI_REL_OFFSET __ASM_REG(bp), 0
+ __ASM_SIZE(push,) %__ASM_REG(bp)
__ASM_SIZE(mov) %__ASM_REG(sp), %__ASM_REG(bp)
.endm
.macro ENDFRAME
- __ASM_SIZE(pop,_cfi) %__ASM_REG(bp)
- CFI_RESTORE __ASM_REG(bp)
+ __ASM_SIZE(pop,) %__ASM_REG(bp)
.endm
#else
.macro FRAME
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index 0f5fb6b6567e..7178043b0e1d 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -14,6 +14,7 @@ typedef struct {
#endif
#ifdef CONFIG_HAVE_KVM
unsigned int kvm_posted_intr_ipis;
+ unsigned int kvm_posted_intr_wakeup_ipis;
#endif
unsigned int x86_platform_ipis; /* arch dependent */
unsigned int apic_perf_irqs;
@@ -33,6 +34,9 @@ typedef struct {
#ifdef CONFIG_X86_MCE_THRESHOLD
unsigned int irq_threshold_count;
#endif
+#ifdef CONFIG_X86_MCE_AMD
+ unsigned int irq_deferred_error_count;
+#endif
#if IS_ENABLED(CONFIG_HYPERV) || defined(CONFIG_XEN)
unsigned int irq_hv_callback_count;
#endif
diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h
index 36f7125945e3..5fa9fb0f8809 100644
--- a/arch/x86/include/asm/hpet.h
+++ b/arch/x86/include/asm/hpet.h
@@ -74,20 +74,16 @@ extern unsigned int hpet_readl(unsigned int a);
extern void force_hpet_resume(void);
struct irq_data;
+struct hpet_dev;
+struct irq_domain;
+
extern void hpet_msi_unmask(struct irq_data *data);
extern void hpet_msi_mask(struct irq_data *data);
-struct hpet_dev;
extern void hpet_msi_write(struct hpet_dev *hdev, struct msi_msg *msg);
extern void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg);
-
-#ifdef CONFIG_PCI_MSI
-extern int default_setup_hpet_msi(unsigned int irq, unsigned int id);
-#else
-static inline int default_setup_hpet_msi(unsigned int irq, unsigned int id)
-{
- return -EINVAL;
-}
-#endif
+extern struct irq_domain *hpet_create_irq_domain(int hpet_id);
+extern int hpet_assign_irq(struct irq_domain *domain,
+ struct hpet_dev *dev, int dev_num);
#ifdef CONFIG_HPET_EMULATE_RTC
diff --git a/arch/x86/include/asm/hugetlb.h b/arch/x86/include/asm/hugetlb.h
index 68c05398bba9..f8a29d2c97b0 100644
--- a/arch/x86/include/asm/hugetlb.h
+++ b/arch/x86/include/asm/hugetlb.h
@@ -26,9 +26,6 @@ static inline int prepare_hugepage_range(struct file *file,
return 0;
}
-static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm) {
-}
-
static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
unsigned long addr, unsigned long end,
unsigned long floor,
@@ -83,15 +80,6 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
return *ptep;
}
-static inline int arch_prepare_hugepage(struct page *page)
-{
- return 0;
-}
-
-static inline void arch_release_hugepage(struct page *page)
-{
-}
-
static inline void arch_clear_hugepage_flags(struct page *page)
{
}
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index e9571ddabc4f..6615032e19c8 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -29,6 +29,7 @@
extern asmlinkage void apic_timer_interrupt(void);
extern asmlinkage void x86_platform_ipi(void);
extern asmlinkage void kvm_posted_intr_ipi(void);
+extern asmlinkage void kvm_posted_intr_wakeup_ipi(void);
extern asmlinkage void error_interrupt(void);
extern asmlinkage void irq_work_interrupt(void);
@@ -36,43 +37,10 @@ extern asmlinkage void spurious_interrupt(void);
extern asmlinkage void thermal_interrupt(void);
extern asmlinkage void reschedule_interrupt(void);
-extern asmlinkage void invalidate_interrupt(void);
-extern asmlinkage void invalidate_interrupt0(void);
-extern asmlinkage void invalidate_interrupt1(void);
-extern asmlinkage void invalidate_interrupt2(void);
-extern asmlinkage void invalidate_interrupt3(void);
-extern asmlinkage void invalidate_interrupt4(void);
-extern asmlinkage void invalidate_interrupt5(void);
-extern asmlinkage void invalidate_interrupt6(void);
-extern asmlinkage void invalidate_interrupt7(void);
-extern asmlinkage void invalidate_interrupt8(void);
-extern asmlinkage void invalidate_interrupt9(void);
-extern asmlinkage void invalidate_interrupt10(void);
-extern asmlinkage void invalidate_interrupt11(void);
-extern asmlinkage void invalidate_interrupt12(void);
-extern asmlinkage void invalidate_interrupt13(void);
-extern asmlinkage void invalidate_interrupt14(void);
-extern asmlinkage void invalidate_interrupt15(void);
-extern asmlinkage void invalidate_interrupt16(void);
-extern asmlinkage void invalidate_interrupt17(void);
-extern asmlinkage void invalidate_interrupt18(void);
-extern asmlinkage void invalidate_interrupt19(void);
-extern asmlinkage void invalidate_interrupt20(void);
-extern asmlinkage void invalidate_interrupt21(void);
-extern asmlinkage void invalidate_interrupt22(void);
-extern asmlinkage void invalidate_interrupt23(void);
-extern asmlinkage void invalidate_interrupt24(void);
-extern asmlinkage void invalidate_interrupt25(void);
-extern asmlinkage void invalidate_interrupt26(void);
-extern asmlinkage void invalidate_interrupt27(void);
-extern asmlinkage void invalidate_interrupt28(void);
-extern asmlinkage void invalidate_interrupt29(void);
-extern asmlinkage void invalidate_interrupt30(void);
-extern asmlinkage void invalidate_interrupt31(void);
-
extern asmlinkage void irq_move_cleanup_interrupt(void);
extern asmlinkage void reboot_interrupt(void);
extern asmlinkage void threshold_interrupt(void);
+extern asmlinkage void deferred_error_interrupt(void);
extern asmlinkage void call_function_interrupt(void);
extern asmlinkage void call_function_single_interrupt(void);
@@ -87,60 +55,93 @@ extern void trace_spurious_interrupt(void);
extern void trace_thermal_interrupt(void);
extern void trace_reschedule_interrupt(void);
extern void trace_threshold_interrupt(void);
+extern void trace_deferred_error_interrupt(void);
extern void trace_call_function_interrupt(void);
extern void trace_call_function_single_interrupt(void);
#define trace_irq_move_cleanup_interrupt irq_move_cleanup_interrupt
#define trace_reboot_interrupt reboot_interrupt
#define trace_kvm_posted_intr_ipi kvm_posted_intr_ipi
+#define trace_kvm_posted_intr_wakeup_ipi kvm_posted_intr_wakeup_ipi
#endif /* CONFIG_TRACING */
-#ifdef CONFIG_IRQ_REMAP
-/* Intel specific interrupt remapping information */
-struct irq_2_iommu {
- struct intel_iommu *iommu;
- u16 irte_index;
- u16 sub_handle;
- u8 irte_mask;
-};
-
-/* AMD specific interrupt remapping information */
-struct irq_2_irte {
- u16 devid; /* Device ID for IRTE table */
- u16 index; /* Index into IRTE table*/
-};
-#endif /* CONFIG_IRQ_REMAP */
-
#ifdef CONFIG_X86_LOCAL_APIC
struct irq_data;
+struct pci_dev;
+struct msi_desc;
+
+enum irq_alloc_type {
+ X86_IRQ_ALLOC_TYPE_IOAPIC = 1,
+ X86_IRQ_ALLOC_TYPE_HPET,
+ X86_IRQ_ALLOC_TYPE_MSI,
+ X86_IRQ_ALLOC_TYPE_MSIX,
+ X86_IRQ_ALLOC_TYPE_DMAR,
+ X86_IRQ_ALLOC_TYPE_UV,
+};
-struct irq_cfg {
- cpumask_var_t domain;
- cpumask_var_t old_domain;
- u8 vector;
- u8 move_in_progress : 1;
-#ifdef CONFIG_IRQ_REMAP
- u8 remapped : 1;
+struct irq_alloc_info {
+ enum irq_alloc_type type;
+ u32 flags;
+ const struct cpumask *mask; /* CPU mask for vector allocation */
union {
- struct irq_2_iommu irq_2_iommu;
- struct irq_2_irte irq_2_irte;
- };
+ int unused;
+#ifdef CONFIG_HPET_TIMER
+ struct {
+ int hpet_id;
+ int hpet_index;
+ void *hpet_data;
+ };
#endif
- union {
-#ifdef CONFIG_X86_IO_APIC
+#ifdef CONFIG_PCI_MSI
struct {
- struct list_head irq_2_pin;
+ struct pci_dev *msi_dev;
+ irq_hw_number_t msi_hwirq;
+ };
+#endif
+#ifdef CONFIG_X86_IO_APIC
+ struct {
+ int ioapic_id;
+ int ioapic_pin;
+ int ioapic_node;
+ u32 ioapic_trigger : 1;
+ u32 ioapic_polarity : 1;
+ u32 ioapic_valid : 1;
+ struct IO_APIC_route_entry *ioapic_entry;
+ };
+#endif
+#ifdef CONFIG_DMAR_TABLE
+ struct {
+ int dmar_id;
+ void *dmar_data;
+ };
+#endif
+#ifdef CONFIG_HT_IRQ
+ struct {
+ int ht_pos;
+ int ht_idx;
+ struct pci_dev *ht_dev;
+ void *ht_update;
+ };
+#endif
+#ifdef CONFIG_X86_UV
+ struct {
+ int uv_limit;
+ int uv_blade;
+ unsigned long uv_offset;
+ char *uv_name;
};
#endif
};
};
+struct irq_cfg {
+ unsigned int dest_apicid;
+ u8 vector;
+};
+
extern struct irq_cfg *irq_cfg(unsigned int irq);
extern struct irq_cfg *irqd_cfg(struct irq_data *irq_data);
-extern struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node);
extern void lock_vector_lock(void);
extern void unlock_vector_lock(void);
-extern int assign_irq_vector(int, struct irq_cfg *, const struct cpumask *);
-extern void clear_irq_vector(int irq, struct irq_cfg *cfg);
extern void setup_vector_irq(int cpu);
#ifdef CONFIG_SMP
extern void send_cleanup_vector(struct irq_cfg *);
@@ -150,10 +151,7 @@ static inline void send_cleanup_vector(struct irq_cfg *c) { }
static inline void irq_complete_move(struct irq_cfg *c) { }
#endif
-extern int apic_retrigger_irq(struct irq_data *data);
extern void apic_ack_edge(struct irq_data *data);
-extern int apic_set_affinity(struct irq_data *data, const struct cpumask *mask,
- unsigned int *dest_id);
#else /* CONFIG_X86_LOCAL_APIC */
static inline void lock_vector_lock(void) {}
static inline void unlock_vector_lock(void) {}
@@ -163,8 +161,7 @@ static inline void unlock_vector_lock(void) {}
extern atomic_t irq_err_count;
extern atomic_t irq_mis_count;
-/* EISA */
-extern void eisa_set_level_irq(unsigned int irq);
+extern void elcr_set_level_irq(unsigned int irq);
/* SMP */
extern __visible void smp_apic_timer_interrupt(struct pt_regs *);
@@ -178,7 +175,6 @@ extern asmlinkage void smp_irq_move_cleanup_interrupt(void);
extern __visible void smp_reschedule_interrupt(struct pt_regs *);
extern __visible void smp_call_function_interrupt(struct pt_regs *);
extern __visible void smp_call_function_single_interrupt(struct pt_regs *);
-extern __visible void smp_invalidate_interrupt(struct pt_regs *);
#endif
extern char irq_entries_start[];
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h
deleted file mode 100644
index 6eb6fcb83f63..000000000000
--- a/arch/x86/include/asm/i387.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 1994 Linus Torvalds
- *
- * Pentium III FXSR, SSE support
- * General FPU state handling cleanups
- * Gareth Hughes <gareth@valinux.com>, May 2000
- * x86-64 work by Andi Kleen 2002
- */
-
-#ifndef _ASM_X86_I387_H
-#define _ASM_X86_I387_H
-
-#ifndef __ASSEMBLY__
-
-#include <linux/sched.h>
-#include <linux/hardirq.h>
-
-struct pt_regs;
-struct user_i387_struct;
-
-extern int init_fpu(struct task_struct *child);
-extern void fpu_finit(struct fpu *fpu);
-extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
-extern void math_state_restore(void);
-
-extern bool irq_fpu_usable(void);
-
-/*
- * Careful: __kernel_fpu_begin/end() must be called with preempt disabled
- * and they don't touch the preempt state on their own.
- * If you enable preemption after __kernel_fpu_begin(), preempt notifier
- * should call the __kernel_fpu_end() to prevent the kernel/user FPU
- * state from getting corrupted. KVM for example uses this model.
- *
- * All other cases use kernel_fpu_begin/end() which disable preemption
- * during kernel FPU usage.
- */
-extern void __kernel_fpu_begin(void);
-extern void __kernel_fpu_end(void);
-
-static inline void kernel_fpu_begin(void)
-{
- preempt_disable();
- WARN_ON_ONCE(!irq_fpu_usable());
- __kernel_fpu_begin();
-}
-
-static inline void kernel_fpu_end(void)
-{
- __kernel_fpu_end();
- preempt_enable();
-}
-
-/* Must be called with preempt disabled */
-extern void kernel_fpu_disable(void);
-extern void kernel_fpu_enable(void);
-
-/*
- * Some instructions like VIA's padlock instructions generate a spurious
- * DNA fault but don't modify SSE registers. And these instructions
- * get used from interrupt context as well. To prevent these kernel instructions
- * in interrupt context interacting wrongly with other user/kernel fpu usage, we
- * should use them only in the context of irq_ts_save/restore()
- */
-static inline int irq_ts_save(void)
-{
- /*
- * If in process context and not atomic, we can take a spurious DNA fault.
- * Otherwise, doing clts() in process context requires disabling preemption
- * or some heavy lifting like kernel_fpu_begin()
- */
- if (!in_atomic())
- return 0;
-
- if (read_cr0() & X86_CR0_TS) {
- clts();
- return 1;
- }
-
- return 0;
-}
-
-static inline void irq_ts_restore(int TS_state)
-{
- if (TS_state)
- stts();
-}
-
-/*
- * The question "does this thread have fpu access?"
- * is slightly racy, since preemption could come in
- * and revoke it immediately after the test.
- *
- * However, even in that very unlikely scenario,
- * we can just assume we have FPU access - typically
- * to save the FP state - we'll just take a #NM
- * fault and get the FPU access back.
- */
-static inline int user_has_fpu(void)
-{
- return current->thread.fpu.has_fpu;
-}
-
-extern void unlazy_fpu(struct task_struct *tsk);
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* _ASM_X86_I387_H */
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index 34a5b93704d3..83ec9b1d77cc 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -35,11 +35,13 @@
*/
#define ARCH_HAS_IOREMAP_WC
+#define ARCH_HAS_IOREMAP_WT
#include <linux/string.h>
#include <linux/compiler.h>
#include <asm/page.h>
#include <asm/early_ioremap.h>
+#include <asm/pgtable_types.h>
#define build_mmio_read(name, size, type, reg, barrier) \
static inline type name(const volatile void __iomem *addr) \
@@ -177,6 +179,7 @@ static inline unsigned int isa_virt_to_bus(volatile void *address)
* look at pci_iomap().
*/
extern void __iomem *ioremap_nocache(resource_size_t offset, unsigned long size);
+extern void __iomem *ioremap_uc(resource_size_t offset, unsigned long size);
extern void __iomem *ioremap_cache(resource_size_t offset, unsigned long size);
extern void __iomem *ioremap_prot(resource_size_t offset, unsigned long size,
unsigned long prot_val);
@@ -197,8 +200,6 @@ extern void set_iounmap_nonlazy(void);
#include <asm-generic/iomap.h>
-#include <linux/vmalloc.h>
-
/*
* Convert a virtual cached pointer to an uncached pointer
*/
@@ -320,6 +321,7 @@ extern void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr);
extern int ioremap_change_attr(unsigned long vaddr, unsigned long size,
enum page_cache_mode pcm);
extern void __iomem *ioremap_wc(resource_size_t offset, unsigned long size);
+extern void __iomem *ioremap_wt(resource_size_t offset, unsigned long size);
extern bool is_early_ioremap_ptep(pte_t *ptep);
@@ -338,6 +340,9 @@ extern bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
#define IO_SPACE_LIMIT 0xffff
#ifdef CONFIG_MTRR
+extern int __must_check arch_phys_wc_index(int handle);
+#define arch_phys_wc_index arch_phys_wc_index
+
extern int __must_check arch_phys_wc_add(unsigned long base,
unsigned long size);
extern void arch_phys_wc_del(int handle);
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index 2f91685fe1cd..6cbf2cfb3f8a 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -95,9 +95,22 @@ struct IR_IO_APIC_route_entry {
index : 15;
} __attribute__ ((packed));
-#define IOAPIC_AUTO -1
-#define IOAPIC_EDGE 0
-#define IOAPIC_LEVEL 1
+struct irq_alloc_info;
+struct ioapic_domain_cfg;
+
+#define IOAPIC_AUTO -1
+#define IOAPIC_EDGE 0
+#define IOAPIC_LEVEL 1
+
+#define IOAPIC_MASKED 1
+#define IOAPIC_UNMASKED 0
+
+#define IOAPIC_POL_HIGH 0
+#define IOAPIC_POL_LOW 1
+
+#define IOAPIC_DEST_MODE_PHYSICAL 0
+#define IOAPIC_DEST_MODE_LOGICAL 1
+
#define IOAPIC_MAP_ALLOC 0x1
#define IOAPIC_MAP_CHECK 0x2
@@ -110,9 +123,6 @@ extern int nr_ioapics;
extern int mpc_ioapic_id(int ioapic);
extern unsigned int mpc_ioapic_addr(int ioapic);
-extern struct mp_ioapic_gsi *mp_ioapic_gsi_routing(int ioapic);
-
-#define MP_MAX_IOAPIC_PIN 127
/* # of MP IRQ source entries */
extern int mp_irq_entries;
@@ -120,9 +130,6 @@ extern int mp_irq_entries;
/* MP IRQ source entries */
extern struct mpc_intsrc mp_irqs[MAX_IRQ_SOURCES];
-/* Older SiS APIC requires we rewrite the index register */
-extern int sis_apic_bug;
-
/* 1 if "noapic" boot option passed */
extern int skip_ioapic_setup;
@@ -132,6 +139,8 @@ extern int noioapicquirk;
/* -1 if "noapic" boot option passed */
extern int noioapicreroute;
+extern u32 gsi_top;
+
extern unsigned long io_apic_irqs;
#define IO_APIC_IRQ(x) (((x) >= NR_IRQS_LEGACY) || ((1 << (x)) & io_apic_irqs))
@@ -147,13 +156,6 @@ struct irq_cfg;
extern void ioapic_insert_resources(void);
extern int arch_early_ioapic_init(void);
-extern int native_setup_ioapic_entry(int, struct IO_APIC_route_entry *,
- unsigned int, int,
- struct io_apic_irq_attr *);
-extern void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg);
-
-extern void native_eoi_ioapic_pin(int apic, int pin, int vector);
-
extern int save_ioapic_entries(void);
extern void mask_ioapic_entries(void);
extern int restore_ioapic_entries(void);
@@ -161,82 +163,32 @@ extern int restore_ioapic_entries(void);
extern void setup_ioapic_ids_from_mpc(void);
extern void setup_ioapic_ids_from_mpc_nocheck(void);
-struct io_apic_irq_attr {
- int ioapic;
- int ioapic_pin;
- int trigger;
- int polarity;
-};
-
-enum ioapic_domain_type {
- IOAPIC_DOMAIN_INVALID,
- IOAPIC_DOMAIN_LEGACY,
- IOAPIC_DOMAIN_STRICT,
- IOAPIC_DOMAIN_DYNAMIC,
-};
-
-struct device_node;
-struct irq_domain;
-struct irq_domain_ops;
-
-struct ioapic_domain_cfg {
- enum ioapic_domain_type type;
- const struct irq_domain_ops *ops;
- struct device_node *dev;
-};
-
-struct mp_ioapic_gsi{
- u32 gsi_base;
- u32 gsi_end;
-};
-extern u32 gsi_top;
-
extern int mp_find_ioapic(u32 gsi);
extern int mp_find_ioapic_pin(int ioapic, u32 gsi);
-extern u32 mp_pin_to_gsi(int ioapic, int pin);
-extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags);
+extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags,
+ struct irq_alloc_info *info);
extern void mp_unmap_irq(int irq);
extern int mp_register_ioapic(int id, u32 address, u32 gsi_base,
struct ioapic_domain_cfg *cfg);
extern int mp_unregister_ioapic(u32 gsi_base);
extern int mp_ioapic_registered(u32 gsi_base);
-extern int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
- irq_hw_number_t hwirq);
-extern void mp_irqdomain_unmap(struct irq_domain *domain, unsigned int virq);
-extern int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node);
-extern void __init pre_init_apic_IRQ0(void);
+
+extern void ioapic_set_alloc_attr(struct irq_alloc_info *info,
+ int node, int trigger, int polarity);
extern void mp_save_irq(struct mpc_intsrc *m);
extern void disable_ioapic_support(void);
-extern void __init native_io_apic_init_mappings(void);
+extern void __init io_apic_init_mappings(void);
extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg);
-extern void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int val);
-extern void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val);
extern void native_disable_io_apic(void);
-extern void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries);
-extern void intel_ir_io_apic_print_entries(unsigned int apic, unsigned int nr_entries);
-extern int native_ioapic_set_affinity(struct irq_data *,
- const struct cpumask *,
- bool);
static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
{
return x86_io_apic_ops.read(apic, reg);
}
-static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
-{
- x86_io_apic_ops.write(apic, reg, value);
-}
-static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
-{
- x86_io_apic_ops.modify(apic, reg, value);
-}
-
-extern void io_apic_eoi(unsigned int apic, unsigned int vector);
-
extern void setup_IO_APIC(void);
extern void enable_IO_APIC(void);
extern void disable_IO_APIC(void);
@@ -253,8 +205,12 @@ static inline int arch_early_ioapic_init(void) { return 0; }
static inline void print_IO_APICs(void) {}
#define gsi_top (NR_IRQS_LEGACY)
static inline int mp_find_ioapic(u32 gsi) { return 0; }
-static inline u32 mp_pin_to_gsi(int ioapic, int pin) { return UINT_MAX; }
-static inline int mp_map_gsi_to_irq(u32 gsi, unsigned int flags) { return gsi; }
+static inline int mp_map_gsi_to_irq(u32 gsi, unsigned int flags,
+ struct irq_alloc_info *info)
+{
+ return gsi;
+}
+
static inline void mp_unmap_irq(int irq) { }
static inline int save_ioapic_entries(void)
@@ -268,17 +224,11 @@ static inline int restore_ioapic_entries(void)
return -ENOMEM;
}
-static inline void mp_save_irq(struct mpc_intsrc *m) { };
+static inline void mp_save_irq(struct mpc_intsrc *m) { }
static inline void disable_ioapic_support(void) { }
-#define native_io_apic_init_mappings NULL
+static inline void io_apic_init_mappings(void) { }
#define native_io_apic_read NULL
-#define native_io_apic_write NULL
-#define native_io_apic_modify NULL
#define native_disable_io_apic NULL
-#define native_io_apic_print_entries NULL
-#define native_ioapic_set_affinity NULL
-#define native_setup_ioapic_entry NULL
-#define native_eoi_ioapic_pin NULL
static inline void setup_IO_APIC(void) { }
static inline void enable_IO_APIC(void) { }
diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h
index a80cbb88ea91..8008d06581c7 100644
--- a/arch/x86/include/asm/irq.h
+++ b/arch/x86/include/asm/irq.h
@@ -30,6 +30,10 @@ extern void fixup_irqs(void);
extern void irq_force_complete_move(int);
#endif
+#ifdef CONFIG_HAVE_KVM
+extern void kvm_set_posted_intr_wakeup_handler(void (*handler)(void));
+#endif
+
extern void (*x86_platform_ipi_callback)(void);
extern void native_init_IRQ(void);
extern bool handle_irq(unsigned irq, struct pt_regs *regs);
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index 6224d316c405..046c7fb1ca43 100644
--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -22,84 +22,72 @@
#ifndef __X86_IRQ_REMAPPING_H
#define __X86_IRQ_REMAPPING_H
+#include <asm/irqdomain.h>
+#include <asm/hw_irq.h>
#include <asm/io_apic.h>
-struct IO_APIC_route_entry;
-struct io_apic_irq_attr;
-struct irq_chip;
struct msi_msg;
-struct pci_dev;
-struct irq_cfg;
+struct irq_alloc_info;
+
+enum irq_remap_cap {
+ IRQ_POSTING_CAP = 0,
+};
#ifdef CONFIG_IRQ_REMAP
+extern bool irq_remapping_cap(enum irq_remap_cap cap);
extern void set_irq_remapping_broken(void);
extern int irq_remapping_prepare(void);
extern int irq_remapping_enable(void);
extern void irq_remapping_disable(void);
extern int irq_remapping_reenable(int);
extern int irq_remap_enable_fault_handling(void);
-extern int setup_ioapic_remapped_entry(int irq,
- struct IO_APIC_route_entry *entry,
- unsigned int destination,
- int vector,
- struct io_apic_irq_attr *attr);
-extern void free_remapped_irq(int irq);
-extern void compose_remapped_msi_msg(struct pci_dev *pdev,
- unsigned int irq, unsigned int dest,
- struct msi_msg *msg, u8 hpet_id);
-extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id);
extern void panic_if_irq_remap(const char *msg);
-extern bool setup_remapped_irq(int irq,
- struct irq_cfg *cfg,
- struct irq_chip *chip);
-void irq_remap_modify_chip_defaults(struct irq_chip *chip);
+extern struct irq_domain *
+irq_remapping_get_ir_irq_domain(struct irq_alloc_info *info);
+extern struct irq_domain *
+irq_remapping_get_irq_domain(struct irq_alloc_info *info);
+
+/* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */
+extern struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent);
+
+/* Get parent irqdomain for interrupt remapping irqdomain */
+static inline struct irq_domain *arch_get_ir_parent_domain(void)
+{
+ return x86_vector_domain;
+}
+
+struct vcpu_data {
+ u64 pi_desc_addr; /* Physical address of PI Descriptor */
+ u32 vector; /* Guest vector of the interrupt */
+};
#else /* CONFIG_IRQ_REMAP */
+static inline bool irq_remapping_cap(enum irq_remap_cap cap) { return 0; }
static inline void set_irq_remapping_broken(void) { }
static inline int irq_remapping_prepare(void) { return -ENODEV; }
static inline int irq_remapping_enable(void) { return -ENODEV; }
static inline void irq_remapping_disable(void) { }
static inline int irq_remapping_reenable(int eim) { return -ENODEV; }
static inline int irq_remap_enable_fault_handling(void) { return -ENODEV; }
-static inline int setup_ioapic_remapped_entry(int irq,
- struct IO_APIC_route_entry *entry,
- unsigned int destination,
- int vector,
- struct io_apic_irq_attr *attr)
-{
- return -ENODEV;
-}
-static inline void free_remapped_irq(int irq) { }
-static inline void compose_remapped_msi_msg(struct pci_dev *pdev,
- unsigned int irq, unsigned int dest,
- struct msi_msg *msg, u8 hpet_id)
-{
-}
-static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
-{
- return -ENODEV;
-}
static inline void panic_if_irq_remap(const char *msg)
{
}
-static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip)
+static inline struct irq_domain *
+irq_remapping_get_ir_irq_domain(struct irq_alloc_info *info)
{
+ return NULL;
}
-static inline bool setup_remapped_irq(int irq,
- struct irq_cfg *cfg,
- struct irq_chip *chip)
+static inline struct irq_domain *
+irq_remapping_get_irq_domain(struct irq_alloc_info *info)
{
- return false;
+ return NULL;
}
-#endif /* CONFIG_IRQ_REMAP */
-
-#define dmar_alloc_hwirq() irq_alloc_hwirq(-1)
-#define dmar_free_hwirq irq_free_hwirq
+#endif /* CONFIG_IRQ_REMAP */
#endif /* __X86_IRQ_REMAPPING_H */
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h
index 666c89ec4bd7..4c2d2eb2060a 100644
--- a/arch/x86/include/asm/irq_vectors.h
+++ b/arch/x86/include/asm/irq_vectors.h
@@ -47,31 +47,12 @@
#define IRQ_MOVE_CLEANUP_VECTOR FIRST_EXTERNAL_VECTOR
#define IA32_SYSCALL_VECTOR 0x80
-#ifdef CONFIG_X86_32
-# define SYSCALL_VECTOR 0x80
-#endif
/*
* Vectors 0x30-0x3f are used for ISA interrupts.
* round up to the next 16-vector boundary
*/
-#define IRQ0_VECTOR ((FIRST_EXTERNAL_VECTOR + 16) & ~15)
-
-#define IRQ1_VECTOR (IRQ0_VECTOR + 1)
-#define IRQ2_VECTOR (IRQ0_VECTOR + 2)
-#define IRQ3_VECTOR (IRQ0_VECTOR + 3)
-#define IRQ4_VECTOR (IRQ0_VECTOR + 4)
-#define IRQ5_VECTOR (IRQ0_VECTOR + 5)
-#define IRQ6_VECTOR (IRQ0_VECTOR + 6)
-#define IRQ7_VECTOR (IRQ0_VECTOR + 7)
-#define IRQ8_VECTOR (IRQ0_VECTOR + 8)
-#define IRQ9_VECTOR (IRQ0_VECTOR + 9)
-#define IRQ10_VECTOR (IRQ0_VECTOR + 10)
-#define IRQ11_VECTOR (IRQ0_VECTOR + 11)
-#define IRQ12_VECTOR (IRQ0_VECTOR + 12)
-#define IRQ13_VECTOR (IRQ0_VECTOR + 13)
-#define IRQ14_VECTOR (IRQ0_VECTOR + 14)
-#define IRQ15_VECTOR (IRQ0_VECTOR + 15)
+#define ISA_IRQ_VECTOR(irq) (((FIRST_EXTERNAL_VECTOR + 16) & ~15) + irq)
/*
* Special IRQ vectors used by the SMP architecture, 0xf0-0xff
@@ -102,21 +83,23 @@
*/
#define X86_PLATFORM_IPI_VECTOR 0xf7
-/* Vector for KVM to deliver posted interrupt IPI */
-#ifdef CONFIG_HAVE_KVM
-#define POSTED_INTR_VECTOR 0xf2
-#endif
-
+#define POSTED_INTR_WAKEUP_VECTOR 0xf1
/*
* IRQ work vector:
*/
#define IRQ_WORK_VECTOR 0xf6
#define UV_BAU_MESSAGE 0xf5
+#define DEFERRED_ERROR_VECTOR 0xf4
/* Vector on which hypervisor callbacks will be delivered */
#define HYPERVISOR_CALLBACK_VECTOR 0xf3
+/* Vector for KVM to deliver posted interrupt IPI */
+#ifdef CONFIG_HAVE_KVM
+#define POSTED_INTR_VECTOR 0xf2
+#endif
+
/*
* Local APIC timer IRQ vector is on a different priority level,
* to work around the 'lost local interrupt if more than 2 IRQ
@@ -155,18 +138,22 @@ static inline int invalid_vm86_irq(int irq)
* static arrays.
*/
-#define NR_IRQS_LEGACY 16
+#define NR_IRQS_LEGACY 16
-#define IO_APIC_VECTOR_LIMIT ( 32 * MAX_IO_APICS )
+#define CPU_VECTOR_LIMIT (64 * NR_CPUS)
+#define IO_APIC_VECTOR_LIMIT (32 * MAX_IO_APICS)
-#ifdef CONFIG_X86_IO_APIC
-# define CPU_VECTOR_LIMIT (64 * NR_CPUS)
-# define NR_IRQS \
+#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_PCI_MSI)
+#define NR_IRQS \
(CPU_VECTOR_LIMIT > IO_APIC_VECTOR_LIMIT ? \
(NR_VECTORS + CPU_VECTOR_LIMIT) : \
(NR_VECTORS + IO_APIC_VECTOR_LIMIT))
-#else /* !CONFIG_X86_IO_APIC: */
-# define NR_IRQS NR_IRQS_LEGACY
+#elif defined(CONFIG_X86_IO_APIC)
+#define NR_IRQS (NR_VECTORS + IO_APIC_VECTOR_LIMIT)
+#elif defined(CONFIG_PCI_MSI)
+#define NR_IRQS (NR_VECTORS + CPU_VECTOR_LIMIT)
+#else
+#define NR_IRQS NR_IRQS_LEGACY
#endif
#endif /* _ASM_X86_IRQ_VECTORS_H */
diff --git a/arch/x86/include/asm/irqdomain.h b/arch/x86/include/asm/irqdomain.h
new file mode 100644
index 000000000000..d26075b52885
--- /dev/null
+++ b/arch/x86/include/asm/irqdomain.h
@@ -0,0 +1,63 @@
+#ifndef _ASM_IRQDOMAIN_H
+#define _ASM_IRQDOMAIN_H
+
+#include <linux/irqdomain.h>
+#include <asm/hw_irq.h>
+
+#ifdef CONFIG_X86_LOCAL_APIC
+enum {
+ /* Allocate contiguous CPU vectors */
+ X86_IRQ_ALLOC_CONTIGUOUS_VECTORS = 0x1,
+};
+
+extern struct irq_domain *x86_vector_domain;
+
+extern void init_irq_alloc_info(struct irq_alloc_info *info,
+ const struct cpumask *mask);
+extern void copy_irq_alloc_info(struct irq_alloc_info *dst,
+ struct irq_alloc_info *src);
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_X86_IO_APIC
+struct device_node;
+struct irq_data;
+
+enum ioapic_domain_type {
+ IOAPIC_DOMAIN_INVALID,
+ IOAPIC_DOMAIN_LEGACY,
+ IOAPIC_DOMAIN_STRICT,
+ IOAPIC_DOMAIN_DYNAMIC,
+};
+
+struct ioapic_domain_cfg {
+ enum ioapic_domain_type type;
+ const struct irq_domain_ops *ops;
+ struct device_node *dev;
+};
+
+extern const struct irq_domain_ops mp_ioapic_irqdomain_ops;
+
+extern int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg);
+extern void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs);
+extern void mp_irqdomain_activate(struct irq_domain *domain,
+ struct irq_data *irq_data);
+extern void mp_irqdomain_deactivate(struct irq_domain *domain,
+ struct irq_data *irq_data);
+extern int mp_irqdomain_ioapic_idx(struct irq_domain *domain);
+#endif /* CONFIG_X86_IO_APIC */
+
+#ifdef CONFIG_PCI_MSI
+extern void arch_init_msi_domain(struct irq_domain *domain);
+#else
+static inline void arch_init_msi_domain(struct irq_domain *domain) { }
+#endif
+
+#ifdef CONFIG_HT_IRQ
+extern void arch_init_htirq_domain(struct irq_domain *domain);
+#else
+static inline void arch_init_htirq_domain(struct irq_domain *domain) { }
+#endif
+
+#endif
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 57a9d94fe160..e16466ec473c 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -193,6 +193,8 @@ struct x86_emulate_ops {
int (*cpl)(struct x86_emulate_ctxt *ctxt);
int (*get_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong *dest);
int (*set_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong value);
+ u64 (*get_smbase)(struct x86_emulate_ctxt *ctxt);
+ void (*set_smbase)(struct x86_emulate_ctxt *ctxt, u64 smbase);
int (*set_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 data);
int (*get_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata);
int (*check_pmc)(struct x86_emulate_ctxt *ctxt, u32 pmc);
@@ -262,6 +264,11 @@ enum x86emul_mode {
X86EMUL_MODE_PROT64, /* 64-bit (long) mode. */
};
+/* These match some of the HF_* flags defined in kvm_host.h */
+#define X86EMUL_GUEST_MASK (1 << 5) /* VCPU is in guest-mode */
+#define X86EMUL_SMM_MASK (1 << 6)
+#define X86EMUL_SMM_INSIDE_NMI_MASK (1 << 7)
+
struct x86_emulate_ctxt {
const struct x86_emulate_ops *ops;
@@ -273,8 +280,8 @@ struct x86_emulate_ctxt {
/* interruptibility state, as a result of execution of STI or MOV SS */
int interruptibility;
+ int emul_flags;
- bool guest_mode; /* guest running a nested guest */
bool perm_ok; /* do not check permissions if true */
bool ud; /* inject an #UD if host doesn't support insn */
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index f4a555beef19..c7fa57b529d2 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -184,23 +184,12 @@ struct kvm_mmu_memory_cache {
void *objects[KVM_NR_MEM_OBJS];
};
-/*
- * kvm_mmu_page_role, below, is defined as:
- *
- * bits 0:3 - total guest paging levels (2-4, or zero for real mode)
- * bits 4:7 - page table level for this shadow (1-4)
- * bits 8:9 - page table quadrant for 2-level guests
- * bit 16 - direct mapping of virtual to physical mapping at gfn
- * used for real mode and two-dimensional paging
- * bits 17:19 - common access permissions for all ptes in this shadow page
- */
union kvm_mmu_page_role {
unsigned word;
struct {
unsigned level:4;
unsigned cr4_pae:1;
unsigned quadrant:2;
- unsigned pad_for_nice_hex_output:6;
unsigned direct:1;
unsigned access:3;
unsigned invalid:1;
@@ -208,6 +197,15 @@ union kvm_mmu_page_role {
unsigned cr0_wp:1;
unsigned smep_andnot_wp:1;
unsigned smap_andnot_wp:1;
+ unsigned :8;
+
+ /*
+ * This is left at the top of the word so that
+ * kvm_memslots_for_spte_role can extract it with a
+ * simple shift. While there is room, give it a whole
+ * byte so it is also faster to load it from memory.
+ */
+ unsigned smm:8;
};
};
@@ -338,12 +336,28 @@ struct kvm_pmu {
u64 reprogram_pmi;
};
+struct kvm_pmu_ops;
+
enum {
KVM_DEBUGREG_BP_ENABLED = 1,
KVM_DEBUGREG_WONT_EXIT = 2,
KVM_DEBUGREG_RELOAD = 4,
};
+struct kvm_mtrr_range {
+ u64 base;
+ u64 mask;
+ struct list_head node;
+};
+
+struct kvm_mtrr {
+ struct kvm_mtrr_range var_ranges[KVM_NR_VAR_MTRR];
+ mtrr_type fixed_ranges[KVM_NR_FIXED_MTRR_REGION];
+ u64 deftype;
+
+ struct list_head head;
+};
+
struct kvm_vcpu_arch {
/*
* rip and regs accesses must go through
@@ -368,6 +382,7 @@ struct kvm_vcpu_arch {
int32_t apic_arb_prio;
int mp_state;
u64 ia32_misc_enable_msr;
+ u64 smbase;
bool tpr_access_reporting;
u64 ia32_xss;
@@ -471,8 +486,9 @@ struct kvm_vcpu_arch {
atomic_t nmi_queued; /* unprocessed asynchronous NMIs */
unsigned nmi_pending; /* NMI queued after currently running handler */
bool nmi_injected; /* Trying to inject an NMI this entry */
+ bool smi_pending; /* SMI queued after currently running handler */
- struct mtrr_state_type mtrr_state;
+ struct kvm_mtrr mtrr_state;
u64 pat;
unsigned switch_db_regs;
@@ -637,6 +653,8 @@ struct kvm_arch {
#endif
bool boot_vcpu_runs_old_kvmclock;
+
+ u64 disabled_quirks;
};
struct kvm_vm_stat {
@@ -689,12 +707,13 @@ struct msr_data {
struct kvm_lapic_irq {
u32 vector;
- u32 delivery_mode;
- u32 dest_mode;
- u32 level;
- u32 trig_mode;
+ u16 delivery_mode;
+ u16 dest_mode;
+ bool level;
+ u16 trig_mode;
u32 shorthand;
u32 dest_id;
+ bool msi_redir_hint;
};
struct kvm_x86_ops {
@@ -706,19 +725,20 @@ struct kvm_x86_ops {
int (*hardware_setup)(void); /* __init */
void (*hardware_unsetup)(void); /* __exit */
bool (*cpu_has_accelerated_tpr)(void);
+ bool (*cpu_has_high_real_mode_segbase)(void);
void (*cpuid_update)(struct kvm_vcpu *vcpu);
/* Create, but do not attach this VCPU */
struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id);
void (*vcpu_free)(struct kvm_vcpu *vcpu);
- void (*vcpu_reset)(struct kvm_vcpu *vcpu);
+ void (*vcpu_reset)(struct kvm_vcpu *vcpu, bool init_event);
void (*prepare_guest_switch)(struct kvm_vcpu *vcpu);
void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
void (*vcpu_put)(struct kvm_vcpu *vcpu);
void (*update_db_bp_intercept)(struct kvm_vcpu *vcpu);
- int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
+ int (*get_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr);
int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr);
u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
void (*get_segment)(struct kvm_vcpu *vcpu,
@@ -836,6 +856,8 @@ struct kvm_x86_ops {
void (*enable_log_dirty_pt_masked)(struct kvm *kvm,
struct kvm_memory_slot *slot,
gfn_t offset, unsigned long mask);
+ /* pmu operations of sub-arch */
+ const struct kvm_pmu_ops *pmu_ops;
};
struct kvm_arch_async_pf {
@@ -871,7 +893,7 @@ void kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
struct kvm_memory_slot *memslot);
void kvm_mmu_zap_collapsible_sptes(struct kvm *kvm,
- struct kvm_memory_slot *memslot);
+ const struct kvm_memory_slot *memslot);
void kvm_mmu_slot_leaf_clear_dirty(struct kvm *kvm,
struct kvm_memory_slot *memslot);
void kvm_mmu_slot_largepage_remove_write_access(struct kvm *kvm,
@@ -882,7 +904,7 @@ void kvm_mmu_clear_dirty_pt_masked(struct kvm *kvm,
struct kvm_memory_slot *slot,
gfn_t gfn_offset, unsigned long mask);
void kvm_mmu_zap_all(struct kvm *kvm);
-void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm);
+void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, struct kvm_memslots *slots);
unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm);
void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages);
@@ -890,7 +912,6 @@ int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3);
int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
const void *val, int bytes);
-u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn);
struct kvm_irq_mask_notifier {
void (*func)(struct kvm_irq_mask_notifier *kimn, bool masked);
@@ -938,7 +959,7 @@ static inline int emulate_instruction(struct kvm_vcpu *vcpu,
void kvm_enable_efer_bits(u64);
bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer);
-int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
+int kvm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr);
int kvm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr);
struct x86_emulate_ctxt;
@@ -967,7 +988,7 @@ void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
int kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr);
-int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
+int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr);
int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr);
unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu);
@@ -1002,8 +1023,6 @@ void kvm_pic_clear_all(struct kvm_pic *pic, int irq_source_id);
void kvm_inject_nmi(struct kvm_vcpu *vcpu);
-int fx_init(struct kvm_vcpu *vcpu);
-
void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
const u8 *new, int bytes);
int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn);
@@ -1112,6 +1131,14 @@ enum {
#define HF_NMI_MASK (1 << 3)
#define HF_IRET_MASK (1 << 4)
#define HF_GUEST_MASK (1 << 5) /* VCPU is in guest-mode */
+#define HF_SMM_MASK (1 << 6)
+#define HF_SMM_INSIDE_NMI_MASK (1 << 7)
+
+#define __KVM_VCPU_MULTIPLE_ADDRESS_SPACE
+#define KVM_ADDRESS_SPACE_NUM 2
+
+#define kvm_arch_vcpu_memslots_id(vcpu) ((vcpu)->arch.hflags & HF_SMM_MASK ? 1 : 0)
+#define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, (role).smm)
/*
* Hardware virtualization extension instructions may fault if a
@@ -1146,7 +1173,7 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v);
int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu);
int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
-void kvm_vcpu_reset(struct kvm_vcpu *vcpu);
+void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event);
void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu);
void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
unsigned long address);
@@ -1170,16 +1197,9 @@ void kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err);
int kvm_is_in_guest(void);
-void kvm_pmu_init(struct kvm_vcpu *vcpu);
-void kvm_pmu_destroy(struct kvm_vcpu *vcpu);
-void kvm_pmu_reset(struct kvm_vcpu *vcpu);
-void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu);
-bool kvm_pmu_msr(struct kvm_vcpu *vcpu, u32 msr);
-int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
-int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
-int kvm_pmu_check_pmc(struct kvm_vcpu *vcpu, unsigned pmc);
-int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);
-void kvm_handle_pmu_event(struct kvm_vcpu *vcpu);
-void kvm_deliver_pmi(struct kvm_vcpu *vcpu);
+int __x86_set_memory_region(struct kvm *kvm,
+ const struct kvm_userspace_memory_region *mem);
+int x86_set_memory_region(struct kvm *kvm,
+ const struct kvm_userspace_memory_region *mem);
#endif /* _ASM_X86_KVM_HOST_H */
diff --git a/arch/x86/include/asm/livepatch.h b/arch/x86/include/asm/livepatch.h
index 2d29197bd2fb..19c099afa861 100644
--- a/arch/x86/include/asm/livepatch.h
+++ b/arch/x86/include/asm/livepatch.h
@@ -21,6 +21,7 @@
#ifndef _ASM_X86_LIVEPATCH_H
#define _ASM_X86_LIVEPATCH_H
+#include <asm/setup.h>
#include <linux/module.h>
#include <linux/ftrace.h>
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index 1f5a86d518db..982dfc3679ad 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -17,11 +17,16 @@
#define MCG_EXT_CNT(c) (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT)
#define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */
#define MCG_ELOG_P (1ULL<<26) /* Extended error log supported */
+#define MCG_LMCE_P (1ULL<<27) /* Local machine check supported */
/* MCG_STATUS register defines */
#define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */
#define MCG_STATUS_EIPV (1ULL<<1) /* ip points to correct instruction */
#define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */
+#define MCG_STATUS_LMCES (1ULL<<3) /* LMCE signaled */
+
+/* MCG_EXT_CTL register defines */
+#define MCG_EXT_CTL_LMCE_EN (1ULL<<0) /* Enable LMCE */
/* MCi_STATUS register defines */
#define MCI_STATUS_VAL (1ULL<<63) /* valid error */
@@ -104,6 +109,7 @@ struct mce_log {
struct mca_config {
bool dont_log_ce;
bool cmci_disabled;
+ bool lmce_disabled;
bool ignore_ce;
bool disabled;
bool ser;
@@ -117,8 +123,19 @@ struct mca_config {
};
struct mce_vendor_flags {
- __u64 overflow_recov : 1, /* cpuid_ebx(80000007) */
- __reserved_0 : 63;
+ /*
+ * overflow recovery cpuid bit indicates that overflow
+ * conditions are not fatal
+ */
+ __u64 overflow_recov : 1,
+
+ /*
+ * SUCCOR stands for S/W UnCorrectable error COntainment
+ * and Recovery. It indicates support for data poisoning
+ * in HW and deferred error interrupts.
+ */
+ succor : 1,
+ __reserved_0 : 62;
};
extern struct mce_vendor_flags mce_flags;
@@ -168,12 +185,16 @@ void cmci_clear(void);
void cmci_reenable(void);
void cmci_rediscover(void);
void cmci_recheck(void);
+void lmce_clear(void);
+void lmce_enable(void);
#else
static inline void mce_intel_feature_init(struct cpuinfo_x86 *c) { }
static inline void cmci_clear(void) {}
static inline void cmci_reenable(void) {}
static inline void cmci_rediscover(void) {}
static inline void cmci_recheck(void) {}
+static inline void lmce_clear(void) {}
+static inline void lmce_enable(void) {}
#endif
#ifdef CONFIG_X86_MCE_AMD
@@ -223,6 +244,9 @@ void do_machine_check(struct pt_regs *, long);
extern void (*mce_threshold_vector)(void);
extern void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
+/* Deferred error interrupt handler */
+extern void (*deferred_error_int_vector)(void);
+
/*
* Thermal handler
*/
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
index 2fb20d6f7e23..9e6278c7140e 100644
--- a/arch/x86/include/asm/microcode.h
+++ b/arch/x86/include/asm/microcode.h
@@ -1,6 +1,8 @@
#ifndef _ASM_X86_MICROCODE_H
#define _ASM_X86_MICROCODE_H
+#include <linux/earlycpio.h>
+
#define native_rdmsr(msr, val1, val2) \
do { \
u64 __val = native_read_msr((msr)); \
@@ -152,6 +154,7 @@ extern void __init load_ucode_bsp(void);
extern void load_ucode_ap(void);
extern int __init save_microcode_in_initrd(void);
void reload_early_microcode(void);
+extern bool get_builtin_firmware(struct cpio_data *cd, const char *name);
#else
static inline void __init load_ucode_bsp(void) {}
static inline void load_ucode_ap(void) {}
@@ -160,6 +163,9 @@ static inline int __init save_microcode_in_initrd(void)
return 0;
}
static inline void reload_early_microcode(void) {}
+static inline bool get_builtin_firmware(struct cpio_data *cd, const char *name)
+{
+ return false;
+}
#endif
-
#endif /* _ASM_X86_MICROCODE_H */
diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h
index af935397e053..ac6d328977a6 100644
--- a/arch/x86/include/asm/microcode_amd.h
+++ b/arch/x86/include/asm/microcode_amd.h
@@ -65,12 +65,12 @@ extern enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, s
extern u8 amd_ucode_patch[PATCH_MAX_SIZE];
#ifdef CONFIG_MICROCODE_AMD_EARLY
-extern void __init load_ucode_amd_bsp(void);
+extern void __init load_ucode_amd_bsp(unsigned int family);
extern void load_ucode_amd_ap(void);
extern int __init save_microcode_in_initrd_amd(void);
void reload_ucode_amd(void);
#else
-static inline void __init load_ucode_amd_bsp(void) {}
+static inline void __init load_ucode_amd_bsp(unsigned int family) {}
static inline void load_ucode_amd_ap(void) {}
static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; }
void reload_ucode_amd(void) {}
diff --git a/arch/x86/include/asm/microcode_intel.h b/arch/x86/include/asm/microcode_intel.h
index 2b9209c46ca9..7991c606125d 100644
--- a/arch/x86/include/asm/microcode_intel.h
+++ b/arch/x86/include/asm/microcode_intel.h
@@ -51,20 +51,11 @@ struct extended_sigtable {
(((struct microcode_intel *)mc)->hdr.datasize ? \
((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
-#define sigmatch(s1, s2, p1, p2) \
- (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
-
#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
-extern int get_matching_microcode(unsigned int csig, int cpf, int rev, void *mc);
+extern int has_newer_microcode(void *mc, unsigned int csig, int cpf, int rev);
extern int microcode_sanity_check(void *mc, int print_err);
-extern int get_matching_sig(unsigned int csig, int cpf, int rev, void *mc);
-
-static inline int
-revision_is_newer(struct microcode_header_intel *mc_header, int rev)
-{
- return (mc_header->rev <= rev) ? 0 : 1;
-}
+extern int find_matching_signature(void *mc, unsigned int csig, int cpf);
#ifdef CONFIG_MICROCODE_INTEL_EARLY
extern void __init load_ucode_intel_bsp(void);
diff --git a/arch/x86/include/asm/mm-arch-hooks.h b/arch/x86/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..4e881a342236
--- /dev/null
+++ b/arch/x86/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_X86_MM_ARCH_HOOKS_H
+#define _ASM_X86_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_X86_MM_ARCH_HOOKS_H */
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index 883f6b933fa4..5e8daee7c5c9 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -142,6 +142,19 @@ static inline void arch_exit_mmap(struct mm_struct *mm)
paravirt_arch_exit_mmap(mm);
}
+#ifdef CONFIG_X86_64
+static inline bool is_64bit_mm(struct mm_struct *mm)
+{
+ return !config_enabled(CONFIG_IA32_EMULATION) ||
+ !(mm->context.ia32_compat == TIF_IA32);
+}
+#else
+static inline bool is_64bit_mm(struct mm_struct *mm)
+{
+ return false;
+}
+#endif
+
static inline void arch_bprm_mm_init(struct mm_struct *mm,
struct vm_area_struct *vma)
{
diff --git a/arch/x86/include/asm/mpx.h b/arch/x86/include/asm/mpx.h
index a952a13d59a7..7a35495275a9 100644
--- a/arch/x86/include/asm/mpx.h
+++ b/arch/x86/include/asm/mpx.h
@@ -13,55 +13,50 @@
#define MPX_BNDCFG_ENABLE_FLAG 0x1
#define MPX_BD_ENTRY_VALID_FLAG 0x1
-#ifdef CONFIG_X86_64
-
-/* upper 28 bits [47:20] of the virtual address in 64-bit used to
- * index into bounds directory (BD).
- */
-#define MPX_BD_ENTRY_OFFSET 28
-#define MPX_BD_ENTRY_SHIFT 3
-/* bits [19:3] of the virtual address in 64-bit used to index into
- * bounds table (BT).
+/*
+ * The upper 28 bits [47:20] of the virtual address in 64-bit
+ * are used to index into bounds directory (BD).
+ *
+ * The directory is 2G (2^31) in size, and with 8-byte entries
+ * it has 2^28 entries.
*/
-#define MPX_BT_ENTRY_OFFSET 17
-#define MPX_BT_ENTRY_SHIFT 5
-#define MPX_IGN_BITS 3
-#define MPX_BD_ENTRY_TAIL 3
+#define MPX_BD_SIZE_BYTES_64 (1UL<<31)
+#define MPX_BD_ENTRY_BYTES_64 8
+#define MPX_BD_NR_ENTRIES_64 (MPX_BD_SIZE_BYTES_64/MPX_BD_ENTRY_BYTES_64)
-#else
-
-#define MPX_BD_ENTRY_OFFSET 20
-#define MPX_BD_ENTRY_SHIFT 2
-#define MPX_BT_ENTRY_OFFSET 10
-#define MPX_BT_ENTRY_SHIFT 4
-#define MPX_IGN_BITS 2
-#define MPX_BD_ENTRY_TAIL 2
+/*
+ * The 32-bit directory is 4MB (2^22) in size, and with 4-byte
+ * entries it has 2^20 entries.
+ */
+#define MPX_BD_SIZE_BYTES_32 (1UL<<22)
+#define MPX_BD_ENTRY_BYTES_32 4
+#define MPX_BD_NR_ENTRIES_32 (MPX_BD_SIZE_BYTES_32/MPX_BD_ENTRY_BYTES_32)
-#endif
+/*
+ * A 64-bit table is 4MB total in size, and an entry is
+ * 4 64-bit pointers in size.
+ */
+#define MPX_BT_SIZE_BYTES_64 (1UL<<22)
+#define MPX_BT_ENTRY_BYTES_64 32
+#define MPX_BT_NR_ENTRIES_64 (MPX_BT_SIZE_BYTES_64/MPX_BT_ENTRY_BYTES_64)
-#define MPX_BD_SIZE_BYTES (1UL<<(MPX_BD_ENTRY_OFFSET+MPX_BD_ENTRY_SHIFT))
-#define MPX_BT_SIZE_BYTES (1UL<<(MPX_BT_ENTRY_OFFSET+MPX_BT_ENTRY_SHIFT))
+/*
+ * A 32-bit table is 16kB total in size, and an entry is
+ * 4 32-bit pointers in size.
+ */
+#define MPX_BT_SIZE_BYTES_32 (1UL<<14)
+#define MPX_BT_ENTRY_BYTES_32 16
+#define MPX_BT_NR_ENTRIES_32 (MPX_BT_SIZE_BYTES_32/MPX_BT_ENTRY_BYTES_32)
#define MPX_BNDSTA_TAIL 2
#define MPX_BNDCFG_TAIL 12
#define MPX_BNDSTA_ADDR_MASK (~((1UL<<MPX_BNDSTA_TAIL)-1))
#define MPX_BNDCFG_ADDR_MASK (~((1UL<<MPX_BNDCFG_TAIL)-1))
-#define MPX_BT_ADDR_MASK (~((1UL<<MPX_BD_ENTRY_TAIL)-1))
-
-#define MPX_BNDCFG_ADDR_MASK (~((1UL<<MPX_BNDCFG_TAIL)-1))
#define MPX_BNDSTA_ERROR_CODE 0x3
-#define MPX_BD_ENTRY_MASK ((1<<MPX_BD_ENTRY_OFFSET)-1)
-#define MPX_BT_ENTRY_MASK ((1<<MPX_BT_ENTRY_OFFSET)-1)
-#define MPX_GET_BD_ENTRY_OFFSET(addr) ((((addr)>>(MPX_BT_ENTRY_OFFSET+ \
- MPX_IGN_BITS)) & MPX_BD_ENTRY_MASK) << MPX_BD_ENTRY_SHIFT)
-#define MPX_GET_BT_ENTRY_OFFSET(addr) ((((addr)>>MPX_IGN_BITS) & \
- MPX_BT_ENTRY_MASK) << MPX_BT_ENTRY_SHIFT)
-
#ifdef CONFIG_X86_INTEL_MPX
-siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
- struct xsave_struct *xsave_buf);
-int mpx_handle_bd_fault(struct xsave_struct *xsave_buf);
+siginfo_t *mpx_generate_siginfo(struct pt_regs *regs);
+int mpx_handle_bd_fault(void);
static inline int kernel_managing_mpx_tables(struct mm_struct *mm)
{
return (mm->bd_addr != MPX_INVALID_BOUNDS_DIR);
@@ -77,12 +72,11 @@ static inline void mpx_mm_init(struct mm_struct *mm)
void mpx_notify_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long start, unsigned long end);
#else
-static inline siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
- struct xsave_struct *xsave_buf)
+static inline siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
{
return NULL;
}
-static inline int mpx_handle_bd_fault(struct xsave_struct *xsave_buf)
+static inline int mpx_handle_bd_fault(void)
{
return -EINVAL;
}
diff --git a/arch/x86/include/asm/msi.h b/arch/x86/include/asm/msi.h
new file mode 100644
index 000000000000..93724cc62177
--- /dev/null
+++ b/arch/x86/include/asm/msi.h
@@ -0,0 +1,7 @@
+#ifndef _ASM_X86_MSI_H
+#define _ASM_X86_MSI_H
+#include <asm/hw_irq.h>
+
+typedef struct irq_alloc_info msi_alloc_info_t;
+
+#endif /* _ASM_X86_MSI_H */
diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 3c6bb342a48f..9ebc3d009373 100644
--- a/arch/x86/include/uapi/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -56,6 +56,7 @@
#define MSR_IA32_MCG_CAP 0x00000179
#define MSR_IA32_MCG_STATUS 0x0000017a
#define MSR_IA32_MCG_CTL 0x0000017b
+#define MSR_IA32_MCG_EXT_CTL 0x000004d0
#define MSR_OFFCORE_RSP_0 0x000001a6
#define MSR_OFFCORE_RSP_1 0x000001a7
@@ -380,6 +381,7 @@
#define FEATURE_CONTROL_LOCKED (1<<0)
#define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1<<1)
#define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1<<2)
+#define FEATURE_CONTROL_LMCE (1<<20)
#define MSR_IA32_APICBASE 0x0000001b
#define MSR_IA32_APICBASE_BSP (1<<8)
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index de36f22eb0b9..e6a707eb5081 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -1,13 +1,14 @@
#ifndef _ASM_X86_MSR_H
#define _ASM_X86_MSR_H
-#include <uapi/asm/msr.h>
+#include "msr-index.h"
#ifndef __ASSEMBLY__
#include <asm/asm.h>
#include <asm/errno.h>
#include <asm/cpumask.h>
+#include <uapi/asm/msr.h>
struct msr {
union {
@@ -205,8 +206,13 @@ do { \
#endif /* !CONFIG_PARAVIRT */
-#define wrmsrl_safe(msr, val) wrmsr_safe((msr), (u32)(val), \
- (u32)((val) >> 32))
+/*
+ * 64-bit version of wrmsr_safe():
+ */
+static inline int wrmsrl_safe(u32 msr, u64 val)
+{
+ return wrmsr_safe(msr, (u32)val, (u32)(val >> 32));
+}
#define write_tsc(low, high) wrmsr(MSR_IA32_TSC, (low), (high))
diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h
index f768f6298419..b94f6f64e23d 100644
--- a/arch/x86/include/asm/mtrr.h
+++ b/arch/x86/include/asm/mtrr.h
@@ -31,7 +31,7 @@
* arch_phys_wc_add and arch_phys_wc_del.
*/
# ifdef CONFIG_MTRR
-extern u8 mtrr_type_lookup(u64 addr, u64 end);
+extern u8 mtrr_type_lookup(u64 addr, u64 end, u8 *uniform);
extern void mtrr_save_fixed_ranges(void *);
extern void mtrr_save_state(void);
extern int mtrr_add(unsigned long base, unsigned long size,
@@ -48,14 +48,13 @@ extern void mtrr_aps_init(void);
extern void mtrr_bp_restore(void);
extern int mtrr_trim_uncached_memory(unsigned long end_pfn);
extern int amd_special_default_mtrr(void);
-extern int phys_wc_to_mtrr_index(int handle);
# else
-static inline u8 mtrr_type_lookup(u64 addr, u64 end)
+static inline u8 mtrr_type_lookup(u64 addr, u64 end, u8 *uniform)
{
/*
* Return no-MTRRs:
*/
- return 0xff;
+ return MTRR_TYPE_INVALID;
}
#define mtrr_save_fixed_ranges(arg) do {} while (0)
#define mtrr_save_state() do {} while (0)
@@ -84,10 +83,6 @@ static inline int mtrr_trim_uncached_memory(unsigned long end_pfn)
static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
{
}
-static inline int phys_wc_to_mtrr_index(int handle)
-{
- return -1;
-}
#define mtrr_ap_init() do {} while (0)
#define mtrr_bp_init() do {} while (0)
@@ -127,4 +122,8 @@ struct mtrr_gentry32 {
_IOW(MTRR_IOCTL_BASE, 9, struct mtrr_sentry32)
#endif /* CONFIG_COMPAT */
+/* Bit fields for enabled in struct mtrr_state_type */
+#define MTRR_STATE_MTRR_FIXED_ENABLED 0x01
+#define MTRR_STATE_MTRR_ENABLED 0x02
+
#endif /* _ASM_X86_MTRR_H */
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 8957810ad7d1..d143bfad45d7 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -712,6 +712,31 @@ static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx,
#if defined(CONFIG_SMP) && defined(CONFIG_PARAVIRT_SPINLOCKS)
+#ifdef CONFIG_QUEUED_SPINLOCKS
+
+static __always_inline void pv_queued_spin_lock_slowpath(struct qspinlock *lock,
+ u32 val)
+{
+ PVOP_VCALL2(pv_lock_ops.queued_spin_lock_slowpath, lock, val);
+}
+
+static __always_inline void pv_queued_spin_unlock(struct qspinlock *lock)
+{
+ PVOP_VCALLEE1(pv_lock_ops.queued_spin_unlock, lock);
+}
+
+static __always_inline void pv_wait(u8 *ptr, u8 val)
+{
+ PVOP_VCALL2(pv_lock_ops.wait, ptr, val);
+}
+
+static __always_inline void pv_kick(int cpu)
+{
+ PVOP_VCALL1(pv_lock_ops.kick, cpu);
+}
+
+#else /* !CONFIG_QUEUED_SPINLOCKS */
+
static __always_inline void __ticket_lock_spinning(struct arch_spinlock *lock,
__ticket_t ticket)
{
@@ -724,7 +749,9 @@ static __always_inline void __ticket_unlock_kick(struct arch_spinlock *lock,
PVOP_VCALL2(pv_lock_ops.unlock_kick, lock, ticket);
}
-#endif
+#endif /* CONFIG_QUEUED_SPINLOCKS */
+
+#endif /* SMP && PARAVIRT_SPINLOCKS */
#ifdef CONFIG_X86_32
#define PV_SAVE_REGS "pushl %ecx; pushl %edx;"
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index f7b0b5c112f2..a6b8f9fadb06 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -160,13 +160,14 @@ struct pv_cpu_ops {
u64 (*read_pmc)(int counter);
unsigned long long (*read_tscp)(unsigned int *aux);
+#ifdef CONFIG_X86_32
/*
* Atomically enable interrupts and return to userspace. This
- * is only ever used to return to 32-bit processes; in a
- * 64-bit kernel, it's used for 32-on-64 compat processes, but
- * never native 64-bit processes. (Jump, not call.)
+ * is only used in 32-bit kernels. 64-bit kernels use
+ * usergs_sysret32 instead.
*/
void (*irq_enable_sysexit)(void);
+#endif
/*
* Switch to usermode gs and return to 64-bit usermode using
@@ -333,9 +334,19 @@ struct arch_spinlock;
typedef u16 __ticket_t;
#endif
+struct qspinlock;
+
struct pv_lock_ops {
+#ifdef CONFIG_QUEUED_SPINLOCKS
+ void (*queued_spin_lock_slowpath)(struct qspinlock *lock, u32 val);
+ struct paravirt_callee_save queued_spin_unlock;
+
+ void (*wait)(u8 *ptr, u8 val);
+ void (*kick)(int cpu);
+#else /* !CONFIG_QUEUED_SPINLOCKS */
struct paravirt_callee_save lock_spinning;
void (*unlock_kick)(struct arch_spinlock *lock, __ticket_t ticket);
+#endif /* !CONFIG_QUEUED_SPINLOCKS */
};
/* This contains all the paravirt structures: we get a convenient
diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h
index 91bc4ba95f91..ca6c228d5e62 100644
--- a/arch/x86/include/asm/pat.h
+++ b/arch/x86/include/asm/pat.h
@@ -4,14 +4,9 @@
#include <linux/types.h>
#include <asm/pgtable_types.h>
-#ifdef CONFIG_X86_PAT
-extern int pat_enabled;
-#else
-static const int pat_enabled;
-#endif
-
+bool pat_enabled(void);
extern void pat_init(void);
-void pat_init_cache_modes(void);
+void pat_init_cache_modes(u64);
extern int reserve_memtype(u64 start, u64 end,
enum page_cache_mode req_pcm, enum page_cache_mode *ret_pcm);
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 4e370a5d8117..462594320d39 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -5,7 +5,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <asm/io.h>
#include <asm/x86_init.h>
@@ -80,13 +80,6 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
#ifdef CONFIG_PCI
extern void early_quirks(void);
-static inline void pci_dma_burst_advice(struct pci_dev *pdev,
- enum pci_dma_burst_strategy *strat,
- unsigned long *strategy_parameter)
-{
- *strat = PCI_DMA_BURST_INFINITY;
- *strategy_parameter = ~0UL;
-}
#else
static inline void early_quirks(void) { }
#endif
@@ -96,15 +89,10 @@ extern void pci_iommu_alloc(void);
#ifdef CONFIG_PCI_MSI
/* implemented in arch/x86/kernel/apic/io_apic. */
struct msi_desc;
-void native_compose_msi_msg(struct pci_dev *pdev, unsigned int irq,
- unsigned int dest, struct msi_msg *msg, u8 hpet_id);
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
void native_teardown_msi_irq(unsigned int irq);
void native_restore_msi_irqs(struct pci_dev *dev);
-int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
- unsigned int irq_base, unsigned int irq_offset);
#else
-#define native_compose_msi_msg NULL
#define native_setup_msi_irqs NULL
#define native_teardown_msi_irq NULL
#endif
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index fe57e7a98839..867da5bbb4a3 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -398,11 +398,17 @@ static inline int is_new_memtype_allowed(u64 paddr, unsigned long size,
* requested memtype:
* - request is uncached, return cannot be write-back
* - request is write-combine, return cannot be write-back
+ * - request is write-through, return cannot be write-back
+ * - request is write-through, return cannot be write-combine
*/
if ((pcm == _PAGE_CACHE_MODE_UC_MINUS &&
new_pcm == _PAGE_CACHE_MODE_WB) ||
(pcm == _PAGE_CACHE_MODE_WC &&
- new_pcm == _PAGE_CACHE_MODE_WB)) {
+ new_pcm == _PAGE_CACHE_MODE_WB) ||
+ (pcm == _PAGE_CACHE_MODE_WT &&
+ new_pcm == _PAGE_CACHE_MODE_WB) ||
+ (pcm == _PAGE_CACHE_MODE_WT &&
+ new_pcm == _PAGE_CACHE_MODE_WC)) {
return 0;
}
@@ -799,8 +805,8 @@ static inline int pmd_write(pmd_t pmd)
return pmd_flags(pmd) & _PAGE_RW;
}
-#define __HAVE_ARCH_PMDP_GET_AND_CLEAR
-static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, unsigned long addr,
+#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
+static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp)
{
pmd_t pmd = native_pmdp_get_and_clear(pmdp);
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 78f0c8cbe316..13f310bfc09a 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -367,6 +367,9 @@ extern int nx_enabled;
#define pgprot_writecombine pgprot_writecombine
extern pgprot_t pgprot_writecombine(pgprot_t prot);
+#define pgprot_writethrough pgprot_writethrough
+extern pgprot_t pgprot_writethrough(pgprot_t prot);
+
/* Indicate that x86 has its own track and untrack pfn vma functions */
#define __HAVE_PFNMAP_TRACKING
diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h
index 8f3271842533..dca71714f860 100644
--- a/arch/x86/include/asm/preempt.h
+++ b/arch/x86/include/asm/preempt.h
@@ -99,11 +99,9 @@ static __always_inline bool should_resched(void)
extern asmlinkage void ___preempt_schedule(void);
# define __preempt_schedule() asm ("call ___preempt_schedule")
extern asmlinkage void preempt_schedule(void);
-# ifdef CONFIG_CONTEXT_TRACKING
- extern asmlinkage void ___preempt_schedule_context(void);
-# define __preempt_schedule_context() asm ("call ___preempt_schedule_context")
- extern asmlinkage void preempt_schedule_context(void);
-# endif
+ extern asmlinkage void ___preempt_schedule_notrace(void);
+# define __preempt_schedule_notrace() asm ("call ___preempt_schedule_notrace")
+ extern asmlinkage void preempt_schedule_notrace(void);
#endif
#endif /* __ASM_PREEMPT_H */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 23ba6765b718..43e6519df0d5 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -21,6 +21,7 @@ struct mm_struct;
#include <asm/desc_defs.h>
#include <asm/nops.h>
#include <asm/special_insns.h>
+#include <asm/fpu/types.h>
#include <linux/personality.h>
#include <linux/cpumask.h>
@@ -52,11 +53,16 @@ static inline void *current_text_addr(void)
return pc;
}
+/*
+ * These alignment constraints are for performance in the vSMP case,
+ * but in the task_struct case we must also meet hardware imposed
+ * alignment requirements of the FPU state:
+ */
#ifdef CONFIG_X86_VSMP
# define ARCH_MIN_TASKALIGN (1 << INTERNODE_CACHE_SHIFT)
# define ARCH_MIN_MMSTRUCT_ALIGN (1 << INTERNODE_CACHE_SHIFT)
#else
-# define ARCH_MIN_TASKALIGN 16
+# define ARCH_MIN_TASKALIGN __alignof__(union fpregs_state)
# define ARCH_MIN_MMSTRUCT_ALIGN 0
#endif
@@ -166,7 +172,6 @@ extern const struct seq_operations cpuinfo_op;
#define cache_line_size() (boot_cpu_data.x86_cache_alignment)
extern void cpu_detect(struct cpuinfo_x86 *c);
-extern void fpu_detect(struct cpuinfo_x86 *c);
extern void early_cpu_init(void);
extern void identify_boot_cpu(void);
@@ -313,128 +318,6 @@ struct orig_ist {
unsigned long ist[7];
};
-#define MXCSR_DEFAULT 0x1f80
-
-struct i387_fsave_struct {
- u32 cwd; /* FPU Control Word */
- u32 swd; /* FPU Status Word */
- u32 twd; /* FPU Tag Word */
- u32 fip; /* FPU IP Offset */
- u32 fcs; /* FPU IP Selector */
- u32 foo; /* FPU Operand Pointer Offset */
- u32 fos; /* FPU Operand Pointer Selector */
-
- /* 8*10 bytes for each FP-reg = 80 bytes: */
- u32 st_space[20];
-
- /* Software status information [not touched by FSAVE ]: */
- u32 status;
-};
-
-struct i387_fxsave_struct {
- u16 cwd; /* Control Word */
- u16 swd; /* Status Word */
- u16 twd; /* Tag Word */
- u16 fop; /* Last Instruction Opcode */
- union {
- struct {
- u64 rip; /* Instruction Pointer */
- u64 rdp; /* Data Pointer */
- };
- struct {
- u32 fip; /* FPU IP Offset */
- u32 fcs; /* FPU IP Selector */
- u32 foo; /* FPU Operand Offset */
- u32 fos; /* FPU Operand Selector */
- };
- };
- u32 mxcsr; /* MXCSR Register State */
- u32 mxcsr_mask; /* MXCSR Mask */
-
- /* 8*16 bytes for each FP-reg = 128 bytes: */
- u32 st_space[32];
-
- /* 16*16 bytes for each XMM-reg = 256 bytes: */
- u32 xmm_space[64];
-
- u32 padding[12];
-
- union {
- u32 padding1[12];
- u32 sw_reserved[12];
- };
-
-} __attribute__((aligned(16)));
-
-struct i387_soft_struct {
- u32 cwd;
- u32 swd;
- u32 twd;
- u32 fip;
- u32 fcs;
- u32 foo;
- u32 fos;
- /* 8*10 bytes for each FP-reg = 80 bytes: */
- u32 st_space[20];
- u8 ftop;
- u8 changed;
- u8 lookahead;
- u8 no_update;
- u8 rm;
- u8 alimit;
- struct math_emu_info *info;
- u32 entry_eip;
-};
-
-struct ymmh_struct {
- /* 16 * 16 bytes for each YMMH-reg = 256 bytes */
- u32 ymmh_space[64];
-};
-
-/* We don't support LWP yet: */
-struct lwp_struct {
- u8 reserved[128];
-};
-
-struct bndreg {
- u64 lower_bound;
- u64 upper_bound;
-} __packed;
-
-struct bndcsr {
- u64 bndcfgu;
- u64 bndstatus;
-} __packed;
-
-struct xsave_hdr_struct {
- u64 xstate_bv;
- u64 xcomp_bv;
- u64 reserved[6];
-} __attribute__((packed));
-
-struct xsave_struct {
- struct i387_fxsave_struct i387;
- struct xsave_hdr_struct xsave_hdr;
- struct ymmh_struct ymmh;
- struct lwp_struct lwp;
- struct bndreg bndreg[4];
- struct bndcsr bndcsr;
- /* new processor state extensions will go here */
-} __attribute__ ((packed, aligned (64)));
-
-union thread_xstate {
- struct i387_fsave_struct fsave;
- struct i387_fxsave_struct fxsave;
- struct i387_soft_struct soft;
- struct xsave_struct xsave;
-};
-
-struct fpu {
- unsigned int last_cpu;
- unsigned int has_fpu;
- union thread_xstate *state;
-};
-
#ifdef CONFIG_X86_64
DECLARE_PER_CPU(struct orig_ist, orig_ist);
@@ -483,8 +366,6 @@ DECLARE_PER_CPU(struct irq_stack *, softirq_stack);
#endif /* X86_64 */
extern unsigned int xstate_size;
-extern void free_thread_xstate(struct task_struct *);
-extern struct kmem_cache *task_xstate_cachep;
struct perf_event;
@@ -508,6 +389,10 @@ struct thread_struct {
unsigned long fs;
#endif
unsigned long gs;
+
+ /* Floating point and extended processor state */
+ struct fpu fpu;
+
/* Save middle states of ptrace breakpoints */
struct perf_event *ptrace_bps[HBP_NUM];
/* Debug status used for traps, single steps, etc... */
@@ -518,8 +403,6 @@ struct thread_struct {
unsigned long cr2;
unsigned long trap_nr;
unsigned long error_code;
- /* floating point and extended processor state */
- struct fpu fpu;
#ifdef CONFIG_X86_32
/* Virtual 86 mode info */
struct vm86_struct __user *vm86_info;
@@ -535,15 +418,6 @@ struct thread_struct {
unsigned long iopl;
/* Max allowed port in the bitmap, in bytes: */
unsigned io_bitmap_max;
- /*
- * fpu_counter contains the number of consecutive context switches
- * that the FPU is used. If this is over a threshold, the lazy fpu
- * saving becomes unlazy to save the trap. This is an unsigned char
- * so that after 256 times the counter wraps and the behavior turns
- * lazy again; this to deal with bursty apps that only use FPU for
- * a short time
- */
- unsigned char fpu_counter;
};
/*
@@ -928,24 +802,25 @@ extern int get_tsc_mode(unsigned long adr);
extern int set_tsc_mode(unsigned int val);
/* Register/unregister a process' MPX related resource */
-#define MPX_ENABLE_MANAGEMENT(tsk) mpx_enable_management((tsk))
-#define MPX_DISABLE_MANAGEMENT(tsk) mpx_disable_management((tsk))
+#define MPX_ENABLE_MANAGEMENT() mpx_enable_management()
+#define MPX_DISABLE_MANAGEMENT() mpx_disable_management()
#ifdef CONFIG_X86_INTEL_MPX
-extern int mpx_enable_management(struct task_struct *tsk);
-extern int mpx_disable_management(struct task_struct *tsk);
+extern int mpx_enable_management(void);
+extern int mpx_disable_management(void);
#else
-static inline int mpx_enable_management(struct task_struct *tsk)
+static inline int mpx_enable_management(void)
{
return -EINVAL;
}
-static inline int mpx_disable_management(struct task_struct *tsk)
+static inline int mpx_disable_management(void)
{
return -EINVAL;
}
#endif /* CONFIG_X86_INTEL_MPX */
extern u16 amd_get_nb_id(int cpu);
+extern u32 amd_get_nodes_per_socket(void);
static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves)
{
diff --git a/arch/x86/include/asm/proto.h b/arch/x86/include/asm/proto.h
index a90f8972dad5..a4a77286cb1d 100644
--- a/arch/x86/include/asm/proto.h
+++ b/arch/x86/include/asm/proto.h
@@ -5,12 +5,14 @@
/* misc architecture specific prototypes */
-void system_call(void);
void syscall_init(void);
-void ia32_syscall(void);
-void ia32_cstar_target(void);
-void ia32_sysenter_target(void);
+void entry_SYSCALL_64(void);
+void entry_SYSCALL_compat(void);
+void entry_INT80_32(void);
+void entry_INT80_compat(void);
+void entry_SYSENTER_32(void);
+void entry_SYSENTER_compat(void);
void x86_configure_nx(void);
void x86_report_nx(void);
diff --git a/arch/x86/include/asm/pvclock-abi.h b/arch/x86/include/asm/pvclock-abi.h
index 6167fd798188..655e07a48f6c 100644
--- a/arch/x86/include/asm/pvclock-abi.h
+++ b/arch/x86/include/asm/pvclock-abi.h
@@ -41,5 +41,6 @@ struct pvclock_wall_clock {
#define PVCLOCK_TSC_STABLE_BIT (1 << 0)
#define PVCLOCK_GUEST_STOPPED (1 << 1)
+#define PVCLOCK_COUNTS_FROM_ZERO (1 << 2)
#endif /* __ASSEMBLY__ */
#endif /* _ASM_X86_PVCLOCK_ABI_H */
diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h
index d6b078e9fa28..628954ceede1 100644
--- a/arch/x86/include/asm/pvclock.h
+++ b/arch/x86/include/asm/pvclock.h
@@ -86,7 +86,6 @@ unsigned __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src,
offset = pvclock_get_nsec_offset(src);
ret = src->system_time + offset;
ret_flags = src->flags;
- rdtsc_barrier();
*cycles = ret;
*flags = ret_flags;
diff --git a/arch/x86/include/asm/qspinlock.h b/arch/x86/include/asm/qspinlock.h
new file mode 100644
index 000000000000..9d51fae1cba3
--- /dev/null
+++ b/arch/x86/include/asm/qspinlock.h
@@ -0,0 +1,57 @@
+#ifndef _ASM_X86_QSPINLOCK_H
+#define _ASM_X86_QSPINLOCK_H
+
+#include <asm/cpufeature.h>
+#include <asm-generic/qspinlock_types.h>
+#include <asm/paravirt.h>
+
+#define queued_spin_unlock queued_spin_unlock
+/**
+ * queued_spin_unlock - release a queued spinlock
+ * @lock : Pointer to queued spinlock structure
+ *
+ * A smp_store_release() on the least-significant byte.
+ */
+static inline void native_queued_spin_unlock(struct qspinlock *lock)
+{
+ smp_store_release((u8 *)lock, 0);
+}
+
+#ifdef CONFIG_PARAVIRT_SPINLOCKS
+extern void native_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
+extern void __pv_init_lock_hash(void);
+extern void __pv_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
+extern void __raw_callee_save___pv_queued_spin_unlock(struct qspinlock *lock);
+
+static inline void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
+{
+ pv_queued_spin_lock_slowpath(lock, val);
+}
+
+static inline void queued_spin_unlock(struct qspinlock *lock)
+{
+ pv_queued_spin_unlock(lock);
+}
+#else
+static inline void queued_spin_unlock(struct qspinlock *lock)
+{
+ native_queued_spin_unlock(lock);
+}
+#endif
+
+#define virt_queued_spin_lock virt_queued_spin_lock
+
+static inline bool virt_queued_spin_lock(struct qspinlock *lock)
+{
+ if (!static_cpu_has(X86_FEATURE_HYPERVISOR))
+ return false;
+
+ while (atomic_cmpxchg(&lock->val, 0, _Q_LOCKED_VAL) != 0)
+ cpu_relax();
+
+ return true;
+}
+
+#include <asm-generic/qspinlock.h>
+
+#endif /* _ASM_X86_QSPINLOCK_H */
diff --git a/arch/x86/include/asm/qspinlock_paravirt.h b/arch/x86/include/asm/qspinlock_paravirt.h
new file mode 100644
index 000000000000..b002e711ba88
--- /dev/null
+++ b/arch/x86/include/asm/qspinlock_paravirt.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_QSPINLOCK_PARAVIRT_H
+#define __ASM_QSPINLOCK_PARAVIRT_H
+
+PV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock);
+
+#endif
diff --git a/arch/x86/include/asm/serial.h b/arch/x86/include/asm/serial.h
index 8378b8c9109c..bb658211edad 100644
--- a/arch/x86/include/asm/serial.h
+++ b/arch/x86/include/asm/serial.h
@@ -11,7 +11,7 @@
#define BASE_BAUD (1843200/16)
/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
# define STD_COMX_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
# define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | 0 | UPF_AUTO_IRQ)
#else
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index f69e06b283fb..11af24e09c8a 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -60,17 +60,24 @@ static inline void x86_ce4100_early_setup(void) { }
#ifndef _SETUP
#include <asm/espfix.h>
+#include <linux/kernel.h>
/*
* This is set up by the setup-routine at boot-time
*/
extern struct boot_params boot_params;
+extern char _text[];
static inline bool kaslr_enabled(void)
{
return !!(boot_params.hdr.loadflags & KASLR_FLAG);
}
+static inline unsigned long kaslr_offset(void)
+{
+ return (unsigned long)&_text - __START_KERNEL;
+}
+
/*
* Do NOT EVER look at the BIOS memory size location.
* It does not work on many machines.
diff --git a/arch/x86/include/asm/simd.h b/arch/x86/include/asm/simd.h
index ee80b92f0096..6c8a7ed13365 100644
--- a/arch/x86/include/asm/simd.h
+++ b/arch/x86/include/asm/simd.h
@@ -1,5 +1,5 @@
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
/*
* may_use_simd - whether it is allowable at this time to issue SIMD
diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
index 17a8dced12da..222a6a3ca2b5 100644
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -37,16 +37,6 @@ DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map);
DECLARE_PER_CPU_READ_MOSTLY(u16, cpu_llc_id);
DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
-static inline struct cpumask *cpu_sibling_mask(int cpu)
-{
- return per_cpu(cpu_sibling_map, cpu);
-}
-
-static inline struct cpumask *cpu_core_mask(int cpu)
-{
- return per_cpu(cpu_core_map, cpu);
-}
-
static inline struct cpumask *cpu_llc_shared_mask(int cpu)
{
return per_cpu(cpu_llc_shared_map, cpu);
diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h
index aeb4666e0c0a..2270e41b32fd 100644
--- a/arch/x86/include/asm/special_insns.h
+++ b/arch/x86/include/asm/special_insns.h
@@ -215,6 +215,44 @@ static inline void clwb(volatile void *__p)
: [pax] "a" (p));
}
+/**
+ * pcommit_sfence() - persistent commit and fence
+ *
+ * The PCOMMIT instruction ensures that data that has been flushed from the
+ * processor's cache hierarchy with CLWB, CLFLUSHOPT or CLFLUSH is accepted to
+ * memory and is durable on the DIMM. The primary use case for this is
+ * persistent memory.
+ *
+ * This function shows how to properly use CLWB/CLFLUSHOPT/CLFLUSH and PCOMMIT
+ * with appropriate fencing.
+ *
+ * Example:
+ * void flush_and_commit_buffer(void *vaddr, unsigned int size)
+ * {
+ * unsigned long clflush_mask = boot_cpu_data.x86_clflush_size - 1;
+ * void *vend = vaddr + size;
+ * void *p;
+ *
+ * for (p = (void *)((unsigned long)vaddr & ~clflush_mask);
+ * p < vend; p += boot_cpu_data.x86_clflush_size)
+ * clwb(p);
+ *
+ * // SFENCE to order CLWB/CLFLUSHOPT/CLFLUSH cache flushes
+ * // MFENCE via mb() also works
+ * wmb();
+ *
+ * // PCOMMIT and the required SFENCE for ordering
+ * pcommit_sfence();
+ * }
+ *
+ * After this function completes the data pointed to by 'vaddr' has been
+ * accepted to memory and will be durable if the 'vaddr' points to persistent
+ * memory.
+ *
+ * PCOMMIT must always be ordered by an MFENCE or SFENCE, so to help simplify
+ * things we include both the PCOMMIT and the required SFENCE in the
+ * alternatives generated by pcommit_sfence().
+ */
static inline void pcommit_sfence(void)
{
alternative(ASM_NOP7,
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index 64b611782ef0..be0a05913b91 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -42,6 +42,10 @@
extern struct static_key paravirt_ticketlocks_enabled;
static __always_inline bool static_key_false(struct static_key *key);
+#ifdef CONFIG_QUEUED_SPINLOCKS
+#include <asm/qspinlock.h>
+#else
+
#ifdef CONFIG_PARAVIRT_SPINLOCKS
static inline void __ticket_enter_slowpath(arch_spinlock_t *lock)
@@ -196,6 +200,7 @@ static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
cpu_relax();
}
}
+#endif /* CONFIG_QUEUED_SPINLOCKS */
/*
* Read-write spinlocks, allowing multiple readers
diff --git a/arch/x86/include/asm/spinlock_types.h b/arch/x86/include/asm/spinlock_types.h
index 5f9d7572d82b..65c3e37f879a 100644
--- a/arch/x86/include/asm/spinlock_types.h
+++ b/arch/x86/include/asm/spinlock_types.h
@@ -23,6 +23,9 @@ typedef u32 __ticketpair_t;
#define TICKET_SHIFT (sizeof(__ticket_t) * 8)
+#ifdef CONFIG_QUEUED_SPINLOCKS
+#include <asm-generic/qspinlock_types.h>
+#else
typedef struct arch_spinlock {
union {
__ticketpair_t head_tail;
@@ -33,6 +36,7 @@ typedef struct arch_spinlock {
} arch_spinlock_t;
#define __ARCH_SPIN_LOCK_UNLOCKED { { 0 } }
+#endif /* CONFIG_QUEUED_SPINLOCKS */
#include <asm-generic/qrwlock_types.h>
diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h
index 6a998598f172..c2e00bb2a136 100644
--- a/arch/x86/include/asm/stackprotector.h
+++ b/arch/x86/include/asm/stackprotector.h
@@ -39,7 +39,9 @@
#include <asm/processor.h>
#include <asm/percpu.h>
#include <asm/desc.h>
+
#include <linux/random.h>
+#include <linux/sched.h>
/*
* 24 byte read-only segment initializer for stack canary. Linker
diff --git a/arch/x86/include/asm/suspend_32.h b/arch/x86/include/asm/suspend_32.h
index 552d6c90a6d4..d1793f06854d 100644
--- a/arch/x86/include/asm/suspend_32.h
+++ b/arch/x86/include/asm/suspend_32.h
@@ -7,7 +7,7 @@
#define _ASM_X86_SUSPEND_32_H
#include <asm/desc.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
/* image of the saved processor state */
struct saved_context {
diff --git a/arch/x86/include/asm/suspend_64.h b/arch/x86/include/asm/suspend_64.h
index bc6232834bab..7ebf0ebe4e68 100644
--- a/arch/x86/include/asm/suspend_64.h
+++ b/arch/x86/include/asm/suspend_64.h
@@ -7,7 +7,7 @@
#define _ASM_X86_SUSPEND_64_H
#include <asm/desc.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
/*
* Image of the saved processor state, used by the low level ACPI suspend to
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index b4bdec3e9523..225ee545e1a0 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -177,8 +177,6 @@ struct thread_info {
*/
#ifndef __ASSEMBLY__
-DECLARE_PER_CPU(unsigned long, kernel_stack);
-
static inline struct thread_info *current_thread_info(void)
{
return (struct thread_info *)(current_top_of_stack() - THREAD_SIZE);
@@ -197,9 +195,13 @@ static inline unsigned long current_stack_pointer(void)
#else /* !__ASSEMBLY__ */
+#ifdef CONFIG_X86_64
+# define cpu_current_top_of_stack (cpu_tss + TSS_sp0)
+#endif
+
/* Load thread_info address into "reg" */
#define GET_THREAD_INFO(reg) \
- _ASM_MOV PER_CPU_VAR(kernel_stack),reg ; \
+ _ASM_MOV PER_CPU_VAR(cpu_current_top_of_stack),reg ; \
_ASM_SUB $(THREAD_SIZE),reg ;
/*
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index 0e8f04f2c26f..0fb46482dfde 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -26,7 +26,7 @@
#define _ASM_X86_TOPOLOGY_H
#ifdef CONFIG_X86_32
-# ifdef CONFIG_X86_HT
+# ifdef CONFIG_SMP
# define ENABLE_TOPO_DEFINES
# endif
#else
@@ -124,7 +124,7 @@ extern const struct cpumask *cpu_coregroup_mask(int cpu);
#ifdef ENABLE_TOPO_DEFINES
#define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu))
-#define topology_thread_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu))
+#define topology_sibling_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu))
#endif
static inline void arch_fix_phys_package_id(int num, u32 slot)
diff --git a/arch/x86/include/asm/trace/irq_vectors.h b/arch/x86/include/asm/trace/irq_vectors.h
index 4cab890007a7..38a09a13a9bc 100644
--- a/arch/x86/include/asm/trace/irq_vectors.h
+++ b/arch/x86/include/asm/trace/irq_vectors.h
@@ -101,6 +101,12 @@ DEFINE_IRQ_VECTOR_EVENT(call_function_single);
DEFINE_IRQ_VECTOR_EVENT(threshold_apic);
/*
+ * deferred_error_apic - called when entering/exiting a deferred apic interrupt
+ * vector handler
+ */
+DEFINE_IRQ_VECTOR_EVENT(deferred_error_apic);
+
+/*
* thermal_apic - called when entering/exiting a thermal apic interrupt
* vector handler
*/
diff --git a/arch/x86/include/asm/trace/mpx.h b/arch/x86/include/asm/trace/mpx.h
new file mode 100644
index 000000000000..173dd3ba108c
--- /dev/null
+++ b/arch/x86/include/asm/trace/mpx.h
@@ -0,0 +1,132 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mpx
+
+#if !defined(_TRACE_MPX_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MPX_H
+
+#include <linux/tracepoint.h>
+
+#ifdef CONFIG_X86_INTEL_MPX
+
+TRACE_EVENT(mpx_bounds_register_exception,
+
+ TP_PROTO(void *addr_referenced,
+ const struct bndreg *bndreg),
+ TP_ARGS(addr_referenced, bndreg),
+
+ TP_STRUCT__entry(
+ __field(void *, addr_referenced)
+ __field(u64, lower_bound)
+ __field(u64, upper_bound)
+ ),
+
+ TP_fast_assign(
+ __entry->addr_referenced = addr_referenced;
+ __entry->lower_bound = bndreg->lower_bound;
+ __entry->upper_bound = bndreg->upper_bound;
+ ),
+ /*
+ * Note that we are printing out the '~' of the upper
+ * bounds register here. It is actually stored in its
+ * one's complement form so that its 'init' state
+ * corresponds to all 0's. But, that looks like
+ * gibberish when printed out, so print out the 1's
+ * complement instead of the actual value here. Note
+ * though that you still need to specify filters for the
+ * actual value, not the displayed one.
+ */
+ TP_printk("address referenced: 0x%p bounds: lower: 0x%llx ~upper: 0x%llx",
+ __entry->addr_referenced,
+ __entry->lower_bound,
+ ~__entry->upper_bound
+ )
+);
+
+TRACE_EVENT(bounds_exception_mpx,
+
+ TP_PROTO(const struct bndcsr *bndcsr),
+ TP_ARGS(bndcsr),
+
+ TP_STRUCT__entry(
+ __field(u64, bndcfgu)
+ __field(u64, bndstatus)
+ ),
+
+ TP_fast_assign(
+ /* need to get rid of the 'const' on bndcsr */
+ __entry->bndcfgu = (u64)bndcsr->bndcfgu;
+ __entry->bndstatus = (u64)bndcsr->bndstatus;
+ ),
+
+ TP_printk("bndcfgu:0x%llx bndstatus:0x%llx",
+ __entry->bndcfgu,
+ __entry->bndstatus)
+);
+
+DECLARE_EVENT_CLASS(mpx_range_trace,
+
+ TP_PROTO(unsigned long start,
+ unsigned long end),
+ TP_ARGS(start, end),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, start)
+ __field(unsigned long, end)
+ ),
+
+ TP_fast_assign(
+ __entry->start = start;
+ __entry->end = end;
+ ),
+
+ TP_printk("[0x%p:0x%p]",
+ (void *)__entry->start,
+ (void *)__entry->end
+ )
+);
+
+DEFINE_EVENT(mpx_range_trace, mpx_unmap_zap,
+ TP_PROTO(unsigned long start, unsigned long end),
+ TP_ARGS(start, end)
+);
+
+DEFINE_EVENT(mpx_range_trace, mpx_unmap_search,
+ TP_PROTO(unsigned long start, unsigned long end),
+ TP_ARGS(start, end)
+);
+
+TRACE_EVENT(mpx_new_bounds_table,
+
+ TP_PROTO(unsigned long table_vaddr),
+ TP_ARGS(table_vaddr),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, table_vaddr)
+ ),
+
+ TP_fast_assign(
+ __entry->table_vaddr = table_vaddr;
+ ),
+
+ TP_printk("table vaddr:%p", (void *)__entry->table_vaddr)
+);
+
+#else
+
+/*
+ * This gets used outside of MPX-specific code, so we need a stub.
+ */
+static inline void trace_bounds_exception_mpx(const struct bndcsr *bndcsr)
+{
+}
+
+#endif /* CONFIG_X86_INTEL_MPX */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH asm/trace/
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE mpx
+#endif /* _TRACE_MPX_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index 4e49d7dff78e..c5380bea2a36 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -108,7 +108,8 @@ extern int panic_on_unrecovered_nmi;
void math_emulate(struct math_emu_info *);
#ifndef CONFIG_X86_32
asmlinkage void smp_thermal_interrupt(void);
-asmlinkage void mce_threshold_interrupt(void);
+asmlinkage void smp_threshold_interrupt(void);
+asmlinkage void smp_deferred_error_interrupt(void);
#endif
extern enum ctx_state ist_enter(struct pt_regs *regs);
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index ace9dec050b1..a8df874f3e88 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -74,7 +74,8 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
* @addr: User space pointer to start of block to check
* @size: Size of block to check
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Checks if a pointer to a block of memory in user space is valid.
*
@@ -145,7 +146,8 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
@@ -240,7 +242,8 @@ extern void __put_user_8(void);
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
@@ -455,7 +458,8 @@ struct __large_struct { unsigned long buf[100]; };
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
@@ -479,7 +483,8 @@ struct __large_struct { unsigned long buf[100]; };
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h
index 3c03a5de64d3..f5dcb5204dcd 100644
--- a/arch/x86/include/asm/uaccess_32.h
+++ b/arch/x86/include/asm/uaccess_32.h
@@ -59,6 +59,10 @@ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
__put_user_size(*(u32 *)from, (u32 __user *)to,
4, ret, 4);
return ret;
+ case 8:
+ __put_user_size(*(u64 *)from, (u64 __user *)to,
+ 8, ret, 8);
+ return ret;
}
}
return __copy_to_user_ll(to, from, n);
@@ -70,7 +74,8 @@ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from kernel space to user space. Caller must check
* the specified block with access_ok() before calling this function.
@@ -117,7 +122,8 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from user space to kernel space. Caller must check
* the specified block with access_ok() before calling this function.
diff --git a/arch/x86/include/asm/user.h b/arch/x86/include/asm/user.h
index ccab4af1646d..59a54e869f15 100644
--- a/arch/x86/include/asm/user.h
+++ b/arch/x86/include/asm/user.h
@@ -14,8 +14,8 @@ struct user_ymmh_regs {
__u32 ymmh_space[64];
};
-struct user_xsave_hdr {
- __u64 xstate_bv;
+struct user_xstate_header {
+ __u64 xfeatures;
__u64 reserved1[2];
__u64 reserved2[5];
};
@@ -41,11 +41,11 @@ struct user_xsave_hdr {
* particular process/thread.
*
* Also when the user modifies certain state FP/SSE/etc through the
- * ptrace interface, they must ensure that the xsave_hdr.xstate_bv
+ * ptrace interface, they must ensure that the header.xfeatures
* bytes[512..519] of the memory layout are updated correspondingly.
* i.e., for example when FP state is modified to a non-init state,
- * xsave_hdr.xstate_bv's bit 0 must be set to '1', when SSE is modified to
- * non-init state, xsave_hdr.xstate_bv's bit 1 must to be set to '1', etc.
+ * header.xfeatures's bit 0 must be set to '1', when SSE is modified to
+ * non-init state, header.xfeatures's bit 1 must to be set to '1', etc.
*/
#define USER_XSTATE_FX_SW_WORDS 6
#define USER_XSTATE_XCR0_WORD 0
@@ -55,7 +55,7 @@ struct user_xstateregs {
__u64 fpx_space[58];
__u64 xstate_fx_sw[USER_XSTATE_FX_SW_WORDS];
} i387;
- struct user_xsave_hdr xsave_hdr;
+ struct user_xstate_header header;
struct user_ymmh_regs ymmh;
/* further processor state extensions go here */
};
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index f58a9c7a3c86..48d34d28f5a6 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -171,38 +171,17 @@ struct x86_platform_ops {
};
struct pci_dev;
-struct msi_msg;
struct x86_msi_ops {
int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
- void (*compose_msi_msg)(struct pci_dev *dev, unsigned int irq,
- unsigned int dest, struct msi_msg *msg,
- u8 hpet_id);
void (*teardown_msi_irq)(unsigned int irq);
void (*teardown_msi_irqs)(struct pci_dev *dev);
void (*restore_msi_irqs)(struct pci_dev *dev);
- int (*setup_hpet_msi)(unsigned int irq, unsigned int id);
};
-struct IO_APIC_route_entry;
-struct io_apic_irq_attr;
-struct irq_data;
-struct cpumask;
-
struct x86_io_apic_ops {
- void (*init) (void);
unsigned int (*read) (unsigned int apic, unsigned int reg);
- void (*write) (unsigned int apic, unsigned int reg, unsigned int value);
- void (*modify) (unsigned int apic, unsigned int reg, unsigned int value);
void (*disable)(void);
- void (*print_entries)(unsigned int apic, unsigned int nr_entries);
- int (*set_affinity)(struct irq_data *data,
- const struct cpumask *mask,
- bool force);
- int (*setup_entry)(int irq, struct IO_APIC_route_entry *entry,
- unsigned int destination, int vector,
- struct io_apic_irq_attr *attr);
- void (*eoi_ioapic_pin)(int apic, int pin, int vector);
};
extern struct x86_init_ops x86_init;
diff --git a/arch/x86/include/asm/xcr.h b/arch/x86/include/asm/xcr.h
deleted file mode 100644
index f2cba4e79a23..000000000000
--- a/arch/x86/include/asm/xcr.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- linux-c -*- ------------------------------------------------------- *
- *
- * Copyright 2008 rPath, Inc. - All Rights Reserved
- *
- * This file is part of the Linux kernel, and is made available under
- * the terms of the GNU General Public License version 2 or (at your
- * option) any later version; incorporated herein by reference.
- *
- * ----------------------------------------------------------------------- */
-
-/*
- * asm-x86/xcr.h
- *
- * Definitions for the eXtended Control Register instructions
- */
-
-#ifndef _ASM_X86_XCR_H
-#define _ASM_X86_XCR_H
-
-#define XCR_XFEATURE_ENABLED_MASK 0x00000000
-
-#ifdef __KERNEL__
-# ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-static inline u64 xgetbv(u32 index)
-{
- u32 eax, edx;
-
- asm volatile(".byte 0x0f,0x01,0xd0" /* xgetbv */
- : "=a" (eax), "=d" (edx)
- : "c" (index));
- return eax + ((u64)edx << 32);
-}
-
-static inline void xsetbv(u32 index, u64 value)
-{
- u32 eax = value;
- u32 edx = value >> 32;
-
- asm volatile(".byte 0x0f,0x01,0xd1" /* xsetbv */
- : : "a" (eax), "d" (edx), "c" (index));
-}
-
-# endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
-
-#endif /* _ASM_X86_XCR_H */
diff --git a/arch/x86/include/asm/xor.h b/arch/x86/include/asm/xor.h
index d8829751b3f8..1f5c5161ead6 100644
--- a/arch/x86/include/asm/xor.h
+++ b/arch/x86/include/asm/xor.h
@@ -36,7 +36,7 @@
* no advantages to be gotten from x86-64 here anyways.
*/
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
#ifdef CONFIG_X86_32
/* reduce register pressure */
diff --git a/arch/x86/include/asm/xor_32.h b/arch/x86/include/asm/xor_32.h
index ce05722e3c68..5a08bc8bff33 100644
--- a/arch/x86/include/asm/xor_32.h
+++ b/arch/x86/include/asm/xor_32.h
@@ -26,7 +26,7 @@
#define XO3(x, y) " pxor 8*("#x")(%4), %%mm"#y" ;\n"
#define XO4(x, y) " pxor 8*("#x")(%5), %%mm"#y" ;\n"
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
static void
xor_pII_mmx_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
diff --git a/arch/x86/include/asm/xor_avx.h b/arch/x86/include/asm/xor_avx.h
index 492b29802f57..7c0a517ec751 100644
--- a/arch/x86/include/asm/xor_avx.h
+++ b/arch/x86/include/asm/xor_avx.h
@@ -18,7 +18,7 @@
#ifdef CONFIG_AS_AVX
#include <linux/compiler.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
#define BLOCK4(i) \
BLOCK(32 * i, 0) \
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
deleted file mode 100644
index c9a6d68b8d62..000000000000
--- a/arch/x86/include/asm/xsave.h
+++ /dev/null
@@ -1,257 +0,0 @@
-#ifndef __ASM_X86_XSAVE_H
-#define __ASM_X86_XSAVE_H
-
-#include <linux/types.h>
-#include <asm/processor.h>
-
-#define XSTATE_CPUID 0x0000000d
-
-#define XSTATE_FP 0x1
-#define XSTATE_SSE 0x2
-#define XSTATE_YMM 0x4
-#define XSTATE_BNDREGS 0x8
-#define XSTATE_BNDCSR 0x10
-#define XSTATE_OPMASK 0x20
-#define XSTATE_ZMM_Hi256 0x40
-#define XSTATE_Hi16_ZMM 0x80
-
-#define XSTATE_FPSSE (XSTATE_FP | XSTATE_SSE)
-#define XSTATE_AVX512 (XSTATE_OPMASK | XSTATE_ZMM_Hi256 | XSTATE_Hi16_ZMM)
-/* Bit 63 of XCR0 is reserved for future expansion */
-#define XSTATE_EXTEND_MASK (~(XSTATE_FPSSE | (1ULL << 63)))
-
-#define FXSAVE_SIZE 512
-
-#define XSAVE_HDR_SIZE 64
-#define XSAVE_HDR_OFFSET FXSAVE_SIZE
-
-#define XSAVE_YMM_SIZE 256
-#define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET)
-
-/* Supported features which support lazy state saving */
-#define XSTATE_LAZY (XSTATE_FP | XSTATE_SSE | XSTATE_YMM \
- | XSTATE_OPMASK | XSTATE_ZMM_Hi256 | XSTATE_Hi16_ZMM)
-
-/* Supported features which require eager state saving */
-#define XSTATE_EAGER (XSTATE_BNDREGS | XSTATE_BNDCSR)
-
-/* All currently supported features */
-#define XCNTXT_MASK (XSTATE_LAZY | XSTATE_EAGER)
-
-#ifdef CONFIG_X86_64
-#define REX_PREFIX "0x48, "
-#else
-#define REX_PREFIX
-#endif
-
-extern unsigned int xstate_size;
-extern u64 pcntxt_mask;
-extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
-extern struct xsave_struct *init_xstate_buf;
-
-extern void xsave_init(void);
-extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask);
-extern int init_fpu(struct task_struct *child);
-
-/* These macros all use (%edi)/(%rdi) as the single memory argument. */
-#define XSAVE ".byte " REX_PREFIX "0x0f,0xae,0x27"
-#define XSAVEOPT ".byte " REX_PREFIX "0x0f,0xae,0x37"
-#define XSAVES ".byte " REX_PREFIX "0x0f,0xc7,0x2f"
-#define XRSTOR ".byte " REX_PREFIX "0x0f,0xae,0x2f"
-#define XRSTORS ".byte " REX_PREFIX "0x0f,0xc7,0x1f"
-
-#define xstate_fault ".section .fixup,\"ax\"\n" \
- "3: movl $-1,%[err]\n" \
- " jmp 2b\n" \
- ".previous\n" \
- _ASM_EXTABLE(1b, 3b) \
- : [err] "=r" (err)
-
-/*
- * This function is called only during boot time when x86 caps are not set
- * up and alternative can not be used yet.
- */
-static inline int xsave_state_booting(struct xsave_struct *fx, u64 mask)
-{
- u32 lmask = mask;
- u32 hmask = mask >> 32;
- int err = 0;
-
- WARN_ON(system_state != SYSTEM_BOOTING);
-
- if (boot_cpu_has(X86_FEATURE_XSAVES))
- asm volatile("1:"XSAVES"\n\t"
- "2:\n\t"
- xstate_fault
- : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
- : "memory");
- else
- asm volatile("1:"XSAVE"\n\t"
- "2:\n\t"
- xstate_fault
- : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
- : "memory");
- return err;
-}
-
-/*
- * This function is called only during boot time when x86 caps are not set
- * up and alternative can not be used yet.
- */
-static inline int xrstor_state_booting(struct xsave_struct *fx, u64 mask)
-{
- u32 lmask = mask;
- u32 hmask = mask >> 32;
- int err = 0;
-
- WARN_ON(system_state != SYSTEM_BOOTING);
-
- if (boot_cpu_has(X86_FEATURE_XSAVES))
- asm volatile("1:"XRSTORS"\n\t"
- "2:\n\t"
- xstate_fault
- : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
- : "memory");
- else
- asm volatile("1:"XRSTOR"\n\t"
- "2:\n\t"
- xstate_fault
- : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
- : "memory");
- return err;
-}
-
-/*
- * Save processor xstate to xsave area.
- */
-static inline int xsave_state(struct xsave_struct *fx, u64 mask)
-{
- u32 lmask = mask;
- u32 hmask = mask >> 32;
- int err = 0;
-
- /*
- * If xsaves is enabled, xsaves replaces xsaveopt because
- * it supports compact format and supervisor states in addition to
- * modified optimization in xsaveopt.
- *
- * Otherwise, if xsaveopt is enabled, xsaveopt replaces xsave
- * because xsaveopt supports modified optimization which is not
- * supported by xsave.
- *
- * If none of xsaves and xsaveopt is enabled, use xsave.
- */
- alternative_input_2(
- "1:"XSAVE,
- XSAVEOPT,
- X86_FEATURE_XSAVEOPT,
- XSAVES,
- X86_FEATURE_XSAVES,
- [fx] "D" (fx), "a" (lmask), "d" (hmask) :
- "memory");
- asm volatile("2:\n\t"
- xstate_fault
- : "0" (0)
- : "memory");
-
- return err;
-}
-
-/*
- * Restore processor xstate from xsave area.
- */
-static inline int xrstor_state(struct xsave_struct *fx, u64 mask)
-{
- int err = 0;
- u32 lmask = mask;
- u32 hmask = mask >> 32;
-
- /*
- * Use xrstors to restore context if it is enabled. xrstors supports
- * compacted format of xsave area which is not supported by xrstor.
- */
- alternative_input(
- "1: " XRSTOR,
- XRSTORS,
- X86_FEATURE_XSAVES,
- "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
- : "memory");
-
- asm volatile("2:\n"
- xstate_fault
- : "0" (0)
- : "memory");
-
- return err;
-}
-
-/*
- * Save xstate context for old process during context switch.
- */
-static inline void fpu_xsave(struct fpu *fpu)
-{
- xsave_state(&fpu->state->xsave, -1);
-}
-
-/*
- * Restore xstate context for new process during context switch.
- */
-static inline int fpu_xrstor_checking(struct xsave_struct *fx)
-{
- return xrstor_state(fx, -1);
-}
-
-/*
- * Save xstate to user space xsave area.
- *
- * We don't use modified optimization because xrstor/xrstors might track
- * a different application.
- *
- * We don't use compacted format xsave area for
- * backward compatibility for old applications which don't understand
- * compacted format of xsave area.
- */
-static inline int xsave_user(struct xsave_struct __user *buf)
-{
- int err;
-
- /*
- * Clear the xsave header first, so that reserved fields are
- * initialized to zero.
- */
- err = __clear_user(&buf->xsave_hdr, sizeof(buf->xsave_hdr));
- if (unlikely(err))
- return -EFAULT;
-
- __asm__ __volatile__(ASM_STAC "\n"
- "1:"XSAVE"\n"
- "2: " ASM_CLAC "\n"
- xstate_fault
- : "D" (buf), "a" (-1), "d" (-1), "0" (0)
- : "memory");
- return err;
-}
-
-/*
- * Restore xstate from user space xsave area.
- */
-static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
-{
- int err = 0;
- struct xsave_struct *xstate = ((__force struct xsave_struct *)buf);
- u32 lmask = mask;
- u32 hmask = mask >> 32;
-
- __asm__ __volatile__(ASM_STAC "\n"
- "1:"XRSTOR"\n"
- "2: " ASM_CLAC "\n"
- xstate_fault
- : "D" (xstate), "a" (lmask), "d" (hmask), "0" (0)
- : "memory"); /* memory required? */
- return err;
-}
-
-void *get_xsave_addr(struct xsave_struct *xsave, int xstate);
-void setup_xstate_comp(void);
-
-#endif
diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
index d7dcef58aefa..a4ae82eb82aa 100644
--- a/arch/x86/include/uapi/asm/kvm.h
+++ b/arch/x86/include/uapi/asm/kvm.h
@@ -106,6 +106,8 @@ struct kvm_ioapic_state {
#define KVM_IRQCHIP_IOAPIC 2
#define KVM_NR_IRQCHIPS 3
+#define KVM_RUN_X86_SMM (1 << 0)
+
/* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs {
/* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
@@ -281,6 +283,7 @@ struct kvm_reinject_control {
#define KVM_VCPUEVENT_VALID_NMI_PENDING 0x00000001
#define KVM_VCPUEVENT_VALID_SIPI_VECTOR 0x00000002
#define KVM_VCPUEVENT_VALID_SHADOW 0x00000004
+#define KVM_VCPUEVENT_VALID_SMM 0x00000008
/* Interrupt shadow states */
#define KVM_X86_SHADOW_INT_MOV_SS 0x01
@@ -309,7 +312,13 @@ struct kvm_vcpu_events {
} nmi;
__u32 sipi_vector;
__u32 flags;
- __u32 reserved[10];
+ struct {
+ __u8 smm;
+ __u8 pending;
+ __u8 smm_inside_nmi;
+ __u8 latched_init;
+ } smi;
+ __u32 reserved[9];
};
/* for KVM_GET/SET_DEBUGREGS */
@@ -345,4 +354,7 @@ struct kvm_xcrs {
struct kvm_sync_regs {
};
+#define KVM_QUIRK_LINT0_REENABLED (1 << 0)
+#define KVM_QUIRK_CD_NW_CLEARED (1 << 1)
+
#endif /* _ASM_X86_KVM_H */
diff --git a/arch/x86/include/uapi/asm/msr.h b/arch/x86/include/uapi/asm/msr.h
index 155e51048fa4..c41f4fe25483 100644
--- a/arch/x86/include/uapi/asm/msr.h
+++ b/arch/x86/include/uapi/asm/msr.h
@@ -1,8 +1,6 @@
#ifndef _UAPI_ASM_X86_MSR_H
#define _UAPI_ASM_X86_MSR_H
-#include <asm/msr-index.h>
-
#ifndef __ASSEMBLY__
#include <linux/types.h>
diff --git a/arch/x86/include/uapi/asm/mtrr.h b/arch/x86/include/uapi/asm/mtrr.h
index d0acb658c8f4..7528dcf59691 100644
--- a/arch/x86/include/uapi/asm/mtrr.h
+++ b/arch/x86/include/uapi/asm/mtrr.h
@@ -103,7 +103,7 @@ struct mtrr_state_type {
#define MTRRIOC_GET_PAGE_ENTRY _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry)
#define MTRRIOC_KILL_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 9, struct mtrr_sentry)
-/* These are the region types */
+/* MTRR memory types, which are defined in SDM */
#define MTRR_TYPE_UNCACHABLE 0
#define MTRR_TYPE_WRCOMB 1
/*#define MTRR_TYPE_ 2*/
@@ -113,5 +113,11 @@ struct mtrr_state_type {
#define MTRR_TYPE_WRBACK 6
#define MTRR_NUM_TYPES 7
+/*
+ * Invalid MTRR memory type. mtrr_type_lookup() returns this value when
+ * MTRRs are disabled. Note, this value is allocated from the reserved
+ * values (0x7-0xff) of the MTRR memory types.
+ */
+#define MTRR_TYPE_INVALID 0xff
#endif /* _UAPI_ASM_X86_MTRR_H */
diff --git a/arch/x86/include/uapi/asm/sigcontext.h b/arch/x86/include/uapi/asm/sigcontext.h
index 16dc4e8a2cd3..0e8a973de9ee 100644
--- a/arch/x86/include/uapi/asm/sigcontext.h
+++ b/arch/x86/include/uapi/asm/sigcontext.h
@@ -25,7 +25,7 @@ struct _fpx_sw_bytes {
__u32 extended_size; /* total size of the layout referred by
* fpstate pointer in the sigcontext.
*/
- __u64 xstate_bv;
+ __u64 xfeatures;
/* feature bit mask (including fp/sse/extended
* state) that is present in the memory
* layout.
@@ -209,8 +209,8 @@ struct sigcontext {
#endif /* !__i386__ */
-struct _xsave_hdr {
- __u64 xstate_bv;
+struct _header {
+ __u64 xfeatures;
__u64 reserved1[2];
__u64 reserved2[5];
};
@@ -228,7 +228,7 @@ struct _ymmh_state {
*/
struct _xstate {
struct _fpstate fpstate;
- struct _xsave_hdr xstate_hdr;
+ struct _header xstate_hdr;
struct _ymmh_state ymmh;
/* new processor state extensions go here */
};
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 9bcd0b56ca17..0f15af41bd80 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -22,7 +22,7 @@ KASAN_SANITIZE_dumpstack_$(BITS).o := n
CFLAGS_irq.o := -I$(src)/../include/asm/trace
-obj-y := process_$(BITS).o signal.o entry_$(BITS).o
+obj-y := process_$(BITS).o signal.o
obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
obj-y += time.o ioport.o ldt.o dumpstack.o nmi.o
obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o
@@ -31,9 +31,6 @@ obj-y += probe_roms.o
obj-$(CONFIG_X86_32) += i386_ksyms_32.o
obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o
obj-$(CONFIG_X86_64) += mcount_64.o
-obj-y += syscall_$(BITS).o vsyscall_gtod.o
-obj-$(CONFIG_IA32_EMULATION) += syscall_32.o
-obj-$(CONFIG_X86_VSYSCALL_EMULATION) += vsyscall_64.o vsyscall_emu_64.o
obj-$(CONFIG_X86_ESPFIX64) += espfix_64.o
obj-$(CONFIG_SYSFS) += ksysfs.o
obj-y += bootflag.o e820.o
@@ -44,7 +41,7 @@ obj-y += pci-iommu_table.o
obj-y += resource.o
obj-y += process.o
-obj-y += i387.o xsave.o
+obj-y += fpu/
obj-y += ptrace.o
obj-$(CONFIG_X86_32) += tls.o
obj-$(CONFIG_IA32_EMULATION) += tls.o
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index dbe76a14c3c9..e49ee24da85e 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -31,12 +31,12 @@
#include <linux/module.h>
#include <linux/dmi.h>
#include <linux/irq.h>
-#include <linux/irqdomain.h>
#include <linux/slab.h>
#include <linux/bootmem.h>
#include <linux/ioport.h>
#include <linux/pci.h>
+#include <asm/irqdomain.h>
#include <asm/pci_x86.h>
#include <asm/pgtable.h>
#include <asm/io_apic.h>
@@ -400,57 +400,13 @@ static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger,
return 0;
}
-static int mp_register_gsi(struct device *dev, u32 gsi, int trigger,
- int polarity)
-{
- int irq, node;
-
- if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
- return gsi;
-
- trigger = trigger == ACPI_EDGE_SENSITIVE ? 0 : 1;
- polarity = polarity == ACPI_ACTIVE_HIGH ? 0 : 1;
- node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
- if (mp_set_gsi_attr(gsi, trigger, polarity, node)) {
- pr_warn("Failed to set pin attr for GSI%d\n", gsi);
- return -1;
- }
-
- irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC);
- if (irq < 0)
- return irq;
-
- /* Don't set up the ACPI SCI because it's already set up */
- if (enable_update_mptable && acpi_gbl_FADT.sci_interrupt != gsi)
- mp_config_acpi_gsi(dev, gsi, trigger, polarity);
-
- return irq;
-}
-
-static void mp_unregister_gsi(u32 gsi)
-{
- int irq;
-
- if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
- return;
-
- irq = mp_map_gsi_to_irq(gsi, 0);
- if (irq > 0)
- mp_unmap_irq(irq);
-}
-
-static struct irq_domain_ops acpi_irqdomain_ops = {
- .map = mp_irqdomain_map,
- .unmap = mp_irqdomain_unmap,
-};
-
static int __init
acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
{
struct acpi_madt_io_apic *ioapic = NULL;
struct ioapic_domain_cfg cfg = {
.type = IOAPIC_DOMAIN_DYNAMIC,
- .ops = &acpi_irqdomain_ops,
+ .ops = &mp_ioapic_irqdomain_ops,
};
ioapic = (struct acpi_madt_io_apic *)header;
@@ -652,7 +608,7 @@ static int acpi_register_gsi_pic(struct device *dev, u32 gsi,
* Make sure all (legacy) PCI IRQs are set as level-triggered.
*/
if (trigger == ACPI_LEVEL_SENSITIVE)
- eisa_set_level_irq(gsi);
+ elcr_set_level_irq(gsi);
#endif
return gsi;
@@ -663,10 +619,21 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
int trigger, int polarity)
{
int irq = gsi;
-
#ifdef CONFIG_X86_IO_APIC
+ int node;
+ struct irq_alloc_info info;
+
+ node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
+ trigger = trigger == ACPI_EDGE_SENSITIVE ? 0 : 1;
+ polarity = polarity == ACPI_ACTIVE_HIGH ? 0 : 1;
+ ioapic_set_alloc_attr(&info, node, trigger, polarity);
+
mutex_lock(&acpi_ioapic_lock);
- irq = mp_register_gsi(dev, gsi, trigger, polarity);
+ irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC, &info);
+ /* Don't set up the ACPI SCI because it's already set up */
+ if (irq >= 0 && enable_update_mptable &&
+ acpi_gbl_FADT.sci_interrupt != gsi)
+ mp_config_acpi_gsi(dev, gsi, trigger, polarity);
mutex_unlock(&acpi_ioapic_lock);
#endif
@@ -676,8 +643,12 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
static void acpi_unregister_gsi_ioapic(u32 gsi)
{
#ifdef CONFIG_X86_IO_APIC
+ int irq;
+
mutex_lock(&acpi_ioapic_lock);
- mp_unregister_gsi(gsi);
+ irq = mp_map_gsi_to_irq(gsi, 0, NULL);
+ if (irq > 0)
+ mp_unmap_irq(irq);
mutex_unlock(&acpi_ioapic_lock);
#endif
}
@@ -786,7 +757,7 @@ int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
u64 addr;
struct ioapic_domain_cfg cfg = {
.type = IOAPIC_DOMAIN_DYNAMIC,
- .ops = &acpi_irqdomain_ops,
+ .ops = &mp_ioapic_irqdomain_ops,
};
ioapic_id = acpi_get_ioapic_id(handle, gsi_base, &addr);
diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S
index 665c6b7d2ea9..0c26b1b44e51 100644
--- a/arch/x86/kernel/acpi/wakeup_32.S
+++ b/arch/x86/kernel/acpi/wakeup_32.S
@@ -12,11 +12,13 @@ ENTRY(wakeup_pmode_return)
wakeup_pmode_return:
movw $__KERNEL_DS, %ax
movw %ax, %ss
- movw %ax, %ds
- movw %ax, %es
movw %ax, %fs
movw %ax, %gs
+ movw $__USER_DS, %ax
+ movw %ax, %ds
+ movw %ax, %es
+
# reload the gdt, as we need the full 32 bit address
lidt saved_idt
lldt saved_ldt
diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S
index ae693b51ed8e..8c35df468104 100644
--- a/arch/x86/kernel/acpi/wakeup_64.S
+++ b/arch/x86/kernel/acpi/wakeup_64.S
@@ -62,7 +62,7 @@ ENTRY(do_suspend_lowlevel)
pushfq
popq pt_regs_flags(%rax)
- movq $resume_point, saved_rip(%rip)
+ movq $.Lresume_point, saved_rip(%rip)
movq %rsp, saved_rsp
movq %rbp, saved_rbp
@@ -75,10 +75,10 @@ ENTRY(do_suspend_lowlevel)
xorl %eax, %eax
call x86_acpi_enter_sleep_state
/* in case something went wrong, restore the machine status and go on */
- jmp resume_point
+ jmp .Lresume_point
.align 4
-resume_point:
+.Lresume_point:
/* We don't restore %rax, it must be 0 anyway */
movq $saved_context, %rax
movq saved_context_cr4(%rax), %rbx
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index aef653193160..c42827eb86cf 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -21,6 +21,10 @@
#include <asm/io.h>
#include <asm/fixmap.h>
+int __read_mostly alternatives_patched;
+
+EXPORT_SYMBOL_GPL(alternatives_patched);
+
#define MAX_PATCH_LEN (255-1)
static int __initdata_or_module debug_alternative;
@@ -227,6 +231,15 @@ void __init arch_init_ideal_nops(void)
#endif
}
break;
+
+ case X86_VENDOR_AMD:
+ if (boot_cpu_data.x86 > 0xf) {
+ ideal_nops = p6_nops;
+ return;
+ }
+
+ /* fall through */
+
default:
#ifdef CONFIG_X86_64
ideal_nops = k8_nops;
@@ -627,6 +640,7 @@ void __init alternative_instructions(void)
apply_paravirt(__parainstructions, __parainstructions_end);
restart_nmi();
+ alternatives_patched = 1;
}
/**
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index 5caed1dd7ccf..29fa475ec518 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -89,9 +89,7 @@ int amd_cache_northbridges(void)
next_northbridge(link, amd_nb_link_ids);
}
- /* GART present only on Fam15h upto model 0fh */
- if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
- (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model < 0x10))
+ if (amd_gart_present())
amd_northbridges.flags |= AMD_NB_GART;
/*
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c
index 6a7c23ff21d3..ede92c3364d3 100644
--- a/arch/x86/kernel/apb_timer.c
+++ b/arch/x86/kernel/apb_timer.c
@@ -171,10 +171,6 @@ static int __init apbt_clockevent_register(void)
static void apbt_setup_irq(struct apbt_dev *adev)
{
- /* timer0 irq has been setup early */
- if (adev->irq == 0)
- return;
-
irq_modify_status(adev->irq, 0, IRQ_MOVE_PCNTXT);
irq_set_affinity(adev->irq, cpumask_of(adev->cpu));
}
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c
index 76164e173a24..6e85f713641d 100644
--- a/arch/x86/kernel/aperture_64.c
+++ b/arch/x86/kernel/aperture_64.c
@@ -262,6 +262,9 @@ void __init early_gart_iommu_check(void)
u64 aper_base = 0, last_aper_base = 0;
int aper_enabled = 0, last_aper_enabled = 0, last_valid = 0;
+ if (!amd_gart_present())
+ return;
+
if (!early_pci_allowed())
return;
@@ -355,6 +358,9 @@ int __init gart_iommu_hole_init(void)
int fix, slot, valid_agp = 0;
int i, node;
+ if (!amd_gart_present())
+ return -ENODEV;
+
if (gart_iommu_aperture_disabled || !fix_aperture ||
!early_pci_allowed())
return -ENODEV;
@@ -452,7 +458,7 @@ out:
force_iommu ||
valid_agp ||
fallback_aper_force) {
- pr_info("Your BIOS doesn't leave a aperture memory hole\n");
+ pr_info("Your BIOS doesn't leave an aperture memory hole\n");
pr_info("Please enable the IOMMU option in the BIOS setup\n");
pr_info("This costs you %dMB of RAM\n",
32 << fallback_aper_order);
diff --git a/arch/x86/kernel/apic/htirq.c b/arch/x86/kernel/apic/htirq.c
index 816f36e979ad..ae50d3454d78 100644
--- a/arch/x86/kernel/apic/htirq.c
+++ b/arch/x86/kernel/apic/htirq.c
@@ -3,6 +3,8 @@
*
* Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
* Moved from arch/x86/kernel/apic/io_apic.c.
+ * Jiang Liu <jiang.liu@linux.intel.com>
+ * Add support of hierarchical irqdomain
*
* 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
@@ -14,78 +16,112 @@
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/htirq.h>
+#include <asm/irqdomain.h>
#include <asm/hw_irq.h>
#include <asm/apic.h>
#include <asm/hypertransport.h>
+static struct irq_domain *htirq_domain;
+
/*
* Hypertransport interrupt support
*/
-static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
-{
- struct ht_irq_msg msg;
-
- fetch_ht_irq_msg(irq, &msg);
-
- msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
- msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
-
- msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
- msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest);
-
- write_ht_irq_msg(irq, &msg);
-}
-
static int
ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
{
- struct irq_cfg *cfg = irqd_cfg(data);
- unsigned int dest;
+ struct irq_data *parent = data->parent_data;
int ret;
- ret = apic_set_affinity(data, mask, &dest);
- if (ret)
- return ret;
-
- target_ht_irq(data->irq, dest, cfg->vector);
- return IRQ_SET_MASK_OK_NOCOPY;
+ ret = parent->chip->irq_set_affinity(parent, mask, force);
+ if (ret >= 0) {
+ struct ht_irq_msg msg;
+ struct irq_cfg *cfg = irqd_cfg(data);
+
+ fetch_ht_irq_msg(data->irq, &msg);
+ msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK |
+ HT_IRQ_LOW_DEST_ID_MASK);
+ msg.address_lo |= HT_IRQ_LOW_VECTOR(cfg->vector) |
+ HT_IRQ_LOW_DEST_ID(cfg->dest_apicid);
+ msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
+ msg.address_hi |= HT_IRQ_HIGH_DEST_ID(cfg->dest_apicid);
+ write_ht_irq_msg(data->irq, &msg);
+ }
+
+ return ret;
}
static struct irq_chip ht_irq_chip = {
.name = "PCI-HT",
.irq_mask = mask_ht_irq,
.irq_unmask = unmask_ht_irq,
- .irq_ack = apic_ack_edge,
+ .irq_ack = irq_chip_ack_parent,
.irq_set_affinity = ht_set_affinity,
- .irq_retrigger = apic_retrigger_irq,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
-int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
+static int htirq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
{
- struct irq_cfg *cfg;
- struct ht_irq_msg msg;
- unsigned dest;
- int err;
+ struct ht_irq_cfg *ht_cfg;
+ struct irq_alloc_info *info = arg;
+ struct pci_dev *dev;
+ irq_hw_number_t hwirq;
+ int ret;
- if (disable_apic)
- return -ENXIO;
+ if (nr_irqs > 1 || !info)
+ return -EINVAL;
- cfg = irq_cfg(irq);
- err = assign_irq_vector(irq, cfg, apic->target_cpus());
- if (err)
- return err;
+ dev = info->ht_dev;
+ hwirq = (info->ht_idx & 0xFF) |
+ PCI_DEVID(dev->bus->number, dev->devfn) << 8 |
+ (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 24;
+ if (irq_find_mapping(domain, hwirq) > 0)
+ return -EEXIST;
- err = apic->cpu_mask_to_apicid_and(cfg->domain,
- apic->target_cpus(), &dest);
- if (err)
- return err;
+ ht_cfg = kmalloc(sizeof(*ht_cfg), GFP_KERNEL);
+ if (!ht_cfg)
+ return -ENOMEM;
- msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
+ if (ret < 0) {
+ kfree(ht_cfg);
+ return ret;
+ }
+
+ /* Initialize msg to a value that will never match the first write. */
+ ht_cfg->msg.address_lo = 0xffffffff;
+ ht_cfg->msg.address_hi = 0xffffffff;
+ ht_cfg->dev = info->ht_dev;
+ ht_cfg->update = info->ht_update;
+ ht_cfg->pos = info->ht_pos;
+ ht_cfg->idx = 0x10 + (info->ht_idx * 2);
+ irq_domain_set_info(domain, virq, hwirq, &ht_irq_chip, ht_cfg,
+ handle_edge_irq, ht_cfg, "edge");
+
+ return 0;
+}
+
+static void htirq_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq);
+
+ BUG_ON(nr_irqs != 1);
+ kfree(irq_data->chip_data);
+ irq_domain_free_irqs_top(domain, virq, nr_irqs);
+}
+static void htirq_domain_activate(struct irq_domain *domain,
+ struct irq_data *irq_data)
+{
+ struct ht_irq_msg msg;
+ struct irq_cfg *cfg = irqd_cfg(irq_data);
+
+ msg.address_hi = HT_IRQ_HIGH_DEST_ID(cfg->dest_apicid);
msg.address_lo =
HT_IRQ_LOW_BASE |
- HT_IRQ_LOW_DEST_ID(dest) |
+ HT_IRQ_LOW_DEST_ID(cfg->dest_apicid) |
HT_IRQ_LOW_VECTOR(cfg->vector) |
((apic->irq_dest_mode == 0) ?
HT_IRQ_LOW_DM_PHYSICAL :
@@ -95,13 +131,56 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
HT_IRQ_LOW_MT_FIXED :
HT_IRQ_LOW_MT_ARBITRATED) |
HT_IRQ_LOW_IRQ_MASKED;
+ write_ht_irq_msg(irq_data->irq, &msg);
+}
- write_ht_irq_msg(irq, &msg);
+static void htirq_domain_deactivate(struct irq_domain *domain,
+ struct irq_data *irq_data)
+{
+ struct ht_irq_msg msg;
- irq_set_chip_and_handler_name(irq, &ht_irq_chip,
- handle_edge_irq, "edge");
+ memset(&msg, 0, sizeof(msg));
+ write_ht_irq_msg(irq_data->irq, &msg);
+}
- dev_dbg(&dev->dev, "irq %d for HT\n", irq);
+static const struct irq_domain_ops htirq_domain_ops = {
+ .alloc = htirq_domain_alloc,
+ .free = htirq_domain_free,
+ .activate = htirq_domain_activate,
+ .deactivate = htirq_domain_deactivate,
+};
- return 0;
+void arch_init_htirq_domain(struct irq_domain *parent)
+{
+ if (disable_apic)
+ return;
+
+ htirq_domain = irq_domain_add_tree(NULL, &htirq_domain_ops, NULL);
+ if (!htirq_domain)
+ pr_warn("failed to initialize irqdomain for HTIRQ.\n");
+ else
+ htirq_domain->parent = parent;
+}
+
+int arch_setup_ht_irq(int idx, int pos, struct pci_dev *dev,
+ ht_irq_update_t *update)
+{
+ struct irq_alloc_info info;
+
+ if (!htirq_domain)
+ return -ENOSYS;
+
+ init_irq_alloc_info(&info, NULL);
+ info.ht_idx = idx;
+ info.ht_pos = pos;
+ info.ht_dev = dev;
+ info.ht_update = update;
+
+ return irq_domain_alloc_irqs(htirq_domain, 1, dev_to_node(&dev->dev),
+ &info);
+}
+
+void arch_teardown_ht_irq(unsigned int irq)
+{
+ irq_domain_free_irqs(irq, 1);
}
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index f4dc2462a1ac..845dc0df2002 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -18,6 +18,16 @@
* and Rolf G. Tews
* for testing these extensively
* Paul Diefenbaugh : Added full ACPI support
+ *
+ * Historical information which is worth to be preserved:
+ *
+ * - SiS APIC rmw bug:
+ *
+ * We used to have a workaround for a bug in SiS chips which
+ * required to rewrite the index register for a read-modify-write
+ * operation as the chip lost the index information which was
+ * setup for the read already. We cache the data now, so that
+ * workaround has been removed.
*/
#include <linux/mm.h>
@@ -31,13 +41,13 @@
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/syscore_ops.h>
-#include <linux/irqdomain.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/jiffies.h> /* time_after() */
#include <linux/slab.h>
#include <linux/bootmem.h>
+#include <asm/irqdomain.h>
#include <asm/idle.h>
#include <asm/io.h>
#include <asm/smp.h>
@@ -63,27 +73,31 @@
#define for_each_ioapic_pin(idx, pin) \
for_each_ioapic((idx)) \
for_each_pin((idx), (pin))
-
#define for_each_irq_pin(entry, head) \
list_for_each_entry(entry, &head, list)
-/*
- * Is the SiS APIC rmw bug present ?
- * -1 = don't know, 0 = no, 1 = yes
- */
-int sis_apic_bug = -1;
-
static DEFINE_RAW_SPINLOCK(ioapic_lock);
static DEFINE_MUTEX(ioapic_mutex);
static unsigned int ioapic_dynirq_base;
static int ioapic_initialized;
-struct mp_pin_info {
+struct irq_pin_list {
+ struct list_head list;
+ int apic, pin;
+};
+
+struct mp_chip_data {
+ struct list_head irq_2_pin;
+ struct IO_APIC_route_entry entry;
int trigger;
int polarity;
- int node;
- int set;
u32 count;
+ bool isa_irq;
+};
+
+struct mp_ioapic_gsi {
+ u32 gsi_base;
+ u32 gsi_end;
};
static struct ioapic {
@@ -101,7 +115,6 @@ static struct ioapic {
struct mp_ioapic_gsi gsi_config;
struct ioapic_domain_cfg irqdomain_cfg;
struct irq_domain *irqdomain;
- struct mp_pin_info *pin_info;
struct resource *iomem_res;
} ioapics[MAX_IO_APICS];
@@ -117,7 +130,7 @@ unsigned int mpc_ioapic_addr(int ioapic_idx)
return ioapics[ioapic_idx].mp_config.apicaddr;
}
-struct mp_ioapic_gsi *mp_ioapic_gsi_routing(int ioapic_idx)
+static inline struct mp_ioapic_gsi *mp_ioapic_gsi_routing(int ioapic_idx)
{
return &ioapics[ioapic_idx].gsi_config;
}
@@ -129,11 +142,16 @@ static inline int mp_ioapic_pin_count(int ioapic)
return gsi_cfg->gsi_end - gsi_cfg->gsi_base + 1;
}
-u32 mp_pin_to_gsi(int ioapic, int pin)
+static inline u32 mp_pin_to_gsi(int ioapic, int pin)
{
return mp_ioapic_gsi_routing(ioapic)->gsi_base + pin;
}
+static inline bool mp_is_legacy_irq(int irq)
+{
+ return irq >= 0 && irq < nr_legacy_irqs();
+}
+
/*
* Initialize all legacy IRQs and all pins on the first IOAPIC
* if we have legacy interrupt controller. Kernel boot option "pirq="
@@ -144,12 +162,7 @@ static inline int mp_init_irq_at_boot(int ioapic, int irq)
if (!nr_legacy_irqs())
return 0;
- return ioapic == 0 || (irq >= 0 && irq < nr_legacy_irqs());
-}
-
-static inline struct mp_pin_info *mp_pin_info(int ioapic_idx, int pin)
-{
- return ioapics[ioapic_idx].pin_info + pin;
+ return ioapic == 0 || mp_is_legacy_irq(irq);
}
static inline struct irq_domain *mp_ioapic_irqdomain(int ioapic)
@@ -216,16 +229,6 @@ void mp_save_irq(struct mpc_intsrc *m)
panic("Max # of irq sources exceeded!!\n");
}
-struct irq_pin_list {
- struct list_head list;
- int apic, pin;
-};
-
-static struct irq_pin_list *alloc_irq_pin_list(int node)
-{
- return kzalloc_node(sizeof(struct irq_pin_list), GFP_KERNEL, node);
-}
-
static void alloc_ioapic_saved_registers(int idx)
{
size_t size;
@@ -247,8 +250,7 @@ static void free_ioapic_saved_registers(int idx)
int __init arch_early_ioapic_init(void)
{
- struct irq_cfg *cfg;
- int i, node = cpu_to_node(0);
+ int i;
if (!nr_legacy_irqs())
io_apic_irqs = ~0UL;
@@ -256,16 +258,6 @@ int __init arch_early_ioapic_init(void)
for_each_ioapic(i)
alloc_ioapic_saved_registers(i);
- /*
- * For legacy IRQ's, start with assigning irq0 to irq15 to
- * IRQ0_VECTOR to IRQ15_VECTOR for all cpu's.
- */
- for (i = 0; i < nr_legacy_irqs(); i++) {
- cfg = alloc_irq_and_cfg_at(i, node);
- cfg->vector = IRQ0_VECTOR + i;
- cpumask_setall(cfg->domain);
- }
-
return 0;
}
@@ -283,7 +275,7 @@ static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
+ (mpc_ioapic_addr(idx) & ~PAGE_MASK);
}
-void io_apic_eoi(unsigned int apic, unsigned int vector)
+static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
{
struct io_apic __iomem *io_apic = io_apic_base(apic);
writel(vector, &io_apic->eoi);
@@ -296,7 +288,8 @@ unsigned int native_io_apic_read(unsigned int apic, unsigned int reg)
return readl(&io_apic->data);
}
-void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
+static void io_apic_write(unsigned int apic, unsigned int reg,
+ unsigned int value)
{
struct io_apic __iomem *io_apic = io_apic_base(apic);
@@ -304,21 +297,6 @@ void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int valu
writel(value, &io_apic->data);
}
-/*
- * Re-write a value: to be used for read-modify-write
- * cycles where the read already set up the index register.
- *
- * Older SiS APIC requires we rewrite the index register
- */
-void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
-{
- struct io_apic __iomem *io_apic = io_apic_base(apic);
-
- if (sis_apic_bug)
- writel(reg, &io_apic->index);
- writel(value, &io_apic->data);
-}
-
union entry_union {
struct { u32 w1, w2; };
struct IO_APIC_route_entry entry;
@@ -378,7 +356,7 @@ static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
static void ioapic_mask_entry(int apic, int pin)
{
unsigned long flags;
- union entry_union eu = { .entry.mask = 1 };
+ union entry_union eu = { .entry.mask = IOAPIC_MASKED };
raw_spin_lock_irqsave(&ioapic_lock, flags);
io_apic_write(apic, 0x10 + 2*pin, eu.w1);
@@ -391,16 +369,17 @@ static void ioapic_mask_entry(int apic, int pin)
* shared ISA-space IRQs, so we have to support them. We are super
* fast in the common case, and fast for shared ISA-space IRQs.
*/
-static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
+static int __add_pin_to_irq_node(struct mp_chip_data *data,
+ int node, int apic, int pin)
{
struct irq_pin_list *entry;
/* don't allow duplicates */
- for_each_irq_pin(entry, cfg->irq_2_pin)
+ for_each_irq_pin(entry, data->irq_2_pin)
if (entry->apic == apic && entry->pin == pin)
return 0;
- entry = alloc_irq_pin_list(node);
+ entry = kzalloc_node(sizeof(struct irq_pin_list), GFP_ATOMIC, node);
if (!entry) {
pr_err("can not alloc irq_pin_list (%d,%d,%d)\n",
node, apic, pin);
@@ -408,16 +387,16 @@ static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pi
}
entry->apic = apic;
entry->pin = pin;
+ list_add_tail(&entry->list, &data->irq_2_pin);
- list_add_tail(&entry->list, &cfg->irq_2_pin);
return 0;
}
-static void __remove_pin_from_irq(struct irq_cfg *cfg, int apic, int pin)
+static void __remove_pin_from_irq(struct mp_chip_data *data, int apic, int pin)
{
struct irq_pin_list *tmp, *entry;
- list_for_each_entry_safe(entry, tmp, &cfg->irq_2_pin, list)
+ list_for_each_entry_safe(entry, tmp, &data->irq_2_pin, list)
if (entry->apic == apic && entry->pin == pin) {
list_del(&entry->list);
kfree(entry);
@@ -425,22 +404,23 @@ static void __remove_pin_from_irq(struct irq_cfg *cfg, int apic, int pin)
}
}
-static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
+static void add_pin_to_irq_node(struct mp_chip_data *data,
+ int node, int apic, int pin)
{
- if (__add_pin_to_irq_node(cfg, node, apic, pin))
+ if (__add_pin_to_irq_node(data, node, apic, pin))
panic("IO-APIC: failed to add irq-pin. Can not proceed\n");
}
/*
* Reroute an IRQ to a different pin.
*/
-static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node,
+static void __init replace_pin_at_irq_node(struct mp_chip_data *data, int node,
int oldapic, int oldpin,
int newapic, int newpin)
{
struct irq_pin_list *entry;
- for_each_irq_pin(entry, cfg->irq_2_pin) {
+ for_each_irq_pin(entry, data->irq_2_pin) {
if (entry->apic == oldapic && entry->pin == oldpin) {
entry->apic = newapic;
entry->pin = newpin;
@@ -450,32 +430,26 @@ static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node,
}
/* old apic/pin didn't exist, so just add new ones */
- add_pin_to_irq_node(cfg, node, newapic, newpin);
-}
-
-static void __io_apic_modify_irq(struct irq_pin_list *entry,
- int mask_and, int mask_or,
- void (*final)(struct irq_pin_list *entry))
-{
- unsigned int reg, pin;
-
- pin = entry->pin;
- reg = io_apic_read(entry->apic, 0x10 + pin * 2);
- reg &= mask_and;
- reg |= mask_or;
- io_apic_modify(entry->apic, 0x10 + pin * 2, reg);
- if (final)
- final(entry);
+ add_pin_to_irq_node(data, node, newapic, newpin);
}
-static void io_apic_modify_irq(struct irq_cfg *cfg,
+static void io_apic_modify_irq(struct mp_chip_data *data,
int mask_and, int mask_or,
void (*final)(struct irq_pin_list *entry))
{
+ union entry_union eu;
struct irq_pin_list *entry;
- for_each_irq_pin(entry, cfg->irq_2_pin)
- __io_apic_modify_irq(entry, mask_and, mask_or, final);
+ eu.entry = data->entry;
+ eu.w1 &= mask_and;
+ eu.w1 |= mask_or;
+ data->entry = eu.entry;
+
+ for_each_irq_pin(entry, data->irq_2_pin) {
+ io_apic_write(entry->apic, 0x10 + 2 * entry->pin, eu.w1);
+ if (final)
+ final(entry);
+ }
}
static void io_apic_sync(struct irq_pin_list *entry)
@@ -490,39 +464,31 @@ static void io_apic_sync(struct irq_pin_list *entry)
readl(&io_apic->data);
}
-static void mask_ioapic(struct irq_cfg *cfg)
+static void mask_ioapic_irq(struct irq_data *irq_data)
{
+ struct mp_chip_data *data = irq_data->chip_data;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags);
- io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
+ io_apic_modify_irq(data, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
}
-static void mask_ioapic_irq(struct irq_data *data)
+static void __unmask_ioapic(struct mp_chip_data *data)
{
- mask_ioapic(irqd_cfg(data));
+ io_apic_modify_irq(data, ~IO_APIC_REDIR_MASKED, 0, NULL);
}
-static void __unmask_ioapic(struct irq_cfg *cfg)
-{
- io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED, 0, NULL);
-}
-
-static void unmask_ioapic(struct irq_cfg *cfg)
+static void unmask_ioapic_irq(struct irq_data *irq_data)
{
+ struct mp_chip_data *data = irq_data->chip_data;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags);
- __unmask_ioapic(cfg);
+ __unmask_ioapic(data);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
}
-static void unmask_ioapic_irq(struct irq_data *data)
-{
- unmask_ioapic(irqd_cfg(data));
-}
-
/*
* IO-APIC versions below 0x20 don't support EOI register.
* For the record, here is the information about various versions:
@@ -539,7 +505,7 @@ static void unmask_ioapic_irq(struct irq_data *data)
* Otherwise, we simulate the EOI message manually by changing the trigger
* mode to edge and then back to level, with RTE being masked during this.
*/
-void native_eoi_ioapic_pin(int apic, int pin, int vector)
+static void __eoi_ioapic_pin(int apic, int pin, int vector)
{
if (mpc_ioapic_ver(apic) >= 0x20) {
io_apic_eoi(apic, vector);
@@ -551,7 +517,7 @@ void native_eoi_ioapic_pin(int apic, int pin, int vector)
/*
* Mask the entry and change the trigger mode to edge.
*/
- entry1.mask = 1;
+ entry1.mask = IOAPIC_MASKED;
entry1.trigger = IOAPIC_EDGE;
__ioapic_write_entry(apic, pin, entry1);
@@ -563,15 +529,14 @@ void native_eoi_ioapic_pin(int apic, int pin, int vector)
}
}
-void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
+void eoi_ioapic_pin(int vector, struct mp_chip_data *data)
{
- struct irq_pin_list *entry;
unsigned long flags;
+ struct irq_pin_list *entry;
raw_spin_lock_irqsave(&ioapic_lock, flags);
- for_each_irq_pin(entry, cfg->irq_2_pin)
- x86_io_apic_ops.eoi_ioapic_pin(entry->apic, entry->pin,
- cfg->vector);
+ for_each_irq_pin(entry, data->irq_2_pin)
+ __eoi_ioapic_pin(entry->apic, entry->pin, vector);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
}
@@ -588,8 +553,8 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
* Make sure the entry is masked and re-read the contents to check
* if it is a level triggered pin and if the remote-IRR is set.
*/
- if (!entry.mask) {
- entry.mask = 1;
+ if (entry.mask == IOAPIC_UNMASKED) {
+ entry.mask = IOAPIC_MASKED;
ioapic_write_entry(apic, pin, entry);
entry = ioapic_read_entry(apic, pin);
}
@@ -602,13 +567,12 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
* doesn't clear the remote-IRR if the trigger mode is not
* set to level.
*/
- if (!entry.trigger) {
+ if (entry.trigger == IOAPIC_EDGE) {
entry.trigger = IOAPIC_LEVEL;
ioapic_write_entry(apic, pin, entry);
}
-
raw_spin_lock_irqsave(&ioapic_lock, flags);
- x86_io_apic_ops.eoi_ioapic_pin(apic, pin, entry.vector);
+ __eoi_ioapic_pin(apic, pin, entry.vector);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
}
@@ -706,8 +670,8 @@ void mask_ioapic_entries(void)
struct IO_APIC_route_entry entry;
entry = ioapics[apic].saved_registers[pin];
- if (!entry.mask) {
- entry.mask = 1;
+ if (entry.mask == IOAPIC_UNMASKED) {
+ entry.mask = IOAPIC_MASKED;
ioapic_write_entry(apic, pin, entry);
}
}
@@ -809,11 +773,11 @@ static int EISA_ELCR(unsigned int irq)
#endif
-/* ISA interrupts are always polarity zero edge triggered,
+/* ISA interrupts are always active high edge triggered,
* when listed as conforming in the MP table. */
-#define default_ISA_trigger(idx) (0)
-#define default_ISA_polarity(idx) (0)
+#define default_ISA_trigger(idx) (IOAPIC_EDGE)
+#define default_ISA_polarity(idx) (IOAPIC_POL_HIGH)
/* EISA interrupts are always polarity zero and can be edge or level
* trigger depending on the ELCR value. If an interrupt is listed as
@@ -823,53 +787,55 @@ static int EISA_ELCR(unsigned int irq)
#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].srcbusirq))
#define default_EISA_polarity(idx) default_ISA_polarity(idx)
-/* PCI interrupts are always polarity one level triggered,
+/* PCI interrupts are always active low level triggered,
* when listed as conforming in the MP table. */
-#define default_PCI_trigger(idx) (1)
-#define default_PCI_polarity(idx) (1)
+#define default_PCI_trigger(idx) (IOAPIC_LEVEL)
+#define default_PCI_polarity(idx) (IOAPIC_POL_LOW)
static int irq_polarity(int idx)
{
int bus = mp_irqs[idx].srcbus;
- int polarity;
/*
* Determine IRQ line polarity (high active or low active):
*/
- switch (mp_irqs[idx].irqflag & 3)
- {
- case 0: /* conforms, ie. bus-type dependent polarity */
- if (test_bit(bus, mp_bus_not_pci))
- polarity = default_ISA_polarity(idx);
- else
- polarity = default_PCI_polarity(idx);
- break;
- case 1: /* high active */
- {
- polarity = 0;
- break;
- }
- case 2: /* reserved */
- {
- pr_warn("broken BIOS!!\n");
- polarity = 1;
- break;
- }
- case 3: /* low active */
- {
- polarity = 1;
- break;
- }
- default: /* invalid */
- {
- pr_warn("broken BIOS!!\n");
- polarity = 1;
- break;
- }
+ switch (mp_irqs[idx].irqflag & 0x03) {
+ case 0:
+ /* conforms to spec, ie. bus-type dependent polarity */
+ if (test_bit(bus, mp_bus_not_pci))
+ return default_ISA_polarity(idx);
+ else
+ return default_PCI_polarity(idx);
+ case 1:
+ return IOAPIC_POL_HIGH;
+ case 2:
+ pr_warn("IOAPIC: Invalid polarity: 2, defaulting to low\n");
+ case 3:
+ default: /* Pointless default required due to do gcc stupidity */
+ return IOAPIC_POL_LOW;
+ }
+}
+
+#ifdef CONFIG_EISA
+static int eisa_irq_trigger(int idx, int bus, int trigger)
+{
+ switch (mp_bus_id_to_type[bus]) {
+ case MP_BUS_PCI:
+ case MP_BUS_ISA:
+ return trigger;
+ case MP_BUS_EISA:
+ return default_EISA_trigger(idx);
}
- return polarity;
+ pr_warn("IOAPIC: Invalid srcbus: %d defaulting to level\n", bus);
+ return IOAPIC_LEVEL;
}
+#else
+static inline int eisa_irq_trigger(int idx, int bus, int trigger)
+{
+ return trigger;
+}
+#endif
static int irq_trigger(int idx)
{
@@ -879,153 +845,227 @@ static int irq_trigger(int idx)
/*
* Determine IRQ trigger mode (edge or level sensitive):
*/
- switch ((mp_irqs[idx].irqflag>>2) & 3)
- {
- case 0: /* conforms, ie. bus-type dependent */
- if (test_bit(bus, mp_bus_not_pci))
- trigger = default_ISA_trigger(idx);
- else
- trigger = default_PCI_trigger(idx);
-#ifdef CONFIG_EISA
- switch (mp_bus_id_to_type[bus]) {
- case MP_BUS_ISA: /* ISA pin */
- {
- /* set before the switch */
- break;
- }
- case MP_BUS_EISA: /* EISA pin */
- {
- trigger = default_EISA_trigger(idx);
- break;
- }
- case MP_BUS_PCI: /* PCI pin */
- {
- /* set before the switch */
- break;
- }
- default:
- {
- pr_warn("broken BIOS!!\n");
- trigger = 1;
- break;
- }
- }
+ switch ((mp_irqs[idx].irqflag >> 2) & 0x03) {
+ case 0:
+ /* conforms to spec, ie. bus-type dependent trigger mode */
+ if (test_bit(bus, mp_bus_not_pci))
+ trigger = default_ISA_trigger(idx);
+ else
+ trigger = default_PCI_trigger(idx);
+ /* Take EISA into account */
+ return eisa_irq_trigger(idx, bus, trigger);
+ case 1:
+ return IOAPIC_EDGE;
+ case 2:
+ pr_warn("IOAPIC: Invalid trigger mode 2 defaulting to level\n");
+ case 3:
+ default: /* Pointless default required due to do gcc stupidity */
+ return IOAPIC_LEVEL;
+ }
+}
+
+void ioapic_set_alloc_attr(struct irq_alloc_info *info, int node,
+ int trigger, int polarity)
+{
+ init_irq_alloc_info(info, NULL);
+ info->type = X86_IRQ_ALLOC_TYPE_IOAPIC;
+ info->ioapic_node = node;
+ info->ioapic_trigger = trigger;
+ info->ioapic_polarity = polarity;
+ info->ioapic_valid = 1;
+}
+
+#ifndef CONFIG_ACPI
+int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);
#endif
- break;
- case 1: /* edge */
- {
- trigger = 0;
- break;
- }
- case 2: /* reserved */
- {
- pr_warn("broken BIOS!!\n");
- trigger = 1;
- break;
- }
- case 3: /* level */
- {
- trigger = 1;
- break;
- }
- default: /* invalid */
- {
- pr_warn("broken BIOS!!\n");
- trigger = 0;
- break;
+
+static void ioapic_copy_alloc_attr(struct irq_alloc_info *dst,
+ struct irq_alloc_info *src,
+ u32 gsi, int ioapic_idx, int pin)
+{
+ int trigger, polarity;
+
+ copy_irq_alloc_info(dst, src);
+ dst->type = X86_IRQ_ALLOC_TYPE_IOAPIC;
+ dst->ioapic_id = mpc_ioapic_id(ioapic_idx);
+ dst->ioapic_pin = pin;
+ dst->ioapic_valid = 1;
+ if (src && src->ioapic_valid) {
+ dst->ioapic_node = src->ioapic_node;
+ dst->ioapic_trigger = src->ioapic_trigger;
+ dst->ioapic_polarity = src->ioapic_polarity;
+ } else {
+ dst->ioapic_node = NUMA_NO_NODE;
+ if (acpi_get_override_irq(gsi, &trigger, &polarity) >= 0) {
+ dst->ioapic_trigger = trigger;
+ dst->ioapic_polarity = polarity;
+ } else {
+ /*
+ * PCI interrupts are always active low level
+ * triggered.
+ */
+ dst->ioapic_trigger = IOAPIC_LEVEL;
+ dst->ioapic_polarity = IOAPIC_POL_LOW;
}
}
- return trigger;
}
-static int alloc_irq_from_domain(struct irq_domain *domain, u32 gsi, int pin)
+static int ioapic_alloc_attr_node(struct irq_alloc_info *info)
+{
+ return (info && info->ioapic_valid) ? info->ioapic_node : NUMA_NO_NODE;
+}
+
+static void mp_register_handler(unsigned int irq, unsigned long trigger)
+{
+ irq_flow_handler_t hdl;
+ bool fasteoi;
+
+ if (trigger) {
+ irq_set_status_flags(irq, IRQ_LEVEL);
+ fasteoi = true;
+ } else {
+ irq_clear_status_flags(irq, IRQ_LEVEL);
+ fasteoi = false;
+ }
+
+ hdl = fasteoi ? handle_fasteoi_irq : handle_edge_irq;
+ __irq_set_handler(irq, hdl, 0, fasteoi ? "fasteoi" : "edge");
+}
+
+static bool mp_check_pin_attr(int irq, struct irq_alloc_info *info)
{
+ struct mp_chip_data *data = irq_get_chip_data(irq);
+
+ /*
+ * setup_IO_APIC_irqs() programs all legacy IRQs with default trigger
+ * and polarity attirbutes. So allow the first user to reprogram the
+ * pin with real trigger and polarity attributes.
+ */
+ if (irq < nr_legacy_irqs() && data->count == 1) {
+ if (info->ioapic_trigger != data->trigger)
+ mp_register_handler(irq, data->trigger);
+ data->entry.trigger = data->trigger = info->ioapic_trigger;
+ data->entry.polarity = data->polarity = info->ioapic_polarity;
+ }
+
+ return data->trigger == info->ioapic_trigger &&
+ data->polarity == info->ioapic_polarity;
+}
+
+static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi,
+ struct irq_alloc_info *info)
+{
+ bool legacy = false;
int irq = -1;
- int ioapic = (int)(long)domain->host_data;
int type = ioapics[ioapic].irqdomain_cfg.type;
switch (type) {
case IOAPIC_DOMAIN_LEGACY:
/*
- * Dynamically allocate IRQ number for non-ISA IRQs in the first 16
- * GSIs on some weird platforms.
+ * Dynamically allocate IRQ number for non-ISA IRQs in the first
+ * 16 GSIs on some weird platforms.
*/
- if (gsi < nr_legacy_irqs())
- irq = irq_create_mapping(domain, pin);
- else if (irq_create_strict_mappings(domain, gsi, pin, 1) == 0)
+ if (!ioapic_initialized || gsi >= nr_legacy_irqs())
irq = gsi;
+ legacy = mp_is_legacy_irq(irq);
break;
case IOAPIC_DOMAIN_STRICT:
- if (irq_create_strict_mappings(domain, gsi, pin, 1) == 0)
- irq = gsi;
+ irq = gsi;
break;
case IOAPIC_DOMAIN_DYNAMIC:
- irq = irq_create_mapping(domain, pin);
break;
default:
WARN(1, "ioapic: unknown irqdomain type %d\n", type);
- break;
+ return -1;
+ }
+
+ return __irq_domain_alloc_irqs(domain, irq, 1,
+ ioapic_alloc_attr_node(info),
+ info, legacy);
+}
+
+/*
+ * Need special handling for ISA IRQs because there may be multiple IOAPIC pins
+ * sharing the same ISA IRQ number and irqdomain only supports 1:1 mapping
+ * between IOAPIC pin and IRQ number. A typical IOAPIC has 24 pins, pin 0-15 are
+ * used for legacy IRQs and pin 16-23 are used for PCI IRQs (PIRQ A-H).
+ * When ACPI is disabled, only legacy IRQ numbers (IRQ0-15) are available, and
+ * some BIOSes may use MP Interrupt Source records to override IRQ numbers for
+ * PIRQs instead of reprogramming the interrupt routing logic. Thus there may be
+ * multiple pins sharing the same legacy IRQ number when ACPI is disabled.
+ */
+static int alloc_isa_irq_from_domain(struct irq_domain *domain,
+ int irq, int ioapic, int pin,
+ struct irq_alloc_info *info)
+{
+ struct mp_chip_data *data;
+ struct irq_data *irq_data = irq_get_irq_data(irq);
+ int node = ioapic_alloc_attr_node(info);
+
+ /*
+ * Legacy ISA IRQ has already been allocated, just add pin to
+ * the pin list assoicated with this IRQ and program the IOAPIC
+ * entry. The IOAPIC entry
+ */
+ if (irq_data && irq_data->parent_data) {
+ if (!mp_check_pin_attr(irq, info))
+ return -EBUSY;
+ if (__add_pin_to_irq_node(irq_data->chip_data, node, ioapic,
+ info->ioapic_pin))
+ return -ENOMEM;
+ } else {
+ irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true);
+ if (irq >= 0) {
+ irq_data = irq_domain_get_irq_data(domain, irq);
+ data = irq_data->chip_data;
+ data->isa_irq = true;
+ }
}
- return irq > 0 ? irq : -1;
+ return irq;
}
static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin,
- unsigned int flags)
+ unsigned int flags, struct irq_alloc_info *info)
{
int irq;
+ bool legacy = false;
+ struct irq_alloc_info tmp;
+ struct mp_chip_data *data;
struct irq_domain *domain = mp_ioapic_irqdomain(ioapic);
- struct mp_pin_info *info = mp_pin_info(ioapic, pin);
if (!domain)
- return -1;
+ return -ENOSYS;
- mutex_lock(&ioapic_mutex);
-
- /*
- * Don't use irqdomain to manage ISA IRQs because there may be
- * multiple IOAPIC pins sharing the same ISA IRQ number and
- * irqdomain only supports 1:1 mapping between IOAPIC pin and
- * IRQ number. A typical IOAPIC has 24 pins, pin 0-15 are used
- * for legacy IRQs and pin 16-23 are used for PCI IRQs (PIRQ A-H).
- * When ACPI is disabled, only legacy IRQ numbers (IRQ0-15) are
- * available, and some BIOSes may use MP Interrupt Source records
- * to override IRQ numbers for PIRQs instead of reprogramming
- * the interrupt routing logic. Thus there may be multiple pins
- * sharing the same legacy IRQ number when ACPI is disabled.
- */
if (idx >= 0 && test_bit(mp_irqs[idx].srcbus, mp_bus_not_pci)) {
irq = mp_irqs[idx].srcbusirq;
- if (flags & IOAPIC_MAP_ALLOC) {
- if (info->count == 0 &&
- mp_irqdomain_map(domain, irq, pin) != 0)
- irq = -1;
+ legacy = mp_is_legacy_irq(irq);
+ }
- /* special handling for timer IRQ0 */
+ mutex_lock(&ioapic_mutex);
+ if (!(flags & IOAPIC_MAP_ALLOC)) {
+ if (!legacy) {
+ irq = irq_find_mapping(domain, pin);
if (irq == 0)
- info->count++;
+ irq = -ENOENT;
}
} else {
- irq = irq_find_mapping(domain, pin);
- if (irq <= 0 && (flags & IOAPIC_MAP_ALLOC))
- irq = alloc_irq_from_domain(domain, gsi, pin);
- }
-
- if (flags & IOAPIC_MAP_ALLOC) {
- /* special handling for legacy IRQs */
- if (irq < nr_legacy_irqs() && info->count == 1 &&
- mp_irqdomain_map(domain, irq, pin) != 0)
- irq = -1;
-
- if (irq > 0)
- info->count++;
- else if (info->count == 0)
- info->set = 0;
+ ioapic_copy_alloc_attr(&tmp, info, gsi, ioapic, pin);
+ if (legacy)
+ irq = alloc_isa_irq_from_domain(domain, irq,
+ ioapic, pin, &tmp);
+ else if ((irq = irq_find_mapping(domain, pin)) == 0)
+ irq = alloc_irq_from_domain(domain, ioapic, gsi, &tmp);
+ else if (!mp_check_pin_attr(irq, &tmp))
+ irq = -EBUSY;
+ if (irq >= 0) {
+ data = irq_get_chip_data(irq);
+ data->count++;
+ }
}
-
mutex_unlock(&ioapic_mutex);
- return irq > 0 ? irq : -1;
+ return irq;
}
static int pin_2_irq(int idx, int ioapic, int pin, unsigned int flags)
@@ -1058,10 +1098,10 @@ static int pin_2_irq(int idx, int ioapic, int pin, unsigned int flags)
}
#endif
- return mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags);
+ return mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags, NULL);
}
-int mp_map_gsi_to_irq(u32 gsi, unsigned int flags)
+int mp_map_gsi_to_irq(u32 gsi, unsigned int flags, struct irq_alloc_info *info)
{
int ioapic, pin, idx;
@@ -1074,31 +1114,24 @@ int mp_map_gsi_to_irq(u32 gsi, unsigned int flags)
if ((flags & IOAPIC_MAP_CHECK) && idx < 0)
return -1;
- return mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags);
+ return mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags, info);
}
void mp_unmap_irq(int irq)
{
- struct irq_data *data = irq_get_irq_data(irq);
- struct mp_pin_info *info;
- int ioapic, pin;
+ struct irq_data *irq_data = irq_get_irq_data(irq);
+ struct mp_chip_data *data;
- if (!data || !data->domain)
+ if (!irq_data || !irq_data->domain)
return;
- ioapic = (int)(long)data->domain->host_data;
- pin = (int)data->hwirq;
- info = mp_pin_info(ioapic, pin);
+ data = irq_data->chip_data;
+ if (!data || data->isa_irq)
+ return;
mutex_lock(&ioapic_mutex);
- if (--info->count == 0) {
- info->set = 0;
- if (irq < nr_legacy_irqs() &&
- ioapics[ioapic].irqdomain_cfg.type == IOAPIC_DOMAIN_LEGACY)
- mp_irqdomain_unmap(data->domain, irq);
- else
- irq_dispose_mapping(irq);
- }
+ if (--data->count == 0)
+ irq_domain_free_irqs(irq, 1);
mutex_unlock(&ioapic_mutex);
}
@@ -1165,7 +1198,7 @@ out:
}
EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
-static struct irq_chip ioapic_chip;
+static struct irq_chip ioapic_chip, ioapic_ir_chip;
#ifdef CONFIG_X86_32
static inline int IO_APIC_irq_trigger(int irq)
@@ -1189,96 +1222,6 @@ static inline int IO_APIC_irq_trigger(int irq)
}
#endif
-static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg,
- unsigned long trigger)
-{
- struct irq_chip *chip = &ioapic_chip;
- irq_flow_handler_t hdl;
- bool fasteoi;
-
- if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
- trigger == IOAPIC_LEVEL) {
- irq_set_status_flags(irq, IRQ_LEVEL);
- fasteoi = true;
- } else {
- irq_clear_status_flags(irq, IRQ_LEVEL);
- fasteoi = false;
- }
-
- if (setup_remapped_irq(irq, cfg, chip))
- fasteoi = trigger != 0;
-
- hdl = fasteoi ? handle_fasteoi_irq : handle_edge_irq;
- irq_set_chip_and_handler_name(irq, chip, hdl,
- fasteoi ? "fasteoi" : "edge");
-}
-
-int native_setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
- unsigned int destination, int vector,
- struct io_apic_irq_attr *attr)
-{
- memset(entry, 0, sizeof(*entry));
-
- entry->delivery_mode = apic->irq_delivery_mode;
- entry->dest_mode = apic->irq_dest_mode;
- entry->dest = destination;
- entry->vector = vector;
- entry->mask = 0; /* enable IRQ */
- entry->trigger = attr->trigger;
- entry->polarity = attr->polarity;
-
- /*
- * Mask level triggered irqs.
- * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
- */
- if (attr->trigger)
- entry->mask = 1;
-
- return 0;
-}
-
-static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
- struct io_apic_irq_attr *attr)
-{
- struct IO_APIC_route_entry entry;
- unsigned int dest;
-
- if (!IO_APIC_IRQ(irq))
- return;
-
- if (assign_irq_vector(irq, cfg, apic->target_cpus()))
- return;
-
- if (apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus(),
- &dest)) {
- pr_warn("Failed to obtain apicid for ioapic %d, pin %d\n",
- mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
- clear_irq_vector(irq, cfg);
-
- return;
- }
-
- apic_printk(APIC_VERBOSE,KERN_DEBUG
- "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> "
- "IRQ %d Mode:%i Active:%i Dest:%d)\n",
- attr->ioapic, mpc_ioapic_id(attr->ioapic), attr->ioapic_pin,
- cfg->vector, irq, attr->trigger, attr->polarity, dest);
-
- if (x86_io_apic_ops.setup_entry(irq, &entry, dest, cfg->vector, attr)) {
- pr_warn("Failed to setup ioapic entry for ioapic %d, pin %d\n",
- mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
- clear_irq_vector(irq, cfg);
-
- return;
- }
-
- ioapic_register_intr(irq, cfg, attr->trigger);
- if (irq < nr_legacy_irqs())
- legacy_pic->mask(irq);
-
- ioapic_write_entry(attr->ioapic, attr->ioapic_pin, entry);
-}
-
static void __init setup_IO_APIC_irqs(void)
{
unsigned int ioapic, pin;
@@ -1298,106 +1241,41 @@ static void __init setup_IO_APIC_irqs(void)
}
}
-/*
- * Set up the timer pin, possibly with the 8259A-master behind.
- */
-static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
- unsigned int pin, int vector)
-{
- struct IO_APIC_route_entry entry;
- unsigned int dest;
-
- memset(&entry, 0, sizeof(entry));
-
- /*
- * We use logical delivery to get the timer IRQ
- * to the first CPU.
- */
- if (unlikely(apic->cpu_mask_to_apicid_and(apic->target_cpus(),
- apic->target_cpus(), &dest)))
- dest = BAD_APICID;
-
- entry.dest_mode = apic->irq_dest_mode;
- entry.mask = 0; /* don't mask IRQ for edge */
- entry.dest = dest;
- entry.delivery_mode = apic->irq_delivery_mode;
- entry.polarity = 0;
- entry.trigger = 0;
- entry.vector = vector;
-
- /*
- * The timer IRQ doesn't have to know that behind the
- * scene we may have a 8259A-master in AEOI mode ...
- */
- irq_set_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq,
- "edge");
-
- /*
- * Add it to the IO-APIC irq-routing table:
- */
- ioapic_write_entry(ioapic_idx, pin, entry);
-}
-
-void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries)
+void ioapic_zap_locks(void)
{
- int i;
-
- pr_debug(" NR Dst Mask Trig IRR Pol Stat Dmod Deli Vect:\n");
-
- for (i = 0; i <= nr_entries; i++) {
- struct IO_APIC_route_entry entry;
-
- entry = ioapic_read_entry(apic, i);
-
- pr_debug(" %02x %02X ", i, entry.dest);
- pr_cont("%1d %1d %1d %1d %1d "
- "%1d %1d %02X\n",
- entry.mask,
- entry.trigger,
- entry.irr,
- entry.polarity,
- entry.delivery_status,
- entry.dest_mode,
- entry.delivery_mode,
- entry.vector);
- }
+ raw_spin_lock_init(&ioapic_lock);
}
-void intel_ir_io_apic_print_entries(unsigned int apic,
- unsigned int nr_entries)
+static void io_apic_print_entries(unsigned int apic, unsigned int nr_entries)
{
int i;
+ char buf[256];
+ struct IO_APIC_route_entry entry;
+ struct IR_IO_APIC_route_entry *ir_entry = (void *)&entry;
- pr_debug(" NR Indx Fmt Mask Trig IRR Pol Stat Indx2 Zero Vect:\n");
-
+ printk(KERN_DEBUG "IOAPIC %d:\n", apic);
for (i = 0; i <= nr_entries; i++) {
- struct IR_IO_APIC_route_entry *ir_entry;
- struct IO_APIC_route_entry entry;
-
entry = ioapic_read_entry(apic, i);
-
- ir_entry = (struct IR_IO_APIC_route_entry *)&entry;
-
- pr_debug(" %02x %04X ", i, ir_entry->index);
- pr_cont("%1d %1d %1d %1d %1d "
- "%1d %1d %X %02X\n",
- ir_entry->format,
- ir_entry->mask,
- ir_entry->trigger,
- ir_entry->irr,
- ir_entry->polarity,
- ir_entry->delivery_status,
- ir_entry->index2,
- ir_entry->zero,
- ir_entry->vector);
+ snprintf(buf, sizeof(buf),
+ " pin%02x, %s, %s, %s, V(%02X), IRR(%1d), S(%1d)",
+ i,
+ entry.mask == IOAPIC_MASKED ? "disabled" : "enabled ",
+ entry.trigger == IOAPIC_LEVEL ? "level" : "edge ",
+ entry.polarity == IOAPIC_POL_LOW ? "low " : "high",
+ entry.vector, entry.irr, entry.delivery_status);
+ if (ir_entry->format)
+ printk(KERN_DEBUG "%s, remapped, I(%04X), Z(%X)\n",
+ buf, (ir_entry->index << 15) | ir_entry->index,
+ ir_entry->zero);
+ else
+ printk(KERN_DEBUG "%s, %s, D(%02X), M(%1d)\n",
+ buf,
+ entry.dest_mode == IOAPIC_DEST_MODE_LOGICAL ?
+ "logical " : "physical",
+ entry.dest, entry.delivery_mode);
}
}
-void ioapic_zap_locks(void)
-{
- raw_spin_lock_init(&ioapic_lock);
-}
-
static void __init print_IO_APIC(int ioapic_idx)
{
union IO_APIC_reg_00 reg_00;
@@ -1451,16 +1329,13 @@ static void __init print_IO_APIC(int ioapic_idx)
}
printk(KERN_DEBUG ".... IRQ redirection table:\n");
-
- x86_io_apic_ops.print_entries(ioapic_idx, reg_01.bits.entries);
+ io_apic_print_entries(ioapic_idx, reg_01.bits.entries);
}
void __init print_IO_APICs(void)
{
int ioapic_idx;
- struct irq_cfg *cfg;
unsigned int irq;
- struct irq_chip *chip;
printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
for_each_ioapic(ioapic_idx)
@@ -1480,18 +1355,20 @@ void __init print_IO_APICs(void)
printk(KERN_DEBUG "IRQ to pin mappings:\n");
for_each_active_irq(irq) {
struct irq_pin_list *entry;
+ struct irq_chip *chip;
+ struct mp_chip_data *data;
chip = irq_get_chip(irq);
- if (chip != &ioapic_chip)
+ if (chip != &ioapic_chip && chip != &ioapic_ir_chip)
continue;
-
- cfg = irq_cfg(irq);
- if (!cfg)
+ data = irq_get_chip_data(irq);
+ if (!data)
continue;
- if (list_empty(&cfg->irq_2_pin))
+ if (list_empty(&data->irq_2_pin))
continue;
+
printk(KERN_DEBUG "IRQ%d ", irq);
- for_each_irq_pin(entry, cfg->irq_2_pin)
+ for_each_irq_pin(entry, data->irq_2_pin)
pr_cont("-> %d:%d", entry->apic, entry->pin);
pr_cont("\n");
}
@@ -1564,15 +1441,12 @@ void native_disable_io_apic(void)
struct IO_APIC_route_entry entry;
memset(&entry, 0, sizeof(entry));
- entry.mask = 0; /* Enabled */
- entry.trigger = 0; /* Edge */
- entry.irr = 0;
- entry.polarity = 0; /* High */
- entry.delivery_status = 0;
- entry.dest_mode = 0; /* Physical */
- entry.delivery_mode = dest_ExtINT; /* ExtInt */
- entry.vector = 0;
- entry.dest = read_apic_id();
+ entry.mask = IOAPIC_UNMASKED;
+ entry.trigger = IOAPIC_EDGE;
+ entry.polarity = IOAPIC_POL_HIGH;
+ entry.dest_mode = IOAPIC_DEST_MODE_PHYSICAL;
+ entry.delivery_mode = dest_ExtINT;
+ entry.dest = read_apic_id();
/*
* Add it to the IO-APIC irq-routing table:
@@ -1582,7 +1456,6 @@ void native_disable_io_apic(void)
if (cpu_has_apic || apic_from_smp_config())
disconnect_bsp_APIC(ioapic_i8259.pin != -1);
-
}
/*
@@ -1792,7 +1665,6 @@ static int __init timer_irq_works(void)
* This is not complete - we should be able to fake
* an edge even if it isn't on the 8259A...
*/
-
static unsigned int startup_ioapic_irq(struct irq_data *data)
{
int was_pending = 0, irq = data->irq;
@@ -1804,74 +1676,22 @@ static unsigned int startup_ioapic_irq(struct irq_data *data)
if (legacy_pic->irq_pending(irq))
was_pending = 1;
}
- __unmask_ioapic(irqd_cfg(data));
+ __unmask_ioapic(data->chip_data);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
return was_pending;
}
-/*
- * Level and edge triggered IO-APIC interrupts need different handling,
- * so we use two separate IRQ descriptors. Edge triggered IRQs can be
- * handled with the level-triggered descriptor, but that one has slightly
- * more overhead. Level-triggered interrupts cannot be handled with the
- * edge-triggered handler, without risking IRQ storms and other ugly
- * races.
- */
-
-static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
-{
- int apic, pin;
- struct irq_pin_list *entry;
- u8 vector = cfg->vector;
-
- for_each_irq_pin(entry, cfg->irq_2_pin) {
- unsigned int reg;
-
- apic = entry->apic;
- pin = entry->pin;
-
- io_apic_write(apic, 0x11 + pin*2, dest);
- reg = io_apic_read(apic, 0x10 + pin*2);
- reg &= ~IO_APIC_REDIR_VECTOR_MASK;
- reg |= vector;
- io_apic_modify(apic, 0x10 + pin*2, reg);
- }
-}
-
-int native_ioapic_set_affinity(struct irq_data *data,
- const struct cpumask *mask,
- bool force)
-{
- unsigned int dest, irq = data->irq;
- unsigned long flags;
- int ret;
-
- if (!config_enabled(CONFIG_SMP))
- return -EPERM;
-
- raw_spin_lock_irqsave(&ioapic_lock, flags);
- ret = apic_set_affinity(data, mask, &dest);
- if (!ret) {
- /* Only the high 8 bits are valid. */
- dest = SET_APIC_LOGICAL_ID(dest);
- __target_IO_APIC_irq(irq, dest, irqd_cfg(data));
- ret = IRQ_SET_MASK_OK_NOCOPY;
- }
- raw_spin_unlock_irqrestore(&ioapic_lock, flags);
- return ret;
-}
-
atomic_t irq_mis_count;
#ifdef CONFIG_GENERIC_PENDING_IRQ
-static bool io_apic_level_ack_pending(struct irq_cfg *cfg)
+static bool io_apic_level_ack_pending(struct mp_chip_data *data)
{
struct irq_pin_list *entry;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags);
- for_each_irq_pin(entry, cfg->irq_2_pin) {
+ for_each_irq_pin(entry, data->irq_2_pin) {
unsigned int reg;
int pin;
@@ -1888,18 +1708,17 @@ static bool io_apic_level_ack_pending(struct irq_cfg *cfg)
return false;
}
-static inline bool ioapic_irqd_mask(struct irq_data *data, struct irq_cfg *cfg)
+static inline bool ioapic_irqd_mask(struct irq_data *data)
{
/* If we are moving the irq we need to mask it */
if (unlikely(irqd_is_setaffinity_pending(data))) {
- mask_ioapic(cfg);
+ mask_ioapic_irq(data);
return true;
}
return false;
}
-static inline void ioapic_irqd_unmask(struct irq_data *data,
- struct irq_cfg *cfg, bool masked)
+static inline void ioapic_irqd_unmask(struct irq_data *data, bool masked)
{
if (unlikely(masked)) {
/* Only migrate the irq if the ack has been received.
@@ -1928,31 +1747,30 @@ static inline void ioapic_irqd_unmask(struct irq_data *data,
* accurate and is causing problems then it is a hardware bug
* and you can go talk to the chipset vendor about it.
*/
- if (!io_apic_level_ack_pending(cfg))
+ if (!io_apic_level_ack_pending(data->chip_data))
irq_move_masked_irq(data);
- unmask_ioapic(cfg);
+ unmask_ioapic_irq(data);
}
}
#else
-static inline bool ioapic_irqd_mask(struct irq_data *data, struct irq_cfg *cfg)
+static inline bool ioapic_irqd_mask(struct irq_data *data)
{
return false;
}
-static inline void ioapic_irqd_unmask(struct irq_data *data,
- struct irq_cfg *cfg, bool masked)
+static inline void ioapic_irqd_unmask(struct irq_data *data, bool masked)
{
}
#endif
-static void ack_ioapic_level(struct irq_data *data)
+static void ioapic_ack_level(struct irq_data *irq_data)
{
- struct irq_cfg *cfg = irqd_cfg(data);
- int i, irq = data->irq;
+ struct irq_cfg *cfg = irqd_cfg(irq_data);
unsigned long v;
bool masked;
+ int i;
irq_complete_move(cfg);
- masked = ioapic_irqd_mask(data, cfg);
+ masked = ioapic_irqd_mask(irq_data);
/*
* It appears there is an erratum which affects at least version 0x11
@@ -2004,11 +1822,49 @@ static void ack_ioapic_level(struct irq_data *data)
*/
if (!(v & (1 << (i & 0x1f)))) {
atomic_inc(&irq_mis_count);
+ eoi_ioapic_pin(cfg->vector, irq_data->chip_data);
+ }
+
+ ioapic_irqd_unmask(irq_data, masked);
+}
+
+static void ioapic_ir_ack_level(struct irq_data *irq_data)
+{
+ struct mp_chip_data *data = irq_data->chip_data;
+
+ /*
+ * Intr-remapping uses pin number as the virtual vector
+ * in the RTE. Actual vector is programmed in
+ * intr-remapping table entry. Hence for the io-apic
+ * EOI we use the pin number.
+ */
+ ack_APIC_irq();
+ eoi_ioapic_pin(data->entry.vector, data);
+}
- eoi_ioapic_irq(irq, cfg);
+static int ioapic_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *mask, bool force)
+{
+ struct irq_data *parent = irq_data->parent_data;
+ struct mp_chip_data *data = irq_data->chip_data;
+ struct irq_pin_list *entry;
+ struct irq_cfg *cfg;
+ unsigned long flags;
+ int ret;
+
+ ret = parent->chip->irq_set_affinity(parent, mask, force);
+ raw_spin_lock_irqsave(&ioapic_lock, flags);
+ if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE) {
+ cfg = irqd_cfg(irq_data);
+ data->entry.dest = cfg->dest_apicid;
+ data->entry.vector = cfg->vector;
+ for_each_irq_pin(entry, data->irq_2_pin)
+ __ioapic_write_entry(entry->apic, entry->pin,
+ data->entry);
}
+ raw_spin_unlock_irqrestore(&ioapic_lock, flags);
- ioapic_irqd_unmask(data, cfg, masked);
+ return ret;
}
static struct irq_chip ioapic_chip __read_mostly = {
@@ -2016,10 +1872,20 @@ static struct irq_chip ioapic_chip __read_mostly = {
.irq_startup = startup_ioapic_irq,
.irq_mask = mask_ioapic_irq,
.irq_unmask = unmask_ioapic_irq,
- .irq_ack = apic_ack_edge,
- .irq_eoi = ack_ioapic_level,
- .irq_set_affinity = native_ioapic_set_affinity,
- .irq_retrigger = apic_retrigger_irq,
+ .irq_ack = irq_chip_ack_parent,
+ .irq_eoi = ioapic_ack_level,
+ .irq_set_affinity = ioapic_set_affinity,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
+};
+
+static struct irq_chip ioapic_ir_chip __read_mostly = {
+ .name = "IR-IO-APIC",
+ .irq_startup = startup_ioapic_irq,
+ .irq_mask = mask_ioapic_irq,
+ .irq_unmask = unmask_ioapic_irq,
+ .irq_ack = irq_chip_ack_parent,
+ .irq_eoi = ioapic_ir_ack_level,
+ .irq_set_affinity = ioapic_set_affinity,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
@@ -2113,12 +1979,12 @@ static inline void __init unlock_ExtINT_logic(void)
memset(&entry1, 0, sizeof(entry1));
- entry1.dest_mode = 0; /* physical delivery */
- entry1.mask = 0; /* unmask IRQ now */
+ entry1.dest_mode = IOAPIC_DEST_MODE_PHYSICAL;
+ entry1.mask = IOAPIC_UNMASKED;
entry1.dest = hard_smp_processor_id();
entry1.delivery_mode = dest_ExtINT;
entry1.polarity = entry0.polarity;
- entry1.trigger = 0;
+ entry1.trigger = IOAPIC_EDGE;
entry1.vector = 0;
ioapic_write_entry(apic, pin, entry1);
@@ -2152,6 +2018,25 @@ static int __init disable_timer_pin_setup(char *arg)
}
early_param("disable_timer_pin_1", disable_timer_pin_setup);
+static int mp_alloc_timer_irq(int ioapic, int pin)
+{
+ int irq = -1;
+ struct irq_domain *domain = mp_ioapic_irqdomain(ioapic);
+
+ if (domain) {
+ struct irq_alloc_info info;
+
+ ioapic_set_alloc_attr(&info, NUMA_NO_NODE, 0, 0);
+ info.ioapic_id = mpc_ioapic_id(ioapic);
+ info.ioapic_pin = pin;
+ mutex_lock(&ioapic_mutex);
+ irq = alloc_isa_irq_from_domain(domain, 0, ioapic, pin, &info);
+ mutex_unlock(&ioapic_mutex);
+ }
+
+ return irq;
+}
+
/*
* This code may look a bit paranoid, but it's supposed to cooperate with
* a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
@@ -2162,7 +2047,9 @@ early_param("disable_timer_pin_1", disable_timer_pin_setup);
*/
static inline void __init check_timer(void)
{
- struct irq_cfg *cfg = irq_cfg(0);
+ struct irq_data *irq_data = irq_get_irq_data(0);
+ struct mp_chip_data *data = irq_data->chip_data;
+ struct irq_cfg *cfg = irqd_cfg(irq_data);
int node = cpu_to_node(0);
int apic1, pin1, apic2, pin2;
unsigned long flags;
@@ -2174,7 +2061,6 @@ static inline void __init check_timer(void)
* get/set the timer IRQ vector:
*/
legacy_pic->mask(0);
- assign_irq_vector(0, cfg, apic->target_cpus());
/*
* As IRQ0 is to be enabled in the 8259A, the virtual
@@ -2215,23 +2101,21 @@ static inline void __init check_timer(void)
}
if (pin1 != -1) {
- /*
- * Ok, does IRQ0 through the IOAPIC work?
- */
+ /* Ok, does IRQ0 through the IOAPIC work? */
if (no_pin1) {
- add_pin_to_irq_node(cfg, node, apic1, pin1);
- setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
+ mp_alloc_timer_irq(apic1, pin1);
} else {
- /* for edge trigger, setup_ioapic_irq already
- * leave it unmasked.
+ /*
+ * for edge trigger, it's already unmasked,
* so only need to unmask if it is level-trigger
* do we really have level trigger timer?
*/
int idx;
idx = find_irq_entry(apic1, pin1, mp_INT);
if (idx != -1 && irq_trigger(idx))
- unmask_ioapic(cfg);
+ unmask_ioapic_irq(irq_get_chip_data(0));
}
+ irq_domain_activate_irq(irq_data);
if (timer_irq_works()) {
if (disable_timer_pin_1 > 0)
clear_IO_APIC_pin(0, pin1);
@@ -2251,8 +2135,8 @@ static inline void __init check_timer(void)
/*
* legacy devices should be connected to IO APIC #0
*/
- replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2);
- setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
+ replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2);
+ irq_domain_activate_irq(irq_data);
legacy_pic->unmask(0);
if (timer_irq_works()) {
apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
@@ -2329,36 +2213,35 @@ out:
static int mp_irqdomain_create(int ioapic)
{
- size_t size;
+ struct irq_alloc_info info;
+ struct irq_domain *parent;
int hwirqs = mp_ioapic_pin_count(ioapic);
struct ioapic *ip = &ioapics[ioapic];
struct ioapic_domain_cfg *cfg = &ip->irqdomain_cfg;
struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(ioapic);
- size = sizeof(struct mp_pin_info) * mp_ioapic_pin_count(ioapic);
- ip->pin_info = kzalloc(size, GFP_KERNEL);
- if (!ip->pin_info)
- return -ENOMEM;
-
if (cfg->type == IOAPIC_DOMAIN_INVALID)
return 0;
+ init_irq_alloc_info(&info, NULL);
+ info.type = X86_IRQ_ALLOC_TYPE_IOAPIC;
+ info.ioapic_id = mpc_ioapic_id(ioapic);
+ parent = irq_remapping_get_ir_irq_domain(&info);
+ if (!parent)
+ parent = x86_vector_domain;
+
ip->irqdomain = irq_domain_add_linear(cfg->dev, hwirqs, cfg->ops,
(void *)(long)ioapic);
- if(!ip->irqdomain) {
- kfree(ip->pin_info);
- ip->pin_info = NULL;
+ if (!ip->irqdomain)
return -ENOMEM;
- }
+
+ ip->irqdomain->parent = parent;
if (cfg->type == IOAPIC_DOMAIN_LEGACY ||
cfg->type == IOAPIC_DOMAIN_STRICT)
ioapic_dynirq_base = max(ioapic_dynirq_base,
gsi_cfg->gsi_end + 1);
- if (gsi_cfg->gsi_base == 0)
- irq_set_default_host(ip->irqdomain);
-
return 0;
}
@@ -2368,8 +2251,6 @@ static void ioapic_destroy_irqdomain(int idx)
irq_domain_remove(ioapics[idx].irqdomain);
ioapics[idx].irqdomain = NULL;
}
- kfree(ioapics[idx].pin_info);
- ioapics[idx].pin_info = NULL;
}
void __init setup_IO_APIC(void)
@@ -2399,20 +2280,6 @@ void __init setup_IO_APIC(void)
ioapic_initialized = 1;
}
-/*
- * Called after all the initialization is done. If we didn't find any
- * APIC bugs then we can allow the modify fast path
- */
-
-static int __init io_apic_bug_finalize(void)
-{
- if (sis_apic_bug == -1)
- sis_apic_bug = 0;
- return 0;
-}
-
-late_initcall(io_apic_bug_finalize);
-
static void resume_ioapic_id(int ioapic_idx)
{
unsigned long flags;
@@ -2451,20 +2318,6 @@ static int __init ioapic_init_ops(void)
device_initcall(ioapic_init_ops);
-static int
-io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr)
-{
- struct irq_cfg *cfg = alloc_irq_and_cfg_at(irq, node);
- int ret;
-
- if (!cfg)
- return -EINVAL;
- ret = __add_pin_to_irq_node(cfg, node, attr->ioapic, attr->ioapic_pin);
- if (!ret)
- setup_ioapic_irq(irq, cfg, attr);
- return ret;
-}
-
static int io_apic_get_redir_entries(int ioapic)
{
union IO_APIC_reg_01 reg_01;
@@ -2692,7 +2545,7 @@ void __init setup_ioapic_dest(void)
else
mask = apic->target_cpus();
- x86_io_apic_ops.set_affinity(idata, mask, false);
+ irq_set_affinity(irq, mask);
}
}
@@ -2737,7 +2590,7 @@ static struct resource * __init ioapic_setup_resources(void)
return res;
}
-void __init native_io_apic_init_mappings(void)
+void __init io_apic_init_mappings(void)
{
unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
struct resource *ioapic_res;
@@ -2962,7 +2815,6 @@ int mp_unregister_ioapic(u32 gsi_base)
{
int ioapic, pin;
int found = 0;
- struct mp_pin_info *pin_info;
for_each_ioapic(ioapic)
if (ioapics[ioapic].gsi_config.gsi_base == gsi_base) {
@@ -2975,11 +2827,17 @@ int mp_unregister_ioapic(u32 gsi_base)
}
for_each_pin(ioapic, pin) {
- pin_info = mp_pin_info(ioapic, pin);
- if (pin_info->count) {
- pr_warn("pin%d on IOAPIC%d is still in use.\n",
- pin, ioapic);
- return -EBUSY;
+ u32 gsi = mp_pin_to_gsi(ioapic, pin);
+ int irq = mp_map_gsi_to_irq(gsi, 0, NULL);
+ struct mp_chip_data *data;
+
+ if (irq >= 0) {
+ data = irq_get_chip_data(irq);
+ if (data && data->count) {
+ pr_warn("pin%d on IOAPIC%d is still in use.\n",
+ pin, ioapic);
+ return -EBUSY;
+ }
}
}
@@ -3006,108 +2864,141 @@ int mp_ioapic_registered(u32 gsi_base)
return 0;
}
-static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr,
- int ioapic, int ioapic_pin,
- int trigger, int polarity)
+static void mp_irqdomain_get_attr(u32 gsi, struct mp_chip_data *data,
+ struct irq_alloc_info *info)
{
- irq_attr->ioapic = ioapic;
- irq_attr->ioapic_pin = ioapic_pin;
- irq_attr->trigger = trigger;
- irq_attr->polarity = polarity;
+ if (info && info->ioapic_valid) {
+ data->trigger = info->ioapic_trigger;
+ data->polarity = info->ioapic_polarity;
+ } else if (acpi_get_override_irq(gsi, &data->trigger,
+ &data->polarity) < 0) {
+ /* PCI interrupts are always active low level triggered. */
+ data->trigger = IOAPIC_LEVEL;
+ data->polarity = IOAPIC_POL_LOW;
+ }
}
-int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
- irq_hw_number_t hwirq)
+static void mp_setup_entry(struct irq_cfg *cfg, struct mp_chip_data *data,
+ struct IO_APIC_route_entry *entry)
{
- int ioapic = (int)(long)domain->host_data;
- struct mp_pin_info *info = mp_pin_info(ioapic, hwirq);
- struct io_apic_irq_attr attr;
+ memset(entry, 0, sizeof(*entry));
+ entry->delivery_mode = apic->irq_delivery_mode;
+ entry->dest_mode = apic->irq_dest_mode;
+ entry->dest = cfg->dest_apicid;
+ entry->vector = cfg->vector;
+ entry->trigger = data->trigger;
+ entry->polarity = data->polarity;
+ /*
+ * Mask level triggered irqs. Edge triggered irqs are masked
+ * by the irq core code in case they fire.
+ */
+ if (data->trigger == IOAPIC_LEVEL)
+ entry->mask = IOAPIC_MASKED;
+ else
+ entry->mask = IOAPIC_UNMASKED;
+}
- /* Get default attribute if not set by caller yet */
- if (!info->set) {
- u32 gsi = mp_pin_to_gsi(ioapic, hwirq);
+int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ int ret, ioapic, pin;
+ struct irq_cfg *cfg;
+ struct irq_data *irq_data;
+ struct mp_chip_data *data;
+ struct irq_alloc_info *info = arg;
- if (acpi_get_override_irq(gsi, &info->trigger,
- &info->polarity) < 0) {
- /*
- * PCI interrupts are always polarity one level
- * triggered.
- */
- info->trigger = 1;
- info->polarity = 1;
- }
- info->node = NUMA_NO_NODE;
+ if (!info || nr_irqs > 1)
+ return -EINVAL;
+ irq_data = irq_domain_get_irq_data(domain, virq);
+ if (!irq_data)
+ return -EINVAL;
- /*
- * setup_IO_APIC_irqs() programs all legacy IRQs with default
- * trigger and polarity attributes. Don't set the flag for that
- * case so the first legacy IRQ user could reprogram the pin
- * with real trigger and polarity attributes.
- */
- if (virq >= nr_legacy_irqs() || info->count)
- info->set = 1;
- }
- set_io_apic_irq_attr(&attr, ioapic, hwirq, info->trigger,
- info->polarity);
+ ioapic = mp_irqdomain_ioapic_idx(domain);
+ pin = info->ioapic_pin;
+ if (irq_find_mapping(domain, (irq_hw_number_t)pin) > 0)
+ return -EEXIST;
- return io_apic_setup_irq_pin(virq, info->node, &attr);
-}
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
-void mp_irqdomain_unmap(struct irq_domain *domain, unsigned int virq)
-{
- struct irq_data *data = irq_get_irq_data(virq);
- struct irq_cfg *cfg = irq_cfg(virq);
- int ioapic = (int)(long)domain->host_data;
- int pin = (int)data->hwirq;
+ info->ioapic_entry = &data->entry;
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
+ if (ret < 0) {
+ kfree(data);
+ return ret;
+ }
+
+ INIT_LIST_HEAD(&data->irq_2_pin);
+ irq_data->hwirq = info->ioapic_pin;
+ irq_data->chip = (domain->parent == x86_vector_domain) ?
+ &ioapic_chip : &ioapic_ir_chip;
+ irq_data->chip_data = data;
+ mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info);
+
+ cfg = irqd_cfg(irq_data);
+ add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);
+ if (info->ioapic_entry)
+ mp_setup_entry(cfg, data, info->ioapic_entry);
+ mp_register_handler(virq, data->trigger);
+ if (virq < nr_legacy_irqs())
+ legacy_pic->mask(virq);
+
+ apic_printk(APIC_VERBOSE, KERN_DEBUG
+ "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i Dest:%d)\n",
+ ioapic, mpc_ioapic_id(ioapic), pin, cfg->vector,
+ virq, data->trigger, data->polarity, cfg->dest_apicid);
- ioapic_mask_entry(ioapic, pin);
- __remove_pin_from_irq(cfg, ioapic, pin);
- WARN_ON(!list_empty(&cfg->irq_2_pin));
- arch_teardown_hwirq(virq);
+ return 0;
}
-int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node)
+void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
{
- int ret = 0;
- int ioapic, pin;
- struct mp_pin_info *info;
+ struct irq_data *irq_data;
+ struct mp_chip_data *data;
- ioapic = mp_find_ioapic(gsi);
- if (ioapic < 0)
- return -ENODEV;
-
- pin = mp_find_ioapic_pin(ioapic, gsi);
- info = mp_pin_info(ioapic, pin);
- trigger = trigger ? 1 : 0;
- polarity = polarity ? 1 : 0;
-
- mutex_lock(&ioapic_mutex);
- if (!info->set) {
- info->trigger = trigger;
- info->polarity = polarity;
- info->node = node;
- info->set = 1;
- } else if (info->trigger != trigger || info->polarity != polarity) {
- ret = -EBUSY;
+ BUG_ON(nr_irqs != 1);
+ irq_data = irq_domain_get_irq_data(domain, virq);
+ if (irq_data && irq_data->chip_data) {
+ data = irq_data->chip_data;
+ __remove_pin_from_irq(data, mp_irqdomain_ioapic_idx(domain),
+ (int)irq_data->hwirq);
+ WARN_ON(!list_empty(&data->irq_2_pin));
+ kfree(irq_data->chip_data);
}
- mutex_unlock(&ioapic_mutex);
-
- return ret;
+ irq_domain_free_irqs_top(domain, virq, nr_irqs);
}
-/* Enable IOAPIC early just for system timer */
-void __init pre_init_apic_IRQ0(void)
+void mp_irqdomain_activate(struct irq_domain *domain,
+ struct irq_data *irq_data)
{
- struct io_apic_irq_attr attr = { 0, 0, 0, 0 };
+ unsigned long flags;
+ struct irq_pin_list *entry;
+ struct mp_chip_data *data = irq_data->chip_data;
- printk(KERN_INFO "Early APIC setup for system timer0\n");
-#ifndef CONFIG_SMP
- physid_set_mask_of_physid(boot_cpu_physical_apicid,
- &phys_cpu_present_map);
-#endif
- setup_local_APIC();
+ raw_spin_lock_irqsave(&ioapic_lock, flags);
+ for_each_irq_pin(entry, data->irq_2_pin)
+ __ioapic_write_entry(entry->apic, entry->pin, data->entry);
+ raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+}
- io_apic_setup_irq_pin(0, 0, &attr);
- irq_set_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq,
- "edge");
+void mp_irqdomain_deactivate(struct irq_domain *domain,
+ struct irq_data *irq_data)
+{
+ /* It won't be called for IRQ with multiple IOAPIC pins associated */
+ ioapic_mask_entry(mp_irqdomain_ioapic_idx(domain),
+ (int)irq_data->hwirq);
+}
+
+int mp_irqdomain_ioapic_idx(struct irq_domain *domain)
+{
+ return (int)(long)domain->host_data;
}
+
+const struct irq_domain_ops mp_ioapic_irqdomain_ops = {
+ .alloc = mp_irqdomain_alloc,
+ .free = mp_irqdomain_free,
+ .activate = mp_irqdomain_activate,
+ .deactivate = mp_irqdomain_deactivate,
+};
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index d6ba2d660dc5..1a9d735e09c6 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -3,6 +3,8 @@
*
* Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
* Moved from arch/x86/kernel/apic/io_apic.c.
+ * Jiang Liu <jiang.liu@linux.intel.com>
+ * Convert to hierarchical irqdomain
*
* 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
@@ -14,22 +16,23 @@
#include <linux/dmar.h>
#include <linux/hpet.h>
#include <linux/msi.h>
+#include <asm/irqdomain.h>
#include <asm/msidef.h>
#include <asm/hpet.h>
#include <asm/hw_irq.h>
#include <asm/apic.h>
#include <asm/irq_remapping.h>
-void native_compose_msi_msg(struct pci_dev *pdev,
- unsigned int irq, unsigned int dest,
- struct msi_msg *msg, u8 hpet_id)
+static struct irq_domain *msi_default_domain;
+
+static void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
{
- struct irq_cfg *cfg = irq_cfg(irq);
+ struct irq_cfg *cfg = irqd_cfg(data);
msg->address_hi = MSI_ADDR_BASE_HI;
if (x2apic_enabled())
- msg->address_hi |= MSI_ADDR_EXT_DEST_ID(dest);
+ msg->address_hi |= MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid);
msg->address_lo =
MSI_ADDR_BASE_LO |
@@ -39,7 +42,7 @@ void native_compose_msi_msg(struct pci_dev *pdev,
((apic->irq_delivery_mode != dest_LowestPrio) ?
MSI_ADDR_REDIRECTION_CPU :
MSI_ADDR_REDIRECTION_LOWPRI) |
- MSI_ADDR_DEST_ID(dest);
+ MSI_ADDR_DEST_ID(cfg->dest_apicid);
msg->data =
MSI_DATA_TRIGGER_EDGE |
@@ -50,180 +53,201 @@ void native_compose_msi_msg(struct pci_dev *pdev,
MSI_DATA_VECTOR(cfg->vector);
}
-static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
- struct msi_msg *msg, u8 hpet_id)
+/*
+ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
+ * which implement the MSI or MSI-X Capability Structure.
+ */
+static struct irq_chip pci_msi_controller = {
+ .name = "PCI-MSI",
+ .irq_unmask = pci_msi_unmask_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_ack = irq_chip_ack_parent,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_compose_msi_msg = irq_msi_compose_msg,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
+};
+
+int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
- struct irq_cfg *cfg;
- int err;
- unsigned dest;
+ struct irq_domain *domain;
+ struct irq_alloc_info info;
- if (disable_apic)
- return -ENXIO;
+ init_irq_alloc_info(&info, NULL);
+ info.type = X86_IRQ_ALLOC_TYPE_MSI;
+ info.msi_dev = dev;
- cfg = irq_cfg(irq);
- err = assign_irq_vector(irq, cfg, apic->target_cpus());
- if (err)
- return err;
+ domain = irq_remapping_get_irq_domain(&info);
+ if (domain == NULL)
+ domain = msi_default_domain;
+ if (domain == NULL)
+ return -ENOSYS;
- err = apic->cpu_mask_to_apicid_and(cfg->domain,
- apic->target_cpus(), &dest);
- if (err)
- return err;
+ return pci_msi_domain_alloc_irqs(domain, dev, nvec, type);
+}
- x86_msi.compose_msi_msg(pdev, irq, dest, msg, hpet_id);
+void native_teardown_msi_irq(unsigned int irq)
+{
+ irq_domain_free_irqs(irq, 1);
+}
- return 0;
+static irq_hw_number_t pci_msi_get_hwirq(struct msi_domain_info *info,
+ msi_alloc_info_t *arg)
+{
+ return arg->msi_hwirq;
}
-static int
-msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
+static int pci_msi_prepare(struct irq_domain *domain, struct device *dev,
+ int nvec, msi_alloc_info_t *arg)
{
- struct irq_cfg *cfg = irqd_cfg(data);
- struct msi_msg msg;
- unsigned int dest;
- int ret;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct msi_desc *desc = first_pci_msi_entry(pdev);
+
+ init_irq_alloc_info(arg, NULL);
+ arg->msi_dev = pdev;
+ if (desc->msi_attrib.is_msix) {
+ arg->type = X86_IRQ_ALLOC_TYPE_MSIX;
+ } else {
+ arg->type = X86_IRQ_ALLOC_TYPE_MSI;
+ arg->flags |= X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
+ }
- ret = apic_set_affinity(data, mask, &dest);
- if (ret)
- return ret;
+ return 0;
+}
- __get_cached_msi_msg(data->msi_desc, &msg);
+static void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
+{
+ arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc);
+}
+
+static struct msi_domain_ops pci_msi_domain_ops = {
+ .get_hwirq = pci_msi_get_hwirq,
+ .msi_prepare = pci_msi_prepare,
+ .set_desc = pci_msi_set_desc,
+};
- msg.data &= ~MSI_DATA_VECTOR_MASK;
- msg.data |= MSI_DATA_VECTOR(cfg->vector);
- msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
- msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+static struct msi_domain_info pci_msi_domain_info = {
+ .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+ MSI_FLAG_PCI_MSIX,
+ .ops = &pci_msi_domain_ops,
+ .chip = &pci_msi_controller,
+ .handler = handle_edge_irq,
+ .handler_name = "edge",
+};
- __pci_write_msi_msg(data->msi_desc, &msg);
+void arch_init_msi_domain(struct irq_domain *parent)
+{
+ if (disable_apic)
+ return;
- return IRQ_SET_MASK_OK_NOCOPY;
+ msi_default_domain = pci_msi_create_irq_domain(NULL,
+ &pci_msi_domain_info, parent);
+ if (!msi_default_domain)
+ pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n");
}
-/*
- * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI or MSI-X Capability Structure.
- */
-static struct irq_chip msi_chip = {
- .name = "PCI-MSI",
+#ifdef CONFIG_IRQ_REMAP
+static struct irq_chip pci_msi_ir_controller = {
+ .name = "IR-PCI-MSI",
.irq_unmask = pci_msi_unmask_irq,
.irq_mask = pci_msi_mask_irq,
- .irq_ack = apic_ack_edge,
- .irq_set_affinity = msi_set_affinity,
- .irq_retrigger = apic_retrigger_irq,
+ .irq_ack = irq_chip_ack_parent,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
-int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
- unsigned int irq_base, unsigned int irq_offset)
-{
- struct irq_chip *chip = &msi_chip;
- struct msi_msg msg;
- unsigned int irq = irq_base + irq_offset;
- int ret;
-
- ret = msi_compose_msg(dev, irq, &msg, -1);
- if (ret < 0)
- return ret;
-
- irq_set_msi_desc_off(irq_base, irq_offset, msidesc);
-
- /*
- * MSI-X message is written per-IRQ, the offset is always 0.
- * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
- */
- if (!irq_offset)
- pci_write_msi_msg(irq, &msg);
+static struct msi_domain_info pci_msi_ir_domain_info = {
+ .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+ MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
+ .ops = &pci_msi_domain_ops,
+ .chip = &pci_msi_ir_controller,
+ .handler = handle_edge_irq,
+ .handler_name = "edge",
+};
- setup_remapped_irq(irq, irq_cfg(irq), chip);
+struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent)
+{
+ return pci_msi_create_irq_domain(NULL, &pci_msi_ir_domain_info, parent);
+}
+#endif
- irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
+#ifdef CONFIG_DMAR_TABLE
+static void dmar_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
+{
+ dmar_msi_write(data->irq, msg);
+}
- dev_dbg(&dev->dev, "irq %d for MSI/MSI-X\n", irq);
+static struct irq_chip dmar_msi_controller = {
+ .name = "DMAR-MSI",
+ .irq_unmask = dmar_msi_unmask,
+ .irq_mask = dmar_msi_mask,
+ .irq_ack = irq_chip_ack_parent,
+ .irq_set_affinity = msi_domain_set_affinity,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_compose_msi_msg = irq_msi_compose_msg,
+ .irq_write_msi_msg = dmar_msi_write_msg,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
+};
- return 0;
+static irq_hw_number_t dmar_msi_get_hwirq(struct msi_domain_info *info,
+ msi_alloc_info_t *arg)
+{
+ return arg->dmar_id;
}
-int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+static int dmar_msi_init(struct irq_domain *domain,
+ struct msi_domain_info *info, unsigned int virq,
+ irq_hw_number_t hwirq, msi_alloc_info_t *arg)
{
- struct msi_desc *msidesc;
- unsigned int irq;
- int node, ret;
+ irq_domain_set_info(domain, virq, arg->dmar_id, info->chip, NULL,
+ handle_edge_irq, arg->dmar_data, "edge");
- /* Multiple MSI vectors only supported with interrupt remapping */
- if (type == PCI_CAP_ID_MSI && nvec > 1)
- return 1;
+ return 0;
+}
- node = dev_to_node(&dev->dev);
+static struct msi_domain_ops dmar_msi_domain_ops = {
+ .get_hwirq = dmar_msi_get_hwirq,
+ .msi_init = dmar_msi_init,
+};
- list_for_each_entry(msidesc, &dev->msi_list, list) {
- irq = irq_alloc_hwirq(node);
- if (!irq)
- return -ENOSPC;
+static struct msi_domain_info dmar_msi_domain_info = {
+ .ops = &dmar_msi_domain_ops,
+ .chip = &dmar_msi_controller,
+};
- ret = setup_msi_irq(dev, msidesc, irq, 0);
- if (ret < 0) {
- irq_free_hwirq(irq);
- return ret;
- }
+static struct irq_domain *dmar_get_irq_domain(void)
+{
+ static struct irq_domain *dmar_domain;
+ static DEFINE_MUTEX(dmar_lock);
- }
- return 0;
-}
+ mutex_lock(&dmar_lock);
+ if (dmar_domain == NULL)
+ dmar_domain = msi_create_irq_domain(NULL, &dmar_msi_domain_info,
+ x86_vector_domain);
+ mutex_unlock(&dmar_lock);
-void native_teardown_msi_irq(unsigned int irq)
-{
- irq_free_hwirq(irq);
+ return dmar_domain;
}
-#ifdef CONFIG_DMAR_TABLE
-static int
-dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
- bool force)
+int dmar_alloc_hwirq(int id, int node, void *arg)
{
- struct irq_cfg *cfg = irqd_cfg(data);
- unsigned int dest, irq = data->irq;
- struct msi_msg msg;
- int ret;
-
- ret = apic_set_affinity(data, mask, &dest);
- if (ret)
- return ret;
+ struct irq_domain *domain = dmar_get_irq_domain();
+ struct irq_alloc_info info;
- dmar_msi_read(irq, &msg);
+ if (!domain)
+ return -1;
- msg.data &= ~MSI_DATA_VECTOR_MASK;
- msg.data |= MSI_DATA_VECTOR(cfg->vector);
- msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
- msg.address_lo |= MSI_ADDR_DEST_ID(dest);
- msg.address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(dest);
+ init_irq_alloc_info(&info, NULL);
+ info.type = X86_IRQ_ALLOC_TYPE_DMAR;
+ info.dmar_id = id;
+ info.dmar_data = arg;
- dmar_msi_write(irq, &msg);
-
- return IRQ_SET_MASK_OK_NOCOPY;
+ return irq_domain_alloc_irqs(domain, 1, node, &info);
}
-static struct irq_chip dmar_msi_type = {
- .name = "DMAR_MSI",
- .irq_unmask = dmar_msi_unmask,
- .irq_mask = dmar_msi_mask,
- .irq_ack = apic_ack_edge,
- .irq_set_affinity = dmar_msi_set_affinity,
- .irq_retrigger = apic_retrigger_irq,
- .flags = IRQCHIP_SKIP_SET_WAKE,
-};
-
-int arch_setup_dmar_msi(unsigned int irq)
+void dmar_free_hwirq(int irq)
{
- int ret;
- struct msi_msg msg;
-
- ret = msi_compose_msg(NULL, irq, &msg, -1);
- if (ret < 0)
- return ret;
- dmar_msi_write(irq, &msg);
- irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
- "edge");
- return 0;
+ irq_domain_free_irqs(irq, 1);
}
#endif
@@ -231,56 +255,103 @@ int arch_setup_dmar_msi(unsigned int irq)
* MSI message composition
*/
#ifdef CONFIG_HPET_TIMER
+static inline int hpet_dev_id(struct irq_domain *domain)
+{
+ struct msi_domain_info *info = msi_get_domain_info(domain);
+
+ return (int)(long)info->data;
+}
-static int hpet_msi_set_affinity(struct irq_data *data,
- const struct cpumask *mask, bool force)
+static void hpet_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
{
- struct irq_cfg *cfg = irqd_cfg(data);
- struct msi_msg msg;
- unsigned int dest;
- int ret;
+ hpet_msi_write(data->handler_data, msg);
+}
- ret = apic_set_affinity(data, mask, &dest);
- if (ret)
- return ret;
+static struct irq_chip hpet_msi_controller = {
+ .name = "HPET-MSI",
+ .irq_unmask = hpet_msi_unmask,
+ .irq_mask = hpet_msi_mask,
+ .irq_ack = irq_chip_ack_parent,
+ .irq_set_affinity = msi_domain_set_affinity,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_compose_msi_msg = irq_msi_compose_msg,
+ .irq_write_msi_msg = hpet_msi_write_msg,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
+};
- hpet_msi_read(data->handler_data, &msg);
+static irq_hw_number_t hpet_msi_get_hwirq(struct msi_domain_info *info,
+ msi_alloc_info_t *arg)
+{
+ return arg->hpet_index;
+}
- msg.data &= ~MSI_DATA_VECTOR_MASK;
- msg.data |= MSI_DATA_VECTOR(cfg->vector);
- msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
- msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+static int hpet_msi_init(struct irq_domain *domain,
+ struct msi_domain_info *info, unsigned int virq,
+ irq_hw_number_t hwirq, msi_alloc_info_t *arg)
+{
+ irq_set_status_flags(virq, IRQ_MOVE_PCNTXT);
+ irq_domain_set_info(domain, virq, arg->hpet_index, info->chip, NULL,
+ handle_edge_irq, arg->hpet_data, "edge");
- hpet_msi_write(data->handler_data, &msg);
+ return 0;
+}
- return IRQ_SET_MASK_OK_NOCOPY;
+static void hpet_msi_free(struct irq_domain *domain,
+ struct msi_domain_info *info, unsigned int virq)
+{
+ irq_clear_status_flags(virq, IRQ_MOVE_PCNTXT);
}
-static struct irq_chip hpet_msi_type = {
- .name = "HPET_MSI",
- .irq_unmask = hpet_msi_unmask,
- .irq_mask = hpet_msi_mask,
- .irq_ack = apic_ack_edge,
- .irq_set_affinity = hpet_msi_set_affinity,
- .irq_retrigger = apic_retrigger_irq,
- .flags = IRQCHIP_SKIP_SET_WAKE,
+static struct msi_domain_ops hpet_msi_domain_ops = {
+ .get_hwirq = hpet_msi_get_hwirq,
+ .msi_init = hpet_msi_init,
+ .msi_free = hpet_msi_free,
+};
+
+static struct msi_domain_info hpet_msi_domain_info = {
+ .ops = &hpet_msi_domain_ops,
+ .chip = &hpet_msi_controller,
};
-int default_setup_hpet_msi(unsigned int irq, unsigned int id)
+struct irq_domain *hpet_create_irq_domain(int hpet_id)
{
- struct irq_chip *chip = &hpet_msi_type;
- struct msi_msg msg;
- int ret;
+ struct irq_domain *parent;
+ struct irq_alloc_info info;
+ struct msi_domain_info *domain_info;
+
+ if (x86_vector_domain == NULL)
+ return NULL;
+
+ domain_info = kzalloc(sizeof(*domain_info), GFP_KERNEL);
+ if (!domain_info)
+ return NULL;
+
+ *domain_info = hpet_msi_domain_info;
+ domain_info->data = (void *)(long)hpet_id;
+
+ init_irq_alloc_info(&info, NULL);
+ info.type = X86_IRQ_ALLOC_TYPE_HPET;
+ info.hpet_id = hpet_id;
+ parent = irq_remapping_get_ir_irq_domain(&info);
+ if (parent == NULL)
+ parent = x86_vector_domain;
+ else
+ hpet_msi_controller.name = "IR-HPET-MSI";
+
+ return msi_create_irq_domain(NULL, domain_info, parent);
+}
- ret = msi_compose_msg(NULL, irq, &msg, id);
- if (ret < 0)
- return ret;
+int hpet_assign_irq(struct irq_domain *domain, struct hpet_dev *dev,
+ int dev_num)
+{
+ struct irq_alloc_info info;
- hpet_msi_write(irq_get_handler_data(irq), &msg);
- irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
- setup_remapped_irq(irq, irq_cfg(irq), chip);
+ init_irq_alloc_info(&info, NULL);
+ info.type = X86_IRQ_ALLOC_TYPE_HPET;
+ info.hpet_data = dev;
+ info.hpet_id = hpet_dev_id(domain);
+ info.hpet_index = dev_num;
- irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
- return 0;
+ return irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, &info);
}
#endif
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index 6cedd7914581..28eba2d38b15 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -3,6 +3,8 @@
*
* Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
* Moved from arch/x86/kernel/apic/io_apic.c.
+ * Jiang Liu <jiang.liu@linux.intel.com>
+ * Enable support of hierarchical irqdomains
*
* 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
@@ -11,15 +13,28 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/compiler.h>
-#include <linux/irqdomain.h>
#include <linux/slab.h>
+#include <asm/irqdomain.h>
#include <asm/hw_irq.h>
#include <asm/apic.h>
#include <asm/i8259.h>
#include <asm/desc.h>
#include <asm/irq_remapping.h>
+struct apic_chip_data {
+ struct irq_cfg cfg;
+ cpumask_var_t domain;
+ cpumask_var_t old_domain;
+ u8 move_in_progress : 1;
+};
+
+struct irq_domain *x86_vector_domain;
static DEFINE_RAW_SPINLOCK(vector_lock);
+static cpumask_var_t vector_cpumask;
+static struct irq_chip lapic_controller;
+#ifdef CONFIG_X86_IO_APIC
+static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY];
+#endif
void lock_vector_lock(void)
{
@@ -34,71 +49,59 @@ void unlock_vector_lock(void)
raw_spin_unlock(&vector_lock);
}
-struct irq_cfg *irq_cfg(unsigned int irq)
+static struct apic_chip_data *apic_chip_data(struct irq_data *irq_data)
{
- return irq_get_chip_data(irq);
+ if (!irq_data)
+ return NULL;
+
+ while (irq_data->parent_data)
+ irq_data = irq_data->parent_data;
+
+ return irq_data->chip_data;
}
struct irq_cfg *irqd_cfg(struct irq_data *irq_data)
{
- return irq_data->chip_data;
+ struct apic_chip_data *data = apic_chip_data(irq_data);
+
+ return data ? &data->cfg : NULL;
}
-static struct irq_cfg *alloc_irq_cfg(unsigned int irq, int node)
+struct irq_cfg *irq_cfg(unsigned int irq)
{
- struct irq_cfg *cfg;
+ return irqd_cfg(irq_get_irq_data(irq));
+}
- cfg = kzalloc_node(sizeof(*cfg), GFP_KERNEL, node);
- if (!cfg)
+static struct apic_chip_data *alloc_apic_chip_data(int node)
+{
+ struct apic_chip_data *data;
+
+ data = kzalloc_node(sizeof(*data), GFP_KERNEL, node);
+ if (!data)
return NULL;
- if (!zalloc_cpumask_var_node(&cfg->domain, GFP_KERNEL, node))
- goto out_cfg;
- if (!zalloc_cpumask_var_node(&cfg->old_domain, GFP_KERNEL, node))
+ if (!zalloc_cpumask_var_node(&data->domain, GFP_KERNEL, node))
+ goto out_data;
+ if (!zalloc_cpumask_var_node(&data->old_domain, GFP_KERNEL, node))
goto out_domain;
-#ifdef CONFIG_X86_IO_APIC
- INIT_LIST_HEAD(&cfg->irq_2_pin);
-#endif
- return cfg;
+ return data;
out_domain:
- free_cpumask_var(cfg->domain);
-out_cfg:
- kfree(cfg);
+ free_cpumask_var(data->domain);
+out_data:
+ kfree(data);
return NULL;
}
-struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node)
+static void free_apic_chip_data(struct apic_chip_data *data)
{
- int res = irq_alloc_desc_at(at, node);
- struct irq_cfg *cfg;
-
- if (res < 0) {
- if (res != -EEXIST)
- return NULL;
- cfg = irq_cfg(at);
- if (cfg)
- return cfg;
+ if (data) {
+ free_cpumask_var(data->domain);
+ free_cpumask_var(data->old_domain);
+ kfree(data);
}
-
- cfg = alloc_irq_cfg(at, node);
- if (cfg)
- irq_set_chip_data(at, cfg);
- else
- irq_free_desc(at);
- return cfg;
-}
-
-static void free_irq_cfg(unsigned int at, struct irq_cfg *cfg)
-{
- if (!cfg)
- return;
- irq_set_chip_data(at, NULL);
- free_cpumask_var(cfg->domain);
- free_cpumask_var(cfg->old_domain);
- kfree(cfg);
}
-static int
-__assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
+static int __assign_irq_vector(int irq, struct apic_chip_data *d,
+ const struct cpumask *mask)
{
/*
* NOTE! The local APIC isn't very good at handling
@@ -114,36 +117,33 @@ __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START;
static int current_offset = VECTOR_OFFSET_START % 16;
int cpu, err;
- cpumask_var_t tmp_mask;
- if (cfg->move_in_progress)
+ if (d->move_in_progress)
return -EBUSY;
- if (!alloc_cpumask_var(&tmp_mask, GFP_ATOMIC))
- return -ENOMEM;
-
/* Only try and allocate irqs on cpus that are present */
err = -ENOSPC;
- cpumask_clear(cfg->old_domain);
+ cpumask_clear(d->old_domain);
cpu = cpumask_first_and(mask, cpu_online_mask);
while (cpu < nr_cpu_ids) {
int new_cpu, vector, offset;
- apic->vector_allocation_domain(cpu, tmp_mask, mask);
+ apic->vector_allocation_domain(cpu, vector_cpumask, mask);
- if (cpumask_subset(tmp_mask, cfg->domain)) {
+ if (cpumask_subset(vector_cpumask, d->domain)) {
err = 0;
- if (cpumask_equal(tmp_mask, cfg->domain))
+ if (cpumask_equal(vector_cpumask, d->domain))
break;
/*
* New cpumask using the vector is a proper subset of
* the current in use mask. So cleanup the vector
* allocation for the members that are not used anymore.
*/
- cpumask_andnot(cfg->old_domain, cfg->domain, tmp_mask);
- cfg->move_in_progress =
- cpumask_intersects(cfg->old_domain, cpu_online_mask);
- cpumask_and(cfg->domain, cfg->domain, tmp_mask);
+ cpumask_andnot(d->old_domain, d->domain,
+ vector_cpumask);
+ d->move_in_progress =
+ cpumask_intersects(d->old_domain, cpu_online_mask);
+ cpumask_and(d->domain, d->domain, vector_cpumask);
break;
}
@@ -157,16 +157,18 @@ next:
}
if (unlikely(current_vector == vector)) {
- cpumask_or(cfg->old_domain, cfg->old_domain, tmp_mask);
- cpumask_andnot(tmp_mask, mask, cfg->old_domain);
- cpu = cpumask_first_and(tmp_mask, cpu_online_mask);
+ cpumask_or(d->old_domain, d->old_domain,
+ vector_cpumask);
+ cpumask_andnot(vector_cpumask, mask, d->old_domain);
+ cpu = cpumask_first_and(vector_cpumask,
+ cpu_online_mask);
continue;
}
if (test_bit(vector, used_vectors))
goto next;
- for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask) {
+ for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) {
if (per_cpu(vector_irq, new_cpu)[vector] >
VECTOR_UNDEFINED)
goto next;
@@ -174,55 +176,73 @@ next:
/* Found one! */
current_vector = vector;
current_offset = offset;
- if (cfg->vector) {
- cpumask_copy(cfg->old_domain, cfg->domain);
- cfg->move_in_progress =
- cpumask_intersects(cfg->old_domain, cpu_online_mask);
+ if (d->cfg.vector) {
+ cpumask_copy(d->old_domain, d->domain);
+ d->move_in_progress =
+ cpumask_intersects(d->old_domain, cpu_online_mask);
}
- for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask)
+ for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask)
per_cpu(vector_irq, new_cpu)[vector] = irq;
- cfg->vector = vector;
- cpumask_copy(cfg->domain, tmp_mask);
+ d->cfg.vector = vector;
+ cpumask_copy(d->domain, vector_cpumask);
err = 0;
break;
}
- free_cpumask_var(tmp_mask);
+
+ if (!err) {
+ /* cache destination APIC IDs into cfg->dest_apicid */
+ err = apic->cpu_mask_to_apicid_and(mask, d->domain,
+ &d->cfg.dest_apicid);
+ }
return err;
}
-int assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
+static int assign_irq_vector(int irq, struct apic_chip_data *data,
+ const struct cpumask *mask)
{
int err;
unsigned long flags;
raw_spin_lock_irqsave(&vector_lock, flags);
- err = __assign_irq_vector(irq, cfg, mask);
+ err = __assign_irq_vector(irq, data, mask);
raw_spin_unlock_irqrestore(&vector_lock, flags);
return err;
}
-void clear_irq_vector(int irq, struct irq_cfg *cfg)
+static int assign_irq_vector_policy(int irq, int node,
+ struct apic_chip_data *data,
+ struct irq_alloc_info *info)
+{
+ if (info && info->mask)
+ return assign_irq_vector(irq, data, info->mask);
+ if (node != NUMA_NO_NODE &&
+ assign_irq_vector(irq, data, cpumask_of_node(node)) == 0)
+ return 0;
+ return assign_irq_vector(irq, data, apic->target_cpus());
+}
+
+static void clear_irq_vector(int irq, struct apic_chip_data *data)
{
int cpu, vector;
unsigned long flags;
raw_spin_lock_irqsave(&vector_lock, flags);
- BUG_ON(!cfg->vector);
+ BUG_ON(!data->cfg.vector);
- vector = cfg->vector;
- for_each_cpu_and(cpu, cfg->domain, cpu_online_mask)
+ vector = data->cfg.vector;
+ for_each_cpu_and(cpu, data->domain, cpu_online_mask)
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
- cfg->vector = 0;
- cpumask_clear(cfg->domain);
+ data->cfg.vector = 0;
+ cpumask_clear(data->domain);
- if (likely(!cfg->move_in_progress)) {
+ if (likely(!data->move_in_progress)) {
raw_spin_unlock_irqrestore(&vector_lock, flags);
return;
}
- for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) {
+ for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) {
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
vector++) {
if (per_cpu(vector_irq, cpu)[vector] != irq)
@@ -231,10 +251,95 @@ void clear_irq_vector(int irq, struct irq_cfg *cfg)
break;
}
}
- cfg->move_in_progress = 0;
+ data->move_in_progress = 0;
raw_spin_unlock_irqrestore(&vector_lock, flags);
}
+void init_irq_alloc_info(struct irq_alloc_info *info,
+ const struct cpumask *mask)
+{
+ memset(info, 0, sizeof(*info));
+ info->mask = mask;
+}
+
+void copy_irq_alloc_info(struct irq_alloc_info *dst, struct irq_alloc_info *src)
+{
+ if (src)
+ *dst = *src;
+ else
+ memset(dst, 0, sizeof(*dst));
+}
+
+static void x86_vector_free_irqs(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
+{
+ struct irq_data *irq_data;
+ int i;
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_data = irq_domain_get_irq_data(x86_vector_domain, virq + i);
+ if (irq_data && irq_data->chip_data) {
+ clear_irq_vector(virq + i, irq_data->chip_data);
+ free_apic_chip_data(irq_data->chip_data);
+#ifdef CONFIG_X86_IO_APIC
+ if (virq + i < nr_legacy_irqs())
+ legacy_irq_data[virq + i] = NULL;
+#endif
+ irq_domain_reset_irq_data(irq_data);
+ }
+ }
+}
+
+static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ struct irq_alloc_info *info = arg;
+ struct apic_chip_data *data;
+ struct irq_data *irq_data;
+ int i, err;
+
+ if (disable_apic)
+ return -ENXIO;
+
+ /* Currently vector allocator can't guarantee contiguous allocations */
+ if ((info->flags & X86_IRQ_ALLOC_CONTIGUOUS_VECTORS) && nr_irqs > 1)
+ return -ENOSYS;
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_data = irq_domain_get_irq_data(domain, virq + i);
+ BUG_ON(!irq_data);
+#ifdef CONFIG_X86_IO_APIC
+ if (virq + i < nr_legacy_irqs() && legacy_irq_data[virq + i])
+ data = legacy_irq_data[virq + i];
+ else
+#endif
+ data = alloc_apic_chip_data(irq_data->node);
+ if (!data) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ irq_data->chip = &lapic_controller;
+ irq_data->chip_data = data;
+ irq_data->hwirq = virq + i;
+ err = assign_irq_vector_policy(virq, irq_data->node, data,
+ info);
+ if (err)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ x86_vector_free_irqs(domain, virq, i + 1);
+ return err;
+}
+
+static const struct irq_domain_ops x86_vector_domain_ops = {
+ .alloc = x86_vector_alloc_irqs,
+ .free = x86_vector_free_irqs,
+};
+
int __init arch_probe_nr_irqs(void)
{
int nr;
@@ -258,8 +363,43 @@ int __init arch_probe_nr_irqs(void)
return nr_legacy_irqs();
}
+#ifdef CONFIG_X86_IO_APIC
+static void init_legacy_irqs(void)
+{
+ int i, node = cpu_to_node(0);
+ struct apic_chip_data *data;
+
+ /*
+ * For legacy IRQ's, start with assigning irq0 to irq15 to
+ * ISA_IRQ_VECTOR(i) for all cpu's.
+ */
+ for (i = 0; i < nr_legacy_irqs(); i++) {
+ data = legacy_irq_data[i] = alloc_apic_chip_data(node);
+ BUG_ON(!data);
+
+ data->cfg.vector = ISA_IRQ_VECTOR(i);
+ cpumask_setall(data->domain);
+ irq_set_chip_data(i, data);
+ }
+}
+#else
+static void init_legacy_irqs(void) { }
+#endif
+
int __init arch_early_irq_init(void)
{
+ init_legacy_irqs();
+
+ x86_vector_domain = irq_domain_add_tree(NULL, &x86_vector_domain_ops,
+ NULL);
+ BUG_ON(x86_vector_domain == NULL);
+ irq_set_default_host(x86_vector_domain);
+
+ arch_init_msi_domain(x86_vector_domain);
+ arch_init_htirq_domain(x86_vector_domain);
+
+ BUG_ON(!alloc_cpumask_var(&vector_cpumask, GFP_KERNEL));
+
return arch_early_ioapic_init();
}
@@ -267,7 +407,7 @@ static void __setup_vector_irq(int cpu)
{
/* Initialize vector_irq on a new cpu */
int irq, vector;
- struct irq_cfg *cfg;
+ struct apic_chip_data *data;
/*
* vector_lock will make sure that we don't run into irq vector
@@ -277,13 +417,13 @@ static void __setup_vector_irq(int cpu)
raw_spin_lock(&vector_lock);
/* Mark the inuse vectors */
for_each_active_irq(irq) {
- cfg = irq_cfg(irq);
- if (!cfg)
+ data = apic_chip_data(irq_get_irq_data(irq));
+ if (!data)
continue;
- if (!cpumask_test_cpu(cpu, cfg->domain))
+ if (!cpumask_test_cpu(cpu, data->domain))
continue;
- vector = cfg->vector;
+ vector = data->cfg.vector;
per_cpu(vector_irq, cpu)[vector] = irq;
}
/* Mark the free vectors */
@@ -292,8 +432,8 @@ static void __setup_vector_irq(int cpu)
if (irq <= VECTOR_UNDEFINED)
continue;
- cfg = irq_cfg(irq);
- if (!cpumask_test_cpu(cpu, cfg->domain))
+ data = apic_chip_data(irq_get_irq_data(irq));
+ if (!cpumask_test_cpu(cpu, data->domain))
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
}
raw_spin_unlock(&vector_lock);
@@ -314,20 +454,20 @@ void setup_vector_irq(int cpu)
* legacy vector to irq mapping:
*/
for (irq = 0; irq < nr_legacy_irqs(); irq++)
- per_cpu(vector_irq, cpu)[IRQ0_VECTOR + irq] = irq;
+ per_cpu(vector_irq, cpu)[ISA_IRQ_VECTOR(irq)] = irq;
__setup_vector_irq(cpu);
}
-int apic_retrigger_irq(struct irq_data *data)
+static int apic_retrigger_irq(struct irq_data *irq_data)
{
- struct irq_cfg *cfg = irqd_cfg(data);
+ struct apic_chip_data *data = apic_chip_data(irq_data);
unsigned long flags;
int cpu;
raw_spin_lock_irqsave(&vector_lock, flags);
- cpu = cpumask_first_and(cfg->domain, cpu_online_mask);
- apic->send_IPI_mask(cpumask_of(cpu), cfg->vector);
+ cpu = cpumask_first_and(data->domain, cpu_online_mask);
+ apic->send_IPI_mask(cpumask_of(cpu), data->cfg.vector);
raw_spin_unlock_irqrestore(&vector_lock, flags);
return 1;
@@ -340,73 +480,76 @@ void apic_ack_edge(struct irq_data *data)
ack_APIC_irq();
}
-/*
- * Either sets data->affinity to a valid value, and returns
- * ->cpu_mask_to_apicid of that in dest_id, or returns -1 and
- * leaves data->affinity untouched.
- */
-int apic_set_affinity(struct irq_data *data, const struct cpumask *mask,
- unsigned int *dest_id)
+static int apic_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *dest, bool force)
{
- struct irq_cfg *cfg = irqd_cfg(data);
- unsigned int irq = data->irq;
- int err;
+ struct apic_chip_data *data = irq_data->chip_data;
+ int err, irq = irq_data->irq;
if (!config_enabled(CONFIG_SMP))
return -EPERM;
- if (!cpumask_intersects(mask, cpu_online_mask))
+ if (!cpumask_intersects(dest, cpu_online_mask))
return -EINVAL;
- err = assign_irq_vector(irq, cfg, mask);
- if (err)
- return err;
-
- err = apic->cpu_mask_to_apicid_and(mask, cfg->domain, dest_id);
+ err = assign_irq_vector(irq, data, dest);
if (err) {
- if (assign_irq_vector(irq, cfg, data->affinity))
+ struct irq_data *top = irq_get_irq_data(irq);
+
+ if (assign_irq_vector(irq, data, top->affinity))
pr_err("Failed to recover vector for irq %d\n", irq);
return err;
}
- cpumask_copy(data->affinity, mask);
-
- return 0;
+ return IRQ_SET_MASK_OK;
}
+static struct irq_chip lapic_controller = {
+ .irq_ack = apic_ack_edge,
+ .irq_set_affinity = apic_set_affinity,
+ .irq_retrigger = apic_retrigger_irq,
+};
+
#ifdef CONFIG_SMP
-void send_cleanup_vector(struct irq_cfg *cfg)
+static void __send_cleanup_vector(struct apic_chip_data *data)
{
cpumask_var_t cleanup_mask;
if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
unsigned int i;
- for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
+ for_each_cpu_and(i, data->old_domain, cpu_online_mask)
apic->send_IPI_mask(cpumask_of(i),
IRQ_MOVE_CLEANUP_VECTOR);
} else {
- cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
+ cpumask_and(cleanup_mask, data->old_domain, cpu_online_mask);
apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
free_cpumask_var(cleanup_mask);
}
- cfg->move_in_progress = 0;
+ data->move_in_progress = 0;
+}
+
+void send_cleanup_vector(struct irq_cfg *cfg)
+{
+ struct apic_chip_data *data;
+
+ data = container_of(cfg, struct apic_chip_data, cfg);
+ if (data->move_in_progress)
+ __send_cleanup_vector(data);
}
asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
{
unsigned vector, me;
- ack_APIC_irq();
- irq_enter();
- exit_idle();
+ entering_ack_irq();
me = smp_processor_id();
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
int irq;
unsigned int irr;
struct irq_desc *desc;
- struct irq_cfg *cfg;
+ struct apic_chip_data *data;
irq = __this_cpu_read(vector_irq[vector]);
@@ -417,8 +560,8 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
if (!desc)
continue;
- cfg = irq_cfg(irq);
- if (!cfg)
+ data = apic_chip_data(&desc->irq_data);
+ if (!data)
continue;
raw_spin_lock(&desc->lock);
@@ -427,10 +570,11 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
* Check if the irq migration is in progress. If so, we
* haven't received the cleanup request yet for this irq.
*/
- if (cfg->move_in_progress)
+ if (data->move_in_progress)
goto unlock;
- if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
+ if (vector == data->cfg.vector &&
+ cpumask_test_cpu(me, data->domain))
goto unlock;
irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
@@ -450,20 +594,21 @@ unlock:
raw_spin_unlock(&desc->lock);
}
- irq_exit();
+ exiting_irq();
}
static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
{
unsigned me;
+ struct apic_chip_data *data;
- if (likely(!cfg->move_in_progress))
+ data = container_of(cfg, struct apic_chip_data, cfg);
+ if (likely(!data->move_in_progress))
return;
me = smp_processor_id();
-
- if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
- send_cleanup_vector(cfg);
+ if (vector == data->cfg.vector && cpumask_test_cpu(me, data->domain))
+ __send_cleanup_vector(data);
}
void irq_complete_move(struct irq_cfg *cfg)
@@ -475,46 +620,11 @@ void irq_force_complete_move(int irq)
{
struct irq_cfg *cfg = irq_cfg(irq);
- if (!cfg)
- return;
-
- __irq_complete_move(cfg, cfg->vector);
+ if (cfg)
+ __irq_complete_move(cfg, cfg->vector);
}
#endif
-/*
- * Dynamic irq allocate and deallocation. Should be replaced by irq domains!
- */
-int arch_setup_hwirq(unsigned int irq, int node)
-{
- struct irq_cfg *cfg;
- unsigned long flags;
- int ret;
-
- cfg = alloc_irq_cfg(irq, node);
- if (!cfg)
- return -ENOMEM;
-
- raw_spin_lock_irqsave(&vector_lock, flags);
- ret = __assign_irq_vector(irq, cfg, apic->target_cpus());
- raw_spin_unlock_irqrestore(&vector_lock, flags);
-
- if (!ret)
- irq_set_chip_data(irq, cfg);
- else
- free_irq_cfg(irq, cfg);
- return ret;
-}
-
-void arch_teardown_hwirq(unsigned int irq)
-{
- struct irq_cfg *cfg = irq_cfg(irq);
-
- free_remapped_irq(irq);
- clear_irq_vector(irq, cfg);
- free_irq_cfg(irq, cfg);
-}
-
static void __init print_APIC_field(int base)
{
int i;
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index 6fae733e9194..3ffd925655e0 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -21,11 +21,13 @@ early_param("x2apic_phys", set_x2apic_phys_mode);
static bool x2apic_fadt_phys(void)
{
+#ifdef CONFIG_ACPI
if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) &&
(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
printk(KERN_DEBUG "System requires x2apic physical mode\n");
return true;
}
+#endif
return false;
}
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
index 9f6b9341950f..8e3d22a1af94 100644
--- a/arch/x86/kernel/asm-offsets.c
+++ b/arch/x86/kernel/asm-offsets.c
@@ -41,6 +41,25 @@ void common(void) {
OFFSET(pbe_orig_address, pbe, orig_address);
OFFSET(pbe_next, pbe, next);
+#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
+ BLANK();
+ OFFSET(IA32_SIGCONTEXT_ax, sigcontext_ia32, ax);
+ OFFSET(IA32_SIGCONTEXT_bx, sigcontext_ia32, bx);
+ OFFSET(IA32_SIGCONTEXT_cx, sigcontext_ia32, cx);
+ OFFSET(IA32_SIGCONTEXT_dx, sigcontext_ia32, dx);
+ OFFSET(IA32_SIGCONTEXT_si, sigcontext_ia32, si);
+ OFFSET(IA32_SIGCONTEXT_di, sigcontext_ia32, di);
+ OFFSET(IA32_SIGCONTEXT_bp, sigcontext_ia32, bp);
+ OFFSET(IA32_SIGCONTEXT_sp, sigcontext_ia32, sp);
+ OFFSET(IA32_SIGCONTEXT_ip, sigcontext_ia32, ip);
+
+ BLANK();
+ OFFSET(TI_sysenter_return, thread_info, sysenter_return);
+
+ BLANK();
+ OFFSET(IA32_RT_SIGFRAME_sigcontext, rt_sigframe_ia32, uc.uc_mcontext);
+#endif
+
#ifdef CONFIG_PARAVIRT
BLANK();
OFFSET(PARAVIRT_enabled, pv_info, paravirt_enabled);
@@ -49,7 +68,9 @@ void common(void) {
OFFSET(PV_IRQ_irq_disable, pv_irq_ops, irq_disable);
OFFSET(PV_IRQ_irq_enable, pv_irq_ops, irq_enable);
OFFSET(PV_CPU_iret, pv_cpu_ops, iret);
+#ifdef CONFIG_X86_32
OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit);
+#endif
OFFSET(PV_CPU_read_cr0, pv_cpu_ops, read_cr0);
OFFSET(PV_MMU_read_cr2, pv_mmu_ops, read_cr2);
#endif
diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c
index 47703aed74cf..6ce39025f467 100644
--- a/arch/x86/kernel/asm-offsets_32.c
+++ b/arch/x86/kernel/asm-offsets_32.c
@@ -17,17 +17,6 @@ void foo(void);
void foo(void)
{
- OFFSET(IA32_SIGCONTEXT_ax, sigcontext, ax);
- OFFSET(IA32_SIGCONTEXT_bx, sigcontext, bx);
- OFFSET(IA32_SIGCONTEXT_cx, sigcontext, cx);
- OFFSET(IA32_SIGCONTEXT_dx, sigcontext, dx);
- OFFSET(IA32_SIGCONTEXT_si, sigcontext, si);
- OFFSET(IA32_SIGCONTEXT_di, sigcontext, di);
- OFFSET(IA32_SIGCONTEXT_bp, sigcontext, bp);
- OFFSET(IA32_SIGCONTEXT_sp, sigcontext, sp);
- OFFSET(IA32_SIGCONTEXT_ip, sigcontext, ip);
- BLANK();
-
OFFSET(CPUINFO_x86, cpuinfo_x86, x86);
OFFSET(CPUINFO_x86_vendor, cpuinfo_x86, x86_vendor);
OFFSET(CPUINFO_x86_model, cpuinfo_x86, x86_model);
@@ -37,10 +26,6 @@ void foo(void)
OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id);
BLANK();
- OFFSET(TI_sysenter_return, thread_info, sysenter_return);
- OFFSET(TI_cpu, thread_info, cpu);
- BLANK();
-
OFFSET(PT_EBX, pt_regs, bx);
OFFSET(PT_ECX, pt_regs, cx);
OFFSET(PT_EDX, pt_regs, dx);
@@ -60,9 +45,6 @@ void foo(void)
OFFSET(PT_OLDSS, pt_regs, ss);
BLANK();
- OFFSET(IA32_RT_SIGFRAME_sigcontext, rt_sigframe, uc.uc_mcontext);
- BLANK();
-
OFFSET(saved_context_gdt_desc, saved_context, gdt_desc);
BLANK();
diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c
index 5ce6f2da8763..d8f42f902a0f 100644
--- a/arch/x86/kernel/asm-offsets_64.c
+++ b/arch/x86/kernel/asm-offsets_64.c
@@ -29,27 +29,6 @@ int main(void)
BLANK();
#endif
-#ifdef CONFIG_IA32_EMULATION
- OFFSET(TI_sysenter_return, thread_info, sysenter_return);
- BLANK();
-
-#define ENTRY(entry) OFFSET(IA32_SIGCONTEXT_ ## entry, sigcontext_ia32, entry)
- ENTRY(ax);
- ENTRY(bx);
- ENTRY(cx);
- ENTRY(dx);
- ENTRY(si);
- ENTRY(di);
- ENTRY(bp);
- ENTRY(sp);
- ENTRY(ip);
- BLANK();
-#undef ENTRY
-
- OFFSET(IA32_RT_SIGFRAME_sigcontext, rt_sigframe_ia32, uc.uc_mcontext);
- BLANK();
-#endif
-
#define ENTRY(entry) OFFSET(pt_regs_ ## entry, pt_regs, entry)
ENTRY(bx);
ENTRY(cx);
@@ -87,7 +66,7 @@ int main(void)
DEFINE(__NR_syscall_max, sizeof(syscalls_64) - 1);
DEFINE(NR_syscalls, sizeof(syscalls_64));
- DEFINE(__NR_ia32_syscall_max, sizeof(syscalls_ia32) - 1);
+ DEFINE(__NR_syscall_compat_max, sizeof(syscalls_ia32) - 1);
DEFINE(IA32_NR_syscalls, sizeof(syscalls_ia32));
return 0;
diff --git a/arch/x86/kernel/check.c b/arch/x86/kernel/check.c
index 83a7995625a6..58118e207a69 100644
--- a/arch/x86/kernel/check.c
+++ b/arch/x86/kernel/check.c
@@ -91,7 +91,8 @@ void __init setup_bios_corruption_check(void)
corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
- for_each_free_mem_range(i, NUMA_NO_NODE, &start, &end, NULL) {
+ for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end,
+ NULL) {
start = clamp_t(phys_addr_t, round_up(start, PAGE_SIZE),
PAGE_SIZE, corruption_check_size);
end = clamp_t(phys_addr_t, round_down(end, PAGE_SIZE),
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index e4cf63301ff4..dd3a4baffe50 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -19,6 +19,13 @@
#include "cpu.h"
+/*
+ * nodes_per_socket: Stores the number of nodes per socket.
+ * Refer to Fam15h Models 00-0fh BKDG - CPUID Fn8000_001E_ECX
+ * Node Identifiers[10:8]
+ */
+static u32 nodes_per_socket = 1;
+
static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
{
u32 gprs[8] = { 0 };
@@ -288,10 +295,10 @@ static int nearby_node(int apicid)
* Assumption: Number of cores in each internal node is the same.
* (2) AMD processors supporting compute units
*/
-#ifdef CONFIG_X86_HT
+#ifdef CONFIG_SMP
static void amd_get_topology(struct cpuinfo_x86 *c)
{
- u32 nodes, cores_per_cu = 1;
+ u32 cores_per_cu = 1;
u8 node_id;
int cpu = smp_processor_id();
@@ -300,7 +307,7 @@ static void amd_get_topology(struct cpuinfo_x86 *c)
u32 eax, ebx, ecx, edx;
cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
- nodes = ((ecx >> 8) & 7) + 1;
+ nodes_per_socket = ((ecx >> 8) & 7) + 1;
node_id = ecx & 7;
/* get compute unit information */
@@ -311,18 +318,18 @@ static void amd_get_topology(struct cpuinfo_x86 *c)
u64 value;
rdmsrl(MSR_FAM10H_NODE_ID, value);
- nodes = ((value >> 3) & 7) + 1;
+ nodes_per_socket = ((value >> 3) & 7) + 1;
node_id = value & 7;
} else
return;
/* fixup multi-node processor information */
- if (nodes > 1) {
+ if (nodes_per_socket > 1) {
u32 cores_per_node;
u32 cus_per_node;
set_cpu_cap(c, X86_FEATURE_AMD_DCM);
- cores_per_node = c->x86_max_cores / nodes;
+ cores_per_node = c->x86_max_cores / nodes_per_socket;
cus_per_node = cores_per_node / cores_per_cu;
/* store NodeID, use llc_shared_map to store sibling info */
@@ -341,7 +348,7 @@ static void amd_get_topology(struct cpuinfo_x86 *c)
*/
static void amd_detect_cmp(struct cpuinfo_x86 *c)
{
-#ifdef CONFIG_X86_HT
+#ifdef CONFIG_SMP
unsigned bits;
int cpu = smp_processor_id();
@@ -366,6 +373,12 @@ u16 amd_get_nb_id(int cpu)
}
EXPORT_SYMBOL_GPL(amd_get_nb_id);
+u32 amd_get_nodes_per_socket(void)
+{
+ return nodes_per_socket;
+}
+EXPORT_SYMBOL_GPL(amd_get_nodes_per_socket);
+
static void srat_detect_node(struct cpuinfo_x86 *c)
{
#ifdef CONFIG_NUMA
@@ -420,7 +433,7 @@ static void srat_detect_node(struct cpuinfo_x86 *c)
static void early_init_amd_mc(struct cpuinfo_x86 *c)
{
-#ifdef CONFIG_X86_HT
+#ifdef CONFIG_SMP
unsigned bits, ecx;
/* Multi core CPU? */
@@ -520,8 +533,16 @@ static void early_init_amd(struct cpuinfo_x86 *c)
set_cpu_cap(c, X86_FEATURE_K6_MTRR);
#endif
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PCI)
- /* check CPU config space for extended APIC ID */
- if (cpu_has_apic && c->x86 >= 0xf) {
+ /*
+ * ApicID can always be treated as an 8-bit value for AMD APIC versions
+ * >= 0x10, but even old K8s came out of reset with version 0x10. So, we
+ * can safely set X86_FEATURE_EXTD_APICID unconditionally for families
+ * after 16h.
+ */
+ if (cpu_has_apic && c->x86 > 0x16) {
+ set_cpu_cap(c, X86_FEATURE_EXTD_APICID);
+ } else if (cpu_has_apic && c->x86 >= 0xf) {
+ /* check CPU config space for extended APIC ID */
unsigned int val;
val = read_pci_config(0, 24, 0, 0x68);
if ((val & ((1 << 17) | (1 << 18))) == ((1 << 17) | (1 << 18)))
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 03445346ee0a..bd17db15a2c1 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -12,57 +12,11 @@
#include <asm/bugs.h>
#include <asm/processor.h>
#include <asm/processor-flags.h>
-#include <asm/i387.h>
+#include <asm/fpu/internal.h>
#include <asm/msr.h>
#include <asm/paravirt.h>
#include <asm/alternative.h>
-static double __initdata x = 4195835.0;
-static double __initdata y = 3145727.0;
-
-/*
- * This used to check for exceptions..
- * However, it turns out that to support that,
- * the XMM trap handlers basically had to
- * be buggy. So let's have a correct XMM trap
- * handler, and forget about printing out
- * some status at boot.
- *
- * We should really only care about bugs here
- * anyway. Not features.
- */
-static void __init check_fpu(void)
-{
- s32 fdiv_bug;
-
- kernel_fpu_begin();
-
- /*
- * trap_init() enabled FXSR and company _before_ testing for FP
- * problems here.
- *
- * Test for the divl bug: http://en.wikipedia.org/wiki/Fdiv_bug
- */
- __asm__("fninit\n\t"
- "fldl %1\n\t"
- "fdivl %2\n\t"
- "fmull %2\n\t"
- "fldl %1\n\t"
- "fsubp %%st,%%st(1)\n\t"
- "fistpl %0\n\t"
- "fwait\n\t"
- "fninit"
- : "=m" (*&fdiv_bug)
- : "m" (*&x), "m" (*&y));
-
- kernel_fpu_end();
-
- if (fdiv_bug) {
- set_cpu_bug(&boot_cpu_data, X86_BUG_FDIV);
- pr_warn("Hmm, FPU with FDIV bug\n");
- }
-}
-
void __init check_bugs(void)
{
identify_boot_cpu();
@@ -85,10 +39,5 @@ void __init check_bugs(void)
'0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
alternative_instructions();
- /*
- * kernel_fpu_begin/end() in check_fpu() relies on the patched
- * alternative instructions.
- */
- if (cpu_has_fpu)
- check_fpu();
+ fpu__init_check_bugs();
}
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index a62cf04dac8a..9fc5e3d9d9c8 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -5,6 +5,7 @@
#include <linux/module.h>
#include <linux/percpu.h>
#include <linux/string.h>
+#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/init.h>
@@ -31,8 +32,7 @@
#include <asm/setup.h>
#include <asm/apic.h>
#include <asm/desc.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h>
+#include <asm/fpu/internal.h>
#include <asm/mtrr.h>
#include <linux/numa.h>
#include <asm/asm.h>
@@ -145,32 +145,21 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = {
} };
EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
-static int __init x86_xsave_setup(char *s)
+static int __init x86_mpx_setup(char *s)
{
+ /* require an exact match without trailing characters */
if (strlen(s))
return 0;
- setup_clear_cpu_cap(X86_FEATURE_XSAVE);
- setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
- setup_clear_cpu_cap(X86_FEATURE_XSAVES);
- setup_clear_cpu_cap(X86_FEATURE_AVX);
- setup_clear_cpu_cap(X86_FEATURE_AVX2);
- return 1;
-}
-__setup("noxsave", x86_xsave_setup);
-static int __init x86_xsaveopt_setup(char *s)
-{
- setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
- return 1;
-}
-__setup("noxsaveopt", x86_xsaveopt_setup);
+ /* do not emit a message if the feature is not present */
+ if (!boot_cpu_has(X86_FEATURE_MPX))
+ return 1;
-static int __init x86_xsaves_setup(char *s)
-{
- setup_clear_cpu_cap(X86_FEATURE_XSAVES);
+ setup_clear_cpu_cap(X86_FEATURE_MPX);
+ pr_info("nompx: Intel Memory Protection Extensions (MPX) disabled\n");
return 1;
}
-__setup("noxsaves", x86_xsaves_setup);
+__setup("nompx", x86_mpx_setup);
#ifdef CONFIG_X86_32
static int cachesize_override = -1;
@@ -183,14 +172,6 @@ static int __init cachesize_setup(char *str)
}
__setup("cachesize=", cachesize_setup);
-static int __init x86_fxsr_setup(char *s)
-{
- setup_clear_cpu_cap(X86_FEATURE_FXSR);
- setup_clear_cpu_cap(X86_FEATURE_XMM);
- return 1;
-}
-__setup("nofxsr", x86_fxsr_setup);
-
static int __init x86_sep_setup(char *s)
{
setup_clear_cpu_cap(X86_FEATURE_SEP);
@@ -419,7 +400,7 @@ static const struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
static void get_model_name(struct cpuinfo_x86 *c)
{
unsigned int *v;
- char *p, *q;
+ char *p, *q, *s;
if (c->extended_cpuid_level < 0x80000004)
return;
@@ -430,19 +411,21 @@ static void get_model_name(struct cpuinfo_x86 *c)
cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
c->x86_model_id[48] = 0;
- /*
- * Intel chips right-justify this string for some dumb reason;
- * undo that brain damage:
- */
- p = q = &c->x86_model_id[0];
+ /* Trim whitespace */
+ p = q = s = &c->x86_model_id[0];
+
while (*p == ' ')
p++;
- if (p != q) {
- while (*p)
- *q++ = *p++;
- while (q <= &c->x86_model_id[48])
- *q++ = '\0'; /* Zero-pad the rest */
+
+ while (*p) {
+ /* Note the last non-whitespace index */
+ if (!isspace(*p))
+ s = q;
+
+ *q++ = *p++;
}
+
+ *(s + 1) = '\0';
}
void cpu_detect_cache_sizes(struct cpuinfo_x86 *c)
@@ -508,7 +491,7 @@ static void cpu_detect_tlb(struct cpuinfo_x86 *c)
void detect_ht(struct cpuinfo_x86 *c)
{
-#ifdef CONFIG_X86_HT
+#ifdef CONFIG_SMP
u32 eax, ebx, ecx, edx;
int index_msb, core_bits;
static bool printed;
@@ -759,7 +742,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
cpu_detect(c);
get_cpu_vendor(c);
get_cpu_cap(c);
- fpu_detect(c);
+ fpu__init_system(c);
if (this_cpu->c_early_init)
this_cpu->c_early_init(c);
@@ -844,7 +827,7 @@ static void generic_identify(struct cpuinfo_x86 *c)
if (c->cpuid_level >= 0x00000001) {
c->initial_apicid = (cpuid_ebx(1) >> 24) & 0xFF;
#ifdef CONFIG_X86_32
-# ifdef CONFIG_X86_HT
+# ifdef CONFIG_SMP
c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
# else
c->apicid = c->initial_apicid;
@@ -1026,7 +1009,7 @@ void enable_sep_cpu(void)
(unsigned long)tss + offsetofend(struct tss_struct, SYSENTER_stack),
0);
- wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long)ia32_sysenter_target, 0);
+ wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long)entry_SYSENTER_32, 0);
out:
put_cpu();
@@ -1122,7 +1105,7 @@ void print_cpu_info(struct cpuinfo_x86 *c)
printk(KERN_CONT "%s ", vendor);
if (c->x86_model_id[0])
- printk(KERN_CONT "%s", strim(c->x86_model_id));
+ printk(KERN_CONT "%s", c->x86_model_id);
else
printk(KERN_CONT "%d86", c->x86);
@@ -1155,10 +1138,6 @@ static __init int setup_disablecpuid(char *arg)
}
__setup("clearcpuid=", setup_disablecpuid);
-DEFINE_PER_CPU(unsigned long, kernel_stack) =
- (unsigned long)&init_thread_union + THREAD_SIZE;
-EXPORT_PER_CPU_SYMBOL(kernel_stack);
-
#ifdef CONFIG_X86_64
struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table };
struct desc_ptr debug_idt_descr = { NR_VECTORS * 16 - 1,
@@ -1183,8 +1162,6 @@ DEFINE_PER_CPU(unsigned int, irq_count) __visible = -1;
DEFINE_PER_CPU(int, __preempt_count) = INIT_PREEMPT_COUNT;
EXPORT_PER_CPU_SYMBOL(__preempt_count);
-DEFINE_PER_CPU(struct task_struct *, fpu_owner_task);
-
/*
* Special IST stacks which the CPU switches to when it calls
* an IST-marked descriptor entry. Up to 7 stacks (hardware
@@ -1208,10 +1185,10 @@ void syscall_init(void)
* set CS/DS but only a 32bit target. LSTAR sets the 64bit rip.
*/
wrmsrl(MSR_STAR, ((u64)__USER32_CS)<<48 | ((u64)__KERNEL_CS)<<32);
- wrmsrl(MSR_LSTAR, system_call);
+ wrmsrl(MSR_LSTAR, entry_SYSCALL_64);
#ifdef CONFIG_IA32_EMULATION
- wrmsrl(MSR_CSTAR, ia32_cstar_target);
+ wrmsrl(MSR_CSTAR, entry_SYSCALL_compat);
/*
* This only works on Intel CPUs.
* On AMD CPUs these MSRs are 32-bit, CPU truncates MSR_IA32_SYSENTER_EIP.
@@ -1220,7 +1197,7 @@ void syscall_init(void)
*/
wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL);
- wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target);
+ wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)entry_SYSENTER_compat);
#else
wrmsrl(MSR_CSTAR, ignore_sysret);
wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)GDT_ENTRY_INVALID_SEG);
@@ -1275,7 +1252,6 @@ DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
EXPORT_PER_CPU_SYMBOL(current_task);
DEFINE_PER_CPU(int, __preempt_count) = INIT_PREEMPT_COUNT;
EXPORT_PER_CPU_SYMBOL(__preempt_count);
-DEFINE_PER_CPU(struct task_struct *, fpu_owner_task);
/*
* On x86_32, vm86 modifies tss.sp0, so sp0 isn't a reliable way to find
@@ -1439,7 +1415,7 @@ void cpu_init(void)
clear_all_debug_regs();
dbg_restore_debug_regs();
- fpu_init();
+ fpu__init_cpu();
if (is_uv_system())
uv_cpu_init();
@@ -1495,7 +1471,7 @@ void cpu_init(void)
clear_all_debug_regs();
dbg_restore_debug_regs();
- fpu_init();
+ fpu__init_cpu();
}
#endif
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index edcb0e28c336..be4febc58b94 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -654,7 +654,7 @@ unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb;
-#ifdef CONFIG_X86_HT
+#ifdef CONFIG_SMP
unsigned int cpu = c->cpu_index;
#endif
@@ -773,19 +773,19 @@ unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
if (new_l2) {
l2 = new_l2;
-#ifdef CONFIG_X86_HT
+#ifdef CONFIG_SMP
per_cpu(cpu_llc_id, cpu) = l2_id;
#endif
}
if (new_l3) {
l3 = new_l3;
-#ifdef CONFIG_X86_HT
+#ifdef CONFIG_SMP
per_cpu(cpu_llc_id, cpu) = l3_id;
#endif
}
-#ifdef CONFIG_X86_HT
+#ifdef CONFIG_SMP
/*
* If cpu_llc_id is not yet set, this means cpuid_level < 4 which in
* turns means that the only possibility is SMT (as indicated in
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 20190bdac9d5..df919ff103c3 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -53,9 +53,12 @@
static DEFINE_MUTEX(mce_chrdev_read_mutex);
#define rcu_dereference_check_mce(p) \
- rcu_dereference_index_check((p), \
- rcu_read_lock_sched_held() || \
- lockdep_is_held(&mce_chrdev_read_mutex))
+({ \
+ rcu_lockdep_assert(rcu_read_lock_sched_held() || \
+ lockdep_is_held(&mce_chrdev_read_mutex), \
+ "suspicious rcu_dereference_check_mce() usage"); \
+ smp_load_acquire(&(p)); \
+})
#define CREATE_TRACE_POINTS
#include <trace/events/mce.h>
@@ -1050,6 +1053,7 @@ void do_machine_check(struct pt_regs *regs, long error_code)
char *msg = "Unknown";
u64 recover_paddr = ~0ull;
int flags = MF_ACTION_REQUIRED;
+ int lmce = 0;
prev_state = ist_enter(regs);
@@ -1077,11 +1081,20 @@ void do_machine_check(struct pt_regs *regs, long error_code)
kill_it = 1;
/*
- * Go through all the banks in exclusion of the other CPUs.
- * This way we don't report duplicated events on shared banks
- * because the first one to see it will clear it.
+ * Check if this MCE is signaled to only this logical processor
*/
- order = mce_start(&no_way_out);
+ if (m.mcgstatus & MCG_STATUS_LMCES)
+ lmce = 1;
+ else {
+ /*
+ * Go through all the banks in exclusion of the other CPUs.
+ * This way we don't report duplicated events on shared banks
+ * because the first one to see it will clear it.
+ * If this is a Local MCE, then no need to perform rendezvous.
+ */
+ order = mce_start(&no_way_out);
+ }
+
for (i = 0; i < cfg->banks; i++) {
__clear_bit(i, toclear);
if (!test_bit(i, valid_banks))
@@ -1158,8 +1171,18 @@ void do_machine_check(struct pt_regs *regs, long error_code)
* Do most of the synchronization with other CPUs.
* When there's any problem use only local no_way_out state.
*/
- if (mce_end(order) < 0)
- no_way_out = worst >= MCE_PANIC_SEVERITY;
+ if (!lmce) {
+ if (mce_end(order) < 0)
+ no_way_out = worst >= MCE_PANIC_SEVERITY;
+ } else {
+ /*
+ * Local MCE skipped calling mce_reign()
+ * If we found a fatal error, we need to panic here.
+ */
+ if (worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3)
+ mce_panic("Machine check from unknown source",
+ NULL, NULL);
+ }
/*
* At insane "tolerant" levels we take no action. Otherwise
@@ -1640,10 +1663,16 @@ static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c)
mce_intel_feature_init(c);
mce_adjust_timer = cmci_intel_adjust_timer;
break;
- case X86_VENDOR_AMD:
+
+ case X86_VENDOR_AMD: {
+ u32 ebx = cpuid_ebx(0x80000007);
+
mce_amd_feature_init(c);
- mce_flags.overflow_recov = cpuid_ebx(0x80000007) & 0x1;
+ mce_flags.overflow_recov = !!(ebx & BIT(0));
+ mce_flags.succor = !!(ebx & BIT(1));
break;
+ }
+
default:
break;
}
@@ -1887,7 +1916,7 @@ out:
static unsigned int mce_chrdev_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &mce_chrdev_wait, wait);
- if (rcu_access_index(mcelog.next))
+ if (READ_ONCE(mcelog.next))
return POLLIN | POLLRDNORM;
if (!mce_apei_read_done && apei_check_mce())
return POLLIN | POLLRDNORM;
@@ -1932,8 +1961,8 @@ void register_mce_write_callback(ssize_t (*fn)(struct file *filp,
}
EXPORT_SYMBOL_GPL(register_mce_write_callback);
-ssize_t mce_chrdev_write(struct file *filp, const char __user *ubuf,
- size_t usize, loff_t *off)
+static ssize_t mce_chrdev_write(struct file *filp, const char __user *ubuf,
+ size_t usize, loff_t *off)
{
if (mce_write)
return mce_write(filp, ubuf, usize, off);
@@ -1979,6 +2008,7 @@ void mce_disable_bank(int bank)
/*
* mce=off Disables machine check
* mce=no_cmci Disables CMCI
+ * mce=no_lmce Disables LMCE
* mce=dont_log_ce Clears corrected events silently, no log created for CEs.
* mce=ignore_ce Disables polling and CMCI, corrected events are not cleared.
* mce=TOLERANCELEVEL[,monarchtimeout] (number, see above)
@@ -2002,6 +2032,8 @@ static int __init mcheck_enable(char *str)
cfg->disabled = true;
else if (!strcmp(str, "no_cmci"))
cfg->cmci_disabled = true;
+ else if (!strcmp(str, "no_lmce"))
+ cfg->lmce_disabled = true;
else if (!strcmp(str, "dont_log_ce"))
cfg->dont_log_ce = true;
else if (!strcmp(str, "ignore_ce"))
@@ -2011,11 +2043,8 @@ static int __init mcheck_enable(char *str)
else if (!strcmp(str, "bios_cmci_threshold"))
cfg->bios_cmci_threshold = true;
else if (isdigit(str[0])) {
- get_option(&str, &(cfg->tolerant));
- if (*str == ',') {
- ++str;
+ if (get_option(&str, &cfg->tolerant) == 2)
get_option(&str, &(cfg->monarch_timeout));
- }
} else {
pr_info("mce argument %s ignored. Please use /sys\n", str);
return 0;
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index 55ad9b37cae8..e99b15077e94 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -1,19 +1,13 @@
/*
- * (c) 2005-2012 Advanced Micro Devices, Inc.
+ * (c) 2005-2015 Advanced Micro Devices, Inc.
* Your use of this code is subject to the terms and conditions of the
* GNU general public license version 2. See "COPYING" or
* http://www.gnu.org/licenses/gpl.html
*
* Written by Jacob Shin - AMD, Inc.
- *
* Maintained by: Borislav Petkov <bp@alien8.de>
*
- * April 2006
- * - added support for AMD Family 0x10 processors
- * May 2012
- * - major scrubbing
- *
- * All MC4_MISCi registers are shared between multi-cores
+ * All MC4_MISCi registers are shared between cores on a node.
*/
#include <linux/interrupt.h>
#include <linux/notifier.h>
@@ -32,6 +26,7 @@
#include <asm/idle.h>
#include <asm/mce.h>
#include <asm/msr.h>
+#include <asm/trace/irq_vectors.h>
#define NR_BLOCKS 9
#define THRESHOLD_MAX 0xFFF
@@ -47,6 +42,13 @@
#define MASK_BLKPTR_LO 0xFF000000
#define MCG_XBLK_ADDR 0xC0000400
+/* Deferred error settings */
+#define MSR_CU_DEF_ERR 0xC0000410
+#define MASK_DEF_LVTOFF 0x000000F0
+#define MASK_DEF_INT_TYPE 0x00000006
+#define DEF_LVT_OFF 0x2
+#define DEF_INT_TYPE_APIC 0x2
+
static const char * const th_names[] = {
"load_store",
"insn_fetch",
@@ -60,6 +62,13 @@ static DEFINE_PER_CPU(struct threshold_bank **, threshold_banks);
static DEFINE_PER_CPU(unsigned char, bank_map); /* see which banks are on */
static void amd_threshold_interrupt(void);
+static void amd_deferred_error_interrupt(void);
+
+static void default_deferred_error_interrupt(void)
+{
+ pr_err("Unexpected deferred interrupt at vector %x\n", DEFERRED_ERROR_VECTOR);
+}
+void (*deferred_error_int_vector)(void) = default_deferred_error_interrupt;
/*
* CPU Initialization
@@ -196,7 +205,7 @@ static void mce_threshold_block_init(struct threshold_block *b, int offset)
threshold_restart_bank(&tr);
};
-static int setup_APIC_mce(int reserved, int new)
+static int setup_APIC_mce_threshold(int reserved, int new)
{
if (reserved < 0 && !setup_APIC_eilvt(new, THRESHOLD_APIC_VECTOR,
APIC_EILVT_MSG_FIX, 0))
@@ -205,6 +214,39 @@ static int setup_APIC_mce(int reserved, int new)
return reserved;
}
+static int setup_APIC_deferred_error(int reserved, int new)
+{
+ if (reserved < 0 && !setup_APIC_eilvt(new, DEFERRED_ERROR_VECTOR,
+ APIC_EILVT_MSG_FIX, 0))
+ return new;
+
+ return reserved;
+}
+
+static void deferred_error_interrupt_enable(struct cpuinfo_x86 *c)
+{
+ u32 low = 0, high = 0;
+ int def_offset = -1, def_new;
+
+ if (rdmsr_safe(MSR_CU_DEF_ERR, &low, &high))
+ return;
+
+ def_new = (low & MASK_DEF_LVTOFF) >> 4;
+ if (!(low & MASK_DEF_LVTOFF)) {
+ pr_err(FW_BUG "Your BIOS is not setting up LVT offset 0x2 for deferred error IRQs correctly.\n");
+ def_new = DEF_LVT_OFF;
+ low = (low & ~MASK_DEF_LVTOFF) | (DEF_LVT_OFF << 4);
+ }
+
+ def_offset = setup_APIC_deferred_error(def_offset, def_new);
+ if ((def_offset == def_new) &&
+ (deferred_error_int_vector != amd_deferred_error_interrupt))
+ deferred_error_int_vector = amd_deferred_error_interrupt;
+
+ low = (low & ~MASK_DEF_INT_TYPE) | DEF_INT_TYPE_APIC;
+ wrmsr(MSR_CU_DEF_ERR, low, high);
+}
+
/* cpu init entry point, called from mce.c with preempt off */
void mce_amd_feature_init(struct cpuinfo_x86 *c)
{
@@ -252,7 +294,7 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
b.interrupt_enable = 1;
new = (high & MASK_LVTOFF_HI) >> 20;
- offset = setup_APIC_mce(offset, new);
+ offset = setup_APIC_mce_threshold(offset, new);
if ((offset == new) &&
(mce_threshold_vector != amd_threshold_interrupt))
@@ -262,6 +304,73 @@ init:
mce_threshold_block_init(&b, offset);
}
}
+
+ if (mce_flags.succor)
+ deferred_error_interrupt_enable(c);
+}
+
+static void __log_error(unsigned int bank, bool threshold_err, u64 misc)
+{
+ struct mce m;
+ u64 status;
+
+ rdmsrl(MSR_IA32_MCx_STATUS(bank), status);
+ if (!(status & MCI_STATUS_VAL))
+ return;
+
+ mce_setup(&m);
+
+ m.status = status;
+ m.bank = bank;
+
+ if (threshold_err)
+ m.misc = misc;
+
+ if (m.status & MCI_STATUS_ADDRV)
+ rdmsrl(MSR_IA32_MCx_ADDR(bank), m.addr);
+
+ mce_log(&m);
+ wrmsrl(MSR_IA32_MCx_STATUS(bank), 0);
+}
+
+static inline void __smp_deferred_error_interrupt(void)
+{
+ inc_irq_stat(irq_deferred_error_count);
+ deferred_error_int_vector();
+}
+
+asmlinkage __visible void smp_deferred_error_interrupt(void)
+{
+ entering_irq();
+ __smp_deferred_error_interrupt();
+ exiting_ack_irq();
+}
+
+asmlinkage __visible void smp_trace_deferred_error_interrupt(void)
+{
+ entering_irq();
+ trace_deferred_error_apic_entry(DEFERRED_ERROR_VECTOR);
+ __smp_deferred_error_interrupt();
+ trace_deferred_error_apic_exit(DEFERRED_ERROR_VECTOR);
+ exiting_ack_irq();
+}
+
+/* APIC interrupt handler for deferred errors */
+static void amd_deferred_error_interrupt(void)
+{
+ u64 status;
+ unsigned int bank;
+
+ for (bank = 0; bank < mca_cfg.banks; ++bank) {
+ rdmsrl(MSR_IA32_MCx_STATUS(bank), status);
+
+ if (!(status & MCI_STATUS_VAL) ||
+ !(status & MCI_STATUS_DEFERRED))
+ continue;
+
+ __log_error(bank, false, 0);
+ break;
+ }
}
/*
@@ -273,12 +382,12 @@ init:
* the interrupt goes off when error_count reaches threshold_limit.
* the handler will simply log mcelog w/ software defined bank number.
*/
+
static void amd_threshold_interrupt(void)
{
u32 low = 0, high = 0, address = 0;
int cpu = smp_processor_id();
unsigned int bank, block;
- struct mce m;
/* assume first bank caused it */
for (bank = 0; bank < mca_cfg.banks; ++bank) {
@@ -321,15 +430,7 @@ static void amd_threshold_interrupt(void)
return;
log:
- mce_setup(&m);
- rdmsrl(MSR_IA32_MCx_STATUS(bank), m.status);
- if (!(m.status & MCI_STATUS_VAL))
- return;
- m.misc = ((u64)high << 32) | low;
- m.bank = bank;
- mce_log(&m);
-
- wrmsrl(MSR_IA32_MCx_STATUS(bank), 0);
+ __log_error(bank, true, ((u64)high << 32) | low);
}
/*
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c
index b4a41cf030ed..844f56c5616d 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_intel.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c
@@ -91,6 +91,36 @@ static int cmci_supported(int *banks)
return !!(cap & MCG_CMCI_P);
}
+static bool lmce_supported(void)
+{
+ u64 tmp;
+
+ if (mca_cfg.lmce_disabled)
+ return false;
+
+ rdmsrl(MSR_IA32_MCG_CAP, tmp);
+
+ /*
+ * LMCE depends on recovery support in the processor. Hence both
+ * MCG_SER_P and MCG_LMCE_P should be present in MCG_CAP.
+ */
+ if ((tmp & (MCG_SER_P | MCG_LMCE_P)) !=
+ (MCG_SER_P | MCG_LMCE_P))
+ return false;
+
+ /*
+ * BIOS should indicate support for LMCE by setting bit 20 in
+ * IA32_FEATURE_CONTROL without which touching MCG_EXT_CTL will
+ * generate a #GP fault.
+ */
+ rdmsrl(MSR_IA32_FEATURE_CONTROL, tmp);
+ if ((tmp & (FEATURE_CONTROL_LOCKED | FEATURE_CONTROL_LMCE)) ==
+ (FEATURE_CONTROL_LOCKED | FEATURE_CONTROL_LMCE))
+ return true;
+
+ return false;
+}
+
bool mce_intel_cmci_poll(void)
{
if (__this_cpu_read(cmci_storm_state) == CMCI_STORM_NONE)
@@ -405,8 +435,22 @@ static void intel_init_cmci(void)
cmci_recheck();
}
+void intel_init_lmce(void)
+{
+ u64 val;
+
+ if (!lmce_supported())
+ return;
+
+ rdmsrl(MSR_IA32_MCG_EXT_CTL, val);
+
+ if (!(val & MCG_EXT_CTL_LMCE_EN))
+ wrmsrl(MSR_IA32_MCG_EXT_CTL, val | MCG_EXT_CTL_LMCE_EN);
+}
+
void mce_intel_feature_init(struct cpuinfo_x86 *c)
{
intel_init_thermal(c);
intel_init_cmci();
+ intel_init_lmce();
}
diff --git a/arch/x86/kernel/cpu/microcode/amd_early.c b/arch/x86/kernel/cpu/microcode/amd_early.c
index 737737edbd1e..e8a215a9a345 100644
--- a/arch/x86/kernel/cpu/microcode/amd_early.c
+++ b/arch/x86/kernel/cpu/microcode/amd_early.c
@@ -228,7 +228,23 @@ static void apply_ucode_in_initrd(void *ucode, size_t size, bool save_patch)
}
}
-void __init load_ucode_amd_bsp(void)
+static bool __init load_builtin_amd_microcode(struct cpio_data *cp,
+ unsigned int family)
+{
+#ifdef CONFIG_X86_64
+ char fw_name[36] = "amd-ucode/microcode_amd.bin";
+
+ if (family >= 0x15)
+ snprintf(fw_name, sizeof(fw_name),
+ "amd-ucode/microcode_amd_fam%.2xh.bin", family);
+
+ return get_builtin_firmware(cp, fw_name);
+#else
+ return false;
+#endif
+}
+
+void __init load_ucode_amd_bsp(unsigned int family)
{
struct cpio_data cp;
void **data;
@@ -243,8 +259,10 @@ void __init load_ucode_amd_bsp(void)
#endif
cp = find_ucode_in_initrd();
- if (!cp.data)
- return;
+ if (!cp.data) {
+ if (!load_builtin_amd_microcode(&cp, family))
+ return;
+ }
*data = cp.data;
*size = cp.size;
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 36a83617eb21..6236a54a63f4 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -1,74 +1,16 @@
/*
- * Intel CPU Microcode Update Driver for Linux
+ * CPU Microcode Update Driver for Linux
*
- * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
- * 2006 Shaohua Li <shaohua.li@intel.com>
+ * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ * 2006 Shaohua Li <shaohua.li@intel.com>
+ * 2013-2015 Borislav Petkov <bp@alien8.de>
*
- * This driver allows to upgrade microcode on Intel processors
- * belonging to IA-32 family - PentiumPro, Pentium II,
- * Pentium III, Xeon, Pentium 4, etc.
+ * This driver allows to upgrade microcode on x86 processors.
*
- * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
- * Software Developer's Manual
- * Order Number 253668 or free download from:
- *
- * http://developer.intel.com/Assets/PDF/manual/253668.pdf
- *
- * For more information, go to http://www.urbanmyth.org/microcode
- *
- * 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.
- *
- * 1.0 16 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Initial release.
- * 1.01 18 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Added read() support + cleanups.
- * 1.02 21 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Added 'device trimming' support. open(O_WRONLY) zeroes
- * and frees the saved copy of applied microcode.
- * 1.03 29 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Made to use devfs (/dev/cpu/microcode) + cleanups.
- * 1.04 06 Jun 2000, Simon Trimmer <simon@veritas.com>
- * Added misc device support (now uses both devfs and misc).
- * Added MICROCODE_IOCFREE ioctl to clear memory.
- * 1.05 09 Jun 2000, Simon Trimmer <simon@veritas.com>
- * Messages for error cases (non Intel & no suitable microcode).
- * 1.06 03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
- * Removed ->release(). Removed exclusive open and status bitmap.
- * Added microcode_rwsem to serialize read()/write()/ioctl().
- * Removed global kernel lock usage.
- * 1.07 07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
- * Write 0 to 0x8B msr and then cpuid before reading revision,
- * so that it works even if there were no update done by the
- * BIOS. Otherwise, reading from 0x8B gives junk (which happened
- * to be 0 on my machine which is why it worked even when I
- * disabled update by the BIOS)
- * Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
- * 1.08 11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
- * Tigran Aivazian <tigran@veritas.com>
- * Intel Pentium 4 processor support and bugfixes.
- * 1.09 30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
- * Bugfix for HT (Hyper-Threading) enabled processors
- * whereby processor resources are shared by all logical processors
- * in a single CPU package.
- * 1.10 28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
- * Tigran Aivazian <tigran@veritas.com>,
- * Serialize updates as required on HT processors due to
- * speculative nature of implementation.
- * 1.11 22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
- * Fix the panic when writing zero-length microcode chunk.
- * 1.12 29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
- * Jun Nakajima <jun.nakajima@intel.com>
- * Support for the microcode updates in the new format.
- * 1.13 10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
- * Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
- * because we no longer hold a copy of applied microcode
- * in kernel memory.
- * 1.14 25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
- * Fix sigmatch() macro to handle old CPUs with pf == 0.
- * Thanks to Stuart Swales for pointing out this bug.
+ * 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/arch/x86/kernel/cpu/microcode/core_early.c b/arch/x86/kernel/cpu/microcode/core_early.c
index a413a69cbd74..8ebc421d6299 100644
--- a/arch/x86/kernel/cpu/microcode/core_early.c
+++ b/arch/x86/kernel/cpu/microcode/core_early.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com>
* H Peter Anvin" <hpa@zytor.com>
+ * (C) 2015 Borislav Petkov <bp@alien8.de>
*
* This driver allows to early upgrade microcode on Intel processors
* belonging to IA-32 family - PentiumPro, Pentium II,
@@ -17,6 +18,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include <linux/module.h>
+#include <linux/firmware.h>
#include <asm/microcode.h>
#include <asm/microcode_intel.h>
#include <asm/microcode_amd.h>
@@ -43,9 +45,29 @@ static bool __init check_loader_disabled_bsp(void)
return *res;
}
+extern struct builtin_fw __start_builtin_fw[];
+extern struct builtin_fw __end_builtin_fw[];
+
+bool get_builtin_firmware(struct cpio_data *cd, const char *name)
+{
+#ifdef CONFIG_FW_LOADER
+ struct builtin_fw *b_fw;
+
+ for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) {
+ if (!strcmp(name, b_fw->name)) {
+ cd->size = b_fw->size;
+ cd->data = b_fw->data;
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
void __init load_ucode_bsp(void)
{
- int vendor, family;
+ int vendor;
+ unsigned int family;
if (check_loader_disabled_bsp())
return;
@@ -63,7 +85,7 @@ void __init load_ucode_bsp(void)
break;
case X86_VENDOR_AMD:
if (family >= 0x10)
- load_ucode_amd_bsp();
+ load_ucode_amd_bsp(family);
break;
default:
break;
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index a41beadb3db9..969dc17eb1b4 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -1,74 +1,13 @@
/*
- * Intel CPU Microcode Update Driver for Linux
+ * Intel CPU Microcode Update Driver for Linux
*
- * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
- * 2006 Shaohua Li <shaohua.li@intel.com>
+ * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ * 2006 Shaohua Li <shaohua.li@intel.com>
*
- * This driver allows to upgrade microcode on Intel processors
- * belonging to IA-32 family - PentiumPro, Pentium II,
- * Pentium III, Xeon, Pentium 4, etc.
- *
- * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
- * Software Developer's Manual
- * Order Number 253668 or free download from:
- *
- * http://developer.intel.com/Assets/PDF/manual/253668.pdf
- *
- * For more information, go to http://www.urbanmyth.org/microcode
- *
- * 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.
- *
- * 1.0 16 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Initial release.
- * 1.01 18 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Added read() support + cleanups.
- * 1.02 21 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Added 'device trimming' support. open(O_WRONLY) zeroes
- * and frees the saved copy of applied microcode.
- * 1.03 29 Feb 2000, Tigran Aivazian <tigran@sco.com>
- * Made to use devfs (/dev/cpu/microcode) + cleanups.
- * 1.04 06 Jun 2000, Simon Trimmer <simon@veritas.com>
- * Added misc device support (now uses both devfs and misc).
- * Added MICROCODE_IOCFREE ioctl to clear memory.
- * 1.05 09 Jun 2000, Simon Trimmer <simon@veritas.com>
- * Messages for error cases (non Intel & no suitable microcode).
- * 1.06 03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
- * Removed ->release(). Removed exclusive open and status bitmap.
- * Added microcode_rwsem to serialize read()/write()/ioctl().
- * Removed global kernel lock usage.
- * 1.07 07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
- * Write 0 to 0x8B msr and then cpuid before reading revision,
- * so that it works even if there were no update done by the
- * BIOS. Otherwise, reading from 0x8B gives junk (which happened
- * to be 0 on my machine which is why it worked even when I
- * disabled update by the BIOS)
- * Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
- * 1.08 11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
- * Tigran Aivazian <tigran@veritas.com>
- * Intel Pentium 4 processor support and bugfixes.
- * 1.09 30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
- * Bugfix for HT (Hyper-Threading) enabled processors
- * whereby processor resources are shared by all logical processors
- * in a single CPU package.
- * 1.10 28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
- * Tigran Aivazian <tigran@veritas.com>,
- * Serialize updates as required on HT processors due to
- * speculative nature of implementation.
- * 1.11 22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
- * Fix the panic when writing zero-length microcode chunk.
- * 1.12 29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
- * Jun Nakajima <jun.nakajima@intel.com>
- * Support for the microcode updates in the new format.
- * 1.13 10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
- * Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
- * because we no longer hold a copy of applied microcode
- * in kernel memory.
- * 1.14 25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
- * Fix sigmatch() macro to handle old CPUs with pf == 0.
- * Thanks to Stuart Swales for pointing out this bug.
+ * 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -124,7 +63,7 @@ static int get_matching_mc(struct microcode_intel *mc_intel, int cpu)
cpf = cpu_sig.pf;
crev = cpu_sig.rev;
- return get_matching_microcode(csig, cpf, crev, mc_intel);
+ return has_newer_microcode(mc_intel, csig, cpf, crev);
}
static int apply_microcode_intel(int cpu)
@@ -226,7 +165,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
csig = uci->cpu_sig.sig;
cpf = uci->cpu_sig.pf;
- if (get_matching_microcode(csig, cpf, new_rev, mc)) {
+ if (has_newer_microcode(mc, csig, cpf, new_rev)) {
vfree(new_mc);
new_rev = mc_header.rev;
new_mc = mc;
diff --git a/arch/x86/kernel/cpu/microcode/intel_early.c b/arch/x86/kernel/cpu/microcode/intel_early.c
index 2f49ab4ac0ae..8187b7247d1c 100644
--- a/arch/x86/kernel/cpu/microcode/intel_early.c
+++ b/arch/x86/kernel/cpu/microcode/intel_early.c
@@ -59,10 +59,10 @@ load_microcode_early(struct microcode_intel **saved,
ucode_ptr = saved[i];
mc_hdr = (struct microcode_header_intel *)ucode_ptr;
- ret = get_matching_microcode(uci->cpu_sig.sig,
- uci->cpu_sig.pf,
- new_rev,
- ucode_ptr);
+ ret = has_newer_microcode(ucode_ptr,
+ uci->cpu_sig.sig,
+ uci->cpu_sig.pf,
+ new_rev);
if (!ret)
continue;
@@ -246,7 +246,7 @@ static unsigned int _save_mc(struct microcode_intel **mc_saved,
u8 *ucode_ptr, unsigned int num_saved)
{
struct microcode_header_intel *mc_hdr, *mc_saved_hdr;
- unsigned int sig, pf, new_rev;
+ unsigned int sig, pf;
int found = 0, i;
mc_hdr = (struct microcode_header_intel *)ucode_ptr;
@@ -255,14 +255,13 @@ static unsigned int _save_mc(struct microcode_intel **mc_saved,
mc_saved_hdr = (struct microcode_header_intel *)mc_saved[i];
sig = mc_saved_hdr->sig;
pf = mc_saved_hdr->pf;
- new_rev = mc_hdr->rev;
- if (!get_matching_sig(sig, pf, new_rev, ucode_ptr))
+ if (!find_matching_signature(ucode_ptr, sig, pf))
continue;
found = 1;
- if (!revision_is_newer(mc_hdr, new_rev))
+ if (mc_hdr->rev <= mc_saved_hdr->rev)
continue;
/*
@@ -522,6 +521,27 @@ out:
EXPORT_SYMBOL_GPL(save_mc_for_early);
#endif
+static bool __init load_builtin_intel_microcode(struct cpio_data *cp)
+{
+#ifdef CONFIG_X86_64
+ unsigned int eax = 0x00000001, ebx, ecx = 0, edx;
+ unsigned int family, model, stepping;
+ char name[30];
+
+ native_cpuid(&eax, &ebx, &ecx, &edx);
+
+ family = __x86_family(eax);
+ model = x86_model(eax);
+ stepping = eax & 0xf;
+
+ sprintf(name, "intel-ucode/%02x-%02x-%02x", family, model, stepping);
+
+ return get_builtin_firmware(cp, name);
+#else
+ return false;
+#endif
+}
+
static __initdata char ucode_name[] = "kernel/x86/microcode/GenuineIntel.bin";
static __init enum ucode_state
scan_microcode(struct mc_saved_data *mc_saved_data, unsigned long *initrd,
@@ -540,8 +560,10 @@ scan_microcode(struct mc_saved_data *mc_saved_data, unsigned long *initrd,
cd.size = 0;
cd = find_cpio_data(p, (void *)start, size, &offset);
- if (!cd.data)
- return UCODE_ERROR;
+ if (!cd.data) {
+ if (!load_builtin_intel_microcode(&cd))
+ return UCODE_ERROR;
+ }
return get_matching_model_microcode(0, start, cd.data, cd.size,
mc_saved_data, initrd, uci);
diff --git a/arch/x86/kernel/cpu/microcode/intel_lib.c b/arch/x86/kernel/cpu/microcode/intel_lib.c
index cd47a510a3f1..1883d252ff7d 100644
--- a/arch/x86/kernel/cpu/microcode/intel_lib.c
+++ b/arch/x86/kernel/cpu/microcode/intel_lib.c
@@ -31,11 +31,18 @@
#include <asm/processor.h>
#include <asm/msr.h>
-static inline int
-update_match_cpu(unsigned int csig, unsigned int cpf,
- unsigned int sig, unsigned int pf)
+static inline bool cpu_signatures_match(unsigned int s1, unsigned int p1,
+ unsigned int s2, unsigned int p2)
{
- return (!sigmatch(sig, csig, pf, cpf)) ? 0 : 1;
+ if (s1 != s2)
+ return false;
+
+ /* Processor flags are either both 0 ... */
+ if (!p1 && !p2)
+ return true;
+
+ /* ... or they intersect. */
+ return p1 & p2;
}
int microcode_sanity_check(void *mc, int print_err)
@@ -124,27 +131,25 @@ EXPORT_SYMBOL_GPL(microcode_sanity_check);
/*
* Returns 1 if update has been found, 0 otherwise.
*/
-int get_matching_sig(unsigned int csig, int cpf, int rev, void *mc)
+int find_matching_signature(void *mc, unsigned int csig, int cpf)
{
- struct microcode_header_intel *mc_header = mc;
- struct extended_sigtable *ext_header;
- unsigned long total_size = get_totalsize(mc_header);
- int ext_sigcount, i;
+ struct microcode_header_intel *mc_hdr = mc;
+ struct extended_sigtable *ext_hdr;
struct extended_signature *ext_sig;
+ int i;
- if (update_match_cpu(csig, cpf, mc_header->sig, mc_header->pf))
+ if (cpu_signatures_match(csig, cpf, mc_hdr->sig, mc_hdr->pf))
return 1;
/* Look for ext. headers: */
- if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
+ if (get_totalsize(mc_hdr) <= get_datasize(mc_hdr) + MC_HEADER_SIZE)
return 0;
- ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
- ext_sigcount = ext_header->count;
- ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
+ ext_hdr = mc + get_datasize(mc_hdr) + MC_HEADER_SIZE;
+ ext_sig = (void *)ext_hdr + EXT_HEADER_SIZE;
- for (i = 0; i < ext_sigcount; i++) {
- if (update_match_cpu(csig, cpf, ext_sig->sig, ext_sig->pf))
+ for (i = 0; i < ext_hdr->count; i++) {
+ if (cpu_signatures_match(csig, cpf, ext_sig->sig, ext_sig->pf))
return 1;
ext_sig++;
}
@@ -154,13 +159,13 @@ int get_matching_sig(unsigned int csig, int cpf, int rev, void *mc)
/*
* Returns 1 if update has been found, 0 otherwise.
*/
-int get_matching_microcode(unsigned int csig, int cpf, int rev, void *mc)
+int has_newer_microcode(void *mc, unsigned int csig, int cpf, int new_rev)
{
struct microcode_header_intel *mc_hdr = mc;
- if (!revision_is_newer(mc_hdr, rev))
+ if (mc_hdr->rev <= new_rev)
return 0;
- return get_matching_sig(csig, cpf, rev, mc);
+ return find_matching_signature(mc, csig, cpf);
}
-EXPORT_SYMBOL_GPL(get_matching_microcode);
+EXPORT_SYMBOL_GPL(has_newer_microcode);
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 939155ffdece..aad4bd84b475 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -39,14 +39,12 @@ void hyperv_vector_handler(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
- irq_enter();
- exit_idle();
-
+ entering_irq();
inc_irq_stat(irq_hv_callback_count);
if (vmbus_handler)
vmbus_handler();
- irq_exit();
+ exiting_irq();
set_irq_regs(old_regs);
}
diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c
index 5f90b85ff22e..70d7c93f4550 100644
--- a/arch/x86/kernel/cpu/mtrr/cleanup.c
+++ b/arch/x86/kernel/cpu/mtrr/cleanup.c
@@ -98,7 +98,8 @@ x86_get_mtrr_mem_range(struct range *range, int nr_range,
continue;
base = range_state[i].base_pfn;
if (base < (1<<(20-PAGE_SHIFT)) && mtrr_state.have_fixed &&
- (mtrr_state.enabled & 1)) {
+ (mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED) &&
+ (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
/* Var MTRR contains UC entry below 1M? Skip it: */
printk(BIOS_BUG_MSG, i);
if (base + size <= (1<<(20-PAGE_SHIFT)))
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index 7d74f7b3c6ba..3b533cf37c74 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -102,59 +102,76 @@ static int check_type_overlap(u8 *prev, u8 *curr)
return 0;
}
-/*
- * Error/Semi-error returns:
- * 0xFF - when MTRR is not enabled
- * *repeat == 1 implies [start:end] spanned across MTRR range and type returned
- * corresponds only to [start:*partial_end].
- * Caller has to lookup again for [*partial_end:end].
+/**
+ * mtrr_type_lookup_fixed - look up memory type in MTRR fixed entries
+ *
+ * Return the MTRR fixed memory type of 'start'.
+ *
+ * MTRR fixed entries are divided into the following ways:
+ * 0x00000 - 0x7FFFF : This range is divided into eight 64KB sub-ranges
+ * 0x80000 - 0xBFFFF : This range is divided into sixteen 16KB sub-ranges
+ * 0xC0000 - 0xFFFFF : This range is divided into sixty-four 4KB sub-ranges
+ *
+ * Return Values:
+ * MTRR_TYPE_(type) - Matched memory type
+ * MTRR_TYPE_INVALID - Unmatched
+ */
+static u8 mtrr_type_lookup_fixed(u64 start, u64 end)
+{
+ int idx;
+
+ if (start >= 0x100000)
+ return MTRR_TYPE_INVALID;
+
+ /* 0x0 - 0x7FFFF */
+ if (start < 0x80000) {
+ idx = 0;
+ idx += (start >> 16);
+ return mtrr_state.fixed_ranges[idx];
+ /* 0x80000 - 0xBFFFF */
+ } else if (start < 0xC0000) {
+ idx = 1 * 8;
+ idx += ((start - 0x80000) >> 14);
+ return mtrr_state.fixed_ranges[idx];
+ }
+
+ /* 0xC0000 - 0xFFFFF */
+ idx = 3 * 8;
+ idx += ((start - 0xC0000) >> 12);
+ return mtrr_state.fixed_ranges[idx];
+}
+
+/**
+ * mtrr_type_lookup_variable - look up memory type in MTRR variable entries
+ *
+ * Return Value:
+ * MTRR_TYPE_(type) - Matched memory type or default memory type (unmatched)
+ *
+ * Output Arguments:
+ * repeat - Set to 1 when [start:end] spanned across MTRR range and type
+ * returned corresponds only to [start:*partial_end]. Caller has
+ * to lookup again for [*partial_end:end].
+ *
+ * uniform - Set to 1 when an MTRR covers the region uniformly, i.e. the
+ * region is fully covered by a single MTRR entry or the default
+ * type.
*/
-static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
+static u8 mtrr_type_lookup_variable(u64 start, u64 end, u64 *partial_end,
+ int *repeat, u8 *uniform)
{
int i;
u64 base, mask;
u8 prev_match, curr_match;
*repeat = 0;
- if (!mtrr_state_set)
- return 0xFF;
-
- if (!mtrr_state.enabled)
- return 0xFF;
+ *uniform = 1;
- /* Make end inclusive end, instead of exclusive */
+ /* Make end inclusive instead of exclusive */
end--;
- /* Look in fixed ranges. Just return the type as per start */
- if (mtrr_state.have_fixed && (start < 0x100000)) {
- int idx;
-
- if (start < 0x80000) {
- idx = 0;
- idx += (start >> 16);
- return mtrr_state.fixed_ranges[idx];
- } else if (start < 0xC0000) {
- idx = 1 * 8;
- idx += ((start - 0x80000) >> 14);
- return mtrr_state.fixed_ranges[idx];
- } else if (start < 0x1000000) {
- idx = 3 * 8;
- idx += ((start - 0xC0000) >> 12);
- return mtrr_state.fixed_ranges[idx];
- }
- }
-
- /*
- * Look in variable ranges
- * Look of multiple ranges matching this address and pick type
- * as per MTRR precedence
- */
- if (!(mtrr_state.enabled & 2))
- return mtrr_state.def_type;
-
- prev_match = 0xFF;
+ prev_match = MTRR_TYPE_INVALID;
for (i = 0; i < num_var_ranges; ++i) {
- unsigned short start_state, end_state;
+ unsigned short start_state, end_state, inclusive;
if (!(mtrr_state.var_ranges[i].mask_lo & (1 << 11)))
continue;
@@ -166,20 +183,29 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
start_state = ((start & mask) == (base & mask));
end_state = ((end & mask) == (base & mask));
+ inclusive = ((start < base) && (end > base));
- if (start_state != end_state) {
+ if ((start_state != end_state) || inclusive) {
/*
* We have start:end spanning across an MTRR.
- * We split the region into
- * either
- * (start:mtrr_end) (mtrr_end:end)
- * or
- * (start:mtrr_start) (mtrr_start:end)
+ * We split the region into either
+ *
+ * - start_state:1
+ * (start:mtrr_end)(mtrr_end:end)
+ * - end_state:1
+ * (start:mtrr_start)(mtrr_start:end)
+ * - inclusive:1
+ * (start:mtrr_start)(mtrr_start:mtrr_end)(mtrr_end:end)
+ *
* depending on kind of overlap.
- * Return the type for first region and a pointer to
- * the start of second region so that caller will
- * lookup again on the second region.
- * Note: This way we handle multiple overlaps as well.
+ *
+ * Return the type of the first region and a pointer
+ * to the start of next region so that caller will be
+ * advised to lookup again after having adjusted start
+ * and end.
+ *
+ * Note: This way we handle overlaps with multiple
+ * entries and the default type properly.
*/
if (start_state)
*partial_end = base + get_mtrr_size(mask);
@@ -193,59 +219,94 @@ static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
end = *partial_end - 1; /* end is inclusive */
*repeat = 1;
+ *uniform = 0;
}
if ((start & mask) != (base & mask))
continue;
curr_match = mtrr_state.var_ranges[i].base_lo & 0xff;
- if (prev_match == 0xFF) {
+ if (prev_match == MTRR_TYPE_INVALID) {
prev_match = curr_match;
continue;
}
+ *uniform = 0;
if (check_type_overlap(&prev_match, &curr_match))
return curr_match;
}
- if (mtrr_tom2) {
- if (start >= (1ULL<<32) && (end < mtrr_tom2))
- return MTRR_TYPE_WRBACK;
- }
-
- if (prev_match != 0xFF)
+ if (prev_match != MTRR_TYPE_INVALID)
return prev_match;
return mtrr_state.def_type;
}
-/*
- * Returns the effective MTRR type for the region
- * Error return:
- * 0xFF - when MTRR is not enabled
+/**
+ * mtrr_type_lookup - look up memory type in MTRR
+ *
+ * Return Values:
+ * MTRR_TYPE_(type) - The effective MTRR type for the region
+ * MTRR_TYPE_INVALID - MTRR is disabled
+ *
+ * Output Argument:
+ * uniform - Set to 1 when an MTRR covers the region uniformly, i.e. the
+ * region is fully covered by a single MTRR entry or the default
+ * type.
*/
-u8 mtrr_type_lookup(u64 start, u64 end)
+u8 mtrr_type_lookup(u64 start, u64 end, u8 *uniform)
{
- u8 type, prev_type;
+ u8 type, prev_type, is_uniform = 1, dummy;
int repeat;
u64 partial_end;
- type = __mtrr_type_lookup(start, end, &partial_end, &repeat);
+ if (!mtrr_state_set)
+ return MTRR_TYPE_INVALID;
+
+ if (!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED))
+ return MTRR_TYPE_INVALID;
+
+ /*
+ * Look up the fixed ranges first, which take priority over
+ * the variable ranges.
+ */
+ if ((start < 0x100000) &&
+ (mtrr_state.have_fixed) &&
+ (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
+ is_uniform = 0;
+ type = mtrr_type_lookup_fixed(start, end);
+ goto out;
+ }
+
+ /*
+ * Look up the variable ranges. Look of multiple ranges matching
+ * this address and pick type as per MTRR precedence.
+ */
+ type = mtrr_type_lookup_variable(start, end, &partial_end,
+ &repeat, &is_uniform);
/*
* Common path is with repeat = 0.
* However, we can have cases where [start:end] spans across some
- * MTRR range. Do repeated lookups for that case here.
+ * MTRR ranges and/or the default type. Do repeated lookups for
+ * that case here.
*/
while (repeat) {
prev_type = type;
start = partial_end;
- type = __mtrr_type_lookup(start, end, &partial_end, &repeat);
+ is_uniform = 0;
+ type = mtrr_type_lookup_variable(start, end, &partial_end,
+ &repeat, &dummy);
if (check_type_overlap(&prev_type, &type))
- return type;
+ goto out;
}
+ if (mtrr_tom2 && (start >= (1ULL<<32)) && (end < mtrr_tom2))
+ type = MTRR_TYPE_WRBACK;
+
+out:
+ *uniform = is_uniform;
return type;
}
@@ -347,7 +408,9 @@ static void __init print_mtrr_state(void)
mtrr_attrib_to_str(mtrr_state.def_type));
if (mtrr_state.have_fixed) {
pr_debug("MTRR fixed ranges %sabled:\n",
- mtrr_state.enabled & 1 ? "en" : "dis");
+ ((mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED) &&
+ (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) ?
+ "en" : "dis");
print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0);
for (i = 0; i < 2; ++i)
print_fixed(0x80000 + i * 0x20000, 0x04000,
@@ -360,7 +423,7 @@ static void __init print_mtrr_state(void)
print_fixed_last();
}
pr_debug("MTRR variable ranges %sabled:\n",
- mtrr_state.enabled & 2 ? "en" : "dis");
+ mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED ? "en" : "dis");
high_width = (__ffs64(size_or_mask) - (32 - PAGE_SHIFT) + 3) / 4;
for (i = 0; i < num_var_ranges; ++i) {
@@ -382,7 +445,7 @@ static void __init print_mtrr_state(void)
}
/* Grab all of the MTRR state for this CPU into *state */
-void __init get_mtrr_state(void)
+bool __init get_mtrr_state(void)
{
struct mtrr_var_range *vrs;
unsigned long flags;
@@ -426,6 +489,8 @@ void __init get_mtrr_state(void)
post_set();
local_irq_restore(flags);
+
+ return !!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED);
}
/* Some BIOS's are messed up and don't set all MTRRs the same! */
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index ea5f363a1948..e7ed0d8ebacb 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -59,6 +59,12 @@
#define MTRR_TO_PHYS_WC_OFFSET 1000
u32 num_var_ranges;
+static bool __mtrr_enabled;
+
+static bool mtrr_enabled(void)
+{
+ return __mtrr_enabled;
+}
unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
static DEFINE_MUTEX(mtrr_mutex);
@@ -286,7 +292,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
int i, replace, error;
mtrr_type ltype;
- if (!mtrr_if)
+ if (!mtrr_enabled())
return -ENXIO;
error = mtrr_if->validate_add_page(base, size, type);
@@ -435,6 +441,8 @@ static int mtrr_check(unsigned long base, unsigned long size)
int mtrr_add(unsigned long base, unsigned long size, unsigned int type,
bool increment)
{
+ if (!mtrr_enabled())
+ return -ENODEV;
if (mtrr_check(base, size))
return -EINVAL;
return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
@@ -463,8 +471,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
unsigned long lbase, lsize;
int error = -EINVAL;
- if (!mtrr_if)
- return -ENXIO;
+ if (!mtrr_enabled())
+ return -ENODEV;
max = num_var_ranges;
/* No CPU hotplug when we change MTRR entries */
@@ -523,6 +531,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
*/
int mtrr_del(int reg, unsigned long base, unsigned long size)
{
+ if (!mtrr_enabled())
+ return -ENODEV;
if (mtrr_check(base, size))
return -EINVAL;
return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
@@ -538,6 +548,9 @@ EXPORT_SYMBOL(mtrr_del);
* attempts to add a WC MTRR covering size bytes starting at base and
* logs an error if this fails.
*
+ * The called should provide a power of two size on an equivalent
+ * power of two boundary.
+ *
* Drivers must store the return value to pass to mtrr_del_wc_if_needed,
* but drivers should not try to interpret that return value.
*/
@@ -545,7 +558,7 @@ int arch_phys_wc_add(unsigned long base, unsigned long size)
{
int ret;
- if (pat_enabled)
+ if (pat_enabled() || !mtrr_enabled())
return 0; /* Success! (We don't need to do anything.) */
ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true);
@@ -577,7 +590,7 @@ void arch_phys_wc_del(int handle)
EXPORT_SYMBOL(arch_phys_wc_del);
/*
- * phys_wc_to_mtrr_index - translates arch_phys_wc_add's return value
+ * arch_phys_wc_index - translates arch_phys_wc_add's return value
* @handle: Return value from arch_phys_wc_add
*
* This will turn the return value from arch_phys_wc_add into an mtrr
@@ -587,14 +600,14 @@ EXPORT_SYMBOL(arch_phys_wc_del);
* in printk line. Alas there is an illegitimate use in some ancient
* drm ioctls.
*/
-int phys_wc_to_mtrr_index(int handle)
+int arch_phys_wc_index(int handle)
{
if (handle < MTRR_TO_PHYS_WC_OFFSET)
return -1;
else
return handle - MTRR_TO_PHYS_WC_OFFSET;
}
-EXPORT_SYMBOL_GPL(phys_wc_to_mtrr_index);
+EXPORT_SYMBOL_GPL(arch_phys_wc_index);
/*
* HACK ALERT!
@@ -734,10 +747,12 @@ void __init mtrr_bp_init(void)
}
if (mtrr_if) {
+ __mtrr_enabled = true;
set_num_var_ranges();
init_table();
if (use_intel()) {
- get_mtrr_state();
+ /* BIOS may override */
+ __mtrr_enabled = get_mtrr_state();
if (mtrr_cleanup(phys_addr)) {
changed_by_mtrr_cleanup = 1;
@@ -745,10 +760,16 @@ void __init mtrr_bp_init(void)
}
}
}
+
+ if (!mtrr_enabled())
+ pr_info("MTRR: Disabled\n");
}
void mtrr_ap_init(void)
{
+ if (!mtrr_enabled())
+ return;
+
if (!use_intel() || mtrr_aps_delayed_init)
return;
/*
@@ -774,6 +795,9 @@ void mtrr_save_state(void)
{
int first_cpu;
+ if (!mtrr_enabled())
+ return;
+
get_online_cpus();
first_cpu = cpumask_first(cpu_online_mask);
smp_call_function_single(first_cpu, mtrr_save_fixed_ranges, NULL, 1);
@@ -782,6 +806,8 @@ void mtrr_save_state(void)
void set_mtrr_aps_delayed_init(void)
{
+ if (!mtrr_enabled())
+ return;
if (!use_intel())
return;
@@ -793,7 +819,7 @@ void set_mtrr_aps_delayed_init(void)
*/
void mtrr_aps_init(void)
{
- if (!use_intel())
+ if (!use_intel() || !mtrr_enabled())
return;
/*
@@ -810,7 +836,7 @@ void mtrr_aps_init(void)
void mtrr_bp_restore(void)
{
- if (!use_intel())
+ if (!use_intel() || !mtrr_enabled())
return;
mtrr_if->set_all();
@@ -818,7 +844,7 @@ void mtrr_bp_restore(void)
static int __init mtrr_init_finialize(void)
{
- if (!mtrr_if)
+ if (!mtrr_enabled())
return 0;
if (use_intel()) {
diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h
index df5e41f31a27..951884dcc433 100644
--- a/arch/x86/kernel/cpu/mtrr/mtrr.h
+++ b/arch/x86/kernel/cpu/mtrr/mtrr.h
@@ -51,7 +51,7 @@ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt);
void fill_mtrr_var_range(unsigned int index,
u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi);
-void get_mtrr_state(void);
+bool get_mtrr_state(void);
extern void set_mtrr_ops(const struct mtrr_ops *ops);
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 4f7001f28936..5801a14f7524 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -135,6 +135,7 @@ static int x86_pmu_extra_regs(u64 config, struct perf_event *event)
}
static atomic_t active_events;
+static atomic_t pmc_refcount;
static DEFINE_MUTEX(pmc_reserve_mutex);
#ifdef CONFIG_X86_LOCAL_APIC
@@ -270,11 +271,8 @@ msr_fail:
static void hw_perf_event_destroy(struct perf_event *event)
{
- if (atomic_dec_and_mutex_lock(&active_events, &pmc_reserve_mutex)) {
- release_pmc_hardware();
- release_ds_buffers();
- mutex_unlock(&pmc_reserve_mutex);
- }
+ x86_release_hardware();
+ atomic_dec(&active_events);
}
void hw_perf_lbr_event_destroy(struct perf_event *event)
@@ -324,6 +322,35 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event *event)
return x86_pmu_extra_regs(val, event);
}
+int x86_reserve_hardware(void)
+{
+ int err = 0;
+
+ if (!atomic_inc_not_zero(&pmc_refcount)) {
+ mutex_lock(&pmc_reserve_mutex);
+ if (atomic_read(&pmc_refcount) == 0) {
+ if (!reserve_pmc_hardware())
+ err = -EBUSY;
+ else
+ reserve_ds_buffers();
+ }
+ if (!err)
+ atomic_inc(&pmc_refcount);
+ mutex_unlock(&pmc_reserve_mutex);
+ }
+
+ return err;
+}
+
+void x86_release_hardware(void)
+{
+ if (atomic_dec_and_mutex_lock(&pmc_refcount, &pmc_reserve_mutex)) {
+ release_pmc_hardware();
+ release_ds_buffers();
+ mutex_unlock(&pmc_reserve_mutex);
+ }
+}
+
/*
* Check if we can create event of a certain type (that no conflicting events
* are present).
@@ -336,21 +363,34 @@ int x86_add_exclusive(unsigned int what)
return 0;
mutex_lock(&pmc_reserve_mutex);
- for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++)
+ for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) {
if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i]))
goto out;
+ }
atomic_inc(&x86_pmu.lbr_exclusive[what]);
ret = 0;
out:
mutex_unlock(&pmc_reserve_mutex);
+
+ /*
+ * Assuming that all exclusive events will share the PMI handler
+ * (which checks active_events for whether there is work to do),
+ * we can bump active_events counter right here, except for
+ * x86_lbr_exclusive_lbr events that go through x86_pmu_event_init()
+ * path, which already bumps active_events for them.
+ */
+ if (!ret && what != x86_lbr_exclusive_lbr)
+ atomic_inc(&active_events);
+
return ret;
}
void x86_del_exclusive(unsigned int what)
{
atomic_dec(&x86_pmu.lbr_exclusive[what]);
+ atomic_dec(&active_events);
}
int x86_setup_perfctr(struct perf_event *event)
@@ -527,22 +567,11 @@ static int __x86_pmu_event_init(struct perf_event *event)
if (!x86_pmu_initialized())
return -ENODEV;
- err = 0;
- if (!atomic_inc_not_zero(&active_events)) {
- mutex_lock(&pmc_reserve_mutex);
- if (atomic_read(&active_events) == 0) {
- if (!reserve_pmc_hardware())
- err = -EBUSY;
- else
- reserve_ds_buffers();
- }
- if (!err)
- atomic_inc(&active_events);
- mutex_unlock(&pmc_reserve_mutex);
- }
+ err = x86_reserve_hardware();
if (err)
return err;
+ atomic_inc(&active_events);
event->destroy = hw_perf_event_destroy;
event->hw.idx = -1;
@@ -881,10 +910,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
if (x86_pmu.commit_scheduling)
x86_pmu.commit_scheduling(cpuc, i, assign[i]);
}
- }
-
- if (!assign || unsched) {
-
+ } else {
for (i = 0; i < n; i++) {
e = cpuc->event_list[i];
/*
@@ -1097,13 +1123,16 @@ int x86_perf_event_set_period(struct perf_event *event)
per_cpu(pmc_prev_left[idx], smp_processor_id()) = left;
- /*
- * The hw event starts counting from this event offset,
- * mark it to be able to extra future deltas:
- */
- local64_set(&hwc->prev_count, (u64)-left);
+ if (!(hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) ||
+ local64_read(&hwc->prev_count) != (u64)-left) {
+ /*
+ * The hw event starts counting from this event offset,
+ * mark it to be able to extra future deltas:
+ */
+ local64_set(&hwc->prev_count, (u64)-left);
- wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask);
+ wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask);
+ }
/*
* Due to erratum on certan cpu we need
@@ -1415,6 +1444,10 @@ perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs)
u64 finish_clock;
int ret;
+ /*
+ * All PMUs/events that share this PMI handler should make sure to
+ * increment active_events for their events.
+ */
if (!atomic_read(&active_events))
return NMI_DONE;
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index ef78516850fb..3e7fd27dfe20 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -75,6 +75,8 @@ struct event_constraint {
#define PERF_X86_EVENT_DYNAMIC 0x0080 /* dynamic alloc'd constraint */
#define PERF_X86_EVENT_RDPMC_ALLOWED 0x0100 /* grant rdpmc permission */
#define PERF_X86_EVENT_EXCL_ACCT 0x0200 /* accounted EXCL event */
+#define PERF_X86_EVENT_AUTO_RELOAD 0x0400 /* use PEBS auto-reload */
+#define PERF_X86_EVENT_FREERUNNING 0x0800 /* use freerunning PEBS */
struct amd_nb {
@@ -88,6 +90,18 @@ struct amd_nb {
#define MAX_PEBS_EVENTS 8
/*
+ * Flags PEBS can handle without an PMI.
+ *
+ * TID can only be handled by flushing at context switch.
+ *
+ */
+#define PEBS_FREERUNNING_FLAGS \
+ (PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_ADDR | \
+ PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_STREAM_ID | \
+ PERF_SAMPLE_DATA_SRC | PERF_SAMPLE_IDENTIFIER | \
+ PERF_SAMPLE_TRANSACTION)
+
+/*
* A debug store configuration.
*
* We only support architectures that use 64bit fields.
@@ -133,7 +147,6 @@ enum intel_excl_state_type {
};
struct intel_excl_states {
- enum intel_excl_state_type init_state[X86_PMC_IDX_MAX];
enum intel_excl_state_type state[X86_PMC_IDX_MAX];
bool sched_started; /* true if scheduling has started */
};
@@ -527,10 +540,10 @@ struct x86_pmu {
void (*put_event_constraints)(struct cpu_hw_events *cpuc,
struct perf_event *event);
- void (*commit_scheduling)(struct cpu_hw_events *cpuc, int idx, int cntr);
-
void (*start_scheduling)(struct cpu_hw_events *cpuc);
+ void (*commit_scheduling)(struct cpu_hw_events *cpuc, int idx, int cntr);
+
void (*stop_scheduling)(struct cpu_hw_events *cpuc);
struct event_constraint *event_constraints;
@@ -703,6 +716,10 @@ int x86_add_exclusive(unsigned int what);
void x86_del_exclusive(unsigned int what);
+int x86_reserve_hardware(void);
+
+void x86_release_hardware(void);
+
void hw_perf_lbr_event_destroy(struct perf_event *event);
int x86_setup_perfctr(struct perf_event *event);
@@ -866,6 +883,8 @@ void intel_pmu_pebs_enable_all(void);
void intel_pmu_pebs_disable_all(void);
+void intel_pmu_pebs_sched_task(struct perf_event_context *ctx, bool sched_in);
+
void intel_ds_init(void);
void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in);
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index a1e35c9f06b9..b9826a981fb2 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1903,9 +1903,8 @@ static void
intel_start_scheduling(struct cpu_hw_events *cpuc)
{
struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
- struct intel_excl_states *xl, *xlo;
+ struct intel_excl_states *xl;
int tid = cpuc->excl_thread_id;
- int o_tid = 1 - tid; /* sibling thread */
/*
* nothing needed if in group validation mode
@@ -1916,10 +1915,9 @@ intel_start_scheduling(struct cpu_hw_events *cpuc)
/*
* no exclusion needed
*/
- if (!excl_cntrs)
+ if (WARN_ON_ONCE(!excl_cntrs))
return;
- xlo = &excl_cntrs->states[o_tid];
xl = &excl_cntrs->states[tid];
xl->sched_started = true;
@@ -1928,22 +1926,41 @@ intel_start_scheduling(struct cpu_hw_events *cpuc)
* in stop_event_scheduling()
* makes scheduling appear as a transaction
*/
- WARN_ON_ONCE(!irqs_disabled());
raw_spin_lock(&excl_cntrs->lock);
+}
- /*
- * save initial state of sibling thread
- */
- memcpy(xlo->init_state, xlo->state, sizeof(xlo->init_state));
+static void intel_commit_scheduling(struct cpu_hw_events *cpuc, int idx, int cntr)
+{
+ struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
+ struct event_constraint *c = cpuc->event_constraint[idx];
+ struct intel_excl_states *xl;
+ int tid = cpuc->excl_thread_id;
+
+ if (cpuc->is_fake || !is_ht_workaround_enabled())
+ return;
+
+ if (WARN_ON_ONCE(!excl_cntrs))
+ return;
+
+ if (!(c->flags & PERF_X86_EVENT_DYNAMIC))
+ return;
+
+ xl = &excl_cntrs->states[tid];
+
+ lockdep_assert_held(&excl_cntrs->lock);
+
+ if (c->flags & PERF_X86_EVENT_EXCL)
+ xl->state[cntr] = INTEL_EXCL_EXCLUSIVE;
+ else
+ xl->state[cntr] = INTEL_EXCL_SHARED;
}
static void
intel_stop_scheduling(struct cpu_hw_events *cpuc)
{
struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
- struct intel_excl_states *xl, *xlo;
+ struct intel_excl_states *xl;
int tid = cpuc->excl_thread_id;
- int o_tid = 1 - tid; /* sibling thread */
/*
* nothing needed if in group validation mode
@@ -1953,17 +1970,11 @@ intel_stop_scheduling(struct cpu_hw_events *cpuc)
/*
* no exclusion needed
*/
- if (!excl_cntrs)
+ if (WARN_ON_ONCE(!excl_cntrs))
return;
- xlo = &excl_cntrs->states[o_tid];
xl = &excl_cntrs->states[tid];
- /*
- * make new sibling thread state visible
- */
- memcpy(xlo->state, xlo->init_state, sizeof(xlo->state));
-
xl->sched_started = false;
/*
* release shared state lock (acquired in intel_start_scheduling())
@@ -1975,12 +1986,10 @@ static struct event_constraint *
intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
int idx, struct event_constraint *c)
{
- struct event_constraint *cx;
struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
- struct intel_excl_states *xl, *xlo;
- int is_excl, i;
+ struct intel_excl_states *xlo;
int tid = cpuc->excl_thread_id;
- int o_tid = 1 - tid; /* alternate */
+ int is_excl, i;
/*
* validating a group does not require
@@ -1992,27 +2001,8 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
/*
* no exclusion needed
*/
- if (!excl_cntrs)
+ if (WARN_ON_ONCE(!excl_cntrs))
return c;
- /*
- * event requires exclusive counter access
- * across HT threads
- */
- is_excl = c->flags & PERF_X86_EVENT_EXCL;
- if (is_excl && !(event->hw.flags & PERF_X86_EVENT_EXCL_ACCT)) {
- event->hw.flags |= PERF_X86_EVENT_EXCL_ACCT;
- if (!cpuc->n_excl++)
- WRITE_ONCE(excl_cntrs->has_exclusive[tid], 1);
- }
-
- /*
- * xl = state of current HT
- * xlo = state of sibling HT
- */
- xl = &excl_cntrs->states[tid];
- xlo = &excl_cntrs->states[o_tid];
-
- cx = c;
/*
* because we modify the constraint, we need
@@ -2023,10 +2013,7 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
* been cloned (marked dynamic)
*/
if (!(c->flags & PERF_X86_EVENT_DYNAMIC)) {
-
- /* sanity check */
- if (idx < 0)
- return &emptyconstraint;
+ struct event_constraint *cx;
/*
* grab pre-allocated constraint entry
@@ -2037,13 +2024,14 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
* initialize dynamic constraint
* with static constraint
*/
- memcpy(cx, c, sizeof(*cx));
+ *cx = *c;
/*
* mark constraint as dynamic, so we
* can free it later on
*/
cx->flags |= PERF_X86_EVENT_DYNAMIC;
+ c = cx;
}
/*
@@ -2054,6 +2042,22 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
*/
/*
+ * state of sibling HT
+ */
+ xlo = &excl_cntrs->states[tid ^ 1];
+
+ /*
+ * event requires exclusive counter access
+ * across HT threads
+ */
+ is_excl = c->flags & PERF_X86_EVENT_EXCL;
+ if (is_excl && !(event->hw.flags & PERF_X86_EVENT_EXCL_ACCT)) {
+ event->hw.flags |= PERF_X86_EVENT_EXCL_ACCT;
+ if (!cpuc->n_excl++)
+ WRITE_ONCE(excl_cntrs->has_exclusive[tid], 1);
+ }
+
+ /*
* Modify static constraint with current dynamic
* state of thread
*
@@ -2061,37 +2065,37 @@ intel_get_excl_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
* SHARED : sibling counter measuring non-exclusive event
* UNUSED : sibling counter unused
*/
- for_each_set_bit(i, cx->idxmsk, X86_PMC_IDX_MAX) {
+ for_each_set_bit(i, c->idxmsk, X86_PMC_IDX_MAX) {
/*
* exclusive event in sibling counter
* our corresponding counter cannot be used
* regardless of our event
*/
- if (xl->state[i] == INTEL_EXCL_EXCLUSIVE)
- __clear_bit(i, cx->idxmsk);
+ if (xlo->state[i] == INTEL_EXCL_EXCLUSIVE)
+ __clear_bit(i, c->idxmsk);
/*
* if measuring an exclusive event, sibling
* measuring non-exclusive, then counter cannot
* be used
*/
- if (is_excl && xl->state[i] == INTEL_EXCL_SHARED)
- __clear_bit(i, cx->idxmsk);
+ if (is_excl && xlo->state[i] == INTEL_EXCL_SHARED)
+ __clear_bit(i, c->idxmsk);
}
/*
* recompute actual bit weight for scheduling algorithm
*/
- cx->weight = hweight64(cx->idxmsk64);
+ c->weight = hweight64(c->idxmsk64);
/*
* if we return an empty mask, then switch
* back to static empty constraint to avoid
* the cost of freeing later on
*/
- if (cx->weight == 0)
- cx = &emptyconstraint;
+ if (c->weight == 0)
+ c = &emptyconstraint;
- return cx;
+ return c;
}
static struct event_constraint *
@@ -2124,10 +2128,8 @@ static void intel_put_excl_constraints(struct cpu_hw_events *cpuc,
{
struct hw_perf_event *hwc = &event->hw;
struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
- struct intel_excl_states *xlo, *xl;
- unsigned long flags = 0; /* keep compiler happy */
int tid = cpuc->excl_thread_id;
- int o_tid = 1 - tid;
+ struct intel_excl_states *xl;
/*
* nothing needed if in group validation mode
@@ -2135,13 +2137,9 @@ static void intel_put_excl_constraints(struct cpu_hw_events *cpuc,
if (cpuc->is_fake)
return;
- WARN_ON_ONCE(!excl_cntrs);
-
- if (!excl_cntrs)
+ if (WARN_ON_ONCE(!excl_cntrs))
return;
- xl = &excl_cntrs->states[tid];
- xlo = &excl_cntrs->states[o_tid];
if (hwc->flags & PERF_X86_EVENT_EXCL_ACCT) {
hwc->flags &= ~PERF_X86_EVENT_EXCL_ACCT;
if (!--cpuc->n_excl)
@@ -2149,22 +2147,25 @@ static void intel_put_excl_constraints(struct cpu_hw_events *cpuc,
}
/*
- * put_constraint may be called from x86_schedule_events()
- * which already has the lock held so here make locking
- * conditional
+ * If event was actually assigned, then mark the counter state as
+ * unused now.
*/
- if (!xl->sched_started)
- raw_spin_lock_irqsave(&excl_cntrs->lock, flags);
+ if (hwc->idx >= 0) {
+ xl = &excl_cntrs->states[tid];
- /*
- * if event was actually assigned, then mark the
- * counter state as unused now
- */
- if (hwc->idx >= 0)
- xlo->state[hwc->idx] = INTEL_EXCL_UNUSED;
+ /*
+ * put_constraint may be called from x86_schedule_events()
+ * which already has the lock held so here make locking
+ * conditional.
+ */
+ if (!xl->sched_started)
+ raw_spin_lock(&excl_cntrs->lock);
+
+ xl->state[hwc->idx] = INTEL_EXCL_UNUSED;
- if (!xl->sched_started)
- raw_spin_unlock_irqrestore(&excl_cntrs->lock, flags);
+ if (!xl->sched_started)
+ raw_spin_unlock(&excl_cntrs->lock);
+ }
}
static void
@@ -2196,41 +2197,6 @@ static void intel_put_event_constraints(struct cpu_hw_events *cpuc,
intel_put_excl_constraints(cpuc, event);
}
-static void intel_commit_scheduling(struct cpu_hw_events *cpuc, int idx, int cntr)
-{
- struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs;
- struct event_constraint *c = cpuc->event_constraint[idx];
- struct intel_excl_states *xlo, *xl;
- int tid = cpuc->excl_thread_id;
- int o_tid = 1 - tid;
- int is_excl;
-
- if (cpuc->is_fake || !c)
- return;
-
- is_excl = c->flags & PERF_X86_EVENT_EXCL;
-
- if (!(c->flags & PERF_X86_EVENT_DYNAMIC))
- return;
-
- WARN_ON_ONCE(!excl_cntrs);
-
- if (!excl_cntrs)
- return;
-
- xl = &excl_cntrs->states[tid];
- xlo = &excl_cntrs->states[o_tid];
-
- WARN_ON_ONCE(!raw_spin_is_locked(&excl_cntrs->lock));
-
- if (cntr >= 0) {
- if (is_excl)
- xlo->init_state[cntr] = INTEL_EXCL_EXCLUSIVE;
- else
- xlo->init_state[cntr] = INTEL_EXCL_SHARED;
- }
-}
-
static void intel_pebs_aliases_core2(struct perf_event *event)
{
if ((event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) {
@@ -2294,8 +2260,15 @@ static int intel_pmu_hw_config(struct perf_event *event)
if (ret)
return ret;
- if (event->attr.precise_ip && x86_pmu.pebs_aliases)
- x86_pmu.pebs_aliases(event);
+ if (event->attr.precise_ip) {
+ if (!event->attr.freq) {
+ event->hw.flags |= PERF_X86_EVENT_AUTO_RELOAD;
+ if (!(event->attr.sample_type & ~PEBS_FREERUNNING_FLAGS))
+ event->hw.flags |= PERF_X86_EVENT_FREERUNNING;
+ }
+ if (x86_pmu.pebs_aliases)
+ x86_pmu.pebs_aliases(event);
+ }
if (needs_branch_stack(event)) {
ret = intel_pmu_setup_lbr_filter(event);
@@ -2544,19 +2517,11 @@ struct intel_shared_regs *allocate_shared_regs(int cpu)
static struct intel_excl_cntrs *allocate_excl_cntrs(int cpu)
{
struct intel_excl_cntrs *c;
- int i;
c = kzalloc_node(sizeof(struct intel_excl_cntrs),
GFP_KERNEL, cpu_to_node(cpu));
if (c) {
raw_spin_lock_init(&c->lock);
- for (i = 0; i < X86_PMC_IDX_MAX; i++) {
- c->states[0].state[i] = INTEL_EXCL_UNUSED;
- c->states[0].init_state[i] = INTEL_EXCL_UNUSED;
-
- c->states[1].state[i] = INTEL_EXCL_UNUSED;
- c->states[1].init_state[i] = INTEL_EXCL_UNUSED;
- }
c->core_id = -1;
}
return c;
@@ -2611,7 +2576,7 @@ static void intel_pmu_cpu_starting(int cpu)
if (!(x86_pmu.flags & PMU_FL_NO_HT_SHARING)) {
void **onln = &cpuc->kfree_on_online[X86_PERF_KFREE_SHARED];
- for_each_cpu(i, topology_thread_cpumask(cpu)) {
+ for_each_cpu(i, topology_sibling_cpumask(cpu)) {
struct intel_shared_regs *pc;
pc = per_cpu(cpu_hw_events, i).shared_regs;
@@ -2629,7 +2594,7 @@ static void intel_pmu_cpu_starting(int cpu)
cpuc->lbr_sel = &cpuc->shared_regs->regs[EXTRA_REG_LBR];
if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) {
- for_each_cpu(i, topology_thread_cpumask(cpu)) {
+ for_each_cpu(i, topology_sibling_cpumask(cpu)) {
struct intel_excl_cntrs *c;
c = per_cpu(cpu_hw_events, i).excl_cntrs;
@@ -2677,6 +2642,15 @@ static void intel_pmu_cpu_dying(int cpu)
fini_debug_store_on_cpu(cpu);
}
+static void intel_pmu_sched_task(struct perf_event_context *ctx,
+ bool sched_in)
+{
+ if (x86_pmu.pebs_active)
+ intel_pmu_pebs_sched_task(ctx, sched_in);
+ if (x86_pmu.lbr_nr)
+ intel_pmu_lbr_sched_task(ctx, sched_in);
+}
+
PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
PMU_FORMAT_ATTR(ldlat, "config1:0-15");
@@ -2766,7 +2740,7 @@ static __initconst const struct x86_pmu intel_pmu = {
.cpu_starting = intel_pmu_cpu_starting,
.cpu_dying = intel_pmu_cpu_dying,
.guest_get_msrs = intel_guest_get_msrs,
- .sched_task = intel_pmu_lbr_sched_task,
+ .sched_task = intel_pmu_sched_task,
};
static __init void intel_clovertown_quirk(void)
@@ -2939,8 +2913,8 @@ static __init void intel_ht_bug(void)
{
x86_pmu.flags |= PMU_FL_EXCL_CNTRS | PMU_FL_EXCL_ENABLED;
- x86_pmu.commit_scheduling = intel_commit_scheduling;
x86_pmu.start_scheduling = intel_start_scheduling;
+ x86_pmu.commit_scheduling = intel_commit_scheduling;
x86_pmu.stop_scheduling = intel_stop_scheduling;
}
@@ -3253,6 +3227,8 @@ __init int intel_pmu_init(void)
case 61: /* 14nm Broadwell Core-M */
case 86: /* 14nm Broadwell Xeon D */
+ case 71: /* 14nm Broadwell + GT3e (Intel Iris Pro graphics) */
+ case 79: /* 14nm Broadwell Server */
x86_pmu.late_ack = true;
memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids));
memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
@@ -3322,13 +3298,13 @@ __init int intel_pmu_init(void)
* counter, so do not extend mask to generic counters
*/
for_each_event_constraint(c, x86_pmu.event_constraints) {
- if (c->cmask != FIXED_EVENT_FLAGS
- || c->idxmsk64 == INTEL_PMC_MSK_FIXED_REF_CYCLES) {
- continue;
+ if (c->cmask == FIXED_EVENT_FLAGS
+ && c->idxmsk64 != INTEL_PMC_MSK_FIXED_REF_CYCLES) {
+ c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1;
}
-
- c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1;
- c->weight += x86_pmu.num_counters;
+ c->idxmsk64 &=
+ ~(~0UL << (INTEL_PMC_IDX_FIXED + x86_pmu.num_counters_fixed));
+ c->weight = hweight64(c->idxmsk64);
}
}
@@ -3386,7 +3362,7 @@ static __init int fixup_ht_bug(void)
if (!(x86_pmu.flags & PMU_FL_EXCL_ENABLED))
return 0;
- w = cpumask_weight(topology_thread_cpumask(cpu));
+ w = cpumask_weight(topology_sibling_cpumask(cpu));
if (w > 1) {
pr_info("PMU erratum BJ122, BV98, HSD29 worked around, HT is on\n");
return 0;
@@ -3396,8 +3372,8 @@ static __init int fixup_ht_bug(void)
x86_pmu.flags &= ~(PMU_FL_EXCL_CNTRS | PMU_FL_EXCL_ENABLED);
- x86_pmu.commit_scheduling = NULL;
x86_pmu.start_scheduling = NULL;
+ x86_pmu.commit_scheduling = NULL;
x86_pmu.stop_scheduling = NULL;
watchdog_nmi_enable_all();
diff --git a/arch/x86/kernel/cpu/perf_event_intel_bts.c b/arch/x86/kernel/cpu/perf_event_intel_bts.c
index ac1f0c55f379..7795f3f8b1d5 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_bts.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_bts.c
@@ -483,17 +483,26 @@ static int bts_event_add(struct perf_event *event, int mode)
static void bts_event_destroy(struct perf_event *event)
{
+ x86_release_hardware();
x86_del_exclusive(x86_lbr_exclusive_bts);
}
static int bts_event_init(struct perf_event *event)
{
+ int ret;
+
if (event->attr.type != bts_pmu.type)
return -ENOENT;
if (x86_add_exclusive(x86_lbr_exclusive_bts))
return -EBUSY;
+ ret = x86_reserve_hardware();
+ if (ret) {
+ x86_del_exclusive(x86_lbr_exclusive_bts);
+ return ret;
+ }
+
event->destroy = bts_event_destroy;
return 0;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_cqm.c b/arch/x86/kernel/cpu/perf_event_intel_cqm.c
index e4d1b8b738fa..188076161c1b 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_cqm.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_cqm.c
@@ -13,16 +13,35 @@
#define MSR_IA32_QM_CTR 0x0c8e
#define MSR_IA32_QM_EVTSEL 0x0c8d
-static unsigned int cqm_max_rmid = -1;
+static u32 cqm_max_rmid = -1;
static unsigned int cqm_l3_scale; /* supposedly cacheline size */
-struct intel_cqm_state {
- raw_spinlock_t lock;
- int rmid;
- int cnt;
+/**
+ * struct intel_pqr_state - State cache for the PQR MSR
+ * @rmid: The cached Resource Monitoring ID
+ * @closid: The cached Class Of Service ID
+ * @rmid_usecnt: The usage counter for rmid
+ *
+ * The upper 32 bits of MSR_IA32_PQR_ASSOC contain closid and the
+ * lower 10 bits rmid. The update to MSR_IA32_PQR_ASSOC always
+ * contains both parts, so we need to cache them.
+ *
+ * The cache also helps to avoid pointless updates if the value does
+ * not change.
+ */
+struct intel_pqr_state {
+ u32 rmid;
+ u32 closid;
+ int rmid_usecnt;
};
-static DEFINE_PER_CPU(struct intel_cqm_state, cqm_state);
+/*
+ * The cached intel_pqr_state is strictly per CPU and can never be
+ * updated from a remote CPU. Both functions which modify the state
+ * (intel_cqm_event_start and intel_cqm_event_stop) are called with
+ * interrupts disabled, which is sufficient for the protection.
+ */
+static DEFINE_PER_CPU(struct intel_pqr_state, pqr_state);
/*
* Protects cache_cgroups and cqm_rmid_free_lru and cqm_rmid_limbo_lru.
@@ -57,7 +76,7 @@ static cpumask_t cqm_cpumask;
* near-zero occupancy value, i.e. no cachelines are tagged with this
* RMID, once __intel_cqm_rmid_rotate() returns.
*/
-static unsigned int intel_cqm_rotation_rmid;
+static u32 intel_cqm_rotation_rmid;
#define INVALID_RMID (-1)
@@ -69,7 +88,7 @@ static unsigned int intel_cqm_rotation_rmid;
* Likewise, an rmid value of -1 is used to indicate "no rmid currently
* assigned" and is used as part of the rotation code.
*/
-static inline bool __rmid_valid(unsigned int rmid)
+static inline bool __rmid_valid(u32 rmid)
{
if (!rmid || rmid == INVALID_RMID)
return false;
@@ -77,7 +96,7 @@ static inline bool __rmid_valid(unsigned int rmid)
return true;
}
-static u64 __rmid_read(unsigned int rmid)
+static u64 __rmid_read(u32 rmid)
{
u64 val;
@@ -102,7 +121,7 @@ enum rmid_recycle_state {
};
struct cqm_rmid_entry {
- unsigned int rmid;
+ u32 rmid;
enum rmid_recycle_state state;
struct list_head list;
unsigned long queue_time;
@@ -147,7 +166,7 @@ static LIST_HEAD(cqm_rmid_limbo_lru);
*/
static struct cqm_rmid_entry **cqm_rmid_ptrs;
-static inline struct cqm_rmid_entry *__rmid_entry(int rmid)
+static inline struct cqm_rmid_entry *__rmid_entry(u32 rmid)
{
struct cqm_rmid_entry *entry;
@@ -162,7 +181,7 @@ static inline struct cqm_rmid_entry *__rmid_entry(int rmid)
*
* We expect to be called with cache_mutex held.
*/
-static int __get_rmid(void)
+static u32 __get_rmid(void)
{
struct cqm_rmid_entry *entry;
@@ -177,7 +196,7 @@ static int __get_rmid(void)
return entry->rmid;
}
-static void __put_rmid(unsigned int rmid)
+static void __put_rmid(u32 rmid)
{
struct cqm_rmid_entry *entry;
@@ -372,7 +391,7 @@ static bool __conflict_event(struct perf_event *a, struct perf_event *b)
}
struct rmid_read {
- unsigned int rmid;
+ u32 rmid;
atomic64_t value;
};
@@ -381,12 +400,11 @@ static void __intel_cqm_event_count(void *info);
/*
* Exchange the RMID of a group of events.
*/
-static unsigned int
-intel_cqm_xchg_rmid(struct perf_event *group, unsigned int rmid)
+static u32 intel_cqm_xchg_rmid(struct perf_event *group, u32 rmid)
{
struct perf_event *event;
- unsigned int old_rmid = group->hw.cqm_rmid;
struct list_head *head = &group->hw.cqm_group_entry;
+ u32 old_rmid = group->hw.cqm_rmid;
lockdep_assert_held(&cache_mutex);
@@ -451,7 +469,7 @@ static void intel_cqm_stable(void *arg)
* If we have group events waiting for an RMID that don't conflict with
* events already running, assign @rmid.
*/
-static bool intel_cqm_sched_in_event(unsigned int rmid)
+static bool intel_cqm_sched_in_event(u32 rmid)
{
struct perf_event *leader, *event;
@@ -598,7 +616,7 @@ static bool intel_cqm_rmid_stabilize(unsigned int *available)
static void __intel_cqm_pick_and_rotate(struct perf_event *next)
{
struct perf_event *rotor;
- unsigned int rmid;
+ u32 rmid;
lockdep_assert_held(&cache_mutex);
@@ -626,7 +644,7 @@ static void __intel_cqm_pick_and_rotate(struct perf_event *next)
static void intel_cqm_sched_out_conflicting_events(struct perf_event *event)
{
struct perf_event *group, *g;
- unsigned int rmid;
+ u32 rmid;
lockdep_assert_held(&cache_mutex);
@@ -828,8 +846,8 @@ static void intel_cqm_setup_event(struct perf_event *event,
struct perf_event **group)
{
struct perf_event *iter;
- unsigned int rmid;
bool conflict = false;
+ u32 rmid;
list_for_each_entry(iter, &cache_groups, hw.cqm_groups_entry) {
rmid = iter->hw.cqm_rmid;
@@ -860,7 +878,7 @@ static void intel_cqm_setup_event(struct perf_event *event,
static void intel_cqm_event_read(struct perf_event *event)
{
unsigned long flags;
- unsigned int rmid;
+ u32 rmid;
u64 val;
/*
@@ -961,55 +979,48 @@ out:
static void intel_cqm_event_start(struct perf_event *event, int mode)
{
- struct intel_cqm_state *state = this_cpu_ptr(&cqm_state);
- unsigned int rmid = event->hw.cqm_rmid;
- unsigned long flags;
+ struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
+ u32 rmid = event->hw.cqm_rmid;
if (!(event->hw.cqm_state & PERF_HES_STOPPED))
return;
event->hw.cqm_state &= ~PERF_HES_STOPPED;
- raw_spin_lock_irqsave(&state->lock, flags);
-
- if (state->cnt++)
- WARN_ON_ONCE(state->rmid != rmid);
- else
+ if (state->rmid_usecnt++) {
+ if (!WARN_ON_ONCE(state->rmid != rmid))
+ return;
+ } else {
WARN_ON_ONCE(state->rmid);
+ }
state->rmid = rmid;
- wrmsrl(MSR_IA32_PQR_ASSOC, state->rmid);
-
- raw_spin_unlock_irqrestore(&state->lock, flags);
+ wrmsr(MSR_IA32_PQR_ASSOC, rmid, state->closid);
}
static void intel_cqm_event_stop(struct perf_event *event, int mode)
{
- struct intel_cqm_state *state = this_cpu_ptr(&cqm_state);
- unsigned long flags;
+ struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
if (event->hw.cqm_state & PERF_HES_STOPPED)
return;
event->hw.cqm_state |= PERF_HES_STOPPED;
- raw_spin_lock_irqsave(&state->lock, flags);
intel_cqm_event_read(event);
- if (!--state->cnt) {
+ if (!--state->rmid_usecnt) {
state->rmid = 0;
- wrmsrl(MSR_IA32_PQR_ASSOC, 0);
+ wrmsr(MSR_IA32_PQR_ASSOC, 0, state->closid);
} else {
WARN_ON_ONCE(!state->rmid);
}
-
- raw_spin_unlock_irqrestore(&state->lock, flags);
}
static int intel_cqm_event_add(struct perf_event *event, int mode)
{
unsigned long flags;
- unsigned int rmid;
+ u32 rmid;
raw_spin_lock_irqsave(&cache_lock, flags);
@@ -1024,11 +1035,6 @@ static int intel_cqm_event_add(struct perf_event *event, int mode)
return 0;
}
-static void intel_cqm_event_del(struct perf_event *event, int mode)
-{
- intel_cqm_event_stop(event, mode);
-}
-
static void intel_cqm_event_destroy(struct perf_event *event)
{
struct perf_event *group_other = NULL;
@@ -1057,7 +1063,7 @@ static void intel_cqm_event_destroy(struct perf_event *event)
list_replace(&event->hw.cqm_groups_entry,
&group_other->hw.cqm_groups_entry);
} else {
- unsigned int rmid = event->hw.cqm_rmid;
+ u32 rmid = event->hw.cqm_rmid;
if (__rmid_valid(rmid))
__put_rmid(rmid);
@@ -1221,7 +1227,7 @@ static struct pmu intel_cqm_pmu = {
.task_ctx_nr = perf_sw_context,
.event_init = intel_cqm_event_init,
.add = intel_cqm_event_add,
- .del = intel_cqm_event_del,
+ .del = intel_cqm_event_stop,
.start = intel_cqm_event_start,
.stop = intel_cqm_event_stop,
.read = intel_cqm_event_read,
@@ -1243,12 +1249,12 @@ static inline void cqm_pick_event_reader(int cpu)
static void intel_cqm_cpu_prepare(unsigned int cpu)
{
- struct intel_cqm_state *state = &per_cpu(cqm_state, cpu);
+ struct intel_pqr_state *state = &per_cpu(pqr_state, cpu);
struct cpuinfo_x86 *c = &cpu_data(cpu);
- raw_spin_lock_init(&state->lock);
state->rmid = 0;
- state->cnt = 0;
+ state->closid = 0;
+ state->rmid_usecnt = 0;
WARN_ON(c->x86_cache_max_rmid != cqm_max_rmid);
WARN_ON(c->x86_cache_occ_scale != cqm_l3_scale);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index 7f73b3553e2e..71fc40238843 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -11,7 +11,7 @@
#define BTS_RECORD_SIZE 24
#define BTS_BUFFER_SIZE (PAGE_SIZE << 4)
-#define PEBS_BUFFER_SIZE PAGE_SIZE
+#define PEBS_BUFFER_SIZE (PAGE_SIZE << 4)
#define PEBS_FIXUP_SIZE PAGE_SIZE
/*
@@ -250,7 +250,7 @@ static int alloc_pebs_buffer(int cpu)
{
struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
int node = cpu_to_node(cpu);
- int max, thresh = 1; /* always use a single PEBS record */
+ int max;
void *buffer, *ibuffer;
if (!x86_pmu.pebs)
@@ -280,9 +280,6 @@ static int alloc_pebs_buffer(int cpu)
ds->pebs_absolute_maximum = ds->pebs_buffer_base +
max * x86_pmu.pebs_record_size;
- ds->pebs_interrupt_threshold = ds->pebs_buffer_base +
- thresh * x86_pmu.pebs_record_size;
-
return 0;
}
@@ -549,6 +546,19 @@ int intel_pmu_drain_bts_buffer(void)
return 1;
}
+static inline void intel_pmu_drain_pebs_buffer(void)
+{
+ struct pt_regs regs;
+
+ x86_pmu.drain_pebs(&regs);
+}
+
+void intel_pmu_pebs_sched_task(struct perf_event_context *ctx, bool sched_in)
+{
+ if (!sched_in)
+ intel_pmu_drain_pebs_buffer();
+}
+
/*
* PEBS
*/
@@ -684,25 +694,66 @@ struct event_constraint *intel_pebs_constraints(struct perf_event *event)
return &emptyconstraint;
}
+static inline bool pebs_is_enabled(struct cpu_hw_events *cpuc)
+{
+ return (cpuc->pebs_enabled & ((1ULL << MAX_PEBS_EVENTS) - 1));
+}
+
void intel_pmu_pebs_enable(struct perf_event *event)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
struct hw_perf_event *hwc = &event->hw;
+ struct debug_store *ds = cpuc->ds;
+ bool first_pebs;
+ u64 threshold;
hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT;
+ first_pebs = !pebs_is_enabled(cpuc);
cpuc->pebs_enabled |= 1ULL << hwc->idx;
if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT)
cpuc->pebs_enabled |= 1ULL << (hwc->idx + 32);
else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST)
cpuc->pebs_enabled |= 1ULL << 63;
+
+ /*
+ * When the event is constrained enough we can use a larger
+ * threshold and run the event with less frequent PMI.
+ */
+ if (hwc->flags & PERF_X86_EVENT_FREERUNNING) {
+ threshold = ds->pebs_absolute_maximum -
+ x86_pmu.max_pebs_events * x86_pmu.pebs_record_size;
+
+ if (first_pebs)
+ perf_sched_cb_inc(event->ctx->pmu);
+ } else {
+ threshold = ds->pebs_buffer_base + x86_pmu.pebs_record_size;
+
+ /*
+ * If not all events can use larger buffer,
+ * roll back to threshold = 1
+ */
+ if (!first_pebs &&
+ (ds->pebs_interrupt_threshold > threshold))
+ perf_sched_cb_dec(event->ctx->pmu);
+ }
+
+ /* Use auto-reload if possible to save a MSR write in the PMI */
+ if (hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) {
+ ds->pebs_event_reset[hwc->idx] =
+ (u64)(-hwc->sample_period) & x86_pmu.cntval_mask;
+ }
+
+ if (first_pebs || ds->pebs_interrupt_threshold > threshold)
+ ds->pebs_interrupt_threshold = threshold;
}
void intel_pmu_pebs_disable(struct perf_event *event)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
struct hw_perf_event *hwc = &event->hw;
+ struct debug_store *ds = cpuc->ds;
cpuc->pebs_enabled &= ~(1ULL << hwc->idx);
@@ -711,6 +762,13 @@ void intel_pmu_pebs_disable(struct perf_event *event)
else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST)
cpuc->pebs_enabled &= ~(1ULL << 63);
+ if (ds->pebs_interrupt_threshold >
+ ds->pebs_buffer_base + x86_pmu.pebs_record_size) {
+ intel_pmu_drain_pebs_buffer();
+ if (!pebs_is_enabled(cpuc))
+ perf_sched_cb_dec(event->ctx->pmu);
+ }
+
if (cpuc->enabled)
wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled);
@@ -846,8 +904,10 @@ static inline u64 intel_hsw_transaction(struct pebs_record_hsw *pebs)
return txn;
}
-static void __intel_pmu_pebs_event(struct perf_event *event,
- struct pt_regs *iregs, void *__pebs)
+static void setup_pebs_sample_data(struct perf_event *event,
+ struct pt_regs *iregs, void *__pebs,
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
{
#define PERF_X86_EVENT_PEBS_HSW_PREC \
(PERF_X86_EVENT_PEBS_ST_HSW | \
@@ -859,13 +919,11 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
*/
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
struct pebs_record_hsw *pebs = __pebs;
- struct perf_sample_data data;
- struct pt_regs regs;
u64 sample_type;
int fll, fst, dsrc;
int fl = event->hw.flags;
- if (!intel_pmu_save_and_restart(event))
+ if (pebs == NULL)
return;
sample_type = event->attr.sample_type;
@@ -874,15 +932,15 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
fll = fl & PERF_X86_EVENT_PEBS_LDLAT;
fst = fl & (PERF_X86_EVENT_PEBS_ST | PERF_X86_EVENT_PEBS_HSW_PREC);
- perf_sample_data_init(&data, 0, event->hw.last_period);
+ perf_sample_data_init(data, 0, event->hw.last_period);
- data.period = event->hw.last_period;
+ data->period = event->hw.last_period;
/*
* Use latency for weight (only avail with PEBS-LL)
*/
if (fll && (sample_type & PERF_SAMPLE_WEIGHT))
- data.weight = pebs->lat;
+ data->weight = pebs->lat;
/*
* data.data_src encodes the data source
@@ -895,7 +953,7 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
val = precise_datala_hsw(event, pebs->dse);
else if (fst)
val = precise_store_data(pebs->dse);
- data.data_src.val = val;
+ data->data_src.val = val;
}
/*
@@ -908,61 +966,123 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
* PERF_SAMPLE_IP and PERF_SAMPLE_CALLCHAIN to function properly.
* A possible PERF_SAMPLE_REGS will have to transfer all regs.
*/
- regs = *iregs;
- regs.flags = pebs->flags;
- set_linear_ip(&regs, pebs->ip);
- regs.bp = pebs->bp;
- regs.sp = pebs->sp;
+ *regs = *iregs;
+ regs->flags = pebs->flags;
+ set_linear_ip(regs, pebs->ip);
+ regs->bp = pebs->bp;
+ regs->sp = pebs->sp;
if (sample_type & PERF_SAMPLE_REGS_INTR) {
- regs.ax = pebs->ax;
- regs.bx = pebs->bx;
- regs.cx = pebs->cx;
- regs.dx = pebs->dx;
- regs.si = pebs->si;
- regs.di = pebs->di;
- regs.bp = pebs->bp;
- regs.sp = pebs->sp;
-
- regs.flags = pebs->flags;
+ regs->ax = pebs->ax;
+ regs->bx = pebs->bx;
+ regs->cx = pebs->cx;
+ regs->dx = pebs->dx;
+ regs->si = pebs->si;
+ regs->di = pebs->di;
+ regs->bp = pebs->bp;
+ regs->sp = pebs->sp;
+
+ regs->flags = pebs->flags;
#ifndef CONFIG_X86_32
- regs.r8 = pebs->r8;
- regs.r9 = pebs->r9;
- regs.r10 = pebs->r10;
- regs.r11 = pebs->r11;
- regs.r12 = pebs->r12;
- regs.r13 = pebs->r13;
- regs.r14 = pebs->r14;
- regs.r15 = pebs->r15;
+ regs->r8 = pebs->r8;
+ regs->r9 = pebs->r9;
+ regs->r10 = pebs->r10;
+ regs->r11 = pebs->r11;
+ regs->r12 = pebs->r12;
+ regs->r13 = pebs->r13;
+ regs->r14 = pebs->r14;
+ regs->r15 = pebs->r15;
#endif
}
if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format >= 2) {
- regs.ip = pebs->real_ip;
- regs.flags |= PERF_EFLAGS_EXACT;
- } else if (event->attr.precise_ip > 1 && intel_pmu_pebs_fixup_ip(&regs))
- regs.flags |= PERF_EFLAGS_EXACT;
+ regs->ip = pebs->real_ip;
+ regs->flags |= PERF_EFLAGS_EXACT;
+ } else if (event->attr.precise_ip > 1 && intel_pmu_pebs_fixup_ip(regs))
+ regs->flags |= PERF_EFLAGS_EXACT;
else
- regs.flags &= ~PERF_EFLAGS_EXACT;
+ regs->flags &= ~PERF_EFLAGS_EXACT;
if ((sample_type & PERF_SAMPLE_ADDR) &&
x86_pmu.intel_cap.pebs_format >= 1)
- data.addr = pebs->dla;
+ data->addr = pebs->dla;
if (x86_pmu.intel_cap.pebs_format >= 2) {
/* Only set the TSX weight when no memory weight. */
if ((sample_type & PERF_SAMPLE_WEIGHT) && !fll)
- data.weight = intel_hsw_weight(pebs);
+ data->weight = intel_hsw_weight(pebs);
if (sample_type & PERF_SAMPLE_TRANSACTION)
- data.txn = intel_hsw_transaction(pebs);
+ data->txn = intel_hsw_transaction(pebs);
}
if (has_branch_stack(event))
- data.br_stack = &cpuc->lbr_stack;
+ data->br_stack = &cpuc->lbr_stack;
+}
+
+static inline void *
+get_next_pebs_record_by_bit(void *base, void *top, int bit)
+{
+ struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+ void *at;
+ u64 pebs_status;
+
+ if (base == NULL)
+ return NULL;
+
+ for (at = base; at < top; at += x86_pmu.pebs_record_size) {
+ struct pebs_record_nhm *p = at;
+
+ if (test_bit(bit, (unsigned long *)&p->status)) {
+ /* PEBS v3 has accurate status bits */
+ if (x86_pmu.intel_cap.pebs_format >= 3)
+ return at;
- if (perf_event_overflow(event, &data, &regs))
+ if (p->status == (1 << bit))
+ return at;
+
+ /* clear non-PEBS bit and re-check */
+ pebs_status = p->status & cpuc->pebs_enabled;
+ pebs_status &= (1ULL << MAX_PEBS_EVENTS) - 1;
+ if (pebs_status == (1 << bit))
+ return at;
+ }
+ }
+ return NULL;
+}
+
+static void __intel_pmu_pebs_event(struct perf_event *event,
+ struct pt_regs *iregs,
+ void *base, void *top,
+ int bit, int count)
+{
+ struct perf_sample_data data;
+ struct pt_regs regs;
+ void *at = get_next_pebs_record_by_bit(base, top, bit);
+
+ if (!intel_pmu_save_and_restart(event) &&
+ !(event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD))
+ return;
+
+ while (count > 1) {
+ setup_pebs_sample_data(event, iregs, at, &data, &regs);
+ perf_event_output(event, &data, &regs);
+ at += x86_pmu.pebs_record_size;
+ at = get_next_pebs_record_by_bit(at, top, bit);
+ count--;
+ }
+
+ setup_pebs_sample_data(event, iregs, at, &data, &regs);
+
+ /*
+ * All but the last records are processed.
+ * The last one is left to be able to call the overflow handler.
+ */
+ if (perf_event_overflow(event, &data, &regs)) {
x86_pmu_stop(event, 0);
+ return;
+ }
+
}
static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
@@ -992,72 +1112,99 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
if (!event->attr.precise_ip)
return;
- n = top - at;
+ n = (top - at) / x86_pmu.pebs_record_size;
if (n <= 0)
return;
- /*
- * Should not happen, we program the threshold at 1 and do not
- * set a reset value.
- */
- WARN_ONCE(n > 1, "bad leftover pebs %d\n", n);
- at += n - 1;
-
- __intel_pmu_pebs_event(event, iregs, at);
+ __intel_pmu_pebs_event(event, iregs, at, top, 0, n);
}
static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
struct debug_store *ds = cpuc->ds;
- struct perf_event *event = NULL;
- void *at, *top;
- u64 status = 0;
- int bit;
+ struct perf_event *event;
+ void *base, *at, *top;
+ short counts[MAX_PEBS_EVENTS] = {};
+ short error[MAX_PEBS_EVENTS] = {};
+ int bit, i;
if (!x86_pmu.pebs_active)
return;
- at = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base;
+ base = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base;
top = (struct pebs_record_nhm *)(unsigned long)ds->pebs_index;
ds->pebs_index = ds->pebs_buffer_base;
- if (unlikely(at > top))
+ if (unlikely(base >= top))
return;
- /*
- * Should not happen, we program the threshold at 1 and do not
- * set a reset value.
- */
- WARN_ONCE(top - at > x86_pmu.max_pebs_events * x86_pmu.pebs_record_size,
- "Unexpected number of pebs records %ld\n",
- (long)(top - at) / x86_pmu.pebs_record_size);
-
- for (; at < top; at += x86_pmu.pebs_record_size) {
+ for (at = base; at < top; at += x86_pmu.pebs_record_size) {
struct pebs_record_nhm *p = at;
- for_each_set_bit(bit, (unsigned long *)&p->status,
- x86_pmu.max_pebs_events) {
- event = cpuc->events[bit];
- if (!test_bit(bit, cpuc->active_mask))
- continue;
-
- WARN_ON_ONCE(!event);
+ /* PEBS v3 has accurate status bits */
+ if (x86_pmu.intel_cap.pebs_format >= 3) {
+ for_each_set_bit(bit, (unsigned long *)&p->status,
+ MAX_PEBS_EVENTS)
+ counts[bit]++;
- if (!event->attr.precise_ip)
- continue;
+ continue;
+ }
- if (__test_and_set_bit(bit, (unsigned long *)&status))
+ bit = find_first_bit((unsigned long *)&p->status,
+ x86_pmu.max_pebs_events);
+ if (bit >= x86_pmu.max_pebs_events)
+ continue;
+ if (!test_bit(bit, cpuc->active_mask))
+ continue;
+ /*
+ * The PEBS hardware does not deal well with the situation
+ * when events happen near to each other and multiple bits
+ * are set. But it should happen rarely.
+ *
+ * If these events include one PEBS and multiple non-PEBS
+ * events, it doesn't impact PEBS record. The record will
+ * be handled normally. (slow path)
+ *
+ * If these events include two or more PEBS events, the
+ * records for the events can be collapsed into a single
+ * one, and it's not possible to reconstruct all events
+ * that caused the PEBS record. It's called collision.
+ * If collision happened, the record will be dropped.
+ *
+ */
+ if (p->status != (1 << bit)) {
+ u64 pebs_status;
+
+ /* slow path */
+ pebs_status = p->status & cpuc->pebs_enabled;
+ pebs_status &= (1ULL << MAX_PEBS_EVENTS) - 1;
+ if (pebs_status != (1 << bit)) {
+ for_each_set_bit(i, (unsigned long *)&pebs_status,
+ MAX_PEBS_EVENTS)
+ error[i]++;
continue;
-
- break;
+ }
}
+ counts[bit]++;
+ }
- if (!event || bit >= x86_pmu.max_pebs_events)
+ for (bit = 0; bit < x86_pmu.max_pebs_events; bit++) {
+ if ((counts[bit] == 0) && (error[bit] == 0))
continue;
+ event = cpuc->events[bit];
+ WARN_ON_ONCE(!event);
+ WARN_ON_ONCE(!event->attr.precise_ip);
- __intel_pmu_pebs_event(event, iregs, at);
+ /* log dropped samples number */
+ if (error[bit])
+ perf_log_lost_samples(event, error[bit]);
+
+ if (counts[bit]) {
+ __intel_pmu_pebs_event(event, iregs, base,
+ top, bit, counts[bit]);
+ }
}
}
diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
index 94e5b506caa6..452a7bd2dedb 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
@@ -96,6 +96,7 @@ enum {
X86_BR_NO_TX = 1 << 14,/* not in transaction */
X86_BR_ZERO_CALL = 1 << 15,/* zero length call */
X86_BR_CALL_STACK = 1 << 16,/* call stack */
+ X86_BR_IND_JMP = 1 << 17,/* indirect jump */
};
#define X86_BR_PLM (X86_BR_USER | X86_BR_KERNEL)
@@ -113,6 +114,7 @@ enum {
X86_BR_IRQ |\
X86_BR_ABORT |\
X86_BR_IND_CALL |\
+ X86_BR_IND_JMP |\
X86_BR_ZERO_CALL)
#define X86_BR_ALL (X86_BR_PLM | X86_BR_ANY)
@@ -262,9 +264,6 @@ void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in)
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
struct x86_perf_task_context *task_ctx;
- if (!x86_pmu.lbr_nr)
- return;
-
/*
* If LBR callstack feature is enabled and the stack was saved when
* the task was scheduled out, restore the stack. Otherwise flush
@@ -523,6 +522,9 @@ static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
X86_BR_CALL_STACK;
}
+ if (br_type & PERF_SAMPLE_BRANCH_IND_JUMP)
+ mask |= X86_BR_IND_JMP;
+
/*
* stash actual user request into reg, it may
* be used by fixup code for some CPU
@@ -736,7 +738,7 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
break;
case 4:
case 5:
- ret = X86_BR_JMP;
+ ret = X86_BR_IND_JMP;
break;
}
break;
@@ -844,6 +846,7 @@ static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = {
*/
[PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = LBR_IND_CALL | LBR_IND_JMP,
[PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_JCC,
+ [PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = LBR_IND_JMP,
};
static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = {
@@ -856,6 +859,7 @@ static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = {
| LBR_FAR,
[PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = LBR_IND_CALL,
[PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_JCC,
+ [PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = LBR_IND_JMP,
};
static const int hsw_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = {
@@ -870,6 +874,7 @@ static const int hsw_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = {
[PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_JCC,
[PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT] = LBR_REL_CALL | LBR_IND_CALL
| LBR_RETURN | LBR_CALL_STACK,
+ [PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = LBR_IND_JMP,
};
/* core */
diff --git a/arch/x86/kernel/cpu/perf_event_intel_pt.c b/arch/x86/kernel/cpu/perf_event_intel_pt.c
index 123ff1bb2f60..159887c3a89d 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_pt.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_pt.c
@@ -187,15 +187,6 @@ static bool pt_event_valid(struct perf_event *event)
* These all are cpu affine and operate on a local PT
*/
-static bool pt_is_running(void)
-{
- u64 ctl;
-
- rdmsrl(MSR_IA32_RTIT_CTL, ctl);
-
- return !!(ctl & RTIT_CTL_TRACEEN);
-}
-
static void pt_config(struct perf_event *event)
{
u64 reg;
@@ -609,7 +600,12 @@ static unsigned int pt_topa_next_entry(struct pt_buffer *buf, unsigned int pg)
* @handle: Current output handle.
*
* Place INT and STOP marks to prevent overwriting old data that the consumer
- * hasn't yet collected.
+ * hasn't yet collected and waking up the consumer after a certain fraction of
+ * the buffer has filled up. Only needed and sensible for non-snapshot counters.
+ *
+ * This obviously relies on buf::head to figure out buffer markers, so it has
+ * to be called after pt_buffer_reset_offsets() and before the hardware tracing
+ * is enabled.
*/
static int pt_buffer_reset_markers(struct pt_buffer *buf,
struct perf_output_handle *handle)
@@ -618,9 +614,6 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf,
unsigned long head = local64_read(&buf->head);
unsigned long idx, npages, wakeup;
- if (buf->snapshot)
- return 0;
-
/* can't stop in the middle of an output region */
if (buf->output_off + handle->size + 1 <
sizes(TOPA_ENTRY(buf->cur, buf->cur_idx)->size))
@@ -674,7 +667,7 @@ static void pt_buffer_setup_topa_index(struct pt_buffer *buf)
struct topa *cur = buf->first, *prev = buf->last;
struct topa_entry *te_cur = TOPA_ENTRY(cur, 0),
*te_prev = TOPA_ENTRY(prev, prev->last - 1);
- int pg = 0, idx = 0, ntopa = 0;
+ int pg = 0, idx = 0;
while (pg < buf->nr_pages) {
int tidx;
@@ -689,9 +682,9 @@ static void pt_buffer_setup_topa_index(struct pt_buffer *buf)
/* advance to next topa table */
idx = 0;
cur = list_entry(cur->list.next, struct topa, list);
- ntopa++;
- } else
+ } else {
idx++;
+ }
te_cur = TOPA_ENTRY(cur, idx);
}
@@ -703,7 +696,14 @@ static void pt_buffer_setup_topa_index(struct pt_buffer *buf)
* @head: Write pointer (aux_head) from AUX buffer.
*
* Find the ToPA table and entry corresponding to given @head and set buffer's
- * "current" pointers accordingly.
+ * "current" pointers accordingly. This is done after we have obtained the
+ * current aux_head position from a successful call to perf_aux_output_begin()
+ * to make sure the hardware is writing to the right place.
+ *
+ * This function modifies buf::{cur,cur_idx,output_off} that will be programmed
+ * into PT msrs when the tracing is enabled and buf::head and buf::data_size,
+ * which are used to determine INT and STOP markers' locations by a subsequent
+ * call to pt_buffer_reset_markers().
*/
static void pt_buffer_reset_offsets(struct pt_buffer *buf, unsigned long head)
{
@@ -901,6 +901,7 @@ void intel_pt_interrupt(void)
}
pt_buffer_reset_offsets(buf, pt->handle.head);
+ /* snapshot counters don't use PMI, so it's safe */
ret = pt_buffer_reset_markers(buf, &pt->handle);
if (ret) {
perf_aux_output_end(&pt->handle, 0, true);
@@ -923,7 +924,7 @@ static void pt_event_start(struct perf_event *event, int mode)
struct pt *pt = this_cpu_ptr(&pt_ctx);
struct pt_buffer *buf = perf_get_aux(&pt->handle);
- if (pt_is_running() || !buf || pt_buffer_is_full(buf, pt)) {
+ if (!buf || pt_buffer_is_full(buf, pt)) {
event->hw.state = PERF_HES_STOPPED;
return;
}
@@ -954,7 +955,6 @@ static void pt_event_stop(struct perf_event *event, int mode)
event->hw.state = PERF_HES_STOPPED;
if (mode & PERF_EF_UPDATE) {
- struct pt *pt = this_cpu_ptr(&pt_ctx);
struct pt_buffer *buf = perf_get_aux(&pt->handle);
if (!buf)
diff --git a/arch/x86/kernel/cpu/perf_event_intel_rapl.c b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
index 358c54ad20d4..5cbd4e64feb5 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_rapl.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
@@ -204,9 +204,8 @@ again:
static void rapl_start_hrtimer(struct rapl_pmu *pmu)
{
- __hrtimer_start_range_ns(&pmu->hrtimer,
- pmu->timer_interval, 0,
- HRTIMER_MODE_REL_PINNED, 0);
+ hrtimer_start(&pmu->hrtimer, pmu->timer_interval,
+ HRTIMER_MODE_REL_PINNED);
}
static void rapl_stop_hrtimer(struct rapl_pmu *pmu)
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
index 90b7c501c95b..21b5e38c921b 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -233,9 +233,8 @@ static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
void uncore_pmu_start_hrtimer(struct intel_uncore_box *box)
{
- __hrtimer_start_range_ns(&box->hrtimer,
- ns_to_ktime(box->hrtimer_duration), 0,
- HRTIMER_MODE_REL_PINNED, 0);
+ hrtimer_start(&box->hrtimer, ns_to_ktime(box->hrtimer_duration),
+ HRTIMER_MODE_REL_PINNED);
}
void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box)
@@ -922,6 +921,9 @@ static int __init uncore_pci_init(void)
case 69: /* Haswell Celeron */
ret = hsw_uncore_pci_init();
break;
+ case 61: /* Broadwell */
+ ret = bdw_uncore_pci_init();
+ break;
default:
return 0;
}
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
index ceac8f5dc018..0f77f0a196e4 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -325,6 +325,7 @@ extern struct event_constraint uncore_constraint_empty;
int snb_uncore_pci_init(void);
int ivb_uncore_pci_init(void);
int hsw_uncore_pci_init(void);
+int bdw_uncore_pci_init(void);
void snb_uncore_cpu_init(void);
void nhm_uncore_cpu_init(void);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c
index 4562e9e22c60..b005a78c7012 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c
@@ -7,6 +7,7 @@
#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC 0x0150
#define PCI_DEVICE_ID_INTEL_HSW_IMC 0x0c00
#define PCI_DEVICE_ID_INTEL_HSW_U_IMC 0x0a04
+#define PCI_DEVICE_ID_INTEL_BDW_IMC 0x1604
/* SNB event control */
#define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff
@@ -486,6 +487,14 @@ static const struct pci_device_id hsw_uncore_pci_ids[] = {
{ /* end: all zeroes */ },
};
+static const struct pci_device_id bdw_uncore_pci_ids[] = {
+ { /* IMC */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_IMC),
+ .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+ },
+ { /* end: all zeroes */ },
+};
+
static struct pci_driver snb_uncore_pci_driver = {
.name = "snb_uncore",
.id_table = snb_uncore_pci_ids,
@@ -501,6 +510,11 @@ static struct pci_driver hsw_uncore_pci_driver = {
.id_table = hsw_uncore_pci_ids,
};
+static struct pci_driver bdw_uncore_pci_driver = {
+ .name = "bdw_uncore",
+ .id_table = bdw_uncore_pci_ids,
+};
+
struct imc_uncore_pci_dev {
__u32 pci_id;
struct pci_driver *driver;
@@ -514,6 +528,7 @@ static const struct imc_uncore_pci_dev desktop_imc_pci_ids[] = {
IMC_DEV(IVB_E3_IMC, &ivb_uncore_pci_driver), /* Xeon E3-1200 v2/3rd Gen Core processor */
IMC_DEV(HSW_IMC, &hsw_uncore_pci_driver), /* 4th Gen Core Processor */
IMC_DEV(HSW_U_IMC, &hsw_uncore_pci_driver), /* 4th Gen Core ULT Mobile Processor */
+ IMC_DEV(BDW_IMC, &bdw_uncore_pci_driver), /* 5th Gen Core U */
{ /* end marker */ }
};
@@ -561,6 +576,11 @@ int hsw_uncore_pci_init(void)
return imc_uncore_pci_init();
}
+int bdw_uncore_pci_init(void)
+{
+ return imc_uncore_pci_init();
+}
+
/* end of Sandy Bridge uncore support */
/* Nehalem uncore support */
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c
index e7d8c7608471..18ca99f2798b 100644
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -12,7 +12,8 @@ static void show_cpuinfo_core(struct seq_file *m, struct cpuinfo_x86 *c,
{
#ifdef CONFIG_SMP
seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
- seq_printf(m, "siblings\t: %d\n", cpumask_weight(cpu_core_mask(cpu)));
+ seq_printf(m, "siblings\t: %d\n",
+ cpumask_weight(topology_core_cpumask(cpu)));
seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
seq_printf(m, "apicid\t\t: %d\n", c->apicid);
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index c76d3e37c6e1..e068d6683dba 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -22,6 +22,7 @@
#include <linux/elfcore.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <asm/processor.h>
#include <asm/hardirq.h>
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
index 6367a780cc8c..5ee771859b6f 100644
--- a/arch/x86/kernel/devicetree.c
+++ b/arch/x86/kernel/devicetree.c
@@ -4,7 +4,6 @@
#include <linux/bootmem.h>
#include <linux/export.h>
#include <linux/io.h>
-#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/of.h>
@@ -17,6 +16,7 @@
#include <linux/of_pci.h>
#include <linux/initrd.h>
+#include <asm/irqdomain.h>
#include <asm/hpet.h>
#include <asm/apic.h>
#include <asm/pci_x86.h>
@@ -196,38 +196,31 @@ static struct of_ioapic_type of_ioapic_type[] =
},
};
-static int ioapic_xlate(struct irq_domain *domain,
- struct device_node *controller,
- const u32 *intspec, u32 intsize,
- irq_hw_number_t *out_hwirq, u32 *out_type)
+static int dt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
{
+ struct of_phandle_args *irq_data = (void *)arg;
struct of_ioapic_type *it;
- u32 line, idx, gsi;
+ struct irq_alloc_info tmp;
- if (WARN_ON(intsize < 2))
+ if (WARN_ON(irq_data->args_count < 2))
return -EINVAL;
-
- line = intspec[0];
-
- if (intspec[1] >= ARRAY_SIZE(of_ioapic_type))
+ if (irq_data->args[1] >= ARRAY_SIZE(of_ioapic_type))
return -EINVAL;
- it = &of_ioapic_type[intspec[1]];
+ it = &of_ioapic_type[irq_data->args[1]];
+ ioapic_set_alloc_attr(&tmp, NUMA_NO_NODE, it->trigger, it->polarity);
+ tmp.ioapic_id = mpc_ioapic_id(mp_irqdomain_ioapic_idx(domain));
+ tmp.ioapic_pin = irq_data->args[0];
- idx = (u32)(long)domain->host_data;
- gsi = mp_pin_to_gsi(idx, line);
- if (mp_set_gsi_attr(gsi, it->trigger, it->polarity, cpu_to_node(0)))
- return -EBUSY;
-
- *out_hwirq = line;
- *out_type = it->out_type;
- return 0;
+ return mp_irqdomain_alloc(domain, virq, nr_irqs, &tmp);
}
-const struct irq_domain_ops ioapic_irq_domain_ops = {
- .map = mp_irqdomain_map,
- .unmap = mp_irqdomain_unmap,
- .xlate = ioapic_xlate,
+static const struct irq_domain_ops ioapic_irq_domain_ops = {
+ .alloc = dt_irqdomain_alloc,
+ .free = mp_irqdomain_free,
+ .activate = mp_irqdomain_activate,
+ .deactivate = mp_irqdomain_deactivate,
};
static void __init dtb_add_ioapic(struct device_node *dn)
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index e2ce85db2283..c8dda42cb6a3 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -1123,7 +1123,8 @@ void __init memblock_find_dma_reserve(void)
nr_pages += end_pfn - start_pfn;
}
- for_each_free_mem_range(u, NUMA_NO_NODE, &start, &end, NULL) {
+ for_each_free_mem_range(u, NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end,
+ NULL) {
start_pfn = min_t(unsigned long, PFN_UP(start), MAX_DMA_PFN);
end_pfn = min_t(unsigned long, PFN_DOWN(end), MAX_DMA_PFN);
if (start_pfn < end_pfn)
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index fe9f0b79a18b..9f9cc682e561 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -546,6 +546,7 @@ static const struct pci_device_id intel_stolen_ids[] __initconst = {
INTEL_BDW_D_IDS(&gen8_stolen_funcs),
INTEL_CHV_IDS(&chv_stolen_funcs),
INTEL_SKL_IDS(&gen9_stolen_funcs),
+ INTEL_BXT_IDS(&gen9_stolen_funcs),
};
static void __init intel_graphics_stolen(int num, int slot, int func)
@@ -627,8 +628,12 @@ static struct chipset early_qrk[] __initdata = {
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA, PCI_ANY_ID,
QFLAG_APPLY_ONCE, intel_graphics_stolen },
/*
- * HPET on current version of Baytrail platform has accuracy
- * problems, disable it for now:
+ * HPET on the current version of the Baytrail platform has accuracy
+ * problems: it will halt in deep idle state - so we disable it.
+ *
+ * More details can be found in section 18.10.1.3 of the datasheet:
+ *
+ * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/atom-z8000-datasheet-vol-1.pdf
*/
{ PCI_VENDOR_ID_INTEL, 0x0f00,
PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet},
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
deleted file mode 100644
index 1c309763e321..000000000000
--- a/arch/x86/kernel/entry_32.S
+++ /dev/null
@@ -1,1401 +0,0 @@
-/*
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/*
- * entry.S contains the system-call and fault low-level handling routines.
- * This also contains the timer-interrupt handler, as well as all interrupts
- * and faults that can result in a task-switch.
- *
- * NOTE: This code handles signal-recognition, which happens every time
- * after a timer-interrupt and after each system call.
- *
- * I changed all the .align's to 4 (16 byte alignment), as that's faster
- * on a 486.
- *
- * Stack layout in 'syscall_exit':
- * ptrace needs to have all regs on the stack.
- * if the order here is changed, it needs to be
- * updated in fork.c:copy_process, signal.c:do_signal,
- * ptrace.c and ptrace.h
- *
- * 0(%esp) - %ebx
- * 4(%esp) - %ecx
- * 8(%esp) - %edx
- * C(%esp) - %esi
- * 10(%esp) - %edi
- * 14(%esp) - %ebp
- * 18(%esp) - %eax
- * 1C(%esp) - %ds
- * 20(%esp) - %es
- * 24(%esp) - %fs
- * 28(%esp) - %gs saved iff !CONFIG_X86_32_LAZY_GS
- * 2C(%esp) - orig_eax
- * 30(%esp) - %eip
- * 34(%esp) - %cs
- * 38(%esp) - %eflags
- * 3C(%esp) - %oldesp
- * 40(%esp) - %oldss
- *
- * "current" is in register %ebx during any slow entries.
- */
-
-#include <linux/linkage.h>
-#include <linux/err.h>
-#include <asm/thread_info.h>
-#include <asm/irqflags.h>
-#include <asm/errno.h>
-#include <asm/segment.h>
-#include <asm/smp.h>
-#include <asm/page_types.h>
-#include <asm/percpu.h>
-#include <asm/dwarf2.h>
-#include <asm/processor-flags.h>
-#include <asm/ftrace.h>
-#include <asm/irq_vectors.h>
-#include <asm/cpufeature.h>
-#include <asm/alternative-asm.h>
-#include <asm/asm.h>
-#include <asm/smap.h>
-
-/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
-#include <linux/elf-em.h>
-#define AUDIT_ARCH_I386 (EM_386|__AUDIT_ARCH_LE)
-#define __AUDIT_ARCH_LE 0x40000000
-
-#ifndef CONFIG_AUDITSYSCALL
-#define sysenter_audit syscall_trace_entry
-#define sysexit_audit syscall_exit_work
-#endif
-
- .section .entry.text, "ax"
-
-/*
- * We use macros for low-level operations which need to be overridden
- * for paravirtualization. The following will never clobber any registers:
- * INTERRUPT_RETURN (aka. "iret")
- * GET_CR0_INTO_EAX (aka. "movl %cr0, %eax")
- * ENABLE_INTERRUPTS_SYSEXIT (aka "sti; sysexit").
- *
- * For DISABLE_INTERRUPTS/ENABLE_INTERRUPTS (aka "cli"/"sti"), you must
- * specify what registers can be overwritten (CLBR_NONE, CLBR_EAX/EDX/ECX/ANY).
- * Allowing a register to be clobbered can shrink the paravirt replacement
- * enough to patch inline, increasing performance.
- */
-
-#ifdef CONFIG_PREEMPT
-#define preempt_stop(clobbers) DISABLE_INTERRUPTS(clobbers); TRACE_IRQS_OFF
-#else
-#define preempt_stop(clobbers)
-#define resume_kernel restore_all
-#endif
-
-.macro TRACE_IRQS_IRET
-#ifdef CONFIG_TRACE_IRQFLAGS
- testl $X86_EFLAGS_IF,PT_EFLAGS(%esp) # interrupts off?
- jz 1f
- TRACE_IRQS_ON
-1:
-#endif
-.endm
-
-/*
- * User gs save/restore
- *
- * %gs is used for userland TLS and kernel only uses it for stack
- * canary which is required to be at %gs:20 by gcc. Read the comment
- * at the top of stackprotector.h for more info.
- *
- * Local labels 98 and 99 are used.
- */
-#ifdef CONFIG_X86_32_LAZY_GS
-
- /* unfortunately push/pop can't be no-op */
-.macro PUSH_GS
- pushl_cfi $0
-.endm
-.macro POP_GS pop=0
- addl $(4 + \pop), %esp
- CFI_ADJUST_CFA_OFFSET -(4 + \pop)
-.endm
-.macro POP_GS_EX
-.endm
-
- /* all the rest are no-op */
-.macro PTGS_TO_GS
-.endm
-.macro PTGS_TO_GS_EX
-.endm
-.macro GS_TO_REG reg
-.endm
-.macro REG_TO_PTGS reg
-.endm
-.macro SET_KERNEL_GS reg
-.endm
-
-#else /* CONFIG_X86_32_LAZY_GS */
-
-.macro PUSH_GS
- pushl_cfi %gs
- /*CFI_REL_OFFSET gs, 0*/
-.endm
-
-.macro POP_GS pop=0
-98: popl_cfi %gs
- /*CFI_RESTORE gs*/
- .if \pop <> 0
- add $\pop, %esp
- CFI_ADJUST_CFA_OFFSET -\pop
- .endif
-.endm
-.macro POP_GS_EX
-.pushsection .fixup, "ax"
-99: movl $0, (%esp)
- jmp 98b
-.popsection
- _ASM_EXTABLE(98b,99b)
-.endm
-
-.macro PTGS_TO_GS
-98: mov PT_GS(%esp), %gs
-.endm
-.macro PTGS_TO_GS_EX
-.pushsection .fixup, "ax"
-99: movl $0, PT_GS(%esp)
- jmp 98b
-.popsection
- _ASM_EXTABLE(98b,99b)
-.endm
-
-.macro GS_TO_REG reg
- movl %gs, \reg
- /*CFI_REGISTER gs, \reg*/
-.endm
-.macro REG_TO_PTGS reg
- movl \reg, PT_GS(%esp)
- /*CFI_REL_OFFSET gs, PT_GS*/
-.endm
-.macro SET_KERNEL_GS reg
- movl $(__KERNEL_STACK_CANARY), \reg
- movl \reg, %gs
-.endm
-
-#endif /* CONFIG_X86_32_LAZY_GS */
-
-.macro SAVE_ALL
- cld
- PUSH_GS
- pushl_cfi %fs
- /*CFI_REL_OFFSET fs, 0;*/
- pushl_cfi %es
- /*CFI_REL_OFFSET es, 0;*/
- pushl_cfi %ds
- /*CFI_REL_OFFSET ds, 0;*/
- pushl_cfi %eax
- CFI_REL_OFFSET eax, 0
- pushl_cfi %ebp
- CFI_REL_OFFSET ebp, 0
- pushl_cfi %edi
- CFI_REL_OFFSET edi, 0
- pushl_cfi %esi
- CFI_REL_OFFSET esi, 0
- pushl_cfi %edx
- CFI_REL_OFFSET edx, 0
- pushl_cfi %ecx
- CFI_REL_OFFSET ecx, 0
- pushl_cfi %ebx
- CFI_REL_OFFSET ebx, 0
- movl $(__USER_DS), %edx
- movl %edx, %ds
- movl %edx, %es
- movl $(__KERNEL_PERCPU), %edx
- movl %edx, %fs
- SET_KERNEL_GS %edx
-.endm
-
-.macro RESTORE_INT_REGS
- popl_cfi %ebx
- CFI_RESTORE ebx
- popl_cfi %ecx
- CFI_RESTORE ecx
- popl_cfi %edx
- CFI_RESTORE edx
- popl_cfi %esi
- CFI_RESTORE esi
- popl_cfi %edi
- CFI_RESTORE edi
- popl_cfi %ebp
- CFI_RESTORE ebp
- popl_cfi %eax
- CFI_RESTORE eax
-.endm
-
-.macro RESTORE_REGS pop=0
- RESTORE_INT_REGS
-1: popl_cfi %ds
- /*CFI_RESTORE ds;*/
-2: popl_cfi %es
- /*CFI_RESTORE es;*/
-3: popl_cfi %fs
- /*CFI_RESTORE fs;*/
- POP_GS \pop
-.pushsection .fixup, "ax"
-4: movl $0, (%esp)
- jmp 1b
-5: movl $0, (%esp)
- jmp 2b
-6: movl $0, (%esp)
- jmp 3b
-.popsection
- _ASM_EXTABLE(1b,4b)
- _ASM_EXTABLE(2b,5b)
- _ASM_EXTABLE(3b,6b)
- POP_GS_EX
-.endm
-
-.macro RING0_INT_FRAME
- CFI_STARTPROC simple
- CFI_SIGNAL_FRAME
- CFI_DEF_CFA esp, 3*4
- /*CFI_OFFSET cs, -2*4;*/
- CFI_OFFSET eip, -3*4
-.endm
-
-.macro RING0_EC_FRAME
- CFI_STARTPROC simple
- CFI_SIGNAL_FRAME
- CFI_DEF_CFA esp, 4*4
- /*CFI_OFFSET cs, -2*4;*/
- CFI_OFFSET eip, -3*4
-.endm
-
-.macro RING0_PTREGS_FRAME
- CFI_STARTPROC simple
- CFI_SIGNAL_FRAME
- CFI_DEF_CFA esp, PT_OLDESP-PT_EBX
- /*CFI_OFFSET cs, PT_CS-PT_OLDESP;*/
- CFI_OFFSET eip, PT_EIP-PT_OLDESP
- /*CFI_OFFSET es, PT_ES-PT_OLDESP;*/
- /*CFI_OFFSET ds, PT_DS-PT_OLDESP;*/
- CFI_OFFSET eax, PT_EAX-PT_OLDESP
- CFI_OFFSET ebp, PT_EBP-PT_OLDESP
- CFI_OFFSET edi, PT_EDI-PT_OLDESP
- CFI_OFFSET esi, PT_ESI-PT_OLDESP
- CFI_OFFSET edx, PT_EDX-PT_OLDESP
- CFI_OFFSET ecx, PT_ECX-PT_OLDESP
- CFI_OFFSET ebx, PT_EBX-PT_OLDESP
-.endm
-
-ENTRY(ret_from_fork)
- CFI_STARTPROC
- pushl_cfi %eax
- call schedule_tail
- GET_THREAD_INFO(%ebp)
- popl_cfi %eax
- pushl_cfi $0x0202 # Reset kernel eflags
- popfl_cfi
- jmp syscall_exit
- CFI_ENDPROC
-END(ret_from_fork)
-
-ENTRY(ret_from_kernel_thread)
- CFI_STARTPROC
- pushl_cfi %eax
- call schedule_tail
- GET_THREAD_INFO(%ebp)
- popl_cfi %eax
- pushl_cfi $0x0202 # Reset kernel eflags
- popfl_cfi
- movl PT_EBP(%esp),%eax
- call *PT_EBX(%esp)
- movl $0,PT_EAX(%esp)
- jmp syscall_exit
- CFI_ENDPROC
-ENDPROC(ret_from_kernel_thread)
-
-/*
- * Return to user mode is not as complex as all this looks,
- * but we want the default path for a system call return to
- * go as quickly as possible which is why some of this is
- * less clear than it otherwise should be.
- */
-
- # userspace resumption stub bypassing syscall exit tracing
- ALIGN
- RING0_PTREGS_FRAME
-ret_from_exception:
- preempt_stop(CLBR_ANY)
-ret_from_intr:
- GET_THREAD_INFO(%ebp)
-#ifdef CONFIG_VM86
- movl PT_EFLAGS(%esp), %eax # mix EFLAGS and CS
- movb PT_CS(%esp), %al
- andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax
-#else
- /*
- * We can be coming here from child spawned by kernel_thread().
- */
- movl PT_CS(%esp), %eax
- andl $SEGMENT_RPL_MASK, %eax
-#endif
- cmpl $USER_RPL, %eax
- jb resume_kernel # not returning to v8086 or userspace
-
-ENTRY(resume_userspace)
- LOCKDEP_SYS_EXIT
- DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
- # setting need_resched or sigpending
- # between sampling and the iret
- TRACE_IRQS_OFF
- movl TI_flags(%ebp), %ecx
- andl $_TIF_WORK_MASK, %ecx # is there any work to be done on
- # int/exception return?
- jne work_pending
- jmp restore_all
-END(ret_from_exception)
-
-#ifdef CONFIG_PREEMPT
-ENTRY(resume_kernel)
- DISABLE_INTERRUPTS(CLBR_ANY)
-need_resched:
- cmpl $0,PER_CPU_VAR(__preempt_count)
- jnz restore_all
- testl $X86_EFLAGS_IF,PT_EFLAGS(%esp) # interrupts off (exception path) ?
- jz restore_all
- call preempt_schedule_irq
- jmp need_resched
-END(resume_kernel)
-#endif
- CFI_ENDPROC
-
-/* SYSENTER_RETURN points to after the "sysenter" instruction in
- the vsyscall page. See vsyscall-sysentry.S, which defines the symbol. */
-
- # sysenter call handler stub
-ENTRY(ia32_sysenter_target)
- CFI_STARTPROC simple
- CFI_SIGNAL_FRAME
- CFI_DEF_CFA esp, 0
- CFI_REGISTER esp, ebp
- movl TSS_sysenter_sp0(%esp),%esp
-sysenter_past_esp:
- /*
- * Interrupts are disabled here, but we can't trace it until
- * enough kernel state to call TRACE_IRQS_OFF can be called - but
- * we immediately enable interrupts at that point anyway.
- */
- pushl_cfi $__USER_DS
- /*CFI_REL_OFFSET ss, 0*/
- pushl_cfi %ebp
- CFI_REL_OFFSET esp, 0
- pushfl_cfi
- orl $X86_EFLAGS_IF, (%esp)
- pushl_cfi $__USER_CS
- /*CFI_REL_OFFSET cs, 0*/
- /*
- * Push current_thread_info()->sysenter_return to the stack.
- * A tiny bit of offset fixup is necessary: TI_sysenter_return
- * is relative to thread_info, which is at the bottom of the
- * kernel stack page. 4*4 means the 4 words pushed above;
- * TOP_OF_KERNEL_STACK_PADDING takes us to the top of the stack;
- * and THREAD_SIZE takes us to the bottom.
- */
- pushl_cfi ((TI_sysenter_return) - THREAD_SIZE + TOP_OF_KERNEL_STACK_PADDING + 4*4)(%esp)
- CFI_REL_OFFSET eip, 0
-
- pushl_cfi %eax
- SAVE_ALL
- ENABLE_INTERRUPTS(CLBR_NONE)
-
-/*
- * Load the potential sixth argument from user stack.
- * Careful about security.
- */
- cmpl $__PAGE_OFFSET-3,%ebp
- jae syscall_fault
- ASM_STAC
-1: movl (%ebp),%ebp
- ASM_CLAC
- movl %ebp,PT_EBP(%esp)
- _ASM_EXTABLE(1b,syscall_fault)
-
- GET_THREAD_INFO(%ebp)
-
- testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
- jnz sysenter_audit
-sysenter_do_call:
- cmpl $(NR_syscalls), %eax
- jae sysenter_badsys
- call *sys_call_table(,%eax,4)
-sysenter_after_call:
- movl %eax,PT_EAX(%esp)
- LOCKDEP_SYS_EXIT
- DISABLE_INTERRUPTS(CLBR_ANY)
- TRACE_IRQS_OFF
- movl TI_flags(%ebp), %ecx
- testl $_TIF_ALLWORK_MASK, %ecx
- jnz sysexit_audit
-sysenter_exit:
-/* if something modifies registers it must also disable sysexit */
- movl PT_EIP(%esp), %edx
- movl PT_OLDESP(%esp), %ecx
- xorl %ebp,%ebp
- TRACE_IRQS_ON
-1: mov PT_FS(%esp), %fs
- PTGS_TO_GS
- ENABLE_INTERRUPTS_SYSEXIT
-
-#ifdef CONFIG_AUDITSYSCALL
-sysenter_audit:
- testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
- jnz syscall_trace_entry
- /* movl PT_EAX(%esp), %eax already set, syscall number: 1st arg to audit */
- movl PT_EBX(%esp), %edx /* ebx/a0: 2nd arg to audit */
- /* movl PT_ECX(%esp), %ecx already set, a1: 3nd arg to audit */
- pushl_cfi PT_ESI(%esp) /* a3: 5th arg */
- pushl_cfi PT_EDX+4(%esp) /* a2: 4th arg */
- call __audit_syscall_entry
- popl_cfi %ecx /* get that remapped edx off the stack */
- popl_cfi %ecx /* get that remapped esi off the stack */
- movl PT_EAX(%esp),%eax /* reload syscall number */
- jmp sysenter_do_call
-
-sysexit_audit:
- testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %ecx
- jnz syscall_exit_work
- TRACE_IRQS_ON
- ENABLE_INTERRUPTS(CLBR_ANY)
- movl %eax,%edx /* second arg, syscall return value */
- cmpl $-MAX_ERRNO,%eax /* is it an error ? */
- setbe %al /* 1 if so, 0 if not */
- movzbl %al,%eax /* zero-extend that */
- call __audit_syscall_exit
- DISABLE_INTERRUPTS(CLBR_ANY)
- TRACE_IRQS_OFF
- movl TI_flags(%ebp), %ecx
- testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %ecx
- jnz syscall_exit_work
- movl PT_EAX(%esp),%eax /* reload syscall return value */
- jmp sysenter_exit
-#endif
-
- CFI_ENDPROC
-.pushsection .fixup,"ax"
-2: movl $0,PT_FS(%esp)
- jmp 1b
-.popsection
- _ASM_EXTABLE(1b,2b)
- PTGS_TO_GS_EX
-ENDPROC(ia32_sysenter_target)
-
- # system call handler stub
-ENTRY(system_call)
- RING0_INT_FRAME # can't unwind into user space anyway
- ASM_CLAC
- pushl_cfi %eax # save orig_eax
- SAVE_ALL
- GET_THREAD_INFO(%ebp)
- # system call tracing in operation / emulation
- testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
- jnz syscall_trace_entry
- cmpl $(NR_syscalls), %eax
- jae syscall_badsys
-syscall_call:
- call *sys_call_table(,%eax,4)
-syscall_after_call:
- movl %eax,PT_EAX(%esp) # store the return value
-syscall_exit:
- LOCKDEP_SYS_EXIT
- DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
- # setting need_resched or sigpending
- # between sampling and the iret
- TRACE_IRQS_OFF
- movl TI_flags(%ebp), %ecx
- testl $_TIF_ALLWORK_MASK, %ecx # current->work
- jnz syscall_exit_work
-
-restore_all:
- TRACE_IRQS_IRET
-restore_all_notrace:
-#ifdef CONFIG_X86_ESPFIX32
- movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
- # Warning: PT_OLDSS(%esp) contains the wrong/random values if we
- # are returning to the kernel.
- # See comments in process.c:copy_thread() for details.
- movb PT_OLDSS(%esp), %ah
- movb PT_CS(%esp), %al
- andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
- cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
- CFI_REMEMBER_STATE
- je ldt_ss # returning to user-space with LDT SS
-#endif
-restore_nocheck:
- RESTORE_REGS 4 # skip orig_eax/error_code
-irq_return:
- INTERRUPT_RETURN
-.section .fixup,"ax"
-ENTRY(iret_exc)
- pushl $0 # no error code
- pushl $do_iret_error
- jmp error_code
-.previous
- _ASM_EXTABLE(irq_return,iret_exc)
-
-#ifdef CONFIG_X86_ESPFIX32
- CFI_RESTORE_STATE
-ldt_ss:
-#ifdef CONFIG_PARAVIRT
- /*
- * The kernel can't run on a non-flat stack if paravirt mode
- * is active. Rather than try to fixup the high bits of
- * ESP, bypass this code entirely. This may break DOSemu
- * and/or Wine support in a paravirt VM, although the option
- * is still available to implement the setting of the high
- * 16-bits in the INTERRUPT_RETURN paravirt-op.
- */
- cmpl $0, pv_info+PARAVIRT_enabled
- jne restore_nocheck
-#endif
-
-/*
- * Setup and switch to ESPFIX stack
- *
- * We're returning to userspace with a 16 bit stack. The CPU will not
- * restore the high word of ESP for us on executing iret... This is an
- * "official" bug of all the x86-compatible CPUs, which we can work
- * around to make dosemu and wine happy. We do this by preloading the
- * high word of ESP with the high word of the userspace ESP while
- * compensating for the offset by changing to the ESPFIX segment with
- * a base address that matches for the difference.
- */
-#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + (GDT_ENTRY_ESPFIX_SS * 8)
- mov %esp, %edx /* load kernel esp */
- mov PT_OLDESP(%esp), %eax /* load userspace esp */
- mov %dx, %ax /* eax: new kernel esp */
- sub %eax, %edx /* offset (low word is 0) */
- shr $16, %edx
- mov %dl, GDT_ESPFIX_SS + 4 /* bits 16..23 */
- mov %dh, GDT_ESPFIX_SS + 7 /* bits 24..31 */
- pushl_cfi $__ESPFIX_SS
- pushl_cfi %eax /* new kernel esp */
- /* Disable interrupts, but do not irqtrace this section: we
- * will soon execute iret and the tracer was already set to
- * the irqstate after the iret */
- DISABLE_INTERRUPTS(CLBR_EAX)
- lss (%esp), %esp /* switch to espfix segment */
- CFI_ADJUST_CFA_OFFSET -8
- jmp restore_nocheck
-#endif
- CFI_ENDPROC
-ENDPROC(system_call)
-
- # perform work that needs to be done immediately before resumption
- ALIGN
- RING0_PTREGS_FRAME # can't unwind into user space anyway
-work_pending:
- testb $_TIF_NEED_RESCHED, %cl
- jz work_notifysig
-work_resched:
- call schedule
- LOCKDEP_SYS_EXIT
- DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
- # setting need_resched or sigpending
- # between sampling and the iret
- TRACE_IRQS_OFF
- movl TI_flags(%ebp), %ecx
- andl $_TIF_WORK_MASK, %ecx # is there any work to be done other
- # than syscall tracing?
- jz restore_all
- testb $_TIF_NEED_RESCHED, %cl
- jnz work_resched
-
-work_notifysig: # deal with pending signals and
- # notify-resume requests
-#ifdef CONFIG_VM86
- testl $X86_EFLAGS_VM, PT_EFLAGS(%esp)
- movl %esp, %eax
- jnz work_notifysig_v86 # returning to kernel-space or
- # vm86-space
-1:
-#else
- movl %esp, %eax
-#endif
- TRACE_IRQS_ON
- ENABLE_INTERRUPTS(CLBR_NONE)
- movb PT_CS(%esp), %bl
- andb $SEGMENT_RPL_MASK, %bl
- cmpb $USER_RPL, %bl
- jb resume_kernel
- xorl %edx, %edx
- call do_notify_resume
- jmp resume_userspace
-
-#ifdef CONFIG_VM86
- ALIGN
-work_notifysig_v86:
- pushl_cfi %ecx # save ti_flags for do_notify_resume
- call save_v86_state # %eax contains pt_regs pointer
- popl_cfi %ecx
- movl %eax, %esp
- jmp 1b
-#endif
-END(work_pending)
-
- # perform syscall exit tracing
- ALIGN
-syscall_trace_entry:
- movl $-ENOSYS,PT_EAX(%esp)
- movl %esp, %eax
- call syscall_trace_enter
- /* What it returned is what we'll actually use. */
- cmpl $(NR_syscalls), %eax
- jnae syscall_call
- jmp syscall_exit
-END(syscall_trace_entry)
-
- # perform syscall exit tracing
- ALIGN
-syscall_exit_work:
- testl $_TIF_WORK_SYSCALL_EXIT, %ecx
- jz work_pending
- TRACE_IRQS_ON
- ENABLE_INTERRUPTS(CLBR_ANY) # could let syscall_trace_leave() call
- # schedule() instead
- movl %esp, %eax
- call syscall_trace_leave
- jmp resume_userspace
-END(syscall_exit_work)
- CFI_ENDPROC
-
- RING0_INT_FRAME # can't unwind into user space anyway
-syscall_fault:
- ASM_CLAC
- GET_THREAD_INFO(%ebp)
- movl $-EFAULT,PT_EAX(%esp)
- jmp resume_userspace
-END(syscall_fault)
-
-syscall_badsys:
- movl $-ENOSYS,%eax
- jmp syscall_after_call
-END(syscall_badsys)
-
-sysenter_badsys:
- movl $-ENOSYS,%eax
- jmp sysenter_after_call
-END(sysenter_badsys)
- CFI_ENDPROC
-
-.macro FIXUP_ESPFIX_STACK
-/*
- * Switch back for ESPFIX stack to the normal zerobased stack
- *
- * We can't call C functions using the ESPFIX stack. This code reads
- * the high word of the segment base from the GDT and swiches to the
- * normal stack and adjusts ESP with the matching offset.
- */
-#ifdef CONFIG_X86_ESPFIX32
- /* fixup the stack */
- mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */
- mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
- shl $16, %eax
- addl %esp, %eax /* the adjusted stack pointer */
- pushl_cfi $__KERNEL_DS
- pushl_cfi %eax
- lss (%esp), %esp /* switch to the normal stack segment */
- CFI_ADJUST_CFA_OFFSET -8
-#endif
-.endm
-.macro UNWIND_ESPFIX_STACK
-#ifdef CONFIG_X86_ESPFIX32
- movl %ss, %eax
- /* see if on espfix stack */
- cmpw $__ESPFIX_SS, %ax
- jne 27f
- movl $__KERNEL_DS, %eax
- movl %eax, %ds
- movl %eax, %es
- /* switch to normal stack */
- FIXUP_ESPFIX_STACK
-27:
-#endif
-.endm
-
-/*
- * Build the entry stubs with some assembler magic.
- * We pack 1 stub into every 8-byte block.
- */
- .align 8
-ENTRY(irq_entries_start)
- RING0_INT_FRAME
- vector=FIRST_EXTERNAL_VECTOR
- .rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
- pushl_cfi $(~vector+0x80) /* Note: always in signed byte range */
- vector=vector+1
- jmp common_interrupt
- CFI_ADJUST_CFA_OFFSET -4
- .align 8
- .endr
-END(irq_entries_start)
-
-/*
- * the CPU automatically disables interrupts when executing an IRQ vector,
- * so IRQ-flags tracing has to follow that:
- */
- .p2align CONFIG_X86_L1_CACHE_SHIFT
-common_interrupt:
- ASM_CLAC
- addl $-0x80,(%esp) /* Adjust vector into the [-256,-1] range */
- SAVE_ALL
- TRACE_IRQS_OFF
- movl %esp,%eax
- call do_IRQ
- jmp ret_from_intr
-ENDPROC(common_interrupt)
- CFI_ENDPROC
-
-#define BUILD_INTERRUPT3(name, nr, fn) \
-ENTRY(name) \
- RING0_INT_FRAME; \
- ASM_CLAC; \
- pushl_cfi $~(nr); \
- SAVE_ALL; \
- TRACE_IRQS_OFF \
- movl %esp,%eax; \
- call fn; \
- jmp ret_from_intr; \
- CFI_ENDPROC; \
-ENDPROC(name)
-
-
-#ifdef CONFIG_TRACING
-#define TRACE_BUILD_INTERRUPT(name, nr) \
- BUILD_INTERRUPT3(trace_##name, nr, smp_trace_##name)
-#else
-#define TRACE_BUILD_INTERRUPT(name, nr)
-#endif
-
-#define BUILD_INTERRUPT(name, nr) \
- BUILD_INTERRUPT3(name, nr, smp_##name); \
- TRACE_BUILD_INTERRUPT(name, nr)
-
-/* The include is where all of the SMP etc. interrupts come from */
-#include <asm/entry_arch.h>
-
-ENTRY(coprocessor_error)
- RING0_INT_FRAME
- ASM_CLAC
- pushl_cfi $0
- pushl_cfi $do_coprocessor_error
- jmp error_code
- CFI_ENDPROC
-END(coprocessor_error)
-
-ENTRY(simd_coprocessor_error)
- RING0_INT_FRAME
- ASM_CLAC
- pushl_cfi $0
-#ifdef CONFIG_X86_INVD_BUG
- /* AMD 486 bug: invd from userspace calls exception 19 instead of #GP */
- ALTERNATIVE "pushl_cfi $do_general_protection", \
- "pushl $do_simd_coprocessor_error", \
- X86_FEATURE_XMM
-#else
- pushl_cfi $do_simd_coprocessor_error
-#endif
- jmp error_code
- CFI_ENDPROC
-END(simd_coprocessor_error)
-
-ENTRY(device_not_available)
- RING0_INT_FRAME
- ASM_CLAC
- pushl_cfi $-1 # mark this as an int
- pushl_cfi $do_device_not_available
- jmp error_code
- CFI_ENDPROC
-END(device_not_available)
-
-#ifdef CONFIG_PARAVIRT
-ENTRY(native_iret)
- iret
- _ASM_EXTABLE(native_iret, iret_exc)
-END(native_iret)
-
-ENTRY(native_irq_enable_sysexit)
- sti
- sysexit
-END(native_irq_enable_sysexit)
-#endif
-
-ENTRY(overflow)
- RING0_INT_FRAME
- ASM_CLAC
- pushl_cfi $0
- pushl_cfi $do_overflow
- jmp error_code
- CFI_ENDPROC
-END(overflow)
-
-ENTRY(bounds)
- RING0_INT_FRAME
- ASM_CLAC
- pushl_cfi $0
- pushl_cfi $do_bounds
- jmp error_code
- CFI_ENDPROC
-END(bounds)
-
-ENTRY(invalid_op)
- RING0_INT_FRAME
- ASM_CLAC
- pushl_cfi $0
- pushl_cfi $do_invalid_op
- jmp error_code
- CFI_ENDPROC
-END(invalid_op)
-
-ENTRY(coprocessor_segment_overrun)
- RING0_INT_FRAME
- ASM_CLAC
- pushl_cfi $0
- pushl_cfi $do_coprocessor_segment_overrun
- jmp error_code
- CFI_ENDPROC
-END(coprocessor_segment_overrun)
-
-ENTRY(invalid_TSS)
- RING0_EC_FRAME
- ASM_CLAC
- pushl_cfi $do_invalid_TSS
- jmp error_code
- CFI_ENDPROC
-END(invalid_TSS)
-
-ENTRY(segment_not_present)
- RING0_EC_FRAME
- ASM_CLAC
- pushl_cfi $do_segment_not_present
- jmp error_code
- CFI_ENDPROC
-END(segment_not_present)
-
-ENTRY(stack_segment)
- RING0_EC_FRAME
- ASM_CLAC
- pushl_cfi $do_stack_segment
- jmp error_code
- CFI_ENDPROC
-END(stack_segment)
-
-ENTRY(alignment_check)
- RING0_EC_FRAME
- ASM_CLAC
- pushl_cfi $do_alignment_check
- jmp error_code
- CFI_ENDPROC
-END(alignment_check)
-
-ENTRY(divide_error)
- RING0_INT_FRAME
- ASM_CLAC
- pushl_cfi $0 # no error code
- pushl_cfi $do_divide_error
- jmp error_code
- CFI_ENDPROC
-END(divide_error)
-
-#ifdef CONFIG_X86_MCE
-ENTRY(machine_check)
- RING0_INT_FRAME
- ASM_CLAC
- pushl_cfi $0
- pushl_cfi machine_check_vector
- jmp error_code
- CFI_ENDPROC
-END(machine_check)
-#endif
-
-ENTRY(spurious_interrupt_bug)
- RING0_INT_FRAME
- ASM_CLAC
- pushl_cfi $0
- pushl_cfi $do_spurious_interrupt_bug
- jmp error_code
- CFI_ENDPROC
-END(spurious_interrupt_bug)
-
-#ifdef CONFIG_XEN
-/* Xen doesn't set %esp to be precisely what the normal sysenter
- entrypoint expects, so fix it up before using the normal path. */
-ENTRY(xen_sysenter_target)
- RING0_INT_FRAME
- addl $5*4, %esp /* remove xen-provided frame */
- CFI_ADJUST_CFA_OFFSET -5*4
- jmp sysenter_past_esp
- CFI_ENDPROC
-
-ENTRY(xen_hypervisor_callback)
- CFI_STARTPROC
- pushl_cfi $-1 /* orig_ax = -1 => not a system call */
- SAVE_ALL
- TRACE_IRQS_OFF
-
- /* Check to see if we got the event in the critical
- region in xen_iret_direct, after we've reenabled
- events and checked for pending events. This simulates
- iret instruction's behaviour where it delivers a
- pending interrupt when enabling interrupts. */
- movl PT_EIP(%esp),%eax
- cmpl $xen_iret_start_crit,%eax
- jb 1f
- cmpl $xen_iret_end_crit,%eax
- jae 1f
-
- jmp xen_iret_crit_fixup
-
-ENTRY(xen_do_upcall)
-1: mov %esp, %eax
- call xen_evtchn_do_upcall
-#ifndef CONFIG_PREEMPT
- call xen_maybe_preempt_hcall
-#endif
- jmp ret_from_intr
- CFI_ENDPROC
-ENDPROC(xen_hypervisor_callback)
-
-# Hypervisor uses this for application faults while it executes.
-# We get here for two reasons:
-# 1. Fault while reloading DS, ES, FS or GS
-# 2. Fault while executing IRET
-# Category 1 we fix up by reattempting the load, and zeroing the segment
-# register if the load fails.
-# Category 2 we fix up by jumping to do_iret_error. We cannot use the
-# normal Linux return path in this case because if we use the IRET hypercall
-# to pop the stack frame we end up in an infinite loop of failsafe callbacks.
-# We distinguish between categories by maintaining a status value in EAX.
-ENTRY(xen_failsafe_callback)
- CFI_STARTPROC
- pushl_cfi %eax
- movl $1,%eax
-1: mov 4(%esp),%ds
-2: mov 8(%esp),%es
-3: mov 12(%esp),%fs
-4: mov 16(%esp),%gs
- /* EAX == 0 => Category 1 (Bad segment)
- EAX != 0 => Category 2 (Bad IRET) */
- testl %eax,%eax
- popl_cfi %eax
- lea 16(%esp),%esp
- CFI_ADJUST_CFA_OFFSET -16
- jz 5f
- jmp iret_exc
-5: pushl_cfi $-1 /* orig_ax = -1 => not a system call */
- SAVE_ALL
- jmp ret_from_exception
- CFI_ENDPROC
-
-.section .fixup,"ax"
-6: xorl %eax,%eax
- movl %eax,4(%esp)
- jmp 1b
-7: xorl %eax,%eax
- movl %eax,8(%esp)
- jmp 2b
-8: xorl %eax,%eax
- movl %eax,12(%esp)
- jmp 3b
-9: xorl %eax,%eax
- movl %eax,16(%esp)
- jmp 4b
-.previous
- _ASM_EXTABLE(1b,6b)
- _ASM_EXTABLE(2b,7b)
- _ASM_EXTABLE(3b,8b)
- _ASM_EXTABLE(4b,9b)
-ENDPROC(xen_failsafe_callback)
-
-BUILD_INTERRUPT3(xen_hvm_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
- xen_evtchn_do_upcall)
-
-#endif /* CONFIG_XEN */
-
-#if IS_ENABLED(CONFIG_HYPERV)
-
-BUILD_INTERRUPT3(hyperv_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
- hyperv_vector_handler)
-
-#endif /* CONFIG_HYPERV */
-
-#ifdef CONFIG_FUNCTION_TRACER
-#ifdef CONFIG_DYNAMIC_FTRACE
-
-ENTRY(mcount)
- ret
-END(mcount)
-
-ENTRY(ftrace_caller)
- pushl %eax
- pushl %ecx
- pushl %edx
- pushl $0 /* Pass NULL as regs pointer */
- movl 4*4(%esp), %eax
- movl 0x4(%ebp), %edx
- movl function_trace_op, %ecx
- subl $MCOUNT_INSN_SIZE, %eax
-
-.globl ftrace_call
-ftrace_call:
- call ftrace_stub
-
- addl $4,%esp /* skip NULL pointer */
- popl %edx
- popl %ecx
- popl %eax
-ftrace_ret:
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-.globl ftrace_graph_call
-ftrace_graph_call:
- jmp ftrace_stub
-#endif
-
-.globl ftrace_stub
-ftrace_stub:
- ret
-END(ftrace_caller)
-
-ENTRY(ftrace_regs_caller)
- pushf /* push flags before compare (in cs location) */
-
- /*
- * i386 does not save SS and ESP when coming from kernel.
- * Instead, to get sp, &regs->sp is used (see ptrace.h).
- * Unfortunately, that means eflags must be at the same location
- * as the current return ip is. We move the return ip into the
- * ip location, and move flags into the return ip location.
- */
- pushl 4(%esp) /* save return ip into ip slot */
-
- pushl $0 /* Load 0 into orig_ax */
- pushl %gs
- pushl %fs
- pushl %es
- pushl %ds
- pushl %eax
- pushl %ebp
- pushl %edi
- pushl %esi
- pushl %edx
- pushl %ecx
- pushl %ebx
-
- movl 13*4(%esp), %eax /* Get the saved flags */
- movl %eax, 14*4(%esp) /* Move saved flags into regs->flags location */
- /* clobbering return ip */
- movl $__KERNEL_CS,13*4(%esp)
-
- movl 12*4(%esp), %eax /* Load ip (1st parameter) */
- subl $MCOUNT_INSN_SIZE, %eax /* Adjust ip */
- movl 0x4(%ebp), %edx /* Load parent ip (2nd parameter) */
- movl function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */
- pushl %esp /* Save pt_regs as 4th parameter */
-
-GLOBAL(ftrace_regs_call)
- call ftrace_stub
-
- addl $4, %esp /* Skip pt_regs */
- movl 14*4(%esp), %eax /* Move flags back into cs */
- movl %eax, 13*4(%esp) /* Needed to keep addl from modifying flags */
- movl 12*4(%esp), %eax /* Get return ip from regs->ip */
- movl %eax, 14*4(%esp) /* Put return ip back for ret */
-
- popl %ebx
- popl %ecx
- popl %edx
- popl %esi
- popl %edi
- popl %ebp
- popl %eax
- popl %ds
- popl %es
- popl %fs
- popl %gs
- addl $8, %esp /* Skip orig_ax and ip */
- popf /* Pop flags at end (no addl to corrupt flags) */
- jmp ftrace_ret
-
- popf
- jmp ftrace_stub
-#else /* ! CONFIG_DYNAMIC_FTRACE */
-
-ENTRY(mcount)
- cmpl $__PAGE_OFFSET, %esp
- jb ftrace_stub /* Paging not enabled yet? */
-
- cmpl $ftrace_stub, ftrace_trace_function
- jnz trace
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
- cmpl $ftrace_stub, ftrace_graph_return
- jnz ftrace_graph_caller
-
- cmpl $ftrace_graph_entry_stub, ftrace_graph_entry
- jnz ftrace_graph_caller
-#endif
-.globl ftrace_stub
-ftrace_stub:
- ret
-
- /* taken from glibc */
-trace:
- pushl %eax
- pushl %ecx
- pushl %edx
- movl 0xc(%esp), %eax
- movl 0x4(%ebp), %edx
- subl $MCOUNT_INSN_SIZE, %eax
-
- call *ftrace_trace_function
-
- popl %edx
- popl %ecx
- popl %eax
- jmp ftrace_stub
-END(mcount)
-#endif /* CONFIG_DYNAMIC_FTRACE */
-#endif /* CONFIG_FUNCTION_TRACER */
-
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-ENTRY(ftrace_graph_caller)
- pushl %eax
- pushl %ecx
- pushl %edx
- movl 0xc(%esp), %eax
- lea 0x4(%ebp), %edx
- movl (%ebp), %ecx
- subl $MCOUNT_INSN_SIZE, %eax
- call prepare_ftrace_return
- popl %edx
- popl %ecx
- popl %eax
- ret
-END(ftrace_graph_caller)
-
-.globl return_to_handler
-return_to_handler:
- pushl %eax
- pushl %edx
- movl %ebp, %eax
- call ftrace_return_to_handler
- movl %eax, %ecx
- popl %edx
- popl %eax
- jmp *%ecx
-#endif
-
-#ifdef CONFIG_TRACING
-ENTRY(trace_page_fault)
- RING0_EC_FRAME
- ASM_CLAC
- pushl_cfi $trace_do_page_fault
- jmp error_code
- CFI_ENDPROC
-END(trace_page_fault)
-#endif
-
-ENTRY(page_fault)
- RING0_EC_FRAME
- ASM_CLAC
- pushl_cfi $do_page_fault
- ALIGN
-error_code:
- /* the function address is in %gs's slot on the stack */
- pushl_cfi %fs
- /*CFI_REL_OFFSET fs, 0*/
- pushl_cfi %es
- /*CFI_REL_OFFSET es, 0*/
- pushl_cfi %ds
- /*CFI_REL_OFFSET ds, 0*/
- pushl_cfi_reg eax
- pushl_cfi_reg ebp
- pushl_cfi_reg edi
- pushl_cfi_reg esi
- pushl_cfi_reg edx
- pushl_cfi_reg ecx
- pushl_cfi_reg ebx
- cld
- movl $(__KERNEL_PERCPU), %ecx
- movl %ecx, %fs
- UNWIND_ESPFIX_STACK
- GS_TO_REG %ecx
- movl PT_GS(%esp), %edi # get the function address
- movl PT_ORIG_EAX(%esp), %edx # get the error code
- movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart
- REG_TO_PTGS %ecx
- SET_KERNEL_GS %ecx
- movl $(__USER_DS), %ecx
- movl %ecx, %ds
- movl %ecx, %es
- TRACE_IRQS_OFF
- movl %esp,%eax # pt_regs pointer
- call *%edi
- jmp ret_from_exception
- CFI_ENDPROC
-END(page_fault)
-
-/*
- * Debug traps and NMI can happen at the one SYSENTER instruction
- * that sets up the real kernel stack. Check here, since we can't
- * allow the wrong stack to be used.
- *
- * "TSS_sysenter_sp0+12" is because the NMI/debug handler will have
- * already pushed 3 words if it hits on the sysenter instruction:
- * eflags, cs and eip.
- *
- * We just load the right stack, and push the three (known) values
- * by hand onto the new stack - while updating the return eip past
- * the instruction that would have done it for sysenter.
- */
-.macro FIX_STACK offset ok label
- cmpw $__KERNEL_CS, 4(%esp)
- jne \ok
-\label:
- movl TSS_sysenter_sp0 + \offset(%esp), %esp
- CFI_DEF_CFA esp, 0
- CFI_UNDEFINED eip
- pushfl_cfi
- pushl_cfi $__KERNEL_CS
- pushl_cfi $sysenter_past_esp
- CFI_REL_OFFSET eip, 0
-.endm
-
-ENTRY(debug)
- RING0_INT_FRAME
- ASM_CLAC
- cmpl $ia32_sysenter_target,(%esp)
- jne debug_stack_correct
- FIX_STACK 12, debug_stack_correct, debug_esp_fix_insn
-debug_stack_correct:
- pushl_cfi $-1 # mark this as an int
- SAVE_ALL
- TRACE_IRQS_OFF
- xorl %edx,%edx # error code 0
- movl %esp,%eax # pt_regs pointer
- call do_debug
- jmp ret_from_exception
- CFI_ENDPROC
-END(debug)
-
-/*
- * NMI is doubly nasty. It can happen _while_ we're handling
- * a debug fault, and the debug fault hasn't yet been able to
- * clear up the stack. So we first check whether we got an
- * NMI on the sysenter entry path, but after that we need to
- * check whether we got an NMI on the debug path where the debug
- * fault happened on the sysenter path.
- */
-ENTRY(nmi)
- RING0_INT_FRAME
- ASM_CLAC
-#ifdef CONFIG_X86_ESPFIX32
- pushl_cfi %eax
- movl %ss, %eax
- cmpw $__ESPFIX_SS, %ax
- popl_cfi %eax
- je nmi_espfix_stack
-#endif
- cmpl $ia32_sysenter_target,(%esp)
- je nmi_stack_fixup
- pushl_cfi %eax
- movl %esp,%eax
- /* Do not access memory above the end of our stack page,
- * it might not exist.
- */
- andl $(THREAD_SIZE-1),%eax
- cmpl $(THREAD_SIZE-20),%eax
- popl_cfi %eax
- jae nmi_stack_correct
- cmpl $ia32_sysenter_target,12(%esp)
- je nmi_debug_stack_check
-nmi_stack_correct:
- /* We have a RING0_INT_FRAME here */
- pushl_cfi %eax
- SAVE_ALL
- xorl %edx,%edx # zero error code
- movl %esp,%eax # pt_regs pointer
- call do_nmi
- jmp restore_all_notrace
- CFI_ENDPROC
-
-nmi_stack_fixup:
- RING0_INT_FRAME
- FIX_STACK 12, nmi_stack_correct, 1
- jmp nmi_stack_correct
-
-nmi_debug_stack_check:
- /* We have a RING0_INT_FRAME here */
- cmpw $__KERNEL_CS,16(%esp)
- jne nmi_stack_correct
- cmpl $debug,(%esp)
- jb nmi_stack_correct
- cmpl $debug_esp_fix_insn,(%esp)
- ja nmi_stack_correct
- FIX_STACK 24, nmi_stack_correct, 1
- jmp nmi_stack_correct
-
-#ifdef CONFIG_X86_ESPFIX32
-nmi_espfix_stack:
- /* We have a RING0_INT_FRAME here.
- *
- * create the pointer to lss back
- */
- pushl_cfi %ss
- pushl_cfi %esp
- addl $4, (%esp)
- /* copy the iret frame of 12 bytes */
- .rept 3
- pushl_cfi 16(%esp)
- .endr
- pushl_cfi %eax
- SAVE_ALL
- FIXUP_ESPFIX_STACK # %eax == %esp
- xorl %edx,%edx # zero error code
- call do_nmi
- RESTORE_REGS
- lss 12+4(%esp), %esp # back to espfix stack
- CFI_ADJUST_CFA_OFFSET -24
- jmp irq_return
-#endif
- CFI_ENDPROC
-END(nmi)
-
-ENTRY(int3)
- RING0_INT_FRAME
- ASM_CLAC
- pushl_cfi $-1 # mark this as an int
- SAVE_ALL
- TRACE_IRQS_OFF
- xorl %edx,%edx # zero error code
- movl %esp,%eax # pt_regs pointer
- call do_int3
- jmp ret_from_exception
- CFI_ENDPROC
-END(int3)
-
-ENTRY(general_protection)
- RING0_EC_FRAME
- pushl_cfi $do_general_protection
- jmp error_code
- CFI_ENDPROC
-END(general_protection)
-
-#ifdef CONFIG_KVM_GUEST
-ENTRY(async_page_fault)
- RING0_EC_FRAME
- ASM_CLAC
- pushl_cfi $do_async_page_fault
- jmp error_code
- CFI_ENDPROC
-END(async_page_fault)
-#endif
-
diff --git a/arch/x86/kernel/fpu/Makefile b/arch/x86/kernel/fpu/Makefile
new file mode 100644
index 000000000000..68279efb811a
--- /dev/null
+++ b/arch/x86/kernel/fpu/Makefile
@@ -0,0 +1,5 @@
+#
+# Build rules for the FPU support code:
+#
+
+obj-y += init.o bugs.o core.o regset.o signal.o xstate.o
diff --git a/arch/x86/kernel/fpu/bugs.c b/arch/x86/kernel/fpu/bugs.c
new file mode 100644
index 000000000000..dd9ca9b60ff3
--- /dev/null
+++ b/arch/x86/kernel/fpu/bugs.c
@@ -0,0 +1,71 @@
+/*
+ * x86 FPU bug checks:
+ */
+#include <asm/fpu/internal.h>
+
+/*
+ * Boot time CPU/FPU FDIV bug detection code:
+ */
+
+static double __initdata x = 4195835.0;
+static double __initdata y = 3145727.0;
+
+/*
+ * This used to check for exceptions..
+ * However, it turns out that to support that,
+ * the XMM trap handlers basically had to
+ * be buggy. So let's have a correct XMM trap
+ * handler, and forget about printing out
+ * some status at boot.
+ *
+ * We should really only care about bugs here
+ * anyway. Not features.
+ */
+static void __init check_fpu(void)
+{
+ u32 cr0_saved;
+ s32 fdiv_bug;
+
+ /* We might have CR0::TS set already, clear it: */
+ cr0_saved = read_cr0();
+ write_cr0(cr0_saved & ~X86_CR0_TS);
+
+ kernel_fpu_begin();
+
+ /*
+ * trap_init() enabled FXSR and company _before_ testing for FP
+ * problems here.
+ *
+ * Test for the divl bug: http://en.wikipedia.org/wiki/Fdiv_bug
+ */
+ __asm__("fninit\n\t"
+ "fldl %1\n\t"
+ "fdivl %2\n\t"
+ "fmull %2\n\t"
+ "fldl %1\n\t"
+ "fsubp %%st,%%st(1)\n\t"
+ "fistpl %0\n\t"
+ "fwait\n\t"
+ "fninit"
+ : "=m" (*&fdiv_bug)
+ : "m" (*&x), "m" (*&y));
+
+ kernel_fpu_end();
+
+ write_cr0(cr0_saved);
+
+ if (fdiv_bug) {
+ set_cpu_bug(&boot_cpu_data, X86_BUG_FDIV);
+ pr_warn("Hmm, FPU with FDIV bug\n");
+ }
+}
+
+void __init fpu__init_check_bugs(void)
+{
+ /*
+ * kernel_fpu_begin/end() in check_fpu() relies on the patched
+ * alternative instructions.
+ */
+ if (cpu_has_fpu)
+ check_fpu();
+}
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
new file mode 100644
index 000000000000..79de954626fd
--- /dev/null
+++ b/arch/x86/kernel/fpu/core.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 1994 Linus Torvalds
+ *
+ * Pentium III FXSR, SSE support
+ * General FPU state handling cleanups
+ * Gareth Hughes <gareth@valinux.com>, May 2000
+ */
+#include <asm/fpu/internal.h>
+#include <asm/fpu/regset.h>
+#include <asm/fpu/signal.h>
+#include <asm/traps.h>
+
+#include <linux/hardirq.h>
+
+/*
+ * Represents the initial FPU state. It's mostly (but not completely) zeroes,
+ * depending on the FPU hardware format:
+ */
+union fpregs_state init_fpstate __read_mostly;
+
+/*
+ * Track whether the kernel is using the FPU state
+ * currently.
+ *
+ * This flag is used:
+ *
+ * - by IRQ context code to potentially use the FPU
+ * if it's unused.
+ *
+ * - to debug kernel_fpu_begin()/end() correctness
+ */
+static DEFINE_PER_CPU(bool, in_kernel_fpu);
+
+/*
+ * Track which context is using the FPU on the CPU:
+ */
+DEFINE_PER_CPU(struct fpu *, fpu_fpregs_owner_ctx);
+
+static void kernel_fpu_disable(void)
+{
+ WARN_ON_FPU(this_cpu_read(in_kernel_fpu));
+ this_cpu_write(in_kernel_fpu, true);
+}
+
+static void kernel_fpu_enable(void)
+{
+ WARN_ON_FPU(!this_cpu_read(in_kernel_fpu));
+ this_cpu_write(in_kernel_fpu, false);
+}
+
+static bool kernel_fpu_disabled(void)
+{
+ return this_cpu_read(in_kernel_fpu);
+}
+
+/*
+ * Were we in an interrupt that interrupted kernel mode?
+ *
+ * On others, we can do a kernel_fpu_begin/end() pair *ONLY* if that
+ * pair does nothing at all: the thread must not have fpu (so
+ * that we don't try to save the FPU state), and TS must
+ * be set (so that the clts/stts pair does nothing that is
+ * visible in the interrupted kernel thread).
+ *
+ * Except for the eagerfpu case when we return true; in the likely case
+ * the thread has FPU but we are not going to set/clear TS.
+ */
+static bool interrupted_kernel_fpu_idle(void)
+{
+ if (kernel_fpu_disabled())
+ return false;
+
+ if (use_eager_fpu())
+ return true;
+
+ return !current->thread.fpu.fpregs_active && (read_cr0() & X86_CR0_TS);
+}
+
+/*
+ * Were we in user mode (or vm86 mode) when we were
+ * interrupted?
+ *
+ * Doing kernel_fpu_begin/end() is ok if we are running
+ * in an interrupt context from user mode - we'll just
+ * save the FPU state as required.
+ */
+static bool interrupted_user_mode(void)
+{
+ struct pt_regs *regs = get_irq_regs();
+ return regs && user_mode(regs);
+}
+
+/*
+ * Can we use the FPU in kernel mode with the
+ * whole "kernel_fpu_begin/end()" sequence?
+ *
+ * It's always ok in process context (ie "not interrupt")
+ * but it is sometimes ok even from an irq.
+ */
+bool irq_fpu_usable(void)
+{
+ return !in_interrupt() ||
+ interrupted_user_mode() ||
+ interrupted_kernel_fpu_idle();
+}
+EXPORT_SYMBOL(irq_fpu_usable);
+
+void __kernel_fpu_begin(void)
+{
+ struct fpu *fpu = &current->thread.fpu;
+
+ WARN_ON_FPU(!irq_fpu_usable());
+
+ kernel_fpu_disable();
+
+ if (fpu->fpregs_active) {
+ copy_fpregs_to_fpstate(fpu);
+ } else {
+ this_cpu_write(fpu_fpregs_owner_ctx, NULL);
+ __fpregs_activate_hw();
+ }
+}
+EXPORT_SYMBOL(__kernel_fpu_begin);
+
+void __kernel_fpu_end(void)
+{
+ struct fpu *fpu = &current->thread.fpu;
+
+ if (fpu->fpregs_active)
+ copy_kernel_to_fpregs(&fpu->state);
+ else
+ __fpregs_deactivate_hw();
+
+ kernel_fpu_enable();
+}
+EXPORT_SYMBOL(__kernel_fpu_end);
+
+void kernel_fpu_begin(void)
+{
+ preempt_disable();
+ __kernel_fpu_begin();
+}
+EXPORT_SYMBOL_GPL(kernel_fpu_begin);
+
+void kernel_fpu_end(void)
+{
+ __kernel_fpu_end();
+ preempt_enable();
+}
+EXPORT_SYMBOL_GPL(kernel_fpu_end);
+
+/*
+ * CR0::TS save/restore functions:
+ */
+int irq_ts_save(void)
+{
+ /*
+ * If in process context and not atomic, we can take a spurious DNA fault.
+ * Otherwise, doing clts() in process context requires disabling preemption
+ * or some heavy lifting like kernel_fpu_begin()
+ */
+ if (!in_atomic())
+ return 0;
+
+ if (read_cr0() & X86_CR0_TS) {
+ clts();
+ return 1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(irq_ts_save);
+
+void irq_ts_restore(int TS_state)
+{
+ if (TS_state)
+ stts();
+}
+EXPORT_SYMBOL_GPL(irq_ts_restore);
+
+/*
+ * Save the FPU state (mark it for reload if necessary):
+ *
+ * This only ever gets called for the current task.
+ */
+void fpu__save(struct fpu *fpu)
+{
+ WARN_ON_FPU(fpu != &current->thread.fpu);
+
+ preempt_disable();
+ if (fpu->fpregs_active) {
+ if (!copy_fpregs_to_fpstate(fpu))
+ fpregs_deactivate(fpu);
+ }
+ preempt_enable();
+}
+EXPORT_SYMBOL_GPL(fpu__save);
+
+/*
+ * Legacy x87 fpstate state init:
+ */
+static inline void fpstate_init_fstate(struct fregs_state *fp)
+{
+ fp->cwd = 0xffff037fu;
+ fp->swd = 0xffff0000u;
+ fp->twd = 0xffffffffu;
+ fp->fos = 0xffff0000u;
+}
+
+void fpstate_init(union fpregs_state *state)
+{
+ if (!cpu_has_fpu) {
+ fpstate_init_soft(&state->soft);
+ return;
+ }
+
+ memset(state, 0, xstate_size);
+
+ if (cpu_has_fxsr)
+ fpstate_init_fxstate(&state->fxsave);
+ else
+ fpstate_init_fstate(&state->fsave);
+}
+EXPORT_SYMBOL_GPL(fpstate_init);
+
+/*
+ * Copy the current task's FPU state to a new task's FPU context.
+ *
+ * In both the 'eager' and the 'lazy' case we save hardware registers
+ * directly to the destination buffer.
+ */
+static void fpu_copy(struct fpu *dst_fpu, struct fpu *src_fpu)
+{
+ WARN_ON_FPU(src_fpu != &current->thread.fpu);
+
+ /*
+ * Don't let 'init optimized' areas of the XSAVE area
+ * leak into the child task:
+ */
+ if (use_eager_fpu())
+ memset(&dst_fpu->state.xsave, 0, xstate_size);
+
+ /*
+ * Save current FPU registers directly into the child
+ * FPU context, without any memory-to-memory copying.
+ *
+ * If the FPU context got destroyed in the process (FNSAVE
+ * done on old CPUs) then copy it back into the source
+ * context and mark the current task for lazy restore.
+ *
+ * We have to do all this with preemption disabled,
+ * mostly because of the FNSAVE case, because in that
+ * case we must not allow preemption in the window
+ * between the FNSAVE and us marking the context lazy.
+ *
+ * It shouldn't be an issue as even FNSAVE is plenty
+ * fast in terms of critical section length.
+ */
+ preempt_disable();
+ if (!copy_fpregs_to_fpstate(dst_fpu)) {
+ memcpy(&src_fpu->state, &dst_fpu->state, xstate_size);
+ fpregs_deactivate(src_fpu);
+ }
+ preempt_enable();
+}
+
+int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)
+{
+ dst_fpu->counter = 0;
+ dst_fpu->fpregs_active = 0;
+ dst_fpu->last_cpu = -1;
+
+ if (src_fpu->fpstate_active)
+ fpu_copy(dst_fpu, src_fpu);
+
+ return 0;
+}
+
+/*
+ * Activate the current task's in-memory FPU context,
+ * if it has not been used before:
+ */
+void fpu__activate_curr(struct fpu *fpu)
+{
+ WARN_ON_FPU(fpu != &current->thread.fpu);
+
+ if (!fpu->fpstate_active) {
+ fpstate_init(&fpu->state);
+
+ /* Safe to do for the current task: */
+ fpu->fpstate_active = 1;
+ }
+}
+EXPORT_SYMBOL_GPL(fpu__activate_curr);
+
+/*
+ * This function must be called before we read a task's fpstate.
+ *
+ * If the task has not used the FPU before then initialize its
+ * fpstate.
+ *
+ * If the task has used the FPU before then save it.
+ */
+void fpu__activate_fpstate_read(struct fpu *fpu)
+{
+ /*
+ * If fpregs are active (in the current CPU), then
+ * copy them to the fpstate:
+ */
+ if (fpu->fpregs_active) {
+ fpu__save(fpu);
+ } else {
+ if (!fpu->fpstate_active) {
+ fpstate_init(&fpu->state);
+
+ /* Safe to do for current and for stopped child tasks: */
+ fpu->fpstate_active = 1;
+ }
+ }
+}
+
+/*
+ * This function must be called before we write a task's fpstate.
+ *
+ * If the task has used the FPU before then unlazy it.
+ * If the task has not used the FPU before then initialize its fpstate.
+ *
+ * After this function call, after registers in the fpstate are
+ * modified and the child task has woken up, the child task will
+ * restore the modified FPU state from the modified context. If we
+ * didn't clear its lazy status here then the lazy in-registers
+ * state pending on its former CPU could be restored, corrupting
+ * the modifications.
+ */
+void fpu__activate_fpstate_write(struct fpu *fpu)
+{
+ /*
+ * Only stopped child tasks can be used to modify the FPU
+ * state in the fpstate buffer:
+ */
+ WARN_ON_FPU(fpu == &current->thread.fpu);
+
+ if (fpu->fpstate_active) {
+ /* Invalidate any lazy state: */
+ fpu->last_cpu = -1;
+ } else {
+ fpstate_init(&fpu->state);
+
+ /* Safe to do for stopped child tasks: */
+ fpu->fpstate_active = 1;
+ }
+}
+
+/*
+ * 'fpu__restore()' is called to copy FPU registers from
+ * the FPU fpstate to the live hw registers and to activate
+ * access to the hardware registers, so that FPU instructions
+ * can be used afterwards.
+ *
+ * Must be called with kernel preemption disabled (for example
+ * with local interrupts disabled, as it is in the case of
+ * do_device_not_available()).
+ */
+void fpu__restore(struct fpu *fpu)
+{
+ fpu__activate_curr(fpu);
+
+ /* Avoid __kernel_fpu_begin() right after fpregs_activate() */
+ kernel_fpu_disable();
+ fpregs_activate(fpu);
+ copy_kernel_to_fpregs(&fpu->state);
+ fpu->counter++;
+ kernel_fpu_enable();
+}
+EXPORT_SYMBOL_GPL(fpu__restore);
+
+/*
+ * Drops current FPU state: deactivates the fpregs and
+ * the fpstate. NOTE: it still leaves previous contents
+ * in the fpregs in the eager-FPU case.
+ *
+ * This function can be used in cases where we know that
+ * a state-restore is coming: either an explicit one,
+ * or a reschedule.
+ */
+void fpu__drop(struct fpu *fpu)
+{
+ preempt_disable();
+ fpu->counter = 0;
+
+ if (fpu->fpregs_active) {
+ /* Ignore delayed exceptions from user space */
+ asm volatile("1: fwait\n"
+ "2:\n"
+ _ASM_EXTABLE(1b, 2b));
+ fpregs_deactivate(fpu);
+ }
+
+ fpu->fpstate_active = 0;
+
+ preempt_enable();
+}
+
+/*
+ * Clear FPU registers by setting them up from
+ * the init fpstate:
+ */
+static inline void copy_init_fpstate_to_fpregs(void)
+{
+ if (use_xsave())
+ copy_kernel_to_xregs(&init_fpstate.xsave, -1);
+ else
+ copy_kernel_to_fxregs(&init_fpstate.fxsave);
+}
+
+/*
+ * Clear the FPU state back to init state.
+ *
+ * Called by sys_execve(), by the signal handler code and by various
+ * error paths.
+ */
+void fpu__clear(struct fpu *fpu)
+{
+ WARN_ON_FPU(fpu != &current->thread.fpu); /* Almost certainly an anomaly */
+
+ if (!use_eager_fpu()) {
+ /* FPU state will be reallocated lazily at the first use. */
+ fpu__drop(fpu);
+ } else {
+ if (!fpu->fpstate_active) {
+ fpu__activate_curr(fpu);
+ user_fpu_begin();
+ }
+ copy_init_fpstate_to_fpregs();
+ }
+}
+
+/*
+ * x87 math exception handling:
+ */
+
+static inline unsigned short get_fpu_cwd(struct fpu *fpu)
+{
+ if (cpu_has_fxsr) {
+ return fpu->state.fxsave.cwd;
+ } else {
+ return (unsigned short)fpu->state.fsave.cwd;
+ }
+}
+
+static inline unsigned short get_fpu_swd(struct fpu *fpu)
+{
+ if (cpu_has_fxsr) {
+ return fpu->state.fxsave.swd;
+ } else {
+ return (unsigned short)fpu->state.fsave.swd;
+ }
+}
+
+static inline unsigned short get_fpu_mxcsr(struct fpu *fpu)
+{
+ if (cpu_has_xmm) {
+ return fpu->state.fxsave.mxcsr;
+ } else {
+ return MXCSR_DEFAULT;
+ }
+}
+
+int fpu__exception_code(struct fpu *fpu, int trap_nr)
+{
+ int err;
+
+ if (trap_nr == X86_TRAP_MF) {
+ unsigned short cwd, swd;
+ /*
+ * (~cwd & swd) will mask out exceptions that are not set to unmasked
+ * status. 0x3f is the exception bits in these regs, 0x200 is the
+ * C1 reg you need in case of a stack fault, 0x040 is the stack
+ * fault bit. We should only be taking one exception at a time,
+ * so if this combination doesn't produce any single exception,
+ * then we have a bad program that isn't synchronizing its FPU usage
+ * and it will suffer the consequences since we won't be able to
+ * fully reproduce the context of the exception
+ */
+ cwd = get_fpu_cwd(fpu);
+ swd = get_fpu_swd(fpu);
+
+ err = swd & ~cwd;
+ } else {
+ /*
+ * The SIMD FPU exceptions are handled a little differently, as there
+ * is only a single status/control register. Thus, to determine which
+ * unmasked exception was caught we must mask the exception mask bits
+ * at 0x1f80, and then use these to mask the exception bits at 0x3f.
+ */
+ unsigned short mxcsr = get_fpu_mxcsr(fpu);
+ err = ~(mxcsr >> 7) & mxcsr;
+ }
+
+ if (err & 0x001) { /* Invalid op */
+ /*
+ * swd & 0x240 == 0x040: Stack Underflow
+ * swd & 0x240 == 0x240: Stack Overflow
+ * User must clear the SF bit (0x40) if set
+ */
+ return FPE_FLTINV;
+ } else if (err & 0x004) { /* Divide by Zero */
+ return FPE_FLTDIV;
+ } else if (err & 0x008) { /* Overflow */
+ return FPE_FLTOVF;
+ } else if (err & 0x012) { /* Denormal, Underflow */
+ return FPE_FLTUND;
+ } else if (err & 0x020) { /* Precision */
+ return FPE_FLTRES;
+ }
+
+ /*
+ * If we're using IRQ 13, or supposedly even some trap
+ * X86_TRAP_MF implementations, it's possible
+ * we get a spurious trap, which is not an error.
+ */
+ return 0;
+}
diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c
new file mode 100644
index 000000000000..fc878fee6a51
--- /dev/null
+++ b/arch/x86/kernel/fpu/init.c
@@ -0,0 +1,354 @@
+/*
+ * x86 FPU boot time init code:
+ */
+#include <asm/fpu/internal.h>
+#include <asm/tlbflush.h>
+
+/*
+ * Initialize the TS bit in CR0 according to the style of context-switches
+ * we are using:
+ */
+static void fpu__init_cpu_ctx_switch(void)
+{
+ if (!cpu_has_eager_fpu)
+ stts();
+ else
+ clts();
+}
+
+/*
+ * Initialize the registers found in all CPUs, CR0 and CR4:
+ */
+static void fpu__init_cpu_generic(void)
+{
+ unsigned long cr0;
+ unsigned long cr4_mask = 0;
+
+ if (cpu_has_fxsr)
+ cr4_mask |= X86_CR4_OSFXSR;
+ if (cpu_has_xmm)
+ cr4_mask |= X86_CR4_OSXMMEXCPT;
+ if (cr4_mask)
+ cr4_set_bits(cr4_mask);
+
+ cr0 = read_cr0();
+ cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */
+ if (!cpu_has_fpu)
+ cr0 |= X86_CR0_EM;
+ write_cr0(cr0);
+
+ /* Flush out any pending x87 state: */
+ asm volatile ("fninit");
+}
+
+/*
+ * Enable all supported FPU features. Called when a CPU is brought online:
+ */
+void fpu__init_cpu(void)
+{
+ fpu__init_cpu_generic();
+ fpu__init_cpu_xstate();
+ fpu__init_cpu_ctx_switch();
+}
+
+/*
+ * The earliest FPU detection code.
+ *
+ * Set the X86_FEATURE_FPU CPU-capability bit based on
+ * trying to execute an actual sequence of FPU instructions:
+ */
+static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
+{
+ unsigned long cr0;
+ u16 fsw, fcw;
+
+ fsw = fcw = 0xffff;
+
+ cr0 = read_cr0();
+ cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
+ write_cr0(cr0);
+
+ asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
+ : "+m" (fsw), "+m" (fcw));
+
+ if (fsw == 0 && (fcw & 0x103f) == 0x003f)
+ set_cpu_cap(c, X86_FEATURE_FPU);
+ else
+ clear_cpu_cap(c, X86_FEATURE_FPU);
+
+#ifndef CONFIG_MATH_EMULATION
+ if (!cpu_has_fpu) {
+ pr_emerg("x86/fpu: Giving up, no FPU found and no math emulation present\n");
+ for (;;)
+ asm volatile("hlt");
+ }
+#endif
+}
+
+/*
+ * Boot time FPU feature detection code:
+ */
+unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
+
+static void __init fpu__init_system_mxcsr(void)
+{
+ unsigned int mask = 0;
+
+ if (cpu_has_fxsr) {
+ struct fxregs_state fx_tmp __aligned(32) = { };
+
+ asm volatile("fxsave %0" : "+m" (fx_tmp));
+
+ mask = fx_tmp.mxcsr_mask;
+
+ /*
+ * If zero then use the default features mask,
+ * which has all features set, except the
+ * denormals-are-zero feature bit:
+ */
+ if (mask == 0)
+ mask = 0x0000ffbf;
+ }
+ mxcsr_feature_mask &= mask;
+}
+
+/*
+ * Once per bootup FPU initialization sequences that will run on most x86 CPUs:
+ */
+static void __init fpu__init_system_generic(void)
+{
+ /*
+ * Set up the legacy init FPU context. (xstate init might overwrite this
+ * with a more modern format, if the CPU supports it.)
+ */
+ fpstate_init_fxstate(&init_fpstate.fxsave);
+
+ fpu__init_system_mxcsr();
+}
+
+/*
+ * Size of the FPU context state. All tasks in the system use the
+ * same context size, regardless of what portion they use.
+ * This is inherent to the XSAVE architecture which puts all state
+ * components into a single, continuous memory block:
+ */
+unsigned int xstate_size;
+EXPORT_SYMBOL_GPL(xstate_size);
+
+/*
+ * Set up the xstate_size based on the legacy FPU context size.
+ *
+ * We set this up first, and later it will be overwritten by
+ * fpu__init_system_xstate() if the CPU knows about xstates.
+ */
+static void __init fpu__init_system_xstate_size_legacy(void)
+{
+ static int on_boot_cpu = 1;
+
+ WARN_ON_FPU(!on_boot_cpu);
+ on_boot_cpu = 0;
+
+ /*
+ * Note that xstate_size might be overwriten later during
+ * fpu__init_system_xstate().
+ */
+
+ if (!cpu_has_fpu) {
+ /*
+ * Disable xsave as we do not support it if i387
+ * emulation is enabled.
+ */
+ setup_clear_cpu_cap(X86_FEATURE_XSAVE);
+ setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
+ xstate_size = sizeof(struct swregs_state);
+ } else {
+ if (cpu_has_fxsr)
+ xstate_size = sizeof(struct fxregs_state);
+ else
+ xstate_size = sizeof(struct fregs_state);
+ }
+ /*
+ * Quirk: we don't yet handle the XSAVES* instructions
+ * correctly, as we don't correctly convert between
+ * standard and compacted format when interfacing
+ * with user-space - so disable it for now.
+ *
+ * The difference is small: with recent CPUs the
+ * compacted format is only marginally smaller than
+ * the standard FPU state format.
+ *
+ * ( This is easy to backport while we are fixing
+ * XSAVES* support. )
+ */
+ setup_clear_cpu_cap(X86_FEATURE_XSAVES);
+}
+
+/*
+ * FPU context switching strategies:
+ *
+ * Against popular belief, we don't do lazy FPU saves, due to the
+ * task migration complications it brings on SMP - we only do
+ * lazy FPU restores.
+ *
+ * 'lazy' is the traditional strategy, which is based on setting
+ * CR0::TS to 1 during context-switch (instead of doing a full
+ * restore of the FPU state), which causes the first FPU instruction
+ * after the context switch (whenever it is executed) to fault - at
+ * which point we lazily restore the FPU state into FPU registers.
+ *
+ * Tasks are of course under no obligation to execute FPU instructions,
+ * so it can easily happen that another context-switch occurs without
+ * a single FPU instruction being executed. If we eventually switch
+ * back to the original task (that still owns the FPU) then we have
+ * not only saved the restores along the way, but we also have the
+ * FPU ready to be used for the original task.
+ *
+ * 'eager' switching is used on modern CPUs, there we switch the FPU
+ * state during every context switch, regardless of whether the task
+ * has used FPU instructions in that time slice or not. This is done
+ * because modern FPU context saving instructions are able to optimize
+ * state saving and restoration in hardware: they can detect both
+ * unused and untouched FPU state and optimize accordingly.
+ *
+ * [ Note that even in 'lazy' mode we might optimize context switches
+ * to use 'eager' restores, if we detect that a task is using the FPU
+ * frequently. See the fpu->counter logic in fpu/internal.h for that. ]
+ */
+static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO;
+
+static int __init eager_fpu_setup(char *s)
+{
+ if (!strcmp(s, "on"))
+ eagerfpu = ENABLE;
+ else if (!strcmp(s, "off"))
+ eagerfpu = DISABLE;
+ else if (!strcmp(s, "auto"))
+ eagerfpu = AUTO;
+ return 1;
+}
+__setup("eagerfpu=", eager_fpu_setup);
+
+/*
+ * Pick the FPU context switching strategy:
+ */
+static void __init fpu__init_system_ctx_switch(void)
+{
+ static bool on_boot_cpu = 1;
+
+ WARN_ON_FPU(!on_boot_cpu);
+ on_boot_cpu = 0;
+
+ WARN_ON_FPU(current->thread.fpu.fpstate_active);
+ current_thread_info()->status = 0;
+
+ /* Auto enable eagerfpu for xsaveopt */
+ if (cpu_has_xsaveopt && eagerfpu != DISABLE)
+ eagerfpu = ENABLE;
+
+ if (xfeatures_mask & XSTATE_EAGER) {
+ if (eagerfpu == DISABLE) {
+ pr_err("x86/fpu: eagerfpu switching disabled, disabling the following xstate features: 0x%llx.\n",
+ xfeatures_mask & XSTATE_EAGER);
+ xfeatures_mask &= ~XSTATE_EAGER;
+ } else {
+ eagerfpu = ENABLE;
+ }
+ }
+
+ if (eagerfpu == ENABLE)
+ setup_force_cpu_cap(X86_FEATURE_EAGER_FPU);
+
+ printk(KERN_INFO "x86/fpu: Using '%s' FPU context switches.\n", eagerfpu == ENABLE ? "eager" : "lazy");
+}
+
+/*
+ * 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_system_early_generic(c);
+
+ /*
+ * The FPU has to be operational for some of the
+ * later FPU init activities:
+ */
+ fpu__init_cpu();
+
+ /*
+ * But don't leave CR0::TS set yet, as some of the FPU setup
+ * methods depend on being able to execute FPU instructions
+ * that will fault on a set TS, such as the FXSAVE in
+ * fpu__init_system_mxcsr().
+ */
+ clts();
+
+ fpu__init_system_generic();
+ fpu__init_system_xstate_size_legacy();
+ fpu__init_system_xstate();
+
+ 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;
+
+ setup_clear_cpu_cap(X86_FEATURE_XSAVE);
+ setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
+ setup_clear_cpu_cap(X86_FEATURE_XSAVES);
+ setup_clear_cpu_cap(X86_FEATURE_AVX);
+ setup_clear_cpu_cap(X86_FEATURE_AVX2);
+
+ 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/regset.c b/arch/x86/kernel/fpu/regset.c
new file mode 100644
index 000000000000..dc60810c1c74
--- /dev/null
+++ b/arch/x86/kernel/fpu/regset.c
@@ -0,0 +1,356 @@
+/*
+ * FPU register's regset abstraction, for ptrace, core dumps, etc.
+ */
+#include <asm/fpu/internal.h>
+#include <asm/fpu/signal.h>
+#include <asm/fpu/regset.h>
+
+/*
+ * The xstateregs_active() routine is the same as the regset_fpregs_active() routine,
+ * as the "regset->n" for the xstate regset will be updated based on the feature
+ * capabilites supported by the xsave.
+ */
+int regset_fpregs_active(struct task_struct *target, const struct user_regset *regset)
+{
+ struct fpu *target_fpu = &target->thread.fpu;
+
+ return target_fpu->fpstate_active ? regset->n : 0;
+}
+
+int regset_xregset_fpregs_active(struct task_struct *target, const struct user_regset *regset)
+{
+ struct fpu *target_fpu = &target->thread.fpu;
+
+ return (cpu_has_fxsr && target_fpu->fpstate_active) ? regset->n : 0;
+}
+
+int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ struct fpu *fpu = &target->thread.fpu;
+
+ if (!cpu_has_fxsr)
+ return -ENODEV;
+
+ fpu__activate_fpstate_read(fpu);
+ fpstate_sanitize_xstate(fpu);
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &fpu->state.fxsave, 0, -1);
+}
+
+int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ struct fpu *fpu = &target->thread.fpu;
+ int ret;
+
+ if (!cpu_has_fxsr)
+ return -ENODEV;
+
+ fpu__activate_fpstate_write(fpu);
+ fpstate_sanitize_xstate(fpu);
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &fpu->state.fxsave, 0, -1);
+
+ /*
+ * mxcsr reserved bits must be masked to zero for security reasons.
+ */
+ fpu->state.fxsave.mxcsr &= mxcsr_feature_mask;
+
+ /*
+ * update the header bits in the xsave header, indicating the
+ * presence of FP and SSE state.
+ */
+ if (cpu_has_xsave)
+ fpu->state.xsave.header.xfeatures |= XSTATE_FPSSE;
+
+ return ret;
+}
+
+int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ struct fpu *fpu = &target->thread.fpu;
+ struct xregs_state *xsave;
+ int ret;
+
+ if (!cpu_has_xsave)
+ return -ENODEV;
+
+ fpu__activate_fpstate_read(fpu);
+
+ xsave = &fpu->state.xsave;
+
+ /*
+ * Copy the 48bytes defined by the software first into the xstate
+ * memory layout in the thread struct, so that we can copy the entire
+ * xstateregs to the user using one user_regset_copyout().
+ */
+ memcpy(&xsave->i387.sw_reserved,
+ xstate_fx_sw_bytes, sizeof(xstate_fx_sw_bytes));
+ /*
+ * Copy the xstate memory layout.
+ */
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, xsave, 0, -1);
+ return ret;
+}
+
+int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ struct fpu *fpu = &target->thread.fpu;
+ struct xregs_state *xsave;
+ int ret;
+
+ if (!cpu_has_xsave)
+ return -ENODEV;
+
+ fpu__activate_fpstate_write(fpu);
+
+ xsave = &fpu->state.xsave;
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1);
+ /*
+ * mxcsr reserved bits must be masked to zero for security reasons.
+ */
+ xsave->i387.mxcsr &= mxcsr_feature_mask;
+ xsave->header.xfeatures &= xfeatures_mask;
+ /*
+ * These bits must be zero.
+ */
+ memset(&xsave->header.reserved, 0, 48);
+
+ return ret;
+}
+
+#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
+
+/*
+ * FPU tag word conversions.
+ */
+
+static inline unsigned short twd_i387_to_fxsr(unsigned short twd)
+{
+ unsigned int tmp; /* to avoid 16 bit prefixes in the code */
+
+ /* Transform each pair of bits into 01 (valid) or 00 (empty) */
+ tmp = ~twd;
+ tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
+ /* and move the valid bits to the lower byte. */
+ tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
+ tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
+ tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
+
+ return tmp;
+}
+
+#define FPREG_ADDR(f, n) ((void *)&(f)->st_space + (n) * 16)
+#define FP_EXP_TAG_VALID 0
+#define FP_EXP_TAG_ZERO 1
+#define FP_EXP_TAG_SPECIAL 2
+#define FP_EXP_TAG_EMPTY 3
+
+static inline u32 twd_fxsr_to_i387(struct fxregs_state *fxsave)
+{
+ struct _fpxreg *st;
+ u32 tos = (fxsave->swd >> 11) & 7;
+ u32 twd = (unsigned long) fxsave->twd;
+ u32 tag;
+ u32 ret = 0xffff0000u;
+ int i;
+
+ for (i = 0; i < 8; i++, twd >>= 1) {
+ if (twd & 0x1) {
+ st = FPREG_ADDR(fxsave, (i - tos) & 7);
+
+ switch (st->exponent & 0x7fff) {
+ case 0x7fff:
+ tag = FP_EXP_TAG_SPECIAL;
+ break;
+ case 0x0000:
+ if (!st->significand[0] &&
+ !st->significand[1] &&
+ !st->significand[2] &&
+ !st->significand[3])
+ tag = FP_EXP_TAG_ZERO;
+ else
+ tag = FP_EXP_TAG_SPECIAL;
+ break;
+ default:
+ if (st->significand[3] & 0x8000)
+ tag = FP_EXP_TAG_VALID;
+ else
+ tag = FP_EXP_TAG_SPECIAL;
+ break;
+ }
+ } else {
+ tag = FP_EXP_TAG_EMPTY;
+ }
+ ret |= tag << (2 * i);
+ }
+ return ret;
+}
+
+/*
+ * FXSR floating point environment conversions.
+ */
+
+void
+convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
+{
+ struct fxregs_state *fxsave = &tsk->thread.fpu.state.fxsave;
+ struct _fpreg *to = (struct _fpreg *) &env->st_space[0];
+ struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0];
+ int i;
+
+ env->cwd = fxsave->cwd | 0xffff0000u;
+ env->swd = fxsave->swd | 0xffff0000u;
+ env->twd = twd_fxsr_to_i387(fxsave);
+
+#ifdef CONFIG_X86_64
+ env->fip = fxsave->rip;
+ env->foo = fxsave->rdp;
+ /*
+ * should be actually ds/cs at fpu exception time, but
+ * that information is not available in 64bit mode.
+ */
+ env->fcs = task_pt_regs(tsk)->cs;
+ if (tsk == current) {
+ savesegment(ds, env->fos);
+ } else {
+ env->fos = tsk->thread.ds;
+ }
+ env->fos |= 0xffff0000;
+#else
+ env->fip = fxsave->fip;
+ env->fcs = (u16) fxsave->fcs | ((u32) fxsave->fop << 16);
+ env->foo = fxsave->foo;
+ env->fos = fxsave->fos;
+#endif
+
+ for (i = 0; i < 8; ++i)
+ memcpy(&to[i], &from[i], sizeof(to[0]));
+}
+
+void convert_to_fxsr(struct task_struct *tsk,
+ const struct user_i387_ia32_struct *env)
+
+{
+ struct fxregs_state *fxsave = &tsk->thread.fpu.state.fxsave;
+ struct _fpreg *from = (struct _fpreg *) &env->st_space[0];
+ struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0];
+ int i;
+
+ fxsave->cwd = env->cwd;
+ fxsave->swd = env->swd;
+ fxsave->twd = twd_i387_to_fxsr(env->twd);
+ fxsave->fop = (u16) ((u32) env->fcs >> 16);
+#ifdef CONFIG_X86_64
+ fxsave->rip = env->fip;
+ fxsave->rdp = env->foo;
+ /* cs and ds ignored */
+#else
+ fxsave->fip = env->fip;
+ fxsave->fcs = (env->fcs & 0xffff);
+ fxsave->foo = env->foo;
+ fxsave->fos = env->fos;
+#endif
+
+ for (i = 0; i < 8; ++i)
+ memcpy(&to[i], &from[i], sizeof(from[0]));
+}
+
+int fpregs_get(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ struct fpu *fpu = &target->thread.fpu;
+ struct user_i387_ia32_struct env;
+
+ fpu__activate_fpstate_read(fpu);
+
+ if (!static_cpu_has(X86_FEATURE_FPU))
+ return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf);
+
+ if (!cpu_has_fxsr)
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &fpu->state.fsave, 0,
+ -1);
+
+ fpstate_sanitize_xstate(fpu);
+
+ if (kbuf && pos == 0 && count == sizeof(env)) {
+ convert_from_fxsr(kbuf, target);
+ return 0;
+ }
+
+ convert_from_fxsr(&env, target);
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
+}
+
+int fpregs_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ struct fpu *fpu = &target->thread.fpu;
+ struct user_i387_ia32_struct env;
+ int ret;
+
+ fpu__activate_fpstate_write(fpu);
+ fpstate_sanitize_xstate(fpu);
+
+ if (!static_cpu_has(X86_FEATURE_FPU))
+ return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf);
+
+ if (!cpu_has_fxsr)
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &fpu->state.fsave, 0,
+ -1);
+
+ if (pos > 0 || count < sizeof(env))
+ convert_from_fxsr(&env, target);
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
+ if (!ret)
+ convert_to_fxsr(target, &env);
+
+ /*
+ * update the header bit in the xsave header, indicating the
+ * presence of FP.
+ */
+ if (cpu_has_xsave)
+ fpu->state.xsave.header.xfeatures |= XSTATE_FP;
+ return ret;
+}
+
+/*
+ * FPU state for core dumps.
+ * This is only used for a.out dumps now.
+ * It is declared generically using elf_fpregset_t (which is
+ * struct user_i387_struct) but is in fact only used for 32-bit
+ * dumps, so on 64-bit it is really struct user_i387_ia32_struct.
+ */
+int dump_fpu(struct pt_regs *regs, struct user_i387_struct *ufpu)
+{
+ struct task_struct *tsk = current;
+ struct fpu *fpu = &tsk->thread.fpu;
+ int fpvalid;
+
+ fpvalid = fpu->fpstate_active;
+ if (fpvalid)
+ fpvalid = !fpregs_get(tsk, NULL,
+ 0, sizeof(struct user_i387_ia32_struct),
+ ufpu, NULL);
+
+ return fpvalid;
+}
+EXPORT_SYMBOL(dump_fpu);
+
+#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c
new file mode 100644
index 000000000000..50ec9af1bd51
--- /dev/null
+++ b/arch/x86/kernel/fpu/signal.c
@@ -0,0 +1,404 @@
+/*
+ * FPU signal frame handling routines.
+ */
+
+#include <linux/compat.h>
+#include <linux/cpu.h>
+
+#include <asm/fpu/internal.h>
+#include <asm/fpu/signal.h>
+#include <asm/fpu/regset.h>
+
+#include <asm/sigframe.h>
+
+static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32;
+
+/*
+ * Check for the presence of extended state information in the
+ * user fpstate pointer in the sigcontext.
+ */
+static inline int check_for_xstate(struct fxregs_state __user *buf,
+ void __user *fpstate,
+ struct _fpx_sw_bytes *fx_sw)
+{
+ int min_xstate_size = sizeof(struct fxregs_state) +
+ sizeof(struct xstate_header);
+ unsigned int magic2;
+
+ if (__copy_from_user(fx_sw, &buf->sw_reserved[0], sizeof(*fx_sw)))
+ return -1;
+
+ /* Check for the first magic field and other error scenarios. */
+ if (fx_sw->magic1 != FP_XSTATE_MAGIC1 ||
+ fx_sw->xstate_size < min_xstate_size ||
+ fx_sw->xstate_size > xstate_size ||
+ fx_sw->xstate_size > fx_sw->extended_size)
+ return -1;
+
+ /*
+ * Check for the presence of second magic word at the end of memory
+ * layout. This detects the case where the user just copied the legacy
+ * fpstate layout with out copying the extended state information
+ * in the memory layout.
+ */
+ if (__get_user(magic2, (__u32 __user *)(fpstate + fx_sw->xstate_size))
+ || magic2 != FP_XSTATE_MAGIC2)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Signal frame handlers.
+ */
+static inline int save_fsave_header(struct task_struct *tsk, void __user *buf)
+{
+ if (use_fxsr()) {
+ struct xregs_state *xsave = &tsk->thread.fpu.state.xsave;
+ struct user_i387_ia32_struct env;
+ struct _fpstate_ia32 __user *fp = buf;
+
+ convert_from_fxsr(&env, tsk);
+
+ if (__copy_to_user(buf, &env, sizeof(env)) ||
+ __put_user(xsave->i387.swd, &fp->status) ||
+ __put_user(X86_FXSR_MAGIC, &fp->magic))
+ return -1;
+ } else {
+ struct fregs_state __user *fp = buf;
+ u32 swd;
+ if (__get_user(swd, &fp->swd) || __put_user(swd, &fp->status))
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline int save_xstate_epilog(void __user *buf, int ia32_frame)
+{
+ struct xregs_state __user *x = buf;
+ struct _fpx_sw_bytes *sw_bytes;
+ u32 xfeatures;
+ int err;
+
+ /* Setup the bytes not touched by the [f]xsave and reserved for SW. */
+ sw_bytes = ia32_frame ? &fx_sw_reserved_ia32 : &fx_sw_reserved;
+ err = __copy_to_user(&x->i387.sw_reserved, sw_bytes, sizeof(*sw_bytes));
+
+ if (!use_xsave())
+ return err;
+
+ err |= __put_user(FP_XSTATE_MAGIC2, (__u32 *)(buf + xstate_size));
+
+ /*
+ * Read the xfeatures which we copied (directly from the cpu or
+ * from the state in task struct) to the user buffers.
+ */
+ err |= __get_user(xfeatures, (__u32 *)&x->header.xfeatures);
+
+ /*
+ * For legacy compatible, we always set FP/SSE bits in the bit
+ * vector while saving the state to the user context. This will
+ * enable us capturing any changes(during sigreturn) to
+ * the FP/SSE bits by the legacy applications which don't touch
+ * xfeatures in the xsave header.
+ *
+ * xsave aware apps can change the xfeatures in the xsave
+ * header as well as change any contents in the memory layout.
+ * xrestore as part of sigreturn will capture all the changes.
+ */
+ xfeatures |= XSTATE_FPSSE;
+
+ err |= __put_user(xfeatures, (__u32 *)&x->header.xfeatures);
+
+ return err;
+}
+
+static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf)
+{
+ int err;
+
+ if (use_xsave())
+ err = copy_xregs_to_user(buf);
+ else if (use_fxsr())
+ err = copy_fxregs_to_user((struct fxregs_state __user *) buf);
+ else
+ err = copy_fregs_to_user((struct fregs_state __user *) buf);
+
+ if (unlikely(err) && __clear_user(buf, xstate_size))
+ err = -EFAULT;
+ return err;
+}
+
+/*
+ * Save the fpu, extended register state to the user signal frame.
+ *
+ * 'buf_fx' is the 64-byte aligned pointer at which the [f|fx|x]save
+ * state is copied.
+ * 'buf' points to the 'buf_fx' or to the fsave header followed by 'buf_fx'.
+ *
+ * buf == buf_fx for 64-bit frames and 32-bit fsave frame.
+ * buf != buf_fx for 32-bit frames with fxstate.
+ *
+ * If the fpu, extended register state is live, save the state directly
+ * to the user frame pointed by the aligned pointer 'buf_fx'. Otherwise,
+ * copy the thread's fpu state to the user frame starting at 'buf_fx'.
+ *
+ * If this is a 32-bit frame with fxstate, put a fsave header before
+ * the aligned state at 'buf_fx'.
+ *
+ * For [f]xsave state, update the SW reserved fields in the [f]xsave frame
+ * indicating the absence/presence of the extended state to the user.
+ */
+int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
+{
+ struct xregs_state *xsave = &current->thread.fpu.state.xsave;
+ struct task_struct *tsk = current;
+ int ia32_fxstate = (buf != buf_fx);
+
+ ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
+ config_enabled(CONFIG_IA32_EMULATION));
+
+ if (!access_ok(VERIFY_WRITE, buf, size))
+ return -EACCES;
+
+ if (!static_cpu_has(X86_FEATURE_FPU))
+ return fpregs_soft_get(current, NULL, 0,
+ sizeof(struct user_i387_ia32_struct), NULL,
+ (struct _fpstate_ia32 __user *) buf) ? -1 : 1;
+
+ if (fpregs_active()) {
+ /* Save the live register state to the user directly. */
+ if (copy_fpregs_to_sigframe(buf_fx))
+ return -1;
+ /* Update the thread's fxstate to save the fsave header. */
+ if (ia32_fxstate)
+ copy_fxregs_to_kernel(&tsk->thread.fpu);
+ } else {
+ fpstate_sanitize_xstate(&tsk->thread.fpu);
+ if (__copy_to_user(buf_fx, xsave, xstate_size))
+ return -1;
+ }
+
+ /* Save the fsave header for the 32-bit frames. */
+ if ((ia32_fxstate || !use_fxsr()) && save_fsave_header(tsk, buf))
+ return -1;
+
+ if (use_fxsr() && save_xstate_epilog(buf_fx, ia32_fxstate))
+ return -1;
+
+ return 0;
+}
+
+static inline void
+sanitize_restored_xstate(struct task_struct *tsk,
+ struct user_i387_ia32_struct *ia32_env,
+ u64 xfeatures, int fx_only)
+{
+ struct xregs_state *xsave = &tsk->thread.fpu.state.xsave;
+ struct xstate_header *header = &xsave->header;
+
+ if (use_xsave()) {
+ /* These bits must be zero. */
+ memset(header->reserved, 0, 48);
+
+ /*
+ * Init the state that is not present in the memory
+ * layout and not enabled by the OS.
+ */
+ if (fx_only)
+ header->xfeatures = XSTATE_FPSSE;
+ else
+ header->xfeatures &= (xfeatures_mask & xfeatures);
+ }
+
+ if (use_fxsr()) {
+ /*
+ * mscsr reserved bits must be masked to zero for security
+ * reasons.
+ */
+ xsave->i387.mxcsr &= mxcsr_feature_mask;
+
+ convert_to_fxsr(tsk, ia32_env);
+ }
+}
+
+/*
+ * Restore the extended state if present. Otherwise, restore the FP/SSE state.
+ */
+static inline int copy_user_to_fpregs_zeroing(void __user *buf, u64 xbv, int fx_only)
+{
+ if (use_xsave()) {
+ if ((unsigned long)buf % 64 || fx_only) {
+ u64 init_bv = xfeatures_mask & ~XSTATE_FPSSE;
+ copy_kernel_to_xregs(&init_fpstate.xsave, init_bv);
+ return copy_user_to_fxregs(buf);
+ } else {
+ u64 init_bv = xfeatures_mask & ~xbv;
+ if (unlikely(init_bv))
+ copy_kernel_to_xregs(&init_fpstate.xsave, init_bv);
+ return copy_user_to_xregs(buf, xbv);
+ }
+ } else if (use_fxsr()) {
+ return copy_user_to_fxregs(buf);
+ } else
+ return copy_user_to_fregs(buf);
+}
+
+static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
+{
+ int ia32_fxstate = (buf != buf_fx);
+ struct task_struct *tsk = current;
+ struct fpu *fpu = &tsk->thread.fpu;
+ int state_size = xstate_size;
+ u64 xfeatures = 0;
+ int fx_only = 0;
+
+ ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
+ config_enabled(CONFIG_IA32_EMULATION));
+
+ if (!buf) {
+ fpu__clear(fpu);
+ return 0;
+ }
+
+ if (!access_ok(VERIFY_READ, buf, size))
+ return -EACCES;
+
+ fpu__activate_curr(fpu);
+
+ if (!static_cpu_has(X86_FEATURE_FPU))
+ return fpregs_soft_set(current, NULL,
+ 0, sizeof(struct user_i387_ia32_struct),
+ NULL, buf) != 0;
+
+ if (use_xsave()) {
+ struct _fpx_sw_bytes fx_sw_user;
+ if (unlikely(check_for_xstate(buf_fx, buf_fx, &fx_sw_user))) {
+ /*
+ * Couldn't find the extended state information in the
+ * memory layout. Restore just the FP/SSE and init all
+ * the other extended state.
+ */
+ state_size = sizeof(struct fxregs_state);
+ fx_only = 1;
+ } else {
+ state_size = fx_sw_user.xstate_size;
+ xfeatures = fx_sw_user.xfeatures;
+ }
+ }
+
+ if (ia32_fxstate) {
+ /*
+ * For 32-bit frames with fxstate, copy the user state to the
+ * thread's fpu state, reconstruct fxstate from the fsave
+ * header. Sanitize the copied state etc.
+ */
+ struct fpu *fpu = &tsk->thread.fpu;
+ struct user_i387_ia32_struct env;
+ int err = 0;
+
+ /*
+ * Drop the current fpu which clears fpu->fpstate_active. This ensures
+ * that any context-switch during the copy of the new state,
+ * avoids the intermediate state from getting restored/saved.
+ * Thus avoiding the new restored state from getting corrupted.
+ * We will be ready to restore/save the state only after
+ * fpu->fpstate_active is again set.
+ */
+ fpu__drop(fpu);
+
+ if (__copy_from_user(&fpu->state.xsave, buf_fx, state_size) ||
+ __copy_from_user(&env, buf, sizeof(env))) {
+ fpstate_init(&fpu->state);
+ err = -1;
+ } else {
+ sanitize_restored_xstate(tsk, &env, xfeatures, fx_only);
+ }
+
+ fpu->fpstate_active = 1;
+ if (use_eager_fpu()) {
+ preempt_disable();
+ fpu__restore(fpu);
+ preempt_enable();
+ }
+
+ return err;
+ } else {
+ /*
+ * For 64-bit frames and 32-bit fsave frames, restore the user
+ * state to the registers directly (with exceptions handled).
+ */
+ user_fpu_begin();
+ if (copy_user_to_fpregs_zeroing(buf_fx, xfeatures, fx_only)) {
+ fpu__clear(fpu);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static inline int xstate_sigframe_size(void)
+{
+ return use_xsave() ? xstate_size + FP_XSTATE_MAGIC2_SIZE : xstate_size;
+}
+
+/*
+ * Restore FPU state from a sigframe:
+ */
+int fpu__restore_sig(void __user *buf, int ia32_frame)
+{
+ void __user *buf_fx = buf;
+ int size = xstate_sigframe_size();
+
+ if (ia32_frame && use_fxsr()) {
+ buf_fx = buf + sizeof(struct fregs_state);
+ size += sizeof(struct fregs_state);
+ }
+
+ return __fpu__restore_sig(buf, buf_fx, size);
+}
+
+unsigned long
+fpu__alloc_mathframe(unsigned long sp, int ia32_frame,
+ unsigned long *buf_fx, unsigned long *size)
+{
+ unsigned long frame_size = xstate_sigframe_size();
+
+ *buf_fx = sp = round_down(sp - frame_size, 64);
+ if (ia32_frame && use_fxsr()) {
+ frame_size += sizeof(struct fregs_state);
+ sp -= sizeof(struct fregs_state);
+ }
+
+ *size = frame_size;
+
+ return sp;
+}
+/*
+ * Prepare the SW reserved portion of the fxsave memory layout, indicating
+ * the presence of the extended state information in the memory layout
+ * pointed by the fpstate pointer in the sigcontext.
+ * This will be saved when ever the FP and extended state context is
+ * saved on the user stack during the signal handler delivery to the user.
+ */
+void fpu__init_prepare_fx_sw_frame(void)
+{
+ int fsave_header_size = sizeof(struct fregs_state);
+ int size = xstate_size + FP_XSTATE_MAGIC2_SIZE;
+
+ if (config_enabled(CONFIG_X86_32))
+ size += fsave_header_size;
+
+ fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
+ fx_sw_reserved.extended_size = size;
+ fx_sw_reserved.xfeatures = xfeatures_mask;
+ fx_sw_reserved.xstate_size = xstate_size;
+
+ if (config_enabled(CONFIG_IA32_EMULATION)) {
+ fx_sw_reserved_ia32 = fx_sw_reserved;
+ fx_sw_reserved_ia32.extended_size += fsave_header_size;
+ }
+}
+
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
new file mode 100644
index 000000000000..62fc001c7846
--- /dev/null
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -0,0 +1,461 @@
+/*
+ * xsave/xrstor support.
+ *
+ * Author: Suresh Siddha <suresh.b.siddha@intel.com>
+ */
+#include <linux/compat.h>
+#include <linux/cpu.h>
+
+#include <asm/fpu/api.h>
+#include <asm/fpu/internal.h>
+#include <asm/fpu/signal.h>
+#include <asm/fpu/regset.h>
+
+#include <asm/tlbflush.h>
+
+static const char *xfeature_names[] =
+{
+ "x87 floating point registers" ,
+ "SSE registers" ,
+ "AVX registers" ,
+ "MPX bounds registers" ,
+ "MPX CSR" ,
+ "AVX-512 opmask" ,
+ "AVX-512 Hi256" ,
+ "AVX-512 ZMM_Hi256" ,
+ "unknown xstate feature" ,
+};
+
+/*
+ * Mask of xstate features supported by the CPU and the kernel:
+ */
+u64 xfeatures_mask __read_mostly;
+
+static unsigned int xstate_offsets[XFEATURES_NR_MAX] = { [ 0 ... XFEATURES_NR_MAX - 1] = -1};
+static unsigned int xstate_sizes[XFEATURES_NR_MAX] = { [ 0 ... XFEATURES_NR_MAX - 1] = -1};
+static unsigned int xstate_comp_offsets[sizeof(xfeatures_mask)*8];
+
+/* The number of supported xfeatures in xfeatures_mask: */
+static unsigned int xfeatures_nr;
+
+/*
+ * Return whether the system supports a given xfeature.
+ *
+ * Also return the name of the (most advanced) feature that the caller requested:
+ */
+int cpu_has_xfeatures(u64 xfeatures_needed, const char **feature_name)
+{
+ u64 xfeatures_missing = xfeatures_needed & ~xfeatures_mask;
+
+ if (unlikely(feature_name)) {
+ long xfeature_idx, max_idx;
+ u64 xfeatures_print;
+ /*
+ * So we use FLS here to be able to print the most advanced
+ * feature that was requested but is missing. So if a driver
+ * asks about "XSTATE_SSE | XSTATE_YMM" we'll print the
+ * missing AVX feature - this is the most informative message
+ * to users:
+ */
+ if (xfeatures_missing)
+ xfeatures_print = xfeatures_missing;
+ else
+ xfeatures_print = xfeatures_needed;
+
+ xfeature_idx = fls64(xfeatures_print)-1;
+ max_idx = ARRAY_SIZE(xfeature_names)-1;
+ xfeature_idx = min(xfeature_idx, max_idx);
+
+ *feature_name = xfeature_names[xfeature_idx];
+ }
+
+ if (xfeatures_missing)
+ return 0;
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(cpu_has_xfeatures);
+
+/*
+ * When executing XSAVEOPT (or other optimized XSAVE instructions), if
+ * a processor implementation detects that an FPU state component is still
+ * (or is again) in its initialized state, it may clear the corresponding
+ * bit in the header.xfeatures field, and can skip the writeout of registers
+ * to the corresponding memory layout.
+ *
+ * This means that when the bit is zero, the state component might still contain
+ * some previous - non-initialized register state.
+ *
+ * Before writing xstate information to user-space we sanitize those components,
+ * to always ensure that the memory layout of a feature will be in the init state
+ * if the corresponding header bit is zero. This is to ensure that user-space doesn't
+ * see some stale state in the memory layout during signal handling, debugging etc.
+ */
+void fpstate_sanitize_xstate(struct fpu *fpu)
+{
+ struct fxregs_state *fx = &fpu->state.fxsave;
+ int feature_bit;
+ u64 xfeatures;
+
+ if (!use_xsaveopt())
+ return;
+
+ xfeatures = fpu->state.xsave.header.xfeatures;
+
+ /*
+ * None of the feature bits are in init state. So nothing else
+ * to do for us, as the memory layout is up to date.
+ */
+ if ((xfeatures & xfeatures_mask) == xfeatures_mask)
+ return;
+
+ /*
+ * FP is in init state
+ */
+ if (!(xfeatures & XSTATE_FP)) {
+ fx->cwd = 0x37f;
+ fx->swd = 0;
+ fx->twd = 0;
+ fx->fop = 0;
+ fx->rip = 0;
+ fx->rdp = 0;
+ memset(&fx->st_space[0], 0, 128);
+ }
+
+ /*
+ * SSE is in init state
+ */
+ if (!(xfeatures & XSTATE_SSE))
+ memset(&fx->xmm_space[0], 0, 256);
+
+ /*
+ * First two features are FPU and SSE, which above we handled
+ * in a special way already:
+ */
+ feature_bit = 0x2;
+ xfeatures = (xfeatures_mask & ~xfeatures) >> 2;
+
+ /*
+ * Update all the remaining memory layouts according to their
+ * standard xstate layout, if their header bit is in the init
+ * state:
+ */
+ while (xfeatures) {
+ if (xfeatures & 0x1) {
+ int offset = xstate_offsets[feature_bit];
+ int size = xstate_sizes[feature_bit];
+
+ memcpy((void *)fx + offset,
+ (void *)&init_fpstate.xsave + offset,
+ size);
+ }
+
+ xfeatures >>= 1;
+ feature_bit++;
+ }
+}
+
+/*
+ * Enable the extended processor state save/restore feature.
+ * Called once per CPU onlining.
+ */
+void fpu__init_cpu_xstate(void)
+{
+ if (!cpu_has_xsave || !xfeatures_mask)
+ return;
+
+ cr4_set_bits(X86_CR4_OSXSAVE);
+ xsetbv(XCR_XFEATURE_ENABLED_MASK, xfeatures_mask);
+}
+
+/*
+ * Record the offsets and sizes of various xstates contained
+ * in the XSAVE state memory layout.
+ *
+ * ( Note that certain features might be non-present, for them
+ * we'll have 0 offset and 0 size. )
+ */
+static void __init setup_xstate_features(void)
+{
+ u32 eax, ebx, ecx, edx, leaf;
+
+ xfeatures_nr = fls64(xfeatures_mask);
+
+ for (leaf = 2; leaf < xfeatures_nr; leaf++) {
+ cpuid_count(XSTATE_CPUID, leaf, &eax, &ebx, &ecx, &edx);
+
+ xstate_offsets[leaf] = ebx;
+ xstate_sizes[leaf] = eax;
+
+ printk(KERN_INFO "x86/fpu: xstate_offset[%d]: %04x, xstate_sizes[%d]: %04x\n", leaf, ebx, leaf, eax);
+ }
+}
+
+static void __init print_xstate_feature(u64 xstate_mask)
+{
+ const char *feature_name;
+
+ if (cpu_has_xfeatures(xstate_mask, &feature_name))
+ pr_info("x86/fpu: Supporting XSAVE feature 0x%02Lx: '%s'\n", xstate_mask, feature_name);
+}
+
+/*
+ * Print out all the supported xstate features:
+ */
+static void __init print_xstate_features(void)
+{
+ print_xstate_feature(XSTATE_FP);
+ print_xstate_feature(XSTATE_SSE);
+ print_xstate_feature(XSTATE_YMM);
+ print_xstate_feature(XSTATE_BNDREGS);
+ print_xstate_feature(XSTATE_BNDCSR);
+ print_xstate_feature(XSTATE_OPMASK);
+ print_xstate_feature(XSTATE_ZMM_Hi256);
+ print_xstate_feature(XSTATE_Hi16_ZMM);
+}
+
+/*
+ * This function sets up offsets and sizes of all extended states in
+ * xsave area. This supports both standard format and compacted format
+ * of the xsave aread.
+ */
+static void __init setup_xstate_comp(void)
+{
+ unsigned int xstate_comp_sizes[sizeof(xfeatures_mask)*8];
+ int i;
+
+ /*
+ * The FP xstates and SSE xstates are legacy states. They are always
+ * in the fixed offsets in the xsave area in either compacted form
+ * or standard form.
+ */
+ xstate_comp_offsets[0] = 0;
+ xstate_comp_offsets[1] = offsetof(struct fxregs_state, xmm_space);
+
+ if (!cpu_has_xsaves) {
+ for (i = 2; i < xfeatures_nr; i++) {
+ if (test_bit(i, (unsigned long *)&xfeatures_mask)) {
+ xstate_comp_offsets[i] = xstate_offsets[i];
+ xstate_comp_sizes[i] = xstate_sizes[i];
+ }
+ }
+ return;
+ }
+
+ xstate_comp_offsets[2] = FXSAVE_SIZE + XSAVE_HDR_SIZE;
+
+ for (i = 2; i < xfeatures_nr; i++) {
+ if (test_bit(i, (unsigned long *)&xfeatures_mask))
+ xstate_comp_sizes[i] = xstate_sizes[i];
+ else
+ xstate_comp_sizes[i] = 0;
+
+ if (i > 2)
+ xstate_comp_offsets[i] = xstate_comp_offsets[i-1]
+ + xstate_comp_sizes[i-1];
+
+ }
+}
+
+/*
+ * setup the xstate image representing the init state
+ */
+static void __init setup_init_fpu_buf(void)
+{
+ static int on_boot_cpu = 1;
+
+ WARN_ON_FPU(!on_boot_cpu);
+ on_boot_cpu = 0;
+
+ if (!cpu_has_xsave)
+ return;
+
+ setup_xstate_features();
+ print_xstate_features();
+
+ if (cpu_has_xsaves) {
+ init_fpstate.xsave.header.xcomp_bv = (u64)1 << 63 | xfeatures_mask;
+ init_fpstate.xsave.header.xfeatures = xfeatures_mask;
+ }
+
+ /*
+ * Init all the features state with header_bv being 0x0
+ */
+ copy_kernel_to_xregs_booting(&init_fpstate.xsave);
+
+ /*
+ * Dump the init state again. This is to identify the init state
+ * of any feature which is not represented by all zero's.
+ */
+ copy_xregs_to_kernel_booting(&init_fpstate.xsave);
+}
+
+/*
+ * Calculate total size of enabled xstates in XCR0/xfeatures_mask.
+ */
+static void __init init_xstate_size(void)
+{
+ unsigned int eax, ebx, ecx, edx;
+ int i;
+
+ if (!cpu_has_xsaves) {
+ cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
+ xstate_size = ebx;
+ return;
+ }
+
+ xstate_size = FXSAVE_SIZE + XSAVE_HDR_SIZE;
+ for (i = 2; i < 64; i++) {
+ if (test_bit(i, (unsigned long *)&xfeatures_mask)) {
+ cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx);
+ xstate_size += eax;
+ }
+ }
+}
+
+/*
+ * Enable and initialize the xsave feature.
+ * Called once per system bootup.
+ */
+void __init fpu__init_system_xstate(void)
+{
+ unsigned int eax, ebx, ecx, edx;
+ static int on_boot_cpu = 1;
+
+ WARN_ON_FPU(!on_boot_cpu);
+ on_boot_cpu = 0;
+
+ if (!cpu_has_xsave) {
+ pr_info("x86/fpu: Legacy x87 FPU detected.\n");
+ return;
+ }
+
+ if (boot_cpu_data.cpuid_level < XSTATE_CPUID) {
+ WARN_ON_FPU(1);
+ return;
+ }
+
+ cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
+ xfeatures_mask = eax + ((u64)edx << 32);
+
+ if ((xfeatures_mask & XSTATE_FPSSE) != XSTATE_FPSSE) {
+ pr_err("x86/fpu: FP/SSE not present amongst the CPU's xstate features: 0x%llx.\n", xfeatures_mask);
+ BUG();
+ }
+
+ /* Support only the state known to the OS: */
+ xfeatures_mask = xfeatures_mask & XCNTXT_MASK;
+
+ /* Enable xstate instructions to be able to continue with initialization: */
+ fpu__init_cpu_xstate();
+
+ /* Recompute the context size for enabled features: */
+ init_xstate_size();
+
+ update_regset_xstate_info(xstate_size, xfeatures_mask);
+ fpu__init_prepare_fx_sw_frame();
+ setup_init_fpu_buf();
+ setup_xstate_comp();
+
+ pr_info("x86/fpu: Enabled xstate features 0x%llx, context size is 0x%x bytes, using '%s' format.\n",
+ xfeatures_mask,
+ xstate_size,
+ cpu_has_xsaves ? "compacted" : "standard");
+}
+
+/*
+ * Restore minimal FPU state after suspend:
+ */
+void fpu__resume_cpu(void)
+{
+ /*
+ * Restore XCR0 on xsave capable CPUs:
+ */
+ if (cpu_has_xsave)
+ xsetbv(XCR_XFEATURE_ENABLED_MASK, xfeatures_mask);
+}
+
+/*
+ * Given the xsave area and a state inside, this function returns the
+ * address of the state.
+ *
+ * This is the API that is called to get xstate address in either
+ * standard format or compacted format of xsave area.
+ *
+ * Note that if there is no data for the field in the xsave buffer
+ * this will return NULL.
+ *
+ * Inputs:
+ * xstate: the thread's storage area for all FPU data
+ * xstate_feature: state which is defined in xsave.h (e.g.
+ * XSTATE_FP, XSTATE_SSE, etc...)
+ * Output:
+ * address of the state in the xsave area, or NULL if the
+ * field is not present in the xsave buffer.
+ */
+void *get_xsave_addr(struct xregs_state *xsave, int xstate_feature)
+{
+ int feature_nr = fls64(xstate_feature) - 1;
+ /*
+ * Do we even *have* xsave state?
+ */
+ if (!boot_cpu_has(X86_FEATURE_XSAVE))
+ return NULL;
+
+ xsave = &current->thread.fpu.state.xsave;
+ /*
+ * We should not ever be requesting features that we
+ * have not enabled. Remember that pcntxt_mask is
+ * what we write to the XCR0 register.
+ */
+ WARN_ONCE(!(xfeatures_mask & xstate_feature),
+ "get of unsupported state");
+ /*
+ * This assumes the last 'xsave*' instruction to
+ * have requested that 'xstate_feature' be saved.
+ * If it did not, we might be seeing and old value
+ * of the field in the buffer.
+ *
+ * This can happen because the last 'xsave' did not
+ * request that this feature be saved (unlikely)
+ * or because the "init optimization" caused it
+ * to not be saved.
+ */
+ if (!(xsave->header.xfeatures & xstate_feature))
+ return NULL;
+
+ return (void *)xsave + xstate_comp_offsets[feature_nr];
+}
+EXPORT_SYMBOL_GPL(get_xsave_addr);
+
+/*
+ * This wraps up the common operations that need to occur when retrieving
+ * data from xsave state. It first ensures that the current task was
+ * using the FPU and retrieves the data in to a buffer. It then calculates
+ * the offset of the requested field in the buffer.
+ *
+ * This function is safe to call whether the FPU is in use or not.
+ *
+ * Note that this only works on the current task.
+ *
+ * Inputs:
+ * @xsave_state: state which is defined in xsave.h (e.g. XSTATE_FP,
+ * XSTATE_SSE, etc...)
+ * Output:
+ * address of the state in the xsave area or NULL if the state
+ * is not present or is in its 'init state'.
+ */
+const void *get_xsave_field_ptr(int xsave_state)
+{
+ struct fpu *fpu = &current->thread.fpu;
+
+ if (!fpu->fpstate_active)
+ return NULL;
+ /*
+ * fpu__save() takes the CPU's xstate registers
+ * and saves them off to the 'fpu memory buffer.
+ */
+ fpu__save(fpu);
+
+ return get_xsave_addr(&fpu->state.xsave, xsave_state);
+}
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 53eeb226657c..0e2d96ffd158 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -62,9 +62,16 @@
#define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD)
#endif
-/* Number of possible pages in the lowmem region */
-LOWMEM_PAGES = (((1<<32) - __PAGE_OFFSET) >> PAGE_SHIFT)
-
+/*
+ * Number of possible pages in the lowmem region.
+ *
+ * We shift 2 by 31 instead of 1 by 32 to the left in order to avoid a
+ * gas warning about overflowing shift count when gas has been compiled
+ * with only a host target support using a 32-bit type for internal
+ * representation.
+ */
+LOWMEM_PAGES = (((2<<31) - __PAGE_OFFSET) >> PAGE_SHIFT)
+
/* Enough space to fit pagetables for the low memory linear map */
MAPPING_BEYOND_END = PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT
@@ -550,7 +557,7 @@ early_idt_handler_common:
cld
cmpl $2,(%esp) # X86_TRAP_NMI
- je is_nmi # Ignore NMI
+ je .Lis_nmi # Ignore NMI
cmpl $2,%ss:early_recursion_flag
je hlt_loop
@@ -603,7 +610,7 @@ ex_entry:
pop %ecx
pop %eax
decl %ss:early_recursion_flag
-is_nmi:
+.Lis_nmi:
addl $8,%esp /* drop vector number and error code */
iret
ENDPROC(early_idt_handler_common)
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index df7e78057ae0..e5c27f729a38 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -346,7 +346,7 @@ early_idt_handler_common:
cld
cmpl $2,(%rsp) # X86_TRAP_NMI
- je is_nmi # Ignore NMI
+ je .Lis_nmi # Ignore NMI
cmpl $2,early_recursion_flag(%rip)
jz 1f
@@ -411,7 +411,7 @@ early_idt_handler_common:
popq %rcx
popq %rax
decl early_recursion_flag(%rip)
-is_nmi:
+.Lis_nmi:
addq $16,%rsp # drop vector number and error code
INTERRUPT_RETURN
ENDPROC(early_idt_handler_common)
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 3acbff4716b0..10757d0a3fcf 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -12,6 +12,7 @@
#include <linux/pm.h>
#include <linux/io.h>
+#include <asm/irqdomain.h>
#include <asm/fixmap.h>
#include <asm/hpet.h>
#include <asm/time.h>
@@ -305,8 +306,6 @@ static void hpet_legacy_clockevent_register(void)
printk(KERN_DEBUG "hpet clockevent registered\n");
}
-static int hpet_setup_msi_irq(unsigned int irq);
-
static void hpet_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt, int timer)
{
@@ -357,7 +356,7 @@ static void hpet_set_mode(enum clock_event_mode mode,
hpet_enable_legacy_int();
} else {
struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
- hpet_setup_msi_irq(hdev->irq);
+ irq_domain_activate_irq(irq_get_irq_data(hdev->irq));
disable_irq(hdev->irq);
irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu));
enable_irq(hdev->irq);
@@ -423,6 +422,7 @@ static int hpet_legacy_next_event(unsigned long delta,
static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev);
static struct hpet_dev *hpet_devs;
+static struct irq_domain *hpet_domain;
void hpet_msi_unmask(struct irq_data *data)
{
@@ -473,31 +473,6 @@ static int hpet_msi_next_event(unsigned long delta,
return hpet_next_event(delta, evt, hdev->num);
}
-static int hpet_setup_msi_irq(unsigned int irq)
-{
- if (x86_msi.setup_hpet_msi(irq, hpet_blockid)) {
- irq_free_hwirq(irq);
- return -EINVAL;
- }
- return 0;
-}
-
-static int hpet_assign_irq(struct hpet_dev *dev)
-{
- unsigned int irq = irq_alloc_hwirq(-1);
-
- if (!irq)
- return -EINVAL;
-
- irq_set_handler_data(irq, dev);
-
- if (hpet_setup_msi_irq(irq))
- return -EINVAL;
-
- dev->irq = irq;
- return 0;
-}
-
static irqreturn_t hpet_interrupt_handler(int irq, void *data)
{
struct hpet_dev *dev = (struct hpet_dev *)data;
@@ -540,9 +515,6 @@ static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu)
if (!(hdev->flags & HPET_DEV_VALID))
return;
- if (hpet_setup_msi_irq(hdev->irq))
- return;
-
hdev->cpu = cpu;
per_cpu(cpu_hpet_dev, cpu) = hdev;
evt->name = hdev->name;
@@ -574,7 +546,7 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
unsigned int id;
unsigned int num_timers;
unsigned int num_timers_used = 0;
- int i;
+ int i, irq;
if (hpet_msi_disable)
return;
@@ -587,6 +559,10 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
num_timers++; /* Value read out starts from 0 */
hpet_print_config();
+ hpet_domain = hpet_create_irq_domain(hpet_blockid);
+ if (!hpet_domain)
+ return;
+
hpet_devs = kzalloc(sizeof(struct hpet_dev) * num_timers, GFP_KERNEL);
if (!hpet_devs)
return;
@@ -604,12 +580,14 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
hdev->flags = 0;
if (cfg & HPET_TN_PERIODIC_CAP)
hdev->flags |= HPET_DEV_PERI_CAP;
+ sprintf(hdev->name, "hpet%d", i);
hdev->num = i;
- sprintf(hdev->name, "hpet%d", i);
- if (hpet_assign_irq(hdev))
+ irq = hpet_assign_irq(hpet_domain, hdev, hdev->num);
+ if (irq <= 0)
continue;
+ hdev->irq = irq;
hdev->flags |= HPET_DEV_FSB_CAP;
hdev->flags |= HPET_DEV_VALID;
num_timers_used++;
@@ -709,10 +687,6 @@ static int hpet_cpuhp_notify(struct notifier_block *n,
}
#else
-static int hpet_setup_msi_irq(unsigned int irq)
-{
- return 0;
-}
static void hpet_msi_capability_lookup(unsigned int start_timer)
{
return;
diff --git a/arch/x86/kernel/i386_ksyms_32.c b/arch/x86/kernel/i386_ksyms_32.c
index 05fd74f537d6..64341aa485ae 100644
--- a/arch/x86/kernel/i386_ksyms_32.c
+++ b/arch/x86/kernel/i386_ksyms_32.c
@@ -40,7 +40,5 @@ EXPORT_SYMBOL(empty_zero_page);
#ifdef CONFIG_PREEMPT
EXPORT_SYMBOL(___preempt_schedule);
-#ifdef CONFIG_CONTEXT_TRACKING
-EXPORT_SYMBOL(___preempt_schedule_context);
-#endif
+EXPORT_SYMBOL(___preempt_schedule_notrace);
#endif
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
deleted file mode 100644
index 6185d3141219..000000000000
--- a/arch/x86/kernel/i387.c
+++ /dev/null
@@ -1,671 +0,0 @@
-/*
- * Copyright (C) 1994 Linus Torvalds
- *
- * Pentium III FXSR, SSE support
- * General FPU state handling cleanups
- * Gareth Hughes <gareth@valinux.com>, May 2000
- */
-#include <linux/module.h>
-#include <linux/regset.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-#include <asm/sigcontext.h>
-#include <asm/processor.h>
-#include <asm/math_emu.h>
-#include <asm/tlbflush.h>
-#include <asm/uaccess.h>
-#include <asm/ptrace.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h>
-#include <asm/user.h>
-
-static DEFINE_PER_CPU(bool, in_kernel_fpu);
-
-void kernel_fpu_disable(void)
-{
- WARN_ON(this_cpu_read(in_kernel_fpu));
- this_cpu_write(in_kernel_fpu, true);
-}
-
-void kernel_fpu_enable(void)
-{
- this_cpu_write(in_kernel_fpu, false);
-}
-
-/*
- * Were we in an interrupt that interrupted kernel mode?
- *
- * On others, we can do a kernel_fpu_begin/end() pair *ONLY* if that
- * pair does nothing at all: the thread must not have fpu (so
- * that we don't try to save the FPU state), and TS must
- * be set (so that the clts/stts pair does nothing that is
- * visible in the interrupted kernel thread).
- *
- * Except for the eagerfpu case when we return true; in the likely case
- * the thread has FPU but we are not going to set/clear TS.
- */
-static inline bool interrupted_kernel_fpu_idle(void)
-{
- if (this_cpu_read(in_kernel_fpu))
- return false;
-
- if (use_eager_fpu())
- return true;
-
- return !__thread_has_fpu(current) &&
- (read_cr0() & X86_CR0_TS);
-}
-
-/*
- * Were we in user mode (or vm86 mode) when we were
- * interrupted?
- *
- * Doing kernel_fpu_begin/end() is ok if we are running
- * in an interrupt context from user mode - we'll just
- * save the FPU state as required.
- */
-static inline bool interrupted_user_mode(void)
-{
- struct pt_regs *regs = get_irq_regs();
- return regs && user_mode(regs);
-}
-
-/*
- * Can we use the FPU in kernel mode with the
- * whole "kernel_fpu_begin/end()" sequence?
- *
- * It's always ok in process context (ie "not interrupt")
- * but it is sometimes ok even from an irq.
- */
-bool irq_fpu_usable(void)
-{
- return !in_interrupt() ||
- interrupted_user_mode() ||
- interrupted_kernel_fpu_idle();
-}
-EXPORT_SYMBOL(irq_fpu_usable);
-
-void __kernel_fpu_begin(void)
-{
- struct task_struct *me = current;
-
- this_cpu_write(in_kernel_fpu, true);
-
- if (__thread_has_fpu(me)) {
- __save_init_fpu(me);
- } else {
- this_cpu_write(fpu_owner_task, NULL);
- if (!use_eager_fpu())
- clts();
- }
-}
-EXPORT_SYMBOL(__kernel_fpu_begin);
-
-void __kernel_fpu_end(void)
-{
- struct task_struct *me = current;
-
- if (__thread_has_fpu(me)) {
- if (WARN_ON(restore_fpu_checking(me)))
- fpu_reset_state(me);
- } else if (!use_eager_fpu()) {
- stts();
- }
-
- this_cpu_write(in_kernel_fpu, false);
-}
-EXPORT_SYMBOL(__kernel_fpu_end);
-
-void unlazy_fpu(struct task_struct *tsk)
-{
- preempt_disable();
- if (__thread_has_fpu(tsk)) {
- if (use_eager_fpu()) {
- __save_fpu(tsk);
- } else {
- __save_init_fpu(tsk);
- __thread_fpu_end(tsk);
- }
- }
- preempt_enable();
-}
-EXPORT_SYMBOL(unlazy_fpu);
-
-unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
-unsigned int xstate_size;
-EXPORT_SYMBOL_GPL(xstate_size);
-static struct i387_fxsave_struct fx_scratch;
-
-static void mxcsr_feature_mask_init(void)
-{
- unsigned long mask = 0;
-
- if (cpu_has_fxsr) {
- memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
- asm volatile("fxsave %0" : "+m" (fx_scratch));
- mask = fx_scratch.mxcsr_mask;
- if (mask == 0)
- mask = 0x0000ffbf;
- }
- mxcsr_feature_mask &= mask;
-}
-
-static void init_thread_xstate(void)
-{
- /*
- * Note that xstate_size might be overwriten later during
- * xsave_init().
- */
-
- if (!cpu_has_fpu) {
- /*
- * Disable xsave as we do not support it if i387
- * emulation is enabled.
- */
- setup_clear_cpu_cap(X86_FEATURE_XSAVE);
- setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
- xstate_size = sizeof(struct i387_soft_struct);
- return;
- }
-
- if (cpu_has_fxsr)
- xstate_size = sizeof(struct i387_fxsave_struct);
- else
- xstate_size = sizeof(struct i387_fsave_struct);
-
- /*
- * Quirk: we don't yet handle the XSAVES* instructions
- * correctly, as we don't correctly convert between
- * standard and compacted format when interfacing
- * with user-space - so disable it for now.
- *
- * The difference is small: with recent CPUs the
- * compacted format is only marginally smaller than
- * the standard FPU state format.
- *
- * ( This is easy to backport while we are fixing
- * XSAVES* support. )
- */
- setup_clear_cpu_cap(X86_FEATURE_XSAVES);
-}
-
-/*
- * Called at bootup to set up the initial FPU state that is later cloned
- * into all processes.
- */
-
-void fpu_init(void)
-{
- unsigned long cr0;
- unsigned long cr4_mask = 0;
-
-#ifndef CONFIG_MATH_EMULATION
- if (!cpu_has_fpu) {
- pr_emerg("No FPU found and no math emulation present\n");
- pr_emerg("Giving up\n");
- for (;;)
- asm volatile("hlt");
- }
-#endif
- if (cpu_has_fxsr)
- cr4_mask |= X86_CR4_OSFXSR;
- if (cpu_has_xmm)
- cr4_mask |= X86_CR4_OSXMMEXCPT;
- if (cr4_mask)
- cr4_set_bits(cr4_mask);
-
- cr0 = read_cr0();
- cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */
- if (!cpu_has_fpu)
- cr0 |= X86_CR0_EM;
- write_cr0(cr0);
-
- /*
- * init_thread_xstate is only called once to avoid overriding
- * xstate_size during boot time or during CPU hotplug.
- */
- if (xstate_size == 0)
- init_thread_xstate();
-
- mxcsr_feature_mask_init();
- xsave_init();
- eager_fpu_init();
-}
-
-void fpu_finit(struct fpu *fpu)
-{
- if (!cpu_has_fpu) {
- finit_soft_fpu(&fpu->state->soft);
- return;
- }
-
- memset(fpu->state, 0, xstate_size);
-
- if (cpu_has_fxsr) {
- fx_finit(&fpu->state->fxsave);
- } else {
- struct i387_fsave_struct *fp = &fpu->state->fsave;
- fp->cwd = 0xffff037fu;
- fp->swd = 0xffff0000u;
- fp->twd = 0xffffffffu;
- fp->fos = 0xffff0000u;
- }
-}
-EXPORT_SYMBOL_GPL(fpu_finit);
-
-/*
- * The _current_ task is using the FPU for the first time
- * so initialize it and set the mxcsr to its default
- * value at reset if we support XMM instructions and then
- * remember the current task has used the FPU.
- */
-int init_fpu(struct task_struct *tsk)
-{
- int ret;
-
- if (tsk_used_math(tsk)) {
- if (cpu_has_fpu && tsk == current)
- unlazy_fpu(tsk);
- task_disable_lazy_fpu_restore(tsk);
- return 0;
- }
-
- /*
- * Memory allocation at the first usage of the FPU and other state.
- */
- ret = fpu_alloc(&tsk->thread.fpu);
- if (ret)
- return ret;
-
- fpu_finit(&tsk->thread.fpu);
-
- set_stopped_child_used_math(tsk);
- return 0;
-}
-EXPORT_SYMBOL_GPL(init_fpu);
-
-/*
- * The xstateregs_active() routine is the same as the fpregs_active() routine,
- * as the "regset->n" for the xstate regset will be updated based on the feature
- * capabilites supported by the xsave.
- */
-int fpregs_active(struct task_struct *target, const struct user_regset *regset)
-{
- return tsk_used_math(target) ? regset->n : 0;
-}
-
-int xfpregs_active(struct task_struct *target, const struct user_regset *regset)
-{
- return (cpu_has_fxsr && tsk_used_math(target)) ? regset->n : 0;
-}
-
-int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- void *kbuf, void __user *ubuf)
-{
- int ret;
-
- if (!cpu_has_fxsr)
- return -ENODEV;
-
- ret = init_fpu(target);
- if (ret)
- return ret;
-
- sanitize_i387_state(target);
-
- return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.fpu.state->fxsave, 0, -1);
-}
-
-int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- const void *kbuf, const void __user *ubuf)
-{
- int ret;
-
- if (!cpu_has_fxsr)
- return -ENODEV;
-
- ret = init_fpu(target);
- if (ret)
- return ret;
-
- sanitize_i387_state(target);
-
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.fpu.state->fxsave, 0, -1);
-
- /*
- * mxcsr reserved bits must be masked to zero for security reasons.
- */
- target->thread.fpu.state->fxsave.mxcsr &= mxcsr_feature_mask;
-
- /*
- * update the header bits in the xsave header, indicating the
- * presence of FP and SSE state.
- */
- if (cpu_has_xsave)
- target->thread.fpu.state->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
-
- return ret;
-}
-
-int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- void *kbuf, void __user *ubuf)
-{
- struct xsave_struct *xsave;
- int ret;
-
- if (!cpu_has_xsave)
- return -ENODEV;
-
- ret = init_fpu(target);
- if (ret)
- return ret;
-
- xsave = &target->thread.fpu.state->xsave;
-
- /*
- * Copy the 48bytes defined by the software first into the xstate
- * memory layout in the thread struct, so that we can copy the entire
- * xstateregs to the user using one user_regset_copyout().
- */
- memcpy(&xsave->i387.sw_reserved,
- xstate_fx_sw_bytes, sizeof(xstate_fx_sw_bytes));
- /*
- * Copy the xstate memory layout.
- */
- ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, xsave, 0, -1);
- return ret;
-}
-
-int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- const void *kbuf, const void __user *ubuf)
-{
- struct xsave_struct *xsave;
- int ret;
-
- if (!cpu_has_xsave)
- return -ENODEV;
-
- ret = init_fpu(target);
- if (ret)
- return ret;
-
- xsave = &target->thread.fpu.state->xsave;
-
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1);
- /*
- * mxcsr reserved bits must be masked to zero for security reasons.
- */
- xsave->i387.mxcsr &= mxcsr_feature_mask;
- xsave->xsave_hdr.xstate_bv &= pcntxt_mask;
- /*
- * These bits must be zero.
- */
- memset(&xsave->xsave_hdr.reserved, 0, 48);
- return ret;
-}
-
-#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
-
-/*
- * FPU tag word conversions.
- */
-
-static inline unsigned short twd_i387_to_fxsr(unsigned short twd)
-{
- unsigned int tmp; /* to avoid 16 bit prefixes in the code */
-
- /* Transform each pair of bits into 01 (valid) or 00 (empty) */
- tmp = ~twd;
- tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
- /* and move the valid bits to the lower byte. */
- tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
- tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
- tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
-
- return tmp;
-}
-
-#define FPREG_ADDR(f, n) ((void *)&(f)->st_space + (n) * 16)
-#define FP_EXP_TAG_VALID 0
-#define FP_EXP_TAG_ZERO 1
-#define FP_EXP_TAG_SPECIAL 2
-#define FP_EXP_TAG_EMPTY 3
-
-static inline u32 twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
-{
- struct _fpxreg *st;
- u32 tos = (fxsave->swd >> 11) & 7;
- u32 twd = (unsigned long) fxsave->twd;
- u32 tag;
- u32 ret = 0xffff0000u;
- int i;
-
- for (i = 0; i < 8; i++, twd >>= 1) {
- if (twd & 0x1) {
- st = FPREG_ADDR(fxsave, (i - tos) & 7);
-
- switch (st->exponent & 0x7fff) {
- case 0x7fff:
- tag = FP_EXP_TAG_SPECIAL;
- break;
- case 0x0000:
- if (!st->significand[0] &&
- !st->significand[1] &&
- !st->significand[2] &&
- !st->significand[3])
- tag = FP_EXP_TAG_ZERO;
- else
- tag = FP_EXP_TAG_SPECIAL;
- break;
- default:
- if (st->significand[3] & 0x8000)
- tag = FP_EXP_TAG_VALID;
- else
- tag = FP_EXP_TAG_SPECIAL;
- break;
- }
- } else {
- tag = FP_EXP_TAG_EMPTY;
- }
- ret |= tag << (2 * i);
- }
- return ret;
-}
-
-/*
- * FXSR floating point environment conversions.
- */
-
-void
-convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
-{
- struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave;
- struct _fpreg *to = (struct _fpreg *) &env->st_space[0];
- struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0];
- int i;
-
- env->cwd = fxsave->cwd | 0xffff0000u;
- env->swd = fxsave->swd | 0xffff0000u;
- env->twd = twd_fxsr_to_i387(fxsave);
-
-#ifdef CONFIG_X86_64
- env->fip = fxsave->rip;
- env->foo = fxsave->rdp;
- /*
- * should be actually ds/cs at fpu exception time, but
- * that information is not available in 64bit mode.
- */
- env->fcs = task_pt_regs(tsk)->cs;
- if (tsk == current) {
- savesegment(ds, env->fos);
- } else {
- env->fos = tsk->thread.ds;
- }
- env->fos |= 0xffff0000;
-#else
- env->fip = fxsave->fip;
- env->fcs = (u16) fxsave->fcs | ((u32) fxsave->fop << 16);
- env->foo = fxsave->foo;
- env->fos = fxsave->fos;
-#endif
-
- for (i = 0; i < 8; ++i)
- memcpy(&to[i], &from[i], sizeof(to[0]));
-}
-
-void convert_to_fxsr(struct task_struct *tsk,
- const struct user_i387_ia32_struct *env)
-
-{
- struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave;
- struct _fpreg *from = (struct _fpreg *) &env->st_space[0];
- struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0];
- int i;
-
- fxsave->cwd = env->cwd;
- fxsave->swd = env->swd;
- fxsave->twd = twd_i387_to_fxsr(env->twd);
- fxsave->fop = (u16) ((u32) env->fcs >> 16);
-#ifdef CONFIG_X86_64
- fxsave->rip = env->fip;
- fxsave->rdp = env->foo;
- /* cs and ds ignored */
-#else
- fxsave->fip = env->fip;
- fxsave->fcs = (env->fcs & 0xffff);
- fxsave->foo = env->foo;
- fxsave->fos = env->fos;
-#endif
-
- for (i = 0; i < 8; ++i)
- memcpy(&to[i], &from[i], sizeof(from[0]));
-}
-
-int fpregs_get(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- void *kbuf, void __user *ubuf)
-{
- struct user_i387_ia32_struct env;
- int ret;
-
- ret = init_fpu(target);
- if (ret)
- return ret;
-
- if (!static_cpu_has(X86_FEATURE_FPU))
- return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf);
-
- if (!cpu_has_fxsr)
- return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.fpu.state->fsave, 0,
- -1);
-
- sanitize_i387_state(target);
-
- if (kbuf && pos == 0 && count == sizeof(env)) {
- convert_from_fxsr(kbuf, target);
- return 0;
- }
-
- convert_from_fxsr(&env, target);
-
- return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
-}
-
-int fpregs_set(struct task_struct *target, const struct user_regset *regset,
- unsigned int pos, unsigned int count,
- const void *kbuf, const void __user *ubuf)
-{
- struct user_i387_ia32_struct env;
- int ret;
-
- ret = init_fpu(target);
- if (ret)
- return ret;
-
- sanitize_i387_state(target);
-
- if (!static_cpu_has(X86_FEATURE_FPU))
- return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf);
-
- if (!cpu_has_fxsr)
- return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.fpu.state->fsave, 0,
- -1);
-
- if (pos > 0 || count < sizeof(env))
- convert_from_fxsr(&env, target);
-
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &env, 0, -1);
- if (!ret)
- convert_to_fxsr(target, &env);
-
- /*
- * update the header bit in the xsave header, indicating the
- * presence of FP.
- */
- if (cpu_has_xsave)
- target->thread.fpu.state->xsave.xsave_hdr.xstate_bv |= XSTATE_FP;
- return ret;
-}
-
-/*
- * FPU state for core dumps.
- * This is only used for a.out dumps now.
- * It is declared generically using elf_fpregset_t (which is
- * struct user_i387_struct) but is in fact only used for 32-bit
- * dumps, so on 64-bit it is really struct user_i387_ia32_struct.
- */
-int dump_fpu(struct pt_regs *regs, struct user_i387_struct *fpu)
-{
- struct task_struct *tsk = current;
- int fpvalid;
-
- fpvalid = !!used_math();
- if (fpvalid)
- fpvalid = !fpregs_get(tsk, NULL,
- 0, sizeof(struct user_i387_ia32_struct),
- fpu, NULL);
-
- return fpvalid;
-}
-EXPORT_SYMBOL(dump_fpu);
-
-#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
-
-static int __init no_387(char *s)
-{
- setup_clear_cpu_cap(X86_FEATURE_FPU);
- return 1;
-}
-
-__setup("no387", no_387);
-
-void fpu_detect(struct cpuinfo_x86 *c)
-{
- unsigned long cr0;
- u16 fsw, fcw;
-
- fsw = fcw = 0xffff;
-
- cr0 = read_cr0();
- cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
- write_cr0(cr0);
-
- asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
- : "+m" (fsw), "+m" (fcw));
-
- if (fsw == 0 && (fcw & 0x103f) == 0x003f)
- set_cpu_cap(c, X86_FEATURE_FPU);
- else
- clear_cpu_cap(c, X86_FEATURE_FPU);
-
- /* The final cr0 value is set in fpu_init() */
-}
diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c
index e7cc5370cd2f..16cb827a5b27 100644
--- a/arch/x86/kernel/i8259.c
+++ b/arch/x86/kernel/i8259.c
@@ -329,8 +329,8 @@ static void init_8259A(int auto_eoi)
*/
outb_pic(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */
- /* ICW2: 8259A-1 IR0-7 mapped to 0x30-0x37 */
- outb_pic(IRQ0_VECTOR, PIC_MASTER_IMR);
+ /* ICW2: 8259A-1 IR0-7 mapped to ISA_IRQ_VECTOR(0) */
+ outb_pic(ISA_IRQ_VECTOR(0), PIC_MASTER_IMR);
/* 8259A-1 (the master) has a slave on IR2 */
outb_pic(1U << PIC_CASCADE_IR, PIC_MASTER_IMR);
@@ -342,8 +342,8 @@ static void init_8259A(int auto_eoi)
outb_pic(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */
- /* ICW2: 8259A-2 IR0-7 mapped to IRQ8_VECTOR */
- outb_pic(IRQ8_VECTOR, PIC_SLAVE_IMR);
+ /* ICW2: 8259A-2 IR0-7 mapped to ISA_IRQ_VECTOR(8) */
+ outb_pic(ISA_IRQ_VECTOR(8), PIC_SLAVE_IMR);
/* 8259A-2 is a slave on master's IR2 */
outb_pic(PIC_CASCADE_IR, PIC_SLAVE_IMR);
/* (slave's support for AEOI in flat mode is to be investigated) */
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index e5952c225532..88b366487b0e 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -22,6 +22,12 @@
#define CREATE_TRACE_POINTS
#include <asm/trace/irq_vectors.h>
+DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
+EXPORT_PER_CPU_SYMBOL(irq_stat);
+
+DEFINE_PER_CPU(struct pt_regs *, irq_regs);
+EXPORT_PER_CPU_SYMBOL(irq_regs);
+
atomic_t irq_err_count;
/* Function pointer for generic interrupt vector handling */
@@ -116,6 +122,12 @@ int arch_show_interrupts(struct seq_file *p, int prec)
seq_printf(p, "%10u ", irq_stats(j)->irq_threshold_count);
seq_puts(p, " Threshold APIC interrupts\n");
#endif
+#ifdef CONFIG_X86_MCE_AMD
+ seq_printf(p, "%*s: ", prec, "DFR");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stats(j)->irq_deferred_error_count);
+ seq_puts(p, " Deferred Error APIC interrupts\n");
+#endif
#ifdef CONFIG_X86_MCE
seq_printf(p, "%*s: ", prec, "MCE");
for_each_online_cpu(j)
@@ -136,6 +148,18 @@ int arch_show_interrupts(struct seq_file *p, int prec)
#if defined(CONFIG_X86_IO_APIC)
seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count));
#endif
+#ifdef CONFIG_HAVE_KVM
+ seq_printf(p, "%*s: ", prec, "PIN");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stats(j)->kvm_posted_intr_ipis);
+ seq_puts(p, " Posted-interrupt notification event\n");
+
+ seq_printf(p, "%*s: ", prec, "PIW");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ",
+ irq_stats(j)->kvm_posted_intr_wakeup_ipis);
+ seq_puts(p, " Posted-interrupt wakeup event\n");
+#endif
return 0;
}
@@ -192,8 +216,7 @@ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
unsigned vector = ~regs->orig_ax;
unsigned irq;
- irq_enter();
- exit_idle();
+ entering_irq();
irq = __this_cpu_read(vector_irq[vector]);
@@ -209,7 +232,7 @@ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
}
}
- irq_exit();
+ exiting_irq();
set_irq_regs(old_regs);
return 1;
@@ -237,6 +260,18 @@ __visible void smp_x86_platform_ipi(struct pt_regs *regs)
}
#ifdef CONFIG_HAVE_KVM
+static void dummy_handler(void) {}
+static void (*kvm_posted_intr_wakeup_handler)(void) = dummy_handler;
+
+void kvm_set_posted_intr_wakeup_handler(void (*handler)(void))
+{
+ if (handler)
+ kvm_posted_intr_wakeup_handler = handler;
+ else
+ kvm_posted_intr_wakeup_handler = dummy_handler;
+}
+EXPORT_SYMBOL_GPL(kvm_set_posted_intr_wakeup_handler);
+
/*
* Handler for POSTED_INTERRUPT_VECTOR.
*/
@@ -244,16 +279,23 @@ __visible void smp_kvm_posted_intr_ipi(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
- ack_APIC_irq();
-
- irq_enter();
-
- exit_idle();
-
+ entering_ack_irq();
inc_irq_stat(kvm_posted_intr_ipis);
+ exiting_irq();
+ set_irq_regs(old_regs);
+}
- irq_exit();
+/*
+ * Handler for POSTED_INTERRUPT_WAKEUP_VECTOR.
+ */
+__visible void smp_kvm_posted_intr_wakeup_ipi(struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ entering_ack_irq();
+ inc_irq_stat(kvm_posted_intr_wakeup_ipis);
+ kvm_posted_intr_wakeup_handler();
+ exiting_irq();
set_irq_regs(old_regs);
}
#endif
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index f9fd86a7fcc7..cd74f5978ab9 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -21,12 +21,6 @@
#include <asm/apic.h>
-DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
-EXPORT_PER_CPU_SYMBOL(irq_stat);
-
-DEFINE_PER_CPU(struct pt_regs *, irq_regs);
-EXPORT_PER_CPU_SYMBOL(irq_regs);
-
#ifdef CONFIG_DEBUG_STACKOVERFLOW
int sysctl_panic_on_stackoverflow __read_mostly;
diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c
index 394e643d7830..bc4604e500a3 100644
--- a/arch/x86/kernel/irq_64.c
+++ b/arch/x86/kernel/irq_64.c
@@ -20,12 +20,6 @@
#include <asm/idle.h>
#include <asm/apic.h>
-DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
-EXPORT_PER_CPU_SYMBOL(irq_stat);
-
-DEFINE_PER_CPU(struct pt_regs *, irq_regs);
-EXPORT_PER_CPU_SYMBOL(irq_regs);
-
int sysctl_panic_on_stackoverflow;
/*
diff --git a/arch/x86/kernel/irq_work.c b/arch/x86/kernel/irq_work.c
index 15d741ddfeeb..dc5fa6a1e8d6 100644
--- a/arch/x86/kernel/irq_work.c
+++ b/arch/x86/kernel/irq_work.c
@@ -10,12 +10,6 @@
#include <asm/apic.h>
#include <asm/trace/irq_vectors.h>
-static inline void irq_work_entering_irq(void)
-{
- irq_enter();
- ack_APIC_irq();
-}
-
static inline void __smp_irq_work_interrupt(void)
{
inc_irq_stat(apic_irq_work_irqs);
@@ -24,14 +18,14 @@ static inline void __smp_irq_work_interrupt(void)
__visible void smp_irq_work_interrupt(struct pt_regs *regs)
{
- irq_work_entering_irq();
+ ipi_entering_ack_irq();
__smp_irq_work_interrupt();
exiting_irq();
}
__visible void smp_trace_irq_work_interrupt(struct pt_regs *regs)
{
- irq_work_entering_irq();
+ ipi_entering_ack_irq();
trace_irq_work_entry(IRQ_WORK_VECTOR);
__smp_irq_work_interrupt();
trace_irq_work_exit(IRQ_WORK_VECTOR);
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
index cd10a6437264..a3a5e158ed69 100644
--- a/arch/x86/kernel/irqinit.c
+++ b/arch/x86/kernel/irqinit.c
@@ -86,7 +86,7 @@ void __init init_IRQ(void)
int i;
/*
- * On cpu 0, Assign IRQ0_VECTOR..IRQ15_VECTOR's to IRQ 0..15.
+ * On cpu 0, Assign ISA_IRQ_VECTOR(irq) to IRQ 0..15.
* If these IRQ's are handled by legacy interrupt-controllers like PIC,
* then this configuration will likely be static after the boot. If
* these IRQ's are handled by more mordern controllers like IO-APIC,
@@ -94,7 +94,7 @@ void __init init_IRQ(void)
* irq's migrate etc.
*/
for (i = 0; i < nr_legacy_irqs(); i++)
- per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i;
+ per_cpu(vector_irq, 0)[ISA_IRQ_VECTOR(i)] = i;
x86_init.irqs.intr_init();
}
@@ -135,6 +135,10 @@ static void __init apic_intr_init(void)
alloc_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
#endif
+#ifdef CONFIG_X86_MCE_AMD
+ alloc_intr_gate(DEFERRED_ERROR_VECTOR, deferred_error_interrupt);
+#endif
+
#ifdef CONFIG_X86_LOCAL_APIC
/* self generated IPI for local APIC timer */
alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
@@ -144,6 +148,8 @@ static void __init apic_intr_init(void)
#ifdef CONFIG_HAVE_KVM
/* IPI for KVM to deliver posted interrupt */
alloc_intr_gate(POSTED_INTR_VECTOR, kvm_posted_intr_ipi);
+ /* IPI for KVM to deliver interrupt to wake up tasks */
+ alloc_intr_gate(POSTED_INTR_WAKEUP_VECTOR, kvm_posted_intr_wakeup_ipi);
#endif
/* IPI vectors for APIC spurious and error interrupts */
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 9435620062df..47190bd399e7 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -331,7 +331,7 @@ static void kvm_guest_apic_eoi_write(u32 reg, u32 val)
apic_write(APIC_EOI, APIC_EOI_ACK);
}
-void kvm_guest_cpu_init(void)
+static void kvm_guest_cpu_init(void)
{
if (!kvm_para_available())
return;
@@ -584,6 +584,39 @@ static void kvm_kick_cpu(int cpu)
kvm_hypercall2(KVM_HC_KICK_CPU, flags, apicid);
}
+
+#ifdef CONFIG_QUEUED_SPINLOCKS
+
+#include <asm/qspinlock.h>
+
+static void kvm_wait(u8 *ptr, u8 val)
+{
+ unsigned long flags;
+
+ if (in_nmi())
+ return;
+
+ local_irq_save(flags);
+
+ if (READ_ONCE(*ptr) != val)
+ goto out;
+
+ /*
+ * halt until it's our turn and kicked. Note that we do safe halt
+ * for irq enabled case to avoid hang when lock info is overwritten
+ * in irq spinlock slowpath and no spurious interrupt occur to save us.
+ */
+ if (arch_irqs_disabled_flags(flags))
+ halt();
+ else
+ safe_halt();
+
+out:
+ local_irq_restore(flags);
+}
+
+#else /* !CONFIG_QUEUED_SPINLOCKS */
+
enum kvm_contention_stat {
TAKEN_SLOW,
TAKEN_SLOW_PICKUP,
@@ -655,7 +688,7 @@ static inline void spin_time_accum_blocked(u64 start)
static struct dentry *d_spin_debug;
static struct dentry *d_kvm_debug;
-struct dentry *kvm_init_debugfs(void)
+static struct dentry *kvm_init_debugfs(void)
{
d_kvm_debug = debugfs_create_dir("kvm-guest", NULL);
if (!d_kvm_debug)
@@ -817,6 +850,8 @@ static void kvm_unlock_kick(struct arch_spinlock *lock, __ticket_t ticket)
}
}
+#endif /* !CONFIG_QUEUED_SPINLOCKS */
+
/*
* Setup pv_lock_ops to exploit KVM_FEATURE_PV_UNHALT if present.
*/
@@ -828,8 +863,16 @@ void __init kvm_spinlock_init(void)
if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT))
return;
+#ifdef CONFIG_QUEUED_SPINLOCKS
+ __pv_init_lock_hash();
+ pv_lock_ops.queued_spin_lock_slowpath = __pv_queued_spin_lock_slowpath;
+ pv_lock_ops.queued_spin_unlock = PV_CALLEE_SAVE(__pv_queued_spin_unlock);
+ pv_lock_ops.wait = kvm_wait;
+ pv_lock_ops.kick = kvm_kick_cpu;
+#else /* !CONFIG_QUEUED_SPINLOCKS */
pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(kvm_lock_spinning);
pv_lock_ops.unlock_kick = kvm_unlock_kick;
+#endif
}
static __init int kvm_spinlock_init_jump(void)
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index 42caaef897c8..49487b488061 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -24,6 +24,7 @@
#include <linux/percpu.h>
#include <linux/hardirq.h>
#include <linux/memblock.h>
+#include <linux/sched.h>
#include <asm/x86_init.h>
#include <asm/reboot.h>
@@ -217,8 +218,10 @@ static void kvm_shutdown(void)
void __init kvmclock_init(void)
{
+ struct pvclock_vcpu_time_info *vcpu_time;
unsigned long mem;
- int size;
+ int size, cpu;
+ u8 flags;
size = PAGE_ALIGN(sizeof(struct pvclock_vsyscall_time_info)*NR_CPUS);
@@ -264,7 +267,14 @@ void __init kvmclock_init(void)
pv_info.name = "KVM";
if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT))
- pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
+ pvclock_set_flags(~0);
+
+ cpu = get_cpu();
+ vcpu_time = &hv_clock[cpu].pvti;
+ flags = pvclock_read_flags(vcpu_time);
+ if (flags & PVCLOCK_COUNTS_FROM_ZERO)
+ set_sched_clock_stable();
+ put_cpu();
}
int __init kvm_setup_vsyscall_timeinfo(void)
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index 415480d3ea84..819ab3f9c9c7 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -17,6 +17,7 @@
#include <linux/ftrace.h>
#include <linux/io.h>
#include <linux/suspend.h>
+#include <linux/vmalloc.h>
#include <asm/init.h>
#include <asm/pgtable.h>
@@ -25,6 +26,7 @@
#include <asm/io_apic.h>
#include <asm/debugreg.h>
#include <asm/kexec-bzimage64.h>
+#include <asm/setup.h>
#ifdef CONFIG_KEXEC_FILE
static struct kexec_file_ops *kexec_file_loaders[] = {
@@ -334,7 +336,7 @@ void arch_crash_save_vmcoreinfo(void)
VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
#endif
vmcoreinfo_append_str("KERNELOFFSET=%lx\n",
- (unsigned long)&_text - __START_KERNEL);
+ kaslr_offset());
}
/* arch-dependent functionality related to kexec file-based syscall */
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index 2d2a237f2c73..30ca7607cbbb 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -19,8 +19,8 @@
#include <linux/module.h>
#include <linux/smp.h>
#include <linux/pci.h>
-#include <linux/irqdomain.h>
+#include <asm/irqdomain.h>
#include <asm/mtrr.h>
#include <asm/mpspec.h>
#include <asm/pgalloc.h>
@@ -113,11 +113,6 @@ static void __init MP_bus_info(struct mpc_bus *m)
pr_warn("Unknown bustype %s - ignoring\n", str);
}
-static struct irq_domain_ops mp_ioapic_irqdomain_ops = {
- .map = mp_irqdomain_map,
- .unmap = mp_irqdomain_unmap,
-};
-
static void __init MP_ioapic_info(struct mpc_ioapic *m)
{
struct ioapic_domain_cfg cfg = {
diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c
index bbb6c7316341..33ee3e0efd65 100644
--- a/arch/x86/kernel/paravirt-spinlocks.c
+++ b/arch/x86/kernel/paravirt-spinlocks.c
@@ -8,11 +8,33 @@
#include <asm/paravirt.h>
+#ifdef CONFIG_QUEUED_SPINLOCKS
+__visible void __native_queued_spin_unlock(struct qspinlock *lock)
+{
+ native_queued_spin_unlock(lock);
+}
+
+PV_CALLEE_SAVE_REGS_THUNK(__native_queued_spin_unlock);
+
+bool pv_is_native_spin_unlock(void)
+{
+ return pv_lock_ops.queued_spin_unlock.func ==
+ __raw_callee_save___native_queued_spin_unlock;
+}
+#endif
+
struct pv_lock_ops pv_lock_ops = {
#ifdef CONFIG_SMP
+#ifdef CONFIG_QUEUED_SPINLOCKS
+ .queued_spin_lock_slowpath = native_queued_spin_lock_slowpath,
+ .queued_spin_unlock = PV_CALLEE_SAVE(__native_queued_spin_unlock),
+ .wait = paravirt_nop,
+ .kick = paravirt_nop,
+#else /* !CONFIG_QUEUED_SPINLOCKS */
.lock_spinning = __PV_IS_CALLEE_SAVE(paravirt_nop),
.unlock_kick = paravirt_nop,
-#endif
+#endif /* !CONFIG_QUEUED_SPINLOCKS */
+#endif /* SMP */
};
EXPORT_SYMBOL(pv_lock_ops);
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index c614dd492f5f..58bcfb67c01f 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -154,7 +154,9 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
ret = paravirt_patch_ident_64(insnbuf, len);
else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
+#ifdef CONFIG_X86_32
type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) ||
+#endif
type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret32) ||
type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64))
/* If operation requires a jmp, then jmp */
@@ -371,7 +373,7 @@ __visible struct pv_cpu_ops pv_cpu_ops = {
.load_sp0 = native_load_sp0,
-#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
+#if defined(CONFIG_X86_32)
.irq_enable_sysexit = native_irq_enable_sysexit,
#endif
#ifdef CONFIG_X86_64
diff --git a/arch/x86/kernel/paravirt_patch_32.c b/arch/x86/kernel/paravirt_patch_32.c
index d9f32e6d6ab6..e1b013696dde 100644
--- a/arch/x86/kernel/paravirt_patch_32.c
+++ b/arch/x86/kernel/paravirt_patch_32.c
@@ -12,6 +12,10 @@ DEF_NATIVE(pv_mmu_ops, read_cr3, "mov %cr3, %eax");
DEF_NATIVE(pv_cpu_ops, clts, "clts");
DEF_NATIVE(pv_cpu_ops, read_tsc, "rdtsc");
+#if defined(CONFIG_PARAVIRT_SPINLOCKS) && defined(CONFIG_QUEUED_SPINLOCKS)
+DEF_NATIVE(pv_lock_ops, queued_spin_unlock, "movb $0, (%eax)");
+#endif
+
unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len)
{
/* arg in %eax, return in %eax */
@@ -24,6 +28,8 @@ unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len)
return 0;
}
+extern bool pv_is_native_spin_unlock(void);
+
unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
unsigned long addr, unsigned len)
{
@@ -47,14 +53,22 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
PATCH_SITE(pv_mmu_ops, write_cr3);
PATCH_SITE(pv_cpu_ops, clts);
PATCH_SITE(pv_cpu_ops, read_tsc);
-
- patch_site:
- ret = paravirt_patch_insns(ibuf, len, start, end);
- break;
+#if defined(CONFIG_PARAVIRT_SPINLOCKS) && defined(CONFIG_QUEUED_SPINLOCKS)
+ case PARAVIRT_PATCH(pv_lock_ops.queued_spin_unlock):
+ if (pv_is_native_spin_unlock()) {
+ start = start_pv_lock_ops_queued_spin_unlock;
+ end = end_pv_lock_ops_queued_spin_unlock;
+ goto patch_site;
+ }
+#endif
default:
ret = paravirt_patch_default(type, clobbers, ibuf, addr, len);
break;
+
+patch_site:
+ ret = paravirt_patch_insns(ibuf, len, start, end);
+ break;
}
#undef PATCH_SITE
return ret;
diff --git a/arch/x86/kernel/paravirt_patch_64.c b/arch/x86/kernel/paravirt_patch_64.c
index a1da6737ba5b..8aa05583bc42 100644
--- a/arch/x86/kernel/paravirt_patch_64.c
+++ b/arch/x86/kernel/paravirt_patch_64.c
@@ -21,6 +21,10 @@ DEF_NATIVE(pv_cpu_ops, swapgs, "swapgs");
DEF_NATIVE(, mov32, "mov %edi, %eax");
DEF_NATIVE(, mov64, "mov %rdi, %rax");
+#if defined(CONFIG_PARAVIRT_SPINLOCKS) && defined(CONFIG_QUEUED_SPINLOCKS)
+DEF_NATIVE(pv_lock_ops, queued_spin_unlock, "movb $0, (%rdi)");
+#endif
+
unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len)
{
return paravirt_patch_insns(insnbuf, len,
@@ -33,6 +37,8 @@ unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len)
start__mov64, end__mov64);
}
+extern bool pv_is_native_spin_unlock(void);
+
unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
unsigned long addr, unsigned len)
{
@@ -49,7 +55,6 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
PATCH_SITE(pv_irq_ops, save_fl);
PATCH_SITE(pv_irq_ops, irq_enable);
PATCH_SITE(pv_irq_ops, irq_disable);
- PATCH_SITE(pv_cpu_ops, irq_enable_sysexit);
PATCH_SITE(pv_cpu_ops, usergs_sysret32);
PATCH_SITE(pv_cpu_ops, usergs_sysret64);
PATCH_SITE(pv_cpu_ops, swapgs);
@@ -59,14 +64,22 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
PATCH_SITE(pv_cpu_ops, clts);
PATCH_SITE(pv_mmu_ops, flush_tlb_single);
PATCH_SITE(pv_cpu_ops, wbinvd);
-
- patch_site:
- ret = paravirt_patch_insns(ibuf, len, start, end);
- break;
+#if defined(CONFIG_PARAVIRT_SPINLOCKS) && defined(CONFIG_QUEUED_SPINLOCKS)
+ case PARAVIRT_PATCH(pv_lock_ops.queued_spin_unlock):
+ if (pv_is_native_spin_unlock()) {
+ start = start_pv_lock_ops_queued_spin_unlock;
+ end = end_pv_lock_ops_queued_spin_unlock;
+ goto patch_site;
+ }
+#endif
default:
ret = paravirt_patch_default(type, clobbers, ibuf, addr, len);
break;
+
+patch_site:
+ ret = paravirt_patch_insns(ibuf, len, start, end);
+ break;
}
#undef PATCH_SITE
return ret;
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index a25e202bb319..353972c1946c 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -140,6 +140,51 @@ void dma_generic_free_coherent(struct device *dev, size_t size, void *vaddr,
free_pages((unsigned long)vaddr, get_order(size));
}
+void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ gfp_t gfp, struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ void *memory;
+
+ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32);
+
+ if (dma_alloc_from_coherent(dev, size, dma_handle, &memory))
+ return memory;
+
+ if (!dev)
+ dev = &x86_dma_fallback_dev;
+
+ if (!is_device_dma_capable(dev))
+ return NULL;
+
+ if (!ops->alloc)
+ return NULL;
+
+ memory = ops->alloc(dev, size, dma_handle,
+ dma_alloc_coherent_gfp_flags(dev, gfp), attrs);
+ debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
+
+ return memory;
+}
+EXPORT_SYMBOL(dma_alloc_attrs);
+
+void dma_free_attrs(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t bus,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
+ WARN_ON(irqs_disabled()); /* for portability */
+
+ if (dma_release_from_coherent(dev, get_order(size), vaddr))
+ return;
+
+ debug_dma_free_coherent(dev, size, vaddr, bus);
+ if (ops->free)
+ ops->free(dev, size, vaddr, bus, attrs);
+}
+EXPORT_SYMBOL(dma_free_attrs);
+
/*
* See <Documentation/x86/x86_64/boot-options.txt> for the iommu kernel
* parameter documentation.
diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c
index 77dd0ad58be4..adf0392d549a 100644
--- a/arch/x86/kernel/pci-swiotlb.c
+++ b/arch/x86/kernel/pci-swiotlb.c
@@ -20,6 +20,13 @@ void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
{
void *vaddr;
+ /*
+ * Don't print a warning when the first allocation attempt fails.
+ * swiotlb_alloc_coherent() will print a warning when the DMA
+ * memory allocation ultimately failed.
+ */
+ flags |= __GFP_NOWARN;
+
vaddr = dma_generic_alloc_coherent(hwdev, size, dma_handle, flags,
attrs);
if (vaddr)
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 6e338e3b1dc0..9cad694ed7c4 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -25,8 +25,7 @@
#include <asm/idle.h>
#include <asm/uaccess.h>
#include <asm/mwait.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h>
+#include <asm/fpu/internal.h>
#include <asm/debugreg.h>
#include <asm/nmi.h>
#include <asm/tlbflush.h>
@@ -76,9 +75,6 @@ void idle_notifier_unregister(struct notifier_block *n)
EXPORT_SYMBOL_GPL(idle_notifier_unregister);
#endif
-struct kmem_cache *task_xstate_cachep;
-EXPORT_SYMBOL_GPL(task_xstate_cachep);
-
/*
* this gets called so that we can store lazy state into memory and copy the
* current task into the new thread.
@@ -87,36 +83,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
*dst = *src;
- dst->thread.fpu_counter = 0;
- dst->thread.fpu.has_fpu = 0;
- dst->thread.fpu.state = NULL;
- task_disable_lazy_fpu_restore(dst);
- if (tsk_used_math(src)) {
- int err = fpu_alloc(&dst->thread.fpu);
- if (err)
- return err;
- fpu_copy(dst, src);
- }
- return 0;
-}
-
-void free_thread_xstate(struct task_struct *tsk)
-{
- fpu_free(&tsk->thread.fpu);
-}
-
-void arch_release_task_struct(struct task_struct *tsk)
-{
- free_thread_xstate(tsk);
-}
-
-void arch_task_cache_init(void)
-{
- task_xstate_cachep =
- kmem_cache_create("task_xstate", xstate_size,
- __alignof__(union thread_xstate),
- SLAB_PANIC | SLAB_NOTRACK, NULL);
- setup_xstate_comp();
+ return fpu__copy(&dst->thread.fpu, &src->thread.fpu);
}
/*
@@ -127,6 +94,7 @@ void exit_thread(void)
struct task_struct *me = current;
struct thread_struct *t = &me->thread;
unsigned long *bp = t->io_bitmap_ptr;
+ struct fpu *fpu = &t->fpu;
if (bp) {
struct tss_struct *tss = &per_cpu(cpu_tss, get_cpu());
@@ -142,7 +110,7 @@ void exit_thread(void)
kfree(bp);
}
- drop_fpu(me);
+ fpu__drop(fpu);
}
void flush_thread(void)
@@ -152,19 +120,7 @@ void flush_thread(void)
flush_ptrace_hw_breakpoint(tsk);
memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
- if (!use_eager_fpu()) {
- /* FPU state will be reallocated lazily at the first use. */
- drop_fpu(tsk);
- free_thread_xstate(tsk);
- } else {
- if (!tsk_used_math(tsk)) {
- /* kthread execs. TODO: cleanup this horror. */
- if (WARN_ON(init_fpu(tsk)))
- force_sig(SIGKILL, tsk);
- user_fpu_begin();
- }
- restore_init_xstate();
- }
+ fpu__clear(&tsk->thread.fpu);
}
static void hard_disable_TSC(void)
@@ -445,11 +401,10 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
}
/*
- * MONITOR/MWAIT with no hints, used for default default C1 state.
- * This invokes MWAIT with interrutps enabled and no flags,
- * which is backwards compatible with the original MWAIT implementation.
+ * MONITOR/MWAIT with no hints, used for default C1 state. This invokes MWAIT
+ * with interrupts enabled and no flags, which is backwards compatible with the
+ * original MWAIT implementation.
*/
-
static void mwait_idle(void)
{
if (!current_set_polling_and_test()) {
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 8ed2106b06da..c09c99ccf3e3 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -39,8 +39,7 @@
#include <asm/pgtable.h>
#include <asm/ldt.h>
#include <asm/processor.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h>
+#include <asm/fpu/internal.h>
#include <asm/desc.h>
#ifdef CONFIG_MATH_EMULATION
#include <asm/math_emu.h>
@@ -242,14 +241,16 @@ __visible __notrace_funcgraph struct task_struct *
__switch_to(struct task_struct *prev_p, struct task_struct *next_p)
{
struct thread_struct *prev = &prev_p->thread,
- *next = &next_p->thread;
+ *next = &next_p->thread;
+ struct fpu *prev_fpu = &prev->fpu;
+ struct fpu *next_fpu = &next->fpu;
int cpu = smp_processor_id();
struct tss_struct *tss = &per_cpu(cpu_tss, cpu);
- fpu_switch_t fpu;
+ fpu_switch_t fpu_switch;
/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
- fpu = switch_fpu_prepare(prev_p, next_p, cpu);
+ fpu_switch = switch_fpu_prepare(prev_fpu, next_fpu, cpu);
/*
* Save away %gs. No need to save %fs, as it was saved on the
@@ -296,19 +297,16 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
* Leave lazy mode, flushing any hypercalls made here.
* This must be done before restoring TLS segments so
* the GDT and LDT are properly updated, and must be
- * done before math_state_restore, so the TS bit is up
+ * done before fpu__restore(), so the TS bit is up
* to date.
*/
arch_end_context_switch(next_p);
/*
- * Reload esp0, kernel_stack, and current_top_of_stack. This changes
+ * Reload esp0 and cpu_current_top_of_stack. This changes
* current_thread_info().
*/
load_sp0(tss, next);
- this_cpu_write(kernel_stack,
- (unsigned long)task_stack_page(next_p) +
- THREAD_SIZE);
this_cpu_write(cpu_current_top_of_stack,
(unsigned long)task_stack_page(next_p) +
THREAD_SIZE);
@@ -319,7 +317,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
if (prev->gs | next->gs)
lazy_load_gs(next->gs);
- switch_fpu_finish(next_p, fpu);
+ switch_fpu_finish(next_fpu, fpu_switch);
this_cpu_write(current_task, next_p);
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index ddfdbf74f174..843f92e4c711 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -38,8 +38,7 @@
#include <asm/pgtable.h>
#include <asm/processor.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h>
+#include <asm/fpu/internal.h>
#include <asm/mmu_context.h>
#include <asm/prctl.h>
#include <asm/desc.h>
@@ -274,12 +273,14 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
{
struct thread_struct *prev = &prev_p->thread;
struct thread_struct *next = &next_p->thread;
+ struct fpu *prev_fpu = &prev->fpu;
+ struct fpu *next_fpu = &next->fpu;
int cpu = smp_processor_id();
struct tss_struct *tss = &per_cpu(cpu_tss, cpu);
unsigned fsindex, gsindex;
- fpu_switch_t fpu;
+ fpu_switch_t fpu_switch;
- fpu = switch_fpu_prepare(prev_p, next_p, cpu);
+ fpu_switch = switch_fpu_prepare(prev_fpu, next_fpu, cpu);
/* We must save %fs and %gs before load_TLS() because
* %fs and %gs may be cleared by load_TLS().
@@ -299,7 +300,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
* Leave lazy mode, flushing any hypercalls made here. This
* must be done after loading TLS entries in the GDT but before
* loading segments that might reference them, and and it must
- * be done before math_state_restore, so the TS bit is up to
+ * be done before fpu__restore(), so the TS bit is up to
* date.
*/
arch_end_context_switch(next_p);
@@ -391,7 +392,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
wrmsrl(MSR_KERNEL_GS_BASE, next->gs);
prev->gsindex = gsindex;
- switch_fpu_finish(next_p, fpu);
+ switch_fpu_finish(next_fpu, fpu_switch);
/*
* Switch the PDA and FPU contexts.
@@ -409,9 +410,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
/* Reload esp0 and ss1. This changes current_thread_info(). */
load_sp0(tss, next);
- this_cpu_write(kernel_stack,
- (unsigned long)task_stack_page(next_p) + THREAD_SIZE);
-
/*
* Now maybe reload the debug registers and handle I/O bitmaps
*/
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index a7bc79480719..9be72bc3613f 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -11,7 +11,6 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/ptrace.h>
-#include <linux/regset.h>
#include <linux/tracehook.h>
#include <linux/user.h>
#include <linux/elf.h>
@@ -28,8 +27,9 @@
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h>
+#include <asm/fpu/internal.h>
+#include <asm/fpu/signal.h>
+#include <asm/fpu/regset.h>
#include <asm/debugreg.h>
#include <asm/ldt.h>
#include <asm/desc.h>
@@ -1297,7 +1297,7 @@ static struct user_regset x86_64_regsets[] __read_mostly = {
.core_note_type = NT_PRFPREG,
.n = sizeof(struct user_i387_struct) / sizeof(long),
.size = sizeof(long), .align = sizeof(long),
- .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set
+ .active = regset_xregset_fpregs_active, .get = xfpregs_get, .set = xfpregs_set
},
[REGSET_XSTATE] = {
.core_note_type = NT_X86_XSTATE,
@@ -1338,13 +1338,13 @@ static struct user_regset x86_32_regsets[] __read_mostly = {
.core_note_type = NT_PRFPREG,
.n = sizeof(struct user_i387_ia32_struct) / sizeof(u32),
.size = sizeof(u32), .align = sizeof(u32),
- .active = fpregs_active, .get = fpregs_get, .set = fpregs_set
+ .active = regset_fpregs_active, .get = fpregs_get, .set = fpregs_set
},
[REGSET_XFP] = {
.core_note_type = NT_PRXFPREG,
.n = sizeof(struct user32_fxsr_struct) / sizeof(u32),
.size = sizeof(u32), .align = sizeof(u32),
- .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set
+ .active = regset_xregset_fpregs_active, .get = xfpregs_get, .set = xfpregs_set
},
[REGSET_XSTATE] = {
.core_note_type = NT_X86_XSTATE,
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index d74ac33290ae..d3b95b89e9b2 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -531,12 +531,14 @@ static void __init reserve_crashkernel_low(void)
if (ret != 0) {
/*
* two parts from lib/swiotlb.c:
- * swiotlb size: user specified with swiotlb= or default.
- * swiotlb overflow buffer: now is hardcoded to 32k.
- * We round it to 8M for other buffers that
- * may need to stay low too.
+ * -swiotlb size: user-specified with swiotlb= or default.
+ *
+ * -swiotlb overflow buffer: now hardcoded to 32k. We round it
+ * to 8M for other buffers that may need to stay low too. Also
+ * make sure we allocate enough extra low memory so that we
+ * don't run out of DMA buffers for 32-bit devices.
*/
- low_size = swiotlb_size_or_default() + (8UL<<20);
+ low_size = max(swiotlb_size_or_default() + (8UL<<20), 256UL<<20);
auto_set = true;
} else {
/* passed with crashkernel=0,low ? */
@@ -834,7 +836,7 @@ dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
{
if (kaslr_enabled()) {
pr_emerg("Kernel Offset: 0x%lx from 0x%lx (relocation range: 0x%lx-0x%lx)\n",
- (unsigned long)&_text - __START_KERNEL,
+ kaslr_offset(),
__START_KERNEL,
__START_KERNEL_map,
MODULES_VADDR-1);
@@ -1103,6 +1105,9 @@ void __init setup_arch(char **cmdline_p)
memblock_set_current_limit(ISA_END_ADDRESS);
memblock_x86_fill();
+ if (efi_enabled(EFI_BOOT))
+ efi_find_mirror();
+
/*
* The EFI specification says that boot service code won't be called
* after ExitBootServices(). This is, in fact, a lie.
@@ -1222,8 +1227,7 @@ void __init setup_arch(char **cmdline_p)
init_cpu_to_node();
init_apic_mappings();
- if (x86_io_apic_ops.init)
- x86_io_apic_ops.init();
+ io_apic_init_mappings();
kvm_guest_init();
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 1ea14fd53933..206996c1669d 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -26,8 +26,8 @@
#include <asm/processor.h>
#include <asm/ucontext.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h>
+#include <asm/fpu/internal.h>
+#include <asm/fpu/signal.h>
#include <asm/vdso.h>
#include <asm/mce.h>
#include <asm/sighandling.h>
@@ -103,7 +103,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
get_user_ex(buf, &sc->fpstate);
} get_user_catch(err);
- err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32));
+ err |= fpu__restore_sig(buf, config_enabled(CONFIG_X86_32));
force_iret();
@@ -199,6 +199,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
unsigned long sp = regs->sp;
unsigned long buf_fx = 0;
int onsigstack = on_sig_stack(sp);
+ struct fpu *fpu = &current->thread.fpu;
/* redzone */
if (config_enabled(CONFIG_X86_64))
@@ -218,9 +219,9 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
}
}
- if (used_math()) {
- sp = alloc_mathframe(sp, config_enabled(CONFIG_X86_32),
- &buf_fx, &math_size);
+ if (fpu->fpstate_active) {
+ sp = fpu__alloc_mathframe(sp, config_enabled(CONFIG_X86_32),
+ &buf_fx, &math_size);
*fpstate = (void __user *)sp;
}
@@ -234,8 +235,8 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
return (void __user *)-1L;
/* save i387 and extended state */
- if (used_math() &&
- save_xstate_sig(*fpstate, (void __user *)buf_fx, math_size) < 0)
+ if (fpu->fpstate_active &&
+ copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size) < 0)
return (void __user *)-1L;
return (void __user *)sp;
@@ -593,6 +594,22 @@ badframe:
return 0;
}
+static inline int is_ia32_compat_frame(void)
+{
+ return config_enabled(CONFIG_IA32_EMULATION) &&
+ test_thread_flag(TIF_IA32);
+}
+
+static inline int is_ia32_frame(void)
+{
+ return config_enabled(CONFIG_X86_32) || is_ia32_compat_frame();
+}
+
+static inline int is_x32_frame(void)
+{
+ return config_enabled(CONFIG_X86_X32_ABI) && test_thread_flag(TIF_X32);
+}
+
static int
setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
{
@@ -617,6 +634,7 @@ static void
handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
bool stepping, failed;
+ struct fpu *fpu = &current->thread.fpu;
/* Are we from a system call? */
if (syscall_get_nr(current, regs) >= 0) {
@@ -665,8 +683,8 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
/*
* Ensure the signal handler starts with the new fpu state.
*/
- if (used_math())
- fpu_reset_state(current);
+ if (fpu->fpstate_active)
+ fpu__clear(fpu);
}
signal_setup_done(failed, ksig, stepping);
}
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index be8e1bde07aa..15aaa69bbb5e 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -170,8 +170,7 @@ static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs)
asmlinkage __visible void smp_reboot_interrupt(void)
{
- ack_APIC_irq();
- irq_enter();
+ ipi_entering_ack_irq();
stop_this_cpu(NULL);
irq_exit();
}
@@ -265,12 +264,6 @@ __visible void smp_reschedule_interrupt(struct pt_regs *regs)
*/
}
-static inline void smp_entering_irq(void)
-{
- ack_APIC_irq();
- irq_enter();
-}
-
__visible void smp_trace_reschedule_interrupt(struct pt_regs *regs)
{
/*
@@ -279,7 +272,7 @@ __visible void smp_trace_reschedule_interrupt(struct pt_regs *regs)
* scheduler_ipi(). This is OK, since those functions are allowed
* to nest.
*/
- smp_entering_irq();
+ ipi_entering_ack_irq();
trace_reschedule_entry(RESCHEDULE_VECTOR);
__smp_reschedule_interrupt();
trace_reschedule_exit(RESCHEDULE_VECTOR);
@@ -297,14 +290,14 @@ static inline void __smp_call_function_interrupt(void)
__visible void smp_call_function_interrupt(struct pt_regs *regs)
{
- smp_entering_irq();
+ ipi_entering_ack_irq();
__smp_call_function_interrupt();
exiting_irq();
}
__visible void smp_trace_call_function_interrupt(struct pt_regs *regs)
{
- smp_entering_irq();
+ ipi_entering_ack_irq();
trace_call_function_entry(CALL_FUNCTION_VECTOR);
__smp_call_function_interrupt();
trace_call_function_exit(CALL_FUNCTION_VECTOR);
@@ -319,14 +312,14 @@ static inline void __smp_call_function_single_interrupt(void)
__visible void smp_call_function_single_interrupt(struct pt_regs *regs)
{
- smp_entering_irq();
+ ipi_entering_ack_irq();
__smp_call_function_single_interrupt();
exiting_irq();
}
__visible void smp_trace_call_function_single_interrupt(struct pt_regs *regs)
{
- smp_entering_irq();
+ ipi_entering_ack_irq();
trace_call_function_single_entry(CALL_FUNCTION_SINGLE_VECTOR);
__smp_call_function_single_interrupt();
trace_call_function_single_exit(CALL_FUNCTION_SINGLE_VECTOR);
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 50e547eac8cd..8add66b22f33 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -68,8 +68,7 @@
#include <asm/mwait.h>
#include <asm/apic.h>
#include <asm/io_apic.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h>
+#include <asm/fpu/internal.h>
#include <asm/setup.h>
#include <asm/uv/uv.h>
#include <linux/mc146818rtc.h>
@@ -314,10 +313,10 @@ topology_sane(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o, const char *name)
cpu1, name, cpu2, cpu_to_node(cpu1), cpu_to_node(cpu2));
}
-#define link_mask(_m, c1, c2) \
+#define link_mask(mfunc, c1, c2) \
do { \
- cpumask_set_cpu((c1), cpu_##_m##_mask(c2)); \
- cpumask_set_cpu((c2), cpu_##_m##_mask(c1)); \
+ cpumask_set_cpu((c1), mfunc(c2)); \
+ cpumask_set_cpu((c2), mfunc(c1)); \
} while (0)
static bool match_smt(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
@@ -398,9 +397,9 @@ void set_cpu_sibling_map(int cpu)
cpumask_set_cpu(cpu, cpu_sibling_setup_mask);
if (!has_mp) {
- cpumask_set_cpu(cpu, cpu_sibling_mask(cpu));
+ cpumask_set_cpu(cpu, topology_sibling_cpumask(cpu));
cpumask_set_cpu(cpu, cpu_llc_shared_mask(cpu));
- cpumask_set_cpu(cpu, cpu_core_mask(cpu));
+ cpumask_set_cpu(cpu, topology_core_cpumask(cpu));
c->booted_cores = 1;
return;
}
@@ -409,32 +408,34 @@ void set_cpu_sibling_map(int cpu)
o = &cpu_data(i);
if ((i == cpu) || (has_smt && match_smt(c, o)))
- link_mask(sibling, cpu, i);
+ link_mask(topology_sibling_cpumask, cpu, i);
if ((i == cpu) || (has_mp && match_llc(c, o)))
- link_mask(llc_shared, cpu, i);
+ link_mask(cpu_llc_shared_mask, cpu, i);
}
/*
* This needs a separate iteration over the cpus because we rely on all
- * cpu_sibling_mask links to be set-up.
+ * topology_sibling_cpumask links to be set-up.
*/
for_each_cpu(i, cpu_sibling_setup_mask) {
o = &cpu_data(i);
if ((i == cpu) || (has_mp && match_die(c, o))) {
- link_mask(core, cpu, i);
+ link_mask(topology_core_cpumask, cpu, i);
/*
* Does this new cpu bringup a new core?
*/
- if (cpumask_weight(cpu_sibling_mask(cpu)) == 1) {
+ if (cpumask_weight(
+ topology_sibling_cpumask(cpu)) == 1) {
/*
* for each core in package, increment
* the booted_cores for this new cpu
*/
- if (cpumask_first(cpu_sibling_mask(i)) == i)
+ if (cpumask_first(
+ topology_sibling_cpumask(i)) == i)
c->booted_cores++;
/*
* increment the core count for all
@@ -514,6 +515,40 @@ void __inquire_remote_apic(int apicid)
}
/*
+ * The Multiprocessor Specification 1.4 (1997) example code suggests
+ * that there should be a 10ms delay between the BSP asserting INIT
+ * and de-asserting INIT, when starting a remote processor.
+ * But that slows boot and resume on modern processors, which include
+ * many cores and don't require that delay.
+ *
+ * Cmdline "init_cpu_udelay=" is available to over-ride this delay.
+ * Modern processor families are quirked to remove the delay entirely.
+ */
+#define UDELAY_10MS_DEFAULT 10000
+
+static unsigned int init_udelay = UDELAY_10MS_DEFAULT;
+
+static int __init cpu_init_udelay(char *str)
+{
+ get_option(&str, &init_udelay);
+
+ return 0;
+}
+early_param("cpu_init_udelay", cpu_init_udelay);
+
+static void __init smp_quirk_init_udelay(void)
+{
+ /* if cmdline changed it from default, leave it alone */
+ if (init_udelay != UDELAY_10MS_DEFAULT)
+ return;
+
+ /* if modern processor, use no delay */
+ if (((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && (boot_cpu_data.x86 == 6)) ||
+ ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && (boot_cpu_data.x86 >= 0xF)))
+ init_udelay = 0;
+}
+
+/*
* Poke the other CPU in the eye via NMI to wake it up. Remember that the normal
* INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
* won't ... remember to clear down the APIC, etc later.
@@ -555,7 +590,7 @@ wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip)
static int
wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
{
- unsigned long send_status, accept_status = 0;
+ unsigned long send_status = 0, accept_status = 0;
int maxlvt, num_starts, j;
maxlvt = lapic_get_maxlvt();
@@ -583,7 +618,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
pr_debug("Waiting for send to finish...\n");
send_status = safe_apic_wait_icr_idle();
- mdelay(10);
+ udelay(init_udelay);
pr_debug("Deasserting INIT\n");
@@ -651,6 +686,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
* Give the other CPU some time to accept the IPI.
*/
udelay(200);
+
if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
apic_write(APIC_ESR, 0);
accept_status = (apic_read(APIC_ESR) & 0xEF);
@@ -792,8 +828,6 @@ void common_cpu_up(unsigned int cpu, struct task_struct *idle)
clear_tsk_thread_flag(idle, TIF_FORK);
initial_gs = per_cpu_offset(cpu);
#endif
- per_cpu(kernel_stack, cpu) =
- (unsigned long)task_stack_page(idle) + THREAD_SIZE;
}
/*
@@ -1009,8 +1043,8 @@ static __init void disable_smp(void)
physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
else
physid_set_mask_of_physid(0, &phys_cpu_present_map);
- cpumask_set_cpu(0, cpu_sibling_mask(0));
- cpumask_set_cpu(0, cpu_core_mask(0));
+ cpumask_set_cpu(0, topology_sibling_cpumask(0));
+ cpumask_set_cpu(0, topology_core_cpumask(0));
}
enum {
@@ -1176,6 +1210,8 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
uv_system_init();
set_mtrr_aps_delayed_init();
+
+ smp_quirk_init_udelay();
}
void arch_enable_nonboot_cpus_begin(void)
@@ -1293,22 +1329,22 @@ static void remove_siblinginfo(int cpu)
int sibling;
struct cpuinfo_x86 *c = &cpu_data(cpu);
- for_each_cpu(sibling, cpu_core_mask(cpu)) {
- cpumask_clear_cpu(cpu, cpu_core_mask(sibling));
+ for_each_cpu(sibling, topology_core_cpumask(cpu)) {
+ cpumask_clear_cpu(cpu, topology_core_cpumask(sibling));
/*/
* last thread sibling in this cpu core going down
*/
- if (cpumask_weight(cpu_sibling_mask(cpu)) == 1)
+ if (cpumask_weight(topology_sibling_cpumask(cpu)) == 1)
cpu_data(sibling).booted_cores--;
}
- for_each_cpu(sibling, cpu_sibling_mask(cpu))
- cpumask_clear_cpu(cpu, cpu_sibling_mask(sibling));
+ for_each_cpu(sibling, topology_sibling_cpumask(cpu))
+ cpumask_clear_cpu(cpu, topology_sibling_cpumask(sibling));
for_each_cpu(sibling, cpu_llc_shared_mask(cpu))
cpumask_clear_cpu(cpu, cpu_llc_shared_mask(sibling));
cpumask_clear(cpu_llc_shared_mask(cpu));
- cpumask_clear(cpu_sibling_mask(cpu));
- cpumask_clear(cpu_core_mask(cpu));
+ cpumask_clear(topology_sibling_cpumask(cpu));
+ cpumask_clear(topology_core_cpumask(cpu));
c->phys_proc_id = 0;
c->cpu_core_id = 0;
cpumask_clear_cpu(cpu, cpu_sibling_setup_mask);
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 324ab5247687..f5791927aa64 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -54,12 +54,13 @@
#include <asm/ftrace.h>
#include <asm/traps.h>
#include <asm/desc.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h>
+#include <asm/fpu/internal.h>
#include <asm/mce.h>
#include <asm/fixmap.h>
#include <asm/mach_traps.h>
#include <asm/alternative.h>
+#include <asm/fpu/xstate.h>
+#include <asm/trace/mpx.h>
#include <asm/mpx.h>
#ifdef CONFIG_X86_64
@@ -72,8 +73,7 @@ gate_desc debug_idt_table[NR_VECTORS] __page_aligned_bss;
#else
#include <asm/processor-flags.h>
#include <asm/setup.h>
-
-asmlinkage int system_call(void);
+#include <asm/proto.h>
#endif
/* Must be page-aligned because the real IDT is used in a fixmap. */
@@ -371,10 +371,8 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
{
- struct task_struct *tsk = current;
- struct xsave_struct *xsave_buf;
enum ctx_state prev_state;
- struct bndcsr *bndcsr;
+ const struct bndcsr *bndcsr;
siginfo_t *info;
prev_state = exception_enter();
@@ -393,15 +391,15 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
/*
* We need to look at BNDSTATUS to resolve this exception.
- * It is not directly accessible, though, so we need to
- * do an xsave and then pull it out of the xsave buffer.
+ * A NULL here might mean that it is in its 'init state',
+ * which is all zeros which indicates MPX was not
+ * responsible for the exception.
*/
- fpu_save_init(&tsk->thread.fpu);
- xsave_buf = &(tsk->thread.fpu.state->xsave);
- bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);
+ bndcsr = get_xsave_field_ptr(XSTATE_BNDCSR);
if (!bndcsr)
goto exit_trap;
+ trace_bounds_exception_mpx(bndcsr);
/*
* The error code field of the BNDSTATUS register communicates status
* information of a bound range exception #BR or operation involving
@@ -409,11 +407,11 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
*/
switch (bndcsr->bndstatus & MPX_BNDSTA_ERROR_CODE) {
case 2: /* Bound directory has invalid entry. */
- if (mpx_handle_bd_fault(xsave_buf))
+ if (mpx_handle_bd_fault())
goto exit_trap;
break; /* Success, it was handled */
case 1: /* Bound violation. */
- info = mpx_generate_siginfo(regs, xsave_buf);
+ info = mpx_generate_siginfo(regs);
if (IS_ERR(info)) {
/*
* We failed to decode the MPX instruction. Act as if
@@ -709,8 +707,8 @@ NOKPROBE_SYMBOL(do_debug);
static void math_error(struct pt_regs *regs, int error_code, int trapnr)
{
struct task_struct *task = current;
+ struct fpu *fpu = &task->thread.fpu;
siginfo_t info;
- unsigned short err;
char *str = (trapnr == X86_TRAP_MF) ? "fpu exception" :
"simd exception";
@@ -718,8 +716,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
return;
conditional_sti(regs);
- if (!user_mode(regs))
- {
+ if (!user_mode(regs)) {
if (!fixup_exception(regs)) {
task->thread.error_code = error_code;
task->thread.trap_nr = trapnr;
@@ -731,62 +728,20 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
/*
* Save the info for the exception handler and clear the error.
*/
- unlazy_fpu(task);
- task->thread.trap_nr = trapnr;
+ fpu__save(fpu);
+
+ task->thread.trap_nr = trapnr;
task->thread.error_code = error_code;
- info.si_signo = SIGFPE;
- info.si_errno = 0;
- info.si_addr = (void __user *)uprobe_get_trap_addr(regs);
- if (trapnr == X86_TRAP_MF) {
- unsigned short cwd, swd;
- /*
- * (~cwd & swd) will mask out exceptions that are not set to unmasked
- * status. 0x3f is the exception bits in these regs, 0x200 is the
- * C1 reg you need in case of a stack fault, 0x040 is the stack
- * fault bit. We should only be taking one exception at a time,
- * so if this combination doesn't produce any single exception,
- * then we have a bad program that isn't synchronizing its FPU usage
- * and it will suffer the consequences since we won't be able to
- * fully reproduce the context of the exception
- */
- cwd = get_fpu_cwd(task);
- swd = get_fpu_swd(task);
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_addr = (void __user *)uprobe_get_trap_addr(regs);
- err = swd & ~cwd;
- } else {
- /*
- * The SIMD FPU exceptions are handled a little differently, as there
- * is only a single status/control register. Thus, to determine which
- * unmasked exception was caught we must mask the exception mask bits
- * at 0x1f80, and then use these to mask the exception bits at 0x3f.
- */
- unsigned short mxcsr = get_fpu_mxcsr(task);
- err = ~(mxcsr >> 7) & mxcsr;
- }
+ info.si_code = fpu__exception_code(fpu, trapnr);
- if (err & 0x001) { /* Invalid op */
- /*
- * swd & 0x240 == 0x040: Stack Underflow
- * swd & 0x240 == 0x240: Stack Overflow
- * User must clear the SF bit (0x40) if set
- */
- info.si_code = FPE_FLTINV;
- } else if (err & 0x004) { /* Divide by Zero */
- info.si_code = FPE_FLTDIV;
- } else if (err & 0x008) { /* Overflow */
- info.si_code = FPE_FLTOVF;
- } else if (err & 0x012) { /* Denormal, Underflow */
- info.si_code = FPE_FLTUND;
- } else if (err & 0x020) { /* Precision */
- info.si_code = FPE_FLTRES;
- } else {
- /*
- * If we're using IRQ 13, or supposedly even some trap
- * X86_TRAP_MF implementations, it's possible
- * we get a spurious trap, which is not an error.
- */
+ /* Retry when we get spurious exceptions: */
+ if (!info.si_code)
return;
- }
+
force_sig_info(SIGFPE, &info, task);
}
@@ -813,62 +768,8 @@ dotraplinkage void
do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
{
conditional_sti(regs);
-#if 0
- /* No need to warn about this any longer. */
- pr_info("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
-#endif
-}
-
-asmlinkage __visible void __attribute__((weak)) smp_thermal_interrupt(void)
-{
}
-asmlinkage __visible void __attribute__((weak)) smp_threshold_interrupt(void)
-{
-}
-
-/*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task
- *
- * Careful.. There are problems with IBM-designed IRQ13 behaviour.
- * Don't touch unless you *really* know how it works.
- *
- * Must be called with kernel preemption disabled (eg with local
- * local interrupts as in the case of do_device_not_available).
- */
-void math_state_restore(void)
-{
- struct task_struct *tsk = current;
-
- if (!tsk_used_math(tsk)) {
- local_irq_enable();
- /*
- * does a slab alloc which can sleep
- */
- if (init_fpu(tsk)) {
- /*
- * ran out of memory!
- */
- do_group_exit(SIGKILL);
- return;
- }
- local_irq_disable();
- }
-
- /* Avoid __kernel_fpu_begin() right after __thread_fpu_begin() */
- kernel_fpu_disable();
- __thread_fpu_begin(tsk);
- if (unlikely(restore_fpu_checking(tsk))) {
- fpu_reset_state(tsk);
- force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk);
- } else {
- tsk->thread.fpu_counter++;
- }
- kernel_fpu_enable();
-}
-EXPORT_SYMBOL_GPL(math_state_restore);
-
dotraplinkage void
do_device_not_available(struct pt_regs *regs, long error_code)
{
@@ -889,7 +790,7 @@ do_device_not_available(struct pt_regs *regs, long error_code)
return;
}
#endif
- math_state_restore(); /* interrupts still off */
+ fpu__restore(&current->thread.fpu); /* interrupts still off */
#ifdef CONFIG_X86_32
conditional_sti(regs);
#endif
@@ -992,13 +893,13 @@ void __init trap_init(void)
set_bit(i, used_vectors);
#ifdef CONFIG_IA32_EMULATION
- set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
+ set_system_intr_gate(IA32_SYSCALL_VECTOR, entry_INT80_compat);
set_bit(IA32_SYSCALL_VECTOR, used_vectors);
#endif
#ifdef CONFIG_X86_32
- set_system_trap_gate(SYSCALL_VECTOR, &system_call);
- set_bit(SYSCALL_VECTOR, used_vectors);
+ set_system_trap_gate(IA32_SYSCALL_VECTOR, entry_INT80_32);
+ set_bit(IA32_SYSCALL_VECTOR, used_vectors);
#endif
/*
diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c
index 26488487bc61..dd8d0791dfb5 100644
--- a/arch/x86/kernel/tsc_sync.c
+++ b/arch/x86/kernel/tsc_sync.c
@@ -113,7 +113,7 @@ static void check_tsc_warp(unsigned int timeout)
*/
static inline unsigned int loop_timeout(int cpu)
{
- return (cpumask_weight(cpu_core_mask(cpu)) > 1) ? 2 : 20;
+ return (cpumask_weight(topology_core_cpumask(cpu)) > 1) ? 2 : 20;
}
/*
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index 0b81ad67da07..66476244731e 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -29,6 +29,7 @@
#include <linux/kdebug.h>
#include <asm/processor.h>
#include <asm/insn.h>
+#include <asm/mmu_context.h>
/* Post-execution fixups. */
@@ -312,11 +313,6 @@ static int uprobe_init_insn(struct arch_uprobe *auprobe, struct insn *insn, bool
}
#ifdef CONFIG_X86_64
-static inline bool is_64bit_mm(struct mm_struct *mm)
-{
- return !config_enabled(CONFIG_IA32_EMULATION) ||
- !(mm->context.ia32_compat == TIF_IA32);
-}
/*
* If arch_uprobe->insn doesn't use rip-relative addressing, return
* immediately. Otherwise, rewrite the instruction so that it accesses
@@ -497,10 +493,6 @@ static void riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
}
}
#else /* 32-bit: */
-static inline bool is_64bit_mm(struct mm_struct *mm)
-{
- return false;
-}
/*
* No RIP-relative addressing on 32-bit
*/
diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c
index 37d8fa4438f0..a0695be19864 100644
--- a/arch/x86/kernel/x8664_ksyms_64.c
+++ b/arch/x86/kernel/x8664_ksyms_64.c
@@ -75,7 +75,5 @@ EXPORT_SYMBOL(native_load_gs_index);
#ifdef CONFIG_PREEMPT
EXPORT_SYMBOL(___preempt_schedule);
-#ifdef CONFIG_CONTEXT_TRACKING
-EXPORT_SYMBOL(___preempt_schedule_context);
-#endif
+EXPORT_SYMBOL(___preempt_schedule_notrace);
#endif
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 234b0722de53..3839628d962e 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -11,7 +11,6 @@
#include <asm/bios_ebda.h>
#include <asm/paravirt.h>
#include <asm/pci_x86.h>
-#include <asm/pci.h>
#include <asm/mpspec.h>
#include <asm/setup.h>
#include <asm/apic.h>
@@ -111,11 +110,9 @@ EXPORT_SYMBOL_GPL(x86_platform);
#if defined(CONFIG_PCI_MSI)
struct x86_msi_ops x86_msi = {
.setup_msi_irqs = native_setup_msi_irqs,
- .compose_msi_msg = native_compose_msi_msg,
.teardown_msi_irq = native_teardown_msi_irq,
.teardown_msi_irqs = default_teardown_msi_irqs,
.restore_msi_irqs = default_restore_msi_irqs,
- .setup_hpet_msi = default_setup_hpet_msi,
};
/* MSI arch specific hooks */
@@ -141,13 +138,6 @@ void arch_restore_msi_irqs(struct pci_dev *dev)
#endif
struct x86_io_apic_ops x86_io_apic_ops = {
- .init = native_io_apic_init_mappings,
.read = native_io_apic_read,
- .write = native_io_apic_write,
- .modify = native_io_apic_modify,
.disable = native_disable_io_apic,
- .print_entries = native_io_apic_print_entries,
- .set_affinity = native_ioapic_set_affinity,
- .setup_entry = native_setup_ioapic_entry,
- .eoi_ioapic_pin = native_eoi_ioapic_pin,
};
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
deleted file mode 100644
index 87a815b85f3e..000000000000
--- a/arch/x86/kernel/xsave.c
+++ /dev/null
@@ -1,724 +0,0 @@
-/*
- * xsave/xrstor support.
- *
- * Author: Suresh Siddha <suresh.b.siddha@intel.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/bootmem.h>
-#include <linux/compat.h>
-#include <linux/cpu.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h>
-#include <asm/sigframe.h>
-#include <asm/tlbflush.h>
-#include <asm/xcr.h>
-
-/*
- * Supported feature mask by the CPU and the kernel.
- */
-u64 pcntxt_mask;
-
-/*
- * Represents init state for the supported extended state.
- */
-struct xsave_struct *init_xstate_buf;
-
-static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32;
-static unsigned int *xstate_offsets, *xstate_sizes;
-static unsigned int xstate_comp_offsets[sizeof(pcntxt_mask)*8];
-static unsigned int xstate_features;
-
-/*
- * If a processor implementation discern that a processor state component is
- * in its initialized state it may modify the corresponding bit in the
- * xsave_hdr.xstate_bv as '0', with out modifying the corresponding memory
- * layout in the case of xsaveopt. While presenting the xstate information to
- * the user, we always ensure that the memory layout of a feature will be in
- * the init state if the corresponding header bit is zero. This is to ensure
- * that the user doesn't see some stale state in the memory layout during
- * signal handling, debugging etc.
- */
-void __sanitize_i387_state(struct task_struct *tsk)
-{
- struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
- int feature_bit = 0x2;
- u64 xstate_bv;
-
- if (!fx)
- return;
-
- xstate_bv = tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv;
-
- /*
- * None of the feature bits are in init state. So nothing else
- * to do for us, as the memory layout is up to date.
- */
- if ((xstate_bv & pcntxt_mask) == pcntxt_mask)
- return;
-
- /*
- * FP is in init state
- */
- if (!(xstate_bv & XSTATE_FP)) {
- fx->cwd = 0x37f;
- fx->swd = 0;
- fx->twd = 0;
- fx->fop = 0;
- fx->rip = 0;
- fx->rdp = 0;
- memset(&fx->st_space[0], 0, 128);
- }
-
- /*
- * SSE is in init state
- */
- if (!(xstate_bv & XSTATE_SSE))
- memset(&fx->xmm_space[0], 0, 256);
-
- xstate_bv = (pcntxt_mask & ~xstate_bv) >> 2;
-
- /*
- * Update all the other memory layouts for which the corresponding
- * header bit is in the init state.
- */
- while (xstate_bv) {
- if (xstate_bv & 0x1) {
- int offset = xstate_offsets[feature_bit];
- int size = xstate_sizes[feature_bit];
-
- memcpy(((void *) fx) + offset,
- ((void *) init_xstate_buf) + offset,
- size);
- }
-
- xstate_bv >>= 1;
- feature_bit++;
- }
-}
-
-/*
- * Check for the presence of extended state information in the
- * user fpstate pointer in the sigcontext.
- */
-static inline int check_for_xstate(struct i387_fxsave_struct __user *buf,
- void __user *fpstate,
- struct _fpx_sw_bytes *fx_sw)
-{
- int min_xstate_size = sizeof(struct i387_fxsave_struct) +
- sizeof(struct xsave_hdr_struct);
- unsigned int magic2;
-
- if (__copy_from_user(fx_sw, &buf->sw_reserved[0], sizeof(*fx_sw)))
- return -1;
-
- /* Check for the first magic field and other error scenarios. */
- if (fx_sw->magic1 != FP_XSTATE_MAGIC1 ||
- fx_sw->xstate_size < min_xstate_size ||
- fx_sw->xstate_size > xstate_size ||
- fx_sw->xstate_size > fx_sw->extended_size)
- return -1;
-
- /*
- * Check for the presence of second magic word at the end of memory
- * layout. This detects the case where the user just copied the legacy
- * fpstate layout with out copying the extended state information
- * in the memory layout.
- */
- if (__get_user(magic2, (__u32 __user *)(fpstate + fx_sw->xstate_size))
- || magic2 != FP_XSTATE_MAGIC2)
- return -1;
-
- return 0;
-}
-
-/*
- * Signal frame handlers.
- */
-static inline int save_fsave_header(struct task_struct *tsk, void __user *buf)
-{
- if (use_fxsr()) {
- struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
- struct user_i387_ia32_struct env;
- struct _fpstate_ia32 __user *fp = buf;
-
- convert_from_fxsr(&env, tsk);
-
- if (__copy_to_user(buf, &env, sizeof(env)) ||
- __put_user(xsave->i387.swd, &fp->status) ||
- __put_user(X86_FXSR_MAGIC, &fp->magic))
- return -1;
- } else {
- struct i387_fsave_struct __user *fp = buf;
- u32 swd;
- if (__get_user(swd, &fp->swd) || __put_user(swd, &fp->status))
- return -1;
- }
-
- return 0;
-}
-
-static inline int save_xstate_epilog(void __user *buf, int ia32_frame)
-{
- struct xsave_struct __user *x = buf;
- struct _fpx_sw_bytes *sw_bytes;
- u32 xstate_bv;
- int err;
-
- /* Setup the bytes not touched by the [f]xsave and reserved for SW. */
- sw_bytes = ia32_frame ? &fx_sw_reserved_ia32 : &fx_sw_reserved;
- err = __copy_to_user(&x->i387.sw_reserved, sw_bytes, sizeof(*sw_bytes));
-
- if (!use_xsave())
- return err;
-
- err |= __put_user(FP_XSTATE_MAGIC2, (__u32 *)(buf + xstate_size));
-
- /*
- * Read the xstate_bv which we copied (directly from the cpu or
- * from the state in task struct) to the user buffers.
- */
- err |= __get_user(xstate_bv, (__u32 *)&x->xsave_hdr.xstate_bv);
-
- /*
- * For legacy compatible, we always set FP/SSE bits in the bit
- * vector while saving the state to the user context. This will
- * enable us capturing any changes(during sigreturn) to
- * the FP/SSE bits by the legacy applications which don't touch
- * xstate_bv in the xsave header.
- *
- * xsave aware apps can change the xstate_bv in the xsave
- * header as well as change any contents in the memory layout.
- * xrestore as part of sigreturn will capture all the changes.
- */
- xstate_bv |= XSTATE_FPSSE;
-
- err |= __put_user(xstate_bv, (__u32 *)&x->xsave_hdr.xstate_bv);
-
- return err;
-}
-
-static inline int save_user_xstate(struct xsave_struct __user *buf)
-{
- int err;
-
- if (use_xsave())
- err = xsave_user(buf);
- else if (use_fxsr())
- err = fxsave_user((struct i387_fxsave_struct __user *) buf);
- else
- err = fsave_user((struct i387_fsave_struct __user *) buf);
-
- if (unlikely(err) && __clear_user(buf, xstate_size))
- err = -EFAULT;
- return err;
-}
-
-/*
- * Save the fpu, extended register state to the user signal frame.
- *
- * 'buf_fx' is the 64-byte aligned pointer at which the [f|fx|x]save
- * state is copied.
- * 'buf' points to the 'buf_fx' or to the fsave header followed by 'buf_fx'.
- *
- * buf == buf_fx for 64-bit frames and 32-bit fsave frame.
- * buf != buf_fx for 32-bit frames with fxstate.
- *
- * If the fpu, extended register state is live, save the state directly
- * to the user frame pointed by the aligned pointer 'buf_fx'. Otherwise,
- * copy the thread's fpu state to the user frame starting at 'buf_fx'.
- *
- * If this is a 32-bit frame with fxstate, put a fsave header before
- * the aligned state at 'buf_fx'.
- *
- * For [f]xsave state, update the SW reserved fields in the [f]xsave frame
- * indicating the absence/presence of the extended state to the user.
- */
-int save_xstate_sig(void __user *buf, void __user *buf_fx, int size)
-{
- struct xsave_struct *xsave = &current->thread.fpu.state->xsave;
- struct task_struct *tsk = current;
- int ia32_fxstate = (buf != buf_fx);
-
- ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
- config_enabled(CONFIG_IA32_EMULATION));
-
- if (!access_ok(VERIFY_WRITE, buf, size))
- return -EACCES;
-
- if (!static_cpu_has(X86_FEATURE_FPU))
- return fpregs_soft_get(current, NULL, 0,
- sizeof(struct user_i387_ia32_struct), NULL,
- (struct _fpstate_ia32 __user *) buf) ? -1 : 1;
-
- if (user_has_fpu()) {
- /* Save the live register state to the user directly. */
- if (save_user_xstate(buf_fx))
- return -1;
- /* Update the thread's fxstate to save the fsave header. */
- if (ia32_fxstate)
- fpu_fxsave(&tsk->thread.fpu);
- } else {
- sanitize_i387_state(tsk);
- if (__copy_to_user(buf_fx, xsave, xstate_size))
- return -1;
- }
-
- /* Save the fsave header for the 32-bit frames. */
- if ((ia32_fxstate || !use_fxsr()) && save_fsave_header(tsk, buf))
- return -1;
-
- if (use_fxsr() && save_xstate_epilog(buf_fx, ia32_fxstate))
- return -1;
-
- return 0;
-}
-
-static inline void
-sanitize_restored_xstate(struct task_struct *tsk,
- struct user_i387_ia32_struct *ia32_env,
- u64 xstate_bv, int fx_only)
-{
- struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
- struct xsave_hdr_struct *xsave_hdr = &xsave->xsave_hdr;
-
- if (use_xsave()) {
- /* These bits must be zero. */
- memset(xsave_hdr->reserved, 0, 48);
-
- /*
- * Init the state that is not present in the memory
- * layout and not enabled by the OS.
- */
- if (fx_only)
- xsave_hdr->xstate_bv = XSTATE_FPSSE;
- else
- xsave_hdr->xstate_bv &= (pcntxt_mask & xstate_bv);
- }
-
- if (use_fxsr()) {
- /*
- * mscsr reserved bits must be masked to zero for security
- * reasons.
- */
- xsave->i387.mxcsr &= mxcsr_feature_mask;
-
- convert_to_fxsr(tsk, ia32_env);
- }
-}
-
-/*
- * Restore the extended state if present. Otherwise, restore the FP/SSE state.
- */
-static inline int restore_user_xstate(void __user *buf, u64 xbv, int fx_only)
-{
- if (use_xsave()) {
- if ((unsigned long)buf % 64 || fx_only) {
- u64 init_bv = pcntxt_mask & ~XSTATE_FPSSE;
- xrstor_state(init_xstate_buf, init_bv);
- return fxrstor_user(buf);
- } else {
- u64 init_bv = pcntxt_mask & ~xbv;
- if (unlikely(init_bv))
- xrstor_state(init_xstate_buf, init_bv);
- return xrestore_user(buf, xbv);
- }
- } else if (use_fxsr()) {
- return fxrstor_user(buf);
- } else
- return frstor_user(buf);
-}
-
-int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
-{
- int ia32_fxstate = (buf != buf_fx);
- struct task_struct *tsk = current;
- int state_size = xstate_size;
- u64 xstate_bv = 0;
- int fx_only = 0;
-
- ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
- config_enabled(CONFIG_IA32_EMULATION));
-
- if (!buf) {
- fpu_reset_state(tsk);
- return 0;
- }
-
- if (!access_ok(VERIFY_READ, buf, size))
- return -EACCES;
-
- if (!used_math() && init_fpu(tsk))
- return -1;
-
- if (!static_cpu_has(X86_FEATURE_FPU))
- return fpregs_soft_set(current, NULL,
- 0, sizeof(struct user_i387_ia32_struct),
- NULL, buf) != 0;
-
- if (use_xsave()) {
- struct _fpx_sw_bytes fx_sw_user;
- if (unlikely(check_for_xstate(buf_fx, buf_fx, &fx_sw_user))) {
- /*
- * Couldn't find the extended state information in the
- * memory layout. Restore just the FP/SSE and init all
- * the other extended state.
- */
- state_size = sizeof(struct i387_fxsave_struct);
- fx_only = 1;
- } else {
- state_size = fx_sw_user.xstate_size;
- xstate_bv = fx_sw_user.xstate_bv;
- }
- }
-
- if (ia32_fxstate) {
- /*
- * For 32-bit frames with fxstate, copy the user state to the
- * thread's fpu state, reconstruct fxstate from the fsave
- * header. Sanitize the copied state etc.
- */
- struct fpu *fpu = &tsk->thread.fpu;
- struct user_i387_ia32_struct env;
- int err = 0;
-
- /*
- * Drop the current fpu which clears used_math(). This ensures
- * that any context-switch during the copy of the new state,
- * avoids the intermediate state from getting restored/saved.
- * Thus avoiding the new restored state from getting corrupted.
- * We will be ready to restore/save the state only after
- * set_used_math() is again set.
- */
- drop_fpu(tsk);
-
- if (__copy_from_user(&fpu->state->xsave, buf_fx, state_size) ||
- __copy_from_user(&env, buf, sizeof(env))) {
- fpu_finit(fpu);
- err = -1;
- } else {
- sanitize_restored_xstate(tsk, &env, xstate_bv, fx_only);
- }
-
- set_used_math();
- if (use_eager_fpu()) {
- preempt_disable();
- math_state_restore();
- preempt_enable();
- }
-
- return err;
- } else {
- /*
- * For 64-bit frames and 32-bit fsave frames, restore the user
- * state to the registers directly (with exceptions handled).
- */
- user_fpu_begin();
- if (restore_user_xstate(buf_fx, xstate_bv, fx_only)) {
- fpu_reset_state(tsk);
- return -1;
- }
- }
-
- return 0;
-}
-
-/*
- * Prepare the SW reserved portion of the fxsave memory layout, indicating
- * the presence of the extended state information in the memory layout
- * pointed by the fpstate pointer in the sigcontext.
- * This will be saved when ever the FP and extended state context is
- * saved on the user stack during the signal handler delivery to the user.
- */
-static void prepare_fx_sw_frame(void)
-{
- int fsave_header_size = sizeof(struct i387_fsave_struct);
- int size = xstate_size + FP_XSTATE_MAGIC2_SIZE;
-
- if (config_enabled(CONFIG_X86_32))
- size += fsave_header_size;
-
- fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
- fx_sw_reserved.extended_size = size;
- fx_sw_reserved.xstate_bv = pcntxt_mask;
- fx_sw_reserved.xstate_size = xstate_size;
-
- if (config_enabled(CONFIG_IA32_EMULATION)) {
- fx_sw_reserved_ia32 = fx_sw_reserved;
- fx_sw_reserved_ia32.extended_size += fsave_header_size;
- }
-}
-
-/*
- * Enable the extended processor state save/restore feature
- */
-static inline void xstate_enable(void)
-{
- cr4_set_bits(X86_CR4_OSXSAVE);
- xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
-}
-
-/*
- * Record the offsets and sizes of different state managed by the xsave
- * memory layout.
- */
-static void __init setup_xstate_features(void)
-{
- int eax, ebx, ecx, edx, leaf = 0x2;
-
- xstate_features = fls64(pcntxt_mask);
- xstate_offsets = alloc_bootmem(xstate_features * sizeof(int));
- xstate_sizes = alloc_bootmem(xstate_features * sizeof(int));
-
- do {
- cpuid_count(XSTATE_CPUID, leaf, &eax, &ebx, &ecx, &edx);
-
- if (eax == 0)
- break;
-
- xstate_offsets[leaf] = ebx;
- xstate_sizes[leaf] = eax;
-
- leaf++;
- } while (1);
-}
-
-/*
- * This function sets up offsets and sizes of all extended states in
- * xsave area. This supports both standard format and compacted format
- * of the xsave aread.
- *
- * Input: void
- * Output: void
- */
-void setup_xstate_comp(void)
-{
- unsigned int xstate_comp_sizes[sizeof(pcntxt_mask)*8];
- int i;
-
- /*
- * The FP xstates and SSE xstates are legacy states. They are always
- * in the fixed offsets in the xsave area in either compacted form
- * or standard form.
- */
- xstate_comp_offsets[0] = 0;
- xstate_comp_offsets[1] = offsetof(struct i387_fxsave_struct, xmm_space);
-
- if (!cpu_has_xsaves) {
- for (i = 2; i < xstate_features; i++) {
- if (test_bit(i, (unsigned long *)&pcntxt_mask)) {
- xstate_comp_offsets[i] = xstate_offsets[i];
- xstate_comp_sizes[i] = xstate_sizes[i];
- }
- }
- return;
- }
-
- xstate_comp_offsets[2] = FXSAVE_SIZE + XSAVE_HDR_SIZE;
-
- for (i = 2; i < xstate_features; i++) {
- if (test_bit(i, (unsigned long *)&pcntxt_mask))
- xstate_comp_sizes[i] = xstate_sizes[i];
- else
- xstate_comp_sizes[i] = 0;
-
- if (i > 2)
- xstate_comp_offsets[i] = xstate_comp_offsets[i-1]
- + xstate_comp_sizes[i-1];
-
- }
-}
-
-/*
- * setup the xstate image representing the init state
- */
-static void __init setup_init_fpu_buf(void)
-{
- /*
- * Setup init_xstate_buf to represent the init state of
- * all the features managed by the xsave
- */
- init_xstate_buf = alloc_bootmem_align(xstate_size,
- __alignof__(struct xsave_struct));
- fx_finit(&init_xstate_buf->i387);
-
- if (!cpu_has_xsave)
- return;
-
- setup_xstate_features();
-
- if (cpu_has_xsaves) {
- init_xstate_buf->xsave_hdr.xcomp_bv =
- (u64)1 << 63 | pcntxt_mask;
- init_xstate_buf->xsave_hdr.xstate_bv = pcntxt_mask;
- }
-
- /*
- * Init all the features state with header_bv being 0x0
- */
- xrstor_state_booting(init_xstate_buf, -1);
- /*
- * Dump the init state again. This is to identify the init state
- * of any feature which is not represented by all zero's.
- */
- xsave_state_booting(init_xstate_buf, -1);
-}
-
-static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO;
-static int __init eager_fpu_setup(char *s)
-{
- if (!strcmp(s, "on"))
- eagerfpu = ENABLE;
- else if (!strcmp(s, "off"))
- eagerfpu = DISABLE;
- else if (!strcmp(s, "auto"))
- eagerfpu = AUTO;
- return 1;
-}
-__setup("eagerfpu=", eager_fpu_setup);
-
-
-/*
- * Calculate total size of enabled xstates in XCR0/pcntxt_mask.
- */
-static void __init init_xstate_size(void)
-{
- unsigned int eax, ebx, ecx, edx;
- int i;
-
- if (!cpu_has_xsaves) {
- cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
- xstate_size = ebx;
- return;
- }
-
- xstate_size = FXSAVE_SIZE + XSAVE_HDR_SIZE;
- for (i = 2; i < 64; i++) {
- if (test_bit(i, (unsigned long *)&pcntxt_mask)) {
- cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx);
- xstate_size += eax;
- }
- }
-}
-
-/*
- * Enable and initialize the xsave feature.
- */
-static void __init xstate_enable_boot_cpu(void)
-{
- unsigned int eax, ebx, ecx, edx;
-
- if (boot_cpu_data.cpuid_level < XSTATE_CPUID) {
- WARN(1, KERN_ERR "XSTATE_CPUID missing\n");
- return;
- }
-
- cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
- pcntxt_mask = eax + ((u64)edx << 32);
-
- if ((pcntxt_mask & XSTATE_FPSSE) != XSTATE_FPSSE) {
- pr_err("FP/SSE not shown under xsave features 0x%llx\n",
- pcntxt_mask);
- BUG();
- }
-
- /*
- * Support only the state known to OS.
- */
- pcntxt_mask = pcntxt_mask & XCNTXT_MASK;
-
- xstate_enable();
-
- /*
- * Recompute the context size for enabled features
- */
- init_xstate_size();
-
- update_regset_xstate_info(xstate_size, pcntxt_mask);
- prepare_fx_sw_frame();
- setup_init_fpu_buf();
-
- /* Auto enable eagerfpu for xsaveopt */
- if (cpu_has_xsaveopt && eagerfpu != DISABLE)
- eagerfpu = ENABLE;
-
- if (pcntxt_mask & XSTATE_EAGER) {
- if (eagerfpu == DISABLE) {
- pr_err("eagerfpu not present, disabling some xstate features: 0x%llx\n",
- pcntxt_mask & XSTATE_EAGER);
- pcntxt_mask &= ~XSTATE_EAGER;
- } else {
- eagerfpu = ENABLE;
- }
- }
-
- pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x using %s\n",
- pcntxt_mask, xstate_size,
- cpu_has_xsaves ? "compacted form" : "standard form");
-}
-
-/*
- * For the very first instance, this calls xstate_enable_boot_cpu();
- * for all subsequent instances, this calls xstate_enable().
- *
- * This is somewhat obfuscated due to the lack of powerful enough
- * overrides for the section checks.
- */
-void xsave_init(void)
-{
- static __refdata void (*next_func)(void) = xstate_enable_boot_cpu;
- void (*this_func)(void);
-
- if (!cpu_has_xsave)
- return;
-
- this_func = next_func;
- next_func = xstate_enable;
- this_func();
-}
-
-/*
- * setup_init_fpu_buf() is __init and it is OK to call it here because
- * init_xstate_buf will be unset only once during boot.
- */
-void __init_refok eager_fpu_init(void)
-{
- WARN_ON(used_math());
- current_thread_info()->status = 0;
-
- if (eagerfpu == ENABLE)
- setup_force_cpu_cap(X86_FEATURE_EAGER_FPU);
-
- if (!cpu_has_eager_fpu) {
- stts();
- return;
- }
-
- if (!init_xstate_buf)
- setup_init_fpu_buf();
-}
-
-/*
- * Given the xsave area and a state inside, this function returns the
- * address of the state.
- *
- * This is the API that is called to get xstate address in either
- * standard format or compacted format of xsave area.
- *
- * Inputs:
- * xsave: base address of the xsave area;
- * xstate: state which is defined in xsave.h (e.g. XSTATE_FP, XSTATE_SSE,
- * etc.)
- * Output:
- * address of the state in the xsave area.
- */
-void *get_xsave_addr(struct xsave_struct *xsave, int xstate)
-{
- int feature = fls64(xstate) - 1;
- if (!test_bit(feature, (unsigned long *)&pcntxt_mask))
- return NULL;
-
- return (void *)xsave + xstate_comp_offsets[feature];
-}
-EXPORT_SYMBOL_GPL(get_xsave_addr);
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index 413a7bf9efbb..d8a1d56276e1 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -86,15 +86,16 @@ config KVM_MMU_AUDIT
auditing of KVM MMU events at runtime.
config KVM_DEVICE_ASSIGNMENT
- bool "KVM legacy PCI device assignment support"
+ bool "KVM legacy PCI device assignment support (DEPRECATED)"
depends on KVM && PCI && IOMMU_API
- default y
+ default n
---help---
Provide support for legacy PCI device assignment through KVM. The
kernel now also supports a full featured userspace device driver
- framework through VFIO, which supersedes much of this support.
+ framework through VFIO, which supersedes this support and provides
+ better security.
- If unsure, say Y.
+ If unsure, say N.
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
# the virtualization menu.
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index 16e8f962eaad..67d215cb8953 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -12,10 +12,10 @@ kvm-y += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o \
kvm-$(CONFIG_KVM_ASYNC_PF) += $(KVM)/async_pf.o
kvm-y += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \
- i8254.o ioapic.o irq_comm.o cpuid.o pmu.o
+ i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o
kvm-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += assigned-dev.o iommu.o
-kvm-intel-y += vmx.o
-kvm-amd-y += svm.o
+kvm-intel-y += vmx.o pmu_intel.o
+kvm-amd-y += svm.o pmu_amd.o
obj-$(CONFIG_KVM) += kvm.o
obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 1d08ad3582d0..64dd46793099 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -16,14 +16,14 @@
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
-#include <asm/i387.h> /* For use_eager_fpu. Ugh! */
-#include <asm/fpu-internal.h> /* For use_eager_fpu. Ugh! */
+#include <asm/fpu/internal.h> /* For use_eager_fpu. Ugh! */
#include <asm/user.h>
-#include <asm/xsave.h>
+#include <asm/fpu/xstate.h>
#include "cpuid.h"
#include "lapic.h"
#include "mmu.h"
#include "trace.h"
+#include "pmu.h"
static u32 xstate_required_size(u64 xstate_bv, bool compacted)
{
@@ -97,7 +97,7 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu)
if (best && (best->eax & (F(XSAVES) | F(XSAVEC))))
best->ebx = xstate_required_size(vcpu->arch.xcr0, true);
- vcpu->arch.eager_fpu = guest_cpuid_has_mpx(vcpu);
+ vcpu->arch.eager_fpu = use_eager_fpu() || guest_cpuid_has_mpx(vcpu);
/*
* The existing code assumes virtual address is 48-bit in the canonical
@@ -111,7 +111,7 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu)
/* Update physical-address width */
vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu);
- kvm_pmu_cpuid_update(vcpu);
+ kvm_pmu_refresh(vcpu);
return 0;
}
@@ -415,6 +415,12 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
}
break;
}
+ case 6: /* Thermal management */
+ entry->eax = 0x4; /* allow ARAT */
+ entry->ebx = 0;
+ entry->ecx = 0;
+ entry->edx = 0;
+ break;
case 7: {
entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
/* Mask ebx against host capability word 9 */
@@ -591,7 +597,6 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
break;
case 3: /* Processor serial number */
case 5: /* MONITOR/MWAIT */
- case 6: /* Thermal management */
case 0xC0000002:
case 0xC0000003:
case 0xC0000004:
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index 496b3695d3d3..dd05b9cef6ae 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -70,6 +70,14 @@ static inline bool guest_cpuid_has_fsgsbase(struct kvm_vcpu *vcpu)
return best && (best->ebx & bit(X86_FEATURE_FSGSBASE));
}
+static inline bool guest_cpuid_has_longmode(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *best;
+
+ best = kvm_find_cpuid_entry(vcpu, 0x80000001, 0);
+ return best && (best->edx & bit(X86_FEATURE_LM));
+}
+
static inline bool guest_cpuid_has_osvw(struct kvm_vcpu *vcpu)
{
struct kvm_cpuid_entry2 *best;
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 630bcb0d7a04..e7a4fde5d631 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <asm/kvm_emulate.h>
#include <linux/stringify.h>
+#include <asm/debugreg.h>
#include "x86.h"
#include "tss.h"
@@ -523,13 +524,9 @@ static void masked_increment(ulong *reg, ulong mask, int inc)
static inline void
register_address_increment(struct x86_emulate_ctxt *ctxt, int reg, int inc)
{
- ulong mask;
+ ulong *preg = reg_rmw(ctxt, reg);
- if (ctxt->ad_bytes == sizeof(unsigned long))
- mask = ~0UL;
- else
- mask = ad_mask(ctxt);
- masked_increment(reg_rmw(ctxt, reg), mask, inc);
+ assign_register(preg, *preg + inc, ctxt->ad_bytes);
}
static void rsp_increment(struct x86_emulate_ctxt *ctxt, int inc)
@@ -2262,6 +2259,260 @@ static int em_lseg(struct x86_emulate_ctxt *ctxt)
return rc;
}
+static int emulator_has_longmode(struct x86_emulate_ctxt *ctxt)
+{
+ u32 eax, ebx, ecx, edx;
+
+ eax = 0x80000001;
+ ecx = 0;
+ ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx);
+ return edx & bit(X86_FEATURE_LM);
+}
+
+#define GET_SMSTATE(type, smbase, offset) \
+ ({ \
+ type __val; \
+ int r = ctxt->ops->read_std(ctxt, smbase + offset, &__val, \
+ sizeof(__val), NULL); \
+ if (r != X86EMUL_CONTINUE) \
+ return X86EMUL_UNHANDLEABLE; \
+ __val; \
+ })
+
+static void rsm_set_desc_flags(struct desc_struct *desc, u32 flags)
+{
+ desc->g = (flags >> 23) & 1;
+ desc->d = (flags >> 22) & 1;
+ desc->l = (flags >> 21) & 1;
+ desc->avl = (flags >> 20) & 1;
+ desc->p = (flags >> 15) & 1;
+ desc->dpl = (flags >> 13) & 3;
+ desc->s = (flags >> 12) & 1;
+ desc->type = (flags >> 8) & 15;
+}
+
+static int rsm_load_seg_32(struct x86_emulate_ctxt *ctxt, u64 smbase, int n)
+{
+ struct desc_struct desc;
+ int offset;
+ u16 selector;
+
+ selector = GET_SMSTATE(u32, smbase, 0x7fa8 + n * 4);
+
+ if (n < 3)
+ offset = 0x7f84 + n * 12;
+ else
+ offset = 0x7f2c + (n - 3) * 12;
+
+ set_desc_base(&desc, GET_SMSTATE(u32, smbase, offset + 8));
+ set_desc_limit(&desc, GET_SMSTATE(u32, smbase, offset + 4));
+ rsm_set_desc_flags(&desc, GET_SMSTATE(u32, smbase, offset));
+ ctxt->ops->set_segment(ctxt, selector, &desc, 0, n);
+ return X86EMUL_CONTINUE;
+}
+
+static int rsm_load_seg_64(struct x86_emulate_ctxt *ctxt, u64 smbase, int n)
+{
+ struct desc_struct desc;
+ int offset;
+ u16 selector;
+ u32 base3;
+
+ offset = 0x7e00 + n * 16;
+
+ selector = GET_SMSTATE(u16, smbase, offset);
+ rsm_set_desc_flags(&desc, GET_SMSTATE(u16, smbase, offset + 2) << 8);
+ set_desc_limit(&desc, GET_SMSTATE(u32, smbase, offset + 4));
+ set_desc_base(&desc, GET_SMSTATE(u32, smbase, offset + 8));
+ base3 = GET_SMSTATE(u32, smbase, offset + 12);
+
+ ctxt->ops->set_segment(ctxt, selector, &desc, base3, n);
+ return X86EMUL_CONTINUE;
+}
+
+static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt,
+ u64 cr0, u64 cr4)
+{
+ int bad;
+
+ /*
+ * First enable PAE, long mode needs it before CR0.PG = 1 is set.
+ * Then enable protected mode. However, PCID cannot be enabled
+ * if EFER.LMA=0, so set it separately.
+ */
+ bad = ctxt->ops->set_cr(ctxt, 4, cr4 & ~X86_CR4_PCIDE);
+ if (bad)
+ return X86EMUL_UNHANDLEABLE;
+
+ bad = ctxt->ops->set_cr(ctxt, 0, cr0);
+ if (bad)
+ return X86EMUL_UNHANDLEABLE;
+
+ if (cr4 & X86_CR4_PCIDE) {
+ bad = ctxt->ops->set_cr(ctxt, 4, cr4);
+ if (bad)
+ return X86EMUL_UNHANDLEABLE;
+ }
+
+ return X86EMUL_CONTINUE;
+}
+
+static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase)
+{
+ struct desc_struct desc;
+ struct desc_ptr dt;
+ u16 selector;
+ u32 val, cr0, cr4;
+ int i;
+
+ cr0 = GET_SMSTATE(u32, smbase, 0x7ffc);
+ ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u32, smbase, 0x7ff8));
+ ctxt->eflags = GET_SMSTATE(u32, smbase, 0x7ff4) | X86_EFLAGS_FIXED;
+ ctxt->_eip = GET_SMSTATE(u32, smbase, 0x7ff0);
+
+ for (i = 0; i < 8; i++)
+ *reg_write(ctxt, i) = GET_SMSTATE(u32, smbase, 0x7fd0 + i * 4);
+
+ val = GET_SMSTATE(u32, smbase, 0x7fcc);
+ ctxt->ops->set_dr(ctxt, 6, (val & DR6_VOLATILE) | DR6_FIXED_1);
+ val = GET_SMSTATE(u32, smbase, 0x7fc8);
+ ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1);
+
+ selector = GET_SMSTATE(u32, smbase, 0x7fc4);
+ set_desc_base(&desc, GET_SMSTATE(u32, smbase, 0x7f64));
+ set_desc_limit(&desc, GET_SMSTATE(u32, smbase, 0x7f60));
+ rsm_set_desc_flags(&desc, GET_SMSTATE(u32, smbase, 0x7f5c));
+ ctxt->ops->set_segment(ctxt, selector, &desc, 0, VCPU_SREG_TR);
+
+ selector = GET_SMSTATE(u32, smbase, 0x7fc0);
+ set_desc_base(&desc, GET_SMSTATE(u32, smbase, 0x7f80));
+ set_desc_limit(&desc, GET_SMSTATE(u32, smbase, 0x7f7c));
+ rsm_set_desc_flags(&desc, GET_SMSTATE(u32, smbase, 0x7f78));
+ ctxt->ops->set_segment(ctxt, selector, &desc, 0, VCPU_SREG_LDTR);
+
+ dt.address = GET_SMSTATE(u32, smbase, 0x7f74);
+ dt.size = GET_SMSTATE(u32, smbase, 0x7f70);
+ ctxt->ops->set_gdt(ctxt, &dt);
+
+ dt.address = GET_SMSTATE(u32, smbase, 0x7f58);
+ dt.size = GET_SMSTATE(u32, smbase, 0x7f54);
+ ctxt->ops->set_idt(ctxt, &dt);
+
+ for (i = 0; i < 6; i++) {
+ int r = rsm_load_seg_32(ctxt, smbase, i);
+ if (r != X86EMUL_CONTINUE)
+ return r;
+ }
+
+ cr4 = GET_SMSTATE(u32, smbase, 0x7f14);
+
+ ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7ef8));
+
+ return rsm_enter_protected_mode(ctxt, cr0, cr4);
+}
+
+static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase)
+{
+ struct desc_struct desc;
+ struct desc_ptr dt;
+ u64 val, cr0, cr4;
+ u32 base3;
+ u16 selector;
+ int i;
+
+ for (i = 0; i < 16; i++)
+ *reg_write(ctxt, i) = GET_SMSTATE(u64, smbase, 0x7ff8 - i * 8);
+
+ ctxt->_eip = GET_SMSTATE(u64, smbase, 0x7f78);
+ ctxt->eflags = GET_SMSTATE(u32, smbase, 0x7f70) | X86_EFLAGS_FIXED;
+
+ val = GET_SMSTATE(u32, smbase, 0x7f68);
+ ctxt->ops->set_dr(ctxt, 6, (val & DR6_VOLATILE) | DR6_FIXED_1);
+ val = GET_SMSTATE(u32, smbase, 0x7f60);
+ ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1);
+
+ cr0 = GET_SMSTATE(u64, smbase, 0x7f58);
+ ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u64, smbase, 0x7f50));
+ cr4 = GET_SMSTATE(u64, smbase, 0x7f48);
+ ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7f00));
+ val = GET_SMSTATE(u64, smbase, 0x7ed0);
+ ctxt->ops->set_msr(ctxt, MSR_EFER, val & ~EFER_LMA);
+
+ selector = GET_SMSTATE(u32, smbase, 0x7e90);
+ rsm_set_desc_flags(&desc, GET_SMSTATE(u32, smbase, 0x7e92) << 8);
+ set_desc_limit(&desc, GET_SMSTATE(u32, smbase, 0x7e94));
+ set_desc_base(&desc, GET_SMSTATE(u32, smbase, 0x7e98));
+ base3 = GET_SMSTATE(u32, smbase, 0x7e9c);
+ ctxt->ops->set_segment(ctxt, selector, &desc, base3, VCPU_SREG_TR);
+
+ dt.size = GET_SMSTATE(u32, smbase, 0x7e84);
+ dt.address = GET_SMSTATE(u64, smbase, 0x7e88);
+ ctxt->ops->set_idt(ctxt, &dt);
+
+ selector = GET_SMSTATE(u32, smbase, 0x7e70);
+ rsm_set_desc_flags(&desc, GET_SMSTATE(u32, smbase, 0x7e72) << 8);
+ set_desc_limit(&desc, GET_SMSTATE(u32, smbase, 0x7e74));
+ set_desc_base(&desc, GET_SMSTATE(u32, smbase, 0x7e78));
+ base3 = GET_SMSTATE(u32, smbase, 0x7e7c);
+ ctxt->ops->set_segment(ctxt, selector, &desc, base3, VCPU_SREG_LDTR);
+
+ dt.size = GET_SMSTATE(u32, smbase, 0x7e64);
+ dt.address = GET_SMSTATE(u64, smbase, 0x7e68);
+ ctxt->ops->set_gdt(ctxt, &dt);
+
+ for (i = 0; i < 6; i++) {
+ int r = rsm_load_seg_64(ctxt, smbase, i);
+ if (r != X86EMUL_CONTINUE)
+ return r;
+ }
+
+ return rsm_enter_protected_mode(ctxt, cr0, cr4);
+}
+
+static int em_rsm(struct x86_emulate_ctxt *ctxt)
+{
+ unsigned long cr0, cr4, efer;
+ u64 smbase;
+ int ret;
+
+ if ((ctxt->emul_flags & X86EMUL_SMM_MASK) == 0)
+ return emulate_ud(ctxt);
+
+ /*
+ * Get back to real mode, to prepare a safe state in which to load
+ * CR0/CR3/CR4/EFER. Also this will ensure that addresses passed
+ * to read_std/write_std are not virtual.
+ *
+ * CR4.PCIDE must be zero, because it is a 64-bit mode only feature.
+ */
+ cr0 = ctxt->ops->get_cr(ctxt, 0);
+ if (cr0 & X86_CR0_PE)
+ ctxt->ops->set_cr(ctxt, 0, cr0 & ~(X86_CR0_PG | X86_CR0_PE));
+ cr4 = ctxt->ops->get_cr(ctxt, 4);
+ if (cr4 & X86_CR4_PAE)
+ ctxt->ops->set_cr(ctxt, 4, cr4 & ~X86_CR4_PAE);
+ efer = 0;
+ ctxt->ops->set_msr(ctxt, MSR_EFER, efer);
+
+ smbase = ctxt->ops->get_smbase(ctxt);
+ if (emulator_has_longmode(ctxt))
+ ret = rsm_load_state_64(ctxt, smbase + 0x8000);
+ else
+ ret = rsm_load_state_32(ctxt, smbase + 0x8000);
+
+ if (ret != X86EMUL_CONTINUE) {
+ /* FIXME: should triple fault */
+ return X86EMUL_UNHANDLEABLE;
+ }
+
+ if ((ctxt->emul_flags & X86EMUL_SMM_INSIDE_NMI_MASK) == 0)
+ ctxt->ops->set_nmi_mask(ctxt, false);
+
+ ctxt->emul_flags &= ~X86EMUL_SMM_INSIDE_NMI_MASK;
+ ctxt->emul_flags &= ~X86EMUL_SMM_MASK;
+ return X86EMUL_CONTINUE;
+}
+
static void
setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
struct desc_struct *cs, struct desc_struct *ss)
@@ -2573,6 +2824,30 @@ static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
return true;
}
+static void string_registers_quirk(struct x86_emulate_ctxt *ctxt)
+{
+ /*
+ * Intel CPUs mask the counter and pointers in quite strange
+ * manner when ECX is zero due to REP-string optimizations.
+ */
+#ifdef CONFIG_X86_64
+ if (ctxt->ad_bytes != 4 || !vendor_intel(ctxt))
+ return;
+
+ *reg_write(ctxt, VCPU_REGS_RCX) = 0;
+
+ switch (ctxt->b) {
+ case 0xa4: /* movsb */
+ case 0xa5: /* movsd/w */
+ *reg_rmw(ctxt, VCPU_REGS_RSI) &= (u32)-1;
+ /* fall through */
+ case 0xaa: /* stosb */
+ case 0xab: /* stosd/w */
+ *reg_rmw(ctxt, VCPU_REGS_RDI) &= (u32)-1;
+ }
+#endif
+}
+
static void save_state_to_tss16(struct x86_emulate_ctxt *ctxt,
struct tss_segment_16 *tss)
{
@@ -2849,7 +3124,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
ulong old_tss_base =
ops->get_cached_segment_base(ctxt, VCPU_SREG_TR);
u32 desc_limit;
- ulong desc_addr;
+ ulong desc_addr, dr7;
/* FIXME: old_tss_base == ~0 ? */
@@ -2934,6 +3209,9 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
ret = em_push(ctxt);
}
+ ops->get_dr(ctxt, 7, &dr7);
+ ops->set_dr(ctxt, 7, dr7 & ~(DR_LOCAL_ENABLE_MASK | DR_LOCAL_SLOWDOWN));
+
return ret;
}
@@ -3840,7 +4118,7 @@ static const struct opcode group5[] = {
F(DstMem | SrcNone | Lock, em_inc),
F(DstMem | SrcNone | Lock, em_dec),
I(SrcMem | NearBranch, em_call_near_abs),
- I(SrcMemFAddr | ImplicitOps | Stack, em_call_far),
+ I(SrcMemFAddr | ImplicitOps, em_call_far),
I(SrcMem | NearBranch, em_jmp_abs),
I(SrcMemFAddr | ImplicitOps, em_jmp_far),
I(SrcMem | Stack, em_push), D(Undefined),
@@ -4173,7 +4451,7 @@ static const struct opcode twobyte_table[256] = {
F(DstMem | SrcReg | Src2CL | ModRM, em_shld), N, N,
/* 0xA8 - 0xAF */
I(Stack | Src2GS, em_push_sreg), I(Stack | Src2GS, em_pop_sreg),
- DI(ImplicitOps, rsm),
+ II(No64 | EmulateOnUD | ImplicitOps, em_rsm, rsm),
F(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_bts),
F(DstMem | SrcReg | Src2ImmByte | ModRM, em_shrd),
F(DstMem | SrcReg | Src2CL | ModRM, em_shrd),
@@ -4871,7 +5149,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
fetch_possible_mmx_operand(ctxt, &ctxt->dst);
}
- if (unlikely(ctxt->guest_mode) && (ctxt->d & Intercept)) {
+ if (unlikely(ctxt->emul_flags & X86EMUL_GUEST_MASK) && ctxt->intercept) {
rc = emulator_check_intercept(ctxt, ctxt->intercept,
X86_ICPT_PRE_EXCEPT);
if (rc != X86EMUL_CONTINUE)
@@ -4900,7 +5178,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
goto done;
}
- if (unlikely(ctxt->guest_mode) && (ctxt->d & Intercept)) {
+ if (unlikely(ctxt->emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) {
rc = emulator_check_intercept(ctxt, ctxt->intercept,
X86_ICPT_POST_EXCEPT);
if (rc != X86EMUL_CONTINUE)
@@ -4910,6 +5188,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
if (ctxt->rep_prefix && (ctxt->d & String)) {
/* All REP prefixes have the same first termination condition */
if (address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) == 0) {
+ string_registers_quirk(ctxt);
ctxt->eip = ctxt->_eip;
ctxt->eflags &= ~X86_EFLAGS_RF;
goto done;
@@ -4953,7 +5232,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
special_insn:
- if (unlikely(ctxt->guest_mode) && (ctxt->d & Intercept)) {
+ if (unlikely(ctxt->emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) {
rc = emulator_check_intercept(ctxt, ctxt->intercept,
X86_ICPT_POST_MEMACCESS);
if (rc != X86EMUL_CONTINUE)
diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
index 28146f03c514..856f79105bb5 100644
--- a/arch/x86/kvm/ioapic.c
+++ b/arch/x86/kvm/ioapic.c
@@ -349,6 +349,7 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
irqe.delivery_mode = entry->fields.delivery_mode << 8;
irqe.level = 1;
irqe.shorthand = 0;
+ irqe.msi_redir_hint = false;
if (irqe.trig_mode == IOAPIC_EDGE_TRIG)
ioapic->irr_delivered |= 1 << irq;
@@ -637,11 +638,9 @@ void kvm_ioapic_destroy(struct kvm *kvm)
struct kvm_ioapic *ioapic = kvm->arch.vioapic;
cancel_delayed_work_sync(&ioapic->eoi_inject);
- if (ioapic) {
- kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &ioapic->dev);
- kvm->arch.vioapic = NULL;
- kfree(ioapic);
- }
+ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &ioapic->dev);
+ kvm->arch.vioapic = NULL;
+ kfree(ioapic);
}
int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c
index 72298b3ac025..9efff9e5b58c 100644
--- a/arch/x86/kvm/irq_comm.c
+++ b/arch/x86/kvm/irq_comm.c
@@ -31,6 +31,8 @@
#include "ioapic.h"
+#include "lapic.h"
+
static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id, int level,
bool line_status)
@@ -48,11 +50,6 @@ static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
line_status);
}
-inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq)
-{
- return irq->delivery_mode == APIC_DM_LOWEST;
-}
-
int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
struct kvm_lapic_irq *irq, unsigned long *dest_map)
{
@@ -60,7 +57,7 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
struct kvm_vcpu *vcpu, *lowest = NULL;
if (irq->dest_mode == 0 && irq->dest_id == 0xff &&
- kvm_is_dm_lowest_prio(irq)) {
+ kvm_lowest_prio_delivery(irq)) {
printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n");
irq->delivery_mode = APIC_DM_FIXED;
}
@@ -76,7 +73,7 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
irq->dest_id, irq->dest_mode))
continue;
- if (!kvm_is_dm_lowest_prio(irq)) {
+ if (!kvm_lowest_prio_delivery(irq)) {
if (r < 0)
r = 0;
r += kvm_apic_set_irq(vcpu, irq, dest_map);
@@ -106,9 +103,10 @@ static inline void kvm_set_msi_irq(struct kvm_kernel_irq_routing_entry *e,
irq->dest_mode = (1 << MSI_ADDR_DEST_MODE_SHIFT) & e->msi.address_lo;
irq->trig_mode = (1 << MSI_DATA_TRIGGER_SHIFT) & e->msi.data;
irq->delivery_mode = e->msi.data & 0x700;
+ irq->msi_redir_hint = ((e->msi.address_lo
+ & MSI_ADDR_REDIRECTION_LOWPRI) > 0);
irq->level = 1;
irq->shorthand = 0;
- /* TODO Deal with RH bit of MSI message address */
}
int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h
index 544076c4f44b..e1e89ee4af75 100644
--- a/arch/x86/kvm/kvm_cache_regs.h
+++ b/arch/x86/kvm/kvm_cache_regs.h
@@ -99,4 +99,9 @@ static inline bool is_guest_mode(struct kvm_vcpu *vcpu)
return vcpu->arch.hflags & HF_GUEST_MASK;
}
+static inline bool is_smm(struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.hflags & HF_SMM_MASK;
+}
+
#endif
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 629af0f1c5c4..36e9de1b4127 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -240,6 +240,15 @@ static inline void kvm_apic_set_ldr(struct kvm_lapic *apic, u32 id)
recalculate_apic_map(apic->vcpu->kvm);
}
+static inline void kvm_apic_set_x2apic_id(struct kvm_lapic *apic, u8 id)
+{
+ u32 ldr = ((id >> 4) << 16) | (1 << (id & 0xf));
+
+ apic_set_reg(apic, APIC_ID, id << 24);
+ apic_set_reg(apic, APIC_LDR, ldr);
+ recalculate_apic_map(apic->vcpu->kvm);
+}
+
static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type)
{
return !(kvm_apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED);
@@ -728,7 +737,7 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
dst = map->logical_map[cid];
- if (irq->delivery_mode == APIC_DM_LOWEST) {
+ if (kvm_lowest_prio_delivery(irq)) {
int l = -1;
for_each_set_bit(i, &bitmap, 16) {
if (!dst[i])
@@ -799,7 +808,9 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
break;
case APIC_DM_SMI:
- apic_debug("Ignoring guest SMI\n");
+ result = 1;
+ kvm_make_request(KVM_REQ_SMI, vcpu);
+ kvm_vcpu_kick(vcpu);
break;
case APIC_DM_NMI:
@@ -914,9 +925,10 @@ static void apic_send_ipi(struct kvm_lapic *apic)
irq.vector = icr_low & APIC_VECTOR_MASK;
irq.delivery_mode = icr_low & APIC_MODE_MASK;
irq.dest_mode = icr_low & APIC_DEST_MASK;
- irq.level = icr_low & APIC_INT_ASSERT;
+ irq.level = (icr_low & APIC_INT_ASSERT) != 0;
irq.trig_mode = icr_low & APIC_INT_LEVELTRIG;
irq.shorthand = icr_low & APIC_SHORT_MASK;
+ irq.msi_redir_hint = false;
if (apic_x2apic_mode(apic))
irq.dest_id = icr_high;
else
@@ -926,10 +938,11 @@ static void apic_send_ipi(struct kvm_lapic *apic)
apic_debug("icr_high 0x%x, icr_low 0x%x, "
"short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
- "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
+ "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x, "
+ "msi_redir_hint 0x%x\n",
icr_high, icr_low, irq.shorthand, irq.dest_id,
irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode,
- irq.vector);
+ irq.vector, irq.msi_redir_hint);
kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq, NULL);
}
@@ -1090,6 +1103,17 @@ static void update_divide_count(struct kvm_lapic *apic)
apic->divide_count);
}
+static void apic_update_lvtt(struct kvm_lapic *apic)
+{
+ u32 timer_mode = kvm_apic_get_reg(apic, APIC_LVTT) &
+ apic->lapic_timer.timer_mode_mask;
+
+ if (apic->lapic_timer.timer_mode != timer_mode) {
+ apic->lapic_timer.timer_mode = timer_mode;
+ hrtimer_cancel(&apic->lapic_timer.timer);
+ }
+}
+
static void apic_timer_expired(struct kvm_lapic *apic)
{
struct kvm_vcpu *vcpu = apic->vcpu;
@@ -1298,6 +1322,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
apic_set_reg(apic, APIC_LVTT + 0x10 * i,
lvt_val | APIC_LVT_MASKED);
}
+ apic_update_lvtt(apic);
atomic_set(&apic->lapic_timer.pending, 0);
}
@@ -1330,20 +1355,13 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
break;
- case APIC_LVTT: {
- u32 timer_mode = val & apic->lapic_timer.timer_mode_mask;
-
- if (apic->lapic_timer.timer_mode != timer_mode) {
- apic->lapic_timer.timer_mode = timer_mode;
- hrtimer_cancel(&apic->lapic_timer.timer);
- }
-
+ case APIC_LVTT:
if (!kvm_apic_sw_enabled(apic))
val |= APIC_LVT_MASKED;
val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask);
apic_set_reg(apic, APIC_LVTT, val);
+ apic_update_lvtt(apic);
break;
- }
case APIC_TMICT:
if (apic_lvtt_tscdeadline(apic))
@@ -1536,9 +1554,7 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
if ((old_value ^ value) & X2APIC_ENABLE) {
if (value & X2APIC_ENABLE) {
- u32 id = kvm_apic_id(apic);
- u32 ldr = ((id >> 4) << 16) | (1 << (id & 0xf));
- kvm_apic_set_ldr(apic, ldr);
+ kvm_apic_set_x2apic_id(apic, vcpu->vcpu_id);
kvm_x86_ops->set_virtual_x2apic_mode(vcpu, true);
} else
kvm_x86_ops->set_virtual_x2apic_mode(vcpu, false);
@@ -1557,7 +1573,7 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
}
-void kvm_lapic_reset(struct kvm_vcpu *vcpu)
+void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
{
struct kvm_lapic *apic;
int i;
@@ -1571,19 +1587,22 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
/* Stop the timer in case it's a reset to an active apic */
hrtimer_cancel(&apic->lapic_timer.timer);
- kvm_apic_set_id(apic, vcpu->vcpu_id);
+ if (!init_event)
+ kvm_apic_set_id(apic, vcpu->vcpu_id);
kvm_apic_set_version(apic->vcpu);
for (i = 0; i < APIC_LVT_NUM; i++)
apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
- apic->lapic_timer.timer_mode = 0;
- apic_set_reg(apic, APIC_LVT0,
- SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
+ apic_update_lvtt(apic);
+ if (!(vcpu->kvm->arch.disabled_quirks & KVM_QUIRK_LINT0_REENABLED))
+ apic_set_reg(apic, APIC_LVT0,
+ SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
apic_set_reg(apic, APIC_DFR, 0xffffffffU);
apic_set_spiv(apic, 0xff);
apic_set_reg(apic, APIC_TASKPRI, 0);
- kvm_apic_set_ldr(apic, 0);
+ if (!apic_x2apic_mode(apic))
+ kvm_apic_set_ldr(apic, 0);
apic_set_reg(apic, APIC_ESR, 0);
apic_set_reg(apic, APIC_ICR, 0);
apic_set_reg(apic, APIC_ICR2, 0);
@@ -1712,7 +1731,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE);
static_key_slow_inc(&apic_sw_disabled.key); /* sw disabled at reset */
- kvm_lapic_reset(vcpu);
+ kvm_lapic_reset(vcpu, false);
kvm_iodevice_init(&apic->dev, &apic_mmio_ops);
return 0;
@@ -1802,6 +1821,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
apic_update_ppr(apic);
hrtimer_cancel(&apic->lapic_timer.timer);
+ apic_update_lvtt(apic);
update_divide_count(apic);
start_apic_timer(apic);
apic->irr_pending = true;
@@ -2043,11 +2063,22 @@ void kvm_apic_accept_events(struct kvm_vcpu *vcpu)
if (!kvm_vcpu_has_lapic(vcpu) || !apic->pending_events)
return;
- pe = xchg(&apic->pending_events, 0);
+ /*
+ * INITs are latched while in SMM. Because an SMM CPU cannot
+ * be in KVM_MP_STATE_INIT_RECEIVED state, just eat SIPIs
+ * and delay processing of INIT until the next RSM.
+ */
+ if (is_smm(vcpu)) {
+ WARN_ON_ONCE(vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED);
+ if (test_bit(KVM_APIC_SIPI, &apic->pending_events))
+ clear_bit(KVM_APIC_SIPI, &apic->pending_events);
+ return;
+ }
+ pe = xchg(&apic->pending_events, 0);
if (test_bit(KVM_APIC_INIT, &pe)) {
- kvm_lapic_reset(vcpu);
- kvm_vcpu_reset(vcpu);
+ kvm_lapic_reset(vcpu, true);
+ kvm_vcpu_reset(vcpu, true);
if (kvm_vcpu_is_bsp(apic->vcpu))
vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
else
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 9d28383fc1e7..f2f4e10ab772 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -48,7 +48,7 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu);
int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu);
int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
void kvm_apic_accept_events(struct kvm_vcpu *vcpu);
-void kvm_lapic_reset(struct kvm_vcpu *vcpu);
+void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event);
u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu);
@@ -150,7 +150,18 @@ static inline bool kvm_apic_vid_enabled(struct kvm *kvm)
static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu)
{
- return vcpu->arch.apic->pending_events;
+ return kvm_vcpu_has_lapic(vcpu) && vcpu->arch.apic->pending_events;
+}
+
+static inline bool kvm_lowest_prio_delivery(struct kvm_lapic_irq *irq)
+{
+ return (irq->delivery_mode == APIC_DM_LOWEST ||
+ irq->msi_redir_hint);
+}
+
+static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_has_lapic(vcpu) && test_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
}
bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index b73337634214..f807496b62c2 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -223,15 +223,15 @@ static unsigned int get_mmio_spte_generation(u64 spte)
return gen;
}
-static unsigned int kvm_current_mmio_generation(struct kvm *kvm)
+static unsigned int kvm_current_mmio_generation(struct kvm_vcpu *vcpu)
{
- return kvm_memslots(kvm)->generation & MMIO_GEN_MASK;
+ return kvm_vcpu_memslots(vcpu)->generation & MMIO_GEN_MASK;
}
-static void mark_mmio_spte(struct kvm *kvm, u64 *sptep, u64 gfn,
+static void mark_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, u64 gfn,
unsigned access)
{
- unsigned int gen = kvm_current_mmio_generation(kvm);
+ unsigned int gen = kvm_current_mmio_generation(vcpu);
u64 mask = generation_mmio_spte_mask(gen);
access &= ACC_WRITE_MASK | ACC_USER_MASK;
@@ -258,22 +258,22 @@ static unsigned get_mmio_spte_access(u64 spte)
return (spte & ~mask) & ~PAGE_MASK;
}
-static bool set_mmio_spte(struct kvm *kvm, u64 *sptep, gfn_t gfn,
+static bool set_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn,
pfn_t pfn, unsigned access)
{
if (unlikely(is_noslot_pfn(pfn))) {
- mark_mmio_spte(kvm, sptep, gfn, access);
+ mark_mmio_spte(vcpu, sptep, gfn, access);
return true;
}
return false;
}
-static bool check_mmio_spte(struct kvm *kvm, u64 spte)
+static bool check_mmio_spte(struct kvm_vcpu *vcpu, u64 spte)
{
unsigned int kvm_gen, spte_gen;
- kvm_gen = kvm_current_mmio_generation(kvm);
+ kvm_gen = kvm_current_mmio_generation(vcpu);
spte_gen = get_mmio_spte_generation(spte);
trace_check_mmio_spte(spte, kvm_gen, spte_gen);
@@ -804,30 +804,36 @@ static struct kvm_lpage_info *lpage_info_slot(gfn_t gfn,
return &slot->arch.lpage_info[level - 2][idx];
}
-static void account_shadowed(struct kvm *kvm, gfn_t gfn)
+static void account_shadowed(struct kvm *kvm, struct kvm_mmu_page *sp)
{
+ struct kvm_memslots *slots;
struct kvm_memory_slot *slot;
struct kvm_lpage_info *linfo;
+ gfn_t gfn;
int i;
- slot = gfn_to_memslot(kvm, gfn);
- for (i = PT_DIRECTORY_LEVEL;
- i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
+ gfn = sp->gfn;
+ slots = kvm_memslots_for_spte_role(kvm, sp->role);
+ slot = __gfn_to_memslot(slots, gfn);
+ for (i = PT_DIRECTORY_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) {
linfo = lpage_info_slot(gfn, slot, i);
linfo->write_count += 1;
}
kvm->arch.indirect_shadow_pages++;
}
-static void unaccount_shadowed(struct kvm *kvm, gfn_t gfn)
+static void unaccount_shadowed(struct kvm *kvm, struct kvm_mmu_page *sp)
{
+ struct kvm_memslots *slots;
struct kvm_memory_slot *slot;
struct kvm_lpage_info *linfo;
+ gfn_t gfn;
int i;
- slot = gfn_to_memslot(kvm, gfn);
- for (i = PT_DIRECTORY_LEVEL;
- i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
+ gfn = sp->gfn;
+ slots = kvm_memslots_for_spte_role(kvm, sp->role);
+ slot = __gfn_to_memslot(slots, gfn);
+ for (i = PT_DIRECTORY_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) {
linfo = lpage_info_slot(gfn, slot, i);
linfo->write_count -= 1;
WARN_ON(linfo->write_count < 0);
@@ -835,14 +841,14 @@ static void unaccount_shadowed(struct kvm *kvm, gfn_t gfn)
kvm->arch.indirect_shadow_pages--;
}
-static int has_wrprotected_page(struct kvm *kvm,
+static int has_wrprotected_page(struct kvm_vcpu *vcpu,
gfn_t gfn,
int level)
{
struct kvm_memory_slot *slot;
struct kvm_lpage_info *linfo;
- slot = gfn_to_memslot(kvm, gfn);
+ slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
if (slot) {
linfo = lpage_info_slot(gfn, slot, level);
return linfo->write_count;
@@ -858,8 +864,7 @@ static int host_mapping_level(struct kvm *kvm, gfn_t gfn)
page_size = kvm_host_page_size(kvm, gfn);
- for (i = PT_PAGE_TABLE_LEVEL;
- i < (PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES); ++i) {
+ for (i = PT_PAGE_TABLE_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) {
if (page_size >= KVM_HPAGE_SIZE(i))
ret = i;
else
@@ -875,7 +880,7 @@ gfn_to_memslot_dirty_bitmap(struct kvm_vcpu *vcpu, gfn_t gfn,
{
struct kvm_memory_slot *slot;
- slot = gfn_to_memslot(vcpu->kvm, gfn);
+ slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
if (!slot || slot->flags & KVM_MEMSLOT_INVALID ||
(no_dirty_log && slot->dirty_bitmap))
slot = NULL;
@@ -900,7 +905,7 @@ static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn)
max_level = min(kvm_x86_ops->get_lpage_level(), host_level);
for (level = PT_DIRECTORY_LEVEL; level <= max_level; ++level)
- if (has_wrprotected_page(vcpu->kvm, large_gfn, level))
+ if (has_wrprotected_page(vcpu, large_gfn, level))
break;
return level - 1;
@@ -1042,12 +1047,14 @@ static unsigned long *__gfn_to_rmap(gfn_t gfn, int level,
/*
* Take gfn and return the reverse mapping to it.
*/
-static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int level)
+static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, struct kvm_mmu_page *sp)
{
+ struct kvm_memslots *slots;
struct kvm_memory_slot *slot;
- slot = gfn_to_memslot(kvm, gfn);
- return __gfn_to_rmap(gfn, level, slot);
+ slots = kvm_memslots_for_spte_role(kvm, sp->role);
+ slot = __gfn_to_memslot(slots, gfn);
+ return __gfn_to_rmap(gfn, sp->role.level, slot);
}
static bool rmap_can_add(struct kvm_vcpu *vcpu)
@@ -1065,7 +1072,7 @@ static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
sp = page_header(__pa(spte));
kvm_mmu_page_set_gfn(sp, spte - sp->spt, gfn);
- rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level);
+ rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp);
return pte_list_add(vcpu, spte, rmapp);
}
@@ -1077,7 +1084,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
sp = page_header(__pa(spte));
gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt);
- rmapp = gfn_to_rmap(kvm, gfn, sp->role.level);
+ rmapp = gfn_to_rmap(kvm, gfn, sp);
pte_list_remove(spte, rmapp);
}
@@ -1142,6 +1149,11 @@ static u64 *rmap_get_next(struct rmap_iterator *iter)
return NULL;
}
+#define for_each_rmap_spte(_rmap_, _iter_, _spte_) \
+ for (_spte_ = rmap_get_first(*_rmap_, _iter_); \
+ _spte_ && ({BUG_ON(!is_shadow_present_pte(*_spte_)); 1;}); \
+ _spte_ = rmap_get_next(_iter_))
+
static void drop_spte(struct kvm *kvm, u64 *sptep)
{
if (mmu_spte_clear_track_bits(sptep))
@@ -1205,12 +1217,8 @@ static bool __rmap_write_protect(struct kvm *kvm, unsigned long *rmapp,
struct rmap_iterator iter;
bool flush = false;
- for (sptep = rmap_get_first(*rmapp, &iter); sptep;) {
- BUG_ON(!(*sptep & PT_PRESENT_MASK));
-
+ for_each_rmap_spte(rmapp, &iter, sptep)
flush |= spte_write_protect(kvm, sptep, pt_protect);
- sptep = rmap_get_next(&iter);
- }
return flush;
}
@@ -1232,12 +1240,8 @@ static bool __rmap_clear_dirty(struct kvm *kvm, unsigned long *rmapp)
struct rmap_iterator iter;
bool flush = false;
- for (sptep = rmap_get_first(*rmapp, &iter); sptep;) {
- BUG_ON(!(*sptep & PT_PRESENT_MASK));
-
+ for_each_rmap_spte(rmapp, &iter, sptep)
flush |= spte_clear_dirty(kvm, sptep);
- sptep = rmap_get_next(&iter);
- }
return flush;
}
@@ -1259,12 +1263,8 @@ static bool __rmap_set_dirty(struct kvm *kvm, unsigned long *rmapp)
struct rmap_iterator iter;
bool flush = false;
- for (sptep = rmap_get_first(*rmapp, &iter); sptep;) {
- BUG_ON(!(*sptep & PT_PRESENT_MASK));
-
+ for_each_rmap_spte(rmapp, &iter, sptep)
flush |= spte_set_dirty(kvm, sptep);
- sptep = rmap_get_next(&iter);
- }
return flush;
}
@@ -1342,42 +1342,45 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
kvm_mmu_write_protect_pt_masked(kvm, slot, gfn_offset, mask);
}
-static bool rmap_write_protect(struct kvm *kvm, u64 gfn)
+static bool rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
{
struct kvm_memory_slot *slot;
unsigned long *rmapp;
int i;
bool write_protected = false;
- slot = gfn_to_memslot(kvm, gfn);
+ slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
- for (i = PT_PAGE_TABLE_LEVEL;
- i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
+ for (i = PT_PAGE_TABLE_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) {
rmapp = __gfn_to_rmap(gfn, i, slot);
- write_protected |= __rmap_write_protect(kvm, rmapp, true);
+ write_protected |= __rmap_write_protect(vcpu->kvm, rmapp, true);
}
return write_protected;
}
-static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
- struct kvm_memory_slot *slot, gfn_t gfn, int level,
- unsigned long data)
+static bool kvm_zap_rmapp(struct kvm *kvm, unsigned long *rmapp)
{
u64 *sptep;
struct rmap_iterator iter;
- int need_tlb_flush = 0;
+ bool flush = false;
while ((sptep = rmap_get_first(*rmapp, &iter))) {
BUG_ON(!(*sptep & PT_PRESENT_MASK));
- rmap_printk("kvm_rmap_unmap_hva: spte %p %llx gfn %llx (%d)\n",
- sptep, *sptep, gfn, level);
+ rmap_printk("%s: spte %p %llx.\n", __func__, sptep, *sptep);
drop_spte(kvm, sptep);
- need_tlb_flush = 1;
+ flush = true;
}
- return need_tlb_flush;
+ return flush;
+}
+
+static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
+ struct kvm_memory_slot *slot, gfn_t gfn, int level,
+ unsigned long data)
+{
+ return kvm_zap_rmapp(kvm, rmapp);
}
static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
@@ -1394,8 +1397,8 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
WARN_ON(pte_huge(*ptep));
new_pfn = pte_pfn(*ptep);
- for (sptep = rmap_get_first(*rmapp, &iter); sptep;) {
- BUG_ON(!is_shadow_present_pte(*sptep));
+restart:
+ for_each_rmap_spte(rmapp, &iter, sptep) {
rmap_printk("kvm_set_pte_rmapp: spte %p %llx gfn %llx (%d)\n",
sptep, *sptep, gfn, level);
@@ -1403,7 +1406,7 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
if (pte_write(*ptep)) {
drop_spte(kvm, sptep);
- sptep = rmap_get_first(*rmapp, &iter);
+ goto restart;
} else {
new_spte = *sptep & ~PT64_BASE_ADDR_MASK;
new_spte |= (u64)new_pfn << PAGE_SHIFT;
@@ -1414,7 +1417,6 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
mmu_spte_clear_track_bits(sptep);
mmu_spte_set(sptep, new_spte);
- sptep = rmap_get_next(&iter);
}
}
@@ -1424,6 +1426,74 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
return 0;
}
+struct slot_rmap_walk_iterator {
+ /* input fields. */
+ struct kvm_memory_slot *slot;
+ gfn_t start_gfn;
+ gfn_t end_gfn;
+ int start_level;
+ int end_level;
+
+ /* output fields. */
+ gfn_t gfn;
+ unsigned long *rmap;
+ int level;
+
+ /* private field. */
+ unsigned long *end_rmap;
+};
+
+static void
+rmap_walk_init_level(struct slot_rmap_walk_iterator *iterator, int level)
+{
+ iterator->level = level;
+ iterator->gfn = iterator->start_gfn;
+ iterator->rmap = __gfn_to_rmap(iterator->gfn, level, iterator->slot);
+ iterator->end_rmap = __gfn_to_rmap(iterator->end_gfn, level,
+ iterator->slot);
+}
+
+static void
+slot_rmap_walk_init(struct slot_rmap_walk_iterator *iterator,
+ struct kvm_memory_slot *slot, int start_level,
+ int end_level, gfn_t start_gfn, gfn_t end_gfn)
+{
+ iterator->slot = slot;
+ iterator->start_level = start_level;
+ iterator->end_level = end_level;
+ iterator->start_gfn = start_gfn;
+ iterator->end_gfn = end_gfn;
+
+ rmap_walk_init_level(iterator, iterator->start_level);
+}
+
+static bool slot_rmap_walk_okay(struct slot_rmap_walk_iterator *iterator)
+{
+ return !!iterator->rmap;
+}
+
+static void slot_rmap_walk_next(struct slot_rmap_walk_iterator *iterator)
+{
+ if (++iterator->rmap <= iterator->end_rmap) {
+ iterator->gfn += (1UL << KVM_HPAGE_GFN_SHIFT(iterator->level));
+ return;
+ }
+
+ if (++iterator->level > iterator->end_level) {
+ iterator->rmap = NULL;
+ return;
+ }
+
+ rmap_walk_init_level(iterator, iterator->level);
+}
+
+#define for_each_slot_rmap_range(_slot_, _start_level_, _end_level_, \
+ _start_gfn, _end_gfn, _iter_) \
+ for (slot_rmap_walk_init(_iter_, _slot_, _start_level_, \
+ _end_level_, _start_gfn, _end_gfn); \
+ slot_rmap_walk_okay(_iter_); \
+ slot_rmap_walk_next(_iter_))
+
static int kvm_handle_hva_range(struct kvm *kvm,
unsigned long start,
unsigned long end,
@@ -1435,48 +1505,36 @@ static int kvm_handle_hva_range(struct kvm *kvm,
int level,
unsigned long data))
{
- int j;
- int ret = 0;
struct kvm_memslots *slots;
struct kvm_memory_slot *memslot;
+ struct slot_rmap_walk_iterator iterator;
+ int ret = 0;
+ int i;
- slots = kvm_memslots(kvm);
-
- kvm_for_each_memslot(memslot, slots) {
- unsigned long hva_start, hva_end;
- gfn_t gfn_start, gfn_end;
-
- hva_start = max(start, memslot->userspace_addr);
- hva_end = min(end, memslot->userspace_addr +
- (memslot->npages << PAGE_SHIFT));
- if (hva_start >= hva_end)
- continue;
- /*
- * {gfn(page) | page intersects with [hva_start, hva_end)} =
- * {gfn_start, gfn_start+1, ..., gfn_end-1}.
- */
- gfn_start = hva_to_gfn_memslot(hva_start, memslot);
- gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot);
-
- for (j = PT_PAGE_TABLE_LEVEL;
- j < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++j) {
- unsigned long idx, idx_end;
- unsigned long *rmapp;
- gfn_t gfn = gfn_start;
+ for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+ slots = __kvm_memslots(kvm, i);
+ kvm_for_each_memslot(memslot, slots) {
+ unsigned long hva_start, hva_end;
+ gfn_t gfn_start, gfn_end;
+ hva_start = max(start, memslot->userspace_addr);
+ hva_end = min(end, memslot->userspace_addr +
+ (memslot->npages << PAGE_SHIFT));
+ if (hva_start >= hva_end)
+ continue;
/*
- * {idx(page_j) | page_j intersects with
- * [hva_start, hva_end)} = {idx, idx+1, ..., idx_end}.
+ * {gfn(page) | page intersects with [hva_start, hva_end)} =
+ * {gfn_start, gfn_start+1, ..., gfn_end-1}.
*/
- idx = gfn_to_index(gfn_start, memslot->base_gfn, j);
- idx_end = gfn_to_index(gfn_end - 1, memslot->base_gfn, j);
-
- rmapp = __gfn_to_rmap(gfn_start, j, memslot);
-
- for (; idx <= idx_end;
- ++idx, gfn += (1UL << KVM_HPAGE_GFN_SHIFT(j)))
- ret |= handler(kvm, rmapp++, memslot,
- gfn, j, data);
+ gfn_start = hva_to_gfn_memslot(hva_start, memslot);
+ gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot);
+
+ for_each_slot_rmap_range(memslot, PT_PAGE_TABLE_LEVEL,
+ PT_MAX_HUGEPAGE_LEVEL,
+ gfn_start, gfn_end - 1,
+ &iterator)
+ ret |= handler(kvm, iterator.rmap, memslot,
+ iterator.gfn, iterator.level, data);
}
}
@@ -1518,16 +1576,13 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
BUG_ON(!shadow_accessed_mask);
- for (sptep = rmap_get_first(*rmapp, &iter); sptep;
- sptep = rmap_get_next(&iter)) {
- BUG_ON(!is_shadow_present_pte(*sptep));
-
+ for_each_rmap_spte(rmapp, &iter, sptep)
if (*sptep & shadow_accessed_mask) {
young = 1;
clear_bit((ffs(shadow_accessed_mask) - 1),
(unsigned long *)sptep);
}
- }
+
trace_kvm_age_page(gfn, level, slot, young);
return young;
}
@@ -1548,15 +1603,11 @@ static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
if (!shadow_accessed_mask)
goto out;
- for (sptep = rmap_get_first(*rmapp, &iter); sptep;
- sptep = rmap_get_next(&iter)) {
- BUG_ON(!is_shadow_present_pte(*sptep));
-
+ for_each_rmap_spte(rmapp, &iter, sptep)
if (*sptep & shadow_accessed_mask) {
young = 1;
break;
}
- }
out:
return young;
}
@@ -1570,7 +1621,7 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
sp = page_header(__pa(spte));
- rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level);
+ rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp);
kvm_unmap_rmapp(vcpu->kvm, rmapp, NULL, gfn, sp->role.level, 0);
kvm_flush_remote_tlbs(vcpu->kvm);
@@ -1990,7 +2041,7 @@ static void mmu_sync_children(struct kvm_vcpu *vcpu,
bool protected = false;
for_each_sp(pages, sp, parents, i)
- protected |= rmap_write_protect(vcpu->kvm, sp->gfn);
+ protected |= rmap_write_protect(vcpu, sp->gfn);
if (protected)
kvm_flush_remote_tlbs(vcpu->kvm);
@@ -2088,12 +2139,12 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
hlist_add_head(&sp->hash_link,
&vcpu->kvm->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)]);
if (!direct) {
- if (rmap_write_protect(vcpu->kvm, gfn))
+ if (rmap_write_protect(vcpu, gfn))
kvm_flush_remote_tlbs(vcpu->kvm);
if (level > PT_PAGE_TABLE_LEVEL && need_sync)
kvm_sync_pages(vcpu, gfn);
- account_shadowed(vcpu->kvm, gfn);
+ account_shadowed(vcpu->kvm, sp);
}
sp->mmu_valid_gen = vcpu->kvm->arch.mmu_valid_gen;
init_shadow_page_table(sp);
@@ -2274,7 +2325,7 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
kvm_mmu_unlink_parents(kvm, sp);
if (!sp->role.invalid && !sp->role.direct)
- unaccount_shadowed(kvm, sp->gfn);
+ unaccount_shadowed(kvm, sp);
if (sp->unsync)
kvm_unlink_unsync_page(kvm, sp);
@@ -2386,111 +2437,6 @@ int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
}
EXPORT_SYMBOL_GPL(kvm_mmu_unprotect_page);
-/*
- * The function is based on mtrr_type_lookup() in
- * arch/x86/kernel/cpu/mtrr/generic.c
- */
-static int get_mtrr_type(struct mtrr_state_type *mtrr_state,
- u64 start, u64 end)
-{
- int i;
- u64 base, mask;
- u8 prev_match, curr_match;
- int num_var_ranges = KVM_NR_VAR_MTRR;
-
- if (!mtrr_state->enabled)
- return 0xFF;
-
- /* Make end inclusive end, instead of exclusive */
- end--;
-
- /* Look in fixed ranges. Just return the type as per start */
- if (mtrr_state->have_fixed && (start < 0x100000)) {
- int idx;
-
- if (start < 0x80000) {
- idx = 0;
- idx += (start >> 16);
- return mtrr_state->fixed_ranges[idx];
- } else if (start < 0xC0000) {
- idx = 1 * 8;
- idx += ((start - 0x80000) >> 14);
- return mtrr_state->fixed_ranges[idx];
- } else if (start < 0x1000000) {
- idx = 3 * 8;
- idx += ((start - 0xC0000) >> 12);
- return mtrr_state->fixed_ranges[idx];
- }
- }
-
- /*
- * Look in variable ranges
- * Look of multiple ranges matching this address and pick type
- * as per MTRR precedence
- */
- if (!(mtrr_state->enabled & 2))
- return mtrr_state->def_type;
-
- prev_match = 0xFF;
- for (i = 0; i < num_var_ranges; ++i) {
- unsigned short start_state, end_state;
-
- if (!(mtrr_state->var_ranges[i].mask_lo & (1 << 11)))
- continue;
-
- base = (((u64)mtrr_state->var_ranges[i].base_hi) << 32) +
- (mtrr_state->var_ranges[i].base_lo & PAGE_MASK);
- mask = (((u64)mtrr_state->var_ranges[i].mask_hi) << 32) +
- (mtrr_state->var_ranges[i].mask_lo & PAGE_MASK);
-
- start_state = ((start & mask) == (base & mask));
- end_state = ((end & mask) == (base & mask));
- if (start_state != end_state)
- return 0xFE;
-
- if ((start & mask) != (base & mask))
- continue;
-
- curr_match = mtrr_state->var_ranges[i].base_lo & 0xff;
- if (prev_match == 0xFF) {
- prev_match = curr_match;
- continue;
- }
-
- if (prev_match == MTRR_TYPE_UNCACHABLE ||
- curr_match == MTRR_TYPE_UNCACHABLE)
- return MTRR_TYPE_UNCACHABLE;
-
- if ((prev_match == MTRR_TYPE_WRBACK &&
- curr_match == MTRR_TYPE_WRTHROUGH) ||
- (prev_match == MTRR_TYPE_WRTHROUGH &&
- curr_match == MTRR_TYPE_WRBACK)) {
- prev_match = MTRR_TYPE_WRTHROUGH;
- curr_match = MTRR_TYPE_WRTHROUGH;
- }
-
- if (prev_match != curr_match)
- return MTRR_TYPE_UNCACHABLE;
- }
-
- if (prev_match != 0xFF)
- return prev_match;
-
- return mtrr_state->def_type;
-}
-
-u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
-{
- u8 mtrr;
-
- mtrr = get_mtrr_type(&vcpu->arch.mtrr_state, gfn << PAGE_SHIFT,
- (gfn << PAGE_SHIFT) + PAGE_SIZE);
- if (mtrr == 0xfe || mtrr == 0xff)
- mtrr = MTRR_TYPE_WRBACK;
- return mtrr;
-}
-EXPORT_SYMBOL_GPL(kvm_get_guest_memory_type);
-
static void __kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
{
trace_kvm_mmu_unsync_page(sp);
@@ -2541,7 +2487,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
u64 spte;
int ret = 0;
- if (set_mmio_spte(vcpu->kvm, sptep, gfn, pfn, pte_access))
+ if (set_mmio_spte(vcpu, sptep, gfn, pfn, pte_access))
return 0;
spte = PT_PRESENT_MASK;
@@ -2578,7 +2524,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
* be fixed if guest refault.
*/
if (level > PT_PAGE_TABLE_LEVEL &&
- has_wrprotected_page(vcpu->kvm, gfn, level))
+ has_wrprotected_page(vcpu, gfn, level))
goto done;
spte |= PT_WRITABLE_MASK | SPTE_MMU_WRITEABLE;
@@ -2602,7 +2548,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
}
if (pte_access & ACC_WRITE_MASK) {
- mark_page_dirty(vcpu->kvm, gfn);
+ kvm_vcpu_mark_page_dirty(vcpu, gfn);
spte |= shadow_dirty_mask;
}
@@ -2692,15 +2638,17 @@ static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
u64 *start, u64 *end)
{
struct page *pages[PTE_PREFETCH_NUM];
+ struct kvm_memory_slot *slot;
unsigned access = sp->role.access;
int i, ret;
gfn_t gfn;
gfn = kvm_mmu_page_get_gfn(sp, start - sp->spt);
- if (!gfn_to_memslot_dirty_bitmap(vcpu, gfn, access & ACC_WRITE_MASK))
+ slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, access & ACC_WRITE_MASK);
+ if (!slot)
return -1;
- ret = gfn_to_page_many_atomic(vcpu->kvm, gfn, pages, end - start);
+ ret = gfn_to_page_many_atomic(slot, gfn, pages, end - start);
if (ret <= 0)
return -1;
@@ -2818,7 +2766,7 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, pfn_t pfn)
return 1;
if (pfn == KVM_PFN_ERR_HWPOISON) {
- kvm_send_hwpoison_signal(gfn_to_hva(vcpu->kvm, gfn), current);
+ kvm_send_hwpoison_signal(kvm_vcpu_gfn_to_hva(vcpu, gfn), current);
return 0;
}
@@ -2841,7 +2789,7 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,
if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn) &&
level == PT_PAGE_TABLE_LEVEL &&
PageTransCompound(pfn_to_page(pfn)) &&
- !has_wrprotected_page(vcpu->kvm, gfn, PT_DIRECTORY_LEVEL)) {
+ !has_wrprotected_page(vcpu, gfn, PT_DIRECTORY_LEVEL)) {
unsigned long mask;
/*
* mmu_notifier_retry was successful and we hold the
@@ -2933,7 +2881,7 @@ fast_pf_fix_direct_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
* Compare with set_spte where instead shadow_dirty_mask is set.
*/
if (cmpxchg64(sptep, spte, spte | PT_WRITABLE_MASK) == spte)
- mark_page_dirty(vcpu->kvm, gfn);
+ kvm_vcpu_mark_page_dirty(vcpu, gfn);
return true;
}
@@ -3388,7 +3336,7 @@ int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct)
gfn_t gfn = get_mmio_spte_gfn(spte);
unsigned access = get_mmio_spte_access(spte);
- if (!check_mmio_spte(vcpu->kvm, spte))
+ if (!check_mmio_spte(vcpu, spte))
return RET_MMIO_PF_INVALID;
if (direct)
@@ -3460,7 +3408,7 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn)
arch.direct_map = vcpu->arch.mmu.direct_map;
arch.cr3 = vcpu->arch.mmu.get_cr3(vcpu);
- return kvm_setup_async_pf(vcpu, gva, gfn_to_hva(vcpu->kvm, gfn), &arch);
+ return kvm_setup_async_pf(vcpu, gva, kvm_vcpu_gfn_to_hva(vcpu, gfn), &arch);
}
static bool can_do_async_pf(struct kvm_vcpu *vcpu)
@@ -3475,10 +3423,12 @@ 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)
{
+ struct kvm_memory_slot *slot;
bool async;
- *pfn = gfn_to_pfn_async(vcpu->kvm, gfn, &async, write, writable);
-
+ slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
+ async = false;
+ *pfn = __gfn_to_pfn_memslot(slot, gfn, false, &async, write, writable);
if (!async)
return false; /* *pfn has correct page already */
@@ -3492,11 +3442,20 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
return true;
}
- *pfn = gfn_to_pfn_prot(vcpu->kvm, gfn, write, writable);
-
+ *pfn = __gfn_to_pfn_memslot(slot, gfn, false, NULL, write, writable);
return false;
}
+static bool
+check_hugepage_cache_consistency(struct kvm_vcpu *vcpu, gfn_t gfn, int level)
+{
+ int page_num = KVM_PAGES_PER_HPAGE(level);
+
+ gfn &= ~(page_num - 1);
+
+ return kvm_mtrr_check_gfn_range_consistency(vcpu, gfn, page_num);
+}
+
static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
bool prefault)
{
@@ -3522,9 +3481,17 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
if (r)
return r;
- force_pt_level = mapping_level_dirty_bitmap(vcpu, gfn);
+ if (mapping_level_dirty_bitmap(vcpu, gfn) ||
+ !check_hugepage_cache_consistency(vcpu, gfn, PT_DIRECTORY_LEVEL))
+ force_pt_level = 1;
+ else
+ force_pt_level = 0;
+
if (likely(!force_pt_level)) {
level = mapping_level(vcpu, gfn);
+ if (level > PT_DIRECTORY_LEVEL &&
+ !check_hugepage_cache_consistency(vcpu, gfn, level))
+ level = PT_DIRECTORY_LEVEL;
gfn &= ~(KVM_PAGES_PER_HPAGE(level) - 1);
} else
level = PT_PAGE_TABLE_LEVEL;
@@ -3590,7 +3557,7 @@ static void inject_page_fault(struct kvm_vcpu *vcpu,
vcpu->arch.mmu.inject_page_fault(vcpu, fault);
}
-static bool sync_mmio_spte(struct kvm *kvm, u64 *sptep, gfn_t gfn,
+static bool sync_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn,
unsigned access, int *nr_present)
{
if (unlikely(is_mmio_spte(*sptep))) {
@@ -3600,7 +3567,7 @@ static bool sync_mmio_spte(struct kvm *kvm, u64 *sptep, gfn_t gfn,
}
(*nr_present)++;
- mark_mmio_spte(kvm, sptep, gfn, access);
+ mark_mmio_spte(vcpu, sptep, gfn, access);
return true;
}
@@ -3878,6 +3845,7 @@ static void init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
struct kvm_mmu *context = &vcpu->arch.mmu;
context->base_role.word = 0;
+ context->base_role.smm = is_smm(vcpu);
context->page_fault = tdp_page_fault;
context->sync_page = nonpaging_sync_page;
context->invlpg = nonpaging_invlpg;
@@ -3939,6 +3907,7 @@ void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu)
= smep && !is_write_protection(vcpu);
context->base_role.smap_andnot_wp
= smap && !is_write_protection(vcpu);
+ context->base_role.smm = is_smm(vcpu);
}
EXPORT_SYMBOL_GPL(kvm_init_shadow_mmu);
@@ -4110,7 +4079,7 @@ static u64 mmu_pte_write_fetch_gpte(struct kvm_vcpu *vcpu, gpa_t *gpa,
/* Handle a 32-bit guest writing two halves of a 64-bit gpte */
*gpa &= ~(gpa_t)7;
*bytes = 8;
- r = kvm_read_guest(vcpu->kvm, *gpa, &gentry, 8);
+ r = kvm_vcpu_read_guest(vcpu, *gpa, &gentry, 8);
if (r)
gentry = 0;
new = (const u8 *)&gentry;
@@ -4222,6 +4191,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
mask.nxe = 1;
mask.smep_andnot_wp = 1;
mask.smap_andnot_wp = 1;
+ mask.smm = 1;
/*
* If we don't have indirect shadow pages, it means no page is
@@ -4420,36 +4390,115 @@ void kvm_mmu_setup(struct kvm_vcpu *vcpu)
init_kvm_mmu(vcpu);
}
-void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
- struct kvm_memory_slot *memslot)
+/* The return value indicates if tlb flush on all vcpus is needed. */
+typedef bool (*slot_level_handler) (struct kvm *kvm, unsigned long *rmap);
+
+/* The caller should hold mmu-lock before calling this function. */
+static bool
+slot_handle_level_range(struct kvm *kvm, struct kvm_memory_slot *memslot,
+ slot_level_handler fn, int start_level, int end_level,
+ gfn_t start_gfn, gfn_t end_gfn, bool lock_flush_tlb)
{
- gfn_t last_gfn;
- int i;
+ struct slot_rmap_walk_iterator iterator;
bool flush = false;
- last_gfn = memslot->base_gfn + memslot->npages - 1;
+ for_each_slot_rmap_range(memslot, start_level, end_level, start_gfn,
+ end_gfn, &iterator) {
+ if (iterator.rmap)
+ flush |= fn(kvm, iterator.rmap);
- spin_lock(&kvm->mmu_lock);
+ if (need_resched() || spin_needbreak(&kvm->mmu_lock)) {
+ if (flush && lock_flush_tlb) {
+ kvm_flush_remote_tlbs(kvm);
+ flush = false;
+ }
+ cond_resched_lock(&kvm->mmu_lock);
+ }
+ }
- for (i = PT_PAGE_TABLE_LEVEL;
- i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
- unsigned long *rmapp;
- unsigned long last_index, index;
+ if (flush && lock_flush_tlb) {
+ kvm_flush_remote_tlbs(kvm);
+ flush = false;
+ }
- rmapp = memslot->arch.rmap[i - PT_PAGE_TABLE_LEVEL];
- last_index = gfn_to_index(last_gfn, memslot->base_gfn, i);
+ return flush;
+}
- for (index = 0; index <= last_index; ++index, ++rmapp) {
- if (*rmapp)
- flush |= __rmap_write_protect(kvm, rmapp,
- false);
+static bool
+slot_handle_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
+ slot_level_handler fn, int start_level, int end_level,
+ bool lock_flush_tlb)
+{
+ return slot_handle_level_range(kvm, memslot, fn, start_level,
+ end_level, memslot->base_gfn,
+ memslot->base_gfn + memslot->npages - 1,
+ lock_flush_tlb);
+}
+
+static bool
+slot_handle_all_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
+ slot_level_handler fn, bool lock_flush_tlb)
+{
+ return slot_handle_level(kvm, memslot, fn, PT_PAGE_TABLE_LEVEL,
+ PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb);
+}
+
+static bool
+slot_handle_large_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
+ slot_level_handler fn, bool lock_flush_tlb)
+{
+ return slot_handle_level(kvm, memslot, fn, PT_PAGE_TABLE_LEVEL + 1,
+ PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb);
+}
+
+static bool
+slot_handle_leaf(struct kvm *kvm, struct kvm_memory_slot *memslot,
+ slot_level_handler fn, bool lock_flush_tlb)
+{
+ return slot_handle_level(kvm, memslot, fn, PT_PAGE_TABLE_LEVEL,
+ PT_PAGE_TABLE_LEVEL, lock_flush_tlb);
+}
- if (need_resched() || spin_needbreak(&kvm->mmu_lock))
- cond_resched_lock(&kvm->mmu_lock);
+void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
+{
+ struct kvm_memslots *slots;
+ struct kvm_memory_slot *memslot;
+ int i;
+
+ spin_lock(&kvm->mmu_lock);
+ for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+ slots = __kvm_memslots(kvm, i);
+ kvm_for_each_memslot(memslot, slots) {
+ gfn_t start, end;
+
+ start = max(gfn_start, memslot->base_gfn);
+ end = min(gfn_end, memslot->base_gfn + memslot->npages);
+ if (start >= end)
+ continue;
+
+ slot_handle_level_range(kvm, memslot, kvm_zap_rmapp,
+ PT_PAGE_TABLE_LEVEL, PT_MAX_HUGEPAGE_LEVEL,
+ start, end - 1, true);
}
}
spin_unlock(&kvm->mmu_lock);
+}
+
+static bool slot_rmap_write_protect(struct kvm *kvm, unsigned long *rmapp)
+{
+ return __rmap_write_protect(kvm, rmapp, false);
+}
+
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
+ struct kvm_memory_slot *memslot)
+{
+ bool flush;
+
+ spin_lock(&kvm->mmu_lock);
+ flush = slot_handle_all_level(kvm, memslot, slot_rmap_write_protect,
+ false);
+ spin_unlock(&kvm->mmu_lock);
/*
* kvm_mmu_slot_remove_write_access() and kvm_vm_ioctl_get_dirty_log()
@@ -4482,9 +4531,8 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,
pfn_t pfn;
struct kvm_mmu_page *sp;
- for (sptep = rmap_get_first(*rmapp, &iter); sptep;) {
- BUG_ON(!(*sptep & PT_PRESENT_MASK));
-
+restart:
+ for_each_rmap_spte(rmapp, &iter, sptep) {
sp = page_header(__pa(sptep));
pfn = spte_to_pfn(*sptep);
@@ -4499,71 +4547,31 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,
!kvm_is_reserved_pfn(pfn) &&
PageTransCompound(pfn_to_page(pfn))) {
drop_spte(kvm, sptep);
- sptep = rmap_get_first(*rmapp, &iter);
need_tlb_flush = 1;
- } else
- sptep = rmap_get_next(&iter);
+ goto restart;
+ }
}
return need_tlb_flush;
}
void kvm_mmu_zap_collapsible_sptes(struct kvm *kvm,
- struct kvm_memory_slot *memslot)
+ const struct kvm_memory_slot *memslot)
{
- bool flush = false;
- unsigned long *rmapp;
- unsigned long last_index, index;
-
+ /* FIXME: const-ify all uses of struct kvm_memory_slot. */
spin_lock(&kvm->mmu_lock);
-
- rmapp = memslot->arch.rmap[0];
- last_index = gfn_to_index(memslot->base_gfn + memslot->npages - 1,
- memslot->base_gfn, PT_PAGE_TABLE_LEVEL);
-
- for (index = 0; index <= last_index; ++index, ++rmapp) {
- if (*rmapp)
- flush |= kvm_mmu_zap_collapsible_spte(kvm, rmapp);
-
- if (need_resched() || spin_needbreak(&kvm->mmu_lock)) {
- if (flush) {
- kvm_flush_remote_tlbs(kvm);
- flush = false;
- }
- cond_resched_lock(&kvm->mmu_lock);
- }
- }
-
- if (flush)
- kvm_flush_remote_tlbs(kvm);
-
+ slot_handle_leaf(kvm, (struct kvm_memory_slot *)memslot,
+ kvm_mmu_zap_collapsible_spte, true);
spin_unlock(&kvm->mmu_lock);
}
void kvm_mmu_slot_leaf_clear_dirty(struct kvm *kvm,
struct kvm_memory_slot *memslot)
{
- gfn_t last_gfn;
- unsigned long *rmapp;
- unsigned long last_index, index;
- bool flush = false;
-
- last_gfn = memslot->base_gfn + memslot->npages - 1;
+ bool flush;
spin_lock(&kvm->mmu_lock);
-
- rmapp = memslot->arch.rmap[PT_PAGE_TABLE_LEVEL - 1];
- last_index = gfn_to_index(last_gfn, memslot->base_gfn,
- PT_PAGE_TABLE_LEVEL);
-
- for (index = 0; index <= last_index; ++index, ++rmapp) {
- if (*rmapp)
- flush |= __rmap_clear_dirty(kvm, rmapp);
-
- if (need_resched() || spin_needbreak(&kvm->mmu_lock))
- cond_resched_lock(&kvm->mmu_lock);
- }
-
+ flush = slot_handle_leaf(kvm, memslot, __rmap_clear_dirty, false);
spin_unlock(&kvm->mmu_lock);
lockdep_assert_held(&kvm->slots_lock);
@@ -4582,31 +4590,11 @@ EXPORT_SYMBOL_GPL(kvm_mmu_slot_leaf_clear_dirty);
void kvm_mmu_slot_largepage_remove_write_access(struct kvm *kvm,
struct kvm_memory_slot *memslot)
{
- gfn_t last_gfn;
- int i;
- bool flush = false;
-
- last_gfn = memslot->base_gfn + memslot->npages - 1;
+ bool flush;
spin_lock(&kvm->mmu_lock);
-
- for (i = PT_PAGE_TABLE_LEVEL + 1; /* skip rmap for 4K page */
- i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
- unsigned long *rmapp;
- unsigned long last_index, index;
-
- rmapp = memslot->arch.rmap[i - PT_PAGE_TABLE_LEVEL];
- last_index = gfn_to_index(last_gfn, memslot->base_gfn, i);
-
- for (index = 0; index <= last_index; ++index, ++rmapp) {
- if (*rmapp)
- flush |= __rmap_write_protect(kvm, rmapp,
- false);
-
- if (need_resched() || spin_needbreak(&kvm->mmu_lock))
- cond_resched_lock(&kvm->mmu_lock);
- }
- }
+ flush = slot_handle_large_level(kvm, memslot, slot_rmap_write_protect,
+ false);
spin_unlock(&kvm->mmu_lock);
/* see kvm_mmu_slot_remove_write_access */
@@ -4620,31 +4608,10 @@ EXPORT_SYMBOL_GPL(kvm_mmu_slot_largepage_remove_write_access);
void kvm_mmu_slot_set_dirty(struct kvm *kvm,
struct kvm_memory_slot *memslot)
{
- gfn_t last_gfn;
- int i;
- bool flush = false;
-
- last_gfn = memslot->base_gfn + memslot->npages - 1;
+ bool flush;
spin_lock(&kvm->mmu_lock);
-
- for (i = PT_PAGE_TABLE_LEVEL;
- i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
- unsigned long *rmapp;
- unsigned long last_index, index;
-
- rmapp = memslot->arch.rmap[i - PT_PAGE_TABLE_LEVEL];
- last_index = gfn_to_index(last_gfn, memslot->base_gfn, i);
-
- for (index = 0; index <= last_index; ++index, ++rmapp) {
- if (*rmapp)
- flush |= __rmap_set_dirty(kvm, rmapp);
-
- if (need_resched() || spin_needbreak(&kvm->mmu_lock))
- cond_resched_lock(&kvm->mmu_lock);
- }
- }
-
+ flush = slot_handle_all_level(kvm, memslot, __rmap_set_dirty, false);
spin_unlock(&kvm->mmu_lock);
lockdep_assert_held(&kvm->slots_lock);
@@ -4741,13 +4708,13 @@ static bool kvm_has_zapped_obsolete_pages(struct kvm *kvm)
return unlikely(!list_empty_careful(&kvm->arch.zapped_obsolete_pages));
}
-void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm)
+void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, struct kvm_memslots *slots)
{
/*
* The very rare case: if the generation-number is round,
* zap all shadow pages.
*/
- if (unlikely(kvm_current_mmio_generation(kvm) == 0)) {
+ if (unlikely((slots->generation & MMIO_GEN_MASK) == 0)) {
printk_ratelimited(KERN_DEBUG "kvm: zapping shadow pages for mmio generation wraparound\n");
kvm_mmu_invalidate_zap_all_pages(kvm);
}
@@ -4869,15 +4836,18 @@ unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm)
unsigned int nr_pages = 0;
struct kvm_memslots *slots;
struct kvm_memory_slot *memslot;
+ int i;
- slots = kvm_memslots(kvm);
+ for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+ slots = __kvm_memslots(kvm, i);
- kvm_for_each_memslot(memslot, slots)
- nr_pages += memslot->npages;
+ kvm_for_each_memslot(memslot, slots)
+ nr_pages += memslot->npages;
+ }
nr_mmu_pages = nr_pages * KVM_PERMILLE_MMU_PAGES / 1000;
nr_mmu_pages = max(nr_mmu_pages,
- (unsigned int) KVM_MIN_ALLOC_MMU_PAGES);
+ (unsigned int) KVM_MIN_ALLOC_MMU_PAGES);
return nr_mmu_pages;
}
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 0ada65ecddcf..398d21c0f6dd 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -43,6 +43,7 @@
#define PT_PDPE_LEVEL 3
#define PT_DIRECTORY_LEVEL 2
#define PT_PAGE_TABLE_LEVEL 1
+#define PT_MAX_HUGEPAGE_LEVEL (PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES - 1)
static inline u64 rsvd_bits(int s, int e)
{
@@ -170,4 +171,5 @@ static inline bool permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
}
void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm);
+void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end);
#endif
diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c
index 9ade5cfb5a4c..a4f62e6f2db2 100644
--- a/arch/x86/kvm/mmu_audit.c
+++ b/arch/x86/kvm/mmu_audit.c
@@ -114,7 +114,7 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
return;
gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt);
- pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn);
+ pfn = kvm_vcpu_gfn_to_pfn_atomic(vcpu, gfn);
if (is_error_pfn(pfn))
return;
@@ -131,12 +131,16 @@ static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10);
unsigned long *rmapp;
struct kvm_mmu_page *rev_sp;
+ struct kvm_memslots *slots;
+ struct kvm_memory_slot *slot;
gfn_t gfn;
rev_sp = page_header(__pa(sptep));
gfn = kvm_mmu_page_get_gfn(rev_sp, sptep - rev_sp->spt);
- if (!gfn_to_memslot(kvm, gfn)) {
+ slots = kvm_memslots_for_spte_role(kvm, rev_sp->role);
+ slot = __gfn_to_memslot(slots, gfn);
+ if (!slot) {
if (!__ratelimit(&ratelimit_state))
return;
audit_printk(kvm, "no memslot for gfn %llx\n", gfn);
@@ -146,7 +150,7 @@ static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
return;
}
- rmapp = gfn_to_rmap(kvm, gfn, rev_sp->role.level);
+ rmapp = __gfn_to_rmap(gfn, rev_sp->role.level, slot);
if (!*rmapp) {
if (!__ratelimit(&ratelimit_state))
return;
@@ -191,19 +195,21 @@ static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
unsigned long *rmapp;
u64 *sptep;
struct rmap_iterator iter;
+ struct kvm_memslots *slots;
+ struct kvm_memory_slot *slot;
if (sp->role.direct || sp->unsync || sp->role.invalid)
return;
- rmapp = gfn_to_rmap(kvm, sp->gfn, PT_PAGE_TABLE_LEVEL);
+ slots = kvm_memslots_for_spte_role(kvm, sp->role);
+ slot = __gfn_to_memslot(slots, sp->gfn);
+ rmapp = __gfn_to_rmap(sp->gfn, PT_PAGE_TABLE_LEVEL, slot);
- for (sptep = rmap_get_first(*rmapp, &iter); sptep;
- sptep = rmap_get_next(&iter)) {
+ for_each_rmap_spte(rmapp, &iter, sptep)
if (is_writable_pte(*sptep))
audit_printk(kvm, "shadow page has writable "
"mappings: gfn %llx role %x\n",
sp->gfn, sp->role.word);
- }
}
static void audit_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
index ce463a9cc8fb..5a24b846a1cb 100644
--- a/arch/x86/kvm/mmutrace.h
+++ b/arch/x86/kvm/mmutrace.h
@@ -2,7 +2,7 @@
#define _TRACE_KVMMMU_H
#include <linux/tracepoint.h>
-#include <linux/ftrace_event.h>
+#include <linux/trace_events.h>
#undef TRACE_SYSTEM
#define TRACE_SYSTEM kvmmmu
diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c
new file mode 100644
index 000000000000..de1d2d8062e2
--- /dev/null
+++ b/arch/x86/kvm/mtrr.c
@@ -0,0 +1,699 @@
+/*
+ * vMTRR implementation
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
+ * Copyright(C) 2015 Intel Corporation.
+ *
+ * Authors:
+ * Yaniv Kamay <yaniv@qumranet.com>
+ * Avi Kivity <avi@qumranet.com>
+ * Marcelo Tosatti <mtosatti@redhat.com>
+ * Paolo Bonzini <pbonzini@redhat.com>
+ * Xiao Guangrong <guangrong.xiao@linux.intel.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/mtrr.h>
+
+#include "cpuid.h"
+#include "mmu.h"
+
+#define IA32_MTRR_DEF_TYPE_E (1ULL << 11)
+#define IA32_MTRR_DEF_TYPE_FE (1ULL << 10)
+#define IA32_MTRR_DEF_TYPE_TYPE_MASK (0xff)
+
+static bool msr_mtrr_valid(unsigned msr)
+{
+ switch (msr) {
+ case 0x200 ... 0x200 + 2 * KVM_NR_VAR_MTRR - 1:
+ case MSR_MTRRfix64K_00000:
+ case MSR_MTRRfix16K_80000:
+ case MSR_MTRRfix16K_A0000:
+ case MSR_MTRRfix4K_C0000:
+ case MSR_MTRRfix4K_C8000:
+ case MSR_MTRRfix4K_D0000:
+ case MSR_MTRRfix4K_D8000:
+ case MSR_MTRRfix4K_E0000:
+ case MSR_MTRRfix4K_E8000:
+ case MSR_MTRRfix4K_F0000:
+ case MSR_MTRRfix4K_F8000:
+ case MSR_MTRRdefType:
+ case MSR_IA32_CR_PAT:
+ return true;
+ case 0x2f8:
+ return true;
+ }
+ return false;
+}
+
+static bool valid_pat_type(unsigned t)
+{
+ return t < 8 && (1 << t) & 0xf3; /* 0, 1, 4, 5, 6, 7 */
+}
+
+static bool valid_mtrr_type(unsigned t)
+{
+ return t < 8 && (1 << t) & 0x73; /* 0, 1, 4, 5, 6 */
+}
+
+bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+{
+ int i;
+ u64 mask;
+
+ if (!msr_mtrr_valid(msr))
+ return false;
+
+ if (msr == MSR_IA32_CR_PAT) {
+ for (i = 0; i < 8; i++)
+ if (!valid_pat_type((data >> (i * 8)) & 0xff))
+ return false;
+ return true;
+ } else if (msr == MSR_MTRRdefType) {
+ if (data & ~0xcff)
+ return false;
+ return valid_mtrr_type(data & 0xff);
+ } else if (msr >= MSR_MTRRfix64K_00000 && msr <= MSR_MTRRfix4K_F8000) {
+ for (i = 0; i < 8 ; i++)
+ if (!valid_mtrr_type((data >> (i * 8)) & 0xff))
+ return false;
+ return true;
+ }
+
+ /* variable MTRRs */
+ WARN_ON(!(msr >= 0x200 && msr < 0x200 + 2 * KVM_NR_VAR_MTRR));
+
+ mask = (~0ULL) << cpuid_maxphyaddr(vcpu);
+ if ((msr & 1) == 0) {
+ /* MTRR base */
+ if (!valid_mtrr_type(data & 0xff))
+ return false;
+ mask |= 0xf00;
+ } else
+ /* MTRR mask */
+ mask |= 0x7ff;
+ if (data & mask) {
+ kvm_inject_gp(vcpu, 0);
+ return false;
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(kvm_mtrr_valid);
+
+static bool mtrr_is_enabled(struct kvm_mtrr *mtrr_state)
+{
+ return !!(mtrr_state->deftype & IA32_MTRR_DEF_TYPE_E);
+}
+
+static bool fixed_mtrr_is_enabled(struct kvm_mtrr *mtrr_state)
+{
+ return !!(mtrr_state->deftype & IA32_MTRR_DEF_TYPE_FE);
+}
+
+static u8 mtrr_default_type(struct kvm_mtrr *mtrr_state)
+{
+ return mtrr_state->deftype & IA32_MTRR_DEF_TYPE_TYPE_MASK;
+}
+
+/*
+* Three terms are used in the following code:
+* - segment, it indicates the address segments covered by fixed MTRRs.
+* - unit, it corresponds to the MSR entry in the segment.
+* - range, a range is covered in one memory cache type.
+*/
+struct fixed_mtrr_segment {
+ u64 start;
+ u64 end;
+
+ int range_shift;
+
+ /* the start position in kvm_mtrr.fixed_ranges[]. */
+ int range_start;
+};
+
+static struct fixed_mtrr_segment fixed_seg_table[] = {
+ /* MSR_MTRRfix64K_00000, 1 unit. 64K fixed mtrr. */
+ {
+ .start = 0x0,
+ .end = 0x80000,
+ .range_shift = 16, /* 64K */
+ .range_start = 0,
+ },
+
+ /*
+ * MSR_MTRRfix16K_80000 ... MSR_MTRRfix16K_A0000, 2 units,
+ * 16K fixed mtrr.
+ */
+ {
+ .start = 0x80000,
+ .end = 0xc0000,
+ .range_shift = 14, /* 16K */
+ .range_start = 8,
+ },
+
+ /*
+ * MSR_MTRRfix4K_C0000 ... MSR_MTRRfix4K_F8000, 8 units,
+ * 4K fixed mtrr.
+ */
+ {
+ .start = 0xc0000,
+ .end = 0x100000,
+ .range_shift = 12, /* 12K */
+ .range_start = 24,
+ }
+};
+
+/*
+ * The size of unit is covered in one MSR, one MSR entry contains
+ * 8 ranges so that unit size is always 8 * 2^range_shift.
+ */
+static u64 fixed_mtrr_seg_unit_size(int seg)
+{
+ return 8 << fixed_seg_table[seg].range_shift;
+}
+
+static bool fixed_msr_to_seg_unit(u32 msr, int *seg, int *unit)
+{
+ switch (msr) {
+ case MSR_MTRRfix64K_00000:
+ *seg = 0;
+ *unit = 0;
+ break;
+ case MSR_MTRRfix16K_80000 ... MSR_MTRRfix16K_A0000:
+ *seg = 1;
+ *unit = msr - MSR_MTRRfix16K_80000;
+ break;
+ case MSR_MTRRfix4K_C0000 ... MSR_MTRRfix4K_F8000:
+ *seg = 2;
+ *unit = msr - MSR_MTRRfix4K_C0000;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static void fixed_mtrr_seg_unit_range(int seg, int unit, u64 *start, u64 *end)
+{
+ struct fixed_mtrr_segment *mtrr_seg = &fixed_seg_table[seg];
+ u64 unit_size = fixed_mtrr_seg_unit_size(seg);
+
+ *start = mtrr_seg->start + unit * unit_size;
+ *end = *start + unit_size;
+ WARN_ON(*end > mtrr_seg->end);
+}
+
+static int fixed_mtrr_seg_unit_range_index(int seg, int unit)
+{
+ struct fixed_mtrr_segment *mtrr_seg = &fixed_seg_table[seg];
+
+ WARN_ON(mtrr_seg->start + unit * fixed_mtrr_seg_unit_size(seg)
+ > mtrr_seg->end);
+
+ /* each unit has 8 ranges. */
+ return mtrr_seg->range_start + 8 * unit;
+}
+
+static int fixed_mtrr_seg_end_range_index(int seg)
+{
+ struct fixed_mtrr_segment *mtrr_seg = &fixed_seg_table[seg];
+ int n;
+
+ n = (mtrr_seg->end - mtrr_seg->start) >> mtrr_seg->range_shift;
+ return mtrr_seg->range_start + n - 1;
+}
+
+static bool fixed_msr_to_range(u32 msr, u64 *start, u64 *end)
+{
+ int seg, unit;
+
+ if (!fixed_msr_to_seg_unit(msr, &seg, &unit))
+ return false;
+
+ fixed_mtrr_seg_unit_range(seg, unit, start, end);
+ return true;
+}
+
+static int fixed_msr_to_range_index(u32 msr)
+{
+ int seg, unit;
+
+ if (!fixed_msr_to_seg_unit(msr, &seg, &unit))
+ return -1;
+
+ return fixed_mtrr_seg_unit_range_index(seg, unit);
+}
+
+static int fixed_mtrr_addr_to_seg(u64 addr)
+{
+ struct fixed_mtrr_segment *mtrr_seg;
+ int seg, seg_num = ARRAY_SIZE(fixed_seg_table);
+
+ for (seg = 0; seg < seg_num; seg++) {
+ mtrr_seg = &fixed_seg_table[seg];
+ if (mtrr_seg->start >= addr && addr < mtrr_seg->end)
+ return seg;
+ }
+
+ return -1;
+}
+
+static int fixed_mtrr_addr_seg_to_range_index(u64 addr, int seg)
+{
+ struct fixed_mtrr_segment *mtrr_seg;
+ int index;
+
+ mtrr_seg = &fixed_seg_table[seg];
+ index = mtrr_seg->range_start;
+ index += (addr - mtrr_seg->start) >> mtrr_seg->range_shift;
+ return index;
+}
+
+static u64 fixed_mtrr_range_end_addr(int seg, int index)
+{
+ struct fixed_mtrr_segment *mtrr_seg = &fixed_seg_table[seg];
+ int pos = index - mtrr_seg->range_start;
+
+ return mtrr_seg->start + ((pos + 1) << mtrr_seg->range_shift);
+}
+
+static void var_mtrr_range(struct kvm_mtrr_range *range, u64 *start, u64 *end)
+{
+ u64 mask;
+
+ *start = range->base & PAGE_MASK;
+
+ mask = range->mask & PAGE_MASK;
+ mask |= ~0ULL << boot_cpu_data.x86_phys_bits;
+
+ /* This cannot overflow because writing to the reserved bits of
+ * variable MTRRs causes a #GP.
+ */
+ *end = (*start | ~mask) + 1;
+}
+
+static void update_mtrr(struct kvm_vcpu *vcpu, u32 msr)
+{
+ struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state;
+ gfn_t start, end;
+ int index;
+
+ if (msr == MSR_IA32_CR_PAT || !tdp_enabled ||
+ !kvm_arch_has_noncoherent_dma(vcpu->kvm))
+ return;
+
+ if (!mtrr_is_enabled(mtrr_state) && msr != MSR_MTRRdefType)
+ return;
+
+ /* fixed MTRRs. */
+ if (fixed_msr_to_range(msr, &start, &end)) {
+ if (!fixed_mtrr_is_enabled(mtrr_state))
+ return;
+ } else if (msr == MSR_MTRRdefType) {
+ start = 0x0;
+ end = ~0ULL;
+ } else {
+ /* variable range MTRRs. */
+ index = (msr - 0x200) / 2;
+ var_mtrr_range(&mtrr_state->var_ranges[index], &start, &end);
+ }
+
+ kvm_zap_gfn_range(vcpu->kvm, gpa_to_gfn(start), gpa_to_gfn(end));
+}
+
+static bool var_mtrr_range_is_valid(struct kvm_mtrr_range *range)
+{
+ return (range->mask & (1 << 11)) != 0;
+}
+
+static void set_var_mtrr_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+{
+ struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state;
+ struct kvm_mtrr_range *tmp, *cur;
+ int index, is_mtrr_mask;
+
+ index = (msr - 0x200) / 2;
+ is_mtrr_mask = msr - 0x200 - 2 * index;
+ cur = &mtrr_state->var_ranges[index];
+
+ /* remove the entry if it's in the list. */
+ if (var_mtrr_range_is_valid(cur))
+ list_del(&mtrr_state->var_ranges[index].node);
+
+ if (!is_mtrr_mask)
+ cur->base = data;
+ else
+ cur->mask = data;
+
+ /* add it to the list if it's enabled. */
+ if (var_mtrr_range_is_valid(cur)) {
+ list_for_each_entry(tmp, &mtrr_state->head, node)
+ if (cur->base >= tmp->base)
+ break;
+ list_add_tail(&cur->node, &tmp->node);
+ }
+}
+
+int kvm_mtrr_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+{
+ int index;
+
+ if (!kvm_mtrr_valid(vcpu, msr, data))
+ return 1;
+
+ index = fixed_msr_to_range_index(msr);
+ if (index >= 0)
+ *(u64 *)&vcpu->arch.mtrr_state.fixed_ranges[index] = data;
+ else if (msr == MSR_MTRRdefType)
+ vcpu->arch.mtrr_state.deftype = data;
+ else if (msr == MSR_IA32_CR_PAT)
+ vcpu->arch.pat = data;
+ else
+ set_var_mtrr_msr(vcpu, msr, data);
+
+ update_mtrr(vcpu, msr);
+ return 0;
+}
+
+int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
+{
+ int index;
+
+ /* MSR_MTRRcap is a readonly MSR. */
+ if (msr == MSR_MTRRcap) {
+ /*
+ * SMRR = 0
+ * WC = 1
+ * FIX = 1
+ * VCNT = KVM_NR_VAR_MTRR
+ */
+ *pdata = 0x500 | KVM_NR_VAR_MTRR;
+ return 0;
+ }
+
+ if (!msr_mtrr_valid(msr))
+ return 1;
+
+ index = fixed_msr_to_range_index(msr);
+ if (index >= 0)
+ *pdata = *(u64 *)&vcpu->arch.mtrr_state.fixed_ranges[index];
+ else if (msr == MSR_MTRRdefType)
+ *pdata = vcpu->arch.mtrr_state.deftype;
+ else if (msr == MSR_IA32_CR_PAT)
+ *pdata = vcpu->arch.pat;
+ else { /* Variable MTRRs */
+ int is_mtrr_mask;
+
+ index = (msr - 0x200) / 2;
+ is_mtrr_mask = msr - 0x200 - 2 * index;
+ if (!is_mtrr_mask)
+ *pdata = vcpu->arch.mtrr_state.var_ranges[index].base;
+ else
+ *pdata = vcpu->arch.mtrr_state.var_ranges[index].mask;
+ }
+
+ return 0;
+}
+
+void kvm_vcpu_mtrr_init(struct kvm_vcpu *vcpu)
+{
+ INIT_LIST_HEAD(&vcpu->arch.mtrr_state.head);
+}
+
+struct mtrr_iter {
+ /* input fields. */
+ struct kvm_mtrr *mtrr_state;
+ u64 start;
+ u64 end;
+
+ /* output fields. */
+ int mem_type;
+ /* [start, end) is not fully covered in MTRRs? */
+ bool partial_map;
+
+ /* private fields. */
+ union {
+ /* used for fixed MTRRs. */
+ struct {
+ int index;
+ int seg;
+ };
+
+ /* used for var MTRRs. */
+ struct {
+ struct kvm_mtrr_range *range;
+ /* max address has been covered in var MTRRs. */
+ u64 start_max;
+ };
+ };
+
+ bool fixed;
+};
+
+static bool mtrr_lookup_fixed_start(struct mtrr_iter *iter)
+{
+ int seg, index;
+
+ if (!fixed_mtrr_is_enabled(iter->mtrr_state))
+ return false;
+
+ seg = fixed_mtrr_addr_to_seg(iter->start);
+ if (seg < 0)
+ return false;
+
+ iter->fixed = true;
+ index = fixed_mtrr_addr_seg_to_range_index(iter->start, seg);
+ iter->index = index;
+ iter->seg = seg;
+ return true;
+}
+
+static bool match_var_range(struct mtrr_iter *iter,
+ struct kvm_mtrr_range *range)
+{
+ u64 start, end;
+
+ var_mtrr_range(range, &start, &end);
+ if (!(start >= iter->end || end <= iter->start)) {
+ iter->range = range;
+
+ /*
+ * the function is called when we do kvm_mtrr.head walking.
+ * Range has the minimum base address which interleaves
+ * [looker->start_max, looker->end).
+ */
+ iter->partial_map |= iter->start_max < start;
+
+ /* update the max address has been covered. */
+ iter->start_max = max(iter->start_max, end);
+ return true;
+ }
+
+ return false;
+}
+
+static void __mtrr_lookup_var_next(struct mtrr_iter *iter)
+{
+ struct kvm_mtrr *mtrr_state = iter->mtrr_state;
+
+ list_for_each_entry_continue(iter->range, &mtrr_state->head, node)
+ if (match_var_range(iter, iter->range))
+ return;
+
+ iter->range = NULL;
+ iter->partial_map |= iter->start_max < iter->end;
+}
+
+static void mtrr_lookup_var_start(struct mtrr_iter *iter)
+{
+ struct kvm_mtrr *mtrr_state = iter->mtrr_state;
+
+ iter->fixed = false;
+ iter->start_max = iter->start;
+ iter->range = list_prepare_entry(iter->range, &mtrr_state->head, node);
+
+ __mtrr_lookup_var_next(iter);
+}
+
+static void mtrr_lookup_fixed_next(struct mtrr_iter *iter)
+{
+ /* terminate the lookup. */
+ if (fixed_mtrr_range_end_addr(iter->seg, iter->index) >= iter->end) {
+ iter->fixed = false;
+ iter->range = NULL;
+ return;
+ }
+
+ iter->index++;
+
+ /* have looked up for all fixed MTRRs. */
+ if (iter->index >= ARRAY_SIZE(iter->mtrr_state->fixed_ranges))
+ return mtrr_lookup_var_start(iter);
+
+ /* switch to next segment. */
+ if (iter->index > fixed_mtrr_seg_end_range_index(iter->seg))
+ iter->seg++;
+}
+
+static void mtrr_lookup_var_next(struct mtrr_iter *iter)
+{
+ __mtrr_lookup_var_next(iter);
+}
+
+static void mtrr_lookup_start(struct mtrr_iter *iter)
+{
+ if (!mtrr_is_enabled(iter->mtrr_state)) {
+ iter->partial_map = true;
+ return;
+ }
+
+ if (!mtrr_lookup_fixed_start(iter))
+ mtrr_lookup_var_start(iter);
+}
+
+static void mtrr_lookup_init(struct mtrr_iter *iter,
+ struct kvm_mtrr *mtrr_state, u64 start, u64 end)
+{
+ iter->mtrr_state = mtrr_state;
+ iter->start = start;
+ iter->end = end;
+ iter->partial_map = false;
+ iter->fixed = false;
+ iter->range = NULL;
+
+ mtrr_lookup_start(iter);
+}
+
+static bool mtrr_lookup_okay(struct mtrr_iter *iter)
+{
+ if (iter->fixed) {
+ iter->mem_type = iter->mtrr_state->fixed_ranges[iter->index];
+ return true;
+ }
+
+ if (iter->range) {
+ iter->mem_type = iter->range->base & 0xff;
+ return true;
+ }
+
+ return false;
+}
+
+static void mtrr_lookup_next(struct mtrr_iter *iter)
+{
+ if (iter->fixed)
+ mtrr_lookup_fixed_next(iter);
+ else
+ mtrr_lookup_var_next(iter);
+}
+
+#define mtrr_for_each_mem_type(_iter_, _mtrr_, _gpa_start_, _gpa_end_) \
+ for (mtrr_lookup_init(_iter_, _mtrr_, _gpa_start_, _gpa_end_); \
+ mtrr_lookup_okay(_iter_); mtrr_lookup_next(_iter_))
+
+u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
+{
+ struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state;
+ struct mtrr_iter iter;
+ u64 start, end;
+ int type = -1;
+ const int wt_wb_mask = (1 << MTRR_TYPE_WRBACK)
+ | (1 << MTRR_TYPE_WRTHROUGH);
+
+ start = gfn_to_gpa(gfn);
+ end = start + PAGE_SIZE;
+
+ mtrr_for_each_mem_type(&iter, mtrr_state, start, end) {
+ int curr_type = iter.mem_type;
+
+ /*
+ * Please refer to Intel SDM Volume 3: 11.11.4.1 MTRR
+ * Precedences.
+ */
+
+ if (type == -1) {
+ type = curr_type;
+ continue;
+ }
+
+ /*
+ * If two or more variable memory ranges match and the
+ * memory types are identical, then that memory type is
+ * used.
+ */
+ if (type == curr_type)
+ continue;
+
+ /*
+ * If two or more variable memory ranges match and one of
+ * the memory types is UC, the UC memory type used.
+ */
+ if (curr_type == MTRR_TYPE_UNCACHABLE)
+ return MTRR_TYPE_UNCACHABLE;
+
+ /*
+ * If two or more variable memory ranges match and the
+ * memory types are WT and WB, the WT memory type is used.
+ */
+ if (((1 << type) & wt_wb_mask) &&
+ ((1 << curr_type) & wt_wb_mask)) {
+ type = MTRR_TYPE_WRTHROUGH;
+ continue;
+ }
+
+ /*
+ * For overlaps not defined by the above rules, processor
+ * behavior is undefined.
+ */
+
+ /* We use WB for this undefined behavior. :( */
+ return MTRR_TYPE_WRBACK;
+ }
+
+ /* It is not covered by MTRRs. */
+ if (iter.partial_map) {
+ /*
+ * We just check one page, partially covered by MTRRs is
+ * impossible.
+ */
+ WARN_ON(type != -1);
+ type = mtrr_default_type(mtrr_state);
+ }
+ return type;
+}
+EXPORT_SYMBOL_GPL(kvm_mtrr_get_guest_memory_type);
+
+bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn,
+ int page_num)
+{
+ struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state;
+ struct mtrr_iter iter;
+ u64 start, end;
+ int type = -1;
+
+ start = gfn_to_gpa(gfn);
+ end = gfn_to_gpa(gfn + page_num);
+ mtrr_for_each_mem_type(&iter, mtrr_state, start, end) {
+ if (type == -1) {
+ type = iter.mem_type;
+ continue;
+ }
+
+ if (type != iter.mem_type)
+ return false;
+ }
+
+ if (!iter.partial_map)
+ return true;
+
+ if (type == -1)
+ return true;
+
+ return type == mtrr_default_type(mtrr_state);
+}
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 6e6d115fe9b5..0f67d7e24800 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -256,7 +256,7 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu,
if (ret)
return ret;
- mark_page_dirty(vcpu->kvm, table_gfn);
+ kvm_vcpu_mark_page_dirty(vcpu, table_gfn);
walker->ptes[level] = pte;
}
return 0;
@@ -338,7 +338,7 @@ retry_walk:
real_gfn = gpa_to_gfn(real_gfn);
- host_addr = gfn_to_hva_prot(vcpu->kvm, real_gfn,
+ host_addr = kvm_vcpu_gfn_to_hva_prot(vcpu, real_gfn,
&walker->pte_writable[walker->level - 1]);
if (unlikely(kvm_is_error_hva(host_addr)))
goto error;
@@ -511,11 +511,11 @@ static bool FNAME(gpte_changed)(struct kvm_vcpu *vcpu,
base_gpa = pte_gpa & ~mask;
index = (pte_gpa - base_gpa) / sizeof(pt_element_t);
- r = kvm_read_guest_atomic(vcpu->kvm, base_gpa,
+ r = kvm_vcpu_read_guest_atomic(vcpu, base_gpa,
gw->prefetch_ptes, sizeof(gw->prefetch_ptes));
curr_pte = gw->prefetch_ptes[index];
} else
- r = kvm_read_guest_atomic(vcpu->kvm, pte_gpa,
+ r = kvm_vcpu_read_guest_atomic(vcpu, pte_gpa,
&curr_pte, sizeof(curr_pte));
return r || curr_pte != gw->ptes[level - 1];
@@ -869,8 +869,8 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
if (!rmap_can_add(vcpu))
break;
- if (kvm_read_guest_atomic(vcpu->kvm, pte_gpa, &gpte,
- sizeof(pt_element_t)))
+ if (kvm_vcpu_read_guest_atomic(vcpu, pte_gpa, &gpte,
+ sizeof(pt_element_t)))
break;
FNAME(update_pte)(vcpu, sp, sptep, &gpte);
@@ -956,8 +956,8 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
pte_gpa = first_pte_gpa + i * sizeof(pt_element_t);
- if (kvm_read_guest_atomic(vcpu->kvm, pte_gpa, &gpte,
- sizeof(pt_element_t)))
+ if (kvm_vcpu_read_guest_atomic(vcpu, pte_gpa, &gpte,
+ sizeof(pt_element_t)))
return -EINVAL;
if (FNAME(prefetch_invalid_gpte)(vcpu, sp, &sp->spt[i], gpte)) {
@@ -970,7 +970,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
pte_access &= FNAME(gpte_access)(vcpu, gpte);
FNAME(protect_clean_gpte)(&pte_access, gpte);
- if (sync_mmio_spte(vcpu->kvm, &sp->spt[i], gfn, pte_access,
+ if (sync_mmio_spte(vcpu, &sp->spt[i], gfn, pte_access,
&nr_present))
continue;
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 29fbf9dfdc54..31aa2c85dc97 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -1,11 +1,12 @@
/*
* Kernel-based Virtual Machine -- Performance Monitoring Unit support
*
- * Copyright 2011 Red Hat, Inc. and/or its affiliates.
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* Authors:
* Avi Kivity <avi@redhat.com>
* Gleb Natapov <gleb@redhat.com>
+ * Wei Huang <wei@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
@@ -19,88 +20,39 @@
#include "x86.h"
#include "cpuid.h"
#include "lapic.h"
+#include "pmu.h"
+
+/* NOTE:
+ * - Each perf counter is defined as "struct kvm_pmc";
+ * - There are two types of perf counters: general purpose (gp) and fixed.
+ * gp counters are stored in gp_counters[] and fixed counters are stored
+ * in fixed_counters[] respectively. Both of them are part of "struct
+ * kvm_pmu";
+ * - pmu.c understands the difference between gp counters and fixed counters.
+ * However AMD doesn't support fixed-counters;
+ * - There are three types of index to access perf counters (PMC):
+ * 1. MSR (named msr): For example Intel has MSR_IA32_PERFCTRn and AMD
+ * has MSR_K7_PERFCTRn.
+ * 2. MSR Index (named idx): This normally is used by RDPMC instruction.
+ * For instance AMD RDPMC instruction uses 0000_0003h in ECX to access
+ * C001_0007h (MSR_K7_PERCTR3). Intel has a similar mechanism, except
+ * that it also supports fixed counters. idx can be used to as index to
+ * gp and fixed counters.
+ * 3. Global PMC Index (named pmc): pmc is an index specific to PMU
+ * code. Each pmc, stored in kvm_pmc.idx field, is unique across
+ * all perf counters (both gp and fixed). The mapping relationship
+ * between pmc and perf counters is as the following:
+ * * Intel: [0 .. INTEL_PMC_MAX_GENERIC-1] <=> gp counters
+ * [INTEL_PMC_IDX_FIXED .. INTEL_PMC_IDX_FIXED + 2] <=> fixed
+ * * AMD: [0 .. AMD64_NUM_COUNTERS-1] <=> gp counters
+ */
-static struct kvm_arch_event_perf_mapping {
- u8 eventsel;
- u8 unit_mask;
- unsigned event_type;
- bool inexact;
-} arch_events[] = {
- /* Index must match CPUID 0x0A.EBX bit vector */
- [0] = { 0x3c, 0x00, PERF_COUNT_HW_CPU_CYCLES },
- [1] = { 0xc0, 0x00, PERF_COUNT_HW_INSTRUCTIONS },
- [2] = { 0x3c, 0x01, PERF_COUNT_HW_BUS_CYCLES },
- [3] = { 0x2e, 0x4f, PERF_COUNT_HW_CACHE_REFERENCES },
- [4] = { 0x2e, 0x41, PERF_COUNT_HW_CACHE_MISSES },
- [5] = { 0xc4, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
- [6] = { 0xc5, 0x00, PERF_COUNT_HW_BRANCH_MISSES },
- [7] = { 0x00, 0x30, PERF_COUNT_HW_REF_CPU_CYCLES },
-};
-
-/* mapping between fixed pmc index and arch_events array */
-static int fixed_pmc_events[] = {1, 0, 7};
-
-static bool pmc_is_gp(struct kvm_pmc *pmc)
-{
- return pmc->type == KVM_PMC_GP;
-}
-
-static inline u64 pmc_bitmask(struct kvm_pmc *pmc)
-{
- struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu;
-
- return pmu->counter_bitmask[pmc->type];
-}
-
-static inline bool pmc_enabled(struct kvm_pmc *pmc)
-{
- struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu;
- return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
-}
-
-static inline struct kvm_pmc *get_gp_pmc(struct kvm_pmu *pmu, u32 msr,
- u32 base)
-{
- if (msr >= base && msr < base + pmu->nr_arch_gp_counters)
- return &pmu->gp_counters[msr - base];
- return NULL;
-}
-
-static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)
-{
- int base = MSR_CORE_PERF_FIXED_CTR0;
- if (msr >= base && msr < base + pmu->nr_arch_fixed_counters)
- return &pmu->fixed_counters[msr - base];
- return NULL;
-}
-
-static inline struct kvm_pmc *get_fixed_pmc_idx(struct kvm_pmu *pmu, int idx)
-{
- return get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + idx);
-}
-
-static struct kvm_pmc *global_idx_to_pmc(struct kvm_pmu *pmu, int idx)
-{
- if (idx < INTEL_PMC_IDX_FIXED)
- return get_gp_pmc(pmu, MSR_P6_EVNTSEL0 + idx, MSR_P6_EVNTSEL0);
- else
- return get_fixed_pmc_idx(pmu, idx - INTEL_PMC_IDX_FIXED);
-}
-
-void kvm_deliver_pmi(struct kvm_vcpu *vcpu)
-{
- if (vcpu->arch.apic)
- kvm_apic_local_deliver(vcpu->arch.apic, APIC_LVTPC);
-}
-
-static void trigger_pmi(struct irq_work *irq_work)
+static void kvm_pmi_trigger_fn(struct irq_work *irq_work)
{
- struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu,
- irq_work);
- struct kvm_vcpu *vcpu = container_of(pmu, struct kvm_vcpu,
- arch.pmu);
+ struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu, irq_work);
+ struct kvm_vcpu *vcpu = pmu_to_vcpu(pmu);
- kvm_deliver_pmi(vcpu);
+ kvm_pmu_deliver_pmi(vcpu);
}
static void kvm_perf_overflow(struct perf_event *perf_event,
@@ -108,63 +60,46 @@ static void kvm_perf_overflow(struct perf_event *perf_event,
struct pt_regs *regs)
{
struct kvm_pmc *pmc = perf_event->overflow_handler_context;
- struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu;
- if (!test_and_set_bit(pmc->idx, (unsigned long *)&pmu->reprogram_pmi)) {
+ struct kvm_pmu *pmu = pmc_to_pmu(pmc);
+
+ if (!test_and_set_bit(pmc->idx,
+ (unsigned long *)&pmu->reprogram_pmi)) {
__set_bit(pmc->idx, (unsigned long *)&pmu->global_status);
kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
}
}
static void kvm_perf_overflow_intr(struct perf_event *perf_event,
- struct perf_sample_data *data, struct pt_regs *regs)
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
{
struct kvm_pmc *pmc = perf_event->overflow_handler_context;
- struct kvm_pmu *pmu = &pmc->vcpu->arch.pmu;
- if (!test_and_set_bit(pmc->idx, (unsigned long *)&pmu->reprogram_pmi)) {
+ struct kvm_pmu *pmu = pmc_to_pmu(pmc);
+
+ if (!test_and_set_bit(pmc->idx,
+ (unsigned long *)&pmu->reprogram_pmi)) {
__set_bit(pmc->idx, (unsigned long *)&pmu->global_status);
kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
+
/*
* Inject PMI. If vcpu was in a guest mode during NMI PMI
* can be ejected on a guest mode re-entry. Otherwise we can't
* be sure that vcpu wasn't executing hlt instruction at the
- * time of vmexit and is not going to re-enter guest mode until,
+ * time of vmexit and is not going to re-enter guest mode until
* woken up. So we should wake it, but this is impossible from
* NMI context. Do it from irq work instead.
*/
if (!kvm_is_in_guest())
- irq_work_queue(&pmc->vcpu->arch.pmu.irq_work);
+ irq_work_queue(&pmc_to_pmu(pmc)->irq_work);
else
kvm_make_request(KVM_REQ_PMI, pmc->vcpu);
}
}
-static u64 read_pmc(struct kvm_pmc *pmc)
-{
- u64 counter, enabled, running;
-
- counter = pmc->counter;
-
- if (pmc->perf_event)
- counter += perf_event_read_value(pmc->perf_event,
- &enabled, &running);
-
- /* FIXME: Scaling needed? */
-
- return counter & pmc_bitmask(pmc);
-}
-
-static void stop_counter(struct kvm_pmc *pmc)
-{
- if (pmc->perf_event) {
- pmc->counter = read_pmc(pmc);
- perf_event_release_kernel(pmc->perf_event);
- pmc->perf_event = NULL;
- }
-}
-
-static void reprogram_counter(struct kvm_pmc *pmc, u32 type,
- unsigned config, bool exclude_user, bool exclude_kernel,
- bool intr, bool in_tx, bool in_tx_cp)
+static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type,
+ unsigned config, bool exclude_user,
+ bool exclude_kernel, bool intr,
+ bool in_tx, bool in_tx_cp)
{
struct perf_event *event;
struct perf_event_attr attr = {
@@ -177,6 +112,7 @@ static void reprogram_counter(struct kvm_pmc *pmc, u32 type,
.exclude_kernel = exclude_kernel,
.config = config,
};
+
if (in_tx)
attr.config |= HSW_IN_TX;
if (in_tx_cp)
@@ -188,33 +124,16 @@ static void reprogram_counter(struct kvm_pmc *pmc, u32 type,
intr ? kvm_perf_overflow_intr :
kvm_perf_overflow, pmc);
if (IS_ERR(event)) {
- printk_once("kvm: pmu event creation failed %ld\n",
- PTR_ERR(event));
+ printk_once("kvm_pmu: event creation failed %ld\n",
+ PTR_ERR(event));
return;
}
pmc->perf_event = event;
- clear_bit(pmc->idx, (unsigned long*)&pmc->vcpu->arch.pmu.reprogram_pmi);
-}
-
-static unsigned find_arch_event(struct kvm_pmu *pmu, u8 event_select,
- u8 unit_mask)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(arch_events); i++)
- if (arch_events[i].eventsel == event_select
- && arch_events[i].unit_mask == unit_mask
- && (pmu->available_event_types & (1 << i)))
- break;
-
- if (i == ARRAY_SIZE(arch_events))
- return PERF_COUNT_HW_MAX;
-
- return arch_events[i].event_type;
+ clear_bit(pmc->idx, (unsigned long*)&pmc_to_pmu(pmc)->reprogram_pmi);
}
-static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
+void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
{
unsigned config, type = PERF_TYPE_RAW;
u8 event_select, unit_mask;
@@ -224,21 +143,22 @@ static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
pmc->eventsel = eventsel;
- stop_counter(pmc);
+ pmc_stop_counter(pmc);
- if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE) || !pmc_enabled(pmc))
+ if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE) || !pmc_is_enabled(pmc))
return;
event_select = eventsel & ARCH_PERFMON_EVENTSEL_EVENT;
unit_mask = (eventsel & ARCH_PERFMON_EVENTSEL_UMASK) >> 8;
if (!(eventsel & (ARCH_PERFMON_EVENTSEL_EDGE |
- ARCH_PERFMON_EVENTSEL_INV |
- ARCH_PERFMON_EVENTSEL_CMASK |
- HSW_IN_TX |
- HSW_IN_TX_CHECKPOINTED))) {
- config = find_arch_event(&pmc->vcpu->arch.pmu, event_select,
- unit_mask);
+ ARCH_PERFMON_EVENTSEL_INV |
+ ARCH_PERFMON_EVENTSEL_CMASK |
+ HSW_IN_TX |
+ HSW_IN_TX_CHECKPOINTED))) {
+ config = kvm_x86_ops->pmu_ops->find_arch_event(pmc_to_pmu(pmc),
+ event_select,
+ unit_mask);
if (config != PERF_COUNT_HW_MAX)
type = PERF_TYPE_HARDWARE;
}
@@ -246,56 +166,36 @@ static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
if (type == PERF_TYPE_RAW)
config = eventsel & X86_RAW_EVENT_MASK;
- reprogram_counter(pmc, type, config,
- !(eventsel & ARCH_PERFMON_EVENTSEL_USR),
- !(eventsel & ARCH_PERFMON_EVENTSEL_OS),
- eventsel & ARCH_PERFMON_EVENTSEL_INT,
- (eventsel & HSW_IN_TX),
- (eventsel & HSW_IN_TX_CHECKPOINTED));
+ pmc_reprogram_counter(pmc, type, config,
+ !(eventsel & ARCH_PERFMON_EVENTSEL_USR),
+ !(eventsel & ARCH_PERFMON_EVENTSEL_OS),
+ eventsel & ARCH_PERFMON_EVENTSEL_INT,
+ (eventsel & HSW_IN_TX),
+ (eventsel & HSW_IN_TX_CHECKPOINTED));
}
+EXPORT_SYMBOL_GPL(reprogram_gp_counter);
-static void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 en_pmi, int idx)
+void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int idx)
{
- unsigned en = en_pmi & 0x3;
- bool pmi = en_pmi & 0x8;
+ unsigned en_field = ctrl & 0x3;
+ bool pmi = ctrl & 0x8;
- stop_counter(pmc);
+ pmc_stop_counter(pmc);
- if (!en || !pmc_enabled(pmc))
+ if (!en_field || !pmc_is_enabled(pmc))
return;
- reprogram_counter(pmc, PERF_TYPE_HARDWARE,
- arch_events[fixed_pmc_events[idx]].event_type,
- !(en & 0x2), /* exclude user */
- !(en & 0x1), /* exclude kernel */
- pmi, false, false);
+ pmc_reprogram_counter(pmc, PERF_TYPE_HARDWARE,
+ kvm_x86_ops->pmu_ops->find_fixed_event(idx),
+ !(en_field & 0x2), /* exclude user */
+ !(en_field & 0x1), /* exclude kernel */
+ pmi, false, false);
}
+EXPORT_SYMBOL_GPL(reprogram_fixed_counter);
-static inline u8 fixed_en_pmi(u64 ctrl, int idx)
+void reprogram_counter(struct kvm_pmu *pmu, int pmc_idx)
{
- return (ctrl >> (idx * 4)) & 0xf;
-}
-
-static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
-{
- int i;
-
- for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
- u8 en_pmi = fixed_en_pmi(data, i);
- struct kvm_pmc *pmc = get_fixed_pmc_idx(pmu, i);
-
- if (fixed_en_pmi(pmu->fixed_ctr_ctrl, i) == en_pmi)
- continue;
-
- reprogram_fixed_counter(pmc, en_pmi, i);
- }
-
- pmu->fixed_ctr_ctrl = data;
-}
-
-static void reprogram_idx(struct kvm_pmu *pmu, int idx)
-{
- struct kvm_pmc *pmc = global_idx_to_pmc(pmu, idx);
+ struct kvm_pmc *pmc = kvm_x86_ops->pmu_ops->pmc_idx_to_pmc(pmu, pmc_idx);
if (!pmc)
return;
@@ -303,274 +203,107 @@ static void reprogram_idx(struct kvm_pmu *pmu, int idx)
if (pmc_is_gp(pmc))
reprogram_gp_counter(pmc, pmc->eventsel);
else {
- int fidx = idx - INTEL_PMC_IDX_FIXED;
- reprogram_fixed_counter(pmc,
- fixed_en_pmi(pmu->fixed_ctr_ctrl, fidx), fidx);
+ int idx = pmc_idx - INTEL_PMC_IDX_FIXED;
+ u8 ctrl = fixed_ctrl_field(pmu->fixed_ctr_ctrl, idx);
+
+ reprogram_fixed_counter(pmc, ctrl, idx);
}
}
+EXPORT_SYMBOL_GPL(reprogram_counter);
-static void global_ctrl_changed(struct kvm_pmu *pmu, u64 data)
+void kvm_pmu_handle_event(struct kvm_vcpu *vcpu)
{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ u64 bitmask;
int bit;
- u64 diff = pmu->global_ctrl ^ data;
-
- pmu->global_ctrl = data;
-
- for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX)
- reprogram_idx(pmu, bit);
-}
-bool kvm_pmu_msr(struct kvm_vcpu *vcpu, u32 msr)
-{
- struct kvm_pmu *pmu = &vcpu->arch.pmu;
- int ret;
-
- switch (msr) {
- case MSR_CORE_PERF_FIXED_CTR_CTRL:
- case MSR_CORE_PERF_GLOBAL_STATUS:
- case MSR_CORE_PERF_GLOBAL_CTRL:
- case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
- ret = pmu->version > 1;
- break;
- default:
- ret = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)
- || get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0)
- || get_fixed_pmc(pmu, msr);
- break;
- }
- return ret;
-}
+ bitmask = pmu->reprogram_pmi;
-int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data)
-{
- struct kvm_pmu *pmu = &vcpu->arch.pmu;
- struct kvm_pmc *pmc;
+ for_each_set_bit(bit, (unsigned long *)&bitmask, X86_PMC_IDX_MAX) {
+ struct kvm_pmc *pmc = kvm_x86_ops->pmu_ops->pmc_idx_to_pmc(pmu, bit);
- switch (index) {
- case MSR_CORE_PERF_FIXED_CTR_CTRL:
- *data = pmu->fixed_ctr_ctrl;
- return 0;
- case MSR_CORE_PERF_GLOBAL_STATUS:
- *data = pmu->global_status;
- return 0;
- case MSR_CORE_PERF_GLOBAL_CTRL:
- *data = pmu->global_ctrl;
- return 0;
- case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
- *data = pmu->global_ovf_ctrl;
- return 0;
- default:
- if ((pmc = get_gp_pmc(pmu, index, MSR_IA32_PERFCTR0)) ||
- (pmc = get_fixed_pmc(pmu, index))) {
- *data = read_pmc(pmc);
- return 0;
- } else if ((pmc = get_gp_pmc(pmu, index, MSR_P6_EVNTSEL0))) {
- *data = pmc->eventsel;
- return 0;
+ if (unlikely(!pmc || !pmc->perf_event)) {
+ clear_bit(bit, (unsigned long *)&pmu->reprogram_pmi);
+ continue;
}
- }
- return 1;
-}
-int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
-{
- struct kvm_pmu *pmu = &vcpu->arch.pmu;
- struct kvm_pmc *pmc;
- u32 index = msr_info->index;
- u64 data = msr_info->data;
-
- switch (index) {
- case MSR_CORE_PERF_FIXED_CTR_CTRL:
- if (pmu->fixed_ctr_ctrl == data)
- return 0;
- if (!(data & 0xfffffffffffff444ull)) {
- reprogram_fixed_counters(pmu, data);
- return 0;
- }
- break;
- case MSR_CORE_PERF_GLOBAL_STATUS:
- if (msr_info->host_initiated) {
- pmu->global_status = data;
- return 0;
- }
- break; /* RO MSR */
- case MSR_CORE_PERF_GLOBAL_CTRL:
- if (pmu->global_ctrl == data)
- return 0;
- if (!(data & pmu->global_ctrl_mask)) {
- global_ctrl_changed(pmu, data);
- return 0;
- }
- break;
- case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
- if (!(data & (pmu->global_ctrl_mask & ~(3ull<<62)))) {
- if (!msr_info->host_initiated)
- pmu->global_status &= ~data;
- pmu->global_ovf_ctrl = data;
- return 0;
- }
- break;
- default:
- if ((pmc = get_gp_pmc(pmu, index, MSR_IA32_PERFCTR0)) ||
- (pmc = get_fixed_pmc(pmu, index))) {
- if (!msr_info->host_initiated)
- data = (s64)(s32)data;
- pmc->counter += data - read_pmc(pmc);
- return 0;
- } else if ((pmc = get_gp_pmc(pmu, index, MSR_P6_EVNTSEL0))) {
- if (data == pmc->eventsel)
- return 0;
- if (!(data & pmu->reserved_bits)) {
- reprogram_gp_counter(pmc, data);
- return 0;
- }
- }
+ reprogram_counter(pmu, bit);
}
- return 1;
}
-int kvm_pmu_check_pmc(struct kvm_vcpu *vcpu, unsigned pmc)
+/* check if idx is a valid index to access PMU */
+int kvm_pmu_is_valid_msr_idx(struct kvm_vcpu *vcpu, unsigned idx)
{
- struct kvm_pmu *pmu = &vcpu->arch.pmu;
- bool fixed = pmc & (1u << 30);
- pmc &= ~(3u << 30);
- return (!fixed && pmc >= pmu->nr_arch_gp_counters) ||
- (fixed && pmc >= pmu->nr_arch_fixed_counters);
+ return kvm_x86_ops->pmu_ops->is_valid_msr_idx(vcpu, idx);
}
-int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data)
+int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
{
- struct kvm_pmu *pmu = &vcpu->arch.pmu;
- bool fast_mode = pmc & (1u << 31);
- bool fixed = pmc & (1u << 30);
- struct kvm_pmc *counters;
- u64 ctr;
-
- pmc &= ~(3u << 30);
- if (!fixed && pmc >= pmu->nr_arch_gp_counters)
- return 1;
- if (fixed && pmc >= pmu->nr_arch_fixed_counters)
+ bool fast_mode = idx & (1u << 31);
+ struct kvm_pmc *pmc;
+ u64 ctr_val;
+
+ pmc = kvm_x86_ops->pmu_ops->msr_idx_to_pmc(vcpu, idx);
+ if (!pmc)
return 1;
- counters = fixed ? pmu->fixed_counters : pmu->gp_counters;
- ctr = read_pmc(&counters[pmc]);
+
+ ctr_val = pmc_read_counter(pmc);
if (fast_mode)
- ctr = (u32)ctr;
- *data = ctr;
+ ctr_val = (u32)ctr_val;
+ *data = ctr_val;
return 0;
}
-void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu)
+void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu)
{
- struct kvm_pmu *pmu = &vcpu->arch.pmu;
- struct kvm_cpuid_entry2 *entry;
- union cpuid10_eax eax;
- union cpuid10_edx edx;
-
- pmu->nr_arch_gp_counters = 0;
- pmu->nr_arch_fixed_counters = 0;
- pmu->counter_bitmask[KVM_PMC_GP] = 0;
- pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
- pmu->version = 0;
- pmu->reserved_bits = 0xffffffff00200000ull;
-
- entry = kvm_find_cpuid_entry(vcpu, 0xa, 0);
- if (!entry)
- return;
- eax.full = entry->eax;
- edx.full = entry->edx;
-
- pmu->version = eax.split.version_id;
- if (!pmu->version)
- return;
-
- pmu->nr_arch_gp_counters = min_t(int, eax.split.num_counters,
- INTEL_PMC_MAX_GENERIC);
- pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << eax.split.bit_width) - 1;
- pmu->available_event_types = ~entry->ebx &
- ((1ull << eax.split.mask_length) - 1);
-
- if (pmu->version == 1) {
- pmu->nr_arch_fixed_counters = 0;
- } else {
- pmu->nr_arch_fixed_counters =
- min_t(int, edx.split.num_counters_fixed,
- INTEL_PMC_MAX_FIXED);
- pmu->counter_bitmask[KVM_PMC_FIXED] =
- ((u64)1 << edx.split.bit_width_fixed) - 1;
- }
+ if (vcpu->arch.apic)
+ kvm_apic_local_deliver(vcpu->arch.apic, APIC_LVTPC);
+}
- pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) |
- (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED);
- pmu->global_ctrl_mask = ~pmu->global_ctrl;
+bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
+{
+ return kvm_x86_ops->pmu_ops->is_valid_msr(vcpu, msr);
+}
- entry = kvm_find_cpuid_entry(vcpu, 7, 0);
- if (entry &&
- (boot_cpu_has(X86_FEATURE_HLE) || boot_cpu_has(X86_FEATURE_RTM)) &&
- (entry->ebx & (X86_FEATURE_HLE|X86_FEATURE_RTM)))
- pmu->reserved_bits ^= HSW_IN_TX|HSW_IN_TX_CHECKPOINTED;
+int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
+{
+ return kvm_x86_ops->pmu_ops->get_msr(vcpu, msr, data);
}
-void kvm_pmu_init(struct kvm_vcpu *vcpu)
+int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
- int i;
- struct kvm_pmu *pmu = &vcpu->arch.pmu;
+ return kvm_x86_ops->pmu_ops->set_msr(vcpu, msr_info);
+}
- memset(pmu, 0, sizeof(*pmu));
- for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
- pmu->gp_counters[i].type = KVM_PMC_GP;
- pmu->gp_counters[i].vcpu = vcpu;
- pmu->gp_counters[i].idx = i;
- }
- for (i = 0; i < INTEL_PMC_MAX_FIXED; i++) {
- pmu->fixed_counters[i].type = KVM_PMC_FIXED;
- pmu->fixed_counters[i].vcpu = vcpu;
- pmu->fixed_counters[i].idx = i + INTEL_PMC_IDX_FIXED;
- }
- init_irq_work(&pmu->irq_work, trigger_pmi);
- kvm_pmu_cpuid_update(vcpu);
+/* refresh PMU settings. This function generally is called when underlying
+ * settings are changed (such as changes of PMU CPUID by guest VMs), which
+ * should rarely happen.
+ */
+void kvm_pmu_refresh(struct kvm_vcpu *vcpu)
+{
+ kvm_x86_ops->pmu_ops->refresh(vcpu);
}
void kvm_pmu_reset(struct kvm_vcpu *vcpu)
{
- struct kvm_pmu *pmu = &vcpu->arch.pmu;
- int i;
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
irq_work_sync(&pmu->irq_work);
- for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
- struct kvm_pmc *pmc = &pmu->gp_counters[i];
- stop_counter(pmc);
- pmc->counter = pmc->eventsel = 0;
- }
+ kvm_x86_ops->pmu_ops->reset(vcpu);
+}
- for (i = 0; i < INTEL_PMC_MAX_FIXED; i++)
- stop_counter(&pmu->fixed_counters[i]);
+void kvm_pmu_init(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
- pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status =
- pmu->global_ovf_ctrl = 0;
+ memset(pmu, 0, sizeof(*pmu));
+ kvm_x86_ops->pmu_ops->init(vcpu);
+ init_irq_work(&pmu->irq_work, kvm_pmi_trigger_fn);
+ kvm_pmu_refresh(vcpu);
}
void kvm_pmu_destroy(struct kvm_vcpu *vcpu)
{
kvm_pmu_reset(vcpu);
}
-
-void kvm_handle_pmu_event(struct kvm_vcpu *vcpu)
-{
- struct kvm_pmu *pmu = &vcpu->arch.pmu;
- u64 bitmask;
- int bit;
-
- bitmask = pmu->reprogram_pmi;
-
- for_each_set_bit(bit, (unsigned long *)&bitmask, X86_PMC_IDX_MAX) {
- struct kvm_pmc *pmc = global_idx_to_pmc(pmu, bit);
-
- if (unlikely(!pmc || !pmc->perf_event)) {
- clear_bit(bit, (unsigned long *)&pmu->reprogram_pmi);
- continue;
- }
-
- reprogram_idx(pmu, bit);
- }
-}
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
new file mode 100644
index 000000000000..f96e1f962587
--- /dev/null
+++ b/arch/x86/kvm/pmu.h
@@ -0,0 +1,118 @@
+#ifndef __KVM_X86_PMU_H
+#define __KVM_X86_PMU_H
+
+#define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu)
+#define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu))
+#define pmc_to_pmu(pmc) (&(pmc)->vcpu->arch.pmu)
+
+/* retrieve the 4 bits for EN and PMI out of IA32_FIXED_CTR_CTRL */
+#define fixed_ctrl_field(ctrl_reg, idx) (((ctrl_reg) >> ((idx)*4)) & 0xf)
+
+struct kvm_event_hw_type_mapping {
+ u8 eventsel;
+ u8 unit_mask;
+ unsigned event_type;
+};
+
+struct kvm_pmu_ops {
+ unsigned (*find_arch_event)(struct kvm_pmu *pmu, u8 event_select,
+ u8 unit_mask);
+ unsigned (*find_fixed_event)(int idx);
+ bool (*pmc_is_enabled)(struct kvm_pmc *pmc);
+ struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
+ struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, unsigned idx);
+ int (*is_valid_msr_idx)(struct kvm_vcpu *vcpu, unsigned idx);
+ bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr);
+ int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
+ int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
+ void (*refresh)(struct kvm_vcpu *vcpu);
+ void (*init)(struct kvm_vcpu *vcpu);
+ void (*reset)(struct kvm_vcpu *vcpu);
+};
+
+static inline u64 pmc_bitmask(struct kvm_pmc *pmc)
+{
+ struct kvm_pmu *pmu = pmc_to_pmu(pmc);
+
+ return pmu->counter_bitmask[pmc->type];
+}
+
+static inline u64 pmc_read_counter(struct kvm_pmc *pmc)
+{
+ u64 counter, enabled, running;
+
+ counter = pmc->counter;
+ if (pmc->perf_event)
+ counter += perf_event_read_value(pmc->perf_event,
+ &enabled, &running);
+ /* FIXME: Scaling needed? */
+ return counter & pmc_bitmask(pmc);
+}
+
+static inline void pmc_stop_counter(struct kvm_pmc *pmc)
+{
+ if (pmc->perf_event) {
+ pmc->counter = pmc_read_counter(pmc);
+ perf_event_release_kernel(pmc->perf_event);
+ pmc->perf_event = NULL;
+ }
+}
+
+static inline bool pmc_is_gp(struct kvm_pmc *pmc)
+{
+ return pmc->type == KVM_PMC_GP;
+}
+
+static inline bool pmc_is_fixed(struct kvm_pmc *pmc)
+{
+ return pmc->type == KVM_PMC_FIXED;
+}
+
+static inline bool pmc_is_enabled(struct kvm_pmc *pmc)
+{
+ return kvm_x86_ops->pmu_ops->pmc_is_enabled(pmc);
+}
+
+/* returns general purpose PMC with the specified MSR. Note that it can be
+ * used for both PERFCTRn and EVNTSELn; that is why it accepts base as a
+ * paramenter to tell them apart.
+ */
+static inline struct kvm_pmc *get_gp_pmc(struct kvm_pmu *pmu, u32 msr,
+ u32 base)
+{
+ if (msr >= base && msr < base + pmu->nr_arch_gp_counters)
+ return &pmu->gp_counters[msr - base];
+
+ return NULL;
+}
+
+/* returns fixed PMC with the specified MSR */
+static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)
+{
+ int base = MSR_CORE_PERF_FIXED_CTR0;
+
+ if (msr >= base && msr < base + pmu->nr_arch_fixed_counters)
+ return &pmu->fixed_counters[msr - base];
+
+ return NULL;
+}
+
+void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel);
+void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int fixed_idx);
+void reprogram_counter(struct kvm_pmu *pmu, int pmc_idx);
+
+void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu);
+void kvm_pmu_handle_event(struct kvm_vcpu *vcpu);
+int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);
+int kvm_pmu_is_valid_msr_idx(struct kvm_vcpu *vcpu, unsigned idx);
+bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr);
+int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
+int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
+void kvm_pmu_refresh(struct kvm_vcpu *vcpu);
+void kvm_pmu_reset(struct kvm_vcpu *vcpu);
+void kvm_pmu_init(struct kvm_vcpu *vcpu);
+void kvm_pmu_destroy(struct kvm_vcpu *vcpu);
+
+extern struct kvm_pmu_ops intel_pmu_ops;
+extern struct kvm_pmu_ops amd_pmu_ops;
+#endif /* __KVM_X86_PMU_H */
diff --git a/arch/x86/kvm/pmu_amd.c b/arch/x86/kvm/pmu_amd.c
new file mode 100644
index 000000000000..886aa25a7131
--- /dev/null
+++ b/arch/x86/kvm/pmu_amd.c
@@ -0,0 +1,207 @@
+/*
+ * KVM PMU support for AMD
+ *
+ * Copyright 2015, Red Hat, Inc. and/or its affiliates.
+ *
+ * Author:
+ * Wei Huang <wei@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Implementation is based on pmu_intel.c file
+ */
+#include <linux/types.h>
+#include <linux/kvm_host.h>
+#include <linux/perf_event.h>
+#include "x86.h"
+#include "cpuid.h"
+#include "lapic.h"
+#include "pmu.h"
+
+/* duplicated from amd_perfmon_event_map, K7 and above should work. */
+static struct kvm_event_hw_type_mapping amd_event_mapping[] = {
+ [0] = { 0x76, 0x00, PERF_COUNT_HW_CPU_CYCLES },
+ [1] = { 0xc0, 0x00, PERF_COUNT_HW_INSTRUCTIONS },
+ [2] = { 0x80, 0x00, PERF_COUNT_HW_CACHE_REFERENCES },
+ [3] = { 0x81, 0x00, PERF_COUNT_HW_CACHE_MISSES },
+ [4] = { 0xc2, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
+ [5] = { 0xc3, 0x00, PERF_COUNT_HW_BRANCH_MISSES },
+ [6] = { 0xd0, 0x00, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
+ [7] = { 0xd1, 0x00, PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
+};
+
+static unsigned amd_find_arch_event(struct kvm_pmu *pmu,
+ u8 event_select,
+ u8 unit_mask)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(amd_event_mapping); i++)
+ if (amd_event_mapping[i].eventsel == event_select
+ && amd_event_mapping[i].unit_mask == unit_mask)
+ break;
+
+ if (i == ARRAY_SIZE(amd_event_mapping))
+ return PERF_COUNT_HW_MAX;
+
+ return amd_event_mapping[i].event_type;
+}
+
+/* return PERF_COUNT_HW_MAX as AMD doesn't have fixed events */
+static unsigned amd_find_fixed_event(int idx)
+{
+ return PERF_COUNT_HW_MAX;
+}
+
+/* check if a PMC is enabled by comparing it against global_ctrl bits. Because
+ * AMD CPU doesn't have global_ctrl MSR, all PMCs are enabled (return TRUE).
+ */
+static bool amd_pmc_is_enabled(struct kvm_pmc *pmc)
+{
+ return true;
+}
+
+static struct kvm_pmc *amd_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx)
+{
+ return get_gp_pmc(pmu, MSR_K7_EVNTSEL0 + pmc_idx, MSR_K7_EVNTSEL0);
+}
+
+/* returns 0 if idx's corresponding MSR exists; otherwise returns 1. */
+static int amd_is_valid_msr_idx(struct kvm_vcpu *vcpu, unsigned idx)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+ idx &= ~(3u << 30);
+
+ return (idx >= pmu->nr_arch_gp_counters);
+}
+
+/* idx is the ECX register of RDPMC instruction */
+static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, unsigned idx)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ struct kvm_pmc *counters;
+
+ idx &= ~(3u << 30);
+ if (idx >= pmu->nr_arch_gp_counters)
+ return NULL;
+ counters = pmu->gp_counters;
+
+ return &counters[idx];
+}
+
+static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ int ret = false;
+
+ ret = get_gp_pmc(pmu, msr, MSR_K7_PERFCTR0) ||
+ get_gp_pmc(pmu, msr, MSR_K7_EVNTSEL0);
+
+ return ret;
+}
+
+static int amd_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ struct kvm_pmc *pmc;
+
+ /* MSR_K7_PERFCTRn */
+ pmc = get_gp_pmc(pmu, msr, MSR_K7_PERFCTR0);
+ if (pmc) {
+ *data = pmc_read_counter(pmc);
+ return 0;
+ }
+ /* MSR_K7_EVNTSELn */
+ pmc = get_gp_pmc(pmu, msr, MSR_K7_EVNTSEL0);
+ if (pmc) {
+ *data = pmc->eventsel;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ struct kvm_pmc *pmc;
+ u32 msr = msr_info->index;
+ u64 data = msr_info->data;
+
+ /* MSR_K7_PERFCTRn */
+ pmc = get_gp_pmc(pmu, msr, MSR_K7_PERFCTR0);
+ if (pmc) {
+ if (!msr_info->host_initiated)
+ data = (s64)data;
+ pmc->counter += data - pmc_read_counter(pmc);
+ return 0;
+ }
+ /* MSR_K7_EVNTSELn */
+ pmc = get_gp_pmc(pmu, msr, MSR_K7_EVNTSEL0);
+ if (pmc) {
+ if (data == pmc->eventsel)
+ return 0;
+ if (!(data & pmu->reserved_bits)) {
+ reprogram_gp_counter(pmc, data);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void amd_pmu_refresh(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+ pmu->nr_arch_gp_counters = AMD64_NUM_COUNTERS;
+ pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << 48) - 1;
+ pmu->reserved_bits = 0xffffffff00200000ull;
+ /* not applicable to AMD; but clean them to prevent any fall out */
+ pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
+ pmu->nr_arch_fixed_counters = 0;
+ pmu->version = 0;
+ pmu->global_status = 0;
+}
+
+static void amd_pmu_init(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ int i;
+
+ for (i = 0; i < AMD64_NUM_COUNTERS ; i++) {
+ pmu->gp_counters[i].type = KVM_PMC_GP;
+ pmu->gp_counters[i].vcpu = vcpu;
+ pmu->gp_counters[i].idx = i;
+ }
+}
+
+static void amd_pmu_reset(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ int i;
+
+ for (i = 0; i < AMD64_NUM_COUNTERS; i++) {
+ struct kvm_pmc *pmc = &pmu->gp_counters[i];
+
+ pmc_stop_counter(pmc);
+ pmc->counter = pmc->eventsel = 0;
+ }
+}
+
+struct kvm_pmu_ops amd_pmu_ops = {
+ .find_arch_event = amd_find_arch_event,
+ .find_fixed_event = amd_find_fixed_event,
+ .pmc_is_enabled = amd_pmc_is_enabled,
+ .pmc_idx_to_pmc = amd_pmc_idx_to_pmc,
+ .msr_idx_to_pmc = amd_msr_idx_to_pmc,
+ .is_valid_msr_idx = amd_is_valid_msr_idx,
+ .is_valid_msr = amd_is_valid_msr,
+ .get_msr = amd_pmu_get_msr,
+ .set_msr = amd_pmu_set_msr,
+ .refresh = amd_pmu_refresh,
+ .init = amd_pmu_init,
+ .reset = amd_pmu_reset,
+};
diff --git a/arch/x86/kvm/pmu_intel.c b/arch/x86/kvm/pmu_intel.c
new file mode 100644
index 000000000000..ab38af4f4947
--- /dev/null
+++ b/arch/x86/kvm/pmu_intel.c
@@ -0,0 +1,358 @@
+/*
+ * KVM PMU support for Intel CPUs
+ *
+ * Copyright 2011 Red Hat, Inc. and/or its affiliates.
+ *
+ * Authors:
+ * Avi Kivity <avi@redhat.com>
+ * Gleb Natapov <gleb@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kvm_host.h>
+#include <linux/perf_event.h>
+#include <asm/perf_event.h>
+#include "x86.h"
+#include "cpuid.h"
+#include "lapic.h"
+#include "pmu.h"
+
+static struct kvm_event_hw_type_mapping intel_arch_events[] = {
+ /* Index must match CPUID 0x0A.EBX bit vector */
+ [0] = { 0x3c, 0x00, PERF_COUNT_HW_CPU_CYCLES },
+ [1] = { 0xc0, 0x00, PERF_COUNT_HW_INSTRUCTIONS },
+ [2] = { 0x3c, 0x01, PERF_COUNT_HW_BUS_CYCLES },
+ [3] = { 0x2e, 0x4f, PERF_COUNT_HW_CACHE_REFERENCES },
+ [4] = { 0x2e, 0x41, PERF_COUNT_HW_CACHE_MISSES },
+ [5] = { 0xc4, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
+ [6] = { 0xc5, 0x00, PERF_COUNT_HW_BRANCH_MISSES },
+ [7] = { 0x00, 0x30, PERF_COUNT_HW_REF_CPU_CYCLES },
+};
+
+/* mapping between fixed pmc index and intel_arch_events array */
+static int fixed_pmc_events[] = {1, 0, 7};
+
+static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
+{
+ int i;
+
+ for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
+ u8 new_ctrl = fixed_ctrl_field(data, i);
+ u8 old_ctrl = fixed_ctrl_field(pmu->fixed_ctr_ctrl, i);
+ struct kvm_pmc *pmc;
+
+ pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i);
+
+ if (old_ctrl == new_ctrl)
+ continue;
+
+ reprogram_fixed_counter(pmc, new_ctrl, i);
+ }
+
+ pmu->fixed_ctr_ctrl = data;
+}
+
+/* function is called when global control register has been updated. */
+static void global_ctrl_changed(struct kvm_pmu *pmu, u64 data)
+{
+ int bit;
+ u64 diff = pmu->global_ctrl ^ data;
+
+ pmu->global_ctrl = data;
+
+ for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX)
+ reprogram_counter(pmu, bit);
+}
+
+static unsigned intel_find_arch_event(struct kvm_pmu *pmu,
+ u8 event_select,
+ u8 unit_mask)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(intel_arch_events); i++)
+ if (intel_arch_events[i].eventsel == event_select
+ && intel_arch_events[i].unit_mask == unit_mask
+ && (pmu->available_event_types & (1 << i)))
+ break;
+
+ if (i == ARRAY_SIZE(intel_arch_events))
+ return PERF_COUNT_HW_MAX;
+
+ return intel_arch_events[i].event_type;
+}
+
+static unsigned intel_find_fixed_event(int idx)
+{
+ if (idx >= ARRAY_SIZE(fixed_pmc_events))
+ return PERF_COUNT_HW_MAX;
+
+ return intel_arch_events[fixed_pmc_events[idx]].event_type;
+}
+
+/* check if a PMC is enabled by comparising it with globl_ctrl bits. */
+static bool intel_pmc_is_enabled(struct kvm_pmc *pmc)
+{
+ struct kvm_pmu *pmu = pmc_to_pmu(pmc);
+
+ return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
+}
+
+static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx)
+{
+ if (pmc_idx < INTEL_PMC_IDX_FIXED)
+ return get_gp_pmc(pmu, MSR_P6_EVNTSEL0 + pmc_idx,
+ MSR_P6_EVNTSEL0);
+ else {
+ u32 idx = pmc_idx - INTEL_PMC_IDX_FIXED;
+
+ return get_fixed_pmc(pmu, idx + MSR_CORE_PERF_FIXED_CTR0);
+ }
+}
+
+/* returns 0 if idx's corresponding MSR exists; otherwise returns 1. */
+static int intel_is_valid_msr_idx(struct kvm_vcpu *vcpu, unsigned idx)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ bool fixed = idx & (1u << 30);
+
+ idx &= ~(3u << 30);
+
+ return (!fixed && idx >= pmu->nr_arch_gp_counters) ||
+ (fixed && idx >= pmu->nr_arch_fixed_counters);
+}
+
+static struct kvm_pmc *intel_msr_idx_to_pmc(struct kvm_vcpu *vcpu,
+ unsigned idx)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ bool fixed = idx & (1u << 30);
+ struct kvm_pmc *counters;
+
+ idx &= ~(3u << 30);
+ if (!fixed && idx >= pmu->nr_arch_gp_counters)
+ return NULL;
+ if (fixed && idx >= pmu->nr_arch_fixed_counters)
+ return NULL;
+ counters = fixed ? pmu->fixed_counters : pmu->gp_counters;
+
+ return &counters[idx];
+}
+
+static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ int ret;
+
+ switch (msr) {
+ case MSR_CORE_PERF_FIXED_CTR_CTRL:
+ case MSR_CORE_PERF_GLOBAL_STATUS:
+ case MSR_CORE_PERF_GLOBAL_CTRL:
+ case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ ret = pmu->version > 1;
+ break;
+ default:
+ ret = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0) ||
+ get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0) ||
+ get_fixed_pmc(pmu, msr);
+ break;
+ }
+
+ return ret;
+}
+
+static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ struct kvm_pmc *pmc;
+
+ switch (msr) {
+ case MSR_CORE_PERF_FIXED_CTR_CTRL:
+ *data = pmu->fixed_ctr_ctrl;
+ return 0;
+ case MSR_CORE_PERF_GLOBAL_STATUS:
+ *data = pmu->global_status;
+ return 0;
+ case MSR_CORE_PERF_GLOBAL_CTRL:
+ *data = pmu->global_ctrl;
+ return 0;
+ case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ *data = pmu->global_ovf_ctrl;
+ return 0;
+ default:
+ if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) ||
+ (pmc = get_fixed_pmc(pmu, msr))) {
+ *data = pmc_read_counter(pmc);
+ return 0;
+ } else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
+ *data = pmc->eventsel;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ struct kvm_pmc *pmc;
+ u32 msr = msr_info->index;
+ u64 data = msr_info->data;
+
+ switch (msr) {
+ case MSR_CORE_PERF_FIXED_CTR_CTRL:
+ if (pmu->fixed_ctr_ctrl == data)
+ return 0;
+ if (!(data & 0xfffffffffffff444ull)) {
+ reprogram_fixed_counters(pmu, data);
+ return 0;
+ }
+ break;
+ case MSR_CORE_PERF_GLOBAL_STATUS:
+ if (msr_info->host_initiated) {
+ pmu->global_status = data;
+ return 0;
+ }
+ break; /* RO MSR */
+ case MSR_CORE_PERF_GLOBAL_CTRL:
+ if (pmu->global_ctrl == data)
+ return 0;
+ if (!(data & pmu->global_ctrl_mask)) {
+ global_ctrl_changed(pmu, data);
+ return 0;
+ }
+ break;
+ case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ if (!(data & (pmu->global_ctrl_mask & ~(3ull<<62)))) {
+ if (!msr_info->host_initiated)
+ pmu->global_status &= ~data;
+ pmu->global_ovf_ctrl = data;
+ return 0;
+ }
+ break;
+ default:
+ if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) ||
+ (pmc = get_fixed_pmc(pmu, msr))) {
+ if (!msr_info->host_initiated)
+ data = (s64)(s32)data;
+ pmc->counter += data - pmc_read_counter(pmc);
+ return 0;
+ } else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
+ if (data == pmc->eventsel)
+ return 0;
+ if (!(data & pmu->reserved_bits)) {
+ reprogram_gp_counter(pmc, data);
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ struct kvm_cpuid_entry2 *entry;
+ union cpuid10_eax eax;
+ union cpuid10_edx edx;
+
+ pmu->nr_arch_gp_counters = 0;
+ pmu->nr_arch_fixed_counters = 0;
+ pmu->counter_bitmask[KVM_PMC_GP] = 0;
+ pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
+ pmu->version = 0;
+ pmu->reserved_bits = 0xffffffff00200000ull;
+
+ entry = kvm_find_cpuid_entry(vcpu, 0xa, 0);
+ if (!entry)
+ return;
+ eax.full = entry->eax;
+ edx.full = entry->edx;
+
+ pmu->version = eax.split.version_id;
+ if (!pmu->version)
+ return;
+
+ pmu->nr_arch_gp_counters = min_t(int, eax.split.num_counters,
+ INTEL_PMC_MAX_GENERIC);
+ pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << eax.split.bit_width) - 1;
+ pmu->available_event_types = ~entry->ebx &
+ ((1ull << eax.split.mask_length) - 1);
+
+ if (pmu->version == 1) {
+ pmu->nr_arch_fixed_counters = 0;
+ } else {
+ pmu->nr_arch_fixed_counters =
+ min_t(int, edx.split.num_counters_fixed,
+ INTEL_PMC_MAX_FIXED);
+ pmu->counter_bitmask[KVM_PMC_FIXED] =
+ ((u64)1 << edx.split.bit_width_fixed) - 1;
+ }
+
+ pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) |
+ (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED);
+ pmu->global_ctrl_mask = ~pmu->global_ctrl;
+
+ entry = kvm_find_cpuid_entry(vcpu, 7, 0);
+ if (entry &&
+ (boot_cpu_has(X86_FEATURE_HLE) || boot_cpu_has(X86_FEATURE_RTM)) &&
+ (entry->ebx & (X86_FEATURE_HLE|X86_FEATURE_RTM)))
+ pmu->reserved_bits ^= HSW_IN_TX|HSW_IN_TX_CHECKPOINTED;
+}
+
+static void intel_pmu_init(struct kvm_vcpu *vcpu)
+{
+ int i;
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+
+ for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
+ pmu->gp_counters[i].type = KVM_PMC_GP;
+ pmu->gp_counters[i].vcpu = vcpu;
+ pmu->gp_counters[i].idx = i;
+ }
+
+ for (i = 0; i < INTEL_PMC_MAX_FIXED; i++) {
+ pmu->fixed_counters[i].type = KVM_PMC_FIXED;
+ pmu->fixed_counters[i].vcpu = vcpu;
+ pmu->fixed_counters[i].idx = i + INTEL_PMC_IDX_FIXED;
+ }
+}
+
+static void intel_pmu_reset(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ int i;
+
+ for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
+ struct kvm_pmc *pmc = &pmu->gp_counters[i];
+
+ pmc_stop_counter(pmc);
+ pmc->counter = pmc->eventsel = 0;
+ }
+
+ for (i = 0; i < INTEL_PMC_MAX_FIXED; i++)
+ pmc_stop_counter(&pmu->fixed_counters[i]);
+
+ pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status =
+ pmu->global_ovf_ctrl = 0;
+}
+
+struct kvm_pmu_ops intel_pmu_ops = {
+ .find_arch_event = intel_find_arch_event,
+ .find_fixed_event = intel_find_fixed_event,
+ .pmc_is_enabled = intel_pmc_is_enabled,
+ .pmc_idx_to_pmc = intel_pmc_idx_to_pmc,
+ .msr_idx_to_pmc = intel_msr_idx_to_pmc,
+ .is_valid_msr_idx = intel_is_valid_msr_idx,
+ .is_valid_msr = intel_is_valid_msr,
+ .get_msr = intel_pmu_get_msr,
+ .set_msr = intel_pmu_set_msr,
+ .refresh = intel_pmu_refresh,
+ .init = intel_pmu_init,
+ .reset = intel_pmu_reset,
+};
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 9afa233b5482..602b974a60a6 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -21,6 +21,7 @@
#include "kvm_cache_regs.h"
#include "x86.h"
#include "cpuid.h"
+#include "pmu.h"
#include <linux/module.h>
#include <linux/mod_devicetable.h>
@@ -28,7 +29,7 @@
#include <linux/vmalloc.h>
#include <linux/highmem.h>
#include <linux/sched.h>
-#include <linux/ftrace_event.h>
+#include <linux/trace_events.h>
#include <linux/slab.h>
#include <asm/perf_event.h>
@@ -511,8 +512,10 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
- if (svm->vmcb->control.next_rip != 0)
+ if (svm->vmcb->control.next_rip != 0) {
+ WARN_ON(!static_cpu_has(X86_FEATURE_NRIPS));
svm->next_rip = svm->vmcb->control.next_rip;
+ }
if (!svm->next_rip) {
if (emulate_instruction(vcpu, EMULTYPE_SKIP) !=
@@ -1082,7 +1085,7 @@ static u64 svm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
return target_tsc - tsc;
}
-static void init_vmcb(struct vcpu_svm *svm)
+static void init_vmcb(struct vcpu_svm *svm, bool init_event)
{
struct vmcb_control_area *control = &svm->vmcb->control;
struct vmcb_save_area *save = &svm->vmcb->save;
@@ -1153,17 +1156,17 @@ static void init_vmcb(struct vcpu_svm *svm)
init_sys_seg(&save->ldtr, SEG_TYPE_LDT);
init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16);
- svm_set_efer(&svm->vcpu, 0);
+ if (!init_event)
+ svm_set_efer(&svm->vcpu, 0);
save->dr6 = 0xffff0ff0;
kvm_set_rflags(&svm->vcpu, 2);
save->rip = 0x0000fff0;
svm->vcpu.arch.regs[VCPU_REGS_RIP] = save->rip;
/*
- * This is the guest-visible cr0 value.
* svm_set_cr0() sets PG and WP and clears NW and CD on save->cr0.
+ * It also updates the guest-visible cr0 value.
*/
- svm->vcpu.arch.cr0 = 0;
(void)kvm_set_cr0(&svm->vcpu, X86_CR0_NW | X86_CR0_CD | X86_CR0_ET);
save->cr4 = X86_CR4_PAE;
@@ -1176,7 +1179,7 @@ static void init_vmcb(struct vcpu_svm *svm)
clr_exception_intercept(svm, PF_VECTOR);
clr_cr_intercept(svm, INTERCEPT_CR3_READ);
clr_cr_intercept(svm, INTERCEPT_CR3_WRITE);
- save->g_pat = 0x0007040600070406ULL;
+ save->g_pat = svm->vcpu.arch.pat;
save->cr3 = 0;
save->cr4 = 0;
}
@@ -1195,13 +1198,19 @@ static void init_vmcb(struct vcpu_svm *svm)
enable_gif(svm);
}
-static void svm_vcpu_reset(struct kvm_vcpu *vcpu)
+static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
{
struct vcpu_svm *svm = to_svm(vcpu);
u32 dummy;
u32 eax = 1;
- init_vmcb(svm);
+ if (!init_event) {
+ svm->vcpu.arch.apic_base = APIC_DEFAULT_PHYS_BASE |
+ MSR_IA32_APICBASE_ENABLE;
+ if (kvm_vcpu_is_reset_bsp(&svm->vcpu))
+ svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP;
+ }
+ init_vmcb(svm, init_event);
kvm_cpuid(vcpu, &eax, &dummy, &dummy, &dummy);
kvm_register_write(vcpu, VCPU_REGS_RDX, eax);
@@ -1257,12 +1266,7 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
clear_page(svm->vmcb);
svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
svm->asid_generation = 0;
- init_vmcb(svm);
-
- svm->vcpu.arch.apic_base = APIC_DEFAULT_PHYS_BASE |
- MSR_IA32_APICBASE_ENABLE;
- if (kvm_vcpu_is_reset_bsp(&svm->vcpu))
- svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP;
+ init_vmcb(svm, false);
svm_init_osvw(&svm->vcpu);
@@ -1575,7 +1579,8 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
* does not do it - this results in some delay at
* reboot
*/
- cr0 &= ~(X86_CR0_CD | X86_CR0_NW);
+ if (!(vcpu->kvm->arch.disabled_quirks & KVM_QUIRK_CD_NW_CLEARED))
+ cr0 &= ~(X86_CR0_CD | X86_CR0_NW);
svm->vmcb->save.cr0 = cr0;
mark_dirty(svm->vmcb, VMCB_CR);
update_cr0_intercept(svm);
@@ -1883,7 +1888,7 @@ static int shutdown_interception(struct vcpu_svm *svm)
* so reinitialize it.
*/
clear_page(svm->vmcb);
- init_vmcb(svm);
+ init_vmcb(svm, false);
kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
return 0;
@@ -1953,8 +1958,8 @@ static u64 nested_svm_get_tdp_pdptr(struct kvm_vcpu *vcpu, int index)
u64 pdpte;
int ret;
- ret = kvm_read_guest_page(vcpu->kvm, gpa_to_gfn(cr3), &pdpte,
- offset_in_page(cr3) + index * 8, 8);
+ ret = kvm_vcpu_read_guest_page(vcpu, gpa_to_gfn(cr3), &pdpte,
+ offset_in_page(cr3) + index * 8, 8);
if (ret)
return 0;
return pdpte;
@@ -2112,7 +2117,7 @@ static void *nested_svm_map(struct vcpu_svm *svm, u64 gpa, struct page **_page)
might_sleep();
- page = gfn_to_page(svm->vcpu.kvm, gpa >> PAGE_SHIFT);
+ page = kvm_vcpu_gfn_to_page(&svm->vcpu, gpa >> PAGE_SHIFT);
if (is_error_page(page))
goto error;
@@ -2151,7 +2156,7 @@ static int nested_svm_intercept_ioio(struct vcpu_svm *svm)
mask = (0xf >> (4 - size)) << start_bit;
val = 0;
- if (kvm_read_guest(svm->vcpu.kvm, gpa, &val, iopm_len))
+ if (kvm_vcpu_read_guest(&svm->vcpu, gpa, &val, iopm_len))
return NESTED_EXIT_DONE;
return (val & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
@@ -2176,7 +2181,7 @@ static int nested_svm_exit_handled_msr(struct vcpu_svm *svm)
/* Offset is in 32 bit units but need in 8 bit units */
offset *= 4;
- if (kvm_read_guest(svm->vcpu.kvm, svm->nested.vmcb_msrpm + offset, &value, 4))
+ if (kvm_vcpu_read_guest(&svm->vcpu, svm->nested.vmcb_msrpm + offset, &value, 4))
return NESTED_EXIT_DONE;
return (value & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
@@ -2447,7 +2452,7 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
p = msrpm_offsets[i];
offset = svm->nested.vmcb_msrpm + (p * 4);
- if (kvm_read_guest(svm->vcpu.kvm, offset, &value, 4))
+ if (kvm_vcpu_read_guest(&svm->vcpu, offset, &value, 4))
return false;
svm->nested.msrpm[p] = svm->msrpm[p] | value;
@@ -3067,42 +3072,42 @@ static u64 svm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
svm_scale_tsc(vcpu, host_tsc);
}
-static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
+static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
struct vcpu_svm *svm = to_svm(vcpu);
- switch (ecx) {
+ switch (msr_info->index) {
case MSR_IA32_TSC: {
- *data = svm->vmcb->control.tsc_offset +
+ msr_info->data = svm->vmcb->control.tsc_offset +
svm_scale_tsc(vcpu, native_read_tsc());
break;
}
case MSR_STAR:
- *data = svm->vmcb->save.star;
+ msr_info->data = svm->vmcb->save.star;
break;
#ifdef CONFIG_X86_64
case MSR_LSTAR:
- *data = svm->vmcb->save.lstar;
+ msr_info->data = svm->vmcb->save.lstar;
break;
case MSR_CSTAR:
- *data = svm->vmcb->save.cstar;
+ msr_info->data = svm->vmcb->save.cstar;
break;
case MSR_KERNEL_GS_BASE:
- *data = svm->vmcb->save.kernel_gs_base;
+ msr_info->data = svm->vmcb->save.kernel_gs_base;
break;
case MSR_SYSCALL_MASK:
- *data = svm->vmcb->save.sfmask;
+ msr_info->data = svm->vmcb->save.sfmask;
break;
#endif
case MSR_IA32_SYSENTER_CS:
- *data = svm->vmcb->save.sysenter_cs;
+ msr_info->data = svm->vmcb->save.sysenter_cs;
break;
case MSR_IA32_SYSENTER_EIP:
- *data = svm->sysenter_eip;
+ msr_info->data = svm->sysenter_eip;
break;
case MSR_IA32_SYSENTER_ESP:
- *data = svm->sysenter_esp;
+ msr_info->data = svm->sysenter_esp;
break;
/*
* Nobody will change the following 5 values in the VMCB so we can
@@ -3110,31 +3115,31 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
* implemented.
*/
case MSR_IA32_DEBUGCTLMSR:
- *data = svm->vmcb->save.dbgctl;
+ msr_info->data = svm->vmcb->save.dbgctl;
break;
case MSR_IA32_LASTBRANCHFROMIP:
- *data = svm->vmcb->save.br_from;
+ msr_info->data = svm->vmcb->save.br_from;
break;
case MSR_IA32_LASTBRANCHTOIP:
- *data = svm->vmcb->save.br_to;
+ msr_info->data = svm->vmcb->save.br_to;
break;
case MSR_IA32_LASTINTFROMIP:
- *data = svm->vmcb->save.last_excp_from;
+ msr_info->data = svm->vmcb->save.last_excp_from;
break;
case MSR_IA32_LASTINTTOIP:
- *data = svm->vmcb->save.last_excp_to;
+ msr_info->data = svm->vmcb->save.last_excp_to;
break;
case MSR_VM_HSAVE_PA:
- *data = svm->nested.hsave_msr;
+ msr_info->data = svm->nested.hsave_msr;
break;
case MSR_VM_CR:
- *data = svm->nested.vm_cr_msr;
+ msr_info->data = svm->nested.vm_cr_msr;
break;
case MSR_IA32_UCODE_REV:
- *data = 0x01000065;
+ msr_info->data = 0x01000065;
break;
default:
- return kvm_get_msr_common(vcpu, ecx, data);
+ return kvm_get_msr_common(vcpu, msr_info);
}
return 0;
}
@@ -3142,16 +3147,20 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
static int rdmsr_interception(struct vcpu_svm *svm)
{
u32 ecx = kvm_register_read(&svm->vcpu, VCPU_REGS_RCX);
- u64 data;
+ struct msr_data msr_info;
- if (svm_get_msr(&svm->vcpu, ecx, &data)) {
+ msr_info.index = ecx;
+ msr_info.host_initiated = false;
+ if (svm_get_msr(&svm->vcpu, &msr_info)) {
trace_kvm_msr_read_ex(ecx);
kvm_inject_gp(&svm->vcpu, 0);
} else {
- trace_kvm_msr_read(ecx, data);
+ trace_kvm_msr_read(ecx, msr_info.data);
- kvm_register_write(&svm->vcpu, VCPU_REGS_RAX, data & 0xffffffff);
- kvm_register_write(&svm->vcpu, VCPU_REGS_RDX, data >> 32);
+ kvm_register_write(&svm->vcpu, VCPU_REGS_RAX,
+ msr_info.data & 0xffffffff);
+ kvm_register_write(&svm->vcpu, VCPU_REGS_RDX,
+ msr_info.data >> 32);
svm->next_rip = kvm_rip_read(&svm->vcpu) + 2;
skip_emulated_instruction(&svm->vcpu);
}
@@ -3388,6 +3397,7 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
[SVM_EXIT_MWAIT] = mwait_interception,
[SVM_EXIT_XSETBV] = xsetbv_interception,
[SVM_EXIT_NPF] = pf_interception,
+ [SVM_EXIT_RSM] = emulate_on_interception,
};
static void dump_vmcb(struct kvm_vcpu *vcpu)
@@ -4073,6 +4083,11 @@ static bool svm_cpu_has_accelerated_tpr(void)
return false;
}
+static bool svm_has_high_real_mode_segbase(void)
+{
+ return true;
+}
+
static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
{
return 0;
@@ -4317,7 +4332,9 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
break;
}
- vmcb->control.next_rip = info->next_rip;
+ /* TODO: Advertise NRIPS to guest hypervisor unconditionally */
+ if (static_cpu_has(X86_FEATURE_NRIPS))
+ vmcb->control.next_rip = info->next_rip;
vmcb->control.exit_code = icpt_info.exit_code;
vmexit = nested_svm_exit_handled(svm);
@@ -4346,6 +4363,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.hardware_enable = svm_hardware_enable,
.hardware_disable = svm_hardware_disable,
.cpu_has_accelerated_tpr = svm_cpu_has_accelerated_tpr,
+ .cpu_has_high_real_mode_segbase = svm_has_high_real_mode_segbase,
.vcpu_create = svm_create_vcpu,
.vcpu_free = svm_free_vcpu,
@@ -4440,6 +4458,8 @@ static struct kvm_x86_ops svm_x86_ops = {
.handle_external_intr = svm_handle_external_intr,
.sched_in = svm_sched_in,
+
+ .pmu_ops = &amd_pmu_ops,
};
static int __init svm_init(void)
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
index 7c7bc8bef21f..4eae7c35ddf5 100644
--- a/arch/x86/kvm/trace.h
+++ b/arch/x86/kvm/trace.h
@@ -952,6 +952,28 @@ TRACE_EVENT(kvm_wait_lapic_expire,
__entry->delta < 0 ? "early" : "late")
);
+TRACE_EVENT(kvm_enter_smm,
+ TP_PROTO(unsigned int vcpu_id, u64 smbase, bool entering),
+ TP_ARGS(vcpu_id, smbase, entering),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, vcpu_id )
+ __field( u64, smbase )
+ __field( bool, entering )
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->smbase = smbase;
+ __entry->entering = entering;
+ ),
+
+ TP_printk("vcpu %u: %s SMM, smbase 0x%llx",
+ __entry->vcpu_id,
+ __entry->entering ? "entering" : "leaving",
+ __entry->smbase)
+);
+
#endif /* _TRACE_KVM_H */
#undef TRACE_INCLUDE_PATH
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 2d73807f0d31..e856dd566f4c 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -28,7 +28,7 @@
#include <linux/sched.h>
#include <linux/moduleparam.h>
#include <linux/mod_devicetable.h>
-#include <linux/ftrace_event.h>
+#include <linux/trace_events.h>
#include <linux/slab.h>
#include <linux/tboot.h>
#include <linux/hrtimer.h>
@@ -40,14 +40,14 @@
#include <asm/vmx.h>
#include <asm/virtext.h>
#include <asm/mce.h>
-#include <asm/i387.h>
-#include <asm/xcr.h>
+#include <asm/fpu/internal.h>
#include <asm/perf_event.h>
#include <asm/debugreg.h>
#include <asm/kexec.h>
#include <asm/apic.h>
#include "trace.h"
+#include "pmu.h"
#define __ex(x) __kvm_handle_fault_on_reboot(x)
#define __ex_clear(x, reg) \
@@ -786,7 +786,7 @@ static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
static struct page *nested_get_page(struct kvm_vcpu *vcpu, gpa_t addr)
{
- struct page *page = gfn_to_page(vcpu->kvm, addr >> PAGE_SHIFT);
+ struct page *page = kvm_vcpu_gfn_to_page(vcpu, addr >> PAGE_SHIFT);
if (is_error_page(page))
return NULL;
@@ -1883,7 +1883,7 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
* If the FPU is not active (through the host task or
* the guest vcpu), then restore the cr0.TS bit.
*/
- if (!user_has_fpu() && !vmx->vcpu.guest_fpu_loaded)
+ if (!fpregs_active() && !vmx->vcpu.guest_fpu_loaded)
stts();
load_gdt(this_cpu_ptr(&host_gdt));
}
@@ -2170,8 +2170,7 @@ static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
if (is_guest_mode(vcpu))
msr_bitmap = vmx_msr_bitmap_nested;
- else if (irqchip_in_kernel(vcpu->kvm) &&
- apic_x2apic_mode(vcpu->arch.apic)) {
+ else if (vcpu->arch.apic_base & X2APIC_ENABLE) {
if (is_long_mode(vcpu))
msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
else
@@ -2623,76 +2622,69 @@ static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
* Returns 0 on success, non-0 otherwise.
* Assumes vcpu_load() was already called.
*/
-static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
- u64 data;
struct shared_msr_entry *msr;
- if (!pdata) {
- printk(KERN_ERR "BUG: get_msr called with NULL pdata\n");
- return -EINVAL;
- }
-
- switch (msr_index) {
+ switch (msr_info->index) {
#ifdef CONFIG_X86_64
case MSR_FS_BASE:
- data = vmcs_readl(GUEST_FS_BASE);
+ msr_info->data = vmcs_readl(GUEST_FS_BASE);
break;
case MSR_GS_BASE:
- data = vmcs_readl(GUEST_GS_BASE);
+ msr_info->data = vmcs_readl(GUEST_GS_BASE);
break;
case MSR_KERNEL_GS_BASE:
vmx_load_host_state(to_vmx(vcpu));
- data = to_vmx(vcpu)->msr_guest_kernel_gs_base;
+ msr_info->data = to_vmx(vcpu)->msr_guest_kernel_gs_base;
break;
#endif
case MSR_EFER:
- return kvm_get_msr_common(vcpu, msr_index, pdata);
+ return kvm_get_msr_common(vcpu, msr_info);
case MSR_IA32_TSC:
- data = guest_read_tsc();
+ msr_info->data = guest_read_tsc();
break;
case MSR_IA32_SYSENTER_CS:
- data = vmcs_read32(GUEST_SYSENTER_CS);
+ msr_info->data = vmcs_read32(GUEST_SYSENTER_CS);
break;
case MSR_IA32_SYSENTER_EIP:
- data = vmcs_readl(GUEST_SYSENTER_EIP);
+ msr_info->data = vmcs_readl(GUEST_SYSENTER_EIP);
break;
case MSR_IA32_SYSENTER_ESP:
- data = vmcs_readl(GUEST_SYSENTER_ESP);
+ msr_info->data = vmcs_readl(GUEST_SYSENTER_ESP);
break;
case MSR_IA32_BNDCFGS:
if (!vmx_mpx_supported())
return 1;
- data = vmcs_read64(GUEST_BNDCFGS);
+ msr_info->data = vmcs_read64(GUEST_BNDCFGS);
break;
case MSR_IA32_FEATURE_CONTROL:
if (!nested_vmx_allowed(vcpu))
return 1;
- data = to_vmx(vcpu)->nested.msr_ia32_feature_control;
+ msr_info->data = to_vmx(vcpu)->nested.msr_ia32_feature_control;
break;
case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC:
if (!nested_vmx_allowed(vcpu))
return 1;
- return vmx_get_vmx_msr(vcpu, msr_index, pdata);
+ return vmx_get_vmx_msr(vcpu, msr_info->index, &msr_info->data);
case MSR_IA32_XSS:
if (!vmx_xsaves_supported())
return 1;
- data = vcpu->arch.ia32_xss;
+ msr_info->data = vcpu->arch.ia32_xss;
break;
case MSR_TSC_AUX:
if (!to_vmx(vcpu)->rdtscp_enabled)
return 1;
/* Otherwise falls through */
default:
- msr = find_msr_entry(to_vmx(vcpu), msr_index);
+ msr = find_msr_entry(to_vmx(vcpu), msr_info->index);
if (msr) {
- data = msr->data;
+ msr_info->data = msr->data;
break;
}
- return kvm_get_msr_common(vcpu, msr_index, pdata);
+ return kvm_get_msr_common(vcpu, msr_info);
}
- *pdata = data;
return 0;
}
@@ -4123,7 +4115,7 @@ static int alloc_apic_access_page(struct kvm *kvm)
kvm_userspace_mem.flags = 0;
kvm_userspace_mem.guest_phys_addr = APIC_DEFAULT_PHYS_BASE;
kvm_userspace_mem.memory_size = PAGE_SIZE;
- r = __kvm_set_memory_region(kvm, &kvm_userspace_mem);
+ r = __x86_set_memory_region(kvm, &kvm_userspace_mem);
if (r)
goto out;
@@ -4158,7 +4150,7 @@ static int alloc_identity_pagetable(struct kvm *kvm)
kvm_userspace_mem.guest_phys_addr =
kvm->arch.ept_identity_map_addr;
kvm_userspace_mem.memory_size = PAGE_SIZE;
- r = __kvm_set_memory_region(kvm, &kvm_userspace_mem);
+ r = __x86_set_memory_region(kvm, &kvm_userspace_mem);
return r;
}
@@ -4667,16 +4659,8 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0);
vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest));
- if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) {
- u32 msr_low, msr_high;
- u64 host_pat;
- rdmsr(MSR_IA32_CR_PAT, msr_low, msr_high);
- host_pat = msr_low | ((u64) msr_high << 32);
- /* Write the default value follow host pat */
- vmcs_write64(GUEST_IA32_PAT, host_pat);
- /* Keep arch.pat sync with GUEST_IA32_PAT */
- vmx->vcpu.arch.pat = host_pat;
- }
+ if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT)
+ vmcs_write64(GUEST_IA32_PAT, vmx->vcpu.arch.pat);
for (i = 0; i < ARRAY_SIZE(vmx_msr_index); ++i) {
u32 index = vmx_msr_index[i];
@@ -4708,22 +4692,27 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
return 0;
}
-static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
+static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
struct msr_data apic_base_msr;
+ u64 cr0;
vmx->rmode.vm86_active = 0;
vmx->soft_vnmi_blocked = 0;
vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val();
- kvm_set_cr8(&vmx->vcpu, 0);
- apic_base_msr.data = APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE;
- if (kvm_vcpu_is_reset_bsp(&vmx->vcpu))
- apic_base_msr.data |= MSR_IA32_APICBASE_BSP;
- apic_base_msr.host_initiated = true;
- kvm_set_apic_base(&vmx->vcpu, &apic_base_msr);
+ kvm_set_cr8(vcpu, 0);
+
+ if (!init_event) {
+ apic_base_msr.data = APIC_DEFAULT_PHYS_BASE |
+ MSR_IA32_APICBASE_ENABLE;
+ if (kvm_vcpu_is_reset_bsp(vcpu))
+ apic_base_msr.data |= MSR_IA32_APICBASE_BSP;
+ apic_base_msr.host_initiated = true;
+ kvm_set_apic_base(vcpu, &apic_base_msr);
+ }
vmx_segment_cache_clear(vmx);
@@ -4747,9 +4736,12 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
vmcs_write32(GUEST_LDTR_LIMIT, 0xffff);
vmcs_write32(GUEST_LDTR_AR_BYTES, 0x00082);
- vmcs_write32(GUEST_SYSENTER_CS, 0);
- vmcs_writel(GUEST_SYSENTER_ESP, 0);
- vmcs_writel(GUEST_SYSENTER_EIP, 0);
+ if (!init_event) {
+ vmcs_write32(GUEST_SYSENTER_CS, 0);
+ vmcs_writel(GUEST_SYSENTER_ESP, 0);
+ vmcs_writel(GUEST_SYSENTER_EIP, 0);
+ vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
+ }
vmcs_writel(GUEST_RFLAGS, 0x02);
kvm_rip_write(vcpu, 0xfff0);
@@ -4764,18 +4756,15 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
- /* Special registers */
- vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
-
setup_msrs(vmx);
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */
- if (cpu_has_vmx_tpr_shadow()) {
+ if (cpu_has_vmx_tpr_shadow() && !init_event) {
vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
- if (vm_need_tpr_shadow(vmx->vcpu.kvm))
+ if (vm_need_tpr_shadow(vcpu->kvm))
vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
- __pa(vmx->vcpu.arch.apic->regs));
+ __pa(vcpu->arch.apic->regs));
vmcs_write32(TPR_THRESHOLD, 0);
}
@@ -4787,12 +4776,14 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
if (vmx->vpid != 0)
vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid);
- vmx->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
- vmx_set_cr0(&vmx->vcpu, kvm_read_cr0(vcpu)); /* enter rmode */
- vmx_set_cr4(&vmx->vcpu, 0);
- vmx_set_efer(&vmx->vcpu, 0);
- vmx_fpu_activate(&vmx->vcpu);
- update_exception_bitmap(&vmx->vcpu);
+ cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
+ vmx_set_cr0(vcpu, cr0); /* enter rmode */
+ vmx->vcpu.arch.cr0 = cr0;
+ vmx_set_cr4(vcpu, 0);
+ if (!init_event)
+ vmx_set_efer(vcpu, 0);
+ vmx_fpu_activate(vcpu);
+ update_exception_bitmap(vcpu);
vpid_sync_context(vmx);
}
@@ -4965,7 +4956,7 @@ static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr)
.flags = 0,
};
- ret = kvm_set_memory_region(kvm, &tss_mem);
+ ret = x86_set_memory_region(kvm, &tss_mem);
if (ret)
return ret;
kvm->arch.tss_addr = addr;
@@ -5475,19 +5466,21 @@ static int handle_cpuid(struct kvm_vcpu *vcpu)
static int handle_rdmsr(struct kvm_vcpu *vcpu)
{
u32 ecx = vcpu->arch.regs[VCPU_REGS_RCX];
- u64 data;
+ struct msr_data msr_info;
- if (vmx_get_msr(vcpu, ecx, &data)) {
+ msr_info.index = ecx;
+ msr_info.host_initiated = false;
+ if (vmx_get_msr(vcpu, &msr_info)) {
trace_kvm_msr_read_ex(ecx);
kvm_inject_gp(vcpu, 0);
return 1;
}
- trace_kvm_msr_read(ecx, data);
+ trace_kvm_msr_read(ecx, msr_info.data);
/* FIXME: handling of bits 32:63 of rax, rdx */
- vcpu->arch.regs[VCPU_REGS_RAX] = data & -1u;
- vcpu->arch.regs[VCPU_REGS_RDX] = (data >> 32) & -1u;
+ vcpu->arch.regs[VCPU_REGS_RAX] = msr_info.data & -1u;
+ vcpu->arch.regs[VCPU_REGS_RDX] = (msr_info.data >> 32) & -1u;
skip_emulated_instruction(vcpu);
return 1;
}
@@ -5710,9 +5703,6 @@ static int handle_task_switch(struct kvm_vcpu *vcpu)
return 0;
}
- /* clear all local breakpoint enable flags */
- vmcs_writel(GUEST_DR7, vmcs_readl(GUEST_DR7) & ~0x155);
-
/*
* TODO: What about debug traps on tss switch?
* Are we supposed to inject them and update dr6?
@@ -7333,7 +7323,7 @@ static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
bitmap += (port & 0x7fff) / 8;
if (last_bitmap != bitmap)
- if (kvm_read_guest(vcpu->kvm, bitmap, &b, 1))
+ if (kvm_vcpu_read_guest(vcpu, bitmap, &b, 1))
return true;
if (b & (1 << (port & 7)))
return true;
@@ -7377,7 +7367,7 @@ static bool nested_vmx_exit_handled_msr(struct kvm_vcpu *vcpu,
/* Then read the msr_index'th bit from this bitmap: */
if (msr_index < 1024*8) {
unsigned char b;
- if (kvm_read_guest(vcpu->kvm, bitmap + msr_index/8, &b, 1))
+ if (kvm_vcpu_read_guest(vcpu, bitmap + msr_index/8, &b, 1))
return true;
return 1 & (b >> (msr_index & 7));
} else
@@ -7642,9 +7632,9 @@ static void vmx_disable_pml(struct vcpu_vmx *vmx)
vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control);
}
-static void vmx_flush_pml_buffer(struct vcpu_vmx *vmx)
+static void vmx_flush_pml_buffer(struct kvm_vcpu *vcpu)
{
- struct kvm *kvm = vmx->vcpu.kvm;
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
u64 *pml_buf;
u16 pml_idx;
@@ -7666,7 +7656,7 @@ static void vmx_flush_pml_buffer(struct vcpu_vmx *vmx)
gpa = pml_buf[pml_idx];
WARN_ON(gpa & (PAGE_SIZE - 1));
- mark_page_dirty(kvm, gpa >> PAGE_SHIFT);
+ kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
}
/* reset PML index */
@@ -7691,6 +7681,158 @@ static void kvm_flush_pml_buffers(struct kvm *kvm)
kvm_vcpu_kick(vcpu);
}
+static void vmx_dump_sel(char *name, uint32_t sel)
+{
+ pr_err("%s sel=0x%04x, attr=0x%05x, limit=0x%08x, base=0x%016lx\n",
+ name, vmcs_read32(sel),
+ vmcs_read32(sel + GUEST_ES_AR_BYTES - GUEST_ES_SELECTOR),
+ vmcs_read32(sel + GUEST_ES_LIMIT - GUEST_ES_SELECTOR),
+ vmcs_readl(sel + GUEST_ES_BASE - GUEST_ES_SELECTOR));
+}
+
+static void vmx_dump_dtsel(char *name, uint32_t limit)
+{
+ pr_err("%s limit=0x%08x, base=0x%016lx\n",
+ name, vmcs_read32(limit),
+ vmcs_readl(limit + GUEST_GDTR_BASE - GUEST_GDTR_LIMIT));
+}
+
+static void dump_vmcs(void)
+{
+ u32 vmentry_ctl = vmcs_read32(VM_ENTRY_CONTROLS);
+ u32 vmexit_ctl = vmcs_read32(VM_EXIT_CONTROLS);
+ u32 cpu_based_exec_ctrl = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ u32 pin_based_exec_ctrl = vmcs_read32(PIN_BASED_VM_EXEC_CONTROL);
+ u32 secondary_exec_control = 0;
+ unsigned long cr4 = vmcs_readl(GUEST_CR4);
+ u64 efer = vmcs_readl(GUEST_IA32_EFER);
+ int i, n;
+
+ if (cpu_has_secondary_exec_ctrls())
+ secondary_exec_control = vmcs_read32(SECONDARY_VM_EXEC_CONTROL);
+
+ pr_err("*** Guest State ***\n");
+ pr_err("CR0: actual=0x%016lx, shadow=0x%016lx, gh_mask=%016lx\n",
+ vmcs_readl(GUEST_CR0), vmcs_readl(CR0_READ_SHADOW),
+ vmcs_readl(CR0_GUEST_HOST_MASK));
+ pr_err("CR4: actual=0x%016lx, shadow=0x%016lx, gh_mask=%016lx\n",
+ cr4, vmcs_readl(CR4_READ_SHADOW), vmcs_readl(CR4_GUEST_HOST_MASK));
+ pr_err("CR3 = 0x%016lx\n", vmcs_readl(GUEST_CR3));
+ if ((secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT) &&
+ (cr4 & X86_CR4_PAE) && !(efer & EFER_LMA))
+ {
+ pr_err("PDPTR0 = 0x%016lx PDPTR1 = 0x%016lx\n",
+ vmcs_readl(GUEST_PDPTR0), vmcs_readl(GUEST_PDPTR1));
+ pr_err("PDPTR2 = 0x%016lx PDPTR3 = 0x%016lx\n",
+ vmcs_readl(GUEST_PDPTR2), vmcs_readl(GUEST_PDPTR3));
+ }
+ pr_err("RSP = 0x%016lx RIP = 0x%016lx\n",
+ vmcs_readl(GUEST_RSP), vmcs_readl(GUEST_RIP));
+ pr_err("RFLAGS=0x%08lx DR7 = 0x%016lx\n",
+ vmcs_readl(GUEST_RFLAGS), vmcs_readl(GUEST_DR7));
+ pr_err("Sysenter RSP=%016lx CS:RIP=%04x:%016lx\n",
+ vmcs_readl(GUEST_SYSENTER_ESP),
+ vmcs_read32(GUEST_SYSENTER_CS), vmcs_readl(GUEST_SYSENTER_EIP));
+ vmx_dump_sel("CS: ", GUEST_CS_SELECTOR);
+ vmx_dump_sel("DS: ", GUEST_DS_SELECTOR);
+ vmx_dump_sel("SS: ", GUEST_SS_SELECTOR);
+ vmx_dump_sel("ES: ", GUEST_ES_SELECTOR);
+ vmx_dump_sel("FS: ", GUEST_FS_SELECTOR);
+ vmx_dump_sel("GS: ", GUEST_GS_SELECTOR);
+ vmx_dump_dtsel("GDTR:", GUEST_GDTR_LIMIT);
+ vmx_dump_sel("LDTR:", GUEST_LDTR_SELECTOR);
+ vmx_dump_dtsel("IDTR:", GUEST_IDTR_LIMIT);
+ vmx_dump_sel("TR: ", GUEST_TR_SELECTOR);
+ if ((vmexit_ctl & (VM_EXIT_SAVE_IA32_PAT | VM_EXIT_SAVE_IA32_EFER)) ||
+ (vmentry_ctl & (VM_ENTRY_LOAD_IA32_PAT | VM_ENTRY_LOAD_IA32_EFER)))
+ pr_err("EFER = 0x%016llx PAT = 0x%016lx\n",
+ efer, vmcs_readl(GUEST_IA32_PAT));
+ pr_err("DebugCtl = 0x%016lx DebugExceptions = 0x%016lx\n",
+ vmcs_readl(GUEST_IA32_DEBUGCTL),
+ vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS));
+ if (vmentry_ctl & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)
+ pr_err("PerfGlobCtl = 0x%016lx\n",
+ vmcs_readl(GUEST_IA32_PERF_GLOBAL_CTRL));
+ if (vmentry_ctl & VM_ENTRY_LOAD_BNDCFGS)
+ pr_err("BndCfgS = 0x%016lx\n", vmcs_readl(GUEST_BNDCFGS));
+ pr_err("Interruptibility = %08x ActivityState = %08x\n",
+ vmcs_read32(GUEST_INTERRUPTIBILITY_INFO),
+ vmcs_read32(GUEST_ACTIVITY_STATE));
+ if (secondary_exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY)
+ pr_err("InterruptStatus = %04x\n",
+ vmcs_read16(GUEST_INTR_STATUS));
+
+ pr_err("*** Host State ***\n");
+ pr_err("RIP = 0x%016lx RSP = 0x%016lx\n",
+ vmcs_readl(HOST_RIP), vmcs_readl(HOST_RSP));
+ pr_err("CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x TR=%04x\n",
+ vmcs_read16(HOST_CS_SELECTOR), vmcs_read16(HOST_SS_SELECTOR),
+ vmcs_read16(HOST_DS_SELECTOR), vmcs_read16(HOST_ES_SELECTOR),
+ vmcs_read16(HOST_FS_SELECTOR), vmcs_read16(HOST_GS_SELECTOR),
+ vmcs_read16(HOST_TR_SELECTOR));
+ pr_err("FSBase=%016lx GSBase=%016lx TRBase=%016lx\n",
+ vmcs_readl(HOST_FS_BASE), vmcs_readl(HOST_GS_BASE),
+ vmcs_readl(HOST_TR_BASE));
+ pr_err("GDTBase=%016lx IDTBase=%016lx\n",
+ vmcs_readl(HOST_GDTR_BASE), vmcs_readl(HOST_IDTR_BASE));
+ pr_err("CR0=%016lx CR3=%016lx CR4=%016lx\n",
+ vmcs_readl(HOST_CR0), vmcs_readl(HOST_CR3),
+ vmcs_readl(HOST_CR4));
+ pr_err("Sysenter RSP=%016lx CS:RIP=%04x:%016lx\n",
+ vmcs_readl(HOST_IA32_SYSENTER_ESP),
+ vmcs_read32(HOST_IA32_SYSENTER_CS),
+ vmcs_readl(HOST_IA32_SYSENTER_EIP));
+ if (vmexit_ctl & (VM_EXIT_LOAD_IA32_PAT | VM_EXIT_LOAD_IA32_EFER))
+ pr_err("EFER = 0x%016lx PAT = 0x%016lx\n",
+ vmcs_readl(HOST_IA32_EFER), vmcs_readl(HOST_IA32_PAT));
+ if (vmexit_ctl & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL)
+ pr_err("PerfGlobCtl = 0x%016lx\n",
+ vmcs_readl(HOST_IA32_PERF_GLOBAL_CTRL));
+
+ pr_err("*** Control State ***\n");
+ pr_err("PinBased=%08x CPUBased=%08x SecondaryExec=%08x\n",
+ pin_based_exec_ctrl, cpu_based_exec_ctrl, secondary_exec_control);
+ pr_err("EntryControls=%08x ExitControls=%08x\n", vmentry_ctl, vmexit_ctl);
+ pr_err("ExceptionBitmap=%08x PFECmask=%08x PFECmatch=%08x\n",
+ vmcs_read32(EXCEPTION_BITMAP),
+ vmcs_read32(PAGE_FAULT_ERROR_CODE_MASK),
+ vmcs_read32(PAGE_FAULT_ERROR_CODE_MATCH));
+ pr_err("VMEntry: intr_info=%08x errcode=%08x ilen=%08x\n",
+ vmcs_read32(VM_ENTRY_INTR_INFO_FIELD),
+ vmcs_read32(VM_ENTRY_EXCEPTION_ERROR_CODE),
+ vmcs_read32(VM_ENTRY_INSTRUCTION_LEN));
+ pr_err("VMExit: intr_info=%08x errcode=%08x ilen=%08x\n",
+ vmcs_read32(VM_EXIT_INTR_INFO),
+ vmcs_read32(VM_EXIT_INTR_ERROR_CODE),
+ vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
+ pr_err(" reason=%08x qualification=%016lx\n",
+ vmcs_read32(VM_EXIT_REASON), vmcs_readl(EXIT_QUALIFICATION));
+ pr_err("IDTVectoring: info=%08x errcode=%08x\n",
+ vmcs_read32(IDT_VECTORING_INFO_FIELD),
+ vmcs_read32(IDT_VECTORING_ERROR_CODE));
+ pr_err("TSC Offset = 0x%016lx\n", vmcs_readl(TSC_OFFSET));
+ if (cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW)
+ pr_err("TPR Threshold = 0x%02x\n", vmcs_read32(TPR_THRESHOLD));
+ if (pin_based_exec_ctrl & PIN_BASED_POSTED_INTR)
+ pr_err("PostedIntrVec = 0x%02x\n", vmcs_read16(POSTED_INTR_NV));
+ if ((secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT))
+ pr_err("EPT pointer = 0x%016lx\n", vmcs_readl(EPT_POINTER));
+ n = vmcs_read32(CR3_TARGET_COUNT);
+ for (i = 0; i + 1 < n; i += 4)
+ pr_err("CR3 target%u=%016lx target%u=%016lx\n",
+ i, vmcs_readl(CR3_TARGET_VALUE0 + i * 2),
+ i + 1, vmcs_readl(CR3_TARGET_VALUE0 + i * 2 + 2));
+ if (i < n)
+ pr_err("CR3 target%u=%016lx\n",
+ i, vmcs_readl(CR3_TARGET_VALUE0 + i * 2));
+ if (secondary_exec_control & SECONDARY_EXEC_PAUSE_LOOP_EXITING)
+ pr_err("PLE Gap=%08x Window=%08x\n",
+ vmcs_read32(PLE_GAP), vmcs_read32(PLE_WINDOW));
+ if (secondary_exec_control & SECONDARY_EXEC_ENABLE_VPID)
+ pr_err("Virtual processor ID = 0x%04x\n",
+ vmcs_read16(VIRTUAL_PROCESSOR_ID));
+}
+
/*
* The guest has exited. See if we can fix it or if we need userspace
* assistance.
@@ -7709,7 +7851,7 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
* flushed already.
*/
if (enable_pml)
- vmx_flush_pml_buffer(vmx);
+ vmx_flush_pml_buffer(vcpu);
/* If guest state is invalid, start emulating */
if (vmx->emulation_required)
@@ -7723,6 +7865,7 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
}
if (exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) {
+ dump_vmcs();
vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY;
vcpu->run->fail_entry.hardware_entry_failure_reason
= exit_reason;
@@ -7996,6 +8139,11 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
local_irq_enable();
}
+static bool vmx_has_high_real_mode_segbase(void)
+{
+ return enable_unrestricted_guest || emulate_invalid_guest_state;
+}
+
static bool vmx_mpx_supported(void)
{
return (vmcs_config.vmexit_ctrl & VM_EXIT_CLEAR_BNDCFGS) &&
@@ -8480,7 +8628,8 @@ static int get_ept_level(void)
static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
{
- u64 ret;
+ u8 cache;
+ u64 ipat = 0;
/* For VT-d and EPT combination
* 1. MMIO: always map as UC
@@ -8493,16 +8642,27 @@ static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
* 3. EPT without VT-d: always map as WB and set IPAT=1 to keep
* consistent with host MTRR
*/
- if (is_mmio)
- ret = MTRR_TYPE_UNCACHABLE << VMX_EPT_MT_EPTE_SHIFT;
- else if (kvm_arch_has_noncoherent_dma(vcpu->kvm))
- ret = kvm_get_guest_memory_type(vcpu, gfn) <<
- VMX_EPT_MT_EPTE_SHIFT;
- else
- ret = (MTRR_TYPE_WRBACK << VMX_EPT_MT_EPTE_SHIFT)
- | VMX_EPT_IPAT_BIT;
+ if (is_mmio) {
+ cache = MTRR_TYPE_UNCACHABLE;
+ goto exit;
+ }
- return ret;
+ if (!kvm_arch_has_noncoherent_dma(vcpu->kvm)) {
+ ipat = VMX_EPT_IPAT_BIT;
+ cache = MTRR_TYPE_WRBACK;
+ goto exit;
+ }
+
+ if (kvm_read_cr0(vcpu) & X86_CR0_CD) {
+ ipat = VMX_EPT_IPAT_BIT;
+ cache = MTRR_TYPE_UNCACHABLE;
+ goto exit;
+ }
+
+ cache = kvm_mtrr_get_guest_memory_type(vcpu, gfn);
+
+exit:
+ return (cache << VMX_EPT_MT_EPTE_SHIFT) | ipat;
}
static int vmx_get_lpage_level(void)
@@ -8924,7 +9084,7 @@ static int nested_vmx_msr_check_common(struct kvm_vcpu *vcpu,
struct vmx_msr_entry *e)
{
/* x2APIC MSR accesses are not allowed */
- if (apic_x2apic_mode(vcpu->arch.apic) && e->index >> 8 == 0x8)
+ if (vcpu->arch.apic_base & X2APIC_ENABLE && e->index >> 8 == 0x8)
return -EINVAL;
if (e->index == MSR_IA32_UCODE_WRITE || /* SDM Table 35-2 */
e->index == MSR_IA32_UCODE_REV)
@@ -8966,8 +9126,8 @@ static u32 nested_vmx_load_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count)
msr.host_initiated = false;
for (i = 0; i < count; i++) {
- if (kvm_read_guest(vcpu->kvm, gpa + i * sizeof(e),
- &e, sizeof(e))) {
+ if (kvm_vcpu_read_guest(vcpu, gpa + i * sizeof(e),
+ &e, sizeof(e))) {
pr_warn_ratelimited(
"%s cannot read MSR entry (%u, 0x%08llx)\n",
__func__, i, gpa + i * sizeof(e));
@@ -8999,9 +9159,10 @@ static int nested_vmx_store_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count)
struct vmx_msr_entry e;
for (i = 0; i < count; i++) {
- if (kvm_read_guest(vcpu->kvm,
- gpa + i * sizeof(e),
- &e, 2 * sizeof(u32))) {
+ struct msr_data msr_info;
+ if (kvm_vcpu_read_guest(vcpu,
+ gpa + i * sizeof(e),
+ &e, 2 * sizeof(u32))) {
pr_warn_ratelimited(
"%s cannot read MSR entry (%u, 0x%08llx)\n",
__func__, i, gpa + i * sizeof(e));
@@ -9013,19 +9174,21 @@ static int nested_vmx_store_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count)
__func__, i, e.index, e.reserved);
return -EINVAL;
}
- if (kvm_get_msr(vcpu, e.index, &e.value)) {
+ msr_info.host_initiated = false;
+ msr_info.index = e.index;
+ if (kvm_get_msr(vcpu, &msr_info)) {
pr_warn_ratelimited(
"%s cannot read MSR (%u, 0x%x)\n",
__func__, i, e.index);
return -EINVAL;
}
- if (kvm_write_guest(vcpu->kvm,
- gpa + i * sizeof(e) +
- offsetof(struct vmx_msr_entry, value),
- &e.value, sizeof(e.value))) {
+ if (kvm_vcpu_write_guest(vcpu,
+ gpa + i * sizeof(e) +
+ offsetof(struct vmx_msr_entry, value),
+ &msr_info.data, sizeof(msr_info.data))) {
pr_warn_ratelimited(
"%s cannot write MSR (%u, 0x%x, 0x%llx)\n",
- __func__, i, e.index, e.value);
+ __func__, i, e.index, msr_info.data);
return -EINVAL;
}
}
@@ -10150,6 +10313,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
.hardware_enable = hardware_enable,
.hardware_disable = hardware_disable,
.cpu_has_accelerated_tpr = report_flexpriority,
+ .cpu_has_high_real_mode_segbase = vmx_has_high_real_mode_segbase,
.vcpu_create = vmx_create_vcpu,
.vcpu_free = vmx_free_vcpu,
@@ -10255,6 +10419,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
.slot_disable_log_dirty = vmx_slot_disable_log_dirty,
.flush_log_dirty = vmx_flush_log_dirty,
.enable_log_dirty_pt_masked = vmx_enable_log_dirty_pt_masked,
+
+ .pmu_ops = &intel_pmu_ops,
};
static int __init vmx_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index ea306adbbc13..ac165c2fb8e5 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -28,6 +28,7 @@
#include "x86.h"
#include "cpuid.h"
#include "assigned-dev.h"
+#include "pmu.h"
#include <linux/clocksource.h>
#include <linux/interrupt.h>
@@ -57,11 +58,9 @@
#include <asm/debugreg.h>
#include <asm/msr.h>
#include <asm/desc.h>
-#include <asm/mtrr.h>
#include <asm/mce.h>
-#include <asm/i387.h>
-#include <asm/fpu-internal.h> /* Ugh! */
-#include <asm/xcr.h>
+#include <linux/kernel_stat.h>
+#include <asm/fpu/internal.h> /* Ugh! */
#include <asm/pvclock.h>
#include <asm/div64.h>
@@ -99,6 +98,9 @@ module_param(ignore_msrs, bool, S_IRUGO | S_IWUSR);
unsigned int min_timer_period_us = 500;
module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR);
+static bool __read_mostly kvmclock_periodic_sync = true;
+module_param(kvmclock_periodic_sync, bool, S_IRUGO);
+
bool kvm_has_tsc_control;
EXPORT_SYMBOL_GPL(kvm_has_tsc_control);
u32 kvm_max_guest_tsc_khz;
@@ -475,7 +477,7 @@ EXPORT_SYMBOL_GPL(kvm_require_dr);
/*
* This function will be used to read from the physical memory of the currently
- * running guest. The difference to kvm_read_guest_page is that this function
+ * running guest. The difference to kvm_vcpu_read_guest_page is that this function
* can read from guest physical or from the guest's guest physical memory.
*/
int kvm_read_guest_page_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
@@ -493,7 +495,7 @@ int kvm_read_guest_page_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
real_gfn = gpa_to_gfn(real_gfn);
- return kvm_read_guest_page(vcpu->kvm, real_gfn, data, offset, len);
+ return kvm_vcpu_read_guest_page(vcpu, real_gfn, data, offset, len);
}
EXPORT_SYMBOL_GPL(kvm_read_guest_page_mmu);
@@ -572,8 +574,7 @@ out:
int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
unsigned long old_cr0 = kvm_read_cr0(vcpu);
- unsigned long update_bits = X86_CR0_PG | X86_CR0_WP |
- X86_CR0_CD | X86_CR0_NW;
+ unsigned long update_bits = X86_CR0_PG | X86_CR0_WP;
cr0 |= X86_CR0_ET;
@@ -619,6 +620,10 @@ int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
if ((cr0 ^ old_cr0) & update_bits)
kvm_mmu_reset_context(vcpu);
+
+ if ((cr0 ^ old_cr0) & X86_CR0_CD)
+ kvm_zap_gfn_range(vcpu->kvm, 0, ~0ULL);
+
return 0;
}
EXPORT_SYMBOL_GPL(kvm_set_cr0);
@@ -908,7 +913,7 @@ bool kvm_rdpmc(struct kvm_vcpu *vcpu)
u64 data;
int err;
- err = kvm_pmu_read_pmc(vcpu, ecx, &data);
+ err = kvm_pmu_rdpmc(vcpu, ecx, &data);
if (err)
return err;
kvm_register_write(vcpu, VCPU_REGS_RAX, (u32)data);
@@ -923,17 +928,11 @@ EXPORT_SYMBOL_GPL(kvm_rdpmc);
*
* This list is modified at module load time to reflect the
* capabilities of the host cpu. This capabilities test skips MSRs that are
- * kvm-specific. Those are put in the beginning of the list.
+ * kvm-specific. Those are put in emulated_msrs; filtering of emulated_msrs
+ * may depend on host virtualization features rather than host cpu features.
*/
-#define KVM_SAVE_MSRS_BEGIN 12
static u32 msrs_to_save[] = {
- MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
- MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW,
- HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
- HV_X64_MSR_TIME_REF_COUNT, HV_X64_MSR_REFERENCE_TSC,
- HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
- MSR_KVM_PV_EOI_EN,
MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
MSR_STAR,
#ifdef CONFIG_X86_64
@@ -945,14 +944,24 @@ static u32 msrs_to_save[] = {
static unsigned num_msrs_to_save;
-static const u32 emulated_msrs[] = {
+static u32 emulated_msrs[] = {
+ MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
+ MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW,
+ HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
+ HV_X64_MSR_TIME_REF_COUNT, HV_X64_MSR_REFERENCE_TSC,
+ HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
+ MSR_KVM_PV_EOI_EN,
+
MSR_IA32_TSC_ADJUST,
MSR_IA32_TSCDEADLINE,
MSR_IA32_MISC_ENABLE,
MSR_IA32_MCG_STATUS,
MSR_IA32_MCG_CTL,
+ MSR_IA32_SMBASE,
};
+static unsigned num_emulated_msrs;
+
bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
{
if (efer & efer_reserved_bits)
@@ -1046,6 +1055,21 @@ EXPORT_SYMBOL_GPL(kvm_set_msr);
/*
* Adapt set_msr() to msr_io()'s calling convention
*/
+static int do_get_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
+{
+ struct msr_data msr;
+ int r;
+
+ msr.index = index;
+ msr.host_initiated = true;
+ r = kvm_get_msr(vcpu, &msr);
+ if (r)
+ return r;
+
+ *data = msr.data;
+ return 0;
+}
+
static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
{
struct msr_data msr;
@@ -1698,6 +1722,8 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
vcpu->pvclock_set_guest_stopped_request = false;
}
+ pvclock_flags |= PVCLOCK_COUNTS_FROM_ZERO;
+
/* If the host uses TSC clocksource, then it is stable */
if (use_master_clock)
pvclock_flags |= PVCLOCK_TSC_STABLE_BIT;
@@ -1768,127 +1794,14 @@ static void kvmclock_sync_fn(struct work_struct *work)
kvmclock_sync_work);
struct kvm *kvm = container_of(ka, struct kvm, arch);
+ if (!kvmclock_periodic_sync)
+ return;
+
schedule_delayed_work(&kvm->arch.kvmclock_update_work, 0);
schedule_delayed_work(&kvm->arch.kvmclock_sync_work,
KVMCLOCK_SYNC_PERIOD);
}
-static bool msr_mtrr_valid(unsigned msr)
-{
- switch (msr) {
- case 0x200 ... 0x200 + 2 * KVM_NR_VAR_MTRR - 1:
- case MSR_MTRRfix64K_00000:
- case MSR_MTRRfix16K_80000:
- case MSR_MTRRfix16K_A0000:
- case MSR_MTRRfix4K_C0000:
- case MSR_MTRRfix4K_C8000:
- case MSR_MTRRfix4K_D0000:
- case MSR_MTRRfix4K_D8000:
- case MSR_MTRRfix4K_E0000:
- case MSR_MTRRfix4K_E8000:
- case MSR_MTRRfix4K_F0000:
- case MSR_MTRRfix4K_F8000:
- case MSR_MTRRdefType:
- case MSR_IA32_CR_PAT:
- return true;
- case 0x2f8:
- return true;
- }
- return false;
-}
-
-static bool valid_pat_type(unsigned t)
-{
- return t < 8 && (1 << t) & 0xf3; /* 0, 1, 4, 5, 6, 7 */
-}
-
-static bool valid_mtrr_type(unsigned t)
-{
- return t < 8 && (1 << t) & 0x73; /* 0, 1, 4, 5, 6 */
-}
-
-bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data)
-{
- int i;
- u64 mask;
-
- if (!msr_mtrr_valid(msr))
- return false;
-
- if (msr == MSR_IA32_CR_PAT) {
- for (i = 0; i < 8; i++)
- if (!valid_pat_type((data >> (i * 8)) & 0xff))
- return false;
- return true;
- } else if (msr == MSR_MTRRdefType) {
- if (data & ~0xcff)
- return false;
- return valid_mtrr_type(data & 0xff);
- } else if (msr >= MSR_MTRRfix64K_00000 && msr <= MSR_MTRRfix4K_F8000) {
- for (i = 0; i < 8 ; i++)
- if (!valid_mtrr_type((data >> (i * 8)) & 0xff))
- return false;
- return true;
- }
-
- /* variable MTRRs */
- WARN_ON(!(msr >= 0x200 && msr < 0x200 + 2 * KVM_NR_VAR_MTRR));
-
- mask = (~0ULL) << cpuid_maxphyaddr(vcpu);
- if ((msr & 1) == 0) {
- /* MTRR base */
- if (!valid_mtrr_type(data & 0xff))
- return false;
- mask |= 0xf00;
- } else
- /* MTRR mask */
- mask |= 0x7ff;
- if (data & mask) {
- kvm_inject_gp(vcpu, 0);
- return false;
- }
-
- return true;
-}
-EXPORT_SYMBOL_GPL(kvm_mtrr_valid);
-
-static int set_msr_mtrr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
-{
- u64 *p = (u64 *)&vcpu->arch.mtrr_state.fixed_ranges;
-
- if (!kvm_mtrr_valid(vcpu, msr, data))
- return 1;
-
- if (msr == MSR_MTRRdefType) {
- vcpu->arch.mtrr_state.def_type = data;
- vcpu->arch.mtrr_state.enabled = (data & 0xc00) >> 10;
- } else if (msr == MSR_MTRRfix64K_00000)
- p[0] = data;
- else if (msr == MSR_MTRRfix16K_80000 || msr == MSR_MTRRfix16K_A0000)
- p[1 + msr - MSR_MTRRfix16K_80000] = data;
- else if (msr >= MSR_MTRRfix4K_C0000 && msr <= MSR_MTRRfix4K_F8000)
- p[3 + msr - MSR_MTRRfix4K_C0000] = data;
- else if (msr == MSR_IA32_CR_PAT)
- vcpu->arch.pat = data;
- else { /* Variable MTRRs */
- int idx, is_mtrr_mask;
- u64 *pt;
-
- idx = (msr - 0x200) / 2;
- is_mtrr_mask = msr - 0x200 - 2 * idx;
- if (!is_mtrr_mask)
- pt =
- (u64 *)&vcpu->arch.mtrr_state.var_ranges[idx].base_lo;
- else
- pt =
- (u64 *)&vcpu->arch.mtrr_state.var_ranges[idx].mask_lo;
- *pt = data;
- }
-
- kvm_mmu_reset_context(vcpu);
- return 0;
-}
-
static int set_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 data)
{
u64 mcg_cap = vcpu->arch.mcg_cap;
@@ -1947,7 +1860,7 @@ static int xen_hvm_config(struct kvm_vcpu *vcpu, u64 data)
r = PTR_ERR(page);
goto out;
}
- if (kvm_write_guest(kvm, page_addr, page, PAGE_SIZE))
+ if (kvm_vcpu_write_guest(vcpu, page_addr, page, PAGE_SIZE))
goto out_free;
r = 0;
out_free:
@@ -2047,13 +1960,13 @@ static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data)
break;
}
gfn = data >> HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT;
- addr = gfn_to_hva(vcpu->kvm, gfn);
+ addr = kvm_vcpu_gfn_to_hva(vcpu, gfn);
if (kvm_is_error_hva(addr))
return 1;
if (__clear_user((void __user *)addr, PAGE_SIZE))
return 1;
vcpu->arch.hv_vapic = data;
- mark_page_dirty(vcpu->kvm, gfn);
+ kvm_vcpu_mark_page_dirty(vcpu, gfn);
if (kvm_lapic_enable_pv_eoi(vcpu, gfn_to_gpa(gfn) | KVM_MSR_ENABLED))
return 1;
break;
@@ -2180,7 +2093,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
__func__, data);
break;
case 0x200 ... 0x2ff:
- return set_msr_mtrr(vcpu, msr, data);
+ return kvm_mtrr_set_msr(vcpu, msr, data);
case MSR_IA32_APICBASE:
return kvm_set_apic_base(vcpu, msr_info);
case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
@@ -2200,6 +2113,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case MSR_IA32_MISC_ENABLE:
vcpu->arch.ia32_misc_enable_msr = data;
break;
+ case MSR_IA32_SMBASE:
+ if (!msr_info->host_initiated)
+ return 1;
+ vcpu->arch.smbase = data;
+ break;
case MSR_KVM_WALL_CLOCK_NEW:
case MSR_KVM_WALL_CLOCK:
vcpu->kvm->arch.wall_clock = data;
@@ -2220,6 +2138,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
&vcpu->requests);
ka->boot_vcpu_runs_old_kvmclock = tmp;
+
+ ka->kvmclock_offset = -get_kernel_ns();
}
vcpu->arch.time = data;
@@ -2281,37 +2201,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1:
return set_msr_mce(vcpu, msr, data);
- /* Performance counters are not protected by a CPUID bit,
- * so we should check all of them in the generic path for the sake of
- * cross vendor migration.
- * Writing a zero into the event select MSRs disables them,
- * which we perfectly emulate ;-). Any other value should be at least
- * reported, some guests depend on them.
- */
- case MSR_K7_EVNTSEL0:
- case MSR_K7_EVNTSEL1:
- case MSR_K7_EVNTSEL2:
- case MSR_K7_EVNTSEL3:
- if (data != 0)
- vcpu_unimpl(vcpu, "unimplemented perfctr wrmsr: "
- "0x%x data 0x%llx\n", msr, data);
- break;
- /* at least RHEL 4 unconditionally writes to the perfctr registers,
- * so we ignore writes to make it happy.
- */
- case MSR_K7_PERFCTR0:
- case MSR_K7_PERFCTR1:
- case MSR_K7_PERFCTR2:
- case MSR_K7_PERFCTR3:
- vcpu_unimpl(vcpu, "unimplemented perfctr wrmsr: "
- "0x%x data 0x%llx\n", msr, data);
- break;
- case MSR_P6_PERFCTR0:
- case MSR_P6_PERFCTR1:
- pr = true;
- case MSR_P6_EVNTSEL0:
- case MSR_P6_EVNTSEL1:
- if (kvm_pmu_msr(vcpu, msr))
+ case MSR_K7_PERFCTR0 ... MSR_K7_PERFCTR3:
+ case MSR_P6_PERFCTR0 ... MSR_P6_PERFCTR1:
+ pr = true; /* fall through */
+ case MSR_K7_EVNTSEL0 ... MSR_K7_EVNTSEL3:
+ case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL1:
+ if (kvm_pmu_is_valid_msr(vcpu, msr))
return kvm_pmu_set_msr(vcpu, msr_info);
if (pr || data != 0)
@@ -2357,7 +2252,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
default:
if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
return xen_hvm_config(vcpu, data);
- if (kvm_pmu_msr(vcpu, msr))
+ if (kvm_pmu_is_valid_msr(vcpu, msr))
return kvm_pmu_set_msr(vcpu, msr_info);
if (!ignore_msrs) {
vcpu_unimpl(vcpu, "unhandled wrmsr: 0x%x data %llx\n",
@@ -2379,48 +2274,12 @@ EXPORT_SYMBOL_GPL(kvm_set_msr_common);
* Returns 0 on success, non-0 otherwise.
* Assumes vcpu_load() was already called.
*/
-int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+int kvm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
{
- return kvm_x86_ops->get_msr(vcpu, msr_index, pdata);
+ return kvm_x86_ops->get_msr(vcpu, msr);
}
EXPORT_SYMBOL_GPL(kvm_get_msr);
-static int get_msr_mtrr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
-{
- u64 *p = (u64 *)&vcpu->arch.mtrr_state.fixed_ranges;
-
- if (!msr_mtrr_valid(msr))
- return 1;
-
- if (msr == MSR_MTRRdefType)
- *pdata = vcpu->arch.mtrr_state.def_type +
- (vcpu->arch.mtrr_state.enabled << 10);
- else if (msr == MSR_MTRRfix64K_00000)
- *pdata = p[0];
- else if (msr == MSR_MTRRfix16K_80000 || msr == MSR_MTRRfix16K_A0000)
- *pdata = p[1 + msr - MSR_MTRRfix16K_80000];
- else if (msr >= MSR_MTRRfix4K_C0000 && msr <= MSR_MTRRfix4K_F8000)
- *pdata = p[3 + msr - MSR_MTRRfix4K_C0000];
- else if (msr == MSR_IA32_CR_PAT)
- *pdata = vcpu->arch.pat;
- else { /* Variable MTRRs */
- int idx, is_mtrr_mask;
- u64 *pt;
-
- idx = (msr - 0x200) / 2;
- is_mtrr_mask = msr - 0x200 - 2 * idx;
- if (!is_mtrr_mask)
- pt =
- (u64 *)&vcpu->arch.mtrr_state.var_ranges[idx].base_lo;
- else
- pt =
- (u64 *)&vcpu->arch.mtrr_state.var_ranges[idx].mask_lo;
- *pdata = *pt;
- }
-
- return 0;
-}
-
static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
{
u64 data;
@@ -2518,11 +2377,11 @@ static int get_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
return 0;
}
-int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
+int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
u64 data;
- switch (msr) {
+ switch (msr_info->index) {
case MSR_IA32_PLATFORM_ID:
case MSR_IA32_EBL_CR_POWERON:
case MSR_IA32_DEBUGCTLMSR:
@@ -2533,38 +2392,28 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case MSR_K8_SYSCFG:
case MSR_K7_HWCR:
case MSR_VM_HSAVE_PA:
- case MSR_K7_EVNTSEL0:
- case MSR_K7_EVNTSEL1:
- case MSR_K7_EVNTSEL2:
- case MSR_K7_EVNTSEL3:
- case MSR_K7_PERFCTR0:
- case MSR_K7_PERFCTR1:
- case MSR_K7_PERFCTR2:
- case MSR_K7_PERFCTR3:
case MSR_K8_INT_PENDING_MSG:
case MSR_AMD64_NB_CFG:
case MSR_FAM10H_MMIO_CONF_BASE:
case MSR_AMD64_BU_CFG2:
- data = 0;
+ msr_info->data = 0;
break;
- case MSR_P6_PERFCTR0:
- case MSR_P6_PERFCTR1:
- case MSR_P6_EVNTSEL0:
- case MSR_P6_EVNTSEL1:
- if (kvm_pmu_msr(vcpu, msr))
- return kvm_pmu_get_msr(vcpu, msr, pdata);
- data = 0;
+ case MSR_K7_EVNTSEL0 ... MSR_K7_EVNTSEL3:
+ case MSR_K7_PERFCTR0 ... MSR_K7_PERFCTR3:
+ case MSR_P6_PERFCTR0 ... MSR_P6_PERFCTR1:
+ case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL1:
+ if (kvm_pmu_is_valid_msr(vcpu, msr_info->index))
+ return kvm_pmu_get_msr(vcpu, msr_info->index, &msr_info->data);
+ msr_info->data = 0;
break;
case MSR_IA32_UCODE_REV:
- data = 0x100000000ULL;
+ msr_info->data = 0x100000000ULL;
break;
case MSR_MTRRcap:
- data = 0x500 | KVM_NR_VAR_MTRR;
- break;
case 0x200 ... 0x2ff:
- return get_msr_mtrr(vcpu, msr, pdata);
+ return kvm_mtrr_get_msr(vcpu, msr_info->index, &msr_info->data);
case 0xcd: /* fsb frequency */
- data = 3;
+ msr_info->data = 3;
break;
/*
* MSR_EBC_FREQUENCY_ID
@@ -2578,48 +2427,53 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
* multiplying by zero otherwise.
*/
case MSR_EBC_FREQUENCY_ID:
- data = 1 << 24;
+ msr_info->data = 1 << 24;
break;
case MSR_IA32_APICBASE:
- data = kvm_get_apic_base(vcpu);
+ msr_info->data = kvm_get_apic_base(vcpu);
break;
case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
- return kvm_x2apic_msr_read(vcpu, msr, pdata);
+ return kvm_x2apic_msr_read(vcpu, msr_info->index, &msr_info->data);
break;
case MSR_IA32_TSCDEADLINE:
- data = kvm_get_lapic_tscdeadline_msr(vcpu);
+ msr_info->data = kvm_get_lapic_tscdeadline_msr(vcpu);
break;
case MSR_IA32_TSC_ADJUST:
- data = (u64)vcpu->arch.ia32_tsc_adjust_msr;
+ msr_info->data = (u64)vcpu->arch.ia32_tsc_adjust_msr;
break;
case MSR_IA32_MISC_ENABLE:
- data = vcpu->arch.ia32_misc_enable_msr;
+ msr_info->data = vcpu->arch.ia32_misc_enable_msr;
+ break;
+ case MSR_IA32_SMBASE:
+ if (!msr_info->host_initiated)
+ return 1;
+ msr_info->data = vcpu->arch.smbase;
break;
case MSR_IA32_PERF_STATUS:
/* TSC increment by tick */
- data = 1000ULL;
+ msr_info->data = 1000ULL;
/* CPU multiplier */
data |= (((uint64_t)4ULL) << 40);
break;
case MSR_EFER:
- data = vcpu->arch.efer;
+ msr_info->data = vcpu->arch.efer;
break;
case MSR_KVM_WALL_CLOCK:
case MSR_KVM_WALL_CLOCK_NEW:
- data = vcpu->kvm->arch.wall_clock;
+ msr_info->data = vcpu->kvm->arch.wall_clock;
break;
case MSR_KVM_SYSTEM_TIME:
case MSR_KVM_SYSTEM_TIME_NEW:
- data = vcpu->arch.time;
+ msr_info->data = vcpu->arch.time;
break;
case MSR_KVM_ASYNC_PF_EN:
- data = vcpu->arch.apf.msr_val;
+ msr_info->data = vcpu->arch.apf.msr_val;
break;
case MSR_KVM_STEAL_TIME:
- data = vcpu->arch.st.msr_val;
+ msr_info->data = vcpu->arch.st.msr_val;
break;
case MSR_KVM_PV_EOI_EN:
- data = vcpu->arch.pv_eoi.msr_val;
+ msr_info->data = vcpu->arch.pv_eoi.msr_val;
break;
case MSR_IA32_P5_MC_ADDR:
case MSR_IA32_P5_MC_TYPE:
@@ -2627,7 +2481,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case MSR_IA32_MCG_CTL:
case MSR_IA32_MCG_STATUS:
case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1:
- return get_msr_mce(vcpu, msr, pdata);
+ return get_msr_mce(vcpu, msr_info->index, &msr_info->data);
case MSR_K7_CLK_CTL:
/*
* Provide expected ramp-up count for K7. All other
@@ -2638,17 +2492,17 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
* type 6, model 8 and higher from exploding due to
* the rdmsr failing.
*/
- data = 0x20000000;
+ msr_info->data = 0x20000000;
break;
case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
- if (kvm_hv_msr_partition_wide(msr)) {
+ if (kvm_hv_msr_partition_wide(msr_info->index)) {
int r;
mutex_lock(&vcpu->kvm->lock);
- r = get_msr_hyperv_pw(vcpu, msr, pdata);
+ r = get_msr_hyperv_pw(vcpu, msr_info->index, &msr_info->data);
mutex_unlock(&vcpu->kvm->lock);
return r;
} else
- return get_msr_hyperv(vcpu, msr, pdata);
+ return get_msr_hyperv(vcpu, msr_info->index, &msr_info->data);
break;
case MSR_IA32_BBL_CR_CTL3:
/* This legacy MSR exists but isn't fully documented in current
@@ -2661,31 +2515,30 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
* L2 cache control register 3: 64GB range, 256KB size,
* enabled, latency 0x1, configured
*/
- data = 0xbe702111;
+ msr_info->data = 0xbe702111;
break;
case MSR_AMD64_OSVW_ID_LENGTH:
if (!guest_cpuid_has_osvw(vcpu))
return 1;
- data = vcpu->arch.osvw.length;
+ msr_info->data = vcpu->arch.osvw.length;
break;
case MSR_AMD64_OSVW_STATUS:
if (!guest_cpuid_has_osvw(vcpu))
return 1;
- data = vcpu->arch.osvw.status;
+ msr_info->data = vcpu->arch.osvw.status;
break;
default:
- if (kvm_pmu_msr(vcpu, msr))
- return kvm_pmu_get_msr(vcpu, msr, pdata);
+ if (kvm_pmu_is_valid_msr(vcpu, msr_info->index))
+ return kvm_pmu_get_msr(vcpu, msr_info->index, &msr_info->data);
if (!ignore_msrs) {
- vcpu_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
+ vcpu_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr_info->index);
return 1;
} else {
- vcpu_unimpl(vcpu, "ignored rdmsr: 0x%x\n", msr);
- data = 0;
+ vcpu_unimpl(vcpu, "ignored rdmsr: 0x%x\n", msr_info->index);
+ msr_info->data = 0;
}
break;
}
- *pdata = data;
return 0;
}
EXPORT_SYMBOL_GPL(kvm_get_msr_common);
@@ -2798,12 +2651,25 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_HYPERV_TIME:
case KVM_CAP_IOAPIC_POLARITY_IGNORED:
case KVM_CAP_TSC_DEADLINE_TIMER:
+ case KVM_CAP_ENABLE_CAP_VM:
+ case KVM_CAP_DISABLE_QUIRKS:
#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
case KVM_CAP_ASSIGN_DEV_IRQ:
case KVM_CAP_PCI_2_3:
#endif
r = 1;
break;
+ case KVM_CAP_X86_SMM:
+ /* SMBASE is usually relocated above 1M on modern chipsets,
+ * and SMM handlers might indeed rely on 4G segment limits,
+ * so do not report SMM to be available if real mode is
+ * emulated via vm86 mode. Still, do not go to great lengths
+ * to avoid userspace's usage of the feature, because it is a
+ * fringe case that is not enabled except via specific settings
+ * of the module parameters.
+ */
+ r = kvm_x86_ops->cpu_has_high_real_mode_segbase();
+ break;
case KVM_CAP_COALESCED_MMIO:
r = KVM_COALESCED_MMIO_PAGE_OFFSET;
break;
@@ -2860,7 +2726,7 @@ long kvm_arch_dev_ioctl(struct file *filp,
if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list))
goto out;
n = msr_list.nmsrs;
- msr_list.nmsrs = num_msrs_to_save + ARRAY_SIZE(emulated_msrs);
+ msr_list.nmsrs = num_msrs_to_save + num_emulated_msrs;
if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list))
goto out;
r = -E2BIG;
@@ -2872,7 +2738,7 @@ long kvm_arch_dev_ioctl(struct file *filp,
goto out;
if (copy_to_user(user_msr_list->indices + num_msrs_to_save,
&emulated_msrs,
- ARRAY_SIZE(emulated_msrs) * sizeof(u32)))
+ num_emulated_msrs * sizeof(u32)))
goto out;
r = 0;
break;
@@ -3016,6 +2882,13 @@ static int kvm_vcpu_ioctl_nmi(struct kvm_vcpu *vcpu)
return 0;
}
+static int kvm_vcpu_ioctl_smi(struct kvm_vcpu *vcpu)
+{
+ kvm_make_request(KVM_REQ_SMI, vcpu);
+
+ return 0;
+}
+
static int vcpu_ioctl_tpr_access_reporting(struct kvm_vcpu *vcpu,
struct kvm_tpr_access_ctl *tac)
{
@@ -3121,8 +2994,15 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
events->sipi_vector = 0; /* never valid when reporting to user space */
+ events->smi.smm = is_smm(vcpu);
+ events->smi.pending = vcpu->arch.smi_pending;
+ events->smi.smm_inside_nmi =
+ !!(vcpu->arch.hflags & HF_SMM_INSIDE_NMI_MASK);
+ events->smi.latched_init = kvm_lapic_latched_init(vcpu);
+
events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
- | KVM_VCPUEVENT_VALID_SHADOW);
+ | KVM_VCPUEVENT_VALID_SHADOW
+ | KVM_VCPUEVENT_VALID_SMM);
memset(&events->reserved, 0, sizeof(events->reserved));
}
@@ -3131,7 +3011,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
{
if (events->flags & ~(KVM_VCPUEVENT_VALID_NMI_PENDING
| KVM_VCPUEVENT_VALID_SIPI_VECTOR
- | KVM_VCPUEVENT_VALID_SHADOW))
+ | KVM_VCPUEVENT_VALID_SHADOW
+ | KVM_VCPUEVENT_VALID_SMM))
return -EINVAL;
process_nmi(vcpu);
@@ -3156,6 +3037,24 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
kvm_vcpu_has_lapic(vcpu))
vcpu->arch.apic->sipi_vector = events->sipi_vector;
+ if (events->flags & KVM_VCPUEVENT_VALID_SMM) {
+ if (events->smi.smm)
+ vcpu->arch.hflags |= HF_SMM_MASK;
+ else
+ vcpu->arch.hflags &= ~HF_SMM_MASK;
+ vcpu->arch.smi_pending = events->smi.pending;
+ if (events->smi.smm_inside_nmi)
+ vcpu->arch.hflags |= HF_SMM_INSIDE_NMI_MASK;
+ else
+ vcpu->arch.hflags &= ~HF_SMM_INSIDE_NMI_MASK;
+ if (kvm_vcpu_has_lapic(vcpu)) {
+ if (events->smi.latched_init)
+ set_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
+ else
+ clear_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
+ }
+ }
+
kvm_make_request(KVM_REQ_EVENT, vcpu);
return 0;
@@ -3194,8 +3093,8 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
static void fill_xsave(u8 *dest, struct kvm_vcpu *vcpu)
{
- struct xsave_struct *xsave = &vcpu->arch.guest_fpu.state->xsave;
- u64 xstate_bv = xsave->xsave_hdr.xstate_bv;
+ struct xregs_state *xsave = &vcpu->arch.guest_fpu.state.xsave;
+ u64 xstate_bv = xsave->header.xfeatures;
u64 valid;
/*
@@ -3230,7 +3129,7 @@ static void fill_xsave(u8 *dest, struct kvm_vcpu *vcpu)
static void load_xsave(struct kvm_vcpu *vcpu, u8 *src)
{
- struct xsave_struct *xsave = &vcpu->arch.guest_fpu.state->xsave;
+ struct xregs_state *xsave = &vcpu->arch.guest_fpu.state.xsave;
u64 xstate_bv = *(u64 *)(src + XSAVE_HDR_OFFSET);
u64 valid;
@@ -3241,9 +3140,9 @@ static void load_xsave(struct kvm_vcpu *vcpu, u8 *src)
memcpy(xsave, src, XSAVE_HDR_OFFSET);
/* Set XSTATE_BV and possibly XCOMP_BV. */
- xsave->xsave_hdr.xstate_bv = xstate_bv;
+ xsave->header.xfeatures = xstate_bv;
if (cpu_has_xsaves)
- xsave->xsave_hdr.xcomp_bv = host_xcr0 | XSTATE_COMPACTION_ENABLED;
+ xsave->header.xcomp_bv = host_xcr0 | XSTATE_COMPACTION_ENABLED;
/*
* Copy each region from the non-compacted offset to the
@@ -3275,8 +3174,8 @@ static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
fill_xsave((u8 *) guest_xsave->region, vcpu);
} else {
memcpy(guest_xsave->region,
- &vcpu->arch.guest_fpu.state->fxsave,
- sizeof(struct i387_fxsave_struct));
+ &vcpu->arch.guest_fpu.state.fxsave,
+ sizeof(struct fxregs_state));
*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)] =
XSTATE_FPSSE;
}
@@ -3300,8 +3199,8 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
} else {
if (xstate_bv & ~XSTATE_FPSSE)
return -EINVAL;
- memcpy(&vcpu->arch.guest_fpu.state->fxsave,
- guest_xsave->region, sizeof(struct i387_fxsave_struct));
+ memcpy(&vcpu->arch.guest_fpu.state.fxsave,
+ guest_xsave->region, sizeof(struct fxregs_state));
}
return 0;
}
@@ -3415,6 +3314,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = kvm_vcpu_ioctl_nmi(vcpu);
break;
}
+ case KVM_SMI: {
+ r = kvm_vcpu_ioctl_smi(vcpu);
+ break;
+ }
case KVM_SET_CPUID: {
struct kvm_cpuid __user *cpuid_arg = argp;
struct kvm_cpuid cpuid;
@@ -3454,7 +3357,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
break;
}
case KVM_GET_MSRS:
- r = msr_io(vcpu, argp, kvm_get_msr, 1);
+ r = msr_io(vcpu, argp, do_get_msr, 1);
break;
case KVM_SET_MSRS:
r = msr_io(vcpu, argp, do_set_msr, 0);
@@ -3845,6 +3748,26 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event,
return 0;
}
+static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
+ struct kvm_enable_cap *cap)
+{
+ int r;
+
+ if (cap->flags)
+ return -EINVAL;
+
+ switch (cap->cap) {
+ case KVM_CAP_DISABLE_QUIRKS:
+ kvm->arch.disabled_quirks = cap->args[0];
+ r = 0;
+ break;
+ default:
+ r = -EINVAL;
+ break;
+ }
+ return r;
+}
+
long kvm_arch_vm_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -4097,7 +4020,15 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = 0;
break;
}
+ case KVM_ENABLE_CAP: {
+ struct kvm_enable_cap cap;
+ r = -EFAULT;
+ if (copy_from_user(&cap, argp, sizeof(cap)))
+ goto out;
+ r = kvm_vm_ioctl_enable_cap(kvm, &cap);
+ break;
+ }
default:
r = kvm_vm_ioctl_assigned_device(kvm, ioctl, arg);
}
@@ -4110,8 +4041,7 @@ static void kvm_init_msr_list(void)
u32 dummy[2];
unsigned i, j;
- /* skip the first msrs in the list. KVM-specific */
- for (i = j = KVM_SAVE_MSRS_BEGIN; i < ARRAY_SIZE(msrs_to_save); i++) {
+ for (i = j = 0; i < ARRAY_SIZE(msrs_to_save); i++) {
if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0)
continue;
@@ -4136,6 +4066,22 @@ static void kvm_init_msr_list(void)
j++;
}
num_msrs_to_save = j;
+
+ for (i = j = 0; i < ARRAY_SIZE(emulated_msrs); i++) {
+ switch (emulated_msrs[i]) {
+ case MSR_IA32_SMBASE:
+ if (!kvm_x86_ops->cpu_has_high_real_mode_segbase())
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ if (j < i)
+ emulated_msrs[j] = emulated_msrs[i];
+ j++;
+ }
+ num_emulated_msrs = j;
}
static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len,
@@ -4253,8 +4199,8 @@ static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
if (gpa == UNMAPPED_GVA)
return X86EMUL_PROPAGATE_FAULT;
- ret = kvm_read_guest_page(vcpu->kvm, gpa >> PAGE_SHIFT, data,
- offset, toread);
+ ret = kvm_vcpu_read_guest_page(vcpu, gpa >> PAGE_SHIFT, data,
+ offset, toread);
if (ret < 0) {
r = X86EMUL_IO_NEEDED;
goto out;
@@ -4287,8 +4233,8 @@ static int kvm_fetch_guest_virt(struct x86_emulate_ctxt *ctxt,
offset = addr & (PAGE_SIZE-1);
if (WARN_ON(offset + bytes > PAGE_SIZE))
bytes = (unsigned)PAGE_SIZE - offset;
- ret = kvm_read_guest_page(vcpu->kvm, gpa >> PAGE_SHIFT, val,
- offset, bytes);
+ ret = kvm_vcpu_read_guest_page(vcpu, gpa >> PAGE_SHIFT, val,
+ offset, bytes);
if (unlikely(ret < 0))
return X86EMUL_IO_NEEDED;
@@ -4334,7 +4280,7 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
if (gpa == UNMAPPED_GVA)
return X86EMUL_PROPAGATE_FAULT;
- ret = kvm_write_guest(vcpu->kvm, gpa, data, towrite);
+ ret = kvm_vcpu_write_guest(vcpu, gpa, data, towrite);
if (ret < 0) {
r = X86EMUL_IO_NEEDED;
goto out;
@@ -4387,7 +4333,7 @@ int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
{
int ret;
- ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes);
+ ret = kvm_vcpu_write_guest(vcpu, gpa, val, bytes);
if (ret < 0)
return 0;
kvm_mmu_pte_write(vcpu, gpa, val, bytes);
@@ -4421,7 +4367,7 @@ static int read_prepare(struct kvm_vcpu *vcpu, void *val, int bytes)
static int read_emulate(struct kvm_vcpu *vcpu, gpa_t gpa,
void *val, int bytes)
{
- return !kvm_read_guest(vcpu->kvm, gpa, val, bytes);
+ return !kvm_vcpu_read_guest(vcpu, gpa, val, bytes);
}
static int write_emulate(struct kvm_vcpu *vcpu, gpa_t gpa,
@@ -4619,7 +4565,7 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
if (((gpa + bytes - 1) & PAGE_MASK) != (gpa & PAGE_MASK))
goto emul_write;
- page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
+ page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT);
if (is_error_page(page))
goto emul_write;
@@ -4647,7 +4593,7 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
if (!exchanged)
return X86EMUL_CMPXCHG_FAILED;
- mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
+ kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
kvm_mmu_pte_write(vcpu, gpa, new, bytes);
return X86EMUL_CONTINUE;
@@ -4946,7 +4892,17 @@ static void emulator_set_segment(struct x86_emulate_ctxt *ctxt, u16 selector,
static int emulator_get_msr(struct x86_emulate_ctxt *ctxt,
u32 msr_index, u64 *pdata)
{
- return kvm_get_msr(emul_to_vcpu(ctxt), msr_index, pdata);
+ struct msr_data msr;
+ int r;
+
+ msr.index = msr_index;
+ msr.host_initiated = false;
+ r = kvm_get_msr(emul_to_vcpu(ctxt), &msr);
+ if (r)
+ return r;
+
+ *pdata = msr.data;
+ return 0;
}
static int emulator_set_msr(struct x86_emulate_ctxt *ctxt,
@@ -4960,16 +4916,30 @@ static int emulator_set_msr(struct x86_emulate_ctxt *ctxt,
return kvm_set_msr(emul_to_vcpu(ctxt), &msr);
}
+static u64 emulator_get_smbase(struct x86_emulate_ctxt *ctxt)
+{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
+
+ return vcpu->arch.smbase;
+}
+
+static void emulator_set_smbase(struct x86_emulate_ctxt *ctxt, u64 smbase)
+{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
+
+ vcpu->arch.smbase = smbase;
+}
+
static int emulator_check_pmc(struct x86_emulate_ctxt *ctxt,
u32 pmc)
{
- return kvm_pmu_check_pmc(emul_to_vcpu(ctxt), pmc);
+ return kvm_pmu_is_valid_msr_idx(emul_to_vcpu(ctxt), pmc);
}
static int emulator_read_pmc(struct x86_emulate_ctxt *ctxt,
u32 pmc, u64 *pdata)
{
- return kvm_pmu_read_pmc(emul_to_vcpu(ctxt), pmc, pdata);
+ return kvm_pmu_rdpmc(emul_to_vcpu(ctxt), pmc, pdata);
}
static void emulator_halt(struct x86_emulate_ctxt *ctxt)
@@ -5045,6 +5015,8 @@ static const struct x86_emulate_ops emulate_ops = {
.cpl = emulator_get_cpl,
.get_dr = emulator_get_dr,
.set_dr = emulator_set_dr,
+ .get_smbase = emulator_get_smbase,
+ .set_smbase = emulator_set_smbase,
.set_msr = emulator_set_msr,
.get_msr = emulator_get_msr,
.check_pmc = emulator_check_pmc,
@@ -5106,7 +5078,10 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu)
(cs_l && is_long_mode(vcpu)) ? X86EMUL_MODE_PROT64 :
cs_db ? X86EMUL_MODE_PROT32 :
X86EMUL_MODE_PROT16;
- ctxt->guest_mode = is_guest_mode(vcpu);
+ BUILD_BUG_ON(HF_GUEST_MASK != X86EMUL_GUEST_MASK);
+ BUILD_BUG_ON(HF_SMM_MASK != X86EMUL_SMM_MASK);
+ BUILD_BUG_ON(HF_SMM_INSIDE_NMI_MASK != X86EMUL_SMM_INSIDE_NMI_MASK);
+ ctxt->emul_flags = vcpu->arch.hflags;
init_decode_cache(ctxt);
vcpu->arch.emulate_regs_need_sync_from_vcpu = false;
@@ -5275,6 +5250,34 @@ static bool retry_instruction(struct x86_emulate_ctxt *ctxt,
static int complete_emulated_mmio(struct kvm_vcpu *vcpu);
static int complete_emulated_pio(struct kvm_vcpu *vcpu);
+static void kvm_smm_changed(struct kvm_vcpu *vcpu)
+{
+ if (!(vcpu->arch.hflags & HF_SMM_MASK)) {
+ /* This is a good place to trace that we are exiting SMM. */
+ trace_kvm_enter_smm(vcpu->vcpu_id, vcpu->arch.smbase, false);
+
+ if (unlikely(vcpu->arch.smi_pending)) {
+ kvm_make_request(KVM_REQ_SMI, vcpu);
+ vcpu->arch.smi_pending = 0;
+ } else {
+ /* Process a latched INIT, if any. */
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
+ }
+ }
+
+ kvm_mmu_reset_context(vcpu);
+}
+
+static void kvm_set_hflags(struct kvm_vcpu *vcpu, unsigned emul_flags)
+{
+ unsigned changed = vcpu->arch.hflags ^ emul_flags;
+
+ vcpu->arch.hflags = emul_flags;
+
+ if (changed & HF_SMM_MASK)
+ kvm_smm_changed(vcpu);
+}
+
static int kvm_vcpu_check_hw_bp(unsigned long addr, u32 type, u32 dr7,
unsigned long *db)
{
@@ -5474,6 +5477,8 @@ restart:
unsigned long rflags = kvm_x86_ops->get_rflags(vcpu);
toggle_interruptibility(vcpu, ctxt->interruptibility);
vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
+ if (vcpu->arch.hflags != ctxt->emul_flags)
+ kvm_set_hflags(vcpu, ctxt->emul_flags);
kvm_rip_write(vcpu, ctxt->eip);
if (r == EMULATE_DONE)
kvm_vcpu_check_singlestep(vcpu, rflags, &r);
@@ -5952,6 +5957,7 @@ static void kvm_pv_kick_cpu_op(struct kvm *kvm, unsigned long flags, int apicid)
lapic_irq.shorthand = 0;
lapic_irq.dest_mode = 0;
lapic_irq.dest_id = apicid;
+ lapic_irq.msi_redir_hint = false;
lapic_irq.delivery_mode = APIC_DM_REMRD;
kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL);
@@ -6039,6 +6045,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
struct kvm_run *kvm_run = vcpu->run;
kvm_run->if_flag = (kvm_get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
+ kvm_run->flags = is_smm(vcpu) ? KVM_RUN_X86_SMM : 0;
kvm_run->cr8 = kvm_get_cr8(vcpu);
kvm_run->apic_base = kvm_get_apic_base(vcpu);
if (irqchip_in_kernel(vcpu->kvm))
@@ -6162,6 +6169,233 @@ static void process_nmi(struct kvm_vcpu *vcpu)
kvm_make_request(KVM_REQ_EVENT, vcpu);
}
+#define put_smstate(type, buf, offset, val) \
+ *(type *)((buf) + (offset) - 0x7e00) = val
+
+static u32 process_smi_get_segment_flags(struct kvm_segment *seg)
+{
+ u32 flags = 0;
+ flags |= seg->g << 23;
+ flags |= seg->db << 22;
+ flags |= seg->l << 21;
+ flags |= seg->avl << 20;
+ flags |= seg->present << 15;
+ flags |= seg->dpl << 13;
+ flags |= seg->s << 12;
+ flags |= seg->type << 8;
+ return flags;
+}
+
+static void process_smi_save_seg_32(struct kvm_vcpu *vcpu, char *buf, int n)
+{
+ struct kvm_segment seg;
+ int offset;
+
+ kvm_get_segment(vcpu, &seg, n);
+ put_smstate(u32, buf, 0x7fa8 + n * 4, seg.selector);
+
+ if (n < 3)
+ offset = 0x7f84 + n * 12;
+ else
+ offset = 0x7f2c + (n - 3) * 12;
+
+ put_smstate(u32, buf, offset + 8, seg.base);
+ put_smstate(u32, buf, offset + 4, seg.limit);
+ put_smstate(u32, buf, offset, process_smi_get_segment_flags(&seg));
+}
+
+static void process_smi_save_seg_64(struct kvm_vcpu *vcpu, char *buf, int n)
+{
+ struct kvm_segment seg;
+ int offset;
+ u16 flags;
+
+ kvm_get_segment(vcpu, &seg, n);
+ offset = 0x7e00 + n * 16;
+
+ flags = process_smi_get_segment_flags(&seg) >> 8;
+ put_smstate(u16, buf, offset, seg.selector);
+ put_smstate(u16, buf, offset + 2, flags);
+ put_smstate(u32, buf, offset + 4, seg.limit);
+ put_smstate(u64, buf, offset + 8, seg.base);
+}
+
+static void process_smi_save_state_32(struct kvm_vcpu *vcpu, char *buf)
+{
+ struct desc_ptr dt;
+ struct kvm_segment seg;
+ unsigned long val;
+ int i;
+
+ put_smstate(u32, buf, 0x7ffc, kvm_read_cr0(vcpu));
+ put_smstate(u32, buf, 0x7ff8, kvm_read_cr3(vcpu));
+ put_smstate(u32, buf, 0x7ff4, kvm_get_rflags(vcpu));
+ put_smstate(u32, buf, 0x7ff0, kvm_rip_read(vcpu));
+
+ for (i = 0; i < 8; i++)
+ put_smstate(u32, buf, 0x7fd0 + i * 4, kvm_register_read(vcpu, i));
+
+ kvm_get_dr(vcpu, 6, &val);
+ put_smstate(u32, buf, 0x7fcc, (u32)val);
+ kvm_get_dr(vcpu, 7, &val);
+ put_smstate(u32, buf, 0x7fc8, (u32)val);
+
+ kvm_get_segment(vcpu, &seg, VCPU_SREG_TR);
+ put_smstate(u32, buf, 0x7fc4, seg.selector);
+ put_smstate(u32, buf, 0x7f64, seg.base);
+ put_smstate(u32, buf, 0x7f60, seg.limit);
+ put_smstate(u32, buf, 0x7f5c, process_smi_get_segment_flags(&seg));
+
+ kvm_get_segment(vcpu, &seg, VCPU_SREG_LDTR);
+ put_smstate(u32, buf, 0x7fc0, seg.selector);
+ put_smstate(u32, buf, 0x7f80, seg.base);
+ put_smstate(u32, buf, 0x7f7c, seg.limit);
+ put_smstate(u32, buf, 0x7f78, process_smi_get_segment_flags(&seg));
+
+ kvm_x86_ops->get_gdt(vcpu, &dt);
+ put_smstate(u32, buf, 0x7f74, dt.address);
+ put_smstate(u32, buf, 0x7f70, dt.size);
+
+ kvm_x86_ops->get_idt(vcpu, &dt);
+ put_smstate(u32, buf, 0x7f58, dt.address);
+ put_smstate(u32, buf, 0x7f54, dt.size);
+
+ for (i = 0; i < 6; i++)
+ process_smi_save_seg_32(vcpu, buf, i);
+
+ put_smstate(u32, buf, 0x7f14, kvm_read_cr4(vcpu));
+
+ /* revision id */
+ put_smstate(u32, buf, 0x7efc, 0x00020000);
+ put_smstate(u32, buf, 0x7ef8, vcpu->arch.smbase);
+}
+
+static void process_smi_save_state_64(struct kvm_vcpu *vcpu, char *buf)
+{
+#ifdef CONFIG_X86_64
+ struct desc_ptr dt;
+ struct kvm_segment seg;
+ unsigned long val;
+ int i;
+
+ for (i = 0; i < 16; i++)
+ put_smstate(u64, buf, 0x7ff8 - i * 8, kvm_register_read(vcpu, i));
+
+ put_smstate(u64, buf, 0x7f78, kvm_rip_read(vcpu));
+ put_smstate(u32, buf, 0x7f70, kvm_get_rflags(vcpu));
+
+ kvm_get_dr(vcpu, 6, &val);
+ put_smstate(u64, buf, 0x7f68, val);
+ kvm_get_dr(vcpu, 7, &val);
+ put_smstate(u64, buf, 0x7f60, val);
+
+ put_smstate(u64, buf, 0x7f58, kvm_read_cr0(vcpu));
+ put_smstate(u64, buf, 0x7f50, kvm_read_cr3(vcpu));
+ put_smstate(u64, buf, 0x7f48, kvm_read_cr4(vcpu));
+
+ put_smstate(u32, buf, 0x7f00, vcpu->arch.smbase);
+
+ /* revision id */
+ put_smstate(u32, buf, 0x7efc, 0x00020064);
+
+ put_smstate(u64, buf, 0x7ed0, vcpu->arch.efer);
+
+ kvm_get_segment(vcpu, &seg, VCPU_SREG_TR);
+ put_smstate(u16, buf, 0x7e90, seg.selector);
+ put_smstate(u16, buf, 0x7e92, process_smi_get_segment_flags(&seg) >> 8);
+ put_smstate(u32, buf, 0x7e94, seg.limit);
+ put_smstate(u64, buf, 0x7e98, seg.base);
+
+ kvm_x86_ops->get_idt(vcpu, &dt);
+ put_smstate(u32, buf, 0x7e84, dt.size);
+ put_smstate(u64, buf, 0x7e88, dt.address);
+
+ kvm_get_segment(vcpu, &seg, VCPU_SREG_LDTR);
+ put_smstate(u16, buf, 0x7e70, seg.selector);
+ put_smstate(u16, buf, 0x7e72, process_smi_get_segment_flags(&seg) >> 8);
+ put_smstate(u32, buf, 0x7e74, seg.limit);
+ put_smstate(u64, buf, 0x7e78, seg.base);
+
+ kvm_x86_ops->get_gdt(vcpu, &dt);
+ put_smstate(u32, buf, 0x7e64, dt.size);
+ put_smstate(u64, buf, 0x7e68, dt.address);
+
+ for (i = 0; i < 6; i++)
+ process_smi_save_seg_64(vcpu, buf, i);
+#else
+ WARN_ON_ONCE(1);
+#endif
+}
+
+static void process_smi(struct kvm_vcpu *vcpu)
+{
+ struct kvm_segment cs, ds;
+ char buf[512];
+ u32 cr0;
+
+ if (is_smm(vcpu)) {
+ vcpu->arch.smi_pending = true;
+ return;
+ }
+
+ trace_kvm_enter_smm(vcpu->vcpu_id, vcpu->arch.smbase, true);
+ vcpu->arch.hflags |= HF_SMM_MASK;
+ memset(buf, 0, 512);
+ if (guest_cpuid_has_longmode(vcpu))
+ process_smi_save_state_64(vcpu, buf);
+ else
+ process_smi_save_state_32(vcpu, buf);
+
+ kvm_vcpu_write_guest(vcpu, vcpu->arch.smbase + 0xfe00, buf, sizeof(buf));
+
+ if (kvm_x86_ops->get_nmi_mask(vcpu))
+ vcpu->arch.hflags |= HF_SMM_INSIDE_NMI_MASK;
+ else
+ kvm_x86_ops->set_nmi_mask(vcpu, true);
+
+ kvm_set_rflags(vcpu, X86_EFLAGS_FIXED);
+ kvm_rip_write(vcpu, 0x8000);
+
+ cr0 = vcpu->arch.cr0 & ~(X86_CR0_PE | X86_CR0_EM | X86_CR0_TS | X86_CR0_PG);
+ kvm_x86_ops->set_cr0(vcpu, cr0);
+ vcpu->arch.cr0 = cr0;
+
+ kvm_x86_ops->set_cr4(vcpu, 0);
+
+ __kvm_set_dr(vcpu, 7, DR7_FIXED_1);
+
+ cs.selector = (vcpu->arch.smbase >> 4) & 0xffff;
+ cs.base = vcpu->arch.smbase;
+
+ ds.selector = 0;
+ ds.base = 0;
+
+ cs.limit = ds.limit = 0xffffffff;
+ cs.type = ds.type = 0x3;
+ cs.dpl = ds.dpl = 0;
+ cs.db = ds.db = 0;
+ cs.s = ds.s = 1;
+ cs.l = ds.l = 0;
+ cs.g = ds.g = 1;
+ cs.avl = ds.avl = 0;
+ cs.present = ds.present = 1;
+ cs.unusable = ds.unusable = 0;
+ cs.padding = ds.padding = 0;
+
+ kvm_set_segment(vcpu, &cs, VCPU_SREG_CS);
+ kvm_set_segment(vcpu, &ds, VCPU_SREG_DS);
+ kvm_set_segment(vcpu, &ds, VCPU_SREG_ES);
+ kvm_set_segment(vcpu, &ds, VCPU_SREG_FS);
+ kvm_set_segment(vcpu, &ds, VCPU_SREG_GS);
+ kvm_set_segment(vcpu, &ds, VCPU_SREG_SS);
+
+ if (guest_cpuid_has_longmode(vcpu))
+ kvm_x86_ops->set_efer(vcpu, 0);
+
+ kvm_update_cpuid(vcpu);
+ kvm_mmu_reset_context(vcpu);
+}
+
static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
{
u64 eoi_exit_bitmap[4];
@@ -6270,12 +6504,14 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
}
if (kvm_check_request(KVM_REQ_STEAL_UPDATE, vcpu))
record_steal_time(vcpu);
+ if (kvm_check_request(KVM_REQ_SMI, vcpu))
+ process_smi(vcpu);
if (kvm_check_request(KVM_REQ_NMI, vcpu))
process_nmi(vcpu);
if (kvm_check_request(KVM_REQ_PMU, vcpu))
- kvm_handle_pmu_event(vcpu);
+ kvm_pmu_handle_event(vcpu);
if (kvm_check_request(KVM_REQ_PMI, vcpu))
- kvm_deliver_pmi(vcpu);
+ kvm_pmu_deliver_pmi(vcpu);
if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
vcpu_scan_ioapic(vcpu);
if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
@@ -6347,7 +6583,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
if (req_immediate_exit)
smp_send_reschedule(vcpu->cpu);
- kvm_guest_enter();
+ __kvm_guest_enter();
if (unlikely(vcpu->arch.switch_db_regs)) {
set_debugreg(0, 7);
@@ -6597,11 +6833,11 @@ static int complete_emulated_mmio(struct kvm_vcpu *vcpu)
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
+ struct fpu *fpu = &current->thread.fpu;
int r;
sigset_t sigsaved;
- if (!tsk_used_math(current) && init_fpu(current))
- return -ENOMEM;
+ fpu__activate_curr(fpu);
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
@@ -6971,8 +7207,8 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- struct i387_fxsave_struct *fxsave =
- &vcpu->arch.guest_fpu.state->fxsave;
+ struct fxregs_state *fxsave =
+ &vcpu->arch.guest_fpu.state.fxsave;
memcpy(fpu->fpr, fxsave->st_space, 128);
fpu->fcw = fxsave->cwd;
@@ -6988,8 +7224,8 @@ int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- struct i387_fxsave_struct *fxsave =
- &vcpu->arch.guest_fpu.state->fxsave;
+ struct fxregs_state *fxsave =
+ &vcpu->arch.guest_fpu.state.fxsave;
memcpy(fxsave->st_space, fpu->fpr, 128);
fxsave->cwd = fpu->fcw;
@@ -7003,17 +7239,11 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
return 0;
}
-int fx_init(struct kvm_vcpu *vcpu)
+static void fx_init(struct kvm_vcpu *vcpu)
{
- int err;
-
- err = fpu_alloc(&vcpu->arch.guest_fpu);
- if (err)
- return err;
-
- fpu_finit(&vcpu->arch.guest_fpu);
+ fpstate_init(&vcpu->arch.guest_fpu.state);
if (cpu_has_xsaves)
- vcpu->arch.guest_fpu.state->xsave.xsave_hdr.xcomp_bv =
+ vcpu->arch.guest_fpu.state.xsave.header.xcomp_bv =
host_xcr0 | XSTATE_COMPACTION_ENABLED;
/*
@@ -7022,14 +7252,6 @@ int fx_init(struct kvm_vcpu *vcpu)
vcpu->arch.xcr0 = XSTATE_FP;
vcpu->arch.cr0 |= X86_CR0_ET;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(fx_init);
-
-static void fx_free(struct kvm_vcpu *vcpu)
-{
- fpu_free(&vcpu->arch.guest_fpu);
}
void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
@@ -7045,7 +7267,7 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
kvm_put_guest_xcr0(vcpu);
vcpu->guest_fpu_loaded = 1;
__kernel_fpu_begin();
- fpu_restore_checking(&vcpu->arch.guest_fpu);
+ __copy_kernel_to_fpregs(&vcpu->arch.guest_fpu.state);
trace_kvm_fpu(1);
}
@@ -7053,16 +7275,25 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
{
kvm_put_guest_xcr0(vcpu);
- if (!vcpu->guest_fpu_loaded)
+ if (!vcpu->guest_fpu_loaded) {
+ vcpu->fpu_counter = 0;
return;
+ }
vcpu->guest_fpu_loaded = 0;
- fpu_save_init(&vcpu->arch.guest_fpu);
+ copy_fpregs_to_fpstate(&vcpu->arch.guest_fpu);
__kernel_fpu_end();
++vcpu->stat.fpu_reload;
- if (!vcpu->arch.eager_fpu)
- kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu);
-
+ /*
+ * If using eager FPU mode, or if the guest is a frequent user
+ * of the FPU, just leave the FPU active for next time.
+ * Every 255 times fpu_counter rolls over to 0; a guest that uses
+ * the FPU in bursts will revert to loading it on demand.
+ */
+ if (!vcpu->arch.eager_fpu) {
+ if (++vcpu->fpu_counter < 5)
+ kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu);
+ }
trace_kvm_fpu(0);
}
@@ -7071,7 +7302,6 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
kvmclock_reset(vcpu);
free_cpumask_var(vcpu->arch.wbinvd_dirty_mask);
- fx_free(vcpu);
kvm_x86_ops->vcpu_free(vcpu);
}
@@ -7099,14 +7329,13 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
int r;
- vcpu->arch.mtrr_state.have_fixed = 1;
+ kvm_vcpu_mtrr_init(vcpu);
r = vcpu_load(vcpu);
if (r)
return r;
- kvm_vcpu_reset(vcpu);
+ kvm_vcpu_reset(vcpu, false);
kvm_mmu_setup(vcpu);
vcpu_put(vcpu);
-
return r;
}
@@ -7123,6 +7352,9 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
kvm_write_tsc(vcpu, &msr);
vcpu_put(vcpu);
+ if (!kvmclock_periodic_sync)
+ return;
+
schedule_delayed_work(&kvm->arch.kvmclock_sync_work,
KVMCLOCK_SYNC_PERIOD);
}
@@ -7137,12 +7369,13 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
kvm_mmu_unload(vcpu);
vcpu_put(vcpu);
- fx_free(vcpu);
kvm_x86_ops->vcpu_free(vcpu);
}
-void kvm_vcpu_reset(struct kvm_vcpu *vcpu)
+void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
{
+ vcpu->arch.hflags = 0;
+
atomic_set(&vcpu->arch.nmi_queued, 0);
vcpu->arch.nmi_pending = 0;
vcpu->arch.nmi_injected = false;
@@ -7168,13 +7401,16 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu)
kvm_async_pf_hash_reset(vcpu);
vcpu->arch.apf.halted = false;
- kvm_pmu_reset(vcpu);
+ if (!init_event) {
+ kvm_pmu_reset(vcpu);
+ vcpu->arch.smbase = 0x30000;
+ }
memset(vcpu->arch.regs, 0, sizeof(vcpu->arch.regs));
vcpu->arch.regs_avail = ~0;
vcpu->arch.regs_dirty = ~0;
- kvm_x86_ops->vcpu_reset(vcpu);
+ kvm_x86_ops->vcpu_reset(vcpu, init_event);
}
void kvm_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector)
@@ -7363,9 +7599,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
goto fail_free_mce_banks;
}
- r = fx_init(vcpu);
- if (r)
- goto fail_free_wbinvd_dirty_mask;
+ fx_init(vcpu);
vcpu->arch.ia32_tsc_adjust_msr = 0x0;
vcpu->arch.pv_time_enabled = false;
@@ -7375,12 +7609,13 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu);
+ vcpu->arch.pat = MSR_IA32_CR_PAT_DEFAULT;
+
kvm_async_pf_hash_reset(vcpu);
kvm_pmu_init(vcpu);
return 0;
-fail_free_wbinvd_dirty_mask:
- free_cpumask_var(vcpu->arch.wbinvd_dirty_mask);
+
fail_free_mce_banks:
kfree(vcpu->arch.mce_banks);
fail_free_lapic:
@@ -7482,6 +7717,40 @@ void kvm_arch_sync_events(struct kvm *kvm)
kvm_free_pit(kvm);
}
+int __x86_set_memory_region(struct kvm *kvm,
+ const struct kvm_userspace_memory_region *mem)
+{
+ int i, r;
+
+ /* Called with kvm->slots_lock held. */
+ BUG_ON(mem->slot >= KVM_MEM_SLOTS_NUM);
+
+ for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+ struct kvm_userspace_memory_region m = *mem;
+
+ m.slot |= i << 16;
+ r = __kvm_set_memory_region(kvm, &m);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__x86_set_memory_region);
+
+int x86_set_memory_region(struct kvm *kvm,
+ const struct kvm_userspace_memory_region *mem)
+{
+ int r;
+
+ mutex_lock(&kvm->slots_lock);
+ r = __x86_set_memory_region(kvm, mem);
+ mutex_unlock(&kvm->slots_lock);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(x86_set_memory_region);
+
void kvm_arch_destroy_vm(struct kvm *kvm)
{
if (current->mm == kvm->mm) {
@@ -7493,13 +7762,13 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
struct kvm_userspace_memory_region mem;
memset(&mem, 0, sizeof(mem));
mem.slot = APIC_ACCESS_PAGE_PRIVATE_MEMSLOT;
- kvm_set_memory_region(kvm, &mem);
+ x86_set_memory_region(kvm, &mem);
mem.slot = IDENTITY_PAGETABLE_PRIVATE_MEMSLOT;
- kvm_set_memory_region(kvm, &mem);
+ x86_set_memory_region(kvm, &mem);
mem.slot = TSS_PRIVATE_MEMSLOT;
- kvm_set_memory_region(kvm, &mem);
+ x86_set_memory_region(kvm, &mem);
}
kvm_iommu_unmap_guest(kvm);
kfree(kvm->arch.vpic);
@@ -7588,18 +7857,18 @@ out_free:
return -ENOMEM;
}
-void kvm_arch_memslots_updated(struct kvm *kvm)
+void kvm_arch_memslots_updated(struct kvm *kvm, struct kvm_memslots *slots)
{
/*
* memslots->generation has been incremented.
* mmio generation may have reached its maximum value.
*/
- kvm_mmu_invalidate_mmio_sptes(kvm);
+ kvm_mmu_invalidate_mmio_sptes(kvm, slots);
}
int kvm_arch_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
- struct kvm_userspace_memory_region *mem,
+ const struct kvm_userspace_memory_region *mem,
enum kvm_mr_change change)
{
/*
@@ -7677,14 +7946,14 @@ static void kvm_mmu_slot_apply_flags(struct kvm *kvm,
}
void kvm_arch_commit_memory_region(struct kvm *kvm,
- struct kvm_userspace_memory_region *mem,
+ const struct kvm_userspace_memory_region *mem,
const struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new,
enum kvm_mr_change change)
{
- struct kvm_memory_slot *new;
int nr_mmu_pages = 0;
- if ((mem->slot >= KVM_USER_MEM_SLOTS) && (change == KVM_MR_DELETE)) {
+ if (change == KVM_MR_DELETE && old->id >= KVM_USER_MEM_SLOTS) {
int ret;
ret = vm_munmap(old->userspace_addr,
@@ -7701,9 +7970,6 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
if (nr_mmu_pages)
kvm_mmu_change_mmu_pages(kvm, nr_mmu_pages);
- /* It's OK to get 'new' slot here as it has already been installed */
- new = id_to_memslot(kvm->memslots, mem->slot);
-
/*
* Dirty logging tracks sptes in 4k granularity, meaning that large
* sptes have to be split. If live migration is successful, the guest
@@ -7728,9 +7994,11 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
* been zapped so no dirty logging staff is needed for old slot. For
* KVM_MR_FLAGS_ONLY, the old slot is essentially the same one as the
* new and it's also covered when dealing with the new slot.
+ *
+ * FIXME: const-ify all uses of struct kvm_memory_slot.
*/
if (change != KVM_MR_DELETE)
- kvm_mmu_slot_apply_flags(kvm, new);
+ kvm_mmu_slot_apply_flags(kvm, (struct kvm_memory_slot *) new);
}
void kvm_arch_flush_shadow_all(struct kvm *kvm)
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index f5fef1868096..edc8cdcd786b 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -4,6 +4,8 @@
#include <linux/kvm_host.h>
#include "kvm_cache_regs.h"
+#define MSR_IA32_CR_PAT_DEFAULT 0x0007040600070406ULL
+
static inline void kvm_clear_exception_queue(struct kvm_vcpu *vcpu)
{
vcpu->arch.exception.pending = false;
@@ -160,7 +162,13 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
gva_t addr, void *val, unsigned int bytes,
struct x86_exception *exception);
+void kvm_vcpu_mtrr_init(struct kvm_vcpu *vcpu);
+u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn);
bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data);
+int kvm_mtrr_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data);
+int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
+bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn,
+ int page_num);
#define KVM_SUPPORTED_XCR0 (XSTATE_FP | XSTATE_SSE | XSTATE_YMM \
| XSTATE_BNDREGS | XSTATE_BNDCSR \
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 8f9a133cc099..f2dc08c003eb 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -70,7 +70,7 @@
#include <asm/e820.h>
#include <asm/mce.h>
#include <asm/io.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
#include <asm/stackprotector.h>
#include <asm/reboot.h> /* for struct machine_ops */
#include <asm/kvm_para.h>
@@ -90,7 +90,7 @@ struct lguest_data lguest_data = {
.noirq_iret = (u32)lguest_noirq_iret,
.kernel_address = PAGE_OFFSET,
.blocked_interrupts = { 1 }, /* Block timer interrupts */
- .syscall_vec = SYSCALL_VECTOR,
+ .syscall_vec = IA32_SYSCALL_VECTOR,
};
/*G:037
@@ -866,7 +866,7 @@ static void __init lguest_init_IRQ(void)
for (i = FIRST_EXTERNAL_VECTOR; i < FIRST_SYSTEM_VECTOR; i++) {
/* Some systems map "vectors" to interrupts weirdly. Not us! */
__this_cpu_write(vector_irq[i], i - FIRST_EXTERNAL_VECTOR);
- if (i != SYSCALL_VECTOR)
+ if (i != IA32_SYSCALL_VECTOR)
set_intr_gate(i, irq_entries_start +
8 * (i - FIRST_EXTERNAL_VECTOR));
}
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 1530afb07c85..f2587888d987 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -17,7 +17,6 @@ clean-files := inat-tables.c
obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o
lib-y := delay.o misc.o cmdline.o
-lib-y += thunk_$(BITS).o
lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
lib-y += memcpy_$(BITS).o
lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
@@ -40,6 +39,6 @@ else
lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o
lib-y += clear_page_64.o copy_page_64.o
lib-y += memmove_64.o memset_64.o
- lib-y += copy_user_64.o copy_user_nocache_64.o
+ lib-y += copy_user_64.o
lib-y += cmpxchg16b_emu.o
endif
diff --git a/arch/x86/lib/atomic64_386_32.S b/arch/x86/lib/atomic64_386_32.S
index 00933d5e992f..9b0ca8fe80fc 100644
--- a/arch/x86/lib/atomic64_386_32.S
+++ b/arch/x86/lib/atomic64_386_32.S
@@ -11,26 +11,23 @@
#include <linux/linkage.h>
#include <asm/alternative-asm.h>
-#include <asm/dwarf2.h>
/* if you want SMP support, implement these with real spinlocks */
.macro LOCK reg
- pushfl_cfi
+ pushfl
cli
.endm
.macro UNLOCK reg
- popfl_cfi
+ popfl
.endm
#define BEGIN(op) \
.macro endp; \
- CFI_ENDPROC; \
ENDPROC(atomic64_##op##_386); \
.purgem endp; \
.endm; \
ENTRY(atomic64_##op##_386); \
- CFI_STARTPROC; \
LOCK v;
#define ENDP endp
diff --git a/arch/x86/lib/atomic64_cx8_32.S b/arch/x86/lib/atomic64_cx8_32.S
index 082a85167a5b..db3ae85440ff 100644
--- a/arch/x86/lib/atomic64_cx8_32.S
+++ b/arch/x86/lib/atomic64_cx8_32.S
@@ -11,7 +11,6 @@
#include <linux/linkage.h>
#include <asm/alternative-asm.h>
-#include <asm/dwarf2.h>
.macro read64 reg
movl %ebx, %eax
@@ -22,16 +21,11 @@
.endm
ENTRY(atomic64_read_cx8)
- CFI_STARTPROC
-
read64 %ecx
ret
- CFI_ENDPROC
ENDPROC(atomic64_read_cx8)
ENTRY(atomic64_set_cx8)
- CFI_STARTPROC
-
1:
/* we don't need LOCK_PREFIX since aligned 64-bit writes
* are atomic on 586 and newer */
@@ -39,28 +33,23 @@ ENTRY(atomic64_set_cx8)
jne 1b
ret
- CFI_ENDPROC
ENDPROC(atomic64_set_cx8)
ENTRY(atomic64_xchg_cx8)
- CFI_STARTPROC
-
1:
LOCK_PREFIX
cmpxchg8b (%esi)
jne 1b
ret
- CFI_ENDPROC
ENDPROC(atomic64_xchg_cx8)
.macro addsub_return func ins insc
ENTRY(atomic64_\func\()_return_cx8)
- CFI_STARTPROC
- pushl_cfi_reg ebp
- pushl_cfi_reg ebx
- pushl_cfi_reg esi
- pushl_cfi_reg edi
+ pushl %ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
movl %eax, %esi
movl %edx, %edi
@@ -79,12 +68,11 @@ ENTRY(atomic64_\func\()_return_cx8)
10:
movl %ebx, %eax
movl %ecx, %edx
- popl_cfi_reg edi
- popl_cfi_reg esi
- popl_cfi_reg ebx
- popl_cfi_reg ebp
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
ret
- CFI_ENDPROC
ENDPROC(atomic64_\func\()_return_cx8)
.endm
@@ -93,8 +81,7 @@ addsub_return sub sub sbb
.macro incdec_return func ins insc
ENTRY(atomic64_\func\()_return_cx8)
- CFI_STARTPROC
- pushl_cfi_reg ebx
+ pushl %ebx
read64 %esi
1:
@@ -109,9 +96,8 @@ ENTRY(atomic64_\func\()_return_cx8)
10:
movl %ebx, %eax
movl %ecx, %edx
- popl_cfi_reg ebx
+ popl %ebx
ret
- CFI_ENDPROC
ENDPROC(atomic64_\func\()_return_cx8)
.endm
@@ -119,8 +105,7 @@ incdec_return inc add adc
incdec_return dec sub sbb
ENTRY(atomic64_dec_if_positive_cx8)
- CFI_STARTPROC
- pushl_cfi_reg ebx
+ pushl %ebx
read64 %esi
1:
@@ -136,18 +121,16 @@ ENTRY(atomic64_dec_if_positive_cx8)
2:
movl %ebx, %eax
movl %ecx, %edx
- popl_cfi_reg ebx
+ popl %ebx
ret
- CFI_ENDPROC
ENDPROC(atomic64_dec_if_positive_cx8)
ENTRY(atomic64_add_unless_cx8)
- CFI_STARTPROC
- pushl_cfi_reg ebp
- pushl_cfi_reg ebx
+ pushl %ebp
+ pushl %ebx
/* these just push these two parameters on the stack */
- pushl_cfi_reg edi
- pushl_cfi_reg ecx
+ pushl %edi
+ pushl %ecx
movl %eax, %ebp
movl %edx, %edi
@@ -168,21 +151,18 @@ ENTRY(atomic64_add_unless_cx8)
movl $1, %eax
3:
addl $8, %esp
- CFI_ADJUST_CFA_OFFSET -8
- popl_cfi_reg ebx
- popl_cfi_reg ebp
+ popl %ebx
+ popl %ebp
ret
4:
cmpl %edx, 4(%esp)
jne 2b
xorl %eax, %eax
jmp 3b
- CFI_ENDPROC
ENDPROC(atomic64_add_unless_cx8)
ENTRY(atomic64_inc_not_zero_cx8)
- CFI_STARTPROC
- pushl_cfi_reg ebx
+ pushl %ebx
read64 %esi
1:
@@ -199,7 +179,6 @@ ENTRY(atomic64_inc_not_zero_cx8)
movl $1, %eax
3:
- popl_cfi_reg ebx
+ popl %ebx
ret
- CFI_ENDPROC
ENDPROC(atomic64_inc_not_zero_cx8)
diff --git a/arch/x86/lib/checksum_32.S b/arch/x86/lib/checksum_32.S
index 9bc944a91274..c1e623209853 100644
--- a/arch/x86/lib/checksum_32.S
+++ b/arch/x86/lib/checksum_32.S
@@ -26,7 +26,6 @@
*/
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
#include <asm/errno.h>
#include <asm/asm.h>
@@ -50,9 +49,8 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
* alignment for the unrolled loop.
*/
ENTRY(csum_partial)
- CFI_STARTPROC
- pushl_cfi_reg esi
- pushl_cfi_reg ebx
+ pushl %esi
+ pushl %ebx
movl 20(%esp),%eax # Function arg: unsigned int sum
movl 16(%esp),%ecx # Function arg: int len
movl 12(%esp),%esi # Function arg: unsigned char *buff
@@ -129,10 +127,9 @@ ENTRY(csum_partial)
jz 8f
roll $8, %eax
8:
- popl_cfi_reg ebx
- popl_cfi_reg esi
+ popl %ebx
+ popl %esi
ret
- CFI_ENDPROC
ENDPROC(csum_partial)
#else
@@ -140,9 +137,8 @@ ENDPROC(csum_partial)
/* Version for PentiumII/PPro */
ENTRY(csum_partial)
- CFI_STARTPROC
- pushl_cfi_reg esi
- pushl_cfi_reg ebx
+ pushl %esi
+ pushl %ebx
movl 20(%esp),%eax # Function arg: unsigned int sum
movl 16(%esp),%ecx # Function arg: int len
movl 12(%esp),%esi # Function arg: const unsigned char *buf
@@ -249,10 +245,9 @@ ENTRY(csum_partial)
jz 90f
roll $8, %eax
90:
- popl_cfi_reg ebx
- popl_cfi_reg esi
+ popl %ebx
+ popl %esi
ret
- CFI_ENDPROC
ENDPROC(csum_partial)
#endif
@@ -287,12 +282,10 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,
#define FP 12
ENTRY(csum_partial_copy_generic)
- CFI_STARTPROC
subl $4,%esp
- CFI_ADJUST_CFA_OFFSET 4
- pushl_cfi_reg edi
- pushl_cfi_reg esi
- pushl_cfi_reg ebx
+ pushl %edi
+ pushl %esi
+ pushl %ebx
movl ARGBASE+16(%esp),%eax # sum
movl ARGBASE+12(%esp),%ecx # len
movl ARGBASE+4(%esp),%esi # src
@@ -401,12 +394,11 @@ DST( movb %cl, (%edi) )
.previous
- popl_cfi_reg ebx
- popl_cfi_reg esi
- popl_cfi_reg edi
- popl_cfi %ecx # equivalent to addl $4,%esp
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ecx # equivalent to addl $4,%esp
ret
- CFI_ENDPROC
ENDPROC(csum_partial_copy_generic)
#else
@@ -426,10 +418,9 @@ ENDPROC(csum_partial_copy_generic)
#define ARGBASE 12
ENTRY(csum_partial_copy_generic)
- CFI_STARTPROC
- pushl_cfi_reg ebx
- pushl_cfi_reg edi
- pushl_cfi_reg esi
+ pushl %ebx
+ pushl %edi
+ pushl %esi
movl ARGBASE+4(%esp),%esi #src
movl ARGBASE+8(%esp),%edi #dst
movl ARGBASE+12(%esp),%ecx #len
@@ -489,11 +480,10 @@ DST( movb %dl, (%edi) )
jmp 7b
.previous
- popl_cfi_reg esi
- popl_cfi_reg edi
- popl_cfi_reg ebx
+ popl %esi
+ popl %edi
+ popl %ebx
ret
- CFI_ENDPROC
ENDPROC(csum_partial_copy_generic)
#undef ROUND
diff --git a/arch/x86/lib/clear_page_64.S b/arch/x86/lib/clear_page_64.S
index e67e579c93bd..a2fe51b00cce 100644
--- a/arch/x86/lib/clear_page_64.S
+++ b/arch/x86/lib/clear_page_64.S
@@ -1,5 +1,4 @@
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
#include <asm/cpufeature.h>
#include <asm/alternative-asm.h>
@@ -15,7 +14,6 @@
* %rdi - page
*/
ENTRY(clear_page)
- CFI_STARTPROC
ALTERNATIVE_2 "jmp clear_page_orig", "", X86_FEATURE_REP_GOOD, \
"jmp clear_page_c_e", X86_FEATURE_ERMS
@@ -24,11 +22,9 @@ ENTRY(clear_page)
xorl %eax,%eax
rep stosq
ret
- CFI_ENDPROC
ENDPROC(clear_page)
ENTRY(clear_page_orig)
- CFI_STARTPROC
xorl %eax,%eax
movl $4096/64,%ecx
@@ -48,14 +44,11 @@ ENTRY(clear_page_orig)
jnz .Lloop
nop
ret
- CFI_ENDPROC
ENDPROC(clear_page_orig)
ENTRY(clear_page_c_e)
- CFI_STARTPROC
movl $4096,%ecx
xorl %eax,%eax
rep stosb
ret
- CFI_ENDPROC
ENDPROC(clear_page_c_e)
diff --git a/arch/x86/lib/cmpxchg16b_emu.S b/arch/x86/lib/cmpxchg16b_emu.S
index 40a172541ee2..9b330242e740 100644
--- a/arch/x86/lib/cmpxchg16b_emu.S
+++ b/arch/x86/lib/cmpxchg16b_emu.S
@@ -6,7 +6,6 @@
*
*/
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
#include <asm/percpu.h>
.text
@@ -21,7 +20,6 @@
* %al : Operation successful
*/
ENTRY(this_cpu_cmpxchg16b_emu)
-CFI_STARTPROC
#
# Emulate 'cmpxchg16b %gs:(%rsi)' except we return the result in %al not
@@ -32,7 +30,7 @@ CFI_STARTPROC
# *atomic* on a single cpu (as provided by the this_cpu_xx class of
# macros).
#
- pushfq_cfi
+ pushfq
cli
cmpq PER_CPU_VAR((%rsi)), %rax
@@ -43,17 +41,13 @@ CFI_STARTPROC
movq %rbx, PER_CPU_VAR((%rsi))
movq %rcx, PER_CPU_VAR(8(%rsi))
- CFI_REMEMBER_STATE
- popfq_cfi
+ popfq
mov $1, %al
ret
- CFI_RESTORE_STATE
.Lnot_same:
- popfq_cfi
+ popfq
xor %al,%al
ret
-CFI_ENDPROC
-
ENDPROC(this_cpu_cmpxchg16b_emu)
diff --git a/arch/x86/lib/cmpxchg8b_emu.S b/arch/x86/lib/cmpxchg8b_emu.S
index b4807fce5177..ad5349778490 100644
--- a/arch/x86/lib/cmpxchg8b_emu.S
+++ b/arch/x86/lib/cmpxchg8b_emu.S
@@ -7,7 +7,6 @@
*/
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
.text
@@ -20,14 +19,13 @@
* %ecx : high 32 bits of new value
*/
ENTRY(cmpxchg8b_emu)
-CFI_STARTPROC
#
# Emulate 'cmpxchg8b (%esi)' on UP except we don't
# set the whole ZF thing (caller will just compare
# eax:edx with the expected value)
#
- pushfl_cfi
+ pushfl
cli
cmpl (%esi), %eax
@@ -38,18 +36,15 @@ CFI_STARTPROC
movl %ebx, (%esi)
movl %ecx, 4(%esi)
- CFI_REMEMBER_STATE
- popfl_cfi
+ popfl
ret
- CFI_RESTORE_STATE
.Lnot_same:
movl (%esi), %eax
.Lhalf_same:
movl 4(%esi), %edx
- popfl_cfi
+ popfl
ret
-CFI_ENDPROC
ENDPROC(cmpxchg8b_emu)
diff --git a/arch/x86/lib/copy_page_64.S b/arch/x86/lib/copy_page_64.S
index 8239dbcbf984..009f98216b7e 100644
--- a/arch/x86/lib/copy_page_64.S
+++ b/arch/x86/lib/copy_page_64.S
@@ -1,7 +1,6 @@
/* Written 2003 by Andi Kleen, based on a kernel by Evandro Menezes */
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
#include <asm/cpufeature.h>
#include <asm/alternative-asm.h>
@@ -13,22 +12,16 @@
*/
ALIGN
ENTRY(copy_page)
- CFI_STARTPROC
ALTERNATIVE "jmp copy_page_regs", "", X86_FEATURE_REP_GOOD
movl $4096/8, %ecx
rep movsq
ret
- CFI_ENDPROC
ENDPROC(copy_page)
ENTRY(copy_page_regs)
- CFI_STARTPROC
subq $2*8, %rsp
- CFI_ADJUST_CFA_OFFSET 2*8
movq %rbx, (%rsp)
- CFI_REL_OFFSET rbx, 0
movq %r12, 1*8(%rsp)
- CFI_REL_OFFSET r12, 1*8
movl $(4096/64)-5, %ecx
.p2align 4
@@ -87,11 +80,7 @@ ENTRY(copy_page_regs)
jnz .Loop2
movq (%rsp), %rbx
- CFI_RESTORE rbx
movq 1*8(%rsp), %r12
- CFI_RESTORE r12
addq $2*8, %rsp
- CFI_ADJUST_CFA_OFFSET -2*8
ret
- CFI_ENDPROC
ENDPROC(copy_page_regs)
diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S
index fa997dfaef24..982ce34f4a9b 100644
--- a/arch/x86/lib/copy_user_64.S
+++ b/arch/x86/lib/copy_user_64.S
@@ -7,7 +7,6 @@
*/
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
#include <asm/current.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
@@ -16,33 +15,8 @@
#include <asm/asm.h>
#include <asm/smap.h>
- .macro ALIGN_DESTINATION
- /* check for bad alignment of destination */
- movl %edi,%ecx
- andl $7,%ecx
- jz 102f /* already aligned */
- subl $8,%ecx
- negl %ecx
- subl %ecx,%edx
-100: movb (%rsi),%al
-101: movb %al,(%rdi)
- incq %rsi
- incq %rdi
- decl %ecx
- jnz 100b
-102:
- .section .fixup,"ax"
-103: addl %ecx,%edx /* ecx is zerorest also */
- jmp copy_user_handle_tail
- .previous
-
- _ASM_EXTABLE(100b,103b)
- _ASM_EXTABLE(101b,103b)
- .endm
-
/* Standard copy_to_user with segment limit checking */
ENTRY(_copy_to_user)
- CFI_STARTPROC
GET_THREAD_INFO(%rax)
movq %rdi,%rcx
addq %rdx,%rcx
@@ -54,12 +28,10 @@ ENTRY(_copy_to_user)
X86_FEATURE_REP_GOOD, \
"jmp copy_user_enhanced_fast_string", \
X86_FEATURE_ERMS
- CFI_ENDPROC
ENDPROC(_copy_to_user)
/* Standard copy_from_user with segment limit checking */
ENTRY(_copy_from_user)
- CFI_STARTPROC
GET_THREAD_INFO(%rax)
movq %rsi,%rcx
addq %rdx,%rcx
@@ -71,14 +43,12 @@ ENTRY(_copy_from_user)
X86_FEATURE_REP_GOOD, \
"jmp copy_user_enhanced_fast_string", \
X86_FEATURE_ERMS
- CFI_ENDPROC
ENDPROC(_copy_from_user)
.section .fixup,"ax"
/* must zero dest */
ENTRY(bad_from_user)
bad_from_user:
- CFI_STARTPROC
movl %edx,%ecx
xorl %eax,%eax
rep
@@ -86,7 +56,6 @@ bad_from_user:
bad_to_user:
movl %edx,%eax
ret
- CFI_ENDPROC
ENDPROC(bad_from_user)
.previous
@@ -104,7 +73,6 @@ ENDPROC(bad_from_user)
* eax uncopied bytes or 0 if successful.
*/
ENTRY(copy_user_generic_unrolled)
- CFI_STARTPROC
ASM_STAC
cmpl $8,%edx
jb 20f /* less then 8 bytes, go to byte copy loop */
@@ -186,7 +154,6 @@ ENTRY(copy_user_generic_unrolled)
_ASM_EXTABLE(19b,40b)
_ASM_EXTABLE(21b,50b)
_ASM_EXTABLE(22b,50b)
- CFI_ENDPROC
ENDPROC(copy_user_generic_unrolled)
/* Some CPUs run faster using the string copy instructions.
@@ -208,7 +175,6 @@ ENDPROC(copy_user_generic_unrolled)
* eax uncopied bytes or 0 if successful.
*/
ENTRY(copy_user_generic_string)
- CFI_STARTPROC
ASM_STAC
cmpl $8,%edx
jb 2f /* less than 8 bytes, go to byte copy loop */
@@ -233,7 +199,6 @@ ENTRY(copy_user_generic_string)
_ASM_EXTABLE(1b,11b)
_ASM_EXTABLE(3b,12b)
- CFI_ENDPROC
ENDPROC(copy_user_generic_string)
/*
@@ -249,7 +214,6 @@ ENDPROC(copy_user_generic_string)
* eax uncopied bytes or 0 if successful.
*/
ENTRY(copy_user_enhanced_fast_string)
- CFI_STARTPROC
ASM_STAC
movl %edx,%ecx
1: rep
@@ -264,5 +228,94 @@ ENTRY(copy_user_enhanced_fast_string)
.previous
_ASM_EXTABLE(1b,12b)
- CFI_ENDPROC
ENDPROC(copy_user_enhanced_fast_string)
+
+/*
+ * copy_user_nocache - Uncached memory copy with exception handling
+ * This will force destination/source out of cache for more performance.
+ */
+ENTRY(__copy_user_nocache)
+ ASM_STAC
+ cmpl $8,%edx
+ jb 20f /* less then 8 bytes, go to byte copy loop */
+ ALIGN_DESTINATION
+ movl %edx,%ecx
+ andl $63,%edx
+ shrl $6,%ecx
+ jz 17f
+1: movq (%rsi),%r8
+2: movq 1*8(%rsi),%r9
+3: movq 2*8(%rsi),%r10
+4: movq 3*8(%rsi),%r11
+5: movnti %r8,(%rdi)
+6: movnti %r9,1*8(%rdi)
+7: movnti %r10,2*8(%rdi)
+8: movnti %r11,3*8(%rdi)
+9: movq 4*8(%rsi),%r8
+10: movq 5*8(%rsi),%r9
+11: movq 6*8(%rsi),%r10
+12: movq 7*8(%rsi),%r11
+13: movnti %r8,4*8(%rdi)
+14: movnti %r9,5*8(%rdi)
+15: movnti %r10,6*8(%rdi)
+16: movnti %r11,7*8(%rdi)
+ leaq 64(%rsi),%rsi
+ leaq 64(%rdi),%rdi
+ decl %ecx
+ jnz 1b
+17: movl %edx,%ecx
+ andl $7,%edx
+ shrl $3,%ecx
+ jz 20f
+18: movq (%rsi),%r8
+19: movnti %r8,(%rdi)
+ leaq 8(%rsi),%rsi
+ leaq 8(%rdi),%rdi
+ decl %ecx
+ jnz 18b
+20: andl %edx,%edx
+ jz 23f
+ movl %edx,%ecx
+21: movb (%rsi),%al
+22: movb %al,(%rdi)
+ incq %rsi
+ incq %rdi
+ decl %ecx
+ jnz 21b
+23: xorl %eax,%eax
+ ASM_CLAC
+ sfence
+ ret
+
+ .section .fixup,"ax"
+30: shll $6,%ecx
+ addl %ecx,%edx
+ jmp 60f
+40: lea (%rdx,%rcx,8),%rdx
+ jmp 60f
+50: movl %ecx,%edx
+60: sfence
+ jmp copy_user_handle_tail
+ .previous
+
+ _ASM_EXTABLE(1b,30b)
+ _ASM_EXTABLE(2b,30b)
+ _ASM_EXTABLE(3b,30b)
+ _ASM_EXTABLE(4b,30b)
+ _ASM_EXTABLE(5b,30b)
+ _ASM_EXTABLE(6b,30b)
+ _ASM_EXTABLE(7b,30b)
+ _ASM_EXTABLE(8b,30b)
+ _ASM_EXTABLE(9b,30b)
+ _ASM_EXTABLE(10b,30b)
+ _ASM_EXTABLE(11b,30b)
+ _ASM_EXTABLE(12b,30b)
+ _ASM_EXTABLE(13b,30b)
+ _ASM_EXTABLE(14b,30b)
+ _ASM_EXTABLE(15b,30b)
+ _ASM_EXTABLE(16b,30b)
+ _ASM_EXTABLE(18b,40b)
+ _ASM_EXTABLE(19b,40b)
+ _ASM_EXTABLE(21b,50b)
+ _ASM_EXTABLE(22b,50b)
+ENDPROC(__copy_user_nocache)
diff --git a/arch/x86/lib/copy_user_nocache_64.S b/arch/x86/lib/copy_user_nocache_64.S
deleted file mode 100644
index 6a4f43c2d9e6..000000000000
--- a/arch/x86/lib/copy_user_nocache_64.S
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2008 Vitaly Mayatskikh <vmayatsk@redhat.com>
- * Copyright 2002 Andi Kleen, SuSE Labs.
- * Subject to the GNU Public License v2.
- *
- * Functions to copy from and to user space.
- */
-
-#include <linux/linkage.h>
-#include <asm/dwarf2.h>
-
-#define FIX_ALIGNMENT 1
-
-#include <asm/current.h>
-#include <asm/asm-offsets.h>
-#include <asm/thread_info.h>
-#include <asm/asm.h>
-#include <asm/smap.h>
-
- .macro ALIGN_DESTINATION
-#ifdef FIX_ALIGNMENT
- /* check for bad alignment of destination */
- movl %edi,%ecx
- andl $7,%ecx
- jz 102f /* already aligned */
- subl $8,%ecx
- negl %ecx
- subl %ecx,%edx
-100: movb (%rsi),%al
-101: movb %al,(%rdi)
- incq %rsi
- incq %rdi
- decl %ecx
- jnz 100b
-102:
- .section .fixup,"ax"
-103: addl %ecx,%edx /* ecx is zerorest also */
- jmp copy_user_handle_tail
- .previous
-
- _ASM_EXTABLE(100b,103b)
- _ASM_EXTABLE(101b,103b)
-#endif
- .endm
-
-/*
- * copy_user_nocache - Uncached memory copy with exception handling
- * This will force destination/source out of cache for more performance.
- */
-ENTRY(__copy_user_nocache)
- CFI_STARTPROC
- ASM_STAC
- cmpl $8,%edx
- jb 20f /* less then 8 bytes, go to byte copy loop */
- ALIGN_DESTINATION
- movl %edx,%ecx
- andl $63,%edx
- shrl $6,%ecx
- jz 17f
-1: movq (%rsi),%r8
-2: movq 1*8(%rsi),%r9
-3: movq 2*8(%rsi),%r10
-4: movq 3*8(%rsi),%r11
-5: movnti %r8,(%rdi)
-6: movnti %r9,1*8(%rdi)
-7: movnti %r10,2*8(%rdi)
-8: movnti %r11,3*8(%rdi)
-9: movq 4*8(%rsi),%r8
-10: movq 5*8(%rsi),%r9
-11: movq 6*8(%rsi),%r10
-12: movq 7*8(%rsi),%r11
-13: movnti %r8,4*8(%rdi)
-14: movnti %r9,5*8(%rdi)
-15: movnti %r10,6*8(%rdi)
-16: movnti %r11,7*8(%rdi)
- leaq 64(%rsi),%rsi
- leaq 64(%rdi),%rdi
- decl %ecx
- jnz 1b
-17: movl %edx,%ecx
- andl $7,%edx
- shrl $3,%ecx
- jz 20f
-18: movq (%rsi),%r8
-19: movnti %r8,(%rdi)
- leaq 8(%rsi),%rsi
- leaq 8(%rdi),%rdi
- decl %ecx
- jnz 18b
-20: andl %edx,%edx
- jz 23f
- movl %edx,%ecx
-21: movb (%rsi),%al
-22: movb %al,(%rdi)
- incq %rsi
- incq %rdi
- decl %ecx
- jnz 21b
-23: xorl %eax,%eax
- ASM_CLAC
- sfence
- ret
-
- .section .fixup,"ax"
-30: shll $6,%ecx
- addl %ecx,%edx
- jmp 60f
-40: lea (%rdx,%rcx,8),%rdx
- jmp 60f
-50: movl %ecx,%edx
-60: sfence
- jmp copy_user_handle_tail
- .previous
-
- _ASM_EXTABLE(1b,30b)
- _ASM_EXTABLE(2b,30b)
- _ASM_EXTABLE(3b,30b)
- _ASM_EXTABLE(4b,30b)
- _ASM_EXTABLE(5b,30b)
- _ASM_EXTABLE(6b,30b)
- _ASM_EXTABLE(7b,30b)
- _ASM_EXTABLE(8b,30b)
- _ASM_EXTABLE(9b,30b)
- _ASM_EXTABLE(10b,30b)
- _ASM_EXTABLE(11b,30b)
- _ASM_EXTABLE(12b,30b)
- _ASM_EXTABLE(13b,30b)
- _ASM_EXTABLE(14b,30b)
- _ASM_EXTABLE(15b,30b)
- _ASM_EXTABLE(16b,30b)
- _ASM_EXTABLE(18b,40b)
- _ASM_EXTABLE(19b,40b)
- _ASM_EXTABLE(21b,50b)
- _ASM_EXTABLE(22b,50b)
- CFI_ENDPROC
-ENDPROC(__copy_user_nocache)
diff --git a/arch/x86/lib/csum-copy_64.S b/arch/x86/lib/csum-copy_64.S
index 9734182966f3..7e48807b2fa1 100644
--- a/arch/x86/lib/csum-copy_64.S
+++ b/arch/x86/lib/csum-copy_64.S
@@ -6,7 +6,6 @@
* for more details. No warranty for anything given at all.
*/
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
#include <asm/errno.h>
#include <asm/asm.h>
@@ -47,23 +46,16 @@
ENTRY(csum_partial_copy_generic)
- CFI_STARTPROC
cmpl $3*64, %edx
jle .Lignore
.Lignore:
subq $7*8, %rsp
- CFI_ADJUST_CFA_OFFSET 7*8
movq %rbx, 2*8(%rsp)
- CFI_REL_OFFSET rbx, 2*8
movq %r12, 3*8(%rsp)
- CFI_REL_OFFSET r12, 3*8
movq %r14, 4*8(%rsp)
- CFI_REL_OFFSET r14, 4*8
movq %r13, 5*8(%rsp)
- CFI_REL_OFFSET r13, 5*8
movq %rbp, 6*8(%rsp)
- CFI_REL_OFFSET rbp, 6*8
movq %r8, (%rsp)
movq %r9, 1*8(%rsp)
@@ -206,22 +198,14 @@ ENTRY(csum_partial_copy_generic)
addl %ebx, %eax
adcl %r9d, %eax /* carry */
- CFI_REMEMBER_STATE
.Lende:
movq 2*8(%rsp), %rbx
- CFI_RESTORE rbx
movq 3*8(%rsp), %r12
- CFI_RESTORE r12
movq 4*8(%rsp), %r14
- CFI_RESTORE r14
movq 5*8(%rsp), %r13
- CFI_RESTORE r13
movq 6*8(%rsp), %rbp
- CFI_RESTORE rbp
addq $7*8, %rsp
- CFI_ADJUST_CFA_OFFSET -7*8
ret
- CFI_RESTORE_STATE
/* Exception handlers. Very simple, zeroing is done in the wrappers */
.Lbad_source:
@@ -237,5 +221,4 @@ ENTRY(csum_partial_copy_generic)
jz .Lende
movl $-EFAULT, (%rax)
jmp .Lende
- CFI_ENDPROC
ENDPROC(csum_partial_copy_generic)
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index a4512359656a..46668cda4ffd 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -26,7 +26,6 @@
*/
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
#include <asm/page_types.h>
#include <asm/errno.h>
#include <asm/asm-offsets.h>
@@ -36,7 +35,6 @@
.text
ENTRY(__get_user_1)
- CFI_STARTPROC
GET_THREAD_INFO(%_ASM_DX)
cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
jae bad_get_user
@@ -45,11 +43,9 @@ ENTRY(__get_user_1)
xor %eax,%eax
ASM_CLAC
ret
- CFI_ENDPROC
ENDPROC(__get_user_1)
ENTRY(__get_user_2)
- CFI_STARTPROC
add $1,%_ASM_AX
jc bad_get_user
GET_THREAD_INFO(%_ASM_DX)
@@ -60,11 +56,9 @@ ENTRY(__get_user_2)
xor %eax,%eax
ASM_CLAC
ret
- CFI_ENDPROC
ENDPROC(__get_user_2)
ENTRY(__get_user_4)
- CFI_STARTPROC
add $3,%_ASM_AX
jc bad_get_user
GET_THREAD_INFO(%_ASM_DX)
@@ -75,11 +69,9 @@ ENTRY(__get_user_4)
xor %eax,%eax
ASM_CLAC
ret
- CFI_ENDPROC
ENDPROC(__get_user_4)
ENTRY(__get_user_8)
- CFI_STARTPROC
#ifdef CONFIG_X86_64
add $7,%_ASM_AX
jc bad_get_user
@@ -104,28 +96,23 @@ ENTRY(__get_user_8)
ASM_CLAC
ret
#endif
- CFI_ENDPROC
ENDPROC(__get_user_8)
bad_get_user:
- CFI_STARTPROC
xor %edx,%edx
mov $(-EFAULT),%_ASM_AX
ASM_CLAC
ret
- CFI_ENDPROC
END(bad_get_user)
#ifdef CONFIG_X86_32
bad_get_user_8:
- CFI_STARTPROC
xor %edx,%edx
xor %ecx,%ecx
mov $(-EFAULT),%_ASM_AX
ASM_CLAC
ret
- CFI_ENDPROC
END(bad_get_user_8)
#endif
diff --git a/arch/x86/lib/iomap_copy_64.S b/arch/x86/lib/iomap_copy_64.S
index 05a95e713da8..33147fef3452 100644
--- a/arch/x86/lib/iomap_copy_64.S
+++ b/arch/x86/lib/iomap_copy_64.S
@@ -16,15 +16,12 @@
*/
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
/*
* override generic version in lib/iomap_copy.c
*/
ENTRY(__iowrite32_copy)
- CFI_STARTPROC
movl %edx,%ecx
rep movsd
ret
- CFI_ENDPROC
ENDPROC(__iowrite32_copy)
diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S
index b046664f5a1c..16698bba87de 100644
--- a/arch/x86/lib/memcpy_64.S
+++ b/arch/x86/lib/memcpy_64.S
@@ -2,7 +2,6 @@
#include <linux/linkage.h>
#include <asm/cpufeature.h>
-#include <asm/dwarf2.h>
#include <asm/alternative-asm.h>
/*
@@ -53,7 +52,6 @@ ENTRY(memcpy_erms)
ENDPROC(memcpy_erms)
ENTRY(memcpy_orig)
- CFI_STARTPROC
movq %rdi, %rax
cmpq $0x20, %rdx
@@ -178,5 +176,4 @@ ENTRY(memcpy_orig)
.Lend:
retq
- CFI_ENDPROC
ENDPROC(memcpy_orig)
diff --git a/arch/x86/lib/memmove_64.S b/arch/x86/lib/memmove_64.S
index 0f8a0d0331b9..ca2afdd6d98e 100644
--- a/arch/x86/lib/memmove_64.S
+++ b/arch/x86/lib/memmove_64.S
@@ -6,7 +6,6 @@
* - Copyright 2011 Fenghua Yu <fenghua.yu@intel.com>
*/
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
#include <asm/cpufeature.h>
#include <asm/alternative-asm.h>
@@ -27,7 +26,6 @@
ENTRY(memmove)
ENTRY(__memmove)
- CFI_STARTPROC
/* Handle more 32 bytes in loop */
mov %rdi, %rax
@@ -207,6 +205,5 @@ ENTRY(__memmove)
movb %r11b, (%rdi)
13:
retq
- CFI_ENDPROC
ENDPROC(__memmove)
ENDPROC(memmove)
diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S
index 93118fb23976..2661fad05827 100644
--- a/arch/x86/lib/memset_64.S
+++ b/arch/x86/lib/memset_64.S
@@ -1,7 +1,6 @@
/* Copyright 2002 Andi Kleen, SuSE Labs */
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
#include <asm/cpufeature.h>
#include <asm/alternative-asm.h>
@@ -66,7 +65,6 @@ ENTRY(memset_erms)
ENDPROC(memset_erms)
ENTRY(memset_orig)
- CFI_STARTPROC
movq %rdi,%r10
/* expand byte value */
@@ -78,7 +76,6 @@ ENTRY(memset_orig)
movl %edi,%r9d
andl $7,%r9d
jnz .Lbad_alignment
- CFI_REMEMBER_STATE
.Lafter_bad_alignment:
movq %rdx,%rcx
@@ -128,7 +125,6 @@ ENTRY(memset_orig)
movq %r10,%rax
ret
- CFI_RESTORE_STATE
.Lbad_alignment:
cmpq $7,%rdx
jbe .Lhandle_7
@@ -139,5 +135,4 @@ ENTRY(memset_orig)
subq %r8,%rdx
jmp .Lafter_bad_alignment
.Lfinal:
- CFI_ENDPROC
ENDPROC(memset_orig)
diff --git a/arch/x86/lib/mmx_32.c b/arch/x86/lib/mmx_32.c
index c9f2d9ba8dd8..e5e3ed8dc079 100644
--- a/arch/x86/lib/mmx_32.c
+++ b/arch/x86/lib/mmx_32.c
@@ -22,7 +22,7 @@
#include <linux/sched.h>
#include <linux/types.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
#include <asm/asm.h>
void *_mmx_memcpy(void *to, const void *from, size_t len)
diff --git a/arch/x86/lib/msr-reg.S b/arch/x86/lib/msr-reg.S
index 3ca5218fbece..c81556409bbb 100644
--- a/arch/x86/lib/msr-reg.S
+++ b/arch/x86/lib/msr-reg.S
@@ -1,6 +1,5 @@
#include <linux/linkage.h>
#include <linux/errno.h>
-#include <asm/dwarf2.h>
#include <asm/asm.h>
#include <asm/msr.h>
@@ -13,9 +12,8 @@
*/
.macro op_safe_regs op
ENTRY(\op\()_safe_regs)
- CFI_STARTPROC
- pushq_cfi_reg rbx
- pushq_cfi_reg rbp
+ pushq %rbx
+ pushq %rbp
movq %rdi, %r10 /* Save pointer */
xorl %r11d, %r11d /* Return value */
movl (%rdi), %eax
@@ -25,7 +23,6 @@ ENTRY(\op\()_safe_regs)
movl 20(%rdi), %ebp
movl 24(%rdi), %esi
movl 28(%rdi), %edi
- CFI_REMEMBER_STATE
1: \op
2: movl %eax, (%r10)
movl %r11d, %eax /* Return value */
@@ -35,16 +32,14 @@ ENTRY(\op\()_safe_regs)
movl %ebp, 20(%r10)
movl %esi, 24(%r10)
movl %edi, 28(%r10)
- popq_cfi_reg rbp
- popq_cfi_reg rbx
+ popq %rbp
+ popq %rbx
ret
3:
- CFI_RESTORE_STATE
movl $-EIO, %r11d
jmp 2b
_ASM_EXTABLE(1b, 3b)
- CFI_ENDPROC
ENDPROC(\op\()_safe_regs)
.endm
@@ -52,13 +47,12 @@ ENDPROC(\op\()_safe_regs)
.macro op_safe_regs op
ENTRY(\op\()_safe_regs)
- CFI_STARTPROC
- pushl_cfi_reg ebx
- pushl_cfi_reg ebp
- pushl_cfi_reg esi
- pushl_cfi_reg edi
- pushl_cfi $0 /* Return value */
- pushl_cfi %eax
+ pushl %ebx
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushl $0 /* Return value */
+ pushl %eax
movl 4(%eax), %ecx
movl 8(%eax), %edx
movl 12(%eax), %ebx
@@ -66,32 +60,28 @@ ENTRY(\op\()_safe_regs)
movl 24(%eax), %esi
movl 28(%eax), %edi
movl (%eax), %eax
- CFI_REMEMBER_STATE
1: \op
-2: pushl_cfi %eax
+2: pushl %eax
movl 4(%esp), %eax
- popl_cfi (%eax)
+ popl (%eax)
addl $4, %esp
- CFI_ADJUST_CFA_OFFSET -4
movl %ecx, 4(%eax)
movl %edx, 8(%eax)
movl %ebx, 12(%eax)
movl %ebp, 20(%eax)
movl %esi, 24(%eax)
movl %edi, 28(%eax)
- popl_cfi %eax
- popl_cfi_reg edi
- popl_cfi_reg esi
- popl_cfi_reg ebp
- popl_cfi_reg ebx
+ popl %eax
+ popl %edi
+ popl %esi
+ popl %ebp
+ popl %ebx
ret
3:
- CFI_RESTORE_STATE
movl $-EIO, 4(%esp)
jmp 2b
_ASM_EXTABLE(1b, 3b)
- CFI_ENDPROC
ENDPROC(\op\()_safe_regs)
.endm
diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S
index fc6ba17a7eec..e0817a12d323 100644
--- a/arch/x86/lib/putuser.S
+++ b/arch/x86/lib/putuser.S
@@ -11,7 +11,6 @@
* return value.
*/
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
#include <asm/thread_info.h>
#include <asm/errno.h>
#include <asm/asm.h>
@@ -30,11 +29,9 @@
* as they get called from within inline assembly.
*/
-#define ENTER CFI_STARTPROC ; \
- GET_THREAD_INFO(%_ASM_BX)
+#define ENTER GET_THREAD_INFO(%_ASM_BX)
#define EXIT ASM_CLAC ; \
- ret ; \
- CFI_ENDPROC
+ ret
.text
ENTRY(__put_user_1)
@@ -87,7 +84,6 @@ ENTRY(__put_user_8)
ENDPROC(__put_user_8)
bad_put_user:
- CFI_STARTPROC
movl $-EFAULT,%eax
EXIT
END(bad_put_user)
diff --git a/arch/x86/lib/rwsem.S b/arch/x86/lib/rwsem.S
index 2322abe4da3b..40027db99140 100644
--- a/arch/x86/lib/rwsem.S
+++ b/arch/x86/lib/rwsem.S
@@ -15,7 +15,6 @@
#include <linux/linkage.h>
#include <asm/alternative-asm.h>
-#include <asm/dwarf2.h>
#define __ASM_HALF_REG(reg) __ASM_SEL(reg, e##reg)
#define __ASM_HALF_SIZE(inst) __ASM_SEL(inst##w, inst##l)
@@ -34,10 +33,10 @@
*/
#define save_common_regs \
- pushl_cfi_reg ecx
+ pushl %ecx
#define restore_common_regs \
- popl_cfi_reg ecx
+ popl %ecx
/* Avoid uglifying the argument copying x86-64 needs to do. */
.macro movq src, dst
@@ -64,50 +63,45 @@
*/
#define save_common_regs \
- pushq_cfi_reg rdi; \
- pushq_cfi_reg rsi; \
- pushq_cfi_reg rcx; \
- pushq_cfi_reg r8; \
- pushq_cfi_reg r9; \
- pushq_cfi_reg r10; \
- pushq_cfi_reg r11
+ pushq %rdi; \
+ pushq %rsi; \
+ pushq %rcx; \
+ pushq %r8; \
+ pushq %r9; \
+ pushq %r10; \
+ pushq %r11
#define restore_common_regs \
- popq_cfi_reg r11; \
- popq_cfi_reg r10; \
- popq_cfi_reg r9; \
- popq_cfi_reg r8; \
- popq_cfi_reg rcx; \
- popq_cfi_reg rsi; \
- popq_cfi_reg rdi
+ popq %r11; \
+ popq %r10; \
+ popq %r9; \
+ popq %r8; \
+ popq %rcx; \
+ popq %rsi; \
+ popq %rdi
#endif
/* Fix up special calling conventions */
ENTRY(call_rwsem_down_read_failed)
- CFI_STARTPROC
save_common_regs
- __ASM_SIZE(push,_cfi_reg) __ASM_REG(dx)
+ __ASM_SIZE(push,) %__ASM_REG(dx)
movq %rax,%rdi
call rwsem_down_read_failed
- __ASM_SIZE(pop,_cfi_reg) __ASM_REG(dx)
+ __ASM_SIZE(pop,) %__ASM_REG(dx)
restore_common_regs
ret
- CFI_ENDPROC
ENDPROC(call_rwsem_down_read_failed)
ENTRY(call_rwsem_down_write_failed)
- CFI_STARTPROC
save_common_regs
movq %rax,%rdi
call rwsem_down_write_failed
restore_common_regs
ret
- CFI_ENDPROC
ENDPROC(call_rwsem_down_write_failed)
ENTRY(call_rwsem_wake)
- CFI_STARTPROC
/* do nothing if still outstanding active readers */
__ASM_HALF_SIZE(dec) %__ASM_HALF_REG(dx)
jnz 1f
@@ -116,17 +110,14 @@ ENTRY(call_rwsem_wake)
call rwsem_wake
restore_common_regs
1: ret
- CFI_ENDPROC
ENDPROC(call_rwsem_wake)
ENTRY(call_rwsem_downgrade_wake)
- CFI_STARTPROC
save_common_regs
- __ASM_SIZE(push,_cfi_reg) __ASM_REG(dx)
+ __ASM_SIZE(push,) %__ASM_REG(dx)
movq %rax,%rdi
call rwsem_downgrade_wake
- __ASM_SIZE(pop,_cfi_reg) __ASM_REG(dx)
+ __ASM_SIZE(pop,) %__ASM_REG(dx)
restore_common_regs
ret
- CFI_ENDPROC
ENDPROC(call_rwsem_downgrade_wake)
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index e2f5e21c03b3..91d93b95bd86 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -647,7 +647,8 @@ EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero);
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from kernel space to user space.
*
@@ -668,7 +669,8 @@ EXPORT_SYMBOL(_copy_to_user);
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
- * Context: User context only. This function may sleep.
+ * Context: User context only. This function may sleep if pagefaults are
+ * enabled.
*
* Copy data from user space to kernel space.
*
diff --git a/arch/x86/math-emu/fpu_aux.c b/arch/x86/math-emu/fpu_aux.c
index dc8adad10a2f..dd76a05729b0 100644
--- a/arch/x86/math-emu/fpu_aux.c
+++ b/arch/x86/math-emu/fpu_aux.c
@@ -30,7 +30,7 @@ static void fclex(void)
}
/* Needs to be externally visible */
-void finit_soft_fpu(struct i387_soft_struct *soft)
+void fpstate_init_soft(struct swregs_state *soft)
{
struct address *oaddr, *iaddr;
memset(soft, 0, sizeof(*soft));
@@ -52,7 +52,7 @@ void finit_soft_fpu(struct i387_soft_struct *soft)
void finit(void)
{
- finit_soft_fpu(&current->thread.fpu.state->soft);
+ fpstate_init_soft(&current->thread.fpu.state.soft);
}
/*
diff --git a/arch/x86/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c
index 9b868124128d..f37e84ab49f3 100644
--- a/arch/x86/math-emu/fpu_entry.c
+++ b/arch/x86/math-emu/fpu_entry.c
@@ -31,7 +31,7 @@
#include <asm/traps.h>
#include <asm/desc.h>
#include <asm/user.h>
-#include <asm/i387.h>
+#include <asm/fpu/internal.h>
#include "fpu_system.h"
#include "fpu_emu.h"
@@ -147,13 +147,9 @@ void math_emulate(struct math_emu_info *info)
unsigned long code_base = 0;
unsigned long code_limit = 0; /* Initialized to stop compiler warnings */
struct desc_struct code_descriptor;
+ struct fpu *fpu = &current->thread.fpu;
- if (!used_math()) {
- if (init_fpu(current)) {
- do_group_exit(SIGKILL);
- return;
- }
- }
+ fpu__activate_curr(fpu);
#ifdef RE_ENTRANT_CHECKING
if (emulating) {
@@ -673,7 +669,7 @@ void math_abort(struct math_emu_info *info, unsigned int signal)
#endif /* PARANOID */
}
-#define S387 ((struct i387_soft_struct *)s387)
+#define S387 ((struct swregs_state *)s387)
#define sstatus_word() \
((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
@@ -682,14 +678,14 @@ int fpregs_soft_set(struct task_struct *target,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
- struct i387_soft_struct *s387 = &target->thread.fpu.state->soft;
+ struct swregs_state *s387 = &target->thread.fpu.state.soft;
void *space = s387->st_space;
int ret;
int offset, other, i, tags, regnr, tag, newtop;
RE_ENTRANT_CHECK_OFF;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, s387, 0,
- offsetof(struct i387_soft_struct, st_space));
+ offsetof(struct swregs_state, st_space));
RE_ENTRANT_CHECK_ON;
if (ret)
@@ -734,7 +730,7 @@ int fpregs_soft_get(struct task_struct *target,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
- struct i387_soft_struct *s387 = &target->thread.fpu.state->soft;
+ struct swregs_state *s387 = &target->thread.fpu.state.soft;
const void *space = s387->st_space;
int ret;
int offset = (S387->ftop & 7) * 10, other = 80 - offset;
@@ -752,7 +748,7 @@ int fpregs_soft_get(struct task_struct *target,
#endif /* PECULIAR_486 */
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, s387, 0,
- offsetof(struct i387_soft_struct, st_space));
+ offsetof(struct swregs_state, st_space));
/* Copy all registers in stack order. */
if (!ret)
diff --git a/arch/x86/math-emu/fpu_system.h b/arch/x86/math-emu/fpu_system.h
index 2c614410a5f3..9ccecb61a4fa 100644
--- a/arch/x86/math-emu/fpu_system.h
+++ b/arch/x86/math-emu/fpu_system.h
@@ -31,7 +31,7 @@
#define SEG_EXPAND_DOWN(s) (((s).b & ((1 << 11) | (1 << 10))) \
== (1 << 10))
-#define I387 (current->thread.fpu.state)
+#define I387 (&current->thread.fpu.state)
#define FPU_info (I387->soft.info)
#define FPU_CS (*(unsigned short *) &(FPU_info->regs->cs))
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 181c53bac3a7..9dc909841739 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -13,6 +13,7 @@
#include <linux/hugetlb.h> /* hstate_index_to_shift */
#include <linux/prefetch.h> /* prefetchw */
#include <linux/context_tracking.h> /* exception_enter(), ... */
+#include <linux/uaccess.h> /* faulthandler_disabled() */
#include <asm/traps.h> /* dotraplinkage, ... */
#include <asm/pgalloc.h> /* pgd_*(), ... */
@@ -1126,9 +1127,9 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code,
/*
* If we're in an interrupt, have no user context or are running
- * in an atomic region then we must not take the fault:
+ * in a region with pagefaults disabled then we must not take the fault
*/
- if (unlikely(in_atomic() || !mm)) {
+ if (unlikely(faulthandler_disabled() || !mm)) {
bad_area_nosemaphore(regs, error_code, address);
return;
}
diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c
index 4500142bc4aa..eecb207a2037 100644
--- a/arch/x86/mm/highmem_32.c
+++ b/arch/x86/mm/highmem_32.c
@@ -35,7 +35,7 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot)
unsigned long vaddr;
int idx, type;
- /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+ preempt_disable();
pagefault_disable();
if (!PageHighMem(page))
@@ -100,6 +100,7 @@ void __kunmap_atomic(void *kvaddr)
#endif
pagefault_enable();
+ preempt_enable();
}
EXPORT_SYMBOL(__kunmap_atomic);
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 1d553186c434..8533b46e6bee 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -40,7 +40,7 @@
*/
uint16_t __cachemode2pte_tbl[_PAGE_CACHE_MODE_NUM] = {
[_PAGE_CACHE_MODE_WB ] = 0 | 0 ,
- [_PAGE_CACHE_MODE_WC ] = _PAGE_PWT | 0 ,
+ [_PAGE_CACHE_MODE_WC ] = 0 | _PAGE_PCD,
[_PAGE_CACHE_MODE_UC_MINUS] = 0 | _PAGE_PCD,
[_PAGE_CACHE_MODE_UC ] = _PAGE_PWT | _PAGE_PCD,
[_PAGE_CACHE_MODE_WT ] = 0 | _PAGE_PCD,
@@ -50,11 +50,11 @@ EXPORT_SYMBOL(__cachemode2pte_tbl);
uint8_t __pte2cachemode_tbl[8] = {
[__pte2cm_idx( 0 | 0 | 0 )] = _PAGE_CACHE_MODE_WB,
- [__pte2cm_idx(_PAGE_PWT | 0 | 0 )] = _PAGE_CACHE_MODE_WC,
+ [__pte2cm_idx(_PAGE_PWT | 0 | 0 )] = _PAGE_CACHE_MODE_UC_MINUS,
[__pte2cm_idx( 0 | _PAGE_PCD | 0 )] = _PAGE_CACHE_MODE_UC_MINUS,
[__pte2cm_idx(_PAGE_PWT | _PAGE_PCD | 0 )] = _PAGE_CACHE_MODE_UC,
[__pte2cm_idx( 0 | 0 | _PAGE_PAT)] = _PAGE_CACHE_MODE_WB,
- [__pte2cm_idx(_PAGE_PWT | 0 | _PAGE_PAT)] = _PAGE_CACHE_MODE_WC,
+ [__pte2cm_idx(_PAGE_PWT | 0 | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC_MINUS,
[__pte2cm_idx(0 | _PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC_MINUS,
[__pte2cm_idx(_PAGE_PWT | _PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC,
};
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index c8140e12816a..8340e45c891a 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -433,7 +433,7 @@ void __init add_highpages_with_active_regions(int nid,
phys_addr_t start, end;
u64 i;
- for_each_free_mem_range(i, nid, &start, &end, NULL) {
+ for_each_free_mem_range(i, nid, MEMBLOCK_NONE, &start, &end, NULL) {
unsigned long pfn = clamp_t(unsigned long, PFN_UP(start),
start_pfn, end_pfn);
unsigned long e_pfn = clamp_t(unsigned long, PFN_DOWN(end),
diff --git a/arch/x86/mm/iomap_32.c b/arch/x86/mm/iomap_32.c
index 9ca35fc60cfe..9c0ff045fdd4 100644
--- a/arch/x86/mm/iomap_32.c
+++ b/arch/x86/mm/iomap_32.c
@@ -59,6 +59,7 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
unsigned long vaddr;
int idx, type;
+ preempt_disable();
pagefault_disable();
type = kmap_atomic_idx_push();
@@ -77,13 +78,13 @@ void __iomem *
iomap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
{
/*
- * For non-PAT systems, promote PAGE_KERNEL_WC to PAGE_KERNEL_UC_MINUS.
- * PAGE_KERNEL_WC maps to PWT, which translates to uncached if the
- * MTRR is UC or WC. UC_MINUS gets the real intention, of the
- * user, which is "WC if the MTRR is WC, UC if you can't do that."
+ * For non-PAT systems, translate non-WB request to UC- just in
+ * case the caller set the PWT bit to prot directly without using
+ * pgprot_writecombine(). UC- translates to uncached if the MTRR
+ * is UC or WC. UC- gets the real intention, of the user, which is
+ * "WC if the MTRR is WC, UC if you can't do that."
*/
- if (!pat_enabled && pgprot_val(prot) ==
- (__PAGE_KERNEL | cachemode2protval(_PAGE_CACHE_MODE_WC)))
+ if (!pat_enabled() && pgprot2cachemode(prot) != _PAGE_CACHE_MODE_WB)
prot = __pgprot(__PAGE_KERNEL |
cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS));
@@ -117,5 +118,6 @@ iounmap_atomic(void __iomem *kvaddr)
}
pagefault_enable();
+ preempt_enable();
}
EXPORT_SYMBOL_GPL(iounmap_atomic);
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 70e7444c6835..cc5ccc415cc0 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -42,6 +42,9 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size,
case _PAGE_CACHE_MODE_WC:
err = _set_memory_wc(vaddr, nrpages);
break;
+ case _PAGE_CACHE_MODE_WT:
+ err = _set_memory_wt(vaddr, nrpages);
+ break;
case _PAGE_CACHE_MODE_WB:
err = _set_memory_wb(vaddr, nrpages);
break;
@@ -172,6 +175,10 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
prot = __pgprot(pgprot_val(prot) |
cachemode2protval(_PAGE_CACHE_MODE_WC));
break;
+ case _PAGE_CACHE_MODE_WT:
+ prot = __pgprot(pgprot_val(prot) |
+ cachemode2protval(_PAGE_CACHE_MODE_WT));
+ break;
case _PAGE_CACHE_MODE_WB:
break;
}
@@ -234,10 +241,11 @@ void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size)
{
/*
* Ideally, this should be:
- * pat_enabled ? _PAGE_CACHE_MODE_UC : _PAGE_CACHE_MODE_UC_MINUS;
+ * pat_enabled() ? _PAGE_CACHE_MODE_UC : _PAGE_CACHE_MODE_UC_MINUS;
*
* Till we fix all X drivers to use ioremap_wc(), we will use
- * UC MINUS.
+ * UC MINUS. Drivers that are certain they need or can already
+ * be converted over to strong UC can use ioremap_uc().
*/
enum page_cache_mode pcm = _PAGE_CACHE_MODE_UC_MINUS;
@@ -247,6 +255,39 @@ void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size)
EXPORT_SYMBOL(ioremap_nocache);
/**
+ * ioremap_uc - map bus memory into CPU space as strongly uncachable
+ * @phys_addr: bus address of the memory
+ * @size: size of the resource to map
+ *
+ * ioremap_uc performs a platform specific sequence of operations to
+ * make bus memory CPU accessible via the readb/readw/readl/writeb/
+ * writew/writel functions and the other mmio helpers. The returned
+ * address is not guaranteed to be usable directly as a virtual
+ * address.
+ *
+ * This version of ioremap ensures that the memory is marked with a strong
+ * preference as completely uncachable on the CPU when possible. For non-PAT
+ * systems this ends up setting page-attribute flags PCD=1, PWT=1. For PAT
+ * systems this will set the PAT entry for the pages as strong UC. This call
+ * will honor existing caching rules from things like the PCI bus. Note that
+ * there are other caches and buffers on many busses. In particular driver
+ * authors should read up on PCI writes.
+ *
+ * It's useful if some control registers are in such an area and
+ * write combining or read caching is not desirable:
+ *
+ * Must be freed with iounmap.
+ */
+void __iomem *ioremap_uc(resource_size_t phys_addr, unsigned long size)
+{
+ enum page_cache_mode pcm = _PAGE_CACHE_MODE_UC;
+
+ return __ioremap_caller(phys_addr, size, pcm,
+ __builtin_return_address(0));
+}
+EXPORT_SYMBOL_GPL(ioremap_uc);
+
+/**
* ioremap_wc - map memory into CPU space write combined
* @phys_addr: bus address of the memory
* @size: size of the resource to map
@@ -258,14 +299,28 @@ EXPORT_SYMBOL(ioremap_nocache);
*/
void __iomem *ioremap_wc(resource_size_t phys_addr, unsigned long size)
{
- if (pat_enabled)
- return __ioremap_caller(phys_addr, size, _PAGE_CACHE_MODE_WC,
+ return __ioremap_caller(phys_addr, size, _PAGE_CACHE_MODE_WC,
__builtin_return_address(0));
- else
- return ioremap_nocache(phys_addr, size);
}
EXPORT_SYMBOL(ioremap_wc);
+/**
+ * ioremap_wt - map memory into CPU space write through
+ * @phys_addr: bus address of the memory
+ * @size: size of the resource to map
+ *
+ * This version of ioremap ensures that the memory is marked write through.
+ * Write through stores data into memory while keeping the cache up-to-date.
+ *
+ * Must be freed with iounmap.
+ */
+void __iomem *ioremap_wt(resource_size_t phys_addr, unsigned long size)
+{
+ return __ioremap_caller(phys_addr, size, _PAGE_CACHE_MODE_WT,
+ __builtin_return_address(0));
+}
+EXPORT_SYMBOL(ioremap_wt);
+
void __iomem *ioremap_cache(resource_size_t phys_addr, unsigned long size)
{
return __ioremap_caller(phys_addr, size, _PAGE_CACHE_MODE_WB,
@@ -331,7 +386,7 @@ void iounmap(volatile void __iomem *addr)
}
EXPORT_SYMBOL(iounmap);
-int arch_ioremap_pud_supported(void)
+int __init arch_ioremap_pud_supported(void)
{
#ifdef CONFIG_X86_64
return cpu_has_gbpages;
@@ -340,7 +395,7 @@ int arch_ioremap_pud_supported(void)
#endif
}
-int arch_ioremap_pmd_supported(void)
+int __init arch_ioremap_pmd_supported(void)
{
return cpu_has_pse;
}
@@ -353,18 +408,18 @@ void *xlate_dev_mem_ptr(phys_addr_t phys)
{
unsigned long start = phys & PAGE_MASK;
unsigned long offset = phys & ~PAGE_MASK;
- unsigned long vaddr;
+ void *vaddr;
/* If page is RAM, we can use __va. Otherwise ioremap and unmap. */
if (page_is_ram(start >> PAGE_SHIFT))
return __va(phys);
- vaddr = (unsigned long)ioremap_cache(start, PAGE_SIZE);
+ vaddr = ioremap_cache(start, PAGE_SIZE);
/* Only add the offset on success and return NULL if the ioremap() failed: */
if (vaddr)
vaddr += offset;
- return (void *)vaddr;
+ return vaddr;
}
void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
@@ -373,7 +428,6 @@ void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
return;
iounmap((void __iomem *)((unsigned long)addr & PAGE_MASK));
- return;
}
static pte_t bm_pte[PAGE_SIZE/sizeof(pte_t)] __page_aligned_bss;
diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c
index c439ec478216..7a657f58bbea 100644
--- a/arch/x86/mm/mpx.c
+++ b/arch/x86/mm/mpx.c
@@ -10,13 +10,15 @@
#include <linux/syscalls.h>
#include <linux/sched/sysctl.h>
-#include <asm/i387.h>
#include <asm/insn.h>
#include <asm/mman.h>
#include <asm/mmu_context.h>
#include <asm/mpx.h>
#include <asm/processor.h>
-#include <asm/fpu-internal.h>
+#include <asm/fpu/internal.h>
+
+#define CREATE_TRACE_POINTS
+#include <asm/trace/mpx.h>
static const char *mpx_mapping_name(struct vm_area_struct *vma)
{
@@ -32,6 +34,22 @@ static int is_mpx_vma(struct vm_area_struct *vma)
return (vma->vm_ops == &mpx_vma_ops);
}
+static inline unsigned long mpx_bd_size_bytes(struct mm_struct *mm)
+{
+ if (is_64bit_mm(mm))
+ return MPX_BD_SIZE_BYTES_64;
+ else
+ return MPX_BD_SIZE_BYTES_32;
+}
+
+static inline unsigned long mpx_bt_size_bytes(struct mm_struct *mm)
+{
+ if (is_64bit_mm(mm))
+ return MPX_BT_SIZE_BYTES_64;
+ else
+ return MPX_BT_SIZE_BYTES_32;
+}
+
/*
* This is really a simplified "vm_mmap". it only handles MPX
* bounds tables (the bounds directory is user-allocated).
@@ -47,8 +65,8 @@ static unsigned long mpx_mmap(unsigned long len)
vm_flags_t vm_flags;
struct vm_area_struct *vma;
- /* Only bounds table and bounds directory can be allocated here */
- if (len != MPX_BD_SIZE_BYTES && len != MPX_BT_SIZE_BYTES)
+ /* Only bounds table can be allocated here */
+ if (len != mpx_bt_size_bytes(mm))
return -EINVAL;
down_write(&mm->mmap_sem);
@@ -272,10 +290,9 @@ bad_opcode:
*
* The caller is expected to kfree() the returned siginfo_t.
*/
-siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
- struct xsave_struct *xsave_buf)
+siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
{
- struct bndreg *bndregs, *bndreg;
+ const struct bndreg *bndregs, *bndreg;
siginfo_t *info = NULL;
struct insn insn;
uint8_t bndregno;
@@ -295,8 +312,8 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
err = -EINVAL;
goto err_out;
}
- /* get the bndregs _area_ of the xsave structure */
- bndregs = get_xsave_addr(xsave_buf, XSTATE_BNDREGS);
+ /* get bndregs field from current task's xsave area */
+ bndregs = get_xsave_field_ptr(XSTATE_BNDREGS);
if (!bndregs) {
err = -EINVAL;
goto err_out;
@@ -334,6 +351,7 @@ siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
err = -EINVAL;
goto err_out;
}
+ trace_mpx_bounds_register_exception(info->si_addr, bndreg);
return info;
err_out:
/* info might be NULL, but kfree() handles that */
@@ -341,25 +359,18 @@ err_out:
return ERR_PTR(err);
}
-static __user void *task_get_bounds_dir(struct task_struct *tsk)
+static __user void *mpx_get_bounds_dir(void)
{
- struct bndcsr *bndcsr;
+ const struct bndcsr *bndcsr;
if (!cpu_feature_enabled(X86_FEATURE_MPX))
return MPX_INVALID_BOUNDS_DIR;
/*
- * 32-bit binaries on 64-bit kernels are currently
- * unsupported.
- */
- if (IS_ENABLED(CONFIG_X86_64) && test_thread_flag(TIF_IA32))
- return MPX_INVALID_BOUNDS_DIR;
- /*
* The bounds directory pointer is stored in a register
* only accessible if we first do an xsave.
*/
- fpu_save_init(&tsk->thread.fpu);
- bndcsr = get_xsave_addr(&tsk->thread.fpu.state->xsave, XSTATE_BNDCSR);
+ bndcsr = get_xsave_field_ptr(XSTATE_BNDCSR);
if (!bndcsr)
return MPX_INVALID_BOUNDS_DIR;
@@ -378,10 +389,10 @@ static __user void *task_get_bounds_dir(struct task_struct *tsk)
(bndcsr->bndcfgu & MPX_BNDCFG_ADDR_MASK);
}
-int mpx_enable_management(struct task_struct *tsk)
+int mpx_enable_management(void)
{
void __user *bd_base = MPX_INVALID_BOUNDS_DIR;
- struct mm_struct *mm = tsk->mm;
+ struct mm_struct *mm = current->mm;
int ret = 0;
/*
@@ -390,11 +401,12 @@ int mpx_enable_management(struct task_struct *tsk)
* directory into XSAVE/XRSTOR Save Area and enable MPX through
* XRSTOR instruction.
*
- * fpu_xsave() is expected to be very expensive. Storing the bounds
- * directory here means that we do not have to do xsave in the unmap
- * path; we can just use mm->bd_addr instead.
+ * The copy_xregs_to_kernel() beneath get_xsave_field_ptr() is
+ * expected to be relatively expensive. Storing the bounds
+ * directory here means that we do not have to do xsave in the
+ * unmap path; we can just use mm->bd_addr instead.
*/
- bd_base = task_get_bounds_dir(tsk);
+ bd_base = mpx_get_bounds_dir();
down_write(&mm->mmap_sem);
mm->bd_addr = bd_base;
if (mm->bd_addr == MPX_INVALID_BOUNDS_DIR)
@@ -404,7 +416,7 @@ int mpx_enable_management(struct task_struct *tsk)
return ret;
}
-int mpx_disable_management(struct task_struct *tsk)
+int mpx_disable_management(void)
{
struct mm_struct *mm = current->mm;
@@ -417,29 +429,59 @@ int mpx_disable_management(struct task_struct *tsk)
return 0;
}
+static int mpx_cmpxchg_bd_entry(struct mm_struct *mm,
+ unsigned long *curval,
+ unsigned long __user *addr,
+ unsigned long old_val, unsigned long new_val)
+{
+ int ret;
+ /*
+ * user_atomic_cmpxchg_inatomic() actually uses sizeof()
+ * the pointer that we pass to it to figure out how much
+ * data to cmpxchg. We have to be careful here not to
+ * pass a pointer to a 64-bit data type when we only want
+ * a 32-bit copy.
+ */
+ if (is_64bit_mm(mm)) {
+ ret = user_atomic_cmpxchg_inatomic(curval,
+ addr, old_val, new_val);
+ } else {
+ u32 uninitialized_var(curval_32);
+ u32 old_val_32 = old_val;
+ u32 new_val_32 = new_val;
+ u32 __user *addr_32 = (u32 __user *)addr;
+
+ ret = user_atomic_cmpxchg_inatomic(&curval_32,
+ addr_32, old_val_32, new_val_32);
+ *curval = curval_32;
+ }
+ return ret;
+}
+
/*
- * With 32-bit mode, MPX_BT_SIZE_BYTES is 4MB, and the size of each
- * bounds table is 16KB. With 64-bit mode, MPX_BT_SIZE_BYTES is 2GB,
+ * With 32-bit mode, a bounds directory is 4MB, and the size of each
+ * bounds table is 16KB. With 64-bit mode, a bounds directory is 2GB,
* and the size of each bounds table is 4MB.
*/
-static int allocate_bt(long __user *bd_entry)
+static int allocate_bt(struct mm_struct *mm, long __user *bd_entry)
{
unsigned long expected_old_val = 0;
unsigned long actual_old_val = 0;
unsigned long bt_addr;
+ unsigned long bd_new_entry;
int ret = 0;
/*
* Carve the virtual space out of userspace for the new
* bounds table:
*/
- bt_addr = mpx_mmap(MPX_BT_SIZE_BYTES);
+ bt_addr = mpx_mmap(mpx_bt_size_bytes(mm));
if (IS_ERR((void *)bt_addr))
return PTR_ERR((void *)bt_addr);
/*
* Set the valid flag (kinda like _PAGE_PRESENT in a pte)
*/
- bt_addr = bt_addr | MPX_BD_ENTRY_VALID_FLAG;
+ bd_new_entry = bt_addr | MPX_BD_ENTRY_VALID_FLAG;
/*
* Go poke the address of the new bounds table in to the
@@ -452,8 +494,8 @@ static int allocate_bt(long __user *bd_entry)
* mmap_sem at this point, unlike some of the other part
* of the MPX code that have to pagefault_disable().
*/
- ret = user_atomic_cmpxchg_inatomic(&actual_old_val, bd_entry,
- expected_old_val, bt_addr);
+ ret = mpx_cmpxchg_bd_entry(mm, &actual_old_val, bd_entry,
+ expected_old_val, bd_new_entry);
if (ret)
goto out_unmap;
@@ -481,9 +523,10 @@ static int allocate_bt(long __user *bd_entry)
ret = -EINVAL;
goto out_unmap;
}
+ trace_mpx_new_bounds_table(bt_addr);
return 0;
out_unmap:
- vm_munmap(bt_addr & MPX_BT_ADDR_MASK, MPX_BT_SIZE_BYTES);
+ vm_munmap(bt_addr, mpx_bt_size_bytes(mm));
return ret;
}
@@ -498,12 +541,13 @@ out_unmap:
* bound table is 16KB. With 64-bit mode, the size of BD is 2GB,
* and the size of each bound table is 4MB.
*/
-static int do_mpx_bt_fault(struct xsave_struct *xsave_buf)
+static int do_mpx_bt_fault(void)
{
unsigned long bd_entry, bd_base;
- struct bndcsr *bndcsr;
+ const struct bndcsr *bndcsr;
+ struct mm_struct *mm = current->mm;
- bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);
+ bndcsr = get_xsave_field_ptr(XSTATE_BNDCSR);
if (!bndcsr)
return -EINVAL;
/*
@@ -520,13 +564,13 @@ static int do_mpx_bt_fault(struct xsave_struct *xsave_buf)
* the directory is.
*/
if ((bd_entry < bd_base) ||
- (bd_entry >= bd_base + MPX_BD_SIZE_BYTES))
+ (bd_entry >= bd_base + mpx_bd_size_bytes(mm)))
return -EINVAL;
- return allocate_bt((long __user *)bd_entry);
+ return allocate_bt(mm, (long __user *)bd_entry);
}
-int mpx_handle_bd_fault(struct xsave_struct *xsave_buf)
+int mpx_handle_bd_fault(void)
{
/*
* Userspace never asked us to manage the bounds tables,
@@ -535,7 +579,7 @@ int mpx_handle_bd_fault(struct xsave_struct *xsave_buf)
if (!kernel_managing_mpx_tables(current->mm))
return -EINVAL;
- if (do_mpx_bt_fault(xsave_buf)) {
+ if (do_mpx_bt_fault()) {
force_sig(SIGSEGV, current);
/*
* The force_sig() is essentially "handling" this
@@ -572,29 +616,55 @@ static int mpx_resolve_fault(long __user *addr, int write)
return 0;
}
+static unsigned long mpx_bd_entry_to_bt_addr(struct mm_struct *mm,
+ unsigned long bd_entry)
+{
+ unsigned long bt_addr = bd_entry;
+ int align_to_bytes;
+ /*
+ * Bit 0 in a bt_entry is always the valid bit.
+ */
+ bt_addr &= ~MPX_BD_ENTRY_VALID_FLAG;
+ /*
+ * Tables are naturally aligned at 8-byte boundaries
+ * on 64-bit and 4-byte boundaries on 32-bit. The
+ * documentation makes it appear that the low bits
+ * are ignored by the hardware, so we do the same.
+ */
+ if (is_64bit_mm(mm))
+ align_to_bytes = 8;
+ else
+ align_to_bytes = 4;
+ bt_addr &= ~(align_to_bytes-1);
+ return bt_addr;
+}
+
/*
* Get the base of bounds tables pointed by specific bounds
* directory entry.
*/
static int get_bt_addr(struct mm_struct *mm,
- long __user *bd_entry, unsigned long *bt_addr)
+ long __user *bd_entry_ptr,
+ unsigned long *bt_addr_result)
{
int ret;
int valid_bit;
+ unsigned long bd_entry;
+ unsigned long bt_addr;
- if (!access_ok(VERIFY_READ, (bd_entry), sizeof(*bd_entry)))
+ if (!access_ok(VERIFY_READ, (bd_entry_ptr), sizeof(*bd_entry_ptr)))
return -EFAULT;
while (1) {
int need_write = 0;
pagefault_disable();
- ret = get_user(*bt_addr, bd_entry);
+ ret = get_user(bd_entry, bd_entry_ptr);
pagefault_enable();
if (!ret)
break;
if (ret == -EFAULT)
- ret = mpx_resolve_fault(bd_entry, need_write);
+ ret = mpx_resolve_fault(bd_entry_ptr, need_write);
/*
* If we could not resolve the fault, consider it
* userspace's fault and error out.
@@ -603,8 +673,8 @@ static int get_bt_addr(struct mm_struct *mm,
return ret;
}
- valid_bit = *bt_addr & MPX_BD_ENTRY_VALID_FLAG;
- *bt_addr &= MPX_BT_ADDR_MASK;
+ valid_bit = bd_entry & MPX_BD_ENTRY_VALID_FLAG;
+ bt_addr = mpx_bd_entry_to_bt_addr(mm, bd_entry);
/*
* When the kernel is managing bounds tables, a bounds directory
@@ -613,7 +683,7 @@ static int get_bt_addr(struct mm_struct *mm,
* data in the address field, we know something is wrong. This
* -EINVAL return will cause a SIGSEGV.
*/
- if (!valid_bit && *bt_addr)
+ if (!valid_bit && bt_addr)
return -EINVAL;
/*
* Do we have an completely zeroed bt entry? That is OK. It
@@ -624,19 +694,100 @@ static int get_bt_addr(struct mm_struct *mm,
if (!valid_bit)
return -ENOENT;
+ *bt_addr_result = bt_addr;
return 0;
}
+static inline int bt_entry_size_bytes(struct mm_struct *mm)
+{
+ if (is_64bit_mm(mm))
+ return MPX_BT_ENTRY_BYTES_64;
+ else
+ return MPX_BT_ENTRY_BYTES_32;
+}
+
+/*
+ * Take a virtual address and turns it in to the offset in bytes
+ * inside of the bounds table where the bounds table entry
+ * controlling 'addr' can be found.
+ */
+static unsigned long mpx_get_bt_entry_offset_bytes(struct mm_struct *mm,
+ unsigned long addr)
+{
+ unsigned long bt_table_nr_entries;
+ unsigned long offset = addr;
+
+ if (is_64bit_mm(mm)) {
+ /* Bottom 3 bits are ignored on 64-bit */
+ offset >>= 3;
+ bt_table_nr_entries = MPX_BT_NR_ENTRIES_64;
+ } else {
+ /* Bottom 2 bits are ignored on 32-bit */
+ offset >>= 2;
+ bt_table_nr_entries = MPX_BT_NR_ENTRIES_32;
+ }
+ /*
+ * We know the size of the table in to which we are
+ * indexing, and we have eliminated all the low bits
+ * which are ignored for indexing.
+ *
+ * Mask out all the high bits which we do not need
+ * to index in to the table. Note that the tables
+ * are always powers of two so this gives us a proper
+ * mask.
+ */
+ offset &= (bt_table_nr_entries-1);
+ /*
+ * We now have an entry offset in terms of *entries* in
+ * the table. We need to scale it back up to bytes.
+ */
+ offset *= bt_entry_size_bytes(mm);
+ return offset;
+}
+
+/*
+ * How much virtual address space does a single bounds
+ * directory entry cover?
+ *
+ * Note, we need a long long because 4GB doesn't fit in
+ * to a long on 32-bit.
+ */
+static inline unsigned long bd_entry_virt_space(struct mm_struct *mm)
+{
+ unsigned long long virt_space = (1ULL << boot_cpu_data.x86_virt_bits);
+ if (is_64bit_mm(mm))
+ return virt_space / MPX_BD_NR_ENTRIES_64;
+ else
+ return virt_space / MPX_BD_NR_ENTRIES_32;
+}
+
/*
* Free the backing physical pages of bounds table 'bt_addr'.
* Assume start...end is within that bounds table.
*/
-static int zap_bt_entries(struct mm_struct *mm,
+static noinline int zap_bt_entries_mapping(struct mm_struct *mm,
unsigned long bt_addr,
- unsigned long start, unsigned long end)
+ unsigned long start_mapping, unsigned long end_mapping)
{
struct vm_area_struct *vma;
unsigned long addr, len;
+ unsigned long start;
+ unsigned long end;
+
+ /*
+ * if we 'end' on a boundary, the offset will be 0 which
+ * is not what we want. Back it up a byte to get the
+ * last bt entry. Then once we have the entry itself,
+ * move 'end' back up by the table entry size.
+ */
+ start = bt_addr + mpx_get_bt_entry_offset_bytes(mm, start_mapping);
+ end = bt_addr + mpx_get_bt_entry_offset_bytes(mm, end_mapping - 1);
+ /*
+ * Move end back up by one entry. Among other things
+ * this ensures that it remains page-aligned and does
+ * not screw up zap_page_range()
+ */
+ end += bt_entry_size_bytes(mm);
/*
* Find the first overlapping vma. If vma->vm_start > start, there
@@ -648,7 +799,7 @@ static int zap_bt_entries(struct mm_struct *mm,
return -EINVAL;
/*
- * A NUMA policy on a VM_MPX VMA could cause this bouds table to
+ * A NUMA policy on a VM_MPX VMA could cause this bounds table to
* be split. So we need to look across the entire 'start -> end'
* range of this bounds table, find all of the VM_MPX VMAs, and
* zap only those.
@@ -666,27 +817,65 @@ static int zap_bt_entries(struct mm_struct *mm,
len = min(vma->vm_end, end) - addr;
zap_page_range(vma, addr, len, NULL);
+ trace_mpx_unmap_zap(addr, addr+len);
vma = vma->vm_next;
addr = vma->vm_start;
}
-
return 0;
}
-static int unmap_single_bt(struct mm_struct *mm,
+static unsigned long mpx_get_bd_entry_offset(struct mm_struct *mm,
+ unsigned long addr)
+{
+ /*
+ * There are several ways to derive the bd offsets. We
+ * use the following approach here:
+ * 1. We know the size of the virtual address space
+ * 2. We know the number of entries in a bounds table
+ * 3. We know that each entry covers a fixed amount of
+ * virtual address space.
+ * So, we can just divide the virtual address by the
+ * virtual space used by one entry to determine which
+ * entry "controls" the given virtual address.
+ */
+ if (is_64bit_mm(mm)) {
+ int bd_entry_size = 8; /* 64-bit pointer */
+ /*
+ * Take the 64-bit addressing hole in to account.
+ */
+ addr &= ((1UL << boot_cpu_data.x86_virt_bits) - 1);
+ return (addr / bd_entry_virt_space(mm)) * bd_entry_size;
+ } else {
+ int bd_entry_size = 4; /* 32-bit pointer */
+ /*
+ * 32-bit has no hole so this case needs no mask
+ */
+ return (addr / bd_entry_virt_space(mm)) * bd_entry_size;
+ }
+ /*
+ * The two return calls above are exact copies. If we
+ * pull out a single copy and put it in here, gcc won't
+ * realize that we're doing a power-of-2 divide and use
+ * shifts. It uses a real divide. If we put them up
+ * there, it manages to figure it out (gcc 4.8.3).
+ */
+}
+
+static int unmap_entire_bt(struct mm_struct *mm,
long __user *bd_entry, unsigned long bt_addr)
{
unsigned long expected_old_val = bt_addr | MPX_BD_ENTRY_VALID_FLAG;
- unsigned long actual_old_val = 0;
+ unsigned long uninitialized_var(actual_old_val);
int ret;
while (1) {
int need_write = 1;
+ unsigned long cleared_bd_entry = 0;
pagefault_disable();
- ret = user_atomic_cmpxchg_inatomic(&actual_old_val, bd_entry,
- expected_old_val, 0);
+ ret = mpx_cmpxchg_bd_entry(mm, &actual_old_val,
+ bd_entry, expected_old_val, cleared_bd_entry);
pagefault_enable();
if (!ret)
break;
@@ -705,9 +894,8 @@ static int unmap_single_bt(struct mm_struct *mm,
if (actual_old_val != expected_old_val) {
/*
* Someone else raced with us to unmap the table.
- * There was no bounds table pointed to by the
- * directory, so declare success. Somebody freed
- * it.
+ * That is OK, since we were both trying to do
+ * the same thing. Declare success.
*/
if (!actual_old_val)
return 0;
@@ -720,176 +908,113 @@ static int unmap_single_bt(struct mm_struct *mm,
*/
return -EINVAL;
}
-
/*
* Note, we are likely being called under do_munmap() already. To
* avoid recursion, do_munmap() will check whether it comes
* from one bounds table through VM_MPX flag.
*/
- return do_munmap(mm, bt_addr, MPX_BT_SIZE_BYTES);
+ return do_munmap(mm, bt_addr, mpx_bt_size_bytes(mm));
}
-/*
- * If the bounds table pointed by bounds directory 'bd_entry' is
- * not shared, unmap this whole bounds table. Otherwise, only free
- * those backing physical pages of bounds table entries covered
- * in this virtual address region start...end.
- */
-static int unmap_shared_bt(struct mm_struct *mm,
- long __user *bd_entry, unsigned long start,
- unsigned long end, bool prev_shared, bool next_shared)
+static int try_unmap_single_bt(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
{
- unsigned long bt_addr;
- int ret;
-
- ret = get_bt_addr(mm, bd_entry, &bt_addr);
+ struct vm_area_struct *next;
+ struct vm_area_struct *prev;
/*
- * We could see an "error" ret for not-present bounds
- * tables (not really an error), or actual errors, but
- * stop unmapping either way.
+ * "bta" == Bounds Table Area: the area controlled by the
+ * bounds table that we are unmapping.
*/
- if (ret)
- return ret;
-
- if (prev_shared && next_shared)
- ret = zap_bt_entries(mm, bt_addr,
- bt_addr+MPX_GET_BT_ENTRY_OFFSET(start),
- bt_addr+MPX_GET_BT_ENTRY_OFFSET(end));
- else if (prev_shared)
- ret = zap_bt_entries(mm, bt_addr,
- bt_addr+MPX_GET_BT_ENTRY_OFFSET(start),
- bt_addr+MPX_BT_SIZE_BYTES);
- else if (next_shared)
- ret = zap_bt_entries(mm, bt_addr, bt_addr,
- bt_addr+MPX_GET_BT_ENTRY_OFFSET(end));
- else
- ret = unmap_single_bt(mm, bd_entry, bt_addr);
-
- return ret;
-}
-
-/*
- * A virtual address region being munmap()ed might share bounds table
- * with adjacent VMAs. We only need to free the backing physical
- * memory of these shared bounds tables entries covered in this virtual
- * address region.
- */
-static int unmap_edge_bts(struct mm_struct *mm,
- unsigned long start, unsigned long end)
-{
+ unsigned long bta_start_vaddr = start & ~(bd_entry_virt_space(mm)-1);
+ unsigned long bta_end_vaddr = bta_start_vaddr + bd_entry_virt_space(mm);
+ unsigned long uninitialized_var(bt_addr);
+ void __user *bde_vaddr;
int ret;
- long __user *bde_start, *bde_end;
- struct vm_area_struct *prev, *next;
- bool prev_shared = false, next_shared = false;
-
- bde_start = mm->bd_addr + MPX_GET_BD_ENTRY_OFFSET(start);
- bde_end = mm->bd_addr + MPX_GET_BD_ENTRY_OFFSET(end-1);
-
/*
- * Check whether bde_start and bde_end are shared with adjacent
- * VMAs.
- *
- * We already unliked the VMAs from the mm's rbtree so 'start'
+ * We already unlinked the VMAs from the mm's rbtree so 'start'
* is guaranteed to be in a hole. This gets us the first VMA
* before the hole in to 'prev' and the next VMA after the hole
* in to 'next'.
*/
next = find_vma_prev(mm, start, &prev);
- if (prev && (mm->bd_addr + MPX_GET_BD_ENTRY_OFFSET(prev->vm_end-1))
- == bde_start)
- prev_shared = true;
- if (next && (mm->bd_addr + MPX_GET_BD_ENTRY_OFFSET(next->vm_start))
- == bde_end)
- next_shared = true;
-
/*
- * This virtual address region being munmap()ed is only
- * covered by one bounds table.
- *
- * In this case, if this table is also shared with adjacent
- * VMAs, only part of the backing physical memory of the bounds
- * table need be freeed. Otherwise the whole bounds table need
- * be unmapped.
- */
- if (bde_start == bde_end) {
- return unmap_shared_bt(mm, bde_start, start, end,
- prev_shared, next_shared);
+ * Do not count other MPX bounds table VMAs as neighbors.
+ * Although theoretically possible, we do not allow bounds
+ * tables for bounds tables so our heads do not explode.
+ * If we count them as neighbors here, we may end up with
+ * lots of tables even though we have no actual table
+ * entries in use.
+ */
+ while (next && is_mpx_vma(next))
+ next = next->vm_next;
+ while (prev && is_mpx_vma(prev))
+ prev = prev->vm_prev;
+ /*
+ * We know 'start' and 'end' lie within an area controlled
+ * by a single bounds table. See if there are any other
+ * VMAs controlled by that bounds table. If there are not
+ * then we can "expand" the are we are unmapping to possibly
+ * cover the entire table.
+ */
+ next = find_vma_prev(mm, start, &prev);
+ if ((!prev || prev->vm_end <= bta_start_vaddr) &&
+ (!next || next->vm_start >= bta_end_vaddr)) {
+ /*
+ * No neighbor VMAs controlled by same bounds
+ * table. Try to unmap the whole thing
+ */
+ start = bta_start_vaddr;
+ end = bta_end_vaddr;
}
+ bde_vaddr = mm->bd_addr + mpx_get_bd_entry_offset(mm, start);
+ ret = get_bt_addr(mm, bde_vaddr, &bt_addr);
/*
- * If more than one bounds tables are covered in this virtual
- * address region being munmap()ed, we need to separately check
- * whether bde_start and bde_end are shared with adjacent VMAs.
+ * No bounds table there, so nothing to unmap.
*/
- ret = unmap_shared_bt(mm, bde_start, start, end, prev_shared, false);
- if (ret)
- return ret;
- ret = unmap_shared_bt(mm, bde_end, start, end, false, next_shared);
+ if (ret == -ENOENT) {
+ ret = 0;
+ return 0;
+ }
if (ret)
return ret;
-
- return 0;
+ /*
+ * We are unmapping an entire table. Either because the
+ * unmap that started this whole process was large enough
+ * to cover an entire table, or that the unmap was small
+ * but was the area covered by a bounds table.
+ */
+ if ((start == bta_start_vaddr) &&
+ (end == bta_end_vaddr))
+ return unmap_entire_bt(mm, bde_vaddr, bt_addr);
+ return zap_bt_entries_mapping(mm, bt_addr, start, end);
}
static int mpx_unmap_tables(struct mm_struct *mm,
unsigned long start, unsigned long end)
{
- int ret;
- long __user *bd_entry, *bde_start, *bde_end;
- unsigned long bt_addr;
-
- /*
- * "Edge" bounds tables are those which are being used by the region
- * (start -> end), but that may be shared with adjacent areas. If they
- * turn out to be completely unshared, they will be freed. If they are
- * shared, we will free the backing store (like an MADV_DONTNEED) for
- * areas used by this region.
- */
- ret = unmap_edge_bts(mm, start, end);
- switch (ret) {
- /* non-present tables are OK */
- case 0:
- case -ENOENT:
- /* Success, or no tables to unmap */
- break;
- case -EINVAL:
- case -EFAULT:
- default:
- return ret;
- }
-
- /*
- * Only unmap the bounds table that are
- * 1. fully covered
- * 2. not at the edges of the mapping, even if full aligned
- */
- bde_start = mm->bd_addr + MPX_GET_BD_ENTRY_OFFSET(start);
- bde_end = mm->bd_addr + MPX_GET_BD_ENTRY_OFFSET(end-1);
- for (bd_entry = bde_start + 1; bd_entry < bde_end; bd_entry++) {
- ret = get_bt_addr(mm, bd_entry, &bt_addr);
- switch (ret) {
- case 0:
- break;
- case -ENOENT:
- /* No table here, try the next one */
- continue;
- case -EINVAL:
- case -EFAULT:
- default:
- /*
- * Note: we are being strict here.
- * Any time we run in to an issue
- * unmapping tables, we stop and
- * SIGSEGV.
- */
- return ret;
- }
-
- ret = unmap_single_bt(mm, bd_entry, bt_addr);
+ unsigned long one_unmap_start;
+ trace_mpx_unmap_search(start, end);
+
+ one_unmap_start = start;
+ while (one_unmap_start < end) {
+ int ret;
+ unsigned long next_unmap_start = ALIGN(one_unmap_start+1,
+ bd_entry_virt_space(mm));
+ unsigned long one_unmap_end = end;
+ /*
+ * if the end is beyond the current bounds table,
+ * move it back so we only deal with a single one
+ * at a time
+ */
+ if (one_unmap_end > next_unmap_start)
+ one_unmap_end = next_unmap_start;
+ ret = try_unmap_single_bt(mm, one_unmap_start, one_unmap_end);
if (ret)
return ret;
- }
+ one_unmap_start = next_unmap_start;
+ }
return 0;
}
diff --git a/arch/x86/mm/pageattr-test.c b/arch/x86/mm/pageattr-test.c
index 6629f397b467..8ff686aa7e8c 100644
--- a/arch/x86/mm/pageattr-test.c
+++ b/arch/x86/mm/pageattr-test.c
@@ -9,6 +9,7 @@
#include <linux/random.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/vmalloc.h>
#include <asm/cacheflush.h>
#include <asm/pgtable.h>
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 89af288ec674..727158cb3b3c 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -14,6 +14,7 @@
#include <linux/percpu.h>
#include <linux/gfp.h>
#include <linux/pci.h>
+#include <linux/vmalloc.h>
#include <asm/e820.h>
#include <asm/processor.h>
@@ -129,16 +130,15 @@ within(unsigned long addr, unsigned long start, unsigned long end)
*/
void clflush_cache_range(void *vaddr, unsigned int size)
{
- void *vend = vaddr + size - 1;
+ unsigned long clflush_mask = boot_cpu_data.x86_clflush_size - 1;
+ void *vend = vaddr + size;
+ void *p;
mb();
- for (; vaddr < vend; vaddr += boot_cpu_data.x86_clflush_size)
- clflushopt(vaddr);
- /*
- * Flush any possible final partial cacheline:
- */
- clflushopt(vend);
+ for (p = (void *)((unsigned long)vaddr & ~clflush_mask);
+ p < vend; p += boot_cpu_data.x86_clflush_size)
+ clflushopt(p);
mb();
}
@@ -418,13 +418,11 @@ phys_addr_t slow_virt_to_phys(void *__virt_addr)
phys_addr_t phys_addr;
unsigned long offset;
enum pg_level level;
- unsigned long psize;
unsigned long pmask;
pte_t *pte;
pte = lookup_address(virt_addr, &level);
BUG_ON(!pte);
- psize = page_level_size(level);
pmask = page_level_mask(level);
offset = virt_addr & ~pmask;
phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT;
@@ -1468,6 +1466,9 @@ int _set_memory_uc(unsigned long addr, int numpages)
{
/*
* for now UC MINUS. see comments in ioremap_nocache()
+ * If you really need strong UC use ioremap_uc(), but note
+ * that you cannot override IO areas with set_memory_*() as
+ * these helpers cannot work with IO memory.
*/
return change_page_attr_set(&addr, numpages,
cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS),
@@ -1502,12 +1503,10 @@ EXPORT_SYMBOL(set_memory_uc);
static int _set_memory_array(unsigned long *addr, int addrinarray,
enum page_cache_mode new_type)
{
+ enum page_cache_mode set_type;
int i, j;
int ret;
- /*
- * for now UC MINUS. see comments in ioremap_nocache()
- */
for (i = 0; i < addrinarray; i++) {
ret = reserve_memtype(__pa(addr[i]), __pa(addr[i]) + PAGE_SIZE,
new_type, NULL);
@@ -1515,9 +1514,12 @@ static int _set_memory_array(unsigned long *addr, int addrinarray,
goto out_free;
}
+ /* If WC, set to UC- first and then WC */
+ set_type = (new_type == _PAGE_CACHE_MODE_WC) ?
+ _PAGE_CACHE_MODE_UC_MINUS : new_type;
+
ret = change_page_attr_set(addr, addrinarray,
- cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS),
- 1);
+ cachemode2pgprot(set_type), 1);
if (!ret && new_type == _PAGE_CACHE_MODE_WC)
ret = change_page_attr_set_clr(addr, addrinarray,
@@ -1549,6 +1551,12 @@ int set_memory_array_wc(unsigned long *addr, int addrinarray)
}
EXPORT_SYMBOL(set_memory_array_wc);
+int set_memory_array_wt(unsigned long *addr, int addrinarray)
+{
+ return _set_memory_array(addr, addrinarray, _PAGE_CACHE_MODE_WT);
+}
+EXPORT_SYMBOL_GPL(set_memory_array_wt);
+
int _set_memory_wc(unsigned long addr, int numpages)
{
int ret;
@@ -1571,27 +1579,42 @@ int set_memory_wc(unsigned long addr, int numpages)
{
int ret;
- if (!pat_enabled)
- return set_memory_uc(addr, numpages);
-
ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
_PAGE_CACHE_MODE_WC, NULL);
if (ret)
- goto out_err;
+ return ret;
ret = _set_memory_wc(addr, numpages);
if (ret)
- goto out_free;
-
- return 0;
+ free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE);
-out_free:
- free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE);
-out_err:
return ret;
}
EXPORT_SYMBOL(set_memory_wc);
+int _set_memory_wt(unsigned long addr, int numpages)
+{
+ return change_page_attr_set(&addr, numpages,
+ cachemode2pgprot(_PAGE_CACHE_MODE_WT), 0);
+}
+
+int set_memory_wt(unsigned long addr, int numpages)
+{
+ int ret;
+
+ ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
+ _PAGE_CACHE_MODE_WT, NULL);
+ if (ret)
+ return ret;
+
+ ret = _set_memory_wt(addr, numpages);
+ if (ret)
+ free_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(set_memory_wt);
+
int _set_memory_wb(unsigned long addr, int numpages)
{
/* WB cache mode is hard wired to all cache attribute bits being 0 */
@@ -1682,6 +1705,7 @@ static int _set_pages_array(struct page **pages, int addrinarray,
{
unsigned long start;
unsigned long end;
+ enum page_cache_mode set_type;
int i;
int free_idx;
int ret;
@@ -1695,8 +1719,12 @@ static int _set_pages_array(struct page **pages, int addrinarray,
goto err_out;
}
+ /* If WC, set to UC- first and then WC */
+ set_type = (new_type == _PAGE_CACHE_MODE_WC) ?
+ _PAGE_CACHE_MODE_UC_MINUS : new_type;
+
ret = cpa_set_pages_array(pages, addrinarray,
- cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS));
+ cachemode2pgprot(set_type));
if (!ret && new_type == _PAGE_CACHE_MODE_WC)
ret = change_page_attr_set_clr(NULL, addrinarray,
cachemode2pgprot(
@@ -1730,6 +1758,12 @@ int set_pages_array_wc(struct page **pages, int addrinarray)
}
EXPORT_SYMBOL(set_pages_array_wc);
+int set_pages_array_wt(struct page **pages, int addrinarray)
+{
+ return _set_pages_array(pages, addrinarray, _PAGE_CACHE_MODE_WT);
+}
+EXPORT_SYMBOL_GPL(set_pages_array_wt);
+
int set_pages_wb(struct page *page, int numpages)
{
unsigned long addr = (unsigned long)page_address(page);
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 35af6771a95a..188e3e07eeeb 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -33,13 +33,17 @@
#include "pat_internal.h"
#include "mm_internal.h"
-#ifdef CONFIG_X86_PAT
-int __read_mostly pat_enabled = 1;
+#undef pr_fmt
+#define pr_fmt(fmt) "" fmt
+
+static bool boot_cpu_done;
+
+static int __read_mostly __pat_enabled = IS_ENABLED(CONFIG_X86_PAT);
static inline void pat_disable(const char *reason)
{
- pat_enabled = 0;
- printk(KERN_INFO "%s\n", reason);
+ __pat_enabled = 0;
+ pr_info("x86/PAT: %s\n", reason);
}
static int __init nopat(char *str)
@@ -48,13 +52,12 @@ static int __init nopat(char *str)
return 0;
}
early_param("nopat", nopat);
-#else
-static inline void pat_disable(const char *reason)
+
+bool pat_enabled(void)
{
- (void)reason;
+ return !!__pat_enabled;
}
-#endif
-
+EXPORT_SYMBOL_GPL(pat_enabled);
int pat_debug_enable;
@@ -65,22 +68,24 @@ static int __init pat_debug_setup(char *str)
}
__setup("debugpat", pat_debug_setup);
-static u64 __read_mostly boot_pat_state;
-
#ifdef CONFIG_X86_PAT
/*
- * X86 PAT uses page flags WC and Uncached together to keep track of
- * memory type of pages that have backing page struct. X86 PAT supports 3
- * different memory types, _PAGE_CACHE_MODE_WB, _PAGE_CACHE_MODE_WC and
- * _PAGE_CACHE_MODE_UC_MINUS and fourth state where page's memory type has not
- * been changed from its default (value of -1 used to denote this).
- * Note we do not support _PAGE_CACHE_MODE_UC here.
+ * X86 PAT uses page flags arch_1 and uncached together to keep track of
+ * memory type of pages that have backing page struct.
+ *
+ * X86 PAT supports 4 different memory types:
+ * - _PAGE_CACHE_MODE_WB
+ * - _PAGE_CACHE_MODE_WC
+ * - _PAGE_CACHE_MODE_UC_MINUS
+ * - _PAGE_CACHE_MODE_WT
+ *
+ * _PAGE_CACHE_MODE_WB is the default type.
*/
-#define _PGMT_DEFAULT 0
+#define _PGMT_WB 0
#define _PGMT_WC (1UL << PG_arch_1)
#define _PGMT_UC_MINUS (1UL << PG_uncached)
-#define _PGMT_WB (1UL << PG_uncached | 1UL << PG_arch_1)
+#define _PGMT_WT (1UL << PG_uncached | 1UL << PG_arch_1)
#define _PGMT_MASK (1UL << PG_uncached | 1UL << PG_arch_1)
#define _PGMT_CLEAR_MASK (~_PGMT_MASK)
@@ -88,14 +93,14 @@ static inline enum page_cache_mode get_page_memtype(struct page *pg)
{
unsigned long pg_flags = pg->flags & _PGMT_MASK;
- if (pg_flags == _PGMT_DEFAULT)
- return -1;
+ if (pg_flags == _PGMT_WB)
+ return _PAGE_CACHE_MODE_WB;
else if (pg_flags == _PGMT_WC)
return _PAGE_CACHE_MODE_WC;
else if (pg_flags == _PGMT_UC_MINUS)
return _PAGE_CACHE_MODE_UC_MINUS;
else
- return _PAGE_CACHE_MODE_WB;
+ return _PAGE_CACHE_MODE_WT;
}
static inline void set_page_memtype(struct page *pg,
@@ -112,11 +117,12 @@ static inline void set_page_memtype(struct page *pg,
case _PAGE_CACHE_MODE_UC_MINUS:
memtype_flags = _PGMT_UC_MINUS;
break;
- case _PAGE_CACHE_MODE_WB:
- memtype_flags = _PGMT_WB;
+ case _PAGE_CACHE_MODE_WT:
+ memtype_flags = _PGMT_WT;
break;
+ case _PAGE_CACHE_MODE_WB:
default:
- memtype_flags = _PGMT_DEFAULT;
+ memtype_flags = _PGMT_WB;
break;
}
@@ -174,78 +180,154 @@ static enum page_cache_mode pat_get_cache_mode(unsigned pat_val, char *msg)
* configuration.
* Using lower indices is preferred, so we start with highest index.
*/
-void pat_init_cache_modes(void)
+void pat_init_cache_modes(u64 pat)
{
- int i;
enum page_cache_mode cache;
char pat_msg[33];
- u64 pat;
+ int i;
- rdmsrl(MSR_IA32_CR_PAT, pat);
pat_msg[32] = 0;
for (i = 7; i >= 0; i--) {
cache = pat_get_cache_mode((pat >> (i * 8)) & 7,
pat_msg + 4 * i);
update_cache_mode_entry(i, cache);
}
- pr_info("PAT configuration [0-7]: %s\n", pat_msg);
+ pr_info("x86/PAT: Configuration [0-7]: %s\n", pat_msg);
}
#define PAT(x, y) ((u64)PAT_ ## y << ((x)*8))
-void pat_init(void)
+static void pat_bsp_init(u64 pat)
{
- u64 pat;
- bool boot_cpu = !boot_pat_state;
+ u64 tmp_pat;
- if (!pat_enabled)
+ if (!cpu_has_pat) {
+ pat_disable("PAT not supported by CPU.");
return;
+ }
- if (!cpu_has_pat) {
- if (!boot_pat_state) {
- pat_disable("PAT not supported by CPU.");
- return;
- } else {
- /*
- * If this happens we are on a secondary CPU, but
- * switched to PAT on the boot CPU. We have no way to
- * undo PAT.
- */
- printk(KERN_ERR "PAT enabled, "
- "but not supported by secondary CPU\n");
- BUG();
- }
+ if (!pat_enabled())
+ goto done;
+
+ rdmsrl(MSR_IA32_CR_PAT, tmp_pat);
+ if (!tmp_pat) {
+ pat_disable("PAT MSR is 0, disabled.");
+ return;
}
- /* Set PWT to Write-Combining. All other bits stay the same */
- /*
- * PTE encoding used in Linux:
- * PAT
- * |PCD
- * ||PWT
- * |||
- * 000 WB _PAGE_CACHE_WB
- * 001 WC _PAGE_CACHE_WC
- * 010 UC- _PAGE_CACHE_UC_MINUS
- * 011 UC _PAGE_CACHE_UC
- * PAT bit unused
- */
- pat = PAT(0, WB) | PAT(1, WC) | PAT(2, UC_MINUS) | PAT(3, UC) |
- PAT(4, WB) | PAT(5, WC) | PAT(6, UC_MINUS) | PAT(7, UC);
-
- /* Boot CPU check */
- if (!boot_pat_state) {
- rdmsrl(MSR_IA32_CR_PAT, boot_pat_state);
- if (!boot_pat_state) {
- pat_disable("PAT read returns always zero, disabled.");
- return;
- }
+ wrmsrl(MSR_IA32_CR_PAT, pat);
+
+done:
+ pat_init_cache_modes(pat);
+}
+
+static void pat_ap_init(u64 pat)
+{
+ if (!pat_enabled())
+ return;
+
+ if (!cpu_has_pat) {
+ /*
+ * If this happens we are on a secondary CPU, but switched to
+ * PAT on the boot CPU. We have no way to undo PAT.
+ */
+ panic("x86/PAT: PAT enabled, but not supported by secondary CPU\n");
}
wrmsrl(MSR_IA32_CR_PAT, pat);
+}
+
+void pat_init(void)
+{
+ u64 pat;
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+
+ if (!pat_enabled()) {
+ /*
+ * No PAT. Emulate the PAT table that corresponds to the two
+ * cache bits, PWT (Write Through) and PCD (Cache Disable). This
+ * setup is the same as the BIOS default setup when the system
+ * has PAT but the "nopat" boot option has been specified. This
+ * emulated PAT table is used when MSR_IA32_CR_PAT returns 0.
+ *
+ * PTE encoding:
+ *
+ * PCD
+ * |PWT PAT
+ * || slot
+ * 00 0 WB : _PAGE_CACHE_MODE_WB
+ * 01 1 WT : _PAGE_CACHE_MODE_WT
+ * 10 2 UC-: _PAGE_CACHE_MODE_UC_MINUS
+ * 11 3 UC : _PAGE_CACHE_MODE_UC
+ *
+ * NOTE: When WC or WP is used, it is redirected to UC- per
+ * the default setup in __cachemode2pte_tbl[].
+ */
+ pat = PAT(0, WB) | PAT(1, WT) | PAT(2, UC_MINUS) | PAT(3, UC) |
+ PAT(4, WB) | PAT(5, WT) | PAT(6, UC_MINUS) | PAT(7, UC);
- if (boot_cpu)
- pat_init_cache_modes();
+ } else if ((c->x86_vendor == X86_VENDOR_INTEL) &&
+ (((c->x86 == 0x6) && (c->x86_model <= 0xd)) ||
+ ((c->x86 == 0xf) && (c->x86_model <= 0x6)))) {
+ /*
+ * PAT support with the lower four entries. Intel Pentium 2,
+ * 3, M, and 4 are affected by PAT errata, which makes the
+ * upper four entries unusable. To be on the safe side, we don't
+ * use those.
+ *
+ * PTE encoding:
+ * PAT
+ * |PCD
+ * ||PWT PAT
+ * ||| slot
+ * 000 0 WB : _PAGE_CACHE_MODE_WB
+ * 001 1 WC : _PAGE_CACHE_MODE_WC
+ * 010 2 UC-: _PAGE_CACHE_MODE_UC_MINUS
+ * 011 3 UC : _PAGE_CACHE_MODE_UC
+ * PAT bit unused
+ *
+ * NOTE: When WT or WP is used, it is redirected to UC- per
+ * the default setup in __cachemode2pte_tbl[].
+ */
+ pat = PAT(0, WB) | PAT(1, WC) | PAT(2, UC_MINUS) | PAT(3, UC) |
+ PAT(4, WB) | PAT(5, WC) | PAT(6, UC_MINUS) | PAT(7, UC);
+ } else {
+ /*
+ * Full PAT support. We put WT in slot 7 to improve
+ * robustness in the presence of errata that might cause
+ * the high PAT bit to be ignored. This way, a buggy slot 7
+ * access will hit slot 3, and slot 3 is UC, so at worst
+ * we lose performance without causing a correctness issue.
+ * Pentium 4 erratum N46 is an example for such an erratum,
+ * although we try not to use PAT at all on affected CPUs.
+ *
+ * PTE encoding:
+ * PAT
+ * |PCD
+ * ||PWT PAT
+ * ||| slot
+ * 000 0 WB : _PAGE_CACHE_MODE_WB
+ * 001 1 WC : _PAGE_CACHE_MODE_WC
+ * 010 2 UC-: _PAGE_CACHE_MODE_UC_MINUS
+ * 011 3 UC : _PAGE_CACHE_MODE_UC
+ * 100 4 WB : Reserved
+ * 101 5 WC : Reserved
+ * 110 6 UC-: Reserved
+ * 111 7 WT : _PAGE_CACHE_MODE_WT
+ *
+ * The reserved slots are unused, but mapped to their
+ * corresponding types in the presence of PAT errata.
+ */
+ pat = PAT(0, WB) | PAT(1, WC) | PAT(2, UC_MINUS) | PAT(3, UC) |
+ PAT(4, WB) | PAT(5, WC) | PAT(6, UC_MINUS) | PAT(7, WT);
+ }
+
+ if (!boot_cpu_done) {
+ pat_bsp_init(pat);
+ boot_cpu_done = true;
+ } else {
+ pat_ap_init(pat);
+ }
}
#undef PAT
@@ -267,9 +349,9 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end,
* request is for WB.
*/
if (req_type == _PAGE_CACHE_MODE_WB) {
- u8 mtrr_type;
+ u8 mtrr_type, uniform;
- mtrr_type = mtrr_type_lookup(start, end);
+ mtrr_type = mtrr_type_lookup(start, end, &uniform);
if (mtrr_type != MTRR_TYPE_WRBACK)
return _PAGE_CACHE_MODE_UC_MINUS;
@@ -324,9 +406,14 @@ static int pat_pagerange_is_ram(resource_size_t start, resource_size_t end)
/*
* For RAM pages, we use page flags to mark the pages with appropriate type.
- * Here we do two pass:
- * - Find the memtype of all the pages in the range, look for any conflicts
- * - In case of no conflicts, set the new memtype for pages in the range
+ * The page flags are limited to four types, WB (default), WC, WT and UC-.
+ * WP request fails with -EINVAL, and UC gets redirected to UC-. Setting
+ * a new memory type is only allowed for a page mapped with the default WB
+ * type.
+ *
+ * Here we do two passes:
+ * - Find the memtype of all the pages in the range, look for any conflicts.
+ * - In case of no conflicts, set the new memtype for pages in the range.
*/
static int reserve_ram_pages_type(u64 start, u64 end,
enum page_cache_mode req_type,
@@ -335,6 +422,12 @@ static int reserve_ram_pages_type(u64 start, u64 end,
struct page *page;
u64 pfn;
+ if (req_type == _PAGE_CACHE_MODE_WP) {
+ if (new_type)
+ *new_type = _PAGE_CACHE_MODE_UC_MINUS;
+ return -EINVAL;
+ }
+
if (req_type == _PAGE_CACHE_MODE_UC) {
/* We do not support strong UC */
WARN_ON_ONCE(1);
@@ -346,8 +439,8 @@ static int reserve_ram_pages_type(u64 start, u64 end,
page = pfn_to_page(pfn);
type = get_page_memtype(page);
- if (type != -1) {
- pr_info("reserve_ram_pages_type failed [mem %#010Lx-%#010Lx], track 0x%x, req 0x%x\n",
+ if (type != _PAGE_CACHE_MODE_WB) {
+ pr_info("x86/PAT: reserve_ram_pages_type failed [mem %#010Lx-%#010Lx], track 0x%x, req 0x%x\n",
start, end - 1, type, req_type);
if (new_type)
*new_type = type;
@@ -373,7 +466,7 @@ static int free_ram_pages_type(u64 start, u64 end)
for (pfn = (start >> PAGE_SHIFT); pfn < (end >> PAGE_SHIFT); ++pfn) {
page = pfn_to_page(pfn);
- set_page_memtype(page, -1);
+ set_page_memtype(page, _PAGE_CACHE_MODE_WB);
}
return 0;
}
@@ -384,6 +477,7 @@ static int free_ram_pages_type(u64 start, u64 end)
* - _PAGE_CACHE_MODE_WC
* - _PAGE_CACHE_MODE_UC_MINUS
* - _PAGE_CACHE_MODE_UC
+ * - _PAGE_CACHE_MODE_WT
*
* If new_type is NULL, function will return an error if it cannot reserve the
* region with req_type. If new_type is non-NULL, function will return
@@ -400,14 +494,10 @@ int reserve_memtype(u64 start, u64 end, enum page_cache_mode req_type,
BUG_ON(start >= end); /* end is exclusive */
- if (!pat_enabled) {
+ if (!pat_enabled()) {
/* This is identical to page table setting without PAT */
- if (new_type) {
- if (req_type == _PAGE_CACHE_MODE_WC)
- *new_type = _PAGE_CACHE_MODE_UC_MINUS;
- else
- *new_type = req_type;
- }
+ if (new_type)
+ *new_type = req_type;
return 0;
}
@@ -451,9 +541,9 @@ int reserve_memtype(u64 start, u64 end, enum page_cache_mode req_type,
err = rbt_memtype_check_insert(new, new_type);
if (err) {
- printk(KERN_INFO "reserve_memtype failed [mem %#010Lx-%#010Lx], track %s, req %s\n",
- start, end - 1,
- cattr_name(new->type), cattr_name(req_type));
+ pr_info("x86/PAT: reserve_memtype failed [mem %#010Lx-%#010Lx], track %s, req %s\n",
+ start, end - 1,
+ cattr_name(new->type), cattr_name(req_type));
kfree(new);
spin_unlock(&memtype_lock);
@@ -475,7 +565,7 @@ int free_memtype(u64 start, u64 end)
int is_range_ram;
struct memtype *entry;
- if (!pat_enabled)
+ if (!pat_enabled())
return 0;
/* Low ISA region is always mapped WB. No need to track */
@@ -497,8 +587,8 @@ int free_memtype(u64 start, u64 end)
spin_unlock(&memtype_lock);
if (!entry) {
- printk(KERN_INFO "%s:%d freeing invalid memtype [mem %#010Lx-%#010Lx]\n",
- current->comm, current->pid, start, end - 1);
+ pr_info("x86/PAT: %s:%d freeing invalid memtype [mem %#010Lx-%#010Lx]\n",
+ current->comm, current->pid, start, end - 1);
return -EINVAL;
}
@@ -517,7 +607,7 @@ int free_memtype(u64 start, u64 end)
* Only to be called when PAT is enabled
*
* Returns _PAGE_CACHE_MODE_WB, _PAGE_CACHE_MODE_WC, _PAGE_CACHE_MODE_UC_MINUS
- * or _PAGE_CACHE_MODE_UC
+ * or _PAGE_CACHE_MODE_WT.
*/
static enum page_cache_mode lookup_memtype(u64 paddr)
{
@@ -529,16 +619,9 @@ static enum page_cache_mode lookup_memtype(u64 paddr)
if (pat_pagerange_is_ram(paddr, paddr + PAGE_SIZE)) {
struct page *page;
- page = pfn_to_page(paddr >> PAGE_SHIFT);
- rettype = get_page_memtype(page);
- /*
- * -1 from get_page_memtype() implies RAM page is in its
- * default state and not reserved, and hence of type WB
- */
- if (rettype == -1)
- rettype = _PAGE_CACHE_MODE_WB;
- return rettype;
+ page = pfn_to_page(paddr >> PAGE_SHIFT);
+ return get_page_memtype(page);
}
spin_lock(&memtype_lock);
@@ -623,13 +706,13 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
u64 to = from + size;
u64 cursor = from;
- if (!pat_enabled)
+ if (!pat_enabled())
return 1;
while (cursor < to) {
if (!devmem_is_allowed(pfn)) {
- printk(KERN_INFO "Program %s tried to access /dev/mem between [mem %#010Lx-%#010Lx], PAT prevents it\n",
- current->comm, from, to - 1);
+ pr_info("x86/PAT: Program %s tried to access /dev/mem between [mem %#010Lx-%#010Lx], PAT prevents it\n",
+ current->comm, from, to - 1);
return 0;
}
cursor += PAGE_SIZE;
@@ -659,7 +742,7 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
* caching for the high addresses through the KEN pin, but
* we maintain the tradition of paranoia in this code.
*/
- if (!pat_enabled &&
+ if (!pat_enabled() &&
!(boot_cpu_has(X86_FEATURE_MTRR) ||
boot_cpu_has(X86_FEATURE_K6_MTRR) ||
boot_cpu_has(X86_FEATURE_CYRIX_ARR) ||
@@ -698,8 +781,7 @@ int kernel_map_sync_memtype(u64 base, unsigned long size,
size;
if (ioremap_change_attr((unsigned long)__va(base), id_sz, pcm) < 0) {
- printk(KERN_INFO "%s:%d ioremap_change_attr failed %s "
- "for [mem %#010Lx-%#010Lx]\n",
+ pr_info("x86/PAT: %s:%d ioremap_change_attr failed %s for [mem %#010Lx-%#010Lx]\n",
current->comm, current->pid,
cattr_name(pcm),
base, (unsigned long long)(base + size-1));
@@ -729,12 +811,12 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
* the type requested matches the type of first page in the range.
*/
if (is_ram) {
- if (!pat_enabled)
+ if (!pat_enabled())
return 0;
pcm = lookup_memtype(paddr);
if (want_pcm != pcm) {
- printk(KERN_WARNING "%s:%d map pfn RAM range req %s for [mem %#010Lx-%#010Lx], got %s\n",
+ pr_warn("x86/PAT: %s:%d map pfn RAM range req %s for [mem %#010Lx-%#010Lx], got %s\n",
current->comm, current->pid,
cattr_name(want_pcm),
(unsigned long long)paddr,
@@ -755,13 +837,12 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
if (strict_prot ||
!is_new_memtype_allowed(paddr, size, want_pcm, pcm)) {
free_memtype(paddr, paddr + size);
- printk(KERN_ERR "%s:%d map pfn expected mapping type %s"
- " for [mem %#010Lx-%#010Lx], got %s\n",
- current->comm, current->pid,
- cattr_name(want_pcm),
- (unsigned long long)paddr,
- (unsigned long long)(paddr + size - 1),
- cattr_name(pcm));
+ pr_err("x86/PAT: %s:%d map pfn expected mapping type %s for [mem %#010Lx-%#010Lx], got %s\n",
+ current->comm, current->pid,
+ cattr_name(want_pcm),
+ (unsigned long long)paddr,
+ (unsigned long long)(paddr + size - 1),
+ cattr_name(pcm));
return -EINVAL;
}
/*
@@ -844,7 +925,7 @@ int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
return ret;
}
- if (!pat_enabled)
+ if (!pat_enabled())
return 0;
/*
@@ -872,7 +953,7 @@ int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
{
enum page_cache_mode pcm;
- if (!pat_enabled)
+ if (!pat_enabled())
return 0;
/* Set prot based on lookup */
@@ -913,14 +994,18 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
pgprot_t pgprot_writecombine(pgprot_t prot)
{
- if (pat_enabled)
- return __pgprot(pgprot_val(prot) |
+ return __pgprot(pgprot_val(prot) |
cachemode2protval(_PAGE_CACHE_MODE_WC));
- else
- return pgprot_noncached(prot);
}
EXPORT_SYMBOL_GPL(pgprot_writecombine);
+pgprot_t pgprot_writethrough(pgprot_t prot)
+{
+ return __pgprot(pgprot_val(prot) |
+ cachemode2protval(_PAGE_CACHE_MODE_WT));
+}
+EXPORT_SYMBOL_GPL(pgprot_writethrough);
+
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_X86_PAT)
static struct memtype *memtype_get_idx(loff_t pos)
@@ -996,7 +1081,7 @@ static const struct file_operations memtype_fops = {
static int __init pat_memtype_list_init(void)
{
- if (pat_enabled) {
+ if (pat_enabled()) {
debugfs_create_file("pat_memtype_list", S_IRUSR,
arch_debugfs_dir, NULL, &memtype_fops);
}
diff --git a/arch/x86/mm/pat_internal.h b/arch/x86/mm/pat_internal.h
index f6411620305d..a739bfc40690 100644
--- a/arch/x86/mm/pat_internal.h
+++ b/arch/x86/mm/pat_internal.h
@@ -4,7 +4,7 @@
extern int pat_debug_enable;
#define dprintk(fmt, arg...) \
- do { if (pat_debug_enable) printk(KERN_INFO fmt, ##arg); } while (0)
+ do { if (pat_debug_enable) pr_info("x86/PAT: " fmt, ##arg); } while (0)
struct memtype {
u64 start;
diff --git a/arch/x86/mm/pat_rbtree.c b/arch/x86/mm/pat_rbtree.c
index 6582adcc8bd9..63931080366a 100644
--- a/arch/x86/mm/pat_rbtree.c
+++ b/arch/x86/mm/pat_rbtree.c
@@ -160,9 +160,9 @@ success:
return 0;
failure:
- printk(KERN_INFO "%s:%d conflicting memory types "
- "%Lx-%Lx %s<->%s\n", current->comm, current->pid, start,
- end, cattr_name(found_type), cattr_name(match->type));
+ pr_info("x86/PAT: %s:%d conflicting memory types %Lx-%Lx %s<->%s\n",
+ current->comm, current->pid, start, end,
+ cattr_name(found_type), cattr_name(match->type));
return -EBUSY;
}
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index 0b97d2c75df3..fb0a9dd1d6e4 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -563,16 +563,31 @@ void native_set_fixmap(enum fixed_addresses idx, phys_addr_t phys,
}
#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
+/**
+ * pud_set_huge - setup kernel PUD mapping
+ *
+ * MTRRs can override PAT memory types with 4KiB granularity. Therefore, this
+ * function sets up a huge page only if any of the following conditions are met:
+ *
+ * - MTRRs are disabled, or
+ *
+ * - MTRRs are enabled and the range is completely covered by a single MTRR, or
+ *
+ * - MTRRs are enabled and the corresponding MTRR memory type is WB, which
+ * has no effect on the requested PAT memory type.
+ *
+ * Callers should try to decrease page size (1GB -> 2MB -> 4K) if the bigger
+ * page mapping attempt fails.
+ *
+ * Returns 1 on success and 0 on failure.
+ */
int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
{
- u8 mtrr;
+ u8 mtrr, uniform;
- /*
- * Do not use a huge page when the range is covered by non-WB type
- * of MTRRs.
- */
- mtrr = mtrr_type_lookup(addr, addr + PUD_SIZE);
- if ((mtrr != MTRR_TYPE_WRBACK) && (mtrr != 0xFF))
+ mtrr = mtrr_type_lookup(addr, addr + PUD_SIZE, &uniform);
+ if ((mtrr != MTRR_TYPE_INVALID) && (!uniform) &&
+ (mtrr != MTRR_TYPE_WRBACK))
return 0;
prot = pgprot_4k_2_large(prot);
@@ -584,17 +599,24 @@ int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot)
return 1;
}
+/**
+ * pmd_set_huge - setup kernel PMD mapping
+ *
+ * See text over pud_set_huge() above.
+ *
+ * Returns 1 on success and 0 on failure.
+ */
int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot)
{
- u8 mtrr;
+ u8 mtrr, uniform;
- /*
- * Do not use a huge page when the range is covered by non-WB type
- * of MTRRs.
- */
- mtrr = mtrr_type_lookup(addr, addr + PMD_SIZE);
- if ((mtrr != MTRR_TYPE_WRBACK) && (mtrr != 0xFF))
+ mtrr = mtrr_type_lookup(addr, addr + PMD_SIZE, &uniform);
+ if ((mtrr != MTRR_TYPE_INVALID) && (!uniform) &&
+ (mtrr != MTRR_TYPE_WRBACK)) {
+ pr_warn_once("%s: Cannot satisfy [mem %#010llx-%#010llx] with a huge-page mapping due to MTRR override.\n",
+ __func__, addr, addr + PMD_SIZE);
return 0;
+ }
prot = pgprot_4k_2_large(prot);
@@ -605,6 +627,11 @@ int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot)
return 1;
}
+/**
+ * pud_clear_huge - clear kernel PUD mapping when it is set
+ *
+ * Returns 1 on success and 0 on failure (no PUD map is found).
+ */
int pud_clear_huge(pud_t *pud)
{
if (pud_large(*pud)) {
@@ -615,6 +642,11 @@ int pud_clear_huge(pud_t *pud)
return 0;
}
+/**
+ * pmd_clear_huge - clear kernel PMD mapping when it is set
+ *
+ * Returns 1 on success and 0 on failure (no PMD map is found).
+ */
int pmd_clear_huge(pmd_t *pmd)
{
if (pmd_large(*pmd)) {
diff --git a/arch/x86/net/bpf_jit.S b/arch/x86/net/bpf_jit.S
index 6440221ced0d..4093216b3791 100644
--- a/arch/x86/net/bpf_jit.S
+++ b/arch/x86/net/bpf_jit.S
@@ -8,7 +8,6 @@
* of the License.
*/
#include <linux/linkage.h>
-#include <asm/dwarf2.h>
/*
* Calling convention :
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index ddeff4844a10..579a8fd74be0 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -12,6 +12,7 @@
#include <linux/filter.h>
#include <linux/if_vlan.h>
#include <asm/cacheflush.h>
+#include <linux/bpf.h>
int bpf_jit_enable __read_mostly;
@@ -37,7 +38,8 @@ static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
return ptr + len;
}
-#define EMIT(bytes, len) do { prog = emit_code(prog, bytes, len); } while (0)
+#define EMIT(bytes, len) \
+ do { prog = emit_code(prog, bytes, len); cnt += len; } while (0)
#define EMIT1(b1) EMIT(b1, 1)
#define EMIT2(b1, b2) EMIT((b1) + ((b2) << 8), 2)
@@ -186,31 +188,31 @@ struct jit_context {
#define BPF_MAX_INSN_SIZE 128
#define BPF_INSN_SAFETY 64
-static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
- int oldproglen, struct jit_context *ctx)
+#define STACKSIZE \
+ (MAX_BPF_STACK + \
+ 32 /* space for rbx, r13, r14, r15 */ + \
+ 8 /* space for skb_copy_bits() buffer */)
+
+#define PROLOGUE_SIZE 51
+
+/* emit x64 prologue code for BPF program and check it's size.
+ * bpf_tail_call helper will skip it while jumping into another program
+ */
+static void emit_prologue(u8 **pprog)
{
- struct bpf_insn *insn = bpf_prog->insnsi;
- int insn_cnt = bpf_prog->len;
- bool seen_ld_abs = ctx->seen_ld_abs | (oldproglen == 0);
- bool seen_exit = false;
- u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY];
- int i;
- int proglen = 0;
- u8 *prog = temp;
- int stacksize = MAX_BPF_STACK +
- 32 /* space for rbx, r13, r14, r15 */ +
- 8 /* space for skb_copy_bits() buffer */;
+ u8 *prog = *pprog;
+ int cnt = 0;
EMIT1(0x55); /* push rbp */
EMIT3(0x48, 0x89, 0xE5); /* mov rbp,rsp */
- /* sub rsp, stacksize */
- EMIT3_off32(0x48, 0x81, 0xEC, stacksize);
+ /* sub rsp, STACKSIZE */
+ EMIT3_off32(0x48, 0x81, 0xEC, STACKSIZE);
/* all classic BPF filters use R6(rbx) save it */
/* mov qword ptr [rbp-X],rbx */
- EMIT3_off32(0x48, 0x89, 0x9D, -stacksize);
+ EMIT3_off32(0x48, 0x89, 0x9D, -STACKSIZE);
/* bpf_convert_filter() maps classic BPF register X to R7 and uses R8
* as temporary, so all tcpdump filters need to spill/fill R7(r13) and
@@ -221,16 +223,112 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
*/
/* mov qword ptr [rbp-X],r13 */
- EMIT3_off32(0x4C, 0x89, 0xAD, -stacksize + 8);
+ EMIT3_off32(0x4C, 0x89, 0xAD, -STACKSIZE + 8);
/* mov qword ptr [rbp-X],r14 */
- EMIT3_off32(0x4C, 0x89, 0xB5, -stacksize + 16);
+ EMIT3_off32(0x4C, 0x89, 0xB5, -STACKSIZE + 16);
/* mov qword ptr [rbp-X],r15 */
- EMIT3_off32(0x4C, 0x89, 0xBD, -stacksize + 24);
+ EMIT3_off32(0x4C, 0x89, 0xBD, -STACKSIZE + 24);
/* clear A and X registers */
EMIT2(0x31, 0xc0); /* xor eax, eax */
EMIT3(0x4D, 0x31, 0xED); /* xor r13, r13 */
+ /* clear tail_cnt: mov qword ptr [rbp-X], rax */
+ EMIT3_off32(0x48, 0x89, 0x85, -STACKSIZE + 32);
+
+ BUILD_BUG_ON(cnt != PROLOGUE_SIZE);
+ *pprog = prog;
+}
+
+/* generate the following code:
+ * ... bpf_tail_call(void *ctx, struct bpf_array *array, u64 index) ...
+ * if (index >= array->map.max_entries)
+ * goto out;
+ * if (++tail_call_cnt > MAX_TAIL_CALL_CNT)
+ * goto out;
+ * prog = array->prog[index];
+ * if (prog == NULL)
+ * goto out;
+ * goto *(prog->bpf_func + prologue_size);
+ * out:
+ */
+static void emit_bpf_tail_call(u8 **pprog)
+{
+ u8 *prog = *pprog;
+ int label1, label2, label3;
+ int cnt = 0;
+
+ /* rdi - pointer to ctx
+ * rsi - pointer to bpf_array
+ * rdx - index in bpf_array
+ */
+
+ /* if (index >= array->map.max_entries)
+ * goto out;
+ */
+ EMIT4(0x48, 0x8B, 0x46, /* mov rax, qword ptr [rsi + 16] */
+ offsetof(struct bpf_array, map.max_entries));
+ EMIT3(0x48, 0x39, 0xD0); /* cmp rax, rdx */
+#define OFFSET1 44 /* number of bytes to jump */
+ EMIT2(X86_JBE, OFFSET1); /* jbe out */
+ label1 = cnt;
+
+ /* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
+ * goto out;
+ */
+ EMIT2_off32(0x8B, 0x85, -STACKSIZE + 36); /* mov eax, dword ptr [rbp - 516] */
+ EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */
+#define OFFSET2 33
+ EMIT2(X86_JA, OFFSET2); /* ja out */
+ label2 = cnt;
+ EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */
+ EMIT2_off32(0x89, 0x85, -STACKSIZE + 36); /* mov dword ptr [rbp - 516], eax */
+
+ /* prog = array->prog[index]; */
+ EMIT4(0x48, 0x8D, 0x44, 0xD6); /* lea rax, [rsi + rdx * 8 + 0x50] */
+ EMIT1(offsetof(struct bpf_array, prog));
+ EMIT3(0x48, 0x8B, 0x00); /* mov rax, qword ptr [rax] */
+
+ /* if (prog == NULL)
+ * goto out;
+ */
+ EMIT4(0x48, 0x83, 0xF8, 0x00); /* cmp rax, 0 */
+#define OFFSET3 10
+ EMIT2(X86_JE, OFFSET3); /* je out */
+ label3 = cnt;
+
+ /* goto *(prog->bpf_func + prologue_size); */
+ EMIT4(0x48, 0x8B, 0x40, /* mov rax, qword ptr [rax + 32] */
+ offsetof(struct bpf_prog, bpf_func));
+ EMIT4(0x48, 0x83, 0xC0, PROLOGUE_SIZE); /* add rax, prologue_size */
+
+ /* now we're ready to jump into next BPF program
+ * rdi == ctx (1st arg)
+ * rax == prog->bpf_func + prologue_size
+ */
+ EMIT2(0xFF, 0xE0); /* jmp rax */
+
+ /* out: */
+ BUILD_BUG_ON(cnt - label1 != OFFSET1);
+ BUILD_BUG_ON(cnt - label2 != OFFSET2);
+ BUILD_BUG_ON(cnt - label3 != OFFSET3);
+ *pprog = prog;
+}
+
+static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
+ int oldproglen, struct jit_context *ctx)
+{
+ struct bpf_insn *insn = bpf_prog->insnsi;
+ int insn_cnt = bpf_prog->len;
+ bool seen_ld_abs = ctx->seen_ld_abs | (oldproglen == 0);
+ bool seen_exit = false;
+ u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY];
+ int i, cnt = 0;
+ int proglen = 0;
+ u8 *prog = temp;
+
+ emit_prologue(&prog);
+
if (seen_ld_abs) {
/* r9d : skb->len - skb->data_len (headlen)
* r10 : skb->data
@@ -739,6 +837,10 @@ xadd: if (is_imm8(insn->off))
}
break;
+ case BPF_JMP | BPF_CALL | BPF_X:
+ emit_bpf_tail_call(&prog);
+ break;
+
/* cond jump */
case BPF_JMP | BPF_JEQ | BPF_X:
case BPF_JMP | BPF_JNE | BPF_X:
@@ -891,13 +993,13 @@ common_load:
/* update cleanup_addr */
ctx->cleanup_addr = proglen;
/* mov rbx, qword ptr [rbp-X] */
- EMIT3_off32(0x48, 0x8B, 0x9D, -stacksize);
+ EMIT3_off32(0x48, 0x8B, 0x9D, -STACKSIZE);
/* mov r13, qword ptr [rbp-X] */
- EMIT3_off32(0x4C, 0x8B, 0xAD, -stacksize + 8);
+ EMIT3_off32(0x4C, 0x8B, 0xAD, -STACKSIZE + 8);
/* mov r14, qword ptr [rbp-X] */
- EMIT3_off32(0x4C, 0x8B, 0xB5, -stacksize + 16);
+ EMIT3_off32(0x4C, 0x8B, 0xB5, -STACKSIZE + 16);
/* mov r15, qword ptr [rbp-X] */
- EMIT3_off32(0x4C, 0x8B, 0xBD, -stacksize + 24);
+ EMIT3_off32(0x4C, 0x8B, 0xBD, -STACKSIZE + 24);
EMIT1(0xC9); /* leave */
EMIT1(0xC3); /* ret */
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 14a63ed6fe09..ff9911707160 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -81,6 +81,17 @@ static const struct dmi_system_id pci_crs_quirks[] __initconst = {
DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
},
},
+ /* https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/931368 */
+ /* https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/1033299 */
+ {
+ .callback = set_use_crs,
+ .ident = "Foxconn K8M890-8237A",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Foxconn"),
+ DMI_MATCH(DMI_BOARD_NAME, "K8M890-8237A"),
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
+ },
+ },
/* Now for the blacklist.. */
@@ -121,8 +132,10 @@ void __init pci_acpi_crs_quirks(void)
{
int year;
- if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008)
- pci_use_crs = false;
+ if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008) {
+ if (iomem_resource.end <= 0xffffffff)
+ pci_use_crs = false;
+ }
dmi_check_system(pci_crs_quirks);
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 349c0d32cc0b..0a9f2caf358f 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -429,12 +429,12 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
* Caller can followup with UC MINUS request and add a WC mtrr if there
* is a free mtrr slot.
*/
- if (!pat_enabled && write_combine)
+ if (!pat_enabled() && write_combine)
return -EINVAL;
- if (pat_enabled && write_combine)
+ if (pat_enabled() && write_combine)
prot |= cachemode2protval(_PAGE_CACHE_MODE_WC);
- else if (pat_enabled || boot_cpu_data.x86 > 3)
+ else if (pat_enabled() || boot_cpu_data.x86 > 3)
/*
* ioremap() and ioremap_nocache() defaults to UC MINUS for now.
* To avoid attribute conflicts, request UC MINUS here
diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c
index 852aa4c92da0..27062303c881 100644
--- a/arch/x86/pci/intel_mid_pci.c
+++ b/arch/x86/pci/intel_mid_pci.c
@@ -208,6 +208,7 @@ static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
static int intel_mid_pci_irq_enable(struct pci_dev *dev)
{
+ struct irq_alloc_info info;
int polarity;
if (dev->irq_managed && dev->irq > 0)
@@ -217,14 +218,13 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
polarity = 0; /* active high */
else
polarity = 1; /* active low */
+ ioapic_set_alloc_attr(&info, dev_to_node(&dev->dev), 1, polarity);
/*
* MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to
* IOAPIC RTE entries, so we just enable RTE for the device.
*/
- if (mp_set_gsi_attr(dev->irq, 1, polarity, dev_to_node(&dev->dev)))
- return -EBUSY;
- if (mp_map_gsi_to_irq(dev->irq, IOAPIC_MAP_ALLOC) < 0)
+ if (mp_map_gsi_to_irq(dev->irq, IOAPIC_MAP_ALLOC, &info) < 0)
return -EBUSY;
dev->irq_managed = 1;
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 5dc6ca5e1741..9bd115484745 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -146,19 +146,20 @@ static void __init pirq_peer_trick(void)
/*
* Code for querying and setting of IRQ routes on various interrupt routers.
+ * PIC Edge/Level Control Registers (ELCR) 0x4d0 & 0x4d1.
*/
-void eisa_set_level_irq(unsigned int irq)
+void elcr_set_level_irq(unsigned int irq)
{
unsigned char mask = 1 << (irq & 7);
unsigned int port = 0x4d0 + (irq >> 3);
unsigned char val;
- static u16 eisa_irq_mask;
+ static u16 elcr_irq_mask;
- if (irq >= 16 || (1 << irq) & eisa_irq_mask)
+ if (irq >= 16 || (1 << irq) & elcr_irq_mask)
return;
- eisa_irq_mask |= (1 << irq);
+ elcr_irq_mask |= (1 << irq);
printk(KERN_DEBUG "PCI: setting IRQ %u as level-triggered\n", irq);
val = inb(port);
if (!(val & mask)) {
@@ -965,11 +966,11 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
} else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask))) {
msg = "found";
- eisa_set_level_irq(irq);
+ elcr_set_level_irq(irq);
} else if (newirq && r->set &&
(dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
if (r->set(pirq_router_dev, dev, pirq, newirq)) {
- eisa_set_level_irq(newirq);
+ elcr_set_level_irq(newirq);
msg = "assigned";
irq = newirq;
}
diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile
index a62e0be3a2f1..f1a6c8e86ddd 100644
--- a/arch/x86/platform/Makefile
+++ b/arch/x86/platform/Makefile
@@ -1,4 +1,5 @@
# Platform specific code goes here
+obj-y += atom/
obj-y += ce4100/
obj-y += efi/
obj-y += geode/
diff --git a/arch/x86/platform/atom/Makefile b/arch/x86/platform/atom/Makefile
new file mode 100644
index 000000000000..0a3a40cbc794
--- /dev/null
+++ b/arch/x86/platform/atom/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PUNIT_ATOM_DEBUG) += punit_atom_debug.o
diff --git a/arch/x86/platform/atom/punit_atom_debug.c b/arch/x86/platform/atom/punit_atom_debug.c
new file mode 100644
index 000000000000..5ca8ead91579
--- /dev/null
+++ b/arch/x86/platform/atom/punit_atom_debug.c
@@ -0,0 +1,183 @@
+/*
+ * Intel SOC Punit device state debug driver
+ * Punit controls power management for North Complex devices (Graphics
+ * blocks, Image Signal Processing, video processing, display, DSP etc.)
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/io.h>
+#include <asm/cpu_device_id.h>
+#include <asm/iosf_mbi.h>
+
+/* Side band Interface port */
+#define PUNIT_PORT 0x04
+/* Power gate status reg */
+#define PWRGT_STATUS 0x61
+/* Subsystem config/status Video processor */
+#define VED_SS_PM0 0x32
+/* Subsystem config/status ISP (Image Signal Processor) */
+#define ISP_SS_PM0 0x39
+/* Subsystem config/status Input/output controller */
+#define MIO_SS_PM 0x3B
+/* Shift bits for getting status for video, isp and i/o */
+#define SSS_SHIFT 24
+/* Shift bits for getting status for graphics rendering */
+#define RENDER_POS 0
+/* Shift bits for getting status for media control */
+#define MEDIA_POS 2
+/* Shift bits for getting status for Valley View/Baytrail display */
+#define VLV_DISPLAY_POS 6
+/* Subsystem config/status display for Cherry Trail SOC */
+#define CHT_DSP_SSS 0x36
+/* Shift bits for getting status for display */
+#define CHT_DSP_SSS_POS 16
+
+struct punit_device {
+ char *name;
+ int reg;
+ int sss_pos;
+};
+
+static const struct punit_device punit_device_byt[] = {
+ { "GFX RENDER", PWRGT_STATUS, RENDER_POS },
+ { "GFX MEDIA", PWRGT_STATUS, MEDIA_POS },
+ { "DISPLAY", PWRGT_STATUS, VLV_DISPLAY_POS },
+ { "VED", VED_SS_PM0, SSS_SHIFT },
+ { "ISP", ISP_SS_PM0, SSS_SHIFT },
+ { "MIO", MIO_SS_PM, SSS_SHIFT },
+ { NULL }
+};
+
+static const struct punit_device punit_device_cht[] = {
+ { "GFX RENDER", PWRGT_STATUS, RENDER_POS },
+ { "GFX MEDIA", PWRGT_STATUS, MEDIA_POS },
+ { "DISPLAY", CHT_DSP_SSS, CHT_DSP_SSS_POS },
+ { "VED", VED_SS_PM0, SSS_SHIFT },
+ { "ISP", ISP_SS_PM0, SSS_SHIFT },
+ { "MIO", MIO_SS_PM, SSS_SHIFT },
+ { NULL }
+};
+
+static const char * const dstates[] = {"D0", "D0i1", "D0i2", "D0i3"};
+
+static int punit_dev_state_show(struct seq_file *seq_file, void *unused)
+{
+ u32 punit_pwr_status;
+ struct punit_device *punit_devp = seq_file->private;
+ int index;
+ int status;
+
+ seq_puts(seq_file, "\n\nPUNIT NORTH COMPLEX DEVICES :\n");
+ while (punit_devp->name) {
+ status = iosf_mbi_read(PUNIT_PORT, BT_MBI_PMC_READ,
+ punit_devp->reg,
+ &punit_pwr_status);
+ if (status) {
+ seq_printf(seq_file, "%9s : Read Failed\n",
+ punit_devp->name);
+ } else {
+ index = (punit_pwr_status >> punit_devp->sss_pos) & 3;
+ seq_printf(seq_file, "%9s : %s\n", punit_devp->name,
+ dstates[index]);
+ }
+ punit_devp++;
+ }
+
+ return 0;
+}
+
+static int punit_dev_state_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, punit_dev_state_show, inode->i_private);
+}
+
+static const struct file_operations punit_dev_state_ops = {
+ .open = punit_dev_state_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *punit_dbg_file;
+
+static int punit_dbgfs_register(struct punit_device *punit_device)
+{
+ static struct dentry *dev_state;
+
+ punit_dbg_file = debugfs_create_dir("punit_atom", NULL);
+ if (!punit_dbg_file)
+ return -ENXIO;
+
+ dev_state = debugfs_create_file("dev_power_state", S_IFREG | S_IRUGO,
+ punit_dbg_file, punit_device,
+ &punit_dev_state_ops);
+ if (!dev_state) {
+ pr_err("punit_dev_state register failed\n");
+ debugfs_remove(punit_dbg_file);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void punit_dbgfs_unregister(void)
+{
+ debugfs_remove_recursive(punit_dbg_file);
+}
+
+#define ICPU(model, drv_data) \
+ { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT,\
+ (kernel_ulong_t)&drv_data }
+
+static const struct x86_cpu_id intel_punit_cpu_ids[] = {
+ ICPU(55, punit_device_byt), /* Valleyview, Bay Trail */
+ ICPU(76, punit_device_cht), /* Braswell, Cherry Trail */
+ {}
+};
+
+MODULE_DEVICE_TABLE(x86cpu, intel_punit_cpu_ids);
+
+static int __init punit_atom_debug_init(void)
+{
+ const struct x86_cpu_id *id;
+ int ret;
+
+ id = x86_match_cpu(intel_punit_cpu_ids);
+ if (!id)
+ return -ENODEV;
+
+ ret = punit_dbgfs_register((struct punit_device *)id->driver_data);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void __exit punit_atom_debug_exit(void)
+{
+ punit_dbgfs_unregister();
+}
+
+module_init(punit_atom_debug_init);
+module_exit(punit_atom_debug_exit);
+
+MODULE_AUTHOR("Kumar P, Mahesh <mahesh.kumar.p@intel.com>");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_DESCRIPTION("Driver for Punit devices states debugging");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 02744df576d5..c1c382c58c60 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -117,6 +117,27 @@ void efi_get_time(struct timespec *now)
now->tv_nsec = 0;
}
+void __init efi_find_mirror(void)
+{
+ void *p;
+ u64 mirror_size = 0, total_size = 0;
+
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ efi_memory_desc_t *md = p;
+ unsigned long long start = md->phys_addr;
+ unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
+
+ total_size += size;
+ if (md->attribute & EFI_MEMORY_MORE_RELIABLE) {
+ memblock_mark_mirror(start, size);
+ mirror_size += size;
+ }
+ }
+ if (mirror_size)
+ pr_info("Memory: %lldM/%lldM mirrored memory\n",
+ mirror_size>>20, total_size>>20);
+}
+
/*
* Tell the kernel about the EFI memory map. This might include
* more than the max 128 entries that can fit in the e820 legacy
@@ -501,6 +522,8 @@ void __init efi_init(void)
if (efi_enabled(EFI_DBG))
print_efi_memmap();
+
+ efi_esrt_init();
}
void __init efi_late_init(void)
diff --git a/arch/x86/platform/intel-mid/device_libs/platform_wdt.c b/arch/x86/platform/intel-mid/device_libs/platform_wdt.c
index 0b283d4d0ad7..de734134bc8d 100644
--- a/arch/x86/platform/intel-mid/device_libs/platform_wdt.c
+++ b/arch/x86/platform/intel-mid/device_libs/platform_wdt.c
@@ -27,6 +27,7 @@ static struct platform_device wdt_dev = {
static int tangier_probe(struct platform_device *pdev)
{
int gsi;
+ struct irq_alloc_info info;
struct intel_mid_wdt_pdata *pdata = pdev->dev.platform_data;
if (!pdata)
@@ -34,8 +35,8 @@ static int tangier_probe(struct platform_device *pdev)
/* IOAPIC builds identity mapping between GSI and IRQ on MID */
gsi = pdata->irq;
- if (mp_set_gsi_attr(gsi, 1, 0, cpu_to_node(0)) ||
- mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC) <= 0) {
+ ioapic_set_alloc_attr(&info, cpu_to_node(0), 1, 0);
+ if (mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC, &info) <= 0) {
dev_warn(&pdev->dev, "cannot find interrupt %d in ioapic\n",
gsi);
return -EINVAL;
diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c
index 3005f0c89f2e..01d54ea766c1 100644
--- a/arch/x86/platform/intel-mid/intel-mid.c
+++ b/arch/x86/platform/intel-mid/intel-mid.c
@@ -81,26 +81,34 @@ static unsigned long __init intel_mid_calibrate_tsc(void)
return 0;
}
+static void __init intel_mid_setup_bp_timer(void)
+{
+ apbt_time_init();
+ setup_boot_APIC_clock();
+}
+
static void __init intel_mid_time_init(void)
{
sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr);
+
switch (intel_mid_timer_options) {
case INTEL_MID_TIMER_APBT_ONLY:
break;
case INTEL_MID_TIMER_LAPIC_APBT:
- x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
+ /* Use apbt and local apic */
+ x86_init.timers.setup_percpu_clockev = intel_mid_setup_bp_timer;
x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
- break;
+ return;
default:
if (!boot_cpu_has(X86_FEATURE_ARAT))
break;
+ /* Lapic only, no apbt */
x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
return;
}
- /* we need at least one APB timer */
- pre_init_apic_IRQ0();
- apbt_time_init();
+
+ x86_init.timers.setup_percpu_clockev = apbt_time_init;
}
static void intel_mid_arch_setup(void)
diff --git a/arch/x86/platform/intel-mid/sfi.c b/arch/x86/platform/intel-mid/sfi.c
index c14ad34776c4..ce992e8cc065 100644
--- a/arch/x86/platform/intel-mid/sfi.c
+++ b/arch/x86/platform/intel-mid/sfi.c
@@ -95,18 +95,16 @@ int __init sfi_parse_mtmr(struct sfi_table_header *table)
pr_debug("timer[%d]: paddr = 0x%08x, freq = %dHz, irq = %d\n",
totallen, (u32)pentry->phys_addr,
pentry->freq_hz, pentry->irq);
- if (!pentry->irq)
- continue;
- mp_irq.type = MP_INTSRC;
- mp_irq.irqtype = mp_INT;
-/* triggering mode edge bit 2-3, active high polarity bit 0-1 */
- mp_irq.irqflag = 5;
- mp_irq.srcbus = MP_BUS_ISA;
- mp_irq.srcbusirq = pentry->irq; /* IRQ */
- mp_irq.dstapic = MP_APIC_ALL;
- mp_irq.dstirq = pentry->irq;
- mp_save_irq(&mp_irq);
- mp_map_gsi_to_irq(pentry->irq, IOAPIC_MAP_ALLOC);
+ mp_irq.type = MP_INTSRC;
+ mp_irq.irqtype = mp_INT;
+ /* triggering mode edge bit 2-3, active high polarity bit 0-1 */
+ mp_irq.irqflag = 5;
+ mp_irq.srcbus = MP_BUS_ISA;
+ mp_irq.srcbusirq = pentry->irq; /* IRQ */
+ mp_irq.dstapic = MP_APIC_ALL;
+ mp_irq.dstirq = pentry->irq;
+ mp_save_irq(&mp_irq);
+ mp_map_gsi_to_irq(pentry->irq, IOAPIC_MAP_ALLOC, NULL);
}
return 0;
@@ -177,7 +175,7 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table)
mp_irq.dstapic = MP_APIC_ALL;
mp_irq.dstirq = pentry->irq;
mp_save_irq(&mp_irq);
- mp_map_gsi_to_irq(pentry->irq, IOAPIC_MAP_ALLOC);
+ mp_map_gsi_to_irq(pentry->irq, IOAPIC_MAP_ALLOC, NULL);
}
return 0;
}
@@ -436,6 +434,7 @@ static int __init sfi_parse_devs(struct sfi_table_header *table)
struct devs_id *dev = NULL;
int num, i, ret;
int polarity;
+ struct irq_alloc_info info;
sb = (struct sfi_table_simple *)table;
num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry);
@@ -469,9 +468,8 @@ static int __init sfi_parse_devs(struct sfi_table_header *table)
polarity = 1;
}
- ret = mp_set_gsi_attr(irq, 1, polarity, NUMA_NO_NODE);
- if (ret == 0)
- ret = mp_map_gsi_to_irq(irq, IOAPIC_MAP_ALLOC);
+ ioapic_set_alloc_attr(&info, NUMA_NO_NODE, 1, polarity);
+ ret = mp_map_gsi_to_irq(irq, IOAPIC_MAP_ALLOC, &info);
WARN_ON(ret < 0);
}
diff --git a/arch/x86/platform/sfi/sfi.c b/arch/x86/platform/sfi/sfi.c
index 2a8a74f3bd76..6c7111bbd1e9 100644
--- a/arch/x86/platform/sfi/sfi.c
+++ b/arch/x86/platform/sfi/sfi.c
@@ -25,8 +25,8 @@
#include <linux/init.h>
#include <linux/sfi.h>
#include <linux/io.h>
-#include <linux/irqdomain.h>
+#include <asm/irqdomain.h>
#include <asm/io_apic.h>
#include <asm/mpspec.h>
#include <asm/setup.h>
@@ -71,9 +71,6 @@ static int __init sfi_parse_cpus(struct sfi_table_header *table)
#endif /* CONFIG_X86_LOCAL_APIC */
#ifdef CONFIG_X86_IO_APIC
-static struct irq_domain_ops sfi_ioapic_irqdomain_ops = {
- .map = mp_irqdomain_map,
-};
static int __init sfi_parse_ioapic(struct sfi_table_header *table)
{
@@ -82,7 +79,7 @@ static int __init sfi_parse_ioapic(struct sfi_table_header *table)
int i, num;
struct ioapic_domain_cfg cfg = {
.type = IOAPIC_DOMAIN_STRICT,
- .ops = &sfi_ioapic_irqdomain_ops,
+ .ops = &mp_ioapic_irqdomain_ops,
};
sb = (struct sfi_table_simple *)table;
diff --git a/arch/x86/platform/uv/uv_irq.c b/arch/x86/platform/uv/uv_irq.c
index 0ce673645432..8570abe68be1 100644
--- a/arch/x86/platform/uv/uv_irq.c
+++ b/arch/x86/platform/uv/uv_irq.c
@@ -13,22 +13,37 @@
#include <linux/slab.h>
#include <linux/irq.h>
+#include <asm/irqdomain.h>
#include <asm/apic.h>
#include <asm/uv/uv_irq.h>
#include <asm/uv/uv_hub.h>
/* MMR offset and pnode of hub sourcing interrupts for a given irq */
-struct uv_irq_2_mmr_pnode{
- struct rb_node list;
+struct uv_irq_2_mmr_pnode {
unsigned long offset;
int pnode;
- int irq;
};
-static DEFINE_SPINLOCK(uv_irq_lock);
-static struct rb_root uv_irq_root;
+static void uv_program_mmr(struct irq_cfg *cfg, struct uv_irq_2_mmr_pnode *info)
+{
+ unsigned long mmr_value;
+ struct uv_IO_APIC_route_entry *entry;
+
+ BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
+ sizeof(unsigned long));
+
+ mmr_value = 0;
+ entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+ entry->vector = cfg->vector;
+ entry->delivery_mode = apic->irq_delivery_mode;
+ entry->dest_mode = apic->irq_dest_mode;
+ entry->polarity = 0;
+ entry->trigger = 0;
+ entry->mask = 0;
+ entry->dest = cfg->dest_apicid;
-static int uv_set_irq_affinity(struct irq_data *, const struct cpumask *, bool);
+ uv_write_global_mmr64(info->pnode, info->offset, mmr_value);
+}
static void uv_noop(struct irq_data *data) { }
@@ -37,6 +52,23 @@ static void uv_ack_apic(struct irq_data *data)
ack_APIC_irq();
}
+static int
+uv_set_irq_affinity(struct irq_data *data, const struct cpumask *mask,
+ bool force)
+{
+ struct irq_data *parent = data->parent_data;
+ struct irq_cfg *cfg = irqd_cfg(data);
+ int ret;
+
+ ret = parent->chip->irq_set_affinity(parent, mask, force);
+ if (ret >= 0) {
+ uv_program_mmr(cfg, data->chip_data);
+ send_cleanup_vector(cfg);
+ }
+
+ return ret;
+}
+
static struct irq_chip uv_irq_chip = {
.name = "UV-CORE",
.irq_mask = uv_noop,
@@ -45,189 +77,99 @@ static struct irq_chip uv_irq_chip = {
.irq_set_affinity = uv_set_irq_affinity,
};
-/*
- * Add offset and pnode information of the hub sourcing interrupts to the
- * rb tree for a specific irq.
- */
-static int uv_set_irq_2_mmr_info(int irq, unsigned long offset, unsigned blade)
+static int uv_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
{
- struct rb_node **link = &uv_irq_root.rb_node;
- struct rb_node *parent = NULL;
- struct uv_irq_2_mmr_pnode *n;
- struct uv_irq_2_mmr_pnode *e;
- unsigned long irqflags;
-
- n = kmalloc_node(sizeof(struct uv_irq_2_mmr_pnode), GFP_KERNEL,
- uv_blade_to_memory_nid(blade));
- if (!n)
+ struct uv_irq_2_mmr_pnode *chip_data;
+ struct irq_alloc_info *info = arg;
+ struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq);
+ int ret;
+
+ if (nr_irqs > 1 || !info || info->type != X86_IRQ_ALLOC_TYPE_UV)
+ return -EINVAL;
+
+ chip_data = kmalloc_node(sizeof(*chip_data), GFP_KERNEL,
+ irq_data->node);
+ if (!chip_data)
return -ENOMEM;
- n->irq = irq;
- n->offset = offset;
- n->pnode = uv_blade_to_pnode(blade);
- spin_lock_irqsave(&uv_irq_lock, irqflags);
- /* Find the right place in the rbtree: */
- while (*link) {
- parent = *link;
- e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list);
-
- if (unlikely(irq == e->irq)) {
- /* irq entry exists */
- e->pnode = uv_blade_to_pnode(blade);
- e->offset = offset;
- spin_unlock_irqrestore(&uv_irq_lock, irqflags);
- kfree(n);
- return 0;
- }
-
- if (irq < e->irq)
- link = &(*link)->rb_left;
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+ if (ret >= 0) {
+ if (info->uv_limit == UV_AFFINITY_CPU)
+ irq_set_status_flags(virq, IRQ_NO_BALANCING);
else
- link = &(*link)->rb_right;
+ irq_set_status_flags(virq, IRQ_MOVE_PCNTXT);
+
+ chip_data->pnode = uv_blade_to_pnode(info->uv_blade);
+ chip_data->offset = info->uv_offset;
+ irq_domain_set_info(domain, virq, virq, &uv_irq_chip, chip_data,
+ handle_percpu_irq, NULL, info->uv_name);
+ } else {
+ kfree(chip_data);
}
- /* Insert the node into the rbtree. */
- rb_link_node(&n->list, parent, link);
- rb_insert_color(&n->list, &uv_irq_root);
-
- spin_unlock_irqrestore(&uv_irq_lock, irqflags);
- return 0;
+ return ret;
}
-/* Retrieve offset and pnode information from the rb tree for a specific irq */
-int uv_irq_2_mmr_info(int irq, unsigned long *offset, int *pnode)
+static void uv_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
{
- struct uv_irq_2_mmr_pnode *e;
- struct rb_node *n;
- unsigned long irqflags;
-
- spin_lock_irqsave(&uv_irq_lock, irqflags);
- n = uv_irq_root.rb_node;
- while (n) {
- e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
-
- if (e->irq == irq) {
- *offset = e->offset;
- *pnode = e->pnode;
- spin_unlock_irqrestore(&uv_irq_lock, irqflags);
- return 0;
- }
-
- if (irq < e->irq)
- n = n->rb_left;
- else
- n = n->rb_right;
- }
- spin_unlock_irqrestore(&uv_irq_lock, irqflags);
- return -1;
+ struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq);
+
+ BUG_ON(nr_irqs != 1);
+ kfree(irq_data->chip_data);
+ irq_clear_status_flags(virq, IRQ_MOVE_PCNTXT);
+ irq_clear_status_flags(virq, IRQ_NO_BALANCING);
+ irq_domain_free_irqs_top(domain, virq, nr_irqs);
}
/*
* Re-target the irq to the specified CPU and enable the specified MMR located
* on the specified blade to allow the sending of MSIs to the specified CPU.
*/
-static int
-arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
- unsigned long mmr_offset, int limit)
+static void uv_domain_activate(struct irq_domain *domain,
+ struct irq_data *irq_data)
{
- const struct cpumask *eligible_cpu = cpumask_of(cpu);
- struct irq_cfg *cfg = irq_cfg(irq);
- unsigned long mmr_value;
- struct uv_IO_APIC_route_entry *entry;
- int mmr_pnode, err;
- unsigned int dest;
-
- BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
- sizeof(unsigned long));
-
- err = assign_irq_vector(irq, cfg, eligible_cpu);
- if (err != 0)
- return err;
-
- err = apic->cpu_mask_to_apicid_and(eligible_cpu, eligible_cpu, &dest);
- if (err != 0)
- return err;
-
- if (limit == UV_AFFINITY_CPU)
- irq_set_status_flags(irq, IRQ_NO_BALANCING);
- else
- irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-
- irq_set_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
- irq_name);
-
- mmr_value = 0;
- entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
- entry->vector = cfg->vector;
- entry->delivery_mode = apic->irq_delivery_mode;
- entry->dest_mode = apic->irq_dest_mode;
- entry->polarity = 0;
- entry->trigger = 0;
- entry->mask = 0;
- entry->dest = dest;
-
- mmr_pnode = uv_blade_to_pnode(mmr_blade);
- uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
-
- if (cfg->move_in_progress)
- send_cleanup_vector(cfg);
-
- return irq;
+ uv_program_mmr(irqd_cfg(irq_data), irq_data->chip_data);
}
/*
* Disable the specified MMR located on the specified blade so that MSIs are
* longer allowed to be sent.
*/
-static void arch_disable_uv_irq(int mmr_pnode, unsigned long mmr_offset)
+static void uv_domain_deactivate(struct irq_domain *domain,
+ struct irq_data *irq_data)
{
unsigned long mmr_value;
struct uv_IO_APIC_route_entry *entry;
- BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
- sizeof(unsigned long));
-
mmr_value = 0;
entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
entry->mask = 1;
-
- uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+ uv_program_mmr(irqd_cfg(irq_data), irq_data->chip_data);
}
-static int
-uv_set_irq_affinity(struct irq_data *data, const struct cpumask *mask,
- bool force)
-{
- struct irq_cfg *cfg = irqd_cfg(data);
- unsigned int dest;
- unsigned long mmr_value, mmr_offset;
- struct uv_IO_APIC_route_entry *entry;
- int mmr_pnode;
-
- if (apic_set_affinity(data, mask, &dest))
- return -1;
-
- mmr_value = 0;
- entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
-
- entry->vector = cfg->vector;
- entry->delivery_mode = apic->irq_delivery_mode;
- entry->dest_mode = apic->irq_dest_mode;
- entry->polarity = 0;
- entry->trigger = 0;
- entry->mask = 0;
- entry->dest = dest;
-
- /* Get previously stored MMR and pnode of hub sourcing interrupts */
- if (uv_irq_2_mmr_info(data->irq, &mmr_offset, &mmr_pnode))
- return -1;
-
- uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+static const struct irq_domain_ops uv_domain_ops = {
+ .alloc = uv_domain_alloc,
+ .free = uv_domain_free,
+ .activate = uv_domain_activate,
+ .deactivate = uv_domain_deactivate,
+};
- if (cfg->move_in_progress)
- send_cleanup_vector(cfg);
+static struct irq_domain *uv_get_irq_domain(void)
+{
+ static struct irq_domain *uv_domain;
+ static DEFINE_MUTEX(uv_lock);
+
+ mutex_lock(&uv_lock);
+ if (uv_domain == NULL) {
+ uv_domain = irq_domain_add_tree(NULL, &uv_domain_ops, NULL);
+ if (uv_domain)
+ uv_domain->parent = x86_vector_domain;
+ }
+ mutex_unlock(&uv_lock);
- return IRQ_SET_MASK_OK_NOCOPY;
+ return uv_domain;
}
/*
@@ -238,19 +180,21 @@ uv_set_irq_affinity(struct irq_data *data, const struct cpumask *mask,
int uv_setup_irq(char *irq_name, int cpu, int mmr_blade,
unsigned long mmr_offset, int limit)
{
- int ret, irq = irq_alloc_hwirq(uv_blade_to_memory_nid(mmr_blade));
+ struct irq_alloc_info info;
+ struct irq_domain *domain = uv_get_irq_domain();
- if (!irq)
- return -EBUSY;
+ if (!domain)
+ return -ENOMEM;
- ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset,
- limit);
- if (ret == irq)
- uv_set_irq_2_mmr_info(irq, mmr_offset, mmr_blade);
- else
- irq_free_hwirq(irq);
+ init_irq_alloc_info(&info, cpumask_of(cpu));
+ info.type = X86_IRQ_ALLOC_TYPE_UV;
+ info.uv_limit = limit;
+ info.uv_blade = mmr_blade;
+ info.uv_offset = mmr_offset;
+ info.uv_name = irq_name;
- return ret;
+ return irq_domain_alloc_irqs(domain, 1,
+ uv_blade_to_memory_nid(mmr_blade), &info);
}
EXPORT_SYMBOL_GPL(uv_setup_irq);
@@ -263,26 +207,6 @@ EXPORT_SYMBOL_GPL(uv_setup_irq);
*/
void uv_teardown_irq(unsigned int irq)
{
- struct uv_irq_2_mmr_pnode *e;
- struct rb_node *n;
- unsigned long irqflags;
-
- spin_lock_irqsave(&uv_irq_lock, irqflags);
- n = uv_irq_root.rb_node;
- while (n) {
- e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
- if (e->irq == irq) {
- arch_disable_uv_irq(e->pnode, e->offset);
- rb_erase(n, &uv_irq_root);
- kfree(e);
- break;
- }
- if (irq < e->irq)
- n = n->rb_left;
- else
- n = n->rb_right;
- }
- spin_unlock_irqrestore(&uv_irq_lock, irqflags);
- irq_free_hwirq(irq);
+ irq_domain_free_irqs(irq, 1);
}
EXPORT_SYMBOL_GPL(uv_teardown_irq);
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 757678fb26e1..0d7dd1f5ac36 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -18,10 +18,9 @@
#include <asm/mtrr.h>
#include <asm/page.h>
#include <asm/mce.h>
-#include <asm/xcr.h>
#include <asm/suspend.h>
+#include <asm/fpu/internal.h>
#include <asm/debugreg.h>
-#include <asm/fpu-internal.h> /* pcntxt_mask */
#include <asm/cpu.h>
#ifdef CONFIG_X86_32
@@ -155,6 +154,8 @@ static void fix_processor_context(void)
#endif
load_TR_desc(); /* This does ltr */
load_LDT(&current->active_mm->context); /* This does lldt */
+
+ fpu__resume_cpu();
}
/**
@@ -221,12 +222,6 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
#endif
- /*
- * restore XCR0 for xsave capable cpu's.
- */
- if (cpu_has_xsave)
- xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
-
fix_processor_context();
do_fpu_end();
diff --git a/arch/x86/power/hibernate_asm_64.S b/arch/x86/power/hibernate_asm_64.S
index 3c4469a7a929..e2386cb4e0c3 100644
--- a/arch/x86/power/hibernate_asm_64.S
+++ b/arch/x86/power/hibernate_asm_64.S
@@ -78,9 +78,9 @@ ENTRY(restore_image)
/* code below has been relocated to a safe page */
ENTRY(core_restore_code)
-loop:
+.Lloop:
testq %rdx, %rdx
- jz done
+ jz .Ldone
/* get addresses from the pbe and copy the page */
movq pbe_address(%rdx), %rsi
@@ -91,8 +91,8 @@ loop:
/* progress to the next pbe */
movq pbe_next(%rdx), %rdx
- jmp loop
-done:
+ jmp .Lloop
+.Ldone:
/* jump to the restore_registers address from the image header */
jmpq *%rax
/*
diff --git a/arch/x86/um/Makefile b/arch/x86/um/Makefile
index acb384d24669..a8fecc226946 100644
--- a/arch/x86/um/Makefile
+++ b/arch/x86/um/Makefile
@@ -26,7 +26,7 @@ else
obj-y += syscalls_64.o vdso/
-subarch-y = ../lib/csum-partial_64.o ../lib/memcpy_64.o ../lib/thunk_64.o \
+subarch-y = ../lib/csum-partial_64.o ../lib/memcpy_64.o ../entry/thunk_64.o \
../lib/rwsem.o
endif
diff --git a/arch/x86/um/asm/barrier.h b/arch/x86/um/asm/barrier.h
index 7e8a1a650435..b9531d343134 100644
--- a/arch/x86/um/asm/barrier.h
+++ b/arch/x86/um/asm/barrier.h
@@ -39,7 +39,8 @@
#define smp_mb() barrier()
#define smp_rmb() barrier()
#define smp_wmb() barrier()
-#define set_mb(var, value) do { var = value; barrier(); } while (0)
+
+#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)
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 46957ead3060..0b95c9b8283f 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1181,10 +1181,11 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
.read_tscp = native_read_tscp,
.iret = xen_iret,
- .irq_enable_sysexit = xen_sysexit,
#ifdef CONFIG_X86_64
.usergs_sysret32 = xen_sysret32,
.usergs_sysret64 = xen_sysret64,
+#else
+ .irq_enable_sysexit = xen_sysexit,
#endif
.load_tr_desc = paravirt_nop,
@@ -1423,7 +1424,7 @@ static void xen_pvh_set_cr_flags(int cpu)
return;
/*
* For BSP, PSE PGE are set in probe_page_size_mask(), for APs
- * set them here. For all, OSFXSR OSXMMEXCPT are set in fpu_init.
+ * set them here. For all, OSFXSR OSXMMEXCPT are set in fpu__init_cpu().
*/
if (cpu_has_pse)
cr4_set_bits_and_update_boot(X86_CR4_PSE);
@@ -1467,6 +1468,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
{
struct physdev_set_iopl set_iopl;
unsigned long initrd_start = 0;
+ u64 pat;
int rc;
if (!xen_start_info)
@@ -1574,8 +1576,8 @@ asmlinkage __visible void __init xen_start_kernel(void)
* Modify the cache mode translation tables to match Xen's PAT
* configuration.
*/
-
- pat_init_cache_modes();
+ rdmsrl(MSR_IA32_CR_PAT, pat);
+ pat_init_cache_modes(pat);
/* keep using Xen gdt for now; no urgent need to change it */
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index b47124d4cd67..8b7f18e200aa 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -67,6 +67,7 @@
#include <linux/seq_file.h>
#include <linux/bootmem.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <asm/cache.h>
#include <asm/setup.h>
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
index 956374c1edbc..9e2ba5c6e1dd 100644
--- a/arch/x86/xen/spinlock.c
+++ b/arch/x86/xen/spinlock.c
@@ -17,6 +17,56 @@
#include "xen-ops.h"
#include "debugfs.h"
+static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
+static DEFINE_PER_CPU(char *, irq_name);
+static bool xen_pvspin = true;
+
+#ifdef CONFIG_QUEUED_SPINLOCKS
+
+#include <asm/qspinlock.h>
+
+static void xen_qlock_kick(int cpu)
+{
+ xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
+}
+
+/*
+ * Halt the current CPU & release it back to the host
+ */
+static void xen_qlock_wait(u8 *byte, u8 val)
+{
+ int irq = __this_cpu_read(lock_kicker_irq);
+
+ /* If kicker interrupts not initialized yet, just spin */
+ if (irq == -1)
+ return;
+
+ /* clear pending */
+ xen_clear_irq_pending(irq);
+ barrier();
+
+ /*
+ * We check the byte value after clearing pending IRQ to make sure
+ * that we won't miss a wakeup event because of the clearing.
+ *
+ * The sync_clear_bit() call in xen_clear_irq_pending() is atomic.
+ * So it is effectively a memory barrier for x86.
+ */
+ if (READ_ONCE(*byte) != val)
+ return;
+
+ /*
+ * If an interrupt happens here, it will leave the wakeup irq
+ * pending, which will cause xen_poll_irq() to return
+ * immediately.
+ */
+
+ /* Block until irq becomes pending (or perhaps a spurious wakeup) */
+ xen_poll_irq(irq);
+}
+
+#else /* CONFIG_QUEUED_SPINLOCKS */
+
enum xen_contention_stat {
TAKEN_SLOW,
TAKEN_SLOW_PICKUP,
@@ -100,12 +150,9 @@ struct xen_lock_waiting {
__ticket_t want;
};
-static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
-static DEFINE_PER_CPU(char *, irq_name);
static DEFINE_PER_CPU(struct xen_lock_waiting, lock_waiting);
static cpumask_t waiting_cpus;
-static bool xen_pvspin = true;
__visible void xen_lock_spinning(struct arch_spinlock *lock, __ticket_t want)
{
int irq = __this_cpu_read(lock_kicker_irq);
@@ -217,6 +264,7 @@ static void xen_unlock_kick(struct arch_spinlock *lock, __ticket_t next)
}
}
}
+#endif /* CONFIG_QUEUED_SPINLOCKS */
static irqreturn_t dummy_handler(int irq, void *dev_id)
{
@@ -280,8 +328,16 @@ void __init xen_init_spinlocks(void)
return;
}
printk(KERN_DEBUG "xen: PV spinlocks enabled\n");
+#ifdef CONFIG_QUEUED_SPINLOCKS
+ __pv_init_lock_hash();
+ pv_lock_ops.queued_spin_lock_slowpath = __pv_queued_spin_lock_slowpath;
+ pv_lock_ops.queued_spin_unlock = PV_CALLEE_SAVE(__pv_queued_spin_unlock);
+ pv_lock_ops.wait = xen_qlock_wait;
+ pv_lock_ops.kick = xen_qlock_kick;
+#else
pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(xen_lock_spinning);
pv_lock_ops.unlock_kick = xen_unlock_kick;
+#endif
}
/*
@@ -310,7 +366,7 @@ static __init int xen_parse_nopvspin(char *arg)
}
early_param("xen_nopvspin", xen_parse_nopvspin);
-#ifdef CONFIG_XEN_DEBUG_FS
+#if defined(CONFIG_XEN_DEBUG_FS) && !defined(CONFIG_QUEUED_SPINLOCKS)
static struct dentry *d_spin_debug;
diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S
index 985fc3ee0973..f22667abf7b9 100644
--- a/arch/x86/xen/xen-asm_64.S
+++ b/arch/x86/xen/xen-asm_64.S
@@ -15,6 +15,8 @@
#include <asm/percpu.h>
#include <asm/processor-flags.h>
#include <asm/segment.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
#include <xen/interface/xen.h>
@@ -47,29 +49,13 @@ ENTRY(xen_iret)
ENDPATCH(xen_iret)
RELOC(xen_iret, 1b+1)
-/*
- * sysexit is not used for 64-bit processes, so it's only ever used to
- * return to 32-bit compat userspace.
- */
-ENTRY(xen_sysexit)
- pushq $__USER32_DS
- pushq %rcx
- pushq $X86_EFLAGS_IF
- pushq $__USER32_CS
- pushq %rdx
-
- pushq $0
-1: jmp hypercall_iret
-ENDPATCH(xen_sysexit)
-RELOC(xen_sysexit, 1b+1)
-
ENTRY(xen_sysret64)
/*
* We're already on the usermode stack at this point, but
* still with the kernel gs, so we can easily switch back
*/
movq %rsp, PER_CPU_VAR(rsp_scratch)
- movq PER_CPU_VAR(kernel_stack), %rsp
+ movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
pushq $__USER_DS
pushq PER_CPU_VAR(rsp_scratch)
@@ -88,7 +74,7 @@ ENTRY(xen_sysret32)
* still with the kernel gs, so we can easily switch back
*/
movq %rsp, PER_CPU_VAR(rsp_scratch)
- movq PER_CPU_VAR(kernel_stack), %rsp
+ movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
pushq $__USER32_DS
pushq PER_CPU_VAR(rsp_scratch)
@@ -128,7 +114,7 @@ RELOC(xen_sysret32, 1b+1)
/* Normal 64-bit system call target */
ENTRY(xen_syscall_target)
undo_xen_syscall
- jmp system_call_after_swapgs
+ jmp entry_SYSCALL_64_after_swapgs
ENDPROC(xen_syscall_target)
#ifdef CONFIG_IA32_EMULATION
@@ -136,13 +122,13 @@ ENDPROC(xen_syscall_target)
/* 32-bit compat syscall target */
ENTRY(xen_syscall32_target)
undo_xen_syscall
- jmp ia32_cstar_target
+ jmp entry_SYSCALL_compat
ENDPROC(xen_syscall32_target)
/* 32-bit compat sysenter target */
ENTRY(xen_sysenter_target)
undo_xen_syscall
- jmp ia32_sysenter_target
+ jmp entry_SYSENTER_compat
ENDPROC(xen_sysenter_target)
#else /* !CONFIG_IA32_EMULATION */
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index 9e195c683549..c20fe29e65f4 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -134,7 +134,9 @@ DECL_ASM(void, xen_restore_fl_direct, unsigned long);
/* These are not functions, and cannot be called normally */
__visible void xen_iret(void);
+#ifdef CONFIG_X86_32
__visible void xen_sysexit(void);
+#endif
__visible void xen_sysret32(void);
__visible void xen_sysret64(void);
__visible void xen_adjust_exception_frame(void);
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 87be10e8b57a..e5b872ba2484 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -151,7 +151,7 @@ config HAVE_SMP
the CPU core definition and currently needs to be selected manually.
Multiprocessor support in implemented with external cache and
- interrupt controlers.
+ interrupt controllers.
The MX interrupt distributer adds Interprocessor Interrupts
and causes the IRQ numbers to be increased by 4 for devices
diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild
index 86a9ab2e2ca9..14d15bf1a95b 100644
--- a/arch/xtensa/include/asm/Kbuild
+++ b/arch/xtensa/include/asm/Kbuild
@@ -22,7 +22,6 @@ generic-y += mcs_spinlock.h
generic-y += percpu.h
generic-y += preempt.h
generic-y += resource.h
-generic-y += scatterlist.h
generic-y += sections.h
generic-y += siginfo.h
generic-y += statfs.h
diff --git a/arch/xtensa/include/asm/dma-mapping.h b/arch/xtensa/include/asm/dma-mapping.h
index ba78ccf651e7..1f5f6dc09736 100644
--- a/arch/xtensa/include/asm/dma-mapping.h
+++ b/arch/xtensa/include/asm/dma-mapping.h
@@ -52,14 +52,15 @@ dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
}
static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
enum dma_data_direction direction)
{
int i;
+ struct scatterlist *sg;
BUG_ON(direction == DMA_NONE);
- for (i = 0; i < nents; i++, sg++ ) {
+ for_each_sg(sglist, sg, nents, i) {
BUG_ON(!sg_page(sg));
sg->dma_address = sg_phys(sg);
@@ -124,20 +125,24 @@ dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
consistent_sync((void *)bus_to_virt(dma_handle)+offset,size,direction);
}
static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nelems,
enum dma_data_direction dir)
{
int i;
- for (i = 0; i < nelems; i++, sg++)
+ struct scatterlist *sg;
+
+ for_each_sg(sglist, sg, nelems, i)
consistent_sync(sg_virt(sg), sg->length, dir);
}
static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
- enum dma_data_direction dir)
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction dir)
{
int i;
- for (i = 0; i < nelems; i++, sg++)
+ struct scatterlist *sg;
+
+ for_each_sg(sglist, sg, nelems, i)
consistent_sync(sg_virt(sg), sg->length, dir);
}
static inline int
diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h
index fe1600a09438..c39bb6e61911 100644
--- a/arch/xtensa/include/asm/io.h
+++ b/arch/xtensa/include/asm/io.h
@@ -59,6 +59,7 @@ static inline void __iomem *ioremap_cache(unsigned long offset,
}
#define ioremap_wc ioremap_nocache
+#define ioremap_wt ioremap_nocache
static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
{
diff --git a/arch/xtensa/include/asm/mm-arch-hooks.h b/arch/xtensa/include/asm/mm-arch-hooks.h
new file mode 100644
index 000000000000..d2e5cfd3dd02
--- /dev/null
+++ b/arch/xtensa/include/asm/mm-arch-hooks.h
@@ -0,0 +1,15 @@
+/*
+ * Architecture specific mm hooks
+ *
+ * Copyright (C) 2015, IBM Corporation
+ * Author: Laurent Dufour <ldufour@linux.vnet.ibm.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 _ASM_XTENSA_MM_ARCH_HOOKS_H
+#define _ASM_XTENSA_MM_ARCH_HOOKS_H
+
+#endif /* _ASM_XTENSA_MM_ARCH_HOOKS_H */
diff --git a/arch/xtensa/include/asm/pci.h b/arch/xtensa/include/asm/pci.h
index 5d52dc43dfe7..e438a00fbd63 100644
--- a/arch/xtensa/include/asm/pci.h
+++ b/arch/xtensa/include/asm/pci.h
@@ -33,7 +33,7 @@ extern struct pci_controller* pcibios_alloc_controller(void);
#include <linux/types.h>
#include <linux/slab.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <linux/string.h>
#include <asm/io.h>
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
index 9e3571a6535c..83a44a33cfa1 100644
--- a/arch/xtensa/mm/fault.c
+++ b/arch/xtensa/mm/fault.c
@@ -15,10 +15,10 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/hardirq.h>
+#include <linux/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
#include <asm/hardirq.h>
-#include <asm/uaccess.h>
#include <asm/pgalloc.h>
DEFINE_PER_CPU(unsigned long, asid_cache) = ASID_USER_FIRST;
@@ -57,7 +57,7 @@ void do_page_fault(struct pt_regs *regs)
/* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_atomic() || !mm) {
+ if (faulthandler_disabled() || !mm) {
bad_page_fault(regs, address, SIGSEGV);
return;
}
diff --git a/arch/xtensa/mm/highmem.c b/arch/xtensa/mm/highmem.c
index 8cfb71ec0937..184ceadccc1a 100644
--- a/arch/xtensa/mm/highmem.c
+++ b/arch/xtensa/mm/highmem.c
@@ -42,6 +42,7 @@ void *kmap_atomic(struct page *page)
enum fixed_addresses idx;
unsigned long vaddr;
+ preempt_disable();
pagefault_disable();
if (!PageHighMem(page))
return page_address(page);
@@ -79,6 +80,7 @@ void __kunmap_atomic(void *kvaddr)
}
pagefault_enable();
+ preempt_enable();
}
EXPORT_SYMBOL(__kunmap_atomic);
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index 5cbd5d9ea61d..0436c21db7f2 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -361,7 +361,7 @@ static void bio_integrity_verify_fn(struct work_struct *work)
/* Restore original bio completion handler */
bio->bi_end_io = bip->bip_end_io;
- bio_endio_nodec(bio, error);
+ bio_endio(bio, error);
}
/**
@@ -388,7 +388,7 @@ void bio_integrity_endio(struct bio *bio, int error)
*/
if (error) {
bio->bi_end_io = bip->bip_end_io;
- bio_endio_nodec(bio, error);
+ bio_endio(bio, error);
return;
}
diff --git a/block/bio.c b/block/bio.c
index f66a4eae16ee..2a00d349cd68 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -270,8 +270,8 @@ void bio_init(struct bio *bio)
{
memset(bio, 0, sizeof(*bio));
bio->bi_flags = 1 << BIO_UPTODATE;
- atomic_set(&bio->bi_remaining, 1);
- atomic_set(&bio->bi_cnt, 1);
+ atomic_set(&bio->__bi_remaining, 1);
+ atomic_set(&bio->__bi_cnt, 1);
}
EXPORT_SYMBOL(bio_init);
@@ -292,8 +292,8 @@ void bio_reset(struct bio *bio)
__bio_free(bio);
memset(bio, 0, BIO_RESET_BYTES);
- bio->bi_flags = flags|(1 << BIO_UPTODATE);
- atomic_set(&bio->bi_remaining, 1);
+ bio->bi_flags = flags | (1 << BIO_UPTODATE);
+ atomic_set(&bio->__bi_remaining, 1);
}
EXPORT_SYMBOL(bio_reset);
@@ -303,6 +303,17 @@ static void bio_chain_endio(struct bio *bio, int error)
bio_put(bio);
}
+/*
+ * Increment chain count for the bio. Make sure the CHAIN flag update
+ * is visible before the raised count.
+ */
+static inline void bio_inc_remaining(struct bio *bio)
+{
+ bio->bi_flags |= (1 << BIO_CHAIN);
+ smp_mb__before_atomic();
+ atomic_inc(&bio->__bi_remaining);
+}
+
/**
* bio_chain - chain bio completions
* @bio: the target bio
@@ -320,7 +331,7 @@ void bio_chain(struct bio *bio, struct bio *parent)
bio->bi_private = parent;
bio->bi_end_io = bio_chain_endio;
- atomic_inc(&parent->bi_remaining);
+ bio_inc_remaining(parent);
}
EXPORT_SYMBOL(bio_chain);
@@ -524,13 +535,17 @@ EXPORT_SYMBOL(zero_fill_bio);
**/
void bio_put(struct bio *bio)
{
- BIO_BUG_ON(!atomic_read(&bio->bi_cnt));
-
- /*
- * last put frees it
- */
- if (atomic_dec_and_test(&bio->bi_cnt))
+ if (!bio_flagged(bio, BIO_REFFED))
bio_free(bio);
+ else {
+ BIO_BUG_ON(!atomic_read(&bio->__bi_cnt));
+
+ /*
+ * last put frees it
+ */
+ if (atomic_dec_and_test(&bio->__bi_cnt))
+ bio_free(bio);
+ }
}
EXPORT_SYMBOL(bio_put);
@@ -1741,6 +1756,25 @@ void bio_flush_dcache_pages(struct bio *bi)
EXPORT_SYMBOL(bio_flush_dcache_pages);
#endif
+static inline bool bio_remaining_done(struct bio *bio)
+{
+ /*
+ * If we're not chaining, then ->__bi_remaining is always 1 and
+ * we always end io on the first invocation.
+ */
+ if (!bio_flagged(bio, BIO_CHAIN))
+ return true;
+
+ BUG_ON(atomic_read(&bio->__bi_remaining) <= 0);
+
+ if (atomic_dec_and_test(&bio->__bi_remaining)) {
+ clear_bit(BIO_CHAIN, &bio->bi_flags);
+ return true;
+ }
+
+ return false;
+}
+
/**
* bio_endio - end I/O on a bio
* @bio: bio
@@ -1758,15 +1792,13 @@ EXPORT_SYMBOL(bio_flush_dcache_pages);
void bio_endio(struct bio *bio, int error)
{
while (bio) {
- BUG_ON(atomic_read(&bio->bi_remaining) <= 0);
-
if (error)
clear_bit(BIO_UPTODATE, &bio->bi_flags);
else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
error = -EIO;
- if (!atomic_dec_and_test(&bio->bi_remaining))
- return;
+ if (unlikely(!bio_remaining_done(bio)))
+ break;
/*
* Need to have a real endio function for chained bios,
@@ -1790,21 +1822,6 @@ void bio_endio(struct bio *bio, int error)
EXPORT_SYMBOL(bio_endio);
/**
- * bio_endio_nodec - end I/O on a bio, without decrementing bi_remaining
- * @bio: bio
- * @error: error, if any
- *
- * For code that has saved and restored bi_end_io; thing hard before using this
- * function, probably you should've cloned the entire bio.
- **/
-void bio_endio_nodec(struct bio *bio, int error)
-{
- atomic_inc(&bio->bi_remaining);
- bio_endio(bio, error);
-}
-EXPORT_SYMBOL(bio_endio_nodec);
-
-/**
* bio_split - split a bio
* @bio: bio to split
* @sectors: number of sectors to split from the front of @bio
@@ -1971,6 +1988,28 @@ struct bio_set *bioset_create_nobvec(unsigned int pool_size, unsigned int front_
EXPORT_SYMBOL(bioset_create_nobvec);
#ifdef CONFIG_BLK_CGROUP
+
+/**
+ * bio_associate_blkcg - associate a bio with the specified blkcg
+ * @bio: target bio
+ * @blkcg_css: css of the blkcg to associate
+ *
+ * Associate @bio with the blkcg specified by @blkcg_css. Block layer will
+ * treat @bio as if it were issued by a task which belongs to the blkcg.
+ *
+ * This function takes an extra reference of @blkcg_css which will be put
+ * when @bio is released. The caller must own @bio and is responsible for
+ * synchronizing calls to this function.
+ */
+int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css)
+{
+ if (unlikely(bio->bi_css))
+ return -EBUSY;
+ css_get(blkcg_css);
+ bio->bi_css = blkcg_css;
+ return 0;
+}
+
/**
* bio_associate_current - associate a bio with %current
* @bio: target bio
@@ -1987,26 +2026,17 @@ EXPORT_SYMBOL(bioset_create_nobvec);
int bio_associate_current(struct bio *bio)
{
struct io_context *ioc;
- struct cgroup_subsys_state *css;
- if (bio->bi_ioc)
+ if (bio->bi_css)
return -EBUSY;
ioc = current->io_context;
if (!ioc)
return -ENOENT;
- /* acquire active ref on @ioc and associate */
get_io_context_active(ioc);
bio->bi_ioc = ioc;
-
- /* associate blkcg if exists */
- rcu_read_lock();
- css = task_css(current, blkio_cgrp_id);
- if (css && css_tryget_online(css))
- bio->bi_css = css;
- rcu_read_unlock();
-
+ bio->bi_css = task_get_css(current, blkio_cgrp_id);
return 0;
}
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 0ac817b750db..9f97da52d006 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -9,27 +9,33 @@
*
* Copyright (C) 2009 Vivek Goyal <vgoyal@redhat.com>
* Nauman Rafique <nauman@google.com>
+ *
+ * For policy-specific per-blkcg data:
+ * Copyright (C) 2015 Paolo Valente <paolo.valente@unimore.it>
+ * Arianna Avanzini <avanzini.arianna@gmail.com>
*/
#include <linux/ioprio.h>
#include <linux/kdev_t.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/blkdev.h>
+#include <linux/backing-dev.h>
#include <linux/slab.h>
#include <linux/genhd.h>
#include <linux/delay.h>
#include <linux/atomic.h>
-#include "blk-cgroup.h"
+#include <linux/blk-cgroup.h>
#include "blk.h"
#define MAX_KEY_LEN 100
static DEFINE_MUTEX(blkcg_pol_mutex);
-struct blkcg blkcg_root = { .cfq_weight = 2 * CFQ_WEIGHT_DEFAULT,
- .cfq_leaf_weight = 2 * CFQ_WEIGHT_DEFAULT, };
+struct blkcg blkcg_root;
EXPORT_SYMBOL_GPL(blkcg_root);
+struct cgroup_subsys_state * const blkcg_root_css = &blkcg_root.css;
+
static struct blkcg_policy *blkcg_policy[BLKCG_MAX_POLS];
static bool blkcg_policy_enabled(struct request_queue *q,
@@ -179,6 +185,7 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
struct blkcg_gq *new_blkg)
{
struct blkcg_gq *blkg;
+ struct bdi_writeback_congested *wb_congested;
int i, ret;
WARN_ON_ONCE(!rcu_read_lock_held());
@@ -190,22 +197,30 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
goto err_free_blkg;
}
+ wb_congested = wb_congested_get_create(&q->backing_dev_info,
+ blkcg->css.id, GFP_ATOMIC);
+ if (!wb_congested) {
+ ret = -ENOMEM;
+ goto err_put_css;
+ }
+
/* allocate */
if (!new_blkg) {
new_blkg = blkg_alloc(blkcg, q, GFP_ATOMIC);
if (unlikely(!new_blkg)) {
ret = -ENOMEM;
- goto err_put_css;
+ goto err_put_congested;
}
}
blkg = new_blkg;
+ blkg->wb_congested = wb_congested;
/* link parent */
if (blkcg_parent(blkcg)) {
blkg->parent = __blkg_lookup(blkcg_parent(blkcg), q, false);
if (WARN_ON_ONCE(!blkg->parent)) {
ret = -EINVAL;
- goto err_put_css;
+ goto err_put_congested;
}
blkg_get(blkg->parent);
}
@@ -235,18 +250,15 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
blkg->online = true;
spin_unlock(&blkcg->lock);
- if (!ret) {
- if (blkcg == &blkcg_root) {
- q->root_blkg = blkg;
- q->root_rl.blkg = blkg;
- }
+ if (!ret)
return blkg;
- }
/* @blkg failed fully initialized, use the usual release path */
blkg_put(blkg);
return ERR_PTR(ret);
+err_put_congested:
+ wb_congested_put(wb_congested);
err_put_css:
css_put(&blkcg->css);
err_free_blkg:
@@ -340,15 +352,6 @@ static void blkg_destroy(struct blkcg_gq *blkg)
rcu_assign_pointer(blkcg->blkg_hint, NULL);
/*
- * If root blkg is destroyed. Just clear the pointer since root_rl
- * does not take reference on root blkg.
- */
- if (blkcg == &blkcg_root) {
- blkg->q->root_blkg = NULL;
- blkg->q->root_rl.blkg = NULL;
- }
-
- /*
* Put the reference taken at the time of creation so that when all
* queues are gone, group can be destroyed.
*/
@@ -402,6 +405,8 @@ void __blkg_release_rcu(struct rcu_head *rcu_head)
if (blkg->parent)
blkg_put(blkg->parent);
+ wb_congested_put(blkg->wb_congested);
+
blkg_free(blkg);
}
EXPORT_SYMBOL_GPL(__blkg_release_rcu);
@@ -809,6 +814,8 @@ static void blkcg_css_offline(struct cgroup_subsys_state *css)
}
spin_unlock_irq(&blkcg->lock);
+
+ wb_blkcg_offline(blkcg);
}
static void blkcg_css_free(struct cgroup_subsys_state *css)
@@ -823,6 +830,8 @@ static struct cgroup_subsys_state *
blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
{
struct blkcg *blkcg;
+ struct cgroup_subsys_state *ret;
+ int i;
if (!parent_css) {
blkcg = &blkcg_root;
@@ -830,17 +839,51 @@ blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
}
blkcg = kzalloc(sizeof(*blkcg), GFP_KERNEL);
- if (!blkcg)
- return ERR_PTR(-ENOMEM);
+ if (!blkcg) {
+ ret = ERR_PTR(-ENOMEM);
+ goto free_blkcg;
+ }
+
+ for (i = 0; i < BLKCG_MAX_POLS ; i++) {
+ struct blkcg_policy *pol = blkcg_policy[i];
+ struct blkcg_policy_data *cpd;
+
+ /*
+ * If the policy hasn't been attached yet, wait for it
+ * to be attached before doing anything else. Otherwise,
+ * check if the policy requires any specific per-cgroup
+ * data: if it does, allocate and initialize it.
+ */
+ if (!pol || !pol->cpd_size)
+ continue;
+
+ BUG_ON(blkcg->pd[i]);
+ cpd = kzalloc(pol->cpd_size, GFP_KERNEL);
+ if (!cpd) {
+ ret = ERR_PTR(-ENOMEM);
+ goto free_pd_blkcg;
+ }
+ blkcg->pd[i] = cpd;
+ cpd->plid = i;
+ pol->cpd_init_fn(blkcg);
+ }
- blkcg->cfq_weight = CFQ_WEIGHT_DEFAULT;
- blkcg->cfq_leaf_weight = CFQ_WEIGHT_DEFAULT;
done:
spin_lock_init(&blkcg->lock);
INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_ATOMIC);
INIT_HLIST_HEAD(&blkcg->blkg_list);
-
+#ifdef CONFIG_CGROUP_WRITEBACK
+ INIT_LIST_HEAD(&blkcg->cgwb_list);
+#endif
return &blkcg->css;
+
+free_pd_blkcg:
+ for (i--; i >= 0; i--)
+ kfree(blkcg->pd[i]);
+
+free_blkcg:
+ kfree(blkcg);
+ return ret;
}
/**
@@ -855,9 +898,45 @@ done:
*/
int blkcg_init_queue(struct request_queue *q)
{
- might_sleep();
+ struct blkcg_gq *new_blkg, *blkg;
+ bool preloaded;
+ int ret;
+
+ new_blkg = blkg_alloc(&blkcg_root, q, GFP_KERNEL);
+ if (!new_blkg)
+ return -ENOMEM;
+
+ preloaded = !radix_tree_preload(GFP_KERNEL);
+
+ /*
+ * Make sure the root blkg exists and count the existing blkgs. As
+ * @q is bypassing at this point, blkg_lookup_create() can't be
+ * used. Open code insertion.
+ */
+ rcu_read_lock();
+ spin_lock_irq(q->queue_lock);
+ blkg = blkg_create(&blkcg_root, q, new_blkg);
+ spin_unlock_irq(q->queue_lock);
+ rcu_read_unlock();
+
+ if (preloaded)
+ radix_tree_preload_end();
+
+ if (IS_ERR(blkg)) {
+ kfree(new_blkg);
+ return PTR_ERR(blkg);
+ }
+
+ q->root_blkg = blkg;
+ q->root_rl.blkg = blkg;
- return blk_throtl_init(q);
+ ret = blk_throtl_init(q);
+ if (ret) {
+ spin_lock_irq(q->queue_lock);
+ blkg_destroy_all(q);
+ spin_unlock_irq(q->queue_lock);
+ }
+ return ret;
}
/**
@@ -958,52 +1037,26 @@ int blkcg_activate_policy(struct request_queue *q,
const struct blkcg_policy *pol)
{
LIST_HEAD(pds);
- struct blkcg_gq *blkg, *new_blkg;
- struct blkg_policy_data *pd, *n;
+ LIST_HEAD(cpds);
+ struct blkcg_gq *blkg;
+ struct blkg_policy_data *pd, *nd;
+ struct blkcg_policy_data *cpd, *cnd;
int cnt = 0, ret;
- bool preloaded;
if (blkcg_policy_enabled(q, pol))
return 0;
- /* preallocations for root blkg */
- new_blkg = blkg_alloc(&blkcg_root, q, GFP_KERNEL);
- if (!new_blkg)
- return -ENOMEM;
-
+ /* count and allocate policy_data for all existing blkgs */
blk_queue_bypass_start(q);
-
- preloaded = !radix_tree_preload(GFP_KERNEL);
-
- /*
- * Make sure the root blkg exists and count the existing blkgs. As
- * @q is bypassing at this point, blkg_lookup_create() can't be
- * used. Open code it.
- */
spin_lock_irq(q->queue_lock);
-
- rcu_read_lock();
- blkg = __blkg_lookup(&blkcg_root, q, false);
- if (blkg)
- blkg_free(new_blkg);
- else
- blkg = blkg_create(&blkcg_root, q, new_blkg);
- rcu_read_unlock();
-
- if (preloaded)
- radix_tree_preload_end();
-
- if (IS_ERR(blkg)) {
- ret = PTR_ERR(blkg);
- goto out_unlock;
- }
-
list_for_each_entry(blkg, &q->blkg_list, q_node)
cnt++;
-
spin_unlock_irq(q->queue_lock);
- /* allocate policy_data for all existing blkgs */
+ /*
+ * Allocate per-blkg and per-blkcg policy data
+ * for all existing blkgs.
+ */
while (cnt--) {
pd = kzalloc_node(pol->pd_size, GFP_KERNEL, q->node);
if (!pd) {
@@ -1011,26 +1064,50 @@ int blkcg_activate_policy(struct request_queue *q,
goto out_free;
}
list_add_tail(&pd->alloc_node, &pds);
+
+ if (!pol->cpd_size)
+ continue;
+ cpd = kzalloc_node(pol->cpd_size, GFP_KERNEL, q->node);
+ if (!cpd) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+ list_add_tail(&cpd->alloc_node, &cpds);
}
/*
- * Install the allocated pds. With @q bypassing, no new blkg
+ * Install the allocated pds and cpds. With @q bypassing, no new blkg
* should have been created while the queue lock was dropped.
*/
spin_lock_irq(q->queue_lock);
list_for_each_entry(blkg, &q->blkg_list, q_node) {
- if (WARN_ON(list_empty(&pds))) {
+ if (WARN_ON(list_empty(&pds)) ||
+ WARN_ON(pol->cpd_size && list_empty(&cpds))) {
/* umm... this shouldn't happen, just abort */
ret = -ENOMEM;
goto out_unlock;
}
+ cpd = list_first_entry(&cpds, struct blkcg_policy_data,
+ alloc_node);
+ list_del_init(&cpd->alloc_node);
pd = list_first_entry(&pds, struct blkg_policy_data, alloc_node);
list_del_init(&pd->alloc_node);
/* grab blkcg lock too while installing @pd on @blkg */
spin_lock(&blkg->blkcg->lock);
+ if (!pol->cpd_size)
+ goto no_cpd;
+ if (!blkg->blkcg->pd[pol->plid]) {
+ /* Per-policy per-blkcg data */
+ blkg->blkcg->pd[pol->plid] = cpd;
+ cpd->plid = pol->plid;
+ pol->cpd_init_fn(blkg->blkcg);
+ } else { /* must free it as it has already been extracted */
+ kfree(cpd);
+ }
+no_cpd:
blkg->pd[pol->plid] = pd;
pd->blkg = blkg;
pd->plid = pol->plid;
@@ -1045,8 +1122,10 @@ out_unlock:
spin_unlock_irq(q->queue_lock);
out_free:
blk_queue_bypass_end(q);
- list_for_each_entry_safe(pd, n, &pds, alloc_node)
+ list_for_each_entry_safe(pd, nd, &pds, alloc_node)
kfree(pd);
+ list_for_each_entry_safe(cpd, cnd, &cpds, alloc_node)
+ kfree(cpd);
return ret;
}
EXPORT_SYMBOL_GPL(blkcg_activate_policy);
@@ -1072,10 +1151,6 @@ void blkcg_deactivate_policy(struct request_queue *q,
__clear_bit(pol->plid, q->blkcg_pols);
- /* if no policy is left, no need for blkgs - shoot them down */
- if (bitmap_empty(q->blkcg_pols, BLKCG_MAX_POLS))
- blkg_destroy_all(q);
-
list_for_each_entry(blkg, &q->blkg_list, q_node) {
/* grab blkcg lock too while removing @pd from @blkg */
spin_lock(&blkg->blkcg->lock);
@@ -1087,6 +1162,8 @@ void blkcg_deactivate_policy(struct request_queue *q,
kfree(blkg->pd[pol->plid]);
blkg->pd[pol->plid] = NULL;
+ kfree(blkg->blkcg->pd[pol->plid]);
+ blkg->blkcg->pd[pol->plid] = NULL;
spin_unlock(&blkg->blkcg->lock);
}
diff --git a/block/blk-core.c b/block/blk-core.c
index 03b5f8d77f37..82819e68f58b 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -32,12 +32,12 @@
#include <linux/delay.h>
#include <linux/ratelimit.h>
#include <linux/pm_runtime.h>
+#include <linux/blk-cgroup.h>
#define CREATE_TRACE_POINTS
#include <trace/events/block.h>
#include "blk.h"
-#include "blk-cgroup.h"
#include "blk-mq.h"
EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap);
@@ -63,6 +63,31 @@ struct kmem_cache *blk_requestq_cachep;
*/
static struct workqueue_struct *kblockd_workqueue;
+static void blk_clear_congested(struct request_list *rl, int sync)
+{
+#ifdef CONFIG_CGROUP_WRITEBACK
+ clear_wb_congested(rl->blkg->wb_congested, sync);
+#else
+ /*
+ * If !CGROUP_WRITEBACK, all blkg's map to bdi->wb and we shouldn't
+ * flip its congestion state for events on other blkcgs.
+ */
+ if (rl == &rl->q->root_rl)
+ clear_wb_congested(rl->q->backing_dev_info.wb.congested, sync);
+#endif
+}
+
+static void blk_set_congested(struct request_list *rl, int sync)
+{
+#ifdef CONFIG_CGROUP_WRITEBACK
+ set_wb_congested(rl->blkg->wb_congested, sync);
+#else
+ /* see blk_clear_congested() */
+ if (rl == &rl->q->root_rl)
+ set_wb_congested(rl->q->backing_dev_info.wb.congested, sync);
+#endif
+}
+
void blk_queue_congestion_threshold(struct request_queue *q)
{
int nr;
@@ -285,6 +310,7 @@ inline void __blk_run_queue_uncond(struct request_queue *q)
q->request_fn(q);
q->request_fn_active--;
}
+EXPORT_SYMBOL_GPL(__blk_run_queue_uncond);
/**
* __blk_run_queue - run a single device queue
@@ -621,8 +647,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
q->backing_dev_info.ra_pages =
(VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
- q->backing_dev_info.state = 0;
- q->backing_dev_info.capabilities = 0;
+ q->backing_dev_info.capabilities = BDI_CAP_CGROUP_WRITEBACK;
q->backing_dev_info.name = "block";
q->node = node_id;
@@ -845,13 +870,8 @@ static void __freed_request(struct request_list *rl, int sync)
{
struct request_queue *q = rl->q;
- /*
- * bdi isn't aware of blkcg yet. As all async IOs end up root
- * blkcg anyway, just use root blkcg state.
- */
- if (rl == &q->root_rl &&
- rl->count[sync] < queue_congestion_off_threshold(q))
- blk_clear_queue_congested(q, sync);
+ if (rl->count[sync] < queue_congestion_off_threshold(q))
+ blk_clear_congested(rl, sync);
if (rl->count[sync] + 1 <= q->nr_requests) {
if (waitqueue_active(&rl->wait[sync]))
@@ -884,25 +904,25 @@ static void freed_request(struct request_list *rl, unsigned int flags)
int blk_update_nr_requests(struct request_queue *q, unsigned int nr)
{
struct request_list *rl;
+ int on_thresh, off_thresh;
spin_lock_irq(q->queue_lock);
q->nr_requests = nr;
blk_queue_congestion_threshold(q);
+ on_thresh = queue_congestion_on_threshold(q);
+ off_thresh = queue_congestion_off_threshold(q);
- /* congestion isn't cgroup aware and follows root blkcg for now */
- rl = &q->root_rl;
-
- if (rl->count[BLK_RW_SYNC] >= queue_congestion_on_threshold(q))
- blk_set_queue_congested(q, BLK_RW_SYNC);
- else if (rl->count[BLK_RW_SYNC] < queue_congestion_off_threshold(q))
- blk_clear_queue_congested(q, BLK_RW_SYNC);
+ blk_queue_for_each_rl(rl, q) {
+ if (rl->count[BLK_RW_SYNC] >= on_thresh)
+ blk_set_congested(rl, BLK_RW_SYNC);
+ else if (rl->count[BLK_RW_SYNC] < off_thresh)
+ blk_clear_congested(rl, BLK_RW_SYNC);
- if (rl->count[BLK_RW_ASYNC] >= queue_congestion_on_threshold(q))
- blk_set_queue_congested(q, BLK_RW_ASYNC);
- else if (rl->count[BLK_RW_ASYNC] < queue_congestion_off_threshold(q))
- blk_clear_queue_congested(q, BLK_RW_ASYNC);
+ if (rl->count[BLK_RW_ASYNC] >= on_thresh)
+ blk_set_congested(rl, BLK_RW_ASYNC);
+ else if (rl->count[BLK_RW_ASYNC] < off_thresh)
+ blk_clear_congested(rl, BLK_RW_ASYNC);
- blk_queue_for_each_rl(rl, q) {
if (rl->count[BLK_RW_SYNC] >= q->nr_requests) {
blk_set_rl_full(rl, BLK_RW_SYNC);
} else {
@@ -1012,12 +1032,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
}
}
}
- /*
- * bdi isn't aware of blkcg yet. As all async IOs end up
- * root blkcg anyway, just use root blkcg state.
- */
- if (rl == &q->root_rl)
- blk_set_queue_congested(q, is_sync);
+ blk_set_congested(rl, is_sync);
}
/*
@@ -1525,7 +1540,8 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req,
* Caller must ensure !blk_queue_nomerges(q) beforehand.
*/
bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio,
- unsigned int *request_count)
+ unsigned int *request_count,
+ struct request **same_queue_rq)
{
struct blk_plug *plug;
struct request *rq;
@@ -1545,8 +1561,16 @@ bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio,
list_for_each_entry_reverse(rq, plug_list, queuelist) {
int el_ret;
- if (rq->q == q)
+ if (rq->q == q) {
(*request_count)++;
+ /*
+ * Only blk-mq multiple hardware queues case checks the
+ * rq in the same queue, there should be only one such
+ * rq in a queue
+ **/
+ if (same_queue_rq)
+ *same_queue_rq = rq;
+ }
if (rq->q != q || !blk_rq_merge_ok(rq, bio))
continue;
@@ -1611,7 +1635,7 @@ static void blk_queue_bio(struct request_queue *q, struct bio *bio)
* any locks.
*/
if (!blk_queue_nomerges(q) &&
- blk_attempt_plug_merge(q, bio, &request_count))
+ blk_attempt_plug_merge(q, bio, &request_count, NULL))
return;
spin_lock_irq(q->queue_lock);
@@ -1718,8 +1742,6 @@ static void handle_bad_sector(struct bio *bio)
bio->bi_rw,
(unsigned long long)bio_end_sector(bio),
(long long)(i_size_read(bio->bi_bdev->bd_inode) >> 9));
-
- set_bit(BIO_EOF, &bio->bi_flags);
}
#ifdef CONFIG_FAIL_MAKE_REQUEST
@@ -3034,21 +3056,20 @@ void blk_start_plug(struct blk_plug *plug)
{
struct task_struct *tsk = current;
+ /*
+ * If this is a nested plug, don't actually assign it.
+ */
+ if (tsk->plug)
+ return;
+
INIT_LIST_HEAD(&plug->list);
INIT_LIST_HEAD(&plug->mq_list);
INIT_LIST_HEAD(&plug->cb_list);
-
/*
- * If this is a nested plug, don't actually assign it. It will be
- * flushed on its own.
+ * Store ordering should not be needed here, since a potential
+ * preempt will imply a full memory barrier
*/
- if (!tsk->plug) {
- /*
- * Store ordering should not be needed here, since a potential
- * preempt will imply a full memory barrier
- */
- tsk->plug = plug;
- }
+ tsk->plug = plug;
}
EXPORT_SYMBOL(blk_start_plug);
@@ -3195,10 +3216,11 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
void blk_finish_plug(struct blk_plug *plug)
{
+ if (plug != current->plug)
+ return;
blk_flush_plug_list(plug, false);
- if (plug == current->plug)
- current->plug = NULL;
+ current->plug = NULL;
}
EXPORT_SYMBOL(blk_finish_plug);
diff --git a/block/blk-exec.c b/block/blk-exec.c
index 9924725fa50d..3fec8a29d0fa 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -53,7 +53,6 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
rq_end_io_fn *done)
{
int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
- bool is_pm_resume;
WARN_ON(irqs_disabled());
WARN_ON(rq->cmd_type == REQ_TYPE_FS);
@@ -70,12 +69,6 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
return;
}
- /*
- * need to check this before __blk_run_queue(), because rq can
- * be freed before that returns.
- */
- is_pm_resume = rq->cmd_type == REQ_TYPE_PM_RESUME;
-
spin_lock_irq(q->queue_lock);
if (unlikely(blk_queue_dying(q))) {
@@ -88,9 +81,6 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
__elv_add_request(q, rq, where);
__blk_run_queue(q);
- /* the queue is stopped so it won't be run */
- if (is_pm_resume)
- __blk_run_queue_uncond(q);
spin_unlock_irq(q->queue_lock);
}
EXPORT_SYMBOL_GPL(blk_execute_rq_nowait);
diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index 79ffb4855af0..f548b64be092 100644
--- a/block/blk-integrity.c
+++ b/block/blk-integrity.c
@@ -21,6 +21,7 @@
*/
#include <linux/blkdev.h>
+#include <linux/backing-dev.h>
#include <linux/mempool.h>
#include <linux/bio.h>
#include <linux/scatterlist.h>
diff --git a/block/blk-merge.c b/block/blk-merge.c
index fd3fee81c23c..30a0d9f89017 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -589,7 +589,8 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
!blk_write_same_mergeable(rq->bio, bio))
return false;
- if (q->queue_flags & (1 << QUEUE_FLAG_SG_GAPS)) {
+ /* Only check gaps if the bio carries data */
+ if (q->queue_flags & (1 << QUEUE_FLAG_SG_GAPS) && bio_has_data(bio)) {
struct bio_vec *bprev;
bprev = &rq->biotail->bi_io_vec[rq->biotail->bi_vcnt - 1];
diff --git a/block/blk-mq-cpumap.c b/block/blk-mq-cpumap.c
index 5f13f4d0bcce..1e28ddb656b8 100644
--- a/block/blk-mq-cpumap.c
+++ b/block/blk-mq-cpumap.c
@@ -24,7 +24,7 @@ static int get_first_sibling(unsigned int cpu)
{
unsigned int ret;
- ret = cpumask_first(topology_thread_cpumask(cpu));
+ ret = cpumask_first(topology_sibling_cpumask(cpu));
if (ret < nr_cpu_ids)
return ret;
diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c
index be3290cc0644..9b6e28830b82 100644
--- a/block/blk-mq-tag.c
+++ b/block/blk-mq-tag.c
@@ -438,6 +438,39 @@ static void bt_for_each(struct blk_mq_hw_ctx *hctx,
}
}
+static void bt_tags_for_each(struct blk_mq_tags *tags,
+ struct blk_mq_bitmap_tags *bt, unsigned int off,
+ busy_tag_iter_fn *fn, void *data, bool reserved)
+{
+ struct request *rq;
+ int bit, i;
+
+ if (!tags->rqs)
+ return;
+ for (i = 0; i < bt->map_nr; i++) {
+ struct blk_align_bitmap *bm = &bt->map[i];
+
+ for (bit = find_first_bit(&bm->word, bm->depth);
+ bit < bm->depth;
+ bit = find_next_bit(&bm->word, bm->depth, bit + 1)) {
+ rq = blk_mq_tag_to_rq(tags, off + bit);
+ fn(rq, data, reserved);
+ }
+
+ off += (1 << bt->bits_per_word);
+ }
+}
+
+void blk_mq_all_tag_busy_iter(struct blk_mq_tags *tags, busy_tag_iter_fn *fn,
+ void *priv)
+{
+ if (tags->nr_reserved_tags)
+ bt_tags_for_each(tags, &tags->breserved_tags, 0, fn, priv, true);
+ bt_tags_for_each(tags, &tags->bitmap_tags, tags->nr_reserved_tags, fn, priv,
+ false);
+}
+EXPORT_SYMBOL(blk_mq_all_tag_busy_iter);
+
void blk_mq_tag_busy_iter(struct blk_mq_hw_ctx *hctx, busy_iter_fn *fn,
void *priv)
{
@@ -580,6 +613,11 @@ struct blk_mq_tags *blk_mq_init_tags(unsigned int total_tags,
if (!tags)
return NULL;
+ if (!zalloc_cpumask_var(&tags->cpumask, GFP_KERNEL)) {
+ kfree(tags);
+ return NULL;
+ }
+
tags->nr_tags = total_tags;
tags->nr_reserved_tags = reserved_tags;
diff --git a/block/blk-mq-tag.h b/block/blk-mq-tag.h
index 90767b370308..75893a34237d 100644
--- a/block/blk-mq-tag.h
+++ b/block/blk-mq-tag.h
@@ -44,6 +44,7 @@ struct blk_mq_tags {
struct list_head page_list;
int alloc_policy;
+ cpumask_var_t cpumask;
};
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 594eea04266e..f53779692c77 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -89,7 +89,8 @@ static int blk_mq_queue_enter(struct request_queue *q, gfp_t gfp)
return -EBUSY;
ret = wait_event_interruptible(q->mq_freeze_wq,
- !q->mq_freeze_depth || blk_queue_dying(q));
+ !atomic_read(&q->mq_freeze_depth) ||
+ blk_queue_dying(q));
if (blk_queue_dying(q))
return -ENODEV;
if (ret)
@@ -112,13 +113,10 @@ static void blk_mq_usage_counter_release(struct percpu_ref *ref)
void blk_mq_freeze_queue_start(struct request_queue *q)
{
- bool freeze;
+ int freeze_depth;
- spin_lock_irq(q->queue_lock);
- freeze = !q->mq_freeze_depth++;
- spin_unlock_irq(q->queue_lock);
-
- if (freeze) {
+ freeze_depth = atomic_inc_return(&q->mq_freeze_depth);
+ if (freeze_depth == 1) {
percpu_ref_kill(&q->mq_usage_counter);
blk_mq_run_hw_queues(q, false);
}
@@ -143,13 +141,11 @@ EXPORT_SYMBOL_GPL(blk_mq_freeze_queue);
void blk_mq_unfreeze_queue(struct request_queue *q)
{
- bool wake;
+ int freeze_depth;
- spin_lock_irq(q->queue_lock);
- wake = !--q->mq_freeze_depth;
- WARN_ON_ONCE(q->mq_freeze_depth < 0);
- spin_unlock_irq(q->queue_lock);
- if (wake) {
+ freeze_depth = atomic_dec_return(&q->mq_freeze_depth);
+ WARN_ON_ONCE(freeze_depth < 0);
+ if (!freeze_depth) {
percpu_ref_reinit(&q->mq_usage_counter);
wake_up_all(&q->mq_freeze_wq);
}
@@ -1237,6 +1233,38 @@ static struct request *blk_mq_map_request(struct request_queue *q,
return rq;
}
+static int blk_mq_direct_issue_request(struct request *rq)
+{
+ int ret;
+ struct request_queue *q = rq->q;
+ struct blk_mq_hw_ctx *hctx = q->mq_ops->map_queue(q,
+ rq->mq_ctx->cpu);
+ struct blk_mq_queue_data bd = {
+ .rq = rq,
+ .list = NULL,
+ .last = 1
+ };
+
+ /*
+ * For OK queue, we are done. For error, kill it. Any other
+ * error (busy), just add it to our list as we previously
+ * would have done
+ */
+ ret = q->mq_ops->queue_rq(hctx, &bd);
+ if (ret == BLK_MQ_RQ_QUEUE_OK)
+ return 0;
+ else {
+ __blk_mq_requeue_request(rq);
+
+ if (ret == BLK_MQ_RQ_QUEUE_ERROR) {
+ rq->errors = -EIO;
+ blk_mq_end_request(rq, rq->errors);
+ return 0;
+ }
+ return -1;
+ }
+}
+
/*
* Multiple hardware queue variant. This will not use per-process plugs,
* but will attempt to bypass the hctx queueing if we can go straight to
@@ -1248,6 +1276,9 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
const int is_flush_fua = bio->bi_rw & (REQ_FLUSH | REQ_FUA);
struct blk_map_ctx data;
struct request *rq;
+ unsigned int request_count = 0;
+ struct blk_plug *plug;
+ struct request *same_queue_rq = NULL;
blk_queue_bounce(q, &bio);
@@ -1256,6 +1287,10 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
return;
}
+ if (!is_flush_fua && !blk_queue_nomerges(q) &&
+ blk_attempt_plug_merge(q, bio, &request_count, &same_queue_rq))
+ return;
+
rq = blk_mq_map_request(q, bio, &data);
if (unlikely(!rq))
return;
@@ -1266,38 +1301,42 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
goto run_queue;
}
+ plug = current->plug;
/*
* If the driver supports defer issued based on 'last', then
* queue it up like normal since we can potentially save some
* CPU this way.
*/
- if (is_sync && !(data.hctx->flags & BLK_MQ_F_DEFER_ISSUE)) {
- struct blk_mq_queue_data bd = {
- .rq = rq,
- .list = NULL,
- .last = 1
- };
- int ret;
+ if (((plug && !blk_queue_nomerges(q)) || is_sync) &&
+ !(data.hctx->flags & BLK_MQ_F_DEFER_ISSUE)) {
+ struct request *old_rq = NULL;
blk_mq_bio_to_request(rq, bio);
/*
- * For OK queue, we are done. For error, kill it. Any other
- * error (busy), just add it to our list as we previously
- * would have done
+ * we do limited pluging. If bio can be merged, do merge.
+ * Otherwise the existing request in the plug list will be
+ * issued. So the plug list will have one request at most
*/
- ret = q->mq_ops->queue_rq(data.hctx, &bd);
- if (ret == BLK_MQ_RQ_QUEUE_OK)
- goto done;
- else {
- __blk_mq_requeue_request(rq);
-
- if (ret == BLK_MQ_RQ_QUEUE_ERROR) {
- rq->errors = -EIO;
- blk_mq_end_request(rq, rq->errors);
- goto done;
+ if (plug) {
+ /*
+ * The plug list might get flushed before this. If that
+ * happens, same_queue_rq is invalid and plug list is empty
+ **/
+ if (same_queue_rq && !list_empty(&plug->mq_list)) {
+ old_rq = same_queue_rq;
+ list_del_init(&old_rq->queuelist);
}
- }
+ list_add_tail(&rq->queuelist, &plug->mq_list);
+ } else /* is_sync */
+ old_rq = rq;
+ blk_mq_put_ctx(data.ctx);
+ if (!old_rq)
+ return;
+ if (!blk_mq_direct_issue_request(old_rq))
+ return;
+ blk_mq_insert_request(old_rq, false, true, true);
+ return;
}
if (!blk_mq_merge_queue_io(data.hctx, data.ctx, rq, bio)) {
@@ -1310,7 +1349,6 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
run_queue:
blk_mq_run_hw_queue(data.hctx, !is_sync || is_flush_fua);
}
-done:
blk_mq_put_ctx(data.ctx);
}
@@ -1322,16 +1360,11 @@ static void blk_sq_make_request(struct request_queue *q, struct bio *bio)
{
const int is_sync = rw_is_sync(bio->bi_rw);
const int is_flush_fua = bio->bi_rw & (REQ_FLUSH | REQ_FUA);
- unsigned int use_plug, request_count = 0;
+ struct blk_plug *plug;
+ unsigned int request_count = 0;
struct blk_map_ctx data;
struct request *rq;
- /*
- * If we have multiple hardware queues, just go directly to
- * one of those for sync IO.
- */
- use_plug = !is_flush_fua && !is_sync;
-
blk_queue_bounce(q, &bio);
if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
@@ -1339,8 +1372,8 @@ static void blk_sq_make_request(struct request_queue *q, struct bio *bio)
return;
}
- if (use_plug && !blk_queue_nomerges(q) &&
- blk_attempt_plug_merge(q, bio, &request_count))
+ if (!is_flush_fua && !blk_queue_nomerges(q) &&
+ blk_attempt_plug_merge(q, bio, &request_count, NULL))
return;
rq = blk_mq_map_request(q, bio, &data);
@@ -1358,21 +1391,18 @@ static void blk_sq_make_request(struct request_queue *q, struct bio *bio)
* utilize that to temporarily store requests until the task is
* either done or scheduled away.
*/
- if (use_plug) {
- struct blk_plug *plug = current->plug;
-
- if (plug) {
- blk_mq_bio_to_request(rq, bio);
- if (list_empty(&plug->mq_list))
- trace_block_plug(q);
- else if (request_count >= BLK_MAX_REQUEST_COUNT) {
- blk_flush_plug_list(plug, false);
- trace_block_plug(q);
- }
- list_add_tail(&rq->queuelist, &plug->mq_list);
- blk_mq_put_ctx(data.ctx);
- return;
+ plug = current->plug;
+ if (plug) {
+ blk_mq_bio_to_request(rq, bio);
+ if (list_empty(&plug->mq_list))
+ trace_block_plug(q);
+ else if (request_count >= BLK_MAX_REQUEST_COUNT) {
+ blk_flush_plug_list(plug, false);
+ trace_block_plug(q);
}
+ list_add_tail(&rq->queuelist, &plug->mq_list);
+ blk_mq_put_ctx(data.ctx);
+ return;
}
if (!blk_mq_merge_queue_io(data.hctx, data.ctx, rq, bio)) {
@@ -1508,7 +1538,6 @@ static struct blk_mq_tags *blk_mq_init_rq_map(struct blk_mq_tag_set *set,
i++;
}
}
-
return tags;
fail:
@@ -1792,6 +1821,7 @@ static void blk_mq_map_swqueue(struct request_queue *q)
hctx = q->mq_ops->map_queue(q, i);
cpumask_set_cpu(i, hctx->cpumask);
+ cpumask_set_cpu(i, hctx->tags->cpumask);
ctx->index_hw = hctx->nr_ctx;
hctx->ctxs[hctx->nr_ctx++] = ctx;
}
@@ -2056,7 +2086,7 @@ void blk_mq_free_queue(struct request_queue *q)
/* Basically redo blk_mq_init_queue with queue frozen */
static void blk_mq_queue_reinit(struct request_queue *q)
{
- WARN_ON_ONCE(!q->mq_freeze_depth);
+ WARN_ON_ONCE(!atomic_read(&q->mq_freeze_depth));
blk_mq_sysfs_unregister(q);
@@ -2173,6 +2203,12 @@ static int blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)
return 0;
}
+struct cpumask *blk_mq_tags_cpumask(struct blk_mq_tags *tags)
+{
+ return tags->cpumask;
+}
+EXPORT_SYMBOL_GPL(blk_mq_tags_cpumask);
+
/*
* Alloc a tag set to be associated with one or more request queues.
* May fail with EINVAL for various error conditions. May adjust the
@@ -2234,8 +2270,10 @@ void blk_mq_free_tag_set(struct blk_mq_tag_set *set)
int i;
for (i = 0; i < set->nr_hw_queues; i++) {
- if (set->tags[i])
+ if (set->tags[i]) {
blk_mq_free_rq_map(set, set->tags[i], i);
+ free_cpumask_var(set->tags[i]->cpumask);
+ }
}
kfree(set->tags);
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 2b8fd302f677..6264b382d4d1 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -6,11 +6,12 @@
#include <linux/module.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
+#include <linux/backing-dev.h>
#include <linux/blktrace_api.h>
#include <linux/blk-mq.h>
+#include <linux/blk-cgroup.h>
#include "blk.h"
-#include "blk-cgroup.h"
#include "blk-mq.h"
struct queue_sysfs_entry {
diff --git a/block/blk-throttle.c b/block/blk-throttle.c
index 5b9c6d5c3636..b23193518ac7 100644
--- a/block/blk-throttle.c
+++ b/block/blk-throttle.c
@@ -9,7 +9,7 @@
#include <linux/blkdev.h>
#include <linux/bio.h>
#include <linux/blktrace_api.h>
-#include "blk-cgroup.h"
+#include <linux/blk-cgroup.h>
#include "blk.h"
/* Max dispatch from a group in 1 round */
diff --git a/block/blk.h b/block/blk.h
index 43b036185712..026d9594142b 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -78,7 +78,8 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req,
bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
struct bio *bio);
bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio,
- unsigned int *request_count);
+ unsigned int *request_count,
+ struct request **same_queue_rq);
void blk_account_io_start(struct request *req, bool new_io);
void blk_account_io_completion(struct request *req, unsigned int bytes);
@@ -193,8 +194,6 @@ int blk_try_merge(struct request *rq, struct bio *bio);
void blk_queue_congestion_threshold(struct request_queue *q);
-void __blk_run_queue_uncond(struct request_queue *q);
-
int blk_dev_init(void);
diff --git a/block/bounce.c b/block/bounce.c
index ed9dd8067120..b17311227c12 100644
--- a/block/bounce.c
+++ b/block/bounce.c
@@ -13,6 +13,7 @@
#include <linux/pagemap.h>
#include <linux/mempool.h>
#include <linux/blkdev.h>
+#include <linux/backing-dev.h>
#include <linux/init.h>
#include <linux/hash.h>
#include <linux/highmem.h>
@@ -128,9 +129,6 @@ static void bounce_end_io(struct bio *bio, mempool_t *pool, int err)
struct bio_vec *bvec, *org_vec;
int i;
- if (test_bit(BIO_EOPNOTSUPP, &bio->bi_flags))
- set_bit(BIO_EOPNOTSUPP, &bio_orig->bi_flags);
-
/*
* free up bounce indirect pages used
*/
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 5da8e6e9ab4b..c62bb2e650b8 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -14,8 +14,8 @@
#include <linux/rbtree.h>
#include <linux/ioprio.h>
#include <linux/blktrace_api.h>
+#include <linux/blk-cgroup.h>
#include "blk.h"
-#include "blk-cgroup.h"
/*
* tunables
@@ -67,6 +67,11 @@ static struct kmem_cache *cfq_pool;
#define sample_valid(samples) ((samples) > 80)
#define rb_entry_cfqg(node) rb_entry((node), struct cfq_group, rb_node)
+/* blkio-related constants */
+#define CFQ_WEIGHT_MIN 10
+#define CFQ_WEIGHT_MAX 1000
+#define CFQ_WEIGHT_DEFAULT 500
+
struct cfq_ttime {
unsigned long last_end_request;
@@ -212,6 +217,15 @@ struct cfqg_stats {
#endif /* CONFIG_CFQ_GROUP_IOSCHED */
};
+/* Per-cgroup data */
+struct cfq_group_data {
+ /* must be the first member */
+ struct blkcg_policy_data pd;
+
+ unsigned int weight;
+ unsigned int leaf_weight;
+};
+
/* This is per cgroup per device grouping structure */
struct cfq_group {
/* must be the first member */
@@ -446,16 +460,6 @@ CFQ_CFQQ_FNS(deep);
CFQ_CFQQ_FNS(wait_busy);
#undef CFQ_CFQQ_FNS
-static inline struct cfq_group *pd_to_cfqg(struct blkg_policy_data *pd)
-{
- return pd ? container_of(pd, struct cfq_group, pd) : NULL;
-}
-
-static inline struct blkcg_gq *cfqg_to_blkg(struct cfq_group *cfqg)
-{
- return pd_to_blkg(&cfqg->pd);
-}
-
#if defined(CONFIG_CFQ_GROUP_IOSCHED) && defined(CONFIG_DEBUG_BLK_CGROUP)
/* cfqg stats flags */
@@ -600,6 +604,22 @@ static inline void cfqg_stats_update_avg_queue_size(struct cfq_group *cfqg) { }
#ifdef CONFIG_CFQ_GROUP_IOSCHED
+static inline struct cfq_group *pd_to_cfqg(struct blkg_policy_data *pd)
+{
+ return pd ? container_of(pd, struct cfq_group, pd) : NULL;
+}
+
+static struct cfq_group_data
+*cpd_to_cfqgd(struct blkcg_policy_data *cpd)
+{
+ return cpd ? container_of(cpd, struct cfq_group_data, pd) : NULL;
+}
+
+static inline struct blkcg_gq *cfqg_to_blkg(struct cfq_group *cfqg)
+{
+ return pd_to_blkg(&cfqg->pd);
+}
+
static struct blkcg_policy blkcg_policy_cfq;
static inline struct cfq_group *blkg_to_cfqg(struct blkcg_gq *blkg)
@@ -607,6 +627,11 @@ static inline struct cfq_group *blkg_to_cfqg(struct blkcg_gq *blkg)
return pd_to_cfqg(blkg_to_pd(blkg, &blkcg_policy_cfq));
}
+static struct cfq_group_data *blkcg_to_cfqgd(struct blkcg *blkcg)
+{
+ return cpd_to_cfqgd(blkcg_to_cpd(blkcg, &blkcg_policy_cfq));
+}
+
static inline struct cfq_group *cfqg_parent(struct cfq_group *cfqg)
{
struct blkcg_gq *pblkg = cfqg_to_blkg(cfqg)->parent;
@@ -1544,13 +1569,28 @@ static void cfqg_stats_init(struct cfqg_stats *stats)
#endif
}
+static void cfq_cpd_init(const struct blkcg *blkcg)
+{
+ struct cfq_group_data *cgd =
+ cpd_to_cfqgd(blkcg->pd[blkcg_policy_cfq.plid]);
+
+ if (blkcg == &blkcg_root) {
+ cgd->weight = 2 * CFQ_WEIGHT_DEFAULT;
+ cgd->leaf_weight = 2 * CFQ_WEIGHT_DEFAULT;
+ } else {
+ cgd->weight = CFQ_WEIGHT_DEFAULT;
+ cgd->leaf_weight = CFQ_WEIGHT_DEFAULT;
+ }
+}
+
static void cfq_pd_init(struct blkcg_gq *blkg)
{
struct cfq_group *cfqg = blkg_to_cfqg(blkg);
+ struct cfq_group_data *cgd = blkcg_to_cfqgd(blkg->blkcg);
cfq_init_cfqg_base(cfqg);
- cfqg->weight = blkg->blkcg->cfq_weight;
- cfqg->leaf_weight = blkg->blkcg->cfq_leaf_weight;
+ cfqg->weight = cgd->weight;
+ cfqg->leaf_weight = cgd->leaf_weight;
cfqg_stats_init(&cfqg->stats);
cfqg_stats_init(&cfqg->dead_stats);
}
@@ -1673,13 +1713,27 @@ static int cfqg_print_leaf_weight_device(struct seq_file *sf, void *v)
static int cfq_print_weight(struct seq_file *sf, void *v)
{
- seq_printf(sf, "%u\n", css_to_blkcg(seq_css(sf))->cfq_weight);
+ struct blkcg *blkcg = css_to_blkcg(seq_css(sf));
+ struct cfq_group_data *cgd = blkcg_to_cfqgd(blkcg);
+ unsigned int val = 0;
+
+ if (cgd)
+ val = cgd->weight;
+
+ seq_printf(sf, "%u\n", val);
return 0;
}
static int cfq_print_leaf_weight(struct seq_file *sf, void *v)
{
- seq_printf(sf, "%u\n", css_to_blkcg(seq_css(sf))->cfq_leaf_weight);
+ struct blkcg *blkcg = css_to_blkcg(seq_css(sf));
+ struct cfq_group_data *cgd = blkcg_to_cfqgd(blkcg);
+ unsigned int val = 0;
+
+ if (cgd)
+ val = cgd->leaf_weight;
+
+ seq_printf(sf, "%u\n", val);
return 0;
}
@@ -1690,6 +1744,7 @@ static ssize_t __cfqg_set_weight_device(struct kernfs_open_file *of,
struct blkcg *blkcg = css_to_blkcg(of_css(of));
struct blkg_conf_ctx ctx;
struct cfq_group *cfqg;
+ struct cfq_group_data *cfqgd;
int ret;
ret = blkg_conf_prep(blkcg, &blkcg_policy_cfq, buf, &ctx);
@@ -1698,17 +1753,22 @@ static ssize_t __cfqg_set_weight_device(struct kernfs_open_file *of,
ret = -EINVAL;
cfqg = blkg_to_cfqg(ctx.blkg);
+ cfqgd = blkcg_to_cfqgd(blkcg);
+ if (!cfqg || !cfqgd)
+ goto err;
+
if (!ctx.v || (ctx.v >= CFQ_WEIGHT_MIN && ctx.v <= CFQ_WEIGHT_MAX)) {
if (!is_leaf_weight) {
cfqg->dev_weight = ctx.v;
- cfqg->new_weight = ctx.v ?: blkcg->cfq_weight;
+ cfqg->new_weight = ctx.v ?: cfqgd->weight;
} else {
cfqg->dev_leaf_weight = ctx.v;
- cfqg->new_leaf_weight = ctx.v ?: blkcg->cfq_leaf_weight;
+ cfqg->new_leaf_weight = ctx.v ?: cfqgd->leaf_weight;
}
ret = 0;
}
+err:
blkg_conf_finish(&ctx);
return ret ?: nbytes;
}
@@ -1730,16 +1790,23 @@ static int __cfq_set_weight(struct cgroup_subsys_state *css, struct cftype *cft,
{
struct blkcg *blkcg = css_to_blkcg(css);
struct blkcg_gq *blkg;
+ struct cfq_group_data *cfqgd;
+ int ret = 0;
if (val < CFQ_WEIGHT_MIN || val > CFQ_WEIGHT_MAX)
return -EINVAL;
spin_lock_irq(&blkcg->lock);
+ cfqgd = blkcg_to_cfqgd(blkcg);
+ if (!cfqgd) {
+ ret = -EINVAL;
+ goto out;
+ }
if (!is_leaf_weight)
- blkcg->cfq_weight = val;
+ cfqgd->weight = val;
else
- blkcg->cfq_leaf_weight = val;
+ cfqgd->leaf_weight = val;
hlist_for_each_entry(blkg, &blkcg->blkg_list, blkcg_node) {
struct cfq_group *cfqg = blkg_to_cfqg(blkg);
@@ -1749,15 +1816,16 @@ static int __cfq_set_weight(struct cgroup_subsys_state *css, struct cftype *cft,
if (!is_leaf_weight) {
if (!cfqg->dev_weight)
- cfqg->new_weight = blkcg->cfq_weight;
+ cfqg->new_weight = cfqgd->weight;
} else {
if (!cfqg->dev_leaf_weight)
- cfqg->new_leaf_weight = blkcg->cfq_leaf_weight;
+ cfqg->new_leaf_weight = cfqgd->leaf_weight;
}
}
+out:
spin_unlock_irq(&blkcg->lock);
- return 0;
+ return ret;
}
static int cfq_set_weight(struct cgroup_subsys_state *css, struct cftype *cft,
@@ -4477,6 +4545,18 @@ out_free:
return ret;
}
+static void cfq_registered_queue(struct request_queue *q)
+{
+ struct elevator_queue *e = q->elevator;
+ struct cfq_data *cfqd = e->elevator_data;
+
+ /*
+ * Default to IOPS mode with no idling for SSDs
+ */
+ if (blk_queue_nonrot(q))
+ cfqd->cfq_slice_idle = 0;
+}
+
/*
* sysfs parts below -->
*/
@@ -4592,6 +4672,7 @@ static struct elevator_type iosched_cfq = {
.elevator_may_queue_fn = cfq_may_queue,
.elevator_init_fn = cfq_init_queue,
.elevator_exit_fn = cfq_exit_queue,
+ .elevator_registered_fn = cfq_registered_queue,
},
.icq_size = sizeof(struct cfq_io_cq),
.icq_align = __alignof__(struct cfq_io_cq),
@@ -4603,8 +4684,10 @@ static struct elevator_type iosched_cfq = {
#ifdef CONFIG_CFQ_GROUP_IOSCHED
static struct blkcg_policy blkcg_policy_cfq = {
.pd_size = sizeof(struct cfq_group),
+ .cpd_size = sizeof(struct cfq_group_data),
.cftypes = cfq_blkcg_files,
+ .cpd_init_fn = cfq_cpd_init,
.pd_init_fn = cfq_pd_init,
.pd_offline_fn = cfq_pd_offline,
.pd_reset_stats_fn = cfq_pd_reset_stats,
diff --git a/block/elevator.c b/block/elevator.c
index 8985038f398c..84d63943f2de 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -35,11 +35,11 @@
#include <linux/hash.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
+#include <linux/blk-cgroup.h>
#include <trace/events/block.h>
#include "blk.h"
-#include "blk-cgroup.h"
static DEFINE_SPINLOCK(elv_list_lock);
static LIST_HEAD(elv_list);
@@ -806,6 +806,8 @@ int elv_register_queue(struct request_queue *q)
}
kobject_uevent(&e->kobj, KOBJ_ADD);
e->registered = 1;
+ if (e->type->ops.elevator_registered_fn)
+ e->type->ops.elevator_registered_fn(q);
}
return error;
}
diff --git a/block/genhd.c b/block/genhd.c
index ea982eadaf63..59a1395eedac 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -8,6 +8,7 @@
#include <linux/kdev_t.h>
#include <linux/kernel.h>
#include <linux/blkdev.h>
+#include <linux/backing-dev.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/proc_fs.h>
diff --git a/block/ioctl.c b/block/ioctl.c
index 7d8befde2aca..8061eba42887 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -150,21 +150,48 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
}
}
-static int blkdev_reread_part(struct block_device *bdev)
+/*
+ * This is an exported API for the block driver, and will not
+ * acquire bd_mutex. This API should be used in case that
+ * caller has held bd_mutex already.
+ */
+int __blkdev_reread_part(struct block_device *bdev)
{
struct gendisk *disk = bdev->bd_disk;
- int res;
if (!disk_part_scan_enabled(disk) || bdev != bdev->bd_contains)
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (!mutex_trylock(&bdev->bd_mutex))
- return -EBUSY;
- res = rescan_partitions(disk, bdev);
+
+ lockdep_assert_held(&bdev->bd_mutex);
+
+ return rescan_partitions(disk, bdev);
+}
+EXPORT_SYMBOL(__blkdev_reread_part);
+
+/*
+ * This is an exported API for the block driver, and will
+ * try to acquire bd_mutex. If bd_mutex has been held already
+ * in current context, please call __blkdev_reread_part().
+ *
+ * Make sure the held locks in current context aren't required
+ * in open()/close() handler and I/O path for avoiding ABBA deadlock:
+ * - bd_mutex is held before calling block driver's open/close
+ * handler
+ * - reading partition table may submit I/O to the block device
+ */
+int blkdev_reread_part(struct block_device *bdev)
+{
+ int res;
+
+ mutex_lock(&bdev->bd_mutex);
+ res = __blkdev_reread_part(bdev);
mutex_unlock(&bdev->bd_mutex);
+
return res;
}
+EXPORT_SYMBOL(blkdev_reread_part);
static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
uint64_t len, int secure)
diff --git a/crypto/.gitignore b/crypto/.gitignore
new file mode 100644
index 000000000000..ee328374dba8
--- /dev/null
+++ b/crypto/.gitignore
@@ -0,0 +1 @@
+*-asn1.[ch]
diff --git a/crypto/842.c b/crypto/842.c
index b48f4f108c47..98e387efb8c8 100644
--- a/crypto/842.c
+++ b/crypto/842.c
@@ -1,5 +1,5 @@
/*
- * Cryptographic API for the 842 compression algorithm.
+ * Cryptographic API for the 842 software compression algorithm.
*
* 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
@@ -11,173 +11,73 @@
* 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * Copyright (C) IBM Corporation, 2011-2015
*
- * Copyright (C) IBM Corporation, 2011
+ * Original Authors: Robert Jennings <rcj@linux.vnet.ibm.com>
+ * Seth Jennings <sjenning@linux.vnet.ibm.com>
*
- * Authors: Robert Jennings <rcj@linux.vnet.ibm.com>
- * Seth Jennings <sjenning@linux.vnet.ibm.com>
+ * Rewrite: Dan Streetman <ddstreet@ieee.org>
+ *
+ * This is the software implementation of compression and decompression using
+ * the 842 format. This uses the software 842 library at lib/842/ which is
+ * only a reference implementation, and is very, very slow as compared to other
+ * software compressors. You probably do not want to use this software
+ * compression. If you have access to the PowerPC 842 compression hardware, you
+ * want to use the 842 hardware compression interface, which is at:
+ * drivers/crypto/nx/nx-842-crypto.c
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/crypto.h>
-#include <linux/vmalloc.h>
-#include <linux/nx842.h>
-#include <linux/lzo.h>
-#include <linux/timer.h>
-
-static int nx842_uselzo;
-
-struct nx842_ctx {
- void *nx842_wmem; /* working memory for 842/lzo */
-};
+#include <linux/sw842.h>
-enum nx842_crypto_type {
- NX842_CRYPTO_TYPE_842,
- NX842_CRYPTO_TYPE_LZO
+struct crypto842_ctx {
+ char wmem[SW842_MEM_COMPRESS]; /* working memory for compress */
};
-#define NX842_SENTINEL 0xdeadbeef
-
-struct nx842_crypto_header {
- unsigned int sentinel; /* debug */
- enum nx842_crypto_type type;
-};
-
-static int nx842_init(struct crypto_tfm *tfm)
-{
- struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
- int wmemsize;
-
- wmemsize = max_t(int, nx842_get_workmem_size(), LZO1X_MEM_COMPRESS);
- ctx->nx842_wmem = kmalloc(wmemsize, GFP_NOFS);
- if (!ctx->nx842_wmem)
- return -ENOMEM;
-
- return 0;
-}
-
-static void nx842_exit(struct crypto_tfm *tfm)
-{
- struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
-
- kfree(ctx->nx842_wmem);
-}
-
-static void nx842_reset_uselzo(unsigned long data)
+static int crypto842_compress(struct crypto_tfm *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen)
{
- nx842_uselzo = 0;
-}
-
-static DEFINE_TIMER(failover_timer, nx842_reset_uselzo, 0, 0);
-
-static int nx842_crypto_compress(struct crypto_tfm *tfm, const u8 *src,
- unsigned int slen, u8 *dst, unsigned int *dlen)
-{
- struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
- struct nx842_crypto_header *hdr;
- unsigned int tmp_len = *dlen;
- size_t lzodlen; /* needed for lzo */
- int err;
-
- *dlen = 0;
- hdr = (struct nx842_crypto_header *)dst;
- hdr->sentinel = NX842_SENTINEL; /* debug */
- dst += sizeof(struct nx842_crypto_header);
- tmp_len -= sizeof(struct nx842_crypto_header);
- lzodlen = tmp_len;
-
- if (likely(!nx842_uselzo)) {
- err = nx842_compress(src, slen, dst, &tmp_len, ctx->nx842_wmem);
-
- if (likely(!err)) {
- hdr->type = NX842_CRYPTO_TYPE_842;
- *dlen = tmp_len + sizeof(struct nx842_crypto_header);
- return 0;
- }
-
- /* hardware failed */
- nx842_uselzo = 1;
+ struct crypto842_ctx *ctx = crypto_tfm_ctx(tfm);
- /* set timer to check for hardware again in 1 second */
- mod_timer(&failover_timer, jiffies + msecs_to_jiffies(1000));
- }
-
- /* no hardware, use lzo */
- err = lzo1x_1_compress(src, slen, dst, &lzodlen, ctx->nx842_wmem);
- if (err != LZO_E_OK)
- return -EINVAL;
-
- hdr->type = NX842_CRYPTO_TYPE_LZO;
- *dlen = lzodlen + sizeof(struct nx842_crypto_header);
- return 0;
+ return sw842_compress(src, slen, dst, dlen, ctx->wmem);
}
-static int nx842_crypto_decompress(struct crypto_tfm *tfm, const u8 *src,
- unsigned int slen, u8 *dst, unsigned int *dlen)
+static int crypto842_decompress(struct crypto_tfm *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen)
{
- struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
- struct nx842_crypto_header *hdr;
- unsigned int tmp_len = *dlen;
- size_t lzodlen; /* needed for lzo */
- int err;
-
- *dlen = 0;
- hdr = (struct nx842_crypto_header *)src;
-
- if (unlikely(hdr->sentinel != NX842_SENTINEL))
- return -EINVAL;
-
- src += sizeof(struct nx842_crypto_header);
- slen -= sizeof(struct nx842_crypto_header);
-
- if (likely(hdr->type == NX842_CRYPTO_TYPE_842)) {
- err = nx842_decompress(src, slen, dst, &tmp_len,
- ctx->nx842_wmem);
- if (err)
- return -EINVAL;
- *dlen = tmp_len;
- } else if (hdr->type == NX842_CRYPTO_TYPE_LZO) {
- lzodlen = tmp_len;
- err = lzo1x_decompress_safe(src, slen, dst, &lzodlen);
- if (err != LZO_E_OK)
- return -EINVAL;
- *dlen = lzodlen;
- } else
- return -EINVAL;
-
- return 0;
+ return sw842_decompress(src, slen, dst, dlen);
}
static struct crypto_alg alg = {
.cra_name = "842",
+ .cra_driver_name = "842-generic",
+ .cra_priority = 100,
.cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
- .cra_ctxsize = sizeof(struct nx842_ctx),
+ .cra_ctxsize = sizeof(struct crypto842_ctx),
.cra_module = THIS_MODULE,
- .cra_init = nx842_init,
- .cra_exit = nx842_exit,
.cra_u = { .compress = {
- .coa_compress = nx842_crypto_compress,
- .coa_decompress = nx842_crypto_decompress } }
+ .coa_compress = crypto842_compress,
+ .coa_decompress = crypto842_decompress } }
};
-static int __init nx842_mod_init(void)
+static int __init crypto842_mod_init(void)
{
- del_timer(&failover_timer);
return crypto_register_alg(&alg);
}
+module_init(crypto842_mod_init);
-static void __exit nx842_mod_exit(void)
+static void __exit crypto842_mod_exit(void)
{
crypto_unregister_alg(&alg);
}
-
-module_init(nx842_mod_init);
-module_exit(nx842_mod_exit);
+module_exit(crypto842_mod_exit);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("842 Compression Algorithm");
+MODULE_DESCRIPTION("842 Software Compression Algorithm");
MODULE_ALIAS_CRYPTO("842");
+MODULE_ALIAS_CRYPTO("842-generic");
+MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>");
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 362905e7c841..b4cfc5754033 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -78,6 +78,10 @@ config CRYPTO_RNG2
tristate
select CRYPTO_ALGAPI2
+config CRYPTO_RNG_DEFAULT
+ tristate
+ select CRYPTO_DRBG_MENU
+
config CRYPTO_PCOMP
tristate
select CRYPTO_PCOMP2
@@ -87,6 +91,23 @@ config CRYPTO_PCOMP2
tristate
select CRYPTO_ALGAPI2
+config CRYPTO_AKCIPHER2
+ tristate
+ select CRYPTO_ALGAPI2
+
+config CRYPTO_AKCIPHER
+ tristate
+ select CRYPTO_AKCIPHER2
+ select CRYPTO_ALGAPI
+
+config CRYPTO_RSA
+ tristate "RSA algorithm"
+ select CRYPTO_AKCIPHER
+ select MPILIB
+ select ASN1
+ help
+ Generic implementation of the RSA public key algorithm.
+
config CRYPTO_MANAGER
tristate "Cryptographic algorithm manager"
select CRYPTO_MANAGER2
@@ -100,6 +121,7 @@ config CRYPTO_MANAGER2
select CRYPTO_HASH2
select CRYPTO_BLKCIPHER2
select CRYPTO_PCOMP2
+ select CRYPTO_AKCIPHER2
config CRYPTO_USER
tristate "Userspace cryptographic algorithm configuration"
@@ -217,15 +239,39 @@ config CRYPTO_GCM
Support for Galois/Counter Mode (GCM) and Galois Message
Authentication Code (GMAC). Required for IPSec.
+config CRYPTO_CHACHA20POLY1305
+ tristate "ChaCha20-Poly1305 AEAD support"
+ select CRYPTO_CHACHA20
+ select CRYPTO_POLY1305
+ select CRYPTO_AEAD
+ help
+ ChaCha20-Poly1305 AEAD support, RFC7539.
+
+ Support for the AEAD wrapper using the ChaCha20 stream cipher combined
+ with the Poly1305 authenticator. It is defined in RFC7539 for use in
+ IETF protocols.
+
config CRYPTO_SEQIV
tristate "Sequence Number IV Generator"
select CRYPTO_AEAD
select CRYPTO_BLKCIPHER
- select CRYPTO_RNG
+ select CRYPTO_NULL
+ select CRYPTO_RNG_DEFAULT
help
This IV generator generates an IV based on a sequence number by
xoring it with a salt. This algorithm is mainly useful for CTR
+config CRYPTO_ECHAINIV
+ tristate "Encrypted Chain IV Generator"
+ select CRYPTO_AEAD
+ select CRYPTO_NULL
+ select CRYPTO_RNG_DEFAULT
+ default m
+ help
+ This IV generator generates an IV based on the encryption of
+ a sequence number xored with a salt. This is the default
+ algorithm for CBC.
+
comment "Block modes"
config CRYPTO_CBC
@@ -415,6 +461,15 @@ config CRYPTO_GHASH
help
GHASH is message digest algorithm for GCM (Galois/Counter Mode).
+config CRYPTO_POLY1305
+ tristate "Poly1305 authenticator algorithm"
+ help
+ Poly1305 authenticator algorithm, RFC7539.
+
+ Poly1305 is an authenticator algorithm designed by Daniel J. Bernstein.
+ It is used for the ChaCha20-Poly1305 AEAD, specified in RFC7539 for use
+ in IETF protocols. This is the portable C implementation of Poly1305.
+
config CRYPTO_MD4
tristate "MD4 digest algorithm"
select CRYPTO_HASH
@@ -1145,6 +1200,19 @@ config CRYPTO_SALSA20_X86_64
The Salsa20 stream cipher algorithm is designed by Daniel J.
Bernstein <djb@cr.yp.to>. See <http://cr.yp.to/snuffle.html>
+config CRYPTO_CHACHA20
+ tristate "ChaCha20 cipher algorithm"
+ select CRYPTO_BLKCIPHER
+ help
+ ChaCha20 cipher algorithm, RFC7539.
+
+ ChaCha20 is a 256-bit high-speed stream cipher designed by Daniel J.
+ Bernstein and further specified in RFC7539 for use in IETF protocols.
+ This is the portable C implementation of ChaCha20.
+
+ See also:
+ <http://cr.yp.to/chacha/chacha-20080128.pdf>
+
config CRYPTO_SEED
tristate "SEED cipher algorithm"
select CRYPTO_ALGAPI
@@ -1412,10 +1480,9 @@ config CRYPTO_LZO
config CRYPTO_842
tristate "842 compression algorithm"
- depends on CRYPTO_DEV_NX_COMPRESS
- # 842 uses lzo if the hardware becomes unavailable
- select LZO_COMPRESS
- select LZO_DECOMPRESS
+ select CRYPTO_ALGAPI
+ select 842_COMPRESS
+ select 842_DECOMPRESS
help
This is the 842 algorithm.
@@ -1439,7 +1506,6 @@ comment "Random Number Generation"
config CRYPTO_ANSI_CPRNG
tristate "Pseudo Random Number Generation for Cryptographic modules"
- default m
select CRYPTO_AES
select CRYPTO_RNG
help
@@ -1457,15 +1523,14 @@ menuconfig CRYPTO_DRBG_MENU
if CRYPTO_DRBG_MENU
config CRYPTO_DRBG_HMAC
- bool "Enable HMAC DRBG"
+ bool
default y
select CRYPTO_HMAC
- help
- Enable the HMAC DRBG variant as defined in NIST SP800-90A.
+ select CRYPTO_SHA256
config CRYPTO_DRBG_HASH
bool "Enable Hash DRBG"
- select CRYPTO_HASH
+ select CRYPTO_SHA256
help
Enable the Hash DRBG variant as defined in NIST SP800-90A.
@@ -1477,11 +1542,21 @@ config CRYPTO_DRBG_CTR
config CRYPTO_DRBG
tristate
- default CRYPTO_DRBG_MENU if (CRYPTO_DRBG_HMAC || CRYPTO_DRBG_HASH || CRYPTO_DRBG_CTR)
+ default CRYPTO_DRBG_MENU
select CRYPTO_RNG
+ select CRYPTO_JITTERENTROPY
endif # if CRYPTO_DRBG_MENU
+config CRYPTO_JITTERENTROPY
+ tristate "Jitterentropy Non-Deterministic Random Number Generator"
+ help
+ The Jitterentropy RNG is a noise that is intended
+ to provide seed to another RNG. The RNG does not
+ perform any cryptographic whitening of the generated
+ random numbers. This Jitterentropy RNG registers with
+ the kernel crypto API and can be used by any caller.
+
config CRYPTO_USER_API
tristate
@@ -1512,6 +1587,15 @@ config CRYPTO_USER_API_RNG
This option enables the user-spaces interface for random
number generator algorithms.
+config CRYPTO_USER_API_AEAD
+ tristate "User-space interface for AEAD cipher algorithms"
+ depends on NET
+ select CRYPTO_AEAD
+ select CRYPTO_USER_API
+ help
+ This option enables the user-spaces interface for AEAD
+ cipher algorithms.
+
config CRYPTO_HASH_INFO
bool
diff --git a/crypto/Makefile b/crypto/Makefile
index 97b7d3ac87e7..a16a7e7f2d60 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -21,12 +21,22 @@ obj-$(CONFIG_CRYPTO_BLKCIPHER2) += crypto_blkcipher.o
obj-$(CONFIG_CRYPTO_BLKCIPHER2) += chainiv.o
obj-$(CONFIG_CRYPTO_BLKCIPHER2) += eseqiv.o
obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
+obj-$(CONFIG_CRYPTO_ECHAINIV) += echainiv.o
crypto_hash-y += ahash.o
crypto_hash-y += shash.o
obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o
obj-$(CONFIG_CRYPTO_PCOMP2) += pcompress.o
+obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o
+
+$(obj)/rsakey-asn1.o: $(obj)/rsakey-asn1.c $(obj)/rsakey-asn1.h
+clean-files += rsakey-asn1.c rsakey-asn1.h
+
+rsa_generic-y := rsakey-asn1.o
+rsa_generic-y += rsa.o
+rsa_generic-y += rsa_helper.o
+obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o
cryptomgr-y := algboss.o testmgr.o
@@ -58,6 +68,7 @@ obj-$(CONFIG_CRYPTO_XTS) += xts.o
obj-$(CONFIG_CRYPTO_CTR) += ctr.o
obj-$(CONFIG_CRYPTO_GCM) += gcm.o
obj-$(CONFIG_CRYPTO_CCM) += ccm.o
+obj-$(CONFIG_CRYPTO_CHACHA20POLY1305) += chacha20poly1305.o
obj-$(CONFIG_CRYPTO_PCRYPT) += pcrypt.o
obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o
obj-$(CONFIG_CRYPTO_MCRYPTD) += mcryptd.o
@@ -79,6 +90,8 @@ obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o
obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o
obj-$(CONFIG_CRYPTO_SEED) += seed.o
obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
+obj-$(CONFIG_CRYPTO_CHACHA20) += chacha20_generic.o
+obj-$(CONFIG_CRYPTO_POLY1305) += poly1305_generic.o
obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
@@ -91,9 +104,11 @@ obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o
obj-$(CONFIG_CRYPTO_842) += 842.o
obj-$(CONFIG_CRYPTO_RNG2) += rng.o
-obj-$(CONFIG_CRYPTO_RNG2) += krng.o
obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o
obj-$(CONFIG_CRYPTO_DRBG) += drbg.o
+obj-$(CONFIG_CRYPTO_JITTERENTROPY) += jitterentropy_rng.o
+CFLAGS_jitterentropy.o = -O0
+jitterentropy_rng-y := jitterentropy.o jitterentropy-kcapi.o
obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o
obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o
diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c
index db201bca1581..b788f169cc98 100644
--- a/crypto/ablkcipher.c
+++ b/crypto/ablkcipher.c
@@ -454,7 +454,7 @@ static int crypto_init_givcipher_ops(struct crypto_tfm *tfm, u32 type,
alg->setkey : setkey;
crt->encrypt = alg->encrypt;
crt->decrypt = alg->decrypt;
- crt->givencrypt = alg->givencrypt;
+ crt->givencrypt = alg->givencrypt ?: no_givdecrypt;
crt->givdecrypt = alg->givdecrypt ?: no_givdecrypt;
crt->base = __crypto_ablkcipher_cast(tfm);
crt->ivsize = alg->ivsize;
@@ -586,6 +586,13 @@ static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask)
if (!tmpl)
goto kill_larval;
+ if (tmpl->create) {
+ err = tmpl->create(tmpl, tb);
+ if (err)
+ goto put_tmpl;
+ goto ok;
+ }
+
inst = tmpl->alloc(tb);
err = PTR_ERR(inst);
if (IS_ERR(inst))
@@ -597,6 +604,7 @@ static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask)
goto put_tmpl;
}
+ok:
/* Redo the lookup to use the instance we just registered. */
err = -EAGAIN;
@@ -636,7 +644,7 @@ struct crypto_alg *crypto_lookup_skcipher(const char *name, u32 type, u32 mask)
if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
CRYPTO_ALG_TYPE_GIVCIPHER) {
- if ((alg->cra_flags ^ type ^ ~mask) & CRYPTO_ALG_TESTED) {
+ if (~alg->cra_flags & (type ^ ~mask) & CRYPTO_ALG_TESTED) {
crypto_mod_put(alg);
alg = ERR_PTR(-ENOENT);
}
diff --git a/crypto/aead.c b/crypto/aead.c
index 222271070b49..07bf99773548 100644
--- a/crypto/aead.c
+++ b/crypto/aead.c
@@ -12,7 +12,8 @@
*
*/
-#include <crypto/internal/aead.h>
+#include <crypto/internal/geniv.h>
+#include <crypto/scatterwalk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -26,10 +27,20 @@
#include "internal.h"
+struct compat_request_ctx {
+ struct scatterlist src[2];
+ struct scatterlist dst[2];
+ struct scatterlist ivbuf[2];
+ struct scatterlist *ivsg;
+ struct aead_givcrypt_request subreq;
+};
+
+static int aead_null_givencrypt(struct aead_givcrypt_request *req);
+static int aead_null_givdecrypt(struct aead_givcrypt_request *req);
+
static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key,
unsigned int keylen)
{
- struct aead_alg *aead = crypto_aead_alg(tfm);
unsigned long alignmask = crypto_aead_alignmask(tfm);
int ret;
u8 *buffer, *alignbuffer;
@@ -42,47 +53,95 @@ static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key,
alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
memcpy(alignbuffer, key, keylen);
- ret = aead->setkey(tfm, alignbuffer, keylen);
+ ret = tfm->setkey(tfm, alignbuffer, keylen);
memset(alignbuffer, 0, keylen);
kfree(buffer);
return ret;
}
-static int setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
+int crypto_aead_setkey(struct crypto_aead *tfm,
+ const u8 *key, unsigned int keylen)
{
- struct aead_alg *aead = crypto_aead_alg(tfm);
unsigned long alignmask = crypto_aead_alignmask(tfm);
+ tfm = tfm->child;
+
if ((unsigned long)key & alignmask)
return setkey_unaligned(tfm, key, keylen);
- return aead->setkey(tfm, key, keylen);
+ return tfm->setkey(tfm, key, keylen);
}
+EXPORT_SYMBOL_GPL(crypto_aead_setkey);
int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
{
- struct aead_tfm *crt = crypto_aead_crt(tfm);
int err;
- if (authsize > crypto_aead_alg(tfm)->maxauthsize)
+ if (authsize > crypto_aead_maxauthsize(tfm))
return -EINVAL;
- if (crypto_aead_alg(tfm)->setauthsize) {
- err = crypto_aead_alg(tfm)->setauthsize(crt->base, authsize);
+ if (tfm->setauthsize) {
+ err = tfm->setauthsize(tfm->child, authsize);
if (err)
return err;
}
- crypto_aead_crt(crt->base)->authsize = authsize;
- crt->authsize = authsize;
+ tfm->child->authsize = authsize;
+ tfm->authsize = authsize;
return 0;
}
EXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
-static unsigned int crypto_aead_ctxsize(struct crypto_alg *alg, u32 type,
- u32 mask)
+struct aead_old_request {
+ struct scatterlist srcbuf[2];
+ struct scatterlist dstbuf[2];
+ struct aead_request subreq;
+};
+
+unsigned int crypto_aead_reqsize(struct crypto_aead *tfm)
{
- return alg->cra_ctxsize;
+ return tfm->reqsize + sizeof(struct aead_old_request);
+}
+EXPORT_SYMBOL_GPL(crypto_aead_reqsize);
+
+static int old_crypt(struct aead_request *req,
+ int (*crypt)(struct aead_request *req))
+{
+ struct aead_old_request *nreq = aead_request_ctx(req);
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct scatterlist *src, *dst;
+
+ if (req->old)
+ return crypt(req);
+
+ src = scatterwalk_ffwd(nreq->srcbuf, req->src, req->assoclen);
+ dst = req->src == req->dst ?
+ src : scatterwalk_ffwd(nreq->dstbuf, req->dst, req->assoclen);
+
+ aead_request_set_tfm(&nreq->subreq, aead);
+ aead_request_set_callback(&nreq->subreq, aead_request_flags(req),
+ req->base.complete, req->base.data);
+ aead_request_set_crypt(&nreq->subreq, src, dst, req->cryptlen,
+ req->iv);
+ aead_request_set_assoc(&nreq->subreq, req->src, req->assoclen);
+
+ return crypt(&nreq->subreq);
+}
+
+static int old_encrypt(struct aead_request *req)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct old_aead_alg *alg = crypto_old_aead_alg(aead);
+
+ return old_crypt(req, alg->encrypt);
+}
+
+static int old_decrypt(struct aead_request *req)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct old_aead_alg *alg = crypto_old_aead_alg(aead);
+
+ return old_crypt(req, alg->decrypt);
}
static int no_givcrypt(struct aead_givcrypt_request *req)
@@ -90,32 +149,68 @@ static int no_givcrypt(struct aead_givcrypt_request *req)
return -ENOSYS;
}
-static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+static int crypto_old_aead_init_tfm(struct crypto_tfm *tfm)
{
- struct aead_alg *alg = &tfm->__crt_alg->cra_aead;
- struct aead_tfm *crt = &tfm->crt_aead;
+ struct old_aead_alg *alg = &tfm->__crt_alg->cra_aead;
+ struct crypto_aead *crt = __crypto_aead_cast(tfm);
if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8)
return -EINVAL;
- crt->setkey = tfm->__crt_alg->cra_flags & CRYPTO_ALG_GENIV ?
- alg->setkey : setkey;
- crt->encrypt = alg->encrypt;
- crt->decrypt = alg->decrypt;
- crt->givencrypt = alg->givencrypt ?: no_givcrypt;
- crt->givdecrypt = alg->givdecrypt ?: no_givcrypt;
- crt->base = __crypto_aead_cast(tfm);
- crt->ivsize = alg->ivsize;
+ crt->setkey = alg->setkey;
+ crt->setauthsize = alg->setauthsize;
+ crt->encrypt = old_encrypt;
+ crt->decrypt = old_decrypt;
+ if (alg->ivsize) {
+ crt->givencrypt = alg->givencrypt ?: no_givcrypt;
+ crt->givdecrypt = alg->givdecrypt ?: no_givcrypt;
+ } else {
+ crt->givencrypt = aead_null_givencrypt;
+ crt->givdecrypt = aead_null_givdecrypt;
+ }
+ crt->child = __crypto_aead_cast(tfm);
crt->authsize = alg->maxauthsize;
return 0;
}
+static void crypto_aead_exit_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_aead *aead = __crypto_aead_cast(tfm);
+ struct aead_alg *alg = crypto_aead_alg(aead);
+
+ alg->exit(aead);
+}
+
+static int crypto_aead_init_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_aead *aead = __crypto_aead_cast(tfm);
+ struct aead_alg *alg = crypto_aead_alg(aead);
+
+ if (crypto_old_aead_alg(aead)->encrypt)
+ return crypto_old_aead_init_tfm(tfm);
+
+ aead->setkey = alg->setkey;
+ aead->setauthsize = alg->setauthsize;
+ aead->encrypt = alg->encrypt;
+ aead->decrypt = alg->decrypt;
+ aead->child = __crypto_aead_cast(tfm);
+ aead->authsize = alg->maxauthsize;
+
+ if (alg->exit)
+ aead->base.exit = crypto_aead_exit_tfm;
+
+ if (alg->init)
+ return alg->init(aead);
+
+ return 0;
+}
+
#ifdef CONFIG_NET
-static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
+static int crypto_old_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_report_aead raead;
- struct aead_alg *aead = &alg->cra_aead;
+ struct old_aead_alg *aead = &alg->cra_aead;
strncpy(raead.type, "aead", sizeof(raead.type));
strncpy(raead.geniv, aead->geniv ?: "<built-in>", sizeof(raead.geniv));
@@ -133,6 +228,64 @@ nla_put_failure:
return -EMSGSIZE;
}
#else
+static int crypto_old_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+ return -ENOSYS;
+}
+#endif
+
+static void crypto_old_aead_show(struct seq_file *m, struct crypto_alg *alg)
+ __attribute__ ((unused));
+static void crypto_old_aead_show(struct seq_file *m, struct crypto_alg *alg)
+{
+ struct old_aead_alg *aead = &alg->cra_aead;
+
+ seq_printf(m, "type : aead\n");
+ seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
+ "yes" : "no");
+ seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
+ seq_printf(m, "ivsize : %u\n", aead->ivsize);
+ seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize);
+ seq_printf(m, "geniv : %s\n", aead->geniv ?: "<built-in>");
+}
+
+const struct crypto_type crypto_aead_type = {
+ .extsize = crypto_alg_extsize,
+ .init_tfm = crypto_aead_init_tfm,
+#ifdef CONFIG_PROC_FS
+ .show = crypto_old_aead_show,
+#endif
+ .report = crypto_old_aead_report,
+ .lookup = crypto_lookup_aead,
+ .maskclear = ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV),
+ .maskset = CRYPTO_ALG_TYPE_MASK,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .tfmsize = offsetof(struct crypto_aead, base),
+};
+EXPORT_SYMBOL_GPL(crypto_aead_type);
+
+#ifdef CONFIG_NET
+static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+ struct crypto_report_aead raead;
+ struct aead_alg *aead = container_of(alg, struct aead_alg, base);
+
+ strncpy(raead.type, "aead", sizeof(raead.type));
+ strncpy(raead.geniv, "<none>", sizeof(raead.geniv));
+
+ raead.blocksize = alg->cra_blocksize;
+ raead.maxauthsize = aead->maxauthsize;
+ raead.ivsize = aead->ivsize;
+
+ if (nla_put(skb, CRYPTOCFGA_REPORT_AEAD,
+ sizeof(struct crypto_report_aead), &raead))
+ goto nla_put_failure;
+ return 0;
+
+nla_put_failure:
+ return -EMSGSIZE;
+}
+#else
static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
{
return -ENOSYS;
@@ -143,7 +296,7 @@ static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
__attribute__ ((unused));
static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
{
- struct aead_alg *aead = &alg->cra_aead;
+ struct aead_alg *aead = container_of(alg, struct aead_alg, base);
seq_printf(m, "type : aead\n");
seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
@@ -151,18 +304,21 @@ static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
seq_printf(m, "ivsize : %u\n", aead->ivsize);
seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize);
- seq_printf(m, "geniv : %s\n", aead->geniv ?: "<built-in>");
+ seq_printf(m, "geniv : <none>\n");
}
-const struct crypto_type crypto_aead_type = {
- .ctxsize = crypto_aead_ctxsize,
- .init = crypto_init_aead_ops,
+static const struct crypto_type crypto_new_aead_type = {
+ .extsize = crypto_alg_extsize,
+ .init_tfm = crypto_aead_init_tfm,
#ifdef CONFIG_PROC_FS
.show = crypto_aead_show,
#endif
.report = crypto_aead_report,
+ .maskclear = ~CRYPTO_ALG_TYPE_MASK,
+ .maskset = CRYPTO_ALG_TYPE_MASK,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .tfmsize = offsetof(struct crypto_aead, base),
};
-EXPORT_SYMBOL_GPL(crypto_aead_type);
static int aead_null_givencrypt(struct aead_givcrypt_request *req)
{
@@ -174,33 +330,11 @@ static int aead_null_givdecrypt(struct aead_givcrypt_request *req)
return crypto_aead_decrypt(&req->areq);
}
-static int crypto_init_nivaead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
-{
- struct aead_alg *alg = &tfm->__crt_alg->cra_aead;
- struct aead_tfm *crt = &tfm->crt_aead;
-
- if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8)
- return -EINVAL;
-
- crt->setkey = setkey;
- crt->encrypt = alg->encrypt;
- crt->decrypt = alg->decrypt;
- if (!alg->ivsize) {
- crt->givencrypt = aead_null_givencrypt;
- crt->givdecrypt = aead_null_givdecrypt;
- }
- crt->base = __crypto_aead_cast(tfm);
- crt->ivsize = alg->ivsize;
- crt->authsize = alg->maxauthsize;
-
- return 0;
-}
-
#ifdef CONFIG_NET
static int crypto_nivaead_report(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_report_aead raead;
- struct aead_alg *aead = &alg->cra_aead;
+ struct old_aead_alg *aead = &alg->cra_aead;
strncpy(raead.type, "nivaead", sizeof(raead.type));
strncpy(raead.geniv, aead->geniv, sizeof(raead.geniv));
@@ -229,7 +363,7 @@ static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg)
__attribute__ ((unused));
static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg)
{
- struct aead_alg *aead = &alg->cra_aead;
+ struct old_aead_alg *aead = &alg->cra_aead;
seq_printf(m, "type : nivaead\n");
seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
@@ -241,43 +375,215 @@ static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg)
}
const struct crypto_type crypto_nivaead_type = {
- .ctxsize = crypto_aead_ctxsize,
- .init = crypto_init_nivaead_ops,
+ .extsize = crypto_alg_extsize,
+ .init_tfm = crypto_aead_init_tfm,
#ifdef CONFIG_PROC_FS
.show = crypto_nivaead_show,
#endif
.report = crypto_nivaead_report,
+ .maskclear = ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV),
+ .maskset = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .tfmsize = offsetof(struct crypto_aead, base),
};
EXPORT_SYMBOL_GPL(crypto_nivaead_type);
static int crypto_grab_nivaead(struct crypto_aead_spawn *spawn,
const char *name, u32 type, u32 mask)
{
- struct crypto_alg *alg;
+ spawn->base.frontend = &crypto_nivaead_type;
+ return crypto_grab_spawn(&spawn->base, name, type, mask);
+}
+
+static int aead_geniv_setkey(struct crypto_aead *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ struct aead_geniv_ctx *ctx = crypto_aead_ctx(tfm);
+
+ return crypto_aead_setkey(ctx->child, key, keylen);
+}
+
+static int aead_geniv_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ struct aead_geniv_ctx *ctx = crypto_aead_ctx(tfm);
+
+ return crypto_aead_setauthsize(ctx->child, authsize);
+}
+
+static void compat_encrypt_complete2(struct aead_request *req, int err)
+{
+ struct compat_request_ctx *rctx = aead_request_ctx(req);
+ struct aead_givcrypt_request *subreq = &rctx->subreq;
+ struct crypto_aead *geniv;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ if (err)
+ goto out;
+
+ geniv = crypto_aead_reqtfm(req);
+ scatterwalk_map_and_copy(subreq->giv, rctx->ivsg, 0,
+ crypto_aead_ivsize(geniv), 1);
+
+out:
+ kzfree(subreq->giv);
+}
+
+static void compat_encrypt_complete(struct crypto_async_request *base, int err)
+{
+ struct aead_request *req = base->data;
+
+ compat_encrypt_complete2(req, err);
+ aead_request_complete(req, err);
+}
+
+static int compat_encrypt(struct aead_request *req)
+{
+ struct crypto_aead *geniv = crypto_aead_reqtfm(req);
+ struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
+ struct compat_request_ctx *rctx = aead_request_ctx(req);
+ struct aead_givcrypt_request *subreq = &rctx->subreq;
+ unsigned int ivsize = crypto_aead_ivsize(geniv);
+ struct scatterlist *src, *dst;
+ crypto_completion_t compl;
+ void *data;
+ u8 *info;
+ __be64 seq;
int err;
- type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
- type |= CRYPTO_ALG_TYPE_AEAD;
- mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV;
+ if (req->cryptlen < ivsize)
+ return -EINVAL;
- alg = crypto_alg_mod_lookup(name, type, mask);
- if (IS_ERR(alg))
- return PTR_ERR(alg);
+ compl = req->base.complete;
+ data = req->base.data;
+
+ rctx->ivsg = scatterwalk_ffwd(rctx->ivbuf, req->dst, req->assoclen);
+ info = PageHighMem(sg_page(rctx->ivsg)) ? NULL : sg_virt(rctx->ivsg);
+
+ if (!info) {
+ info = kmalloc(ivsize, req->base.flags &
+ CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
+ GFP_ATOMIC);
+ if (!info)
+ return -ENOMEM;
+
+ compl = compat_encrypt_complete;
+ data = req;
+ }
+
+ memcpy(&seq, req->iv + ivsize - sizeof(seq), sizeof(seq));
+
+ src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen + ivsize);
+ dst = req->src == req->dst ?
+ src : scatterwalk_ffwd(rctx->dst, rctx->ivsg, ivsize);
+
+ aead_givcrypt_set_tfm(subreq, ctx->child);
+ aead_givcrypt_set_callback(subreq, req->base.flags,
+ req->base.complete, req->base.data);
+ aead_givcrypt_set_crypt(subreq, src, dst,
+ req->cryptlen - ivsize, req->iv);
+ aead_givcrypt_set_assoc(subreq, req->src, req->assoclen);
+ aead_givcrypt_set_giv(subreq, info, be64_to_cpu(seq));
+
+ err = crypto_aead_givencrypt(subreq);
+ if (unlikely(PageHighMem(sg_page(rctx->ivsg))))
+ compat_encrypt_complete2(req, err);
+ return err;
+}
+
+static int compat_decrypt(struct aead_request *req)
+{
+ struct crypto_aead *geniv = crypto_aead_reqtfm(req);
+ struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
+ struct compat_request_ctx *rctx = aead_request_ctx(req);
+ struct aead_request *subreq = &rctx->subreq.areq;
+ unsigned int ivsize = crypto_aead_ivsize(geniv);
+ struct scatterlist *src, *dst;
+ crypto_completion_t compl;
+ void *data;
+
+ if (req->cryptlen < ivsize)
+ return -EINVAL;
+
+ aead_request_set_tfm(subreq, ctx->child);
+
+ compl = req->base.complete;
+ data = req->base.data;
+
+ src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen + ivsize);
+ dst = req->src == req->dst ?
+ src : scatterwalk_ffwd(rctx->dst, req->dst,
+ req->assoclen + ivsize);
+
+ aead_request_set_callback(subreq, req->base.flags, compl, data);
+ aead_request_set_crypt(subreq, src, dst,
+ req->cryptlen - ivsize, req->iv);
+ aead_request_set_assoc(subreq, req->src, req->assoclen);
+
+ scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0);
+
+ return crypto_aead_decrypt(subreq);
+}
+
+static int compat_encrypt_first(struct aead_request *req)
+{
+ struct crypto_aead *geniv = crypto_aead_reqtfm(req);
+ struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
+ int err = 0;
+
+ spin_lock_bh(&ctx->lock);
+ if (geniv->encrypt != compat_encrypt_first)
+ goto unlock;
+
+ geniv->encrypt = compat_encrypt;
+
+unlock:
+ spin_unlock_bh(&ctx->lock);
+
+ if (err)
+ return err;
+
+ return compat_encrypt(req);
+}
+
+static int aead_geniv_init_compat(struct crypto_tfm *tfm)
+{
+ struct crypto_aead *geniv = __crypto_aead_cast(tfm);
+ struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
+ int err;
+
+ spin_lock_init(&ctx->lock);
+
+ crypto_aead_set_reqsize(geniv, sizeof(struct compat_request_ctx));
+
+ err = aead_geniv_init(tfm);
+
+ ctx->child = geniv->child;
+ geniv->child = geniv;
- err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask);
- crypto_mod_put(alg);
return err;
}
-struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl,
- struct rtattr **tb, u32 type,
- u32 mask)
+static void aead_geniv_exit_compat(struct crypto_tfm *tfm)
+{
+ struct crypto_aead *geniv = __crypto_aead_cast(tfm);
+ struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
+
+ crypto_free_aead(ctx->child);
+}
+
+struct aead_instance *aead_geniv_alloc(struct crypto_template *tmpl,
+ struct rtattr **tb, u32 type, u32 mask)
{
const char *name;
struct crypto_aead_spawn *spawn;
struct crypto_attr_type *algt;
- struct crypto_instance *inst;
- struct crypto_alg *alg;
+ struct aead_instance *inst;
+ struct aead_alg *alg;
+ unsigned int ivsize;
+ unsigned int maxauthsize;
int err;
algt = crypto_get_attr_type(tb);
@@ -296,20 +602,25 @@ struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl,
if (!inst)
return ERR_PTR(-ENOMEM);
- spawn = crypto_instance_ctx(inst);
+ spawn = aead_instance_ctx(inst);
/* Ignore async algorithms if necessary. */
mask |= crypto_requires_sync(algt->type, algt->mask);
- crypto_set_aead_spawn(spawn, inst);
- err = crypto_grab_nivaead(spawn, name, type, mask);
+ crypto_set_aead_spawn(spawn, aead_crypto_instance(inst));
+ err = (algt->mask & CRYPTO_ALG_GENIV) ?
+ crypto_grab_nivaead(spawn, name, type, mask) :
+ crypto_grab_aead(spawn, name, type, mask);
if (err)
goto err_free_inst;
- alg = crypto_aead_spawn_alg(spawn);
+ alg = crypto_spawn_aead_alg(spawn);
+
+ ivsize = crypto_aead_alg_ivsize(alg);
+ maxauthsize = crypto_aead_alg_maxauthsize(alg);
err = -EINVAL;
- if (!alg->cra_aead.ivsize)
+ if (ivsize < sizeof(u64))
goto err_drop_alg;
/*
@@ -318,39 +629,64 @@ struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl,
* template name and double-check the IV generator.
*/
if (algt->mask & CRYPTO_ALG_GENIV) {
- if (strcmp(tmpl->name, alg->cra_aead.geniv))
+ if (!alg->base.cra_aead.encrypt)
+ goto err_drop_alg;
+ if (strcmp(tmpl->name, alg->base.cra_aead.geniv))
goto err_drop_alg;
- memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
- memcpy(inst->alg.cra_driver_name, alg->cra_driver_name,
+ memcpy(inst->alg.base.cra_name, alg->base.cra_name,
CRYPTO_MAX_ALG_NAME);
- } else {
- err = -ENAMETOOLONG;
- if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
- "%s(%s)", tmpl->name, alg->cra_name) >=
- CRYPTO_MAX_ALG_NAME)
- goto err_drop_alg;
- if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
- "%s(%s)", tmpl->name, alg->cra_driver_name) >=
- CRYPTO_MAX_ALG_NAME)
- goto err_drop_alg;
+ memcpy(inst->alg.base.cra_driver_name,
+ alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME);
+
+ inst->alg.base.cra_flags = CRYPTO_ALG_TYPE_AEAD |
+ CRYPTO_ALG_GENIV;
+ inst->alg.base.cra_flags |= alg->base.cra_flags &
+ CRYPTO_ALG_ASYNC;
+ inst->alg.base.cra_priority = alg->base.cra_priority;
+ inst->alg.base.cra_blocksize = alg->base.cra_blocksize;
+ inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
+ inst->alg.base.cra_type = &crypto_aead_type;
+
+ inst->alg.base.cra_aead.ivsize = ivsize;
+ inst->alg.base.cra_aead.maxauthsize = maxauthsize;
+
+ inst->alg.base.cra_aead.setkey = alg->base.cra_aead.setkey;
+ inst->alg.base.cra_aead.setauthsize =
+ alg->base.cra_aead.setauthsize;
+ inst->alg.base.cra_aead.encrypt = alg->base.cra_aead.encrypt;
+ inst->alg.base.cra_aead.decrypt = alg->base.cra_aead.decrypt;
+
+ goto out;
}
- inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV;
- inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
- inst->alg.cra_priority = alg->cra_priority;
- inst->alg.cra_blocksize = alg->cra_blocksize;
- inst->alg.cra_alignmask = alg->cra_alignmask;
- inst->alg.cra_type = &crypto_aead_type;
+ err = -ENAMETOOLONG;
+ if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
+ "%s(%s)", tmpl->name, alg->base.cra_name) >=
+ CRYPTO_MAX_ALG_NAME)
+ goto err_drop_alg;
+ if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+ "%s(%s)", tmpl->name, alg->base.cra_driver_name) >=
+ CRYPTO_MAX_ALG_NAME)
+ goto err_drop_alg;
+
+ inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC;
+ inst->alg.base.cra_priority = alg->base.cra_priority;
+ inst->alg.base.cra_blocksize = alg->base.cra_blocksize;
+ inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
+ inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx);
+
+ inst->alg.setkey = aead_geniv_setkey;
+ inst->alg.setauthsize = aead_geniv_setauthsize;
- inst->alg.cra_aead.ivsize = alg->cra_aead.ivsize;
- inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize;
- inst->alg.cra_aead.geniv = alg->cra_aead.geniv;
+ inst->alg.ivsize = ivsize;
+ inst->alg.maxauthsize = maxauthsize;
- inst->alg.cra_aead.setkey = alg->cra_aead.setkey;
- inst->alg.cra_aead.setauthsize = alg->cra_aead.setauthsize;
- inst->alg.cra_aead.encrypt = alg->cra_aead.encrypt;
- inst->alg.cra_aead.decrypt = alg->cra_aead.decrypt;
+ inst->alg.encrypt = compat_encrypt_first;
+ inst->alg.decrypt = compat_decrypt;
+
+ inst->alg.base.cra_init = aead_geniv_init_compat;
+ inst->alg.base.cra_exit = aead_geniv_exit_compat;
out:
return inst;
@@ -364,9 +700,9 @@ err_free_inst:
}
EXPORT_SYMBOL_GPL(aead_geniv_alloc);
-void aead_geniv_free(struct crypto_instance *inst)
+void aead_geniv_free(struct aead_instance *inst)
{
- crypto_drop_aead(crypto_instance_ctx(inst));
+ crypto_drop_aead(aead_instance_ctx(inst));
kfree(inst);
}
EXPORT_SYMBOL_GPL(aead_geniv_free);
@@ -374,14 +710,17 @@ EXPORT_SYMBOL_GPL(aead_geniv_free);
int aead_geniv_init(struct crypto_tfm *tfm)
{
struct crypto_instance *inst = (void *)tfm->__crt_alg;
+ struct crypto_aead *child;
struct crypto_aead *aead;
- aead = crypto_spawn_aead(crypto_instance_ctx(inst));
- if (IS_ERR(aead))
- return PTR_ERR(aead);
+ aead = __crypto_aead_cast(tfm);
+
+ child = crypto_spawn_aead(crypto_instance_ctx(inst));
+ if (IS_ERR(child))
+ return PTR_ERR(child);
- tfm->crt_aead.base = aead;
- tfm->crt_aead.reqsize += crypto_aead_reqsize(aead);
+ aead->child = child;
+ aead->reqsize += crypto_aead_reqsize(child);
return 0;
}
@@ -389,7 +728,7 @@ EXPORT_SYMBOL_GPL(aead_geniv_init);
void aead_geniv_exit(struct crypto_tfm *tfm)
{
- crypto_free_aead(tfm->crt_aead.base);
+ crypto_free_aead(__crypto_aead_cast(tfm)->child);
}
EXPORT_SYMBOL_GPL(aead_geniv_exit);
@@ -443,6 +782,13 @@ static int crypto_nivaead_default(struct crypto_alg *alg, u32 type, u32 mask)
if (!tmpl)
goto kill_larval;
+ if (tmpl->create) {
+ err = tmpl->create(tmpl, tb);
+ if (err)
+ goto put_tmpl;
+ goto ok;
+ }
+
inst = tmpl->alloc(tb);
err = PTR_ERR(inst);
if (IS_ERR(inst))
@@ -454,6 +800,7 @@ static int crypto_nivaead_default(struct crypto_alg *alg, u32 type, u32 mask)
goto put_tmpl;
}
+ok:
/* Redo the lookup to use the instance we just registered. */
err = -EAGAIN;
@@ -489,7 +836,7 @@ struct crypto_alg *crypto_lookup_aead(const char *name, u32 type, u32 mask)
return alg;
if (alg->cra_type == &crypto_aead_type) {
- if ((alg->cra_flags ^ type ^ ~mask) & CRYPTO_ALG_TESTED) {
+ if (~alg->cra_flags & (type ^ ~mask) & CRYPTO_ALG_TESTED) {
crypto_mod_put(alg);
alg = ERR_PTR(-ENOENT);
}
@@ -505,62 +852,91 @@ EXPORT_SYMBOL_GPL(crypto_lookup_aead);
int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name,
u32 type, u32 mask)
{
- struct crypto_alg *alg;
- int err;
+ spawn->base.frontend = &crypto_aead_type;
+ return crypto_grab_spawn(&spawn->base, name, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_grab_aead);
- type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
- type |= CRYPTO_ALG_TYPE_AEAD;
- mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
- mask |= CRYPTO_ALG_TYPE_MASK;
+struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask)
+{
+ return crypto_alloc_tfm(alg_name, &crypto_aead_type, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_aead);
- alg = crypto_lookup_aead(name, type, mask);
- if (IS_ERR(alg))
- return PTR_ERR(alg);
+static int aead_prepare_alg(struct aead_alg *alg)
+{
+ struct crypto_alg *base = &alg->base;
- err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask);
- crypto_mod_put(alg);
- return err;
+ if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8)
+ return -EINVAL;
+
+ base->cra_type = &crypto_new_aead_type;
+ base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
+ base->cra_flags |= CRYPTO_ALG_TYPE_AEAD;
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(crypto_grab_aead);
-struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask)
+int crypto_register_aead(struct aead_alg *alg)
{
- struct crypto_tfm *tfm;
+ struct crypto_alg *base = &alg->base;
int err;
- type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
- type |= CRYPTO_ALG_TYPE_AEAD;
- mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
- mask |= CRYPTO_ALG_TYPE_MASK;
+ err = aead_prepare_alg(alg);
+ if (err)
+ return err;
- for (;;) {
- struct crypto_alg *alg;
+ return crypto_register_alg(base);
+}
+EXPORT_SYMBOL_GPL(crypto_register_aead);
- alg = crypto_lookup_aead(alg_name, type, mask);
- if (IS_ERR(alg)) {
- err = PTR_ERR(alg);
- goto err;
- }
+void crypto_unregister_aead(struct aead_alg *alg)
+{
+ crypto_unregister_alg(&alg->base);
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_aead);
- tfm = __crypto_alloc_tfm(alg, type, mask);
- if (!IS_ERR(tfm))
- return __crypto_aead_cast(tfm);
+int crypto_register_aeads(struct aead_alg *algs, int count)
+{
+ int i, ret;
- crypto_mod_put(alg);
- err = PTR_ERR(tfm);
+ for (i = 0; i < count; i++) {
+ ret = crypto_register_aead(&algs[i]);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
err:
- if (err != -EAGAIN)
- break;
- if (signal_pending(current)) {
- err = -EINTR;
- break;
- }
- }
+ for (--i; i >= 0; --i)
+ crypto_unregister_aead(&algs[i]);
- return ERR_PTR(err);
+ return ret;
}
-EXPORT_SYMBOL_GPL(crypto_alloc_aead);
+EXPORT_SYMBOL_GPL(crypto_register_aeads);
+
+void crypto_unregister_aeads(struct aead_alg *algs, int count)
+{
+ int i;
+
+ for (i = count - 1; i >= 0; --i)
+ crypto_unregister_aead(&algs[i]);
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_aeads);
+
+int aead_register_instance(struct crypto_template *tmpl,
+ struct aead_instance *inst)
+{
+ int err;
+
+ err = aead_prepare_alg(&inst->alg);
+ if (err)
+ return err;
+
+ return crypto_register_instance(tmpl, aead_crypto_instance(inst));
+}
+EXPORT_SYMBOL_GPL(aead_register_instance);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index f22cc56fd1b3..a8e7aa3e257b 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -127,6 +127,7 @@ EXPORT_SYMBOL_GPL(af_alg_release);
static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
+ const u32 forbidden = CRYPTO_ALG_INTERNAL;
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);
struct sockaddr_alg *sa = (void *)uaddr;
@@ -151,7 +152,9 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if (IS_ERR(type))
return PTR_ERR(type);
- private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask);
+ private = type->bind(sa->salg_name,
+ sa->salg_feat & ~forbidden,
+ sa->salg_mask & ~forbidden);
if (IS_ERR(private)) {
module_put(type->owner);
return PTR_ERR(private);
@@ -244,7 +247,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock)
if (!type)
goto unlock;
- sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto);
+ sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto, 0);
err = -ENOMEM;
if (!sk2)
goto unlock;
@@ -324,7 +327,7 @@ static int alg_create(struct net *net, struct socket *sock, int protocol,
return -EPROTONOSUPPORT;
err = -ENOMEM;
- sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto);
+ sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto, kern);
if (!sk)
goto out;
diff --git a/crypto/akcipher.c b/crypto/akcipher.c
new file mode 100644
index 000000000000..528ae6aa9bff
--- /dev/null
+++ b/crypto/akcipher.c
@@ -0,0 +1,117 @@
+/*
+ * Public Key Encryption
+ *
+ * Copyright (c) 2015, Intel Corporation
+ * Authors: Tadeusz Struk <tadeusz.struk@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; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <linux/cryptouser.h>
+#include <net/netlink.h>
+#include <crypto/akcipher.h>
+#include <crypto/public_key.h>
+#include "internal.h"
+
+#ifdef CONFIG_NET
+static int crypto_akcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+ struct crypto_report_akcipher rakcipher;
+
+ strncpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
+
+ if (nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER,
+ sizeof(struct crypto_report_akcipher), &rakcipher))
+ goto nla_put_failure;
+ return 0;
+
+nla_put_failure:
+ return -EMSGSIZE;
+}
+#else
+static int crypto_akcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
+{
+ return -ENOSYS;
+}
+#endif
+
+static void crypto_akcipher_show(struct seq_file *m, struct crypto_alg *alg)
+ __attribute__ ((unused));
+
+static void crypto_akcipher_show(struct seq_file *m, struct crypto_alg *alg)
+{
+ seq_puts(m, "type : akcipher\n");
+}
+
+static void crypto_akcipher_exit_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_akcipher *akcipher = __crypto_akcipher_tfm(tfm);
+ struct akcipher_alg *alg = crypto_akcipher_alg(akcipher);
+
+ alg->exit(akcipher);
+}
+
+static int crypto_akcipher_init_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_akcipher *akcipher = __crypto_akcipher_tfm(tfm);
+ struct akcipher_alg *alg = crypto_akcipher_alg(akcipher);
+
+ if (alg->exit)
+ akcipher->base.exit = crypto_akcipher_exit_tfm;
+
+ if (alg->init)
+ return alg->init(akcipher);
+
+ return 0;
+}
+
+static const struct crypto_type crypto_akcipher_type = {
+ .extsize = crypto_alg_extsize,
+ .init_tfm = crypto_akcipher_init_tfm,
+#ifdef CONFIG_PROC_FS
+ .show = crypto_akcipher_show,
+#endif
+ .report = crypto_akcipher_report,
+ .maskclear = ~CRYPTO_ALG_TYPE_MASK,
+ .maskset = CRYPTO_ALG_TYPE_MASK,
+ .type = CRYPTO_ALG_TYPE_AKCIPHER,
+ .tfmsize = offsetof(struct crypto_akcipher, base),
+};
+
+struct crypto_akcipher *crypto_alloc_akcipher(const char *alg_name, u32 type,
+ u32 mask)
+{
+ return crypto_alloc_tfm(alg_name, &crypto_akcipher_type, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_akcipher);
+
+int crypto_register_akcipher(struct akcipher_alg *alg)
+{
+ struct crypto_alg *base = &alg->base;
+
+ base->cra_type = &crypto_akcipher_type;
+ base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
+ base->cra_flags |= CRYPTO_ALG_TYPE_AKCIPHER;
+ return crypto_register_alg(base);
+}
+EXPORT_SYMBOL_GPL(crypto_register_akcipher);
+
+void crypto_unregister_akcipher(struct akcipher_alg *alg)
+{
+ crypto_unregister_alg(&alg->base);
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_akcipher);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic public key cipher type");
diff --git a/crypto/algapi.c b/crypto/algapi.c
index d2627a3d4ed8..3c079b7f23f6 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -12,6 +12,7 @@
#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/fips.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -43,12 +44,9 @@ static inline int crypto_set_driver_name(struct crypto_alg *alg)
static inline void crypto_check_module_sig(struct module *mod)
{
-#ifdef CONFIG_CRYPTO_FIPS
- if (fips_enabled && mod && !mod->sig_ok)
+ if (fips_enabled && mod && !module_sig_ok(mod))
panic("Module %s signature verification failed in FIPS mode\n",
- mod->name);
-#endif
- return;
+ module_name(mod));
}
static int crypto_check_alg(struct crypto_alg *alg)
@@ -614,6 +612,22 @@ out:
}
EXPORT_SYMBOL_GPL(crypto_init_spawn2);
+int crypto_grab_spawn(struct crypto_spawn *spawn, const char *name,
+ u32 type, u32 mask)
+{
+ struct crypto_alg *alg;
+ int err;
+
+ alg = crypto_find_alg(name, spawn->frontend, type, mask);
+ if (IS_ERR(alg))
+ return PTR_ERR(alg);
+
+ err = crypto_init_spawn(spawn, alg, spawn->inst, mask);
+ crypto_mod_put(alg);
+ return err;
+}
+EXPORT_SYMBOL_GPL(crypto_grab_spawn);
+
void crypto_drop_spawn(struct crypto_spawn *spawn)
{
if (!spawn->alg)
@@ -964,6 +978,13 @@ void crypto_xor(u8 *dst, const u8 *src, unsigned int size)
}
EXPORT_SYMBOL_GPL(crypto_xor);
+unsigned int crypto_alg_extsize(struct crypto_alg *alg)
+{
+ return alg->cra_ctxsize +
+ (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
+}
+EXPORT_SYMBOL_GPL(crypto_alg_extsize);
+
static int __init crypto_algapi_init(void)
{
crypto_init_proc();
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index 69abada22373..e0408a480d2f 100644
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -13,6 +13,7 @@
* any later version.
*/
+#include <crypto/aead.h>
#include <crypto/scatterwalk.h>
#include <crypto/if_alg.h>
#include <linux/init.h>
@@ -71,7 +72,7 @@ static inline bool aead_sufficient_data(struct aead_ctx *ctx)
{
unsigned as = crypto_aead_authsize(crypto_aead_reqtfm(&ctx->aead_req));
- return (ctx->used >= (ctx->aead_assoclen + (ctx->enc ? 0 : as)));
+ return ctx->used >= ctx->aead_assoclen + as;
}
static void aead_put_sgl(struct sock *sk)
@@ -352,12 +353,8 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);
struct aead_ctx *ctx = ask->private;
- unsigned bs = crypto_aead_blocksize(crypto_aead_reqtfm(&ctx->aead_req));
unsigned as = crypto_aead_authsize(crypto_aead_reqtfm(&ctx->aead_req));
struct aead_sg_list *sgl = &ctx->tsgl;
- struct scatterlist *sg = NULL;
- struct scatterlist assoc[ALG_MAX_PAGES];
- size_t assoclen = 0;
unsigned int i = 0;
int err = -EINVAL;
unsigned long used = 0;
@@ -406,23 +403,13 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
if (!aead_sufficient_data(ctx))
goto unlock;
+ outlen = used;
+
/*
* The cipher operation input data is reduced by the associated data
* length as this data is processed separately later on.
*/
- used -= ctx->aead_assoclen;
-
- if (ctx->enc) {
- /* round up output buffer to multiple of block size */
- outlen = ((used + bs - 1) / bs * bs);
- /* add the size needed for the auth tag to be created */
- outlen += as;
- } else {
- /* output data size is input without the authentication tag */
- outlen = used - as;
- /* round up output buffer to multiple of block size */
- outlen = ((outlen + bs - 1) / bs * bs);
- }
+ used -= ctx->aead_assoclen + (ctx->enc ? as : 0);
/* convert iovecs of output buffers into scatterlists */
while (iov_iter_count(&msg->msg_iter)) {
@@ -451,47 +438,11 @@ static int aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored,
if (usedpages < outlen)
goto unlock;
- sg_init_table(assoc, ALG_MAX_PAGES);
- assoclen = ctx->aead_assoclen;
- /*
- * Split scatterlist into two: first part becomes AD, second part
- * is plaintext / ciphertext. The first part is assigned to assoc
- * scatterlist. When this loop finishes, sg points to the start of the
- * plaintext / ciphertext.
- */
- for (i = 0; i < ctx->tsgl.cur; i++) {
- sg = sgl->sg + i;
- if (sg->length <= assoclen) {
- /* AD is larger than one page */
- sg_set_page(assoc + i, sg_page(sg),
- sg->length, sg->offset);
- assoclen -= sg->length;
- if (i >= ctx->tsgl.cur)
- goto unlock;
- } else if (!assoclen) {
- /* current page is to start of plaintext / ciphertext */
- if (i)
- /* AD terminates at page boundary */
- sg_mark_end(assoc + i - 1);
- else
- /* AD size is zero */
- sg_mark_end(assoc);
- break;
- } else {
- /* AD does not terminate at page boundary */
- sg_set_page(assoc + i, sg_page(sg),
- assoclen, sg->offset);
- sg_mark_end(assoc + i);
- /* plaintext / ciphertext starts after AD */
- sg->length -= assoclen;
- sg->offset += assoclen;
- break;
- }
- }
+ sg_mark_end(sgl->sg + sgl->cur - 1);
- aead_request_set_assoc(&ctx->aead_req, assoc, ctx->aead_assoclen);
- aead_request_set_crypt(&ctx->aead_req, sg, ctx->rsgl[0].sg, used,
- ctx->iv);
+ aead_request_set_crypt(&ctx->aead_req, sgl->sg, ctx->rsgl[0].sg,
+ used, ctx->iv);
+ aead_request_set_ad(&ctx->aead_req, ctx->aead_assoclen);
err = af_alg_wait_for_completion(ctx->enc ?
crypto_aead_encrypt(&ctx->aead_req) :
@@ -563,7 +514,8 @@ static struct proto_ops algif_aead_ops = {
static void *aead_bind(const char *name, u32 type, u32 mask)
{
- return crypto_alloc_aead(name, type, mask);
+ return crypto_alloc_aead(name, type | CRYPTO_ALG_AEAD_NEW,
+ mask | CRYPTO_ALG_AEAD_NEW);
}
static void aead_release(void *private)
diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c
index 8109aaad2726..150c2b6480ed 100644
--- a/crypto/algif_rng.c
+++ b/crypto/algif_rng.c
@@ -164,7 +164,7 @@ static int rng_setkey(void *private, const u8 *seed, unsigned int seedlen)
* Check whether seedlen is of sufficient size is done in RNG
* implementations.
*/
- return crypto_rng_reset(private, (u8 *)seed, seedlen);
+ return crypto_rng_reset(private, seed, seedlen);
}
static const struct af_alg_type algif_type_rng = {
diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c
index 765fe7609348..eff337ce9003 100644
--- a/crypto/ansi_cprng.c
+++ b/crypto/ansi_cprng.c
@@ -20,8 +20,6 @@
#include <linux/moduleparam.h>
#include <linux/string.h>
-#include "internal.h"
-
#define DEFAULT_PRNG_KEY "0123456789abcdef"
#define DEFAULT_PRNG_KSZ 16
#define DEFAULT_BLK_SZ 16
@@ -281,11 +279,11 @@ static void free_prng_context(struct prng_context *ctx)
}
static int reset_prng_context(struct prng_context *ctx,
- unsigned char *key, size_t klen,
- unsigned char *V, unsigned char *DT)
+ const unsigned char *key, size_t klen,
+ const unsigned char *V, const unsigned char *DT)
{
int ret;
- unsigned char *prng_key;
+ const unsigned char *prng_key;
spin_lock_bh(&ctx->prng_lock);
ctx->flags |= PRNG_NEED_RESET;
@@ -353,8 +351,9 @@ static void cprng_exit(struct crypto_tfm *tfm)
free_prng_context(crypto_tfm_ctx(tfm));
}
-static int cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
- unsigned int dlen)
+static int cprng_get_random(struct crypto_rng *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *rdata, unsigned int dlen)
{
struct prng_context *prng = crypto_rng_ctx(tfm);
@@ -367,11 +366,12 @@ static int cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
* V and KEY are required during reset, and DT is optional, detected
* as being present by testing the length of the seed
*/
-static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+static int cprng_reset(struct crypto_rng *tfm,
+ const u8 *seed, unsigned int slen)
{
struct prng_context *prng = crypto_rng_ctx(tfm);
- u8 *key = seed + DEFAULT_BLK_SZ;
- u8 *dt = NULL;
+ const u8 *key = seed + DEFAULT_BLK_SZ;
+ const u8 *dt = NULL;
if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ)
return -EINVAL;
@@ -387,18 +387,20 @@ static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
}
#ifdef CONFIG_CRYPTO_FIPS
-static int fips_cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
- unsigned int dlen)
+static int fips_cprng_get_random(struct crypto_rng *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *rdata, unsigned int dlen)
{
struct prng_context *prng = crypto_rng_ctx(tfm);
return get_prng_bytes(rdata, dlen, prng, 1);
}
-static int fips_cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+static int fips_cprng_reset(struct crypto_rng *tfm,
+ const u8 *seed, unsigned int slen)
{
u8 rdata[DEFAULT_BLK_SZ];
- u8 *key = seed + DEFAULT_BLK_SZ;
+ const u8 *key = seed + DEFAULT_BLK_SZ;
int rc;
struct prng_context *prng = crypto_rng_ctx(tfm);
@@ -424,40 +426,32 @@ out:
}
#endif
-static struct crypto_alg rng_algs[] = { {
- .cra_name = "stdrng",
- .cra_driver_name = "ansi_cprng",
- .cra_priority = 100,
- .cra_flags = CRYPTO_ALG_TYPE_RNG,
- .cra_ctxsize = sizeof(struct prng_context),
- .cra_type = &crypto_rng_type,
- .cra_module = THIS_MODULE,
- .cra_init = cprng_init,
- .cra_exit = cprng_exit,
- .cra_u = {
- .rng = {
- .rng_make_random = cprng_get_random,
- .rng_reset = cprng_reset,
- .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ,
- }
+static struct rng_alg rng_algs[] = { {
+ .generate = cprng_get_random,
+ .seed = cprng_reset,
+ .seedsize = DEFAULT_PRNG_KSZ + 2 * DEFAULT_BLK_SZ,
+ .base = {
+ .cra_name = "stdrng",
+ .cra_driver_name = "ansi_cprng",
+ .cra_priority = 100,
+ .cra_ctxsize = sizeof(struct prng_context),
+ .cra_module = THIS_MODULE,
+ .cra_init = cprng_init,
+ .cra_exit = cprng_exit,
}
#ifdef CONFIG_CRYPTO_FIPS
}, {
- .cra_name = "fips(ansi_cprng)",
- .cra_driver_name = "fips_ansi_cprng",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_RNG,
- .cra_ctxsize = sizeof(struct prng_context),
- .cra_type = &crypto_rng_type,
- .cra_module = THIS_MODULE,
- .cra_init = cprng_init,
- .cra_exit = cprng_exit,
- .cra_u = {
- .rng = {
- .rng_make_random = fips_cprng_get_random,
- .rng_reset = fips_cprng_reset,
- .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ,
- }
+ .generate = fips_cprng_get_random,
+ .seed = fips_cprng_reset,
+ .seedsize = DEFAULT_PRNG_KSZ + 2 * DEFAULT_BLK_SZ,
+ .base = {
+ .cra_name = "fips(ansi_cprng)",
+ .cra_driver_name = "fips_ansi_cprng",
+ .cra_priority = 300,
+ .cra_ctxsize = sizeof(struct prng_context),
+ .cra_module = THIS_MODULE,
+ .cra_init = cprng_init,
+ .cra_exit = cprng_exit,
}
#endif
} };
@@ -465,12 +459,12 @@ static struct crypto_alg rng_algs[] = { {
/* Module initalization */
static int __init prng_mod_init(void)
{
- return crypto_register_algs(rng_algs, ARRAY_SIZE(rng_algs));
+ return crypto_register_rngs(rng_algs, ARRAY_SIZE(rng_algs));
}
static void __exit prng_mod_fini(void)
{
- crypto_unregister_algs(rng_algs, ARRAY_SIZE(rng_algs));
+ crypto_unregister_rngs(rng_algs, ARRAY_SIZE(rng_algs));
}
MODULE_LICENSE("GPL");
diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c
index 459cf97a75e2..508b57b77474 100644
--- a/crypto/asymmetric_keys/rsa.c
+++ b/crypto/asymmetric_keys/rsa.c
@@ -120,7 +120,7 @@ static int RSAVP1(const struct public_key *key, MPI s, MPI *_m)
/*
* Integer to Octet String conversion [RFC3447 sec 4.1]
*/
-static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
+static int RSA_I2OSP(MPI x, size_t xLen, u8 **pX)
{
unsigned X_size, x_size;
int X_sign;
@@ -147,7 +147,7 @@ static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
return -EBADMSG;
}
- *_X = X;
+ *pX = X;
return 0;
}
diff --git a/crypto/authenc.c b/crypto/authenc.c
index 78fb16cab13f..3e852299afb4 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -10,7 +10,7 @@
*
*/
-#include <crypto/aead.h>
+#include <crypto/internal/aead.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/skcipher.h>
#include <crypto/authenc.h>
@@ -570,13 +570,14 @@ static int crypto_authenc_init_tfm(struct crypto_tfm *tfm)
crypto_ahash_alignmask(auth) + 1) +
crypto_ablkcipher_ivsize(enc);
- tfm->crt_aead.reqsize = sizeof(struct authenc_request_ctx) +
- ctx->reqoff +
- max_t(unsigned int,
- crypto_ahash_reqsize(auth) +
- sizeof(struct ahash_request),
- sizeof(struct skcipher_givcrypt_request) +
- crypto_ablkcipher_reqsize(enc));
+ crypto_aead_set_reqsize(__crypto_aead_cast(tfm),
+ sizeof(struct authenc_request_ctx) +
+ ctx->reqoff +
+ max_t(unsigned int,
+ crypto_ahash_reqsize(auth) +
+ sizeof(struct ahash_request),
+ sizeof(struct skcipher_givcrypt_request) +
+ crypto_ablkcipher_reqsize(enc)));
return 0;
diff --git a/crypto/authencesn.c b/crypto/authencesn.c
index 024bff2344fc..a3da6770bc9e 100644
--- a/crypto/authencesn.c
+++ b/crypto/authencesn.c
@@ -12,7 +12,7 @@
*
*/
-#include <crypto/aead.h>
+#include <crypto/internal/aead.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/skcipher.h>
#include <crypto/authenc.h>
@@ -662,13 +662,14 @@ static int crypto_authenc_esn_init_tfm(struct crypto_tfm *tfm)
crypto_ahash_alignmask(auth) + 1) +
crypto_ablkcipher_ivsize(enc);
- tfm->crt_aead.reqsize = sizeof(struct authenc_esn_request_ctx) +
- ctx->reqoff +
- max_t(unsigned int,
- crypto_ahash_reqsize(auth) +
- sizeof(struct ahash_request),
- sizeof(struct skcipher_givcrypt_request) +
- crypto_ablkcipher_reqsize(enc));
+ crypto_aead_set_reqsize(__crypto_aead_cast(tfm),
+ sizeof(struct authenc_esn_request_ctx) +
+ ctx->reqoff +
+ max_t(unsigned int,
+ crypto_ahash_reqsize(auth) +
+ sizeof(struct ahash_request),
+ sizeof(struct skcipher_givcrypt_request) +
+ crypto_ablkcipher_reqsize(enc)));
return 0;
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index 0122bec38564..11b981492031 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -14,6 +14,7 @@
*
*/
+#include <crypto/aead.h>
#include <crypto/internal/skcipher.h>
#include <crypto/scatterwalk.h>
#include <linux/errno.h>
diff --git a/crypto/ccm.c b/crypto/ccm.c
index 003bbbd21a2b..a4d1a5eda18b 100644
--- a/crypto/ccm.c
+++ b/crypto/ccm.c
@@ -453,9 +453,9 @@ static int crypto_ccm_init_tfm(struct crypto_tfm *tfm)
align = crypto_tfm_alg_alignmask(tfm);
align &= ~(crypto_tfm_ctx_alignment() - 1);
- tfm->crt_aead.reqsize = align +
- sizeof(struct crypto_ccm_req_priv_ctx) +
- crypto_ablkcipher_reqsize(ctr);
+ crypto_aead_set_reqsize(__crypto_aead_cast(tfm),
+ align + sizeof(struct crypto_ccm_req_priv_ctx) +
+ crypto_ablkcipher_reqsize(ctr));
return 0;
@@ -729,10 +729,10 @@ static int crypto_rfc4309_init_tfm(struct crypto_tfm *tfm)
align = crypto_aead_alignmask(aead);
align &= ~(crypto_tfm_ctx_alignment() - 1);
- tfm->crt_aead.reqsize = sizeof(struct aead_request) +
- ALIGN(crypto_aead_reqsize(aead),
- crypto_tfm_ctx_alignment()) +
- align + 16;
+ crypto_aead_set_reqsize(__crypto_aead_cast(tfm),
+ sizeof(struct aead_request) +
+ ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) +
+ align + 16);
return 0;
}
diff --git a/crypto/chacha20_generic.c b/crypto/chacha20_generic.c
new file mode 100644
index 000000000000..fa42e708aa96
--- /dev/null
+++ b/crypto/chacha20_generic.c
@@ -0,0 +1,216 @@
+/*
+ * ChaCha20 256-bit cipher algorithm, RFC7539
+ *
+ * Copyright (C) 2015 Martin Willi
+ *
+ * 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 <crypto/algapi.h>
+#include <linux/crypto.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#define CHACHA20_NONCE_SIZE 16
+#define CHACHA20_KEY_SIZE 32
+#define CHACHA20_BLOCK_SIZE 64
+
+struct chacha20_ctx {
+ u32 key[8];
+};
+
+static inline u32 rotl32(u32 v, u8 n)
+{
+ return (v << n) | (v >> (sizeof(v) * 8 - n));
+}
+
+static inline u32 le32_to_cpuvp(const void *p)
+{
+ return le32_to_cpup(p);
+}
+
+static void chacha20_block(u32 *state, void *stream)
+{
+ u32 x[16], *out = stream;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(x); i++)
+ x[i] = state[i];
+
+ for (i = 0; i < 20; i += 2) {
+ x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 16);
+ x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 16);
+ x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 16);
+ x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 16);
+
+ x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 12);
+ x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 12);
+ x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 12);
+ x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 12);
+
+ x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 8);
+ x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 8);
+ x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 8);
+ x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 8);
+
+ x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 7);
+ x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 7);
+ x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 7);
+ x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 7);
+
+ x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 16);
+ x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 16);
+ x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 16);
+ x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 16);
+
+ x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 12);
+ x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 12);
+ x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 12);
+ x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 12);
+
+ x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 8);
+ x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 8);
+ x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 8);
+ x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 8);
+
+ x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 7);
+ x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 7);
+ x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 7);
+ x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 7);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(x); i++)
+ out[i] = cpu_to_le32(x[i] + state[i]);
+
+ state[12]++;
+}
+
+static void chacha20_docrypt(u32 *state, u8 *dst, const u8 *src,
+ unsigned int bytes)
+{
+ u8 stream[CHACHA20_BLOCK_SIZE];
+
+ if (dst != src)
+ memcpy(dst, src, bytes);
+
+ while (bytes >= CHACHA20_BLOCK_SIZE) {
+ chacha20_block(state, stream);
+ crypto_xor(dst, stream, CHACHA20_BLOCK_SIZE);
+ bytes -= CHACHA20_BLOCK_SIZE;
+ dst += CHACHA20_BLOCK_SIZE;
+ }
+ if (bytes) {
+ chacha20_block(state, stream);
+ crypto_xor(dst, stream, bytes);
+ }
+}
+
+static void chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv)
+{
+ static const char constant[16] = "expand 32-byte k";
+
+ state[0] = le32_to_cpuvp(constant + 0);
+ state[1] = le32_to_cpuvp(constant + 4);
+ state[2] = le32_to_cpuvp(constant + 8);
+ state[3] = le32_to_cpuvp(constant + 12);
+ state[4] = ctx->key[0];
+ state[5] = ctx->key[1];
+ state[6] = ctx->key[2];
+ state[7] = ctx->key[3];
+ state[8] = ctx->key[4];
+ state[9] = ctx->key[5];
+ state[10] = ctx->key[6];
+ state[11] = ctx->key[7];
+ state[12] = le32_to_cpuvp(iv + 0);
+ state[13] = le32_to_cpuvp(iv + 4);
+ state[14] = le32_to_cpuvp(iv + 8);
+ state[15] = le32_to_cpuvp(iv + 12);
+}
+
+static int chacha20_setkey(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int keysize)
+{
+ struct chacha20_ctx *ctx = crypto_tfm_ctx(tfm);
+ int i;
+
+ if (keysize != CHACHA20_KEY_SIZE)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(ctx->key); i++)
+ ctx->key[i] = le32_to_cpuvp(key + i * sizeof(u32));
+
+ return 0;
+}
+
+static int chacha20_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
+{
+ struct blkcipher_walk walk;
+ u32 state[16];
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt_block(desc, &walk, CHACHA20_BLOCK_SIZE);
+
+ chacha20_init(state, crypto_blkcipher_ctx(desc->tfm), walk.iv);
+
+ while (walk.nbytes >= CHACHA20_BLOCK_SIZE) {
+ chacha20_docrypt(state, walk.dst.virt.addr, walk.src.virt.addr,
+ rounddown(walk.nbytes, CHACHA20_BLOCK_SIZE));
+ err = blkcipher_walk_done(desc, &walk,
+ walk.nbytes % CHACHA20_BLOCK_SIZE);
+ }
+
+ if (walk.nbytes) {
+ chacha20_docrypt(state, walk.dst.virt.addr, walk.src.virt.addr,
+ walk.nbytes);
+ err = blkcipher_walk_done(desc, &walk, 0);
+ }
+
+ return err;
+}
+
+static struct crypto_alg alg = {
+ .cra_name = "chacha20",
+ .cra_driver_name = "chacha20-generic",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = 1,
+ .cra_type = &crypto_blkcipher_type,
+ .cra_ctxsize = sizeof(struct chacha20_ctx),
+ .cra_alignmask = sizeof(u32) - 1,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = CHACHA20_KEY_SIZE,
+ .max_keysize = CHACHA20_KEY_SIZE,
+ .ivsize = CHACHA20_NONCE_SIZE,
+ .geniv = "seqiv",
+ .setkey = chacha20_setkey,
+ .encrypt = chacha20_crypt,
+ .decrypt = chacha20_crypt,
+ },
+ },
+};
+
+static int __init chacha20_generic_mod_init(void)
+{
+ return crypto_register_alg(&alg);
+}
+
+static void __exit chacha20_generic_mod_fini(void)
+{
+ crypto_unregister_alg(&alg);
+}
+
+module_init(chacha20_generic_mod_init);
+module_exit(chacha20_generic_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
+MODULE_DESCRIPTION("chacha20 cipher algorithm");
+MODULE_ALIAS_CRYPTO("chacha20");
+MODULE_ALIAS_CRYPTO("chacha20-generic");
diff --git a/crypto/chacha20poly1305.c b/crypto/chacha20poly1305.c
new file mode 100644
index 000000000000..7b46ed799a64
--- /dev/null
+++ b/crypto/chacha20poly1305.c
@@ -0,0 +1,695 @@
+/*
+ * ChaCha20-Poly1305 AEAD, RFC7539
+ *
+ * Copyright (C) 2015 Martin Willi
+ *
+ * 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 <crypto/internal/aead.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "internal.h"
+
+#define POLY1305_BLOCK_SIZE 16
+#define POLY1305_DIGEST_SIZE 16
+#define POLY1305_KEY_SIZE 32
+#define CHACHA20_KEY_SIZE 32
+#define CHACHA20_IV_SIZE 16
+#define CHACHAPOLY_IV_SIZE 12
+
+struct chachapoly_instance_ctx {
+ struct crypto_skcipher_spawn chacha;
+ struct crypto_ahash_spawn poly;
+ unsigned int saltlen;
+};
+
+struct chachapoly_ctx {
+ struct crypto_ablkcipher *chacha;
+ struct crypto_ahash *poly;
+ /* key bytes we use for the ChaCha20 IV */
+ unsigned int saltlen;
+ u8 salt[];
+};
+
+struct poly_req {
+ /* zero byte padding for AD/ciphertext, as needed */
+ u8 pad[POLY1305_BLOCK_SIZE];
+ /* tail data with AD/ciphertext lengths */
+ struct {
+ __le64 assoclen;
+ __le64 cryptlen;
+ } tail;
+ struct scatterlist src[1];
+ struct ahash_request req; /* must be last member */
+};
+
+struct chacha_req {
+ u8 iv[CHACHA20_IV_SIZE];
+ struct scatterlist src[1];
+ struct ablkcipher_request req; /* must be last member */
+};
+
+struct chachapoly_req_ctx {
+ /* the key we generate for Poly1305 using Chacha20 */
+ u8 key[POLY1305_KEY_SIZE];
+ /* calculated Poly1305 tag */
+ u8 tag[POLY1305_DIGEST_SIZE];
+ /* length of data to en/decrypt, without ICV */
+ unsigned int cryptlen;
+ union {
+ struct poly_req poly;
+ struct chacha_req chacha;
+ } u;
+};
+
+static inline void async_done_continue(struct aead_request *req, int err,
+ int (*cont)(struct aead_request *))
+{
+ if (!err)
+ err = cont(req);
+
+ if (err != -EINPROGRESS && err != -EBUSY)
+ aead_request_complete(req, err);
+}
+
+static void chacha_iv(u8 *iv, struct aead_request *req, u32 icb)
+{
+ struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ __le32 leicb = cpu_to_le32(icb);
+
+ memcpy(iv, &leicb, sizeof(leicb));
+ memcpy(iv + sizeof(leicb), ctx->salt, ctx->saltlen);
+ memcpy(iv + sizeof(leicb) + ctx->saltlen, req->iv,
+ CHACHA20_IV_SIZE - sizeof(leicb) - ctx->saltlen);
+}
+
+static int poly_verify_tag(struct aead_request *req)
+{
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+ u8 tag[sizeof(rctx->tag)];
+
+ scatterwalk_map_and_copy(tag, req->src, rctx->cryptlen, sizeof(tag), 0);
+ if (crypto_memneq(tag, rctx->tag, sizeof(tag)))
+ return -EBADMSG;
+ return 0;
+}
+
+static int poly_copy_tag(struct aead_request *req)
+{
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+
+ scatterwalk_map_and_copy(rctx->tag, req->dst, rctx->cryptlen,
+ sizeof(rctx->tag), 1);
+ return 0;
+}
+
+static void chacha_decrypt_done(struct crypto_async_request *areq, int err)
+{
+ async_done_continue(areq->data, err, poly_verify_tag);
+}
+
+static int chacha_decrypt(struct aead_request *req)
+{
+ struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+ struct chacha_req *creq = &rctx->u.chacha;
+ int err;
+
+ chacha_iv(creq->iv, req, 1);
+
+ ablkcipher_request_set_callback(&creq->req, aead_request_flags(req),
+ chacha_decrypt_done, req);
+ ablkcipher_request_set_tfm(&creq->req, ctx->chacha);
+ ablkcipher_request_set_crypt(&creq->req, req->src, req->dst,
+ rctx->cryptlen, creq->iv);
+ err = crypto_ablkcipher_decrypt(&creq->req);
+ if (err)
+ return err;
+
+ return poly_verify_tag(req);
+}
+
+static int poly_tail_continue(struct aead_request *req)
+{
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+
+ if (rctx->cryptlen == req->cryptlen) /* encrypting */
+ return poly_copy_tag(req);
+
+ return chacha_decrypt(req);
+}
+
+static void poly_tail_done(struct crypto_async_request *areq, int err)
+{
+ async_done_continue(areq->data, err, poly_tail_continue);
+}
+
+static int poly_tail(struct aead_request *req)
+{
+ struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+ struct poly_req *preq = &rctx->u.poly;
+ __le64 len;
+ int err;
+
+ sg_init_table(preq->src, 1);
+ len = cpu_to_le64(req->assoclen);
+ memcpy(&preq->tail.assoclen, &len, sizeof(len));
+ len = cpu_to_le64(rctx->cryptlen);
+ memcpy(&preq->tail.cryptlen, &len, sizeof(len));
+ sg_set_buf(preq->src, &preq->tail, sizeof(preq->tail));
+
+ ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ poly_tail_done, req);
+ ahash_request_set_tfm(&preq->req, ctx->poly);
+ ahash_request_set_crypt(&preq->req, preq->src,
+ rctx->tag, sizeof(preq->tail));
+
+ err = crypto_ahash_finup(&preq->req);
+ if (err)
+ return err;
+
+ return poly_tail_continue(req);
+}
+
+static void poly_cipherpad_done(struct crypto_async_request *areq, int err)
+{
+ async_done_continue(areq->data, err, poly_tail);
+}
+
+static int poly_cipherpad(struct aead_request *req)
+{
+ struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+ struct poly_req *preq = &rctx->u.poly;
+ unsigned int padlen, bs = POLY1305_BLOCK_SIZE;
+ int err;
+
+ padlen = (bs - (rctx->cryptlen % bs)) % bs;
+ memset(preq->pad, 0, sizeof(preq->pad));
+ sg_init_table(preq->src, 1);
+ sg_set_buf(preq->src, &preq->pad, padlen);
+
+ ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ poly_cipherpad_done, req);
+ ahash_request_set_tfm(&preq->req, ctx->poly);
+ ahash_request_set_crypt(&preq->req, preq->src, NULL, padlen);
+
+ err = crypto_ahash_update(&preq->req);
+ if (err)
+ return err;
+
+ return poly_tail(req);
+}
+
+static void poly_cipher_done(struct crypto_async_request *areq, int err)
+{
+ async_done_continue(areq->data, err, poly_cipherpad);
+}
+
+static int poly_cipher(struct aead_request *req)
+{
+ struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+ struct poly_req *preq = &rctx->u.poly;
+ struct scatterlist *crypt = req->src;
+ int err;
+
+ if (rctx->cryptlen == req->cryptlen) /* encrypting */
+ crypt = req->dst;
+
+ ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ poly_cipher_done, req);
+ ahash_request_set_tfm(&preq->req, ctx->poly);
+ ahash_request_set_crypt(&preq->req, crypt, NULL, rctx->cryptlen);
+
+ err = crypto_ahash_update(&preq->req);
+ if (err)
+ return err;
+
+ return poly_cipherpad(req);
+}
+
+static void poly_adpad_done(struct crypto_async_request *areq, int err)
+{
+ async_done_continue(areq->data, err, poly_cipher);
+}
+
+static int poly_adpad(struct aead_request *req)
+{
+ struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+ struct poly_req *preq = &rctx->u.poly;
+ unsigned int padlen, bs = POLY1305_BLOCK_SIZE;
+ int err;
+
+ padlen = (bs - (req->assoclen % bs)) % bs;
+ memset(preq->pad, 0, sizeof(preq->pad));
+ sg_init_table(preq->src, 1);
+ sg_set_buf(preq->src, preq->pad, padlen);
+
+ ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ poly_adpad_done, req);
+ ahash_request_set_tfm(&preq->req, ctx->poly);
+ ahash_request_set_crypt(&preq->req, preq->src, NULL, padlen);
+
+ err = crypto_ahash_update(&preq->req);
+ if (err)
+ return err;
+
+ return poly_cipher(req);
+}
+
+static void poly_ad_done(struct crypto_async_request *areq, int err)
+{
+ async_done_continue(areq->data, err, poly_adpad);
+}
+
+static int poly_ad(struct aead_request *req)
+{
+ struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+ struct poly_req *preq = &rctx->u.poly;
+ int err;
+
+ ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ poly_ad_done, req);
+ ahash_request_set_tfm(&preq->req, ctx->poly);
+ ahash_request_set_crypt(&preq->req, req->assoc, NULL, req->assoclen);
+
+ err = crypto_ahash_update(&preq->req);
+ if (err)
+ return err;
+
+ return poly_adpad(req);
+}
+
+static void poly_setkey_done(struct crypto_async_request *areq, int err)
+{
+ async_done_continue(areq->data, err, poly_ad);
+}
+
+static int poly_setkey(struct aead_request *req)
+{
+ struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+ struct poly_req *preq = &rctx->u.poly;
+ int err;
+
+ sg_init_table(preq->src, 1);
+ sg_set_buf(preq->src, rctx->key, sizeof(rctx->key));
+
+ ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ poly_setkey_done, req);
+ ahash_request_set_tfm(&preq->req, ctx->poly);
+ ahash_request_set_crypt(&preq->req, preq->src, NULL, sizeof(rctx->key));
+
+ err = crypto_ahash_update(&preq->req);
+ if (err)
+ return err;
+
+ return poly_ad(req);
+}
+
+static void poly_init_done(struct crypto_async_request *areq, int err)
+{
+ async_done_continue(areq->data, err, poly_setkey);
+}
+
+static int poly_init(struct aead_request *req)
+{
+ struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+ struct poly_req *preq = &rctx->u.poly;
+ int err;
+
+ ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ poly_init_done, req);
+ ahash_request_set_tfm(&preq->req, ctx->poly);
+
+ err = crypto_ahash_init(&preq->req);
+ if (err)
+ return err;
+
+ return poly_setkey(req);
+}
+
+static void poly_genkey_done(struct crypto_async_request *areq, int err)
+{
+ async_done_continue(areq->data, err, poly_init);
+}
+
+static int poly_genkey(struct aead_request *req)
+{
+ struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+ struct chacha_req *creq = &rctx->u.chacha;
+ int err;
+
+ sg_init_table(creq->src, 1);
+ memset(rctx->key, 0, sizeof(rctx->key));
+ sg_set_buf(creq->src, rctx->key, sizeof(rctx->key));
+
+ chacha_iv(creq->iv, req, 0);
+
+ ablkcipher_request_set_callback(&creq->req, aead_request_flags(req),
+ poly_genkey_done, req);
+ ablkcipher_request_set_tfm(&creq->req, ctx->chacha);
+ ablkcipher_request_set_crypt(&creq->req, creq->src, creq->src,
+ POLY1305_KEY_SIZE, creq->iv);
+
+ err = crypto_ablkcipher_decrypt(&creq->req);
+ if (err)
+ return err;
+
+ return poly_init(req);
+}
+
+static void chacha_encrypt_done(struct crypto_async_request *areq, int err)
+{
+ async_done_continue(areq->data, err, poly_genkey);
+}
+
+static int chacha_encrypt(struct aead_request *req)
+{
+ struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+ struct chacha_req *creq = &rctx->u.chacha;
+ int err;
+
+ chacha_iv(creq->iv, req, 1);
+
+ ablkcipher_request_set_callback(&creq->req, aead_request_flags(req),
+ chacha_encrypt_done, req);
+ ablkcipher_request_set_tfm(&creq->req, ctx->chacha);
+ ablkcipher_request_set_crypt(&creq->req, req->src, req->dst,
+ req->cryptlen, creq->iv);
+ err = crypto_ablkcipher_encrypt(&creq->req);
+ if (err)
+ return err;
+
+ return poly_genkey(req);
+}
+
+static int chachapoly_encrypt(struct aead_request *req)
+{
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+
+ rctx->cryptlen = req->cryptlen;
+
+ /* encrypt call chain:
+ * - chacha_encrypt/done()
+ * - poly_genkey/done()
+ * - poly_init/done()
+ * - poly_setkey/done()
+ * - poly_ad/done()
+ * - poly_adpad/done()
+ * - poly_cipher/done()
+ * - poly_cipherpad/done()
+ * - poly_tail/done/continue()
+ * - poly_copy_tag()
+ */
+ return chacha_encrypt(req);
+}
+
+static int chachapoly_decrypt(struct aead_request *req)
+{
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+
+ if (req->cryptlen < POLY1305_DIGEST_SIZE)
+ return -EINVAL;
+ rctx->cryptlen = req->cryptlen - POLY1305_DIGEST_SIZE;
+
+ /* decrypt call chain:
+ * - poly_genkey/done()
+ * - poly_init/done()
+ * - poly_setkey/done()
+ * - poly_ad/done()
+ * - poly_adpad/done()
+ * - poly_cipher/done()
+ * - poly_cipherpad/done()
+ * - poly_tail/done/continue()
+ * - chacha_decrypt/done()
+ * - poly_verify_tag()
+ */
+ return poly_genkey(req);
+}
+
+static int chachapoly_setkey(struct crypto_aead *aead, const u8 *key,
+ unsigned int keylen)
+{
+ struct chachapoly_ctx *ctx = crypto_aead_ctx(aead);
+ int err;
+
+ if (keylen != ctx->saltlen + CHACHA20_KEY_SIZE)
+ return -EINVAL;
+
+ keylen -= ctx->saltlen;
+ memcpy(ctx->salt, key + keylen, ctx->saltlen);
+
+ crypto_ablkcipher_clear_flags(ctx->chacha, CRYPTO_TFM_REQ_MASK);
+ crypto_ablkcipher_set_flags(ctx->chacha, crypto_aead_get_flags(aead) &
+ CRYPTO_TFM_REQ_MASK);
+
+ err = crypto_ablkcipher_setkey(ctx->chacha, key, keylen);
+ crypto_aead_set_flags(aead, crypto_ablkcipher_get_flags(ctx->chacha) &
+ CRYPTO_TFM_RES_MASK);
+ return err;
+}
+
+static int chachapoly_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ if (authsize != POLY1305_DIGEST_SIZE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int chachapoly_init(struct crypto_tfm *tfm)
+{
+ struct crypto_instance *inst = (void *)tfm->__crt_alg;
+ struct chachapoly_instance_ctx *ictx = crypto_instance_ctx(inst);
+ struct chachapoly_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_ablkcipher *chacha;
+ struct crypto_ahash *poly;
+ unsigned long align;
+
+ poly = crypto_spawn_ahash(&ictx->poly);
+ if (IS_ERR(poly))
+ return PTR_ERR(poly);
+
+ chacha = crypto_spawn_skcipher(&ictx->chacha);
+ if (IS_ERR(chacha)) {
+ crypto_free_ahash(poly);
+ return PTR_ERR(chacha);
+ }
+
+ ctx->chacha = chacha;
+ ctx->poly = poly;
+ ctx->saltlen = ictx->saltlen;
+
+ align = crypto_tfm_alg_alignmask(tfm);
+ align &= ~(crypto_tfm_ctx_alignment() - 1);
+ crypto_aead_set_reqsize(__crypto_aead_cast(tfm),
+ align + offsetof(struct chachapoly_req_ctx, u) +
+ max(offsetof(struct chacha_req, req) +
+ sizeof(struct ablkcipher_request) +
+ crypto_ablkcipher_reqsize(chacha),
+ offsetof(struct poly_req, req) +
+ sizeof(struct ahash_request) +
+ crypto_ahash_reqsize(poly)));
+
+ return 0;
+}
+
+static void chachapoly_exit(struct crypto_tfm *tfm)
+{
+ struct chachapoly_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ crypto_free_ahash(ctx->poly);
+ crypto_free_ablkcipher(ctx->chacha);
+}
+
+static struct crypto_instance *chachapoly_alloc(struct rtattr **tb,
+ const char *name,
+ unsigned int ivsize)
+{
+ struct crypto_attr_type *algt;
+ struct crypto_instance *inst;
+ struct crypto_alg *chacha;
+ struct crypto_alg *poly;
+ struct ahash_alg *poly_ahash;
+ struct chachapoly_instance_ctx *ctx;
+ const char *chacha_name, *poly_name;
+ int err;
+
+ if (ivsize > CHACHAPOLY_IV_SIZE)
+ return ERR_PTR(-EINVAL);
+
+ algt = crypto_get_attr_type(tb);
+ if (IS_ERR(algt))
+ return ERR_CAST(algt);
+
+ if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
+ return ERR_PTR(-EINVAL);
+
+ chacha_name = crypto_attr_alg_name(tb[1]);
+ if (IS_ERR(chacha_name))
+ return ERR_CAST(chacha_name);
+ poly_name = crypto_attr_alg_name(tb[2]);
+ if (IS_ERR(poly_name))
+ return ERR_CAST(poly_name);
+
+ poly = crypto_find_alg(poly_name, &crypto_ahash_type,
+ CRYPTO_ALG_TYPE_HASH,
+ CRYPTO_ALG_TYPE_AHASH_MASK);
+ if (IS_ERR(poly))
+ return ERR_CAST(poly);
+
+ err = -ENOMEM;
+ inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
+ if (!inst)
+ goto out_put_poly;
+
+ ctx = crypto_instance_ctx(inst);
+ ctx->saltlen = CHACHAPOLY_IV_SIZE - ivsize;
+ poly_ahash = container_of(poly, struct ahash_alg, halg.base);
+ err = crypto_init_ahash_spawn(&ctx->poly, &poly_ahash->halg, inst);
+ if (err)
+ goto err_free_inst;
+
+ crypto_set_skcipher_spawn(&ctx->chacha, inst);
+ err = crypto_grab_skcipher(&ctx->chacha, chacha_name, 0,
+ crypto_requires_sync(algt->type,
+ algt->mask));
+ if (err)
+ goto err_drop_poly;
+
+ chacha = crypto_skcipher_spawn_alg(&ctx->chacha);
+
+ err = -EINVAL;
+ /* Need 16-byte IV size, including Initial Block Counter value */
+ if (chacha->cra_ablkcipher.ivsize != CHACHA20_IV_SIZE)
+ goto out_drop_chacha;
+ /* Not a stream cipher? */
+ if (chacha->cra_blocksize != 1)
+ goto out_drop_chacha;
+
+ err = -ENAMETOOLONG;
+ if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
+ "%s(%s,%s)", name, chacha_name,
+ poly_name) >= CRYPTO_MAX_ALG_NAME)
+ goto out_drop_chacha;
+ if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+ "%s(%s,%s)", name, chacha->cra_driver_name,
+ poly->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+ goto out_drop_chacha;
+
+ inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
+ inst->alg.cra_flags |= (chacha->cra_flags |
+ poly->cra_flags) & CRYPTO_ALG_ASYNC;
+ inst->alg.cra_priority = (chacha->cra_priority +
+ poly->cra_priority) / 2;
+ inst->alg.cra_blocksize = 1;
+ inst->alg.cra_alignmask = chacha->cra_alignmask | poly->cra_alignmask;
+ inst->alg.cra_type = &crypto_nivaead_type;
+ inst->alg.cra_aead.ivsize = ivsize;
+ inst->alg.cra_aead.maxauthsize = POLY1305_DIGEST_SIZE;
+ inst->alg.cra_ctxsize = sizeof(struct chachapoly_ctx) + ctx->saltlen;
+ inst->alg.cra_init = chachapoly_init;
+ inst->alg.cra_exit = chachapoly_exit;
+ inst->alg.cra_aead.encrypt = chachapoly_encrypt;
+ inst->alg.cra_aead.decrypt = chachapoly_decrypt;
+ inst->alg.cra_aead.setkey = chachapoly_setkey;
+ inst->alg.cra_aead.setauthsize = chachapoly_setauthsize;
+ inst->alg.cra_aead.geniv = "seqiv";
+
+out:
+ crypto_mod_put(poly);
+ return inst;
+
+out_drop_chacha:
+ crypto_drop_skcipher(&ctx->chacha);
+err_drop_poly:
+ crypto_drop_ahash(&ctx->poly);
+err_free_inst:
+ kfree(inst);
+out_put_poly:
+ inst = ERR_PTR(err);
+ goto out;
+}
+
+static struct crypto_instance *rfc7539_alloc(struct rtattr **tb)
+{
+ return chachapoly_alloc(tb, "rfc7539", 12);
+}
+
+static struct crypto_instance *rfc7539esp_alloc(struct rtattr **tb)
+{
+ return chachapoly_alloc(tb, "rfc7539esp", 8);
+}
+
+static void chachapoly_free(struct crypto_instance *inst)
+{
+ struct chachapoly_instance_ctx *ctx = crypto_instance_ctx(inst);
+
+ crypto_drop_skcipher(&ctx->chacha);
+ crypto_drop_ahash(&ctx->poly);
+ kfree(inst);
+}
+
+static struct crypto_template rfc7539_tmpl = {
+ .name = "rfc7539",
+ .alloc = rfc7539_alloc,
+ .free = chachapoly_free,
+ .module = THIS_MODULE,
+};
+
+static struct crypto_template rfc7539esp_tmpl = {
+ .name = "rfc7539esp",
+ .alloc = rfc7539esp_alloc,
+ .free = chachapoly_free,
+ .module = THIS_MODULE,
+};
+
+static int __init chacha20poly1305_module_init(void)
+{
+ int err;
+
+ err = crypto_register_template(&rfc7539_tmpl);
+ if (err)
+ return err;
+
+ err = crypto_register_template(&rfc7539esp_tmpl);
+ if (err)
+ crypto_unregister_template(&rfc7539_tmpl);
+
+ return err;
+}
+
+static void __exit chacha20poly1305_module_exit(void)
+{
+ crypto_unregister_template(&rfc7539esp_tmpl);
+ crypto_unregister_template(&rfc7539_tmpl);
+}
+
+module_init(chacha20poly1305_module_init);
+module_exit(chacha20poly1305_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
+MODULE_DESCRIPTION("ChaCha20-Poly1305 AEAD");
+MODULE_ALIAS_CRYPTO("chacha20poly1305");
+MODULE_ALIAS_CRYPTO("rfc7539");
+MODULE_ALIAS_CRYPTO("rfc7539esp");
diff --git a/crypto/chainiv.c b/crypto/chainiv.c
index 63c17d5992f7..b4340018c8d4 100644
--- a/crypto/chainiv.c
+++ b/crypto/chainiv.c
@@ -80,44 +80,37 @@ unlock:
return err;
}
-static int chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
+static int chainiv_init_common(struct crypto_tfm *tfm, char iv[])
{
- struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
- struct chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+ struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
int err = 0;
- spin_lock_bh(&ctx->lock);
- if (crypto_ablkcipher_crt(geniv)->givencrypt !=
- chainiv_givencrypt_first)
- goto unlock;
-
- crypto_ablkcipher_crt(geniv)->givencrypt = chainiv_givencrypt;
- err = crypto_rng_get_bytes(crypto_default_rng, ctx->iv,
- crypto_ablkcipher_ivsize(geniv));
-
-unlock:
- spin_unlock_bh(&ctx->lock);
-
- if (err)
- return err;
-
- return chainiv_givencrypt(req);
-}
-
-static int chainiv_init_common(struct crypto_tfm *tfm)
-{
tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request);
- return skcipher_geniv_init(tfm);
+ if (iv) {
+ err = crypto_rng_get_bytes(crypto_default_rng, iv,
+ crypto_ablkcipher_ivsize(geniv));
+ crypto_put_default_rng();
+ }
+
+ return err ?: skcipher_geniv_init(tfm);
}
static int chainiv_init(struct crypto_tfm *tfm)
{
+ struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
struct chainiv_ctx *ctx = crypto_tfm_ctx(tfm);
+ char *iv;
spin_lock_init(&ctx->lock);
- return chainiv_init_common(tfm);
+ iv = NULL;
+ if (!crypto_get_default_rng()) {
+ crypto_ablkcipher_crt(geniv)->givencrypt = chainiv_givencrypt;
+ iv = ctx->iv;
+ }
+
+ return chainiv_init_common(tfm, iv);
}
static int async_chainiv_schedule_work(struct async_chainiv_ctx *ctx)
@@ -205,33 +198,6 @@ postpone:
return async_chainiv_postpone_request(req);
}
-static int async_chainiv_givencrypt_first(struct skcipher_givcrypt_request *req)
-{
- struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
- struct async_chainiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
- int err = 0;
-
- if (test_and_set_bit(CHAINIV_STATE_INUSE, &ctx->state))
- goto out;
-
- if (crypto_ablkcipher_crt(geniv)->givencrypt !=
- async_chainiv_givencrypt_first)
- goto unlock;
-
- crypto_ablkcipher_crt(geniv)->givencrypt = async_chainiv_givencrypt;
- err = crypto_rng_get_bytes(crypto_default_rng, ctx->iv,
- crypto_ablkcipher_ivsize(geniv));
-
-unlock:
- clear_bit(CHAINIV_STATE_INUSE, &ctx->state);
-
- if (err)
- return err;
-
-out:
- return async_chainiv_givencrypt(req);
-}
-
static void async_chainiv_do_postponed(struct work_struct *work)
{
struct async_chainiv_ctx *ctx = container_of(work,
@@ -263,14 +229,23 @@ static void async_chainiv_do_postponed(struct work_struct *work)
static int async_chainiv_init(struct crypto_tfm *tfm)
{
+ struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
struct async_chainiv_ctx *ctx = crypto_tfm_ctx(tfm);
+ char *iv;
spin_lock_init(&ctx->lock);
crypto_init_queue(&ctx->queue, 100);
INIT_WORK(&ctx->postponed, async_chainiv_do_postponed);
- return chainiv_init_common(tfm);
+ iv = NULL;
+ if (!crypto_get_default_rng()) {
+ crypto_ablkcipher_crt(geniv)->givencrypt =
+ async_chainiv_givencrypt;
+ iv = ctx->iv;
+ }
+
+ return chainiv_init_common(tfm, iv);
}
static void async_chainiv_exit(struct crypto_tfm *tfm)
@@ -288,21 +263,14 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb)
{
struct crypto_attr_type *algt;
struct crypto_instance *inst;
- int err;
algt = crypto_get_attr_type(tb);
if (IS_ERR(algt))
return ERR_CAST(algt);
- err = crypto_get_default_rng();
- if (err)
- return ERR_PTR(err);
-
inst = skcipher_geniv_alloc(&chainiv_tmpl, tb, 0, 0);
if (IS_ERR(inst))
- goto put_rng;
-
- inst->alg.cra_ablkcipher.givencrypt = chainiv_givencrypt_first;
+ goto out;
inst->alg.cra_init = chainiv_init;
inst->alg.cra_exit = skcipher_geniv_exit;
@@ -312,9 +280,6 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb)
if (!crypto_requires_sync(algt->type, algt->mask)) {
inst->alg.cra_flags |= CRYPTO_ALG_ASYNC;
- inst->alg.cra_ablkcipher.givencrypt =
- async_chainiv_givencrypt_first;
-
inst->alg.cra_init = async_chainiv_init;
inst->alg.cra_exit = async_chainiv_exit;
@@ -325,22 +290,12 @@ static struct crypto_instance *chainiv_alloc(struct rtattr **tb)
out:
return inst;
-
-put_rng:
- crypto_put_default_rng();
- goto out;
-}
-
-static void chainiv_free(struct crypto_instance *inst)
-{
- skcipher_geniv_free(inst);
- crypto_put_default_rng();
}
static struct crypto_template chainiv_tmpl = {
.name = "chainiv",
.alloc = chainiv_alloc,
- .free = chainiv_free,
+ .free = skcipher_geniv_free,
.module = THIS_MODULE,
};
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index b0602ba03111..22ba81f76764 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -295,6 +295,23 @@ static void cryptd_blkcipher_exit_tfm(struct crypto_tfm *tfm)
crypto_free_blkcipher(ctx->child);
}
+static int cryptd_init_instance(struct crypto_instance *inst,
+ struct crypto_alg *alg)
+{
+ if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+ "cryptd(%s)",
+ alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+ return -ENAMETOOLONG;
+
+ memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
+
+ inst->alg.cra_priority = alg->cra_priority + 50;
+ inst->alg.cra_blocksize = alg->cra_blocksize;
+ inst->alg.cra_alignmask = alg->cra_alignmask;
+
+ return 0;
+}
+
static void *cryptd_alloc_instance(struct crypto_alg *alg, unsigned int head,
unsigned int tail)
{
@@ -308,17 +325,10 @@ static void *cryptd_alloc_instance(struct crypto_alg *alg, unsigned int head,
inst = (void *)(p + head);
- err = -ENAMETOOLONG;
- if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
- "cryptd(%s)", alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+ err = cryptd_init_instance(inst, alg);
+ if (err)
goto out_free_inst;
- memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
-
- inst->alg.cra_priority = alg->cra_priority + 50;
- inst->alg.cra_blocksize = alg->cra_blocksize;
- inst->alg.cra_alignmask = alg->cra_alignmask;
-
out:
return p;
@@ -654,6 +664,24 @@ out_put_alg:
return err;
}
+static int cryptd_aead_setkey(struct crypto_aead *parent,
+ const u8 *key, unsigned int keylen)
+{
+ struct cryptd_aead_ctx *ctx = crypto_aead_ctx(parent);
+ struct crypto_aead *child = ctx->child;
+
+ return crypto_aead_setkey(child, key, keylen);
+}
+
+static int cryptd_aead_setauthsize(struct crypto_aead *parent,
+ unsigned int authsize)
+{
+ struct cryptd_aead_ctx *ctx = crypto_aead_ctx(parent);
+ struct crypto_aead *child = ctx->child;
+
+ return crypto_aead_setauthsize(child, authsize);
+}
+
static void cryptd_aead_crypt(struct aead_request *req,
struct crypto_aead *child,
int err,
@@ -715,27 +743,26 @@ static int cryptd_aead_decrypt_enqueue(struct aead_request *req)
return cryptd_aead_enqueue(req, cryptd_aead_decrypt );
}
-static int cryptd_aead_init_tfm(struct crypto_tfm *tfm)
+static int cryptd_aead_init_tfm(struct crypto_aead *tfm)
{
- struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
- struct aead_instance_ctx *ictx = crypto_instance_ctx(inst);
+ struct aead_instance *inst = aead_alg_instance(tfm);
+ struct aead_instance_ctx *ictx = aead_instance_ctx(inst);
struct crypto_aead_spawn *spawn = &ictx->aead_spawn;
- struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct cryptd_aead_ctx *ctx = crypto_aead_ctx(tfm);
struct crypto_aead *cipher;
cipher = crypto_spawn_aead(spawn);
if (IS_ERR(cipher))
return PTR_ERR(cipher);
- crypto_aead_set_flags(cipher, CRYPTO_TFM_REQ_MAY_SLEEP);
ctx->child = cipher;
- tfm->crt_aead.reqsize = sizeof(struct cryptd_aead_request_ctx);
+ crypto_aead_set_reqsize(tfm, sizeof(struct cryptd_aead_request_ctx));
return 0;
}
-static void cryptd_aead_exit_tfm(struct crypto_tfm *tfm)
+static void cryptd_aead_exit_tfm(struct crypto_aead *tfm)
{
- struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct cryptd_aead_ctx *ctx = crypto_aead_ctx(tfm);
crypto_free_aead(ctx->child);
}
@@ -744,57 +771,57 @@ static int cryptd_create_aead(struct crypto_template *tmpl,
struct cryptd_queue *queue)
{
struct aead_instance_ctx *ctx;
- struct crypto_instance *inst;
- struct crypto_alg *alg;
- u32 type = CRYPTO_ALG_TYPE_AEAD;
- u32 mask = CRYPTO_ALG_TYPE_MASK;
+ struct aead_instance *inst;
+ struct aead_alg *alg;
+ const char *name;
+ u32 type = 0;
+ u32 mask = 0;
int err;
cryptd_check_internal(tb, &type, &mask);
- alg = crypto_get_attr_alg(tb, type, mask);
- if (IS_ERR(alg))
- return PTR_ERR(alg);
+ name = crypto_attr_alg_name(tb[1]);
+ if (IS_ERR(name))
+ return PTR_ERR(name);
- inst = cryptd_alloc_instance(alg, 0, sizeof(*ctx));
- err = PTR_ERR(inst);
- if (IS_ERR(inst))
- goto out_put_alg;
+ inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
- ctx = crypto_instance_ctx(inst);
+ ctx = aead_instance_ctx(inst);
ctx->queue = queue;
- err = crypto_init_spawn(&ctx->aead_spawn.base, alg, inst,
- CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+ crypto_set_aead_spawn(&ctx->aead_spawn, aead_crypto_instance(inst));
+ err = crypto_grab_aead(&ctx->aead_spawn, name, type, mask);
if (err)
goto out_free_inst;
- type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC;
- if (alg->cra_flags & CRYPTO_ALG_INTERNAL)
- type |= CRYPTO_ALG_INTERNAL;
- inst->alg.cra_flags = type;
- inst->alg.cra_type = alg->cra_type;
- inst->alg.cra_ctxsize = sizeof(struct cryptd_aead_ctx);
- inst->alg.cra_init = cryptd_aead_init_tfm;
- inst->alg.cra_exit = cryptd_aead_exit_tfm;
- inst->alg.cra_aead.setkey = alg->cra_aead.setkey;
- inst->alg.cra_aead.setauthsize = alg->cra_aead.setauthsize;
- inst->alg.cra_aead.geniv = alg->cra_aead.geniv;
- inst->alg.cra_aead.ivsize = alg->cra_aead.ivsize;
- inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize;
- inst->alg.cra_aead.encrypt = cryptd_aead_encrypt_enqueue;
- inst->alg.cra_aead.decrypt = cryptd_aead_decrypt_enqueue;
- inst->alg.cra_aead.givencrypt = alg->cra_aead.givencrypt;
- inst->alg.cra_aead.givdecrypt = alg->cra_aead.givdecrypt;
+ alg = crypto_spawn_aead_alg(&ctx->aead_spawn);
+ err = cryptd_init_instance(aead_crypto_instance(inst), &alg->base);
+ if (err)
+ goto out_drop_aead;
- err = crypto_register_instance(tmpl, inst);
+ inst->alg.base.cra_flags = CRYPTO_ALG_ASYNC |
+ (alg->base.cra_flags & CRYPTO_ALG_INTERNAL);
+ inst->alg.base.cra_ctxsize = sizeof(struct cryptd_aead_ctx);
+
+ inst->alg.ivsize = crypto_aead_alg_ivsize(alg);
+ inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);
+
+ inst->alg.init = cryptd_aead_init_tfm;
+ inst->alg.exit = cryptd_aead_exit_tfm;
+ inst->alg.setkey = cryptd_aead_setkey;
+ inst->alg.setauthsize = cryptd_aead_setauthsize;
+ inst->alg.encrypt = cryptd_aead_encrypt_enqueue;
+ inst->alg.decrypt = cryptd_aead_decrypt_enqueue;
+
+ err = aead_register_instance(tmpl, inst);
if (err) {
- crypto_drop_spawn(&ctx->aead_spawn.base);
+out_drop_aead:
+ crypto_drop_aead(&ctx->aead_spawn);
out_free_inst:
kfree(inst);
}
-out_put_alg:
- crypto_mod_put(alg);
return err;
}
@@ -832,8 +859,8 @@ static void cryptd_free(struct crypto_instance *inst)
kfree(ahash_instance(inst));
return;
case CRYPTO_ALG_TYPE_AEAD:
- crypto_drop_spawn(&aead_ctx->aead_spawn.base);
- kfree(inst);
+ crypto_drop_aead(&aead_ctx->aead_spawn);
+ kfree(aead_instance(inst));
return;
default:
crypto_drop_spawn(&ctx->spawn);
diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c
index a20319132e33..941c9a434d50 100644
--- a/crypto/crypto_null.c
+++ b/crypto/crypto_null.c
@@ -25,6 +25,10 @@
#include <linux/mm.h>
#include <linux/string.h>
+static DEFINE_MUTEX(crypto_default_null_skcipher_lock);
+static struct crypto_blkcipher *crypto_default_null_skcipher;
+static int crypto_default_null_skcipher_refcnt;
+
static int null_compress(struct crypto_tfm *tfm, const u8 *src,
unsigned int slen, u8 *dst, unsigned int *dlen)
{
@@ -149,6 +153,41 @@ MODULE_ALIAS_CRYPTO("compress_null");
MODULE_ALIAS_CRYPTO("digest_null");
MODULE_ALIAS_CRYPTO("cipher_null");
+struct crypto_blkcipher *crypto_get_default_null_skcipher(void)
+{
+ struct crypto_blkcipher *tfm;
+
+ mutex_lock(&crypto_default_null_skcipher_lock);
+ tfm = crypto_default_null_skcipher;
+
+ if (!tfm) {
+ tfm = crypto_alloc_blkcipher("ecb(cipher_null)", 0, 0);
+ if (IS_ERR(tfm))
+ goto unlock;
+
+ crypto_default_null_skcipher = tfm;
+ }
+
+ crypto_default_null_skcipher_refcnt++;
+
+unlock:
+ mutex_unlock(&crypto_default_null_skcipher_lock);
+
+ return tfm;
+}
+EXPORT_SYMBOL_GPL(crypto_get_default_null_skcipher);
+
+void crypto_put_default_null_skcipher(void)
+{
+ mutex_lock(&crypto_default_null_skcipher_lock);
+ if (!--crypto_default_null_skcipher_refcnt) {
+ crypto_free_blkcipher(crypto_default_null_skcipher);
+ crypto_default_null_skcipher = NULL;
+ }
+ mutex_unlock(&crypto_default_null_skcipher_lock);
+}
+EXPORT_SYMBOL_GPL(crypto_put_default_null_skcipher);
+
static int __init crypto_null_mod_init(void)
{
int ret = 0;
diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
index 41dfe762b7fb..08ea2867fc8a 100644
--- a/crypto/crypto_user.c
+++ b/crypto/crypto_user.c
@@ -27,6 +27,8 @@
#include <net/net_namespace.h>
#include <crypto/internal/aead.h>
#include <crypto/internal/skcipher.h>
+#include <crypto/internal/rng.h>
+#include <crypto/akcipher.h>
#include "internal.h"
@@ -110,6 +112,21 @@ nla_put_failure:
return -EMSGSIZE;
}
+static int crypto_report_akcipher(struct sk_buff *skb, struct crypto_alg *alg)
+{
+ struct crypto_report_akcipher rakcipher;
+
+ strncpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
+
+ if (nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER,
+ sizeof(struct crypto_report_akcipher), &rakcipher))
+ goto nla_put_failure;
+ return 0;
+
+nla_put_failure:
+ return -EMSGSIZE;
+}
+
static int crypto_report_one(struct crypto_alg *alg,
struct crypto_user_alg *ualg, struct sk_buff *skb)
{
@@ -154,6 +171,12 @@ static int crypto_report_one(struct crypto_alg *alg,
goto nla_put_failure;
break;
+
+ case CRYPTO_ALG_TYPE_AKCIPHER:
+ if (crypto_report_akcipher(skb, alg))
+ goto nla_put_failure;
+
+ break;
}
out:
@@ -450,13 +473,21 @@ static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
return 0;
}
+static int crypto_del_rng(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct nlattr **attrs)
+{
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+ return crypto_del_default_rng();
+}
+
#define MSGSIZE(type) sizeof(struct type)
static const int crypto_msg_min[CRYPTO_NR_MSGTYPES] = {
[CRYPTO_MSG_NEWALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
[CRYPTO_MSG_DELALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
[CRYPTO_MSG_UPDATEALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
- [CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
+ [CRYPTO_MSG_DELRNG - CRYPTO_MSG_BASE] = 0,
};
static const struct nla_policy crypto_policy[CRYPTOCFGA_MAX+1] = {
@@ -476,6 +507,7 @@ static const struct crypto_link {
[CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE] = { .doit = crypto_report,
.dump = crypto_dump_report,
.done = crypto_dump_report_done},
+ [CRYPTO_MSG_DELRNG - CRYPTO_MSG_BASE] = { .doit = crypto_del_rng },
};
static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
diff --git a/crypto/drbg.c b/crypto/drbg.c
index b69409cb7e6a..a7c23146b87f 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -98,6 +98,7 @@
*/
#include <crypto/drbg.h>
+#include <linux/kernel.h>
/***************************************************************
* Backend cipher definitions available to DRBG
@@ -190,6 +191,8 @@ static const struct drbg_core drbg_cores[] = {
#endif /* CONFIG_CRYPTO_DRBG_HMAC */
};
+static int drbg_uninstantiate(struct drbg_state *drbg);
+
/******************************************************************
* Generic helper functions
******************************************************************/
@@ -235,7 +238,7 @@ static bool drbg_fips_continuous_test(struct drbg_state *drbg,
#ifdef CONFIG_CRYPTO_FIPS
int ret = 0;
/* skip test if we test the overall system */
- if (drbg->test_data)
+ if (list_empty(&drbg->test_data.list))
return true;
/* only perform test in FIPS mode */
if (0 == fips_enabled)
@@ -487,7 +490,7 @@ static int drbg_ctr_df(struct drbg_state *drbg,
out:
memset(iv, 0, drbg_blocklen(drbg));
- memset(temp, 0, drbg_statelen(drbg));
+ memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg));
memset(pad, 0, drbg_blocklen(drbg));
return ret;
}
@@ -1041,6 +1044,58 @@ static struct drbg_state_ops drbg_hash_ops = {
* Functions common for DRBG implementations
******************************************************************/
+static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed,
+ int reseed)
+{
+ int ret = drbg->d_ops->update(drbg, seed, reseed);
+
+ if (ret)
+ return ret;
+
+ drbg->seeded = true;
+ /* 10.1.1.2 / 10.1.1.3 step 5 */
+ drbg->reseed_ctr = 1;
+
+ return ret;
+}
+
+static void drbg_async_seed(struct work_struct *work)
+{
+ struct drbg_string data;
+ LIST_HEAD(seedlist);
+ struct drbg_state *drbg = container_of(work, struct drbg_state,
+ seed_work);
+ unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
+ unsigned char entropy[32];
+
+ BUG_ON(!entropylen);
+ BUG_ON(entropylen > sizeof(entropy));
+ get_random_bytes(entropy, entropylen);
+
+ drbg_string_fill(&data, entropy, entropylen);
+ list_add_tail(&data.list, &seedlist);
+
+ mutex_lock(&drbg->drbg_mutex);
+
+ /* If nonblocking pool is initialized, deactivate Jitter RNG */
+ crypto_free_rng(drbg->jent);
+ drbg->jent = NULL;
+
+ /* Set seeded to false so that if __drbg_seed fails the
+ * next generate call will trigger a reseed.
+ */
+ drbg->seeded = false;
+
+ __drbg_seed(drbg, &seedlist, true);
+
+ if (drbg->seeded)
+ drbg->reseed_threshold = drbg_max_requests(drbg);
+
+ mutex_unlock(&drbg->drbg_mutex);
+
+ memzero_explicit(entropy, entropylen);
+}
+
/*
* Seeding or reseeding of the DRBG
*
@@ -1055,9 +1110,9 @@ static struct drbg_state_ops drbg_hash_ops = {
static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
bool reseed)
{
- int ret = 0;
- unsigned char *entropy = NULL;
- size_t entropylen = 0;
+ int ret;
+ unsigned char entropy[((32 + 16) * 2)];
+ unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
struct drbg_string data1;
LIST_HEAD(seedlist);
@@ -1068,31 +1123,45 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
return -EINVAL;
}
- if (drbg->test_data && drbg->test_data->testentropy) {
- drbg_string_fill(&data1, drbg->test_data->testentropy->buf,
- drbg->test_data->testentropy->len);
+ if (list_empty(&drbg->test_data.list)) {
+ drbg_string_fill(&data1, drbg->test_data.buf,
+ drbg->test_data.len);
pr_devel("DRBG: using test entropy\n");
} else {
/*
* Gather entropy equal to the security strength of the DRBG.
* With a derivation function, a nonce is required in addition
* to the entropy. A nonce must be at least 1/2 of the security
- * strength of the DRBG in size. Thus, entropy * nonce is 3/2
+ * strength of the DRBG in size. Thus, entropy + nonce is 3/2
* of the strength. The consideration of a nonce is only
* applicable during initial seeding.
*/
- entropylen = drbg_sec_strength(drbg->core->flags);
- if (!entropylen)
- return -EFAULT;
+ BUG_ON(!entropylen);
if (!reseed)
entropylen = ((entropylen + 1) / 2) * 3;
- pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
- entropylen);
- entropy = kzalloc(entropylen, GFP_KERNEL);
- if (!entropy)
- return -ENOMEM;
+ BUG_ON((entropylen * 2) > sizeof(entropy));
+
+ /* Get seed from in-kernel /dev/urandom */
get_random_bytes(entropy, entropylen);
- drbg_string_fill(&data1, entropy, entropylen);
+
+ if (!drbg->jent) {
+ drbg_string_fill(&data1, entropy, entropylen);
+ pr_devel("DRBG: (re)seeding with %u bytes of entropy\n",
+ entropylen);
+ } else {
+ /* Get seed from Jitter RNG */
+ ret = crypto_rng_get_bytes(drbg->jent,
+ entropy + entropylen,
+ entropylen);
+ if (ret) {
+ pr_devel("DRBG: jent failed with %d\n", ret);
+ return ret;
+ }
+
+ drbg_string_fill(&data1, entropy, entropylen * 2);
+ pr_devel("DRBG: (re)seeding with %u bytes of entropy\n",
+ entropylen * 2);
+ }
}
list_add_tail(&data1.list, &seedlist);
@@ -1111,16 +1180,10 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
memset(drbg->C, 0, drbg_statelen(drbg));
}
- ret = drbg->d_ops->update(drbg, &seedlist, reseed);
- if (ret)
- goto out;
+ ret = __drbg_seed(drbg, &seedlist, reseed);
- drbg->seeded = true;
- /* 10.1.1.2 / 10.1.1.3 step 5 */
- drbg->reseed_ctr = 1;
+ memzero_explicit(entropy, entropylen * 2);
-out:
- kzfree(entropy);
return ret;
}
@@ -1136,6 +1199,8 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)
kzfree(drbg->scratchpad);
drbg->scratchpad = NULL;
drbg->reseed_ctr = 0;
+ drbg->d_ops = NULL;
+ drbg->core = NULL;
#ifdef CONFIG_CRYPTO_FIPS
kzfree(drbg->prev);
drbg->prev = NULL;
@@ -1152,6 +1217,27 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
int ret = -ENOMEM;
unsigned int sb_size = 0;
+ switch (drbg->core->flags & DRBG_TYPE_MASK) {
+#ifdef CONFIG_CRYPTO_DRBG_HMAC
+ case DRBG_HMAC:
+ drbg->d_ops = &drbg_hmac_ops;
+ break;
+#endif /* CONFIG_CRYPTO_DRBG_HMAC */
+#ifdef CONFIG_CRYPTO_DRBG_HASH
+ case DRBG_HASH:
+ drbg->d_ops = &drbg_hash_ops;
+ break;
+#endif /* CONFIG_CRYPTO_DRBG_HASH */
+#ifdef CONFIG_CRYPTO_DRBG_CTR
+ case DRBG_CTR:
+ drbg->d_ops = &drbg_ctr_ops;
+ break;
+#endif /* CONFIG_CRYPTO_DRBG_CTR */
+ default:
+ ret = -EOPNOTSUPP;
+ goto err;
+ }
+
drbg->V = kmalloc(drbg_statelen(drbg), GFP_KERNEL);
if (!drbg->V)
goto err;
@@ -1181,87 +1267,14 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
if (!drbg->scratchpad)
goto err;
}
- spin_lock_init(&drbg->drbg_lock);
- return 0;
-
-err:
- drbg_dealloc_state(drbg);
- return ret;
-}
-
-/*
- * Strategy to avoid holding long term locks: generate a shadow copy of DRBG
- * and perform all operations on this shadow copy. After finishing, restore
- * the updated state of the shadow copy into original drbg state. This way,
- * only the read and write operations of the original drbg state must be
- * locked
- */
-static inline void drbg_copy_drbg(struct drbg_state *src,
- struct drbg_state *dst)
-{
- if (!src || !dst)
- return;
- memcpy(dst->V, src->V, drbg_statelen(src));
- memcpy(dst->C, src->C, drbg_statelen(src));
- dst->reseed_ctr = src->reseed_ctr;
- dst->seeded = src->seeded;
- dst->pr = src->pr;
-#ifdef CONFIG_CRYPTO_FIPS
- dst->fips_primed = src->fips_primed;
- memcpy(dst->prev, src->prev, drbg_blocklen(src));
-#endif
- /*
- * Not copied:
- * scratchpad is initialized drbg_alloc_state;
- * priv_data is initialized with call to crypto_init;
- * d_ops and core are set outside, as these parameters are const;
- * test_data is set outside to prevent it being copied back.
- */
-}
-
-static int drbg_make_shadow(struct drbg_state *drbg, struct drbg_state **shadow)
-{
- int ret = -ENOMEM;
- struct drbg_state *tmp = NULL;
-
- tmp = kzalloc(sizeof(struct drbg_state), GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- /* read-only data as they are defined as const, no lock needed */
- tmp->core = drbg->core;
- tmp->d_ops = drbg->d_ops;
- ret = drbg_alloc_state(tmp);
- if (ret)
- goto err;
-
- spin_lock_bh(&drbg->drbg_lock);
- drbg_copy_drbg(drbg, tmp);
- /* only make a link to the test buffer, as we only read that data */
- tmp->test_data = drbg->test_data;
- spin_unlock_bh(&drbg->drbg_lock);
- *shadow = tmp;
return 0;
err:
- kzfree(tmp);
+ drbg_dealloc_state(drbg);
return ret;
}
-static void drbg_restore_shadow(struct drbg_state *drbg,
- struct drbg_state **shadow)
-{
- struct drbg_state *tmp = *shadow;
-
- spin_lock_bh(&drbg->drbg_lock);
- drbg_copy_drbg(tmp, drbg);
- spin_unlock_bh(&drbg->drbg_lock);
- drbg_dealloc_state(tmp);
- kzfree(tmp);
- *shadow = NULL;
-}
-
/*************************************************************************
* DRBG interface functions
*************************************************************************/
@@ -1287,14 +1300,12 @@ static int drbg_generate(struct drbg_state *drbg,
struct drbg_string *addtl)
{
int len = 0;
- struct drbg_state *shadow = NULL;
LIST_HEAD(addtllist);
- struct drbg_string timestamp;
- union {
- cycles_t cycles;
- unsigned char char_cycles[sizeof(cycles_t)];
- } now;
+ if (!drbg->core) {
+ pr_devel("DRBG: not yet seeded\n");
+ return -EINVAL;
+ }
if (0 == buflen || !buf) {
pr_devel("DRBG: no output buffer provided\n");
return -EINVAL;
@@ -1304,15 +1315,9 @@ static int drbg_generate(struct drbg_state *drbg,
return -EINVAL;
}
- len = drbg_make_shadow(drbg, &shadow);
- if (len) {
- pr_devel("DRBG: shadow copy cannot be generated\n");
- return len;
- }
-
/* 9.3.1 step 2 */
len = -EINVAL;
- if (buflen > (drbg_max_request_bytes(shadow))) {
+ if (buflen > (drbg_max_request_bytes(drbg))) {
pr_devel("DRBG: requested random numbers too large %u\n",
buflen);
goto err;
@@ -1321,7 +1326,7 @@ static int drbg_generate(struct drbg_state *drbg,
/* 9.3.1 step 3 is implicit with the chosen DRBG */
/* 9.3.1 step 4 */
- if (addtl && addtl->len > (drbg_max_addtl(shadow))) {
+ if (addtl && addtl->len > (drbg_max_addtl(drbg))) {
pr_devel("DRBG: additional information string too long %zu\n",
addtl->len);
goto err;
@@ -1332,46 +1337,29 @@ static int drbg_generate(struct drbg_state *drbg,
* 9.3.1 step 6 and 9 supplemented by 9.3.2 step c is implemented
* here. The spec is a bit convoluted here, we make it simpler.
*/
- if ((drbg_max_requests(shadow)) < shadow->reseed_ctr)
- shadow->seeded = false;
+ if (drbg->reseed_threshold < drbg->reseed_ctr)
+ drbg->seeded = false;
- /* allocate cipher handle */
- len = shadow->d_ops->crypto_init(shadow);
- if (len)
- goto err;
-
- if (shadow->pr || !shadow->seeded) {
+ if (drbg->pr || !drbg->seeded) {
pr_devel("DRBG: reseeding before generation (prediction "
"resistance: %s, state %s)\n",
drbg->pr ? "true" : "false",
drbg->seeded ? "seeded" : "unseeded");
/* 9.3.1 steps 7.1 through 7.3 */
- len = drbg_seed(shadow, addtl, true);
+ len = drbg_seed(drbg, addtl, true);
if (len)
goto err;
/* 9.3.1 step 7.4 */
addtl = NULL;
}
- /*
- * Mix the time stamp into the DRBG state if the DRBG is not in
- * test mode. If there are two callers invoking the DRBG at the same
- * time, i.e. before the first caller merges its shadow state back,
- * both callers would obtain the same random number stream without
- * changing the state here.
- */
- if (!drbg->test_data) {
- now.cycles = random_get_entropy();
- drbg_string_fill(&timestamp, now.char_cycles, sizeof(cycles_t));
- list_add_tail(&timestamp.list, &addtllist);
- }
if (addtl && 0 < addtl->len)
list_add_tail(&addtl->list, &addtllist);
/* 9.3.1 step 8 and 10 */
- len = shadow->d_ops->generate(shadow, buf, buflen, &addtllist);
+ len = drbg->d_ops->generate(drbg, buf, buflen, &addtllist);
/* 10.1.1.4 step 6, 10.1.2.5 step 7, 10.2.1.5.2 step 7 */
- shadow->reseed_ctr++;
+ drbg->reseed_ctr++;
if (0 >= len)
goto err;
@@ -1391,7 +1379,7 @@ static int drbg_generate(struct drbg_state *drbg,
* case somebody has a need to implement the test of 11.3.3.
*/
#if 0
- if (shadow->reseed_ctr && !(shadow->reseed_ctr % 4096)) {
+ if (drbg->reseed_ctr && !(drbg->reseed_ctr % 4096)) {
int err = 0;
pr_devel("DRBG: start to perform self test\n");
if (drbg->core->flags & DRBG_HMAC)
@@ -1410,8 +1398,6 @@ static int drbg_generate(struct drbg_state *drbg,
* are returned when reusing this DRBG cipher handle
*/
drbg_uninstantiate(drbg);
- drbg_dealloc_state(shadow);
- kzfree(shadow);
return 0;
} else {
pr_devel("DRBG: self test successful\n");
@@ -1425,8 +1411,6 @@ static int drbg_generate(struct drbg_state *drbg,
*/
len = 0;
err:
- shadow->d_ops->crypto_fini(shadow);
- drbg_restore_shadow(drbg, &shadow);
return len;
}
@@ -1442,19 +1426,68 @@ static int drbg_generate_long(struct drbg_state *drbg,
unsigned char *buf, unsigned int buflen,
struct drbg_string *addtl)
{
- int len = 0;
+ unsigned int len = 0;
unsigned int slice = 0;
do {
- int tmplen = 0;
+ int err = 0;
unsigned int chunk = 0;
slice = ((buflen - len) / drbg_max_request_bytes(drbg));
chunk = slice ? drbg_max_request_bytes(drbg) : (buflen - len);
- tmplen = drbg_generate(drbg, buf + len, chunk, addtl);
- if (0 >= tmplen)
- return tmplen;
- len += tmplen;
+ mutex_lock(&drbg->drbg_mutex);
+ err = drbg_generate(drbg, buf + len, chunk, addtl);
+ mutex_unlock(&drbg->drbg_mutex);
+ if (0 > err)
+ return err;
+ len += chunk;
} while (slice > 0 && (len < buflen));
- return len;
+ return 0;
+}
+
+static void drbg_schedule_async_seed(struct random_ready_callback *rdy)
+{
+ struct drbg_state *drbg = container_of(rdy, struct drbg_state,
+ random_ready);
+
+ schedule_work(&drbg->seed_work);
+}
+
+static int drbg_prepare_hrng(struct drbg_state *drbg)
+{
+ int err;
+
+ /* We do not need an HRNG in test mode. */
+ if (list_empty(&drbg->test_data.list))
+ return 0;
+
+ INIT_WORK(&drbg->seed_work, drbg_async_seed);
+
+ drbg->random_ready.owner = THIS_MODULE;
+ drbg->random_ready.func = drbg_schedule_async_seed;
+
+ err = add_random_ready_callback(&drbg->random_ready);
+
+ switch (err) {
+ case 0:
+ break;
+
+ case -EALREADY:
+ err = 0;
+ /* fall through */
+
+ default:
+ drbg->random_ready.func = NULL;
+ return err;
+ }
+
+ drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0);
+
+ /*
+ * Require frequent reseeds until the seed source is fully
+ * initialized.
+ */
+ drbg->reseed_threshold = 50;
+
+ return err;
}
/*
@@ -1477,32 +1510,12 @@ static int drbg_generate_long(struct drbg_state *drbg,
static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,
int coreref, bool pr)
{
- int ret = -ENOMEM;
+ int ret;
+ bool reseed = true;
pr_devel("DRBG: Initializing DRBG core %d with prediction resistance "
"%s\n", coreref, pr ? "enabled" : "disabled");
- drbg->core = &drbg_cores[coreref];
- drbg->pr = pr;
- drbg->seeded = false;
- switch (drbg->core->flags & DRBG_TYPE_MASK) {
-#ifdef CONFIG_CRYPTO_DRBG_HMAC
- case DRBG_HMAC:
- drbg->d_ops = &drbg_hmac_ops;
- break;
-#endif /* CONFIG_CRYPTO_DRBG_HMAC */
-#ifdef CONFIG_CRYPTO_DRBG_HASH
- case DRBG_HASH:
- drbg->d_ops = &drbg_hash_ops;
- break;
-#endif /* CONFIG_CRYPTO_DRBG_HASH */
-#ifdef CONFIG_CRYPTO_DRBG_CTR
- case DRBG_CTR:
- drbg->d_ops = &drbg_ctr_ops;
- break;
-#endif /* CONFIG_CRYPTO_DRBG_CTR */
- default:
- return -EOPNOTSUPP;
- }
+ mutex_lock(&drbg->drbg_mutex);
/* 9.1 step 1 is implicit with the selected DRBG type */
@@ -1514,22 +1527,52 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,
/* 9.1 step 4 is implicit in drbg_sec_strength */
- ret = drbg_alloc_state(drbg);
- if (ret)
- return ret;
+ if (!drbg->core) {
+ drbg->core = &drbg_cores[coreref];
+ drbg->pr = pr;
+ drbg->seeded = false;
+ drbg->reseed_threshold = drbg_max_requests(drbg);
- ret = -EFAULT;
- if (drbg->d_ops->crypto_init(drbg))
- goto err;
- ret = drbg_seed(drbg, pers, false);
- drbg->d_ops->crypto_fini(drbg);
- if (ret)
- goto err;
+ ret = drbg_alloc_state(drbg);
+ if (ret)
+ goto unlock;
- return 0;
+ ret = -EFAULT;
+ if (drbg->d_ops->crypto_init(drbg))
+ goto err;
+
+ ret = drbg_prepare_hrng(drbg);
+ if (ret)
+ goto free_everything;
+
+ if (IS_ERR(drbg->jent)) {
+ ret = PTR_ERR(drbg->jent);
+ drbg->jent = NULL;
+ if (fips_enabled || ret != -ENOENT)
+ goto free_everything;
+ pr_info("DRBG: Continuing without Jitter RNG\n");
+ }
+
+ reseed = false;
+ }
+
+ ret = drbg_seed(drbg, pers, reseed);
+
+ if (ret && !reseed)
+ goto free_everything;
+
+ mutex_unlock(&drbg->drbg_mutex);
+ return ret;
err:
drbg_dealloc_state(drbg);
+unlock:
+ mutex_unlock(&drbg->drbg_mutex);
+ return ret;
+
+free_everything:
+ mutex_unlock(&drbg->drbg_mutex);
+ drbg_uninstantiate(drbg);
return ret;
}
@@ -1544,10 +1587,17 @@ err:
*/
static int drbg_uninstantiate(struct drbg_state *drbg)
{
- spin_lock_bh(&drbg->drbg_lock);
+ if (drbg->random_ready.func) {
+ del_random_ready_callback(&drbg->random_ready);
+ cancel_work_sync(&drbg->seed_work);
+ crypto_free_rng(drbg->jent);
+ drbg->jent = NULL;
+ }
+
+ if (drbg->d_ops)
+ drbg->d_ops->crypto_fini(drbg);
drbg_dealloc_state(drbg);
/* no scrubbing of test_data -- this shall survive an uninstantiate */
- spin_unlock_bh(&drbg->drbg_lock);
return 0;
}
@@ -1555,16 +1605,17 @@ static int drbg_uninstantiate(struct drbg_state *drbg)
* Helper function for setting the test data in the DRBG
*
* @drbg DRBG state handle
- * @test_data test data to sets
+ * @data test data
+ * @len test data length
*/
-static inline void drbg_set_testdata(struct drbg_state *drbg,
- struct drbg_test_data *test_data)
+static void drbg_kcapi_set_entropy(struct crypto_rng *tfm,
+ const u8 *data, unsigned int len)
{
- if (!test_data || !test_data->testentropy)
- return;
- spin_lock_bh(&drbg->drbg_lock);
- drbg->test_data = test_data;
- spin_unlock_bh(&drbg->drbg_lock);
+ struct drbg_state *drbg = crypto_rng_ctx(tfm);
+
+ mutex_lock(&drbg->drbg_mutex);
+ drbg_string_fill(&drbg->test_data, data, len);
+ mutex_unlock(&drbg->drbg_mutex);
}
/***************************************************************
@@ -1584,7 +1635,8 @@ static int drbg_init_hash_kernel(struct drbg_state *drbg)
tfm = crypto_alloc_shash(drbg->core->backend_cra_name, 0, 0);
if (IS_ERR(tfm)) {
- pr_info("DRBG: could not allocate digest TFM handle\n");
+ pr_info("DRBG: could not allocate digest TFM handle: %s\n",
+ drbg->core->backend_cra_name);
return PTR_ERR(tfm);
}
BUG_ON(drbg_blocklen(drbg) != crypto_shash_digestsize(tfm));
@@ -1635,7 +1687,8 @@ static int drbg_init_sym_kernel(struct drbg_state *drbg)
tfm = crypto_alloc_cipher(drbg->core->backend_cra_name, 0, 0);
if (IS_ERR(tfm)) {
- pr_info("DRBG: could not allocate cipher TFM handle\n");
+ pr_info("DRBG: could not allocate cipher TFM handle: %s\n",
+ drbg->core->backend_cra_name);
return PTR_ERR(tfm);
}
BUG_ON(drbg_blocklen(drbg) != crypto_cipher_blocksize(tfm));
@@ -1714,15 +1767,10 @@ static inline void drbg_convert_tfm_core(const char *cra_driver_name,
static int drbg_kcapi_init(struct crypto_tfm *tfm)
{
struct drbg_state *drbg = crypto_tfm_ctx(tfm);
- bool pr = false;
- int coreref = 0;
- drbg_convert_tfm_core(crypto_tfm_alg_driver_name(tfm), &coreref, &pr);
- /*
- * when personalization string is needed, the caller must call reset
- * and provide the personalization string as seed information
- */
- return drbg_instantiate(drbg, NULL, coreref, pr);
+ mutex_init(&drbg->drbg_mutex);
+
+ return 0;
}
static void drbg_kcapi_cleanup(struct crypto_tfm *tfm)
@@ -1734,65 +1782,49 @@ static void drbg_kcapi_cleanup(struct crypto_tfm *tfm)
* Generate random numbers invoked by the kernel crypto API:
* The API of the kernel crypto API is extended as follows:
*
- * If dlen is larger than zero, rdata is interpreted as the output buffer
- * where random data is to be stored.
- *
- * If dlen is zero, rdata is interpreted as a pointer to a struct drbg_gen
- * which holds the additional information string that is used for the
- * DRBG generation process. The output buffer that is to be used to store
- * data is also pointed to by struct drbg_gen.
+ * src is additional input supplied to the RNG.
+ * slen is the length of src.
+ * dst is the output buffer where random data is to be stored.
+ * dlen is the length of dst.
*/
-static int drbg_kcapi_random(struct crypto_rng *tfm, u8 *rdata,
- unsigned int dlen)
+static int drbg_kcapi_random(struct crypto_rng *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int dlen)
{
struct drbg_state *drbg = crypto_rng_ctx(tfm);
- if (0 < dlen) {
- return drbg_generate_long(drbg, rdata, dlen, NULL);
- } else {
- struct drbg_gen *data = (struct drbg_gen *)rdata;
- struct drbg_string addtl;
- /* catch NULL pointer */
- if (!data)
- return 0;
- drbg_set_testdata(drbg, data->test_data);
+ struct drbg_string *addtl = NULL;
+ struct drbg_string string;
+
+ if (slen) {
/* linked list variable is now local to allow modification */
- drbg_string_fill(&addtl, data->addtl->buf, data->addtl->len);
- return drbg_generate_long(drbg, data->outbuf, data->outlen,
- &addtl);
+ drbg_string_fill(&string, src, slen);
+ addtl = &string;
}
+
+ return drbg_generate_long(drbg, dst, dlen, addtl);
}
/*
- * Reset the DRBG invoked by the kernel crypto API
- * The reset implies a full re-initialization of the DRBG. Similar to the
- * generate function of drbg_kcapi_random, this function extends the
- * kernel crypto API interface with struct drbg_gen
+ * Seed the DRBG invoked by the kernel crypto API
*/
-static int drbg_kcapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+static int drbg_kcapi_seed(struct crypto_rng *tfm,
+ const u8 *seed, unsigned int slen)
{
struct drbg_state *drbg = crypto_rng_ctx(tfm);
struct crypto_tfm *tfm_base = crypto_rng_tfm(tfm);
bool pr = false;
- struct drbg_string seed_string;
+ struct drbg_string string;
+ struct drbg_string *seed_string = NULL;
int coreref = 0;
- drbg_uninstantiate(drbg);
drbg_convert_tfm_core(crypto_tfm_alg_driver_name(tfm_base), &coreref,
&pr);
if (0 < slen) {
- drbg_string_fill(&seed_string, seed, slen);
- return drbg_instantiate(drbg, &seed_string, coreref, pr);
- } else {
- struct drbg_gen *data = (struct drbg_gen *)seed;
- /* allow invocation of API call with NULL, 0 */
- if (!data)
- return drbg_instantiate(drbg, NULL, coreref, pr);
- drbg_set_testdata(drbg, data->test_data);
- /* linked list variable is now local to allow modification */
- drbg_string_fill(&seed_string, data->addtl->buf,
- data->addtl->len);
- return drbg_instantiate(drbg, &seed_string, coreref, pr);
+ drbg_string_fill(&string, seed, slen);
+ seed_string = &string;
}
+
+ return drbg_instantiate(drbg, seed_string, coreref, pr);
}
/***************************************************************
@@ -1811,7 +1843,6 @@ static int drbg_kcapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
*/
static inline int __init drbg_healthcheck_sanity(void)
{
-#ifdef CONFIG_CRYPTO_FIPS
int len = 0;
#define OUTBUFLEN 16
unsigned char buf[OUTBUFLEN];
@@ -1839,6 +1870,8 @@ static inline int __init drbg_healthcheck_sanity(void)
if (!drbg)
return -ENOMEM;
+ mutex_init(&drbg->drbg_mutex);
+
/*
* if the following tests fail, it is likely that there is a buffer
* overflow as buf is much smaller than the requested or provided
@@ -1877,37 +1910,33 @@ static inline int __init drbg_healthcheck_sanity(void)
outbuf:
kzfree(drbg);
return rc;
-#else /* CONFIG_CRYPTO_FIPS */
- return 0;
-#endif /* CONFIG_CRYPTO_FIPS */
}
-static struct crypto_alg drbg_algs[22];
+static struct rng_alg drbg_algs[22];
/*
* Fill the array drbg_algs used to register the different DRBGs
* with the kernel crypto API. To fill the array, the information
* from drbg_cores[] is used.
*/
-static inline void __init drbg_fill_array(struct crypto_alg *alg,
+static inline void __init drbg_fill_array(struct rng_alg *alg,
const struct drbg_core *core, int pr)
{
int pos = 0;
- static int priority = 100;
+ static int priority = 200;
- memset(alg, 0, sizeof(struct crypto_alg));
- memcpy(alg->cra_name, "stdrng", 6);
+ memcpy(alg->base.cra_name, "stdrng", 6);
if (pr) {
- memcpy(alg->cra_driver_name, "drbg_pr_", 8);
+ memcpy(alg->base.cra_driver_name, "drbg_pr_", 8);
pos = 8;
} else {
- memcpy(alg->cra_driver_name, "drbg_nopr_", 10);
+ memcpy(alg->base.cra_driver_name, "drbg_nopr_", 10);
pos = 10;
}
- memcpy(alg->cra_driver_name + pos, core->cra_name,
+ memcpy(alg->base.cra_driver_name + pos, core->cra_name,
strlen(core->cra_name));
- alg->cra_priority = priority;
+ alg->base.cra_priority = priority;
priority++;
/*
* If FIPS mode enabled, the selected DRBG shall have the
@@ -1915,17 +1944,16 @@ static inline void __init drbg_fill_array(struct crypto_alg *alg,
* it is selected.
*/
if (fips_enabled)
- alg->cra_priority += 200;
-
- alg->cra_flags = CRYPTO_ALG_TYPE_RNG;
- alg->cra_ctxsize = sizeof(struct drbg_state);
- alg->cra_type = &crypto_rng_type;
- alg->cra_module = THIS_MODULE;
- alg->cra_init = drbg_kcapi_init;
- alg->cra_exit = drbg_kcapi_cleanup;
- alg->cra_u.rng.rng_make_random = drbg_kcapi_random;
- alg->cra_u.rng.rng_reset = drbg_kcapi_reset;
- alg->cra_u.rng.seedsize = 0;
+ alg->base.cra_priority += 200;
+
+ alg->base.cra_ctxsize = sizeof(struct drbg_state);
+ alg->base.cra_module = THIS_MODULE;
+ alg->base.cra_init = drbg_kcapi_init;
+ alg->base.cra_exit = drbg_kcapi_cleanup;
+ alg->generate = drbg_kcapi_random;
+ alg->seed = drbg_kcapi_seed;
+ alg->set_ent = drbg_kcapi_set_entropy;
+ alg->seedsize = 0;
}
static int __init drbg_init(void)
@@ -1958,12 +1986,12 @@ static int __init drbg_init(void)
drbg_fill_array(&drbg_algs[i], &drbg_cores[j], 1);
for (j = 0; ARRAY_SIZE(drbg_cores) > j; j++, i++)
drbg_fill_array(&drbg_algs[i], &drbg_cores[j], 0);
- return crypto_register_algs(drbg_algs, (ARRAY_SIZE(drbg_cores) * 2));
+ return crypto_register_rngs(drbg_algs, (ARRAY_SIZE(drbg_cores) * 2));
}
static void __exit drbg_exit(void)
{
- crypto_unregister_algs(drbg_algs, (ARRAY_SIZE(drbg_cores) * 2));
+ crypto_unregister_rngs(drbg_algs, (ARRAY_SIZE(drbg_cores) * 2));
}
module_init(drbg_init);
@@ -1984,3 +2012,4 @@ MODULE_DESCRIPTION("NIST SP800-90A Deterministic Random Bit Generator (DRBG) "
CRYPTO_DRBG_HASH_STRING
CRYPTO_DRBG_HMAC_STRING
CRYPTO_DRBG_CTR_STRING);
+MODULE_ALIAS_CRYPTO("stdrng");
diff --git a/crypto/echainiv.c b/crypto/echainiv.c
new file mode 100644
index 000000000000..b6e43dc61356
--- /dev/null
+++ b/crypto/echainiv.c
@@ -0,0 +1,312 @@
+/*
+ * echainiv: Encrypted Chain IV Generator
+ *
+ * This generator generates an IV based on a sequence number by xoring it
+ * with a salt and then encrypting it with the same key as used to encrypt
+ * the plain text. This algorithm requires that the block size be equal
+ * to the IV size. It is mainly useful for CBC.
+ *
+ * This generator can only be used by algorithms where authentication
+ * is performed after encryption (i.e., authenc).
+ *
+ * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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 <crypto/internal/geniv.h>
+#include <crypto/null.h>
+#include <crypto/rng.h>
+#include <crypto/scatterwalk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+#define MAX_IV_SIZE 16
+
+struct echainiv_ctx {
+ /* aead_geniv_ctx must be first the element */
+ struct aead_geniv_ctx geniv;
+ struct crypto_blkcipher *null;
+ u8 salt[] __attribute__ ((aligned(__alignof__(u32))));
+};
+
+static DEFINE_PER_CPU(u32 [MAX_IV_SIZE / sizeof(u32)], echainiv_iv);
+
+/* We don't care if we get preempted and read/write IVs from the next CPU. */
+static void echainiv_read_iv(u8 *dst, unsigned size)
+{
+ u32 *a = (u32 *)dst;
+ u32 __percpu *b = echainiv_iv;
+
+ for (; size >= 4; size -= 4) {
+ *a++ = this_cpu_read(*b);
+ b++;
+ }
+}
+
+static void echainiv_write_iv(const u8 *src, unsigned size)
+{
+ const u32 *a = (const u32 *)src;
+ u32 __percpu *b = echainiv_iv;
+
+ for (; size >= 4; size -= 4) {
+ this_cpu_write(*b, *a);
+ a++;
+ b++;
+ }
+}
+
+static void echainiv_encrypt_complete2(struct aead_request *req, int err)
+{
+ struct aead_request *subreq = aead_request_ctx(req);
+ struct crypto_aead *geniv;
+ unsigned int ivsize;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ if (err)
+ goto out;
+
+ geniv = crypto_aead_reqtfm(req);
+ ivsize = crypto_aead_ivsize(geniv);
+
+ echainiv_write_iv(subreq->iv, ivsize);
+
+ if (req->iv != subreq->iv)
+ memcpy(req->iv, subreq->iv, ivsize);
+
+out:
+ if (req->iv != subreq->iv)
+ kzfree(subreq->iv);
+}
+
+static void echainiv_encrypt_complete(struct crypto_async_request *base,
+ int err)
+{
+ struct aead_request *req = base->data;
+
+ echainiv_encrypt_complete2(req, err);
+ aead_request_complete(req, err);
+}
+
+static int echainiv_encrypt(struct aead_request *req)
+{
+ struct crypto_aead *geniv = crypto_aead_reqtfm(req);
+ struct echainiv_ctx *ctx = crypto_aead_ctx(geniv);
+ struct aead_request *subreq = aead_request_ctx(req);
+ crypto_completion_t compl;
+ void *data;
+ u8 *info;
+ unsigned int ivsize = crypto_aead_ivsize(geniv);
+ int err;
+
+ if (req->cryptlen < ivsize)
+ return -EINVAL;
+
+ aead_request_set_tfm(subreq, ctx->geniv.child);
+
+ compl = echainiv_encrypt_complete;
+ data = req;
+ info = req->iv;
+
+ if (req->src != req->dst) {
+ struct blkcipher_desc desc = {
+ .tfm = ctx->null,
+ };
+
+ err = crypto_blkcipher_encrypt(
+ &desc, req->dst, req->src,
+ req->assoclen + req->cryptlen);
+ if (err)
+ return err;
+ }
+
+ if (unlikely(!IS_ALIGNED((unsigned long)info,
+ crypto_aead_alignmask(geniv) + 1))) {
+ info = kmalloc(ivsize, req->base.flags &
+ CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
+ GFP_ATOMIC);
+ if (!info)
+ return -ENOMEM;
+
+ memcpy(info, req->iv, ivsize);
+ }
+
+ aead_request_set_callback(subreq, req->base.flags, compl, data);
+ aead_request_set_crypt(subreq, req->dst, req->dst,
+ req->cryptlen - ivsize, info);
+ aead_request_set_ad(subreq, req->assoclen + ivsize);
+
+ crypto_xor(info, ctx->salt, ivsize);
+ scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1);
+ echainiv_read_iv(info, ivsize);
+
+ err = crypto_aead_encrypt(subreq);
+ echainiv_encrypt_complete2(req, err);
+ return err;
+}
+
+static int echainiv_decrypt(struct aead_request *req)
+{
+ struct crypto_aead *geniv = crypto_aead_reqtfm(req);
+ struct echainiv_ctx *ctx = crypto_aead_ctx(geniv);
+ struct aead_request *subreq = aead_request_ctx(req);
+ crypto_completion_t compl;
+ void *data;
+ unsigned int ivsize = crypto_aead_ivsize(geniv);
+
+ if (req->cryptlen < ivsize + crypto_aead_authsize(geniv))
+ return -EINVAL;
+
+ aead_request_set_tfm(subreq, ctx->geniv.child);
+
+ compl = req->base.complete;
+ data = req->base.data;
+
+ aead_request_set_callback(subreq, req->base.flags, compl, data);
+ aead_request_set_crypt(subreq, req->src, req->dst,
+ req->cryptlen - ivsize, req->iv);
+ aead_request_set_ad(subreq, req->assoclen + ivsize);
+
+ scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0);
+ if (req->src != req->dst)
+ scatterwalk_map_and_copy(req->iv, req->dst,
+ req->assoclen, ivsize, 1);
+
+ return crypto_aead_decrypt(subreq);
+}
+
+static int echainiv_init(struct crypto_tfm *tfm)
+{
+ struct crypto_aead *geniv = __crypto_aead_cast(tfm);
+ struct echainiv_ctx *ctx = crypto_aead_ctx(geniv);
+ int err;
+
+ spin_lock_init(&ctx->geniv.lock);
+
+ crypto_aead_set_reqsize(geniv, sizeof(struct aead_request));
+
+ err = crypto_get_default_rng();
+ if (err)
+ goto out;
+
+ err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
+ crypto_aead_ivsize(geniv));
+ crypto_put_default_rng();
+ if (err)
+ goto out;
+
+ ctx->null = crypto_get_default_null_skcipher();
+ err = PTR_ERR(ctx->null);
+ if (IS_ERR(ctx->null))
+ goto out;
+
+ err = aead_geniv_init(tfm);
+ if (err)
+ goto drop_null;
+
+ ctx->geniv.child = geniv->child;
+ geniv->child = geniv;
+
+out:
+ return err;
+
+drop_null:
+ crypto_put_default_null_skcipher();
+ goto out;
+}
+
+static void echainiv_exit(struct crypto_tfm *tfm)
+{
+ struct echainiv_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ crypto_free_aead(ctx->geniv.child);
+ crypto_put_default_null_skcipher();
+}
+
+static int echainiv_aead_create(struct crypto_template *tmpl,
+ struct rtattr **tb)
+{
+ struct aead_instance *inst;
+ struct crypto_aead_spawn *spawn;
+ struct aead_alg *alg;
+ int err;
+
+ inst = aead_geniv_alloc(tmpl, tb, 0, 0);
+
+ if (IS_ERR(inst))
+ return PTR_ERR(inst);
+
+ spawn = aead_instance_ctx(inst);
+ alg = crypto_spawn_aead_alg(spawn);
+
+ if (alg->base.cra_aead.encrypt)
+ goto done;
+
+ err = -EINVAL;
+ if (inst->alg.ivsize & (sizeof(u32) - 1) ||
+ inst->alg.ivsize > MAX_IV_SIZE)
+ goto free_inst;
+
+ inst->alg.encrypt = echainiv_encrypt;
+ inst->alg.decrypt = echainiv_decrypt;
+
+ inst->alg.base.cra_init = echainiv_init;
+ inst->alg.base.cra_exit = echainiv_exit;
+
+ inst->alg.base.cra_alignmask |= __alignof__(u32) - 1;
+ inst->alg.base.cra_ctxsize = sizeof(struct echainiv_ctx);
+ inst->alg.base.cra_ctxsize += inst->alg.ivsize;
+
+done:
+ err = aead_register_instance(tmpl, inst);
+ if (err)
+ goto free_inst;
+
+out:
+ return err;
+
+free_inst:
+ aead_geniv_free(inst);
+ goto out;
+}
+
+static void echainiv_free(struct crypto_instance *inst)
+{
+ aead_geniv_free(aead_instance(inst));
+}
+
+static struct crypto_template echainiv_tmpl = {
+ .name = "echainiv",
+ .create = echainiv_aead_create,
+ .free = echainiv_free,
+ .module = THIS_MODULE,
+};
+
+static int __init echainiv_module_init(void)
+{
+ return crypto_register_template(&echainiv_tmpl);
+}
+
+static void __exit echainiv_module_exit(void)
+{
+ crypto_unregister_template(&echainiv_tmpl);
+}
+
+module_init(echainiv_module_init);
+module_exit(echainiv_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Encrypted Chain IV Generator");
+MODULE_ALIAS_CRYPTO("echainiv");
diff --git a/crypto/eseqiv.c b/crypto/eseqiv.c
index f116fae766f8..16dda72fc4f8 100644
--- a/crypto/eseqiv.c
+++ b/crypto/eseqiv.c
@@ -146,35 +146,13 @@ out:
return err;
}
-static int eseqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
-{
- struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
- struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
- int err = 0;
-
- spin_lock_bh(&ctx->lock);
- if (crypto_ablkcipher_crt(geniv)->givencrypt != eseqiv_givencrypt_first)
- goto unlock;
-
- crypto_ablkcipher_crt(geniv)->givencrypt = eseqiv_givencrypt;
- err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
- crypto_ablkcipher_ivsize(geniv));
-
-unlock:
- spin_unlock_bh(&ctx->lock);
-
- if (err)
- return err;
-
- return eseqiv_givencrypt(req);
-}
-
static int eseqiv_init(struct crypto_tfm *tfm)
{
struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
unsigned long alignmask;
unsigned int reqsize;
+ int err;
spin_lock_init(&ctx->lock);
@@ -198,7 +176,15 @@ static int eseqiv_init(struct crypto_tfm *tfm)
tfm->crt_ablkcipher.reqsize = reqsize +
sizeof(struct ablkcipher_request);
- return skcipher_geniv_init(tfm);
+ err = 0;
+ if (!crypto_get_default_rng()) {
+ crypto_ablkcipher_crt(geniv)->givencrypt = eseqiv_givencrypt;
+ err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
+ crypto_ablkcipher_ivsize(geniv));
+ crypto_put_default_rng();
+ }
+
+ return err ?: skcipher_geniv_init(tfm);
}
static struct crypto_template eseqiv_tmpl;
@@ -208,20 +194,14 @@ static struct crypto_instance *eseqiv_alloc(struct rtattr **tb)
struct crypto_instance *inst;
int err;
- err = crypto_get_default_rng();
- if (err)
- return ERR_PTR(err);
-
inst = skcipher_geniv_alloc(&eseqiv_tmpl, tb, 0, 0);
if (IS_ERR(inst))
- goto put_rng;
+ goto out;
err = -EINVAL;
if (inst->alg.cra_ablkcipher.ivsize != inst->alg.cra_blocksize)
goto free_inst;
- inst->alg.cra_ablkcipher.givencrypt = eseqiv_givencrypt_first;
-
inst->alg.cra_init = eseqiv_init;
inst->alg.cra_exit = skcipher_geniv_exit;
@@ -234,21 +214,13 @@ out:
free_inst:
skcipher_geniv_free(inst);
inst = ERR_PTR(err);
-put_rng:
- crypto_put_default_rng();
goto out;
}
-static void eseqiv_free(struct crypto_instance *inst)
-{
- skcipher_geniv_free(inst);
- crypto_put_default_rng();
-}
-
static struct crypto_template eseqiv_tmpl = {
.name = "eseqiv",
.alloc = eseqiv_alloc,
- .free = eseqiv_free,
+ .free = skcipher_geniv_free,
.module = THIS_MODULE,
};
diff --git a/crypto/fips.c b/crypto/fips.c
index 553970081c62..9d627c1cf8bc 100644
--- a/crypto/fips.c
+++ b/crypto/fips.c
@@ -10,7 +10,12 @@
*
*/
-#include "internal.h"
+#include <linux/export.h>
+#include <linux/fips.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sysctl.h>
int fips_enabled;
EXPORT_SYMBOL_GPL(fips_enabled);
@@ -25,3 +30,49 @@ static int fips_enable(char *str)
}
__setup("fips=", fips_enable);
+
+static struct ctl_table crypto_sysctl_table[] = {
+ {
+ .procname = "fips_enabled",
+ .data = &fips_enabled,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = proc_dointvec
+ },
+ {}
+};
+
+static struct ctl_table crypto_dir_table[] = {
+ {
+ .procname = "crypto",
+ .mode = 0555,
+ .child = crypto_sysctl_table
+ },
+ {}
+};
+
+static struct ctl_table_header *crypto_sysctls;
+
+static void crypto_proc_fips_init(void)
+{
+ crypto_sysctls = register_sysctl_table(crypto_dir_table);
+}
+
+static void crypto_proc_fips_exit(void)
+{
+ unregister_sysctl_table(crypto_sysctls);
+}
+
+static int __init fips_init(void)
+{
+ crypto_proc_fips_init();
+ return 0;
+}
+
+static void __exit fips_exit(void)
+{
+ crypto_proc_fips_exit();
+}
+
+module_init(fips_init);
+module_exit(fips_exit);
diff --git a/crypto/gcm.c b/crypto/gcm.c
index 2e403f6138c1..7d32d4720564 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -12,6 +12,7 @@
#include <crypto/internal/aead.h>
#include <crypto/internal/skcipher.h>
#include <crypto/internal/hash.h>
+#include <crypto/null.h>
#include <crypto/scatterwalk.h>
#include <crypto/hash.h>
#include "internal.h"
@@ -39,7 +40,6 @@ struct crypto_rfc4106_ctx {
struct crypto_rfc4543_instance_ctx {
struct crypto_aead_spawn aead;
- struct crypto_skcipher_spawn null;
};
struct crypto_rfc4543_ctx {
@@ -49,25 +49,22 @@ struct crypto_rfc4543_ctx {
};
struct crypto_rfc4543_req_ctx {
- u8 auth_tag[16];
- u8 assocbuf[32];
- struct scatterlist cipher[1];
- struct scatterlist payload[2];
- struct scatterlist assoc[2];
struct aead_request subreq;
};
struct crypto_gcm_ghash_ctx {
unsigned int cryptlen;
struct scatterlist *src;
- void (*complete)(struct aead_request *req, int err);
+ int (*complete)(struct aead_request *req, u32 flags);
};
struct crypto_gcm_req_priv_ctx {
+ u8 iv[16];
u8 auth_tag[16];
u8 iauth_tag[16];
- struct scatterlist src[2];
- struct scatterlist dst[2];
+ struct scatterlist src[3];
+ struct scatterlist dst[3];
+ struct scatterlist sg;
struct crypto_gcm_ghash_ctx ghash_ctx;
union {
struct ahash_request ahreq;
@@ -80,7 +77,12 @@ struct crypto_gcm_setkey_result {
struct completion completion;
};
-static void *gcm_zeroes;
+static struct {
+ u8 buf[16];
+ struct scatterlist sg;
+} *gcm_zeroes;
+
+static int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc);
static inline struct crypto_gcm_req_priv_ctx *crypto_gcm_reqctx(
struct aead_request *req)
@@ -120,15 +122,13 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
crypto_ablkcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
crypto_ablkcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
- CRYPTO_TFM_REQ_MASK);
-
+ CRYPTO_TFM_REQ_MASK);
err = crypto_ablkcipher_setkey(ctr, key, keylen);
+ crypto_aead_set_flags(aead, crypto_ablkcipher_get_flags(ctr) &
+ CRYPTO_TFM_RES_MASK);
if (err)
return err;
- crypto_aead_set_flags(aead, crypto_ablkcipher_get_flags(ctr) &
- CRYPTO_TFM_RES_MASK);
-
data = kzalloc(sizeof(*data) + crypto_ablkcipher_reqsize(ctr),
GFP_KERNEL);
if (!data)
@@ -163,7 +163,7 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
CRYPTO_TFM_RES_MASK);
out:
- kfree(data);
+ kzfree(data);
return err;
}
@@ -186,35 +186,46 @@ static int crypto_gcm_setauthsize(struct crypto_aead *tfm,
return 0;
}
-static void crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req,
- struct aead_request *req,
- unsigned int cryptlen)
+static void crypto_gcm_init_common(struct aead_request *req)
{
- struct crypto_aead *aead = crypto_aead_reqtfm(req);
- struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
- struct scatterlist *dst;
__be32 counter = cpu_to_be32(1);
+ struct scatterlist *sg;
memset(pctx->auth_tag, 0, sizeof(pctx->auth_tag));
- memcpy(req->iv + 12, &counter, 4);
+ memcpy(pctx->iv, req->iv, 12);
+ memcpy(pctx->iv + 12, &counter, 4);
- sg_init_table(pctx->src, 2);
+ sg_init_table(pctx->src, 3);
sg_set_buf(pctx->src, pctx->auth_tag, sizeof(pctx->auth_tag));
- scatterwalk_sg_chain(pctx->src, 2, req->src);
+ sg = scatterwalk_ffwd(pctx->src + 1, req->src, req->assoclen);
+ if (sg != pctx->src + 1)
+ scatterwalk_sg_chain(pctx->src, 2, sg);
- dst = pctx->src;
if (req->src != req->dst) {
- sg_init_table(pctx->dst, 2);
+ sg_init_table(pctx->dst, 3);
sg_set_buf(pctx->dst, pctx->auth_tag, sizeof(pctx->auth_tag));
- scatterwalk_sg_chain(pctx->dst, 2, req->dst);
- dst = pctx->dst;
+ sg = scatterwalk_ffwd(pctx->dst + 1, req->dst, req->assoclen);
+ if (sg != pctx->dst + 1)
+ scatterwalk_sg_chain(pctx->dst, 2, sg);
}
+}
+
+static void crypto_gcm_init_crypt(struct aead_request *req,
+ unsigned int cryptlen)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
+ struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
+ struct ablkcipher_request *ablk_req = &pctx->u.abreq;
+ struct scatterlist *dst;
+
+ dst = req->src == req->dst ? pctx->src : pctx->dst;
ablkcipher_request_set_tfm(ablk_req, ctx->ctr);
ablkcipher_request_set_crypt(ablk_req, pctx->src, dst,
cryptlen + sizeof(pctx->auth_tag),
- req->iv);
+ pctx->iv);
}
static inline unsigned int gcm_remain(unsigned int len)
@@ -224,41 +235,31 @@ static inline unsigned int gcm_remain(unsigned int len)
}
static void gcm_hash_len_done(struct crypto_async_request *areq, int err);
-static void gcm_hash_final_done(struct crypto_async_request *areq, int err);
static int gcm_hash_update(struct aead_request *req,
- struct crypto_gcm_req_priv_ctx *pctx,
crypto_completion_t compl,
struct scatterlist *src,
- unsigned int len)
+ unsigned int len, u32 flags)
{
+ struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
struct ahash_request *ahreq = &pctx->u.ahreq;
- ahash_request_set_callback(ahreq, aead_request_flags(req),
- compl, req);
+ ahash_request_set_callback(ahreq, flags, compl, req);
ahash_request_set_crypt(ahreq, src, NULL, len);
return crypto_ahash_update(ahreq);
}
static int gcm_hash_remain(struct aead_request *req,
- struct crypto_gcm_req_priv_ctx *pctx,
unsigned int remain,
- crypto_completion_t compl)
+ crypto_completion_t compl, u32 flags)
{
- struct ahash_request *ahreq = &pctx->u.ahreq;
-
- ahash_request_set_callback(ahreq, aead_request_flags(req),
- compl, req);
- sg_init_one(pctx->src, gcm_zeroes, remain);
- ahash_request_set_crypt(ahreq, pctx->src, NULL, remain);
-
- return crypto_ahash_update(ahreq);
+ return gcm_hash_update(req, compl, &gcm_zeroes->sg, remain, flags);
}
-static int gcm_hash_len(struct aead_request *req,
- struct crypto_gcm_req_priv_ctx *pctx)
+static int gcm_hash_len(struct aead_request *req, u32 flags)
{
+ struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
struct ahash_request *ahreq = &pctx->u.ahreq;
struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
u128 lengths;
@@ -266,76 +267,41 @@ static int gcm_hash_len(struct aead_request *req,
lengths.a = cpu_to_be64(req->assoclen * 8);
lengths.b = cpu_to_be64(gctx->cryptlen * 8);
memcpy(pctx->iauth_tag, &lengths, 16);
- sg_init_one(pctx->src, pctx->iauth_tag, 16);
- ahash_request_set_callback(ahreq, aead_request_flags(req),
- gcm_hash_len_done, req);
- ahash_request_set_crypt(ahreq, pctx->src,
- NULL, sizeof(lengths));
+ sg_init_one(&pctx->sg, pctx->iauth_tag, 16);
+ ahash_request_set_callback(ahreq, flags, gcm_hash_len_done, req);
+ ahash_request_set_crypt(ahreq, &pctx->sg,
+ pctx->iauth_tag, sizeof(lengths));
- return crypto_ahash_update(ahreq);
-}
-
-static int gcm_hash_final(struct aead_request *req,
- struct crypto_gcm_req_priv_ctx *pctx)
-{
- struct ahash_request *ahreq = &pctx->u.ahreq;
-
- ahash_request_set_callback(ahreq, aead_request_flags(req),
- gcm_hash_final_done, req);
- ahash_request_set_crypt(ahreq, NULL, pctx->iauth_tag, 0);
-
- return crypto_ahash_final(ahreq);
+ return crypto_ahash_finup(ahreq);
}
-static void __gcm_hash_final_done(struct aead_request *req, int err)
+static int gcm_hash_len_continue(struct aead_request *req, u32 flags)
{
struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
- if (!err)
- crypto_xor(pctx->auth_tag, pctx->iauth_tag, 16);
-
- gctx->complete(req, err);
+ return gctx->complete(req, flags);
}
-static void gcm_hash_final_done(struct crypto_async_request *areq, int err)
+static void gcm_hash_len_done(struct crypto_async_request *areq, int err)
{
struct aead_request *req = areq->data;
- __gcm_hash_final_done(req, err);
-}
-
-static void __gcm_hash_len_done(struct aead_request *req, int err)
-{
- struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
-
- if (!err) {
- err = gcm_hash_final(req, pctx);
- if (err == -EINPROGRESS || err == -EBUSY)
- return;
- }
-
- __gcm_hash_final_done(req, err);
-}
+ if (err)
+ goto out;
-static void gcm_hash_len_done(struct crypto_async_request *areq, int err)
-{
- struct aead_request *req = areq->data;
+ err = gcm_hash_len_continue(req, 0);
+ if (err == -EINPROGRESS)
+ return;
- __gcm_hash_len_done(req, err);
+out:
+ aead_request_complete(req, err);
}
-static void __gcm_hash_crypt_remain_done(struct aead_request *req, int err)
+static int gcm_hash_crypt_remain_continue(struct aead_request *req, u32 flags)
{
- struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
-
- if (!err) {
- err = gcm_hash_len(req, pctx);
- if (err == -EINPROGRESS || err == -EBUSY)
- return;
- }
-
- __gcm_hash_len_done(req, err);
+ return gcm_hash_len(req, flags) ?:
+ gcm_hash_len_continue(req, flags);
}
static void gcm_hash_crypt_remain_done(struct crypto_async_request *areq,
@@ -343,55 +309,58 @@ static void gcm_hash_crypt_remain_done(struct crypto_async_request *areq,
{
struct aead_request *req = areq->data;
- __gcm_hash_crypt_remain_done(req, err);
+ if (err)
+ goto out;
+
+ err = gcm_hash_crypt_remain_continue(req, 0);
+ if (err == -EINPROGRESS)
+ return;
+
+out:
+ aead_request_complete(req, err);
}
-static void __gcm_hash_crypt_done(struct aead_request *req, int err)
+static int gcm_hash_crypt_continue(struct aead_request *req, u32 flags)
{
struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
unsigned int remain;
- if (!err) {
- remain = gcm_remain(gctx->cryptlen);
- BUG_ON(!remain);
- err = gcm_hash_remain(req, pctx, remain,
- gcm_hash_crypt_remain_done);
- if (err == -EINPROGRESS || err == -EBUSY)
- return;
- }
+ remain = gcm_remain(gctx->cryptlen);
+ if (remain)
+ return gcm_hash_remain(req, remain,
+ gcm_hash_crypt_remain_done, flags) ?:
+ gcm_hash_crypt_remain_continue(req, flags);
- __gcm_hash_crypt_remain_done(req, err);
+ return gcm_hash_crypt_remain_continue(req, flags);
}
static void gcm_hash_crypt_done(struct crypto_async_request *areq, int err)
{
struct aead_request *req = areq->data;
- __gcm_hash_crypt_done(req, err);
+ if (err)
+ goto out;
+
+ err = gcm_hash_crypt_continue(req, 0);
+ if (err == -EINPROGRESS)
+ return;
+
+out:
+ aead_request_complete(req, err);
}
-static void __gcm_hash_assoc_remain_done(struct aead_request *req, int err)
+static int gcm_hash_assoc_remain_continue(struct aead_request *req, u32 flags)
{
struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
- crypto_completion_t compl;
- unsigned int remain = 0;
-
- if (!err && gctx->cryptlen) {
- remain = gcm_remain(gctx->cryptlen);
- compl = remain ? gcm_hash_crypt_done :
- gcm_hash_crypt_remain_done;
- err = gcm_hash_update(req, pctx, compl,
- gctx->src, gctx->cryptlen);
- if (err == -EINPROGRESS || err == -EBUSY)
- return;
- }
- if (remain)
- __gcm_hash_crypt_done(req, err);
- else
- __gcm_hash_crypt_remain_done(req, err);
+ if (gctx->cryptlen)
+ return gcm_hash_update(req, gcm_hash_crypt_done,
+ gctx->src, gctx->cryptlen, flags) ?:
+ gcm_hash_crypt_continue(req, flags);
+
+ return gcm_hash_crypt_remain_continue(req, flags);
}
static void gcm_hash_assoc_remain_done(struct crypto_async_request *areq,
@@ -399,146 +368,120 @@ static void gcm_hash_assoc_remain_done(struct crypto_async_request *areq,
{
struct aead_request *req = areq->data;
- __gcm_hash_assoc_remain_done(req, err);
+ if (err)
+ goto out;
+
+ err = gcm_hash_assoc_remain_continue(req, 0);
+ if (err == -EINPROGRESS)
+ return;
+
+out:
+ aead_request_complete(req, err);
}
-static void __gcm_hash_assoc_done(struct aead_request *req, int err)
+static int gcm_hash_assoc_continue(struct aead_request *req, u32 flags)
{
- struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
unsigned int remain;
- if (!err) {
- remain = gcm_remain(req->assoclen);
- BUG_ON(!remain);
- err = gcm_hash_remain(req, pctx, remain,
- gcm_hash_assoc_remain_done);
- if (err == -EINPROGRESS || err == -EBUSY)
- return;
- }
+ remain = gcm_remain(req->assoclen);
+ if (remain)
+ return gcm_hash_remain(req, remain,
+ gcm_hash_assoc_remain_done, flags) ?:
+ gcm_hash_assoc_remain_continue(req, flags);
- __gcm_hash_assoc_remain_done(req, err);
+ return gcm_hash_assoc_remain_continue(req, flags);
}
static void gcm_hash_assoc_done(struct crypto_async_request *areq, int err)
{
struct aead_request *req = areq->data;
- __gcm_hash_assoc_done(req, err);
+ if (err)
+ goto out;
+
+ err = gcm_hash_assoc_continue(req, 0);
+ if (err == -EINPROGRESS)
+ return;
+
+out:
+ aead_request_complete(req, err);
}
-static void __gcm_hash_init_done(struct aead_request *req, int err)
+static int gcm_hash_init_continue(struct aead_request *req, u32 flags)
{
- struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
- crypto_completion_t compl;
- unsigned int remain = 0;
-
- if (!err && req->assoclen) {
- remain = gcm_remain(req->assoclen);
- compl = remain ? gcm_hash_assoc_done :
- gcm_hash_assoc_remain_done;
- err = gcm_hash_update(req, pctx, compl,
- req->assoc, req->assoclen);
- if (err == -EINPROGRESS || err == -EBUSY)
- return;
- }
+ if (req->assoclen)
+ return gcm_hash_update(req, gcm_hash_assoc_done,
+ req->src, req->assoclen, flags) ?:
+ gcm_hash_assoc_continue(req, flags);
- if (remain)
- __gcm_hash_assoc_done(req, err);
- else
- __gcm_hash_assoc_remain_done(req, err);
+ return gcm_hash_assoc_remain_continue(req, flags);
}
static void gcm_hash_init_done(struct crypto_async_request *areq, int err)
{
struct aead_request *req = areq->data;
- __gcm_hash_init_done(req, err);
+ if (err)
+ goto out;
+
+ err = gcm_hash_init_continue(req, 0);
+ if (err == -EINPROGRESS)
+ return;
+
+out:
+ aead_request_complete(req, err);
}
-static int gcm_hash(struct aead_request *req,
- struct crypto_gcm_req_priv_ctx *pctx)
+static int gcm_hash(struct aead_request *req, u32 flags)
{
+ struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
struct ahash_request *ahreq = &pctx->u.ahreq;
- struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
- struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
- unsigned int remain;
- crypto_completion_t compl;
- int err;
+ struct crypto_gcm_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
ahash_request_set_tfm(ahreq, ctx->ghash);
- ahash_request_set_callback(ahreq, aead_request_flags(req),
- gcm_hash_init_done, req);
- err = crypto_ahash_init(ahreq);
- if (err)
- return err;
- remain = gcm_remain(req->assoclen);
- compl = remain ? gcm_hash_assoc_done : gcm_hash_assoc_remain_done;
- err = gcm_hash_update(req, pctx, compl, req->assoc, req->assoclen);
- if (err)
- return err;
- if (remain) {
- err = gcm_hash_remain(req, pctx, remain,
- gcm_hash_assoc_remain_done);
- if (err)
- return err;
- }
- remain = gcm_remain(gctx->cryptlen);
- compl = remain ? gcm_hash_crypt_done : gcm_hash_crypt_remain_done;
- err = gcm_hash_update(req, pctx, compl, gctx->src, gctx->cryptlen);
- if (err)
- return err;
- if (remain) {
- err = gcm_hash_remain(req, pctx, remain,
- gcm_hash_crypt_remain_done);
- if (err)
- return err;
- }
- err = gcm_hash_len(req, pctx);
- if (err)
- return err;
- err = gcm_hash_final(req, pctx);
- if (err)
- return err;
-
- return 0;
+ ahash_request_set_callback(ahreq, flags, gcm_hash_init_done, req);
+ return crypto_ahash_init(ahreq) ?:
+ gcm_hash_init_continue(req, flags);
}
-static void gcm_enc_copy_hash(struct aead_request *req,
- struct crypto_gcm_req_priv_ctx *pctx)
+static int gcm_enc_copy_hash(struct aead_request *req, u32 flags)
{
+ struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
struct crypto_aead *aead = crypto_aead_reqtfm(req);
u8 *auth_tag = pctx->auth_tag;
- scatterwalk_map_and_copy(auth_tag, req->dst, req->cryptlen,
+ crypto_xor(auth_tag, pctx->iauth_tag, 16);
+ scatterwalk_map_and_copy(auth_tag, req->dst,
+ req->assoclen + req->cryptlen,
crypto_aead_authsize(aead), 1);
+ return 0;
}
-static void gcm_enc_hash_done(struct aead_request *req, int err)
+static int gcm_encrypt_continue(struct aead_request *req, u32 flags)
{
struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
+ struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
- if (!err)
- gcm_enc_copy_hash(req, pctx);
+ gctx->src = sg_next(req->src == req->dst ? pctx->src : pctx->dst);
+ gctx->cryptlen = req->cryptlen;
+ gctx->complete = gcm_enc_copy_hash;
- aead_request_complete(req, err);
+ return gcm_hash(req, flags);
}
static void gcm_encrypt_done(struct crypto_async_request *areq, int err)
{
struct aead_request *req = areq->data;
- struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
- if (!err) {
- err = gcm_hash(req, pctx);
- if (err == -EINPROGRESS || err == -EBUSY)
- return;
- else if (!err) {
- crypto_xor(pctx->auth_tag, pctx->iauth_tag, 16);
- gcm_enc_copy_hash(req, pctx);
- }
- }
+ if (err)
+ goto out;
+
+ err = gcm_encrypt_continue(req, 0);
+ if (err == -EINPROGRESS)
+ return;
+out:
aead_request_complete(req, err);
}
@@ -546,34 +489,19 @@ static int crypto_gcm_encrypt(struct aead_request *req)
{
struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
struct ablkcipher_request *abreq = &pctx->u.abreq;
- struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
- int err;
-
- crypto_gcm_init_crypt(abreq, req, req->cryptlen);
- ablkcipher_request_set_callback(abreq, aead_request_flags(req),
- gcm_encrypt_done, req);
-
- gctx->src = req->dst;
- gctx->cryptlen = req->cryptlen;
- gctx->complete = gcm_enc_hash_done;
-
- err = crypto_ablkcipher_encrypt(abreq);
- if (err)
- return err;
-
- err = gcm_hash(req, pctx);
- if (err)
- return err;
+ u32 flags = aead_request_flags(req);
- crypto_xor(pctx->auth_tag, pctx->iauth_tag, 16);
- gcm_enc_copy_hash(req, pctx);
+ crypto_gcm_init_common(req);
+ crypto_gcm_init_crypt(req, req->cryptlen);
+ ablkcipher_request_set_callback(abreq, flags, gcm_encrypt_done, req);
- return 0;
+ return crypto_ablkcipher_encrypt(abreq) ?:
+ gcm_encrypt_continue(req, flags);
}
-static int crypto_gcm_verify(struct aead_request *req,
- struct crypto_gcm_req_priv_ctx *pctx)
+static int crypto_gcm_verify(struct aead_request *req)
{
+ struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
struct crypto_aead *aead = crypto_aead_reqtfm(req);
u8 *auth_tag = pctx->auth_tag;
u8 *iauth_tag = pctx->iauth_tag;
@@ -581,78 +509,57 @@ static int crypto_gcm_verify(struct aead_request *req,
unsigned int cryptlen = req->cryptlen - authsize;
crypto_xor(auth_tag, iauth_tag, 16);
- scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0);
+ scatterwalk_map_and_copy(iauth_tag, req->src,
+ req->assoclen + cryptlen, authsize, 0);
return crypto_memneq(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0;
}
static void gcm_decrypt_done(struct crypto_async_request *areq, int err)
{
struct aead_request *req = areq->data;
- struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
if (!err)
- err = crypto_gcm_verify(req, pctx);
+ err = crypto_gcm_verify(req);
aead_request_complete(req, err);
}
-static void gcm_dec_hash_done(struct aead_request *req, int err)
+static int gcm_dec_hash_continue(struct aead_request *req, u32 flags)
{
struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
struct ablkcipher_request *abreq = &pctx->u.abreq;
struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
- if (!err) {
- ablkcipher_request_set_callback(abreq, aead_request_flags(req),
- gcm_decrypt_done, req);
- crypto_gcm_init_crypt(abreq, req, gctx->cryptlen);
- err = crypto_ablkcipher_decrypt(abreq);
- if (err == -EINPROGRESS || err == -EBUSY)
- return;
- else if (!err)
- err = crypto_gcm_verify(req, pctx);
- }
-
- aead_request_complete(req, err);
+ crypto_gcm_init_crypt(req, gctx->cryptlen);
+ ablkcipher_request_set_callback(abreq, flags, gcm_decrypt_done, req);
+ return crypto_ablkcipher_decrypt(abreq) ?: crypto_gcm_verify(req);
}
static int crypto_gcm_decrypt(struct aead_request *req)
{
struct crypto_aead *aead = crypto_aead_reqtfm(req);
struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
- struct ablkcipher_request *abreq = &pctx->u.abreq;
struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
unsigned int authsize = crypto_aead_authsize(aead);
unsigned int cryptlen = req->cryptlen;
- int err;
+ u32 flags = aead_request_flags(req);
- if (cryptlen < authsize)
- return -EINVAL;
cryptlen -= authsize;
- gctx->src = req->src;
- gctx->cryptlen = cryptlen;
- gctx->complete = gcm_dec_hash_done;
-
- err = gcm_hash(req, pctx);
- if (err)
- return err;
+ crypto_gcm_init_common(req);
- ablkcipher_request_set_callback(abreq, aead_request_flags(req),
- gcm_decrypt_done, req);
- crypto_gcm_init_crypt(abreq, req, cryptlen);
- err = crypto_ablkcipher_decrypt(abreq);
- if (err)
- return err;
+ gctx->src = sg_next(pctx->src);
+ gctx->cryptlen = cryptlen;
+ gctx->complete = gcm_dec_hash_continue;
- return crypto_gcm_verify(req, pctx);
+ return gcm_hash(req, flags);
}
-static int crypto_gcm_init_tfm(struct crypto_tfm *tfm)
+static int crypto_gcm_init_tfm(struct crypto_aead *tfm)
{
- struct crypto_instance *inst = (void *)tfm->__crt_alg;
- struct gcm_instance_ctx *ictx = crypto_instance_ctx(inst);
- struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct aead_instance *inst = aead_alg_instance(tfm);
+ struct gcm_instance_ctx *ictx = aead_instance_ctx(inst);
+ struct crypto_gcm_ctx *ctx = crypto_aead_ctx(tfm);
struct crypto_ablkcipher *ctr;
struct crypto_ahash *ghash;
unsigned long align;
@@ -670,14 +577,14 @@ static int crypto_gcm_init_tfm(struct crypto_tfm *tfm)
ctx->ctr = ctr;
ctx->ghash = ghash;
- align = crypto_tfm_alg_alignmask(tfm);
+ align = crypto_aead_alignmask(tfm);
align &= ~(crypto_tfm_ctx_alignment() - 1);
- tfm->crt_aead.reqsize = align +
- offsetof(struct crypto_gcm_req_priv_ctx, u) +
+ crypto_aead_set_reqsize(tfm,
+ align + offsetof(struct crypto_gcm_req_priv_ctx, u) +
max(sizeof(struct ablkcipher_request) +
crypto_ablkcipher_reqsize(ctr),
sizeof(struct ahash_request) +
- crypto_ahash_reqsize(ghash));
+ crypto_ahash_reqsize(ghash)));
return 0;
@@ -686,53 +593,59 @@ err_free_hash:
return err;
}
-static void crypto_gcm_exit_tfm(struct crypto_tfm *tfm)
+static void crypto_gcm_exit_tfm(struct crypto_aead *tfm)
{
- struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_gcm_ctx *ctx = crypto_aead_ctx(tfm);
crypto_free_ahash(ctx->ghash);
crypto_free_ablkcipher(ctx->ctr);
}
-static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb,
- const char *full_name,
- const char *ctr_name,
- const char *ghash_name)
+static int crypto_gcm_create_common(struct crypto_template *tmpl,
+ struct rtattr **tb,
+ const char *full_name,
+ const char *ctr_name,
+ const char *ghash_name)
{
struct crypto_attr_type *algt;
- struct crypto_instance *inst;
+ struct aead_instance *inst;
struct crypto_alg *ctr;
struct crypto_alg *ghash_alg;
- struct ahash_alg *ghash_ahash_alg;
+ struct hash_alg_common *ghash;
struct gcm_instance_ctx *ctx;
int err;
algt = crypto_get_attr_type(tb);
if (IS_ERR(algt))
- return ERR_CAST(algt);
+ return PTR_ERR(algt);
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
ghash_alg = crypto_find_alg(ghash_name, &crypto_ahash_type,
CRYPTO_ALG_TYPE_HASH,
CRYPTO_ALG_TYPE_AHASH_MASK);
if (IS_ERR(ghash_alg))
- return ERR_CAST(ghash_alg);
+ return PTR_ERR(ghash_alg);
+
+ ghash = __crypto_hash_alg_common(ghash_alg);
err = -ENOMEM;
inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
if (!inst)
goto out_put_ghash;
- ctx = crypto_instance_ctx(inst);
- ghash_ahash_alg = container_of(ghash_alg, struct ahash_alg, halg.base);
- err = crypto_init_ahash_spawn(&ctx->ghash, &ghash_ahash_alg->halg,
- inst);
+ ctx = aead_instance_ctx(inst);
+ err = crypto_init_ahash_spawn(&ctx->ghash, ghash,
+ aead_crypto_instance(inst));
if (err)
goto err_free_inst;
- crypto_set_skcipher_spawn(&ctx->ctr, inst);
+ err = -EINVAL;
+ if (ghash->digestsize != 16)
+ goto err_drop_ghash;
+
+ crypto_set_skcipher_spawn(&ctx->ctr, aead_crypto_instance(inst));
err = crypto_grab_skcipher(&ctx->ctr, ctr_name, 0,
crypto_requires_sync(algt->type,
algt->mask));
@@ -751,33 +664,38 @@ static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb,
goto out_put_ctr;
err = -ENAMETOOLONG;
- if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+ if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
"gcm_base(%s,%s)", ctr->cra_driver_name,
ghash_alg->cra_driver_name) >=
CRYPTO_MAX_ALG_NAME)
goto out_put_ctr;
- memcpy(inst->alg.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
-
- inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
- inst->alg.cra_flags |= ctr->cra_flags & CRYPTO_ALG_ASYNC;
- inst->alg.cra_priority = ctr->cra_priority;
- inst->alg.cra_blocksize = 1;
- inst->alg.cra_alignmask = ctr->cra_alignmask | (__alignof__(u64) - 1);
- inst->alg.cra_type = &crypto_aead_type;
- inst->alg.cra_aead.ivsize = 16;
- inst->alg.cra_aead.maxauthsize = 16;
- inst->alg.cra_ctxsize = sizeof(struct crypto_gcm_ctx);
- inst->alg.cra_init = crypto_gcm_init_tfm;
- inst->alg.cra_exit = crypto_gcm_exit_tfm;
- inst->alg.cra_aead.setkey = crypto_gcm_setkey;
- inst->alg.cra_aead.setauthsize = crypto_gcm_setauthsize;
- inst->alg.cra_aead.encrypt = crypto_gcm_encrypt;
- inst->alg.cra_aead.decrypt = crypto_gcm_decrypt;
+ memcpy(inst->alg.base.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
+
+ inst->alg.base.cra_flags = (ghash->base.cra_flags | ctr->cra_flags) &
+ CRYPTO_ALG_ASYNC;
+ inst->alg.base.cra_priority = (ghash->base.cra_priority +
+ ctr->cra_priority) / 2;
+ inst->alg.base.cra_blocksize = 1;
+ inst->alg.base.cra_alignmask = ghash->base.cra_alignmask |
+ ctr->cra_alignmask;
+ inst->alg.base.cra_ctxsize = sizeof(struct crypto_gcm_ctx);
+ inst->alg.ivsize = 12;
+ inst->alg.maxauthsize = 16;
+ inst->alg.init = crypto_gcm_init_tfm;
+ inst->alg.exit = crypto_gcm_exit_tfm;
+ inst->alg.setkey = crypto_gcm_setkey;
+ inst->alg.setauthsize = crypto_gcm_setauthsize;
+ inst->alg.encrypt = crypto_gcm_encrypt;
+ inst->alg.decrypt = crypto_gcm_decrypt;
+
+ err = aead_register_instance(tmpl, inst);
+ if (err)
+ goto out_put_ctr;
-out:
+out_put_ghash:
crypto_mod_put(ghash_alg);
- return inst;
+ return err;
out_put_ctr:
crypto_drop_skcipher(&ctx->ctr);
@@ -785,12 +703,10 @@ err_drop_ghash:
crypto_drop_ahash(&ctx->ghash);
err_free_inst:
kfree(inst);
-out_put_ghash:
- inst = ERR_PTR(err);
- goto out;
+ goto out_put_ghash;
}
-static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb)
+static int crypto_gcm_create(struct crypto_template *tmpl, struct rtattr **tb)
{
const char *cipher_name;
char ctr_name[CRYPTO_MAX_ALG_NAME];
@@ -798,17 +714,18 @@ static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb)
cipher_name = crypto_attr_alg_name(tb[1]);
if (IS_ERR(cipher_name))
- return ERR_CAST(cipher_name);
+ return PTR_ERR(cipher_name);
if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >=
CRYPTO_MAX_ALG_NAME)
- return ERR_PTR(-ENAMETOOLONG);
+ return -ENAMETOOLONG;
if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >=
CRYPTO_MAX_ALG_NAME)
- return ERR_PTR(-ENAMETOOLONG);
+ return -ENAMETOOLONG;
- return crypto_gcm_alloc_common(tb, full_name, ctr_name, "ghash");
+ return crypto_gcm_create_common(tmpl, tb, full_name,
+ ctr_name, "ghash");
}
static void crypto_gcm_free(struct crypto_instance *inst)
@@ -817,17 +734,18 @@ static void crypto_gcm_free(struct crypto_instance *inst)
crypto_drop_skcipher(&ctx->ctr);
crypto_drop_ahash(&ctx->ghash);
- kfree(inst);
+ kfree(aead_instance(inst));
}
static struct crypto_template crypto_gcm_tmpl = {
.name = "gcm",
- .alloc = crypto_gcm_alloc,
+ .create = crypto_gcm_create,
.free = crypto_gcm_free,
.module = THIS_MODULE,
};
-static struct crypto_instance *crypto_gcm_base_alloc(struct rtattr **tb)
+static int crypto_gcm_base_create(struct crypto_template *tmpl,
+ struct rtattr **tb)
{
const char *ctr_name;
const char *ghash_name;
@@ -835,22 +753,23 @@ static struct crypto_instance *crypto_gcm_base_alloc(struct rtattr **tb)
ctr_name = crypto_attr_alg_name(tb[1]);
if (IS_ERR(ctr_name))
- return ERR_CAST(ctr_name);
+ return PTR_ERR(ctr_name);
ghash_name = crypto_attr_alg_name(tb[2]);
if (IS_ERR(ghash_name))
- return ERR_CAST(ghash_name);
+ return PTR_ERR(ghash_name);
if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s,%s)",
ctr_name, ghash_name) >= CRYPTO_MAX_ALG_NAME)
- return ERR_PTR(-ENAMETOOLONG);
+ return -ENAMETOOLONG;
- return crypto_gcm_alloc_common(tb, full_name, ctr_name, ghash_name);
+ return crypto_gcm_create_common(tmpl, tb, full_name,
+ ctr_name, ghash_name);
}
static struct crypto_template crypto_gcm_base_tmpl = {
.name = "gcm_base",
- .alloc = crypto_gcm_base_alloc,
+ .create = crypto_gcm_base_create,
.free = crypto_gcm_free,
.module = THIS_MODULE,
};
@@ -911,7 +830,7 @@ static struct aead_request *crypto_rfc4106_crypt(struct aead_request *req)
aead_request_set_callback(subreq, req->base.flags, req->base.complete,
req->base.data);
aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, iv);
- aead_request_set_assoc(subreq, req->assoc, req->assoclen);
+ aead_request_set_ad(subreq, req->assoclen);
return subreq;
}
@@ -930,11 +849,11 @@ static int crypto_rfc4106_decrypt(struct aead_request *req)
return crypto_aead_decrypt(req);
}
-static int crypto_rfc4106_init_tfm(struct crypto_tfm *tfm)
+static int crypto_rfc4106_init_tfm(struct crypto_aead *tfm)
{
- struct crypto_instance *inst = (void *)tfm->__crt_alg;
- struct crypto_aead_spawn *spawn = crypto_instance_ctx(inst);
- struct crypto_rfc4106_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct aead_instance *inst = aead_alg_instance(tfm);
+ struct crypto_aead_spawn *spawn = aead_instance_ctx(inst);
+ struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(tfm);
struct crypto_aead *aead;
unsigned long align;
@@ -946,126 +865,120 @@ static int crypto_rfc4106_init_tfm(struct crypto_tfm *tfm)
align = crypto_aead_alignmask(aead);
align &= ~(crypto_tfm_ctx_alignment() - 1);
- tfm->crt_aead.reqsize = sizeof(struct aead_request) +
- ALIGN(crypto_aead_reqsize(aead),
- crypto_tfm_ctx_alignment()) +
- align + 16;
+ crypto_aead_set_reqsize(
+ tfm,
+ sizeof(struct aead_request) +
+ ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) +
+ align + 12);
return 0;
}
-static void crypto_rfc4106_exit_tfm(struct crypto_tfm *tfm)
+static void crypto_rfc4106_exit_tfm(struct crypto_aead *tfm)
{
- struct crypto_rfc4106_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(tfm);
crypto_free_aead(ctx->child);
}
-static struct crypto_instance *crypto_rfc4106_alloc(struct rtattr **tb)
+static int crypto_rfc4106_create(struct crypto_template *tmpl,
+ struct rtattr **tb)
{
struct crypto_attr_type *algt;
- struct crypto_instance *inst;
+ struct aead_instance *inst;
struct crypto_aead_spawn *spawn;
- struct crypto_alg *alg;
+ struct aead_alg *alg;
const char *ccm_name;
int err;
algt = crypto_get_attr_type(tb);
if (IS_ERR(algt))
- return ERR_CAST(algt);
+ return PTR_ERR(algt);
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
ccm_name = crypto_attr_alg_name(tb[1]);
if (IS_ERR(ccm_name))
- return ERR_CAST(ccm_name);
+ return PTR_ERR(ccm_name);
inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
if (!inst)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
- spawn = crypto_instance_ctx(inst);
- crypto_set_aead_spawn(spawn, inst);
+ spawn = aead_instance_ctx(inst);
+ crypto_set_aead_spawn(spawn, aead_crypto_instance(inst));
err = crypto_grab_aead(spawn, ccm_name, 0,
crypto_requires_sync(algt->type, algt->mask));
if (err)
goto out_free_inst;
- alg = crypto_aead_spawn_alg(spawn);
+ alg = crypto_spawn_aead_alg(spawn);
err = -EINVAL;
- /* We only support 16-byte blocks. */
- if (alg->cra_aead.ivsize != 16)
+ /* Underlying IV size must be 12. */
+ if (crypto_aead_alg_ivsize(alg) != 12)
goto out_drop_alg;
/* Not a stream cipher? */
- if (alg->cra_blocksize != 1)
+ if (alg->base.cra_blocksize != 1)
goto out_drop_alg;
err = -ENAMETOOLONG;
- if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
- "rfc4106(%s)", alg->cra_name) >= CRYPTO_MAX_ALG_NAME ||
- snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
- "rfc4106(%s)", alg->cra_driver_name) >=
+ if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
+ "rfc4106(%s)", alg->base.cra_name) >=
+ CRYPTO_MAX_ALG_NAME ||
+ snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+ "rfc4106(%s)", alg->base.cra_driver_name) >=
CRYPTO_MAX_ALG_NAME)
goto out_drop_alg;
- inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
- inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
- inst->alg.cra_priority = alg->cra_priority;
- inst->alg.cra_blocksize = 1;
- inst->alg.cra_alignmask = alg->cra_alignmask;
- inst->alg.cra_type = &crypto_nivaead_type;
+ inst->alg.base.cra_flags |= alg->base.cra_flags & CRYPTO_ALG_ASYNC;
+ inst->alg.base.cra_priority = alg->base.cra_priority;
+ inst->alg.base.cra_blocksize = 1;
+ inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
- inst->alg.cra_aead.ivsize = 8;
- inst->alg.cra_aead.maxauthsize = 16;
+ inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4106_ctx);
- inst->alg.cra_ctxsize = sizeof(struct crypto_rfc4106_ctx);
+ inst->alg.ivsize = 8;
+ inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);
- inst->alg.cra_init = crypto_rfc4106_init_tfm;
- inst->alg.cra_exit = crypto_rfc4106_exit_tfm;
+ inst->alg.init = crypto_rfc4106_init_tfm;
+ inst->alg.exit = crypto_rfc4106_exit_tfm;
- inst->alg.cra_aead.setkey = crypto_rfc4106_setkey;
- inst->alg.cra_aead.setauthsize = crypto_rfc4106_setauthsize;
- inst->alg.cra_aead.encrypt = crypto_rfc4106_encrypt;
- inst->alg.cra_aead.decrypt = crypto_rfc4106_decrypt;
+ inst->alg.setkey = crypto_rfc4106_setkey;
+ inst->alg.setauthsize = crypto_rfc4106_setauthsize;
+ inst->alg.encrypt = crypto_rfc4106_encrypt;
+ inst->alg.decrypt = crypto_rfc4106_decrypt;
- inst->alg.cra_aead.geniv = "seqiv";
+ err = aead_register_instance(tmpl, inst);
+ if (err)
+ goto out_drop_alg;
out:
- return inst;
+ return err;
out_drop_alg:
crypto_drop_aead(spawn);
out_free_inst:
kfree(inst);
- inst = ERR_PTR(err);
goto out;
}
static void crypto_rfc4106_free(struct crypto_instance *inst)
{
- crypto_drop_spawn(crypto_instance_ctx(inst));
- kfree(inst);
+ crypto_drop_aead(crypto_instance_ctx(inst));
+ kfree(aead_instance(inst));
}
static struct crypto_template crypto_rfc4106_tmpl = {
.name = "rfc4106",
- .alloc = crypto_rfc4106_alloc,
+ .create = crypto_rfc4106_create,
.free = crypto_rfc4106_free,
.module = THIS_MODULE,
};
-static inline struct crypto_rfc4543_req_ctx *crypto_rfc4543_reqctx(
- struct aead_request *req)
-{
- unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req));
-
- return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1);
-}
-
static int crypto_rfc4543_setkey(struct crypto_aead *parent, const u8 *key,
unsigned int keylen)
{
@@ -1100,83 +1013,35 @@ static int crypto_rfc4543_setauthsize(struct crypto_aead *parent,
return crypto_aead_setauthsize(ctx->child, authsize);
}
-static void crypto_rfc4543_done(struct crypto_async_request *areq, int err)
-{
- struct aead_request *req = areq->data;
- struct crypto_aead *aead = crypto_aead_reqtfm(req);
- struct crypto_rfc4543_req_ctx *rctx = crypto_rfc4543_reqctx(req);
-
- if (!err) {
- scatterwalk_map_and_copy(rctx->auth_tag, req->dst,
- req->cryptlen,
- crypto_aead_authsize(aead), 1);
- }
-
- aead_request_complete(req, err);
-}
-
-static struct aead_request *crypto_rfc4543_crypt(struct aead_request *req,
- bool enc)
+static int crypto_rfc4543_crypt(struct aead_request *req, bool enc)
{
struct crypto_aead *aead = crypto_aead_reqtfm(req);
struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead);
- struct crypto_rfc4543_req_ctx *rctx = crypto_rfc4543_reqctx(req);
+ struct crypto_rfc4543_req_ctx *rctx = aead_request_ctx(req);
struct aead_request *subreq = &rctx->subreq;
- struct scatterlist *src = req->src;
- struct scatterlist *cipher = rctx->cipher;
- struct scatterlist *payload = rctx->payload;
- struct scatterlist *assoc = rctx->assoc;
unsigned int authsize = crypto_aead_authsize(aead);
- unsigned int assoclen = req->assoclen;
- struct page *srcp;
- u8 *vsrc;
u8 *iv = PTR_ALIGN((u8 *)(rctx + 1) + crypto_aead_reqsize(ctx->child),
crypto_aead_alignmask(ctx->child) + 1);
+ int err;
+
+ if (req->src != req->dst) {
+ err = crypto_rfc4543_copy_src_to_dst(req, enc);
+ if (err)
+ return err;
+ }
memcpy(iv, ctx->nonce, 4);
memcpy(iv + 4, req->iv, 8);
- /* construct cipher/plaintext */
- if (enc)
- memset(rctx->auth_tag, 0, authsize);
- else
- scatterwalk_map_and_copy(rctx->auth_tag, src,
- req->cryptlen - authsize,
- authsize, 0);
-
- sg_init_one(cipher, rctx->auth_tag, authsize);
-
- /* construct the aad */
- srcp = sg_page(src);
- vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + src->offset;
-
- sg_init_table(payload, 2);
- sg_set_buf(payload, req->iv, 8);
- scatterwalk_crypto_chain(payload, src, vsrc == req->iv + 8, 2);
- assoclen += 8 + req->cryptlen - (enc ? 0 : authsize);
-
- if (req->assoc->length == req->assoclen) {
- sg_init_table(assoc, 2);
- sg_set_page(assoc, sg_page(req->assoc), req->assoc->length,
- req->assoc->offset);
- } else {
- BUG_ON(req->assoclen > sizeof(rctx->assocbuf));
-
- scatterwalk_map_and_copy(rctx->assocbuf, req->assoc, 0,
- req->assoclen, 0);
-
- sg_init_table(assoc, 2);
- sg_set_buf(assoc, rctx->assocbuf, req->assoclen);
- }
- scatterwalk_crypto_chain(assoc, payload, 0, 2);
-
aead_request_set_tfm(subreq, ctx->child);
- aead_request_set_callback(subreq, req->base.flags, crypto_rfc4543_done,
- req);
- aead_request_set_crypt(subreq, cipher, cipher, enc ? 0 : authsize, iv);
- aead_request_set_assoc(subreq, assoc, assoclen);
-
- return subreq;
+ aead_request_set_callback(subreq, req->base.flags,
+ req->base.complete, req->base.data);
+ aead_request_set_crypt(subreq, req->src, req->dst,
+ enc ? 0 : authsize, iv);
+ aead_request_set_ad(subreq, req->assoclen + req->cryptlen -
+ subreq->cryptlen);
+
+ return enc ? crypto_aead_encrypt(subreq) : crypto_aead_decrypt(subreq);
}
static int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc)
@@ -1184,7 +1049,8 @@ static int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc)
struct crypto_aead *aead = crypto_aead_reqtfm(req);
struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead);
unsigned int authsize = crypto_aead_authsize(aead);
- unsigned int nbytes = req->cryptlen - (enc ? 0 : authsize);
+ unsigned int nbytes = req->assoclen + req->cryptlen -
+ (enc ? 0 : authsize);
struct blkcipher_desc desc = {
.tfm = ctx->null,
};
@@ -1194,49 +1060,20 @@ static int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc)
static int crypto_rfc4543_encrypt(struct aead_request *req)
{
- struct crypto_aead *aead = crypto_aead_reqtfm(req);
- struct crypto_rfc4543_req_ctx *rctx = crypto_rfc4543_reqctx(req);
- struct aead_request *subreq;
- int err;
-
- if (req->src != req->dst) {
- err = crypto_rfc4543_copy_src_to_dst(req, true);
- if (err)
- return err;
- }
-
- subreq = crypto_rfc4543_crypt(req, true);
- err = crypto_aead_encrypt(subreq);
- if (err)
- return err;
-
- scatterwalk_map_and_copy(rctx->auth_tag, req->dst, req->cryptlen,
- crypto_aead_authsize(aead), 1);
-
- return 0;
+ return crypto_rfc4543_crypt(req, true);
}
static int crypto_rfc4543_decrypt(struct aead_request *req)
{
- int err;
-
- if (req->src != req->dst) {
- err = crypto_rfc4543_copy_src_to_dst(req, false);
- if (err)
- return err;
- }
-
- req = crypto_rfc4543_crypt(req, false);
-
- return crypto_aead_decrypt(req);
+ return crypto_rfc4543_crypt(req, false);
}
-static int crypto_rfc4543_init_tfm(struct crypto_tfm *tfm)
+static int crypto_rfc4543_init_tfm(struct crypto_aead *tfm)
{
- struct crypto_instance *inst = (void *)tfm->__crt_alg;
- struct crypto_rfc4543_instance_ctx *ictx = crypto_instance_ctx(inst);
+ struct aead_instance *inst = aead_alg_instance(tfm);
+ struct crypto_rfc4543_instance_ctx *ictx = aead_instance_ctx(inst);
struct crypto_aead_spawn *spawn = &ictx->aead;
- struct crypto_rfc4543_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm);
struct crypto_aead *aead;
struct crypto_blkcipher *null;
unsigned long align;
@@ -1246,7 +1083,7 @@ static int crypto_rfc4543_init_tfm(struct crypto_tfm *tfm)
if (IS_ERR(aead))
return PTR_ERR(aead);
- null = crypto_spawn_blkcipher(&ictx->null.base);
+ null = crypto_get_default_null_skcipher();
err = PTR_ERR(null);
if (IS_ERR(null))
goto err_free_aead;
@@ -1256,10 +1093,11 @@ static int crypto_rfc4543_init_tfm(struct crypto_tfm *tfm)
align = crypto_aead_alignmask(aead);
align &= ~(crypto_tfm_ctx_alignment() - 1);
- tfm->crt_aead.reqsize = sizeof(struct crypto_rfc4543_req_ctx) +
- ALIGN(crypto_aead_reqsize(aead),
- crypto_tfm_ctx_alignment()) +
- align + 16;
+ crypto_aead_set_reqsize(
+ tfm,
+ sizeof(struct crypto_rfc4543_req_ctx) +
+ ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) +
+ align + 12);
return 0;
@@ -1268,107 +1106,98 @@ err_free_aead:
return err;
}
-static void crypto_rfc4543_exit_tfm(struct crypto_tfm *tfm)
+static void crypto_rfc4543_exit_tfm(struct crypto_aead *tfm)
{
- struct crypto_rfc4543_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm);
crypto_free_aead(ctx->child);
- crypto_free_blkcipher(ctx->null);
+ crypto_put_default_null_skcipher();
}
-static struct crypto_instance *crypto_rfc4543_alloc(struct rtattr **tb)
+static int crypto_rfc4543_create(struct crypto_template *tmpl,
+ struct rtattr **tb)
{
struct crypto_attr_type *algt;
- struct crypto_instance *inst;
+ struct aead_instance *inst;
struct crypto_aead_spawn *spawn;
- struct crypto_alg *alg;
+ struct aead_alg *alg;
struct crypto_rfc4543_instance_ctx *ctx;
const char *ccm_name;
int err;
algt = crypto_get_attr_type(tb);
if (IS_ERR(algt))
- return ERR_CAST(algt);
+ return PTR_ERR(algt);
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
ccm_name = crypto_attr_alg_name(tb[1]);
if (IS_ERR(ccm_name))
- return ERR_CAST(ccm_name);
+ return PTR_ERR(ccm_name);
inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
if (!inst)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
- ctx = crypto_instance_ctx(inst);
+ ctx = aead_instance_ctx(inst);
spawn = &ctx->aead;
- crypto_set_aead_spawn(spawn, inst);
+ crypto_set_aead_spawn(spawn, aead_crypto_instance(inst));
err = crypto_grab_aead(spawn, ccm_name, 0,
crypto_requires_sync(algt->type, algt->mask));
if (err)
goto out_free_inst;
- alg = crypto_aead_spawn_alg(spawn);
-
- crypto_set_skcipher_spawn(&ctx->null, inst);
- err = crypto_grab_skcipher(&ctx->null, "ecb(cipher_null)", 0,
- CRYPTO_ALG_ASYNC);
- if (err)
- goto out_drop_alg;
-
- crypto_skcipher_spawn_alg(&ctx->null);
+ alg = crypto_spawn_aead_alg(spawn);
err = -EINVAL;
- /* We only support 16-byte blocks. */
- if (alg->cra_aead.ivsize != 16)
- goto out_drop_ecbnull;
+ /* Underlying IV size must be 12. */
+ if (crypto_aead_alg_ivsize(alg) != 12)
+ goto out_drop_alg;
/* Not a stream cipher? */
- if (alg->cra_blocksize != 1)
- goto out_drop_ecbnull;
+ if (alg->base.cra_blocksize != 1)
+ goto out_drop_alg;
err = -ENAMETOOLONG;
- if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
- "rfc4543(%s)", alg->cra_name) >= CRYPTO_MAX_ALG_NAME ||
- snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
- "rfc4543(%s)", alg->cra_driver_name) >=
+ if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
+ "rfc4543(%s)", alg->base.cra_name) >=
+ CRYPTO_MAX_ALG_NAME ||
+ snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+ "rfc4543(%s)", alg->base.cra_driver_name) >=
CRYPTO_MAX_ALG_NAME)
- goto out_drop_ecbnull;
+ goto out_drop_alg;
- inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
- inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
- inst->alg.cra_priority = alg->cra_priority;
- inst->alg.cra_blocksize = 1;
- inst->alg.cra_alignmask = alg->cra_alignmask;
- inst->alg.cra_type = &crypto_nivaead_type;
+ inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC;
+ inst->alg.base.cra_priority = alg->base.cra_priority;
+ inst->alg.base.cra_blocksize = 1;
+ inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
- inst->alg.cra_aead.ivsize = 8;
- inst->alg.cra_aead.maxauthsize = 16;
+ inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4543_ctx);
- inst->alg.cra_ctxsize = sizeof(struct crypto_rfc4543_ctx);
+ inst->alg.ivsize = 8;
+ inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);
- inst->alg.cra_init = crypto_rfc4543_init_tfm;
- inst->alg.cra_exit = crypto_rfc4543_exit_tfm;
+ inst->alg.init = crypto_rfc4543_init_tfm;
+ inst->alg.exit = crypto_rfc4543_exit_tfm;
- inst->alg.cra_aead.setkey = crypto_rfc4543_setkey;
- inst->alg.cra_aead.setauthsize = crypto_rfc4543_setauthsize;
- inst->alg.cra_aead.encrypt = crypto_rfc4543_encrypt;
- inst->alg.cra_aead.decrypt = crypto_rfc4543_decrypt;
+ inst->alg.setkey = crypto_rfc4543_setkey;
+ inst->alg.setauthsize = crypto_rfc4543_setauthsize;
+ inst->alg.encrypt = crypto_rfc4543_encrypt;
+ inst->alg.decrypt = crypto_rfc4543_decrypt;
- inst->alg.cra_aead.geniv = "seqiv";
+ err = aead_register_instance(tmpl, inst);
+ if (err)
+ goto out_drop_alg;
out:
- return inst;
+ return err;
-out_drop_ecbnull:
- crypto_drop_skcipher(&ctx->null);
out_drop_alg:
crypto_drop_aead(spawn);
out_free_inst:
kfree(inst);
- inst = ERR_PTR(err);
goto out;
}
@@ -1377,14 +1206,13 @@ static void crypto_rfc4543_free(struct crypto_instance *inst)
struct crypto_rfc4543_instance_ctx *ctx = crypto_instance_ctx(inst);
crypto_drop_aead(&ctx->aead);
- crypto_drop_skcipher(&ctx->null);
- kfree(inst);
+ kfree(aead_instance(inst));
}
static struct crypto_template crypto_rfc4543_tmpl = {
.name = "rfc4543",
- .alloc = crypto_rfc4543_alloc,
+ .create = crypto_rfc4543_create,
.free = crypto_rfc4543_free,
.module = THIS_MODULE,
};
@@ -1393,10 +1221,12 @@ static int __init crypto_gcm_module_init(void)
{
int err;
- gcm_zeroes = kzalloc(16, GFP_KERNEL);
+ gcm_zeroes = kzalloc(sizeof(*gcm_zeroes), GFP_KERNEL);
if (!gcm_zeroes)
return -ENOMEM;
+ sg_init_one(&gcm_zeroes->sg, gcm_zeroes->buf, sizeof(gcm_zeroes->buf));
+
err = crypto_register_template(&crypto_gcm_base_tmpl);
if (err)
goto out;
diff --git a/crypto/internal.h b/crypto/internal.h
index bd39bfc92eab..00e42a3ed814 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -25,7 +25,6 @@
#include <linux/notifier.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
-#include <linux/fips.h>
/* Crypto notification events. */
enum {
@@ -103,6 +102,8 @@ int crypto_register_notifier(struct notifier_block *nb);
int crypto_unregister_notifier(struct notifier_block *nb);
int crypto_probing_notify(unsigned long val, void *v);
+unsigned int crypto_alg_extsize(struct crypto_alg *alg);
+
static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
{
atomic_inc(&alg->cra_refcnt);
diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c
new file mode 100644
index 000000000000..b32d834144cd
--- /dev/null
+++ b/crypto/jitterentropy-kcapi.c
@@ -0,0 +1,208 @@
+/*
+ * Non-physical true random number generator based on timing jitter --
+ * Linux Kernel Crypto API specific code
+ *
+ * Copyright Stephan Mueller <smueller@chronox.de>, 2015
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU General Public License, in which case the provisions of the GPL2 are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/fips.h>
+#include <linux/time.h>
+#include <linux/crypto.h>
+#include <crypto/internal/rng.h>
+
+struct rand_data;
+int jent_read_entropy(struct rand_data *ec, unsigned char *data,
+ unsigned int len);
+int jent_entropy_init(void);
+struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
+ unsigned int flags);
+void jent_entropy_collector_free(struct rand_data *entropy_collector);
+
+/***************************************************************************
+ * Helper function
+ ***************************************************************************/
+
+__u64 jent_rol64(__u64 word, unsigned int shift)
+{
+ return rol64(word, shift);
+}
+
+void *jent_zalloc(unsigned int len)
+{
+ return kzalloc(len, GFP_KERNEL);
+}
+
+void jent_zfree(void *ptr)
+{
+ kzfree(ptr);
+}
+
+int jent_fips_enabled(void)
+{
+ return fips_enabled;
+}
+
+void jent_panic(char *s)
+{
+ panic(s);
+}
+
+void jent_memcpy(void *dest, const void *src, unsigned int n)
+{
+ memcpy(dest, src, n);
+}
+
+void jent_get_nstime(__u64 *out)
+{
+ struct timespec ts;
+ __u64 tmp = 0;
+
+ tmp = random_get_entropy();
+
+ /*
+ * If random_get_entropy does not return a value (which is possible on,
+ * for example, MIPS), invoke __getnstimeofday
+ * hoping that there are timers we can work with.
+ *
+ * The list of available timers can be obtained from
+ * /sys/devices/system/clocksource/clocksource0/available_clocksource
+ * and are registered with clocksource_register()
+ */
+ if ((0 == tmp) &&
+ (0 == __getnstimeofday(&ts))) {
+ tmp = ts.tv_sec;
+ tmp = tmp << 32;
+ tmp = tmp | ts.tv_nsec;
+ }
+
+ *out = tmp;
+}
+
+/***************************************************************************
+ * Kernel crypto API interface
+ ***************************************************************************/
+
+struct jitterentropy {
+ spinlock_t jent_lock;
+ struct rand_data *entropy_collector;
+};
+
+static int jent_kcapi_init(struct crypto_tfm *tfm)
+{
+ struct jitterentropy *rng = crypto_tfm_ctx(tfm);
+ int ret = 0;
+
+ rng->entropy_collector = jent_entropy_collector_alloc(1, 0);
+ if (!rng->entropy_collector)
+ ret = -ENOMEM;
+
+ spin_lock_init(&rng->jent_lock);
+ return ret;
+}
+
+static void jent_kcapi_cleanup(struct crypto_tfm *tfm)
+{
+ struct jitterentropy *rng = crypto_tfm_ctx(tfm);
+
+ spin_lock(&rng->jent_lock);
+ if (rng->entropy_collector)
+ jent_entropy_collector_free(rng->entropy_collector);
+ rng->entropy_collector = NULL;
+ spin_unlock(&rng->jent_lock);
+}
+
+static int jent_kcapi_random(struct crypto_rng *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *rdata, unsigned int dlen)
+{
+ struct jitterentropy *rng = crypto_rng_ctx(tfm);
+ int ret = 0;
+
+ spin_lock(&rng->jent_lock);
+ ret = jent_read_entropy(rng->entropy_collector, rdata, dlen);
+ spin_unlock(&rng->jent_lock);
+
+ return ret;
+}
+
+static int jent_kcapi_reset(struct crypto_rng *tfm,
+ const u8 *seed, unsigned int slen)
+{
+ return 0;
+}
+
+static struct rng_alg jent_alg = {
+ .generate = jent_kcapi_random,
+ .seed = jent_kcapi_reset,
+ .seedsize = 0,
+ .base = {
+ .cra_name = "jitterentropy_rng",
+ .cra_driver_name = "jitterentropy_rng",
+ .cra_priority = 100,
+ .cra_ctxsize = sizeof(struct jitterentropy),
+ .cra_module = THIS_MODULE,
+ .cra_init = jent_kcapi_init,
+ .cra_exit = jent_kcapi_cleanup,
+
+ }
+};
+
+static int __init jent_mod_init(void)
+{
+ int ret = 0;
+
+ ret = jent_entropy_init();
+ if (ret) {
+ pr_info("jitterentropy: Initialization failed with host not compliant with requirements: %d\n", ret);
+ return -EFAULT;
+ }
+ return crypto_register_rng(&jent_alg);
+}
+
+static void __exit jent_mod_exit(void)
+{
+ crypto_unregister_rng(&jent_alg);
+}
+
+module_init(jent_mod_init);
+module_exit(jent_mod_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
+MODULE_DESCRIPTION("Non-physical True Random Number Generator based on CPU Jitter");
+MODULE_ALIAS_CRYPTO("jitterentropy_rng");
diff --git a/crypto/jitterentropy.c b/crypto/jitterentropy.c
new file mode 100644
index 000000000000..acf44b2d2d1d
--- /dev/null
+++ b/crypto/jitterentropy.c
@@ -0,0 +1,787 @@
+/*
+ * Non-physical true random number generator based on timing jitter --
+ * Jitter RNG standalone code.
+ *
+ * Copyright Stephan Mueller <smueller@chronox.de>, 2015
+ *
+ * Design
+ * ======
+ *
+ * See http://www.chronox.de/jent.html
+ *
+ * License
+ * =======
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU General Public License, in which case the provisions of the GPL2 are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+/*
+ * This Jitterentropy RNG is based on the jitterentropy library
+ * version 1.1.0 provided at http://www.chronox.de/jent.html
+ */
+
+#ifdef __OPTIMIZE__
+ #error "The CPU Jitter random number generator must not be compiled with optimizations. See documentation. Use the compiler switch -O0 for compiling jitterentropy.c."
+#endif
+
+typedef unsigned long long __u64;
+typedef long long __s64;
+typedef unsigned int __u32;
+#define NULL ((void *) 0)
+
+/* The entropy pool */
+struct rand_data {
+ /* all data values that are vital to maintain the security
+ * of the RNG are marked as SENSITIVE. A user must not
+ * access that information while the RNG executes its loops to
+ * calculate the next random value. */
+ __u64 data; /* SENSITIVE Actual random number */
+ __u64 old_data; /* SENSITIVE Previous random number */
+ __u64 prev_time; /* SENSITIVE Previous time stamp */
+#define DATA_SIZE_BITS ((sizeof(__u64)) * 8)
+ __u64 last_delta; /* SENSITIVE stuck test */
+ __s64 last_delta2; /* SENSITIVE stuck test */
+ unsigned int stuck:1; /* Time measurement stuck */
+ unsigned int osr; /* Oversample rate */
+ unsigned int stir:1; /* Post-processing stirring */
+ unsigned int disable_unbias:1; /* Deactivate Von-Neuman unbias */
+#define JENT_MEMORY_BLOCKS 64
+#define JENT_MEMORY_BLOCKSIZE 32
+#define JENT_MEMORY_ACCESSLOOPS 128
+#define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE)
+ unsigned char *mem; /* Memory access location with size of
+ * memblocks * memblocksize */
+ unsigned int memlocation; /* Pointer to byte in *mem */
+ unsigned int memblocks; /* Number of memory blocks in *mem */
+ unsigned int memblocksize; /* Size of one memory block in bytes */
+ unsigned int memaccessloops; /* Number of memory accesses per random
+ * bit generation */
+};
+
+/* Flags that can be used to initialize the RNG */
+#define JENT_DISABLE_STIR (1<<0) /* Disable stirring the entropy pool */
+#define JENT_DISABLE_UNBIAS (1<<1) /* Disable the Von-Neuman Unbiaser */
+#define JENT_DISABLE_MEMORY_ACCESS (1<<2) /* Disable memory access for more
+ * entropy, saves MEMORY_SIZE RAM for
+ * entropy collector */
+
+/* -- error codes for init function -- */
+#define JENT_ENOTIME 1 /* Timer service not available */
+#define JENT_ECOARSETIME 2 /* Timer too coarse for RNG */
+#define JENT_ENOMONOTONIC 3 /* Timer is not monotonic increasing */
+#define JENT_EMINVARIATION 4 /* Timer variations too small for RNG */
+#define JENT_EVARVAR 5 /* Timer does not produce variations of
+ * variations (2nd derivation of time is
+ * zero). */
+#define JENT_EMINVARVAR 6 /* Timer variations of variations is tooi
+ * small. */
+
+/***************************************************************************
+ * Helper functions
+ ***************************************************************************/
+
+void jent_get_nstime(__u64 *out);
+__u64 jent_rol64(__u64 word, unsigned int shift);
+void *jent_zalloc(unsigned int len);
+void jent_zfree(void *ptr);
+int jent_fips_enabled(void);
+void jent_panic(char *s);
+void jent_memcpy(void *dest, const void *src, unsigned int n);
+
+/**
+ * Update of the loop count used for the next round of
+ * an entropy collection.
+ *
+ * Input:
+ * @ec entropy collector struct -- may be NULL
+ * @bits is the number of low bits of the timer to consider
+ * @min is the number of bits we shift the timer value to the right at
+ * the end to make sure we have a guaranteed minimum value
+ *
+ * @return Newly calculated loop counter
+ */
+static __u64 jent_loop_shuffle(struct rand_data *ec,
+ unsigned int bits, unsigned int min)
+{
+ __u64 time = 0;
+ __u64 shuffle = 0;
+ unsigned int i = 0;
+ unsigned int mask = (1<<bits) - 1;
+
+ jent_get_nstime(&time);
+ /*
+ * mix the current state of the random number into the shuffle
+ * calculation to balance that shuffle a bit more
+ */
+ if (ec)
+ time ^= ec->data;
+ /*
+ * we fold the time value as much as possible to ensure that as many
+ * bits of the time stamp are included as possible
+ */
+ for (i = 0; (DATA_SIZE_BITS / bits) > i; i++) {
+ shuffle ^= time & mask;
+ time = time >> bits;
+ }
+
+ /*
+ * We add a lower boundary value to ensure we have a minimum
+ * RNG loop count.
+ */
+ return (shuffle + (1<<min));
+}
+
+/***************************************************************************
+ * Noise sources
+ ***************************************************************************/
+
+/**
+ * CPU Jitter noise source -- this is the noise source based on the CPU
+ * execution time jitter
+ *
+ * This function folds the time into one bit units by iterating
+ * through the DATA_SIZE_BITS bit time value as follows: assume our time value
+ * is 0xabcd
+ * 1st loop, 1st shift generates 0xd000
+ * 1st loop, 2nd shift generates 0x000d
+ * 2nd loop, 1st shift generates 0xcd00
+ * 2nd loop, 2nd shift generates 0x000c
+ * 3rd loop, 1st shift generates 0xbcd0
+ * 3rd loop, 2nd shift generates 0x000b
+ * 4th loop, 1st shift generates 0xabcd
+ * 4th loop, 2nd shift generates 0x000a
+ * Now, the values at the end of the 2nd shifts are XORed together.
+ *
+ * The code is deliberately inefficient and shall stay that way. This function
+ * is the root cause why the code shall be compiled without optimization. This
+ * function not only acts as folding operation, but this function's execution
+ * is used to measure the CPU execution time jitter. Any change to the loop in
+ * this function implies that careful retesting must be done.
+ *
+ * Input:
+ * @ec entropy collector struct -- may be NULL
+ * @time time stamp to be folded
+ * @loop_cnt if a value not equal to 0 is set, use the given value as number of
+ * loops to perform the folding
+ *
+ * Output:
+ * @folded result of folding operation
+ *
+ * @return Number of loops the folding operation is performed
+ */
+static __u64 jent_fold_time(struct rand_data *ec, __u64 time,
+ __u64 *folded, __u64 loop_cnt)
+{
+ unsigned int i;
+ __u64 j = 0;
+ __u64 new = 0;
+#define MAX_FOLD_LOOP_BIT 4
+#define MIN_FOLD_LOOP_BIT 0
+ __u64 fold_loop_cnt =
+ jent_loop_shuffle(ec, MAX_FOLD_LOOP_BIT, MIN_FOLD_LOOP_BIT);
+
+ /*
+ * testing purposes -- allow test app to set the counter, not
+ * needed during runtime
+ */
+ if (loop_cnt)
+ fold_loop_cnt = loop_cnt;
+ for (j = 0; j < fold_loop_cnt; j++) {
+ new = 0;
+ for (i = 1; (DATA_SIZE_BITS) >= i; i++) {
+ __u64 tmp = time << (DATA_SIZE_BITS - i);
+
+ tmp = tmp >> (DATA_SIZE_BITS - 1);
+ new ^= tmp;
+ }
+ }
+ *folded = new;
+ return fold_loop_cnt;
+}
+
+/**
+ * Memory Access noise source -- this is a noise source based on variations in
+ * memory access times
+ *
+ * This function performs memory accesses which will add to the timing
+ * variations due to an unknown amount of CPU wait states that need to be
+ * added when accessing memory. The memory size should be larger than the L1
+ * caches as outlined in the documentation and the associated testing.
+ *
+ * The L1 cache has a very high bandwidth, albeit its access rate is usually
+ * slower than accessing CPU registers. Therefore, L1 accesses only add minimal
+ * variations as the CPU has hardly to wait. Starting with L2, significant
+ * variations are added because L2 typically does not belong to the CPU any more
+ * and therefore a wider range of CPU wait states is necessary for accesses.
+ * L3 and real memory accesses have even a wider range of wait states. However,
+ * to reliably access either L3 or memory, the ec->mem memory must be quite
+ * large which is usually not desirable.
+ *
+ * Input:
+ * @ec Reference to the entropy collector with the memory access data -- if
+ * the reference to the memory block to be accessed is NULL, this noise
+ * source is disabled
+ * @loop_cnt if a value not equal to 0 is set, use the given value as number of
+ * loops to perform the folding
+ *
+ * @return Number of memory access operations
+ */
+static unsigned int jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
+{
+ unsigned char *tmpval = NULL;
+ unsigned int wrap = 0;
+ __u64 i = 0;
+#define MAX_ACC_LOOP_BIT 7
+#define MIN_ACC_LOOP_BIT 0
+ __u64 acc_loop_cnt =
+ jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT);
+
+ if (NULL == ec || NULL == ec->mem)
+ return 0;
+ wrap = ec->memblocksize * ec->memblocks;
+
+ /*
+ * testing purposes -- allow test app to set the counter, not
+ * needed during runtime
+ */
+ if (loop_cnt)
+ acc_loop_cnt = loop_cnt;
+
+ for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) {
+ tmpval = ec->mem + ec->memlocation;
+ /*
+ * memory access: just add 1 to one byte,
+ * wrap at 255 -- memory access implies read
+ * from and write to memory location
+ */
+ *tmpval = (*tmpval + 1) & 0xff;
+ /*
+ * Addition of memblocksize - 1 to pointer
+ * with wrap around logic to ensure that every
+ * memory location is hit evenly
+ */
+ ec->memlocation = ec->memlocation + ec->memblocksize - 1;
+ ec->memlocation = ec->memlocation % wrap;
+ }
+ return i;
+}
+
+/***************************************************************************
+ * Start of entropy processing logic
+ ***************************************************************************/
+
+/**
+ * Stuck test by checking the:
+ * 1st derivation of the jitter measurement (time delta)
+ * 2nd derivation of the jitter measurement (delta of time deltas)
+ * 3rd derivation of the jitter measurement (delta of delta of time deltas)
+ *
+ * All values must always be non-zero.
+ *
+ * Input:
+ * @ec Reference to entropy collector
+ * @current_delta Jitter time delta
+ *
+ * @return
+ * 0 jitter measurement not stuck (good bit)
+ * 1 jitter measurement stuck (reject bit)
+ */
+static void jent_stuck(struct rand_data *ec, __u64 current_delta)
+{
+ __s64 delta2 = ec->last_delta - current_delta;
+ __s64 delta3 = delta2 - ec->last_delta2;
+
+ ec->last_delta = current_delta;
+ ec->last_delta2 = delta2;
+
+ if (!current_delta || !delta2 || !delta3)
+ ec->stuck = 1;
+}
+
+/**
+ * This is the heart of the entropy generation: calculate time deltas and
+ * use the CPU jitter in the time deltas. The jitter is folded into one
+ * bit. You can call this function the "random bit generator" as it
+ * produces one random bit per invocation.
+ *
+ * WARNING: ensure that ->prev_time is primed before using the output
+ * of this function! This can be done by calling this function
+ * and not using its result.
+ *
+ * Input:
+ * @entropy_collector Reference to entropy collector
+ *
+ * @return One random bit
+ */
+static __u64 jent_measure_jitter(struct rand_data *ec)
+{
+ __u64 time = 0;
+ __u64 data = 0;
+ __u64 current_delta = 0;
+
+ /* Invoke one noise source before time measurement to add variations */
+ jent_memaccess(ec, 0);
+
+ /*
+ * Get time stamp and calculate time delta to previous
+ * invocation to measure the timing variations
+ */
+ jent_get_nstime(&time);
+ current_delta = time - ec->prev_time;
+ ec->prev_time = time;
+
+ /* Now call the next noise sources which also folds the data */
+ jent_fold_time(ec, current_delta, &data, 0);
+
+ /*
+ * Check whether we have a stuck measurement. The enforcement
+ * is performed after the stuck value has been mixed into the
+ * entropy pool.
+ */
+ jent_stuck(ec, current_delta);
+
+ return data;
+}
+
+/**
+ * Von Neuman unbias as explained in RFC 4086 section 4.2. As shown in the
+ * documentation of that RNG, the bits from jent_measure_jitter are considered
+ * independent which implies that the Von Neuman unbias operation is applicable.
+ * A proof of the Von-Neumann unbias operation to remove skews is given in the
+ * document "A proposal for: Functionality classes for random number
+ * generators", version 2.0 by Werner Schindler, section 5.4.1.
+ *
+ * Input:
+ * @entropy_collector Reference to entropy collector
+ *
+ * @return One random bit
+ */
+static __u64 jent_unbiased_bit(struct rand_data *entropy_collector)
+{
+ do {
+ __u64 a = jent_measure_jitter(entropy_collector);
+ __u64 b = jent_measure_jitter(entropy_collector);
+
+ if (a == b)
+ continue;
+ if (1 == a)
+ return 1;
+ else
+ return 0;
+ } while (1);
+}
+
+/**
+ * Shuffle the pool a bit by mixing some value with a bijective function (XOR)
+ * into the pool.
+ *
+ * The function generates a mixer value that depends on the bits set and the
+ * location of the set bits in the random number generated by the entropy
+ * source. Therefore, based on the generated random number, this mixer value
+ * can have 2**64 different values. That mixer value is initialized with the
+ * first two SHA-1 constants. After obtaining the mixer value, it is XORed into
+ * the random number.
+ *
+ * The mixer value is not assumed to contain any entropy. But due to the XOR
+ * operation, it can also not destroy any entropy present in the entropy pool.
+ *
+ * Input:
+ * @entropy_collector Reference to entropy collector
+ */
+static void jent_stir_pool(struct rand_data *entropy_collector)
+{
+ /*
+ * to shut up GCC on 32 bit, we have to initialize the 64 variable
+ * with two 32 bit variables
+ */
+ union c {
+ __u64 u64;
+ __u32 u32[2];
+ };
+ /*
+ * This constant is derived from the first two 32 bit initialization
+ * vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1
+ */
+ union c constant;
+ /*
+ * The start value of the mixer variable is derived from the third
+ * and fourth 32 bit initialization vector of SHA-1 as defined in
+ * FIPS 180-4 section 5.3.1
+ */
+ union c mixer;
+ unsigned int i = 0;
+
+ /*
+ * Store the SHA-1 constants in reverse order to make up the 64 bit
+ * value -- this applies to a little endian system, on a big endian
+ * system, it reverses as expected. But this really does not matter
+ * as we do not rely on the specific numbers. We just pick the SHA-1
+ * constants as they have a good mix of bit set and unset.
+ */
+ constant.u32[1] = 0x67452301;
+ constant.u32[0] = 0xefcdab89;
+ mixer.u32[1] = 0x98badcfe;
+ mixer.u32[0] = 0x10325476;
+
+ for (i = 0; i < DATA_SIZE_BITS; i++) {
+ /*
+ * get the i-th bit of the input random number and only XOR
+ * the constant into the mixer value when that bit is set
+ */
+ if ((entropy_collector->data >> i) & 1)
+ mixer.u64 ^= constant.u64;
+ mixer.u64 = jent_rol64(mixer.u64, 1);
+ }
+ entropy_collector->data ^= mixer.u64;
+}
+
+/**
+ * Generator of one 64 bit random number
+ * Function fills rand_data->data
+ *
+ * Input:
+ * @ec Reference to entropy collector
+ */
+static void jent_gen_entropy(struct rand_data *ec)
+{
+ unsigned int k = 0;
+
+ /* priming of the ->prev_time value */
+ jent_measure_jitter(ec);
+
+ while (1) {
+ __u64 data = 0;
+
+ if (ec->disable_unbias == 1)
+ data = jent_measure_jitter(ec);
+ else
+ data = jent_unbiased_bit(ec);
+
+ /* enforcement of the jent_stuck test */
+ if (ec->stuck) {
+ /*
+ * We only mix in the bit considered not appropriate
+ * without the LSFR. The reason is that if we apply
+ * the LSFR and we do not rotate, the 2nd bit with LSFR
+ * will cancel out the first LSFR application on the
+ * bad bit.
+ *
+ * And we do not rotate as we apply the next bit to the
+ * current bit location again.
+ */
+ ec->data ^= data;
+ ec->stuck = 0;
+ continue;
+ }
+
+ /*
+ * Fibonacci LSFR with polynom of
+ * x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is
+ * primitive according to
+ * http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf
+ * (the shift values are the polynom values minus one
+ * due to counting bits from 0 to 63). As the current
+ * position is always the LSB, the polynom only needs
+ * to shift data in from the left without wrap.
+ */
+ ec->data ^= data;
+ ec->data ^= ((ec->data >> 63) & 1);
+ ec->data ^= ((ec->data >> 60) & 1);
+ ec->data ^= ((ec->data >> 55) & 1);
+ ec->data ^= ((ec->data >> 30) & 1);
+ ec->data ^= ((ec->data >> 27) & 1);
+ ec->data ^= ((ec->data >> 22) & 1);
+ ec->data = jent_rol64(ec->data, 1);
+
+ /*
+ * We multiply the loop value with ->osr to obtain the
+ * oversampling rate requested by the caller
+ */
+ if (++k >= (DATA_SIZE_BITS * ec->osr))
+ break;
+ }
+ if (ec->stir)
+ jent_stir_pool(ec);
+}
+
+/**
+ * The continuous test required by FIPS 140-2 -- the function automatically
+ * primes the test if needed.
+ *
+ * Return:
+ * 0 if FIPS test passed
+ * < 0 if FIPS test failed
+ */
+static void jent_fips_test(struct rand_data *ec)
+{
+ if (!jent_fips_enabled())
+ return;
+
+ /* prime the FIPS test */
+ if (!ec->old_data) {
+ ec->old_data = ec->data;
+ jent_gen_entropy(ec);
+ }
+
+ if (ec->data == ec->old_data)
+ jent_panic("jitterentropy: Duplicate output detected\n");
+
+ ec->old_data = ec->data;
+}
+
+/**
+ * Entry function: Obtain entropy for the caller.
+ *
+ * This function invokes the entropy gathering logic as often to generate
+ * as many bytes as requested by the caller. The entropy gathering logic
+ * creates 64 bit per invocation.
+ *
+ * This function truncates the last 64 bit entropy value output to the exact
+ * size specified by the caller.
+ *
+ * Input:
+ * @ec Reference to entropy collector
+ * @data pointer to buffer for storing random data -- buffer must already
+ * exist
+ * @len size of the buffer, specifying also the requested number of random
+ * in bytes
+ *
+ * @return 0 when request is fulfilled or an error
+ *
+ * The following error codes can occur:
+ * -1 entropy_collector is NULL
+ */
+int jent_read_entropy(struct rand_data *ec, unsigned char *data,
+ unsigned int len)
+{
+ unsigned char *p = data;
+
+ if (!ec)
+ return -1;
+
+ while (0 < len) {
+ unsigned int tocopy;
+
+ jent_gen_entropy(ec);
+ jent_fips_test(ec);
+ if ((DATA_SIZE_BITS / 8) < len)
+ tocopy = (DATA_SIZE_BITS / 8);
+ else
+ tocopy = len;
+ jent_memcpy(p, &ec->data, tocopy);
+
+ len -= tocopy;
+ p += tocopy;
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ * Initialization logic
+ ***************************************************************************/
+
+struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
+ unsigned int flags)
+{
+ struct rand_data *entropy_collector;
+
+ entropy_collector = jent_zalloc(sizeof(struct rand_data));
+ if (!entropy_collector)
+ return NULL;
+
+ if (!(flags & JENT_DISABLE_MEMORY_ACCESS)) {
+ /* Allocate memory for adding variations based on memory
+ * access
+ */
+ entropy_collector->mem = jent_zalloc(JENT_MEMORY_SIZE);
+ if (!entropy_collector->mem) {
+ jent_zfree(entropy_collector);
+ return NULL;
+ }
+ entropy_collector->memblocksize = JENT_MEMORY_BLOCKSIZE;
+ entropy_collector->memblocks = JENT_MEMORY_BLOCKS;
+ entropy_collector->memaccessloops = JENT_MEMORY_ACCESSLOOPS;
+ }
+
+ /* verify and set the oversampling rate */
+ if (0 == osr)
+ osr = 1; /* minimum sampling rate is 1 */
+ entropy_collector->osr = osr;
+
+ entropy_collector->stir = 1;
+ if (flags & JENT_DISABLE_STIR)
+ entropy_collector->stir = 0;
+ if (flags & JENT_DISABLE_UNBIAS)
+ entropy_collector->disable_unbias = 1;
+
+ /* fill the data pad with non-zero values */
+ jent_gen_entropy(entropy_collector);
+
+ return entropy_collector;
+}
+
+void jent_entropy_collector_free(struct rand_data *entropy_collector)
+{
+ jent_zfree(entropy_collector->mem);
+ entropy_collector->mem = NULL;
+ jent_zfree(entropy_collector);
+ entropy_collector = NULL;
+}
+
+int jent_entropy_init(void)
+{
+ int i;
+ __u64 delta_sum = 0;
+ __u64 old_delta = 0;
+ int time_backwards = 0;
+ int count_var = 0;
+ int count_mod = 0;
+
+ /* We could perform statistical tests here, but the problem is
+ * that we only have a few loop counts to do testing. These
+ * loop counts may show some slight skew and we produce
+ * false positives.
+ *
+ * Moreover, only old systems show potentially problematic
+ * jitter entropy that could potentially be caught here. But
+ * the RNG is intended for hardware that is available or widely
+ * used, but not old systems that are long out of favor. Thus,
+ * no statistical tests.
+ */
+
+ /*
+ * We could add a check for system capabilities such as clock_getres or
+ * check for CONFIG_X86_TSC, but it does not make much sense as the
+ * following sanity checks verify that we have a high-resolution
+ * timer.
+ */
+ /*
+ * TESTLOOPCOUNT needs some loops to identify edge systems. 100 is
+ * definitely too little.
+ */
+#define TESTLOOPCOUNT 300
+#define CLEARCACHE 100
+ for (i = 0; (TESTLOOPCOUNT + CLEARCACHE) > i; i++) {
+ __u64 time = 0;
+ __u64 time2 = 0;
+ __u64 folded = 0;
+ __u64 delta = 0;
+ unsigned int lowdelta = 0;
+
+ jent_get_nstime(&time);
+ jent_fold_time(NULL, time, &folded, 1<<MIN_FOLD_LOOP_BIT);
+ jent_get_nstime(&time2);
+
+ /* test whether timer works */
+ if (!time || !time2)
+ return JENT_ENOTIME;
+ delta = time2 - time;
+ /*
+ * test whether timer is fine grained enough to provide
+ * delta even when called shortly after each other -- this
+ * implies that we also have a high resolution timer
+ */
+ if (!delta)
+ return JENT_ECOARSETIME;
+
+ /*
+ * up to here we did not modify any variable that will be
+ * evaluated later, but we already performed some work. Thus we
+ * already have had an impact on the caches, branch prediction,
+ * etc. with the goal to clear it to get the worst case
+ * measurements.
+ */
+ if (CLEARCACHE > i)
+ continue;
+
+ /* test whether we have an increasing timer */
+ if (!(time2 > time))
+ time_backwards++;
+
+ /*
+ * Avoid modulo of 64 bit integer to allow code to compile
+ * on 32 bit architectures.
+ */
+ lowdelta = time2 - time;
+ if (!(lowdelta % 100))
+ count_mod++;
+
+ /*
+ * ensure that we have a varying delta timer which is necessary
+ * for the calculation of entropy -- perform this check
+ * only after the first loop is executed as we need to prime
+ * the old_data value
+ */
+ if (i) {
+ if (delta != old_delta)
+ count_var++;
+ if (delta > old_delta)
+ delta_sum += (delta - old_delta);
+ else
+ delta_sum += (old_delta - delta);
+ }
+ old_delta = delta;
+ }
+
+ /*
+ * we allow up to three times the time running backwards.
+ * CLOCK_REALTIME is affected by adjtime and NTP operations. Thus,
+ * if such an operation just happens to interfere with our test, it
+ * should not fail. The value of 3 should cover the NTP case being
+ * performed during our test run.
+ */
+ if (3 < time_backwards)
+ return JENT_ENOMONOTONIC;
+ /* Error if the time variances are always identical */
+ if (!delta_sum)
+ return JENT_EVARVAR;
+
+ /*
+ * Variations of deltas of time must on average be larger
+ * than 1 to ensure the entropy estimation
+ * implied with 1 is preserved
+ */
+ if (delta_sum <= 1)
+ return JENT_EMINVARVAR;
+
+ /*
+ * Ensure that we have variations in the time stamp below 10 for at
+ * least 10% of all checks -- on some platforms, the counter
+ * increments in multiples of 100, but not always
+ */
+ if ((TESTLOOPCOUNT/10 * 9) < count_mod)
+ return JENT_ECOARSETIME;
+
+ return 0;
+}
diff --git a/crypto/krng.c b/crypto/krng.c
deleted file mode 100644
index 0224841b6579..000000000000
--- a/crypto/krng.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * RNG implementation using standard kernel RNG.
- *
- * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
- *
- * 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
- * any later version.
- *
- */
-
-#include <crypto/internal/rng.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/random.h>
-
-static int krng_get_random(struct crypto_rng *tfm, u8 *rdata, unsigned int dlen)
-{
- get_random_bytes(rdata, dlen);
- return 0;
-}
-
-static int krng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
-{
- return 0;
-}
-
-static struct crypto_alg krng_alg = {
- .cra_name = "stdrng",
- .cra_driver_name = "krng",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_TYPE_RNG,
- .cra_ctxsize = 0,
- .cra_type = &crypto_rng_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .rng = {
- .rng_make_random = krng_get_random,
- .rng_reset = krng_reset,
- .seedsize = 0,
- }
- }
-};
-
-
-/* Module initalization */
-static int __init krng_mod_init(void)
-{
- return crypto_register_alg(&krng_alg);
-}
-
-static void __exit krng_mod_fini(void)
-{
- crypto_unregister_alg(&krng_alg);
- return;
-}
-
-module_init(krng_mod_init);
-module_exit(krng_mod_fini);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Kernel Random Number Generator");
-MODULE_ALIAS_CRYPTO("stdrng");
-MODULE_ALIAS_CRYPTO("krng");
diff --git a/crypto/md5.c b/crypto/md5.c
index 36f5e5b103f3..33d17e9a8702 100644
--- a/crypto/md5.c
+++ b/crypto/md5.c
@@ -51,10 +51,10 @@ static int md5_init(struct shash_desc *desc)
{
struct md5_state *mctx = shash_desc_ctx(desc);
- mctx->hash[0] = 0x67452301;
- mctx->hash[1] = 0xefcdab89;
- mctx->hash[2] = 0x98badcfe;
- mctx->hash[3] = 0x10325476;
+ mctx->hash[0] = MD5_H0;
+ mctx->hash[1] = MD5_H1;
+ mctx->hash[2] = MD5_H2;
+ mctx->hash[3] = MD5_H3;
mctx->byte_count = 0;
return 0;
diff --git a/crypto/pcompress.c b/crypto/pcompress.c
index 7140fe70c7af..7a13b4088857 100644
--- a/crypto/pcompress.c
+++ b/crypto/pcompress.c
@@ -38,11 +38,6 @@ static int crypto_pcomp_init(struct crypto_tfm *tfm, u32 type, u32 mask)
return 0;
}
-static unsigned int crypto_pcomp_extsize(struct crypto_alg *alg)
-{
- return alg->cra_ctxsize;
-}
-
static int crypto_pcomp_init_tfm(struct crypto_tfm *tfm)
{
return 0;
@@ -77,7 +72,7 @@ static void crypto_pcomp_show(struct seq_file *m, struct crypto_alg *alg)
}
static const struct crypto_type crypto_pcomp_type = {
- .extsize = crypto_pcomp_extsize,
+ .extsize = crypto_alg_extsize,
.init = crypto_pcomp_init,
.init_tfm = crypto_pcomp_init_tfm,
#ifdef CONFIG_PROC_FS
diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c
index c305d4112735..45e7d5155672 100644
--- a/crypto/pcrypt.c
+++ b/crypto/pcrypt.c
@@ -20,6 +20,7 @@
#include <crypto/algapi.h>
#include <crypto/internal/aead.h>
+#include <linux/atomic.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -60,8 +61,8 @@ static struct padata_pcrypt pdecrypt;
static struct kset *pcrypt_kset;
struct pcrypt_instance_ctx {
- struct crypto_spawn spawn;
- unsigned int tfm_count;
+ struct crypto_aead_spawn spawn;
+ atomic_t tfm_count;
};
struct pcrypt_aead_ctx {
@@ -122,14 +123,6 @@ static void pcrypt_aead_serial(struct padata_priv *padata)
aead_request_complete(req->base.data, padata->info);
}
-static void pcrypt_aead_giv_serial(struct padata_priv *padata)
-{
- struct pcrypt_request *preq = pcrypt_padata_request(padata);
- struct aead_givcrypt_request *req = pcrypt_request_ctx(preq);
-
- aead_request_complete(req->areq.base.data, padata->info);
-}
-
static void pcrypt_aead_done(struct crypto_async_request *areq, int err)
{
struct aead_request *req = areq->data;
@@ -175,7 +168,7 @@ static int pcrypt_aead_encrypt(struct aead_request *req)
pcrypt_aead_done, req);
aead_request_set_crypt(creq, req->src, req->dst,
req->cryptlen, req->iv);
- aead_request_set_assoc(creq, req->assoc, req->assoclen);
+ aead_request_set_ad(creq, req->assoclen);
err = pcrypt_do_parallel(padata, &ctx->cb_cpu, &pencrypt);
if (!err)
@@ -217,7 +210,7 @@ static int pcrypt_aead_decrypt(struct aead_request *req)
pcrypt_aead_done, req);
aead_request_set_crypt(creq, req->src, req->dst,
req->cryptlen, req->iv);
- aead_request_set_assoc(creq, req->assoc, req->assoclen);
+ aead_request_set_ad(creq, req->assoclen);
err = pcrypt_do_parallel(padata, &ctx->cb_cpu, &pdecrypt);
if (!err)
@@ -226,182 +219,134 @@ static int pcrypt_aead_decrypt(struct aead_request *req)
return err;
}
-static void pcrypt_aead_givenc(struct padata_priv *padata)
-{
- struct pcrypt_request *preq = pcrypt_padata_request(padata);
- struct aead_givcrypt_request *req = pcrypt_request_ctx(preq);
-
- padata->info = crypto_aead_givencrypt(req);
-
- if (padata->info == -EINPROGRESS)
- return;
-
- padata_do_serial(padata);
-}
-
-static int pcrypt_aead_givencrypt(struct aead_givcrypt_request *req)
-{
- int err;
- struct aead_request *areq = &req->areq;
- struct pcrypt_request *preq = aead_request_ctx(areq);
- struct aead_givcrypt_request *creq = pcrypt_request_ctx(preq);
- struct padata_priv *padata = pcrypt_request_padata(preq);
- struct crypto_aead *aead = aead_givcrypt_reqtfm(req);
- struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(aead);
- u32 flags = aead_request_flags(areq);
-
- memset(padata, 0, sizeof(struct padata_priv));
-
- padata->parallel = pcrypt_aead_givenc;
- padata->serial = pcrypt_aead_giv_serial;
-
- aead_givcrypt_set_tfm(creq, ctx->child);
- aead_givcrypt_set_callback(creq, flags & ~CRYPTO_TFM_REQ_MAY_SLEEP,
- pcrypt_aead_done, areq);
- aead_givcrypt_set_crypt(creq, areq->src, areq->dst,
- areq->cryptlen, areq->iv);
- aead_givcrypt_set_assoc(creq, areq->assoc, areq->assoclen);
- aead_givcrypt_set_giv(creq, req->giv, req->seq);
-
- err = pcrypt_do_parallel(padata, &ctx->cb_cpu, &pencrypt);
- if (!err)
- return -EINPROGRESS;
-
- return err;
-}
-
-static int pcrypt_aead_init_tfm(struct crypto_tfm *tfm)
+static int pcrypt_aead_init_tfm(struct crypto_aead *tfm)
{
int cpu, cpu_index;
- struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
- struct pcrypt_instance_ctx *ictx = crypto_instance_ctx(inst);
- struct pcrypt_aead_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct aead_instance *inst = aead_alg_instance(tfm);
+ struct pcrypt_instance_ctx *ictx = aead_instance_ctx(inst);
+ struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(tfm);
struct crypto_aead *cipher;
- ictx->tfm_count++;
-
- cpu_index = ictx->tfm_count % cpumask_weight(cpu_online_mask);
+ cpu_index = (unsigned int)atomic_inc_return(&ictx->tfm_count) %
+ cpumask_weight(cpu_online_mask);
ctx->cb_cpu = cpumask_first(cpu_online_mask);
for (cpu = 0; cpu < cpu_index; cpu++)
ctx->cb_cpu = cpumask_next(ctx->cb_cpu, cpu_online_mask);
- cipher = crypto_spawn_aead(crypto_instance_ctx(inst));
+ cipher = crypto_spawn_aead(&ictx->spawn);
if (IS_ERR(cipher))
return PTR_ERR(cipher);
ctx->child = cipher;
- tfm->crt_aead.reqsize = sizeof(struct pcrypt_request)
- + sizeof(struct aead_givcrypt_request)
- + crypto_aead_reqsize(cipher);
+ crypto_aead_set_reqsize(tfm, sizeof(struct pcrypt_request) +
+ sizeof(struct aead_request) +
+ crypto_aead_reqsize(cipher));
return 0;
}
-static void pcrypt_aead_exit_tfm(struct crypto_tfm *tfm)
+static void pcrypt_aead_exit_tfm(struct crypto_aead *tfm)
{
- struct pcrypt_aead_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(tfm);
crypto_free_aead(ctx->child);
}
-static struct crypto_instance *pcrypt_alloc_instance(struct crypto_alg *alg)
+static int pcrypt_init_instance(struct crypto_instance *inst,
+ struct crypto_alg *alg)
{
- struct crypto_instance *inst;
- struct pcrypt_instance_ctx *ctx;
- int err;
-
- inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
- if (!inst) {
- inst = ERR_PTR(-ENOMEM);
- goto out;
- }
-
- err = -ENAMETOOLONG;
if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
"pcrypt(%s)", alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
- goto out_free_inst;
+ return -ENAMETOOLONG;
memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
- ctx = crypto_instance_ctx(inst);
- err = crypto_init_spawn(&ctx->spawn, alg, inst,
- CRYPTO_ALG_TYPE_MASK);
- if (err)
- goto out_free_inst;
-
inst->alg.cra_priority = alg->cra_priority + 100;
inst->alg.cra_blocksize = alg->cra_blocksize;
inst->alg.cra_alignmask = alg->cra_alignmask;
-out:
- return inst;
-
-out_free_inst:
- kfree(inst);
- inst = ERR_PTR(err);
- goto out;
+ return 0;
}
-static struct crypto_instance *pcrypt_alloc_aead(struct rtattr **tb,
- u32 type, u32 mask)
+static int pcrypt_create_aead(struct crypto_template *tmpl, struct rtattr **tb,
+ u32 type, u32 mask)
{
- struct crypto_instance *inst;
- struct crypto_alg *alg;
+ struct pcrypt_instance_ctx *ctx;
+ struct aead_instance *inst;
+ struct aead_alg *alg;
+ const char *name;
+ int err;
+
+ name = crypto_attr_alg_name(tb[1]);
+ if (IS_ERR(name))
+ return PTR_ERR(name);
+
+ inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ ctx = aead_instance_ctx(inst);
+ crypto_set_aead_spawn(&ctx->spawn, aead_crypto_instance(inst));
+
+ err = crypto_grab_aead(&ctx->spawn, name, 0, 0);
+ if (err)
+ goto out_free_inst;
- alg = crypto_get_attr_alg(tb, type, (mask & CRYPTO_ALG_TYPE_MASK));
- if (IS_ERR(alg))
- return ERR_CAST(alg);
+ alg = crypto_spawn_aead_alg(&ctx->spawn);
+ err = pcrypt_init_instance(aead_crypto_instance(inst), &alg->base);
+ if (err)
+ goto out_drop_aead;
- inst = pcrypt_alloc_instance(alg);
- if (IS_ERR(inst))
- goto out_put_alg;
+ inst->alg.ivsize = crypto_aead_alg_ivsize(alg);
+ inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);
- inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC;
- inst->alg.cra_type = &crypto_aead_type;
+ inst->alg.base.cra_ctxsize = sizeof(struct pcrypt_aead_ctx);
- inst->alg.cra_aead.ivsize = alg->cra_aead.ivsize;
- inst->alg.cra_aead.geniv = alg->cra_aead.geniv;
- inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize;
+ inst->alg.init = pcrypt_aead_init_tfm;
+ inst->alg.exit = pcrypt_aead_exit_tfm;
- inst->alg.cra_ctxsize = sizeof(struct pcrypt_aead_ctx);
+ inst->alg.setkey = pcrypt_aead_setkey;
+ inst->alg.setauthsize = pcrypt_aead_setauthsize;
+ inst->alg.encrypt = pcrypt_aead_encrypt;
+ inst->alg.decrypt = pcrypt_aead_decrypt;
- inst->alg.cra_init = pcrypt_aead_init_tfm;
- inst->alg.cra_exit = pcrypt_aead_exit_tfm;
+ err = aead_register_instance(tmpl, inst);
+ if (err)
+ goto out_drop_aead;
- inst->alg.cra_aead.setkey = pcrypt_aead_setkey;
- inst->alg.cra_aead.setauthsize = pcrypt_aead_setauthsize;
- inst->alg.cra_aead.encrypt = pcrypt_aead_encrypt;
- inst->alg.cra_aead.decrypt = pcrypt_aead_decrypt;
- inst->alg.cra_aead.givencrypt = pcrypt_aead_givencrypt;
+out:
+ return err;
-out_put_alg:
- crypto_mod_put(alg);
- return inst;
+out_drop_aead:
+ crypto_drop_aead(&ctx->spawn);
+out_free_inst:
+ kfree(inst);
+ goto out;
}
-static struct crypto_instance *pcrypt_alloc(struct rtattr **tb)
+static int pcrypt_create(struct crypto_template *tmpl, struct rtattr **tb)
{
struct crypto_attr_type *algt;
algt = crypto_get_attr_type(tb);
if (IS_ERR(algt))
- return ERR_CAST(algt);
+ return PTR_ERR(algt);
switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) {
case CRYPTO_ALG_TYPE_AEAD:
- return pcrypt_alloc_aead(tb, algt->type, algt->mask);
+ return pcrypt_create_aead(tmpl, tb, algt->type, algt->mask);
}
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
static void pcrypt_free(struct crypto_instance *inst)
{
struct pcrypt_instance_ctx *ctx = crypto_instance_ctx(inst);
- crypto_drop_spawn(&ctx->spawn);
+ crypto_drop_aead(&ctx->spawn);
kfree(inst);
}
@@ -516,7 +461,7 @@ static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt)
static struct crypto_template pcrypt_tmpl = {
.name = "pcrypt",
- .alloc = pcrypt_alloc,
+ .create = pcrypt_create,
.free = pcrypt_free,
.module = THIS_MODULE,
};
diff --git a/crypto/poly1305_generic.c b/crypto/poly1305_generic.c
new file mode 100644
index 000000000000..387b5c887a80
--- /dev/null
+++ b/crypto/poly1305_generic.c
@@ -0,0 +1,321 @@
+/*
+ * Poly1305 authenticator algorithm, RFC7539
+ *
+ * Copyright (C) 2015 Martin Willi
+ *
+ * Based on public domain code by Andrew Moon and Daniel J. Bernstein.
+ *
+ * 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 <crypto/algapi.h>
+#include <crypto/internal/hash.h>
+#include <linux/crypto.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#define POLY1305_BLOCK_SIZE 16
+#define POLY1305_KEY_SIZE 32
+#define POLY1305_DIGEST_SIZE 16
+
+struct poly1305_desc_ctx {
+ /* key */
+ u32 r[5];
+ /* finalize key */
+ u32 s[4];
+ /* accumulator */
+ u32 h[5];
+ /* partial buffer */
+ u8 buf[POLY1305_BLOCK_SIZE];
+ /* bytes used in partial buffer */
+ unsigned int buflen;
+ /* r key has been set */
+ bool rset;
+ /* s key has been set */
+ bool sset;
+};
+
+static inline u64 mlt(u64 a, u64 b)
+{
+ return a * b;
+}
+
+static inline u32 sr(u64 v, u_char n)
+{
+ return v >> n;
+}
+
+static inline u32 and(u32 v, u32 mask)
+{
+ return v & mask;
+}
+
+static inline u32 le32_to_cpuvp(const void *p)
+{
+ return le32_to_cpup(p);
+}
+
+static int poly1305_init(struct shash_desc *desc)
+{
+ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+
+ memset(dctx->h, 0, sizeof(dctx->h));
+ dctx->buflen = 0;
+ dctx->rset = false;
+ dctx->sset = false;
+
+ return 0;
+}
+
+static int poly1305_setkey(struct crypto_shash *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ /* Poly1305 requires a unique key for each tag, which implies that
+ * we can't set it on the tfm that gets accessed by multiple users
+ * simultaneously. Instead we expect the key as the first 32 bytes in
+ * the update() call. */
+ return -ENOTSUPP;
+}
+
+static void poly1305_setrkey(struct poly1305_desc_ctx *dctx, const u8 *key)
+{
+ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+ dctx->r[0] = (le32_to_cpuvp(key + 0) >> 0) & 0x3ffffff;
+ dctx->r[1] = (le32_to_cpuvp(key + 3) >> 2) & 0x3ffff03;
+ dctx->r[2] = (le32_to_cpuvp(key + 6) >> 4) & 0x3ffc0ff;
+ dctx->r[3] = (le32_to_cpuvp(key + 9) >> 6) & 0x3f03fff;
+ dctx->r[4] = (le32_to_cpuvp(key + 12) >> 8) & 0x00fffff;
+}
+
+static void poly1305_setskey(struct poly1305_desc_ctx *dctx, const u8 *key)
+{
+ dctx->s[0] = le32_to_cpuvp(key + 0);
+ dctx->s[1] = le32_to_cpuvp(key + 4);
+ dctx->s[2] = le32_to_cpuvp(key + 8);
+ dctx->s[3] = le32_to_cpuvp(key + 12);
+}
+
+static unsigned int poly1305_blocks(struct poly1305_desc_ctx *dctx,
+ const u8 *src, unsigned int srclen,
+ u32 hibit)
+{
+ u32 r0, r1, r2, r3, r4;
+ u32 s1, s2, s3, s4;
+ u32 h0, h1, h2, h3, h4;
+ u64 d0, d1, d2, d3, d4;
+
+ if (unlikely(!dctx->sset)) {
+ if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
+ poly1305_setrkey(dctx, src);
+ src += POLY1305_BLOCK_SIZE;
+ srclen -= POLY1305_BLOCK_SIZE;
+ dctx->rset = true;
+ }
+ if (srclen >= POLY1305_BLOCK_SIZE) {
+ poly1305_setskey(dctx, src);
+ src += POLY1305_BLOCK_SIZE;
+ srclen -= POLY1305_BLOCK_SIZE;
+ dctx->sset = true;
+ }
+ }
+
+ r0 = dctx->r[0];
+ r1 = dctx->r[1];
+ r2 = dctx->r[2];
+ r3 = dctx->r[3];
+ r4 = dctx->r[4];
+
+ s1 = r1 * 5;
+ s2 = r2 * 5;
+ s3 = r3 * 5;
+ s4 = r4 * 5;
+
+ h0 = dctx->h[0];
+ h1 = dctx->h[1];
+ h2 = dctx->h[2];
+ h3 = dctx->h[3];
+ h4 = dctx->h[4];
+
+ while (likely(srclen >= POLY1305_BLOCK_SIZE)) {
+
+ /* h += m[i] */
+ h0 += (le32_to_cpuvp(src + 0) >> 0) & 0x3ffffff;
+ h1 += (le32_to_cpuvp(src + 3) >> 2) & 0x3ffffff;
+ h2 += (le32_to_cpuvp(src + 6) >> 4) & 0x3ffffff;
+ h3 += (le32_to_cpuvp(src + 9) >> 6) & 0x3ffffff;
+ h4 += (le32_to_cpuvp(src + 12) >> 8) | hibit;
+
+ /* h *= r */
+ d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) +
+ mlt(h3, s2) + mlt(h4, s1);
+ d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) +
+ mlt(h3, s3) + mlt(h4, s2);
+ d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) +
+ mlt(h3, s4) + mlt(h4, s3);
+ d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) +
+ mlt(h3, r0) + mlt(h4, s4);
+ d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) +
+ mlt(h3, r1) + mlt(h4, r0);
+
+ /* (partial) h %= p */
+ d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff);
+ d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff);
+ d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff);
+ d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff);
+ h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
+ h1 += h0 >> 26; h0 = h0 & 0x3ffffff;
+
+ src += POLY1305_BLOCK_SIZE;
+ srclen -= POLY1305_BLOCK_SIZE;
+ }
+
+ dctx->h[0] = h0;
+ dctx->h[1] = h1;
+ dctx->h[2] = h2;
+ dctx->h[3] = h3;
+ dctx->h[4] = h4;
+
+ return srclen;
+}
+
+static int poly1305_update(struct shash_desc *desc,
+ const u8 *src, unsigned int srclen)
+{
+ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+ unsigned int bytes;
+
+ if (unlikely(dctx->buflen)) {
+ bytes = min(srclen, POLY1305_BLOCK_SIZE - dctx->buflen);
+ memcpy(dctx->buf + dctx->buflen, src, bytes);
+ src += bytes;
+ srclen -= bytes;
+ dctx->buflen += bytes;
+
+ if (dctx->buflen == POLY1305_BLOCK_SIZE) {
+ poly1305_blocks(dctx, dctx->buf,
+ POLY1305_BLOCK_SIZE, 1 << 24);
+ dctx->buflen = 0;
+ }
+ }
+
+ if (likely(srclen >= POLY1305_BLOCK_SIZE)) {
+ bytes = poly1305_blocks(dctx, src, srclen, 1 << 24);
+ src += srclen - bytes;
+ srclen = bytes;
+ }
+
+ if (unlikely(srclen)) {
+ dctx->buflen = srclen;
+ memcpy(dctx->buf, src, srclen);
+ }
+
+ return 0;
+}
+
+static int poly1305_final(struct shash_desc *desc, u8 *dst)
+{
+ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+ __le32 *mac = (__le32 *)dst;
+ u32 h0, h1, h2, h3, h4;
+ u32 g0, g1, g2, g3, g4;
+ u32 mask;
+ u64 f = 0;
+
+ if (unlikely(!dctx->sset))
+ return -ENOKEY;
+
+ if (unlikely(dctx->buflen)) {
+ dctx->buf[dctx->buflen++] = 1;
+ memset(dctx->buf + dctx->buflen, 0,
+ POLY1305_BLOCK_SIZE - dctx->buflen);
+ poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE, 0);
+ }
+
+ /* fully carry h */
+ h0 = dctx->h[0];
+ h1 = dctx->h[1];
+ h2 = dctx->h[2];
+ h3 = dctx->h[3];
+ h4 = dctx->h[4];
+
+ h2 += (h1 >> 26); h1 = h1 & 0x3ffffff;
+ h3 += (h2 >> 26); h2 = h2 & 0x3ffffff;
+ h4 += (h3 >> 26); h3 = h3 & 0x3ffffff;
+ h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
+ h1 += (h0 >> 26); h0 = h0 & 0x3ffffff;
+
+ /* compute h + -p */
+ g0 = h0 + 5;
+ g1 = h1 + (g0 >> 26); g0 &= 0x3ffffff;
+ g2 = h2 + (g1 >> 26); g1 &= 0x3ffffff;
+ g3 = h3 + (g2 >> 26); g2 &= 0x3ffffff;
+ g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
+
+ /* select h if h < p, or h + -p if h >= p */
+ mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1;
+ g0 &= mask;
+ g1 &= mask;
+ g2 &= mask;
+ g3 &= mask;
+ g4 &= mask;
+ mask = ~mask;
+ h0 = (h0 & mask) | g0;
+ h1 = (h1 & mask) | g1;
+ h2 = (h2 & mask) | g2;
+ h3 = (h3 & mask) | g3;
+ h4 = (h4 & mask) | g4;
+
+ /* h = h % (2^128) */
+ h0 = (h0 >> 0) | (h1 << 26);
+ h1 = (h1 >> 6) | (h2 << 20);
+ h2 = (h2 >> 12) | (h3 << 14);
+ h3 = (h3 >> 18) | (h4 << 8);
+
+ /* mac = (h + s) % (2^128) */
+ f = (f >> 32) + h0 + dctx->s[0]; mac[0] = cpu_to_le32(f);
+ f = (f >> 32) + h1 + dctx->s[1]; mac[1] = cpu_to_le32(f);
+ f = (f >> 32) + h2 + dctx->s[2]; mac[2] = cpu_to_le32(f);
+ f = (f >> 32) + h3 + dctx->s[3]; mac[3] = cpu_to_le32(f);
+
+ return 0;
+}
+
+static struct shash_alg poly1305_alg = {
+ .digestsize = POLY1305_DIGEST_SIZE,
+ .init = poly1305_init,
+ .update = poly1305_update,
+ .final = poly1305_final,
+ .setkey = poly1305_setkey,
+ .descsize = sizeof(struct poly1305_desc_ctx),
+ .base = {
+ .cra_name = "poly1305",
+ .cra_driver_name = "poly1305-generic",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_alignmask = sizeof(u32) - 1,
+ .cra_blocksize = POLY1305_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ },
+};
+
+static int __init poly1305_mod_init(void)
+{
+ return crypto_register_shash(&poly1305_alg);
+}
+
+static void __exit poly1305_mod_exit(void)
+{
+ crypto_unregister_shash(&poly1305_alg);
+}
+
+module_init(poly1305_mod_init);
+module_exit(poly1305_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
+MODULE_DESCRIPTION("Poly1305 authenticator");
+MODULE_ALIAS_CRYPTO("poly1305");
+MODULE_ALIAS_CRYPTO("poly1305-generic");
diff --git a/crypto/proc.c b/crypto/proc.c
index 4ffe73b51612..2cc10c96d753 100644
--- a/crypto/proc.c
+++ b/crypto/proc.c
@@ -20,47 +20,8 @@
#include <linux/rwsem.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/sysctl.h>
#include "internal.h"
-#ifdef CONFIG_CRYPTO_FIPS
-static struct ctl_table crypto_sysctl_table[] = {
- {
- .procname = "fips_enabled",
- .data = &fips_enabled,
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = proc_dointvec
- },
- {}
-};
-
-static struct ctl_table crypto_dir_table[] = {
- {
- .procname = "crypto",
- .mode = 0555,
- .child = crypto_sysctl_table
- },
- {}
-};
-
-static struct ctl_table_header *crypto_sysctls;
-
-static void crypto_proc_fips_init(void)
-{
- crypto_sysctls = register_sysctl_table(crypto_dir_table);
-}
-
-static void crypto_proc_fips_exit(void)
-{
- if (crypto_sysctls)
- unregister_sysctl_table(crypto_sysctls);
-}
-#else
-#define crypto_proc_fips_init()
-#define crypto_proc_fips_exit()
-#endif
-
static void *c_start(struct seq_file *m, loff_t *pos)
{
down_read(&crypto_alg_sem);
@@ -148,11 +109,9 @@ static const struct file_operations proc_crypto_ops = {
void __init crypto_init_proc(void)
{
proc_create("crypto", 0, NULL, &proc_crypto_ops);
- crypto_proc_fips_init();
}
void __exit crypto_exit_proc(void)
{
- crypto_proc_fips_exit();
remove_proc_entry("crypto", NULL);
}
diff --git a/crypto/rng.c b/crypto/rng.c
index e0a25c2456de..b81cffb13bab 100644
--- a/crypto/rng.c
+++ b/crypto/rng.c
@@ -4,6 +4,7 @@
* RNG operations.
*
* Copyright (c) 2008 Neil Horman <nhorman@tuxdriver.com>
+ * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au>
*
* 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
@@ -24,12 +25,19 @@
#include <linux/cryptouser.h>
#include <net/netlink.h>
+#include "internal.h"
+
static DEFINE_MUTEX(crypto_default_rng_lock);
struct crypto_rng *crypto_default_rng;
EXPORT_SYMBOL_GPL(crypto_default_rng);
static int crypto_default_rng_refcnt;
-static int rngapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+static inline struct crypto_rng *__crypto_rng_cast(struct crypto_tfm *tfm)
+{
+ return container_of(tfm, struct crypto_rng, base);
+}
+
+int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen)
{
u8 *buf = NULL;
int err;
@@ -43,21 +51,23 @@ static int rngapi_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
seed = buf;
}
- err = crypto_rng_alg(tfm)->rng_reset(tfm, seed, slen);
+ err = crypto_rng_alg(tfm)->seed(tfm, seed, slen);
- kfree(buf);
+ kzfree(buf);
return err;
}
+EXPORT_SYMBOL_GPL(crypto_rng_reset);
-static int crypto_init_rng_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+static int crypto_rng_init_tfm(struct crypto_tfm *tfm)
{
- struct rng_alg *alg = &tfm->__crt_alg->cra_rng;
- struct rng_tfm *ops = &tfm->crt_rng;
+ return 0;
+}
- ops->rng_gen_random = alg->rng_make_random;
- ops->rng_reset = rngapi_reset;
+static unsigned int seedsize(struct crypto_alg *alg)
+{
+ struct rng_alg *ralg = container_of(alg, struct rng_alg, base);
- return 0;
+ return ralg->seedsize;
}
#ifdef CONFIG_NET
@@ -67,7 +77,7 @@ static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg)
strncpy(rrng.type, "rng", sizeof(rrng.type));
- rrng.seedsize = alg->cra_rng.seedsize;
+ rrng.seedsize = seedsize(alg);
if (nla_put(skb, CRYPTOCFGA_REPORT_RNG,
sizeof(struct crypto_report_rng), &rrng))
@@ -89,24 +99,27 @@ static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
{
seq_printf(m, "type : rng\n");
- seq_printf(m, "seedsize : %u\n", alg->cra_rng.seedsize);
-}
-
-static unsigned int crypto_rng_ctxsize(struct crypto_alg *alg, u32 type,
- u32 mask)
-{
- return alg->cra_ctxsize;
+ seq_printf(m, "seedsize : %u\n", seedsize(alg));
}
-const struct crypto_type crypto_rng_type = {
- .ctxsize = crypto_rng_ctxsize,
- .init = crypto_init_rng_ops,
+static const struct crypto_type crypto_rng_type = {
+ .extsize = crypto_alg_extsize,
+ .init_tfm = crypto_rng_init_tfm,
#ifdef CONFIG_PROC_FS
.show = crypto_rng_show,
#endif
.report = crypto_rng_report,
+ .maskclear = ~CRYPTO_ALG_TYPE_MASK,
+ .maskset = CRYPTO_ALG_TYPE_MASK,
+ .type = CRYPTO_ALG_TYPE_RNG,
+ .tfmsize = offsetof(struct crypto_rng, base),
};
-EXPORT_SYMBOL_GPL(crypto_rng_type);
+
+struct crypto_rng *crypto_alloc_rng(const char *alg_name, u32 type, u32 mask)
+{
+ return crypto_alloc_tfm(alg_name, &crypto_rng_type, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_rng);
int crypto_get_default_rng(void)
{
@@ -142,13 +155,82 @@ EXPORT_SYMBOL_GPL(crypto_get_default_rng);
void crypto_put_default_rng(void)
{
mutex_lock(&crypto_default_rng_lock);
- if (!--crypto_default_rng_refcnt) {
- crypto_free_rng(crypto_default_rng);
- crypto_default_rng = NULL;
- }
+ crypto_default_rng_refcnt--;
mutex_unlock(&crypto_default_rng_lock);
}
EXPORT_SYMBOL_GPL(crypto_put_default_rng);
+#if defined(CONFIG_CRYPTO_RNG) || defined(CONFIG_CRYPTO_RNG_MODULE)
+int crypto_del_default_rng(void)
+{
+ int err = -EBUSY;
+
+ mutex_lock(&crypto_default_rng_lock);
+ if (crypto_default_rng_refcnt)
+ goto out;
+
+ crypto_free_rng(crypto_default_rng);
+ crypto_default_rng = NULL;
+
+ err = 0;
+
+out:
+ mutex_unlock(&crypto_default_rng_lock);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(crypto_del_default_rng);
+#endif
+
+int crypto_register_rng(struct rng_alg *alg)
+{
+ struct crypto_alg *base = &alg->base;
+
+ if (alg->seedsize > PAGE_SIZE / 8)
+ return -EINVAL;
+
+ base->cra_type = &crypto_rng_type;
+ base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
+ base->cra_flags |= CRYPTO_ALG_TYPE_RNG;
+
+ return crypto_register_alg(base);
+}
+EXPORT_SYMBOL_GPL(crypto_register_rng);
+
+void crypto_unregister_rng(struct rng_alg *alg)
+{
+ crypto_unregister_alg(&alg->base);
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_rng);
+
+int crypto_register_rngs(struct rng_alg *algs, int count)
+{
+ int i, ret;
+
+ for (i = 0; i < count; i++) {
+ ret = crypto_register_rng(algs + i);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ for (--i; i >= 0; --i)
+ crypto_unregister_rng(algs + i);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(crypto_register_rngs);
+
+void crypto_unregister_rngs(struct rng_alg *algs, int count)
+{
+ int i;
+
+ for (i = count - 1; i >= 0; --i)
+ crypto_unregister_rng(algs + i);
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_rngs);
+
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Random Number Generator");
diff --git a/crypto/rsa.c b/crypto/rsa.c
new file mode 100644
index 000000000000..752af0656f2e
--- /dev/null
+++ b/crypto/rsa.c
@@ -0,0 +1,315 @@
+/* RSA asymmetric public-key algorithm [RFC3447]
+ *
+ * Copyright (c) 2015, Intel Corporation
+ * Authors: Tadeusz Struk <tadeusz.struk@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <crypto/internal/rsa.h>
+#include <crypto/internal/akcipher.h>
+#include <crypto/akcipher.h>
+
+/*
+ * RSAEP function [RFC3447 sec 5.1.1]
+ * c = m^e mod n;
+ */
+static int _rsa_enc(const struct rsa_key *key, MPI c, MPI m)
+{
+ /* (1) Validate 0 <= m < n */
+ if (mpi_cmp_ui(m, 0) < 0 || mpi_cmp(m, key->n) >= 0)
+ return -EINVAL;
+
+ /* (2) c = m^e mod n */
+ return mpi_powm(c, m, key->e, key->n);
+}
+
+/*
+ * RSADP function [RFC3447 sec 5.1.2]
+ * m = c^d mod n;
+ */
+static int _rsa_dec(const struct rsa_key *key, MPI m, MPI c)
+{
+ /* (1) Validate 0 <= c < n */
+ if (mpi_cmp_ui(c, 0) < 0 || mpi_cmp(c, key->n) >= 0)
+ return -EINVAL;
+
+ /* (2) m = c^d mod n */
+ return mpi_powm(m, c, key->d, key->n);
+}
+
+/*
+ * RSASP1 function [RFC3447 sec 5.2.1]
+ * s = m^d mod n
+ */
+static int _rsa_sign(const struct rsa_key *key, MPI s, MPI m)
+{
+ /* (1) Validate 0 <= m < n */
+ if (mpi_cmp_ui(m, 0) < 0 || mpi_cmp(m, key->n) >= 0)
+ return -EINVAL;
+
+ /* (2) s = m^d mod n */
+ return mpi_powm(s, m, key->d, key->n);
+}
+
+/*
+ * RSAVP1 function [RFC3447 sec 5.2.2]
+ * m = s^e mod n;
+ */
+static int _rsa_verify(const struct rsa_key *key, MPI m, MPI s)
+{
+ /* (1) Validate 0 <= s < n */
+ if (mpi_cmp_ui(s, 0) < 0 || mpi_cmp(s, key->n) >= 0)
+ return -EINVAL;
+
+ /* (2) m = s^e mod n */
+ return mpi_powm(m, s, key->e, key->n);
+}
+
+static inline struct rsa_key *rsa_get_key(struct crypto_akcipher *tfm)
+{
+ return akcipher_tfm_ctx(tfm);
+}
+
+static int rsa_enc(struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ const struct rsa_key *pkey = rsa_get_key(tfm);
+ MPI m, c = mpi_alloc(0);
+ int ret = 0;
+ int sign;
+
+ if (!c)
+ return -ENOMEM;
+
+ if (unlikely(!pkey->n || !pkey->e)) {
+ ret = -EINVAL;
+ goto err_free_c;
+ }
+
+ if (req->dst_len < mpi_get_size(pkey->n)) {
+ req->dst_len = mpi_get_size(pkey->n);
+ ret = -EOVERFLOW;
+ goto err_free_c;
+ }
+
+ m = mpi_read_raw_data(req->src, req->src_len);
+ if (!m) {
+ ret = -ENOMEM;
+ goto err_free_c;
+ }
+
+ ret = _rsa_enc(pkey, c, m);
+ if (ret)
+ goto err_free_m;
+
+ ret = mpi_read_buffer(c, req->dst, req->dst_len, &req->dst_len, &sign);
+ if (ret)
+ goto err_free_m;
+
+ if (sign < 0) {
+ ret = -EBADMSG;
+ goto err_free_m;
+ }
+
+err_free_m:
+ mpi_free(m);
+err_free_c:
+ mpi_free(c);
+ return ret;
+}
+
+static int rsa_dec(struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ const struct rsa_key *pkey = rsa_get_key(tfm);
+ MPI c, m = mpi_alloc(0);
+ int ret = 0;
+ int sign;
+
+ if (!m)
+ return -ENOMEM;
+
+ if (unlikely(!pkey->n || !pkey->d)) {
+ ret = -EINVAL;
+ goto err_free_m;
+ }
+
+ if (req->dst_len < mpi_get_size(pkey->n)) {
+ req->dst_len = mpi_get_size(pkey->n);
+ ret = -EOVERFLOW;
+ goto err_free_m;
+ }
+
+ c = mpi_read_raw_data(req->src, req->src_len);
+ if (!c) {
+ ret = -ENOMEM;
+ goto err_free_m;
+ }
+
+ ret = _rsa_dec(pkey, m, c);
+ if (ret)
+ goto err_free_c;
+
+ ret = mpi_read_buffer(m, req->dst, req->dst_len, &req->dst_len, &sign);
+ if (ret)
+ goto err_free_c;
+
+ if (sign < 0) {
+ ret = -EBADMSG;
+ goto err_free_c;
+ }
+
+err_free_c:
+ mpi_free(c);
+err_free_m:
+ mpi_free(m);
+ return ret;
+}
+
+static int rsa_sign(struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ const struct rsa_key *pkey = rsa_get_key(tfm);
+ MPI m, s = mpi_alloc(0);
+ int ret = 0;
+ int sign;
+
+ if (!s)
+ return -ENOMEM;
+
+ if (unlikely(!pkey->n || !pkey->d)) {
+ ret = -EINVAL;
+ goto err_free_s;
+ }
+
+ if (req->dst_len < mpi_get_size(pkey->n)) {
+ req->dst_len = mpi_get_size(pkey->n);
+ ret = -EOVERFLOW;
+ goto err_free_s;
+ }
+
+ m = mpi_read_raw_data(req->src, req->src_len);
+ if (!m) {
+ ret = -ENOMEM;
+ goto err_free_s;
+ }
+
+ ret = _rsa_sign(pkey, s, m);
+ if (ret)
+ goto err_free_m;
+
+ ret = mpi_read_buffer(s, req->dst, req->dst_len, &req->dst_len, &sign);
+ if (ret)
+ goto err_free_m;
+
+ if (sign < 0) {
+ ret = -EBADMSG;
+ goto err_free_m;
+ }
+
+err_free_m:
+ mpi_free(m);
+err_free_s:
+ mpi_free(s);
+ return ret;
+}
+
+static int rsa_verify(struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ const struct rsa_key *pkey = rsa_get_key(tfm);
+ MPI s, m = mpi_alloc(0);
+ int ret = 0;
+ int sign;
+
+ if (!m)
+ return -ENOMEM;
+
+ if (unlikely(!pkey->n || !pkey->e)) {
+ ret = -EINVAL;
+ goto err_free_m;
+ }
+
+ if (req->dst_len < mpi_get_size(pkey->n)) {
+ req->dst_len = mpi_get_size(pkey->n);
+ ret = -EOVERFLOW;
+ goto err_free_m;
+ }
+
+ s = mpi_read_raw_data(req->src, req->src_len);
+ if (!s) {
+ ret = -ENOMEM;
+ goto err_free_m;
+ }
+
+ ret = _rsa_verify(pkey, m, s);
+ if (ret)
+ goto err_free_s;
+
+ ret = mpi_read_buffer(m, req->dst, req->dst_len, &req->dst_len, &sign);
+ if (ret)
+ goto err_free_s;
+
+ if (sign < 0) {
+ ret = -EBADMSG;
+ goto err_free_s;
+ }
+
+err_free_s:
+ mpi_free(s);
+err_free_m:
+ mpi_free(m);
+ return ret;
+}
+
+static int rsa_setkey(struct crypto_akcipher *tfm, const void *key,
+ unsigned int keylen)
+{
+ struct rsa_key *pkey = akcipher_tfm_ctx(tfm);
+
+ return rsa_parse_key(pkey, key, keylen);
+}
+
+static void rsa_exit_tfm(struct crypto_akcipher *tfm)
+{
+ struct rsa_key *pkey = akcipher_tfm_ctx(tfm);
+
+ rsa_free_key(pkey);
+}
+
+static struct akcipher_alg rsa = {
+ .encrypt = rsa_enc,
+ .decrypt = rsa_dec,
+ .sign = rsa_sign,
+ .verify = rsa_verify,
+ .setkey = rsa_setkey,
+ .exit = rsa_exit_tfm,
+ .base = {
+ .cra_name = "rsa",
+ .cra_driver_name = "rsa-generic",
+ .cra_priority = 100,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct rsa_key),
+ },
+};
+
+static int rsa_init(void)
+{
+ return crypto_register_akcipher(&rsa);
+}
+
+static void rsa_exit(void)
+{
+ crypto_unregister_akcipher(&rsa);
+}
+
+module_init(rsa_init);
+module_exit(rsa_exit);
+MODULE_ALIAS_CRYPTO("rsa");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RSA generic algorithm");
diff --git a/crypto/rsa_helper.c b/crypto/rsa_helper.c
new file mode 100644
index 000000000000..3e8e0a9e5a8e
--- /dev/null
+++ b/crypto/rsa_helper.c
@@ -0,0 +1,121 @@
+/*
+ * RSA key extract helper
+ *
+ * Copyright (c) 2015, Intel Corporation
+ * Authors: Tadeusz Struk <tadeusz.struk@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; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/fips.h>
+#include <crypto/internal/rsa.h>
+#include "rsakey-asn1.h"
+
+int rsa_get_n(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct rsa_key *key = context;
+
+ key->n = mpi_read_raw_data(value, vlen);
+
+ if (!key->n)
+ return -ENOMEM;
+
+ /* In FIPS mode only allow key size 2K & 3K */
+ if (fips_enabled && (mpi_get_size(key->n) != 256 ||
+ mpi_get_size(key->n) != 384)) {
+ pr_err("RSA: key size not allowed in FIPS mode\n");
+ mpi_free(key->n);
+ key->n = NULL;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int rsa_get_e(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct rsa_key *key = context;
+
+ key->e = mpi_read_raw_data(value, vlen);
+
+ if (!key->e)
+ return -ENOMEM;
+
+ return 0;
+}
+
+int rsa_get_d(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct rsa_key *key = context;
+
+ key->d = mpi_read_raw_data(value, vlen);
+
+ if (!key->d)
+ return -ENOMEM;
+
+ /* In FIPS mode only allow key size 2K & 3K */
+ if (fips_enabled && (mpi_get_size(key->d) != 256 ||
+ mpi_get_size(key->d) != 384)) {
+ pr_err("RSA: key size not allowed in FIPS mode\n");
+ mpi_free(key->d);
+ key->d = NULL;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void free_mpis(struct rsa_key *key)
+{
+ mpi_free(key->n);
+ mpi_free(key->e);
+ mpi_free(key->d);
+ key->n = NULL;
+ key->e = NULL;
+ key->d = NULL;
+}
+
+/**
+ * rsa_free_key() - frees rsa key allocated by rsa_parse_key()
+ *
+ * @rsa_key: struct rsa_key key representation
+ */
+void rsa_free_key(struct rsa_key *key)
+{
+ free_mpis(key);
+}
+EXPORT_SYMBOL_GPL(rsa_free_key);
+
+/**
+ * rsa_parse_key() - extracts an rsa key from BER encoded buffer
+ * and stores it in the provided struct rsa_key
+ *
+ * @rsa_key: struct rsa_key key representation
+ * @key: key in BER format
+ * @key_len: length of key
+ *
+ * Return: 0 on success or error code in case of error
+ */
+int rsa_parse_key(struct rsa_key *rsa_key, const void *key,
+ unsigned int key_len)
+{
+ int ret;
+
+ free_mpis(rsa_key);
+ ret = asn1_ber_decoder(&rsakey_decoder, rsa_key, key, key_len);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+error:
+ free_mpis(rsa_key);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rsa_parse_key);
diff --git a/crypto/rsakey.asn1 b/crypto/rsakey.asn1
new file mode 100644
index 000000000000..3c7b5df7b428
--- /dev/null
+++ b/crypto/rsakey.asn1
@@ -0,0 +1,5 @@
+RsaKey ::= SEQUENCE {
+ n INTEGER ({ rsa_get_n }),
+ e INTEGER ({ rsa_get_e }),
+ d INTEGER ({ rsa_get_d })
+}
diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c
index 3bd749c7bb70..ea5815c5e128 100644
--- a/crypto/scatterwalk.c
+++ b/crypto/scatterwalk.c
@@ -54,7 +54,11 @@ static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
struct page *page;
page = sg_page(walk->sg) + ((walk->offset - 1) >> PAGE_SHIFT);
- if (!PageSlab(page))
+ /* Test ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE first as
+ * PageSlab cannot be optimised away per se due to
+ * use of volatile pointer.
+ */
+ if (ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE && !PageSlab(page))
flush_dcache_page(page);
}
@@ -104,22 +108,18 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
unsigned int start, unsigned int nbytes, int out)
{
struct scatter_walk walk;
- unsigned int offset = 0;
+ struct scatterlist tmp[2];
if (!nbytes)
return;
- for (;;) {
- scatterwalk_start(&walk, sg);
-
- if (start < offset + sg->length)
- break;
+ sg = scatterwalk_ffwd(tmp, sg, start);
- offset += sg->length;
- sg = sg_next(sg);
- }
+ if (sg_page(sg) == virt_to_page(buf) &&
+ sg->offset == offset_in_page(buf))
+ return;
- scatterwalk_advance(&walk, start - offset);
+ scatterwalk_start(&walk, sg);
scatterwalk_copychunks(buf, &walk, nbytes, out);
scatterwalk_done(&walk, out, 0);
}
@@ -146,3 +146,26 @@ int scatterwalk_bytes_sglen(struct scatterlist *sg, int num_bytes)
return n;
}
EXPORT_SYMBOL_GPL(scatterwalk_bytes_sglen);
+
+struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2],
+ struct scatterlist *src,
+ unsigned int len)
+{
+ for (;;) {
+ if (!len)
+ return src;
+
+ if (src->length > len)
+ break;
+
+ len -= src->length;
+ src = sg_next(src);
+ }
+
+ sg_init_table(dst, 2);
+ sg_set_page(dst, sg_page(src), src->length - len, src->offset + len);
+ scatterwalk_crypto_chain(dst, sg_next(src), 0, 2);
+
+ return dst;
+}
+EXPORT_SYMBOL_GPL(scatterwalk_ffwd);
diff --git a/crypto/seqiv.c b/crypto/seqiv.c
index b7bb9a2f4a31..122c56e3491b 100644
--- a/crypto/seqiv.c
+++ b/crypto/seqiv.c
@@ -13,9 +13,11 @@
*
*/
-#include <crypto/internal/aead.h>
+#include <crypto/internal/geniv.h>
#include <crypto/internal/skcipher.h>
+#include <crypto/null.h>
#include <crypto/rng.h>
+#include <crypto/scatterwalk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -24,11 +26,25 @@
#include <linux/spinlock.h>
#include <linux/string.h>
+struct seqniv_request_ctx {
+ struct scatterlist dst[2];
+ struct aead_request subreq;
+};
+
struct seqiv_ctx {
spinlock_t lock;
u8 salt[] __attribute__ ((aligned(__alignof__(u32))));
};
+struct seqiv_aead_ctx {
+ /* aead_geniv_ctx must be first the element */
+ struct aead_geniv_ctx geniv;
+ struct crypto_blkcipher *null;
+ u8 salt[] __attribute__ ((aligned(__alignof__(u32))));
+};
+
+static void seqiv_free(struct crypto_instance *inst);
+
static void seqiv_complete2(struct skcipher_givcrypt_request *req, int err)
{
struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
@@ -81,6 +97,77 @@ static void seqiv_aead_complete(struct crypto_async_request *base, int err)
aead_givcrypt_complete(req, err);
}
+static void seqiv_aead_encrypt_complete2(struct aead_request *req, int err)
+{
+ struct aead_request *subreq = aead_request_ctx(req);
+ struct crypto_aead *geniv;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ if (err)
+ goto out;
+
+ geniv = crypto_aead_reqtfm(req);
+ memcpy(req->iv, subreq->iv, crypto_aead_ivsize(geniv));
+
+out:
+ kzfree(subreq->iv);
+}
+
+static void seqiv_aead_encrypt_complete(struct crypto_async_request *base,
+ int err)
+{
+ struct aead_request *req = base->data;
+
+ seqiv_aead_encrypt_complete2(req, err);
+ aead_request_complete(req, err);
+}
+
+static void seqniv_aead_encrypt_complete2(struct aead_request *req, int err)
+{
+ unsigned int ivsize = 8;
+ u8 data[20];
+
+ if (err == -EINPROGRESS)
+ return;
+
+ /* Swap IV and ESP header back to correct order. */
+ scatterwalk_map_and_copy(data, req->dst, 0, req->assoclen + ivsize, 0);
+ scatterwalk_map_and_copy(data + ivsize, req->dst, 0, req->assoclen, 1);
+ scatterwalk_map_and_copy(data, req->dst, req->assoclen, ivsize, 1);
+}
+
+static void seqniv_aead_encrypt_complete(struct crypto_async_request *base,
+ int err)
+{
+ struct aead_request *req = base->data;
+
+ seqniv_aead_encrypt_complete2(req, err);
+ aead_request_complete(req, err);
+}
+
+static void seqniv_aead_decrypt_complete2(struct aead_request *req, int err)
+{
+ u8 data[4];
+
+ if (err == -EINPROGRESS)
+ return;
+
+ /* Move ESP header back to correct location. */
+ scatterwalk_map_and_copy(data, req->dst, 16, req->assoclen - 8, 0);
+ scatterwalk_map_and_copy(data, req->dst, 8, req->assoclen - 8, 1);
+}
+
+static void seqniv_aead_decrypt_complete(struct crypto_async_request *base,
+ int err)
+{
+ struct aead_request *req = base->data;
+
+ seqniv_aead_decrypt_complete2(req, err);
+ aead_request_complete(req, err);
+}
+
static void seqiv_geniv(struct seqiv_ctx *ctx, u8 *info, u64 seq,
unsigned int ivsize)
{
@@ -186,160 +273,477 @@ static int seqiv_aead_givencrypt(struct aead_givcrypt_request *req)
return err;
}
-static int seqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
+static int seqniv_aead_encrypt(struct aead_request *req)
{
- struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
- struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
- int err = 0;
+ struct crypto_aead *geniv = crypto_aead_reqtfm(req);
+ struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv);
+ struct seqniv_request_ctx *rctx = aead_request_ctx(req);
+ struct aead_request *subreq = &rctx->subreq;
+ struct scatterlist *dst;
+ crypto_completion_t compl;
+ void *data;
+ unsigned int ivsize = 8;
+ u8 buf[20] __attribute__ ((aligned(__alignof__(u32))));
+ int err;
- spin_lock_bh(&ctx->lock);
- if (crypto_ablkcipher_crt(geniv)->givencrypt != seqiv_givencrypt_first)
- goto unlock;
+ if (req->cryptlen < ivsize)
+ return -EINVAL;
- crypto_ablkcipher_crt(geniv)->givencrypt = seqiv_givencrypt;
- err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
- crypto_ablkcipher_ivsize(geniv));
+ /* ESP AD is at most 12 bytes (ESN). */
+ if (req->assoclen > 12)
+ return -EINVAL;
-unlock:
- spin_unlock_bh(&ctx->lock);
+ aead_request_set_tfm(subreq, ctx->geniv.child);
- if (err)
- return err;
+ compl = seqniv_aead_encrypt_complete;
+ data = req;
+
+ if (req->src != req->dst) {
+ struct blkcipher_desc desc = {
+ .tfm = ctx->null,
+ };
+
+ err = crypto_blkcipher_encrypt(&desc, req->dst, req->src,
+ req->assoclen + req->cryptlen);
+ if (err)
+ return err;
+ }
- return seqiv_givencrypt(req);
+ dst = scatterwalk_ffwd(rctx->dst, req->dst, ivsize);
+
+ aead_request_set_callback(subreq, req->base.flags, compl, data);
+ aead_request_set_crypt(subreq, dst, dst,
+ req->cryptlen - ivsize, req->iv);
+ aead_request_set_ad(subreq, req->assoclen);
+
+ memcpy(buf, req->iv, ivsize);
+ crypto_xor(buf, ctx->salt, ivsize);
+ memcpy(req->iv, buf, ivsize);
+
+ /* Swap order of IV and ESP AD for ICV generation. */
+ scatterwalk_map_and_copy(buf + ivsize, req->dst, 0, req->assoclen, 0);
+ scatterwalk_map_and_copy(buf, req->dst, 0, req->assoclen + ivsize, 1);
+
+ err = crypto_aead_encrypt(subreq);
+ seqniv_aead_encrypt_complete2(req, err);
+ return err;
}
-static int seqiv_aead_givencrypt_first(struct aead_givcrypt_request *req)
+static int seqiv_aead_encrypt(struct aead_request *req)
{
- struct crypto_aead *geniv = aead_givcrypt_reqtfm(req);
- struct seqiv_ctx *ctx = crypto_aead_ctx(geniv);
- int err = 0;
+ struct crypto_aead *geniv = crypto_aead_reqtfm(req);
+ struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv);
+ struct aead_request *subreq = aead_request_ctx(req);
+ crypto_completion_t compl;
+ void *data;
+ u8 *info;
+ unsigned int ivsize = 8;
+ int err;
- spin_lock_bh(&ctx->lock);
- if (crypto_aead_crt(geniv)->givencrypt != seqiv_aead_givencrypt_first)
- goto unlock;
+ if (req->cryptlen < ivsize)
+ return -EINVAL;
- crypto_aead_crt(geniv)->givencrypt = seqiv_aead_givencrypt;
- err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
- crypto_aead_ivsize(geniv));
+ aead_request_set_tfm(subreq, ctx->geniv.child);
-unlock:
- spin_unlock_bh(&ctx->lock);
+ compl = req->base.complete;
+ data = req->base.data;
+ info = req->iv;
- if (err)
- return err;
+ if (req->src != req->dst) {
+ struct blkcipher_desc desc = {
+ .tfm = ctx->null,
+ };
- return seqiv_aead_givencrypt(req);
+ err = crypto_blkcipher_encrypt(&desc, req->dst, req->src,
+ req->assoclen + req->cryptlen);
+ if (err)
+ return err;
+ }
+
+ if (unlikely(!IS_ALIGNED((unsigned long)info,
+ crypto_aead_alignmask(geniv) + 1))) {
+ info = kmalloc(ivsize, req->base.flags &
+ CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
+ GFP_ATOMIC);
+ if (!info)
+ return -ENOMEM;
+
+ memcpy(info, req->iv, ivsize);
+ compl = seqiv_aead_encrypt_complete;
+ data = req;
+ }
+
+ aead_request_set_callback(subreq, req->base.flags, compl, data);
+ aead_request_set_crypt(subreq, req->dst, req->dst,
+ req->cryptlen - ivsize, info);
+ aead_request_set_ad(subreq, req->assoclen + ivsize);
+
+ crypto_xor(info, ctx->salt, ivsize);
+ scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1);
+
+ err = crypto_aead_encrypt(subreq);
+ if (unlikely(info != req->iv))
+ seqiv_aead_encrypt_complete2(req, err);
+ return err;
+}
+
+static int seqniv_aead_decrypt(struct aead_request *req)
+{
+ struct crypto_aead *geniv = crypto_aead_reqtfm(req);
+ struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv);
+ struct seqniv_request_ctx *rctx = aead_request_ctx(req);
+ struct aead_request *subreq = &rctx->subreq;
+ struct scatterlist *dst;
+ crypto_completion_t compl;
+ void *data;
+ unsigned int ivsize = 8;
+ u8 buf[20];
+ int err;
+
+ if (req->cryptlen < ivsize + crypto_aead_authsize(geniv))
+ return -EINVAL;
+
+ aead_request_set_tfm(subreq, ctx->geniv.child);
+
+ compl = req->base.complete;
+ data = req->base.data;
+
+ if (req->assoclen > 12)
+ return -EINVAL;
+ else if (req->assoclen > 8) {
+ compl = seqniv_aead_decrypt_complete;
+ data = req;
+ }
+
+ if (req->src != req->dst) {
+ struct blkcipher_desc desc = {
+ .tfm = ctx->null,
+ };
+
+ err = crypto_blkcipher_encrypt(&desc, req->dst, req->src,
+ req->assoclen + req->cryptlen);
+ if (err)
+ return err;
+ }
+
+ /* Move ESP AD forward for ICV generation. */
+ scatterwalk_map_and_copy(buf, req->dst, 0, req->assoclen + ivsize, 0);
+ memcpy(req->iv, buf + req->assoclen, ivsize);
+ scatterwalk_map_and_copy(buf, req->dst, ivsize, req->assoclen, 1);
+
+ dst = scatterwalk_ffwd(rctx->dst, req->dst, ivsize);
+
+ aead_request_set_callback(subreq, req->base.flags, compl, data);
+ aead_request_set_crypt(subreq, dst, dst,
+ req->cryptlen - ivsize, req->iv);
+ aead_request_set_ad(subreq, req->assoclen);
+
+ err = crypto_aead_decrypt(subreq);
+ if (req->assoclen > 8)
+ seqniv_aead_decrypt_complete2(req, err);
+ return err;
+}
+
+static int seqiv_aead_decrypt(struct aead_request *req)
+{
+ struct crypto_aead *geniv = crypto_aead_reqtfm(req);
+ struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv);
+ struct aead_request *subreq = aead_request_ctx(req);
+ crypto_completion_t compl;
+ void *data;
+ unsigned int ivsize = 8;
+
+ if (req->cryptlen < ivsize + crypto_aead_authsize(geniv))
+ return -EINVAL;
+
+ aead_request_set_tfm(subreq, ctx->geniv.child);
+
+ compl = req->base.complete;
+ data = req->base.data;
+
+ aead_request_set_callback(subreq, req->base.flags, compl, data);
+ aead_request_set_crypt(subreq, req->src, req->dst,
+ req->cryptlen - ivsize, req->iv);
+ aead_request_set_ad(subreq, req->assoclen + ivsize);
+
+ scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0);
+ if (req->src != req->dst)
+ scatterwalk_map_and_copy(req->iv, req->dst,
+ req->assoclen, ivsize, 1);
+
+ return crypto_aead_decrypt(subreq);
}
static int seqiv_init(struct crypto_tfm *tfm)
{
struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
+ int err;
spin_lock_init(&ctx->lock);
tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request);
- return skcipher_geniv_init(tfm);
+ err = 0;
+ if (!crypto_get_default_rng()) {
+ crypto_ablkcipher_crt(geniv)->givencrypt = seqiv_givencrypt;
+ err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
+ crypto_ablkcipher_ivsize(geniv));
+ crypto_put_default_rng();
+ }
+
+ return err ?: skcipher_geniv_init(tfm);
}
-static int seqiv_aead_init(struct crypto_tfm *tfm)
+static int seqiv_old_aead_init(struct crypto_tfm *tfm)
{
struct crypto_aead *geniv = __crypto_aead_cast(tfm);
struct seqiv_ctx *ctx = crypto_aead_ctx(geniv);
+ int err;
spin_lock_init(&ctx->lock);
- tfm->crt_aead.reqsize = sizeof(struct aead_request);
+ crypto_aead_set_reqsize(__crypto_aead_cast(tfm),
+ sizeof(struct aead_request));
+ err = 0;
+ if (!crypto_get_default_rng()) {
+ geniv->givencrypt = seqiv_aead_givencrypt;
+ err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
+ crypto_aead_ivsize(geniv));
+ crypto_put_default_rng();
+ }
- return aead_geniv_init(tfm);
+ return err ?: aead_geniv_init(tfm);
}
-static struct crypto_template seqiv_tmpl;
-
-static struct crypto_instance *seqiv_ablkcipher_alloc(struct rtattr **tb)
+static int seqiv_aead_init_common(struct crypto_tfm *tfm, unsigned int reqsize)
{
- struct crypto_instance *inst;
+ struct crypto_aead *geniv = __crypto_aead_cast(tfm);
+ struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv);
+ int err;
- inst = skcipher_geniv_alloc(&seqiv_tmpl, tb, 0, 0);
+ spin_lock_init(&ctx->geniv.lock);
- if (IS_ERR(inst))
+ crypto_aead_set_reqsize(geniv, sizeof(struct aead_request));
+
+ err = crypto_get_default_rng();
+ if (err)
goto out;
- if (inst->alg.cra_ablkcipher.ivsize < sizeof(u64)) {
- skcipher_geniv_free(inst);
- inst = ERR_PTR(-EINVAL);
+ err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
+ crypto_aead_ivsize(geniv));
+ crypto_put_default_rng();
+ if (err)
goto out;
- }
- inst->alg.cra_ablkcipher.givencrypt = seqiv_givencrypt_first;
+ ctx->null = crypto_get_default_null_skcipher();
+ err = PTR_ERR(ctx->null);
+ if (IS_ERR(ctx->null))
+ goto out;
- inst->alg.cra_init = seqiv_init;
- inst->alg.cra_exit = skcipher_geniv_exit;
+ err = aead_geniv_init(tfm);
+ if (err)
+ goto drop_null;
- inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize;
+ ctx->geniv.child = geniv->child;
+ geniv->child = geniv;
out:
- return inst;
+ return err;
+
+drop_null:
+ crypto_put_default_null_skcipher();
+ goto out;
+}
+
+static int seqiv_aead_init(struct crypto_tfm *tfm)
+{
+ return seqiv_aead_init_common(tfm, sizeof(struct aead_request));
+}
+
+static int seqniv_aead_init(struct crypto_tfm *tfm)
+{
+ return seqiv_aead_init_common(tfm, sizeof(struct seqniv_request_ctx));
+}
+
+static void seqiv_aead_exit(struct crypto_tfm *tfm)
+{
+ struct seqiv_aead_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ crypto_free_aead(ctx->geniv.child);
+ crypto_put_default_null_skcipher();
}
-static struct crypto_instance *seqiv_aead_alloc(struct rtattr **tb)
+static int seqiv_ablkcipher_create(struct crypto_template *tmpl,
+ struct rtattr **tb)
{
struct crypto_instance *inst;
+ int err;
- inst = aead_geniv_alloc(&seqiv_tmpl, tb, 0, 0);
+ inst = skcipher_geniv_alloc(tmpl, tb, 0, 0);
if (IS_ERR(inst))
- goto out;
+ return PTR_ERR(inst);
- if (inst->alg.cra_aead.ivsize < sizeof(u64)) {
- aead_geniv_free(inst);
- inst = ERR_PTR(-EINVAL);
- goto out;
- }
+ err = -EINVAL;
+ if (inst->alg.cra_ablkcipher.ivsize < sizeof(u64))
+ goto free_inst;
+
+ inst->alg.cra_init = seqiv_init;
+ inst->alg.cra_exit = skcipher_geniv_exit;
+
+ inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize;
+ inst->alg.cra_ctxsize += sizeof(struct seqiv_ctx);
+
+ inst->alg.cra_alignmask |= __alignof__(u32) - 1;
- inst->alg.cra_aead.givencrypt = seqiv_aead_givencrypt_first;
+ err = crypto_register_instance(tmpl, inst);
+ if (err)
+ goto free_inst;
- inst->alg.cra_init = seqiv_aead_init;
+out:
+ return err;
+
+free_inst:
+ skcipher_geniv_free(inst);
+ goto out;
+}
+
+static int seqiv_old_aead_create(struct crypto_template *tmpl,
+ struct aead_instance *aead)
+{
+ struct crypto_instance *inst = aead_crypto_instance(aead);
+ int err = -EINVAL;
+
+ if (inst->alg.cra_aead.ivsize < sizeof(u64))
+ goto free_inst;
+
+ inst->alg.cra_init = seqiv_old_aead_init;
inst->alg.cra_exit = aead_geniv_exit;
inst->alg.cra_ctxsize = inst->alg.cra_aead.ivsize;
+ inst->alg.cra_ctxsize += sizeof(struct seqiv_ctx);
+
+ err = crypto_register_instance(tmpl, inst);
+ if (err)
+ goto free_inst;
out:
- return inst;
+ return err;
+
+free_inst:
+ aead_geniv_free(aead);
+ goto out;
}
-static struct crypto_instance *seqiv_alloc(struct rtattr **tb)
+static int seqiv_aead_create(struct crypto_template *tmpl, struct rtattr **tb)
+{
+ struct aead_instance *inst;
+ struct crypto_aead_spawn *spawn;
+ struct aead_alg *alg;
+ int err;
+
+ inst = aead_geniv_alloc(tmpl, tb, 0, 0);
+
+ if (IS_ERR(inst))
+ return PTR_ERR(inst);
+
+ inst->alg.base.cra_alignmask |= __alignof__(u32) - 1;
+
+ if (inst->alg.base.cra_aead.encrypt)
+ return seqiv_old_aead_create(tmpl, inst);
+
+ spawn = aead_instance_ctx(inst);
+ alg = crypto_spawn_aead_alg(spawn);
+
+ if (alg->base.cra_aead.encrypt)
+ goto done;
+
+ err = -EINVAL;
+ if (inst->alg.ivsize != sizeof(u64))
+ goto free_inst;
+
+ inst->alg.encrypt = seqiv_aead_encrypt;
+ inst->alg.decrypt = seqiv_aead_decrypt;
+
+ inst->alg.base.cra_init = seqiv_aead_init;
+ inst->alg.base.cra_exit = seqiv_aead_exit;
+
+ inst->alg.base.cra_ctxsize = sizeof(struct seqiv_aead_ctx);
+ inst->alg.base.cra_ctxsize += inst->alg.base.cra_aead.ivsize;
+
+done:
+ err = aead_register_instance(tmpl, inst);
+ if (err)
+ goto free_inst;
+
+out:
+ return err;
+
+free_inst:
+ aead_geniv_free(inst);
+ goto out;
+}
+
+static int seqiv_create(struct crypto_template *tmpl, struct rtattr **tb)
{
struct crypto_attr_type *algt;
- struct crypto_instance *inst;
int err;
algt = crypto_get_attr_type(tb);
if (IS_ERR(algt))
- return ERR_CAST(algt);
-
- err = crypto_get_default_rng();
- if (err)
- return ERR_PTR(err);
+ return PTR_ERR(algt);
if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK)
- inst = seqiv_ablkcipher_alloc(tb);
+ err = seqiv_ablkcipher_create(tmpl, tb);
else
- inst = seqiv_aead_alloc(tb);
+ err = seqiv_aead_create(tmpl, tb);
+ return err;
+}
+
+static int seqniv_create(struct crypto_template *tmpl, struct rtattr **tb)
+{
+ struct aead_instance *inst;
+ struct crypto_aead_spawn *spawn;
+ struct aead_alg *alg;
+ int err;
+
+ inst = aead_geniv_alloc(tmpl, tb, 0, 0);
+ err = PTR_ERR(inst);
if (IS_ERR(inst))
- goto put_rng;
+ goto out;
- inst->alg.cra_alignmask |= __alignof__(u32) - 1;
- inst->alg.cra_ctxsize += sizeof(struct seqiv_ctx);
+ spawn = aead_instance_ctx(inst);
+ alg = crypto_spawn_aead_alg(spawn);
+
+ if (alg->base.cra_aead.encrypt)
+ goto done;
+
+ err = -EINVAL;
+ if (inst->alg.ivsize != sizeof(u64))
+ goto free_inst;
+
+ inst->alg.encrypt = seqniv_aead_encrypt;
+ inst->alg.decrypt = seqniv_aead_decrypt;
+
+ inst->alg.base.cra_init = seqniv_aead_init;
+ inst->alg.base.cra_exit = seqiv_aead_exit;
+
+ inst->alg.base.cra_alignmask |= __alignof__(u32) - 1;
+ inst->alg.base.cra_ctxsize = sizeof(struct seqiv_aead_ctx);
+ inst->alg.base.cra_ctxsize += inst->alg.ivsize;
+
+done:
+ err = aead_register_instance(tmpl, inst);
+ if (err)
+ goto free_inst;
out:
- return inst;
+ return err;
-put_rng:
- crypto_put_default_rng();
+free_inst:
+ aead_geniv_free(inst);
goto out;
}
@@ -348,24 +752,46 @@ static void seqiv_free(struct crypto_instance *inst)
if ((inst->alg.cra_flags ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK)
skcipher_geniv_free(inst);
else
- aead_geniv_free(inst);
- crypto_put_default_rng();
+ aead_geniv_free(aead_instance(inst));
}
static struct crypto_template seqiv_tmpl = {
.name = "seqiv",
- .alloc = seqiv_alloc,
+ .create = seqiv_create,
+ .free = seqiv_free,
+ .module = THIS_MODULE,
+};
+
+static struct crypto_template seqniv_tmpl = {
+ .name = "seqniv",
+ .create = seqniv_create,
.free = seqiv_free,
.module = THIS_MODULE,
};
static int __init seqiv_module_init(void)
{
- return crypto_register_template(&seqiv_tmpl);
+ int err;
+
+ err = crypto_register_template(&seqiv_tmpl);
+ if (err)
+ goto out;
+
+ err = crypto_register_template(&seqniv_tmpl);
+ if (err)
+ goto out_undo_niv;
+
+out:
+ return err;
+
+out_undo_niv:
+ crypto_unregister_template(&seqiv_tmpl);
+ goto out;
}
static void __exit seqiv_module_exit(void)
{
+ crypto_unregister_template(&seqniv_tmpl);
crypto_unregister_template(&seqiv_tmpl);
}
@@ -375,3 +801,4 @@ module_exit(seqiv_module_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Sequence Number IV Generator");
MODULE_ALIAS_CRYPTO("seqiv");
+MODULE_ALIAS_CRYPTO("seqniv");
diff --git a/crypto/shash.c b/crypto/shash.c
index 47c713954bf3..ecb1e3d39bf0 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -520,11 +520,6 @@ static int crypto_shash_init_tfm(struct crypto_tfm *tfm)
return 0;
}
-static unsigned int crypto_shash_extsize(struct crypto_alg *alg)
-{
- return alg->cra_ctxsize;
-}
-
#ifdef CONFIG_NET
static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg)
{
@@ -564,7 +559,7 @@ static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg)
static const struct crypto_type crypto_shash_type = {
.ctxsize = crypto_shash_ctxsize,
- .extsize = crypto_shash_extsize,
+ .extsize = crypto_alg_extsize,
.init = crypto_init_shash_ops,
.init_tfm = crypto_shash_init_tfm,
#ifdef CONFIG_PROC_FS
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 1a2800107fc8..9f6f10b498ba 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -22,8 +22,10 @@
*
*/
+#include <crypto/aead.h>
#include <crypto/hash.h>
#include <linux/err.h>
+#include <linux/fips.h>
#include <linux/init.h>
#include <linux/gfp.h>
#include <linux/module.h>
@@ -34,7 +36,6 @@
#include <linux/timex.h>
#include <linux/interrupt.h>
#include "tcrypt.h"
-#include "internal.h"
/*
* Need slab memory for testing (size in number of pages).
@@ -257,12 +258,12 @@ static void sg_init_aead(struct scatterlist *sg, char *xbuf[XBUFSIZE],
rem = buflen % PAGE_SIZE;
}
- sg_init_table(sg, np);
+ sg_init_table(sg, np + 1);
np--;
for (k = 0; k < np; k++)
- sg_set_buf(&sg[k], xbuf[k], PAGE_SIZE);
+ sg_set_buf(&sg[k + 1], xbuf[k], PAGE_SIZE);
- sg_set_buf(&sg[k], xbuf[k], rem);
+ sg_set_buf(&sg[k + 1], xbuf[k], rem);
}
static void test_aead_speed(const char *algo, int enc, unsigned int secs,
@@ -276,7 +277,6 @@ static void test_aead_speed(const char *algo, int enc, unsigned int secs,
const char *key;
struct aead_request *req;
struct scatterlist *sg;
- struct scatterlist *asg;
struct scatterlist *sgout;
const char *e;
void *assoc;
@@ -308,11 +308,10 @@ static void test_aead_speed(const char *algo, int enc, unsigned int secs,
if (testmgr_alloc_buf(xoutbuf))
goto out_nooutbuf;
- sg = kmalloc(sizeof(*sg) * 8 * 3, GFP_KERNEL);
+ sg = kmalloc(sizeof(*sg) * 9 * 2, GFP_KERNEL);
if (!sg)
goto out_nosg;
- asg = &sg[8];
- sgout = &asg[8];
+ sgout = &sg[9];
tfm = crypto_alloc_aead(algo, 0, 0);
@@ -338,7 +337,6 @@ static void test_aead_speed(const char *algo, int enc, unsigned int secs,
do {
assoc = axbuf[0];
memset(assoc, 0xff, aad_size);
- sg_init_one(&asg[0], assoc, aad_size);
if ((*keysize + *b_size) > TVMEMSIZE * PAGE_SIZE) {
pr_err("template (%u) too big for tvmem (%lu)\n",
@@ -374,14 +372,17 @@ static void test_aead_speed(const char *algo, int enc, unsigned int secs,
goto out;
}
- sg_init_aead(&sg[0], xbuf,
+ sg_init_aead(sg, xbuf,
*b_size + (enc ? authsize : 0));
- sg_init_aead(&sgout[0], xoutbuf,
+ sg_init_aead(sgout, xoutbuf,
*b_size + (enc ? authsize : 0));
+ sg_set_buf(&sg[0], assoc, aad_size);
+ sg_set_buf(&sgout[0], assoc, aad_size);
+
aead_request_set_crypt(req, sg, sgout, *b_size, iv);
- aead_request_set_assoc(req, asg, aad_size);
+ aead_request_set_ad(req, aad_size);
if (secs)
ret = test_aead_jiffies(req, enc, *b_size,
@@ -808,7 +809,7 @@ static int test_ahash_jiffies(struct ahash_request *req, int blen,
for (start = jiffies, end = start + secs * HZ, bcount = 0;
time_before(jiffies, end); bcount++) {
- ret = crypto_ahash_init(req);
+ ret = do_one_ahash_op(req, crypto_ahash_init(req));
if (ret)
return ret;
for (pcount = 0; pcount < blen; pcount += plen) {
@@ -877,7 +878,7 @@ static int test_ahash_cycles(struct ahash_request *req, int blen,
/* Warm-up run. */
for (i = 0; i < 4; i++) {
- ret = crypto_ahash_init(req);
+ ret = do_one_ahash_op(req, crypto_ahash_init(req));
if (ret)
goto out;
for (pcount = 0; pcount < blen; pcount += plen) {
@@ -896,7 +897,7 @@ static int test_ahash_cycles(struct ahash_request *req, int blen,
start = get_cycles();
- ret = crypto_ahash_init(req);
+ ret = do_one_ahash_op(req, crypto_ahash_init(req));
if (ret)
goto out;
for (pcount = 0; pcount < blen; pcount += plen) {
@@ -1761,6 +1762,11 @@ static int do_test(const char *alg, u32 type, u32 mask, int m)
NULL, 0, 16, 8, aead_speed_template_20);
break;
+ case 212:
+ test_aead_speed("rfc4309(ccm(aes))", ENCRYPT, sec,
+ NULL, 0, 16, 8, aead_speed_template_19);
+ break;
+
case 300:
if (alg) {
test_hash_speed(alg, sec, generic_hash_speed_template);
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index 6c7e21a09f78..6cc1b856871b 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -65,6 +65,7 @@ static u8 speed_template_32_64[] = {32, 64, 0};
/*
* AEAD speed tests
*/
+static u8 aead_speed_template_19[] = {19, 0};
static u8 aead_speed_template_20[] = {20, 0};
/*
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index f9bce3d7ee7f..d0a42bd3aae9 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -20,14 +20,17 @@
*
*/
+#include <crypto/aead.h>
#include <crypto/hash.h>
#include <linux/err.h>
+#include <linux/fips.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <crypto/rng.h>
#include <crypto/drbg.h>
+#include <crypto/akcipher.h>
#include "internal.h"
@@ -114,6 +117,11 @@ struct drbg_test_suite {
unsigned int count;
};
+struct akcipher_test_suite {
+ struct akcipher_testvec *vecs;
+ unsigned int count;
+};
+
struct alg_test_desc {
const char *alg;
int (*test)(const struct alg_test_desc *desc, const char *driver,
@@ -128,6 +136,7 @@ struct alg_test_desc {
struct hash_test_suite hash;
struct cprng_test_suite cprng;
struct drbg_test_suite drbg;
+ struct akcipher_test_suite akcipher;
} suite;
};
@@ -425,7 +434,6 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
char *key;
struct aead_request *req;
struct scatterlist *sg;
- struct scatterlist *asg;
struct scatterlist *sgout;
const char *e, *d;
struct tcrypt_result result;
@@ -452,11 +460,10 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
goto out_nooutbuf;
/* avoid "the frame size is larger than 1024 bytes" compiler warning */
- sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 3 : 2), GFP_KERNEL);
+ sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 4 : 2), GFP_KERNEL);
if (!sg)
goto out_nosg;
- asg = &sg[8];
- sgout = &asg[8];
+ sgout = &sg[16];
if (diff_dst)
d = "-ddst";
@@ -535,23 +542,27 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
goto out;
}
+ k = !!template[i].alen;
+ sg_init_table(sg, k + 1);
+ sg_set_buf(&sg[0], assoc, template[i].alen);
+ sg_set_buf(&sg[k], input,
+ template[i].ilen + (enc ? authsize : 0));
+ output = input;
+
if (diff_dst) {
+ sg_init_table(sgout, k + 1);
+ sg_set_buf(&sgout[0], assoc, template[i].alen);
+
output = xoutbuf[0];
output += align_offset;
- sg_init_one(&sg[0], input, template[i].ilen);
- sg_init_one(&sgout[0], output, template[i].rlen);
- } else {
- sg_init_one(&sg[0], input,
- template[i].ilen + (enc ? authsize : 0));
- output = input;
+ sg_set_buf(&sgout[k], output,
+ template[i].rlen + (enc ? 0 : authsize));
}
- sg_init_one(&asg[0], assoc, template[i].alen);
-
aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg,
template[i].ilen, iv);
- aead_request_set_assoc(req, asg, template[i].alen);
+ aead_request_set_ad(req, template[i].alen);
ret = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
@@ -631,9 +642,29 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
authsize = abs(template[i].rlen - template[i].ilen);
ret = -EINVAL;
- sg_init_table(sg, template[i].np);
+ sg_init_table(sg, template[i].anp + template[i].np);
if (diff_dst)
- sg_init_table(sgout, template[i].np);
+ sg_init_table(sgout, template[i].anp + template[i].np);
+
+ ret = -EINVAL;
+ for (k = 0, temp = 0; k < template[i].anp; k++) {
+ if (WARN_ON(offset_in_page(IDX[k]) +
+ template[i].atap[k] > PAGE_SIZE))
+ goto out;
+ sg_set_buf(&sg[k],
+ memcpy(axbuf[IDX[k] >> PAGE_SHIFT] +
+ offset_in_page(IDX[k]),
+ template[i].assoc + temp,
+ template[i].atap[k]),
+ template[i].atap[k]);
+ if (diff_dst)
+ sg_set_buf(&sgout[k],
+ axbuf[IDX[k] >> PAGE_SHIFT] +
+ offset_in_page(IDX[k]),
+ template[i].atap[k]);
+ temp += template[i].atap[k];
+ }
+
for (k = 0, temp = 0; k < template[i].np; k++) {
if (WARN_ON(offset_in_page(IDX[k]) +
template[i].tap[k] > PAGE_SIZE))
@@ -641,7 +672,8 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
q = xbuf[IDX[k] >> PAGE_SHIFT] + offset_in_page(IDX[k]);
memcpy(q, template[i].input + temp, template[i].tap[k]);
- sg_set_buf(&sg[k], q, template[i].tap[k]);
+ sg_set_buf(&sg[template[i].anp + k],
+ q, template[i].tap[k]);
if (diff_dst) {
q = xoutbuf[IDX[k] >> PAGE_SHIFT] +
@@ -649,7 +681,8 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
memset(q, 0, template[i].tap[k]);
- sg_set_buf(&sgout[k], q, template[i].tap[k]);
+ sg_set_buf(&sgout[template[i].anp + k],
+ q, template[i].tap[k]);
}
n = template[i].tap[k];
@@ -669,39 +702,24 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
}
if (enc) {
- if (WARN_ON(sg[k - 1].offset +
- sg[k - 1].length + authsize >
- PAGE_SIZE)) {
+ if (WARN_ON(sg[template[i].anp + k - 1].offset +
+ sg[template[i].anp + k - 1].length +
+ authsize > PAGE_SIZE)) {
ret = -EINVAL;
goto out;
}
if (diff_dst)
- sgout[k - 1].length += authsize;
- else
- sg[k - 1].length += authsize;
- }
-
- sg_init_table(asg, template[i].anp);
- ret = -EINVAL;
- for (k = 0, temp = 0; k < template[i].anp; k++) {
- if (WARN_ON(offset_in_page(IDX[k]) +
- template[i].atap[k] > PAGE_SIZE))
- goto out;
- sg_set_buf(&asg[k],
- memcpy(axbuf[IDX[k] >> PAGE_SHIFT] +
- offset_in_page(IDX[k]),
- template[i].assoc + temp,
- template[i].atap[k]),
- template[i].atap[k]);
- temp += template[i].atap[k];
+ sgout[template[i].anp + k - 1].length +=
+ authsize;
+ sg[template[i].anp + k - 1].length += authsize;
}
aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg,
template[i].ilen,
iv);
- aead_request_set_assoc(req, asg, template[i].alen);
+ aead_request_set_ad(req, template[i].alen);
ret = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
@@ -1814,6 +1832,147 @@ static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver,
}
+static int do_test_rsa(struct crypto_akcipher *tfm,
+ struct akcipher_testvec *vecs)
+{
+ struct akcipher_request *req;
+ void *outbuf_enc = NULL;
+ void *outbuf_dec = NULL;
+ struct tcrypt_result result;
+ unsigned int out_len_max, out_len = 0;
+ int err = -ENOMEM;
+
+ req = akcipher_request_alloc(tfm, GFP_KERNEL);
+ if (!req)
+ return err;
+
+ init_completion(&result.completion);
+ err = crypto_akcipher_setkey(tfm, vecs->key, vecs->key_len);
+ if (err)
+ goto free_req;
+
+ akcipher_request_set_crypt(req, vecs->m, outbuf_enc, vecs->m_size,
+ out_len);
+ /* expect this to fail, and update the required buf len */
+ crypto_akcipher_encrypt(req);
+ out_len = req->dst_len;
+ if (!out_len) {
+ err = -EINVAL;
+ goto free_req;
+ }
+
+ out_len_max = out_len;
+ err = -ENOMEM;
+ outbuf_enc = kzalloc(out_len_max, GFP_KERNEL);
+ if (!outbuf_enc)
+ goto free_req;
+
+ akcipher_request_set_crypt(req, vecs->m, outbuf_enc, vecs->m_size,
+ out_len);
+ akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ tcrypt_complete, &result);
+
+ /* Run RSA encrypt - c = m^e mod n;*/
+ err = wait_async_op(&result, crypto_akcipher_encrypt(req));
+ if (err) {
+ pr_err("alg: rsa: encrypt test failed. err %d\n", err);
+ goto free_all;
+ }
+ if (out_len != vecs->c_size) {
+ pr_err("alg: rsa: encrypt test failed. Invalid output len\n");
+ err = -EINVAL;
+ goto free_all;
+ }
+ /* verify that encrypted message is equal to expected */
+ if (memcmp(vecs->c, outbuf_enc, vecs->c_size)) {
+ pr_err("alg: rsa: encrypt test failed. Invalid output\n");
+ err = -EINVAL;
+ goto free_all;
+ }
+ /* Don't invoke decrypt for vectors with public key */
+ if (vecs->public_key_vec) {
+ err = 0;
+ goto free_all;
+ }
+ outbuf_dec = kzalloc(out_len_max, GFP_KERNEL);
+ if (!outbuf_dec) {
+ err = -ENOMEM;
+ goto free_all;
+ }
+ init_completion(&result.completion);
+ akcipher_request_set_crypt(req, outbuf_enc, outbuf_dec, vecs->c_size,
+ out_len);
+
+ /* Run RSA decrypt - m = c^d mod n;*/
+ err = wait_async_op(&result, crypto_akcipher_decrypt(req));
+ if (err) {
+ pr_err("alg: rsa: decrypt test failed. err %d\n", err);
+ goto free_all;
+ }
+ out_len = req->dst_len;
+ if (out_len != vecs->m_size) {
+ pr_err("alg: rsa: decrypt test failed. Invalid output len\n");
+ err = -EINVAL;
+ goto free_all;
+ }
+ /* verify that decrypted message is equal to the original msg */
+ if (memcmp(vecs->m, outbuf_dec, vecs->m_size)) {
+ pr_err("alg: rsa: decrypt test failed. Invalid output\n");
+ err = -EINVAL;
+ }
+free_all:
+ kfree(outbuf_dec);
+ kfree(outbuf_enc);
+free_req:
+ akcipher_request_free(req);
+ return err;
+}
+
+static int test_rsa(struct crypto_akcipher *tfm, struct akcipher_testvec *vecs,
+ unsigned int tcount)
+{
+ int ret, i;
+
+ for (i = 0; i < tcount; i++) {
+ ret = do_test_rsa(tfm, vecs++);
+ if (ret) {
+ pr_err("alg: rsa: test failed on vector %d, err=%d\n",
+ i + 1, ret);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int test_akcipher(struct crypto_akcipher *tfm, const char *alg,
+ struct akcipher_testvec *vecs, unsigned int tcount)
+{
+ if (strncmp(alg, "rsa", 3) == 0)
+ return test_rsa(tfm, vecs, tcount);
+
+ return 0;
+}
+
+static int alg_test_akcipher(const struct alg_test_desc *desc,
+ const char *driver, u32 type, u32 mask)
+{
+ struct crypto_akcipher *tfm;
+ int err = 0;
+
+ tfm = crypto_alloc_akcipher(driver, type | CRYPTO_ALG_INTERNAL, mask);
+ if (IS_ERR(tfm)) {
+ pr_err("alg: akcipher: Failed to load tfm for %s: %ld\n",
+ driver, PTR_ERR(tfm));
+ return PTR_ERR(tfm);
+ }
+ if (desc->suite.akcipher.vecs)
+ err = test_akcipher(tfm, desc->alg, desc->suite.akcipher.vecs,
+ desc->suite.akcipher.count);
+
+ crypto_free_akcipher(tfm);
+ return err;
+}
+
static int alg_test_null(const struct alg_test_desc *desc,
const char *driver, u32 type, u32 mask)
{
@@ -1897,6 +2056,10 @@ static const struct alg_test_desc alg_test_descs[] = {
.alg = "__driver-ecb-twofish-avx",
.test = alg_test_null,
}, {
+ .alg = "__driver-gcm-aes-aesni",
+ .test = alg_test_null,
+ .fips_allowed = 1,
+ }, {
.alg = "__ghash-pclmulqdqni",
.test = alg_test_null,
.fips_allowed = 1,
@@ -2297,6 +2460,21 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "chacha20",
+ .test = alg_test_skcipher,
+ .suite = {
+ .cipher = {
+ .enc = {
+ .vecs = chacha20_enc_tv_template,
+ .count = CHACHA20_ENC_TEST_VECTORS
+ },
+ .dec = {
+ .vecs = chacha20_enc_tv_template,
+ .count = CHACHA20_ENC_TEST_VECTORS
+ },
+ }
+ }
+ }, {
.alg = "cmac(aes)",
.test = alg_test_hash,
.suite = {
@@ -2318,6 +2496,15 @@ static const struct alg_test_desc alg_test_descs[] = {
.alg = "compress_null",
.test = alg_test_null,
}, {
+ .alg = "crc32",
+ .test = alg_test_hash,
+ .suite = {
+ .hash = {
+ .vecs = crc32_tv_template,
+ .count = CRC32_TEST_VECTORS
+ }
+ }
+ }, {
.alg = "crc32c",
.test = alg_test_crc32c,
.fips_allowed = 1,
@@ -3095,6 +3282,10 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "jitterentropy_rng",
+ .fips_allowed = 1,
+ .test = alg_test_null,
+ }, {
.alg = "lrw(aes)",
.test = alg_test_skcipher,
.suite = {
@@ -3276,6 +3467,15 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "poly1305",
+ .test = alg_test_hash,
+ .suite = {
+ .hash = {
+ .vecs = poly1305_tv_template,
+ .count = POLY1305_TEST_VECTORS
+ }
+ }
+ }, {
.alg = "rfc3686(ctr(aes))",
.test = alg_test_skcipher,
.fips_allowed = 1,
@@ -3339,6 +3539,36 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "rfc7539(chacha20,poly1305)",
+ .test = alg_test_aead,
+ .suite = {
+ .aead = {
+ .enc = {
+ .vecs = rfc7539_enc_tv_template,
+ .count = RFC7539_ENC_TEST_VECTORS
+ },
+ .dec = {
+ .vecs = rfc7539_dec_tv_template,
+ .count = RFC7539_DEC_TEST_VECTORS
+ },
+ }
+ }
+ }, {
+ .alg = "rfc7539esp(chacha20,poly1305)",
+ .test = alg_test_aead,
+ .suite = {
+ .aead = {
+ .enc = {
+ .vecs = rfc7539esp_enc_tv_template,
+ .count = RFC7539ESP_ENC_TEST_VECTORS
+ },
+ .dec = {
+ .vecs = rfc7539esp_dec_tv_template,
+ .count = RFC7539ESP_DEC_TEST_VECTORS
+ },
+ }
+ }
+ }, {
.alg = "rmd128",
.test = alg_test_hash,
.suite = {
@@ -3375,6 +3605,16 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "rsa",
+ .test = alg_test_akcipher,
+ .fips_allowed = 1,
+ .suite = {
+ .akcipher = {
+ .vecs = rsa_tv_template,
+ .count = RSA_TEST_VECTORS
+ }
+ }
+ }, {
.alg = "salsa20",
.test = alg_test_skcipher,
.suite = {
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 62e2485bb428..868edf117041 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -46,6 +46,24 @@ struct hash_testvec {
unsigned char ksize;
};
+/*
+ * cipher_testvec: structure to describe a cipher test
+ * @key: A pointer to a key used by the test
+ * @klen: The length of @key
+ * @iv: A pointer to the IV used by the test
+ * @input: A pointer to data used as input
+ * @ilen The length of data in @input
+ * @result: A pointer to what the test need to produce
+ * @rlen: The length of data in @result
+ * @fail: If set to one, the test need to fail
+ * @wk: Does the test need CRYPTO_TFM_REQ_WEAK_KEY
+ * ( e.g. test needs to fail due to a weak key )
+ * @np: numbers of SG to distribute data in (from 1 to MAX_TAP)
+ * @tap: How to distribute data in @np SGs
+ * @also_non_np: if set to 1, the test will be also done without
+ * splitting data in @np SGs
+ */
+
struct cipher_testvec {
char *key;
char *iv;
@@ -54,7 +72,7 @@ struct cipher_testvec {
unsigned short tap[MAX_TAP];
int np;
unsigned char also_non_np;
- unsigned char fail;
+ bool fail;
unsigned char wk; /* weak key flag */
unsigned char klen;
unsigned short ilen;
@@ -71,7 +89,7 @@ struct aead_testvec {
unsigned char atap[MAX_TAP];
int np;
int anp;
- unsigned char fail;
+ bool fail;
unsigned char novrfy; /* ccm dec verification failure expected */
unsigned char wk; /* weak key flag */
unsigned char klen;
@@ -107,9 +125,196 @@ struct drbg_testvec {
size_t expectedlen;
};
+struct akcipher_testvec {
+ unsigned char *key;
+ unsigned char *m;
+ unsigned char *c;
+ unsigned int key_len;
+ unsigned int m_size;
+ unsigned int c_size;
+ bool public_key_vec;
+};
+
static char zeroed_string[48];
/*
+ * RSA test vectors. Borrowed from openSSL.
+ */
+#ifdef CONFIG_CRYPTO_FIPS
+#define RSA_TEST_VECTORS 2
+#else
+#define RSA_TEST_VECTORS 4
+#endif
+static struct akcipher_testvec rsa_tv_template[] = {
+ {
+#ifndef CONFIG_CRYPTO_FIPS
+ .key =
+ "\x30\x81\x88" /* sequence of 136 bytes */
+ "\x02\x41" /* modulus - integer of 65 bytes */
+ "\x00\xAA\x36\xAB\xCE\x88\xAC\xFD\xFF\x55\x52\x3C\x7F\xC4\x52\x3F"
+ "\x90\xEF\xA0\x0D\xF3\x77\x4A\x25\x9F\x2E\x62\xB4\xC5\xD9\x9C\xB5"
+ "\xAD\xB3\x00\xA0\x28\x5E\x53\x01\x93\x0E\x0C\x70\xFB\x68\x76\x93"
+ "\x9C\xE6\x16\xCE\x62\x4A\x11\xE0\x08\x6D\x34\x1E\xBC\xAC\xA0\xA1"
+ "\xF5"
+ "\x02\x01\x11" /* public key - integer of 1 byte */
+ "\x02\x40" /* private key - integer of 64 bytes */
+ "\x0A\x03\x37\x48\x62\x64\x87\x69\x5F\x5F\x30\xBC\x38\xB9\x8B\x44"
+ "\xC2\xCD\x2D\xFF\x43\x40\x98\xCD\x20\xD8\xA1\x38\xD0\x90\xBF\x64"
+ "\x79\x7C\x3F\xA7\xA2\xCD\xCB\x3C\xD1\xE0\xBD\xBA\x26\x54\xB4\xF9"
+ "\xDF\x8E\x8A\xE5\x9D\x73\x3D\x9F\x33\xB3\x01\x62\x4A\xFD\x1D\x51",
+ .m = "\x54\x85\x9b\x34\x2c\x49\xea\x2a",
+ .c =
+ "\x63\x1c\xcd\x7b\xe1\x7e\xe4\xde\xc9\xa8\x89\xa1\x74\xcb\x3c\x63"
+ "\x7d\x24\xec\x83\xc3\x15\xe4\x7f\x73\x05\x34\xd1\xec\x22\xbb\x8a"
+ "\x5e\x32\x39\x6d\xc1\x1d\x7d\x50\x3b\x9f\x7a\xad\xf0\x2e\x25\x53"
+ "\x9f\x6e\xbd\x4c\x55\x84\x0c\x9b\xcf\x1a\x4b\x51\x1e\x9e\x0c\x06",
+ .key_len = 139,
+ .m_size = 8,
+ .c_size = 64,
+ }, {
+ .key =
+ "\x30\x82\x01\x0B" /* sequence of 267 bytes */
+ "\x02\x81\x81" /* modulus - integer of 129 bytes */
+ "\x00\xBB\xF8\x2F\x09\x06\x82\xCE\x9C\x23\x38\xAC\x2B\x9D\xA8\x71"
+ "\xF7\x36\x8D\x07\xEE\xD4\x10\x43\xA4\x40\xD6\xB6\xF0\x74\x54\xF5"
+ "\x1F\xB8\xDF\xBA\xAF\x03\x5C\x02\xAB\x61\xEA\x48\xCE\xEB\x6F\xCD"
+ "\x48\x76\xED\x52\x0D\x60\xE1\xEC\x46\x19\x71\x9D\x8A\x5B\x8B\x80"
+ "\x7F\xAF\xB8\xE0\xA3\xDF\xC7\x37\x72\x3E\xE6\xB4\xB7\xD9\x3A\x25"
+ "\x84\xEE\x6A\x64\x9D\x06\x09\x53\x74\x88\x34\xB2\x45\x45\x98\x39"
+ "\x4E\xE0\xAA\xB1\x2D\x7B\x61\xA5\x1F\x52\x7A\x9A\x41\xF6\xC1\x68"
+ "\x7F\xE2\x53\x72\x98\xCA\x2A\x8F\x59\x46\xF8\xE5\xFD\x09\x1D\xBD"
+ "\xCB"
+ "\x02\x01\x11" /* public key - integer of 1 byte */
+ "\x02\x81\x81" /* private key - integer of 129 bytes */
+ "\x00\xA5\xDA\xFC\x53\x41\xFA\xF2\x89\xC4\xB9\x88\xDB\x30\xC1\xCD"
+ "\xF8\x3F\x31\x25\x1E\x06\x68\xB4\x27\x84\x81\x38\x01\x57\x96\x41"
+ "\xB2\x94\x10\xB3\xC7\x99\x8D\x6B\xC4\x65\x74\x5E\x5C\x39\x26\x69"
+ "\xD6\x87\x0D\xA2\xC0\x82\xA9\x39\xE3\x7F\xDC\xB8\x2E\xC9\x3E\xDA"
+ "\xC9\x7F\xF3\xAD\x59\x50\xAC\xCF\xBC\x11\x1C\x76\xF1\xA9\x52\x94"
+ "\x44\xE5\x6A\xAF\x68\xC5\x6C\x09\x2C\xD3\x8D\xC3\xBE\xF5\xD2\x0A"
+ "\x93\x99\x26\xED\x4F\x74\xA1\x3E\xDD\xFB\xE1\xA1\xCE\xCC\x48\x94"
+ "\xAF\x94\x28\xC2\xB7\xB8\x88\x3F\xE4\x46\x3A\x4B\xC8\x5B\x1C\xB3"
+ "\xC1",
+ .key_len = 271,
+ .m = "\x54\x85\x9b\x34\x2c\x49\xea\x2a",
+ .c =
+ "\x74\x1b\x55\xac\x47\xb5\x08\x0a\x6e\x2b\x2d\xf7\x94\xb8\x8a\x95"
+ "\xed\xa3\x6b\xc9\x29\xee\xb2\x2c\x80\xc3\x39\x3b\x8c\x62\x45\x72"
+ "\xc2\x7f\x74\x81\x91\x68\x44\x48\x5a\xdc\xa0\x7e\xa7\x0b\x05\x7f"
+ "\x0e\xa0\x6c\xe5\x8f\x19\x4d\xce\x98\x47\x5f\xbd\x5f\xfe\xe5\x34"
+ "\x59\x89\xaf\xf0\xba\x44\xd7\xf1\x1a\x50\x72\xef\x5e\x4a\xb6\xb7"
+ "\x54\x34\xd1\xc4\x83\x09\xdf\x0f\x91\x5f\x7d\x91\x70\x2f\xd4\x13"
+ "\xcc\x5e\xa4\x6c\xc3\x4d\x28\xef\xda\xaf\xec\x14\x92\xfc\xa3\x75"
+ "\x13\xb4\xc1\xa1\x11\xfc\x40\x2f\x4c\x9d\xdf\x16\x76\x11\x20\x6b",
+ .m_size = 8,
+ .c_size = 128,
+ }, {
+#endif
+ .key =
+ "\x30\x82\x02\x0D" /* sequence of 525 bytes */
+ "\x02\x82\x01\x00" /* modulus - integer of 256 bytes */
+ "\xDB\x10\x1A\xC2\xA3\xF1\xDC\xFF\x13\x6B\xED\x44\xDF\xF0\x02\x6D"
+ "\x13\xC7\x88\xDA\x70\x6B\x54\xF1\xE8\x27\xDC\xC3\x0F\x99\x6A\xFA"
+ "\xC6\x67\xFF\x1D\x1E\x3C\x1D\xC1\xB5\x5F\x6C\xC0\xB2\x07\x3A\x6D"
+ "\x41\xE4\x25\x99\xAC\xFC\xD2\x0F\x02\xD3\xD1\x54\x06\x1A\x51\x77"
+ "\xBD\xB6\xBF\xEA\xA7\x5C\x06\xA9\x5D\x69\x84\x45\xD7\xF5\x05\xBA"
+ "\x47\xF0\x1B\xD7\x2B\x24\xEC\xCB\x9B\x1B\x10\x8D\x81\xA0\xBE\xB1"
+ "\x8C\x33\xE4\x36\xB8\x43\xEB\x19\x2A\x81\x8D\xDE\x81\x0A\x99\x48"
+ "\xB6\xF6\xBC\xCD\x49\x34\x3A\x8F\x26\x94\xE3\x28\x82\x1A\x7C\x8F"
+ "\x59\x9F\x45\xE8\x5D\x1A\x45\x76\x04\x56\x05\xA1\xD0\x1B\x8C\x77"
+ "\x6D\xAF\x53\xFA\x71\xE2\x67\xE0\x9A\xFE\x03\xA9\x85\xD2\xC9\xAA"
+ "\xBA\x2A\xBC\xF4\xA0\x08\xF5\x13\x98\x13\x5D\xF0\xD9\x33\x34\x2A"
+ "\x61\xC3\x89\x55\xF0\xAE\x1A\x9C\x22\xEE\x19\x05\x8D\x32\xFE\xEC"
+ "\x9C\x84\xBA\xB7\xF9\x6C\x3A\x4F\x07\xFC\x45\xEB\x12\xE5\x7B\xFD"
+ "\x55\xE6\x29\x69\xD1\xC2\xE8\xB9\x78\x59\xF6\x79\x10\xC6\x4E\xEB"
+ "\x6A\x5E\xB9\x9A\xC7\xC4\x5B\x63\xDA\xA3\x3F\x5E\x92\x7A\x81\x5E"
+ "\xD6\xB0\xE2\x62\x8F\x74\x26\xC2\x0C\xD3\x9A\x17\x47\xE6\x8E\xAB"
+ "\x02\x03\x01\x00\x01" /* public key - integer of 3 bytes */
+ "\x02\x82\x01\x00" /* private key - integer of 256 bytes */
+ "\x52\x41\xF4\xDA\x7B\xB7\x59\x55\xCA\xD4\x2F\x0F\x3A\xCB\xA4\x0D"
+ "\x93\x6C\xCC\x9D\xC1\xB2\xFB\xFD\xAE\x40\x31\xAC\x69\x52\x21\x92"
+ "\xB3\x27\xDF\xEA\xEE\x2C\x82\xBB\xF7\x40\x32\xD5\x14\xC4\x94\x12"
+ "\xEC\xB8\x1F\xCA\x59\xE3\xC1\x78\xF3\x85\xD8\x47\xA5\xD7\x02\x1A"
+ "\x65\x79\x97\x0D\x24\xF4\xF0\x67\x6E\x75\x2D\xBF\x10\x3D\xA8\x7D"
+ "\xEF\x7F\x60\xE4\xE6\x05\x82\x89\x5D\xDF\xC6\xD2\x6C\x07\x91\x33"
+ "\x98\x42\xF0\x02\x00\x25\x38\xC5\x85\x69\x8A\x7D\x2F\x95\x6C\x43"
+ "\x9A\xB8\x81\xE2\xD0\x07\x35\xAA\x05\x41\xC9\x1E\xAF\xE4\x04\x3B"
+ "\x19\xB8\x73\xA2\xAC\x4B\x1E\x66\x48\xD8\x72\x1F\xAC\xF6\xCB\xBC"
+ "\x90\x09\xCA\xEC\x0C\xDC\xF9\x2C\xD7\xEB\xAE\xA3\xA4\x47\xD7\x33"
+ "\x2F\x8A\xCA\xBC\x5E\xF0\x77\xE4\x97\x98\x97\xC7\x10\x91\x7D\x2A"
+ "\xA6\xFF\x46\x83\x97\xDE\xE9\xE2\x17\x03\x06\x14\xE2\xD7\xB1\x1D"
+ "\x77\xAF\x51\x27\x5B\x5E\x69\xB8\x81\xE6\x11\xC5\x43\x23\x81\x04"
+ "\x62\xFF\xE9\x46\xB8\xD8\x44\xDB\xA5\xCC\x31\x54\x34\xCE\x3E\x82"
+ "\xD6\xBF\x7A\x0B\x64\x21\x6D\x88\x7E\x5B\x45\x12\x1E\x63\x8D\x49"
+ "\xA7\x1D\xD9\x1E\x06\xCD\xE8\xBA\x2C\x8C\x69\x32\xEA\xBE\x60\x71",
+ .key_len = 529,
+ .m = "\x54\x85\x9b\x34\x2c\x49\xea\x2a",
+ .c =
+ "\xb2\x97\x76\xb4\xae\x3e\x38\x3c\x7e\x64\x1f\xcc\xa2\x7f\xf6\xbe"
+ "\xcf\x49\xbc\x48\xd3\x6c\x8f\x0a\x0e\xc1\x73\xbd\x7b\x55\x79\x36"
+ "\x0e\xa1\x87\x88\xb9\x2c\x90\xa6\x53\x5e\xe9\xef\xc4\xe2\x4d\xdd"
+ "\xf7\xa6\x69\x82\x3f\x56\xa4\x7b\xfb\x62\xe0\xae\xb8\xd3\x04\xb3"
+ "\xac\x5a\x15\x2a\xe3\x19\x9b\x03\x9a\x0b\x41\xda\x64\xec\x0a\x69"
+ "\xfc\xf2\x10\x92\xf3\xc1\xbf\x84\x7f\xfd\x2c\xae\xc8\xb5\xf6\x41"
+ "\x70\xc5\x47\x03\x8a\xf8\xff\x6f\x3f\xd2\x6f\x09\xb4\x22\xf3\x30"
+ "\xbe\xa9\x85\xcb\x9c\x8d\xf9\x8f\xeb\x32\x91\xa2\x25\x84\x8f\xf5"
+ "\xdc\xc7\x06\x9c\x2d\xe5\x11\x2c\x09\x09\x87\x09\xa9\xf6\x33\x73"
+ "\x90\xf1\x60\xf2\x65\xdd\x30\xa5\x66\xce\x62\x7b\xd0\xf8\x2d\x3d"
+ "\x19\x82\x77\xe3\x0a\x5f\x75\x2f\x8e\xb1\xe5\xe8\x91\x35\x1b\x3b"
+ "\x33\xb7\x66\x92\xd1\xf2\x8e\x6f\xe5\x75\x0c\xad\x36\xfb\x4e\xd0"
+ "\x66\x61\xbd\x49\xfe\xf4\x1a\xa2\x2b\x49\xfe\x03\x4c\x74\x47\x8d"
+ "\x9a\x66\xb2\x49\x46\x4d\x77\xea\x33\x4d\x6b\x3c\xb4\x49\x4a\xc6"
+ "\x7d\x3d\xb5\xb9\x56\x41\x15\x67\x0f\x94\x3c\x93\x65\x27\xe0\x21"
+ "\x5d\x59\xc3\x62\xd5\xa6\xda\x38\x26\x22\x5e\x34\x1c\x94\xaf\x98",
+ .m_size = 8,
+ .c_size = 256,
+ }, {
+ .key =
+ "\x30\x82\x01\x09" /* sequence of 265 bytes */
+ "\x02\x82\x01\x00" /* modulus - integer of 256 bytes */
+ "\xDB\x10\x1A\xC2\xA3\xF1\xDC\xFF\x13\x6B\xED\x44\xDF\xF0\x02\x6D"
+ "\x13\xC7\x88\xDA\x70\x6B\x54\xF1\xE8\x27\xDC\xC3\x0F\x99\x6A\xFA"
+ "\xC6\x67\xFF\x1D\x1E\x3C\x1D\xC1\xB5\x5F\x6C\xC0\xB2\x07\x3A\x6D"
+ "\x41\xE4\x25\x99\xAC\xFC\xD2\x0F\x02\xD3\xD1\x54\x06\x1A\x51\x77"
+ "\xBD\xB6\xBF\xEA\xA7\x5C\x06\xA9\x5D\x69\x84\x45\xD7\xF5\x05\xBA"
+ "\x47\xF0\x1B\xD7\x2B\x24\xEC\xCB\x9B\x1B\x10\x8D\x81\xA0\xBE\xB1"
+ "\x8C\x33\xE4\x36\xB8\x43\xEB\x19\x2A\x81\x8D\xDE\x81\x0A\x99\x48"
+ "\xB6\xF6\xBC\xCD\x49\x34\x3A\x8F\x26\x94\xE3\x28\x82\x1A\x7C\x8F"
+ "\x59\x9F\x45\xE8\x5D\x1A\x45\x76\x04\x56\x05\xA1\xD0\x1B\x8C\x77"
+ "\x6D\xAF\x53\xFA\x71\xE2\x67\xE0\x9A\xFE\x03\xA9\x85\xD2\xC9\xAA"
+ "\xBA\x2A\xBC\xF4\xA0\x08\xF5\x13\x98\x13\x5D\xF0\xD9\x33\x34\x2A"
+ "\x61\xC3\x89\x55\xF0\xAE\x1A\x9C\x22\xEE\x19\x05\x8D\x32\xFE\xEC"
+ "\x9C\x84\xBA\xB7\xF9\x6C\x3A\x4F\x07\xFC\x45\xEB\x12\xE5\x7B\xFD"
+ "\x55\xE6\x29\x69\xD1\xC2\xE8\xB9\x78\x59\xF6\x79\x10\xC6\x4E\xEB"
+ "\x6A\x5E\xB9\x9A\xC7\xC4\x5B\x63\xDA\xA3\x3F\x5E\x92\x7A\x81\x5E"
+ "\xD6\xB0\xE2\x62\x8F\x74\x26\xC2\x0C\xD3\x9A\x17\x47\xE6\x8E\xAB"
+ "\x02\x03\x01\x00\x01", /* public key - integer of 3 bytes */
+ .key_len = 269,
+ .m = "\x54\x85\x9b\x34\x2c\x49\xea\x2a",
+ .c =
+ "\xb2\x97\x76\xb4\xae\x3e\x38\x3c\x7e\x64\x1f\xcc\xa2\x7f\xf6\xbe"
+ "\xcf\x49\xbc\x48\xd3\x6c\x8f\x0a\x0e\xc1\x73\xbd\x7b\x55\x79\x36"
+ "\x0e\xa1\x87\x88\xb9\x2c\x90\xa6\x53\x5e\xe9\xef\xc4\xe2\x4d\xdd"
+ "\xf7\xa6\x69\x82\x3f\x56\xa4\x7b\xfb\x62\xe0\xae\xb8\xd3\x04\xb3"
+ "\xac\x5a\x15\x2a\xe3\x19\x9b\x03\x9a\x0b\x41\xda\x64\xec\x0a\x69"
+ "\xfc\xf2\x10\x92\xf3\xc1\xbf\x84\x7f\xfd\x2c\xae\xc8\xb5\xf6\x41"
+ "\x70\xc5\x47\x03\x8a\xf8\xff\x6f\x3f\xd2\x6f\x09\xb4\x22\xf3\x30"
+ "\xbe\xa9\x85\xcb\x9c\x8d\xf9\x8f\xeb\x32\x91\xa2\x25\x84\x8f\xf5"
+ "\xdc\xc7\x06\x9c\x2d\xe5\x11\x2c\x09\x09\x87\x09\xa9\xf6\x33\x73"
+ "\x90\xf1\x60\xf2\x65\xdd\x30\xa5\x66\xce\x62\x7b\xd0\xf8\x2d\x3d"
+ "\x19\x82\x77\xe3\x0a\x5f\x75\x2f\x8e\xb1\xe5\xe8\x91\x35\x1b\x3b"
+ "\x33\xb7\x66\x92\xd1\xf2\x8e\x6f\xe5\x75\x0c\xad\x36\xfb\x4e\xd0"
+ "\x66\x61\xbd\x49\xfe\xf4\x1a\xa2\x2b\x49\xfe\x03\x4c\x74\x47\x8d"
+ "\x9a\x66\xb2\x49\x46\x4d\x77\xea\x33\x4d\x6b\x3c\xb4\x49\x4a\xc6"
+ "\x7d\x3d\xb5\xb9\x56\x41\x15\x67\x0f\x94\x3c\x93\x65\x27\xe0\x21"
+ "\x5d\x59\xc3\x62\xd5\xa6\xda\x38\x26\x22\x5e\x34\x1c\x94\xaf\x98",
+ .m_size = 8,
+ .c_size = 256,
+ .public_key_vec = true,
+ }
+};
+
+/*
* MD4 test vectors from RFC1320
*/
#define MD4_TEST_VECTORS 7
@@ -1822,7 +2027,7 @@ static struct hash_testvec tgr128_tv_template[] = {
},
};
-#define GHASH_TEST_VECTORS 5
+#define GHASH_TEST_VECTORS 6
static struct hash_testvec ghash_tv_template[] =
{
@@ -1875,6 +2080,63 @@ static struct hash_testvec ghash_tv_template[] =
.psize = 20,
.digest = "\xf8\x94\x87\x2a\x4b\x63\x99\x28"
"\x23\xf7\x93\xf7\x19\xf5\x96\xd9",
+ }, {
+ .key = "\x0a\x1b\x2c\x3d\x4e\x5f\x64\x71"
+ "\x82\x93\xa4\xb5\xc6\xd7\xe8\xf9",
+ .ksize = 16,
+ .plaintext = "\x56\x6f\x72\x20\x6c\x61\x75\x74"
+ "\x65\x72\x20\x4c\x61\x75\x73\x63"
+ "\x68\x65\x6e\x20\x75\x6e\x64\x20"
+ "\x53\x74\x61\x75\x6e\x65\x6e\x20"
+ "\x73\x65\x69\x20\x73\x74\x69\x6c"
+ "\x6c\x2c\x0a\x64\x75\x20\x6d\x65"
+ "\x69\x6e\x20\x74\x69\x65\x66\x74"
+ "\x69\x65\x66\x65\x73\x20\x4c\x65"
+ "\x62\x65\x6e\x3b\x0a\x64\x61\x73"
+ "\x73\x20\x64\x75\x20\x77\x65\x69"
+ "\xc3\x9f\x74\x20\x77\x61\x73\x20"
+ "\x64\x65\x72\x20\x57\x69\x6e\x64"
+ "\x20\x64\x69\x72\x20\x77\x69\x6c"
+ "\x6c\x2c\x0a\x65\x68\x20\x6e\x6f"
+ "\x63\x68\x20\x64\x69\x65\x20\x42"
+ "\x69\x72\x6b\x65\x6e\x20\x62\x65"
+ "\x62\x65\x6e\x2e\x0a\x0a\x55\x6e"
+ "\x64\x20\x77\x65\x6e\x6e\x20\x64"
+ "\x69\x72\x20\x65\x69\x6e\x6d\x61"
+ "\x6c\x20\x64\x61\x73\x20\x53\x63"
+ "\x68\x77\x65\x69\x67\x65\x6e\x20"
+ "\x73\x70\x72\x61\x63\x68\x2c\x0a"
+ "\x6c\x61\x73\x73\x20\x64\x65\x69"
+ "\x6e\x65\x20\x53\x69\x6e\x6e\x65"
+ "\x20\x62\x65\x73\x69\x65\x67\x65"
+ "\x6e\x2e\x0a\x4a\x65\x64\x65\x6d"
+ "\x20\x48\x61\x75\x63\x68\x65\x20"
+ "\x67\x69\x62\x74\x20\x64\x69\x63"
+ "\x68\x2c\x20\x67\x69\x62\x20\x6e"
+ "\x61\x63\x68\x2c\x0a\x65\x72\x20"
+ "\x77\x69\x72\x64\x20\x64\x69\x63"
+ "\x68\x20\x6c\x69\x65\x62\x65\x6e"
+ "\x20\x75\x6e\x64\x20\x77\x69\x65"
+ "\x67\x65\x6e\x2e\x0a\x0a\x55\x6e"
+ "\x64\x20\x64\x61\x6e\x6e\x20\x6d"
+ "\x65\x69\x6e\x65\x20\x53\x65\x65"
+ "\x6c\x65\x20\x73\x65\x69\x74\x20"
+ "\x77\x65\x69\x74\x2c\x20\x73\x65"
+ "\x69\x20\x77\x65\x69\x74\x2c\x0a"
+ "\x64\x61\x73\x73\x20\x64\x69\x72"
+ "\x20\x64\x61\x73\x20\x4c\x65\x62"
+ "\x65\x6e\x20\x67\x65\x6c\x69\x6e"
+ "\x67\x65\x2c\x0a\x62\x72\x65\x69"
+ "\x74\x65\x20\x64\x69\x63\x68\x20"
+ "\x77\x69\x65\x20\x65\x69\x6e\x20"
+ "\x46\x65\x69\x65\x72\x6b\x6c\x65"
+ "\x69\x64\x0a\xc3\xbc\x62\x65\x72"
+ "\x20\x64\x69\x65\x20\x73\x69\x6e"
+ "\x6e\x65\x6e\x64\x65\x6e\x20\x44"
+ "\x69\x6e\x67\x65\x2e\x2e\x2e\x0a",
+ .psize = 400,
+ .digest = "\xad\xb1\xc1\xe9\x56\x70\x31\x1d"
+ "\xbb\x5b\xdf\x5e\x70\x72\x1a\x57",
},
};
@@ -2969,6 +3231,254 @@ static struct hash_testvec hmac_sha512_tv_template[] = {
};
/*
+ * Poly1305 test vectors from RFC7539 A.3.
+ */
+
+#define POLY1305_TEST_VECTORS 11
+
+static struct hash_testvec poly1305_tv_template[] = {
+ { /* Test Vector #1 */
+ .plaintext = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .psize = 96,
+ .digest = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ }, { /* Test Vector #2 */
+ .plaintext = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x36\xe5\xf6\xb5\xc5\xe0\x60\x70"
+ "\xf0\xef\xca\x96\x22\x7a\x86\x3e"
+ "\x41\x6e\x79\x20\x73\x75\x62\x6d"
+ "\x69\x73\x73\x69\x6f\x6e\x20\x74"
+ "\x6f\x20\x74\x68\x65\x20\x49\x45"
+ "\x54\x46\x20\x69\x6e\x74\x65\x6e"
+ "\x64\x65\x64\x20\x62\x79\x20\x74"
+ "\x68\x65\x20\x43\x6f\x6e\x74\x72"
+ "\x69\x62\x75\x74\x6f\x72\x20\x66"
+ "\x6f\x72\x20\x70\x75\x62\x6c\x69"
+ "\x63\x61\x74\x69\x6f\x6e\x20\x61"
+ "\x73\x20\x61\x6c\x6c\x20\x6f\x72"
+ "\x20\x70\x61\x72\x74\x20\x6f\x66"
+ "\x20\x61\x6e\x20\x49\x45\x54\x46"
+ "\x20\x49\x6e\x74\x65\x72\x6e\x65"
+ "\x74\x2d\x44\x72\x61\x66\x74\x20"
+ "\x6f\x72\x20\x52\x46\x43\x20\x61"
+ "\x6e\x64\x20\x61\x6e\x79\x20\x73"
+ "\x74\x61\x74\x65\x6d\x65\x6e\x74"
+ "\x20\x6d\x61\x64\x65\x20\x77\x69"
+ "\x74\x68\x69\x6e\x20\x74\x68\x65"
+ "\x20\x63\x6f\x6e\x74\x65\x78\x74"
+ "\x20\x6f\x66\x20\x61\x6e\x20\x49"
+ "\x45\x54\x46\x20\x61\x63\x74\x69"
+ "\x76\x69\x74\x79\x20\x69\x73\x20"
+ "\x63\x6f\x6e\x73\x69\x64\x65\x72"
+ "\x65\x64\x20\x61\x6e\x20\x22\x49"
+ "\x45\x54\x46\x20\x43\x6f\x6e\x74"
+ "\x72\x69\x62\x75\x74\x69\x6f\x6e"
+ "\x22\x2e\x20\x53\x75\x63\x68\x20"
+ "\x73\x74\x61\x74\x65\x6d\x65\x6e"
+ "\x74\x73\x20\x69\x6e\x63\x6c\x75"
+ "\x64\x65\x20\x6f\x72\x61\x6c\x20"
+ "\x73\x74\x61\x74\x65\x6d\x65\x6e"
+ "\x74\x73\x20\x69\x6e\x20\x49\x45"
+ "\x54\x46\x20\x73\x65\x73\x73\x69"
+ "\x6f\x6e\x73\x2c\x20\x61\x73\x20"
+ "\x77\x65\x6c\x6c\x20\x61\x73\x20"
+ "\x77\x72\x69\x74\x74\x65\x6e\x20"
+ "\x61\x6e\x64\x20\x65\x6c\x65\x63"
+ "\x74\x72\x6f\x6e\x69\x63\x20\x63"
+ "\x6f\x6d\x6d\x75\x6e\x69\x63\x61"
+ "\x74\x69\x6f\x6e\x73\x20\x6d\x61"
+ "\x64\x65\x20\x61\x74\x20\x61\x6e"
+ "\x79\x20\x74\x69\x6d\x65\x20\x6f"
+ "\x72\x20\x70\x6c\x61\x63\x65\x2c"
+ "\x20\x77\x68\x69\x63\x68\x20\x61"
+ "\x72\x65\x20\x61\x64\x64\x72\x65"
+ "\x73\x73\x65\x64\x20\x74\x6f",
+ .psize = 407,
+ .digest = "\x36\xe5\xf6\xb5\xc5\xe0\x60\x70"
+ "\xf0\xef\xca\x96\x22\x7a\x86\x3e",
+ }, { /* Test Vector #3 */
+ .plaintext = "\x36\xe5\xf6\xb5\xc5\xe0\x60\x70"
+ "\xf0\xef\xca\x96\x22\x7a\x86\x3e"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x41\x6e\x79\x20\x73\x75\x62\x6d"
+ "\x69\x73\x73\x69\x6f\x6e\x20\x74"
+ "\x6f\x20\x74\x68\x65\x20\x49\x45"
+ "\x54\x46\x20\x69\x6e\x74\x65\x6e"
+ "\x64\x65\x64\x20\x62\x79\x20\x74"
+ "\x68\x65\x20\x43\x6f\x6e\x74\x72"
+ "\x69\x62\x75\x74\x6f\x72\x20\x66"
+ "\x6f\x72\x20\x70\x75\x62\x6c\x69"
+ "\x63\x61\x74\x69\x6f\x6e\x20\x61"
+ "\x73\x20\x61\x6c\x6c\x20\x6f\x72"
+ "\x20\x70\x61\x72\x74\x20\x6f\x66"
+ "\x20\x61\x6e\x20\x49\x45\x54\x46"
+ "\x20\x49\x6e\x74\x65\x72\x6e\x65"
+ "\x74\x2d\x44\x72\x61\x66\x74\x20"
+ "\x6f\x72\x20\x52\x46\x43\x20\x61"
+ "\x6e\x64\x20\x61\x6e\x79\x20\x73"
+ "\x74\x61\x74\x65\x6d\x65\x6e\x74"
+ "\x20\x6d\x61\x64\x65\x20\x77\x69"
+ "\x74\x68\x69\x6e\x20\x74\x68\x65"
+ "\x20\x63\x6f\x6e\x74\x65\x78\x74"
+ "\x20\x6f\x66\x20\x61\x6e\x20\x49"
+ "\x45\x54\x46\x20\x61\x63\x74\x69"
+ "\x76\x69\x74\x79\x20\x69\x73\x20"
+ "\x63\x6f\x6e\x73\x69\x64\x65\x72"
+ "\x65\x64\x20\x61\x6e\x20\x22\x49"
+ "\x45\x54\x46\x20\x43\x6f\x6e\x74"
+ "\x72\x69\x62\x75\x74\x69\x6f\x6e"
+ "\x22\x2e\x20\x53\x75\x63\x68\x20"
+ "\x73\x74\x61\x74\x65\x6d\x65\x6e"
+ "\x74\x73\x20\x69\x6e\x63\x6c\x75"
+ "\x64\x65\x20\x6f\x72\x61\x6c\x20"
+ "\x73\x74\x61\x74\x65\x6d\x65\x6e"
+ "\x74\x73\x20\x69\x6e\x20\x49\x45"
+ "\x54\x46\x20\x73\x65\x73\x73\x69"
+ "\x6f\x6e\x73\x2c\x20\x61\x73\x20"
+ "\x77\x65\x6c\x6c\x20\x61\x73\x20"
+ "\x77\x72\x69\x74\x74\x65\x6e\x20"
+ "\x61\x6e\x64\x20\x65\x6c\x65\x63"
+ "\x74\x72\x6f\x6e\x69\x63\x20\x63"
+ "\x6f\x6d\x6d\x75\x6e\x69\x63\x61"
+ "\x74\x69\x6f\x6e\x73\x20\x6d\x61"
+ "\x64\x65\x20\x61\x74\x20\x61\x6e"
+ "\x79\x20\x74\x69\x6d\x65\x20\x6f"
+ "\x72\x20\x70\x6c\x61\x63\x65\x2c"
+ "\x20\x77\x68\x69\x63\x68\x20\x61"
+ "\x72\x65\x20\x61\x64\x64\x72\x65"
+ "\x73\x73\x65\x64\x20\x74\x6f",
+ .psize = 407,
+ .digest = "\xf3\x47\x7e\x7c\xd9\x54\x17\xaf"
+ "\x89\xa6\xb8\x79\x4c\x31\x0c\xf0",
+ }, { /* Test Vector #4 */
+ .plaintext = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a"
+ "\xf3\x33\x88\x86\x04\xf6\xb5\xf0"
+ "\x47\x39\x17\xc1\x40\x2b\x80\x09"
+ "\x9d\xca\x5c\xbc\x20\x70\x75\xc0"
+ "\x27\x54\x77\x61\x73\x20\x62\x72"
+ "\x69\x6c\x6c\x69\x67\x2c\x20\x61"
+ "\x6e\x64\x20\x74\x68\x65\x20\x73"
+ "\x6c\x69\x74\x68\x79\x20\x74\x6f"
+ "\x76\x65\x73\x0a\x44\x69\x64\x20"
+ "\x67\x79\x72\x65\x20\x61\x6e\x64"
+ "\x20\x67\x69\x6d\x62\x6c\x65\x20"
+ "\x69\x6e\x20\x74\x68\x65\x20\x77"
+ "\x61\x62\x65\x3a\x0a\x41\x6c\x6c"
+ "\x20\x6d\x69\x6d\x73\x79\x20\x77"
+ "\x65\x72\x65\x20\x74\x68\x65\x20"
+ "\x62\x6f\x72\x6f\x67\x6f\x76\x65"
+ "\x73\x2c\x0a\x41\x6e\x64\x20\x74"
+ "\x68\x65\x20\x6d\x6f\x6d\x65\x20"
+ "\x72\x61\x74\x68\x73\x20\x6f\x75"
+ "\x74\x67\x72\x61\x62\x65\x2e",
+ .psize = 159,
+ .digest = "\x45\x41\x66\x9a\x7e\xaa\xee\x61"
+ "\xe7\x08\xdc\x7c\xbc\xc5\xeb\x62",
+ }, { /* Test Vector #5 */
+ .plaintext = "\x02\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff",
+ .psize = 48,
+ .digest = "\x03\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ }, { /* Test Vector #6 */
+ .plaintext = "\x02\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\x02\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .psize = 48,
+ .digest = "\x03\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ }, { /* Test Vector #7 */
+ .plaintext = "\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xf0\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\x11\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .psize = 80,
+ .digest = "\x05\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ }, { /* Test Vector #8 */
+ .plaintext = "\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xfb\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+ "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
+ "\x01\x01\x01\x01\x01\x01\x01\x01"
+ "\x01\x01\x01\x01\x01\x01\x01\x01",
+ .psize = 80,
+ .digest = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ }, { /* Test Vector #9 */
+ .plaintext = "\x02\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xfd\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff",
+ .psize = 48,
+ .digest = "\xfa\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff",
+ }, { /* Test Vector #10 */
+ .plaintext = "\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x04\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xe3\x35\x94\xd7\x50\x5e\x43\xb9"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x33\x94\xd7\x50\x5e\x43\x79\xcd"
+ "\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .psize = 96,
+ .digest = "\x14\x00\x00\x00\x00\x00\x00\x00"
+ "\x55\x00\x00\x00\x00\x00\x00\x00",
+ }, { /* Test Vector #11 */
+ .plaintext = "\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x04\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xe3\x35\x94\xd7\x50\x5e\x43\xb9"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x33\x94\xd7\x50\x5e\x43\x79\xcd"
+ "\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .psize = 80,
+ .digest = "\x13\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ },
+};
+
+/*
* DES test vectors.
*/
#define DES_ENC_TEST_VECTORS 11
@@ -3018,7 +3528,7 @@ static struct cipher_testvec des_enc_tv_template[] = {
"\xb4\x99\x26\xf7\x1f\xe1\xd4\x90",
.rlen = 24,
}, { /* Weak key */
- .fail = 1,
+ .fail = true,
.wk = 1,
.key = "\x01\x01\x01\x01\x01\x01\x01\x01",
.klen = 8,
@@ -13629,8 +14139,8 @@ static struct cipher_testvec cast6_xts_dec_tv_template[] = {
#define AES_CTR_3686_DEC_TEST_VECTORS 6
#define AES_GCM_ENC_TEST_VECTORS 9
#define AES_GCM_DEC_TEST_VECTORS 8
-#define AES_GCM_4106_ENC_TEST_VECTORS 7
-#define AES_GCM_4106_DEC_TEST_VECTORS 7
+#define AES_GCM_4106_ENC_TEST_VECTORS 23
+#define AES_GCM_4106_DEC_TEST_VECTORS 23
#define AES_GCM_4543_ENC_TEST_VECTORS 1
#define AES_GCM_4543_DEC_TEST_VECTORS 2
#define AES_CCM_ENC_TEST_VECTORS 8
@@ -19789,6 +20299,428 @@ static struct aead_testvec aes_gcm_rfc4106_enc_tv_template[] = {
"\x37\x08\x1C\xCF\xBA\x5D\x71\x46"
"\x80\x72\xB0\x4C\x82\x0D\x60\x3C",
.rlen = 208,
+ }, { /* From draft-mcgrew-gcm-test-01 */
+ .key = "\x4C\x80\xCD\xEF\xBB\x5D\x10\xDA"
+ "\x90\x6A\xC7\x3C\x36\x13\xA6\x34"
+ "\x2E\x44\x3B\x68",
+ .klen = 20,
+ .iv = "\x49\x56\xED\x7E\x3B\x24\x4C\xFE",
+ .input = "\x45\x00\x00\x48\x69\x9A\x00\x00"
+ "\x80\x11\x4D\xB7\xC0\xA8\x01\x02"
+ "\xC0\xA8\x01\x01\x0A\x9B\xF1\x56"
+ "\x38\xD3\x01\x00\x00\x01\x00\x00"
+ "\x00\x00\x00\x00\x04\x5F\x73\x69"
+ "\x70\x04\x5F\x75\x64\x70\x03\x73"
+ "\x69\x70\x09\x63\x79\x62\x65\x72"
+ "\x63\x69\x74\x79\x02\x64\x6B\x00"
+ "\x00\x21\x00\x01\x01\x02\x02\x01",
+ .ilen = 72,
+ .assoc = "\x00\x00\x43\x21\x87\x65\x43\x21"
+ "\x00\x00\x00\x00",
+ .alen = 12,
+ .result = "\xFE\xCF\x53\x7E\x72\x9D\x5B\x07"
+ "\xDC\x30\xDF\x52\x8D\xD2\x2B\x76"
+ "\x8D\x1B\x98\x73\x66\x96\xA6\xFD"
+ "\x34\x85\x09\xFA\x13\xCE\xAC\x34"
+ "\xCF\xA2\x43\x6F\x14\xA3\xF3\xCF"
+ "\x65\x92\x5B\xF1\xF4\xA1\x3C\x5D"
+ "\x15\xB2\x1E\x18\x84\xF5\xFF\x62"
+ "\x47\xAE\xAB\xB7\x86\xB9\x3B\xCE"
+ "\x61\xBC\x17\xD7\x68\xFD\x97\x32"
+ "\x45\x90\x18\x14\x8F\x6C\xBE\x72"
+ "\x2F\xD0\x47\x96\x56\x2D\xFD\xB4",
+ .rlen = 88,
+ }, {
+ .key = "\xFE\xFF\xE9\x92\x86\x65\x73\x1C"
+ "\x6D\x6A\x8F\x94\x67\x30\x83\x08"
+ "\xCA\xFE\xBA\xBE",
+ .klen = 20,
+ .iv = "\xFA\xCE\xDB\xAD\xDE\xCA\xF8\x88",
+ .input = "\x45\x00\x00\x3E\x69\x8F\x00\x00"
+ "\x80\x11\x4D\xCC\xC0\xA8\x01\x02"
+ "\xC0\xA8\x01\x01\x0A\x98\x00\x35"
+ "\x00\x2A\x23\x43\xB2\xD0\x01\x00"
+ "\x00\x01\x00\x00\x00\x00\x00\x00"
+ "\x03\x73\x69\x70\x09\x63\x79\x62"
+ "\x65\x72\x63\x69\x74\x79\x02\x64"
+ "\x6B\x00\x00\x01\x00\x01\x00\x01",
+ .ilen = 64,
+ .assoc = "\x00\x00\xA5\xF8\x00\x00\x00\x0A",
+ .alen = 8,
+ .result = "\xDE\xB2\x2C\xD9\xB0\x7C\x72\xC1"
+ "\x6E\x3A\x65\xBE\xEB\x8D\xF3\x04"
+ "\xA5\xA5\x89\x7D\x33\xAE\x53\x0F"
+ "\x1B\xA7\x6D\x5D\x11\x4D\x2A\x5C"
+ "\x3D\xE8\x18\x27\xC1\x0E\x9A\x4F"
+ "\x51\x33\x0D\x0E\xEC\x41\x66\x42"
+ "\xCF\xBB\x85\xA5\xB4\x7E\x48\xA4"
+ "\xEC\x3B\x9B\xA9\x5D\x91\x8B\xD1"
+ "\x83\xB7\x0D\x3A\xA8\xBC\x6E\xE4"
+ "\xC3\x09\xE9\xD8\x5A\x41\xAD\x4A",
+ .rlen = 80,
+ }, {
+ .key = "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\x11\x22\x33\x44",
+ .klen = 36,
+ .iv = "\x01\x02\x03\x04\x05\x06\x07\x08",
+ .input = "\x45\x00\x00\x30\x69\xA6\x40\x00"
+ "\x80\x06\x26\x90\xC0\xA8\x01\x02"
+ "\x93\x89\x15\x5E\x0A\x9E\x00\x8B"
+ "\x2D\xC5\x7E\xE0\x00\x00\x00\x00"
+ "\x70\x02\x40\x00\x20\xBF\x00\x00"
+ "\x02\x04\x05\xB4\x01\x01\x04\x02"
+ "\x01\x02\x02\x01",
+ .ilen = 52,
+ .assoc = "\x4A\x2C\xBF\xE3\x00\x00\x00\x02",
+ .alen = 8,
+ .result = "\xFF\x42\x5C\x9B\x72\x45\x99\xDF"
+ "\x7A\x3B\xCD\x51\x01\x94\xE0\x0D"
+ "\x6A\x78\x10\x7F\x1B\x0B\x1C\xBF"
+ "\x06\xEF\xAE\x9D\x65\xA5\xD7\x63"
+ "\x74\x8A\x63\x79\x85\x77\x1D\x34"
+ "\x7F\x05\x45\x65\x9F\x14\xE9\x9D"
+ "\xEF\x84\x2D\x8E\xB3\x35\xF4\xEE"
+ "\xCF\xDB\xF8\x31\x82\x4B\x4C\x49"
+ "\x15\x95\x6C\x96",
+ .rlen = 68,
+ }, {
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ .klen = 20,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x45\x00\x00\x3C\x99\xC5\x00\x00"
+ "\x80\x01\xCB\x7A\x40\x67\x93\x18"
+ "\x01\x01\x01\x01\x08\x00\x07\x5C"
+ "\x02\x00\x44\x00\x61\x62\x63\x64"
+ "\x65\x66\x67\x68\x69\x6A\x6B\x6C"
+ "\x6D\x6E\x6F\x70\x71\x72\x73\x74"
+ "\x75\x76\x77\x61\x62\x63\x64\x65"
+ "\x66\x67\x68\x69\x01\x02\x02\x01",
+ .ilen = 64,
+ .assoc = "\x00\x00\x00\x00\x00\x00\x00\x01",
+ .alen = 8,
+ .result = "\x46\x88\xDA\xF2\xF9\x73\xA3\x92"
+ "\x73\x29\x09\xC3\x31\xD5\x6D\x60"
+ "\xF6\x94\xAB\xAA\x41\x4B\x5E\x7F"
+ "\xF5\xFD\xCD\xFF\xF5\xE9\xA2\x84"
+ "\x45\x64\x76\x49\x27\x19\xFF\xB6"
+ "\x4D\xE7\xD9\xDC\xA1\xE1\xD8\x94"
+ "\xBC\x3B\xD5\x78\x73\xED\x4D\x18"
+ "\x1D\x19\xD4\xD5\xC8\xC1\x8A\xF3"
+ "\xF8\x21\xD4\x96\xEE\xB0\x96\xE9"
+ "\x8A\xD2\xB6\x9E\x47\x99\xC7\x1D",
+ .rlen = 80,
+ }, {
+ .key = "\x3D\xE0\x98\x74\xB3\x88\xE6\x49"
+ "\x19\x88\xD0\xC3\x60\x7E\xAE\x1F"
+ "\x57\x69\x0E\x43",
+ .klen = 20,
+ .iv = "\x4E\x28\x00\x00\xA2\xFC\xA1\xA3",
+ .input = "\x45\x00\x00\x3C\x99\xC3\x00\x00"
+ "\x80\x01\xCB\x7C\x40\x67\x93\x18"
+ "\x01\x01\x01\x01\x08\x00\x08\x5C"
+ "\x02\x00\x43\x00\x61\x62\x63\x64"
+ "\x65\x66\x67\x68\x69\x6A\x6B\x6C"
+ "\x6D\x6E\x6F\x70\x71\x72\x73\x74"
+ "\x75\x76\x77\x61\x62\x63\x64\x65"
+ "\x66\x67\x68\x69\x01\x02\x02\x01",
+ .ilen = 64,
+ .assoc = "\x42\xF6\x7E\x3F\x10\x10\x10\x10"
+ "\x10\x10\x10\x10",
+ .alen = 12,
+ .result = "\xFB\xA2\xCA\xA4\x85\x3C\xF9\xF0"
+ "\xF2\x2C\xB1\x0D\x86\xDD\x83\xB0"
+ "\xFE\xC7\x56\x91\xCF\x1A\x04\xB0"
+ "\x0D\x11\x38\xEC\x9C\x35\x79\x17"
+ "\x65\xAC\xBD\x87\x01\xAD\x79\x84"
+ "\x5B\xF9\xFE\x3F\xBA\x48\x7B\xC9"
+ "\x17\x55\xE6\x66\x2B\x4C\x8D\x0D"
+ "\x1F\x5E\x22\x73\x95\x30\x32\x0A"
+ "\xE0\xD7\x31\xCC\x97\x8E\xCA\xFA"
+ "\xEA\xE8\x8F\x00\xE8\x0D\x6E\x48",
+ .rlen = 80,
+ }, {
+ .key = "\x3D\xE0\x98\x74\xB3\x88\xE6\x49"
+ "\x19\x88\xD0\xC3\x60\x7E\xAE\x1F"
+ "\x57\x69\x0E\x43",
+ .klen = 20,
+ .iv = "\x4E\x28\x00\x00\xA2\xFC\xA1\xA3",
+ .input = "\x45\x00\x00\x1C\x42\xA2\x00\x00"
+ "\x80\x01\x44\x1F\x40\x67\x93\xB6"
+ "\xE0\x00\x00\x02\x0A\x00\xF5\xFF"
+ "\x01\x02\x02\x01",
+ .ilen = 28,
+ .assoc = "\x42\xF6\x7E\x3F\x10\x10\x10\x10"
+ "\x10\x10\x10\x10",
+ .alen = 12,
+ .result = "\xFB\xA2\xCA\x84\x5E\x5D\xF9\xF0"
+ "\xF2\x2C\x3E\x6E\x86\xDD\x83\x1E"
+ "\x1F\xC6\x57\x92\xCD\x1A\xF9\x13"
+ "\x0E\x13\x79\xED\x36\x9F\x07\x1F"
+ "\x35\xE0\x34\xBE\x95\xF1\x12\xE4"
+ "\xE7\xD0\x5D\x35",
+ .rlen = 44,
+ }, {
+ .key = "\xFE\xFF\xE9\x92\x86\x65\x73\x1C"
+ "\x6D\x6A\x8F\x94\x67\x30\x83\x08"
+ "\xFE\xFF\xE9\x92\x86\x65\x73\x1C"
+ "\xCA\xFE\xBA\xBE",
+ .klen = 28,
+ .iv = "\xFA\xCE\xDB\xAD\xDE\xCA\xF8\x88",
+ .input = "\x45\x00\x00\x28\xA4\xAD\x40\x00"
+ "\x40\x06\x78\x80\x0A\x01\x03\x8F"
+ "\x0A\x01\x06\x12\x80\x23\x06\xB8"
+ "\xCB\x71\x26\x02\xDD\x6B\xB0\x3E"
+ "\x50\x10\x16\xD0\x75\x68\x00\x01",
+ .ilen = 40,
+ .assoc = "\x00\x00\xA5\xF8\x00\x00\x00\x0A",
+ .alen = 8,
+ .result = "\xA5\xB1\xF8\x06\x60\x29\xAE\xA4"
+ "\x0E\x59\x8B\x81\x22\xDE\x02\x42"
+ "\x09\x38\xB3\xAB\x33\xF8\x28\xE6"
+ "\x87\xB8\x85\x8B\x5B\xFB\xDB\xD0"
+ "\x31\x5B\x27\x45\x21\x44\xCC\x77"
+ "\x95\x45\x7B\x96\x52\x03\x7F\x53"
+ "\x18\x02\x7B\x5B\x4C\xD7\xA6\x36",
+ .rlen = 56,
+ }, {
+ .key = "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\xDE\xCA\xF8\x88",
+ .klen = 20,
+ .iv = "\xCA\xFE\xDE\xBA\xCE\xFA\xCE\x74",
+ .input = "\x45\x00\x00\x49\x33\xBA\x00\x00"
+ "\x7F\x11\x91\x06\xC3\xFB\x1D\x10"
+ "\xC2\xB1\xD3\x26\xC0\x28\x31\xCE"
+ "\x00\x35\xDD\x7B\x80\x03\x02\xD5"
+ "\x00\x00\x4E\x20\x00\x1E\x8C\x18"
+ "\xD7\x5B\x81\xDC\x91\xBA\xA0\x47"
+ "\x6B\x91\xB9\x24\xB2\x80\x38\x9D"
+ "\x92\xC9\x63\xBA\xC0\x46\xEC\x95"
+ "\x9B\x62\x66\xC0\x47\x22\xB1\x49"
+ "\x23\x01\x01\x01",
+ .ilen = 76,
+ .assoc = "\x00\x00\x01\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x01",
+ .alen = 12,
+ .result = "\x18\xA6\xFD\x42\xF7\x2C\xBF\x4A"
+ "\xB2\xA2\xEA\x90\x1F\x73\xD8\x14"
+ "\xE3\xE7\xF2\x43\xD9\x54\x12\xE1"
+ "\xC3\x49\xC1\xD2\xFB\xEC\x16\x8F"
+ "\x91\x90\xFE\xEB\xAF\x2C\xB0\x19"
+ "\x84\xE6\x58\x63\x96\x5D\x74\x72"
+ "\xB7\x9D\xA3\x45\xE0\xE7\x80\x19"
+ "\x1F\x0D\x2F\x0E\x0F\x49\x6C\x22"
+ "\x6F\x21\x27\xB2\x7D\xB3\x57\x24"
+ "\xE7\x84\x5D\x68\x65\x1F\x57\xE6"
+ "\x5F\x35\x4F\x75\xFF\x17\x01\x57"
+ "\x69\x62\x34\x36",
+ .rlen = 92,
+ }, {
+ .key = "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\x73\x61\x6C\x74",
+ .klen = 36,
+ .iv = "\x61\x6E\x64\x01\x69\x76\x65\x63",
+ .input = "\x45\x08\x00\x28\x73\x2C\x00\x00"
+ "\x40\x06\xE9\xF9\x0A\x01\x06\x12"
+ "\x0A\x01\x03\x8F\x06\xB8\x80\x23"
+ "\xDD\x6B\xAF\xBE\xCB\x71\x26\x02"
+ "\x50\x10\x1F\x64\x6D\x54\x00\x01",
+ .ilen = 40,
+ .assoc = "\x17\x40\x5E\x67\x15\x6F\x31\x26"
+ "\xDD\x0D\xB9\x9B",
+ .alen = 12,
+ .result = "\xF2\xD6\x9E\xCD\xBD\x5A\x0D\x5B"
+ "\x8D\x5E\xF3\x8B\xAD\x4D\xA5\x8D"
+ "\x1F\x27\x8F\xDE\x98\xEF\x67\x54"
+ "\x9D\x52\x4A\x30\x18\xD9\xA5\x7F"
+ "\xF4\xD3\xA3\x1C\xE6\x73\x11\x9E"
+ "\x45\x16\x26\xC2\x41\x57\x71\xE3"
+ "\xB7\xEE\xBC\xA6\x14\xC8\x9B\x35",
+ .rlen = 56,
+ }, {
+ .key = "\x3D\xE0\x98\x74\xB3\x88\xE6\x49"
+ "\x19\x88\xD0\xC3\x60\x7E\xAE\x1F"
+ "\x57\x69\x0E\x43",
+ .klen = 20,
+ .iv = "\x4E\x28\x00\x00\xA2\xFC\xA1\xA3",
+ .input = "\x45\x00\x00\x49\x33\x3E\x00\x00"
+ "\x7F\x11\x91\x82\xC3\xFB\x1D\x10"
+ "\xC2\xB1\xD3\x26\xC0\x28\x31\xCE"
+ "\x00\x35\xCB\x45\x80\x03\x02\x5B"
+ "\x00\x00\x01\xE0\x00\x1E\x8C\x18"
+ "\xD6\x57\x59\xD5\x22\x84\xA0\x35"
+ "\x2C\x71\x47\x5C\x88\x80\x39\x1C"
+ "\x76\x4D\x6E\x5E\xE0\x49\x6B\x32"
+ "\x5A\xE2\x70\xC0\x38\x99\x49\x39"
+ "\x15\x01\x01\x01",
+ .ilen = 76,
+ .assoc = "\x42\xF6\x7E\x3F\x10\x10\x10\x10"
+ "\x10\x10\x10\x10",
+ .alen = 12,
+ .result = "\xFB\xA2\xCA\xD1\x2F\xC1\xF9\xF0"
+ "\x0D\x3C\xEB\xF3\x05\x41\x0D\xB8"
+ "\x3D\x77\x84\xB6\x07\x32\x3D\x22"
+ "\x0F\x24\xB0\xA9\x7D\x54\x18\x28"
+ "\x00\xCA\xDB\x0F\x68\xD9\x9E\xF0"
+ "\xE0\xC0\xC8\x9A\xE9\xBE\xA8\x88"
+ "\x4E\x52\xD6\x5B\xC1\xAF\xD0\x74"
+ "\x0F\x74\x24\x44\x74\x7B\x5B\x39"
+ "\xAB\x53\x31\x63\xAA\xD4\x55\x0E"
+ "\xE5\x16\x09\x75\xCD\xB6\x08\xC5"
+ "\x76\x91\x89\x60\x97\x63\xB8\xE1"
+ "\x8C\xAA\x81\xE2",
+ .rlen = 92,
+ }, {
+ .key = "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\x73\x61\x6C\x74",
+ .klen = 36,
+ .iv = "\x61\x6E\x64\x01\x69\x76\x65\x63",
+ .input = "\x63\x69\x73\x63\x6F\x01\x72\x75"
+ "\x6C\x65\x73\x01\x74\x68\x65\x01"
+ "\x6E\x65\x74\x77\x65\x01\x64\x65"
+ "\x66\x69\x6E\x65\x01\x74\x68\x65"
+ "\x74\x65\x63\x68\x6E\x6F\x6C\x6F"
+ "\x67\x69\x65\x73\x01\x74\x68\x61"
+ "\x74\x77\x69\x6C\x6C\x01\x64\x65"
+ "\x66\x69\x6E\x65\x74\x6F\x6D\x6F"
+ "\x72\x72\x6F\x77\x01\x02\x02\x01",
+ .ilen = 72,
+ .assoc = "\x17\x40\x5E\x67\x15\x6F\x31\x26"
+ "\xDD\x0D\xB9\x9B",
+ .alen = 12,
+ .result = "\xD4\xB7\xED\x86\xA1\x77\x7F\x2E"
+ "\xA1\x3D\x69\x73\xD3\x24\xC6\x9E"
+ "\x7B\x43\xF8\x26\xFB\x56\x83\x12"
+ "\x26\x50\x8B\xEB\xD2\xDC\xEB\x18"
+ "\xD0\xA6\xDF\x10\xE5\x48\x7D\xF0"
+ "\x74\x11\x3E\x14\xC6\x41\x02\x4E"
+ "\x3E\x67\x73\xD9\x1A\x62\xEE\x42"
+ "\x9B\x04\x3A\x10\xE3\xEF\xE6\xB0"
+ "\x12\xA4\x93\x63\x41\x23\x64\xF8"
+ "\xC0\xCA\xC5\x87\xF2\x49\xE5\x6B"
+ "\x11\xE2\x4F\x30\xE4\x4C\xCC\x76",
+ .rlen = 88,
+ }, {
+ .key = "\x7D\x77\x3D\x00\xC1\x44\xC5\x25"
+ "\xAC\x61\x9D\x18\xC8\x4A\x3F\x47"
+ "\xD9\x66\x42\x67",
+ .klen = 20,
+ .iv = "\x43\x45\x7E\x91\x82\x44\x3B\xC6",
+ .input = "\x01\x02\x02\x01",
+ .ilen = 4,
+ .assoc = "\x33\x54\x67\xAE\xFF\xFF\xFF\xFF",
+ .alen = 8,
+ .result = "\x43\x7F\x86\x6B\xCB\x3F\x69\x9F"
+ "\xE9\xB0\x82\x2B\xAC\x96\x1C\x45"
+ "\x04\xBE\xF2\x70",
+ .rlen = 20,
+ }, {
+ .key = "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\xDE\xCA\xF8\x88",
+ .klen = 20,
+ .iv = "\xCA\xFE\xDE\xBA\xCE\xFA\xCE\x74",
+ .input = "\x74\x6F\x01\x62\x65\x01\x6F\x72"
+ "\x01\x6E\x6F\x74\x01\x74\x6F\x01"
+ "\x62\x65\x00\x01",
+ .ilen = 20,
+ .assoc = "\x00\x00\x01\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x01",
+ .alen = 12,
+ .result = "\x29\xC9\xFC\x69\xA1\x97\xD0\x38"
+ "\xCC\xDD\x14\xE2\xDD\xFC\xAA\x05"
+ "\x43\x33\x21\x64\x41\x25\x03\x52"
+ "\x43\x03\xED\x3C\x6C\x5F\x28\x38"
+ "\x43\xAF\x8C\x3E",
+ .rlen = 36,
+ }, {
+ .key = "\x6C\x65\x67\x61\x6C\x69\x7A\x65"
+ "\x6D\x61\x72\x69\x6A\x75\x61\x6E"
+ "\x61\x61\x6E\x64\x64\x6F\x69\x74"
+ "\x62\x65\x66\x6F\x72\x65\x69\x61"
+ "\x74\x75\x72\x6E",
+ .klen = 36,
+ .iv = "\x33\x30\x21\x69\x67\x65\x74\x6D",
+ .input = "\x45\x00\x00\x30\xDA\x3A\x00\x00"
+ "\x80\x01\xDF\x3B\xC0\xA8\x00\x05"
+ "\xC0\xA8\x00\x01\x08\x00\xC6\xCD"
+ "\x02\x00\x07\x00\x61\x62\x63\x64"
+ "\x65\x66\x67\x68\x69\x6A\x6B\x6C"
+ "\x6D\x6E\x6F\x70\x71\x72\x73\x74"
+ "\x01\x02\x02\x01",
+ .ilen = 52,
+ .assoc = "\x79\x6B\x69\x63\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF",
+ .alen = 12,
+ .result = "\xF9\x7A\xB2\xAA\x35\x6D\x8E\xDC"
+ "\xE1\x76\x44\xAC\x8C\x78\xE2\x5D"
+ "\xD2\x4D\xED\xBB\x29\xEB\xF1\xB6"
+ "\x4A\x27\x4B\x39\xB4\x9C\x3A\x86"
+ "\x4C\xD3\xD7\x8C\xA4\xAE\x68\xA3"
+ "\x2B\x42\x45\x8F\xB5\x7D\xBE\x82"
+ "\x1D\xCC\x63\xB9\xD0\x93\x7B\xA2"
+ "\x94\x5F\x66\x93\x68\x66\x1A\x32"
+ "\x9F\xB4\xC0\x53",
+ .rlen = 68,
+ }, {
+ .key = "\x3D\xE0\x98\x74\xB3\x88\xE6\x49"
+ "\x19\x88\xD0\xC3\x60\x7E\xAE\x1F"
+ "\x57\x69\x0E\x43",
+ .klen = 20,
+ .iv = "\x4E\x28\x00\x00\xA2\xFC\xA1\xA3",
+ .input = "\x45\x00\x00\x30\xDA\x3A\x00\x00"
+ "\x80\x01\xDF\x3B\xC0\xA8\x00\x05"
+ "\xC0\xA8\x00\x01\x08\x00\xC6\xCD"
+ "\x02\x00\x07\x00\x61\x62\x63\x64"
+ "\x65\x66\x67\x68\x69\x6A\x6B\x6C"
+ "\x6D\x6E\x6F\x70\x71\x72\x73\x74"
+ "\x01\x02\x02\x01",
+ .ilen = 52,
+ .assoc = "\x3F\x7E\xF6\x42\x10\x10\x10\x10"
+ "\x10\x10\x10\x10",
+ .alen = 12,
+ .result = "\xFB\xA2\xCA\xA8\xC6\xC5\xF9\xF0"
+ "\xF2\x2C\xA5\x4A\x06\x12\x10\xAD"
+ "\x3F\x6E\x57\x91\xCF\x1A\xCA\x21"
+ "\x0D\x11\x7C\xEC\x9C\x35\x79\x17"
+ "\x65\xAC\xBD\x87\x01\xAD\x79\x84"
+ "\x5B\xF9\xFE\x3F\xBA\x48\x7B\xC9"
+ "\x63\x21\x93\x06\x84\xEE\xCA\xDB"
+ "\x56\x91\x25\x46\xE7\xA9\x5C\x97"
+ "\x40\xD7\xCB\x05",
+ .rlen = 68,
+ }, {
+ .key = "\x4C\x80\xCD\xEF\xBB\x5D\x10\xDA"
+ "\x90\x6A\xC7\x3C\x36\x13\xA6\x34"
+ "\x22\x43\x3C\x64",
+ .klen = 20,
+ .iv = "\x48\x55\xEC\x7D\x3A\x23\x4B\xFD",
+ .input = "\x08\x00\xC6\xCD\x02\x00\x07\x00"
+ "\x61\x62\x63\x64\x65\x66\x67\x68"
+ "\x69\x6A\x6B\x6C\x6D\x6E\x6F\x70"
+ "\x71\x72\x73\x74\x01\x02\x02\x01",
+ .ilen = 32,
+ .assoc = "\x00\x00\x43\x21\x87\x65\x43\x21"
+ "\x00\x00\x00\x07",
+ .alen = 12,
+ .result = "\x74\x75\x2E\x8A\xEB\x5D\x87\x3C"
+ "\xD7\xC0\xF4\xAC\xC3\x6C\x4B\xFF"
+ "\x84\xB7\xD7\xB9\x8F\x0C\xA8\xB6"
+ "\xAC\xDA\x68\x94\xBC\x61\x90\x69"
+ "\xEF\x9C\xBC\x28\xFE\x1B\x56\xA7"
+ "\xC4\xE0\xD5\x8C\x86\xCD\x2B\xC0",
+ .rlen = 48,
}
};
@@ -19964,7 +20896,428 @@ static struct aead_testvec aes_gcm_rfc4106_dec_tv_template[] = {
"\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff",
.rlen = 192,
-
+ }, {
+ .key = "\x4C\x80\xCD\xEF\xBB\x5D\x10\xDA"
+ "\x90\x6A\xC7\x3C\x36\x13\xA6\x34"
+ "\x2E\x44\x3B\x68",
+ .klen = 20,
+ .iv = "\x49\x56\xED\x7E\x3B\x24\x4C\xFE",
+ .result = "\x45\x00\x00\x48\x69\x9A\x00\x00"
+ "\x80\x11\x4D\xB7\xC0\xA8\x01\x02"
+ "\xC0\xA8\x01\x01\x0A\x9B\xF1\x56"
+ "\x38\xD3\x01\x00\x00\x01\x00\x00"
+ "\x00\x00\x00\x00\x04\x5F\x73\x69"
+ "\x70\x04\x5F\x75\x64\x70\x03\x73"
+ "\x69\x70\x09\x63\x79\x62\x65\x72"
+ "\x63\x69\x74\x79\x02\x64\x6B\x00"
+ "\x00\x21\x00\x01\x01\x02\x02\x01",
+ .rlen = 72,
+ .assoc = "\x00\x00\x43\x21\x87\x65\x43\x21"
+ "\x00\x00\x00\x00",
+ .alen = 12,
+ .input = "\xFE\xCF\x53\x7E\x72\x9D\x5B\x07"
+ "\xDC\x30\xDF\x52\x8D\xD2\x2B\x76"
+ "\x8D\x1B\x98\x73\x66\x96\xA6\xFD"
+ "\x34\x85\x09\xFA\x13\xCE\xAC\x34"
+ "\xCF\xA2\x43\x6F\x14\xA3\xF3\xCF"
+ "\x65\x92\x5B\xF1\xF4\xA1\x3C\x5D"
+ "\x15\xB2\x1E\x18\x84\xF5\xFF\x62"
+ "\x47\xAE\xAB\xB7\x86\xB9\x3B\xCE"
+ "\x61\xBC\x17\xD7\x68\xFD\x97\x32"
+ "\x45\x90\x18\x14\x8F\x6C\xBE\x72"
+ "\x2F\xD0\x47\x96\x56\x2D\xFD\xB4",
+ .ilen = 88,
+ }, {
+ .key = "\xFE\xFF\xE9\x92\x86\x65\x73\x1C"
+ "\x6D\x6A\x8F\x94\x67\x30\x83\x08"
+ "\xCA\xFE\xBA\xBE",
+ .klen = 20,
+ .iv = "\xFA\xCE\xDB\xAD\xDE\xCA\xF8\x88",
+ .result = "\x45\x00\x00\x3E\x69\x8F\x00\x00"
+ "\x80\x11\x4D\xCC\xC0\xA8\x01\x02"
+ "\xC0\xA8\x01\x01\x0A\x98\x00\x35"
+ "\x00\x2A\x23\x43\xB2\xD0\x01\x00"
+ "\x00\x01\x00\x00\x00\x00\x00\x00"
+ "\x03\x73\x69\x70\x09\x63\x79\x62"
+ "\x65\x72\x63\x69\x74\x79\x02\x64"
+ "\x6B\x00\x00\x01\x00\x01\x00\x01",
+ .rlen = 64,
+ .assoc = "\x00\x00\xA5\xF8\x00\x00\x00\x0A",
+ .alen = 8,
+ .input = "\xDE\xB2\x2C\xD9\xB0\x7C\x72\xC1"
+ "\x6E\x3A\x65\xBE\xEB\x8D\xF3\x04"
+ "\xA5\xA5\x89\x7D\x33\xAE\x53\x0F"
+ "\x1B\xA7\x6D\x5D\x11\x4D\x2A\x5C"
+ "\x3D\xE8\x18\x27\xC1\x0E\x9A\x4F"
+ "\x51\x33\x0D\x0E\xEC\x41\x66\x42"
+ "\xCF\xBB\x85\xA5\xB4\x7E\x48\xA4"
+ "\xEC\x3B\x9B\xA9\x5D\x91\x8B\xD1"
+ "\x83\xB7\x0D\x3A\xA8\xBC\x6E\xE4"
+ "\xC3\x09\xE9\xD8\x5A\x41\xAD\x4A",
+ .ilen = 80,
+ }, {
+ .key = "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\x11\x22\x33\x44",
+ .klen = 36,
+ .iv = "\x01\x02\x03\x04\x05\x06\x07\x08",
+ .result = "\x45\x00\x00\x30\x69\xA6\x40\x00"
+ "\x80\x06\x26\x90\xC0\xA8\x01\x02"
+ "\x93\x89\x15\x5E\x0A\x9E\x00\x8B"
+ "\x2D\xC5\x7E\xE0\x00\x00\x00\x00"
+ "\x70\x02\x40\x00\x20\xBF\x00\x00"
+ "\x02\x04\x05\xB4\x01\x01\x04\x02"
+ "\x01\x02\x02\x01",
+ .rlen = 52,
+ .assoc = "\x4A\x2C\xBF\xE3\x00\x00\x00\x02",
+ .alen = 8,
+ .input = "\xFF\x42\x5C\x9B\x72\x45\x99\xDF"
+ "\x7A\x3B\xCD\x51\x01\x94\xE0\x0D"
+ "\x6A\x78\x10\x7F\x1B\x0B\x1C\xBF"
+ "\x06\xEF\xAE\x9D\x65\xA5\xD7\x63"
+ "\x74\x8A\x63\x79\x85\x77\x1D\x34"
+ "\x7F\x05\x45\x65\x9F\x14\xE9\x9D"
+ "\xEF\x84\x2D\x8E\xB3\x35\xF4\xEE"
+ "\xCF\xDB\xF8\x31\x82\x4B\x4C\x49"
+ "\x15\x95\x6C\x96",
+ .ilen = 68,
+ }, {
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00",
+ .klen = 20,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .result = "\x45\x00\x00\x3C\x99\xC5\x00\x00"
+ "\x80\x01\xCB\x7A\x40\x67\x93\x18"
+ "\x01\x01\x01\x01\x08\x00\x07\x5C"
+ "\x02\x00\x44\x00\x61\x62\x63\x64"
+ "\x65\x66\x67\x68\x69\x6A\x6B\x6C"
+ "\x6D\x6E\x6F\x70\x71\x72\x73\x74"
+ "\x75\x76\x77\x61\x62\x63\x64\x65"
+ "\x66\x67\x68\x69\x01\x02\x02\x01",
+ .rlen = 64,
+ .assoc = "\x00\x00\x00\x00\x00\x00\x00\x01",
+ .alen = 8,
+ .input = "\x46\x88\xDA\xF2\xF9\x73\xA3\x92"
+ "\x73\x29\x09\xC3\x31\xD5\x6D\x60"
+ "\xF6\x94\xAB\xAA\x41\x4B\x5E\x7F"
+ "\xF5\xFD\xCD\xFF\xF5\xE9\xA2\x84"
+ "\x45\x64\x76\x49\x27\x19\xFF\xB6"
+ "\x4D\xE7\xD9\xDC\xA1\xE1\xD8\x94"
+ "\xBC\x3B\xD5\x78\x73\xED\x4D\x18"
+ "\x1D\x19\xD4\xD5\xC8\xC1\x8A\xF3"
+ "\xF8\x21\xD4\x96\xEE\xB0\x96\xE9"
+ "\x8A\xD2\xB6\x9E\x47\x99\xC7\x1D",
+ .ilen = 80,
+ }, {
+ .key = "\x3D\xE0\x98\x74\xB3\x88\xE6\x49"
+ "\x19\x88\xD0\xC3\x60\x7E\xAE\x1F"
+ "\x57\x69\x0E\x43",
+ .klen = 20,
+ .iv = "\x4E\x28\x00\x00\xA2\xFC\xA1\xA3",
+ .result = "\x45\x00\x00\x3C\x99\xC3\x00\x00"
+ "\x80\x01\xCB\x7C\x40\x67\x93\x18"
+ "\x01\x01\x01\x01\x08\x00\x08\x5C"
+ "\x02\x00\x43\x00\x61\x62\x63\x64"
+ "\x65\x66\x67\x68\x69\x6A\x6B\x6C"
+ "\x6D\x6E\x6F\x70\x71\x72\x73\x74"
+ "\x75\x76\x77\x61\x62\x63\x64\x65"
+ "\x66\x67\x68\x69\x01\x02\x02\x01",
+ .rlen = 64,
+ .assoc = "\x42\xF6\x7E\x3F\x10\x10\x10\x10"
+ "\x10\x10\x10\x10",
+ .alen = 12,
+ .input = "\xFB\xA2\xCA\xA4\x85\x3C\xF9\xF0"
+ "\xF2\x2C\xB1\x0D\x86\xDD\x83\xB0"
+ "\xFE\xC7\x56\x91\xCF\x1A\x04\xB0"
+ "\x0D\x11\x38\xEC\x9C\x35\x79\x17"
+ "\x65\xAC\xBD\x87\x01\xAD\x79\x84"
+ "\x5B\xF9\xFE\x3F\xBA\x48\x7B\xC9"
+ "\x17\x55\xE6\x66\x2B\x4C\x8D\x0D"
+ "\x1F\x5E\x22\x73\x95\x30\x32\x0A"
+ "\xE0\xD7\x31\xCC\x97\x8E\xCA\xFA"
+ "\xEA\xE8\x8F\x00\xE8\x0D\x6E\x48",
+ .ilen = 80,
+ }, {
+ .key = "\x3D\xE0\x98\x74\xB3\x88\xE6\x49"
+ "\x19\x88\xD0\xC3\x60\x7E\xAE\x1F"
+ "\x57\x69\x0E\x43",
+ .klen = 20,
+ .iv = "\x4E\x28\x00\x00\xA2\xFC\xA1\xA3",
+ .result = "\x45\x00\x00\x1C\x42\xA2\x00\x00"
+ "\x80\x01\x44\x1F\x40\x67\x93\xB6"
+ "\xE0\x00\x00\x02\x0A\x00\xF5\xFF"
+ "\x01\x02\x02\x01",
+ .rlen = 28,
+ .assoc = "\x42\xF6\x7E\x3F\x10\x10\x10\x10"
+ "\x10\x10\x10\x10",
+ .alen = 12,
+ .input = "\xFB\xA2\xCA\x84\x5E\x5D\xF9\xF0"
+ "\xF2\x2C\x3E\x6E\x86\xDD\x83\x1E"
+ "\x1F\xC6\x57\x92\xCD\x1A\xF9\x13"
+ "\x0E\x13\x79\xED\x36\x9F\x07\x1F"
+ "\x35\xE0\x34\xBE\x95\xF1\x12\xE4"
+ "\xE7\xD0\x5D\x35",
+ .ilen = 44,
+ }, {
+ .key = "\xFE\xFF\xE9\x92\x86\x65\x73\x1C"
+ "\x6D\x6A\x8F\x94\x67\x30\x83\x08"
+ "\xFE\xFF\xE9\x92\x86\x65\x73\x1C"
+ "\xCA\xFE\xBA\xBE",
+ .klen = 28,
+ .iv = "\xFA\xCE\xDB\xAD\xDE\xCA\xF8\x88",
+ .result = "\x45\x00\x00\x28\xA4\xAD\x40\x00"
+ "\x40\x06\x78\x80\x0A\x01\x03\x8F"
+ "\x0A\x01\x06\x12\x80\x23\x06\xB8"
+ "\xCB\x71\x26\x02\xDD\x6B\xB0\x3E"
+ "\x50\x10\x16\xD0\x75\x68\x00\x01",
+ .rlen = 40,
+ .assoc = "\x00\x00\xA5\xF8\x00\x00\x00\x0A",
+ .alen = 8,
+ .input = "\xA5\xB1\xF8\x06\x60\x29\xAE\xA4"
+ "\x0E\x59\x8B\x81\x22\xDE\x02\x42"
+ "\x09\x38\xB3\xAB\x33\xF8\x28\xE6"
+ "\x87\xB8\x85\x8B\x5B\xFB\xDB\xD0"
+ "\x31\x5B\x27\x45\x21\x44\xCC\x77"
+ "\x95\x45\x7B\x96\x52\x03\x7F\x53"
+ "\x18\x02\x7B\x5B\x4C\xD7\xA6\x36",
+ .ilen = 56,
+ }, {
+ .key = "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\xDE\xCA\xF8\x88",
+ .klen = 20,
+ .iv = "\xCA\xFE\xDE\xBA\xCE\xFA\xCE\x74",
+ .result = "\x45\x00\x00\x49\x33\xBA\x00\x00"
+ "\x7F\x11\x91\x06\xC3\xFB\x1D\x10"
+ "\xC2\xB1\xD3\x26\xC0\x28\x31\xCE"
+ "\x00\x35\xDD\x7B\x80\x03\x02\xD5"
+ "\x00\x00\x4E\x20\x00\x1E\x8C\x18"
+ "\xD7\x5B\x81\xDC\x91\xBA\xA0\x47"
+ "\x6B\x91\xB9\x24\xB2\x80\x38\x9D"
+ "\x92\xC9\x63\xBA\xC0\x46\xEC\x95"
+ "\x9B\x62\x66\xC0\x47\x22\xB1\x49"
+ "\x23\x01\x01\x01",
+ .rlen = 76,
+ .assoc = "\x00\x00\x01\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x01",
+ .alen = 12,
+ .input = "\x18\xA6\xFD\x42\xF7\x2C\xBF\x4A"
+ "\xB2\xA2\xEA\x90\x1F\x73\xD8\x14"
+ "\xE3\xE7\xF2\x43\xD9\x54\x12\xE1"
+ "\xC3\x49\xC1\xD2\xFB\xEC\x16\x8F"
+ "\x91\x90\xFE\xEB\xAF\x2C\xB0\x19"
+ "\x84\xE6\x58\x63\x96\x5D\x74\x72"
+ "\xB7\x9D\xA3\x45\xE0\xE7\x80\x19"
+ "\x1F\x0D\x2F\x0E\x0F\x49\x6C\x22"
+ "\x6F\x21\x27\xB2\x7D\xB3\x57\x24"
+ "\xE7\x84\x5D\x68\x65\x1F\x57\xE6"
+ "\x5F\x35\x4F\x75\xFF\x17\x01\x57"
+ "\x69\x62\x34\x36",
+ .ilen = 92,
+ }, {
+ .key = "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\x73\x61\x6C\x74",
+ .klen = 36,
+ .iv = "\x61\x6E\x64\x01\x69\x76\x65\x63",
+ .result = "\x45\x08\x00\x28\x73\x2C\x00\x00"
+ "\x40\x06\xE9\xF9\x0A\x01\x06\x12"
+ "\x0A\x01\x03\x8F\x06\xB8\x80\x23"
+ "\xDD\x6B\xAF\xBE\xCB\x71\x26\x02"
+ "\x50\x10\x1F\x64\x6D\x54\x00\x01",
+ .rlen = 40,
+ .assoc = "\x17\x40\x5E\x67\x15\x6F\x31\x26"
+ "\xDD\x0D\xB9\x9B",
+ .alen = 12,
+ .input = "\xF2\xD6\x9E\xCD\xBD\x5A\x0D\x5B"
+ "\x8D\x5E\xF3\x8B\xAD\x4D\xA5\x8D"
+ "\x1F\x27\x8F\xDE\x98\xEF\x67\x54"
+ "\x9D\x52\x4A\x30\x18\xD9\xA5\x7F"
+ "\xF4\xD3\xA3\x1C\xE6\x73\x11\x9E"
+ "\x45\x16\x26\xC2\x41\x57\x71\xE3"
+ "\xB7\xEE\xBC\xA6\x14\xC8\x9B\x35",
+ .ilen = 56,
+ }, {
+ .key = "\x3D\xE0\x98\x74\xB3\x88\xE6\x49"
+ "\x19\x88\xD0\xC3\x60\x7E\xAE\x1F"
+ "\x57\x69\x0E\x43",
+ .klen = 20,
+ .iv = "\x4E\x28\x00\x00\xA2\xFC\xA1\xA3",
+ .result = "\x45\x00\x00\x49\x33\x3E\x00\x00"
+ "\x7F\x11\x91\x82\xC3\xFB\x1D\x10"
+ "\xC2\xB1\xD3\x26\xC0\x28\x31\xCE"
+ "\x00\x35\xCB\x45\x80\x03\x02\x5B"
+ "\x00\x00\x01\xE0\x00\x1E\x8C\x18"
+ "\xD6\x57\x59\xD5\x22\x84\xA0\x35"
+ "\x2C\x71\x47\x5C\x88\x80\x39\x1C"
+ "\x76\x4D\x6E\x5E\xE0\x49\x6B\x32"
+ "\x5A\xE2\x70\xC0\x38\x99\x49\x39"
+ "\x15\x01\x01\x01",
+ .rlen = 76,
+ .assoc = "\x42\xF6\x7E\x3F\x10\x10\x10\x10"
+ "\x10\x10\x10\x10",
+ .alen = 12,
+ .input = "\xFB\xA2\xCA\xD1\x2F\xC1\xF9\xF0"
+ "\x0D\x3C\xEB\xF3\x05\x41\x0D\xB8"
+ "\x3D\x77\x84\xB6\x07\x32\x3D\x22"
+ "\x0F\x24\xB0\xA9\x7D\x54\x18\x28"
+ "\x00\xCA\xDB\x0F\x68\xD9\x9E\xF0"
+ "\xE0\xC0\xC8\x9A\xE9\xBE\xA8\x88"
+ "\x4E\x52\xD6\x5B\xC1\xAF\xD0\x74"
+ "\x0F\x74\x24\x44\x74\x7B\x5B\x39"
+ "\xAB\x53\x31\x63\xAA\xD4\x55\x0E"
+ "\xE5\x16\x09\x75\xCD\xB6\x08\xC5"
+ "\x76\x91\x89\x60\x97\x63\xB8\xE1"
+ "\x8C\xAA\x81\xE2",
+ .ilen = 92,
+ }, {
+ .key = "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\x73\x61\x6C\x74",
+ .klen = 36,
+ .iv = "\x61\x6E\x64\x01\x69\x76\x65\x63",
+ .result = "\x63\x69\x73\x63\x6F\x01\x72\x75"
+ "\x6C\x65\x73\x01\x74\x68\x65\x01"
+ "\x6E\x65\x74\x77\x65\x01\x64\x65"
+ "\x66\x69\x6E\x65\x01\x74\x68\x65"
+ "\x74\x65\x63\x68\x6E\x6F\x6C\x6F"
+ "\x67\x69\x65\x73\x01\x74\x68\x61"
+ "\x74\x77\x69\x6C\x6C\x01\x64\x65"
+ "\x66\x69\x6E\x65\x74\x6F\x6D\x6F"
+ "\x72\x72\x6F\x77\x01\x02\x02\x01",
+ .rlen = 72,
+ .assoc = "\x17\x40\x5E\x67\x15\x6F\x31\x26"
+ "\xDD\x0D\xB9\x9B",
+ .alen = 12,
+ .input = "\xD4\xB7\xED\x86\xA1\x77\x7F\x2E"
+ "\xA1\x3D\x69\x73\xD3\x24\xC6\x9E"
+ "\x7B\x43\xF8\x26\xFB\x56\x83\x12"
+ "\x26\x50\x8B\xEB\xD2\xDC\xEB\x18"
+ "\xD0\xA6\xDF\x10\xE5\x48\x7D\xF0"
+ "\x74\x11\x3E\x14\xC6\x41\x02\x4E"
+ "\x3E\x67\x73\xD9\x1A\x62\xEE\x42"
+ "\x9B\x04\x3A\x10\xE3\xEF\xE6\xB0"
+ "\x12\xA4\x93\x63\x41\x23\x64\xF8"
+ "\xC0\xCA\xC5\x87\xF2\x49\xE5\x6B"
+ "\x11\xE2\x4F\x30\xE4\x4C\xCC\x76",
+ .ilen = 88,
+ }, {
+ .key = "\x7D\x77\x3D\x00\xC1\x44\xC5\x25"
+ "\xAC\x61\x9D\x18\xC8\x4A\x3F\x47"
+ "\xD9\x66\x42\x67",
+ .klen = 20,
+ .iv = "\x43\x45\x7E\x91\x82\x44\x3B\xC6",
+ .result = "\x01\x02\x02\x01",
+ .rlen = 4,
+ .assoc = "\x33\x54\x67\xAE\xFF\xFF\xFF\xFF",
+ .alen = 8,
+ .input = "\x43\x7F\x86\x6B\xCB\x3F\x69\x9F"
+ "\xE9\xB0\x82\x2B\xAC\x96\x1C\x45"
+ "\x04\xBE\xF2\x70",
+ .ilen = 20,
+ }, {
+ .key = "\xAB\xBC\xCD\xDE\xF0\x01\x12\x23"
+ "\x34\x45\x56\x67\x78\x89\x9A\xAB"
+ "\xDE\xCA\xF8\x88",
+ .klen = 20,
+ .iv = "\xCA\xFE\xDE\xBA\xCE\xFA\xCE\x74",
+ .result = "\x74\x6F\x01\x62\x65\x01\x6F\x72"
+ "\x01\x6E\x6F\x74\x01\x74\x6F\x01"
+ "\x62\x65\x00\x01",
+ .rlen = 20,
+ .assoc = "\x00\x00\x01\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x01",
+ .alen = 12,
+ .input = "\x29\xC9\xFC\x69\xA1\x97\xD0\x38"
+ "\xCC\xDD\x14\xE2\xDD\xFC\xAA\x05"
+ "\x43\x33\x21\x64\x41\x25\x03\x52"
+ "\x43\x03\xED\x3C\x6C\x5F\x28\x38"
+ "\x43\xAF\x8C\x3E",
+ .ilen = 36,
+ }, {
+ .key = "\x6C\x65\x67\x61\x6C\x69\x7A\x65"
+ "\x6D\x61\x72\x69\x6A\x75\x61\x6E"
+ "\x61\x61\x6E\x64\x64\x6F\x69\x74"
+ "\x62\x65\x66\x6F\x72\x65\x69\x61"
+ "\x74\x75\x72\x6E",
+ .klen = 36,
+ .iv = "\x33\x30\x21\x69\x67\x65\x74\x6D",
+ .result = "\x45\x00\x00\x30\xDA\x3A\x00\x00"
+ "\x80\x01\xDF\x3B\xC0\xA8\x00\x05"
+ "\xC0\xA8\x00\x01\x08\x00\xC6\xCD"
+ "\x02\x00\x07\x00\x61\x62\x63\x64"
+ "\x65\x66\x67\x68\x69\x6A\x6B\x6C"
+ "\x6D\x6E\x6F\x70\x71\x72\x73\x74"
+ "\x01\x02\x02\x01",
+ .rlen = 52,
+ .assoc = "\x79\x6B\x69\x63\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF",
+ .alen = 12,
+ .input = "\xF9\x7A\xB2\xAA\x35\x6D\x8E\xDC"
+ "\xE1\x76\x44\xAC\x8C\x78\xE2\x5D"
+ "\xD2\x4D\xED\xBB\x29\xEB\xF1\xB6"
+ "\x4A\x27\x4B\x39\xB4\x9C\x3A\x86"
+ "\x4C\xD3\xD7\x8C\xA4\xAE\x68\xA3"
+ "\x2B\x42\x45\x8F\xB5\x7D\xBE\x82"
+ "\x1D\xCC\x63\xB9\xD0\x93\x7B\xA2"
+ "\x94\x5F\x66\x93\x68\x66\x1A\x32"
+ "\x9F\xB4\xC0\x53",
+ .ilen = 68,
+ }, {
+ .key = "\x3D\xE0\x98\x74\xB3\x88\xE6\x49"
+ "\x19\x88\xD0\xC3\x60\x7E\xAE\x1F"
+ "\x57\x69\x0E\x43",
+ .klen = 20,
+ .iv = "\x4E\x28\x00\x00\xA2\xFC\xA1\xA3",
+ .result = "\x45\x00\x00\x30\xDA\x3A\x00\x00"
+ "\x80\x01\xDF\x3B\xC0\xA8\x00\x05"
+ "\xC0\xA8\x00\x01\x08\x00\xC6\xCD"
+ "\x02\x00\x07\x00\x61\x62\x63\x64"
+ "\x65\x66\x67\x68\x69\x6A\x6B\x6C"
+ "\x6D\x6E\x6F\x70\x71\x72\x73\x74"
+ "\x01\x02\x02\x01",
+ .rlen = 52,
+ .assoc = "\x3F\x7E\xF6\x42\x10\x10\x10\x10"
+ "\x10\x10\x10\x10",
+ .alen = 12,
+ .input = "\xFB\xA2\xCA\xA8\xC6\xC5\xF9\xF0"
+ "\xF2\x2C\xA5\x4A\x06\x12\x10\xAD"
+ "\x3F\x6E\x57\x91\xCF\x1A\xCA\x21"
+ "\x0D\x11\x7C\xEC\x9C\x35\x79\x17"
+ "\x65\xAC\xBD\x87\x01\xAD\x79\x84"
+ "\x5B\xF9\xFE\x3F\xBA\x48\x7B\xC9"
+ "\x63\x21\x93\x06\x84\xEE\xCA\xDB"
+ "\x56\x91\x25\x46\xE7\xA9\x5C\x97"
+ "\x40\xD7\xCB\x05",
+ .ilen = 68,
+ }, {
+ .key = "\x4C\x80\xCD\xEF\xBB\x5D\x10\xDA"
+ "\x90\x6A\xC7\x3C\x36\x13\xA6\x34"
+ "\x22\x43\x3C\x64",
+ .klen = 20,
+ .iv = "\x48\x55\xEC\x7D\x3A\x23\x4B\xFD",
+ .result = "\x08\x00\xC6\xCD\x02\x00\x07\x00"
+ "\x61\x62\x63\x64\x65\x66\x67\x68"
+ "\x69\x6A\x6B\x6C\x6D\x6E\x6F\x70"
+ "\x71\x72\x73\x74\x01\x02\x02\x01",
+ .rlen = 32,
+ .assoc = "\x00\x00\x43\x21\x87\x65\x43\x21"
+ "\x00\x00\x00\x07",
+ .alen = 12,
+ .input = "\x74\x75\x2E\x8A\xEB\x5D\x87\x3C"
+ "\xD7\xC0\xF4\xAC\xC3\x6C\x4B\xFF"
+ "\x84\xB7\xD7\xB9\x8F\x0C\xA8\xB6"
+ "\xAC\xDA\x68\x94\xBC\x61\x90\x69"
+ "\xEF\x9C\xBC\x28\xFE\x1B\x56\xA7"
+ "\xC4\xE0\xD5\x8C\x86\xCD\x2B\xC0",
+ .ilen = 48,
}
};
@@ -19975,8 +21328,9 @@ static struct aead_testvec aes_gcm_rfc4543_enc_tv_template[] = {
"\x22\x43\x3c\x64",
.klen = 20,
.iv = zeroed_string,
- .assoc = "\x00\x00\x43\x21\x00\x00\x00\x07",
- .alen = 8,
+ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x07"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .alen = 16,
.input = "\x45\x00\x00\x30\xda\x3a\x00\x00"
"\x80\x01\xdf\x3b\xc0\xa8\x00\x05"
"\xc0\xa8\x00\x01\x08\x00\xc6\xcd"
@@ -20005,8 +21359,9 @@ static struct aead_testvec aes_gcm_rfc4543_dec_tv_template[] = {
"\x22\x43\x3c\x64",
.klen = 20,
.iv = zeroed_string,
- .assoc = "\x00\x00\x43\x21\x00\x00\x00\x07",
- .alen = 8,
+ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x07"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .alen = 16,
.input = "\x45\x00\x00\x30\xda\x3a\x00\x00"
"\x80\x01\xdf\x3b\xc0\xa8\x00\x05"
"\xc0\xa8\x00\x01\x08\x00\xc6\xcd"
@@ -20031,8 +21386,9 @@ static struct aead_testvec aes_gcm_rfc4543_dec_tv_template[] = {
"\x22\x43\x3c\x64",
.klen = 20,
.iv = zeroed_string,
- .assoc = "\x00\x00\x43\x21\x00\x00\x00\x07",
- .alen = 8,
+ .assoc = "\x00\x00\x43\x21\x00\x00\x00\x07"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .alen = 16,
.input = "\x45\x00\x00\x30\xda\x3a\x00\x00"
"\x80\x01\xdf\x3b\xc0\xa8\x00\x05"
"\xc0\xa8\x00\x01\x08\x00\xc6\xcd"
@@ -20704,6 +22060,454 @@ static struct aead_testvec aes_ccm_rfc4309_dec_tv_template[] = {
};
/*
+ * ChaCha20-Poly1305 AEAD test vectors from RFC7539 2.8.2./A.5.
+ */
+#define RFC7539_ENC_TEST_VECTORS 2
+#define RFC7539_DEC_TEST_VECTORS 2
+static struct aead_testvec rfc7539_enc_tv_template[] = {
+ {
+ .key = "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
+ .klen = 32,
+ .iv = "\x07\x00\x00\x00\x40\x41\x42\x43"
+ "\x44\x45\x46\x47",
+ .assoc = "\x50\x51\x52\x53\xc0\xc1\xc2\xc3"
+ "\xc4\xc5\xc6\xc7",
+ .alen = 12,
+ .input = "\x4c\x61\x64\x69\x65\x73\x20\x61"
+ "\x6e\x64\x20\x47\x65\x6e\x74\x6c"
+ "\x65\x6d\x65\x6e\x20\x6f\x66\x20"
+ "\x74\x68\x65\x20\x63\x6c\x61\x73"
+ "\x73\x20\x6f\x66\x20\x27\x39\x39"
+ "\x3a\x20\x49\x66\x20\x49\x20\x63"
+ "\x6f\x75\x6c\x64\x20\x6f\x66\x66"
+ "\x65\x72\x20\x79\x6f\x75\x20\x6f"
+ "\x6e\x6c\x79\x20\x6f\x6e\x65\x20"
+ "\x74\x69\x70\x20\x66\x6f\x72\x20"
+ "\x74\x68\x65\x20\x66\x75\x74\x75"
+ "\x72\x65\x2c\x20\x73\x75\x6e\x73"
+ "\x63\x72\x65\x65\x6e\x20\x77\x6f"
+ "\x75\x6c\x64\x20\x62\x65\x20\x69"
+ "\x74\x2e",
+ .ilen = 114,
+ .result = "\xd3\x1a\x8d\x34\x64\x8e\x60\xdb"
+ "\x7b\x86\xaf\xbc\x53\xef\x7e\xc2"
+ "\xa4\xad\xed\x51\x29\x6e\x08\xfe"
+ "\xa9\xe2\xb5\xa7\x36\xee\x62\xd6"
+ "\x3d\xbe\xa4\x5e\x8c\xa9\x67\x12"
+ "\x82\xfa\xfb\x69\xda\x92\x72\x8b"
+ "\x1a\x71\xde\x0a\x9e\x06\x0b\x29"
+ "\x05\xd6\xa5\xb6\x7e\xcd\x3b\x36"
+ "\x92\xdd\xbd\x7f\x2d\x77\x8b\x8c"
+ "\x98\x03\xae\xe3\x28\x09\x1b\x58"
+ "\xfa\xb3\x24\xe4\xfa\xd6\x75\x94"
+ "\x55\x85\x80\x8b\x48\x31\xd7\xbc"
+ "\x3f\xf4\xde\xf0\x8e\x4b\x7a\x9d"
+ "\xe5\x76\xd2\x65\x86\xce\xc6\x4b"
+ "\x61\x16\x1a\xe1\x0b\x59\x4f\x09"
+ "\xe2\x6a\x7e\x90\x2e\xcb\xd0\x60"
+ "\x06\x91",
+ .rlen = 130,
+ }, {
+ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a"
+ "\xf3\x33\x88\x86\x04\xf6\xb5\xf0"
+ "\x47\x39\x17\xc1\x40\x2b\x80\x09"
+ "\x9d\xca\x5c\xbc\x20\x70\x75\xc0",
+ .klen = 32,
+ .iv = "\x00\x00\x00\x00\x01\x02\x03\x04"
+ "\x05\x06\x07\x08",
+ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00"
+ "\x00\x00\x4e\x91",
+ .alen = 12,
+ .input = "\x49\x6e\x74\x65\x72\x6e\x65\x74"
+ "\x2d\x44\x72\x61\x66\x74\x73\x20"
+ "\x61\x72\x65\x20\x64\x72\x61\x66"
+ "\x74\x20\x64\x6f\x63\x75\x6d\x65"
+ "\x6e\x74\x73\x20\x76\x61\x6c\x69"
+ "\x64\x20\x66\x6f\x72\x20\x61\x20"
+ "\x6d\x61\x78\x69\x6d\x75\x6d\x20"
+ "\x6f\x66\x20\x73\x69\x78\x20\x6d"
+ "\x6f\x6e\x74\x68\x73\x20\x61\x6e"
+ "\x64\x20\x6d\x61\x79\x20\x62\x65"
+ "\x20\x75\x70\x64\x61\x74\x65\x64"
+ "\x2c\x20\x72\x65\x70\x6c\x61\x63"
+ "\x65\x64\x2c\x20\x6f\x72\x20\x6f"
+ "\x62\x73\x6f\x6c\x65\x74\x65\x64"
+ "\x20\x62\x79\x20\x6f\x74\x68\x65"
+ "\x72\x20\x64\x6f\x63\x75\x6d\x65"
+ "\x6e\x74\x73\x20\x61\x74\x20\x61"
+ "\x6e\x79\x20\x74\x69\x6d\x65\x2e"
+ "\x20\x49\x74\x20\x69\x73\x20\x69"
+ "\x6e\x61\x70\x70\x72\x6f\x70\x72"
+ "\x69\x61\x74\x65\x20\x74\x6f\x20"
+ "\x75\x73\x65\x20\x49\x6e\x74\x65"
+ "\x72\x6e\x65\x74\x2d\x44\x72\x61"
+ "\x66\x74\x73\x20\x61\x73\x20\x72"
+ "\x65\x66\x65\x72\x65\x6e\x63\x65"
+ "\x20\x6d\x61\x74\x65\x72\x69\x61"
+ "\x6c\x20\x6f\x72\x20\x74\x6f\x20"
+ "\x63\x69\x74\x65\x20\x74\x68\x65"
+ "\x6d\x20\x6f\x74\x68\x65\x72\x20"
+ "\x74\x68\x61\x6e\x20\x61\x73\x20"
+ "\x2f\xe2\x80\x9c\x77\x6f\x72\x6b"
+ "\x20\x69\x6e\x20\x70\x72\x6f\x67"
+ "\x72\x65\x73\x73\x2e\x2f\xe2\x80"
+ "\x9d",
+ .ilen = 265,
+ .result = "\x64\xa0\x86\x15\x75\x86\x1a\xf4"
+ "\x60\xf0\x62\xc7\x9b\xe6\x43\xbd"
+ "\x5e\x80\x5c\xfd\x34\x5c\xf3\x89"
+ "\xf1\x08\x67\x0a\xc7\x6c\x8c\xb2"
+ "\x4c\x6c\xfc\x18\x75\x5d\x43\xee"
+ "\xa0\x9e\xe9\x4e\x38\x2d\x26\xb0"
+ "\xbd\xb7\xb7\x3c\x32\x1b\x01\x00"
+ "\xd4\xf0\x3b\x7f\x35\x58\x94\xcf"
+ "\x33\x2f\x83\x0e\x71\x0b\x97\xce"
+ "\x98\xc8\xa8\x4a\xbd\x0b\x94\x81"
+ "\x14\xad\x17\x6e\x00\x8d\x33\xbd"
+ "\x60\xf9\x82\xb1\xff\x37\xc8\x55"
+ "\x97\x97\xa0\x6e\xf4\xf0\xef\x61"
+ "\xc1\x86\x32\x4e\x2b\x35\x06\x38"
+ "\x36\x06\x90\x7b\x6a\x7c\x02\xb0"
+ "\xf9\xf6\x15\x7b\x53\xc8\x67\xe4"
+ "\xb9\x16\x6c\x76\x7b\x80\x4d\x46"
+ "\xa5\x9b\x52\x16\xcd\xe7\xa4\xe9"
+ "\x90\x40\xc5\xa4\x04\x33\x22\x5e"
+ "\xe2\x82\xa1\xb0\xa0\x6c\x52\x3e"
+ "\xaf\x45\x34\xd7\xf8\x3f\xa1\x15"
+ "\x5b\x00\x47\x71\x8c\xbc\x54\x6a"
+ "\x0d\x07\x2b\x04\xb3\x56\x4e\xea"
+ "\x1b\x42\x22\x73\xf5\x48\x27\x1a"
+ "\x0b\xb2\x31\x60\x53\xfa\x76\x99"
+ "\x19\x55\xeb\xd6\x31\x59\x43\x4e"
+ "\xce\xbb\x4e\x46\x6d\xae\x5a\x10"
+ "\x73\xa6\x72\x76\x27\x09\x7a\x10"
+ "\x49\xe6\x17\xd9\x1d\x36\x10\x94"
+ "\xfa\x68\xf0\xff\x77\x98\x71\x30"
+ "\x30\x5b\xea\xba\x2e\xda\x04\xdf"
+ "\x99\x7b\x71\x4d\x6c\x6f\x2c\x29"
+ "\xa6\xad\x5c\xb4\x02\x2b\x02\x70"
+ "\x9b\xee\xad\x9d\x67\x89\x0c\xbb"
+ "\x22\x39\x23\x36\xfe\xa1\x85\x1f"
+ "\x38",
+ .rlen = 281,
+ },
+};
+
+static struct aead_testvec rfc7539_dec_tv_template[] = {
+ {
+ .key = "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
+ .klen = 32,
+ .iv = "\x07\x00\x00\x00\x40\x41\x42\x43"
+ "\x44\x45\x46\x47",
+ .assoc = "\x50\x51\x52\x53\xc0\xc1\xc2\xc3"
+ "\xc4\xc5\xc6\xc7",
+ .alen = 12,
+ .input = "\xd3\x1a\x8d\x34\x64\x8e\x60\xdb"
+ "\x7b\x86\xaf\xbc\x53\xef\x7e\xc2"
+ "\xa4\xad\xed\x51\x29\x6e\x08\xfe"
+ "\xa9\xe2\xb5\xa7\x36\xee\x62\xd6"
+ "\x3d\xbe\xa4\x5e\x8c\xa9\x67\x12"
+ "\x82\xfa\xfb\x69\xda\x92\x72\x8b"
+ "\x1a\x71\xde\x0a\x9e\x06\x0b\x29"
+ "\x05\xd6\xa5\xb6\x7e\xcd\x3b\x36"
+ "\x92\xdd\xbd\x7f\x2d\x77\x8b\x8c"
+ "\x98\x03\xae\xe3\x28\x09\x1b\x58"
+ "\xfa\xb3\x24\xe4\xfa\xd6\x75\x94"
+ "\x55\x85\x80\x8b\x48\x31\xd7\xbc"
+ "\x3f\xf4\xde\xf0\x8e\x4b\x7a\x9d"
+ "\xe5\x76\xd2\x65\x86\xce\xc6\x4b"
+ "\x61\x16\x1a\xe1\x0b\x59\x4f\x09"
+ "\xe2\x6a\x7e\x90\x2e\xcb\xd0\x60"
+ "\x06\x91",
+ .ilen = 130,
+ .result = "\x4c\x61\x64\x69\x65\x73\x20\x61"
+ "\x6e\x64\x20\x47\x65\x6e\x74\x6c"
+ "\x65\x6d\x65\x6e\x20\x6f\x66\x20"
+ "\x74\x68\x65\x20\x63\x6c\x61\x73"
+ "\x73\x20\x6f\x66\x20\x27\x39\x39"
+ "\x3a\x20\x49\x66\x20\x49\x20\x63"
+ "\x6f\x75\x6c\x64\x20\x6f\x66\x66"
+ "\x65\x72\x20\x79\x6f\x75\x20\x6f"
+ "\x6e\x6c\x79\x20\x6f\x6e\x65\x20"
+ "\x74\x69\x70\x20\x66\x6f\x72\x20"
+ "\x74\x68\x65\x20\x66\x75\x74\x75"
+ "\x72\x65\x2c\x20\x73\x75\x6e\x73"
+ "\x63\x72\x65\x65\x6e\x20\x77\x6f"
+ "\x75\x6c\x64\x20\x62\x65\x20\x69"
+ "\x74\x2e",
+ .rlen = 114,
+ }, {
+ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a"
+ "\xf3\x33\x88\x86\x04\xf6\xb5\xf0"
+ "\x47\x39\x17\xc1\x40\x2b\x80\x09"
+ "\x9d\xca\x5c\xbc\x20\x70\x75\xc0",
+ .klen = 32,
+ .iv = "\x00\x00\x00\x00\x01\x02\x03\x04"
+ "\x05\x06\x07\x08",
+ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00"
+ "\x00\x00\x4e\x91",
+ .alen = 12,
+ .input = "\x64\xa0\x86\x15\x75\x86\x1a\xf4"
+ "\x60\xf0\x62\xc7\x9b\xe6\x43\xbd"
+ "\x5e\x80\x5c\xfd\x34\x5c\xf3\x89"
+ "\xf1\x08\x67\x0a\xc7\x6c\x8c\xb2"
+ "\x4c\x6c\xfc\x18\x75\x5d\x43\xee"
+ "\xa0\x9e\xe9\x4e\x38\x2d\x26\xb0"
+ "\xbd\xb7\xb7\x3c\x32\x1b\x01\x00"
+ "\xd4\xf0\x3b\x7f\x35\x58\x94\xcf"
+ "\x33\x2f\x83\x0e\x71\x0b\x97\xce"
+ "\x98\xc8\xa8\x4a\xbd\x0b\x94\x81"
+ "\x14\xad\x17\x6e\x00\x8d\x33\xbd"
+ "\x60\xf9\x82\xb1\xff\x37\xc8\x55"
+ "\x97\x97\xa0\x6e\xf4\xf0\xef\x61"
+ "\xc1\x86\x32\x4e\x2b\x35\x06\x38"
+ "\x36\x06\x90\x7b\x6a\x7c\x02\xb0"
+ "\xf9\xf6\x15\x7b\x53\xc8\x67\xe4"
+ "\xb9\x16\x6c\x76\x7b\x80\x4d\x46"
+ "\xa5\x9b\x52\x16\xcd\xe7\xa4\xe9"
+ "\x90\x40\xc5\xa4\x04\x33\x22\x5e"
+ "\xe2\x82\xa1\xb0\xa0\x6c\x52\x3e"
+ "\xaf\x45\x34\xd7\xf8\x3f\xa1\x15"
+ "\x5b\x00\x47\x71\x8c\xbc\x54\x6a"
+ "\x0d\x07\x2b\x04\xb3\x56\x4e\xea"
+ "\x1b\x42\x22\x73\xf5\x48\x27\x1a"
+ "\x0b\xb2\x31\x60\x53\xfa\x76\x99"
+ "\x19\x55\xeb\xd6\x31\x59\x43\x4e"
+ "\xce\xbb\x4e\x46\x6d\xae\x5a\x10"
+ "\x73\xa6\x72\x76\x27\x09\x7a\x10"
+ "\x49\xe6\x17\xd9\x1d\x36\x10\x94"
+ "\xfa\x68\xf0\xff\x77\x98\x71\x30"
+ "\x30\x5b\xea\xba\x2e\xda\x04\xdf"
+ "\x99\x7b\x71\x4d\x6c\x6f\x2c\x29"
+ "\xa6\xad\x5c\xb4\x02\x2b\x02\x70"
+ "\x9b\xee\xad\x9d\x67\x89\x0c\xbb"
+ "\x22\x39\x23\x36\xfe\xa1\x85\x1f"
+ "\x38",
+ .ilen = 281,
+ .result = "\x49\x6e\x74\x65\x72\x6e\x65\x74"
+ "\x2d\x44\x72\x61\x66\x74\x73\x20"
+ "\x61\x72\x65\x20\x64\x72\x61\x66"
+ "\x74\x20\x64\x6f\x63\x75\x6d\x65"
+ "\x6e\x74\x73\x20\x76\x61\x6c\x69"
+ "\x64\x20\x66\x6f\x72\x20\x61\x20"
+ "\x6d\x61\x78\x69\x6d\x75\x6d\x20"
+ "\x6f\x66\x20\x73\x69\x78\x20\x6d"
+ "\x6f\x6e\x74\x68\x73\x20\x61\x6e"
+ "\x64\x20\x6d\x61\x79\x20\x62\x65"
+ "\x20\x75\x70\x64\x61\x74\x65\x64"
+ "\x2c\x20\x72\x65\x70\x6c\x61\x63"
+ "\x65\x64\x2c\x20\x6f\x72\x20\x6f"
+ "\x62\x73\x6f\x6c\x65\x74\x65\x64"
+ "\x20\x62\x79\x20\x6f\x74\x68\x65"
+ "\x72\x20\x64\x6f\x63\x75\x6d\x65"
+ "\x6e\x74\x73\x20\x61\x74\x20\x61"
+ "\x6e\x79\x20\x74\x69\x6d\x65\x2e"
+ "\x20\x49\x74\x20\x69\x73\x20\x69"
+ "\x6e\x61\x70\x70\x72\x6f\x70\x72"
+ "\x69\x61\x74\x65\x20\x74\x6f\x20"
+ "\x75\x73\x65\x20\x49\x6e\x74\x65"
+ "\x72\x6e\x65\x74\x2d\x44\x72\x61"
+ "\x66\x74\x73\x20\x61\x73\x20\x72"
+ "\x65\x66\x65\x72\x65\x6e\x63\x65"
+ "\x20\x6d\x61\x74\x65\x72\x69\x61"
+ "\x6c\x20\x6f\x72\x20\x74\x6f\x20"
+ "\x63\x69\x74\x65\x20\x74\x68\x65"
+ "\x6d\x20\x6f\x74\x68\x65\x72\x20"
+ "\x74\x68\x61\x6e\x20\x61\x73\x20"
+ "\x2f\xe2\x80\x9c\x77\x6f\x72\x6b"
+ "\x20\x69\x6e\x20\x70\x72\x6f\x67"
+ "\x72\x65\x73\x73\x2e\x2f\xe2\x80"
+ "\x9d",
+ .rlen = 265,
+ },
+};
+
+/*
+ * draft-irtf-cfrg-chacha20-poly1305
+ */
+#define RFC7539ESP_DEC_TEST_VECTORS 1
+#define RFC7539ESP_ENC_TEST_VECTORS 1
+static struct aead_testvec rfc7539esp_enc_tv_template[] = {
+ {
+ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a"
+ "\xf3\x33\x88\x86\x04\xf6\xb5\xf0"
+ "\x47\x39\x17\xc1\x40\x2b\x80\x09"
+ "\x9d\xca\x5c\xbc\x20\x70\x75\xc0"
+ "\x00\x00\x00\x00",
+ .klen = 36,
+ .iv = "\x01\x02\x03\x04\x05\x06\x07\x08",
+ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00"
+ "\x00\x00\x4e\x91",
+ .alen = 12,
+ .input = "\x49\x6e\x74\x65\x72\x6e\x65\x74"
+ "\x2d\x44\x72\x61\x66\x74\x73\x20"
+ "\x61\x72\x65\x20\x64\x72\x61\x66"
+ "\x74\x20\x64\x6f\x63\x75\x6d\x65"
+ "\x6e\x74\x73\x20\x76\x61\x6c\x69"
+ "\x64\x20\x66\x6f\x72\x20\x61\x20"
+ "\x6d\x61\x78\x69\x6d\x75\x6d\x20"
+ "\x6f\x66\x20\x73\x69\x78\x20\x6d"
+ "\x6f\x6e\x74\x68\x73\x20\x61\x6e"
+ "\x64\x20\x6d\x61\x79\x20\x62\x65"
+ "\x20\x75\x70\x64\x61\x74\x65\x64"
+ "\x2c\x20\x72\x65\x70\x6c\x61\x63"
+ "\x65\x64\x2c\x20\x6f\x72\x20\x6f"
+ "\x62\x73\x6f\x6c\x65\x74\x65\x64"
+ "\x20\x62\x79\x20\x6f\x74\x68\x65"
+ "\x72\x20\x64\x6f\x63\x75\x6d\x65"
+ "\x6e\x74\x73\x20\x61\x74\x20\x61"
+ "\x6e\x79\x20\x74\x69\x6d\x65\x2e"
+ "\x20\x49\x74\x20\x69\x73\x20\x69"
+ "\x6e\x61\x70\x70\x72\x6f\x70\x72"
+ "\x69\x61\x74\x65\x20\x74\x6f\x20"
+ "\x75\x73\x65\x20\x49\x6e\x74\x65"
+ "\x72\x6e\x65\x74\x2d\x44\x72\x61"
+ "\x66\x74\x73\x20\x61\x73\x20\x72"
+ "\x65\x66\x65\x72\x65\x6e\x63\x65"
+ "\x20\x6d\x61\x74\x65\x72\x69\x61"
+ "\x6c\x20\x6f\x72\x20\x74\x6f\x20"
+ "\x63\x69\x74\x65\x20\x74\x68\x65"
+ "\x6d\x20\x6f\x74\x68\x65\x72\x20"
+ "\x74\x68\x61\x6e\x20\x61\x73\x20"
+ "\x2f\xe2\x80\x9c\x77\x6f\x72\x6b"
+ "\x20\x69\x6e\x20\x70\x72\x6f\x67"
+ "\x72\x65\x73\x73\x2e\x2f\xe2\x80"
+ "\x9d",
+ .ilen = 265,
+ .result = "\x64\xa0\x86\x15\x75\x86\x1a\xf4"
+ "\x60\xf0\x62\xc7\x9b\xe6\x43\xbd"
+ "\x5e\x80\x5c\xfd\x34\x5c\xf3\x89"
+ "\xf1\x08\x67\x0a\xc7\x6c\x8c\xb2"
+ "\x4c\x6c\xfc\x18\x75\x5d\x43\xee"
+ "\xa0\x9e\xe9\x4e\x38\x2d\x26\xb0"
+ "\xbd\xb7\xb7\x3c\x32\x1b\x01\x00"
+ "\xd4\xf0\x3b\x7f\x35\x58\x94\xcf"
+ "\x33\x2f\x83\x0e\x71\x0b\x97\xce"
+ "\x98\xc8\xa8\x4a\xbd\x0b\x94\x81"
+ "\x14\xad\x17\x6e\x00\x8d\x33\xbd"
+ "\x60\xf9\x82\xb1\xff\x37\xc8\x55"
+ "\x97\x97\xa0\x6e\xf4\xf0\xef\x61"
+ "\xc1\x86\x32\x4e\x2b\x35\x06\x38"
+ "\x36\x06\x90\x7b\x6a\x7c\x02\xb0"
+ "\xf9\xf6\x15\x7b\x53\xc8\x67\xe4"
+ "\xb9\x16\x6c\x76\x7b\x80\x4d\x46"
+ "\xa5\x9b\x52\x16\xcd\xe7\xa4\xe9"
+ "\x90\x40\xc5\xa4\x04\x33\x22\x5e"
+ "\xe2\x82\xa1\xb0\xa0\x6c\x52\x3e"
+ "\xaf\x45\x34\xd7\xf8\x3f\xa1\x15"
+ "\x5b\x00\x47\x71\x8c\xbc\x54\x6a"
+ "\x0d\x07\x2b\x04\xb3\x56\x4e\xea"
+ "\x1b\x42\x22\x73\xf5\x48\x27\x1a"
+ "\x0b\xb2\x31\x60\x53\xfa\x76\x99"
+ "\x19\x55\xeb\xd6\x31\x59\x43\x4e"
+ "\xce\xbb\x4e\x46\x6d\xae\x5a\x10"
+ "\x73\xa6\x72\x76\x27\x09\x7a\x10"
+ "\x49\xe6\x17\xd9\x1d\x36\x10\x94"
+ "\xfa\x68\xf0\xff\x77\x98\x71\x30"
+ "\x30\x5b\xea\xba\x2e\xda\x04\xdf"
+ "\x99\x7b\x71\x4d\x6c\x6f\x2c\x29"
+ "\xa6\xad\x5c\xb4\x02\x2b\x02\x70"
+ "\x9b\xee\xad\x9d\x67\x89\x0c\xbb"
+ "\x22\x39\x23\x36\xfe\xa1\x85\x1f"
+ "\x38",
+ .rlen = 281,
+ },
+};
+
+static struct aead_testvec rfc7539esp_dec_tv_template[] = {
+ {
+ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a"
+ "\xf3\x33\x88\x86\x04\xf6\xb5\xf0"
+ "\x47\x39\x17\xc1\x40\x2b\x80\x09"
+ "\x9d\xca\x5c\xbc\x20\x70\x75\xc0"
+ "\x00\x00\x00\x00",
+ .klen = 36,
+ .iv = "\x01\x02\x03\x04\x05\x06\x07\x08",
+ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00"
+ "\x00\x00\x4e\x91",
+ .alen = 12,
+ .input = "\x64\xa0\x86\x15\x75\x86\x1a\xf4"
+ "\x60\xf0\x62\xc7\x9b\xe6\x43\xbd"
+ "\x5e\x80\x5c\xfd\x34\x5c\xf3\x89"
+ "\xf1\x08\x67\x0a\xc7\x6c\x8c\xb2"
+ "\x4c\x6c\xfc\x18\x75\x5d\x43\xee"
+ "\xa0\x9e\xe9\x4e\x38\x2d\x26\xb0"
+ "\xbd\xb7\xb7\x3c\x32\x1b\x01\x00"
+ "\xd4\xf0\x3b\x7f\x35\x58\x94\xcf"
+ "\x33\x2f\x83\x0e\x71\x0b\x97\xce"
+ "\x98\xc8\xa8\x4a\xbd\x0b\x94\x81"
+ "\x14\xad\x17\x6e\x00\x8d\x33\xbd"
+ "\x60\xf9\x82\xb1\xff\x37\xc8\x55"
+ "\x97\x97\xa0\x6e\xf4\xf0\xef\x61"
+ "\xc1\x86\x32\x4e\x2b\x35\x06\x38"
+ "\x36\x06\x90\x7b\x6a\x7c\x02\xb0"
+ "\xf9\xf6\x15\x7b\x53\xc8\x67\xe4"
+ "\xb9\x16\x6c\x76\x7b\x80\x4d\x46"
+ "\xa5\x9b\x52\x16\xcd\xe7\xa4\xe9"
+ "\x90\x40\xc5\xa4\x04\x33\x22\x5e"
+ "\xe2\x82\xa1\xb0\xa0\x6c\x52\x3e"
+ "\xaf\x45\x34\xd7\xf8\x3f\xa1\x15"
+ "\x5b\x00\x47\x71\x8c\xbc\x54\x6a"
+ "\x0d\x07\x2b\x04\xb3\x56\x4e\xea"
+ "\x1b\x42\x22\x73\xf5\x48\x27\x1a"
+ "\x0b\xb2\x31\x60\x53\xfa\x76\x99"
+ "\x19\x55\xeb\xd6\x31\x59\x43\x4e"
+ "\xce\xbb\x4e\x46\x6d\xae\x5a\x10"
+ "\x73\xa6\x72\x76\x27\x09\x7a\x10"
+ "\x49\xe6\x17\xd9\x1d\x36\x10\x94"
+ "\xfa\x68\xf0\xff\x77\x98\x71\x30"
+ "\x30\x5b\xea\xba\x2e\xda\x04\xdf"
+ "\x99\x7b\x71\x4d\x6c\x6f\x2c\x29"
+ "\xa6\xad\x5c\xb4\x02\x2b\x02\x70"
+ "\x9b\xee\xad\x9d\x67\x89\x0c\xbb"
+ "\x22\x39\x23\x36\xfe\xa1\x85\x1f"
+ "\x38",
+ .ilen = 281,
+ .result = "\x49\x6e\x74\x65\x72\x6e\x65\x74"
+ "\x2d\x44\x72\x61\x66\x74\x73\x20"
+ "\x61\x72\x65\x20\x64\x72\x61\x66"
+ "\x74\x20\x64\x6f\x63\x75\x6d\x65"
+ "\x6e\x74\x73\x20\x76\x61\x6c\x69"
+ "\x64\x20\x66\x6f\x72\x20\x61\x20"
+ "\x6d\x61\x78\x69\x6d\x75\x6d\x20"
+ "\x6f\x66\x20\x73\x69\x78\x20\x6d"
+ "\x6f\x6e\x74\x68\x73\x20\x61\x6e"
+ "\x64\x20\x6d\x61\x79\x20\x62\x65"
+ "\x20\x75\x70\x64\x61\x74\x65\x64"
+ "\x2c\x20\x72\x65\x70\x6c\x61\x63"
+ "\x65\x64\x2c\x20\x6f\x72\x20\x6f"
+ "\x62\x73\x6f\x6c\x65\x74\x65\x64"
+ "\x20\x62\x79\x20\x6f\x74\x68\x65"
+ "\x72\x20\x64\x6f\x63\x75\x6d\x65"
+ "\x6e\x74\x73\x20\x61\x74\x20\x61"
+ "\x6e\x79\x20\x74\x69\x6d\x65\x2e"
+ "\x20\x49\x74\x20\x69\x73\x20\x69"
+ "\x6e\x61\x70\x70\x72\x6f\x70\x72"
+ "\x69\x61\x74\x65\x20\x74\x6f\x20"
+ "\x75\x73\x65\x20\x49\x6e\x74\x65"
+ "\x72\x6e\x65\x74\x2d\x44\x72\x61"
+ "\x66\x74\x73\x20\x61\x73\x20\x72"
+ "\x65\x66\x65\x72\x65\x6e\x63\x65"
+ "\x20\x6d\x61\x74\x65\x72\x69\x61"
+ "\x6c\x20\x6f\x72\x20\x74\x6f\x20"
+ "\x63\x69\x74\x65\x20\x74\x68\x65"
+ "\x6d\x20\x6f\x74\x68\x65\x72\x20"
+ "\x74\x68\x61\x6e\x20\x61\x73\x20"
+ "\x2f\xe2\x80\x9c\x77\x6f\x72\x6b"
+ "\x20\x69\x6e\x20\x70\x72\x6f\x67"
+ "\x72\x65\x73\x73\x2e\x2f\xe2\x80"
+ "\x9d",
+ .rlen = 265,
+ },
+};
+
+/*
* ANSI X9.31 Continuous Pseudo-Random Number Generator (AES mode)
* test vectors, taken from Appendix B.2.9 and B.2.10:
* http://csrc.nist.gov/groups/STM/cavp/documents/rng/RNGVS.pdf
@@ -28370,6 +30174,183 @@ static struct cipher_testvec salsa20_stream_enc_tv_template[] = {
},
};
+#define CHACHA20_ENC_TEST_VECTORS 3
+static struct cipher_testvec chacha20_enc_tv_template[] = {
+ { /* RFC7539 A.2. Test Vector #1 */
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 32,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .ilen = 64,
+ .result = "\x76\xb8\xe0\xad\xa0\xf1\x3d\x90"
+ "\x40\x5d\x6a\xe5\x53\x86\xbd\x28"
+ "\xbd\xd2\x19\xb8\xa0\x8d\xed\x1a"
+ "\xa8\x36\xef\xcc\x8b\x77\x0d\xc7"
+ "\xda\x41\x59\x7c\x51\x57\x48\x8d"
+ "\x77\x24\xe0\x3f\xb8\xd8\x4a\x37"
+ "\x6a\x43\xb8\xf4\x15\x18\xa1\x1c"
+ "\xc3\x87\xb6\x69\xb2\xee\x65\x86",
+ .rlen = 64,
+ }, { /* RFC7539 A.2. Test Vector #2 */
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x01",
+ .klen = 32,
+ .iv = "\x01\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x02",
+ .input = "\x41\x6e\x79\x20\x73\x75\x62\x6d"
+ "\x69\x73\x73\x69\x6f\x6e\x20\x74"
+ "\x6f\x20\x74\x68\x65\x20\x49\x45"
+ "\x54\x46\x20\x69\x6e\x74\x65\x6e"
+ "\x64\x65\x64\x20\x62\x79\x20\x74"
+ "\x68\x65\x20\x43\x6f\x6e\x74\x72"
+ "\x69\x62\x75\x74\x6f\x72\x20\x66"
+ "\x6f\x72\x20\x70\x75\x62\x6c\x69"
+ "\x63\x61\x74\x69\x6f\x6e\x20\x61"
+ "\x73\x20\x61\x6c\x6c\x20\x6f\x72"
+ "\x20\x70\x61\x72\x74\x20\x6f\x66"
+ "\x20\x61\x6e\x20\x49\x45\x54\x46"
+ "\x20\x49\x6e\x74\x65\x72\x6e\x65"
+ "\x74\x2d\x44\x72\x61\x66\x74\x20"
+ "\x6f\x72\x20\x52\x46\x43\x20\x61"
+ "\x6e\x64\x20\x61\x6e\x79\x20\x73"
+ "\x74\x61\x74\x65\x6d\x65\x6e\x74"
+ "\x20\x6d\x61\x64\x65\x20\x77\x69"
+ "\x74\x68\x69\x6e\x20\x74\x68\x65"
+ "\x20\x63\x6f\x6e\x74\x65\x78\x74"
+ "\x20\x6f\x66\x20\x61\x6e\x20\x49"
+ "\x45\x54\x46\x20\x61\x63\x74\x69"
+ "\x76\x69\x74\x79\x20\x69\x73\x20"
+ "\x63\x6f\x6e\x73\x69\x64\x65\x72"
+ "\x65\x64\x20\x61\x6e\x20\x22\x49"
+ "\x45\x54\x46\x20\x43\x6f\x6e\x74"
+ "\x72\x69\x62\x75\x74\x69\x6f\x6e"
+ "\x22\x2e\x20\x53\x75\x63\x68\x20"
+ "\x73\x74\x61\x74\x65\x6d\x65\x6e"
+ "\x74\x73\x20\x69\x6e\x63\x6c\x75"
+ "\x64\x65\x20\x6f\x72\x61\x6c\x20"
+ "\x73\x74\x61\x74\x65\x6d\x65\x6e"
+ "\x74\x73\x20\x69\x6e\x20\x49\x45"
+ "\x54\x46\x20\x73\x65\x73\x73\x69"
+ "\x6f\x6e\x73\x2c\x20\x61\x73\x20"
+ "\x77\x65\x6c\x6c\x20\x61\x73\x20"
+ "\x77\x72\x69\x74\x74\x65\x6e\x20"
+ "\x61\x6e\x64\x20\x65\x6c\x65\x63"
+ "\x74\x72\x6f\x6e\x69\x63\x20\x63"
+ "\x6f\x6d\x6d\x75\x6e\x69\x63\x61"
+ "\x74\x69\x6f\x6e\x73\x20\x6d\x61"
+ "\x64\x65\x20\x61\x74\x20\x61\x6e"
+ "\x79\x20\x74\x69\x6d\x65\x20\x6f"
+ "\x72\x20\x70\x6c\x61\x63\x65\x2c"
+ "\x20\x77\x68\x69\x63\x68\x20\x61"
+ "\x72\x65\x20\x61\x64\x64\x72\x65"
+ "\x73\x73\x65\x64\x20\x74\x6f",
+ .ilen = 375,
+ .result = "\xa3\xfb\xf0\x7d\xf3\xfa\x2f\xde"
+ "\x4f\x37\x6c\xa2\x3e\x82\x73\x70"
+ "\x41\x60\x5d\x9f\x4f\x4f\x57\xbd"
+ "\x8c\xff\x2c\x1d\x4b\x79\x55\xec"
+ "\x2a\x97\x94\x8b\xd3\x72\x29\x15"
+ "\xc8\xf3\xd3\x37\xf7\xd3\x70\x05"
+ "\x0e\x9e\x96\xd6\x47\xb7\xc3\x9f"
+ "\x56\xe0\x31\xca\x5e\xb6\x25\x0d"
+ "\x40\x42\xe0\x27\x85\xec\xec\xfa"
+ "\x4b\x4b\xb5\xe8\xea\xd0\x44\x0e"
+ "\x20\xb6\xe8\xdb\x09\xd8\x81\xa7"
+ "\xc6\x13\x2f\x42\x0e\x52\x79\x50"
+ "\x42\xbd\xfa\x77\x73\xd8\xa9\x05"
+ "\x14\x47\xb3\x29\x1c\xe1\x41\x1c"
+ "\x68\x04\x65\x55\x2a\xa6\xc4\x05"
+ "\xb7\x76\x4d\x5e\x87\xbe\xa8\x5a"
+ "\xd0\x0f\x84\x49\xed\x8f\x72\xd0"
+ "\xd6\x62\xab\x05\x26\x91\xca\x66"
+ "\x42\x4b\xc8\x6d\x2d\xf8\x0e\xa4"
+ "\x1f\x43\xab\xf9\x37\xd3\x25\x9d"
+ "\xc4\xb2\xd0\xdf\xb4\x8a\x6c\x91"
+ "\x39\xdd\xd7\xf7\x69\x66\xe9\x28"
+ "\xe6\x35\x55\x3b\xa7\x6c\x5c\x87"
+ "\x9d\x7b\x35\xd4\x9e\xb2\xe6\x2b"
+ "\x08\x71\xcd\xac\x63\x89\x39\xe2"
+ "\x5e\x8a\x1e\x0e\xf9\xd5\x28\x0f"
+ "\xa8\xca\x32\x8b\x35\x1c\x3c\x76"
+ "\x59\x89\xcb\xcf\x3d\xaa\x8b\x6c"
+ "\xcc\x3a\xaf\x9f\x39\x79\xc9\x2b"
+ "\x37\x20\xfc\x88\xdc\x95\xed\x84"
+ "\xa1\xbe\x05\x9c\x64\x99\xb9\xfd"
+ "\xa2\x36\xe7\xe8\x18\xb0\x4b\x0b"
+ "\xc3\x9c\x1e\x87\x6b\x19\x3b\xfe"
+ "\x55\x69\x75\x3f\x88\x12\x8c\xc0"
+ "\x8a\xaa\x9b\x63\xd1\xa1\x6f\x80"
+ "\xef\x25\x54\xd7\x18\x9c\x41\x1f"
+ "\x58\x69\xca\x52\xc5\xb8\x3f\xa3"
+ "\x6f\xf2\x16\xb9\xc1\xd3\x00\x62"
+ "\xbe\xbc\xfd\x2d\xc5\xbc\xe0\x91"
+ "\x19\x34\xfd\xa7\x9a\x86\xf6\xe6"
+ "\x98\xce\xd7\x59\xc3\xff\x9b\x64"
+ "\x77\x33\x8f\x3d\xa4\xf9\xcd\x85"
+ "\x14\xea\x99\x82\xcc\xaf\xb3\x41"
+ "\xb2\x38\x4d\xd9\x02\xf3\xd1\xab"
+ "\x7a\xc6\x1d\xd2\x9c\x6f\x21\xba"
+ "\x5b\x86\x2f\x37\x30\xe3\x7c\xfd"
+ "\xc4\xfd\x80\x6c\x22\xf2\x21",
+ .rlen = 375,
+ }, { /* RFC7539 A.2. Test Vector #3 */
+ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a"
+ "\xf3\x33\x88\x86\x04\xf6\xb5\xf0"
+ "\x47\x39\x17\xc1\x40\x2b\x80\x09"
+ "\x9d\xca\x5c\xbc\x20\x70\x75\xc0",
+ .klen = 32,
+ .iv = "\x2a\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x02",
+ .input = "\x27\x54\x77\x61\x73\x20\x62\x72"
+ "\x69\x6c\x6c\x69\x67\x2c\x20\x61"
+ "\x6e\x64\x20\x74\x68\x65\x20\x73"
+ "\x6c\x69\x74\x68\x79\x20\x74\x6f"
+ "\x76\x65\x73\x0a\x44\x69\x64\x20"
+ "\x67\x79\x72\x65\x20\x61\x6e\x64"
+ "\x20\x67\x69\x6d\x62\x6c\x65\x20"
+ "\x69\x6e\x20\x74\x68\x65\x20\x77"
+ "\x61\x62\x65\x3a\x0a\x41\x6c\x6c"
+ "\x20\x6d\x69\x6d\x73\x79\x20\x77"
+ "\x65\x72\x65\x20\x74\x68\x65\x20"
+ "\x62\x6f\x72\x6f\x67\x6f\x76\x65"
+ "\x73\x2c\x0a\x41\x6e\x64\x20\x74"
+ "\x68\x65\x20\x6d\x6f\x6d\x65\x20"
+ "\x72\x61\x74\x68\x73\x20\x6f\x75"
+ "\x74\x67\x72\x61\x62\x65\x2e",
+ .ilen = 127,
+ .result = "\x62\xe6\x34\x7f\x95\xed\x87\xa4"
+ "\x5f\xfa\xe7\x42\x6f\x27\xa1\xdf"
+ "\x5f\xb6\x91\x10\x04\x4c\x0d\x73"
+ "\x11\x8e\xff\xa9\x5b\x01\xe5\xcf"
+ "\x16\x6d\x3d\xf2\xd7\x21\xca\xf9"
+ "\xb2\x1e\x5f\xb1\x4c\x61\x68\x71"
+ "\xfd\x84\xc5\x4f\x9d\x65\xb2\x83"
+ "\x19\x6c\x7f\xe4\xf6\x05\x53\xeb"
+ "\xf3\x9c\x64\x02\xc4\x22\x34\xe3"
+ "\x2a\x35\x6b\x3e\x76\x43\x12\xa6"
+ "\x1a\x55\x32\x05\x57\x16\xea\xd6"
+ "\x96\x25\x68\xf8\x7d\x3f\x3f\x77"
+ "\x04\xc6\xa8\xd1\xbc\xd1\xbf\x4d"
+ "\x50\xd6\x15\x4b\x6d\xa7\x31\xb1"
+ "\x87\xb5\x8d\xfd\x72\x8a\xfa\x36"
+ "\x75\x7a\x79\x7a\xc1\x88\xd1",
+ .rlen = 127,
+ },
+};
+
/*
* CTS (Cipher Text Stealing) mode tests
*/
@@ -28591,7 +30572,7 @@ struct comp_testvec {
};
struct pcomp_testvec {
- void *params;
+ const void *params;
unsigned int paramsize;
int inlen, outlen;
char input[COMP_BUF_SIZE];
@@ -28946,6 +30927,440 @@ static struct hash_testvec michael_mic_tv_template[] = {
};
/*
+ * CRC32 test vectors
+ */
+#define CRC32_TEST_VECTORS 14
+
+static struct hash_testvec crc32_tv_template[] = {
+ {
+ .key = "\x87\xa9\xcb\xed",
+ .ksize = 4,
+ .psize = 0,
+ .digest = "\x87\xa9\xcb\xed",
+ },
+ {
+ .key = "\xff\xff\xff\xff",
+ .ksize = 4,
+ .plaintext = "\x01\x02\x03\x04\x05\x06\x07\x08"
+ "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+ "\x11\x12\x13\x14\x15\x16\x17\x18"
+ "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
+ "\x21\x22\x23\x24\x25\x26\x27\x28",
+ .psize = 40,
+ .digest = "\x3a\xdf\x4b\xb0",
+ },
+ {
+ .key = "\xff\xff\xff\xff",
+ .ksize = 4,
+ .plaintext = "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
+ "\x31\x32\x33\x34\x35\x36\x37\x38"
+ "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
+ "\x41\x42\x43\x44\x45\x46\x47\x48"
+ "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50",
+ .psize = 40,
+ .digest = "\xa9\x7a\x7f\x7b",
+ },
+ {
+ .key = "\xff\xff\xff\xff",
+ .ksize = 4,
+ .plaintext = "\x51\x52\x53\x54\x55\x56\x57\x58"
+ "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
+ "\x61\x62\x63\x64\x65\x66\x67\x68"
+ "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+ "\x71\x72\x73\x74\x75\x76\x77\x78",
+ .psize = 40,
+ .digest = "\xba\xd3\xf8\x1c",
+ },
+ {
+ .key = "\xff\xff\xff\xff",
+ .ksize = 4,
+ .plaintext = "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
+ "\x81\x82\x83\x84\x85\x86\x87\x88"
+ "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
+ "\x91\x92\x93\x94\x95\x96\x97\x98"
+ "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0",
+ .psize = 40,
+ .digest = "\xa8\xa9\xc2\x02",
+ },
+ {
+ .key = "\xff\xff\xff\xff",
+ .ksize = 4,
+ .plaintext = "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
+ "\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
+ "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8"
+ "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
+ "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8",
+ .psize = 40,
+ .digest = "\x27\xf0\x57\xe2",
+ },
+ {
+ .key = "\xff\xff\xff\xff",
+ .ksize = 4,
+ .plaintext = "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
+ "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8"
+ "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
+ "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
+ "\xe9\xea\xeb\xec\xed\xee\xef\xf0",
+ .psize = 40,
+ .digest = "\x49\x78\x10\x08",
+ },
+ {
+ .key = "\x80\xea\xd3\xf1",
+ .ksize = 4,
+ .plaintext = "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
+ "\x31\x32\x33\x34\x35\x36\x37\x38"
+ "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
+ "\x41\x42\x43\x44\x45\x46\x47\x48"
+ "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50",
+ .psize = 40,
+ .digest = "\x9a\xb1\xdc\xf0",
+ },
+ {
+ .key = "\xf3\x4a\x1d\x5d",
+ .ksize = 4,
+ .plaintext = "\x51\x52\x53\x54\x55\x56\x57\x58"
+ "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
+ "\x61\x62\x63\x64\x65\x66\x67\x68"
+ "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+ "\x71\x72\x73\x74\x75\x76\x77\x78",
+ .psize = 40,
+ .digest = "\xb4\x97\xcc\xd4",
+ },
+ {
+ .key = "\x2e\x80\x04\x59",
+ .ksize = 4,
+ .plaintext = "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
+ "\x81\x82\x83\x84\x85\x86\x87\x88"
+ "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
+ "\x91\x92\x93\x94\x95\x96\x97\x98"
+ "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0",
+ .psize = 40,
+ .digest = "\x67\x9b\xfa\x79",
+ },
+ {
+ .key = "\xa6\xcc\x19\x85",
+ .ksize = 4,
+ .plaintext = "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
+ "\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
+ "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8"
+ "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
+ "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8",
+ .psize = 40,
+ .digest = "\x24\xb5\x16\xef",
+ },
+ {
+ .key = "\x41\xfc\xfe\x2d",
+ .ksize = 4,
+ .plaintext = "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
+ "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8"
+ "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
+ "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
+ "\xe9\xea\xeb\xec\xed\xee\xef\xf0",
+ .psize = 40,
+ .digest = "\x15\x94\x80\x39",
+ },
+ {
+ .key = "\xff\xff\xff\xff",
+ .ksize = 4,
+ .plaintext = "\x01\x02\x03\x04\x05\x06\x07\x08"
+ "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+ "\x11\x12\x13\x14\x15\x16\x17\x18"
+ "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
+ "\x21\x22\x23\x24\x25\x26\x27\x28"
+ "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
+ "\x31\x32\x33\x34\x35\x36\x37\x38"
+ "\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
+ "\x41\x42\x43\x44\x45\x46\x47\x48"
+ "\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
+ "\x51\x52\x53\x54\x55\x56\x57\x58"
+ "\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
+ "\x61\x62\x63\x64\x65\x66\x67\x68"
+ "\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
+ "\x71\x72\x73\x74\x75\x76\x77\x78"
+ "\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
+ "\x81\x82\x83\x84\x85\x86\x87\x88"
+ "\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
+ "\x91\x92\x93\x94\x95\x96\x97\x98"
+ "\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
+ "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8"
+ "\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
+ "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8"
+ "\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
+ "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8"
+ "\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
+ "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8"
+ "\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
+ "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
+ "\xe9\xea\xeb\xec\xed\xee\xef\xf0",
+ .psize = 240,
+ .digest = "\x6c\xc6\x56\xde",
+ .np = 2,
+ .tap = { 31, 209 }
+ }, {
+ .key = "\xff\xff\xff\xff",
+ .ksize = 4,
+ .plaintext = "\x6e\x05\x79\x10\xa7\x1b\xb2\x49"
+ "\xe0\x54\xeb\x82\x19\x8d\x24\xbb"
+ "\x2f\xc6\x5d\xf4\x68\xff\x96\x0a"
+ "\xa1\x38\xcf\x43\xda\x71\x08\x7c"
+ "\x13\xaa\x1e\xb5\x4c\xe3\x57\xee"
+ "\x85\x1c\x90\x27\xbe\x32\xc9\x60"
+ "\xf7\x6b\x02\x99\x0d\xa4\x3b\xd2"
+ "\x46\xdd\x74\x0b\x7f\x16\xad\x21"
+ "\xb8\x4f\xe6\x5a\xf1\x88\x1f\x93"
+ "\x2a\xc1\x35\xcc\x63\xfa\x6e\x05"
+ "\x9c\x10\xa7\x3e\xd5\x49\xe0\x77"
+ "\x0e\x82\x19\xb0\x24\xbb\x52\xe9"
+ "\x5d\xf4\x8b\x22\x96\x2d\xc4\x38"
+ "\xcf\x66\xfd\x71\x08\x9f\x13\xaa"
+ "\x41\xd8\x4c\xe3\x7a\x11\x85\x1c"
+ "\xb3\x27\xbe\x55\xec\x60\xf7\x8e"
+ "\x02\x99\x30\xc7\x3b\xd2\x69\x00"
+ "\x74\x0b\xa2\x16\xad\x44\xdb\x4f"
+ "\xe6\x7d\x14\x88\x1f\xb6\x2a\xc1"
+ "\x58\xef\x63\xfa\x91\x05\x9c\x33"
+ "\xca\x3e\xd5\x6c\x03\x77\x0e\xa5"
+ "\x19\xb0\x47\xde\x52\xe9\x80\x17"
+ "\x8b\x22\xb9\x2d\xc4\x5b\xf2\x66"
+ "\xfd\x94\x08\x9f\x36\xcd\x41\xd8"
+ "\x6f\x06\x7a\x11\xa8\x1c\xb3\x4a"
+ "\xe1\x55\xec\x83\x1a\x8e\x25\xbc"
+ "\x30\xc7\x5e\xf5\x69\x00\x97\x0b"
+ "\xa2\x39\xd0\x44\xdb\x72\x09\x7d"
+ "\x14\xab\x1f\xb6\x4d\xe4\x58\xef"
+ "\x86\x1d\x91\x28\xbf\x33\xca\x61"
+ "\xf8\x6c\x03\x9a\x0e\xa5\x3c\xd3"
+ "\x47\xde\x75\x0c\x80\x17\xae\x22"
+ "\xb9\x50\xe7\x5b\xf2\x89\x20\x94"
+ "\x2b\xc2\x36\xcd\x64\xfb\x6f\x06"
+ "\x9d\x11\xa8\x3f\xd6\x4a\xe1\x78"
+ "\x0f\x83\x1a\xb1\x25\xbc\x53\xea"
+ "\x5e\xf5\x8c\x00\x97\x2e\xc5\x39"
+ "\xd0\x67\xfe\x72\x09\xa0\x14\xab"
+ "\x42\xd9\x4d\xe4\x7b\x12\x86\x1d"
+ "\xb4\x28\xbf\x56\xed\x61\xf8\x8f"
+ "\x03\x9a\x31\xc8\x3c\xd3\x6a\x01"
+ "\x75\x0c\xa3\x17\xae\x45\xdc\x50"
+ "\xe7\x7e\x15\x89\x20\xb7\x2b\xc2"
+ "\x59\xf0\x64\xfb\x92\x06\x9d\x34"
+ "\xcb\x3f\xd6\x6d\x04\x78\x0f\xa6"
+ "\x1a\xb1\x48\xdf\x53\xea\x81\x18"
+ "\x8c\x23\xba\x2e\xc5\x5c\xf3\x67"
+ "\xfe\x95\x09\xa0\x37\xce\x42\xd9"
+ "\x70\x07\x7b\x12\xa9\x1d\xb4\x4b"
+ "\xe2\x56\xed\x84\x1b\x8f\x26\xbd"
+ "\x31\xc8\x5f\xf6\x6a\x01\x98\x0c"
+ "\xa3\x3a\xd1\x45\xdc\x73\x0a\x7e"
+ "\x15\xac\x20\xb7\x4e\xe5\x59\xf0"
+ "\x87\x1e\x92\x29\xc0\x34\xcb\x62"
+ "\xf9\x6d\x04\x9b\x0f\xa6\x3d\xd4"
+ "\x48\xdf\x76\x0d\x81\x18\xaf\x23"
+ "\xba\x51\xe8\x5c\xf3\x8a\x21\x95"
+ "\x2c\xc3\x37\xce\x65\xfc\x70\x07"
+ "\x9e\x12\xa9\x40\xd7\x4b\xe2\x79"
+ "\x10\x84\x1b\xb2\x26\xbd\x54\xeb"
+ "\x5f\xf6\x8d\x01\x98\x2f\xc6\x3a"
+ "\xd1\x68\xff\x73\x0a\xa1\x15\xac"
+ "\x43\xda\x4e\xe5\x7c\x13\x87\x1e"
+ "\xb5\x29\xc0\x57\xee\x62\xf9\x90"
+ "\x04\x9b\x32\xc9\x3d\xd4\x6b\x02"
+ "\x76\x0d\xa4\x18\xaf\x46\xdd\x51"
+ "\xe8\x7f\x16\x8a\x21\xb8\x2c\xc3"
+ "\x5a\xf1\x65\xfc\x93\x07\x9e\x35"
+ "\xcc\x40\xd7\x6e\x05\x79\x10\xa7"
+ "\x1b\xb2\x49\xe0\x54\xeb\x82\x19"
+ "\x8d\x24\xbb\x2f\xc6\x5d\xf4\x68"
+ "\xff\x96\x0a\xa1\x38\xcf\x43\xda"
+ "\x71\x08\x7c\x13\xaa\x1e\xb5\x4c"
+ "\xe3\x57\xee\x85\x1c\x90\x27\xbe"
+ "\x32\xc9\x60\xf7\x6b\x02\x99\x0d"
+ "\xa4\x3b\xd2\x46\xdd\x74\x0b\x7f"
+ "\x16\xad\x21\xb8\x4f\xe6\x5a\xf1"
+ "\x88\x1f\x93\x2a\xc1\x35\xcc\x63"
+ "\xfa\x6e\x05\x9c\x10\xa7\x3e\xd5"
+ "\x49\xe0\x77\x0e\x82\x19\xb0\x24"
+ "\xbb\x52\xe9\x5d\xf4\x8b\x22\x96"
+ "\x2d\xc4\x38\xcf\x66\xfd\x71\x08"
+ "\x9f\x13\xaa\x41\xd8\x4c\xe3\x7a"
+ "\x11\x85\x1c\xb3\x27\xbe\x55\xec"
+ "\x60\xf7\x8e\x02\x99\x30\xc7\x3b"
+ "\xd2\x69\x00\x74\x0b\xa2\x16\xad"
+ "\x44\xdb\x4f\xe6\x7d\x14\x88\x1f"
+ "\xb6\x2a\xc1\x58\xef\x63\xfa\x91"
+ "\x05\x9c\x33\xca\x3e\xd5\x6c\x03"
+ "\x77\x0e\xa5\x19\xb0\x47\xde\x52"
+ "\xe9\x80\x17\x8b\x22\xb9\x2d\xc4"
+ "\x5b\xf2\x66\xfd\x94\x08\x9f\x36"
+ "\xcd\x41\xd8\x6f\x06\x7a\x11\xa8"
+ "\x1c\xb3\x4a\xe1\x55\xec\x83\x1a"
+ "\x8e\x25\xbc\x30\xc7\x5e\xf5\x69"
+ "\x00\x97\x0b\xa2\x39\xd0\x44\xdb"
+ "\x72\x09\x7d\x14\xab\x1f\xb6\x4d"
+ "\xe4\x58\xef\x86\x1d\x91\x28\xbf"
+ "\x33\xca\x61\xf8\x6c\x03\x9a\x0e"
+ "\xa5\x3c\xd3\x47\xde\x75\x0c\x80"
+ "\x17\xae\x22\xb9\x50\xe7\x5b\xf2"
+ "\x89\x20\x94\x2b\xc2\x36\xcd\x64"
+ "\xfb\x6f\x06\x9d\x11\xa8\x3f\xd6"
+ "\x4a\xe1\x78\x0f\x83\x1a\xb1\x25"
+ "\xbc\x53\xea\x5e\xf5\x8c\x00\x97"
+ "\x2e\xc5\x39\xd0\x67\xfe\x72\x09"
+ "\xa0\x14\xab\x42\xd9\x4d\xe4\x7b"
+ "\x12\x86\x1d\xb4\x28\xbf\x56\xed"
+ "\x61\xf8\x8f\x03\x9a\x31\xc8\x3c"
+ "\xd3\x6a\x01\x75\x0c\xa3\x17\xae"
+ "\x45\xdc\x50\xe7\x7e\x15\x89\x20"
+ "\xb7\x2b\xc2\x59\xf0\x64\xfb\x92"
+ "\x06\x9d\x34\xcb\x3f\xd6\x6d\x04"
+ "\x78\x0f\xa6\x1a\xb1\x48\xdf\x53"
+ "\xea\x81\x18\x8c\x23\xba\x2e\xc5"
+ "\x5c\xf3\x67\xfe\x95\x09\xa0\x37"
+ "\xce\x42\xd9\x70\x07\x7b\x12\xa9"
+ "\x1d\xb4\x4b\xe2\x56\xed\x84\x1b"
+ "\x8f\x26\xbd\x31\xc8\x5f\xf6\x6a"
+ "\x01\x98\x0c\xa3\x3a\xd1\x45\xdc"
+ "\x73\x0a\x7e\x15\xac\x20\xb7\x4e"
+ "\xe5\x59\xf0\x87\x1e\x92\x29\xc0"
+ "\x34\xcb\x62\xf9\x6d\x04\x9b\x0f"
+ "\xa6\x3d\xd4\x48\xdf\x76\x0d\x81"
+ "\x18\xaf\x23\xba\x51\xe8\x5c\xf3"
+ "\x8a\x21\x95\x2c\xc3\x37\xce\x65"
+ "\xfc\x70\x07\x9e\x12\xa9\x40\xd7"
+ "\x4b\xe2\x79\x10\x84\x1b\xb2\x26"
+ "\xbd\x54\xeb\x5f\xf6\x8d\x01\x98"
+ "\x2f\xc6\x3a\xd1\x68\xff\x73\x0a"
+ "\xa1\x15\xac\x43\xda\x4e\xe5\x7c"
+ "\x13\x87\x1e\xb5\x29\xc0\x57\xee"
+ "\x62\xf9\x90\x04\x9b\x32\xc9\x3d"
+ "\xd4\x6b\x02\x76\x0d\xa4\x18\xaf"
+ "\x46\xdd\x51\xe8\x7f\x16\x8a\x21"
+ "\xb8\x2c\xc3\x5a\xf1\x65\xfc\x93"
+ "\x07\x9e\x35\xcc\x40\xd7\x6e\x05"
+ "\x79\x10\xa7\x1b\xb2\x49\xe0\x54"
+ "\xeb\x82\x19\x8d\x24\xbb\x2f\xc6"
+ "\x5d\xf4\x68\xff\x96\x0a\xa1\x38"
+ "\xcf\x43\xda\x71\x08\x7c\x13\xaa"
+ "\x1e\xb5\x4c\xe3\x57\xee\x85\x1c"
+ "\x90\x27\xbe\x32\xc9\x60\xf7\x6b"
+ "\x02\x99\x0d\xa4\x3b\xd2\x46\xdd"
+ "\x74\x0b\x7f\x16\xad\x21\xb8\x4f"
+ "\xe6\x5a\xf1\x88\x1f\x93\x2a\xc1"
+ "\x35\xcc\x63\xfa\x6e\x05\x9c\x10"
+ "\xa7\x3e\xd5\x49\xe0\x77\x0e\x82"
+ "\x19\xb0\x24\xbb\x52\xe9\x5d\xf4"
+ "\x8b\x22\x96\x2d\xc4\x38\xcf\x66"
+ "\xfd\x71\x08\x9f\x13\xaa\x41\xd8"
+ "\x4c\xe3\x7a\x11\x85\x1c\xb3\x27"
+ "\xbe\x55\xec\x60\xf7\x8e\x02\x99"
+ "\x30\xc7\x3b\xd2\x69\x00\x74\x0b"
+ "\xa2\x16\xad\x44\xdb\x4f\xe6\x7d"
+ "\x14\x88\x1f\xb6\x2a\xc1\x58\xef"
+ "\x63\xfa\x91\x05\x9c\x33\xca\x3e"
+ "\xd5\x6c\x03\x77\x0e\xa5\x19\xb0"
+ "\x47\xde\x52\xe9\x80\x17\x8b\x22"
+ "\xb9\x2d\xc4\x5b\xf2\x66\xfd\x94"
+ "\x08\x9f\x36\xcd\x41\xd8\x6f\x06"
+ "\x7a\x11\xa8\x1c\xb3\x4a\xe1\x55"
+ "\xec\x83\x1a\x8e\x25\xbc\x30\xc7"
+ "\x5e\xf5\x69\x00\x97\x0b\xa2\x39"
+ "\xd0\x44\xdb\x72\x09\x7d\x14\xab"
+ "\x1f\xb6\x4d\xe4\x58\xef\x86\x1d"
+ "\x91\x28\xbf\x33\xca\x61\xf8\x6c"
+ "\x03\x9a\x0e\xa5\x3c\xd3\x47\xde"
+ "\x75\x0c\x80\x17\xae\x22\xb9\x50"
+ "\xe7\x5b\xf2\x89\x20\x94\x2b\xc2"
+ "\x36\xcd\x64\xfb\x6f\x06\x9d\x11"
+ "\xa8\x3f\xd6\x4a\xe1\x78\x0f\x83"
+ "\x1a\xb1\x25\xbc\x53\xea\x5e\xf5"
+ "\x8c\x00\x97\x2e\xc5\x39\xd0\x67"
+ "\xfe\x72\x09\xa0\x14\xab\x42\xd9"
+ "\x4d\xe4\x7b\x12\x86\x1d\xb4\x28"
+ "\xbf\x56\xed\x61\xf8\x8f\x03\x9a"
+ "\x31\xc8\x3c\xd3\x6a\x01\x75\x0c"
+ "\xa3\x17\xae\x45\xdc\x50\xe7\x7e"
+ "\x15\x89\x20\xb7\x2b\xc2\x59\xf0"
+ "\x64\xfb\x92\x06\x9d\x34\xcb\x3f"
+ "\xd6\x6d\x04\x78\x0f\xa6\x1a\xb1"
+ "\x48\xdf\x53\xea\x81\x18\x8c\x23"
+ "\xba\x2e\xc5\x5c\xf3\x67\xfe\x95"
+ "\x09\xa0\x37\xce\x42\xd9\x70\x07"
+ "\x7b\x12\xa9\x1d\xb4\x4b\xe2\x56"
+ "\xed\x84\x1b\x8f\x26\xbd\x31\xc8"
+ "\x5f\xf6\x6a\x01\x98\x0c\xa3\x3a"
+ "\xd1\x45\xdc\x73\x0a\x7e\x15\xac"
+ "\x20\xb7\x4e\xe5\x59\xf0\x87\x1e"
+ "\x92\x29\xc0\x34\xcb\x62\xf9\x6d"
+ "\x04\x9b\x0f\xa6\x3d\xd4\x48\xdf"
+ "\x76\x0d\x81\x18\xaf\x23\xba\x51"
+ "\xe8\x5c\xf3\x8a\x21\x95\x2c\xc3"
+ "\x37\xce\x65\xfc\x70\x07\x9e\x12"
+ "\xa9\x40\xd7\x4b\xe2\x79\x10\x84"
+ "\x1b\xb2\x26\xbd\x54\xeb\x5f\xf6"
+ "\x8d\x01\x98\x2f\xc6\x3a\xd1\x68"
+ "\xff\x73\x0a\xa1\x15\xac\x43\xda"
+ "\x4e\xe5\x7c\x13\x87\x1e\xb5\x29"
+ "\xc0\x57\xee\x62\xf9\x90\x04\x9b"
+ "\x32\xc9\x3d\xd4\x6b\x02\x76\x0d"
+ "\xa4\x18\xaf\x46\xdd\x51\xe8\x7f"
+ "\x16\x8a\x21\xb8\x2c\xc3\x5a\xf1"
+ "\x65\xfc\x93\x07\x9e\x35\xcc\x40"
+ "\xd7\x6e\x05\x79\x10\xa7\x1b\xb2"
+ "\x49\xe0\x54\xeb\x82\x19\x8d\x24"
+ "\xbb\x2f\xc6\x5d\xf4\x68\xff\x96"
+ "\x0a\xa1\x38\xcf\x43\xda\x71\x08"
+ "\x7c\x13\xaa\x1e\xb5\x4c\xe3\x57"
+ "\xee\x85\x1c\x90\x27\xbe\x32\xc9"
+ "\x60\xf7\x6b\x02\x99\x0d\xa4\x3b"
+ "\xd2\x46\xdd\x74\x0b\x7f\x16\xad"
+ "\x21\xb8\x4f\xe6\x5a\xf1\x88\x1f"
+ "\x93\x2a\xc1\x35\xcc\x63\xfa\x6e"
+ "\x05\x9c\x10\xa7\x3e\xd5\x49\xe0"
+ "\x77\x0e\x82\x19\xb0\x24\xbb\x52"
+ "\xe9\x5d\xf4\x8b\x22\x96\x2d\xc4"
+ "\x38\xcf\x66\xfd\x71\x08\x9f\x13"
+ "\xaa\x41\xd8\x4c\xe3\x7a\x11\x85"
+ "\x1c\xb3\x27\xbe\x55\xec\x60\xf7"
+ "\x8e\x02\x99\x30\xc7\x3b\xd2\x69"
+ "\x00\x74\x0b\xa2\x16\xad\x44\xdb"
+ "\x4f\xe6\x7d\x14\x88\x1f\xb6\x2a"
+ "\xc1\x58\xef\x63\xfa\x91\x05\x9c"
+ "\x33\xca\x3e\xd5\x6c\x03\x77\x0e"
+ "\xa5\x19\xb0\x47\xde\x52\xe9\x80"
+ "\x17\x8b\x22\xb9\x2d\xc4\x5b\xf2"
+ "\x66\xfd\x94\x08\x9f\x36\xcd\x41"
+ "\xd8\x6f\x06\x7a\x11\xa8\x1c\xb3"
+ "\x4a\xe1\x55\xec\x83\x1a\x8e\x25"
+ "\xbc\x30\xc7\x5e\xf5\x69\x00\x97"
+ "\x0b\xa2\x39\xd0\x44\xdb\x72\x09"
+ "\x7d\x14\xab\x1f\xb6\x4d\xe4\x58"
+ "\xef\x86\x1d\x91\x28\xbf\x33\xca"
+ "\x61\xf8\x6c\x03\x9a\x0e\xa5\x3c"
+ "\xd3\x47\xde\x75\x0c\x80\x17\xae"
+ "\x22\xb9\x50\xe7\x5b\xf2\x89\x20"
+ "\x94\x2b\xc2\x36\xcd\x64\xfb\x6f"
+ "\x06\x9d\x11\xa8\x3f\xd6\x4a\xe1"
+ "\x78\x0f\x83\x1a\xb1\x25\xbc\x53"
+ "\xea\x5e\xf5\x8c\x00\x97\x2e\xc5"
+ "\x39\xd0\x67\xfe\x72\x09\xa0\x14"
+ "\xab\x42\xd9\x4d\xe4\x7b\x12\x86"
+ "\x1d\xb4\x28\xbf\x56\xed\x61\xf8"
+ "\x8f\x03\x9a\x31\xc8\x3c\xd3\x6a"
+ "\x01\x75\x0c\xa3\x17\xae\x45\xdc"
+ "\x50\xe7\x7e\x15\x89\x20\xb7\x2b"
+ "\xc2\x59\xf0\x64\xfb\x92\x06\x9d"
+ "\x34\xcb\x3f\xd6\x6d\x04\x78\x0f"
+ "\xa6\x1a\xb1\x48\xdf\x53\xea\x81"
+ "\x18\x8c\x23\xba\x2e\xc5\x5c\xf3"
+ "\x67\xfe\x95\x09\xa0\x37\xce\x42"
+ "\xd9\x70\x07\x7b\x12\xa9\x1d\xb4"
+ "\x4b\xe2\x56\xed\x84\x1b\x8f\x26"
+ "\xbd\x31\xc8\x5f\xf6\x6a\x01\x98",
+ .psize = 2048,
+ .digest = "\xfb\x3a\x7a\xda",
+ }
+};
+
+/*
* CRC32C test vectors
*/
#define CRC32C_TEST_VECTORS 15
diff --git a/crypto/zlib.c b/crypto/zlib.c
index 0eefa9d237ac..d51a30a29e42 100644
--- a/crypto/zlib.c
+++ b/crypto/zlib.c
@@ -78,7 +78,7 @@ static void zlib_exit(struct crypto_tfm *tfm)
}
-static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
+static int zlib_compress_setup(struct crypto_pcomp *tfm, const void *params,
unsigned int len)
{
struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
@@ -209,7 +209,7 @@ static int zlib_compress_final(struct crypto_pcomp *tfm,
}
-static int zlib_decompress_setup(struct crypto_pcomp *tfm, void *params,
+static int zlib_decompress_setup(struct crypto_pcomp *tfm, const void *params,
unsigned int len)
{
struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
diff --git a/drivers/Makefile b/drivers/Makefile
index 46d2554be404..9a02fb7c5106 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -98,7 +98,6 @@ obj-$(CONFIG_USB_GADGET) += usb/
obj-$(CONFIG_SERIO) += input/serio/
obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_INPUT) += input/
-obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_RTC_LIB) += rtc/
obj-y += i2c/ media/
obj-$(CONFIG_PPS) += pps/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index ab2cbb51c6aa..35da507411a0 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -54,6 +54,9 @@ config ACPI_GENERIC_GSI
config ACPI_SYSTEM_POWER_STATES_SUPPORT
bool
+config ACPI_CCA_REQUIRED
+ bool
+
config ACPI_SLEEP
bool
depends on SUSPEND || HIBERNATION
@@ -62,7 +65,7 @@ config ACPI_SLEEP
config ACPI_PROCFS_POWER
bool "Deprecated power /proc/acpi directories"
- depends on PROC_FS
+ depends on X86 && PROC_FS
help
For backwards compatibility, this option allows
deprecated power /proc/acpi/ directories to exist, even when
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 8a063e276530..73d840bef455 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -52,9 +52,6 @@ acpi-$(CONFIG_X86) += acpi_cmos_rtc.o
acpi-$(CONFIG_DEBUG_FS) += debugfs.o
acpi-$(CONFIG_ACPI_NUMA) += numa.o
acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
-ifdef CONFIG_ACPI_VIDEO
-acpi-y += video_detect.o
-endif
acpi-y += acpi_lpat.o
acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o
@@ -95,3 +92,5 @@ obj-$(CONFIG_ACPI_EXTLOG) += acpi_extlog.o
obj-$(CONFIG_PMIC_OPREGION) += pmic/intel_pmic.o
obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o
obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o
+
+video-objs += acpi_video.o video_detect.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index bbcc2b5a70d4..9b5354a2cd08 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -308,7 +308,7 @@ static int thinkpad_e530_quirk(const struct dmi_system_id *d)
return 0;
}
-static struct dmi_system_id ac_dmi_table[] = {
+static const struct dmi_system_id ac_dmi_table[] = {
{
.callback = thinkpad_e530_quirk,
.ident = "thinkpad e530",
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 37fb19047603..569ee090343f 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -129,50 +129,50 @@ static void byt_i2c_setup(struct lpss_private_data *pdata)
writel(0, pdata->mmio_base + LPSS_I2C_ENABLE);
}
-static struct lpss_device_desc lpt_dev_desc = {
+static const struct lpss_device_desc lpt_dev_desc = {
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR,
.prv_offset = 0x800,
};
-static struct lpss_device_desc lpt_i2c_dev_desc = {
+static const struct lpss_device_desc lpt_i2c_dev_desc = {
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_LTR,
.prv_offset = 0x800,
};
-static struct lpss_device_desc lpt_uart_dev_desc = {
+static const struct lpss_device_desc lpt_uart_dev_desc = {
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR,
.clk_con_id = "baudclk",
.prv_offset = 0x800,
.setup = lpss_uart_setup,
};
-static struct lpss_device_desc lpt_sdio_dev_desc = {
+static const struct lpss_device_desc lpt_sdio_dev_desc = {
.flags = LPSS_LTR,
.prv_offset = 0x1000,
.prv_size_override = 0x1018,
};
-static struct lpss_device_desc byt_pwm_dev_desc = {
+static const struct lpss_device_desc byt_pwm_dev_desc = {
.flags = LPSS_SAVE_CTX,
};
-static struct lpss_device_desc byt_uart_dev_desc = {
+static const struct lpss_device_desc byt_uart_dev_desc = {
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
.clk_con_id = "baudclk",
.prv_offset = 0x800,
.setup = lpss_uart_setup,
};
-static struct lpss_device_desc byt_spi_dev_desc = {
+static const struct lpss_device_desc byt_spi_dev_desc = {
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
.prv_offset = 0x400,
};
-static struct lpss_device_desc byt_sdio_dev_desc = {
+static const struct lpss_device_desc byt_sdio_dev_desc = {
.flags = LPSS_CLK,
};
-static struct lpss_device_desc byt_i2c_dev_desc = {
+static const struct lpss_device_desc byt_i2c_dev_desc = {
.flags = LPSS_CLK | LPSS_SAVE_CTX,
.prv_offset = 0x800,
.setup = byt_i2c_setup,
@@ -323,14 +323,14 @@ out:
static int acpi_lpss_create_device(struct acpi_device *adev,
const struct acpi_device_id *id)
{
- struct lpss_device_desc *dev_desc;
+ const struct lpss_device_desc *dev_desc;
struct lpss_private_data *pdata;
struct resource_entry *rentry;
struct list_head resource_list;
struct platform_device *pdev;
int ret;
- dev_desc = (struct lpss_device_desc *)id->driver_data;
+ dev_desc = (const struct lpss_device_desc *)id->driver_data;
if (!dev_desc) {
pdev = acpi_create_platform_device(adev);
return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 6bc9cbc01ad6..00b39802d7ec 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -105,7 +105,7 @@ static void round_robin_cpu(unsigned int tsk_index)
mutex_lock(&round_robin_lock);
cpumask_clear(tmp);
for_each_cpu(cpu, pad_busy_cpus)
- cpumask_or(tmp, tmp, topology_thread_cpumask(cpu));
+ cpumask_or(tmp, tmp, topology_sibling_cpumask(cpu));
cpumask_andnot(tmp, cpu_online_mask, tmp);
/* avoid HT sibilings if possible */
if (cpumask_empty(tmp))
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 4bf75597f732..06a67d5f2846 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -103,7 +103,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
pdevinfo.res = resources;
pdevinfo.num_res = count;
pdevinfo.fwnode = acpi_fwnode_handle(adev);
- pdevinfo.dma_mask = DMA_BIT_MASK(32);
+ pdevinfo.dma_mask = acpi_check_dma(adev, NULL) ? DMA_BIT_MASK(32) : 0;
pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev))
dev_err(&adev->dev, "platform device creation failed: %ld\n",
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 58f335ca2e75..92a5f738e370 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -170,7 +170,7 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
acpi_status status;
int ret;
- if (pr->phys_id == PHYS_CPUID_INVALID)
+ if (invalid_phys_cpuid(pr->phys_id))
return -ENODEV;
status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta);
@@ -215,8 +215,7 @@ static int acpi_processor_get_info(struct acpi_device *device)
union acpi_object object = { 0 };
struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
struct acpi_processor *pr = acpi_driver_data(device);
- phys_cpuid_t phys_id;
- int cpu_index, device_declaration = 0;
+ int device_declaration = 0;
acpi_status status = AE_OK;
static int cpu0_initialized;
unsigned long long value;
@@ -263,29 +262,28 @@ static int acpi_processor_get_info(struct acpi_device *device)
pr->acpi_id = value;
}
- phys_id = acpi_get_phys_id(pr->handle, device_declaration, pr->acpi_id);
- if (phys_id == PHYS_CPUID_INVALID)
+ pr->phys_id = acpi_get_phys_id(pr->handle, device_declaration,
+ pr->acpi_id);
+ if (invalid_phys_cpuid(pr->phys_id))
acpi_handle_debug(pr->handle, "failed to get CPU physical ID.\n");
- pr->phys_id = phys_id;
- cpu_index = acpi_map_cpuid(pr->phys_id, pr->acpi_id);
+ pr->id = acpi_map_cpuid(pr->phys_id, pr->acpi_id);
if (!cpu0_initialized && !acpi_has_cpu_in_madt()) {
cpu0_initialized = 1;
/*
* Handle UP system running SMP kernel, with no CPU
* entry in MADT
*/
- if ((cpu_index == -1) && (num_online_cpus() == 1))
- cpu_index = 0;
+ if (invalid_logical_cpuid(pr->id) && (num_online_cpus() == 1))
+ pr->id = 0;
}
- pr->id = cpu_index;
/*
* Extra Processor objects may be enumerated on MP systems with
* less than the max # of CPUs. They should be ignored _iff
* they are physically not present.
*/
- if (pr->id == -1) {
+ if (invalid_logical_cpuid(pr->id)) {
int ret = acpi_processor_hotadd_init(pr);
if (ret)
return ret;
diff --git a/drivers/acpi/video.c b/drivers/acpi/acpi_video.c
index cc79d3fedfb2..8c2fe2f2f9fd 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/acpi_video.c
@@ -43,7 +43,7 @@
#include <acpi/video.h>
#include <asm/uaccess.h>
-#include "internal.h"
+#define PREFIX "ACPI: "
#define ACPI_VIDEO_BUS_NAME "Video Bus"
#define ACPI_VIDEO_DEVICE_NAME "Video Device"
@@ -78,26 +78,17 @@ module_param(brightness_switch_enabled, bool, 0644);
static bool allow_duplicates;
module_param(allow_duplicates, bool, 0644);
-/*
- * For Windows 8 systems: used to decide if video module
- * should skip registering backlight interface of its own.
- */
-enum {
- NATIVE_BACKLIGHT_NOT_SET = -1,
- NATIVE_BACKLIGHT_OFF,
- NATIVE_BACKLIGHT_ON,
-};
-
-static int use_native_backlight_param = NATIVE_BACKLIGHT_NOT_SET;
-module_param_named(use_native_backlight, use_native_backlight_param, int, 0444);
-static int use_native_backlight_dmi = NATIVE_BACKLIGHT_NOT_SET;
+static int disable_backlight_sysfs_if = -1;
+module_param(disable_backlight_sysfs_if, int, 0444);
static int register_count;
+static DEFINE_MUTEX(register_count_mutex);
static struct mutex video_list_lock;
static struct list_head video_bus_head;
static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device);
static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
+void acpi_video_detect_exit(void);
static const struct acpi_device_id video_device_ids[] = {
{ACPI_VIDEO_HID, 0},
@@ -157,7 +148,6 @@ struct acpi_video_enumerated_device {
struct acpi_video_bus {
struct acpi_device *device;
bool backlight_registered;
- bool backlight_notifier_registered;
u8 dos_setting;
struct acpi_video_enumerated_device *attached_array;
u8 attached_count;
@@ -170,7 +160,6 @@ struct acpi_video_bus {
struct input_dev *input;
char phys[32]; /* for input device */
struct notifier_block pm_nb;
- struct notifier_block backlight_nb;
};
struct acpi_video_device_flags {
@@ -241,24 +230,6 @@ static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event);
static void acpi_video_switch_brightness(struct work_struct *work);
-static bool acpi_video_use_native_backlight(void)
-{
- if (use_native_backlight_param != NATIVE_BACKLIGHT_NOT_SET)
- return use_native_backlight_param;
- else if (use_native_backlight_dmi != NATIVE_BACKLIGHT_NOT_SET)
- return use_native_backlight_dmi;
- return acpi_osi_is_win8();
-}
-
-bool acpi_video_verify_backlight_support(void)
-{
- if (acpi_video_use_native_backlight() &&
- backlight_device_registered(BACKLIGHT_RAW))
- return false;
- return acpi_video_backlight_support();
-}
-EXPORT_SYMBOL_GPL(acpi_video_verify_backlight_support);
-
/* backlight device sysfs support */
static int acpi_video_get_brightness(struct backlight_device *bd)
{
@@ -413,25 +384,21 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
*/
static int bqc_offset_aml_bug_workaround;
-static int __init video_set_bqc_offset(const struct dmi_system_id *d)
+static int video_set_bqc_offset(const struct dmi_system_id *d)
{
bqc_offset_aml_bug_workaround = 9;
return 0;
}
-static int __init video_disable_native_backlight(const struct dmi_system_id *d)
-{
- use_native_backlight_dmi = NATIVE_BACKLIGHT_OFF;
- return 0;
-}
-
-static int __init video_enable_native_backlight(const struct dmi_system_id *d)
+static int video_disable_backlight_sysfs_if(
+ const struct dmi_system_id *d)
{
- use_native_backlight_dmi = NATIVE_BACKLIGHT_ON;
+ if (disable_backlight_sysfs_if == -1)
+ disable_backlight_sysfs_if = 1;
return 0;
}
-static struct dmi_system_id video_dmi_table[] __initdata = {
+static struct dmi_system_id video_dmi_table[] = {
/*
* Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
*/
@@ -477,110 +444,19 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
},
/*
- * These models have a working acpi_video backlight control, and using
- * native backlight causes a regression where backlight does not work
- * when userspace is not handling brightness key events. Disable
- * native_backlight on these to fix this:
- * https://bugzilla.kernel.org/show_bug.cgi?id=81691
+ * Some machines have a broken acpi-video interface for brightness
+ * control, but still need an acpi_video_device_lcd_set_level() call
+ * on resume to turn the backlight power on. We Enable backlight
+ * control on these systems, but do not register a backlight sysfs
+ * as brightness control does not work.
*/
{
- .callback = video_disable_native_backlight,
- .ident = "ThinkPad T420",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T420"),
- },
- },
- {
- .callback = video_disable_native_backlight,
- .ident = "ThinkPad T520",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"),
- },
- },
- {
- .callback = video_disable_native_backlight,
- .ident = "ThinkPad X201s",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"),
- },
- },
-
- /* The native backlight controls do not work on some older machines */
- {
- /* https://bugs.freedesktop.org/show_bug.cgi?id=81515 */
- .callback = video_disable_native_backlight,
- .ident = "HP ENVY 15 Notebook",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"),
- },
- },
-
- {
- .callback = video_disable_native_backlight,
- .ident = "SAMSUNG 870Z5E/880Z5E/680Z5E",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"),
- },
- },
- {
- .callback = video_disable_native_backlight,
- .ident = "SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "370R4E/370R4V/370R5E/3570RE/370R5V"),
- },
- },
- {
- /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */
- .callback = video_disable_native_backlight,
- .ident = "SAMSUNG 3570R/370R/470R/450R/510R/4450RV",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "3570R/370R/470R/450R/510R/4450RV"),
- },
- },
- {
- /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
- .callback = video_disable_native_backlight,
- .ident = "SAMSUNG 730U3E/740U3E",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"),
- },
- },
- {
- /* https://bugs.freedesktop.org/show_bug.cgi?id=87286 */
- .callback = video_disable_native_backlight,
- .ident = "SAMSUNG 900X3C/900X3D/900X3E/900X4C/900X4D",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
- DMI_MATCH(DMI_PRODUCT_NAME, "900X3C/900X3D/900X3E/900X4C/900X4D"),
- },
- },
-
- {
- /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */
- .callback = video_disable_native_backlight,
- .ident = "Dell XPS15 L521X",
+ /* https://bugs.freedesktop.org/show_bug.cgi?id=82634 */
+ .callback = video_disable_backlight_sysfs_if,
+ .ident = "Toshiba Portege R830",
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"),
- },
- },
-
- /* Non win8 machines which need native backlight nevertheless */
- {
- /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */
- .callback = video_enable_native_backlight,
- .ident = "Lenovo Ideapad Z570",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_NAME, "102434U"),
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R830"),
},
},
{}
@@ -1382,7 +1258,7 @@ acpi_video_switch_brightness(struct work_struct *work)
int result = -EINVAL;
/* no warning message if acpi_backlight=vendor or a quirk is used */
- if (!acpi_video_verify_backlight_support())
+ if (!device->backlight)
return;
if (!device->brightness)
@@ -1657,8 +1533,9 @@ static int acpi_video_resume(struct notifier_block *nb,
for (i = 0; i < video->attached_count; i++) {
video_device = video->attached_array[i].bind_info;
- if (video_device && video_device->backlight)
- acpi_video_set_brightness(video_device->backlight);
+ if (video_device && video_device->brightness)
+ acpi_video_device_lcd_set_level(video_device,
+ video_device->brightness->curr);
}
return NOTIFY_OK;
@@ -1707,6 +1584,10 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
result = acpi_video_init_brightness(device);
if (result)
return;
+
+ if (disable_backlight_sysfs_if > 0)
+ return;
+
name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
if (!name)
return;
@@ -1729,8 +1610,10 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
&acpi_backlight_ops,
&props);
kfree(name);
- if (IS_ERR(device->backlight))
+ if (IS_ERR(device->backlight)) {
+ device->backlight = NULL;
return;
+ }
/*
* Save current brightness level in case we have to restore it
@@ -1787,7 +1670,7 @@ static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
acpi_video_run_bcl_for_osi(video);
- if (!acpi_video_verify_backlight_support())
+ if (acpi_video_get_backlight_type() != acpi_backlight_video)
return 0;
mutex_lock(&video->device_list_lock);
@@ -1931,56 +1814,6 @@ static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video)
video->input = NULL;
}
-static int acpi_video_backlight_notify(struct notifier_block *nb,
- unsigned long val, void *bd)
-{
- struct backlight_device *backlight = bd;
- struct acpi_video_bus *video;
-
- /* acpi_video_verify_backlight_support only cares about raw devices */
- if (backlight->props.type != BACKLIGHT_RAW)
- return NOTIFY_DONE;
-
- video = container_of(nb, struct acpi_video_bus, backlight_nb);
-
- switch (val) {
- case BACKLIGHT_REGISTERED:
- if (!acpi_video_verify_backlight_support())
- acpi_video_bus_unregister_backlight(video);
- break;
- case BACKLIGHT_UNREGISTERED:
- acpi_video_bus_register_backlight(video);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static int acpi_video_bus_add_backlight_notify_handler(
- struct acpi_video_bus *video)
-{
- int error;
-
- video->backlight_nb.notifier_call = acpi_video_backlight_notify;
- video->backlight_nb.priority = 0;
- error = backlight_register_notifier(&video->backlight_nb);
- if (error == 0)
- video->backlight_notifier_registered = true;
-
- return error;
-}
-
-static int acpi_video_bus_remove_backlight_notify_handler(
- struct acpi_video_bus *video)
-{
- if (!video->backlight_notifier_registered)
- return 0;
-
- video->backlight_notifier_registered = false;
-
- return backlight_unregister_notifier(&video->backlight_nb);
-}
-
static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
{
struct acpi_video_device *dev, *next;
@@ -2062,7 +1895,6 @@ static int acpi_video_bus_add(struct acpi_device *device)
acpi_video_bus_register_backlight(video);
acpi_video_bus_add_notify_handler(video);
- acpi_video_bus_add_backlight_notify_handler(video);
return 0;
@@ -2086,7 +1918,6 @@ static int acpi_video_bus_remove(struct acpi_device *device)
video = acpi_driver_data(device);
- acpi_video_bus_remove_backlight_notify_handler(video);
acpi_video_bus_remove_notify_handler(video);
acpi_video_bus_unregister_backlight(video);
acpi_video_bus_put_devices(video);
@@ -2134,22 +1965,25 @@ static int __init intel_opregion_present(void)
int acpi_video_register(void)
{
- int ret;
+ int ret = 0;
+ mutex_lock(&register_count_mutex);
if (register_count) {
/*
* if the function of acpi_video_register is already called,
* don't register the acpi_vide_bus again and return no error.
*/
- return 0;
+ goto leave;
}
mutex_init(&video_list_lock);
INIT_LIST_HEAD(&video_bus_head);
+ dmi_check_system(video_dmi_table);
+
ret = acpi_bus_register_driver(&acpi_video_bus);
if (ret)
- return ret;
+ goto leave;
/*
* When the acpi_video_bus is loaded successfully, increase
@@ -2157,24 +1991,20 @@ int acpi_video_register(void)
*/
register_count = 1;
- return 0;
+leave:
+ mutex_unlock(&register_count_mutex);
+ return ret;
}
EXPORT_SYMBOL(acpi_video_register);
void acpi_video_unregister(void)
{
- if (!register_count) {
- /*
- * If the acpi video bus is already unloaded, don't
- * unload it again and return directly.
- */
- return;
+ mutex_lock(&register_count_mutex);
+ if (register_count) {
+ acpi_bus_unregister_driver(&acpi_video_bus);
+ register_count = 0;
}
- acpi_bus_unregister_driver(&acpi_video_bus);
-
- register_count = 0;
-
- return;
+ mutex_unlock(&register_count_mutex);
}
EXPORT_SYMBOL(acpi_video_unregister);
@@ -2182,15 +2012,15 @@ void acpi_video_unregister_backlight(void)
{
struct acpi_video_bus *video;
- if (!register_count)
- return;
-
- mutex_lock(&video_list_lock);
- list_for_each_entry(video, &video_bus_head, entry)
- acpi_video_bus_unregister_backlight(video);
- mutex_unlock(&video_list_lock);
+ mutex_lock(&register_count_mutex);
+ if (register_count) {
+ mutex_lock(&video_list_lock);
+ list_for_each_entry(video, &video_bus_head, entry)
+ acpi_video_bus_unregister_backlight(video);
+ mutex_unlock(&video_list_lock);
+ }
+ mutex_unlock(&register_count_mutex);
}
-EXPORT_SYMBOL(acpi_video_unregister_backlight);
/*
* This is kind of nasty. Hardware using Intel chipsets may require
@@ -2212,8 +2042,6 @@ static int __init acpi_video_init(void)
if (acpi_disabled)
return 0;
- dmi_check_system(video_dmi_table);
-
if (intel_opregion_present())
return 0;
@@ -2222,6 +2050,7 @@ static int __init acpi_video_init(void)
static void __exit acpi_video_exit(void)
{
+ acpi_video_detect_exit();
acpi_video_unregister();
return;
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 4169bb87a996..43685dd36c77 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -231,7 +231,9 @@ void acpi_db_open_debug_file(char *name);
acpi_status acpi_db_load_acpi_table(char *filename);
acpi_status
-acpi_db_get_table_from_file(char *filename, struct acpi_table_header **table);
+acpi_db_get_table_from_file(char *filename,
+ struct acpi_table_header **table,
+ u8 must_be_aml_table);
/*
* dbhistry - debugger HISTORY command
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 87b27521fcac..ffdb956391f6 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -352,11 +352,21 @@ struct acpi_package_info3 {
u16 reserved;
};
+struct acpi_package_info4 {
+ u8 type;
+ u8 object_type1;
+ u8 count1;
+ u8 sub_object_types;
+ u8 pkg_count;
+ u16 reserved;
+};
+
union acpi_predefined_info {
struct acpi_name_info info;
struct acpi_package_info ret_info;
struct acpi_package_info2 ret_info2;
struct acpi_package_info3 ret_info3;
+ struct acpi_package_info4 ret_info4;
};
/* Reset to default packing */
@@ -1165,4 +1175,9 @@ struct ah_uuid {
char *string;
};
+struct ah_table {
+ char *signature;
+ char *description;
+};
+
#endif /* __ACLOCAL_H__ */
diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h
index 74a390c6db16..0cdd2fce493a 100644
--- a/drivers/acpi/acpica/acparser.h
+++ b/drivers/acpi/acpica/acparser.h
@@ -70,6 +70,9 @@
*
*****************************************************************************/
+extern const u8 acpi_gbl_short_op_index[];
+extern const u8 acpi_gbl_long_op_index[];
+
/*
* psxface - Parser external interfaces
*/
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index a972d11c97c9..b9474b529fcb 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -105,6 +105,11 @@
* count = 0 (optional)
* (Used for _DLM)
*
+ * ACPI_PTYPE2_VAR_VAR: Variable number of subpackages, each of either a
+ * constant or variable length. The subpackages are preceded by a
+ * constant number of objects.
+ * (Used for _LPI, _RDI)
+ *
* ACPI_PTYPE2_UUID_PAIR: Each subpackage is preceded by a UUID Buffer. The UUID
* defines the format of the package. Zero-length parent package is
* allowed.
@@ -123,7 +128,8 @@ enum acpi_return_package_types {
ACPI_PTYPE2_MIN = 8,
ACPI_PTYPE2_REV_FIXED = 9,
ACPI_PTYPE2_FIX_VAR = 10,
- ACPI_PTYPE2_UUID_PAIR = 11
+ ACPI_PTYPE2_VAR_VAR = 11,
+ ACPI_PTYPE2_UUID_PAIR = 12
};
/* Support macros for users of the predefined info table */
@@ -172,7 +178,7 @@ enum acpi_return_package_types {
* These are the names that can actually be evaluated via acpi_evaluate_object.
* Not present in this table are the following:
*
- * 1) Predefined/Reserved names that are never evaluated via
+ * 1) Predefined/Reserved names that are not usually evaluated via
* acpi_evaluate_object:
* _Lxx and _Exx GPE methods
* _Qxx EC methods
@@ -361,6 +367,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0),
+ {{"_BTH", METHOD_1ARGS(ACPI_TYPE_INTEGER), /* ACPI 6.0 */
+ METHOD_NO_RETURN_VALUE}},
+
{{"_BTM", METHOD_1ARGS(ACPI_TYPE_INTEGER),
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
@@ -390,6 +399,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER, 0,
0, 0, 0),
+ {{"_CR3", METHOD_0ARGS, /* ACPI 6.0 */
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
{{"_CRS", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
@@ -445,7 +457,7 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_DOS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
METHOD_NO_RETURN_VALUE}},
- {{"_DSD", METHOD_0ARGS,
+ {{"_DSD", METHOD_0ARGS, /* ACPI 6.0 */
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Buf, 1 Pkg */
PACKAGE_INFO(ACPI_PTYPE2_UUID_PAIR, ACPI_RTYPE_BUFFER, 1,
ACPI_RTYPE_PACKAGE, 1, 0),
@@ -604,6 +616,12 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Int) */
PACKAGE_INFO(ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0),
+ {{"_LPI", METHOD_0ARGS, /* ACPI 6.0 */
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (3 Int, n Pkg (10 Int/Buf) */
+ PACKAGE_INFO(ACPI_PTYPE2_VAR_VAR, ACPI_RTYPE_INTEGER, 3,
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER | ACPI_RTYPE_STRING,
+ 10, 0),
+
{{"_MAT", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
@@ -624,6 +642,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
ACPI_TYPE_INTEGER),
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+ {{"_MTL", METHOD_0ARGS, /* ACPI 6.0 */
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
{{"_NTT", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
@@ -716,6 +737,10 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+ {{"_PRR", METHOD_0ARGS, /* ACPI 6.0 */
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Ref) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_REFERENCE, 1, 0, 0, 0),
+
{{"_PRS", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
@@ -796,6 +821,11 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_PXM", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+ {{"_RDI", METHOD_0ARGS, /* ACPI 6.0 */
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int, n Pkg (m Ref)) */
+ PACKAGE_INFO(ACPI_PTYPE2_VAR_VAR, ACPI_RTYPE_INTEGER, 1,
+ ACPI_RTYPE_REFERENCE, 0, 0),
+
{{"_REG", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER),
METHOD_NO_RETURN_VALUE}},
@@ -808,6 +838,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_ROM", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER),
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+ {{"_RST", METHOD_0ARGS, /* ACPI 6.0 */
+ METHOD_NO_RETURN_VALUE}},
+
{{"_RTV", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
@@ -935,6 +968,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_TDL", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+ {{"_TFP", METHOD_0ARGS, /* ACPI 6.0 */
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
{{"_TIP", METHOD_1ARGS(ACPI_TYPE_INTEGER),
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
@@ -959,6 +995,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 5 Int with count */
PACKAGE_INFO(ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 5, 0, 0, 0),
+ {{"_TSN", METHOD_0ARGS, /* ACPI 6.0 */
+ METHOD_RETURNS(ACPI_RTYPE_REFERENCE)}},
+
{{"_TSP", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 2b3c5bd222f1..d49f5c7a20d9 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -251,7 +251,7 @@ extern const u8 _acpi_ctype[];
#define _ACPI_DI 0x04 /* '0'-'9' */
#define _ACPI_LO 0x02 /* 'a'-'z' */
#define _ACPI_PU 0x10 /* punctuation */
-#define _ACPI_SP 0x08 /* space */
+#define _ACPI_SP 0x08 /* space, tab, CR, LF, VT, FF */
#define _ACPI_UP 0x01 /* 'A'-'Z' */
#define _ACPI_XD 0x80 /* '0'-'9', 'A'-'F', 'a'-'f' */
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index d72565a3c646..85bb951430d9 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -116,6 +116,7 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
walk_state =
acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL);
if (!walk_state) {
+ acpi_ps_free_op(op);
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -125,6 +126,7 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
obj_desc->method.aml_length, NULL, 0);
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
+ acpi_ps_free_op(op);
return_ACPI_STATUS(status);
}
@@ -133,9 +135,6 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
/* Parse the method, scan for creation of named objects */
status = acpi_ps_parse_aml(walk_state);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
acpi_ps_delete_parse_tree(op);
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c
index c5214dec4988..f785ea788356 100644
--- a/drivers/acpi/acpica/hwpci.c
+++ b/drivers/acpi/acpica/hwpci.c
@@ -123,7 +123,7 @@ acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
acpi_handle root_pci_device, acpi_handle pci_region)
{
acpi_status status;
- struct acpi_pci_device *list_head = NULL;
+ struct acpi_pci_device *list_head;
ACPI_FUNCTION_TRACE(hw_derive_pci_id);
@@ -177,13 +177,13 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device,
acpi_handle parent_device;
acpi_status status;
struct acpi_pci_device *list_element;
- struct acpi_pci_device *list_head = NULL;
/*
* Ascend namespace branch until the root_pci_device is reached, building
* a list of device nodes. Loop will exit when either the PCI device is
* found, or the root of the namespace is reached.
*/
+ *return_list_head = NULL;
current_device = pci_region;
while (1) {
status = acpi_get_parent(current_device, &parent_device);
@@ -198,7 +198,6 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device,
/* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
if (parent_device == root_pci_device) {
- *return_list_head = list_head;
return (AE_OK);
}
@@ -213,9 +212,9 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device,
/* Put new element at the head of the list */
- list_element->next = list_head;
+ list_element->next = *return_list_head;
list_element->device = parent_device;
- list_head = list_element;
+ *return_list_head = list_element;
current_device = parent_device;
}
diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c
index 8b79958b7aca..9bb251932b45 100644
--- a/drivers/acpi/acpica/nsprepkg.c
+++ b/drivers/acpi/acpica/nsprepkg.c
@@ -316,6 +316,13 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
acpi_ns_check_package_list(info, package, elements, count);
break;
+ case ACPI_PTYPE2_VAR_VAR:
+ /*
+ * Returns a variable list of packages, each with a variable list
+ * of objects.
+ */
+ break;
+
case ACPI_PTYPE2_UUID_PAIR:
/* The package must contain pairs of (UUID + type) */
@@ -487,6 +494,12 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
}
break;
+ case ACPI_PTYPE2_VAR_VAR:
+ /*
+ * Each subpackage has a fixed or variable number of elements
+ */
+ break;
+
case ACPI_PTYPE2_FIXED:
/* Each subpackage has a fixed length */
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index 151fcd95ba84..77d8103d0094 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -497,10 +497,10 @@ acpi_ns_remove_null_elements(struct acpi_evaluate_info *info,
case ACPI_PTYPE2_MIN:
case ACPI_PTYPE2_REV_FIXED:
case ACPI_PTYPE2_FIX_VAR:
-
break;
default:
+ case ACPI_PTYPE2_VAR_VAR:
case ACPI_PTYPE1_FIXED:
case ACPI_PTYPE1_OPTION:
return;
diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c
index 20e1a35169fc..58310907fa7b 100644
--- a/drivers/acpi/acpica/psopinfo.c
+++ b/drivers/acpi/acpica/psopinfo.c
@@ -50,9 +50,6 @@
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psopinfo")
-extern const u8 acpi_gbl_short_op_index[];
-extern const u8 acpi_gbl_long_op_index[];
-
static const u8 acpi_gbl_argument_count[] =
{ 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 };
diff --git a/drivers/acpi/acpica/utfileio.c b/drivers/acpi/acpica/utfileio.c
index 7e1168be39fa..857af824337b 100644
--- a/drivers/acpi/acpica/utfileio.c
+++ b/drivers/acpi/acpica/utfileio.c
@@ -198,11 +198,8 @@ acpi_ut_read_table(FILE * fp,
table_header.length, file_size);
#ifdef ACPI_ASL_COMPILER
- status = fl_check_for_ascii(fp, NULL, FALSE);
- if (ACPI_SUCCESS(status)) {
- acpi_os_printf
- ("File appears to be ASCII only, must be binary\n");
- }
+ acpi_os_printf("File is corrupt or is ASCII text -- "
+ "it must be a binary file\n");
#endif
return (AE_BAD_HEADER);
}
@@ -315,7 +312,7 @@ acpi_ut_read_table_from_file(char *filename, struct acpi_table_header ** table)
/* Get the entire file */
fprintf(stderr,
- "Loading Acpi table from file %10s - Length %.8u (%06X)\n",
+ "Reading ACPI table from file %10s - Length %.8u (0x%06X)\n",
filename, file_size, file_size);
status = acpi_ut_read_table(file, table, &table_length);
diff --git a/drivers/acpi/acpica/uthex.c b/drivers/acpi/acpica/uthex.c
index aa448278ba28..fda8b3def81c 100644
--- a/drivers/acpi/acpica/uthex.c
+++ b/drivers/acpi/acpica/uthex.c
@@ -75,9 +75,9 @@ char acpi_ut_hex_to_ascii_char(u64 integer, u32 position)
/*******************************************************************************
*
- * FUNCTION: acpi_ut_hex_char_to_value
+ * FUNCTION: acpi_ut_ascii_char_to_hex
*
- * PARAMETERS: ascii_char - Hex character in Ascii
+ * PARAMETERS: hex_char - Hex character in Ascii
*
* RETURN: The binary value of the ascii/hex character
*
diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c
index 306e785f9418..98d578753101 100644
--- a/drivers/acpi/acpica/utxferror.c
+++ b/drivers/acpi/acpica/utxferror.c
@@ -107,9 +107,16 @@ acpi_exception(const char *module_name,
va_list arg_list;
ACPI_MSG_REDIRECT_BEGIN;
- acpi_os_printf(ACPI_MSG_EXCEPTION "%s, ",
- acpi_format_exception(status));
+ /* For AE_OK, just print the message */
+
+ if (ACPI_SUCCESS(status)) {
+ acpi_os_printf(ACPI_MSG_EXCEPTION);
+
+ } else {
+ acpi_os_printf(ACPI_MSG_EXCEPTION "%s, ",
+ acpi_format_exception(status));
+ }
va_start(arg_list, format);
acpi_os_vprintf(format, arg_list);
ACPI_MSG_SUFFIX;
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index ed65e9c4b5b0..3670bbab57a3 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -35,6 +35,7 @@
#include <linux/nmi.h>
#include <linux/hardirq.h>
#include <linux/pstore.h>
+#include <linux/vmalloc.h>
#include <acpi/apei.h>
#include "apei-internal.h"
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index e82d0976a5d0..2bfd53cbfe80 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -729,10 +729,10 @@ static struct llist_head ghes_estatus_llist;
static struct irq_work ghes_proc_irq_work;
/*
- * NMI may be triggered on any CPU, so ghes_nmi_lock is used for
- * mutual exclusion.
+ * NMI may be triggered on any CPU, so ghes_in_nmi is used for
+ * having only one concurrent reader.
*/
-static DEFINE_RAW_SPINLOCK(ghes_nmi_lock);
+static atomic_t ghes_in_nmi = ATOMIC_INIT(0);
static LIST_HEAD(ghes_nmi);
@@ -797,73 +797,75 @@ static void ghes_print_queued_estatus(void)
}
}
+/* Save estatus for further processing in IRQ context */
+static void __process_error(struct ghes *ghes)
+{
+#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
+ u32 len, node_len;
+ struct ghes_estatus_node *estatus_node;
+ struct acpi_hest_generic_status *estatus;
+
+ if (ghes_estatus_cached(ghes->estatus))
+ return;
+
+ len = cper_estatus_len(ghes->estatus);
+ node_len = GHES_ESTATUS_NODE_LEN(len);
+
+ estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool, node_len);
+ if (!estatus_node)
+ return;
+
+ estatus_node->ghes = ghes;
+ estatus_node->generic = ghes->generic;
+ estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
+ memcpy(estatus, ghes->estatus, len);
+ llist_add(&estatus_node->llnode, &ghes_estatus_llist);
+#endif
+}
+
+static void __ghes_panic(struct ghes *ghes)
+{
+ oops_begin();
+ ghes_print_queued_estatus();
+ __ghes_print_estatus(KERN_EMERG, ghes->generic, ghes->estatus);
+
+ /* reboot to log the error! */
+ if (panic_timeout == 0)
+ panic_timeout = ghes_panic_timeout;
+ panic("Fatal hardware error!");
+}
+
static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
{
- struct ghes *ghes, *ghes_global = NULL;
- int sev, sev_global = -1;
- int ret = NMI_DONE;
+ struct ghes *ghes;
+ int sev, ret = NMI_DONE;
+
+ if (!atomic_add_unless(&ghes_in_nmi, 1, 1))
+ return ret;
- raw_spin_lock(&ghes_nmi_lock);
list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
if (ghes_read_estatus(ghes, 1)) {
ghes_clear_estatus(ghes);
continue;
}
- sev = ghes_severity(ghes->estatus->error_severity);
- if (sev > sev_global) {
- sev_global = sev;
- ghes_global = ghes;
- }
- ret = NMI_HANDLED;
- }
-
- if (ret == NMI_DONE)
- goto out;
- if (sev_global >= GHES_SEV_PANIC) {
- oops_begin();
- ghes_print_queued_estatus();
- __ghes_print_estatus(KERN_EMERG, ghes_global->generic,
- ghes_global->estatus);
- /* reboot to log the error! */
- if (panic_timeout == 0)
- panic_timeout = ghes_panic_timeout;
- panic("Fatal hardware error!");
- }
+ sev = ghes_severity(ghes->estatus->error_severity);
+ if (sev >= GHES_SEV_PANIC)
+ __ghes_panic(ghes);
- list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
-#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
- u32 len, node_len;
- struct ghes_estatus_node *estatus_node;
- struct acpi_hest_generic_status *estatus;
-#endif
if (!(ghes->flags & GHES_TO_CLEAR))
continue;
-#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
- if (ghes_estatus_cached(ghes->estatus))
- goto next;
- /* Save estatus for further processing in IRQ context */
- len = cper_estatus_len(ghes->estatus);
- node_len = GHES_ESTATUS_NODE_LEN(len);
- estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool,
- node_len);
- if (estatus_node) {
- estatus_node->ghes = ghes;
- estatus_node->generic = ghes->generic;
- estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
- memcpy(estatus, ghes->estatus, len);
- llist_add(&estatus_node->llnode, &ghes_estatus_llist);
- }
-next:
-#endif
+
+ __process_error(ghes);
ghes_clear_estatus(ghes);
+
+ ret = NMI_HANDLED;
}
+
#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
irq_work_queue(&ghes_proc_irq_work);
#endif
-
-out:
- raw_spin_unlock(&ghes_nmi_lock);
+ atomic_dec(&ghes_in_nmi);
return ret;
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 63d43677f644..b3628cc01a53 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -70,6 +70,7 @@ MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
MODULE_DESCRIPTION("ACPI Battery Driver");
MODULE_LICENSE("GPL");
+static async_cookie_t async_cookie;
static int battery_bix_broken_package;
static int battery_notification_delay_ms;
static unsigned int cache_time = 1000;
@@ -338,14 +339,6 @@ static enum power_supply_property energy_battery_props[] = {
POWER_SUPPLY_PROP_SERIAL_NUMBER,
};
-#ifdef CONFIG_ACPI_PROCFS_POWER
-inline char *acpi_battery_units(struct acpi_battery *battery)
-{
- return (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) ?
- "mA" : "mW";
-}
-#endif
-
/* --------------------------------------------------------------------------
Battery Management
-------------------------------------------------------------------------- */
@@ -354,14 +347,14 @@ struct acpi_offsets {
u8 mode; /* int or string? */
};
-static struct acpi_offsets state_offsets[] = {
+static const struct acpi_offsets state_offsets[] = {
{offsetof(struct acpi_battery, state), 0},
{offsetof(struct acpi_battery, rate_now), 0},
{offsetof(struct acpi_battery, capacity_now), 0},
{offsetof(struct acpi_battery, voltage_now), 0},
};
-static struct acpi_offsets info_offsets[] = {
+static const struct acpi_offsets info_offsets[] = {
{offsetof(struct acpi_battery, power_unit), 0},
{offsetof(struct acpi_battery, design_capacity), 0},
{offsetof(struct acpi_battery, full_charge_capacity), 0},
@@ -377,7 +370,7 @@ static struct acpi_offsets info_offsets[] = {
{offsetof(struct acpi_battery, oem_info), 1},
};
-static struct acpi_offsets extended_info_offsets[] = {
+static const struct acpi_offsets extended_info_offsets[] = {
{offsetof(struct acpi_battery, revision), 0},
{offsetof(struct acpi_battery, power_unit), 0},
{offsetof(struct acpi_battery, design_capacity), 0},
@@ -402,7 +395,7 @@ static struct acpi_offsets extended_info_offsets[] = {
static int extract_package(struct acpi_battery *battery,
union acpi_object *package,
- struct acpi_offsets *offsets, int num)
+ const struct acpi_offsets *offsets, int num)
{
int i;
union acpi_object *element;
@@ -792,6 +785,12 @@ static void acpi_battery_refresh(struct acpi_battery *battery)
#ifdef CONFIG_ACPI_PROCFS_POWER
static struct proc_dir_entry *acpi_battery_dir;
+static const char *acpi_battery_units(const struct acpi_battery *battery)
+{
+ return (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) ?
+ "mA" : "mW";
+}
+
static int acpi_battery_print_info(struct seq_file *seq, int result)
{
struct acpi_battery *battery = seq->private;
@@ -1125,19 +1124,21 @@ static int battery_notify(struct notifier_block *nb,
return 0;
}
-static int battery_bix_broken_package_quirk(const struct dmi_system_id *d)
+static int __init
+battery_bix_broken_package_quirk(const struct dmi_system_id *d)
{
battery_bix_broken_package = 1;
return 0;
}
-static int battery_notification_delay_quirk(const struct dmi_system_id *d)
+static int __init
+battery_notification_delay_quirk(const struct dmi_system_id *d)
{
battery_notification_delay_ms = 1000;
return 0;
}
-static struct dmi_system_id bat_dmi_table[] = {
+static const struct dmi_system_id bat_dmi_table[] __initconst = {
{
.callback = battery_bix_broken_package_quirk,
.ident = "NEC LZ750/LS",
@@ -1292,33 +1293,34 @@ static struct acpi_driver acpi_battery_driver = {
static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie)
{
- if (acpi_disabled)
- return;
+ int result;
dmi_check_system(bat_dmi_table);
-
+
#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_battery_dir = acpi_lock_battery_dir();
if (!acpi_battery_dir)
return;
#endif
- if (acpi_bus_register_driver(&acpi_battery_driver) < 0) {
+ result = acpi_bus_register_driver(&acpi_battery_driver);
#ifdef CONFIG_ACPI_PROCFS_POWER
+ if (result < 0)
acpi_unlock_battery_dir(acpi_battery_dir);
#endif
- return;
- }
- return;
}
static int __init acpi_battery_init(void)
{
- async_schedule(acpi_battery_init_async, NULL);
+ if (acpi_disabled)
+ return -ENODEV;
+
+ async_cookie = async_schedule(acpi_battery_init_async, NULL);
return 0;
}
static void __exit acpi_battery_exit(void)
{
+ async_synchronize_cookie(async_cookie);
acpi_bus_unregister_driver(&acpi_battery_driver);
#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_unlock_battery_dir(acpi_battery_dir);
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index c412fdb28d34..513e7230e3d0 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -470,6 +470,16 @@ static int __init acpi_bus_init_irq(void)
return 0;
}
+/**
+ * acpi_early_init - Initialize ACPICA and populate the ACPI namespace.
+ *
+ * The ACPI tables are accessible after this, but the handling of events has not
+ * been initialized and the global lock is not available yet, so AML should not
+ * be executed at this point.
+ *
+ * Doing this before switching the EFI runtime services to virtual mode allows
+ * the EfiBootServices memory to be freed slightly earlier on boot.
+ */
void __init acpi_early_init(void)
{
acpi_status status;
@@ -533,26 +543,42 @@ void __init acpi_early_init(void)
acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
}
#endif
+ return;
+
+ error0:
+ disable_acpi();
+}
+
+/**
+ * acpi_subsystem_init - Finalize the early initialization of ACPI.
+ *
+ * Switch over the platform to the ACPI mode (if possible), initialize the
+ * handling of ACPI events, install the interrupt and global lock handlers.
+ *
+ * Doing this too early is generally unsafe, but at the same time it needs to be
+ * done before all things that really depend on ACPI. The right spot appears to
+ * be before finalizing the EFI initialization.
+ */
+void __init acpi_subsystem_init(void)
+{
+ acpi_status status;
+
+ if (acpi_disabled)
+ return;
status = acpi_enable_subsystem(~ACPI_NO_ACPI_ENABLE);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX "Unable to enable ACPI\n");
- goto error0;
+ disable_acpi();
+ } else {
+ /*
+ * If the system is using ACPI then we can be reasonably
+ * confident that any regulators are managed by the firmware
+ * so tell the regulator core it has everything it needs to
+ * know.
+ */
+ regulator_has_full_constraints();
}
-
- /*
- * If the system is using ACPI then we can be reasonably
- * confident that any regulators are managed by the firmware
- * so tell the regulator core it has everything it needs to
- * know.
- */
- regulator_has_full_constraints();
-
- return;
-
- error0:
- disable_acpi();
- return;
}
static int __init acpi_bus_init(void)
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 735db11a9b00..717afcdb5f4a 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -98,17 +98,16 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
/*
* The power resources settings may indicate a power state
- * shallower than the actual power state of the device.
+ * shallower than the actual power state of the device, because
+ * the same power resources may be referenced by other devices.
*
- * Moreover, on systems predating ACPI 4.0, if the device
- * doesn't depend on any power resources and _PSC returns 3,
- * that means "power off". We need to maintain compatibility
- * with those systems.
+ * For systems predating ACPI 4.0 we assume that D3hot is the
+ * deepest state that can be supported.
*/
if (psc > result && psc < ACPI_STATE_D3_COLD)
result = psc;
else if (result == ACPI_STATE_UNKNOWN)
- result = psc > ACPI_STATE_D2 ? ACPI_STATE_D3_COLD : psc;
+ result = psc > ACPI_STATE_D2 ? ACPI_STATE_D3_HOT : psc;
}
/*
@@ -153,8 +152,8 @@ static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state)
*/
int acpi_device_set_power(struct acpi_device *device, int state)
{
+ int target_state = state;
int result = 0;
- bool cut_power = false;
if (!device || !device->flags.power_manageable
|| (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
@@ -169,11 +168,21 @@ int acpi_device_set_power(struct acpi_device *device, int state)
return 0;
}
- if (!device->power.states[state].flags.valid) {
+ if (state == ACPI_STATE_D3_COLD) {
+ /*
+ * For transitions to D3cold we need to execute _PS3 and then
+ * possibly drop references to the power resources in use.
+ */
+ state = ACPI_STATE_D3_HOT;
+ /* If _PR3 is not available, use D3hot as the target state. */
+ if (!device->power.states[ACPI_STATE_D3_COLD].flags.valid)
+ target_state = state;
+ } else if (!device->power.states[state].flags.valid) {
dev_warn(&device->dev, "Power state %s not supported\n",
acpi_power_state_string(state));
return -ENODEV;
}
+
if (!device->power.flags.ignore_parent &&
device->parent && (state < device->parent->power.state)) {
dev_warn(&device->dev,
@@ -183,39 +192,38 @@ int acpi_device_set_power(struct acpi_device *device, int state)
return -ENODEV;
}
- /* For D3cold we should first transition into D3hot. */
- if (state == ACPI_STATE_D3_COLD
- && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) {
- state = ACPI_STATE_D3_HOT;
- cut_power = true;
- }
-
- if (state < device->power.state && state != ACPI_STATE_D0
- && device->power.state >= ACPI_STATE_D3_HOT) {
- dev_warn(&device->dev,
- "Cannot transition to non-D0 state from D3\n");
- return -ENODEV;
- }
-
/*
* Transition Power
* ----------------
- * In accordance with the ACPI specification first apply power (via
- * power resources) and then evaluate _PSx.
+ * In accordance with ACPI 6, _PSx is executed before manipulating power
+ * resources, unless the target state is D0, in which case _PS0 is
+ * supposed to be executed after turning the power resources on.
*/
- if (device->power.flags.power_resources) {
- result = acpi_power_transition(device, state);
+ if (state > ACPI_STATE_D0) {
+ /*
+ * According to ACPI 6, devices cannot go from lower-power
+ * (deeper) states to higher-power (shallower) states.
+ */
+ if (state < device->power.state) {
+ dev_warn(&device->dev, "Cannot transition from %s to %s\n",
+ acpi_power_state_string(device->power.state),
+ acpi_power_state_string(state));
+ return -ENODEV;
+ }
+
+ result = acpi_dev_pm_explicit_set(device, state);
if (result)
goto end;
- }
- result = acpi_dev_pm_explicit_set(device, state);
- if (result)
- goto end;
- if (cut_power) {
- device->power.state = state;
- state = ACPI_STATE_D3_COLD;
- result = acpi_power_transition(device, state);
+ if (device->power.flags.power_resources)
+ result = acpi_power_transition(device, target_state);
+ } else {
+ if (device->power.flags.power_resources) {
+ result = acpi_power_transition(device, ACPI_STATE_D0);
+ if (result)
+ goto end;
+ }
+ result = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0);
}
end:
@@ -264,13 +272,24 @@ int acpi_bus_init_power(struct acpi_device *device)
return result;
if (state < ACPI_STATE_D3_COLD && device->power.flags.power_resources) {
+ /* Reference count the power resources. */
result = acpi_power_on_resources(device, state);
if (result)
return result;
- result = acpi_dev_pm_explicit_set(device, state);
- if (result)
- return result;
+ if (state == ACPI_STATE_D0) {
+ /*
+ * If _PSC is not present and the state inferred from
+ * power resources appears to be D0, it still may be
+ * necessary to execute _PS0 at this point, because
+ * another device using the same power resources may
+ * have been put into D0 previously and that's why we
+ * see D0 here.
+ */
+ result = acpi_dev_pm_explicit_set(device, state);
+ if (result)
+ return result;
+ }
} else if (state == ACPI_STATE_UNKNOWN) {
/*
* No power resources and missing _PSC? Cross fingers and make
@@ -603,12 +622,12 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in)
if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3_COLD)
return -EINVAL;
- if (d_max_in > ACPI_STATE_D3_HOT) {
+ if (d_max_in > ACPI_STATE_D2) {
enum pm_qos_flags_status stat;
stat = dev_pm_qos_flags(dev, PM_QOS_FLAG_NO_POWER_OFF);
if (stat == PM_QOS_FLAGS_ALL)
- d_max_in = ACPI_STATE_D3_HOT;
+ d_max_in = ACPI_STATE_D2;
}
adev = ACPI_COMPANION(dev);
@@ -953,6 +972,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
*/
void acpi_subsys_complete(struct device *dev)
{
+ pm_generic_complete(dev);
/*
* If the device had been runtime-suspended before the system went into
* the sleep state it is going out of and it has never been resumed till
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 5e8fed448850..9d4761d2f6b7 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -59,6 +59,38 @@
#define ACPI_EC_FLAG_BURST 0x10 /* burst mode */
#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
+/*
+ * The SCI_EVT clearing timing is not defined by the ACPI specification.
+ * This leads to lots of practical timing issues for the host EC driver.
+ * The following variations are defined (from the target EC firmware's
+ * perspective):
+ * STATUS: After indicating SCI_EVT edge triggered IRQ to the host, the
+ * target can clear SCI_EVT at any time so long as the host can see
+ * the indication by reading the status register (EC_SC). So the
+ * host should re-check SCI_EVT after the first time the SCI_EVT
+ * indication is seen, which is the same time the query request
+ * (QR_EC) is written to the command register (EC_CMD). SCI_EVT set
+ * at any later time could indicate another event. Normally such
+ * kind of EC firmware has implemented an event queue and will
+ * return 0x00 to indicate "no outstanding event".
+ * QUERY: After seeing the query request (QR_EC) written to the command
+ * register (EC_CMD) by the host and having prepared the responding
+ * event value in the data register (EC_DATA), the target can safely
+ * clear SCI_EVT because the target can confirm that the current
+ * event is being handled by the host. The host then should check
+ * SCI_EVT right after reading the event response from the data
+ * register (EC_DATA).
+ * EVENT: After seeing the event response read from the data register
+ * (EC_DATA) by the host, the target can clear SCI_EVT. As the
+ * target requires time to notice the change in the data register
+ * (EC_DATA), the host may be required to wait additional guarding
+ * time before checking the SCI_EVT again. Such guarding may not be
+ * necessary if the host is notified via another IRQ.
+ */
+#define ACPI_EC_EVT_TIMING_STATUS 0x00
+#define ACPI_EC_EVT_TIMING_QUERY 0x01
+#define ACPI_EC_EVT_TIMING_EVENT 0x02
+
/* EC commands */
enum ec_command {
ACPI_EC_COMMAND_READ = 0x80,
@@ -70,13 +102,13 @@ enum ec_command {
#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
-#define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */
-#define ACPI_EC_UDELAY_POLL 1000 /* Wait 1ms for EC transaction polling */
+#define ACPI_EC_UDELAY_POLL 550 /* Wait 1ms for EC transaction polling */
#define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query
* when trying to clear the EC */
enum {
EC_FLAGS_QUERY_PENDING, /* Query is pending */
+ EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */
EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and
* OpReg are installed */
EC_FLAGS_STARTED, /* Driver is started */
@@ -93,6 +125,16 @@ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
module_param(ec_delay, uint, 0644);
MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
+static bool ec_busy_polling __read_mostly;
+module_param(ec_busy_polling, bool, 0644);
+MODULE_PARM_DESC(ec_busy_polling, "Use busy polling to advance EC transaction");
+
+static unsigned int ec_polling_guard __read_mostly = ACPI_EC_UDELAY_POLL;
+module_param(ec_polling_guard, uint, 0644);
+MODULE_PARM_DESC(ec_polling_guard, "Guard time(us) between EC accesses in polling modes");
+
+static unsigned int ec_event_clearing __read_mostly = ACPI_EC_EVT_TIMING_QUERY;
+
/*
* If the number of false interrupts per one transaction exceeds
* this threshold, will think there is a GPE storm happened and
@@ -121,7 +163,6 @@ struct transaction {
u8 wlen;
u8 rlen;
u8 flags;
- unsigned long timestamp;
};
static int acpi_ec_query(struct acpi_ec *ec, u8 *data);
@@ -130,7 +171,6 @@ static void advance_transaction(struct acpi_ec *ec);
struct acpi_ec *boot_ec, *first_ec;
EXPORT_SYMBOL(first_ec);
-static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
@@ -218,7 +258,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
{
u8 x = inb(ec->data_addr);
- ec->curr->timestamp = jiffies;
+ ec->timestamp = jiffies;
ec_dbg_raw("EC_DATA(R) = 0x%2.2x", x);
return x;
}
@@ -227,14 +267,14 @@ static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
{
ec_dbg_raw("EC_SC(W) = 0x%2.2x", command);
outb(command, ec->command_addr);
- ec->curr->timestamp = jiffies;
+ ec->timestamp = jiffies;
}
static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
{
ec_dbg_raw("EC_DATA(W) = 0x%2.2x", data);
outb(data, ec->data_addr);
- ec->curr->timestamp = jiffies;
+ ec->timestamp = jiffies;
}
#ifdef DEBUG
@@ -267,7 +307,7 @@ static inline bool acpi_ec_is_gpe_raised(struct acpi_ec *ec)
acpi_event_status gpe_status = 0;
(void)acpi_get_gpe_status(NULL, ec->gpe, &gpe_status);
- return (gpe_status & ACPI_EVENT_FLAG_SET) ? true : false;
+ return (gpe_status & ACPI_EVENT_FLAG_STATUS_SET) ? true : false;
}
static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open)
@@ -379,19 +419,49 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
static void acpi_ec_submit_query(struct acpi_ec *ec)
{
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
- ec_dbg_req("Event started");
+ ec_dbg_evt("Command(%s) submitted/blocked",
+ acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
+ ec->nr_pending_queries++;
schedule_work(&ec->work);
}
}
static void acpi_ec_complete_query(struct acpi_ec *ec)
{
- if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
+ if (test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
- ec_dbg_req("Event stopped");
+ ec_dbg_evt("Command(%s) unblocked",
+ acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
}
}
+static bool acpi_ec_guard_event(struct acpi_ec *ec)
+{
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS ||
+ ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY ||
+ !test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags) ||
+ (ec->curr && ec->curr->command == ACPI_EC_COMMAND_QUERY))
+ return false;
+
+ /*
+ * Postpone the query submission to allow the firmware to proceed,
+ * we shouldn't check SCI_EVT before the firmware reflagging it.
+ */
+ return true;
+}
+
+static int ec_transaction_polled(struct acpi_ec *ec)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&ec->lock, flags);
+ if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_POLL))
+ ret = 1;
+ spin_unlock_irqrestore(&ec->lock, flags);
+ return ret;
+}
+
static int ec_transaction_completed(struct acpi_ec *ec)
{
unsigned long flags;
@@ -404,6 +474,22 @@ static int ec_transaction_completed(struct acpi_ec *ec)
return ret;
}
+static inline void ec_transaction_transition(struct acpi_ec *ec, unsigned long flag)
+{
+ ec->curr->flags |= flag;
+ if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS &&
+ flag == ACPI_EC_COMMAND_POLL)
+ acpi_ec_complete_query(ec);
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY &&
+ flag == ACPI_EC_COMMAND_COMPLETE)
+ acpi_ec_complete_query(ec);
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
+ flag == ACPI_EC_COMMAND_COMPLETE)
+ set_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags);
+ }
+}
+
static void advance_transaction(struct acpi_ec *ec)
{
struct transaction *t;
@@ -420,6 +506,18 @@ static void advance_transaction(struct acpi_ec *ec)
acpi_ec_clear_gpe(ec);
status = acpi_ec_read_status(ec);
t = ec->curr;
+ /*
+ * Another IRQ or a guarded polling mode advancement is detected,
+ * the next QR_EC submission is then allowed.
+ */
+ if (!t || !(t->flags & ACPI_EC_COMMAND_POLL)) {
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
+ (!ec->nr_pending_queries ||
+ test_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags))) {
+ clear_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags);
+ acpi_ec_complete_query(ec);
+ }
+ }
if (!t)
goto err;
if (t->flags & ACPI_EC_COMMAND_POLL) {
@@ -432,17 +530,17 @@ static void advance_transaction(struct acpi_ec *ec)
if ((status & ACPI_EC_FLAG_OBF) == 1) {
t->rdata[t->ri++] = acpi_ec_read_data(ec);
if (t->rlen == t->ri) {
- t->flags |= ACPI_EC_COMMAND_COMPLETE;
+ ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
if (t->command == ACPI_EC_COMMAND_QUERY)
- ec_dbg_req("Command(%s) hardware completion",
- acpi_ec_cmd_string(t->command));
+ ec_dbg_evt("Command(%s) completed by hardware",
+ acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
wakeup = true;
}
} else
goto err;
} else if (t->wlen == t->wi &&
(status & ACPI_EC_FLAG_IBF) == 0) {
- t->flags |= ACPI_EC_COMMAND_COMPLETE;
+ ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
wakeup = true;
}
goto out;
@@ -450,17 +548,15 @@ static void advance_transaction(struct acpi_ec *ec)
if (EC_FLAGS_QUERY_HANDSHAKE &&
!(status & ACPI_EC_FLAG_SCI) &&
(t->command == ACPI_EC_COMMAND_QUERY)) {
- t->flags |= ACPI_EC_COMMAND_POLL;
- acpi_ec_complete_query(ec);
+ ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL);
t->rdata[t->ri++] = 0x00;
- t->flags |= ACPI_EC_COMMAND_COMPLETE;
- ec_dbg_req("Command(%s) software completion",
- acpi_ec_cmd_string(t->command));
+ ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
+ ec_dbg_evt("Command(%s) completed by software",
+ acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
wakeup = true;
} else if ((status & ACPI_EC_FLAG_IBF) == 0) {
acpi_ec_write_cmd(ec, t->command);
- t->flags |= ACPI_EC_COMMAND_POLL;
- acpi_ec_complete_query(ec);
+ ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL);
} else
goto err;
goto out;
@@ -490,8 +586,39 @@ static void start_transaction(struct acpi_ec *ec)
{
ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0;
ec->curr->flags = 0;
- ec->curr->timestamp = jiffies;
- advance_transaction(ec);
+}
+
+static int ec_guard(struct acpi_ec *ec)
+{
+ unsigned long guard = usecs_to_jiffies(ec_polling_guard);
+ unsigned long timeout = ec->timestamp + guard;
+
+ do {
+ if (ec_busy_polling) {
+ /* Perform busy polling */
+ if (ec_transaction_completed(ec))
+ return 0;
+ udelay(jiffies_to_usecs(guard));
+ } else {
+ /*
+ * Perform wait polling
+ *
+ * For SCI_EVT clearing timing of "event",
+ * performing guarding before re-checking the
+ * SCI_EVT. Otherwise, such guarding is not needed
+ * due to the old practices.
+ */
+ if (!ec_transaction_polled(ec) &&
+ !acpi_ec_guard_event(ec))
+ break;
+ if (wait_event_timeout(ec->wait,
+ ec_transaction_completed(ec),
+ guard))
+ return 0;
+ }
+ /* Guard the register accesses for the polling modes */
+ } while (time_before(jiffies, timeout));
+ return -ETIME;
}
static int ec_poll(struct acpi_ec *ec)
@@ -502,25 +629,11 @@ static int ec_poll(struct acpi_ec *ec)
while (repeat--) {
unsigned long delay = jiffies +
msecs_to_jiffies(ec_delay);
- unsigned long usecs = ACPI_EC_UDELAY_POLL;
do {
- /* don't sleep with disabled interrupts */
- if (EC_FLAGS_MSI || irqs_disabled()) {
- usecs = ACPI_EC_MSI_UDELAY;
- udelay(usecs);
- if (ec_transaction_completed(ec))
- return 0;
- } else {
- if (wait_event_timeout(ec->wait,
- ec_transaction_completed(ec),
- usecs_to_jiffies(usecs)))
- return 0;
- }
+ if (!ec_guard(ec))
+ return 0;
spin_lock_irqsave(&ec->lock, flags);
- if (time_after(jiffies,
- ec->curr->timestamp +
- usecs_to_jiffies(usecs)))
- advance_transaction(ec);
+ advance_transaction(ec);
spin_unlock_irqrestore(&ec->lock, flags);
} while (time_before(jiffies, delay));
pr_debug("controller reset, restart transaction\n");
@@ -537,8 +650,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
unsigned long tmp;
int ret = 0;
- if (EC_FLAGS_MSI)
- udelay(ACPI_EC_MSI_UDELAY);
/* start transaction */
spin_lock_irqsave(&ec->lock, tmp);
/* Enable GPE for command processing (IBF=0/OBF=1) */
@@ -552,7 +663,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
ec_dbg_req("Command(%s) started", acpi_ec_cmd_string(t->command));
start_transaction(ec);
spin_unlock_irqrestore(&ec->lock, tmp);
+
ret = ec_poll(ec);
+
spin_lock_irqsave(&ec->lock, tmp);
if (t->irq_count == ec_storm_threshold)
acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
@@ -575,6 +688,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
return -EINVAL;
if (t->rdata)
memset(t->rdata, 0, t->rlen);
+
mutex_lock(&ec->mutex);
if (ec->global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
@@ -586,8 +700,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
status = acpi_ec_transaction_unlocked(ec, t);
- if (test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags))
- msleep(1);
if (ec->global_lock)
acpi_release_global_lock(glk);
unlock:
@@ -923,11 +1035,54 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
return result;
}
-static void acpi_ec_gpe_poller(struct work_struct *work)
+static void acpi_ec_check_event(struct acpi_ec *ec)
{
+ unsigned long flags;
+
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT) {
+ if (ec_guard(ec)) {
+ spin_lock_irqsave(&ec->lock, flags);
+ /*
+ * Take care of the SCI_EVT unless no one else is
+ * taking care of it.
+ */
+ if (!ec->curr)
+ advance_transaction(ec);
+ spin_unlock_irqrestore(&ec->lock, flags);
+ }
+ }
+}
+
+static void acpi_ec_event_handler(struct work_struct *work)
+{
+ unsigned long flags;
struct acpi_ec *ec = container_of(work, struct acpi_ec, work);
- acpi_ec_query(ec, NULL);
+ ec_dbg_evt("Event started");
+
+ spin_lock_irqsave(&ec->lock, flags);
+ while (ec->nr_pending_queries) {
+ spin_unlock_irqrestore(&ec->lock, flags);
+ (void)acpi_ec_query(ec, NULL);
+ spin_lock_irqsave(&ec->lock, flags);
+ ec->nr_pending_queries--;
+ /*
+ * Before exit, make sure that this work item can be
+ * scheduled again. There might be QR_EC failures, leaving
+ * EC_FLAGS_QUERY_PENDING uncleared and preventing this work
+ * item from being scheduled again.
+ */
+ if (!ec->nr_pending_queries) {
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS ||
+ ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY)
+ acpi_ec_complete_query(ec);
+ }
+ }
+ spin_unlock_irqrestore(&ec->lock, flags);
+
+ ec_dbg_evt("Event stopped");
+
+ acpi_ec_check_event(ec);
}
static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
@@ -961,7 +1116,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
if (function != ACPI_READ && function != ACPI_WRITE)
return AE_BAD_PARAMETER;
- if (EC_FLAGS_MSI || bits > 8)
+ if (ec_busy_polling || bits > 8)
acpi_ec_burst_enable(ec);
for (i = 0; i < bytes; ++i, ++address, ++value)
@@ -969,7 +1124,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
acpi_ec_read(ec, address, value) :
acpi_ec_write(ec, address, *value);
- if (EC_FLAGS_MSI || bits > 8)
+ if (ec_busy_polling || bits > 8)
acpi_ec_burst_disable(ec);
switch (result) {
@@ -1002,7 +1157,8 @@ static struct acpi_ec *make_acpi_ec(void)
init_waitqueue_head(&ec->wait);
INIT_LIST_HEAD(&ec->list);
spin_lock_init(&ec->lock);
- INIT_WORK(&ec->work, acpi_ec_gpe_poller);
+ INIT_WORK(&ec->work, acpi_ec_event_handler);
+ ec->timestamp = jiffies;
return ec;
}
@@ -1237,30 +1393,13 @@ static int ec_validate_ecdt(const struct dmi_system_id *id)
return 0;
}
-/* MSI EC needs special treatment, enable it */
-static int ec_flag_msi(const struct dmi_system_id *id)
-{
- pr_debug("Detected MSI hardware, enabling workarounds.\n");
- EC_FLAGS_MSI = 1;
- EC_FLAGS_VALIDATE_ECDT = 1;
- return 0;
-}
-
-/*
- * Clevo M720 notebook actually works ok with IRQ mode, if we lifted
- * the GPE storm threshold back to 20
- */
-static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
-{
- pr_debug("Setting the EC GPE storm threshold to 20\n");
- ec_storm_threshold = 20;
- return 0;
-}
-
+#if 0
/*
- * Acer EC firmware refuses to respond QR_EC when SCI_EVT is not set, for
- * which case, we complete the QR_EC without issuing it to the firmware.
- * https://bugzilla.kernel.org/show_bug.cgi?id=86211
+ * Some EC firmware variations refuses to respond QR_EC when SCI_EVT is not
+ * set, for which case, we complete the QR_EC without issuing it to the
+ * firmware.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=82611
+ * https://bugzilla.kernel.org/show_bug.cgi?id=97381
*/
static int ec_flag_query_handshake(const struct dmi_system_id *id)
{
@@ -1268,6 +1407,7 @@ static int ec_flag_query_handshake(const struct dmi_system_id *id)
EC_FLAGS_QUERY_HANDSHAKE = 1;
return 0;
}
+#endif
/*
* On some hardware it is necessary to clear events accumulated by the EC during
@@ -1290,6 +1430,7 @@ static int ec_clear_on_resume(const struct dmi_system_id *id)
{
pr_debug("Detected system needing EC poll on resume.\n");
EC_FLAGS_CLEAR_ON_RESUME = 1;
+ ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS;
return 0;
}
@@ -1299,29 +1440,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
DMI_MATCH(DMI_BOARD_NAME, "JFL92") }, NULL},
{
- ec_flag_msi, "MSI hardware", {
- DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star")}, NULL},
- {
- ec_flag_msi, "MSI hardware", {
- DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star")}, NULL},
- {
- ec_flag_msi, "MSI hardware", {
- DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star")}, NULL},
- {
- ec_flag_msi, "MSI hardware", {
- DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR")}, NULL},
- {
- ec_flag_msi, "Quanta hardware", {
- DMI_MATCH(DMI_SYS_VENDOR, "Quanta"),
- DMI_MATCH(DMI_PRODUCT_NAME, "TW8/SW8/DW8"),}, NULL},
- {
- ec_flag_msi, "Quanta hardware", {
- DMI_MATCH(DMI_SYS_VENDOR, "Quanta"),
- DMI_MATCH(DMI_PRODUCT_NAME, "TW9/SW9"),}, NULL},
- {
- ec_flag_msi, "Clevo W350etq", {
- DMI_MATCH(DMI_SYS_VENDOR, "CLEVO CO."),
- DMI_MATCH(DMI_PRODUCT_NAME, "W35_37ET"),}, NULL},
+ ec_validate_ecdt, "MSI MS-171F", {
+ DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL},
{
ec_validate_ecdt, "ASUS hardware", {
DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
@@ -1329,10 +1450,6 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
ec_validate_ecdt, "ASUS hardware", {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc.") }, NULL},
{
- ec_enlarge_storm_threshold, "CLEVO hardware", {
- DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."),
- DMI_MATCH(DMI_PRODUCT_NAME, "M720T/M730T"),}, NULL},
- {
ec_skip_dsdt_scan, "HP Folio 13", {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13"),}, NULL},
@@ -1343,9 +1460,6 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
{
ec_clear_on_resume, "Samsung hardware", {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
- {
- ec_flag_query_handshake, "Acer hardware", {
- DMI_MATCH(DMI_SYS_VENDOR, "Acer"), }, NULL},
{},
};
@@ -1427,6 +1541,43 @@ error:
return -ENODEV;
}
+static int param_set_event_clearing(const char *val, struct kernel_param *kp)
+{
+ int result = 0;
+
+ if (!strncmp(val, "status", sizeof("status") - 1)) {
+ ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS;
+ pr_info("Assuming SCI_EVT clearing on EC_SC accesses\n");
+ } else if (!strncmp(val, "query", sizeof("query") - 1)) {
+ ec_event_clearing = ACPI_EC_EVT_TIMING_QUERY;
+ pr_info("Assuming SCI_EVT clearing on QR_EC writes\n");
+ } else if (!strncmp(val, "event", sizeof("event") - 1)) {
+ ec_event_clearing = ACPI_EC_EVT_TIMING_EVENT;
+ pr_info("Assuming SCI_EVT clearing on event reads\n");
+ } else
+ result = -EINVAL;
+ return result;
+}
+
+static int param_get_event_clearing(char *buffer, struct kernel_param *kp)
+{
+ switch (ec_event_clearing) {
+ case ACPI_EC_EVT_TIMING_STATUS:
+ return sprintf(buffer, "status");
+ case ACPI_EC_EVT_TIMING_QUERY:
+ return sprintf(buffer, "query");
+ case ACPI_EC_EVT_TIMING_EVENT:
+ return sprintf(buffer, "event");
+ default:
+ return sprintf(buffer, "invalid");
+ }
+ return 0;
+}
+
+module_param_call(ec_event_clearing, param_set_event_clearing, param_get_event_clearing,
+ NULL, 0644);
+MODULE_PARM_DESC(ec_event_clearing, "Assumed SCI_EVT clearing timing");
+
static struct acpi_driver acpi_ec_driver = {
.name = "ec",
.class = ACPI_EC_CLASS,
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 7a36f02598a6..bea0bbaafa97 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -158,8 +158,9 @@ static int fan_get_state(struct acpi_device *device, unsigned long *state)
if (result)
return result;
- *state = (acpi_state == ACPI_STATE_D3_COLD ? 0 :
- (acpi_state == ACPI_STATE_D0 ? 1 : -1));
+ *state = acpi_state == ACPI_STATE_D3_COLD
+ || acpi_state == ACPI_STATE_D3_HOT ?
+ 0 : (acpi_state == ACPI_STATE_D0 ? 1 : -1);
return 0;
}
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 39c485b0c25c..b9657af751d1 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/rwsem.h>
#include <linux/acpi.h>
+#include <linux/dma-mapping.h>
#include "internal.h"
@@ -167,6 +168,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
struct list_head *physnode_list;
unsigned int node_id;
int retval = -EINVAL;
+ bool coherent;
if (has_acpi_companion(dev)) {
if (acpi_dev) {
@@ -223,6 +225,9 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
if (!has_acpi_companion(dev))
ACPI_COMPANION_SET(dev, acpi_dev);
+ if (acpi_check_dma(acpi_dev, &coherent))
+ arch_setup_dma_ops(dev, 0, 0, NULL, coherent);
+
acpi_physnode_link_name(physical_node_name, node_id);
retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
physical_node_name);
diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c
index aafe3ca829c2..a322710b5ba4 100644
--- a/drivers/acpi/hed.c
+++ b/drivers/acpi/hed.c
@@ -27,7 +27,7 @@
#include <linux/acpi.h>
#include <acpi/hed.h>
-static struct acpi_device_id acpi_hed_ids[] = {
+static const struct acpi_device_id acpi_hed_ids[] = {
{"PNP0C33", 0},
{"", 0},
};
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index ba4a61e964be..787c629bc9b4 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -138,6 +138,8 @@ struct acpi_ec {
struct transaction *curr;
spinlock_t lock;
struct work_struct work;
+ unsigned long timestamp;
+ unsigned long nr_pending_queries;
};
extern struct acpi_ec *first_ec;
@@ -182,15 +184,10 @@ static inline void suspend_nvs_restore(void) {}
#endif
/*--------------------------------------------------------------------------
- Video
- -------------------------------------------------------------------------- */
-#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
-bool acpi_osi_is_win8(void);
-#endif
-
-/*--------------------------------------------------------------------------
Device properties
-------------------------------------------------------------------------- */
+#define ACPI_DT_NAMESPACE_HID "PRP0001"
+
void acpi_init_properties(struct acpi_device *adev);
void acpi_free_properties(struct acpi_device *adev);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 7ccba395c9dd..a5dc9034efee 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -175,11 +175,7 @@ static void __init acpi_request_region (struct acpi_generic_address *gas,
if (!addr || !length)
return;
- /* Resources are never freed */
- if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
- request_region(addr, length, desc);
- else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
- request_mem_region(addr, length, desc);
+ acpi_reserve_region(addr, length, gas->space_id, 0, desc);
}
static void __init acpi_reserve_resources(void)
@@ -540,7 +536,7 @@ static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN];
acpi_status
acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
- acpi_string * new_val)
+ char **new_val)
{
if (!init_val || !new_val)
return AE_BAD_PARAMETER;
@@ -1684,6 +1680,12 @@ int acpi_resources_are_enforced(void)
}
EXPORT_SYMBOL(acpi_resources_are_enforced);
+bool acpi_osi_is_win8(void)
+{
+ return acpi_gbl_osi_data >= ACPI_OSI_WIN_8;
+}
+EXPORT_SYMBOL(acpi_osi_is_win8);
+
/*
* Deallocate the memory for a spinlock.
*/
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index b1def411c0b8..304eccb0ae5c 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -44,7 +44,6 @@
ACPI_MODULE_NAME("pci_irq");
struct acpi_prt_entry {
- struct list_head list;
struct acpi_pci_id id;
u8 pin;
acpi_handle link;
@@ -163,7 +162,7 @@ static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev,
{
int segment = pci_domain_nr(dev->bus);
int bus = dev->bus->number;
- int device = PCI_SLOT(dev->devfn);
+ int device = pci_ari_enabled(dev->bus) ? 0 : PCI_SLOT(dev->devfn);
struct acpi_prt_entry *entry;
if (((prt->address >> 16) & 0xffff) != device ||
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index e0bcfb642b52..93eac53b5110 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -684,7 +684,8 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
}
}
- *state = ACPI_STATE_D3_COLD;
+ *state = device->power.states[ACPI_STATE_D3_COLD].flags.valid ?
+ ACPI_STATE_D3_COLD : ACPI_STATE_D3_HOT;
return 0;
}
@@ -710,8 +711,6 @@ int acpi_power_transition(struct acpi_device *device, int state)
|| (device->power.state > ACPI_STATE_D3_COLD))
return -ENODEV;
- /* TBD: Resources must be ordered. */
-
/*
* First we reference all power resources required in the target list
* (e.g. so the device doesn't lose power while transitioning). Then,
@@ -761,6 +760,25 @@ static void acpi_power_sysfs_remove(struct acpi_device *device)
device_remove_file(&device->dev, &dev_attr_resource_in_use);
}
+static void acpi_power_add_resource_to_list(struct acpi_power_resource *resource)
+{
+ mutex_lock(&power_resource_list_lock);
+
+ if (!list_empty(&acpi_power_resource_list)) {
+ struct acpi_power_resource *r;
+
+ list_for_each_entry(r, &acpi_power_resource_list, list_node)
+ if (r->order > resource->order) {
+ list_add_tail(&resource->list_node, &r->list_node);
+ goto out;
+ }
+ }
+ list_add_tail(&resource->list_node, &acpi_power_resource_list);
+
+ out:
+ mutex_unlock(&power_resource_list_lock);
+}
+
int acpi_add_power_resource(acpi_handle handle)
{
struct acpi_power_resource *resource;
@@ -811,9 +829,7 @@ int acpi_add_power_resource(acpi_handle handle)
if (!device_create_file(&device->dev, &dev_attr_resource_in_use))
device->remove = acpi_power_sysfs_remove;
- mutex_lock(&power_resource_list_lock);
- list_add(&resource->list_node, &acpi_power_resource_list);
- mutex_unlock(&power_resource_list_lock);
+ acpi_power_add_resource_to_list(resource);
acpi_device_add_finalize(device);
return 0;
@@ -844,7 +860,22 @@ void acpi_resume_power_resources(void)
&& resource->ref_count) {
dev_info(&resource->device.dev, "Turning ON\n");
__acpi_power_on(resource);
- } else if (state == ACPI_POWER_RESOURCE_STATE_ON
+ }
+
+ mutex_unlock(&resource->resource_lock);
+ }
+ list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) {
+ int result, state;
+
+ mutex_lock(&resource->resource_lock);
+
+ result = acpi_power_get_state(resource->device.handle, &state);
+ if (result) {
+ mutex_unlock(&resource->resource_lock);
+ continue;
+ }
+
+ if (state == ACPI_POWER_RESOURCE_STATE_ON
&& !resource->ref_count) {
dev_info(&resource->device.dev, "Turning OFF\n");
__acpi_power_off(resource);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index b1ec78b8a645..33a38d604630 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -184,7 +184,7 @@ phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
phys_cpuid_t phys_id;
phys_id = map_mat_entry(handle, type, acpi_id);
- if (phys_id == PHYS_CPUID_INVALID)
+ if (invalid_phys_cpuid(phys_id))
phys_id = map_madt_entry(type, acpi_id);
return phys_id;
@@ -196,7 +196,7 @@ int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
int i;
#endif
- if (phys_id == PHYS_CPUID_INVALID) {
+ if (invalid_phys_cpuid(phys_id)) {
/*
* On UP processor, there is no _MAT or MADT table.
* So above phys_id is always set to PHYS_CPUID_INVALID.
@@ -215,12 +215,12 @@ int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
* Ignores phys_id and always returns 0 for the processor
* handle with acpi id 0 if nr_cpu_ids is 1.
* This should be the case if SMP tables are not found.
- * Return -1 for other CPU's handle.
+ * Return -EINVAL for other CPU's handle.
*/
if (nr_cpu_ids <= 1 && acpi_id == 0)
return acpi_id;
else
- return -1;
+ return -EINVAL;
}
#ifdef CONFIG_SMP
@@ -233,7 +233,7 @@ int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
if (phys_id == 0)
return phys_id;
#endif
- return -1;
+ return -ENODEV;
}
int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 39e0c8e36244..d540f42c9232 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -94,7 +94,7 @@ static int set_max_cstate(const struct dmi_system_id *id)
return 0;
}
-static struct dmi_system_id processor_power_dmi_table[] = {
+static const struct dmi_system_id processor_power_dmi_table[] = {
{ set_max_cstate, "Clevo 5600D", {
DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")},
diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c
index e5dd80800930..7cfbda4d7c51 100644
--- a/drivers/acpi/processor_pdc.c
+++ b/drivers/acpi/processor_pdc.c
@@ -52,10 +52,7 @@ static bool __init processor_physically_present(acpi_handle handle)
type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0;
cpuid = acpi_get_cpuid(handle, type, acpi_id);
- if (cpuid == -1)
- return false;
-
- return true;
+ return !invalid_logical_cpuid(cpuid);
}
static void acpi_set_pdc_bits(u32 *buf)
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 0d083736e25b..7836e2e980f4 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -79,50 +79,51 @@ static bool acpi_properties_format_valid(const union acpi_object *properties)
static void acpi_init_of_compatible(struct acpi_device *adev)
{
const union acpi_object *of_compatible;
- struct acpi_hardware_id *hwid;
- bool acpi_of = false;
int ret;
- /*
- * Check if the special PRP0001 ACPI ID is present and in that
- * case we fill in Device Tree compatible properties for this
- * device.
- */
- list_for_each_entry(hwid, &adev->pnp.ids, list) {
- if (!strcmp(hwid->id, "PRP0001")) {
- acpi_of = true;
- break;
- }
- }
-
- if (!acpi_of)
- return;
-
ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
&of_compatible);
if (ret) {
ret = acpi_dev_get_property(adev, "compatible",
ACPI_TYPE_STRING, &of_compatible);
if (ret) {
- acpi_handle_warn(adev->handle,
- "PRP0001 requires compatible property\n");
+ if (adev->parent
+ && adev->parent->flags.of_compatible_ok)
+ goto out;
+
return;
}
}
adev->data.of_compatible = of_compatible;
+
+ out:
+ adev->flags.of_compatible_ok = 1;
}
void acpi_init_properties(struct acpi_device *adev)
{
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ bool acpi_of = false;
+ struct acpi_hardware_id *hwid;
const union acpi_object *desc;
acpi_status status;
int i;
+ /*
+ * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in
+ * Device Tree compatible properties for this device.
+ */
+ list_for_each_entry(hwid, &adev->pnp.ids, list) {
+ if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) {
+ acpi_of = true;
+ break;
+ }
+ }
+
status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
ACPI_TYPE_PACKAGE);
if (ACPI_FAILURE(status))
- return;
+ goto out;
desc = buf.pointer;
if (desc->package.count % 2)
@@ -156,13 +157,20 @@ void acpi_init_properties(struct acpi_device *adev)
adev->data.pointer = buf.pointer;
adev->data.properties = properties;
- acpi_init_of_compatible(adev);
- return;
+ if (acpi_of)
+ acpi_init_of_compatible(adev);
+
+ goto out;
}
fail:
- dev_warn(&adev->dev, "Returned _DSD data is not valid, skipping\n");
+ dev_dbg(&adev->dev, "Returned _DSD data is not valid, skipping\n");
ACPI_FREE(buf.pointer);
+
+ out:
+ if (acpi_of && !adev->flags.of_compatible_ok)
+ acpi_handle_info(adev->handle,
+ ACPI_DT_NAMESPACE_HID " requires 'compatible' property\n");
}
void acpi_free_properties(struct acpi_device *adev)
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index 8244f013f210..fcb7807ea8b7 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -26,6 +26,7 @@
#include <linux/device.h>
#include <linux/export.h>
#include <linux/ioport.h>
+#include <linux/list.h>
#include <linux/slab.h>
#ifdef CONFIG_X86
@@ -621,3 +622,162 @@ int acpi_dev_filter_resource_type(struct acpi_resource *ares,
return (type & types) ? 0 : 1;
}
EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
+
+struct reserved_region {
+ struct list_head node;
+ u64 start;
+ u64 end;
+};
+
+static LIST_HEAD(reserved_io_regions);
+static LIST_HEAD(reserved_mem_regions);
+
+static int request_range(u64 start, u64 end, u8 space_id, unsigned long flags,
+ char *desc)
+{
+ unsigned int length = end - start + 1;
+ struct resource *res;
+
+ res = space_id == ACPI_ADR_SPACE_SYSTEM_IO ?
+ request_region(start, length, desc) :
+ request_mem_region(start, length, desc);
+ if (!res)
+ return -EIO;
+
+ res->flags &= ~flags;
+ return 0;
+}
+
+static int add_region_before(u64 start, u64 end, u8 space_id,
+ unsigned long flags, char *desc,
+ struct list_head *head)
+{
+ struct reserved_region *reg;
+ int error;
+
+ reg = kmalloc(sizeof(*reg), GFP_KERNEL);
+ if (!reg)
+ return -ENOMEM;
+
+ error = request_range(start, end, space_id, flags, desc);
+ if (error)
+ return error;
+
+ reg->start = start;
+ reg->end = end;
+ list_add_tail(&reg->node, head);
+ return 0;
+}
+
+/**
+ * acpi_reserve_region - Reserve an I/O or memory region as a system resource.
+ * @start: Starting address of the region.
+ * @length: Length of the region.
+ * @space_id: Identifier of address space to reserve the region from.
+ * @flags: Resource flags to clear for the region after requesting it.
+ * @desc: Region description (for messages).
+ *
+ * Reserve an I/O or memory region as a system resource to prevent others from
+ * using it. If the new region overlaps with one of the regions (in the given
+ * address space) already reserved by this routine, only the non-overlapping
+ * parts of it will be reserved.
+ *
+ * Returned is either 0 (success) or a negative error code indicating a resource
+ * reservation problem. It is the code of the first encountered error, but the
+ * routine doesn't abort until it has attempted to request all of the parts of
+ * the new region that don't overlap with other regions reserved previously.
+ *
+ * The resources requested by this routine are never released.
+ */
+int acpi_reserve_region(u64 start, unsigned int length, u8 space_id,
+ unsigned long flags, char *desc)
+{
+ struct list_head *regions;
+ struct reserved_region *reg;
+ u64 end = start + length - 1;
+ int ret = 0, error = 0;
+
+ if (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+ regions = &reserved_io_regions;
+ else if (space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+ regions = &reserved_mem_regions;
+ else
+ return -EINVAL;
+
+ if (list_empty(regions))
+ return add_region_before(start, end, space_id, flags, desc, regions);
+
+ list_for_each_entry(reg, regions, node)
+ if (reg->start == end + 1) {
+ /* The new region can be prepended to this one. */
+ ret = request_range(start, end, space_id, flags, desc);
+ if (!ret)
+ reg->start = start;
+
+ return ret;
+ } else if (reg->start > end) {
+ /* No overlap. Add the new region here and get out. */
+ return add_region_before(start, end, space_id, flags,
+ desc, &reg->node);
+ } else if (reg->end == start - 1) {
+ goto combine;
+ } else if (reg->end >= start) {
+ goto overlap;
+ }
+
+ /* The new region goes after the last existing one. */
+ return add_region_before(start, end, space_id, flags, desc, regions);
+
+ overlap:
+ /*
+ * The new region overlaps an existing one.
+ *
+ * The head part of the new region immediately preceding the existing
+ * overlapping one can be combined with it right away.
+ */
+ if (reg->start > start) {
+ error = request_range(start, reg->start - 1, space_id, flags, desc);
+ if (error)
+ ret = error;
+ else
+ reg->start = start;
+ }
+
+ combine:
+ /*
+ * The new region is adjacent to an existing one. If it extends beyond
+ * that region all the way to the next one, it is possible to combine
+ * all three of them.
+ */
+ while (reg->end < end) {
+ struct reserved_region *next = NULL;
+ u64 a = reg->end + 1, b = end;
+
+ if (!list_is_last(&reg->node, regions)) {
+ next = list_next_entry(reg, node);
+ if (next->start <= end)
+ b = next->start - 1;
+ }
+ error = request_range(a, b, space_id, flags, desc);
+ if (!error) {
+ if (next && next->start == b + 1) {
+ reg->end = next->end;
+ list_del(&next->node);
+ kfree(next);
+ } else {
+ reg->end = end;
+ break;
+ }
+ } else if (next) {
+ if (!ret)
+ ret = error;
+
+ reg = next;
+ } else {
+ break;
+ }
+ }
+
+ return ret ? ret : error;
+}
+EXPORT_SYMBOL_GPL(acpi_reserve_region);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 03141aa4ea95..2649a068671d 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -11,6 +11,7 @@
#include <linux/kthread.h>
#include <linux/dmi.h>
#include <linux/nls.h>
+#include <linux/dma-mapping.h>
#include <asm/pgtable.h>
@@ -135,12 +136,13 @@ static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
struct acpi_hardware_id *id;
/*
- * Since we skip PRP0001 from the modalias below, 0 should be returned
- * if PRP0001 is the only ACPI/PNP ID in the device's list.
+ * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should
+ * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the
+ * device's list.
*/
count = 0;
list_for_each_entry(id, &acpi_dev->pnp.ids, list)
- if (strcmp(id->id, "PRP0001"))
+ if (strcmp(id->id, ACPI_DT_NAMESPACE_HID))
count++;
if (!count)
@@ -153,7 +155,7 @@ static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
size -= len;
list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
- if (!strcmp(id->id, "PRP0001"))
+ if (!strcmp(id->id, ACPI_DT_NAMESPACE_HID))
continue;
count = snprintf(&modalias[len], size, "%s:", id->id);
@@ -177,7 +179,8 @@ static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
* @size: Size of the buffer.
*
* Expose DT compatible modalias as of:NnameTCcompatible. This function should
- * only be called for devices having PRP0001 in their list of ACPI/PNP IDs.
+ * only be called for devices having ACPI_DT_NAMESPACE_HID in their list of
+ * ACPI/PNP IDs.
*/
static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
int size)
@@ -980,9 +983,9 @@ static void acpi_device_remove_files(struct acpi_device *dev)
* @adev: ACPI device object to match.
* @of_match_table: List of device IDs to match against.
*
- * If @dev has an ACPI companion which has the special PRP0001 device ID in its
- * list of identifiers and a _DSD object with the "compatible" property, use
- * that property to match against the given list of identifiers.
+ * If @dev has an ACPI companion which has ACPI_DT_NAMESPACE_HID in its list of
+ * identifiers and a _DSD object with the "compatible" property, use that
+ * property to match against the given list of identifiers.
*/
static bool acpi_of_match_device(struct acpi_device *adev,
const struct of_device_id *of_match_table)
@@ -1038,14 +1041,14 @@ static const struct acpi_device_id *__acpi_match_device(
return id;
/*
- * Next, check the special "PRP0001" ID and try to match the
+ * Next, check ACPI_DT_NAMESPACE_HID and try to match the
* "compatible" property if found.
*
* The id returned by the below is not valid, but the only
* caller passing non-NULL of_ids here is only interested in
* whether or not the return value is NULL.
*/
- if (!strcmp("PRP0001", hwid->id)
+ if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id)
&& acpi_of_match_device(device, of_ids))
return id;
}
@@ -1671,7 +1674,7 @@ static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
static void acpi_wakeup_gpe_init(struct acpi_device *device)
{
- struct acpi_device_id button_device_ids[] = {
+ static const struct acpi_device_id button_device_ids[] = {
{"PNP0C0C", 0},
{"PNP0C0D", 0},
{"PNP0C0E", 0},
@@ -1766,15 +1769,9 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
if (acpi_has_method(device->handle, pathname))
ps->flags.explicit_set = 1;
- /*
- * State is valid if there are means to put the device into it.
- * D3hot is only valid if _PR3 present.
- */
- if (!list_empty(&ps->resources)
- || (ps->flags.explicit_set && state < ACPI_STATE_D3_HOT)) {
+ /* State is valid if there are means to put the device into it. */
+ if (!list_empty(&ps->resources) || ps->flags.explicit_set)
ps->flags.valid = 1;
- ps->flags.os_accessible = 1;
- }
ps->power = -1; /* Unknown - driver assigned */
ps->latency = -1; /* Unknown - driver assigned */
@@ -1810,21 +1807,13 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
acpi_bus_init_power_state(device, i);
INIT_LIST_HEAD(&device->power.states[ACPI_STATE_D3_COLD].resources);
+ if (!list_empty(&device->power.states[ACPI_STATE_D3_HOT].resources))
+ device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1;
- /* Set defaults for D0 and D3 states (always valid) */
+ /* Set defaults for D0 and D3hot states (always valid) */
device->power.states[ACPI_STATE_D0].flags.valid = 1;
device->power.states[ACPI_STATE_D0].power = 100;
- device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1;
- device->power.states[ACPI_STATE_D3_COLD].power = 0;
-
- /* Set D3cold's explicit_set flag if _PS3 exists. */
- if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set)
- device->power.states[ACPI_STATE_D3_COLD].flags.explicit_set = 1;
-
- /* Presence of _PS3 or _PRx means we can put the device into D3 cold */
- if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set ||
- device->power.flags.power_resources)
- device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1;
+ device->power.states[ACPI_STATE_D3_HOT].flags.valid = 1;
if (acpi_bus_init_power(device))
device->flags.power_manageable = 0;
@@ -1947,6 +1936,62 @@ bool acpi_dock_match(acpi_handle handle)
return acpi_has_method(handle, "_DCK");
}
+static acpi_status
+acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
+ void **return_value)
+{
+ long *cap = context;
+
+ if (acpi_has_method(handle, "_BCM") &&
+ acpi_has_method(handle, "_BCL")) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
+ "support\n"));
+ *cap |= ACPI_VIDEO_BACKLIGHT;
+ if (!acpi_has_method(handle, "_BQC"))
+ printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, "
+ "cannot determine initial brightness\n");
+ /* We have backlight support, no need to scan further */
+ return AE_CTRL_TERMINATE;
+ }
+ return 0;
+}
+
+/* Returns true if the ACPI object is a video device which can be
+ * handled by video.ko.
+ * The device will get a Linux specific CID added in scan.c to
+ * identify the device as an ACPI graphics device
+ * Be aware that the graphics device may not be physically present
+ * Use acpi_video_get_capabilities() to detect general ACPI video
+ * capabilities of present cards
+ */
+long acpi_is_video_device(acpi_handle handle)
+{
+ long video_caps = 0;
+
+ /* Is this device able to support video switching ? */
+ if (acpi_has_method(handle, "_DOD") || acpi_has_method(handle, "_DOS"))
+ video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
+
+ /* Is this device able to retrieve a video ROM ? */
+ if (acpi_has_method(handle, "_ROM"))
+ video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
+
+ /* Is this device able to configure which video head to be POSTed ? */
+ if (acpi_has_method(handle, "_VPO") &&
+ acpi_has_method(handle, "_GPD") &&
+ acpi_has_method(handle, "_SPD"))
+ video_caps |= ACPI_VIDEO_DEVICE_POSTING;
+
+ /* Only check for backlight functionality if one of the above hit. */
+ if (video_caps)
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+ ACPI_UINT32_MAX, acpi_backlight_cap_match, NULL,
+ &video_caps, NULL);
+
+ return video_caps;
+}
+EXPORT_SYMBOL(acpi_is_video_device);
+
const char *acpi_device_hid(struct acpi_device *device)
{
struct acpi_hardware_id *hid;
@@ -2109,6 +2154,39 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
kfree(pnp->unique_id);
}
+static void acpi_init_coherency(struct acpi_device *adev)
+{
+ unsigned long long cca = 0;
+ acpi_status status;
+ struct acpi_device *parent = adev->parent;
+
+ if (parent && parent->flags.cca_seen) {
+ /*
+ * From ACPI spec, OSPM will ignore _CCA if an ancestor
+ * already saw one.
+ */
+ adev->flags.cca_seen = 1;
+ cca = parent->flags.coherent_dma;
+ } else {
+ status = acpi_evaluate_integer(adev->handle, "_CCA",
+ NULL, &cca);
+ if (ACPI_SUCCESS(status))
+ adev->flags.cca_seen = 1;
+ else if (!IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED))
+ /*
+ * If architecture does not specify that _CCA is
+ * required for DMA-able devices (e.g. x86),
+ * we default to _CCA=1.
+ */
+ cca = 1;
+ else
+ acpi_handle_debug(adev->handle,
+ "ACPI device is missing _CCA.\n");
+ }
+
+ adev->flags.coherent_dma = cca;
+}
+
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
int type, unsigned long long sta)
{
@@ -2127,6 +2205,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
device->flags.visited = false;
device_initialize(&device->dev);
dev_set_uevent_suppress(&device->dev, true);
+ acpi_init_coherency(device);
}
void acpi_device_add_finalize(struct acpi_device *device)
@@ -2405,7 +2484,7 @@ static void acpi_default_enumeration(struct acpi_device *device)
}
static const struct acpi_device_id generic_device_ids[] = {
- {"PRP0001", },
+ {ACPI_DT_NAMESPACE_HID, },
{"", },
};
@@ -2413,8 +2492,8 @@ static int acpi_generic_device_attach(struct acpi_device *adev,
const struct acpi_device_id *not_used)
{
/*
- * Since PRP0001 is the only ID handled here, the test below can be
- * unconditional.
+ * Since ACPI_DT_NAMESPACE_HID is the only ID handled here, the test
+ * below can be unconditional.
*/
if (adev->data.of_compatible)
acpi_default_enumeration(adev);
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index d24fa1964eb8..6d4e44ea74ac 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -800,7 +800,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
result =
thermal_zone_bind_cooling_device
(thermal, trip, cdev,
- THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
+ THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
+ THERMAL_WEIGHT_DEFAULT);
else
result =
thermal_zone_unbind_cooling_device
@@ -824,7 +825,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
if (bind)
result = thermal_zone_bind_cooling_device
(thermal, trip, cdev,
- THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
+ THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
+ THERMAL_WEIGHT_DEFAULT);
else
result = thermal_zone_unbind_cooling_device
(thermal, trip, cdev);
@@ -841,7 +843,8 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
result = thermal_zone_bind_cooling_device
(thermal, THERMAL_TRIPS_NONE,
cdev, THERMAL_NO_LIMIT,
- THERMAL_NO_LIMIT);
+ THERMAL_NO_LIMIT,
+ THERMAL_WEIGHT_DEFAULT);
else
result = thermal_zone_unbind_cooling_device
(thermal, THERMAL_TRIPS_NONE,
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index cd49a3982b6a..67c548ad3764 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -712,3 +712,18 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs)
return false;
}
EXPORT_SYMBOL(acpi_check_dsm);
+
+/*
+ * acpi_backlight= handling, this is done here rather then in video_detect.c
+ * because __setup cannot be used in modules.
+ */
+char acpi_video_backlight_string[16];
+EXPORT_SYMBOL(acpi_video_backlight_string);
+
+static int __init acpi_backlight(char *str)
+{
+ strlcpy(acpi_video_backlight_string, str,
+ sizeof(acpi_video_backlight_string));
+ return 1;
+}
+__setup("acpi_backlight=", acpi_backlight);
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index c42feb2bacd0..815f75ef2411 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -1,106 +1,61 @@
/*
+ * Copyright (C) 2015 Red Hat Inc.
+ * Hans de Goede <hdegoede@redhat.com>
* Copyright (C) 2008 SuSE Linux Products GmbH
* Thomas Renninger <trenn@suse.de>
*
* May be copied or modified under the terms of the GNU General Public License
*
* video_detect.c:
- * Provides acpi_is_video_device() for early scanning of ACPI devices in scan.c
- * There a Linux specific (Spec does not provide a HID for video devices) is
- * assigned
- *
* After PCI devices are glued with ACPI devices
* acpi_get_pci_dev() can be called to identify ACPI graphics
* devices for which a real graphics card is plugged in
*
- * Now acpi_video_get_capabilities() can be called to check which
- * capabilities the graphics cards plugged in support. The check for general
- * video capabilities will be triggered by the first caller of
- * acpi_video_get_capabilities(NULL); which will happen when the first
- * backlight switching supporting driver calls:
- * acpi_video_backlight_support();
- *
* Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
* are available, video.ko should be used to handle the device.
*
* Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop,
* sony_acpi,... can take care about backlight brightness.
*
- * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
- * this file will not be compiled, acpi_video_get_capabilities() and
- * acpi_video_backlight_support() will always return 0 and vendor specific
- * drivers always can handle backlight.
+ * Backlight drivers can use acpi_video_get_backlight_type() to determine
+ * which driver should handle the backlight.
*
+ * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
+ * this file will not be compiled and acpi_video_get_backlight_type() will
+ * always return acpi_backlight_vendor.
*/
#include <linux/export.h>
#include <linux/acpi.h>
+#include <linux/backlight.h>
#include <linux/dmi.h>
+#include <linux/module.h>
#include <linux/pci.h>
-
-#include "internal.h"
+#include <linux/types.h>
+#include <acpi/video.h>
ACPI_MODULE_NAME("video");
#define _COMPONENT ACPI_VIDEO_COMPONENT
-static long acpi_video_support;
-static bool acpi_video_caps_checked;
+void acpi_video_unregister_backlight(void);
-static acpi_status
-acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
- void **return_value)
-{
- long *cap = context;
+static bool backlight_notifier_registered;
+static struct notifier_block backlight_nb;
- if (acpi_has_method(handle, "_BCM") &&
- acpi_has_method(handle, "_BCL")) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
- "support\n"));
- *cap |= ACPI_VIDEO_BACKLIGHT;
- if (!acpi_has_method(handle, "_BQC"))
- printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, "
- "cannot determine initial brightness\n");
- /* We have backlight support, no need to scan further */
- return AE_CTRL_TERMINATE;
- }
- return 0;
-}
+static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef;
+static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef;
-/* Returns true if the ACPI object is a video device which can be
- * handled by video.ko.
- * The device will get a Linux specific CID added in scan.c to
- * identify the device as an ACPI graphics device
- * Be aware that the graphics device may not be physically present
- * Use acpi_video_get_capabilities() to detect general ACPI video
- * capabilities of present cards
- */
-long acpi_is_video_device(acpi_handle handle)
+static void acpi_video_parse_cmdline(void)
{
- long video_caps = 0;
-
- /* Is this device able to support video switching ? */
- if (acpi_has_method(handle, "_DOD") || acpi_has_method(handle, "_DOS"))
- video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
-
- /* Is this device able to retrieve a video ROM ? */
- if (acpi_has_method(handle, "_ROM"))
- video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
-
- /* Is this device able to configure which video head to be POSTed ? */
- if (acpi_has_method(handle, "_VPO") &&
- acpi_has_method(handle, "_GPD") &&
- acpi_has_method(handle, "_SPD"))
- video_caps |= ACPI_VIDEO_DEVICE_POSTING;
-
- /* Only check for backlight functionality if one of the above hit. */
- if (video_caps)
- acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
- ACPI_UINT32_MAX, acpi_backlight_cap_match, NULL,
- &video_caps, NULL);
-
- return video_caps;
+ if (!strcmp("vendor", acpi_video_backlight_string))
+ acpi_backlight_cmdline = acpi_backlight_vendor;
+ if (!strcmp("video", acpi_video_backlight_string))
+ acpi_backlight_cmdline = acpi_backlight_video;
+ if (!strcmp("native", acpi_video_backlight_string))
+ acpi_backlight_cmdline = acpi_backlight_native;
+ if (!strcmp("none", acpi_video_backlight_string))
+ acpi_backlight_cmdline = acpi_backlight_none;
}
-EXPORT_SYMBOL(acpi_is_video_device);
static acpi_status
find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
@@ -109,7 +64,7 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
struct pci_dev *dev;
struct acpi_device *acpi_dev;
- const struct acpi_device_id video_ids[] = {
+ static const struct acpi_device_id video_ids[] = {
{ACPI_VIDEO_HID, 0},
{"", 0},
};
@@ -130,11 +85,23 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
* buggy */
static int video_detect_force_vendor(const struct dmi_system_id *d)
{
- acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
+ acpi_backlight_dmi = acpi_backlight_vendor;
+ return 0;
+}
+
+static int video_detect_force_video(const struct dmi_system_id *d)
+{
+ acpi_backlight_dmi = acpi_backlight_video;
return 0;
}
-static struct dmi_system_id video_detect_dmi_table[] = {
+static int video_detect_force_native(const struct dmi_system_id *d)
+{
+ acpi_backlight_dmi = acpi_backlight_native;
+ return 0;
+}
+
+static const struct dmi_system_id video_detect_dmi_table[] = {
/* On Samsung X360, the BIOS will set a flag (VDRV) if generic
* ACPI backlight device is used. This flag will definitively break
* the backlight interface (even the vendor interface) untill next
@@ -174,137 +141,209 @@ static struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5737"),
},
},
+
+ /*
+ * These models have a working acpi_video backlight control, and using
+ * native backlight causes a regression where backlight does not work
+ * when userspace is not handling brightness key events. Disable
+ * native_backlight on these to fix this:
+ * https://bugzilla.kernel.org/show_bug.cgi?id=81691
+ */
+ {
+ .callback = video_detect_force_video,
+ .ident = "ThinkPad T420",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T420"),
+ },
+ },
+ {
+ .callback = video_detect_force_video,
+ .ident = "ThinkPad T520",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"),
+ },
+ },
+ {
+ .callback = video_detect_force_video,
+ .ident = "ThinkPad X201s",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"),
+ },
+ },
+
+ /* The native backlight controls do not work on some older machines */
+ {
+ /* https://bugs.freedesktop.org/show_bug.cgi?id=81515 */
+ .callback = video_detect_force_video,
+ .ident = "HP ENVY 15 Notebook",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"),
+ },
+ },
+ {
+ .callback = video_detect_force_video,
+ .ident = "SAMSUNG 870Z5E/880Z5E/680Z5E",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"),
+ },
+ },
+ {
+ .callback = video_detect_force_video,
+ .ident = "SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME,
+ "370R4E/370R4V/370R5E/3570RE/370R5V"),
+ },
+ },
+ {
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */
+ .callback = video_detect_force_video,
+ .ident = "SAMSUNG 3570R/370R/470R/450R/510R/4450RV",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME,
+ "3570R/370R/470R/450R/510R/4450RV"),
+ },
+ },
+ {
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
+ .callback = video_detect_force_video,
+ .ident = "SAMSUNG 730U3E/740U3E",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"),
+ },
+ },
+ {
+ /* https://bugs.freedesktop.org/show_bug.cgi?id=87286 */
+ .callback = video_detect_force_video,
+ .ident = "SAMSUNG 900X3C/900X3D/900X3E/900X4C/900X4D",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME,
+ "900X3C/900X3D/900X3E/900X4C/900X4D"),
+ },
+ },
+ {
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */
+ .callback = video_detect_force_video,
+ .ident = "Dell XPS15 L521X",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"),
+ },
+ },
+
+ /* Non win8 machines which need native backlight nevertheless */
+ {
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */
+ .callback = video_detect_force_native,
+ .ident = "Lenovo Ideapad Z570",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "102434U"),
+ },
+ },
+ {
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
+ .callback = video_detect_force_native,
+ .ident = "Apple MacBook Pro 12,1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"),
+ },
+ },
{ },
};
+static int acpi_video_backlight_notify(struct notifier_block *nb,
+ unsigned long val, void *bd)
+{
+ struct backlight_device *backlight = bd;
+
+ /* A raw bl registering may change video -> native */
+ if (backlight->props.type == BACKLIGHT_RAW &&
+ val == BACKLIGHT_REGISTERED &&
+ acpi_video_get_backlight_type() != acpi_backlight_video)
+ acpi_video_unregister_backlight();
+
+ return NOTIFY_OK;
+}
+
/*
- * Returns the video capabilities of a specific ACPI graphics device
+ * Determine which type of backlight interface to use on this system,
+ * First check cmdline, then dmi quirks, then do autodetect.
*
- * if NULL is passed as argument all ACPI devices are enumerated and
- * all graphics capabilities of physically present devices are
- * summarized and returned. This is cached and done only once.
+ * The autodetect order is:
+ * 1) Is the acpi-video backlight interface supported ->
+ * no, use a vendor interface
+ * 2) Is this a win8 "ready" BIOS and do we have a native interface ->
+ * yes, use a native interface
+ * 3) Else use the acpi-video interface
+ *
+ * Arguably the native on win8 check should be done first, but that would
+ * be a behavior change, which may causes issues.
*/
-long acpi_video_get_capabilities(acpi_handle graphics_handle)
+enum acpi_backlight_type acpi_video_get_backlight_type(void)
{
- long caps = 0;
- struct acpi_device *tmp_dev;
- acpi_status status;
-
- if (acpi_video_caps_checked && graphics_handle == NULL)
- return acpi_video_support;
-
- if (!graphics_handle) {
- /* Only do the global walk through all graphics devices once */
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, find_video, NULL,
- &caps, NULL);
- /* There might be boot param flags set already... */
- acpi_video_support |= caps;
- acpi_video_caps_checked = 1;
- /* Add blacklists here. Be careful to use the right *DMI* bits
- * to still be able to override logic via boot params, e.g.:
- *
- * if (dmi_name_in_vendors("XY")) {
- * acpi_video_support |=
- * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
- *}
- */
+ static DEFINE_MUTEX(init_mutex);
+ static bool init_done;
+ static long video_caps;
+ /* Parse cmdline, dmi and acpi only once */
+ mutex_lock(&init_mutex);
+ if (!init_done) {
+ acpi_video_parse_cmdline();
dmi_check_system(video_detect_dmi_table);
- } else {
- status = acpi_bus_get_device(graphics_handle, &tmp_dev);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Invalid device"));
- return 0;
- }
- acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle,
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_video, NULL,
- &caps, NULL);
+ &video_caps, NULL);
+ backlight_nb.notifier_call = acpi_video_backlight_notify;
+ backlight_nb.priority = 0;
+ if (backlight_register_notifier(&backlight_nb) == 0)
+ backlight_notifier_registered = true;
+ init_done = true;
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n",
- graphics_handle ? caps : acpi_video_support,
- graphics_handle ? "on device " : "in general",
- graphics_handle ? acpi_device_bid(tmp_dev) : ""));
- return caps;
-}
-EXPORT_SYMBOL(acpi_video_get_capabilities);
+ mutex_unlock(&init_mutex);
-static void acpi_video_caps_check(void)
-{
- /*
- * We must check whether the ACPI graphics device is physically plugged
- * in. Therefore this must be called after binding PCI and ACPI devices
- */
- if (!acpi_video_caps_checked)
- acpi_video_get_capabilities(NULL);
-}
+ if (acpi_backlight_cmdline != acpi_backlight_undef)
+ return acpi_backlight_cmdline;
-bool acpi_osi_is_win8(void)
-{
- return acpi_gbl_osi_data >= ACPI_OSI_WIN_8;
-}
-EXPORT_SYMBOL(acpi_osi_is_win8);
+ if (acpi_backlight_dmi != acpi_backlight_undef)
+ return acpi_backlight_dmi;
-/* Promote the vendor interface instead of the generic video module.
- * This function allow DMI blacklists to be implemented by externals
- * platform drivers instead of putting a big blacklist in video_detect.c
- * After calling this function you will probably want to call
- * acpi_video_unregister() to make sure the video module is not loaded
- */
-void acpi_video_dmi_promote_vendor(void)
-{
- acpi_video_caps_check();
- acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
-}
-EXPORT_SYMBOL(acpi_video_dmi_promote_vendor);
-
-/* To be called when a driver who previously promoted the vendor
- * interface */
-void acpi_video_dmi_demote_vendor(void)
-{
- acpi_video_caps_check();
- acpi_video_support &= ~ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
-}
-EXPORT_SYMBOL(acpi_video_dmi_demote_vendor);
-
-/* Returns true if video.ko can do backlight switching */
-int acpi_video_backlight_support(void)
-{
- acpi_video_caps_check();
-
- /* First check for boot param -> highest prio */
- if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR)
- return 0;
- else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO)
- return 1;
+ if (!(video_caps & ACPI_VIDEO_BACKLIGHT))
+ return acpi_backlight_vendor;
- /* Then check for DMI blacklist -> second highest prio */
- if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR)
- return 0;
- else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO)
- return 1;
+ if (acpi_osi_is_win8() && backlight_device_registered(BACKLIGHT_RAW))
+ return acpi_backlight_native;
- /* Then go the default way */
- return acpi_video_support & ACPI_VIDEO_BACKLIGHT;
+ return acpi_backlight_video;
}
-EXPORT_SYMBOL(acpi_video_backlight_support);
+EXPORT_SYMBOL(acpi_video_get_backlight_type);
/*
- * Use acpi_backlight=vendor/video to force that backlight switching
- * is processed by vendor specific acpi drivers or video.ko driver.
+ * Set the preferred backlight interface type based on DMI info.
+ * This function allows DMI blacklists to be implemented by external
+ * platform drivers instead of putting a big blacklist in video_detect.c
*/
-static int __init acpi_backlight(char *str)
+void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type)
{
- if (str == NULL || *str == '\0')
- return 1;
- else {
- if (!strcmp("vendor", str))
- acpi_video_support |=
- ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR;
- if (!strcmp("video", str))
- acpi_video_support |=
- ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO;
- }
- return 1;
+ acpi_backlight_dmi = type;
+ /* Remove acpi-video backlight interface if it is no longer desired */
+ if (acpi_video_get_backlight_type() != acpi_backlight_video)
+ acpi_video_unregister_backlight();
+}
+EXPORT_SYMBOL(acpi_video_set_dmi_backlight_type);
+
+void __exit acpi_video_detect_exit(void)
+{
+ if (backlight_notifier_registered)
+ backlight_unregister_notifier(&backlight_nb);
}
-__setup("acpi_backlight=", acpi_backlight);
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 9dca4b995be0..6d17a3b65ef7 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -98,6 +98,15 @@ config SATA_AHCI_PLATFORM
If unsure, say N.
+config AHCI_BRCMSTB
+ tristate "Broadcom STB AHCI SATA support"
+ depends on ARCH_BRCMSTB
+ help
+ This option enables support for the AHCI SATA3 controller found on
+ STB SoC's.
+
+ If unsure, say N.
+
config AHCI_DA850
tristate "DaVinci DA850 AHCI SATA support"
depends on ARCH_DAVINCI_DA850
@@ -124,6 +133,15 @@ config AHCI_IMX
If unsure, say N.
+config AHCI_CEVA
+ tristate "CEVA AHCI SATA support"
+ depends on OF
+ help
+ This option enables support for the CEVA AHCI SATA.
+ It can be found on the Xilinx Zynq UltraScale+ MPSoC.
+
+ If unsure, say N.
+
config AHCI_MVEBU
tristate "Marvell EBU AHCI SATA support"
depends on ARCH_MVEBU
@@ -827,7 +845,6 @@ config PATA_AT32
config PATA_AT91
tristate "PATA support for AT91SAM9260"
depends on ARM && SOC_AT91SAM9
- depends on !ARCH_MULTIPLATFORM
help
This option enables support for IDE devices on the Atmel AT91SAM9260 SoC.
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 40f7865f20a1..af70919f7dde 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -10,6 +10,8 @@ obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
+obj-$(CONFIG_AHCI_BRCMSTB) += ahci_brcmstb.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_CEVA) += ahci_ceva.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o
diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c
index 12489ce863c4..ed6a30cd681a 100644
--- a/drivers/ata/acard-ahci.c
+++ b/drivers/ata/acard-ahci.c
@@ -433,6 +433,8 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
+
+ hpriv->irq = pdev->irq;
hpriv->flags |= (unsigned long)pi.private_data;
if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
@@ -498,7 +500,7 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id
acard_ahci_pci_print_info(host);
pci_set_master(pdev);
- return ahci_host_activate(host, pdev->irq, &acard_ahci_sht);
+ return ahci_host_activate(host, &acard_ahci_sht);
}
module_pci_driver(acard_ahci_pci_driver);
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 65ee94454bbd..7e62751abfac 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -42,6 +42,7 @@
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/gfp.h>
+#include <linux/msi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
@@ -52,6 +53,7 @@
enum {
AHCI_PCI_BAR_STA2X11 = 0,
+ AHCI_PCI_BAR_CAVIUM = 0,
AHCI_PCI_BAR_ENMOTUS = 2,
AHCI_PCI_BAR_STANDARD = 5,
};
@@ -1288,17 +1290,60 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
{}
#endif
-static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
- struct ahci_host_priv *hpriv)
+/*
+ * ahci_init_msix() only implements single MSI-X support, not multiple
+ * MSI-X per-port interrupts. This is needed for host controllers that only
+ * have MSI-X support implemented, but no MSI or intx.
+ */
+static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports,
+ struct ahci_host_priv *hpriv)
{
int rc, nvec;
+ struct msix_entry entry = {};
+ /* Do not init MSI-X if MSI is disabled for the device */
if (hpriv->flags & AHCI_HFLAG_NO_MSI)
- goto intx;
+ return -ENODEV;
+
+ nvec = pci_msix_vec_count(pdev);
+ if (nvec < 0)
+ return nvec;
+
+ if (!nvec) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ /*
+ * There can be more than one vector (e.g. for error detection or
+ * hdd hotplug). Only the first vector (entry.entry = 0) is used.
+ */
+ rc = pci_enable_msix_exact(pdev, &entry, 1);
+ if (rc < 0)
+ goto fail;
+
+ hpriv->irq = entry.vector;
+
+ return 1;
+fail:
+ dev_err(&pdev->dev,
+ "failed to enable MSI-X with error %d, # of vectors: %d\n",
+ rc, nvec);
+
+ return rc;
+}
+
+static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports,
+ struct ahci_host_priv *hpriv)
+{
+ int rc, nvec;
+
+ if (hpriv->flags & AHCI_HFLAG_NO_MSI)
+ return -ENODEV;
nvec = pci_msi_vec_count(pdev);
if (nvec < 0)
- goto intx;
+ return nvec;
/*
* If number of MSIs is less than number of ports then Sharing Last
@@ -1311,8 +1356,8 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
rc = pci_enable_msi_exact(pdev, nvec);
if (rc == -ENOSPC)
goto single_msi;
- else if (rc < 0)
- goto intx;
+ if (rc < 0)
+ return rc;
/* fallback to single MSI mode if the controller enforced MRSM mode */
if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) {
@@ -1324,15 +1369,42 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
if (nvec > 1)
hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
- return nvec;
+ goto out;
single_msi:
- if (pci_enable_msi(pdev))
- goto intx;
- return 1;
+ nvec = 1;
+
+ rc = pci_enable_msi(pdev);
+ if (rc < 0)
+ return rc;
+out:
+ hpriv->irq = pdev->irq;
+
+ return nvec;
+}
+
+static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
+ struct ahci_host_priv *hpriv)
+{
+ int nvec;
+
+ nvec = ahci_init_msi(pdev, n_ports, hpriv);
+ if (nvec >= 0)
+ return nvec;
+
+ /*
+ * Currently, MSI-X support only implements single IRQ mode and
+ * exists for controllers which can't do other types of IRQ. Only
+ * set it up if MSI fails.
+ */
+ nvec = ahci_init_msix(pdev, n_ports, hpriv);
+ if (nvec >= 0)
+ return nvec;
-intx:
+ /* lagacy intx interrupts */
pci_intx(pdev, 1);
+ hpriv->irq = pdev->irq;
+
return 0;
}
@@ -1371,11 +1443,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_info(&pdev->dev,
"PDC42819 can only drive SATA devices with this driver\n");
- /* Both Connext and Enmotus devices use non-standard BARs */
+ /* Some devices use non-standard BARs */
if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06)
ahci_pci_bar = AHCI_PCI_BAR_STA2X11;
else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000)
ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS;
+ else if (pdev->vendor == 0x177d && pdev->device == 0xa01c)
+ ahci_pci_bar = AHCI_PCI_BAR_CAVIUM;
/*
* The JMicron chip 361/363 contains one SATA controller and one
@@ -1497,13 +1571,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
- ahci_init_interrupts(pdev, n_ports, hpriv);
-
host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
if (!host)
return -ENOMEM;
host->private_data = hpriv;
+ ahci_init_interrupts(pdev, n_ports, hpriv);
+
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
host->flags |= ATA_HOST_PARALLEL_SCAN;
else
@@ -1549,7 +1623,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
- return ahci_host_activate(host, pdev->irq, &ahci_sht);
+ return ahci_host_activate(host, &ahci_sht);
}
module_pci_driver(ahci_pci_driver);
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 71262e08648e..5b8e8a0fab48 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -238,6 +238,8 @@ enum {
AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */
AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */
AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */
+ AHCI_HFLAG_EDGE_IRQ = (1 << 19), /* HOST_IRQ_STAT behaves as
+ Edge Triggered */
/* ap->flags bits */
@@ -341,6 +343,7 @@ struct ahci_host_priv {
struct phy **phys;
unsigned nports; /* Number of ports */
void *plat_data; /* Other platform data */
+ unsigned int irq; /* interrupt line */
/*
* Optional ahci_start_engine override, if not set this gets set to the
* default ahci_start_engine during ahci_save_initial_config, this can
@@ -393,8 +396,7 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv,
struct ata_port_info *pi);
int ahci_reset_em(struct ata_host *host);
void ahci_print_info(struct ata_host *host, const char *scc_s);
-int ahci_host_activate(struct ata_host *host, int irq,
- struct scsi_host_template *sht);
+int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht);
void ahci_error_handler(struct ata_port *ap);
static inline void __iomem *__ahci_port_base(struct ata_host *host,
diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c
new file mode 100644
index 000000000000..ce1e3a885981
--- /dev/null
+++ b/drivers/ata/ahci_brcmstb.c
@@ -0,0 +1,322 @@
+/*
+ * Broadcom SATA3 AHCI Controller Driver
+ *
+ * Copyright © 2009-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; either version 2, 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/ahci_platform.h>
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+
+#include "ahci.h"
+
+#define DRV_NAME "brcm-ahci"
+
+#define SATA_TOP_CTRL_VERSION 0x0
+#define SATA_TOP_CTRL_BUS_CTRL 0x4
+ #define MMIO_ENDIAN_SHIFT 0 /* CPU->AHCI */
+ #define DMADESC_ENDIAN_SHIFT 2 /* AHCI->DDR */
+ #define DMADATA_ENDIAN_SHIFT 4 /* AHCI->DDR */
+ #define PIODATA_ENDIAN_SHIFT 6
+ #define ENDIAN_SWAP_NONE 0
+ #define ENDIAN_SWAP_FULL 2
+ #define OVERRIDE_HWINIT BIT(16)
+#define SATA_TOP_CTRL_TP_CTRL 0x8
+#define SATA_TOP_CTRL_PHY_CTRL 0xc
+ #define SATA_TOP_CTRL_PHY_CTRL_1 0x0
+ #define SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE BIT(14)
+ #define SATA_TOP_CTRL_PHY_CTRL_2 0x4
+ #define SATA_TOP_CTRL_2_SW_RST_MDIOREG BIT(0)
+ #define SATA_TOP_CTRL_2_SW_RST_OOB BIT(1)
+ #define SATA_TOP_CTRL_2_SW_RST_RX BIT(2)
+ #define SATA_TOP_CTRL_2_SW_RST_TX BIT(3)
+ #define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET BIT(14)
+ #define SATA_TOP_CTRL_PHY_OFFS 0x8
+ #define SATA_TOP_MAX_PHYS 2
+#define SATA_TOP_CTRL_SATA_TP_OUT 0x1c
+#define SATA_TOP_CTRL_CLIENT_INIT_CTRL 0x20
+
+/* On big-endian MIPS, buses are reversed to big endian, so switch them back */
+#if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
+#define DATA_ENDIAN 2 /* AHCI->DDR inbound accesses */
+#define MMIO_ENDIAN 2 /* CPU->AHCI outbound accesses */
+#else
+#define DATA_ENDIAN 0
+#define MMIO_ENDIAN 0
+#endif
+
+#define BUS_CTRL_ENDIAN_CONF \
+ ((DATA_ENDIAN << DMADATA_ENDIAN_SHIFT) | \
+ (DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) | \
+ (MMIO_ENDIAN << MMIO_ENDIAN_SHIFT))
+
+struct brcm_ahci_priv {
+ struct device *dev;
+ void __iomem *top_ctrl;
+ u32 port_mask;
+};
+
+static const struct ata_port_info ahci_brcm_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
+};
+
+static inline u32 brcm_sata_readreg(void __iomem *addr)
+{
+ /*
+ * 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 (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
+ return __raw_readl(addr);
+ else
+ return readl_relaxed(addr);
+}
+
+static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
+{
+ /* See brcm_sata_readreg() comments */
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
+ __raw_writel(val, addr);
+ else
+ writel_relaxed(val, addr);
+}
+
+static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
+{
+ void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
+ (port * SATA_TOP_CTRL_PHY_OFFS);
+ void __iomem *p;
+ u32 reg;
+
+ /* clear PHY_DEFAULT_POWER_STATE */
+ p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
+ reg = brcm_sata_readreg(p);
+ reg &= ~SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
+ brcm_sata_writereg(reg, p);
+
+ /* reset the PHY digital logic */
+ p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
+ reg = brcm_sata_readreg(p);
+ reg &= ~(SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
+ SATA_TOP_CTRL_2_SW_RST_RX);
+ reg |= SATA_TOP_CTRL_2_SW_RST_TX;
+ brcm_sata_writereg(reg, p);
+ reg = brcm_sata_readreg(p);
+ reg |= SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
+ brcm_sata_writereg(reg, p);
+ reg = brcm_sata_readreg(p);
+ reg &= ~SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
+ brcm_sata_writereg(reg, p);
+ (void)brcm_sata_readreg(p);
+}
+
+static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port)
+{
+ void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
+ (port * SATA_TOP_CTRL_PHY_OFFS);
+ void __iomem *p;
+ u32 reg;
+
+ /* power-off the PHY digital logic */
+ p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
+ reg = brcm_sata_readreg(p);
+ reg |= (SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
+ SATA_TOP_CTRL_2_SW_RST_RX | SATA_TOP_CTRL_2_SW_RST_TX |
+ SATA_TOP_CTRL_2_PHY_GLOBAL_RESET);
+ brcm_sata_writereg(reg, p);
+
+ /* set PHY_DEFAULT_POWER_STATE */
+ p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
+ reg = brcm_sata_readreg(p);
+ reg |= SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
+ brcm_sata_writereg(reg, p);
+}
+
+static void brcm_sata_phys_enable(struct brcm_ahci_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < SATA_TOP_MAX_PHYS; i++)
+ if (priv->port_mask & BIT(i))
+ brcm_sata_phy_enable(priv, i);
+}
+
+static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < SATA_TOP_MAX_PHYS; i++)
+ if (priv->port_mask & BIT(i))
+ brcm_sata_phy_disable(priv, i);
+}
+
+static u32 brcm_ahci_get_portmask(struct platform_device *pdev,
+ struct brcm_ahci_priv *priv)
+{
+ void __iomem *ahci;
+ struct resource *res;
+ u32 impl;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci");
+ ahci = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ahci))
+ return 0;
+
+ impl = readl(ahci + HOST_PORTS_IMPL);
+
+ if (fls(impl) > SATA_TOP_MAX_PHYS)
+ dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n",
+ impl);
+ else if (!impl)
+ dev_info(priv->dev, "no ports found\n");
+
+ devm_iounmap(&pdev->dev, ahci);
+ devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
+
+ return impl;
+}
+
+static void brcm_sata_init(struct brcm_ahci_priv *priv)
+{
+ /* Configure endianness */
+ brcm_sata_writereg(BUS_CTRL_ENDIAN_CONF,
+ priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
+}
+
+static int brcm_ahci_suspend(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct brcm_ahci_priv *priv = hpriv->plat_data;
+ int ret;
+
+ ret = ahci_platform_suspend(dev);
+ brcm_sata_phys_disable(priv);
+ return ret;
+}
+
+static int brcm_ahci_resume(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct brcm_ahci_priv *priv = hpriv->plat_data;
+
+ brcm_sata_init(priv);
+ brcm_sata_phys_enable(priv);
+ return ahci_platform_resume(dev);
+}
+
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT(DRV_NAME),
+};
+
+static int brcm_ahci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct brcm_ahci_priv *priv;
+ struct ahci_host_priv *hpriv;
+ struct resource *res;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->dev = dev;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "top-ctrl");
+ priv->top_ctrl = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->top_ctrl))
+ return PTR_ERR(priv->top_ctrl);
+
+ brcm_sata_init(priv);
+
+ priv->port_mask = brcm_ahci_get_portmask(pdev, priv);
+ if (!priv->port_mask)
+ return -ENODEV;
+
+ brcm_sata_phys_enable(priv);
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+ hpriv->plat_data = priv;
+
+ ret = ahci_platform_enable_resources(hpriv);
+ if (ret)
+ return ret;
+
+ ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
+ &ahci_platform_sht);
+ if (ret)
+ return ret;
+
+ dev_info(dev, "Broadcom AHCI SATA3 registered\n");
+
+ return 0;
+}
+
+static int brcm_ahci_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct brcm_ahci_priv *priv = hpriv->plat_data;
+ int ret;
+
+ ret = ata_platform_remove_one(pdev);
+ if (ret)
+ return ret;
+
+ brcm_sata_phys_disable(priv);
+
+ return 0;
+}
+
+static const struct of_device_id ahci_of_match[] = {
+ {.compatible = "brcm,bcm7445-ahci"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, ahci_of_match);
+
+static SIMPLE_DEV_PM_OPS(ahci_brcm_pm_ops, brcm_ahci_suspend, brcm_ahci_resume);
+
+static struct platform_driver brcm_ahci_driver = {
+ .probe = brcm_ahci_probe,
+ .remove = brcm_ahci_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = ahci_of_match,
+ .pm = &ahci_brcm_pm_ops,
+ },
+};
+module_platform_driver(brcm_ahci_driver);
+
+MODULE_DESCRIPTION("Broadcom SATA3 AHCI Controller Driver");
+MODULE_AUTHOR("Brian Norris");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sata-brcmstb");
diff --git a/drivers/ata/ahci_ceva.c b/drivers/ata/ahci_ceva.c
new file mode 100644
index 000000000000..207649d323c5
--- /dev/null
+++ b/drivers/ata/ahci_ceva.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2015 Xilinx, Inc.
+ * CEVA AHCI SATA platform driver
+ *
+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
+ *
+ * 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/ahci_platform.h>
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "ahci.h"
+
+/* Vendor Specific Register Offsets */
+#define AHCI_VEND_PCFG 0xA4
+#define AHCI_VEND_PPCFG 0xA8
+#define AHCI_VEND_PP2C 0xAC
+#define AHCI_VEND_PP3C 0xB0
+#define AHCI_VEND_PP4C 0xB4
+#define AHCI_VEND_PP5C 0xB8
+#define AHCI_VEND_PAXIC 0xC0
+#define AHCI_VEND_PTC 0xC8
+
+/* Vendor Specific Register bit definitions */
+#define PAXIC_ADBW_BW64 0x1
+#define PAXIC_MAWIDD (1 << 8)
+#define PAXIC_MARIDD (1 << 16)
+#define PAXIC_OTL (0x4 << 20)
+
+#define PCFG_TPSS_VAL (0x32 << 16)
+#define PCFG_TPRS_VAL (0x2 << 12)
+#define PCFG_PAD_VAL 0x2
+
+#define PPCFG_TTA 0x1FFFE
+#define PPCFG_PSSO_EN (1 << 28)
+#define PPCFG_PSS_EN (1 << 29)
+#define PPCFG_ESDF_EN (1 << 31)
+
+#define PP2C_CIBGMN 0x0F
+#define PP2C_CIBGMX (0x25 << 8)
+#define PP2C_CIBGN (0x18 << 16)
+#define PP2C_CINMP (0x29 << 24)
+
+#define PP3C_CWBGMN 0x04
+#define PP3C_CWBGMX (0x0B << 8)
+#define PP3C_CWBGN (0x08 << 16)
+#define PP3C_CWNMP (0x0F << 24)
+
+#define PP4C_BMX 0x0a
+#define PP4C_BNM (0x08 << 8)
+#define PP4C_SFD (0x4a << 16)
+#define PP4C_PTST (0x06 << 24)
+
+#define PP5C_RIT 0x60216
+#define PP5C_RCT (0x7f0 << 20)
+
+#define PTC_RX_WM_VAL 0x40
+#define PTC_RSVD (1 << 27)
+
+#define PORT0_BASE 0x100
+#define PORT1_BASE 0x180
+
+/* Port Control Register Bit Definitions */
+#define PORT_SCTL_SPD_GEN2 (0x2 << 4)
+#define PORT_SCTL_SPD_GEN1 (0x1 << 4)
+#define PORT_SCTL_IPM (0x3 << 8)
+
+#define PORT_BASE 0x100
+#define PORT_OFFSET 0x80
+#define NR_PORTS 2
+#define DRV_NAME "ahci-ceva"
+#define CEVA_FLAG_BROKEN_GEN2 1
+
+struct ceva_ahci_priv {
+ struct platform_device *ahci_pdev;
+ int flags;
+};
+
+static struct ata_port_operations ahci_ceva_ops = {
+ .inherits = &ahci_platform_ops,
+};
+
+static const struct ata_port_info ahci_ceva_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ceva_ops,
+};
+
+static void ahci_ceva_setup(struct ahci_host_priv *hpriv)
+{
+ void __iomem *mmio = hpriv->mmio;
+ struct ceva_ahci_priv *cevapriv = hpriv->plat_data;
+ u32 tmp;
+ int i;
+
+ /*
+ * AXI Data bus width to 64
+ * Set Mem Addr Read, Write ID for data transfers
+ * Transfer limit to 72 DWord
+ */
+ tmp = PAXIC_ADBW_BW64 | PAXIC_MAWIDD | PAXIC_MARIDD | PAXIC_OTL;
+ writel(tmp, mmio + AHCI_VEND_PAXIC);
+
+ /* Set AHCI Enable */
+ tmp = readl(mmio + HOST_CTL);
+ tmp |= HOST_AHCI_EN;
+ writel(tmp, mmio + HOST_CTL);
+
+ for (i = 0; i < NR_PORTS; i++) {
+ /* TPSS TPRS scalars, CISE and Port Addr */
+ tmp = PCFG_TPSS_VAL | PCFG_TPRS_VAL | (PCFG_PAD_VAL + i);
+ writel(tmp, mmio + AHCI_VEND_PCFG);
+
+ /* Port Phy Cfg register enables */
+ tmp = PPCFG_TTA | PPCFG_PSS_EN | PPCFG_ESDF_EN;
+ writel(tmp, mmio + AHCI_VEND_PPCFG);
+
+ /* Phy Control OOB timing parameters COMINIT */
+ tmp = PP2C_CIBGMN | PP2C_CIBGMX | PP2C_CIBGN | PP2C_CINMP;
+ writel(tmp, mmio + AHCI_VEND_PP2C);
+
+ /* Phy Control OOB timing parameters COMWAKE */
+ tmp = PP3C_CWBGMN | PP3C_CWBGMX | PP3C_CWBGN | PP3C_CWNMP;
+ writel(tmp, mmio + AHCI_VEND_PP3C);
+
+ /* Phy Control Burst timing setting */
+ tmp = PP4C_BMX | PP4C_BNM | PP4C_SFD | PP4C_PTST;
+ writel(tmp, mmio + AHCI_VEND_PP4C);
+
+ /* Rate Change Timer and Retry Interval Timer setting */
+ tmp = PP5C_RIT | PP5C_RCT;
+ writel(tmp, mmio + AHCI_VEND_PP5C);
+
+ /* Rx Watermark setting */
+ tmp = PTC_RX_WM_VAL | PTC_RSVD;
+ writel(tmp, mmio + AHCI_VEND_PTC);
+
+ /* Default to Gen 2 Speed and Gen 1 if Gen2 is broken */
+ tmp = PORT_SCTL_SPD_GEN2 | PORT_SCTL_IPM;
+ if (cevapriv->flags & CEVA_FLAG_BROKEN_GEN2)
+ tmp = PORT_SCTL_SPD_GEN1 | PORT_SCTL_IPM;
+ writel(tmp, mmio + PORT_SCR_CTL + PORT_BASE + PORT_OFFSET * i);
+ }
+}
+
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT(DRV_NAME),
+};
+
+static int ceva_ahci_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct ceva_ahci_priv *cevapriv;
+ int rc;
+
+ cevapriv = devm_kzalloc(dev, sizeof(*cevapriv), GFP_KERNEL);
+ if (!cevapriv)
+ return -ENOMEM;
+
+ cevapriv->ahci_pdev = pdev;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ if (of_property_read_bool(np, "ceva,broken-gen2"))
+ cevapriv->flags = CEVA_FLAG_BROKEN_GEN2;
+
+ hpriv->plat_data = cevapriv;
+
+ /* CEVA specific initialization */
+ ahci_ceva_setup(hpriv);
+
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_ceva_port_info,
+ &ahci_platform_sht);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+
+static int __maybe_unused ceva_ahci_suspend(struct device *dev)
+{
+ return ahci_platform_suspend_host(dev);
+}
+
+static int __maybe_unused ceva_ahci_resume(struct device *dev)
+{
+ return ahci_platform_resume_host(dev);
+}
+
+static SIMPLE_DEV_PM_OPS(ahci_ceva_pm_ops, ceva_ahci_suspend, ceva_ahci_resume);
+
+static const struct of_device_id ceva_ahci_of_match[] = {
+ { .compatible = "ceva,ahci-1v84" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ceva_ahci_of_match);
+
+static struct platform_driver ceva_ahci_driver = {
+ .probe = ceva_ahci_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = ceva_ahci_of_match,
+ .pm = &ahci_ceva_pm_ops,
+ },
+};
+module_platform_driver(ceva_ahci_driver);
+
+MODULE_DESCRIPTION("CEVA AHCI SATA platform driver");
+MODULE_AUTHOR("Xilinx Inc.");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c
index 5928d0746a27..8490d37aee2a 100644
--- a/drivers/ata/ahci_mvebu.c
+++ b/drivers/ata/ahci_mvebu.c
@@ -62,6 +62,26 @@ static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv)
writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA);
}
+static int ahci_mvebu_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return ahci_platform_suspend_host(&pdev->dev);
+}
+
+static int ahci_mvebu_resume(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ const struct mbus_dram_target_info *dram;
+
+ dram = mv_mbus_dram_info();
+ if (dram)
+ ahci_mvebu_mbus_config(hpriv, dram);
+
+ ahci_mvebu_regret_option(hpriv);
+
+ return ahci_platform_resume_host(&pdev->dev);
+}
+
static const struct ata_port_info ahci_mvebu_port_info = {
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
@@ -120,6 +140,8 @@ MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match);
static struct platform_driver ahci_mvebu_driver = {
.probe = ahci_mvebu_probe,
.remove = ata_platform_remove_one,
+ .suspend = ahci_mvebu_suspend,
+ .resume = ahci_mvebu_resume,
.driver = {
.name = DRV_NAME,
.of_match_table = ahci_mvebu_of_match,
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 78d6ae0b90c4..614c78f510f0 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -74,6 +74,7 @@ static const struct of_device_id ahci_of_match[] = {
{ .compatible = "ibm,476gtr-ahci", },
{ .compatible = "snps,dwc-ahci", },
{ .compatible = "hisilicon,hisi-ahci", },
+ { .compatible = "fsl,qoriq-ahci", },
{},
};
MODULE_DEVICE_TABLE(of, ahci_of_match);
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
index 2b78510d94dd..e2c6d9e0c5ac 100644
--- a/drivers/ata/ahci_xgene.c
+++ b/drivers/ata/ahci_xgene.c
@@ -27,6 +27,7 @@
#include <linux/platform_device.h>
#include <linux/ahci_platform.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/phy/phy.h>
#include "ahci.h"
@@ -84,6 +85,11 @@
/* Max retry for link down */
#define MAX_LINK_DOWN_RETRY 3
+enum xgene_ahci_version {
+ XGENE_AHCI_V1 = 1,
+ XGENE_AHCI_V2,
+};
+
struct xgene_ahci_context {
struct ahci_host_priv *hpriv;
struct device *dev;
@@ -542,7 +548,7 @@ softreset_retry:
return rc;
}
-static struct ata_port_operations xgene_ahci_ops = {
+static struct ata_port_operations xgene_ahci_v1_ops = {
.inherits = &ahci_ops,
.host_stop = xgene_ahci_host_stop,
.hardreset = xgene_ahci_hardreset,
@@ -552,11 +558,25 @@ static struct ata_port_operations xgene_ahci_ops = {
.pmp_softreset = xgene_ahci_pmp_softreset
};
-static const struct ata_port_info xgene_ahci_port_info = {
+static const struct ata_port_info xgene_ahci_v1_port_info = {
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &xgene_ahci_v1_ops,
+};
+
+static struct ata_port_operations xgene_ahci_v2_ops = {
+ .inherits = &ahci_ops,
+ .host_stop = xgene_ahci_host_stop,
+ .hardreset = xgene_ahci_hardreset,
+ .read_id = xgene_ahci_read_id,
+};
+
+static const struct ata_port_info xgene_ahci_v2_port_info = {
.flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
- .port_ops = &xgene_ahci_ops,
+ .port_ops = &xgene_ahci_v2_ops,
};
static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv)
@@ -629,12 +649,32 @@ static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME),
};
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_ahci_acpi_match[] = {
+ { "APMC0D0D", XGENE_AHCI_V1},
+ { "APMC0D32", XGENE_AHCI_V2},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match);
+#endif
+
+static const struct of_device_id xgene_ahci_of_match[] = {
+ {.compatible = "apm,xgene-ahci", .data = (void *) XGENE_AHCI_V1},
+ {.compatible = "apm,xgene-ahci-v2", .data = (void *) XGENE_AHCI_V2},
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
+
static int xgene_ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
struct xgene_ahci_context *ctx;
struct resource *res;
+ const struct of_device_id *of_devid;
+ enum xgene_ahci_version version = XGENE_AHCI_V1;
+ const struct ata_port_info *ppi[] = { &xgene_ahci_v1_port_info,
+ &xgene_ahci_v2_port_info };
int rc;
hpriv = ahci_platform_get_resources(pdev);
@@ -677,6 +717,35 @@ static int xgene_ahci_probe(struct platform_device *pdev)
ctx->csr_mux = csr;
}
+ of_devid = of_match_device(xgene_ahci_of_match, dev);
+ if (of_devid) {
+ if (of_devid->data)
+ version = (enum xgene_ahci_version) of_devid->data;
+ }
+#ifdef CONFIG_ACPI
+ else {
+ const struct acpi_device_id *acpi_id;
+ struct acpi_device_info *info;
+ acpi_status status;
+
+ acpi_id = acpi_match_device(xgene_ahci_acpi_match, &pdev->dev);
+ if (!acpi_id) {
+ dev_warn(&pdev->dev, "No node entry in ACPI table. Assume version1\n");
+ version = XGENE_AHCI_V1;
+ } else if (acpi_id->driver_data) {
+ version = (enum xgene_ahci_version) acpi_id->driver_data;
+ status = acpi_get_object_info(ACPI_HANDLE(&pdev->dev), &info);
+ if (ACPI_FAILURE(status)) {
+ dev_warn(&pdev->dev, "%s: Error reading device info. Assume version1\n",
+ __func__);
+ version = XGENE_AHCI_V1;
+ }
+ if (info->valid & ACPI_VALID_CID)
+ version = XGENE_AHCI_V2;
+ }
+ }
+#endif
+
dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core,
hpriv->mmio);
@@ -704,9 +773,19 @@ static int xgene_ahci_probe(struct platform_device *pdev)
/* Configure the host controller */
xgene_ahci_hw_init(hpriv);
skip_clk_phy:
- hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ;
- rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info,
+ switch (version) {
+ case XGENE_AHCI_V1:
+ hpriv->flags = AHCI_HFLAG_NO_NCQ;
+ break;
+ case XGENE_AHCI_V2:
+ hpriv->flags |= AHCI_HFLAG_YES_FBS | AHCI_HFLAG_EDGE_IRQ;
+ break;
+ default:
+ break;
+ }
+
+ rc = ahci_platform_init_host(pdev, hpriv, ppi[version - 1],
&ahci_platform_sht);
if (rc)
goto disable_resources;
@@ -719,20 +798,6 @@ disable_resources:
return rc;
}
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id xgene_ahci_acpi_match[] = {
- { "APMC0D0D", },
- { }
-};
-MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match);
-#endif
-
-static const struct of_device_id xgene_ahci_of_match[] = {
- {.compatible = "apm,xgene-ahci"},
- {},
-};
-MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
-
static struct platform_driver xgene_ahci_driver = {
.probe = xgene_ahci_probe,
.remove = ata_platform_remove_one,
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 287c4ba0219f..d256a66158be 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1825,11 +1825,38 @@ static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance)
return IRQ_WAKE_THREAD;
}
-static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance)
+static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
+{
+ unsigned int i, handled = 0;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap;
+
+ if (!(irq_masked & (1 << i)))
+ continue;
+
+ ap = host->ports[i];
+ if (ap) {
+ ahci_port_intr(ap);
+ VPRINTK("port %u\n", i);
+ } else {
+ VPRINTK("port %u (no irq)\n", i);
+ if (ata_ratelimit())
+ dev_warn(host->dev,
+ "interrupt on disabled port %u\n", i);
+ }
+
+ handled = 1;
+ }
+
+ return handled;
+}
+
+static irqreturn_t ahci_single_edge_irq_intr(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
struct ahci_host_priv *hpriv;
- unsigned int i, handled = 0;
+ unsigned int rc = 0;
void __iomem *mmio;
u32 irq_stat, irq_masked;
@@ -1847,25 +1874,44 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance)
spin_lock(&host->lock);
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap;
+ /*
+ * HOST_IRQ_STAT behaves as edge triggered latch meaning that
+ * it should be cleared before all the port events are cleared.
+ */
+ writel(irq_stat, mmio + HOST_IRQ_STAT);
- if (!(irq_masked & (1 << i)))
- continue;
+ rc = ahci_handle_port_intr(host, irq_masked);
- ap = host->ports[i];
- if (ap) {
- ahci_port_intr(ap);
- VPRINTK("port %u\n", i);
- } else {
- VPRINTK("port %u (no irq)\n", i);
- if (ata_ratelimit())
- dev_warn(host->dev,
- "interrupt on disabled port %u\n", i);
- }
+ spin_unlock(&host->lock);
- handled = 1;
- }
+ VPRINTK("EXIT\n");
+
+ return IRQ_RETVAL(rc);
+}
+
+static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ struct ahci_host_priv *hpriv;
+ unsigned int rc = 0;
+ void __iomem *mmio;
+ u32 irq_stat, irq_masked;
+
+ VPRINTK("ENTER\n");
+
+ hpriv = host->private_data;
+ mmio = hpriv->mmio;
+
+ /* sigh. 0xffffffff is a valid return from h/w */
+ irq_stat = readl(mmio + HOST_IRQ_STAT);
+ if (!irq_stat)
+ return IRQ_NONE;
+
+ irq_masked = irq_stat & hpriv->port_map;
+
+ spin_lock(&host->lock);
+
+ rc = ahci_handle_port_intr(host, irq_masked);
/* HOST_IRQ_STAT behaves as level triggered latch meaning that
* it should be cleared after all the port events are cleared;
@@ -1882,7 +1928,7 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance)
VPRINTK("EXIT\n");
- return IRQ_RETVAL(handled);
+ return IRQ_RETVAL(rc);
}
unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
@@ -2297,7 +2343,7 @@ static int ahci_port_start(struct ata_port *ap)
/*
* Switch to per-port locking in case each port has its own MSI vector.
*/
- if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) {
+ if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) {
spin_lock_init(&pp->lock);
ap->lock = &pp->lock;
}
@@ -2425,7 +2471,10 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
rc = ata_host_start(host);
if (rc)
return rc;
-
+ /*
+ * Requests IRQs according to AHCI-1.1 when multiple MSIs were
+ * allocated. That is one MSI per port, starting from @irq.
+ */
for (i = 0; i < host->n_ports; i++) {
struct ahci_port_priv *pp = host->ports[i]->private_data;
@@ -2464,29 +2513,27 @@ out_free_irqs:
/**
* ahci_host_activate - start AHCI host, request IRQs and register it
* @host: target ATA host
- * @irq: base IRQ number to request
* @sht: scsi_host_template to use when registering the host
*
- * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
- * when multiple MSIs were allocated. That is one MSI per port, starting
- * from @irq.
- *
* LOCKING:
* Inherited from calling layer (may sleep).
*
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ahci_host_activate(struct ata_host *host, int irq,
- struct scsi_host_template *sht)
+int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
{
struct ahci_host_priv *hpriv = host->private_data;
+ int irq = hpriv->irq;
int rc;
if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
rc = ahci_host_activate_multi_irqs(host, irq, sht);
+ else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ)
+ rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr,
+ IRQF_SHARED, sht);
else
- rc = ata_host_activate(host, irq, ahci_single_irq_intr,
+ rc = ata_host_activate(host, irq, ahci_single_level_irq_intr,
IRQF_SHARED, sht);
return rc;
}
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index d89305d289f6..aaa761b9081c 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -518,6 +518,8 @@ int ahci_platform_init_host(struct platform_device *pdev,
return -EINVAL;
}
+ hpriv->irq = irq;
+
/* prepare host */
pi.private_data = (void *)(unsigned long)hpriv->flags;
@@ -588,7 +590,7 @@ int ahci_platform_init_host(struct platform_device *pdev,
ahci_init_controller(host);
ahci_print_info(host, "platform");
- return ahci_host_activate(host, irq, sht);
+ return ahci_host_activate(host, sht);
}
EXPORT_SYMBOL_GPL(ahci_platform_init_host);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 577849c6611a..e83fc3d0da9c 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -3654,7 +3654,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
* EH context.
*
* RETURNS:
- * 0 on succes, -errno otherwise.
+ * 0 on success, -errno otherwise.
*/
int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
bool spm_wakeup)
@@ -4225,7 +4225,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER },
/* devices that don't properly handle queued TRIM commands */
- { "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
+ { "Micron_M500_*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
{ "Crucial_CT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, },
@@ -6456,12 +6456,7 @@ static int __init ata_parse_force_one(char **cur,
struct ata_force_ent *force_ent,
const char **reason)
{
- /* FIXME: Currently, there's no way to tag init const data and
- * using __initdata causes build failure on some versions of
- * gcc. Once __initdataconst is implemented, add const to the
- * following structure.
- */
- static struct ata_force_param force_tbl[] __initdata = {
+ static const struct ata_force_param force_tbl[] __initconst = {
{ "40c", .cbl = ATA_CBL_PATA40 },
{ "80c", .cbl = ATA_CBL_PATA80 },
{ "short40c", .cbl = ATA_CBL_PATA40_SHORT },
@@ -6472,6 +6467,8 @@ static int __init ata_parse_force_one(char **cur,
{ "3.0Gbps", .spd_limit = 2 },
{ "noncq", .horkage_on = ATA_HORKAGE_NONCQ },
{ "ncq", .horkage_off = ATA_HORKAGE_NONCQ },
+ { "noncqtrim", .horkage_on = ATA_HORKAGE_NO_NCQ_TRIM },
+ { "ncqtrim", .horkage_off = ATA_HORKAGE_NO_NCQ_TRIM },
{ "dump_id", .horkage_on = ATA_HORKAGE_DUMP_ID },
{ "pio0", .xfer_mask = 1 << (ATA_SHIFT_PIO + 0) },
{ "pio1", .xfer_mask = 1 << (ATA_SHIFT_PIO + 1) },
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index cf0022ec07f2..7465031a893c 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1507,16 +1507,21 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
{
struct ata_taskfile tf;
unsigned int err_mask;
+ bool dma = false;
DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
+retry:
ata_tf_init(dev, &tf);
- if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id)) {
+ if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) &&
+ !(dev->horkage & ATA_HORKAGE_NO_NCQ_LOG)) {
tf.command = ATA_CMD_READ_LOG_DMA_EXT;
tf.protocol = ATA_PROT_DMA;
+ dma = true;
} else {
tf.command = ATA_CMD_READ_LOG_EXT;
tf.protocol = ATA_PROT_PIO;
+ dma = false;
}
tf.lbal = log;
tf.lbam = page;
@@ -1527,6 +1532,12 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
buf, sectors * ATA_SECT_SIZE, 0);
+ if (err_mask && dma) {
+ dev->horkage |= ATA_HORKAGE_NO_NCQ_LOG;
+ ata_dev_warn(dev, "READ LOG DMA EXT failed, trying unqueued\n");
+ goto retry;
+ }
+
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
}
diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
index 3227b7c8a05f..d6c37bcd416d 100644
--- a/drivers/ata/libata-transport.c
+++ b/drivers/ata/libata-transport.c
@@ -560,6 +560,27 @@ show_ata_dev_gscr(struct device *dev,
static DEVICE_ATTR(gscr, S_IRUGO, show_ata_dev_gscr, NULL);
+static ssize_t
+show_ata_dev_trim(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ata_device *ata_dev = transport_class_to_dev(dev);
+ unsigned char *mode;
+
+ if (!ata_id_has_trim(ata_dev->id))
+ mode = "unsupported";
+ else if (ata_dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM)
+ mode = "forced_unqueued";
+ else if (ata_fpdma_dsm_supported(ata_dev))
+ mode = "queued";
+ else
+ mode = "unqueued";
+
+ return snprintf(buf, 20, "%s\n", mode);
+}
+
+static DEVICE_ATTR(trim, S_IRUGO, show_ata_dev_trim, NULL);
+
static DECLARE_TRANSPORT_CLASS(ata_dev_class,
"ata_device", NULL, NULL, NULL);
@@ -733,6 +754,7 @@ struct scsi_transport_template *ata_attach_transport(void)
SETUP_DEV_ATTRIBUTE(ering);
SETUP_DEV_ATTRIBUTE(id);
SETUP_DEV_ATTRIBUTE(gscr);
+ SETUP_DEV_ATTRIBUTE(trim);
BUG_ON(count > ATA_DEV_ATTRS);
i->dev_attrs[count] = NULL;
diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c
index 9e85937d36a9..ace0a4de3449 100644
--- a/drivers/ata/pata_at91.c
+++ b/drivers/ata/pata_at91.c
@@ -24,11 +24,13 @@
#include <linux/ata.h>
#include <linux/clk.h>
#include <linux/libata.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/atmel-smc.h>
#include <linux/platform_device.h>
#include <linux/ata_platform.h>
#include <linux/platform_data/atmel.h>
+#include <linux/regmap.h>
-#include <mach/at91sam9_smc.h>
#include <asm/gpio.h>
#define DRV_NAME "pata_at91"
@@ -57,6 +59,15 @@ struct smc_range {
int max;
};
+struct regmap *smc;
+
+struct at91sam9_smc_generic_fields {
+ struct regmap_field *setup;
+ struct regmap_field *pulse;
+ struct regmap_field *cycle;
+ struct regmap_field *mode;
+} fields;
+
/**
* adjust_smc_value - adjust value for one of SMC registers.
* @value: adjusted value
@@ -206,7 +217,6 @@ static void set_smc_timing(struct device *dev, struct ata_device *adev,
{
int ret = 0;
int use_iordy;
- struct sam9_smc_config smc;
unsigned int t6z; /* data tristate time in ns */
unsigned int cycle; /* SMC Cycle width in MCK ticks */
unsigned int setup; /* SMC Setup width in MCK ticks */
@@ -244,19 +254,21 @@ static void set_smc_timing(struct device *dev, struct ata_device *adev,
dev_dbg(dev, "Use IORDY=%u, TDF Cycles=%u\n", use_iordy, tdf_cycles);
- /* SMC Setup Register */
- smc.nwe_setup = smc.nrd_setup = setup;
- smc.ncs_write_setup = smc.ncs_read_setup = 0;
- /* SMC Pulse Register */
- smc.nwe_pulse = smc.nrd_pulse = pulse;
- smc.ncs_write_pulse = smc.ncs_read_pulse = cs_pulse;
- /* SMC Cycle Register */
- smc.write_cycle = smc.read_cycle = cycle;
- /* SMC Mode Register*/
- smc.tdf_cycles = tdf_cycles;
- smc.mode = info->mode;
-
- sam9_smc_configure(0, info->cs, &smc);
+ regmap_fields_write(fields.setup, info->cs,
+ AT91SAM9_SMC_NRDSETUP(setup) |
+ AT91SAM9_SMC_NWESETUP(setup) |
+ AT91SAM9_SMC_NCS_NRDSETUP(0) |
+ AT91SAM9_SMC_NCS_WRSETUP(0));
+ regmap_fields_write(fields.pulse, info->cs,
+ AT91SAM9_SMC_NRDPULSE(pulse) |
+ AT91SAM9_SMC_NWEPULSE(pulse) |
+ AT91SAM9_SMC_NCS_NRDPULSE(cs_pulse) |
+ AT91SAM9_SMC_NCS_WRPULSE(cs_pulse));
+ regmap_fields_write(fields.cycle, info->cs,
+ AT91SAM9_SMC_NRDCYCLE(cycle) |
+ AT91SAM9_SMC_NWECYCLE(cycle));
+ regmap_fields_write(fields.mode, info->cs, info->mode |
+ AT91_SMC_TDF_(tdf_cycles));
}
static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -280,21 +292,21 @@ static unsigned int pata_at91_data_xfer_noirq(struct ata_device *dev,
{
struct at91_ide_info *info = dev->link->ap->host->private_data;
unsigned int consumed;
+ unsigned int mode;
unsigned long flags;
- struct sam9_smc_config smc;
local_irq_save(flags);
- sam9_smc_read_mode(0, info->cs, &smc);
+ regmap_fields_read(fields.mode, info->cs, &mode);
/* set 16bit mode before writing data */
- smc.mode = (smc.mode & ~AT91_SMC_DBW) | AT91_SMC_DBW_16;
- sam9_smc_write_mode(0, info->cs, &smc);
+ regmap_fields_write(fields.mode, info->cs, (mode & ~AT91_SMC_DBW) |
+ AT91_SMC_DBW_16);
consumed = ata_sff_data_xfer(dev, buf, buflen, rw);
/* restore 8bit mode after data is written */
- smc.mode = (smc.mode & ~AT91_SMC_DBW) | AT91_SMC_DBW_8;
- sam9_smc_write_mode(0, info->cs, &smc);
+ regmap_fields_write(fields.mode, info->cs, (mode & ~AT91_SMC_DBW) |
+ AT91_SMC_DBW_8);
local_irq_restore(flags);
return consumed;
@@ -312,6 +324,36 @@ static struct ata_port_operations pata_at91_port_ops = {
.cable_detect = ata_cable_40wire,
};
+static int at91sam9_smc_fields_init(struct device *dev)
+{
+ struct reg_field field = REG_FIELD(0, 0, 31);
+
+ field.id_size = 8;
+ field.id_offset = AT91SAM9_SMC_GENERIC_BLK_SZ;
+
+ field.reg = AT91SAM9_SMC_SETUP(AT91SAM9_SMC_GENERIC);
+ fields.setup = devm_regmap_field_alloc(dev, smc, field);
+ if (IS_ERR(fields.setup))
+ return PTR_ERR(fields.setup);
+
+ field.reg = AT91SAM9_SMC_PULSE(AT91SAM9_SMC_GENERIC);
+ fields.pulse = devm_regmap_field_alloc(dev, smc, field);
+ if (IS_ERR(fields.pulse))
+ return PTR_ERR(fields.pulse);
+
+ field.reg = AT91SAM9_SMC_CYCLE(AT91SAM9_SMC_GENERIC);
+ fields.cycle = devm_regmap_field_alloc(dev, smc, field);
+ if (IS_ERR(fields.cycle))
+ return PTR_ERR(fields.cycle);
+
+ field.reg = AT91SAM9_SMC_MODE(AT91SAM9_SMC_GENERIC);
+ fields.mode = devm_regmap_field_alloc(dev, smc, field);
+ if (IS_ERR(fields.mode))
+ return PTR_ERR(fields.mode);
+
+ return 0;
+}
+
static int pata_at91_probe(struct platform_device *pdev)
{
struct at91_cf_data *board = dev_get_platdata(&pdev->dev);
@@ -341,6 +383,14 @@ static int pata_at91_probe(struct platform_device *pdev)
irq = board->irq_pin;
+ smc = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "atmel,smc");
+ if (IS_ERR(smc))
+ return PTR_ERR(smc);
+
+ ret = at91sam9_smc_fields_init(dev);
+ if (ret < 0)
+ return ret;
+
/* init ata host */
host = ata_host_alloc(dev, 1);
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index cbc3de793d1d..0038dc4c06c7 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -352,7 +352,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
};
const struct ata_port_info *ppi[] = { &info_hpt366, NULL };
- void *hpriv = NULL;
+ const void *hpriv = NULL;
u32 reg1;
int rc;
@@ -383,7 +383,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
break;
}
/* Now kick off ATA set up */
- return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, hpriv, 0);
+ return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, (void *)hpriv, 0);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c
index fa44eb2872db..cbb5a471eb9d 100644
--- a/drivers/ata/pata_samsung_cf.c
+++ b/drivers/ata/pata_samsung_cf.c
@@ -638,7 +638,7 @@ static const struct dev_pm_ops pata_s3c_pm_ops = {
#endif
/* driver device registration */
-static struct platform_device_id pata_s3c_driver_ids[] = {
+static const struct platform_device_id pata_s3c_driver_ids[] = {
{
.name = "s3c64xx-pata",
.driver_data = TYPE_S3C64XX,
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index 24e311fe2c1c..8638d575b2b9 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -499,6 +499,7 @@ static int ahci_highbank_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ hpriv->irq = irq;
hpriv->flags |= (unsigned long)pi.private_data;
hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
@@ -568,7 +569,7 @@ static int ahci_highbank_probe(struct platform_device *pdev)
ahci_init_controller(host);
ahci_print_info(host, "platform");
- rc = ahci_host_activate(host, irq, &ahci_highbank_platform_sht);
+ rc = ahci_host_activate(host, &ahci_highbank_platform_sht);
if (rc)
goto err0;
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 7ece85f43020..734f563b8d37 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -599,7 +599,7 @@ MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
MODULE_VERSION(DRV_VERSION);
static bool adma_enabled;
-static bool swncq_enabled = 1;
+static bool swncq_enabled = true;
static bool msi_enabled;
static void nv_adma_register_mode(struct ata_port *ap)
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 93dca2e73bf5..a8da3a50e374 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -116,8 +116,8 @@ static bool disable64;
static short nvpibits = -1;
static short nvcibits = -1;
static short rx_skb_reserve = 16;
-static bool irq_coalesce = 1;
-static bool sdh = 0;
+static bool irq_coalesce = true;
+static bool sdh;
/* Read from EEPROM = 0000 0011b */
static unsigned int readtab[] = {
diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
index 909c95bd7be2..feb023d7eebd 100644
--- a/drivers/atm/idt77105.c
+++ b/drivers/atm/idt77105.c
@@ -306,14 +306,12 @@ static int idt77105_start(struct atm_dev *dev)
if (start_timer) {
start_timer = 0;
- init_timer(&stats_timer);
+ setup_timer(&stats_timer, idt77105_stats_timer_func, 0UL);
stats_timer.expires = jiffies+IDT77105_STATS_TIMER_PERIOD;
- stats_timer.function = idt77105_stats_timer_func;
add_timer(&stats_timer);
- init_timer(&restart_timer);
+ setup_timer(&restart_timer, idt77105_restart_timer_func, 0UL);
restart_timer.expires = jiffies+IDT77105_RESTART_TIMER_PERIOD;
- restart_timer.function = idt77105_restart_timer_func;
add_timer(&restart_timer);
}
spin_unlock_irqrestore(&idt77105_priv_lock, flags);
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 924f8e26789d..65e65903faa0 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -2618,7 +2618,7 @@ static void ia_close(struct atm_vcc *vcc)
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
iadev->close_pending++;
prepare_to_wait(&iadev->timeout_wait, &wait, TASK_UNINTERRUPTIBLE);
- schedule_timeout(50);
+ schedule_timeout(msecs_to_jiffies(500));
finish_wait(&iadev->timeout_wait, &wait);
spin_lock_irqsave(&iadev->tx_lock, flags);
while((skb = skb_dequeue(&iadev->tx_backlog))) {
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 251c5d30f963..fd3347d9f153 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -116,6 +116,7 @@ static inline int driver_match_device(struct device_driver *drv,
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
+extern bool driver_allows_async_probing(struct device_driver *drv);
extern int driver_add_groups(struct device_driver *drv,
const struct attribute_group **groups);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 79bc203f51ef..500592486e88 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -10,6 +10,7 @@
*
*/
+#include <linux/async.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/errno.h>
@@ -549,15 +550,12 @@ void bus_probe_device(struct device *dev)
{
struct bus_type *bus = dev->bus;
struct subsys_interface *sif;
- int ret;
if (!bus)
return;
- if (bus->p->drivers_autoprobe) {
- ret = device_attach(dev);
- WARN_ON(ret < 0);
- }
+ if (bus->p->drivers_autoprobe)
+ device_initial_probe(dev);
mutex_lock(&bus->p->mutex);
list_for_each_entry(sif, &bus->p->interfaces, node)
@@ -659,6 +657,17 @@ static ssize_t uevent_store(struct device_driver *drv, const char *buf,
}
static DRIVER_ATTR_WO(uevent);
+static void driver_attach_async(void *_drv, async_cookie_t cookie)
+{
+ struct device_driver *drv = _drv;
+ int ret;
+
+ ret = driver_attach(drv);
+
+ pr_debug("bus: '%s': driver %s async attach completed: %d\n",
+ drv->bus->name, drv->name, ret);
+}
+
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
@@ -691,9 +700,15 @@ int bus_add_driver(struct device_driver *drv)
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) {
- error = driver_attach(drv);
- if (error)
- goto out_unregister;
+ if (driver_allows_async_probing(drv)) {
+ pr_debug("bus: '%s': probing driver %s asynchronously\n",
+ drv->bus->name, drv->name);
+ async_schedule(driver_attach_async, drv);
+ } else {
+ error = driver_attach(drv);
+ if (error)
+ goto out_unregister;
+ }
}
module_add_driver(drv->owner, drv);
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index df0c66cb7ad3..764280a91776 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -191,12 +191,12 @@ static int detect_cache_attributes(unsigned int cpu)
if (ret)
goto free_ci;
/*
- * For systems using DT for cache hierarcy, of_node and shared_cpu_map
+ * For systems using DT for cache hierarchy, of_node and shared_cpu_map
* will be set up here only if they are not populated already
*/
ret = cache_shared_cpu_map_setup(cpu);
if (ret) {
- pr_warn("Unable to detect cache hierarcy from DT for CPU %d\n",
+ pr_warn("Unable to detect cache hierarchy from DT for CPU %d\n",
cpu);
goto free_ci;
}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 21d13038534e..dafae6d2f7ac 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1303,12 +1303,11 @@ const char *device_get_devnode(struct device *dev,
return dev_name(dev);
/* replace '!' in the name with '/' */
- *tmp = kstrdup(dev_name(dev), GFP_KERNEL);
- if (!*tmp)
+ s = kstrdup(dev_name(dev), GFP_KERNEL);
+ if (!s)
return NULL;
- while ((s = strchr(*tmp, '!')))
- s[0] = '/';
- return *tmp;
+ strreplace(s, '!', '/');
+ return *tmp = s;
}
/**
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index f160ea44a86d..78720e706176 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -16,6 +16,7 @@
#include <linux/acpi.h>
#include <linux/of.h>
#include <linux/cpufeature.h>
+#include <linux/tick.h>
#include "base.h"
@@ -265,6 +266,30 @@ static ssize_t print_cpus_offline(struct device *dev,
}
static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL);
+static ssize_t print_cpus_isolated(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int n = 0, len = PAGE_SIZE-2;
+
+ n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(cpu_isolated_map));
+
+ return n;
+}
+static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL);
+
+#ifdef CONFIG_NO_HZ_FULL
+static ssize_t print_cpus_nohz_full(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int n = 0, len = PAGE_SIZE-2;
+
+ n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask));
+
+ return n;
+}
+static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL);
+#endif
+
static void cpu_device_release(struct device *dev)
{
/*
@@ -431,6 +456,10 @@ static struct attribute *cpu_root_attrs[] = {
&cpu_attrs[2].attr.attr,
&dev_attr_kernel_max.attr,
&dev_attr_offline.attr,
+ &dev_attr_isolated.attr,
+#ifdef CONFIG_NO_HZ_FULL
+ &dev_attr_nohz_full.attr,
+#endif
#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
&dev_attr_modalias.attr,
#endif
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index e843fdbe4925..a638bbb1a27a 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -141,7 +141,7 @@ static bool driver_deferred_probe_enable = false;
* more than one device is probing at the same time, it is possible for one
* probe to complete successfully while another is about to defer. If the second
* depends on the first, then it will get put on the pending list after the
- * trigger event has already occured and will be stuck there.
+ * trigger event has already occurred and will be stuck there.
*
* The atomic 'deferred_trigger_count' is used to determine if a successful
* trigger has occurred in the midst of probing a driver. If the trigger count
@@ -417,31 +417,107 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
return ret;
}
-static int __device_attach(struct device_driver *drv, void *data)
+bool driver_allows_async_probing(struct device_driver *drv)
{
- struct device *dev = data;
+ switch (drv->probe_type) {
+ case PROBE_PREFER_ASYNCHRONOUS:
+ return true;
+
+ case PROBE_FORCE_SYNCHRONOUS:
+ return false;
+
+ default:
+ if (module_requested_async_probing(drv->owner))
+ return true;
+
+ return false;
+ }
+}
+
+struct device_attach_data {
+ struct device *dev;
+
+ /*
+ * Indicates whether we are are considering asynchronous probing or
+ * not. Only initial binding after device or driver registration
+ * (including deferral processing) may be done asynchronously, the
+ * rest is always synchronous, as we expect it is being done by
+ * request from userspace.
+ */
+ bool check_async;
+
+ /*
+ * Indicates if we are binding synchronous or asynchronous drivers.
+ * When asynchronous probing is enabled we'll execute 2 passes
+ * over drivers: first pass doing synchronous probing and second
+ * doing asynchronous probing (if synchronous did not succeed -
+ * most likely because there was no driver requiring synchronous
+ * probing - and we found asynchronous driver during first pass).
+ * The 2 passes are done because we can't shoot asynchronous
+ * probe for given device and driver from bus_for_each_drv() since
+ * driver pointer is not guaranteed to stay valid once
+ * bus_for_each_drv() iterates to the next driver on the bus.
+ */
+ bool want_async;
+
+ /*
+ * We'll set have_async to 'true' if, while scanning for matching
+ * driver, we'll encounter one that requests asynchronous probing.
+ */
+ bool have_async;
+};
+
+static int __device_attach_driver(struct device_driver *drv, void *_data)
+{
+ struct device_attach_data *data = _data;
+ struct device *dev = data->dev;
+ bool async_allowed;
+
+ /*
+ * Check if device has already been claimed. This may
+ * happen with driver loading, device discovery/registration,
+ * and deferred probe processing happens all at once with
+ * multiple threads.
+ */
+ if (dev->driver)
+ return -EBUSY;
if (!driver_match_device(drv, dev))
return 0;
+ async_allowed = driver_allows_async_probing(drv);
+
+ if (async_allowed)
+ data->have_async = true;
+
+ if (data->check_async && async_allowed != data->want_async)
+ return 0;
+
return driver_probe_device(drv, dev);
}
-/**
- * device_attach - try to attach device to a driver.
- * @dev: device.
- *
- * Walk the list of drivers that the bus has and call
- * driver_probe_device() for each pair. If a compatible
- * pair is found, break out and return.
- *
- * Returns 1 if the device was bound to a driver;
- * 0 if no matching driver was found;
- * -ENODEV if the device is not registered.
- *
- * When called for a USB interface, @dev->parent lock must be held.
- */
-int device_attach(struct device *dev)
+static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
+{
+ struct device *dev = _dev;
+ struct device_attach_data data = {
+ .dev = dev,
+ .check_async = true,
+ .want_async = true,
+ };
+
+ device_lock(dev);
+
+ bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
+ dev_dbg(dev, "async probe completed\n");
+
+ pm_request_idle(dev);
+
+ device_unlock(dev);
+
+ put_device(dev);
+}
+
+static int __device_attach(struct device *dev, bool allow_async)
{
int ret = 0;
@@ -459,15 +535,59 @@ int device_attach(struct device *dev)
ret = 0;
}
} else {
- ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
- pm_request_idle(dev);
+ struct device_attach_data data = {
+ .dev = dev,
+ .check_async = allow_async,
+ .want_async = false,
+ };
+
+ ret = bus_for_each_drv(dev->bus, NULL, &data,
+ __device_attach_driver);
+ if (!ret && allow_async && data.have_async) {
+ /*
+ * If we could not find appropriate driver
+ * synchronously and we are allowed to do
+ * async probes and there are drivers that
+ * want to probe asynchronously, we'll
+ * try them.
+ */
+ dev_dbg(dev, "scheduling asynchronous probe\n");
+ get_device(dev);
+ async_schedule(__device_attach_async_helper, dev);
+ } else {
+ pm_request_idle(dev);
+ }
}
out_unlock:
device_unlock(dev);
return ret;
}
+
+/**
+ * device_attach - try to attach device to a driver.
+ * @dev: device.
+ *
+ * Walk the list of drivers that the bus has and call
+ * driver_probe_device() for each pair. If a compatible
+ * pair is found, break out and return.
+ *
+ * Returns 1 if the device was bound to a driver;
+ * 0 if no matching driver was found;
+ * -ENODEV if the device is not registered.
+ *
+ * When called for a USB interface, @dev->parent lock must be held.
+ */
+int device_attach(struct device *dev)
+{
+ return __device_attach(dev, false);
+}
EXPORT_SYMBOL_GPL(device_attach);
+void device_initial_probe(struct device *dev)
+{
+ __device_attach(dev, true);
+}
+
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
@@ -522,6 +642,9 @@ static void __device_release_driver(struct device *dev)
drv = dev->driver;
if (drv) {
+ if (driver_allows_async_probing(drv))
+ async_synchronize_full();
+
pm_runtime_get_sync(dev);
driver_sysfs_remove(dev);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 171841ad1008..9c4288362a8e 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -150,17 +150,17 @@ struct firmware_buf {
int page_array_size;
struct list_head pending_list;
#endif
- char fw_id[];
+ const char *fw_id;
};
struct fw_cache_entry {
struct list_head list;
- char name[];
+ const char *name;
};
struct fw_name_devm {
unsigned long magic;
- char name[];
+ const char *name;
};
#define to_fwbuf(d) container_of(d, struct firmware_buf, ref)
@@ -181,13 +181,17 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
{
struct firmware_buf *buf;
- buf = kzalloc(sizeof(*buf) + strlen(fw_name) + 1, GFP_ATOMIC);
-
+ buf = kzalloc(sizeof(*buf), GFP_ATOMIC);
if (!buf)
- return buf;
+ return NULL;
+
+ buf->fw_id = kstrdup_const(fw_name, GFP_ATOMIC);
+ if (!buf->fw_id) {
+ kfree(buf);
+ return NULL;
+ }
kref_init(&buf->ref);
- strcpy(buf->fw_id, fw_name);
buf->fwc = fwc;
init_completion(&buf->completion);
#ifdef CONFIG_FW_LOADER_USER_HELPER
@@ -257,6 +261,7 @@ static void __fw_free_buf(struct kref *ref)
} else
#endif
vfree(buf->data);
+ kfree_const(buf->fw_id);
kfree(buf);
}
@@ -320,9 +325,13 @@ fail:
static int fw_get_filesystem_firmware(struct device *device,
struct firmware_buf *buf)
{
- int i;
+ int i, len;
int rc = -ENOENT;
- char *path = __getname();
+ char *path;
+
+ path = __getname();
+ if (!path)
+ return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
struct file *file;
@@ -331,7 +340,12 @@ static int fw_get_filesystem_firmware(struct device *device,
if (!fw_path[i][0])
continue;
- snprintf(path, PATH_MAX, "%s/%s", fw_path[i], buf->fw_id);
+ len = snprintf(path, PATH_MAX, "%s/%s",
+ fw_path[i], buf->fw_id);
+ if (len >= PATH_MAX) {
+ rc = -ENAMETOOLONG;
+ break;
+ }
file = filp_open(path, O_RDONLY, 0);
if (IS_ERR(file))
@@ -392,6 +406,7 @@ static void fw_name_devm_release(struct device *dev, void *res)
if (fwn->magic == (unsigned long)&fw_cache)
pr_debug("%s: fw_name-%s devm-%p released\n",
__func__, fwn->name, res);
+ kfree_const(fwn->name);
}
static int fw_devm_match(struct device *dev, void *res,
@@ -422,13 +437,17 @@ static int fw_add_devm_name(struct device *dev, const char *name)
if (fwn)
return 1;
- fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) +
- strlen(name) + 1, GFP_KERNEL);
+ fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm),
+ GFP_KERNEL);
if (!fwn)
return -ENOMEM;
+ fwn->name = kstrdup_const(name, GFP_KERNEL);
+ if (!fwn->name) {
+ kfree(fwn);
+ return -ENOMEM;
+ }
fwn->magic = (unsigned long)&fw_cache;
- strcpy(fwn->name, name);
devres_add(dev, fwn);
return 0;
@@ -1247,6 +1266,7 @@ static void request_firmware_work_func(struct work_struct *work)
put_device(fw_work->device); /* taken in request_firmware_nowait() */
module_put(fw_work->module);
+ kfree_const(fw_work->name);
kfree(fw_work);
}
@@ -1286,7 +1306,11 @@ request_firmware_nowait(
return -ENOMEM;
fw_work->module = module;
- fw_work->name = name;
+ fw_work->name = kstrdup_const(name, gfp);
+ if (!fw_work->name) {
+ kfree(fw_work);
+ return -ENOMEM;
+ }
fw_work->device = device;
fw_work->context = context;
fw_work->cont = cont;
@@ -1294,6 +1318,7 @@ request_firmware_nowait(
(uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER);
if (!try_module_get(module)) {
+ kfree_const(fw_work->name);
kfree(fw_work);
return -EFAULT;
}
@@ -1384,11 +1409,16 @@ static struct fw_cache_entry *alloc_fw_cache_entry(const char *name)
{
struct fw_cache_entry *fce;
- fce = kzalloc(sizeof(*fce) + strlen(name) + 1, GFP_ATOMIC);
+ fce = kzalloc(sizeof(*fce), GFP_ATOMIC);
if (!fce)
goto exit;
- strcpy(fce->name, name);
+ fce->name = kstrdup_const(name, GFP_ATOMIC);
+ if (!fce->name) {
+ kfree(fce);
+ fce = NULL;
+ goto exit;
+ }
exit:
return fce;
}
@@ -1428,6 +1458,7 @@ found:
static void free_fw_cache_entry(struct fw_cache_entry *fce)
{
+ kfree_const(fce->name);
kfree(fce);
}
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index ebf034b97278..063f0ab15259 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -613,6 +613,19 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv,
{
int retval, code;
+ if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) {
+ pr_err("%s: drivers registered with %s can not be probed asynchronously\n",
+ drv->driver.name, __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * We have to run our probes synchronously because we check if
+ * we find any devices to bind to and exit with error if there
+ * are any.
+ */
+ drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS;
+
/*
* Prevent driver from requesting probe deferral to avoid further
* futile probe attempts.
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 1cb8544598d5..f94a6ccfe787 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o
+obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o
obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
obj-$(CONFIG_PM_OPP) += opp.o
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index 7fdd0172605a..acef9f9f759a 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -15,6 +15,7 @@
#include <linux/clkdev.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/pm_runtime.h>
#ifdef CONFIG_PM
@@ -67,7 +68,8 @@ static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
} else {
clk_prepare(ce->clk);
ce->status = PCE_STATUS_ACQUIRED;
- dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
+ dev_dbg(dev, "Clock %pC con_id %s managed by runtime PM.\n",
+ ce->clk, ce->con_id);
}
}
@@ -93,7 +95,7 @@ static int __pm_clk_add(struct device *dev, const char *con_id,
return -ENOMEM;
}
} else {
- if (IS_ERR(ce->clk) || !__clk_get(clk)) {
+ if (IS_ERR(clk) || !__clk_get(clk)) {
kfree(ce);
return -ENOENT;
}
@@ -367,6 +369,43 @@ static int pm_clk_notify(struct notifier_block *nb,
return 0;
}
+int pm_clk_runtime_suspend(struct device *dev)
+{
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ ret = pm_generic_runtime_suspend(dev);
+ if (ret) {
+ dev_err(dev, "failed to suspend device\n");
+ return ret;
+ }
+
+ ret = pm_clk_suspend(dev);
+ if (ret) {
+ dev_err(dev, "failed to suspend clock\n");
+ pm_generic_runtime_resume(dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+int pm_clk_runtime_resume(struct device *dev)
+{
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ ret = pm_clk_resume(dev);
+ if (ret) {
+ dev_err(dev, "failed to resume clock\n");
+ return ret;
+ }
+
+ return pm_generic_runtime_resume(dev);
+}
+
#else /* !CONFIG_PM */
/**
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 2327613d4539..cdd547bd67df 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -181,7 +181,7 @@ static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd)
genpd->cpuidle_data->idle_state->exit_latency = usecs64;
}
-static int genpd_power_on(struct generic_pm_domain *genpd)
+static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
{
ktime_t time_start;
s64 elapsed_ns;
@@ -190,6 +190,9 @@ static int genpd_power_on(struct generic_pm_domain *genpd)
if (!genpd->power_on)
return 0;
+ if (!timed)
+ return genpd->power_on(genpd);
+
time_start = ktime_get();
ret = genpd->power_on(genpd);
if (ret)
@@ -208,7 +211,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd)
return ret;
}
-static int genpd_power_off(struct generic_pm_domain *genpd)
+static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
{
ktime_t time_start;
s64 elapsed_ns;
@@ -217,6 +220,9 @@ static int genpd_power_off(struct generic_pm_domain *genpd)
if (!genpd->power_off)
return 0;
+ if (!timed)
+ return genpd->power_off(genpd);
+
time_start = ktime_get();
ret = genpd->power_off(genpd);
if (ret == -EBUSY)
@@ -305,7 +311,7 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
}
}
- ret = genpd_power_on(genpd);
+ ret = genpd_power_on(genpd, true);
if (ret)
goto err;
@@ -615,7 +621,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
* the pm_genpd_poweron() restore power for us (this shouldn't
* happen very often).
*/
- ret = genpd_power_off(genpd);
+ ret = genpd_power_off(genpd, true);
if (ret == -EBUSY) {
genpd_set_active(genpd);
goto out;
@@ -827,6 +833,7 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
/**
* pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
* @genpd: PM domain to power off, if possible.
+ * @timed: True if latency measurements are allowed.
*
* Check if the given PM domain can be powered off (during system suspend or
* hibernation) and do that if so. Also, in that case propagate to its masters.
@@ -836,7 +843,8 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
* executed sequentially, so it is guaranteed that it will never run twice in
* parallel).
*/
-static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
+static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd,
+ bool timed)
{
struct gpd_link *link;
@@ -847,26 +855,28 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
|| atomic_read(&genpd->sd_count) > 0)
return;
- genpd_power_off(genpd);
+ genpd_power_off(genpd, timed);
genpd->status = GPD_STATE_POWER_OFF;
list_for_each_entry(link, &genpd->slave_links, slave_node) {
genpd_sd_counter_dec(link->master);
- pm_genpd_sync_poweroff(link->master);
+ pm_genpd_sync_poweroff(link->master, timed);
}
}
/**
* pm_genpd_sync_poweron - Synchronously power on a PM domain and its masters.
* @genpd: PM domain to power on.
+ * @timed: True if latency measurements are allowed.
*
* This function is only called in "noirq" and "syscore" stages of system power
* transitions, so it need not acquire locks (all of the "noirq" callbacks are
* executed sequentially, so it is guaranteed that it will never run twice in
* parallel).
*/
-static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd)
+static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd,
+ bool timed)
{
struct gpd_link *link;
@@ -874,11 +884,11 @@ static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd)
return;
list_for_each_entry(link, &genpd->slave_links, slave_node) {
- pm_genpd_sync_poweron(link->master);
+ pm_genpd_sync_poweron(link->master, timed);
genpd_sd_counter_inc(link->master);
}
- genpd_power_on(genpd);
+ genpd_power_on(genpd, timed);
genpd->status = GPD_STATE_ACTIVE;
}
@@ -1056,7 +1066,7 @@ static int pm_genpd_suspend_noirq(struct device *dev)
* the same PM domain, so it is not necessary to use locking here.
*/
genpd->suspended_count++;
- pm_genpd_sync_poweroff(genpd);
+ pm_genpd_sync_poweroff(genpd, true);
return 0;
}
@@ -1086,7 +1096,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
* guaranteed that this function will never run twice in parallel for
* the same PM domain, so it is not necessary to use locking here.
*/
- pm_genpd_sync_poweron(genpd);
+ pm_genpd_sync_poweron(genpd, true);
genpd->suspended_count--;
return genpd_start_dev(genpd, dev);
@@ -1300,7 +1310,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
* If the domain was off before the hibernation, make
* sure it will be off going forward.
*/
- genpd_power_off(genpd);
+ genpd_power_off(genpd, true);
return 0;
}
@@ -1309,7 +1319,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
if (genpd->suspend_power_off)
return 0;
- pm_genpd_sync_poweron(genpd);
+ pm_genpd_sync_poweron(genpd, true);
return genpd_start_dev(genpd, dev);
}
@@ -1367,9 +1377,9 @@ static void genpd_syscore_switch(struct device *dev, bool suspend)
if (suspend) {
genpd->suspended_count++;
- pm_genpd_sync_poweroff(genpd);
+ pm_genpd_sync_poweroff(genpd, false);
} else {
- pm_genpd_sync_poweron(genpd);
+ pm_genpd_sync_poweron(genpd, false);
genpd->suspended_count--;
}
}
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 3d874eca7104..30b7bbfdc558 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -24,6 +24,7 @@
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/pm-trace.h>
+#include <linux/pm_wakeirq.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/async.h>
@@ -587,6 +588,7 @@ void dpm_resume_noirq(pm_message_t state)
async_synchronize_full();
dpm_show_time(starttime, state, "noirq");
resume_device_irqs();
+ device_wakeup_disarm_wake_irqs();
cpuidle_resume();
trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false);
}
@@ -920,9 +922,7 @@ static void device_complete(struct device *dev, pm_message_t state)
if (callback) {
pm_dev_dbg(dev, state, info);
- trace_device_pm_callback_start(dev, info, state.event);
callback(dev);
- trace_device_pm_callback_end(dev, 0);
}
device_unlock(dev);
@@ -954,7 +954,9 @@ void dpm_complete(pm_message_t state)
list_move(&dev->power.entry, &list);
mutex_unlock(&dpm_list_mtx);
+ trace_device_pm_callback_start(dev, "", state.event);
device_complete(dev, state);
+ trace_device_pm_callback_end(dev, 0);
mutex_lock(&dpm_list_mtx);
put_device(dev);
@@ -1104,6 +1106,7 @@ int dpm_suspend_noirq(pm_message_t state)
trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true);
cpuidle_pause();
+ device_wakeup_arm_wake_irqs();
suspend_device_irqs();
mutex_lock(&dpm_list_mtx);
pm_transition = state;
@@ -1585,11 +1588,8 @@ static int device_prepare(struct device *dev, pm_message_t state)
callback = dev->driver->pm->prepare;
}
- if (callback) {
- trace_device_pm_callback_start(dev, info, state.event);
+ if (callback)
ret = callback(dev);
- trace_device_pm_callback_end(dev, ret);
- }
device_unlock(dev);
@@ -1631,7 +1631,9 @@ int dpm_prepare(pm_message_t state)
get_device(dev);
mutex_unlock(&dpm_list_mtx);
+ trace_device_pm_callback_start(dev, "", state.event);
error = device_prepare(dev, state);
+ trace_device_pm_callback_end(dev, error);
mutex_lock(&dpm_list_mtx);
if (error) {
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index b6b8a273c5da..f1a5d95e7b20 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -20,6 +20,46 @@ static inline void pm_runtime_early_init(struct device *dev)
extern void pm_runtime_init(struct device *dev);
extern void pm_runtime_remove(struct device *dev);
+struct wake_irq {
+ struct device *dev;
+ int irq;
+ bool dedicated_irq:1;
+};
+
+extern void dev_pm_arm_wake_irq(struct wake_irq *wirq);
+extern void dev_pm_disarm_wake_irq(struct wake_irq *wirq);
+
+#ifdef CONFIG_PM_SLEEP
+
+extern int device_wakeup_attach_irq(struct device *dev,
+ struct wake_irq *wakeirq);
+extern void device_wakeup_detach_irq(struct device *dev);
+extern void device_wakeup_arm_wake_irqs(void);
+extern void device_wakeup_disarm_wake_irqs(void);
+
+#else
+
+static inline int
+device_wakeup_attach_irq(struct device *dev,
+ struct wake_irq *wakeirq)
+{
+ return 0;
+}
+
+static inline void device_wakeup_detach_irq(struct device *dev)
+{
+}
+
+static inline void device_wakeup_arm_wake_irqs(void)
+{
+}
+
+static inline void device_wakeup_disarm_wake_irqs(void)
+{
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
/*
* sysfs.c
*/
@@ -52,6 +92,14 @@ static inline void wakeup_sysfs_remove(struct device *dev) {}
static inline int pm_qos_sysfs_add(struct device *dev) { return 0; }
static inline void pm_qos_sysfs_remove(struct device *dev) {}
+static inline void dev_pm_arm_wake_irq(struct wake_irq *wirq)
+{
+}
+
+static inline void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
+{
+}
+
#endif
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 5070c4fe8542..e1a10a03df8e 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -10,6 +10,7 @@
#include <linux/sched.h>
#include <linux/export.h>
#include <linux/pm_runtime.h>
+#include <linux/pm_wakeirq.h>
#include <trace/events/rpm.h>
#include "power.h"
@@ -514,6 +515,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
callback = RPM_GET_CALLBACK(dev, runtime_suspend);
+ dev_pm_enable_wake_irq(dev);
retval = rpm_callback(callback, dev);
if (retval)
goto fail;
@@ -552,6 +554,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
return retval;
fail:
+ dev_pm_disable_wake_irq(dev);
__update_runtime_status(dev, RPM_ACTIVE);
dev->power.deferred_resume = false;
wake_up_all(&dev->power.wait_queue);
@@ -734,13 +737,16 @@ static int rpm_resume(struct device *dev, int rpmflags)
callback = RPM_GET_CALLBACK(dev, runtime_resume);
+ dev_pm_disable_wake_irq(dev);
retval = rpm_callback(callback, dev);
if (retval) {
__update_runtime_status(dev, RPM_SUSPENDED);
pm_runtime_cancel_pending(dev);
+ dev_pm_enable_wake_irq(dev);
} else {
no_callback:
__update_runtime_status(dev, RPM_ACTIVE);
+ pm_runtime_mark_last_busy(dev);
if (parent)
atomic_inc(&parent->power.child_count);
}
diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c
new file mode 100644
index 000000000000..7470004ca810
--- /dev/null
+++ b/drivers/base/power/wakeirq.c
@@ -0,0 +1,273 @@
+/*
+ * wakeirq.c - Device wakeirq helper functions
+ *
+ * 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/device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_wakeirq.h>
+
+#include "power.h"
+
+/**
+ * dev_pm_attach_wake_irq - Attach device interrupt as a wake IRQ
+ * @dev: Device entry
+ * @irq: Device wake-up capable interrupt
+ * @wirq: Wake irq specific data
+ *
+ * Internal function to attach either a device IO interrupt or a
+ * dedicated wake-up interrupt as a wake IRQ.
+ */
+static int dev_pm_attach_wake_irq(struct device *dev, int irq,
+ struct wake_irq *wirq)
+{
+ unsigned long flags;
+ int err;
+
+ if (!dev || !wirq)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+ if (dev_WARN_ONCE(dev, dev->power.wakeirq,
+ "wake irq already initialized\n")) {
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+ return -EEXIST;
+ }
+
+ dev->power.wakeirq = wirq;
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+
+ err = device_wakeup_attach_irq(dev, wirq);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/**
+ * dev_pm_set_wake_irq - Attach device IO interrupt as wake IRQ
+ * @dev: Device entry
+ * @irq: Device IO interrupt
+ *
+ * Attach a device IO interrupt as a wake IRQ. The wake IRQ gets
+ * automatically configured for wake-up from suspend based
+ * on the device specific sysfs wakeup entry. Typically called
+ * during driver probe after calling device_init_wakeup().
+ */
+int dev_pm_set_wake_irq(struct device *dev, int irq)
+{
+ struct wake_irq *wirq;
+ int err;
+
+ wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
+ if (!wirq)
+ return -ENOMEM;
+
+ wirq->dev = dev;
+ wirq->irq = irq;
+
+ err = dev_pm_attach_wake_irq(dev, irq, wirq);
+ if (err)
+ kfree(wirq);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq);
+
+/**
+ * dev_pm_clear_wake_irq - Detach a device IO interrupt wake IRQ
+ * @dev: Device entry
+ *
+ * Detach a device wake IRQ and free resources.
+ *
+ * Note that it's OK for drivers to call this without calling
+ * dev_pm_set_wake_irq() as all the driver instances may not have
+ * a wake IRQ configured. This avoid adding wake IRQ specific
+ * checks into the drivers.
+ */
+void dev_pm_clear_wake_irq(struct device *dev)
+{
+ struct wake_irq *wirq = dev->power.wakeirq;
+ unsigned long flags;
+
+ if (!wirq)
+ return;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+ dev->power.wakeirq = NULL;
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+
+ device_wakeup_detach_irq(dev);
+ if (wirq->dedicated_irq)
+ free_irq(wirq->irq, wirq);
+ kfree(wirq);
+}
+EXPORT_SYMBOL_GPL(dev_pm_clear_wake_irq);
+
+/**
+ * handle_threaded_wake_irq - Handler for dedicated wake-up interrupts
+ * @irq: Device specific dedicated wake-up interrupt
+ * @_wirq: Wake IRQ data
+ *
+ * Some devices have a separate wake-up interrupt in addition to the
+ * device IO interrupt. The wake-up interrupt signals that a device
+ * should be woken up from it's idle state. This handler uses device
+ * specific pm_runtime functions to wake the device, and then it's
+ * up to the device to do whatever it needs to. Note that as the
+ * device may need to restore context and start up regulators, we
+ * use a threaded IRQ.
+ *
+ * Also note that we are not resending the lost device interrupts.
+ * We assume that the wake-up interrupt just needs to wake-up the
+ * device, and then device's pm_runtime_resume() can deal with the
+ * situation.
+ */
+static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq)
+{
+ struct wake_irq *wirq = _wirq;
+ int res;
+
+ /* We don't want RPM_ASYNC or RPM_NOWAIT here */
+ res = pm_runtime_resume(wirq->dev);
+ if (res < 0)
+ dev_warn(wirq->dev,
+ "wake IRQ with no resume: %i\n", res);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt
+ * @dev: Device entry
+ * @irq: Device wake-up interrupt
+ *
+ * Unless your hardware has separate wake-up interrupts in addition
+ * to the device IO interrupts, you don't need this.
+ *
+ * Sets up a threaded interrupt handler for a device that has
+ * a dedicated wake-up interrupt in addition to the device IO
+ * interrupt.
+ *
+ * The interrupt starts disabled, and needs to be managed for
+ * the device by the bus code or the device driver using
+ * dev_pm_enable_wake_irq() and dev_pm_disable_wake_irq()
+ * functions.
+ */
+int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
+{
+ struct wake_irq *wirq;
+ int err;
+
+ wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
+ if (!wirq)
+ return -ENOMEM;
+
+ wirq->dev = dev;
+ wirq->irq = irq;
+ wirq->dedicated_irq = true;
+ irq_set_status_flags(irq, IRQ_NOAUTOEN);
+
+ /*
+ * Consumer device may need to power up and restore state
+ * so we use a threaded irq.
+ */
+ err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq,
+ IRQF_ONESHOT, dev_name(dev), wirq);
+ if (err)
+ goto err_free;
+
+ err = dev_pm_attach_wake_irq(dev, irq, wirq);
+ if (err)
+ goto err_free_irq;
+
+ return err;
+
+err_free_irq:
+ free_irq(irq, wirq);
+err_free:
+ kfree(wirq);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
+
+/**
+ * dev_pm_enable_wake_irq - Enable device wake-up interrupt
+ * @dev: Device
+ *
+ * Called from the bus code or the device driver for
+ * runtime_suspend() to enable the wake-up interrupt while
+ * the device is running.
+ *
+ * Note that for runtime_suspend()) the wake-up interrupts
+ * should be unconditionally enabled unlike for suspend()
+ * that is conditional.
+ */
+void dev_pm_enable_wake_irq(struct device *dev)
+{
+ struct wake_irq *wirq = dev->power.wakeirq;
+
+ if (wirq && wirq->dedicated_irq)
+ enable_irq(wirq->irq);
+}
+EXPORT_SYMBOL_GPL(dev_pm_enable_wake_irq);
+
+/**
+ * dev_pm_disable_wake_irq - Disable device wake-up interrupt
+ * @dev: Device
+ *
+ * Called from the bus code or the device driver for
+ * runtime_resume() to disable the wake-up interrupt while
+ * the device is running.
+ */
+void dev_pm_disable_wake_irq(struct device *dev)
+{
+ struct wake_irq *wirq = dev->power.wakeirq;
+
+ if (wirq && wirq->dedicated_irq)
+ disable_irq_nosync(wirq->irq);
+}
+EXPORT_SYMBOL_GPL(dev_pm_disable_wake_irq);
+
+/**
+ * dev_pm_arm_wake_irq - Arm device wake-up
+ * @wirq: Device wake-up interrupt
+ *
+ * Sets up the wake-up event conditionally based on the
+ * device_may_wake().
+ */
+void dev_pm_arm_wake_irq(struct wake_irq *wirq)
+{
+ if (!wirq)
+ return;
+
+ if (device_may_wakeup(wirq->dev))
+ enable_irq_wake(wirq->irq);
+}
+
+/**
+ * dev_pm_disarm_wake_irq - Disarm device wake-up
+ * @wirq: Device wake-up interrupt
+ *
+ * Clears up the wake-up event conditionally based on the
+ * device_may_wake().
+ */
+void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
+{
+ if (!wirq)
+ return;
+
+ if (device_may_wakeup(wirq->dev))
+ disable_irq_wake(wirq->irq);
+}
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 77262009f89d..40f71603378c 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -14,6 +14,7 @@
#include <linux/suspend.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
+#include <linux/pm_wakeirq.h>
#include <trace/events/power.h>
#include "power.h"
@@ -56,6 +57,11 @@ static LIST_HEAD(wakeup_sources);
static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);
+static struct wakeup_source deleted_ws = {
+ .name = "deleted",
+ .lock = __SPIN_LOCK_UNLOCKED(deleted_ws.lock),
+};
+
/**
* wakeup_source_prepare - Prepare a new wakeup source for initialization.
* @ws: Wakeup source to prepare.
@@ -107,6 +113,34 @@ void wakeup_source_drop(struct wakeup_source *ws)
}
EXPORT_SYMBOL_GPL(wakeup_source_drop);
+/*
+ * Record wakeup_source statistics being deleted into a dummy wakeup_source.
+ */
+static void wakeup_source_record(struct wakeup_source *ws)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&deleted_ws.lock, flags);
+
+ if (ws->event_count) {
+ deleted_ws.total_time =
+ ktime_add(deleted_ws.total_time, ws->total_time);
+ deleted_ws.prevent_sleep_time =
+ ktime_add(deleted_ws.prevent_sleep_time,
+ ws->prevent_sleep_time);
+ deleted_ws.max_time =
+ ktime_compare(deleted_ws.max_time, ws->max_time) > 0 ?
+ deleted_ws.max_time : ws->max_time;
+ deleted_ws.event_count += ws->event_count;
+ deleted_ws.active_count += ws->active_count;
+ deleted_ws.relax_count += ws->relax_count;
+ deleted_ws.expire_count += ws->expire_count;
+ deleted_ws.wakeup_count += ws->wakeup_count;
+ }
+
+ spin_unlock_irqrestore(&deleted_ws.lock, flags);
+}
+
/**
* wakeup_source_destroy - Destroy a struct wakeup_source object.
* @ws: Wakeup source to destroy.
@@ -119,6 +153,7 @@ void wakeup_source_destroy(struct wakeup_source *ws)
return;
wakeup_source_drop(ws);
+ wakeup_source_record(ws);
kfree(ws->name);
kfree(ws);
}
@@ -239,6 +274,97 @@ int device_wakeup_enable(struct device *dev)
EXPORT_SYMBOL_GPL(device_wakeup_enable);
/**
+ * device_wakeup_attach_irq - Attach a wakeirq to a wakeup source
+ * @dev: Device to handle
+ * @wakeirq: Device specific wakeirq entry
+ *
+ * Attach a device wakeirq to the wakeup source so the device
+ * wake IRQ can be configured automatically for suspend and
+ * resume.
+ */
+int device_wakeup_attach_irq(struct device *dev,
+ struct wake_irq *wakeirq)
+{
+ struct wakeup_source *ws;
+ int ret = 0;
+
+ spin_lock_irq(&dev->power.lock);
+ ws = dev->power.wakeup;
+ if (!ws) {
+ dev_err(dev, "forgot to call call device_init_wakeup?\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ if (ws->wakeirq) {
+ ret = -EEXIST;
+ goto unlock;
+ }
+
+ ws->wakeirq = wakeirq;
+
+unlock:
+ spin_unlock_irq(&dev->power.lock);
+
+ return ret;
+}
+
+/**
+ * device_wakeup_detach_irq - Detach a wakeirq from a wakeup source
+ * @dev: Device to handle
+ *
+ * Removes a device wakeirq from the wakeup source.
+ */
+void device_wakeup_detach_irq(struct device *dev)
+{
+ struct wakeup_source *ws;
+
+ spin_lock_irq(&dev->power.lock);
+ ws = dev->power.wakeup;
+ if (!ws)
+ goto unlock;
+
+ ws->wakeirq = NULL;
+
+unlock:
+ spin_unlock_irq(&dev->power.lock);
+}
+
+/**
+ * device_wakeup_arm_wake_irqs(void)
+ *
+ * Itereates over the list of device wakeirqs to arm them.
+ */
+void device_wakeup_arm_wake_irqs(void)
+{
+ struct wakeup_source *ws;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+ if (ws->wakeirq)
+ dev_pm_arm_wake_irq(ws->wakeirq);
+ }
+ rcu_read_unlock();
+}
+
+/**
+ * device_wakeup_disarm_wake_irqs(void)
+ *
+ * Itereates over the list of device wakeirqs to disarm them.
+ */
+void device_wakeup_disarm_wake_irqs(void)
+{
+ struct wakeup_source *ws;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+ if (ws->wakeirq)
+ dev_pm_disarm_wake_irq(ws->wakeirq);
+ }
+ rcu_read_unlock();
+}
+
+/**
* device_wakeup_detach - Detach a device's wakeup source object from it.
* @dev: Device to detach the wakeup source object from.
*
@@ -351,6 +477,20 @@ int device_set_wakeup_enable(struct device *dev, bool enable)
}
EXPORT_SYMBOL_GPL(device_set_wakeup_enable);
+/**
+ * wakeup_source_not_registered - validate the given wakeup source.
+ * @ws: Wakeup source to be validated.
+ */
+static bool wakeup_source_not_registered(struct wakeup_source *ws)
+{
+ /*
+ * Use timer struct to check if the given source is initialized
+ * by wakeup_source_add.
+ */
+ return ws->timer.function != pm_wakeup_timer_fn ||
+ ws->timer.data != (unsigned long)ws;
+}
+
/*
* The functions below use the observation that each wakeup event starts a
* period in which the system should not be suspended. The moment this period
@@ -391,6 +531,10 @@ static void wakeup_source_activate(struct wakeup_source *ws)
{
unsigned int cec;
+ if (WARN_ONCE(wakeup_source_not_registered(ws),
+ "unregistered wakeup source\n"))
+ return;
+
/*
* active wakeup source should bring the system
* out of PM_SUSPEND_FREEZE state
@@ -894,6 +1038,8 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
print_wakeup_source_stats(m, ws);
rcu_read_unlock();
+ print_wakeup_source_stats(m, &deleted_ws);
+
return 0;
}
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 1d0b116cae95..e645852396ba 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -14,6 +14,7 @@
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/property.h>
/**
@@ -519,3 +520,16 @@ unsigned int device_get_child_node_count(struct device *dev)
return count;
}
EXPORT_SYMBOL_GPL(device_get_child_node_count);
+
+bool device_dma_is_coherent(struct device *dev)
+{
+ bool coherent = false;
+
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ coherent = of_dma_is_coherent(dev->of_node);
+ else
+ acpi_check_dma(ACPI_COMPANION(dev), &coherent);
+
+ return coherent;
+}
+EXPORT_SYMBOL_GPL(device_dma_is_coherent);
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index a13587b5c2be..b2b2849fc6d3 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -131,7 +131,10 @@ struct regmap {
struct reg_default *reg_defaults;
const void *reg_defaults_raw;
void *cache;
+ /* if set, the cache contains newer data than the HW */
u32 cache_dirty;
+ /* if set, the HW registers are known to match map->reg_defaults */
+ bool no_sync_defaults;
struct reg_default *patch;
int patch_regs;
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 7eb7b3b98794..b9862d741a56 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -249,6 +249,22 @@ int regcache_write(struct regmap *map,
return 0;
}
+static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
+ unsigned int val)
+{
+ int ret;
+
+ /* If we don't know the chip just got reset, then sync everything. */
+ if (!map->no_sync_defaults)
+ return true;
+
+ /* Is this the hardware default? If so skip. */
+ ret = regcache_lookup_reg(map, reg);
+ if (ret >= 0 && val == map->reg_defaults[ret].def)
+ return false;
+ return true;
+}
+
static int regcache_default_sync(struct regmap *map, unsigned int min,
unsigned int max)
{
@@ -266,9 +282,7 @@ static int regcache_default_sync(struct regmap *map, unsigned int min,
if (ret)
return ret;
- /* Is this the hardware default? If so skip. */
- ret = regcache_lookup_reg(map, reg);
- if (ret >= 0 && val == map->reg_defaults[ret].def)
+ if (!regcache_reg_needs_sync(map, reg, val))
continue;
map->cache_bypass = 1;
@@ -342,6 +356,7 @@ out:
/* Restore the bypass state */
map->async = false;
map->cache_bypass = bypass;
+ map->no_sync_defaults = false;
map->unlock(map->lock_arg);
regmap_async_complete(map);
@@ -397,6 +412,7 @@ out:
/* Restore the bypass state */
map->cache_bypass = bypass;
map->async = false;
+ map->no_sync_defaults = false;
map->unlock(map->lock_arg);
regmap_async_complete(map);
@@ -461,18 +477,23 @@ void regcache_cache_only(struct regmap *map, bool enable)
EXPORT_SYMBOL_GPL(regcache_cache_only);
/**
- * regcache_mark_dirty: Mark the register cache as dirty
+ * regcache_mark_dirty: Indicate that HW registers were reset to default values
*
* @map: map to mark
*
- * Mark the register cache as dirty, for example due to the device
- * having been powered down for suspend. If the cache is not marked
- * as dirty then the cache sync will be suppressed.
+ * Inform regcache that the device has been powered down or reset, so that
+ * on resume, regcache_sync() knows to write out all non-default values
+ * stored in the cache.
+ *
+ * If this function is not called, regcache_sync() will assume that
+ * the hardware state still matches the cache state, modulo any writes that
+ * happened when cache_only was true.
*/
void regcache_mark_dirty(struct regmap *map)
{
map->lock(map->lock_arg);
map->cache_dirty = true;
+ map->no_sync_defaults = true;
map->unlock(map->lock_arg);
}
EXPORT_SYMBOL_GPL(regcache_mark_dirty);
@@ -613,10 +634,7 @@ static int regcache_sync_block_single(struct regmap *map, void *block,
continue;
val = regcache_get_val(map, block, i);
-
- /* Is this the hardware default? If so skip. */
- ret = regcache_lookup_reg(map, regtmp);
- if (ret >= 0 && val == map->reg_defaults[ret].def)
+ if (!regcache_reg_needs_sync(map, regtmp, val))
continue;
map->cache_bypass = 1;
@@ -688,10 +706,7 @@ static int regcache_sync_block_raw(struct regmap *map, void *block,
}
val = regcache_get_val(map, block, i);
-
- /* Is this the hardware default? If so skip. */
- ret = regcache_lookup_reg(map, regtmp);
- if (ret >= 0 && val == map->reg_defaults[ret].def) {
+ if (!regcache_reg_needs_sync(map, regtmp, val)) {
ret = regcache_sync_block_raw_flush(map, &data,
base, regtmp);
if (ret != 0)
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index a6c3f75b4b01..2597600a5d26 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -109,7 +109,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
if (!d->chip->init_ack_masked)
continue;
/*
- * Ack all the masked interrupts uncondictionly,
+ * Ack all the masked interrupts unconditionally,
* OR if there is masked interrupt which hasn't been Acked,
* it'll be ignored in irq handler, then may introduce irq storm
*/
@@ -306,19 +306,12 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
irq_set_chip_data(virq, data);
irq_set_chip(virq, &data->irq_chip);
irq_set_nested_thread(virq, 1);
-
- /* ARM needs us to explicitly flag the IRQ as valid
- * and will set them noprobe when we do so. */
-#ifdef CONFIG_ARM
- set_irq_flags(virq, IRQF_VALID);
-#else
irq_set_noprobe(virq);
-#endif
return 0;
}
-static struct irq_domain_ops regmap_domain_ops = {
+static const struct irq_domain_ops regmap_domain_ops = {
.map = regmap_irq_map,
.xlate = irq_domain_xlate_twocell,
};
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 6273ff072f3e..7111d04f2621 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -945,11 +945,10 @@ EXPORT_SYMBOL_GPL(devm_regmap_init);
static void regmap_field_init(struct regmap_field *rm_field,
struct regmap *regmap, struct reg_field reg_field)
{
- int field_bits = reg_field.msb - reg_field.lsb + 1;
rm_field->regmap = regmap;
rm_field->reg = reg_field.reg;
rm_field->shift = reg_field.lsb;
- rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb);
+ rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb);
rm_field->id_size = reg_field.id_size;
rm_field->id_offset = reg_field.id_offset;
}
@@ -2318,7 +2317,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
&ival);
if (ret != 0)
return ret;
- memcpy(val + (i * val_bytes), &ival, val_bytes);
+ map->format.format_val(val + (i * val_bytes), ival, 0);
}
}
@@ -2583,10 +2582,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
map->async = true;
ret = _regmap_multi_reg_write(map, regs, num_regs);
- if (ret != 0)
- goto out;
-out:
map->async = false;
map->cache_bypass = bypass;
@@ -2613,6 +2609,30 @@ int regmap_get_val_bytes(struct regmap *map)
}
EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
+/**
+ * regmap_get_max_register(): Report the max register value
+ *
+ * Report the max register value, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_max_register(struct regmap *map)
+{
+ return map->max_register ? map->max_register : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regmap_get_max_register);
+
+/**
+ * regmap_get_reg_stride(): Report the register address stride
+ *
+ * Report the register address stride, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_reg_stride(struct regmap *map)
+{
+ return map->reg_stride;
+}
+EXPORT_SYMBOL_GPL(regmap_get_reg_stride);
+
int regmap_parse_val(struct regmap *map, const void *buf,
unsigned int *val)
{
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 6491f45200a7..8b7d7f8e5851 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -61,7 +61,7 @@ static DEVICE_ATTR_RO(physical_package_id);
define_id_show_func(core_id);
static DEVICE_ATTR_RO(core_id);
-define_siblings_show_func(thread_siblings, thread_cpumask);
+define_siblings_show_func(thread_siblings, sibling_cpumask);
static DEVICE_ATTR_RO(thread_siblings);
static DEVICE_ATTR_RO(thread_siblings_list);
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index fc6ffcfa8061..be5fffb6da24 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -29,12 +29,6 @@ config BCMA_HOST_PCI
select BCMA_DRIVER_PCI
default y
-config BCMA_DRIVER_PCI_HOSTMODE
- bool "Driver for PCI core working in hostmode"
- depends on BCMA && MIPS && BCMA_HOST_PCI
- help
- PCI core hostmode operation (external PCI bus).
-
config BCMA_HOST_SOC
bool "Support for BCMA in a SoC"
depends on BCMA
@@ -61,6 +55,12 @@ config BCMA_DRIVER_PCI
This driver is also prerequisite for a hostmode PCIe core
support.
+config BCMA_DRIVER_PCI_HOSTMODE
+ bool "Driver for PCI core working in hostmode"
+ depends on BCMA && MIPS && BCMA_DRIVER_PCI
+ help
+ PCI core hostmode operation (external PCI bus).
+
config BCMA_DRIVER_MIPS
bool "BCMA Broadcom MIPS core driver"
depends on BCMA && MIPS
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c
index 74ccb02e0f10..5f6018e7cd4c 100644
--- a/drivers/bcma/driver_gpio.c
+++ b/drivers/bcma/driver_gpio.c
@@ -226,6 +226,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
chip->of_node = cc->core->dev.of_node;
#endif
switch (bus->chipinfo.id) {
+ case BCMA_CHIP_ID_BCM4707:
case BCMA_CHIP_ID_BCM5357:
case BCMA_CHIP_ID_BCM53572:
chip->ngpio = 32;
@@ -235,16 +236,17 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
}
/*
- * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO
- * pin numbers. We don't have Device Tree there and we can't really use
- * relative (per chip) numbers.
- * So let's use predictable base for BCM47XX and "random" for all other.
+ * Register SoC GPIO devices with absolute GPIO pin base.
+ * On MIPS, we don't have Device Tree and we can't use relative (per chip)
+ * GPIO numbers.
+ * On some ARM devices, user space may want to access some system GPIO
+ * pins directly, which is easier to do with a predictable GPIO base.
*/
-#if IS_BUILTIN(CONFIG_BCM47XX)
- chip->base = bus->num * BCMA_GPIO_MAX_PINS;
-#else
- chip->base = -1;
-#endif
+ if (IS_BUILTIN(CONFIG_BCM47XX) ||
+ cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
+ chip->base = bus->num * BCMA_GPIO_MAX_PINS;
+ else
+ chip->base = -1;
err = bcma_gpio_irq_domain_init(cc);
if (err)
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index ff20f192b0f6..0422c47261c3 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -139,8 +139,6 @@ static struct board_type products[] = {
{0x3214103C, "Smart Array E200i", &SA5_access},
{0x3215103C, "Smart Array E200i", &SA5_access},
{0x3237103C, "Smart Array E500", &SA5_access},
- {0x3223103C, "Smart Array P800", &SA5_access},
- {0x3234103C, "Smart Array P400", &SA5_access},
{0x323D103C, "Smart Array P700m", &SA5_access},
};
@@ -574,8 +572,6 @@ static void cciss_procinit(ctlr_info_t *h)
/* List of controllers which cannot be hard reset on kexec with reset_devices */
static u32 unresettable_controller[] = {
- 0x324a103C, /* Smart Array P712m */
- 0x324b103C, /* SmartArray P711m */
0x3223103C, /* Smart Array P800 */
0x3234103C, /* Smart Array P400 */
0x3235103C, /* Smart Array P400i */
@@ -586,12 +582,32 @@ static u32 unresettable_controller[] = {
0x3215103C, /* Smart Array E200i */
0x3237103C, /* Smart Array E500 */
0x323D103C, /* Smart Array P700m */
+ 0x40800E11, /* Smart Array 5i */
0x409C0E11, /* Smart Array 6400 */
0x409D0E11, /* Smart Array 6400 EM */
+ 0x40700E11, /* Smart Array 5300 */
+ 0x40820E11, /* Smart Array 532 */
+ 0x40830E11, /* Smart Array 5312 */
+ 0x409A0E11, /* Smart Array 641 */
+ 0x409B0E11, /* Smart Array 642 */
+ 0x40910E11, /* Smart Array 6i */
};
/* List of controllers which cannot even be soft reset */
static u32 soft_unresettable_controller[] = {
+ 0x40800E11, /* Smart Array 5i */
+ 0x40700E11, /* Smart Array 5300 */
+ 0x40820E11, /* Smart Array 532 */
+ 0x40830E11, /* Smart Array 5312 */
+ 0x409A0E11, /* Smart Array 641 */
+ 0x409B0E11, /* Smart Array 642 */
+ 0x40910E11, /* Smart Array 6i */
+ /* Exclude 640x boards. These are two pci devices in one slot
+ * which share a battery backed cache module. One controls the
+ * cache, the other accesses the cache through the one that controls
+ * it. If we reset the one controlling the cache, the other will
+ * likely not be happy. Just forbid resetting this conjoined mess.
+ */
0x409C0E11, /* Smart Array 6400 */
0x409D0E11, /* Smart Array 6400 EM */
};
@@ -4667,8 +4683,7 @@ static int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
*/
cciss_lookup_board_id(pdev, &board_id);
if (!ctlr_is_resettable(board_id)) {
- dev_warn(&pdev->dev, "Cannot reset Smart Array 640x "
- "due to shared cache module.");
+ dev_warn(&pdev->dev, "Controller not resettable\n");
return -ENODEV;
}
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index ecd845cd28d8..1537302e56e3 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -84,7 +84,6 @@ static struct scsi_host_template cciss_driver_template = {
.show_info = cciss_scsi_show_info,
.queuecommand = cciss_scsi_queue_command,
.this_id = 7,
- .cmd_per_lun = 1,
.use_clustering = DISABLE_CLUSTERING,
/* Can't have eh_bus_reset_handler or eh_host_reset_handler for cciss */
.eh_device_reset_handler= cciss_eh_device_reset_handler,
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index b905e9888b88..efd19c2da9c2 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -38,6 +38,7 @@
#include <linux/mutex.h>
#include <linux/major.h>
#include <linux/blkdev.h>
+#include <linux/backing-dev.h>
#include <linux/genhd.h>
#include <linux/idr.h>
#include <net/tcp.h>
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 81fde9ef7f8e..a1518539b858 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -2359,7 +2359,7 @@ static void drbd_cleanup(void)
* @congested_data: User data
* @bdi_bits: Bits the BDI flusher thread is currently interested in
*
- * Returns 1<<BDI_async_congested and/or 1<<BDI_sync_congested if we are congested.
+ * Returns 1<<WB_async_congested and/or 1<<WB_sync_congested if we are congested.
*/
static int drbd_congested(void *congested_data, int bdi_bits)
{
@@ -2376,14 +2376,14 @@ static int drbd_congested(void *congested_data, int bdi_bits)
}
if (test_bit(CALLBACK_PENDING, &first_peer_device(device)->connection->flags)) {
- r |= (1 << BDI_async_congested);
+ r |= (1 << WB_async_congested);
/* Without good local data, we would need to read from remote,
* and that would need the worker thread as well, which is
* currently blocked waiting for that usermode helper to
* finish.
*/
if (!get_ldev_if_state(device, D_UP_TO_DATE))
- r |= (1 << BDI_sync_congested);
+ r |= (1 << WB_sync_congested);
else
put_ldev(device);
r &= bdi_bits;
@@ -2399,9 +2399,9 @@ static int drbd_congested(void *congested_data, int bdi_bits)
reason = 'b';
}
- if (bdi_bits & (1 << BDI_async_congested) &&
+ if (bdi_bits & (1 << WB_async_congested) &&
test_bit(NET_CONGESTED, &first_peer_device(device)->connection->flags)) {
- r |= (1 << BDI_async_congested);
+ r |= (1 << WB_async_congested);
reason = reason == 'b' ? 'a' : 'n';
}
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index cee20354ac37..c097909c589c 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -598,7 +598,7 @@ static struct socket *drbd_try_connect(struct drbd_connection *connection)
memcpy(&peer_in6, &connection->peer_addr, peer_addr_len);
what = "sock_create_kern";
- err = sock_create_kern(((struct sockaddr *)&src_in6)->sa_family,
+ err = sock_create_kern(&init_net, ((struct sockaddr *)&src_in6)->sa_family,
SOCK_STREAM, IPPROTO_TCP, &sock);
if (err < 0) {
sock = NULL;
@@ -693,7 +693,7 @@ static int prepare_listen_socket(struct drbd_connection *connection, struct acce
memcpy(&my_addr, &connection->my_addr, my_addr_len);
what = "sock_create_kern";
- err = sock_create_kern(((struct sockaddr *)&my_addr)->sa_family,
+ err = sock_create_kern(&init_net, ((struct sockaddr *)&my_addr)->sa_family,
SOCK_STREAM, IPPROTO_TCP, &s_listen);
if (err) {
s_listen = NULL;
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index d7173cb1ea76..40580dc7f41c 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -86,8 +86,6 @@ static DEFINE_MUTEX(loop_index_mutex);
static int max_part;
static int part_shift;
-static struct workqueue_struct *loop_wq;
-
static int transfer_xor(struct loop_device *lo, int cmd,
struct page *raw_page, unsigned raw_off,
struct page *loop_page, unsigned loop_off,
@@ -476,6 +474,28 @@ static int loop_flush(struct loop_device *lo)
return loop_switch(lo, NULL);
}
+static void loop_reread_partitions(struct loop_device *lo,
+ struct block_device *bdev)
+{
+ int rc;
+
+ /*
+ * bd_mutex has been held already in release path, so don't
+ * acquire it if this function is called in such case.
+ *
+ * If the reread partition isn't from release path, lo_refcnt
+ * must be at least one and it can only become zero when the
+ * current holder is released.
+ */
+ if (!atomic_read(&lo->lo_refcnt))
+ rc = __blkdev_reread_part(bdev);
+ else
+ rc = blkdev_reread_part(bdev);
+ if (rc)
+ pr_warn("%s: partition scan of loop%d (%s) failed (rc=%d)\n",
+ __func__, lo->lo_number, lo->lo_file_name, rc);
+}
+
/*
* loop_change_fd switched the backing store of a loopback device to
* a new file. This is useful for operating system installers to free up
@@ -524,7 +544,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
fput(old_file);
if (lo->lo_flags & LO_FLAGS_PARTSCAN)
- ioctl_by_bdev(bdev, BLKRRPART, 0);
+ loop_reread_partitions(lo, bdev);
return 0;
out_putf:
@@ -725,6 +745,12 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
size = get_loop_size(lo, file);
if ((loff_t)(sector_t)size != size)
goto out_putf;
+ error = -ENOMEM;
+ lo->wq = alloc_workqueue("kloopd%d",
+ WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 16,
+ lo->lo_number);
+ if (!lo->wq)
+ goto out_putf;
error = 0;
@@ -755,7 +781,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
if (part_shift)
lo->lo_flags |= LO_FLAGS_PARTSCAN;
if (lo->lo_flags & LO_FLAGS_PARTSCAN)
- ioctl_by_bdev(bdev, BLKRRPART, 0);
+ loop_reread_partitions(lo, bdev);
/* Grab the block_device to prevent its destruction after we
* put /dev/loopXX inode. Later in loop_clr_fd() we bdput(bdev).
@@ -827,7 +853,7 @@ static int loop_clr_fd(struct loop_device *lo)
* <dev>/do something like mkfs/losetup -d <dev> causing the losetup -d
* command to fail with EBUSY.
*/
- if (lo->lo_refcnt > 1) {
+ if (atomic_read(&lo->lo_refcnt) > 1) {
lo->lo_flags |= LO_FLAGS_AUTOCLEAR;
mutex_unlock(&lo->lo_ctl_mutex);
return 0;
@@ -836,6 +862,9 @@ static int loop_clr_fd(struct loop_device *lo)
if (filp == NULL)
return -EINVAL;
+ /* freeze request queue during the transition */
+ blk_mq_freeze_queue(lo->lo_queue);
+
spin_lock_irq(&lo->lo_lock);
lo->lo_state = Lo_rundown;
lo->lo_backing_file = NULL;
@@ -867,11 +896,15 @@ static int loop_clr_fd(struct loop_device *lo)
lo->lo_state = Lo_unbound;
/* This is safe: open() is still holding a reference. */
module_put(THIS_MODULE);
+ blk_mq_unfreeze_queue(lo->lo_queue);
+
if (lo->lo_flags & LO_FLAGS_PARTSCAN && bdev)
- ioctl_by_bdev(bdev, BLKRRPART, 0);
+ loop_reread_partitions(lo, bdev);
lo->lo_flags = 0;
if (!part_shift)
lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN;
+ destroy_workqueue(lo->wq);
+ lo->wq = NULL;
mutex_unlock(&lo->lo_ctl_mutex);
/*
* Need not hold lo_ctl_mutex to fput backing file.
@@ -943,7 +976,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
!(lo->lo_flags & LO_FLAGS_PARTSCAN)) {
lo->lo_flags |= LO_FLAGS_PARTSCAN;
lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN;
- ioctl_by_bdev(lo->lo_device, BLKRRPART, 0);
+ loop_reread_partitions(lo, lo->lo_device);
}
lo->lo_encrypt_key_size = info->lo_encrypt_key_size;
@@ -1324,9 +1357,7 @@ static int lo_open(struct block_device *bdev, fmode_t mode)
goto out;
}
- mutex_lock(&lo->lo_ctl_mutex);
- lo->lo_refcnt++;
- mutex_unlock(&lo->lo_ctl_mutex);
+ atomic_inc(&lo->lo_refcnt);
out:
mutex_unlock(&loop_index_mutex);
return err;
@@ -1337,11 +1368,10 @@ static void lo_release(struct gendisk *disk, fmode_t mode)
struct loop_device *lo = disk->private_data;
int err;
- mutex_lock(&lo->lo_ctl_mutex);
-
- if (--lo->lo_refcnt)
- goto out;
+ if (atomic_dec_return(&lo->lo_refcnt))
+ return;
+ mutex_lock(&lo->lo_ctl_mutex);
if (lo->lo_flags & LO_FLAGS_AUTOCLEAR) {
/*
* In autoclear mode, stop the loop thread
@@ -1358,7 +1388,6 @@ static void lo_release(struct gendisk *disk, fmode_t mode)
loop_flush(lo);
}
-out:
mutex_unlock(&lo->lo_ctl_mutex);
}
@@ -1425,9 +1454,13 @@ static int loop_queue_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
{
struct loop_cmd *cmd = blk_mq_rq_to_pdu(bd->rq);
+ struct loop_device *lo = cmd->rq->q->queuedata;
blk_mq_start_request(bd->rq);
+ if (lo->lo_state != Lo_bound)
+ return -EIO;
+
if (cmd->rq->cmd_flags & REQ_WRITE) {
struct loop_device *lo = cmd->rq->q->queuedata;
bool need_sched = true;
@@ -1441,9 +1474,9 @@ static int loop_queue_rq(struct blk_mq_hw_ctx *hctx,
spin_unlock_irq(&lo->lo_lock);
if (need_sched)
- queue_work(loop_wq, &lo->write_work);
+ queue_work(lo->wq, &lo->write_work);
} else {
- queue_work(loop_wq, &cmd->read_work);
+ queue_work(lo->wq, &cmd->read_work);
}
return BLK_MQ_RQ_QUEUE_OK;
@@ -1455,9 +1488,6 @@ static void loop_handle_cmd(struct loop_cmd *cmd)
struct loop_device *lo = cmd->rq->q->queuedata;
int ret = -EIO;
- if (lo->lo_state != Lo_bound)
- goto failed;
-
if (write && (lo->lo_flags & LO_FLAGS_READ_ONLY))
goto failed;
@@ -1594,6 +1624,7 @@ static int loop_add(struct loop_device **l, int i)
disk->flags |= GENHD_FL_NO_PART_SCAN;
disk->flags |= GENHD_FL_EXT_DEVT;
mutex_init(&lo->lo_ctl_mutex);
+ atomic_set(&lo->lo_refcnt, 0);
lo->lo_number = i;
spin_lock_init(&lo->lo_lock);
disk->major = LOOP_MAJOR;
@@ -1711,7 +1742,7 @@ static long loop_control_ioctl(struct file *file, unsigned int cmd,
mutex_unlock(&lo->lo_ctl_mutex);
break;
}
- if (lo->lo_refcnt > 0) {
+ if (atomic_read(&lo->lo_refcnt) > 0) {
ret = -EBUSY;
mutex_unlock(&lo->lo_ctl_mutex);
break;
@@ -1806,13 +1837,6 @@ static int __init loop_init(void)
goto misc_out;
}
- loop_wq = alloc_workqueue("kloopd",
- WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0);
- if (!loop_wq) {
- err = -ENOMEM;
- goto misc_out;
- }
-
blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
THIS_MODULE, loop_probe, NULL, NULL);
@@ -1850,8 +1874,6 @@ static void __exit loop_exit(void)
blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range);
unregister_blkdev(LOOP_MAJOR, "loop");
- destroy_workqueue(loop_wq);
-
misc_deregister(&loop_misc);
}
diff --git a/drivers/block/loop.h b/drivers/block/loop.h
index 301c27f8323f..25e8997ed246 100644
--- a/drivers/block/loop.h
+++ b/drivers/block/loop.h
@@ -28,7 +28,7 @@ struct loop_func_table;
struct loop_device {
int lo_number;
- int lo_refcnt;
+ atomic_t lo_refcnt;
loff_t lo_offset;
loff_t lo_sizelimit;
int lo_flags;
@@ -54,6 +54,7 @@ struct loop_device {
gfp_t old_gfp_mask;
spinlock_t lo_lock;
+ struct workqueue_struct *wq;
struct list_head write_cmd_head;
struct work_struct write_work;
bool write_started;
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 3bd7ca9853a8..4a2ef09e6704 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -163,12 +163,6 @@ static bool mtip_check_surprise_removal(struct pci_dev *pdev)
else
dev_warn(&dd->pdev->dev,
"%s: dd->queue is NULL\n", __func__);
- if (dd->port) {
- set_bit(MTIP_PF_SR_CLEANUP_BIT, &dd->port->flags);
- wake_up_interruptible(&dd->port->svc_wait);
- } else
- dev_warn(&dd->pdev->dev,
- "%s: dd->port is NULL\n", __func__);
return true; /* device removed */
}
@@ -269,8 +263,11 @@ static int mtip_hba_reset(struct driver_data *dd)
/* Flush */
readl(dd->mmio + HOST_CTL);
- /* Spin for up to 2 seconds, waiting for reset acknowledgement */
- timeout = jiffies + msecs_to_jiffies(2000);
+ /*
+ * Spin for up to 10 seconds waiting for reset acknowledgement. Spec
+ * is 1 sec but in LUN failure conditions, up to 10 secs are required
+ */
+ timeout = jiffies + msecs_to_jiffies(10000);
do {
mdelay(10);
if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))
@@ -623,8 +620,7 @@ static void mtip_handle_tfe(struct driver_data *dd)
set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags);
- if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) &&
- test_bit(MTIP_TAG_INTERNAL, port->allocated)) {
+ if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) {
cmd = mtip_cmd_from_tag(dd, MTIP_TAG_INTERNAL);
dbg_printk(MTIP_DRV_NAME " TFE for the internal command\n");
@@ -896,6 +892,10 @@ static inline irqreturn_t mtip_handle_irq(struct driver_data *data)
/* Acknowledge the interrupt status on the port.*/
port_stat = readl(port->mmio + PORT_IRQ_STAT);
+ if (unlikely(port_stat == 0xFFFFFFFF)) {
+ mtip_check_surprise_removal(dd->pdev);
+ return IRQ_HANDLED;
+ }
writel(port_stat, port->mmio + PORT_IRQ_STAT);
/* Demux port status */
@@ -991,15 +991,10 @@ static bool mtip_pause_ncq(struct mtip_port *port,
reply = port->rxfis + RX_FIS_D2H_REG;
task_file_data = readl(port->mmio+PORT_TFDATA);
- if (fis->command == ATA_CMD_SEC_ERASE_UNIT)
- clear_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag);
-
if ((task_file_data & 1))
return false;
if (fis->command == ATA_CMD_SEC_ERASE_PREP) {
- set_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
- set_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag);
port->ic_pause_timer = jiffies;
return true;
} else if ((fis->command == ATA_CMD_DOWNLOAD_MICRO) &&
@@ -1011,8 +1006,10 @@ static bool mtip_pause_ncq(struct mtip_port *port,
((fis->command == 0xFC) &&
(fis->features == 0x27 || fis->features == 0x72 ||
fis->features == 0x62 || fis->features == 0x26))) {
+ clear_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag);
/* Com reset after secure erase or lowlevel format */
mtip_restart_port(port);
+ clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
return false;
}
@@ -1112,9 +1109,10 @@ static int mtip_exec_internal_command(struct mtip_port *port,
int_cmd = mtip_get_int_command(dd);
set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
- port->ic_pause_timer = 0;
- clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
+ if (fis->command == ATA_CMD_SEC_ERASE_PREP)
+ set_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
+
clear_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags);
if (atomic == GFP_KERNEL) {
@@ -1251,11 +1249,11 @@ static int mtip_exec_internal_command(struct mtip_port *port,
exec_ic_exit:
/* Clear the allocated and active bits for the internal command. */
mtip_put_int_command(dd, int_cmd);
+ clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
if (rv >= 0 && mtip_pause_ncq(port, fis)) {
/* NCQ paused */
return rv;
}
- clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
wake_up_interruptible(&port->svc_wait);
return rv;
@@ -2625,18 +2623,6 @@ static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
readl(dd->mmio + HOST_IRQ_STAT));
size += sprintf(&buf[size], "\n");
- size += sprintf(&buf[size], "L/ Allocated : [ 0x");
-
- for (n = dd->slot_groups-1; n >= 0; n--) {
- if (sizeof(long) > sizeof(u32))
- group_allocated =
- dd->port->allocated[n/2] >> (32*(n&1));
- else
- group_allocated = dd->port->allocated[n];
- size += sprintf(&buf[size], "%08X ", group_allocated);
- }
- size += sprintf(&buf[size], "]\n");
-
size += sprintf(&buf[size], "L/ Commands in Q : [ 0x");
for (n = dd->slot_groups-1; n >= 0; n--) {
@@ -2780,48 +2766,6 @@ static void mtip_hw_debugfs_exit(struct driver_data *dd)
debugfs_remove_recursive(dd->dfs_node);
}
-static int mtip_free_orphan(struct driver_data *dd)
-{
- struct kobject *kobj;
-
- if (dd->bdev) {
- if (dd->bdev->bd_holders >= 1)
- return -2;
-
- bdput(dd->bdev);
- dd->bdev = NULL;
- }
-
- mtip_hw_debugfs_exit(dd);
-
- spin_lock(&rssd_index_lock);
- ida_remove(&rssd_index_ida, dd->index);
- spin_unlock(&rssd_index_lock);
-
- if (!test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag) &&
- test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)) {
- put_disk(dd->disk);
- } else {
- if (dd->disk) {
- kobj = kobject_get(&disk_to_dev(dd->disk)->kobj);
- if (kobj) {
- mtip_hw_sysfs_exit(dd, kobj);
- kobject_put(kobj);
- }
- del_gendisk(dd->disk);
- dd->disk = NULL;
- }
- if (dd->queue) {
- dd->queue->queuedata = NULL;
- blk_cleanup_queue(dd->queue);
- blk_mq_free_tag_set(&dd->tags);
- dd->queue = NULL;
- }
- }
- kfree(dd);
- return 0;
-}
-
/*
* Perform any init/resume time hardware setup
*
@@ -2944,7 +2888,6 @@ static int mtip_ftl_rebuild_poll(struct driver_data *dd)
mtip_block_initialize(dd);
return 0;
}
- ssleep(10);
} while (time_before(jiffies, timeout));
/* Check for timeout */
@@ -2969,7 +2912,6 @@ static int mtip_service_thread(void *data)
unsigned long slot, slot_start, slot_wrap;
unsigned int num_cmd_slots = dd->slot_groups * 32;
struct mtip_port *port = dd->port;
- int ret;
while (1) {
if (kthread_should_stop() ||
@@ -2990,10 +2932,6 @@ static int mtip_service_thread(void *data)
test_bit(MTIP_PF_SVC_THD_STOP_BIT, &port->flags))
goto st_out;
- /* If I am an orphan, start self cleanup */
- if (test_bit(MTIP_PF_SR_CLEANUP_BIT, &port->flags))
- break;
-
if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT,
&dd->dd_flag)))
goto st_out;
@@ -3047,26 +2985,6 @@ restart_eh:
}
}
- /* wait for pci remove to exit */
- while (1) {
- if (test_bit(MTIP_DDF_REMOVE_DONE_BIT, &dd->dd_flag))
- break;
- msleep_interruptible(1000);
- if (kthread_should_stop())
- goto st_out;
- }
-
- while (1) {
- ret = mtip_free_orphan(dd);
- if (!ret) {
- /* NOTE: All data structures are invalid, do not
- * access any here */
- return 0;
- }
- msleep_interruptible(1000);
- if (kthread_should_stop())
- goto st_out;
- }
st_out:
return 0;
}
@@ -3394,6 +3312,7 @@ static int mtip_hw_exit(struct driver_data *dd)
/* Release the IRQ. */
irq_set_affinity_hint(dd->pdev->irq, NULL);
devm_free_irq(&dd->pdev->dev, dd->pdev->irq, dd);
+ msleep(1000);
/* Free dma regions */
mtip_dma_free(dd);
@@ -3699,6 +3618,26 @@ static const struct block_device_operations mtip_block_ops = {
.owner = THIS_MODULE
};
+static inline bool is_se_active(struct driver_data *dd)
+{
+ if (unlikely(test_bit(MTIP_PF_SE_ACTIVE_BIT, &dd->port->flags))) {
+ if (dd->port->ic_pause_timer) {
+ unsigned long to = dd->port->ic_pause_timer +
+ msecs_to_jiffies(1000);
+ if (time_after(jiffies, to)) {
+ clear_bit(MTIP_PF_SE_ACTIVE_BIT,
+ &dd->port->flags);
+ clear_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag);
+ dd->port->ic_pause_timer = 0;
+ wake_up_interruptible(&dd->port->svc_wait);
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
/*
* Block layer make request function.
*
@@ -3716,6 +3655,9 @@ static int mtip_submit_request(struct blk_mq_hw_ctx *hctx, struct request *rq)
struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq);
unsigned int nents;
+ if (is_se_active(dd))
+ return -ENODATA;
+
if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) {
if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT,
&dd->dd_flag))) {
@@ -3900,7 +3842,8 @@ static int mtip_block_initialize(struct driver_data *dd)
dd->disk->driverfs_dev = &dd->pdev->dev;
dd->disk->major = dd->major;
- dd->disk->first_minor = dd->instance * MTIP_MAX_MINORS;
+ dd->disk->first_minor = index * MTIP_MAX_MINORS;
+ dd->disk->minors = MTIP_MAX_MINORS;
dd->disk->fops = &mtip_block_ops;
dd->disk->private_data = dd;
dd->index = index;
@@ -4066,52 +4009,51 @@ static int mtip_block_remove(struct driver_data *dd)
{
struct kobject *kobj;
- if (!dd->sr) {
- mtip_hw_debugfs_exit(dd);
+ mtip_hw_debugfs_exit(dd);
- if (dd->mtip_svc_handler) {
- set_bit(MTIP_PF_SVC_THD_STOP_BIT, &dd->port->flags);
- wake_up_interruptible(&dd->port->svc_wait);
- kthread_stop(dd->mtip_svc_handler);
- }
+ if (dd->mtip_svc_handler) {
+ set_bit(MTIP_PF_SVC_THD_STOP_BIT, &dd->port->flags);
+ wake_up_interruptible(&dd->port->svc_wait);
+ kthread_stop(dd->mtip_svc_handler);
+ }
- /* Clean up the sysfs attributes, if created */
- if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) {
- kobj = kobject_get(&disk_to_dev(dd->disk)->kobj);
- if (kobj) {
- mtip_hw_sysfs_exit(dd, kobj);
- kobject_put(kobj);
- }
+ /* Clean up the sysfs attributes, if created */
+ if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) {
+ kobj = kobject_get(&disk_to_dev(dd->disk)->kobj);
+ if (kobj) {
+ mtip_hw_sysfs_exit(dd, kobj);
+ kobject_put(kobj);
}
+ }
+ if (!dd->sr)
mtip_standby_drive(dd);
-
- /*
- * Delete our gendisk structure. This also removes the device
- * from /dev
- */
- if (dd->bdev) {
- bdput(dd->bdev);
- dd->bdev = NULL;
- }
- if (dd->disk) {
- if (dd->disk->queue) {
- del_gendisk(dd->disk);
- blk_cleanup_queue(dd->queue);
- blk_mq_free_tag_set(&dd->tags);
- dd->queue = NULL;
- } else
- put_disk(dd->disk);
- }
- dd->disk = NULL;
-
- spin_lock(&rssd_index_lock);
- ida_remove(&rssd_index_ida, dd->index);
- spin_unlock(&rssd_index_lock);
- } else {
+ else
dev_info(&dd->pdev->dev, "device %s surprise removal\n",
dd->disk->disk_name);
+
+ /*
+ * Delete our gendisk structure. This also removes the device
+ * from /dev
+ */
+ if (dd->bdev) {
+ bdput(dd->bdev);
+ dd->bdev = NULL;
}
+ if (dd->disk) {
+ del_gendisk(dd->disk);
+ if (dd->disk->queue) {
+ blk_cleanup_queue(dd->queue);
+ blk_mq_free_tag_set(&dd->tags);
+ dd->queue = NULL;
+ }
+ put_disk(dd->disk);
+ }
+ dd->disk = NULL;
+
+ spin_lock(&rssd_index_lock);
+ ida_remove(&rssd_index_ida, dd->index);
+ spin_unlock(&rssd_index_lock);
/* De-initialize the protocol layer. */
mtip_hw_exit(dd);
@@ -4140,12 +4082,12 @@ static int mtip_block_shutdown(struct driver_data *dd)
dev_info(&dd->pdev->dev,
"Shutting down %s ...\n", dd->disk->disk_name);
+ del_gendisk(dd->disk);
if (dd->disk->queue) {
- del_gendisk(dd->disk);
blk_cleanup_queue(dd->queue);
blk_mq_free_tag_set(&dd->tags);
- } else
- put_disk(dd->disk);
+ }
+ put_disk(dd->disk);
dd->disk = NULL;
dd->queue = NULL;
}
@@ -4507,6 +4449,7 @@ static void mtip_pci_remove(struct pci_dev *pdev)
"Completion workers still active!\n");
}
+ blk_mq_stop_hw_queues(dd->queue);
/* Clean up the block layer. */
mtip_block_remove(dd);
@@ -4524,10 +4467,7 @@ static void mtip_pci_remove(struct pci_dev *pdev)
list_del_init(&dd->remove_list);
spin_unlock_irqrestore(&dev_lock, flags);
- if (!dd->sr)
- kfree(dd);
- else
- set_bit(MTIP_DDF_REMOVE_DONE_BIT, &dd->dd_flag);
+ kfree(dd);
pcim_iounmap_regions(pdev, 1 << MTIP_ABAR);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h
index ba1b31ee22ec..3274784008eb 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -142,7 +142,6 @@ enum {
MTIP_PF_SVC_THD_ACTIVE_BIT = 4,
MTIP_PF_ISSUE_CMDS_BIT = 5,
MTIP_PF_REBUILD_BIT = 6,
- MTIP_PF_SR_CLEANUP_BIT = 7,
MTIP_PF_SVC_THD_STOP_BIT = 8,
/* below are bit numbers in 'dd_flag' defined in driver_data */
@@ -150,7 +149,6 @@ enum {
MTIP_DDF_REMOVE_PENDING_BIT = 1,
MTIP_DDF_OVER_TEMP_BIT = 2,
MTIP_DDF_WRITE_PROTECT_BIT = 3,
- MTIP_DDF_REMOVE_DONE_BIT = 4,
MTIP_DDF_CLEANUP_BIT = 5,
MTIP_DDF_RESUME_BIT = 6,
MTIP_DDF_INIT_DONE_BIT = 7,
@@ -412,19 +410,13 @@ struct mtip_port {
* by the DMA when the driver issues internal commands.
*/
dma_addr_t sector_buffer_dma;
- /*
- * Bit significant, used to determine if a command slot has
- * been allocated. i.e. the slot is in use. Bits are cleared
- * when the command slot and all associated data structures
- * are no longer needed.
- */
+
u16 *log_buf;
dma_addr_t log_buf_dma;
u8 *smart_buf;
dma_addr_t smart_buf_dma;
- unsigned long allocated[SLOTBITS_IN_LONGS];
/*
* used to queue commands when an internal command is in progress
* or error handling is active
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 39e5f7fae3ef..0e385d8e9b86 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -230,29 +230,40 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req)
int result, flags;
struct nbd_request request;
unsigned long size = blk_rq_bytes(req);
+ u32 type;
+
+ if (req->cmd_type == REQ_TYPE_DRV_PRIV)
+ type = NBD_CMD_DISC;
+ else if (req->cmd_flags & REQ_DISCARD)
+ type = NBD_CMD_TRIM;
+ else if (req->cmd_flags & REQ_FLUSH)
+ type = NBD_CMD_FLUSH;
+ else if (rq_data_dir(req) == WRITE)
+ type = NBD_CMD_WRITE;
+ else
+ type = NBD_CMD_READ;
memset(&request, 0, sizeof(request));
request.magic = htonl(NBD_REQUEST_MAGIC);
- request.type = htonl(nbd_cmd(req));
-
- if (nbd_cmd(req) != NBD_CMD_FLUSH && nbd_cmd(req) != NBD_CMD_DISC) {
+ request.type = htonl(type);
+ if (type != NBD_CMD_FLUSH && type != NBD_CMD_DISC) {
request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9);
request.len = htonl(size);
}
memcpy(request.handle, &req, sizeof(req));
dev_dbg(nbd_to_dev(nbd), "request %p: sending control (%s@%llu,%uB)\n",
- req, nbdcmd_to_ascii(nbd_cmd(req)),
+ req, nbdcmd_to_ascii(type),
(unsigned long long)blk_rq_pos(req) << 9, blk_rq_bytes(req));
result = sock_xmit(nbd, 1, &request, sizeof(request),
- (nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0);
+ (type == NBD_CMD_WRITE) ? MSG_MORE : 0);
if (result <= 0) {
dev_err(disk_to_dev(nbd->disk),
"Send control failed (result %d)\n", result);
return -EIO;
}
- if (nbd_cmd(req) == NBD_CMD_WRITE) {
+ if (type == NBD_CMD_WRITE) {
struct req_iterator iter;
struct bio_vec bvec;
/*
@@ -352,7 +363,7 @@ static struct request *nbd_read_stat(struct nbd_device *nbd)
}
dev_dbg(nbd_to_dev(nbd), "request %p: got reply\n", req);
- if (nbd_cmd(req) == NBD_CMD_READ) {
+ if (rq_data_dir(req) != WRITE) {
struct req_iterator iter;
struct bio_vec bvec;
@@ -452,23 +463,11 @@ static void nbd_handle_req(struct nbd_device *nbd, struct request *req)
if (req->cmd_type != REQ_TYPE_FS)
goto error_out;
- nbd_cmd(req) = NBD_CMD_READ;
- if (rq_data_dir(req) == WRITE) {
- if ((req->cmd_flags & REQ_DISCARD)) {
- WARN_ON(!(nbd->flags & NBD_FLAG_SEND_TRIM));
- nbd_cmd(req) = NBD_CMD_TRIM;
- } else
- nbd_cmd(req) = NBD_CMD_WRITE;
- if (nbd->flags & NBD_FLAG_READ_ONLY) {
- dev_err(disk_to_dev(nbd->disk),
- "Write on read-only\n");
- goto error_out;
- }
- }
-
- if (req->cmd_flags & REQ_FLUSH) {
- BUG_ON(unlikely(blk_rq_sectors(req)));
- nbd_cmd(req) = NBD_CMD_FLUSH;
+ if (rq_data_dir(req) == WRITE &&
+ (nbd->flags & NBD_FLAG_READ_ONLY)) {
+ dev_err(disk_to_dev(nbd->disk),
+ "Write on read-only\n");
+ goto error_out;
}
req->errors = 0;
@@ -592,8 +591,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
fsync_bdev(bdev);
mutex_lock(&nbd->tx_lock);
blk_rq_init(NULL, &sreq);
- sreq.cmd_type = REQ_TYPE_SPECIAL;
- nbd_cmd(&sreq) = NBD_CMD_DISC;
+ sreq.cmd_type = REQ_TYPE_DRV_PRIV;
/* Check again after getting mutex back. */
if (!nbd->sock)
@@ -713,7 +711,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
bdev->bd_inode->i_size = 0;
set_capacity(nbd->disk, 0);
if (max_part > 0)
- ioctl_by_bdev(bdev, BLKRRPART, 0);
+ blkdev_reread_part(bdev);
if (nbd->disconnect) /* user requested, ignore socket errors */
return 0;
return nbd->harderror;
diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c
index 65cd61a4145e..6f9b7534928e 100644
--- a/drivers/block/null_blk.c
+++ b/drivers/block/null_blk.c
@@ -243,6 +243,17 @@ static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
cmd = container_of(entry, struct nullb_cmd, ll_list);
entry = entry->next;
end_cmd(cmd);
+
+ if (cmd->rq) {
+ struct request_queue *q = cmd->rq->q;
+
+ if (!q->mq_ops && blk_queue_stopped(q)) {
+ spin_lock(q->queue_lock);
+ if (blk_queue_stopped(q))
+ blk_start_queue(q);
+ spin_unlock(q->queue_lock);
+ }
+ }
} while (entry);
}
@@ -257,7 +268,7 @@ static void null_cmd_end_timer(struct nullb_cmd *cmd)
if (llist_add(&cmd->ll_list, &cq->list)) {
ktime_t kt = ktime_set(0, completion_nsec);
- hrtimer_start(&cq->timer, kt, HRTIMER_MODE_REL);
+ hrtimer_start(&cq->timer, kt, HRTIMER_MODE_REL_PINNED);
}
put_cpu();
@@ -334,6 +345,7 @@ static int null_rq_prep_fn(struct request_queue *q, struct request *req)
req->special = cmd;
return BLKPREP_OK;
}
+ blk_stop_queue(q);
return BLKPREP_DEFER;
}
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index 683dff272562..e5112714188f 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -29,6 +29,7 @@
#include <linux/kdev_t.h>
#include <linux/kthread.h>
#include <linux/kernel.h>
+#include <linux/list_sort.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -80,6 +81,7 @@ static wait_queue_head_t nvme_kthread_wait;
static struct class *nvme_class;
static void nvme_reset_failed_dev(struct work_struct *ws);
+static int nvme_reset(struct nvme_dev *dev);
static int nvme_process_cq(struct nvme_queue *nvmeq);
struct async_cmd_info {
@@ -102,6 +104,7 @@ struct nvme_queue {
spinlock_t q_lock;
struct nvme_command *sq_cmds;
volatile struct nvme_completion *cqes;
+ struct blk_mq_tags **tags;
dma_addr_t sq_dma_addr;
dma_addr_t cq_dma_addr;
u32 __iomem *q_db;
@@ -114,7 +117,6 @@ struct nvme_queue {
u8 cq_phase;
u8 cqe_seen;
struct async_cmd_info cmdinfo;
- struct blk_mq_hw_ctx *hctx;
};
/*
@@ -182,9 +184,12 @@ static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
struct nvme_dev *dev = data;
struct nvme_queue *nvmeq = dev->queues[0];
- WARN_ON(nvmeq->hctx);
- nvmeq->hctx = hctx;
+ WARN_ON(hctx_idx != 0);
+ WARN_ON(dev->admin_tagset.tags[0] != hctx->tags);
+ WARN_ON(nvmeq->tags);
+
hctx->driver_data = nvmeq;
+ nvmeq->tags = &dev->admin_tagset.tags[0];
return 0;
}
@@ -201,27 +206,16 @@ static int nvme_admin_init_request(void *data, struct request *req,
return 0;
}
-static void nvme_exit_hctx(struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx)
-{
- struct nvme_queue *nvmeq = hctx->driver_data;
-
- nvmeq->hctx = NULL;
-}
-
static int nvme_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
unsigned int hctx_idx)
{
struct nvme_dev *dev = data;
- struct nvme_queue *nvmeq = dev->queues[
- (hctx_idx % dev->queue_count) + 1];
-
- if (!nvmeq->hctx)
- nvmeq->hctx = hctx;
+ struct nvme_queue *nvmeq = dev->queues[hctx_idx + 1];
- /* nvmeq queues are shared between namespaces. We assume here that
- * blk-mq map the tags so they match up with the nvme queue tags. */
- WARN_ON(nvmeq->hctx->tags != hctx->tags);
+ if (!nvmeq->tags)
+ nvmeq->tags = &dev->tagset.tags[hctx_idx];
+ WARN_ON(dev->tagset.tags[hctx_idx] != hctx->tags);
hctx->driver_data = nvmeq;
return 0;
}
@@ -307,9 +301,16 @@ static void async_req_completion(struct nvme_queue *nvmeq, void *ctx,
if (status == NVME_SC_SUCCESS || status == NVME_SC_ABORT_REQ)
++nvmeq->dev->event_limit;
- if (status == NVME_SC_SUCCESS)
- dev_warn(nvmeq->q_dmadev,
- "async event result %08x\n", result);
+ if (status != NVME_SC_SUCCESS)
+ return;
+
+ switch (result & 0xff07) {
+ case NVME_AER_NOTICE_NS_CHANGED:
+ dev_info(nvmeq->q_dmadev, "rescanning\n");
+ schedule_work(&nvmeq->dev->scan_work);
+ default:
+ dev_warn(nvmeq->q_dmadev, "async event result %08x\n", result);
+ }
}
static void abort_completion(struct nvme_queue *nvmeq, void *ctx,
@@ -320,7 +321,7 @@ static void abort_completion(struct nvme_queue *nvmeq, void *ctx,
u16 status = le16_to_cpup(&cqe->status) >> 1;
u32 result = le32_to_cpup(&cqe->result);
- blk_mq_free_hctx_request(nvmeq->hctx, req);
+ blk_mq_free_request(req);
dev_warn(nvmeq->q_dmadev, "Abort status:%x result:%x", status, result);
++nvmeq->dev->abort_limit;
@@ -333,14 +334,13 @@ static void async_completion(struct nvme_queue *nvmeq, void *ctx,
cmdinfo->result = le32_to_cpup(&cqe->result);
cmdinfo->status = le16_to_cpup(&cqe->status) >> 1;
queue_kthread_work(cmdinfo->worker, &cmdinfo->work);
- blk_mq_free_hctx_request(nvmeq->hctx, cmdinfo->req);
+ blk_mq_free_request(cmdinfo->req);
}
static inline struct nvme_cmd_info *get_cmd_from_tag(struct nvme_queue *nvmeq,
unsigned int tag)
{
- struct blk_mq_hw_ctx *hctx = nvmeq->hctx;
- struct request *req = blk_mq_tag_to_rq(hctx->tags, tag);
+ struct request *req = blk_mq_tag_to_rq(*nvmeq->tags, tag);
return blk_mq_rq_to_pdu(req);
}
@@ -445,7 +445,7 @@ static struct nvme_iod *nvme_alloc_iod(struct request *rq, struct nvme_dev *dev,
(unsigned long) rq, gfp);
}
-void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod)
+static void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod)
{
const int last_prp = dev->page_size / 8 - 1;
int i;
@@ -605,22 +605,30 @@ static void req_completion(struct nvme_queue *nvmeq, void *ctx,
spin_unlock_irqrestore(req->q->queue_lock, flags);
return;
}
- req->errors = nvme_error_status(status);
+ if (req->cmd_type == REQ_TYPE_DRV_PRIV) {
+ req->errors = status;
+ } else {
+ req->errors = nvme_error_status(status);
+ }
} else
req->errors = 0;
+ if (req->cmd_type == REQ_TYPE_DRV_PRIV) {
+ u32 result = le32_to_cpup(&cqe->result);
+ req->special = (void *)(uintptr_t)result;
+ }
if (cmd_rq->aborted)
- dev_warn(&nvmeq->dev->pci_dev->dev,
+ dev_warn(nvmeq->dev->dev,
"completing aborted command with status:%04x\n",
status);
if (iod->nents) {
- dma_unmap_sg(&nvmeq->dev->pci_dev->dev, iod->sg, iod->nents,
+ dma_unmap_sg(nvmeq->dev->dev, iod->sg, iod->nents,
rq_data_dir(req) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (blk_integrity_rq(req)) {
if (!rq_data_dir(req))
nvme_dif_remap(req, nvme_dif_complete);
- dma_unmap_sg(&nvmeq->dev->pci_dev->dev, iod->meta_sg, 1,
+ dma_unmap_sg(nvmeq->dev->dev, iod->meta_sg, 1,
rq_data_dir(req) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
}
}
@@ -630,8 +638,8 @@ static void req_completion(struct nvme_queue *nvmeq, void *ctx,
}
/* length is in bytes. gfp flags indicates whether we may sleep. */
-int nvme_setup_prps(struct nvme_dev *dev, struct nvme_iod *iod, int total_len,
- gfp_t gfp)
+static int nvme_setup_prps(struct nvme_dev *dev, struct nvme_iod *iod,
+ int total_len, gfp_t gfp)
{
struct dma_pool *pool;
int length = total_len;
@@ -709,6 +717,23 @@ int nvme_setup_prps(struct nvme_dev *dev, struct nvme_iod *iod, int total_len,
return total_len;
}
+static void nvme_submit_priv(struct nvme_queue *nvmeq, struct request *req,
+ struct nvme_iod *iod)
+{
+ struct nvme_command *cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail];
+
+ memcpy(cmnd, req->cmd, sizeof(struct nvme_command));
+ cmnd->rw.command_id = req->tag;
+ if (req->nr_phys_segments) {
+ cmnd->rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg));
+ cmnd->rw.prp2 = cpu_to_le64(iod->first_dma);
+ }
+
+ if (++nvmeq->sq_tail == nvmeq->q_depth)
+ nvmeq->sq_tail = 0;
+ writel(nvmeq->sq_tail, nvmeq->q_db);
+}
+
/*
* We reuse the small pool to allocate the 16-byte range here as it is not
* worth having a special pool for these or additional cases to handle freeing
@@ -807,11 +832,15 @@ static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod,
return 0;
}
+/*
+ * NOTE: ns is NULL when called on the admin queue.
+ */
static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
{
struct nvme_ns *ns = hctx->queue->queuedata;
struct nvme_queue *nvmeq = hctx->driver_data;
+ struct nvme_dev *dev = nvmeq->dev;
struct request *req = bd->rq;
struct nvme_cmd_info *cmd = blk_mq_rq_to_pdu(req);
struct nvme_iod *iod;
@@ -822,15 +851,16 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
* unless this namespace is formated such that the metadata can be
* stripped/generated by the controller with PRACT=1.
*/
- if (ns->ms && !blk_integrity_rq(req)) {
- if (!(ns->pi_type && ns->ms == 8)) {
+ if (ns && ns->ms && !blk_integrity_rq(req)) {
+ if (!(ns->pi_type && ns->ms == 8) &&
+ req->cmd_type != REQ_TYPE_DRV_PRIV) {
req->errors = -EFAULT;
blk_mq_complete_request(req);
return BLK_MQ_RQ_QUEUE_OK;
}
}
- iod = nvme_alloc_iod(req, ns->dev, GFP_ATOMIC);
+ iod = nvme_alloc_iod(req, dev, GFP_ATOMIC);
if (!iod)
return BLK_MQ_RQ_QUEUE_BUSY;
@@ -841,8 +871,7 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
* as it is not worth having a special pool for these or
* additional cases to handle freeing the iod.
*/
- range = dma_pool_alloc(nvmeq->dev->prp_small_pool,
- GFP_ATOMIC,
+ range = dma_pool_alloc(dev->prp_small_pool, GFP_ATOMIC,
&iod->first_dma);
if (!range)
goto retry_cmd;
@@ -860,9 +889,8 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
goto retry_cmd;
if (blk_rq_bytes(req) !=
- nvme_setup_prps(nvmeq->dev, iod, blk_rq_bytes(req), GFP_ATOMIC)) {
- dma_unmap_sg(&nvmeq->dev->pci_dev->dev, iod->sg,
- iod->nents, dma_dir);
+ nvme_setup_prps(dev, iod, blk_rq_bytes(req), GFP_ATOMIC)) {
+ dma_unmap_sg(dev->dev, iod->sg, iod->nents, dma_dir);
goto retry_cmd;
}
if (blk_integrity_rq(req)) {
@@ -884,7 +912,9 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
nvme_set_info(cmd, iod, req_completion);
spin_lock_irq(&nvmeq->q_lock);
- if (req->cmd_flags & REQ_DISCARD)
+ if (req->cmd_type == REQ_TYPE_DRV_PRIV)
+ nvme_submit_priv(nvmeq, req, iod);
+ else if (req->cmd_flags & REQ_DISCARD)
nvme_submit_discard(nvmeq, ns, req, iod);
else if (req->cmd_flags & REQ_FLUSH)
nvme_submit_flush(nvmeq, ns, req->tag);
@@ -896,10 +926,10 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
return BLK_MQ_RQ_QUEUE_OK;
error_cmd:
- nvme_free_iod(nvmeq->dev, iod);
+ nvme_free_iod(dev, iod);
return BLK_MQ_RQ_QUEUE_ERROR;
retry_cmd:
- nvme_free_iod(nvmeq->dev, iod);
+ nvme_free_iod(dev, iod);
return BLK_MQ_RQ_QUEUE_BUSY;
}
@@ -942,15 +972,6 @@ static int nvme_process_cq(struct nvme_queue *nvmeq)
return 1;
}
-/* Admin queue isn't initialized as a request queue. If at some point this
- * happens anyway, make sure to notify the user */
-static int nvme_admin_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd)
-{
- WARN_ON_ONCE(1);
- return BLK_MQ_RQ_QUEUE_ERROR;
-}
-
static irqreturn_t nvme_irq(int irq, void *data)
{
irqreturn_t result;
@@ -972,46 +993,61 @@ static irqreturn_t nvme_irq_check(int irq, void *data)
return IRQ_WAKE_THREAD;
}
-struct sync_cmd_info {
- struct task_struct *task;
- u32 result;
- int status;
-};
-
-static void sync_completion(struct nvme_queue *nvmeq, void *ctx,
- struct nvme_completion *cqe)
-{
- struct sync_cmd_info *cmdinfo = ctx;
- cmdinfo->result = le32_to_cpup(&cqe->result);
- cmdinfo->status = le16_to_cpup(&cqe->status) >> 1;
- wake_up_process(cmdinfo->task);
-}
-
/*
* Returns 0 on success. If the result is negative, it's a Linux error code;
* if the result is positive, it's an NVM Express status code
*/
-static int nvme_submit_sync_cmd(struct request *req, struct nvme_command *cmd,
- u32 *result, unsigned timeout)
+int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
+ void *buffer, void __user *ubuffer, unsigned bufflen,
+ u32 *result, unsigned timeout)
{
- struct sync_cmd_info cmdinfo;
- struct nvme_cmd_info *cmd_rq = blk_mq_rq_to_pdu(req);
- struct nvme_queue *nvmeq = cmd_rq->nvmeq;
+ bool write = cmd->common.opcode & 1;
+ struct bio *bio = NULL;
+ struct request *req;
+ int ret;
- cmdinfo.task = current;
- cmdinfo.status = -EINTR;
+ req = blk_mq_alloc_request(q, write, GFP_KERNEL, false);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
- cmd->common.command_id = req->tag;
+ req->cmd_type = REQ_TYPE_DRV_PRIV;
+ req->cmd_flags |= REQ_FAILFAST_DRIVER;
+ req->__data_len = 0;
+ req->__sector = (sector_t) -1;
+ req->bio = req->biotail = NULL;
+
+ req->timeout = timeout ? timeout : ADMIN_TIMEOUT;
- nvme_set_info(cmd_rq, &cmdinfo, sync_completion);
+ req->cmd = (unsigned char *)cmd;
+ req->cmd_len = sizeof(struct nvme_command);
+ req->special = (void *)0;
- set_current_state(TASK_UNINTERRUPTIBLE);
- nvme_submit_cmd(nvmeq, cmd);
- schedule();
+ if (buffer && bufflen) {
+ ret = blk_rq_map_kern(q, req, buffer, bufflen, __GFP_WAIT);
+ if (ret)
+ goto out;
+ } else if (ubuffer && bufflen) {
+ ret = blk_rq_map_user(q, req, NULL, ubuffer, bufflen, __GFP_WAIT);
+ if (ret)
+ goto out;
+ bio = req->bio;
+ }
+ blk_execute_rq(req->q, NULL, req, 0);
+ if (bio)
+ blk_rq_unmap_user(bio);
if (result)
- *result = cmdinfo.result;
- return cmdinfo.status;
+ *result = (u32)(uintptr_t)req->special;
+ ret = req->errors;
+ out:
+ blk_mq_free_request(req);
+ return ret;
+}
+
+int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
+ void *buffer, unsigned bufflen)
+{
+ return __nvme_submit_sync_cmd(q, cmd, buffer, NULL, bufflen, NULL, 0);
}
static int nvme_submit_async_admin_req(struct nvme_dev *dev)
@@ -1033,7 +1069,7 @@ static int nvme_submit_async_admin_req(struct nvme_dev *dev)
c.common.opcode = nvme_admin_async_event;
c.common.command_id = req->tag;
- blk_mq_free_hctx_request(nvmeq->hctx, req);
+ blk_mq_free_request(req);
return __nvme_submit_cmd(nvmeq, &c);
}
@@ -1060,41 +1096,6 @@ static int nvme_submit_admin_async_cmd(struct nvme_dev *dev,
return nvme_submit_cmd(nvmeq, cmd);
}
-static int __nvme_submit_admin_cmd(struct nvme_dev *dev, struct nvme_command *cmd,
- u32 *result, unsigned timeout)
-{
- int res;
- struct request *req;
-
- req = blk_mq_alloc_request(dev->admin_q, WRITE, GFP_KERNEL, false);
- if (IS_ERR(req))
- return PTR_ERR(req);
- res = nvme_submit_sync_cmd(req, cmd, result, timeout);
- blk_mq_free_request(req);
- return res;
-}
-
-int nvme_submit_admin_cmd(struct nvme_dev *dev, struct nvme_command *cmd,
- u32 *result)
-{
- return __nvme_submit_admin_cmd(dev, cmd, result, ADMIN_TIMEOUT);
-}
-
-int nvme_submit_io_cmd(struct nvme_dev *dev, struct nvme_ns *ns,
- struct nvme_command *cmd, u32 *result)
-{
- int res;
- struct request *req;
-
- req = blk_mq_alloc_request(ns->queue, WRITE, (GFP_KERNEL|__GFP_WAIT),
- false);
- if (IS_ERR(req))
- return PTR_ERR(req);
- res = nvme_submit_sync_cmd(req, cmd, result, NVME_IO_TIMEOUT);
- blk_mq_free_request(req);
- return res;
-}
-
static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id)
{
struct nvme_command c;
@@ -1103,7 +1104,7 @@ static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id)
c.delete_queue.opcode = opcode;
c.delete_queue.qid = cpu_to_le16(id);
- return nvme_submit_admin_cmd(dev, &c, NULL);
+ return nvme_submit_sync_cmd(dev->admin_q, &c, NULL, 0);
}
static int adapter_alloc_cq(struct nvme_dev *dev, u16 qid,
@@ -1112,6 +1113,10 @@ static int adapter_alloc_cq(struct nvme_dev *dev, u16 qid,
struct nvme_command c;
int flags = NVME_QUEUE_PHYS_CONTIG | NVME_CQ_IRQ_ENABLED;
+ /*
+ * Note: we (ab)use the fact the the prp fields survive if no data
+ * is attached to the request.
+ */
memset(&c, 0, sizeof(c));
c.create_cq.opcode = nvme_admin_create_cq;
c.create_cq.prp1 = cpu_to_le64(nvmeq->cq_dma_addr);
@@ -1120,7 +1125,7 @@ static int adapter_alloc_cq(struct nvme_dev *dev, u16 qid,
c.create_cq.cq_flags = cpu_to_le16(flags);
c.create_cq.irq_vector = cpu_to_le16(nvmeq->cq_vector);
- return nvme_submit_admin_cmd(dev, &c, NULL);
+ return nvme_submit_sync_cmd(dev->admin_q, &c, NULL, 0);
}
static int adapter_alloc_sq(struct nvme_dev *dev, u16 qid,
@@ -1129,6 +1134,10 @@ static int adapter_alloc_sq(struct nvme_dev *dev, u16 qid,
struct nvme_command c;
int flags = NVME_QUEUE_PHYS_CONTIG | NVME_SQ_PRIO_MEDIUM;
+ /*
+ * Note: we (ab)use the fact the the prp fields survive if no data
+ * is attached to the request.
+ */
memset(&c, 0, sizeof(c));
c.create_sq.opcode = nvme_admin_create_sq;
c.create_sq.prp1 = cpu_to_le64(nvmeq->sq_dma_addr);
@@ -1137,7 +1146,7 @@ static int adapter_alloc_sq(struct nvme_dev *dev, u16 qid,
c.create_sq.sq_flags = cpu_to_le16(flags);
c.create_sq.cqid = cpu_to_le16(qid);
- return nvme_submit_admin_cmd(dev, &c, NULL);
+ return nvme_submit_sync_cmd(dev->admin_q, &c, NULL, 0);
}
static int adapter_delete_cq(struct nvme_dev *dev, u16 cqid)
@@ -1150,18 +1159,43 @@ static int adapter_delete_sq(struct nvme_dev *dev, u16 sqid)
return adapter_delete_queue(dev, nvme_admin_delete_sq, sqid);
}
-int nvme_identify(struct nvme_dev *dev, unsigned nsid, unsigned cns,
- dma_addr_t dma_addr)
+int nvme_identify_ctrl(struct nvme_dev *dev, struct nvme_id_ctrl **id)
{
- struct nvme_command c;
+ struct nvme_command c = {
+ .identify.opcode = nvme_admin_identify,
+ .identify.cns = cpu_to_le32(1),
+ };
+ int error;
- memset(&c, 0, sizeof(c));
- c.identify.opcode = nvme_admin_identify;
- c.identify.nsid = cpu_to_le32(nsid);
- c.identify.prp1 = cpu_to_le64(dma_addr);
- c.identify.cns = cpu_to_le32(cns);
+ *id = kmalloc(sizeof(struct nvme_id_ctrl), GFP_KERNEL);
+ if (!*id)
+ return -ENOMEM;
- return nvme_submit_admin_cmd(dev, &c, NULL);
+ error = nvme_submit_sync_cmd(dev->admin_q, &c, *id,
+ sizeof(struct nvme_id_ctrl));
+ if (error)
+ kfree(*id);
+ return error;
+}
+
+int nvme_identify_ns(struct nvme_dev *dev, unsigned nsid,
+ struct nvme_id_ns **id)
+{
+ struct nvme_command c = {
+ .identify.opcode = nvme_admin_identify,
+ .identify.nsid = cpu_to_le32(nsid),
+ };
+ int error;
+
+ *id = kmalloc(sizeof(struct nvme_id_ns), GFP_KERNEL);
+ if (!*id)
+ return -ENOMEM;
+
+ error = nvme_submit_sync_cmd(dev->admin_q, &c, *id,
+ sizeof(struct nvme_id_ns));
+ if (error)
+ kfree(*id);
+ return error;
}
int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
@@ -1175,7 +1209,8 @@ int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
c.features.prp1 = cpu_to_le64(dma_addr);
c.features.fid = cpu_to_le32(fid);
- return nvme_submit_admin_cmd(dev, &c, result);
+ return __nvme_submit_sync_cmd(dev->admin_q, &c, NULL, NULL, 0,
+ result, 0);
}
int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,
@@ -1189,7 +1224,30 @@ int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,
c.features.fid = cpu_to_le32(fid);
c.features.dword11 = cpu_to_le32(dword11);
- return nvme_submit_admin_cmd(dev, &c, result);
+ return __nvme_submit_sync_cmd(dev->admin_q, &c, NULL, NULL, 0,
+ result, 0);
+}
+
+int nvme_get_log_page(struct nvme_dev *dev, struct nvme_smart_log **log)
+{
+ struct nvme_command c = {
+ .common.opcode = nvme_admin_get_log_page,
+ .common.nsid = cpu_to_le32(0xFFFFFFFF),
+ .common.cdw10[0] = cpu_to_le32(
+ (((sizeof(struct nvme_smart_log) / 4) - 1) << 16) |
+ NVME_LOG_SMART),
+ };
+ int error;
+
+ *log = kmalloc(sizeof(struct nvme_smart_log), GFP_KERNEL);
+ if (!*log)
+ return -ENOMEM;
+
+ error = nvme_submit_sync_cmd(dev->admin_q, &c, *log,
+ sizeof(struct nvme_smart_log));
+ if (error)
+ kfree(*log);
+ return error;
}
/**
@@ -1214,8 +1272,7 @@ static void nvme_abort_req(struct request *req)
if (work_busy(&dev->reset_work))
goto out;
list_del_init(&dev->node);
- dev_warn(&dev->pci_dev->dev,
- "I/O %d QID %d timeout, reset controller\n",
+ dev_warn(dev->dev, "I/O %d QID %d timeout, reset controller\n",
req->tag, nvmeq->qid);
dev->reset_workfn = nvme_reset_failed_dev;
queue_work(nvme_workq, &dev->reset_work);
@@ -1254,8 +1311,7 @@ static void nvme_abort_req(struct request *req)
}
}
-static void nvme_cancel_queue_ios(struct blk_mq_hw_ctx *hctx,
- struct request *req, void *data, bool reserved)
+static void nvme_cancel_queue_ios(struct request *req, void *data, bool reserved)
{
struct nvme_queue *nvmeq = data;
void *ctx;
@@ -1352,11 +1408,9 @@ static int nvme_suspend_queue(struct nvme_queue *nvmeq)
static void nvme_clear_queue(struct nvme_queue *nvmeq)
{
- struct blk_mq_hw_ctx *hctx = nvmeq->hctx;
-
spin_lock_irq(&nvmeq->q_lock);
- if (hctx && hctx->tags)
- blk_mq_tag_busy_iter(hctx, nvme_cancel_queue_ios, nvmeq);
+ if (nvmeq->tags && *nvmeq->tags)
+ blk_mq_all_tag_busy_iter(*nvmeq->tags, nvme_cancel_queue_ios, nvmeq);
spin_unlock_irq(&nvmeq->q_lock);
}
@@ -1384,22 +1438,21 @@ static void nvme_disable_queue(struct nvme_dev *dev, int qid)
static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
int depth)
{
- struct device *dmadev = &dev->pci_dev->dev;
struct nvme_queue *nvmeq = kzalloc(sizeof(*nvmeq), GFP_KERNEL);
if (!nvmeq)
return NULL;
- nvmeq->cqes = dma_zalloc_coherent(dmadev, CQ_SIZE(depth),
+ nvmeq->cqes = dma_zalloc_coherent(dev->dev, CQ_SIZE(depth),
&nvmeq->cq_dma_addr, GFP_KERNEL);
if (!nvmeq->cqes)
goto free_nvmeq;
- nvmeq->sq_cmds = dma_alloc_coherent(dmadev, SQ_SIZE(depth),
+ nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth),
&nvmeq->sq_dma_addr, GFP_KERNEL);
if (!nvmeq->sq_cmds)
goto free_cqdma;
- nvmeq->q_dmadev = dmadev;
+ nvmeq->q_dmadev = dev->dev;
nvmeq->dev = dev;
snprintf(nvmeq->irqname, sizeof(nvmeq->irqname), "nvme%dq%d",
dev->instance, qid);
@@ -1409,13 +1462,16 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride];
nvmeq->q_depth = depth;
nvmeq->qid = qid;
- dev->queue_count++;
dev->queues[qid] = nvmeq;
+ /* make sure queue descriptor is set before queue count, for kthread */
+ mb();
+ dev->queue_count++;
+
return nvmeq;
free_cqdma:
- dma_free_coherent(dmadev, CQ_SIZE(depth), (void *)nvmeq->cqes,
+ dma_free_coherent(dev->dev, CQ_SIZE(depth), (void *)nvmeq->cqes,
nvmeq->cq_dma_addr);
free_nvmeq:
kfree(nvmeq);
@@ -1487,7 +1543,7 @@ static int nvme_wait_ready(struct nvme_dev *dev, u64 cap, bool enabled)
if (fatal_signal_pending(current))
return -EINTR;
if (time_after(jiffies, timeout)) {
- dev_err(&dev->pci_dev->dev,
+ dev_err(dev->dev,
"Device not ready; aborting %s\n", enabled ?
"initialisation" : "reset");
return -ENODEV;
@@ -1537,7 +1593,7 @@ static int nvme_shutdown_ctrl(struct nvme_dev *dev)
if (fatal_signal_pending(current))
return -EINTR;
if (time_after(jiffies, timeout)) {
- dev_err(&dev->pci_dev->dev,
+ dev_err(dev->dev,
"Device shutdown incomplete; abort shutdown\n");
return -ENODEV;
}
@@ -1547,10 +1603,9 @@ static int nvme_shutdown_ctrl(struct nvme_dev *dev)
}
static struct blk_mq_ops nvme_mq_admin_ops = {
- .queue_rq = nvme_admin_queue_rq,
+ .queue_rq = nvme_queue_rq,
.map_queue = blk_mq_map_queue,
.init_hctx = nvme_admin_init_hctx,
- .exit_hctx = nvme_exit_hctx,
.init_request = nvme_admin_init_request,
.timeout = nvme_timeout,
};
@@ -1559,7 +1614,6 @@ static struct blk_mq_ops nvme_mq_ops = {
.queue_rq = nvme_queue_rq,
.map_queue = blk_mq_map_queue,
.init_hctx = nvme_init_hctx,
- .exit_hctx = nvme_exit_hctx,
.init_request = nvme_init_request,
.timeout = nvme_timeout,
};
@@ -1580,7 +1634,7 @@ static int nvme_alloc_admin_tags(struct nvme_dev *dev)
dev->admin_tagset.queue_depth = NVME_AQ_DEPTH - 1;
dev->admin_tagset.reserved_tags = 1;
dev->admin_tagset.timeout = ADMIN_TIMEOUT;
- dev->admin_tagset.numa_node = dev_to_node(&dev->pci_dev->dev);
+ dev->admin_tagset.numa_node = dev_to_node(dev->dev);
dev->admin_tagset.cmd_size = nvme_cmd_size(dev);
dev->admin_tagset.driver_data = dev;
@@ -1613,14 +1667,14 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
unsigned dev_page_max = NVME_CAP_MPSMAX(cap) + 12;
if (page_shift < dev_page_min) {
- dev_err(&dev->pci_dev->dev,
+ dev_err(dev->dev,
"Minimum device page size (%u) too large for "
"host (%u)\n", 1 << dev_page_min,
1 << page_shift);
return -ENODEV;
}
if (page_shift > dev_page_max) {
- dev_info(&dev->pci_dev->dev,
+ dev_info(dev->dev,
"Device maximum page size (%u) smaller than "
"host (%u); enabling work-around\n",
1 << dev_page_max, 1 << page_shift);
@@ -1668,126 +1722,43 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
return result;
}
-struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
- unsigned long addr, unsigned length)
-{
- int i, err, count, nents, offset;
- struct scatterlist *sg;
- struct page **pages;
- struct nvme_iod *iod;
-
- if (addr & 3)
- return ERR_PTR(-EINVAL);
- if (!length || length > INT_MAX - PAGE_SIZE)
- return ERR_PTR(-EINVAL);
-
- offset = offset_in_page(addr);
- count = DIV_ROUND_UP(offset + length, PAGE_SIZE);
- pages = kcalloc(count, sizeof(*pages), GFP_KERNEL);
- if (!pages)
- return ERR_PTR(-ENOMEM);
-
- err = get_user_pages_fast(addr, count, 1, pages);
- if (err < count) {
- count = err;
- err = -EFAULT;
- goto put_pages;
- }
-
- err = -ENOMEM;
- iod = __nvme_alloc_iod(count, length, dev, 0, GFP_KERNEL);
- if (!iod)
- goto put_pages;
-
- sg = iod->sg;
- sg_init_table(sg, count);
- for (i = 0; i < count; i++) {
- sg_set_page(&sg[i], pages[i],
- min_t(unsigned, length, PAGE_SIZE - offset),
- offset);
- length -= (PAGE_SIZE - offset);
- offset = 0;
- }
- sg_mark_end(&sg[i - 1]);
- iod->nents = count;
-
- nents = dma_map_sg(&dev->pci_dev->dev, sg, count,
- write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- if (!nents)
- goto free_iod;
-
- kfree(pages);
- return iod;
-
- free_iod:
- kfree(iod);
- put_pages:
- for (i = 0; i < count; i++)
- put_page(pages[i]);
- kfree(pages);
- return ERR_PTR(err);
-}
-
-void nvme_unmap_user_pages(struct nvme_dev *dev, int write,
- struct nvme_iod *iod)
-{
- int i;
-
- dma_unmap_sg(&dev->pci_dev->dev, iod->sg, iod->nents,
- write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-
- for (i = 0; i < iod->nents; i++)
- put_page(sg_page(&iod->sg[i]));
-}
-
static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
{
struct nvme_dev *dev = ns->dev;
struct nvme_user_io io;
struct nvme_command c;
- unsigned length, meta_len, prp_len;
+ unsigned length, meta_len;
int status, write;
- struct nvme_iod *iod;
dma_addr_t meta_dma = 0;
void *meta = NULL;
void __user *metadata;
if (copy_from_user(&io, uio, sizeof(io)))
return -EFAULT;
- length = (io.nblocks + 1) << ns->lba_shift;
- meta_len = (io.nblocks + 1) * ns->ms;
-
- if (meta_len && ((io.metadata & 3) || !io.metadata) && !ns->ext)
- return -EINVAL;
- else if (meta_len && ns->ext) {
- length += meta_len;
- meta_len = 0;
- }
-
- metadata = (void __user *)(unsigned long)io.metadata;
-
- write = io.opcode & 1;
switch (io.opcode) {
case nvme_cmd_write:
case nvme_cmd_read:
case nvme_cmd_compare:
- iod = nvme_map_user_pages(dev, write, io.addr, length);
break;
default:
return -EINVAL;
}
- if (IS_ERR(iod))
- return PTR_ERR(iod);
+ length = (io.nblocks + 1) << ns->lba_shift;
+ meta_len = (io.nblocks + 1) * ns->ms;
+ metadata = (void __user *)(unsigned long)io.metadata;
+ write = io.opcode & 1;
- prp_len = nvme_setup_prps(dev, iod, length, GFP_KERNEL);
- if (length != prp_len) {
- status = -ENOMEM;
- goto unmap;
+ if (ns->ext) {
+ length += meta_len;
+ meta_len = 0;
}
if (meta_len) {
- meta = dma_alloc_coherent(&dev->pci_dev->dev, meta_len,
+ if (((io.metadata & 3) || !io.metadata) && !ns->ext)
+ return -EINVAL;
+
+ meta = dma_alloc_coherent(dev->dev, meta_len,
&meta_dma, GFP_KERNEL);
if (!meta) {
@@ -1813,19 +1784,17 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
c.rw.reftag = cpu_to_le32(io.reftag);
c.rw.apptag = cpu_to_le16(io.apptag);
c.rw.appmask = cpu_to_le16(io.appmask);
- c.rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg));
- c.rw.prp2 = cpu_to_le64(iod->first_dma);
c.rw.metadata = cpu_to_le64(meta_dma);
- status = nvme_submit_io_cmd(dev, ns, &c, NULL);
+
+ status = __nvme_submit_sync_cmd(ns->queue, &c, NULL,
+ (void __user *)io.addr, length, NULL, 0);
unmap:
- nvme_unmap_user_pages(dev, write, iod);
- nvme_free_iod(dev, iod);
if (meta) {
if (status == NVME_SC_SUCCESS && !write) {
if (copy_to_user(metadata, meta, meta_len))
status = -EFAULT;
}
- dma_free_coherent(&dev->pci_dev->dev, meta_len, meta, meta_dma);
+ dma_free_coherent(dev->dev, meta_len, meta, meta_dma);
}
return status;
}
@@ -1835,9 +1804,8 @@ static int nvme_user_cmd(struct nvme_dev *dev, struct nvme_ns *ns,
{
struct nvme_passthru_cmd cmd;
struct nvme_command c;
- int status, length;
- struct nvme_iod *uninitialized_var(iod);
- unsigned timeout;
+ unsigned timeout = 0;
+ int status;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -1857,46 +1825,17 @@ static int nvme_user_cmd(struct nvme_dev *dev, struct nvme_ns *ns,
c.common.cdw10[4] = cpu_to_le32(cmd.cdw14);
c.common.cdw10[5] = cpu_to_le32(cmd.cdw15);
- length = cmd.data_len;
- if (cmd.data_len) {
- iod = nvme_map_user_pages(dev, cmd.opcode & 1, cmd.addr,
- length);
- if (IS_ERR(iod))
- return PTR_ERR(iod);
- length = nvme_setup_prps(dev, iod, length, GFP_KERNEL);
- c.common.prp1 = cpu_to_le64(sg_dma_address(iod->sg));
- c.common.prp2 = cpu_to_le64(iod->first_dma);
- }
-
- timeout = cmd.timeout_ms ? msecs_to_jiffies(cmd.timeout_ms) :
- ADMIN_TIMEOUT;
-
- if (length != cmd.data_len)
- status = -ENOMEM;
- else if (ns) {
- struct request *req;
-
- req = blk_mq_alloc_request(ns->queue, WRITE,
- (GFP_KERNEL|__GFP_WAIT), false);
- if (IS_ERR(req))
- status = PTR_ERR(req);
- else {
- status = nvme_submit_sync_cmd(req, &c, &cmd.result,
- timeout);
- blk_mq_free_request(req);
- }
- } else
- status = __nvme_submit_admin_cmd(dev, &c, &cmd.result, timeout);
+ if (cmd.timeout_ms)
+ timeout = msecs_to_jiffies(cmd.timeout_ms);
- if (cmd.data_len) {
- nvme_unmap_user_pages(dev, cmd.opcode & 1, iod);
- nvme_free_iod(dev, iod);
+ status = __nvme_submit_sync_cmd(ns ? ns->queue : dev->admin_q, &c,
+ NULL, (void __user *)cmd.addr, cmd.data_len,
+ &cmd.result, timeout);
+ if (status >= 0) {
+ if (put_user(cmd.result, &ucmd->result))
+ return -EFAULT;
}
- if ((status >= 0) && copy_to_user(&ucmd->result, &cmd.result,
- sizeof(cmd.result)))
- status = -EFAULT;
-
return status;
}
@@ -1988,23 +1927,18 @@ static int nvme_revalidate_disk(struct gendisk *disk)
struct nvme_ns *ns = disk->private_data;
struct nvme_dev *dev = ns->dev;
struct nvme_id_ns *id;
- dma_addr_t dma_addr;
u8 lbaf, pi_type;
u16 old_ms;
unsigned short bs;
- id = dma_alloc_coherent(&dev->pci_dev->dev, 4096, &dma_addr,
- GFP_KERNEL);
- if (!id) {
- dev_warn(&dev->pci_dev->dev, "%s: Memory alocation failure\n",
- __func__);
- return 0;
+ if (nvme_identify_ns(dev, ns->ns_id, &id)) {
+ dev_warn(dev->dev, "%s: Identify failure nvme%dn%d\n", __func__,
+ dev->instance, ns->ns_id);
+ return -ENODEV;
}
- if (nvme_identify(dev, ns->ns_id, 0, dma_addr)) {
- dev_warn(&dev->pci_dev->dev,
- "identify failed ns:%d, setting capacity to 0\n",
- ns->ns_id);
- memset(id, 0, sizeof(*id));
+ if (id->ncap == 0) {
+ kfree(id);
+ return -ENODEV;
}
old_ms = ns->ms;
@@ -2038,7 +1972,7 @@ static int nvme_revalidate_disk(struct gendisk *disk)
!ns->ext)
nvme_init_integrity(ns);
- if (id->ncap == 0 || (ns->ms && !blk_get_integrity(disk)))
+ if (ns->ms && !blk_get_integrity(disk))
set_capacity(disk, 0);
else
set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
@@ -2046,7 +1980,7 @@ static int nvme_revalidate_disk(struct gendisk *disk)
if (dev->oncs & NVME_CTRL_ONCS_DSM)
nvme_config_discard(ns);
- dma_free_coherent(&dev->pci_dev->dev, 4096, id, dma_addr);
+ kfree(id);
return 0;
}
@@ -2073,7 +2007,7 @@ static int nvme_kthread(void *data)
if (work_busy(&dev->reset_work))
continue;
list_del_init(&dev->node);
- dev_warn(&dev->pci_dev->dev,
+ dev_warn(dev->dev,
"Failed status: %x, reset controller\n",
readl(&dev->bar->csts));
dev->reset_workfn = nvme_reset_failed_dev;
@@ -2105,7 +2039,7 @@ static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid)
{
struct nvme_ns *ns;
struct gendisk *disk;
- int node = dev_to_node(&dev->pci_dev->dev);
+ int node = dev_to_node(dev->dev);
ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node);
if (!ns)
@@ -2153,11 +2087,16 @@ static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid)
* requires it.
*/
set_capacity(disk, 0);
- nvme_revalidate_disk(ns->disk);
+ if (nvme_revalidate_disk(ns->disk))
+ goto out_free_disk;
+
add_disk(ns->disk);
if (ns->ms)
revalidate_disk(ns->disk);
return;
+ out_free_disk:
+ kfree(disk);
+ list_del(&ns->list);
out_free_queue:
blk_cleanup_queue(ns->queue);
out_free_ns:
@@ -2188,8 +2127,7 @@ static int set_queue_count(struct nvme_dev *dev, int count)
if (status < 0)
return status;
if (status > 0) {
- dev_err(&dev->pci_dev->dev, "Could not set queue count (%d)\n",
- status);
+ dev_err(dev->dev, "Could not set queue count (%d)\n", status);
return 0;
}
return min(result & 0xffff, result >> 16) + 1;
@@ -2203,7 +2141,7 @@ static size_t db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues)
static int nvme_setup_io_queues(struct nvme_dev *dev)
{
struct nvme_queue *adminq = dev->queues[0];
- struct pci_dev *pdev = dev->pci_dev;
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
int result, i, vecs, nr_io_queues, size;
nr_io_queues = num_possible_cpus();
@@ -2275,6 +2213,99 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
return result;
}
+static void nvme_free_namespace(struct nvme_ns *ns)
+{
+ list_del(&ns->list);
+
+ spin_lock(&dev_list_lock);
+ ns->disk->private_data = NULL;
+ spin_unlock(&dev_list_lock);
+
+ put_disk(ns->disk);
+ kfree(ns);
+}
+
+static int ns_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+ struct nvme_ns *nsa = container_of(a, struct nvme_ns, list);
+ struct nvme_ns *nsb = container_of(b, struct nvme_ns, list);
+
+ return nsa->ns_id - nsb->ns_id;
+}
+
+static struct nvme_ns *nvme_find_ns(struct nvme_dev *dev, unsigned nsid)
+{
+ struct nvme_ns *ns;
+
+ list_for_each_entry(ns, &dev->namespaces, list) {
+ if (ns->ns_id == nsid)
+ return ns;
+ if (ns->ns_id > nsid)
+ break;
+ }
+ return NULL;
+}
+
+static inline bool nvme_io_incapable(struct nvme_dev *dev)
+{
+ return (!dev->bar || readl(&dev->bar->csts) & NVME_CSTS_CFS ||
+ dev->online_queues < 2);
+}
+
+static void nvme_ns_remove(struct nvme_ns *ns)
+{
+ bool kill = nvme_io_incapable(ns->dev) && !blk_queue_dying(ns->queue);
+
+ if (kill)
+ blk_set_queue_dying(ns->queue);
+ if (ns->disk->flags & GENHD_FL_UP) {
+ if (blk_get_integrity(ns->disk))
+ blk_integrity_unregister(ns->disk);
+ del_gendisk(ns->disk);
+ }
+ if (kill || !blk_queue_dying(ns->queue)) {
+ blk_mq_abort_requeue_list(ns->queue);
+ blk_cleanup_queue(ns->queue);
+ }
+}
+
+static void nvme_scan_namespaces(struct nvme_dev *dev, unsigned nn)
+{
+ struct nvme_ns *ns, *next;
+ unsigned i;
+
+ for (i = 1; i <= nn; i++) {
+ ns = nvme_find_ns(dev, i);
+ if (ns) {
+ if (revalidate_disk(ns->disk)) {
+ nvme_ns_remove(ns);
+ nvme_free_namespace(ns);
+ }
+ } else
+ nvme_alloc_ns(dev, i);
+ }
+ list_for_each_entry_safe(ns, next, &dev->namespaces, list) {
+ if (ns->ns_id > nn) {
+ nvme_ns_remove(ns);
+ nvme_free_namespace(ns);
+ }
+ }
+ list_sort(NULL, &dev->namespaces, ns_cmp);
+}
+
+static void nvme_dev_scan(struct work_struct *work)
+{
+ struct nvme_dev *dev = container_of(work, struct nvme_dev, scan_work);
+ struct nvme_id_ctrl *ctrl;
+
+ if (!dev->tagset.tags)
+ return;
+ if (nvme_identify_ctrl(dev, &ctrl))
+ return;
+ nvme_scan_namespaces(dev, le32_to_cpup(&ctrl->nn));
+ kfree(ctrl);
+}
+
/*
* Return: error value if an error occurred setting up the queues or calling
* Identify Device. 0 if these succeeded, even if adding some of the
@@ -2283,26 +2314,18 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
*/
static int nvme_dev_add(struct nvme_dev *dev)
{
- struct pci_dev *pdev = dev->pci_dev;
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
int res;
- unsigned nn, i;
+ unsigned nn;
struct nvme_id_ctrl *ctrl;
- void *mem;
- dma_addr_t dma_addr;
int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12;
- mem = dma_alloc_coherent(&pdev->dev, 4096, &dma_addr, GFP_KERNEL);
- if (!mem)
- return -ENOMEM;
-
- res = nvme_identify(dev, 0, 1, dma_addr);
+ res = nvme_identify_ctrl(dev, &ctrl);
if (res) {
- dev_err(&pdev->dev, "Identify Controller failed (%d)\n", res);
- dma_free_coherent(&dev->pci_dev->dev, 4096, mem, dma_addr);
+ dev_err(dev->dev, "Identify Controller failed (%d)\n", res);
return -EIO;
}
- ctrl = mem;
nn = le32_to_cpup(&ctrl->nn);
dev->oncs = le16_to_cpup(&ctrl->oncs);
dev->abort_limit = ctrl->acl + 1;
@@ -2324,12 +2347,12 @@ static int nvme_dev_add(struct nvme_dev *dev)
} else
dev->max_hw_sectors = max_hw_sectors;
}
- dma_free_coherent(&dev->pci_dev->dev, 4096, mem, dma_addr);
+ kfree(ctrl);
dev->tagset.ops = &nvme_mq_ops;
dev->tagset.nr_hw_queues = dev->online_queues - 1;
dev->tagset.timeout = NVME_IO_TIMEOUT;
- dev->tagset.numa_node = dev_to_node(&dev->pci_dev->dev);
+ dev->tagset.numa_node = dev_to_node(dev->dev);
dev->tagset.queue_depth =
min_t(int, dev->q_depth, BLK_MQ_MAX_DEPTH) - 1;
dev->tagset.cmd_size = nvme_cmd_size(dev);
@@ -2339,9 +2362,7 @@ static int nvme_dev_add(struct nvme_dev *dev)
if (blk_mq_alloc_tag_set(&dev->tagset))
return 0;
- for (i = 1; i <= nn; i++)
- nvme_alloc_ns(dev, i);
-
+ schedule_work(&dev->scan_work);
return 0;
}
@@ -2349,7 +2370,7 @@ static int nvme_dev_map(struct nvme_dev *dev)
{
u64 cap;
int bars, result = -ENOMEM;
- struct pci_dev *pdev = dev->pci_dev;
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
if (pci_enable_device_mem(pdev))
return result;
@@ -2363,8 +2384,8 @@ static int nvme_dev_map(struct nvme_dev *dev)
if (pci_request_selected_regions(pdev, bars, "nvme"))
goto disable_pci;
- if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) &&
- dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))
+ if (dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64)) &&
+ dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(32)))
goto disable;
dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
@@ -2405,19 +2426,21 @@ static int nvme_dev_map(struct nvme_dev *dev)
static void nvme_dev_unmap(struct nvme_dev *dev)
{
- if (dev->pci_dev->msi_enabled)
- pci_disable_msi(dev->pci_dev);
- else if (dev->pci_dev->msix_enabled)
- pci_disable_msix(dev->pci_dev);
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+
+ if (pdev->msi_enabled)
+ pci_disable_msi(pdev);
+ else if (pdev->msix_enabled)
+ pci_disable_msix(pdev);
if (dev->bar) {
iounmap(dev->bar);
dev->bar = NULL;
- pci_release_regions(dev->pci_dev);
+ pci_release_regions(pdev);
}
- if (pci_is_enabled(dev->pci_dev))
- pci_disable_device(dev->pci_dev);
+ if (pci_is_enabled(pdev))
+ pci_disable_device(pdev);
}
struct nvme_delq_ctx {
@@ -2536,7 +2559,7 @@ static void nvme_disable_io_queues(struct nvme_dev *dev)
&worker, "nvme%d", dev->instance);
if (IS_ERR(kworker_task)) {
- dev_err(&dev->pci_dev->dev,
+ dev_err(dev->dev,
"Failed to create queue del task\n");
for (i = dev->queue_count - 1; i > 0; i--)
nvme_disable_queue(dev, i);
@@ -2587,9 +2610,9 @@ static void nvme_freeze_queues(struct nvme_dev *dev)
list_for_each_entry(ns, &dev->namespaces, list) {
blk_mq_freeze_queue_start(ns->queue);
- spin_lock(ns->queue->queue_lock);
+ spin_lock_irq(ns->queue->queue_lock);
queue_flag_set(QUEUE_FLAG_STOPPED, ns->queue);
- spin_unlock(ns->queue->queue_lock);
+ spin_unlock_irq(ns->queue->queue_lock);
blk_mq_cancel_requeue_work(ns->queue);
blk_mq_stop_hw_queues(ns->queue);
@@ -2639,29 +2662,19 @@ static void nvme_dev_remove(struct nvme_dev *dev)
{
struct nvme_ns *ns;
- list_for_each_entry(ns, &dev->namespaces, list) {
- if (ns->disk->flags & GENHD_FL_UP) {
- if (blk_get_integrity(ns->disk))
- blk_integrity_unregister(ns->disk);
- del_gendisk(ns->disk);
- }
- if (!blk_queue_dying(ns->queue)) {
- blk_mq_abort_requeue_list(ns->queue);
- blk_cleanup_queue(ns->queue);
- }
- }
+ list_for_each_entry(ns, &dev->namespaces, list)
+ nvme_ns_remove(ns);
}
static int nvme_setup_prp_pools(struct nvme_dev *dev)
{
- struct device *dmadev = &dev->pci_dev->dev;
- dev->prp_page_pool = dma_pool_create("prp list page", dmadev,
+ dev->prp_page_pool = dma_pool_create("prp list page", dev->dev,
PAGE_SIZE, PAGE_SIZE, 0);
if (!dev->prp_page_pool)
return -ENOMEM;
/* Optimisation for I/Os between 4k and 128k */
- dev->prp_small_pool = dma_pool_create("prp list 256", dmadev,
+ dev->prp_small_pool = dma_pool_create("prp list 256", dev->dev,
256, 256, 0);
if (!dev->prp_small_pool) {
dma_pool_destroy(dev->prp_page_pool);
@@ -2709,23 +2722,15 @@ static void nvme_free_namespaces(struct nvme_dev *dev)
{
struct nvme_ns *ns, *next;
- list_for_each_entry_safe(ns, next, &dev->namespaces, list) {
- list_del(&ns->list);
-
- spin_lock(&dev_list_lock);
- ns->disk->private_data = NULL;
- spin_unlock(&dev_list_lock);
-
- put_disk(ns->disk);
- kfree(ns);
- }
+ list_for_each_entry_safe(ns, next, &dev->namespaces, list)
+ nvme_free_namespace(ns);
}
static void nvme_free_dev(struct kref *kref)
{
struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref);
- pci_dev_put(dev->pci_dev);
+ put_device(dev->dev);
put_device(dev->device);
nvme_free_namespaces(dev);
nvme_release_instance(dev);
@@ -2781,6 +2786,9 @@ static long nvme_dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
return -ENOTTY;
ns = list_first_entry(&dev->namespaces, struct nvme_ns, list);
return nvme_user_cmd(dev, ns, (void __user *)arg);
+ case NVME_IOCTL_RESET:
+ dev_warn(dev->dev, "resetting controller\n");
+ return nvme_reset(dev);
default:
return -ENOTTY;
}
@@ -2802,11 +2810,11 @@ static void nvme_set_irq_hints(struct nvme_dev *dev)
for (i = 0; i < dev->online_queues; i++) {
nvmeq = dev->queues[i];
- if (!nvmeq->hctx)
+ if (!nvmeq->tags || !(*nvmeq->tags))
continue;
irq_set_affinity_hint(dev->entry[nvmeq->cq_vector].vector,
- nvmeq->hctx->cpumask);
+ blk_mq_tags_cpumask(*nvmeq->tags));
}
}
@@ -2869,7 +2877,7 @@ static int nvme_dev_start(struct nvme_dev *dev)
static int nvme_remove_dead_ctrl(void *arg)
{
struct nvme_dev *dev = (struct nvme_dev *)arg;
- struct pci_dev *pdev = dev->pci_dev;
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
if (pci_get_drvdata(pdev))
pci_stop_and_remove_bus_device_locked(pdev);
@@ -2899,6 +2907,7 @@ static int nvme_dev_resume(struct nvme_dev *dev)
spin_unlock(&dev_list_lock);
} else {
nvme_unfreeze_queues(dev);
+ schedule_work(&dev->scan_work);
nvme_set_irq_hints(dev);
}
return 0;
@@ -2908,11 +2917,11 @@ static void nvme_dev_reset(struct nvme_dev *dev)
{
nvme_dev_shutdown(dev);
if (nvme_dev_resume(dev)) {
- dev_warn(&dev->pci_dev->dev, "Device failed to resume\n");
+ dev_warn(dev->dev, "Device failed to resume\n");
kref_get(&dev->kref);
if (IS_ERR(kthread_run(nvme_remove_dead_ctrl, dev, "nvme%d",
dev->instance))) {
- dev_err(&dev->pci_dev->dev,
+ dev_err(dev->dev,
"Failed to start controller remove task\n");
kref_put(&dev->kref, nvme_free_dev);
}
@@ -2931,6 +2940,44 @@ static void nvme_reset_workfn(struct work_struct *work)
dev->reset_workfn(work);
}
+static int nvme_reset(struct nvme_dev *dev)
+{
+ int ret = -EBUSY;
+
+ if (!dev->admin_q || blk_queue_dying(dev->admin_q))
+ return -ENODEV;
+
+ spin_lock(&dev_list_lock);
+ if (!work_pending(&dev->reset_work)) {
+ dev->reset_workfn = nvme_reset_failed_dev;
+ queue_work(nvme_workq, &dev->reset_work);
+ ret = 0;
+ }
+ spin_unlock(&dev_list_lock);
+
+ if (!ret) {
+ flush_work(&dev->reset_work);
+ return 0;
+ }
+
+ return ret;
+}
+
+static ssize_t nvme_sysfs_reset(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct nvme_dev *ndev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = nvme_reset(ndev);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+static DEVICE_ATTR(reset_controller, S_IWUSR, NULL, nvme_sysfs_reset);
+
static void nvme_async_probe(struct work_struct *work);
static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
@@ -2956,7 +3003,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&dev->namespaces);
dev->reset_workfn = nvme_reset_failed_dev;
INIT_WORK(&dev->reset_work, nvme_reset_workfn);
- dev->pci_dev = pci_dev_get(pdev);
+ dev->dev = get_device(&pdev->dev);
pci_set_drvdata(pdev, dev);
result = nvme_set_instance(dev);
if (result)
@@ -2975,18 +3022,27 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto release_pools;
}
get_device(dev->device);
+ dev_set_drvdata(dev->device, dev);
+
+ result = device_create_file(dev->device, &dev_attr_reset_controller);
+ if (result)
+ goto put_dev;
INIT_LIST_HEAD(&dev->node);
+ INIT_WORK(&dev->scan_work, nvme_dev_scan);
INIT_WORK(&dev->probe_work, nvme_async_probe);
schedule_work(&dev->probe_work);
return 0;
+ put_dev:
+ device_destroy(nvme_class, MKDEV(nvme_char_major, dev->instance));
+ put_device(dev->device);
release_pools:
nvme_release_prp_pools(dev);
release:
nvme_release_instance(dev);
put_pci:
- pci_dev_put(dev->pci_dev);
+ put_device(dev->dev);
free:
kfree(dev->queues);
kfree(dev->entry);
@@ -3011,10 +3067,12 @@ static void nvme_async_probe(struct work_struct *work)
nvme_set_irq_hints(dev);
return;
reset:
+ spin_lock(&dev_list_lock);
if (!work_busy(&dev->reset_work)) {
dev->reset_workfn = nvme_reset_failed_dev;
queue_work(nvme_workq, &dev->reset_work);
}
+ spin_unlock(&dev_list_lock);
}
static void nvme_reset_notify(struct pci_dev *pdev, bool prepare)
@@ -3044,6 +3102,8 @@ static void nvme_remove(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
flush_work(&dev->probe_work);
flush_work(&dev->reset_work);
+ flush_work(&dev->scan_work);
+ device_remove_file(dev->device, &dev_attr_reset_controller);
nvme_dev_shutdown(dev);
nvme_dev_remove(dev);
nvme_dev_remove_admin(dev);
diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c
index 44f2514fb775..e5a63f06fb0f 100644
--- a/drivers/block/nvme-scsi.c
+++ b/drivers/block/nvme-scsi.c
@@ -41,15 +41,13 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <asm/unaligned.h>
#include <scsi/sg.h>
#include <scsi/scsi.h>
static int sg_version_num = 30534; /* 2 digits for each component */
-#define SNTI_TRANSLATION_SUCCESS 0
-#define SNTI_INTERNAL_ERROR 1
-
/* VPD Page Codes */
#define VPD_SUPPORTED_PAGES 0x00
#define VPD_SERIAL_NUMBER 0x80
@@ -58,49 +56,14 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#define VPD_BLOCK_LIMITS 0xB0
#define VPD_BLOCK_DEV_CHARACTERISTICS 0xB1
-/* CDB offsets */
-#define REPORT_LUNS_CDB_ALLOC_LENGTH_OFFSET 6
-#define REPORT_LUNS_SR_OFFSET 2
-#define READ_CAP_16_CDB_ALLOC_LENGTH_OFFSET 10
-#define REQUEST_SENSE_CDB_ALLOC_LENGTH_OFFSET 4
-#define REQUEST_SENSE_DESC_OFFSET 1
-#define REQUEST_SENSE_DESC_MASK 0x01
-#define DESCRIPTOR_FORMAT_SENSE_DATA_TYPE 1
-#define INQUIRY_EVPD_BYTE_OFFSET 1
-#define INQUIRY_PAGE_CODE_BYTE_OFFSET 2
-#define INQUIRY_EVPD_BIT_MASK 1
-#define INQUIRY_CDB_ALLOCATION_LENGTH_OFFSET 3
-#define START_STOP_UNIT_CDB_IMMED_OFFSET 1
-#define START_STOP_UNIT_CDB_IMMED_MASK 0x1
-#define START_STOP_UNIT_CDB_POWER_COND_MOD_OFFSET 3
-#define START_STOP_UNIT_CDB_POWER_COND_MOD_MASK 0xF
-#define START_STOP_UNIT_CDB_POWER_COND_OFFSET 4
-#define START_STOP_UNIT_CDB_POWER_COND_MASK 0xF0
-#define START_STOP_UNIT_CDB_NO_FLUSH_OFFSET 4
-#define START_STOP_UNIT_CDB_NO_FLUSH_MASK 0x4
-#define START_STOP_UNIT_CDB_START_OFFSET 4
-#define START_STOP_UNIT_CDB_START_MASK 0x1
-#define WRITE_BUFFER_CDB_MODE_OFFSET 1
-#define WRITE_BUFFER_CDB_MODE_MASK 0x1F
-#define WRITE_BUFFER_CDB_BUFFER_ID_OFFSET 2
-#define WRITE_BUFFER_CDB_BUFFER_OFFSET_OFFSET 3
-#define WRITE_BUFFER_CDB_PARM_LIST_LENGTH_OFFSET 6
-#define FORMAT_UNIT_CDB_FORMAT_PROT_INFO_OFFSET 1
-#define FORMAT_UNIT_CDB_FORMAT_PROT_INFO_MASK 0xC0
-#define FORMAT_UNIT_CDB_FORMAT_PROT_INFO_SHIFT 6
-#define FORMAT_UNIT_CDB_LONG_LIST_OFFSET 1
-#define FORMAT_UNIT_CDB_LONG_LIST_MASK 0x20
-#define FORMAT_UNIT_CDB_FORMAT_DATA_OFFSET 1
-#define FORMAT_UNIT_CDB_FORMAT_DATA_MASK 0x10
+/* format unit paramter list offsets */
#define FORMAT_UNIT_SHORT_PARM_LIST_LEN 4
#define FORMAT_UNIT_LONG_PARM_LIST_LEN 8
#define FORMAT_UNIT_PROT_INT_OFFSET 3
#define FORMAT_UNIT_PROT_FIELD_USAGE_OFFSET 0
#define FORMAT_UNIT_PROT_FIELD_USAGE_MASK 0x07
-#define UNMAP_CDB_PARAM_LIST_LENGTH_OFFSET 7
/* Misc. defines */
-#define NIBBLE_SHIFT 4
#define FIXED_SENSE_DATA 0x70
#define DESC_FORMAT_SENSE_DATA 0x72
#define FIXED_SENSE_DATA_ADD_LENGTH 10
@@ -144,27 +107,6 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#define EXTENDED_INQUIRY_DATA_PAGE_LENGTH 0x3C
#define RESERVED_FIELD 0
-/* SCSI READ/WRITE Defines */
-#define IO_CDB_WP_MASK 0xE0
-#define IO_CDB_WP_SHIFT 5
-#define IO_CDB_FUA_MASK 0x8
-#define IO_6_CDB_LBA_OFFSET 0
-#define IO_6_CDB_LBA_MASK 0x001FFFFF
-#define IO_6_CDB_TX_LEN_OFFSET 4
-#define IO_6_DEFAULT_TX_LEN 256
-#define IO_10_CDB_LBA_OFFSET 2
-#define IO_10_CDB_TX_LEN_OFFSET 7
-#define IO_10_CDB_WP_OFFSET 1
-#define IO_10_CDB_FUA_OFFSET 1
-#define IO_12_CDB_LBA_OFFSET 2
-#define IO_12_CDB_TX_LEN_OFFSET 6
-#define IO_12_CDB_WP_OFFSET 1
-#define IO_12_CDB_FUA_OFFSET 1
-#define IO_16_CDB_FUA_OFFSET 1
-#define IO_16_CDB_WP_OFFSET 1
-#define IO_16_CDB_LBA_OFFSET 2
-#define IO_16_CDB_TX_LEN_OFFSET 10
-
/* Mode Sense/Select defines */
#define MODE_PAGE_INFO_EXCEP 0x1C
#define MODE_PAGE_CACHING 0x08
@@ -179,23 +121,14 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#define MODE_PAGE_INF_EXC_LEN 0x0C
#define MODE_PAGE_ALL_LEN 0x54
#define MODE_SENSE6_MPH_SIZE 4
-#define MODE_SENSE6_ALLOC_LEN_OFFSET 4
-#define MODE_SENSE_PAGE_CONTROL_OFFSET 2
#define MODE_SENSE_PAGE_CONTROL_MASK 0xC0
#define MODE_SENSE_PAGE_CODE_OFFSET 2
#define MODE_SENSE_PAGE_CODE_MASK 0x3F
-#define MODE_SENSE_LLBAA_OFFSET 1
#define MODE_SENSE_LLBAA_MASK 0x10
#define MODE_SENSE_LLBAA_SHIFT 4
-#define MODE_SENSE_DBD_OFFSET 1
#define MODE_SENSE_DBD_MASK 8
#define MODE_SENSE_DBD_SHIFT 3
#define MODE_SENSE10_MPH_SIZE 8
-#define MODE_SENSE10_ALLOC_LEN_OFFSET 7
-#define MODE_SELECT_CDB_PAGE_FORMAT_OFFSET 1
-#define MODE_SELECT_CDB_SAVE_PAGES_OFFSET 1
-#define MODE_SELECT_6_CDB_PARAM_LIST_LENGTH_OFFSET 4
-#define MODE_SELECT_10_CDB_PARAM_LIST_LENGTH_OFFSET 7
#define MODE_SELECT_CDB_PAGE_FORMAT_MASK 0x10
#define MODE_SELECT_CDB_SAVE_PAGES_MASK 0x1
#define MODE_SELECT_6_BD_OFFSET 3
@@ -221,14 +154,11 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#define LOG_PAGE_SUPPORTED_LOG_PAGES_LENGTH 0x07
#define LOG_PAGE_INFORMATIONAL_EXCEPTIONS_PAGE 0x2F
#define LOG_PAGE_TEMPERATURE_PAGE 0x0D
-#define LOG_SENSE_CDB_SP_OFFSET 1
#define LOG_SENSE_CDB_SP_NOT_ENABLED 0
-#define LOG_SENSE_CDB_PC_OFFSET 2
#define LOG_SENSE_CDB_PC_MASK 0xC0
#define LOG_SENSE_CDB_PC_SHIFT 6
#define LOG_SENSE_CDB_PC_CUMULATIVE_VALUES 1
#define LOG_SENSE_CDB_PAGE_CODE_MASK 0x3F
-#define LOG_SENSE_CDB_ALLOC_LENGTH_OFFSET 7
#define REMAINING_INFO_EXCP_PAGE_LENGTH 0x8
#define LOG_INFO_EXCP_PAGE_LENGTH 0xC
#define REMAINING_TEMP_PAGE_LENGTH 0xC
@@ -278,77 +208,11 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#define SCSI_ASCQ_POWER_LOSS_EXPECTED 0x08
#define SCSI_ASCQ_INVALID_LUN_ID 0x09
-/**
- * DEVICE_SPECIFIC_PARAMETER in mode parameter header (see sbc2r16) to
- * enable DPOFUA support type 0x10 value.
- */
-#define DEVICE_SPECIFIC_PARAMETER 0
-#define VPD_ID_DESCRIPTOR_LENGTH sizeof(VPD_IDENTIFICATION_DESCRIPTOR)
-
-/* MACROs to extract information from CDBs */
-
-#define GET_OPCODE(cdb) cdb[0]
-
-#define GET_U8_FROM_CDB(cdb, index) (cdb[index] << 0)
-
-#define GET_U16_FROM_CDB(cdb, index) ((cdb[index] << 8) | (cdb[index + 1] << 0))
-
-#define GET_U24_FROM_CDB(cdb, index) ((cdb[index] << 16) | \
-(cdb[index + 1] << 8) | \
-(cdb[index + 2] << 0))
-
-#define GET_U32_FROM_CDB(cdb, index) ((cdb[index] << 24) | \
-(cdb[index + 1] << 16) | \
-(cdb[index + 2] << 8) | \
-(cdb[index + 3] << 0))
-
-#define GET_U64_FROM_CDB(cdb, index) ((((u64)cdb[index]) << 56) | \
-(((u64)cdb[index + 1]) << 48) | \
-(((u64)cdb[index + 2]) << 40) | \
-(((u64)cdb[index + 3]) << 32) | \
-(((u64)cdb[index + 4]) << 24) | \
-(((u64)cdb[index + 5]) << 16) | \
-(((u64)cdb[index + 6]) << 8) | \
-(((u64)cdb[index + 7]) << 0))
-
-/* Inquiry Helper Macros */
-#define GET_INQ_EVPD_BIT(cdb) \
-((GET_U8_FROM_CDB(cdb, INQUIRY_EVPD_BYTE_OFFSET) & \
-INQUIRY_EVPD_BIT_MASK) ? 1 : 0)
-
-#define GET_INQ_PAGE_CODE(cdb) \
-(GET_U8_FROM_CDB(cdb, INQUIRY_PAGE_CODE_BYTE_OFFSET))
-
-#define GET_INQ_ALLOC_LENGTH(cdb) \
-(GET_U16_FROM_CDB(cdb, INQUIRY_CDB_ALLOCATION_LENGTH_OFFSET))
-
-/* Report LUNs Helper Macros */
-#define GET_REPORT_LUNS_ALLOC_LENGTH(cdb) \
-(GET_U32_FROM_CDB(cdb, REPORT_LUNS_CDB_ALLOC_LENGTH_OFFSET))
-
-/* Read Capacity Helper Macros */
-#define GET_READ_CAP_16_ALLOC_LENGTH(cdb) \
-(GET_U32_FROM_CDB(cdb, READ_CAP_16_CDB_ALLOC_LENGTH_OFFSET))
-
-#define IS_READ_CAP_16(cdb) \
-((cdb[0] == SERVICE_ACTION_IN_16 && cdb[1] == SAI_READ_CAPACITY_16) ? 1 : 0)
-
-/* Request Sense Helper Macros */
-#define GET_REQUEST_SENSE_ALLOC_LENGTH(cdb) \
-(GET_U8_FROM_CDB(cdb, REQUEST_SENSE_CDB_ALLOC_LENGTH_OFFSET))
-
-/* Mode Sense Helper Macros */
-#define GET_MODE_SENSE_DBD(cdb) \
-((GET_U8_FROM_CDB(cdb, MODE_SENSE_DBD_OFFSET) & MODE_SENSE_DBD_MASK) >> \
-MODE_SENSE_DBD_SHIFT)
-
-#define GET_MODE_SENSE_LLBAA(cdb) \
-((GET_U8_FROM_CDB(cdb, MODE_SENSE_LLBAA_OFFSET) & \
-MODE_SENSE_LLBAA_MASK) >> MODE_SENSE_LLBAA_SHIFT)
-
-#define GET_MODE_SENSE_MPH_SIZE(cdb10) \
-(cdb10 ? MODE_SENSE10_MPH_SIZE : MODE_SENSE6_MPH_SIZE)
-
+/* copied from drivers/usb/gadget/function/storage_common.h */
+static inline u32 get_unaligned_be24(u8 *buf)
+{
+ return 0xffffff & (u32) get_unaligned_be32(buf - 1);
+}
/* Struct to gather data that needs to be extracted from a SCSI CDB.
Not conforming to any particular CDB variant, but compatible with all. */
@@ -369,8 +233,6 @@ struct nvme_trans_io_cdb {
static int nvme_trans_copy_to_user(struct sg_io_hdr *hdr, void *from,
unsigned long n)
{
- int res = SNTI_TRANSLATION_SUCCESS;
- unsigned long not_copied;
int i;
void *index = from;
size_t remaining = n;
@@ -380,29 +242,25 @@ static int nvme_trans_copy_to_user(struct sg_io_hdr *hdr, void *from,
struct sg_iovec sgl;
for (i = 0; i < hdr->iovec_count; i++) {
- not_copied = copy_from_user(&sgl, hdr->dxferp +
+ if (copy_from_user(&sgl, hdr->dxferp +
i * sizeof(struct sg_iovec),
- sizeof(struct sg_iovec));
- if (not_copied)
+ sizeof(struct sg_iovec)))
return -EFAULT;
xfer_len = min(remaining, sgl.iov_len);
- not_copied = copy_to_user(sgl.iov_base, index,
- xfer_len);
- if (not_copied) {
- res = -EFAULT;
- break;
- }
+ if (copy_to_user(sgl.iov_base, index, xfer_len))
+ return -EFAULT;
+
index += xfer_len;
remaining -= xfer_len;
if (remaining == 0)
break;
}
- return res;
+ return 0;
}
- not_copied = copy_to_user(hdr->dxferp, from, n);
- if (not_copied)
- res = -EFAULT;
- return res;
+
+ if (copy_to_user(hdr->dxferp, from, n))
+ return -EFAULT;
+ return 0;
}
/* Copy data from userspace memory */
@@ -410,8 +268,6 @@ static int nvme_trans_copy_to_user(struct sg_io_hdr *hdr, void *from,
static int nvme_trans_copy_from_user(struct sg_io_hdr *hdr, void *to,
unsigned long n)
{
- int res = SNTI_TRANSLATION_SUCCESS;
- unsigned long not_copied;
int i;
void *index = to;
size_t remaining = n;
@@ -421,30 +277,24 @@ static int nvme_trans_copy_from_user(struct sg_io_hdr *hdr, void *to,
struct sg_iovec sgl;
for (i = 0; i < hdr->iovec_count; i++) {
- not_copied = copy_from_user(&sgl, hdr->dxferp +
+ if (copy_from_user(&sgl, hdr->dxferp +
i * sizeof(struct sg_iovec),
- sizeof(struct sg_iovec));
- if (not_copied)
+ sizeof(struct sg_iovec)))
return -EFAULT;
xfer_len = min(remaining, sgl.iov_len);
- not_copied = copy_from_user(index, sgl.iov_base,
- xfer_len);
- if (not_copied) {
- res = -EFAULT;
- break;
- }
+ if (copy_from_user(index, sgl.iov_base, xfer_len))
+ return -EFAULT;
index += xfer_len;
remaining -= xfer_len;
if (remaining == 0)
break;
}
- return res;
+ return 0;
}
- not_copied = copy_from_user(to, hdr->dxferp, n);
- if (not_copied)
- res = -EFAULT;
- return res;
+ if (copy_from_user(to, hdr->dxferp, n))
+ return -EFAULT;
+ return 0;
}
/* Status/Sense Buffer Writeback */
@@ -452,7 +302,6 @@ static int nvme_trans_copy_from_user(struct sg_io_hdr *hdr, void *to,
static int nvme_trans_completion(struct sg_io_hdr *hdr, u8 status, u8 sense_key,
u8 asc, u8 ascq)
{
- int res = SNTI_TRANSLATION_SUCCESS;
u8 xfer_len;
u8 resp[DESC_FMT_SENSE_DATA_SIZE];
@@ -477,25 +326,29 @@ static int nvme_trans_completion(struct sg_io_hdr *hdr, u8 status, u8 sense_key,
xfer_len = min_t(u8, hdr->mx_sb_len, DESC_FMT_SENSE_DATA_SIZE);
hdr->sb_len_wr = xfer_len;
if (copy_to_user(hdr->sbp, resp, xfer_len) > 0)
- res = -EFAULT;
+ return -EFAULT;
}
- return res;
+ return 0;
}
+/*
+ * Take a status code from a lowlevel routine, and if it was a positive NVMe
+ * error code update the sense data based on it. In either case the passed
+ * in value is returned again, unless an -EFAULT from copy_to_user overrides
+ * it.
+ */
static int nvme_trans_status_code(struct sg_io_hdr *hdr, int nvme_sc)
{
u8 status, sense_key, asc, ascq;
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
/* For non-nvme (Linux) errors, simply return the error code */
if (nvme_sc < 0)
return nvme_sc;
/* Mask DNR, More, and reserved fields */
- nvme_sc &= 0x7FF;
-
- switch (nvme_sc) {
+ switch (nvme_sc & 0x7FF) {
/* Generic Command Status */
case NVME_SC_SUCCESS:
status = SAM_STAT_GOOD;
@@ -662,8 +515,7 @@ static int nvme_trans_status_code(struct sg_io_hdr *hdr, int nvme_sc)
}
res = nvme_trans_completion(hdr, status, sense_key, asc, ascq);
-
- return res;
+ return res ? res : nvme_sc;
}
/* INQUIRY Helper Functions */
@@ -673,10 +525,8 @@ static int nvme_trans_standard_inquiry_page(struct nvme_ns *ns,
int alloc_len)
{
struct nvme_dev *dev = ns->dev;
- dma_addr_t dma_addr;
- void *mem;
struct nvme_id_ns *id_ns;
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int nvme_sc;
int xfer_len;
u8 resp_data_format = 0x02;
@@ -684,31 +534,17 @@ static int nvme_trans_standard_inquiry_page(struct nvme_ns *ns,
u8 cmdque = 0x01 << 1;
u8 fw_offset = sizeof(dev->firmware_rev);
- mem = dma_alloc_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns),
- &dma_addr, GFP_KERNEL);
- if (mem == NULL) {
- res = -ENOMEM;
- goto out_dma;
- }
-
/* nvme ns identify - use DPS value for PROTECT field */
- nvme_sc = nvme_identify(dev, ns->ns_id, 0, dma_addr);
+ nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
res = nvme_trans_status_code(hdr, nvme_sc);
- /*
- * If nvme_sc was -ve, res will be -ve here.
- * If nvme_sc was +ve, the status would bace been translated, and res
- * can only be 0 or -ve.
- * - If 0 && nvme_sc > 0, then go into next if where res gets nvme_sc
- * - If -ve, return because its a Linux error.
- */
if (res)
- goto out_free;
- if (nvme_sc) {
- res = nvme_sc;
- goto out_free;
- }
- id_ns = mem;
- (id_ns->dps) ? (protect = 0x01) : (protect = 0);
+ return res;
+
+ if (id_ns->dps)
+ protect = 0x01;
+ else
+ protect = 0;
+ kfree(id_ns);
memset(inq_response, 0, STANDARD_INQUIRY_LENGTH);
inq_response[2] = VERSION_SPC_4;
@@ -725,20 +561,13 @@ static int nvme_trans_standard_inquiry_page(struct nvme_ns *ns,
strncpy(&inq_response[32], dev->firmware_rev + fw_offset, 4);
xfer_len = min(alloc_len, STANDARD_INQUIRY_LENGTH);
- res = nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
-
- out_free:
- dma_free_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns), mem,
- dma_addr);
- out_dma:
- return res;
+ return nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
}
static int nvme_trans_supported_vpd_pages(struct nvme_ns *ns,
struct sg_io_hdr *hdr, u8 *inq_response,
int alloc_len)
{
- int res = SNTI_TRANSLATION_SUCCESS;
int xfer_len;
memset(inq_response, 0, STANDARD_INQUIRY_LENGTH);
@@ -752,9 +581,7 @@ static int nvme_trans_supported_vpd_pages(struct nvme_ns *ns,
inq_response[9] = INQ_BDEV_LIMITS_PAGE;
xfer_len = min(alloc_len, STANDARD_INQUIRY_LENGTH);
- res = nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
-
- return res;
+ return nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
}
static int nvme_trans_unit_serial_page(struct nvme_ns *ns,
@@ -762,7 +589,6 @@ static int nvme_trans_unit_serial_page(struct nvme_ns *ns,
int alloc_len)
{
struct nvme_dev *dev = ns->dev;
- int res = SNTI_TRANSLATION_SUCCESS;
int xfer_len;
memset(inq_response, 0, STANDARD_INQUIRY_LENGTH);
@@ -771,53 +597,42 @@ static int nvme_trans_unit_serial_page(struct nvme_ns *ns,
strncpy(&inq_response[4], dev->serial, INQ_SERIAL_NUMBER_LENGTH);
xfer_len = min(alloc_len, STANDARD_INQUIRY_LENGTH);
- res = nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
-
- return res;
+ return nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
}
static int nvme_trans_device_id_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *inq_response, int alloc_len)
{
struct nvme_dev *dev = ns->dev;
- dma_addr_t dma_addr;
- void *mem;
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int nvme_sc;
int xfer_len;
__be32 tmp_id = cpu_to_be32(ns->ns_id);
- mem = dma_alloc_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns),
- &dma_addr, GFP_KERNEL);
- if (mem == NULL) {
- res = -ENOMEM;
- goto out_dma;
- }
-
memset(inq_response, 0, alloc_len);
inq_response[1] = INQ_DEVICE_IDENTIFICATION_PAGE; /* Page Code */
if (readl(&dev->bar->vs) >= NVME_VS(1, 1)) {
- struct nvme_id_ns *id_ns = mem;
- void *eui = id_ns->eui64;
- int len = sizeof(id_ns->eui64);
+ struct nvme_id_ns *id_ns;
+ void *eui;
+ int len;
- nvme_sc = nvme_identify(dev, ns->ns_id, 0, dma_addr);
+ nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
res = nvme_trans_status_code(hdr, nvme_sc);
if (res)
- goto out_free;
- if (nvme_sc) {
- res = nvme_sc;
- goto out_free;
- }
+ return res;
+ eui = id_ns->eui64;
+ len = sizeof(id_ns->eui64);
if (readl(&dev->bar->vs) >= NVME_VS(1, 2)) {
if (bitmap_empty(eui, len * 8)) {
eui = id_ns->nguid;
len = sizeof(id_ns->nguid);
}
}
- if (bitmap_empty(eui, len * 8))
+ if (bitmap_empty(eui, len * 8)) {
+ kfree(id_ns);
goto scsi_string;
+ }
inq_response[3] = 4 + len; /* Page Length */
/* Designation Descriptor start */
@@ -826,14 +641,14 @@ static int nvme_trans_device_id_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
inq_response[6] = 0x00; /* Rsvd */
inq_response[7] = len; /* Designator Length */
memcpy(&inq_response[8], eui, len);
+ kfree(id_ns);
} else {
scsi_string:
if (alloc_len < 72) {
- res = nvme_trans_completion(hdr,
+ return nvme_trans_completion(hdr,
SAM_STAT_CHECK_CONDITION,
ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
- goto out_free;
}
inq_response[3] = 0x48; /* Page Length */
/* Designation Descriptor start */
@@ -842,30 +657,22 @@ static int nvme_trans_device_id_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
inq_response[6] = 0x00; /* Rsvd */
inq_response[7] = 0x44; /* Designator Length */
- sprintf(&inq_response[8], "%04x", dev->pci_dev->vendor);
+ sprintf(&inq_response[8], "%04x", to_pci_dev(dev->dev)->vendor);
memcpy(&inq_response[12], dev->model, sizeof(dev->model));
sprintf(&inq_response[52], "%04x", tmp_id);
memcpy(&inq_response[56], dev->serial, sizeof(dev->serial));
}
xfer_len = alloc_len;
- res = nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
-
- out_free:
- dma_free_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns), mem,
- dma_addr);
- out_dma:
- return res;
+ return nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
}
static int nvme_trans_ext_inq_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
int alloc_len)
{
u8 *inq_response;
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int nvme_sc;
struct nvme_dev *dev = ns->dev;
- dma_addr_t dma_addr;
- void *mem;
struct nvme_id_ctrl *id_ctrl;
struct nvme_id_ns *id_ns;
int xfer_len;
@@ -878,45 +685,32 @@ static int nvme_trans_ext_inq_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 luiclr = 0x01;
inq_response = kmalloc(EXTENDED_INQUIRY_DATA_PAGE_LENGTH, GFP_KERNEL);
- if (inq_response == NULL) {
- res = -ENOMEM;
- goto out_mem;
- }
-
- mem = dma_alloc_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns),
- &dma_addr, GFP_KERNEL);
- if (mem == NULL) {
- res = -ENOMEM;
- goto out_dma;
- }
+ if (inq_response == NULL)
+ return -ENOMEM;
- /* nvme ns identify */
- nvme_sc = nvme_identify(dev, ns->ns_id, 0, dma_addr);
+ nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
res = nvme_trans_status_code(hdr, nvme_sc);
if (res)
- goto out_free;
- if (nvme_sc) {
- res = nvme_sc;
- goto out_free;
- }
- id_ns = mem;
- spt = spt_lut[(id_ns->dpc) & 0x07] << 3;
- (id_ns->dps) ? (protect = 0x01) : (protect = 0);
+ goto out_free_inq;
+
+ spt = spt_lut[id_ns->dpc & 0x07] << 3;
+ if (id_ns->dps)
+ protect = 0x01;
+ else
+ protect = 0;
+ kfree(id_ns);
+
grd_chk = protect << 2;
app_chk = protect << 1;
ref_chk = protect;
- /* nvme controller identify */
- nvme_sc = nvme_identify(dev, 0, 1, dma_addr);
+ nvme_sc = nvme_identify_ctrl(dev, &id_ctrl);
res = nvme_trans_status_code(hdr, nvme_sc);
if (res)
- goto out_free;
- if (nvme_sc) {
- res = nvme_sc;
- goto out_free;
- }
- id_ctrl = mem;
+ goto out_free_inq;
+
v_sup = id_ctrl->vwc;
+ kfree(id_ctrl);
memset(inq_response, 0, EXTENDED_INQUIRY_DATA_PAGE_LENGTH);
inq_response[1] = INQ_EXTENDED_INQUIRY_DATA_PAGE; /* Page Code */
@@ -932,12 +726,8 @@ static int nvme_trans_ext_inq_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
xfer_len = min(alloc_len, EXTENDED_INQUIRY_DATA_PAGE_LENGTH);
res = nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
- out_free:
- dma_free_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns), mem,
- dma_addr);
- out_dma:
+ out_free_inq:
kfree(inq_response);
- out_mem:
return res;
}
@@ -965,7 +755,7 @@ static int nvme_trans_bdev_char_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
int alloc_len)
{
u8 *inq_response;
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int xfer_len;
inq_response = kzalloc(EXTENDED_INQUIRY_DATA_PAGE_LENGTH, GFP_KERNEL);
@@ -994,7 +784,7 @@ static int nvme_trans_bdev_char_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
static int nvme_trans_log_supp_pages(struct nvme_ns *ns, struct sg_io_hdr *hdr,
int alloc_len)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int xfer_len;
u8 *log_response;
@@ -1022,47 +812,30 @@ static int nvme_trans_log_supp_pages(struct nvme_ns *ns, struct sg_io_hdr *hdr,
static int nvme_trans_log_info_exceptions(struct nvme_ns *ns,
struct sg_io_hdr *hdr, int alloc_len)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int xfer_len;
u8 *log_response;
- struct nvme_command c;
struct nvme_dev *dev = ns->dev;
struct nvme_smart_log *smart_log;
- dma_addr_t dma_addr;
- void *mem;
u8 temp_c;
u16 temp_k;
log_response = kzalloc(LOG_INFO_EXCP_PAGE_LENGTH, GFP_KERNEL);
- if (log_response == NULL) {
- res = -ENOMEM;
- goto out_mem;
- }
+ if (log_response == NULL)
+ return -ENOMEM;
- mem = dma_alloc_coherent(&dev->pci_dev->dev,
- sizeof(struct nvme_smart_log),
- &dma_addr, GFP_KERNEL);
- if (mem == NULL) {
- res = -ENOMEM;
- goto out_dma;
- }
+ res = nvme_get_log_page(dev, &smart_log);
+ if (res < 0)
+ goto out_free_response;
- /* Get SMART Log Page */
- memset(&c, 0, sizeof(c));
- c.common.opcode = nvme_admin_get_log_page;
- c.common.nsid = cpu_to_le32(0xFFFFFFFF);
- c.common.prp1 = cpu_to_le64(dma_addr);
- c.common.cdw10[0] = cpu_to_le32((((sizeof(struct nvme_smart_log) /
- BYTES_TO_DWORDS) - 1) << 16) | NVME_LOG_SMART);
- res = nvme_submit_admin_cmd(dev, &c, NULL);
if (res != NVME_SC_SUCCESS) {
temp_c = LOG_TEMP_UNKNOWN;
} else {
- smart_log = mem;
temp_k = (smart_log->temperature[1] << 8) +
(smart_log->temperature[0]);
temp_c = temp_k - KELVIN_TEMP_FACTOR;
}
+ kfree(smart_log);
log_response[0] = LOG_PAGE_INFORMATIONAL_EXCEPTIONS_PAGE;
/* Subpage=0x00, Page Length MSB=0 */
@@ -1078,59 +851,39 @@ static int nvme_trans_log_info_exceptions(struct nvme_ns *ns,
xfer_len = min(alloc_len, LOG_INFO_EXCP_PAGE_LENGTH);
res = nvme_trans_copy_to_user(hdr, log_response, xfer_len);
- dma_free_coherent(&dev->pci_dev->dev, sizeof(struct nvme_smart_log),
- mem, dma_addr);
- out_dma:
+ out_free_response:
kfree(log_response);
- out_mem:
return res;
}
static int nvme_trans_log_temperature(struct nvme_ns *ns, struct sg_io_hdr *hdr,
int alloc_len)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int xfer_len;
u8 *log_response;
- struct nvme_command c;
struct nvme_dev *dev = ns->dev;
struct nvme_smart_log *smart_log;
- dma_addr_t dma_addr;
- void *mem;
u32 feature_resp;
u8 temp_c_cur, temp_c_thresh;
u16 temp_k;
log_response = kzalloc(LOG_TEMP_PAGE_LENGTH, GFP_KERNEL);
- if (log_response == NULL) {
- res = -ENOMEM;
- goto out_mem;
- }
+ if (log_response == NULL)
+ return -ENOMEM;
- mem = dma_alloc_coherent(&dev->pci_dev->dev,
- sizeof(struct nvme_smart_log),
- &dma_addr, GFP_KERNEL);
- if (mem == NULL) {
- res = -ENOMEM;
- goto out_dma;
- }
+ res = nvme_get_log_page(dev, &smart_log);
+ if (res < 0)
+ goto out_free_response;
- /* Get SMART Log Page */
- memset(&c, 0, sizeof(c));
- c.common.opcode = nvme_admin_get_log_page;
- c.common.nsid = cpu_to_le32(0xFFFFFFFF);
- c.common.prp1 = cpu_to_le64(dma_addr);
- c.common.cdw10[0] = cpu_to_le32((((sizeof(struct nvme_smart_log) /
- BYTES_TO_DWORDS) - 1) << 16) | NVME_LOG_SMART);
- res = nvme_submit_admin_cmd(dev, &c, NULL);
if (res != NVME_SC_SUCCESS) {
temp_c_cur = LOG_TEMP_UNKNOWN;
} else {
- smart_log = mem;
temp_k = (smart_log->temperature[1] << 8) +
(smart_log->temperature[0]);
temp_c_cur = temp_k - KELVIN_TEMP_FACTOR;
}
+ kfree(smart_log);
/* Get Features for Temp Threshold */
res = nvme_get_features(dev, NVME_FEAT_TEMP_THRESH, 0, 0,
@@ -1159,11 +912,8 @@ static int nvme_trans_log_temperature(struct nvme_ns *ns, struct sg_io_hdr *hdr,
xfer_len = min(alloc_len, LOG_TEMP_PAGE_LENGTH);
res = nvme_trans_copy_to_user(hdr, log_response, xfer_len);
- dma_free_coherent(&dev->pci_dev->dev, sizeof(struct nvme_smart_log),
- mem, dma_addr);
- out_dma:
+ out_free_response:
kfree(log_response);
- out_mem:
return res;
}
@@ -1174,59 +924,45 @@ static int nvme_trans_fill_mode_parm_hdr(u8 *resp, int len, u8 cdb10, u8 llbaa,
{
/* Quick check to make sure I don't stomp on my own memory... */
if ((cdb10 && len < 8) || (!cdb10 && len < 4))
- return SNTI_INTERNAL_ERROR;
+ return -EINVAL;
if (cdb10) {
resp[0] = (mode_data_length & 0xFF00) >> 8;
resp[1] = (mode_data_length & 0x00FF);
- /* resp[2] and [3] are zero */
+ resp[3] = 0x10 /* DPOFUA */;
resp[4] = llbaa;
resp[5] = RESERVED_FIELD;
resp[6] = (blk_desc_len & 0xFF00) >> 8;
resp[7] = (blk_desc_len & 0x00FF);
} else {
resp[0] = (mode_data_length & 0x00FF);
- /* resp[1] and [2] are zero */
+ resp[2] = 0x10 /* DPOFUA */;
resp[3] = (blk_desc_len & 0x00FF);
}
- return SNTI_TRANSLATION_SUCCESS;
+ return 0;
}
static int nvme_trans_fill_blk_desc(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *resp, int len, u8 llbaa)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int nvme_sc;
struct nvme_dev *dev = ns->dev;
- dma_addr_t dma_addr;
- void *mem;
struct nvme_id_ns *id_ns;
u8 flbas;
u32 lba_length;
if (llbaa == 0 && len < MODE_PAGE_BLK_DES_LEN)
- return SNTI_INTERNAL_ERROR;
+ return -EINVAL;
else if (llbaa > 0 && len < MODE_PAGE_LLBAA_BLK_DES_LEN)
- return SNTI_INTERNAL_ERROR;
-
- mem = dma_alloc_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns),
- &dma_addr, GFP_KERNEL);
- if (mem == NULL) {
- res = -ENOMEM;
- goto out;
- }
+ return -EINVAL;
- /* nvme ns identify */
- nvme_sc = nvme_identify(dev, ns->ns_id, 0, dma_addr);
+ nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
res = nvme_trans_status_code(hdr, nvme_sc);
if (res)
- goto out_dma;
- if (nvme_sc) {
- res = nvme_sc;
- goto out_dma;
- }
- id_ns = mem;
+ return res;
+
flbas = (id_ns->flbas) & 0x0F;
lba_length = (1 << (id_ns->lbaf[flbas].ds));
@@ -1246,10 +982,7 @@ static int nvme_trans_fill_blk_desc(struct nvme_ns *ns, struct sg_io_hdr *hdr,
memcpy(&resp[12], &tmp_len, sizeof(u32));
}
- out_dma:
- dma_free_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns), mem,
- dma_addr);
- out:
+ kfree(id_ns);
return res;
}
@@ -1258,7 +991,7 @@ static int nvme_trans_fill_control_page(struct nvme_ns *ns,
int len)
{
if (len < MODE_PAGE_CONTROL_LEN)
- return SNTI_INTERNAL_ERROR;
+ return -EINVAL;
resp[0] = MODE_PAGE_CONTROL;
resp[1] = MODE_PAGE_CONTROL_LEN_FIELD;
@@ -1272,78 +1005,69 @@ static int nvme_trans_fill_control_page(struct nvme_ns *ns,
resp[9] = 0xFF;
/* Bytes 10,11: Extended selftest completion time = 0x0000 */
- return SNTI_TRANSLATION_SUCCESS;
+ return 0;
}
static int nvme_trans_fill_caching_page(struct nvme_ns *ns,
struct sg_io_hdr *hdr,
u8 *resp, int len)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res = 0;
int nvme_sc;
struct nvme_dev *dev = ns->dev;
u32 feature_resp;
u8 vwc;
if (len < MODE_PAGE_CACHING_LEN)
- return SNTI_INTERNAL_ERROR;
+ return -EINVAL;
nvme_sc = nvme_get_features(dev, NVME_FEAT_VOLATILE_WC, 0, 0,
&feature_resp);
res = nvme_trans_status_code(hdr, nvme_sc);
if (res)
- goto out;
- if (nvme_sc) {
- res = nvme_sc;
- goto out;
- }
+ return res;
+
vwc = feature_resp & 0x00000001;
resp[0] = MODE_PAGE_CACHING;
resp[1] = MODE_PAGE_CACHING_LEN_FIELD;
resp[2] = vwc << 2;
-
- out:
- return res;
+ return 0;
}
static int nvme_trans_fill_pow_cnd_page(struct nvme_ns *ns,
struct sg_io_hdr *hdr, u8 *resp,
int len)
{
- int res = SNTI_TRANSLATION_SUCCESS;
-
if (len < MODE_PAGE_POW_CND_LEN)
- return SNTI_INTERNAL_ERROR;
+ return -EINVAL;
resp[0] = MODE_PAGE_POWER_CONDITION;
resp[1] = MODE_PAGE_POW_CND_LEN_FIELD;
/* All other bytes are zero */
- return res;
+ return 0;
}
static int nvme_trans_fill_inf_exc_page(struct nvme_ns *ns,
struct sg_io_hdr *hdr, u8 *resp,
int len)
{
- int res = SNTI_TRANSLATION_SUCCESS;
-
if (len < MODE_PAGE_INF_EXC_LEN)
- return SNTI_INTERNAL_ERROR;
+ return -EINVAL;
resp[0] = MODE_PAGE_INFO_EXCEP;
resp[1] = MODE_PAGE_INF_EXC_LEN_FIELD;
resp[2] = 0x88;
/* All other bytes are zero */
- return res;
+ return 0;
}
static int nvme_trans_fill_all_pages(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *resp, int len)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
u16 mode_pages_offset_1 = 0;
u16 mode_pages_offset_2, mode_pages_offset_3, mode_pages_offset_4;
@@ -1353,23 +1077,18 @@ static int nvme_trans_fill_all_pages(struct nvme_ns *ns, struct sg_io_hdr *hdr,
res = nvme_trans_fill_caching_page(ns, hdr, &resp[mode_pages_offset_1],
MODE_PAGE_CACHING_LEN);
- if (res != SNTI_TRANSLATION_SUCCESS)
- goto out;
+ if (res)
+ return res;
res = nvme_trans_fill_control_page(ns, hdr, &resp[mode_pages_offset_2],
MODE_PAGE_CONTROL_LEN);
- if (res != SNTI_TRANSLATION_SUCCESS)
- goto out;
+ if (res)
+ return res;
res = nvme_trans_fill_pow_cnd_page(ns, hdr, &resp[mode_pages_offset_3],
MODE_PAGE_POW_CND_LEN);
- if (res != SNTI_TRANSLATION_SUCCESS)
- goto out;
- res = nvme_trans_fill_inf_exc_page(ns, hdr, &resp[mode_pages_offset_4],
+ if (res)
+ return res;
+ return nvme_trans_fill_inf_exc_page(ns, hdr, &resp[mode_pages_offset_4],
MODE_PAGE_INF_EXC_LEN);
- if (res != SNTI_TRANSLATION_SUCCESS)
- goto out;
-
- out:
- return res;
}
static inline int nvme_trans_get_blk_desc_len(u8 dbd, u8 llbaa)
@@ -1390,7 +1109,7 @@ static int nvme_trans_mode_page_create(struct nvme_ns *ns,
struct sg_io_hdr *hdr, u8 *, int),
u16 mode_pages_tot_len)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int xfer_len;
u8 *response;
u8 dbd, llbaa;
@@ -1399,9 +1118,10 @@ static int nvme_trans_mode_page_create(struct nvme_ns *ns,
u16 mode_pages_offset_1;
u16 blk_desc_len, blk_desc_offset, mode_data_length;
- dbd = GET_MODE_SENSE_DBD(cmd);
- llbaa = GET_MODE_SENSE_LLBAA(cmd);
- mph_size = GET_MODE_SENSE_MPH_SIZE(cdb10);
+ dbd = (cmd[1] & MODE_SENSE_DBD_MASK) >> MODE_SENSE_DBD_SHIFT;
+ llbaa = (cmd[1] & MODE_SENSE_LLBAA_MASK) >> MODE_SENSE_LLBAA_SHIFT;
+ mph_size = cdb10 ? MODE_SENSE10_MPH_SIZE : MODE_SENSE6_MPH_SIZE;
+
blk_desc_len = nvme_trans_get_blk_desc_len(dbd, llbaa);
resp_size = mph_size + blk_desc_len + mode_pages_tot_len;
@@ -1419,18 +1139,18 @@ static int nvme_trans_mode_page_create(struct nvme_ns *ns,
res = nvme_trans_fill_mode_parm_hdr(&response[0], mph_size, cdb10,
llbaa, mode_data_length, blk_desc_len);
- if (res != SNTI_TRANSLATION_SUCCESS)
+ if (res)
goto out_free;
if (blk_desc_len > 0) {
res = nvme_trans_fill_blk_desc(ns, hdr,
&response[blk_desc_offset],
blk_desc_len, llbaa);
- if (res != SNTI_TRANSLATION_SUCCESS)
+ if (res)
goto out_free;
}
res = mode_page_fill_func(ns, hdr, &response[mode_pages_offset_1],
mode_pages_tot_len);
- if (res != SNTI_TRANSLATION_SUCCESS)
+ if (res)
goto out_free;
xfer_len = min(alloc_len, resp_size);
@@ -1485,33 +1205,20 @@ static void nvme_trans_fill_read_cap(u8 *response, struct nvme_id_ns *id_ns,
static int nvme_trans_power_state(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 pc, u8 pcmod, u8 start)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int nvme_sc;
struct nvme_dev *dev = ns->dev;
- dma_addr_t dma_addr;
- void *mem;
struct nvme_id_ctrl *id_ctrl;
int lowest_pow_st; /* max npss = lowest power consumption */
unsigned ps_desired = 0;
- /* NVMe Controller Identify */
- mem = dma_alloc_coherent(&dev->pci_dev->dev,
- sizeof(struct nvme_id_ctrl),
- &dma_addr, GFP_KERNEL);
- if (mem == NULL) {
- res = -ENOMEM;
- goto out;
- }
- nvme_sc = nvme_identify(dev, 0, 1, dma_addr);
+ nvme_sc = nvme_identify_ctrl(dev, &id_ctrl);
res = nvme_trans_status_code(hdr, nvme_sc);
if (res)
- goto out_dma;
- if (nvme_sc) {
- res = nvme_sc;
- goto out_dma;
- }
- id_ctrl = mem;
+ return res;
+
lowest_pow_st = max(POWER_STATE_0, (int)(id_ctrl->npss - 1));
+ kfree(id_ctrl);
switch (pc) {
case NVME_POWER_STATE_START_VALID:
@@ -1551,79 +1258,48 @@ static int nvme_trans_power_state(struct nvme_ns *ns, struct sg_io_hdr *hdr,
}
nvme_sc = nvme_set_features(dev, NVME_FEAT_POWER_MGMT, ps_desired, 0,
NULL);
- res = nvme_trans_status_code(hdr, nvme_sc);
- if (res)
- goto out_dma;
- if (nvme_sc)
- res = nvme_sc;
- out_dma:
- dma_free_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ctrl), mem,
- dma_addr);
- out:
- return res;
+ return nvme_trans_status_code(hdr, nvme_sc);
}
-/* Write Buffer Helper Functions */
-/* Also using this for Format Unit with hdr passed as NULL, and buffer_id, 0 */
+static int nvme_trans_send_activate_fw_cmd(struct nvme_ns *ns, struct sg_io_hdr *hdr,
+ u8 buffer_id)
+{
+ struct nvme_command c;
+ int nvme_sc;
-static int nvme_trans_send_fw_cmd(struct nvme_ns *ns, struct sg_io_hdr *hdr,
+ memset(&c, 0, sizeof(c));
+ c.common.opcode = nvme_admin_activate_fw;
+ c.common.cdw10[0] = cpu_to_le32(buffer_id | NVME_FWACT_REPL_ACTV);
+
+ nvme_sc = nvme_submit_sync_cmd(ns->queue, &c, NULL, 0);
+ return nvme_trans_status_code(hdr, nvme_sc);
+}
+
+static int nvme_trans_send_download_fw_cmd(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 opcode, u32 tot_len, u32 offset,
u8 buffer_id)
{
- int res = SNTI_TRANSLATION_SUCCESS;
int nvme_sc;
struct nvme_dev *dev = ns->dev;
struct nvme_command c;
- struct nvme_iod *iod = NULL;
- unsigned length;
- memset(&c, 0, sizeof(c));
- c.common.opcode = opcode;
- if (opcode == nvme_admin_download_fw) {
- if (hdr->iovec_count > 0) {
- /* Assuming SGL is not allowed for this command */
- res = nvme_trans_completion(hdr,
- SAM_STAT_CHECK_CONDITION,
- ILLEGAL_REQUEST,
- SCSI_ASC_INVALID_CDB,
- SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
- goto out;
- }
- iod = nvme_map_user_pages(dev, DMA_TO_DEVICE,
- (unsigned long)hdr->dxferp, tot_len);
- if (IS_ERR(iod)) {
- res = PTR_ERR(iod);
- goto out;
- }
- length = nvme_setup_prps(dev, iod, tot_len, GFP_KERNEL);
- if (length != tot_len) {
- res = -ENOMEM;
- goto out_unmap;
- }
-
- c.dlfw.prp1 = cpu_to_le64(sg_dma_address(iod->sg));
- c.dlfw.prp2 = cpu_to_le64(iod->first_dma);
- c.dlfw.numd = cpu_to_le32((tot_len/BYTES_TO_DWORDS) - 1);
- c.dlfw.offset = cpu_to_le32(offset/BYTES_TO_DWORDS);
- } else if (opcode == nvme_admin_activate_fw) {
- u32 cdw10 = buffer_id | NVME_FWACT_REPL_ACTV;
- c.common.cdw10[0] = cpu_to_le32(cdw10);
+ if (hdr->iovec_count > 0) {
+ /* Assuming SGL is not allowed for this command */
+ return nvme_trans_completion(hdr,
+ SAM_STAT_CHECK_CONDITION,
+ ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_CDB,
+ SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
}
- nvme_sc = nvme_submit_admin_cmd(dev, &c, NULL);
- res = nvme_trans_status_code(hdr, nvme_sc);
- if (res)
- goto out_unmap;
- if (nvme_sc)
- res = nvme_sc;
-
- out_unmap:
- if (opcode == nvme_admin_download_fw) {
- nvme_unmap_user_pages(dev, DMA_TO_DEVICE, iod);
- nvme_free_iod(dev, iod);
- }
- out:
- return res;
+ memset(&c, 0, sizeof(c));
+ c.common.opcode = nvme_admin_download_fw;
+ c.dlfw.numd = cpu_to_le32((tot_len/BYTES_TO_DWORDS) - 1);
+ c.dlfw.offset = cpu_to_le32(offset/BYTES_TO_DWORDS);
+
+ nvme_sc = __nvme_submit_sync_cmd(dev->admin_q, &c, NULL,
+ hdr->dxferp, tot_len, NULL, 0);
+ return nvme_trans_status_code(hdr, nvme_sc);
}
/* Mode Select Helper Functions */
@@ -1686,7 +1362,7 @@ static void nvme_trans_modesel_save_bd(struct nvme_ns *ns, u8 *parm_list,
static int nvme_trans_modesel_get_mp(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *mode_page, u8 page_code)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res = 0;
int nvme_sc;
struct nvme_dev *dev = ns->dev;
unsigned dword11;
@@ -1697,12 +1373,6 @@ static int nvme_trans_modesel_get_mp(struct nvme_ns *ns, struct sg_io_hdr *hdr,
nvme_sc = nvme_set_features(dev, NVME_FEAT_VOLATILE_WC, dword11,
0, NULL);
res = nvme_trans_status_code(hdr, nvme_sc);
- if (res)
- break;
- if (nvme_sc) {
- res = nvme_sc;
- break;
- }
break;
case MODE_PAGE_CONTROL:
break;
@@ -1714,8 +1384,6 @@ static int nvme_trans_modesel_get_mp(struct nvme_ns *ns, struct sg_io_hdr *hdr,
ILLEGAL_REQUEST,
SCSI_ASC_INVALID_PARAMETER,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
- if (!res)
- res = SNTI_INTERNAL_ERROR;
break;
}
break;
@@ -1723,8 +1391,6 @@ static int nvme_trans_modesel_get_mp(struct nvme_ns *ns, struct sg_io_hdr *hdr,
res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
- if (!res)
- res = SNTI_INTERNAL_ERROR;
break;
}
@@ -1735,7 +1401,7 @@ static int nvme_trans_modesel_data(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *cmd, u16 parm_list_len, u8 pf,
u8 sp, u8 cdb10)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
u8 *parm_list;
u16 bd_len;
u8 llbaa = 0;
@@ -1751,7 +1417,7 @@ static int nvme_trans_modesel_data(struct nvme_ns *ns, struct sg_io_hdr *hdr,
}
res = nvme_trans_copy_from_user(hdr, parm_list, parm_list_len);
- if (res != SNTI_TRANSLATION_SUCCESS)
+ if (res)
goto out_mem;
nvme_trans_modesel_get_bd_len(parm_list, cdb10, &bd_len, &llbaa);
@@ -1789,7 +1455,7 @@ static int nvme_trans_modesel_data(struct nvme_ns *ns, struct sg_io_hdr *hdr,
mp_size = parm_list[index + 1] + 2;
res = nvme_trans_modesel_get_mp(ns, hdr, &parm_list[index],
page_code);
- if (res != SNTI_TRANSLATION_SUCCESS)
+ if (res)
break;
index += mp_size;
} while (index < parm_list_len);
@@ -1805,12 +1471,9 @@ static int nvme_trans_modesel_data(struct nvme_ns *ns, struct sg_io_hdr *hdr,
static int nvme_trans_fmt_set_blk_size_count(struct nvme_ns *ns,
struct sg_io_hdr *hdr)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res = 0;
int nvme_sc;
struct nvme_dev *dev = ns->dev;
- dma_addr_t dma_addr;
- void *mem;
- struct nvme_id_ns *id_ns;
u8 flbas;
/*
@@ -1821,22 +1484,12 @@ static int nvme_trans_fmt_set_blk_size_count(struct nvme_ns *ns,
*/
if (ns->mode_select_num_blocks == 0 || ns->mode_select_block_len == 0) {
- mem = dma_alloc_coherent(&dev->pci_dev->dev,
- sizeof(struct nvme_id_ns), &dma_addr, GFP_KERNEL);
- if (mem == NULL) {
- res = -ENOMEM;
- goto out;
- }
- /* nvme ns identify */
- nvme_sc = nvme_identify(dev, ns->ns_id, 0, dma_addr);
+ struct nvme_id_ns *id_ns;
+
+ nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
res = nvme_trans_status_code(hdr, nvme_sc);
if (res)
- goto out_dma;
- if (nvme_sc) {
- res = nvme_sc;
- goto out_dma;
- }
- id_ns = mem;
+ return res;
if (ns->mode_select_num_blocks == 0)
ns->mode_select_num_blocks = le64_to_cpu(id_ns->ncap);
@@ -1845,18 +1498,17 @@ static int nvme_trans_fmt_set_blk_size_count(struct nvme_ns *ns,
ns->mode_select_block_len =
(1 << (id_ns->lbaf[flbas].ds));
}
- out_dma:
- dma_free_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns),
- mem, dma_addr);
+
+ kfree(id_ns);
}
- out:
- return res;
+
+ return 0;
}
static int nvme_trans_fmt_get_parm_header(struct sg_io_hdr *hdr, u8 len,
u8 format_prot_info, u8 *nvme_pf_code)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
u8 *parm_list;
u8 pf_usage, pf_code;
@@ -1866,7 +1518,7 @@ static int nvme_trans_fmt_get_parm_header(struct sg_io_hdr *hdr, u8 len,
goto out;
}
res = nvme_trans_copy_from_user(hdr, parm_list, len);
- if (res != SNTI_TRANSLATION_SUCCESS)
+ if (res)
goto out_mem;
if ((parm_list[FORMAT_UNIT_IMMED_OFFSET] &
@@ -1916,11 +1568,9 @@ static int nvme_trans_fmt_get_parm_header(struct sg_io_hdr *hdr, u8 len,
static int nvme_trans_fmt_send_cmd(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 prot_info)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int nvme_sc;
struct nvme_dev *dev = ns->dev;
- dma_addr_t dma_addr;
- void *mem;
struct nvme_id_ns *id_ns;
u8 i;
u8 flbas, nlbaf;
@@ -1929,22 +1579,11 @@ static int nvme_trans_fmt_send_cmd(struct nvme_ns *ns, struct sg_io_hdr *hdr,
struct nvme_command c;
/* Loop thru LBAF's in id_ns to match reqd lbaf, put in cdw10 */
- mem = dma_alloc_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns),
- &dma_addr, GFP_KERNEL);
- if (mem == NULL) {
- res = -ENOMEM;
- goto out;
- }
- /* nvme ns identify */
- nvme_sc = nvme_identify(dev, ns->ns_id, 0, dma_addr);
+ nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
res = nvme_trans_status_code(hdr, nvme_sc);
if (res)
- goto out_dma;
- if (nvme_sc) {
- res = nvme_sc;
- goto out_dma;
- }
- id_ns = mem;
+ return res;
+
flbas = (id_ns->flbas) & 0x0F;
nlbaf = id_ns->nlbaf;
@@ -1972,69 +1611,13 @@ static int nvme_trans_fmt_send_cmd(struct nvme_ns *ns, struct sg_io_hdr *hdr,
c.format.nsid = cpu_to_le32(ns->ns_id);
c.format.cdw10 = cpu_to_le32(cdw10);
- nvme_sc = nvme_submit_admin_cmd(dev, &c, NULL);
+ nvme_sc = nvme_submit_sync_cmd(dev->admin_q, &c, NULL, 0);
res = nvme_trans_status_code(hdr, nvme_sc);
- if (res)
- goto out_dma;
- if (nvme_sc)
- res = nvme_sc;
- out_dma:
- dma_free_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns), mem,
- dma_addr);
- out:
+ kfree(id_ns);
return res;
}
-/* Read/Write Helper Functions */
-
-static inline void nvme_trans_get_io_cdb6(u8 *cmd,
- struct nvme_trans_io_cdb *cdb_info)
-{
- cdb_info->fua = 0;
- cdb_info->prot_info = 0;
- cdb_info->lba = GET_U32_FROM_CDB(cmd, IO_6_CDB_LBA_OFFSET) &
- IO_6_CDB_LBA_MASK;
- cdb_info->xfer_len = GET_U8_FROM_CDB(cmd, IO_6_CDB_TX_LEN_OFFSET);
-
- /* sbc3r27 sec 5.32 - TRANSFER LEN of 0 implies a 256 Block transfer */
- if (cdb_info->xfer_len == 0)
- cdb_info->xfer_len = IO_6_DEFAULT_TX_LEN;
-}
-
-static inline void nvme_trans_get_io_cdb10(u8 *cmd,
- struct nvme_trans_io_cdb *cdb_info)
-{
- cdb_info->fua = GET_U8_FROM_CDB(cmd, IO_10_CDB_FUA_OFFSET) &
- IO_CDB_FUA_MASK;
- cdb_info->prot_info = GET_U8_FROM_CDB(cmd, IO_10_CDB_WP_OFFSET) &
- IO_CDB_WP_MASK >> IO_CDB_WP_SHIFT;
- cdb_info->lba = GET_U32_FROM_CDB(cmd, IO_10_CDB_LBA_OFFSET);
- cdb_info->xfer_len = GET_U16_FROM_CDB(cmd, IO_10_CDB_TX_LEN_OFFSET);
-}
-
-static inline void nvme_trans_get_io_cdb12(u8 *cmd,
- struct nvme_trans_io_cdb *cdb_info)
-{
- cdb_info->fua = GET_U8_FROM_CDB(cmd, IO_12_CDB_FUA_OFFSET) &
- IO_CDB_FUA_MASK;
- cdb_info->prot_info = GET_U8_FROM_CDB(cmd, IO_12_CDB_WP_OFFSET) &
- IO_CDB_WP_MASK >> IO_CDB_WP_SHIFT;
- cdb_info->lba = GET_U32_FROM_CDB(cmd, IO_12_CDB_LBA_OFFSET);
- cdb_info->xfer_len = GET_U32_FROM_CDB(cmd, IO_12_CDB_TX_LEN_OFFSET);
-}
-
-static inline void nvme_trans_get_io_cdb16(u8 *cmd,
- struct nvme_trans_io_cdb *cdb_info)
-{
- cdb_info->fua = GET_U8_FROM_CDB(cmd, IO_16_CDB_FUA_OFFSET) &
- IO_CDB_FUA_MASK;
- cdb_info->prot_info = GET_U8_FROM_CDB(cmd, IO_16_CDB_WP_OFFSET) &
- IO_CDB_WP_MASK >> IO_CDB_WP_SHIFT;
- cdb_info->lba = GET_U64_FROM_CDB(cmd, IO_16_CDB_LBA_OFFSET);
- cdb_info->xfer_len = GET_U32_FROM_CDB(cmd, IO_16_CDB_TX_LEN_OFFSET);
-}
-
static inline u32 nvme_trans_io_get_num_cmds(struct sg_io_hdr *hdr,
struct nvme_trans_io_cdb *cdb_info,
u32 max_blocks)
@@ -2064,11 +1647,8 @@ static u16 nvme_trans_io_get_control(struct nvme_ns *ns,
static int nvme_trans_do_nvme_io(struct nvme_ns *ns, struct sg_io_hdr *hdr,
struct nvme_trans_io_cdb *cdb_info, u8 is_write)
{
- int res = SNTI_TRANSLATION_SUCCESS;
- int nvme_sc;
- struct nvme_dev *dev = ns->dev;
+ int nvme_sc = NVME_SC_SUCCESS;
u32 num_cmds;
- struct nvme_iod *iod;
u64 unit_len;
u64 unit_num_blocks; /* Number of blocks to xfer in each nvme cmd */
u32 retcode;
@@ -2119,45 +1699,20 @@ static int nvme_trans_do_nvme_io(struct nvme_ns *ns, struct sg_io_hdr *hdr,
control = nvme_trans_io_get_control(ns, cdb_info);
c.rw.control = cpu_to_le16(control);
- iod = nvme_map_user_pages(dev,
- (is_write) ? DMA_TO_DEVICE : DMA_FROM_DEVICE,
- (unsigned long)next_mapping_addr, unit_len);
- if (IS_ERR(iod)) {
- res = PTR_ERR(iod);
- goto out;
- }
- retcode = nvme_setup_prps(dev, iod, unit_len, GFP_KERNEL);
- if (retcode != unit_len) {
- nvme_unmap_user_pages(dev,
- (is_write) ? DMA_TO_DEVICE : DMA_FROM_DEVICE,
- iod);
- nvme_free_iod(dev, iod);
- res = -ENOMEM;
- goto out;
+ if (get_capacity(ns->disk) - unit_num_blocks <
+ cdb_info->lba + nvme_offset) {
+ nvme_sc = NVME_SC_LBA_RANGE;
+ break;
}
- c.rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg));
- c.rw.prp2 = cpu_to_le64(iod->first_dma);
+ nvme_sc = __nvme_submit_sync_cmd(ns->queue, &c, NULL,
+ next_mapping_addr, unit_len, NULL, 0);
+ if (nvme_sc)
+ break;
nvme_offset += unit_num_blocks;
-
- nvme_sc = nvme_submit_io_cmd(dev, ns, &c, NULL);
- if (nvme_sc != NVME_SC_SUCCESS) {
- nvme_unmap_user_pages(dev,
- (is_write) ? DMA_TO_DEVICE : DMA_FROM_DEVICE,
- iod);
- nvme_free_iod(dev, iod);
- res = nvme_trans_status_code(hdr, nvme_sc);
- goto out;
- }
- nvme_unmap_user_pages(dev,
- (is_write) ? DMA_TO_DEVICE : DMA_FROM_DEVICE,
- iod);
- nvme_free_iod(dev, iod);
}
- res = nvme_trans_status_code(hdr, NVME_SC_SUCCESS);
- out:
- return res;
+ return nvme_trans_status_code(hdr, nvme_sc);
}
@@ -2166,8 +1721,8 @@ static int nvme_trans_do_nvme_io(struct nvme_ns *ns, struct sg_io_hdr *hdr,
static int nvme_trans_io(struct nvme_ns *ns, struct sg_io_hdr *hdr, u8 is_write,
u8 *cmd)
{
- int res = SNTI_TRANSLATION_SUCCESS;
- struct nvme_trans_io_cdb cdb_info;
+ int res = 0;
+ struct nvme_trans_io_cdb cdb_info = { 0, };
u8 opcode = cmd[0];
u64 xfer_bytes;
u64 sum_iov_len = 0;
@@ -2175,27 +1730,52 @@ static int nvme_trans_io(struct nvme_ns *ns, struct sg_io_hdr *hdr, u8 is_write,
int i;
size_t not_copied;
- /* Extract Fields from CDB */
+ /*
+ * The FUA and WPROTECT fields are not supported in 6-byte CDBs,
+ * but always in the same place for all others.
+ */
+ switch (opcode) {
+ case WRITE_6:
+ case READ_6:
+ break;
+ default:
+ cdb_info.fua = cmd[1] & 0x8;
+ cdb_info.prot_info = (cmd[1] & 0xe0) >> 5;
+ if (cdb_info.prot_info && !ns->pi_type) {
+ return nvme_trans_completion(hdr,
+ SAM_STAT_CHECK_CONDITION,
+ ILLEGAL_REQUEST,
+ SCSI_ASC_INVALID_CDB,
+ SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
+ }
+ }
+
switch (opcode) {
case WRITE_6:
case READ_6:
- nvme_trans_get_io_cdb6(cmd, &cdb_info);
+ cdb_info.lba = get_unaligned_be24(&cmd[1]);
+ cdb_info.xfer_len = cmd[4];
+ if (cdb_info.xfer_len == 0)
+ cdb_info.xfer_len = 256;
break;
case WRITE_10:
case READ_10:
- nvme_trans_get_io_cdb10(cmd, &cdb_info);
+ cdb_info.lba = get_unaligned_be32(&cmd[2]);
+ cdb_info.xfer_len = get_unaligned_be16(&cmd[7]);
break;
case WRITE_12:
case READ_12:
- nvme_trans_get_io_cdb12(cmd, &cdb_info);
+ cdb_info.lba = get_unaligned_be32(&cmd[2]);
+ cdb_info.xfer_len = get_unaligned_be32(&cmd[6]);
break;
case WRITE_16:
case READ_16:
- nvme_trans_get_io_cdb16(cmd, &cdb_info);
+ cdb_info.lba = get_unaligned_be64(&cmd[2]);
+ cdb_info.xfer_len = get_unaligned_be32(&cmd[10]);
break;
default:
/* Will never really reach here */
- res = SNTI_INTERNAL_ERROR;
+ res = -EIO;
goto out;
}
@@ -2237,7 +1817,7 @@ static int nvme_trans_io(struct nvme_ns *ns, struct sg_io_hdr *hdr, u8 is_write,
/* Send NVMe IO Command(s) */
res = nvme_trans_do_nvme_io(ns, hdr, &cdb_info, is_write);
- if (res != SNTI_TRANSLATION_SUCCESS)
+ if (res)
goto out;
out:
@@ -2247,15 +1827,15 @@ static int nvme_trans_io(struct nvme_ns *ns, struct sg_io_hdr *hdr, u8 is_write,
static int nvme_trans_inquiry(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *cmd)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res = 0;
u8 evpd;
u8 page_code;
int alloc_len;
u8 *inq_response;
- evpd = GET_INQ_EVPD_BIT(cmd);
- page_code = GET_INQ_PAGE_CODE(cmd);
- alloc_len = GET_INQ_ALLOC_LENGTH(cmd);
+ evpd = cmd[1] & 0x01;
+ page_code = cmd[2];
+ alloc_len = get_unaligned_be16(&cmd[3]);
inq_response = kmalloc(max(alloc_len, STANDARD_INQUIRY_LENGTH),
GFP_KERNEL);
@@ -2316,29 +1896,27 @@ static int nvme_trans_inquiry(struct nvme_ns *ns, struct sg_io_hdr *hdr,
static int nvme_trans_log_sense(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *cmd)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
u16 alloc_len;
- u8 sp;
u8 pc;
u8 page_code;
- sp = GET_U8_FROM_CDB(cmd, LOG_SENSE_CDB_SP_OFFSET);
- if (sp != LOG_SENSE_CDB_SP_NOT_ENABLED) {
+ if (cmd[1] != LOG_SENSE_CDB_SP_NOT_ENABLED) {
res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
goto out;
}
- pc = GET_U8_FROM_CDB(cmd, LOG_SENSE_CDB_PC_OFFSET);
- page_code = pc & LOG_SENSE_CDB_PAGE_CODE_MASK;
- pc = (pc & LOG_SENSE_CDB_PC_MASK) >> LOG_SENSE_CDB_PC_SHIFT;
+
+ page_code = cmd[2] & LOG_SENSE_CDB_PAGE_CODE_MASK;
+ pc = (cmd[2] & LOG_SENSE_CDB_PC_MASK) >> LOG_SENSE_CDB_PC_SHIFT;
if (pc != LOG_SENSE_CDB_PC_CUMULATIVE_VALUES) {
res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
goto out;
}
- alloc_len = GET_U16_FROM_CDB(cmd, LOG_SENSE_CDB_ALLOC_LENGTH_OFFSET);
+ alloc_len = get_unaligned_be16(&cmd[7]);
switch (page_code) {
case LOG_PAGE_SUPPORTED_LOG_PAGES_PAGE:
res = nvme_trans_log_supp_pages(ns, hdr, alloc_len);
@@ -2363,24 +1941,18 @@ static int nvme_trans_log_sense(struct nvme_ns *ns, struct sg_io_hdr *hdr,
static int nvme_trans_mode_select(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *cmd)
{
- int res = SNTI_TRANSLATION_SUCCESS;
u8 cdb10 = 0;
u16 parm_list_len;
u8 page_format;
u8 save_pages;
- page_format = GET_U8_FROM_CDB(cmd, MODE_SELECT_CDB_PAGE_FORMAT_OFFSET);
- page_format &= MODE_SELECT_CDB_PAGE_FORMAT_MASK;
+ page_format = cmd[1] & MODE_SELECT_CDB_PAGE_FORMAT_MASK;
+ save_pages = cmd[1] & MODE_SELECT_CDB_SAVE_PAGES_MASK;
- save_pages = GET_U8_FROM_CDB(cmd, MODE_SELECT_CDB_SAVE_PAGES_OFFSET);
- save_pages &= MODE_SELECT_CDB_SAVE_PAGES_MASK;
-
- if (GET_OPCODE(cmd) == MODE_SELECT) {
- parm_list_len = GET_U8_FROM_CDB(cmd,
- MODE_SELECT_6_CDB_PARAM_LIST_LENGTH_OFFSET);
+ if (cmd[0] == MODE_SELECT) {
+ parm_list_len = cmd[4];
} else {
- parm_list_len = GET_U16_FROM_CDB(cmd,
- MODE_SELECT_10_CDB_PARAM_LIST_LENGTH_OFFSET);
+ parm_list_len = cmd[7];
cdb10 = 1;
}
@@ -2389,42 +1961,36 @@ static int nvme_trans_mode_select(struct nvme_ns *ns, struct sg_io_hdr *hdr,
* According to SPC-4 r24, a paramter list length field of 0
* shall not be considered an error
*/
- res = nvme_trans_modesel_data(ns, hdr, cmd, parm_list_len,
+ return nvme_trans_modesel_data(ns, hdr, cmd, parm_list_len,
page_format, save_pages, cdb10);
}
- return res;
+ return 0;
}
static int nvme_trans_mode_sense(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *cmd)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res = 0;
u16 alloc_len;
u8 cdb10 = 0;
- u8 page_code;
- u8 pc;
- if (GET_OPCODE(cmd) == MODE_SENSE) {
- alloc_len = GET_U8_FROM_CDB(cmd, MODE_SENSE6_ALLOC_LEN_OFFSET);
+ if (cmd[0] == MODE_SENSE) {
+ alloc_len = cmd[4];
} else {
- alloc_len = GET_U16_FROM_CDB(cmd,
- MODE_SENSE10_ALLOC_LEN_OFFSET);
+ alloc_len = get_unaligned_be16(&cmd[7]);
cdb10 = 1;
}
- pc = GET_U8_FROM_CDB(cmd, MODE_SENSE_PAGE_CONTROL_OFFSET) &
- MODE_SENSE_PAGE_CONTROL_MASK;
- if (pc != MODE_SENSE_PC_CURRENT_VALUES) {
+ if ((cmd[2] & MODE_SENSE_PAGE_CONTROL_MASK) !=
+ MODE_SENSE_PC_CURRENT_VALUES) {
res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
goto out;
}
- page_code = GET_U8_FROM_CDB(cmd, MODE_SENSE_PAGE_CODE_OFFSET) &
- MODE_SENSE_PAGE_CODE_MASK;
- switch (page_code) {
+ switch (cmd[2] & MODE_SENSE_PAGE_CODE_MASK) {
case MODE_PAGE_CACHING:
res = nvme_trans_mode_page_create(ns, hdr, cmd, alloc_len,
cdb10,
@@ -2467,47 +2033,34 @@ static int nvme_trans_mode_sense(struct nvme_ns *ns, struct sg_io_hdr *hdr,
}
static int nvme_trans_read_capacity(struct nvme_ns *ns, struct sg_io_hdr *hdr,
- u8 *cmd)
+ u8 *cmd, u8 cdb16)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int nvme_sc;
- u32 alloc_len = READ_CAP_10_RESP_SIZE;
- u32 resp_size = READ_CAP_10_RESP_SIZE;
+ u32 alloc_len;
+ u32 resp_size;
u32 xfer_len;
- u8 cdb16;
struct nvme_dev *dev = ns->dev;
- dma_addr_t dma_addr;
- void *mem;
struct nvme_id_ns *id_ns;
u8 *response;
- cdb16 = IS_READ_CAP_16(cmd);
if (cdb16) {
- alloc_len = GET_READ_CAP_16_ALLOC_LENGTH(cmd);
+ alloc_len = get_unaligned_be32(&cmd[10]);
resp_size = READ_CAP_16_RESP_SIZE;
+ } else {
+ alloc_len = READ_CAP_10_RESP_SIZE;
+ resp_size = READ_CAP_10_RESP_SIZE;
}
- mem = dma_alloc_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns),
- &dma_addr, GFP_KERNEL);
- if (mem == NULL) {
- res = -ENOMEM;
- goto out;
- }
- /* nvme ns identify */
- nvme_sc = nvme_identify(dev, ns->ns_id, 0, dma_addr);
+ nvme_sc = nvme_identify_ns(dev, ns->ns_id, &id_ns);
res = nvme_trans_status_code(hdr, nvme_sc);
if (res)
- goto out_dma;
- if (nvme_sc) {
- res = nvme_sc;
- goto out_dma;
- }
- id_ns = mem;
+ return res;
response = kzalloc(resp_size, GFP_KERNEL);
if (response == NULL) {
res = -ENOMEM;
- goto out_dma;
+ goto out_free_id;
}
nvme_trans_fill_read_cap(response, id_ns, cdb16);
@@ -2515,72 +2068,53 @@ static int nvme_trans_read_capacity(struct nvme_ns *ns, struct sg_io_hdr *hdr,
res = nvme_trans_copy_to_user(hdr, response, xfer_len);
kfree(response);
- out_dma:
- dma_free_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ns), mem,
- dma_addr);
- out:
+ out_free_id:
+ kfree(id_ns);
return res;
}
static int nvme_trans_report_luns(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *cmd)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
int nvme_sc;
u32 alloc_len, xfer_len, resp_size;
- u8 select_report;
u8 *response;
struct nvme_dev *dev = ns->dev;
- dma_addr_t dma_addr;
- void *mem;
struct nvme_id_ctrl *id_ctrl;
u32 ll_length, lun_id;
u8 lun_id_offset = REPORT_LUNS_FIRST_LUN_OFFSET;
__be32 tmp_len;
- alloc_len = GET_REPORT_LUNS_ALLOC_LENGTH(cmd);
- select_report = GET_U8_FROM_CDB(cmd, REPORT_LUNS_SR_OFFSET);
-
- if ((select_report != ALL_LUNS_RETURNED) &&
- (select_report != ALL_WELL_KNOWN_LUNS_RETURNED) &&
- (select_report != RESTRICTED_LUNS_RETURNED)) {
- res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
+ switch (cmd[2]) {
+ default:
+ return nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
- goto out;
- } else {
- /* NVMe Controller Identify */
- mem = dma_alloc_coherent(&dev->pci_dev->dev,
- sizeof(struct nvme_id_ctrl),
- &dma_addr, GFP_KERNEL);
- if (mem == NULL) {
- res = -ENOMEM;
- goto out;
- }
- nvme_sc = nvme_identify(dev, 0, 1, dma_addr);
+ case ALL_LUNS_RETURNED:
+ case ALL_WELL_KNOWN_LUNS_RETURNED:
+ case RESTRICTED_LUNS_RETURNED:
+ nvme_sc = nvme_identify_ctrl(dev, &id_ctrl);
res = nvme_trans_status_code(hdr, nvme_sc);
if (res)
- goto out_dma;
- if (nvme_sc) {
- res = nvme_sc;
- goto out_dma;
- }
- id_ctrl = mem;
+ return res;
+
ll_length = le32_to_cpu(id_ctrl->nn) * LUN_ENTRY_SIZE;
resp_size = ll_length + LUN_DATA_HEADER_SIZE;
+ alloc_len = get_unaligned_be32(&cmd[6]);
if (alloc_len < resp_size) {
res = nvme_trans_completion(hdr,
SAM_STAT_CHECK_CONDITION,
ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
- goto out_dma;
+ goto out_free_id;
}
response = kzalloc(resp_size, GFP_KERNEL);
if (response == NULL) {
res = -ENOMEM;
- goto out_dma;
+ goto out_free_id;
}
/* The first LUN ID will always be 0 per the SAM spec */
@@ -2601,24 +2135,21 @@ static int nvme_trans_report_luns(struct nvme_ns *ns, struct sg_io_hdr *hdr,
res = nvme_trans_copy_to_user(hdr, response, xfer_len);
kfree(response);
- out_dma:
- dma_free_coherent(&dev->pci_dev->dev, sizeof(struct nvme_id_ctrl), mem,
- dma_addr);
- out:
+ out_free_id:
+ kfree(id_ctrl);
return res;
}
static int nvme_trans_request_sense(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *cmd)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
u8 alloc_len, xfer_len, resp_size;
u8 desc_format;
u8 *response;
- alloc_len = GET_REQUEST_SENSE_ALLOC_LENGTH(cmd);
- desc_format = GET_U8_FROM_CDB(cmd, REQUEST_SENSE_DESC_OFFSET);
- desc_format &= REQUEST_SENSE_DESC_MASK;
+ desc_format = cmd[1] & 0x01;
+ alloc_len = cmd[4];
resp_size = ((desc_format) ? (DESC_FMT_SENSE_DATA_SIZE) :
(FIXED_FMT_SENSE_DATA_SIZE));
@@ -2628,7 +2159,7 @@ static int nvme_trans_request_sense(struct nvme_ns *ns, struct sg_io_hdr *hdr,
goto out;
}
- if (desc_format == DESCRIPTOR_FORMAT_SENSE_DATA_TYPE) {
+ if (desc_format) {
/* Descriptor Format Sense Data */
response[0] = DESC_FORMAT_SENSE_DATA;
response[1] = NO_SENSE;
@@ -2667,95 +2198,58 @@ static int nvme_trans_security_protocol(struct nvme_ns *ns,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
}
-static int nvme_trans_start_stop(struct nvme_ns *ns, struct sg_io_hdr *hdr,
- u8 *cmd)
+static int nvme_trans_synchronize_cache(struct nvme_ns *ns,
+ struct sg_io_hdr *hdr)
{
- int res = SNTI_TRANSLATION_SUCCESS;
int nvme_sc;
struct nvme_command c;
- u8 immed, pcmod, pc, no_flush, start;
- immed = GET_U8_FROM_CDB(cmd, START_STOP_UNIT_CDB_IMMED_OFFSET);
- pcmod = GET_U8_FROM_CDB(cmd, START_STOP_UNIT_CDB_POWER_COND_MOD_OFFSET);
- pc = GET_U8_FROM_CDB(cmd, START_STOP_UNIT_CDB_POWER_COND_OFFSET);
- no_flush = GET_U8_FROM_CDB(cmd, START_STOP_UNIT_CDB_NO_FLUSH_OFFSET);
- start = GET_U8_FROM_CDB(cmd, START_STOP_UNIT_CDB_START_OFFSET);
+ memset(&c, 0, sizeof(c));
+ c.common.opcode = nvme_cmd_flush;
+ c.common.nsid = cpu_to_le32(ns->ns_id);
- immed &= START_STOP_UNIT_CDB_IMMED_MASK;
- pcmod &= START_STOP_UNIT_CDB_POWER_COND_MOD_MASK;
- pc = (pc & START_STOP_UNIT_CDB_POWER_COND_MASK) >> NIBBLE_SHIFT;
- no_flush &= START_STOP_UNIT_CDB_NO_FLUSH_MASK;
- start &= START_STOP_UNIT_CDB_START_MASK;
+ nvme_sc = nvme_submit_sync_cmd(ns->queue, &c, NULL, 0);
+ return nvme_trans_status_code(hdr, nvme_sc);
+}
+
+static int nvme_trans_start_stop(struct nvme_ns *ns, struct sg_io_hdr *hdr,
+ u8 *cmd)
+{
+ u8 immed, pcmod, pc, no_flush, start;
+
+ immed = cmd[1] & 0x01;
+ pcmod = cmd[3] & 0x0f;
+ pc = (cmd[4] & 0xf0) >> 4;
+ no_flush = cmd[4] & 0x04;
+ start = cmd[4] & 0x01;
if (immed != 0) {
- res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
+ return nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
} else {
if (no_flush == 0) {
/* Issue NVME FLUSH command prior to START STOP UNIT */
- memset(&c, 0, sizeof(c));
- c.common.opcode = nvme_cmd_flush;
- c.common.nsid = cpu_to_le32(ns->ns_id);
-
- nvme_sc = nvme_submit_io_cmd(ns->dev, ns, &c, NULL);
- res = nvme_trans_status_code(hdr, nvme_sc);
+ int res = nvme_trans_synchronize_cache(ns, hdr);
if (res)
- goto out;
- if (nvme_sc) {
- res = nvme_sc;
- goto out;
- }
+ return res;
}
/* Setup the expected power state transition */
- res = nvme_trans_power_state(ns, hdr, pc, pcmod, start);
+ return nvme_trans_power_state(ns, hdr, pc, pcmod, start);
}
-
- out:
- return res;
-}
-
-static int nvme_trans_synchronize_cache(struct nvme_ns *ns,
- struct sg_io_hdr *hdr, u8 *cmd)
-{
- int res = SNTI_TRANSLATION_SUCCESS;
- int nvme_sc;
- struct nvme_command c;
-
- memset(&c, 0, sizeof(c));
- c.common.opcode = nvme_cmd_flush;
- c.common.nsid = cpu_to_le32(ns->ns_id);
-
- nvme_sc = nvme_submit_io_cmd(ns->dev, ns, &c, NULL);
-
- res = nvme_trans_status_code(hdr, nvme_sc);
- if (res)
- goto out;
- if (nvme_sc)
- res = nvme_sc;
-
- out:
- return res;
}
static int nvme_trans_format_unit(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *cmd)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res;
u8 parm_hdr_len = 0;
u8 nvme_pf_code = 0;
u8 format_prot_info, long_list, format_data;
- format_prot_info = GET_U8_FROM_CDB(cmd,
- FORMAT_UNIT_CDB_FORMAT_PROT_INFO_OFFSET);
- long_list = GET_U8_FROM_CDB(cmd, FORMAT_UNIT_CDB_LONG_LIST_OFFSET);
- format_data = GET_U8_FROM_CDB(cmd, FORMAT_UNIT_CDB_FORMAT_DATA_OFFSET);
-
- format_prot_info = (format_prot_info &
- FORMAT_UNIT_CDB_FORMAT_PROT_INFO_MASK) >>
- FORMAT_UNIT_CDB_FORMAT_PROT_INFO_SHIFT;
- long_list &= FORMAT_UNIT_CDB_LONG_LIST_MASK;
- format_data &= FORMAT_UNIT_CDB_FORMAT_DATA_MASK;
+ format_prot_info = (cmd[1] & 0xc0) >> 6;
+ long_list = cmd[1] & 0x20;
+ format_data = cmd[1] & 0x10;
if (format_data != 0) {
if (format_prot_info != 0) {
@@ -2779,16 +2273,16 @@ static int nvme_trans_format_unit(struct nvme_ns *ns, struct sg_io_hdr *hdr,
if (parm_hdr_len > 0) {
res = nvme_trans_fmt_get_parm_header(hdr, parm_hdr_len,
format_prot_info, &nvme_pf_code);
- if (res != SNTI_TRANSLATION_SUCCESS)
+ if (res)
goto out;
}
/* Attempt to activate any previously downloaded firmware image */
- res = nvme_trans_send_fw_cmd(ns, hdr, nvme_admin_activate_fw, 0, 0, 0);
+ res = nvme_trans_send_activate_fw_cmd(ns, hdr, 0);
/* Determine Block size and count and send format command */
res = nvme_trans_fmt_set_blk_size_count(ns, hdr);
- if (res != SNTI_TRANSLATION_SUCCESS)
+ if (res)
goto out;
res = nvme_trans_fmt_send_cmd(ns, hdr, nvme_pf_code);
@@ -2801,28 +2295,24 @@ static int nvme_trans_test_unit_ready(struct nvme_ns *ns,
struct sg_io_hdr *hdr,
u8 *cmd)
{
- int res = SNTI_TRANSLATION_SUCCESS;
struct nvme_dev *dev = ns->dev;
if (!(readl(&dev->bar->csts) & NVME_CSTS_RDY))
- res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
+ return nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
NOT_READY, SCSI_ASC_LUN_NOT_READY,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
else
- res = nvme_trans_completion(hdr, SAM_STAT_GOOD, NO_SENSE, 0, 0);
-
- return res;
+ return nvme_trans_completion(hdr, SAM_STAT_GOOD, NO_SENSE, 0, 0);
}
static int nvme_trans_write_buffer(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *cmd)
{
- int res = SNTI_TRANSLATION_SUCCESS;
+ int res = 0;
u32 buffer_offset, parm_list_length;
u8 buffer_id, mode;
- parm_list_length =
- GET_U24_FROM_CDB(cmd, WRITE_BUFFER_CDB_PARM_LIST_LENGTH_OFFSET);
+ parm_list_length = get_unaligned_be24(&cmd[6]);
if (parm_list_length % BYTES_TO_DWORDS != 0) {
/* NVMe expects Firmware file to be a whole number of DWORDS */
res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
@@ -2830,38 +2320,32 @@ static int nvme_trans_write_buffer(struct nvme_ns *ns, struct sg_io_hdr *hdr,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
goto out;
}
- buffer_id = GET_U8_FROM_CDB(cmd, WRITE_BUFFER_CDB_BUFFER_ID_OFFSET);
+ buffer_id = cmd[2];
if (buffer_id > NVME_MAX_FIRMWARE_SLOT) {
res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
goto out;
}
- mode = GET_U8_FROM_CDB(cmd, WRITE_BUFFER_CDB_MODE_OFFSET) &
- WRITE_BUFFER_CDB_MODE_MASK;
- buffer_offset =
- GET_U24_FROM_CDB(cmd, WRITE_BUFFER_CDB_BUFFER_OFFSET_OFFSET);
+ mode = cmd[1] & 0x1f;
+ buffer_offset = get_unaligned_be24(&cmd[3]);
switch (mode) {
case DOWNLOAD_SAVE_ACTIVATE:
- res = nvme_trans_send_fw_cmd(ns, hdr, nvme_admin_download_fw,
+ res = nvme_trans_send_download_fw_cmd(ns, hdr, nvme_admin_download_fw,
parm_list_length, buffer_offset,
buffer_id);
- if (res != SNTI_TRANSLATION_SUCCESS)
+ if (res)
goto out;
- res = nvme_trans_send_fw_cmd(ns, hdr, nvme_admin_activate_fw,
- parm_list_length, buffer_offset,
- buffer_id);
+ res = nvme_trans_send_activate_fw_cmd(ns, hdr, buffer_id);
break;
case DOWNLOAD_SAVE_DEFER_ACTIVATE:
- res = nvme_trans_send_fw_cmd(ns, hdr, nvme_admin_download_fw,
+ res = nvme_trans_send_download_fw_cmd(ns, hdr, nvme_admin_download_fw,
parm_list_length, buffer_offset,
buffer_id);
break;
case ACTIVATE_DEFERRED_MICROCODE:
- res = nvme_trans_send_fw_cmd(ns, hdr, nvme_admin_activate_fw,
- parm_list_length, buffer_offset,
- buffer_id);
+ res = nvme_trans_send_activate_fw_cmd(ns, hdr, buffer_id);
break;
default:
res = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION,
@@ -2890,15 +2374,13 @@ struct scsi_unmap_parm_list {
static int nvme_trans_unmap(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *cmd)
{
- struct nvme_dev *dev = ns->dev;
struct scsi_unmap_parm_list *plist;
struct nvme_dsm_range *range;
struct nvme_command c;
- int i, nvme_sc, res = -ENOMEM;
+ int i, nvme_sc, res;
u16 ndesc, list_len;
- dma_addr_t dma_addr;
- list_len = GET_U16_FROM_CDB(cmd, UNMAP_CDB_PARAM_LIST_LENGTH_OFFSET);
+ list_len = get_unaligned_be16(&cmd[7]);
if (!list_len)
return -EINVAL;
@@ -2907,7 +2389,7 @@ static int nvme_trans_unmap(struct nvme_ns *ns, struct sg_io_hdr *hdr,
return -ENOMEM;
res = nvme_trans_copy_from_user(hdr, plist, list_len);
- if (res != SNTI_TRANSLATION_SUCCESS)
+ if (res)
goto out;
ndesc = be16_to_cpu(plist->unmap_blk_desc_data_len) >> 4;
@@ -2916,10 +2398,11 @@ static int nvme_trans_unmap(struct nvme_ns *ns, struct sg_io_hdr *hdr,
goto out;
}
- range = dma_alloc_coherent(&dev->pci_dev->dev, ndesc * sizeof(*range),
- &dma_addr, GFP_KERNEL);
- if (!range)
+ range = kcalloc(ndesc, sizeof(*range), GFP_KERNEL);
+ if (!range) {
+ res = -ENOMEM;
goto out;
+ }
for (i = 0; i < ndesc; i++) {
range[i].nlb = cpu_to_le32(be32_to_cpu(plist->desc[i].nlb));
@@ -2930,15 +2413,14 @@ static int nvme_trans_unmap(struct nvme_ns *ns, struct sg_io_hdr *hdr,
memset(&c, 0, sizeof(c));
c.dsm.opcode = nvme_cmd_dsm;
c.dsm.nsid = cpu_to_le32(ns->ns_id);
- c.dsm.prp1 = cpu_to_le64(dma_addr);
c.dsm.nr = cpu_to_le32(ndesc - 1);
c.dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD);
- nvme_sc = nvme_submit_io_cmd(dev, ns, &c, NULL);
+ nvme_sc = nvme_submit_sync_cmd(ns->queue, &c, range,
+ ndesc * sizeof(*range));
res = nvme_trans_status_code(hdr, nvme_sc);
- dma_free_coherent(&dev->pci_dev->dev, ndesc * sizeof(*range),
- range, dma_addr);
+ kfree(range);
out:
kfree(plist);
return res;
@@ -2993,13 +2475,16 @@ static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr)
retcode = nvme_trans_mode_sense(ns, hdr, cmd);
break;
case READ_CAPACITY:
- retcode = nvme_trans_read_capacity(ns, hdr, cmd);
+ retcode = nvme_trans_read_capacity(ns, hdr, cmd, 0);
break;
case SERVICE_ACTION_IN_16:
- if (IS_READ_CAP_16(cmd))
- retcode = nvme_trans_read_capacity(ns, hdr, cmd);
- else
+ switch (cmd[1]) {
+ case SAI_READ_CAPACITY_16:
+ retcode = nvme_trans_read_capacity(ns, hdr, cmd, 1);
+ break;
+ default:
goto out;
+ }
break;
case REPORT_LUNS:
retcode = nvme_trans_report_luns(ns, hdr, cmd);
@@ -3015,7 +2500,7 @@ static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr)
retcode = nvme_trans_start_stop(ns, hdr, cmd);
break;
case SYNCHRONIZE_CACHE:
- retcode = nvme_trans_synchronize_cache(ns, hdr, cmd);
+ retcode = nvme_trans_synchronize_cache(ns, hdr);
break;
case FORMAT_UNIT:
retcode = nvme_trans_format_unit(ns, hdr, cmd);
@@ -3053,15 +2538,16 @@ int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr)
if (hdr.cmd_len > BLK_MAX_CDB)
return -EINVAL;
+ /*
+ * A positive return code means a NVMe status, which has been
+ * translated to sense data.
+ */
retcode = nvme_scsi_translate(ns, &hdr);
if (retcode < 0)
return retcode;
- if (retcode > 0)
- retcode = SNTI_TRANSLATION_SUCCESS;
if (copy_to_user(u_hdr, &hdr, sizeof(sg_io_hdr_t)) > 0)
return -EFAULT;
-
- return retcode;
+ return 0;
}
int nvme_sg_get_version_num(int __user *ip)
diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
index 48c50f11f63b..0e287993b778 100644
--- a/drivers/block/paride/paride.c
+++ b/drivers/block/paride/paride.c
@@ -30,6 +30,7 @@
#include <linux/wait.h>
#include <linux/sched.h> /* TASK_* */
#include <linux/parport.h>
+#include <linux/slab.h>
#include "paride.h"
@@ -244,17 +245,19 @@ void paride_unregister(PIP * pr)
EXPORT_SYMBOL(paride_unregister);
-static int pi_register_parport(PIA * pi, int verbose)
+static int pi_register_parport(PIA *pi, int verbose, int unit)
{
struct parport *port;
+ struct pardev_cb par_cb;
port = parport_find_base(pi->port);
if (!port)
return 0;
-
- pi->pardev = parport_register_device(port,
- pi->device, NULL,
- pi_wake_up, NULL, 0, (void *) pi);
+ memset(&par_cb, 0, sizeof(par_cb));
+ par_cb.wakeup = pi_wake_up;
+ par_cb.private = (void *)pi;
+ pi->pardev = parport_register_dev_model(port, pi->device, &par_cb,
+ unit);
parport_put_port(port);
if (!pi->pardev)
return 0;
@@ -311,7 +314,7 @@ static int pi_probe_unit(PIA * pi, int unit, char *scratch, int verbose)
e = pi->proto->max_units;
}
- if (!pi_register_parport(pi, verbose))
+ if (!pi_register_parport(pi, verbose, s))
return 0;
if (pi->proto->test_port) {
@@ -432,3 +435,45 @@ int pi_init(PIA * pi, int autoprobe, int port, int mode,
}
EXPORT_SYMBOL(pi_init);
+
+static int pi_probe(struct pardevice *par_dev)
+{
+ struct device_driver *drv = par_dev->dev.driver;
+ int len = strlen(drv->name);
+
+ if (strncmp(par_dev->name, drv->name, len))
+ return -ENODEV;
+
+ return 0;
+}
+
+void *pi_register_driver(char *name)
+{
+ struct parport_driver *parp_drv;
+ int ret;
+
+ parp_drv = kzalloc(sizeof(*parp_drv), GFP_KERNEL);
+ if (!parp_drv)
+ return NULL;
+
+ parp_drv->name = name;
+ parp_drv->probe = pi_probe;
+ parp_drv->devmodel = true;
+
+ ret = parport_register_driver(parp_drv);
+ if (ret) {
+ kfree(parp_drv);
+ return NULL;
+ }
+ return (void *)parp_drv;
+}
+EXPORT_SYMBOL(pi_register_driver);
+
+void pi_unregister_driver(void *_drv)
+{
+ struct parport_driver *drv = _drv;
+
+ parport_unregister_driver(drv);
+ kfree(drv);
+}
+EXPORT_SYMBOL(pi_unregister_driver);
diff --git a/drivers/block/paride/paride.h b/drivers/block/paride/paride.h
index 2bddbf45518b..ddb9e589da7f 100644
--- a/drivers/block/paride/paride.h
+++ b/drivers/block/paride/paride.h
@@ -165,6 +165,8 @@ typedef struct pi_protocol PIP;
extern int paride_register( PIP * );
extern void paride_unregister ( PIP * );
+void *pi_register_driver(char *);
+void pi_unregister_driver(void *);
#endif /* __DRIVERS_PARIDE_H__ */
/* end of paride.h */
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index 3b7c9f1be484..93362362aa55 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -221,6 +221,7 @@ static int pcd_busy; /* request being processed ? */
static int pcd_sector; /* address of next requested sector */
static int pcd_count; /* number of blocks still to do */
static char *pcd_buf; /* buffer for request in progress */
+static void *par_drv; /* reference of parport driver */
/* kernel glue structures */
@@ -690,6 +691,12 @@ static int pcd_detect(void)
printk("%s: %s version %s, major %d, nice %d\n",
name, name, PCD_VERSION, major, nice);
+ par_drv = pi_register_driver(name);
+ if (!par_drv) {
+ pr_err("failed to register %s driver\n", name);
+ return -1;
+ }
+
k = 0;
if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
cd = pcd;
@@ -723,6 +730,7 @@ static int pcd_detect(void)
printk("%s: No CD-ROM drive found\n", name);
for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++)
put_disk(cd->disk);
+ pi_unregister_driver(par_drv);
return -1;
}
@@ -984,6 +992,7 @@ static void __exit pcd_exit(void)
}
blk_cleanup_queue(pcd_queue);
unregister_blkdev(major, name);
+ pi_unregister_driver(par_drv);
}
MODULE_LICENSE("GPL");
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index d48715b287e6..b9242d78283d 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -247,6 +247,8 @@ static char *pd_errs[17] = { "ERR", "INDEX", "ECC", "DRQ", "SEEK", "WRERR",
"IDNF", "MC", "UNC", "???", "TMO"
};
+static void *par_drv; /* reference of parport driver */
+
static inline int status_reg(struct pd_unit *disk)
{
return pi_read_regr(disk->pi, 1, 6);
@@ -442,7 +444,7 @@ static char *pd_buf; /* buffer for request in progress */
static enum action do_pd_io_start(void)
{
- if (pd_req->cmd_type == REQ_TYPE_SPECIAL) {
+ if (pd_req->cmd_type == REQ_TYPE_DRV_PRIV) {
phase = pd_special;
return pd_special();
}
@@ -725,7 +727,7 @@ static int pd_special_command(struct pd_unit *disk,
if (IS_ERR(rq))
return PTR_ERR(rq);
- rq->cmd_type = REQ_TYPE_SPECIAL;
+ rq->cmd_type = REQ_TYPE_DRV_PRIV;
rq->special = func;
err = blk_execute_rq(disk->gd->queue, disk->gd, rq, 0);
@@ -872,6 +874,12 @@ static int pd_detect(void)
pd_drive_count++;
}
+ par_drv = pi_register_driver(name);
+ if (!par_drv) {
+ pr_err("failed to register %s driver\n", name);
+ return -1;
+ }
+
if (pd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
disk = pd;
if (pi_init(disk->pi, 1, -1, -1, -1, -1, -1, pd_scratch,
@@ -902,8 +910,10 @@ static int pd_detect(void)
found = 1;
}
}
- if (!found)
+ if (!found) {
printk("%s: no valid drive found\n", name);
+ pi_unregister_driver(par_drv);
+ }
return found;
}
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index 9a15fd3c9349..7a7d977a76c5 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -264,6 +264,7 @@ static int pf_cmd; /* current command READ/WRITE */
static struct pf_unit *pf_current;/* unit of current request */
static int pf_mask; /* stopper for pseudo-int */
static char *pf_buf; /* buffer for request in progress */
+static void *par_drv; /* reference of parport driver */
/* kernel glue structures */
@@ -703,6 +704,11 @@ static int pf_detect(void)
printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
name, name, PF_VERSION, major, cluster, nice);
+ par_drv = pi_register_driver(name);
+ if (!par_drv) {
+ pr_err("failed to register %s driver\n", name);
+ return -1;
+ }
k = 0;
if (pf_drive_count == 0) {
if (pi_init(pf->pi, 1, -1, -1, -1, -1, -1, pf_scratch, PI_PF,
@@ -735,6 +741,7 @@ static int pf_detect(void)
printk("%s: No ATAPI disk detected\n", name);
for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++)
put_disk(pf->disk);
+ pi_unregister_driver(par_drv);
return -1;
}
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
index 876d0c3eaf58..bfbd4c852dd9 100644
--- a/drivers/block/paride/pg.c
+++ b/drivers/block/paride/pg.c
@@ -227,6 +227,7 @@ static int pg_identify(struct pg *dev, int log);
static char pg_scratch[512]; /* scratch block buffer */
static struct class *pg_class;
+static void *par_drv; /* reference of parport driver */
/* kernel glue structures */
@@ -481,6 +482,12 @@ static int pg_detect(void)
printk("%s: %s version %s, major %d\n", name, name, PG_VERSION, major);
+ par_drv = pi_register_driver(name);
+ if (!par_drv) {
+ pr_err("failed to register %s driver\n", name);
+ return -1;
+ }
+
k = 0;
if (pg_drive_count == 0) {
if (pi_init(dev->pi, 1, -1, -1, -1, -1, -1, pg_scratch,
@@ -511,6 +518,7 @@ static int pg_detect(void)
if (k)
return 0;
+ pi_unregister_driver(par_drv);
printk("%s: No ATAPI device detected\n", name);
return -1;
}
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index 2596042eb987..1740d75e8a32 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -232,6 +232,7 @@ static int pt_identify(struct pt_unit *tape);
static struct pt_unit pt[PT_UNITS];
static char pt_scratch[512]; /* scratch block buffer */
+static void *par_drv; /* reference of parport driver */
/* kernel glue structures */
@@ -605,6 +606,12 @@ static int pt_detect(void)
printk("%s: %s version %s, major %d\n", name, name, PT_VERSION, major);
+ par_drv = pi_register_driver(name);
+ if (!par_drv) {
+ pr_err("failed to register %s driver\n", name);
+ return -1;
+ }
+
specified = 0;
for (unit = 0; unit < PT_UNITS; unit++) {
struct pt_unit *tape = &pt[unit];
@@ -644,6 +651,7 @@ static int pt_detect(void)
if (found)
return 0;
+ pi_unregister_driver(par_drv);
printk("%s: No ATAPI tape drive detected\n", name);
return -1;
}
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 09e628dafd9d..4c20c228184c 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -61,6 +61,7 @@
#include <linux/freezer.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/backing-dev.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/scsi.h>
diff --git a/drivers/block/pmem.c b/drivers/block/pmem.c
index eabf4a8d0085..095dfaadcaa5 100644
--- a/drivers/block/pmem.c
+++ b/drivers/block/pmem.c
@@ -139,11 +139,11 @@ static struct pmem_device *pmem_alloc(struct device *dev, struct resource *res)
}
/*
- * Map the memory as non-cachable, as we can't write back the contents
+ * Map the memory as write-through, as we can't write back the contents
* of the CPU caches in case of a crash.
*/
err = -ENOMEM;
- pmem->virt_addr = ioremap_nocache(pmem->phys_addr, pmem->size);
+ pmem->virt_addr = ioremap_wt(pmem->phys_addr, pmem->size);
if (!pmem->virt_addr)
goto out_release_region;
diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c
index ef45cfb98fd2..b1612eb16172 100644
--- a/drivers/block/ps3vram.c
+++ b/drivers/block/ps3vram.c
@@ -1,5 +1,5 @@
/*
- * ps3vram - Use extra PS3 video ram as MTD block device.
+ * ps3vram - Use extra PS3 video ram as block device.
*
* Copyright 2009 Sony Corporation
*
@@ -73,8 +73,8 @@ struct ps3vram_priv {
u64 memory_handle;
u64 context_handle;
- u32 *ctrl;
- void *reports;
+ u32 __iomem *ctrl;
+ void __iomem *reports;
u8 *xdr_buf;
u32 *fifo_base;
@@ -104,7 +104,7 @@ static char *size = "256M";
module_param(size, charp, 0);
MODULE_PARM_DESC(size, "memory size");
-static u32 *ps3vram_get_notifier(void *reports, int notifier)
+static u32 __iomem *ps3vram_get_notifier(void __iomem *reports, int notifier)
{
return reports + DMA_NOTIFIER_OFFSET_BASE +
DMA_NOTIFIER_SIZE * notifier;
@@ -113,22 +113,22 @@ static u32 *ps3vram_get_notifier(void *reports, int notifier)
static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
- u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
+ u32 __iomem *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
int i;
for (i = 0; i < 4; i++)
- notify[i] = 0xffffffff;
+ iowrite32be(0xffffffff, notify + i);
}
static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev,
unsigned int timeout_ms)
{
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
- u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
+ u32 __iomem *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
unsigned long timeout;
for (timeout = 20; timeout; timeout--) {
- if (!notify[3])
+ if (!ioread32be(notify + 3))
return 0;
udelay(10);
}
@@ -136,7 +136,7 @@ static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev,
timeout = jiffies + msecs_to_jiffies(timeout_ms);
do {
- if (!notify[3])
+ if (!ioread32be(notify + 3))
return 0;
msleep(1);
} while (time_before(jiffies, timeout));
@@ -148,8 +148,8 @@ static void ps3vram_init_ring(struct ps3_system_bus_device *dev)
{
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
- priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
- priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET;
+ iowrite32be(FIFO_BASE + FIFO_OFFSET, priv->ctrl + CTRL_PUT);
+ iowrite32be(FIFO_BASE + FIFO_OFFSET, priv->ctrl + CTRL_GET);
}
static int ps3vram_wait_ring(struct ps3_system_bus_device *dev,
@@ -159,14 +159,14 @@ static int ps3vram_wait_ring(struct ps3_system_bus_device *dev,
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
do {
- if (priv->ctrl[CTRL_PUT] == priv->ctrl[CTRL_GET])
+ if (ioread32be(priv->ctrl + CTRL_PUT) == ioread32be(priv->ctrl + CTRL_GET))
return 0;
msleep(1);
} while (time_before(jiffies, timeout));
dev_warn(&dev->core, "FIFO timeout (%08x/%08x/%08x)\n",
- priv->ctrl[CTRL_PUT], priv->ctrl[CTRL_GET],
- priv->ctrl[CTRL_TOP]);
+ ioread32be(priv->ctrl + CTRL_PUT), ioread32be(priv->ctrl + CTRL_GET),
+ ioread32be(priv->ctrl + CTRL_TOP));
return -ETIMEDOUT;
}
@@ -189,7 +189,7 @@ static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev)
ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET));
- priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
+ iowrite32be(FIFO_BASE + FIFO_OFFSET, priv->ctrl + CTRL_PUT);
/* asking the HV for a blit will kick the FIFO */
status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0);
@@ -207,8 +207,8 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev)
mutex_lock(&ps3_gpu_mutex);
- priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET +
- (priv->fifo_ptr - priv->fifo_base) * sizeof(u32);
+ iowrite32be(FIFO_BASE + FIFO_OFFSET + (priv->fifo_ptr - priv->fifo_base)
+ * sizeof(u32), priv->ctrl + CTRL_PUT);
/* asking the HV for a blit will kick the FIFO */
status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0);
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 5d552857de41..59c91d49b14b 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -620,7 +620,7 @@ static int carm_array_info (struct carm_host *host, unsigned int array_idx)
spin_unlock_irq(&host->lock);
DPRINTK("blk_execute_rq_nowait, tag == %u\n", idx);
- crq->rq->cmd_type = REQ_TYPE_SPECIAL;
+ crq->rq->cmd_type = REQ_TYPE_DRV_PRIV;
crq->rq->special = crq;
blk_execute_rq_nowait(host->oob_q, NULL, crq->rq, true, NULL);
@@ -661,7 +661,7 @@ static int carm_send_special (struct carm_host *host, carm_sspc_t func)
crq->msg_bucket = (u32) rc;
DPRINTK("blk_execute_rq_nowait, tag == %u\n", idx);
- crq->rq->cmd_type = REQ_TYPE_SPECIAL;
+ crq->rq->cmd_type = REQ_TYPE_DRV_PRIV;
crq->rq->special = crq;
blk_execute_rq_nowait(host->oob_q, NULL, crq->rq, true, NULL);
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 5ea2f0bbbc7c..d4d05f064d39 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -124,7 +124,7 @@ static inline void virtblk_request_done(struct request *req)
req->resid_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.residual);
req->sense_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.sense_len);
req->errors = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.errors);
- } else if (req->cmd_type == REQ_TYPE_SPECIAL) {
+ } else if (req->cmd_type == REQ_TYPE_DRV_PRIV) {
req->errors = (error != 0);
}
@@ -188,7 +188,7 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx,
vbr->out_hdr.sector = 0;
vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
break;
- case REQ_TYPE_SPECIAL:
+ case REQ_TYPE_DRV_PRIV:
vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID);
vbr->out_hdr.sector = 0;
vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
@@ -251,7 +251,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
return PTR_ERR(req);
}
- req->cmd_type = REQ_TYPE_SPECIAL;
+ req->cmd_type = REQ_TYPE_DRV_PRIV;
err = blk_execute_rq(vblk->disk->queue, vblk->disk, req, false);
blk_put_request(req);
diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
index 6489c0fd0ea6..386ba3d1a6ee 100644
--- a/drivers/block/zram/Kconfig
+++ b/drivers/block/zram/Kconfig
@@ -23,12 +23,4 @@ config ZRAM_LZ4_COMPRESS
default n
help
This option enables LZ4 compression algorithm support. Compression
- algorithm can be changed using `comp_algorithm' device attribute.
-
-config ZRAM_DEBUG
- bool "Compressed RAM block device debug support"
- depends on ZRAM
- default n
- help
- This option adds additional debugging code to the compressed
- RAM block device driver.
+ algorithm can be changed using `comp_algorithm' device attribute. \ No newline at end of file
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index f1ff39a3d1c1..965d1afb0eaa 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -274,7 +274,7 @@ ssize_t zcomp_available_show(const char *comp, char *buf)
int i = 0;
while (backends[i]) {
- if (sysfs_streq(comp, backends[i]->name))
+ if (!strcmp(comp, backends[i]->name))
sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
"[%s] ", backends[i]->name);
else
@@ -286,6 +286,11 @@ ssize_t zcomp_available_show(const char *comp, char *buf)
return sz;
}
+bool zcomp_available_algorithm(const char *comp)
+{
+ return find_backend(comp) != NULL;
+}
+
bool zcomp_set_max_streams(struct zcomp *comp, int num_strm)
{
return comp->set_max_streams(comp, num_strm);
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
index c59d1fca72c0..46e2b9f8f1f0 100644
--- a/drivers/block/zram/zcomp.h
+++ b/drivers/block/zram/zcomp.h
@@ -51,6 +51,7 @@ struct zcomp {
};
ssize_t zcomp_available_show(const char *comp, char *buf);
+bool zcomp_available_algorithm(const char *comp);
struct zcomp *zcomp_create(const char *comp, int max_strm);
void zcomp_destroy(struct zcomp *comp);
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 6e134f4759c0..fb655e8d1e3b 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -15,10 +15,6 @@
#define KMSG_COMPONENT "zram"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-#ifdef CONFIG_ZRAM_DEBUG
-#define DEBUG
-#endif
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/bio.h>
@@ -32,12 +28,16 @@
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/err.h>
+#include <linux/idr.h>
+#include <linux/sysfs.h>
#include "zram_drv.h"
-/* Globals */
+static DEFINE_IDR(zram_index_idr);
+/* idr index must be protected */
+static DEFINE_MUTEX(zram_index_mutex);
+
static int zram_major;
-static struct zram *zram_devices;
static const char *default_compressor = "lzo";
/* Module params (documentation at end) */
@@ -53,7 +53,7 @@ static inline void deprecated_attr_warn(const char *name)
}
#define ZRAM_ATTR_RO(name) \
-static ssize_t name##_show(struct device *d, \
+static ssize_t name##_show(struct device *d, \
struct device_attribute *attr, char *b) \
{ \
struct zram *zram = dev_to_zram(d); \
@@ -74,33 +74,117 @@ static inline struct zram *dev_to_zram(struct device *dev)
return (struct zram *)dev_to_disk(dev)->private_data;
}
-static ssize_t compact_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
+/* flag operations require table entry bit_spin_lock() being held */
+static int zram_test_flag(struct zram_meta *meta, u32 index,
+ enum zram_pageflags flag)
{
- unsigned long nr_migrated;
- struct zram *zram = dev_to_zram(dev);
- struct zram_meta *meta;
+ return meta->table[index].value & BIT(flag);
+}
- down_read(&zram->init_lock);
- if (!init_done(zram)) {
- up_read(&zram->init_lock);
- return -EINVAL;
- }
+static void zram_set_flag(struct zram_meta *meta, u32 index,
+ enum zram_pageflags flag)
+{
+ meta->table[index].value |= BIT(flag);
+}
- meta = zram->meta;
- nr_migrated = zs_compact(meta->mem_pool);
- atomic64_add(nr_migrated, &zram->stats.num_migrated);
- up_read(&zram->init_lock);
+static void zram_clear_flag(struct zram_meta *meta, u32 index,
+ enum zram_pageflags flag)
+{
+ meta->table[index].value &= ~BIT(flag);
+}
- return len;
+static size_t zram_get_obj_size(struct zram_meta *meta, u32 index)
+{
+ return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1);
}
-static ssize_t disksize_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static void zram_set_obj_size(struct zram_meta *meta,
+ u32 index, size_t size)
{
- struct zram *zram = dev_to_zram(dev);
+ unsigned long flags = meta->table[index].value >> ZRAM_FLAG_SHIFT;
- return scnprintf(buf, PAGE_SIZE, "%llu\n", zram->disksize);
+ meta->table[index].value = (flags << ZRAM_FLAG_SHIFT) | size;
+}
+
+static inline int is_partial_io(struct bio_vec *bvec)
+{
+ return bvec->bv_len != PAGE_SIZE;
+}
+
+/*
+ * Check if request is within bounds and aligned on zram logical blocks.
+ */
+static inline int valid_io_request(struct zram *zram,
+ sector_t start, unsigned int size)
+{
+ u64 end, bound;
+
+ /* unaligned request */
+ if (unlikely(start & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)))
+ return 0;
+ if (unlikely(size & (ZRAM_LOGICAL_BLOCK_SIZE - 1)))
+ return 0;
+
+ end = start + (size >> SECTOR_SHIFT);
+ bound = zram->disksize >> SECTOR_SHIFT;
+ /* out of range range */
+ if (unlikely(start >= bound || end > bound || start > end))
+ return 0;
+
+ /* I/O request is valid */
+ return 1;
+}
+
+static void update_position(u32 *index, int *offset, struct bio_vec *bvec)
+{
+ if (*offset + bvec->bv_len >= PAGE_SIZE)
+ (*index)++;
+ *offset = (*offset + bvec->bv_len) % PAGE_SIZE;
+}
+
+static inline void update_used_max(struct zram *zram,
+ const unsigned long pages)
+{
+ unsigned long old_max, cur_max;
+
+ old_max = atomic_long_read(&zram->stats.max_used_pages);
+
+ do {
+ cur_max = old_max;
+ if (pages > cur_max)
+ old_max = atomic_long_cmpxchg(
+ &zram->stats.max_used_pages, cur_max, pages);
+ } while (old_max != cur_max);
+}
+
+static int page_zero_filled(void *ptr)
+{
+ unsigned int pos;
+ unsigned long *page;
+
+ page = (unsigned long *)ptr;
+
+ for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) {
+ if (page[pos])
+ return 0;
+ }
+
+ return 1;
+}
+
+static void handle_zero_page(struct bio_vec *bvec)
+{
+ struct page *page = bvec->bv_page;
+ void *user_mem;
+
+ user_mem = kmap_atomic(page);
+ if (is_partial_io(bvec))
+ memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
+ else
+ clear_page(user_mem);
+ kunmap_atomic(user_mem);
+
+ flush_dcache_page(page);
}
static ssize_t initstate_show(struct device *dev,
@@ -116,6 +200,14 @@ static ssize_t initstate_show(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%u\n", val);
}
+static ssize_t disksize_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", zram->disksize);
+}
+
static ssize_t orig_data_size_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -143,19 +235,6 @@ static ssize_t mem_used_total_show(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%llu\n", val << PAGE_SHIFT);
}
-static ssize_t max_comp_streams_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int val;
- struct zram *zram = dev_to_zram(dev);
-
- down_read(&zram->init_lock);
- val = zram->max_comp_streams;
- up_read(&zram->init_lock);
-
- return scnprintf(buf, PAGE_SIZE, "%d\n", val);
-}
-
static ssize_t mem_limit_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -225,6 +304,19 @@ static ssize_t mem_used_max_store(struct device *dev,
return len;
}
+static ssize_t max_comp_streams_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int val;
+ struct zram *zram = dev_to_zram(dev);
+
+ down_read(&zram->init_lock);
+ val = zram->max_comp_streams;
+ up_read(&zram->init_lock);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
static ssize_t max_comp_streams_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
@@ -271,6 +363,8 @@ static ssize_t comp_algorithm_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
struct zram *zram = dev_to_zram(dev);
+ size_t sz;
+
down_write(&zram->init_lock);
if (init_done(zram)) {
up_write(&zram->init_lock);
@@ -278,69 +372,108 @@ static ssize_t comp_algorithm_store(struct device *dev,
return -EBUSY;
}
strlcpy(zram->compressor, buf, sizeof(zram->compressor));
+
+ /* ignore trailing newline */
+ sz = strlen(zram->compressor);
+ if (sz > 0 && zram->compressor[sz - 1] == '\n')
+ zram->compressor[sz - 1] = 0x00;
+
+ if (!zcomp_available_algorithm(zram->compressor))
+ len = -EINVAL;
+
up_write(&zram->init_lock);
return len;
}
-/* flag operations needs meta->tb_lock */
-static int zram_test_flag(struct zram_meta *meta, u32 index,
- enum zram_pageflags flag)
+static ssize_t compact_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
{
- return meta->table[index].value & BIT(flag);
-}
+ unsigned long nr_migrated;
+ struct zram *zram = dev_to_zram(dev);
+ struct zram_meta *meta;
-static void zram_set_flag(struct zram_meta *meta, u32 index,
- enum zram_pageflags flag)
-{
- meta->table[index].value |= BIT(flag);
-}
+ down_read(&zram->init_lock);
+ if (!init_done(zram)) {
+ up_read(&zram->init_lock);
+ return -EINVAL;
+ }
-static void zram_clear_flag(struct zram_meta *meta, u32 index,
- enum zram_pageflags flag)
-{
- meta->table[index].value &= ~BIT(flag);
+ meta = zram->meta;
+ nr_migrated = zs_compact(meta->mem_pool);
+ atomic64_add(nr_migrated, &zram->stats.num_migrated);
+ up_read(&zram->init_lock);
+
+ return len;
}
-static size_t zram_get_obj_size(struct zram_meta *meta, u32 index)
+static ssize_t io_stat_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1);
+ struct zram *zram = dev_to_zram(dev);
+ ssize_t ret;
+
+ down_read(&zram->init_lock);
+ ret = scnprintf(buf, PAGE_SIZE,
+ "%8llu %8llu %8llu %8llu\n",
+ (u64)atomic64_read(&zram->stats.failed_reads),
+ (u64)atomic64_read(&zram->stats.failed_writes),
+ (u64)atomic64_read(&zram->stats.invalid_io),
+ (u64)atomic64_read(&zram->stats.notify_free));
+ up_read(&zram->init_lock);
+
+ return ret;
}
-static void zram_set_obj_size(struct zram_meta *meta,
- u32 index, size_t size)
+static ssize_t mm_stat_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- unsigned long flags = meta->table[index].value >> ZRAM_FLAG_SHIFT;
+ struct zram *zram = dev_to_zram(dev);
+ u64 orig_size, mem_used = 0;
+ long max_used;
+ ssize_t ret;
- meta->table[index].value = (flags << ZRAM_FLAG_SHIFT) | size;
+ down_read(&zram->init_lock);
+ if (init_done(zram))
+ mem_used = zs_get_total_pages(zram->meta->mem_pool);
+
+ orig_size = atomic64_read(&zram->stats.pages_stored);
+ max_used = atomic_long_read(&zram->stats.max_used_pages);
+
+ ret = scnprintf(buf, PAGE_SIZE,
+ "%8llu %8llu %8llu %8lu %8ld %8llu %8llu\n",
+ orig_size << PAGE_SHIFT,
+ (u64)atomic64_read(&zram->stats.compr_data_size),
+ mem_used << PAGE_SHIFT,
+ zram->limit_pages << PAGE_SHIFT,
+ max_used << PAGE_SHIFT,
+ (u64)atomic64_read(&zram->stats.zero_pages),
+ (u64)atomic64_read(&zram->stats.num_migrated));
+ up_read(&zram->init_lock);
+
+ return ret;
}
-static inline int is_partial_io(struct bio_vec *bvec)
+static DEVICE_ATTR_RO(io_stat);
+static DEVICE_ATTR_RO(mm_stat);
+ZRAM_ATTR_RO(num_reads);
+ZRAM_ATTR_RO(num_writes);
+ZRAM_ATTR_RO(failed_reads);
+ZRAM_ATTR_RO(failed_writes);
+ZRAM_ATTR_RO(invalid_io);
+ZRAM_ATTR_RO(notify_free);
+ZRAM_ATTR_RO(zero_pages);
+ZRAM_ATTR_RO(compr_data_size);
+
+static inline bool zram_meta_get(struct zram *zram)
{
- return bvec->bv_len != PAGE_SIZE;
+ if (atomic_inc_not_zero(&zram->refcount))
+ return true;
+ return false;
}
-/*
- * Check if request is within bounds and aligned on zram logical blocks.
- */
-static inline int valid_io_request(struct zram *zram,
- sector_t start, unsigned int size)
+static inline void zram_meta_put(struct zram *zram)
{
- u64 end, bound;
-
- /* unaligned request */
- if (unlikely(start & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)))
- return 0;
- if (unlikely(size & (ZRAM_LOGICAL_BLOCK_SIZE - 1)))
- return 0;
-
- end = start + (size >> SECTOR_SHIFT);
- bound = zram->disksize >> SECTOR_SHIFT;
- /* out of range range */
- if (unlikely(start >= bound || end > bound || start > end))
- return 0;
-
- /* I/O request is valid */
- return 1;
+ atomic_dec(&zram->refcount);
}
static void zram_meta_free(struct zram_meta *meta, u64 disksize)
@@ -394,56 +527,6 @@ out_error:
return NULL;
}
-static inline bool zram_meta_get(struct zram *zram)
-{
- if (atomic_inc_not_zero(&zram->refcount))
- return true;
- return false;
-}
-
-static inline void zram_meta_put(struct zram *zram)
-{
- atomic_dec(&zram->refcount);
-}
-
-static void update_position(u32 *index, int *offset, struct bio_vec *bvec)
-{
- if (*offset + bvec->bv_len >= PAGE_SIZE)
- (*index)++;
- *offset = (*offset + bvec->bv_len) % PAGE_SIZE;
-}
-
-static int page_zero_filled(void *ptr)
-{
- unsigned int pos;
- unsigned long *page;
-
- page = (unsigned long *)ptr;
-
- for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) {
- if (page[pos])
- return 0;
- }
-
- return 1;
-}
-
-static void handle_zero_page(struct bio_vec *bvec)
-{
- struct page *page = bvec->bv_page;
- void *user_mem;
-
- user_mem = kmap_atomic(page);
- if (is_partial_io(bvec))
- memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
- else
- clear_page(user_mem);
- kunmap_atomic(user_mem);
-
- flush_dcache_page(page);
-}
-
-
/*
* To protect concurrent access to the same index entry,
* caller should hold this table index entry's bit_spinlock to
@@ -561,21 +644,6 @@ out_cleanup:
return ret;
}
-static inline void update_used_max(struct zram *zram,
- const unsigned long pages)
-{
- unsigned long old_max, cur_max;
-
- old_max = atomic_long_read(&zram->stats.max_used_pages);
-
- do {
- cur_max = old_max;
- if (pages > cur_max)
- old_max = atomic_long_cmpxchg(
- &zram->stats.max_used_pages, cur_max, pages);
- } while (old_max != cur_max);
-}
-
static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
int offset)
{
@@ -585,8 +653,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
struct page *page;
unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
struct zram_meta *meta = zram->meta;
- struct zcomp_strm *zstrm;
- bool locked = false;
+ struct zcomp_strm *zstrm = NULL;
unsigned long alloced_pages;
page = bvec->bv_page;
@@ -606,7 +673,6 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
}
zstrm = zcomp_strm_find(zram->comp);
- locked = true;
user_mem = kmap_atomic(page);
if (is_partial_io(bvec)) {
@@ -678,7 +744,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
}
zcomp_strm_release(zram->comp, zstrm);
- locked = false;
+ zstrm = NULL;
zs_unmap_object(meta->mem_pool, handle);
/*
@@ -696,42 +762,13 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
atomic64_add(clen, &zram->stats.compr_data_size);
atomic64_inc(&zram->stats.pages_stored);
out:
- if (locked)
+ if (zstrm)
zcomp_strm_release(zram->comp, zstrm);
if (is_partial_io(bvec))
kfree(uncmem);
return ret;
}
-static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
- int offset, int rw)
-{
- unsigned long start_time = jiffies;
- int ret;
-
- generic_start_io_acct(rw, bvec->bv_len >> SECTOR_SHIFT,
- &zram->disk->part0);
-
- if (rw == READ) {
- atomic64_inc(&zram->stats.num_reads);
- ret = zram_bvec_read(zram, bvec, index, offset);
- } else {
- atomic64_inc(&zram->stats.num_writes);
- ret = zram_bvec_write(zram, bvec, index, offset);
- }
-
- generic_end_io_acct(rw, &zram->disk->part0, start_time);
-
- if (unlikely(ret)) {
- if (rw == READ)
- atomic64_inc(&zram->stats.failed_reads);
- else
- atomic64_inc(&zram->stats.failed_writes);
- }
-
- return ret;
-}
-
/*
* zram_bio_discard - handler on discard request
* @index: physical block index in PAGE_SIZE units
@@ -771,151 +808,32 @@ static void zram_bio_discard(struct zram *zram, u32 index,
}
}
-static void zram_reset_device(struct zram *zram)
-{
- struct zram_meta *meta;
- struct zcomp *comp;
- u64 disksize;
-
- down_write(&zram->init_lock);
-
- zram->limit_pages = 0;
-
- if (!init_done(zram)) {
- up_write(&zram->init_lock);
- return;
- }
-
- meta = zram->meta;
- comp = zram->comp;
- disksize = zram->disksize;
- /*
- * Refcount will go down to 0 eventually and r/w handler
- * cannot handle further I/O so it will bail out by
- * check zram_meta_get.
- */
- zram_meta_put(zram);
- /*
- * We want to free zram_meta in process context to avoid
- * deadlock between reclaim path and any other locks.
- */
- wait_event(zram->io_done, atomic_read(&zram->refcount) == 0);
-
- /* Reset stats */
- memset(&zram->stats, 0, sizeof(zram->stats));
- zram->disksize = 0;
- zram->max_comp_streams = 1;
-
- set_capacity(zram->disk, 0);
- part_stat_set_all(&zram->disk->part0, 0);
-
- up_write(&zram->init_lock);
- /* I/O operation under all of CPU are done so let's free */
- zram_meta_free(meta, disksize);
- zcomp_destroy(comp);
-}
-
-static ssize_t disksize_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
-{
- u64 disksize;
- struct zcomp *comp;
- struct zram_meta *meta;
- struct zram *zram = dev_to_zram(dev);
- int err;
-
- disksize = memparse(buf, NULL);
- if (!disksize)
- return -EINVAL;
-
- disksize = PAGE_ALIGN(disksize);
- meta = zram_meta_alloc(zram->disk->first_minor, disksize);
- if (!meta)
- return -ENOMEM;
-
- comp = zcomp_create(zram->compressor, zram->max_comp_streams);
- if (IS_ERR(comp)) {
- pr_info("Cannot initialise %s compressing backend\n",
- zram->compressor);
- err = PTR_ERR(comp);
- goto out_free_meta;
- }
-
- down_write(&zram->init_lock);
- if (init_done(zram)) {
- pr_info("Cannot change disksize for initialized device\n");
- err = -EBUSY;
- goto out_destroy_comp;
- }
-
- init_waitqueue_head(&zram->io_done);
- atomic_set(&zram->refcount, 1);
- zram->meta = meta;
- zram->comp = comp;
- zram->disksize = disksize;
- set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
- up_write(&zram->init_lock);
-
- /*
- * Revalidate disk out of the init_lock to avoid lockdep splat.
- * It's okay because disk's capacity is protected by init_lock
- * so that revalidate_disk always sees up-to-date capacity.
- */
- revalidate_disk(zram->disk);
-
- return len;
-
-out_destroy_comp:
- up_write(&zram->init_lock);
- zcomp_destroy(comp);
-out_free_meta:
- zram_meta_free(meta, disksize);
- return err;
-}
-
-static ssize_t reset_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
+static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
+ int offset, int rw)
{
+ unsigned long start_time = jiffies;
int ret;
- unsigned short do_reset;
- struct zram *zram;
- struct block_device *bdev;
- zram = dev_to_zram(dev);
- bdev = bdget_disk(zram->disk, 0);
-
- if (!bdev)
- return -ENOMEM;
+ generic_start_io_acct(rw, bvec->bv_len >> SECTOR_SHIFT,
+ &zram->disk->part0);
- mutex_lock(&bdev->bd_mutex);
- /* Do not reset an active device! */
- if (bdev->bd_openers) {
- ret = -EBUSY;
- goto out;
+ if (rw == READ) {
+ atomic64_inc(&zram->stats.num_reads);
+ ret = zram_bvec_read(zram, bvec, index, offset);
+ } else {
+ atomic64_inc(&zram->stats.num_writes);
+ ret = zram_bvec_write(zram, bvec, index, offset);
}
- ret = kstrtou16(buf, 10, &do_reset);
- if (ret)
- goto out;
+ generic_end_io_acct(rw, &zram->disk->part0, start_time);
- if (!do_reset) {
- ret = -EINVAL;
- goto out;
+ if (unlikely(ret)) {
+ if (rw == READ)
+ atomic64_inc(&zram->stats.failed_reads);
+ else
+ atomic64_inc(&zram->stats.failed_writes);
}
- /* Make sure all pending I/O is finished */
- fsync_bdev(bdev);
- zram_reset_device(zram);
-
- mutex_unlock(&bdev->bd_mutex);
- revalidate_disk(zram->disk);
- bdput(bdev);
-
- return len;
-
-out:
- mutex_unlock(&bdev->bd_mutex);
- bdput(bdev);
return ret;
}
@@ -1055,80 +973,185 @@ out:
return err;
}
-static const struct block_device_operations zram_devops = {
- .swap_slot_free_notify = zram_slot_free_notify,
- .rw_page = zram_rw_page,
- .owner = THIS_MODULE
-};
+static void zram_reset_device(struct zram *zram)
+{
+ struct zram_meta *meta;
+ struct zcomp *comp;
+ u64 disksize;
-static DEVICE_ATTR_WO(compact);
-static DEVICE_ATTR_RW(disksize);
-static DEVICE_ATTR_RO(initstate);
-static DEVICE_ATTR_WO(reset);
-static DEVICE_ATTR_RO(orig_data_size);
-static DEVICE_ATTR_RO(mem_used_total);
-static DEVICE_ATTR_RW(mem_limit);
-static DEVICE_ATTR_RW(mem_used_max);
-static DEVICE_ATTR_RW(max_comp_streams);
-static DEVICE_ATTR_RW(comp_algorithm);
+ down_write(&zram->init_lock);
-static ssize_t io_stat_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ zram->limit_pages = 0;
+
+ if (!init_done(zram)) {
+ up_write(&zram->init_lock);
+ return;
+ }
+
+ meta = zram->meta;
+ comp = zram->comp;
+ disksize = zram->disksize;
+ /*
+ * Refcount will go down to 0 eventually and r/w handler
+ * cannot handle further I/O so it will bail out by
+ * check zram_meta_get.
+ */
+ zram_meta_put(zram);
+ /*
+ * We want to free zram_meta in process context to avoid
+ * deadlock between reclaim path and any other locks.
+ */
+ wait_event(zram->io_done, atomic_read(&zram->refcount) == 0);
+
+ /* Reset stats */
+ memset(&zram->stats, 0, sizeof(zram->stats));
+ zram->disksize = 0;
+ zram->max_comp_streams = 1;
+
+ set_capacity(zram->disk, 0);
+ part_stat_set_all(&zram->disk->part0, 0);
+
+ up_write(&zram->init_lock);
+ /* I/O operation under all of CPU are done so let's free */
+ zram_meta_free(meta, disksize);
+ zcomp_destroy(comp);
+}
+
+static ssize_t disksize_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
{
+ u64 disksize;
+ struct zcomp *comp;
+ struct zram_meta *meta;
struct zram *zram = dev_to_zram(dev);
- ssize_t ret;
+ int err;
- down_read(&zram->init_lock);
- ret = scnprintf(buf, PAGE_SIZE,
- "%8llu %8llu %8llu %8llu\n",
- (u64)atomic64_read(&zram->stats.failed_reads),
- (u64)atomic64_read(&zram->stats.failed_writes),
- (u64)atomic64_read(&zram->stats.invalid_io),
- (u64)atomic64_read(&zram->stats.notify_free));
- up_read(&zram->init_lock);
+ disksize = memparse(buf, NULL);
+ if (!disksize)
+ return -EINVAL;
- return ret;
+ disksize = PAGE_ALIGN(disksize);
+ meta = zram_meta_alloc(zram->disk->first_minor, disksize);
+ if (!meta)
+ return -ENOMEM;
+
+ comp = zcomp_create(zram->compressor, zram->max_comp_streams);
+ if (IS_ERR(comp)) {
+ pr_info("Cannot initialise %s compressing backend\n",
+ zram->compressor);
+ err = PTR_ERR(comp);
+ goto out_free_meta;
+ }
+
+ down_write(&zram->init_lock);
+ if (init_done(zram)) {
+ pr_info("Cannot change disksize for initialized device\n");
+ err = -EBUSY;
+ goto out_destroy_comp;
+ }
+
+ init_waitqueue_head(&zram->io_done);
+ atomic_set(&zram->refcount, 1);
+ zram->meta = meta;
+ zram->comp = comp;
+ zram->disksize = disksize;
+ set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
+ up_write(&zram->init_lock);
+
+ /*
+ * Revalidate disk out of the init_lock to avoid lockdep splat.
+ * It's okay because disk's capacity is protected by init_lock
+ * so that revalidate_disk always sees up-to-date capacity.
+ */
+ revalidate_disk(zram->disk);
+
+ return len;
+
+out_destroy_comp:
+ up_write(&zram->init_lock);
+ zcomp_destroy(comp);
+out_free_meta:
+ zram_meta_free(meta, disksize);
+ return err;
}
-static ssize_t mm_stat_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t reset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
{
- struct zram *zram = dev_to_zram(dev);
- u64 orig_size, mem_used = 0;
- long max_used;
- ssize_t ret;
+ int ret;
+ unsigned short do_reset;
+ struct zram *zram;
+ struct block_device *bdev;
- down_read(&zram->init_lock);
- if (init_done(zram))
- mem_used = zs_get_total_pages(zram->meta->mem_pool);
+ ret = kstrtou16(buf, 10, &do_reset);
+ if (ret)
+ return ret;
- orig_size = atomic64_read(&zram->stats.pages_stored);
- max_used = atomic_long_read(&zram->stats.max_used_pages);
+ if (!do_reset)
+ return -EINVAL;
- ret = scnprintf(buf, PAGE_SIZE,
- "%8llu %8llu %8llu %8lu %8ld %8llu %8llu\n",
- orig_size << PAGE_SHIFT,
- (u64)atomic64_read(&zram->stats.compr_data_size),
- mem_used << PAGE_SHIFT,
- zram->limit_pages << PAGE_SHIFT,
- max_used << PAGE_SHIFT,
- (u64)atomic64_read(&zram->stats.zero_pages),
- (u64)atomic64_read(&zram->stats.num_migrated));
- up_read(&zram->init_lock);
+ zram = dev_to_zram(dev);
+ bdev = bdget_disk(zram->disk, 0);
+ if (!bdev)
+ return -ENOMEM;
+
+ mutex_lock(&bdev->bd_mutex);
+ /* Do not reset an active device or claimed device */
+ if (bdev->bd_openers || zram->claim) {
+ mutex_unlock(&bdev->bd_mutex);
+ bdput(bdev);
+ return -EBUSY;
+ }
+
+ /* From now on, anyone can't open /dev/zram[0-9] */
+ zram->claim = true;
+ mutex_unlock(&bdev->bd_mutex);
+
+ /* Make sure all the pending I/O are finished */
+ fsync_bdev(bdev);
+ zram_reset_device(zram);
+ revalidate_disk(zram->disk);
+ bdput(bdev);
+
+ mutex_lock(&bdev->bd_mutex);
+ zram->claim = false;
+ mutex_unlock(&bdev->bd_mutex);
+
+ return len;
+}
+
+static int zram_open(struct block_device *bdev, fmode_t mode)
+{
+ int ret = 0;
+ struct zram *zram;
+
+ WARN_ON(!mutex_is_locked(&bdev->bd_mutex));
+
+ zram = bdev->bd_disk->private_data;
+ /* zram was claimed to reset so open request fails */
+ if (zram->claim)
+ ret = -EBUSY;
return ret;
}
-static DEVICE_ATTR_RO(io_stat);
-static DEVICE_ATTR_RO(mm_stat);
-ZRAM_ATTR_RO(num_reads);
-ZRAM_ATTR_RO(num_writes);
-ZRAM_ATTR_RO(failed_reads);
-ZRAM_ATTR_RO(failed_writes);
-ZRAM_ATTR_RO(invalid_io);
-ZRAM_ATTR_RO(notify_free);
-ZRAM_ATTR_RO(zero_pages);
-ZRAM_ATTR_RO(compr_data_size);
+static const struct block_device_operations zram_devops = {
+ .open = zram_open,
+ .swap_slot_free_notify = zram_slot_free_notify,
+ .rw_page = zram_rw_page,
+ .owner = THIS_MODULE
+};
+
+static DEVICE_ATTR_WO(compact);
+static DEVICE_ATTR_RW(disksize);
+static DEVICE_ATTR_RO(initstate);
+static DEVICE_ATTR_WO(reset);
+static DEVICE_ATTR_RO(orig_data_size);
+static DEVICE_ATTR_RO(mem_used_total);
+static DEVICE_ATTR_RW(mem_limit);
+static DEVICE_ATTR_RW(mem_used_max);
+static DEVICE_ATTR_RW(max_comp_streams);
+static DEVICE_ATTR_RW(comp_algorithm);
static struct attribute *zram_disk_attrs[] = {
&dev_attr_disksize.attr,
@@ -1158,10 +1181,24 @@ static struct attribute_group zram_disk_attr_group = {
.attrs = zram_disk_attrs,
};
-static int create_device(struct zram *zram, int device_id)
+/*
+ * Allocate and initialize new zram device. the function returns
+ * '>= 0' device_id upon success, and negative value otherwise.
+ */
+static int zram_add(void)
{
+ struct zram *zram;
struct request_queue *queue;
- int ret = -ENOMEM;
+ int ret, device_id;
+
+ zram = kzalloc(sizeof(struct zram), GFP_KERNEL);
+ if (!zram)
+ return -ENOMEM;
+
+ ret = idr_alloc(&zram_index_idr, zram, 0, 0, GFP_KERNEL);
+ if (ret < 0)
+ goto out_free_dev;
+ device_id = ret;
init_rwsem(&zram->init_lock);
@@ -1169,12 +1206,13 @@ static int create_device(struct zram *zram, int device_id)
if (!queue) {
pr_err("Error allocating disk queue for device %d\n",
device_id);
- goto out;
+ ret = -ENOMEM;
+ goto out_free_idr;
}
blk_queue_make_request(queue, zram_make_request);
- /* gendisk structure */
+ /* gendisk structure */
zram->disk = alloc_disk(1);
if (!zram->disk) {
pr_warn("Error allocating disk structure for device %d\n",
@@ -1232,90 +1270,177 @@ static int create_device(struct zram *zram, int device_id)
strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor));
zram->meta = NULL;
zram->max_comp_streams = 1;
- return 0;
+
+ pr_info("Added device: %s\n", zram->disk->disk_name);
+ return device_id;
out_free_disk:
del_gendisk(zram->disk);
put_disk(zram->disk);
out_free_queue:
blk_cleanup_queue(queue);
-out:
+out_free_idr:
+ idr_remove(&zram_index_idr, device_id);
+out_free_dev:
+ kfree(zram);
return ret;
}
-static void destroy_devices(unsigned int nr)
+static int zram_remove(struct zram *zram)
+{
+ struct block_device *bdev;
+
+ bdev = bdget_disk(zram->disk, 0);
+ if (!bdev)
+ return -ENOMEM;
+
+ mutex_lock(&bdev->bd_mutex);
+ if (bdev->bd_openers || zram->claim) {
+ mutex_unlock(&bdev->bd_mutex);
+ bdput(bdev);
+ return -EBUSY;
+ }
+
+ zram->claim = true;
+ mutex_unlock(&bdev->bd_mutex);
+
+ /*
+ * Remove sysfs first, so no one will perform a disksize
+ * store while we destroy the devices. This also helps during
+ * hot_remove -- zram_reset_device() is the last holder of
+ * ->init_lock, no later/concurrent disksize_store() or any
+ * other sysfs handlers are possible.
+ */
+ sysfs_remove_group(&disk_to_dev(zram->disk)->kobj,
+ &zram_disk_attr_group);
+
+ /* Make sure all the pending I/O are finished */
+ fsync_bdev(bdev);
+ zram_reset_device(zram);
+ bdput(bdev);
+
+ 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);
+ kfree(zram);
+ return 0;
+}
+
+/* zram-control sysfs attributes */
+static ssize_t hot_add_show(struct class *class,
+ struct class_attribute *attr,
+ char *buf)
+{
+ int ret;
+
+ mutex_lock(&zram_index_mutex);
+ ret = zram_add();
+ mutex_unlock(&zram_index_mutex);
+
+ if (ret < 0)
+ return ret;
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+}
+
+static ssize_t hot_remove_store(struct class *class,
+ struct class_attribute *attr,
+ const char *buf,
+ size_t count)
{
struct zram *zram;
- unsigned int i;
+ int ret, dev_id;
- for (i = 0; i < nr; i++) {
- zram = &zram_devices[i];
- /*
- * Remove sysfs first, so no one will perform a disksize
- * store while we destroy the devices
- */
- sysfs_remove_group(&disk_to_dev(zram->disk)->kobj,
- &zram_disk_attr_group);
+ /* dev_id is gendisk->first_minor, which is `int' */
+ ret = kstrtoint(buf, 10, &dev_id);
+ if (ret)
+ return ret;
+ if (dev_id < 0)
+ return -EINVAL;
- zram_reset_device(zram);
+ mutex_lock(&zram_index_mutex);
- blk_cleanup_queue(zram->disk->queue);
- del_gendisk(zram->disk);
- put_disk(zram->disk);
- }
+ zram = idr_find(&zram_index_idr, dev_id);
+ if (zram)
+ ret = zram_remove(zram);
+ else
+ ret = -ENODEV;
- kfree(zram_devices);
+ mutex_unlock(&zram_index_mutex);
+ return ret ? ret : count;
+}
+
+static struct class_attribute zram_control_class_attrs[] = {
+ __ATTR_RO(hot_add),
+ __ATTR_WO(hot_remove),
+ __ATTR_NULL,
+};
+
+static struct class zram_control_class = {
+ .name = "zram-control",
+ .owner = THIS_MODULE,
+ .class_attrs = zram_control_class_attrs,
+};
+
+static int zram_remove_cb(int id, void *ptr, void *data)
+{
+ zram_remove(ptr);
+ return 0;
+}
+
+static void destroy_devices(void)
+{
+ class_unregister(&zram_control_class);
+ idr_for_each(&zram_index_idr, &zram_remove_cb, NULL);
+ idr_destroy(&zram_index_idr);
unregister_blkdev(zram_major, "zram");
- pr_info("Destroyed %u device(s)\n", nr);
}
static int __init zram_init(void)
{
- int ret, dev_id;
+ int ret;
- if (num_devices > max_num_devices) {
- pr_warn("Invalid value for num_devices: %u\n",
- num_devices);
- return -EINVAL;
+ ret = class_register(&zram_control_class);
+ if (ret) {
+ pr_warn("Unable to register zram-control class\n");
+ return ret;
}
zram_major = register_blkdev(0, "zram");
if (zram_major <= 0) {
pr_warn("Unable to get major number\n");
+ class_unregister(&zram_control_class);
return -EBUSY;
}
- /* Allocate the device array and initialize each one */
- zram_devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL);
- if (!zram_devices) {
- unregister_blkdev(zram_major, "zram");
- return -ENOMEM;
- }
-
- for (dev_id = 0; dev_id < num_devices; dev_id++) {
- ret = create_device(&zram_devices[dev_id], dev_id);
- if (ret)
+ while (num_devices != 0) {
+ mutex_lock(&zram_index_mutex);
+ ret = zram_add();
+ mutex_unlock(&zram_index_mutex);
+ if (ret < 0)
goto out_error;
+ num_devices--;
}
- pr_info("Created %u device(s)\n", num_devices);
return 0;
out_error:
- destroy_devices(dev_id);
+ destroy_devices();
return ret;
}
static void __exit zram_exit(void)
{
- destroy_devices(num_devices);
+ destroy_devices();
}
module_init(zram_init);
module_exit(zram_exit);
module_param(num_devices, uint, 0);
-MODULE_PARM_DESC(num_devices, "Number of zram devices");
+MODULE_PARM_DESC(num_devices, "Number of pre-created zram devices");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index 570c598f4ce9..6dbe2df506bf 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -20,12 +20,6 @@
#include "zcomp.h"
-/*
- * Some arbitrary value. This is just to catch
- * invalid value for num_devices module parameter.
- */
-static const unsigned max_num_devices = 32;
-
/*-- Configurable parameters */
/*
@@ -121,5 +115,9 @@ struct zram {
*/
u64 disksize; /* bytes */
char compressor[10];
+ /*
+ * zram is claimed so open request will be failed
+ */
+ bool claim; /* Protected by bdev->bd_mutex */
};
#endif
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index ed5c2738bea2..2e777071e1dc 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -9,6 +9,10 @@ config BT_BCM
tristate
select FW_LOADER
+config BT_RTL
+ tristate
+ select FW_LOADER
+
config BT_HCIBTUSB
tristate "HCI USB driver"
depends on USB
@@ -32,6 +36,17 @@ config BT_HCIBTUSB_BCM
Say Y here to compile support for Broadcom protocol.
+config BT_HCIBTUSB_RTL
+ bool "Realtek protocol support"
+ depends on BT_HCIBTUSB
+ select BT_RTL
+ default y
+ help
+ The Realtek protocol support enables firmware and configuration
+ download support for Realtek Bluetooth controllers.
+
+ Say Y here to compile support for Realtek protocol.
+
config BT_HCIBTSDIO
tristate "HCI SDIO driver"
depends on MMC
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index dd0d9c40b999..f40e194e7080 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_BT_MRVL) += btmrvl.o
obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
obj-$(CONFIG_BT_WILINK) += btwilink.o
obj-$(CONFIG_BT_BCM) += btbcm.o
+obj-$(CONFIG_BT_RTL) += btrtl.o
btmrvl-y := btmrvl_main.o
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 8c81af6dbe06..e527a3e13939 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -80,6 +80,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x0489, 0xe057) },
{ USB_DEVICE(0x0489, 0xe056) },
{ USB_DEVICE(0x0489, 0xe05f) },
+ { USB_DEVICE(0x0489, 0xe076) },
{ USB_DEVICE(0x0489, 0xe078) },
{ USB_DEVICE(0x04c5, 0x1330) },
{ USB_DEVICE(0x04CA, 0x3004) },
@@ -88,6 +89,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x04CA, 0x3007) },
{ USB_DEVICE(0x04CA, 0x3008) },
{ USB_DEVICE(0x04CA, 0x300b) },
+ { USB_DEVICE(0x04CA, 0x300d) },
{ USB_DEVICE(0x04CA, 0x300f) },
{ USB_DEVICE(0x04CA, 0x3010) },
{ USB_DEVICE(0x0930, 0x0219) },
@@ -113,6 +115,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x13d3, 0x3408) },
{ USB_DEVICE(0x13d3, 0x3423) },
{ USB_DEVICE(0x13d3, 0x3432) },
+ { USB_DEVICE(0x13d3, 0x3474) },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
@@ -137,6 +140,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
@@ -145,6 +149,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x04ca, 0x3007), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
@@ -170,6 +175,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 6de97b3871b0..7aab65427d38 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -202,9 +202,8 @@ static void bt3c_write_wakeup(struct bt3c_info *info)
/* Send frame */
len = bt3c_write(iobase, 256, skb->data, skb->len);
- if (len != skb->len) {
+ if (len != skb->len)
BT_ERR("Very strange");
- }
kfree_skb(skb);
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index 4bba86677adc..1e1a4323a71f 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -33,6 +33,7 @@
#define VERSION "0.1"
#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
+#define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}})
int btbcm_check_bdaddr(struct hci_dev *hdev)
{
@@ -55,17 +56,19 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
}
bda = (struct hci_rp_read_bd_addr *)skb->data;
- if (bda->status) {
- BT_ERR("%s: BCM: Device address result failed (%02x)",
- hdev->name, bda->status);
- kfree_skb(skb);
- return -bt_to_errno(bda->status);
- }
- /* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller
+ /* Check if the address indicates a controller with either an
+ * invalid or default address. In both cases the device needs
+ * to be marked as not having a valid address.
+ *
+ * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller
* with no configured address.
+ *
+ * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller
+ * with waiting for configuration state.
*/
- if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) {
+ if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) ||
+ !bacmp(&bda->bdaddr, BDADDR_BCM4324B3)) {
BT_INFO("%s: BCM: Using default device address (%pMR)",
hdev->name, &bda->bdaddr);
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
@@ -95,21 +98,14 @@ int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
}
EXPORT_SYMBOL_GPL(btbcm_set_bdaddr);
-int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
+int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw)
{
const struct hci_command_hdr *cmd;
- const struct firmware *fw;
const u8 *fw_ptr;
size_t fw_size;
struct sk_buff *skb;
u16 opcode;
- int err;
-
- err = request_firmware(&fw, firmware, &hdev->dev);
- if (err < 0) {
- BT_INFO("%s: BCM: Patch %s not found", hdev->name, firmware);
- return err;
- }
+ int err = 0;
/* Start Download */
skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
@@ -135,8 +131,7 @@ int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
fw_size -= sizeof(*cmd);
if (fw_size < cmd->plen) {
- BT_ERR("%s: BCM: Patch %s is corrupted", hdev->name,
- firmware);
+ BT_ERR("%s: BCM: Patch is corrupted", hdev->name);
err = -EINVAL;
goto done;
}
@@ -162,7 +157,6 @@ int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
msleep(250);
done:
- release_firmware(fw);
return err;
}
EXPORT_SYMBOL(btbcm_patchram);
@@ -248,9 +242,101 @@ static const struct {
const char *name;
} bcm_uart_subver_table[] = {
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */
+ { 0x4406, "BCM4324B3" }, /* 002.004.006 */
+ { 0x610c, "BCM4354" }, /* 003.001.012 */
{ }
};
+int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len)
+{
+ u16 subver, rev;
+ const char *hw_name = NULL;
+ struct sk_buff *skb;
+ struct hci_rp_read_local_version *ver;
+ int i, err;
+
+ /* Reset */
+ err = btbcm_reset(hdev);
+ if (err)
+ return err;
+
+ /* Read Local Version Info */
+ skb = btbcm_read_local_version(hdev);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ ver = (struct hci_rp_read_local_version *)skb->data;
+ rev = le16_to_cpu(ver->hci_rev);
+ subver = le16_to_cpu(ver->lmp_subver);
+ kfree_skb(skb);
+
+ /* Read Verbose Config Version Info */
+ skb = btbcm_read_verbose_config(hdev);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]);
+ kfree_skb(skb);
+
+ switch ((rev & 0xf000) >> 12) {
+ case 0:
+ case 1:
+ case 3:
+ for (i = 0; bcm_uart_subver_table[i].name; i++) {
+ if (subver == bcm_uart_subver_table[i].subver) {
+ hw_name = bcm_uart_subver_table[i].name;
+ break;
+ }
+ }
+
+ snprintf(fw_name, len, "brcm/%s.hcd", hw_name ? : "BCM");
+ break;
+ default:
+ return 0;
+ }
+
+ BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
+ hw_name ? : "BCM", (subver & 0x7000) >> 13,
+ (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btbcm_initialize);
+
+int btbcm_finalize(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+ struct hci_rp_read_local_version *ver;
+ u16 subver, rev;
+ int err;
+
+ /* Reset */
+ err = btbcm_reset(hdev);
+ if (err)
+ return err;
+
+ /* Read Local Version Info */
+ skb = btbcm_read_local_version(hdev);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ ver = (struct hci_rp_read_local_version *)skb->data;
+ rev = le16_to_cpu(ver->hci_rev);
+ subver = le16_to_cpu(ver->lmp_subver);
+ kfree_skb(skb);
+
+ BT_INFO("%s: BCM (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
+ (subver & 0x7000) >> 13, (subver & 0x1f00) >> 8,
+ (subver & 0x00ff), rev & 0x0fff);
+
+ btbcm_check_bdaddr(hdev);
+
+ set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btbcm_finalize);
+
static const struct {
u16 subver;
const char *name;
@@ -271,6 +357,7 @@ static const struct {
int btbcm_setup_patchram(struct hci_dev *hdev)
{
char fw_name[64];
+ const struct firmware *fw;
u16 subver, rev, pid, vid;
const char *hw_name = NULL;
struct sk_buff *skb;
@@ -302,6 +389,7 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
switch ((rev & 0xf000) >> 12) {
case 0:
+ case 3:
for (i = 0; bcm_uart_subver_table[i].name; i++) {
if (subver == bcm_uart_subver_table[i].subver) {
hw_name = bcm_uart_subver_table[i].name;
@@ -341,9 +429,15 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
hw_name ? : "BCM", (subver & 0x7000) >> 13,
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
- err = btbcm_patchram(hdev, fw_name);
- if (err == -ENOENT)
+ err = request_firmware(&fw, fw_name, &hdev->dev);
+ if (err < 0) {
+ BT_INFO("%s: BCM: Patch %s not found", hdev->name, fw_name);
return 0;
+ }
+
+ btbcm_patchram(hdev, fw);
+
+ release_firmware(fw);
/* Reset */
err = btbcm_reset(hdev);
diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h
index eb6ab5f9483d..d9e6b41658e5 100644
--- a/drivers/bluetooth/btbcm.h
+++ b/drivers/bluetooth/btbcm.h
@@ -21,15 +21,61 @@
*
*/
+#define BCM_UART_CLOCK_48MHZ 0x01
+#define BCM_UART_CLOCK_24MHZ 0x02
+
+struct bcm_update_uart_baud_rate {
+ __le16 zero;
+ __le32 baud_rate;
+} __packed;
+
+struct bcm_write_uart_clock_setting {
+ __u8 type;
+} __packed;
+
+struct bcm_set_sleep_mode {
+ __u8 sleep_mode;
+ __u8 idle_host;
+ __u8 idle_dev;
+ __u8 bt_wake_active;
+ __u8 host_wake_active;
+ __u8 allow_host_sleep;
+ __u8 combine_modes;
+ __u8 tristate_control;
+ __u8 usb_auto_sleep;
+ __u8 usb_resume_timeout;
+ __u8 pulsed_host_wake;
+ __u8 break_to_host;
+} __packed;
+
+struct bcm_set_pcm_int_params {
+ __u8 routing;
+ __u8 rate;
+ __u8 frame_sync;
+ __u8 sync_mode;
+ __u8 clock_mode;
+} __packed;
+
+struct bcm_set_pcm_format_params {
+ __u8 lsb_first;
+ __u8 fill_value;
+ __u8 fill_method;
+ __u8 fill_num;
+ __u8 right_justify;
+} __packed;
+
#if IS_ENABLED(CONFIG_BT_BCM)
int btbcm_check_bdaddr(struct hci_dev *hdev);
int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
-int btbcm_patchram(struct hci_dev *hdev, const char *firmware);
+int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw);
int btbcm_setup_patchram(struct hci_dev *hdev);
int btbcm_setup_apple(struct hci_dev *hdev);
+int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len);
+int btbcm_finalize(struct hci_dev *hdev);
+
#else
static inline int btbcm_check_bdaddr(struct hci_dev *hdev)
@@ -42,7 +88,7 @@ static inline int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
return -EOPNOTSUPP;
}
-static inline int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
+static inline int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw)
{
return -EOPNOTSUPP;
}
@@ -57,4 +103,15 @@ static inline int btbcm_setup_apple(struct hci_dev *hdev)
return 0;
}
+static inline int btbcm_initialize(struct hci_dev *hdev, char *fw_name,
+ size_t len)
+{
+ return 0;
+}
+
+static inline int btbcm_finalize(struct hci_dev *hdev)
+{
+ return 0;
+}
+
#endif
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 2d43d4279b00..828f2f8d1568 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -53,12 +53,6 @@ int btintel_check_bdaddr(struct hci_dev *hdev)
}
bda = (struct hci_rp_read_bd_addr *)skb->data;
- if (bda->status) {
- BT_ERR("%s: Intel device address result failed (%02x)",
- hdev->name, bda->status);
- kfree_skb(skb);
- return -bt_to_errno(bda->status);
- }
/* For some Intel based controllers, the default Bluetooth device
* address 00:03:19:9E:8B:00 can be found. These controllers are
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 01d6da577eeb..b9a811900f6a 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -1217,7 +1217,7 @@ static void btmrvl_sdio_dump_firmware(struct btmrvl_private *priv)
unsigned int reg, reg_start, reg_end;
enum rdwr_status stat;
u8 *dbg_ptr, *end_ptr, *fw_dump_data, *fw_dump_ptr;
- u8 dump_num, idx, i, read_reg, doneflag = 0;
+ u8 dump_num = 0, idx, i, read_reg, doneflag = 0;
u32 memory_size, fw_dump_len = 0;
/* dump sdio register first */
diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
new file mode 100644
index 000000000000..84288938f7f2
--- /dev/null
+++ b/drivers/bluetooth/btrtl.c
@@ -0,0 +1,390 @@
+/*
+ * Bluetooth support for Realtek devices
+ *
+ * Copyright (C) 2015 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 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/firmware.h>
+#include <asm/unaligned.h>
+#include <linux/usb.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btrtl.h"
+
+#define VERSION "0.1"
+
+#define RTL_EPATCH_SIGNATURE "Realtech"
+#define RTL_ROM_LMP_3499 0x3499
+#define RTL_ROM_LMP_8723A 0x1200
+#define RTL_ROM_LMP_8723B 0x8723
+#define RTL_ROM_LMP_8821A 0x8821
+#define RTL_ROM_LMP_8761A 0x8761
+
+static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
+{
+ struct rtl_rom_version_evt *rom_version;
+ struct sk_buff *skb;
+
+ /* Read RTL ROM version command */
+ skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Read ROM version failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return PTR_ERR(skb);
+ }
+
+ if (skb->len != sizeof(*rom_version)) {
+ BT_ERR("%s: RTL version event length mismatch", hdev->name);
+ kfree_skb(skb);
+ return -EIO;
+ }
+
+ rom_version = (struct rtl_rom_version_evt *)skb->data;
+ BT_INFO("%s: rom_version status=%x version=%x",
+ hdev->name, rom_version->status, rom_version->version);
+
+ *version = rom_version->version;
+
+ kfree_skb(skb);
+ return 0;
+}
+
+static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
+ const struct firmware *fw,
+ unsigned char **_buf)
+{
+ const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
+ struct rtl_epatch_header *epatch_info;
+ unsigned char *buf;
+ int i, ret, len;
+ size_t min_size;
+ u8 opcode, length, data, rom_version = 0;
+ int project_id = -1;
+ const unsigned char *fwptr, *chip_id_base;
+ const unsigned char *patch_length_base, *patch_offset_base;
+ u32 patch_offset = 0;
+ u16 patch_length, num_patches;
+ const u16 project_id_to_lmp_subver[] = {
+ RTL_ROM_LMP_8723A,
+ RTL_ROM_LMP_8723B,
+ RTL_ROM_LMP_8821A,
+ RTL_ROM_LMP_8761A
+ };
+
+ ret = rtl_read_rom_version(hdev, &rom_version);
+ if (ret)
+ return ret;
+
+ min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
+ if (fw->size < min_size)
+ return -EINVAL;
+
+ fwptr = fw->data + fw->size - sizeof(extension_sig);
+ if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) {
+ BT_ERR("%s: extension section signature mismatch", hdev->name);
+ return -EINVAL;
+ }
+
+ /* Loop from the end of the firmware parsing instructions, until
+ * we find an instruction that identifies the "project ID" for the
+ * hardware supported by this firwmare file.
+ * Once we have that, we double-check that that project_id is suitable
+ * for the hardware we are working with.
+ */
+ while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) {
+ opcode = *--fwptr;
+ length = *--fwptr;
+ data = *--fwptr;
+
+ BT_DBG("check op=%x len=%x data=%x", opcode, length, data);
+
+ if (opcode == 0xff) /* EOF */
+ break;
+
+ if (length == 0) {
+ BT_ERR("%s: found instruction with length 0",
+ hdev->name);
+ return -EINVAL;
+ }
+
+ if (opcode == 0 && length == 1) {
+ project_id = data;
+ break;
+ }
+
+ fwptr -= length;
+ }
+
+ if (project_id < 0) {
+ BT_ERR("%s: failed to find version instruction", hdev->name);
+ return -EINVAL;
+ }
+
+ if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) {
+ BT_ERR("%s: unknown project id %d", hdev->name, project_id);
+ return -EINVAL;
+ }
+
+ if (lmp_subver != project_id_to_lmp_subver[project_id]) {
+ BT_ERR("%s: firmware is for %x but this is a %x", hdev->name,
+ project_id_to_lmp_subver[project_id], lmp_subver);
+ return -EINVAL;
+ }
+
+ epatch_info = (struct rtl_epatch_header *)fw->data;
+ if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) {
+ BT_ERR("%s: bad EPATCH signature", hdev->name);
+ return -EINVAL;
+ }
+
+ num_patches = le16_to_cpu(epatch_info->num_patches);
+ BT_DBG("fw_version=%x, num_patches=%d",
+ le32_to_cpu(epatch_info->fw_version), num_patches);
+
+ /* After the rtl_epatch_header there is a funky patch metadata section.
+ * Assuming 2 patches, the layout is:
+ * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2
+ *
+ * Find the right patch for this chip.
+ */
+ min_size += 8 * num_patches;
+ if (fw->size < min_size)
+ return -EINVAL;
+
+ chip_id_base = fw->data + sizeof(struct rtl_epatch_header);
+ patch_length_base = chip_id_base + (sizeof(u16) * num_patches);
+ patch_offset_base = patch_length_base + (sizeof(u16) * num_patches);
+ for (i = 0; i < num_patches; i++) {
+ u16 chip_id = get_unaligned_le16(chip_id_base +
+ (i * sizeof(u16)));
+ if (chip_id == rom_version + 1) {
+ patch_length = get_unaligned_le16(patch_length_base +
+ (i * sizeof(u16)));
+ patch_offset = get_unaligned_le32(patch_offset_base +
+ (i * sizeof(u32)));
+ break;
+ }
+ }
+
+ if (!patch_offset) {
+ BT_ERR("%s: didn't find patch for chip id %d",
+ hdev->name, rom_version);
+ return -EINVAL;
+ }
+
+ BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i);
+ min_size = patch_offset + patch_length;
+ if (fw->size < min_size)
+ return -EINVAL;
+
+ /* Copy the firmware into a new buffer and write the version at
+ * the end.
+ */
+ len = patch_length;
+ buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4);
+
+ *_buf = buf;
+ return len;
+}
+
+static int rtl_download_firmware(struct hci_dev *hdev,
+ const unsigned char *data, int fw_len)
+{
+ struct rtl_download_cmd *dl_cmd;
+ int frag_num = fw_len / RTL_FRAG_LEN + 1;
+ int frag_len = RTL_FRAG_LEN;
+ int ret = 0;
+ int i;
+
+ dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL);
+ if (!dl_cmd)
+ return -ENOMEM;
+
+ for (i = 0; i < frag_num; i++) {
+ struct sk_buff *skb;
+
+ BT_DBG("download fw (%d/%d)", i, frag_num);
+
+ dl_cmd->index = i;
+ if (i == (frag_num - 1)) {
+ dl_cmd->index |= 0x80; /* data end */
+ frag_len = fw_len % RTL_FRAG_LEN;
+ }
+ memcpy(dl_cmd->data, data, frag_len);
+
+ /* Send download command */
+ skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: download fw command failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ ret = -PTR_ERR(skb);
+ goto out;
+ }
+
+ if (skb->len != sizeof(struct rtl_download_response)) {
+ BT_ERR("%s: download fw event length mismatch",
+ hdev->name);
+ kfree_skb(skb);
+ ret = -EIO;
+ goto out;
+ }
+
+ kfree_skb(skb);
+ data += RTL_FRAG_LEN;
+ }
+
+out:
+ kfree(dl_cmd);
+ return ret;
+}
+
+static int btrtl_setup_rtl8723a(struct hci_dev *hdev)
+{
+ const struct firmware *fw;
+ int ret;
+
+ BT_INFO("%s: rtl: loading rtl_bt/rtl8723a_fw.bin", hdev->name);
+ ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &hdev->dev);
+ if (ret < 0) {
+ BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name);
+ return ret;
+ }
+
+ if (fw->size < 8) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Check that the firmware doesn't have the epatch signature
+ * (which is only for RTL8723B and newer).
+ */
+ if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) {
+ BT_ERR("%s: unexpected EPATCH signature!", hdev->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = rtl_download_firmware(hdev, fw->data, fw->size);
+
+out:
+ release_firmware(fw);
+ return ret;
+}
+
+static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
+ const char *fw_name)
+{
+ unsigned char *fw_data = NULL;
+ const struct firmware *fw;
+ int ret;
+
+ BT_INFO("%s: rtl: loading %s", hdev->name, fw_name);
+ ret = request_firmware(&fw, fw_name, &hdev->dev);
+ if (ret < 0) {
+ BT_ERR("%s: Failed to load %s", hdev->name, fw_name);
+ return ret;
+ }
+
+ ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data);
+ if (ret < 0)
+ goto out;
+
+ ret = rtl_download_firmware(hdev, fw_data, ret);
+ kfree(fw_data);
+ if (ret < 0)
+ goto out;
+
+out:
+ release_firmware(fw);
+ return ret;
+}
+
+static struct sk_buff *btrtl_read_local_version(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+
+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return skb;
+ }
+
+ if (skb->len != sizeof(struct hci_rp_read_local_version)) {
+ BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
+ hdev->name);
+ kfree_skb(skb);
+ return ERR_PTR(-EIO);
+ }
+
+ return skb;
+}
+
+int btrtl_setup_realtek(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+ struct hci_rp_read_local_version *resp;
+ u16 lmp_subver;
+
+ skb = btrtl_read_local_version(hdev);
+ if (IS_ERR(skb))
+ return -PTR_ERR(skb);
+
+ resp = (struct hci_rp_read_local_version *)skb->data;
+ BT_INFO("%s: rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
+ "lmp_subver=%04x", hdev->name, resp->hci_ver, resp->hci_rev,
+ resp->lmp_ver, resp->lmp_subver);
+
+ lmp_subver = le16_to_cpu(resp->lmp_subver);
+ kfree_skb(skb);
+
+ /* Match a set of subver values that correspond to stock firmware,
+ * which is not compatible with standard btusb.
+ * If matched, upload an alternative firmware that does conform to
+ * standard btusb. Once that firmware is uploaded, the subver changes
+ * to a different value.
+ */
+ switch (lmp_subver) {
+ case RTL_ROM_LMP_8723A:
+ case RTL_ROM_LMP_3499:
+ return btrtl_setup_rtl8723a(hdev);
+ case RTL_ROM_LMP_8723B:
+ return btrtl_setup_rtl8723b(hdev, lmp_subver,
+ "rtl_bt/rtl8723b_fw.bin");
+ case RTL_ROM_LMP_8821A:
+ return btrtl_setup_rtl8723b(hdev, lmp_subver,
+ "rtl_bt/rtl8821a_fw.bin");
+ case RTL_ROM_LMP_8761A:
+ return btrtl_setup_rtl8723b(hdev, lmp_subver,
+ "rtl_bt/rtl8761a_fw.bin");
+ default:
+ BT_INFO("rtl: assuming no firmware upload needed.");
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(btrtl_setup_realtek);
+
+MODULE_AUTHOR("Daniel Drake <drake@endlessm.com>");
+MODULE_DESCRIPTION("Bluetooth support for Realtek devices ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h
new file mode 100644
index 000000000000..38ffe4890cd1
--- /dev/null
+++ b/drivers/bluetooth/btrtl.h
@@ -0,0 +1,52 @@
+/*
+ * Bluetooth support for Realtek devices
+ *
+ * Copyright (C) 2015 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 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.
+ *
+ */
+
+#define RTL_FRAG_LEN 252
+
+struct rtl_download_cmd {
+ __u8 index;
+ __u8 data[RTL_FRAG_LEN];
+} __packed;
+
+struct rtl_download_response {
+ __u8 status;
+ __u8 index;
+} __packed;
+
+struct rtl_rom_version_evt {
+ __u8 status;
+ __u8 version;
+} __packed;
+
+struct rtl_epatch_header {
+ __u8 signature[8];
+ __le32 fw_version;
+ __le16 num_patches;
+} __packed;
+
+#if IS_ENABLED(CONFIG_BT_RTL)
+
+int btrtl_setup_realtek(struct hci_dev *hdev);
+
+#else
+
+static inline int btrtl_setup_realtek(struct hci_dev *hdev)
+{
+ return -EOPNOTSUPP;
+}
+
+#endif
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 3c10d4dfe9a7..b4cf8d9c9dac 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -31,13 +31,14 @@
#include "btintel.h"
#include "btbcm.h"
+#include "btrtl.h"
#define VERSION "0.8"
static bool disable_scofix;
static bool force_scofix;
-static bool reset = 1;
+static bool reset = true;
static struct usb_driver btusb_driver;
@@ -178,6 +179,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
@@ -186,6 +188,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x04ca, 0x3007), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
@@ -211,6 +214,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -265,7 +269,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC },
/* Roper Class 1 Bluetooth Dongle (Silicon Wave based) */
- { USB_DEVICE(0x1300, 0x0001), .driver_info = BTUSB_SWAVE },
+ { USB_DEVICE(0x1310, 0x0001), .driver_info = BTUSB_SWAVE },
/* Digianswer devices */
{ USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },
@@ -330,6 +334,7 @@ static const struct usb_device_id blacklist_table[] = {
#define BTUSB_FIRMWARE_LOADED 7
#define BTUSB_FIRMWARE_FAILED 8
#define BTUSB_BOOTING 9
+#define BTUSB_RESET_RESUME 10
struct btusb_data {
struct hci_dev *hdev;
@@ -1298,28 +1303,6 @@ static void btusb_waker(struct work_struct *work)
usb_autopm_put_interface(data->intf);
}
-static struct sk_buff *btusb_read_local_version(struct hci_dev *hdev)
-{
- struct sk_buff *skb;
-
- skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
- hdev->name, PTR_ERR(skb));
- return skb;
- }
-
- if (skb->len != sizeof(struct hci_rp_read_local_version)) {
- BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
- hdev->name);
- kfree_skb(skb);
- return ERR_PTR(-EIO);
- }
-
- return skb;
-}
-
static int btusb_setup_bcm92035(struct hci_dev *hdev)
{
struct sk_buff *skb;
@@ -1340,408 +1323,40 @@ static int btusb_setup_csr(struct hci_dev *hdev)
{
struct hci_rp_read_local_version *rp;
struct sk_buff *skb;
- int ret;
BT_DBG("%s", hdev->name);
- skb = btusb_read_local_version(hdev);
- if (IS_ERR(skb))
- return -PTR_ERR(skb);
-
- rp = (struct hci_rp_read_local_version *)skb->data;
-
- if (!rp->status) {
- if (le16_to_cpu(rp->manufacturer) != 10) {
- /* Clear the reset quirk since this is not an actual
- * early Bluetooth 1.1 device from CSR.
- */
- clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
-
- /* These fake CSR controllers have all a broken
- * stored link key handling and so just disable it.
- */
- set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY,
- &hdev->quirks);
- }
- }
-
- ret = -bt_to_errno(rp->status);
-
- kfree_skb(skb);
-
- return ret;
-}
-
-#define RTL_FRAG_LEN 252
-
-struct rtl_download_cmd {
- __u8 index;
- __u8 data[RTL_FRAG_LEN];
-} __packed;
-
-struct rtl_download_response {
- __u8 status;
- __u8 index;
-} __packed;
-
-struct rtl_rom_version_evt {
- __u8 status;
- __u8 version;
-} __packed;
-
-struct rtl_epatch_header {
- __u8 signature[8];
- __le32 fw_version;
- __le16 num_patches;
-} __packed;
-
-#define RTL_EPATCH_SIGNATURE "Realtech"
-#define RTL_ROM_LMP_3499 0x3499
-#define RTL_ROM_LMP_8723A 0x1200
-#define RTL_ROM_LMP_8723B 0x8723
-#define RTL_ROM_LMP_8821A 0x8821
-#define RTL_ROM_LMP_8761A 0x8761
-
-static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
-{
- struct rtl_rom_version_evt *rom_version;
- struct sk_buff *skb;
- int ret;
-
- /* Read RTL ROM version command */
- skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT);
+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+ HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
- BT_ERR("%s: Read ROM version failed (%ld)",
- hdev->name, PTR_ERR(skb));
- return PTR_ERR(skb);
+ int err = PTR_ERR(skb);
+ BT_ERR("%s: CSR: Local version failed (%d)", hdev->name, err);
+ return err;
}
- if (skb->len != sizeof(*rom_version)) {
- BT_ERR("%s: RTL version event length mismatch", hdev->name);
+ if (skb->len != sizeof(struct hci_rp_read_local_version)) {
+ BT_ERR("%s: CSR: Local version length mismatch", hdev->name);
kfree_skb(skb);
return -EIO;
}
- rom_version = (struct rtl_rom_version_evt *)skb->data;
- BT_INFO("%s: rom_version status=%x version=%x",
- hdev->name, rom_version->status, rom_version->version);
-
- ret = rom_version->status;
- if (ret == 0)
- *version = rom_version->version;
-
- kfree_skb(skb);
- return ret;
-}
-
-static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
- const struct firmware *fw,
- unsigned char **_buf)
-{
- const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
- struct rtl_epatch_header *epatch_info;
- unsigned char *buf;
- int i, ret, len;
- size_t min_size;
- u8 opcode, length, data, rom_version = 0;
- int project_id = -1;
- const unsigned char *fwptr, *chip_id_base;
- const unsigned char *patch_length_base, *patch_offset_base;
- u32 patch_offset = 0;
- u16 patch_length, num_patches;
- const u16 project_id_to_lmp_subver[] = {
- RTL_ROM_LMP_8723A,
- RTL_ROM_LMP_8723B,
- RTL_ROM_LMP_8821A,
- RTL_ROM_LMP_8761A
- };
-
- ret = rtl_read_rom_version(hdev, &rom_version);
- if (ret)
- return -bt_to_errno(ret);
-
- min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
- if (fw->size < min_size)
- return -EINVAL;
-
- fwptr = fw->data + fw->size - sizeof(extension_sig);
- if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) {
- BT_ERR("%s: extension section signature mismatch", hdev->name);
- return -EINVAL;
- }
-
- /* Loop from the end of the firmware parsing instructions, until
- * we find an instruction that identifies the "project ID" for the
- * hardware supported by this firwmare file.
- * Once we have that, we double-check that that project_id is suitable
- * for the hardware we are working with.
- */
- while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) {
- opcode = *--fwptr;
- length = *--fwptr;
- data = *--fwptr;
-
- BT_DBG("check op=%x len=%x data=%x", opcode, length, data);
-
- if (opcode == 0xff) /* EOF */
- break;
-
- if (length == 0) {
- BT_ERR("%s: found instruction with length 0",
- hdev->name);
- return -EINVAL;
- }
-
- if (opcode == 0 && length == 1) {
- project_id = data;
- break;
- }
-
- fwptr -= length;
- }
-
- if (project_id < 0) {
- BT_ERR("%s: failed to find version instruction", hdev->name);
- return -EINVAL;
- }
-
- if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) {
- BT_ERR("%s: unknown project id %d", hdev->name, project_id);
- return -EINVAL;
- }
-
- if (lmp_subver != project_id_to_lmp_subver[project_id]) {
- BT_ERR("%s: firmware is for %x but this is a %x", hdev->name,
- project_id_to_lmp_subver[project_id], lmp_subver);
- return -EINVAL;
- }
-
- epatch_info = (struct rtl_epatch_header *)fw->data;
- if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) {
- BT_ERR("%s: bad EPATCH signature", hdev->name);
- return -EINVAL;
- }
-
- num_patches = le16_to_cpu(epatch_info->num_patches);
- BT_DBG("fw_version=%x, num_patches=%d",
- le32_to_cpu(epatch_info->fw_version), num_patches);
-
- /* After the rtl_epatch_header there is a funky patch metadata section.
- * Assuming 2 patches, the layout is:
- * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2
- *
- * Find the right patch for this chip.
- */
- min_size += 8 * num_patches;
- if (fw->size < min_size)
- return -EINVAL;
-
- chip_id_base = fw->data + sizeof(struct rtl_epatch_header);
- patch_length_base = chip_id_base + (sizeof(u16) * num_patches);
- patch_offset_base = patch_length_base + (sizeof(u16) * num_patches);
- for (i = 0; i < num_patches; i++) {
- u16 chip_id = get_unaligned_le16(chip_id_base +
- (i * sizeof(u16)));
- if (chip_id == rom_version + 1) {
- patch_length = get_unaligned_le16(patch_length_base +
- (i * sizeof(u16)));
- patch_offset = get_unaligned_le32(patch_offset_base +
- (i * sizeof(u32)));
- break;
- }
- }
-
- if (!patch_offset) {
- BT_ERR("%s: didn't find patch for chip id %d",
- hdev->name, rom_version);
- return -EINVAL;
- }
-
- BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i);
- min_size = patch_offset + patch_length;
- if (fw->size < min_size)
- return -EINVAL;
-
- /* Copy the firmware into a new buffer and write the version at
- * the end.
- */
- len = patch_length;
- buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4);
-
- *_buf = buf;
- return len;
-}
-
-static int rtl_download_firmware(struct hci_dev *hdev,
- const unsigned char *data, int fw_len)
-{
- struct rtl_download_cmd *dl_cmd;
- int frag_num = fw_len / RTL_FRAG_LEN + 1;
- int frag_len = RTL_FRAG_LEN;
- int ret = 0;
- int i;
-
- dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL);
- if (!dl_cmd)
- return -ENOMEM;
-
- for (i = 0; i < frag_num; i++) {
- struct rtl_download_response *dl_resp;
- struct sk_buff *skb;
-
- BT_DBG("download fw (%d/%d)", i, frag_num);
-
- dl_cmd->index = i;
- if (i == (frag_num - 1)) {
- dl_cmd->index |= 0x80; /* data end */
- frag_len = fw_len % RTL_FRAG_LEN;
- }
- memcpy(dl_cmd->data, data, frag_len);
-
- /* Send download command */
- skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- BT_ERR("%s: download fw command failed (%ld)",
- hdev->name, PTR_ERR(skb));
- ret = -PTR_ERR(skb);
- goto out;
- }
-
- if (skb->len != sizeof(*dl_resp)) {
- BT_ERR("%s: download fw event length mismatch",
- hdev->name);
- kfree_skb(skb);
- ret = -EIO;
- goto out;
- }
-
- dl_resp = (struct rtl_download_response *)skb->data;
- if (dl_resp->status != 0) {
- kfree_skb(skb);
- ret = bt_to_errno(dl_resp->status);
- goto out;
- }
-
- kfree_skb(skb);
- data += RTL_FRAG_LEN;
- }
-
-out:
- kfree(dl_cmd);
- return ret;
-}
-
-static int btusb_setup_rtl8723a(struct hci_dev *hdev)
-{
- struct btusb_data *data = dev_get_drvdata(&hdev->dev);
- struct usb_device *udev = interface_to_usbdev(data->intf);
- const struct firmware *fw;
- int ret;
-
- BT_INFO("%s: rtl: loading rtl_bt/rtl8723a_fw.bin", hdev->name);
- ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &udev->dev);
- if (ret < 0) {
- BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name);
- return ret;
- }
-
- if (fw->size < 8) {
- ret = -EINVAL;
- goto out;
- }
-
- /* Check that the firmware doesn't have the epatch signature
- * (which is only for RTL8723B and newer).
- */
- if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) {
- BT_ERR("%s: unexpected EPATCH signature!", hdev->name);
- ret = -EINVAL;
- goto out;
- }
-
- ret = rtl_download_firmware(hdev, fw->data, fw->size);
-
-out:
- release_firmware(fw);
- return ret;
-}
+ rp = (struct hci_rp_read_local_version *)skb->data;
-static int btusb_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
- const char *fw_name)
-{
- struct btusb_data *data = dev_get_drvdata(&hdev->dev);
- struct usb_device *udev = interface_to_usbdev(data->intf);
- unsigned char *fw_data = NULL;
- const struct firmware *fw;
- int ret;
+ if (le16_to_cpu(rp->manufacturer) != 10) {
+ /* Clear the reset quirk since this is not an actual
+ * early Bluetooth 1.1 device from CSR.
+ */
+ clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
- BT_INFO("%s: rtl: loading %s", hdev->name, fw_name);
- ret = request_firmware(&fw, fw_name, &udev->dev);
- if (ret < 0) {
- BT_ERR("%s: Failed to load %s", hdev->name, fw_name);
- return ret;
+ /* These fake CSR controllers have all a broken
+ * stored link key handling and so just disable it.
+ */
+ set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
}
- ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data);
- if (ret < 0)
- goto out;
-
- ret = rtl_download_firmware(hdev, fw_data, ret);
- kfree(fw_data);
- if (ret < 0)
- goto out;
-
-out:
- release_firmware(fw);
- return ret;
-}
-
-static int btusb_setup_realtek(struct hci_dev *hdev)
-{
- struct sk_buff *skb;
- struct hci_rp_read_local_version *resp;
- u16 lmp_subver;
-
- skb = btusb_read_local_version(hdev);
- if (IS_ERR(skb))
- return -PTR_ERR(skb);
-
- resp = (struct hci_rp_read_local_version *)skb->data;
- BT_INFO("%s: rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
- "lmp_subver=%04x", hdev->name, resp->hci_ver, resp->hci_rev,
- resp->lmp_ver, resp->lmp_subver);
-
- lmp_subver = le16_to_cpu(resp->lmp_subver);
kfree_skb(skb);
- /* Match a set of subver values that correspond to stock firmware,
- * which is not compatible with standard btusb.
- * If matched, upload an alternative firmware that does conform to
- * standard btusb. Once that firmware is uploaded, the subver changes
- * to a different value.
- */
- switch (lmp_subver) {
- case RTL_ROM_LMP_8723A:
- case RTL_ROM_LMP_3499:
- return btusb_setup_rtl8723a(hdev);
- case RTL_ROM_LMP_8723B:
- return btusb_setup_rtl8723b(hdev, lmp_subver,
- "rtl_bt/rtl8723b_fw.bin");
- case RTL_ROM_LMP_8821A:
- return btusb_setup_rtl8723b(hdev, lmp_subver,
- "rtl_bt/rtl8821a_fw.bin");
- case RTL_ROM_LMP_8761A:
- return btusb_setup_rtl8723b(hdev, lmp_subver,
- "rtl_bt/rtl8761a_fw.bin");
- default:
- BT_INFO("rtl: assuming no firmware upload needed.");
- return 0;
- }
+ return 0;
}
static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev,
@@ -1951,12 +1566,6 @@ static int btusb_setup_intel(struct hci_dev *hdev)
}
ver = (struct intel_version *)skb->data;
- if (ver->status) {
- BT_ERR("%s Intel fw version event failed (%02x)", hdev->name,
- ver->status);
- kfree_skb(skb);
- return -bt_to_errno(ver->status);
- }
BT_INFO("%s: read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x",
hdev->name, ver->hw_platform, ver->hw_variant,
@@ -1990,6 +1599,8 @@ static int btusb_setup_intel(struct hci_dev *hdev)
}
fw_ptr = fw->data;
+ kfree_skb(skb);
+
/* This Intel specific command enables the manufacturer mode of the
* controller.
*
@@ -2004,15 +1615,6 @@ static int btusb_setup_intel(struct hci_dev *hdev)
return PTR_ERR(skb);
}
- if (skb->data[0]) {
- u8 evt_status = skb->data[0];
-
- BT_ERR("%s enable Intel manufacturer mode event failed (%02x)",
- hdev->name, evt_status);
- kfree_skb(skb);
- release_firmware(fw);
- return -bt_to_errno(evt_status);
- }
kfree_skb(skb);
disable_patch = 1;
@@ -2331,6 +1933,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
struct intel_boot_params *params;
const struct firmware *fw;
const u8 *fw_ptr;
+ u32 frag_len;
char fwname[64];
ktime_t calltime, delta, rettime;
unsigned long long duration;
@@ -2358,13 +1961,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
}
ver = (struct intel_version *)skb->data;
- if (ver->status) {
- BT_ERR("%s: Intel version command failure (%02x)",
- hdev->name, ver->status);
- err = -bt_to_errno(ver->status);
- kfree_skb(skb);
- return err;
- }
/* The hardware platform number has a fixed value of 0x37 and
* for now only accept this single value.
@@ -2439,13 +2035,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
}
params = (struct intel_boot_params *)skb->data;
- if (params->status) {
- BT_ERR("%s: Intel boot parameters command failure (%02x)",
- hdev->name, params->status);
- err = -bt_to_errno(params->status);
- kfree_skb(skb);
- return err;
- }
BT_INFO("%s: Device revision is %u", hdev->name,
le16_to_cpu(params->dev_revid));
@@ -2495,6 +2084,12 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
BT_INFO("%s: Found device firmware: %s", hdev->name, fwname);
+ /* Save the DDC file name for later use to apply once the firmware
+ * downloading is done.
+ */
+ snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.ddc",
+ le16_to_cpu(params->dev_revid));
+
kfree_skb(skb);
if (fw->size < 644) {
@@ -2537,24 +2132,33 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
}
fw_ptr = fw->data + 644;
+ frag_len = 0;
while (fw_ptr - fw->data < fw->size) {
- struct hci_command_hdr *cmd = (void *)fw_ptr;
- u8 cmd_len;
+ struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
- cmd_len = sizeof(*cmd) + cmd->plen;
+ frag_len += sizeof(*cmd) + cmd->plen;
- /* Send each command from the firmware data buffer as
- * a single Data fragment.
+ /* The paramter length of the secure send command requires
+ * a 4 byte alignment. It happens so that the firmware file
+ * contains proper Intel_NOP commands to align the fragments
+ * as needed.
+ *
+ * Send set of commands with 4 byte alignment from the
+ * firmware data buffer as a single Data fragement.
*/
- err = btusb_intel_secure_send(hdev, 0x01, cmd_len, fw_ptr);
- if (err < 0) {
- BT_ERR("%s: Failed to send firmware data (%d)",
- hdev->name, err);
- goto done;
- }
+ if (!(frag_len % 4)) {
+ err = btusb_intel_secure_send(hdev, 0x01, frag_len,
+ fw_ptr);
+ if (err < 0) {
+ BT_ERR("%s: Failed to send firmware data (%d)",
+ hdev->name, err);
+ goto done;
+ }
- fw_ptr += cmd_len;
+ fw_ptr += frag_len;
+ frag_len = 0;
+ }
}
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
@@ -2647,6 +2251,43 @@ done:
clear_bit(BTUSB_BOOTLOADER, &data->flags);
+ /* Once the device is running in operational mode, it needs to apply
+ * the device configuration (DDC) parameters.
+ *
+ * The device can work without DDC parameters, so even if it fails
+ * to load the file, no need to fail the setup.
+ */
+ err = request_firmware_direct(&fw, fwname, &hdev->dev);
+ if (err < 0)
+ return 0;
+
+ BT_INFO("%s: Found Intel DDC parameters: %s", hdev->name, fwname);
+
+ fw_ptr = fw->data;
+
+ /* DDC file contains one or more DDC structure which has
+ * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2).
+ */
+ while (fw->size > fw_ptr - fw->data) {
+ u8 cmd_plen = fw_ptr[0] + sizeof(u8);
+
+ skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Failed to send Intel_Write_DDC (%ld)",
+ hdev->name, PTR_ERR(skb));
+ release_firmware(fw);
+ return PTR_ERR(skb);
+ }
+
+ fw_ptr += cmd_plen;
+ kfree_skb(skb);
+ }
+
+ release_firmware(fw);
+
+ BT_INFO("%s: Applying Intel DDC parameters completed", hdev->name);
+
return 0;
}
@@ -2678,13 +2319,6 @@ static void btusb_hw_error_intel(struct hci_dev *hdev, u8 code)
return;
}
- if (skb->data[0] != 0x00) {
- BT_ERR("%s: Exception info command failure (%02x)",
- hdev->name, skb->data[0]);
- kfree_skb(skb);
- return;
- }
-
BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1));
kfree_skb(skb);
@@ -2792,6 +2426,7 @@ struct qca_device_info {
static const struct qca_device_info qca_devices_table[] = {
{ 0x00000100, 20, 4, 10 }, /* Rome 1.0 */
{ 0x00000101, 20, 4, 10 }, /* Rome 1.1 */
+ { 0x00000200, 28, 4, 18 }, /* Rome 2.0 */
{ 0x00000201, 28, 4, 18 }, /* Rome 2.1 */
{ 0x00000300, 28, 4, 18 }, /* Rome 3.0 */
{ 0x00000302, 28, 4, 18 }, /* Rome 3.2 */
@@ -3175,8 +2810,17 @@ static int btusb_probe(struct usb_interface *intf,
hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
}
- if (id->driver_info & BTUSB_REALTEK)
- hdev->setup = btusb_setup_realtek;
+#ifdef CONFIG_BT_HCIBTUSB_RTL
+ if (id->driver_info & BTUSB_REALTEK) {
+ hdev->setup = btrtl_setup_realtek;
+
+ /* Realtek devices lose their updated firmware over suspend,
+ * but the USB hub doesn't notice any status change.
+ * Explicitly request a device reset on resume.
+ */
+ set_bit(BTUSB_RESET_RESUME, &data->flags);
+ }
+#endif
if (id->driver_info & BTUSB_AMP) {
/* AMP controllers do not support SCO packets */
@@ -3308,6 +2952,14 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
btusb_stop_traffic(data);
usb_kill_anchored_urbs(&data->tx_anchor);
+ /* Optionally request a device reset on resume, but only when
+ * wakeups are disabled. If wakeups are enabled we assume the
+ * device will stay powered up throughout suspend.
+ */
+ if (test_bit(BTUSB_RESET_RESUME, &data->flags) &&
+ !device_may_wakeup(&data->udev->dev))
+ data->udev->reset_resume = 1;
+
return 0;
}
diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c
index 55c135b7757a..7a722df97343 100644
--- a/drivers/bluetooth/btwilink.c
+++ b/drivers/bluetooth/btwilink.c
@@ -22,7 +22,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#define DEBUG
+
#include <linux/platform_device.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index ec8fa0e0f036..6da5e4ca13ea 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -192,6 +192,7 @@ static int ath_recv(struct hci_uart *hu, const void *data, int count)
if (IS_ERR(ath->rx_skb)) {
int err = PTR_ERR(ath->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
+ ath->rx_skb = NULL;
return err;
}
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 1ec0b4a5ffa6..23523e140a9a 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -24,6 +24,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
+#include <linux/firmware.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -36,6 +37,55 @@ struct bcm_data {
struct sk_buff_head txq;
};
+static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed)
+{
+ struct hci_dev *hdev = hu->hdev;
+ struct sk_buff *skb;
+ struct bcm_update_uart_baud_rate param;
+
+ if (speed > 3000000) {
+ struct bcm_write_uart_clock_setting clock;
+
+ clock.type = BCM_UART_CLOCK_48MHZ;
+
+ BT_DBG("%s: Set Controller clock (%d)", hdev->name, clock.type);
+
+ /* This Broadcom specific command changes the UART's controller
+ * clock for baud rate > 3000000.
+ */
+ skb = __hci_cmd_sync(hdev, 0xfc45, 1, &clock, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ int err = PTR_ERR(skb);
+ BT_ERR("%s: BCM: failed to write clock command (%d)",
+ hdev->name, err);
+ return err;
+ }
+
+ kfree_skb(skb);
+ }
+
+ BT_DBG("%s: Set Controller UART speed to %d bit/s", hdev->name, speed);
+
+ param.zero = cpu_to_le16(0);
+ param.baud_rate = cpu_to_le32(speed);
+
+ /* This Broadcom specific command changes the UART's controller baud
+ * rate.
+ */
+ skb = __hci_cmd_sync(hdev, 0xfc18, sizeof(param), &param,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ int err = PTR_ERR(skb);
+ BT_ERR("%s: BCM: failed to write update baudrate command (%d)",
+ hdev->name, err);
+ return err;
+ }
+
+ kfree_skb(skb);
+
+ return 0;
+}
+
static int bcm_open(struct hci_uart *hu)
{
struct bcm_data *bcm;
@@ -79,11 +129,62 @@ static int bcm_flush(struct hci_uart *hu)
static int bcm_setup(struct hci_uart *hu)
{
+ char fw_name[64];
+ const struct firmware *fw;
+ unsigned int speed;
+ int err;
+
BT_DBG("hu %p", hu);
hu->hdev->set_bdaddr = btbcm_set_bdaddr;
- return btbcm_setup_patchram(hu->hdev);
+ err = btbcm_initialize(hu->hdev, fw_name, sizeof(fw_name));
+ if (err)
+ return err;
+
+ err = request_firmware(&fw, fw_name, &hu->hdev->dev);
+ if (err < 0) {
+ BT_INFO("%s: BCM: Patch %s not found", hu->hdev->name, fw_name);
+ return 0;
+ }
+
+ err = btbcm_patchram(hu->hdev, fw);
+ if (err) {
+ BT_INFO("%s: BCM: Patch failed (%d)", hu->hdev->name, err);
+ goto finalize;
+ }
+
+ /* Init speed if any */
+ if (hu->init_speed)
+ speed = hu->init_speed;
+ else if (hu->proto->init_speed)
+ speed = hu->proto->init_speed;
+ else
+ speed = 0;
+
+ if (speed)
+ hci_uart_set_baudrate(hu, speed);
+
+ /* Operational speed if any */
+ if (hu->oper_speed)
+ speed = hu->oper_speed;
+ else if (hu->proto->oper_speed)
+ speed = hu->proto->oper_speed;
+ else
+ speed = 0;
+
+ if (speed) {
+ err = bcm_set_baudrate(hu, speed);
+ if (!err)
+ hci_uart_set_baudrate(hu, speed);
+ }
+
+finalize:
+ release_firmware(fw);
+
+ err = btbcm_finalize(hu->hdev);
+
+ return err;
}
static const struct h4_recv_pkt bcm_recv_pkts[] = {
@@ -104,6 +205,7 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count)
if (IS_ERR(bcm->rx_skb)) {
int err = PTR_ERR(bcm->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
+ bcm->rx_skb = NULL;
return err;
}
@@ -133,10 +235,13 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
static const struct hci_uart_proto bcm_proto = {
.id = HCI_UART_BCM,
.name = "BCM",
+ .init_speed = 115200,
+ .oper_speed = 4000000,
.open = bcm_open,
.close = bcm_close,
.flush = bcm_flush,
.setup = bcm_setup,
+ .set_baudrate = bcm_set_baudrate,
.recv = bcm_recv,
.enqueue = bcm_enqueue,
.dequeue = bcm_dequeue,
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index dc8e3d4356a0..d0b615a932d1 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -47,8 +47,8 @@
#include "hci_uart.h"
-static bool txcrc = 1;
-static bool hciextn = 1;
+static bool txcrc = true;
+static bool hciextn = true;
#define BCSP_TXWINSIZE 4
@@ -436,7 +436,7 @@ static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char
break;
default:
memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1);
- if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
+ if ((bcsp->rx_skb->data[0] & 0x40) != 0 &&
bcsp->rx_state != BCSP_W4_CRC)
bcsp_crc_update(&bcsp->message_crc, byte);
bcsp->rx_count--;
@@ -447,24 +447,24 @@ static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char
switch (byte) {
case 0xdc:
memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1);
- if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
+ if ((bcsp->rx_skb->data[0] & 0x40) != 0 &&
bcsp->rx_state != BCSP_W4_CRC)
- bcsp_crc_update(&bcsp-> message_crc, 0xc0);
+ bcsp_crc_update(&bcsp->message_crc, 0xc0);
bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
bcsp->rx_count--;
break;
case 0xdd:
memcpy(skb_put(bcsp->rx_skb, 1), &db, 1);
- if ((bcsp->rx_skb-> data[0] & 0x40) != 0 &&
+ if ((bcsp->rx_skb->data[0] & 0x40) != 0 &&
bcsp->rx_state != BCSP_W4_CRC)
- bcsp_crc_update(&bcsp-> message_crc, 0xdb);
+ bcsp_crc_update(&bcsp->message_crc, 0xdb);
bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
bcsp->rx_count--;
break;
default:
- BT_ERR ("Invalid byte %02x after esc byte", byte);
+ BT_ERR("Invalid byte %02x after esc byte", byte);
kfree_skb(bcsp->rx_skb);
bcsp->rx_skb = NULL;
bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
@@ -527,7 +527,7 @@ static void bcsp_complete_rx_pkt(struct hci_uart *hu)
hci_recv_frame(hu->hdev, bcsp->rx_skb);
} else {
- BT_ERR ("Packet for unknown channel (%u %s)",
+ BT_ERR("Packet for unknown channel (%u %s)",
bcsp->rx_skb->data[1] & 0x0f,
bcsp->rx_skb->data[0] & 0x80 ?
"reliable" : "unreliable");
@@ -587,7 +587,7 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
}
if (bcsp->rx_skb->data[0] & 0x80 /* reliable pkt */
&& (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
- BT_ERR ("Out-of-order packet arrived, got %u expected %u",
+ BT_ERR("Out-of-order packet arrived, got %u expected %u",
bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
kfree_skb(bcsp->rx_skb);
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index f7190f01e135..57faddc53645 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -133,6 +133,7 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count)
if (IS_ERR(h4->rx_skb)) {
int err = PTR_ERR(h4->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
+ h4->rx_skb = NULL;
return err;
}
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 5c9a73f02664..177dd69fdd95 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -40,6 +40,7 @@
#include <linux/signal.h>
#include <linux/ioctl.h>
#include <linux/skbuff.h>
+#include <linux/firmware.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -265,11 +266,133 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
return 0;
}
+/* Flow control or un-flow control the device */
+void hci_uart_set_flow_control(struct hci_uart *hu, bool enable)
+{
+ struct tty_struct *tty = hu->tty;
+ struct ktermios ktermios;
+ int status;
+ unsigned int set = 0;
+ unsigned int clear = 0;
+
+ if (enable) {
+ /* Disable hardware flow control */
+ ktermios = tty->termios;
+ ktermios.c_cflag &= ~CRTSCTS;
+ status = tty_set_termios(tty, &ktermios);
+ BT_DBG("Disabling hardware flow control: %s",
+ status ? "failed" : "success");
+
+ /* Clear RTS to prevent the device from sending */
+ /* Most UARTs need OUT2 to enable interrupts */
+ status = tty->driver->ops->tiocmget(tty);
+ BT_DBG("Current tiocm 0x%x", status);
+
+ set &= ~(TIOCM_OUT2 | TIOCM_RTS);
+ clear = ~set;
+ set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
+ TIOCM_OUT2 | TIOCM_LOOP;
+ clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
+ TIOCM_OUT2 | TIOCM_LOOP;
+ status = tty->driver->ops->tiocmset(tty, set, clear);
+ BT_DBG("Clearing RTS: %s", status ? "failed" : "success");
+ } else {
+ /* Set RTS to allow the device to send again */
+ status = tty->driver->ops->tiocmget(tty);
+ BT_DBG("Current tiocm 0x%x", status);
+
+ set |= (TIOCM_OUT2 | TIOCM_RTS);
+ clear = ~set;
+ set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
+ TIOCM_OUT2 | TIOCM_LOOP;
+ clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
+ TIOCM_OUT2 | TIOCM_LOOP;
+ status = tty->driver->ops->tiocmset(tty, set, clear);
+ BT_DBG("Setting RTS: %s", status ? "failed" : "success");
+
+ /* Re-enable hardware flow control */
+ ktermios = tty->termios;
+ ktermios.c_cflag |= CRTSCTS;
+ status = tty_set_termios(tty, &ktermios);
+ BT_DBG("Enabling hardware flow control: %s",
+ status ? "failed" : "success");
+ }
+}
+
+void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed,
+ unsigned int oper_speed)
+{
+ hu->init_speed = init_speed;
+ hu->oper_speed = oper_speed;
+}
+
+void hci_uart_init_tty(struct hci_uart *hu)
+{
+ struct tty_struct *tty = hu->tty;
+ struct ktermios ktermios;
+
+ /* Bring the UART into a known 8 bits no parity hw fc state */
+ ktermios = tty->termios;
+ ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP |
+ INLCR | IGNCR | ICRNL | IXON);
+ ktermios.c_oflag &= ~OPOST;
+ ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ ktermios.c_cflag &= ~(CSIZE | PARENB);
+ ktermios.c_cflag |= CS8;
+ ktermios.c_cflag |= CRTSCTS;
+
+ /* tty_set_termios() return not checked as it is always 0 */
+ tty_set_termios(tty, &ktermios);
+}
+
+void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed)
+{
+ struct tty_struct *tty = hu->tty;
+ struct ktermios ktermios;
+
+ ktermios = tty->termios;
+ ktermios.c_cflag &= ~CBAUD;
+ tty_termios_encode_baud_rate(&ktermios, speed, speed);
+
+ /* tty_set_termios() return not checked as it is always 0 */
+ tty_set_termios(tty, &ktermios);
+
+ BT_DBG("%s: New tty speeds: %d/%d", hu->hdev->name,
+ tty->termios.c_ispeed, tty->termios.c_ospeed);
+}
+
static int hci_uart_setup(struct hci_dev *hdev)
{
struct hci_uart *hu = hci_get_drvdata(hdev);
struct hci_rp_read_local_version *ver;
struct sk_buff *skb;
+ unsigned int speed;
+ int err;
+
+ /* Init speed if any */
+ if (hu->init_speed)
+ speed = hu->init_speed;
+ else if (hu->proto->init_speed)
+ speed = hu->proto->init_speed;
+ else
+ speed = 0;
+
+ if (speed)
+ hci_uart_set_baudrate(hu, speed);
+
+ /* Operational speed if any */
+ if (hu->oper_speed)
+ speed = hu->oper_speed;
+ else if (hu->proto->oper_speed)
+ speed = hu->proto->oper_speed;
+ else
+ speed = 0;
+
+ if (hu->proto->set_baudrate && speed) {
+ err = hu->proto->set_baudrate(hu, speed);
+ if (!err)
+ hci_uart_set_baudrate(hu, speed);
+ }
if (hu->proto->setup)
return hu->proto->setup(hu);
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 72120a5ba13c..ce9c670956f5 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -58,10 +58,13 @@ struct hci_uart;
struct hci_uart_proto {
unsigned int id;
const char *name;
+ unsigned int init_speed;
+ unsigned int oper_speed;
int (*open)(struct hci_uart *hu);
int (*close)(struct hci_uart *hu);
int (*flush)(struct hci_uart *hu);
int (*setup)(struct hci_uart *hu);
+ int (*set_baudrate)(struct hci_uart *hu, unsigned int speed);
int (*recv)(struct hci_uart *hu, const void *data, int len);
int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
struct sk_buff *(*dequeue)(struct hci_uart *hu);
@@ -82,6 +85,9 @@ struct hci_uart {
struct sk_buff *tx_skb;
unsigned long tx_state;
spinlock_t rx_lock;
+
+ unsigned int init_speed;
+ unsigned int oper_speed;
};
/* HCI_UART proto flag bits */
@@ -96,6 +102,11 @@ int hci_uart_register_proto(const struct hci_uart_proto *p);
int hci_uart_unregister_proto(const struct hci_uart_proto *p);
int hci_uart_tx_wakeup(struct hci_uart *hu);
int hci_uart_init_ready(struct hci_uart *hu);
+void hci_uart_init_tty(struct hci_uart *hu);
+void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed);
+void hci_uart_set_flow_control(struct hci_uart *hu, bool enable);
+void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed,
+ unsigned int oper_speed);
#ifdef CONFIG_BT_HCIUART_H4
int h4_init(void);
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 6653473f2757..78653db2ef2b 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -366,7 +366,7 @@ static const struct file_operations vhci_fops = {
.llseek = no_llseek,
};
-static struct miscdevice vhci_miscdev= {
+static struct miscdevice vhci_miscdev = {
.name = "vhci",
.fops = &vhci_fops,
.minor = VHCI_MINOR,
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index a1d4af6df3f5..1a82f3a17681 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -7,21 +7,24 @@ menu "Bus devices"
config ARM_CCI
bool
+config ARM_CCI_PMU
+ bool
+ select ARM_CCI
+
config ARM_CCI400_COMMON
bool
select ARM_CCI
config ARM_CCI400_PMU
bool "ARM CCI400 PMU support"
- default y
- depends on ARM || ARM64
- depends on HW_PERF_EVENTS
+ depends on (ARM && CPU_V7) || ARM64
+ depends on PERF_EVENTS
select ARM_CCI400_COMMON
+ select ARM_CCI_PMU
help
- Support for PMU events monitoring on the ARM CCI cache coherent
- interconnect.
-
- If unsure, say Y
+ Support for PMU events monitoring on the ARM CCI-400 (cache coherent
+ interconnect). CCI-400 supports counting events related to the
+ connected slave/master interfaces.
config ARM_CCI400_PORT_CTRL
bool
@@ -31,6 +34,20 @@ config ARM_CCI400_PORT_CTRL
Low level power management driver for CCI400 cache coherent
interconnect for ARM platforms.
+config ARM_CCI500_PMU
+ bool "ARM CCI500 PMU support"
+ default y
+ depends on (ARM && CPU_V7) || ARM64
+ depends on PERF_EVENTS
+ select ARM_CCI_PMU
+ help
+ Support for PMU events monitoring on the ARM CCI-500 cache coherent
+ interconnect. CCI-500 provides 8 independent event counters, which
+ can count events pertaining to the slave/master interfaces as well
+ as the internal events to the CCI.
+
+ If unsure, say Y
+
config ARM_CCN
bool "ARM CCN driver support"
depends on ARM || ARM64
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 5340604b23a4..577cc4bf6a9d 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -52,12 +52,15 @@ static const struct of_device_id arm_cci_matches[] = {
#ifdef CONFIG_ARM_CCI400_COMMON
{.compatible = "arm,cci-400", .data = CCI400_PORTS_DATA },
#endif
+#ifdef CONFIG_ARM_CCI500_PMU
+ { .compatible = "arm,cci-500", },
+#endif
{},
};
-#ifdef CONFIG_ARM_CCI400_PMU
+#ifdef CONFIG_ARM_CCI_PMU
-#define DRIVER_NAME "CCI-400"
+#define DRIVER_NAME "ARM-CCI"
#define DRIVER_NAME_PMU DRIVER_NAME " PMU"
#define CCI_PMCR 0x0100
@@ -77,20 +80,21 @@ static const struct of_device_id arm_cci_matches[] = {
#define CCI_PMU_OVRFLW_FLAG 1
-#define CCI_PMU_CNTR_BASE(idx) ((idx) * SZ_4K)
-
-#define CCI_PMU_CNTR_MASK ((1ULL << 32) -1)
+#define CCI_PMU_CNTR_SIZE(model) ((model)->cntr_size)
+#define CCI_PMU_CNTR_BASE(model, idx) ((idx) * CCI_PMU_CNTR_SIZE(model))
+#define CCI_PMU_CNTR_MASK ((1ULL << 32) -1)
+#define CCI_PMU_CNTR_LAST(cci_pmu) (cci_pmu->num_cntrs - 1)
-#define CCI_PMU_EVENT_MASK 0xffUL
-#define CCI_PMU_EVENT_SOURCE(event) ((event >> 5) & 0x7)
-#define CCI_PMU_EVENT_CODE(event) (event & 0x1f)
-
-#define CCI_PMU_MAX_HW_EVENTS 5 /* CCI PMU has 4 counters + 1 cycle counter */
+#define CCI_PMU_MAX_HW_CNTRS(model) \
+ ((model)->num_hw_cntrs + (model)->fixed_hw_cntrs)
/* Types of interfaces that can generate events */
enum {
CCI_IF_SLAVE,
CCI_IF_MASTER,
+#ifdef CONFIG_ARM_CCI500_PMU
+ CCI_IF_GLOBAL,
+#endif
CCI_IF_MAX,
};
@@ -100,14 +104,30 @@ struct event_range {
};
struct cci_pmu_hw_events {
- struct perf_event *events[CCI_PMU_MAX_HW_EVENTS];
- unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)];
+ struct perf_event **events;
+ unsigned long *used_mask;
raw_spinlock_t pmu_lock;
};
+struct cci_pmu;
+/*
+ * struct cci_pmu_model:
+ * @fixed_hw_cntrs - Number of fixed event counters
+ * @num_hw_cntrs - Maximum number of programmable event counters
+ * @cntr_size - Size of an event counter mapping
+ */
struct cci_pmu_model {
char *name;
+ u32 fixed_hw_cntrs;
+ u32 num_hw_cntrs;
+ u32 cntr_size;
+ u64 nformat_attrs;
+ u64 nevent_attrs;
+ struct dev_ext_attribute *format_attrs;
+ struct dev_ext_attribute *event_attrs;
struct event_range event_ranges[CCI_IF_MAX];
+ int (*validate_hw_event)(struct cci_pmu *, unsigned long);
+ int (*get_event_idx)(struct cci_pmu *, struct cci_pmu_hw_events *, unsigned long);
};
static struct cci_pmu_model cci_pmu_models[];
@@ -116,33 +136,59 @@ struct cci_pmu {
void __iomem *base;
struct pmu pmu;
int nr_irqs;
- int irqs[CCI_PMU_MAX_HW_EVENTS];
+ int *irqs;
unsigned long active_irqs;
const struct cci_pmu_model *model;
struct cci_pmu_hw_events hw_events;
struct platform_device *plat_device;
- int num_events;
+ int num_cntrs;
atomic_t active_events;
struct mutex reserve_mutex;
+ struct notifier_block cpu_nb;
cpumask_t cpus;
};
-static struct cci_pmu *pmu;
#define to_cci_pmu(c) (container_of(c, struct cci_pmu, pmu))
+enum cci_models {
+#ifdef CONFIG_ARM_CCI400_PMU
+ CCI400_R0,
+ CCI400_R1,
+#endif
+#ifdef CONFIG_ARM_CCI500_PMU
+ CCI500_R0,
+#endif
+ CCI_MODEL_MAX
+};
+
+static ssize_t cci_pmu_format_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t cci_pmu_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+#define CCI_EXT_ATTR_ENTRY(_name, _func, _config) \
+ { __ATTR(_name, S_IRUGO, _func, NULL), (void *)_config }
+
+#define CCI_FORMAT_EXT_ATTR_ENTRY(_name, _config) \
+ CCI_EXT_ATTR_ENTRY(_name, cci_pmu_format_show, (char *)_config)
+#define CCI_EVENT_EXT_ATTR_ENTRY(_name, _config) \
+ CCI_EXT_ATTR_ENTRY(_name, cci_pmu_event_show, (unsigned long)_config)
+
+/* CCI400 PMU Specific definitions */
+
+#ifdef CONFIG_ARM_CCI400_PMU
+
/* Port ids */
-#define CCI_PORT_S0 0
-#define CCI_PORT_S1 1
-#define CCI_PORT_S2 2
-#define CCI_PORT_S3 3
-#define CCI_PORT_S4 4
-#define CCI_PORT_M0 5
-#define CCI_PORT_M1 6
-#define CCI_PORT_M2 7
-
-#define CCI_REV_R0 0
-#define CCI_REV_R1 1
-#define CCI_REV_R1_PX 5
+#define CCI400_PORT_S0 0
+#define CCI400_PORT_S1 1
+#define CCI400_PORT_S2 2
+#define CCI400_PORT_S3 3
+#define CCI400_PORT_S4 4
+#define CCI400_PORT_M0 5
+#define CCI400_PORT_M1 6
+#define CCI400_PORT_M2 7
+
+#define CCI400_R1_PX 5
/*
* Instead of an event id to monitor CCI cycles, a dedicated counter is
@@ -150,12 +196,11 @@ static struct cci_pmu *pmu;
* make use of this event in hardware.
*/
enum cci400_perf_events {
- CCI_PMU_CYCLES = 0xff
+ CCI400_PMU_CYCLES = 0xff
};
-#define CCI_PMU_CYCLE_CNTR_IDX 0
-#define CCI_PMU_CNTR0_IDX 1
-#define CCI_PMU_CNTR_LAST(cci_pmu) (CCI_PMU_CYCLE_CNTR_IDX + cci_pmu->num_events - 1)
+#define CCI400_PMU_CYCLE_CNTR_IDX 0
+#define CCI400_PMU_CNTR0_IDX 1
/*
* CCI PMU event id is an 8-bit value made of two parts - bits 7:5 for one of 8
@@ -169,37 +214,173 @@ enum cci400_perf_events {
* the different revisions and are used to validate the event to be monitored.
*/
-#define CCI_REV_R0_SLAVE_PORT_MIN_EV 0x00
-#define CCI_REV_R0_SLAVE_PORT_MAX_EV 0x13
-#define CCI_REV_R0_MASTER_PORT_MIN_EV 0x14
-#define CCI_REV_R0_MASTER_PORT_MAX_EV 0x1a
+#define CCI400_PMU_EVENT_MASK 0xffUL
+#define CCI400_PMU_EVENT_SOURCE_SHIFT 5
+#define CCI400_PMU_EVENT_SOURCE_MASK 0x7
+#define CCI400_PMU_EVENT_CODE_SHIFT 0
+#define CCI400_PMU_EVENT_CODE_MASK 0x1f
+#define CCI400_PMU_EVENT_SOURCE(event) \
+ ((event >> CCI400_PMU_EVENT_SOURCE_SHIFT) & \
+ CCI400_PMU_EVENT_SOURCE_MASK)
+#define CCI400_PMU_EVENT_CODE(event) \
+ ((event >> CCI400_PMU_EVENT_CODE_SHIFT) & CCI400_PMU_EVENT_CODE_MASK)
+
+#define CCI400_R0_SLAVE_PORT_MIN_EV 0x00
+#define CCI400_R0_SLAVE_PORT_MAX_EV 0x13
+#define CCI400_R0_MASTER_PORT_MIN_EV 0x14
+#define CCI400_R0_MASTER_PORT_MAX_EV 0x1a
+
+#define CCI400_R1_SLAVE_PORT_MIN_EV 0x00
+#define CCI400_R1_SLAVE_PORT_MAX_EV 0x14
+#define CCI400_R1_MASTER_PORT_MIN_EV 0x00
+#define CCI400_R1_MASTER_PORT_MAX_EV 0x11
+
+#define CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(_name, _config) \
+ CCI_EXT_ATTR_ENTRY(_name, cci400_pmu_cycle_event_show, \
+ (unsigned long)_config)
+
+static ssize_t cci400_pmu_cycle_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static struct dev_ext_attribute cci400_pmu_format_attrs[] = {
+ CCI_FORMAT_EXT_ATTR_ENTRY(event, "config:0-4"),
+ CCI_FORMAT_EXT_ATTR_ENTRY(source, "config:5-7"),
+};
+
+static struct dev_ext_attribute cci400_r0_pmu_event_attrs[] = {
+ /* Slave events */
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_any, 0x0),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_device, 0x01),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_normal_or_nonshareable, 0x2),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_inner_or_outershareable, 0x3),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maintenance, 0x4),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_mem_barrier, 0x5),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_sync_barrier, 0x6),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg_sync, 0x8),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_tt_full, 0x9),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_last_hs_snoop, 0xA),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall_rvalids_h_rready_l, 0xB),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_any, 0xC),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_device, 0xD),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_normal_or_nonshareable, 0xE),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_inner_or_outershare_wback_wclean, 0xF),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_unique, 0x10),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_line_unique, 0x11),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_evict, 0x12),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall_tt_full, 0x13),
+ /* Master events */
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_retry_speculative_fetch, 0x14),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_addr_hazard, 0x15),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_id_hazard, 0x16),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_tt_full, 0x17),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_barrier_hazard, 0x18),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_barrier_hazard, 0x19),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_tt_full, 0x1A),
+ /* Special event for cycles counter */
+ CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(cycles, 0xff),
+};
+
+static struct dev_ext_attribute cci400_r1_pmu_event_attrs[] = {
+ /* Slave events */
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_any, 0x0),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_device, 0x01),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_normal_or_nonshareable, 0x2),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_inner_or_outershareable, 0x3),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maintenance, 0x4),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_mem_barrier, 0x5),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_sync_barrier, 0x6),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg_sync, 0x8),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_tt_full, 0x9),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_last_hs_snoop, 0xA),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall_rvalids_h_rready_l, 0xB),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_any, 0xC),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_device, 0xD),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_normal_or_nonshareable, 0xE),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_inner_or_outershare_wback_wclean, 0xF),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_unique, 0x10),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_write_line_unique, 0x11),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_evict, 0x12),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall_tt_full, 0x13),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_slave_id_hazard, 0x14),
+ /* Master events */
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_retry_speculative_fetch, 0x0),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_stall_cycle_addr_hazard, 0x1),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_master_id_hazard, 0x2),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_hi_prio_rtq_full, 0x3),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_barrier_hazard, 0x4),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_barrier_hazard, 0x5),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_wtq_full, 0x6),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_low_prio_rtq_full, 0x7),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_mid_prio_rtq_full, 0x8),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn0, 0x9),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn1, 0xA),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn2, 0xB),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall_qvn_vn3, 0xC),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn0, 0xD),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn1, 0xE),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn2, 0xF),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall_qvn_vn3, 0x10),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_unique_or_line_unique_addr_hazard, 0x11),
+ /* Special event for cycles counter */
+ CCI400_CYCLE_EVENT_EXT_ATTR_ENTRY(cycles, 0xff),
+};
-#define CCI_REV_R1_SLAVE_PORT_MIN_EV 0x00
-#define CCI_REV_R1_SLAVE_PORT_MAX_EV 0x14
-#define CCI_REV_R1_MASTER_PORT_MIN_EV 0x00
-#define CCI_REV_R1_MASTER_PORT_MAX_EV 0x11
+static ssize_t cci400_pmu_cycle_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *eattr = container_of(attr,
+ struct dev_ext_attribute, attr);
+ return snprintf(buf, PAGE_SIZE, "config=0x%lx\n", (unsigned long)eattr->var);
+}
-static int pmu_validate_hw_event(unsigned long hw_event)
+static int cci400_get_event_idx(struct cci_pmu *cci_pmu,
+ struct cci_pmu_hw_events *hw,
+ unsigned long cci_event)
{
- u8 ev_source = CCI_PMU_EVENT_SOURCE(hw_event);
- u8 ev_code = CCI_PMU_EVENT_CODE(hw_event);
+ int idx;
+
+ /* cycles event idx is fixed */
+ if (cci_event == CCI400_PMU_CYCLES) {
+ if (test_and_set_bit(CCI400_PMU_CYCLE_CNTR_IDX, hw->used_mask))
+ return -EAGAIN;
+
+ return CCI400_PMU_CYCLE_CNTR_IDX;
+ }
+
+ for (idx = CCI400_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+ if (!test_and_set_bit(idx, hw->used_mask))
+ return idx;
+
+ /* No counters available */
+ return -EAGAIN;
+}
+
+static int cci400_validate_hw_event(struct cci_pmu *cci_pmu, unsigned long hw_event)
+{
+ u8 ev_source = CCI400_PMU_EVENT_SOURCE(hw_event);
+ u8 ev_code = CCI400_PMU_EVENT_CODE(hw_event);
int if_type;
- if (hw_event & ~CCI_PMU_EVENT_MASK)
+ if (hw_event & ~CCI400_PMU_EVENT_MASK)
return -ENOENT;
+ if (hw_event == CCI400_PMU_CYCLES)
+ return hw_event;
+
switch (ev_source) {
- case CCI_PORT_S0:
- case CCI_PORT_S1:
- case CCI_PORT_S2:
- case CCI_PORT_S3:
- case CCI_PORT_S4:
+ case CCI400_PORT_S0:
+ case CCI400_PORT_S1:
+ case CCI400_PORT_S2:
+ case CCI400_PORT_S3:
+ case CCI400_PORT_S4:
/* Slave Interface */
if_type = CCI_IF_SLAVE;
break;
- case CCI_PORT_M0:
- case CCI_PORT_M1:
- case CCI_PORT_M2:
+ case CCI400_PORT_M0:
+ case CCI400_PORT_M1:
+ case CCI400_PORT_M2:
/* Master Interface */
if_type = CCI_IF_MASTER;
break;
@@ -207,87 +388,291 @@ static int pmu_validate_hw_event(unsigned long hw_event)
return -ENOENT;
}
- if (ev_code >= pmu->model->event_ranges[if_type].min &&
- ev_code <= pmu->model->event_ranges[if_type].max)
+ if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
+ ev_code <= cci_pmu->model->event_ranges[if_type].max)
return hw_event;
return -ENOENT;
}
-static int probe_cci_revision(void)
+static int probe_cci400_revision(void)
{
int rev;
rev = readl_relaxed(cci_ctrl_base + CCI_PID2) & CCI_PID2_REV_MASK;
rev >>= CCI_PID2_REV_SHIFT;
- if (rev < CCI_REV_R1_PX)
- return CCI_REV_R0;
+ if (rev < CCI400_R1_PX)
+ return CCI400_R0;
else
- return CCI_REV_R1;
+ return CCI400_R1;
}
static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
{
if (platform_has_secure_cci_access())
- return &cci_pmu_models[probe_cci_revision()];
+ return &cci_pmu_models[probe_cci400_revision()];
return NULL;
}
+#else /* !CONFIG_ARM_CCI400_PMU */
+static inline struct cci_pmu_model *probe_cci_model(struct platform_device *pdev)
+{
+ return NULL;
+}
+#endif /* CONFIG_ARM_CCI400_PMU */
+
+#ifdef CONFIG_ARM_CCI500_PMU
+
+/*
+ * CCI500 provides 8 independent event counters that can count
+ * any of the events available.
+ *
+ * CCI500 PMU event id is an 9-bit value made of two parts.
+ * bits [8:5] - Source for the event
+ * 0x0-0x6 - Slave interfaces
+ * 0x8-0xD - Master interfaces
+ * 0xf - Global Events
+ * 0x7,0xe - Reserved
+ *
+ * bits [4:0] - Event code (specific to type of interface)
+ */
+
+/* Port ids */
+#define CCI500_PORT_S0 0x0
+#define CCI500_PORT_S1 0x1
+#define CCI500_PORT_S2 0x2
+#define CCI500_PORT_S3 0x3
+#define CCI500_PORT_S4 0x4
+#define CCI500_PORT_S5 0x5
+#define CCI500_PORT_S6 0x6
+
+#define CCI500_PORT_M0 0x8
+#define CCI500_PORT_M1 0x9
+#define CCI500_PORT_M2 0xa
+#define CCI500_PORT_M3 0xb
+#define CCI500_PORT_M4 0xc
+#define CCI500_PORT_M5 0xd
+
+#define CCI500_PORT_GLOBAL 0xf
+
+#define CCI500_PMU_EVENT_MASK 0x1ffUL
+#define CCI500_PMU_EVENT_SOURCE_SHIFT 0x5
+#define CCI500_PMU_EVENT_SOURCE_MASK 0xf
+#define CCI500_PMU_EVENT_CODE_SHIFT 0x0
+#define CCI500_PMU_EVENT_CODE_MASK 0x1f
+
+#define CCI500_PMU_EVENT_SOURCE(event) \
+ ((event >> CCI500_PMU_EVENT_SOURCE_SHIFT) & CCI500_PMU_EVENT_SOURCE_MASK)
+#define CCI500_PMU_EVENT_CODE(event) \
+ ((event >> CCI500_PMU_EVENT_CODE_SHIFT) & CCI500_PMU_EVENT_CODE_MASK)
+
+#define CCI500_SLAVE_PORT_MIN_EV 0x00
+#define CCI500_SLAVE_PORT_MAX_EV 0x1f
+#define CCI500_MASTER_PORT_MIN_EV 0x00
+#define CCI500_MASTER_PORT_MAX_EV 0x06
+#define CCI500_GLOBAL_PORT_MIN_EV 0x00
+#define CCI500_GLOBAL_PORT_MAX_EV 0x0f
+
+
+#define CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(_name, _config) \
+ CCI_EXT_ATTR_ENTRY(_name, cci500_pmu_global_event_show, \
+ (unsigned long) _config)
+
+static ssize_t cci500_pmu_global_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static struct dev_ext_attribute cci500_pmu_format_attrs[] = {
+ CCI_FORMAT_EXT_ATTR_ENTRY(event, "config:0-4"),
+ CCI_FORMAT_EXT_ATTR_ENTRY(source, "config:5-8"),
+};
+
+static struct dev_ext_attribute cci500_pmu_event_attrs[] = {
+ /* Slave events */
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_arvalid, 0x0),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_dev, 0x1),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_nonshareable, 0x2),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_shareable_non_alloc, 0x3),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_shareable_alloc, 0x4),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_invalidate, 0x5),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_cache_maint, 0x6),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_dvm_msg, 0x7),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_rval, 0x8),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_hs_rlast_snoop, 0x9),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_hs_awalid, 0xA),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_dev, 0xB),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_non_shareable, 0xC),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wb, 0xD),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wlu, 0xE),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_share_wunique, 0xF),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_evict, 0x10),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_wrevict, 0x11),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_w_data_beat, 0x12),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_srq_acvalid, 0x13),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_srq_read, 0x14),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_srq_clean, 0x15),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_srq_data_transfer_low, 0x16),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rrq_stall_arvalid, 0x17),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_r_data_stall, 0x18),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_wrq_stall, 0x19),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_w_data_stall, 0x1A),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_w_resp_stall, 0x1B),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_srq_stall, 0x1C),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_s_data_stall, 0x1D),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_rq_stall_ot_limit, 0x1E),
+ CCI_EVENT_EXT_ATTR_ENTRY(si_r_stall_arbit, 0x1F),
+
+ /* Master events */
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_r_data_beat_any, 0x0),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_w_data_beat_any, 0x1),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_rrq_stall, 0x2),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_r_data_stall, 0x3),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_wrq_stall, 0x4),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_w_data_stall, 0x5),
+ CCI_EVENT_EXT_ATTR_ENTRY(mi_w_resp_stall, 0x6),
+
+ /* Global events */
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_0_1, 0x0),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_2_3, 0x1),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_4_5, 0x2),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_filter_bank_6_7, 0x3),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_0_1, 0x4),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_2_3, 0x5),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_4_5, 0x6),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_access_miss_filter_bank_6_7, 0x7),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_back_invalidation, 0x8),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_stall_alloc_busy, 0x9),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_stall_tt_full, 0xA),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_wrq, 0xB),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_cd_hs, 0xC),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_rq_stall_addr_hazard, 0xD),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snopp_rq_stall_tt_full, 0xE),
+ CCI500_GLOBAL_EVENT_EXT_ATTR_ENTRY(cci_snoop_rq_tzmp1_prot, 0xF),
+};
+
+static ssize_t cci500_pmu_global_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *eattr = container_of(attr,
+ struct dev_ext_attribute, attr);
+ /* Global events have single fixed source code */
+ return snprintf(buf, PAGE_SIZE, "event=0x%lx,source=0x%x\n",
+ (unsigned long)eattr->var, CCI500_PORT_GLOBAL);
+}
+
+static int cci500_validate_hw_event(struct cci_pmu *cci_pmu,
+ unsigned long hw_event)
+{
+ u32 ev_source = CCI500_PMU_EVENT_SOURCE(hw_event);
+ u32 ev_code = CCI500_PMU_EVENT_CODE(hw_event);
+ int if_type;
+
+ if (hw_event & ~CCI500_PMU_EVENT_MASK)
+ return -ENOENT;
+
+ switch (ev_source) {
+ case CCI500_PORT_S0:
+ case CCI500_PORT_S1:
+ case CCI500_PORT_S2:
+ case CCI500_PORT_S3:
+ case CCI500_PORT_S4:
+ case CCI500_PORT_S5:
+ case CCI500_PORT_S6:
+ if_type = CCI_IF_SLAVE;
+ break;
+ case CCI500_PORT_M0:
+ case CCI500_PORT_M1:
+ case CCI500_PORT_M2:
+ case CCI500_PORT_M3:
+ case CCI500_PORT_M4:
+ case CCI500_PORT_M5:
+ if_type = CCI_IF_MASTER;
+ break;
+ case CCI500_PORT_GLOBAL:
+ if_type = CCI_IF_GLOBAL;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ if (ev_code >= cci_pmu->model->event_ranges[if_type].min &&
+ ev_code <= cci_pmu->model->event_ranges[if_type].max)
+ return hw_event;
+
+ return -ENOENT;
+}
+#endif /* CONFIG_ARM_CCI500_PMU */
+
+static ssize_t cci_pmu_format_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *eattr = container_of(attr,
+ struct dev_ext_attribute, attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n", (char *)eattr->var);
+}
+
+static ssize_t cci_pmu_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *eattr = container_of(attr,
+ struct dev_ext_attribute, attr);
+ /* source parameter is mandatory for normal PMU events */
+ return snprintf(buf, PAGE_SIZE, "source=?,event=0x%lx\n",
+ (unsigned long)eattr->var);
+}
static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
{
- return CCI_PMU_CYCLE_CNTR_IDX <= idx &&
- idx <= CCI_PMU_CNTR_LAST(cci_pmu);
+ return 0 <= idx && idx <= CCI_PMU_CNTR_LAST(cci_pmu);
}
-static u32 pmu_read_register(int idx, unsigned int offset)
+static u32 pmu_read_register(struct cci_pmu *cci_pmu, int idx, unsigned int offset)
{
- return readl_relaxed(pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
+ return readl_relaxed(cci_pmu->base +
+ CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
}
-static void pmu_write_register(u32 value, int idx, unsigned int offset)
+static void pmu_write_register(struct cci_pmu *cci_pmu, u32 value,
+ int idx, unsigned int offset)
{
- return writel_relaxed(value, pmu->base + CCI_PMU_CNTR_BASE(idx) + offset);
+ return writel_relaxed(value, cci_pmu->base +
+ CCI_PMU_CNTR_BASE(cci_pmu->model, idx) + offset);
}
-static void pmu_disable_counter(int idx)
+static void pmu_disable_counter(struct cci_pmu *cci_pmu, int idx)
{
- pmu_write_register(0, idx, CCI_PMU_CNTR_CTRL);
+ pmu_write_register(cci_pmu, 0, idx, CCI_PMU_CNTR_CTRL);
}
-static void pmu_enable_counter(int idx)
+static void pmu_enable_counter(struct cci_pmu *cci_pmu, int idx)
{
- pmu_write_register(1, idx, CCI_PMU_CNTR_CTRL);
+ pmu_write_register(cci_pmu, 1, idx, CCI_PMU_CNTR_CTRL);
}
-static void pmu_set_event(int idx, unsigned long event)
+static void pmu_set_event(struct cci_pmu *cci_pmu, int idx, unsigned long event)
{
- pmu_write_register(event, idx, CCI_PMU_EVT_SEL);
+ pmu_write_register(cci_pmu, event, idx, CCI_PMU_EVT_SEL);
}
+/*
+ * Returns the number of programmable counters actually implemented
+ * by the cci
+ */
static u32 pmu_get_max_counters(void)
{
- u32 n_cnts = (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
- CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
-
- /* add 1 for cycle counter */
- return n_cnts + 1;
+ return (readl_relaxed(cci_ctrl_base + CCI_PMCR) &
+ CCI_PMCR_NCNT_MASK) >> CCI_PMCR_NCNT_SHIFT;
}
static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
{
struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
- struct hw_perf_event *hw_event = &event->hw;
- unsigned long cci_event = hw_event->config_base;
+ unsigned long cci_event = event->hw.config_base;
int idx;
- if (cci_event == CCI_PMU_CYCLES) {
- if (test_and_set_bit(CCI_PMU_CYCLE_CNTR_IDX, hw->used_mask))
- return -EAGAIN;
+ if (cci_pmu->model->get_event_idx)
+ return cci_pmu->model->get_event_idx(cci_pmu, hw, cci_event);
- return CCI_PMU_CYCLE_CNTR_IDX;
- }
-
- for (idx = CCI_PMU_CNTR0_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); ++idx)
+ /* Generic code to find an unused idx from the mask */
+ for(idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++)
if (!test_and_set_bit(idx, hw->used_mask))
return idx;
@@ -297,18 +682,13 @@ static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *ev
static int pmu_map_event(struct perf_event *event)
{
- int mapping;
- unsigned long config = event->attr.config;
+ struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
- if (event->attr.type < PERF_TYPE_MAX)
+ if (event->attr.type < PERF_TYPE_MAX ||
+ !cci_pmu->model->validate_hw_event)
return -ENOENT;
- if (config == CCI_PMU_CYCLES)
- mapping = config;
- else
- mapping = pmu_validate_hw_event(config);
-
- return mapping;
+ return cci_pmu->model->validate_hw_event(cci_pmu, event->attr.config);
}
static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
@@ -319,7 +699,7 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
if (unlikely(!pmu_device))
return -ENODEV;
- if (pmu->nr_irqs < 1) {
+ if (cci_pmu->nr_irqs < 1) {
dev_err(&pmu_device->dev, "no irqs for CCI PMUs defined\n");
return -ENODEV;
}
@@ -331,16 +711,16 @@ static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
*
* This should allow handling of non-unique interrupt for the counters.
*/
- for (i = 0; i < pmu->nr_irqs; i++) {
- int err = request_irq(pmu->irqs[i], handler, IRQF_SHARED,
+ for (i = 0; i < cci_pmu->nr_irqs; i++) {
+ int err = request_irq(cci_pmu->irqs[i], handler, IRQF_SHARED,
"arm-cci-pmu", cci_pmu);
if (err) {
dev_err(&pmu_device->dev, "unable to request IRQ%d for ARM CCI PMU counters\n",
- pmu->irqs[i]);
+ cci_pmu->irqs[i]);
return err;
}
- set_bit(i, &pmu->active_irqs);
+ set_bit(i, &cci_pmu->active_irqs);
}
return 0;
@@ -350,11 +730,11 @@ static void pmu_free_irq(struct cci_pmu *cci_pmu)
{
int i;
- for (i = 0; i < pmu->nr_irqs; i++) {
- if (!test_and_clear_bit(i, &pmu->active_irqs))
+ for (i = 0; i < cci_pmu->nr_irqs; i++) {
+ if (!test_and_clear_bit(i, &cci_pmu->active_irqs))
continue;
- free_irq(pmu->irqs[i], cci_pmu);
+ free_irq(cci_pmu->irqs[i], cci_pmu);
}
}
@@ -369,7 +749,7 @@ static u32 pmu_read_counter(struct perf_event *event)
dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
return 0;
}
- value = pmu_read_register(idx, CCI_PMU_CNTR);
+ value = pmu_read_register(cci_pmu, idx, CCI_PMU_CNTR);
return value;
}
@@ -383,7 +763,7 @@ static void pmu_write_counter(struct perf_event *event, u32 value)
if (unlikely(!pmu_is_valid_counter(cci_pmu, idx)))
dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
else
- pmu_write_register(value, idx, CCI_PMU_CNTR);
+ pmu_write_register(cci_pmu, value, idx, CCI_PMU_CNTR);
}
static u64 pmu_event_update(struct perf_event *event)
@@ -427,7 +807,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
{
unsigned long flags;
struct cci_pmu *cci_pmu = dev;
- struct cci_pmu_hw_events *events = &pmu->hw_events;
+ struct cci_pmu_hw_events *events = &cci_pmu->hw_events;
int idx, handled = IRQ_NONE;
raw_spin_lock_irqsave(&events->pmu_lock, flags);
@@ -436,7 +816,7 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
* This should work regardless of whether we have per-counter overflow
* interrupt or a combined overflow interrupt.
*/
- for (idx = CCI_PMU_CYCLE_CNTR_IDX; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
+ for (idx = 0; idx <= CCI_PMU_CNTR_LAST(cci_pmu); idx++) {
struct perf_event *event = events->events[idx];
struct hw_perf_event *hw_counter;
@@ -446,11 +826,12 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
hw_counter = &event->hw;
/* Did this counter overflow? */
- if (!(pmu_read_register(idx, CCI_PMU_OVRFLW) &
+ if (!(pmu_read_register(cci_pmu, idx, CCI_PMU_OVRFLW) &
CCI_PMU_OVRFLW_FLAG))
continue;
- pmu_write_register(CCI_PMU_OVRFLW_FLAG, idx, CCI_PMU_OVRFLW);
+ pmu_write_register(cci_pmu, CCI_PMU_OVRFLW_FLAG, idx,
+ CCI_PMU_OVRFLW);
pmu_event_update(event);
pmu_event_set_period(event);
@@ -492,7 +873,7 @@ static void cci_pmu_enable(struct pmu *pmu)
{
struct cci_pmu *cci_pmu = to_cci_pmu(pmu);
struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
- int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_events);
+ int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_cntrs);
unsigned long flags;
u32 val;
@@ -523,6 +904,16 @@ static void cci_pmu_disable(struct pmu *pmu)
raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
}
+/*
+ * Check if the idx represents a non-programmable counter.
+ * All the fixed event counters are mapped before the programmable
+ * counters.
+ */
+static bool pmu_fixed_hw_idx(struct cci_pmu *cci_pmu, int idx)
+{
+ return (idx >= 0) && (idx < cci_pmu->model->fixed_hw_cntrs);
+}
+
static void cci_pmu_start(struct perf_event *event, int pmu_flags)
{
struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
@@ -547,12 +938,12 @@ static void cci_pmu_start(struct perf_event *event, int pmu_flags)
raw_spin_lock_irqsave(&hw_events->pmu_lock, flags);
- /* Configure the event to count, unless you are counting cycles */
- if (idx != CCI_PMU_CYCLE_CNTR_IDX)
- pmu_set_event(idx, hwc->config_base);
+ /* Configure the counter unless you are counting a fixed event */
+ if (!pmu_fixed_hw_idx(cci_pmu, idx))
+ pmu_set_event(cci_pmu, idx, hwc->config_base);
pmu_event_set_period(event);
- pmu_enable_counter(idx);
+ pmu_enable_counter(cci_pmu, idx);
raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
}
@@ -575,7 +966,7 @@ static void cci_pmu_stop(struct perf_event *event, int pmu_flags)
* We always reprogram the counter, so ignore PERF_EF_UPDATE. See
* cci_pmu_start()
*/
- pmu_disable_counter(idx);
+ pmu_disable_counter(cci_pmu, idx);
pmu_event_update(event);
hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
}
@@ -655,13 +1046,16 @@ static int
validate_group(struct perf_event *event)
{
struct perf_event *sibling, *leader = event->group_leader;
+ struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
+ unsigned long mask[BITS_TO_LONGS(cci_pmu->num_cntrs)];
struct cci_pmu_hw_events fake_pmu = {
/*
* Initialise the fake PMU. We only need to populate the
* used_mask for the purposes of validation.
*/
- .used_mask = { 0 },
+ .used_mask = mask,
};
+ memset(mask, 0, BITS_TO_LONGS(cci_pmu->num_cntrs) * sizeof(unsigned long));
if (!validate_event(event->pmu, &fake_pmu, leader))
return -EINVAL;
@@ -779,20 +1173,27 @@ static int cci_pmu_event_init(struct perf_event *event)
return err;
}
-static ssize_t pmu_attr_cpumask_show(struct device *dev,
+static ssize_t pmu_cpumask_attr_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ struct dev_ext_attribute *eattr = container_of(attr,
+ struct dev_ext_attribute, attr);
+ struct cci_pmu *cci_pmu = eattr->var;
+
int n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
- cpumask_pr_args(&pmu->cpus));
+ cpumask_pr_args(&cci_pmu->cpus));
buf[n++] = '\n';
buf[n] = '\0';
return n;
}
-static DEVICE_ATTR(cpumask, S_IRUGO, pmu_attr_cpumask_show, NULL);
+static struct dev_ext_attribute pmu_cpumask_attr = {
+ __ATTR(cpumask, S_IRUGO, pmu_cpumask_attr_show, NULL),
+ NULL, /* Populated in cci_pmu_init */
+};
static struct attribute *pmu_attrs[] = {
- &dev_attr_cpumask.attr,
+ &pmu_cpumask_attr.attr.attr,
NULL,
};
@@ -800,14 +1201,78 @@ static struct attribute_group pmu_attr_group = {
.attrs = pmu_attrs,
};
+static struct attribute_group pmu_format_attr_group = {
+ .name = "format",
+ .attrs = NULL, /* Filled in cci_pmu_init_attrs */
+};
+
+static struct attribute_group pmu_event_attr_group = {
+ .name = "events",
+ .attrs = NULL, /* Filled in cci_pmu_init_attrs */
+};
+
static const struct attribute_group *pmu_attr_groups[] = {
&pmu_attr_group,
+ &pmu_format_attr_group,
+ &pmu_event_attr_group,
NULL
};
+static struct attribute **alloc_attrs(struct platform_device *pdev,
+ int n, struct dev_ext_attribute *source)
+{
+ int i;
+ struct attribute **attrs;
+
+ /* Alloc n + 1 (for terminating NULL) */
+ attrs = devm_kcalloc(&pdev->dev, n + 1, sizeof(struct attribute *),
+ GFP_KERNEL);
+ if (!attrs)
+ return attrs;
+ for(i = 0; i < n; i++)
+ attrs[i] = &source[i].attr.attr;
+ return attrs;
+}
+
+static int cci_pmu_init_attrs(struct cci_pmu *cci_pmu, struct platform_device *pdev)
+{
+ const struct cci_pmu_model *model = cci_pmu->model;
+ struct attribute **attrs;
+
+ /*
+ * All allocations below are managed, hence doesn't need to be
+ * free'd explicitly in case of an error.
+ */
+
+ if (model->nevent_attrs) {
+ attrs = alloc_attrs(pdev, model->nevent_attrs,
+ model->event_attrs);
+ if (!attrs)
+ return -ENOMEM;
+ pmu_event_attr_group.attrs = attrs;
+ }
+ if (model->nformat_attrs) {
+ attrs = alloc_attrs(pdev, model->nformat_attrs,
+ model->format_attrs);
+ if (!attrs)
+ return -ENOMEM;
+ pmu_format_attr_group.attrs = attrs;
+ }
+ pmu_cpumask_attr.var = cci_pmu;
+
+ return 0;
+}
+
static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
{
char *name = cci_pmu->model->name;
+ u32 num_cntrs;
+ int rc;
+
+ rc = cci_pmu_init_attrs(cci_pmu, pdev);
+ if (rc)
+ return rc;
+
cci_pmu->pmu = (struct pmu) {
.name = cci_pmu->model->name,
.task_ctx_nr = perf_invalid_context,
@@ -823,7 +1288,15 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
};
cci_pmu->plat_device = pdev;
- cci_pmu->num_events = pmu_get_max_counters();
+ num_cntrs = pmu_get_max_counters();
+ if (num_cntrs > cci_pmu->model->num_hw_cntrs) {
+ dev_warn(&pdev->dev,
+ "PMU implements more counters(%d) than supported by"
+ " the model(%d), truncated.",
+ num_cntrs, cci_pmu->model->num_hw_cntrs);
+ num_cntrs = cci_pmu->model->num_hw_cntrs;
+ }
+ cci_pmu->num_cntrs = num_cntrs + cci_pmu->model->fixed_hw_cntrs;
return perf_pmu_register(&cci_pmu->pmu, name, -1);
}
@@ -831,12 +1304,14 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
static int cci_pmu_cpu_notifier(struct notifier_block *self,
unsigned long action, void *hcpu)
{
+ struct cci_pmu *cci_pmu = container_of(self,
+ struct cci_pmu, cpu_nb);
unsigned int cpu = (long)hcpu;
unsigned int target;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_DOWN_PREPARE:
- if (!cpumask_test_and_clear_cpu(cpu, &pmu->cpus))
+ if (!cpumask_test_and_clear_cpu(cpu, &cci_pmu->cpus))
break;
target = cpumask_any_but(cpu_online_mask, cpu);
if (target < 0) // UP, last CPU
@@ -845,7 +1320,7 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
* TODO: migrate context once core races on event->ctx have
* been fixed.
*/
- cpumask_set_cpu(target, &pmu->cpus);
+ cpumask_set_cpu(target, &cci_pmu->cpus);
default:
break;
}
@@ -853,57 +1328,103 @@ static int cci_pmu_cpu_notifier(struct notifier_block *self,
return NOTIFY_OK;
}
-static struct notifier_block cci_pmu_cpu_nb = {
- .notifier_call = cci_pmu_cpu_notifier,
- /*
- * to migrate uncore events, our notifier should be executed
- * before perf core's notifier.
- */
- .priority = CPU_PRI_PERF + 1,
-};
-
static struct cci_pmu_model cci_pmu_models[] = {
- [CCI_REV_R0] = {
+#ifdef CONFIG_ARM_CCI400_PMU
+ [CCI400_R0] = {
.name = "CCI_400",
+ .fixed_hw_cntrs = 1, /* Cycle counter */
+ .num_hw_cntrs = 4,
+ .cntr_size = SZ_4K,
+ .format_attrs = cci400_pmu_format_attrs,
+ .nformat_attrs = ARRAY_SIZE(cci400_pmu_format_attrs),
+ .event_attrs = cci400_r0_pmu_event_attrs,
+ .nevent_attrs = ARRAY_SIZE(cci400_r0_pmu_event_attrs),
.event_ranges = {
[CCI_IF_SLAVE] = {
- CCI_REV_R0_SLAVE_PORT_MIN_EV,
- CCI_REV_R0_SLAVE_PORT_MAX_EV,
+ CCI400_R0_SLAVE_PORT_MIN_EV,
+ CCI400_R0_SLAVE_PORT_MAX_EV,
},
[CCI_IF_MASTER] = {
- CCI_REV_R0_MASTER_PORT_MIN_EV,
- CCI_REV_R0_MASTER_PORT_MAX_EV,
+ CCI400_R0_MASTER_PORT_MIN_EV,
+ CCI400_R0_MASTER_PORT_MAX_EV,
},
},
+ .validate_hw_event = cci400_validate_hw_event,
+ .get_event_idx = cci400_get_event_idx,
},
- [CCI_REV_R1] = {
+ [CCI400_R1] = {
.name = "CCI_400_r1",
+ .fixed_hw_cntrs = 1, /* Cycle counter */
+ .num_hw_cntrs = 4,
+ .cntr_size = SZ_4K,
+ .format_attrs = cci400_pmu_format_attrs,
+ .nformat_attrs = ARRAY_SIZE(cci400_pmu_format_attrs),
+ .event_attrs = cci400_r1_pmu_event_attrs,
+ .nevent_attrs = ARRAY_SIZE(cci400_r1_pmu_event_attrs),
.event_ranges = {
[CCI_IF_SLAVE] = {
- CCI_REV_R1_SLAVE_PORT_MIN_EV,
- CCI_REV_R1_SLAVE_PORT_MAX_EV,
+ CCI400_R1_SLAVE_PORT_MIN_EV,
+ CCI400_R1_SLAVE_PORT_MAX_EV,
},
[CCI_IF_MASTER] = {
- CCI_REV_R1_MASTER_PORT_MIN_EV,
- CCI_REV_R1_MASTER_PORT_MAX_EV,
+ CCI400_R1_MASTER_PORT_MIN_EV,
+ CCI400_R1_MASTER_PORT_MAX_EV,
},
},
+ .validate_hw_event = cci400_validate_hw_event,
+ .get_event_idx = cci400_get_event_idx,
},
+#endif
+#ifdef CONFIG_ARM_CCI500_PMU
+ [CCI500_R0] = {
+ .name = "CCI_500",
+ .fixed_hw_cntrs = 0,
+ .num_hw_cntrs = 8,
+ .cntr_size = SZ_64K,
+ .format_attrs = cci500_pmu_format_attrs,
+ .nformat_attrs = ARRAY_SIZE(cci500_pmu_format_attrs),
+ .event_attrs = cci500_pmu_event_attrs,
+ .nevent_attrs = ARRAY_SIZE(cci500_pmu_event_attrs),
+ .event_ranges = {
+ [CCI_IF_SLAVE] = {
+ CCI500_SLAVE_PORT_MIN_EV,
+ CCI500_SLAVE_PORT_MAX_EV,
+ },
+ [CCI_IF_MASTER] = {
+ CCI500_MASTER_PORT_MIN_EV,
+ CCI500_MASTER_PORT_MAX_EV,
+ },
+ [CCI_IF_GLOBAL] = {
+ CCI500_GLOBAL_PORT_MIN_EV,
+ CCI500_GLOBAL_PORT_MAX_EV,
+ },
+ },
+ .validate_hw_event = cci500_validate_hw_event,
+ },
+#endif
};
static const struct of_device_id arm_cci_pmu_matches[] = {
+#ifdef CONFIG_ARM_CCI400_PMU
{
.compatible = "arm,cci-400-pmu",
.data = NULL,
},
{
.compatible = "arm,cci-400-pmu,r0",
- .data = &cci_pmu_models[CCI_REV_R0],
+ .data = &cci_pmu_models[CCI400_R0],
},
{
.compatible = "arm,cci-400-pmu,r1",
- .data = &cci_pmu_models[CCI_REV_R1],
+ .data = &cci_pmu_models[CCI400_R1],
+ },
+#endif
+#ifdef CONFIG_ARM_CCI500_PMU
+ {
+ .compatible = "arm,cci-500-pmu,r0",
+ .data = &cci_pmu_models[CCI500_R0],
},
+#endif
{},
};
@@ -932,68 +1453,114 @@ static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
return false;
}
-static int cci_pmu_probe(struct platform_device *pdev)
+static struct cci_pmu *cci_pmu_alloc(struct platform_device *pdev)
{
- struct resource *res;
- int i, ret, irq;
+ struct cci_pmu *cci_pmu;
const struct cci_pmu_model *model;
+ /*
+ * All allocations are devm_* hence we don't have to free
+ * them explicitly on an error, as it would end up in driver
+ * detach.
+ */
model = get_cci_model(pdev);
if (!model) {
dev_warn(&pdev->dev, "CCI PMU version not supported\n");
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
}
- pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL);
- if (!pmu)
- return -ENOMEM;
+ cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*cci_pmu), GFP_KERNEL);
+ if (!cci_pmu)
+ return ERR_PTR(-ENOMEM);
+
+ cci_pmu->model = model;
+ cci_pmu->irqs = devm_kcalloc(&pdev->dev, CCI_PMU_MAX_HW_CNTRS(model),
+ sizeof(*cci_pmu->irqs), GFP_KERNEL);
+ if (!cci_pmu->irqs)
+ return ERR_PTR(-ENOMEM);
+ cci_pmu->hw_events.events = devm_kcalloc(&pdev->dev,
+ CCI_PMU_MAX_HW_CNTRS(model),
+ sizeof(*cci_pmu->hw_events.events),
+ GFP_KERNEL);
+ if (!cci_pmu->hw_events.events)
+ return ERR_PTR(-ENOMEM);
+ cci_pmu->hw_events.used_mask = devm_kcalloc(&pdev->dev,
+ BITS_TO_LONGS(CCI_PMU_MAX_HW_CNTRS(model)),
+ sizeof(*cci_pmu->hw_events.used_mask),
+ GFP_KERNEL);
+ if (!cci_pmu->hw_events.used_mask)
+ return ERR_PTR(-ENOMEM);
+
+ return cci_pmu;
+}
+
+
+static int cci_pmu_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct cci_pmu *cci_pmu;
+ int i, ret, irq;
+
+ cci_pmu = cci_pmu_alloc(pdev);
+ if (IS_ERR(cci_pmu))
+ return PTR_ERR(cci_pmu);
- pmu->model = model;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- pmu->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(pmu->base))
+ cci_pmu->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(cci_pmu->base))
return -ENOMEM;
/*
- * CCI PMU has 5 overflow signals - one per counter; but some may be tied
+ * CCI PMU has one overflow interrupt per counter; but some may be tied
* together to a common interrupt.
*/
- pmu->nr_irqs = 0;
- for (i = 0; i < CCI_PMU_MAX_HW_EVENTS; i++) {
+ cci_pmu->nr_irqs = 0;
+ for (i = 0; i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model); i++) {
irq = platform_get_irq(pdev, i);
if (irq < 0)
break;
- if (is_duplicate_irq(irq, pmu->irqs, pmu->nr_irqs))
+ if (is_duplicate_irq(irq, cci_pmu->irqs, cci_pmu->nr_irqs))
continue;
- pmu->irqs[pmu->nr_irqs++] = irq;
+ cci_pmu->irqs[cci_pmu->nr_irqs++] = irq;
}
/*
* Ensure that the device tree has as many interrupts as the number
* of counters.
*/
- if (i < CCI_PMU_MAX_HW_EVENTS) {
+ if (i < CCI_PMU_MAX_HW_CNTRS(cci_pmu->model)) {
dev_warn(&pdev->dev, "In-correct number of interrupts: %d, should be %d\n",
- i, CCI_PMU_MAX_HW_EVENTS);
+ i, CCI_PMU_MAX_HW_CNTRS(cci_pmu->model));
return -EINVAL;
}
- raw_spin_lock_init(&pmu->hw_events.pmu_lock);
- mutex_init(&pmu->reserve_mutex);
- atomic_set(&pmu->active_events, 0);
- cpumask_set_cpu(smp_processor_id(), &pmu->cpus);
+ raw_spin_lock_init(&cci_pmu->hw_events.pmu_lock);
+ mutex_init(&cci_pmu->reserve_mutex);
+ atomic_set(&cci_pmu->active_events, 0);
+ cpumask_set_cpu(smp_processor_id(), &cci_pmu->cpus);
+
+ cci_pmu->cpu_nb = (struct notifier_block) {
+ .notifier_call = cci_pmu_cpu_notifier,
+ /*
+ * to migrate uncore events, our notifier should be executed
+ * before perf core's notifier.
+ */
+ .priority = CPU_PRI_PERF + 1,
+ };
- ret = register_cpu_notifier(&cci_pmu_cpu_nb);
+ ret = register_cpu_notifier(&cci_pmu->cpu_nb);
if (ret)
return ret;
- ret = cci_pmu_init(pmu, pdev);
- if (ret)
+ ret = cci_pmu_init(cci_pmu, pdev);
+ if (ret) {
+ unregister_cpu_notifier(&cci_pmu->cpu_nb);
return ret;
+ }
- pr_info("ARM %s PMU driver probed", pmu->model->name);
+ pr_info("ARM %s PMU driver probed", cci_pmu->model->name);
return 0;
}
@@ -1032,14 +1599,14 @@ static int __init cci_platform_init(void)
return platform_driver_register(&cci_platform_driver);
}
-#else /* !CONFIG_ARM_CCI400_PMU */
+#else /* !CONFIG_ARM_CCI_PMU */
static int __init cci_platform_init(void)
{
return 0;
}
-#endif /* CONFIG_ARM_CCI400_PMU */
+#endif /* CONFIG_ARM_CCI_PMU */
#ifdef CONFIG_ARM_CCI400_PORT_CTRL
diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c
index aaa0f2a87118..7d9879e166cf 100644
--- a/drivers/bus/arm-ccn.c
+++ b/drivers/bus/arm-ccn.c
@@ -166,13 +166,17 @@ struct arm_ccn_dt {
struct hrtimer hrtimer;
+ cpumask_t cpu;
+ struct notifier_block cpu_nb;
+
struct pmu pmu;
};
struct arm_ccn {
struct device *dev;
void __iomem *base;
- unsigned irq_used:1;
+ unsigned int irq;
+
unsigned sbas_present:1;
unsigned sbsx_present:1;
@@ -212,7 +216,7 @@ static int arm_ccn_node_to_xp_port(int node)
static void arm_ccn_pmu_config_set(u64 *config, u32 node_xp, u32 type, u32 port)
{
- *config &= ~((0xff << 0) | (0xff << 8) | (0xff << 24));
+ *config &= ~((0xff << 0) | (0xff << 8) | (0x3 << 24));
*config |= (node_xp << 0) | (type << 8) | (port << 24);
}
@@ -336,6 +340,23 @@ static ssize_t arm_ccn_pmu_event_show(struct device *dev,
if (event->mask)
res += snprintf(buf + res, PAGE_SIZE - res, ",mask=0x%x",
event->mask);
+
+ /* Arguments required by an event */
+ switch (event->type) {
+ case CCN_TYPE_CYCLES:
+ break;
+ case CCN_TYPE_XP:
+ res += snprintf(buf + res, PAGE_SIZE - res,
+ ",xp=?,port=?,vc=?,dir=?");
+ if (event->event == CCN_EVENT_WATCHPOINT)
+ res += snprintf(buf + res, PAGE_SIZE - res,
+ ",cmp_l=?,cmp_h=?,mask=?");
+ break;
+ default:
+ res += snprintf(buf + res, PAGE_SIZE - res, ",node=?");
+ break;
+ }
+
res += snprintf(buf + res, PAGE_SIZE - res, "\n");
return res;
@@ -521,6 +542,25 @@ static struct attribute_group arm_ccn_pmu_cmp_mask_attr_group = {
.attrs = arm_ccn_pmu_cmp_mask_attrs,
};
+static ssize_t arm_ccn_pmu_cpumask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct arm_ccn *ccn = pmu_to_arm_ccn(dev_get_drvdata(dev));
+
+ return cpumap_print_to_pagebuf(true, buf, &ccn->dt.cpu);
+}
+
+static struct device_attribute arm_ccn_pmu_cpumask_attr =
+ __ATTR(cpumask, S_IRUGO, arm_ccn_pmu_cpumask_show, NULL);
+
+static struct attribute *arm_ccn_pmu_cpumask_attrs[] = {
+ &arm_ccn_pmu_cpumask_attr.attr,
+ NULL,
+};
+
+static struct attribute_group arm_ccn_pmu_cpumask_attr_group = {
+ .attrs = arm_ccn_pmu_cpumask_attrs,
+};
/*
* Default poll period is 10ms, which is way over the top anyway,
@@ -542,6 +582,7 @@ static const struct attribute_group *arm_ccn_pmu_attr_groups[] = {
&arm_ccn_pmu_events_attr_group,
&arm_ccn_pmu_format_attr_group,
&arm_ccn_pmu_cmp_mask_attr_group,
+ &arm_ccn_pmu_cpumask_attr_group,
NULL
};
@@ -587,7 +628,65 @@ static int arm_ccn_pmu_type_eq(u32 a, u32 b)
return 0;
}
-static void arm_ccn_pmu_event_destroy(struct perf_event *event)
+static int arm_ccn_pmu_event_alloc(struct perf_event *event)
+{
+ struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu);
+ struct hw_perf_event *hw = &event->hw;
+ u32 node_xp, type, event_id;
+ struct arm_ccn_component *source;
+ int bit;
+
+ node_xp = CCN_CONFIG_NODE(event->attr.config);
+ type = CCN_CONFIG_TYPE(event->attr.config);
+ event_id = CCN_CONFIG_EVENT(event->attr.config);
+
+ /* Allocate the cycle counter */
+ if (type == CCN_TYPE_CYCLES) {
+ if (test_and_set_bit(CCN_IDX_PMU_CYCLE_COUNTER,
+ ccn->dt.pmu_counters_mask))
+ return -EAGAIN;
+
+ hw->idx = CCN_IDX_PMU_CYCLE_COUNTER;
+ ccn->dt.pmu_counters[CCN_IDX_PMU_CYCLE_COUNTER].event = event;
+
+ return 0;
+ }
+
+ /* Allocate an event counter */
+ hw->idx = arm_ccn_pmu_alloc_bit(ccn->dt.pmu_counters_mask,
+ CCN_NUM_PMU_EVENT_COUNTERS);
+ if (hw->idx < 0) {
+ dev_dbg(ccn->dev, "No more counters available!\n");
+ return -EAGAIN;
+ }
+
+ if (type == CCN_TYPE_XP)
+ source = &ccn->xp[node_xp];
+ else
+ source = &ccn->node[node_xp];
+ ccn->dt.pmu_counters[hw->idx].source = source;
+
+ /* Allocate an event source or a watchpoint */
+ if (type == CCN_TYPE_XP && event_id == CCN_EVENT_WATCHPOINT)
+ bit = arm_ccn_pmu_alloc_bit(source->xp.dt_cmp_mask,
+ CCN_NUM_XP_WATCHPOINTS);
+ else
+ bit = arm_ccn_pmu_alloc_bit(source->pmu_events_mask,
+ CCN_NUM_PMU_EVENTS);
+ if (bit < 0) {
+ dev_dbg(ccn->dev, "No more event sources/watchpoints on node/XP %d!\n",
+ node_xp);
+ clear_bit(hw->idx, ccn->dt.pmu_counters_mask);
+ return -EAGAIN;
+ }
+ hw->config_base = bit;
+
+ ccn->dt.pmu_counters[hw->idx].event = event;
+
+ return 0;
+}
+
+static void arm_ccn_pmu_event_release(struct perf_event *event)
{
struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu);
struct hw_perf_event *hw = &event->hw;
@@ -616,15 +715,14 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
struct arm_ccn *ccn;
struct hw_perf_event *hw = &event->hw;
u32 node_xp, type, event_id;
- int valid, bit;
- struct arm_ccn_component *source;
+ int valid;
int i;
+ struct perf_event *sibling;
if (event->attr.type != event->pmu->type)
return -ENOENT;
ccn = pmu_to_arm_ccn(event->pmu);
- event->destroy = arm_ccn_pmu_event_destroy;
if (hw->sample_period) {
dev_warn(ccn->dev, "Sampling not supported!\n");
@@ -642,6 +740,16 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
dev_warn(ccn->dev, "Can't provide per-task data!\n");
return -EOPNOTSUPP;
}
+ /*
+ * Many perf core operations (eg. events rotation) operate on a
+ * single CPU context. This is obvious for CPU PMUs, where one
+ * expects the same sets of events being observed on all CPUs,
+ * but can lead to issues for off-core PMUs, like CCN, where each
+ * event could be theoretically assigned to a different CPU. To
+ * mitigate this, we enforce CPU assignment to one, selected
+ * processor (the one described in the "cpumask" attribute).
+ */
+ event->cpu = cpumask_first(&ccn->dt.cpu);
node_xp = CCN_CONFIG_NODE(event->attr.config);
type = CCN_CONFIG_TYPE(event->attr.config);
@@ -711,48 +819,20 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
node_xp, type, port);
}
- /* Allocate the cycle counter */
- if (type == CCN_TYPE_CYCLES) {
- if (test_and_set_bit(CCN_IDX_PMU_CYCLE_COUNTER,
- ccn->dt.pmu_counters_mask))
- return -EAGAIN;
-
- hw->idx = CCN_IDX_PMU_CYCLE_COUNTER;
- ccn->dt.pmu_counters[CCN_IDX_PMU_CYCLE_COUNTER].event = event;
-
- return 0;
- }
-
- /* Allocate an event counter */
- hw->idx = arm_ccn_pmu_alloc_bit(ccn->dt.pmu_counters_mask,
- CCN_NUM_PMU_EVENT_COUNTERS);
- if (hw->idx < 0) {
- dev_warn(ccn->dev, "No more counters available!\n");
- return -EAGAIN;
- }
-
- if (type == CCN_TYPE_XP)
- source = &ccn->xp[node_xp];
- else
- source = &ccn->node[node_xp];
- ccn->dt.pmu_counters[hw->idx].source = source;
-
- /* Allocate an event source or a watchpoint */
- if (type == CCN_TYPE_XP && event_id == CCN_EVENT_WATCHPOINT)
- bit = arm_ccn_pmu_alloc_bit(source->xp.dt_cmp_mask,
- CCN_NUM_XP_WATCHPOINTS);
- else
- bit = arm_ccn_pmu_alloc_bit(source->pmu_events_mask,
- CCN_NUM_PMU_EVENTS);
- if (bit < 0) {
- dev_warn(ccn->dev, "No more event sources/watchpoints on node/XP %d!\n",
- node_xp);
- clear_bit(hw->idx, ccn->dt.pmu_counters_mask);
- return -EAGAIN;
- }
- hw->config_base = bit;
+ /*
+ * We must NOT create groups containing mixed PMUs, although software
+ * events are acceptable (for example to create a CCN group
+ * periodically read when a hrtimer aka cpu-clock leader triggers).
+ */
+ if (event->group_leader->pmu != event->pmu &&
+ !is_software_event(event->group_leader))
+ return -EINVAL;
- ccn->dt.pmu_counters[hw->idx].event = event;
+ list_for_each_entry(sibling, &event->group_leader->sibling_list,
+ group_entry)
+ if (sibling->pmu != event->pmu &&
+ !is_software_event(sibling))
+ return -EINVAL;
return 0;
}
@@ -835,9 +915,14 @@ static void arm_ccn_pmu_event_start(struct perf_event *event, int flags)
arm_ccn_pmu_read_counter(ccn, hw->idx));
hw->state = 0;
- if (!ccn->irq_used)
+ /*
+ * Pin the timer, so that the overflows are handled by the chosen
+ * event->cpu (this is the same one as presented in "cpumask"
+ * attribute).
+ */
+ if (!ccn->irq)
hrtimer_start(&ccn->dt.hrtimer, arm_ccn_pmu_timer_period(),
- HRTIMER_MODE_REL);
+ HRTIMER_MODE_REL_PINNED);
/* Set the DT bus input, engaging the counter */
arm_ccn_pmu_xp_dt_config(event, 1);
@@ -852,7 +937,7 @@ static void arm_ccn_pmu_event_stop(struct perf_event *event, int flags)
/* Disable counting, setting the DT bus to pass-through mode */
arm_ccn_pmu_xp_dt_config(event, 0);
- if (!ccn->irq_used)
+ if (!ccn->irq)
hrtimer_cancel(&ccn->dt.hrtimer);
/* Let the DT bus drain */
@@ -1014,8 +1099,13 @@ static void arm_ccn_pmu_event_config(struct perf_event *event)
static int arm_ccn_pmu_event_add(struct perf_event *event, int flags)
{
+ int err;
struct hw_perf_event *hw = &event->hw;
+ err = arm_ccn_pmu_event_alloc(event);
+ if (err)
+ return err;
+
arm_ccn_pmu_event_config(event);
hw->state = PERF_HES_STOPPED;
@@ -1029,6 +1119,8 @@ static int arm_ccn_pmu_event_add(struct perf_event *event, int flags)
static void arm_ccn_pmu_event_del(struct perf_event *event, int flags)
{
arm_ccn_pmu_event_stop(event, PERF_EF_UPDATE);
+
+ arm_ccn_pmu_event_release(event);
}
static void arm_ccn_pmu_event_read(struct perf_event *event)
@@ -1079,12 +1171,39 @@ static enum hrtimer_restart arm_ccn_pmu_timer_handler(struct hrtimer *hrtimer)
}
+static int arm_ccn_pmu_cpu_notifier(struct notifier_block *nb,
+ unsigned long action, void *hcpu)
+{
+ struct arm_ccn_dt *dt = container_of(nb, struct arm_ccn_dt, cpu_nb);
+ struct arm_ccn *ccn = container_of(dt, struct arm_ccn, dt);
+ unsigned int cpu = (long)hcpu; /* for (long) see kernel/cpu.c */
+ unsigned int target;
+
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_DOWN_PREPARE:
+ if (!cpumask_test_and_clear_cpu(cpu, &dt->cpu))
+ break;
+ target = cpumask_any_but(cpu_online_mask, cpu);
+ if (target < 0)
+ break;
+ perf_pmu_migrate_context(&dt->pmu, cpu, target);
+ cpumask_set_cpu(target, &dt->cpu);
+ WARN_ON(irq_set_affinity(ccn->irq, &dt->cpu) != 0);
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+
static DEFINE_IDA(arm_ccn_pmu_ida);
static int arm_ccn_pmu_init(struct arm_ccn *ccn)
{
int i;
char *name;
+ int err;
/* Initialize DT subsystem */
ccn->dt.base = ccn->base + CCN_REGION_SIZE;
@@ -1136,20 +1255,58 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
};
/* No overflow interrupt? Have to use a timer instead. */
- if (!ccn->irq_used) {
+ if (!ccn->irq) {
dev_info(ccn->dev, "No access to interrupts, using timer.\n");
hrtimer_init(&ccn->dt.hrtimer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL);
ccn->dt.hrtimer.function = arm_ccn_pmu_timer_handler;
}
- return perf_pmu_register(&ccn->dt.pmu, name, -1);
+ /* Pick one CPU which we will use to collect data from CCN... */
+ cpumask_set_cpu(smp_processor_id(), &ccn->dt.cpu);
+
+ /*
+ * ... and change the selection when it goes offline. Priority is
+ * picked to have a chance to migrate events before perf is notified.
+ */
+ ccn->dt.cpu_nb.notifier_call = arm_ccn_pmu_cpu_notifier;
+ ccn->dt.cpu_nb.priority = CPU_PRI_PERF + 1,
+ err = register_cpu_notifier(&ccn->dt.cpu_nb);
+ if (err)
+ goto error_cpu_notifier;
+
+ /* Also make sure that the overflow interrupt is handled by this CPU */
+ if (ccn->irq) {
+ err = irq_set_affinity(ccn->irq, &ccn->dt.cpu);
+ if (err) {
+ dev_err(ccn->dev, "Failed to set interrupt affinity!\n");
+ goto error_set_affinity;
+ }
+ }
+
+ err = perf_pmu_register(&ccn->dt.pmu, name, -1);
+ if (err)
+ goto error_pmu_register;
+
+ return 0;
+
+error_pmu_register:
+error_set_affinity:
+ unregister_cpu_notifier(&ccn->dt.cpu_nb);
+error_cpu_notifier:
+ ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id);
+ for (i = 0; i < ccn->num_xps; i++)
+ writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL);
+ writel(0, ccn->dt.base + CCN_DT_PMCR);
+ return err;
}
static void arm_ccn_pmu_cleanup(struct arm_ccn *ccn)
{
int i;
+ irq_set_affinity(ccn->irq, cpu_possible_mask);
+ unregister_cpu_notifier(&ccn->dt.cpu_nb);
for (i = 0; i < ccn->num_xps; i++)
writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL);
writel(0, ccn->dt.base + CCN_DT_PMCR);
@@ -1285,6 +1442,7 @@ static int arm_ccn_probe(struct platform_device *pdev)
{
struct arm_ccn *ccn;
struct resource *res;
+ unsigned int irq;
int err;
ccn = devm_kzalloc(&pdev->dev, sizeof(*ccn), GFP_KERNEL);
@@ -1309,6 +1467,7 @@ static int arm_ccn_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res)
return -EINVAL;
+ irq = res->start;
/* Check if we can use the interrupt */
writel(CCN_MN_ERRINT_STATUS__PMU_EVENTS__DISABLE,
@@ -1318,13 +1477,12 @@ static int arm_ccn_probe(struct platform_device *pdev)
/* Can set 'disable' bits, so can acknowledge interrupts */
writel(CCN_MN_ERRINT_STATUS__PMU_EVENTS__ENABLE,
ccn->base + CCN_MN_ERRINT_STATUS);
- err = devm_request_irq(ccn->dev, res->start,
- arm_ccn_irq_handler, 0, dev_name(ccn->dev),
- ccn);
+ err = devm_request_irq(ccn->dev, irq, arm_ccn_irq_handler, 0,
+ dev_name(ccn->dev), ccn);
if (err)
return err;
- ccn->irq_used = 1;
+ ccn->irq = irq;
}
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 738612c45266..f364fa4d24eb 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -91,6 +91,7 @@ static const int gisb_offsets_bcm7445[] = {
struct brcmstb_gisb_arb_device {
void __iomem *base;
const int *gisb_offsets;
+ bool big_endian;
struct mutex lock;
struct list_head next;
u32 valid_mask;
@@ -108,7 +109,10 @@ static u32 gisb_read(struct brcmstb_gisb_arb_device *gdev, int reg)
if (offset == -1)
return 1;
- return ioread32(gdev->base + offset);
+ if (gdev->big_endian)
+ return ioread32be(gdev->base + offset);
+ else
+ return ioread32(gdev->base + offset);
}
static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
@@ -117,7 +121,11 @@ static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
if (offset == -1)
return;
- iowrite32(val, gdev->base + reg);
+
+ if (gdev->big_endian)
+ iowrite32be(val, gdev->base + reg);
+ else
+ iowrite32(val, gdev->base + reg);
}
static ssize_t gisb_arb_get_timeout(struct device *dev,
@@ -296,6 +304,7 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
return -EINVAL;
}
gdev->gisb_offsets = of_id->data;
+ gdev->big_endian = of_device_is_big_endian(dn);
err = devm_request_irq(&pdev->dev, timeout_irq,
brcmstb_gisb_timeout_handler, 0, pdev->name,
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 6f047dcb94c2..c43c3d2baf73 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -57,6 +57,7 @@
#include <linux/of_address.h>
#include <linux/debugfs.h>
#include <linux/log2.h>
+#include <linux/memblock.h>
#include <linux/syscore_ops.h>
/*
@@ -152,13 +153,39 @@ struct mvebu_mbus_state {
static struct mvebu_mbus_state mbus_state;
+/*
+ * We provide two variants of the mv_mbus_dram_info() function:
+ *
+ * - The normal one, where the described DRAM ranges may overlap with
+ * the I/O windows, but for which the DRAM ranges are guaranteed to
+ * have a power of two size. Such ranges are suitable for the DMA
+ * masters that only DMA between the RAM and the device, which is
+ * actually all devices except the crypto engines.
+ *
+ * - The 'nooverlap' one, where the described DRAM ranges are
+ * guaranteed to not overlap with the I/O windows, but for which the
+ * DRAM ranges will not have power of two sizes. They will only be
+ * aligned on a 64 KB boundary, and have a size multiple of 64
+ * KB. Such ranges are suitable for the DMA masters that DMA between
+ * the crypto SRAM (which is mapped through an I/O window) and a
+ * device. This is the case for the crypto engines.
+ */
+
static struct mbus_dram_target_info mvebu_mbus_dram_info;
+static struct mbus_dram_target_info mvebu_mbus_dram_info_nooverlap;
+
const struct mbus_dram_target_info *mv_mbus_dram_info(void)
{
return &mvebu_mbus_dram_info;
}
EXPORT_SYMBOL_GPL(mv_mbus_dram_info);
+const struct mbus_dram_target_info *mv_mbus_dram_info_nooverlap(void)
+{
+ return &mvebu_mbus_dram_info_nooverlap;
+}
+EXPORT_SYMBOL_GPL(mv_mbus_dram_info_nooverlap);
+
/* Checks whether the given window has remap capability */
static bool mvebu_mbus_window_is_remappable(struct mvebu_mbus_state *mbus,
const int win)
@@ -576,6 +603,95 @@ static unsigned int armada_xp_mbus_win_remap_offset(int win)
return MVEBU_MBUS_NO_REMAP;
}
+/*
+ * Use the memblock information to find the MBus bridge hole in the
+ * physical address space.
+ */
+static void __init
+mvebu_mbus_find_bridge_hole(uint64_t *start, uint64_t *end)
+{
+ struct memblock_region *r;
+ uint64_t s = 0;
+
+ for_each_memblock(memory, r) {
+ /*
+ * This part of the memory is above 4 GB, so we don't
+ * care for the MBus bridge hole.
+ */
+ if (r->base >= 0x100000000ULL)
+ continue;
+
+ /*
+ * The MBus bridge hole is at the end of the RAM under
+ * the 4 GB limit.
+ */
+ if (r->base + r->size > s)
+ s = r->base + r->size;
+ }
+
+ *start = s;
+ *end = 0x100000000ULL;
+}
+
+/*
+ * This function fills in the mvebu_mbus_dram_info_nooverlap data
+ * structure, by looking at the mvebu_mbus_dram_info data, and
+ * removing the parts of it that overlap with I/O windows.
+ */
+static void __init
+mvebu_mbus_setup_cpu_target_nooverlap(struct mvebu_mbus_state *mbus)
+{
+ uint64_t mbus_bridge_base, mbus_bridge_end;
+ int cs_nooverlap = 0;
+ int i;
+
+ mvebu_mbus_find_bridge_hole(&mbus_bridge_base, &mbus_bridge_end);
+
+ for (i = 0; i < mvebu_mbus_dram_info.num_cs; i++) {
+ struct mbus_dram_window *w;
+ u64 base, size, end;
+
+ w = &mvebu_mbus_dram_info.cs[i];
+ base = w->base;
+ size = w->size;
+ end = base + size;
+
+ /*
+ * The CS is fully enclosed inside the MBus bridge
+ * area, so ignore it.
+ */
+ if (base >= mbus_bridge_base && end <= mbus_bridge_end)
+ continue;
+
+ /*
+ * Beginning of CS overlaps with end of MBus, raise CS
+ * base address, and shrink its size.
+ */
+ if (base >= mbus_bridge_base && end > mbus_bridge_end) {
+ size -= mbus_bridge_end - base;
+ base = mbus_bridge_end;
+ }
+
+ /*
+ * End of CS overlaps with beginning of MBus, shrink
+ * CS size.
+ */
+ if (base < mbus_bridge_base && end > mbus_bridge_base)
+ size -= end - mbus_bridge_base;
+
+ w = &mvebu_mbus_dram_info_nooverlap.cs[cs_nooverlap++];
+ w->cs_index = i;
+ w->mbus_attr = 0xf & ~(1 << i);
+ if (mbus->hw_io_coherency)
+ w->mbus_attr |= ATTR_HW_COHERENCY;
+ w->base = base;
+ w->size = size;
+ }
+
+ mvebu_mbus_dram_info_nooverlap.mbus_dram_target_id = TARGET_DDR;
+ mvebu_mbus_dram_info_nooverlap.num_cs = cs_nooverlap;
+}
+
static void __init
mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
{
@@ -964,6 +1080,7 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
mvebu_mbus_disable_window(mbus, win);
mbus->soc->setup_cpu_target(mbus);
+ mvebu_mbus_setup_cpu_target_nooverlap(mbus);
if (is_coherent)
writel(UNIT_SYNC_BARRIER_ALL,
diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c
index ebee57d715d2..5012e3ad1225 100644
--- a/drivers/bus/omap_l3_noc.c
+++ b/drivers/bus/omap_l3_noc.c
@@ -301,7 +301,7 @@ static int omap_l3_probe(struct platform_device *pdev)
return ret;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/**
* l3_resume_noirq() - resume function for l3_noc
@@ -347,7 +347,7 @@ static int l3_resume_noirq(struct device *dev)
}
static const struct dev_pm_ops l3_dev_pm_ops = {
- .resume_noirq = l3_resume_noirq,
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, l3_resume_noirq)
};
#define L3_DEV_PM_OPS (&l3_dev_pm_ops)
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index a4af8221751e..a043107da2af 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -590,14 +590,6 @@ config DEVPORT
source "drivers/s390/char/Kconfig"
-config MSM_SMD_PKT
- bool "Enable device interface for some SMD packet ports"
- default n
- depends on MSM_SMD
- help
- Enables userspace clients to read and write to some packet SMD
- ports via device interface for MSM chipset.
-
config TILE_SROM
bool "Character-device access via hypervisor to the Tilera SPI ROM"
depends on TILE
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index d06cde26031b..d8a7579300d2 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
-obj-$(CONFIG_MSM_SMD_PKT) += msm_smd_pkt.o
obj-$(CONFIG_MSPEC) += mspec.o
obj-$(CONFIG_MMTIMER) += mmtimer.o
obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o
@@ -36,7 +35,6 @@ else
obj-$(CONFIG_NVRAM) += nvram.o
endif
obj-$(CONFIG_TOSHIBA) += toshiba.o
-obj-$(CONFIG_I8K) += i8k.o
obj-$(CONFIG_DS1620) += ds1620.o
obj-$(CONFIG_HW_RANDOM) += hw_random/
obj-$(CONFIG_PPDEV) += ppdev.o
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index a3bebef255ad..0c98a9d51a24 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -33,7 +33,7 @@
#include <asm/io.h>
#include <asm/msr.h>
#include <asm/cpufeature.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c
index 8753b0f6a317..9b409c0f14f7 100644
--- a/drivers/char/ipmi/ipmi_powernv.c
+++ b/drivers/char/ipmi/ipmi_powernv.c
@@ -15,6 +15,8 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
#include <asm/opal.h>
@@ -23,8 +25,7 @@ struct ipmi_smi_powernv {
u64 interface_id;
struct ipmi_device_id ipmi_id;
ipmi_smi_t intf;
- u64 event;
- struct notifier_block event_nb;
+ unsigned int irq;
/**
* We assume that there can only be one outstanding request, so
@@ -197,15 +198,12 @@ static struct ipmi_smi_handlers ipmi_powernv_smi_handlers = {
.poll = ipmi_powernv_poll,
};
-static int ipmi_opal_event(struct notifier_block *nb,
- unsigned long events, void *change)
+static irqreturn_t ipmi_opal_event(int irq, void *data)
{
- struct ipmi_smi_powernv *smi = container_of(nb,
- struct ipmi_smi_powernv, event_nb);
+ struct ipmi_smi_powernv *smi = data;
- if (events & smi->event)
- ipmi_powernv_recv(smi);
- return 0;
+ ipmi_powernv_recv(smi);
+ return IRQ_HANDLED;
}
static int ipmi_powernv_probe(struct platform_device *pdev)
@@ -240,13 +238,16 @@ static int ipmi_powernv_probe(struct platform_device *pdev)
goto err_free;
}
- ipmi->event = 1ull << prop;
- ipmi->event_nb.notifier_call = ipmi_opal_event;
+ ipmi->irq = irq_of_parse_and_map(dev->of_node, 0);
+ if (!ipmi->irq) {
+ dev_info(dev, "Unable to map irq from device tree\n");
+ ipmi->irq = opal_event_request(prop);
+ }
- rc = opal_notifier_register(&ipmi->event_nb);
- if (rc) {
- dev_warn(dev, "OPAL notifier registration failed (%d)\n", rc);
- goto err_free;
+ if (request_irq(ipmi->irq, ipmi_opal_event, IRQ_TYPE_LEVEL_HIGH,
+ "opal-ipmi", ipmi)) {
+ dev_warn(dev, "Unable to request irq\n");
+ goto err_dispose;
}
ipmi->opal_msg = devm_kmalloc(dev,
@@ -271,7 +272,9 @@ static int ipmi_powernv_probe(struct platform_device *pdev)
err_free_msg:
devm_kfree(dev, ipmi->opal_msg);
err_unregister:
- opal_notifier_unregister(&ipmi->event_nb);
+ free_irq(ipmi->irq, ipmi);
+err_dispose:
+ irq_dispose_mapping(ipmi->irq);
err_free:
devm_kfree(dev, ipmi);
return rc;
@@ -282,7 +285,9 @@ static int ipmi_powernv_remove(struct platform_device *pdev)
struct ipmi_smi_powernv *smi = dev_get_drvdata(&pdev->dev);
ipmi_unregister_smi(smi->intf);
- opal_notifier_unregister(&smi->event_nb);
+ free_irq(smi->irq, smi);
+ irq_dispose_mapping(smi->irq);
+
return 0;
}
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 9fd5a91e0d81..fdb0f9b3fe45 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -117,14 +117,14 @@ static int misc_open(struct inode * inode, struct file * file)
const struct file_operations *new_fops = NULL;
mutex_lock(&misc_mtx);
-
+
list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
- new_fops = fops_get(c->fops);
+ new_fops = fops_get(c->fops);
break;
}
}
-
+
if (!new_fops) {
mutex_unlock(&misc_mtx);
request_module("char-major-%d-%d", MISC_MAJOR, minor);
@@ -167,7 +167,7 @@ static const struct file_operations misc_fops = {
/**
* misc_register - register a miscellaneous device
* @misc: device structure
- *
+ *
* Register a miscellaneous device with the kernel. If the minor
* number is set to %MISC_DYNAMIC_MINOR a minor number is assigned
* and placed in the minor field of the structure. For other cases
@@ -181,17 +181,18 @@ static const struct file_operations misc_fops = {
* A zero is returned on success and a negative errno code for
* failure.
*/
-
+
int misc_register(struct miscdevice * misc)
{
dev_t dev;
int err = 0;
+ bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR);
INIT_LIST_HEAD(&misc->list);
mutex_lock(&misc_mtx);
- if (misc->minor == MISC_DYNAMIC_MINOR) {
+ if (is_dynamic) {
int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
if (i >= DYNAMIC_MINORS) {
err = -EBUSY;
@@ -216,9 +217,13 @@ int misc_register(struct miscdevice * misc)
device_create_with_groups(misc_class, misc->parent, dev,
misc, misc->groups, "%s", misc->name);
if (IS_ERR(misc->this_device)) {
- int i = DYNAMIC_MINORS - misc->minor - 1;
- if (i < DYNAMIC_MINORS && i >= 0)
- clear_bit(i, misc_minors);
+ if (is_dynamic) {
+ int i = DYNAMIC_MINORS - misc->minor - 1;
+
+ if (i < DYNAMIC_MINORS && i >= 0)
+ clear_bit(i, misc_minors);
+ misc->minor = MISC_DYNAMIC_MINOR;
+ }
err = PTR_ERR(misc->this_device);
goto out;
}
diff --git a/drivers/char/msm_smd_pkt.c b/drivers/char/msm_smd_pkt.c
deleted file mode 100644
index ba82a06d9684..000000000000
--- a/drivers/char/msm_smd_pkt.c
+++ /dev/null
@@ -1,465 +0,0 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. 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.
- *
- * 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.
- *
- */
-/*
- * SMD Packet Driver -- Provides userspace interface to SMD packet ports.
- */
-
-#include <linux/slab.h>
-#include <linux/cdev.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/sched.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/uaccess.h>
-#include <linux/workqueue.h>
-#include <linux/poll.h>
-
-#include <mach/msm_smd.h>
-
-#define NUM_SMD_PKT_PORTS 9
-#define DEVICE_NAME "smdpkt"
-#define MAX_BUF_SIZE 2048
-
-struct smd_pkt_dev {
- struct cdev cdev;
- struct device *devicep;
-
- struct smd_channel *ch;
- int open_count;
- struct mutex ch_lock;
- struct mutex rx_lock;
- struct mutex tx_lock;
- wait_queue_head_t ch_read_wait_queue;
- wait_queue_head_t ch_opened_wait_queue;
-
- int i;
-
- unsigned char tx_buf[MAX_BUF_SIZE];
- unsigned char rx_buf[MAX_BUF_SIZE];
- int remote_open;
-
-} *smd_pkt_devp[NUM_SMD_PKT_PORTS];
-
-struct class *smd_pkt_classp;
-static dev_t smd_pkt_number;
-
-static int msm_smd_pkt_debug_enable;
-module_param_named(debug_enable, msm_smd_pkt_debug_enable,
- int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#ifdef DEBUG
-#define D_DUMP_BUFFER(prestr, cnt, buf) do { \
- int i; \
- if (msm_smd_pkt_debug_enable) { \
- pr_debug("%s", prestr); \
- for (i = 0; i < cnt; i++) \
- pr_debug("%.2x", buf[i]); \
- pr_debug("\n"); \
- } \
- } while (0)
-#else
-#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
-#endif
-
-#ifdef DEBUG
-#define DBG(x...) do { \
- if (msm_smd_pkt_debug_enable) \
- pr_debug(x); \
- } while (0)
-#else
-#define DBG(x...) do {} while (0)
-#endif
-
-static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp)
-{
- int sz;
-
- if (!smd_pkt_devp || !smd_pkt_devp->ch)
- return;
-
- sz = smd_cur_packet_size(smd_pkt_devp->ch);
- if (sz == 0) {
- DBG("no packet\n");
- return;
- }
- if (sz > smd_read_avail(smd_pkt_devp->ch)) {
- DBG("incomplete packet\n");
- return;
- }
-
- DBG("waking up reader\n");
- wake_up_interruptible(&smd_pkt_devp->ch_read_wait_queue);
-}
-
-static int smd_pkt_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- int r, bytes_read;
- struct smd_pkt_dev *smd_pkt_devp;
- struct smd_channel *chl;
-
- DBG("read %d bytes\n", count);
- if (count > MAX_BUF_SIZE)
- return -EINVAL;
-
- smd_pkt_devp = file->private_data;
- if (!smd_pkt_devp || !smd_pkt_devp->ch)
- return -EINVAL;
-
- chl = smd_pkt_devp->ch;
-wait_for_packet:
- r = wait_event_interruptible(smd_pkt_devp->ch_read_wait_queue,
- (smd_cur_packet_size(chl) > 0 &&
- smd_read_avail(chl) >=
- smd_cur_packet_size(chl)));
-
- if (r < 0) {
- if (r != -ERESTARTSYS)
- pr_err("wait returned %d\n", r);
- return r;
- }
-
- mutex_lock(&smd_pkt_devp->rx_lock);
-
- bytes_read = smd_cur_packet_size(smd_pkt_devp->ch);
- if (bytes_read == 0 ||
- bytes_read < smd_read_avail(smd_pkt_devp->ch)) {
- mutex_unlock(&smd_pkt_devp->rx_lock);
- DBG("Nothing to read\n");
- goto wait_for_packet;
- }
-
- if (bytes_read > count) {
- mutex_unlock(&smd_pkt_devp->rx_lock);
- pr_info("packet size %d > buffer size %d", bytes_read, count);
- return -EINVAL;
- }
-
- r = smd_read(smd_pkt_devp->ch, smd_pkt_devp->rx_buf, bytes_read);
- if (r != bytes_read) {
- mutex_unlock(&smd_pkt_devp->rx_lock);
- pr_err("smd_read failed to read %d bytes: %d\n", bytes_read, r);
- return -EIO;
- }
-
- D_DUMP_BUFFER("read: ", bytes_read, smd_pkt_devp->rx_buf);
- r = copy_to_user(buf, smd_pkt_devp->rx_buf, bytes_read);
- mutex_unlock(&smd_pkt_devp->rx_lock);
- if (r) {
- pr_err("copy_to_user failed %d\n", r);
- return -EFAULT;
- }
-
- DBG("read complete %d bytes\n", bytes_read);
- check_and_wakeup_reader(smd_pkt_devp);
-
- return bytes_read;
-}
-
-static int smd_pkt_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- int r;
- struct smd_pkt_dev *smd_pkt_devp;
-
- if (count > MAX_BUF_SIZE)
- return -EINVAL;
-
- DBG("writing %d bytes\n", count);
-
- smd_pkt_devp = file->private_data;
- if (!smd_pkt_devp || !smd_pkt_devp->ch)
- return -EINVAL;
-
- mutex_lock(&smd_pkt_devp->tx_lock);
- if (smd_write_avail(smd_pkt_devp->ch) < count) {
- mutex_unlock(&smd_pkt_devp->tx_lock);
- DBG("Not enough space to write\n");
- return -ENOMEM;
- }
-
- D_DUMP_BUFFER("write: ", count, buf);
- r = copy_from_user(smd_pkt_devp->tx_buf, buf, count);
- if (r) {
- mutex_unlock(&smd_pkt_devp->tx_lock);
- pr_err("copy_from_user failed %d\n", r);
- return -EFAULT;
- }
-
- r = smd_write(smd_pkt_devp->ch, smd_pkt_devp->tx_buf, count);
- if (r != count) {
- mutex_unlock(&smd_pkt_devp->tx_lock);
- pr_err("smd_write failed to write %d bytes: %d.\n", count, r);
- return -EIO;
- }
- mutex_unlock(&smd_pkt_devp->tx_lock);
-
- DBG("wrote %d bytes\n", count);
- return count;
-}
-
-static unsigned int smd_pkt_poll(struct file *file, poll_table *wait)
-{
- struct smd_pkt_dev *smd_pkt_devp;
- unsigned int mask = 0;
-
- smd_pkt_devp = file->private_data;
- if (!smd_pkt_devp)
- return POLLERR;
-
- DBG("poll waiting\n");
- poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait);
- if (smd_read_avail(smd_pkt_devp->ch))
- mask |= POLLIN | POLLRDNORM;
-
- DBG("poll return\n");
- return mask;
-}
-
-static void smd_pkt_ch_notify(void *priv, unsigned event)
-{
- struct smd_pkt_dev *smd_pkt_devp = priv;
-
- if (smd_pkt_devp->ch == 0)
- return;
-
- switch (event) {
- case SMD_EVENT_DATA:
- DBG("data\n");
- check_and_wakeup_reader(smd_pkt_devp);
- break;
-
- case SMD_EVENT_OPEN:
- DBG("remote open\n");
- smd_pkt_devp->remote_open = 1;
- wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
- break;
-
- case SMD_EVENT_CLOSE:
- smd_pkt_devp->remote_open = 0;
- pr_info("remote closed\n");
- break;
-
- default:
- pr_err("unknown event %d\n", event);
- break;
- }
-}
-
-static char *smd_pkt_dev_name[] = {
- "smdcntl0",
- "smdcntl1",
- "smdcntl2",
- "smdcntl3",
- "smdcntl4",
- "smdcntl5",
- "smdcntl6",
- "smdcntl7",
- "smd22",
-};
-
-static char *smd_ch_name[] = {
- "DATA5_CNTL",
- "DATA6_CNTL",
- "DATA7_CNTL",
- "DATA8_CNTL",
- "DATA9_CNTL",
- "DATA12_CNTL",
- "DATA13_CNTL",
- "DATA14_CNTL",
- "DATA22",
-};
-
-static int smd_pkt_open(struct inode *inode, struct file *file)
-{
- int r = 0;
- struct smd_pkt_dev *smd_pkt_devp;
-
- smd_pkt_devp = container_of(inode->i_cdev, struct smd_pkt_dev, cdev);
- if (!smd_pkt_devp)
- return -EINVAL;
-
- file->private_data = smd_pkt_devp;
-
- mutex_lock(&smd_pkt_devp->ch_lock);
- if (smd_pkt_devp->open_count == 0) {
- r = smd_open(smd_ch_name[smd_pkt_devp->i],
- &smd_pkt_devp->ch, smd_pkt_devp,
- smd_pkt_ch_notify);
- if (r < 0) {
- pr_err("smd_open failed for %s, %d\n",
- smd_ch_name[smd_pkt_devp->i], r);
- goto out;
- }
-
- r = wait_event_interruptible_timeout(
- smd_pkt_devp->ch_opened_wait_queue,
- smd_pkt_devp->remote_open,
- msecs_to_jiffies(2 * HZ));
- if (r == 0)
- r = -ETIMEDOUT;
-
- if (r < 0) {
- pr_err("wait returned %d\n", r);
- smd_close(smd_pkt_devp->ch);
- smd_pkt_devp->ch = 0;
- } else {
- smd_pkt_devp->open_count++;
- r = 0;
- }
- }
-out:
- mutex_unlock(&smd_pkt_devp->ch_lock);
- return r;
-}
-
-static int smd_pkt_release(struct inode *inode, struct file *file)
-{
- int r = 0;
- struct smd_pkt_dev *smd_pkt_devp = file->private_data;
-
- if (!smd_pkt_devp)
- return -EINVAL;
-
- mutex_lock(&smd_pkt_devp->ch_lock);
- if (--smd_pkt_devp->open_count == 0) {
- r = smd_close(smd_pkt_devp->ch);
- smd_pkt_devp->ch = 0;
- }
- mutex_unlock(&smd_pkt_devp->ch_lock);
-
- return r;
-}
-
-static const struct file_operations smd_pkt_fops = {
- .owner = THIS_MODULE,
- .open = smd_pkt_open,
- .release = smd_pkt_release,
- .read = smd_pkt_read,
- .write = smd_pkt_write,
- .poll = smd_pkt_poll,
-};
-
-static int __init smd_pkt_init(void)
-{
- int i;
- int r;
-
- r = alloc_chrdev_region(&smd_pkt_number, 0,
- NUM_SMD_PKT_PORTS, DEVICE_NAME);
- if (r) {
- pr_err("alloc_chrdev_region() failed %d\n", r);
- return r;
- }
-
- smd_pkt_classp = class_create(THIS_MODULE, DEVICE_NAME);
- if (IS_ERR(smd_pkt_classp)) {
- r = PTR_ERR(smd_pkt_classp);
- pr_err("class_create() failed %d\n", r);
- goto unreg_chardev;
- }
-
- for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
- smd_pkt_devp[i] = kzalloc(sizeof(struct smd_pkt_dev),
- GFP_KERNEL);
- if (!smd_pkt_devp[i]) {
- pr_err("kmalloc() failed\n");
- goto clean_cdevs;
- }
-
- smd_pkt_devp[i]->i = i;
-
- init_waitqueue_head(&smd_pkt_devp[i]->ch_read_wait_queue);
- smd_pkt_devp[i]->remote_open = 0;
- init_waitqueue_head(&smd_pkt_devp[i]->ch_opened_wait_queue);
-
- mutex_init(&smd_pkt_devp[i]->ch_lock);
- mutex_init(&smd_pkt_devp[i]->rx_lock);
- mutex_init(&smd_pkt_devp[i]->tx_lock);
-
- cdev_init(&smd_pkt_devp[i]->cdev, &smd_pkt_fops);
- smd_pkt_devp[i]->cdev.owner = THIS_MODULE;
-
- r = cdev_add(&smd_pkt_devp[i]->cdev,
- (smd_pkt_number + i), 1);
- if (r) {
- pr_err("cdev_add() failed %d\n", r);
- kfree(smd_pkt_devp[i]);
- goto clean_cdevs;
- }
-
- smd_pkt_devp[i]->devicep =
- device_create(smd_pkt_classp, NULL,
- (smd_pkt_number + i), NULL,
- smd_pkt_dev_name[i]);
- if (IS_ERR(smd_pkt_devp[i]->devicep)) {
- r = PTR_ERR(smd_pkt_devp[i]->devicep);
- pr_err("device_create() failed %d\n", r);
- cdev_del(&smd_pkt_devp[i]->cdev);
- kfree(smd_pkt_devp[i]);
- goto clean_cdevs;
- }
-
- }
-
- pr_info("SMD Packet Port Driver Initialized.\n");
- return 0;
-
-clean_cdevs:
- if (i > 0) {
- while (--i >= 0) {
- mutex_destroy(&smd_pkt_devp[i]->ch_lock);
- mutex_destroy(&smd_pkt_devp[i]->rx_lock);
- mutex_destroy(&smd_pkt_devp[i]->tx_lock);
- cdev_del(&smd_pkt_devp[i]->cdev);
- kfree(smd_pkt_devp[i]);
- device_destroy(smd_pkt_classp,
- MKDEV(MAJOR(smd_pkt_number), i));
- }
- }
-
- class_destroy(smd_pkt_classp);
-unreg_chardev:
- unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS);
- return r;
-}
-module_init(smd_pkt_init);
-
-static void __exit smd_pkt_cleanup(void)
-{
- int i;
-
- for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
- mutex_destroy(&smd_pkt_devp[i]->ch_lock);
- mutex_destroy(&smd_pkt_devp[i]->rx_lock);
- mutex_destroy(&smd_pkt_devp[i]->tx_lock);
- cdev_del(&smd_pkt_devp[i]->cdev);
- kfree(smd_pkt_devp[i]);
- device_destroy(smd_pkt_classp,
- MKDEV(MAJOR(smd_pkt_number), i));
- }
-
- class_destroy(smd_pkt_classp);
- unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS);
-}
-module_exit(smd_pkt_cleanup);
-
-MODULE_DESCRIPTION("MSM Shared Memory Packet Port");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 8dd48a2be911..fc061f7c2bd1 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -532,9 +532,8 @@ static int reader_config(struct pcmcia_device *link, int devno)
fail_rc = pcmcia_enable_device(link);
if (fail_rc != 0) {
- dev_printk(KERN_INFO, &link->dev,
- "pcmcia_enable_device failed 0x%x\n",
- fail_rc);
+ dev_info(&link->dev, "pcmcia_enable_device failed 0x%x\n",
+ fail_rc);
goto cs_release;
}
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 0ea9986059af..7680d5213ff8 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -437,7 +437,7 @@ static int mgslpc_device_count = 0;
* .text section address and breakpoint on module load.
* This is useful for use with gdb and add-symbol-file command.
*/
-static bool break_on_load=0;
+static bool break_on_load;
/*
* Driver major number, defaults to zero to get auto
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 9cd6968e2f92..d0da5d852d41 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -409,6 +409,9 @@ static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
static DECLARE_WAIT_QUEUE_HEAD(urandom_init_wait);
static struct fasync_struct *fasync;
+static DEFINE_SPINLOCK(random_ready_list_lock);
+static LIST_HEAD(random_ready_list);
+
/**********************************************************************
*
* OS independent entropy store. Here are the functions which handle
@@ -589,6 +592,22 @@ static void fast_mix(struct fast_pool *f)
f->count++;
}
+static void process_random_ready_list(void)
+{
+ unsigned long flags;
+ struct random_ready_callback *rdy, *tmp;
+
+ spin_lock_irqsave(&random_ready_list_lock, flags);
+ list_for_each_entry_safe(rdy, tmp, &random_ready_list, list) {
+ struct module *owner = rdy->owner;
+
+ list_del_init(&rdy->list);
+ rdy->func(rdy);
+ module_put(owner);
+ }
+ spin_unlock_irqrestore(&random_ready_list_lock, flags);
+}
+
/*
* Credit (or debit) the entropy store with n bits of entropy.
* Use credit_entropy_bits_safe() if the value comes from userspace
@@ -660,7 +679,8 @@ retry:
r->entropy_total = 0;
if (r == &nonblocking_pool) {
prandom_reseed_late();
- wake_up_interruptible(&urandom_init_wait);
+ process_random_ready_list();
+ wake_up_all(&urandom_init_wait);
pr_notice("random: %s pool is initialized\n", r->name);
}
}
@@ -1245,6 +1265,64 @@ void get_random_bytes(void *buf, int nbytes)
EXPORT_SYMBOL(get_random_bytes);
/*
+ * Add a callback function that will be invoked when the nonblocking
+ * pool is initialised.
+ *
+ * returns: 0 if callback is successfully added
+ * -EALREADY if pool is already initialised (callback not called)
+ * -ENOENT if module for callback is not alive
+ */
+int add_random_ready_callback(struct random_ready_callback *rdy)
+{
+ struct module *owner;
+ unsigned long flags;
+ int err = -EALREADY;
+
+ if (likely(nonblocking_pool.initialized))
+ return err;
+
+ owner = rdy->owner;
+ if (!try_module_get(owner))
+ return -ENOENT;
+
+ spin_lock_irqsave(&random_ready_list_lock, flags);
+ if (nonblocking_pool.initialized)
+ goto out;
+
+ owner = NULL;
+
+ list_add(&rdy->list, &random_ready_list);
+ err = 0;
+
+out:
+ spin_unlock_irqrestore(&random_ready_list_lock, flags);
+
+ module_put(owner);
+
+ return err;
+}
+EXPORT_SYMBOL(add_random_ready_callback);
+
+/*
+ * Delete a previously registered readiness callback function.
+ */
+void del_random_ready_callback(struct random_ready_callback *rdy)
+{
+ unsigned long flags;
+ struct module *owner = NULL;
+
+ spin_lock_irqsave(&random_ready_list_lock, flags);
+ if (!list_empty(&rdy->list)) {
+ list_del_init(&rdy->list);
+ owner = rdy->owner;
+ }
+ spin_unlock_irqrestore(&random_ready_list_lock, flags);
+
+ module_put(owner);
+}
+EXPORT_SYMBOL(del_random_ready_callback);
+
+/*
* This function will use the architecture-specific hardware random
* number generator if it is available. The arch-specific hw RNG will
* almost certainly be faster than what we can do in software, but it
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 5fc291c6157e..60316fbaf295 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -12,6 +12,7 @@
#include <linux/fs.h>
#include <linux/major.h>
#include <linux/blkdev.h>
+#include <linux/backing-dev.h>
#include <linux/module.h>
#include <linux/raw.h>
#include <linux/capability.h>
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index 8bab59292a0d..8a80ead8d316 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -198,7 +198,7 @@ scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
add_wait_queue(&sd->sd_rq, &wait);
spin_unlock_irqrestore(&sd->sd_rlock, flags);
- schedule_timeout(SCDRV_TIMEOUT);
+ schedule_timeout(msecs_to_jiffies(SCDRV_TIMEOUT));
remove_wait_queue(&sd->sd_rq, &wait);
if (signal_pending(current)) {
@@ -294,7 +294,7 @@ scdrv_write(struct file *file, const char __user *buf,
add_wait_queue(&sd->sd_wq, &wait);
spin_unlock_irqrestore(&sd->sd_wlock, flags);
- schedule_timeout(SCDRV_TIMEOUT);
+ schedule_timeout(msecs_to_jiffies(SCDRV_TIMEOUT));
remove_wait_queue(&sd->sd_wq, &wait);
if (signal_pending(current)) {
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 50754d203310..d2406fe25533 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1492,8 +1492,8 @@ static int add_port(struct ports_device *portdev, u32 id)
* Finally, create the debugfs file that we can use to
* inspect a port's state at any time
*/
- sprintf(debugfs_name, "vport%up%u",
- port->portdev->vdev->index, id);
+ snprintf(debugfs_name, sizeof(debugfs_name), "vport%up%u",
+ port->portdev->vdev->index, id);
port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
pdrvdata.debugfs_dir,
port,
diff --git a/drivers/char/xilinx_hwicap/buffer_icap.c b/drivers/char/xilinx_hwicap/buffer_icap.c
index 05d897764f02..53c3882e4981 100644
--- a/drivers/char/xilinx_hwicap/buffer_icap.c
+++ b/drivers/char/xilinx_hwicap/buffer_icap.c
@@ -270,7 +270,7 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
int status;
s32 buffer_count = 0;
s32 num_writes = 0;
- bool dirty = 0;
+ bool dirty = false;
u32 i;
void __iomem *base_address = drvdata->base_address;
@@ -279,7 +279,7 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
/* Copy data to bram */
buffer_icap_set_bram(base_address, buffer_count, data[i]);
- dirty = 1;
+ dirty = true;
if (buffer_count < XHI_MAX_BUFFER_INTS - 1) {
buffer_count++;
@@ -299,7 +299,7 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
buffer_count = 0;
num_writes++;
- dirty = 0;
+ dirty = false;
}
/* Write unwritten data to ICAP */
diff --git a/drivers/char/xillybus/Kconfig b/drivers/char/xillybus/Kconfig
index b53bdf12da0d..b302684d86c1 100644
--- a/drivers/char/xillybus/Kconfig
+++ b/drivers/char/xillybus/Kconfig
@@ -24,7 +24,7 @@ config XILLYBUS_PCIE
config XILLYBUS_OF
tristate "Xillybus over Device Tree"
- depends on OF_ADDRESS && OF_IRQ
+ depends on OF_ADDRESS && OF_IRQ && HAS_DMA
help
Set to M if you want Xillybus to find its resources from the
Open Firmware Flattened Device Tree. If the target is an embedded
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 78029bd2444b..8732e4c5bf3c 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
obj-$(CONFIG_ARCH_HIP04) += hisilicon/
obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
+obj-$(CONFIG_ARCH_MXC) += imx/
obj-$(CONFIG_MACH_INGENIC) += ingenic/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
ifeq ($(CONFIG_COMMON_CLK), y)
@@ -73,4 +74,6 @@ obj-$(CONFIG_ARCH_OMAP2PLUS) += ti/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
obj-$(CONFIG_X86) += x86/
+obj-$(CONFIG_ARCH_ZX) += zte/
obj-$(CONFIG_ARCH_ZYNQ) += zynq/
+obj-$(CONFIG_H8300) += h8300/
diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
index 597fed423d7d..df2c1afa52b4 100644
--- a/drivers/clk/at91/clk-peripheral.c
+++ b/drivers/clk/at91/clk-peripheral.c
@@ -29,7 +29,7 @@
#define PERIPHERAL_RSHIFT_MASK 0x3
#define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK)
-#define PERIPHERAL_MAX_SHIFT 4
+#define PERIPHERAL_MAX_SHIFT 3
struct clk_peripheral {
struct clk_hw hw;
@@ -242,7 +242,7 @@ static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
return *parent_rate;
if (periph->range.max) {
- for (; shift < PERIPHERAL_MAX_SHIFT; shift++) {
+ for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
cur_rate = *parent_rate >> shift;
if (cur_rate <= periph->range.max)
break;
@@ -254,7 +254,7 @@ static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
best_diff = cur_rate - rate;
best_rate = cur_rate;
- for (; shift < PERIPHERAL_MAX_SHIFT; shift++) {
+ for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
cur_rate = *parent_rate >> shift;
if (cur_rate < rate)
cur_diff = rate - cur_rate;
@@ -289,7 +289,7 @@ static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw,
if (periph->range.max && rate > periph->range.max)
return -EINVAL;
- for (shift = 0; shift < PERIPHERAL_MAX_SHIFT; shift++) {
+ for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
if (parent_rate >> shift == rate) {
periph->auto_div = false;
periph->div = shift;
diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
index 6ec79dbc0840..cbbe40377ad6 100644
--- a/drivers/clk/at91/clk-pll.c
+++ b/drivers/clk/at91/clk-pll.c
@@ -173,8 +173,7 @@ static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
int i = 0;
/* Check if parent_rate is a valid input rate */
- if (parent_rate < characteristics->input.min ||
- parent_rate > characteristics->input.max)
+ if (parent_rate < characteristics->input.min)
return -ERANGE;
/*
@@ -187,6 +186,15 @@ static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
if (!mindiv)
mindiv = 1;
+ if (parent_rate > characteristics->input.max) {
+ tmpdiv = DIV_ROUND_UP(parent_rate, characteristics->input.max);
+ if (tmpdiv > PLL_DIV_MAX)
+ return -ERANGE;
+
+ if (tmpdiv > mindiv)
+ mindiv = tmpdiv;
+ }
+
/*
* Calculate the maximum divider which is limited by PLL register
* layout (limited by the MUL or DIV field size).
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 69abb08cf146..eb8e5dc9076d 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -121,7 +121,7 @@ extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
struct at91_pmc *pmc);
#endif
-#if defined(CONFIG_HAVE_AT91_SMD)
+#if defined(CONFIG_HAVE_AT91_H32MX)
extern void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
struct at91_pmc *pmc);
#endif
diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c
index 515fb133495c..73153fc45ee9 100644
--- a/drivers/clk/berlin/bg2.c
+++ b/drivers/clk/berlin/bg2.c
@@ -502,12 +502,13 @@ static const struct berlin2_gate_data bg2_gates[] __initconst = {
static void __init berlin2_clock_setup(struct device_node *np)
{
+ struct device_node *parent_np = of_get_parent(np);
const char *parent_names[9];
struct clk *clk;
u8 avpll_flags = 0;
int n;
- gbase = of_iomap(np, 0);
+ gbase = of_iomap(parent_np, 0);
if (!gbase)
return;
@@ -685,7 +686,5 @@ static void __init berlin2_clock_setup(struct device_node *np)
bg2_fail:
iounmap(gbase);
}
-CLK_OF_DECLARE(berlin2_clock, "marvell,berlin2-chip-ctrl",
- berlin2_clock_setup);
-CLK_OF_DECLARE(berlin2cd_clock, "marvell,berlin2cd-chip-ctrl",
+CLK_OF_DECLARE(berlin2_clk, "marvell,berlin2-clk",
berlin2_clock_setup);
diff --git a/drivers/clk/berlin/bg2q.c b/drivers/clk/berlin/bg2q.c
index 440ef81ab15c..221f40c2b850 100644
--- a/drivers/clk/berlin/bg2q.c
+++ b/drivers/clk/berlin/bg2q.c
@@ -290,18 +290,19 @@ static const struct berlin2_gate_data bg2q_gates[] __initconst = {
static void __init berlin2q_clock_setup(struct device_node *np)
{
+ struct device_node *parent_np = of_get_parent(np);
const char *parent_names[9];
struct clk *clk;
int n;
- gbase = of_iomap(np, 0);
+ gbase = of_iomap(parent_np, 0);
if (!gbase) {
pr_err("%s: Unable to map global base\n", np->full_name);
return;
}
/* BG2Q CPU PLL is not part of global registers */
- cpupll_base = of_iomap(np, 1);
+ cpupll_base = of_iomap(parent_np, 1);
if (!cpupll_base) {
pr_err("%s: Unable to map cpupll base\n", np->full_name);
iounmap(gbase);
@@ -384,5 +385,5 @@ bg2q_fail:
iounmap(cpupll_base);
iounmap(gbase);
}
-CLK_OF_DECLARE(berlin2q_clock, "marvell,berlin2q-chip-ctrl",
+CLK_OF_DECLARE(berlin2q_clk, "marvell,berlin2q-clk",
berlin2q_clock_setup);
diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c
index bfa1e64e267d..9b13a303d3f8 100644
--- a/drivers/clk/clk-s2mps11.c
+++ b/drivers/clk/clk-s2mps11.c
@@ -242,14 +242,12 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
goto err_reg;
}
- s2mps11_clk->lookup = clkdev_alloc(s2mps11_clk->clk,
+ s2mps11_clk->lookup = clkdev_create(s2mps11_clk->clk,
s2mps11_name(s2mps11_clk), NULL);
if (!s2mps11_clk->lookup) {
ret = -ENOMEM;
goto err_lup;
}
-
- clkdev_add(s2mps11_clk->lookup);
}
for (i = 0; i < S2MPS11_CLKS_NUM; i++) {
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 1fcb6ef2cdac..c0eaf0973bd2 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -177,7 +177,7 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id)
if (!cl)
goto out;
- clk = __clk_create_clk(__clk_get_hw(cl->clk), dev_id, con_id);
+ clk = __clk_create_clk(cl->clk_hw, dev_id, con_id);
if (IS_ERR(clk))
goto out;
@@ -215,18 +215,26 @@ void clk_put(struct clk *clk)
}
EXPORT_SYMBOL(clk_put);
-void clkdev_add(struct clk_lookup *cl)
+static void __clkdev_add(struct clk_lookup *cl)
{
mutex_lock(&clocks_mutex);
list_add_tail(&cl->node, &clocks);
mutex_unlock(&clocks_mutex);
}
+
+void clkdev_add(struct clk_lookup *cl)
+{
+ if (!cl->clk_hw)
+ cl->clk_hw = __clk_get_hw(cl->clk);
+ __clkdev_add(cl);
+}
EXPORT_SYMBOL(clkdev_add);
-void __init clkdev_add_table(struct clk_lookup *cl, size_t num)
+void clkdev_add_table(struct clk_lookup *cl, size_t num)
{
mutex_lock(&clocks_mutex);
while (num--) {
+ cl->clk_hw = __clk_get_hw(cl->clk);
list_add_tail(&cl->node, &clocks);
cl++;
}
@@ -243,7 +251,7 @@ struct clk_lookup_alloc {
};
static struct clk_lookup * __init_refok
-vclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt,
+vclkdev_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
va_list ap)
{
struct clk_lookup_alloc *cla;
@@ -252,7 +260,7 @@ vclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt,
if (!cla)
return NULL;
- cla->cl.clk = clk;
+ cla->cl.clk_hw = hw;
if (con_id) {
strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
cla->cl.con_id = cla->con_id;
@@ -266,6 +274,19 @@ vclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt,
return &cla->cl;
}
+static struct clk_lookup *
+vclkdev_create(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
+ va_list ap)
+{
+ struct clk_lookup *cl;
+
+ cl = vclkdev_alloc(hw, con_id, dev_fmt, ap);
+ if (cl)
+ __clkdev_add(cl);
+
+ return cl;
+}
+
struct clk_lookup * __init_refok
clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...)
{
@@ -273,28 +294,49 @@ clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...)
va_list ap;
va_start(ap, dev_fmt);
- cl = vclkdev_alloc(clk, con_id, dev_fmt, ap);
+ cl = vclkdev_alloc(__clk_get_hw(clk), con_id, dev_fmt, ap);
va_end(ap);
return cl;
}
EXPORT_SYMBOL(clkdev_alloc);
-int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
- struct device *dev)
+/**
+ * clkdev_create - allocate and add a clkdev lookup structure
+ * @clk: struct clk to associate with all clk_lookups
+ * @con_id: connection ID string on device
+ * @dev_fmt: format string describing device name
+ *
+ * Returns a clk_lookup structure, which can be later unregistered and
+ * freed.
+ */
+struct clk_lookup *clkdev_create(struct clk *clk, const char *con_id,
+ const char *dev_fmt, ...)
{
- struct clk *r = clk_get(dev, id);
+ struct clk_lookup *cl;
+ va_list ap;
+
+ va_start(ap, dev_fmt);
+ cl = vclkdev_create(__clk_get_hw(clk), con_id, dev_fmt, ap);
+ va_end(ap);
+
+ return cl;
+}
+EXPORT_SYMBOL_GPL(clkdev_create);
+
+int clk_add_alias(const char *alias, const char *alias_dev_name,
+ const char *con_id, struct device *dev)
+{
+ struct clk *r = clk_get(dev, con_id);
struct clk_lookup *l;
if (IS_ERR(r))
return PTR_ERR(r);
- l = clkdev_alloc(r, alias, alias_dev_name);
+ l = clkdev_create(r, alias, "%s", alias_dev_name);
clk_put(r);
- if (!l)
- return -ENODEV;
- clkdev_add(l);
- return 0;
+
+ return l ? 0 : -ENODEV;
}
EXPORT_SYMBOL(clk_add_alias);
@@ -334,15 +376,10 @@ int clk_register_clkdev(struct clk *clk, const char *con_id,
return PTR_ERR(clk);
va_start(ap, dev_fmt);
- cl = vclkdev_alloc(clk, con_id, dev_fmt, ap);
+ cl = vclkdev_create(__clk_get_hw(clk), con_id, dev_fmt, ap);
va_end(ap);
- if (!cl)
- return -ENOMEM;
-
- clkdev_add(cl);
-
- return 0;
+ return cl ? 0 : -ENOMEM;
}
EXPORT_SYMBOL(clk_register_clkdev);
@@ -365,8 +402,8 @@ int clk_register_clkdevs(struct clk *clk, struct clk_lookup *cl, size_t num)
return PTR_ERR(clk);
for (i = 0; i < num; i++, cl++) {
- cl->clk = clk;
- clkdev_add(cl);
+ cl->clk_hw = __clk_get_hw(clk);
+ __clkdev_add(cl);
}
return 0;
diff --git a/drivers/clk/h8300/Makefile b/drivers/clk/h8300/Makefile
new file mode 100644
index 000000000000..b86427c31fca
--- /dev/null
+++ b/drivers/clk/h8300/Makefile
@@ -0,0 +1,2 @@
+obj-y += clk-div.o
+obj-$(CONFIG_H8S2678) += clk-h8s2678.o
diff --git a/drivers/clk/h8300/clk-div.c b/drivers/clk/h8300/clk-div.c
new file mode 100644
index 000000000000..56f9eba91b83
--- /dev/null
+++ b/drivers/clk/h8300/clk-div.c
@@ -0,0 +1,53 @@
+/*
+ * H8/300 divide clock driver
+ *
+ * Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+static DEFINE_SPINLOCK(clklock);
+
+static void __init h8300_div_clk_setup(struct device_node *node)
+{
+ unsigned int num_parents;
+ struct clk *clk;
+ const char *clk_name = node->name;
+ const char *parent_name;
+ void __iomem *divcr = NULL;
+ int width;
+
+ num_parents = of_clk_get_parent_count(node);
+ if (num_parents < 1) {
+ pr_err("%s: no parent found", clk_name);
+ return;
+ }
+
+ divcr = of_iomap(node, 0);
+ if (divcr == NULL) {
+ pr_err("%s: failed to map divide register", clk_name);
+ goto error;
+ }
+
+ parent_name = of_clk_get_parent_name(node, 0);
+ of_property_read_u32(node, "renesas,width", &width);
+ clk = clk_register_divider(NULL, clk_name, parent_name,
+ CLK_SET_RATE_GATE, divcr, 0, width,
+ CLK_DIVIDER_POWER_OF_TWO, &clklock);
+ if (!IS_ERR(clk)) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ return;
+ }
+ pr_err("%s: failed to register %s div clock (%ld)\n",
+ __func__, clk_name, PTR_ERR(clk));
+error:
+ if (divcr)
+ iounmap(divcr);
+}
+
+CLK_OF_DECLARE(h8300_div_clk, "renesas,h8300-div-clock", h8300_div_clk_setup);
diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c
new file mode 100644
index 000000000000..4701b093e497
--- /dev/null
+++ b/drivers/clk/h8300/clk-h8s2678.c
@@ -0,0 +1,146 @@
+/*
+ * H8S2678 clock driver
+ *
+ * Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/of_address.h>
+
+static DEFINE_SPINLOCK(clklock);
+
+#define MAX_FREQ 33333333
+#define MIN_FREQ 8000000
+
+struct pll_clock {
+ struct clk_hw hw;
+ void __iomem *sckcr;
+ void __iomem *pllcr;
+};
+
+#define to_pll_clock(_hw) container_of(_hw, struct pll_clock, hw)
+
+static unsigned long pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct pll_clock *pll_clock = to_pll_clock(hw);
+ int mul = 1 << (ctrl_inb((unsigned long)pll_clock->pllcr) & 3);
+
+ return parent_rate * mul;
+}
+
+static long pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ int i, m = -1;
+ long offset[3];
+
+ if (rate > MAX_FREQ)
+ rate = MAX_FREQ;
+ if (rate < MIN_FREQ)
+ rate = MIN_FREQ;
+
+ for (i = 0; i < 3; i++)
+ offset[i] = abs(rate - (*prate * (1 << i)));
+ for (i = 0; i < 3; i++)
+ if (m < 0)
+ m = i;
+ else
+ m = (offset[i] < offset[m])?i:m;
+
+ return *prate * (1 << m);
+}
+
+static int pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int pll;
+ unsigned char val;
+ unsigned long flags;
+ struct pll_clock *pll_clock = to_pll_clock(hw);
+
+ pll = ((rate / parent_rate) / 2) & 0x03;
+ spin_lock_irqsave(&clklock, flags);
+ val = ctrl_inb((unsigned long)pll_clock->sckcr);
+ val |= 0x08;
+ ctrl_outb(val, (unsigned long)pll_clock->sckcr);
+ val = ctrl_inb((unsigned long)pll_clock->pllcr);
+ val &= ~0x03;
+ val |= pll;
+ ctrl_outb(val, (unsigned long)pll_clock->pllcr);
+ spin_unlock_irqrestore(&clklock, flags);
+ return 0;
+}
+
+static const struct clk_ops pll_ops = {
+ .recalc_rate = pll_recalc_rate,
+ .round_rate = pll_round_rate,
+ .set_rate = pll_set_rate,
+};
+
+static void __init h8s2678_pll_clk_setup(struct device_node *node)
+{
+ unsigned int num_parents;
+ struct clk *clk;
+ const char *clk_name = node->name;
+ const char *parent_name;
+ struct pll_clock *pll_clock;
+ struct clk_init_data init;
+
+ num_parents = of_clk_get_parent_count(node);
+ if (num_parents < 1) {
+ pr_err("%s: no parent found", clk_name);
+ return;
+ }
+
+
+ pll_clock = kzalloc(sizeof(struct pll_clock), GFP_KERNEL);
+ if (!pll_clock) {
+ pr_err("%s: failed to alloc memory", clk_name);
+ return;
+ }
+
+ pll_clock->sckcr = of_iomap(node, 0);
+ if (pll_clock->sckcr == NULL) {
+ pr_err("%s: failed to map divide register", clk_name);
+ goto free_clock;
+ }
+
+ pll_clock->pllcr = of_iomap(node, 1);
+ if (pll_clock->pllcr == NULL) {
+ pr_err("%s: failed to map multiply register", clk_name);
+ goto unmap_sckcr;
+ }
+
+ parent_name = of_clk_get_parent_name(node, 0);
+ init.name = clk_name;
+ init.ops = &pll_ops;
+ init.flags = CLK_IS_BASIC;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ pll_clock->hw.init = &init;
+
+ clk = clk_register(NULL, &pll_clock->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register %s div clock (%ld)\n",
+ __func__, clk_name, PTR_ERR(clk));
+ goto unmap_pllcr;
+ }
+
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ return;
+
+unmap_pllcr:
+ iounmap(pll_clock->pllcr);
+unmap_sckcr:
+ iounmap(pll_clock->sckcr);
+free_clock:
+ kfree(pll_clock);
+}
+
+CLK_OF_DECLARE(h8s2678_div_clk, "renesas,h8s2678-pll-clock",
+ h8s2678_pll_clk_setup);
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
new file mode 100644
index 000000000000..75fae169ce8f
--- /dev/null
+++ b/drivers/clk/imx/Makefile
@@ -0,0 +1,26 @@
+
+obj-y += \
+ clk.o \
+ clk-busy.o \
+ clk-cpu.o \
+ clk-fixup-div.o \
+ clk-fixup-mux.o \
+ clk-gate-exclusive.o \
+ clk-gate2.o \
+ clk-pllv1.o \
+ clk-pllv2.o \
+ clk-pllv3.o \
+ clk-pfd.o
+
+obj-$(CONFIG_SOC_IMX1) += clk-imx1.o
+obj-$(CONFIG_SOC_IMX21) += clk-imx21.o
+obj-$(CONFIG_SOC_IMX25) += clk-imx25.o
+obj-$(CONFIG_SOC_IMX27) += clk-imx27.o
+obj-$(CONFIG_SOC_IMX31) += clk-imx31.o
+obj-$(CONFIG_SOC_IMX35) += clk-imx35.o
+obj-$(CONFIG_SOC_IMX5) += clk-imx51-imx53.o
+obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o
+obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o
+obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o
+obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o
+obj-$(CONFIG_SOC_VF610) += clk-vf610.o
diff --git a/arch/arm/mach-imx/clk-busy.c b/drivers/clk/imx/clk-busy.c
index 4bb1bc419b79..4bb1bc419b79 100644
--- a/arch/arm/mach-imx/clk-busy.c
+++ b/drivers/clk/imx/clk-busy.c
diff --git a/arch/arm/mach-imx/clk-cpu.c b/drivers/clk/imx/clk-cpu.c
index aa1c345e2a19..9d46eac87f45 100644
--- a/arch/arm/mach-imx/clk-cpu.c
+++ b/drivers/clk/imx/clk-cpu.c
@@ -12,6 +12,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/slab.h>
+#include "clk.h"
struct clk_cpu {
struct clk_hw hw;
diff --git a/arch/arm/mach-imx/clk-fixup-div.c b/drivers/clk/imx/clk-fixup-div.c
index 21db020b1f2d..21db020b1f2d 100644
--- a/arch/arm/mach-imx/clk-fixup-div.c
+++ b/drivers/clk/imx/clk-fixup-div.c
diff --git a/arch/arm/mach-imx/clk-fixup-mux.c b/drivers/clk/imx/clk-fixup-mux.c
index 0d40b35c557c..0d40b35c557c 100644
--- a/arch/arm/mach-imx/clk-fixup-mux.c
+++ b/drivers/clk/imx/clk-fixup-mux.c
diff --git a/arch/arm/mach-imx/clk-gate-exclusive.c b/drivers/clk/imx/clk-gate-exclusive.c
index c12f5f2e04dc..c12f5f2e04dc 100644
--- a/arch/arm/mach-imx/clk-gate-exclusive.c
+++ b/drivers/clk/imx/clk-gate-exclusive.c
diff --git a/arch/arm/mach-imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
index 8935bff99fe7..8935bff99fe7 100644
--- a/arch/arm/mach-imx/clk-gate2.c
+++ b/drivers/clk/imx/clk-gate2.c
diff --git a/arch/arm/mach-imx/clk-imx1.c b/drivers/clk/imx/clk-imx1.c
index 37c307a8d896..c2647fa19f28 100644
--- a/arch/arm/mach-imx/clk-imx1.c
+++ b/drivers/clk/imx/clk-imx1.c
@@ -23,10 +23,14 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <dt-bindings/clock/imx1-clock.h>
+#include <soc/imx/timer.h>
+#include <asm/irq.h>
#include "clk.h"
-#include "common.h"
-#include "hardware.h"
+
+#define MX1_CCM_BASE_ADDR 0x0021b000
+#define MX1_TIM1_BASE_ADDR 0x00220000
+#define MX1_TIM1_INT (NR_IRQS_LEGACY + 59)
static const char *prem_sel_clks[] = { "clk32_premult", "clk16m", };
static const char *clko_sel_clks[] = { "per1", "hclk", "clk48m", "clk16m",
@@ -50,9 +54,9 @@ static void __init _mx1_clocks_init(unsigned long fref)
clk[IMX1_CLK_CLK16M] = imx_clk_gate("clk16m", "clk16m_ext", CCM_CSCR, 17);
clk[IMX1_CLK_CLK32_PREMULT] = imx_clk_fixed_factor("clk32_premult", "clk32", 512, 1);
clk[IMX1_CLK_PREM] = imx_clk_mux("prem", CCM_CSCR, 16, 1, prem_sel_clks, ARRAY_SIZE(prem_sel_clks));
- clk[IMX1_CLK_MPLL] = imx_clk_pllv1("mpll", "clk32_premult", CCM_MPCTL0);
+ clk[IMX1_CLK_MPLL] = imx_clk_pllv1(IMX_PLLV1_IMX1, "mpll", "clk32_premult", CCM_MPCTL0);
clk[IMX1_CLK_MPLL_GATE] = imx_clk_gate("mpll_gate", "mpll", CCM_CSCR, 0);
- clk[IMX1_CLK_SPLL] = imx_clk_pllv1("spll", "prem", CCM_SPCTL0);
+ clk[IMX1_CLK_SPLL] = imx_clk_pllv1(IMX_PLLV1_IMX1, "spll", "prem", CCM_SPCTL0);
clk[IMX1_CLK_SPLL_GATE] = imx_clk_gate("spll_gate", "spll", CCM_CSCR, 1);
clk[IMX1_CLK_MCU] = imx_clk_divider("mcu", "clk32_premult", CCM_CSCR, 15, 1);
clk[IMX1_CLK_FCLK] = imx_clk_divider("fclk", "mpll_gate", CCM_CSCR, 15, 1);
@@ -75,7 +79,8 @@ static void __init _mx1_clocks_init(unsigned long fref)
int __init mx1_clocks_init(unsigned long fref)
{
- ccm = MX1_IO_ADDRESS(MX1_CCM_BASE_ADDR);
+ ccm = ioremap(MX1_CCM_BASE_ADDR, SZ_4K);
+ BUG_ON(!ccm);
_mx1_clocks_init(fref);
@@ -98,7 +103,7 @@ int __init mx1_clocks_init(unsigned long fref)
clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ipg", "imx1-fb.0");
clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ahb", "imx1-fb.0");
- mxc_timer_init(MX1_IO_ADDRESS(MX1_TIM1_BASE_ADDR), MX1_TIM1_INT);
+ mxc_timer_init(MX1_TIM1_BASE_ADDR, MX1_TIM1_INT, GPT_TYPE_IMX1);
return 0;
}
diff --git a/arch/arm/mach-imx/clk-imx21.c b/drivers/clk/imx/clk-imx21.c
index 4b4c75339aa6..dba987e3b89f 100644
--- a/arch/arm/mach-imx/clk-imx21.c
+++ b/drivers/clk/imx/clk-imx21.c
@@ -15,10 +15,14 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <dt-bindings/clock/imx21-clock.h>
+#include <soc/imx/timer.h>
+#include <asm/irq.h>
#include "clk.h"
-#include "common.h"
-#include "hardware.h"
+
+#define MX21_CCM_BASE_ADDR 0x10027000
+#define MX21_GPT1_BASE_ADDR 0x10003000
+#define MX21_INT_GPT1 (NR_IRQS_LEGACY + 26)
static void __iomem *ccm __initdata;
@@ -63,9 +67,9 @@ static void __init _mx21_clocks_init(unsigned long lref, unsigned long href)
clk[IMX21_CLK_USB_DIV] = imx_clk_divider("usb_div", "spll_gate", CCM_CSCR, 26, 3);
clk[IMX21_CLK_FCLK] = imx_clk_divider("fclk", "mpll_gate", CCM_CSCR, 29, 3);
- clk[IMX21_CLK_MPLL] = imx_clk_pllv1("mpll", "mpll_sel", CCM_MPCTL0);
+ clk[IMX21_CLK_MPLL] = imx_clk_pllv1(IMX_PLLV1_IMX21, "mpll", "mpll_sel", CCM_MPCTL0);
- clk[IMX21_CLK_SPLL] = imx_clk_pllv1("spll", "spll_sel", CCM_SPCTL0);
+ clk[IMX21_CLK_SPLL] = imx_clk_pllv1(IMX_PLLV1_IMX21, "spll", "spll_sel", CCM_SPCTL0);
clk[IMX21_CLK_NFC_DIV] = imx_clk_divider("nfc_div", "fclk", CCM_PCDR0, 12, 4);
clk[IMX21_CLK_SSI1_DIV] = imx_clk_divider("ssi1_div", "ssi1_sel", CCM_PCDR0, 16, 6);
@@ -153,7 +157,7 @@ int __init mx21_clocks_init(unsigned long lref, unsigned long href)
clk_register_clkdev(clk[IMX21_CLK_I2C_GATE], NULL, "imx21-i2c.0");
clk_register_clkdev(clk[IMX21_CLK_OWIRE_GATE], NULL, "mxc_w1.0");
- mxc_timer_init(MX21_IO_ADDRESS(MX21_GPT1_BASE_ADDR), MX21_INT_GPT1);
+ mxc_timer_init(MX21_GPT1_BASE_ADDR, MX21_INT_GPT1, GPT_TYPE_IMX21);
return 0;
}
diff --git a/arch/arm/mach-imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c
index 9c2633a9de9f..ec1a4c1dacf1 100644
--- a/arch/arm/mach-imx/clk-imx25.c
+++ b/drivers/clk/imx/clk-imx25.c
@@ -28,8 +28,6 @@
#include <linux/of_irq.h>
#include "clk.h"
-#include "common.h"
-#include "hardware.h"
#define CCM_MPCTL 0x00
#define CCM_UPCTL 0x04
@@ -95,8 +93,8 @@ static int __init __mx25_clocks_init(unsigned long osc_rate,
clk[dummy] = imx_clk_fixed("dummy", 0);
clk[osc] = imx_clk_fixed("osc", osc_rate);
- clk[mpll] = imx_clk_pllv1("mpll", "osc", ccm(CCM_MPCTL));
- clk[upll] = imx_clk_pllv1("upll", "osc", ccm(CCM_UPCTL));
+ 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);
clk[cpu_sel] = imx_clk_mux("cpu_sel", ccm(CCM_CCTL), 14, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks));
clk[cpu] = imx_clk_divider("cpu", "cpu_sel", ccm(CCM_CCTL), 30, 2);
diff --git a/arch/arm/mach-imx/clk-imx27.c b/drivers/clk/imx/clk-imx27.c
index ab6349ec23b9..d9d50d54ef2a 100644
--- a/arch/arm/mach-imx/clk-imx27.c
+++ b/drivers/clk/imx/clk-imx27.c
@@ -5,10 +5,15 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <dt-bindings/clock/imx27-clock.h>
+#include <soc/imx/revision.h>
+#include <soc/imx/timer.h>
+#include <asm/irq.h>
#include "clk.h"
-#include "common.h"
-#include "hardware.h"
+
+#define MX27_CCM_BASE_ADDR 0x10027000
+#define MX27_GPT1_BASE_ADDR 0x10003000
+#define MX27_INT_GPT1 (NR_IRQS_LEGACY + 26)
static void __iomem *ccm __initdata;
@@ -54,8 +59,8 @@ static void __init _mx27_clocks_init(unsigned long fref)
clk[IMX27_CLK_CKIH_GATE] = imx_clk_gate_dis("ckih_gate", "ckih", CCM_CSCR, 3);
clk[IMX27_CLK_MPLL_OSC_SEL] = imx_clk_mux("mpll_osc_sel", CCM_CSCR, 4, 1, mpll_osc_sel_clks, ARRAY_SIZE(mpll_osc_sel_clks));
clk[IMX27_CLK_MPLL_SEL] = imx_clk_mux("mpll_sel", CCM_CSCR, 16, 1, mpll_sel_clks, ARRAY_SIZE(mpll_sel_clks));
- clk[IMX27_CLK_MPLL] = imx_clk_pllv1("mpll", "mpll_sel", CCM_MPCTL0);
- clk[IMX27_CLK_SPLL] = imx_clk_pllv1("spll", "ckih_gate", CCM_SPCTL0);
+ clk[IMX27_CLK_MPLL] = imx_clk_pllv1(IMX_PLLV1_IMX27, "mpll", "mpll_sel", CCM_MPCTL0);
+ clk[IMX27_CLK_SPLL] = imx_clk_pllv1(IMX_PLLV1_IMX27, "spll", "ckih_gate", CCM_SPCTL0);
clk[IMX27_CLK_SPLL_GATE] = imx_clk_gate("spll_gate", "spll", CCM_CSCR, 1);
clk[IMX27_CLK_MPLL_MAIN2] = imx_clk_fixed_factor("mpll_main2", "mpll", 2, 3);
@@ -229,7 +234,7 @@ int __init mx27_clocks_init(unsigned long fref)
clk_register_clkdev(clk[IMX27_CLK_EMMA_AHB_GATE], "ahb", "m2m-emmaprp.0");
clk_register_clkdev(clk[IMX27_CLK_EMMA_IPG_GATE], "ipg", "m2m-emmaprp.0");
- mxc_timer_init(MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR), MX27_INT_GPT1);
+ mxc_timer_init(MX27_GPT1_BASE_ADDR, MX27_INT_GPT1, GPT_TYPE_IMX21);
return 0;
}
diff --git a/arch/arm/mach-imx/clk-imx31.c b/drivers/clk/imx/clk-imx31.c
index 286ef422cebc..fe66c40b7be2 100644
--- a/arch/arm/mach-imx/clk-imx31.c
+++ b/drivers/clk/imx/clk-imx31.c
@@ -21,12 +21,26 @@
#include <linux/io.h>
#include <linux/err.h>
#include <linux/of.h>
+#include <soc/imx/revision.h>
+#include <soc/imx/timer.h>
+#include <asm/irq.h>
#include "clk.h"
-#include "common.h"
-#include "crmregs-imx3.h"
-#include "hardware.h"
-#include "mx31.h"
+
+#define MX31_CCM_BASE_ADDR 0x53f80000
+#define MX31_GPT1_BASE_ADDR 0x53f90000
+#define MX31_INT_GPT (NR_IRQS_LEGACY + 29)
+
+#define MXC_CCM_CCMR 0x00
+#define MXC_CCM_PDR0 0x04
+#define MXC_CCM_PDR1 0x08
+#define MXC_CCM_MPCTL 0x10
+#define MXC_CCM_UPCTL 0x14
+#define MXC_CCM_SRPCTL 0x18
+#define MXC_CCM_CGR0 0x20
+#define MXC_CCM_CGR1 0x24
+#define MXC_CCM_CGR2 0x28
+#define MXC_CCM_PMCR0 0x5c
static const char *mcu_main_sel[] = { "spll", "mpll", };
static const char *per_sel[] = { "per_div", "ipg", };
@@ -50,15 +64,18 @@ static struct clk_onecell_data clk_data;
int __init mx31_clocks_init(unsigned long fref)
{
- void __iomem *base = MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR);
+ void __iomem *base;
struct device_node *np;
+ base = ioremap(MX31_CCM_BASE_ADDR, SZ_4K);
+ BUG_ON(!base);
+
clk[dummy] = imx_clk_fixed("dummy", 0);
clk[ckih] = imx_clk_fixed("ckih", fref);
clk[ckil] = imx_clk_fixed("ckil", 32768);
- clk[mpll] = imx_clk_pllv1("mpll", "ckih", base + MXC_CCM_MPCTL);
- clk[spll] = imx_clk_pllv1("spll", "ckih", base + MXC_CCM_SRPCTL);
- clk[upll] = imx_clk_pllv1("upll", "ckih", base + MXC_CCM_UPCTL);
+ clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX31, "mpll", "ckih", base + MXC_CCM_MPCTL);
+ clk[spll] = imx_clk_pllv1(IMX_PLLV1_IMX31, "spll", "ckih", base + MXC_CCM_SRPCTL);
+ clk[upll] = imx_clk_pllv1(IMX_PLLV1_IMX31, "upll", "ckih", base + MXC_CCM_UPCTL);
clk[mcu_main] = imx_clk_mux("mcu_main", base + MXC_CCM_PMCR0, 31, 1, mcu_main_sel, ARRAY_SIZE(mcu_main_sel));
clk[hsp] = imx_clk_divider("hsp", "mcu_main", base + MXC_CCM_PDR0, 11, 3);
clk[ahb] = imx_clk_divider("ahb", "mcu_main", base + MXC_CCM_PDR0, 3, 3);
@@ -182,7 +199,7 @@ int __init mx31_clocks_init(unsigned long fref)
mx31_revision();
clk_disable_unprepare(clk[iim_gate]);
- mxc_timer_init(MX31_IO_ADDRESS(MX31_GPT1_BASE_ADDR), MX31_INT_GPT);
+ mxc_timer_init(MX31_GPT1_BASE_ADDR, MX31_INT_GPT, GPT_TYPE_IMX31);
return 0;
}
diff --git a/arch/arm/mach-imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c
index a0d2b57fd376..69138ba3dec7 100644
--- a/arch/arm/mach-imx/clk-imx35.c
+++ b/drivers/clk/imx/clk-imx35.c
@@ -13,11 +13,26 @@
#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/err.h>
+#include <soc/imx/revision.h>
+#include <soc/imx/timer.h>
+#include <asm/irq.h>
-#include "crmregs-imx3.h"
#include "clk.h"
-#include "common.h"
-#include "hardware.h"
+
+#define MX35_CCM_BASE_ADDR 0x53f80000
+#define MX35_GPT1_BASE_ADDR 0x53f90000
+#define MX35_INT_GPT (NR_IRQS_LEGACY + 29)
+
+#define MXC_CCM_PDR0 0x04
+#define MX35_CCM_PDR2 0x0c
+#define MX35_CCM_PDR3 0x10
+#define MX35_CCM_PDR4 0x14
+#define MX35_CCM_MPCTL 0x1c
+#define MX35_CCM_PPCTL 0x20
+#define MX35_CCM_CGR0 0x2c
+#define MX35_CCM_CGR1 0x30
+#define MX35_CCM_CGR2 0x34
+#define MX35_CCM_CGR3 0x38
struct arm_ahb_div {
unsigned char arm, ahb, sel;
@@ -71,11 +86,14 @@ static struct clk *clk[clk_max];
int __init mx35_clocks_init(void)
{
- void __iomem *base = MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR);
+ void __iomem *base;
u32 pdr0, consumer_sel, hsp_sel;
struct arm_ahb_div *aad;
unsigned char *hsp_div;
+ base = ioremap(MX35_CCM_BASE_ADDR, SZ_4K);
+ BUG_ON(!base);
+
pdr0 = __raw_readl(base + MXC_CCM_PDR0);
consumer_sel = (pdr0 >> 16) & 0xf;
aad = &clk_consumer[consumer_sel];
@@ -89,8 +107,8 @@ int __init mx35_clocks_init(void)
}
clk[ckih] = imx_clk_fixed("ckih", 24000000);
- clk[mpll] = imx_clk_pllv1("mpll", "ckih", base + MX35_CCM_MPCTL);
- clk[ppll] = imx_clk_pllv1("ppll", "ckih", base + MX35_CCM_PPCTL);
+ clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "mpll", "ckih", base + MX35_CCM_MPCTL);
+ clk[ppll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "ppll", "ckih", base + MX35_CCM_PPCTL);
clk[mpll] = imx_clk_fixed_factor("mpll_075", "mpll", 3, 4);
@@ -276,11 +294,7 @@ int __init mx35_clocks_init(void)
imx_print_silicon_rev("i.MX35", mx35_revision());
-#ifdef CONFIG_MXC_USE_EPIT
- epit_timer_init(MX35_IO_ADDRESS(MX35_EPIT1_BASE_ADDR), MX35_INT_EPIT1);
-#else
- mxc_timer_init(MX35_IO_ADDRESS(MX35_GPT1_BASE_ADDR), MX35_INT_GPT);
-#endif
+ mxc_timer_init(MX35_GPT1_BASE_ADDR, MX35_INT_GPT, GPT_TYPE_IMX31);
return 0;
}
diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/drivers/clk/imx/clk-imx51-imx53.c
index 0f7e536147cb..a7e4f394be0d 100644
--- a/arch/arm/mach-imx/clk-imx51-imx53.c
+++ b/drivers/clk/imx/clk-imx51-imx53.c
@@ -16,11 +16,10 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <soc/imx/revision.h>
#include <dt-bindings/clock/imx5-clock.h>
#include "clk.h"
-#include "common.h"
-#include "hardware.h"
#define MX51_DPLL1_BASE 0x83f80000
#define MX51_DPLL2_BASE 0x83f84000
@@ -133,8 +132,6 @@ static struct clk_onecell_data clk_data;
static void __init mx5_clocks_common_init(void __iomem *ccm_base)
{
- imx5_pm_set_ccm_base(ccm_base);
-
clk[IMX5_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
clk[IMX5_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
clk[IMX5_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
diff --git a/arch/arm/mach-imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index 469a150bf98f..d046f8e43de8 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -19,11 +19,10 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <soc/imx/revision.h>
#include <dt-bindings/clock/imx6qdl-clock.h>
#include "clk.h"
-#include "common.h"
-#include "hardware.h"
static const char *step_sels[] = { "osc", "pll2_pfd2_396m", };
static const char *pll1_sw_sels[] = { "pll1_sys", "step", };
@@ -121,6 +120,16 @@ static unsigned int share_count_ssi2;
static unsigned int share_count_ssi3;
static unsigned int share_count_mipi_core_cfg;
+static inline int clk_on_imx6q(void)
+{
+ return of_machine_is_compatible("fsl,imx6q");
+}
+
+static inline int clk_on_imx6dl(void)
+{
+ return of_machine_is_compatible("fsl,imx6dl");
+}
+
static void __init imx6q_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
@@ -141,7 +150,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
WARN_ON(!base);
/* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */
- if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) {
+ if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) {
post_div_table[1].div = 1;
post_div_table[2].div = 1;
video_div_table[1].div = 1;
@@ -248,7 +257,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2);
clk[IMX6QDL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
clk[IMX6QDL_CLK_VIDEO_27M] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20);
- if (cpu_is_imx6dl()) {
+ if (clk_on_imx6dl()) {
clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1);
clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
}
@@ -262,8 +271,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
base = of_iomap(np, 0);
WARN_ON(!base);
- imx6q_pm_set_ccm_base(base);
-
/* name reg shift width parent_names num_parents */
clk[IMX6QDL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
clk[IMX6QDL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
@@ -275,7 +282,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
clk[IMX6QDL_CLK_ASRC_SEL] = imx_clk_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
clk[IMX6QDL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
- if (cpu_is_imx6q()) {
+ if (clk_on_imx6q()) {
clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_mux("gpu2d_axi", base + 0x18, 0, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_mux("gpu3d_axi", base + 0x18, 1, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
}
@@ -382,7 +389,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2);
clk[IMX6QDL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4);
clk[IMX6QDL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6);
- if (cpu_is_imx6dl())
+ if (clk_on_imx6dl())
clk[IMX6DL_CLK_I2C4] = imx_clk_gate2("i2c4", "ipg_per", base + 0x6c, 8);
else
clk[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8);
@@ -392,7 +399,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai);
clk[IMX6QDL_CLK_GPT_IPG] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20);
clk[IMX6QDL_CLK_GPT_IPG_PER] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22);
- if (cpu_is_imx6dl())
+ if (clk_on_imx6dl())
/*
* The multiplexer and divider of imx6q clock gpu3d_shader get
* redefined/reused as gpu2d_core_sel and gpu2d_core_podf on imx6dl.
@@ -420,7 +427,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_HSI_TX] = imx_clk_gate2_shared("hsi_tx", "hsi_tx_podf", base + 0x74, 16, &share_count_mipi_core_cfg);
clk[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg);
clk[IMX6QDL_CLK_MIPI_IPG] = imx_clk_gate2_shared("mipi_ipg", "ipg", base + 0x74, 16, &share_count_mipi_core_cfg);
- if (cpu_is_imx6dl())
+ if (clk_on_imx6dl())
/*
* The multiplexer and divider of the imx6q clock gpu2d get
* redefined/reused as mlb_sys_sel and mlb_sys_clk_podf on imx6dl.
@@ -443,7 +450,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28);
clk[IMX6QDL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30);
clk[IMX6QDL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0);
- clk[IMX6QDL_CLK_SATA] = imx_clk_gate2("sata", "ipg", base + 0x7c, 4);
+ clk[IMX6QDL_CLK_SATA] = imx_clk_gate2("sata", "ahb", base + 0x7c, 4);
clk[IMX6QDL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
clk[IMX6QDL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
clk[IMX6QDL_CLK_SPDIF] = imx_clk_gate2("spdif", "spdif_podf", base + 0x7c, 14);
@@ -470,7 +477,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
* The gpt_3m clock is not available on i.MX6Q TO1.0. Let's point it
* to clock gpt_ipg_per to ease the gpt driver code.
*/
- if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0)
+ if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0)
clk[IMX6QDL_CLK_GPT_3M] = clk[IMX6QDL_CLK_GPT_IPG_PER];
imx_check_clocks(clk, ARRAY_SIZE(clk));
@@ -482,7 +489,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk_register_clkdev(clk[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);
if ((imx_get_soc_revision() != IMX_CHIP_REVISION_1_0) ||
- cpu_is_imx6dl()) {
+ clk_on_imx6dl()) {
clk_set_parent(clk[IMX6QDL_CLK_LDB_DI0_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
clk_set_parent(clk[IMX6QDL_CLK_LDB_DI1_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
}
@@ -527,8 +534,5 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
/* All existing boards with PCIe use LVDS1 */
if (IS_ENABLED(CONFIG_PCI_IMX6))
clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]);
-
- /* Set initial power mode */
- imx6q_set_lpm(WAIT_CLOCKED);
}
CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c
index e982ebe10814..a0d4cf26cfa9 100644
--- a/arch/arm/mach-imx/clk-imx6sl.c
+++ b/drivers/clk/imx/clk-imx6sl.c
@@ -16,7 +16,6 @@
#include <dt-bindings/clock/imx6sl-clock.h>
#include "clk.h"
-#include "common.h"
#define CCSR 0xc
#define BM_CCSR_PLL1_SW_CLK_SEL (1 << 2)
@@ -288,9 +287,6 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
WARN_ON(!base);
ccm_base = base;
- /* Reuse imx6q pm code */
- imx6q_pm_set_ccm_base(base);
-
/* name reg shift width parent_names num_parents */
clks[IMX6SL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
clks[IMX6SL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
@@ -443,8 +439,5 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clk_set_parent(clks[IMX6SL_CLK_LCDIF_AXI_SEL],
clks[IMX6SL_CLK_PLL2_PFD2]);
-
- /* Set initial power mode */
- imx6q_set_lpm(WAIT_CLOCKED);
}
CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init);
diff --git a/arch/arm/mach-imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c
index 5a3e5a159e70..5b95c2c2bf52 100644
--- a/arch/arm/mach-imx/clk-imx6sx.c
+++ b/drivers/clk/imx/clk-imx6sx.c
@@ -21,7 +21,6 @@
#include <linux/types.h>
#include "clk.h"
-#include "common.h"
#define CCDR 0x4
#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16)
@@ -216,7 +215,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
clks[IMX6SX_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
- /* FIXME 100Mhz is used for pcie ref for all imx6 pcie, excepted imx6q */
+ /* FIXME 100MHz is used for pcie ref for all imx6 pcie, excepted imx6q */
clks[IMX6SX_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 5);
clks[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
@@ -268,8 +267,6 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
base = of_iomap(np, 0);
WARN_ON(!base);
- imx6q_pm_set_ccm_base(base);
-
/* name reg shift width parent_names num_parents */
clks[IMX6SX_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
clks[IMX6SX_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
@@ -520,7 +517,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
pr_err("Failed to set pcie parent clk.\n");
/*
- * Init enet system AHB clock, set to 200Mhz
+ * Init enet system AHB clock, set to 200MHz
* pll2_pfd2_396m-> ENET_PODF-> ENET_AHB
*/
clk_set_parent(clks[IMX6SX_CLK_ENET_PRE_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
@@ -560,8 +557,5 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clk_set_parent(clks[IMX6SX_CLK_QSPI1_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
clk_set_parent(clks[IMX6SX_CLK_QSPI2_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
-
- /* Set initial power mode */
- imx6q_set_lpm(WAIT_CLOCKED);
}
CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init);
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
new file mode 100644
index 000000000000..71f3a94b472c
--- /dev/null
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -0,0 +1,860 @@
+/*
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
+ *
+ * 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 <dt-bindings/clock/imx7d-clock.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/types.h>
+
+#include "clk.h"
+
+static struct clk *clks[IMX7D_CLK_END];
+static const char *arm_a7_sel[] = { "osc", "pll_arm_main_clk",
+ "pll_enet_500m_clk", "pll_dram_main_clk",
+ "pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_audio_main_clk",
+ "pll_usb_main_clk", };
+
+static const char *arm_m4_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_enet_250m_clk", "pll_sys_pfd2_270m_clk",
+ "pll_dram_533m_clk", "pll_audio_main_clk", "pll_video_main_clk",
+ "pll_usb_main_clk", };
+
+static const char *arm_m0_sel[] = { "osc", "pll_sys_main_120m_clk",
+ "pll_enet_125m_clk", "pll_sys_pfd2_135m_clk",
+ "pll_dram_533m_clk", "pll_audio_main_clk", "pll_video_main_clk",
+ "pll_usb_main_clk", };
+
+static const char *axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk",
+ "pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd5_clk",
+ "pll_audio_main_clk", "pll_video_main_clk", "pll_sys_pfd7_clk", };
+
+static const char *disp_axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk",
+ "pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd6_clk",
+ "pll_sys_pfd7_clk", "pll_audio_main_clk", "pll_video_main_clk", };
+
+static const char *enet_axi_sel[] = { "osc", "pll_sys_pfd2_270m_clk",
+ "pll_dram_533m_clk", "pll_enet_250m_clk",
+ "pll_sys_main_240m_clk", "pll_audio_main_clk", "pll_video_main_clk",
+ "pll_sys_pfd4_clk", };
+
+static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk",
+ "pll_dram_533m_clk", "pll_sys_main_240m_clk",
+ "pll_sys_pfd2_135m_clk", "pll_sys_pfd6_clk", "pll_enet_250m_clk",
+ "pll_audio_main_clk", };
+
+static const char *ahb_channel_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
+ "pll_dram_533m_clk", "pll_sys_pfd0_392m_clk",
+ "pll_enet_125m_clk", "pll_usb_main_clk", "pll_audio_main_clk",
+ "pll_video_main_clk", };
+
+static const char *dram_phym_sel[] = { "pll_dram_main_clk",
+ "dram_phym_alt_clk", };
+
+static const char *dram_sel[] = { "pll_dram_main_clk",
+ "dram_alt_clk", };
+
+static const char *dram_phym_alt_sel[] = { "osc", "pll_dram_533m_clk",
+ "pll_sys_main_clk", "pll_enet_500m_clk",
+ "pll_usb_main_clk", "pll_sys_pfd7_clk", "pll_audio_main_clk",
+ "pll_video_main_clk", };
+
+static const char *dram_alt_sel[] = { "osc", "pll_dram_533m_clk",
+ "pll_sys_main_clk", "pll_enet_500m_clk",
+ "pll_enet_250m_clk", "pll_sys_pfd0_392m_clk",
+ "pll_audio_main_clk", "pll_sys_pfd2_270m_clk", };
+
+static const char *usb_hsic_sel[] = { "osc", "pll_sys_main_clk",
+ "pll_usb_main_clk", "pll_sys_pfd3_clk", "pll_sys_pfd4_clk",
+ "pll_sys_pfd5_clk", "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", };
+
+static const char *pcie_ctrl_sel[] = { "osc", "pll_enet_250m_clk",
+ "pll_sys_main_240m_clk", "pll_sys_pfd2_270m_clk",
+ "pll_dram_533m_clk", "pll_enet_500m_clk",
+ "pll_sys_pfd1_332m_clk", "pll_sys_pfd6_clk", };
+
+static const char *pcie_phy_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_enet_500m_clk", "ext_clk_1", "ext_clk_2", "ext_clk_3",
+ "ext_clk_4", "pll_sys_pfd0_392m_clk", };
+
+static const char *epdc_pixel_sel[] = { "osc", "pll_sys_pfd1_332m_clk",
+ "pll_dram_533m_clk", "pll_sys_main_clk", "pll_sys_pfd5_clk",
+ "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", "pll_video_main_clk", };
+
+static const char *lcdif_pixel_sel[] = { "osc", "pll_sys_pfd5_clk",
+ "pll_dram_533m_clk", "ext_clk_3", "pll_sys_pfd4_clk",
+ "pll_sys_pfd2_270m_clk", "pll_video_main_clk",
+ "pll_usb_main_clk", };
+
+static const char *mipi_dsi_sel[] = { "osc", "pll_sys_pfd5_clk",
+ "pll_sys_pfd3_clk", "pll_sys_main_clk", "pll_sys_pfd0_196m_clk",
+ "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_main_clk", };
+
+static const char *mipi_csi_sel[] = { "osc", "pll_sys_pfd4_clk",
+ "pll_sys_pfd3_clk", "pll_sys_main_clk", "pll_sys_pfd0_196m_clk",
+ "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_main_clk", };
+
+static const char *mipi_dphy_sel[] = { "osc", "pll_sys_main_120m_clk",
+ "pll_dram_533m_clk", "pll_sys_pfd5_clk", "ref_1m_clk", "ext_clk_2",
+ "pll_video_main_clk", "ext_clk_3", };
+
+static const char *sai1_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
+ "pll_audio_main_clk", "pll_dram_533m_clk", "pll_video_main_clk",
+ "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_2", };
+
+static const char *sai2_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
+ "pll_audio_main_clk", "pll_dram_533m_clk", "pll_video_main_clk",
+ "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_2", };
+
+static const char *sai3_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
+ "pll_audio_main_clk", "pll_dram_533m_clk", "pll_video_main_clk",
+ "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_3", };
+
+static const char *spdif_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
+ "pll_audio_main_clk", "pll_dram_533m_clk", "pll_video_main_clk",
+ "pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_3_clk", };
+
+static const char *enet1_ref_sel[] = { "osc", "pll_enet_125m_clk",
+ "pll_enet_50m_clk", "pll_enet_25m_clk",
+ "pll_sys_main_120m_clk", "pll_audio_main_clk", "pll_video_main_clk",
+ "ext_clk_4", };
+
+static const char *enet1_time_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_audio_main_clk", "ext_clk_1", "ext_clk_2", "ext_clk_3",
+ "ext_clk_4", "pll_video_main_clk", };
+
+static const char *enet2_ref_sel[] = { "osc", "pll_enet_125m_clk",
+ "pll_enet_50m_clk", "pll_enet_25m_clk",
+ "pll_sys_main_120m_clk", "pll_audio_main_clk", "pll_video_main_clk",
+ "ext_clk_4", };
+
+static const char *enet2_time_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_audio_main_clk", "ext_clk_1", "ext_clk_2", "ext_clk_3",
+ "ext_clk_4", "pll_video_main_clk", };
+
+static const char *enet_phy_ref_sel[] = { "osc", "pll_enet_25m_clk",
+ "pll_enet_50m_clk", "pll_enet_125m_clk",
+ "pll_dram_533m_clk", "pll_audio_main_clk", "pll_video_main_clk",
+ "pll_sys_pfd3_clk", };
+
+static const char *eim_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
+ "pll_sys_main_120m_clk", "pll_dram_533m_clk",
+ "pll_sys_pfd2_270m_clk", "pll_sys_pfd3_clk", "pll_enet_125m_clk",
+ "pll_usb_main_clk", };
+
+static const char *nand_sel[] = { "osc", "pll_sys_main_clk",
+ "pll_dram_533m_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd3_clk",
+ "pll_enet_500m_clk", "pll_enet_250m_clk",
+ "pll_video_main_clk", };
+
+static const char *qspi_sel[] = { "osc", "pll_sys_pfd4_clk",
+ "pll_dram_533m_clk", "pll_enet_500m_clk", "pll_sys_pfd3_clk",
+ "pll_sys_pfd2_270m_clk", "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", };
+
+static const char *usdhc1_sel[] = { "osc", "pll_sys_pfd0_392m_clk",
+ "pll_dram_533m_clk", "pll_enet_500m_clk", "pll_sys_pfd4_clk",
+ "pll_sys_pfd2_270m_clk", "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", };
+
+static const char *usdhc2_sel[] = { "osc", "pll_sys_pfd0_392m_clk",
+ "pll_dram_533m_clk", "pll_enet_500m_clk", "pll_sys_pfd4_clk",
+ "pll_sys_pfd2_270m_clk", "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", };
+
+static const char *usdhc3_sel[] = { "osc", "pll_sys_pfd0_392m_clk",
+ "pll_dram_533m_clk", "pll_enet_500m_clk", "pll_sys_pfd4_clk",
+ "pll_sys_pfd2_270m_clk", "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", };
+
+static const char *can1_sel[] = { "osc", "pll_sys_main_120m_clk",
+ "pll_dram_533m_clk", "pll_sys_main_clk",
+ "pll_enet_40m_clk", "pll_usb_main_clk", "ext_clk_1",
+ "ext_clk_4", };
+
+static const char *can2_sel[] = { "osc", "pll_sys_main_120m_clk",
+ "pll_dram_533m_clk", "pll_sys_main_clk",
+ "pll_enet_40m_clk", "pll_usb_main_clk", "ext_clk_1",
+ "ext_clk_3", };
+
+static const char *i2c1_sel[] = { "osc", "pll_sys_main_120m_clk",
+ "pll_enet_50m_clk", "pll_dram_533m_clk",
+ "pll_audio_main_clk", "pll_video_main_clk", "pll_usb_main_clk",
+ "pll_sys_pfd2_135m_clk", };
+
+static const char *i2c2_sel[] = { "osc", "pll_sys_main_120m_clk",
+ "pll_enet_50m_clk", "pll_dram_533m_clk",
+ "pll_audio_main_clk", "pll_video_main_clk", "pll_usb_main_clk",
+ "pll_sys_pfd2_135m_clk", };
+
+static const char *i2c3_sel[] = { "osc", "pll_sys_main_120m_clk",
+ "pll_enet_50m_clk", "pll_dram_533m_clk",
+ "pll_audio_main_clk", "pll_video_main_clk", "pll_usb_main_clk",
+ "pll_sys_pfd2_135m_clk", };
+
+static const char *i2c4_sel[] = { "osc", "pll_sys_main_120m_clk",
+ "pll_enet_50m_clk", "pll_dram_533m_clk",
+ "pll_audio_main_clk", "pll_video_main_clk", "pll_usb_main_clk",
+ "pll_sys_pfd2_135m_clk", };
+
+static const char *uart1_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_enet_40m_clk", "pll_enet_100m_clk",
+ "pll_sys_main_clk", "ext_clk_2", "ext_clk_4",
+ "pll_usb_main_clk", };
+
+static const char *uart2_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_enet_40m_clk", "pll_enet_100m_clk",
+ "pll_sys_main_clk", "ext_clk_2", "ext_clk_3",
+ "pll_usb_main_clk", };
+
+static const char *uart3_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_enet_40m_clk", "pll_enet_100m_clk",
+ "pll_sys_main_clk", "ext_clk_2", "ext_clk_4",
+ "pll_usb_main_clk", };
+
+static const char *uart4_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_enet_40m_clk", "pll_enet_100m_clk",
+ "pll_sys_main_clk", "ext_clk_2", "ext_clk_3",
+ "pll_usb_main_clk", };
+
+static const char *uart5_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_enet_40m_clk", "pll_enet_100m_clk",
+ "pll_sys_main_clk", "ext_clk_2", "ext_clk_4",
+ "pll_usb_main_clk", };
+
+static const char *uart6_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_enet_40m_clk", "pll_enet_100m_clk",
+ "pll_sys_main_clk", "ext_clk_2", "ext_clk_3",
+ "pll_usb_main_clk", };
+
+static const char *uart7_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_enet_40m_clk", "pll_enet_100m_clk",
+ "pll_sys_main_clk", "ext_clk_2", "ext_clk_4",
+ "pll_usb_main_clk", };
+
+static const char *ecspi1_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_enet_40m_clk", "pll_sys_main_120m_clk",
+ "pll_sys_main_clk", "pll_sys_pfd4_clk", "pll_enet_250m_clk",
+ "pll_usb_main_clk", };
+
+static const char *ecspi2_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_enet_40m_clk", "pll_sys_main_120m_clk",
+ "pll_sys_main_clk", "pll_sys_pfd4_clk", "pll_enet_250m_clk",
+ "pll_usb_main_clk", };
+
+static const char *ecspi3_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_enet_40m_clk", "pll_sys_main_120m_clk",
+ "pll_sys_main_clk", "pll_sys_pfd4_clk", "pll_enet_250m_clk",
+ "pll_usb_main_clk", };
+
+static const char *ecspi4_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_enet_40m_clk", "pll_sys_main_120m_clk",
+ "pll_sys_main_clk", "pll_sys_pfd4_clk", "pll_enet_250m_clk",
+ "pll_usb_main_clk", };
+
+static const char *pwm1_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk",
+ "ext_clk_1", "ref_1m_clk", "pll_video_main_clk", };
+
+static const char *pwm2_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk",
+ "ext_clk_1", "ref_1m_clk", "pll_video_main_clk", };
+
+static const char *pwm3_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk",
+ "ext_clk_2", "ref_1m_clk", "pll_video_main_clk", };
+
+static const char *pwm4_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk",
+ "ext_clk_2", "ref_1m_clk", "pll_video_main_clk", };
+
+static const char *flextimer1_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk",
+ "ext_clk_3", "ref_1m_clk", "pll_video_main_clk", };
+
+static const char *flextimer2_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_main_clk",
+ "ext_clk_3", "ref_1m_clk", "pll_video_main_clk", };
+
+static const char *sim1_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
+ "pll_sys_main_120m_clk", "pll_dram_533m_clk",
+ "pll_usb_main_clk", "pll_audio_main_clk", "pll_enet_125m_clk",
+ "pll_sys_pfd7_clk", };
+
+static const char *sim2_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
+ "pll_sys_main_120m_clk", "pll_dram_533m_clk",
+ "pll_usb_main_clk", "pll_video_main_clk", "pll_enet_125m_clk",
+ "pll_sys_pfd7_clk", };
+
+static const char *gpt1_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk",
+ "ref_1m_clk", "pll_audio_main_clk", "ext_clk_1", };
+
+static const char *gpt2_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk",
+ "ref_1m_clk", "pll_audio_main_clk", "ext_clk_2", };
+
+static const char *gpt3_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk",
+ "ref_1m_clk", "pll_audio_main_clk", "ext_clk_3", };
+
+static const char *gpt4_sel[] = { "osc", "pll_enet_100m_clk",
+ "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk",
+ "ref_1m_clk", "pll_audio_main_clk", "ext_clk_4", };
+
+static const char *trace_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
+ "pll_sys_main_120m_clk", "pll_dram_533m_clk",
+ "pll_enet_125m_clk", "pll_usb_main_clk", "ext_clk_2",
+ "ext_clk_3", };
+
+static const char *wdog_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
+ "pll_sys_main_120m_clk", "pll_dram_533m_clk",
+ "pll_enet_125m_clk", "pll_usb_main_clk", "ref_1m_clk",
+ "pll_sys_pfd1_166m_clk", };
+
+static const char *csi_mclk_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
+ "pll_sys_main_120m_clk", "pll_dram_533m_clk",
+ "pll_enet_125m_clk", "pll_audio_main_clk", "pll_video_main_clk",
+ "pll_usb_main_clk", };
+
+static const char *audio_mclk_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
+ "pll_sys_main_120m_clk", "pll_dram_533m_clk",
+ "pll_enet_125m_clk", "pll_audio_main_clk", "pll_video_main_clk",
+ "pll_usb_main_clk", };
+
+static const char *wrclk_sel[] = { "osc", "pll_enet_40m_clk",
+ "pll_dram_533m_clk", "pll_usb_main_clk",
+ "pll_sys_main_240m_clk", "pll_sys_pfd2_270m_clk",
+ "pll_enet_500m_clk", "pll_sys_pfd7_clk", };
+
+static const char *clko1_sel[] = { "osc", "pll_sys_main_clk",
+ "pll_sys_main_240m_clk", "pll_sys_pfd0_196m_clk", "pll_sys_pfd3_clk",
+ "pll_enet_500m_clk", "pll_dram_533m_clk", "ref_1m_clk", };
+
+static const char *clko2_sel[] = { "osc", "pll_sys_main_240m_clk",
+ "pll_sys_pfd0_392m_clk", "pll_sys_pfd1_166m_clk", "pll_sys_pfd4_clk",
+ "pll_audio_main_clk", "pll_video_main_clk", "osc_32k_clk", };
+
+static const char *lvds1_sel[] = { "pll_arm_main_clk",
+ "pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd1_332m_clk",
+ "pll_sys_pfd2_270m_clk", "pll_sys_pfd3_clk", "pll_sys_pfd4_clk",
+ "pll_sys_pfd5_clk", "pll_sys_pfd6_clk", "pll_sys_pfd7_clk",
+ "pll_audio_main_clk", "pll_video_main_clk", "pll_enet_500m_clk",
+ "pll_enet_250m_clk", "pll_enet_125m_clk", "pll_enet_100m_clk",
+ "pll_enet_50m_clk", "pll_enet_40m_clk", "pll_enet_25m_clk",
+ "pll_dram_main_clk", };
+
+static const char *pll_bypass_src_sel[] = { "osc", "dummy", };
+static const char *pll_arm_bypass_sel[] = { "pll_arm_main", "pll_arm_main_src", };
+static const char *pll_dram_bypass_sel[] = { "pll_dram_main", "pll_dram_main_src", };
+static const char *pll_sys_bypass_sel[] = { "pll_sys_main", "pll_sys_main_src", };
+static const char *pll_enet_bypass_sel[] = { "pll_enet_main", "pll_enet_main_src", };
+static const char *pll_audio_bypass_sel[] = { "pll_audio_main", "pll_audio_main_src", };
+static const char *pll_video_bypass_sel[] = { "pll_video_main", "pll_video_main_src", };
+
+static struct clk_onecell_data clk_data;
+
+static void __init imx7d_clocks_init(struct device_node *ccm_node)
+{
+ struct device_node *np;
+ void __iomem *base;
+ int i;
+
+ clks[IMX7D_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+ clks[IMX7D_OSC_24M_CLK] = of_clk_get_by_name(ccm_node, "osc");
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop");
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX7D_PLL_ARM_MAIN_SRC] = imx_clk_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+ clks[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+ clks[IMX7D_PLL_SYS_MAIN_SRC] = imx_clk_mux("pll_sys_main_src", base + 0xb0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+ clks[IMX7D_PLL_ENET_MAIN_SRC] = imx_clk_mux("pll_enet_main_src", base + 0xe0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+ clks[IMX7D_PLL_AUDIO_MAIN_SRC] = imx_clk_mux("pll_audio_main_src", base + 0xf0, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+ clks[IMX7D_PLL_VIDEO_MAIN_SRC] = imx_clk_mux("pll_video_main_src", base + 0x130, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
+
+ clks[IMX7D_PLL_ARM_MAIN] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll_arm_main", "pll_arm_main_src", base + 0x60, 0x7f);
+ clks[IMX7D_PLL_DRAM_MAIN] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll_dram_main", "pll_dram_main_src", base + 0x70, 0x7f);
+ clks[IMX7D_PLL_SYS_MAIN] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll_sys_main", "pll_sys_main_src", base + 0xb0, 0x1);
+ clks[IMX7D_PLL_ENET_MAIN] = imx_clk_pllv3(IMX_PLLV3_ENET_IMX7, "pll_enet_main", "pll_enet_main_src", base + 0xe0, 0x0);
+ clks[IMX7D_PLL_AUDIO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV, "pll_audio_main", "pll_audio_main_src", base + 0xf0, 0x7f);
+ clks[IMX7D_PLL_VIDEO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV, "pll_video_main", "pll_video_main_src", base + 0x130, 0x7f);
+
+ clks[IMX7D_PLL_ARM_MAIN_BYPASS] = imx_clk_mux_flags("pll_arm_main_bypass", base + 0x60, 16, 1, pll_arm_bypass_sel, ARRAY_SIZE(pll_arm_bypass_sel), CLK_SET_RATE_PARENT);
+ clks[IMX7D_PLL_DRAM_MAIN_BYPASS] = imx_clk_mux_flags("pll_dram_main_bypass", base + 0x70, 16, 1, pll_dram_bypass_sel, ARRAY_SIZE(pll_dram_bypass_sel), CLK_SET_RATE_PARENT);
+ clks[IMX7D_PLL_SYS_MAIN_BYPASS] = imx_clk_mux_flags("pll_sys_main_bypass", base + 0xb0, 16, 1, pll_sys_bypass_sel, ARRAY_SIZE(pll_sys_bypass_sel), CLK_SET_RATE_PARENT);
+ clks[IMX7D_PLL_ENET_MAIN_BYPASS] = imx_clk_mux_flags("pll_enet_main_bypass", base + 0xe0, 16, 1, pll_enet_bypass_sel, ARRAY_SIZE(pll_enet_bypass_sel), CLK_SET_RATE_PARENT);
+ clks[IMX7D_PLL_AUDIO_MAIN_BYPASS] = imx_clk_mux_flags("pll_audio_main_bypass", base + 0xf0, 16, 1, pll_audio_bypass_sel, ARRAY_SIZE(pll_audio_bypass_sel), CLK_SET_RATE_PARENT);
+ clks[IMX7D_PLL_VIDEO_MAIN_BYPASS] = imx_clk_mux_flags("pll_video_main_bypass", base + 0x130, 16, 1, pll_video_bypass_sel, ARRAY_SIZE(pll_video_bypass_sel), CLK_SET_RATE_PARENT);
+
+ clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]);
+ clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]);
+ clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]);
+ clk_set_parent(clks[IMX7D_PLL_ENET_MAIN_BYPASS], clks[IMX7D_PLL_ENET_MAIN]);
+ clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]);
+ clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]);
+
+ clks[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13);
+ clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_main_bypass", base + 0x70, 13);
+ clks[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13);
+ clks[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_gate("pll_audio_main_clk", "pll_audio_main_bypass", base + 0xf0, 13);
+ clks[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_gate("pll_video_main_clk", "pll_video_main_bypass", base + 0x130, 13);
+
+ clks[IMX7D_PLL_SYS_PFD0_392M_CLK] = imx_clk_pfd("pll_sys_pfd0_392m_clk", "pll_sys_main_clk", base + 0xc0, 0);
+ clks[IMX7D_PLL_SYS_PFD1_332M_CLK] = imx_clk_pfd("pll_sys_pfd1_332m_clk", "pll_sys_main_clk", base + 0xc0, 1);
+ clks[IMX7D_PLL_SYS_PFD2_270M_CLK] = imx_clk_pfd("pll_sys_pfd2_270m_clk", "pll_sys_main_clk", base + 0xc0, 2);
+
+ clks[IMX7D_PLL_SYS_PFD3_CLK] = imx_clk_pfd("pll_sys_pfd3_clk", "pll_sys_main_clk", base + 0xc0, 3);
+ clks[IMX7D_PLL_SYS_PFD4_CLK] = imx_clk_pfd("pll_sys_pfd4_clk", "pll_sys_main_clk", base + 0xd0, 0);
+ clks[IMX7D_PLL_SYS_PFD5_CLK] = imx_clk_pfd("pll_sys_pfd5_clk", "pll_sys_main_clk", base + 0xd0, 1);
+ clks[IMX7D_PLL_SYS_PFD6_CLK] = imx_clk_pfd("pll_sys_pfd6_clk", "pll_sys_main_clk", base + 0xd0, 2);
+ clks[IMX7D_PLL_SYS_PFD7_CLK] = imx_clk_pfd("pll_sys_pfd7_clk", "pll_sys_main_clk", base + 0xd0, 3);
+
+ clks[IMX7D_PLL_SYS_MAIN_480M] = imx_clk_fixed_factor("pll_sys_main_480m", "pll_sys_main_clk", 1, 1);
+ clks[IMX7D_PLL_SYS_MAIN_240M] = imx_clk_fixed_factor("pll_sys_main_240m", "pll_sys_main_clk", 1, 2);
+ clks[IMX7D_PLL_SYS_MAIN_120M] = imx_clk_fixed_factor("pll_sys_main_120m", "pll_sys_main_clk", 1, 4);
+ clks[IMX7D_PLL_DRAM_MAIN_533M] = imx_clk_fixed_factor("pll_dram_533m", "pll_dram_main_clk", 1, 2);
+
+ clks[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_gate_dis("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4);
+ clks[IMX7D_PLL_SYS_MAIN_240M_CLK] = imx_clk_gate_dis("pll_sys_main_240m_clk", "pll_sys_main_240m", base + 0xb0, 5);
+ clks[IMX7D_PLL_SYS_MAIN_120M_CLK] = imx_clk_gate_dis("pll_sys_main_120m_clk", "pll_sys_main_120m", base + 0xb0, 6);
+ clks[IMX7D_PLL_DRAM_MAIN_533M_CLK] = imx_clk_gate("pll_dram_533m_clk", "pll_dram_533m", base + 0x70, 12);
+
+ clks[IMX7D_PLL_SYS_PFD0_196M] = imx_clk_fixed_factor("pll_sys_pfd0_196m", "pll_sys_pfd0_392m_clk", 1, 2);
+ clks[IMX7D_PLL_SYS_PFD1_166M] = imx_clk_fixed_factor("pll_sys_pfd1_166m", "pll_sys_pfd1_332m_clk", 1, 2);
+ clks[IMX7D_PLL_SYS_PFD2_135M] = imx_clk_fixed_factor("pll_sys_pfd2_135m", "pll_sys_pfd2_270m_clk", 1, 2);
+
+ clks[IMX7D_PLL_SYS_PFD0_196M_CLK] = imx_clk_gate_dis("pll_sys_pfd0_196m_clk", "pll_sys_pfd0_196m", base + 0xb0, 26);
+ clks[IMX7D_PLL_SYS_PFD1_166M_CLK] = imx_clk_gate_dis("pll_sys_pfd1_166m_clk", "pll_sys_pfd1_166m", base + 0xb0, 27);
+ clks[IMX7D_PLL_SYS_PFD2_135M_CLK] = imx_clk_gate_dis("pll_sys_pfd2_135m_clk", "pll_sys_pfd2_135m", base + 0xb0, 28);
+
+ clks[IMX7D_PLL_ENET_MAIN_CLK] = imx_clk_fixed_factor("pll_enet_main_clk", "pll_enet_main_bypass", 1, 1);
+ clks[IMX7D_PLL_ENET_MAIN_500M] = imx_clk_fixed_factor("pll_enet_500m", "pll_enet_main_clk", 1, 2);
+ clks[IMX7D_PLL_ENET_MAIN_250M] = imx_clk_fixed_factor("pll_enet_250m", "pll_enet_main_clk", 1, 4);
+ clks[IMX7D_PLL_ENET_MAIN_125M] = imx_clk_fixed_factor("pll_enet_125m", "pll_enet_main_clk", 1, 8);
+ clks[IMX7D_PLL_ENET_MAIN_100M] = imx_clk_fixed_factor("pll_enet_100m", "pll_enet_main_clk", 1, 10);
+ clks[IMX7D_PLL_ENET_MAIN_50M] = imx_clk_fixed_factor("pll_enet_50m", "pll_enet_main_clk", 1, 20);
+ clks[IMX7D_PLL_ENET_MAIN_40M] = imx_clk_fixed_factor("pll_enet_40m", "pll_enet_main_clk", 1, 25);
+ clks[IMX7D_PLL_ENET_MAIN_25M] = imx_clk_fixed_factor("pll_enet_25m", "pll_enet_main_clk", 1, 40);
+
+ clks[IMX7D_PLL_ENET_MAIN_500M_CLK] = imx_clk_gate("pll_enet_500m_clk", "pll_enet_500m", base + 0xe0, 12);
+ clks[IMX7D_PLL_ENET_MAIN_250M_CLK] = imx_clk_gate("pll_enet_250m_clk", "pll_enet_250m", base + 0xe0, 11);
+ clks[IMX7D_PLL_ENET_MAIN_125M_CLK] = imx_clk_gate("pll_enet_125m_clk", "pll_enet_125m", base + 0xe0, 10);
+ clks[IMX7D_PLL_ENET_MAIN_100M_CLK] = imx_clk_gate("pll_enet_100m_clk", "pll_enet_100m", base + 0xe0, 9);
+ clks[IMX7D_PLL_ENET_MAIN_50M_CLK] = imx_clk_gate("pll_enet_50m_clk", "pll_enet_50m", base + 0xe0, 8);
+ clks[IMX7D_PLL_ENET_MAIN_40M_CLK] = imx_clk_gate("pll_enet_40m_clk", "pll_enet_40m", base + 0xe0, 7);
+ clks[IMX7D_PLL_ENET_MAIN_25M_CLK] = imx_clk_gate("pll_enet_25m_clk", "pll_enet_25m", base + 0xe0, 6);
+
+ clks[IMX7D_LVDS1_OUT_SEL] = imx_clk_mux("lvds1_sel", base + 0x170, 0, 5, lvds1_sel, ARRAY_SIZE(lvds1_sel));
+ clks[IMX7D_LVDS1_OUT_CLK] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x170, 5, BIT(6));
+
+ np = ccm_node;
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX7D_ARM_A7_ROOT_SRC] = imx_clk_mux("arm_a7_src", base + 0x8000, 24, 3, arm_a7_sel, ARRAY_SIZE(arm_a7_sel));
+ clks[IMX7D_ARM_M4_ROOT_SRC] = imx_clk_mux("arm_m4_src", base + 0x8080, 24, 3, arm_m4_sel, ARRAY_SIZE(arm_m4_sel));
+ clks[IMX7D_ARM_M0_ROOT_SRC] = imx_clk_mux("arm_m0_src", base + 0x8100, 24, 3, arm_m0_sel, ARRAY_SIZE(arm_m0_sel));
+ clks[IMX7D_MAIN_AXI_ROOT_SRC] = imx_clk_mux("axi_src", base + 0x8800, 24, 3, axi_sel, ARRAY_SIZE(axi_sel));
+ clks[IMX7D_DISP_AXI_ROOT_SRC] = imx_clk_mux("disp_axi_src", base + 0x8880, 24, 3, disp_axi_sel, ARRAY_SIZE(disp_axi_sel));
+ clks[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_mux("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel));
+ clks[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_mux("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel));
+ clks[IMX7D_AHB_CHANNEL_ROOT_SRC] = imx_clk_mux("ahb_src", base + 0x9000, 24, 3, ahb_channel_sel, ARRAY_SIZE(ahb_channel_sel));
+ clks[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_mux("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel));
+ clks[IMX7D_DRAM_ROOT_SRC] = imx_clk_mux("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel));
+ clks[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_mux("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel));
+ clks[IMX7D_DRAM_ALT_ROOT_SRC] = imx_clk_mux("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel));
+ clks[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_mux("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel));
+ clks[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_mux("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel));
+ clks[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_mux("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel));
+ clks[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_mux("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel));
+ clks[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_mux("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel));
+ clks[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_mux("mipi_dsi_src", base + 0xa380, 24, 3, mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel));
+ clks[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_mux("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel));
+ clks[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_mux("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel));
+ clks[IMX7D_SAI1_ROOT_SRC] = imx_clk_mux("sai1_src", base + 0xa500, 24, 3, sai1_sel, ARRAY_SIZE(sai1_sel));
+ clks[IMX7D_SAI2_ROOT_SRC] = imx_clk_mux("sai2_src", base + 0xa580, 24, 3, sai2_sel, ARRAY_SIZE(sai2_sel));
+ clks[IMX7D_SAI3_ROOT_SRC] = imx_clk_mux("sai3_src", base + 0xa600, 24, 3, sai3_sel, ARRAY_SIZE(sai3_sel));
+ clks[IMX7D_SPDIF_ROOT_SRC] = imx_clk_mux("spdif_src", base + 0xa680, 24, 3, spdif_sel, ARRAY_SIZE(spdif_sel));
+ clks[IMX7D_ENET1_REF_ROOT_SRC] = imx_clk_mux("enet1_ref_src", base + 0xa700, 24, 3, enet1_ref_sel, ARRAY_SIZE(enet1_ref_sel));
+ clks[IMX7D_ENET1_TIME_ROOT_SRC] = imx_clk_mux("enet1_time_src", base + 0xa780, 24, 3, enet1_time_sel, ARRAY_SIZE(enet1_time_sel));
+ clks[IMX7D_ENET2_REF_ROOT_SRC] = imx_clk_mux("enet2_ref_src", base + 0xa800, 24, 3, enet2_ref_sel, ARRAY_SIZE(enet2_ref_sel));
+ clks[IMX7D_ENET2_TIME_ROOT_SRC] = imx_clk_mux("enet2_time_src", base + 0xa880, 24, 3, enet2_time_sel, ARRAY_SIZE(enet2_time_sel));
+ clks[IMX7D_ENET_PHY_REF_ROOT_SRC] = imx_clk_mux("enet_phy_ref_src", base + 0xa900, 24, 3, enet_phy_ref_sel, ARRAY_SIZE(enet_phy_ref_sel));
+ clks[IMX7D_EIM_ROOT_SRC] = imx_clk_mux("eim_src", base + 0xa980, 24, 3, eim_sel, ARRAY_SIZE(eim_sel));
+ clks[IMX7D_NAND_ROOT_SRC] = imx_clk_mux("nand_src", base + 0xaa00, 24, 3, nand_sel, ARRAY_SIZE(nand_sel));
+ clks[IMX7D_QSPI_ROOT_SRC] = imx_clk_mux("qspi_src", base + 0xaa80, 24, 3, qspi_sel, ARRAY_SIZE(qspi_sel));
+ clks[IMX7D_USDHC1_ROOT_SRC] = imx_clk_mux("usdhc1_src", base + 0xab00, 24, 3, usdhc1_sel, ARRAY_SIZE(usdhc1_sel));
+ clks[IMX7D_USDHC2_ROOT_SRC] = imx_clk_mux("usdhc2_src", base + 0xab80, 24, 3, usdhc2_sel, ARRAY_SIZE(usdhc2_sel));
+ clks[IMX7D_USDHC3_ROOT_SRC] = imx_clk_mux("usdhc3_src", base + 0xac00, 24, 3, usdhc3_sel, ARRAY_SIZE(usdhc3_sel));
+ clks[IMX7D_CAN1_ROOT_SRC] = imx_clk_mux("can1_src", base + 0xac80, 24, 3, can1_sel, ARRAY_SIZE(can1_sel));
+ clks[IMX7D_CAN2_ROOT_SRC] = imx_clk_mux("can2_src", base + 0xad00, 24, 3, can2_sel, ARRAY_SIZE(can2_sel));
+ clks[IMX7D_I2C1_ROOT_SRC] = imx_clk_mux("i2c1_src", base + 0xad80, 24, 3, i2c1_sel, ARRAY_SIZE(i2c1_sel));
+ clks[IMX7D_I2C2_ROOT_SRC] = imx_clk_mux("i2c2_src", base + 0xae00, 24, 3, i2c2_sel, ARRAY_SIZE(i2c2_sel));
+ clks[IMX7D_I2C3_ROOT_SRC] = imx_clk_mux("i2c3_src", base + 0xae80, 24, 3, i2c3_sel, ARRAY_SIZE(i2c3_sel));
+ clks[IMX7D_I2C4_ROOT_SRC] = imx_clk_mux("i2c4_src", base + 0xaf00, 24, 3, i2c4_sel, ARRAY_SIZE(i2c4_sel));
+ clks[IMX7D_UART1_ROOT_SRC] = imx_clk_mux("uart1_src", base + 0xaf80, 24, 3, uart1_sel, ARRAY_SIZE(uart1_sel));
+ clks[IMX7D_UART2_ROOT_SRC] = imx_clk_mux("uart2_src", base + 0xb000, 24, 3, uart2_sel, ARRAY_SIZE(uart2_sel));
+ clks[IMX7D_UART3_ROOT_SRC] = imx_clk_mux("uart3_src", base + 0xb080, 24, 3, uart3_sel, ARRAY_SIZE(uart3_sel));
+ clks[IMX7D_UART4_ROOT_SRC] = imx_clk_mux("uart4_src", base + 0xb100, 24, 3, uart4_sel, ARRAY_SIZE(uart4_sel));
+ clks[IMX7D_UART5_ROOT_SRC] = imx_clk_mux("uart5_src", base + 0xb180, 24, 3, uart5_sel, ARRAY_SIZE(uart5_sel));
+ clks[IMX7D_UART6_ROOT_SRC] = imx_clk_mux("uart6_src", base + 0xb200, 24, 3, uart6_sel, ARRAY_SIZE(uart6_sel));
+ clks[IMX7D_UART7_ROOT_SRC] = imx_clk_mux("uart7_src", base + 0xb280, 24, 3, uart7_sel, ARRAY_SIZE(uart7_sel));
+ clks[IMX7D_ECSPI1_ROOT_SRC] = imx_clk_mux("ecspi1_src", base + 0xb300, 24, 3, ecspi1_sel, ARRAY_SIZE(ecspi1_sel));
+ clks[IMX7D_ECSPI2_ROOT_SRC] = imx_clk_mux("ecspi2_src", base + 0xb380, 24, 3, ecspi2_sel, ARRAY_SIZE(ecspi2_sel));
+ clks[IMX7D_ECSPI3_ROOT_SRC] = imx_clk_mux("ecspi3_src", base + 0xb400, 24, 3, ecspi3_sel, ARRAY_SIZE(ecspi3_sel));
+ clks[IMX7D_ECSPI4_ROOT_SRC] = imx_clk_mux("ecspi4_src", base + 0xb480, 24, 3, ecspi4_sel, ARRAY_SIZE(ecspi4_sel));
+ clks[IMX7D_PWM1_ROOT_SRC] = imx_clk_mux("pwm1_src", base + 0xb500, 24, 3, pwm1_sel, ARRAY_SIZE(pwm1_sel));
+ clks[IMX7D_PWM2_ROOT_SRC] = imx_clk_mux("pwm2_src", base + 0xb580, 24, 3, pwm2_sel, ARRAY_SIZE(pwm2_sel));
+ clks[IMX7D_PWM3_ROOT_SRC] = imx_clk_mux("pwm3_src", base + 0xb600, 24, 3, pwm3_sel, ARRAY_SIZE(pwm3_sel));
+ clks[IMX7D_PWM4_ROOT_SRC] = imx_clk_mux("pwm4_src", base + 0xb680, 24, 3, pwm4_sel, ARRAY_SIZE(pwm4_sel));
+ clks[IMX7D_FLEXTIMER1_ROOT_SRC] = imx_clk_mux("flextimer1_src", base + 0xb700, 24, 3, flextimer1_sel, ARRAY_SIZE(flextimer1_sel));
+ clks[IMX7D_FLEXTIMER2_ROOT_SRC] = imx_clk_mux("flextimer2_src", base + 0xb780, 24, 3, flextimer2_sel, ARRAY_SIZE(flextimer2_sel));
+ clks[IMX7D_SIM1_ROOT_SRC] = imx_clk_mux("sim1_src", base + 0xb800, 24, 3, sim1_sel, ARRAY_SIZE(sim1_sel));
+ clks[IMX7D_SIM2_ROOT_SRC] = imx_clk_mux("sim2_src", base + 0xb880, 24, 3, sim2_sel, ARRAY_SIZE(sim2_sel));
+ clks[IMX7D_GPT1_ROOT_SRC] = imx_clk_mux("gpt1_src", base + 0xb900, 24, 3, gpt1_sel, ARRAY_SIZE(gpt1_sel));
+ clks[IMX7D_GPT2_ROOT_SRC] = imx_clk_mux("gpt2_src", base + 0xb980, 24, 3, gpt2_sel, ARRAY_SIZE(gpt2_sel));
+ clks[IMX7D_GPT3_ROOT_SRC] = imx_clk_mux("gpt3_src", base + 0xba00, 24, 3, gpt3_sel, ARRAY_SIZE(gpt3_sel));
+ clks[IMX7D_GPT4_ROOT_SRC] = imx_clk_mux("gpt4_src", base + 0xba80, 24, 3, gpt4_sel, ARRAY_SIZE(gpt4_sel));
+ clks[IMX7D_TRACE_ROOT_SRC] = imx_clk_mux("trace_src", base + 0xbb00, 24, 3, trace_sel, ARRAY_SIZE(trace_sel));
+ clks[IMX7D_WDOG_ROOT_SRC] = imx_clk_mux("wdog_src", base + 0xbb80, 24, 3, wdog_sel, ARRAY_SIZE(wdog_sel));
+ clks[IMX7D_CSI_MCLK_ROOT_SRC] = imx_clk_mux("csi_mclk_src", base + 0xbc00, 24, 3, csi_mclk_sel, ARRAY_SIZE(csi_mclk_sel));
+ clks[IMX7D_AUDIO_MCLK_ROOT_SRC] = imx_clk_mux("audio_mclk_src", base + 0xbc80, 24, 3, audio_mclk_sel, ARRAY_SIZE(audio_mclk_sel));
+ clks[IMX7D_WRCLK_ROOT_SRC] = imx_clk_mux("wrclk_src", base + 0xbd00, 24, 3, wrclk_sel, ARRAY_SIZE(wrclk_sel));
+ clks[IMX7D_CLKO1_ROOT_SRC] = imx_clk_mux("clko1_src", base + 0xbd80, 24, 3, clko1_sel, ARRAY_SIZE(clko1_sel));
+ clks[IMX7D_CLKO2_ROOT_SRC] = imx_clk_mux("clko2_src", base + 0xbe00, 24, 3, clko2_sel, ARRAY_SIZE(clko2_sel));
+
+ clks[IMX7D_ARM_A7_ROOT_CG] = imx_clk_gate("arm_a7_cg", "arm_a7_src", base + 0x8000, 28);
+ clks[IMX7D_ARM_M4_ROOT_CG] = imx_clk_gate("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
+ clks[IMX7D_ARM_M0_ROOT_CG] = imx_clk_gate("arm_m0_cg", "arm_m0_src", base + 0x8100, 28);
+ clks[IMX7D_MAIN_AXI_ROOT_CG] = imx_clk_gate("axi_cg", "axi_src", base + 0x8800, 28);
+ clks[IMX7D_DISP_AXI_ROOT_CG] = imx_clk_gate("disp_axi_cg", "disp_axi_src", base + 0x8880, 28);
+ clks[IMX7D_ENET_AXI_ROOT_CG] = imx_clk_gate("enet_axi_cg", "enet_axi_src", base + 0x8900, 28);
+ clks[IMX7D_NAND_USDHC_BUS_ROOT_CG] = imx_clk_gate("nand_usdhc_cg", "nand_usdhc_src", base + 0x8980, 28);
+ clks[IMX7D_AHB_CHANNEL_ROOT_CG] = imx_clk_gate("ahb_cg", "ahb_src", base + 0x9000, 28);
+ clks[IMX7D_DRAM_PHYM_ROOT_CG] = imx_clk_gate("dram_phym_cg", "dram_phym_src", base + 0x9800, 28);
+ clks[IMX7D_DRAM_ROOT_CG] = imx_clk_gate("dram_cg", "dram_src", base + 0x9880, 28);
+ clks[IMX7D_DRAM_PHYM_ALT_ROOT_CG] = imx_clk_gate("dram_phym_alt_cg", "dram_phym_alt_src", base + 0xa000, 28);
+ clks[IMX7D_DRAM_ALT_ROOT_CG] = imx_clk_gate("dram_alt_cg", "dram_alt_src", base + 0xa080, 28);
+ clks[IMX7D_USB_HSIC_ROOT_CG] = imx_clk_gate("usb_hsic_cg", "usb_hsic_src", base + 0xa100, 28);
+ clks[IMX7D_PCIE_CTRL_ROOT_CG] = imx_clk_gate("pcie_ctrl_cg", "pcie_ctrl_src", base + 0xa180, 28);
+ clks[IMX7D_PCIE_PHY_ROOT_CG] = imx_clk_gate("pcie_phy_cg", "pcie_phy_src", base + 0xa200, 28);
+ clks[IMX7D_EPDC_PIXEL_ROOT_CG] = imx_clk_gate("epdc_pixel_cg", "epdc_pixel_src", base + 0xa280, 28);
+ clks[IMX7D_LCDIF_PIXEL_ROOT_CG] = imx_clk_gate("lcdif_pixel_cg", "lcdif_pixel_src", base + 0xa300, 28);
+ clks[IMX7D_MIPI_DSI_ROOT_CG] = imx_clk_gate("mipi_dsi_cg", "mipi_dsi_src", base + 0xa380, 28);
+ clks[IMX7D_MIPI_CSI_ROOT_CG] = imx_clk_gate("mipi_csi_cg", "mipi_csi_src", base + 0xa400, 28);
+ clks[IMX7D_MIPI_DPHY_ROOT_CG] = imx_clk_gate("mipi_dphy_cg", "mipi_dphy_src", base + 0xa480, 28);
+ clks[IMX7D_SAI1_ROOT_CG] = imx_clk_gate("sai1_cg", "sai1_src", base + 0xa500, 28);
+ clks[IMX7D_SAI2_ROOT_CG] = imx_clk_gate("sai2_cg", "sai2_src", base + 0xa580, 28);
+ clks[IMX7D_SAI3_ROOT_CG] = imx_clk_gate("sai3_cg", "sai3_src", base + 0xa600, 28);
+ clks[IMX7D_SPDIF_ROOT_CG] = imx_clk_gate("spdif_cg", "spdif_src", base + 0xa680, 28);
+ clks[IMX7D_ENET1_REF_ROOT_CG] = imx_clk_gate("enet1_ref_cg", "enet1_ref_src", base + 0xa700, 28);
+ clks[IMX7D_ENET1_TIME_ROOT_CG] = imx_clk_gate("enet1_time_cg", "enet1_time_src", base + 0xa780, 28);
+ clks[IMX7D_ENET2_REF_ROOT_CG] = imx_clk_gate("enet2_ref_cg", "enet2_ref_src", base + 0xa800, 28);
+ clks[IMX7D_ENET2_TIME_ROOT_CG] = imx_clk_gate("enet2_time_cg", "enet2_time_src", base + 0xa880, 28);
+ clks[IMX7D_ENET_PHY_REF_ROOT_CG] = imx_clk_gate("enet_phy_ref_cg", "enet_phy_ref_src", base + 0xa900, 28);
+ clks[IMX7D_EIM_ROOT_CG] = imx_clk_gate("eim_cg", "eim_src", base + 0xa980, 28);
+ clks[IMX7D_NAND_ROOT_CG] = imx_clk_gate("nand_cg", "nand_src", base + 0xaa00, 28);
+ clks[IMX7D_QSPI_ROOT_CG] = imx_clk_gate("qspi_cg", "qspi_src", base + 0xaa80, 28);
+ clks[IMX7D_USDHC1_ROOT_CG] = imx_clk_gate("usdhc1_cg", "usdhc1_src", base + 0xab00, 28);
+ clks[IMX7D_USDHC2_ROOT_CG] = imx_clk_gate("usdhc2_cg", "usdhc2_src", base + 0xab80, 28);
+ clks[IMX7D_USDHC3_ROOT_CG] = imx_clk_gate("usdhc3_cg", "usdhc3_src", base + 0xac00, 28);
+ clks[IMX7D_CAN1_ROOT_CG] = imx_clk_gate("can1_cg", "can1_src", base + 0xac80, 28);
+ clks[IMX7D_CAN2_ROOT_CG] = imx_clk_gate("can2_cg", "can2_src", base + 0xad00, 28);
+ clks[IMX7D_I2C1_ROOT_CG] = imx_clk_gate("i2c1_cg", "i2c1_src", base + 0xad80, 28);
+ clks[IMX7D_I2C2_ROOT_CG] = imx_clk_gate("i2c2_cg", "i2c2_src", base + 0xae00, 28);
+ clks[IMX7D_I2C3_ROOT_CG] = imx_clk_gate("i2c3_cg", "i2c3_src", base + 0xae80, 28);
+ clks[IMX7D_I2C4_ROOT_CG] = imx_clk_gate("i2c4_cg", "i2c4_src", base + 0xaf00, 28);
+ clks[IMX7D_UART1_ROOT_CG] = imx_clk_gate("uart1_cg", "uart1_src", base + 0xaf80, 28);
+ clks[IMX7D_UART2_ROOT_CG] = imx_clk_gate("uart2_cg", "uart2_src", base + 0xb000, 28);
+ clks[IMX7D_UART3_ROOT_CG] = imx_clk_gate("uart3_cg", "uart3_src", base + 0xb080, 28);
+ clks[IMX7D_UART4_ROOT_CG] = imx_clk_gate("uart4_cg", "uart4_src", base + 0xb100, 28);
+ clks[IMX7D_UART5_ROOT_CG] = imx_clk_gate("uart5_cg", "uart5_src", base + 0xb180, 28);
+ clks[IMX7D_UART6_ROOT_CG] = imx_clk_gate("uart6_cg", "uart6_src", base + 0xb200, 28);
+ clks[IMX7D_UART7_ROOT_CG] = imx_clk_gate("uart7_cg", "uart7_src", base + 0xb280, 28);
+ clks[IMX7D_ECSPI1_ROOT_CG] = imx_clk_gate("ecspi1_cg", "ecspi1_src", base + 0xb300, 28);
+ clks[IMX7D_ECSPI2_ROOT_CG] = imx_clk_gate("ecspi2_cg", "ecspi2_src", base + 0xb380, 28);
+ clks[IMX7D_ECSPI3_ROOT_CG] = imx_clk_gate("ecspi3_cg", "ecspi3_src", base + 0xb400, 28);
+ clks[IMX7D_ECSPI4_ROOT_CG] = imx_clk_gate("ecspi4_cg", "ecspi4_src", base + 0xb480, 28);
+ clks[IMX7D_PWM1_ROOT_CG] = imx_clk_gate("pwm1_cg", "pwm1_src", base + 0xb500, 28);
+ clks[IMX7D_PWM2_ROOT_CG] = imx_clk_gate("pwm2_cg", "pwm2_src", base + 0xb580, 28);
+ clks[IMX7D_PWM3_ROOT_CG] = imx_clk_gate("pwm3_cg", "pwm3_src", base + 0xb600, 28);
+ clks[IMX7D_PWM4_ROOT_CG] = imx_clk_gate("pwm4_cg", "pwm4_src", base + 0xb680, 28);
+ clks[IMX7D_FLEXTIMER1_ROOT_CG] = imx_clk_gate("flextimer1_cg", "flextimer1_src", base + 0xb700, 28);
+ clks[IMX7D_FLEXTIMER2_ROOT_CG] = imx_clk_gate("flextimer2_cg", "flextimer2_src", base + 0xb780, 28);
+ clks[IMX7D_SIM1_ROOT_CG] = imx_clk_gate("sim1_cg", "sim1_src", base + 0xb800, 28);
+ clks[IMX7D_SIM2_ROOT_CG] = imx_clk_gate("sim2_cg", "sim2_src", base + 0xb880, 28);
+ clks[IMX7D_GPT1_ROOT_CG] = imx_clk_gate("gpt1_cg", "gpt1_src", base + 0xb900, 28);
+ clks[IMX7D_GPT2_ROOT_CG] = imx_clk_gate("gpt2_cg", "gpt2_src", base + 0xb980, 28);
+ clks[IMX7D_GPT3_ROOT_CG] = imx_clk_gate("gpt3_cg", "gpt3_src", base + 0xbA00, 28);
+ clks[IMX7D_GPT4_ROOT_CG] = imx_clk_gate("gpt4_cg", "gpt4_src", base + 0xbA80, 28);
+ clks[IMX7D_TRACE_ROOT_CG] = imx_clk_gate("trace_cg", "trace_src", base + 0xbb00, 28);
+ clks[IMX7D_WDOG_ROOT_CG] = imx_clk_gate("wdog_cg", "wdog_src", base + 0xbb80, 28);
+ clks[IMX7D_CSI_MCLK_ROOT_CG] = imx_clk_gate("csi_mclk_cg", "csi_mclk_src", base + 0xbc00, 28);
+ clks[IMX7D_AUDIO_MCLK_ROOT_CG] = imx_clk_gate("audio_mclk_cg", "audio_mclk_src", base + 0xbc80, 28);
+ clks[IMX7D_WRCLK_ROOT_CG] = imx_clk_gate("wrclk_cg", "wrclk_src", base + 0xbd00, 28);
+ clks[IMX7D_CLKO1_ROOT_CG] = imx_clk_gate("clko1_cg", "clko1_src", base + 0xbd80, 28);
+ clks[IMX7D_CLKO2_ROOT_CG] = imx_clk_gate("clko2_cg", "clko2_src", base + 0xbe00, 28);
+
+ clks[IMX7D_MAIN_AXI_ROOT_PRE_DIV] = imx_clk_divider("axi_pre_div", "axi_cg", base + 0x8800, 16, 3);
+ clks[IMX7D_DISP_AXI_ROOT_PRE_DIV] = imx_clk_divider("disp_axi_pre_div", "disp_axi_cg", base + 0x8880, 16, 3);
+ clks[IMX7D_ENET_AXI_ROOT_PRE_DIV] = imx_clk_divider("enet_axi_pre_div", "enet_axi_cg", base + 0x8900, 16, 3);
+ clks[IMX7D_NAND_USDHC_BUS_ROOT_PRE_DIV] = imx_clk_divider("nand_usdhc_pre_div", "nand_usdhc_cg", base + 0x8980, 16, 3);
+ clks[IMX7D_AHB_CHANNEL_ROOT_PRE_DIV] = imx_clk_divider("ahb_pre_div", "ahb_cg", base + 0x9000, 16, 3);
+ clks[IMX7D_DRAM_PHYM_ALT_ROOT_PRE_DIV] = imx_clk_divider("dram_phym_alt_pre_div", "dram_phym_alt_cg", base + 0xa000, 16, 3);
+ clks[IMX7D_DRAM_ALT_ROOT_PRE_DIV] = imx_clk_divider("dram_alt_pre_div", "dram_alt_cg", base + 0xa080, 16, 3);
+ clks[IMX7D_USB_HSIC_ROOT_PRE_DIV] = imx_clk_divider("usb_hsic_pre_div", "usb_hsic_cg", base + 0xa100, 16, 3);
+ clks[IMX7D_PCIE_CTRL_ROOT_PRE_DIV] = imx_clk_divider("pcie_ctrl_pre_div", "pcie_ctrl_cg", base + 0xa180, 16, 3);
+ clks[IMX7D_PCIE_PHY_ROOT_PRE_DIV] = imx_clk_divider("pcie_phy_pre_div", "pcie_phy_cg", base + 0xa200, 16, 3);
+ clks[IMX7D_EPDC_PIXEL_ROOT_PRE_DIV] = imx_clk_divider("epdc_pixel_pre_div", "epdc_pixel_cg", base + 0xa280, 16, 3);
+ clks[IMX7D_LCDIF_PIXEL_ROOT_PRE_DIV] = imx_clk_divider("lcdif_pixel_pre_div", "lcdif_pixel_cg", base + 0xa300, 16, 3);
+ clks[IMX7D_MIPI_DSI_ROOT_PRE_DIV] = imx_clk_divider("mipi_dsi_pre_div", "mipi_dsi_cg", base + 0xa380, 16, 3);
+ clks[IMX7D_MIPI_CSI_ROOT_PRE_DIV] = imx_clk_divider("mipi_csi_pre_div", "mipi_csi_cg", base + 0xa400, 16, 3);
+ clks[IMX7D_MIPI_DPHY_ROOT_PRE_DIV] = imx_clk_divider("mipi_dphy_pre_div", "mipi_dphy_cg", base + 0xa480, 16, 3);
+ clks[IMX7D_SAI1_ROOT_PRE_DIV] = imx_clk_divider("sai1_pre_div", "sai1_cg", base + 0xa500, 16, 3);
+ clks[IMX7D_SAI2_ROOT_PRE_DIV] = imx_clk_divider("sai2_pre_div", "sai2_cg", base + 0xa580, 16, 3);
+ clks[IMX7D_SAI3_ROOT_PRE_DIV] = imx_clk_divider("sai3_pre_div", "sai3_cg", base + 0xa600, 16, 3);
+ clks[IMX7D_SPDIF_ROOT_PRE_DIV] = imx_clk_divider("spdif_pre_div", "spdif_cg", base + 0xa680, 16, 3);
+ clks[IMX7D_ENET1_REF_ROOT_PRE_DIV] = imx_clk_divider("enet1_ref_pre_div", "enet1_ref_cg", base + 0xa700, 16, 3);
+ clks[IMX7D_ENET1_TIME_ROOT_PRE_DIV] = imx_clk_divider("enet1_time_pre_div", "enet1_time_cg", base + 0xa780, 16, 3);
+ clks[IMX7D_ENET2_REF_ROOT_PRE_DIV] = imx_clk_divider("enet2_ref_pre_div", "enet2_ref_cg", base + 0xa800, 16, 3);
+ clks[IMX7D_ENET2_TIME_ROOT_PRE_DIV] = imx_clk_divider("enet2_time_pre_div", "enet2_time_cg", base + 0xa880, 16, 3);
+ clks[IMX7D_ENET_PHY_REF_ROOT_PRE_DIV] = imx_clk_divider("enet_phy_ref_pre_div", "enet_phy_ref_cg", base + 0xa900, 16, 3);
+ clks[IMX7D_EIM_ROOT_PRE_DIV] = imx_clk_divider("eim_pre_div", "eim_cg", base + 0xa980, 16, 3);
+ clks[IMX7D_NAND_ROOT_PRE_DIV] = imx_clk_divider("nand_pre_div", "nand_cg", base + 0xaa00, 16, 3);
+ clks[IMX7D_QSPI_ROOT_PRE_DIV] = imx_clk_divider("qspi_pre_div", "qspi_cg", base + 0xaa80, 16, 3);
+ clks[IMX7D_USDHC1_ROOT_PRE_DIV] = imx_clk_divider("usdhc1_pre_div", "usdhc1_cg", base + 0xab00, 16, 3);
+ clks[IMX7D_USDHC2_ROOT_PRE_DIV] = imx_clk_divider("usdhc2_pre_div", "usdhc2_cg", base + 0xab80, 16, 3);
+ clks[IMX7D_USDHC3_ROOT_PRE_DIV] = imx_clk_divider("usdhc3_pre_div", "usdhc3_cg", base + 0xac00, 16, 3);
+ clks[IMX7D_CAN1_ROOT_PRE_DIV] = imx_clk_divider("can1_pre_div", "can1_cg", base + 0xac80, 16, 3);
+ clks[IMX7D_CAN2_ROOT_PRE_DIV] = imx_clk_divider("can2_pre_div", "can2_cg", base + 0xad00, 16, 3);
+ clks[IMX7D_I2C1_ROOT_PRE_DIV] = imx_clk_divider("i2c1_pre_div", "i2c1_cg", base + 0xad80, 16, 3);
+ clks[IMX7D_I2C2_ROOT_PRE_DIV] = imx_clk_divider("i2c2_pre_div", "i2c2_cg", base + 0xae00, 16, 3);
+ clks[IMX7D_I2C3_ROOT_PRE_DIV] = imx_clk_divider("i2c3_pre_div", "i2c3_cg", base + 0xae80, 16, 3);
+ clks[IMX7D_I2C4_ROOT_PRE_DIV] = imx_clk_divider("i2c4_pre_div", "i2c4_cg", base + 0xaf00, 16, 3);
+ clks[IMX7D_UART1_ROOT_PRE_DIV] = imx_clk_divider("uart1_pre_div", "uart1_cg", base + 0xaf80, 16, 3);
+ clks[IMX7D_UART2_ROOT_PRE_DIV] = imx_clk_divider("uart2_pre_div", "uart2_cg", base + 0xb000, 16, 3);
+ clks[IMX7D_UART3_ROOT_PRE_DIV] = imx_clk_divider("uart3_pre_div", "uart3_cg", base + 0xb080, 16, 3);
+ clks[IMX7D_UART4_ROOT_PRE_DIV] = imx_clk_divider("uart4_pre_div", "uart4_cg", base + 0xb100, 16, 3);
+ clks[IMX7D_UART5_ROOT_PRE_DIV] = imx_clk_divider("uart5_pre_div", "uart5_cg", base + 0xb180, 16, 3);
+ clks[IMX7D_UART6_ROOT_PRE_DIV] = imx_clk_divider("uart6_pre_div", "uart6_cg", base + 0xb200, 16, 3);
+ clks[IMX7D_UART7_ROOT_PRE_DIV] = imx_clk_divider("uart7_pre_div", "uart7_cg", base + 0xb280, 16, 3);
+ clks[IMX7D_ECSPI1_ROOT_PRE_DIV] = imx_clk_divider("ecspi1_pre_div", "ecspi1_cg", base + 0xb300, 16, 3);
+ clks[IMX7D_ECSPI2_ROOT_PRE_DIV] = imx_clk_divider("ecspi2_pre_div", "ecspi2_cg", base + 0xb380, 16, 3);
+ clks[IMX7D_ECSPI3_ROOT_PRE_DIV] = imx_clk_divider("ecspi3_pre_div", "ecspi3_cg", base + 0xb400, 16, 3);
+ clks[IMX7D_ECSPI4_ROOT_PRE_DIV] = imx_clk_divider("ecspi4_pre_div", "ecspi4_cg", base + 0xb480, 16, 3);
+ clks[IMX7D_PWM1_ROOT_PRE_DIV] = imx_clk_divider("pwm1_pre_div", "pwm1_cg", base + 0xb500, 16, 3);
+ clks[IMX7D_PWM2_ROOT_PRE_DIV] = imx_clk_divider("pwm2_pre_div", "pwm2_cg", base + 0xb580, 16, 3);
+ clks[IMX7D_PWM3_ROOT_PRE_DIV] = imx_clk_divider("pwm3_pre_div", "pwm3_cg", base + 0xb600, 16, 3);
+ clks[IMX7D_PWM4_ROOT_PRE_DIV] = imx_clk_divider("pwm4_pre_div", "pwm4_cg", base + 0xb680, 16, 3);
+ clks[IMX7D_FLEXTIMER1_ROOT_PRE_DIV] = imx_clk_divider("flextimer1_pre_div", "flextimer1_cg", base + 0xb700, 16, 3);
+ clks[IMX7D_FLEXTIMER2_ROOT_PRE_DIV] = imx_clk_divider("flextimer2_pre_div", "flextimer2_cg", base + 0xb780, 16, 3);
+ clks[IMX7D_SIM1_ROOT_PRE_DIV] = imx_clk_divider("sim1_pre_div", "sim1_cg", base + 0xb800, 16, 3);
+ clks[IMX7D_SIM2_ROOT_PRE_DIV] = imx_clk_divider("sim2_pre_div", "sim2_cg", base + 0xb880, 16, 3);
+ clks[IMX7D_GPT1_ROOT_PRE_DIV] = imx_clk_divider("gpt1_pre_div", "gpt1_cg", base + 0xb900, 16, 3);
+ clks[IMX7D_GPT2_ROOT_PRE_DIV] = imx_clk_divider("gpt2_pre_div", "gpt2_cg", base + 0xb980, 16, 3);
+ clks[IMX7D_GPT3_ROOT_PRE_DIV] = imx_clk_divider("gpt3_pre_div", "gpt3_cg", base + 0xba00, 16, 3);
+ clks[IMX7D_GPT4_ROOT_PRE_DIV] = imx_clk_divider("gpt4_pre_div", "gpt4_cg", base + 0xba80, 16, 3);
+ clks[IMX7D_TRACE_ROOT_PRE_DIV] = imx_clk_divider("trace_pre_div", "trace_cg", base + 0xbb00, 16, 3);
+ clks[IMX7D_WDOG_ROOT_PRE_DIV] = imx_clk_divider("wdog_pre_div", "wdog_cg", base + 0xbb80, 16, 3);
+ clks[IMX7D_CSI_MCLK_ROOT_PRE_DIV] = imx_clk_divider("csi_mclk_pre_div", "csi_mclk_cg", base + 0xbc00, 16, 3);
+ clks[IMX7D_AUDIO_MCLK_ROOT_PRE_DIV] = imx_clk_divider("audio_mclk_pre_div", "audio_mclk_cg", base + 0xbc80, 16, 3);
+ clks[IMX7D_WRCLK_ROOT_PRE_DIV] = imx_clk_divider("wrclk_pre_div", "wrclk_cg", base + 0xbd00, 16, 3);
+ clks[IMX7D_CLKO1_ROOT_PRE_DIV] = imx_clk_divider("clko1_pre_div", "clko1_cg", base + 0xbd80, 16, 3);
+ clks[IMX7D_CLKO2_ROOT_PRE_DIV] = imx_clk_divider("clko2_pre_div", "clko2_cg", base + 0xbe00, 16, 3);
+
+ clks[IMX7D_ARM_A7_ROOT_DIV] = imx_clk_divider("arm_a7_div", "arm_a7_cg", base + 0x8000, 0, 3);
+ clks[IMX7D_ARM_M4_ROOT_DIV] = imx_clk_divider("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
+ clks[IMX7D_ARM_M0_ROOT_DIV] = imx_clk_divider("arm_m0_div", "arm_m0_cg", base + 0x8100, 0, 3);
+ clks[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_divider("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6);
+ clks[IMX7D_DISP_AXI_ROOT_DIV] = imx_clk_divider("disp_axi_post_div", "disp_axi_pre_div", base + 0x8880, 0, 6);
+ clks[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_divider("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6);
+ clks[IMX7D_NAND_USDHC_BUS_ROOT_DIV] = imx_clk_divider("nand_usdhc_post_div", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
+ clks[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_divider("ahb_post_div", "ahb_pre_div", base + 0x9000, 0, 6);
+ clks[IMX7D_DRAM_ROOT_DIV] = imx_clk_divider("dram_post_div", "dram_cg", base + 0x9880, 0, 3);
+ clks[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_divider("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3);
+ clks[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_divider("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3);
+ clks[IMX7D_USB_HSIC_ROOT_DIV] = imx_clk_divider("usb_hsic_post_div", "usb_hsic_pre_div", base + 0xa100, 0, 6);
+ clks[IMX7D_PCIE_CTRL_ROOT_DIV] = imx_clk_divider("pcie_ctrl_post_div", "pcie_ctrl_pre_div", base + 0xa180, 0, 6);
+ clks[IMX7D_PCIE_PHY_ROOT_DIV] = imx_clk_divider("pcie_phy_post_div", "pcie_phy_pre_div", base + 0xa200, 0, 6);
+ clks[IMX7D_EPDC_PIXEL_ROOT_DIV] = imx_clk_divider("epdc_pixel_post_div", "epdc_pixel_pre_div", base + 0xa280, 0, 6);
+ clks[IMX7D_LCDIF_PIXEL_ROOT_DIV] = imx_clk_divider("lcdif_pixel_post_div", "lcdif_pixel_pre_div", base + 0xa300, 0, 6);
+ clks[IMX7D_MIPI_DSI_ROOT_DIV] = imx_clk_divider("mipi_dsi_post_div", "mipi_dsi_pre_div", base + 0xa380, 0, 6);
+ clks[IMX7D_MIPI_CSI_ROOT_DIV] = imx_clk_divider("mipi_csi_post_div", "mipi_csi_pre_div", base + 0xa400, 0, 6);
+ clks[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_divider("mipi_dphy_post_div", "mipi_csi_dphy_div", base + 0xa480, 0, 6);
+ clks[IMX7D_SAI1_ROOT_DIV] = imx_clk_divider("sai1_post_div", "sai1_pre_div", base + 0xa500, 0, 6);
+ clks[IMX7D_SAI2_ROOT_DIV] = imx_clk_divider("sai2_post_div", "sai2_pre_div", base + 0xa580, 0, 6);
+ clks[IMX7D_SAI3_ROOT_DIV] = imx_clk_divider("sai3_post_div", "sai3_pre_div", base + 0xa600, 0, 6);
+ clks[IMX7D_SPDIF_ROOT_DIV] = imx_clk_divider("spdif_post_div", "spdif_pre_div", base + 0xa680, 0, 6);
+ clks[IMX7D_ENET1_REF_ROOT_DIV] = imx_clk_divider("enet1_ref_post_div", "enet1_ref_pre_div", base + 0xa700, 0, 6);
+ clks[IMX7D_ENET1_TIME_ROOT_DIV] = imx_clk_divider("enet1_time_post_div", "enet1_time_pre_div", base + 0xa780, 0, 6);
+ clks[IMX7D_ENET2_REF_ROOT_DIV] = imx_clk_divider("enet2_ref_post_div", "enet2_ref_pre_div", base + 0xa800, 0, 6);
+ clks[IMX7D_ENET2_TIME_ROOT_DIV] = imx_clk_divider("enet2_time_post_div", "enet2_time_pre_div", base + 0xa880, 0, 6);
+ clks[IMX7D_ENET_PHY_REF_ROOT_DIV] = imx_clk_divider("enet_phy_ref_post_div", "enet_phy_ref_pre_div", base + 0xa900, 0, 6);
+ clks[IMX7D_EIM_ROOT_DIV] = imx_clk_divider("eim_post_div", "eim_pre_div", base + 0xa980, 0, 6);
+ clks[IMX7D_NAND_ROOT_DIV] = imx_clk_divider("nand_post_div", "nand_pre_div", base + 0xaa00, 0, 6);
+ clks[IMX7D_QSPI_ROOT_DIV] = imx_clk_divider("qspi_post_div", "qspi_pre_div", base + 0xaa80, 0, 6);
+ clks[IMX7D_USDHC1_ROOT_DIV] = imx_clk_divider("usdhc1_post_div", "usdhc1_pre_div", base + 0xab00, 0, 6);
+ clks[IMX7D_USDHC2_ROOT_DIV] = imx_clk_divider("usdhc2_post_div", "usdhc2_pre_div", base + 0xab80, 0, 6);
+ clks[IMX7D_USDHC3_ROOT_DIV] = imx_clk_divider("usdhc3_post_div", "usdhc3_pre_div", base + 0xac00, 0, 6);
+ clks[IMX7D_CAN1_ROOT_DIV] = imx_clk_divider("can1_post_div", "can1_pre_div", base + 0xac80, 0, 6);
+ clks[IMX7D_CAN2_ROOT_DIV] = imx_clk_divider("can2_post_div", "can2_pre_div", base + 0xad00, 0, 6);
+ clks[IMX7D_I2C1_ROOT_DIV] = imx_clk_divider("i2c1_post_div", "i2c1_pre_div", base + 0xad80, 0, 6);
+ clks[IMX7D_I2C2_ROOT_DIV] = imx_clk_divider("i2c2_post_div", "i2c2_pre_div", base + 0xae00, 0, 6);
+ clks[IMX7D_I2C3_ROOT_DIV] = imx_clk_divider("i2c3_post_div", "i2c3_pre_div", base + 0xae80, 0, 6);
+ clks[IMX7D_I2C4_ROOT_DIV] = imx_clk_divider("i2c4_post_div", "i2c4_pre_div", base + 0xaf00, 0, 6);
+ clks[IMX7D_UART1_ROOT_DIV] = imx_clk_divider("uart1_post_div", "uart1_pre_div", base + 0xaf80, 0, 6);
+ clks[IMX7D_UART2_ROOT_DIV] = imx_clk_divider("uart2_post_div", "uart2_pre_div", base + 0xb000, 0, 6);
+ clks[IMX7D_UART3_ROOT_DIV] = imx_clk_divider("uart3_post_div", "uart3_pre_div", base + 0xb080, 0, 6);
+ clks[IMX7D_UART4_ROOT_DIV] = imx_clk_divider("uart4_post_div", "uart4_pre_div", base + 0xb100, 0, 6);
+ clks[IMX7D_UART5_ROOT_DIV] = imx_clk_divider("uart5_post_div", "uart5_pre_div", base + 0xb180, 0, 6);
+ clks[IMX7D_UART6_ROOT_DIV] = imx_clk_divider("uart6_post_div", "uart6_pre_div", base + 0xb200, 0, 6);
+ clks[IMX7D_UART7_ROOT_DIV] = imx_clk_divider("uart7_post_div", "uart7_pre_div", base + 0xb280, 0, 6);
+ clks[IMX7D_ECSPI1_ROOT_DIV] = imx_clk_divider("ecspi1_post_div", "ecspi1_pre_div", base + 0xb300, 0, 6);
+ clks[IMX7D_ECSPI2_ROOT_DIV] = imx_clk_divider("ecspi2_post_div", "ecspi2_pre_div", base + 0xb380, 0, 6);
+ clks[IMX7D_ECSPI3_ROOT_DIV] = imx_clk_divider("ecspi3_post_div", "ecspi3_pre_div", base + 0xb400, 0, 6);
+ clks[IMX7D_ECSPI4_ROOT_DIV] = imx_clk_divider("ecspi4_post_div", "ecspi4_pre_div", base + 0xb480, 0, 6);
+ clks[IMX7D_PWM1_ROOT_DIV] = imx_clk_divider("pwm1_post_div", "pwm1_pre_div", base + 0xb500, 0, 6);
+ clks[IMX7D_PWM2_ROOT_DIV] = imx_clk_divider("pwm2_post_div", "pwm2_pre_div", base + 0xb580, 0, 6);
+ clks[IMX7D_PWM3_ROOT_DIV] = imx_clk_divider("pwm3_post_div", "pwm3_pre_div", base + 0xb600, 0, 6);
+ clks[IMX7D_PWM4_ROOT_DIV] = imx_clk_divider("pwm4_post_div", "pwm4_pre_div", base + 0xb680, 0, 6);
+ clks[IMX7D_FLEXTIMER1_ROOT_DIV] = imx_clk_divider("flextimer1_post_div", "flextimer1_pre_div", base + 0xb700, 0, 6);
+ clks[IMX7D_FLEXTIMER2_ROOT_DIV] = imx_clk_divider("flextimer2_post_div", "flextimer2_pre_div", base + 0xb780, 0, 6);
+ clks[IMX7D_SIM1_ROOT_DIV] = imx_clk_divider("sim1_post_div", "sim1_pre_div", base + 0xb800, 0, 6);
+ clks[IMX7D_SIM2_ROOT_DIV] = imx_clk_divider("sim2_post_div", "sim2_pre_div", base + 0xb880, 0, 6);
+ clks[IMX7D_GPT1_ROOT_DIV] = imx_clk_divider("gpt1_post_div", "gpt1_pre_div", base + 0xb900, 0, 6);
+ clks[IMX7D_GPT2_ROOT_DIV] = imx_clk_divider("gpt2_post_div", "gpt2_pre_div", base + 0xb980, 0, 6);
+ clks[IMX7D_GPT3_ROOT_DIV] = imx_clk_divider("gpt3_post_div", "gpt3_pre_div", base + 0xba00, 0, 6);
+ clks[IMX7D_GPT4_ROOT_DIV] = imx_clk_divider("gpt4_post_div", "gpt4_pre_div", base + 0xba80, 0, 6);
+ clks[IMX7D_TRACE_ROOT_DIV] = imx_clk_divider("trace_post_div", "trace_pre_div", base + 0xbb00, 0, 6);
+ clks[IMX7D_WDOG_ROOT_DIV] = imx_clk_divider("wdog_post_div", "wdog_pre_div", base + 0xbb80, 0, 6);
+ clks[IMX7D_CSI_MCLK_ROOT_DIV] = imx_clk_divider("csi_mclk_post_div", "csi_mclk_pre_div", base + 0xbc00, 0, 6);
+ clks[IMX7D_AUDIO_MCLK_ROOT_DIV] = imx_clk_divider("audio_mclk_post_div", "audio_mclk_pre_div", base + 0xbc80, 0, 6);
+ clks[IMX7D_WRCLK_ROOT_DIV] = imx_clk_divider("wrclk_post_div", "wrclk_pre_div", base + 0xbd00, 0, 6);
+ clks[IMX7D_CLKO1_ROOT_DIV] = imx_clk_divider("clko1_post_div", "clko1_pre_div", base + 0xbd80, 0, 6);
+ clks[IMX7D_CLKO2_ROOT_DIV] = imx_clk_divider("clko2_post_div", "clko2_pre_div", base + 0xbe00, 0, 6);
+
+ clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate2("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0);
+ clks[IMX7D_ARM_M4_ROOT_CLK] = imx_clk_gate2("arm_m4_root_clk", "arm_m4_div", base + 0x4010, 0);
+ clks[IMX7D_ARM_M0_ROOT_CLK] = imx_clk_gate2("arm_m0_root_clk", "arm_m0_div", base + 0x4020, 0);
+ clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate2("main_axi_root_clk", "axi_post_div", base + 0x4040, 0);
+ clks[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_gate2("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0);
+ clks[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_gate2("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0);
+ clks[IMX7D_OCRAM_CLK] = imx_clk_gate2("ocram_clk", "axi_post_div", base + 0x4110, 0);
+ clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate2("ocram_s_clk", "ahb_post_div", base + 0x4120, 0);
+ clks[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_gate2("nand_usdhc_root_clk", "nand_usdhc_post_div", base + 0x4130, 0);
+ clks[IMX7D_AHB_CHANNEL_ROOT_CLK] = imx_clk_gate2("ahb_root_clk", "ahb_post_div", base + 0x4200, 0);
+ clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate2("dram_root_clk", "dram_post_div", base + 0x4130, 0);
+ clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate2("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0);
+ clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate2("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0);
+ clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate2("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0);
+ clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate2("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4420, 0);
+ clks[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_gate2("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0);
+ clks[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_gate2("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0);
+ clks[IMX7D_EPDC_PIXEL_ROOT_CLK] = imx_clk_gate2("epdc_pixel_root_clk", "epdc_pixel_post_div", base + 0x44a0, 0);
+ clks[IMX7D_LCDIF_PIXEL_ROOT_CLK] = imx_clk_gate2("lcdif_pixel_root_clk", "lcdif_pixel_post_div", base + 0x44b0, 0);
+ clks[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_gate2("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0);
+ clks[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_gate2("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0);
+ clks[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_gate2("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0);
+ clks[IMX7D_SAI1_ROOT_CLK] = imx_clk_gate2("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0);
+ clks[IMX7D_SAI2_ROOT_CLK] = imx_clk_gate2("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0);
+ clks[IMX7D_SAI3_ROOT_CLK] = imx_clk_gate2("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0);
+ clks[IMX7D_SPDIF_ROOT_CLK] = imx_clk_gate2("spdif_root_clk", "spdif_post_div", base + 0x44d0, 0);
+ clks[IMX7D_ENET1_REF_ROOT_CLK] = imx_clk_gate2("enet1_ref_root_clk", "enet1_ref_post_div", base + 0x44e0, 0);
+ clks[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_gate2("enet1_time_root_clk", "enet1_time_post_div", base + 0x44f0, 0);
+ clks[IMX7D_ENET2_REF_ROOT_CLK] = imx_clk_gate2("enet2_ref_root_clk", "enet2_ref_post_div", base + 0x4500, 0);
+ clks[IMX7D_ENET2_TIME_ROOT_CLK] = imx_clk_gate2("enet2_time_root_clk", "enet2_time_post_div", base + 0x4510, 0);
+ clks[IMX7D_ENET_PHY_REF_ROOT_CLK] = imx_clk_gate2("enet_phy_ref_root_clk", "enet_phy_ref_post_div", base + 0x4520, 0);
+ clks[IMX7D_EIM_ROOT_CLK] = imx_clk_gate2("eim_root_clk", "eim_post_div", base + 0x4160, 0);
+ clks[IMX7D_NAND_ROOT_CLK] = imx_clk_gate2("nand_root_clk", "nand_post_div", base + 0x4140, 0);
+ clks[IMX7D_QSPI_ROOT_CLK] = imx_clk_gate2("qspi_root_clk", "qspi_post_div", base + 0x4150, 0);
+ clks[IMX7D_USDHC1_ROOT_CLK] = imx_clk_gate2("usdhc1_root_clk", "usdhc1_post_div", base + 0x46c0, 0);
+ clks[IMX7D_USDHC2_ROOT_CLK] = imx_clk_gate2("usdhc2_root_clk", "usdhc2_post_div", base + 0x46d0, 0);
+ clks[IMX7D_USDHC3_ROOT_CLK] = imx_clk_gate2("usdhc3_root_clk", "usdhc3_post_div", base + 0x46e0, 0);
+ clks[IMX7D_CAN1_ROOT_CLK] = imx_clk_gate2("can1_root_clk", "can1_post_div", base + 0x4740, 0);
+ clks[IMX7D_CAN2_ROOT_CLK] = imx_clk_gate2("can2_root_clk", "can2_post_div", base + 0x4750, 0);
+ clks[IMX7D_I2C1_ROOT_CLK] = imx_clk_gate2("i2c1_root_clk", "i2c1_post_div", base + 0x4880, 0);
+ clks[IMX7D_I2C2_ROOT_CLK] = imx_clk_gate2("i2c2_root_clk", "i2c2_post_div", base + 0x4890, 0);
+ clks[IMX7D_I2C3_ROOT_CLK] = imx_clk_gate2("i2c3_root_clk", "i2c3_post_div", base + 0x48a0, 0);
+ clks[IMX7D_I2C4_ROOT_CLK] = imx_clk_gate2("i2c4_root_clk", "i2c4_post_div", base + 0x48b0, 0);
+ clks[IMX7D_UART1_ROOT_CLK] = imx_clk_gate2("uart1_root_clk", "uart1_post_div", base + 0x4940, 0);
+ clks[IMX7D_UART2_ROOT_CLK] = imx_clk_gate2("uart2_root_clk", "uart2_post_div", base + 0x4950, 0);
+ clks[IMX7D_UART3_ROOT_CLK] = imx_clk_gate2("uart3_root_clk", "uart3_post_div", base + 0x4960, 0);
+ clks[IMX7D_UART4_ROOT_CLK] = imx_clk_gate2("uart4_root_clk", "uart4_post_div", base + 0x4970, 0);
+ clks[IMX7D_UART5_ROOT_CLK] = imx_clk_gate2("uart5_root_clk", "uart5_post_div", base + 0x4980, 0);
+ clks[IMX7D_UART6_ROOT_CLK] = imx_clk_gate2("uart6_root_clk", "uart6_post_div", base + 0x4990, 0);
+ clks[IMX7D_UART7_ROOT_CLK] = imx_clk_gate2("uart7_root_clk", "uart7_post_div", base + 0x49a0, 0);
+ clks[IMX7D_ECSPI1_ROOT_CLK] = imx_clk_gate2("ecspi1_root_clk", "ecspi1_post_div", base + 0x4780, 0);
+ clks[IMX7D_ECSPI2_ROOT_CLK] = imx_clk_gate2("ecspi2_root_clk", "ecspi2_post_div", base + 0x4790, 0);
+ clks[IMX7D_ECSPI3_ROOT_CLK] = imx_clk_gate2("ecspi3_root_clk", "ecspi3_post_div", base + 0x47a0, 0);
+ clks[IMX7D_ECSPI4_ROOT_CLK] = imx_clk_gate2("ecspi4_root_clk", "ecspi4_post_div", base + 0x47b0, 0);
+ clks[IMX7D_PWM1_ROOT_CLK] = imx_clk_gate2("pwm1_root_clk", "pwm1_post_div", base + 0x4840, 0);
+ clks[IMX7D_PWM2_ROOT_CLK] = imx_clk_gate2("pwm2_root_clk", "pwm2_post_div", base + 0x4850, 0);
+ clks[IMX7D_PWM3_ROOT_CLK] = imx_clk_gate2("pwm3_root_clk", "pwm3_post_div", base + 0x4860, 0);
+ clks[IMX7D_PWM4_ROOT_CLK] = imx_clk_gate2("pwm4_root_clk", "pwm4_post_div", base + 0x4870, 0);
+ clks[IMX7D_FLEXTIMER1_ROOT_CLK] = imx_clk_gate2("flextimer1_root_clk", "flextimer1_post_div", base + 0x4800, 0);
+ clks[IMX7D_FLEXTIMER2_ROOT_CLK] = imx_clk_gate2("flextimer2_root_clk", "flextimer2_post_div", base + 0x4810, 0);
+ clks[IMX7D_SIM1_ROOT_CLK] = imx_clk_gate2("sim1_root_clk", "sim1_post_div", base + 0x4900, 0);
+ clks[IMX7D_SIM2_ROOT_CLK] = imx_clk_gate2("sim2_root_clk", "sim2_post_div", base + 0x4910, 0);
+ clks[IMX7D_GPT1_ROOT_CLK] = imx_clk_gate2("gpt1_root_clk", "gpt1_post_div", base + 0x47c0, 0);
+ clks[IMX7D_GPT2_ROOT_CLK] = imx_clk_gate2("gpt2_root_clk", "gpt2_post_div", base + 0x47d0, 0);
+ clks[IMX7D_GPT3_ROOT_CLK] = imx_clk_gate2("gpt3_root_clk", "gpt3_post_div", base + 0x47e0, 0);
+ clks[IMX7D_GPT4_ROOT_CLK] = imx_clk_gate2("gpt4_root_clk", "gpt4_post_div", base + 0x47f0, 0);
+ clks[IMX7D_TRACE_ROOT_CLK] = imx_clk_gate2("trace_root_clk", "trace_post_div", base + 0x4300, 0);
+ clks[IMX7D_WDOG1_ROOT_CLK] = imx_clk_gate2("wdog1_root_clk", "wdog_post_div", base + 0x49c0, 0);
+ clks[IMX7D_WDOG2_ROOT_CLK] = imx_clk_gate2("wdog2_root_clk", "wdog_post_div", base + 0x49d0, 0);
+ clks[IMX7D_WDOG3_ROOT_CLK] = imx_clk_gate2("wdog3_root_clk", "wdog_post_div", base + 0x49e0, 0);
+ clks[IMX7D_WDOG4_ROOT_CLK] = imx_clk_gate2("wdog4_root_clk", "wdog_post_div", base + 0x49f0, 0);
+ clks[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_gate2("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0);
+ clks[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_gate2("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0);
+ clks[IMX7D_WRCLK_ROOT_CLK] = imx_clk_gate2("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0);
+
+ 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]));
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+ /* TO BE FIXED LATER
+ * Enable all clock to bring up imx7, otherwise system will be halt and block
+ * the other part upstream Because imx7d clock design changed, clock framework
+ * need do a little modify.
+ * Dong Aisheng is working on this. After that, this part need be changed.
+ */
+ for (i = 0; i < IMX7D_CLK_END; i++)
+ clk_prepare_enable(clks[i]);
+
+ /* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
+ clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
+
+ /*
+ * init enet clock source:
+ * AXI clock source is 250MHz
+ * Phy refrence clock is 25MHz
+ * 1588 time clock source is 100MHz
+ */
+ clk_set_parent(clks[IMX7D_ENET_AXI_ROOT_SRC], clks[IMX7D_PLL_ENET_MAIN_250M_CLK]);
+ clk_set_parent(clks[IMX7D_ENET_PHY_REF_ROOT_SRC], clks[IMX7D_PLL_ENET_MAIN_25M_CLK]);
+ clk_set_parent(clks[IMX7D_ENET1_TIME_ROOT_SRC], clks[IMX7D_PLL_ENET_MAIN_100M_CLK]);
+ clk_set_parent(clks[IMX7D_ENET2_TIME_ROOT_SRC], clks[IMX7D_PLL_ENET_MAIN_100M_CLK]);
+
+ /* set uart module clock's parent clock source that must be great then 80MHz */
+ clk_set_parent(clks[IMX7D_UART1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
+
+}
+CLK_OF_DECLARE(imx7d, "fsl,imx7d-ccm", imx7d_clocks_init);
diff --git a/arch/arm/mach-imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c
index 0b0f6f66ec56..0b0f6f66ec56 100644
--- a/arch/arm/mach-imx/clk-pfd.c
+++ b/drivers/clk/imx/clk-pfd.c
diff --git a/arch/arm/mach-imx/clk-pllv1.c b/drivers/clk/imx/clk-pllv1.c
index d21d14ca46c1..c34ad8a611dd 100644
--- a/arch/arm/mach-imx/clk-pllv1.c
+++ b/drivers/clk/imx/clk-pllv1.c
@@ -6,8 +6,6 @@
#include <linux/err.h>
#include "clk.h"
-#include "common.h"
-#include "hardware.h"
/**
* pll v1
@@ -26,13 +24,29 @@
struct clk_pllv1 {
struct clk_hw hw;
void __iomem *base;
+ enum imx_pllv1_type type;
};
#define to_clk_pllv1(clk) (container_of(clk, struct clk_pllv1, clk))
-static inline bool mfn_is_negative(unsigned int mfn)
+static inline bool is_imx1_pllv1(struct clk_pllv1 *pll)
{
- return !cpu_is_mx1() && !cpu_is_mx21() && (mfn & MFN_SIGN);
+ return pll->type == IMX_PLLV1_IMX1;
+}
+
+static inline bool is_imx21_pllv1(struct clk_pllv1 *pll)
+{
+ return pll->type == IMX_PLLV1_IMX21;
+}
+
+static inline bool is_imx27_pllv1(struct clk_pllv1 *pll)
+{
+ return pll->type == IMX_PLLV1_IMX27;
+}
+
+static inline bool mfn_is_negative(struct clk_pllv1 *pll, unsigned int mfn)
+{
+ return !is_imx1_pllv1(pll) && !is_imx21_pllv1(pll) && (mfn & MFN_SIGN);
}
static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw,
@@ -71,8 +85,8 @@ static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw,
* 2's complements number.
* On i.MX27 the bit 9 is the sign bit.
*/
- if (mfn_is_negative(mfn)) {
- if (cpu_is_mx27())
+ if (mfn_is_negative(pll, mfn)) {
+ if (is_imx27_pllv1(pll))
mfn_abs = mfn & MFN_MASK;
else
mfn_abs = BIT(MFN_BITS) - mfn;
@@ -85,7 +99,7 @@ static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw,
do_div(ll, mfd + 1);
- if (mfn_is_negative(mfn))
+ if (mfn_is_negative(pll, mfn))
ll = -ll;
ll = (rate * mfi) + ll;
@@ -97,8 +111,8 @@ static struct clk_ops clk_pllv1_ops = {
.recalc_rate = clk_pllv1_recalc_rate,
};
-struct clk *imx_clk_pllv1(const char *name, const char *parent,
- void __iomem *base)
+struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name,
+ const char *parent, void __iomem *base)
{
struct clk_pllv1 *pll;
struct clk *clk;
@@ -109,6 +123,7 @@ struct clk *imx_clk_pllv1(const char *name, const char *parent,
return ERR_PTR(-ENOMEM);
pll->base = base;
+ pll->type = type;
init.name = name;
init.ops = &clk_pllv1_ops;
diff --git a/arch/arm/mach-imx/clk-pllv2.c b/drivers/clk/imx/clk-pllv2.c
index 20889d59b44d..20889d59b44d 100644
--- a/arch/arm/mach-imx/clk-pllv2.c
+++ b/drivers/clk/imx/clk-pllv2.c
diff --git a/arch/arm/mach-imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
index 641ebc508920..f0d15fb9d783 100644
--- a/arch/arm/mach-imx/clk-pllv3.c
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -24,12 +24,14 @@
#define BM_PLL_POWER (0x1 << 12)
#define BM_PLL_LOCK (0x1 << 31)
+#define IMX7_ENET_PLL_POWER (0x1 << 5)
/**
* struct clk_pllv3 - IMX PLL clock version 3
* @clk_hw: clock source
* @base: base address of PLL registers
* @powerup_set: set POWER bit to power up the PLL
+ * @powerdown: pll powerdown offset bit
* @div_mask: mask of divider bits
* @div_shift: shift of divider bits
*
@@ -40,6 +42,7 @@ struct clk_pllv3 {
struct clk_hw hw;
void __iomem *base;
bool powerup_set;
+ u32 powerdown;
u32 div_mask;
u32 div_shift;
};
@@ -49,7 +52,7 @@ struct clk_pllv3 {
static int clk_pllv3_wait_lock(struct clk_pllv3 *pll)
{
unsigned long timeout = jiffies + msecs_to_jiffies(10);
- u32 val = readl_relaxed(pll->base) & BM_PLL_POWER;
+ u32 val = readl_relaxed(pll->base) & pll->powerdown;
/* No need to wait for lock when pll is not powered up */
if ((pll->powerup_set && !val) || (!pll->powerup_set && val))
@@ -215,7 +218,7 @@ static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long max_rate = parent_rate * 54;
u32 div;
u32 mfn, mfd = 1000000;
- s64 temp64;
+ u64 temp64;
if (rate > max_rate)
rate = max_rate;
@@ -239,7 +242,7 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long max_rate = parent_rate * 54;
u32 val, div;
u32 mfn, mfd = 1000000;
- s64 temp64;
+ u64 temp64;
if (rate < min_rate || rate > max_rate)
return -EINVAL;
@@ -293,6 +296,8 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
if (!pll)
return ERR_PTR(-ENOMEM);
+ pll->powerdown = BM_PLL_POWER;
+
switch (type) {
case IMX_PLLV3_SYS:
ops = &clk_pllv3_sys_ops;
@@ -306,6 +311,8 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
case IMX_PLLV3_AV:
ops = &clk_pllv3_av_ops;
break;
+ case IMX_PLLV3_ENET_IMX7:
+ pll->powerdown = IMX7_ENET_PLL_POWER;
case IMX_PLLV3_ENET:
ops = &clk_pllv3_enet_ops;
break;
diff --git a/arch/arm/mach-imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c
index 61876ed6e11e..bff45ead7389 100644
--- a/arch/arm/mach-imx/clk-vf610.c
+++ b/drivers/clk/imx/clk-vf610.c
@@ -118,6 +118,7 @@ static struct clk_onecell_data clk_data;
static unsigned int const clks_init_on[] __initconst = {
VF610_CLK_SYS_BUS,
VF610_CLK_DDR_SEL,
+ VF610_CLK_DAP,
};
static struct clk * __init vf610_get_fixed_clock(
@@ -272,6 +273,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk[VF610_CLK_I2C0] = imx_clk_gate2("i2c0", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(6));
clk[VF610_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(7));
+ clk[VF610_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(6));
+ clk[VF610_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_bus", CCM_CCGR10, CCM_CCGRx_CGn(7));
clk[VF610_CLK_DSPI0] = imx_clk_gate2("dspi0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(12));
clk[VF610_CLK_DSPI1] = imx_clk_gate2("dspi1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(13));
@@ -383,6 +386,7 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk[VF610_CLK_DMAMUX3] = imx_clk_gate2("dmamux3", "platform_bus", CCM_CCGR6, CCM_CCGRx_CGn(2));
clk[VF610_CLK_SNVS] = imx_clk_gate2("snvs-rtc", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(7));
+ clk[VF610_CLK_DAP] = imx_clk_gate("dap", "platform_bus", CCM_CCSR, 24);
imx_check_clocks(clk, ARRAY_SIZE(clk));
diff --git a/arch/arm/mach-imx/clk.c b/drivers/clk/imx/clk.c
index df12b5307175..df12b5307175 100644
--- a/arch/arm/mach-imx/clk.c
+++ b/drivers/clk/imx/clk.c
diff --git a/arch/arm/mach-imx/clk.h b/drivers/clk/imx/clk.h
index 6a07903a28bc..1049b0c7d818 100644
--- a/arch/arm/mach-imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -10,8 +10,17 @@ void imx_check_clocks(struct clk *clks[], unsigned int count);
extern void imx_cscmr1_fixup(u32 *val);
-struct clk *imx_clk_pllv1(const char *name, const char *parent,
- void __iomem *base);
+enum imx_pllv1_type {
+ IMX_PLLV1_IMX1,
+ IMX_PLLV1_IMX21,
+ IMX_PLLV1_IMX25,
+ IMX_PLLV1_IMX27,
+ IMX_PLLV1_IMX31,
+ IMX_PLLV1_IMX35,
+};
+
+struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name,
+ const char *parent, void __iomem *base);
struct clk *imx_clk_pllv2(const char *name, const char *parent,
void __iomem *base);
@@ -23,6 +32,7 @@ enum imx_pllv3_type {
IMX_PLLV3_USB_VF610,
IMX_PLLV3_AV,
IMX_PLLV3_ENET,
+ IMX_PLLV3_ENET_IMX7,
};
struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c
index 5f9b54b024b9..9a31b77eed23 100644
--- a/drivers/clk/pxa/clk-pxa27x.c
+++ b/drivers/clk/pxa/clk-pxa27x.c
@@ -353,6 +353,34 @@ static u8 clk_pxa27x_memory_get_parent(struct clk_hw *hw)
PARENTS(clk_pxa27x_memory) = { "osc_13mhz", "system_bus", "run" };
MUX_RO_RATE_RO_OPS(clk_pxa27x_memory, "memory");
+#define DUMMY_CLK(_con_id, _dev_id, _parent) \
+ { .con_id = _con_id, .dev_id = _dev_id, .parent = _parent }
+struct dummy_clk {
+ const char *con_id;
+ const char *dev_id;
+ const char *parent;
+};
+static struct dummy_clk dummy_clks[] __initdata = {
+ DUMMY_CLK(NULL, "pxa27x-gpio", "osc_32_768khz"),
+ DUMMY_CLK(NULL, "sa1100-rtc", "osc_32_768khz"),
+ DUMMY_CLK("UARTCLK", "pxa2xx-ir", "STUART"),
+};
+
+static void __init pxa27x_dummy_clocks_init(void)
+{
+ struct clk *clk;
+ struct dummy_clk *d;
+ const char *name;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dummy_clks); i++) {
+ d = &dummy_clks[i];
+ name = d->dev_id ? d->dev_id : d->con_id;
+ clk = clk_register_fixed_factor(NULL, name, d->parent, 0, 1, 1);
+ clk_register_clkdev(clk, d->con_id, d->dev_id);
+ }
+}
+
static void __init pxa27x_base_clocks_init(void)
{
pxa27x_register_plls();
@@ -362,12 +390,12 @@ static void __init pxa27x_base_clocks_init(void)
clk_register_clk_pxa27x_lcd_base();
}
-static int __init pxa27x_clocks_init(void)
+int __init pxa27x_clocks_init(void)
{
pxa27x_base_clocks_init();
+ pxa27x_dummy_clocks_init();
return clk_pxa_cken_init(pxa27x_clocks, ARRAY_SIZE(pxa27x_clocks));
}
-postcore_initcall(pxa27x_clocks_init);
static void __init pxa27x_dt_clocks_init(struct device_node *np)
{
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c
index a50936a17376..563969942a1d 100644
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -140,12 +140,47 @@ static struct clk_regmap pll14_vote = {
},
};
+#define NSS_PLL_RATE(f, _l, _m, _n, i) \
+ { \
+ .freq = f, \
+ .l = _l, \
+ .m = _m, \
+ .n = _n, \
+ .ibits = i, \
+ }
+
+static struct pll_freq_tbl pll18_freq_tbl[] = {
+ NSS_PLL_RATE(550000000, 44, 0, 1, 0x01495625),
+ NSS_PLL_RATE(733000000, 58, 16, 25, 0x014b5625),
+};
+
+static struct clk_pll pll18 = {
+ .l_reg = 0x31a4,
+ .m_reg = 0x31a8,
+ .n_reg = 0x31ac,
+ .config_reg = 0x31b4,
+ .mode_reg = 0x31a0,
+ .status_reg = 0x31b8,
+ .status_bit = 16,
+ .post_div_shift = 16,
+ .post_div_width = 1,
+ .freq_tbl = pll18_freq_tbl,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pll18",
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
enum {
P_PXO,
P_PLL8,
P_PLL3,
P_PLL0,
P_CXO,
+ P_PLL14,
+ P_PLL18,
};
static const struct parent_map gcc_pxo_pll8_map[] = {
@@ -197,6 +232,22 @@ static const char *gcc_pxo_pll8_pll0_map[] = {
"pll0_vote",
};
+static const struct parent_map gcc_pxo_pll8_pll14_pll18_pll0_map[] = {
+ { P_PXO, 0 },
+ { P_PLL8, 4 },
+ { P_PLL0, 2 },
+ { P_PLL14, 5 },
+ { P_PLL18, 1 }
+};
+
+static const char *gcc_pxo_pll8_pll14_pll18_pll0[] = {
+ "pxo",
+ "pll8_vote",
+ "pll0_vote",
+ "pll14",
+ "pll18",
+};
+
static struct freq_tbl clk_tbl_gsbi_uart[] = {
{ 1843200, P_PLL8, 2, 6, 625 },
{ 3686400, P_PLL8, 2, 12, 625 },
@@ -2202,6 +2253,472 @@ static struct clk_branch ebi2_aon_clk = {
},
};
+static const struct freq_tbl clk_tbl_gmac[] = {
+ { 133000000, P_PLL0, 1, 50, 301 },
+ { 266000000, P_PLL0, 1, 127, 382 },
+ { }
+};
+
+static struct clk_dyn_rcg gmac_core1_src = {
+ .ns_reg[0] = 0x3cac,
+ .ns_reg[1] = 0x3cb0,
+ .md_reg[0] = 0x3ca4,
+ .md_reg[1] = 0x3ca8,
+ .bank_reg = 0x3ca0,
+ .mn[0] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .mn[1] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_gmac,
+ .clkr = {
+ .enable_reg = 0x3ca0,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core1_src",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch gmac_core1_clk = {
+ .halt_reg = 0x3c20,
+ .halt_bit = 4,
+ .hwcg_reg = 0x3cb4,
+ .hwcg_bit = 6,
+ .clkr = {
+ .enable_reg = 0x3cb4,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core1_clk",
+ .parent_names = (const char *[]){
+ "gmac_core1_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_dyn_rcg gmac_core2_src = {
+ .ns_reg[0] = 0x3ccc,
+ .ns_reg[1] = 0x3cd0,
+ .md_reg[0] = 0x3cc4,
+ .md_reg[1] = 0x3cc8,
+ .bank_reg = 0x3ca0,
+ .mn[0] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .mn[1] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_gmac,
+ .clkr = {
+ .enable_reg = 0x3cc0,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core2_src",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch gmac_core2_clk = {
+ .halt_reg = 0x3c20,
+ .halt_bit = 5,
+ .hwcg_reg = 0x3cd4,
+ .hwcg_bit = 6,
+ .clkr = {
+ .enable_reg = 0x3cd4,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core2_clk",
+ .parent_names = (const char *[]){
+ "gmac_core2_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_dyn_rcg gmac_core3_src = {
+ .ns_reg[0] = 0x3cec,
+ .ns_reg[1] = 0x3cf0,
+ .md_reg[0] = 0x3ce4,
+ .md_reg[1] = 0x3ce8,
+ .bank_reg = 0x3ce0,
+ .mn[0] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .mn[1] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_gmac,
+ .clkr = {
+ .enable_reg = 0x3ce0,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core3_src",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch gmac_core3_clk = {
+ .halt_reg = 0x3c20,
+ .halt_bit = 6,
+ .hwcg_reg = 0x3cf4,
+ .hwcg_bit = 6,
+ .clkr = {
+ .enable_reg = 0x3cf4,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core3_clk",
+ .parent_names = (const char *[]){
+ "gmac_core3_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_dyn_rcg gmac_core4_src = {
+ .ns_reg[0] = 0x3d0c,
+ .ns_reg[1] = 0x3d10,
+ .md_reg[0] = 0x3d04,
+ .md_reg[1] = 0x3d08,
+ .bank_reg = 0x3d00,
+ .mn[0] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .mn[1] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_gmac,
+ .clkr = {
+ .enable_reg = 0x3d00,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core4_src",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch gmac_core4_clk = {
+ .halt_reg = 0x3c20,
+ .halt_bit = 7,
+ .hwcg_reg = 0x3d14,
+ .hwcg_bit = 6,
+ .clkr = {
+ .enable_reg = 0x3d14,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gmac_core4_clk",
+ .parent_names = (const char *[]){
+ "gmac_core4_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static const struct freq_tbl clk_tbl_nss_tcm[] = {
+ { 266000000, P_PLL0, 3, 0, 0 },
+ { 400000000, P_PLL0, 2, 0, 0 },
+ { }
+};
+
+static struct clk_dyn_rcg nss_tcm_src = {
+ .ns_reg[0] = 0x3dc4,
+ .ns_reg[1] = 0x3dc8,
+ .bank_reg = 0x3dc0,
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 4,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 4,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_nss_tcm,
+ .clkr = {
+ .enable_reg = 0x3dc0,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "nss_tcm_src",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ },
+ },
+};
+
+static struct clk_branch nss_tcm_clk = {
+ .halt_reg = 0x3c20,
+ .halt_bit = 14,
+ .clkr = {
+ .enable_reg = 0x3dd0,
+ .enable_mask = BIT(6) | BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "nss_tcm_clk",
+ .parent_names = (const char *[]){
+ "nss_tcm_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static const struct freq_tbl clk_tbl_nss[] = {
+ { 110000000, P_PLL18, 1, 1, 5 },
+ { 275000000, P_PLL18, 2, 0, 0 },
+ { 550000000, P_PLL18, 1, 0, 0 },
+ { 733000000, P_PLL18, 1, 0, 0 },
+ { }
+};
+
+static struct clk_dyn_rcg ubi32_core1_src_clk = {
+ .ns_reg[0] = 0x3d2c,
+ .ns_reg[1] = 0x3d30,
+ .md_reg[0] = 0x3d24,
+ .md_reg[1] = 0x3d28,
+ .bank_reg = 0x3d20,
+ .mn[0] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .mn[1] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_nss,
+ .clkr = {
+ .enable_reg = 0x3d20,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "ubi32_core1_src_clk",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ },
+ },
+};
+
+static struct clk_dyn_rcg ubi32_core2_src_clk = {
+ .ns_reg[0] = 0x3d4c,
+ .ns_reg[1] = 0x3d50,
+ .md_reg[0] = 0x3d44,
+ .md_reg[1] = 0x3d48,
+ .bank_reg = 0x3d40,
+ .mn[0] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .mn[1] = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .s[0] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .s[1] = {
+ .src_sel_shift = 0,
+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
+ },
+ .p[0] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .p[1] = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .mux_sel_bit = 0,
+ .freq_tbl = clk_tbl_nss,
+ .clkr = {
+ .enable_reg = 0x3d40,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "ubi32_core2_src_clk",
+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
+ .num_parents = 5,
+ .ops = &clk_dyn_rcg_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ },
+ },
+};
+
static struct clk_regmap *gcc_ipq806x_clks[] = {
[PLL0] = &pll0.clkr,
[PLL0_VOTE] = &pll0_vote,
@@ -2211,6 +2728,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
[PLL8_VOTE] = &pll8_vote,
[PLL14] = &pll14.clkr,
[PLL14_VOTE] = &pll14_vote,
+ [PLL18] = &pll18.clkr,
[GSBI1_UART_SRC] = &gsbi1_uart_src.clkr,
[GSBI1_UART_CLK] = &gsbi1_uart_clk.clkr,
[GSBI2_UART_SRC] = &gsbi2_uart_src.clkr,
@@ -2307,6 +2825,18 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
[USB_FS1_SYSTEM_CLK] = &usb_fs1_sys_clk.clkr,
[EBI2_CLK] = &ebi2_clk.clkr,
[EBI2_AON_CLK] = &ebi2_aon_clk.clkr,
+ [GMAC_CORE1_CLK_SRC] = &gmac_core1_src.clkr,
+ [GMAC_CORE1_CLK] = &gmac_core1_clk.clkr,
+ [GMAC_CORE2_CLK_SRC] = &gmac_core2_src.clkr,
+ [GMAC_CORE2_CLK] = &gmac_core2_clk.clkr,
+ [GMAC_CORE3_CLK_SRC] = &gmac_core3_src.clkr,
+ [GMAC_CORE3_CLK] = &gmac_core3_clk.clkr,
+ [GMAC_CORE4_CLK_SRC] = &gmac_core4_src.clkr,
+ [GMAC_CORE4_CLK] = &gmac_core4_clk.clkr,
+ [UBI32_CORE1_CLK_SRC] = &ubi32_core1_src_clk.clkr,
+ [UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr,
+ [NSSTCM_CLK_SRC] = &nss_tcm_src.clkr,
+ [NSSTCM_CLK] = &nss_tcm_clk.clkr,
};
static const struct qcom_reset_map gcc_ipq806x_resets[] = {
@@ -2425,6 +2955,48 @@ static const struct qcom_reset_map gcc_ipq806x_resets[] = {
[USB30_1_PHY_RESET] = { 0x3b58, 0 },
[NSSFB0_RESET] = { 0x3b60, 6 },
[NSSFB1_RESET] = { 0x3b60, 7 },
+ [UBI32_CORE1_CLKRST_CLAMP_RESET] = { 0x3d3c, 3},
+ [UBI32_CORE1_CLAMP_RESET] = { 0x3d3c, 2 },
+ [UBI32_CORE1_AHB_RESET] = { 0x3d3c, 1 },
+ [UBI32_CORE1_AXI_RESET] = { 0x3d3c, 0 },
+ [UBI32_CORE2_CLKRST_CLAMP_RESET] = { 0x3d5c, 3 },
+ [UBI32_CORE2_CLAMP_RESET] = { 0x3d5c, 2 },
+ [UBI32_CORE2_AHB_RESET] = { 0x3d5c, 1 },
+ [UBI32_CORE2_AXI_RESET] = { 0x3d5c, 0 },
+ [GMAC_CORE1_RESET] = { 0x3cbc, 0 },
+ [GMAC_CORE2_RESET] = { 0x3cdc, 0 },
+ [GMAC_CORE3_RESET] = { 0x3cfc, 0 },
+ [GMAC_CORE4_RESET] = { 0x3d1c, 0 },
+ [GMAC_AHB_RESET] = { 0x3e24, 0 },
+ [NSS_CH0_RST_RX_CLK_N_RESET] = { 0x3b60, 0 },
+ [NSS_CH0_RST_TX_CLK_N_RESET] = { 0x3b60, 1 },
+ [NSS_CH0_RST_RX_125M_N_RESET] = { 0x3b60, 2 },
+ [NSS_CH0_HW_RST_RX_125M_N_RESET] = { 0x3b60, 3 },
+ [NSS_CH0_RST_TX_125M_N_RESET] = { 0x3b60, 4 },
+ [NSS_CH1_RST_RX_CLK_N_RESET] = { 0x3b60, 5 },
+ [NSS_CH1_RST_TX_CLK_N_RESET] = { 0x3b60, 6 },
+ [NSS_CH1_RST_RX_125M_N_RESET] = { 0x3b60, 7 },
+ [NSS_CH1_HW_RST_RX_125M_N_RESET] = { 0x3b60, 8 },
+ [NSS_CH1_RST_TX_125M_N_RESET] = { 0x3b60, 9 },
+ [NSS_CH2_RST_RX_CLK_N_RESET] = { 0x3b60, 10 },
+ [NSS_CH2_RST_TX_CLK_N_RESET] = { 0x3b60, 11 },
+ [NSS_CH2_RST_RX_125M_N_RESET] = { 0x3b60, 12 },
+ [NSS_CH2_HW_RST_RX_125M_N_RESET] = { 0x3b60, 13 },
+ [NSS_CH2_RST_TX_125M_N_RESET] = { 0x3b60, 14 },
+ [NSS_CH3_RST_RX_CLK_N_RESET] = { 0x3b60, 15 },
+ [NSS_CH3_RST_TX_CLK_N_RESET] = { 0x3b60, 16 },
+ [NSS_CH3_RST_RX_125M_N_RESET] = { 0x3b60, 17 },
+ [NSS_CH3_HW_RST_RX_125M_N_RESET] = { 0x3b60, 18 },
+ [NSS_CH3_RST_TX_125M_N_RESET] = { 0x3b60, 19 },
+ [NSS_RST_RX_250M_125M_N_RESET] = { 0x3b60, 20 },
+ [NSS_RST_TX_250M_125M_N_RESET] = { 0x3b60, 21 },
+ [NSS_QSGMII_TXPI_RST_N_RESET] = { 0x3b60, 22 },
+ [NSS_QSGMII_CDR_RST_N_RESET] = { 0x3b60, 23 },
+ [NSS_SGMII2_CDR_RST_N_RESET] = { 0x3b60, 24 },
+ [NSS_SGMII3_CDR_RST_N_RESET] = { 0x3b60, 25 },
+ [NSS_CAL_PRBS_RST_N_RESET] = { 0x3b60, 26 },
+ [NSS_LCKDT_RST_N_RESET] = { 0x3b60, 27 },
+ [NSS_SRDS_N_RESET] = { 0x3b60, 28 },
};
static const struct regmap_config gcc_ipq806x_regmap_config = {
@@ -2453,6 +3025,8 @@ 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);
@@ -2463,7 +3037,25 @@ static int gcc_ipq806x_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- return qcom_cc_probe(pdev, &gcc_ipq806x_desc);
+ ret = qcom_cc_probe(pdev, &gcc_ipq806x_desc);
+ if (ret)
+ return ret;
+
+ regmap = dev_get_regmap(dev, NULL);
+ if (!regmap)
+ return -ENODEV;
+
+ /* Setup PLL18 static bits */
+ regmap_update_bits(regmap, 0x31a4, 0xffffffc0, 0x40000400);
+ regmap_write(regmap, 0x31b0, 0x3080);
+
+ /* Set GMAC footswitch sleep/wakeup values */
+ regmap_write(regmap, 0x3cb8, 8);
+ regmap_write(regmap, 0x3cd8, 8);
+ regmap_write(regmap, 0x3cf8, 8);
+ regmap_write(regmap, 0x3d18, 8);
+
+ return 0;
}
static int gcc_ipq806x_remove(struct platform_device *pdev)
diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c
index 5d2217ae4478..63b8323df918 100644
--- a/drivers/clk/ti/clk-7xx.c
+++ b/drivers/clk/ti/clk-7xx.c
@@ -305,13 +305,14 @@ static struct ti_dt_clk dra7xx_clks[] = {
DT_CLK("4882c000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK("4882e000.timer", "timer_sys_ck", "timer_sys_clk_div"),
DT_CLK(NULL, "sys_clkin", "sys_clkin1"),
+ DT_CLK(NULL, "dss_deshdcp_clk", "dss_deshdcp_clk"),
{ .node_name = NULL },
};
int __init dra7xx_dt_clk_init(void)
{
int rc;
- struct clk *abe_dpll_mux, *sys_clkin2, *dpll_ck;
+ struct clk *abe_dpll_mux, *sys_clkin2, *dpll_ck, *hdcp_ck;
ti_dt_clocks_register(dra7xx_clks);
@@ -347,5 +348,10 @@ int __init dra7xx_dt_clk_init(void)
if (rc)
pr_err("%s: failed to set USB_DPLL M2 OUT\n", __func__);
+ hdcp_ck = clk_get_sys(NULL, "dss_deshdcp_clk");
+ rc = clk_prepare_enable(hdcp_ck);
+ if (rc)
+ pr_err("%s: failed to set dss_deshdcp_clk\n", __func__);
+
return rc;
}
diff --git a/drivers/clk/zte/Makefile b/drivers/clk/zte/Makefile
new file mode 100644
index 000000000000..95b707c18108
--- /dev/null
+++ b/drivers/clk/zte/Makefile
@@ -0,0 +1,2 @@
+obj-y := clk-pll.o
+obj-$(CONFIG_SOC_ZX296702) += clk-zx296702.o
diff --git a/drivers/clk/zte/clk-pll.c b/drivers/clk/zte/clk-pll.c
new file mode 100644
index 000000000000..c3b221ae6cd7
--- /dev/null
+++ b/drivers/clk/zte/clk-pll.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2014 Linaro Ltd.
+ * Copyright (C) 2014 ZTE 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/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "clk.h"
+
+#define to_clk_zx_pll(_hw) container_of(_hw, struct clk_zx_pll, hw)
+
+#define CFG0_CFG1_OFFSET 4
+#define LOCK_FLAG BIT(30)
+#define POWER_DOWN BIT(31)
+
+static int rate_to_idx(struct clk_zx_pll *zx_pll, unsigned long rate)
+{
+ const struct zx_pll_config *config = zx_pll->lookup_table;
+ int i;
+
+ for (i = 0; i < zx_pll->count; i++) {
+ if (config[i].rate > rate)
+ return i > 0 ? i - 1 : 0;
+
+ if (config[i].rate == rate)
+ return i;
+ }
+
+ return i - 1;
+}
+
+static int hw_to_idx(struct clk_zx_pll *zx_pll)
+{
+ const struct zx_pll_config *config = zx_pll->lookup_table;
+ u32 hw_cfg0, hw_cfg1;
+ int i;
+
+ hw_cfg0 = readl_relaxed(zx_pll->reg_base);
+ hw_cfg1 = readl_relaxed(zx_pll->reg_base + CFG0_CFG1_OFFSET);
+
+ /* For matching the value in lookup table */
+ hw_cfg0 &= ~LOCK_FLAG;
+ hw_cfg0 |= POWER_DOWN;
+
+ for (i = 0; i < zx_pll->count; i++) {
+ if (hw_cfg0 == config[i].cfg0 && hw_cfg1 == config[i].cfg1)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static unsigned long zx_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw);
+ int idx;
+
+ idx = hw_to_idx(zx_pll);
+ if (unlikely(idx == -EINVAL))
+ return 0;
+
+ return zx_pll->lookup_table[idx].rate;
+}
+
+static long zx_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw);
+ int idx;
+
+ idx = rate_to_idx(zx_pll, rate);
+
+ return zx_pll->lookup_table[idx].rate;
+}
+
+static int zx_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ /* Assume current cpu is not running on current PLL */
+ struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw);
+ const struct zx_pll_config *config;
+ int idx;
+
+ idx = rate_to_idx(zx_pll, rate);
+ config = &zx_pll->lookup_table[idx];
+
+ writel_relaxed(config->cfg0, zx_pll->reg_base);
+ writel_relaxed(config->cfg1, zx_pll->reg_base + CFG0_CFG1_OFFSET);
+
+ return 0;
+}
+
+static int zx_pll_enable(struct clk_hw *hw)
+{
+ struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw);
+ u32 reg;
+
+ reg = readl_relaxed(zx_pll->reg_base);
+ writel_relaxed(reg & ~POWER_DOWN, zx_pll->reg_base);
+
+ return readl_relaxed_poll_timeout(zx_pll->reg_base, reg,
+ reg & LOCK_FLAG, 0, 100);
+}
+
+static void zx_pll_disable(struct clk_hw *hw)
+{
+ struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw);
+ u32 reg;
+
+ reg = readl_relaxed(zx_pll->reg_base);
+ writel_relaxed(reg | POWER_DOWN, zx_pll->reg_base);
+}
+
+static int zx_pll_is_enabled(struct clk_hw *hw)
+{
+ struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw);
+ u32 reg;
+
+ reg = readl_relaxed(zx_pll->reg_base);
+
+ return !(reg & POWER_DOWN);
+}
+
+static const struct clk_ops zx_pll_ops = {
+ .recalc_rate = zx_pll_recalc_rate,
+ .round_rate = zx_pll_round_rate,
+ .set_rate = zx_pll_set_rate,
+ .enable = zx_pll_enable,
+ .disable = zx_pll_disable,
+ .is_enabled = zx_pll_is_enabled,
+};
+
+struct clk *clk_register_zx_pll(const char *name, const char *parent_name,
+ unsigned long flags, void __iomem *reg_base,
+ const struct zx_pll_config *lookup_table, int count, spinlock_t *lock)
+{
+ struct clk_zx_pll *zx_pll;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ zx_pll = kzalloc(sizeof(*zx_pll), GFP_KERNEL);
+ if (!zx_pll)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &zx_pll_ops;
+ init.flags = flags;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ zx_pll->reg_base = reg_base;
+ zx_pll->lookup_table = lookup_table;
+ zx_pll->count = count;
+ zx_pll->lock = lock;
+ zx_pll->hw.init = &init;
+
+ clk = clk_register(NULL, &zx_pll->hw);
+ if (IS_ERR(clk))
+ kfree(zx_pll);
+
+ return clk;
+}
diff --git a/drivers/clk/zte/clk-zx296702.c b/drivers/clk/zte/clk-zx296702.c
new file mode 100644
index 000000000000..929d033594af
--- /dev/null
+++ b/drivers/clk/zte/clk-zx296702.c
@@ -0,0 +1,657 @@
+/*
+ * Copyright 2014 Linaro Ltd.
+ * Copyright (C) 2014 ZTE 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/clk-provider.h>
+#include <linux/of_address.h>
+#include <dt-bindings/clock/zx296702-clock.h>
+#include "clk.h"
+
+static DEFINE_SPINLOCK(reg_lock);
+
+static void __iomem *topcrm_base;
+static void __iomem *lsp0crpm_base;
+static void __iomem *lsp1crpm_base;
+
+static struct clk *topclk[ZX296702_TOPCLK_END];
+static struct clk *lsp0clk[ZX296702_LSP0CLK_END];
+static struct clk *lsp1clk[ZX296702_LSP1CLK_END];
+
+static struct clk_onecell_data topclk_data;
+static struct clk_onecell_data lsp0clk_data;
+static struct clk_onecell_data lsp1clk_data;
+
+#define CLK_MUX (topcrm_base + 0x04)
+#define CLK_DIV (topcrm_base + 0x08)
+#define CLK_EN0 (topcrm_base + 0x0c)
+#define CLK_EN1 (topcrm_base + 0x10)
+#define VOU_LOCAL_CLKEN (topcrm_base + 0x68)
+#define VOU_LOCAL_CLKSEL (topcrm_base + 0x70)
+#define VOU_LOCAL_DIV2_SET (topcrm_base + 0x74)
+#define CLK_MUX1 (topcrm_base + 0x8c)
+
+#define CLK_SDMMC1 (lsp0crpm_base + 0x0c)
+
+#define CLK_UART0 (lsp1crpm_base + 0x20)
+#define CLK_UART1 (lsp1crpm_base + 0x24)
+#define CLK_SDMMC0 (lsp1crpm_base + 0x2c)
+
+static const struct zx_pll_config pll_a9_config[] = {
+ { .rate = 700000000, .cfg0 = 0x800405d1, .cfg1 = 0x04555555 },
+ { .rate = 800000000, .cfg0 = 0x80040691, .cfg1 = 0x04aaaaaa },
+ { .rate = 900000000, .cfg0 = 0x80040791, .cfg1 = 0x04000000 },
+ { .rate = 1000000000, .cfg0 = 0x80040851, .cfg1 = 0x04555555 },
+ { .rate = 1100000000, .cfg0 = 0x80040911, .cfg1 = 0x04aaaaaa },
+ { .rate = 1200000000, .cfg0 = 0x80040a11, .cfg1 = 0x04000000 },
+};
+
+static const struct clk_div_table main_hlk_div[] = {
+ { .val = 1, .div = 2, },
+ { .val = 3, .div = 4, },
+ { /* sentinel */ }
+};
+
+static const struct clk_div_table a9_as1_aclk_divider[] = {
+ { .val = 0, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 3, .div = 4, },
+ { /* sentinel */ }
+};
+
+static const struct clk_div_table sec_wclk_divider[] = {
+ { .val = 0, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 3, .div = 4, },
+ { .val = 5, .div = 6, },
+ { .val = 7, .div = 8, },
+ { /* sentinel */ }
+};
+
+static const char * matrix_aclk_sel[] = {
+ "pll_mm0_198M",
+ "osc",
+ "clk_148M5",
+ "pll_lsp_104M",
+};
+
+static const char * a9_wclk_sel[] = {
+ "pll_a9",
+ "osc",
+ "clk_500",
+ "clk_250",
+};
+
+static const char * a9_as1_aclk_sel[] = {
+ "clk_250",
+ "osc",
+ "pll_mm0_396M",
+ "pll_mac_333M",
+};
+
+static const char * a9_trace_clkin_sel[] = {
+ "clk_74M25",
+ "pll_mm1_108M",
+ "clk_125",
+ "clk_148M5",
+};
+
+static const char * decppu_aclk_sel[] = {
+ "clk_250",
+ "pll_mm0_198M",
+ "pll_lsp_104M",
+ "pll_audio_294M912",
+};
+
+static const char * vou_main_wclk_sel[] = {
+ "clk_148M5",
+ "clk_74M25",
+ "clk_27",
+ "pll_mm1_54M",
+};
+
+static const char * vou_scaler_wclk_sel[] = {
+ "clk_250",
+ "pll_mac_333M",
+ "pll_audio_294M912",
+ "pll_mm0_198M",
+};
+
+static const char * r2d_wclk_sel[] = {
+ "pll_audio_294M912",
+ "pll_mac_333M",
+ "pll_a9_350M",
+ "pll_mm0_396M",
+};
+
+static const char * ddr_wclk_sel[] = {
+ "pll_mac_333M",
+ "pll_ddr_266M",
+ "pll_audio_294M912",
+ "pll_mm0_198M",
+};
+
+static const char * nand_wclk_sel[] = {
+ "pll_lsp_104M",
+ "osc",
+};
+
+static const char * lsp_26_wclk_sel[] = {
+ "pll_lsp_26M",
+ "osc",
+};
+
+static const char * vl0_sel[] = {
+ "vou_main_channel_div",
+ "vou_aux_channel_div",
+};
+
+static const char * hdmi_sel[] = {
+ "vou_main_channel_wclk",
+ "vou_aux_channel_wclk",
+};
+
+static const char * sdmmc0_wclk_sel[] = {
+ "lsp1_104M_wclk",
+ "lsp1_26M_wclk",
+};
+
+static const char * sdmmc1_wclk_sel[] = {
+ "lsp0_104M_wclk",
+ "lsp0_26M_wclk",
+};
+
+static const char * uart_wclk_sel[] = {
+ "lsp1_104M_wclk",
+ "lsp1_26M_wclk",
+};
+
+static inline struct clk *zx_divtbl(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u8 width,
+ const struct clk_div_table *table)
+{
+ return clk_register_divider_table(NULL, name, parent, 0, reg, shift,
+ width, 0, table, &reg_lock);
+}
+
+static inline struct clk *zx_div(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u8 width)
+{
+ return clk_register_divider(NULL, name, parent, 0,
+ reg, shift, width, 0, &reg_lock);
+}
+
+static inline struct clk *zx_mux(const char *name, const char **parents,
+ int num_parents, void __iomem *reg, u8 shift, u8 width)
+{
+ return clk_register_mux(NULL, name, parents, num_parents,
+ 0, reg, shift, width, 0, &reg_lock);
+}
+
+static inline struct clk *zx_gate(const char *name, const char *parent,
+ void __iomem *reg, u8 shift)
+{
+ return clk_register_gate(NULL, name, parent, CLK_IGNORE_UNUSED,
+ reg, shift, 0, &reg_lock);
+}
+
+static void __init zx296702_top_clocks_init(struct device_node *np)
+{
+ struct clk **clk = topclk;
+ int i;
+
+ topcrm_base = of_iomap(np, 0);
+ WARN_ON(!topcrm_base);
+
+ clk[ZX296702_OSC] =
+ clk_register_fixed_rate(NULL, "osc", NULL, CLK_IS_ROOT,
+ 30000000);
+ clk[ZX296702_PLL_A9] =
+ clk_register_zx_pll("pll_a9", "osc", 0, topcrm_base
+ + 0x01c, pll_a9_config,
+ ARRAY_SIZE(pll_a9_config), &reg_lock);
+
+ /* TODO: pll_a9_350M look like changeble follow a9 pll */
+ clk[ZX296702_PLL_A9_350M] =
+ clk_register_fixed_rate(NULL, "pll_a9_350M", "osc", 0,
+ 350000000);
+ clk[ZX296702_PLL_MAC_1000M] =
+ clk_register_fixed_rate(NULL, "pll_mac_1000M", "osc", 0,
+ 1000000000);
+ clk[ZX296702_PLL_MAC_333M] =
+ clk_register_fixed_rate(NULL, "pll_mac_333M", "osc", 0,
+ 333000000);
+ clk[ZX296702_PLL_MM0_1188M] =
+ clk_register_fixed_rate(NULL, "pll_mm0_1188M", "osc", 0,
+ 1188000000);
+ clk[ZX296702_PLL_MM0_396M] =
+ clk_register_fixed_rate(NULL, "pll_mm0_396M", "osc", 0,
+ 396000000);
+ clk[ZX296702_PLL_MM0_198M] =
+ clk_register_fixed_rate(NULL, "pll_mm0_198M", "osc", 0,
+ 198000000);
+ clk[ZX296702_PLL_MM1_108M] =
+ clk_register_fixed_rate(NULL, "pll_mm1_108M", "osc", 0,
+ 108000000);
+ clk[ZX296702_PLL_MM1_72M] =
+ clk_register_fixed_rate(NULL, "pll_mm1_72M", "osc", 0,
+ 72000000);
+ clk[ZX296702_PLL_MM1_54M] =
+ clk_register_fixed_rate(NULL, "pll_mm1_54M", "osc", 0,
+ 54000000);
+ clk[ZX296702_PLL_LSP_104M] =
+ clk_register_fixed_rate(NULL, "pll_lsp_104M", "osc", 0,
+ 104000000);
+ clk[ZX296702_PLL_LSP_26M] =
+ clk_register_fixed_rate(NULL, "pll_lsp_26M", "osc", 0,
+ 26000000);
+ clk[ZX296702_PLL_DDR_266M] =
+ clk_register_fixed_rate(NULL, "pll_ddr_266M", "osc", 0,
+ 266000000);
+ clk[ZX296702_PLL_AUDIO_294M912] =
+ clk_register_fixed_rate(NULL, "pll_audio_294M912", "osc", 0,
+ 294912000);
+
+ /* bus clock */
+ clk[ZX296702_MATRIX_ACLK] =
+ zx_mux("matrix_aclk", matrix_aclk_sel,
+ ARRAY_SIZE(matrix_aclk_sel), CLK_MUX, 2, 2);
+ clk[ZX296702_MAIN_HCLK] =
+ zx_divtbl("main_hclk", "matrix_aclk", CLK_DIV, 0, 2,
+ main_hlk_div);
+ clk[ZX296702_MAIN_PCLK] =
+ zx_divtbl("main_pclk", "matrix_aclk", CLK_DIV, 2, 2,
+ main_hlk_div);
+
+ /* cpu clock */
+ clk[ZX296702_CLK_500] =
+ clk_register_fixed_factor(NULL, "clk_500", "pll_mac_1000M", 0,
+ 1, 2);
+ clk[ZX296702_CLK_250] =
+ clk_register_fixed_factor(NULL, "clk_250", "pll_mac_1000M", 0,
+ 1, 4);
+ clk[ZX296702_CLK_125] =
+ clk_register_fixed_factor(NULL, "clk_125", "clk_250", 0, 1, 2);
+ clk[ZX296702_CLK_148M5] =
+ clk_register_fixed_factor(NULL, "clk_148M5", "pll_mm0_1188M", 0,
+ 1, 8);
+ clk[ZX296702_CLK_74M25] =
+ clk_register_fixed_factor(NULL, "clk_74M25", "pll_mm0_1188M", 0,
+ 1, 16);
+ clk[ZX296702_A9_WCLK] =
+ zx_mux("a9_wclk", a9_wclk_sel, ARRAY_SIZE(a9_wclk_sel), CLK_MUX,
+ 0, 2);
+ clk[ZX296702_A9_AS1_ACLK_MUX] =
+ zx_mux("a9_as1_aclk_mux", a9_as1_aclk_sel,
+ ARRAY_SIZE(a9_as1_aclk_sel), CLK_MUX, 4, 2);
+ clk[ZX296702_A9_TRACE_CLKIN_MUX] =
+ zx_mux("a9_trace_clkin_mux", a9_trace_clkin_sel,
+ ARRAY_SIZE(a9_trace_clkin_sel), CLK_MUX1, 0, 2);
+ clk[ZX296702_A9_AS1_ACLK_DIV] =
+ zx_divtbl("a9_as1_aclk_div", "a9_as1_aclk_mux", CLK_DIV, 4, 2,
+ a9_as1_aclk_divider);
+
+ /* multi-media clock */
+ clk[ZX296702_CLK_2] =
+ clk_register_fixed_factor(NULL, "clk_2", "pll_mm1_72M", 0,
+ 1, 36);
+ clk[ZX296702_CLK_27] =
+ clk_register_fixed_factor(NULL, "clk_27", "pll_mm1_54M", 0,
+ 1, 2);
+ clk[ZX296702_DECPPU_ACLK_MUX] =
+ zx_mux("decppu_aclk_mux", decppu_aclk_sel,
+ ARRAY_SIZE(decppu_aclk_sel), CLK_MUX, 6, 2);
+ clk[ZX296702_PPU_ACLK_MUX] =
+ zx_mux("ppu_aclk_mux", decppu_aclk_sel,
+ ARRAY_SIZE(decppu_aclk_sel), CLK_MUX, 8, 2);
+ clk[ZX296702_MALI400_ACLK_MUX] =
+ zx_mux("mali400_aclk_mux", decppu_aclk_sel,
+ ARRAY_SIZE(decppu_aclk_sel), CLK_MUX, 12, 2);
+ clk[ZX296702_VOU_ACLK_MUX] =
+ zx_mux("vou_aclk_mux", decppu_aclk_sel,
+ ARRAY_SIZE(decppu_aclk_sel), CLK_MUX, 10, 2);
+ clk[ZX296702_VOU_MAIN_WCLK_MUX] =
+ zx_mux("vou_main_wclk_mux", vou_main_wclk_sel,
+ ARRAY_SIZE(vou_main_wclk_sel), CLK_MUX, 14, 2);
+ clk[ZX296702_VOU_AUX_WCLK_MUX] =
+ zx_mux("vou_aux_wclk_mux", vou_main_wclk_sel,
+ ARRAY_SIZE(vou_main_wclk_sel), CLK_MUX, 16, 2);
+ clk[ZX296702_VOU_SCALER_WCLK_MUX] =
+ zx_mux("vou_scaler_wclk_mux", vou_scaler_wclk_sel,
+ ARRAY_SIZE(vou_scaler_wclk_sel), CLK_MUX,
+ 18, 2);
+ clk[ZX296702_R2D_ACLK_MUX] =
+ zx_mux("r2d_aclk_mux", decppu_aclk_sel,
+ ARRAY_SIZE(decppu_aclk_sel), CLK_MUX, 20, 2);
+ clk[ZX296702_R2D_WCLK_MUX] =
+ zx_mux("r2d_wclk_mux", r2d_wclk_sel,
+ ARRAY_SIZE(r2d_wclk_sel), CLK_MUX, 22, 2);
+
+ /* other clock */
+ clk[ZX296702_CLK_50] =
+ clk_register_fixed_factor(NULL, "clk_50", "pll_mac_1000M",
+ 0, 1, 20);
+ clk[ZX296702_CLK_25] =
+ clk_register_fixed_factor(NULL, "clk_25", "pll_mac_1000M",
+ 0, 1, 40);
+ clk[ZX296702_CLK_12] =
+ clk_register_fixed_factor(NULL, "clk_12", "pll_mm1_72M",
+ 0, 1, 6);
+ clk[ZX296702_CLK_16M384] =
+ clk_register_fixed_factor(NULL, "clk_16M384",
+ "pll_audio_294M912", 0, 1, 18);
+ clk[ZX296702_CLK_32K768] =
+ clk_register_fixed_factor(NULL, "clk_32K768", "clk_16M384",
+ 0, 1, 500);
+ clk[ZX296702_SEC_WCLK_DIV] =
+ zx_divtbl("sec_wclk_div", "pll_lsp_104M", CLK_DIV, 6, 3,
+ sec_wclk_divider);
+ clk[ZX296702_DDR_WCLK_MUX] =
+ zx_mux("ddr_wclk_mux", ddr_wclk_sel,
+ ARRAY_SIZE(ddr_wclk_sel), CLK_MUX, 24, 2);
+ clk[ZX296702_NAND_WCLK_MUX] =
+ zx_mux("nand_wclk_mux", nand_wclk_sel,
+ ARRAY_SIZE(nand_wclk_sel), CLK_MUX, 24, 2);
+ clk[ZX296702_LSP_26_WCLK_MUX] =
+ zx_mux("lsp_26_wclk_mux", lsp_26_wclk_sel,
+ ARRAY_SIZE(lsp_26_wclk_sel), CLK_MUX, 27, 1);
+
+ /* gates */
+ clk[ZX296702_A9_AS0_ACLK] =
+ zx_gate("a9_as0_aclk", "matrix_aclk", CLK_EN0, 0);
+ clk[ZX296702_A9_AS1_ACLK] =
+ zx_gate("a9_as1_aclk", "a9_as1_aclk_div", CLK_EN0, 1);
+ clk[ZX296702_A9_TRACE_CLKIN] =
+ zx_gate("a9_trace_clkin", "a9_trace_clkin_mux", CLK_EN0, 2);
+ clk[ZX296702_DECPPU_AXI_M_ACLK] =
+ zx_gate("decppu_axi_m_aclk", "decppu_aclk_mux", CLK_EN0, 3);
+ clk[ZX296702_DECPPU_AHB_S_HCLK] =
+ zx_gate("decppu_ahb_s_hclk", "main_hclk", CLK_EN0, 4);
+ clk[ZX296702_PPU_AXI_M_ACLK] =
+ zx_gate("ppu_axi_m_aclk", "ppu_aclk_mux", CLK_EN0, 5);
+ clk[ZX296702_PPU_AHB_S_HCLK] =
+ zx_gate("ppu_ahb_s_hclk", "main_hclk", CLK_EN0, 6);
+ clk[ZX296702_VOU_AXI_M_ACLK] =
+ zx_gate("vou_axi_m_aclk", "vou_aclk_mux", CLK_EN0, 7);
+ clk[ZX296702_VOU_APB_PCLK] =
+ zx_gate("vou_apb_pclk", "main_pclk", CLK_EN0, 8);
+ clk[ZX296702_VOU_MAIN_CHANNEL_WCLK] =
+ zx_gate("vou_main_channel_wclk", "vou_main_wclk_mux",
+ CLK_EN0, 9);
+ clk[ZX296702_VOU_AUX_CHANNEL_WCLK] =
+ zx_gate("vou_aux_channel_wclk", "vou_aux_wclk_mux",
+ CLK_EN0, 10);
+ clk[ZX296702_VOU_HDMI_OSCLK_CEC] =
+ zx_gate("vou_hdmi_osclk_cec", "clk_2", CLK_EN0, 11);
+ clk[ZX296702_VOU_SCALER_WCLK] =
+ zx_gate("vou_scaler_wclk", "vou_scaler_wclk_mux", CLK_EN0, 12);
+ clk[ZX296702_MALI400_AXI_M_ACLK] =
+ zx_gate("mali400_axi_m_aclk", "mali400_aclk_mux", CLK_EN0, 13);
+ clk[ZX296702_MALI400_APB_PCLK] =
+ zx_gate("mali400_apb_pclk", "main_pclk", CLK_EN0, 14);
+ clk[ZX296702_R2D_WCLK] =
+ zx_gate("r2d_wclk", "r2d_wclk_mux", CLK_EN0, 15);
+ clk[ZX296702_R2D_AXI_M_ACLK] =
+ zx_gate("r2d_axi_m_aclk", "r2d_aclk_mux", CLK_EN0, 16);
+ clk[ZX296702_R2D_AHB_HCLK] =
+ zx_gate("r2d_ahb_hclk", "main_hclk", CLK_EN0, 17);
+ clk[ZX296702_DDR3_AXI_S0_ACLK] =
+ zx_gate("ddr3_axi_s0_aclk", "matrix_aclk", CLK_EN0, 18);
+ clk[ZX296702_DDR3_APB_PCLK] =
+ zx_gate("ddr3_apb_pclk", "main_pclk", CLK_EN0, 19);
+ clk[ZX296702_DDR3_WCLK] =
+ zx_gate("ddr3_wclk", "ddr_wclk_mux", CLK_EN0, 20);
+ clk[ZX296702_USB20_0_AHB_HCLK] =
+ zx_gate("usb20_0_ahb_hclk", "main_hclk", CLK_EN0, 21);
+ clk[ZX296702_USB20_0_EXTREFCLK] =
+ zx_gate("usb20_0_extrefclk", "clk_12", CLK_EN0, 22);
+ clk[ZX296702_USB20_1_AHB_HCLK] =
+ zx_gate("usb20_1_ahb_hclk", "main_hclk", CLK_EN0, 23);
+ clk[ZX296702_USB20_1_EXTREFCLK] =
+ zx_gate("usb20_1_extrefclk", "clk_12", CLK_EN0, 24);
+ clk[ZX296702_USB20_2_AHB_HCLK] =
+ zx_gate("usb20_2_ahb_hclk", "main_hclk", CLK_EN0, 25);
+ clk[ZX296702_USB20_2_EXTREFCLK] =
+ zx_gate("usb20_2_extrefclk", "clk_12", CLK_EN0, 26);
+ clk[ZX296702_GMAC_AXI_M_ACLK] =
+ zx_gate("gmac_axi_m_aclk", "matrix_aclk", CLK_EN0, 27);
+ clk[ZX296702_GMAC_APB_PCLK] =
+ zx_gate("gmac_apb_pclk", "main_pclk", CLK_EN0, 28);
+ clk[ZX296702_GMAC_125_CLKIN] =
+ zx_gate("gmac_125_clkin", "clk_125", CLK_EN0, 29);
+ clk[ZX296702_GMAC_RMII_CLKIN] =
+ zx_gate("gmac_rmii_clkin", "clk_50", CLK_EN0, 30);
+ clk[ZX296702_GMAC_25M_CLK] =
+ zx_gate("gmac_25M_clk", "clk_25", CLK_EN0, 31);
+ clk[ZX296702_NANDFLASH_AHB_HCLK] =
+ zx_gate("nandflash_ahb_hclk", "main_hclk", CLK_EN1, 0);
+ clk[ZX296702_NANDFLASH_WCLK] =
+ zx_gate("nandflash_wclk", "nand_wclk_mux", CLK_EN1, 1);
+ clk[ZX296702_LSP0_APB_PCLK] =
+ zx_gate("lsp0_apb_pclk", "main_pclk", CLK_EN1, 2);
+ clk[ZX296702_LSP0_AHB_HCLK] =
+ zx_gate("lsp0_ahb_hclk", "main_hclk", CLK_EN1, 3);
+ clk[ZX296702_LSP0_26M_WCLK] =
+ zx_gate("lsp0_26M_wclk", "lsp_26_wclk_mux", CLK_EN1, 4);
+ clk[ZX296702_LSP0_104M_WCLK] =
+ zx_gate("lsp0_104M_wclk", "pll_lsp_104M", CLK_EN1, 5);
+ clk[ZX296702_LSP0_16M384_WCLK] =
+ zx_gate("lsp0_16M384_wclk", "clk_16M384", CLK_EN1, 6);
+ clk[ZX296702_LSP1_APB_PCLK] =
+ zx_gate("lsp1_apb_pclk", "main_pclk", CLK_EN1, 7);
+ /* FIXME: wclk enable bit is bit8. We hack it as reserved 31 for
+ * UART does not work after parent clk is disabled/enabled */
+ clk[ZX296702_LSP1_26M_WCLK] =
+ zx_gate("lsp1_26M_wclk", "lsp_26_wclk_mux", CLK_EN1, 31);
+ clk[ZX296702_LSP1_104M_WCLK] =
+ zx_gate("lsp1_104M_wclk", "pll_lsp_104M", CLK_EN1, 9);
+ clk[ZX296702_LSP1_32K_CLK] =
+ zx_gate("lsp1_32K_clk", "clk_32K768", CLK_EN1, 10);
+ clk[ZX296702_AON_HCLK] =
+ zx_gate("aon_hclk", "main_hclk", CLK_EN1, 11);
+ clk[ZX296702_SYS_CTRL_PCLK] =
+ zx_gate("sys_ctrl_pclk", "main_pclk", CLK_EN1, 12);
+ clk[ZX296702_DMA_PCLK] =
+ zx_gate("dma_pclk", "main_pclk", CLK_EN1, 13);
+ clk[ZX296702_DMA_ACLK] =
+ zx_gate("dma_aclk", "matrix_aclk", CLK_EN1, 14);
+ clk[ZX296702_SEC_HCLK] =
+ zx_gate("sec_hclk", "main_hclk", CLK_EN1, 15);
+ clk[ZX296702_AES_WCLK] =
+ zx_gate("aes_wclk", "sec_wclk_div", CLK_EN1, 16);
+ clk[ZX296702_DES_WCLK] =
+ zx_gate("des_wclk", "sec_wclk_div", CLK_EN1, 17);
+ clk[ZX296702_IRAM_ACLK] =
+ zx_gate("iram_aclk", "matrix_aclk", CLK_EN1, 18);
+ clk[ZX296702_IROM_ACLK] =
+ zx_gate("irom_aclk", "matrix_aclk", CLK_EN1, 19);
+ clk[ZX296702_BOOT_CTRL_HCLK] =
+ zx_gate("boot_ctrl_hclk", "main_hclk", CLK_EN1, 20);
+ clk[ZX296702_EFUSE_CLK_30] =
+ zx_gate("efuse_clk_30", "osc", CLK_EN1, 21);
+
+ /* TODO: add VOU Local clocks */
+ clk[ZX296702_VOU_MAIN_CHANNEL_DIV] =
+ zx_div("vou_main_channel_div", "vou_main_channel_wclk",
+ VOU_LOCAL_DIV2_SET, 1, 1);
+ clk[ZX296702_VOU_AUX_CHANNEL_DIV] =
+ zx_div("vou_aux_channel_div", "vou_aux_channel_wclk",
+ VOU_LOCAL_DIV2_SET, 0, 1);
+ clk[ZX296702_VOU_TV_ENC_HD_DIV] =
+ zx_div("vou_tv_enc_hd_div", "vou_tv_enc_hd_mux",
+ VOU_LOCAL_DIV2_SET, 3, 1);
+ clk[ZX296702_VOU_TV_ENC_SD_DIV] =
+ zx_div("vou_tv_enc_sd_div", "vou_tv_enc_sd_mux",
+ VOU_LOCAL_DIV2_SET, 2, 1);
+ clk[ZX296702_VL0_MUX] =
+ zx_mux("vl0_mux", vl0_sel, ARRAY_SIZE(vl0_sel),
+ VOU_LOCAL_CLKSEL, 8, 1);
+ clk[ZX296702_VL1_MUX] =
+ zx_mux("vl1_mux", vl0_sel, ARRAY_SIZE(vl0_sel),
+ VOU_LOCAL_CLKSEL, 9, 1);
+ clk[ZX296702_VL2_MUX] =
+ zx_mux("vl2_mux", vl0_sel, ARRAY_SIZE(vl0_sel),
+ VOU_LOCAL_CLKSEL, 10, 1);
+ clk[ZX296702_GL0_MUX] =
+ zx_mux("gl0_mux", vl0_sel, ARRAY_SIZE(vl0_sel),
+ VOU_LOCAL_CLKSEL, 5, 1);
+ clk[ZX296702_GL1_MUX] =
+ zx_mux("gl1_mux", vl0_sel, ARRAY_SIZE(vl0_sel),
+ VOU_LOCAL_CLKSEL, 6, 1);
+ clk[ZX296702_GL2_MUX] =
+ zx_mux("gl2_mux", vl0_sel, ARRAY_SIZE(vl0_sel),
+ VOU_LOCAL_CLKSEL, 7, 1);
+ clk[ZX296702_WB_MUX] =
+ zx_mux("wb_mux", vl0_sel, ARRAY_SIZE(vl0_sel),
+ VOU_LOCAL_CLKSEL, 11, 1);
+ clk[ZX296702_HDMI_MUX] =
+ zx_mux("hdmi_mux", hdmi_sel, ARRAY_SIZE(hdmi_sel),
+ VOU_LOCAL_CLKSEL, 4, 1);
+ clk[ZX296702_VOU_TV_ENC_HD_MUX] =
+ zx_mux("vou_tv_enc_hd_mux", hdmi_sel, ARRAY_SIZE(hdmi_sel),
+ VOU_LOCAL_CLKSEL, 3, 1);
+ clk[ZX296702_VOU_TV_ENC_SD_MUX] =
+ zx_mux("vou_tv_enc_sd_mux", hdmi_sel, ARRAY_SIZE(hdmi_sel),
+ VOU_LOCAL_CLKSEL, 2, 1);
+ clk[ZX296702_VL0_CLK] =
+ zx_gate("vl0_clk", "vl0_mux", VOU_LOCAL_CLKEN, 8);
+ clk[ZX296702_VL1_CLK] =
+ zx_gate("vl1_clk", "vl1_mux", VOU_LOCAL_CLKEN, 9);
+ clk[ZX296702_VL2_CLK] =
+ zx_gate("vl2_clk", "vl2_mux", VOU_LOCAL_CLKEN, 10);
+ clk[ZX296702_GL0_CLK] =
+ zx_gate("gl0_clk", "gl0_mux", VOU_LOCAL_CLKEN, 5);
+ clk[ZX296702_GL1_CLK] =
+ zx_gate("gl1_clk", "gl1_mux", VOU_LOCAL_CLKEN, 6);
+ clk[ZX296702_GL2_CLK] =
+ zx_gate("gl2_clk", "gl2_mux", VOU_LOCAL_CLKEN, 7);
+ clk[ZX296702_WB_CLK] =
+ zx_gate("wb_clk", "wb_mux", VOU_LOCAL_CLKEN, 11);
+ clk[ZX296702_CL_CLK] =
+ zx_gate("cl_clk", "vou_main_channel_div", VOU_LOCAL_CLKEN, 12);
+ clk[ZX296702_MAIN_MIX_CLK] =
+ zx_gate("main_mix_clk", "vou_main_channel_div",
+ VOU_LOCAL_CLKEN, 4);
+ clk[ZX296702_AUX_MIX_CLK] =
+ zx_gate("aux_mix_clk", "vou_aux_channel_div",
+ VOU_LOCAL_CLKEN, 3);
+ clk[ZX296702_HDMI_CLK] =
+ zx_gate("hdmi_clk", "hdmi_mux", VOU_LOCAL_CLKEN, 2);
+ clk[ZX296702_VOU_TV_ENC_HD_DAC_CLK] =
+ zx_gate("vou_tv_enc_hd_dac_clk", "vou_tv_enc_hd_div",
+ VOU_LOCAL_CLKEN, 1);
+ clk[ZX296702_VOU_TV_ENC_SD_DAC_CLK] =
+ zx_gate("vou_tv_enc_sd_dac_clk", "vou_tv_enc_sd_div",
+ VOU_LOCAL_CLKEN, 0);
+
+ /* CA9 PERIPHCLK = a9_wclk / 2 */
+ clk[ZX296702_A9_PERIPHCLK] =
+ clk_register_fixed_factor(NULL, "a9_periphclk", "a9_wclk",
+ 0, 1, 2);
+
+ for (i = 0; i < ARRAY_SIZE(topclk); i++) {
+ if (IS_ERR(clk[i])) {
+ pr_err("zx296702 clk %d: register failed with %ld\n",
+ i, PTR_ERR(clk[i]));
+ return;
+ }
+ }
+
+ topclk_data.clks = topclk;
+ topclk_data.clk_num = ARRAY_SIZE(topclk);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &topclk_data);
+}
+CLK_OF_DECLARE(zx296702_top_clk, "zte,zx296702-topcrm-clk",
+ zx296702_top_clocks_init);
+
+static void __init zx296702_lsp0_clocks_init(struct device_node *np)
+{
+ struct clk **clk = lsp0clk;
+ int i;
+
+ lsp0crpm_base = of_iomap(np, 0);
+ WARN_ON(!lsp0crpm_base);
+
+ /* SDMMC1 */
+ clk[ZX296702_SDMMC1_WCLK_MUX] =
+ zx_mux("sdmmc1_wclk_mux", sdmmc1_wclk_sel,
+ ARRAY_SIZE(sdmmc1_wclk_sel), CLK_SDMMC1, 4, 1);
+ clk[ZX296702_SDMMC1_WCLK_DIV] =
+ zx_div("sdmmc1_wclk_div", "sdmmc1_wclk_mux", CLK_SDMMC1, 12, 4);
+ clk[ZX296702_SDMMC1_WCLK] =
+ zx_gate("sdmmc1_wclk", "sdmmc1_wclk_div", CLK_SDMMC1, 1);
+ clk[ZX296702_SDMMC1_PCLK] =
+ zx_gate("sdmmc1_pclk", "lsp1_apb_pclk", CLK_SDMMC1, 0);
+
+ for (i = 0; i < ARRAY_SIZE(lsp0clk); i++) {
+ if (IS_ERR(clk[i])) {
+ pr_err("zx296702 clk %d: register failed with %ld\n",
+ i, PTR_ERR(clk[i]));
+ return;
+ }
+ }
+
+ lsp0clk_data.clks = lsp0clk;
+ lsp0clk_data.clk_num = ARRAY_SIZE(lsp0clk);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &lsp0clk_data);
+}
+CLK_OF_DECLARE(zx296702_lsp0_clk, "zte,zx296702-lsp0crpm-clk",
+ zx296702_lsp0_clocks_init);
+
+static void __init zx296702_lsp1_clocks_init(struct device_node *np)
+{
+ struct clk **clk = lsp1clk;
+ int i;
+
+ lsp1crpm_base = of_iomap(np, 0);
+ WARN_ON(!lsp1crpm_base);
+
+ /* UART0 */
+ clk[ZX296702_UART0_WCLK_MUX] =
+ zx_mux("uart0_wclk_mux", uart_wclk_sel,
+ ARRAY_SIZE(uart_wclk_sel), CLK_UART0, 4, 1);
+ /* FIXME: uart wclk enable bit is bit1 in. We hack it as reserved 31 for
+ * UART does not work after parent clk is disabled/enabled */
+ clk[ZX296702_UART0_WCLK] =
+ zx_gate("uart0_wclk", "uart0_wclk_mux", CLK_UART0, 31);
+ clk[ZX296702_UART0_PCLK] =
+ zx_gate("uart0_pclk", "lsp1_apb_pclk", CLK_UART0, 0);
+
+ /* UART1 */
+ clk[ZX296702_UART1_WCLK_MUX] =
+ zx_mux("uart1_wclk_mux", uart_wclk_sel,
+ ARRAY_SIZE(uart_wclk_sel), CLK_UART1, 4, 1);
+ clk[ZX296702_UART1_WCLK] =
+ zx_gate("uart1_wclk", "uart1_wclk_mux", CLK_UART1, 1);
+ clk[ZX296702_UART1_PCLK] =
+ zx_gate("uart1_pclk", "lsp1_apb_pclk", CLK_UART1, 0);
+
+ /* SDMMC0 */
+ clk[ZX296702_SDMMC0_WCLK_MUX] =
+ zx_mux("sdmmc0_wclk_mux", sdmmc0_wclk_sel,
+ ARRAY_SIZE(sdmmc0_wclk_sel), CLK_SDMMC0, 4, 1);
+ clk[ZX296702_SDMMC0_WCLK_DIV] =
+ zx_div("sdmmc0_wclk_div", "sdmmc0_wclk_mux", CLK_SDMMC0, 12, 4);
+ clk[ZX296702_SDMMC0_WCLK] =
+ zx_gate("sdmmc0_wclk", "sdmmc0_wclk_div", CLK_SDMMC0, 1);
+ clk[ZX296702_SDMMC0_PCLK] =
+ zx_gate("sdmmc0_pclk", "lsp1_apb_pclk", CLK_SDMMC0, 0);
+
+ for (i = 0; i < ARRAY_SIZE(lsp1clk); i++) {
+ if (IS_ERR(clk[i])) {
+ pr_err("zx296702 clk %d: register failed with %ld\n",
+ i, PTR_ERR(clk[i]));
+ return;
+ }
+ }
+
+ lsp1clk_data.clks = lsp1clk;
+ lsp1clk_data.clk_num = ARRAY_SIZE(lsp1clk);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &lsp1clk_data);
+}
+CLK_OF_DECLARE(zx296702_lsp1_clk, "zte,zx296702-lsp1crpm-clk",
+ zx296702_lsp1_clocks_init);
diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h
new file mode 100644
index 000000000000..0914a82d0535
--- /dev/null
+++ b/drivers/clk/zte/clk.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 Linaro Ltd.
+ * Copyright (C) 2014 ZTE 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 __ZTE_CLK_H
+#define __ZTE_CLK_H
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+
+struct zx_pll_config {
+ unsigned long rate;
+ u32 cfg0;
+ u32 cfg1;
+};
+
+struct clk_zx_pll {
+ struct clk_hw hw;
+ void __iomem *reg_base;
+ const struct zx_pll_config *lookup_table; /* order by rate asc */
+ int count;
+ spinlock_t *lock;
+};
+
+struct clk *clk_register_zx_pll(const char *name, const char *parent_name,
+ unsigned long flags, void __iomem *reg_base,
+ const struct zx_pll_config *lookup_table, int count, spinlock_t *lock);
+#endif
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 51d7865fdddb..4e57730e0be4 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -106,6 +106,16 @@ config CLKSRC_EFM32
Support to use the timers of EFM32 SoCs as clock source and clock
event device.
+config CLKSRC_LPC32XX
+ bool
+ select CLKSRC_MMIO
+ select CLKSRC_OF
+
+config CLKSRC_STM32
+ bool "Clocksource for STM32 SoCs" if !ARCH_STM32
+ depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
+ select CLKSRC_MMIO
+
config ARM_ARCH_TIMER
bool
select CLKSRC_OF if OF
@@ -132,6 +142,12 @@ config ARM_GLOBAL_TIMER
help
This options enables support for the ARM global timer unit
+config ARM_TIMER_SP804
+ bool "Support for Dual Timer SP804 module"
+ depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP
+ select CLKSRC_MMIO
+ select CLKSRC_OF if OF
+
config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
bool
depends on ARM_GLOBAL_TIMER
@@ -139,6 +155,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
help
Use ARM global timer clock source as sched_clock
+config ARMV7M_SYSTICK
+ bool
+ select CLKSRC_OF if OF
+ select CLKSRC_MMIO
+ help
+ This options enables support for the ARMv7M system timer unit
+
config ATMEL_PIT
select CLKSRC_OF if OF
def_bool SOC_AT91SAM9 || SOC_SAMA5
@@ -258,4 +281,16 @@ config CLKSRC_PXA
help
This enables OST0 support available on PXA and SA-11x0
platforms.
+
+config H8300_TMR16
+ bool
+
+config H8300_TPU
+ bool
+
+config CLKSRC_IMX_GPT
+ bool "Clocksource using i.MX GPT" if COMPILE_TEST
+ depends on ARM && CLKDEV_LOOKUP
+ select CLKSRC_MMIO
+
endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 5b85f6adb258..f228354961ca 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -36,7 +36,9 @@ obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o
obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm_kona_timer.o
obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o
obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o
+obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o
obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o
+obj-$(CONFIG_CLKSRC_LPC32XX) += time-lpc32xx.o
obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o
obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o
obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o
@@ -45,10 +47,16 @@ obj-$(CONFIG_MTK_TIMER) += mtk_timer.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
+obj-$(CONFIG_ARMV7M_SYSTICK) += armv7m_systick.o
+obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp804.o
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o
obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o
obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o
+obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o
obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o
+obj-$(CONFIG_H8300) += h8300_timer8.o
+obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o
+obj-$(CONFIG_H8300_TPU) += h8300_tpu.o
diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c
new file mode 100644
index 000000000000..addfd2c64f54
--- /dev/null
+++ b/drivers/clocksource/armv7m_systick.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/bitops.h>
+
+#define SYST_CSR 0x00
+#define SYST_RVR 0x04
+#define SYST_CVR 0x08
+#define SYST_CALIB 0x0c
+
+#define SYST_CSR_ENABLE BIT(0)
+
+#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
+
+static void __init system_timer_of_register(struct device_node *np)
+{
+ struct clk *clk = NULL;
+ void __iomem *base;
+ u32 rate;
+ int ret;
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_warn("system-timer: invalid base address\n");
+ return;
+ }
+
+ ret = of_property_read_u32(np, "clock-frequency", &rate);
+ if (ret) {
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk))
+ goto out_unmap;
+
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ goto out_clk_put;
+
+ rate = clk_get_rate(clk);
+ if (!rate)
+ goto out_clk_disable;
+ }
+
+ writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
+ writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
+
+ ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer", rate,
+ 200, 24, clocksource_mmio_readl_down);
+ if (ret) {
+ pr_err("failed to init clocksource (%d)\n", ret);
+ if (clk)
+ goto out_clk_disable;
+ else
+ goto out_unmap;
+ }
+
+ pr_info("ARM System timer initialized as clocksource\n");
+
+ return;
+
+out_clk_disable:
+ clk_disable_unprepare(clk);
+out_clk_put:
+ clk_put(clk);
+out_unmap:
+ iounmap(base);
+ pr_warn("ARM System timer register failed (%d)\n", ret);
+}
+
+CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
+ system_timer_of_register);
diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c
index 2c9c993727c8..4c2ba59897e8 100644
--- a/drivers/clocksource/asm9260_timer.c
+++ b/drivers/clocksource/asm9260_timer.c
@@ -178,7 +178,7 @@ static void __init asm9260_timer_init(struct device_node *np)
unsigned long rate;
priv.base = of_io_request_and_map(np, 0, np->name);
- if (!priv.base)
+ if (IS_ERR(priv.base))
panic("%s: unable to map resource", np->name);
clk = of_clk_get(np, 0);
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index 83564c9cfdbe..935b05936dbd 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -209,7 +209,7 @@ static void exynos4_frc_resume(struct clocksource *cs)
exynos4_mct_frc_start();
}
-struct clocksource mct_frc = {
+static struct clocksource mct_frc = {
.name = "mct-frc",
.rating = 400,
.read = exynos4_frc_read,
@@ -413,7 +413,7 @@ static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
}
}
-static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
+static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
{
struct clock_event_device *evt = &mevt->evt;
@@ -426,12 +426,8 @@ static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
exynos4_mct_tick_stop(mevt);
/* Clear the MCT tick interrupt */
- if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) {
+ if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1)
exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
- return 1;
- } else {
- return 0;
- }
}
static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
@@ -564,18 +560,6 @@ out_irq:
free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick);
}
-void __init mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1)
-{
- mct_irqs[MCT_G0_IRQ] = irq_g0;
- mct_irqs[MCT_L0_IRQ] = irq_l0;
- mct_irqs[MCT_L1_IRQ] = irq_l1;
- mct_int_type = MCT_INT_SPI;
-
- exynos4_timer_resources(NULL, base);
- exynos4_clocksource_init();
- exynos4_clockevent_init();
-}
-
static void __init mct_init_dt(struct device_node *np, unsigned int int_type)
{
u32 nr_irqs, i;
diff --git a/drivers/clocksource/h8300_timer16.c b/drivers/clocksource/h8300_timer16.c
new file mode 100644
index 000000000000..82941c1e9e33
--- /dev/null
+++ b/drivers/clocksource/h8300_timer16.c
@@ -0,0 +1,254 @@
+/*
+ * H8/300 16bit Timer driver
+ *
+ * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/clocksource.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <asm/segment.h>
+#include <asm/irq.h>
+
+#define TSTR 0
+#define TSNC 1
+#define TMDR 2
+#define TOLR 3
+#define TISRA 4
+#define TISRB 5
+#define TISRC 6
+
+#define TCR 0
+#define TIOR 1
+#define TCNT 2
+#define GRA 4
+#define GRB 6
+
+#define FLAG_REPROGRAM (1 << 0)
+#define FLAG_SKIPEVENT (1 << 1)
+#define FLAG_IRQCONTEXT (1 << 2)
+#define FLAG_STARTED (1 << 3)
+
+#define ONESHOT 0
+#define PERIODIC 1
+
+#define RELATIVE 0
+#define ABSOLUTE 1
+
+struct timer16_priv {
+ struct platform_device *pdev;
+ struct clocksource cs;
+ struct irqaction irqaction;
+ unsigned long total_cycles;
+ unsigned long mapbase;
+ unsigned long mapcommon;
+ unsigned long flags;
+ unsigned short gra;
+ unsigned short cs_enabled;
+ unsigned char enb;
+ unsigned char imfa;
+ unsigned char imiea;
+ unsigned char ovf;
+ raw_spinlock_t lock;
+ struct clk *clk;
+};
+
+static unsigned long timer16_get_counter(struct timer16_priv *p)
+{
+ unsigned long v1, v2, v3;
+ int o1, o2;
+
+ o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf;
+
+ /* Make sure the timer value is stable. Stolen from acpi_pm.c */
+ do {
+ o2 = o1;
+ v1 = ctrl_inw(p->mapbase + TCNT);
+ v2 = ctrl_inw(p->mapbase + TCNT);
+ v3 = ctrl_inw(p->mapbase + TCNT);
+ o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf;
+ } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
+ || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
+
+ v2 |= 0x10000;
+ return v2;
+}
+
+
+static irqreturn_t timer16_interrupt(int irq, void *dev_id)
+{
+ struct timer16_priv *p = (struct timer16_priv *)dev_id;
+
+ ctrl_outb(ctrl_inb(p->mapcommon + TISRA) & ~p->imfa,
+ p->mapcommon + TISRA);
+ p->total_cycles += 0x10000;
+
+ return IRQ_HANDLED;
+}
+
+static inline struct timer16_priv *cs_to_priv(struct clocksource *cs)
+{
+ return container_of(cs, struct timer16_priv, cs);
+}
+
+static cycle_t timer16_clocksource_read(struct clocksource *cs)
+{
+ struct timer16_priv *p = cs_to_priv(cs);
+ unsigned long flags, raw;
+ unsigned long value;
+
+ raw_spin_lock_irqsave(&p->lock, flags);
+ value = p->total_cycles;
+ raw = timer16_get_counter(p);
+ raw_spin_unlock_irqrestore(&p->lock, flags);
+
+ return value + raw;
+}
+
+static int timer16_enable(struct clocksource *cs)
+{
+ struct timer16_priv *p = cs_to_priv(cs);
+
+ WARN_ON(p->cs_enabled);
+
+ p->total_cycles = 0;
+ ctrl_outw(0x0000, p->mapbase + TCNT);
+ ctrl_outb(0x83, p->mapbase + TCR);
+ ctrl_outb(ctrl_inb(p->mapcommon + TSTR) | p->enb,
+ p->mapcommon + TSTR);
+
+ p->cs_enabled = true;
+ return 0;
+}
+
+static void timer16_disable(struct clocksource *cs)
+{
+ struct timer16_priv *p = cs_to_priv(cs);
+
+ WARN_ON(!p->cs_enabled);
+
+ ctrl_outb(ctrl_inb(p->mapcommon + TSTR) & ~p->enb,
+ p->mapcommon + TSTR);
+
+ p->cs_enabled = false;
+}
+
+#define REG_CH 0
+#define REG_COMM 1
+
+static int timer16_setup(struct timer16_priv *p, struct platform_device *pdev)
+{
+ struct resource *res[2];
+ int ret, irq;
+ unsigned int ch;
+
+ memset(p, 0, sizeof(*p));
+ p->pdev = pdev;
+
+ res[REG_CH] = platform_get_resource(p->pdev,
+ IORESOURCE_MEM, REG_CH);
+ res[REG_COMM] = platform_get_resource(p->pdev,
+ IORESOURCE_MEM, REG_COMM);
+ if (!res[REG_CH] || !res[REG_COMM]) {
+ dev_err(&p->pdev->dev, "failed to get I/O memory\n");
+ return -ENXIO;
+ }
+ irq = platform_get_irq(p->pdev, 0);
+ if (irq < 0) {
+ dev_err(&p->pdev->dev, "failed to get irq\n");
+ return irq;
+ }
+
+ p->clk = clk_get(&p->pdev->dev, "fck");
+ if (IS_ERR(p->clk)) {
+ dev_err(&p->pdev->dev, "can't get clk\n");
+ return PTR_ERR(p->clk);
+ }
+ of_property_read_u32(p->pdev->dev.of_node, "renesas,channel", &ch);
+
+ p->pdev = pdev;
+ p->mapbase = res[REG_CH]->start;
+ p->mapcommon = res[REG_COMM]->start;
+ p->enb = 1 << ch;
+ p->imfa = 1 << ch;
+ p->imiea = 1 << (4 + ch);
+ p->cs.name = pdev->name;
+ p->cs.rating = 200;
+ p->cs.read = timer16_clocksource_read;
+ p->cs.enable = timer16_enable;
+ p->cs.disable = timer16_disable;
+ p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
+ p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+ ret = request_irq(irq, timer16_interrupt,
+ IRQF_TIMER, pdev->name, p);
+ if (ret < 0) {
+ dev_err(&p->pdev->dev, "failed to request irq %d\n", irq);
+ return ret;
+ }
+
+ clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 8);
+
+ return 0;
+}
+
+static int timer16_probe(struct platform_device *pdev)
+{
+ struct timer16_priv *p = platform_get_drvdata(pdev);
+
+ if (p) {
+ dev_info(&pdev->dev, "kept as earlytimer\n");
+ return 0;
+ }
+
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ return timer16_setup(p, pdev);
+}
+
+static int timer16_remove(struct platform_device *pdev)
+{
+ return -EBUSY;
+}
+
+static const struct of_device_id timer16_of_table[] = {
+ { .compatible = "renesas,16bit-timer" },
+ { }
+};
+static struct platform_driver timer16_driver = {
+ .probe = timer16_probe,
+ .remove = timer16_remove,
+ .driver = {
+ .name = "h8300h-16timer",
+ .of_match_table = of_match_ptr(timer16_of_table),
+ }
+};
+
+static int __init timer16_init(void)
+{
+ return platform_driver_register(&timer16_driver);
+}
+
+static void __exit timer16_exit(void)
+{
+ platform_driver_unregister(&timer16_driver);
+}
+
+subsys_initcall(timer16_init);
+module_exit(timer16_exit);
+MODULE_AUTHOR("Yoshinori Sato");
+MODULE_DESCRIPTION("H8/300H 16bit Timer Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c
new file mode 100644
index 000000000000..0214cb3a7f5e
--- /dev/null
+++ b/drivers/clocksource/h8300_timer8.c
@@ -0,0 +1,313 @@
+/*
+ * linux/arch/h8300/kernel/cpu/timer/timer8.c
+ *
+ * Yoshinori Sato <ysato@users.sourcefoge.jp>
+ *
+ * 8bit Timer driver
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clockchips.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <asm/irq.h>
+
+#define _8TCR 0
+#define _8TCSR 2
+#define TCORA 4
+#define TCORB 6
+#define _8TCNT 8
+
+#define FLAG_REPROGRAM (1 << 0)
+#define FLAG_SKIPEVENT (1 << 1)
+#define FLAG_IRQCONTEXT (1 << 2)
+#define FLAG_STARTED (1 << 3)
+
+#define ONESHOT 0
+#define PERIODIC 1
+
+#define RELATIVE 0
+#define ABSOLUTE 1
+
+struct timer8_priv {
+ struct platform_device *pdev;
+ struct clock_event_device ced;
+ struct irqaction irqaction;
+ unsigned long mapbase;
+ raw_spinlock_t lock;
+ unsigned long flags;
+ unsigned int rate;
+ unsigned int tcora;
+ struct clk *pclk;
+};
+
+static unsigned long timer8_get_counter(struct timer8_priv *p)
+{
+ unsigned long v1, v2, v3;
+ int o1, o2;
+
+ o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20;
+
+ /* Make sure the timer value is stable. Stolen from acpi_pm.c */
+ do {
+ o2 = o1;
+ v1 = ctrl_inw(p->mapbase + _8TCNT);
+ v2 = ctrl_inw(p->mapbase + _8TCNT);
+ v3 = ctrl_inw(p->mapbase + _8TCNT);
+ o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20;
+ } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
+ || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
+
+ v2 |= o1 << 10;
+ return v2;
+}
+
+static irqreturn_t timer8_interrupt(int irq, void *dev_id)
+{
+ struct timer8_priv *p = dev_id;
+
+ ctrl_outb(ctrl_inb(p->mapbase + _8TCSR) & ~0x40,
+ p->mapbase + _8TCSR);
+ p->flags |= FLAG_IRQCONTEXT;
+ ctrl_outw(p->tcora, p->mapbase + TCORA);
+ if (!(p->flags & FLAG_SKIPEVENT)) {
+ if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT)
+ ctrl_outw(0x0000, p->mapbase + _8TCR);
+ p->ced.event_handler(&p->ced);
+ }
+ p->flags &= ~(FLAG_SKIPEVENT | FLAG_IRQCONTEXT);
+
+ return IRQ_HANDLED;
+}
+
+static void timer8_set_next(struct timer8_priv *p, unsigned long delta)
+{
+ unsigned long flags;
+ unsigned long now;
+
+ raw_spin_lock_irqsave(&p->lock, flags);
+ if (delta >= 0x10000)
+ dev_warn(&p->pdev->dev, "delta out of range\n");
+ now = timer8_get_counter(p);
+ p->tcora = delta;
+ ctrl_outb(ctrl_inb(p->mapbase + _8TCR) | 0x40, p->mapbase + _8TCR);
+ if (delta > now)
+ ctrl_outw(delta, p->mapbase + TCORA);
+ else
+ ctrl_outw(now + 1, p->mapbase + TCORA);
+
+ raw_spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static int timer8_enable(struct timer8_priv *p)
+{
+ p->rate = clk_get_rate(p->pclk) / 64;
+ ctrl_outw(0xffff, p->mapbase + TCORA);
+ ctrl_outw(0x0000, p->mapbase + _8TCNT);
+ ctrl_outw(0x0c02, p->mapbase + _8TCR);
+
+ return 0;
+}
+
+static int timer8_start(struct timer8_priv *p)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&p->lock, flags);
+
+ if (!(p->flags & FLAG_STARTED))
+ ret = timer8_enable(p);
+
+ if (ret)
+ goto out;
+ p->flags |= FLAG_STARTED;
+
+ out:
+ raw_spin_unlock_irqrestore(&p->lock, flags);
+
+ return ret;
+}
+
+static void timer8_stop(struct timer8_priv *p)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&p->lock, flags);
+
+ ctrl_outw(0x0000, p->mapbase + _8TCR);
+
+ raw_spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced)
+{
+ return container_of(ced, struct timer8_priv, ced);
+}
+
+static void timer8_clock_event_start(struct timer8_priv *p, int periodic)
+{
+ struct clock_event_device *ced = &p->ced;
+
+ timer8_start(p);
+
+ ced->shift = 32;
+ ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift);
+ ced->max_delta_ns = clockevent_delta2ns(0xffff, ced);
+ ced->min_delta_ns = clockevent_delta2ns(0x0001, ced);
+
+ timer8_set_next(p, periodic?(p->rate + HZ/2) / HZ:0x10000);
+}
+
+static void timer8_clock_event_mode(enum clock_event_mode mode,
+ struct clock_event_device *ced)
+{
+ struct timer8_priv *p = ced_to_priv(ced);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ dev_info(&p->pdev->dev, "used for periodic clock events\n");
+ timer8_stop(p);
+ timer8_clock_event_start(p, PERIODIC);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ dev_info(&p->pdev->dev, "used for oneshot clock events\n");
+ timer8_stop(p);
+ timer8_clock_event_start(p, ONESHOT);
+ break;
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ timer8_stop(p);
+ break;
+ default:
+ break;
+ }
+}
+
+static int timer8_clock_event_next(unsigned long delta,
+ struct clock_event_device *ced)
+{
+ struct timer8_priv *p = ced_to_priv(ced);
+
+ BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
+ timer8_set_next(p, delta - 1);
+
+ return 0;
+}
+
+static int timer8_setup(struct timer8_priv *p,
+ struct platform_device *pdev)
+{
+ struct resource *res;
+ int irq;
+ int ret;
+
+ memset(p, 0, sizeof(*p));
+ p->pdev = pdev;
+
+ res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&p->pdev->dev, "failed to get I/O memory\n");
+ return -ENXIO;
+ }
+
+ irq = platform_get_irq(p->pdev, 0);
+ if (irq < 0) {
+ dev_err(&p->pdev->dev, "failed to get irq\n");
+ return -ENXIO;
+ }
+
+ p->mapbase = res->start;
+
+ p->irqaction.name = dev_name(&p->pdev->dev);
+ p->irqaction.handler = timer8_interrupt;
+ p->irqaction.dev_id = p;
+ p->irqaction.flags = IRQF_TIMER;
+
+ p->pclk = clk_get(&p->pdev->dev, "fck");
+ if (IS_ERR(p->pclk)) {
+ dev_err(&p->pdev->dev, "can't get clk\n");
+ return PTR_ERR(p->pclk);
+ }
+
+ p->ced.name = pdev->name;
+ p->ced.features = CLOCK_EVT_FEAT_PERIODIC |
+ CLOCK_EVT_FEAT_ONESHOT;
+ p->ced.rating = 200;
+ p->ced.cpumask = cpumask_of(0);
+ p->ced.set_next_event = timer8_clock_event_next;
+ p->ced.set_mode = timer8_clock_event_mode;
+
+ ret = setup_irq(irq, &p->irqaction);
+ if (ret < 0) {
+ dev_err(&p->pdev->dev,
+ "failed to request irq %d\n", irq);
+ return ret;
+ }
+ clockevents_register_device(&p->ced);
+ platform_set_drvdata(pdev, p);
+
+ return 0;
+}
+
+static int timer8_probe(struct platform_device *pdev)
+{
+ struct timer8_priv *p = platform_get_drvdata(pdev);
+
+ if (p) {
+ dev_info(&pdev->dev, "kept as earlytimer\n");
+ return 0;
+ }
+
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ return timer8_setup(p, pdev);
+}
+
+static int timer8_remove(struct platform_device *pdev)
+{
+ return -EBUSY;
+}
+
+static const struct of_device_id timer8_of_table[] __maybe_unused = {
+ { .compatible = "renesas,8bit-timer" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, timer8_of_table);
+static struct platform_driver timer8_driver = {
+ .probe = timer8_probe,
+ .remove = timer8_remove,
+ .driver = {
+ .name = "h8300-8timer",
+ .of_match_table = of_match_ptr(timer8_of_table),
+ }
+};
+
+static int __init timer8_init(void)
+{
+ return platform_driver_register(&timer8_driver);
+}
+
+static void __exit timer8_exit(void)
+{
+ platform_driver_unregister(&timer8_driver);
+}
+
+subsys_initcall(timer8_init);
+module_exit(timer8_exit);
+MODULE_AUTHOR("Yoshinori Sato");
+MODULE_DESCRIPTION("H8/300 8bit Timer Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clocksource/h8300_tpu.c b/drivers/clocksource/h8300_tpu.c
new file mode 100644
index 000000000000..64195fdd78bf
--- /dev/null
+++ b/drivers/clocksource/h8300_tpu.c
@@ -0,0 +1,207 @@
+/*
+ * H8/300 TPU Driver
+ *
+ * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clocksource.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <asm/irq.h>
+
+#define TCR 0
+#define TMDR 1
+#define TIOR 2
+#define TER 4
+#define TSR 5
+#define TCNT 6
+#define TGRA 8
+#define TGRB 10
+#define TGRC 12
+#define TGRD 14
+
+struct tpu_priv {
+ struct platform_device *pdev;
+ struct clocksource cs;
+ struct clk *clk;
+ unsigned long mapbase1;
+ unsigned long mapbase2;
+ raw_spinlock_t lock;
+ unsigned int cs_enabled;
+};
+
+static inline unsigned long read_tcnt32(struct tpu_priv *p)
+{
+ unsigned long tcnt;
+
+ tcnt = ctrl_inw(p->mapbase1 + TCNT) << 16;
+ tcnt |= ctrl_inw(p->mapbase2 + TCNT);
+ return tcnt;
+}
+
+static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val)
+{
+ unsigned long v1, v2, v3;
+ int o1, o2;
+
+ o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10;
+
+ /* Make sure the timer value is stable. Stolen from acpi_pm.c */
+ do {
+ o2 = o1;
+ v1 = read_tcnt32(p);
+ v2 = read_tcnt32(p);
+ v3 = read_tcnt32(p);
+ o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10;
+ } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
+ || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
+
+ *val = v2;
+ return o1;
+}
+
+static inline struct tpu_priv *cs_to_priv(struct clocksource *cs)
+{
+ return container_of(cs, struct tpu_priv, cs);
+}
+
+static cycle_t tpu_clocksource_read(struct clocksource *cs)
+{
+ struct tpu_priv *p = cs_to_priv(cs);
+ unsigned long flags;
+ unsigned long long value;
+
+ raw_spin_lock_irqsave(&p->lock, flags);
+ if (tpu_get_counter(p, &value))
+ value += 0x100000000;
+ raw_spin_unlock_irqrestore(&p->lock, flags);
+
+ return value;
+}
+
+static int tpu_clocksource_enable(struct clocksource *cs)
+{
+ struct tpu_priv *p = cs_to_priv(cs);
+
+ WARN_ON(p->cs_enabled);
+
+ ctrl_outw(0, p->mapbase1 + TCNT);
+ ctrl_outw(0, p->mapbase2 + TCNT);
+ ctrl_outb(0x0f, p->mapbase1 + TCR);
+ ctrl_outb(0x03, p->mapbase2 + TCR);
+
+ p->cs_enabled = true;
+ return 0;
+}
+
+static void tpu_clocksource_disable(struct clocksource *cs)
+{
+ struct tpu_priv *p = cs_to_priv(cs);
+
+ WARN_ON(!p->cs_enabled);
+
+ ctrl_outb(0, p->mapbase1 + TCR);
+ ctrl_outb(0, p->mapbase2 + TCR);
+ p->cs_enabled = false;
+}
+
+#define CH_L 0
+#define CH_H 1
+
+static int __init tpu_setup(struct tpu_priv *p, struct platform_device *pdev)
+{
+ struct resource *res[2];
+
+ memset(p, 0, sizeof(*p));
+ p->pdev = pdev;
+
+ res[CH_L] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_L);
+ res[CH_H] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_H);
+ if (!res[CH_L] || !res[CH_H]) {
+ dev_err(&p->pdev->dev, "failed to get I/O memory\n");
+ return -ENXIO;
+ }
+
+ p->clk = clk_get(&p->pdev->dev, "fck");
+ if (IS_ERR(p->clk)) {
+ dev_err(&p->pdev->dev, "can't get clk\n");
+ return PTR_ERR(p->clk);
+ }
+
+ p->mapbase1 = res[CH_L]->start;
+ p->mapbase2 = res[CH_H]->start;
+
+ p->cs.name = pdev->name;
+ p->cs.rating = 200;
+ p->cs.read = tpu_clocksource_read;
+ p->cs.enable = tpu_clocksource_enable;
+ p->cs.disable = tpu_clocksource_disable;
+ p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
+ p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+ clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 64);
+ platform_set_drvdata(pdev, p);
+
+ return 0;
+}
+
+static int tpu_probe(struct platform_device *pdev)
+{
+ struct tpu_priv *p = platform_get_drvdata(pdev);
+
+ if (p) {
+ dev_info(&pdev->dev, "kept as earlytimer\n");
+ return 0;
+ }
+
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ return tpu_setup(p, pdev);
+}
+
+static int tpu_remove(struct platform_device *pdev)
+{
+ return -EBUSY;
+}
+
+static const struct of_device_id tpu_of_table[] = {
+ { .compatible = "renesas,tpu" },
+ { }
+};
+
+static struct platform_driver tpu_driver = {
+ .probe = tpu_probe,
+ .remove = tpu_remove,
+ .driver = {
+ .name = "h8s-tpu",
+ .of_match_table = of_match_ptr(tpu_of_table),
+ }
+};
+
+static int __init tpu_init(void)
+{
+ return platform_driver_register(&tpu_driver);
+}
+
+static void __exit tpu_exit(void)
+{
+ platform_driver_unregister(&tpu_driver);
+}
+
+subsys_initcall(tpu_init);
+module_exit(tpu_exit);
+MODULE_AUTHOR("Yoshinori Sato");
+MODULE_DESCRIPTION("H8S Timer Pulse Unit Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c
index 098c542e5c53..cba2d015564c 100644
--- a/drivers/clocksource/qcom-timer.c
+++ b/drivers/clocksource/qcom-timer.c
@@ -40,8 +40,6 @@
#define GPT_HZ 32768
-#define MSM_DGT_SHIFT 5
-
static void __iomem *event_base;
static void __iomem *sts_base;
@@ -232,7 +230,6 @@ err:
register_current_timer_delay(&msm_delay_timer);
}
-#ifdef CONFIG_ARCH_QCOM
static void __init msm_dt_timer_init(struct device_node *np)
{
u32 freq;
@@ -285,59 +282,3 @@ static void __init msm_dt_timer_init(struct device_node *np)
}
CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init);
CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init);
-#else
-
-static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source,
- u32 sts)
-{
- void __iomem *base;
-
- base = ioremap(addr, SZ_256);
- if (!base) {
- pr_err("Failed to map timer base\n");
- return -ENOMEM;
- }
- event_base = base + event;
- source_base = base + source;
- if (sts)
- sts_base = base + sts;
-
- return 0;
-}
-
-static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs)
-{
- /*
- * Shift timer count down by a constant due to unreliable lower bits
- * on some targets.
- */
- return msm_read_timer_count(cs) >> MSM_DGT_SHIFT;
-}
-
-void __init msm7x01_timer_init(void)
-{
- struct clocksource *cs = &msm_clocksource;
-
- if (msm_timer_map(0xc0100000, 0x0, 0x10, 0x0))
- return;
- cs->read = msm_read_timer_count_shift;
- cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT));
- /* 600 KHz */
- msm_timer_init(19200000 >> MSM_DGT_SHIFT, 32 - MSM_DGT_SHIFT, 7,
- false);
-}
-
-void __init msm7x30_timer_init(void)
-{
- if (msm_timer_map(0xc0100000, 0x4, 0x24, 0x80))
- return;
- msm_timer_init(24576000 / 4, 32, 1, false);
-}
-
-void __init qsd8x50_timer_init(void)
-{
- if (msm_timer_map(0xAC100000, 0x0, 0x10, 0x34))
- return;
- msm_timer_init(19200000 / 4, 32, 7, false);
-}
-#endif
diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/time-lpc32xx.c
new file mode 100644
index 000000000000..a1c06a2bc77c
--- /dev/null
+++ b/drivers/clocksource/time-lpc32xx.c
@@ -0,0 +1,272 @@
+/*
+ * Clocksource driver for NXP LPC32xx/18xx/43xx timer
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * Based on:
+ * time-efm32 Copyright (C) 2013 Pengutronix
+ * mach-lpc32xx/timer.c Copyright (C) 2009 - 2010 NXP Semiconductors
+ *
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
+
+#define LPC32XX_TIMER_IR 0x000
+#define LPC32XX_TIMER_IR_MR0INT BIT(0)
+#define LPC32XX_TIMER_TCR 0x004
+#define LPC32XX_TIMER_TCR_CEN BIT(0)
+#define LPC32XX_TIMER_TCR_CRST BIT(1)
+#define LPC32XX_TIMER_TC 0x008
+#define LPC32XX_TIMER_PR 0x00c
+#define LPC32XX_TIMER_MCR 0x014
+#define LPC32XX_TIMER_MCR_MR0I BIT(0)
+#define LPC32XX_TIMER_MCR_MR0R BIT(1)
+#define LPC32XX_TIMER_MCR_MR0S BIT(2)
+#define LPC32XX_TIMER_MR0 0x018
+#define LPC32XX_TIMER_CTCR 0x070
+
+struct lpc32xx_clock_event_ddata {
+ struct clock_event_device evtdev;
+ void __iomem *base;
+};
+
+/* Needed for the sched clock */
+static void __iomem *clocksource_timer_counter;
+
+static u64 notrace lpc32xx_read_sched_clock(void)
+{
+ return readl(clocksource_timer_counter);
+}
+
+static int lpc32xx_clkevt_next_event(unsigned long delta,
+ struct clock_event_device *evtdev)
+{
+ struct lpc32xx_clock_event_ddata *ddata =
+ container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
+
+ /*
+ * Place timer in reset and program the delta in the prescale
+ * register (PR). When the prescale counter matches the value
+ * in PR the counter register is incremented and the compare
+ * match will trigger. After setup the timer is released from
+ * reset and enabled.
+ */
+ writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR);
+ writel_relaxed(delta, ddata->base + LPC32XX_TIMER_PR);
+ writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR);
+
+ return 0;
+}
+
+static int lpc32xx_clkevt_shutdown(struct clock_event_device *evtdev)
+{
+ struct lpc32xx_clock_event_ddata *ddata =
+ container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
+
+ /* Disable the timer */
+ writel_relaxed(0, ddata->base + LPC32XX_TIMER_TCR);
+
+ return 0;
+}
+
+static int lpc32xx_clkevt_oneshot(struct clock_event_device *evtdev)
+{
+ /*
+ * When using oneshot, we must also disable the timer
+ * to wait for the first call to set_next_event().
+ */
+ return lpc32xx_clkevt_shutdown(evtdev);
+}
+
+static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id)
+{
+ struct lpc32xx_clock_event_ddata *ddata = dev_id;
+
+ /* Clear match on channel 0 */
+ writel_relaxed(LPC32XX_TIMER_IR_MR0INT, ddata->base + LPC32XX_TIMER_IR);
+
+ ddata->evtdev.event_handler(&ddata->evtdev);
+
+ return IRQ_HANDLED;
+}
+
+static struct lpc32xx_clock_event_ddata lpc32xx_clk_event_ddata = {
+ .evtdev = {
+ .name = "lpc3220 clockevent",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 300,
+ .set_next_event = lpc32xx_clkevt_next_event,
+ .set_state_shutdown = lpc32xx_clkevt_shutdown,
+ .set_state_oneshot = lpc32xx_clkevt_oneshot,
+ },
+};
+
+static int __init lpc32xx_clocksource_init(struct device_node *np)
+{
+ void __iomem *base;
+ unsigned long rate;
+ struct clk *clk;
+ int ret;
+
+ clk = of_clk_get_by_name(np, "timerclk");
+ if (IS_ERR(clk)) {
+ pr_err("clock get failed (%lu)\n", PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ pr_err("clock enable failed (%d)\n", ret);
+ goto err_clk_enable;
+ }
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_err("unable to map registers\n");
+ ret = -EADDRNOTAVAIL;
+ goto err_iomap;
+ }
+
+ /*
+ * Disable and reset timer then set it to free running timer
+ * mode (CTCR) with no prescaler (PR) or match operations (MCR).
+ * After setup the timer is released from reset and enabled.
+ */
+ writel_relaxed(LPC32XX_TIMER_TCR_CRST, base + LPC32XX_TIMER_TCR);
+ writel_relaxed(0, base + LPC32XX_TIMER_PR);
+ writel_relaxed(0, base + LPC32XX_TIMER_MCR);
+ writel_relaxed(0, base + LPC32XX_TIMER_CTCR);
+ writel_relaxed(LPC32XX_TIMER_TCR_CEN, base + LPC32XX_TIMER_TCR);
+
+ rate = clk_get_rate(clk);
+ ret = clocksource_mmio_init(base + LPC32XX_TIMER_TC, "lpc3220 timer",
+ rate, 300, 32, clocksource_mmio_readl_up);
+ if (ret) {
+ pr_err("failed to init clocksource (%d)\n", ret);
+ goto err_clocksource_init;
+ }
+
+ clocksource_timer_counter = base + LPC32XX_TIMER_TC;
+ sched_clock_register(lpc32xx_read_sched_clock, 32, rate);
+
+ return 0;
+
+err_clocksource_init:
+ iounmap(base);
+err_iomap:
+ clk_disable_unprepare(clk);
+err_clk_enable:
+ clk_put(clk);
+ return ret;
+}
+
+static int __init lpc32xx_clockevent_init(struct device_node *np)
+{
+ void __iomem *base;
+ unsigned long rate;
+ struct clk *clk;
+ int ret, irq;
+
+ clk = of_clk_get_by_name(np, "timerclk");
+ if (IS_ERR(clk)) {
+ pr_err("clock get failed (%lu)\n", PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ pr_err("clock enable failed (%d)\n", ret);
+ goto err_clk_enable;
+ }
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_err("unable to map registers\n");
+ ret = -EADDRNOTAVAIL;
+ goto err_iomap;
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ pr_err("get irq failed\n");
+ ret = -ENOENT;
+ goto err_irq;
+ }
+
+ /*
+ * Disable timer and clear any pending interrupt (IR) on match
+ * channel 0 (MR0). Configure a compare match value of 1 on MR0
+ * and enable interrupt, reset on match and stop on match (MCR).
+ */
+ writel_relaxed(0, base + LPC32XX_TIMER_TCR);
+ writel_relaxed(0, base + LPC32XX_TIMER_CTCR);
+ writel_relaxed(LPC32XX_TIMER_IR_MR0INT, base + LPC32XX_TIMER_IR);
+ writel_relaxed(1, base + LPC32XX_TIMER_MR0);
+ writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R |
+ LPC32XX_TIMER_MCR_MR0S, base + LPC32XX_TIMER_MCR);
+
+ rate = clk_get_rate(clk);
+ lpc32xx_clk_event_ddata.base = base;
+ clockevents_config_and_register(&lpc32xx_clk_event_ddata.evtdev,
+ rate, 1, -1);
+
+ ret = request_irq(irq, lpc32xx_clock_event_handler,
+ IRQF_TIMER | IRQF_IRQPOLL, "lpc3220 clockevent",
+ &lpc32xx_clk_event_ddata);
+ if (ret) {
+ pr_err("request irq failed\n");
+ goto err_irq;
+ }
+
+ return 0;
+
+err_irq:
+ iounmap(base);
+err_iomap:
+ clk_disable_unprepare(clk);
+err_clk_enable:
+ clk_put(clk);
+ return ret;
+}
+
+/*
+ * This function asserts that we have exactly one clocksource and one
+ * clock_event_device in the end.
+ */
+static void __init lpc32xx_timer_init(struct device_node *np)
+{
+ static int has_clocksource, has_clockevent;
+ int ret;
+
+ if (!has_clocksource) {
+ ret = lpc32xx_clocksource_init(np);
+ if (!ret) {
+ has_clocksource = 1;
+ return;
+ }
+ }
+
+ if (!has_clockevent) {
+ ret = lpc32xx_clockevent_init(np);
+ if (!ret) {
+ has_clockevent = 1;
+ return;
+ }
+ }
+}
+CLOCKSOURCE_OF_DECLARE(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init);
diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c
new file mode 100644
index 000000000000..879c78423546
--- /dev/null
+++ b/drivers/clocksource/timer-imx-gpt.c
@@ -0,0 +1,540 @@
+/*
+ * linux/arch/arm/plat-mxc/time.c
+ *
+ * Copyright (C) 2000-2001 Deep Blue Solutions
+ * Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ * Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
+ * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/sched_clock.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <soc/imx/timer.h>
+
+/*
+ * There are 4 versions of the timer hardware on Freescale MXC hardware.
+ * - MX1/MXL
+ * - MX21, MX27.
+ * - MX25, MX31, MX35, MX37, MX51, MX6Q(rev1.0)
+ * - MX6DL, MX6SX, MX6Q(rev1.1+)
+ */
+
+/* defines common for all i.MX */
+#define MXC_TCTL 0x00
+#define MXC_TCTL_TEN (1 << 0) /* Enable module */
+#define MXC_TPRER 0x04
+
+/* MX1, MX21, MX27 */
+#define MX1_2_TCTL_CLK_PCLK1 (1 << 1)
+#define MX1_2_TCTL_IRQEN (1 << 4)
+#define MX1_2_TCTL_FRR (1 << 8)
+#define MX1_2_TCMP 0x08
+#define MX1_2_TCN 0x10
+#define MX1_2_TSTAT 0x14
+
+/* MX21, MX27 */
+#define MX2_TSTAT_CAPT (1 << 1)
+#define MX2_TSTAT_COMP (1 << 0)
+
+/* MX31, MX35, MX25, MX5, MX6 */
+#define V2_TCTL_WAITEN (1 << 3) /* Wait enable mode */
+#define V2_TCTL_CLK_IPG (1 << 6)
+#define V2_TCTL_CLK_PER (2 << 6)
+#define V2_TCTL_CLK_OSC_DIV8 (5 << 6)
+#define V2_TCTL_FRR (1 << 9)
+#define V2_TCTL_24MEN (1 << 10)
+#define V2_TPRER_PRE24M 12
+#define V2_IR 0x0c
+#define V2_TSTAT 0x08
+#define V2_TSTAT_OF1 (1 << 0)
+#define V2_TCN 0x24
+#define V2_TCMP 0x10
+
+#define V2_TIMER_RATE_OSC_DIV8 3000000
+
+struct imx_timer {
+ enum imx_gpt_type type;
+ void __iomem *base;
+ int irq;
+ struct clk *clk_per;
+ struct clk *clk_ipg;
+ const struct imx_gpt_data *gpt;
+ struct clock_event_device ced;
+ enum clock_event_mode cem;
+ struct irqaction act;
+};
+
+struct imx_gpt_data {
+ int reg_tstat;
+ int reg_tcn;
+ int reg_tcmp;
+ void (*gpt_setup_tctl)(struct imx_timer *imxtm);
+ void (*gpt_irq_enable)(struct imx_timer *imxtm);
+ void (*gpt_irq_disable)(struct imx_timer *imxtm);
+ void (*gpt_irq_acknowledge)(struct imx_timer *imxtm);
+ int (*set_next_event)(unsigned long evt,
+ struct clock_event_device *ced);
+};
+
+static inline struct imx_timer *to_imx_timer(struct clock_event_device *ced)
+{
+ return container_of(ced, struct imx_timer, ced);
+}
+
+static void imx1_gpt_irq_disable(struct imx_timer *imxtm)
+{
+ unsigned int tmp;
+
+ tmp = readl_relaxed(imxtm->base + MXC_TCTL);
+ writel_relaxed(tmp & ~MX1_2_TCTL_IRQEN, imxtm->base + MXC_TCTL);
+}
+#define imx21_gpt_irq_disable imx1_gpt_irq_disable
+
+static void imx31_gpt_irq_disable(struct imx_timer *imxtm)
+{
+ writel_relaxed(0, imxtm->base + V2_IR);
+}
+#define imx6dl_gpt_irq_disable imx31_gpt_irq_disable
+
+static void imx1_gpt_irq_enable(struct imx_timer *imxtm)
+{
+ unsigned int tmp;
+
+ tmp = readl_relaxed(imxtm->base + MXC_TCTL);
+ writel_relaxed(tmp | MX1_2_TCTL_IRQEN, imxtm->base + MXC_TCTL);
+}
+#define imx21_gpt_irq_enable imx1_gpt_irq_enable
+
+static void imx31_gpt_irq_enable(struct imx_timer *imxtm)
+{
+ writel_relaxed(1<<0, imxtm->base + V2_IR);
+}
+#define imx6dl_gpt_irq_enable imx31_gpt_irq_enable
+
+static void imx1_gpt_irq_acknowledge(struct imx_timer *imxtm)
+{
+ writel_relaxed(0, imxtm->base + MX1_2_TSTAT);
+}
+
+static void imx21_gpt_irq_acknowledge(struct imx_timer *imxtm)
+{
+ writel_relaxed(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
+ imxtm->base + MX1_2_TSTAT);
+}
+
+static void imx31_gpt_irq_acknowledge(struct imx_timer *imxtm)
+{
+ writel_relaxed(V2_TSTAT_OF1, imxtm->base + V2_TSTAT);
+}
+#define imx6dl_gpt_irq_acknowledge imx31_gpt_irq_acknowledge
+
+static void __iomem *sched_clock_reg;
+
+static u64 notrace mxc_read_sched_clock(void)
+{
+ return sched_clock_reg ? readl_relaxed(sched_clock_reg) : 0;
+}
+
+static struct delay_timer imx_delay_timer;
+
+static unsigned long imx_read_current_timer(void)
+{
+ return readl_relaxed(sched_clock_reg);
+}
+
+static int __init mxc_clocksource_init(struct imx_timer *imxtm)
+{
+ unsigned int c = clk_get_rate(imxtm->clk_per);
+ void __iomem *reg = imxtm->base + imxtm->gpt->reg_tcn;
+
+ imx_delay_timer.read_current_timer = &imx_read_current_timer;
+ imx_delay_timer.freq = c;
+ register_current_timer_delay(&imx_delay_timer);
+
+ sched_clock_reg = reg;
+
+ sched_clock_register(mxc_read_sched_clock, 32, c);
+ return clocksource_mmio_init(reg, "mxc_timer1", c, 200, 32,
+ clocksource_mmio_readl_up);
+}
+
+/* clock event */
+
+static int mx1_2_set_next_event(unsigned long evt,
+ struct clock_event_device *ced)
+{
+ struct imx_timer *imxtm = to_imx_timer(ced);
+ unsigned long tcmp;
+
+ tcmp = readl_relaxed(imxtm->base + MX1_2_TCN) + evt;
+
+ writel_relaxed(tcmp, imxtm->base + MX1_2_TCMP);
+
+ return (int)(tcmp - readl_relaxed(imxtm->base + MX1_2_TCN)) < 0 ?
+ -ETIME : 0;
+}
+
+static int v2_set_next_event(unsigned long evt,
+ struct clock_event_device *ced)
+{
+ struct imx_timer *imxtm = to_imx_timer(ced);
+ unsigned long tcmp;
+
+ tcmp = readl_relaxed(imxtm->base + V2_TCN) + evt;
+
+ writel_relaxed(tcmp, imxtm->base + V2_TCMP);
+
+ return evt < 0x7fffffff &&
+ (int)(tcmp - readl_relaxed(imxtm->base + V2_TCN)) < 0 ?
+ -ETIME : 0;
+}
+
+#ifdef DEBUG
+static const char *clock_event_mode_label[] = {
+ [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
+ [CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT",
+ [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
+ [CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED",
+ [CLOCK_EVT_MODE_RESUME] = "CLOCK_EVT_MODE_RESUME",
+};
+#endif /* DEBUG */
+
+static void mxc_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *ced)
+{
+ struct imx_timer *imxtm = to_imx_timer(ced);
+ unsigned long flags;
+
+ /*
+ * The timer interrupt generation is disabled at least
+ * for enough time to call mxc_set_next_event()
+ */
+ local_irq_save(flags);
+
+ /* Disable interrupt in GPT module */
+ imxtm->gpt->gpt_irq_disable(imxtm);
+
+ if (mode != imxtm->cem) {
+ u32 tcn = readl_relaxed(imxtm->base + imxtm->gpt->reg_tcn);
+ /* Set event time into far-far future */
+ writel_relaxed(tcn - 3, imxtm->base + imxtm->gpt->reg_tcmp);
+
+ /* Clear pending interrupt */
+ imxtm->gpt->gpt_irq_acknowledge(imxtm);
+ }
+
+#ifdef DEBUG
+ printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n",
+ clock_event_mode_label[imxtm->cem],
+ clock_event_mode_label[mode]);
+#endif /* DEBUG */
+
+ /* Remember timer mode */
+ imxtm->cem = mode;
+ local_irq_restore(flags);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ printk(KERN_ERR"mxc_set_mode: Periodic mode is not "
+ "supported for i.MX\n");
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /*
+ * Do not put overhead of interrupt enable/disable into
+ * mxc_set_next_event(), the core has about 4 minutes
+ * to call mxc_set_next_event() or shutdown clock after
+ * mode switching
+ */
+ local_irq_save(flags);
+ imxtm->gpt->gpt_irq_enable(imxtm);
+ local_irq_restore(flags);
+ break;
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_RESUME:
+ /* Left event sources disabled, no more interrupts appear */
+ break;
+ }
+}
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *ced = dev_id;
+ struct imx_timer *imxtm = to_imx_timer(ced);
+ uint32_t tstat;
+
+ tstat = readl_relaxed(imxtm->base + imxtm->gpt->reg_tstat);
+
+ imxtm->gpt->gpt_irq_acknowledge(imxtm);
+
+ ced->event_handler(ced);
+
+ return IRQ_HANDLED;
+}
+
+static int __init mxc_clockevent_init(struct imx_timer *imxtm)
+{
+ struct clock_event_device *ced = &imxtm->ced;
+ struct irqaction *act = &imxtm->act;
+
+ imxtm->cem = CLOCK_EVT_MODE_UNUSED;
+
+ ced->name = "mxc_timer1";
+ ced->features = CLOCK_EVT_FEAT_ONESHOT;
+ ced->set_mode = mxc_set_mode;
+ ced->set_next_event = imxtm->gpt->set_next_event;
+ ced->rating = 200;
+ ced->cpumask = cpumask_of(0);
+ clockevents_config_and_register(ced, clk_get_rate(imxtm->clk_per),
+ 0xff, 0xfffffffe);
+
+ act->name = "i.MX Timer Tick";
+ act->flags = IRQF_TIMER | IRQF_IRQPOLL;
+ act->handler = mxc_timer_interrupt;
+ act->dev_id = ced;
+
+ return setup_irq(imxtm->irq, act);
+}
+
+static void imx1_gpt_setup_tctl(struct imx_timer *imxtm)
+{
+ u32 tctl_val;
+
+ tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
+ writel_relaxed(tctl_val, imxtm->base + MXC_TCTL);
+}
+#define imx21_gpt_setup_tctl imx1_gpt_setup_tctl
+
+static void imx31_gpt_setup_tctl(struct imx_timer *imxtm)
+{
+ u32 tctl_val;
+
+ tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
+ if (clk_get_rate(imxtm->clk_per) == V2_TIMER_RATE_OSC_DIV8)
+ tctl_val |= V2_TCTL_CLK_OSC_DIV8;
+ else
+ tctl_val |= V2_TCTL_CLK_PER;
+
+ writel_relaxed(tctl_val, imxtm->base + MXC_TCTL);
+}
+
+static void imx6dl_gpt_setup_tctl(struct imx_timer *imxtm)
+{
+ u32 tctl_val;
+
+ tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
+ if (clk_get_rate(imxtm->clk_per) == V2_TIMER_RATE_OSC_DIV8) {
+ tctl_val |= V2_TCTL_CLK_OSC_DIV8;
+ /* 24 / 8 = 3 MHz */
+ writel_relaxed(7 << V2_TPRER_PRE24M, imxtm->base + MXC_TPRER);
+ tctl_val |= V2_TCTL_24MEN;
+ } else {
+ tctl_val |= V2_TCTL_CLK_PER;
+ }
+
+ writel_relaxed(tctl_val, imxtm->base + MXC_TCTL);
+}
+
+static const struct imx_gpt_data imx1_gpt_data = {
+ .reg_tstat = MX1_2_TSTAT,
+ .reg_tcn = MX1_2_TCN,
+ .reg_tcmp = MX1_2_TCMP,
+ .gpt_irq_enable = imx1_gpt_irq_enable,
+ .gpt_irq_disable = imx1_gpt_irq_disable,
+ .gpt_irq_acknowledge = imx1_gpt_irq_acknowledge,
+ .gpt_setup_tctl = imx1_gpt_setup_tctl,
+ .set_next_event = mx1_2_set_next_event,
+};
+
+static const struct imx_gpt_data imx21_gpt_data = {
+ .reg_tstat = MX1_2_TSTAT,
+ .reg_tcn = MX1_2_TCN,
+ .reg_tcmp = MX1_2_TCMP,
+ .gpt_irq_enable = imx21_gpt_irq_enable,
+ .gpt_irq_disable = imx21_gpt_irq_disable,
+ .gpt_irq_acknowledge = imx21_gpt_irq_acknowledge,
+ .gpt_setup_tctl = imx21_gpt_setup_tctl,
+ .set_next_event = mx1_2_set_next_event,
+};
+
+static const struct imx_gpt_data imx31_gpt_data = {
+ .reg_tstat = V2_TSTAT,
+ .reg_tcn = V2_TCN,
+ .reg_tcmp = V2_TCMP,
+ .gpt_irq_enable = imx31_gpt_irq_enable,
+ .gpt_irq_disable = imx31_gpt_irq_disable,
+ .gpt_irq_acknowledge = imx31_gpt_irq_acknowledge,
+ .gpt_setup_tctl = imx31_gpt_setup_tctl,
+ .set_next_event = v2_set_next_event,
+};
+
+static const struct imx_gpt_data imx6dl_gpt_data = {
+ .reg_tstat = V2_TSTAT,
+ .reg_tcn = V2_TCN,
+ .reg_tcmp = V2_TCMP,
+ .gpt_irq_enable = imx6dl_gpt_irq_enable,
+ .gpt_irq_disable = imx6dl_gpt_irq_disable,
+ .gpt_irq_acknowledge = imx6dl_gpt_irq_acknowledge,
+ .gpt_setup_tctl = imx6dl_gpt_setup_tctl,
+ .set_next_event = v2_set_next_event,
+};
+
+static void __init _mxc_timer_init(struct imx_timer *imxtm)
+{
+ switch (imxtm->type) {
+ case GPT_TYPE_IMX1:
+ imxtm->gpt = &imx1_gpt_data;
+ break;
+ case GPT_TYPE_IMX21:
+ imxtm->gpt = &imx21_gpt_data;
+ break;
+ case GPT_TYPE_IMX31:
+ imxtm->gpt = &imx31_gpt_data;
+ break;
+ case GPT_TYPE_IMX6DL:
+ imxtm->gpt = &imx6dl_gpt_data;
+ break;
+ default:
+ BUG();
+ }
+
+ if (IS_ERR(imxtm->clk_per)) {
+ pr_err("i.MX timer: unable to get clk\n");
+ return;
+ }
+
+ if (!IS_ERR(imxtm->clk_ipg))
+ clk_prepare_enable(imxtm->clk_ipg);
+
+ clk_prepare_enable(imxtm->clk_per);
+
+ /*
+ * Initialise to a known state (all timers off, and timing reset)
+ */
+
+ writel_relaxed(0, imxtm->base + MXC_TCTL);
+ writel_relaxed(0, imxtm->base + MXC_TPRER); /* see datasheet note */
+
+ imxtm->gpt->gpt_setup_tctl(imxtm);
+
+ /* init and register the timer to the framework */
+ mxc_clocksource_init(imxtm);
+ mxc_clockevent_init(imxtm);
+}
+
+void __init mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type)
+{
+ struct imx_timer *imxtm;
+
+ imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL);
+ BUG_ON(!imxtm);
+
+ imxtm->clk_per = clk_get_sys("imx-gpt.0", "per");
+ imxtm->clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
+
+ imxtm->base = ioremap(pbase, SZ_4K);
+ BUG_ON(!imxtm->base);
+
+ imxtm->type = type;
+
+ _mxc_timer_init(imxtm);
+}
+
+static void __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type type)
+{
+ struct imx_timer *imxtm;
+ static int initialized;
+
+ /* Support one instance only */
+ if (initialized)
+ return;
+
+ imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL);
+ BUG_ON(!imxtm);
+
+ imxtm->base = of_iomap(np, 0);
+ WARN_ON(!imxtm->base);
+ imxtm->irq = irq_of_parse_and_map(np, 0);
+
+ imxtm->clk_ipg = of_clk_get_by_name(np, "ipg");
+
+ /* Try osc_per first, and fall back to per otherwise */
+ imxtm->clk_per = of_clk_get_by_name(np, "osc_per");
+ if (IS_ERR(imxtm->clk_per))
+ imxtm->clk_per = of_clk_get_by_name(np, "per");
+
+ imxtm->type = type;
+
+ _mxc_timer_init(imxtm);
+
+ initialized = 1;
+}
+
+static void __init imx1_timer_init_dt(struct device_node *np)
+{
+ mxc_timer_init_dt(np, GPT_TYPE_IMX1);
+}
+
+static void __init imx21_timer_init_dt(struct device_node *np)
+{
+ mxc_timer_init_dt(np, GPT_TYPE_IMX21);
+}
+
+static void __init imx31_timer_init_dt(struct device_node *np)
+{
+ enum imx_gpt_type type = GPT_TYPE_IMX31;
+
+ /*
+ * We were using the same compatible string for i.MX6Q/D and i.MX6DL/S
+ * GPT device, while they actually have different programming model.
+ * This is a workaround to keep the existing i.MX6DL/S DTBs continue
+ * working with the new kernel.
+ */
+ if (of_machine_is_compatible("fsl,imx6dl"))
+ type = GPT_TYPE_IMX6DL;
+
+ mxc_timer_init_dt(np, type);
+}
+
+static void __init imx6dl_timer_init_dt(struct device_node *np)
+{
+ mxc_timer_init_dt(np, GPT_TYPE_IMX6DL);
+}
+
+CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt);
diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c
index b9efd30513d5..a68866e0ecd4 100644
--- a/drivers/clocksource/timer-integrator-ap.c
+++ b/drivers/clocksource/timer-integrator-ap.c
@@ -26,7 +26,8 @@
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/sched_clock.h>
-#include <asm/hardware/arm_timer.h>
+
+#include "timer-sp.h"
static void __iomem * sched_clk_base;
@@ -166,7 +167,7 @@ static void __init integrator_ap_timer_init_of(struct device_node *node)
struct device_node *sec_node;
base = of_io_request_and_map(node, 0, "integrator-timer");
- if (!base)
+ if (IS_ERR(base))
return;
clk = of_clk_get(node, 0);
diff --git a/arch/arm/include/asm/hardware/arm_timer.h b/drivers/clocksource/timer-sp.h
index d6030ff599db..050d88561e9c 100644
--- a/arch/arm/include/asm/hardware/arm_timer.h
+++ b/drivers/clocksource/timer-sp.h
@@ -1,6 +1,3 @@
-#ifndef __ASM_ARM_HARDWARE_ARM_TIMER_H
-#define __ASM_ARM_HARDWARE_ARM_TIMER_H
-
/*
* ARM timer implementation, found in Integrator, Versatile and Realview
* platforms. Not all platforms support all registers and bits in these
@@ -31,5 +28,3 @@
#define TIMER_RIS 0x10 /* CVR ro */
#define TIMER_MIS 0x14 /* CVR ro */
#define TIMER_BGLOAD 0x18 /* CVR rw */
-
-#endif
diff --git a/arch/arm/common/timer-sp.c b/drivers/clocksource/timer-sp804.c
index 19211324772f..ca02503f17d1 100644
--- a/arch/arm/common/timer-sp.c
+++ b/drivers/clocksource/timer-sp804.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/common/timer-sp.c
+ * linux/drivers/clocksource/timer-sp.c
*
* Copyright (C) 1999 - 2003 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
@@ -30,8 +30,9 @@
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
-#include <asm/hardware/arm_timer.h>
-#include <asm/hardware/timer-sp.h>
+#include <clocksource/timer-sp804.h>
+
+#include "timer-sp.h"
static long __init sp804_get_clock_rate(struct clk *clk)
{
@@ -71,6 +72,11 @@ static u64 notrace sp804_read(void)
return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
}
+void __init sp804_timer_disable(void __iomem *base)
+{
+ writel(0, base + TIMER_CTRL);
+}
+
void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base,
const char *name,
struct clk *clk,
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
new file mode 100644
index 000000000000..a97e8b50701c
--- /dev/null
+++ b/drivers/clocksource/timer-stm32.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Inspired by time-efm32.c from Uwe Kleine-Koenig
+ */
+
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+
+#define TIM_CR1 0x00
+#define TIM_DIER 0x0c
+#define TIM_SR 0x10
+#define TIM_EGR 0x14
+#define TIM_PSC 0x28
+#define TIM_ARR 0x2c
+
+#define TIM_CR1_CEN BIT(0)
+#define TIM_CR1_OPM BIT(3)
+#define TIM_CR1_ARPE BIT(7)
+
+#define TIM_DIER_UIE BIT(0)
+
+#define TIM_SR_UIF BIT(0)
+
+#define TIM_EGR_UG BIT(0)
+
+struct stm32_clock_event_ddata {
+ struct clock_event_device evtdev;
+ unsigned periodic_top;
+ void __iomem *base;
+};
+
+static void stm32_clock_event_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evtdev)
+{
+ struct stm32_clock_event_ddata *data =
+ container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
+ void *base = data->base;
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ writel_relaxed(data->periodic_top, base + TIM_ARR);
+ writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ default:
+ writel_relaxed(0, base + TIM_CR1);
+ break;
+ }
+}
+
+static int stm32_clock_event_set_next_event(unsigned long evt,
+ struct clock_event_device *evtdev)
+{
+ struct stm32_clock_event_ddata *data =
+ container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
+
+ writel_relaxed(evt, data->base + TIM_ARR);
+ writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN,
+ data->base + TIM_CR1);
+
+ return 0;
+}
+
+static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
+{
+ struct stm32_clock_event_ddata *data = dev_id;
+
+ writel_relaxed(0, data->base + TIM_SR);
+
+ data->evtdev.event_handler(&data->evtdev);
+
+ return IRQ_HANDLED;
+}
+
+static struct stm32_clock_event_ddata clock_event_ddata = {
+ .evtdev = {
+ .name = "stm32 clockevent",
+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+ .set_mode = stm32_clock_event_set_mode,
+ .set_next_event = stm32_clock_event_set_next_event,
+ .rating = 200,
+ },
+};
+
+static void __init stm32_clockevent_init(struct device_node *np)
+{
+ struct stm32_clock_event_ddata *data = &clock_event_ddata;
+ struct clk *clk;
+ struct reset_control *rstc;
+ unsigned long rate, max_delta;
+ int irq, ret, bits, prescaler = 1;
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ pr_err("failed to get clock for clockevent (%d)\n", ret);
+ goto err_clk_get;
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ pr_err("failed to enable timer clock for clockevent (%d)\n",
+ ret);
+ goto err_clk_enable;
+ }
+
+ rate = clk_get_rate(clk);
+
+ rstc = of_reset_control_get(np, NULL);
+ if (!IS_ERR(rstc)) {
+ reset_control_assert(rstc);
+ reset_control_deassert(rstc);
+ }
+
+ data->base = of_iomap(np, 0);
+ if (!data->base) {
+ pr_err("failed to map registers for clockevent\n");
+ goto err_iomap;
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ pr_err("%s: failed to get irq.\n", np->full_name);
+ goto err_get_irq;
+ }
+
+ /* Detect whether the timer is 16 or 32 bits */
+ writel_relaxed(~0U, data->base + TIM_ARR);
+ max_delta = readl_relaxed(data->base + TIM_ARR);
+ if (max_delta == ~0U) {
+ prescaler = 1;
+ bits = 32;
+ } else {
+ prescaler = 1024;
+ bits = 16;
+ }
+ writel_relaxed(0, data->base + TIM_ARR);
+
+ writel_relaxed(prescaler - 1, data->base + TIM_PSC);
+ writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
+ writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
+ writel_relaxed(0, data->base + TIM_SR);
+
+ data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
+
+ clockevents_config_and_register(&data->evtdev,
+ DIV_ROUND_CLOSEST(rate, prescaler),
+ 0x1, max_delta);
+
+ ret = request_irq(irq, stm32_clock_event_handler, IRQF_TIMER,
+ "stm32 clockevent", data);
+ if (ret) {
+ pr_err("%s: failed to request irq.\n", np->full_name);
+ goto err_get_irq;
+ }
+
+ pr_info("%s: STM32 clockevent driver initialized (%d bits)\n",
+ np->full_name, bits);
+
+ return;
+
+err_get_irq:
+ iounmap(data->base);
+err_iomap:
+ clk_disable_unprepare(clk);
+err_clk_enable:
+ clk_put(clk);
+err_clk_get:
+ return;
+}
+
+CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init);
diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c
index 28aa4b7bb602..0ffb4ea7c925 100644
--- a/drivers/clocksource/timer-sun5i.c
+++ b/drivers/clocksource/timer-sun5i.c
@@ -324,7 +324,7 @@ static void __init sun5i_timer_init(struct device_node *node)
int irq;
timer_base = of_io_request_and_map(node, 0, of_node_full_name(node));
- if (!timer_base)
+ if (IS_ERR(timer_base))
panic("Can't map registers");
irq = irq_of_parse_and_map(node, 0);
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 4f3dbc8cf729..611cb09239eb 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -5,7 +5,7 @@
# big LITTLE core layer and glue drivers
config ARM_BIG_LITTLE_CPUFREQ
tristate "Generic ARM big LITTLE CPUfreq driver"
- depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK
+ depends on (ARM_CPU_TOPOLOGY || ARM64) && HAVE_CLK
select PM_OPP
help
This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index b0c18ed8d83f..0136dfcdabf0 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -699,13 +699,14 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
dmi_check_system(sw_any_bug_dmi_table);
if (bios_with_sw_any_bug && !policy_is_shared(policy)) {
policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
- cpumask_copy(policy->cpus, cpu_core_mask(cpu));
+ cpumask_copy(policy->cpus, topology_core_cpumask(cpu));
}
if (check_amd_hwpstate_cpu(cpu) && !acpi_pstate_strict) {
cpumask_clear(policy->cpus);
cpumask_set_cpu(cpu, policy->cpus);
- cpumask_copy(data->freqdomain_cpus, cpu_sibling_mask(cpu));
+ cpumask_copy(data->freqdomain_cpus,
+ topology_sibling_cpumask(cpu));
policy->shared_type = CPUFREQ_SHARED_TYPE_HW;
pr_info_once(PFX "overriding BIOS provided _PSD data\n");
}
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index e1a6ba66a7f5..f1e42f8ce0fc 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -31,7 +31,6 @@
#include <linux/slab.h>
#include <linux/topology.h>
#include <linux/types.h>
-#include <asm/bL_switcher.h>
#include "arm_big_little.h"
@@ -41,12 +40,16 @@
#define MAX_CLUSTERS 2
#ifdef CONFIG_BL_SWITCHER
+#include <asm/bL_switcher.h>
static bool bL_switching_enabled;
#define is_bL_switching_enabled() bL_switching_enabled
#define set_switching_enabled(x) (bL_switching_enabled = (x))
#else
#define is_bL_switching_enabled() false
#define set_switching_enabled(x) do { } while (0)
+#define bL_switch_request(...) do { } while (0)
+#define bL_switcher_put_enabled() do { } while (0)
+#define bL_switcher_get_enabled() do { } while (0)
#endif
#define ACTUAL_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq << 1 : freq)
@@ -186,6 +189,15 @@ bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate)
mutex_unlock(&cluster_lock[old_cluster]);
}
+ /*
+ * FIXME: clk_set_rate has to handle the case where clk_change_rate
+ * can fail due to hardware or firmware issues. Until the clk core
+ * layer is fixed, we can check here. In most of the cases we will
+ * be reading only the cached value anyway. This needs to be removed
+ * once clk core is fixed.
+ */
+ if (bL_cpufreq_get_rate(cpu) != new_rate)
+ return -EIO;
return 0;
}
@@ -322,7 +334,6 @@ static void put_cluster_clk_and_freq_table(struct device *cpu_dev)
static int _get_cluster_clk_and_freq_table(struct device *cpu_dev)
{
u32 cluster = raw_cpu_to_cluster(cpu_dev->id);
- char name[14] = "cpu-cluster.";
int ret;
if (freq_table[cluster])
@@ -342,8 +353,7 @@ static int _get_cluster_clk_and_freq_table(struct device *cpu_dev)
goto free_opp_table;
}
- name[12] = cluster + '0';
- clk[cluster] = clk_get(cpu_dev, name);
+ clk[cluster] = clk_get(cpu_dev, NULL);
if (!IS_ERR(clk[cluster])) {
dev_dbg(cpu_dev, "%s: clk: %p & freq table: %p, cluster: %d\n",
__func__, clk[cluster], freq_table[cluster],
@@ -506,6 +516,7 @@ static struct cpufreq_driver bL_cpufreq_driver = {
.attr = cpufreq_generic_attr,
};
+#ifdef CONFIG_BL_SWITCHER
static int bL_cpufreq_switcher_notifier(struct notifier_block *nfb,
unsigned long action, void *_arg)
{
@@ -538,6 +549,20 @@ static struct notifier_block bL_switcher_notifier = {
.notifier_call = bL_cpufreq_switcher_notifier,
};
+static int __bLs_register_notifier(void)
+{
+ return bL_switcher_register_notifier(&bL_switcher_notifier);
+}
+
+static int __bLs_unregister_notifier(void)
+{
+ return bL_switcher_unregister_notifier(&bL_switcher_notifier);
+}
+#else
+static int __bLs_register_notifier(void) { return 0; }
+static int __bLs_unregister_notifier(void) { return 0; }
+#endif
+
int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
{
int ret, i;
@@ -555,8 +580,7 @@ int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
arm_bL_ops = ops;
- ret = bL_switcher_get_enabled();
- set_switching_enabled(ret);
+ set_switching_enabled(bL_switcher_get_enabled());
for (i = 0; i < MAX_CLUSTERS; i++)
mutex_init(&cluster_lock[i]);
@@ -567,7 +591,7 @@ int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
__func__, ops->name, ret);
arm_bL_ops = NULL;
} else {
- ret = bL_switcher_register_notifier(&bL_switcher_notifier);
+ ret = __bLs_register_notifier();
if (ret) {
cpufreq_unregister_driver(&bL_cpufreq_driver);
arm_bL_ops = NULL;
@@ -591,7 +615,7 @@ void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
}
bL_switcher_get_enabled();
- bL_switcher_unregister_notifier(&bL_switcher_notifier);
+ __bLs_unregister_notifier();
cpufreq_unregister_driver(&bL_cpufreq_driver);
bL_switcher_put_enabled();
pr_info("%s: Un-registered platform driver: %s\n", __func__,
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index bab67db54b7e..528a82bf5038 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -416,6 +416,7 @@ static struct platform_driver dt_cpufreq_platdrv = {
};
module_platform_driver(dt_cpufreq_platdrv);
+MODULE_ALIAS("platform:cpufreq-dt");
MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
MODULE_DESCRIPTION("Generic cpufreq driver");
diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c
index a2258090b58b..db69eeb501a7 100644
--- a/drivers/cpufreq/cpufreq-nforce2.c
+++ b/drivers/cpufreq/cpufreq-nforce2.c
@@ -414,7 +414,7 @@ static int nforce2_detect_chipset(void)
* nforce2_init - initializes the nForce2 CPUFreq driver
*
* Initializes the nForce2 FSB support. Returns -ENODEV on unsupported
- * devices, -EINVAL on problems during initiatization, and zero on
+ * devices, -EINVAL on problems during initialization, and zero on
* success.
*/
static int __init nforce2_init(void)
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 8ae655c364f4..b612411655f9 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -31,10 +31,62 @@
#include <linux/tick.h>
#include <trace/events/power.h>
-/* Macros to iterate over lists */
-/* Iterate over online CPUs policies */
static LIST_HEAD(cpufreq_policy_list);
-#define for_each_policy(__policy) \
+
+static inline bool policy_is_inactive(struct cpufreq_policy *policy)
+{
+ return cpumask_empty(policy->cpus);
+}
+
+static bool suitable_policy(struct cpufreq_policy *policy, bool active)
+{
+ return active == !policy_is_inactive(policy);
+}
+
+/* Finds Next Acive/Inactive policy */
+static struct cpufreq_policy *next_policy(struct cpufreq_policy *policy,
+ bool active)
+{
+ do {
+ policy = list_next_entry(policy, policy_list);
+
+ /* No more policies in the list */
+ if (&policy->policy_list == &cpufreq_policy_list)
+ return NULL;
+ } while (!suitable_policy(policy, active));
+
+ return policy;
+}
+
+static struct cpufreq_policy *first_policy(bool active)
+{
+ struct cpufreq_policy *policy;
+
+ /* No policies in the list */
+ if (list_empty(&cpufreq_policy_list))
+ return NULL;
+
+ policy = list_first_entry(&cpufreq_policy_list, typeof(*policy),
+ policy_list);
+
+ if (!suitable_policy(policy, active))
+ policy = next_policy(policy, active);
+
+ return policy;
+}
+
+/* Macros to iterate over CPU policies */
+#define for_each_suitable_policy(__policy, __active) \
+ for (__policy = first_policy(__active); \
+ __policy; \
+ __policy = next_policy(__policy, __active))
+
+#define for_each_active_policy(__policy) \
+ for_each_suitable_policy(__policy, true)
+#define for_each_inactive_policy(__policy) \
+ for_each_suitable_policy(__policy, false)
+
+#define for_each_policy(__policy) \
list_for_each_entry(__policy, &cpufreq_policy_list, policy_list)
/* Iterate over governors */
@@ -49,13 +101,9 @@ static LIST_HEAD(cpufreq_governor_list);
*/
static struct cpufreq_driver *cpufreq_driver;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
-static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback);
static DEFINE_RWLOCK(cpufreq_driver_lock);
DEFINE_MUTEX(cpufreq_governor_lock);
-/* This one keeps track of the previously set governor of a removed CPU */
-static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
-
/* Flag to suspend/resume CPUFreq governors */
static bool cpufreq_suspended;
@@ -178,7 +226,7 @@ int cpufreq_generic_init(struct cpufreq_policy *policy,
policy->cpuinfo.transition_latency = transition_latency;
/*
- * The driver only supports the SMP configuartion where all processors
+ * The driver only supports the SMP configuration where all processors
* share the clock and voltage and clock.
*/
cpumask_setall(policy->cpus);
@@ -187,10 +235,18 @@ int cpufreq_generic_init(struct cpufreq_policy *policy,
}
EXPORT_SYMBOL_GPL(cpufreq_generic_init);
-unsigned int cpufreq_generic_get(unsigned int cpu)
+/* Only for cpufreq core internal use */
+struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
{
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
+ return policy && cpumask_test_cpu(cpu, policy->cpus) ? policy : NULL;
+}
+
+unsigned int cpufreq_generic_get(unsigned int cpu)
+{
+ struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
+
if (!policy || IS_ERR(policy->clk)) {
pr_err("%s: No %s associated to cpu: %d\n",
__func__, policy ? "clk" : "policy", cpu);
@@ -201,18 +257,29 @@ unsigned int cpufreq_generic_get(unsigned int cpu)
}
EXPORT_SYMBOL_GPL(cpufreq_generic_get);
-/* Only for cpufreq core internal use */
-struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
-{
- return per_cpu(cpufreq_cpu_data, cpu);
-}
-
+/**
+ * cpufreq_cpu_get: returns policy for a cpu and marks it busy.
+ *
+ * @cpu: cpu to find policy for.
+ *
+ * This returns policy for 'cpu', returns NULL if it doesn't exist.
+ * It also increments the kobject reference count to mark it busy and so would
+ * require a corresponding call to cpufreq_cpu_put() to decrement it back.
+ * If corresponding call cpufreq_cpu_put() isn't made, the policy wouldn't be
+ * freed as that depends on the kobj count.
+ *
+ * It also takes a read-lock of 'cpufreq_rwsem' and doesn't put it back if a
+ * valid policy is found. This is done to make sure the driver doesn't get
+ * unregistered while the policy is being used.
+ *
+ * Return: A valid policy on success, otherwise NULL on failure.
+ */
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
{
struct cpufreq_policy *policy = NULL;
unsigned long flags;
- if (cpu >= nr_cpu_ids)
+ if (WARN_ON(cpu >= nr_cpu_ids))
return NULL;
if (!down_read_trylock(&cpufreq_rwsem))
@@ -223,7 +290,7 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
if (cpufreq_driver) {
/* get the CPU */
- policy = per_cpu(cpufreq_cpu_data, cpu);
+ policy = cpufreq_cpu_get_raw(cpu);
if (policy)
kobject_get(&policy->kobj);
}
@@ -237,6 +304,16 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
}
EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
+/**
+ * cpufreq_cpu_put: Decrements the usage count of a policy
+ *
+ * @policy: policy earlier returned by cpufreq_cpu_get().
+ *
+ * This decrements the kobject reference count incremented earlier by calling
+ * cpufreq_cpu_get().
+ *
+ * It also drops the read-lock of 'cpufreq_rwsem' taken at cpufreq_cpu_get().
+ */
void cpufreq_cpu_put(struct cpufreq_policy *policy)
{
kobject_put(&policy->kobj);
@@ -798,11 +875,18 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
down_write(&policy->rwsem);
+ /* Updating inactive policies is invalid, so avoid doing that. */
+ if (unlikely(policy_is_inactive(policy))) {
+ ret = -EBUSY;
+ goto unlock_policy_rwsem;
+ }
+
if (fattr->store)
ret = fattr->store(policy, buf, count);
else
ret = -EIO;
+unlock_policy_rwsem:
up_write(&policy->rwsem);
up_read(&cpufreq_rwsem);
@@ -873,28 +957,67 @@ void cpufreq_sysfs_remove_file(const struct attribute *attr)
}
EXPORT_SYMBOL(cpufreq_sysfs_remove_file);
-/* symlink affected CPUs */
+static int add_cpu_dev_symlink(struct cpufreq_policy *policy, int cpu)
+{
+ struct device *cpu_dev;
+
+ pr_debug("%s: Adding symlink for CPU: %u\n", __func__, cpu);
+
+ if (!policy)
+ return 0;
+
+ cpu_dev = get_cpu_device(cpu);
+ if (WARN_ON(!cpu_dev))
+ return 0;
+
+ return sysfs_create_link(&cpu_dev->kobj, &policy->kobj, "cpufreq");
+}
+
+static void remove_cpu_dev_symlink(struct cpufreq_policy *policy, int cpu)
+{
+ struct device *cpu_dev;
+
+ pr_debug("%s: Removing symlink for CPU: %u\n", __func__, cpu);
+
+ cpu_dev = get_cpu_device(cpu);
+ if (WARN_ON(!cpu_dev))
+ return;
+
+ sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
+}
+
+/* Add/remove symlinks for all related CPUs */
static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy)
{
unsigned int j;
int ret = 0;
- for_each_cpu(j, policy->cpus) {
- struct device *cpu_dev;
-
- if (j == policy->cpu)
+ /* Some related CPUs might not be present (physically hotplugged) */
+ for_each_cpu_and(j, policy->related_cpus, cpu_present_mask) {
+ if (j == policy->kobj_cpu)
continue;
- pr_debug("Adding link for CPU: %u\n", j);
- cpu_dev = get_cpu_device(j);
- ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
- "cpufreq");
+ ret = add_cpu_dev_symlink(policy, j);
if (ret)
break;
}
+
return ret;
}
+static void cpufreq_remove_dev_symlink(struct cpufreq_policy *policy)
+{
+ unsigned int j;
+
+ /* Some related CPUs might not be present (physically hotplugged) */
+ for_each_cpu_and(j, policy->related_cpus, cpu_present_mask) {
+ if (j == policy->kobj_cpu)
+ continue;
+
+ remove_cpu_dev_symlink(policy, j);
+ }
+}
+
static int cpufreq_add_dev_interface(struct cpufreq_policy *policy,
struct device *dev)
{
@@ -937,7 +1060,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)
memcpy(&new_policy, policy, sizeof(*policy));
/* Update governor of new_policy to the governor used before hotplug */
- gov = find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu));
+ gov = find_governor(policy->last_governor);
if (gov)
pr_debug("Restoring governor %s for cpu %d\n",
policy->governor->name, policy->cpu);
@@ -963,7 +1086,10 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
unsigned int cpu, struct device *dev)
{
int ret = 0;
- unsigned long flags;
+
+ /* Has this CPU been taken care of already? */
+ if (cpumask_test_cpu(cpu, policy->cpus))
+ return 0;
if (has_target()) {
ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
@@ -974,13 +1100,7 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
}
down_write(&policy->rwsem);
-
- write_lock_irqsave(&cpufreq_driver_lock, flags);
-
cpumask_set_cpu(cpu, policy->cpus);
- per_cpu(cpufreq_cpu_data, cpu) = policy;
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
up_write(&policy->rwsem);
if (has_target()) {
@@ -994,7 +1114,7 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
}
}
- return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
+ return 0;
}
static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
@@ -1003,20 +1123,25 @@ static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
unsigned long flags;
read_lock_irqsave(&cpufreq_driver_lock, flags);
-
- policy = per_cpu(cpufreq_cpu_data_fallback, cpu);
-
+ policy = per_cpu(cpufreq_cpu_data, cpu);
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
- if (policy)
- policy->governor = NULL;
+ if (likely(policy)) {
+ /* Policy should be inactive here */
+ WARN_ON(!policy_is_inactive(policy));
+
+ down_write(&policy->rwsem);
+ policy->cpu = cpu;
+ up_write(&policy->rwsem);
+ }
return policy;
}
-static struct cpufreq_policy *cpufreq_policy_alloc(void)
+static struct cpufreq_policy *cpufreq_policy_alloc(struct device *dev)
{
struct cpufreq_policy *policy;
+ int ret;
policy = kzalloc(sizeof(*policy), GFP_KERNEL);
if (!policy)
@@ -1028,6 +1153,13 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void)
if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
goto err_free_cpumask;
+ ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &dev->kobj,
+ "cpufreq");
+ if (ret) {
+ pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
+ goto err_free_rcpumask;
+ }
+
INIT_LIST_HEAD(&policy->policy_list);
init_rwsem(&policy->rwsem);
spin_lock_init(&policy->transition_lock);
@@ -1035,8 +1167,15 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void)
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update);
+ policy->cpu = dev->id;
+
+ /* Set this once on allocation */
+ policy->kobj_cpu = dev->id;
+
return policy;
+err_free_rcpumask:
+ free_cpumask_var(policy->related_cpus);
err_free_cpumask:
free_cpumask_var(policy->cpus);
err_free_policy:
@@ -1045,18 +1184,20 @@ err_free_policy:
return NULL;
}
-static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
+static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy, bool notify)
{
struct kobject *kobj;
struct completion *cmp;
- blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
- CPUFREQ_REMOVE_POLICY, policy);
+ if (notify)
+ blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
+ CPUFREQ_REMOVE_POLICY, policy);
- down_read(&policy->rwsem);
+ down_write(&policy->rwsem);
+ cpufreq_remove_dev_symlink(policy);
kobj = &policy->kobj;
cmp = &policy->kobj_unregister;
- up_read(&policy->rwsem);
+ up_write(&policy->rwsem);
kobject_put(kobj);
/*
@@ -1069,68 +1210,64 @@ static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
pr_debug("wait complete\n");
}
-static void cpufreq_policy_free(struct cpufreq_policy *policy)
-{
- free_cpumask_var(policy->related_cpus);
- free_cpumask_var(policy->cpus);
- kfree(policy);
-}
-
-static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu,
- struct device *cpu_dev)
+static void cpufreq_policy_free(struct cpufreq_policy *policy, bool notify)
{
- int ret;
-
- if (WARN_ON(cpu == policy->cpu))
- return 0;
+ unsigned long flags;
+ int cpu;
- /* Move kobject to the new policy->cpu */
- ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
- if (ret) {
- pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
- return ret;
- }
+ /* Remove policy from list */
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ list_del(&policy->policy_list);
- down_write(&policy->rwsem);
- policy->cpu = cpu;
- up_write(&policy->rwsem);
+ for_each_cpu(cpu, policy->related_cpus)
+ per_cpu(cpufreq_cpu_data, cpu) = NULL;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
- return 0;
+ cpufreq_policy_put_kobj(policy, notify);
+ free_cpumask_var(policy->related_cpus);
+ free_cpumask_var(policy->cpus);
+ kfree(policy);
}
-static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
+/**
+ * cpufreq_add_dev - add a CPU device
+ *
+ * Adds the cpufreq interface for a CPU device.
+ *
+ * The Oracle says: try running cpufreq registration/unregistration concurrently
+ * with with cpu hotplugging and all hell will break loose. Tried to clean this
+ * mess up, but more thorough testing is needed. - Mathieu
+ */
+static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{
unsigned int j, cpu = dev->id;
int ret = -ENOMEM;
struct cpufreq_policy *policy;
unsigned long flags;
- bool recover_policy = cpufreq_suspended;
-
- if (cpu_is_offline(cpu))
- return 0;
+ bool recover_policy = !sif;
pr_debug("adding CPU %u\n", cpu);
- /* check whether a different CPU already registered this
- * CPU because it is in the same boat. */
- policy = cpufreq_cpu_get_raw(cpu);
- if (unlikely(policy))
- return 0;
+ /*
+ * Only possible if 'cpu' wasn't physically present earlier and we are
+ * here from subsys_interface add callback. A hotplug notifier will
+ * follow and we will handle it like logical CPU hotplug then. For now,
+ * just create the sysfs link.
+ */
+ if (cpu_is_offline(cpu))
+ return add_cpu_dev_symlink(per_cpu(cpufreq_cpu_data, cpu), cpu);
if (!down_read_trylock(&cpufreq_rwsem))
return 0;
- /* Check if this cpu was hot-unplugged earlier and has siblings */
- read_lock_irqsave(&cpufreq_driver_lock, flags);
- for_each_policy(policy) {
- if (cpumask_test_cpu(cpu, policy->related_cpus)) {
- read_unlock_irqrestore(&cpufreq_driver_lock, flags);
- ret = cpufreq_add_policy_cpu(policy, cpu, dev);
- up_read(&cpufreq_rwsem);
- return ret;
- }
+ /* Check if this CPU already has a policy to manage it */
+ policy = per_cpu(cpufreq_cpu_data, cpu);
+ if (policy && !policy_is_inactive(policy)) {
+ WARN_ON(!cpumask_test_cpu(cpu, policy->related_cpus));
+ ret = cpufreq_add_policy_cpu(policy, cpu, dev);
+ up_read(&cpufreq_rwsem);
+ return ret;
}
- read_unlock_irqrestore(&cpufreq_driver_lock, flags);
/*
* Restore the saved policy when doing light-weight init and fall back
@@ -1139,22 +1276,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
policy = recover_policy ? cpufreq_policy_restore(cpu) : NULL;
if (!policy) {
recover_policy = false;
- policy = cpufreq_policy_alloc();
+ policy = cpufreq_policy_alloc(dev);
if (!policy)
goto nomem_out;
}
- /*
- * In the resume path, since we restore a saved policy, the assignment
- * to policy->cpu is like an update of the existing policy, rather than
- * the creation of a brand new one. So we need to perform this update
- * by invoking update_policy_cpu().
- */
- if (recover_policy && cpu != policy->cpu)
- WARN_ON(update_policy_cpu(policy, cpu, dev));
- else
- policy->cpu = cpu;
-
cpumask_copy(policy->cpus, cpumask_of(cpu));
/* call driver. From then on the cpufreq must be able
@@ -1181,21 +1307,12 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
policy->user_policy.min = policy->min;
policy->user_policy.max = policy->max;
- /* prepare interface data */
- ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
- &dev->kobj, "cpufreq");
- if (ret) {
- pr_err("%s: failed to init policy->kobj: %d\n",
- __func__, ret);
- goto err_init_policy_kobj;
- }
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ for_each_cpu(j, policy->related_cpus)
+ per_cpu(cpufreq_cpu_data, j) = policy;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
}
- write_lock_irqsave(&cpufreq_driver_lock, flags);
- for_each_cpu(j, policy->cpus)
- per_cpu(cpufreq_cpu_data, j) = policy;
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
policy->cur = cpufreq_driver->get(policy->cpu);
if (!policy->cur) {
@@ -1253,11 +1370,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
goto err_out_unregister;
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_CREATE_POLICY, policy);
- }
- write_lock_irqsave(&cpufreq_driver_lock, flags);
- list_add(&policy->policy_list, &cpufreq_policy_list);
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
+ list_add(&policy->policy_list, &cpufreq_policy_list);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ }
cpufreq_init_policy(policy);
@@ -1281,68 +1398,28 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
err_out_unregister:
err_get_freq:
- write_lock_irqsave(&cpufreq_driver_lock, flags);
- for_each_cpu(j, policy->cpus)
- per_cpu(cpufreq_cpu_data, j) = NULL;
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
- if (!recover_policy) {
- kobject_put(&policy->kobj);
- wait_for_completion(&policy->kobj_unregister);
- }
-err_init_policy_kobj:
up_write(&policy->rwsem);
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);
err_set_policy_cpu:
- if (recover_policy) {
- /* Do not leave stale fallback data behind. */
- per_cpu(cpufreq_cpu_data_fallback, cpu) = NULL;
- cpufreq_policy_put_kobj(policy);
- }
- cpufreq_policy_free(policy);
-
+ cpufreq_policy_free(policy, recover_policy);
nomem_out:
up_read(&cpufreq_rwsem);
return ret;
}
-/**
- * cpufreq_add_dev - add a CPU device
- *
- * Adds the cpufreq interface for a CPU device.
- *
- * The Oracle says: try running cpufreq registration/unregistration concurrently
- * with with cpu hotplugging and all hell will break loose. Tried to clean this
- * mess up, but more thorough testing is needed. - Mathieu
- */
-static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
-{
- return __cpufreq_add_dev(dev, sif);
-}
-
static int __cpufreq_remove_dev_prepare(struct device *dev,
struct subsys_interface *sif)
{
- unsigned int cpu = dev->id, cpus;
- int ret;
- unsigned long flags;
+ unsigned int cpu = dev->id;
+ int ret = 0;
struct cpufreq_policy *policy;
pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
- write_lock_irqsave(&cpufreq_driver_lock, flags);
-
- policy = per_cpu(cpufreq_cpu_data, cpu);
-
- /* Save the policy somewhere when doing a light-weight tear-down */
- if (cpufreq_suspended)
- per_cpu(cpufreq_cpu_data_fallback, cpu) = policy;
-
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
+ policy = cpufreq_cpu_get_raw(cpu);
if (!policy) {
pr_debug("%s: No cpu_data found\n", __func__);
return -EINVAL;
@@ -1354,108 +1431,75 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
pr_err("%s: Failed to stop governor\n", __func__);
return ret;
}
-
- strncpy(per_cpu(cpufreq_cpu_governor, cpu),
- policy->governor->name, CPUFREQ_NAME_LEN);
}
- down_read(&policy->rwsem);
- cpus = cpumask_weight(policy->cpus);
- up_read(&policy->rwsem);
+ down_write(&policy->rwsem);
+ cpumask_clear_cpu(cpu, policy->cpus);
- if (cpu != policy->cpu) {
- sysfs_remove_link(&dev->kobj, "cpufreq");
- } else if (cpus > 1) {
+ if (policy_is_inactive(policy)) {
+ if (has_target())
+ strncpy(policy->last_governor, policy->governor->name,
+ CPUFREQ_NAME_LEN);
+ } else if (cpu == policy->cpu) {
/* Nominate new CPU */
- int new_cpu = cpumask_any_but(policy->cpus, cpu);
- struct device *cpu_dev = get_cpu_device(new_cpu);
+ policy->cpu = cpumask_any(policy->cpus);
+ }
+ up_write(&policy->rwsem);
- sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
- ret = update_policy_cpu(policy, new_cpu, cpu_dev);
- if (ret) {
- if (sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
- "cpufreq"))
- pr_err("%s: Failed to restore kobj link to cpu:%d\n",
- __func__, cpu_dev->id);
- return ret;
- }
+ /* Start governor again for active policy */
+ if (!policy_is_inactive(policy)) {
+ if (has_target()) {
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ if (!ret)
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
- if (!cpufreq_suspended)
- pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
- __func__, new_cpu, cpu);
+ if (ret)
+ pr_err("%s: Failed to start governor\n", __func__);
+ }
} else if (cpufreq_driver->stop_cpu) {
cpufreq_driver->stop_cpu(policy);
}
- return 0;
+ return ret;
}
static int __cpufreq_remove_dev_finish(struct device *dev,
struct subsys_interface *sif)
{
- unsigned int cpu = dev->id, cpus;
+ unsigned int cpu = dev->id;
int ret;
- unsigned long flags;
- struct cpufreq_policy *policy;
-
- write_lock_irqsave(&cpufreq_driver_lock, flags);
- policy = per_cpu(cpufreq_cpu_data, cpu);
- per_cpu(cpufreq_cpu_data, cpu) = NULL;
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
if (!policy) {
pr_debug("%s: No cpu_data found\n", __func__);
return -EINVAL;
}
- down_write(&policy->rwsem);
- cpus = cpumask_weight(policy->cpus);
-
- if (cpus > 1)
- cpumask_clear_cpu(cpu, policy->cpus);
- up_write(&policy->rwsem);
+ /* Only proceed for inactive policies */
+ if (!policy_is_inactive(policy))
+ return 0;
/* If cpu is last user of policy, free policy */
- if (cpus == 1) {
- if (has_target()) {
- ret = __cpufreq_governor(policy,
- CPUFREQ_GOV_POLICY_EXIT);
- if (ret) {
- pr_err("%s: Failed to exit governor\n",
- __func__);
- return ret;
- }
- }
-
- if (!cpufreq_suspended)
- cpufreq_policy_put_kobj(policy);
-
- /*
- * Perform the ->exit() even during light-weight tear-down,
- * since this is a core component, and is essential for the
- * subsequent light-weight ->init() to succeed.
- */
- if (cpufreq_driver->exit)
- cpufreq_driver->exit(policy);
-
- /* Remove policy from list of active policies */
- write_lock_irqsave(&cpufreq_driver_lock, flags);
- list_del(&policy->policy_list);
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
- if (!cpufreq_suspended)
- cpufreq_policy_free(policy);
- } else if (has_target()) {
- ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
- if (!ret)
- ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
-
+ if (has_target()) {
+ ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
if (ret) {
- pr_err("%s: Failed to start governor\n", __func__);
+ pr_err("%s: Failed to exit governor\n", __func__);
return ret;
}
}
+ /*
+ * Perform the ->exit() even during light-weight tear-down,
+ * since this is a core component, and is essential for the
+ * subsequent light-weight ->init() to succeed.
+ */
+ if (cpufreq_driver->exit)
+ cpufreq_driver->exit(policy);
+
+ /* Free the policy only if the driver is getting removed. */
+ if (sif)
+ cpufreq_policy_free(policy, true);
+
return 0;
}
@@ -1469,8 +1513,33 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
unsigned int cpu = dev->id;
int ret;
- if (cpu_is_offline(cpu))
+ /*
+ * Only possible if 'cpu' is getting physically removed now. A hotplug
+ * notifier should have already been called and we just need to remove
+ * link or free policy here.
+ */
+ if (cpu_is_offline(cpu)) {
+ struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
+ struct cpumask mask;
+
+ if (!policy)
+ return 0;
+
+ cpumask_copy(&mask, policy->related_cpus);
+ cpumask_clear_cpu(cpu, &mask);
+
+ /*
+ * Free policy only if all policy->related_cpus are removed
+ * physically.
+ */
+ if (cpumask_intersects(&mask, cpu_present_mask)) {
+ remove_cpu_dev_symlink(policy, cpu);
+ return 0;
+ }
+
+ cpufreq_policy_free(policy, true);
return 0;
+ }
ret = __cpufreq_remove_dev_prepare(dev, sif);
@@ -1567,6 +1636,10 @@ static unsigned int __cpufreq_get(struct cpufreq_policy *policy)
ret_freq = cpufreq_driver->get(policy->cpu);
+ /* Updating inactive policies is invalid, so avoid doing that. */
+ if (unlikely(policy_is_inactive(policy)))
+ return ret_freq;
+
if (ret_freq && policy->cur &&
!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
/* verify no discrepancy between actual and
@@ -1656,7 +1729,7 @@ void cpufreq_suspend(void)
pr_debug("%s: Suspending Governors\n", __func__);
- for_each_policy(policy) {
+ for_each_active_policy(policy) {
if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP))
pr_err("%s: Failed to stop governor for policy: %p\n",
__func__, policy);
@@ -1690,7 +1763,7 @@ void cpufreq_resume(void)
pr_debug("%s: Resuming Governors\n", __func__);
- for_each_policy(policy) {
+ for_each_active_policy(policy) {
if (cpufreq_driver->resume && cpufreq_driver->resume(policy))
pr_err("%s: Failed to resume driver: %p\n", __func__,
policy);
@@ -1891,7 +1964,7 @@ static int __target_index(struct cpufreq_policy *policy,
* Failed after setting to intermediate freq? Driver should have
* reverted back to initial frequency and so should we. Check
* here for intermediate_freq instead of get_intermediate, in
- * case we have't switched to intermediate freq at all.
+ * case we haven't switched to intermediate freq at all.
*/
if (unlikely(retval && intermediate_freq)) {
freqs.old = intermediate_freq;
@@ -2092,7 +2165,8 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor);
void cpufreq_unregister_governor(struct cpufreq_governor *governor)
{
- int cpu;
+ struct cpufreq_policy *policy;
+ unsigned long flags;
if (!governor)
return;
@@ -2100,12 +2174,15 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
if (cpufreq_disabled())
return;
- for_each_present_cpu(cpu) {
- if (cpu_online(cpu))
- continue;
- if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name))
- strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0");
+ /* clear last_governor for all inactive policies */
+ read_lock_irqsave(&cpufreq_driver_lock, flags);
+ for_each_inactive_policy(policy) {
+ if (!strcmp(policy->last_governor, governor->name)) {
+ policy->governor = NULL;
+ strcpy(policy->last_governor, "\0");
+ }
}
+ read_unlock_irqrestore(&cpufreq_driver_lock, flags);
mutex_lock(&cpufreq_governor_mutex);
list_del(&governor->governor_list);
@@ -2304,7 +2381,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
if (dev) {
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
- __cpufreq_add_dev(dev, NULL);
+ cpufreq_add_dev(dev, NULL);
break;
case CPU_DOWN_PREPARE:
@@ -2316,7 +2393,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
break;
case CPU_DOWN_FAILED:
- __cpufreq_add_dev(dev, NULL);
+ cpufreq_add_dev(dev, NULL);
break;
}
}
@@ -2336,7 +2413,7 @@ static int cpufreq_boost_set_sw(int state)
struct cpufreq_policy *policy;
int ret = -EINVAL;
- for_each_policy(policy) {
+ for_each_active_policy(policy) {
freq_table = cpufreq_frequency_get_table(policy->cpu);
if (freq_table) {
ret = cpufreq_frequency_table_cpuinfo(policy,
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 25a70d06c5bf..c86a10c30912 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -148,6 +148,10 @@ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
return 0;
}
+static struct notifier_block cs_cpufreq_notifier_block = {
+ .notifier_call = dbs_cpufreq_notifier,
+};
+
/************************** sysfs interface ************************/
static struct common_dbs_data cs_dbs_cdata;
@@ -317,7 +321,7 @@ static struct attribute_group cs_attr_group_gov_pol = {
/************************** sysfs end ************************/
-static int cs_init(struct dbs_data *dbs_data)
+static int cs_init(struct dbs_data *dbs_data, bool notify)
{
struct cs_dbs_tuners *tuners;
@@ -336,25 +340,25 @@ static int cs_init(struct dbs_data *dbs_data)
dbs_data->tuners = tuners;
dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
jiffies_to_usecs(10);
- mutex_init(&dbs_data->mutex);
+
+ if (notify)
+ cpufreq_register_notifier(&cs_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
return 0;
}
-static void cs_exit(struct dbs_data *dbs_data)
+static void cs_exit(struct dbs_data *dbs_data, bool notify)
{
+ if (notify)
+ cpufreq_unregister_notifier(&cs_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
kfree(dbs_data->tuners);
}
define_get_cpu_dbs_routines(cs_cpu_dbs_info);
-static struct notifier_block cs_cpufreq_notifier_block = {
- .notifier_call = dbs_cpufreq_notifier,
-};
-
-static struct cs_ops cs_ops = {
- .notifier_block = &cs_cpufreq_notifier_block,
-};
-
static struct common_dbs_data cs_dbs_cdata = {
.governor = GOV_CONSERVATIVE,
.attr_group_gov_sys = &cs_attr_group_gov_sys,
@@ -363,9 +367,9 @@ static struct common_dbs_data cs_dbs_cdata = {
.get_cpu_dbs_info_s = get_cpu_dbs_info_s,
.gov_dbs_timer = cs_dbs_timer,
.gov_check_cpu = cs_check_cpu,
- .gov_ops = &cs_ops,
.init = cs_init,
.exit = cs_exit,
+ .mutex = __MUTEX_INITIALIZER(cs_dbs_cdata.mutex),
};
static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy,
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 1b44496b2d2b..57a39f8a92b7 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -239,211 +239,242 @@ static void set_sampling_rate(struct dbs_data *dbs_data,
}
}
-int cpufreq_governor_dbs(struct cpufreq_policy *policy,
- struct common_dbs_data *cdata, unsigned int event)
+static int cpufreq_governor_init(struct cpufreq_policy *policy,
+ struct dbs_data *dbs_data,
+ struct common_dbs_data *cdata)
{
- struct dbs_data *dbs_data;
- struct od_cpu_dbs_info_s *od_dbs_info = NULL;
- struct cs_cpu_dbs_info_s *cs_dbs_info = NULL;
- struct od_ops *od_ops = NULL;
- struct od_dbs_tuners *od_tuners = NULL;
- struct cs_dbs_tuners *cs_tuners = NULL;
- struct cpu_dbs_common_info *cpu_cdbs;
- unsigned int sampling_rate, latency, ignore_nice, j, cpu = policy->cpu;
- int io_busy = 0;
- int rc;
-
- if (have_governor_per_policy())
- dbs_data = policy->governor_data;
- else
- dbs_data = cdata->gdbs_data;
-
- WARN_ON(!dbs_data && (event != CPUFREQ_GOV_POLICY_INIT));
-
- switch (event) {
- case CPUFREQ_GOV_POLICY_INIT:
- if (have_governor_per_policy()) {
- WARN_ON(dbs_data);
- } else if (dbs_data) {
- dbs_data->usage_count++;
- policy->governor_data = dbs_data;
- return 0;
- }
-
- dbs_data = kzalloc(sizeof(*dbs_data), GFP_KERNEL);
- if (!dbs_data) {
- pr_err("%s: POLICY_INIT: kzalloc failed\n", __func__);
- return -ENOMEM;
- }
+ unsigned int latency;
+ int ret;
- dbs_data->cdata = cdata;
- dbs_data->usage_count = 1;
- rc = cdata->init(dbs_data);
- if (rc) {
- pr_err("%s: POLICY_INIT: init() failed\n", __func__);
- kfree(dbs_data);
- return rc;
- }
+ if (dbs_data) {
+ if (WARN_ON(have_governor_per_policy()))
+ return -EINVAL;
+ dbs_data->usage_count++;
+ policy->governor_data = dbs_data;
+ return 0;
+ }
- if (!have_governor_per_policy())
- WARN_ON(cpufreq_get_global_kobject());
+ dbs_data = kzalloc(sizeof(*dbs_data), GFP_KERNEL);
+ if (!dbs_data)
+ return -ENOMEM;
- rc = sysfs_create_group(get_governor_parent_kobj(policy),
- get_sysfs_attr(dbs_data));
- if (rc) {
- cdata->exit(dbs_data);
- kfree(dbs_data);
- return rc;
- }
+ dbs_data->cdata = cdata;
+ dbs_data->usage_count = 1;
- policy->governor_data = dbs_data;
+ ret = cdata->init(dbs_data, !policy->governor->initialized);
+ if (ret)
+ goto free_dbs_data;
- /* policy latency is in ns. Convert it to us first */
- latency = policy->cpuinfo.transition_latency / 1000;
- if (latency == 0)
- latency = 1;
+ /* policy latency is in ns. Convert it to us first */
+ latency = policy->cpuinfo.transition_latency / 1000;
+ if (latency == 0)
+ latency = 1;
- /* Bring kernel and HW constraints together */
- dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,
- MIN_LATENCY_MULTIPLIER * latency);
- set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate,
+ /* Bring kernel and HW constraints together */
+ dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,
+ MIN_LATENCY_MULTIPLIER * latency);
+ set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate,
latency * LATENCY_MULTIPLIER));
- if ((cdata->governor == GOV_CONSERVATIVE) &&
- (!policy->governor->initialized)) {
- struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;
-
- cpufreq_register_notifier(cs_ops->notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
+ if (!have_governor_per_policy()) {
+ if (WARN_ON(cpufreq_get_global_kobject())) {
+ ret = -EINVAL;
+ goto cdata_exit;
}
+ cdata->gdbs_data = dbs_data;
+ }
- if (!have_governor_per_policy())
- cdata->gdbs_data = dbs_data;
+ ret = sysfs_create_group(get_governor_parent_kobj(policy),
+ get_sysfs_attr(dbs_data));
+ if (ret)
+ goto put_kobj;
- return 0;
- case CPUFREQ_GOV_POLICY_EXIT:
- if (!--dbs_data->usage_count) {
- sysfs_remove_group(get_governor_parent_kobj(policy),
- get_sysfs_attr(dbs_data));
+ policy->governor_data = dbs_data;
- if (!have_governor_per_policy())
- cpufreq_put_global_kobject();
+ return 0;
- if ((dbs_data->cdata->governor == GOV_CONSERVATIVE) &&
- (policy->governor->initialized == 1)) {
- struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;
+put_kobj:
+ if (!have_governor_per_policy()) {
+ cdata->gdbs_data = NULL;
+ cpufreq_put_global_kobject();
+ }
+cdata_exit:
+ cdata->exit(dbs_data, !policy->governor->initialized);
+free_dbs_data:
+ kfree(dbs_data);
+ return ret;
+}
+
+static void cpufreq_governor_exit(struct cpufreq_policy *policy,
+ struct dbs_data *dbs_data)
+{
+ struct common_dbs_data *cdata = dbs_data->cdata;
- cpufreq_unregister_notifier(cs_ops->notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
- }
+ policy->governor_data = NULL;
+ if (!--dbs_data->usage_count) {
+ sysfs_remove_group(get_governor_parent_kobj(policy),
+ get_sysfs_attr(dbs_data));
- cdata->exit(dbs_data);
- kfree(dbs_data);
+ if (!have_governor_per_policy()) {
cdata->gdbs_data = NULL;
+ cpufreq_put_global_kobject();
}
- policy->governor_data = NULL;
- return 0;
+ cdata->exit(dbs_data, policy->governor->initialized == 1);
+ kfree(dbs_data);
}
+}
- cpu_cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);
+static int cpufreq_governor_start(struct cpufreq_policy *policy,
+ struct dbs_data *dbs_data)
+{
+ struct common_dbs_data *cdata = dbs_data->cdata;
+ unsigned int sampling_rate, ignore_nice, j, cpu = policy->cpu;
+ struct cpu_dbs_common_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu);
+ int io_busy = 0;
+
+ if (!policy->cur)
+ return -EINVAL;
+
+ if (cdata->governor == GOV_CONSERVATIVE) {
+ struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
- if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
- cs_tuners = dbs_data->tuners;
- cs_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu);
sampling_rate = cs_tuners->sampling_rate;
ignore_nice = cs_tuners->ignore_nice_load;
} else {
- od_tuners = dbs_data->tuners;
- od_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu);
+ struct od_dbs_tuners *od_tuners = dbs_data->tuners;
+
sampling_rate = od_tuners->sampling_rate;
ignore_nice = od_tuners->ignore_nice_load;
- od_ops = dbs_data->cdata->gov_ops;
io_busy = od_tuners->io_is_busy;
}
- switch (event) {
- case CPUFREQ_GOV_START:
- if (!policy->cur)
- return -EINVAL;
+ for_each_cpu(j, policy->cpus) {
+ struct cpu_dbs_common_info *j_cdbs = cdata->get_cpu_cdbs(j);
+ unsigned int prev_load;
- mutex_lock(&dbs_data->mutex);
+ j_cdbs->cpu = j;
+ j_cdbs->cur_policy = policy;
+ j_cdbs->prev_cpu_idle =
+ get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy);
- for_each_cpu(j, policy->cpus) {
- struct cpu_dbs_common_info *j_cdbs =
- dbs_data->cdata->get_cpu_cdbs(j);
- unsigned int prev_load;
+ prev_load = (unsigned int)(j_cdbs->prev_cpu_wall -
+ j_cdbs->prev_cpu_idle);
+ j_cdbs->prev_load = 100 * prev_load /
+ (unsigned int)j_cdbs->prev_cpu_wall;
- j_cdbs->cpu = j;
- j_cdbs->cur_policy = policy;
- j_cdbs->prev_cpu_idle = get_cpu_idle_time(j,
- &j_cdbs->prev_cpu_wall, io_busy);
+ if (ignore_nice)
+ j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE];
- prev_load = (unsigned int)
- (j_cdbs->prev_cpu_wall - j_cdbs->prev_cpu_idle);
- j_cdbs->prev_load = 100 * prev_load /
- (unsigned int) j_cdbs->prev_cpu_wall;
+ mutex_init(&j_cdbs->timer_mutex);
+ INIT_DEFERRABLE_WORK(&j_cdbs->work, cdata->gov_dbs_timer);
+ }
- if (ignore_nice)
- j_cdbs->prev_cpu_nice =
- kcpustat_cpu(j).cpustat[CPUTIME_NICE];
+ if (cdata->governor == GOV_CONSERVATIVE) {
+ struct cs_cpu_dbs_info_s *cs_dbs_info =
+ cdata->get_cpu_dbs_info_s(cpu);
- mutex_init(&j_cdbs->timer_mutex);
- INIT_DEFERRABLE_WORK(&j_cdbs->work,
- dbs_data->cdata->gov_dbs_timer);
- }
+ cs_dbs_info->down_skip = 0;
+ cs_dbs_info->enable = 1;
+ cs_dbs_info->requested_freq = policy->cur;
+ } else {
+ struct od_ops *od_ops = cdata->gov_ops;
+ struct od_cpu_dbs_info_s *od_dbs_info = cdata->get_cpu_dbs_info_s(cpu);
- if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
- cs_dbs_info->down_skip = 0;
- cs_dbs_info->enable = 1;
- cs_dbs_info->requested_freq = policy->cur;
- } else {
- od_dbs_info->rate_mult = 1;
- od_dbs_info->sample_type = OD_NORMAL_SAMPLE;
- od_ops->powersave_bias_init_cpu(cpu);
- }
+ od_dbs_info->rate_mult = 1;
+ od_dbs_info->sample_type = OD_NORMAL_SAMPLE;
+ od_ops->powersave_bias_init_cpu(cpu);
+ }
- mutex_unlock(&dbs_data->mutex);
+ /* Initiate timer time stamp */
+ cpu_cdbs->time_stamp = ktime_get();
- /* Initiate timer time stamp */
- cpu_cdbs->time_stamp = ktime_get();
+ gov_queue_work(dbs_data, policy, delay_for_sampling_rate(sampling_rate),
+ true);
+ return 0;
+}
- gov_queue_work(dbs_data, policy,
- delay_for_sampling_rate(sampling_rate), true);
- break;
+static void cpufreq_governor_stop(struct cpufreq_policy *policy,
+ struct dbs_data *dbs_data)
+{
+ struct common_dbs_data *cdata = dbs_data->cdata;
+ unsigned int cpu = policy->cpu;
+ struct cpu_dbs_common_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu);
- case CPUFREQ_GOV_STOP:
- if (dbs_data->cdata->governor == GOV_CONSERVATIVE)
- cs_dbs_info->enable = 0;
+ if (cdata->governor == GOV_CONSERVATIVE) {
+ struct cs_cpu_dbs_info_s *cs_dbs_info =
+ cdata->get_cpu_dbs_info_s(cpu);
- gov_cancel_work(dbs_data, policy);
+ cs_dbs_info->enable = 0;
+ }
- mutex_lock(&dbs_data->mutex);
- mutex_destroy(&cpu_cdbs->timer_mutex);
- cpu_cdbs->cur_policy = NULL;
+ gov_cancel_work(dbs_data, policy);
- mutex_unlock(&dbs_data->mutex);
+ mutex_destroy(&cpu_cdbs->timer_mutex);
+ cpu_cdbs->cur_policy = NULL;
+}
- break;
+static void cpufreq_governor_limits(struct cpufreq_policy *policy,
+ struct dbs_data *dbs_data)
+{
+ struct common_dbs_data *cdata = dbs_data->cdata;
+ unsigned int cpu = policy->cpu;
+ struct cpu_dbs_common_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu);
+
+ if (!cpu_cdbs->cur_policy)
+ return;
+
+ mutex_lock(&cpu_cdbs->timer_mutex);
+ if (policy->max < cpu_cdbs->cur_policy->cur)
+ __cpufreq_driver_target(cpu_cdbs->cur_policy, policy->max,
+ CPUFREQ_RELATION_H);
+ else if (policy->min > cpu_cdbs->cur_policy->cur)
+ __cpufreq_driver_target(cpu_cdbs->cur_policy, policy->min,
+ CPUFREQ_RELATION_L);
+ dbs_check_cpu(dbs_data, cpu);
+ mutex_unlock(&cpu_cdbs->timer_mutex);
+}
+
+int cpufreq_governor_dbs(struct cpufreq_policy *policy,
+ struct common_dbs_data *cdata, unsigned int event)
+{
+ struct dbs_data *dbs_data;
+ int ret = 0;
+ /* Lock governor to block concurrent initialization of governor */
+ mutex_lock(&cdata->mutex);
+
+ if (have_governor_per_policy())
+ dbs_data = policy->governor_data;
+ else
+ dbs_data = cdata->gdbs_data;
+
+ if (WARN_ON(!dbs_data && (event != CPUFREQ_GOV_POLICY_INIT))) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ switch (event) {
+ case CPUFREQ_GOV_POLICY_INIT:
+ ret = cpufreq_governor_init(policy, dbs_data, cdata);
+ break;
+ case CPUFREQ_GOV_POLICY_EXIT:
+ cpufreq_governor_exit(policy, dbs_data);
+ break;
+ case CPUFREQ_GOV_START:
+ ret = cpufreq_governor_start(policy, dbs_data);
+ break;
+ case CPUFREQ_GOV_STOP:
+ cpufreq_governor_stop(policy, dbs_data);
+ break;
case CPUFREQ_GOV_LIMITS:
- mutex_lock(&dbs_data->mutex);
- if (!cpu_cdbs->cur_policy) {
- mutex_unlock(&dbs_data->mutex);
- break;
- }
- mutex_lock(&cpu_cdbs->timer_mutex);
- if (policy->max < cpu_cdbs->cur_policy->cur)
- __cpufreq_driver_target(cpu_cdbs->cur_policy,
- policy->max, CPUFREQ_RELATION_H);
- else if (policy->min > cpu_cdbs->cur_policy->cur)
- __cpufreq_driver_target(cpu_cdbs->cur_policy,
- policy->min, CPUFREQ_RELATION_L);
- dbs_check_cpu(dbs_data, cpu);
- mutex_unlock(&cpu_cdbs->timer_mutex);
- mutex_unlock(&dbs_data->mutex);
+ cpufreq_governor_limits(policy, dbs_data);
break;
}
- return 0;
+
+unlock:
+ mutex_unlock(&cdata->mutex);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_governor_dbs);
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index cc401d147e72..34736f5e869d 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -208,11 +208,16 @@ struct common_dbs_data {
void *(*get_cpu_dbs_info_s)(int cpu);
void (*gov_dbs_timer)(struct work_struct *work);
void (*gov_check_cpu)(int cpu, unsigned int load);
- int (*init)(struct dbs_data *dbs_data);
- void (*exit)(struct dbs_data *dbs_data);
+ int (*init)(struct dbs_data *dbs_data, bool notify);
+ void (*exit)(struct dbs_data *dbs_data, bool notify);
/* Governor specific ops, see below */
void *gov_ops;
+
+ /*
+ * Protects governor's data (struct dbs_data and struct common_dbs_data)
+ */
+ struct mutex mutex;
};
/* Governor Per policy data */
@@ -221,9 +226,6 @@ struct dbs_data {
unsigned int min_sampling_rate;
int usage_count;
void *tuners;
-
- /* dbs_mutex protects dbs_enable in governor start/stop */
- struct mutex mutex;
};
/* Governor specific ops, will be passed to dbs_data->gov_ops */
@@ -234,10 +236,6 @@ struct od_ops {
void (*freq_increase)(struct cpufreq_policy *policy, unsigned int freq);
};
-struct cs_ops {
- struct notifier_block *notifier_block;
-};
-
static inline int delay_for_sampling_rate(unsigned int sampling_rate)
{
int delay = usecs_to_jiffies(sampling_rate);
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index ad3f38fd3eb9..3c1e10f2304c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -475,7 +475,7 @@ static struct attribute_group od_attr_group_gov_pol = {
/************************** sysfs end ************************/
-static int od_init(struct dbs_data *dbs_data)
+static int od_init(struct dbs_data *dbs_data, bool notify)
{
struct od_dbs_tuners *tuners;
u64 idle_time;
@@ -513,11 +513,10 @@ static int od_init(struct dbs_data *dbs_data)
tuners->io_is_busy = should_io_be_busy();
dbs_data->tuners = tuners;
- mutex_init(&dbs_data->mutex);
return 0;
}
-static void od_exit(struct dbs_data *dbs_data)
+static void od_exit(struct dbs_data *dbs_data, bool notify)
{
kfree(dbs_data->tuners);
}
@@ -541,6 +540,7 @@ static struct common_dbs_data od_dbs_cdata = {
.gov_ops = &od_ops,
.init = od_init,
.exit = od_exit,
+ .mutex = __MUTEX_INITIALIZER(od_dbs_cdata.mutex),
};
static void od_set_powersave_bias(unsigned int powersave_bias)
diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c
index 1d723dc8880c..3488c9c175eb 100644
--- a/drivers/cpufreq/gx-suspmod.c
+++ b/drivers/cpufreq/gx-suspmod.c
@@ -144,7 +144,7 @@ module_param(max_duration, int, 0444);
/**
- * we can detect a core multipiler from dir0_lsb
+ * we can detect a core multiplier from dir0_lsb
* from GX1 datasheet p.56,
* MULT[3:0]:
* 0000 = SYSCLK multiplied by 4 (test only)
@@ -346,7 +346,7 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy)
/* it needs to be assured that at least one supported frequency is
* within policy->min and policy->max. If it is not, policy->max
- * needs to be increased until one freuqency is supported.
+ * needs to be increased until one frequency is supported.
* policy->min may not be decreased, though. This way we guarantee a
* specific processing capacity.
*/
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 6414661ac1c4..15ada47bb720 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -26,6 +26,7 @@
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/acpi.h>
+#include <linux/vmalloc.h>
#include <trace/events/power.h>
#include <asm/div64.h>
@@ -48,9 +49,9 @@ static inline int32_t mul_fp(int32_t x, int32_t y)
return ((int64_t)x * (int64_t)y) >> FRAC_BITS;
}
-static inline int32_t div_fp(int32_t x, int32_t y)
+static inline int32_t div_fp(s64 x, s64 y)
{
- return div_s64((int64_t)x << FRAC_BITS, y);
+ return div64_s64((int64_t)x << FRAC_BITS, y);
}
static inline int ceiling_fp(int32_t x)
@@ -68,6 +69,7 @@ struct sample {
int32_t core_pct_busy;
u64 aperf;
u64 mperf;
+ u64 tsc;
int freq;
ktime_t time;
};
@@ -109,6 +111,7 @@ struct cpudata {
ktime_t last_sample_time;
u64 prev_aperf;
u64 prev_mperf;
+ u64 prev_tsc;
struct sample sample;
};
@@ -396,7 +399,7 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
update_turbo_state();
if (limits.turbo_disabled) {
- pr_warn("Turbo disabled by BIOS or unavailable on processor\n");
+ pr_warn("intel_pstate: Turbo disabled by BIOS or unavailable on processor\n");
return -EPERM;
}
@@ -484,7 +487,7 @@ static void __init intel_pstate_sysfs_expose_params(void)
static void intel_pstate_hwp_enable(void)
{
hwp_active++;
- pr_info("intel_pstate HWP enabled\n");
+ pr_info("intel_pstate: HWP enabled\n");
wrmsrl( MSR_PM_ENABLE, 0x1);
}
@@ -535,7 +538,7 @@ static void byt_set_pstate(struct cpudata *cpudata, int pstate)
val |= vid;
- wrmsrl(MSR_IA32_PERF_CTL, val);
+ wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
}
#define BYT_BCLK_FREQS 5
@@ -704,19 +707,20 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
*min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
}
-static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
+static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate, bool force)
{
int max_perf, min_perf;
- update_turbo_state();
-
- intel_pstate_get_min_max(cpu, &min_perf, &max_perf);
+ if (force) {
+ update_turbo_state();
- pstate = clamp_t(int, pstate, min_perf, max_perf);
+ intel_pstate_get_min_max(cpu, &min_perf, &max_perf);
- if (pstate == cpu->pstate.current_pstate)
- return;
+ pstate = clamp_t(int, pstate, min_perf, max_perf);
+ if (pstate == cpu->pstate.current_pstate)
+ return;
+ }
trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
cpu->pstate.current_pstate = pstate;
@@ -733,7 +737,7 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
if (pstate_funcs.get_vid)
pstate_funcs.get_vid(cpu);
- intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
+ intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate, false);
}
static inline void intel_pstate_calc_busy(struct cpudata *cpu)
@@ -756,23 +760,28 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
{
u64 aperf, mperf;
unsigned long flags;
+ u64 tsc;
local_irq_save(flags);
rdmsrl(MSR_IA32_APERF, aperf);
rdmsrl(MSR_IA32_MPERF, mperf);
+ tsc = native_read_tsc();
local_irq_restore(flags);
cpu->last_sample_time = cpu->sample.time;
cpu->sample.time = ktime_get();
cpu->sample.aperf = aperf;
cpu->sample.mperf = mperf;
+ cpu->sample.tsc = tsc;
cpu->sample.aperf -= cpu->prev_aperf;
cpu->sample.mperf -= cpu->prev_mperf;
+ cpu->sample.tsc -= cpu->prev_tsc;
intel_pstate_calc_busy(cpu);
cpu->prev_aperf = aperf;
cpu->prev_mperf = mperf;
+ cpu->prev_tsc = tsc;
}
static inline void intel_hwp_set_sample_time(struct cpudata *cpu)
@@ -794,7 +803,7 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
{
int32_t core_busy, max_pstate, current_pstate, sample_ratio;
- u32 duration_us;
+ s64 duration_us;
u32 sample_time;
/*
@@ -821,8 +830,8 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
* to adjust our busyness.
*/
sample_time = pid_params.sample_rate_ms * USEC_PER_MSEC;
- duration_us = (u32) ktime_us_delta(cpu->sample.time,
- cpu->last_sample_time);
+ duration_us = ktime_us_delta(cpu->sample.time,
+ cpu->last_sample_time);
if (duration_us > sample_time * 3) {
sample_ratio = div_fp(int_tofp(sample_time),
int_tofp(duration_us));
@@ -837,6 +846,10 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
int32_t busy_scaled;
struct _pid *pid;
signed int ctl;
+ int from;
+ struct sample *sample;
+
+ from = cpu->pstate.current_pstate;
pid = &cpu->pid;
busy_scaled = intel_pstate_get_scaled_busy(cpu);
@@ -844,7 +857,17 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
ctl = pid_calc(pid, busy_scaled);
/* Negative values of ctl increase the pstate and vice versa */
- intel_pstate_set_pstate(cpu, cpu->pstate.current_pstate - ctl);
+ intel_pstate_set_pstate(cpu, cpu->pstate.current_pstate - ctl, true);
+
+ sample = &cpu->sample;
+ trace_pstate_sample(fp_toint(sample->core_pct_busy),
+ fp_toint(busy_scaled),
+ from,
+ cpu->pstate.current_pstate,
+ sample->mperf,
+ sample->aperf,
+ sample->tsc,
+ sample->freq);
}
static void intel_hwp_timer_func(unsigned long __data)
@@ -858,21 +881,11 @@ static void intel_hwp_timer_func(unsigned long __data)
static void intel_pstate_timer_func(unsigned long __data)
{
struct cpudata *cpu = (struct cpudata *) __data;
- struct sample *sample;
intel_pstate_sample(cpu);
- sample = &cpu->sample;
-
intel_pstate_adjust_busy_pstate(cpu);
- trace_pstate_sample(fp_toint(sample->core_pct_busy),
- fp_toint(intel_pstate_get_scaled_busy(cpu)),
- cpu->pstate.current_pstate,
- sample->mperf,
- sample->aperf,
- sample->freq);
-
intel_pstate_set_sample_time(cpu);
}
@@ -935,7 +948,7 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
add_timer_on(&cpu->timer, cpunum);
- pr_debug("Intel pstate controlling: cpu %d\n", cpunum);
+ pr_debug("intel_pstate: controlling: cpu %d\n", cpunum);
return 0;
}
@@ -1001,13 +1014,13 @@ static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
int cpu_num = policy->cpu;
struct cpudata *cpu = all_cpu_data[cpu_num];
- pr_info("intel_pstate CPU %d exiting\n", cpu_num);
+ pr_debug("intel_pstate: CPU %d exiting\n", cpu_num);
del_timer_sync(&all_cpu_data[cpu_num]->timer);
if (hwp_active)
return;
- intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
+ intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate, false);
}
static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c
index 529cfd92158f..5dd95dab580d 100644
--- a/drivers/cpufreq/p4-clockmod.c
+++ b/drivers/cpufreq/p4-clockmod.c
@@ -172,7 +172,7 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
unsigned int i;
#ifdef CONFIG_SMP
- cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu));
+ cpumask_copy(policy->cpus, topology_sibling_cpumask(policy->cpu));
#endif
/* Errata workaround */
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index f9ce7e4bf0fe..5c035d04d827 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -57,13 +57,6 @@ static DEFINE_PER_CPU(struct powernow_k8_data *, powernow_data);
static struct cpufreq_driver cpufreq_amd64_driver;
-#ifndef CONFIG_SMP
-static inline const struct cpumask *cpu_core_mask(int cpu)
-{
- return cpumask_of(0);
-}
-#endif
-
/* Return a frequency in MHz, given an input fid */
static u32 find_freq_from_fid(u32 fid)
{
@@ -620,7 +613,7 @@ static int fill_powernow_table(struct powernow_k8_data *data,
pr_debug("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid);
data->powernow_table = powernow_table;
- if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu)
+ if (cpumask_first(topology_core_cpumask(data->cpu)) == data->cpu)
print_basics(data);
for (j = 0; j < data->numps; j++)
@@ -784,7 +777,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
CPUFREQ_TABLE_END;
data->powernow_table = powernow_table;
- if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu)
+ if (cpumask_first(topology_core_cpumask(data->cpu)) == data->cpu)
print_basics(data);
/* notify BIOS that we exist */
@@ -1090,7 +1083,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
if (rc != 0)
goto err_out_exit_acpi;
- cpumask_copy(pol->cpus, cpu_core_mask(pol->cpu));
+ cpumask_copy(pol->cpus, topology_core_cpumask(pol->cpu));
data->available_cores = pol->cpus;
/* min/max the cpu is capable of */
diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c
index e24269ab4e9b..1d99c97defa9 100644
--- a/drivers/cpufreq/pxa2xx-cpufreq.c
+++ b/drivers/cpufreq/pxa2xx-cpufreq.c
@@ -56,7 +56,7 @@ module_param(pxa27x_maxfreq, uint, 0);
MODULE_PARM_DESC(pxa27x_maxfreq, "Set the pxa27x maxfreq in MHz"
"(typically 624=>pxa270, 416=>pxa271, 520=>pxa272)");
-typedef struct {
+struct pxa_freqs {
unsigned int khz;
unsigned int membus;
unsigned int cccr;
@@ -64,7 +64,7 @@ typedef struct {
unsigned int cclkcfg;
int vmin;
int vmax;
-} pxa_freqs_t;
+};
/* Define the refresh period in mSec for the SDRAM and the number of rows */
#define SDRAM_TREF 64 /* standard 64ms SDRAM */
@@ -86,7 +86,7 @@ static unsigned int sdram_rows;
/* Use the run mode frequencies for the CPUFREQ_POLICY_PERFORMANCE policy */
#define CCLKCFG CCLKCFG_TURBO | CCLKCFG_FCS
-static pxa_freqs_t pxa255_run_freqs[] =
+static const struct pxa_freqs pxa255_run_freqs[] =
{
/* CPU MEMBUS CCCR DIV2 CCLKCFG run turbo PXbus SDRAM */
{ 99500, 99500, 0x121, 1, CCLKCFG, -1, -1}, /* 99, 99, 50, 50 */
@@ -98,7 +98,7 @@ static pxa_freqs_t pxa255_run_freqs[] =
};
/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */
-static pxa_freqs_t pxa255_turbo_freqs[] =
+static const struct pxa_freqs pxa255_turbo_freqs[] =
{
/* CPU MEMBUS CCCR DIV2 CCLKCFG run turbo PXbus SDRAM */
{ 99500, 99500, 0x121, 1, CCLKCFG, -1, -1}, /* 99, 99, 50, 50 */
@@ -153,7 +153,7 @@ MODULE_PARM_DESC(pxa255_turbo_table, "Selects the frequency table (0 = run table
((HT) ? CCLKCFG_HALFTURBO : 0) | \
((T) ? CCLKCFG_TURBO : 0))
-static pxa_freqs_t pxa27x_freqs[] = {
+static struct pxa_freqs pxa27x_freqs[] = {
{104000, 104000, PXA27x_CCCR(1, 8, 2), 0, CCLKCFG2(1, 0, 1), 900000, 1705000 },
{156000, 104000, PXA27x_CCCR(1, 8, 3), 0, CCLKCFG2(1, 0, 1), 1000000, 1705000 },
{208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1), 1180000, 1705000 },
@@ -171,7 +171,7 @@ extern unsigned get_clk_frequency_khz(int info);
#ifdef CONFIG_REGULATOR
-static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq)
+static int pxa_cpufreq_change_voltage(const struct pxa_freqs *pxa_freq)
{
int ret = 0;
int vmin, vmax;
@@ -202,7 +202,7 @@ static void __init pxa_cpufreq_init_voltages(void)
}
}
#else
-static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq)
+static int pxa_cpufreq_change_voltage(struct pxa_freqs *pxa_freq)
{
return 0;
}
@@ -211,7 +211,7 @@ static void __init pxa_cpufreq_init_voltages(void) { }
#endif
static void find_freq_tables(struct cpufreq_frequency_table **freq_table,
- pxa_freqs_t **pxa_freqs)
+ const struct pxa_freqs **pxa_freqs)
{
if (cpu_is_pxa25x()) {
if (!pxa255_turbo_table) {
@@ -270,7 +270,7 @@ static unsigned int pxa_cpufreq_get(unsigned int cpu)
static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
{
struct cpufreq_frequency_table *pxa_freqs_table;
- pxa_freqs_t *pxa_freq_settings;
+ const struct pxa_freqs *pxa_freq_settings;
unsigned long flags;
unsigned int new_freq_cpu, new_freq_mem;
unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg;
@@ -361,7 +361,7 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
int i;
unsigned int freq;
struct cpufreq_frequency_table *pxa255_freq_table;
- pxa_freqs_t *pxa255_freqs;
+ const struct pxa_freqs *pxa255_freqs;
/* try to guess pxa27x cpu */
if (cpu_is_pxa27x())
diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c
index 88b21ae0d6b0..358f0752c31e 100644
--- a/drivers/cpufreq/qoriq-cpufreq.c
+++ b/drivers/cpufreq/qoriq-cpufreq.c
@@ -27,11 +27,11 @@
/**
* struct cpu_data
- * @parent: the parent node of cpu clock
+ * @pclk: the parent clock of cpu
* @table: frequency table
*/
struct cpu_data {
- struct device_node *parent;
+ struct clk **pclk;
struct cpufreq_frequency_table *table;
};
@@ -196,7 +196,7 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- struct device_node *np;
+ struct device_node *np, *pnode;
int i, count, ret;
u32 freq, mask;
struct clk *clk;
@@ -219,17 +219,23 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
goto err_nomem2;
}
- data->parent = of_parse_phandle(np, "clocks", 0);
- if (!data->parent) {
+ pnode = of_parse_phandle(np, "clocks", 0);
+ if (!pnode) {
pr_err("%s: could not get clock information\n", __func__);
goto err_nomem2;
}
- count = of_property_count_strings(data->parent, "clock-names");
+ count = of_property_count_strings(pnode, "clock-names");
+ data->pclk = kcalloc(count, sizeof(struct clk *), GFP_KERNEL);
+ if (!data->pclk) {
+ pr_err("%s: no memory\n", __func__);
+ goto err_node;
+ }
+
table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL);
if (!table) {
pr_err("%s: no memory\n", __func__);
- goto err_node;
+ goto err_pclk;
}
if (fmask)
@@ -238,7 +244,8 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
mask = 0x0;
for (i = 0; i < count; i++) {
- clk = of_clk_get(data->parent, i);
+ clk = of_clk_get(pnode, i);
+ data->pclk[i] = clk;
freq = clk_get_rate(clk);
/*
* the clock is valid if its frequency is not masked
@@ -273,13 +280,16 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = u64temp + 1;
of_node_put(np);
+ of_node_put(pnode);
return 0;
err_nomem1:
kfree(table);
+err_pclk:
+ kfree(data->pclk);
err_node:
- of_node_put(data->parent);
+ of_node_put(pnode);
err_nomem2:
policy->driver_data = NULL;
kfree(data);
@@ -293,7 +303,7 @@ static int __exit qoriq_cpufreq_cpu_exit(struct cpufreq_policy *policy)
{
struct cpu_data *data = policy->driver_data;
- of_node_put(data->parent);
+ kfree(data->pclk);
kfree(data->table);
kfree(data);
policy->driver_data = NULL;
@@ -307,7 +317,7 @@ static int qoriq_cpufreq_target(struct cpufreq_policy *policy,
struct clk *parent;
struct cpu_data *data = policy->driver_data;
- parent = of_clk_get(data->parent, data->table[index].driver_data);
+ parent = data->pclk[data->table[index].driver_data];
return clk_set_parent(policy->clk, parent);
}
diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c
index e56d632a8b21..37555c6b86a7 100644
--- a/drivers/cpufreq/speedstep-ich.c
+++ b/drivers/cpufreq/speedstep-ich.c
@@ -292,7 +292,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
/* only run on CPU to be set, or on its sibling */
#ifdef CONFIG_SMP
- cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu));
+ cpumask_copy(policy->cpus, topology_sibling_cpumask(policy->cpu));
#endif
policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask);
diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c
index 40c34faffe59..db2ede565f1a 100644
--- a/drivers/cpuidle/cpuidle-big_little.c
+++ b/drivers/cpuidle/cpuidle-big_little.c
@@ -108,13 +108,7 @@ static int notrace bl_powerdown_finisher(unsigned long arg)
unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
mcpm_set_entry_vector(cpu, cluster, cpu_resume);
-
- /*
- * Residency value passed to mcpm_cpu_suspend back-end
- * has to be given clear semantics. Set to 0 as a
- * temporary value.
- */
- mcpm_cpu_suspend(0);
+ mcpm_cpu_suspend();
/* return value != 0 means failure */
return 1;
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index 59372077ec7c..1e3ef5ec4784 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -29,18 +29,25 @@ struct cpuidle_driver powernv_idle_driver = {
static int max_idle_state;
static struct cpuidle_state *cpuidle_state_table;
+static u64 snooze_timeout;
+static bool snooze_timeout_en;
static int snooze_loop(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
+ u64 snooze_exit_time;
+
local_irq_enable();
set_thread_flag(TIF_POLLING_NRFLAG);
+ snooze_exit_time = get_tb() + snooze_timeout;
ppc64_runlatch_off();
while (!need_resched()) {
HMT_low();
HMT_very_low();
+ if (snooze_timeout_en && get_tb() > snooze_exit_time)
+ break;
}
HMT_medium();
@@ -252,6 +259,11 @@ static int powernv_idle_probe(void)
cpuidle_state_table = powernv_states;
/* Device tree can indicate more idle states */
max_idle_state = powernv_add_idle_states();
+ if (max_idle_state > 1) {
+ snooze_timeout_en = true;
+ snooze_timeout = powernv_states[1].target_residency *
+ tb_ticks_per_usec;
+ }
} else
return -ENODEV;
diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c
index bb9e2b6f3ecc..07135e009d8b 100644
--- a/drivers/cpuidle/cpuidle-pseries.c
+++ b/drivers/cpuidle/cpuidle-pseries.c
@@ -27,6 +27,8 @@ struct cpuidle_driver pseries_idle_driver = {
static int max_idle_state;
static struct cpuidle_state *cpuidle_state_table;
+static u64 snooze_timeout;
+static bool snooze_timeout_en;
static inline void idle_loop_prolog(unsigned long *in_purr)
{
@@ -58,14 +60,18 @@ static int snooze_loop(struct cpuidle_device *dev,
int index)
{
unsigned long in_purr;
+ u64 snooze_exit_time;
idle_loop_prolog(&in_purr);
local_irq_enable();
set_thread_flag(TIF_POLLING_NRFLAG);
+ snooze_exit_time = get_tb() + snooze_timeout;
while (!need_resched()) {
HMT_low();
HMT_very_low();
+ if (snooze_timeout_en && get_tb() > snooze_exit_time)
+ break;
}
HMT_medium();
@@ -244,6 +250,11 @@ static int pseries_idle_probe(void)
} else
return -ENODEV;
+ if (max_idle_state > 1) {
+ snooze_timeout_en = true;
+ snooze_timeout = cpuidle_state_table[1].target_residency *
+ tb_ticks_per_usec;
+ }
return 0;
}
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 61c417b9e53f..e8e2775c3821 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -65,7 +65,7 @@ int cpuidle_play_dead(void)
return -ENODEV;
/* Find lowest-power state that supports long-term idle */
- for (i = drv->state_count - 1; i >= CPUIDLE_DRIVER_STATE_START; i--)
+ for (i = drv->state_count - 1; i >= 0; i--)
if (drv->states[i].enter_dead)
return drv->states[i].enter_dead(dev, i);
@@ -73,16 +73,21 @@ int cpuidle_play_dead(void)
}
static int find_deepest_state(struct cpuidle_driver *drv,
- struct cpuidle_device *dev, bool freeze)
+ struct cpuidle_device *dev,
+ unsigned int max_latency,
+ unsigned int forbidden_flags,
+ bool freeze)
{
unsigned int latency_req = 0;
- int i, ret = freeze ? -1 : CPUIDLE_DRIVER_STATE_START - 1;
+ int i, ret = -ENXIO;
- for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
+ for (i = 0; i < drv->state_count; i++) {
struct cpuidle_state *s = &drv->states[i];
struct cpuidle_state_usage *su = &dev->states_usage[i];
if (s->disabled || su->disable || s->exit_latency <= latency_req
+ || s->exit_latency > max_latency
+ || (s->flags & forbidden_flags)
|| (freeze && !s->enter_freeze))
continue;
@@ -92,6 +97,7 @@ static int find_deepest_state(struct cpuidle_driver *drv,
return ret;
}
+#ifdef CONFIG_SUSPEND
/**
* cpuidle_find_deepest_state - Find the deepest available idle state.
* @drv: cpuidle driver for the given CPU.
@@ -100,7 +106,7 @@ static int find_deepest_state(struct cpuidle_driver *drv,
int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
struct cpuidle_device *dev)
{
- return find_deepest_state(drv, dev, false);
+ return find_deepest_state(drv, dev, UINT_MAX, 0, false);
}
static void enter_freeze_proper(struct cpuidle_driver *drv,
@@ -139,18 +145,19 @@ int cpuidle_enter_freeze(struct cpuidle_driver *drv, struct cpuidle_device *dev)
* that interrupts won't be enabled when it exits and allows the tick to
* be frozen safely.
*/
- index = find_deepest_state(drv, dev, true);
+ index = find_deepest_state(drv, dev, UINT_MAX, 0, true);
if (index >= 0)
enter_freeze_proper(drv, dev, index);
return index;
}
+#endif /* CONFIG_SUSPEND */
/**
* cpuidle_enter_state - enter the state and update stats
* @dev: cpuidle device for this cpu
* @drv: cpuidle driver for this cpu
- * @next_state: index into drv->states of the state to enter
+ * @index: index into the states table in @drv of the state to enter
*/
int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
int index)
@@ -167,8 +174,18 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
* local timer will be shut down. If a local timer is used from another
* CPU as a broadcast timer, this call may fail if it is not available.
*/
- if (broadcast && tick_broadcast_enter())
- return -EBUSY;
+ if (broadcast && tick_broadcast_enter()) {
+ index = find_deepest_state(drv, dev, target_state->exit_latency,
+ CPUIDLE_FLAG_TIMER_STOP, false);
+ if (index < 0) {
+ default_idle_call();
+ return -EBUSY;
+ }
+ target_state = &drv->states[index];
+ }
+
+ /* Take note of the planned idle state. */
+ sched_idle_set_state(target_state);
trace_cpu_idle_rcuidle(index, dev->cpu);
time_start = ktime_get();
@@ -178,6 +195,9 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
time_end = ktime_get();
trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
+ /* The cpu is no longer idle or about to enter idle. */
+ sched_idle_set_state(NULL);
+
if (broadcast) {
if (WARN_ON_ONCE(!irqs_disabled()))
local_irq_disable();
@@ -249,7 +269,7 @@ int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev,
*/
void cpuidle_reflect(struct cpuidle_device *dev, int index)
{
- if (cpuidle_curr_governor->reflect)
+ if (cpuidle_curr_governor->reflect && index >= 0)
cpuidle_curr_governor->reflect(dev, index);
}
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index b8a5fa15ca24..22e4463d1787 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -367,9 +367,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
static void menu_reflect(struct cpuidle_device *dev, int index)
{
struct menu_device *data = this_cpu_ptr(&menu_devices);
+
data->last_state_idx = index;
- if (index >= 0)
- data->needs_update = 1;
+ data->needs_update = 1;
}
/**
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 033c0c86f6ec..4044125fb5d5 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -162,10 +162,10 @@ config CRYPTO_GHASH_S390
config CRYPTO_DEV_MV_CESA
tristate "Marvell's Cryptographic Engine"
depends on PLAT_ORION
- select CRYPTO_ALGAPI
select CRYPTO_AES
- select CRYPTO_BLKCIPHER2
+ select CRYPTO_BLKCIPHER
select CRYPTO_HASH
+ select SRAM
help
This driver allows you to utilize the Cryptographic Engines and
Security Accelerator (CESA) which can be found on the Marvell Orion
@@ -173,10 +173,27 @@ config CRYPTO_DEV_MV_CESA
Currently the driver supports AES in ECB and CBC mode without DMA.
+config CRYPTO_DEV_MARVELL_CESA
+ tristate "New Marvell's Cryptographic Engine driver"
+ depends on PLAT_ORION || ARCH_MVEBU
+ select CRYPTO_AES
+ select CRYPTO_DES
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_HASH
+ select SRAM
+ help
+ This driver allows you to utilize the Cryptographic Engines and
+ Security Accelerator (CESA) which can be found on the Armada 370.
+ This driver supports CPU offload through DMA transfers.
+
+ This driver is aimed at replacing the mv_cesa driver. This will only
+ happen once it has received proper testing.
+
config CRYPTO_DEV_NIAGARA2
tristate "Niagara2 Stream Processing Unit driver"
select CRYPTO_DES
- select CRYPTO_ALGAPI
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_HASH
depends on SPARC64
help
Each core of a Niagara2 processor contains a Stream
@@ -189,7 +206,6 @@ config CRYPTO_DEV_NIAGARA2
config CRYPTO_DEV_HIFN_795X
tristate "Driver HIFN 795x crypto accelerator chips"
select CRYPTO_DES
- select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
select HW_RANDOM if CRYPTO_DEV_HIFN_795X_RNG
depends on PCI
@@ -208,8 +224,10 @@ source drivers/crypto/caam/Kconfig
config CRYPTO_DEV_TALITOS
tristate "Talitos Freescale Security Engine (SEC)"
- select CRYPTO_ALGAPI
+ select CRYPTO_AEAD
select CRYPTO_AUTHENC
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_HASH
select HW_RANDOM
depends on FSL_SOC
help
@@ -222,11 +240,29 @@ config CRYPTO_DEV_TALITOS
To compile this driver as a module, choose M here: the module
will be called talitos.
+config CRYPTO_DEV_TALITOS1
+ bool "SEC1 (SEC 1.0 and SEC Lite 1.2)"
+ depends on CRYPTO_DEV_TALITOS
+ depends on PPC_8xx || PPC_82xx
+ default y
+ help
+ Say 'Y' here to use the Freescale Security Engine (SEC) version 1.0
+ found on MPC82xx or the Freescale Security Engine (SEC Lite)
+ version 1.2 found on MPC8xx
+
+config CRYPTO_DEV_TALITOS2
+ bool "SEC2+ (SEC version 2.0 or upper)"
+ depends on CRYPTO_DEV_TALITOS
+ default y if !PPC_8xx
+ help
+ Say 'Y' here to use the Freescale Security Engine (SEC)
+ version 2 and following as found on MPC83xx, MPC85xx, etc ...
+
config CRYPTO_DEV_IXP4XX
tristate "Driver for IXP4xx crypto hardware acceleration"
depends on ARCH_IXP4XX && IXP4XX_QMGR && IXP4XX_NPE
select CRYPTO_DES
- select CRYPTO_ALGAPI
+ select CRYPTO_AEAD
select CRYPTO_AUTHENC
select CRYPTO_BLKCIPHER
help
@@ -236,7 +272,6 @@ config CRYPTO_DEV_PPC4XX
tristate "Driver AMCC PPC4xx crypto accelerator"
depends on PPC && 4xx
select CRYPTO_HASH
- select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
help
This option allows you to have support for AMCC crypto acceleration.
@@ -257,7 +292,7 @@ config CRYPTO_DEV_OMAP_AES
tristate "Support for OMAP AES hw engine"
depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP2PLUS
select CRYPTO_AES
- select CRYPTO_BLKCIPHER2
+ select CRYPTO_BLKCIPHER
help
OMAP processors have AES module accelerator. Select this if you
want to use the OMAP module for AES algorithms.
@@ -266,7 +301,7 @@ config CRYPTO_DEV_OMAP_DES
tristate "Support for OMAP DES3DES hw engine"
depends on ARCH_OMAP2PLUS
select CRYPTO_DES
- select CRYPTO_BLKCIPHER2
+ select CRYPTO_BLKCIPHER
help
OMAP processors have DES/3DES module accelerator. Select this if you
want to use the OMAP module for DES and 3DES algorithms. Currently
@@ -276,9 +311,10 @@ config CRYPTO_DEV_OMAP_DES
config CRYPTO_DEV_PICOXCELL
tristate "Support for picoXcell IPSEC and Layer2 crypto engines"
depends on ARCH_PICOXCELL && HAVE_CLK
+ select CRYPTO_AEAD
select CRYPTO_AES
select CRYPTO_AUTHENC
- select CRYPTO_ALGAPI
+ select CRYPTO_BLKCIPHER
select CRYPTO_DES
select CRYPTO_CBC
select CRYPTO_ECB
@@ -304,7 +340,6 @@ config CRYPTO_DEV_S5P
tristate "Support for Samsung S5PV210/Exynos crypto accelerator"
depends on ARCH_S5PV210 || ARCH_EXYNOS
select CRYPTO_AES
- select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
help
This option allows you to have support for S5P crypto acceleration.
@@ -312,11 +347,13 @@ config CRYPTO_DEV_S5P
algorithms execution.
config CRYPTO_DEV_NX
- bool "Support for IBM Power7+ in-Nest cryptographic acceleration"
- depends on PPC64 && IBMVIO && !CPU_LITTLE_ENDIAN
- default n
+ bool "Support for IBM PowerPC Nest (NX) cryptographic acceleration"
+ depends on PPC64
help
- Support for Power7+ in-Nest cryptographic acceleration.
+ This enables support for the NX hardware cryptographic accelerator
+ coprocessor that is in IBM PowerPC P7+ or later processors. This
+ does not actually enable any drivers, it only allows you to select
+ which acceleration type (encryption and/or compression) to enable.
if CRYPTO_DEV_NX
source "drivers/crypto/nx/Kconfig"
@@ -325,7 +362,6 @@ endif
config CRYPTO_DEV_UX500
tristate "Driver for ST-Ericsson UX500 crypto hardware acceleration"
depends on ARCH_U8500
- select CRYPTO_ALGAPI
help
Driver for ST-Ericsson UX500 crypto engine.
@@ -343,10 +379,7 @@ config CRYPTO_DEV_BFIN_CRC
config CRYPTO_DEV_ATMEL_AES
tristate "Support for Atmel AES hw accelerator"
depends on ARCH_AT91
- select CRYPTO_CBC
- select CRYPTO_ECB
select CRYPTO_AES
- select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
select AT_HDMAC
help
@@ -361,9 +394,6 @@ config CRYPTO_DEV_ATMEL_TDES
tristate "Support for Atmel DES/TDES hw accelerator"
depends on ARCH_AT91
select CRYPTO_DES
- select CRYPTO_CBC
- select CRYPTO_ECB
- select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
help
Some Atmel processors have DES/TDES hw accelerator.
@@ -376,10 +406,7 @@ config CRYPTO_DEV_ATMEL_TDES
config CRYPTO_DEV_ATMEL_SHA
tristate "Support for Atmel SHA hw accelerator"
depends on ARCH_AT91
- select CRYPTO_SHA1
- select CRYPTO_SHA256
- select CRYPTO_SHA512
- select CRYPTO_ALGAPI
+ select CRYPTO_HASH
help
Some Atmel processors have SHA1/SHA224/SHA256/SHA384/SHA512
hw accelerator.
@@ -392,7 +419,6 @@ config CRYPTO_DEV_ATMEL_SHA
config CRYPTO_DEV_CCP
bool "Support for AMD Cryptographic Coprocessor"
depends on ((X86 && PCI) || (ARM64 && (OF_ADDRESS || ACPI))) && HAS_IOMEM
- default n
help
The AMD Cryptographic Coprocessor provides hardware support
for encryption, hashing and related operations.
@@ -404,13 +430,11 @@ endif
config CRYPTO_DEV_MXS_DCP
tristate "Support for Freescale MXS DCP"
depends on ARCH_MXS
- select CRYPTO_SHA1
- select CRYPTO_SHA256
select CRYPTO_CBC
select CRYPTO_ECB
select CRYPTO_AES
select CRYPTO_BLKCIPHER
- select CRYPTO_ALGAPI
+ select CRYPTO_HASH
help
The Freescale i.MX23/i.MX28 has SHA1/SHA256 and AES128 CBC/ECB
co-processor on the die.
@@ -429,7 +453,6 @@ config CRYPTO_DEV_QCE
select CRYPTO_CBC
select CRYPTO_XTS
select CRYPTO_CTR
- select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
help
This driver supports Qualcomm crypto engine accelerator
@@ -439,7 +462,6 @@ config CRYPTO_DEV_QCE
config CRYPTO_DEV_VMX
bool "Support for VMX cryptographic acceleration instructions"
depends on PPC64
- default n
help
Support for VMX cryptographic acceleration instructions.
@@ -449,7 +471,6 @@ config CRYPTO_DEV_IMGTEC_HASH
tristate "Imagination Technologies hardware hash accelerator"
depends on MIPS || COMPILE_TEST
depends on HAS_DMA
- select CRYPTO_ALGAPI
select CRYPTO_MD5
select CRYPTO_SHA1
select CRYPTO_SHA256
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index fb84be7e6be5..e35c07a8da85 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) += img-hash.o
obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o
+obj-$(CONFIG_CRYPTO_DEV_MARVELL_CESA) += marvell/
obj-$(CONFIG_CRYPTO_DEV_MXS_DCP) += mxs-dcp.o
obj-$(CONFIG_CRYPTO_DEV_NIAGARA2) += n2_crypto.o
n2_crypto-y := n2_core.o n2_asm.o
diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig
index e7555ff4cafd..e286e285aa8a 100644
--- a/drivers/crypto/caam/Kconfig
+++ b/drivers/crypto/caam/Kconfig
@@ -45,7 +45,6 @@ config CRYPTO_DEV_FSL_CAAM_RINGSIZE
config CRYPTO_DEV_FSL_CAAM_INTC
bool "Job Ring interrupt coalescing"
depends on CRYPTO_DEV_FSL_CAAM_JR
- default n
help
Enable the Job Ring's interrupt coalescing feature.
@@ -77,8 +76,9 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API
tristate "Register algorithm implementations with the Crypto API"
depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR
default y
- select CRYPTO_ALGAPI
+ select CRYPTO_AEAD
select CRYPTO_AUTHENC
+ select CRYPTO_BLKCIPHER
help
Selecting this will offload crypto for users of the
scatterlist crypto API (such as the linux native IPSec
@@ -115,7 +115,6 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API
config CRYPTO_DEV_FSL_CAAM_DEBUG
bool "Enable debug output in CAAM driver"
depends on CRYPTO_DEV_FSL_CAAM
- default n
help
Selecting this will enable printing of various debug
information in the CAAM driver.
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 29071a156cbe..daca933a82ec 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -65,6 +65,10 @@
/* max IV is max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
#define CAAM_MAX_IV_LENGTH 16
+#define AEAD_DESC_JOB_IO_LEN (DESC_JOB_IO_LEN + CAAM_CMD_SZ * 2)
+#define GCM_DESC_JOB_IO_LEN (AEAD_DESC_JOB_IO_LEN + \
+ CAAM_CMD_SZ * 4)
+
/* length of descriptors text */
#define DESC_AEAD_BASE (4 * CAAM_CMD_SZ)
#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ)
@@ -79,18 +83,16 @@
#define DESC_AEAD_NULL_DEC_LEN (DESC_AEAD_NULL_BASE + 17 * CAAM_CMD_SZ)
#define DESC_GCM_BASE (3 * CAAM_CMD_SZ)
-#define DESC_GCM_ENC_LEN (DESC_GCM_BASE + 23 * CAAM_CMD_SZ)
-#define DESC_GCM_DEC_LEN (DESC_GCM_BASE + 19 * CAAM_CMD_SZ)
+#define DESC_GCM_ENC_LEN (DESC_GCM_BASE + 16 * CAAM_CMD_SZ)
+#define DESC_GCM_DEC_LEN (DESC_GCM_BASE + 12 * CAAM_CMD_SZ)
#define DESC_RFC4106_BASE (3 * CAAM_CMD_SZ)
-#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 15 * CAAM_CMD_SZ)
-#define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 14 * CAAM_CMD_SZ)
-#define DESC_RFC4106_GIVENC_LEN (DESC_RFC4106_BASE + 21 * CAAM_CMD_SZ)
+#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 10 * CAAM_CMD_SZ)
+#define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 10 * CAAM_CMD_SZ)
#define DESC_RFC4543_BASE (3 * CAAM_CMD_SZ)
-#define DESC_RFC4543_ENC_LEN (DESC_RFC4543_BASE + 25 * CAAM_CMD_SZ)
-#define DESC_RFC4543_DEC_LEN (DESC_RFC4543_BASE + 27 * CAAM_CMD_SZ)
-#define DESC_RFC4543_GIVENC_LEN (DESC_RFC4543_BASE + 30 * CAAM_CMD_SZ)
+#define DESC_RFC4543_ENC_LEN (DESC_RFC4543_BASE + 11 * CAAM_CMD_SZ)
+#define DESC_RFC4543_DEC_LEN (DESC_RFC4543_BASE + 12 * CAAM_CMD_SZ)
#define DESC_ABLKCIPHER_BASE (3 * CAAM_CMD_SZ)
#define DESC_ABLKCIPHER_ENC_LEN (DESC_ABLKCIPHER_BASE + \
@@ -98,8 +100,7 @@
#define DESC_ABLKCIPHER_DEC_LEN (DESC_ABLKCIPHER_BASE + \
15 * CAAM_CMD_SZ)
-#define DESC_MAX_USED_BYTES (DESC_RFC4543_GIVENC_LEN + \
- CAAM_MAX_KEY_SIZE)
+#define DESC_MAX_USED_BYTES (CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN)
#define DESC_MAX_USED_LEN (DESC_MAX_USED_BYTES / CAAM_CMD_SZ)
#ifdef DEBUG
@@ -258,7 +259,7 @@ static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx,
static int aead_null_set_sh_desc(struct crypto_aead *aead)
{
- struct aead_tfm *tfm = &aead->base.crt_aead;
+ unsigned int ivsize = crypto_aead_ivsize(aead);
struct caam_ctx *ctx = crypto_aead_ctx(aead);
struct device *jrdev = ctx->jrdev;
bool keys_fit_inline = false;
@@ -273,7 +274,7 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead)
ctx->split_key_pad_len <= CAAM_DESC_BYTES_MAX)
keys_fit_inline = true;
- /* aead_encrypt shared descriptor */
+ /* old_aead_encrypt shared descriptor */
desc = ctx->sh_desc_enc;
init_sh_desc(desc, HDR_SHARE_SERIAL);
@@ -362,7 +363,7 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead)
desc = ctx->sh_desc_dec;
- /* aead_decrypt shared descriptor */
+ /* old_aead_decrypt shared descriptor */
init_sh_desc(desc, HDR_SHARE_SERIAL);
/* Skip if already shared */
@@ -383,7 +384,7 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead)
/* assoclen + cryptlen = seqinlen - ivsize - authsize */
append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM,
- ctx->authsize + tfm->ivsize);
+ ctx->authsize + ivsize);
/* assoclen = (assoclen + cryptlen) - cryptlen */
append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ);
append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ);
@@ -449,7 +450,7 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead)
static int aead_set_sh_desc(struct crypto_aead *aead)
{
- struct aead_tfm *tfm = &aead->base.crt_aead;
+ unsigned int ivsize = crypto_aead_ivsize(aead);
struct caam_ctx *ctx = crypto_aead_ctx(aead);
struct crypto_tfm *ctfm = crypto_aead_tfm(aead);
const char *alg_name = crypto_tfm_alg_name(ctfm);
@@ -496,7 +497,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
CAAM_DESC_BYTES_MAX)
keys_fit_inline = true;
- /* aead_encrypt shared descriptor */
+ /* old_aead_encrypt shared descriptor */
desc = ctx->sh_desc_enc;
/* Note: Context registers are saved. */
@@ -510,7 +511,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize);
/* assoclen + cryptlen = seqinlen - ivsize */
- append_math_sub_imm_u32(desc, REG2, SEQINLEN, IMM, tfm->ivsize);
+ append_math_sub_imm_u32(desc, REG2, SEQINLEN, IMM, ivsize);
/* assoclen = (assoclen + cryptlen) - cryptlen */
append_math_sub(desc, VARSEQINLEN, REG2, REG3, CAAM_CMD_SZ);
@@ -518,7 +519,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
/* read assoc before reading payload */
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG |
KEY_VLF);
- aead_append_ld_iv(desc, tfm->ivsize, ctx1_iv_off);
+ aead_append_ld_iv(desc, ivsize, ctx1_iv_off);
/* Load Counter into CONTEXT1 reg */
if (is_rfc3686)
@@ -565,7 +566,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
CAAM_DESC_BYTES_MAX)
keys_fit_inline = true;
- /* aead_decrypt shared descriptor */
+ /* old_aead_decrypt shared descriptor */
desc = ctx->sh_desc_dec;
/* Note: Context registers are saved. */
@@ -577,7 +578,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
/* assoclen + cryptlen = seqinlen - ivsize - authsize */
append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM,
- ctx->authsize + tfm->ivsize);
+ ctx->authsize + ivsize);
/* assoclen = (assoclen + cryptlen) - cryptlen */
append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ);
append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ);
@@ -586,7 +587,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG |
KEY_VLF);
- aead_append_ld_iv(desc, tfm->ivsize, ctx1_iv_off);
+ aead_append_ld_iv(desc, ivsize, ctx1_iv_off);
/* Load Counter into CONTEXT1 reg */
if (is_rfc3686)
@@ -645,20 +646,20 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
/* Generate IV */
geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO |
NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 |
- NFIFOENTRY_PTYPE_RND | (tfm->ivsize << NFIFOENTRY_DLEN_SHIFT);
+ NFIFOENTRY_PTYPE_RND | (ivsize << NFIFOENTRY_DLEN_SHIFT);
append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB |
LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM);
append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO);
append_move(desc, MOVE_WAITCOMP |
MOVE_SRC_INFIFO | MOVE_DEST_CLASS1CTX |
(ctx1_iv_off << MOVE_OFFSET_SHIFT) |
- (tfm->ivsize << MOVE_LEN_SHIFT));
+ (ivsize << MOVE_LEN_SHIFT));
append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO);
/* Copy IV to class 1 context */
append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_OUTFIFO |
(ctx1_iv_off << MOVE_OFFSET_SHIFT) |
- (tfm->ivsize << MOVE_LEN_SHIFT));
+ (ivsize << MOVE_LEN_SHIFT));
/* Return to encryption */
append_operation(desc, ctx->class2_alg_type |
@@ -676,10 +677,10 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
/* Copy iv from outfifo to class 2 fifo */
moveiv = NFIFOENTRY_STYPE_OFIFO | NFIFOENTRY_DEST_CLASS2 |
- NFIFOENTRY_DTYPE_MSG | (tfm->ivsize << NFIFOENTRY_DLEN_SHIFT);
+ NFIFOENTRY_DTYPE_MSG | (ivsize << NFIFOENTRY_DLEN_SHIFT);
append_load_imm_u32(desc, moveiv, LDST_CLASS_IND_CCB |
LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM);
- append_load_imm_u32(desc, tfm->ivsize, LDST_CLASS_2_CCB |
+ append_load_imm_u32(desc, ivsize, LDST_CLASS_2_CCB |
LDST_SRCDST_WORD_DATASZ_REG | LDST_IMM);
/* Load Counter into CONTEXT1 reg */
@@ -698,7 +699,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
/* Not need to reload iv */
- append_seq_fifo_load(desc, tfm->ivsize,
+ append_seq_fifo_load(desc, ivsize,
FIFOLD_CLASS_SKIP);
/* Will read cryptlen */
@@ -738,7 +739,6 @@ static int aead_setauthsize(struct crypto_aead *authenc,
static int gcm_set_sh_desc(struct crypto_aead *aead)
{
- struct aead_tfm *tfm = &aead->base.crt_aead;
struct caam_ctx *ctx = crypto_aead_ctx(aead);
struct device *jrdev = ctx->jrdev;
bool keys_fit_inline = false;
@@ -754,7 +754,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead)
* Job Descriptor and Shared Descriptor
* must fit into the 64-word Descriptor h/w Buffer
*/
- if (DESC_GCM_ENC_LEN + DESC_JOB_IO_LEN +
+ if (DESC_GCM_ENC_LEN + GCM_DESC_JOB_IO_LEN +
ctx->enckeylen <= CAAM_DESC_BYTES_MAX)
keys_fit_inline = true;
@@ -777,34 +777,34 @@ static int gcm_set_sh_desc(struct crypto_aead *aead)
append_operation(desc, ctx->class1_alg_type |
OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT);
- /* cryptlen = seqoutlen - authsize */
- append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize);
+ /* if assoclen + cryptlen is ZERO, skip to ICV write */
+ append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
+ zero_assoc_jump_cmd2 = append_jump(desc, JUMP_TEST_ALL |
+ JUMP_COND_MATH_Z);
- /* assoclen + cryptlen = seqinlen - ivsize */
- append_math_sub_imm_u32(desc, REG2, SEQINLEN, IMM, tfm->ivsize);
+ /* if assoclen is ZERO, skip reading the assoc data */
+ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
+ zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL |
+ JUMP_COND_MATH_Z);
- /* assoclen = (assoclen + cryptlen) - cryptlen */
- append_math_sub(desc, REG1, REG2, REG3, CAAM_CMD_SZ);
+ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
+
+ /* skip assoc data */
+ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF);
+
+ /* cryptlen = seqinlen - assoclen */
+ append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG3, CAAM_CMD_SZ);
/* if cryptlen is ZERO jump to zero-payload commands */
- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL |
JUMP_COND_MATH_Z);
- /* read IV */
- append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_CLASS1 |
- FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
-
- /* if assoclen is ZERO, skip reading the assoc data */
- append_math_add(desc, VARSEQINLEN, ZERO, REG1, CAAM_CMD_SZ);
- zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL |
- JUMP_COND_MATH_Z);
/* read assoc data */
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1);
set_jump_tgt_here(desc, zero_assoc_jump_cmd1);
- append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
+ append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
/* write encrypted data */
append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF);
@@ -814,31 +814,17 @@ static int gcm_set_sh_desc(struct crypto_aead *aead)
FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1);
/* jump the zero-payload commands */
- append_jump(desc, JUMP_TEST_ALL | 7);
+ append_jump(desc, JUMP_TEST_ALL | 2);
/* zero-payload commands */
set_jump_tgt_here(desc, zero_payload_jump_cmd);
- /* if assoclen is ZERO, jump to IV reading - is the only input data */
- append_math_add(desc, VARSEQINLEN, ZERO, REG1, CAAM_CMD_SZ);
- zero_assoc_jump_cmd2 = append_jump(desc, JUMP_TEST_ALL |
- JUMP_COND_MATH_Z);
- /* read IV */
- append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_CLASS1 |
- FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
-
/* read assoc data */
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST1);
- /* jump to ICV writing */
- append_jump(desc, JUMP_TEST_ALL | 2);
-
- /* read IV - is the only input data */
+ /* There is no input data */
set_jump_tgt_here(desc, zero_assoc_jump_cmd2);
- append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_CLASS1 |
- FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 |
- FIFOLD_TYPE_LAST1);
/* write ICV */
append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB |
@@ -862,7 +848,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead)
* must all fit into the 64-word Descriptor h/w Buffer
*/
keys_fit_inline = false;
- if (DESC_GCM_DEC_LEN + DESC_JOB_IO_LEN +
+ if (DESC_GCM_DEC_LEN + GCM_DESC_JOB_IO_LEN +
ctx->enckeylen <= CAAM_DESC_BYTES_MAX)
keys_fit_inline = true;
@@ -886,33 +872,30 @@ static int gcm_set_sh_desc(struct crypto_aead *aead)
append_operation(desc, ctx->class1_alg_type |
OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON);
- /* assoclen + cryptlen = seqinlen - ivsize - icvsize */
- append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM,
- ctx->authsize + tfm->ivsize);
-
- /* assoclen = (assoclen + cryptlen) - cryptlen */
- append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ);
- append_math_sub(desc, REG1, REG3, REG2, CAAM_CMD_SZ);
+ /* if assoclen is ZERO, skip reading the assoc data */
+ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
+ zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL |
+ JUMP_COND_MATH_Z);
- /* read IV */
- append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_CLASS1 |
- FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
- /* jump to zero-payload command if cryptlen is zero */
- append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ);
- zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL |
- JUMP_COND_MATH_Z);
+ /* skip assoc data */
+ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF);
- append_math_add(desc, VARSEQINLEN, ZERO, REG1, CAAM_CMD_SZ);
- /* if asoclen is ZERO, skip reading assoc data */
- zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL |
- JUMP_COND_MATH_Z);
/* read assoc data */
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1);
+
set_jump_tgt_here(desc, zero_assoc_jump_cmd1);
- append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ);
+ /* cryptlen = seqoutlen - assoclen */
+ append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ);
+
+ /* jump to zero-payload command if cryptlen is zero */
+ zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL |
+ JUMP_COND_MATH_Z);
+
+ append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ);
/* store encrypted data */
append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF);
@@ -921,21 +904,9 @@ static int gcm_set_sh_desc(struct crypto_aead *aead)
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1);
- /* jump the zero-payload commands */
- append_jump(desc, JUMP_TEST_ALL | 4);
-
/* zero-payload command */
set_jump_tgt_here(desc, zero_payload_jump_cmd);
- /* if assoclen is ZERO, jump to ICV reading */
- append_math_add(desc, VARSEQINLEN, ZERO, REG1, CAAM_CMD_SZ);
- zero_assoc_jump_cmd2 = append_jump(desc, JUMP_TEST_ALL |
- JUMP_COND_MATH_Z);
- /* read assoc data */
- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
- FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1);
- set_jump_tgt_here(desc, zero_assoc_jump_cmd2);
-
/* read ICV */
append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS1 |
FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1);
@@ -968,13 +939,11 @@ static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize)
static int rfc4106_set_sh_desc(struct crypto_aead *aead)
{
- struct aead_tfm *tfm = &aead->base.crt_aead;
struct caam_ctx *ctx = crypto_aead_ctx(aead);
struct device *jrdev = ctx->jrdev;
bool keys_fit_inline = false;
- u32 *key_jump_cmd, *move_cmd, *write_iv_cmd;
+ u32 *key_jump_cmd;
u32 *desc;
- u32 geniv;
if (!ctx->enckeylen || !ctx->authsize)
return 0;
@@ -984,7 +953,7 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead)
* Job Descriptor and Shared Descriptor
* must fit into the 64-word Descriptor h/w Buffer
*/
- if (DESC_RFC4106_ENC_LEN + DESC_JOB_IO_LEN +
+ if (DESC_RFC4106_ENC_LEN + GCM_DESC_JOB_IO_LEN +
ctx->enckeylen <= CAAM_DESC_BYTES_MAX)
keys_fit_inline = true;
@@ -1007,29 +976,21 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead)
append_operation(desc, ctx->class1_alg_type |
OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT);
- /* cryptlen = seqoutlen - authsize */
- append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize);
+ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
- /* assoclen + cryptlen = seqinlen - ivsize */
- append_math_sub_imm_u32(desc, REG2, SEQINLEN, IMM, tfm->ivsize);
-
- /* assoclen = (assoclen + cryptlen) - cryptlen */
- append_math_sub(desc, VARSEQINLEN, REG2, REG3, CAAM_CMD_SZ);
-
- /* Read Salt */
- append_fifo_load_as_imm(desc, (void *)(ctx->key + ctx->enckeylen),
- 4, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_IV);
- /* Read AES-GCM-ESP IV */
- append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_CLASS1 |
- FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+ /* Skip assoc data */
+ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF);
/* Read assoc data */
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1);
+ /* cryptlen = seqoutlen - assoclen */
+ append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
+
/* Will read cryptlen bytes */
- append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
+ append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
/* Write encrypted data */
append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF);
@@ -1083,30 +1044,21 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead)
append_operation(desc, ctx->class1_alg_type |
OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON);
- /* assoclen + cryptlen = seqinlen - ivsize - icvsize */
- append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM,
- ctx->authsize + tfm->ivsize);
-
- /* assoclen = (assoclen + cryptlen) - cryptlen */
- append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ);
- append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ);
-
- /* Will write cryptlen bytes */
- append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ);
+ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
+ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
- /* Read Salt */
- append_fifo_load_as_imm(desc, (void *)(ctx->key + ctx->enckeylen),
- 4, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_IV);
- /* Read AES-GCM-ESP IV */
- append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_CLASS1 |
- FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+ /* Skip assoc data */
+ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF);
/* Read assoc data */
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1);
+ /* Will write cryptlen bytes */
+ append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ);
+
/* Will read cryptlen bytes */
- append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ);
+ append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ);
/* Store payload data */
append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF);
@@ -1132,107 +1084,6 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead)
desc_bytes(desc), 1);
#endif
- /*
- * Job Descriptor and Shared Descriptors
- * must all fit into the 64-word Descriptor h/w Buffer
- */
- keys_fit_inline = false;
- if (DESC_RFC4106_GIVENC_LEN + DESC_JOB_IO_LEN +
- ctx->split_key_pad_len + ctx->enckeylen <=
- CAAM_DESC_BYTES_MAX)
- keys_fit_inline = true;
-
- /* rfc4106_givencrypt shared descriptor */
- desc = ctx->sh_desc_givenc;
-
- init_sh_desc(desc, HDR_SHARE_SERIAL);
-
- /* Skip key loading if it is loaded due to sharing */
- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
- JUMP_COND_SHRD);
- if (keys_fit_inline)
- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen,
- ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG);
- else
- append_key(desc, ctx->key_dma, ctx->enckeylen,
- CLASS_1 | KEY_DEST_CLASS_REG);
- set_jump_tgt_here(desc, key_jump_cmd);
-
- /* Generate IV */
- geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO |
- NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 |
- NFIFOENTRY_PTYPE_RND | (tfm->ivsize << NFIFOENTRY_DLEN_SHIFT);
- append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB |
- LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM);
- append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO);
- move_cmd = append_move(desc, MOVE_SRC_INFIFO | MOVE_DEST_DESCBUF |
- (tfm->ivsize << MOVE_LEN_SHIFT));
- append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO);
-
- /* Copy generated IV to OFIFO */
- write_iv_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_OUTFIFO |
- (tfm->ivsize << MOVE_LEN_SHIFT));
-
- /* Class 1 operation */
- append_operation(desc, ctx->class1_alg_type |
- OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT);
-
- /* ivsize + cryptlen = seqoutlen - authsize */
- append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize);
-
- /* assoclen = seqinlen - (ivsize + cryptlen) */
- append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG3, CAAM_CMD_SZ);
-
- /* Will write ivsize + cryptlen */
- append_math_add(desc, VARSEQOUTLEN, REG3, REG0, CAAM_CMD_SZ);
-
- /* Read Salt and generated IV */
- append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_IV |
- FIFOLD_TYPE_FLUSH1 | IMMEDIATE | 12);
- /* Append Salt */
- append_data(desc, (void *)(ctx->key + ctx->enckeylen), 4);
- set_move_tgt_here(desc, move_cmd);
- set_move_tgt_here(desc, write_iv_cmd);
- /* Blank commands. Will be overwritten by generated IV. */
- append_cmd(desc, 0x00000000);
- append_cmd(desc, 0x00000000);
- /* End of blank commands */
-
- /* No need to reload iv */
- append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_SKIP);
-
- /* Read assoc data */
- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
- FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1);
-
- /* Will read cryptlen */
- append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
-
- /* Store generated IV and encrypted data */
- append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF);
-
- /* Read payload data */
- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
- FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1);
-
- /* Write ICV */
- append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB |
- LDST_SRCDST_BYTE_CONTEXT);
-
- ctx->sh_desc_givenc_dma = dma_map_single(jrdev, desc,
- desc_bytes(desc),
- DMA_TO_DEVICE);
- if (dma_mapping_error(jrdev, ctx->sh_desc_givenc_dma)) {
- dev_err(jrdev, "unable to map shared descriptor\n");
- return -ENOMEM;
- }
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "rfc4106 givenc shdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc,
- desc_bytes(desc), 1);
-#endif
-
return 0;
}
@@ -1249,14 +1100,12 @@ static int rfc4106_setauthsize(struct crypto_aead *authenc,
static int rfc4543_set_sh_desc(struct crypto_aead *aead)
{
- struct aead_tfm *tfm = &aead->base.crt_aead;
struct caam_ctx *ctx = crypto_aead_ctx(aead);
struct device *jrdev = ctx->jrdev;
bool keys_fit_inline = false;
- u32 *key_jump_cmd, *write_iv_cmd, *write_aad_cmd;
+ u32 *key_jump_cmd;
u32 *read_move_cmd, *write_move_cmd;
u32 *desc;
- u32 geniv;
if (!ctx->enckeylen || !ctx->authsize)
return 0;
@@ -1266,7 +1115,7 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
* Job Descriptor and Shared Descriptor
* must fit into the 64-word Descriptor h/w Buffer
*/
- if (DESC_RFC4543_ENC_LEN + DESC_JOB_IO_LEN +
+ if (DESC_RFC4543_ENC_LEN + GCM_DESC_JOB_IO_LEN +
ctx->enckeylen <= CAAM_DESC_BYTES_MAX)
keys_fit_inline = true;
@@ -1289,48 +1138,8 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
append_operation(desc, ctx->class1_alg_type |
OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT);
- /* Load AES-GMAC ESP IV into Math1 register */
- append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_DECO_MATH1 |
- LDST_CLASS_DECO | tfm->ivsize);
-
- /* Wait the DMA transaction to finish */
- append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM |
- (1 << JUMP_OFFSET_SHIFT));
-
- /* Overwrite blank immediate AES-GMAC ESP IV data */
- write_iv_cmd = append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_DESCBUF |
- (tfm->ivsize << MOVE_LEN_SHIFT));
-
- /* Overwrite blank immediate AAD data */
- write_aad_cmd = append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_DESCBUF |
- (tfm->ivsize << MOVE_LEN_SHIFT));
-
- /* cryptlen = seqoutlen - authsize */
- append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize);
-
- /* assoclen = (seqinlen - ivsize) - cryptlen */
- append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG3, CAAM_CMD_SZ);
-
- /* Read Salt and AES-GMAC ESP IV */
- append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE |
- FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 | (4 + tfm->ivsize));
- /* Append Salt */
- append_data(desc, (void *)(ctx->key + ctx->enckeylen), 4);
- set_move_tgt_here(desc, write_iv_cmd);
- /* Blank commands. Will be overwritten by AES-GMAC ESP IV. */
- append_cmd(desc, 0x00000000);
- append_cmd(desc, 0x00000000);
- /* End of blank commands */
-
- /* Read assoc data */
- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
- FIFOLD_TYPE_AAD);
-
- /* Will read cryptlen bytes */
- append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
-
- /* Will write cryptlen bytes */
- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
+ /* assoclen + cryptlen = seqinlen */
+ append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ);
/*
* MOVE_LEN opcode is not available in all SEC HW revisions,
@@ -1342,16 +1151,13 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF |
(0x8 << MOVE_LEN_SHIFT));
- /* Authenticate AES-GMAC ESP IV */
- append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE |
- FIFOLD_TYPE_AAD | tfm->ivsize);
- set_move_tgt_here(desc, write_aad_cmd);
- /* Blank commands. Will be overwritten by AES-GMAC ESP IV. */
- append_cmd(desc, 0x00000000);
- append_cmd(desc, 0x00000000);
- /* End of blank commands */
+ /* Will read assoclen + cryptlen bytes */
+ append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
- /* Read and write cryptlen bytes */
+ /* Will write assoclen + cryptlen bytes */
+ append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
+
+ /* Read and write assoclen + cryptlen bytes */
aead_append_src_dst(desc, FIFOLD_TYPE_AAD);
set_move_tgt_here(desc, read_move_cmd);
@@ -1382,7 +1188,7 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
* must all fit into the 64-word Descriptor h/w Buffer
*/
keys_fit_inline = false;
- if (DESC_RFC4543_DEC_LEN + DESC_JOB_IO_LEN +
+ if (DESC_RFC4543_DEC_LEN + GCM_DESC_JOB_IO_LEN +
ctx->enckeylen <= CAAM_DESC_BYTES_MAX)
keys_fit_inline = true;
@@ -1405,28 +1211,8 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
append_operation(desc, ctx->class1_alg_type |
OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON);
- /* Load AES-GMAC ESP IV into Math1 register */
- append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_DECO_MATH1 |
- LDST_CLASS_DECO | tfm->ivsize);
-
- /* Wait the DMA transaction to finish */
- append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM |
- (1 << JUMP_OFFSET_SHIFT));
-
- /* assoclen + cryptlen = (seqinlen - ivsize) - icvsize */
- append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM, ctx->authsize);
-
- /* Overwrite blank immediate AES-GMAC ESP IV data */
- write_iv_cmd = append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_DESCBUF |
- (tfm->ivsize << MOVE_LEN_SHIFT));
-
- /* Overwrite blank immediate AAD data */
- write_aad_cmd = append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_DESCBUF |
- (tfm->ivsize << MOVE_LEN_SHIFT));
-
- /* assoclen = (assoclen + cryptlen) - cryptlen */
- append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ);
- append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ);
+ /* assoclen + cryptlen = seqoutlen */
+ append_math_sub(desc, REG3, SEQOUTLEN, REG0, CAAM_CMD_SZ);
/*
* MOVE_LEN opcode is not available in all SEC HW revisions,
@@ -1438,40 +1224,16 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF |
(0x8 << MOVE_LEN_SHIFT));
- /* Read Salt and AES-GMAC ESP IV */
- append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE |
- FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 | (4 + tfm->ivsize));
- /* Append Salt */
- append_data(desc, (void *)(ctx->key + ctx->enckeylen), 4);
- set_move_tgt_here(desc, write_iv_cmd);
- /* Blank commands. Will be overwritten by AES-GMAC ESP IV. */
- append_cmd(desc, 0x00000000);
- append_cmd(desc, 0x00000000);
- /* End of blank commands */
-
- /* Read assoc data */
- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
- FIFOLD_TYPE_AAD);
-
- /* Will read cryptlen bytes */
- append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ);
+ /* Will read assoclen + cryptlen bytes */
+ append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ);
- /* Will write cryptlen bytes */
- append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ);
-
- /* Authenticate AES-GMAC ESP IV */
- append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE |
- FIFOLD_TYPE_AAD | tfm->ivsize);
- set_move_tgt_here(desc, write_aad_cmd);
- /* Blank commands. Will be overwritten by AES-GMAC ESP IV. */
- append_cmd(desc, 0x00000000);
- append_cmd(desc, 0x00000000);
- /* End of blank commands */
+ /* Will write assoclen + cryptlen bytes */
+ append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ);
/* Store payload data */
append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF);
- /* In-snoop cryptlen data */
+ /* In-snoop assoclen + cryptlen data */
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | FIFOLDST_VLF |
FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST2FLUSH1);
@@ -1499,135 +1261,6 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
desc_bytes(desc), 1);
#endif
- /*
- * Job Descriptor and Shared Descriptors
- * must all fit into the 64-word Descriptor h/w Buffer
- */
- keys_fit_inline = false;
- if (DESC_RFC4543_GIVENC_LEN + DESC_JOB_IO_LEN +
- ctx->enckeylen <= CAAM_DESC_BYTES_MAX)
- keys_fit_inline = true;
-
- /* rfc4543_givencrypt shared descriptor */
- desc = ctx->sh_desc_givenc;
-
- init_sh_desc(desc, HDR_SHARE_SERIAL);
-
- /* Skip key loading if it is loaded due to sharing */
- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
- JUMP_COND_SHRD);
- if (keys_fit_inline)
- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen,
- ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG);
- else
- append_key(desc, ctx->key_dma, ctx->enckeylen,
- CLASS_1 | KEY_DEST_CLASS_REG);
- set_jump_tgt_here(desc, key_jump_cmd);
-
- /* Generate IV */
- geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO |
- NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 |
- NFIFOENTRY_PTYPE_RND | (tfm->ivsize << NFIFOENTRY_DLEN_SHIFT);
- append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB |
- LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM);
- append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO);
- /* Move generated IV to Math1 register */
- append_move(desc, MOVE_SRC_INFIFO | MOVE_DEST_MATH1 |
- (tfm->ivsize << MOVE_LEN_SHIFT));
- append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO);
-
- /* Overwrite blank immediate AES-GMAC IV data */
- write_iv_cmd = append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_DESCBUF |
- (tfm->ivsize << MOVE_LEN_SHIFT));
-
- /* Overwrite blank immediate AAD data */
- write_aad_cmd = append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_DESCBUF |
- (tfm->ivsize << MOVE_LEN_SHIFT));
-
- /* Copy generated IV to OFIFO */
- append_move(desc, MOVE_SRC_MATH1 | MOVE_DEST_OUTFIFO |
- (tfm->ivsize << MOVE_LEN_SHIFT));
-
- /* Class 1 operation */
- append_operation(desc, ctx->class1_alg_type |
- OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT);
-
- /* ivsize + cryptlen = seqoutlen - authsize */
- append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize);
-
- /* assoclen = seqinlen - (ivsize + cryptlen) */
- append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG3, CAAM_CMD_SZ);
-
- /* Will write ivsize + cryptlen */
- append_math_add(desc, VARSEQOUTLEN, REG3, REG0, CAAM_CMD_SZ);
-
- /*
- * MOVE_LEN opcode is not available in all SEC HW revisions,
- * thus need to do some magic, i.e. self-patch the descriptor
- * buffer.
- */
- read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 |
- (0x6 << MOVE_LEN_SHIFT));
- write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF |
- (0x8 << MOVE_LEN_SHIFT));
-
- /* Read Salt and AES-GMAC generated IV */
- append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE |
- FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 | (4 + tfm->ivsize));
- /* Append Salt */
- append_data(desc, (void *)(ctx->key + ctx->enckeylen), 4);
- set_move_tgt_here(desc, write_iv_cmd);
- /* Blank commands. Will be overwritten by AES-GMAC generated IV. */
- append_cmd(desc, 0x00000000);
- append_cmd(desc, 0x00000000);
- /* End of blank commands */
-
- /* No need to reload iv */
- append_seq_fifo_load(desc, tfm->ivsize, FIFOLD_CLASS_SKIP);
-
- /* Read assoc data */
- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
- FIFOLD_TYPE_AAD);
-
- /* Will read cryptlen */
- append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
-
- /* Authenticate AES-GMAC IV */
- append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE |
- FIFOLD_TYPE_AAD | tfm->ivsize);
- set_move_tgt_here(desc, write_aad_cmd);
- /* Blank commands. Will be overwritten by AES-GMAC IV. */
- append_cmd(desc, 0x00000000);
- append_cmd(desc, 0x00000000);
- /* End of blank commands */
-
- /* Read and write cryptlen bytes */
- aead_append_src_dst(desc, FIFOLD_TYPE_AAD);
-
- set_move_tgt_here(desc, read_move_cmd);
- set_move_tgt_here(desc, write_move_cmd);
- append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO);
- /* Move payload data to OFIFO */
- append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO);
-
- /* Write ICV */
- append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB |
- LDST_SRCDST_BYTE_CONTEXT);
-
- ctx->sh_desc_givenc_dma = dma_map_single(jrdev, desc,
- desc_bytes(desc),
- DMA_TO_DEVICE);
- if (dma_mapping_error(jrdev, ctx->sh_desc_givenc_dma)) {
- dev_err(jrdev, "unable to map shared descriptor\n");
- return -ENOMEM;
- }
-#ifdef DEBUG
- print_hex_dump(KERN_ERR,
- "rfc4543 givenc shdesc@"__stringify(__LINE__)": ",
- DUMP_PREFIX_ADDRESS, 16, 4, desc,
- desc_bytes(desc), 1);
-#endif
-
return 0;
}
@@ -2100,7 +1733,7 @@ struct aead_edesc {
int sec4_sg_bytes;
dma_addr_t sec4_sg_dma;
struct sec4_sg_entry *sec4_sg;
- u32 hw_desc[0];
+ u32 hw_desc[];
};
/*
@@ -2154,6 +1787,16 @@ static void aead_unmap(struct device *dev,
struct aead_edesc *edesc,
struct aead_request *req)
{
+ caam_unmap(dev, req->src, req->dst,
+ edesc->src_nents, edesc->src_chained, edesc->dst_nents,
+ edesc->dst_chained, 0, 0,
+ edesc->sec4_sg_dma, edesc->sec4_sg_bytes);
+}
+
+static void old_aead_unmap(struct device *dev,
+ struct aead_edesc *edesc,
+ struct aead_request *req)
+{
struct crypto_aead *aead = crypto_aead_reqtfm(req);
int ivsize = crypto_aead_ivsize(aead);
@@ -2184,6 +1827,28 @@ static void aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
{
struct aead_request *req = context;
struct aead_edesc *edesc;
+
+#ifdef DEBUG
+ dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
+#endif
+
+ edesc = container_of(desc, struct aead_edesc, hw_desc[0]);
+
+ if (err)
+ caam_jr_strstatus(jrdev, err);
+
+ aead_unmap(jrdev, edesc, req);
+
+ kfree(edesc);
+
+ aead_request_complete(req, err);
+}
+
+static void old_aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
+ void *context)
+{
+ struct aead_request *req = context;
+ struct aead_edesc *edesc;
#ifdef DEBUG
struct crypto_aead *aead = crypto_aead_reqtfm(req);
struct caam_ctx *ctx = crypto_aead_ctx(aead);
@@ -2198,7 +1863,7 @@ static void aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
if (err)
caam_jr_strstatus(jrdev, err);
- aead_unmap(jrdev, edesc, req);
+ old_aead_unmap(jrdev, edesc, req);
#ifdef DEBUG
print_hex_dump(KERN_ERR, "assoc @"__stringify(__LINE__)": ",
@@ -2223,6 +1888,34 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
{
struct aead_request *req = context;
struct aead_edesc *edesc;
+
+#ifdef DEBUG
+ dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
+#endif
+
+ edesc = container_of(desc, struct aead_edesc, hw_desc[0]);
+
+ if (err)
+ caam_jr_strstatus(jrdev, err);
+
+ aead_unmap(jrdev, edesc, req);
+
+ /*
+ * verify hw auth check passed else return -EBADMSG
+ */
+ if ((err & JRSTA_CCBERR_ERRID_MASK) == JRSTA_CCBERR_ERRID_ICVCHK)
+ err = -EBADMSG;
+
+ kfree(edesc);
+
+ aead_request_complete(req, err);
+}
+
+static void old_aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
+ void *context)
+{
+ struct aead_request *req = context;
+ struct aead_edesc *edesc;
#ifdef DEBUG
struct crypto_aead *aead = crypto_aead_reqtfm(req);
struct caam_ctx *ctx = crypto_aead_ctx(aead);
@@ -2246,7 +1939,7 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
if (err)
caam_jr_strstatus(jrdev, err);
- aead_unmap(jrdev, edesc, req);
+ old_aead_unmap(jrdev, edesc, req);
/*
* verify hw auth check passed else return -EBADMSG
@@ -2342,10 +2035,10 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
/*
* Fill in aead job descriptor
*/
-static void init_aead_job(u32 *sh_desc, dma_addr_t ptr,
- struct aead_edesc *edesc,
- struct aead_request *req,
- bool all_contig, bool encrypt)
+static void old_init_aead_job(u32 *sh_desc, dma_addr_t ptr,
+ struct aead_edesc *edesc,
+ struct aead_request *req,
+ bool all_contig, bool encrypt)
{
struct crypto_aead *aead = crypto_aead_reqtfm(req);
struct caam_ctx *ctx = crypto_aead_ctx(aead);
@@ -2425,6 +2118,97 @@ static void init_aead_job(u32 *sh_desc, dma_addr_t ptr,
}
/*
+ * Fill in aead job descriptor
+ */
+static void init_aead_job(struct aead_request *req,
+ struct aead_edesc *edesc,
+ bool all_contig, bool encrypt)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ int authsize = ctx->authsize;
+ u32 *desc = edesc->hw_desc;
+ u32 out_options, in_options;
+ dma_addr_t dst_dma, src_dma;
+ int len, sec4_sg_index = 0;
+ dma_addr_t ptr;
+ u32 *sh_desc;
+
+ sh_desc = encrypt ? ctx->sh_desc_enc : ctx->sh_desc_dec;
+ ptr = encrypt ? ctx->sh_desc_enc_dma : ctx->sh_desc_dec_dma;
+
+ len = desc_len(sh_desc);
+ init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE);
+
+ if (all_contig) {
+ src_dma = sg_dma_address(req->src);
+ in_options = 0;
+ } else {
+ src_dma = edesc->sec4_sg_dma;
+ sec4_sg_index += edesc->src_nents;
+ in_options = LDST_SGF;
+ }
+
+ append_seq_in_ptr(desc, src_dma, req->assoclen + req->cryptlen,
+ in_options);
+
+ dst_dma = src_dma;
+ out_options = in_options;
+
+ if (unlikely(req->src != req->dst)) {
+ if (!edesc->dst_nents) {
+ dst_dma = sg_dma_address(req->dst);
+ } else {
+ dst_dma = edesc->sec4_sg_dma +
+ sec4_sg_index *
+ sizeof(struct sec4_sg_entry);
+ out_options = LDST_SGF;
+ }
+ }
+
+ if (encrypt)
+ append_seq_out_ptr(desc, dst_dma,
+ req->assoclen + req->cryptlen + authsize,
+ out_options);
+ else
+ append_seq_out_ptr(desc, dst_dma,
+ req->assoclen + req->cryptlen - authsize,
+ out_options);
+
+ /* REG3 = assoclen */
+ append_math_add_imm_u32(desc, REG3, ZERO, IMM, req->assoclen);
+}
+
+static void init_gcm_job(struct aead_request *req,
+ struct aead_edesc *edesc,
+ bool all_contig, bool encrypt)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ unsigned int ivsize = crypto_aead_ivsize(aead);
+ u32 *desc = edesc->hw_desc;
+ bool generic_gcm = (ivsize == 12);
+ unsigned int last;
+
+ init_aead_job(req, edesc, all_contig, encrypt);
+
+ /* BUG This should not be specific to generic GCM. */
+ last = 0;
+ if (encrypt && generic_gcm && !(req->assoclen + req->cryptlen))
+ last = FIFOLD_TYPE_LAST1;
+
+ /* Read GCM IV */
+ append_cmd(desc, CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | IMMEDIATE |
+ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 | 12 | last);
+ /* Append Salt */
+ if (!generic_gcm)
+ append_data(desc, ctx->key + ctx->enckeylen, 4);
+ /* Append IV */
+ append_data(desc, req->iv, ivsize);
+ /* End of blank commands */
+}
+
+/*
* Fill in aead givencrypt job descriptor
*/
static void init_aead_giv_job(u32 *sh_desc, dma_addr_t ptr,
@@ -2608,9 +2392,10 @@ static void init_ablkcipher_giv_job(u32 *sh_desc, dma_addr_t ptr,
/*
* allocate and map the aead extended descriptor
*/
-static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
- int desc_bytes, bool *all_contig_ptr,
- bool encrypt)
+static struct aead_edesc *old_aead_edesc_alloc(struct aead_request *req,
+ int desc_bytes,
+ bool *all_contig_ptr,
+ bool encrypt)
{
struct crypto_aead *aead = crypto_aead_reqtfm(req);
struct caam_ctx *ctx = crypto_aead_ctx(aead);
@@ -2713,10 +2498,8 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
sec4_sg_index = 0;
if (!all_contig) {
if (!is_gcm) {
- sg_to_sec4_sg(req->assoc,
- assoc_nents,
- edesc->sec4_sg +
- sec4_sg_index, 0);
+ sg_to_sec4_sg_len(req->assoc, req->assoclen,
+ edesc->sec4_sg + sec4_sg_index);
sec4_sg_index += assoc_nents;
}
@@ -2725,10 +2508,8 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
sec4_sg_index += 1;
if (is_gcm) {
- sg_to_sec4_sg(req->assoc,
- assoc_nents,
- edesc->sec4_sg +
- sec4_sg_index, 0);
+ sg_to_sec4_sg_len(req->assoc, req->assoclen,
+ edesc->sec4_sg + sec4_sg_index);
sec4_sg_index += assoc_nents;
}
@@ -2752,7 +2533,124 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
return edesc;
}
-static int aead_encrypt(struct aead_request *req)
+/*
+ * allocate and map the aead extended descriptor
+ */
+static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
+ int desc_bytes, bool *all_contig_ptr,
+ bool encrypt)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC;
+ int src_nents, dst_nents = 0;
+ struct aead_edesc *edesc;
+ int sgc;
+ bool all_contig = true;
+ bool src_chained = false, dst_chained = false;
+ int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes;
+ unsigned int authsize = ctx->authsize;
+
+ if (unlikely(req->dst != req->src)) {
+ src_nents = sg_count(req->src, req->assoclen + req->cryptlen,
+ &src_chained);
+ dst_nents = sg_count(req->dst,
+ req->assoclen + req->cryptlen +
+ (encrypt ? authsize : (-authsize)),
+ &dst_chained);
+ } else {
+ src_nents = sg_count(req->src,
+ req->assoclen + req->cryptlen +
+ (encrypt ? authsize : 0),
+ &src_chained);
+ }
+
+ /* Check if data are contiguous. */
+ all_contig = !src_nents;
+ if (!all_contig) {
+ src_nents = src_nents ? : 1;
+ sec4_sg_len = src_nents;
+ }
+
+ sec4_sg_len += dst_nents;
+
+ sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry);
+
+ /* allocate space for base edesc and hw desc commands, link tables */
+ edesc = kzalloc(sizeof(struct aead_edesc) + desc_bytes +
+ sec4_sg_bytes, GFP_DMA | flags);
+ if (!edesc) {
+ dev_err(jrdev, "could not allocate extended descriptor\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (likely(req->src == req->dst)) {
+ sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1,
+ DMA_BIDIRECTIONAL, src_chained);
+ if (unlikely(!sgc)) {
+ dev_err(jrdev, "unable to map source\n");
+ kfree(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+ } else {
+ sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1,
+ DMA_TO_DEVICE, src_chained);
+ if (unlikely(!sgc)) {
+ dev_err(jrdev, "unable to map source\n");
+ kfree(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ sgc = dma_map_sg_chained(jrdev, req->dst, dst_nents ? : 1,
+ DMA_FROM_DEVICE, dst_chained);
+ if (unlikely(!sgc)) {
+ dev_err(jrdev, "unable to map destination\n");
+ dma_unmap_sg_chained(jrdev, req->src, src_nents ? : 1,
+ DMA_TO_DEVICE, src_chained);
+ kfree(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ edesc->src_nents = src_nents;
+ edesc->src_chained = src_chained;
+ edesc->dst_nents = dst_nents;
+ edesc->dst_chained = dst_chained;
+ edesc->sec4_sg = (void *)edesc + sizeof(struct aead_edesc) +
+ desc_bytes;
+ *all_contig_ptr = all_contig;
+
+ sec4_sg_index = 0;
+ if (!all_contig) {
+ sg_to_sec4_sg_last(req->src, src_nents,
+ edesc->sec4_sg + sec4_sg_index, 0);
+ sec4_sg_index += src_nents;
+ }
+ if (dst_nents) {
+ sg_to_sec4_sg_last(req->dst, dst_nents,
+ edesc->sec4_sg + sec4_sg_index, 0);
+ }
+
+ if (!sec4_sg_bytes)
+ return edesc;
+
+ edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
+ sec4_sg_bytes, DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) {
+ dev_err(jrdev, "unable to map S/G table\n");
+ aead_unmap(jrdev, edesc, req);
+ kfree(edesc);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ edesc->sec4_sg_bytes = sec4_sg_bytes;
+
+ return edesc;
+}
+
+static int gcm_encrypt(struct aead_request *req)
{
struct aead_edesc *edesc;
struct crypto_aead *aead = crypto_aead_reqtfm(req);
@@ -2763,14 +2661,12 @@ static int aead_encrypt(struct aead_request *req)
int ret = 0;
/* allocate extended descriptor */
- edesc = aead_edesc_alloc(req, DESC_JOB_IO_LEN *
- CAAM_CMD_SZ, &all_contig, true);
+ edesc = aead_edesc_alloc(req, GCM_DESC_JOB_IO_LEN, &all_contig, true);
if (IS_ERR(edesc))
return PTR_ERR(edesc);
/* Create and submit job descriptor */
- init_aead_job(ctx->sh_desc_enc, ctx->sh_desc_enc_dma, edesc, req,
- all_contig, true);
+ init_gcm_job(req, edesc, all_contig, true);
#ifdef DEBUG
print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
@@ -2789,7 +2685,7 @@ static int aead_encrypt(struct aead_request *req)
return ret;
}
-static int aead_decrypt(struct aead_request *req)
+static int old_aead_encrypt(struct aead_request *req)
{
struct aead_edesc *edesc;
struct crypto_aead *aead = crypto_aead_reqtfm(req);
@@ -2800,8 +2696,80 @@ static int aead_decrypt(struct aead_request *req)
int ret = 0;
/* allocate extended descriptor */
- edesc = aead_edesc_alloc(req, DESC_JOB_IO_LEN *
- CAAM_CMD_SZ, &all_contig, false);
+ edesc = old_aead_edesc_alloc(req, DESC_JOB_IO_LEN *
+ CAAM_CMD_SZ, &all_contig, true);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ /* Create and submit job descriptor */
+ old_init_aead_job(ctx->sh_desc_enc, ctx->sh_desc_enc_dma, edesc, req,
+ all_contig, true);
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
+ desc_bytes(edesc->hw_desc), 1);
+#endif
+
+ desc = edesc->hw_desc;
+ ret = caam_jr_enqueue(jrdev, desc, old_aead_encrypt_done, req);
+ if (!ret) {
+ ret = -EINPROGRESS;
+ } else {
+ old_aead_unmap(jrdev, edesc, req);
+ kfree(edesc);
+ }
+
+ return ret;
+}
+
+static int gcm_decrypt(struct aead_request *req)
+{
+ struct aead_edesc *edesc;
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ bool all_contig;
+ u32 *desc;
+ int ret = 0;
+
+ /* allocate extended descriptor */
+ edesc = aead_edesc_alloc(req, GCM_DESC_JOB_IO_LEN, &all_contig, false);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ /* Create and submit job descriptor*/
+ init_gcm_job(req, edesc, all_contig, false);
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
+ desc_bytes(edesc->hw_desc), 1);
+#endif
+
+ desc = edesc->hw_desc;
+ ret = caam_jr_enqueue(jrdev, desc, aead_decrypt_done, req);
+ if (!ret) {
+ ret = -EINPROGRESS;
+ } else {
+ aead_unmap(jrdev, edesc, req);
+ kfree(edesc);
+ }
+
+ return ret;
+}
+
+static int old_aead_decrypt(struct aead_request *req)
+{
+ struct aead_edesc *edesc;
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ bool all_contig;
+ u32 *desc;
+ int ret = 0;
+
+ /* allocate extended descriptor */
+ edesc = old_aead_edesc_alloc(req, DESC_JOB_IO_LEN *
+ CAAM_CMD_SZ, &all_contig, false);
if (IS_ERR(edesc))
return PTR_ERR(edesc);
@@ -2812,8 +2780,8 @@ static int aead_decrypt(struct aead_request *req)
#endif
/* Create and submit job descriptor*/
- init_aead_job(ctx->sh_desc_dec,
- ctx->sh_desc_dec_dma, edesc, req, all_contig, false);
+ old_init_aead_job(ctx->sh_desc_dec,
+ ctx->sh_desc_dec_dma, edesc, req, all_contig, false);
#ifdef DEBUG
print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ",
DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc,
@@ -2821,11 +2789,11 @@ static int aead_decrypt(struct aead_request *req)
#endif
desc = edesc->hw_desc;
- ret = caam_jr_enqueue(jrdev, desc, aead_decrypt_done, req);
+ ret = caam_jr_enqueue(jrdev, desc, old_aead_decrypt_done, req);
if (!ret) {
ret = -EINPROGRESS;
} else {
- aead_unmap(jrdev, edesc, req);
+ old_aead_unmap(jrdev, edesc, req);
kfree(edesc);
}
@@ -2953,8 +2921,8 @@ static struct aead_edesc *aead_giv_edesc_alloc(struct aead_givcrypt_request
sec4_sg_index = 0;
if (!(contig & GIV_SRC_CONTIG)) {
if (!is_gcm) {
- sg_to_sec4_sg(req->assoc, assoc_nents,
- edesc->sec4_sg + sec4_sg_index, 0);
+ sg_to_sec4_sg_len(req->assoc, req->assoclen,
+ edesc->sec4_sg + sec4_sg_index);
sec4_sg_index += assoc_nents;
}
@@ -2963,8 +2931,8 @@ static struct aead_edesc *aead_giv_edesc_alloc(struct aead_givcrypt_request
sec4_sg_index += 1;
if (is_gcm) {
- sg_to_sec4_sg(req->assoc, assoc_nents,
- edesc->sec4_sg + sec4_sg_index, 0);
+ sg_to_sec4_sg_len(req->assoc, req->assoclen,
+ edesc->sec4_sg + sec4_sg_index);
sec4_sg_index += assoc_nents;
}
@@ -2999,7 +2967,7 @@ static struct aead_edesc *aead_giv_edesc_alloc(struct aead_givcrypt_request
return edesc;
}
-static int aead_givencrypt(struct aead_givcrypt_request *areq)
+static int old_aead_givencrypt(struct aead_givcrypt_request *areq)
{
struct aead_request *req = &areq->areq;
struct aead_edesc *edesc;
@@ -3033,11 +3001,11 @@ static int aead_givencrypt(struct aead_givcrypt_request *areq)
#endif
desc = edesc->hw_desc;
- ret = caam_jr_enqueue(jrdev, desc, aead_encrypt_done, req);
+ ret = caam_jr_enqueue(jrdev, desc, old_aead_encrypt_done, req);
if (!ret) {
ret = -EINPROGRESS;
} else {
- aead_unmap(jrdev, edesc, req);
+ old_aead_unmap(jrdev, edesc, req);
kfree(edesc);
}
@@ -3046,7 +3014,7 @@ static int aead_givencrypt(struct aead_givcrypt_request *areq)
static int aead_null_givencrypt(struct aead_givcrypt_request *areq)
{
- return aead_encrypt(&areq->areq);
+ return old_aead_encrypt(&areq->areq);
}
/*
@@ -3379,11 +3347,7 @@ struct caam_alg_template {
u32 type;
union {
struct ablkcipher_alg ablkcipher;
- struct aead_alg aead;
- struct blkcipher_alg blkcipher;
- struct cipher_alg cipher;
- struct compress_alg compress;
- struct rng_alg rng;
+ struct old_aead_alg aead;
} template_u;
u32 class1_alg_type;
u32 class2_alg_type;
@@ -3400,8 +3364,8 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
.givencrypt = aead_null_givencrypt,
.geniv = "<built-in>",
.ivsize = NULL_IV_SIZE,
@@ -3419,8 +3383,8 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
.givencrypt = aead_null_givencrypt,
.geniv = "<built-in>",
.ivsize = NULL_IV_SIZE,
@@ -3438,8 +3402,8 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
.givencrypt = aead_null_givencrypt,
.geniv = "<built-in>",
.ivsize = NULL_IV_SIZE,
@@ -3458,8 +3422,8 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
.givencrypt = aead_null_givencrypt,
.geniv = "<built-in>",
.ivsize = NULL_IV_SIZE,
@@ -3478,8 +3442,8 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
.givencrypt = aead_null_givencrypt,
.geniv = "<built-in>",
.ivsize = NULL_IV_SIZE,
@@ -3498,8 +3462,8 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
.givencrypt = aead_null_givencrypt,
.geniv = "<built-in>",
.ivsize = NULL_IV_SIZE,
@@ -3518,9 +3482,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
@@ -3537,9 +3501,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
@@ -3556,9 +3520,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
@@ -3576,9 +3540,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
@@ -3596,9 +3560,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
@@ -3617,9 +3581,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
@@ -3637,9 +3601,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
@@ -3656,9 +3620,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
@@ -3675,9 +3639,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
@@ -3695,9 +3659,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
@@ -3715,9 +3679,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
@@ -3735,9 +3699,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = DES3_EDE_BLOCK_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
@@ -3755,9 +3719,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
@@ -3774,9 +3738,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
@@ -3793,9 +3757,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
@@ -3813,9 +3777,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
@@ -3833,9 +3797,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
@@ -3853,9 +3817,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = DES_BLOCK_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
@@ -3873,9 +3837,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = MD5_DIGEST_SIZE,
@@ -3892,9 +3856,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
@@ -3911,9 +3875,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA224_DIGEST_SIZE,
@@ -3931,9 +3895,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
@@ -3951,9 +3915,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA384_DIGEST_SIZE,
@@ -3971,9 +3935,9 @@ static struct caam_alg_template driver_algs[] = {
.template_aead = {
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
+ .encrypt = old_aead_encrypt,
+ .decrypt = old_aead_decrypt,
+ .givencrypt = old_aead_givencrypt,
.geniv = "<built-in>",
.ivsize = CTR_RFC3686_IV_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
@@ -3983,58 +3947,6 @@ static struct caam_alg_template driver_algs[] = {
OP_ALG_AAI_HMAC_PRECOMP,
.alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC,
},
- {
- .name = "rfc4106(gcm(aes))",
- .driver_name = "rfc4106-gcm-aes-caam",
- .blocksize = 1,
- .type = CRYPTO_ALG_TYPE_AEAD,
- .template_aead = {
- .setkey = rfc4106_setkey,
- .setauthsize = rfc4106_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
- .geniv = "<built-in>",
- .ivsize = 8,
- .maxauthsize = AES_BLOCK_SIZE,
- },
- .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
- },
- {
- .name = "rfc4543(gcm(aes))",
- .driver_name = "rfc4543-gcm-aes-caam",
- .blocksize = 1,
- .type = CRYPTO_ALG_TYPE_AEAD,
- .template_aead = {
- .setkey = rfc4543_setkey,
- .setauthsize = rfc4543_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = aead_givencrypt,
- .geniv = "<built-in>",
- .ivsize = 8,
- .maxauthsize = AES_BLOCK_SIZE,
- },
- .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
- },
- /* Galois Counter Mode */
- {
- .name = "gcm(aes)",
- .driver_name = "gcm-aes-caam",
- .blocksize = 1,
- .type = CRYPTO_ALG_TYPE_AEAD,
- .template_aead = {
- .setkey = gcm_setkey,
- .setauthsize = gcm_setauthsize,
- .encrypt = aead_encrypt,
- .decrypt = aead_decrypt,
- .givencrypt = NULL,
- .geniv = "<built-in>",
- .ivsize = 12,
- .maxauthsize = AES_BLOCK_SIZE,
- },
- .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
- },
/* ablkcipher descriptor */
{
.name = "cbc(aes)",
@@ -4124,21 +4036,84 @@ static struct caam_alg_template driver_algs[] = {
}
};
-struct caam_crypto_alg {
- struct list_head entry;
+struct caam_alg_entry {
int class1_alg_type;
int class2_alg_type;
int alg_op;
+};
+
+struct caam_aead_alg {
+ struct aead_alg aead;
+ struct caam_alg_entry caam;
+ bool registered;
+};
+
+static struct caam_aead_alg driver_aeads[] = {
+ {
+ .aead = {
+ .base = {
+ .cra_name = "rfc4106(gcm(aes))",
+ .cra_driver_name = "rfc4106-gcm-aes-caam",
+ .cra_blocksize = 1,
+ },
+ .setkey = rfc4106_setkey,
+ .setauthsize = rfc4106_setauthsize,
+ .encrypt = gcm_encrypt,
+ .decrypt = gcm_decrypt,
+ .ivsize = 8,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "rfc4543(gcm(aes))",
+ .cra_driver_name = "rfc4543-gcm-aes-caam",
+ .cra_blocksize = 1,
+ },
+ .setkey = rfc4543_setkey,
+ .setauthsize = rfc4543_setauthsize,
+ .encrypt = gcm_encrypt,
+ .decrypt = gcm_decrypt,
+ .ivsize = 8,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+ },
+ },
+ /* Galois Counter Mode */
+ {
+ .aead = {
+ .base = {
+ .cra_name = "gcm(aes)",
+ .cra_driver_name = "gcm-aes-caam",
+ .cra_blocksize = 1,
+ },
+ .setkey = gcm_setkey,
+ .setauthsize = gcm_setauthsize,
+ .encrypt = gcm_encrypt,
+ .decrypt = gcm_decrypt,
+ .ivsize = 12,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+ },
+ },
+};
+
+struct caam_crypto_alg {
struct crypto_alg crypto_alg;
+ struct list_head entry;
+ struct caam_alg_entry caam;
};
-static int caam_cra_init(struct crypto_tfm *tfm)
+static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam)
{
- struct crypto_alg *alg = tfm->__crt_alg;
- struct caam_crypto_alg *caam_alg =
- container_of(alg, struct caam_crypto_alg, crypto_alg);
- struct caam_ctx *ctx = crypto_tfm_ctx(tfm);
-
ctx->jrdev = caam_jr_alloc();
if (IS_ERR(ctx->jrdev)) {
pr_err("Job Ring Device allocation for transform failed\n");
@@ -4146,17 +4121,35 @@ static int caam_cra_init(struct crypto_tfm *tfm)
}
/* copy descriptor header template value */
- ctx->class1_alg_type = OP_TYPE_CLASS1_ALG | caam_alg->class1_alg_type;
- ctx->class2_alg_type = OP_TYPE_CLASS2_ALG | caam_alg->class2_alg_type;
- ctx->alg_op = OP_TYPE_CLASS2_ALG | caam_alg->alg_op;
+ ctx->class1_alg_type = OP_TYPE_CLASS1_ALG | caam->class1_alg_type;
+ ctx->class2_alg_type = OP_TYPE_CLASS2_ALG | caam->class2_alg_type;
+ ctx->alg_op = OP_TYPE_CLASS2_ALG | caam->alg_op;
return 0;
}
-static void caam_cra_exit(struct crypto_tfm *tfm)
+static int caam_cra_init(struct crypto_tfm *tfm)
{
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct caam_crypto_alg *caam_alg =
+ container_of(alg, struct caam_crypto_alg, crypto_alg);
struct caam_ctx *ctx = crypto_tfm_ctx(tfm);
+ return caam_init_common(ctx, &caam_alg->caam);
+}
+
+static int caam_aead_init(struct crypto_aead *tfm)
+{
+ struct aead_alg *alg = crypto_aead_alg(tfm);
+ struct caam_aead_alg *caam_alg =
+ container_of(alg, struct caam_aead_alg, aead);
+ struct caam_ctx *ctx = crypto_aead_ctx(tfm);
+
+ return caam_init_common(ctx, &caam_alg->caam);
+}
+
+static void caam_exit_common(struct caam_ctx *ctx)
+{
if (ctx->sh_desc_enc_dma &&
!dma_mapping_error(ctx->jrdev, ctx->sh_desc_enc_dma))
dma_unmap_single(ctx->jrdev, ctx->sh_desc_enc_dma,
@@ -4179,10 +4172,28 @@ static void caam_cra_exit(struct crypto_tfm *tfm)
caam_jr_free(ctx->jrdev);
}
+static void caam_cra_exit(struct crypto_tfm *tfm)
+{
+ caam_exit_common(crypto_tfm_ctx(tfm));
+}
+
+static void caam_aead_exit(struct crypto_aead *tfm)
+{
+ caam_exit_common(crypto_aead_ctx(tfm));
+}
+
static void __exit caam_algapi_exit(void)
{
struct caam_crypto_alg *t_alg, *n;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) {
+ struct caam_aead_alg *t_alg = driver_aeads + i;
+
+ if (t_alg->registered)
+ crypto_unregister_aead(&t_alg->aead);
+ }
if (!alg_list.next)
return;
@@ -4235,13 +4246,26 @@ static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template
break;
}
- t_alg->class1_alg_type = template->class1_alg_type;
- t_alg->class2_alg_type = template->class2_alg_type;
- t_alg->alg_op = template->alg_op;
+ t_alg->caam.class1_alg_type = template->class1_alg_type;
+ t_alg->caam.class2_alg_type = template->class2_alg_type;
+ t_alg->caam.alg_op = template->alg_op;
return t_alg;
}
+static void caam_aead_alg_init(struct caam_aead_alg *t_alg)
+{
+ struct aead_alg *alg = &t_alg->aead;
+
+ alg->base.cra_module = THIS_MODULE;
+ alg->base.cra_priority = CAAM_CRA_PRIORITY;
+ alg->base.cra_ctxsize = sizeof(struct caam_ctx);
+ alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY;
+
+ alg->init = caam_aead_init;
+ alg->exit = caam_aead_exit;
+}
+
static int __init caam_algapi_init(void)
{
struct device_node *dev_node;
@@ -4249,6 +4273,7 @@ static int __init caam_algapi_init(void)
struct device *ctrldev;
void *priv;
int i = 0, err = 0;
+ bool registered = false;
dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
if (!dev_node) {
@@ -4295,10 +4320,30 @@ static int __init caam_algapi_init(void)
pr_warn("%s alg registration failed\n",
t_alg->crypto_alg.cra_driver_name);
kfree(t_alg);
- } else
- list_add_tail(&t_alg->entry, &alg_list);
+ continue;
+ }
+
+ list_add_tail(&t_alg->entry, &alg_list);
+ registered = true;
}
- if (!list_empty(&alg_list))
+
+ for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) {
+ struct caam_aead_alg *t_alg = driver_aeads + i;
+
+ caam_aead_alg_init(t_alg);
+
+ err = crypto_register_aead(&t_alg->aead);
+ if (err) {
+ pr_warn("%s alg registration failed\n",
+ t_alg->aead.base.cra_driver_name);
+ continue;
+ }
+
+ t_alg->registered = true;
+ registered = true;
+ }
+
+ if (registered)
pr_info("caam algorithms registered in /proc/crypto\n");
return err;
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index ba0532efd3ae..dae1e8099969 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -835,17 +835,17 @@ static int ahash_update_ctx(struct ahash_request *req)
src_map_to_sec4_sg(jrdev, req->src, src_nents,
edesc->sec4_sg + sec4_sg_src_index,
chained);
- if (*next_buflen) {
+ if (*next_buflen)
scatterwalk_map_and_copy(next_buf, req->src,
to_hash - *buflen,
*next_buflen, 0);
- state->current_buf = !state->current_buf;
- }
} else {
(edesc->sec4_sg + sec4_sg_src_index - 1)->len |=
SEC4_SG_LEN_FIN;
}
+ state->current_buf = !state->current_buf;
+
sh_len = desc_len(sh_desc);
desc = edesc->hw_desc;
init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER |
@@ -1268,9 +1268,10 @@ static int ahash_update_no_ctx(struct ahash_request *req)
scatterwalk_map_and_copy(next_buf, req->src,
to_hash - *buflen,
*next_buflen, 0);
- state->current_buf = !state->current_buf;
}
+ state->current_buf = !state->current_buf;
+
sh_len = desc_len(sh_desc);
desc = edesc->hw_desc;
init_job_desc_shared(desc, ptr, sh_len, HDR_SHARE_DEFER |
@@ -1544,6 +1545,8 @@ static int ahash_init(struct ahash_request *req)
state->current_buf = 0;
state->buf_dma = 0;
+ state->buflen_0 = 0;
+ state->buflen_1 = 0;
return 0;
}
diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c
index 26a544b505f1..5095337205b8 100644
--- a/drivers/crypto/caam/caamrng.c
+++ b/drivers/crypto/caam/caamrng.c
@@ -56,7 +56,7 @@
/* Buffer, its dma address and lock */
struct buf_data {
- u8 buf[RN_BUF_SIZE];
+ u8 buf[RN_BUF_SIZE] ____cacheline_aligned;
dma_addr_t addr;
struct completion filled;
u32 hw_desc[DESC_JOB_O_LEN];
diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h
index acd7743e2603..f57f395db33f 100644
--- a/drivers/crypto/caam/compat.h
+++ b/drivers/crypto/caam/compat.h
@@ -32,7 +32,7 @@
#include <crypto/des.h>
#include <crypto/sha.h>
#include <crypto/md5.h>
-#include <crypto/aead.h>
+#include <crypto/internal/aead.h>
#include <crypto/authenc.h>
#include <crypto/scatterwalk.h>
#include <crypto/internal/skcipher.h>
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index efba4ccd4fac..efacab7539ef 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -301,7 +301,7 @@ static int caam_remove(struct platform_device *pdev)
#endif
/* Unmap controller region */
- iounmap(&ctrl);
+ iounmap(ctrl);
return ret;
}
@@ -496,7 +496,7 @@ static int caam_probe(struct platform_device *pdev)
sizeof(struct platform_device *) * rspec,
GFP_KERNEL);
if (ctrlpriv->jrpdev == NULL) {
- iounmap(&ctrl);
+ iounmap(ctrl);
return -ENOMEM;
}
diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
index 378ddc17f60e..672c97489505 100644
--- a/drivers/crypto/caam/regs.h
+++ b/drivers/crypto/caam/regs.h
@@ -83,35 +83,35 @@
#endif
#endif
+/*
+ * The only users of these wr/rd_reg64 functions is the Job Ring (JR).
+ * The DMA address registers in the JR are a pair of 32-bit registers.
+ * The layout is:
+ *
+ * base + 0x0000 : most-significant 32 bits
+ * base + 0x0004 : least-significant 32 bits
+ *
+ * The 32-bit version of this core therefore has to write to base + 0x0004
+ * to set the 32-bit wide DMA address. This seems to be independent of the
+ * endianness of the written/read data.
+ */
+
#ifndef CONFIG_64BIT
-#ifdef __BIG_ENDIAN
-static inline void wr_reg64(u64 __iomem *reg, u64 data)
-{
- wr_reg32((u32 __iomem *)reg, (data & 0xffffffff00000000ull) >> 32);
- wr_reg32((u32 __iomem *)reg + 1, data & 0x00000000ffffffffull);
-}
+#define REG64_MS32(reg) ((u32 __iomem *)(reg))
+#define REG64_LS32(reg) ((u32 __iomem *)(reg) + 1)
-static inline u64 rd_reg64(u64 __iomem *reg)
-{
- return (((u64)rd_reg32((u32 __iomem *)reg)) << 32) |
- ((u64)rd_reg32((u32 __iomem *)reg + 1));
-}
-#else
-#ifdef __LITTLE_ENDIAN
static inline void wr_reg64(u64 __iomem *reg, u64 data)
{
- wr_reg32((u32 __iomem *)reg + 1, (data & 0xffffffff00000000ull) >> 32);
- wr_reg32((u32 __iomem *)reg, data & 0x00000000ffffffffull);
+ wr_reg32(REG64_MS32(reg), data >> 32);
+ wr_reg32(REG64_LS32(reg), data);
}
static inline u64 rd_reg64(u64 __iomem *reg)
{
- return (((u64)rd_reg32((u32 __iomem *)reg + 1)) << 32) |
- ((u64)rd_reg32((u32 __iomem *)reg));
+ return ((u64)rd_reg32(REG64_MS32(reg)) << 32 |
+ (u64)rd_reg32(REG64_LS32(reg)));
}
#endif
-#endif
-#endif
/*
* jr_outentry
diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h
index 3b918218aa4c..b68b74cc7b77 100644
--- a/drivers/crypto/caam/sg_sw_sec4.h
+++ b/drivers/crypto/caam/sg_sw_sec4.h
@@ -55,6 +55,21 @@ static inline void sg_to_sec4_sg_last(struct scatterlist *sg, int sg_count,
sec4_sg_ptr->len |= SEC4_SG_LEN_FIN;
}
+static inline struct sec4_sg_entry *sg_to_sec4_sg_len(
+ struct scatterlist *sg, unsigned int total,
+ struct sec4_sg_entry *sec4_sg_ptr)
+{
+ do {
+ unsigned int len = min(sg_dma_len(sg), total);
+
+ dma_to_sec4_sg_one(sec4_sg_ptr, sg_dma_address(sg), len, 0);
+ sec4_sg_ptr++;
+ sg = sg_next(sg);
+ total -= len;
+ } while (total);
+ return sec4_sg_ptr - 1;
+}
+
/* count number of elements in scatterlist */
static inline int __sg_count(struct scatterlist *sg_list, int nbytes,
bool *chained)
@@ -85,34 +100,41 @@ static inline int sg_count(struct scatterlist *sg_list, int nbytes,
return sg_nents;
}
-static int dma_map_sg_chained(struct device *dev, struct scatterlist *sg,
- unsigned int nents, enum dma_data_direction dir,
- bool chained)
+static inline void dma_unmap_sg_chained(
+ struct device *dev, struct scatterlist *sg, unsigned int nents,
+ enum dma_data_direction dir, bool chained)
{
if (unlikely(chained)) {
int i;
for (i = 0; i < nents; i++) {
- dma_map_sg(dev, sg, 1, dir);
+ dma_unmap_sg(dev, sg, 1, dir);
sg = sg_next(sg);
}
- } else {
- dma_map_sg(dev, sg, nents, dir);
+ } else if (nents) {
+ dma_unmap_sg(dev, sg, nents, dir);
}
- return nents;
}
-static int dma_unmap_sg_chained(struct device *dev, struct scatterlist *sg,
- unsigned int nents, enum dma_data_direction dir,
- bool chained)
+static inline int dma_map_sg_chained(
+ struct device *dev, struct scatterlist *sg, unsigned int nents,
+ enum dma_data_direction dir, bool chained)
{
+ struct scatterlist *first = sg;
+
if (unlikely(chained)) {
int i;
for (i = 0; i < nents; i++) {
- dma_unmap_sg(dev, sg, 1, dir);
+ if (!dma_map_sg(dev, sg, 1, dir)) {
+ dma_unmap_sg_chained(dev, first, i, dir,
+ chained);
+ nents = 0;
+ break;
+ }
+
sg = sg_next(sg);
}
- } else {
- dma_unmap_sg(dev, sg, nents, dir);
- }
+ } else
+ nents = dma_map_sg(dev, sg, nents, dir);
+
return nents;
}
diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig
index 7639ffc36c68..ae38f6b6cc10 100644
--- a/drivers/crypto/ccp/Kconfig
+++ b/drivers/crypto/ccp/Kconfig
@@ -13,7 +13,6 @@ config CRYPTO_DEV_CCP_CRYPTO
tristate "Encryption and hashing acceleration support"
depends on CRYPTO_DEV_CCP_DD
default m
- select CRYPTO_ALGAPI
select CRYPTO_HASH
select CRYPTO_BLKCIPHER
select CRYPTO_AUTHENC
diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c
index 71f2e3c89424..d09c6c4af4aa 100644
--- a/drivers/crypto/ccp/ccp-ops.c
+++ b/drivers/crypto/ccp/ccp-ops.c
@@ -52,8 +52,7 @@ struct ccp_dm_workarea {
struct ccp_sg_workarea {
struct scatterlist *sg;
- unsigned int nents;
- unsigned int length;
+ int nents;
struct scatterlist *dma_sg;
struct device *dma_dev;
@@ -496,8 +495,10 @@ static int ccp_init_sg_workarea(struct ccp_sg_workarea *wa, struct device *dev,
if (!sg)
return 0;
- wa->nents = sg_nents(sg);
- wa->length = sg->length;
+ wa->nents = sg_nents_for_len(sg, len);
+ if (wa->nents < 0)
+ return wa->nents;
+
wa->bytes_left = len;
wa->sg_used = 0;
diff --git a/drivers/crypto/ccp/ccp-platform.c b/drivers/crypto/ccp/ccp-platform.c
index b1c20b2b5647..f2e6de361fd1 100644
--- a/drivers/crypto/ccp/ccp-platform.c
+++ b/drivers/crypto/ccp/ccp-platform.c
@@ -90,58 +90,6 @@ static struct resource *ccp_find_mmio_area(struct ccp_device *ccp)
return NULL;
}
-#ifdef CONFIG_ACPI
-static int ccp_acpi_support(struct ccp_device *ccp)
-{
- struct ccp_platform *ccp_platform = ccp->dev_specific;
- struct acpi_device *adev = ACPI_COMPANION(ccp->dev);
- acpi_handle handle;
- acpi_status status;
- unsigned long long data;
- int cca;
-
- /* Retrieve the device cache coherency value */
- handle = adev->handle;
- do {
- status = acpi_evaluate_integer(handle, "_CCA", NULL, &data);
- if (!ACPI_FAILURE(status)) {
- cca = data;
- break;
- }
- } while (!ACPI_FAILURE(status));
-
- if (ACPI_FAILURE(status)) {
- dev_err(ccp->dev, "error obtaining acpi coherency value\n");
- return -EINVAL;
- }
-
- ccp_platform->coherent = !!cca;
-
- return 0;
-}
-#else /* CONFIG_ACPI */
-static int ccp_acpi_support(struct ccp_device *ccp)
-{
- return -EINVAL;
-}
-#endif
-
-#ifdef CONFIG_OF
-static int ccp_of_support(struct ccp_device *ccp)
-{
- struct ccp_platform *ccp_platform = ccp->dev_specific;
-
- ccp_platform->coherent = of_dma_is_coherent(ccp->dev->of_node);
-
- return 0;
-}
-#else
-static int ccp_of_support(struct ccp_device *ccp)
-{
- return -EINVAL;
-}
-#endif
-
static int ccp_platform_probe(struct platform_device *pdev)
{
struct ccp_device *ccp;
@@ -174,21 +122,13 @@ static int ccp_platform_probe(struct platform_device *pdev)
}
ccp->io_regs = ccp->io_map;
- if (!dev->dma_mask)
- dev->dma_mask = &dev->coherent_dma_mask;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
if (ret) {
dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret);
goto e_err;
}
- if (ccp_platform->use_acpi)
- ret = ccp_acpi_support(ccp);
- else
- ret = ccp_of_support(ccp);
- if (ret)
- goto e_err;
-
+ ccp_platform->coherent = device_dma_is_coherent(ccp->dev);
if (ccp_platform->coherent)
ccp->axcache = CACHE_WB_NO_ALLOC;
else
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index 48f453555f1f..7ba495f75370 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -25,7 +25,7 @@
#include <crypto/aes.h>
#include <crypto/sha.h>
#include <crypto/algapi.h>
-#include <crypto/aead.h>
+#include <crypto/internal/aead.h>
#include <crypto/authenc.h>
#include <crypto/scatterwalk.h>
@@ -575,7 +575,8 @@ static int init_tfm_ablk(struct crypto_tfm *tfm)
static int init_tfm_aead(struct crypto_tfm *tfm)
{
- tfm->crt_aead.reqsize = sizeof(struct aead_ctx);
+ crypto_aead_set_reqsize(__crypto_aead_cast(tfm),
+ sizeof(struct aead_ctx));
return init_tfm(tfm);
}
@@ -1096,7 +1097,7 @@ static int aead_setup(struct crypto_aead *tfm, unsigned int authsize)
{
struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
u32 *flags = &tfm->base.crt_flags;
- unsigned digest_len = crypto_aead_alg(tfm)->maxauthsize;
+ unsigned digest_len = crypto_aead_maxauthsize(tfm);
int ret;
if (!ctx->enckey_len && !ctx->authkey_len)
@@ -1138,7 +1139,7 @@ out:
static int aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
{
- int max = crypto_aead_alg(tfm)->maxauthsize >> 2;
+ int max = crypto_aead_maxauthsize(tfm) >> 2;
if ((authsize>>2) < 1 || (authsize>>2) > max || (authsize & 3))
return -EINVAL;
diff --git a/drivers/crypto/marvell/Makefile b/drivers/crypto/marvell/Makefile
new file mode 100644
index 000000000000..0c12b13574dc
--- /dev/null
+++ b/drivers/crypto/marvell/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CRYPTO_DEV_MARVELL_CESA) += marvell-cesa.o
+marvell-cesa-objs := cesa.o cipher.o hash.o tdma.o
diff --git a/drivers/crypto/marvell/cesa.c b/drivers/crypto/marvell/cesa.c
new file mode 100644
index 000000000000..a432633bced4
--- /dev/null
+++ b/drivers/crypto/marvell/cesa.c
@@ -0,0 +1,548 @@
+/*
+ * Support for Marvell's Cryptographic Engine and Security Accelerator (CESA)
+ * that can be found on the following platform: Orion, Kirkwood, Armada. This
+ * driver supports the TDMA engine on platforms on which it is available.
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ * Author: Arnaud Ebalard <arno@natisbad.org>
+ *
+ * This work is based on an initial version written by
+ * Sebastian Andrzej Siewior < sebastian at breakpoint dot cc >
+ *
+ * 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/genalloc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kthread.h>
+#include <linux/mbus.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+
+#include "cesa.h"
+
+static int allhwsupport = !IS_ENABLED(CONFIG_CRYPTO_DEV_MV_CESA);
+module_param_named(allhwsupport, allhwsupport, int, 0444);
+MODULE_PARM_DESC(allhwsupport, "Enable support for all hardware (even it if overlaps with the mv_cesa driver)");
+
+struct mv_cesa_dev *cesa_dev;
+
+static void mv_cesa_dequeue_req_unlocked(struct mv_cesa_engine *engine)
+{
+ struct crypto_async_request *req, *backlog;
+ struct mv_cesa_ctx *ctx;
+
+ spin_lock_bh(&cesa_dev->lock);
+ backlog = crypto_get_backlog(&cesa_dev->queue);
+ req = crypto_dequeue_request(&cesa_dev->queue);
+ engine->req = req;
+ spin_unlock_bh(&cesa_dev->lock);
+
+ if (!req)
+ return;
+
+ if (backlog)
+ backlog->complete(backlog, -EINPROGRESS);
+
+ ctx = crypto_tfm_ctx(req->tfm);
+ ctx->ops->prepare(req, engine);
+ ctx->ops->step(req);
+}
+
+static irqreturn_t mv_cesa_int(int irq, void *priv)
+{
+ struct mv_cesa_engine *engine = priv;
+ struct crypto_async_request *req;
+ struct mv_cesa_ctx *ctx;
+ u32 status, mask;
+ irqreturn_t ret = IRQ_NONE;
+
+ while (true) {
+ int res;
+
+ mask = mv_cesa_get_int_mask(engine);
+ status = readl(engine->regs + CESA_SA_INT_STATUS);
+
+ if (!(status & mask))
+ break;
+
+ /*
+ * TODO: avoid clearing the FPGA_INT_STATUS if this not
+ * relevant on some platforms.
+ */
+ writel(~status, engine->regs + CESA_SA_FPGA_INT_STATUS);
+ writel(~status, engine->regs + CESA_SA_INT_STATUS);
+
+ ret = IRQ_HANDLED;
+ spin_lock_bh(&engine->lock);
+ req = engine->req;
+ spin_unlock_bh(&engine->lock);
+ if (req) {
+ ctx = crypto_tfm_ctx(req->tfm);
+ res = ctx->ops->process(req, status & mask);
+ if (res != -EINPROGRESS) {
+ spin_lock_bh(&engine->lock);
+ engine->req = NULL;
+ mv_cesa_dequeue_req_unlocked(engine);
+ spin_unlock_bh(&engine->lock);
+ ctx->ops->cleanup(req);
+ local_bh_disable();
+ req->complete(req, res);
+ local_bh_enable();
+ } else {
+ ctx->ops->step(req);
+ }
+ }
+ }
+
+ return ret;
+}
+
+int mv_cesa_queue_req(struct crypto_async_request *req)
+{
+ int ret;
+ int i;
+
+ spin_lock_bh(&cesa_dev->lock);
+ ret = crypto_enqueue_request(&cesa_dev->queue, req);
+ spin_unlock_bh(&cesa_dev->lock);
+
+ if (ret != -EINPROGRESS)
+ return ret;
+
+ for (i = 0; i < cesa_dev->caps->nengines; i++) {
+ spin_lock_bh(&cesa_dev->engines[i].lock);
+ if (!cesa_dev->engines[i].req)
+ mv_cesa_dequeue_req_unlocked(&cesa_dev->engines[i]);
+ spin_unlock_bh(&cesa_dev->engines[i].lock);
+ }
+
+ return -EINPROGRESS;
+}
+
+static int mv_cesa_add_algs(struct mv_cesa_dev *cesa)
+{
+ int ret;
+ int i, j;
+
+ for (i = 0; i < cesa->caps->ncipher_algs; i++) {
+ ret = crypto_register_alg(cesa->caps->cipher_algs[i]);
+ if (ret)
+ goto err_unregister_crypto;
+ }
+
+ for (i = 0; i < cesa->caps->nahash_algs; i++) {
+ ret = crypto_register_ahash(cesa->caps->ahash_algs[i]);
+ if (ret)
+ goto err_unregister_ahash;
+ }
+
+ return 0;
+
+err_unregister_ahash:
+ for (j = 0; j < i; j++)
+ crypto_unregister_ahash(cesa->caps->ahash_algs[j]);
+ i = cesa->caps->ncipher_algs;
+
+err_unregister_crypto:
+ for (j = 0; j < i; j++)
+ crypto_unregister_alg(cesa->caps->cipher_algs[j]);
+
+ return ret;
+}
+
+static void mv_cesa_remove_algs(struct mv_cesa_dev *cesa)
+{
+ int i;
+
+ for (i = 0; i < cesa->caps->nahash_algs; i++)
+ crypto_unregister_ahash(cesa->caps->ahash_algs[i]);
+
+ for (i = 0; i < cesa->caps->ncipher_algs; i++)
+ crypto_unregister_alg(cesa->caps->cipher_algs[i]);
+}
+
+static struct crypto_alg *orion_cipher_algs[] = {
+ &mv_cesa_ecb_des_alg,
+ &mv_cesa_cbc_des_alg,
+ &mv_cesa_ecb_des3_ede_alg,
+ &mv_cesa_cbc_des3_ede_alg,
+ &mv_cesa_ecb_aes_alg,
+ &mv_cesa_cbc_aes_alg,
+};
+
+static struct ahash_alg *orion_ahash_algs[] = {
+ &mv_md5_alg,
+ &mv_sha1_alg,
+ &mv_ahmac_md5_alg,
+ &mv_ahmac_sha1_alg,
+};
+
+static struct crypto_alg *armada_370_cipher_algs[] = {
+ &mv_cesa_ecb_des_alg,
+ &mv_cesa_cbc_des_alg,
+ &mv_cesa_ecb_des3_ede_alg,
+ &mv_cesa_cbc_des3_ede_alg,
+ &mv_cesa_ecb_aes_alg,
+ &mv_cesa_cbc_aes_alg,
+};
+
+static struct ahash_alg *armada_370_ahash_algs[] = {
+ &mv_md5_alg,
+ &mv_sha1_alg,
+ &mv_sha256_alg,
+ &mv_ahmac_md5_alg,
+ &mv_ahmac_sha1_alg,
+ &mv_ahmac_sha256_alg,
+};
+
+static const struct mv_cesa_caps orion_caps = {
+ .nengines = 1,
+ .cipher_algs = orion_cipher_algs,
+ .ncipher_algs = ARRAY_SIZE(orion_cipher_algs),
+ .ahash_algs = orion_ahash_algs,
+ .nahash_algs = ARRAY_SIZE(orion_ahash_algs),
+ .has_tdma = false,
+};
+
+static const struct mv_cesa_caps kirkwood_caps = {
+ .nengines = 1,
+ .cipher_algs = orion_cipher_algs,
+ .ncipher_algs = ARRAY_SIZE(orion_cipher_algs),
+ .ahash_algs = orion_ahash_algs,
+ .nahash_algs = ARRAY_SIZE(orion_ahash_algs),
+ .has_tdma = true,
+};
+
+static const struct mv_cesa_caps armada_370_caps = {
+ .nengines = 1,
+ .cipher_algs = armada_370_cipher_algs,
+ .ncipher_algs = ARRAY_SIZE(armada_370_cipher_algs),
+ .ahash_algs = armada_370_ahash_algs,
+ .nahash_algs = ARRAY_SIZE(armada_370_ahash_algs),
+ .has_tdma = true,
+};
+
+static const struct mv_cesa_caps armada_xp_caps = {
+ .nengines = 2,
+ .cipher_algs = armada_370_cipher_algs,
+ .ncipher_algs = ARRAY_SIZE(armada_370_cipher_algs),
+ .ahash_algs = armada_370_ahash_algs,
+ .nahash_algs = ARRAY_SIZE(armada_370_ahash_algs),
+ .has_tdma = true,
+};
+
+static const struct of_device_id mv_cesa_of_match_table[] = {
+ { .compatible = "marvell,orion-crypto", .data = &orion_caps },
+ { .compatible = "marvell,kirkwood-crypto", .data = &kirkwood_caps },
+ { .compatible = "marvell,dove-crypto", .data = &kirkwood_caps },
+ { .compatible = "marvell,armada-370-crypto", .data = &armada_370_caps },
+ { .compatible = "marvell,armada-xp-crypto", .data = &armada_xp_caps },
+ { .compatible = "marvell,armada-375-crypto", .data = &armada_xp_caps },
+ { .compatible = "marvell,armada-38x-crypto", .data = &armada_xp_caps },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mv_cesa_of_match_table);
+
+static void
+mv_cesa_conf_mbus_windows(struct mv_cesa_engine *engine,
+ const struct mbus_dram_target_info *dram)
+{
+ void __iomem *iobase = engine->regs;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ writel(0, iobase + CESA_TDMA_WINDOW_CTRL(i));
+ writel(0, iobase + CESA_TDMA_WINDOW_BASE(i));
+ }
+
+ for (i = 0; i < dram->num_cs; i++) {
+ const struct mbus_dram_window *cs = dram->cs + i;
+
+ writel(((cs->size - 1) & 0xffff0000) |
+ (cs->mbus_attr << 8) |
+ (dram->mbus_dram_target_id << 4) | 1,
+ iobase + CESA_TDMA_WINDOW_CTRL(i));
+ writel(cs->base, iobase + CESA_TDMA_WINDOW_BASE(i));
+ }
+}
+
+static int mv_cesa_dev_dma_init(struct mv_cesa_dev *cesa)
+{
+ struct device *dev = cesa->dev;
+ struct mv_cesa_dev_dma *dma;
+
+ if (!cesa->caps->has_tdma)
+ return 0;
+
+ dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ return -ENOMEM;
+
+ dma->tdma_desc_pool = dmam_pool_create("tdma_desc", dev,
+ sizeof(struct mv_cesa_tdma_desc),
+ 16, 0);
+ if (!dma->tdma_desc_pool)
+ return -ENOMEM;
+
+ dma->op_pool = dmam_pool_create("cesa_op", dev,
+ sizeof(struct mv_cesa_op_ctx), 16, 0);
+ if (!dma->op_pool)
+ return -ENOMEM;
+
+ dma->cache_pool = dmam_pool_create("cesa_cache", dev,
+ CESA_MAX_HASH_BLOCK_SIZE, 1, 0);
+ if (!dma->cache_pool)
+ return -ENOMEM;
+
+ dma->padding_pool = dmam_pool_create("cesa_padding", dev, 72, 1, 0);
+ if (!dma->cache_pool)
+ return -ENOMEM;
+
+ cesa->dma = dma;
+
+ return 0;
+}
+
+static int mv_cesa_get_sram(struct platform_device *pdev, int idx)
+{
+ struct mv_cesa_dev *cesa = platform_get_drvdata(pdev);
+ struct mv_cesa_engine *engine = &cesa->engines[idx];
+ const char *res_name = "sram";
+ struct resource *res;
+
+ engine->pool = of_get_named_gen_pool(cesa->dev->of_node,
+ "marvell,crypto-srams",
+ idx);
+ if (engine->pool) {
+ engine->sram = gen_pool_dma_alloc(engine->pool,
+ cesa->sram_size,
+ &engine->sram_dma);
+ if (engine->sram)
+ return 0;
+
+ engine->pool = NULL;
+ return -ENOMEM;
+ }
+
+ if (cesa->caps->nengines > 1) {
+ if (!idx)
+ res_name = "sram0";
+ else
+ res_name = "sram1";
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ res_name);
+ if (!res || resource_size(res) < cesa->sram_size)
+ return -EINVAL;
+
+ engine->sram = devm_ioremap_resource(cesa->dev, res);
+ if (IS_ERR(engine->sram))
+ return PTR_ERR(engine->sram);
+
+ engine->sram_dma = phys_to_dma(cesa->dev,
+ (phys_addr_t)res->start);
+
+ return 0;
+}
+
+static void mv_cesa_put_sram(struct platform_device *pdev, int idx)
+{
+ struct mv_cesa_dev *cesa = platform_get_drvdata(pdev);
+ struct mv_cesa_engine *engine = &cesa->engines[idx];
+
+ if (!engine->pool)
+ return;
+
+ gen_pool_free(engine->pool, (unsigned long)engine->sram,
+ cesa->sram_size);
+}
+
+static int mv_cesa_probe(struct platform_device *pdev)
+{
+ const struct mv_cesa_caps *caps = &orion_caps;
+ const struct mbus_dram_target_info *dram;
+ const struct of_device_id *match;
+ struct device *dev = &pdev->dev;
+ struct mv_cesa_dev *cesa;
+ struct mv_cesa_engine *engines;
+ struct resource *res;
+ int irq, ret, i;
+ u32 sram_size;
+
+ if (cesa_dev) {
+ dev_err(&pdev->dev, "Only one CESA device authorized\n");
+ return -EEXIST;
+ }
+
+ if (dev->of_node) {
+ match = of_match_node(mv_cesa_of_match_table, dev->of_node);
+ if (!match || !match->data)
+ return -ENOTSUPP;
+
+ caps = match->data;
+ }
+
+ if ((caps == &orion_caps || caps == &kirkwood_caps) && !allhwsupport)
+ return -ENOTSUPP;
+
+ cesa = devm_kzalloc(dev, sizeof(*cesa), GFP_KERNEL);
+ if (!cesa)
+ return -ENOMEM;
+
+ cesa->caps = caps;
+ cesa->dev = dev;
+
+ sram_size = CESA_SA_DEFAULT_SRAM_SIZE;
+ of_property_read_u32(cesa->dev->of_node, "marvell,crypto-sram-size",
+ &sram_size);
+ if (sram_size < CESA_SA_MIN_SRAM_SIZE)
+ sram_size = CESA_SA_MIN_SRAM_SIZE;
+
+ cesa->sram_size = sram_size;
+ cesa->engines = devm_kzalloc(dev, caps->nengines * sizeof(*engines),
+ GFP_KERNEL);
+ if (!cesa->engines)
+ return -ENOMEM;
+
+ spin_lock_init(&cesa->lock);
+ crypto_init_queue(&cesa->queue, 50);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+ cesa->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(cesa->regs))
+ return -ENOMEM;
+
+ ret = mv_cesa_dev_dma_init(cesa);
+ if (ret)
+ return ret;
+
+ dram = mv_mbus_dram_info_nooverlap();
+
+ platform_set_drvdata(pdev, cesa);
+
+ for (i = 0; i < caps->nengines; i++) {
+ struct mv_cesa_engine *engine = &cesa->engines[i];
+ char res_name[7];
+
+ engine->id = i;
+ spin_lock_init(&engine->lock);
+
+ ret = mv_cesa_get_sram(pdev, i);
+ if (ret)
+ goto err_cleanup;
+
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0) {
+ ret = irq;
+ goto err_cleanup;
+ }
+
+ /*
+ * Not all platforms can gate the CESA clocks: do not complain
+ * if the clock does not exist.
+ */
+ snprintf(res_name, sizeof(res_name), "cesa%d", i);
+ engine->clk = devm_clk_get(dev, res_name);
+ if (IS_ERR(engine->clk)) {
+ engine->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(engine->clk))
+ engine->clk = NULL;
+ }
+
+ snprintf(res_name, sizeof(res_name), "cesaz%d", i);
+ engine->zclk = devm_clk_get(dev, res_name);
+ if (IS_ERR(engine->zclk))
+ engine->zclk = NULL;
+
+ ret = clk_prepare_enable(engine->clk);
+ if (ret)
+ goto err_cleanup;
+
+ ret = clk_prepare_enable(engine->zclk);
+ if (ret)
+ goto err_cleanup;
+
+ engine->regs = cesa->regs + CESA_ENGINE_OFF(i);
+
+ if (dram && cesa->caps->has_tdma)
+ mv_cesa_conf_mbus_windows(&cesa->engines[i], dram);
+
+ writel(0, cesa->engines[i].regs + CESA_SA_INT_STATUS);
+ writel(CESA_SA_CFG_STOP_DIG_ERR,
+ cesa->engines[i].regs + CESA_SA_CFG);
+ writel(engine->sram_dma & CESA_SA_SRAM_MSK,
+ cesa->engines[i].regs + CESA_SA_DESC_P0);
+
+ ret = devm_request_threaded_irq(dev, irq, NULL, mv_cesa_int,
+ IRQF_ONESHOT,
+ dev_name(&pdev->dev),
+ &cesa->engines[i]);
+ if (ret)
+ goto err_cleanup;
+ }
+
+ cesa_dev = cesa;
+
+ ret = mv_cesa_add_algs(cesa);
+ if (ret) {
+ cesa_dev = NULL;
+ goto err_cleanup;
+ }
+
+ dev_info(dev, "CESA device successfully registered\n");
+
+ return 0;
+
+err_cleanup:
+ for (i = 0; i < caps->nengines; i++) {
+ clk_disable_unprepare(cesa->engines[i].zclk);
+ clk_disable_unprepare(cesa->engines[i].clk);
+ mv_cesa_put_sram(pdev, i);
+ }
+
+ return ret;
+}
+
+static int mv_cesa_remove(struct platform_device *pdev)
+{
+ struct mv_cesa_dev *cesa = platform_get_drvdata(pdev);
+ int i;
+
+ mv_cesa_remove_algs(cesa);
+
+ for (i = 0; i < cesa->caps->nengines; i++) {
+ clk_disable_unprepare(cesa->engines[i].zclk);
+ clk_disable_unprepare(cesa->engines[i].clk);
+ mv_cesa_put_sram(pdev, i);
+ }
+
+ return 0;
+}
+
+static struct platform_driver marvell_cesa = {
+ .probe = mv_cesa_probe,
+ .remove = mv_cesa_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "marvell-cesa",
+ .of_match_table = mv_cesa_of_match_table,
+ },
+};
+module_platform_driver(marvell_cesa);
+
+MODULE_ALIAS("platform:mv_crypto");
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_AUTHOR("Arnaud Ebalard <arno@natisbad.org>");
+MODULE_DESCRIPTION("Support for Marvell's cryptographic engine");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/crypto/marvell/cesa.h b/drivers/crypto/marvell/cesa.h
new file mode 100644
index 000000000000..b60698b30d30
--- /dev/null
+++ b/drivers/crypto/marvell/cesa.h
@@ -0,0 +1,791 @@
+#ifndef __MARVELL_CESA_H__
+#define __MARVELL_CESA_H__
+
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+#include <crypto/internal/hash.h>
+
+#include <linux/crypto.h>
+#include <linux/dmapool.h>
+
+#define CESA_ENGINE_OFF(i) (((i) * 0x2000))
+
+#define CESA_TDMA_BYTE_CNT 0x800
+#define CESA_TDMA_SRC_ADDR 0x810
+#define CESA_TDMA_DST_ADDR 0x820
+#define CESA_TDMA_NEXT_ADDR 0x830
+
+#define CESA_TDMA_CONTROL 0x840
+#define CESA_TDMA_DST_BURST GENMASK(2, 0)
+#define CESA_TDMA_DST_BURST_32B 3
+#define CESA_TDMA_DST_BURST_128B 4
+#define CESA_TDMA_OUT_RD_EN BIT(4)
+#define CESA_TDMA_SRC_BURST GENMASK(8, 6)
+#define CESA_TDMA_SRC_BURST_32B (3 << 6)
+#define CESA_TDMA_SRC_BURST_128B (4 << 6)
+#define CESA_TDMA_CHAIN BIT(9)
+#define CESA_TDMA_BYTE_SWAP BIT(11)
+#define CESA_TDMA_NO_BYTE_SWAP BIT(11)
+#define CESA_TDMA_EN BIT(12)
+#define CESA_TDMA_FETCH_ND BIT(13)
+#define CESA_TDMA_ACT BIT(14)
+
+#define CESA_TDMA_CUR 0x870
+#define CESA_TDMA_ERROR_CAUSE 0x8c8
+#define CESA_TDMA_ERROR_MSK 0x8cc
+
+#define CESA_TDMA_WINDOW_BASE(x) (((x) * 0x8) + 0xa00)
+#define CESA_TDMA_WINDOW_CTRL(x) (((x) * 0x8) + 0xa04)
+
+#define CESA_IVDIG(x) (0xdd00 + ((x) * 4) + \
+ (((x) < 5) ? 0 : 0x14))
+
+#define CESA_SA_CMD 0xde00
+#define CESA_SA_CMD_EN_CESA_SA_ACCL0 BIT(0)
+#define CESA_SA_CMD_EN_CESA_SA_ACCL1 BIT(1)
+#define CESA_SA_CMD_DISABLE_SEC BIT(2)
+
+#define CESA_SA_DESC_P0 0xde04
+
+#define CESA_SA_DESC_P1 0xde14
+
+#define CESA_SA_CFG 0xde08
+#define CESA_SA_CFG_STOP_DIG_ERR GENMASK(1, 0)
+#define CESA_SA_CFG_DIG_ERR_CONT 0
+#define CESA_SA_CFG_DIG_ERR_SKIP 1
+#define CESA_SA_CFG_DIG_ERR_STOP 3
+#define CESA_SA_CFG_CH0_W_IDMA BIT(7)
+#define CESA_SA_CFG_CH1_W_IDMA BIT(8)
+#define CESA_SA_CFG_ACT_CH0_IDMA BIT(9)
+#define CESA_SA_CFG_ACT_CH1_IDMA BIT(10)
+#define CESA_SA_CFG_MULTI_PKT BIT(11)
+#define CESA_SA_CFG_PARA_DIS BIT(13)
+
+#define CESA_SA_ACCEL_STATUS 0xde0c
+#define CESA_SA_ST_ACT_0 BIT(0)
+#define CESA_SA_ST_ACT_1 BIT(1)
+
+/*
+ * CESA_SA_FPGA_INT_STATUS looks like a FPGA leftover and is documented only
+ * in Errata 4.12. It looks like that it was part of an IRQ-controller in FPGA
+ * and someone forgot to remove it while switching to the core and moving to
+ * CESA_SA_INT_STATUS.
+ */
+#define CESA_SA_FPGA_INT_STATUS 0xdd68
+#define CESA_SA_INT_STATUS 0xde20
+#define CESA_SA_INT_AUTH_DONE BIT(0)
+#define CESA_SA_INT_DES_E_DONE BIT(1)
+#define CESA_SA_INT_AES_E_DONE BIT(2)
+#define CESA_SA_INT_AES_D_DONE BIT(3)
+#define CESA_SA_INT_ENC_DONE BIT(4)
+#define CESA_SA_INT_ACCEL0_DONE BIT(5)
+#define CESA_SA_INT_ACCEL1_DONE BIT(6)
+#define CESA_SA_INT_ACC0_IDMA_DONE BIT(7)
+#define CESA_SA_INT_ACC1_IDMA_DONE BIT(8)
+#define CESA_SA_INT_IDMA_DONE BIT(9)
+#define CESA_SA_INT_IDMA_OWN_ERR BIT(10)
+
+#define CESA_SA_INT_MSK 0xde24
+
+#define CESA_SA_DESC_CFG_OP_MAC_ONLY 0
+#define CESA_SA_DESC_CFG_OP_CRYPT_ONLY 1
+#define CESA_SA_DESC_CFG_OP_MAC_CRYPT 2
+#define CESA_SA_DESC_CFG_OP_CRYPT_MAC 3
+#define CESA_SA_DESC_CFG_OP_MSK GENMASK(1, 0)
+#define CESA_SA_DESC_CFG_MACM_SHA256 (1 << 4)
+#define CESA_SA_DESC_CFG_MACM_HMAC_SHA256 (3 << 4)
+#define CESA_SA_DESC_CFG_MACM_MD5 (4 << 4)
+#define CESA_SA_DESC_CFG_MACM_SHA1 (5 << 4)
+#define CESA_SA_DESC_CFG_MACM_HMAC_MD5 (6 << 4)
+#define CESA_SA_DESC_CFG_MACM_HMAC_SHA1 (7 << 4)
+#define CESA_SA_DESC_CFG_MACM_MSK GENMASK(6, 4)
+#define CESA_SA_DESC_CFG_CRYPTM_DES (1 << 8)
+#define CESA_SA_DESC_CFG_CRYPTM_3DES (2 << 8)
+#define CESA_SA_DESC_CFG_CRYPTM_AES (3 << 8)
+#define CESA_SA_DESC_CFG_CRYPTM_MSK GENMASK(9, 8)
+#define CESA_SA_DESC_CFG_DIR_ENC (0 << 12)
+#define CESA_SA_DESC_CFG_DIR_DEC (1 << 12)
+#define CESA_SA_DESC_CFG_CRYPTCM_ECB (0 << 16)
+#define CESA_SA_DESC_CFG_CRYPTCM_CBC (1 << 16)
+#define CESA_SA_DESC_CFG_CRYPTCM_MSK BIT(16)
+#define CESA_SA_DESC_CFG_3DES_EEE (0 << 20)
+#define CESA_SA_DESC_CFG_3DES_EDE (1 << 20)
+#define CESA_SA_DESC_CFG_AES_LEN_128 (0 << 24)
+#define CESA_SA_DESC_CFG_AES_LEN_192 (1 << 24)
+#define CESA_SA_DESC_CFG_AES_LEN_256 (2 << 24)
+#define CESA_SA_DESC_CFG_AES_LEN_MSK GENMASK(25, 24)
+#define CESA_SA_DESC_CFG_NOT_FRAG (0 << 30)
+#define CESA_SA_DESC_CFG_FIRST_FRAG (1 << 30)
+#define CESA_SA_DESC_CFG_LAST_FRAG (2 << 30)
+#define CESA_SA_DESC_CFG_MID_FRAG (3 << 30)
+#define CESA_SA_DESC_CFG_FRAG_MSK GENMASK(31, 30)
+
+/*
+ * /-----------\ 0
+ * | ACCEL CFG | 4 * 8
+ * |-----------| 0x20
+ * | CRYPT KEY | 8 * 4
+ * |-----------| 0x40
+ * | IV IN | 4 * 4
+ * |-----------| 0x40 (inplace)
+ * | IV BUF | 4 * 4
+ * |-----------| 0x80
+ * | DATA IN | 16 * x (max ->max_req_size)
+ * |-----------| 0x80 (inplace operation)
+ * | DATA OUT | 16 * x (max ->max_req_size)
+ * \-----------/ SRAM size
+ */
+
+/*
+ * Hashing memory map:
+ * /-----------\ 0
+ * | ACCEL CFG | 4 * 8
+ * |-----------| 0x20
+ * | Inner IV | 8 * 4
+ * |-----------| 0x40
+ * | Outer IV | 8 * 4
+ * |-----------| 0x60
+ * | Output BUF| 8 * 4
+ * |-----------| 0x80
+ * | DATA IN | 64 * x (max ->max_req_size)
+ * \-----------/ SRAM size
+ */
+
+#define CESA_SA_CFG_SRAM_OFFSET 0x00
+#define CESA_SA_DATA_SRAM_OFFSET 0x80
+
+#define CESA_SA_CRYPT_KEY_SRAM_OFFSET 0x20
+#define CESA_SA_CRYPT_IV_SRAM_OFFSET 0x40
+
+#define CESA_SA_MAC_IIV_SRAM_OFFSET 0x20
+#define CESA_SA_MAC_OIV_SRAM_OFFSET 0x40
+#define CESA_SA_MAC_DIG_SRAM_OFFSET 0x60
+
+#define CESA_SA_DESC_CRYPT_DATA(offset) \
+ cpu_to_le32((CESA_SA_DATA_SRAM_OFFSET + (offset)) | \
+ ((CESA_SA_DATA_SRAM_OFFSET + (offset)) << 16))
+
+#define CESA_SA_DESC_CRYPT_IV(offset) \
+ cpu_to_le32((CESA_SA_CRYPT_IV_SRAM_OFFSET + (offset)) | \
+ ((CESA_SA_CRYPT_IV_SRAM_OFFSET + (offset)) << 16))
+
+#define CESA_SA_DESC_CRYPT_KEY(offset) \
+ cpu_to_le32(CESA_SA_CRYPT_KEY_SRAM_OFFSET + (offset))
+
+#define CESA_SA_DESC_MAC_DATA(offset) \
+ cpu_to_le32(CESA_SA_DATA_SRAM_OFFSET + (offset))
+#define CESA_SA_DESC_MAC_DATA_MSK GENMASK(15, 0)
+
+#define CESA_SA_DESC_MAC_TOTAL_LEN(total_len) cpu_to_le32((total_len) << 16)
+#define CESA_SA_DESC_MAC_TOTAL_LEN_MSK GENMASK(31, 16)
+
+#define CESA_SA_DESC_MAC_SRC_TOTAL_LEN_MAX 0xffff
+
+#define CESA_SA_DESC_MAC_DIGEST(offset) \
+ cpu_to_le32(CESA_SA_MAC_DIG_SRAM_OFFSET + (offset))
+#define CESA_SA_DESC_MAC_DIGEST_MSK GENMASK(15, 0)
+
+#define CESA_SA_DESC_MAC_FRAG_LEN(frag_len) cpu_to_le32((frag_len) << 16)
+#define CESA_SA_DESC_MAC_FRAG_LEN_MSK GENMASK(31, 16)
+
+#define CESA_SA_DESC_MAC_IV(offset) \
+ cpu_to_le32((CESA_SA_MAC_IIV_SRAM_OFFSET + (offset)) | \
+ ((CESA_SA_MAC_OIV_SRAM_OFFSET + (offset)) << 16))
+
+#define CESA_SA_SRAM_SIZE 2048
+#define CESA_SA_SRAM_PAYLOAD_SIZE (cesa_dev->sram_size - \
+ CESA_SA_DATA_SRAM_OFFSET)
+
+#define CESA_SA_DEFAULT_SRAM_SIZE 2048
+#define CESA_SA_MIN_SRAM_SIZE 1024
+
+#define CESA_SA_SRAM_MSK (2048 - 1)
+
+#define CESA_MAX_HASH_BLOCK_SIZE 64
+#define CESA_HASH_BLOCK_SIZE_MSK (CESA_MAX_HASH_BLOCK_SIZE - 1)
+
+/**
+ * struct mv_cesa_sec_accel_desc - security accelerator descriptor
+ * @config: engine config
+ * @enc_p: input and output data pointers for a cipher operation
+ * @enc_len: cipher operation length
+ * @enc_key_p: cipher key pointer
+ * @enc_iv: cipher IV pointers
+ * @mac_src_p: input pointer and total hash length
+ * @mac_digest: digest pointer and hash operation length
+ * @mac_iv: hmac IV pointers
+ *
+ * Structure passed to the CESA engine to describe the crypto operation
+ * to be executed.
+ */
+struct mv_cesa_sec_accel_desc {
+ u32 config;
+ u32 enc_p;
+ u32 enc_len;
+ u32 enc_key_p;
+ u32 enc_iv;
+ u32 mac_src_p;
+ u32 mac_digest;
+ u32 mac_iv;
+};
+
+/**
+ * struct mv_cesa_blkcipher_op_ctx - cipher operation context
+ * @key: cipher key
+ * @iv: cipher IV
+ *
+ * Context associated to a cipher operation.
+ */
+struct mv_cesa_blkcipher_op_ctx {
+ u32 key[8];
+ u32 iv[4];
+};
+
+/**
+ * struct mv_cesa_hash_op_ctx - hash or hmac operation context
+ * @key: cipher key
+ * @iv: cipher IV
+ *
+ * Context associated to an hash or hmac operation.
+ */
+struct mv_cesa_hash_op_ctx {
+ u32 iv[16];
+ u32 hash[8];
+};
+
+/**
+ * struct mv_cesa_op_ctx - crypto operation context
+ * @desc: CESA descriptor
+ * @ctx: context associated to the crypto operation
+ *
+ * Context associated to a crypto operation.
+ */
+struct mv_cesa_op_ctx {
+ struct mv_cesa_sec_accel_desc desc;
+ union {
+ struct mv_cesa_blkcipher_op_ctx blkcipher;
+ struct mv_cesa_hash_op_ctx hash;
+ } ctx;
+};
+
+/* TDMA descriptor flags */
+#define CESA_TDMA_DST_IN_SRAM BIT(31)
+#define CESA_TDMA_SRC_IN_SRAM BIT(30)
+#define CESA_TDMA_TYPE_MSK GENMASK(29, 0)
+#define CESA_TDMA_DUMMY 0
+#define CESA_TDMA_DATA 1
+#define CESA_TDMA_OP 2
+
+/**
+ * struct mv_cesa_tdma_desc - TDMA descriptor
+ * @byte_cnt: number of bytes to transfer
+ * @src: DMA address of the source
+ * @dst: DMA address of the destination
+ * @next_dma: DMA address of the next TDMA descriptor
+ * @cur_dma: DMA address of this TDMA descriptor
+ * @next: pointer to the next TDMA descriptor
+ * @op: CESA operation attached to this TDMA descriptor
+ * @data: raw data attached to this TDMA descriptor
+ * @flags: flags describing the TDMA transfer. See the
+ * "TDMA descriptor flags" section above
+ *
+ * TDMA descriptor used to create a transfer chain describing a crypto
+ * operation.
+ */
+struct mv_cesa_tdma_desc {
+ u32 byte_cnt;
+ u32 src;
+ u32 dst;
+ u32 next_dma;
+ u32 cur_dma;
+ struct mv_cesa_tdma_desc *next;
+ union {
+ struct mv_cesa_op_ctx *op;
+ void *data;
+ };
+ u32 flags;
+};
+
+/**
+ * struct mv_cesa_sg_dma_iter - scatter-gather iterator
+ * @dir: transfer direction
+ * @sg: scatter list
+ * @offset: current position in the scatter list
+ * @op_offset: current position in the crypto operation
+ *
+ * Iterator used to iterate over a scatterlist while creating a TDMA chain for
+ * a crypto operation.
+ */
+struct mv_cesa_sg_dma_iter {
+ enum dma_data_direction dir;
+ struct scatterlist *sg;
+ unsigned int offset;
+ unsigned int op_offset;
+};
+
+/**
+ * struct mv_cesa_dma_iter - crypto operation iterator
+ * @len: the crypto operation length
+ * @offset: current position in the crypto operation
+ * @op_len: sub-operation length (the crypto engine can only act on 2kb
+ * chunks)
+ *
+ * Iterator used to create a TDMA chain for a given crypto operation.
+ */
+struct mv_cesa_dma_iter {
+ unsigned int len;
+ unsigned int offset;
+ unsigned int op_len;
+};
+
+/**
+ * struct mv_cesa_tdma_chain - TDMA chain
+ * @first: first entry in the TDMA chain
+ * @last: last entry in the TDMA chain
+ *
+ * Stores a TDMA chain for a specific crypto operation.
+ */
+struct mv_cesa_tdma_chain {
+ struct mv_cesa_tdma_desc *first;
+ struct mv_cesa_tdma_desc *last;
+};
+
+struct mv_cesa_engine;
+
+/**
+ * struct mv_cesa_caps - CESA device capabilities
+ * @engines: number of engines
+ * @has_tdma: whether this device has a TDMA block
+ * @cipher_algs: supported cipher algorithms
+ * @ncipher_algs: number of supported cipher algorithms
+ * @ahash_algs: supported hash algorithms
+ * @nahash_algs: number of supported hash algorithms
+ *
+ * Structure used to describe CESA device capabilities.
+ */
+struct mv_cesa_caps {
+ int nengines;
+ bool has_tdma;
+ struct crypto_alg **cipher_algs;
+ int ncipher_algs;
+ struct ahash_alg **ahash_algs;
+ int nahash_algs;
+};
+
+/**
+ * struct mv_cesa_dev_dma - DMA pools
+ * @tdma_desc_pool: TDMA desc pool
+ * @op_pool: crypto operation pool
+ * @cache_pool: data cache pool (used by hash implementation when the
+ * hash request is smaller than the hash block size)
+ * @padding_pool: padding pool (used by hash implementation when hardware
+ * padding cannot be used)
+ *
+ * Structure containing the different DMA pools used by this driver.
+ */
+struct mv_cesa_dev_dma {
+ struct dma_pool *tdma_desc_pool;
+ struct dma_pool *op_pool;
+ struct dma_pool *cache_pool;
+ struct dma_pool *padding_pool;
+};
+
+/**
+ * struct mv_cesa_dev - CESA device
+ * @caps: device capabilities
+ * @regs: device registers
+ * @sram_size: usable SRAM size
+ * @lock: device lock
+ * @queue: crypto request queue
+ * @engines: array of engines
+ * @dma: dma pools
+ *
+ * Structure storing CESA device information.
+ */
+struct mv_cesa_dev {
+ const struct mv_cesa_caps *caps;
+ void __iomem *regs;
+ struct device *dev;
+ unsigned int sram_size;
+ spinlock_t lock;
+ struct crypto_queue queue;
+ struct mv_cesa_engine *engines;
+ struct mv_cesa_dev_dma *dma;
+};
+
+/**
+ * struct mv_cesa_engine - CESA engine
+ * @id: engine id
+ * @regs: engine registers
+ * @sram: SRAM memory region
+ * @sram_dma: DMA address of the SRAM memory region
+ * @lock: engine lock
+ * @req: current crypto request
+ * @clk: engine clk
+ * @zclk: engine zclk
+ * @max_req_len: maximum chunk length (useful to create the TDMA chain)
+ * @int_mask: interrupt mask cache
+ * @pool: memory pool pointing to the memory region reserved in
+ * SRAM
+ *
+ * Structure storing CESA engine information.
+ */
+struct mv_cesa_engine {
+ int id;
+ void __iomem *regs;
+ void __iomem *sram;
+ dma_addr_t sram_dma;
+ spinlock_t lock;
+ struct crypto_async_request *req;
+ struct clk *clk;
+ struct clk *zclk;
+ size_t max_req_len;
+ u32 int_mask;
+ struct gen_pool *pool;
+};
+
+/**
+ * struct mv_cesa_req_ops - CESA request operations
+ * @prepare: prepare a request to be executed on the specified engine
+ * @process: process a request chunk result (should return 0 if the
+ * operation, -EINPROGRESS if it needs more steps or an error
+ * code)
+ * @step: launch the crypto operation on the next chunk
+ * @cleanup: cleanup the crypto request (release associated data)
+ */
+struct mv_cesa_req_ops {
+ void (*prepare)(struct crypto_async_request *req,
+ struct mv_cesa_engine *engine);
+ int (*process)(struct crypto_async_request *req, u32 status);
+ void (*step)(struct crypto_async_request *req);
+ void (*cleanup)(struct crypto_async_request *req);
+};
+
+/**
+ * struct mv_cesa_ctx - CESA operation context
+ * @ops: crypto operations
+ *
+ * Base context structure inherited by operation specific ones.
+ */
+struct mv_cesa_ctx {
+ const struct mv_cesa_req_ops *ops;
+};
+
+/**
+ * struct mv_cesa_hash_ctx - CESA hash operation context
+ * @base: base context structure
+ *
+ * Hash context structure.
+ */
+struct mv_cesa_hash_ctx {
+ struct mv_cesa_ctx base;
+};
+
+/**
+ * struct mv_cesa_hash_ctx - CESA hmac operation context
+ * @base: base context structure
+ * @iv: initialization vectors
+ *
+ * HMAC context structure.
+ */
+struct mv_cesa_hmac_ctx {
+ struct mv_cesa_ctx base;
+ u32 iv[16];
+};
+
+/**
+ * enum mv_cesa_req_type - request type definitions
+ * @CESA_STD_REQ: standard request
+ * @CESA_DMA_REQ: DMA request
+ */
+enum mv_cesa_req_type {
+ CESA_STD_REQ,
+ CESA_DMA_REQ,
+};
+
+/**
+ * struct mv_cesa_req - CESA request
+ * @type: request type
+ * @engine: engine associated with this request
+ */
+struct mv_cesa_req {
+ enum mv_cesa_req_type type;
+ struct mv_cesa_engine *engine;
+};
+
+/**
+ * struct mv_cesa_tdma_req - CESA TDMA request
+ * @base: base information
+ * @chain: TDMA chain
+ */
+struct mv_cesa_tdma_req {
+ struct mv_cesa_req base;
+ struct mv_cesa_tdma_chain chain;
+};
+
+/**
+ * struct mv_cesa_sg_std_iter - CESA scatter-gather iterator for standard
+ * requests
+ * @iter: sg mapping iterator
+ * @offset: current offset in the SG entry mapped in memory
+ */
+struct mv_cesa_sg_std_iter {
+ struct sg_mapping_iter iter;
+ unsigned int offset;
+};
+
+/**
+ * struct mv_cesa_ablkcipher_std_req - cipher standard request
+ * @base: base information
+ * @op: operation context
+ * @offset: current operation offset
+ * @size: size of the crypto operation
+ */
+struct mv_cesa_ablkcipher_std_req {
+ struct mv_cesa_req base;
+ struct mv_cesa_op_ctx op;
+ unsigned int offset;
+ unsigned int size;
+ bool skip_ctx;
+};
+
+/**
+ * struct mv_cesa_ablkcipher_req - cipher request
+ * @req: type specific request information
+ * @src_nents: number of entries in the src sg list
+ * @dst_nents: number of entries in the dest sg list
+ */
+struct mv_cesa_ablkcipher_req {
+ union {
+ struct mv_cesa_req base;
+ struct mv_cesa_tdma_req dma;
+ struct mv_cesa_ablkcipher_std_req std;
+ } req;
+ int src_nents;
+ int dst_nents;
+};
+
+/**
+ * struct mv_cesa_ahash_std_req - standard hash request
+ * @base: base information
+ * @offset: current operation offset
+ */
+struct mv_cesa_ahash_std_req {
+ struct mv_cesa_req base;
+ unsigned int offset;
+};
+
+/**
+ * struct mv_cesa_ahash_dma_req - DMA hash request
+ * @base: base information
+ * @padding: padding buffer
+ * @padding_dma: DMA address of the padding buffer
+ * @cache_dma: DMA address of the cache buffer
+ */
+struct mv_cesa_ahash_dma_req {
+ struct mv_cesa_tdma_req base;
+ u8 *padding;
+ dma_addr_t padding_dma;
+ dma_addr_t cache_dma;
+};
+
+/**
+ * struct mv_cesa_ahash_req - hash request
+ * @req: type specific request information
+ * @cache: cache buffer
+ * @cache_ptr: write pointer in the cache buffer
+ * @len: hash total length
+ * @src_nents: number of entries in the scatterlist
+ * @last_req: define whether the current operation is the last one
+ * or not
+ * @state: hash state
+ */
+struct mv_cesa_ahash_req {
+ union {
+ struct mv_cesa_req base;
+ struct mv_cesa_ahash_dma_req dma;
+ struct mv_cesa_ahash_std_req std;
+ } req;
+ struct mv_cesa_op_ctx op_tmpl;
+ u8 *cache;
+ unsigned int cache_ptr;
+ u64 len;
+ int src_nents;
+ bool last_req;
+ __be32 state[8];
+};
+
+/* CESA functions */
+
+extern struct mv_cesa_dev *cesa_dev;
+
+static inline void mv_cesa_update_op_cfg(struct mv_cesa_op_ctx *op,
+ u32 cfg, u32 mask)
+{
+ op->desc.config &= cpu_to_le32(~mask);
+ op->desc.config |= cpu_to_le32(cfg);
+}
+
+static inline u32 mv_cesa_get_op_cfg(struct mv_cesa_op_ctx *op)
+{
+ return le32_to_cpu(op->desc.config);
+}
+
+static inline void mv_cesa_set_op_cfg(struct mv_cesa_op_ctx *op, u32 cfg)
+{
+ op->desc.config = cpu_to_le32(cfg);
+}
+
+static inline void mv_cesa_adjust_op(struct mv_cesa_engine *engine,
+ struct mv_cesa_op_ctx *op)
+{
+ u32 offset = engine->sram_dma & CESA_SA_SRAM_MSK;
+
+ op->desc.enc_p = CESA_SA_DESC_CRYPT_DATA(offset);
+ op->desc.enc_key_p = CESA_SA_DESC_CRYPT_KEY(offset);
+ op->desc.enc_iv = CESA_SA_DESC_CRYPT_IV(offset);
+ op->desc.mac_src_p &= ~CESA_SA_DESC_MAC_DATA_MSK;
+ op->desc.mac_src_p |= CESA_SA_DESC_MAC_DATA(offset);
+ op->desc.mac_digest &= ~CESA_SA_DESC_MAC_DIGEST_MSK;
+ op->desc.mac_digest |= CESA_SA_DESC_MAC_DIGEST(offset);
+ op->desc.mac_iv = CESA_SA_DESC_MAC_IV(offset);
+}
+
+static inline void mv_cesa_set_crypt_op_len(struct mv_cesa_op_ctx *op, int len)
+{
+ op->desc.enc_len = cpu_to_le32(len);
+}
+
+static inline void mv_cesa_set_mac_op_total_len(struct mv_cesa_op_ctx *op,
+ int len)
+{
+ op->desc.mac_src_p &= ~CESA_SA_DESC_MAC_TOTAL_LEN_MSK;
+ op->desc.mac_src_p |= CESA_SA_DESC_MAC_TOTAL_LEN(len);
+}
+
+static inline void mv_cesa_set_mac_op_frag_len(struct mv_cesa_op_ctx *op,
+ int len)
+{
+ op->desc.mac_digest &= ~CESA_SA_DESC_MAC_FRAG_LEN_MSK;
+ op->desc.mac_digest |= CESA_SA_DESC_MAC_FRAG_LEN(len);
+}
+
+static inline void mv_cesa_set_int_mask(struct mv_cesa_engine *engine,
+ u32 int_mask)
+{
+ if (int_mask == engine->int_mask)
+ return;
+
+ writel(int_mask, engine->regs + CESA_SA_INT_MSK);
+ engine->int_mask = int_mask;
+}
+
+static inline u32 mv_cesa_get_int_mask(struct mv_cesa_engine *engine)
+{
+ return engine->int_mask;
+}
+
+int mv_cesa_queue_req(struct crypto_async_request *req);
+
+/* TDMA functions */
+
+static inline void mv_cesa_req_dma_iter_init(struct mv_cesa_dma_iter *iter,
+ unsigned int len)
+{
+ iter->len = len;
+ iter->op_len = min(len, CESA_SA_SRAM_PAYLOAD_SIZE);
+ iter->offset = 0;
+}
+
+static inline void mv_cesa_sg_dma_iter_init(struct mv_cesa_sg_dma_iter *iter,
+ struct scatterlist *sg,
+ enum dma_data_direction dir)
+{
+ iter->op_offset = 0;
+ iter->offset = 0;
+ iter->sg = sg;
+ iter->dir = dir;
+}
+
+static inline unsigned int
+mv_cesa_req_dma_iter_transfer_len(struct mv_cesa_dma_iter *iter,
+ struct mv_cesa_sg_dma_iter *sgiter)
+{
+ return min(iter->op_len - sgiter->op_offset,
+ sg_dma_len(sgiter->sg) - sgiter->offset);
+}
+
+bool mv_cesa_req_dma_iter_next_transfer(struct mv_cesa_dma_iter *chain,
+ struct mv_cesa_sg_dma_iter *sgiter,
+ unsigned int len);
+
+static inline bool mv_cesa_req_dma_iter_next_op(struct mv_cesa_dma_iter *iter)
+{
+ iter->offset += iter->op_len;
+ iter->op_len = min(iter->len - iter->offset,
+ CESA_SA_SRAM_PAYLOAD_SIZE);
+
+ return iter->op_len;
+}
+
+void mv_cesa_dma_step(struct mv_cesa_tdma_req *dreq);
+
+static inline int mv_cesa_dma_process(struct mv_cesa_tdma_req *dreq,
+ u32 status)
+{
+ if (!(status & CESA_SA_INT_ACC0_IDMA_DONE))
+ return -EINPROGRESS;
+
+ if (status & CESA_SA_INT_IDMA_OWN_ERR)
+ return -EINVAL;
+
+ return 0;
+}
+
+void mv_cesa_dma_prepare(struct mv_cesa_tdma_req *dreq,
+ struct mv_cesa_engine *engine);
+
+void mv_cesa_dma_cleanup(struct mv_cesa_tdma_req *dreq);
+
+static inline void
+mv_cesa_tdma_desc_iter_init(struct mv_cesa_tdma_chain *chain)
+{
+ memset(chain, 0, sizeof(*chain));
+}
+
+struct mv_cesa_op_ctx *mv_cesa_dma_add_op(struct mv_cesa_tdma_chain *chain,
+ const struct mv_cesa_op_ctx *op_templ,
+ bool skip_ctx,
+ gfp_t flags);
+
+int mv_cesa_dma_add_data_transfer(struct mv_cesa_tdma_chain *chain,
+ dma_addr_t dst, dma_addr_t src, u32 size,
+ u32 flags, gfp_t gfp_flags);
+
+int mv_cesa_dma_add_dummy_launch(struct mv_cesa_tdma_chain *chain,
+ u32 flags);
+
+int mv_cesa_dma_add_dummy_end(struct mv_cesa_tdma_chain *chain, u32 flags);
+
+int mv_cesa_dma_add_op_transfers(struct mv_cesa_tdma_chain *chain,
+ struct mv_cesa_dma_iter *dma_iter,
+ struct mv_cesa_sg_dma_iter *sgiter,
+ gfp_t gfp_flags);
+
+/* Algorithm definitions */
+
+extern struct ahash_alg mv_md5_alg;
+extern struct ahash_alg mv_sha1_alg;
+extern struct ahash_alg mv_sha256_alg;
+extern struct ahash_alg mv_ahmac_md5_alg;
+extern struct ahash_alg mv_ahmac_sha1_alg;
+extern struct ahash_alg mv_ahmac_sha256_alg;
+
+extern struct crypto_alg mv_cesa_ecb_des_alg;
+extern struct crypto_alg mv_cesa_cbc_des_alg;
+extern struct crypto_alg mv_cesa_ecb_des3_ede_alg;
+extern struct crypto_alg mv_cesa_cbc_des3_ede_alg;
+extern struct crypto_alg mv_cesa_ecb_aes_alg;
+extern struct crypto_alg mv_cesa_cbc_aes_alg;
+
+#endif /* __MARVELL_CESA_H__ */
diff --git a/drivers/crypto/marvell/cipher.c b/drivers/crypto/marvell/cipher.c
new file mode 100644
index 000000000000..0745cf3b9c0e
--- /dev/null
+++ b/drivers/crypto/marvell/cipher.c
@@ -0,0 +1,797 @@
+/*
+ * Cipher algorithms supported by the CESA: DES, 3DES and AES.
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ * Author: Arnaud Ebalard <arno@natisbad.org>
+ *
+ * This work is based on an initial version written by
+ * Sebastian Andrzej Siewior < sebastian at breakpoint dot cc >
+ *
+ * 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 <crypto/aes.h>
+#include <crypto/des.h>
+
+#include "cesa.h"
+
+struct mv_cesa_des_ctx {
+ struct mv_cesa_ctx base;
+ u8 key[DES_KEY_SIZE];
+};
+
+struct mv_cesa_des3_ctx {
+ struct mv_cesa_ctx base;
+ u8 key[DES3_EDE_KEY_SIZE];
+};
+
+struct mv_cesa_aes_ctx {
+ struct mv_cesa_ctx base;
+ struct crypto_aes_ctx aes;
+};
+
+struct mv_cesa_ablkcipher_dma_iter {
+ struct mv_cesa_dma_iter base;
+ struct mv_cesa_sg_dma_iter src;
+ struct mv_cesa_sg_dma_iter dst;
+};
+
+static inline void
+mv_cesa_ablkcipher_req_iter_init(struct mv_cesa_ablkcipher_dma_iter *iter,
+ struct ablkcipher_request *req)
+{
+ mv_cesa_req_dma_iter_init(&iter->base, req->nbytes);
+ mv_cesa_sg_dma_iter_init(&iter->src, req->src, DMA_TO_DEVICE);
+ mv_cesa_sg_dma_iter_init(&iter->dst, req->dst, DMA_FROM_DEVICE);
+}
+
+static inline bool
+mv_cesa_ablkcipher_req_iter_next_op(struct mv_cesa_ablkcipher_dma_iter *iter)
+{
+ iter->src.op_offset = 0;
+ iter->dst.op_offset = 0;
+
+ return mv_cesa_req_dma_iter_next_op(&iter->base);
+}
+
+static inline void
+mv_cesa_ablkcipher_dma_cleanup(struct ablkcipher_request *req)
+{
+ struct mv_cesa_ablkcipher_req *creq = ablkcipher_request_ctx(req);
+
+ if (req->dst != req->src) {
+ dma_unmap_sg(cesa_dev->dev, req->dst, creq->dst_nents,
+ DMA_FROM_DEVICE);
+ dma_unmap_sg(cesa_dev->dev, req->src, creq->src_nents,
+ DMA_TO_DEVICE);
+ } else {
+ dma_unmap_sg(cesa_dev->dev, req->src, creq->src_nents,
+ DMA_BIDIRECTIONAL);
+ }
+ mv_cesa_dma_cleanup(&creq->req.dma);
+}
+
+static inline void mv_cesa_ablkcipher_cleanup(struct ablkcipher_request *req)
+{
+ struct mv_cesa_ablkcipher_req *creq = ablkcipher_request_ctx(req);
+
+ if (creq->req.base.type == CESA_DMA_REQ)
+ mv_cesa_ablkcipher_dma_cleanup(req);
+}
+
+static void mv_cesa_ablkcipher_std_step(struct ablkcipher_request *req)
+{
+ struct mv_cesa_ablkcipher_req *creq = ablkcipher_request_ctx(req);
+ struct mv_cesa_ablkcipher_std_req *sreq = &creq->req.std;
+ struct mv_cesa_engine *engine = sreq->base.engine;
+ size_t len = min_t(size_t, req->nbytes - sreq->offset,
+ CESA_SA_SRAM_PAYLOAD_SIZE);
+
+ len = sg_pcopy_to_buffer(req->src, creq->src_nents,
+ engine->sram + CESA_SA_DATA_SRAM_OFFSET,
+ len, sreq->offset);
+
+ sreq->size = len;
+ mv_cesa_set_crypt_op_len(&sreq->op, len);
+
+ /* FIXME: only update enc_len field */
+ if (!sreq->skip_ctx) {
+ memcpy(engine->sram, &sreq->op, sizeof(sreq->op));
+ sreq->skip_ctx = true;
+ } else {
+ memcpy(engine->sram, &sreq->op, sizeof(sreq->op.desc));
+ }
+
+ mv_cesa_set_int_mask(engine, CESA_SA_INT_ACCEL0_DONE);
+ writel(CESA_SA_CFG_PARA_DIS, engine->regs + CESA_SA_CFG);
+ writel(CESA_SA_CMD_EN_CESA_SA_ACCL0, engine->regs + CESA_SA_CMD);
+}
+
+static int mv_cesa_ablkcipher_std_process(struct ablkcipher_request *req,
+ u32 status)
+{
+ struct mv_cesa_ablkcipher_req *creq = ablkcipher_request_ctx(req);
+ struct mv_cesa_ablkcipher_std_req *sreq = &creq->req.std;
+ struct mv_cesa_engine *engine = sreq->base.engine;
+ size_t len;
+
+ len = sg_pcopy_from_buffer(req->dst, creq->dst_nents,
+ engine->sram + CESA_SA_DATA_SRAM_OFFSET,
+ sreq->size, sreq->offset);
+
+ sreq->offset += len;
+ if (sreq->offset < req->nbytes)
+ return -EINPROGRESS;
+
+ return 0;
+}
+
+static int mv_cesa_ablkcipher_process(struct crypto_async_request *req,
+ u32 status)
+{
+ struct ablkcipher_request *ablkreq = ablkcipher_request_cast(req);
+ struct mv_cesa_ablkcipher_req *creq = ablkcipher_request_ctx(ablkreq);
+ struct mv_cesa_ablkcipher_std_req *sreq = &creq->req.std;
+ struct mv_cesa_engine *engine = sreq->base.engine;
+ int ret;
+
+ if (creq->req.base.type == CESA_DMA_REQ)
+ ret = mv_cesa_dma_process(&creq->req.dma, status);
+ else
+ ret = mv_cesa_ablkcipher_std_process(ablkreq, status);
+
+ if (ret)
+ return ret;
+
+ memcpy(ablkreq->info, engine->sram + CESA_SA_CRYPT_IV_SRAM_OFFSET,
+ crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(ablkreq)));
+
+ return 0;
+}
+
+static void mv_cesa_ablkcipher_step(struct crypto_async_request *req)
+{
+ struct ablkcipher_request *ablkreq = ablkcipher_request_cast(req);
+ struct mv_cesa_ablkcipher_req *creq = ablkcipher_request_ctx(ablkreq);
+
+ if (creq->req.base.type == CESA_DMA_REQ)
+ mv_cesa_dma_step(&creq->req.dma);
+ else
+ mv_cesa_ablkcipher_std_step(ablkreq);
+}
+
+static inline void
+mv_cesa_ablkcipher_dma_prepare(struct ablkcipher_request *req)
+{
+ struct mv_cesa_ablkcipher_req *creq = ablkcipher_request_ctx(req);
+ struct mv_cesa_tdma_req *dreq = &creq->req.dma;
+
+ mv_cesa_dma_prepare(dreq, dreq->base.engine);
+}
+
+static inline void
+mv_cesa_ablkcipher_std_prepare(struct ablkcipher_request *req)
+{
+ struct mv_cesa_ablkcipher_req *creq = ablkcipher_request_ctx(req);
+ struct mv_cesa_ablkcipher_std_req *sreq = &creq->req.std;
+ struct mv_cesa_engine *engine = sreq->base.engine;
+
+ sreq->size = 0;
+ sreq->offset = 0;
+ mv_cesa_adjust_op(engine, &sreq->op);
+ memcpy(engine->sram, &sreq->op, sizeof(sreq->op));
+}
+
+static inline void mv_cesa_ablkcipher_prepare(struct crypto_async_request *req,
+ struct mv_cesa_engine *engine)
+{
+ struct ablkcipher_request *ablkreq = ablkcipher_request_cast(req);
+ struct mv_cesa_ablkcipher_req *creq = ablkcipher_request_ctx(ablkreq);
+
+ creq->req.base.engine = engine;
+
+ if (creq->req.base.type == CESA_DMA_REQ)
+ mv_cesa_ablkcipher_dma_prepare(ablkreq);
+ else
+ mv_cesa_ablkcipher_std_prepare(ablkreq);
+}
+
+static inline void
+mv_cesa_ablkcipher_req_cleanup(struct crypto_async_request *req)
+{
+ struct ablkcipher_request *ablkreq = ablkcipher_request_cast(req);
+
+ mv_cesa_ablkcipher_cleanup(ablkreq);
+}
+
+static const struct mv_cesa_req_ops mv_cesa_ablkcipher_req_ops = {
+ .step = mv_cesa_ablkcipher_step,
+ .process = mv_cesa_ablkcipher_process,
+ .prepare = mv_cesa_ablkcipher_prepare,
+ .cleanup = mv_cesa_ablkcipher_req_cleanup,
+};
+
+static int mv_cesa_ablkcipher_cra_init(struct crypto_tfm *tfm)
+{
+ struct mv_cesa_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ ctx->base.ops = &mv_cesa_ablkcipher_req_ops;
+
+ tfm->crt_ablkcipher.reqsize = sizeof(struct mv_cesa_ablkcipher_req);
+
+ return 0;
+}
+
+static int mv_cesa_aes_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
+ unsigned int len)
+{
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
+ struct mv_cesa_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+ int remaining;
+ int offset;
+ int ret;
+ int i;
+
+ ret = crypto_aes_expand_key(&ctx->aes, key, len);
+ if (ret) {
+ crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return ret;
+ }
+
+ remaining = (ctx->aes.key_length - 16) / 4;
+ offset = ctx->aes.key_length + 24 - remaining;
+ for (i = 0; i < remaining; i++)
+ ctx->aes.key_dec[4 + i] =
+ cpu_to_le32(ctx->aes.key_enc[offset + i]);
+
+ return 0;
+}
+
+static int mv_cesa_des_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
+ unsigned int len)
+{
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
+ struct mv_cesa_des_ctx *ctx = crypto_tfm_ctx(tfm);
+ u32 tmp[DES_EXPKEY_WORDS];
+ int ret;
+
+ if (len != DES_KEY_SIZE) {
+ crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ ret = des_ekey(tmp, key);
+ if (!ret && (tfm->crt_flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
+ return -EINVAL;
+ }
+
+ memcpy(ctx->key, key, DES_KEY_SIZE);
+
+ return 0;
+}
+
+static int mv_cesa_des3_ede_setkey(struct crypto_ablkcipher *cipher,
+ const u8 *key, unsigned int len)
+{
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
+ struct mv_cesa_des_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (len != DES3_EDE_KEY_SIZE) {
+ crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ memcpy(ctx->key, key, DES3_EDE_KEY_SIZE);
+
+ return 0;
+}
+
+static int mv_cesa_ablkcipher_dma_req_init(struct ablkcipher_request *req,
+ const struct mv_cesa_op_ctx *op_templ)
+{
+ struct mv_cesa_ablkcipher_req *creq = ablkcipher_request_ctx(req);
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ struct mv_cesa_tdma_req *dreq = &creq->req.dma;
+ struct mv_cesa_ablkcipher_dma_iter iter;
+ struct mv_cesa_tdma_chain chain;
+ bool skip_ctx = false;
+ int ret;
+
+ dreq->base.type = CESA_DMA_REQ;
+ dreq->chain.first = NULL;
+ dreq->chain.last = NULL;
+
+ if (req->src != req->dst) {
+ ret = dma_map_sg(cesa_dev->dev, req->src, creq->src_nents,
+ DMA_TO_DEVICE);
+ if (!ret)
+ return -ENOMEM;
+
+ ret = dma_map_sg(cesa_dev->dev, req->dst, creq->dst_nents,
+ DMA_FROM_DEVICE);
+ if (!ret) {
+ ret = -ENOMEM;
+ goto err_unmap_src;
+ }
+ } else {
+ ret = dma_map_sg(cesa_dev->dev, req->src, creq->src_nents,
+ DMA_BIDIRECTIONAL);
+ if (!ret)
+ return -ENOMEM;
+ }
+
+ mv_cesa_tdma_desc_iter_init(&chain);
+ mv_cesa_ablkcipher_req_iter_init(&iter, req);
+
+ do {
+ struct mv_cesa_op_ctx *op;
+
+ op = mv_cesa_dma_add_op(&chain, op_templ, skip_ctx, flags);
+ if (IS_ERR(op)) {
+ ret = PTR_ERR(op);
+ goto err_free_tdma;
+ }
+ skip_ctx = true;
+
+ mv_cesa_set_crypt_op_len(op, iter.base.op_len);
+
+ /* Add input transfers */
+ ret = mv_cesa_dma_add_op_transfers(&chain, &iter.base,
+ &iter.src, flags);
+ if (ret)
+ goto err_free_tdma;
+
+ /* Add dummy desc to launch the crypto operation */
+ ret = mv_cesa_dma_add_dummy_launch(&chain, flags);
+ if (ret)
+ goto err_free_tdma;
+
+ /* Add output transfers */
+ ret = mv_cesa_dma_add_op_transfers(&chain, &iter.base,
+ &iter.dst, flags);
+ if (ret)
+ goto err_free_tdma;
+
+ } while (mv_cesa_ablkcipher_req_iter_next_op(&iter));
+
+ dreq->chain = chain;
+
+ return 0;
+
+err_free_tdma:
+ mv_cesa_dma_cleanup(dreq);
+ if (req->dst != req->src)
+ dma_unmap_sg(cesa_dev->dev, req->dst, creq->dst_nents,
+ DMA_FROM_DEVICE);
+
+err_unmap_src:
+ dma_unmap_sg(cesa_dev->dev, req->src, creq->src_nents,
+ req->dst != req->src ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL);
+
+ return ret;
+}
+
+static inline int
+mv_cesa_ablkcipher_std_req_init(struct ablkcipher_request *req,
+ const struct mv_cesa_op_ctx *op_templ)
+{
+ struct mv_cesa_ablkcipher_req *creq = ablkcipher_request_ctx(req);
+ struct mv_cesa_ablkcipher_std_req *sreq = &creq->req.std;
+
+ sreq->base.type = CESA_STD_REQ;
+ sreq->op = *op_templ;
+ sreq->skip_ctx = false;
+
+ return 0;
+}
+
+static int mv_cesa_ablkcipher_req_init(struct ablkcipher_request *req,
+ struct mv_cesa_op_ctx *tmpl)
+{
+ struct mv_cesa_ablkcipher_req *creq = ablkcipher_request_ctx(req);
+ struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+ unsigned int blksize = crypto_ablkcipher_blocksize(tfm);
+ int ret;
+
+ if (!IS_ALIGNED(req->nbytes, blksize))
+ return -EINVAL;
+
+ creq->src_nents = sg_nents_for_len(req->src, req->nbytes);
+ creq->dst_nents = sg_nents_for_len(req->dst, req->nbytes);
+
+ mv_cesa_update_op_cfg(tmpl, CESA_SA_DESC_CFG_OP_CRYPT_ONLY,
+ CESA_SA_DESC_CFG_OP_MSK);
+
+ /* TODO: add a threshold for DMA usage */
+ if (cesa_dev->caps->has_tdma)
+ ret = mv_cesa_ablkcipher_dma_req_init(req, tmpl);
+ else
+ ret = mv_cesa_ablkcipher_std_req_init(req, tmpl);
+
+ return ret;
+}
+
+static int mv_cesa_des_op(struct ablkcipher_request *req,
+ struct mv_cesa_op_ctx *tmpl)
+{
+ struct mv_cesa_des_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ int ret;
+
+ mv_cesa_update_op_cfg(tmpl, CESA_SA_DESC_CFG_CRYPTM_DES,
+ CESA_SA_DESC_CFG_CRYPTM_MSK);
+
+ memcpy(tmpl->ctx.blkcipher.key, ctx->key, DES_KEY_SIZE);
+
+ ret = mv_cesa_ablkcipher_req_init(req, tmpl);
+ if (ret)
+ return ret;
+
+ ret = mv_cesa_queue_req(&req->base);
+ if (ret && ret != -EINPROGRESS)
+ mv_cesa_ablkcipher_cleanup(req);
+
+ return ret;
+}
+
+static int mv_cesa_ecb_des_encrypt(struct ablkcipher_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl,
+ CESA_SA_DESC_CFG_CRYPTCM_ECB |
+ CESA_SA_DESC_CFG_DIR_ENC);
+
+ return mv_cesa_des_op(req, &tmpl);
+}
+
+static int mv_cesa_ecb_des_decrypt(struct ablkcipher_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl,
+ CESA_SA_DESC_CFG_CRYPTCM_ECB |
+ CESA_SA_DESC_CFG_DIR_DEC);
+
+ return mv_cesa_des_op(req, &tmpl);
+}
+
+struct crypto_alg mv_cesa_ecb_des_alg = {
+ .cra_name = "ecb(des)",
+ .cra_driver_name = "mv-ecb-des",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mv_cesa_des_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = mv_cesa_ablkcipher_cra_init,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .setkey = mv_cesa_des_setkey,
+ .encrypt = mv_cesa_ecb_des_encrypt,
+ .decrypt = mv_cesa_ecb_des_decrypt,
+ },
+ },
+};
+
+static int mv_cesa_cbc_des_op(struct ablkcipher_request *req,
+ struct mv_cesa_op_ctx *tmpl)
+{
+ mv_cesa_update_op_cfg(tmpl, CESA_SA_DESC_CFG_CRYPTCM_CBC,
+ CESA_SA_DESC_CFG_CRYPTCM_MSK);
+
+ memcpy(tmpl->ctx.blkcipher.iv, req->info, DES_BLOCK_SIZE);
+
+ return mv_cesa_des_op(req, tmpl);
+}
+
+static int mv_cesa_cbc_des_encrypt(struct ablkcipher_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_DIR_ENC);
+
+ return mv_cesa_cbc_des_op(req, &tmpl);
+}
+
+static int mv_cesa_cbc_des_decrypt(struct ablkcipher_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_DIR_DEC);
+
+ return mv_cesa_cbc_des_op(req, &tmpl);
+}
+
+struct crypto_alg mv_cesa_cbc_des_alg = {
+ .cra_name = "cbc(des)",
+ .cra_driver_name = "mv-cbc-des",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mv_cesa_des_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = mv_cesa_ablkcipher_cra_init,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ .setkey = mv_cesa_des_setkey,
+ .encrypt = mv_cesa_cbc_des_encrypt,
+ .decrypt = mv_cesa_cbc_des_decrypt,
+ },
+ },
+};
+
+static int mv_cesa_des3_op(struct ablkcipher_request *req,
+ struct mv_cesa_op_ctx *tmpl)
+{
+ struct mv_cesa_des3_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ int ret;
+
+ mv_cesa_update_op_cfg(tmpl, CESA_SA_DESC_CFG_CRYPTM_3DES,
+ CESA_SA_DESC_CFG_CRYPTM_MSK);
+
+ memcpy(tmpl->ctx.blkcipher.key, ctx->key, DES3_EDE_KEY_SIZE);
+
+ ret = mv_cesa_ablkcipher_req_init(req, tmpl);
+ if (ret)
+ return ret;
+
+ ret = mv_cesa_queue_req(&req->base);
+ if (ret && ret != -EINPROGRESS)
+ mv_cesa_ablkcipher_cleanup(req);
+
+ return ret;
+}
+
+static int mv_cesa_ecb_des3_ede_encrypt(struct ablkcipher_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl,
+ CESA_SA_DESC_CFG_CRYPTCM_ECB |
+ CESA_SA_DESC_CFG_3DES_EDE |
+ CESA_SA_DESC_CFG_DIR_ENC);
+
+ return mv_cesa_des3_op(req, &tmpl);
+}
+
+static int mv_cesa_ecb_des3_ede_decrypt(struct ablkcipher_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl,
+ CESA_SA_DESC_CFG_CRYPTCM_ECB |
+ CESA_SA_DESC_CFG_3DES_EDE |
+ CESA_SA_DESC_CFG_DIR_DEC);
+
+ return mv_cesa_des3_op(req, &tmpl);
+}
+
+struct crypto_alg mv_cesa_ecb_des3_ede_alg = {
+ .cra_name = "ecb(des3_ede)",
+ .cra_driver_name = "mv-ecb-des3-ede",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mv_cesa_des3_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = mv_cesa_ablkcipher_cra_init,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .setkey = mv_cesa_des3_ede_setkey,
+ .encrypt = mv_cesa_ecb_des3_ede_encrypt,
+ .decrypt = mv_cesa_ecb_des3_ede_decrypt,
+ },
+ },
+};
+
+static int mv_cesa_cbc_des3_op(struct ablkcipher_request *req,
+ struct mv_cesa_op_ctx *tmpl)
+{
+ memcpy(tmpl->ctx.blkcipher.iv, req->info, DES3_EDE_BLOCK_SIZE);
+
+ return mv_cesa_des3_op(req, tmpl);
+}
+
+static int mv_cesa_cbc_des3_ede_encrypt(struct ablkcipher_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl,
+ CESA_SA_DESC_CFG_CRYPTCM_CBC |
+ CESA_SA_DESC_CFG_3DES_EDE |
+ CESA_SA_DESC_CFG_DIR_ENC);
+
+ return mv_cesa_cbc_des3_op(req, &tmpl);
+}
+
+static int mv_cesa_cbc_des3_ede_decrypt(struct ablkcipher_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl,
+ CESA_SA_DESC_CFG_CRYPTCM_CBC |
+ CESA_SA_DESC_CFG_3DES_EDE |
+ CESA_SA_DESC_CFG_DIR_DEC);
+
+ return mv_cesa_cbc_des3_op(req, &tmpl);
+}
+
+struct crypto_alg mv_cesa_cbc_des3_ede_alg = {
+ .cra_name = "cbc(des3_ede)",
+ .cra_driver_name = "mv-cbc-des3-ede",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mv_cesa_des3_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = mv_cesa_ablkcipher_cra_init,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .setkey = mv_cesa_des3_ede_setkey,
+ .encrypt = mv_cesa_cbc_des3_ede_encrypt,
+ .decrypt = mv_cesa_cbc_des3_ede_decrypt,
+ },
+ },
+};
+
+static int mv_cesa_aes_op(struct ablkcipher_request *req,
+ struct mv_cesa_op_ctx *tmpl)
+{
+ struct mv_cesa_aes_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ int ret, i;
+ u32 *key;
+ u32 cfg;
+
+ cfg = CESA_SA_DESC_CFG_CRYPTM_AES;
+
+ if (mv_cesa_get_op_cfg(tmpl) & CESA_SA_DESC_CFG_DIR_DEC)
+ key = ctx->aes.key_dec;
+ else
+ key = ctx->aes.key_enc;
+
+ for (i = 0; i < ctx->aes.key_length / sizeof(u32); i++)
+ tmpl->ctx.blkcipher.key[i] = cpu_to_le32(key[i]);
+
+ if (ctx->aes.key_length == 24)
+ cfg |= CESA_SA_DESC_CFG_AES_LEN_192;
+ else if (ctx->aes.key_length == 32)
+ cfg |= CESA_SA_DESC_CFG_AES_LEN_256;
+
+ mv_cesa_update_op_cfg(tmpl, cfg,
+ CESA_SA_DESC_CFG_CRYPTM_MSK |
+ CESA_SA_DESC_CFG_AES_LEN_MSK);
+
+ ret = mv_cesa_ablkcipher_req_init(req, tmpl);
+ if (ret)
+ return ret;
+
+ ret = mv_cesa_queue_req(&req->base);
+ if (ret && ret != -EINPROGRESS)
+ mv_cesa_ablkcipher_cleanup(req);
+
+ return ret;
+}
+
+static int mv_cesa_ecb_aes_encrypt(struct ablkcipher_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl,
+ CESA_SA_DESC_CFG_CRYPTCM_ECB |
+ CESA_SA_DESC_CFG_DIR_ENC);
+
+ return mv_cesa_aes_op(req, &tmpl);
+}
+
+static int mv_cesa_ecb_aes_decrypt(struct ablkcipher_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl,
+ CESA_SA_DESC_CFG_CRYPTCM_ECB |
+ CESA_SA_DESC_CFG_DIR_DEC);
+
+ return mv_cesa_aes_op(req, &tmpl);
+}
+
+struct crypto_alg mv_cesa_ecb_aes_alg = {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "mv-ecb-aes",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mv_cesa_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = mv_cesa_ablkcipher_cra_init,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = mv_cesa_aes_setkey,
+ .encrypt = mv_cesa_ecb_aes_encrypt,
+ .decrypt = mv_cesa_ecb_aes_decrypt,
+ },
+ },
+};
+
+static int mv_cesa_cbc_aes_op(struct ablkcipher_request *req,
+ struct mv_cesa_op_ctx *tmpl)
+{
+ mv_cesa_update_op_cfg(tmpl, CESA_SA_DESC_CFG_CRYPTCM_CBC,
+ CESA_SA_DESC_CFG_CRYPTCM_MSK);
+ memcpy(tmpl->ctx.blkcipher.iv, req->info, AES_BLOCK_SIZE);
+
+ return mv_cesa_aes_op(req, tmpl);
+}
+
+static int mv_cesa_cbc_aes_encrypt(struct ablkcipher_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_DIR_ENC);
+
+ return mv_cesa_cbc_aes_op(req, &tmpl);
+}
+
+static int mv_cesa_cbc_aes_decrypt(struct ablkcipher_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_DIR_DEC);
+
+ return mv_cesa_cbc_aes_op(req, &tmpl);
+}
+
+struct crypto_alg mv_cesa_cbc_aes_alg = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "mv-cbc-aes",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mv_cesa_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = mv_cesa_ablkcipher_cra_init,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = mv_cesa_aes_setkey,
+ .encrypt = mv_cesa_cbc_aes_encrypt,
+ .decrypt = mv_cesa_cbc_aes_decrypt,
+ },
+ },
+};
diff --git a/drivers/crypto/marvell/hash.c b/drivers/crypto/marvell/hash.c
new file mode 100644
index 000000000000..ae9272eb9c1a
--- /dev/null
+++ b/drivers/crypto/marvell/hash.c
@@ -0,0 +1,1441 @@
+/*
+ * Hash algorithms supported by the CESA: MD5, SHA1 and SHA256.
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ * Author: Arnaud Ebalard <arno@natisbad.org>
+ *
+ * This work is based on an initial version written by
+ * Sebastian Andrzej Siewior < sebastian at breakpoint dot cc >
+ *
+ * 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 <crypto/md5.h>
+#include <crypto/sha.h>
+
+#include "cesa.h"
+
+struct mv_cesa_ahash_dma_iter {
+ struct mv_cesa_dma_iter base;
+ struct mv_cesa_sg_dma_iter src;
+};
+
+static inline void
+mv_cesa_ahash_req_iter_init(struct mv_cesa_ahash_dma_iter *iter,
+ struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ unsigned int len = req->nbytes;
+
+ if (!creq->last_req)
+ len = (len + creq->cache_ptr) & ~CESA_HASH_BLOCK_SIZE_MSK;
+
+ mv_cesa_req_dma_iter_init(&iter->base, len);
+ mv_cesa_sg_dma_iter_init(&iter->src, req->src, DMA_TO_DEVICE);
+ iter->src.op_offset = creq->cache_ptr;
+}
+
+static inline bool
+mv_cesa_ahash_req_iter_next_op(struct mv_cesa_ahash_dma_iter *iter)
+{
+ iter->src.op_offset = 0;
+
+ return mv_cesa_req_dma_iter_next_op(&iter->base);
+}
+
+static inline int mv_cesa_ahash_dma_alloc_cache(struct mv_cesa_ahash_req *creq,
+ gfp_t flags)
+{
+ struct mv_cesa_ahash_dma_req *dreq = &creq->req.dma;
+
+ creq->cache = dma_pool_alloc(cesa_dev->dma->cache_pool, flags,
+ &dreq->cache_dma);
+ if (!creq->cache)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static inline int mv_cesa_ahash_std_alloc_cache(struct mv_cesa_ahash_req *creq,
+ gfp_t flags)
+{
+ creq->cache = kzalloc(CESA_MAX_HASH_BLOCK_SIZE, flags);
+ if (!creq->cache)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int mv_cesa_ahash_alloc_cache(struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ int ret;
+
+ if (creq->cache)
+ return 0;
+
+ if (creq->req.base.type == CESA_DMA_REQ)
+ ret = mv_cesa_ahash_dma_alloc_cache(creq, flags);
+ else
+ ret = mv_cesa_ahash_std_alloc_cache(creq, flags);
+
+ return ret;
+}
+
+static inline void mv_cesa_ahash_dma_free_cache(struct mv_cesa_ahash_req *creq)
+{
+ dma_pool_free(cesa_dev->dma->cache_pool, creq->cache,
+ creq->req.dma.cache_dma);
+}
+
+static inline void mv_cesa_ahash_std_free_cache(struct mv_cesa_ahash_req *creq)
+{
+ kfree(creq->cache);
+}
+
+static void mv_cesa_ahash_free_cache(struct mv_cesa_ahash_req *creq)
+{
+ if (!creq->cache)
+ return;
+
+ if (creq->req.base.type == CESA_DMA_REQ)
+ mv_cesa_ahash_dma_free_cache(creq);
+ else
+ mv_cesa_ahash_std_free_cache(creq);
+
+ creq->cache = NULL;
+}
+
+static int mv_cesa_ahash_dma_alloc_padding(struct mv_cesa_ahash_dma_req *req,
+ gfp_t flags)
+{
+ if (req->padding)
+ return 0;
+
+ req->padding = dma_pool_alloc(cesa_dev->dma->padding_pool, flags,
+ &req->padding_dma);
+ if (!req->padding)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void mv_cesa_ahash_dma_free_padding(struct mv_cesa_ahash_dma_req *req)
+{
+ if (!req->padding)
+ return;
+
+ dma_pool_free(cesa_dev->dma->padding_pool, req->padding,
+ req->padding_dma);
+ req->padding = NULL;
+}
+
+static inline void mv_cesa_ahash_dma_last_cleanup(struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+
+ mv_cesa_ahash_dma_free_padding(&creq->req.dma);
+}
+
+static inline void mv_cesa_ahash_dma_cleanup(struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+
+ dma_unmap_sg(cesa_dev->dev, req->src, creq->src_nents, DMA_TO_DEVICE);
+ mv_cesa_dma_cleanup(&creq->req.dma.base);
+}
+
+static inline void mv_cesa_ahash_cleanup(struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+
+ if (creq->req.base.type == CESA_DMA_REQ)
+ mv_cesa_ahash_dma_cleanup(req);
+}
+
+static void mv_cesa_ahash_last_cleanup(struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+
+ mv_cesa_ahash_free_cache(creq);
+
+ if (creq->req.base.type == CESA_DMA_REQ)
+ mv_cesa_ahash_dma_last_cleanup(req);
+}
+
+static int mv_cesa_ahash_pad_len(struct mv_cesa_ahash_req *creq)
+{
+ unsigned int index, padlen;
+
+ index = creq->len & CESA_HASH_BLOCK_SIZE_MSK;
+ padlen = (index < 56) ? (56 - index) : (64 + 56 - index);
+
+ return padlen;
+}
+
+static int mv_cesa_ahash_pad_req(struct mv_cesa_ahash_req *creq, u8 *buf)
+{
+ __be64 bits = cpu_to_be64(creq->len << 3);
+ unsigned int index, padlen;
+
+ buf[0] = 0x80;
+ /* Pad out to 56 mod 64 */
+ index = creq->len & CESA_HASH_BLOCK_SIZE_MSK;
+ padlen = mv_cesa_ahash_pad_len(creq);
+ memset(buf + 1, 0, padlen - 1);
+ memcpy(buf + padlen, &bits, sizeof(bits));
+
+ return padlen + 8;
+}
+
+static void mv_cesa_ahash_std_step(struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ struct mv_cesa_ahash_std_req *sreq = &creq->req.std;
+ struct mv_cesa_engine *engine = sreq->base.engine;
+ struct mv_cesa_op_ctx *op;
+ unsigned int new_cache_ptr = 0;
+ u32 frag_mode;
+ size_t len;
+
+ if (creq->cache_ptr)
+ memcpy(engine->sram + CESA_SA_DATA_SRAM_OFFSET, creq->cache,
+ creq->cache_ptr);
+
+ len = min_t(size_t, req->nbytes + creq->cache_ptr - sreq->offset,
+ CESA_SA_SRAM_PAYLOAD_SIZE);
+
+ if (!creq->last_req) {
+ new_cache_ptr = len & CESA_HASH_BLOCK_SIZE_MSK;
+ len &= ~CESA_HASH_BLOCK_SIZE_MSK;
+ }
+
+ if (len - creq->cache_ptr)
+ sreq->offset += sg_pcopy_to_buffer(req->src, creq->src_nents,
+ engine->sram +
+ CESA_SA_DATA_SRAM_OFFSET +
+ creq->cache_ptr,
+ len - creq->cache_ptr,
+ sreq->offset);
+
+ op = &creq->op_tmpl;
+
+ frag_mode = mv_cesa_get_op_cfg(op) & CESA_SA_DESC_CFG_FRAG_MSK;
+
+ if (creq->last_req && sreq->offset == req->nbytes &&
+ creq->len <= CESA_SA_DESC_MAC_SRC_TOTAL_LEN_MAX) {
+ if (frag_mode == CESA_SA_DESC_CFG_FIRST_FRAG)
+ frag_mode = CESA_SA_DESC_CFG_NOT_FRAG;
+ else if (frag_mode == CESA_SA_DESC_CFG_MID_FRAG)
+ frag_mode = CESA_SA_DESC_CFG_LAST_FRAG;
+ }
+
+ if (frag_mode == CESA_SA_DESC_CFG_NOT_FRAG ||
+ frag_mode == CESA_SA_DESC_CFG_LAST_FRAG) {
+ if (len &&
+ creq->len <= CESA_SA_DESC_MAC_SRC_TOTAL_LEN_MAX) {
+ mv_cesa_set_mac_op_total_len(op, creq->len);
+ } else {
+ int trailerlen = mv_cesa_ahash_pad_len(creq) + 8;
+
+ if (len + trailerlen > CESA_SA_SRAM_PAYLOAD_SIZE) {
+ len &= CESA_HASH_BLOCK_SIZE_MSK;
+ new_cache_ptr = 64 - trailerlen;
+ memcpy(creq->cache,
+ engine->sram +
+ CESA_SA_DATA_SRAM_OFFSET + len,
+ new_cache_ptr);
+ } else {
+ len += mv_cesa_ahash_pad_req(creq,
+ engine->sram + len +
+ CESA_SA_DATA_SRAM_OFFSET);
+ }
+
+ if (frag_mode == CESA_SA_DESC_CFG_LAST_FRAG)
+ frag_mode = CESA_SA_DESC_CFG_MID_FRAG;
+ else
+ frag_mode = CESA_SA_DESC_CFG_FIRST_FRAG;
+ }
+ }
+
+ mv_cesa_set_mac_op_frag_len(op, len);
+ mv_cesa_update_op_cfg(op, frag_mode, CESA_SA_DESC_CFG_FRAG_MSK);
+
+ /* FIXME: only update enc_len field */
+ memcpy(engine->sram, op, sizeof(*op));
+
+ if (frag_mode == CESA_SA_DESC_CFG_FIRST_FRAG)
+ mv_cesa_update_op_cfg(op, CESA_SA_DESC_CFG_MID_FRAG,
+ CESA_SA_DESC_CFG_FRAG_MSK);
+
+ creq->cache_ptr = new_cache_ptr;
+
+ mv_cesa_set_int_mask(engine, CESA_SA_INT_ACCEL0_DONE);
+ writel(CESA_SA_CFG_PARA_DIS, engine->regs + CESA_SA_CFG);
+ writel(CESA_SA_CMD_EN_CESA_SA_ACCL0, engine->regs + CESA_SA_CMD);
+}
+
+static int mv_cesa_ahash_std_process(struct ahash_request *req, u32 status)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ struct mv_cesa_ahash_std_req *sreq = &creq->req.std;
+
+ if (sreq->offset < (req->nbytes - creq->cache_ptr))
+ return -EINPROGRESS;
+
+ return 0;
+}
+
+static inline void mv_cesa_ahash_dma_prepare(struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ struct mv_cesa_tdma_req *dreq = &creq->req.dma.base;
+
+ mv_cesa_dma_prepare(dreq, dreq->base.engine);
+}
+
+static void mv_cesa_ahash_std_prepare(struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ struct mv_cesa_ahash_std_req *sreq = &creq->req.std;
+ struct mv_cesa_engine *engine = sreq->base.engine;
+
+ sreq->offset = 0;
+ mv_cesa_adjust_op(engine, &creq->op_tmpl);
+ memcpy(engine->sram, &creq->op_tmpl, sizeof(creq->op_tmpl));
+}
+
+static void mv_cesa_ahash_step(struct crypto_async_request *req)
+{
+ struct ahash_request *ahashreq = ahash_request_cast(req);
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq);
+
+ if (creq->req.base.type == CESA_DMA_REQ)
+ mv_cesa_dma_step(&creq->req.dma.base);
+ else
+ mv_cesa_ahash_std_step(ahashreq);
+}
+
+static int mv_cesa_ahash_process(struct crypto_async_request *req, u32 status)
+{
+ struct ahash_request *ahashreq = ahash_request_cast(req);
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq);
+ struct mv_cesa_engine *engine = creq->req.base.engine;
+ unsigned int digsize;
+ int ret, i;
+
+ if (creq->req.base.type == CESA_DMA_REQ)
+ ret = mv_cesa_dma_process(&creq->req.dma.base, status);
+ else
+ ret = mv_cesa_ahash_std_process(ahashreq, status);
+
+ if (ret == -EINPROGRESS)
+ return ret;
+
+ digsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(ahashreq));
+ for (i = 0; i < digsize / 4; i++)
+ creq->state[i] = readl(engine->regs + CESA_IVDIG(i));
+
+ if (creq->cache_ptr)
+ sg_pcopy_to_buffer(ahashreq->src, creq->src_nents,
+ creq->cache,
+ creq->cache_ptr,
+ ahashreq->nbytes - creq->cache_ptr);
+
+ if (creq->last_req) {
+ for (i = 0; i < digsize / 4; i++) {
+ /*
+ * Hardware provides MD5 digest in a different
+ * endianness than SHA-1 and SHA-256 ones.
+ */
+ if (digsize == MD5_DIGEST_SIZE)
+ creq->state[i] = cpu_to_le32(creq->state[i]);
+ else
+ creq->state[i] = cpu_to_be32(creq->state[i]);
+ }
+
+ memcpy(ahashreq->result, creq->state, digsize);
+ }
+
+ return ret;
+}
+
+static void mv_cesa_ahash_prepare(struct crypto_async_request *req,
+ struct mv_cesa_engine *engine)
+{
+ struct ahash_request *ahashreq = ahash_request_cast(req);
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq);
+ unsigned int digsize;
+ int i;
+
+ creq->req.base.engine = engine;
+
+ if (creq->req.base.type == CESA_DMA_REQ)
+ mv_cesa_ahash_dma_prepare(ahashreq);
+ else
+ mv_cesa_ahash_std_prepare(ahashreq);
+
+ digsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(ahashreq));
+ for (i = 0; i < digsize / 4; i++)
+ writel(creq->state[i],
+ engine->regs + CESA_IVDIG(i));
+}
+
+static void mv_cesa_ahash_req_cleanup(struct crypto_async_request *req)
+{
+ struct ahash_request *ahashreq = ahash_request_cast(req);
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq);
+
+ if (creq->last_req)
+ mv_cesa_ahash_last_cleanup(ahashreq);
+
+ mv_cesa_ahash_cleanup(ahashreq);
+}
+
+static const struct mv_cesa_req_ops mv_cesa_ahash_req_ops = {
+ .step = mv_cesa_ahash_step,
+ .process = mv_cesa_ahash_process,
+ .prepare = mv_cesa_ahash_prepare,
+ .cleanup = mv_cesa_ahash_req_cleanup,
+};
+
+static int mv_cesa_ahash_init(struct ahash_request *req,
+ struct mv_cesa_op_ctx *tmpl)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+
+ memset(creq, 0, sizeof(*creq));
+ mv_cesa_update_op_cfg(tmpl,
+ CESA_SA_DESC_CFG_OP_MAC_ONLY |
+ CESA_SA_DESC_CFG_FIRST_FRAG,
+ CESA_SA_DESC_CFG_OP_MSK |
+ CESA_SA_DESC_CFG_FRAG_MSK);
+ mv_cesa_set_mac_op_total_len(tmpl, 0);
+ mv_cesa_set_mac_op_frag_len(tmpl, 0);
+ creq->op_tmpl = *tmpl;
+ creq->len = 0;
+
+ return 0;
+}
+
+static inline int mv_cesa_ahash_cra_init(struct crypto_tfm *tfm)
+{
+ struct mv_cesa_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ ctx->base.ops = &mv_cesa_ahash_req_ops;
+
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct mv_cesa_ahash_req));
+ return 0;
+}
+
+static int mv_cesa_ahash_cache_req(struct ahash_request *req, bool *cached)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ int ret;
+
+ if (((creq->cache_ptr + req->nbytes) & CESA_HASH_BLOCK_SIZE_MSK) &&
+ !creq->last_req) {
+ ret = mv_cesa_ahash_alloc_cache(req);
+ if (ret)
+ return ret;
+ }
+
+ if (creq->cache_ptr + req->nbytes < 64 && !creq->last_req) {
+ *cached = true;
+
+ if (!req->nbytes)
+ return 0;
+
+ sg_pcopy_to_buffer(req->src, creq->src_nents,
+ creq->cache + creq->cache_ptr,
+ req->nbytes, 0);
+
+ creq->cache_ptr += req->nbytes;
+ }
+
+ return 0;
+}
+
+static struct mv_cesa_op_ctx *
+mv_cesa_ahash_dma_add_cache(struct mv_cesa_tdma_chain *chain,
+ struct mv_cesa_ahash_dma_iter *dma_iter,
+ struct mv_cesa_ahash_req *creq,
+ gfp_t flags)
+{
+ struct mv_cesa_ahash_dma_req *ahashdreq = &creq->req.dma;
+ struct mv_cesa_op_ctx *op = NULL;
+ int ret;
+
+ if (!creq->cache_ptr)
+ return NULL;
+
+ ret = mv_cesa_dma_add_data_transfer(chain,
+ CESA_SA_DATA_SRAM_OFFSET,
+ ahashdreq->cache_dma,
+ creq->cache_ptr,
+ CESA_TDMA_DST_IN_SRAM,
+ flags);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (!dma_iter->base.op_len) {
+ op = mv_cesa_dma_add_op(chain, &creq->op_tmpl, false, flags);
+ if (IS_ERR(op))
+ return op;
+
+ mv_cesa_set_mac_op_frag_len(op, creq->cache_ptr);
+
+ /* Add dummy desc to launch crypto operation */
+ ret = mv_cesa_dma_add_dummy_launch(chain, flags);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+
+ return op;
+}
+
+static struct mv_cesa_op_ctx *
+mv_cesa_ahash_dma_add_data(struct mv_cesa_tdma_chain *chain,
+ struct mv_cesa_ahash_dma_iter *dma_iter,
+ struct mv_cesa_ahash_req *creq,
+ gfp_t flags)
+{
+ struct mv_cesa_op_ctx *op;
+ int ret;
+
+ op = mv_cesa_dma_add_op(chain, &creq->op_tmpl, false, flags);
+ if (IS_ERR(op))
+ return op;
+
+ mv_cesa_set_mac_op_frag_len(op, dma_iter->base.op_len);
+
+ if ((mv_cesa_get_op_cfg(&creq->op_tmpl) & CESA_SA_DESC_CFG_FRAG_MSK) ==
+ CESA_SA_DESC_CFG_FIRST_FRAG)
+ mv_cesa_update_op_cfg(&creq->op_tmpl,
+ CESA_SA_DESC_CFG_MID_FRAG,
+ CESA_SA_DESC_CFG_FRAG_MSK);
+
+ /* Add input transfers */
+ ret = mv_cesa_dma_add_op_transfers(chain, &dma_iter->base,
+ &dma_iter->src, flags);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /* Add dummy desc to launch crypto operation */
+ ret = mv_cesa_dma_add_dummy_launch(chain, flags);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return op;
+}
+
+static struct mv_cesa_op_ctx *
+mv_cesa_ahash_dma_last_req(struct mv_cesa_tdma_chain *chain,
+ struct mv_cesa_ahash_dma_iter *dma_iter,
+ struct mv_cesa_ahash_req *creq,
+ struct mv_cesa_op_ctx *op,
+ gfp_t flags)
+{
+ struct mv_cesa_ahash_dma_req *ahashdreq = &creq->req.dma;
+ unsigned int len, trailerlen, padoff = 0;
+ int ret;
+
+ if (!creq->last_req)
+ return op;
+
+ if (op && creq->len <= CESA_SA_DESC_MAC_SRC_TOTAL_LEN_MAX) {
+ u32 frag = CESA_SA_DESC_CFG_NOT_FRAG;
+
+ if ((mv_cesa_get_op_cfg(op) & CESA_SA_DESC_CFG_FRAG_MSK) !=
+ CESA_SA_DESC_CFG_FIRST_FRAG)
+ frag = CESA_SA_DESC_CFG_LAST_FRAG;
+
+ mv_cesa_update_op_cfg(op, frag, CESA_SA_DESC_CFG_FRAG_MSK);
+
+ return op;
+ }
+
+ ret = mv_cesa_ahash_dma_alloc_padding(ahashdreq, flags);
+ if (ret)
+ return ERR_PTR(ret);
+
+ trailerlen = mv_cesa_ahash_pad_req(creq, ahashdreq->padding);
+
+ if (op) {
+ len = min(CESA_SA_SRAM_PAYLOAD_SIZE - dma_iter->base.op_len,
+ trailerlen);
+ if (len) {
+ ret = mv_cesa_dma_add_data_transfer(chain,
+ CESA_SA_DATA_SRAM_OFFSET +
+ dma_iter->base.op_len,
+ ahashdreq->padding_dma,
+ len, CESA_TDMA_DST_IN_SRAM,
+ flags);
+ if (ret)
+ return ERR_PTR(ret);
+
+ mv_cesa_update_op_cfg(op, CESA_SA_DESC_CFG_MID_FRAG,
+ CESA_SA_DESC_CFG_FRAG_MSK);
+ mv_cesa_set_mac_op_frag_len(op,
+ dma_iter->base.op_len + len);
+ padoff += len;
+ }
+ }
+
+ if (padoff >= trailerlen)
+ return op;
+
+ if ((mv_cesa_get_op_cfg(&creq->op_tmpl) & CESA_SA_DESC_CFG_FRAG_MSK) !=
+ CESA_SA_DESC_CFG_FIRST_FRAG)
+ mv_cesa_update_op_cfg(&creq->op_tmpl,
+ CESA_SA_DESC_CFG_MID_FRAG,
+ CESA_SA_DESC_CFG_FRAG_MSK);
+
+ op = mv_cesa_dma_add_op(chain, &creq->op_tmpl, false, flags);
+ if (IS_ERR(op))
+ return op;
+
+ mv_cesa_set_mac_op_frag_len(op, trailerlen - padoff);
+
+ ret = mv_cesa_dma_add_data_transfer(chain,
+ CESA_SA_DATA_SRAM_OFFSET,
+ ahashdreq->padding_dma +
+ padoff,
+ trailerlen - padoff,
+ CESA_TDMA_DST_IN_SRAM,
+ flags);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /* Add dummy desc to launch crypto operation */
+ ret = mv_cesa_dma_add_dummy_launch(chain, flags);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return op;
+}
+
+static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
+ GFP_KERNEL : GFP_ATOMIC;
+ struct mv_cesa_ahash_dma_req *ahashdreq = &creq->req.dma;
+ struct mv_cesa_tdma_req *dreq = &ahashdreq->base;
+ struct mv_cesa_tdma_chain chain;
+ struct mv_cesa_ahash_dma_iter iter;
+ struct mv_cesa_op_ctx *op = NULL;
+ int ret;
+
+ dreq->chain.first = NULL;
+ dreq->chain.last = NULL;
+
+ if (creq->src_nents) {
+ ret = dma_map_sg(cesa_dev->dev, req->src, creq->src_nents,
+ DMA_TO_DEVICE);
+ if (!ret) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ }
+
+ mv_cesa_tdma_desc_iter_init(&chain);
+ mv_cesa_ahash_req_iter_init(&iter, req);
+
+ op = mv_cesa_ahash_dma_add_cache(&chain, &iter,
+ creq, flags);
+ if (IS_ERR(op)) {
+ ret = PTR_ERR(op);
+ goto err_free_tdma;
+ }
+
+ do {
+ if (!iter.base.op_len)
+ break;
+
+ op = mv_cesa_ahash_dma_add_data(&chain, &iter,
+ creq, flags);
+ if (IS_ERR(op)) {
+ ret = PTR_ERR(op);
+ goto err_free_tdma;
+ }
+ } while (mv_cesa_ahash_req_iter_next_op(&iter));
+
+ op = mv_cesa_ahash_dma_last_req(&chain, &iter, creq, op, flags);
+ if (IS_ERR(op)) {
+ ret = PTR_ERR(op);
+ goto err_free_tdma;
+ }
+
+ if (op) {
+ /* Add dummy desc to wait for crypto operation end */
+ ret = mv_cesa_dma_add_dummy_end(&chain, flags);
+ if (ret)
+ goto err_free_tdma;
+ }
+
+ if (!creq->last_req)
+ creq->cache_ptr = req->nbytes + creq->cache_ptr -
+ iter.base.len;
+ else
+ creq->cache_ptr = 0;
+
+ dreq->chain = chain;
+
+ return 0;
+
+err_free_tdma:
+ mv_cesa_dma_cleanup(dreq);
+ dma_unmap_sg(cesa_dev->dev, req->src, creq->src_nents, DMA_TO_DEVICE);
+
+err:
+ mv_cesa_ahash_last_cleanup(req);
+
+ return ret;
+}
+
+static int mv_cesa_ahash_req_init(struct ahash_request *req, bool *cached)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ int ret;
+
+ if (cesa_dev->caps->has_tdma)
+ creq->req.base.type = CESA_DMA_REQ;
+ else
+ creq->req.base.type = CESA_STD_REQ;
+
+ creq->src_nents = sg_nents_for_len(req->src, req->nbytes);
+
+ ret = mv_cesa_ahash_cache_req(req, cached);
+ if (ret)
+ return ret;
+
+ if (*cached)
+ return 0;
+
+ if (creq->req.base.type == CESA_DMA_REQ)
+ ret = mv_cesa_ahash_dma_req_init(req);
+
+ return ret;
+}
+
+static int mv_cesa_ahash_update(struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ bool cached = false;
+ int ret;
+
+ creq->len += req->nbytes;
+ ret = mv_cesa_ahash_req_init(req, &cached);
+ if (ret)
+ return ret;
+
+ if (cached)
+ return 0;
+
+ ret = mv_cesa_queue_req(&req->base);
+ if (ret && ret != -EINPROGRESS) {
+ mv_cesa_ahash_cleanup(req);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int mv_cesa_ahash_final(struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ struct mv_cesa_op_ctx *tmpl = &creq->op_tmpl;
+ bool cached = false;
+ int ret;
+
+ mv_cesa_set_mac_op_total_len(tmpl, creq->len);
+ creq->last_req = true;
+ req->nbytes = 0;
+
+ ret = mv_cesa_ahash_req_init(req, &cached);
+ if (ret)
+ return ret;
+
+ if (cached)
+ return 0;
+
+ ret = mv_cesa_queue_req(&req->base);
+ if (ret && ret != -EINPROGRESS)
+ mv_cesa_ahash_cleanup(req);
+
+ return ret;
+}
+
+static int mv_cesa_ahash_finup(struct ahash_request *req)
+{
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ struct mv_cesa_op_ctx *tmpl = &creq->op_tmpl;
+ bool cached = false;
+ int ret;
+
+ creq->len += req->nbytes;
+ mv_cesa_set_mac_op_total_len(tmpl, creq->len);
+ creq->last_req = true;
+
+ ret = mv_cesa_ahash_req_init(req, &cached);
+ if (ret)
+ return ret;
+
+ if (cached)
+ return 0;
+
+ ret = mv_cesa_queue_req(&req->base);
+ if (ret && ret != -EINPROGRESS)
+ mv_cesa_ahash_cleanup(req);
+
+ return ret;
+}
+
+static int mv_cesa_md5_init(struct ahash_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_MD5);
+
+ mv_cesa_ahash_init(req, &tmpl);
+
+ return 0;
+}
+
+static int mv_cesa_md5_export(struct ahash_request *req, void *out)
+{
+ struct md5_state *out_state = out;
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ unsigned int digsize = crypto_ahash_digestsize(ahash);
+
+ out_state->byte_count = creq->len;
+ memcpy(out_state->hash, creq->state, digsize);
+ memset(out_state->block, 0, sizeof(out_state->block));
+ if (creq->cache)
+ memcpy(out_state->block, creq->cache, creq->cache_ptr);
+
+ return 0;
+}
+
+static int mv_cesa_md5_import(struct ahash_request *req, const void *in)
+{
+ const struct md5_state *in_state = in;
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ unsigned int digsize = crypto_ahash_digestsize(ahash);
+ unsigned int cache_ptr;
+ int ret;
+
+ creq->len = in_state->byte_count;
+ memcpy(creq->state, in_state->hash, digsize);
+ creq->cache_ptr = 0;
+
+ cache_ptr = creq->len % sizeof(in_state->block);
+ if (!cache_ptr)
+ return 0;
+
+ ret = mv_cesa_ahash_alloc_cache(req);
+ if (ret)
+ return ret;
+
+ memcpy(creq->cache, in_state->block, cache_ptr);
+ creq->cache_ptr = cache_ptr;
+
+ return 0;
+}
+
+static int mv_cesa_md5_digest(struct ahash_request *req)
+{
+ int ret;
+
+ ret = mv_cesa_md5_init(req);
+ if (ret)
+ return ret;
+
+ return mv_cesa_ahash_finup(req);
+}
+
+struct ahash_alg mv_md5_alg = {
+ .init = mv_cesa_md5_init,
+ .update = mv_cesa_ahash_update,
+ .final = mv_cesa_ahash_final,
+ .finup = mv_cesa_ahash_finup,
+ .digest = mv_cesa_md5_digest,
+ .export = mv_cesa_md5_export,
+ .import = mv_cesa_md5_import,
+ .halg = {
+ .digestsize = MD5_DIGEST_SIZE,
+ .base = {
+ .cra_name = "md5",
+ .cra_driver_name = "mv-md5",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = MD5_HMAC_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mv_cesa_hash_ctx),
+ .cra_init = mv_cesa_ahash_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+};
+
+static int mv_cesa_sha1_init(struct ahash_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_SHA1);
+
+ mv_cesa_ahash_init(req, &tmpl);
+
+ return 0;
+}
+
+static int mv_cesa_sha1_export(struct ahash_request *req, void *out)
+{
+ struct sha1_state *out_state = out;
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ unsigned int digsize = crypto_ahash_digestsize(ahash);
+
+ out_state->count = creq->len;
+ memcpy(out_state->state, creq->state, digsize);
+ memset(out_state->buffer, 0, sizeof(out_state->buffer));
+ if (creq->cache)
+ memcpy(out_state->buffer, creq->cache, creq->cache_ptr);
+
+ return 0;
+}
+
+static int mv_cesa_sha1_import(struct ahash_request *req, const void *in)
+{
+ const struct sha1_state *in_state = in;
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ unsigned int digsize = crypto_ahash_digestsize(ahash);
+ unsigned int cache_ptr;
+ int ret;
+
+ creq->len = in_state->count;
+ memcpy(creq->state, in_state->state, digsize);
+ creq->cache_ptr = 0;
+
+ cache_ptr = creq->len % SHA1_BLOCK_SIZE;
+ if (!cache_ptr)
+ return 0;
+
+ ret = mv_cesa_ahash_alloc_cache(req);
+ if (ret)
+ return ret;
+
+ memcpy(creq->cache, in_state->buffer, cache_ptr);
+ creq->cache_ptr = cache_ptr;
+
+ return 0;
+}
+
+static int mv_cesa_sha1_digest(struct ahash_request *req)
+{
+ int ret;
+
+ ret = mv_cesa_sha1_init(req);
+ if (ret)
+ return ret;
+
+ return mv_cesa_ahash_finup(req);
+}
+
+struct ahash_alg mv_sha1_alg = {
+ .init = mv_cesa_sha1_init,
+ .update = mv_cesa_ahash_update,
+ .final = mv_cesa_ahash_final,
+ .finup = mv_cesa_ahash_finup,
+ .digest = mv_cesa_sha1_digest,
+ .export = mv_cesa_sha1_export,
+ .import = mv_cesa_sha1_import,
+ .halg = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .base = {
+ .cra_name = "sha1",
+ .cra_driver_name = "mv-sha1",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mv_cesa_hash_ctx),
+ .cra_init = mv_cesa_ahash_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+};
+
+static int mv_cesa_sha256_init(struct ahash_request *req)
+{
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_SHA256);
+
+ mv_cesa_ahash_init(req, &tmpl);
+
+ return 0;
+}
+
+static int mv_cesa_sha256_digest(struct ahash_request *req)
+{
+ int ret;
+
+ ret = mv_cesa_sha256_init(req);
+ if (ret)
+ return ret;
+
+ return mv_cesa_ahash_finup(req);
+}
+
+static int mv_cesa_sha256_export(struct ahash_request *req, void *out)
+{
+ struct sha256_state *out_state = out;
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ unsigned int ds = crypto_ahash_digestsize(ahash);
+
+ out_state->count = creq->len;
+ memcpy(out_state->state, creq->state, ds);
+ memset(out_state->buf, 0, sizeof(out_state->buf));
+ if (creq->cache)
+ memcpy(out_state->buf, creq->cache, creq->cache_ptr);
+
+ return 0;
+}
+
+static int mv_cesa_sha256_import(struct ahash_request *req, const void *in)
+{
+ const struct sha256_state *in_state = in;
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
+ unsigned int digsize = crypto_ahash_digestsize(ahash);
+ unsigned int cache_ptr;
+ int ret;
+
+ creq->len = in_state->count;
+ memcpy(creq->state, in_state->state, digsize);
+ creq->cache_ptr = 0;
+
+ cache_ptr = creq->len % SHA256_BLOCK_SIZE;
+ if (!cache_ptr)
+ return 0;
+
+ ret = mv_cesa_ahash_alloc_cache(req);
+ if (ret)
+ return ret;
+
+ memcpy(creq->cache, in_state->buf, cache_ptr);
+ creq->cache_ptr = cache_ptr;
+
+ return 0;
+}
+
+struct ahash_alg mv_sha256_alg = {
+ .init = mv_cesa_sha256_init,
+ .update = mv_cesa_ahash_update,
+ .final = mv_cesa_ahash_final,
+ .finup = mv_cesa_ahash_finup,
+ .digest = mv_cesa_sha256_digest,
+ .export = mv_cesa_sha256_export,
+ .import = mv_cesa_sha256_import,
+ .halg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "mv-sha256",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mv_cesa_hash_ctx),
+ .cra_init = mv_cesa_ahash_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+};
+
+struct mv_cesa_ahash_result {
+ struct completion completion;
+ int error;
+};
+
+static void mv_cesa_hmac_ahash_complete(struct crypto_async_request *req,
+ int error)
+{
+ struct mv_cesa_ahash_result *result = req->data;
+
+ if (error == -EINPROGRESS)
+ return;
+
+ result->error = error;
+ complete(&result->completion);
+}
+
+static int mv_cesa_ahmac_iv_state_init(struct ahash_request *req, u8 *pad,
+ void *state, unsigned int blocksize)
+{
+ struct mv_cesa_ahash_result result;
+ struct scatterlist sg;
+ int ret;
+
+ ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ mv_cesa_hmac_ahash_complete, &result);
+ sg_init_one(&sg, pad, blocksize);
+ ahash_request_set_crypt(req, &sg, pad, blocksize);
+ init_completion(&result.completion);
+
+ ret = crypto_ahash_init(req);
+ if (ret)
+ return ret;
+
+ ret = crypto_ahash_update(req);
+ if (ret && ret != -EINPROGRESS)
+ return ret;
+
+ wait_for_completion_interruptible(&result.completion);
+ if (result.error)
+ return result.error;
+
+ ret = crypto_ahash_export(req, state);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mv_cesa_ahmac_pad_init(struct ahash_request *req,
+ const u8 *key, unsigned int keylen,
+ u8 *ipad, u8 *opad,
+ unsigned int blocksize)
+{
+ struct mv_cesa_ahash_result result;
+ struct scatterlist sg;
+ int ret;
+ int i;
+
+ if (keylen <= blocksize) {
+ memcpy(ipad, key, keylen);
+ } else {
+ u8 *keydup = kmemdup(key, keylen, GFP_KERNEL);
+
+ if (!keydup)
+ return -ENOMEM;
+
+ ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ mv_cesa_hmac_ahash_complete,
+ &result);
+ sg_init_one(&sg, keydup, keylen);
+ ahash_request_set_crypt(req, &sg, ipad, keylen);
+ init_completion(&result.completion);
+
+ ret = crypto_ahash_digest(req);
+ if (ret == -EINPROGRESS) {
+ wait_for_completion_interruptible(&result.completion);
+ ret = result.error;
+ }
+
+ /* Set the memory region to 0 to avoid any leak. */
+ memset(keydup, 0, keylen);
+ kfree(keydup);
+
+ if (ret)
+ return ret;
+
+ keylen = crypto_ahash_digestsize(crypto_ahash_reqtfm(req));
+ }
+
+ memset(ipad + keylen, 0, blocksize - keylen);
+ memcpy(opad, ipad, blocksize);
+
+ for (i = 0; i < blocksize; i++) {
+ ipad[i] ^= 0x36;
+ opad[i] ^= 0x5c;
+ }
+
+ return 0;
+}
+
+static int mv_cesa_ahmac_setkey(const char *hash_alg_name,
+ const u8 *key, unsigned int keylen,
+ void *istate, void *ostate)
+{
+ struct ahash_request *req;
+ struct crypto_ahash *tfm;
+ unsigned int blocksize;
+ u8 *ipad = NULL;
+ u8 *opad;
+ int ret;
+
+ tfm = crypto_alloc_ahash(hash_alg_name, CRYPTO_ALG_TYPE_AHASH,
+ CRYPTO_ALG_TYPE_AHASH_MASK);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ req = ahash_request_alloc(tfm, GFP_KERNEL);
+ if (!req) {
+ ret = -ENOMEM;
+ goto free_ahash;
+ }
+
+ crypto_ahash_clear_flags(tfm, ~0);
+
+ blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
+
+ ipad = kzalloc(2 * blocksize, GFP_KERNEL);
+ if (!ipad) {
+ ret = -ENOMEM;
+ goto free_req;
+ }
+
+ opad = ipad + blocksize;
+
+ ret = mv_cesa_ahmac_pad_init(req, key, keylen, ipad, opad, blocksize);
+ if (ret)
+ goto free_ipad;
+
+ ret = mv_cesa_ahmac_iv_state_init(req, ipad, istate, blocksize);
+ if (ret)
+ goto free_ipad;
+
+ ret = mv_cesa_ahmac_iv_state_init(req, opad, ostate, blocksize);
+
+free_ipad:
+ kfree(ipad);
+free_req:
+ ahash_request_free(req);
+free_ahash:
+ crypto_free_ahash(tfm);
+
+ return ret;
+}
+
+static int mv_cesa_ahmac_cra_init(struct crypto_tfm *tfm)
+{
+ struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ ctx->base.ops = &mv_cesa_ahash_req_ops;
+
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct mv_cesa_ahash_req));
+ return 0;
+}
+
+static int mv_cesa_ahmac_md5_init(struct ahash_request *req)
+{
+ struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_HMAC_MD5);
+ memcpy(tmpl.ctx.hash.iv, ctx->iv, sizeof(ctx->iv));
+
+ mv_cesa_ahash_init(req, &tmpl);
+
+ return 0;
+}
+
+static int mv_cesa_ahmac_md5_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
+ struct md5_state istate, ostate;
+ int ret, i;
+
+ ret = mv_cesa_ahmac_setkey("mv-md5", key, keylen, &istate, &ostate);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(istate.hash); i++)
+ ctx->iv[i] = be32_to_cpu(istate.hash[i]);
+
+ for (i = 0; i < ARRAY_SIZE(ostate.hash); i++)
+ ctx->iv[i + 8] = be32_to_cpu(ostate.hash[i]);
+
+ return 0;
+}
+
+static int mv_cesa_ahmac_md5_digest(struct ahash_request *req)
+{
+ int ret;
+
+ ret = mv_cesa_ahmac_md5_init(req);
+ if (ret)
+ return ret;
+
+ return mv_cesa_ahash_finup(req);
+}
+
+struct ahash_alg mv_ahmac_md5_alg = {
+ .init = mv_cesa_ahmac_md5_init,
+ .update = mv_cesa_ahash_update,
+ .final = mv_cesa_ahash_final,
+ .finup = mv_cesa_ahash_finup,
+ .digest = mv_cesa_ahmac_md5_digest,
+ .setkey = mv_cesa_ahmac_md5_setkey,
+ .export = mv_cesa_md5_export,
+ .import = mv_cesa_md5_import,
+ .halg = {
+ .digestsize = MD5_DIGEST_SIZE,
+ .statesize = sizeof(struct md5_state),
+ .base = {
+ .cra_name = "hmac(md5)",
+ .cra_driver_name = "mv-hmac-md5",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = MD5_HMAC_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mv_cesa_hmac_ctx),
+ .cra_init = mv_cesa_ahmac_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+};
+
+static int mv_cesa_ahmac_sha1_init(struct ahash_request *req)
+{
+ struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_HMAC_SHA1);
+ memcpy(tmpl.ctx.hash.iv, ctx->iv, sizeof(ctx->iv));
+
+ mv_cesa_ahash_init(req, &tmpl);
+
+ return 0;
+}
+
+static int mv_cesa_ahmac_sha1_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
+ struct sha1_state istate, ostate;
+ int ret, i;
+
+ ret = mv_cesa_ahmac_setkey("mv-sha1", key, keylen, &istate, &ostate);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(istate.state); i++)
+ ctx->iv[i] = be32_to_cpu(istate.state[i]);
+
+ for (i = 0; i < ARRAY_SIZE(ostate.state); i++)
+ ctx->iv[i + 8] = be32_to_cpu(ostate.state[i]);
+
+ return 0;
+}
+
+static int mv_cesa_ahmac_sha1_digest(struct ahash_request *req)
+{
+ int ret;
+
+ ret = mv_cesa_ahmac_sha1_init(req);
+ if (ret)
+ return ret;
+
+ return mv_cesa_ahash_finup(req);
+}
+
+struct ahash_alg mv_ahmac_sha1_alg = {
+ .init = mv_cesa_ahmac_sha1_init,
+ .update = mv_cesa_ahash_update,
+ .final = mv_cesa_ahash_final,
+ .finup = mv_cesa_ahash_finup,
+ .digest = mv_cesa_ahmac_sha1_digest,
+ .setkey = mv_cesa_ahmac_sha1_setkey,
+ .export = mv_cesa_sha1_export,
+ .import = mv_cesa_sha1_import,
+ .halg = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .statesize = sizeof(struct sha1_state),
+ .base = {
+ .cra_name = "hmac(sha1)",
+ .cra_driver_name = "mv-hmac-sha1",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mv_cesa_hmac_ctx),
+ .cra_init = mv_cesa_ahmac_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+};
+
+static int mv_cesa_ahmac_sha256_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
+ struct sha256_state istate, ostate;
+ int ret, i;
+
+ ret = mv_cesa_ahmac_setkey("mv-sha256", key, keylen, &istate, &ostate);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(istate.state); i++)
+ ctx->iv[i] = be32_to_cpu(istate.state[i]);
+
+ for (i = 0; i < ARRAY_SIZE(ostate.state); i++)
+ ctx->iv[i + 8] = be32_to_cpu(ostate.state[i]);
+
+ return 0;
+}
+
+static int mv_cesa_ahmac_sha256_init(struct ahash_request *req)
+{
+ struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ struct mv_cesa_op_ctx tmpl;
+
+ mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_HMAC_SHA256);
+ memcpy(tmpl.ctx.hash.iv, ctx->iv, sizeof(ctx->iv));
+
+ mv_cesa_ahash_init(req, &tmpl);
+
+ return 0;
+}
+
+static int mv_cesa_ahmac_sha256_digest(struct ahash_request *req)
+{
+ int ret;
+
+ ret = mv_cesa_ahmac_sha256_init(req);
+ if (ret)
+ return ret;
+
+ return mv_cesa_ahash_finup(req);
+}
+
+struct ahash_alg mv_ahmac_sha256_alg = {
+ .init = mv_cesa_ahmac_sha256_init,
+ .update = mv_cesa_ahash_update,
+ .final = mv_cesa_ahash_final,
+ .finup = mv_cesa_ahash_finup,
+ .digest = mv_cesa_ahmac_sha256_digest,
+ .setkey = mv_cesa_ahmac_sha256_setkey,
+ .export = mv_cesa_sha256_export,
+ .import = mv_cesa_sha256_import,
+ .halg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .statesize = sizeof(struct sha256_state),
+ .base = {
+ .cra_name = "hmac(sha256)",
+ .cra_driver_name = "mv-hmac-sha256",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct mv_cesa_hmac_ctx),
+ .cra_init = mv_cesa_ahmac_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+};
diff --git a/drivers/crypto/marvell/tdma.c b/drivers/crypto/marvell/tdma.c
new file mode 100644
index 000000000000..64a366c50174
--- /dev/null
+++ b/drivers/crypto/marvell/tdma.c
@@ -0,0 +1,224 @@
+/*
+ * Provide TDMA helper functions used by cipher and hash algorithm
+ * implementations.
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ * Author: Arnaud Ebalard <arno@natisbad.org>
+ *
+ * This work is based on an initial version written by
+ * Sebastian Andrzej Siewior < sebastian at breakpoint dot cc >
+ *
+ * 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 "cesa.h"
+
+bool mv_cesa_req_dma_iter_next_transfer(struct mv_cesa_dma_iter *iter,
+ struct mv_cesa_sg_dma_iter *sgiter,
+ unsigned int len)
+{
+ if (!sgiter->sg)
+ return false;
+
+ sgiter->op_offset += len;
+ sgiter->offset += len;
+ if (sgiter->offset == sg_dma_len(sgiter->sg)) {
+ if (sg_is_last(sgiter->sg))
+ return false;
+ sgiter->offset = 0;
+ sgiter->sg = sg_next(sgiter->sg);
+ }
+
+ if (sgiter->op_offset == iter->op_len)
+ return false;
+
+ return true;
+}
+
+void mv_cesa_dma_step(struct mv_cesa_tdma_req *dreq)
+{
+ struct mv_cesa_engine *engine = dreq->base.engine;
+
+ writel(0, engine->regs + CESA_SA_CFG);
+
+ mv_cesa_set_int_mask(engine, CESA_SA_INT_ACC0_IDMA_DONE);
+ writel(CESA_TDMA_DST_BURST_128B | CESA_TDMA_SRC_BURST_128B |
+ CESA_TDMA_NO_BYTE_SWAP | CESA_TDMA_EN,
+ engine->regs + CESA_TDMA_CONTROL);
+
+ writel(CESA_SA_CFG_ACT_CH0_IDMA | CESA_SA_CFG_MULTI_PKT |
+ CESA_SA_CFG_CH0_W_IDMA | CESA_SA_CFG_PARA_DIS,
+ engine->regs + CESA_SA_CFG);
+ writel(dreq->chain.first->cur_dma,
+ engine->regs + CESA_TDMA_NEXT_ADDR);
+ writel(CESA_SA_CMD_EN_CESA_SA_ACCL0, engine->regs + CESA_SA_CMD);
+}
+
+void mv_cesa_dma_cleanup(struct mv_cesa_tdma_req *dreq)
+{
+ struct mv_cesa_tdma_desc *tdma;
+
+ for (tdma = dreq->chain.first; tdma;) {
+ struct mv_cesa_tdma_desc *old_tdma = tdma;
+
+ if (tdma->flags & CESA_TDMA_OP)
+ dma_pool_free(cesa_dev->dma->op_pool, tdma->op,
+ le32_to_cpu(tdma->src));
+
+ tdma = tdma->next;
+ dma_pool_free(cesa_dev->dma->tdma_desc_pool, old_tdma,
+ le32_to_cpu(old_tdma->cur_dma));
+ }
+
+ dreq->chain.first = NULL;
+ dreq->chain.last = NULL;
+}
+
+void mv_cesa_dma_prepare(struct mv_cesa_tdma_req *dreq,
+ struct mv_cesa_engine *engine)
+{
+ struct mv_cesa_tdma_desc *tdma;
+
+ for (tdma = dreq->chain.first; tdma; tdma = tdma->next) {
+ if (tdma->flags & CESA_TDMA_DST_IN_SRAM)
+ tdma->dst = cpu_to_le32(tdma->dst + engine->sram_dma);
+
+ if (tdma->flags & CESA_TDMA_SRC_IN_SRAM)
+ tdma->src = cpu_to_le32(tdma->src + engine->sram_dma);
+
+ if (tdma->flags & CESA_TDMA_OP)
+ mv_cesa_adjust_op(engine, tdma->op);
+ }
+}
+
+static struct mv_cesa_tdma_desc *
+mv_cesa_dma_add_desc(struct mv_cesa_tdma_chain *chain, gfp_t flags)
+{
+ struct mv_cesa_tdma_desc *new_tdma = NULL;
+ dma_addr_t dma_handle;
+
+ new_tdma = dma_pool_alloc(cesa_dev->dma->tdma_desc_pool, flags,
+ &dma_handle);
+ if (!new_tdma)
+ return ERR_PTR(-ENOMEM);
+
+ memset(new_tdma, 0, sizeof(*new_tdma));
+ new_tdma->cur_dma = cpu_to_le32(dma_handle);
+ if (chain->last) {
+ chain->last->next_dma = new_tdma->cur_dma;
+ chain->last->next = new_tdma;
+ } else {
+ chain->first = new_tdma;
+ }
+
+ chain->last = new_tdma;
+
+ return new_tdma;
+}
+
+struct mv_cesa_op_ctx *mv_cesa_dma_add_op(struct mv_cesa_tdma_chain *chain,
+ const struct mv_cesa_op_ctx *op_templ,
+ bool skip_ctx,
+ gfp_t flags)
+{
+ struct mv_cesa_tdma_desc *tdma;
+ struct mv_cesa_op_ctx *op;
+ dma_addr_t dma_handle;
+
+ tdma = mv_cesa_dma_add_desc(chain, flags);
+ if (IS_ERR(tdma))
+ return ERR_CAST(tdma);
+
+ op = dma_pool_alloc(cesa_dev->dma->op_pool, flags, &dma_handle);
+ if (!op)
+ return ERR_PTR(-ENOMEM);
+
+ *op = *op_templ;
+
+ tdma = chain->last;
+ tdma->op = op;
+ tdma->byte_cnt = (skip_ctx ? sizeof(op->desc) : sizeof(*op)) | BIT(31);
+ tdma->src = dma_handle;
+ tdma->flags = CESA_TDMA_DST_IN_SRAM | CESA_TDMA_OP;
+
+ return op;
+}
+
+int mv_cesa_dma_add_data_transfer(struct mv_cesa_tdma_chain *chain,
+ dma_addr_t dst, dma_addr_t src, u32 size,
+ u32 flags, gfp_t gfp_flags)
+{
+ struct mv_cesa_tdma_desc *tdma;
+
+ tdma = mv_cesa_dma_add_desc(chain, gfp_flags);
+ if (IS_ERR(tdma))
+ return PTR_ERR(tdma);
+
+ tdma->byte_cnt = size | BIT(31);
+ tdma->src = src;
+ tdma->dst = dst;
+
+ flags &= (CESA_TDMA_DST_IN_SRAM | CESA_TDMA_SRC_IN_SRAM);
+ tdma->flags = flags | CESA_TDMA_DATA;
+
+ return 0;
+}
+
+int mv_cesa_dma_add_dummy_launch(struct mv_cesa_tdma_chain *chain,
+ u32 flags)
+{
+ struct mv_cesa_tdma_desc *tdma;
+
+ tdma = mv_cesa_dma_add_desc(chain, flags);
+ if (IS_ERR(tdma))
+ return PTR_ERR(tdma);
+
+ return 0;
+}
+
+int mv_cesa_dma_add_dummy_end(struct mv_cesa_tdma_chain *chain, u32 flags)
+{
+ struct mv_cesa_tdma_desc *tdma;
+
+ tdma = mv_cesa_dma_add_desc(chain, flags);
+ if (IS_ERR(tdma))
+ return PTR_ERR(tdma);
+
+ tdma->byte_cnt = BIT(31);
+
+ return 0;
+}
+
+int mv_cesa_dma_add_op_transfers(struct mv_cesa_tdma_chain *chain,
+ struct mv_cesa_dma_iter *dma_iter,
+ struct mv_cesa_sg_dma_iter *sgiter,
+ gfp_t gfp_flags)
+{
+ u32 flags = sgiter->dir == DMA_TO_DEVICE ?
+ CESA_TDMA_DST_IN_SRAM : CESA_TDMA_SRC_IN_SRAM;
+ unsigned int len;
+
+ do {
+ dma_addr_t dst, src;
+ int ret;
+
+ len = mv_cesa_req_dma_iter_transfer_len(dma_iter, sgiter);
+ if (sgiter->dir == DMA_TO_DEVICE) {
+ dst = CESA_SA_DATA_SRAM_OFFSET + sgiter->op_offset;
+ src = sg_dma_address(sgiter->sg) + sgiter->offset;
+ } else {
+ dst = sg_dma_address(sgiter->sg) + sgiter->offset;
+ src = CESA_SA_DATA_SRAM_OFFSET + sgiter->op_offset;
+ }
+
+ ret = mv_cesa_dma_add_data_transfer(chain, dst, src, len,
+ flags, gfp_flags);
+ if (ret)
+ return ret;
+
+ } while (mv_cesa_req_dma_iter_next_transfer(dma_iter, sgiter, len));
+
+ return 0;
+}
diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c
index f91f15ddee92..5bcd575fa96f 100644
--- a/drivers/crypto/mv_cesa.c
+++ b/drivers/crypto/mv_cesa.c
@@ -9,6 +9,7 @@
#include <crypto/aes.h>
#include <crypto/algapi.h>
#include <linux/crypto.h>
+#include <linux/genalloc.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kthread.h>
@@ -29,6 +30,8 @@
#define MAX_HW_HASH_SIZE 0xFFFF
#define MV_CESA_EXPIRE 500 /* msec */
+#define MV_CESA_DEFAULT_SRAM_SIZE 2048
+
/*
* STM:
* /---------------------------------------\
@@ -83,6 +86,8 @@ struct req_progress {
struct crypto_priv {
void __iomem *reg;
void __iomem *sram;
+ struct gen_pool *sram_pool;
+ dma_addr_t sram_dma;
int irq;
struct clk *clk;
struct task_struct *queue_th;
@@ -595,7 +600,7 @@ static int queue_manag(void *data)
cpg->eng_st = ENGINE_IDLE;
do {
struct crypto_async_request *async_req = NULL;
- struct crypto_async_request *backlog;
+ struct crypto_async_request *backlog = NULL;
__set_current_state(TASK_INTERRUPTIBLE);
@@ -1019,6 +1024,39 @@ static struct ahash_alg mv_hmac_sha1_alg = {
}
};
+static int mv_cesa_get_sram(struct platform_device *pdev,
+ struct crypto_priv *cp)
+{
+ struct resource *res;
+ u32 sram_size = MV_CESA_DEFAULT_SRAM_SIZE;
+
+ of_property_read_u32(pdev->dev.of_node, "marvell,crypto-sram-size",
+ &sram_size);
+
+ cp->sram_size = sram_size;
+ cp->sram_pool = of_get_named_gen_pool(pdev->dev.of_node,
+ "marvell,crypto-srams", 0);
+ if (cp->sram_pool) {
+ cp->sram = gen_pool_dma_alloc(cp->sram_pool, sram_size,
+ &cp->sram_dma);
+ if (cp->sram)
+ return 0;
+
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "sram");
+ if (!res || resource_size(res) < cp->sram_size)
+ return -EINVAL;
+
+ cp->sram = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(cp->sram))
+ return PTR_ERR(cp->sram);
+
+ return 0;
+}
+
static int mv_probe(struct platform_device *pdev)
{
struct crypto_priv *cp;
@@ -1041,24 +1079,17 @@ static int mv_probe(struct platform_device *pdev)
spin_lock_init(&cp->lock);
crypto_init_queue(&cp->queue, 50);
- cp->reg = ioremap(res->start, resource_size(res));
- if (!cp->reg) {
- ret = -ENOMEM;
+ cp->reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(cp->reg)) {
+ ret = PTR_ERR(cp->reg);
goto err;
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
- if (!res) {
- ret = -ENXIO;
- goto err_unmap_reg;
- }
- cp->sram_size = resource_size(res);
+ ret = mv_cesa_get_sram(pdev, cp);
+ if (ret)
+ goto err;
+
cp->max_req_size = cp->sram_size - SRAM_CFG_SPACE;
- cp->sram = ioremap(res->start, cp->sram_size);
- if (!cp->sram) {
- ret = -ENOMEM;
- goto err_unmap_reg;
- }
if (pdev->dev.of_node)
irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
@@ -1066,7 +1097,7 @@ static int mv_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0 || irq == NO_IRQ) {
ret = irq;
- goto err_unmap_sram;
+ goto err;
}
cp->irq = irq;
@@ -1076,7 +1107,7 @@ static int mv_probe(struct platform_device *pdev)
cp->queue_th = kthread_run(queue_manag, cp, "mv_crypto");
if (IS_ERR(cp->queue_th)) {
ret = PTR_ERR(cp->queue_th);
- goto err_unmap_sram;
+ goto err;
}
ret = request_irq(irq, crypto_int, 0, dev_name(&pdev->dev),
@@ -1134,10 +1165,6 @@ err_irq:
}
err_thread:
kthread_stop(cp->queue_th);
-err_unmap_sram:
- iounmap(cp->sram);
-err_unmap_reg:
- iounmap(cp->reg);
err:
kfree(cp);
cpg = NULL;
@@ -1157,8 +1184,6 @@ static int mv_remove(struct platform_device *pdev)
kthread_stop(cp->queue_th);
free_irq(cp->irq, cp);
memset(cp->sram, 0, cp->sram_size);
- iounmap(cp->sram);
- iounmap(cp->reg);
if (!IS_ERR(cp->clk)) {
clk_disable_unprepare(cp->clk);
@@ -1172,6 +1197,8 @@ static int mv_remove(struct platform_device *pdev)
static const struct of_device_id mv_cesa_of_match_table[] = {
{ .compatible = "marvell,orion-crypto", },
+ { .compatible = "marvell,kirkwood-crypto", },
+ { .compatible = "marvell,dove-crypto", },
{}
};
MODULE_DEVICE_TABLE(of, mv_cesa_of_match_table);
diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c
index 10a9aeff1666..2e8dab9d4263 100644
--- a/drivers/crypto/n2_core.c
+++ b/drivers/crypto/n2_core.c
@@ -1281,10 +1281,10 @@ static const char md5_zero[MD5_DIGEST_SIZE] = {
0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e,
};
static const u32 md5_init[MD5_HASH_WORDS] = {
- cpu_to_le32(0x67452301),
- cpu_to_le32(0xefcdab89),
- cpu_to_le32(0x98badcfe),
- cpu_to_le32(0x10325476),
+ cpu_to_le32(MD5_H0),
+ cpu_to_le32(MD5_H1),
+ cpu_to_le32(MD5_H2),
+ cpu_to_le32(MD5_H3),
};
static const char sha1_zero[SHA1_DIGEST_SIZE] = {
0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32,
diff --git a/drivers/crypto/nx/Kconfig b/drivers/crypto/nx/Kconfig
index f82616621ae1..e421c96c763a 100644
--- a/drivers/crypto/nx/Kconfig
+++ b/drivers/crypto/nx/Kconfig
@@ -1,26 +1,55 @@
+
config CRYPTO_DEV_NX_ENCRYPT
- tristate "Encryption acceleration support"
- depends on PPC64 && IBMVIO
+ tristate "Encryption acceleration support on pSeries platform"
+ depends on PPC_PSERIES && IBMVIO && !CPU_LITTLE_ENDIAN
default y
select CRYPTO_AES
- select CRYPTO_CBC
- select CRYPTO_ECB
select CRYPTO_CCM
- select CRYPTO_GCM
- select CRYPTO_AUTHENC
- select CRYPTO_XCBC
- select CRYPTO_SHA256
- select CRYPTO_SHA512
help
- Support for Power7+ in-Nest encryption acceleration. This
- module supports acceleration for AES and SHA2 algorithms. If you
- choose 'M' here, this module will be called nx_crypto.
+ Support for PowerPC Nest (NX) encryption acceleration. This
+ module supports acceleration for AES and SHA2 algorithms on
+ the pSeries platform. If you choose 'M' here, this module
+ will be called nx_crypto.
config CRYPTO_DEV_NX_COMPRESS
tristate "Compression acceleration support"
- depends on PPC64 && IBMVIO
default y
help
- Support for Power7+ in-Nest compression acceleration. This
- module supports acceleration for AES and SHA2 algorithms. If you
- choose 'M' here, this module will be called nx_compress.
+ Support for PowerPC Nest (NX) compression acceleration. This
+ module supports acceleration for compressing memory with the 842
+ algorithm. One of the platform drivers must be selected also.
+ If you choose 'M' here, this module will be called nx_compress.
+
+if CRYPTO_DEV_NX_COMPRESS
+
+config CRYPTO_DEV_NX_COMPRESS_PSERIES
+ tristate "Compression acceleration support on pSeries platform"
+ depends on PPC_PSERIES && IBMVIO
+ default y
+ help
+ Support for PowerPC Nest (NX) compression acceleration. This
+ module supports acceleration for compressing memory with the 842
+ algorithm. This supports NX hardware on the pSeries platform.
+ If you choose 'M' here, this module will be called nx_compress_pseries.
+
+config CRYPTO_DEV_NX_COMPRESS_POWERNV
+ tristate "Compression acceleration support on PowerNV platform"
+ depends on PPC_POWERNV
+ default y
+ help
+ Support for PowerPC Nest (NX) compression acceleration. This
+ module supports acceleration for compressing memory with the 842
+ algorithm. This supports NX hardware on the PowerNV platform.
+ If you choose 'M' here, this module will be called nx_compress_powernv.
+
+config CRYPTO_DEV_NX_COMPRESS_CRYPTO
+ tristate "Compression acceleration cryptographic interface"
+ select CRYPTO_ALGAPI
+ select 842_DECOMPRESS
+ default y
+ help
+ Support for PowerPC Nest (NX) accelerators using the cryptographic
+ API. If you choose 'M' here, this module will be called
+ nx_compress_crypto.
+
+endif
diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile
index bb770ea45ce9..e1684f5adb11 100644
--- a/drivers/crypto/nx/Makefile
+++ b/drivers/crypto/nx/Makefile
@@ -10,5 +10,12 @@ nx-crypto-objs := nx.o \
nx-sha256.o \
nx-sha512.o
-obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS) += nx-compress.o
+obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS) += nx-compress.o nx-compress-platform.o
+obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_PSERIES) += nx-compress-pseries.o
+obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_POWERNV) += nx-compress-powernv.o
+obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_CRYPTO) += nx-compress-crypto.o
nx-compress-objs := nx-842.o
+nx-compress-platform-objs := nx-842-platform.o
+nx-compress-pseries-objs := nx-842-pseries.o
+nx-compress-powernv-objs := nx-842-powernv.o
+nx-compress-crypto-objs := nx-842-crypto.o
diff --git a/drivers/crypto/nx/nx-842-crypto.c b/drivers/crypto/nx/nx-842-crypto.c
new file mode 100644
index 000000000000..d53a1dcd7b4e
--- /dev/null
+++ b/drivers/crypto/nx/nx-842-crypto.c
@@ -0,0 +1,580 @@
+/*
+ * Cryptographic API for the NX-842 hardware compression.
+ *
+ * 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.
+ *
+ * Copyright (C) IBM Corporation, 2011-2015
+ *
+ * Original Authors: Robert Jennings <rcj@linux.vnet.ibm.com>
+ * Seth Jennings <sjenning@linux.vnet.ibm.com>
+ *
+ * Rewrite: Dan Streetman <ddstreet@ieee.org>
+ *
+ * This is an interface to the NX-842 compression hardware in PowerPC
+ * processors. Most of the complexity of this drvier is due to the fact that
+ * the NX-842 compression hardware requires the input and output data buffers
+ * to be specifically aligned, to be a specific multiple in length, and within
+ * specific minimum and maximum lengths. Those restrictions, provided by the
+ * nx-842 driver via nx842_constraints, mean this driver must use bounce
+ * buffers and headers to correct misaligned in or out buffers, and to split
+ * input buffers that are too large.
+ *
+ * This driver will fall back to software decompression if the hardware
+ * decompression fails, so this driver's decompression should never fail as
+ * long as the provided compressed buffer is valid. Any compressed buffer
+ * created by this driver will have a header (except ones where the input
+ * perfectly matches the constraints); so users of this driver cannot simply
+ * pass a compressed buffer created by this driver over to the 842 software
+ * decompression library. Instead, users must use this driver to decompress;
+ * if the hardware fails or is unavailable, the compressed buffer will be
+ * parsed and the header removed, and the raw 842 buffer(s) passed to the 842
+ * software decompression library.
+ *
+ * This does not fall back to software compression, however, since the caller
+ * of this function is specifically requesting hardware compression; if the
+ * hardware compression fails, the caller can fall back to software
+ * compression, and the raw 842 compressed buffer that the software compressor
+ * creates can be passed to this driver for hardware decompression; any
+ * buffer without our specific header magic is assumed to be a raw 842 buffer
+ * and passed directly to the hardware. Note that the software compression
+ * library will produce a compressed buffer that is incompatible with the
+ * hardware decompressor if the original input buffer length is not a multiple
+ * of 8; if such a compressed buffer is passed to this driver for
+ * decompression, the hardware will reject it and this driver will then pass
+ * it over to the software library for decompression.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/vmalloc.h>
+#include <linux/sw842.h>
+#include <linux/ratelimit.h>
+
+#include "nx-842.h"
+
+/* The first 5 bits of this magic are 0x1f, which is an invalid 842 5-bit
+ * template (see lib/842/842.h), so this magic number will never appear at
+ * the start of a raw 842 compressed buffer. That is important, as any buffer
+ * passed to us without this magic is assumed to be a raw 842 compressed
+ * buffer, and passed directly to the hardware to decompress.
+ */
+#define NX842_CRYPTO_MAGIC (0xf842)
+#define NX842_CRYPTO_GROUP_MAX (0x20)
+#define NX842_CRYPTO_HEADER_SIZE(g) \
+ (sizeof(struct nx842_crypto_header) + \
+ sizeof(struct nx842_crypto_header_group) * (g))
+#define NX842_CRYPTO_HEADER_MAX_SIZE \
+ NX842_CRYPTO_HEADER_SIZE(NX842_CRYPTO_GROUP_MAX)
+
+/* bounce buffer size */
+#define BOUNCE_BUFFER_ORDER (2)
+#define BOUNCE_BUFFER_SIZE \
+ ((unsigned int)(PAGE_SIZE << BOUNCE_BUFFER_ORDER))
+
+/* try longer on comp because we can fallback to sw decomp if hw is busy */
+#define COMP_BUSY_TIMEOUT (250) /* ms */
+#define DECOMP_BUSY_TIMEOUT (50) /* ms */
+
+struct nx842_crypto_header_group {
+ __be16 padding; /* unused bytes at start of group */
+ __be32 compressed_length; /* compressed bytes in group */
+ __be32 uncompressed_length; /* bytes after decompression */
+} __packed;
+
+struct nx842_crypto_header {
+ __be16 magic; /* NX842_CRYPTO_MAGIC */
+ __be16 ignore; /* decompressed end bytes to ignore */
+ u8 groups; /* total groups in this header */
+ struct nx842_crypto_header_group group[];
+} __packed;
+
+struct nx842_crypto_param {
+ u8 *in;
+ unsigned int iremain;
+ u8 *out;
+ unsigned int oremain;
+ unsigned int ototal;
+};
+
+static int update_param(struct nx842_crypto_param *p,
+ unsigned int slen, unsigned int dlen)
+{
+ if (p->iremain < slen)
+ return -EOVERFLOW;
+ if (p->oremain < dlen)
+ return -ENOSPC;
+
+ p->in += slen;
+ p->iremain -= slen;
+ p->out += dlen;
+ p->oremain -= dlen;
+ p->ototal += dlen;
+
+ return 0;
+}
+
+struct nx842_crypto_ctx {
+ u8 *wmem;
+ u8 *sbounce, *dbounce;
+
+ struct nx842_crypto_header header;
+ struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX];
+};
+
+static int nx842_crypto_init(struct crypto_tfm *tfm)
+{
+ struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ ctx->wmem = kmalloc(nx842_workmem_size(), GFP_KERNEL);
+ ctx->sbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER);
+ ctx->dbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER);
+ if (!ctx->wmem || !ctx->sbounce || !ctx->dbounce) {
+ kfree(ctx->wmem);
+ free_page((unsigned long)ctx->sbounce);
+ free_page((unsigned long)ctx->dbounce);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void nx842_crypto_exit(struct crypto_tfm *tfm)
+{
+ struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ kfree(ctx->wmem);
+ free_page((unsigned long)ctx->sbounce);
+ free_page((unsigned long)ctx->dbounce);
+}
+
+static int read_constraints(struct nx842_constraints *c)
+{
+ int ret;
+
+ ret = nx842_constraints(c);
+ if (ret) {
+ pr_err_ratelimited("could not get nx842 constraints : %d\n",
+ ret);
+ return ret;
+ }
+
+ /* limit maximum, to always have enough bounce buffer to decompress */
+ if (c->maximum > BOUNCE_BUFFER_SIZE) {
+ c->maximum = BOUNCE_BUFFER_SIZE;
+ pr_info_once("limiting nx842 maximum to %x\n", c->maximum);
+ }
+
+ return 0;
+}
+
+static int nx842_crypto_add_header(struct nx842_crypto_header *hdr, u8 *buf)
+{
+ int s = NX842_CRYPTO_HEADER_SIZE(hdr->groups);
+
+ /* compress should have added space for header */
+ if (s > be16_to_cpu(hdr->group[0].padding)) {
+ pr_err("Internal error: no space for header\n");
+ return -EINVAL;
+ }
+
+ memcpy(buf, hdr, s);
+
+ print_hex_dump_debug("header ", DUMP_PREFIX_OFFSET, 16, 1, buf, s, 0);
+
+ return 0;
+}
+
+static int compress(struct nx842_crypto_ctx *ctx,
+ struct nx842_crypto_param *p,
+ struct nx842_crypto_header_group *g,
+ struct nx842_constraints *c,
+ u16 *ignore,
+ unsigned int hdrsize)
+{
+ unsigned int slen = p->iremain, dlen = p->oremain, tmplen;
+ unsigned int adj_slen = slen;
+ u8 *src = p->in, *dst = p->out;
+ int ret, dskip = 0;
+ ktime_t timeout;
+
+ if (p->iremain == 0)
+ return -EOVERFLOW;
+
+ if (p->oremain == 0 || hdrsize + c->minimum > dlen)
+ return -ENOSPC;
+
+ if (slen % c->multiple)
+ adj_slen = round_up(slen, c->multiple);
+ if (slen < c->minimum)
+ adj_slen = c->minimum;
+ if (slen > c->maximum)
+ adj_slen = slen = c->maximum;
+ if (adj_slen > slen || (u64)src % c->alignment) {
+ adj_slen = min(adj_slen, BOUNCE_BUFFER_SIZE);
+ slen = min(slen, BOUNCE_BUFFER_SIZE);
+ if (adj_slen > slen)
+ memset(ctx->sbounce + slen, 0, adj_slen - slen);
+ memcpy(ctx->sbounce, src, slen);
+ src = ctx->sbounce;
+ slen = adj_slen;
+ pr_debug("using comp sbounce buffer, len %x\n", slen);
+ }
+
+ dst += hdrsize;
+ dlen -= hdrsize;
+
+ if ((u64)dst % c->alignment) {
+ dskip = (int)(PTR_ALIGN(dst, c->alignment) - dst);
+ dst += dskip;
+ dlen -= dskip;
+ }
+ if (dlen % c->multiple)
+ dlen = round_down(dlen, c->multiple);
+ if (dlen < c->minimum) {
+nospc:
+ dst = ctx->dbounce;
+ dlen = min(p->oremain, BOUNCE_BUFFER_SIZE);
+ dlen = round_down(dlen, c->multiple);
+ dskip = 0;
+ pr_debug("using comp dbounce buffer, len %x\n", dlen);
+ }
+ if (dlen > c->maximum)
+ dlen = c->maximum;
+
+ tmplen = dlen;
+ timeout = ktime_add_ms(ktime_get(), COMP_BUSY_TIMEOUT);
+ do {
+ dlen = tmplen; /* reset dlen, if we're retrying */
+ ret = nx842_compress(src, slen, dst, &dlen, ctx->wmem);
+ /* possibly we should reduce the slen here, instead of
+ * retrying with the dbounce buffer?
+ */
+ if (ret == -ENOSPC && dst != ctx->dbounce)
+ goto nospc;
+ } while (ret == -EBUSY && ktime_before(ktime_get(), timeout));
+ if (ret)
+ return ret;
+
+ dskip += hdrsize;
+
+ if (dst == ctx->dbounce)
+ memcpy(p->out + dskip, dst, dlen);
+
+ g->padding = cpu_to_be16(dskip);
+ g->compressed_length = cpu_to_be32(dlen);
+ g->uncompressed_length = cpu_to_be32(slen);
+
+ if (p->iremain < slen) {
+ *ignore = slen - p->iremain;
+ slen = p->iremain;
+ }
+
+ pr_debug("compress slen %x ignore %x dlen %x padding %x\n",
+ slen, *ignore, dlen, dskip);
+
+ return update_param(p, slen, dskip + dlen);
+}
+
+static int nx842_crypto_compress(struct crypto_tfm *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen)
+{
+ struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct nx842_crypto_header *hdr = &ctx->header;
+ struct nx842_crypto_param p;
+ struct nx842_constraints c;
+ unsigned int groups, hdrsize, h;
+ int ret, n;
+ bool add_header;
+ u16 ignore = 0;
+
+ p.in = (u8 *)src;
+ p.iremain = slen;
+ p.out = dst;
+ p.oremain = *dlen;
+ p.ototal = 0;
+
+ *dlen = 0;
+
+ ret = read_constraints(&c);
+ if (ret)
+ return ret;
+
+ groups = min_t(unsigned int, NX842_CRYPTO_GROUP_MAX,
+ DIV_ROUND_UP(p.iremain, c.maximum));
+ hdrsize = NX842_CRYPTO_HEADER_SIZE(groups);
+
+ /* skip adding header if the buffers meet all constraints */
+ add_header = (p.iremain % c.multiple ||
+ p.iremain < c.minimum ||
+ p.iremain > c.maximum ||
+ (u64)p.in % c.alignment ||
+ p.oremain % c.multiple ||
+ p.oremain < c.minimum ||
+ p.oremain > c.maximum ||
+ (u64)p.out % c.alignment);
+
+ hdr->magic = cpu_to_be16(NX842_CRYPTO_MAGIC);
+ hdr->groups = 0;
+ hdr->ignore = 0;
+
+ while (p.iremain > 0) {
+ n = hdr->groups++;
+ if (hdr->groups > NX842_CRYPTO_GROUP_MAX)
+ return -ENOSPC;
+
+ /* header goes before first group */
+ h = !n && add_header ? hdrsize : 0;
+
+ if (ignore)
+ pr_warn("interal error, ignore is set %x\n", ignore);
+
+ ret = compress(ctx, &p, &hdr->group[n], &c, &ignore, h);
+ if (ret)
+ return ret;
+ }
+
+ if (!add_header && hdr->groups > 1) {
+ pr_err("Internal error: No header but multiple groups\n");
+ return -EINVAL;
+ }
+
+ /* ignore indicates the input stream needed to be padded */
+ hdr->ignore = cpu_to_be16(ignore);
+ if (ignore)
+ pr_debug("marked %d bytes as ignore\n", ignore);
+
+ if (add_header)
+ ret = nx842_crypto_add_header(hdr, dst);
+ if (ret)
+ return ret;
+
+ *dlen = p.ototal;
+
+ pr_debug("compress total slen %x dlen %x\n", slen, *dlen);
+
+ return 0;
+}
+
+static int decompress(struct nx842_crypto_ctx *ctx,
+ struct nx842_crypto_param *p,
+ struct nx842_crypto_header_group *g,
+ struct nx842_constraints *c,
+ u16 ignore,
+ bool usehw)
+{
+ unsigned int slen = be32_to_cpu(g->compressed_length);
+ unsigned int required_len = be32_to_cpu(g->uncompressed_length);
+ unsigned int dlen = p->oremain, tmplen;
+ unsigned int adj_slen = slen;
+ u8 *src = p->in, *dst = p->out;
+ u16 padding = be16_to_cpu(g->padding);
+ int ret, spadding = 0, dpadding = 0;
+ ktime_t timeout;
+
+ if (!slen || !required_len)
+ return -EINVAL;
+
+ if (p->iremain <= 0 || padding + slen > p->iremain)
+ return -EOVERFLOW;
+
+ if (p->oremain <= 0 || required_len - ignore > p->oremain)
+ return -ENOSPC;
+
+ src += padding;
+
+ if (!usehw)
+ goto usesw;
+
+ if (slen % c->multiple)
+ adj_slen = round_up(slen, c->multiple);
+ if (slen < c->minimum)
+ adj_slen = c->minimum;
+ if (slen > c->maximum)
+ goto usesw;
+ if (slen < adj_slen || (u64)src % c->alignment) {
+ /* we can append padding bytes because the 842 format defines
+ * an "end" template (see lib/842/842_decompress.c) and will
+ * ignore any bytes following it.
+ */
+ if (slen < adj_slen)
+ memset(ctx->sbounce + slen, 0, adj_slen - slen);
+ memcpy(ctx->sbounce, src, slen);
+ src = ctx->sbounce;
+ spadding = adj_slen - slen;
+ slen = adj_slen;
+ pr_debug("using decomp sbounce buffer, len %x\n", slen);
+ }
+
+ if (dlen % c->multiple)
+ dlen = round_down(dlen, c->multiple);
+ if (dlen < required_len || (u64)dst % c->alignment) {
+ dst = ctx->dbounce;
+ dlen = min(required_len, BOUNCE_BUFFER_SIZE);
+ pr_debug("using decomp dbounce buffer, len %x\n", dlen);
+ }
+ if (dlen < c->minimum)
+ goto usesw;
+ if (dlen > c->maximum)
+ dlen = c->maximum;
+
+ tmplen = dlen;
+ timeout = ktime_add_ms(ktime_get(), DECOMP_BUSY_TIMEOUT);
+ do {
+ dlen = tmplen; /* reset dlen, if we're retrying */
+ ret = nx842_decompress(src, slen, dst, &dlen, ctx->wmem);
+ } while (ret == -EBUSY && ktime_before(ktime_get(), timeout));
+ if (ret) {
+usesw:
+ /* reset everything, sw doesn't have constraints */
+ src = p->in + padding;
+ slen = be32_to_cpu(g->compressed_length);
+ spadding = 0;
+ dst = p->out;
+ dlen = p->oremain;
+ dpadding = 0;
+ if (dlen < required_len) { /* have ignore bytes */
+ dst = ctx->dbounce;
+ dlen = BOUNCE_BUFFER_SIZE;
+ }
+ pr_info_ratelimited("using software 842 decompression\n");
+ ret = sw842_decompress(src, slen, dst, &dlen);
+ }
+ if (ret)
+ return ret;
+
+ slen -= spadding;
+
+ dlen -= ignore;
+ if (ignore)
+ pr_debug("ignoring last %x bytes\n", ignore);
+
+ if (dst == ctx->dbounce)
+ memcpy(p->out, dst, dlen);
+
+ pr_debug("decompress slen %x padding %x dlen %x ignore %x\n",
+ slen, padding, dlen, ignore);
+
+ return update_param(p, slen + padding, dlen);
+}
+
+static int nx842_crypto_decompress(struct crypto_tfm *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int *dlen)
+{
+ struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct nx842_crypto_header *hdr;
+ struct nx842_crypto_param p;
+ struct nx842_constraints c;
+ int n, ret, hdr_len;
+ u16 ignore = 0;
+ bool usehw = true;
+
+ p.in = (u8 *)src;
+ p.iremain = slen;
+ p.out = dst;
+ p.oremain = *dlen;
+ p.ototal = 0;
+
+ *dlen = 0;
+
+ if (read_constraints(&c))
+ usehw = false;
+
+ hdr = (struct nx842_crypto_header *)src;
+
+ /* If it doesn't start with our header magic number, assume it's a raw
+ * 842 compressed buffer and pass it directly to the hardware driver
+ */
+ if (be16_to_cpu(hdr->magic) != NX842_CRYPTO_MAGIC) {
+ struct nx842_crypto_header_group g = {
+ .padding = 0,
+ .compressed_length = cpu_to_be32(p.iremain),
+ .uncompressed_length = cpu_to_be32(p.oremain),
+ };
+
+ ret = decompress(ctx, &p, &g, &c, 0, usehw);
+ if (ret)
+ return ret;
+
+ *dlen = p.ototal;
+
+ return 0;
+ }
+
+ if (!hdr->groups) {
+ pr_err("header has no groups\n");
+ return -EINVAL;
+ }
+ if (hdr->groups > NX842_CRYPTO_GROUP_MAX) {
+ pr_err("header has too many groups %x, max %x\n",
+ hdr->groups, NX842_CRYPTO_GROUP_MAX);
+ return -EINVAL;
+ }
+
+ hdr_len = NX842_CRYPTO_HEADER_SIZE(hdr->groups);
+ if (hdr_len > slen)
+ return -EOVERFLOW;
+
+ memcpy(&ctx->header, src, hdr_len);
+ hdr = &ctx->header;
+
+ for (n = 0; n < hdr->groups; n++) {
+ /* ignore applies to last group */
+ if (n + 1 == hdr->groups)
+ ignore = be16_to_cpu(hdr->ignore);
+
+ ret = decompress(ctx, &p, &hdr->group[n], &c, ignore, usehw);
+ if (ret)
+ return ret;
+ }
+
+ *dlen = p.ototal;
+
+ pr_debug("decompress total slen %x dlen %x\n", slen, *dlen);
+
+ return 0;
+}
+
+static struct crypto_alg alg = {
+ .cra_name = "842",
+ .cra_driver_name = "842-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
+ .cra_ctxsize = sizeof(struct nx842_crypto_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_init = nx842_crypto_init,
+ .cra_exit = nx842_crypto_exit,
+ .cra_u = { .compress = {
+ .coa_compress = nx842_crypto_compress,
+ .coa_decompress = nx842_crypto_decompress } }
+};
+
+static int __init nx842_crypto_mod_init(void)
+{
+ return crypto_register_alg(&alg);
+}
+module_init(nx842_crypto_mod_init);
+
+static void __exit nx842_crypto_mod_exit(void)
+{
+ crypto_unregister_alg(&alg);
+}
+module_exit(nx842_crypto_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IBM PowerPC Nest (NX) 842 Hardware Compression Interface");
+MODULE_ALIAS_CRYPTO("842");
+MODULE_ALIAS_CRYPTO("842-nx");
+MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>");
diff --git a/drivers/crypto/nx/nx-842-platform.c b/drivers/crypto/nx/nx-842-platform.c
new file mode 100644
index 000000000000..664f13dd06ed
--- /dev/null
+++ b/drivers/crypto/nx/nx-842-platform.c
@@ -0,0 +1,84 @@
+
+#include "nx-842.h"
+
+/* this is needed, separate from the main nx-842.c driver, because that main
+ * driver loads the platform drivers during its init(), and it expects one
+ * (or none) of the platform drivers to set this pointer to its driver.
+ * That means this pointer can't be in the main nx-842 driver, because it
+ * wouldn't be accessible until after the main driver loaded, which wouldn't
+ * be possible as it's waiting for the platform driver to load. So place it
+ * here.
+ */
+static struct nx842_driver *driver;
+static DEFINE_SPINLOCK(driver_lock);
+
+struct nx842_driver *nx842_platform_driver(void)
+{
+ return driver;
+}
+EXPORT_SYMBOL_GPL(nx842_platform_driver);
+
+bool nx842_platform_driver_set(struct nx842_driver *_driver)
+{
+ bool ret = false;
+
+ spin_lock(&driver_lock);
+
+ if (!driver) {
+ driver = _driver;
+ ret = true;
+ } else
+ WARN(1, "can't set platform driver, already set to %s\n",
+ driver->name);
+
+ spin_unlock(&driver_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(nx842_platform_driver_set);
+
+/* only call this from the platform driver exit function */
+void nx842_platform_driver_unset(struct nx842_driver *_driver)
+{
+ spin_lock(&driver_lock);
+
+ if (driver == _driver)
+ driver = NULL;
+ else if (driver)
+ WARN(1, "can't unset platform driver %s, currently set to %s\n",
+ _driver->name, driver->name);
+ else
+ WARN(1, "can't unset platform driver, already unset\n");
+
+ spin_unlock(&driver_lock);
+}
+EXPORT_SYMBOL_GPL(nx842_platform_driver_unset);
+
+bool nx842_platform_driver_get(void)
+{
+ bool ret = false;
+
+ spin_lock(&driver_lock);
+
+ if (driver)
+ ret = try_module_get(driver->owner);
+
+ spin_unlock(&driver_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(nx842_platform_driver_get);
+
+void nx842_platform_driver_put(void)
+{
+ spin_lock(&driver_lock);
+
+ if (driver)
+ module_put(driver->owner);
+
+ spin_unlock(&driver_lock);
+}
+EXPORT_SYMBOL_GPL(nx842_platform_driver_put);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>");
+MODULE_DESCRIPTION("842 H/W Compression platform driver");
diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c
new file mode 100644
index 000000000000..33b3b0abf4ae
--- /dev/null
+++ b/drivers/crypto/nx/nx-842-powernv.c
@@ -0,0 +1,637 @@
+/*
+ * Driver for IBM PowerNV 842 compression accelerator
+ *
+ * Copyright (C) 2015 Dan Streetman, 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "nx-842.h"
+
+#include <linux/timer.h>
+
+#include <asm/prom.h>
+#include <asm/icswx.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>");
+MODULE_DESCRIPTION("842 H/W Compression driver for IBM PowerNV processors");
+
+#define WORKMEM_ALIGN (CRB_ALIGN)
+#define CSB_WAIT_MAX (5000) /* ms */
+
+struct nx842_workmem {
+ /* Below fields must be properly aligned */
+ struct coprocessor_request_block crb; /* CRB_ALIGN align */
+ struct data_descriptor_entry ddl_in[DDL_LEN_MAX]; /* DDE_ALIGN align */
+ struct data_descriptor_entry ddl_out[DDL_LEN_MAX]; /* DDE_ALIGN align */
+ /* Above fields must be properly aligned */
+
+ ktime_t start;
+
+ char padding[WORKMEM_ALIGN]; /* unused, to allow alignment */
+} __packed __aligned(WORKMEM_ALIGN);
+
+struct nx842_coproc {
+ unsigned int chip_id;
+ unsigned int ct;
+ unsigned int ci;
+ struct list_head list;
+};
+
+/* no cpu hotplug on powernv, so this list never changes after init */
+static LIST_HEAD(nx842_coprocs);
+static unsigned int nx842_ct;
+
+/**
+ * setup_indirect_dde - Setup an indirect DDE
+ *
+ * The DDE is setup with the the DDE count, byte count, and address of
+ * first direct DDE in the list.
+ */
+static void setup_indirect_dde(struct data_descriptor_entry *dde,
+ struct data_descriptor_entry *ddl,
+ unsigned int dde_count, unsigned int byte_count)
+{
+ dde->flags = 0;
+ dde->count = dde_count;
+ dde->index = 0;
+ dde->length = cpu_to_be32(byte_count);
+ dde->address = cpu_to_be64(nx842_get_pa(ddl));
+}
+
+/**
+ * setup_direct_dde - Setup single DDE from buffer
+ *
+ * The DDE is setup with the buffer and length. The buffer must be properly
+ * aligned. The used length is returned.
+ * Returns:
+ * N Successfully set up DDE with N bytes
+ */
+static unsigned int setup_direct_dde(struct data_descriptor_entry *dde,
+ unsigned long pa, unsigned int len)
+{
+ unsigned int l = min_t(unsigned int, len, LEN_ON_PAGE(pa));
+
+ dde->flags = 0;
+ dde->count = 0;
+ dde->index = 0;
+ dde->length = cpu_to_be32(l);
+ dde->address = cpu_to_be64(pa);
+
+ return l;
+}
+
+/**
+ * setup_ddl - Setup DDL from buffer
+ *
+ * Returns:
+ * 0 Successfully set up DDL
+ */
+static int setup_ddl(struct data_descriptor_entry *dde,
+ struct data_descriptor_entry *ddl,
+ unsigned char *buf, unsigned int len,
+ bool in)
+{
+ unsigned long pa = nx842_get_pa(buf);
+ int i, ret, total_len = len;
+
+ if (!IS_ALIGNED(pa, DDE_BUFFER_ALIGN)) {
+ pr_debug("%s buffer pa 0x%lx not 0x%x-byte aligned\n",
+ in ? "input" : "output", pa, DDE_BUFFER_ALIGN);
+ return -EINVAL;
+ }
+
+ /* only need to check last mult; since buffer must be
+ * DDE_BUFFER_ALIGN aligned, and that is a multiple of
+ * DDE_BUFFER_SIZE_MULT, and pre-last page DDE buffers
+ * are guaranteed a multiple of DDE_BUFFER_SIZE_MULT.
+ */
+ if (len % DDE_BUFFER_LAST_MULT) {
+ pr_debug("%s buffer len 0x%x not a multiple of 0x%x\n",
+ in ? "input" : "output", len, DDE_BUFFER_LAST_MULT);
+ if (in)
+ return -EINVAL;
+ len = round_down(len, DDE_BUFFER_LAST_MULT);
+ }
+
+ /* use a single direct DDE */
+ if (len <= LEN_ON_PAGE(pa)) {
+ ret = setup_direct_dde(dde, pa, len);
+ WARN_ON(ret < len);
+ return 0;
+ }
+
+ /* use the DDL */
+ for (i = 0; i < DDL_LEN_MAX && len > 0; i++) {
+ ret = setup_direct_dde(&ddl[i], pa, len);
+ buf += ret;
+ len -= ret;
+ pa = nx842_get_pa(buf);
+ }
+
+ if (len > 0) {
+ pr_debug("0x%x total %s bytes 0x%x too many for DDL.\n",
+ total_len, in ? "input" : "output", len);
+ if (in)
+ return -EMSGSIZE;
+ total_len -= len;
+ }
+ setup_indirect_dde(dde, ddl, i, total_len);
+
+ return 0;
+}
+
+#define CSB_ERR(csb, msg, ...) \
+ pr_err("ERROR: " msg " : %02x %02x %02x %02x %08x\n", \
+ ##__VA_ARGS__, (csb)->flags, \
+ (csb)->cs, (csb)->cc, (csb)->ce, \
+ be32_to_cpu((csb)->count))
+
+#define CSB_ERR_ADDR(csb, msg, ...) \
+ CSB_ERR(csb, msg " at %lx", ##__VA_ARGS__, \
+ (unsigned long)be64_to_cpu((csb)->address))
+
+/**
+ * wait_for_csb
+ */
+static int wait_for_csb(struct nx842_workmem *wmem,
+ struct coprocessor_status_block *csb)
+{
+ ktime_t start = wmem->start, now = ktime_get();
+ ktime_t timeout = ktime_add_ms(start, CSB_WAIT_MAX);
+
+ while (!(ACCESS_ONCE(csb->flags) & CSB_V)) {
+ cpu_relax();
+ now = ktime_get();
+ if (ktime_after(now, timeout))
+ break;
+ }
+
+ /* hw has updated csb and output buffer */
+ barrier();
+
+ /* check CSB flags */
+ if (!(csb->flags & CSB_V)) {
+ CSB_ERR(csb, "CSB still not valid after %ld us, giving up",
+ (long)ktime_us_delta(now, start));
+ return -ETIMEDOUT;
+ }
+ if (csb->flags & CSB_F) {
+ CSB_ERR(csb, "Invalid CSB format");
+ return -EPROTO;
+ }
+ if (csb->flags & CSB_CH) {
+ CSB_ERR(csb, "Invalid CSB chaining state");
+ return -EPROTO;
+ }
+
+ /* verify CSB completion sequence is 0 */
+ if (csb->cs) {
+ CSB_ERR(csb, "Invalid CSB completion sequence");
+ return -EPROTO;
+ }
+
+ /* check CSB Completion Code */
+ switch (csb->cc) {
+ /* no error */
+ case CSB_CC_SUCCESS:
+ break;
+ case CSB_CC_TPBC_GT_SPBC:
+ /* not an error, but the compressed data is
+ * larger than the uncompressed data :(
+ */
+ break;
+
+ /* input data errors */
+ case CSB_CC_OPERAND_OVERLAP:
+ /* input and output buffers overlap */
+ CSB_ERR(csb, "Operand Overlap error");
+ return -EINVAL;
+ case CSB_CC_INVALID_OPERAND:
+ CSB_ERR(csb, "Invalid operand");
+ return -EINVAL;
+ case CSB_CC_NOSPC:
+ /* output buffer too small */
+ return -ENOSPC;
+ case CSB_CC_ABORT:
+ CSB_ERR(csb, "Function aborted");
+ return -EINTR;
+ case CSB_CC_CRC_MISMATCH:
+ CSB_ERR(csb, "CRC mismatch");
+ return -EINVAL;
+ case CSB_CC_TEMPL_INVALID:
+ CSB_ERR(csb, "Compressed data template invalid");
+ return -EINVAL;
+ case CSB_CC_TEMPL_OVERFLOW:
+ CSB_ERR(csb, "Compressed data template shows data past end");
+ return -EINVAL;
+
+ /* these should not happen */
+ case CSB_CC_INVALID_ALIGN:
+ /* setup_ddl should have detected this */
+ CSB_ERR_ADDR(csb, "Invalid alignment");
+ return -EINVAL;
+ case CSB_CC_DATA_LENGTH:
+ /* setup_ddl should have detected this */
+ CSB_ERR(csb, "Invalid data length");
+ return -EINVAL;
+ case CSB_CC_WR_TRANSLATION:
+ case CSB_CC_TRANSLATION:
+ case CSB_CC_TRANSLATION_DUP1:
+ case CSB_CC_TRANSLATION_DUP2:
+ case CSB_CC_TRANSLATION_DUP3:
+ case CSB_CC_TRANSLATION_DUP4:
+ case CSB_CC_TRANSLATION_DUP5:
+ case CSB_CC_TRANSLATION_DUP6:
+ /* should not happen, we use physical addrs */
+ CSB_ERR_ADDR(csb, "Translation error");
+ return -EPROTO;
+ case CSB_CC_WR_PROTECTION:
+ case CSB_CC_PROTECTION:
+ case CSB_CC_PROTECTION_DUP1:
+ case CSB_CC_PROTECTION_DUP2:
+ case CSB_CC_PROTECTION_DUP3:
+ case CSB_CC_PROTECTION_DUP4:
+ case CSB_CC_PROTECTION_DUP5:
+ case CSB_CC_PROTECTION_DUP6:
+ /* should not happen, we use physical addrs */
+ CSB_ERR_ADDR(csb, "Protection error");
+ return -EPROTO;
+ case CSB_CC_PRIVILEGE:
+ /* shouldn't happen, we're in HYP mode */
+ CSB_ERR(csb, "Insufficient Privilege error");
+ return -EPROTO;
+ case CSB_CC_EXCESSIVE_DDE:
+ /* shouldn't happen, setup_ddl doesn't use many dde's */
+ CSB_ERR(csb, "Too many DDEs in DDL");
+ return -EINVAL;
+ case CSB_CC_TRANSPORT:
+ /* shouldn't happen, we setup CRB correctly */
+ CSB_ERR(csb, "Invalid CRB");
+ return -EINVAL;
+ case CSB_CC_SEGMENTED_DDL:
+ /* shouldn't happen, setup_ddl creates DDL right */
+ CSB_ERR(csb, "Segmented DDL error");
+ return -EINVAL;
+ case CSB_CC_DDE_OVERFLOW:
+ /* shouldn't happen, setup_ddl creates DDL right */
+ CSB_ERR(csb, "DDE overflow error");
+ return -EINVAL;
+ case CSB_CC_SESSION:
+ /* should not happen with ICSWX */
+ CSB_ERR(csb, "Session violation error");
+ return -EPROTO;
+ case CSB_CC_CHAIN:
+ /* should not happen, we don't use chained CRBs */
+ CSB_ERR(csb, "Chained CRB error");
+ return -EPROTO;
+ case CSB_CC_SEQUENCE:
+ /* should not happen, we don't use chained CRBs */
+ CSB_ERR(csb, "CRB seqeunce number error");
+ return -EPROTO;
+ case CSB_CC_UNKNOWN_CODE:
+ CSB_ERR(csb, "Unknown subfunction code");
+ return -EPROTO;
+
+ /* hardware errors */
+ case CSB_CC_RD_EXTERNAL:
+ case CSB_CC_RD_EXTERNAL_DUP1:
+ case CSB_CC_RD_EXTERNAL_DUP2:
+ case CSB_CC_RD_EXTERNAL_DUP3:
+ CSB_ERR_ADDR(csb, "Read error outside coprocessor");
+ return -EPROTO;
+ case CSB_CC_WR_EXTERNAL:
+ CSB_ERR_ADDR(csb, "Write error outside coprocessor");
+ return -EPROTO;
+ case CSB_CC_INTERNAL:
+ CSB_ERR(csb, "Internal error in coprocessor");
+ return -EPROTO;
+ case CSB_CC_PROVISION:
+ CSB_ERR(csb, "Storage provision error");
+ return -EPROTO;
+ case CSB_CC_HW:
+ CSB_ERR(csb, "Correctable hardware error");
+ return -EPROTO;
+
+ default:
+ CSB_ERR(csb, "Invalid CC %d", csb->cc);
+ return -EPROTO;
+ }
+
+ /* check Completion Extension state */
+ if (csb->ce & CSB_CE_TERMINATION) {
+ CSB_ERR(csb, "CSB request was terminated");
+ return -EPROTO;
+ }
+ if (csb->ce & CSB_CE_INCOMPLETE) {
+ CSB_ERR(csb, "CSB request not complete");
+ return -EPROTO;
+ }
+ if (!(csb->ce & CSB_CE_TPBC)) {
+ CSB_ERR(csb, "TPBC not provided, unknown target length");
+ return -EPROTO;
+ }
+
+ /* successful completion */
+ pr_debug_ratelimited("Processed %u bytes in %lu us\n", csb->count,
+ (unsigned long)ktime_us_delta(now, start));
+
+ return 0;
+}
+
+/**
+ * nx842_powernv_function - compress/decompress data using the 842 algorithm
+ *
+ * (De)compression provided by the NX842 coprocessor on IBM PowerNV systems.
+ * This compresses or decompresses the provided input buffer into the provided
+ * output buffer.
+ *
+ * Upon return from this function @outlen contains the length of the
+ * output data. If there is an error then @outlen will be 0 and an
+ * error will be specified by the return code from this function.
+ *
+ * The @workmem buffer should only be used by one function call at a time.
+ *
+ * @in: input buffer pointer
+ * @inlen: input buffer size
+ * @out: output buffer pointer
+ * @outlenp: output buffer size pointer
+ * @workmem: working memory buffer pointer, size determined by
+ * nx842_powernv_driver.workmem_size
+ * @fc: function code, see CCW Function Codes in nx-842.h
+ *
+ * Returns:
+ * 0 Success, output of length @outlenp stored in the buffer at @out
+ * -ENODEV Hardware unavailable
+ * -ENOSPC Output buffer is to small
+ * -EMSGSIZE Input buffer too large
+ * -EINVAL buffer constraints do not fix nx842_constraints
+ * -EPROTO hardware error during operation
+ * -ETIMEDOUT hardware did not complete operation in reasonable time
+ * -EINTR operation was aborted
+ */
+static int nx842_powernv_function(const unsigned char *in, unsigned int inlen,
+ unsigned char *out, unsigned int *outlenp,
+ void *workmem, int fc)
+{
+ struct coprocessor_request_block *crb;
+ struct coprocessor_status_block *csb;
+ struct nx842_workmem *wmem;
+ int ret;
+ u64 csb_addr;
+ u32 ccw;
+ unsigned int outlen = *outlenp;
+
+ wmem = PTR_ALIGN(workmem, WORKMEM_ALIGN);
+
+ *outlenp = 0;
+
+ /* shoudn't happen, we don't load without a coproc */
+ if (!nx842_ct) {
+ pr_err_ratelimited("coprocessor CT is 0");
+ return -ENODEV;
+ }
+
+ crb = &wmem->crb;
+ csb = &crb->csb;
+
+ /* Clear any previous values */
+ memset(crb, 0, sizeof(*crb));
+
+ /* set up DDLs */
+ ret = setup_ddl(&crb->source, wmem->ddl_in,
+ (unsigned char *)in, inlen, true);
+ if (ret)
+ return ret;
+ ret = setup_ddl(&crb->target, wmem->ddl_out,
+ out, outlen, false);
+ if (ret)
+ return ret;
+
+ /* set up CCW */
+ ccw = 0;
+ ccw = SET_FIELD(ccw, CCW_CT, nx842_ct);
+ ccw = SET_FIELD(ccw, CCW_CI_842, 0); /* use 0 for hw auto-selection */
+ ccw = SET_FIELD(ccw, CCW_FC_842, fc);
+
+ /* set up CRB's CSB addr */
+ csb_addr = nx842_get_pa(csb) & CRB_CSB_ADDRESS;
+ csb_addr |= CRB_CSB_AT; /* Addrs are phys */
+ crb->csb_addr = cpu_to_be64(csb_addr);
+
+ wmem->start = ktime_get();
+
+ /* do ICSWX */
+ ret = icswx(cpu_to_be32(ccw), crb);
+
+ pr_debug_ratelimited("icswx CR %x ccw %x crb->ccw %x\n", ret,
+ (unsigned int)ccw,
+ (unsigned int)be32_to_cpu(crb->ccw));
+
+ switch (ret) {
+ case ICSWX_INITIATED:
+ ret = wait_for_csb(wmem, csb);
+ break;
+ case ICSWX_BUSY:
+ pr_debug_ratelimited("842 Coprocessor busy\n");
+ ret = -EBUSY;
+ break;
+ case ICSWX_REJECTED:
+ pr_err_ratelimited("ICSWX rejected\n");
+ ret = -EPROTO;
+ break;
+ default:
+ pr_err_ratelimited("Invalid ICSWX return code %x\n", ret);
+ ret = -EPROTO;
+ break;
+ }
+
+ if (!ret)
+ *outlenp = be32_to_cpu(csb->count);
+
+ return ret;
+}
+
+/**
+ * nx842_powernv_compress - Compress data using the 842 algorithm
+ *
+ * Compression provided by the NX842 coprocessor on IBM PowerNV systems.
+ * The input buffer is compressed and the result is stored in the
+ * provided output buffer.
+ *
+ * Upon return from this function @outlen contains the length of the
+ * compressed data. If there is an error then @outlen will be 0 and an
+ * error will be specified by the return code from this function.
+ *
+ * @in: input buffer pointer
+ * @inlen: input buffer size
+ * @out: output buffer pointer
+ * @outlenp: output buffer size pointer
+ * @workmem: working memory buffer pointer, size determined by
+ * nx842_powernv_driver.workmem_size
+ *
+ * Returns: see @nx842_powernv_function()
+ */
+static int nx842_powernv_compress(const unsigned char *in, unsigned int inlen,
+ unsigned char *out, unsigned int *outlenp,
+ void *wmem)
+{
+ return nx842_powernv_function(in, inlen, out, outlenp,
+ wmem, CCW_FC_842_COMP_NOCRC);
+}
+
+/**
+ * nx842_powernv_decompress - Decompress data using the 842 algorithm
+ *
+ * Decompression provided by the NX842 coprocessor on IBM PowerNV systems.
+ * The input buffer is decompressed and the result is stored in the
+ * provided output buffer.
+ *
+ * Upon return from this function @outlen contains the length of the
+ * decompressed data. If there is an error then @outlen will be 0 and an
+ * error will be specified by the return code from this function.
+ *
+ * @in: input buffer pointer
+ * @inlen: input buffer size
+ * @out: output buffer pointer
+ * @outlenp: output buffer size pointer
+ * @workmem: working memory buffer pointer, size determined by
+ * nx842_powernv_driver.workmem_size
+ *
+ * Returns: see @nx842_powernv_function()
+ */
+static int nx842_powernv_decompress(const unsigned char *in, unsigned int inlen,
+ unsigned char *out, unsigned int *outlenp,
+ void *wmem)
+{
+ return nx842_powernv_function(in, inlen, out, outlenp,
+ wmem, CCW_FC_842_DECOMP_NOCRC);
+}
+
+static int __init nx842_powernv_probe(struct device_node *dn)
+{
+ struct nx842_coproc *coproc;
+ struct property *ct_prop, *ci_prop;
+ unsigned int ct, ci;
+ int chip_id;
+
+ chip_id = of_get_ibm_chip_id(dn);
+ if (chip_id < 0) {
+ pr_err("ibm,chip-id missing\n");
+ return -EINVAL;
+ }
+ ct_prop = of_find_property(dn, "ibm,842-coprocessor-type", NULL);
+ if (!ct_prop) {
+ pr_err("ibm,842-coprocessor-type missing\n");
+ return -EINVAL;
+ }
+ ct = be32_to_cpu(*(unsigned int *)ct_prop->value);
+ ci_prop = of_find_property(dn, "ibm,842-coprocessor-instance", NULL);
+ if (!ci_prop) {
+ pr_err("ibm,842-coprocessor-instance missing\n");
+ return -EINVAL;
+ }
+ ci = be32_to_cpu(*(unsigned int *)ci_prop->value);
+
+ coproc = kmalloc(sizeof(*coproc), GFP_KERNEL);
+ if (!coproc)
+ return -ENOMEM;
+
+ coproc->chip_id = chip_id;
+ coproc->ct = ct;
+ coproc->ci = ci;
+ INIT_LIST_HEAD(&coproc->list);
+ list_add(&coproc->list, &nx842_coprocs);
+
+ pr_info("coprocessor found on chip %d, CT %d CI %d\n", chip_id, ct, ci);
+
+ if (!nx842_ct)
+ nx842_ct = ct;
+ else if (nx842_ct != ct)
+ pr_err("NX842 chip %d, CT %d != first found CT %d\n",
+ chip_id, ct, nx842_ct);
+
+ return 0;
+}
+
+static struct nx842_constraints nx842_powernv_constraints = {
+ .alignment = DDE_BUFFER_ALIGN,
+ .multiple = DDE_BUFFER_LAST_MULT,
+ .minimum = DDE_BUFFER_LAST_MULT,
+ .maximum = (DDL_LEN_MAX - 1) * PAGE_SIZE,
+};
+
+static struct nx842_driver nx842_powernv_driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .workmem_size = sizeof(struct nx842_workmem),
+ .constraints = &nx842_powernv_constraints,
+ .compress = nx842_powernv_compress,
+ .decompress = nx842_powernv_decompress,
+};
+
+static __init int nx842_powernv_init(void)
+{
+ struct device_node *dn;
+
+ /* verify workmem size/align restrictions */
+ BUILD_BUG_ON(WORKMEM_ALIGN % CRB_ALIGN);
+ BUILD_BUG_ON(CRB_ALIGN % DDE_ALIGN);
+ BUILD_BUG_ON(CRB_SIZE % DDE_ALIGN);
+ /* verify buffer size/align restrictions */
+ BUILD_BUG_ON(PAGE_SIZE % DDE_BUFFER_ALIGN);
+ BUILD_BUG_ON(DDE_BUFFER_ALIGN % DDE_BUFFER_SIZE_MULT);
+ BUILD_BUG_ON(DDE_BUFFER_SIZE_MULT % DDE_BUFFER_LAST_MULT);
+
+ pr_info("loading\n");
+
+ for_each_compatible_node(dn, NULL, "ibm,power-nx")
+ nx842_powernv_probe(dn);
+
+ if (!nx842_ct) {
+ pr_err("no coprocessors found\n");
+ return -ENODEV;
+ }
+
+ if (!nx842_platform_driver_set(&nx842_powernv_driver)) {
+ struct nx842_coproc *coproc, *n;
+
+ list_for_each_entry_safe(coproc, n, &nx842_coprocs, list) {
+ list_del(&coproc->list);
+ kfree(coproc);
+ }
+
+ return -EEXIST;
+ }
+
+ pr_info("loaded\n");
+
+ return 0;
+}
+module_init(nx842_powernv_init);
+
+static void __exit nx842_powernv_exit(void)
+{
+ struct nx842_coproc *coproc, *n;
+
+ nx842_platform_driver_unset(&nx842_powernv_driver);
+
+ list_for_each_entry_safe(coproc, n, &nx842_coprocs, list) {
+ list_del(&coproc->list);
+ kfree(coproc);
+ }
+
+ pr_info("unloaded\n");
+}
+module_exit(nx842_powernv_exit);
diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c
new file mode 100644
index 000000000000..3040a6091bf2
--- /dev/null
+++ b/drivers/crypto/nx/nx-842-pseries.c
@@ -0,0 +1,1140 @@
+/*
+ * Driver for IBM Power 842 compression accelerator
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright (C) IBM Corporation, 2012
+ *
+ * Authors: Robert Jennings <rcj@linux.vnet.ibm.com>
+ * Seth Jennings <sjenning@linux.vnet.ibm.com>
+ */
+
+#include <asm/vio.h>
+
+#include "nx-842.h"
+#include "nx_csbcpb.h" /* struct nx_csbcpb */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robert Jennings <rcj@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("842 H/W Compression driver for IBM Power processors");
+
+static struct nx842_constraints nx842_pseries_constraints = {
+ .alignment = DDE_BUFFER_ALIGN,
+ .multiple = DDE_BUFFER_LAST_MULT,
+ .minimum = DDE_BUFFER_LAST_MULT,
+ .maximum = PAGE_SIZE, /* dynamic, max_sync_size */
+};
+
+static int check_constraints(unsigned long buf, unsigned int *len, bool in)
+{
+ if (!IS_ALIGNED(buf, nx842_pseries_constraints.alignment)) {
+ pr_debug("%s buffer 0x%lx not aligned to 0x%x\n",
+ in ? "input" : "output", buf,
+ nx842_pseries_constraints.alignment);
+ return -EINVAL;
+ }
+ if (*len % nx842_pseries_constraints.multiple) {
+ pr_debug("%s buffer len 0x%x not multiple of 0x%x\n",
+ in ? "input" : "output", *len,
+ nx842_pseries_constraints.multiple);
+ if (in)
+ return -EINVAL;
+ *len = round_down(*len, nx842_pseries_constraints.multiple);
+ }
+ if (*len < nx842_pseries_constraints.minimum) {
+ pr_debug("%s buffer len 0x%x under minimum 0x%x\n",
+ in ? "input" : "output", *len,
+ nx842_pseries_constraints.minimum);
+ return -EINVAL;
+ }
+ if (*len > nx842_pseries_constraints.maximum) {
+ pr_debug("%s buffer len 0x%x over maximum 0x%x\n",
+ in ? "input" : "output", *len,
+ nx842_pseries_constraints.maximum);
+ if (in)
+ return -EINVAL;
+ *len = nx842_pseries_constraints.maximum;
+ }
+ return 0;
+}
+
+/* I assume we need to align the CSB? */
+#define WORKMEM_ALIGN (256)
+
+struct nx842_workmem {
+ /* scatterlist */
+ char slin[4096];
+ char slout[4096];
+ /* coprocessor status/parameter block */
+ struct nx_csbcpb csbcpb;
+
+ char padding[WORKMEM_ALIGN];
+} __aligned(WORKMEM_ALIGN);
+
+/* Macros for fields within nx_csbcpb */
+/* Check the valid bit within the csbcpb valid field */
+#define NX842_CSBCBP_VALID_CHK(x) (x & BIT_MASK(7))
+
+/* CE macros operate on the completion_extension field bits in the csbcpb.
+ * CE0 0=full completion, 1=partial completion
+ * CE1 0=CE0 indicates completion, 1=termination (output may be modified)
+ * CE2 0=processed_bytes is source bytes, 1=processed_bytes is target bytes */
+#define NX842_CSBCPB_CE0(x) (x & BIT_MASK(7))
+#define NX842_CSBCPB_CE1(x) (x & BIT_MASK(6))
+#define NX842_CSBCPB_CE2(x) (x & BIT_MASK(5))
+
+/* The NX unit accepts data only on 4K page boundaries */
+#define NX842_HW_PAGE_SIZE (4096)
+#define NX842_HW_PAGE_MASK (~(NX842_HW_PAGE_SIZE-1))
+
+enum nx842_status {
+ UNAVAILABLE,
+ AVAILABLE
+};
+
+struct ibm_nx842_counters {
+ atomic64_t comp_complete;
+ atomic64_t comp_failed;
+ atomic64_t decomp_complete;
+ atomic64_t decomp_failed;
+ atomic64_t swdecomp;
+ atomic64_t comp_times[32];
+ atomic64_t decomp_times[32];
+};
+
+static struct nx842_devdata {
+ struct vio_dev *vdev;
+ struct device *dev;
+ struct ibm_nx842_counters *counters;
+ unsigned int max_sg_len;
+ unsigned int max_sync_size;
+ unsigned int max_sync_sg;
+ enum nx842_status status;
+} __rcu *devdata;
+static DEFINE_SPINLOCK(devdata_mutex);
+
+#define NX842_COUNTER_INC(_x) \
+static inline void nx842_inc_##_x( \
+ const struct nx842_devdata *dev) { \
+ if (dev) \
+ atomic64_inc(&dev->counters->_x); \
+}
+NX842_COUNTER_INC(comp_complete);
+NX842_COUNTER_INC(comp_failed);
+NX842_COUNTER_INC(decomp_complete);
+NX842_COUNTER_INC(decomp_failed);
+NX842_COUNTER_INC(swdecomp);
+
+#define NX842_HIST_SLOTS 16
+
+static void ibm_nx842_incr_hist(atomic64_t *times, unsigned int time)
+{
+ int bucket = fls(time);
+
+ if (bucket)
+ bucket = min((NX842_HIST_SLOTS - 1), bucket - 1);
+
+ atomic64_inc(&times[bucket]);
+}
+
+/* NX unit operation flags */
+#define NX842_OP_COMPRESS 0x0
+#define NX842_OP_CRC 0x1
+#define NX842_OP_DECOMPRESS 0x2
+#define NX842_OP_COMPRESS_CRC (NX842_OP_COMPRESS | NX842_OP_CRC)
+#define NX842_OP_DECOMPRESS_CRC (NX842_OP_DECOMPRESS | NX842_OP_CRC)
+#define NX842_OP_ASYNC (1<<23)
+#define NX842_OP_NOTIFY (1<<22)
+#define NX842_OP_NOTIFY_INT(x) ((x & 0xff)<<8)
+
+static unsigned long nx842_get_desired_dma(struct vio_dev *viodev)
+{
+ /* No use of DMA mappings within the driver. */
+ return 0;
+}
+
+struct nx842_slentry {
+ __be64 ptr; /* Real address (use __pa()) */
+ __be64 len;
+};
+
+/* pHyp scatterlist entry */
+struct nx842_scatterlist {
+ int entry_nr; /* number of slentries */
+ struct nx842_slentry *entries; /* ptr to array of slentries */
+};
+
+/* Does not include sizeof(entry_nr) in the size */
+static inline unsigned long nx842_get_scatterlist_size(
+ struct nx842_scatterlist *sl)
+{
+ return sl->entry_nr * sizeof(struct nx842_slentry);
+}
+
+static int nx842_build_scatterlist(unsigned long buf, int len,
+ struct nx842_scatterlist *sl)
+{
+ unsigned long entrylen;
+ struct nx842_slentry *entry;
+
+ sl->entry_nr = 0;
+
+ entry = sl->entries;
+ while (len) {
+ entry->ptr = cpu_to_be64(nx842_get_pa((void *)buf));
+ entrylen = min_t(int, len,
+ LEN_ON_SIZE(buf, NX842_HW_PAGE_SIZE));
+ entry->len = cpu_to_be64(entrylen);
+
+ len -= entrylen;
+ buf += entrylen;
+
+ sl->entry_nr++;
+ entry++;
+ }
+
+ return 0;
+}
+
+static int nx842_validate_result(struct device *dev,
+ struct cop_status_block *csb)
+{
+ /* The csb must be valid after returning from vio_h_cop_sync */
+ if (!NX842_CSBCBP_VALID_CHK(csb->valid)) {
+ dev_err(dev, "%s: cspcbp not valid upon completion.\n",
+ __func__);
+ dev_dbg(dev, "valid:0x%02x cs:0x%02x cc:0x%02x ce:0x%02x\n",
+ csb->valid,
+ csb->crb_seq_number,
+ csb->completion_code,
+ csb->completion_extension);
+ dev_dbg(dev, "processed_bytes:%d address:0x%016lx\n",
+ be32_to_cpu(csb->processed_byte_count),
+ (unsigned long)be64_to_cpu(csb->address));
+ return -EIO;
+ }
+
+ /* Check return values from the hardware in the CSB */
+ switch (csb->completion_code) {
+ case 0: /* Completed without error */
+ break;
+ case 64: /* Target bytes > Source bytes during compression */
+ case 13: /* Output buffer too small */
+ dev_dbg(dev, "%s: Compression output larger than input\n",
+ __func__);
+ return -ENOSPC;
+ case 66: /* Input data contains an illegal template field */
+ case 67: /* Template indicates data past the end of the input stream */
+ dev_dbg(dev, "%s: Bad data for decompression (code:%d)\n",
+ __func__, csb->completion_code);
+ return -EINVAL;
+ default:
+ dev_dbg(dev, "%s: Unspecified error (code:%d)\n",
+ __func__, csb->completion_code);
+ return -EIO;
+ }
+
+ /* Hardware sanity check */
+ if (!NX842_CSBCPB_CE2(csb->completion_extension)) {
+ dev_err(dev, "%s: No error returned by hardware, but "
+ "data returned is unusable, contact support.\n"
+ "(Additional info: csbcbp->processed bytes "
+ "does not specify processed bytes for the "
+ "target buffer.)\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * nx842_pseries_compress - Compress data using the 842 algorithm
+ *
+ * Compression provide by the NX842 coprocessor on IBM Power systems.
+ * The input buffer is compressed and the result is stored in the
+ * provided output buffer.
+ *
+ * Upon return from this function @outlen contains the length of the
+ * compressed data. If there is an error then @outlen will be 0 and an
+ * error will be specified by the return code from this function.
+ *
+ * @in: Pointer to input buffer
+ * @inlen: Length of input buffer
+ * @out: Pointer to output buffer
+ * @outlen: Length of output buffer
+ * @wrkmem: ptr to buffer for working memory, size determined by
+ * nx842_pseries_driver.workmem_size
+ *
+ * Returns:
+ * 0 Success, output of length @outlen stored in the buffer at @out
+ * -ENOMEM Unable to allocate internal buffers
+ * -ENOSPC Output buffer is to small
+ * -EIO Internal error
+ * -ENODEV Hardware unavailable
+ */
+static int nx842_pseries_compress(const unsigned char *in, unsigned int inlen,
+ unsigned char *out, unsigned int *outlen,
+ void *wmem)
+{
+ struct nx842_devdata *local_devdata;
+ struct device *dev = NULL;
+ struct nx842_workmem *workmem;
+ struct nx842_scatterlist slin, slout;
+ struct nx_csbcpb *csbcpb;
+ int ret = 0, max_sync_size;
+ unsigned long inbuf, outbuf;
+ struct vio_pfo_op op = {
+ .done = NULL,
+ .handle = 0,
+ .timeout = 0,
+ };
+ unsigned long start = get_tb();
+
+ inbuf = (unsigned long)in;
+ if (check_constraints(inbuf, &inlen, true))
+ return -EINVAL;
+
+ outbuf = (unsigned long)out;
+ if (check_constraints(outbuf, outlen, false))
+ return -EINVAL;
+
+ rcu_read_lock();
+ local_devdata = rcu_dereference(devdata);
+ if (!local_devdata || !local_devdata->dev) {
+ rcu_read_unlock();
+ return -ENODEV;
+ }
+ max_sync_size = local_devdata->max_sync_size;
+ dev = local_devdata->dev;
+
+ /* Init scatterlist */
+ workmem = PTR_ALIGN(wmem, WORKMEM_ALIGN);
+ slin.entries = (struct nx842_slentry *)workmem->slin;
+ slout.entries = (struct nx842_slentry *)workmem->slout;
+
+ /* Init operation */
+ op.flags = NX842_OP_COMPRESS;
+ csbcpb = &workmem->csbcpb;
+ memset(csbcpb, 0, sizeof(*csbcpb));
+ op.csbcpb = nx842_get_pa(csbcpb);
+
+ if ((inbuf & NX842_HW_PAGE_MASK) ==
+ ((inbuf + inlen - 1) & NX842_HW_PAGE_MASK)) {
+ /* Create direct DDE */
+ op.in = nx842_get_pa((void *)inbuf);
+ op.inlen = inlen;
+ } else {
+ /* Create indirect DDE (scatterlist) */
+ nx842_build_scatterlist(inbuf, inlen, &slin);
+ op.in = nx842_get_pa(slin.entries);
+ op.inlen = -nx842_get_scatterlist_size(&slin);
+ }
+
+ if ((outbuf & NX842_HW_PAGE_MASK) ==
+ ((outbuf + *outlen - 1) & NX842_HW_PAGE_MASK)) {
+ /* Create direct DDE */
+ op.out = nx842_get_pa((void *)outbuf);
+ op.outlen = *outlen;
+ } else {
+ /* Create indirect DDE (scatterlist) */
+ nx842_build_scatterlist(outbuf, *outlen, &slout);
+ op.out = nx842_get_pa(slout.entries);
+ op.outlen = -nx842_get_scatterlist_size(&slout);
+ }
+
+ dev_dbg(dev, "%s: op.in %lx op.inlen %ld op.out %lx op.outlen %ld\n",
+ __func__, (unsigned long)op.in, (long)op.inlen,
+ (unsigned long)op.out, (long)op.outlen);
+
+ /* Send request to pHyp */
+ ret = vio_h_cop_sync(local_devdata->vdev, &op);
+
+ /* Check for pHyp error */
+ if (ret) {
+ dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n",
+ __func__, ret, op.hcall_err);
+ ret = -EIO;
+ goto unlock;
+ }
+
+ /* Check for hardware error */
+ ret = nx842_validate_result(dev, &csbcpb->csb);
+ if (ret)
+ goto unlock;
+
+ *outlen = be32_to_cpu(csbcpb->csb.processed_byte_count);
+ dev_dbg(dev, "%s: processed_bytes=%d\n", __func__, *outlen);
+
+unlock:
+ if (ret)
+ nx842_inc_comp_failed(local_devdata);
+ else {
+ nx842_inc_comp_complete(local_devdata);
+ ibm_nx842_incr_hist(local_devdata->counters->comp_times,
+ (get_tb() - start) / tb_ticks_per_usec);
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+/**
+ * nx842_pseries_decompress - Decompress data using the 842 algorithm
+ *
+ * Decompression provide by the NX842 coprocessor on IBM Power systems.
+ * The input buffer is decompressed and the result is stored in the
+ * provided output buffer. The size allocated to the output buffer is
+ * provided by the caller of this function in @outlen. Upon return from
+ * this function @outlen contains the length of the decompressed data.
+ * If there is an error then @outlen will be 0 and an error will be
+ * specified by the return code from this function.
+ *
+ * @in: Pointer to input buffer
+ * @inlen: Length of input buffer
+ * @out: Pointer to output buffer
+ * @outlen: Length of output buffer
+ * @wrkmem: ptr to buffer for working memory, size determined by
+ * nx842_pseries_driver.workmem_size
+ *
+ * Returns:
+ * 0 Success, output of length @outlen stored in the buffer at @out
+ * -ENODEV Hardware decompression device is unavailable
+ * -ENOMEM Unable to allocate internal buffers
+ * -ENOSPC Output buffer is to small
+ * -EINVAL Bad input data encountered when attempting decompress
+ * -EIO Internal error
+ */
+static int nx842_pseries_decompress(const unsigned char *in, unsigned int inlen,
+ unsigned char *out, unsigned int *outlen,
+ void *wmem)
+{
+ struct nx842_devdata *local_devdata;
+ struct device *dev = NULL;
+ struct nx842_workmem *workmem;
+ struct nx842_scatterlist slin, slout;
+ struct nx_csbcpb *csbcpb;
+ int ret = 0, max_sync_size;
+ unsigned long inbuf, outbuf;
+ struct vio_pfo_op op = {
+ .done = NULL,
+ .handle = 0,
+ .timeout = 0,
+ };
+ unsigned long start = get_tb();
+
+ /* Ensure page alignment and size */
+ inbuf = (unsigned long)in;
+ if (check_constraints(inbuf, &inlen, true))
+ return -EINVAL;
+
+ outbuf = (unsigned long)out;
+ if (check_constraints(outbuf, outlen, false))
+ return -EINVAL;
+
+ rcu_read_lock();
+ local_devdata = rcu_dereference(devdata);
+ if (!local_devdata || !local_devdata->dev) {
+ rcu_read_unlock();
+ return -ENODEV;
+ }
+ max_sync_size = local_devdata->max_sync_size;
+ dev = local_devdata->dev;
+
+ workmem = PTR_ALIGN(wmem, WORKMEM_ALIGN);
+
+ /* Init scatterlist */
+ slin.entries = (struct nx842_slentry *)workmem->slin;
+ slout.entries = (struct nx842_slentry *)workmem->slout;
+
+ /* Init operation */
+ op.flags = NX842_OP_DECOMPRESS;
+ csbcpb = &workmem->csbcpb;
+ memset(csbcpb, 0, sizeof(*csbcpb));
+ op.csbcpb = nx842_get_pa(csbcpb);
+
+ if ((inbuf & NX842_HW_PAGE_MASK) ==
+ ((inbuf + inlen - 1) & NX842_HW_PAGE_MASK)) {
+ /* Create direct DDE */
+ op.in = nx842_get_pa((void *)inbuf);
+ op.inlen = inlen;
+ } else {
+ /* Create indirect DDE (scatterlist) */
+ nx842_build_scatterlist(inbuf, inlen, &slin);
+ op.in = nx842_get_pa(slin.entries);
+ op.inlen = -nx842_get_scatterlist_size(&slin);
+ }
+
+ if ((outbuf & NX842_HW_PAGE_MASK) ==
+ ((outbuf + *outlen - 1) & NX842_HW_PAGE_MASK)) {
+ /* Create direct DDE */
+ op.out = nx842_get_pa((void *)outbuf);
+ op.outlen = *outlen;
+ } else {
+ /* Create indirect DDE (scatterlist) */
+ nx842_build_scatterlist(outbuf, *outlen, &slout);
+ op.out = nx842_get_pa(slout.entries);
+ op.outlen = -nx842_get_scatterlist_size(&slout);
+ }
+
+ dev_dbg(dev, "%s: op.in %lx op.inlen %ld op.out %lx op.outlen %ld\n",
+ __func__, (unsigned long)op.in, (long)op.inlen,
+ (unsigned long)op.out, (long)op.outlen);
+
+ /* Send request to pHyp */
+ ret = vio_h_cop_sync(local_devdata->vdev, &op);
+
+ /* Check for pHyp error */
+ if (ret) {
+ dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n",
+ __func__, ret, op.hcall_err);
+ goto unlock;
+ }
+
+ /* Check for hardware error */
+ ret = nx842_validate_result(dev, &csbcpb->csb);
+ if (ret)
+ goto unlock;
+
+ *outlen = be32_to_cpu(csbcpb->csb.processed_byte_count);
+
+unlock:
+ if (ret)
+ /* decompress fail */
+ nx842_inc_decomp_failed(local_devdata);
+ else {
+ nx842_inc_decomp_complete(local_devdata);
+ ibm_nx842_incr_hist(local_devdata->counters->decomp_times,
+ (get_tb() - start) / tb_ticks_per_usec);
+ }
+
+ rcu_read_unlock();
+ return ret;
+}
+
+/**
+ * nx842_OF_set_defaults -- Set default (disabled) values for devdata
+ *
+ * @devdata - struct nx842_devdata to update
+ *
+ * Returns:
+ * 0 on success
+ * -ENOENT if @devdata ptr is NULL
+ */
+static int nx842_OF_set_defaults(struct nx842_devdata *devdata)
+{
+ if (devdata) {
+ devdata->max_sync_size = 0;
+ devdata->max_sync_sg = 0;
+ devdata->max_sg_len = 0;
+ devdata->status = UNAVAILABLE;
+ return 0;
+ } else
+ return -ENOENT;
+}
+
+/**
+ * nx842_OF_upd_status -- Update the device info from OF status prop
+ *
+ * The status property indicates if the accelerator is enabled. If the
+ * device is in the OF tree it indicates that the hardware is present.
+ * The status field indicates if the device is enabled when the status
+ * is 'okay'. Otherwise the device driver will be disabled.
+ *
+ * @devdata - struct nx842_devdata to update
+ * @prop - struct property point containing the maxsyncop for the update
+ *
+ * Returns:
+ * 0 - Device is available
+ * -EINVAL - Device is not available
+ */
+static int nx842_OF_upd_status(struct nx842_devdata *devdata,
+ struct property *prop) {
+ int ret = 0;
+ const char *status = (const char *)prop->value;
+
+ if (!strncmp(status, "okay", (size_t)prop->length)) {
+ devdata->status = AVAILABLE;
+ } else {
+ dev_info(devdata->dev, "%s: status '%s' is not 'okay'\n",
+ __func__, status);
+ devdata->status = UNAVAILABLE;
+ }
+
+ return ret;
+}
+
+/**
+ * nx842_OF_upd_maxsglen -- Update the device info from OF maxsglen prop
+ *
+ * Definition of the 'ibm,max-sg-len' OF property:
+ * This field indicates the maximum byte length of a scatter list
+ * for the platform facility. It is a single cell encoded as with encode-int.
+ *
+ * Example:
+ * # od -x ibm,max-sg-len
+ * 0000000 0000 0ff0
+ *
+ * In this example, the maximum byte length of a scatter list is
+ * 0x0ff0 (4,080).
+ *
+ * @devdata - struct nx842_devdata to update
+ * @prop - struct property point containing the maxsyncop for the update
+ *
+ * Returns:
+ * 0 on success
+ * -EINVAL on failure
+ */
+static int nx842_OF_upd_maxsglen(struct nx842_devdata *devdata,
+ struct property *prop) {
+ int ret = 0;
+ const unsigned int maxsglen = of_read_number(prop->value, 1);
+
+ if (prop->length != sizeof(maxsglen)) {
+ dev_err(devdata->dev, "%s: unexpected format for ibm,max-sg-len property\n", __func__);
+ dev_dbg(devdata->dev, "%s: ibm,max-sg-len is %d bytes long, expected %lu bytes\n", __func__,
+ prop->length, sizeof(maxsglen));
+ ret = -EINVAL;
+ } else {
+ devdata->max_sg_len = min_t(unsigned int,
+ maxsglen, NX842_HW_PAGE_SIZE);
+ }
+
+ return ret;
+}
+
+/**
+ * nx842_OF_upd_maxsyncop -- Update the device info from OF maxsyncop prop
+ *
+ * Definition of the 'ibm,max-sync-cop' OF property:
+ * Two series of cells. The first series of cells represents the maximums
+ * that can be synchronously compressed. The second series of cells
+ * represents the maximums that can be synchronously decompressed.
+ * 1. The first cell in each series contains the count of the number of
+ * data length, scatter list elements pairs that follow – each being
+ * of the form
+ * a. One cell data byte length
+ * b. One cell total number of scatter list elements
+ *
+ * Example:
+ * # od -x ibm,max-sync-cop
+ * 0000000 0000 0001 0000 1000 0000 01fe 0000 0001
+ * 0000020 0000 1000 0000 01fe
+ *
+ * In this example, compression supports 0x1000 (4,096) data byte length
+ * and 0x1fe (510) total scatter list elements. Decompression supports
+ * 0x1000 (4,096) data byte length and 0x1f3 (510) total scatter list
+ * elements.
+ *
+ * @devdata - struct nx842_devdata to update
+ * @prop - struct property point containing the maxsyncop for the update
+ *
+ * Returns:
+ * 0 on success
+ * -EINVAL on failure
+ */
+static int nx842_OF_upd_maxsyncop(struct nx842_devdata *devdata,
+ struct property *prop) {
+ int ret = 0;
+ unsigned int comp_data_limit, decomp_data_limit;
+ unsigned int comp_sg_limit, decomp_sg_limit;
+ const struct maxsynccop_t {
+ __be32 comp_elements;
+ __be32 comp_data_limit;
+ __be32 comp_sg_limit;
+ __be32 decomp_elements;
+ __be32 decomp_data_limit;
+ __be32 decomp_sg_limit;
+ } *maxsynccop;
+
+ if (prop->length != sizeof(*maxsynccop)) {
+ dev_err(devdata->dev, "%s: unexpected format for ibm,max-sync-cop property\n", __func__);
+ dev_dbg(devdata->dev, "%s: ibm,max-sync-cop is %d bytes long, expected %lu bytes\n", __func__, prop->length,
+ sizeof(*maxsynccop));
+ ret = -EINVAL;
+ goto out;
+ }
+
+ maxsynccop = (const struct maxsynccop_t *)prop->value;
+ comp_data_limit = be32_to_cpu(maxsynccop->comp_data_limit);
+ comp_sg_limit = be32_to_cpu(maxsynccop->comp_sg_limit);
+ decomp_data_limit = be32_to_cpu(maxsynccop->decomp_data_limit);
+ decomp_sg_limit = be32_to_cpu(maxsynccop->decomp_sg_limit);
+
+ /* Use one limit rather than separate limits for compression and
+ * decompression. Set a maximum for this so as not to exceed the
+ * size that the header can support and round the value down to
+ * the hardware page size (4K) */
+ devdata->max_sync_size = min(comp_data_limit, decomp_data_limit);
+
+ devdata->max_sync_size = min_t(unsigned int, devdata->max_sync_size,
+ 65536);
+
+ if (devdata->max_sync_size < 4096) {
+ dev_err(devdata->dev, "%s: hardware max data size (%u) is "
+ "less than the driver minimum, unable to use "
+ "the hardware device\n",
+ __func__, devdata->max_sync_size);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ nx842_pseries_constraints.maximum = devdata->max_sync_size;
+
+ devdata->max_sync_sg = min(comp_sg_limit, decomp_sg_limit);
+ if (devdata->max_sync_sg < 1) {
+ dev_err(devdata->dev, "%s: hardware max sg size (%u) is "
+ "less than the driver minimum, unable to use "
+ "the hardware device\n",
+ __func__, devdata->max_sync_sg);
+ ret = -EINVAL;
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+/**
+ *
+ * nx842_OF_upd -- Handle OF properties updates for the device.
+ *
+ * Set all properties from the OF tree. Optionally, a new property
+ * can be provided by the @new_prop pointer to overwrite an existing value.
+ * The device will remain disabled until all values are valid, this function
+ * will return an error for updates unless all values are valid.
+ *
+ * @new_prop: If not NULL, this property is being updated. If NULL, update
+ * all properties from the current values in the OF tree.
+ *
+ * Returns:
+ * 0 - Success
+ * -ENOMEM - Could not allocate memory for new devdata structure
+ * -EINVAL - property value not found, new_prop is not a recognized
+ * property for the device or property value is not valid.
+ * -ENODEV - Device is not available
+ */
+static int nx842_OF_upd(struct property *new_prop)
+{
+ struct nx842_devdata *old_devdata = NULL;
+ struct nx842_devdata *new_devdata = NULL;
+ struct device_node *of_node = NULL;
+ struct property *status = NULL;
+ struct property *maxsglen = NULL;
+ struct property *maxsyncop = NULL;
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&devdata_mutex, flags);
+ old_devdata = rcu_dereference_check(devdata,
+ lockdep_is_held(&devdata_mutex));
+ if (old_devdata)
+ of_node = old_devdata->dev->of_node;
+
+ if (!old_devdata || !of_node) {
+ pr_err("%s: device is not available\n", __func__);
+ spin_unlock_irqrestore(&devdata_mutex, flags);
+ return -ENODEV;
+ }
+
+ new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS);
+ if (!new_devdata) {
+ dev_err(old_devdata->dev, "%s: Could not allocate memory for device data\n", __func__);
+ ret = -ENOMEM;
+ goto error_out;
+ }
+
+ memcpy(new_devdata, old_devdata, sizeof(*old_devdata));
+ new_devdata->counters = old_devdata->counters;
+
+ /* Set ptrs for existing properties */
+ status = of_find_property(of_node, "status", NULL);
+ maxsglen = of_find_property(of_node, "ibm,max-sg-len", NULL);
+ maxsyncop = of_find_property(of_node, "ibm,max-sync-cop", NULL);
+ if (!status || !maxsglen || !maxsyncop) {
+ dev_err(old_devdata->dev, "%s: Could not locate device properties\n", __func__);
+ ret = -EINVAL;
+ goto error_out;
+ }
+
+ /*
+ * If this is a property update, there are only certain properties that
+ * we care about. Bail if it isn't in the below list
+ */
+ if (new_prop && (strncmp(new_prop->name, "status", new_prop->length) ||
+ strncmp(new_prop->name, "ibm,max-sg-len", new_prop->length) ||
+ strncmp(new_prop->name, "ibm,max-sync-cop", new_prop->length)))
+ goto out;
+
+ /* Perform property updates */
+ ret = nx842_OF_upd_status(new_devdata, status);
+ if (ret)
+ goto error_out;
+
+ ret = nx842_OF_upd_maxsglen(new_devdata, maxsglen);
+ if (ret)
+ goto error_out;
+
+ ret = nx842_OF_upd_maxsyncop(new_devdata, maxsyncop);
+ if (ret)
+ goto error_out;
+
+out:
+ dev_info(old_devdata->dev, "%s: max_sync_size new:%u old:%u\n",
+ __func__, new_devdata->max_sync_size,
+ old_devdata->max_sync_size);
+ dev_info(old_devdata->dev, "%s: max_sync_sg new:%u old:%u\n",
+ __func__, new_devdata->max_sync_sg,
+ old_devdata->max_sync_sg);
+ dev_info(old_devdata->dev, "%s: max_sg_len new:%u old:%u\n",
+ __func__, new_devdata->max_sg_len,
+ old_devdata->max_sg_len);
+
+ rcu_assign_pointer(devdata, new_devdata);
+ spin_unlock_irqrestore(&devdata_mutex, flags);
+ synchronize_rcu();
+ dev_set_drvdata(new_devdata->dev, new_devdata);
+ kfree(old_devdata);
+ return 0;
+
+error_out:
+ if (new_devdata) {
+ dev_info(old_devdata->dev, "%s: device disabled\n", __func__);
+ nx842_OF_set_defaults(new_devdata);
+ rcu_assign_pointer(devdata, new_devdata);
+ spin_unlock_irqrestore(&devdata_mutex, flags);
+ synchronize_rcu();
+ dev_set_drvdata(new_devdata->dev, new_devdata);
+ kfree(old_devdata);
+ } else {
+ dev_err(old_devdata->dev, "%s: could not update driver from hardware\n", __func__);
+ spin_unlock_irqrestore(&devdata_mutex, flags);
+ }
+
+ if (!ret)
+ ret = -EINVAL;
+ return ret;
+}
+
+/**
+ * nx842_OF_notifier - Process updates to OF properties for the device
+ *
+ * @np: notifier block
+ * @action: notifier action
+ * @update: struct pSeries_reconfig_prop_update pointer if action is
+ * PSERIES_UPDATE_PROPERTY
+ *
+ * Returns:
+ * NOTIFY_OK on success
+ * NOTIFY_BAD encoded with error number on failure, use
+ * notifier_to_errno() to decode this value
+ */
+static int nx842_OF_notifier(struct notifier_block *np, unsigned long action,
+ void *data)
+{
+ struct of_reconfig_data *upd = data;
+ struct nx842_devdata *local_devdata;
+ struct device_node *node = NULL;
+
+ rcu_read_lock();
+ local_devdata = rcu_dereference(devdata);
+ if (local_devdata)
+ node = local_devdata->dev->of_node;
+
+ if (local_devdata &&
+ action == OF_RECONFIG_UPDATE_PROPERTY &&
+ !strcmp(upd->dn->name, node->name)) {
+ rcu_read_unlock();
+ nx842_OF_upd(upd->prop);
+ } else
+ rcu_read_unlock();
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block nx842_of_nb = {
+ .notifier_call = nx842_OF_notifier,
+};
+
+#define nx842_counter_read(_name) \
+static ssize_t nx842_##_name##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) { \
+ struct nx842_devdata *local_devdata; \
+ int p = 0; \
+ rcu_read_lock(); \
+ local_devdata = rcu_dereference(devdata); \
+ if (local_devdata) \
+ p = snprintf(buf, PAGE_SIZE, "%ld\n", \
+ atomic64_read(&local_devdata->counters->_name)); \
+ rcu_read_unlock(); \
+ return p; \
+}
+
+#define NX842DEV_COUNTER_ATTR_RO(_name) \
+ nx842_counter_read(_name); \
+ static struct device_attribute dev_attr_##_name = __ATTR(_name, \
+ 0444, \
+ nx842_##_name##_show,\
+ NULL);
+
+NX842DEV_COUNTER_ATTR_RO(comp_complete);
+NX842DEV_COUNTER_ATTR_RO(comp_failed);
+NX842DEV_COUNTER_ATTR_RO(decomp_complete);
+NX842DEV_COUNTER_ATTR_RO(decomp_failed);
+NX842DEV_COUNTER_ATTR_RO(swdecomp);
+
+static ssize_t nx842_timehist_show(struct device *,
+ struct device_attribute *, char *);
+
+static struct device_attribute dev_attr_comp_times = __ATTR(comp_times, 0444,
+ nx842_timehist_show, NULL);
+static struct device_attribute dev_attr_decomp_times = __ATTR(decomp_times,
+ 0444, nx842_timehist_show, NULL);
+
+static ssize_t nx842_timehist_show(struct device *dev,
+ struct device_attribute *attr, char *buf) {
+ char *p = buf;
+ struct nx842_devdata *local_devdata;
+ atomic64_t *times;
+ int bytes_remain = PAGE_SIZE;
+ int bytes;
+ int i;
+
+ rcu_read_lock();
+ local_devdata = rcu_dereference(devdata);
+ if (!local_devdata) {
+ rcu_read_unlock();
+ return 0;
+ }
+
+ if (attr == &dev_attr_comp_times)
+ times = local_devdata->counters->comp_times;
+ else if (attr == &dev_attr_decomp_times)
+ times = local_devdata->counters->decomp_times;
+ else {
+ rcu_read_unlock();
+ return 0;
+ }
+
+ for (i = 0; i < (NX842_HIST_SLOTS - 2); i++) {
+ bytes = snprintf(p, bytes_remain, "%u-%uus:\t%ld\n",
+ i ? (2<<(i-1)) : 0, (2<<i)-1,
+ atomic64_read(&times[i]));
+ bytes_remain -= bytes;
+ p += bytes;
+ }
+ /* The last bucket holds everything over
+ * 2<<(NX842_HIST_SLOTS - 2) us */
+ bytes = snprintf(p, bytes_remain, "%uus - :\t%ld\n",
+ 2<<(NX842_HIST_SLOTS - 2),
+ atomic64_read(&times[(NX842_HIST_SLOTS - 1)]));
+ p += bytes;
+
+ rcu_read_unlock();
+ return p - buf;
+}
+
+static struct attribute *nx842_sysfs_entries[] = {
+ &dev_attr_comp_complete.attr,
+ &dev_attr_comp_failed.attr,
+ &dev_attr_decomp_complete.attr,
+ &dev_attr_decomp_failed.attr,
+ &dev_attr_swdecomp.attr,
+ &dev_attr_comp_times.attr,
+ &dev_attr_decomp_times.attr,
+ NULL,
+};
+
+static struct attribute_group nx842_attribute_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = nx842_sysfs_entries,
+};
+
+static struct nx842_driver nx842_pseries_driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .workmem_size = sizeof(struct nx842_workmem),
+ .constraints = &nx842_pseries_constraints,
+ .compress = nx842_pseries_compress,
+ .decompress = nx842_pseries_decompress,
+};
+
+static int __init nx842_probe(struct vio_dev *viodev,
+ const struct vio_device_id *id)
+{
+ struct nx842_devdata *old_devdata, *new_devdata = NULL;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&devdata_mutex, flags);
+ old_devdata = rcu_dereference_check(devdata,
+ lockdep_is_held(&devdata_mutex));
+
+ if (old_devdata && old_devdata->vdev != NULL) {
+ dev_err(&viodev->dev, "%s: Attempt to register more than one instance of the hardware\n", __func__);
+ ret = -1;
+ goto error_unlock;
+ }
+
+ dev_set_drvdata(&viodev->dev, NULL);
+
+ new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS);
+ if (!new_devdata) {
+ dev_err(&viodev->dev, "%s: Could not allocate memory for device data\n", __func__);
+ ret = -ENOMEM;
+ goto error_unlock;
+ }
+
+ new_devdata->counters = kzalloc(sizeof(*new_devdata->counters),
+ GFP_NOFS);
+ if (!new_devdata->counters) {
+ dev_err(&viodev->dev, "%s: Could not allocate memory for performance counters\n", __func__);
+ ret = -ENOMEM;
+ goto error_unlock;
+ }
+
+ new_devdata->vdev = viodev;
+ new_devdata->dev = &viodev->dev;
+ nx842_OF_set_defaults(new_devdata);
+
+ rcu_assign_pointer(devdata, new_devdata);
+ spin_unlock_irqrestore(&devdata_mutex, flags);
+ synchronize_rcu();
+ kfree(old_devdata);
+
+ of_reconfig_notifier_register(&nx842_of_nb);
+
+ ret = nx842_OF_upd(NULL);
+ if (ret && ret != -ENODEV) {
+ dev_err(&viodev->dev, "could not parse device tree. %d\n", ret);
+ ret = -1;
+ goto error;
+ }
+
+ rcu_read_lock();
+ dev_set_drvdata(&viodev->dev, rcu_dereference(devdata));
+ rcu_read_unlock();
+
+ if (sysfs_create_group(&viodev->dev.kobj, &nx842_attribute_group)) {
+ dev_err(&viodev->dev, "could not create sysfs device attributes\n");
+ ret = -1;
+ goto error;
+ }
+
+ return 0;
+
+error_unlock:
+ spin_unlock_irqrestore(&devdata_mutex, flags);
+ if (new_devdata)
+ kfree(new_devdata->counters);
+ kfree(new_devdata);
+error:
+ return ret;
+}
+
+static int __exit nx842_remove(struct vio_dev *viodev)
+{
+ struct nx842_devdata *old_devdata;
+ unsigned long flags;
+
+ pr_info("Removing IBM Power 842 compression device\n");
+ sysfs_remove_group(&viodev->dev.kobj, &nx842_attribute_group);
+
+ spin_lock_irqsave(&devdata_mutex, flags);
+ old_devdata = rcu_dereference_check(devdata,
+ lockdep_is_held(&devdata_mutex));
+ of_reconfig_notifier_unregister(&nx842_of_nb);
+ RCU_INIT_POINTER(devdata, NULL);
+ spin_unlock_irqrestore(&devdata_mutex, flags);
+ synchronize_rcu();
+ dev_set_drvdata(&viodev->dev, NULL);
+ if (old_devdata)
+ kfree(old_devdata->counters);
+ kfree(old_devdata);
+
+ return 0;
+}
+
+static struct vio_device_id nx842_vio_driver_ids[] = {
+ {"ibm,compression-v1", "ibm,compression"},
+ {"", ""},
+};
+
+static struct vio_driver nx842_vio_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = nx842_probe,
+ .remove = __exit_p(nx842_remove),
+ .get_desired_dma = nx842_get_desired_dma,
+ .id_table = nx842_vio_driver_ids,
+};
+
+static int __init nx842_init(void)
+{
+ struct nx842_devdata *new_devdata;
+ int ret;
+
+ pr_info("Registering IBM Power 842 compression driver\n");
+
+ if (!of_find_compatible_node(NULL, NULL, "ibm,compression"))
+ return -ENODEV;
+
+ RCU_INIT_POINTER(devdata, NULL);
+ new_devdata = kzalloc(sizeof(*new_devdata), GFP_KERNEL);
+ if (!new_devdata) {
+ pr_err("Could not allocate memory for device data\n");
+ return -ENOMEM;
+ }
+ new_devdata->status = UNAVAILABLE;
+ RCU_INIT_POINTER(devdata, new_devdata);
+
+ ret = vio_register_driver(&nx842_vio_driver);
+ if (ret) {
+ pr_err("Could not register VIO driver %d\n", ret);
+
+ kfree(new_devdata);
+ return ret;
+ }
+
+ if (!nx842_platform_driver_set(&nx842_pseries_driver)) {
+ vio_unregister_driver(&nx842_vio_driver);
+ kfree(new_devdata);
+ return -EEXIST;
+ }
+
+ return 0;
+}
+
+module_init(nx842_init);
+
+static void __exit nx842_exit(void)
+{
+ struct nx842_devdata *old_devdata;
+ unsigned long flags;
+
+ pr_info("Exiting IBM Power 842 compression driver\n");
+ nx842_platform_driver_unset(&nx842_pseries_driver);
+ spin_lock_irqsave(&devdata_mutex, flags);
+ old_devdata = rcu_dereference_check(devdata,
+ lockdep_is_held(&devdata_mutex));
+ RCU_INIT_POINTER(devdata, NULL);
+ spin_unlock_irqrestore(&devdata_mutex, flags);
+ synchronize_rcu();
+ if (old_devdata && old_devdata->dev)
+ dev_set_drvdata(old_devdata->dev, NULL);
+ kfree(old_devdata);
+ vio_unregister_driver(&nx842_vio_driver);
+}
+
+module_exit(nx842_exit);
+
diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c
index 887196e9b50c..6e5e0d60d0c8 100644
--- a/drivers/crypto/nx/nx-842.c
+++ b/drivers/crypto/nx/nx-842.c
@@ -1,5 +1,10 @@
/*
- * Driver for IBM Power 842 compression accelerator
+ * Driver frontend for IBM Power 842 compression accelerator
+ *
+ * Copyright (C) 2015 Dan Streetman, IBM Corp
+ *
+ * Designer of the Power data compression engine:
+ * Bulent Abali <abali@us.ibm.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
@@ -10,1594 +15,89 @@
* but WITHOUT 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright (C) IBM Corporation, 2012
- *
- * Authors: Robert Jennings <rcj@linux.vnet.ibm.com>
- * Seth Jennings <sjenning@linux.vnet.ibm.com>
*/
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/nx842.h>
-#include <linux/of.h>
-#include <linux/slab.h>
-
-#include <asm/page.h>
-#include <asm/vio.h>
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include "nx_csbcpb.h" /* struct nx_csbcpb */
+#include "nx-842.h"
-#define MODULE_NAME "nx-compress"
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Robert Jennings <rcj@linux.vnet.ibm.com>");
+MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>");
MODULE_DESCRIPTION("842 H/W Compression driver for IBM Power processors");
-#define SHIFT_4K 12
-#define SHIFT_64K 16
-#define SIZE_4K (1UL << SHIFT_4K)
-#define SIZE_64K (1UL << SHIFT_64K)
-
-/* IO buffer must be 128 byte aligned */
-#define IO_BUFFER_ALIGN 128
-
-struct nx842_header {
- int blocks_nr; /* number of compressed blocks */
- int offset; /* offset of the first block (from beginning of header) */
- int sizes[0]; /* size of compressed blocks */
-};
-
-static inline int nx842_header_size(const struct nx842_header *hdr)
-{
- return sizeof(struct nx842_header) +
- hdr->blocks_nr * sizeof(hdr->sizes[0]);
-}
-
-/* Macros for fields within nx_csbcpb */
-/* Check the valid bit within the csbcpb valid field */
-#define NX842_CSBCBP_VALID_CHK(x) (x & BIT_MASK(7))
-
-/* CE macros operate on the completion_extension field bits in the csbcpb.
- * CE0 0=full completion, 1=partial completion
- * CE1 0=CE0 indicates completion, 1=termination (output may be modified)
- * CE2 0=processed_bytes is source bytes, 1=processed_bytes is target bytes */
-#define NX842_CSBCPB_CE0(x) (x & BIT_MASK(7))
-#define NX842_CSBCPB_CE1(x) (x & BIT_MASK(6))
-#define NX842_CSBCPB_CE2(x) (x & BIT_MASK(5))
-
-/* The NX unit accepts data only on 4K page boundaries */
-#define NX842_HW_PAGE_SHIFT SHIFT_4K
-#define NX842_HW_PAGE_SIZE (ASM_CONST(1) << NX842_HW_PAGE_SHIFT)
-#define NX842_HW_PAGE_MASK (~(NX842_HW_PAGE_SIZE-1))
-
-enum nx842_status {
- UNAVAILABLE,
- AVAILABLE
-};
-
-struct ibm_nx842_counters {
- atomic64_t comp_complete;
- atomic64_t comp_failed;
- atomic64_t decomp_complete;
- atomic64_t decomp_failed;
- atomic64_t swdecomp;
- atomic64_t comp_times[32];
- atomic64_t decomp_times[32];
-};
-
-static struct nx842_devdata {
- struct vio_dev *vdev;
- struct device *dev;
- struct ibm_nx842_counters *counters;
- unsigned int max_sg_len;
- unsigned int max_sync_size;
- unsigned int max_sync_sg;
- enum nx842_status status;
-} __rcu *devdata;
-static DEFINE_SPINLOCK(devdata_mutex);
-
-#define NX842_COUNTER_INC(_x) \
-static inline void nx842_inc_##_x( \
- const struct nx842_devdata *dev) { \
- if (dev) \
- atomic64_inc(&dev->counters->_x); \
-}
-NX842_COUNTER_INC(comp_complete);
-NX842_COUNTER_INC(comp_failed);
-NX842_COUNTER_INC(decomp_complete);
-NX842_COUNTER_INC(decomp_failed);
-NX842_COUNTER_INC(swdecomp);
-
-#define NX842_HIST_SLOTS 16
-
-static void ibm_nx842_incr_hist(atomic64_t *times, unsigned int time)
-{
- int bucket = fls(time);
-
- if (bucket)
- bucket = min((NX842_HIST_SLOTS - 1), bucket - 1);
-
- atomic64_inc(&times[bucket]);
-}
-
-/* NX unit operation flags */
-#define NX842_OP_COMPRESS 0x0
-#define NX842_OP_CRC 0x1
-#define NX842_OP_DECOMPRESS 0x2
-#define NX842_OP_COMPRESS_CRC (NX842_OP_COMPRESS | NX842_OP_CRC)
-#define NX842_OP_DECOMPRESS_CRC (NX842_OP_DECOMPRESS | NX842_OP_CRC)
-#define NX842_OP_ASYNC (1<<23)
-#define NX842_OP_NOTIFY (1<<22)
-#define NX842_OP_NOTIFY_INT(x) ((x & 0xff)<<8)
-
-static unsigned long nx842_get_desired_dma(struct vio_dev *viodev)
-{
- /* No use of DMA mappings within the driver. */
- return 0;
-}
-
-struct nx842_slentry {
- unsigned long ptr; /* Real address (use __pa()) */
- unsigned long len;
-};
-
-/* pHyp scatterlist entry */
-struct nx842_scatterlist {
- int entry_nr; /* number of slentries */
- struct nx842_slentry *entries; /* ptr to array of slentries */
-};
-
-/* Does not include sizeof(entry_nr) in the size */
-static inline unsigned long nx842_get_scatterlist_size(
- struct nx842_scatterlist *sl)
-{
- return sl->entry_nr * sizeof(struct nx842_slentry);
-}
-
-static inline unsigned long nx842_get_pa(void *addr)
-{
- if (is_vmalloc_addr(addr))
- return page_to_phys(vmalloc_to_page(addr))
- + offset_in_page(addr);
- else
- return __pa(addr);
-}
-
-static int nx842_build_scatterlist(unsigned long buf, int len,
- struct nx842_scatterlist *sl)
-{
- unsigned long nextpage;
- struct nx842_slentry *entry;
-
- sl->entry_nr = 0;
-
- entry = sl->entries;
- while (len) {
- entry->ptr = nx842_get_pa((void *)buf);
- nextpage = ALIGN(buf + 1, NX842_HW_PAGE_SIZE);
- if (nextpage < buf + len) {
- /* we aren't at the end yet */
- if (IS_ALIGNED(buf, NX842_HW_PAGE_SIZE))
- /* we are in the middle (or beginning) */
- entry->len = NX842_HW_PAGE_SIZE;
- else
- /* we are at the beginning */
- entry->len = nextpage - buf;
- } else {
- /* at the end */
- entry->len = len;
- }
-
- len -= entry->len;
- buf += entry->len;
- sl->entry_nr++;
- entry++;
- }
-
- return 0;
-}
-
-/*
- * Working memory for software decompression
- */
-struct sw842_fifo {
- union {
- char f8[256][8];
- char f4[512][4];
- };
- char f2[256][2];
- unsigned char f84_full;
- unsigned char f2_full;
- unsigned char f8_count;
- unsigned char f2_count;
- unsigned int f4_count;
-};
-
-/*
- * Working memory for crypto API
+/**
+ * nx842_constraints
+ *
+ * This provides the driver's constraints. Different nx842 implementations
+ * may have varying requirements. The constraints are:
+ * @alignment: All buffers should be aligned to this
+ * @multiple: All buffer lengths should be a multiple of this
+ * @minimum: Buffer lengths must not be less than this amount
+ * @maximum: Buffer lengths must not be more than this amount
+ *
+ * The constraints apply to all buffers and lengths, both input and output,
+ * for both compression and decompression, except for the minimum which
+ * only applies to compression input and decompression output; the
+ * compressed data can be less than the minimum constraint. It can be
+ * assumed that compressed data will always adhere to the multiple
+ * constraint.
+ *
+ * The driver may succeed even if these constraints are violated;
+ * however the driver can return failure or suffer reduced performance
+ * if any constraint is not met.
*/
-struct nx842_workmem {
- char bounce[PAGE_SIZE]; /* bounce buffer for decompression input */
- union {
- /* hardware working memory */
- struct {
- /* scatterlist */
- char slin[SIZE_4K];
- char slout[SIZE_4K];
- /* coprocessor status/parameter block */
- struct nx_csbcpb csbcpb;
- };
- /* software working memory */
- struct sw842_fifo swfifo; /* software decompression fifo */
- };
-};
-
-int nx842_get_workmem_size(void)
-{
- return sizeof(struct nx842_workmem) + NX842_HW_PAGE_SIZE;
-}
-EXPORT_SYMBOL_GPL(nx842_get_workmem_size);
-
-int nx842_get_workmem_size_aligned(void)
-{
- return sizeof(struct nx842_workmem);
-}
-EXPORT_SYMBOL_GPL(nx842_get_workmem_size_aligned);
-
-static int nx842_validate_result(struct device *dev,
- struct cop_status_block *csb)
+int nx842_constraints(struct nx842_constraints *c)
{
- /* The csb must be valid after returning from vio_h_cop_sync */
- if (!NX842_CSBCBP_VALID_CHK(csb->valid)) {
- dev_err(dev, "%s: cspcbp not valid upon completion.\n",
- __func__);
- dev_dbg(dev, "valid:0x%02x cs:0x%02x cc:0x%02x ce:0x%02x\n",
- csb->valid,
- csb->crb_seq_number,
- csb->completion_code,
- csb->completion_extension);
- dev_dbg(dev, "processed_bytes:%d address:0x%016lx\n",
- csb->processed_byte_count,
- (unsigned long)csb->address);
- return -EIO;
- }
-
- /* Check return values from the hardware in the CSB */
- switch (csb->completion_code) {
- case 0: /* Completed without error */
- break;
- case 64: /* Target bytes > Source bytes during compression */
- case 13: /* Output buffer too small */
- dev_dbg(dev, "%s: Compression output larger than input\n",
- __func__);
- return -ENOSPC;
- case 66: /* Input data contains an illegal template field */
- case 67: /* Template indicates data past the end of the input stream */
- dev_dbg(dev, "%s: Bad data for decompression (code:%d)\n",
- __func__, csb->completion_code);
- return -EINVAL;
- default:
- dev_dbg(dev, "%s: Unspecified error (code:%d)\n",
- __func__, csb->completion_code);
- return -EIO;
- }
-
- /* Hardware sanity check */
- if (!NX842_CSBCPB_CE2(csb->completion_extension)) {
- dev_err(dev, "%s: No error returned by hardware, but "
- "data returned is unusable, contact support.\n"
- "(Additional info: csbcbp->processed bytes "
- "does not specify processed bytes for the "
- "target buffer.)\n", __func__);
- return -EIO;
- }
-
+ memcpy(c, nx842_platform_driver()->constraints, sizeof(*c));
return 0;
}
+EXPORT_SYMBOL_GPL(nx842_constraints);
/**
- * nx842_compress - Compress data using the 842 algorithm
- *
- * Compression provide by the NX842 coprocessor on IBM Power systems.
- * The input buffer is compressed and the result is stored in the
- * provided output buffer.
- *
- * Upon return from this function @outlen contains the length of the
- * compressed data. If there is an error then @outlen will be 0 and an
- * error will be specified by the return code from this function.
- *
- * @in: Pointer to input buffer, must be page aligned
- * @inlen: Length of input buffer, must be PAGE_SIZE
- * @out: Pointer to output buffer
- * @outlen: Length of output buffer
- * @wrkmem: ptr to buffer for working memory, size determined by
- * nx842_get_workmem_size()
+ * nx842_workmem_size
*
- * Returns:
- * 0 Success, output of length @outlen stored in the buffer at @out
- * -ENOMEM Unable to allocate internal buffers
- * -ENOSPC Output buffer is to small
- * -EMSGSIZE XXX Difficult to describe this limitation
- * -EIO Internal error
- * -ENODEV Hardware unavailable
+ * Get the amount of working memory the driver requires.
*/
-int nx842_compress(const unsigned char *in, unsigned int inlen,
- unsigned char *out, unsigned int *outlen, void *wmem)
+size_t nx842_workmem_size(void)
{
- struct nx842_header *hdr;
- struct nx842_devdata *local_devdata;
- struct device *dev = NULL;
- struct nx842_workmem *workmem;
- struct nx842_scatterlist slin, slout;
- struct nx_csbcpb *csbcpb;
- int ret = 0, max_sync_size, i, bytesleft, size, hdrsize;
- unsigned long inbuf, outbuf, padding;
- struct vio_pfo_op op = {
- .done = NULL,
- .handle = 0,
- .timeout = 0,
- };
- unsigned long start_time = get_tb();
-
- /*
- * Make sure input buffer is 64k page aligned. This is assumed since
- * this driver is designed for page compression only (for now). This
- * is very nice since we can now use direct DDE(s) for the input and
- * the alignment is guaranteed.
- */
- inbuf = (unsigned long)in;
- if (!IS_ALIGNED(inbuf, PAGE_SIZE) || inlen != PAGE_SIZE)
- return -EINVAL;
-
- rcu_read_lock();
- local_devdata = rcu_dereference(devdata);
- if (!local_devdata || !local_devdata->dev) {
- rcu_read_unlock();
- return -ENODEV;
- }
- max_sync_size = local_devdata->max_sync_size;
- dev = local_devdata->dev;
-
- /* Create the header */
- hdr = (struct nx842_header *)out;
- hdr->blocks_nr = PAGE_SIZE / max_sync_size;
- hdrsize = nx842_header_size(hdr);
- outbuf = (unsigned long)out + hdrsize;
- bytesleft = *outlen - hdrsize;
-
- /* Init scatterlist */
- workmem = (struct nx842_workmem *)ALIGN((unsigned long)wmem,
- NX842_HW_PAGE_SIZE);
- slin.entries = (struct nx842_slentry *)workmem->slin;
- slout.entries = (struct nx842_slentry *)workmem->slout;
-
- /* Init operation */
- op.flags = NX842_OP_COMPRESS;
- csbcpb = &workmem->csbcpb;
- memset(csbcpb, 0, sizeof(*csbcpb));
- op.csbcpb = nx842_get_pa(csbcpb);
- op.out = nx842_get_pa(slout.entries);
-
- for (i = 0; i < hdr->blocks_nr; i++) {
- /*
- * Aligning the output blocks to 128 bytes does waste space,
- * but it prevents the need for bounce buffers and memory
- * copies. It also simplifies the code a lot. In the worst
- * case (64k page, 4k max_sync_size), you lose up to
- * (128*16)/64k = ~3% the compression factor. For 64k
- * max_sync_size, the loss would be at most 128/64k = ~0.2%.
- */
- padding = ALIGN(outbuf, IO_BUFFER_ALIGN) - outbuf;
- outbuf += padding;
- bytesleft -= padding;
- if (i == 0)
- /* save offset into first block in header */
- hdr->offset = padding + hdrsize;
-
- if (bytesleft <= 0) {
- ret = -ENOSPC;
- goto unlock;
- }
-
- /*
- * NOTE: If the default max_sync_size is changed from 4k
- * to 64k, remove the "likely" case below, since a
- * scatterlist will always be needed.
- */
- if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) {
- /* Create direct DDE */
- op.in = nx842_get_pa((void *)inbuf);
- op.inlen = max_sync_size;
-
- } else {
- /* Create indirect DDE (scatterlist) */
- nx842_build_scatterlist(inbuf, max_sync_size, &slin);
- op.in = nx842_get_pa(slin.entries);
- op.inlen = -nx842_get_scatterlist_size(&slin);
- }
-
- /*
- * If max_sync_size != NX842_HW_PAGE_SIZE, an indirect
- * DDE is required for the outbuf.
- * If max_sync_size == NX842_HW_PAGE_SIZE, outbuf must
- * also be page aligned (1 in 128/4k=32 chance) in order
- * to use a direct DDE.
- * This is unlikely, just use an indirect DDE always.
- */
- nx842_build_scatterlist(outbuf,
- min(bytesleft, max_sync_size), &slout);
- /* op.out set before loop */
- op.outlen = -nx842_get_scatterlist_size(&slout);
-
- /* Send request to pHyp */
- ret = vio_h_cop_sync(local_devdata->vdev, &op);
-
- /* Check for pHyp error */
- if (ret) {
- dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n",
- __func__, ret, op.hcall_err);
- ret = -EIO;
- goto unlock;
- }
-
- /* Check for hardware error */
- ret = nx842_validate_result(dev, &csbcpb->csb);
- if (ret && ret != -ENOSPC)
- goto unlock;
-
- /* Handle incompressible data */
- if (unlikely(ret == -ENOSPC)) {
- if (bytesleft < max_sync_size) {
- /*
- * Not enough space left in the output buffer
- * to store uncompressed block
- */
- goto unlock;
- } else {
- /* Store incompressible block */
- memcpy((void *)outbuf, (void *)inbuf,
- max_sync_size);
- hdr->sizes[i] = -max_sync_size;
- outbuf += max_sync_size;
- bytesleft -= max_sync_size;
- /* Reset ret, incompressible data handled */
- ret = 0;
- }
- } else {
- /* Normal case, compression was successful */
- size = csbcpb->csb.processed_byte_count;
- dev_dbg(dev, "%s: processed_bytes=%d\n",
- __func__, size);
- hdr->sizes[i] = size;
- outbuf += size;
- bytesleft -= size;
- }
-
- inbuf += max_sync_size;
- }
-
- *outlen = (unsigned int)(outbuf - (unsigned long)out);
-
-unlock:
- if (ret)
- nx842_inc_comp_failed(local_devdata);
- else {
- nx842_inc_comp_complete(local_devdata);
- ibm_nx842_incr_hist(local_devdata->counters->comp_times,
- (get_tb() - start_time) / tb_ticks_per_usec);
- }
- rcu_read_unlock();
- return ret;
+ return nx842_platform_driver()->workmem_size;
}
-EXPORT_SYMBOL_GPL(nx842_compress);
-
-static int sw842_decompress(const unsigned char *, int, unsigned char *, int *,
- const void *);
+EXPORT_SYMBOL_GPL(nx842_workmem_size);
-/**
- * nx842_decompress - Decompress data using the 842 algorithm
- *
- * Decompression provide by the NX842 coprocessor on IBM Power systems.
- * The input buffer is decompressed and the result is stored in the
- * provided output buffer. The size allocated to the output buffer is
- * provided by the caller of this function in @outlen. Upon return from
- * this function @outlen contains the length of the decompressed data.
- * If there is an error then @outlen will be 0 and an error will be
- * specified by the return code from this function.
- *
- * @in: Pointer to input buffer, will use bounce buffer if not 128 byte
- * aligned
- * @inlen: Length of input buffer
- * @out: Pointer to output buffer, must be page aligned
- * @outlen: Length of output buffer, must be PAGE_SIZE
- * @wrkmem: ptr to buffer for working memory, size determined by
- * nx842_get_workmem_size()
- *
- * Returns:
- * 0 Success, output of length @outlen stored in the buffer at @out
- * -ENODEV Hardware decompression device is unavailable
- * -ENOMEM Unable to allocate internal buffers
- * -ENOSPC Output buffer is to small
- * -EINVAL Bad input data encountered when attempting decompress
- * -EIO Internal error
- */
-int nx842_decompress(const unsigned char *in, unsigned int inlen,
- unsigned char *out, unsigned int *outlen, void *wmem)
+int nx842_compress(const unsigned char *in, unsigned int ilen,
+ unsigned char *out, unsigned int *olen, void *wmem)
{
- struct nx842_header *hdr;
- struct nx842_devdata *local_devdata;
- struct device *dev = NULL;
- struct nx842_workmem *workmem;
- struct nx842_scatterlist slin, slout;
- struct nx_csbcpb *csbcpb;
- int ret = 0, i, size, max_sync_size;
- unsigned long inbuf, outbuf;
- struct vio_pfo_op op = {
- .done = NULL,
- .handle = 0,
- .timeout = 0,
- };
- unsigned long start_time = get_tb();
-
- /* Ensure page alignment and size */
- outbuf = (unsigned long)out;
- if (!IS_ALIGNED(outbuf, PAGE_SIZE) || *outlen != PAGE_SIZE)
- return -EINVAL;
-
- rcu_read_lock();
- local_devdata = rcu_dereference(devdata);
- if (local_devdata)
- dev = local_devdata->dev;
-
- /* Get header */
- hdr = (struct nx842_header *)in;
-
- workmem = (struct nx842_workmem *)ALIGN((unsigned long)wmem,
- NX842_HW_PAGE_SIZE);
-
- inbuf = (unsigned long)in + hdr->offset;
- if (likely(!IS_ALIGNED(inbuf, IO_BUFFER_ALIGN))) {
- /* Copy block(s) into bounce buffer for alignment */
- memcpy(workmem->bounce, in + hdr->offset, inlen - hdr->offset);
- inbuf = (unsigned long)workmem->bounce;
- }
-
- /* Init scatterlist */
- slin.entries = (struct nx842_slentry *)workmem->slin;
- slout.entries = (struct nx842_slentry *)workmem->slout;
-
- /* Init operation */
- op.flags = NX842_OP_DECOMPRESS;
- csbcpb = &workmem->csbcpb;
- memset(csbcpb, 0, sizeof(*csbcpb));
- op.csbcpb = nx842_get_pa(csbcpb);
-
- /*
- * max_sync_size may have changed since compression,
- * so we can't read it from the device info. We need
- * to derive it from hdr->blocks_nr.
- */
- max_sync_size = PAGE_SIZE / hdr->blocks_nr;
-
- for (i = 0; i < hdr->blocks_nr; i++) {
- /* Skip padding */
- inbuf = ALIGN(inbuf, IO_BUFFER_ALIGN);
-
- if (hdr->sizes[i] < 0) {
- /* Negative sizes indicate uncompressed data blocks */
- size = abs(hdr->sizes[i]);
- memcpy((void *)outbuf, (void *)inbuf, size);
- outbuf += size;
- inbuf += size;
- continue;
- }
-
- if (!dev)
- goto sw;
-
- /*
- * The better the compression, the more likely the "likely"
- * case becomes.
- */
- if (likely((inbuf & NX842_HW_PAGE_MASK) ==
- ((inbuf + hdr->sizes[i] - 1) & NX842_HW_PAGE_MASK))) {
- /* Create direct DDE */
- op.in = nx842_get_pa((void *)inbuf);
- op.inlen = hdr->sizes[i];
- } else {
- /* Create indirect DDE (scatterlist) */
- nx842_build_scatterlist(inbuf, hdr->sizes[i] , &slin);
- op.in = nx842_get_pa(slin.entries);
- op.inlen = -nx842_get_scatterlist_size(&slin);
- }
-
- /*
- * NOTE: If the default max_sync_size is changed from 4k
- * to 64k, remove the "likely" case below, since a
- * scatterlist will always be needed.
- */
- if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) {
- /* Create direct DDE */
- op.out = nx842_get_pa((void *)outbuf);
- op.outlen = max_sync_size;
- } else {
- /* Create indirect DDE (scatterlist) */
- nx842_build_scatterlist(outbuf, max_sync_size, &slout);
- op.out = nx842_get_pa(slout.entries);
- op.outlen = -nx842_get_scatterlist_size(&slout);
- }
-
- /* Send request to pHyp */
- ret = vio_h_cop_sync(local_devdata->vdev, &op);
-
- /* Check for pHyp error */
- if (ret) {
- dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n",
- __func__, ret, op.hcall_err);
- dev = NULL;
- goto sw;
- }
-
- /* Check for hardware error */
- ret = nx842_validate_result(dev, &csbcpb->csb);
- if (ret) {
- dev = NULL;
- goto sw;
- }
-
- /* HW decompression success */
- inbuf += hdr->sizes[i];
- outbuf += csbcpb->csb.processed_byte_count;
- continue;
-
-sw:
- /* software decompression */
- size = max_sync_size;
- ret = sw842_decompress(
- (unsigned char *)inbuf, hdr->sizes[i],
- (unsigned char *)outbuf, &size, wmem);
- if (ret)
- pr_debug("%s: sw842_decompress failed with %d\n",
- __func__, ret);
-
- if (ret) {
- if (ret != -ENOSPC && ret != -EINVAL &&
- ret != -EMSGSIZE)
- ret = -EIO;
- goto unlock;
- }
-
- /* SW decompression success */
- inbuf += hdr->sizes[i];
- outbuf += size;
- }
-
- *outlen = (unsigned int)(outbuf - (unsigned long)out);
-
-unlock:
- if (ret)
- /* decompress fail */
- nx842_inc_decomp_failed(local_devdata);
- else {
- if (!dev)
- /* software decompress */
- nx842_inc_swdecomp(local_devdata);
- nx842_inc_decomp_complete(local_devdata);
- ibm_nx842_incr_hist(local_devdata->counters->decomp_times,
- (get_tb() - start_time) / tb_ticks_per_usec);
- }
-
- rcu_read_unlock();
- return ret;
+ return nx842_platform_driver()->compress(in, ilen, out, olen, wmem);
}
-EXPORT_SYMBOL_GPL(nx842_decompress);
+EXPORT_SYMBOL_GPL(nx842_compress);
-/**
- * nx842_OF_set_defaults -- Set default (disabled) values for devdata
- *
- * @devdata - struct nx842_devdata to update
- *
- * Returns:
- * 0 on success
- * -ENOENT if @devdata ptr is NULL
- */
-static int nx842_OF_set_defaults(struct nx842_devdata *devdata)
+int nx842_decompress(const unsigned char *in, unsigned int ilen,
+ unsigned char *out, unsigned int *olen, void *wmem)
{
- if (devdata) {
- devdata->max_sync_size = 0;
- devdata->max_sync_sg = 0;
- devdata->max_sg_len = 0;
- devdata->status = UNAVAILABLE;
- return 0;
- } else
- return -ENOENT;
-}
-
-/**
- * nx842_OF_upd_status -- Update the device info from OF status prop
- *
- * The status property indicates if the accelerator is enabled. If the
- * device is in the OF tree it indicates that the hardware is present.
- * The status field indicates if the device is enabled when the status
- * is 'okay'. Otherwise the device driver will be disabled.
- *
- * @devdata - struct nx842_devdata to update
- * @prop - struct property point containing the maxsyncop for the update
- *
- * Returns:
- * 0 - Device is available
- * -EINVAL - Device is not available
- */
-static int nx842_OF_upd_status(struct nx842_devdata *devdata,
- struct property *prop) {
- int ret = 0;
- const char *status = (const char *)prop->value;
-
- if (!strncmp(status, "okay", (size_t)prop->length)) {
- devdata->status = AVAILABLE;
- } else {
- dev_info(devdata->dev, "%s: status '%s' is not 'okay'\n",
- __func__, status);
- devdata->status = UNAVAILABLE;
- }
-
- return ret;
-}
-
-/**
- * nx842_OF_upd_maxsglen -- Update the device info from OF maxsglen prop
- *
- * Definition of the 'ibm,max-sg-len' OF property:
- * This field indicates the maximum byte length of a scatter list
- * for the platform facility. It is a single cell encoded as with encode-int.
- *
- * Example:
- * # od -x ibm,max-sg-len
- * 0000000 0000 0ff0
- *
- * In this example, the maximum byte length of a scatter list is
- * 0x0ff0 (4,080).
- *
- * @devdata - struct nx842_devdata to update
- * @prop - struct property point containing the maxsyncop for the update
- *
- * Returns:
- * 0 on success
- * -EINVAL on failure
- */
-static int nx842_OF_upd_maxsglen(struct nx842_devdata *devdata,
- struct property *prop) {
- int ret = 0;
- const int *maxsglen = prop->value;
-
- if (prop->length != sizeof(*maxsglen)) {
- dev_err(devdata->dev, "%s: unexpected format for ibm,max-sg-len property\n", __func__);
- dev_dbg(devdata->dev, "%s: ibm,max-sg-len is %d bytes long, expected %lu bytes\n", __func__,
- prop->length, sizeof(*maxsglen));
- ret = -EINVAL;
- } else {
- devdata->max_sg_len = (unsigned int)min(*maxsglen,
- (int)NX842_HW_PAGE_SIZE);
- }
-
- return ret;
-}
-
-/**
- * nx842_OF_upd_maxsyncop -- Update the device info from OF maxsyncop prop
- *
- * Definition of the 'ibm,max-sync-cop' OF property:
- * Two series of cells. The first series of cells represents the maximums
- * that can be synchronously compressed. The second series of cells
- * represents the maximums that can be synchronously decompressed.
- * 1. The first cell in each series contains the count of the number of
- * data length, scatter list elements pairs that follow – each being
- * of the form
- * a. One cell data byte length
- * b. One cell total number of scatter list elements
- *
- * Example:
- * # od -x ibm,max-sync-cop
- * 0000000 0000 0001 0000 1000 0000 01fe 0000 0001
- * 0000020 0000 1000 0000 01fe
- *
- * In this example, compression supports 0x1000 (4,096) data byte length
- * and 0x1fe (510) total scatter list elements. Decompression supports
- * 0x1000 (4,096) data byte length and 0x1f3 (510) total scatter list
- * elements.
- *
- * @devdata - struct nx842_devdata to update
- * @prop - struct property point containing the maxsyncop for the update
- *
- * Returns:
- * 0 on success
- * -EINVAL on failure
- */
-static int nx842_OF_upd_maxsyncop(struct nx842_devdata *devdata,
- struct property *prop) {
- int ret = 0;
- const struct maxsynccop_t {
- int comp_elements;
- int comp_data_limit;
- int comp_sg_limit;
- int decomp_elements;
- int decomp_data_limit;
- int decomp_sg_limit;
- } *maxsynccop;
-
- if (prop->length != sizeof(*maxsynccop)) {
- dev_err(devdata->dev, "%s: unexpected format for ibm,max-sync-cop property\n", __func__);
- dev_dbg(devdata->dev, "%s: ibm,max-sync-cop is %d bytes long, expected %lu bytes\n", __func__, prop->length,
- sizeof(*maxsynccop));
- ret = -EINVAL;
- goto out;
- }
-
- maxsynccop = (const struct maxsynccop_t *)prop->value;
-
- /* Use one limit rather than separate limits for compression and
- * decompression. Set a maximum for this so as not to exceed the
- * size that the header can support and round the value down to
- * the hardware page size (4K) */
- devdata->max_sync_size =
- (unsigned int)min(maxsynccop->comp_data_limit,
- maxsynccop->decomp_data_limit);
-
- devdata->max_sync_size = min_t(unsigned int, devdata->max_sync_size,
- SIZE_64K);
-
- if (devdata->max_sync_size < SIZE_4K) {
- dev_err(devdata->dev, "%s: hardware max data size (%u) is "
- "less than the driver minimum, unable to use "
- "the hardware device\n",
- __func__, devdata->max_sync_size);
- ret = -EINVAL;
- goto out;
- }
-
- devdata->max_sync_sg = (unsigned int)min(maxsynccop->comp_sg_limit,
- maxsynccop->decomp_sg_limit);
- if (devdata->max_sync_sg < 1) {
- dev_err(devdata->dev, "%s: hardware max sg size (%u) is "
- "less than the driver minimum, unable to use "
- "the hardware device\n",
- __func__, devdata->max_sync_sg);
- ret = -EINVAL;
- goto out;
- }
-
-out:
- return ret;
+ return nx842_platform_driver()->decompress(in, ilen, out, olen, wmem);
}
+EXPORT_SYMBOL_GPL(nx842_decompress);
-/**
- *
- * nx842_OF_upd -- Handle OF properties updates for the device.
- *
- * Set all properties from the OF tree. Optionally, a new property
- * can be provided by the @new_prop pointer to overwrite an existing value.
- * The device will remain disabled until all values are valid, this function
- * will return an error for updates unless all values are valid.
- *
- * @new_prop: If not NULL, this property is being updated. If NULL, update
- * all properties from the current values in the OF tree.
- *
- * Returns:
- * 0 - Success
- * -ENOMEM - Could not allocate memory for new devdata structure
- * -EINVAL - property value not found, new_prop is not a recognized
- * property for the device or property value is not valid.
- * -ENODEV - Device is not available
- */
-static int nx842_OF_upd(struct property *new_prop)
+static __init int nx842_init(void)
{
- struct nx842_devdata *old_devdata = NULL;
- struct nx842_devdata *new_devdata = NULL;
- struct device_node *of_node = NULL;
- struct property *status = NULL;
- struct property *maxsglen = NULL;
- struct property *maxsyncop = NULL;
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&devdata_mutex, flags);
- old_devdata = rcu_dereference_check(devdata,
- lockdep_is_held(&devdata_mutex));
- if (old_devdata)
- of_node = old_devdata->dev->of_node;
+ request_module("nx-compress-powernv");
+ request_module("nx-compress-pseries");
- if (!old_devdata || !of_node) {
- pr_err("%s: device is not available\n", __func__);
- spin_unlock_irqrestore(&devdata_mutex, flags);
- return -ENODEV;
- }
-
- new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS);
- if (!new_devdata) {
- dev_err(old_devdata->dev, "%s: Could not allocate memory for device data\n", __func__);
- ret = -ENOMEM;
- goto error_out;
- }
-
- memcpy(new_devdata, old_devdata, sizeof(*old_devdata));
- new_devdata->counters = old_devdata->counters;
-
- /* Set ptrs for existing properties */
- status = of_find_property(of_node, "status", NULL);
- maxsglen = of_find_property(of_node, "ibm,max-sg-len", NULL);
- maxsyncop = of_find_property(of_node, "ibm,max-sync-cop", NULL);
- if (!status || !maxsglen || !maxsyncop) {
- dev_err(old_devdata->dev, "%s: Could not locate device properties\n", __func__);
- ret = -EINVAL;
- goto error_out;
- }
-
- /*
- * If this is a property update, there are only certain properties that
- * we care about. Bail if it isn't in the below list
+ /* we prevent loading if there's no platform driver, and we get the
+ * module that set it so it won't unload, so we don't need to check
+ * if it's set in any of the above functions
*/
- if (new_prop && (strncmp(new_prop->name, "status", new_prop->length) ||
- strncmp(new_prop->name, "ibm,max-sg-len", new_prop->length) ||
- strncmp(new_prop->name, "ibm,max-sync-cop", new_prop->length)))
- goto out;
-
- /* Perform property updates */
- ret = nx842_OF_upd_status(new_devdata, status);
- if (ret)
- goto error_out;
-
- ret = nx842_OF_upd_maxsglen(new_devdata, maxsglen);
- if (ret)
- goto error_out;
-
- ret = nx842_OF_upd_maxsyncop(new_devdata, maxsyncop);
- if (ret)
- goto error_out;
-
-out:
- dev_info(old_devdata->dev, "%s: max_sync_size new:%u old:%u\n",
- __func__, new_devdata->max_sync_size,
- old_devdata->max_sync_size);
- dev_info(old_devdata->dev, "%s: max_sync_sg new:%u old:%u\n",
- __func__, new_devdata->max_sync_sg,
- old_devdata->max_sync_sg);
- dev_info(old_devdata->dev, "%s: max_sg_len new:%u old:%u\n",
- __func__, new_devdata->max_sg_len,
- old_devdata->max_sg_len);
-
- rcu_assign_pointer(devdata, new_devdata);
- spin_unlock_irqrestore(&devdata_mutex, flags);
- synchronize_rcu();
- dev_set_drvdata(new_devdata->dev, new_devdata);
- kfree(old_devdata);
- return 0;
-
-error_out:
- if (new_devdata) {
- dev_info(old_devdata->dev, "%s: device disabled\n", __func__);
- nx842_OF_set_defaults(new_devdata);
- rcu_assign_pointer(devdata, new_devdata);
- spin_unlock_irqrestore(&devdata_mutex, flags);
- synchronize_rcu();
- dev_set_drvdata(new_devdata->dev, new_devdata);
- kfree(old_devdata);
- } else {
- dev_err(old_devdata->dev, "%s: could not update driver from hardware\n", __func__);
- spin_unlock_irqrestore(&devdata_mutex, flags);
- }
-
- if (!ret)
- ret = -EINVAL;
- return ret;
-}
-
-/**
- * nx842_OF_notifier - Process updates to OF properties for the device
- *
- * @np: notifier block
- * @action: notifier action
- * @update: struct pSeries_reconfig_prop_update pointer if action is
- * PSERIES_UPDATE_PROPERTY
- *
- * Returns:
- * NOTIFY_OK on success
- * NOTIFY_BAD encoded with error number on failure, use
- * notifier_to_errno() to decode this value
- */
-static int nx842_OF_notifier(struct notifier_block *np, unsigned long action,
- void *data)
-{
- struct of_reconfig_data *upd = data;
- struct nx842_devdata *local_devdata;
- struct device_node *node = NULL;
-
- rcu_read_lock();
- local_devdata = rcu_dereference(devdata);
- if (local_devdata)
- node = local_devdata->dev->of_node;
-
- if (local_devdata &&
- action == OF_RECONFIG_UPDATE_PROPERTY &&
- !strcmp(upd->dn->name, node->name)) {
- rcu_read_unlock();
- nx842_OF_upd(upd->prop);
- } else
- rcu_read_unlock();
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block nx842_of_nb = {
- .notifier_call = nx842_OF_notifier,
-};
-
-#define nx842_counter_read(_name) \
-static ssize_t nx842_##_name##_show(struct device *dev, \
- struct device_attribute *attr, \
- char *buf) { \
- struct nx842_devdata *local_devdata; \
- int p = 0; \
- rcu_read_lock(); \
- local_devdata = rcu_dereference(devdata); \
- if (local_devdata) \
- p = snprintf(buf, PAGE_SIZE, "%ld\n", \
- atomic64_read(&local_devdata->counters->_name)); \
- rcu_read_unlock(); \
- return p; \
-}
-
-#define NX842DEV_COUNTER_ATTR_RO(_name) \
- nx842_counter_read(_name); \
- static struct device_attribute dev_attr_##_name = __ATTR(_name, \
- 0444, \
- nx842_##_name##_show,\
- NULL);
-
-NX842DEV_COUNTER_ATTR_RO(comp_complete);
-NX842DEV_COUNTER_ATTR_RO(comp_failed);
-NX842DEV_COUNTER_ATTR_RO(decomp_complete);
-NX842DEV_COUNTER_ATTR_RO(decomp_failed);
-NX842DEV_COUNTER_ATTR_RO(swdecomp);
-
-static ssize_t nx842_timehist_show(struct device *,
- struct device_attribute *, char *);
-
-static struct device_attribute dev_attr_comp_times = __ATTR(comp_times, 0444,
- nx842_timehist_show, NULL);
-static struct device_attribute dev_attr_decomp_times = __ATTR(decomp_times,
- 0444, nx842_timehist_show, NULL);
-
-static ssize_t nx842_timehist_show(struct device *dev,
- struct device_attribute *attr, char *buf) {
- char *p = buf;
- struct nx842_devdata *local_devdata;
- atomic64_t *times;
- int bytes_remain = PAGE_SIZE;
- int bytes;
- int i;
-
- rcu_read_lock();
- local_devdata = rcu_dereference(devdata);
- if (!local_devdata) {
- rcu_read_unlock();
- return 0;
- }
-
- if (attr == &dev_attr_comp_times)
- times = local_devdata->counters->comp_times;
- else if (attr == &dev_attr_decomp_times)
- times = local_devdata->counters->decomp_times;
- else {
- rcu_read_unlock();
- return 0;
- }
-
- for (i = 0; i < (NX842_HIST_SLOTS - 2); i++) {
- bytes = snprintf(p, bytes_remain, "%u-%uus:\t%ld\n",
- i ? (2<<(i-1)) : 0, (2<<i)-1,
- atomic64_read(&times[i]));
- bytes_remain -= bytes;
- p += bytes;
- }
- /* The last bucket holds everything over
- * 2<<(NX842_HIST_SLOTS - 2) us */
- bytes = snprintf(p, bytes_remain, "%uus - :\t%ld\n",
- 2<<(NX842_HIST_SLOTS - 2),
- atomic64_read(&times[(NX842_HIST_SLOTS - 1)]));
- p += bytes;
-
- rcu_read_unlock();
- return p - buf;
-}
-
-static struct attribute *nx842_sysfs_entries[] = {
- &dev_attr_comp_complete.attr,
- &dev_attr_comp_failed.attr,
- &dev_attr_decomp_complete.attr,
- &dev_attr_decomp_failed.attr,
- &dev_attr_swdecomp.attr,
- &dev_attr_comp_times.attr,
- &dev_attr_decomp_times.attr,
- NULL,
-};
-
-static struct attribute_group nx842_attribute_group = {
- .name = NULL, /* put in device directory */
- .attrs = nx842_sysfs_entries,
-};
-
-static int __init nx842_probe(struct vio_dev *viodev,
- const struct vio_device_id *id)
-{
- struct nx842_devdata *old_devdata, *new_devdata = NULL;
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&devdata_mutex, flags);
- old_devdata = rcu_dereference_check(devdata,
- lockdep_is_held(&devdata_mutex));
-
- if (old_devdata && old_devdata->vdev != NULL) {
- dev_err(&viodev->dev, "%s: Attempt to register more than one instance of the hardware\n", __func__);
- ret = -1;
- goto error_unlock;
- }
-
- dev_set_drvdata(&viodev->dev, NULL);
-
- new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS);
- if (!new_devdata) {
- dev_err(&viodev->dev, "%s: Could not allocate memory for device data\n", __func__);
- ret = -ENOMEM;
- goto error_unlock;
- }
-
- new_devdata->counters = kzalloc(sizeof(*new_devdata->counters),
- GFP_NOFS);
- if (!new_devdata->counters) {
- dev_err(&viodev->dev, "%s: Could not allocate memory for performance counters\n", __func__);
- ret = -ENOMEM;
- goto error_unlock;
- }
-
- new_devdata->vdev = viodev;
- new_devdata->dev = &viodev->dev;
- nx842_OF_set_defaults(new_devdata);
-
- rcu_assign_pointer(devdata, new_devdata);
- spin_unlock_irqrestore(&devdata_mutex, flags);
- synchronize_rcu();
- kfree(old_devdata);
-
- of_reconfig_notifier_register(&nx842_of_nb);
-
- ret = nx842_OF_upd(NULL);
- if (ret && ret != -ENODEV) {
- dev_err(&viodev->dev, "could not parse device tree. %d\n", ret);
- ret = -1;
- goto error;
- }
-
- rcu_read_lock();
- dev_set_drvdata(&viodev->dev, rcu_dereference(devdata));
- rcu_read_unlock();
-
- if (sysfs_create_group(&viodev->dev.kobj, &nx842_attribute_group)) {
- dev_err(&viodev->dev, "could not create sysfs device attributes\n");
- ret = -1;
- goto error;
+ if (!nx842_platform_driver_get()) {
+ pr_err("no nx842 driver found.\n");
+ return -ENODEV;
}
return 0;
-
-error_unlock:
- spin_unlock_irqrestore(&devdata_mutex, flags);
- if (new_devdata)
- kfree(new_devdata->counters);
- kfree(new_devdata);
-error:
- return ret;
-}
-
-static int __exit nx842_remove(struct vio_dev *viodev)
-{
- struct nx842_devdata *old_devdata;
- unsigned long flags;
-
- pr_info("Removing IBM Power 842 compression device\n");
- sysfs_remove_group(&viodev->dev.kobj, &nx842_attribute_group);
-
- spin_lock_irqsave(&devdata_mutex, flags);
- old_devdata = rcu_dereference_check(devdata,
- lockdep_is_held(&devdata_mutex));
- of_reconfig_notifier_unregister(&nx842_of_nb);
- RCU_INIT_POINTER(devdata, NULL);
- spin_unlock_irqrestore(&devdata_mutex, flags);
- synchronize_rcu();
- dev_set_drvdata(&viodev->dev, NULL);
- if (old_devdata)
- kfree(old_devdata->counters);
- kfree(old_devdata);
- return 0;
-}
-
-static struct vio_device_id nx842_driver_ids[] = {
- {"ibm,compression-v1", "ibm,compression"},
- {"", ""},
-};
-
-static struct vio_driver nx842_driver = {
- .name = MODULE_NAME,
- .probe = nx842_probe,
- .remove = __exit_p(nx842_remove),
- .get_desired_dma = nx842_get_desired_dma,
- .id_table = nx842_driver_ids,
-};
-
-static int __init nx842_init(void)
-{
- struct nx842_devdata *new_devdata;
- pr_info("Registering IBM Power 842 compression driver\n");
-
- RCU_INIT_POINTER(devdata, NULL);
- new_devdata = kzalloc(sizeof(*new_devdata), GFP_KERNEL);
- if (!new_devdata) {
- pr_err("Could not allocate memory for device data\n");
- return -ENOMEM;
- }
- new_devdata->status = UNAVAILABLE;
- RCU_INIT_POINTER(devdata, new_devdata);
-
- return vio_register_driver(&nx842_driver);
}
-
module_init(nx842_init);
static void __exit nx842_exit(void)
{
- struct nx842_devdata *old_devdata;
- unsigned long flags;
-
- pr_info("Exiting IBM Power 842 compression driver\n");
- spin_lock_irqsave(&devdata_mutex, flags);
- old_devdata = rcu_dereference_check(devdata,
- lockdep_is_held(&devdata_mutex));
- RCU_INIT_POINTER(devdata, NULL);
- spin_unlock_irqrestore(&devdata_mutex, flags);
- synchronize_rcu();
- if (old_devdata)
- dev_set_drvdata(old_devdata->dev, NULL);
- kfree(old_devdata);
- vio_unregister_driver(&nx842_driver);
+ nx842_platform_driver_put();
}
-
module_exit(nx842_exit);
-
-/*********************************
- * 842 software decompressor
-*********************************/
-typedef int (*sw842_template_op)(const char **, int *, unsigned char **,
- struct sw842_fifo *);
-
-static int sw842_data8(const char **, int *, unsigned char **,
- struct sw842_fifo *);
-static int sw842_data4(const char **, int *, unsigned char **,
- struct sw842_fifo *);
-static int sw842_data2(const char **, int *, unsigned char **,
- struct sw842_fifo *);
-static int sw842_ptr8(const char **, int *, unsigned char **,
- struct sw842_fifo *);
-static int sw842_ptr4(const char **, int *, unsigned char **,
- struct sw842_fifo *);
-static int sw842_ptr2(const char **, int *, unsigned char **,
- struct sw842_fifo *);
-
-/* special templates */
-#define SW842_TMPL_REPEAT 0x1B
-#define SW842_TMPL_ZEROS 0x1C
-#define SW842_TMPL_EOF 0x1E
-
-static sw842_template_op sw842_tmpl_ops[26][4] = {
- { sw842_data8, NULL}, /* 0 (00000) */
- { sw842_data4, sw842_data2, sw842_ptr2, NULL},
- { sw842_data4, sw842_ptr2, sw842_data2, NULL},
- { sw842_data4, sw842_ptr2, sw842_ptr2, NULL},
- { sw842_data4, sw842_ptr4, NULL},
- { sw842_data2, sw842_ptr2, sw842_data4, NULL},
- { sw842_data2, sw842_ptr2, sw842_data2, sw842_ptr2},
- { sw842_data2, sw842_ptr2, sw842_ptr2, sw842_data2},
- { sw842_data2, sw842_ptr2, sw842_ptr2, sw842_ptr2,},
- { sw842_data2, sw842_ptr2, sw842_ptr4, NULL},
- { sw842_ptr2, sw842_data2, sw842_data4, NULL}, /* 10 (01010) */
- { sw842_ptr2, sw842_data4, sw842_ptr2, NULL},
- { sw842_ptr2, sw842_data2, sw842_ptr2, sw842_data2},
- { sw842_ptr2, sw842_data2, sw842_ptr2, sw842_ptr2},
- { sw842_ptr2, sw842_data2, sw842_ptr4, NULL},
- { sw842_ptr2, sw842_ptr2, sw842_data4, NULL},
- { sw842_ptr2, sw842_ptr2, sw842_data2, sw842_ptr2},
- { sw842_ptr2, sw842_ptr2, sw842_ptr2, sw842_data2},
- { sw842_ptr2, sw842_ptr2, sw842_ptr2, sw842_ptr2},
- { sw842_ptr2, sw842_ptr2, sw842_ptr4, NULL},
- { sw842_ptr4, sw842_data4, NULL}, /* 20 (10100) */
- { sw842_ptr4, sw842_data2, sw842_ptr2, NULL},
- { sw842_ptr4, sw842_ptr2, sw842_data2, NULL},
- { sw842_ptr4, sw842_ptr2, sw842_ptr2, NULL},
- { sw842_ptr4, sw842_ptr4, NULL},
- { sw842_ptr8, NULL}
-};
-
-/* Software decompress helpers */
-
-static uint8_t sw842_get_byte(const char *buf, int bit)
-{
- uint8_t tmpl;
- uint16_t tmp;
- tmp = htons(*(uint16_t *)(buf));
- tmp = (uint16_t)(tmp << bit);
- tmp = ntohs(tmp);
- memcpy(&tmpl, &tmp, 1);
- return tmpl;
-}
-
-static uint8_t sw842_get_template(const char **buf, int *bit)
-{
- uint8_t byte;
- byte = sw842_get_byte(*buf, *bit);
- byte = byte >> 3;
- byte &= 0x1F;
- *buf += (*bit + 5) / 8;
- *bit = (*bit + 5) % 8;
- return byte;
-}
-
-/* repeat_count happens to be 5-bit too (like the template) */
-static uint8_t sw842_get_repeat_count(const char **buf, int *bit)
-{
- uint8_t byte;
- byte = sw842_get_byte(*buf, *bit);
- byte = byte >> 2;
- byte &= 0x3F;
- *buf += (*bit + 6) / 8;
- *bit = (*bit + 6) % 8;
- return byte;
-}
-
-static uint8_t sw842_get_ptr2(const char **buf, int *bit)
-{
- uint8_t ptr;
- ptr = sw842_get_byte(*buf, *bit);
- (*buf)++;
- return ptr;
-}
-
-static uint16_t sw842_get_ptr4(const char **buf, int *bit,
- struct sw842_fifo *fifo)
-{
- uint16_t ptr;
- ptr = htons(*(uint16_t *)(*buf));
- ptr = (uint16_t)(ptr << *bit);
- ptr = ptr >> 7;
- ptr &= 0x01FF;
- *buf += (*bit + 9) / 8;
- *bit = (*bit + 9) % 8;
- return ptr;
-}
-
-static uint8_t sw842_get_ptr8(const char **buf, int *bit,
- struct sw842_fifo *fifo)
-{
- return sw842_get_ptr2(buf, bit);
-}
-
-/* Software decompress template ops */
-
-static int sw842_data8(const char **inbuf, int *inbit,
- unsigned char **outbuf, struct sw842_fifo *fifo)
-{
- int ret;
-
- ret = sw842_data4(inbuf, inbit, outbuf, fifo);
- if (ret)
- return ret;
- ret = sw842_data4(inbuf, inbit, outbuf, fifo);
- return ret;
-}
-
-static int sw842_data4(const char **inbuf, int *inbit,
- unsigned char **outbuf, struct sw842_fifo *fifo)
-{
- int ret;
-
- ret = sw842_data2(inbuf, inbit, outbuf, fifo);
- if (ret)
- return ret;
- ret = sw842_data2(inbuf, inbit, outbuf, fifo);
- return ret;
-}
-
-static int sw842_data2(const char **inbuf, int *inbit,
- unsigned char **outbuf, struct sw842_fifo *fifo)
-{
- **outbuf = sw842_get_byte(*inbuf, *inbit);
- (*inbuf)++;
- (*outbuf)++;
- **outbuf = sw842_get_byte(*inbuf, *inbit);
- (*inbuf)++;
- (*outbuf)++;
- return 0;
-}
-
-static int sw842_ptr8(const char **inbuf, int *inbit,
- unsigned char **outbuf, struct sw842_fifo *fifo)
-{
- uint8_t ptr;
- ptr = sw842_get_ptr8(inbuf, inbit, fifo);
- if (!fifo->f84_full && (ptr >= fifo->f8_count))
- return 1;
- memcpy(*outbuf, fifo->f8[ptr], 8);
- *outbuf += 8;
- return 0;
-}
-
-static int sw842_ptr4(const char **inbuf, int *inbit,
- unsigned char **outbuf, struct sw842_fifo *fifo)
-{
- uint16_t ptr;
- ptr = sw842_get_ptr4(inbuf, inbit, fifo);
- if (!fifo->f84_full && (ptr >= fifo->f4_count))
- return 1;
- memcpy(*outbuf, fifo->f4[ptr], 4);
- *outbuf += 4;
- return 0;
-}
-
-static int sw842_ptr2(const char **inbuf, int *inbit,
- unsigned char **outbuf, struct sw842_fifo *fifo)
-{
- uint8_t ptr;
- ptr = sw842_get_ptr2(inbuf, inbit);
- if (!fifo->f2_full && (ptr >= fifo->f2_count))
- return 1;
- memcpy(*outbuf, fifo->f2[ptr], 2);
- *outbuf += 2;
- return 0;
-}
-
-static void sw842_copy_to_fifo(const char *buf, struct sw842_fifo *fifo)
-{
- unsigned char initial_f2count = fifo->f2_count;
-
- memcpy(fifo->f8[fifo->f8_count], buf, 8);
- fifo->f4_count += 2;
- fifo->f8_count += 1;
-
- if (!fifo->f84_full && fifo->f4_count >= 512) {
- fifo->f84_full = 1;
- fifo->f4_count /= 512;
- }
-
- memcpy(fifo->f2[fifo->f2_count++], buf, 2);
- memcpy(fifo->f2[fifo->f2_count++], buf + 2, 2);
- memcpy(fifo->f2[fifo->f2_count++], buf + 4, 2);
- memcpy(fifo->f2[fifo->f2_count++], buf + 6, 2);
- if (fifo->f2_count < initial_f2count)
- fifo->f2_full = 1;
-}
-
-static int sw842_decompress(const unsigned char *src, int srclen,
- unsigned char *dst, int *destlen,
- const void *wrkmem)
-{
- uint8_t tmpl;
- const char *inbuf;
- int inbit = 0;
- unsigned char *outbuf, *outbuf_end, *origbuf, *prevbuf;
- const char *inbuf_end;
- sw842_template_op op;
- int opindex;
- int i, repeat_count;
- struct sw842_fifo *fifo;
- int ret = 0;
-
- fifo = &((struct nx842_workmem *)(wrkmem))->swfifo;
- memset(fifo, 0, sizeof(*fifo));
-
- origbuf = NULL;
- inbuf = src;
- inbuf_end = src + srclen;
- outbuf = dst;
- outbuf_end = dst + *destlen;
-
- while ((tmpl = sw842_get_template(&inbuf, &inbit)) != SW842_TMPL_EOF) {
- if (inbuf >= inbuf_end) {
- ret = -EINVAL;
- goto out;
- }
-
- opindex = 0;
- prevbuf = origbuf;
- origbuf = outbuf;
- switch (tmpl) {
- case SW842_TMPL_REPEAT:
- if (prevbuf == NULL) {
- ret = -EINVAL;
- goto out;
- }
-
- repeat_count = sw842_get_repeat_count(&inbuf,
- &inbit) + 1;
-
- /* Did the repeat count advance past the end of input */
- if (inbuf > inbuf_end) {
- ret = -EINVAL;
- goto out;
- }
-
- for (i = 0; i < repeat_count; i++) {
- /* Would this overflow the output buffer */
- if ((outbuf + 8) > outbuf_end) {
- ret = -ENOSPC;
- goto out;
- }
-
- memcpy(outbuf, prevbuf, 8);
- sw842_copy_to_fifo(outbuf, fifo);
- outbuf += 8;
- }
- break;
-
- case SW842_TMPL_ZEROS:
- /* Would this overflow the output buffer */
- if ((outbuf + 8) > outbuf_end) {
- ret = -ENOSPC;
- goto out;
- }
-
- memset(outbuf, 0, 8);
- sw842_copy_to_fifo(outbuf, fifo);
- outbuf += 8;
- break;
-
- default:
- if (tmpl > 25) {
- ret = -EINVAL;
- goto out;
- }
-
- /* Does this go past the end of the input buffer */
- if ((inbuf + 2) > inbuf_end) {
- ret = -EINVAL;
- goto out;
- }
-
- /* Would this overflow the output buffer */
- if ((outbuf + 8) > outbuf_end) {
- ret = -ENOSPC;
- goto out;
- }
-
- while (opindex < 4 &&
- (op = sw842_tmpl_ops[tmpl][opindex++])
- != NULL) {
- ret = (*op)(&inbuf, &inbit, &outbuf, fifo);
- if (ret) {
- ret = -EINVAL;
- goto out;
- }
- sw842_copy_to_fifo(origbuf, fifo);
- }
- }
- }
-
-out:
- if (!ret)
- *destlen = (unsigned int)(outbuf - dst);
- else
- *destlen = 0;
-
- return ret;
-}
diff --git a/drivers/crypto/nx/nx-842.h b/drivers/crypto/nx/nx-842.h
new file mode 100644
index 000000000000..ac0ea79d0f8b
--- /dev/null
+++ b/drivers/crypto/nx/nx-842.h
@@ -0,0 +1,144 @@
+
+#ifndef __NX_842_H__
+#define __NX_842_H__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sw842.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/ratelimit.h>
+
+/* Restrictions on Data Descriptor List (DDL) and Entry (DDE) buffers
+ *
+ * From NX P8 workbook, sec 4.9.1 "842 details"
+ * Each DDE buffer is 128 byte aligned
+ * Each DDE buffer size is a multiple of 32 bytes (except the last)
+ * The last DDE buffer size is a multiple of 8 bytes
+ */
+#define DDE_BUFFER_ALIGN (128)
+#define DDE_BUFFER_SIZE_MULT (32)
+#define DDE_BUFFER_LAST_MULT (8)
+
+/* Arbitrary DDL length limit
+ * Allows max buffer size of MAX-1 to MAX pages
+ * (depending on alignment)
+ */
+#define DDL_LEN_MAX (17)
+
+/* CCW 842 CI/FC masks
+ * NX P8 workbook, section 4.3.1, figure 4-6
+ * "CI/FC Boundary by NX CT type"
+ */
+#define CCW_CI_842 (0x00003ff8)
+#define CCW_FC_842 (0x00000007)
+
+/* CCW Function Codes (FC) for 842
+ * NX P8 workbook, section 4.9, table 4-28
+ * "Function Code Definitions for 842 Memory Compression"
+ */
+#define CCW_FC_842_COMP_NOCRC (0)
+#define CCW_FC_842_COMP_CRC (1)
+#define CCW_FC_842_DECOMP_NOCRC (2)
+#define CCW_FC_842_DECOMP_CRC (3)
+#define CCW_FC_842_MOVE (4)
+
+/* CSB CC Error Types for 842
+ * NX P8 workbook, section 4.10.3, table 4-30
+ * "Reported Error Types Summary Table"
+ */
+/* These are all duplicates of existing codes defined in icswx.h. */
+#define CSB_CC_TRANSLATION_DUP1 (80)
+#define CSB_CC_TRANSLATION_DUP2 (82)
+#define CSB_CC_TRANSLATION_DUP3 (84)
+#define CSB_CC_TRANSLATION_DUP4 (86)
+#define CSB_CC_TRANSLATION_DUP5 (92)
+#define CSB_CC_TRANSLATION_DUP6 (94)
+#define CSB_CC_PROTECTION_DUP1 (81)
+#define CSB_CC_PROTECTION_DUP2 (83)
+#define CSB_CC_PROTECTION_DUP3 (85)
+#define CSB_CC_PROTECTION_DUP4 (87)
+#define CSB_CC_PROTECTION_DUP5 (93)
+#define CSB_CC_PROTECTION_DUP6 (95)
+#define CSB_CC_RD_EXTERNAL_DUP1 (89)
+#define CSB_CC_RD_EXTERNAL_DUP2 (90)
+#define CSB_CC_RD_EXTERNAL_DUP3 (91)
+/* These are specific to NX */
+/* 842 codes */
+#define CSB_CC_TPBC_GT_SPBC (64) /* no error, but >1 comp ratio */
+#define CSB_CC_CRC_MISMATCH (65) /* decomp crc mismatch */
+#define CSB_CC_TEMPL_INVALID (66) /* decomp invalid template value */
+#define CSB_CC_TEMPL_OVERFLOW (67) /* decomp template shows data after end */
+/* sym crypt codes */
+#define CSB_CC_DECRYPT_OVERFLOW (64)
+/* asym crypt codes */
+#define CSB_CC_MINV_OVERFLOW (128)
+/* These are reserved for hypervisor use */
+#define CSB_CC_HYP_RESERVE_START (240)
+#define CSB_CC_HYP_RESERVE_END (253)
+#define CSB_CC_HYP_NO_HW (254)
+#define CSB_CC_HYP_HANG_ABORTED (255)
+
+/* CCB Completion Modes (CM) for 842
+ * NX P8 workbook, section 4.3, figure 4-5
+ * "CRB Details - Normal Cop_Req (CL=00, C=1)"
+ */
+#define CCB_CM_EXTRA_WRITE (CCB_CM0_ALL_COMPLETIONS & CCB_CM12_STORE)
+#define CCB_CM_INTERRUPT (CCB_CM0_ALL_COMPLETIONS & CCB_CM12_INTERRUPT)
+
+#define LEN_ON_SIZE(pa, size) ((size) - ((pa) & ((size) - 1)))
+#define LEN_ON_PAGE(pa) LEN_ON_SIZE(pa, PAGE_SIZE)
+
+static inline unsigned long nx842_get_pa(void *addr)
+{
+ if (!is_vmalloc_addr(addr))
+ return __pa(addr);
+
+ return page_to_phys(vmalloc_to_page(addr)) + offset_in_page(addr);
+}
+
+/* Get/Set bit fields */
+#define MASK_LSH(m) (__builtin_ffsl(m) - 1)
+#define GET_FIELD(v, m) (((v) & (m)) >> MASK_LSH(m))
+#define SET_FIELD(v, m, val) (((v) & ~(m)) | (((val) << MASK_LSH(m)) & (m)))
+
+struct nx842_constraints {
+ int alignment;
+ int multiple;
+ int minimum;
+ int maximum;
+};
+
+struct nx842_driver {
+ char *name;
+ struct module *owner;
+ size_t workmem_size;
+
+ struct nx842_constraints *constraints;
+
+ int (*compress)(const unsigned char *in, unsigned int in_len,
+ unsigned char *out, unsigned int *out_len,
+ void *wrkmem);
+ int (*decompress)(const unsigned char *in, unsigned int in_len,
+ unsigned char *out, unsigned int *out_len,
+ void *wrkmem);
+};
+
+struct nx842_driver *nx842_platform_driver(void);
+bool nx842_platform_driver_set(struct nx842_driver *driver);
+void nx842_platform_driver_unset(struct nx842_driver *driver);
+bool nx842_platform_driver_get(void);
+void nx842_platform_driver_put(void);
+
+size_t nx842_workmem_size(void);
+
+int nx842_constraints(struct nx842_constraints *constraints);
+
+int nx842_compress(const unsigned char *in, unsigned int in_len,
+ unsigned char *out, unsigned int *out_len, void *wrkmem);
+int nx842_decompress(const unsigned char *in, unsigned int in_len,
+ unsigned char *out, unsigned int *out_len, void *wrkmem);
+
+#endif /* __NX_842_H__ */
diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c
index 88c562434bc0..08ac6d48688c 100644
--- a/drivers/crypto/nx/nx-aes-gcm.c
+++ b/drivers/crypto/nx/nx-aes-gcm.c
@@ -93,17 +93,6 @@ out:
return rc;
}
-static int gcm_aes_nx_setauthsize(struct crypto_aead *tfm,
- unsigned int authsize)
-{
- if (authsize > crypto_aead_alg(tfm)->maxauthsize)
- return -EINVAL;
-
- crypto_aead_crt(tfm)->authsize = authsize;
-
- return 0;
-}
-
static int gcm4106_aes_nx_setauthsize(struct crypto_aead *tfm,
unsigned int authsize)
{
@@ -116,8 +105,6 @@ static int gcm4106_aes_nx_setauthsize(struct crypto_aead *tfm,
return -EINVAL;
}
- crypto_aead_crt(tfm)->authsize = authsize;
-
return 0;
}
@@ -134,7 +121,7 @@ static int nx_gca(struct nx_crypto_ctx *nx_ctx,
unsigned int max_sg_len;
if (nbytes <= AES_BLOCK_SIZE) {
- scatterwalk_start(&walk, req->assoc);
+ scatterwalk_start(&walk, req->src);
scatterwalk_copychunks(out, &walk, nbytes, SCATTERWALK_FROM_SG);
scatterwalk_done(&walk, SCATTERWALK_FROM_SG, 0);
return 0;
@@ -159,7 +146,7 @@ static int nx_gca(struct nx_crypto_ctx *nx_ctx,
NX_PAGE_SIZE * (max_sg_len - 1));
nx_sg = nx_walk_and_build(nx_ctx->in_sg, max_sg_len,
- req->assoc, processed, &to_process);
+ req->src, processed, &to_process);
if ((to_process + processed) < nbytes)
NX_CPB_FDM(csbcpb_aead) |= NX_FDM_INTERMEDIATE;
@@ -225,7 +212,7 @@ static int gmac(struct aead_request *req, struct blkcipher_desc *desc)
NX_PAGE_SIZE * (max_sg_len - 1));
nx_sg = nx_walk_and_build(nx_ctx->in_sg, max_sg_len,
- req->assoc, processed, &to_process);
+ req->src, processed, &to_process);
if ((to_process + processed) < nbytes)
NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
@@ -377,7 +364,8 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc)
csbcpb->cpb.aes_gcm.bit_length_data = nbytes * 8;
desc.tfm = (struct crypto_blkcipher *) req->base.tfm;
rc = nx_build_sg_lists(nx_ctx, &desc, req->dst,
- req->src, &to_process, processed,
+ req->src, &to_process,
+ processed + req->assoclen,
csbcpb->cpb.aes_gcm.iv_or_cnt);
if (rc)
@@ -412,17 +400,19 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc)
mac:
if (enc) {
/* copy out the auth tag */
- scatterwalk_map_and_copy(csbcpb->cpb.aes_gcm.out_pat_or_mac,
- req->dst, nbytes,
- crypto_aead_authsize(crypto_aead_reqtfm(req)),
- SCATTERWALK_TO_SG);
+ scatterwalk_map_and_copy(
+ csbcpb->cpb.aes_gcm.out_pat_or_mac,
+ req->dst, req->assoclen + nbytes,
+ crypto_aead_authsize(crypto_aead_reqtfm(req)),
+ SCATTERWALK_TO_SG);
} else {
u8 *itag = nx_ctx->priv.gcm.iauth_tag;
u8 *otag = csbcpb->cpb.aes_gcm.out_pat_or_mac;
- scatterwalk_map_and_copy(itag, req->src, nbytes,
- crypto_aead_authsize(crypto_aead_reqtfm(req)),
- SCATTERWALK_FROM_SG);
+ scatterwalk_map_and_copy(
+ itag, req->src, req->assoclen + nbytes,
+ crypto_aead_authsize(crypto_aead_reqtfm(req)),
+ SCATTERWALK_FROM_SG);
rc = memcmp(itag, otag,
crypto_aead_authsize(crypto_aead_reqtfm(req))) ?
-EBADMSG : 0;
@@ -481,45 +471,39 @@ static int gcm4106_aes_nx_decrypt(struct aead_request *req)
* during encrypt/decrypt doesn't solve this problem, because it calls
* blkcipher_walk_done under the covers, which doesn't use walk->blocksize,
* but instead uses this tfm->blocksize. */
-struct crypto_alg nx_gcm_aes_alg = {
- .cra_name = "gcm(aes)",
- .cra_driver_name = "gcm-aes-nx",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AEAD,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct nx_crypto_ctx),
- .cra_type = &crypto_aead_type,
- .cra_module = THIS_MODULE,
- .cra_init = nx_crypto_ctx_aes_gcm_init,
- .cra_exit = nx_crypto_ctx_exit,
- .cra_aead = {
- .ivsize = AES_BLOCK_SIZE,
- .maxauthsize = AES_BLOCK_SIZE,
- .setkey = gcm_aes_nx_set_key,
- .setauthsize = gcm_aes_nx_setauthsize,
- .encrypt = gcm_aes_nx_encrypt,
- .decrypt = gcm_aes_nx_decrypt,
- }
+struct aead_alg nx_gcm_aes_alg = {
+ .base = {
+ .cra_name = "gcm(aes)",
+ .cra_driver_name = "gcm-aes-nx",
+ .cra_priority = 300,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_module = THIS_MODULE,
+ },
+ .init = nx_crypto_ctx_aes_gcm_init,
+ .exit = nx_crypto_ctx_aead_exit,
+ .ivsize = 12,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .setkey = gcm_aes_nx_set_key,
+ .encrypt = gcm_aes_nx_encrypt,
+ .decrypt = gcm_aes_nx_decrypt,
};
-struct crypto_alg nx_gcm4106_aes_alg = {
- .cra_name = "rfc4106(gcm(aes))",
- .cra_driver_name = "rfc4106-gcm-aes-nx",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AEAD,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct nx_crypto_ctx),
- .cra_type = &crypto_nivaead_type,
- .cra_module = THIS_MODULE,
- .cra_init = nx_crypto_ctx_aes_gcm_init,
- .cra_exit = nx_crypto_ctx_exit,
- .cra_aead = {
- .ivsize = 8,
- .maxauthsize = AES_BLOCK_SIZE,
- .geniv = "seqiv",
- .setkey = gcm4106_aes_nx_set_key,
- .setauthsize = gcm4106_aes_nx_setauthsize,
- .encrypt = gcm4106_aes_nx_encrypt,
- .decrypt = gcm4106_aes_nx_decrypt,
- }
+struct aead_alg nx_gcm4106_aes_alg = {
+ .base = {
+ .cra_name = "rfc4106(gcm(aes))",
+ .cra_driver_name = "rfc4106-gcm-aes-nx",
+ .cra_priority = 300,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_module = THIS_MODULE,
+ },
+ .init = nx_crypto_ctx_aes_gcm_init,
+ .exit = nx_crypto_ctx_aead_exit,
+ .ivsize = 8,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .setkey = gcm4106_aes_nx_set_key,
+ .setauthsize = gcm4106_aes_nx_setauthsize,
+ .encrypt = gcm4106_aes_nx_encrypt,
+ .decrypt = gcm4106_aes_nx_decrypt,
};
diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c
index 23621da624c3..4e91bdb83c59 100644
--- a/drivers/crypto/nx/nx-sha256.c
+++ b/drivers/crypto/nx/nx-sha256.c
@@ -33,8 +33,9 @@ static int nx_sha256_init(struct shash_desc *desc)
{
struct sha256_state *sctx = shash_desc_ctx(desc);
struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_sg *out_sg;
int len;
- int rc;
+ u32 max_sg_len;
nx_ctx_init(nx_ctx, HCOP_FC_SHA);
@@ -44,15 +45,18 @@ static int nx_sha256_init(struct shash_desc *desc)
NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA256);
+ max_sg_len = min_t(u64, nx_ctx->ap->sglen,
+ nx_driver.of.max_sg_len/sizeof(struct nx_sg));
+ max_sg_len = min_t(u64, max_sg_len,
+ nx_ctx->ap->databytelen/NX_PAGE_SIZE);
+
len = SHA256_DIGEST_SIZE;
- rc = nx_sha_build_sg_list(nx_ctx, nx_ctx->out_sg,
- &nx_ctx->op.outlen,
- &len,
- (u8 *) sctx->state,
- NX_DS_SHA256);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+ &len, max_sg_len);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
- if (rc)
- goto out;
+ if (len != SHA256_DIGEST_SIZE)
+ return -EINVAL;
sctx->state[0] = __cpu_to_be32(SHA256_H0);
sctx->state[1] = __cpu_to_be32(SHA256_H1);
@@ -64,7 +68,6 @@ static int nx_sha256_init(struct shash_desc *desc)
sctx->state[7] = __cpu_to_be32(SHA256_H7);
sctx->count = 0;
-out:
return 0;
}
@@ -74,10 +77,12 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
struct sha256_state *sctx = shash_desc_ctx(desc);
struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct nx_sg *in_sg;
u64 to_process = 0, leftover, total;
unsigned long irq_flags;
int rc = 0;
int data_len;
+ u32 max_sg_len;
u64 buf_len = (sctx->count % SHA256_BLOCK_SIZE);
spin_lock_irqsave(&nx_ctx->lock, irq_flags);
@@ -97,6 +102,12 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+ in_sg = nx_ctx->in_sg;
+ max_sg_len = min_t(u64, nx_ctx->ap->sglen,
+ nx_driver.of.max_sg_len/sizeof(struct nx_sg));
+ max_sg_len = min_t(u64, max_sg_len,
+ nx_ctx->ap->databytelen/NX_PAGE_SIZE);
+
do {
/*
* to_process: the SHA256_BLOCK_SIZE data chunk to process in
@@ -108,25 +119,22 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
if (buf_len) {
data_len = buf_len;
- rc = nx_sha_build_sg_list(nx_ctx, nx_ctx->in_sg,
- &nx_ctx->op.inlen,
- &data_len,
- (u8 *) sctx->buf,
- NX_DS_SHA256);
+ in_sg = nx_build_sg_list(nx_ctx->in_sg,
+ (u8 *) sctx->buf,
+ &data_len,
+ max_sg_len);
- if (rc || data_len != buf_len)
+ if (data_len != buf_len) {
+ rc = -EINVAL;
goto out;
+ }
}
data_len = to_process - buf_len;
- rc = nx_sha_build_sg_list(nx_ctx, nx_ctx->in_sg,
- &nx_ctx->op.inlen,
- &data_len,
- (u8 *) data,
- NX_DS_SHA256);
+ in_sg = nx_build_sg_list(in_sg, (u8 *) data,
+ &data_len, max_sg_len);
- if (rc)
- goto out;
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
to_process = (data_len + buf_len);
leftover = total - to_process;
@@ -173,12 +181,19 @@ static int nx_sha256_final(struct shash_desc *desc, u8 *out)
struct sha256_state *sctx = shash_desc_ctx(desc);
struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct nx_sg *in_sg, *out_sg;
unsigned long irq_flags;
- int rc;
+ u32 max_sg_len;
+ int rc = 0;
int len;
spin_lock_irqsave(&nx_ctx->lock, irq_flags);
+ max_sg_len = min_t(u64, nx_ctx->ap->sglen,
+ nx_driver.of.max_sg_len/sizeof(struct nx_sg));
+ max_sg_len = min_t(u64, max_sg_len,
+ nx_ctx->ap->databytelen/NX_PAGE_SIZE);
+
/* final is represented by continuing the operation and indicating that
* this is not an intermediate operation */
if (sctx->count >= SHA256_BLOCK_SIZE) {
@@ -195,25 +210,24 @@ static int nx_sha256_final(struct shash_desc *desc, u8 *out)
csbcpb->cpb.sha256.message_bit_length = (u64) (sctx->count * 8);
len = sctx->count & (SHA256_BLOCK_SIZE - 1);
- rc = nx_sha_build_sg_list(nx_ctx, nx_ctx->in_sg,
- &nx_ctx->op.inlen,
- &len,
- (u8 *) sctx->buf,
- NX_DS_SHA256);
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *) sctx->buf,
+ &len, max_sg_len);
- if (rc || len != (sctx->count & (SHA256_BLOCK_SIZE - 1)))
+ if (len != (sctx->count & (SHA256_BLOCK_SIZE - 1))) {
+ rc = -EINVAL;
goto out;
+ }
len = SHA256_DIGEST_SIZE;
- rc = nx_sha_build_sg_list(nx_ctx, nx_ctx->out_sg,
- &nx_ctx->op.outlen,
- &len,
- out,
- NX_DS_SHA256);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, out, &len, max_sg_len);
- if (rc || len != SHA256_DIGEST_SIZE)
+ if (len != SHA256_DIGEST_SIZE) {
+ rc = -EINVAL;
goto out;
+ }
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
if (!nx_ctx->op.outlen) {
rc = -EINVAL;
goto out;
diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c
index b3adf1022673..e6a58d2ee628 100644
--- a/drivers/crypto/nx/nx-sha512.c
+++ b/drivers/crypto/nx/nx-sha512.c
@@ -32,8 +32,9 @@ static int nx_sha512_init(struct shash_desc *desc)
{
struct sha512_state *sctx = shash_desc_ctx(desc);
struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_sg *out_sg;
int len;
- int rc;
+ u32 max_sg_len;
nx_ctx_init(nx_ctx, HCOP_FC_SHA);
@@ -43,15 +44,18 @@ static int nx_sha512_init(struct shash_desc *desc)
NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA512);
+ max_sg_len = min_t(u64, nx_ctx->ap->sglen,
+ nx_driver.of.max_sg_len/sizeof(struct nx_sg));
+ max_sg_len = min_t(u64, max_sg_len,
+ nx_ctx->ap->databytelen/NX_PAGE_SIZE);
+
len = SHA512_DIGEST_SIZE;
- rc = nx_sha_build_sg_list(nx_ctx, nx_ctx->out_sg,
- &nx_ctx->op.outlen,
- &len,
- (u8 *)sctx->state,
- NX_DS_SHA512);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+ &len, max_sg_len);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
- if (rc || len != SHA512_DIGEST_SIZE)
- goto out;
+ if (len != SHA512_DIGEST_SIZE)
+ return -EINVAL;
sctx->state[0] = __cpu_to_be64(SHA512_H0);
sctx->state[1] = __cpu_to_be64(SHA512_H1);
@@ -63,7 +67,6 @@ static int nx_sha512_init(struct shash_desc *desc)
sctx->state[7] = __cpu_to_be64(SHA512_H7);
sctx->count[0] = 0;
-out:
return 0;
}
@@ -73,10 +76,12 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
struct sha512_state *sctx = shash_desc_ctx(desc);
struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct nx_sg *in_sg;
u64 to_process, leftover = 0, total;
unsigned long irq_flags;
int rc = 0;
int data_len;
+ u32 max_sg_len;
u64 buf_len = (sctx->count[0] % SHA512_BLOCK_SIZE);
spin_lock_irqsave(&nx_ctx->lock, irq_flags);
@@ -96,6 +101,12 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+ in_sg = nx_ctx->in_sg;
+ max_sg_len = min_t(u64, nx_ctx->ap->sglen,
+ nx_driver.of.max_sg_len/sizeof(struct nx_sg));
+ max_sg_len = min_t(u64, max_sg_len,
+ nx_ctx->ap->databytelen/NX_PAGE_SIZE);
+
do {
/*
* to_process: the SHA512_BLOCK_SIZE data chunk to process in
@@ -108,25 +119,26 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
if (buf_len) {
data_len = buf_len;
- rc = nx_sha_build_sg_list(nx_ctx, nx_ctx->in_sg,
- &nx_ctx->op.inlen,
- &data_len,
- (u8 *) sctx->buf,
- NX_DS_SHA512);
+ in_sg = nx_build_sg_list(nx_ctx->in_sg,
+ (u8 *) sctx->buf,
+ &data_len, max_sg_len);
- if (rc || data_len != buf_len)
+ if (data_len != buf_len) {
+ rc = -EINVAL;
goto out;
+ }
}
data_len = to_process - buf_len;
- rc = nx_sha_build_sg_list(nx_ctx, nx_ctx->in_sg,
- &nx_ctx->op.inlen,
- &data_len,
- (u8 *) data,
- NX_DS_SHA512);
+ in_sg = nx_build_sg_list(in_sg, (u8 *) data,
+ &data_len, max_sg_len);
- if (rc || data_len != (to_process - buf_len))
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+
+ if (data_len != (to_process - buf_len)) {
+ rc = -EINVAL;
goto out;
+ }
to_process = (data_len + buf_len);
leftover = total - to_process;
@@ -172,13 +184,20 @@ static int nx_sha512_final(struct shash_desc *desc, u8 *out)
struct sha512_state *sctx = shash_desc_ctx(desc);
struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct nx_sg *in_sg, *out_sg;
+ u32 max_sg_len;
u64 count0;
unsigned long irq_flags;
- int rc;
+ int rc = 0;
int len;
spin_lock_irqsave(&nx_ctx->lock, irq_flags);
+ max_sg_len = min_t(u64, nx_ctx->ap->sglen,
+ nx_driver.of.max_sg_len/sizeof(struct nx_sg));
+ max_sg_len = min_t(u64, max_sg_len,
+ nx_ctx->ap->databytelen/NX_PAGE_SIZE);
+
/* final is represented by continuing the operation and indicating that
* this is not an intermediate operation */
if (sctx->count[0] >= SHA512_BLOCK_SIZE) {
@@ -200,24 +219,20 @@ static int nx_sha512_final(struct shash_desc *desc, u8 *out)
csbcpb->cpb.sha512.message_bit_length_lo = count0;
len = sctx->count[0] & (SHA512_BLOCK_SIZE - 1);
- rc = nx_sha_build_sg_list(nx_ctx, nx_ctx->in_sg,
- &nx_ctx->op.inlen,
- &len,
- (u8 *)sctx->buf,
- NX_DS_SHA512);
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, sctx->buf, &len,
+ max_sg_len);
- if (rc || len != (sctx->count[0] & (SHA512_BLOCK_SIZE - 1)))
+ if (len != (sctx->count[0] & (SHA512_BLOCK_SIZE - 1))) {
+ rc = -EINVAL;
goto out;
+ }
len = SHA512_DIGEST_SIZE;
- rc = nx_sha_build_sg_list(nx_ctx, nx_ctx->out_sg,
- &nx_ctx->op.outlen,
- &len,
- out,
- NX_DS_SHA512);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, out, &len,
+ max_sg_len);
- if (rc)
- goto out;
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
if (!nx_ctx->op.outlen) {
rc = -EINVAL;
diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c
index 1da6dc59d0dd..f6198f29a4a8 100644
--- a/drivers/crypto/nx/nx.c
+++ b/drivers/crypto/nx/nx.c
@@ -19,8 +19,8 @@
* Author: Kent Yoder <yoder1@us.ibm.com>
*/
+#include <crypto/internal/aead.h>
#include <crypto/internal/hash.h>
-#include <crypto/hash.h>
#include <crypto/aes.h>
#include <crypto/sha.h>
#include <crypto/algapi.h>
@@ -29,10 +29,10 @@
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/mm.h>
-#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <linux/device.h>
#include <linux/of.h>
+#include <linux/types.h>
#include <asm/hvcall.h>
#include <asm/vio.h>
@@ -215,8 +215,15 @@ struct nx_sg *nx_walk_and_build(struct nx_sg *nx_dst,
* @delta: is the amount we need to crop in order to bound the list.
*
*/
-static long int trim_sg_list(struct nx_sg *sg, struct nx_sg *end, unsigned int delta)
+static long int trim_sg_list(struct nx_sg *sg,
+ struct nx_sg *end,
+ unsigned int delta,
+ unsigned int *nbytes)
{
+ long int oplen;
+ long int data_back;
+ unsigned int is_delta = delta;
+
while (delta && end > sg) {
struct nx_sg *last = end - 1;
@@ -228,54 +235,20 @@ static long int trim_sg_list(struct nx_sg *sg, struct nx_sg *end, unsigned int d
delta -= last->len;
}
}
- return (sg - end) * sizeof(struct nx_sg);
-}
-/**
- * nx_sha_build_sg_list - walk and build sg list to sha modes
- * using right bounds and limits.
- * @nx_ctx: NX crypto context for the lists we're building
- * @nx_sg: current sg list in or out list
- * @op_len: current op_len to be used in order to build a sg list
- * @nbytes: number or bytes to be processed
- * @offset: buf offset
- * @mode: SHA256 or SHA512
- */
-int nx_sha_build_sg_list(struct nx_crypto_ctx *nx_ctx,
- struct nx_sg *nx_in_outsg,
- s64 *op_len,
- unsigned int *nbytes,
- u8 *offset,
- u32 mode)
-{
- unsigned int delta = 0;
- unsigned int total = *nbytes;
- struct nx_sg *nx_insg = nx_in_outsg;
- unsigned int max_sg_len;
-
- max_sg_len = min_t(u64, nx_ctx->ap->sglen,
- nx_driver.of.max_sg_len/sizeof(struct nx_sg));
- max_sg_len = min_t(u64, max_sg_len,
- nx_ctx->ap->databytelen/NX_PAGE_SIZE);
-
- *nbytes = min_t(u64, *nbytes, nx_ctx->ap->databytelen);
- nx_insg = nx_build_sg_list(nx_insg, offset, nbytes, max_sg_len);
-
- switch (mode) {
- case NX_DS_SHA256:
- if (*nbytes < total)
- delta = *nbytes - (*nbytes & ~(SHA256_BLOCK_SIZE - 1));
- break;
- case NX_DS_SHA512:
- if (*nbytes < total)
- delta = *nbytes - (*nbytes & ~(SHA512_BLOCK_SIZE - 1));
- break;
- default:
- return -EINVAL;
+ /* There are cases where we need to crop list in order to make it
+ * a block size multiple, but we also need to align data. In order to
+ * that we need to calculate how much we need to put back to be
+ * processed
+ */
+ oplen = (sg - end) * sizeof(struct nx_sg);
+ if (is_delta) {
+ data_back = (abs(oplen) / AES_BLOCK_SIZE) * sg->len;
+ data_back = *nbytes - (data_back & ~(AES_BLOCK_SIZE - 1));
+ *nbytes -= data_back;
}
- *op_len = trim_sg_list(nx_in_outsg, nx_insg, delta);
- return 0;
+ return oplen;
}
/**
@@ -330,8 +303,8 @@ int nx_build_sg_lists(struct nx_crypto_ctx *nx_ctx,
/* these lengths should be negative, which will indicate to phyp that
* the input and output parameters are scatterlists, not linear
* buffers */
- nx_ctx->op.inlen = trim_sg_list(nx_ctx->in_sg, nx_insg, delta);
- nx_ctx->op.outlen = trim_sg_list(nx_ctx->out_sg, nx_outsg, delta);
+ nx_ctx->op.inlen = trim_sg_list(nx_ctx->in_sg, nx_insg, delta, nbytes);
+ nx_ctx->op.outlen = trim_sg_list(nx_ctx->out_sg, nx_outsg, delta, nbytes);
return 0;
}
@@ -426,6 +399,13 @@ static void nx_of_update_msc(struct device *dev,
goto next_loop;
}
+ if (!trip->sglen || trip->databytelen < NX_PAGE_SIZE) {
+ dev_warn(dev, "bogus sglen/databytelen: "
+ "%u/%u (ignored)\n", trip->sglen,
+ trip->databytelen);
+ goto next_loop;
+ }
+
switch (trip->keybitlen) {
case 128:
case 160:
@@ -518,6 +498,72 @@ static void nx_of_init(struct device *dev, struct nx_of *props)
nx_of_update_msc(dev, p, props);
}
+static bool nx_check_prop(struct device *dev, u32 fc, u32 mode, int slot)
+{
+ struct alg_props *props = &nx_driver.of.ap[fc][mode][slot];
+
+ if (!props->sglen || props->databytelen < NX_PAGE_SIZE) {
+ if (dev)
+ dev_warn(dev, "bogus sglen/databytelen for %u/%u/%u: "
+ "%u/%u (ignored)\n", fc, mode, slot,
+ props->sglen, props->databytelen);
+ return false;
+ }
+
+ return true;
+}
+
+static bool nx_check_props(struct device *dev, u32 fc, u32 mode)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ if (!nx_check_prop(dev, fc, mode, i))
+ return false;
+
+ return true;
+}
+
+static int nx_register_alg(struct crypto_alg *alg, u32 fc, u32 mode)
+{
+ return nx_check_props(&nx_driver.viodev->dev, fc, mode) ?
+ crypto_register_alg(alg) : 0;
+}
+
+static int nx_register_aead(struct aead_alg *alg, u32 fc, u32 mode)
+{
+ return nx_check_props(&nx_driver.viodev->dev, fc, mode) ?
+ crypto_register_aead(alg) : 0;
+}
+
+static int nx_register_shash(struct shash_alg *alg, u32 fc, u32 mode, int slot)
+{
+ return (slot >= 0 ? nx_check_prop(&nx_driver.viodev->dev,
+ fc, mode, slot) :
+ nx_check_props(&nx_driver.viodev->dev, fc, mode)) ?
+ crypto_register_shash(alg) : 0;
+}
+
+static void nx_unregister_alg(struct crypto_alg *alg, u32 fc, u32 mode)
+{
+ if (nx_check_props(NULL, fc, mode))
+ crypto_unregister_alg(alg);
+}
+
+static void nx_unregister_aead(struct aead_alg *alg, u32 fc, u32 mode)
+{
+ if (nx_check_props(NULL, fc, mode))
+ crypto_unregister_aead(alg);
+}
+
+static void nx_unregister_shash(struct shash_alg *alg, u32 fc, u32 mode,
+ int slot)
+{
+ if (slot >= 0 ? nx_check_prop(NULL, fc, mode, slot) :
+ nx_check_props(NULL, fc, mode))
+ crypto_unregister_shash(alg);
+}
+
/**
* nx_register_algs - register algorithms with the crypto API
*
@@ -542,72 +588,77 @@ static int nx_register_algs(void)
nx_driver.of.status = NX_OKAY;
- rc = crypto_register_alg(&nx_ecb_aes_alg);
+ rc = nx_register_alg(&nx_ecb_aes_alg, NX_FC_AES, NX_MODE_AES_ECB);
if (rc)
goto out;
- rc = crypto_register_alg(&nx_cbc_aes_alg);
+ rc = nx_register_alg(&nx_cbc_aes_alg, NX_FC_AES, NX_MODE_AES_CBC);
if (rc)
goto out_unreg_ecb;
- rc = crypto_register_alg(&nx_ctr_aes_alg);
+ rc = nx_register_alg(&nx_ctr_aes_alg, NX_FC_AES, NX_MODE_AES_CTR);
if (rc)
goto out_unreg_cbc;
- rc = crypto_register_alg(&nx_ctr3686_aes_alg);
+ rc = nx_register_alg(&nx_ctr3686_aes_alg, NX_FC_AES, NX_MODE_AES_CTR);
if (rc)
goto out_unreg_ctr;
- rc = crypto_register_alg(&nx_gcm_aes_alg);
+ rc = nx_register_aead(&nx_gcm_aes_alg, NX_FC_AES, NX_MODE_AES_GCM);
if (rc)
goto out_unreg_ctr3686;
- rc = crypto_register_alg(&nx_gcm4106_aes_alg);
+ rc = nx_register_aead(&nx_gcm4106_aes_alg, NX_FC_AES, NX_MODE_AES_GCM);
if (rc)
goto out_unreg_gcm;
- rc = crypto_register_alg(&nx_ccm_aes_alg);
+ rc = nx_register_alg(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM);
if (rc)
goto out_unreg_gcm4106;
- rc = crypto_register_alg(&nx_ccm4309_aes_alg);
+ rc = nx_register_alg(&nx_ccm4309_aes_alg, NX_FC_AES, NX_MODE_AES_CCM);
if (rc)
goto out_unreg_ccm;
- rc = crypto_register_shash(&nx_shash_sha256_alg);
+ rc = nx_register_shash(&nx_shash_sha256_alg, NX_FC_SHA, NX_MODE_SHA,
+ NX_PROPS_SHA256);
if (rc)
goto out_unreg_ccm4309;
- rc = crypto_register_shash(&nx_shash_sha512_alg);
+ rc = nx_register_shash(&nx_shash_sha512_alg, NX_FC_SHA, NX_MODE_SHA,
+ NX_PROPS_SHA512);
if (rc)
goto out_unreg_s256;
- rc = crypto_register_shash(&nx_shash_aes_xcbc_alg);
+ rc = nx_register_shash(&nx_shash_aes_xcbc_alg,
+ NX_FC_AES, NX_MODE_AES_XCBC_MAC, -1);
if (rc)
goto out_unreg_s512;
goto out;
out_unreg_s512:
- crypto_unregister_shash(&nx_shash_sha512_alg);
+ nx_unregister_shash(&nx_shash_sha512_alg, NX_FC_SHA, NX_MODE_SHA,
+ NX_PROPS_SHA512);
out_unreg_s256:
- crypto_unregister_shash(&nx_shash_sha256_alg);
+ nx_unregister_shash(&nx_shash_sha256_alg, NX_FC_SHA, NX_MODE_SHA,
+ NX_PROPS_SHA256);
out_unreg_ccm4309:
- crypto_unregister_alg(&nx_ccm4309_aes_alg);
+ nx_unregister_alg(&nx_ccm4309_aes_alg, NX_FC_AES, NX_MODE_AES_CCM);
out_unreg_ccm:
- crypto_unregister_alg(&nx_ccm_aes_alg);
+ nx_unregister_alg(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM);
out_unreg_gcm4106:
- crypto_unregister_alg(&nx_gcm4106_aes_alg);
+ nx_unregister_aead(&nx_gcm4106_aes_alg, NX_FC_AES, NX_MODE_AES_GCM);
out_unreg_gcm:
- crypto_unregister_alg(&nx_gcm_aes_alg);
+ nx_unregister_aead(&nx_gcm_aes_alg, NX_FC_AES, NX_MODE_AES_GCM);
out_unreg_ctr3686:
- crypto_unregister_alg(&nx_ctr3686_aes_alg);
+ nx_unregister_alg(&nx_ctr3686_aes_alg, NX_FC_AES, NX_MODE_AES_CTR);
out_unreg_ctr:
- crypto_unregister_alg(&nx_ctr_aes_alg);
+ nx_unregister_alg(&nx_ctr_aes_alg, NX_FC_AES, NX_MODE_AES_CTR);
out_unreg_cbc:
- crypto_unregister_alg(&nx_cbc_aes_alg);
+ nx_unregister_alg(&nx_cbc_aes_alg, NX_FC_AES, NX_MODE_AES_CBC);
out_unreg_ecb:
- crypto_unregister_alg(&nx_ecb_aes_alg);
+ nx_unregister_alg(&nx_ecb_aes_alg, NX_FC_AES, NX_MODE_AES_ECB);
out:
return rc;
}
@@ -666,9 +717,9 @@ int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm)
NX_MODE_AES_CCM);
}
-int nx_crypto_ctx_aes_gcm_init(struct crypto_tfm *tfm)
+int nx_crypto_ctx_aes_gcm_init(struct crypto_aead *tfm)
{
- return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ return nx_crypto_ctx_init(crypto_aead_ctx(tfm), NX_FC_AES,
NX_MODE_AES_GCM);
}
@@ -720,6 +771,13 @@ void nx_crypto_ctx_exit(struct crypto_tfm *tfm)
nx_ctx->out_sg = NULL;
}
+void nx_crypto_ctx_aead_exit(struct crypto_aead *tfm)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_aead_ctx(tfm);
+
+ kzfree(nx_ctx->kmem);
+}
+
static int nx_probe(struct vio_dev *viodev, const struct vio_device_id *id)
{
dev_dbg(&viodev->dev, "driver probed: %s resource id: 0x%x\n",
@@ -746,17 +804,24 @@ static int nx_remove(struct vio_dev *viodev)
if (nx_driver.of.status == NX_OKAY) {
NX_DEBUGFS_FINI(&nx_driver);
- crypto_unregister_alg(&nx_ccm_aes_alg);
- crypto_unregister_alg(&nx_ccm4309_aes_alg);
- crypto_unregister_alg(&nx_gcm_aes_alg);
- crypto_unregister_alg(&nx_gcm4106_aes_alg);
- crypto_unregister_alg(&nx_ctr_aes_alg);
- crypto_unregister_alg(&nx_ctr3686_aes_alg);
- crypto_unregister_alg(&nx_cbc_aes_alg);
- crypto_unregister_alg(&nx_ecb_aes_alg);
- crypto_unregister_shash(&nx_shash_sha256_alg);
- crypto_unregister_shash(&nx_shash_sha512_alg);
- crypto_unregister_shash(&nx_shash_aes_xcbc_alg);
+ nx_unregister_shash(&nx_shash_aes_xcbc_alg,
+ NX_FC_AES, NX_MODE_AES_XCBC_MAC, -1);
+ nx_unregister_shash(&nx_shash_sha512_alg,
+ NX_FC_SHA, NX_MODE_SHA, NX_PROPS_SHA256);
+ nx_unregister_shash(&nx_shash_sha256_alg,
+ NX_FC_SHA, NX_MODE_SHA, NX_PROPS_SHA512);
+ nx_unregister_alg(&nx_ccm4309_aes_alg,
+ NX_FC_AES, NX_MODE_AES_CCM);
+ nx_unregister_alg(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM);
+ nx_unregister_aead(&nx_gcm4106_aes_alg,
+ NX_FC_AES, NX_MODE_AES_GCM);
+ nx_unregister_aead(&nx_gcm_aes_alg,
+ NX_FC_AES, NX_MODE_AES_GCM);
+ nx_unregister_alg(&nx_ctr3686_aes_alg,
+ NX_FC_AES, NX_MODE_AES_CTR);
+ nx_unregister_alg(&nx_ctr_aes_alg, NX_FC_AES, NX_MODE_AES_CTR);
+ nx_unregister_alg(&nx_cbc_aes_alg, NX_FC_AES, NX_MODE_AES_CBC);
+ nx_unregister_alg(&nx_ecb_aes_alg, NX_FC_AES, NX_MODE_AES_ECB);
}
return 0;
diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h
index 6c9ecaaead52..de3ea8738146 100644
--- a/drivers/crypto/nx/nx.h
+++ b/drivers/crypto/nx/nx.h
@@ -143,18 +143,17 @@ struct nx_crypto_ctx {
/* prototypes */
int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm);
-int nx_crypto_ctx_aes_gcm_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_gcm_init(struct crypto_aead *tfm);
int nx_crypto_ctx_aes_xcbc_init(struct crypto_tfm *tfm);
int nx_crypto_ctx_aes_ctr_init(struct crypto_tfm *tfm);
int nx_crypto_ctx_aes_cbc_init(struct crypto_tfm *tfm);
int nx_crypto_ctx_aes_ecb_init(struct crypto_tfm *tfm);
int nx_crypto_ctx_sha_init(struct crypto_tfm *tfm);
void nx_crypto_ctx_exit(struct crypto_tfm *tfm);
+void nx_crypto_ctx_aead_exit(struct crypto_aead *tfm);
void nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function);
int nx_hcall_sync(struct nx_crypto_ctx *ctx, struct vio_pfo_op *op,
u32 may_sleep);
-int nx_sha_build_sg_list(struct nx_crypto_ctx *, struct nx_sg *,
- s64 *, unsigned int *, u8 *, u32);
struct nx_sg *nx_build_sg_list(struct nx_sg *, u8 *, unsigned int *, u32);
int nx_build_sg_lists(struct nx_crypto_ctx *, struct blkcipher_desc *,
struct scatterlist *, struct scatterlist *, unsigned int *,
@@ -178,8 +177,8 @@ void nx_debugfs_fini(struct nx_crypto_driver *);
extern struct crypto_alg nx_cbc_aes_alg;
extern struct crypto_alg nx_ecb_aes_alg;
-extern struct crypto_alg nx_gcm_aes_alg;
-extern struct crypto_alg nx_gcm4106_aes_alg;
+extern struct aead_alg nx_gcm_aes_alg;
+extern struct aead_alg nx_gcm4106_aes_alg;
extern struct crypto_alg nx_ctr_aes_alg;
extern struct crypto_alg nx_ctr3686_aes_alg;
extern struct crypto_alg nx_ccm_aes_alg;
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 4d63e0d4da9a..b2024c95a3cf 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -362,7 +362,13 @@ static void omap_sham_copy_ready_hash(struct ahash_request *req)
static int omap_sham_hw_init(struct omap_sham_dev *dd)
{
- pm_runtime_get_sync(dd->dev);
+ int err;
+
+ err = pm_runtime_get_sync(dd->dev);
+ if (err < 0) {
+ dev_err(dd->dev, "failed to get sync: %d\n", err);
+ return err;
+ }
if (!test_bit(FLAGS_INIT, &dd->flags)) {
set_bit(FLAGS_INIT, &dd->flags);
@@ -1793,6 +1799,10 @@ static const struct of_device_id omap_sham_of_match[] = {
.data = &omap_sham_pdata_omap2,
},
{
+ .compatible = "ti,omap3-sham",
+ .data = &omap_sham_pdata_omap2,
+ },
+ {
.compatible = "ti,omap4-sham",
.data = &omap_sham_pdata_omap4,
},
@@ -1947,7 +1957,13 @@ static int omap_sham_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
pm_runtime_irq_safe(dev);
- pm_runtime_get_sync(dev);
+
+ err = pm_runtime_get_sync(dev);
+ if (err < 0) {
+ dev_err(dev, "failed to get sync: %d\n", err);
+ goto err_pm;
+ }
+
rev = omap_sham_read(dd, SHA_REG_REV(dd));
pm_runtime_put_sync(&pdev->dev);
@@ -1977,6 +1993,7 @@ err_algs:
for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
crypto_unregister_ahash(
&dd->pdata->algs_info[i].algs_list[j]);
+err_pm:
pm_runtime_disable(dev);
if (dd->dma_lch)
dma_release_channel(dd->dma_lch);
@@ -2019,7 +2036,11 @@ static int omap_sham_suspend(struct device *dev)
static int omap_sham_resume(struct device *dev)
{
- pm_runtime_get_sync(dev);
+ int err = pm_runtime_get_sync(dev);
+ if (err < 0) {
+ dev_err(dev, "failed to get sync: %d\n", err);
+ return err;
+ }
return 0;
}
#endif
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index c178ed8c3908..da2d6777bd09 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -22,7 +22,7 @@
#include <asm/cpu_device_id.h>
#include <asm/byteorder.h>
#include <asm/processor.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
/*
* Number of data blocks actually fetched for each xcrypt insn.
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index 95f7d27ce491..4e154c9b9206 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -23,7 +23,7 @@
#include <linux/kernel.h>
#include <linux/scatterlist.h>
#include <asm/cpu_device_id.h>
-#include <asm/i387.h>
+#include <asm/fpu/api.h>
struct padlock_sha_desc {
struct shash_desc fallback;
diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c
index 5da5b98b8f29..4f56f3681abd 100644
--- a/drivers/crypto/picoxcell_crypto.c
+++ b/drivers/crypto/picoxcell_crypto.c
@@ -15,7 +15,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <crypto/aead.h>
+#include <crypto/internal/aead.h>
#include <crypto/aes.h>
#include <crypto/algapi.h>
#include <crypto/authenc.h>
@@ -40,6 +40,7 @@
#include <linux/rtnetlink.h>
#include <linux/scatterlist.h>
#include <linux/sched.h>
+#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/timer.h>
@@ -261,18 +262,9 @@ static unsigned spacc_load_ctx(struct spacc_generic_ctx *ctx,
}
/* Count the number of scatterlist entries in a scatterlist. */
-static int sg_count(struct scatterlist *sg_list, int nbytes)
+static inline int sg_count(struct scatterlist *sg_list, int nbytes)
{
- struct scatterlist *sg = sg_list;
- int sg_nents = 0;
-
- while (nbytes > 0) {
- ++sg_nents;
- nbytes -= sg->length;
- sg = sg_next(sg);
- }
-
- return sg_nents;
+ return sg_nents_for_len(sg_list, nbytes);
}
static inline void ddt_set(struct spacc_ddt *ddt, dma_addr_t phys, size_t len)
@@ -326,6 +318,7 @@ static int spacc_aead_make_ddts(struct spacc_req *req, u8 *giv)
struct spacc_ddt *src_ddt, *dst_ddt;
unsigned ivsize = crypto_aead_ivsize(crypto_aead_reqtfm(areq));
unsigned nents = sg_count(areq->src, areq->cryptlen);
+ unsigned total;
dma_addr_t iv_addr;
struct scatterlist *cur;
int i, dst_ents, src_ents, assoc_ents;
@@ -369,11 +362,18 @@ static int spacc_aead_make_ddts(struct spacc_req *req, u8 *giv)
* Map the associated data. For decryption we don't copy the
* associated data.
*/
+ total = areq->assoclen;
for_each_sg(areq->assoc, cur, assoc_ents, i) {
- ddt_set(src_ddt++, sg_dma_address(cur), sg_dma_len(cur));
+ unsigned len = sg_dma_len(cur);
+
+ if (len > total)
+ len = total;
+
+ total -= len;
+
+ ddt_set(src_ddt++, sg_dma_address(cur), len);
if (req->is_encrypt)
- ddt_set(dst_ddt++, sg_dma_address(cur),
- sg_dma_len(cur));
+ ddt_set(dst_ddt++, sg_dma_address(cur), len);
}
ddt_set(src_ddt++, iv_addr, ivsize);
@@ -790,7 +790,8 @@ static int spacc_aead_cra_init(struct crypto_tfm *tfm)
get_random_bytes(ctx->salt, sizeof(ctx->salt));
- tfm->crt_aead.reqsize = sizeof(struct spacc_req);
+ crypto_aead_set_reqsize(__crypto_aead_cast(tfm),
+ sizeof(struct spacc_req));
return 0;
}
@@ -1754,15 +1755,15 @@ static int spacc_probe(struct platform_device *pdev)
return PTR_ERR(engine->clk);
}
- if (clk_enable(engine->clk)) {
- dev_info(&pdev->dev, "unable to enable clk\n");
+ if (clk_prepare_enable(engine->clk)) {
+ dev_info(&pdev->dev, "unable to prepare/enable clk\n");
clk_put(engine->clk);
return -EIO;
}
err = device_create_file(&pdev->dev, &dev_attr_stat_irq_thresh);
if (err) {
- clk_disable(engine->clk);
+ clk_disable_unprepare(engine->clk);
clk_put(engine->clk);
return err;
}
@@ -1830,7 +1831,7 @@ static int spacc_remove(struct platform_device *pdev)
crypto_unregister_alg(&alg->alg);
}
- clk_disable(engine->clk);
+ clk_disable_unprepare(engine->clk);
clk_put(engine->clk);
return 0;
diff --git a/drivers/crypto/qat/Kconfig b/drivers/crypto/qat/Kconfig
index 49bede2a9f77..6fdb9e8b22a7 100644
--- a/drivers/crypto/qat/Kconfig
+++ b/drivers/crypto/qat/Kconfig
@@ -2,9 +2,8 @@ config CRYPTO_DEV_QAT
tristate
select CRYPTO_AEAD
select CRYPTO_AUTHENC
- select CRYPTO_ALGAPI
- select CRYPTO_AES
- select CRYPTO_CBC
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_HMAC
select CRYPTO_SHA1
select CRYPTO_SHA256
select CRYPTO_SHA512
@@ -13,7 +12,6 @@ config CRYPTO_DEV_QAT
config CRYPTO_DEV_QAT_DH895xCC
tristate "Support for Intel(R) DH895xCC"
depends on X86 && PCI
- default n
select CRYPTO_DEV_QAT
help
Support for Intel(R) DH895xcc with Intel(R) QuickAssist Technology
diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h
index f22ce7169fa5..5fe902967620 100644
--- a/drivers/crypto/qat/qat_common/adf_accel_devices.h
+++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h
@@ -48,7 +48,6 @@
#define ADF_ACCEL_DEVICES_H_
#include <linux/module.h>
#include <linux/list.h>
-#include <linux/proc_fs.h>
#include <linux/io.h>
#include "adf_cfg_common.h"
diff --git a/drivers/crypto/qat/qat_common/adf_cfg_user.h b/drivers/crypto/qat/qat_common/adf_cfg_user.h
index 0c38a155a865..ef5988afd4c6 100644
--- a/drivers/crypto/qat/qat_common/adf_cfg_user.h
+++ b/drivers/crypto/qat/qat_common/adf_cfg_user.h
@@ -54,14 +54,6 @@ struct adf_user_cfg_key_val {
char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES];
char val[ADF_CFG_MAX_VAL_LEN_IN_BYTES];
union {
- char *user_val_ptr;
- uint64_t padding1;
- };
- union {
- struct adf_user_cfg_key_val *prev;
- uint64_t padding2;
- };
- union {
struct adf_user_cfg_key_val *next;
uint64_t padding3;
};
@@ -75,10 +67,6 @@ struct adf_user_cfg_section {
uint64_t padding1;
};
union {
- struct adf_user_cfg_section *prev;
- uint64_t padding2;
- };
- union {
struct adf_user_cfg_section *next;
uint64_t padding3;
};
diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h
index 0666ee6a3360..27e16c09230b 100644
--- a/drivers/crypto/qat/qat_common/adf_common_drv.h
+++ b/drivers/crypto/qat/qat_common/adf_common_drv.h
@@ -53,6 +53,13 @@
#include "icp_qat_fw_loader_handle.h"
#include "icp_qat_hal.h"
+#define ADF_MAJOR_VERSION 0
+#define ADF_MINOR_VERSION 1
+#define ADF_BUILD_VERSION 3
+#define ADF_DRV_VERSION __stringify(ADF_MAJOR_VERSION) "." \
+ __stringify(ADF_MINOR_VERSION) "." \
+ __stringify(ADF_BUILD_VERSION)
+
#define ADF_STATUS_RESTARTING 0
#define ADF_STATUS_STARTING 1
#define ADF_STATUS_CONFIGURED 2
diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c
index cb5f066e93a6..e056b9e9bf8a 100644
--- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c
+++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c
@@ -504,3 +504,4 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Intel");
MODULE_DESCRIPTION("Intel(R) QuickAssist Technology");
MODULE_ALIAS_CRYPTO("intel_qat");
+MODULE_VERSION(ADF_DRV_VERSION);
diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
index 1dc5b0a17cf7..067402c7c2a9 100644
--- a/drivers/crypto/qat/qat_common/qat_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_algs.c
@@ -47,7 +47,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/crypto.h>
-#include <crypto/aead.h>
+#include <crypto/internal/aead.h>
#include <crypto/aes.h>
#include <crypto/sha.h>
#include <crypto/hash.h>
@@ -653,7 +653,7 @@ static void qat_alg_free_bufl(struct qat_crypto_instance *inst,
}
static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst,
- struct scatterlist *assoc,
+ struct scatterlist *assoc, int assoclen,
struct scatterlist *sgl,
struct scatterlist *sglout, uint8_t *iv,
uint8_t ivlen,
@@ -685,15 +685,21 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst,
for_each_sg(assoc, sg, assoc_n, i) {
if (!sg->length)
continue;
- bufl->bufers[bufs].addr = dma_map_single(dev,
- sg_virt(sg),
- sg->length,
- DMA_BIDIRECTIONAL);
- bufl->bufers[bufs].len = sg->length;
+
+ if (!(assoclen > 0))
+ break;
+
+ bufl->bufers[bufs].addr =
+ dma_map_single(dev, sg_virt(sg),
+ min_t(int, assoclen, sg->length),
+ DMA_BIDIRECTIONAL);
+ bufl->bufers[bufs].len = min_t(int, assoclen, sg->length);
if (unlikely(dma_mapping_error(dev, bufl->bufers[bufs].addr)))
goto err;
bufs++;
+ assoclen -= sg->length;
}
+
if (ivlen) {
bufl->bufers[bufs].addr = dma_map_single(dev, iv, ivlen,
DMA_BIDIRECTIONAL);
@@ -845,8 +851,9 @@ static int qat_alg_aead_dec(struct aead_request *areq)
int digst_size = crypto_aead_crt(aead_tfm)->authsize;
int ret, ctr = 0;
- ret = qat_alg_sgl_to_bufl(ctx->inst, areq->assoc, areq->src, areq->dst,
- areq->iv, AES_BLOCK_SIZE, qat_req);
+ ret = qat_alg_sgl_to_bufl(ctx->inst, areq->assoc, areq->assoclen,
+ areq->src, areq->dst, areq->iv,
+ AES_BLOCK_SIZE, qat_req);
if (unlikely(ret))
return ret;
@@ -889,8 +896,9 @@ static int qat_alg_aead_enc_internal(struct aead_request *areq, uint8_t *iv,
struct icp_qat_fw_la_bulk_req *msg;
int ret, ctr = 0;
- ret = qat_alg_sgl_to_bufl(ctx->inst, areq->assoc, areq->src, areq->dst,
- iv, AES_BLOCK_SIZE, qat_req);
+ ret = qat_alg_sgl_to_bufl(ctx->inst, areq->assoc, areq->assoclen,
+ areq->src, areq->dst, iv, AES_BLOCK_SIZE,
+ qat_req);
if (unlikely(ret))
return ret;
@@ -1017,7 +1025,7 @@ static int qat_alg_ablkcipher_encrypt(struct ablkcipher_request *req)
struct icp_qat_fw_la_bulk_req *msg;
int ret, ctr = 0;
- ret = qat_alg_sgl_to_bufl(ctx->inst, NULL, req->src, req->dst,
+ ret = qat_alg_sgl_to_bufl(ctx->inst, NULL, 0, req->src, req->dst,
NULL, 0, qat_req);
if (unlikely(ret))
return ret;
@@ -1055,7 +1063,7 @@ static int qat_alg_ablkcipher_decrypt(struct ablkcipher_request *req)
struct icp_qat_fw_la_bulk_req *msg;
int ret, ctr = 0;
- ret = qat_alg_sgl_to_bufl(ctx->inst, NULL, req->src, req->dst,
+ ret = qat_alg_sgl_to_bufl(ctx->inst, NULL, 0, req->src, req->dst,
NULL, 0, qat_req);
if (unlikely(ret))
return ret;
@@ -1094,8 +1102,9 @@ static int qat_alg_aead_init(struct crypto_tfm *tfm,
return -EFAULT;
spin_lock_init(&ctx->lock);
ctx->qat_hash_alg = hash;
- tfm->crt_aead.reqsize = sizeof(struct aead_request) +
- sizeof(struct qat_crypto_request);
+ crypto_aead_set_reqsize(__crypto_aead_cast(tfm),
+ sizeof(struct aead_request) +
+ sizeof(struct qat_crypto_request));
ctx->tfm = tfm;
return 0;
}
diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c
index 9decea2779c6..1bde45b7a3c5 100644
--- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c
+++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c
@@ -300,6 +300,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
goto out_err;
+ pcie_set_readrq(pdev, 1024);
+
/* enable PCI device */
if (pci_enable_device(pdev)) {
ret = -EFAULT;
@@ -417,5 +419,6 @@ module_exit(adfdrv_release);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Intel");
-MODULE_FIRMWARE("qat_895xcc.bin");
+MODULE_FIRMWARE(ADF_DH895XCC_FW);
MODULE_DESCRIPTION("Intel(R) QuickAssist Technology");
+MODULE_VERSION(ADF_DRV_VERSION);
diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c
index 6be377f6b9e7..397a500b3d8a 100644
--- a/drivers/crypto/sahara.c
+++ b/drivers/crypto/sahara.c
@@ -1578,8 +1578,12 @@ static int sahara_probe(struct platform_device *pdev)
init_completion(&dev->dma_completion);
- clk_prepare_enable(dev->clk_ipg);
- clk_prepare_enable(dev->clk_ahb);
+ err = clk_prepare_enable(dev->clk_ipg);
+ if (err)
+ goto err_link;
+ err = clk_prepare_enable(dev->clk_ahb);
+ if (err)
+ goto clk_ipg_disable;
version = sahara_read(dev, SAHARA_REG_VERSION);
if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx27-sahara")) {
@@ -1619,10 +1623,11 @@ err_algs:
dma_free_coherent(&pdev->dev,
SAHARA_MAX_HW_LINK * sizeof(struct sahara_hw_link),
dev->hw_link[0], dev->hw_phys_link[0]);
- clk_disable_unprepare(dev->clk_ipg);
- clk_disable_unprepare(dev->clk_ahb);
kthread_stop(dev->kthread);
dev_ptr = NULL;
+ clk_disable_unprepare(dev->clk_ahb);
+clk_ipg_disable:
+ clk_disable_unprepare(dev->clk_ipg);
err_link:
dma_free_coherent(&pdev->dev,
2 * AES_KEYSIZE_128,
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 857414afa29a..83aca95a95bc 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -46,7 +46,7 @@
#include <crypto/des.h>
#include <crypto/sha.h>
#include <crypto/md5.h>
-#include <crypto/aead.h>
+#include <crypto/internal/aead.h>
#include <crypto/authenc.h>
#include <crypto/skcipher.h>
#include <crypto/hash.h>
@@ -55,49 +55,92 @@
#include "talitos.h"
-static void to_talitos_ptr(struct talitos_ptr *talitos_ptr, dma_addr_t dma_addr)
+static void to_talitos_ptr(struct talitos_ptr *ptr, dma_addr_t dma_addr,
+ bool is_sec1)
{
- talitos_ptr->ptr = cpu_to_be32(lower_32_bits(dma_addr));
- talitos_ptr->eptr = upper_32_bits(dma_addr);
+ ptr->ptr = cpu_to_be32(lower_32_bits(dma_addr));
+ if (!is_sec1)
+ ptr->eptr = upper_32_bits(dma_addr);
+}
+
+static void to_talitos_ptr_len(struct talitos_ptr *ptr, unsigned int len,
+ bool is_sec1)
+{
+ if (is_sec1) {
+ ptr->res = 0;
+ ptr->len1 = cpu_to_be16(len);
+ } else {
+ ptr->len = cpu_to_be16(len);
+ }
+}
+
+static unsigned short from_talitos_ptr_len(struct talitos_ptr *ptr,
+ bool is_sec1)
+{
+ if (is_sec1)
+ return be16_to_cpu(ptr->len1);
+ else
+ return be16_to_cpu(ptr->len);
+}
+
+static void to_talitos_ptr_extent_clear(struct talitos_ptr *ptr, bool is_sec1)
+{
+ if (!is_sec1)
+ ptr->j_extent = 0;
}
/*
* map virtual single (contiguous) pointer to h/w descriptor pointer
*/
static void map_single_talitos_ptr(struct device *dev,
- struct talitos_ptr *talitos_ptr,
- unsigned short len, void *data,
- unsigned char extent,
+ struct talitos_ptr *ptr,
+ unsigned int len, void *data,
enum dma_data_direction dir)
{
dma_addr_t dma_addr = dma_map_single(dev, data, len, dir);
+ struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
- talitos_ptr->len = cpu_to_be16(len);
- to_talitos_ptr(talitos_ptr, dma_addr);
- talitos_ptr->j_extent = extent;
+ to_talitos_ptr_len(ptr, len, is_sec1);
+ to_talitos_ptr(ptr, dma_addr, is_sec1);
+ to_talitos_ptr_extent_clear(ptr, is_sec1);
}
/*
* unmap bus single (contiguous) h/w descriptor pointer
*/
static void unmap_single_talitos_ptr(struct device *dev,
- struct talitos_ptr *talitos_ptr,
+ struct talitos_ptr *ptr,
enum dma_data_direction dir)
{
- dma_unmap_single(dev, be32_to_cpu(talitos_ptr->ptr),
- be16_to_cpu(talitos_ptr->len), dir);
+ struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
+
+ dma_unmap_single(dev, be32_to_cpu(ptr->ptr),
+ from_talitos_ptr_len(ptr, is_sec1), dir);
}
static int reset_channel(struct device *dev, int ch)
{
struct talitos_private *priv = dev_get_drvdata(dev);
unsigned int timeout = TALITOS_TIMEOUT;
+ bool is_sec1 = has_ftr_sec1(priv);
- setbits32(priv->chan[ch].reg + TALITOS_CCCR, TALITOS_CCCR_RESET);
+ if (is_sec1) {
+ setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO,
+ TALITOS1_CCCR_LO_RESET);
- while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) & TALITOS_CCCR_RESET)
- && --timeout)
- cpu_relax();
+ while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR_LO) &
+ TALITOS1_CCCR_LO_RESET) && --timeout)
+ cpu_relax();
+ } else {
+ setbits32(priv->chan[ch].reg + TALITOS_CCCR,
+ TALITOS2_CCCR_RESET);
+
+ while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) &
+ TALITOS2_CCCR_RESET) && --timeout)
+ cpu_relax();
+ }
if (timeout == 0) {
dev_err(dev, "failed to reset channel %d\n", ch);
@@ -120,11 +163,12 @@ static int reset_device(struct device *dev)
{
struct talitos_private *priv = dev_get_drvdata(dev);
unsigned int timeout = TALITOS_TIMEOUT;
- u32 mcr = TALITOS_MCR_SWR;
+ bool is_sec1 = has_ftr_sec1(priv);
+ u32 mcr = is_sec1 ? TALITOS1_MCR_SWR : TALITOS2_MCR_SWR;
setbits32(priv->reg + TALITOS_MCR, mcr);
- while ((in_be32(priv->reg + TALITOS_MCR) & TALITOS_MCR_SWR)
+ while ((in_be32(priv->reg + TALITOS_MCR) & mcr)
&& --timeout)
cpu_relax();
@@ -148,6 +192,7 @@ static int init_device(struct device *dev)
{
struct talitos_private *priv = dev_get_drvdata(dev);
int ch, err;
+ bool is_sec1 = has_ftr_sec1(priv);
/*
* Master reset
@@ -171,12 +216,19 @@ static int init_device(struct device *dev)
}
/* enable channel done and error interrupts */
- setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT);
- setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);
+ if (is_sec1) {
+ clrbits32(priv->reg + TALITOS_IMR, TALITOS1_IMR_INIT);
+ clrbits32(priv->reg + TALITOS_IMR_LO, TALITOS1_IMR_LO_INIT);
+ /* disable parity error check in DEU (erroneous? test vect.) */
+ setbits32(priv->reg_deu + TALITOS_EUICR, TALITOS1_DEUICR_KPE);
+ } else {
+ setbits32(priv->reg + TALITOS_IMR, TALITOS2_IMR_INIT);
+ setbits32(priv->reg + TALITOS_IMR_LO, TALITOS2_IMR_LO_INIT);
+ }
/* disable integrity check error interrupts (use writeback instead) */
if (priv->features & TALITOS_FTR_HW_AUTH_CHECK)
- setbits32(priv->reg + TALITOS_MDEUICR_LO,
+ setbits32(priv->reg_mdeu + TALITOS_EUICR_LO,
TALITOS_MDEUICR_LO_ICE);
return 0;
@@ -204,6 +256,7 @@ int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
struct talitos_request *request;
unsigned long flags;
int head;
+ bool is_sec1 = has_ftr_sec1(priv);
spin_lock_irqsave(&priv->chan[ch].head_lock, flags);
@@ -217,8 +270,17 @@ int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
request = &priv->chan[ch].fifo[head];
/* map descriptor and save caller data */
- request->dma_desc = dma_map_single(dev, desc, sizeof(*desc),
- DMA_BIDIRECTIONAL);
+ if (is_sec1) {
+ desc->hdr1 = desc->hdr;
+ desc->next_desc = 0;
+ request->dma_desc = dma_map_single(dev, &desc->hdr1,
+ TALITOS_DESC_SIZE,
+ DMA_BIDIRECTIONAL);
+ } else {
+ request->dma_desc = dma_map_single(dev, desc,
+ TALITOS_DESC_SIZE,
+ DMA_BIDIRECTIONAL);
+ }
request->callback = callback;
request->context = context;
@@ -250,16 +312,21 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
struct talitos_request *request, saved_req;
unsigned long flags;
int tail, status;
+ bool is_sec1 = has_ftr_sec1(priv);
spin_lock_irqsave(&priv->chan[ch].tail_lock, flags);
tail = priv->chan[ch].tail;
while (priv->chan[ch].fifo[tail].desc) {
+ __be32 hdr;
+
request = &priv->chan[ch].fifo[tail];
/* descriptors with their done bits set don't get the error */
rmb();
- if ((request->desc->hdr & DESC_HDR_DONE) == DESC_HDR_DONE)
+ hdr = is_sec1 ? request->desc->hdr1 : request->desc->hdr;
+
+ if ((hdr & DESC_HDR_DONE) == DESC_HDR_DONE)
status = 0;
else
if (!error)
@@ -268,7 +335,7 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
status = error;
dma_unmap_single(dev, request->dma_desc,
- sizeof(struct talitos_desc),
+ TALITOS_DESC_SIZE,
DMA_BIDIRECTIONAL);
/* copy entries so we can call callback outside lock */
@@ -302,8 +369,37 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
/*
* process completed requests for channels that have done status
*/
-#define DEF_TALITOS_DONE(name, ch_done_mask) \
-static void talitos_done_##name(unsigned long data) \
+#define DEF_TALITOS1_DONE(name, ch_done_mask) \
+static void talitos1_done_##name(unsigned long data) \
+{ \
+ struct device *dev = (struct device *)data; \
+ struct talitos_private *priv = dev_get_drvdata(dev); \
+ unsigned long flags; \
+ \
+ if (ch_done_mask & 0x10000000) \
+ flush_channel(dev, 0, 0, 0); \
+ if (priv->num_channels == 1) \
+ goto out; \
+ if (ch_done_mask & 0x40000000) \
+ flush_channel(dev, 1, 0, 0); \
+ if (ch_done_mask & 0x00010000) \
+ flush_channel(dev, 2, 0, 0); \
+ if (ch_done_mask & 0x00040000) \
+ flush_channel(dev, 3, 0, 0); \
+ \
+out: \
+ /* At this point, all completed channels have been processed */ \
+ /* Unmask done interrupts for channels completed later on. */ \
+ spin_lock_irqsave(&priv->reg_lock, flags); \
+ clrbits32(priv->reg + TALITOS_IMR, ch_done_mask); \
+ clrbits32(priv->reg + TALITOS_IMR_LO, TALITOS1_IMR_LO_INIT); \
+ spin_unlock_irqrestore(&priv->reg_lock, flags); \
+}
+
+DEF_TALITOS1_DONE(4ch, TALITOS1_ISR_4CHDONE)
+
+#define DEF_TALITOS2_DONE(name, ch_done_mask) \
+static void talitos2_done_##name(unsigned long data) \
{ \
struct device *dev = (struct device *)data; \
struct talitos_private *priv = dev_get_drvdata(dev); \
@@ -325,12 +421,13 @@ out: \
/* Unmask done interrupts for channels completed later on. */ \
spin_lock_irqsave(&priv->reg_lock, flags); \
setbits32(priv->reg + TALITOS_IMR, ch_done_mask); \
- setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT); \
+ setbits32(priv->reg + TALITOS_IMR_LO, TALITOS2_IMR_LO_INIT); \
spin_unlock_irqrestore(&priv->reg_lock, flags); \
}
-DEF_TALITOS_DONE(4ch, TALITOS_ISR_4CHDONE)
-DEF_TALITOS_DONE(ch0_2, TALITOS_ISR_CH_0_2_DONE)
-DEF_TALITOS_DONE(ch1_3, TALITOS_ISR_CH_1_3_DONE)
+
+DEF_TALITOS2_DONE(4ch, TALITOS2_ISR_4CHDONE)
+DEF_TALITOS2_DONE(ch0_2, TALITOS2_ISR_CH_0_2_DONE)
+DEF_TALITOS2_DONE(ch1_3, TALITOS2_ISR_CH_1_3_DONE)
/*
* locate current (offending) descriptor
@@ -377,44 +474,44 @@ static void report_eu_error(struct device *dev, int ch, u32 desc_hdr)
switch (desc_hdr & DESC_HDR_SEL0_MASK) {
case DESC_HDR_SEL0_AFEU:
dev_err(dev, "AFEUISR 0x%08x_%08x\n",
- in_be32(priv->reg + TALITOS_AFEUISR),
- in_be32(priv->reg + TALITOS_AFEUISR_LO));
+ in_be32(priv->reg_afeu + TALITOS_EUISR),
+ in_be32(priv->reg_afeu + TALITOS_EUISR_LO));
break;
case DESC_HDR_SEL0_DEU:
dev_err(dev, "DEUISR 0x%08x_%08x\n",
- in_be32(priv->reg + TALITOS_DEUISR),
- in_be32(priv->reg + TALITOS_DEUISR_LO));
+ in_be32(priv->reg_deu + TALITOS_EUISR),
+ in_be32(priv->reg_deu + TALITOS_EUISR_LO));
break;
case DESC_HDR_SEL0_MDEUA:
case DESC_HDR_SEL0_MDEUB:
dev_err(dev, "MDEUISR 0x%08x_%08x\n",
- in_be32(priv->reg + TALITOS_MDEUISR),
- in_be32(priv->reg + TALITOS_MDEUISR_LO));
+ in_be32(priv->reg_mdeu + TALITOS_EUISR),
+ in_be32(priv->reg_mdeu + TALITOS_EUISR_LO));
break;
case DESC_HDR_SEL0_RNG:
dev_err(dev, "RNGUISR 0x%08x_%08x\n",
- in_be32(priv->reg + TALITOS_RNGUISR),
- in_be32(priv->reg + TALITOS_RNGUISR_LO));
+ in_be32(priv->reg_rngu + TALITOS_ISR),
+ in_be32(priv->reg_rngu + TALITOS_ISR_LO));
break;
case DESC_HDR_SEL0_PKEU:
dev_err(dev, "PKEUISR 0x%08x_%08x\n",
- in_be32(priv->reg + TALITOS_PKEUISR),
- in_be32(priv->reg + TALITOS_PKEUISR_LO));
+ in_be32(priv->reg_pkeu + TALITOS_EUISR),
+ in_be32(priv->reg_pkeu + TALITOS_EUISR_LO));
break;
case DESC_HDR_SEL0_AESU:
dev_err(dev, "AESUISR 0x%08x_%08x\n",
- in_be32(priv->reg + TALITOS_AESUISR),
- in_be32(priv->reg + TALITOS_AESUISR_LO));
+ in_be32(priv->reg_aesu + TALITOS_EUISR),
+ in_be32(priv->reg_aesu + TALITOS_EUISR_LO));
break;
case DESC_HDR_SEL0_CRCU:
dev_err(dev, "CRCUISR 0x%08x_%08x\n",
- in_be32(priv->reg + TALITOS_CRCUISR),
- in_be32(priv->reg + TALITOS_CRCUISR_LO));
+ in_be32(priv->reg_crcu + TALITOS_EUISR),
+ in_be32(priv->reg_crcu + TALITOS_EUISR_LO));
break;
case DESC_HDR_SEL0_KEU:
dev_err(dev, "KEUISR 0x%08x_%08x\n",
- in_be32(priv->reg + TALITOS_KEUISR),
- in_be32(priv->reg + TALITOS_KEUISR_LO));
+ in_be32(priv->reg_pkeu + TALITOS_EUISR),
+ in_be32(priv->reg_pkeu + TALITOS_EUISR_LO));
break;
}
@@ -422,13 +519,13 @@ static void report_eu_error(struct device *dev, int ch, u32 desc_hdr)
case DESC_HDR_SEL1_MDEUA:
case DESC_HDR_SEL1_MDEUB:
dev_err(dev, "MDEUISR 0x%08x_%08x\n",
- in_be32(priv->reg + TALITOS_MDEUISR),
- in_be32(priv->reg + TALITOS_MDEUISR_LO));
+ in_be32(priv->reg_mdeu + TALITOS_EUISR),
+ in_be32(priv->reg_mdeu + TALITOS_EUISR_LO));
break;
case DESC_HDR_SEL1_CRCU:
dev_err(dev, "CRCUISR 0x%08x_%08x\n",
- in_be32(priv->reg + TALITOS_CRCUISR),
- in_be32(priv->reg + TALITOS_CRCUISR_LO));
+ in_be32(priv->reg_crcu + TALITOS_EUISR),
+ in_be32(priv->reg_crcu + TALITOS_EUISR_LO));
break;
}
@@ -445,17 +542,24 @@ static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
{
struct talitos_private *priv = dev_get_drvdata(dev);
unsigned int timeout = TALITOS_TIMEOUT;
- int ch, error, reset_dev = 0, reset_ch = 0;
- u32 v, v_lo;
+ int ch, error, reset_dev = 0;
+ u32 v_lo;
+ bool is_sec1 = has_ftr_sec1(priv);
+ int reset_ch = is_sec1 ? 1 : 0; /* only SEC2 supports continuation */
for (ch = 0; ch < priv->num_channels; ch++) {
/* skip channels without errors */
- if (!(isr & (1 << (ch * 2 + 1))))
- continue;
+ if (is_sec1) {
+ /* bits 29, 31, 17, 19 */
+ if (!(isr & (1 << (29 + (ch & 1) * 2 - (ch & 2) * 6))))
+ continue;
+ } else {
+ if (!(isr & (1 << (ch * 2 + 1))))
+ continue;
+ }
error = -EINVAL;
- v = in_be32(priv->chan[ch].reg + TALITOS_CCPSR);
v_lo = in_be32(priv->chan[ch].reg + TALITOS_CCPSR_LO);
if (v_lo & TALITOS_CCPSR_LO_DOF) {
@@ -471,23 +575,28 @@ static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
if (v_lo & TALITOS_CCPSR_LO_MDTE)
dev_err(dev, "master data transfer error\n");
if (v_lo & TALITOS_CCPSR_LO_SGDLZ)
- dev_err(dev, "s/g data length zero error\n");
+ dev_err(dev, is_sec1 ? "pointeur not complete error\n"
+ : "s/g data length zero error\n");
if (v_lo & TALITOS_CCPSR_LO_FPZ)
- dev_err(dev, "fetch pointer zero error\n");
+ dev_err(dev, is_sec1 ? "parity error\n"
+ : "fetch pointer zero error\n");
if (v_lo & TALITOS_CCPSR_LO_IDH)
dev_err(dev, "illegal descriptor header error\n");
if (v_lo & TALITOS_CCPSR_LO_IEU)
- dev_err(dev, "invalid execution unit error\n");
+ dev_err(dev, is_sec1 ? "static assignment error\n"
+ : "invalid exec unit error\n");
if (v_lo & TALITOS_CCPSR_LO_EU)
report_eu_error(dev, ch, current_desc_hdr(dev, ch));
- if (v_lo & TALITOS_CCPSR_LO_GB)
- dev_err(dev, "gather boundary error\n");
- if (v_lo & TALITOS_CCPSR_LO_GRL)
- dev_err(dev, "gather return/length error\n");
- if (v_lo & TALITOS_CCPSR_LO_SB)
- dev_err(dev, "scatter boundary error\n");
- if (v_lo & TALITOS_CCPSR_LO_SRL)
- dev_err(dev, "scatter return/length error\n");
+ if (!is_sec1) {
+ if (v_lo & TALITOS_CCPSR_LO_GB)
+ dev_err(dev, "gather boundary error\n");
+ if (v_lo & TALITOS_CCPSR_LO_GRL)
+ dev_err(dev, "gather return/length error\n");
+ if (v_lo & TALITOS_CCPSR_LO_SB)
+ dev_err(dev, "scatter boundary error\n");
+ if (v_lo & TALITOS_CCPSR_LO_SRL)
+ dev_err(dev, "scatter return/length error\n");
+ }
flush_channel(dev, ch, error, reset_ch);
@@ -495,10 +604,10 @@ static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
reset_channel(dev, ch);
} else {
setbits32(priv->chan[ch].reg + TALITOS_CCCR,
- TALITOS_CCCR_CONT);
+ TALITOS2_CCCR_CONT);
setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO, 0);
while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) &
- TALITOS_CCCR_CONT) && --timeout)
+ TALITOS2_CCCR_CONT) && --timeout)
cpu_relax();
if (timeout == 0) {
dev_err(dev, "failed to restart channel %d\n",
@@ -507,9 +616,14 @@ static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
}
}
}
- if (reset_dev || isr & ~TALITOS_ISR_4CHERR || isr_lo) {
- dev_err(dev, "done overflow, internal time out, or rngu error: "
- "ISR 0x%08x_%08x\n", isr, isr_lo);
+ if (reset_dev || (is_sec1 && isr & ~TALITOS1_ISR_4CHERR) ||
+ (!is_sec1 && isr & ~TALITOS2_ISR_4CHERR) || isr_lo) {
+ if (is_sec1 && (isr_lo & TALITOS1_ISR_TEA_ERR))
+ dev_err(dev, "TEA error: ISR 0x%08x_%08x\n",
+ isr, isr_lo);
+ else
+ dev_err(dev, "done overflow, internal time out, or "
+ "rngu error: ISR 0x%08x_%08x\n", isr, isr_lo);
/* purge request queues */
for (ch = 0; ch < priv->num_channels; ch++)
@@ -520,8 +634,43 @@ static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
}
}
-#define DEF_TALITOS_INTERRUPT(name, ch_done_mask, ch_err_mask, tlet) \
-static irqreturn_t talitos_interrupt_##name(int irq, void *data) \
+#define DEF_TALITOS1_INTERRUPT(name, ch_done_mask, ch_err_mask, tlet) \
+static irqreturn_t talitos1_interrupt_##name(int irq, void *data) \
+{ \
+ struct device *dev = data; \
+ struct talitos_private *priv = dev_get_drvdata(dev); \
+ u32 isr, isr_lo; \
+ unsigned long flags; \
+ \
+ spin_lock_irqsave(&priv->reg_lock, flags); \
+ isr = in_be32(priv->reg + TALITOS_ISR); \
+ isr_lo = in_be32(priv->reg + TALITOS_ISR_LO); \
+ /* Acknowledge interrupt */ \
+ out_be32(priv->reg + TALITOS_ICR, isr & (ch_done_mask | ch_err_mask)); \
+ out_be32(priv->reg + TALITOS_ICR_LO, isr_lo); \
+ \
+ if (unlikely(isr & ch_err_mask || isr_lo & TALITOS1_IMR_LO_INIT)) { \
+ spin_unlock_irqrestore(&priv->reg_lock, flags); \
+ talitos_error(dev, isr & ch_err_mask, isr_lo); \
+ } \
+ else { \
+ if (likely(isr & ch_done_mask)) { \
+ /* mask further done interrupts. */ \
+ setbits32(priv->reg + TALITOS_IMR, ch_done_mask); \
+ /* done_task will unmask done interrupts at exit */ \
+ tasklet_schedule(&priv->done_task[tlet]); \
+ } \
+ spin_unlock_irqrestore(&priv->reg_lock, flags); \
+ } \
+ \
+ return (isr & (ch_done_mask | ch_err_mask) || isr_lo) ? IRQ_HANDLED : \
+ IRQ_NONE; \
+}
+
+DEF_TALITOS1_INTERRUPT(4ch, TALITOS1_ISR_4CHDONE, TALITOS1_ISR_4CHERR, 0)
+
+#define DEF_TALITOS2_INTERRUPT(name, ch_done_mask, ch_err_mask, tlet) \
+static irqreturn_t talitos2_interrupt_##name(int irq, void *data) \
{ \
struct device *dev = data; \
struct talitos_private *priv = dev_get_drvdata(dev); \
@@ -552,9 +701,12 @@ static irqreturn_t talitos_interrupt_##name(int irq, void *data) \
return (isr & (ch_done_mask | ch_err_mask) || isr_lo) ? IRQ_HANDLED : \
IRQ_NONE; \
}
-DEF_TALITOS_INTERRUPT(4ch, TALITOS_ISR_4CHDONE, TALITOS_ISR_4CHERR, 0)
-DEF_TALITOS_INTERRUPT(ch0_2, TALITOS_ISR_CH_0_2_DONE, TALITOS_ISR_CH_0_2_ERR, 0)
-DEF_TALITOS_INTERRUPT(ch1_3, TALITOS_ISR_CH_1_3_DONE, TALITOS_ISR_CH_1_3_ERR, 1)
+
+DEF_TALITOS2_INTERRUPT(4ch, TALITOS2_ISR_4CHDONE, TALITOS2_ISR_4CHERR, 0)
+DEF_TALITOS2_INTERRUPT(ch0_2, TALITOS2_ISR_CH_0_2_DONE, TALITOS2_ISR_CH_0_2_ERR,
+ 0)
+DEF_TALITOS2_INTERRUPT(ch1_3, TALITOS2_ISR_CH_1_3_DONE, TALITOS2_ISR_CH_1_3_ERR,
+ 1)
/*
* hwrng
@@ -567,7 +719,7 @@ static int talitos_rng_data_present(struct hwrng *rng, int wait)
int i;
for (i = 0; i < 20; i++) {
- ofl = in_be32(priv->reg + TALITOS_RNGUSR_LO) &
+ ofl = in_be32(priv->reg_rngu + TALITOS_EUSR_LO) &
TALITOS_RNGUSR_LO_OFL;
if (ofl || !wait)
break;
@@ -583,8 +735,8 @@ static int talitos_rng_data_read(struct hwrng *rng, u32 *data)
struct talitos_private *priv = dev_get_drvdata(dev);
/* rng fifo requires 64-bit accesses */
- *data = in_be32(priv->reg + TALITOS_RNGU_FIFO);
- *data = in_be32(priv->reg + TALITOS_RNGU_FIFO_LO);
+ *data = in_be32(priv->reg_rngu + TALITOS_EU_FIFO);
+ *data = in_be32(priv->reg_rngu + TALITOS_EU_FIFO_LO);
return sizeof(u32);
}
@@ -595,8 +747,9 @@ static int talitos_rng_init(struct hwrng *rng)
struct talitos_private *priv = dev_get_drvdata(dev);
unsigned int timeout = TALITOS_TIMEOUT;
- setbits32(priv->reg + TALITOS_RNGURCR_LO, TALITOS_RNGURCR_LO_SR);
- while (!(in_be32(priv->reg + TALITOS_RNGUSR_LO) & TALITOS_RNGUSR_LO_RD)
+ setbits32(priv->reg_rngu + TALITOS_EURCR_LO, TALITOS_RNGURCR_LO_SR);
+ while (!(in_be32(priv->reg_rngu + TALITOS_EUSR_LO)
+ & TALITOS_RNGUSR_LO_RD)
&& --timeout)
cpu_relax();
if (timeout == 0) {
@@ -605,7 +758,7 @@ static int talitos_rng_init(struct hwrng *rng)
}
/* start generating */
- setbits32(priv->reg + TALITOS_RNGUDSR_LO, 0);
+ setbits32(priv->reg_rngu + TALITOS_EUDSR_LO, 0);
return 0;
}
@@ -661,7 +814,7 @@ struct talitos_ahash_req_ctx {
unsigned int first;
unsigned int last;
unsigned int to_hash_later;
- u64 nbuf;
+ unsigned int nbuf;
struct scatterlist bufsl[2];
struct scatterlist *psrc;
};
@@ -712,9 +865,10 @@ badkey:
* @dst_chained: whether dst is chained or not
* @iv_dma: dma address of iv for checking continuity and link table
* @dma_len: length of dma mapped link_tbl space
- * @dma_link_tbl: bus physical address of link_tbl
+ * @dma_link_tbl: bus physical address of link_tbl/buf
* @desc: h/w descriptor
- * @link_tbl: input and output h/w link tables (if {src,dst}_nents > 1)
+ * @link_tbl: input and output h/w link tables (if {src,dst}_nents > 1) (SEC2)
+ * @buf: input and output buffeur (if {src,dst}_nents > 1) (SEC1)
*
* if decrypting (with authcheck), or either one of src_nents or dst_nents
* is greater than 1, an integrity check value is concatenated to the end
@@ -731,7 +885,10 @@ struct talitos_edesc {
int dma_len;
dma_addr_t dma_link_tbl;
struct talitos_desc desc;
- struct talitos_ptr link_tbl[0];
+ union {
+ struct talitos_ptr link_tbl[0];
+ u8 buf[0];
+ };
};
static int talitos_map_sg(struct device *dev, struct scatterlist *sg,
@@ -907,8 +1064,8 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count,
{
int n_sg = sg_count;
- while (n_sg--) {
- to_talitos_ptr(link_tbl_ptr, sg_dma_address(sg));
+ while (sg && n_sg--) {
+ to_talitos_ptr(link_tbl_ptr, sg_dma_address(sg), 0);
link_tbl_ptr->len = cpu_to_be16(sg_dma_len(sg));
link_tbl_ptr->j_extent = 0;
link_tbl_ptr++;
@@ -925,7 +1082,8 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count,
sg_count--;
link_tbl_ptr--;
}
- be16_add_cpu(&link_tbl_ptr->len, cryptlen);
+ link_tbl_ptr->len = cpu_to_be16(be16_to_cpu(link_tbl_ptr->len)
+ + cryptlen);
/* tag end of link table */
link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN;
@@ -953,7 +1111,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
/* hmac key */
map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key,
- 0, DMA_TO_DEVICE);
+ DMA_TO_DEVICE);
/* hmac data */
desc->ptr[1].len = cpu_to_be16(areq->assoclen + ivsize);
@@ -962,7 +1120,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off];
to_talitos_ptr(&desc->ptr[1], edesc->dma_link_tbl + tbl_off *
- sizeof(struct talitos_ptr));
+ sizeof(struct talitos_ptr), 0);
desc->ptr[1].j_extent = DESC_PTR_LNKTBL_JUMP;
/* assoc_nents - 1 entries for assoc, 1 for IV */
@@ -973,7 +1131,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
tbl_ptr += sg_count - 1;
tbl_ptr->j_extent = 0;
tbl_ptr++;
- to_talitos_ptr(tbl_ptr, edesc->iv_dma);
+ to_talitos_ptr(tbl_ptr, edesc->iv_dma, 0);
tbl_ptr->len = cpu_to_be16(ivsize);
tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN;
@@ -982,14 +1140,14 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
} else {
if (areq->assoclen)
to_talitos_ptr(&desc->ptr[1],
- sg_dma_address(areq->assoc));
+ sg_dma_address(areq->assoc), 0);
else
- to_talitos_ptr(&desc->ptr[1], edesc->iv_dma);
+ to_talitos_ptr(&desc->ptr[1], edesc->iv_dma, 0);
desc->ptr[1].j_extent = 0;
}
/* cipher iv */
- to_talitos_ptr(&desc->ptr[2], edesc->iv_dma);
+ to_talitos_ptr(&desc->ptr[2], edesc->iv_dma, 0);
desc->ptr[2].len = cpu_to_be16(ivsize);
desc->ptr[2].j_extent = 0;
/* Sync needed for the aead_givencrypt case */
@@ -997,7 +1155,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
/* cipher key */
map_single_talitos_ptr(dev, &desc->ptr[3], ctx->enckeylen,
- (char *)&ctx->key + ctx->authkeylen, 0,
+ (char *)&ctx->key + ctx->authkeylen,
DMA_TO_DEVICE);
/*
@@ -1015,7 +1173,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
edesc->src_chained);
if (sg_count == 1) {
- to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->src));
+ to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->src), 0);
} else {
sg_link_tbl_len = cryptlen;
@@ -1026,14 +1184,14 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
&edesc->link_tbl[0]);
if (sg_count > 1) {
desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP;
- to_talitos_ptr(&desc->ptr[4], edesc->dma_link_tbl);
+ to_talitos_ptr(&desc->ptr[4], edesc->dma_link_tbl, 0);
dma_sync_single_for_device(dev, edesc->dma_link_tbl,
edesc->dma_len,
DMA_BIDIRECTIONAL);
} else {
/* Only one segment now, so no link tbl needed */
to_talitos_ptr(&desc->ptr[4],
- sg_dma_address(areq->src));
+ sg_dma_address(areq->src), 0);
}
}
@@ -1047,13 +1205,13 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
DMA_FROM_DEVICE, edesc->dst_chained);
if (sg_count == 1) {
- to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst));
+ to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst), 0);
} else {
int tbl_off = edesc->src_nents + 1;
struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off];
to_talitos_ptr(&desc->ptr[5], edesc->dma_link_tbl +
- tbl_off * sizeof(struct talitos_ptr));
+ tbl_off * sizeof(struct talitos_ptr), 0);
sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen,
tbl_ptr);
@@ -1068,14 +1226,14 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
to_talitos_ptr(tbl_ptr, edesc->dma_link_tbl +
(tbl_off + edesc->dst_nents + 1 +
edesc->assoc_nents) *
- sizeof(struct talitos_ptr));
+ sizeof(struct talitos_ptr), 0);
desc->ptr[5].j_extent |= DESC_PTR_LNKTBL_JUMP;
dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl,
edesc->dma_len, DMA_BIDIRECTIONAL);
}
/* iv out */
- map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, 0,
+ map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv,
DMA_FROM_DEVICE);
ret = talitos_submit(dev, ctx->ch, desc, callback, areq);
@@ -1095,7 +1253,7 @@ static int sg_count(struct scatterlist *sg_list, int nbytes, bool *chained)
int sg_nents = 0;
*chained = false;
- while (nbytes > 0) {
+ while (nbytes > 0 && sg) {
sg_nents++;
nbytes -= sg->length;
if (!sg_is_last(sg) && (sg + 1)->length == 0)
@@ -1128,8 +1286,11 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
dma_addr_t iv_dma = 0;
gfp_t flags = cryptoflags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
GFP_ATOMIC;
+ struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
+ int max_len = is_sec1 ? TALITOS1_MAX_DATA_LEN : TALITOS2_MAX_DATA_LEN;
- if (cryptlen + authsize > TALITOS_MAX_DATA_LEN) {
+ if (cryptlen + authsize > max_len) {
dev_err(dev, "length exceeds h/w max limit\n");
return ERR_PTR(-EINVAL);
}
@@ -1173,8 +1334,12 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
*/
alloc_len = sizeof(struct talitos_edesc);
if (assoc_nents || src_nents || dst_nents) {
- dma_len = (src_nents + dst_nents + 2 + assoc_nents) *
- sizeof(struct talitos_ptr) + authsize;
+ if (is_sec1)
+ dma_len = (src_nents ? cryptlen : 0) +
+ (dst_nents ? cryptlen : 0);
+ else
+ dma_len = (src_nents + dst_nents + 2 + assoc_nents) *
+ sizeof(struct talitos_ptr) + authsize;
alloc_len += dma_len;
} else {
dma_len = 0;
@@ -1327,16 +1492,43 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *cipher,
return 0;
}
+static void unmap_sg_talitos_ptr(struct device *dev, struct scatterlist *src,
+ struct scatterlist *dst, unsigned int len,
+ struct talitos_edesc *edesc)
+{
+ struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
+
+ if (is_sec1) {
+ if (!edesc->src_nents) {
+ dma_unmap_sg(dev, src, 1,
+ dst != src ? DMA_TO_DEVICE
+ : DMA_BIDIRECTIONAL);
+ }
+ if (dst && edesc->dst_nents) {
+ dma_sync_single_for_device(dev,
+ edesc->dma_link_tbl + len,
+ len, DMA_FROM_DEVICE);
+ sg_copy_from_buffer(dst, edesc->dst_nents ? : 1,
+ edesc->buf + len, len);
+ } else if (dst && dst != src) {
+ dma_unmap_sg(dev, dst, 1, DMA_FROM_DEVICE);
+ }
+ } else {
+ talitos_sg_unmap(dev, edesc, src, dst);
+ }
+}
+
static void common_nonsnoop_unmap(struct device *dev,
struct talitos_edesc *edesc,
struct ablkcipher_request *areq)
{
unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE);
+
+ unmap_sg_talitos_ptr(dev, areq->src, areq->dst, areq->nbytes, edesc);
unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2], DMA_TO_DEVICE);
unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1], DMA_TO_DEVICE);
- talitos_sg_unmap(dev, edesc, areq->src, areq->dst);
-
if (edesc->dma_len)
dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
DMA_BIDIRECTIONAL);
@@ -1358,6 +1550,102 @@ static void ablkcipher_done(struct device *dev,
areq->base.complete(&areq->base, err);
}
+int map_sg_in_talitos_ptr(struct device *dev, struct scatterlist *src,
+ unsigned int len, struct talitos_edesc *edesc,
+ enum dma_data_direction dir, struct talitos_ptr *ptr)
+{
+ int sg_count;
+ struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
+
+ to_talitos_ptr_len(ptr, len, is_sec1);
+
+ if (is_sec1) {
+ sg_count = edesc->src_nents ? : 1;
+
+ if (sg_count == 1) {
+ dma_map_sg(dev, src, 1, dir);
+ to_talitos_ptr(ptr, sg_dma_address(src), is_sec1);
+ } else {
+ sg_copy_to_buffer(src, sg_count, edesc->buf, len);
+ to_talitos_ptr(ptr, edesc->dma_link_tbl, is_sec1);
+ dma_sync_single_for_device(dev, edesc->dma_link_tbl,
+ len, DMA_TO_DEVICE);
+ }
+ } else {
+ to_talitos_ptr_extent_clear(ptr, is_sec1);
+
+ sg_count = talitos_map_sg(dev, src, edesc->src_nents ? : 1, dir,
+ edesc->src_chained);
+
+ if (sg_count == 1) {
+ to_talitos_ptr(ptr, sg_dma_address(src), is_sec1);
+ } else {
+ sg_count = sg_to_link_tbl(src, sg_count, len,
+ &edesc->link_tbl[0]);
+ if (sg_count > 1) {
+ to_talitos_ptr(ptr, edesc->dma_link_tbl, 0);
+ ptr->j_extent |= DESC_PTR_LNKTBL_JUMP;
+ dma_sync_single_for_device(dev,
+ edesc->dma_link_tbl,
+ edesc->dma_len,
+ DMA_BIDIRECTIONAL);
+ } else {
+ /* Only one segment now, so no link tbl needed*/
+ to_talitos_ptr(ptr, sg_dma_address(src),
+ is_sec1);
+ }
+ }
+ }
+ return sg_count;
+}
+
+void map_sg_out_talitos_ptr(struct device *dev, struct scatterlist *dst,
+ unsigned int len, struct talitos_edesc *edesc,
+ enum dma_data_direction dir,
+ struct talitos_ptr *ptr, int sg_count)
+{
+ struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
+
+ if (dir != DMA_NONE)
+ sg_count = talitos_map_sg(dev, dst, edesc->dst_nents ? : 1,
+ dir, edesc->dst_chained);
+
+ to_talitos_ptr_len(ptr, len, is_sec1);
+
+ if (is_sec1) {
+ if (sg_count == 1) {
+ if (dir != DMA_NONE)
+ dma_map_sg(dev, dst, 1, dir);
+ to_talitos_ptr(ptr, sg_dma_address(dst), is_sec1);
+ } else {
+ to_talitos_ptr(ptr, edesc->dma_link_tbl + len, is_sec1);
+ dma_sync_single_for_device(dev,
+ edesc->dma_link_tbl + len,
+ len, DMA_FROM_DEVICE);
+ }
+ } else {
+ to_talitos_ptr_extent_clear(ptr, is_sec1);
+
+ if (sg_count == 1) {
+ to_talitos_ptr(ptr, sg_dma_address(dst), is_sec1);
+ } else {
+ struct talitos_ptr *link_tbl_ptr =
+ &edesc->link_tbl[edesc->src_nents + 1];
+
+ to_talitos_ptr(ptr, edesc->dma_link_tbl +
+ (edesc->src_nents + 1) *
+ sizeof(struct talitos_ptr), 0);
+ ptr->j_extent |= DESC_PTR_LNKTBL_JUMP;
+ sg_to_link_tbl(dst, sg_count, len, link_tbl_ptr);
+ dma_sync_single_for_device(dev, edesc->dma_link_tbl,
+ edesc->dma_len,
+ DMA_BIDIRECTIONAL);
+ }
+ }
+}
+
static int common_nonsnoop(struct talitos_edesc *edesc,
struct ablkcipher_request *areq,
void (*callback) (struct device *dev,
@@ -1371,83 +1659,41 @@ static int common_nonsnoop(struct talitos_edesc *edesc,
unsigned int cryptlen = areq->nbytes;
unsigned int ivsize = crypto_ablkcipher_ivsize(cipher);
int sg_count, ret;
+ struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
/* first DWORD empty */
- desc->ptr[0].len = 0;
- to_talitos_ptr(&desc->ptr[0], 0);
- desc->ptr[0].j_extent = 0;
+ desc->ptr[0] = zero_entry;
/* cipher iv */
- to_talitos_ptr(&desc->ptr[1], edesc->iv_dma);
- desc->ptr[1].len = cpu_to_be16(ivsize);
- desc->ptr[1].j_extent = 0;
+ to_talitos_ptr(&desc->ptr[1], edesc->iv_dma, is_sec1);
+ to_talitos_ptr_len(&desc->ptr[1], ivsize, is_sec1);
+ to_talitos_ptr_extent_clear(&desc->ptr[1], is_sec1);
/* cipher key */
map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen,
- (char *)&ctx->key, 0, DMA_TO_DEVICE);
+ (char *)&ctx->key, DMA_TO_DEVICE);
/*
* cipher in
*/
- desc->ptr[3].len = cpu_to_be16(cryptlen);
- desc->ptr[3].j_extent = 0;
-
- sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ? : 1,
- (areq->src == areq->dst) ? DMA_BIDIRECTIONAL
- : DMA_TO_DEVICE,
- edesc->src_chained);
-
- if (sg_count == 1) {
- to_talitos_ptr(&desc->ptr[3], sg_dma_address(areq->src));
- } else {
- sg_count = sg_to_link_tbl(areq->src, sg_count, cryptlen,
- &edesc->link_tbl[0]);
- if (sg_count > 1) {
- to_talitos_ptr(&desc->ptr[3], edesc->dma_link_tbl);
- desc->ptr[3].j_extent |= DESC_PTR_LNKTBL_JUMP;
- dma_sync_single_for_device(dev, edesc->dma_link_tbl,
- edesc->dma_len,
- DMA_BIDIRECTIONAL);
- } else {
- /* Only one segment now, so no link tbl needed */
- to_talitos_ptr(&desc->ptr[3],
- sg_dma_address(areq->src));
- }
- }
+ sg_count = map_sg_in_talitos_ptr(dev, areq->src, cryptlen, edesc,
+ (areq->src == areq->dst) ?
+ DMA_BIDIRECTIONAL : DMA_TO_DEVICE,
+ &desc->ptr[3]);
/* cipher out */
- desc->ptr[4].len = cpu_to_be16(cryptlen);
- desc->ptr[4].j_extent = 0;
-
- if (areq->src != areq->dst)
- sg_count = talitos_map_sg(dev, areq->dst,
- edesc->dst_nents ? : 1,
- DMA_FROM_DEVICE, edesc->dst_chained);
-
- if (sg_count == 1) {
- to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->dst));
- } else {
- struct talitos_ptr *link_tbl_ptr =
- &edesc->link_tbl[edesc->src_nents + 1];
-
- to_talitos_ptr(&desc->ptr[4], edesc->dma_link_tbl +
- (edesc->src_nents + 1) *
- sizeof(struct talitos_ptr));
- desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP;
- sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen,
- link_tbl_ptr);
- dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl,
- edesc->dma_len, DMA_BIDIRECTIONAL);
- }
+ map_sg_out_talitos_ptr(dev, areq->dst, cryptlen, edesc,
+ (areq->src == areq->dst) ? DMA_NONE
+ : DMA_FROM_DEVICE,
+ &desc->ptr[4], sg_count);
/* iv out */
- map_single_talitos_ptr(dev, &desc->ptr[5], ivsize, ctx->iv, 0,
+ map_single_talitos_ptr(dev, &desc->ptr[5], ivsize, ctx->iv,
DMA_FROM_DEVICE);
/* last DWORD empty */
- desc->ptr[6].len = 0;
- to_talitos_ptr(&desc->ptr[6], 0);
- desc->ptr[6].j_extent = 0;
+ desc->ptr[6] = zero_entry;
ret = talitos_submit(dev, ctx->ch, desc, callback, areq);
if (ret != -EINPROGRESS) {
@@ -1507,20 +1753,22 @@ static void common_nonsnoop_hash_unmap(struct device *dev,
struct ahash_request *areq)
{
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+ struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE);
+ unmap_sg_talitos_ptr(dev, req_ctx->psrc, NULL, 0, edesc);
+
/* When using hashctx-in, must unmap it. */
- if (edesc->desc.ptr[1].len)
+ if (from_talitos_ptr_len(&edesc->desc.ptr[1], is_sec1))
unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1],
DMA_TO_DEVICE);
- if (edesc->desc.ptr[2].len)
+ if (from_talitos_ptr_len(&edesc->desc.ptr[2], is_sec1))
unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2],
DMA_TO_DEVICE);
- talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL);
-
if (edesc->dma_len)
dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
DMA_BIDIRECTIONAL);
@@ -1548,6 +1796,27 @@ static void ahash_done(struct device *dev,
areq->base.complete(&areq->base, err);
}
+/*
+ * SEC1 doesn't like hashing of 0 sized message, so we do the padding
+ * ourself and submit a padded block
+ */
+void talitos_handle_buggy_hash(struct talitos_ctx *ctx,
+ struct talitos_edesc *edesc,
+ struct talitos_ptr *ptr)
+{
+ static u8 padded_hash[64] = {
+ 0x80, 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,
+ };
+
+ pr_err_once("Bug in SEC1, padding ourself\n");
+ edesc->desc.hdr &= ~DESC_HDR_MODE0_MDEU_PAD;
+ map_single_talitos_ptr(ctx->dev, ptr, sizeof(padded_hash),
+ (char *)padded_hash, DMA_TO_DEVICE);
+}
+
static int common_nonsnoop_hash(struct talitos_edesc *edesc,
struct ahash_request *areq, unsigned int length,
void (*callback) (struct device *dev,
@@ -1559,7 +1828,9 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
struct device *dev = ctx->dev;
struct talitos_desc *desc = &edesc->desc;
- int sg_count, ret;
+ int ret;
+ struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
/* first DWORD empty */
desc->ptr[0] = zero_entry;
@@ -1568,7 +1839,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
if (!req_ctx->first || req_ctx->swinit) {
map_single_talitos_ptr(dev, &desc->ptr[1],
req_ctx->hw_context_size,
- (char *)req_ctx->hw_context, 0,
+ (char *)req_ctx->hw_context,
DMA_TO_DEVICE);
req_ctx->swinit = 0;
} else {
@@ -1580,38 +1851,15 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
/* HMAC key */
if (ctx->keylen)
map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen,
- (char *)&ctx->key, 0, DMA_TO_DEVICE);
+ (char *)&ctx->key, DMA_TO_DEVICE);
else
desc->ptr[2] = zero_entry;
/*
* data in
*/
- desc->ptr[3].len = cpu_to_be16(length);
- desc->ptr[3].j_extent = 0;
-
- sg_count = talitos_map_sg(dev, req_ctx->psrc,
- edesc->src_nents ? : 1,
- DMA_TO_DEVICE, edesc->src_chained);
-
- if (sg_count == 1) {
- to_talitos_ptr(&desc->ptr[3], sg_dma_address(req_ctx->psrc));
- } else {
- sg_count = sg_to_link_tbl(req_ctx->psrc, sg_count, length,
- &edesc->link_tbl[0]);
- if (sg_count > 1) {
- desc->ptr[3].j_extent |= DESC_PTR_LNKTBL_JUMP;
- to_talitos_ptr(&desc->ptr[3], edesc->dma_link_tbl);
- dma_sync_single_for_device(ctx->dev,
- edesc->dma_link_tbl,
- edesc->dma_len,
- DMA_BIDIRECTIONAL);
- } else {
- /* Only one segment now, so no link tbl needed */
- to_talitos_ptr(&desc->ptr[3],
- sg_dma_address(req_ctx->psrc));
- }
- }
+ map_sg_in_talitos_ptr(dev, req_ctx->psrc, length, edesc,
+ DMA_TO_DEVICE, &desc->ptr[3]);
/* fifth DWORD empty */
desc->ptr[4] = zero_entry;
@@ -1620,15 +1868,18 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
if (req_ctx->last)
map_single_talitos_ptr(dev, &desc->ptr[5],
crypto_ahash_digestsize(tfm),
- areq->result, 0, DMA_FROM_DEVICE);
+ areq->result, DMA_FROM_DEVICE);
else
map_single_talitos_ptr(dev, &desc->ptr[5],
req_ctx->hw_context_size,
- req_ctx->hw_context, 0, DMA_FROM_DEVICE);
+ req_ctx->hw_context, DMA_FROM_DEVICE);
/* last DWORD empty */
desc->ptr[6] = zero_entry;
+ if (is_sec1 && from_talitos_ptr_len(&desc->ptr[3], true) == 0)
+ talitos_handle_buggy_hash(ctx, edesc, &desc->ptr[3]);
+
ret = talitos_submit(dev, ctx->ch, desc, callback, areq);
if (ret != -EINPROGRESS) {
common_nonsnoop_hash_unmap(dev, edesc, areq);
@@ -2561,6 +2812,7 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
break;
default:
dev_err(dev, "unknown algorithm type %d\n", t_alg->algt.type);
+ kfree(t_alg);
return ERR_PTR(-EINVAL);
}
@@ -2581,29 +2833,35 @@ static int talitos_probe_irq(struct platform_device *ofdev)
struct device_node *np = ofdev->dev.of_node;
struct talitos_private *priv = dev_get_drvdata(dev);
int err;
+ bool is_sec1 = has_ftr_sec1(priv);
priv->irq[0] = irq_of_parse_and_map(np, 0);
if (!priv->irq[0]) {
dev_err(dev, "failed to map irq\n");
return -EINVAL;
}
+ if (is_sec1) {
+ err = request_irq(priv->irq[0], talitos1_interrupt_4ch, 0,
+ dev_driver_string(dev), dev);
+ goto primary_out;
+ }
priv->irq[1] = irq_of_parse_and_map(np, 1);
/* get the primary irq line */
if (!priv->irq[1]) {
- err = request_irq(priv->irq[0], talitos_interrupt_4ch, 0,
+ err = request_irq(priv->irq[0], talitos2_interrupt_4ch, 0,
dev_driver_string(dev), dev);
goto primary_out;
}
- err = request_irq(priv->irq[0], talitos_interrupt_ch0_2, 0,
+ err = request_irq(priv->irq[0], talitos2_interrupt_ch0_2, 0,
dev_driver_string(dev), dev);
if (err)
goto primary_out;
/* get the secondary irq line */
- err = request_irq(priv->irq[1], talitos_interrupt_ch1_3, 0,
+ err = request_irq(priv->irq[1], talitos2_interrupt_ch1_3, 0,
dev_driver_string(dev), dev);
if (err) {
dev_err(dev, "failed to request secondary irq\n");
@@ -2630,6 +2888,7 @@ static int talitos_probe(struct platform_device *ofdev)
struct talitos_private *priv;
const unsigned int *prop;
int i, err;
+ int stride;
priv = kzalloc(sizeof(struct talitos_private), GFP_KERNEL);
if (!priv)
@@ -2643,20 +2902,6 @@ static int talitos_probe(struct platform_device *ofdev)
spin_lock_init(&priv->reg_lock);
- err = talitos_probe_irq(ofdev);
- if (err)
- goto err_out;
-
- if (!priv->irq[1]) {
- tasklet_init(&priv->done_task[0], talitos_done_4ch,
- (unsigned long)dev);
- } else {
- tasklet_init(&priv->done_task[0], talitos_done_ch0_2,
- (unsigned long)dev);
- tasklet_init(&priv->done_task[1], talitos_done_ch1_3,
- (unsigned long)dev);
- }
-
priv->reg = of_iomap(np, 0);
if (!priv->reg) {
dev_err(dev, "failed to of_iomap\n");
@@ -2696,6 +2941,53 @@ static int talitos_probe(struct platform_device *ofdev)
TALITOS_FTR_SHA224_HWINIT |
TALITOS_FTR_HMAC_OK;
+ if (of_device_is_compatible(np, "fsl,sec1.0"))
+ priv->features |= TALITOS_FTR_SEC1;
+
+ if (of_device_is_compatible(np, "fsl,sec1.2")) {
+ priv->reg_deu = priv->reg + TALITOS12_DEU;
+ priv->reg_aesu = priv->reg + TALITOS12_AESU;
+ priv->reg_mdeu = priv->reg + TALITOS12_MDEU;
+ stride = TALITOS1_CH_STRIDE;
+ } else if (of_device_is_compatible(np, "fsl,sec1.0")) {
+ priv->reg_deu = priv->reg + TALITOS10_DEU;
+ priv->reg_aesu = priv->reg + TALITOS10_AESU;
+ priv->reg_mdeu = priv->reg + TALITOS10_MDEU;
+ priv->reg_afeu = priv->reg + TALITOS10_AFEU;
+ priv->reg_rngu = priv->reg + TALITOS10_RNGU;
+ priv->reg_pkeu = priv->reg + TALITOS10_PKEU;
+ stride = TALITOS1_CH_STRIDE;
+ } else {
+ priv->reg_deu = priv->reg + TALITOS2_DEU;
+ priv->reg_aesu = priv->reg + TALITOS2_AESU;
+ priv->reg_mdeu = priv->reg + TALITOS2_MDEU;
+ priv->reg_afeu = priv->reg + TALITOS2_AFEU;
+ priv->reg_rngu = priv->reg + TALITOS2_RNGU;
+ priv->reg_pkeu = priv->reg + TALITOS2_PKEU;
+ priv->reg_keu = priv->reg + TALITOS2_KEU;
+ priv->reg_crcu = priv->reg + TALITOS2_CRCU;
+ stride = TALITOS2_CH_STRIDE;
+ }
+
+ err = talitos_probe_irq(ofdev);
+ if (err)
+ goto err_out;
+
+ if (of_device_is_compatible(np, "fsl,sec1.0")) {
+ tasklet_init(&priv->done_task[0], talitos1_done_4ch,
+ (unsigned long)dev);
+ } else {
+ if (!priv->irq[1]) {
+ tasklet_init(&priv->done_task[0], talitos2_done_4ch,
+ (unsigned long)dev);
+ } else {
+ tasklet_init(&priv->done_task[0], talitos2_done_ch0_2,
+ (unsigned long)dev);
+ tasklet_init(&priv->done_task[1], talitos2_done_ch1_3,
+ (unsigned long)dev);
+ }
+ }
+
priv->chan = kzalloc(sizeof(struct talitos_channel) *
priv->num_channels, GFP_KERNEL);
if (!priv->chan) {
@@ -2707,7 +2999,7 @@ static int talitos_probe(struct platform_device *ofdev)
priv->fifo_len = roundup_pow_of_two(priv->chfifo_len);
for (i = 0; i < priv->num_channels; i++) {
- priv->chan[i].reg = priv->reg + TALITOS_CH_STRIDE * (i + 1);
+ priv->chan[i].reg = priv->reg + stride * (i + 1);
if (!priv->irq[1] || !(i & 1))
priv->chan[i].reg += TALITOS_CH_BASE_OFFSET;
@@ -2794,9 +3086,16 @@ err_out:
}
static const struct of_device_id talitos_match[] = {
+#ifdef CONFIG_CRYPTO_DEV_TALITOS1
+ {
+ .compatible = "fsl,sec1.0",
+ },
+#endif
+#ifdef CONFIG_CRYPTO_DEV_TALITOS2
{
.compatible = "fsl,sec2.0",
},
+#endif
{},
};
MODULE_DEVICE_TABLE(of, talitos_match);
diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h
index 61a14054aa39..314daf55e7f7 100644
--- a/drivers/crypto/talitos.h
+++ b/drivers/crypto/talitos.h
@@ -29,7 +29,8 @@
*/
#define TALITOS_TIMEOUT 100000
-#define TALITOS_MAX_DATA_LEN 65535
+#define TALITOS1_MAX_DATA_LEN 32768
+#define TALITOS2_MAX_DATA_LEN 65535
#define DESC_TYPE(desc_hdr) ((be32_to_cpu(desc_hdr) >> 3) & 0x1f)
#define PRIMARY_EU(desc_hdr) ((be32_to_cpu(desc_hdr) >> 28) & 0xf)
@@ -37,9 +38,17 @@
/* descriptor pointer entry */
struct talitos_ptr {
- __be16 len; /* length */
- u8 j_extent; /* jump to sg link table and/or extent */
- u8 eptr; /* extended address */
+ union {
+ struct { /* SEC2 format */
+ __be16 len; /* length */
+ u8 j_extent; /* jump to sg link table and/or extent*/
+ u8 eptr; /* extended address */
+ };
+ struct { /* SEC1 format */
+ __be16 res;
+ __be16 len1; /* length */
+ };
+ };
__be32 ptr; /* address */
};
@@ -53,10 +62,16 @@ static const struct talitos_ptr zero_entry = {
/* descriptor */
struct talitos_desc {
__be32 hdr; /* header high bits */
- __be32 hdr_lo; /* header low bits */
+ union {
+ __be32 hdr_lo; /* header low bits */
+ __be32 hdr1; /* header for SEC1 */
+ };
struct talitos_ptr ptr[7]; /* ptr/len pair array */
+ __be32 next_desc; /* next descriptor (SEC1) */
};
+#define TALITOS_DESC_SIZE (sizeof(struct talitos_desc) - sizeof(__be32))
+
/**
* talitos_request - descriptor submission request
* @desc: descriptor pointer (kernel virtual)
@@ -97,6 +112,14 @@ struct talitos_private {
struct device *dev;
struct platform_device *ofdev;
void __iomem *reg;
+ void __iomem *reg_deu;
+ void __iomem *reg_aesu;
+ void __iomem *reg_mdeu;
+ void __iomem *reg_afeu;
+ void __iomem *reg_rngu;
+ void __iomem *reg_pkeu;
+ void __iomem *reg_keu;
+ void __iomem *reg_crcu;
int irq[2];
/* SEC global registers lock */
@@ -144,49 +167,80 @@ extern int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
#define TALITOS_FTR_HW_AUTH_CHECK 0x00000002
#define TALITOS_FTR_SHA224_HWINIT 0x00000004
#define TALITOS_FTR_HMAC_OK 0x00000008
+#define TALITOS_FTR_SEC1 0x00000010
+
+/*
+ * If both CONFIG_CRYPTO_DEV_TALITOS1 and CONFIG_CRYPTO_DEV_TALITOS2 are
+ * defined, we check the features which are set according to the device tree.
+ * Otherwise, we answer true or false directly
+ */
+static inline bool has_ftr_sec1(struct talitos_private *priv)
+{
+#if defined(CONFIG_CRYPTO_DEV_TALITOS1) && defined(CONFIG_CRYPTO_DEV_TALITOS2)
+ return priv->features & TALITOS_FTR_SEC1 ? true : false;
+#elif defined(CONFIG_CRYPTO_DEV_TALITOS1)
+ return true;
+#else
+ return false;
+#endif
+}
/*
* TALITOS_xxx_LO addresses point to the low data bits (32-63) of the register
*/
+#define ISR1_FORMAT(x) (((x) << 28) | ((x) << 16))
+#define ISR2_FORMAT(x) (((x) << 4) | (x))
+
/* global register offset addresses */
#define TALITOS_MCR 0x1030 /* master control register */
#define TALITOS_MCR_RCA0 (1 << 15) /* remap channel 0 */
#define TALITOS_MCR_RCA1 (1 << 14) /* remap channel 1 */
#define TALITOS_MCR_RCA2 (1 << 13) /* remap channel 2 */
#define TALITOS_MCR_RCA3 (1 << 12) /* remap channel 3 */
-#define TALITOS_MCR_SWR 0x1 /* s/w reset */
+#define TALITOS1_MCR_SWR 0x1000000 /* s/w reset */
+#define TALITOS2_MCR_SWR 0x1 /* s/w reset */
#define TALITOS_MCR_LO 0x1034
#define TALITOS_IMR 0x1008 /* interrupt mask register */
-#define TALITOS_IMR_INIT 0x100ff /* enable channel IRQs */
-#define TALITOS_IMR_DONE 0x00055 /* done IRQs */
+/* enable channel IRQs */
+#define TALITOS1_IMR_INIT ISR1_FORMAT(0xf)
+#define TALITOS1_IMR_DONE ISR1_FORMAT(0x5) /* done IRQs */
+/* enable channel IRQs */
+#define TALITOS2_IMR_INIT (ISR2_FORMAT(0xf) | 0x10000)
+#define TALITOS2_IMR_DONE ISR1_FORMAT(0x5) /* done IRQs */
#define TALITOS_IMR_LO 0x100C
-#define TALITOS_IMR_LO_INIT 0x20000 /* allow RNGU error IRQs */
+#define TALITOS1_IMR_LO_INIT 0x2000000 /* allow RNGU error IRQs */
+#define TALITOS2_IMR_LO_INIT 0x20000 /* allow RNGU error IRQs */
#define TALITOS_ISR 0x1010 /* interrupt status register */
-#define TALITOS_ISR_4CHERR 0xaa /* 4 channel errors mask */
-#define TALITOS_ISR_4CHDONE 0x55 /* 4 channel done mask */
-#define TALITOS_ISR_CH_0_2_ERR 0x22 /* channels 0, 2 errors mask */
-#define TALITOS_ISR_CH_0_2_DONE 0x11 /* channels 0, 2 done mask */
-#define TALITOS_ISR_CH_1_3_ERR 0x88 /* channels 1, 3 errors mask */
-#define TALITOS_ISR_CH_1_3_DONE 0x44 /* channels 1, 3 done mask */
+#define TALITOS1_ISR_4CHERR ISR1_FORMAT(0xa) /* 4 ch errors mask */
+#define TALITOS1_ISR_4CHDONE ISR1_FORMAT(0x5) /* 4 ch done mask */
+#define TALITOS1_ISR_TEA_ERR 0x00000040
+#define TALITOS2_ISR_4CHERR ISR2_FORMAT(0xa) /* 4 ch errors mask */
+#define TALITOS2_ISR_4CHDONE ISR2_FORMAT(0x5) /* 4 ch done mask */
+#define TALITOS2_ISR_CH_0_2_ERR ISR2_FORMAT(0x2) /* ch 0, 2 err mask */
+#define TALITOS2_ISR_CH_0_2_DONE ISR2_FORMAT(0x1) /* ch 0, 2 done mask */
+#define TALITOS2_ISR_CH_1_3_ERR ISR2_FORMAT(0x8) /* ch 1, 3 err mask */
+#define TALITOS2_ISR_CH_1_3_DONE ISR2_FORMAT(0x4) /* ch 1, 3 done mask */
#define TALITOS_ISR_LO 0x1014
#define TALITOS_ICR 0x1018 /* interrupt clear register */
#define TALITOS_ICR_LO 0x101C
/* channel register address stride */
#define TALITOS_CH_BASE_OFFSET 0x1000 /* default channel map base */
-#define TALITOS_CH_STRIDE 0x100
+#define TALITOS1_CH_STRIDE 0x1000
+#define TALITOS2_CH_STRIDE 0x100
/* channel configuration register */
#define TALITOS_CCCR 0x8
-#define TALITOS_CCCR_CONT 0x2 /* channel continue */
-#define TALITOS_CCCR_RESET 0x1 /* channel reset */
+#define TALITOS2_CCCR_CONT 0x2 /* channel continue on SEC2 */
+#define TALITOS2_CCCR_RESET 0x1 /* channel reset on SEC2 */
#define TALITOS_CCCR_LO 0xc
#define TALITOS_CCCR_LO_IWSE 0x80 /* chan. ICCR writeback enab. */
#define TALITOS_CCCR_LO_EAE 0x20 /* extended address enable */
#define TALITOS_CCCR_LO_CDWE 0x10 /* chan. done writeback enab. */
#define TALITOS_CCCR_LO_NT 0x4 /* notification type */
#define TALITOS_CCCR_LO_CDIE 0x2 /* channel done IRQ enable */
+#define TALITOS1_CCCR_LO_RESET 0x1 /* channel reset on SEC1 */
/* CCPSR: channel pointer status register */
#define TALITOS_CCPSR 0x10
@@ -224,37 +278,48 @@ extern int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
#define TALITOS_SCATTER 0xe0
#define TALITOS_SCATTER_LO 0xe4
+/* execution unit registers base */
+#define TALITOS2_DEU 0x2000
+#define TALITOS2_AESU 0x4000
+#define TALITOS2_MDEU 0x6000
+#define TALITOS2_AFEU 0x8000
+#define TALITOS2_RNGU 0xa000
+#define TALITOS2_PKEU 0xc000
+#define TALITOS2_KEU 0xe000
+#define TALITOS2_CRCU 0xf000
+
+#define TALITOS12_AESU 0x4000
+#define TALITOS12_DEU 0x5000
+#define TALITOS12_MDEU 0x6000
+
+#define TALITOS10_AFEU 0x8000
+#define TALITOS10_DEU 0xa000
+#define TALITOS10_MDEU 0xc000
+#define TALITOS10_RNGU 0xe000
+#define TALITOS10_PKEU 0x10000
+#define TALITOS10_AESU 0x12000
+
/* execution unit interrupt status registers */
-#define TALITOS_DEUISR 0x2030 /* DES unit */
-#define TALITOS_DEUISR_LO 0x2034
-#define TALITOS_AESUISR 0x4030 /* AES unit */
-#define TALITOS_AESUISR_LO 0x4034
-#define TALITOS_MDEUISR 0x6030 /* message digest unit */
-#define TALITOS_MDEUISR_LO 0x6034
-#define TALITOS_MDEUICR 0x6038 /* interrupt control */
-#define TALITOS_MDEUICR_LO 0x603c
+#define TALITOS_EUDSR 0x10 /* data size */
+#define TALITOS_EUDSR_LO 0x14
+#define TALITOS_EURCR 0x18 /* reset control*/
+#define TALITOS_EURCR_LO 0x1c
+#define TALITOS_EUSR 0x28 /* rng status */
+#define TALITOS_EUSR_LO 0x2c
+#define TALITOS_EUISR 0x30
+#define TALITOS_EUISR_LO 0x34
+#define TALITOS_EUICR 0x38 /* int. control */
+#define TALITOS_EUICR_LO 0x3c
+#define TALITOS_EU_FIFO 0x800 /* output FIFO */
+#define TALITOS_EU_FIFO_LO 0x804 /* output FIFO */
+/* DES unit */
+#define TALITOS1_DEUICR_KPE 0x00200000 /* Key Parity Error */
+/* message digest unit */
#define TALITOS_MDEUICR_LO_ICE 0x4000 /* integrity check IRQ enable */
-#define TALITOS_AFEUISR 0x8030 /* arc4 unit */
-#define TALITOS_AFEUISR_LO 0x8034
-#define TALITOS_RNGUISR 0xa030 /* random number unit */
-#define TALITOS_RNGUISR_LO 0xa034
-#define TALITOS_RNGUSR 0xa028 /* rng status */
-#define TALITOS_RNGUSR_LO 0xa02c
+/* random number unit */
#define TALITOS_RNGUSR_LO_RD 0x1 /* reset done */
#define TALITOS_RNGUSR_LO_OFL 0xff0000/* output FIFO length */
-#define TALITOS_RNGUDSR 0xa010 /* data size */
-#define TALITOS_RNGUDSR_LO 0xa014
-#define TALITOS_RNGU_FIFO 0xa800 /* output FIFO */
-#define TALITOS_RNGU_FIFO_LO 0xa804 /* output FIFO */
-#define TALITOS_RNGURCR 0xa018 /* reset control */
-#define TALITOS_RNGURCR_LO 0xa01c
#define TALITOS_RNGURCR_LO_SR 0x1 /* software reset */
-#define TALITOS_PKEUISR 0xc030 /* public key unit */
-#define TALITOS_PKEUISR_LO 0xc034
-#define TALITOS_KEUISR 0xe030 /* kasumi unit */
-#define TALITOS_KEUISR_LO 0xe034
-#define TALITOS_CRCUISR 0xf030 /* cyclic redundancy check unit*/
-#define TALITOS_CRCUISR_LO 0xf034
#define TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256 0x28
#define TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512 0x48
diff --git a/drivers/crypto/ux500/Kconfig b/drivers/crypto/ux500/Kconfig
index b35e5c4b025a..30796441b0a6 100644
--- a/drivers/crypto/ux500/Kconfig
+++ b/drivers/crypto/ux500/Kconfig
@@ -7,6 +7,8 @@
config CRYPTO_DEV_UX500_CRYP
tristate "UX500 crypto driver for CRYP block"
depends on CRYPTO_DEV_UX500
+ select CRYPTO_ALGAPI
+ select CRYPTO_BLKCIPHER
select CRYPTO_DES
help
This selects the crypto driver for the UX500_CRYP hardware. It supports
@@ -16,7 +18,6 @@ config CRYPTO_DEV_UX500_HASH
tristate "UX500 crypto driver for HASH block"
depends on CRYPTO_DEV_UX500
select CRYPTO_HASH
- select CRYPTO_HMAC
help
This selects the hash driver for the UX500_HASH hardware.
Depends on UX500/STM DMA if running in DMA mode.
@@ -24,7 +25,6 @@ config CRYPTO_DEV_UX500_HASH
config CRYPTO_DEV_UX500_DEBUG
bool "Activate ux500 platform debug-mode for crypto and hash block"
depends on CRYPTO_DEV_UX500_CRYP || CRYPTO_DEV_UX500_HASH
- default n
help
Say Y if you want to add debug prints to ux500_hash and
ux500_cryp devices.
diff --git a/drivers/crypto/vmx/Kconfig b/drivers/crypto/vmx/Kconfig
index 771babf16aa0..89d8208d9851 100644
--- a/drivers/crypto/vmx/Kconfig
+++ b/drivers/crypto/vmx/Kconfig
@@ -1,6 +1,6 @@
config CRYPTO_DEV_VMX_ENCRYPT
tristate "Encryption acceleration support on P8 CPU"
- depends on PPC64 && CRYPTO_DEV_VMX
+ depends on CRYPTO_DEV_VMX
default y
help
Support for VMX cryptographic acceleration instructions on Power8 CPU.
diff --git a/drivers/crypto/vmx/Makefile b/drivers/crypto/vmx/Makefile
index c699c6e6c82e..d28ab96a2475 100644
--- a/drivers/crypto/vmx/Makefile
+++ b/drivers/crypto/vmx/Makefile
@@ -4,7 +4,7 @@ vmx-crypto-objs := vmx.o aesp8-ppc.o ghashp8-ppc.o aes.o aes_cbc.o aes_ctr.o gha
ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y)
TARGET := linux-ppc64le
else
-TARGET := linux-pcc64
+TARGET := linux-ppc64
endif
quiet_cmd_perl = PERL $@
diff --git a/drivers/crypto/vmx/aes.c b/drivers/crypto/vmx/aes.c
index ab300ea19434..e79e567e43aa 100644
--- a/drivers/crypto/vmx/aes.c
+++ b/drivers/crypto/vmx/aes.c
@@ -30,110 +30,118 @@
#include "aesp8-ppc.h"
struct p8_aes_ctx {
- struct crypto_cipher *fallback;
- struct aes_key enc_key;
- struct aes_key dec_key;
+ struct crypto_cipher *fallback;
+ struct aes_key enc_key;
+ struct aes_key dec_key;
};
static int p8_aes_init(struct crypto_tfm *tfm)
{
- const char *alg;
- struct crypto_cipher *fallback;
- struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm);
-
- if (!(alg = crypto_tfm_alg_name(tfm))) {
- printk(KERN_ERR "Failed to get algorithm name.\n");
- return -ENOENT;
- }
-
- fallback = crypto_alloc_cipher(alg, 0 ,CRYPTO_ALG_NEED_FALLBACK);
- if (IS_ERR(fallback)) {
- printk(KERN_ERR "Failed to allocate transformation for '%s': %ld\n",
- alg, PTR_ERR(fallback));
- return PTR_ERR(fallback);
- }
- printk(KERN_INFO "Using '%s' as fallback implementation.\n",
- crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback));
-
- crypto_cipher_set_flags(fallback,
- crypto_cipher_get_flags((struct crypto_cipher *) tfm));
- ctx->fallback = fallback;
-
- return 0;
+ const char *alg;
+ struct crypto_cipher *fallback;
+ struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (!(alg = crypto_tfm_alg_name(tfm))) {
+ printk(KERN_ERR "Failed to get algorithm name.\n");
+ return -ENOENT;
+ }
+
+ fallback = crypto_alloc_cipher(alg, 0, CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(fallback)) {
+ printk(KERN_ERR
+ "Failed to allocate transformation for '%s': %ld\n",
+ alg, PTR_ERR(fallback));
+ return PTR_ERR(fallback);
+ }
+ printk(KERN_INFO "Using '%s' as fallback implementation.\n",
+ crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback));
+
+ crypto_cipher_set_flags(fallback,
+ crypto_cipher_get_flags((struct
+ crypto_cipher *)
+ tfm));
+ ctx->fallback = fallback;
+
+ return 0;
}
static void p8_aes_exit(struct crypto_tfm *tfm)
{
- struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm);
- if (ctx->fallback) {
- crypto_free_cipher(ctx->fallback);
- ctx->fallback = NULL;
- }
+ if (ctx->fallback) {
+ crypto_free_cipher(ctx->fallback);
+ ctx->fallback = NULL;
+ }
}
static int p8_aes_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
+ unsigned int keylen)
{
- int ret;
- struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm);
-
- pagefault_disable();
- enable_kernel_altivec();
- ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
- ret += aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key);
- pagefault_enable();
-
- ret += crypto_cipher_setkey(ctx->fallback, key, keylen);
- return ret;
+ int ret;
+ struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_altivec();
+ ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
+ ret += aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key);
+ pagefault_enable();
+ preempt_enable();
+
+ ret += crypto_cipher_setkey(ctx->fallback, key, keylen);
+ return ret;
}
static void p8_aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
- struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm);
-
- if (in_interrupt()) {
- crypto_cipher_encrypt_one(ctx->fallback, dst, src);
- } else {
- pagefault_disable();
- enable_kernel_altivec();
- aes_p8_encrypt(src, dst, &ctx->enc_key);
- pagefault_enable();
- }
+ struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (in_interrupt()) {
+ crypto_cipher_encrypt_one(ctx->fallback, dst, src);
+ } else {
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_altivec();
+ aes_p8_encrypt(src, dst, &ctx->enc_key);
+ pagefault_enable();
+ preempt_enable();
+ }
}
static void p8_aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
- struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm);
-
- if (in_interrupt()) {
- crypto_cipher_decrypt_one(ctx->fallback, dst, src);
- } else {
- pagefault_disable();
- enable_kernel_altivec();
- aes_p8_decrypt(src, dst, &ctx->dec_key);
- pagefault_enable();
- }
+ struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (in_interrupt()) {
+ crypto_cipher_decrypt_one(ctx->fallback, dst, src);
+ } else {
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_altivec();
+ aes_p8_decrypt(src, dst, &ctx->dec_key);
+ pagefault_enable();
+ preempt_enable();
+ }
}
struct crypto_alg p8_aes_alg = {
- .cra_name = "aes",
- .cra_driver_name = "p8_aes",
- .cra_module = THIS_MODULE,
- .cra_priority = 1000,
- .cra_type = NULL,
- .cra_flags = CRYPTO_ALG_TYPE_CIPHER | CRYPTO_ALG_NEED_FALLBACK,
- .cra_alignmask = 0,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct p8_aes_ctx),
- .cra_init = p8_aes_init,
- .cra_exit = p8_aes_exit,
- .cra_cipher = {
- .cia_min_keysize = AES_MIN_KEY_SIZE,
- .cia_max_keysize = AES_MAX_KEY_SIZE,
- .cia_setkey = p8_aes_setkey,
- .cia_encrypt = p8_aes_encrypt,
- .cia_decrypt = p8_aes_decrypt,
- },
+ .cra_name = "aes",
+ .cra_driver_name = "p8_aes",
+ .cra_module = THIS_MODULE,
+ .cra_priority = 1000,
+ .cra_type = NULL,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER | CRYPTO_ALG_NEED_FALLBACK,
+ .cra_alignmask = 0,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct p8_aes_ctx),
+ .cra_init = p8_aes_init,
+ .cra_exit = p8_aes_exit,
+ .cra_cipher = {
+ .cia_min_keysize = AES_MIN_KEY_SIZE,
+ .cia_max_keysize = AES_MAX_KEY_SIZE,
+ .cia_setkey = p8_aes_setkey,
+ .cia_encrypt = p8_aes_encrypt,
+ .cia_decrypt = p8_aes_decrypt,
+ },
};
-
diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c
index 1a559b7dddb5..7299995c78ec 100644
--- a/drivers/crypto/vmx/aes_cbc.c
+++ b/drivers/crypto/vmx/aes_cbc.c
@@ -31,154 +31,168 @@
#include "aesp8-ppc.h"
struct p8_aes_cbc_ctx {
- struct crypto_blkcipher *fallback;
- struct aes_key enc_key;
- struct aes_key dec_key;
+ struct crypto_blkcipher *fallback;
+ struct aes_key enc_key;
+ struct aes_key dec_key;
};
static int p8_aes_cbc_init(struct crypto_tfm *tfm)
{
- const char *alg;
- struct crypto_blkcipher *fallback;
- struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
-
- if (!(alg = crypto_tfm_alg_name(tfm))) {
- printk(KERN_ERR "Failed to get algorithm name.\n");
- return -ENOENT;
- }
-
- fallback = crypto_alloc_blkcipher(alg, 0 ,CRYPTO_ALG_NEED_FALLBACK);
- if (IS_ERR(fallback)) {
- printk(KERN_ERR "Failed to allocate transformation for '%s': %ld\n",
- alg, PTR_ERR(fallback));
- return PTR_ERR(fallback);
- }
- printk(KERN_INFO "Using '%s' as fallback implementation.\n",
- crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback));
-
- crypto_blkcipher_set_flags(fallback,
- crypto_blkcipher_get_flags((struct crypto_blkcipher *) tfm));
- ctx->fallback = fallback;
-
- return 0;
+ const char *alg;
+ struct crypto_blkcipher *fallback;
+ struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (!(alg = crypto_tfm_alg_name(tfm))) {
+ printk(KERN_ERR "Failed to get algorithm name.\n");
+ return -ENOENT;
+ }
+
+ fallback =
+ crypto_alloc_blkcipher(alg, 0, CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(fallback)) {
+ printk(KERN_ERR
+ "Failed to allocate transformation for '%s': %ld\n",
+ alg, PTR_ERR(fallback));
+ return PTR_ERR(fallback);
+ }
+ printk(KERN_INFO "Using '%s' as fallback implementation.\n",
+ crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback));
+
+ crypto_blkcipher_set_flags(
+ fallback,
+ crypto_blkcipher_get_flags((struct crypto_blkcipher *)tfm));
+ ctx->fallback = fallback;
+
+ return 0;
}
static void p8_aes_cbc_exit(struct crypto_tfm *tfm)
{
- struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
- if (ctx->fallback) {
- crypto_free_blkcipher(ctx->fallback);
- ctx->fallback = NULL;
- }
+ if (ctx->fallback) {
+ crypto_free_blkcipher(ctx->fallback);
+ ctx->fallback = NULL;
+ }
}
static int p8_aes_cbc_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
+ unsigned int keylen)
{
- int ret;
- struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
-
- pagefault_disable();
- enable_kernel_altivec();
- ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
- ret += aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key);
- pagefault_enable();
-
- ret += crypto_blkcipher_setkey(ctx->fallback, key, keylen);
- return ret;
+ int ret;
+ struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_altivec();
+ ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
+ ret += aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key);
+ pagefault_enable();
+ preempt_enable();
+
+ ret += crypto_blkcipher_setkey(ctx->fallback, key, keylen);
+ return ret;
}
static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst, struct scatterlist *src,
- unsigned int nbytes)
+ struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
{
- int ret;
- struct blkcipher_walk walk;
- struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(
- crypto_blkcipher_tfm(desc->tfm));
- struct blkcipher_desc fallback_desc = {
- .tfm = ctx->fallback,
- .info = desc->info,
- .flags = desc->flags
- };
-
- if (in_interrupt()) {
- ret = crypto_blkcipher_encrypt(&fallback_desc, dst, src, nbytes);
- } else {
- pagefault_disable();
- enable_kernel_altivec();
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- ret = blkcipher_walk_virt(desc, &walk);
- while ((nbytes = walk.nbytes)) {
- aes_p8_cbc_encrypt(walk.src.virt.addr, walk.dst.virt.addr,
- nbytes & AES_BLOCK_MASK, &ctx->enc_key, walk.iv, 1);
+ int ret;
+ struct blkcipher_walk walk;
+ struct p8_aes_cbc_ctx *ctx =
+ crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
+ struct blkcipher_desc fallback_desc = {
+ .tfm = ctx->fallback,
+ .info = desc->info,
+ .flags = desc->flags
+ };
+
+ if (in_interrupt()) {
+ ret = crypto_blkcipher_encrypt(&fallback_desc, dst, src,
+ nbytes);
+ } else {
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_altivec();
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ ret = blkcipher_walk_virt(desc, &walk);
+ while ((nbytes = walk.nbytes)) {
+ aes_p8_cbc_encrypt(walk.src.virt.addr,
+ walk.dst.virt.addr,
+ nbytes & AES_BLOCK_MASK,
+ &ctx->enc_key, walk.iv, 1);
nbytes &= AES_BLOCK_SIZE - 1;
ret = blkcipher_walk_done(desc, &walk, nbytes);
- }
+ }
- pagefault_enable();
- }
+ pagefault_enable();
+ preempt_enable();
+ }
- return ret;
+ return ret;
}
static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst, struct scatterlist *src,
- unsigned int nbytes)
+ struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
{
- int ret;
- struct blkcipher_walk walk;
- struct p8_aes_cbc_ctx *ctx = crypto_tfm_ctx(
- crypto_blkcipher_tfm(desc->tfm));
- struct blkcipher_desc fallback_desc = {
- .tfm = ctx->fallback,
- .info = desc->info,
- .flags = desc->flags
- };
-
- if (in_interrupt()) {
- ret = crypto_blkcipher_decrypt(&fallback_desc, dst, src, nbytes);
- } else {
- pagefault_disable();
- enable_kernel_altivec();
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- ret = blkcipher_walk_virt(desc, &walk);
- while ((nbytes = walk.nbytes)) {
- aes_p8_cbc_encrypt(walk.src.virt.addr, walk.dst.virt.addr,
- nbytes & AES_BLOCK_MASK, &ctx->dec_key, walk.iv, 0);
+ int ret;
+ struct blkcipher_walk walk;
+ struct p8_aes_cbc_ctx *ctx =
+ crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
+ struct blkcipher_desc fallback_desc = {
+ .tfm = ctx->fallback,
+ .info = desc->info,
+ .flags = desc->flags
+ };
+
+ if (in_interrupt()) {
+ ret = crypto_blkcipher_decrypt(&fallback_desc, dst, src,
+ nbytes);
+ } else {
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_altivec();
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ ret = blkcipher_walk_virt(desc, &walk);
+ while ((nbytes = walk.nbytes)) {
+ aes_p8_cbc_encrypt(walk.src.virt.addr,
+ walk.dst.virt.addr,
+ nbytes & AES_BLOCK_MASK,
+ &ctx->dec_key, walk.iv, 0);
nbytes &= AES_BLOCK_SIZE - 1;
ret = blkcipher_walk_done(desc, &walk, nbytes);
}
- pagefault_enable();
- }
+ pagefault_enable();
+ preempt_enable();
+ }
- return ret;
+ return ret;
}
struct crypto_alg p8_aes_cbc_alg = {
- .cra_name = "cbc(aes)",
- .cra_driver_name = "p8_aes_cbc",
- .cra_module = THIS_MODULE,
- .cra_priority = 1000,
- .cra_type = &crypto_blkcipher_type,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
- .cra_alignmask = 0,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct p8_aes_cbc_ctx),
- .cra_init = p8_aes_cbc_init,
- .cra_exit = p8_aes_cbc_exit,
- .cra_blkcipher = {
- .ivsize = 0,
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .setkey = p8_aes_cbc_setkey,
- .encrypt = p8_aes_cbc_encrypt,
- .decrypt = p8_aes_cbc_decrypt,
- },
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "p8_aes_cbc",
+ .cra_module = THIS_MODULE,
+ .cra_priority = 1000,
+ .cra_type = &crypto_blkcipher_type,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
+ .cra_alignmask = 0,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct p8_aes_cbc_ctx),
+ .cra_init = p8_aes_cbc_init,
+ .cra_exit = p8_aes_cbc_exit,
+ .cra_blkcipher = {
+ .ivsize = 0,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = p8_aes_cbc_setkey,
+ .encrypt = p8_aes_cbc_encrypt,
+ .decrypt = p8_aes_cbc_decrypt,
+ },
};
-
diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c
index 96dbee4bf4a6..7adae42a7b79 100644
--- a/drivers/crypto/vmx/aes_ctr.c
+++ b/drivers/crypto/vmx/aes_ctr.c
@@ -30,138 +30,147 @@
#include "aesp8-ppc.h"
struct p8_aes_ctr_ctx {
- struct crypto_blkcipher *fallback;
- struct aes_key enc_key;
+ struct crypto_blkcipher *fallback;
+ struct aes_key enc_key;
};
static int p8_aes_ctr_init(struct crypto_tfm *tfm)
{
- const char *alg;
- struct crypto_blkcipher *fallback;
- struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
-
- if (!(alg = crypto_tfm_alg_name(tfm))) {
- printk(KERN_ERR "Failed to get algorithm name.\n");
- return -ENOENT;
- }
-
- fallback = crypto_alloc_blkcipher(alg, 0 ,CRYPTO_ALG_NEED_FALLBACK);
- if (IS_ERR(fallback)) {
- printk(KERN_ERR "Failed to allocate transformation for '%s': %ld\n",
- alg, PTR_ERR(fallback));
- return PTR_ERR(fallback);
- }
- printk(KERN_INFO "Using '%s' as fallback implementation.\n",
- crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback));
-
- crypto_blkcipher_set_flags(fallback,
- crypto_blkcipher_get_flags((struct crypto_blkcipher *) tfm));
- ctx->fallback = fallback;
-
- return 0;
+ const char *alg;
+ struct crypto_blkcipher *fallback;
+ struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (!(alg = crypto_tfm_alg_name(tfm))) {
+ printk(KERN_ERR "Failed to get algorithm name.\n");
+ return -ENOENT;
+ }
+
+ fallback =
+ crypto_alloc_blkcipher(alg, 0, CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(fallback)) {
+ printk(KERN_ERR
+ "Failed to allocate transformation for '%s': %ld\n",
+ alg, PTR_ERR(fallback));
+ return PTR_ERR(fallback);
+ }
+ printk(KERN_INFO "Using '%s' as fallback implementation.\n",
+ crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback));
+
+ crypto_blkcipher_set_flags(
+ fallback,
+ crypto_blkcipher_get_flags((struct crypto_blkcipher *)tfm));
+ ctx->fallback = fallback;
+
+ return 0;
}
static void p8_aes_ctr_exit(struct crypto_tfm *tfm)
{
- struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
- if (ctx->fallback) {
- crypto_free_blkcipher(ctx->fallback);
- ctx->fallback = NULL;
- }
+ if (ctx->fallback) {
+ crypto_free_blkcipher(ctx->fallback);
+ ctx->fallback = NULL;
+ }
}
static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
+ unsigned int keylen)
{
- int ret;
- struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
+ int ret;
+ struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
- pagefault_disable();
- enable_kernel_altivec();
- ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
- pagefault_enable();
+ pagefault_disable();
+ enable_kernel_altivec();
+ ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
+ pagefault_enable();
- ret += crypto_blkcipher_setkey(ctx->fallback, key, keylen);
- return ret;
+ ret += crypto_blkcipher_setkey(ctx->fallback, key, keylen);
+ return ret;
}
static void p8_aes_ctr_final(struct p8_aes_ctr_ctx *ctx,
- struct blkcipher_walk *walk)
+ struct blkcipher_walk *walk)
{
- u8 *ctrblk = walk->iv;
- u8 keystream[AES_BLOCK_SIZE];
- u8 *src = walk->src.virt.addr;
- u8 *dst = walk->dst.virt.addr;
- unsigned int nbytes = walk->nbytes;
-
- pagefault_disable();
- enable_kernel_altivec();
- aes_p8_encrypt(ctrblk, keystream, &ctx->enc_key);
- pagefault_enable();
-
- crypto_xor(keystream, src, nbytes);
- memcpy(dst, keystream, nbytes);
- crypto_inc(ctrblk, AES_BLOCK_SIZE);
+ u8 *ctrblk = walk->iv;
+ u8 keystream[AES_BLOCK_SIZE];
+ u8 *src = walk->src.virt.addr;
+ u8 *dst = walk->dst.virt.addr;
+ unsigned int nbytes = walk->nbytes;
+
+ pagefault_disable();
+ enable_kernel_altivec();
+ aes_p8_encrypt(ctrblk, keystream, &ctx->enc_key);
+ pagefault_enable();
+
+ crypto_xor(keystream, src, nbytes);
+ memcpy(dst, keystream, nbytes);
+ crypto_inc(ctrblk, AES_BLOCK_SIZE);
}
static int p8_aes_ctr_crypt(struct blkcipher_desc *desc,
- struct scatterlist *dst, struct scatterlist *src,
- unsigned int nbytes)
+ struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
{
- int ret;
- struct blkcipher_walk walk;
- struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(
- crypto_blkcipher_tfm(desc->tfm));
- struct blkcipher_desc fallback_desc = {
- .tfm = ctx->fallback,
- .info = desc->info,
- .flags = desc->flags
- };
-
- if (in_interrupt()) {
- ret = crypto_blkcipher_encrypt(&fallback_desc, dst, src, nbytes);
- } else {
- blkcipher_walk_init(&walk, dst, src, nbytes);
- ret = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
- while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
- pagefault_disable();
- enable_kernel_altivec();
- aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr, walk.dst.virt.addr,
- (nbytes & AES_BLOCK_MASK)/AES_BLOCK_SIZE, &ctx->enc_key, walk.iv);
- pagefault_enable();
-
- crypto_inc(walk.iv, AES_BLOCK_SIZE);
- nbytes &= AES_BLOCK_SIZE - 1;
- ret = blkcipher_walk_done(desc, &walk, nbytes);
- }
- if (walk.nbytes) {
- p8_aes_ctr_final(ctx, &walk);
- ret = blkcipher_walk_done(desc, &walk, 0);
- }
- }
-
- return ret;
+ int ret;
+ struct blkcipher_walk walk;
+ struct p8_aes_ctr_ctx *ctx =
+ crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
+ struct blkcipher_desc fallback_desc = {
+ .tfm = ctx->fallback,
+ .info = desc->info,
+ .flags = desc->flags
+ };
+
+ if (in_interrupt()) {
+ ret = crypto_blkcipher_encrypt(&fallback_desc, dst, src,
+ nbytes);
+ } else {
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ ret = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
+ while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
+ pagefault_disable();
+ enable_kernel_altivec();
+ aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr,
+ walk.dst.virt.addr,
+ (nbytes &
+ AES_BLOCK_MASK) /
+ AES_BLOCK_SIZE,
+ &ctx->enc_key,
+ walk.iv);
+ pagefault_enable();
+
+ crypto_inc(walk.iv, AES_BLOCK_SIZE);
+ nbytes &= AES_BLOCK_SIZE - 1;
+ ret = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+ if (walk.nbytes) {
+ p8_aes_ctr_final(ctx, &walk);
+ ret = blkcipher_walk_done(desc, &walk, 0);
+ }
+ }
+
+ return ret;
}
struct crypto_alg p8_aes_ctr_alg = {
- .cra_name = "ctr(aes)",
- .cra_driver_name = "p8_aes_ctr",
- .cra_module = THIS_MODULE,
- .cra_priority = 1000,
- .cra_type = &crypto_blkcipher_type,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
- .cra_alignmask = 0,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct p8_aes_ctr_ctx),
- .cra_init = p8_aes_ctr_init,
- .cra_exit = p8_aes_ctr_exit,
- .cra_blkcipher = {
- .ivsize = 0,
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .setkey = p8_aes_ctr_setkey,
- .encrypt = p8_aes_ctr_crypt,
- .decrypt = p8_aes_ctr_crypt,
- },
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "p8_aes_ctr",
+ .cra_module = THIS_MODULE,
+ .cra_priority = 1000,
+ .cra_type = &crypto_blkcipher_type,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
+ .cra_alignmask = 0,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct p8_aes_ctr_ctx),
+ .cra_init = p8_aes_ctr_init,
+ .cra_exit = p8_aes_ctr_exit,
+ .cra_blkcipher = {
+ .ivsize = 0,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = p8_aes_ctr_setkey,
+ .encrypt = p8_aes_ctr_crypt,
+ .decrypt = p8_aes_ctr_crypt,
+ },
};
diff --git a/drivers/crypto/vmx/aesp8-ppc.h b/drivers/crypto/vmx/aesp8-ppc.h
index e963945a83e1..4cd34ee54a94 100644
--- a/drivers/crypto/vmx/aesp8-ppc.h
+++ b/drivers/crypto/vmx/aesp8-ppc.h
@@ -4,17 +4,18 @@
#define AES_BLOCK_MASK (~(AES_BLOCK_SIZE-1))
struct aes_key {
- u8 key[AES_MAX_KEYLENGTH];
- int rounds;
+ u8 key[AES_MAX_KEYLENGTH];
+ int rounds;
};
int aes_p8_set_encrypt_key(const u8 *userKey, const int bits,
- struct aes_key *key);
+ struct aes_key *key);
int aes_p8_set_decrypt_key(const u8 *userKey, const int bits,
- struct aes_key *key);
+ struct aes_key *key);
void aes_p8_encrypt(const u8 *in, u8 *out, const struct aes_key *key);
-void aes_p8_decrypt(const u8 *in, u8 *out,const struct aes_key *key);
+void aes_p8_decrypt(const u8 *in, u8 *out, const struct aes_key *key);
void aes_p8_cbc_encrypt(const u8 *in, u8 *out, size_t len,
- const struct aes_key *key, u8 *iv, const int enc);
+ const struct aes_key *key, u8 *iv, const int enc);
void aes_p8_ctr32_encrypt_blocks(const u8 *in, u8 *out,
- size_t len, const struct aes_key *key, const u8 *iv);
+ size_t len, const struct aes_key *key,
+ const u8 *iv);
diff --git a/drivers/crypto/vmx/ghash.c b/drivers/crypto/vmx/ghash.c
index d0ffe277af5c..b5e29002b666 100644
--- a/drivers/crypto/vmx/ghash.c
+++ b/drivers/crypto/vmx/ghash.c
@@ -39,176 +39,188 @@
void gcm_init_p8(u128 htable[16], const u64 Xi[2]);
void gcm_gmult_p8(u64 Xi[2], const u128 htable[16]);
void gcm_ghash_p8(u64 Xi[2], const u128 htable[16],
- const u8 *in,size_t len);
+ const u8 *in, size_t len);
struct p8_ghash_ctx {
- u128 htable[16];
- struct crypto_shash *fallback;
+ u128 htable[16];
+ struct crypto_shash *fallback;
};
struct p8_ghash_desc_ctx {
- u64 shash[2];
- u8 buffer[GHASH_DIGEST_SIZE];
- int bytes;
- struct shash_desc fallback_desc;
+ u64 shash[2];
+ u8 buffer[GHASH_DIGEST_SIZE];
+ int bytes;
+ struct shash_desc fallback_desc;
};
static int p8_ghash_init_tfm(struct crypto_tfm *tfm)
{
- const char *alg;
- struct crypto_shash *fallback;
- struct crypto_shash *shash_tfm = __crypto_shash_cast(tfm);
- struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm);
-
- if (!(alg = crypto_tfm_alg_name(tfm))) {
- printk(KERN_ERR "Failed to get algorithm name.\n");
- return -ENOENT;
- }
-
- fallback = crypto_alloc_shash(alg, 0 ,CRYPTO_ALG_NEED_FALLBACK);
- if (IS_ERR(fallback)) {
- printk(KERN_ERR "Failed to allocate transformation for '%s': %ld\n",
- alg, PTR_ERR(fallback));
- return PTR_ERR(fallback);
- }
- printk(KERN_INFO "Using '%s' as fallback implementation.\n",
- crypto_tfm_alg_driver_name(crypto_shash_tfm(fallback)));
-
- crypto_shash_set_flags(fallback,
- crypto_shash_get_flags((struct crypto_shash *) tfm));
- ctx->fallback = fallback;
-
- shash_tfm->descsize = sizeof(struct p8_ghash_desc_ctx)
- + crypto_shash_descsize(fallback);
-
- return 0;
+ const char *alg;
+ struct crypto_shash *fallback;
+ struct crypto_shash *shash_tfm = __crypto_shash_cast(tfm);
+ struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (!(alg = crypto_tfm_alg_name(tfm))) {
+ printk(KERN_ERR "Failed to get algorithm name.\n");
+ return -ENOENT;
+ }
+
+ fallback = crypto_alloc_shash(alg, 0, CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(fallback)) {
+ printk(KERN_ERR
+ "Failed to allocate transformation for '%s': %ld\n",
+ alg, PTR_ERR(fallback));
+ return PTR_ERR(fallback);
+ }
+ printk(KERN_INFO "Using '%s' as fallback implementation.\n",
+ crypto_tfm_alg_driver_name(crypto_shash_tfm(fallback)));
+
+ crypto_shash_set_flags(fallback,
+ crypto_shash_get_flags((struct crypto_shash
+ *) tfm));
+ ctx->fallback = fallback;
+
+ shash_tfm->descsize = sizeof(struct p8_ghash_desc_ctx)
+ + crypto_shash_descsize(fallback);
+
+ return 0;
}
static void p8_ghash_exit_tfm(struct crypto_tfm *tfm)
{
- struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm);
- if (ctx->fallback) {
- crypto_free_shash(ctx->fallback);
- ctx->fallback = NULL;
- }
+ if (ctx->fallback) {
+ crypto_free_shash(ctx->fallback);
+ ctx->fallback = NULL;
+ }
}
static int p8_ghash_init(struct shash_desc *desc)
{
- struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm));
- struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
-
- dctx->bytes = 0;
- memset(dctx->shash, 0, GHASH_DIGEST_SIZE);
- dctx->fallback_desc.tfm = ctx->fallback;
- dctx->fallback_desc.flags = desc->flags;
- return crypto_shash_init(&dctx->fallback_desc);
+ struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm));
+ struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+
+ dctx->bytes = 0;
+ memset(dctx->shash, 0, GHASH_DIGEST_SIZE);
+ dctx->fallback_desc.tfm = ctx->fallback;
+ dctx->fallback_desc.flags = desc->flags;
+ return crypto_shash_init(&dctx->fallback_desc);
}
static int p8_ghash_setkey(struct crypto_shash *tfm, const u8 *key,
- unsigned int keylen)
+ unsigned int keylen)
{
- struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(tfm));
-
- if (keylen != GHASH_KEY_LEN)
- return -EINVAL;
-
- pagefault_disable();
- enable_kernel_altivec();
- enable_kernel_fp();
- gcm_init_p8(ctx->htable, (const u64 *) key);
- pagefault_enable();
- return crypto_shash_setkey(ctx->fallback, key, keylen);
+ struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(tfm));
+
+ if (keylen != GHASH_KEY_LEN)
+ return -EINVAL;
+
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_altivec();
+ enable_kernel_fp();
+ gcm_init_p8(ctx->htable, (const u64 *) key);
+ pagefault_enable();
+ preempt_enable();
+ return crypto_shash_setkey(ctx->fallback, key, keylen);
}
static int p8_ghash_update(struct shash_desc *desc,
- const u8 *src, unsigned int srclen)
+ const u8 *src, unsigned int srclen)
{
- unsigned int len;
- struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm));
- struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
-
- if (IN_INTERRUPT) {
- return crypto_shash_update(&dctx->fallback_desc, src, srclen);
- } else {
- if (dctx->bytes) {
- if (dctx->bytes + srclen < GHASH_DIGEST_SIZE) {
- memcpy(dctx->buffer + dctx->bytes, src, srclen);
- dctx->bytes += srclen;
- return 0;
- }
- memcpy(dctx->buffer + dctx->bytes, src,
- GHASH_DIGEST_SIZE - dctx->bytes);
- pagefault_disable();
- enable_kernel_altivec();
- enable_kernel_fp();
- gcm_ghash_p8(dctx->shash, ctx->htable, dctx->buffer,
- GHASH_DIGEST_SIZE);
- pagefault_enable();
- src += GHASH_DIGEST_SIZE - dctx->bytes;
- srclen -= GHASH_DIGEST_SIZE - dctx->bytes;
- dctx->bytes = 0;
- }
- len = srclen & ~(GHASH_DIGEST_SIZE - 1);
- if (len) {
- pagefault_disable();
- enable_kernel_altivec();
- enable_kernel_fp();
- gcm_ghash_p8(dctx->shash, ctx->htable, src, len);
- pagefault_enable();
- src += len;
- srclen -= len;
- }
- if (srclen) {
- memcpy(dctx->buffer, src, srclen);
- dctx->bytes = srclen;
- }
- return 0;
- }
+ unsigned int len;
+ struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm));
+ struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+
+ if (IN_INTERRUPT) {
+ return crypto_shash_update(&dctx->fallback_desc, src,
+ srclen);
+ } else {
+ if (dctx->bytes) {
+ if (dctx->bytes + srclen < GHASH_DIGEST_SIZE) {
+ memcpy(dctx->buffer + dctx->bytes, src,
+ srclen);
+ dctx->bytes += srclen;
+ return 0;
+ }
+ memcpy(dctx->buffer + dctx->bytes, src,
+ GHASH_DIGEST_SIZE - dctx->bytes);
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_altivec();
+ enable_kernel_fp();
+ gcm_ghash_p8(dctx->shash, ctx->htable,
+ dctx->buffer, GHASH_DIGEST_SIZE);
+ pagefault_enable();
+ preempt_enable();
+ src += GHASH_DIGEST_SIZE - dctx->bytes;
+ srclen -= GHASH_DIGEST_SIZE - dctx->bytes;
+ dctx->bytes = 0;
+ }
+ len = srclen & ~(GHASH_DIGEST_SIZE - 1);
+ if (len) {
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_altivec();
+ enable_kernel_fp();
+ gcm_ghash_p8(dctx->shash, ctx->htable, src, len);
+ pagefault_enable();
+ preempt_enable();
+ src += len;
+ srclen -= len;
+ }
+ if (srclen) {
+ memcpy(dctx->buffer, src, srclen);
+ dctx->bytes = srclen;
+ }
+ return 0;
+ }
}
static int p8_ghash_final(struct shash_desc *desc, u8 *out)
{
- int i;
- struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm));
- struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
-
- if (IN_INTERRUPT) {
- return crypto_shash_final(&dctx->fallback_desc, out);
- } else {
- if (dctx->bytes) {
- for (i = dctx->bytes; i < GHASH_DIGEST_SIZE; i++)
- dctx->buffer[i] = 0;
- pagefault_disable();
- enable_kernel_altivec();
- enable_kernel_fp();
- gcm_ghash_p8(dctx->shash, ctx->htable, dctx->buffer,
- GHASH_DIGEST_SIZE);
- pagefault_enable();
- dctx->bytes = 0;
- }
- memcpy(out, dctx->shash, GHASH_DIGEST_SIZE);
- return 0;
- }
+ int i;
+ struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(desc->tfm));
+ struct p8_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+
+ if (IN_INTERRUPT) {
+ return crypto_shash_final(&dctx->fallback_desc, out);
+ } else {
+ if (dctx->bytes) {
+ for (i = dctx->bytes; i < GHASH_DIGEST_SIZE; i++)
+ dctx->buffer[i] = 0;
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_altivec();
+ enable_kernel_fp();
+ gcm_ghash_p8(dctx->shash, ctx->htable,
+ dctx->buffer, GHASH_DIGEST_SIZE);
+ pagefault_enable();
+ preempt_enable();
+ dctx->bytes = 0;
+ }
+ memcpy(out, dctx->shash, GHASH_DIGEST_SIZE);
+ return 0;
+ }
}
struct shash_alg p8_ghash_alg = {
- .digestsize = GHASH_DIGEST_SIZE,
- .init = p8_ghash_init,
- .update = p8_ghash_update,
- .final = p8_ghash_final,
- .setkey = p8_ghash_setkey,
- .descsize = sizeof(struct p8_ghash_desc_ctx),
- .base = {
- .cra_name = "ghash",
- .cra_driver_name = "p8_ghash",
- .cra_priority = 1000,
- .cra_flags = CRYPTO_ALG_TYPE_SHASH | CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = GHASH_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct p8_ghash_ctx),
- .cra_module = THIS_MODULE,
- .cra_init = p8_ghash_init_tfm,
- .cra_exit = p8_ghash_exit_tfm,
- },
+ .digestsize = GHASH_DIGEST_SIZE,
+ .init = p8_ghash_init,
+ .update = p8_ghash_update,
+ .final = p8_ghash_final,
+ .setkey = p8_ghash_setkey,
+ .descsize = sizeof(struct p8_ghash_desc_ctx),
+ .base = {
+ .cra_name = "ghash",
+ .cra_driver_name = "p8_ghash",
+ .cra_priority = 1000,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH | CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = GHASH_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct p8_ghash_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_init = p8_ghash_init_tfm,
+ .cra_exit = p8_ghash_exit_tfm,
+ },
};
diff --git a/drivers/crypto/vmx/vmx.c b/drivers/crypto/vmx/vmx.c
index 44d8d5cfe40d..e163d5770438 100644
--- a/drivers/crypto/vmx/vmx.c
+++ b/drivers/crypto/vmx/vmx.c
@@ -32,57 +32,57 @@ extern struct crypto_alg p8_aes_alg;
extern struct crypto_alg p8_aes_cbc_alg;
extern struct crypto_alg p8_aes_ctr_alg;
static struct crypto_alg *algs[] = {
- &p8_aes_alg,
- &p8_aes_cbc_alg,
- &p8_aes_ctr_alg,
- NULL,
+ &p8_aes_alg,
+ &p8_aes_cbc_alg,
+ &p8_aes_ctr_alg,
+ NULL,
};
int __init p8_init(void)
{
- int ret = 0;
- struct crypto_alg **alg_it;
+ int ret = 0;
+ struct crypto_alg **alg_it;
- if (!(cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_VEC_CRYPTO))
- return -ENODEV;
+ if (!(cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_VEC_CRYPTO))
+ return -ENODEV;
- for (alg_it = algs; *alg_it; alg_it++) {
- ret = crypto_register_alg(*alg_it);
- printk(KERN_INFO "crypto_register_alg '%s' = %d\n",
- (*alg_it)->cra_name, ret);
- if (ret) {
- for (alg_it--; alg_it >= algs; alg_it--)
- crypto_unregister_alg(*alg_it);
- break;
- }
- }
- if (ret)
- return ret;
+ for (alg_it = algs; *alg_it; alg_it++) {
+ ret = crypto_register_alg(*alg_it);
+ printk(KERN_INFO "crypto_register_alg '%s' = %d\n",
+ (*alg_it)->cra_name, ret);
+ if (ret) {
+ for (alg_it--; alg_it >= algs; alg_it--)
+ crypto_unregister_alg(*alg_it);
+ break;
+ }
+ }
+ if (ret)
+ return ret;
- ret = crypto_register_shash(&p8_ghash_alg);
- if (ret) {
- for (alg_it = algs; *alg_it; alg_it++)
- crypto_unregister_alg(*alg_it);
- }
- return ret;
+ ret = crypto_register_shash(&p8_ghash_alg);
+ if (ret) {
+ for (alg_it = algs; *alg_it; alg_it++)
+ crypto_unregister_alg(*alg_it);
+ }
+ return ret;
}
void __exit p8_exit(void)
{
- struct crypto_alg **alg_it;
+ struct crypto_alg **alg_it;
- for (alg_it = algs; *alg_it; alg_it++) {
- printk(KERN_INFO "Removing '%s'\n", (*alg_it)->cra_name);
- crypto_unregister_alg(*alg_it);
- }
- crypto_unregister_shash(&p8_ghash_alg);
+ for (alg_it = algs; *alg_it; alg_it++) {
+ printk(KERN_INFO "Removing '%s'\n", (*alg_it)->cra_name);
+ crypto_unregister_alg(*alg_it);
+ }
+ crypto_unregister_shash(&p8_ghash_alg);
}
module_init(p8_init);
module_exit(p8_exit);
MODULE_AUTHOR("Marcelo Cerri<mhcerri@br.ibm.com>");
-MODULE_DESCRIPTION("IBM VMX cryptogaphic acceleration instructions support on Power 8");
+MODULE_DESCRIPTION("IBM VMX cryptographic acceleration instructions "
+ "support on Power 8");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0.0");
-
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index c5a9138a6a8d..155c1464948e 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -29,6 +29,7 @@
#include <linux/anon_inodes.h>
#include <linux/export.h>
#include <linux/debugfs.h>
+#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/poll.h>
#include <linux/reservation.h>
@@ -72,6 +73,7 @@ static int dma_buf_release(struct inode *inode, struct file *file)
if (dmabuf->resv == (struct reservation_object *)&dmabuf[1])
reservation_object_fini(dmabuf->resv);
+ module_put(dmabuf->owner);
kfree(dmabuf);
return 0;
}
@@ -285,6 +287,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
struct reservation_object *resv = exp_info->resv;
struct file *file;
size_t alloc_size = sizeof(struct dma_buf);
+
if (!exp_info->resv)
alloc_size += sizeof(struct reservation_object);
else
@@ -302,14 +305,20 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
return ERR_PTR(-EINVAL);
}
+ if (!try_module_get(exp_info->owner))
+ return ERR_PTR(-ENOENT);
+
dmabuf = kzalloc(alloc_size, GFP_KERNEL);
- if (dmabuf == NULL)
+ if (!dmabuf) {
+ module_put(exp_info->owner);
return ERR_PTR(-ENOMEM);
+ }
dmabuf->priv = exp_info->priv;
dmabuf->ops = exp_info->ops;
dmabuf->size = exp_info->size;
dmabuf->exp_name = exp_info->exp_name;
+ dmabuf->owner = exp_info->owner;
init_waitqueue_head(&dmabuf->poll);
dmabuf->cb_excl.poll = dmabuf->cb_shared.poll = &dmabuf->poll;
dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0;
@@ -545,7 +554,8 @@ int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
return -EINVAL;
if (dmabuf->ops->begin_cpu_access)
- ret = dmabuf->ops->begin_cpu_access(dmabuf, start, len, direction);
+ ret = dmabuf->ops->begin_cpu_access(dmabuf, start,
+ len, direction);
return ret;
}
@@ -649,7 +659,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kunmap);
* @dmabuf: [in] buffer that should back the vma
* @vma: [in] vma for the mmap
* @pgoff: [in] offset in pages where this mmap should start within the
- * dma-buf buffer.
+ * dma-buf buffer.
*
* This function adjusts the passed in vma so that it points at the file of the
* dma_buf operation. It also adjusts the starting pgoff and does bounds
@@ -826,6 +836,7 @@ static int dma_buf_describe(struct seq_file *s)
static int dma_buf_show(struct seq_file *s, void *unused)
{
void (*func)(struct seq_file *) = s->private;
+
func(s);
return 0;
}
@@ -847,7 +858,9 @@ static struct dentry *dma_buf_debugfs_dir;
static int dma_buf_init_debugfs(void)
{
int err = 0;
+
dma_buf_debugfs_dir = debugfs_create_dir("dma_buf", NULL);
+
if (IS_ERR(dma_buf_debugfs_dir)) {
err = PTR_ERR(dma_buf_debugfs_dir);
dma_buf_debugfs_dir = NULL;
diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c
index 39920d77f288..c0bd5722c997 100644
--- a/drivers/dma-buf/reservation.c
+++ b/drivers/dma-buf/reservation.c
@@ -337,7 +337,8 @@ retry:
rcu_read_lock();
if (wait_all) {
- struct reservation_object_list *fobj = rcu_dereference(obj->fence);
+ struct reservation_object_list *fobj =
+ rcu_dereference(obj->fence);
if (fobj)
shared_count = fobj->shared_count;
@@ -429,7 +430,8 @@ retry:
if (test_all) {
unsigned i;
- struct reservation_object_list *fobj = rcu_dereference(obj->fence);
+ struct reservation_object_list *fobj =
+ rcu_dereference(obj->fence);
if (fobj)
shared_count = fobj->shared_count;
@@ -462,7 +464,8 @@ retry:
goto unlock_retry;
if (fence_excl) {
- ret = reservation_object_test_signaled_single(fence_excl);
+ ret = reservation_object_test_signaled_single(
+ fence_excl);
if (ret < 0)
goto unlock_retry;
}
diff --git a/drivers/dma-buf/seqno-fence.c b/drivers/dma-buf/seqno-fence.c
index 7d12a39a4b57..71127f8f1626 100644
--- a/drivers/dma-buf/seqno-fence.c
+++ b/drivers/dma-buf/seqno-fence.c
@@ -24,24 +24,28 @@
static const char *seqno_fence_get_driver_name(struct fence *fence)
{
struct seqno_fence *seqno_fence = to_seqno_fence(fence);
+
return seqno_fence->ops->get_driver_name(fence);
}
static const char *seqno_fence_get_timeline_name(struct fence *fence)
{
struct seqno_fence *seqno_fence = to_seqno_fence(fence);
+
return seqno_fence->ops->get_timeline_name(fence);
}
static bool seqno_enable_signaling(struct fence *fence)
{
struct seqno_fence *seqno_fence = to_seqno_fence(fence);
+
return seqno_fence->ops->enable_signaling(fence);
}
static bool seqno_signaled(struct fence *fence)
{
struct seqno_fence *seqno_fence = to_seqno_fence(fence);
+
return seqno_fence->ops->signaled && seqno_fence->ops->signaled(fence);
}
@@ -56,9 +60,11 @@ static void seqno_release(struct fence *fence)
fence_free(&f->base);
}
-static signed long seqno_wait(struct fence *fence, bool intr, signed long timeout)
+static signed long seqno_wait(struct fence *fence, bool intr,
+ signed long timeout)
{
struct seqno_fence *f = to_seqno_fence(fence);
+
return f->ops->wait(fence, intr, timeout);
}
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index bf09db7ca9ee..88853af69489 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -300,8 +300,7 @@ static int edma_dma_pause(struct dma_chan *chan)
{
struct edma_chan *echan = to_edma_chan(chan);
- /* Pause/Resume only allowed with cyclic mode */
- if (!echan->edesc || !echan->edesc->cyclic)
+ if (!echan->edesc)
return -EINVAL;
edma_pause(echan->ch_num);
@@ -312,10 +311,6 @@ static int edma_dma_resume(struct dma_chan *chan)
{
struct edma_chan *echan = to_edma_chan(chan);
- /* Pause/Resume only allowed with cyclic mode */
- if (!echan->edesc->cyclic)
- return -EINVAL;
-
edma_resume(echan->ch_num);
return 0;
}
diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c
index 6de2e677be04..74d9db05a5ad 100644
--- a/drivers/dma/mic_x100_dma.c
+++ b/drivers/dma/mic_x100_dma.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/io.h>
#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
#include "mic_x100_dma.h"
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index a18d16cc4795..e0302c784ba4 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -465,6 +465,7 @@ static dma_cookie_t rcar_dmac_tx_submit(struct dma_async_tx_descriptor *tx)
static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
{
struct rcar_dmac_desc_page *page;
+ unsigned long flags;
LIST_HEAD(list);
unsigned int i;
@@ -482,10 +483,10 @@ static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
list_add_tail(&desc->node, &list);
}
- spin_lock_irq(&chan->lock);
+ spin_lock_irqsave(&chan->lock, flags);
list_splice_tail(&list, &chan->desc.free);
list_add_tail(&page->node, &chan->desc.pages);
- spin_unlock_irq(&chan->lock);
+ spin_unlock_irqrestore(&chan->lock, flags);
return 0;
}
@@ -516,6 +517,7 @@ static void rcar_dmac_desc_put(struct rcar_dmac_chan *chan,
static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
{
struct rcar_dmac_desc *desc, *_desc;
+ unsigned long flags;
LIST_HEAD(list);
/*
@@ -524,9 +526,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
* list_for_each_entry_safe, isn't safe if we release the channel lock
* around the rcar_dmac_desc_put() call.
*/
- spin_lock_irq(&chan->lock);
+ spin_lock_irqsave(&chan->lock, flags);
list_splice_init(&chan->desc.wait, &list);
- spin_unlock_irq(&chan->lock);
+ spin_unlock_irqrestore(&chan->lock, flags);
list_for_each_entry_safe(desc, _desc, &list, node) {
if (async_tx_test_ack(&desc->async_tx)) {
@@ -539,9 +541,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
return;
/* Put the remaining descriptors back in the wait list. */
- spin_lock_irq(&chan->lock);
+ spin_lock_irqsave(&chan->lock, flags);
list_splice(&list, &chan->desc.wait);
- spin_unlock_irq(&chan->lock);
+ spin_unlock_irqrestore(&chan->lock, flags);
}
/*
@@ -556,12 +558,13 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
{
struct rcar_dmac_desc *desc;
+ unsigned long flags;
int ret;
/* Recycle acked descriptors before attempting allocation. */
rcar_dmac_desc_recycle_acked(chan);
- spin_lock_irq(&chan->lock);
+ spin_lock_irqsave(&chan->lock, flags);
while (list_empty(&chan->desc.free)) {
/*
@@ -570,17 +573,17 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
* allocated descriptors. If the allocation fails return an
* error.
*/
- spin_unlock_irq(&chan->lock);
+ spin_unlock_irqrestore(&chan->lock, flags);
ret = rcar_dmac_desc_alloc(chan, GFP_NOWAIT);
if (ret < 0)
return NULL;
- spin_lock_irq(&chan->lock);
+ spin_lock_irqsave(&chan->lock, flags);
}
desc = list_first_entry(&chan->desc.free, struct rcar_dmac_desc, node);
list_del(&desc->node);
- spin_unlock_irq(&chan->lock);
+ spin_unlock_irqrestore(&chan->lock, flags);
return desc;
}
@@ -593,6 +596,7 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
{
struct rcar_dmac_desc_page *page;
+ unsigned long flags;
LIST_HEAD(list);
unsigned int i;
@@ -606,10 +610,10 @@ static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
list_add_tail(&chunk->node, &list);
}
- spin_lock_irq(&chan->lock);
+ spin_lock_irqsave(&chan->lock, flags);
list_splice_tail(&list, &chan->desc.chunks_free);
list_add_tail(&page->node, &chan->desc.pages);
- spin_unlock_irq(&chan->lock);
+ spin_unlock_irqrestore(&chan->lock, flags);
return 0;
}
@@ -627,9 +631,10 @@ static struct rcar_dmac_xfer_chunk *
rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
{
struct rcar_dmac_xfer_chunk *chunk;
+ unsigned long flags;
int ret;
- spin_lock_irq(&chan->lock);
+ spin_lock_irqsave(&chan->lock, flags);
while (list_empty(&chan->desc.chunks_free)) {
/*
@@ -638,18 +643,18 @@ rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
* allocated descriptors. If the allocation fails return an
* error.
*/
- spin_unlock_irq(&chan->lock);
+ spin_unlock_irqrestore(&chan->lock, flags);
ret = rcar_dmac_xfer_chunk_alloc(chan, GFP_NOWAIT);
if (ret < 0)
return NULL;
- spin_lock_irq(&chan->lock);
+ spin_lock_irqsave(&chan->lock, flags);
}
chunk = list_first_entry(&chan->desc.chunks_free,
struct rcar_dmac_xfer_chunk, node);
list_del(&chunk->node);
- spin_unlock_irq(&chan->lock);
+ spin_unlock_irqrestore(&chan->lock, flags);
return chunk;
}
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index cb59619df23f..8677ead2a8e1 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -2,15 +2,16 @@
# EDAC Kconfig
# Copyright (c) 2008 Doug Thompson www.softwarebitmaker.com
# Licensed and distributed under the GPL
-#
+
+config EDAC_ATOMIC_SCRUB
+ bool
config EDAC_SUPPORT
bool
menuconfig EDAC
bool "EDAC (Error Detection And Correction) reporting"
- depends on HAS_IOMEM
- depends on X86 || PPC || TILE || ARM || EDAC_SUPPORT
+ depends on HAS_IOMEM && EDAC_SUPPORT
help
EDAC is designed to report errors in the core system.
These are low-level errors that are reported in the CPU or
@@ -262,10 +263,10 @@ config EDAC_SBRIDGE
config EDAC_MPC85XX
tristate "Freescale MPC83xx / MPC85xx"
- depends on EDAC_MM_EDAC && FSL_SOC && (PPC_83xx || PPC_85xx)
+ depends on EDAC_MM_EDAC && FSL_SOC
help
Support for error detection and correction on the Freescale
- MPC8349, MPC8560, MPC8540, MPC8548
+ MPC8349, MPC8560, MPC8540, MPC8548, T4240
config EDAC_MV64X60
tristate "Marvell MV64x60"
@@ -377,8 +378,8 @@ config EDAC_OCTEON_PCI
Cavium Octeon family of SOCs.
config EDAC_ALTERA_MC
- tristate "Altera SDRAM Memory Controller EDAC"
- depends on EDAC_MM_EDAC && ARCH_SOCFPGA
+ bool "Altera SDRAM Memory Controller EDAC"
+ depends on EDAC_MM_EDAC=y && ARCH_SOCFPGA
help
Support for error detection and correction on the
Altera SDRAM memory controller. Note that the
@@ -392,4 +393,11 @@ config EDAC_SYNOPSYS
Support for error detection and correction on the Synopsys DDR
memory controller.
+config EDAC_XGENE
+ tristate "APM X-Gene SoC"
+ depends on EDAC_MM_EDAC && (ARM64 || COMPILE_TEST)
+ help
+ Support for error detection and correction on the
+ APM X-Gene family of SOCs.
+
endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index b255f362b1db..28ef2a519f65 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -68,3 +68,4 @@ obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o
obj-$(CONFIG_EDAC_ALTERA_MC) += altera_edac.o
obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o
+obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 3c4929fda9d5..23ef0917483c 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -1,5 +1,5 @@
/*
- * Copyright Altera Corporation (C) 2014. All rights reserved.
+ * Copyright Altera Corporation (C) 2014-2015. All rights reserved.
* Copyright 2011-2012 Calxeda, Inc.
*
* This program is free software; you can redistribute it and/or modify it
@@ -28,113 +28,92 @@
#include <linux/types.h>
#include <linux/uaccess.h>
+#include "altera_edac.h"
#include "edac_core.h"
#include "edac_module.h"
#define EDAC_MOD_STR "altera_edac"
#define EDAC_VERSION "1"
-/* SDRAM Controller CtrlCfg Register */
-#define CTLCFG_OFST 0x00
-
-/* SDRAM Controller CtrlCfg Register Bit Masks */
-#define CTLCFG_ECC_EN 0x400
-#define CTLCFG_ECC_CORR_EN 0x800
-#define CTLCFG_GEN_SB_ERR 0x2000
-#define CTLCFG_GEN_DB_ERR 0x4000
-
-#define CTLCFG_ECC_AUTO_EN (CTLCFG_ECC_EN | \
- CTLCFG_ECC_CORR_EN)
-
-/* SDRAM Controller Address Width Register */
-#define DRAMADDRW_OFST 0x2C
-
-/* SDRAM Controller Address Widths Field Register */
-#define DRAMADDRW_COLBIT_MASK 0x001F
-#define DRAMADDRW_COLBIT_SHIFT 0
-#define DRAMADDRW_ROWBIT_MASK 0x03E0
-#define DRAMADDRW_ROWBIT_SHIFT 5
-#define DRAMADDRW_BANKBIT_MASK 0x1C00
-#define DRAMADDRW_BANKBIT_SHIFT 10
-#define DRAMADDRW_CSBIT_MASK 0xE000
-#define DRAMADDRW_CSBIT_SHIFT 13
-
-/* SDRAM Controller Interface Data Width Register */
-#define DRAMIFWIDTH_OFST 0x30
-
-/* SDRAM Controller Interface Data Width Defines */
-#define DRAMIFWIDTH_16B_ECC 24
-#define DRAMIFWIDTH_32B_ECC 40
-
-/* SDRAM Controller DRAM Status Register */
-#define DRAMSTS_OFST 0x38
-
-/* SDRAM Controller DRAM Status Register Bit Masks */
-#define DRAMSTS_SBEERR 0x04
-#define DRAMSTS_DBEERR 0x08
-#define DRAMSTS_CORR_DROP 0x10
-
-/* SDRAM Controller DRAM IRQ Register */
-#define DRAMINTR_OFST 0x3C
-
-/* SDRAM Controller DRAM IRQ Register Bit Masks */
-#define DRAMINTR_INTREN 0x01
-#define DRAMINTR_SBEMASK 0x02
-#define DRAMINTR_DBEMASK 0x04
-#define DRAMINTR_CORRDROPMASK 0x08
-#define DRAMINTR_INTRCLR 0x10
-
-/* SDRAM Controller Single Bit Error Count Register */
-#define SBECOUNT_OFST 0x40
-
-/* SDRAM Controller Single Bit Error Count Register Bit Masks */
-#define SBECOUNT_MASK 0x0F
-
-/* SDRAM Controller Double Bit Error Count Register */
-#define DBECOUNT_OFST 0x44
-
-/* SDRAM Controller Double Bit Error Count Register Bit Masks */
-#define DBECOUNT_MASK 0x0F
-
-/* SDRAM Controller ECC Error Address Register */
-#define ERRADDR_OFST 0x48
-
-/* SDRAM Controller ECC Error Address Register Bit Masks */
-#define ERRADDR_MASK 0xFFFFFFFF
+static const struct altr_sdram_prv_data c5_data = {
+ .ecc_ctrl_offset = CV_CTLCFG_OFST,
+ .ecc_ctl_en_mask = CV_CTLCFG_ECC_AUTO_EN,
+ .ecc_stat_offset = CV_DRAMSTS_OFST,
+ .ecc_stat_ce_mask = CV_DRAMSTS_SBEERR,
+ .ecc_stat_ue_mask = CV_DRAMSTS_DBEERR,
+ .ecc_saddr_offset = CV_ERRADDR_OFST,
+ .ecc_daddr_offset = CV_ERRADDR_OFST,
+ .ecc_cecnt_offset = CV_SBECOUNT_OFST,
+ .ecc_uecnt_offset = CV_DBECOUNT_OFST,
+ .ecc_irq_en_offset = CV_DRAMINTR_OFST,
+ .ecc_irq_en_mask = CV_DRAMINTR_INTREN,
+ .ecc_irq_clr_offset = CV_DRAMINTR_OFST,
+ .ecc_irq_clr_mask = (CV_DRAMINTR_INTRCLR | CV_DRAMINTR_INTREN),
+ .ecc_cnt_rst_offset = CV_DRAMINTR_OFST,
+ .ecc_cnt_rst_mask = CV_DRAMINTR_INTRCLR,
+#ifdef CONFIG_EDAC_DEBUG
+ .ce_ue_trgr_offset = CV_CTLCFG_OFST,
+ .ce_set_mask = CV_CTLCFG_GEN_SB_ERR,
+ .ue_set_mask = CV_CTLCFG_GEN_DB_ERR,
+#endif
+};
-/* Altera SDRAM Memory Controller data */
-struct altr_sdram_mc_data {
- struct regmap *mc_vbase;
+static const struct altr_sdram_prv_data a10_data = {
+ .ecc_ctrl_offset = A10_ECCCTRL1_OFST,
+ .ecc_ctl_en_mask = A10_ECCCTRL1_ECC_EN,
+ .ecc_stat_offset = A10_INTSTAT_OFST,
+ .ecc_stat_ce_mask = A10_INTSTAT_SBEERR,
+ .ecc_stat_ue_mask = A10_INTSTAT_DBEERR,
+ .ecc_saddr_offset = A10_SERRADDR_OFST,
+ .ecc_daddr_offset = A10_DERRADDR_OFST,
+ .ecc_irq_en_offset = A10_ERRINTEN_OFST,
+ .ecc_irq_en_mask = A10_ECC_IRQ_EN_MASK,
+ .ecc_irq_clr_offset = A10_INTSTAT_OFST,
+ .ecc_irq_clr_mask = (A10_INTSTAT_SBEERR | A10_INTSTAT_DBEERR),
+ .ecc_cnt_rst_offset = A10_ECCCTRL1_OFST,
+ .ecc_cnt_rst_mask = A10_ECC_CNT_RESET_MASK,
+#ifdef CONFIG_EDAC_DEBUG
+ .ce_ue_trgr_offset = A10_DIAGINTTEST_OFST,
+ .ce_set_mask = A10_DIAGINT_TSERRA_MASK,
+ .ue_set_mask = A10_DIAGINT_TDERRA_MASK,
+#endif
};
static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id)
{
struct mem_ctl_info *mci = dev_id;
struct altr_sdram_mc_data *drvdata = mci->pvt_info;
- u32 status, err_count, err_addr;
+ const struct altr_sdram_prv_data *priv = drvdata->data;
+ u32 status, err_count = 1, err_addr;
- /* Error Address is shared by both SBE & DBE */
- regmap_read(drvdata->mc_vbase, ERRADDR_OFST, &err_addr);
+ regmap_read(drvdata->mc_vbase, priv->ecc_stat_offset, &status);
- regmap_read(drvdata->mc_vbase, DRAMSTS_OFST, &status);
-
- if (status & DRAMSTS_DBEERR) {
- regmap_read(drvdata->mc_vbase, DBECOUNT_OFST, &err_count);
+ if (status & priv->ecc_stat_ue_mask) {
+ regmap_read(drvdata->mc_vbase, priv->ecc_daddr_offset,
+ &err_addr);
+ if (priv->ecc_uecnt_offset)
+ regmap_read(drvdata->mc_vbase, priv->ecc_uecnt_offset,
+ &err_count);
panic("\nEDAC: [%d Uncorrectable errors @ 0x%08X]\n",
err_count, err_addr);
}
- if (status & DRAMSTS_SBEERR) {
- regmap_read(drvdata->mc_vbase, SBECOUNT_OFST, &err_count);
+ if (status & priv->ecc_stat_ce_mask) {
+ regmap_read(drvdata->mc_vbase, priv->ecc_saddr_offset,
+ &err_addr);
+ if (priv->ecc_uecnt_offset)
+ regmap_read(drvdata->mc_vbase, priv->ecc_cecnt_offset,
+ &err_count);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, err_count,
err_addr >> PAGE_SHIFT,
err_addr & ~PAGE_MASK, 0,
0, 0, -1, mci->ctl_name, "");
- }
-
- regmap_write(drvdata->mc_vbase, DRAMINTR_OFST,
- (DRAMINTR_INTRCLR | DRAMINTR_INTREN));
+ /* Clear IRQ to resume */
+ regmap_write(drvdata->mc_vbase, priv->ecc_irq_clr_offset,
+ priv->ecc_irq_clr_mask);
- return IRQ_HANDLED;
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
}
#ifdef CONFIG_EDAC_DEBUG
@@ -144,6 +123,7 @@ static ssize_t altr_sdr_mc_err_inject_write(struct file *file,
{
struct mem_ctl_info *mci = file->private_data;
struct altr_sdram_mc_data *drvdata = mci->pvt_info;
+ const struct altr_sdram_prv_data *priv = drvdata->data;
u32 *ptemp;
dma_addr_t dma_handle;
u32 reg, read_reg;
@@ -156,8 +136,9 @@ static ssize_t altr_sdr_mc_err_inject_write(struct file *file,
return -ENOMEM;
}
- regmap_read(drvdata->mc_vbase, CTLCFG_OFST, &read_reg);
- read_reg &= ~(CTLCFG_GEN_SB_ERR | CTLCFG_GEN_DB_ERR);
+ regmap_read(drvdata->mc_vbase, priv->ce_ue_trgr_offset,
+ &read_reg);
+ read_reg &= ~(priv->ce_set_mask | priv->ue_set_mask);
/* Error are injected by writing a word while the SBE or DBE
* bit in the CTLCFG register is set. Reading the word will
@@ -166,20 +147,20 @@ static ssize_t altr_sdr_mc_err_inject_write(struct file *file,
if (count == 3) {
edac_printk(KERN_ALERT, EDAC_MC,
"Inject Double bit error\n");
- regmap_write(drvdata->mc_vbase, CTLCFG_OFST,
- (read_reg | CTLCFG_GEN_DB_ERR));
+ regmap_write(drvdata->mc_vbase, priv->ce_ue_trgr_offset,
+ (read_reg | priv->ue_set_mask));
} else {
edac_printk(KERN_ALERT, EDAC_MC,
"Inject Single bit error\n");
- regmap_write(drvdata->mc_vbase, CTLCFG_OFST,
- (read_reg | CTLCFG_GEN_SB_ERR));
+ regmap_write(drvdata->mc_vbase, priv->ce_ue_trgr_offset,
+ (read_reg | priv->ce_set_mask));
}
ptemp[0] = 0x5A5A5A5A;
ptemp[1] = 0xA5A5A5A5;
/* Clear the error injection bits */
- regmap_write(drvdata->mc_vbase, CTLCFG_OFST, read_reg);
+ regmap_write(drvdata->mc_vbase, priv->ce_ue_trgr_offset, read_reg);
/* Ensure it has been written out */
wmb();
@@ -219,50 +200,106 @@ static void altr_sdr_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
{}
#endif
-/* Get total memory size in bytes */
-static u32 altr_sdram_get_total_mem_size(struct regmap *mc_vbase)
+/* Get total memory size from Open Firmware DTB */
+static unsigned long get_total_mem(void)
{
- u32 size, read_reg, row, bank, col, cs, width;
-
- if (regmap_read(mc_vbase, DRAMADDRW_OFST, &read_reg) < 0)
- return 0;
-
- if (regmap_read(mc_vbase, DRAMIFWIDTH_OFST, &width) < 0)
- return 0;
-
- col = (read_reg & DRAMADDRW_COLBIT_MASK) >>
- DRAMADDRW_COLBIT_SHIFT;
- row = (read_reg & DRAMADDRW_ROWBIT_MASK) >>
- DRAMADDRW_ROWBIT_SHIFT;
- bank = (read_reg & DRAMADDRW_BANKBIT_MASK) >>
- DRAMADDRW_BANKBIT_SHIFT;
- cs = (read_reg & DRAMADDRW_CSBIT_MASK) >>
- DRAMADDRW_CSBIT_SHIFT;
-
- /* Correct for ECC as its not addressible */
- if (width == DRAMIFWIDTH_32B_ECC)
- width = 32;
- if (width == DRAMIFWIDTH_16B_ECC)
- width = 16;
-
- /* calculate the SDRAM size base on this info */
- size = 1 << (row + bank + col);
- size = size * cs * (width / 8);
- return size;
+ struct device_node *np = NULL;
+ const unsigned int *reg, *reg_end;
+ int len, sw, aw;
+ unsigned long start, size, total_mem = 0;
+
+ for_each_node_by_type(np, "memory") {
+ aw = of_n_addr_cells(np);
+ sw = of_n_size_cells(np);
+ reg = (const unsigned int *)of_get_property(np, "reg", &len);
+ reg_end = reg + (len / sizeof(u32));
+
+ total_mem = 0;
+ do {
+ start = of_read_number(reg, aw);
+ reg += aw;
+ size = of_read_number(reg, sw);
+ reg += sw;
+ total_mem += size;
+ } while (reg < reg_end);
+ }
+ edac_dbg(0, "total_mem 0x%lx\n", total_mem);
+ return total_mem;
+}
+
+static const struct of_device_id altr_sdram_ctrl_of_match[] = {
+ { .compatible = "altr,sdram-edac", .data = (void *)&c5_data},
+ { .compatible = "altr,sdram-edac-a10", .data = (void *)&a10_data},
+ {},
+};
+MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match);
+
+static int a10_init(struct regmap *mc_vbase)
+{
+ if (regmap_update_bits(mc_vbase, A10_INTMODE_OFST,
+ A10_INTMODE_SB_INT, A10_INTMODE_SB_INT)) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Error setting SB IRQ mode\n");
+ return -ENODEV;
+ }
+
+ if (regmap_write(mc_vbase, A10_SERRCNTREG_OFST, 1)) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Error setting trigger count\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int a10_unmask_irq(struct platform_device *pdev, u32 mask)
+{
+ void __iomem *sm_base;
+ int ret = 0;
+
+ if (!request_mem_region(A10_SYMAN_INTMASK_CLR, sizeof(u32),
+ dev_name(&pdev->dev))) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Unable to request mem region\n");
+ return -EBUSY;
+ }
+
+ sm_base = ioremap(A10_SYMAN_INTMASK_CLR, sizeof(u32));
+ if (!sm_base) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Unable to ioremap device\n");
+
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ iowrite32(mask, sm_base);
+
+ iounmap(sm_base);
+
+release:
+ release_mem_region(A10_SYMAN_INTMASK_CLR, sizeof(u32));
+
+ return ret;
}
static int altr_sdram_probe(struct platform_device *pdev)
{
+ const struct of_device_id *id;
struct edac_mc_layer layers[2];
struct mem_ctl_info *mci;
struct altr_sdram_mc_data *drvdata;
+ const struct altr_sdram_prv_data *priv;
struct regmap *mc_vbase;
struct dimm_info *dimm;
- u32 read_reg, mem_size;
- int irq;
- int res = 0;
+ u32 read_reg;
+ int irq, irq2, res = 0;
+ unsigned long mem_size, irqflags = 0;
+
+ id = of_match_device(altr_sdram_ctrl_of_match, &pdev->dev);
+ if (!id)
+ return -ENODEV;
- /* Validate the SDRAM controller has ECC enabled */
/* Grab the register range from the sdr controller in device tree */
mc_vbase = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"altr,sdr-syscon");
@@ -272,25 +309,46 @@ static int altr_sdram_probe(struct platform_device *pdev)
return -ENODEV;
}
- if (regmap_read(mc_vbase, CTLCFG_OFST, &read_reg) ||
- ((read_reg & CTLCFG_ECC_AUTO_EN) != CTLCFG_ECC_AUTO_EN)) {
+ /* Check specific dependencies for the module */
+ priv = of_match_node(altr_sdram_ctrl_of_match,
+ pdev->dev.of_node)->data;
+
+ /* Validate the SDRAM controller has ECC enabled */
+ if (regmap_read(mc_vbase, priv->ecc_ctrl_offset, &read_reg) ||
+ ((read_reg & priv->ecc_ctl_en_mask) != priv->ecc_ctl_en_mask)) {
edac_printk(KERN_ERR, EDAC_MC,
"No ECC/ECC disabled [0x%08X]\n", read_reg);
return -ENODEV;
}
/* Grab memory size from device tree. */
- mem_size = altr_sdram_get_total_mem_size(mc_vbase);
+ mem_size = get_total_mem();
if (!mem_size) {
+ edac_printk(KERN_ERR, EDAC_MC, "Unable to calculate memory size\n");
+ return -ENODEV;
+ }
+
+ /* Ensure the SDRAM Interrupt is disabled */
+ if (regmap_update_bits(mc_vbase, priv->ecc_irq_en_offset,
+ priv->ecc_irq_en_mask, 0)) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Error disabling SDRAM ECC IRQ\n");
+ return -ENODEV;
+ }
+
+ /* Toggle to clear the SDRAM Error count */
+ if (regmap_update_bits(mc_vbase, priv->ecc_cnt_rst_offset,
+ priv->ecc_cnt_rst_mask,
+ priv->ecc_cnt_rst_mask)) {
edac_printk(KERN_ERR, EDAC_MC,
- "Unable to calculate memory size\n");
+ "Error clearing SDRAM ECC count\n");
return -ENODEV;
}
- /* Ensure the SDRAM Interrupt is disabled and cleared */
- if (regmap_write(mc_vbase, DRAMINTR_OFST, DRAMINTR_INTRCLR)) {
+ if (regmap_update_bits(mc_vbase, priv->ecc_cnt_rst_offset,
+ priv->ecc_cnt_rst_mask, 0)) {
edac_printk(KERN_ERR, EDAC_MC,
- "Error clearing SDRAM ECC IRQ\n");
+ "Error clearing SDRAM ECC count\n");
return -ENODEV;
}
@@ -301,6 +359,9 @@ static int altr_sdram_probe(struct platform_device *pdev)
return -ENODEV;
}
+ /* Arria10 has a 2nd IRQ */
+ irq2 = platform_get_irq(pdev, 1);
+
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = 1;
layers[0].is_virt_csrow = true;
@@ -315,9 +376,12 @@ static int altr_sdram_probe(struct platform_device *pdev)
mci->pdev = &pdev->dev;
drvdata = mci->pvt_info;
drvdata->mc_vbase = mc_vbase;
+ drvdata->data = priv;
platform_set_drvdata(pdev, mci);
if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Unable to get managed device resource\n");
res = -ENOMEM;
goto free;
}
@@ -342,8 +406,32 @@ static int altr_sdram_probe(struct platform_device *pdev)
if (res < 0)
goto err;
+ /* Only the Arria10 has separate IRQs */
+ if (irq2 > 0) {
+ /* Arria10 specific initialization */
+ res = a10_init(mc_vbase);
+ if (res < 0)
+ goto err2;
+
+ res = devm_request_irq(&pdev->dev, irq2,
+ altr_sdram_mc_err_handler,
+ IRQF_SHARED, dev_name(&pdev->dev), mci);
+ if (res < 0) {
+ edac_mc_printk(mci, KERN_ERR,
+ "Unable to request irq %d\n", irq2);
+ res = -ENODEV;
+ goto err2;
+ }
+
+ res = a10_unmask_irq(pdev, A10_DDR0_IRQ_MASK);
+ if (res < 0)
+ goto err2;
+
+ irqflags = IRQF_SHARED;
+ }
+
res = devm_request_irq(&pdev->dev, irq, altr_sdram_mc_err_handler,
- 0, dev_name(&pdev->dev), mci);
+ irqflags, dev_name(&pdev->dev), mci);
if (res < 0) {
edac_mc_printk(mci, KERN_ERR,
"Unable to request irq %d\n", irq);
@@ -351,8 +439,9 @@ static int altr_sdram_probe(struct platform_device *pdev)
goto err2;
}
- if (regmap_write(drvdata->mc_vbase, DRAMINTR_OFST,
- (DRAMINTR_INTRCLR | DRAMINTR_INTREN))) {
+ /* Infrastructure ready - enable the IRQ */
+ if (regmap_update_bits(drvdata->mc_vbase, priv->ecc_irq_en_offset,
+ priv->ecc_irq_en_mask, priv->ecc_irq_en_mask)) {
edac_mc_printk(mci, KERN_ERR,
"Error enabling SDRAM ECC IRQ\n");
res = -ENODEV;
@@ -388,17 +477,31 @@ static int altr_sdram_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id altr_sdram_ctrl_of_match[] = {
- { .compatible = "altr,sdram-edac", },
- {},
+/*
+ * If you want to suspend, need to disable EDAC by removing it
+ * from the device tree or defconfig.
+ */
+#ifdef CONFIG_PM
+static int altr_sdram_prepare(struct device *dev)
+{
+ pr_err("Suspend not allowed when EDAC is enabled.\n");
+
+ return -EPERM;
+}
+
+static const struct dev_pm_ops altr_sdram_pm_ops = {
+ .prepare = altr_sdram_prepare,
};
-MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match);
+#endif
static struct platform_driver altr_sdram_edac_driver = {
.probe = altr_sdram_probe,
.remove = altr_sdram_remove,
.driver = {
.name = "altr_sdram_edac",
+#ifdef CONFIG_PM
+ .pm = &altr_sdram_pm_ops,
+#endif
.of_match_table = altr_sdram_ctrl_of_match,
},
};
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
new file mode 100644
index 000000000000..7b64dc7c4eb7
--- /dev/null
+++ b/drivers/edac/altera_edac.h
@@ -0,0 +1,201 @@
+/*
+ *
+ * Copyright (C) 2015 Altera 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 _ALTERA_EDAC_H
+#define _ALTERA_EDAC_H
+
+#include <linux/edac.h>
+#include <linux/types.h>
+
+/* SDRAM Controller CtrlCfg Register */
+#define CV_CTLCFG_OFST 0x00
+
+/* SDRAM Controller CtrlCfg Register Bit Masks */
+#define CV_CTLCFG_ECC_EN 0x400
+#define CV_CTLCFG_ECC_CORR_EN 0x800
+#define CV_CTLCFG_GEN_SB_ERR 0x2000
+#define CV_CTLCFG_GEN_DB_ERR 0x4000
+
+#define CV_CTLCFG_ECC_AUTO_EN (CV_CTLCFG_ECC_EN | \
+ CV_CTLCFG_ECC_CORR_EN)
+
+/* SDRAM Controller Address Width Register */
+#define CV_DRAMADDRW_OFST 0x2C
+
+/* SDRAM Controller Address Widths Field Register */
+#define DRAMADDRW_COLBIT_MASK 0x001F
+#define DRAMADDRW_COLBIT_SHIFT 0
+#define DRAMADDRW_ROWBIT_MASK 0x03E0
+#define DRAMADDRW_ROWBIT_SHIFT 5
+#define CV_DRAMADDRW_BANKBIT_MASK 0x1C00
+#define CV_DRAMADDRW_BANKBIT_SHIFT 10
+#define CV_DRAMADDRW_CSBIT_MASK 0xE000
+#define CV_DRAMADDRW_CSBIT_SHIFT 13
+
+/* SDRAM Controller Interface Data Width Register */
+#define CV_DRAMIFWIDTH_OFST 0x30
+
+/* SDRAM Controller Interface Data Width Defines */
+#define CV_DRAMIFWIDTH_16B_ECC 24
+#define CV_DRAMIFWIDTH_32B_ECC 40
+
+/* SDRAM Controller DRAM Status Register */
+#define CV_DRAMSTS_OFST 0x38
+
+/* SDRAM Controller DRAM Status Register Bit Masks */
+#define CV_DRAMSTS_SBEERR 0x04
+#define CV_DRAMSTS_DBEERR 0x08
+#define CV_DRAMSTS_CORR_DROP 0x10
+
+/* SDRAM Controller DRAM IRQ Register */
+#define CV_DRAMINTR_OFST 0x3C
+
+/* SDRAM Controller DRAM IRQ Register Bit Masks */
+#define CV_DRAMINTR_INTREN 0x01
+#define CV_DRAMINTR_SBEMASK 0x02
+#define CV_DRAMINTR_DBEMASK 0x04
+#define CV_DRAMINTR_CORRDROPMASK 0x08
+#define CV_DRAMINTR_INTRCLR 0x10
+
+/* SDRAM Controller Single Bit Error Count Register */
+#define CV_SBECOUNT_OFST 0x40
+
+/* SDRAM Controller Double Bit Error Count Register */
+#define CV_DBECOUNT_OFST 0x44
+
+/* SDRAM Controller ECC Error Address Register */
+#define CV_ERRADDR_OFST 0x48
+
+/*-----------------------------------------*/
+
+/* SDRAM Controller EccCtrl Register */
+#define A10_ECCCTRL1_OFST 0x00
+
+/* SDRAM Controller EccCtrl Register Bit Masks */
+#define A10_ECCCTRL1_ECC_EN 0x001
+#define A10_ECCCTRL1_CNT_RST 0x010
+#define A10_ECCCTRL1_AWB_CNT_RST 0x100
+#define A10_ECC_CNT_RESET_MASK (A10_ECCCTRL1_CNT_RST | \
+ A10_ECCCTRL1_AWB_CNT_RST)
+
+/* SDRAM Controller Address Width Register */
+#define CV_DRAMADDRW 0xFFC2502C
+#define A10_DRAMADDRW 0xFFCFA0A8
+
+/* SDRAM Controller Address Widths Field Register */
+#define DRAMADDRW_COLBIT_MASK 0x001F
+#define DRAMADDRW_COLBIT_SHIFT 0
+#define DRAMADDRW_ROWBIT_MASK 0x03E0
+#define DRAMADDRW_ROWBIT_SHIFT 5
+#define CV_DRAMADDRW_BANKBIT_MASK 0x1C00
+#define CV_DRAMADDRW_BANKBIT_SHIFT 10
+#define CV_DRAMADDRW_CSBIT_MASK 0xE000
+#define CV_DRAMADDRW_CSBIT_SHIFT 13
+
+#define A10_DRAMADDRW_BANKBIT_MASK 0x3C00
+#define A10_DRAMADDRW_BANKBIT_SHIFT 10
+#define A10_DRAMADDRW_GRPBIT_MASK 0xC000
+#define A10_DRAMADDRW_GRPBIT_SHIFT 14
+#define A10_DRAMADDRW_CSBIT_MASK 0x70000
+#define A10_DRAMADDRW_CSBIT_SHIFT 16
+
+/* SDRAM Controller Interface Data Width Register */
+#define CV_DRAMIFWIDTH 0xFFC25030
+#define A10_DRAMIFWIDTH 0xFFCFB008
+
+/* SDRAM Controller Interface Data Width Defines */
+#define CV_DRAMIFWIDTH_16B_ECC 24
+#define CV_DRAMIFWIDTH_32B_ECC 40
+
+#define A10_DRAMIFWIDTH_16B 0x0
+#define A10_DRAMIFWIDTH_32B 0x1
+#define A10_DRAMIFWIDTH_64B 0x2
+
+/* SDRAM Controller DRAM IRQ Register */
+#define A10_ERRINTEN_OFST 0x10
+
+/* SDRAM Controller DRAM IRQ Register Bit Masks */
+#define A10_ERRINTEN_SERRINTEN 0x01
+#define A10_ERRINTEN_DERRINTEN 0x02
+#define A10_ECC_IRQ_EN_MASK (A10_ERRINTEN_SERRINTEN | \
+ A10_ERRINTEN_DERRINTEN)
+
+/* SDRAM Interrupt Mode Register */
+#define A10_INTMODE_OFST 0x1C
+#define A10_INTMODE_SB_INT 1
+
+/* SDRAM Controller Error Status Register */
+#define A10_INTSTAT_OFST 0x20
+
+/* SDRAM Controller Error Status Register Bit Masks */
+#define A10_INTSTAT_SBEERR 0x01
+#define A10_INTSTAT_DBEERR 0x02
+
+/* SDRAM Controller ECC Error Address Register */
+#define A10_DERRADDR_OFST 0x2C
+#define A10_SERRADDR_OFST 0x30
+
+/* SDRAM Controller ECC Diagnostic Register */
+#define A10_DIAGINTTEST_OFST 0x24
+
+#define A10_DIAGINT_TSERRA_MASK 0x0001
+#define A10_DIAGINT_TDERRA_MASK 0x0100
+
+#define A10_SBERR_IRQ 34
+#define A10_DBERR_IRQ 32
+
+/* SDRAM Single Bit Error Count Compare Set Register */
+#define A10_SERRCNTREG_OFST 0x3C
+
+#define A10_SYMAN_INTMASK_CLR 0xFFD06098
+#define A10_INTMASK_CLR_OFST 0x10
+#define A10_DDR0_IRQ_MASK BIT(17)
+
+struct altr_sdram_prv_data {
+ int ecc_ctrl_offset;
+ int ecc_ctl_en_mask;
+ int ecc_cecnt_offset;
+ int ecc_uecnt_offset;
+ int ecc_stat_offset;
+ int ecc_stat_ce_mask;
+ int ecc_stat_ue_mask;
+ int ecc_saddr_offset;
+ int ecc_daddr_offset;
+ int ecc_irq_en_offset;
+ int ecc_irq_en_mask;
+ int ecc_irq_clr_offset;
+ int ecc_irq_clr_mask;
+ int ecc_cnt_rst_offset;
+ int ecc_cnt_rst_mask;
+#ifdef CONFIG_EDAC_DEBUG
+ struct edac_dev_sysfs_attribute *eccmgr_sysfs_attr;
+ int ecc_enable_mask;
+ int ce_set_mask;
+ int ue_set_mask;
+ int ce_ue_trgr_offset;
+#endif
+};
+
+/* Altera SDRAM Memory Controller data */
+struct altr_sdram_mc_data {
+ struct regmap *mc_vbase;
+ int sb_irq;
+ int db_irq;
+ const struct altr_sdram_prv_data *data;
+};
+
+#endif /* #ifndef _ALTERA_EDAC_H */
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 92772fffc52f..73aea40a9c89 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -2964,6 +2964,7 @@ static struct pci_driver amd64_pci_driver = {
.probe = probe_one_instance,
.remove = remove_one_instance,
.id_table = amd64_pci_table,
+ .driver.probe_type = PROBE_FORCE_SYNCHRONOUS,
};
static void setup_pci_device(void)
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index af3be1914dbb..943ed8cf71b9 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -30,11 +30,16 @@
#include <linux/bitops.h>
#include <asm/uaccess.h>
#include <asm/page.h>
-#include <asm/edac.h>
#include "edac_core.h"
#include "edac_module.h"
#include <ras/ras_event.h>
+#ifdef CONFIG_EDAC_ATOMIC_SCRUB
+#include <asm/edac.h>
+#else
+#define edac_atomic_scrub(va, size) do { } while (0)
+#endif
+
/* lock to memory controller's control array */
static DEFINE_MUTEX(mem_ctls_mutex);
static LIST_HEAD(mc_devices);
@@ -874,7 +879,7 @@ static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
virt_addr = kmap_atomic(pg);
/* Perform architecture specific atomic scrub operation */
- atomic_scrub(virt_addr + offset, size);
+ edac_atomic_scrub(virt_addr + offset, size);
/* Unmap and complete */
kunmap_atomic(virt_addr);
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 112d63ad1154..33df7d93c857 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -307,8 +307,6 @@ static struct device_type csrow_attr_type = {
*
*/
-#define EDAC_NR_CHANNELS 6
-
DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR,
channel_dimm_label_show, channel_dimm_label_store, 0);
DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR,
@@ -403,9 +401,6 @@ static inline int nr_pages_per_csrow(struct csrow_info *csrow)
static int edac_create_csrow_object(struct mem_ctl_info *mci,
struct csrow_info *csrow, int index)
{
- if (csrow->nr_channels > EDAC_NR_CHANNELS)
- return -ENODEV;
-
csrow->dev.type = &csrow_attr_type;
csrow->dev.bus = mci->bus;
csrow->dev.groups = csrow_dev_groups;
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c
index 9d9e18aefaaa..ff07aae5b7fb 100644
--- a/drivers/edac/edac_stub.c
+++ b/drivers/edac/edac_stub.c
@@ -16,7 +16,6 @@
#include <linux/edac.h>
#include <linux/atomic.h>
#include <linux/device.h>
-#include <asm/edac.h>
int edac_op_state = EDAC_OPSTATE_INVAL;
EXPORT_SYMBOL_GPL(edac_op_state);
diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c
index f7681b553fd5..4c73e4d03d46 100644
--- a/drivers/edac/mce_amd_inj.c
+++ b/drivers/edac/mce_amd_inj.c
@@ -15,6 +15,8 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/cpu.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
#include <asm/mce.h>
#include "mce_amd.h"
@@ -25,6 +27,25 @@
static struct mce i_mce;
static struct dentry *dfs_inj;
+static u8 n_banks;
+
+#define MAX_FLAG_OPT_SIZE 3
+
+enum injection_type {
+ SW_INJ = 0, /* SW injection, simply decode the error */
+ HW_INJ, /* Trigger a #MC */
+ N_INJ_TYPES,
+};
+
+static const char * const flags_options[] = {
+ [SW_INJ] = "sw",
+ [HW_INJ] = "hw",
+ NULL
+};
+
+/* Set default injection to SW_INJ */
+static enum injection_type inj_type = SW_INJ;
+
#define MCE_INJECT_SET(reg) \
static int inj_##reg##_set(void *data, u64 val) \
{ \
@@ -79,24 +100,66 @@ static int toggle_hw_mce_inject(unsigned int cpu, bool enable)
return err;
}
-static int flags_get(void *data, u64 *val)
+static int __set_inj(const char *buf)
{
- struct mce *m = (struct mce *)data;
+ int i;
- *val = m->inject_flags;
+ for (i = 0; i < N_INJ_TYPES; i++) {
+ if (!strncmp(flags_options[i], buf, strlen(flags_options[i]))) {
+ inj_type = i;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
- return 0;
+static ssize_t flags_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ char buf[MAX_FLAG_OPT_SIZE];
+ int n;
+
+ n = sprintf(buf, "%s\n", flags_options[inj_type]);
+
+ return simple_read_from_buffer(ubuf, cnt, ppos, buf, n);
}
-static int flags_set(void *data, u64 val)
+static ssize_t flags_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
{
- struct mce *m = (struct mce *)data;
+ char buf[MAX_FLAG_OPT_SIZE], *__buf;
+ int err;
+ size_t ret;
- m->inject_flags = (u8)val;
- return 0;
+ if (cnt > MAX_FLAG_OPT_SIZE)
+ cnt = MAX_FLAG_OPT_SIZE;
+
+ ret = cnt;
+
+ if (copy_from_user(&buf, ubuf, cnt))
+ return -EFAULT;
+
+ buf[cnt - 1] = 0;
+
+ /* strip whitespace */
+ __buf = strstrip(buf);
+
+ err = __set_inj(__buf);
+ if (err) {
+ pr_err("%s: Invalid flags value: %s\n", __func__, __buf);
+ return err;
+ }
+
+ *ppos += ret;
+
+ return ret;
}
-DEFINE_SIMPLE_ATTRIBUTE(flags_fops, flags_get, flags_set, "%llu\n");
+static const struct file_operations flags_fops = {
+ .read = flags_read,
+ .write = flags_write,
+ .llseek = generic_file_llseek,
+};
/*
* On which CPU to inject?
@@ -128,21 +191,24 @@ static void do_inject(void)
unsigned int cpu = i_mce.extcpu;
u8 b = i_mce.bank;
- if (!(i_mce.inject_flags & MCJ_EXCEPTION)) {
+ if (i_mce.misc)
+ i_mce.status |= MCI_STATUS_MISCV;
+
+ if (inj_type == SW_INJ) {
amd_decode_mce(NULL, 0, &i_mce);
return;
}
- get_online_cpus();
- if (!cpu_online(cpu))
- goto err;
-
/* prep MCE global settings for the injection */
mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV;
if (!(i_mce.status & MCI_STATUS_PCC))
mcg_status |= MCG_STATUS_RIPV;
+ get_online_cpus();
+ if (!cpu_online(cpu))
+ goto err;
+
toggle_hw_mce_inject(cpu, true);
wrmsr_on_cpu(cpu, MSR_IA32_MCG_STATUS,
@@ -174,11 +240,9 @@ static int inj_bank_set(void *data, u64 val)
{
struct mce *m = (struct mce *)data;
- if (val > 5) {
- if (boot_cpu_data.x86 != 0x15 || val > 6) {
- pr_err("Non-existent MCE bank: %llu\n", val);
- return -EINVAL;
- }
+ if (val >= n_banks) {
+ pr_err("Non-existent MCE bank: %llu\n", val);
+ return -EINVAL;
}
m->bank = val;
@@ -187,32 +251,81 @@ static int inj_bank_set(void *data, u64 val)
return 0;
}
-static int inj_bank_get(void *data, u64 *val)
-{
- struct mce *m = (struct mce *)data;
+MCE_INJECT_GET(bank);
- *val = m->bank;
- return 0;
+DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n");
+
+static const char readme_msg[] =
+"Description of the files and their usages:\n"
+"\n"
+"Note1: i refers to the bank number below.\n"
+"Note2: See respective BKDGs for the exact bit definitions of the files below\n"
+"as they mirror the hardware registers.\n"
+"\n"
+"status:\t Set MCi_STATUS: the bits in that MSR control the error type and\n"
+"\t attributes of the error which caused the MCE.\n"
+"\n"
+"misc:\t Set MCi_MISC: provide auxiliary info about the error. It is mostly\n"
+"\t used for error thresholding purposes and its validity is indicated by\n"
+"\t MCi_STATUS[MiscV].\n"
+"\n"
+"addr:\t Error address value to be written to MCi_ADDR. Log address information\n"
+"\t associated with the error.\n"
+"\n"
+"cpu:\t The CPU to inject the error on.\n"
+"\n"
+"bank:\t Specify the bank you want to inject the error into: the number of\n"
+"\t banks in a processor varies and is family/model-specific, therefore, the\n"
+"\t supplied value is sanity-checked. Setting the bank value also triggers the\n"
+"\t injection.\n"
+"\n"
+"flags:\t Injection type to be performed. Writing to this file will trigger a\n"
+"\t real machine check, an APIC interrupt or invoke the error decoder routines\n"
+"\t for AMD processors.\n"
+"\n"
+"\t Allowed error injection types:\n"
+"\t - \"sw\": Software error injection. Decode error to a human-readable \n"
+"\t format only. Safe to use.\n"
+"\t - \"hw\": Hardware error injection. Causes the #MC exception handler to \n"
+"\t handle the error. Be warned: might cause system panic if MCi_STATUS[PCC] \n"
+"\t is set. Therefore, consider setting (debugfs_mountpoint)/mce/fake_panic \n"
+"\t before injecting.\n"
+"\n";
+
+static ssize_t
+inj_readme_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_read_from_buffer(ubuf, cnt, ppos,
+ readme_msg, strlen(readme_msg));
}
-DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n");
+static const struct file_operations readme_fops = {
+ .read = inj_readme_read,
+};
static struct dfs_node {
char *name;
struct dentry *d;
const struct file_operations *fops;
+ umode_t perm;
} dfs_fls[] = {
- { .name = "status", .fops = &status_fops },
- { .name = "misc", .fops = &misc_fops },
- { .name = "addr", .fops = &addr_fops },
- { .name = "bank", .fops = &bank_fops },
- { .name = "flags", .fops = &flags_fops },
- { .name = "cpu", .fops = &extcpu_fops },
+ { .name = "status", .fops = &status_fops, .perm = S_IRUSR | S_IWUSR },
+ { .name = "misc", .fops = &misc_fops, .perm = S_IRUSR | S_IWUSR },
+ { .name = "addr", .fops = &addr_fops, .perm = S_IRUSR | S_IWUSR },
+ { .name = "bank", .fops = &bank_fops, .perm = S_IRUSR | S_IWUSR },
+ { .name = "flags", .fops = &flags_fops, .perm = S_IRUSR | S_IWUSR },
+ { .name = "cpu", .fops = &extcpu_fops, .perm = S_IRUSR | S_IWUSR },
+ { .name = "README", .fops = &readme_fops, .perm = S_IRUSR | S_IRGRP | S_IROTH },
};
static int __init init_mce_inject(void)
{
int i;
+ u64 cap;
+
+ rdmsrl(MSR_IA32_MCG_CAP, cap);
+ n_banks = cap & MCG_BANKCNT_MASK;
dfs_inj = debugfs_create_dir("mce-inject", NULL);
if (!dfs_inj)
@@ -220,7 +333,7 @@ static int __init init_mce_inject(void)
for (i = 0; i < ARRAY_SIZE(dfs_fls); i++) {
dfs_fls[i].d = debugfs_create_file(dfs_fls[i].name,
- S_IRUSR | S_IWUSR,
+ dfs_fls[i].perm,
dfs_inj,
&i_mce,
dfs_fls[i].fops);
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 68bf234bdfe6..23ef8e9f2c9a 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -811,6 +811,8 @@ static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc,
}
}
+#define make64(high, low) (((u64)(high) << 32) | (low))
+
static void mpc85xx_mc_check(struct mem_ctl_info *mci)
{
struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
@@ -818,7 +820,7 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
u32 bus_width;
u32 err_detect;
u32 syndrome;
- u32 err_addr;
+ u64 err_addr;
u32 pfn;
int row_index;
u32 cap_high;
@@ -849,7 +851,9 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
else
syndrome &= 0xffff;
- err_addr = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS);
+ err_addr = make64(
+ in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_EXT_ADDRESS),
+ in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS));
pfn = err_addr >> PAGE_SHIFT;
for (row_index = 0; row_index < mci->nr_csrows; row_index++) {
@@ -886,7 +890,7 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
mpc85xx_mc_printk(mci, KERN_ERR,
"Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n",
cap_high, cap_low, syndrome);
- mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8x\n", err_addr);
+ mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx\n", err_addr);
mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn);
/* we are out of range */
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
index 4498baf9ce05..9352e88d53e5 100644
--- a/drivers/edac/mpc85xx_edac.h
+++ b/drivers/edac/mpc85xx_edac.h
@@ -43,6 +43,7 @@
#define MPC85XX_MC_ERR_INT_EN 0x0e48
#define MPC85XX_MC_CAPTURE_ATRIBUTES 0x0e4c
#define MPC85XX_MC_CAPTURE_ADDRESS 0x0e50
+#define MPC85XX_MC_CAPTURE_EXT_ADDRESS 0x0e54
#define MPC85XX_MC_ERR_SBE 0x0e58
#define DSC_MEM_EN 0x80000000
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 1acf57ba4c86..ca7831168298 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -34,7 +34,7 @@ static int probed;
/*
* Alter this version for the module when modifications are made
*/
-#define SBRIDGE_REVISION " Ver: 1.1.0 "
+#define SBRIDGE_REVISION " Ver: 1.1.1 "
#define EDAC_MOD_STR "sbridge_edac"
/*
@@ -254,7 +254,7 @@ static const u32 correrrthrsld[] = {
* sbridge structs
*/
-#define NUM_CHANNELS 4
+#define NUM_CHANNELS 8 /* 2MC per socket, four chan per MC */
#define MAX_DIMMS 3 /* Max DIMMS per channel */
#define CHANNEL_UNSPECIFIED 0xf /* Intel IA32 SDM 15-14 */
@@ -393,6 +393,8 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = {
#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS 0x0e79
#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0 0x0e6a
#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1 0x0e6b
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD2 0x0e6c
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD3 0x0e6d
static const struct pci_id_descr pci_dev_descr_ibridge[] = {
/* Processor Home Agent */
@@ -421,6 +423,8 @@ static const struct pci_id_descr pci_dev_descr_ibridge[] = {
#endif
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD2, 1) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD3, 1) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1) },
@@ -504,17 +508,35 @@ static const struct pci_id_table pci_dev_descr_haswell_table[] = {
* DE processor:
* - 1 IMC
* - 2 DDR3 channels, 2 DPC per channel
+ * EP processor:
+ * - 1 or 2 IMC
+ * - 4 DDR4 channels, 3 DPC per channel
+ * EP 4S processor:
+ * - 2 IMC
+ * - 4 DDR4 channels, 3 DPC per channel
+ * EX processor:
+ * - 2 IMC
+ * - each IMC interfaces with a SMI 2 channel
+ * - each SMI channel interfaces with a scalable memory buffer
+ * - each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC
*/
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_VTD_MISC 0x6f28
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0 0x6fa0
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1 0x6f60
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA 0x6fa8
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_THERMAL 0x6f71
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TA 0x6f68
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_THERMAL 0x6f79
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0 0x6ffc
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1 0x6ffd
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0 0x6faa
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1 0x6fab
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2 0x6fac
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3 0x6fad
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD0 0x6f6a
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD1 0x6f6b
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD2 0x6f6c
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD3 0x6f6d
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0 0x6faf
static const struct pci_id_descr pci_dev_descr_broadwell[] = {
@@ -524,13 +546,23 @@ static const struct pci_id_descr pci_dev_descr_broadwell[] = {
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0, 0) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1, 0) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1, 1) },
+
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA, 0) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_THERMAL, 0) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0, 0) },
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1, 0) },
- { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2, 0) },
- { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3, 0) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2, 1) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3, 1) },
+
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0, 1) },
+
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TA, 1) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_THERMAL, 1) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD0, 1) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD1, 1) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD2, 1) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD3, 1) },
};
static const struct pci_id_table pci_dev_descr_broadwell_table[] = {
@@ -559,7 +591,7 @@ static inline int numrank(enum type type, u32 mtr)
int ranks = (1 << RANK_CNT_BITS(mtr));
int max = 4;
- if (type == HASWELL)
+ if (type == HASWELL || type == BROADWELL)
max = 8;
if (ranks > max) {
@@ -909,6 +941,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)
for (i = 0; i < NUM_CHANNELS; i++) {
u32 mtr;
+ if (!pvt->pci_tad[i])
+ continue;
for (j = 0; j < ARRAY_SIZE(mtr_regs); j++) {
dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers,
i, j, 0);
@@ -925,8 +959,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)
size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
npages = MiB_TO_PAGES(size);
- edac_dbg(0, "mc#%d: channel %d, dimm %d, %Ld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
- pvt->sbridge_dev->mc, i, j,
+ edac_dbg(0, "mc#%d: ha %d channel %d, dimm %d, %lld Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
+ pvt->sbridge_dev->mc, i/4, i%4, j,
size, npages,
banks, ranks, rows, cols);
@@ -946,8 +980,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)
dimm->mtype = mtype;
dimm->edac_mode = mode;
snprintf(dimm->label, sizeof(dimm->label),
- "CPU_SrcID#%u_Channel#%u_DIMM#%u",
- pvt->sbridge_dev->source_id, i, j);
+ "CPU_SrcID#%u_Ha#%u_Chan#%u_DIMM#%u",
+ pvt->sbridge_dev->source_id, i/4, i%4, j);
}
}
}
@@ -1128,7 +1162,7 @@ static struct mem_ctl_info *get_mci_for_node_id(u8 node_id)
static int get_memory_error_data(struct mem_ctl_info *mci,
u64 addr,
- u8 *socket,
+ u8 *socket, u8 *ha,
long *channel_mask,
u8 *rank,
char **area_type, char *msg)
@@ -1141,7 +1175,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
int interleave_mode, shiftup = 0;
unsigned sad_interleave[pvt->info.max_interleave];
u32 reg, dram_rule;
- u8 ch_way, sck_way, pkg, sad_ha = 0;
+ u8 ch_way, sck_way, pkg, sad_ha = 0, ch_add = 0;
u32 tad_offset;
u32 rir_way;
u32 mb, gb;
@@ -1242,9 +1276,9 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
bits = GET_BITFIELD(addr, 7, 8) << 1;
bits |= GET_BITFIELD(addr, 9, 9);
} else
- bits = GET_BITFIELD(addr, 7, 9);
+ bits = GET_BITFIELD(addr, 6, 8);
- if (interleave_mode) {
+ if (interleave_mode == 0) {
/* interleave mode will XOR {8,7,6} with {18,17,16} */
idx = GET_BITFIELD(addr, 16, 18);
idx ^= bits;
@@ -1254,6 +1288,8 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx);
*socket = sad_pkg_socket(pkg);
sad_ha = sad_pkg_ha(pkg);
+ if (sad_ha)
+ ch_add = 4;
if (a7mode) {
/* MCChanShiftUpEnable */
@@ -1270,10 +1306,14 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx);
*socket = sad_pkg_socket(pkg);
sad_ha = sad_pkg_ha(pkg);
+ if (sad_ha)
+ ch_add = 4;
edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %d\n",
idx, *socket, sad_ha);
}
+ *ha = sad_ha;
+
/*
* Move to the proper node structure, in order to access the
* right PCI registers
@@ -1346,7 +1386,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
}
*channel_mask = 1 << base_ch;
- pci_read_config_dword(pvt->pci_tad[base_ch],
+ pci_read_config_dword(pvt->pci_tad[ch_add + base_ch],
tad_ch_nilv_offset[n_tads],
&tad_offset);
@@ -1405,7 +1445,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
* Step 3) Decode rank
*/
for (n_rir = 0; n_rir < MAX_RIR_RANGES; n_rir++) {
- pci_read_config_dword(pvt->pci_tad[base_ch],
+ pci_read_config_dword(pvt->pci_tad[ch_add + base_ch],
rir_way_limit[n_rir],
&reg);
@@ -1435,7 +1475,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
idx = (ch_addr >> 13); /* FIXME: Datasheet says to shift by 15 */
idx %= 1 << rir_way;
- pci_read_config_dword(pvt->pci_tad[base_ch],
+ pci_read_config_dword(pvt->pci_tad[ch_add + base_ch],
rir_offset[n_rir][idx],
&reg);
*rank = RIR_RNK_TGT(reg);
@@ -1681,16 +1721,9 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
struct sbridge_dev *sbridge_dev)
{
struct sbridge_pvt *pvt = mci->pvt_info;
- struct pci_dev *pdev, *tmp;
+ struct pci_dev *pdev;
+ u8 saw_chan_mask = 0;
int i;
- bool mode_2ha = false;
-
- tmp = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, NULL);
- if (tmp) {
- mode_2ha = true;
- pci_dev_put(tmp);
- }
for (i = 0; i < sbridge_dev->n_devs; i++) {
pdev = sbridge_dev->pdev[i];
@@ -1706,26 +1739,21 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS:
pvt->pci_ras = pdev;
break;
- case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2:
- case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3:
- /* if we have 2 HAs active, channels 2 and 3
- * are in other device */
- if (mode_2ha)
- break;
- /* fall through */
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0:
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1:
+ case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2:
+ case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3:
{
int id = pdev->device - PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0;
pvt->pci_tad[id] = pdev;
+ saw_chan_mask |= 1 << id;
}
break;
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0:
pvt->pci_ddrio = pdev;
break;
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0:
- if (!mode_2ha)
- pvt->pci_ddrio = pdev;
+ pvt->pci_ddrio = pdev;
break;
case PCI_DEVICE_ID_INTEL_IBRIDGE_SAD:
pvt->pci_sad0 = pdev;
@@ -1741,13 +1769,12 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
break;
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0:
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1:
+ case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD2:
+ case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD3:
{
- int id = pdev->device - PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0 + 2;
-
- /* we shouldn't have this device if we have just one
- * HA present */
- WARN_ON(!mode_2ha);
+ int id = pdev->device - PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0 + 4;
pvt->pci_tad[id] = pdev;
+ saw_chan_mask |= 1 << id;
}
break;
default:
@@ -1766,10 +1793,10 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
!pvt->pci_ta)
goto enodev;
- for (i = 0; i < NUM_CHANNELS; i++) {
- if (!pvt->pci_tad[i])
- goto enodev;
- }
+ if (saw_chan_mask != 0x0f && /* -EN */
+ saw_chan_mask != 0x33 && /* -EP */
+ saw_chan_mask != 0xff) /* -EX */
+ goto enodev;
return 0;
enodev:
@@ -1787,16 +1814,9 @@ static int haswell_mci_bind_devs(struct mem_ctl_info *mci,
struct sbridge_dev *sbridge_dev)
{
struct sbridge_pvt *pvt = mci->pvt_info;
- struct pci_dev *pdev, *tmp;
+ struct pci_dev *pdev;
+ u8 saw_chan_mask = 0;
int i;
- bool mode_2ha = false;
-
- tmp = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1, NULL);
- if (tmp) {
- mode_2ha = true;
- pci_dev_put(tmp);
- }
/* there's only one device per system; not tied to any bus */
if (pvt->info.pci_vtd == NULL)
@@ -1827,18 +1847,26 @@ static int haswell_mci_bind_devs(struct mem_ctl_info *mci,
pvt->pci_ras = pdev;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0:
- pvt->pci_tad[0] = pdev;
- break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1:
- pvt->pci_tad[1] = pdev;
- break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2:
- if (!mode_2ha)
- pvt->pci_tad[2] = pdev;
- break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3:
- if (!mode_2ha)
- pvt->pci_tad[3] = pdev;
+ {
+ int id = pdev->device - PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0;
+
+ pvt->pci_tad[id] = pdev;
+ saw_chan_mask |= 1 << id;
+ }
+ break;
+ case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0:
+ case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1:
+ case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2:
+ case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3:
+ {
+ int id = pdev->device - PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0 + 4;
+
+ pvt->pci_tad[id] = pdev;
+ saw_chan_mask |= 1 << id;
+ }
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0:
pvt->pci_ddrio = pdev;
@@ -1849,14 +1877,6 @@ static int haswell_mci_bind_devs(struct mem_ctl_info *mci,
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA:
pvt->pci_ha1_ta = pdev;
break;
- case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0:
- if (mode_2ha)
- pvt->pci_tad[2] = pdev;
- break;
- case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1:
- if (mode_2ha)
- pvt->pci_tad[3] = pdev;
- break;
default:
break;
}
@@ -1872,10 +1892,10 @@ static int haswell_mci_bind_devs(struct mem_ctl_info *mci,
!pvt->pci_ras || !pvt->pci_ta || !pvt->info.pci_vtd)
goto enodev;
- for (i = 0; i < NUM_CHANNELS; i++) {
- if (!pvt->pci_tad[i])
- goto enodev;
- }
+ if (saw_chan_mask != 0x0f && /* -EN */
+ saw_chan_mask != 0x33 && /* -EP */
+ saw_chan_mask != 0xff) /* -EX */
+ goto enodev;
return 0;
enodev:
@@ -1888,6 +1908,7 @@ static int broadwell_mci_bind_devs(struct mem_ctl_info *mci,
{
struct sbridge_pvt *pvt = mci->pvt_info;
struct pci_dev *pdev;
+ u8 saw_chan_mask = 0;
int i;
/* there's only one device per system; not tied to any bus */
@@ -1919,20 +1940,34 @@ static int broadwell_mci_bind_devs(struct mem_ctl_info *mci,
pvt->pci_ras = pdev;
break;
case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0:
- pvt->pci_tad[0] = pdev;
- break;
case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1:
- pvt->pci_tad[1] = pdev;
- break;
case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2:
- pvt->pci_tad[2] = pdev;
- break;
case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3:
- pvt->pci_tad[3] = pdev;
+ {
+ int id = pdev->device - PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0;
+ pvt->pci_tad[id] = pdev;
+ saw_chan_mask |= 1 << id;
+ }
+ break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD0:
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD1:
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD2:
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD3:
+ {
+ int id = pdev->device - PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD0 + 4;
+ pvt->pci_tad[id] = pdev;
+ saw_chan_mask |= 1 << id;
+ }
break;
case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0:
pvt->pci_ddrio = pdev;
break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1:
+ pvt->pci_ha1 = pdev;
+ break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TA:
+ pvt->pci_ha1_ta = pdev;
+ break;
default:
break;
}
@@ -1948,10 +1983,10 @@ static int broadwell_mci_bind_devs(struct mem_ctl_info *mci,
!pvt->pci_ras || !pvt->pci_ta || !pvt->info.pci_vtd)
goto enodev;
- for (i = 0; i < NUM_CHANNELS; i++) {
- if (!pvt->pci_tad[i])
- goto enodev;
- }
+ if (saw_chan_mask != 0x0f && /* -EN */
+ saw_chan_mask != 0x33 && /* -EP */
+ saw_chan_mask != 0xff) /* -EX */
+ goto enodev;
return 0;
enodev:
@@ -1986,11 +2021,11 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
u32 channel = GET_BITFIELD(m->status, 0, 3);
u32 optypenum = GET_BITFIELD(m->status, 4, 6);
long channel_mask, first_channel;
- u8 rank, socket;
+ u8 rank, socket, ha;
int rc, dimm;
char *area_type = NULL;
- if (pvt->info.type == IVY_BRIDGE)
+ if (pvt->info.type != SANDY_BRIDGE)
recoverable = true;
else
recoverable = GET_BITFIELD(m->status, 56, 56);
@@ -2048,7 +2083,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
if (!GET_BITFIELD(m->status, 58, 58))
return;
- rc = get_memory_error_data(mci, m->addr, &socket,
+ rc = get_memory_error_data(mci, m->addr, &socket, &ha,
&channel_mask, &rank, &area_type, msg);
if (rc < 0)
goto err_parsing;
@@ -2080,12 +2115,12 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
channel = first_channel;
snprintf(msg, sizeof(msg),
- "%s%s area:%s err_code:%04x:%04x socket:%d channel_mask:%ld rank:%d",
+ "%s%s area:%s err_code:%04x:%04x socket:%d ha:%d channel_mask:%ld rank:%d",
overflow ? " OVERFLOW" : "",
(uncorrected_error && recoverable) ? " recoverable" : "",
area_type,
mscod, errcode,
- socket,
+ socket, ha,
channel_mask,
rank);
@@ -2099,7 +2134,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
/* Call the helper to output message */
edac_mc_handle_error(tp_event, mci, core_err_cnt,
m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
- channel, dimm, -1,
+ 4*ha+channel, dimm, -1,
optype, msg);
return;
err_parsing:
diff --git a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c
new file mode 100644
index 000000000000..14636e4b6a08
--- /dev/null
+++ b/drivers/edac/xgene_edac.c
@@ -0,0 +1,1215 @@
+/*
+ * APM X-Gene SoC EDAC (error detection and correction)
+ *
+ * Copyright (c) 2015, Applied Micro Circuits Corporation
+ * Author: Feng Kan <fkan@apm.com>
+ * Loc Ho <lho@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/ctype.h>
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+#include "edac_core.h"
+
+#define EDAC_MOD_STR "xgene_edac"
+
+/* Global error configuration status registers (CSR) */
+#define PCPHPERRINTSTS 0x0000
+#define PCPHPERRINTMSK 0x0004
+#define MCU_CTL_ERR_MASK BIT(12)
+#define IOB_PA_ERR_MASK BIT(11)
+#define IOB_BA_ERR_MASK BIT(10)
+#define IOB_XGIC_ERR_MASK BIT(9)
+#define IOB_RB_ERR_MASK BIT(8)
+#define L3C_UNCORR_ERR_MASK BIT(5)
+#define MCU_UNCORR_ERR_MASK BIT(4)
+#define PMD3_MERR_MASK BIT(3)
+#define PMD2_MERR_MASK BIT(2)
+#define PMD1_MERR_MASK BIT(1)
+#define PMD0_MERR_MASK BIT(0)
+#define PCPLPERRINTSTS 0x0008
+#define PCPLPERRINTMSK 0x000C
+#define CSW_SWITCH_TRACE_ERR_MASK BIT(2)
+#define L3C_CORR_ERR_MASK BIT(1)
+#define MCU_CORR_ERR_MASK BIT(0)
+#define MEMERRINTSTS 0x0010
+#define MEMERRINTMSK 0x0014
+
+struct xgene_edac {
+ struct device *dev;
+ struct regmap *csw_map;
+ struct regmap *mcba_map;
+ struct regmap *mcbb_map;
+ struct regmap *efuse_map;
+ void __iomem *pcp_csr;
+ spinlock_t lock;
+ struct dentry *dfs;
+
+ struct list_head mcus;
+ struct list_head pmds;
+
+ struct mutex mc_lock;
+ int mc_active_mask;
+ int mc_registered_mask;
+};
+
+static void xgene_edac_pcp_rd(struct xgene_edac *edac, u32 reg, u32 *val)
+{
+ *val = readl(edac->pcp_csr + reg);
+}
+
+static void xgene_edac_pcp_clrbits(struct xgene_edac *edac, u32 reg,
+ u32 bits_mask)
+{
+ u32 val;
+
+ spin_lock(&edac->lock);
+ val = readl(edac->pcp_csr + reg);
+ val &= ~bits_mask;
+ writel(val, edac->pcp_csr + reg);
+ spin_unlock(&edac->lock);
+}
+
+static void xgene_edac_pcp_setbits(struct xgene_edac *edac, u32 reg,
+ u32 bits_mask)
+{
+ u32 val;
+
+ spin_lock(&edac->lock);
+ val = readl(edac->pcp_csr + reg);
+ val |= bits_mask;
+ writel(val, edac->pcp_csr + reg);
+ spin_unlock(&edac->lock);
+}
+
+/* Memory controller error CSR */
+#define MCU_MAX_RANK 8
+#define MCU_RANK_STRIDE 0x40
+
+#define MCUGECR 0x0110
+#define MCU_GECR_DEMANDUCINTREN_MASK BIT(0)
+#define MCU_GECR_BACKUCINTREN_MASK BIT(1)
+#define MCU_GECR_CINTREN_MASK BIT(2)
+#define MUC_GECR_MCUADDRERREN_MASK BIT(9)
+#define MCUGESR 0x0114
+#define MCU_GESR_ADDRNOMATCH_ERR_MASK BIT(7)
+#define MCU_GESR_ADDRMULTIMATCH_ERR_MASK BIT(6)
+#define MCU_GESR_PHYP_ERR_MASK BIT(3)
+#define MCUESRR0 0x0314
+#define MCU_ESRR_MULTUCERR_MASK BIT(3)
+#define MCU_ESRR_BACKUCERR_MASK BIT(2)
+#define MCU_ESRR_DEMANDUCERR_MASK BIT(1)
+#define MCU_ESRR_CERR_MASK BIT(0)
+#define MCUESRRA0 0x0318
+#define MCUEBLRR0 0x031c
+#define MCU_EBLRR_ERRBANK_RD(src) (((src) & 0x00000007) >> 0)
+#define MCUERCRR0 0x0320
+#define MCU_ERCRR_ERRROW_RD(src) (((src) & 0xFFFF0000) >> 16)
+#define MCU_ERCRR_ERRCOL_RD(src) ((src) & 0x00000FFF)
+#define MCUSBECNT0 0x0324
+#define MCU_SBECNT_COUNT(src) ((src) & 0xFFFF)
+
+#define CSW_CSWCR 0x0000
+#define CSW_CSWCR_DUALMCB_MASK BIT(0)
+
+#define MCBADDRMR 0x0000
+#define MCBADDRMR_MCU_INTLV_MODE_MASK BIT(3)
+#define MCBADDRMR_DUALMCU_MODE_MASK BIT(2)
+#define MCBADDRMR_MCB_INTLV_MODE_MASK BIT(1)
+#define MCBADDRMR_ADDRESS_MODE_MASK BIT(0)
+
+struct xgene_edac_mc_ctx {
+ struct list_head next;
+ char *name;
+ struct mem_ctl_info *mci;
+ struct xgene_edac *edac;
+ void __iomem *mcu_csr;
+ u32 mcu_id;
+};
+
+static ssize_t xgene_edac_mc_err_inject_write(struct file *file,
+ const char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct mem_ctl_info *mci = file->private_data;
+ struct xgene_edac_mc_ctx *ctx = mci->pvt_info;
+ int i;
+
+ for (i = 0; i < MCU_MAX_RANK; i++) {
+ writel(MCU_ESRR_MULTUCERR_MASK | MCU_ESRR_BACKUCERR_MASK |
+ MCU_ESRR_DEMANDUCERR_MASK | MCU_ESRR_CERR_MASK,
+ ctx->mcu_csr + MCUESRRA0 + i * MCU_RANK_STRIDE);
+ }
+ return count;
+}
+
+static const struct file_operations xgene_edac_mc_debug_inject_fops = {
+ .open = simple_open,
+ .write = xgene_edac_mc_err_inject_write,
+ .llseek = generic_file_llseek,
+};
+
+static void xgene_edac_mc_create_debugfs_node(struct mem_ctl_info *mci)
+{
+ if (!IS_ENABLED(CONFIG_EDAC_DEBUG))
+ return;
+#ifdef CONFIG_EDAC_DEBUG
+ if (!mci->debugfs)
+ return;
+ debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci,
+ &xgene_edac_mc_debug_inject_fops);
+#endif
+}
+
+static void xgene_edac_mc_check(struct mem_ctl_info *mci)
+{
+ struct xgene_edac_mc_ctx *ctx = mci->pvt_info;
+ unsigned int pcp_hp_stat;
+ unsigned int pcp_lp_stat;
+ u32 reg;
+ u32 rank;
+ u32 bank;
+ u32 count;
+ u32 col_row;
+
+ xgene_edac_pcp_rd(ctx->edac, PCPHPERRINTSTS, &pcp_hp_stat);
+ xgene_edac_pcp_rd(ctx->edac, PCPLPERRINTSTS, &pcp_lp_stat);
+ if (!((MCU_UNCORR_ERR_MASK & pcp_hp_stat) ||
+ (MCU_CTL_ERR_MASK & pcp_hp_stat) ||
+ (MCU_CORR_ERR_MASK & pcp_lp_stat)))
+ return;
+
+ for (rank = 0; rank < MCU_MAX_RANK; rank++) {
+ reg = readl(ctx->mcu_csr + MCUESRR0 + rank * MCU_RANK_STRIDE);
+
+ /* Detect uncorrectable memory error */
+ if (reg & (MCU_ESRR_DEMANDUCERR_MASK |
+ MCU_ESRR_BACKUCERR_MASK)) {
+ /* Detected uncorrectable memory error */
+ edac_mc_chipset_printk(mci, KERN_ERR, "X-Gene",
+ "MCU uncorrectable error at rank %d\n", rank);
+
+ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+ 1, 0, 0, 0, 0, 0, -1, mci->ctl_name, "");
+ }
+
+ /* Detect correctable memory error */
+ if (reg & MCU_ESRR_CERR_MASK) {
+ bank = readl(ctx->mcu_csr + MCUEBLRR0 +
+ rank * MCU_RANK_STRIDE);
+ col_row = readl(ctx->mcu_csr + MCUERCRR0 +
+ rank * MCU_RANK_STRIDE);
+ count = readl(ctx->mcu_csr + MCUSBECNT0 +
+ rank * MCU_RANK_STRIDE);
+ edac_mc_chipset_printk(mci, KERN_WARNING, "X-Gene",
+ "MCU correctable error at rank %d bank %d column %d row %d count %d\n",
+ rank, MCU_EBLRR_ERRBANK_RD(bank),
+ MCU_ERCRR_ERRCOL_RD(col_row),
+ MCU_ERCRR_ERRROW_RD(col_row),
+ MCU_SBECNT_COUNT(count));
+
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+ 1, 0, 0, 0, 0, 0, -1, mci->ctl_name, "");
+ }
+
+ /* Clear all error registers */
+ writel(0x0, ctx->mcu_csr + MCUEBLRR0 + rank * MCU_RANK_STRIDE);
+ writel(0x0, ctx->mcu_csr + MCUERCRR0 + rank * MCU_RANK_STRIDE);
+ writel(0x0, ctx->mcu_csr + MCUSBECNT0 +
+ rank * MCU_RANK_STRIDE);
+ writel(reg, ctx->mcu_csr + MCUESRR0 + rank * MCU_RANK_STRIDE);
+ }
+
+ /* Detect memory controller error */
+ reg = readl(ctx->mcu_csr + MCUGESR);
+ if (reg) {
+ if (reg & MCU_GESR_ADDRNOMATCH_ERR_MASK)
+ edac_mc_chipset_printk(mci, KERN_WARNING, "X-Gene",
+ "MCU address miss-match error\n");
+ if (reg & MCU_GESR_ADDRMULTIMATCH_ERR_MASK)
+ edac_mc_chipset_printk(mci, KERN_WARNING, "X-Gene",
+ "MCU address multi-match error\n");
+
+ writel(reg, ctx->mcu_csr + MCUGESR);
+ }
+}
+
+static void xgene_edac_mc_irq_ctl(struct mem_ctl_info *mci, bool enable)
+{
+ struct xgene_edac_mc_ctx *ctx = mci->pvt_info;
+ unsigned int val;
+
+ if (edac_op_state != EDAC_OPSTATE_INT)
+ return;
+
+ mutex_lock(&ctx->edac->mc_lock);
+
+ /*
+ * As there is only single bit for enable error and interrupt mask,
+ * we must only enable top level interrupt after all MCUs are
+ * registered. Otherwise, if there is an error and the corresponding
+ * MCU has not registered, the interrupt will never get cleared. To
+ * determine all MCU have registered, we will keep track of active
+ * MCUs and registered MCUs.
+ */
+ if (enable) {
+ /* Set registered MCU bit */
+ ctx->edac->mc_registered_mask |= 1 << ctx->mcu_id;
+
+ /* Enable interrupt after all active MCU registered */
+ if (ctx->edac->mc_registered_mask ==
+ ctx->edac->mc_active_mask) {
+ /* Enable memory controller top level interrupt */
+ xgene_edac_pcp_clrbits(ctx->edac, PCPHPERRINTMSK,
+ MCU_UNCORR_ERR_MASK |
+ MCU_CTL_ERR_MASK);
+ xgene_edac_pcp_clrbits(ctx->edac, PCPLPERRINTMSK,
+ MCU_CORR_ERR_MASK);
+ }
+
+ /* Enable MCU interrupt and error reporting */
+ val = readl(ctx->mcu_csr + MCUGECR);
+ val |= MCU_GECR_DEMANDUCINTREN_MASK |
+ MCU_GECR_BACKUCINTREN_MASK |
+ MCU_GECR_CINTREN_MASK |
+ MUC_GECR_MCUADDRERREN_MASK;
+ writel(val, ctx->mcu_csr + MCUGECR);
+ } else {
+ /* Disable MCU interrupt */
+ val = readl(ctx->mcu_csr + MCUGECR);
+ val &= ~(MCU_GECR_DEMANDUCINTREN_MASK |
+ MCU_GECR_BACKUCINTREN_MASK |
+ MCU_GECR_CINTREN_MASK |
+ MUC_GECR_MCUADDRERREN_MASK);
+ writel(val, ctx->mcu_csr + MCUGECR);
+
+ /* Disable memory controller top level interrupt */
+ xgene_edac_pcp_setbits(ctx->edac, PCPHPERRINTMSK,
+ MCU_UNCORR_ERR_MASK | MCU_CTL_ERR_MASK);
+ xgene_edac_pcp_setbits(ctx->edac, PCPLPERRINTMSK,
+ MCU_CORR_ERR_MASK);
+
+ /* Clear registered MCU bit */
+ ctx->edac->mc_registered_mask &= ~(1 << ctx->mcu_id);
+ }
+
+ mutex_unlock(&ctx->edac->mc_lock);
+}
+
+static int xgene_edac_mc_is_active(struct xgene_edac_mc_ctx *ctx, int mc_idx)
+{
+ unsigned int reg;
+ u32 mcu_mask;
+
+ if (regmap_read(ctx->edac->csw_map, CSW_CSWCR, &reg))
+ return 0;
+
+ if (reg & CSW_CSWCR_DUALMCB_MASK) {
+ /*
+ * Dual MCB active - Determine if all 4 active or just MCU0
+ * and MCU2 active
+ */
+ if (regmap_read(ctx->edac->mcbb_map, MCBADDRMR, &reg))
+ return 0;
+ mcu_mask = (reg & MCBADDRMR_DUALMCU_MODE_MASK) ? 0xF : 0x5;
+ } else {
+ /*
+ * Single MCB active - Determine if MCU0/MCU1 or just MCU0
+ * active
+ */
+ if (regmap_read(ctx->edac->mcba_map, MCBADDRMR, &reg))
+ return 0;
+ mcu_mask = (reg & MCBADDRMR_DUALMCU_MODE_MASK) ? 0x3 : 0x1;
+ }
+
+ /* Save active MC mask if hasn't set already */
+ if (!ctx->edac->mc_active_mask)
+ ctx->edac->mc_active_mask = mcu_mask;
+
+ return (mcu_mask & (1 << mc_idx)) ? 1 : 0;
+}
+
+static int xgene_edac_mc_add(struct xgene_edac *edac, struct device_node *np)
+{
+ struct mem_ctl_info *mci;
+ struct edac_mc_layer layers[2];
+ struct xgene_edac_mc_ctx tmp_ctx;
+ struct xgene_edac_mc_ctx *ctx;
+ struct resource res;
+ int rc;
+
+ memset(&tmp_ctx, 0, sizeof(tmp_ctx));
+ tmp_ctx.edac = edac;
+
+ if (!devres_open_group(edac->dev, xgene_edac_mc_add, GFP_KERNEL))
+ return -ENOMEM;
+
+ rc = of_address_to_resource(np, 0, &res);
+ if (rc < 0) {
+ dev_err(edac->dev, "no MCU resource address\n");
+ goto err_group;
+ }
+ tmp_ctx.mcu_csr = devm_ioremap_resource(edac->dev, &res);
+ if (IS_ERR(tmp_ctx.mcu_csr)) {
+ dev_err(edac->dev, "unable to map MCU resource\n");
+ rc = PTR_ERR(tmp_ctx.mcu_csr);
+ goto err_group;
+ }
+
+ /* Ignore non-active MCU */
+ if (of_property_read_u32(np, "memory-controller", &tmp_ctx.mcu_id)) {
+ dev_err(edac->dev, "no memory-controller property\n");
+ rc = -ENODEV;
+ goto err_group;
+ }
+ if (!xgene_edac_mc_is_active(&tmp_ctx, tmp_ctx.mcu_id)) {
+ rc = -ENODEV;
+ goto err_group;
+ }
+
+ layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+ layers[0].size = 4;
+ layers[0].is_virt_csrow = true;
+ layers[1].type = EDAC_MC_LAYER_CHANNEL;
+ layers[1].size = 2;
+ layers[1].is_virt_csrow = false;
+ mci = edac_mc_alloc(tmp_ctx.mcu_id, ARRAY_SIZE(layers), layers,
+ sizeof(*ctx));
+ if (!mci) {
+ rc = -ENOMEM;
+ goto err_group;
+ }
+
+ ctx = mci->pvt_info;
+ *ctx = tmp_ctx; /* Copy over resource value */
+ ctx->name = "xgene_edac_mc_err";
+ ctx->mci = mci;
+ mci->pdev = &mci->dev;
+ mci->ctl_name = ctx->name;
+ mci->dev_name = ctx->name;
+
+ mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 | MEM_FLAG_RDDR3 |
+ MEM_FLAG_DDR | MEM_FLAG_DDR2 | MEM_FLAG_DDR3;
+ mci->edac_ctl_cap = EDAC_FLAG_SECDED;
+ mci->edac_cap = EDAC_FLAG_SECDED;
+ mci->mod_name = EDAC_MOD_STR;
+ mci->mod_ver = "0.1";
+ mci->ctl_page_to_phys = NULL;
+ mci->scrub_cap = SCRUB_FLAG_HW_SRC;
+ mci->scrub_mode = SCRUB_HW_SRC;
+
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ mci->edac_check = xgene_edac_mc_check;
+
+ if (edac_mc_add_mc(mci)) {
+ dev_err(edac->dev, "edac_mc_add_mc failed\n");
+ rc = -EINVAL;
+ goto err_free;
+ }
+
+ xgene_edac_mc_create_debugfs_node(mci);
+
+ list_add(&ctx->next, &edac->mcus);
+
+ xgene_edac_mc_irq_ctl(mci, true);
+
+ devres_remove_group(edac->dev, xgene_edac_mc_add);
+
+ dev_info(edac->dev, "X-Gene EDAC MC registered\n");
+ return 0;
+
+err_free:
+ edac_mc_free(mci);
+err_group:
+ devres_release_group(edac->dev, xgene_edac_mc_add);
+ return rc;
+}
+
+static int xgene_edac_mc_remove(struct xgene_edac_mc_ctx *mcu)
+{
+ xgene_edac_mc_irq_ctl(mcu->mci, false);
+ edac_mc_del_mc(&mcu->mci->dev);
+ edac_mc_free(mcu->mci);
+ return 0;
+}
+
+/* CPU L1/L2 error CSR */
+#define MAX_CPU_PER_PMD 2
+#define CPU_CSR_STRIDE 0x00100000
+#define CPU_L2C_PAGE 0x000D0000
+#define CPU_MEMERR_L2C_PAGE 0x000E0000
+#define CPU_MEMERR_CPU_PAGE 0x000F0000
+
+#define MEMERR_CPU_ICFECR_PAGE_OFFSET 0x0000
+#define MEMERR_CPU_ICFESR_PAGE_OFFSET 0x0004
+#define MEMERR_CPU_ICFESR_ERRWAY_RD(src) (((src) & 0xFF000000) >> 24)
+#define MEMERR_CPU_ICFESR_ERRINDEX_RD(src) (((src) & 0x003F0000) >> 16)
+#define MEMERR_CPU_ICFESR_ERRINFO_RD(src) (((src) & 0x0000FF00) >> 8)
+#define MEMERR_CPU_ICFESR_ERRTYPE_RD(src) (((src) & 0x00000070) >> 4)
+#define MEMERR_CPU_ICFESR_MULTCERR_MASK BIT(2)
+#define MEMERR_CPU_ICFESR_CERR_MASK BIT(0)
+#define MEMERR_CPU_LSUESR_PAGE_OFFSET 0x000c
+#define MEMERR_CPU_LSUESR_ERRWAY_RD(src) (((src) & 0xFF000000) >> 24)
+#define MEMERR_CPU_LSUESR_ERRINDEX_RD(src) (((src) & 0x003F0000) >> 16)
+#define MEMERR_CPU_LSUESR_ERRINFO_RD(src) (((src) & 0x0000FF00) >> 8)
+#define MEMERR_CPU_LSUESR_ERRTYPE_RD(src) (((src) & 0x00000070) >> 4)
+#define MEMERR_CPU_LSUESR_MULTCERR_MASK BIT(2)
+#define MEMERR_CPU_LSUESR_CERR_MASK BIT(0)
+#define MEMERR_CPU_LSUECR_PAGE_OFFSET 0x0008
+#define MEMERR_CPU_MMUECR_PAGE_OFFSET 0x0010
+#define MEMERR_CPU_MMUESR_PAGE_OFFSET 0x0014
+#define MEMERR_CPU_MMUESR_ERRWAY_RD(src) (((src) & 0xFF000000) >> 24)
+#define MEMERR_CPU_MMUESR_ERRINDEX_RD(src) (((src) & 0x007F0000) >> 16)
+#define MEMERR_CPU_MMUESR_ERRINFO_RD(src) (((src) & 0x0000FF00) >> 8)
+#define MEMERR_CPU_MMUESR_ERRREQSTR_LSU_MASK BIT(7)
+#define MEMERR_CPU_MMUESR_ERRTYPE_RD(src) (((src) & 0x00000070) >> 4)
+#define MEMERR_CPU_MMUESR_MULTCERR_MASK BIT(2)
+#define MEMERR_CPU_MMUESR_CERR_MASK BIT(0)
+#define MEMERR_CPU_ICFESRA_PAGE_OFFSET 0x0804
+#define MEMERR_CPU_LSUESRA_PAGE_OFFSET 0x080c
+#define MEMERR_CPU_MMUESRA_PAGE_OFFSET 0x0814
+
+#define MEMERR_L2C_L2ECR_PAGE_OFFSET 0x0000
+#define MEMERR_L2C_L2ESR_PAGE_OFFSET 0x0004
+#define MEMERR_L2C_L2ESR_ERRSYN_RD(src) (((src) & 0xFF000000) >> 24)
+#define MEMERR_L2C_L2ESR_ERRWAY_RD(src) (((src) & 0x00FC0000) >> 18)
+#define MEMERR_L2C_L2ESR_ERRCPU_RD(src) (((src) & 0x00020000) >> 17)
+#define MEMERR_L2C_L2ESR_ERRGROUP_RD(src) (((src) & 0x0000E000) >> 13)
+#define MEMERR_L2C_L2ESR_ERRACTION_RD(src) (((src) & 0x00001C00) >> 10)
+#define MEMERR_L2C_L2ESR_ERRTYPE_RD(src) (((src) & 0x00000300) >> 8)
+#define MEMERR_L2C_L2ESR_MULTUCERR_MASK BIT(3)
+#define MEMERR_L2C_L2ESR_MULTICERR_MASK BIT(2)
+#define MEMERR_L2C_L2ESR_UCERR_MASK BIT(1)
+#define MEMERR_L2C_L2ESR_ERR_MASK BIT(0)
+#define MEMERR_L2C_L2EALR_PAGE_OFFSET 0x0008
+#define CPUX_L2C_L2RTOCR_PAGE_OFFSET 0x0010
+#define MEMERR_L2C_L2EAHR_PAGE_OFFSET 0x000c
+#define CPUX_L2C_L2RTOSR_PAGE_OFFSET 0x0014
+#define MEMERR_L2C_L2RTOSR_MULTERR_MASK BIT(1)
+#define MEMERR_L2C_L2RTOSR_ERR_MASK BIT(0)
+#define CPUX_L2C_L2RTOALR_PAGE_OFFSET 0x0018
+#define CPUX_L2C_L2RTOAHR_PAGE_OFFSET 0x001c
+#define MEMERR_L2C_L2ESRA_PAGE_OFFSET 0x0804
+
+/*
+ * Processor Module Domain (PMD) context - Context for a pair of processsors.
+ * Each PMD consists of 2 CPUs and a shared L2 cache. Each CPU consists of
+ * its own L1 cache.
+ */
+struct xgene_edac_pmd_ctx {
+ struct list_head next;
+ struct device ddev;
+ char *name;
+ struct xgene_edac *edac;
+ struct edac_device_ctl_info *edac_dev;
+ void __iomem *pmd_csr;
+ u32 pmd;
+ int version;
+};
+
+static void xgene_edac_pmd_l1_check(struct edac_device_ctl_info *edac_dev,
+ int cpu_idx)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ void __iomem *pg_f;
+ u32 val;
+
+ pg_f = ctx->pmd_csr + cpu_idx * CPU_CSR_STRIDE + CPU_MEMERR_CPU_PAGE;
+
+ val = readl(pg_f + MEMERR_CPU_ICFESR_PAGE_OFFSET);
+ if (val) {
+ dev_err(edac_dev->dev,
+ "CPU%d L1 memory error ICF 0x%08X Way 0x%02X Index 0x%02X Info 0x%02X\n",
+ ctx->pmd * MAX_CPU_PER_PMD + cpu_idx, val,
+ MEMERR_CPU_ICFESR_ERRWAY_RD(val),
+ MEMERR_CPU_ICFESR_ERRINDEX_RD(val),
+ MEMERR_CPU_ICFESR_ERRINFO_RD(val));
+ if (val & MEMERR_CPU_ICFESR_CERR_MASK)
+ dev_err(edac_dev->dev,
+ "One or more correctable error\n");
+ if (val & MEMERR_CPU_ICFESR_MULTCERR_MASK)
+ dev_err(edac_dev->dev, "Multiple correctable error\n");
+ switch (MEMERR_CPU_ICFESR_ERRTYPE_RD(val)) {
+ case 1:
+ dev_err(edac_dev->dev, "L1 TLB multiple hit\n");
+ break;
+ case 2:
+ dev_err(edac_dev->dev, "Way select multiple hit\n");
+ break;
+ case 3:
+ dev_err(edac_dev->dev, "Physical tag parity error\n");
+ break;
+ case 4:
+ case 5:
+ dev_err(edac_dev->dev, "L1 data parity error\n");
+ break;
+ case 6:
+ dev_err(edac_dev->dev, "L1 pre-decode parity error\n");
+ break;
+ }
+
+ /* Clear any HW errors */
+ writel(val, pg_f + MEMERR_CPU_ICFESR_PAGE_OFFSET);
+
+ if (val & (MEMERR_CPU_ICFESR_CERR_MASK |
+ MEMERR_CPU_ICFESR_MULTCERR_MASK))
+ edac_device_handle_ce(edac_dev, 0, 0,
+ edac_dev->ctl_name);
+ }
+
+ val = readl(pg_f + MEMERR_CPU_LSUESR_PAGE_OFFSET);
+ if (val) {
+ dev_err(edac_dev->dev,
+ "CPU%d memory error LSU 0x%08X Way 0x%02X Index 0x%02X Info 0x%02X\n",
+ ctx->pmd * MAX_CPU_PER_PMD + cpu_idx, val,
+ MEMERR_CPU_LSUESR_ERRWAY_RD(val),
+ MEMERR_CPU_LSUESR_ERRINDEX_RD(val),
+ MEMERR_CPU_LSUESR_ERRINFO_RD(val));
+ if (val & MEMERR_CPU_LSUESR_CERR_MASK)
+ dev_err(edac_dev->dev,
+ "One or more correctable error\n");
+ if (val & MEMERR_CPU_LSUESR_MULTCERR_MASK)
+ dev_err(edac_dev->dev, "Multiple correctable error\n");
+ switch (MEMERR_CPU_LSUESR_ERRTYPE_RD(val)) {
+ case 0:
+ dev_err(edac_dev->dev, "Load tag error\n");
+ break;
+ case 1:
+ dev_err(edac_dev->dev, "Load data error\n");
+ break;
+ case 2:
+ dev_err(edac_dev->dev, "WSL multihit error\n");
+ break;
+ case 3:
+ dev_err(edac_dev->dev, "Store tag error\n");
+ break;
+ case 4:
+ dev_err(edac_dev->dev,
+ "DTB multihit from load pipeline error\n");
+ break;
+ case 5:
+ dev_err(edac_dev->dev,
+ "DTB multihit from store pipeline error\n");
+ break;
+ }
+
+ /* Clear any HW errors */
+ writel(val, pg_f + MEMERR_CPU_LSUESR_PAGE_OFFSET);
+
+ if (val & (MEMERR_CPU_LSUESR_CERR_MASK |
+ MEMERR_CPU_LSUESR_MULTCERR_MASK))
+ edac_device_handle_ce(edac_dev, 0, 0,
+ edac_dev->ctl_name);
+ }
+
+ val = readl(pg_f + MEMERR_CPU_MMUESR_PAGE_OFFSET);
+ if (val) {
+ dev_err(edac_dev->dev,
+ "CPU%d memory error MMU 0x%08X Way 0x%02X Index 0x%02X Info 0x%02X %s\n",
+ ctx->pmd * MAX_CPU_PER_PMD + cpu_idx, val,
+ MEMERR_CPU_MMUESR_ERRWAY_RD(val),
+ MEMERR_CPU_MMUESR_ERRINDEX_RD(val),
+ MEMERR_CPU_MMUESR_ERRINFO_RD(val),
+ val & MEMERR_CPU_MMUESR_ERRREQSTR_LSU_MASK ? "LSU" :
+ "ICF");
+ if (val & MEMERR_CPU_MMUESR_CERR_MASK)
+ dev_err(edac_dev->dev,
+ "One or more correctable error\n");
+ if (val & MEMERR_CPU_MMUESR_MULTCERR_MASK)
+ dev_err(edac_dev->dev, "Multiple correctable error\n");
+ switch (MEMERR_CPU_MMUESR_ERRTYPE_RD(val)) {
+ case 0:
+ dev_err(edac_dev->dev, "Stage 1 UTB hit error\n");
+ break;
+ case 1:
+ dev_err(edac_dev->dev, "Stage 1 UTB miss error\n");
+ break;
+ case 2:
+ dev_err(edac_dev->dev, "Stage 1 UTB allocate error\n");
+ break;
+ case 3:
+ dev_err(edac_dev->dev,
+ "TMO operation single bank error\n");
+ break;
+ case 4:
+ dev_err(edac_dev->dev, "Stage 2 UTB error\n");
+ break;
+ case 5:
+ dev_err(edac_dev->dev, "Stage 2 UTB miss error\n");
+ break;
+ case 6:
+ dev_err(edac_dev->dev, "Stage 2 UTB allocate error\n");
+ break;
+ case 7:
+ dev_err(edac_dev->dev,
+ "TMO operation multiple bank error\n");
+ break;
+ }
+
+ /* Clear any HW errors */
+ writel(val, pg_f + MEMERR_CPU_MMUESR_PAGE_OFFSET);
+
+ edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
+ }
+}
+
+static void xgene_edac_pmd_l2_check(struct edac_device_ctl_info *edac_dev)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ void __iomem *pg_d;
+ void __iomem *pg_e;
+ u32 val_hi;
+ u32 val_lo;
+ u32 val;
+
+ /* Check L2 */
+ pg_e = ctx->pmd_csr + CPU_MEMERR_L2C_PAGE;
+ val = readl(pg_e + MEMERR_L2C_L2ESR_PAGE_OFFSET);
+ if (val) {
+ val_lo = readl(pg_e + MEMERR_L2C_L2EALR_PAGE_OFFSET);
+ val_hi = readl(pg_e + MEMERR_L2C_L2EAHR_PAGE_OFFSET);
+ dev_err(edac_dev->dev,
+ "PMD%d memory error L2C L2ESR 0x%08X @ 0x%08X.%08X\n",
+ ctx->pmd, val, val_hi, val_lo);
+ dev_err(edac_dev->dev,
+ "ErrSyndrome 0x%02X ErrWay 0x%02X ErrCpu %d ErrGroup 0x%02X ErrAction 0x%02X\n",
+ MEMERR_L2C_L2ESR_ERRSYN_RD(val),
+ MEMERR_L2C_L2ESR_ERRWAY_RD(val),
+ MEMERR_L2C_L2ESR_ERRCPU_RD(val),
+ MEMERR_L2C_L2ESR_ERRGROUP_RD(val),
+ MEMERR_L2C_L2ESR_ERRACTION_RD(val));
+
+ if (val & MEMERR_L2C_L2ESR_ERR_MASK)
+ dev_err(edac_dev->dev,
+ "One or more correctable error\n");
+ if (val & MEMERR_L2C_L2ESR_MULTICERR_MASK)
+ dev_err(edac_dev->dev, "Multiple correctable error\n");
+ if (val & MEMERR_L2C_L2ESR_UCERR_MASK)
+ dev_err(edac_dev->dev,
+ "One or more uncorrectable error\n");
+ if (val & MEMERR_L2C_L2ESR_MULTUCERR_MASK)
+ dev_err(edac_dev->dev,
+ "Multiple uncorrectable error\n");
+
+ switch (MEMERR_L2C_L2ESR_ERRTYPE_RD(val)) {
+ case 0:
+ dev_err(edac_dev->dev, "Outbound SDB parity error\n");
+ break;
+ case 1:
+ dev_err(edac_dev->dev, "Inbound SDB parity error\n");
+ break;
+ case 2:
+ dev_err(edac_dev->dev, "Tag ECC error\n");
+ break;
+ case 3:
+ dev_err(edac_dev->dev, "Data ECC error\n");
+ break;
+ }
+
+ /* Clear any HW errors */
+ writel(val, pg_e + MEMERR_L2C_L2ESR_PAGE_OFFSET);
+
+ if (val & (MEMERR_L2C_L2ESR_ERR_MASK |
+ MEMERR_L2C_L2ESR_MULTICERR_MASK))
+ edac_device_handle_ce(edac_dev, 0, 0,
+ edac_dev->ctl_name);
+ if (val & (MEMERR_L2C_L2ESR_UCERR_MASK |
+ MEMERR_L2C_L2ESR_MULTUCERR_MASK))
+ edac_device_handle_ue(edac_dev, 0, 0,
+ edac_dev->ctl_name);
+ }
+
+ /* Check if any memory request timed out on L2 cache */
+ pg_d = ctx->pmd_csr + CPU_L2C_PAGE;
+ val = readl(pg_d + CPUX_L2C_L2RTOSR_PAGE_OFFSET);
+ if (val) {
+ val_lo = readl(pg_d + CPUX_L2C_L2RTOALR_PAGE_OFFSET);
+ val_hi = readl(pg_d + CPUX_L2C_L2RTOAHR_PAGE_OFFSET);
+ dev_err(edac_dev->dev,
+ "PMD%d L2C error L2C RTOSR 0x%08X @ 0x%08X.%08X\n",
+ ctx->pmd, val, val_hi, val_lo);
+ writel(val, pg_d + CPUX_L2C_L2RTOSR_PAGE_OFFSET);
+ }
+}
+
+static void xgene_edac_pmd_check(struct edac_device_ctl_info *edac_dev)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ unsigned int pcp_hp_stat;
+ int i;
+
+ xgene_edac_pcp_rd(ctx->edac, PCPHPERRINTSTS, &pcp_hp_stat);
+ if (!((PMD0_MERR_MASK << ctx->pmd) & pcp_hp_stat))
+ return;
+
+ /* Check CPU L1 error */
+ for (i = 0; i < MAX_CPU_PER_PMD; i++)
+ xgene_edac_pmd_l1_check(edac_dev, i);
+
+ /* Check CPU L2 error */
+ xgene_edac_pmd_l2_check(edac_dev);
+}
+
+static void xgene_edac_pmd_cpu_hw_cfg(struct edac_device_ctl_info *edac_dev,
+ int cpu)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ void __iomem *pg_f = ctx->pmd_csr + cpu * CPU_CSR_STRIDE +
+ CPU_MEMERR_CPU_PAGE;
+
+ /*
+ * Enable CPU memory error:
+ * MEMERR_CPU_ICFESRA, MEMERR_CPU_LSUESRA, and MEMERR_CPU_MMUESRA
+ */
+ writel(0x00000301, pg_f + MEMERR_CPU_ICFECR_PAGE_OFFSET);
+ writel(0x00000301, pg_f + MEMERR_CPU_LSUECR_PAGE_OFFSET);
+ writel(0x00000101, pg_f + MEMERR_CPU_MMUECR_PAGE_OFFSET);
+}
+
+static void xgene_edac_pmd_hw_cfg(struct edac_device_ctl_info *edac_dev)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ void __iomem *pg_d = ctx->pmd_csr + CPU_L2C_PAGE;
+ void __iomem *pg_e = ctx->pmd_csr + CPU_MEMERR_L2C_PAGE;
+
+ /* Enable PMD memory error - MEMERR_L2C_L2ECR and L2C_L2RTOCR */
+ writel(0x00000703, pg_e + MEMERR_L2C_L2ECR_PAGE_OFFSET);
+ /* Configure L2C HW request time out feature if supported */
+ if (ctx->version > 1)
+ writel(0x00000119, pg_d + CPUX_L2C_L2RTOCR_PAGE_OFFSET);
+}
+
+static void xgene_edac_pmd_hw_ctl(struct edac_device_ctl_info *edac_dev,
+ bool enable)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ int i;
+
+ /* Enable PMD error interrupt */
+ if (edac_dev->op_state == OP_RUNNING_INTERRUPT) {
+ if (enable)
+ xgene_edac_pcp_clrbits(ctx->edac, PCPHPERRINTMSK,
+ PMD0_MERR_MASK << ctx->pmd);
+ else
+ xgene_edac_pcp_setbits(ctx->edac, PCPHPERRINTMSK,
+ PMD0_MERR_MASK << ctx->pmd);
+ }
+
+ if (enable) {
+ xgene_edac_pmd_hw_cfg(edac_dev);
+
+ /* Two CPUs per a PMD */
+ for (i = 0; i < MAX_CPU_PER_PMD; i++)
+ xgene_edac_pmd_cpu_hw_cfg(edac_dev, i);
+ }
+}
+
+static ssize_t xgene_edac_pmd_l1_inject_ctrl_write(struct file *file,
+ const char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct edac_device_ctl_info *edac_dev = file->private_data;
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ void __iomem *cpux_pg_f;
+ int i;
+
+ for (i = 0; i < MAX_CPU_PER_PMD; i++) {
+ cpux_pg_f = ctx->pmd_csr + i * CPU_CSR_STRIDE +
+ CPU_MEMERR_CPU_PAGE;
+
+ writel(MEMERR_CPU_ICFESR_MULTCERR_MASK |
+ MEMERR_CPU_ICFESR_CERR_MASK,
+ cpux_pg_f + MEMERR_CPU_ICFESRA_PAGE_OFFSET);
+ writel(MEMERR_CPU_LSUESR_MULTCERR_MASK |
+ MEMERR_CPU_LSUESR_CERR_MASK,
+ cpux_pg_f + MEMERR_CPU_LSUESRA_PAGE_OFFSET);
+ writel(MEMERR_CPU_MMUESR_MULTCERR_MASK |
+ MEMERR_CPU_MMUESR_CERR_MASK,
+ cpux_pg_f + MEMERR_CPU_MMUESRA_PAGE_OFFSET);
+ }
+ return count;
+}
+
+static ssize_t xgene_edac_pmd_l2_inject_ctrl_write(struct file *file,
+ const char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct edac_device_ctl_info *edac_dev = file->private_data;
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ void __iomem *pg_e = ctx->pmd_csr + CPU_MEMERR_L2C_PAGE;
+
+ writel(MEMERR_L2C_L2ESR_MULTUCERR_MASK |
+ MEMERR_L2C_L2ESR_MULTICERR_MASK |
+ MEMERR_L2C_L2ESR_UCERR_MASK |
+ MEMERR_L2C_L2ESR_ERR_MASK,
+ pg_e + MEMERR_L2C_L2ESRA_PAGE_OFFSET);
+ return count;
+}
+
+static const struct file_operations xgene_edac_pmd_debug_inject_fops[] = {
+ {
+ .open = simple_open,
+ .write = xgene_edac_pmd_l1_inject_ctrl_write,
+ .llseek = generic_file_llseek, },
+ {
+ .open = simple_open,
+ .write = xgene_edac_pmd_l2_inject_ctrl_write,
+ .llseek = generic_file_llseek, },
+ { }
+};
+
+static void xgene_edac_pmd_create_debugfs_nodes(
+ struct edac_device_ctl_info *edac_dev)
+{
+ struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
+ struct dentry *edac_debugfs;
+ char name[30];
+
+ if (!IS_ENABLED(CONFIG_EDAC_DEBUG))
+ return;
+
+ /*
+ * Todo: Switch to common EDAC debug file system for edac device
+ * when available.
+ */
+ if (!ctx->edac->dfs) {
+ ctx->edac->dfs = debugfs_create_dir(edac_dev->dev->kobj.name,
+ NULL);
+ if (!ctx->edac->dfs)
+ return;
+ }
+ sprintf(name, "PMD%d", ctx->pmd);
+ edac_debugfs = debugfs_create_dir(name, ctx->edac->dfs);
+ if (!edac_debugfs)
+ return;
+
+ debugfs_create_file("l1_inject_ctrl", S_IWUSR, edac_debugfs, edac_dev,
+ &xgene_edac_pmd_debug_inject_fops[0]);
+ debugfs_create_file("l2_inject_ctrl", S_IWUSR, edac_debugfs, edac_dev,
+ &xgene_edac_pmd_debug_inject_fops[1]);
+}
+
+static int xgene_edac_pmd_available(u32 efuse, int pmd)
+{
+ return (efuse & (1 << pmd)) ? 0 : 1;
+}
+
+static int xgene_edac_pmd_add(struct xgene_edac *edac, struct device_node *np,
+ int version)
+{
+ struct edac_device_ctl_info *edac_dev;
+ struct xgene_edac_pmd_ctx *ctx;
+ struct resource res;
+ char edac_name[10];
+ u32 pmd;
+ int rc;
+ u32 val;
+
+ if (!devres_open_group(edac->dev, xgene_edac_pmd_add, GFP_KERNEL))
+ return -ENOMEM;
+
+ /* Determine if this PMD is disabled */
+ if (of_property_read_u32(np, "pmd-controller", &pmd)) {
+ dev_err(edac->dev, "no pmd-controller property\n");
+ rc = -ENODEV;
+ goto err_group;
+ }
+ rc = regmap_read(edac->efuse_map, 0, &val);
+ if (rc)
+ goto err_group;
+ if (!xgene_edac_pmd_available(val, pmd)) {
+ rc = -ENODEV;
+ goto err_group;
+ }
+
+ sprintf(edac_name, "l2c%d", pmd);
+ edac_dev = edac_device_alloc_ctl_info(sizeof(*ctx),
+ edac_name, 1, "l2c", 1, 2, NULL,
+ 0, edac_device_alloc_index());
+ if (!edac_dev) {
+ rc = -ENOMEM;
+ goto err_group;
+ }
+
+ ctx = edac_dev->pvt_info;
+ ctx->name = "xgene_pmd_err";
+ ctx->pmd = pmd;
+ ctx->edac = edac;
+ ctx->edac_dev = edac_dev;
+ ctx->ddev = *edac->dev;
+ ctx->version = version;
+ edac_dev->dev = &ctx->ddev;
+ edac_dev->ctl_name = ctx->name;
+ edac_dev->dev_name = ctx->name;
+ edac_dev->mod_name = EDAC_MOD_STR;
+
+ rc = of_address_to_resource(np, 0, &res);
+ if (rc < 0) {
+ dev_err(edac->dev, "no PMD resource address\n");
+ goto err_free;
+ }
+ ctx->pmd_csr = devm_ioremap_resource(edac->dev, &res);
+ if (IS_ERR(ctx->pmd_csr)) {
+ dev_err(edac->dev,
+ "devm_ioremap_resource failed for PMD resource address\n");
+ rc = PTR_ERR(ctx->pmd_csr);
+ goto err_free;
+ }
+
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ edac_dev->edac_check = xgene_edac_pmd_check;
+
+ xgene_edac_pmd_create_debugfs_nodes(edac_dev);
+
+ rc = edac_device_add_device(edac_dev);
+ if (rc > 0) {
+ dev_err(edac->dev, "edac_device_add_device failed\n");
+ rc = -ENOMEM;
+ goto err_free;
+ }
+
+ if (edac_op_state == EDAC_OPSTATE_INT)
+ edac_dev->op_state = OP_RUNNING_INTERRUPT;
+
+ list_add(&ctx->next, &edac->pmds);
+
+ xgene_edac_pmd_hw_ctl(edac_dev, 1);
+
+ devres_remove_group(edac->dev, xgene_edac_pmd_add);
+
+ dev_info(edac->dev, "X-Gene EDAC PMD%d registered\n", ctx->pmd);
+ return 0;
+
+err_free:
+ edac_device_free_ctl_info(edac_dev);
+err_group:
+ devres_release_group(edac->dev, xgene_edac_pmd_add);
+ return rc;
+}
+
+static int xgene_edac_pmd_remove(struct xgene_edac_pmd_ctx *pmd)
+{
+ struct edac_device_ctl_info *edac_dev = pmd->edac_dev;
+
+ xgene_edac_pmd_hw_ctl(edac_dev, 0);
+ edac_device_del_device(edac_dev->dev);
+ edac_device_free_ctl_info(edac_dev);
+ return 0;
+}
+
+static irqreturn_t xgene_edac_isr(int irq, void *dev_id)
+{
+ struct xgene_edac *ctx = dev_id;
+ struct xgene_edac_pmd_ctx *pmd;
+ unsigned int pcp_hp_stat;
+ unsigned int pcp_lp_stat;
+
+ xgene_edac_pcp_rd(ctx, PCPHPERRINTSTS, &pcp_hp_stat);
+ xgene_edac_pcp_rd(ctx, PCPLPERRINTSTS, &pcp_lp_stat);
+ if ((MCU_UNCORR_ERR_MASK & pcp_hp_stat) ||
+ (MCU_CTL_ERR_MASK & pcp_hp_stat) ||
+ (MCU_CORR_ERR_MASK & pcp_lp_stat)) {
+ struct xgene_edac_mc_ctx *mcu;
+
+ list_for_each_entry(mcu, &ctx->mcus, next) {
+ xgene_edac_mc_check(mcu->mci);
+ }
+ }
+
+ list_for_each_entry(pmd, &ctx->pmds, next) {
+ if ((PMD0_MERR_MASK << pmd->pmd) & pcp_hp_stat)
+ xgene_edac_pmd_check(pmd->edac_dev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int xgene_edac_probe(struct platform_device *pdev)
+{
+ struct xgene_edac *edac;
+ struct device_node *child;
+ struct resource *res;
+ int rc;
+
+ edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL);
+ if (!edac)
+ return -ENOMEM;
+
+ edac->dev = &pdev->dev;
+ platform_set_drvdata(pdev, edac);
+ INIT_LIST_HEAD(&edac->mcus);
+ INIT_LIST_HEAD(&edac->pmds);
+ spin_lock_init(&edac->lock);
+ mutex_init(&edac->mc_lock);
+
+ edac->csw_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "regmap-csw");
+ if (IS_ERR(edac->csw_map)) {
+ dev_err(edac->dev, "unable to get syscon regmap csw\n");
+ rc = PTR_ERR(edac->csw_map);
+ goto out_err;
+ }
+
+ edac->mcba_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "regmap-mcba");
+ if (IS_ERR(edac->mcba_map)) {
+ dev_err(edac->dev, "unable to get syscon regmap mcba\n");
+ rc = PTR_ERR(edac->mcba_map);
+ goto out_err;
+ }
+
+ edac->mcbb_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "regmap-mcbb");
+ if (IS_ERR(edac->mcbb_map)) {
+ dev_err(edac->dev, "unable to get syscon regmap mcbb\n");
+ rc = PTR_ERR(edac->mcbb_map);
+ goto out_err;
+ }
+ edac->efuse_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "regmap-efuse");
+ if (IS_ERR(edac->efuse_map)) {
+ dev_err(edac->dev, "unable to get syscon regmap efuse\n");
+ rc = PTR_ERR(edac->efuse_map);
+ goto out_err;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ edac->pcp_csr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(edac->pcp_csr)) {
+ dev_err(&pdev->dev, "no PCP resource address\n");
+ rc = PTR_ERR(edac->pcp_csr);
+ goto out_err;
+ }
+
+ if (edac_op_state == EDAC_OPSTATE_INT) {
+ int irq;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No IRQ resource\n");
+ rc = -EINVAL;
+ goto out_err;
+ }
+ rc = devm_request_irq(&pdev->dev, irq,
+ xgene_edac_isr, IRQF_SHARED,
+ dev_name(&pdev->dev), edac);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "Could not request IRQ %d\n", irq);
+ goto out_err;
+ }
+ }
+ }
+
+ for_each_child_of_node(pdev->dev.of_node, child) {
+ if (!of_device_is_available(child))
+ continue;
+ if (of_device_is_compatible(child, "apm,xgene-edac-mc"))
+ xgene_edac_mc_add(edac, child);
+ if (of_device_is_compatible(child, "apm,xgene-edac-pmd"))
+ xgene_edac_pmd_add(edac, child, 1);
+ if (of_device_is_compatible(child, "apm,xgene-edac-pmd-v2"))
+ xgene_edac_pmd_add(edac, child, 2);
+ }
+
+ return 0;
+
+out_err:
+ return rc;
+}
+
+static int xgene_edac_remove(struct platform_device *pdev)
+{
+ struct xgene_edac *edac = dev_get_drvdata(&pdev->dev);
+ struct xgene_edac_mc_ctx *mcu;
+ struct xgene_edac_mc_ctx *temp_mcu;
+ struct xgene_edac_pmd_ctx *pmd;
+ struct xgene_edac_pmd_ctx *temp_pmd;
+
+ list_for_each_entry_safe(mcu, temp_mcu, &edac->mcus, next) {
+ xgene_edac_mc_remove(mcu);
+ }
+
+ list_for_each_entry_safe(pmd, temp_pmd, &edac->pmds, next) {
+ xgene_edac_pmd_remove(pmd);
+ }
+ return 0;
+}
+
+static const struct of_device_id xgene_edac_of_match[] = {
+ { .compatible = "apm,xgene-edac" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_edac_of_match);
+
+static struct platform_driver xgene_edac_driver = {
+ .probe = xgene_edac_probe,
+ .remove = xgene_edac_remove,
+ .driver = {
+ .name = "xgene-edac",
+ .owner = THIS_MODULE,
+ .of_match_table = xgene_edac_of_match,
+ },
+};
+
+static int __init xgene_edac_init(void)
+{
+ int rc;
+
+ /* Make sure error reporting method is sane */
+ switch (edac_op_state) {
+ case EDAC_OPSTATE_POLL:
+ case EDAC_OPSTATE_INT:
+ break;
+ default:
+ edac_op_state = EDAC_OPSTATE_INT;
+ break;
+ }
+
+ rc = platform_driver_register(&xgene_edac_driver);
+ if (rc) {
+ edac_printk(KERN_ERR, EDAC_MOD_STR,
+ "EDAC fails to register\n");
+ goto reg_failed;
+ }
+
+ return 0;
+
+reg_failed:
+ return rc;
+}
+module_init(xgene_edac_init);
+
+static void __exit xgene_edac_exit(void)
+{
+ platform_driver_unregister(&xgene_edac_driver);
+}
+module_exit(xgene_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Feng Kan <fkan@apm.com>");
+MODULE_DESCRIPTION("APM X-Gene EDAC driver");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state,
+ "EDAC error reporting state: 0=Poll, 2=Interrupt");
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index fdc0bf0543ce..0cebbf668886 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -28,15 +28,22 @@ config EXTCON_ARIZONA
with Wolfson Arizona devices. These are audio CODECs with
advanced audio accessory detection support.
+config EXTCON_AXP288
+ tristate "X-Power AXP288 EXTCON support"
+ depends on MFD_AXP20X && USB_PHY
+ help
+ Say Y here to enable support for USB peripheral detection
+ and USB MUX switching by X-Power AXP288 PMIC.
+
config EXTCON_GPIO
tristate "GPIO extcon support"
- depends on GPIOLIB
+ depends on GPIOLIB || COMPILE_TEST
help
Say Y here to enable GPIO based extcon support. Note that GPIO
extcon supports single state per extcon instance.
config EXTCON_MAX14577
- tristate "MAX14577/77836 EXTCON Support"
+ tristate "Maxim MAX14577/77836 EXTCON Support"
depends on MFD_MAX14577
select IRQ_DOMAIN
select REGMAP_I2C
@@ -46,7 +53,7 @@ config EXTCON_MAX14577
detector and switch.
config EXTCON_MAX77693
- tristate "MAX77693 EXTCON Support"
+ tristate "Maxim MAX77693 EXTCON Support"
depends on MFD_MAX77693 && INPUT
select IRQ_DOMAIN
select REGMAP_I2C
@@ -56,7 +63,7 @@ config EXTCON_MAX77693
detector and switch.
config EXTCON_MAX77843
- tristate "MAX77843 EXTCON Support"
+ tristate "Maxim MAX77843 EXTCON Support"
depends on MFD_MAX77843
select IRQ_DOMAIN
select REGMAP_I2C
@@ -66,7 +73,7 @@ config EXTCON_MAX77843
detector add switch.
config EXTCON_MAX8997
- tristate "MAX8997 EXTCON Support"
+ tristate "Maxim MAX8997 EXTCON Support"
depends on MFD_MAX8997 && IRQ_DOMAIN
help
If you say yes here you get support for the MUIC device of
@@ -81,7 +88,7 @@ config EXTCON_PALMAS
detection by palmas usb.
config EXTCON_RT8973A
- tristate "RT8973A EXTCON support"
+ tristate "Richtek RT8973A EXTCON support"
depends on I2C
select IRQ_DOMAIN
select REGMAP_I2C
@@ -93,7 +100,7 @@ config EXTCON_RT8973A
from abnormal high input voltage (up to 28V).
config EXTCON_SM5502
- tristate "SM5502 EXTCON support"
+ tristate "Silicon Mitus SM5502 EXTCON support"
depends on I2C
select IRQ_DOMAIN
select REGMAP_I2C
@@ -105,9 +112,9 @@ config EXTCON_SM5502
config EXTCON_USB_GPIO
tristate "USB GPIO extcon support"
- depends on GPIOLIB
+ depends on GPIOLIB || COMPILE_TEST
help
Say Y here to enable GPIO based USB cable detection extcon support.
Used typically if GPIO is used for USB ID pin detection.
-endif # MULTISTATE_SWITCH
+endif
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 9204114791a3..ba787d04295b 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -5,6 +5,7 @@
obj-$(CONFIG_EXTCON) += extcon.o
obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
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_MAX77693) += extcon-max77693.o
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
index 2bb82e55065a..7fc0ae1912f8 100644
--- a/drivers/extcon/extcon-adc-jack.c
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -29,7 +29,6 @@
* struct adc_jack_data - internal data for adc_jack device driver
* @edev: extcon device.
* @cable_names: list of supported cables.
- * @num_cables: size of cable_names.
* @adc_conditions: list of adc value conditions.
* @num_conditions: size of adc_conditions.
* @irq: irq number of attach/detach event (0 if not exist).
@@ -41,8 +40,7 @@
struct adc_jack_data {
struct extcon_dev *edev;
- const char **cable_names;
- int num_cables;
+ const unsigned int **cable_names;
struct adc_jack_cond *adc_conditions;
int num_conditions;
@@ -112,17 +110,6 @@ static int adc_jack_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to allocate extcon device\n");
return -ENOMEM;
}
- data->edev->name = pdata->name;
-
- /* Check the length of array and set num_cables */
- for (i = 0; data->edev->supported_cable[i]; i++)
- ;
- if (i == 0 || i > SUPPORTED_CABLE_MAX) {
- dev_err(&pdev->dev, "error: pdata->cable_names size = %d\n",
- i - 1);
- return -EINVAL;
- }
- data->num_cables = i;
if (!pdata->adc_conditions ||
!pdata->adc_conditions[0].state) {
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index a0ed35b336e4..ad87f263056f 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -32,13 +32,10 @@
#include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
+#include <dt-bindings/mfd/arizona.h>
#define ARIZONA_MAX_MICD_RANGE 8
-#define ARIZONA_ACCDET_MODE_MIC 0
-#define ARIZONA_ACCDET_MODE_HPL 1
-#define ARIZONA_ACCDET_MODE_HPR 2
-
#define ARIZONA_MICD_CLAMP_MODE_JDL 0x4
#define ARIZONA_MICD_CLAMP_MODE_JDH 0x5
#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
@@ -94,7 +91,7 @@ struct arizona_extcon_info {
bool detecting;
int jack_flips;
- int hpdet_ip;
+ int hpdet_ip_version;
struct extcon_dev *edev;
};
@@ -121,17 +118,12 @@ static const int arizona_micd_levels[] = {
1257,
};
-#define ARIZONA_CABLE_MECHANICAL 0
-#define ARIZONA_CABLE_MICROPHONE 1
-#define ARIZONA_CABLE_HEADPHONE 2
-#define ARIZONA_CABLE_LINEOUT 3
-
-static const char *arizona_cable[] = {
- "Mechanical",
- "Microphone",
- "Headphone",
- "Line-out",
- NULL,
+static const unsigned int arizona_cable[] = {
+ EXTCON_MECHANICAL,
+ EXTCON_MICROPHONE,
+ EXTCON_HEADPHONE,
+ EXTCON_LINE_OUT,
+ EXTCON_NONE,
};
static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
@@ -145,6 +137,7 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
switch (arizona->type) {
case WM5110:
+ case WM8280:
mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
ARIZONA_HP1L_SHRTI;
if (clamp)
@@ -380,7 +373,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
return ret;
}
- switch (info->hpdet_ip) {
+ switch (info->hpdet_ip_version) {
case 0:
if (!(val & ARIZONA_HP_DONE)) {
dev_err(arizona->dev, "HPDET did not complete: %x\n",
@@ -441,7 +434,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
default:
dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
- info->hpdet_ip);
+ info->hpdet_ip_version);
case 2:
if (!(val & ARIZONA_HP_DONE_B)) {
dev_err(arizona->dev, "HPDET did not complete: %x\n",
@@ -559,7 +552,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
struct arizona_extcon_info *info = data;
struct arizona *arizona = info->arizona;
int id_gpio = arizona->pdata.hpdet_id_gpio;
- int report = ARIZONA_CABLE_HEADPHONE;
+ unsigned int report = EXTCON_HEADPHONE;
int ret, reading;
bool mic = false;
@@ -573,7 +566,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
}
/* If the cable was removed while measuring ignore the result */
- ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL);
+ ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL);
if (ret < 0) {
dev_err(arizona->dev, "Failed to check cable state: %d\n",
ret);
@@ -604,9 +597,9 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
/* Report high impedence cables as line outputs */
if (reading >= 5000)
- report = ARIZONA_CABLE_LINEOUT;
+ report = EXTCON_LINE_OUT;
else
- report = ARIZONA_CABLE_HEADPHONE;
+ report = EXTCON_HEADPHONE;
ret = extcon_set_cable_state_(info->edev, report, true);
if (ret != 0)
@@ -670,9 +663,9 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
ret = regmap_update_bits(arizona->regmap,
ARIZONA_ACCESSORY_DETECT_MODE_1,
ARIZONA_ACCDET_MODE_MASK,
- ARIZONA_ACCDET_MODE_HPL);
+ arizona->pdata.hpdet_channel);
if (ret != 0) {
- dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
+ dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
goto err;
}
@@ -691,8 +684,7 @@ err:
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
/* Just report headphone */
- ret = extcon_set_cable_state_(info->edev,
- ARIZONA_CABLE_HEADPHONE, true);
+ ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
if (ret != 0)
dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
@@ -722,9 +714,9 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
ARIZONA_ACCESSORY_DETECT_MODE_1,
ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
info->micd_modes[0].src |
- ARIZONA_ACCDET_MODE_HPL);
+ arizona->pdata.hpdet_channel);
if (ret != 0) {
- dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret);
+ dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
goto err;
}
@@ -749,8 +741,7 @@ err:
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
/* Just report headphone */
- ret = extcon_set_cable_state_(info->edev,
- ARIZONA_CABLE_HEADPHONE, true);
+ ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
if (ret != 0)
dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
@@ -789,7 +780,7 @@ static void arizona_micd_detect(struct work_struct *work)
mutex_lock(&info->lock);
/* If the cable was removed while measuring ignore the result */
- ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL);
+ ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL);
if (ret < 0) {
dev_err(arizona->dev, "Failed to check cable state: %d\n",
ret);
@@ -838,8 +829,7 @@ static void arizona_micd_detect(struct work_struct *work)
arizona_identify_headphone(info);
ret = extcon_set_cable_state_(info->edev,
- ARIZONA_CABLE_MICROPHONE, true);
-
+ EXTCON_MICROPHONE, true);
if (ret != 0)
dev_err(arizona->dev, "Headset report failed: %d\n",
ret);
@@ -1030,7 +1020,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
if (info->last_jackdet == present) {
dev_dbg(arizona->dev, "Detected jack\n");
ret = extcon_set_cable_state_(info->edev,
- ARIZONA_CABLE_MECHANICAL, true);
+ EXTCON_MECHANICAL, true);
if (ret != 0)
dev_err(arizona->dev, "Mechanical report failed: %d\n",
@@ -1120,6 +1110,26 @@ static void arizona_micd_set_level(struct arizona *arizona, int index,
regmap_update_bits(arizona->regmap, reg, mask, level);
}
+static int arizona_extcon_of_get_pdata(struct arizona *arizona)
+{
+ struct arizona_pdata *pdata = &arizona->pdata;
+ unsigned int val = ARIZONA_ACCDET_MODE_HPL;
+
+ of_property_read_u32(arizona->dev->of_node, "wlf,hpdet-channel", &val);
+ switch (val) {
+ case ARIZONA_ACCDET_MODE_HPL:
+ case ARIZONA_ACCDET_MODE_HPR:
+ pdata->hpdet_channel = val;
+ break;
+ default:
+ dev_err(arizona->dev,
+ "Wrong wlf,hpdet-channel DT value %d\n", val);
+ pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
+ }
+
+ return 0;
+}
+
static int arizona_extcon_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@@ -1137,6 +1147,11 @@ static int arizona_extcon_probe(struct platform_device *pdev)
if (!info)
return -ENOMEM;
+ if (IS_ENABLED(CONFIG_OF)) {
+ if (!dev_get_platdata(arizona->dev))
+ arizona_extcon_of_get_pdata(arizona);
+ }
+
info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
if (IS_ERR(info->micvdd)) {
ret = PTR_ERR(info->micvdd);
@@ -1161,7 +1176,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
break;
default:
info->micd_clamp = true;
- info->hpdet_ip = 1;
+ info->hpdet_ip_version = 1;
break;
}
break;
@@ -1172,7 +1187,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
break;
default:
info->micd_clamp = true;
- info->hpdet_ip = 2;
+ info->hpdet_ip_version = 2;
break;
}
break;
@@ -1185,7 +1200,6 @@ static int arizona_extcon_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to allocate extcon device\n");
return -ENOMEM;
}
- info->edev->name = "Headset Jack";
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
if (ret < 0) {
diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c
new file mode 100644
index 000000000000..ea962bc547b8
--- /dev/null
+++ b/drivers/extcon/extcon-axp288.c
@@ -0,0 +1,381 @@
+/*
+ * extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver
+ *
+ * Copyright (C) 2015 Intel Corporation
+ * Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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/kernel.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/usb/phy.h>
+#include <linux/notifier.h>
+#include <linux/extcon.h>
+#include <linux/regmap.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mfd/axp20x.h>
+
+/* Power source status register */
+#define PS_STAT_VBUS_TRIGGER BIT(0)
+#define PS_STAT_BAT_CHRG_DIR BIT(2)
+#define PS_STAT_VBUS_ABOVE_VHOLD BIT(3)
+#define PS_STAT_VBUS_VALID BIT(4)
+#define PS_STAT_VBUS_PRESENT BIT(5)
+
+/* BC module global register */
+#define BC_GLOBAL_RUN BIT(0)
+#define BC_GLOBAL_DET_STAT BIT(2)
+#define BC_GLOBAL_DBP_TOUT BIT(3)
+#define BC_GLOBAL_VLGC_COM_SEL BIT(4)
+#define BC_GLOBAL_DCD_TOUT_MASK (BIT(6)|BIT(5))
+#define BC_GLOBAL_DCD_TOUT_300MS 0
+#define BC_GLOBAL_DCD_TOUT_100MS 1
+#define BC_GLOBAL_DCD_TOUT_500MS 2
+#define BC_GLOBAL_DCD_TOUT_900MS 3
+#define BC_GLOBAL_DCD_DET_SEL BIT(7)
+
+/* BC module vbus control and status register */
+#define VBUS_CNTL_DPDM_PD_EN BIT(4)
+#define VBUS_CNTL_DPDM_FD_EN BIT(5)
+#define VBUS_CNTL_FIRST_PO_STAT BIT(6)
+
+/* BC USB status register */
+#define USB_STAT_BUS_STAT_MASK (BIT(3)|BIT(2)|BIT(1)|BIT(0))
+#define USB_STAT_BUS_STAT_SHIFT 0
+#define USB_STAT_BUS_STAT_ATHD 0
+#define USB_STAT_BUS_STAT_CONN 1
+#define USB_STAT_BUS_STAT_SUSP 2
+#define USB_STAT_BUS_STAT_CONF 3
+#define USB_STAT_USB_SS_MODE BIT(4)
+#define USB_STAT_DEAD_BAT_DET BIT(6)
+#define USB_STAT_DBP_UNCFG BIT(7)
+
+/* BC detect status register */
+#define DET_STAT_MASK (BIT(7)|BIT(6)|BIT(5))
+#define DET_STAT_SHIFT 5
+#define DET_STAT_SDP 1
+#define DET_STAT_CDP 2
+#define DET_STAT_DCP 3
+
+/* IRQ enable-1 register */
+#define PWRSRC_IRQ_CFG_MASK (BIT(4)|BIT(3)|BIT(2))
+
+/* IRQ enable-6 register */
+#define BC12_IRQ_CFG_MASK BIT(1)
+
+enum axp288_extcon_reg {
+ AXP288_PS_STAT_REG = 0x00,
+ AXP288_PS_BOOT_REASON_REG = 0x02,
+ AXP288_BC_GLOBAL_REG = 0x2c,
+ AXP288_BC_VBUS_CNTL_REG = 0x2d,
+ AXP288_BC_USB_STAT_REG = 0x2e,
+ AXP288_BC_DET_STAT_REG = 0x2f,
+ AXP288_PWRSRC_IRQ_CFG_REG = 0x40,
+ AXP288_BC12_IRQ_CFG_REG = 0x45,
+};
+
+enum axp288_mux_select {
+ EXTCON_GPIO_MUX_SEL_PMIC = 0,
+ EXTCON_GPIO_MUX_SEL_SOC,
+};
+
+enum axp288_extcon_irq {
+ VBUS_FALLING_IRQ = 0,
+ VBUS_RISING_IRQ,
+ MV_CHNG_IRQ,
+ BC_USB_CHNG_IRQ,
+ EXTCON_IRQ_END,
+};
+
+static const unsigned int axp288_extcon_cables[] = {
+ EXTCON_SLOW_CHARGER,
+ EXTCON_CHARGE_DOWNSTREAM,
+ EXTCON_FAST_CHARGER,
+ EXTCON_NONE,
+};
+
+struct axp288_extcon_info {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regmap_irq_chip_data *regmap_irqc;
+ struct axp288_extcon_pdata *pdata;
+ int irq[EXTCON_IRQ_END];
+ struct extcon_dev *edev;
+ struct notifier_block extcon_nb;
+ struct usb_phy *otg;
+};
+
+/* Power up/down reason string array */
+static char *axp288_pwr_up_down_info[] = {
+ "Last wake caused by user pressing the power button",
+ "Last wake caused by a charger insertion",
+ "Last wake caused by a battery insertion",
+ "Last wake caused by SOC initiated global reset",
+ "Last wake caused by cold reset",
+ "Last shutdown caused by PMIC UVLO threshold",
+ "Last shutdown caused by SOC initiated cold off",
+ "Last shutdown caused by user pressing the power button",
+ NULL,
+};
+
+/*
+ * Decode and log the given "reset source indicator" (rsi)
+ * register and then clear it.
+ */
+static void axp288_extcon_log_rsi(struct axp288_extcon_info *info)
+{
+ char **rsi;
+ unsigned int val, i, clear_mask = 0;
+ int ret;
+
+ ret = regmap_read(info->regmap, AXP288_PS_BOOT_REASON_REG, &val);
+ for (i = 0, rsi = axp288_pwr_up_down_info; *rsi; rsi++, i++) {
+ if (val & BIT(i)) {
+ dev_dbg(info->dev, "%s\n", *rsi);
+ clear_mask |= BIT(i);
+ }
+ }
+
+ /* Clear the register value for next reboot (write 1 to clear bit) */
+ regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask);
+}
+
+static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
+{
+ static bool notify_otg, notify_charger;
+ static unsigned int cable;
+ int ret, stat, cfg, pwr_stat;
+ u8 chrg_type;
+ bool vbus_attach = false;
+
+ ret = regmap_read(info->regmap, AXP288_PS_STAT_REG, &pwr_stat);
+ if (ret < 0) {
+ dev_err(info->dev, "failed to read vbus status\n");
+ return ret;
+ }
+
+ vbus_attach = (pwr_stat & PS_STAT_VBUS_PRESENT);
+ if (!vbus_attach)
+ goto notify_otg;
+
+ /* Check charger detection completion status */
+ ret = regmap_read(info->regmap, AXP288_BC_GLOBAL_REG, &cfg);
+ if (ret < 0)
+ goto dev_det_ret;
+ if (cfg & BC_GLOBAL_DET_STAT) {
+ dev_dbg(info->dev, "can't complete the charger detection\n");
+ goto dev_det_ret;
+ }
+
+ ret = regmap_read(info->regmap, AXP288_BC_DET_STAT_REG, &stat);
+ if (ret < 0)
+ goto dev_det_ret;
+
+ chrg_type = (stat & DET_STAT_MASK) >> DET_STAT_SHIFT;
+
+ switch (chrg_type) {
+ case DET_STAT_SDP:
+ dev_dbg(info->dev, "sdp cable is connecetd\n");
+ notify_otg = true;
+ notify_charger = true;
+ cable = EXTCON_SLOW_CHARGER;
+ break;
+ case DET_STAT_CDP:
+ dev_dbg(info->dev, "cdp cable is connecetd\n");
+ notify_otg = true;
+ notify_charger = true;
+ cable = EXTCON_CHARGE_DOWNSTREAM;
+ break;
+ case DET_STAT_DCP:
+ dev_dbg(info->dev, "dcp cable is connecetd\n");
+ notify_charger = true;
+ cable = EXTCON_FAST_CHARGER;
+ break;
+ default:
+ dev_warn(info->dev,
+ "disconnect or unknown or ID event\n");
+ }
+
+notify_otg:
+ if (notify_otg) {
+ /*
+ * If VBUS is absent Connect D+/D- lines to PMIC for BC
+ * detection. Else connect them to SOC for USB communication.
+ */
+ if (info->pdata->gpio_mux_cntl)
+ gpiod_set_value(info->pdata->gpio_mux_cntl,
+ vbus_attach ? EXTCON_GPIO_MUX_SEL_SOC
+ : EXTCON_GPIO_MUX_SEL_PMIC);
+
+ atomic_notifier_call_chain(&info->otg->notifier,
+ vbus_attach ? USB_EVENT_VBUS : USB_EVENT_NONE, NULL);
+ }
+
+ if (notify_charger)
+ extcon_set_cable_state_(info->edev, cable, vbus_attach);
+
+ /* Clear the flags on disconnect event */
+ if (!vbus_attach)
+ notify_otg = notify_charger = false;
+
+ return 0;
+
+dev_det_ret:
+ if (ret < 0)
+ dev_err(info->dev, "failed to detect BC Mod\n");
+
+ return ret;
+}
+
+static irqreturn_t axp288_extcon_isr(int irq, void *data)
+{
+ struct axp288_extcon_info *info = data;
+ int ret;
+
+ ret = axp288_handle_chrg_det_event(info);
+ if (ret < 0)
+ dev_err(info->dev, "failed to handle the interrupt\n");
+
+ return IRQ_HANDLED;
+}
+
+static void axp288_extcon_enable_irq(struct axp288_extcon_info *info)
+{
+ /* Unmask VBUS interrupt */
+ regmap_write(info->regmap, AXP288_PWRSRC_IRQ_CFG_REG,
+ PWRSRC_IRQ_CFG_MASK);
+ regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
+ BC_GLOBAL_RUN, 0);
+ /* Unmask the BC1.2 complete interrupts */
+ regmap_write(info->regmap, AXP288_BC12_IRQ_CFG_REG, BC12_IRQ_CFG_MASK);
+ /* Enable the charger detection logic */
+ regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
+ BC_GLOBAL_RUN, BC_GLOBAL_RUN);
+}
+
+static int axp288_extcon_probe(struct platform_device *pdev)
+{
+ struct axp288_extcon_info *info;
+ struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+ int ret, i, pirq, gpio;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = &pdev->dev;
+ info->regmap = axp20x->regmap;
+ info->regmap_irqc = axp20x->regmap_irqc;
+ info->pdata = pdev->dev.platform_data;
+
+ if (!info->pdata) {
+ /* Try ACPI provided pdata via device properties */
+ if (!device_property_present(&pdev->dev,
+ "axp288_extcon_data\n"))
+ dev_err(&pdev->dev, "failed to get platform data\n");
+ return -ENODEV;
+ }
+ platform_set_drvdata(pdev, info);
+
+ axp288_extcon_log_rsi(info);
+
+ /* Initialize extcon device */
+ info->edev = devm_extcon_dev_allocate(&pdev->dev,
+ axp288_extcon_cables);
+ if (IS_ERR(info->edev)) {
+ dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
+ return PTR_ERR(info->edev);
+ }
+
+ /* Register extcon device */
+ ret = devm_extcon_dev_register(&pdev->dev, info->edev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register extcon device\n");
+ return ret;
+ }
+
+ /* Get otg transceiver phy */
+ info->otg = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (IS_ERR(info->otg)) {
+ dev_err(&pdev->dev, "failed to get otg transceiver\n");
+ return PTR_ERR(info->otg);
+ }
+
+ /* Set up gpio control for USB Mux */
+ if (info->pdata->gpio_mux_cntl) {
+ gpio = desc_to_gpio(info->pdata->gpio_mux_cntl);
+ ret = gpio_request(gpio, "USB_MUX");
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "failed to request the gpio=%d\n", gpio);
+ goto gpio_req_failed;
+ }
+ gpiod_direction_output(info->pdata->gpio_mux_cntl,
+ EXTCON_GPIO_MUX_SEL_PMIC);
+ }
+
+ for (i = 0; i < EXTCON_IRQ_END; i++) {
+ pirq = platform_get_irq(pdev, i);
+ info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
+ if (info->irq[i] < 0) {
+ dev_err(&pdev->dev,
+ "failed to get virtual interrupt=%d\n", pirq);
+ ret = info->irq[i];
+ goto gpio_req_failed;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, info->irq[i],
+ NULL, axp288_extcon_isr,
+ IRQF_ONESHOT | IRQF_NO_SUSPEND,
+ pdev->name, info);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request interrupt=%d\n",
+ info->irq[i]);
+ goto gpio_req_failed;
+ }
+ }
+
+ /* Enable interrupts */
+ axp288_extcon_enable_irq(info);
+
+ return 0;
+
+gpio_req_failed:
+ usb_put_phy(info->otg);
+ return ret;
+}
+
+static int axp288_extcon_remove(struct platform_device *pdev)
+{
+ struct axp288_extcon_info *info = platform_get_drvdata(pdev);
+
+ usb_put_phy(info->otg);
+ return 0;
+}
+
+static struct platform_driver axp288_extcon_driver = {
+ .probe = axp288_extcon_probe,
+ .remove = axp288_extcon_remove,
+ .driver = {
+ .name = "axp288_extcon",
+ },
+};
+module_platform_driver(axp288_extcon_driver);
+
+MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>");
+MODULE_DESCRIPTION("X-Powers AXP288 extcon driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index 7af33fc433cd..355459a54e8b 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -104,7 +104,6 @@ static int gpio_extcon_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to allocate extcon device\n");
return -ENOMEM;
}
- extcon_data->edev->name = pdata->name;
extcon_data->gpio = pdata->gpio;
extcon_data->gpio_active_low = pdata->gpio_active_low;
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index 3823aa4a3a80..df0659d98e5a 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -148,33 +148,14 @@ enum max14577_muic_acc_type {
MAX14577_MUIC_ADC_OPEN,
};
-/* max14577 MUIC device support below list of accessories(external connector) */
-enum {
- EXTCON_CABLE_USB = 0,
- EXTCON_CABLE_TA,
- EXTCON_CABLE_FAST_CHARGER,
- EXTCON_CABLE_SLOW_CHARGER,
- EXTCON_CABLE_CHARGE_DOWNSTREAM,
- EXTCON_CABLE_JIG_USB_ON,
- EXTCON_CABLE_JIG_USB_OFF,
- EXTCON_CABLE_JIG_UART_OFF,
- EXTCON_CABLE_JIG_UART_ON,
-
- _EXTCON_CABLE_NUM,
-};
-
-static const char *max14577_extcon_cable[] = {
- [EXTCON_CABLE_USB] = "USB",
- [EXTCON_CABLE_TA] = "TA",
- [EXTCON_CABLE_FAST_CHARGER] = "Fast-charger",
- [EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger",
- [EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream",
- [EXTCON_CABLE_JIG_USB_ON] = "JIG-USB-ON",
- [EXTCON_CABLE_JIG_USB_OFF] = "JIG-USB-OFF",
- [EXTCON_CABLE_JIG_UART_OFF] = "JIG-UART-OFF",
- [EXTCON_CABLE_JIG_UART_ON] = "JIG-UART-ON",
-
- NULL,
+static const unsigned int max14577_extcon_cable[] = {
+ EXTCON_USB,
+ EXTCON_TA,
+ EXTCON_FAST_CHARGER,
+ EXTCON_SLOW_CHARGER,
+ EXTCON_CHARGE_DOWNSTREAM,
+ EXTCON_JIG,
+ EXTCON_NONE,
};
/*
@@ -348,7 +329,6 @@ static int max14577_muic_get_cable_type(struct max14577_muic_info *info,
static int max14577_muic_jig_handler(struct max14577_muic_info *info,
int cable_type, bool attached)
{
- char cable_name[32];
int ret = 0;
u8 path = CTRL1_SW_OPEN;
@@ -358,18 +338,12 @@ static int max14577_muic_jig_handler(struct max14577_muic_info *info,
switch (cable_type) {
case MAX14577_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */
- /* PATH:AP_USB */
- strcpy(cable_name, "JIG-USB-OFF");
- path = CTRL1_SW_USB;
- break;
case MAX14577_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */
/* PATH:AP_USB */
- strcpy(cable_name, "JIG-USB-ON");
path = CTRL1_SW_USB;
break;
case MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */
/* PATH:AP_UART */
- strcpy(cable_name, "JIG-UART-OFF");
path = CTRL1_SW_UART;
break;
default:
@@ -382,7 +356,7 @@ static int max14577_muic_jig_handler(struct max14577_muic_info *info,
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, cable_name, attached);
+ extcon_set_cable_state_(info->edev, EXTCON_JIG, attached);
return 0;
}
@@ -479,20 +453,22 @@ static int max14577_muic_chg_handler(struct max14577_muic_info *info)
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, "USB", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
break;
case MAX14577_CHARGER_TYPE_DEDICATED_CHG:
- extcon_set_cable_state(info->edev, "TA", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
break;
case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT:
- extcon_set_cable_state(info->edev,
- "Charge-downstream", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_CHARGE_DOWNSTREAM,
+ attached);
break;
case MAX14577_CHARGER_TYPE_SPECIAL_500MA:
- extcon_set_cable_state(info->edev, "Slow-charger", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_SLOW_CHARGER,
+ attached);
break;
case MAX14577_CHARGER_TYPE_SPECIAL_1A:
- extcon_set_cable_state(info->edev, "Fast-charger", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_FAST_CHARGER,
+ attached);
break;
case MAX14577_CHARGER_TYPE_NONE:
case MAX14577_CHARGER_TYPE_DEAD_BATTERY:
@@ -742,8 +718,6 @@ static int max14577_muic_probe(struct platform_device *pdev)
return -ENOMEM;
}
- info->edev->name = dev_name(&pdev->dev);
-
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
if (ret) {
dev_err(&pdev->dev, "failed to register extcon device\n");
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index a66bec8f6252..f4f3b3d53928 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -200,44 +200,17 @@ enum max77693_muic_acc_type {
/*
* MAX77693 MUIC device support below list of accessories(external connector)
*/
-enum {
- EXTCON_CABLE_USB = 0,
- EXTCON_CABLE_USB_HOST,
- EXTCON_CABLE_TA,
- EXTCON_CABLE_FAST_CHARGER,
- EXTCON_CABLE_SLOW_CHARGER,
- EXTCON_CABLE_CHARGE_DOWNSTREAM,
- EXTCON_CABLE_MHL,
- EXTCON_CABLE_MHL_TA,
- EXTCON_CABLE_JIG_USB_ON,
- EXTCON_CABLE_JIG_USB_OFF,
- EXTCON_CABLE_JIG_UART_OFF,
- EXTCON_CABLE_JIG_UART_ON,
- EXTCON_CABLE_DOCK_SMART,
- EXTCON_CABLE_DOCK_DESK,
- EXTCON_CABLE_DOCK_AUDIO,
-
- _EXTCON_CABLE_NUM,
-};
-
-static const char *max77693_extcon_cable[] = {
- [EXTCON_CABLE_USB] = "USB",
- [EXTCON_CABLE_USB_HOST] = "USB-Host",
- [EXTCON_CABLE_TA] = "TA",
- [EXTCON_CABLE_FAST_CHARGER] = "Fast-charger",
- [EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger",
- [EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream",
- [EXTCON_CABLE_MHL] = "MHL",
- [EXTCON_CABLE_MHL_TA] = "MHL-TA",
- [EXTCON_CABLE_JIG_USB_ON] = "JIG-USB-ON",
- [EXTCON_CABLE_JIG_USB_OFF] = "JIG-USB-OFF",
- [EXTCON_CABLE_JIG_UART_OFF] = "JIG-UART-OFF",
- [EXTCON_CABLE_JIG_UART_ON] = "JIG-UART-ON",
- [EXTCON_CABLE_DOCK_SMART] = "Dock-Smart",
- [EXTCON_CABLE_DOCK_DESK] = "Dock-Desk",
- [EXTCON_CABLE_DOCK_AUDIO] = "Dock-Audio",
-
- NULL,
+static const unsigned int max77693_extcon_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_TA,
+ EXTCON_FAST_CHARGER,
+ EXTCON_SLOW_CHARGER,
+ EXTCON_CHARGE_DOWNSTREAM,
+ EXTCON_MHL,
+ EXTCON_JIG,
+ EXTCON_DOCK,
+ EXTCON_NONE,
};
/*
@@ -484,7 +457,7 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info,
int ret = 0;
int vbvolt;
bool cable_attached;
- char dock_name[CABLE_NAME_MAX];
+ unsigned int dock_id;
dev_info(info->dev,
"external connector is %s (adc:0x%02x)\n",
@@ -507,15 +480,15 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info,
}
/*
- * Notify Dock-Smart/MHL state.
- * - Dock-Smart device include three type of cable which
+ * Notify Dock/MHL state.
+ * - Dock device include three type of cable which
* are HDMI, USB for mouse/keyboard and micro-usb port
- * for USB/TA cable. Dock-Smart device need always exteranl
- * power supply(USB/TA cable through micro-usb cable). Dock-
- * Smart device support screen output of target to separate
+ * for USB/TA cable. Dock device need always exteranl
+ * power supply(USB/TA cable through micro-usb cable). Dock
+ * device support screen output of target to separate
* monitor and mouse/keyboard for desktop mode.
*
- * Features of 'USB/TA cable with Dock-Smart device'
+ * Features of 'USB/TA cable with Dock device'
* - Support MHL
* - Support external output feature of audio
* - Support charging through micro-usb port without data
@@ -529,16 +502,16 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info,
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, "Dock-Smart", attached);
- extcon_set_cable_state(info->edev, "MHL", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_DOCK, attached);
+ extcon_set_cable_state_(info->edev, EXTCON_MHL, attached);
goto out;
case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */
- strcpy(dock_name, "Dock-Desk");
+ dock_id = EXTCON_DOCK;
break;
case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */
- strcpy(dock_name, "Dock-Audio");
+ dock_id = EXTCON_DOCK;
if (!attached)
- extcon_set_cable_state(info->edev, "USB", false);
+ extcon_set_cable_state_(info->edev, EXTCON_USB, false);
break;
default:
dev_err(info->dev, "failed to detect %s dock device\n",
@@ -550,7 +523,7 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info,
ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached);
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, dock_name, attached);
+ extcon_set_cable_state_(info->edev, dock_id, attached);
out:
return 0;
@@ -615,20 +588,19 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info)
ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached);
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, "USB-Host", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached);
break;
case MAX77693_MUIC_GND_AV_CABLE_LOAD:
/* Audio Video Cable with load, PATH:AUDIO */
ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached);
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev,
- "Audio-video-load", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
break;
case MAX77693_MUIC_GND_MHL:
case MAX77693_MUIC_GND_MHL_VB:
/* MHL or MHL with USB/TA cable */
- extcon_set_cable_state(info->edev, "MHL", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_MHL, attached);
break;
default:
dev_err(info->dev, "failed to detect %s cable of gnd type\n",
@@ -642,7 +614,6 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info)
static int max77693_muic_jig_handler(struct max77693_muic_info *info,
int cable_type, bool attached)
{
- char cable_name[32];
int ret = 0;
u8 path = CONTROL1_SW_OPEN;
@@ -652,23 +623,13 @@ static int max77693_muic_jig_handler(struct max77693_muic_info *info,
switch (cable_type) {
case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */
- /* PATH:AP_USB */
- strcpy(cable_name, "JIG-USB-OFF");
- path = CONTROL1_SW_USB;
- break;
case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */
/* PATH:AP_USB */
- strcpy(cable_name, "JIG-USB-ON");
path = CONTROL1_SW_USB;
break;
case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */
- /* PATH:AP_UART */
- strcpy(cable_name, "JIG-UART-OFF");
- path = CONTROL1_SW_UART;
- break;
case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* ADC_JIG_UART_ON */
/* PATH:AP_UART */
- strcpy(cable_name, "JIG-UART-ON");
path = CONTROL1_SW_UART;
break;
default:
@@ -681,7 +642,7 @@ static int max77693_muic_jig_handler(struct max77693_muic_info *info,
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, cable_name, attached);
+ extcon_set_cable_state_(info->edev, EXTCON_JIG, attached);
return 0;
}
@@ -823,22 +784,22 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
case MAX77693_MUIC_GND_MHL:
case MAX77693_MUIC_GND_MHL_VB:
/*
- * MHL cable with MHL-TA(USB/TA) cable
+ * MHL cable with USB/TA cable
* - MHL cable include two port(HDMI line and separate
* micro-usb port. When the target connect MHL cable,
- * extcon driver check whether MHL-TA(USB/TA) cable is
- * connected. If MHL-TA cable is connected, extcon
+ * extcon driver check whether USB/TA cable is
+ * connected. If USB/TA cable is connected, extcon
* driver notify state to notifiee for charging battery.
*
- * Features of 'MHL-TA(USB/TA) with MHL cable'
+ * Features of 'USB/TA with MHL cable'
* - Support MHL
* - Support charging through micro-usb port without
* data connection
*/
- extcon_set_cable_state(info->edev, "MHL-TA", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
if (!cable_attached)
- extcon_set_cable_state(info->edev,
- "MHL", cable_attached);
+ extcon_set_cable_state_(info->edev, EXTCON_MHL,
+ cable_attached);
break;
}
@@ -861,11 +822,12 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
* - Support charging through micro-usb port without
* data connection.
*/
- extcon_set_cable_state(info->edev, "USB", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_USB,
+ attached);
if (!cable_attached)
- extcon_set_cable_state(info->edev, "Dock-Audio",
- cable_attached);
+ extcon_set_cable_state_(info->edev, EXTCON_DOCK,
+ cable_attached);
break;
case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */
/*
@@ -893,10 +855,10 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, "Dock-Smart",
- attached);
- extcon_set_cable_state(info->edev, "MHL", attached);
-
+ extcon_set_cable_state_(info->edev, EXTCON_DOCK,
+ attached);
+ extcon_set_cable_state_(info->edev, EXTCON_MHL,
+ attached);
break;
}
@@ -929,23 +891,26 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, "USB", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_USB,
+ attached);
break;
case MAX77693_CHARGER_TYPE_DEDICATED_CHG:
/* Only TA cable */
- extcon_set_cable_state(info->edev, "TA", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
break;
}
break;
case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT:
- extcon_set_cable_state(info->edev,
- "Charge-downstream", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_CHARGE_DOWNSTREAM,
+ attached);
break;
case MAX77693_CHARGER_TYPE_APPLE_500MA:
- extcon_set_cable_state(info->edev, "Slow-charger", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_SLOW_CHARGER,
+ attached);
break;
case MAX77693_CHARGER_TYPE_APPLE_1A_2A:
- extcon_set_cable_state(info->edev, "Fast-charger", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_FAST_CHARGER,
+ attached);
break;
case MAX77693_CHARGER_TYPE_DEAD_BATTERY:
break;
@@ -1182,7 +1147,6 @@ static int max77693_muic_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
return -ENOMEM;
}
- info->edev->name = DEV_NAME;
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
if (ret) {
diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
index 8db6a926ea07..fac2f1417a79 100644
--- a/drivers/extcon/extcon-max77843.c
+++ b/drivers/extcon/extcon-max77843.c
@@ -118,36 +118,16 @@ enum max77843_muic_charger_type {
MAX77843_MUIC_CHG_GND,
};
-enum {
- MAX77843_CABLE_USB = 0,
- MAX77843_CABLE_USB_HOST,
- MAX77843_CABLE_TA,
- MAX77843_CABLE_CHARGE_DOWNSTREAM,
- MAX77843_CABLE_FAST_CHARGER,
- MAX77843_CABLE_SLOW_CHARGER,
- MAX77843_CABLE_MHL,
- MAX77843_CABLE_MHL_TA,
- MAX77843_CABLE_JIG_USB_ON,
- MAX77843_CABLE_JIG_USB_OFF,
- MAX77843_CABLE_JIG_UART_ON,
- MAX77843_CABLE_JIG_UART_OFF,
-
- MAX77843_CABLE_NUM,
-};
-
-static const char *max77843_extcon_cable[] = {
- [MAX77843_CABLE_USB] = "USB",
- [MAX77843_CABLE_USB_HOST] = "USB-HOST",
- [MAX77843_CABLE_TA] = "TA",
- [MAX77843_CABLE_CHARGE_DOWNSTREAM] = "CHARGER-DOWNSTREAM",
- [MAX77843_CABLE_FAST_CHARGER] = "FAST-CHARGER",
- [MAX77843_CABLE_SLOW_CHARGER] = "SLOW-CHARGER",
- [MAX77843_CABLE_MHL] = "MHL",
- [MAX77843_CABLE_MHL_TA] = "MHL-TA",
- [MAX77843_CABLE_JIG_USB_ON] = "JIG-USB-ON",
- [MAX77843_CABLE_JIG_USB_OFF] = "JIG-USB-OFF",
- [MAX77843_CABLE_JIG_UART_ON] = "JIG-UART-ON",
- [MAX77843_CABLE_JIG_UART_OFF] = "JIG-UART-OFF",
+static const unsigned int max77843_extcon_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_TA,
+ EXTCON_CHARGE_DOWNSTREAM,
+ EXTCON_FAST_CHARGER,
+ EXTCON_SLOW_CHARGER,
+ EXTCON_MHL,
+ EXTCON_JIG,
+ EXTCON_NONE,
};
struct max77843_muic_irq {
@@ -362,7 +342,7 @@ static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info)
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, "USB-HOST", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached);
break;
case MAX77843_MUIC_GND_MHL_VB:
case MAX77843_MUIC_GND_MHL:
@@ -370,7 +350,7 @@ static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info)
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, "MHL", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_MHL, attached);
break;
default:
dev_err(info->dev, "failed to detect %s accessory(gnd:0x%x)\n",
@@ -385,36 +365,29 @@ static int max77843_muic_jig_handler(struct max77843_muic_info *info,
int cable_type, bool attached)
{
int ret;
+ u8 path = CONTROL1_SW_OPEN;
dev_dbg(info->dev, "external connector is %s (adc:0x%02x)\n",
attached ? "attached" : "detached", cable_type);
switch (cable_type) {
case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
- ret = max77843_muic_set_path(info, CONTROL1_SW_USB, attached);
- if (ret < 0)
- return ret;
- extcon_set_cable_state(info->edev, "JIG-USB-OFF", attached);
- break;
case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
- ret = max77843_muic_set_path(info, CONTROL1_SW_USB, attached);
- if (ret < 0)
- return ret;
- extcon_set_cable_state(info->edev, "JIG-USB-ON", attached);
+ path = CONTROL1_SW_USB;
break;
case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
- ret = max77843_muic_set_path(info, CONTROL1_SW_UART, attached);
- if (ret < 0)
- return ret;
- extcon_set_cable_state(info->edev, "JIG-UART-OFF", attached);
+ path = CONTROL1_SW_UART;
break;
default:
- ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
- if (ret < 0)
- return ret;
- break;
+ return -EINVAL;
}
+ ret = max77843_muic_set_path(info, path, attached);
+ if (ret < 0)
+ return ret;
+
+ extcon_set_cable_state_(info->edev, EXTCON_JIG, attached);
+
return 0;
}
@@ -505,36 +478,38 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info)
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, "USB", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
break;
case MAX77843_MUIC_CHG_DOWNSTREAM:
ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev,
- "CHARGER-DOWNSTREAM", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_CHARGE_DOWNSTREAM,
+ attached);
break;
case MAX77843_MUIC_CHG_DEDICATED:
ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, "TA", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
break;
case MAX77843_MUIC_CHG_SPECIAL_500MA:
ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, "SLOW-CHAREGER", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_SLOW_CHARGER,
+ attached);
break;
case MAX77843_MUIC_CHG_SPECIAL_1A:
ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
if (ret < 0)
return ret;
- extcon_set_cable_state(info->edev, "FAST-CHARGER", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_FAST_CHARGER,
+ attached);
break;
case MAX77843_MUIC_CHG_GND:
gnd_type = max77843_muic_get_cable_type(info,
@@ -542,9 +517,9 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info)
/* Charger cable on MHL accessory is attach or detach */
if (gnd_type == MAX77843_MUIC_GND_MHL_VB)
- extcon_set_cable_state(info->edev, "MHL-TA", true);
+ extcon_set_cable_state_(info->edev, EXTCON_TA, true);
else if (gnd_type == MAX77843_MUIC_GND_MHL)
- extcon_set_cable_state(info->edev, "MHL-TA", false);
+ extcon_set_cable_state_(info->edev, EXTCON_TA, false);
break;
case MAX77843_MUIC_CHG_NONE:
break;
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
index 5774e56c6422..7b1ef200b121 100644
--- a/drivers/extcon/extcon-max8997.c
+++ b/drivers/extcon/extcon-max8997.c
@@ -145,34 +145,17 @@ struct max8997_muic_info {
int path_uart;
};
-enum {
- EXTCON_CABLE_USB = 0,
- EXTCON_CABLE_USB_HOST,
- EXTCON_CABLE_TA,
- EXTCON_CABLE_FAST_CHARGER,
- EXTCON_CABLE_SLOW_CHARGER,
- EXTCON_CABLE_CHARGE_DOWNSTREAM,
- EXTCON_CABLE_MHL,
- EXTCON_CABLE_DOCK_DESK,
- EXTCON_CABLE_DOCK_CARD,
- EXTCON_CABLE_JIG,
-
- _EXTCON_CABLE_NUM,
-};
-
-static const char *max8997_extcon_cable[] = {
- [EXTCON_CABLE_USB] = "USB",
- [EXTCON_CABLE_USB_HOST] = "USB-Host",
- [EXTCON_CABLE_TA] = "TA",
- [EXTCON_CABLE_FAST_CHARGER] = "Fast-charger",
- [EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger",
- [EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream",
- [EXTCON_CABLE_MHL] = "MHL",
- [EXTCON_CABLE_DOCK_DESK] = "Dock-Desk",
- [EXTCON_CABLE_DOCK_CARD] = "Dock-Card",
- [EXTCON_CABLE_JIG] = "JIG",
-
- NULL,
+static const unsigned int max8997_extcon_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_TA,
+ EXTCON_FAST_CHARGER,
+ EXTCON_SLOW_CHARGER,
+ EXTCON_CHARGE_DOWNSTREAM,
+ EXTCON_MHL,
+ EXTCON_DOCK,
+ EXTCON_JIG,
+ EXTCON_NONE,
};
/*
@@ -347,10 +330,10 @@ static int max8997_muic_handle_usb(struct max8997_muic_info *info,
switch (usb_type) {
case MAX8997_USB_HOST:
- extcon_set_cable_state(info->edev, "USB-Host", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached);
break;
case MAX8997_USB_DEVICE:
- extcon_set_cable_state(info->edev, "USB", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
break;
default:
dev_err(info->dev, "failed to detect %s usb cable\n",
@@ -374,10 +357,8 @@ static int max8997_muic_handle_dock(struct max8997_muic_info *info,
switch (cable_type) {
case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD:
- extcon_set_cable_state(info->edev, "Dock-desk", attached);
- break;
case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON:
- extcon_set_cable_state(info->edev, "Dock-card", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_DOCK, attached);
break;
default:
dev_err(info->dev, "failed to detect %s dock device\n",
@@ -400,7 +381,7 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
return ret;
}
- extcon_set_cable_state(info->edev, "JIG", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_JIG, attached);
return 0;
}
@@ -422,7 +403,7 @@ static int max8997_muic_adc_handler(struct max8997_muic_info *info)
return ret;
break;
case MAX8997_MUIC_ADC_MHL:
- extcon_set_cable_state(info->edev, "MHL", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_MHL, attached);
break;
case MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF:
case MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON:
@@ -505,17 +486,19 @@ static int max8997_muic_chg_handler(struct max8997_muic_info *info)
}
break;
case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
- extcon_set_cable_state(info->edev,
- "Charge-downstream", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_CHARGE_DOWNSTREAM,
+ attached);
break;
case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
- extcon_set_cable_state(info->edev, "TA", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
break;
case MAX8997_CHARGER_TYPE_500MA:
- extcon_set_cable_state(info->edev, "Slow-charger", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_SLOW_CHARGER,
+ attached);
break;
case MAX8997_CHARGER_TYPE_1A:
- extcon_set_cable_state(info->edev, "Fast-charger", attached);
+ extcon_set_cable_state_(info->edev, EXTCON_FAST_CHARGER,
+ attached);
break;
default:
dev_err(info->dev,
@@ -700,7 +683,6 @@ static int max8997_muic_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto err_irq;
}
- info->edev->name = DEV_NAME;
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
if (ret) {
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
index 11c6757b6c40..080d5cc27055 100644
--- a/drivers/extcon/extcon-palmas.c
+++ b/drivers/extcon/extcon-palmas.c
@@ -29,10 +29,10 @@
#include <linux/of.h>
#include <linux/of_platform.h>
-static const char *palmas_extcon_cable[] = {
- [0] = "USB",
- [1] = "USB-HOST",
- NULL,
+static const unsigned int palmas_extcon_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_NONE,
};
static const int mutually_exclusive[] = {0x3, 0x0};
@@ -49,6 +49,7 @@ static void palmas_usb_wakeup(struct palmas *palmas, int enable)
static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
{
struct palmas_usb *palmas_usb = _palmas_usb;
+ struct extcon_dev *edev = palmas_usb->edev;
unsigned int vbus_line_state;
palmas_read(palmas_usb->palmas, PALMAS_INTERRUPT_BASE,
@@ -57,7 +58,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
if (vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS) {
if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) {
palmas_usb->linkstat = PALMAS_USB_STATE_VBUS;
- extcon_set_cable_state(palmas_usb->edev, "USB", true);
+ extcon_set_cable_state_(edev, EXTCON_USB, true);
dev_info(palmas_usb->dev, "USB cable is attached\n");
} else {
dev_dbg(palmas_usb->dev,
@@ -66,7 +67,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
} else if (!(vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS)) {
if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) {
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
- extcon_set_cable_state(palmas_usb->edev, "USB", false);
+ extcon_set_cable_state_(edev, EXTCON_USB, false);
dev_info(palmas_usb->dev, "USB cable is detached\n");
} else {
dev_dbg(palmas_usb->dev,
@@ -81,6 +82,7 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
{
unsigned int set, id_src;
struct palmas_usb *palmas_usb = _palmas_usb;
+ struct extcon_dev *edev = palmas_usb->edev;
palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
PALMAS_USB_ID_INT_LATCH_SET, &set);
@@ -93,7 +95,7 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
PALMAS_USB_ID_INT_LATCH_CLR,
PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
palmas_usb->linkstat = PALMAS_USB_STATE_ID;
- extcon_set_cable_state(palmas_usb->edev, "USB-HOST", true);
+ extcon_set_cable_state_(edev, EXTCON_USB_HOST, true);
dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
} else if ((set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) &&
(id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT)) {
@@ -101,17 +103,17 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
PALMAS_USB_ID_INT_LATCH_CLR,
PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
- extcon_set_cable_state(palmas_usb->edev, "USB-HOST", false);
+ extcon_set_cable_state_(edev, EXTCON_USB_HOST, false);
dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
} else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) &&
(!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) {
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
- extcon_set_cable_state(palmas_usb->edev, "USB-HOST", false);
+ extcon_set_cable_state_(edev, EXTCON_USB_HOST, false);
dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
} else if ((palmas_usb->linkstat == PALMAS_USB_STATE_DISCONNECT) &&
(id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) {
palmas_usb->linkstat = PALMAS_USB_STATE_ID;
- extcon_set_cable_state(palmas_usb->edev, "USB-HOST", true);
+ extcon_set_cable_state_(edev, EXTCON_USB_HOST, true);
dev_info(palmas_usb->dev, " USB-HOST cable is attached\n");
}
@@ -193,7 +195,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to allocate extcon device\n");
return -ENOMEM;
}
- palmas_usb->edev->name = kstrdup(node->name, GFP_KERNEL);
palmas_usb->edev->mutually_exclusive = mutually_exclusive;
status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev);
diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
index 9ccd5af89d1c..92c939221a41 100644
--- a/drivers/extcon/extcon-rt8973a.c
+++ b/drivers/extcon/extcon-rt8973a.c
@@ -90,27 +90,12 @@ static struct reg_data rt8973a_reg_data[] = {
};
/* List of detectable cables */
-enum {
- EXTCON_CABLE_USB = 0,
- EXTCON_CABLE_USB_HOST,
- EXTCON_CABLE_TA,
- EXTCON_CABLE_JIG_OFF_USB,
- EXTCON_CABLE_JIG_ON_USB,
- EXTCON_CABLE_JIG_OFF_UART,
- EXTCON_CABLE_JIG_ON_UART,
-
- EXTCON_CABLE_END,
-};
-
-static const char *rt8973a_extcon_cable[] = {
- [EXTCON_CABLE_USB] = "USB",
- [EXTCON_CABLE_USB_HOST] = "USB-Host",
- [EXTCON_CABLE_TA] = "TA",
- [EXTCON_CABLE_JIG_OFF_USB] = "JIG-USB-OFF",
- [EXTCON_CABLE_JIG_ON_USB] = "JIG-USB-ON",
- [EXTCON_CABLE_JIG_OFF_UART] = "JIG-UART-OFF",
- [EXTCON_CABLE_JIG_ON_UART] = "JIG-UART-ON",
- NULL,
+static const unsigned int rt8973a_extcon_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_TA,
+ EXTCON_JIG,
+ EXTCON_NONE,
};
/* Define OVP (Over Voltage Protection), OTP (Over Temperature Protection) */
@@ -313,14 +298,11 @@ static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info,
enum rt8973a_event_type event)
{
static unsigned int prev_cable_type;
- const char **cable_names = info->edev->supported_cable;
unsigned int con_sw = DM_DP_SWITCH_UART;
- int ret, idx = 0, cable_type;
+ int ret, cable_type;
+ unsigned int id;
bool attached = false;
- if (!cable_names)
- return 0;
-
switch (event) {
case RT8973A_EVENT_ATTACH:
cable_type = rt8973a_muic_get_cable_type(info);
@@ -347,31 +329,25 @@ static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info,
switch (cable_type) {
case RT8973A_MUIC_ADC_OTG:
- idx = EXTCON_CABLE_USB_HOST;
+ id = EXTCON_USB_HOST;
con_sw = DM_DP_SWITCH_USB;
break;
case RT8973A_MUIC_ADC_TA:
- idx = EXTCON_CABLE_TA;
+ id = EXTCON_TA;
con_sw = DM_DP_SWITCH_OPEN;
break;
case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB:
- idx = EXTCON_CABLE_JIG_OFF_USB;
- con_sw = DM_DP_SWITCH_UART;
- break;
case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB:
- idx = EXTCON_CABLE_JIG_ON_USB;
- con_sw = DM_DP_SWITCH_UART;
+ id = EXTCON_JIG;
+ con_sw = DM_DP_SWITCH_USB;
break;
case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART:
- idx = EXTCON_CABLE_JIG_OFF_UART;
- con_sw = DM_DP_SWITCH_UART;
- break;
case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART:
- idx = EXTCON_CABLE_JIG_ON_UART;
+ id = EXTCON_JIG;
con_sw = DM_DP_SWITCH_UART;
break;
case RT8973A_MUIC_ADC_USB:
- idx = EXTCON_CABLE_USB;
+ id = EXTCON_USB;
con_sw = DM_DP_SWITCH_USB;
break;
case RT8973A_MUIC_ADC_OPEN:
@@ -421,7 +397,7 @@ static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info,
return ret;
/* Change the state of external accessory */
- extcon_set_cable_state(info->edev, cable_names[idx], attached);
+ extcon_set_cable_state_(info->edev, id, attached);
return 0;
}
@@ -643,7 +619,6 @@ static int rt8973a_muic_i2c_probe(struct i2c_client *i2c,
dev_err(info->dev, "failed to allocate memory for extcon\n");
return -ENOMEM;
}
- info->edev->name = np->name;
/* Register extcon device */
ret = devm_extcon_dev_register(info->dev, info->edev);
diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
index 2f93cf307852..817dece23b4c 100644
--- a/drivers/extcon/extcon-sm5502.c
+++ b/drivers/extcon/extcon-sm5502.c
@@ -92,19 +92,11 @@ static struct reg_data sm5502_reg_data[] = {
};
/* List of detectable cables */
-enum {
- EXTCON_CABLE_USB = 0,
- EXTCON_CABLE_USB_HOST,
- EXTCON_CABLE_TA,
-
- EXTCON_CABLE_END,
-};
-
-static const char *sm5502_extcon_cable[] = {
- [EXTCON_CABLE_USB] = "USB",
- [EXTCON_CABLE_USB_HOST] = "USB-Host",
- [EXTCON_CABLE_TA] = "TA",
- NULL,
+static const unsigned int sm5502_extcon_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_TA,
+ EXTCON_NONE,
};
/* Define supported accessory type */
@@ -377,16 +369,12 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
bool attached)
{
static unsigned int prev_cable_type = SM5502_MUIC_ADC_GROUND;
- const char **cable_names = info->edev->supported_cable;
unsigned int cable_type = SM5502_MUIC_ADC_GROUND;
unsigned int con_sw = DM_DP_SWITCH_OPEN;
unsigned int vbus_sw = VBUSIN_SWITCH_OPEN;
- unsigned int idx = 0;
+ unsigned int id;
int ret;
- if (!cable_names)
- return 0;
-
/* Get the type of attached or detached cable */
if (attached)
cable_type = sm5502_muic_get_cable_type(info);
@@ -396,17 +384,17 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
switch (cable_type) {
case SM5502_MUIC_ADC_OPEN_USB:
- idx = EXTCON_CABLE_USB;
+ id = EXTCON_USB;
con_sw = DM_DP_SWITCH_USB;
vbus_sw = VBUSIN_SWITCH_VBUSOUT_WITH_USB;
break;
case SM5502_MUIC_ADC_OPEN_TA:
- idx = EXTCON_CABLE_TA;
+ id = EXTCON_TA;
con_sw = DM_DP_SWITCH_OPEN;
vbus_sw = VBUSIN_SWITCH_VBUSOUT;
break;
case SM5502_MUIC_ADC_OPEN_USB_OTG:
- idx = EXTCON_CABLE_USB_HOST;
+ id = EXTCON_USB_HOST;
con_sw = DM_DP_SWITCH_USB;
vbus_sw = VBUSIN_SWITCH_OPEN;
break;
@@ -422,7 +410,7 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
return ret;
/* Change the state of external accessory */
- extcon_set_cable_state(info->edev, cable_names[idx], attached);
+ extcon_set_cable_state_(info->edev, id, attached);
return 0;
}
@@ -623,7 +611,6 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c,
dev_err(info->dev, "failed to allocate memory for extcon\n");
return -ENOMEM;
}
- info->edev->name = np->name;
/* Register extcon device */
ret = devm_extcon_dev_register(info->dev, info->edev);
diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
index e45d1f13f445..a2a44536a608 100644
--- a/drivers/extcon/extcon-usb-gpio.c
+++ b/drivers/extcon/extcon-usb-gpio.c
@@ -15,6 +15,7 @@
*/
#include <linux/extcon.h>
+#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -38,18 +39,10 @@ struct usb_extcon_info {
struct delayed_work wq_detcable;
};
-/* List of detectable cables */
-enum {
- EXTCON_CABLE_USB = 0,
- EXTCON_CABLE_USB_HOST,
-
- EXTCON_CABLE_END,
-};
-
-static const char *usb_extcon_cable[] = {
- [EXTCON_CABLE_USB] = "USB",
- [EXTCON_CABLE_USB_HOST] = "USB-HOST",
- NULL,
+static const unsigned int usb_extcon_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_NONE,
};
static void usb_extcon_detect_cable(struct work_struct *work)
@@ -67,24 +60,16 @@ static void usb_extcon_detect_cable(struct work_struct *work)
* As we don't have event for USB peripheral cable attached,
* we simulate USB peripheral attach here.
*/
- extcon_set_cable_state(info->edev,
- usb_extcon_cable[EXTCON_CABLE_USB_HOST],
- false);
- extcon_set_cable_state(info->edev,
- usb_extcon_cable[EXTCON_CABLE_USB],
- true);
+ extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, false);
+ extcon_set_cable_state_(info->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(info->edev,
- usb_extcon_cable[EXTCON_CABLE_USB],
- false);
- extcon_set_cable_state(info->edev,
- usb_extcon_cable[EXTCON_CABLE_USB_HOST],
- true);
+ extcon_set_cable_state_(info->edev, EXTCON_USB, false);
+ extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, true);
}
}
@@ -113,7 +98,7 @@ static int usb_extcon_probe(struct platform_device *pdev)
return -ENOMEM;
info->dev = dev;
- info->id_gpiod = devm_gpiod_get(&pdev->dev, "id");
+ info->id_gpiod = devm_gpiod_get(&pdev->dev, "id", GPIOD_IN);
if (IS_ERR(info->id_gpiod)) {
dev_err(dev, "failed to get ID GPIO\n");
return PTR_ERR(info->id_gpiod);
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
index 4c9f165e4a04..76157ab9faf3 100644
--- a/drivers/extcon/extcon.c
+++ b/drivers/extcon/extcon.c
@@ -1,8 +1,11 @@
/*
- * drivers/extcon/extcon_class.c
+ * drivers/extcon/extcon.c - External Connector (extcon) framework.
*
* External connector (extcon) class driver
*
+ * Copyright (C) 2015 Samsung Electronics
+ * Author: Chanwoo Choi <cw00.choi@samsung.com>
+ *
* Copyright (C) 2012 Samsung Electronics
* Author: Donggeun Kim <dg77.kim@samsung.com>
* Author: MyungJoo Ham <myungjoo.ham@samsung.com>
@@ -19,8 +22,7 @@
* but WITHOUT 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/types.h>
@@ -33,36 +35,43 @@
#include <linux/slab.h>
#include <linux/sysfs.h>
-/*
- * extcon_cable_name suggests the standard cable names for commonly used
- * cable types.
- *
- * However, please do not use extcon_cable_name directly for extcon_dev
- * struct's supported_cable pointer unless your device really supports
- * every single port-type of the following cable names. Please choose cable
- * names that are actually used in your extcon device.
- */
-const char extcon_cable_name[][CABLE_NAME_MAX + 1] = {
+#define SUPPORTED_CABLE_MAX 32
+#define CABLE_NAME_MAX 30
+
+static const char *extcon_name[] = {
+ [EXTCON_NONE] = "NONE",
+
+ /* USB external connector */
[EXTCON_USB] = "USB",
- [EXTCON_USB_HOST] = "USB-Host",
+ [EXTCON_USB_HOST] = "USB-HOST",
+
+ /* Charger external connector */
[EXTCON_TA] = "TA",
- [EXTCON_FAST_CHARGER] = "Fast-charger",
- [EXTCON_SLOW_CHARGER] = "Slow-charger",
- [EXTCON_CHARGE_DOWNSTREAM] = "Charge-downstream",
+ [EXTCON_FAST_CHARGER] = "FAST-CHARGER",
+ [EXTCON_SLOW_CHARGER] = "SLOW-CHARGER",
+ [EXTCON_CHARGE_DOWNSTREAM] = "CHARGE-DOWNSTREAM",
+
+ /* Audio/Video external connector */
+ [EXTCON_LINE_IN] = "LINE-IN",
+ [EXTCON_LINE_OUT] = "LINE-OUT",
+ [EXTCON_MICROPHONE] = "MICROPHONE",
+ [EXTCON_HEADPHONE] = "HEADPHONE",
+
[EXTCON_HDMI] = "HDMI",
[EXTCON_MHL] = "MHL",
[EXTCON_DVI] = "DVI",
[EXTCON_VGA] = "VGA",
- [EXTCON_DOCK] = "Dock",
- [EXTCON_LINE_IN] = "Line-in",
- [EXTCON_LINE_OUT] = "Line-out",
- [EXTCON_MIC_IN] = "Microphone",
- [EXTCON_HEADPHONE_OUT] = "Headphone",
- [EXTCON_SPDIF_IN] = "SPDIF-in",
- [EXTCON_SPDIF_OUT] = "SPDIF-out",
- [EXTCON_VIDEO_IN] = "Video-in",
- [EXTCON_VIDEO_OUT] = "Video-out",
- [EXTCON_MECHANICAL] = "Mechanical",
+ [EXTCON_SPDIF_IN] = "SPDIF-IN",
+ [EXTCON_SPDIF_OUT] = "SPDIF-OUT",
+ [EXTCON_VIDEO_IN] = "VIDEO-IN",
+ [EXTCON_VIDEO_OUT] = "VIDEO-OUT",
+
+ /* Etc external connector */
+ [EXTCON_DOCK] = "DOCK",
+ [EXTCON_JIG] = "JIG",
+ [EXTCON_MECHANICAL] = "MECHANICAL",
+
+ NULL,
};
static struct class *extcon_class;
@@ -102,6 +111,51 @@ static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
return 0;
}
+static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id)
+{
+ int i;
+
+ /* Find the the index of extcon cable in edev->supported_cable */
+ for (i = 0; i < edev->max_supported; i++) {
+ if (edev->supported_cable[i] == id)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
+{
+ unsigned int id = EXTCON_NONE;
+ int i = 0;
+
+ if (edev->max_supported == 0)
+ return -EINVAL;
+
+ /* Find the the number of extcon cable */
+ while (extcon_name[i]) {
+ if (!strncmp(extcon_name[i], name, CABLE_NAME_MAX)) {
+ id = i;
+ break;
+ }
+ }
+
+ if (id == EXTCON_NONE)
+ return -EINVAL;
+
+ return find_cable_index_by_id(edev, id);
+}
+
+static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached)
+{
+ if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) {
+ *attached = new ? true : false;
+ return true;
+ }
+
+ return false;
+}
+
static ssize_t state_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -119,11 +173,9 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
if (edev->max_supported == 0)
return sprintf(buf, "%u\n", edev->state);
- for (i = 0; i < SUPPORTED_CABLE_MAX; i++) {
- if (!edev->supported_cable[i])
- break;
+ for (i = 0; i < edev->max_supported; i++) {
count += sprintf(buf + count, "%s=%d\n",
- edev->supported_cable[i],
+ extcon_name[edev->supported_cable[i]],
!!(edev->state & (1 << i)));
}
@@ -155,15 +207,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
{
struct extcon_dev *edev = dev_get_drvdata(dev);
- /* Optional callback given by the user */
- if (edev->print_name) {
- int ret = edev->print_name(edev, buf);
-
- if (ret >= 0)
- return ret;
- }
-
- return sprintf(buf, "%s\n", dev_name(&edev->dev));
+ return sprintf(buf, "%s\n", edev->name);
}
static DEVICE_ATTR_RO(name);
@@ -172,9 +216,10 @@ static ssize_t cable_name_show(struct device *dev,
{
struct extcon_cable *cable = container_of(attr, struct extcon_cable,
attr_name);
+ int i = cable->cable_index;
return sprintf(buf, "%s\n",
- cable->edev->supported_cable[cable->cable_index]);
+ extcon_name[cable->edev->supported_cable[i]]);
}
static ssize_t cable_state_show(struct device *dev,
@@ -211,23 +256,27 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
char *envp[3];
int env_offset = 0;
int length;
+ int index;
unsigned long flags;
+ bool attached;
spin_lock_irqsave(&edev->lock, flags);
if (edev->state != ((edev->state & ~mask) | (state & mask))) {
- u32 old_state = edev->state;
-
if (check_mutually_exclusive(edev, (edev->state & ~mask) |
(state & mask))) {
spin_unlock_irqrestore(&edev->lock, flags);
return -EPERM;
}
+ for (index = 0; index < edev->max_supported; index++) {
+ if (is_extcon_changed(edev->state, state, index, &attached))
+ raw_notifier_call_chain(&edev->nh[index], attached, edev);
+ }
+
edev->state &= ~mask;
edev->state |= state & mask;
- raw_notifier_call_chain(&edev->nh, old_state, edev);
/* This could be in interrupt handler */
prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
if (prop_buf) {
@@ -284,39 +333,19 @@ int extcon_set_state(struct extcon_dev *edev, u32 state)
EXPORT_SYMBOL_GPL(extcon_set_state);
/**
- * extcon_find_cable_index() - Get the cable index based on the cable name.
+ * extcon_get_cable_state_() - Get the status of a specific cable.
* @edev: the extcon device that has the cable.
- * @cable_name: cable name to be searched.
- *
- * Note that accessing a cable state based on cable_index is faster than
- * cable_name because using cable_name induces a loop with strncmp().
- * Thus, when get/set_cable_state is repeatedly used, using cable_index
- * is recommended.
+ * @id: the unique id of each external connector in extcon enumeration.
*/
-int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name)
+int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id)
{
- int i;
+ int index;
- if (edev->supported_cable) {
- for (i = 0; edev->supported_cable[i]; i++) {
- if (!strncmp(edev->supported_cable[i],
- cable_name, CABLE_NAME_MAX))
- return i;
- }
- }
+ index = find_cable_index_by_id(edev, id);
+ if (index < 0)
+ return index;
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(extcon_find_cable_index);
-
-/**
- * extcon_get_cable_state_() - Get the status of a specific cable.
- * @edev: the extcon device that has the cable.
- * @index: cable index that can be retrieved by extcon_find_cable_index().
- */
-int extcon_get_cable_state_(struct extcon_dev *edev, int index)
-{
- if (index < 0 || (edev->max_supported && edev->max_supported <= index))
+ if (edev->max_supported && edev->max_supported <= index)
return -EINVAL;
return !!(edev->state & (1 << index));
@@ -332,7 +361,7 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
*/
int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
{
- return extcon_get_cable_state_(edev, extcon_find_cable_index
+ return extcon_get_cable_state_(edev, find_cable_index_by_name
(edev, cable_name));
}
EXPORT_SYMBOL_GPL(extcon_get_cable_state);
@@ -340,17 +369,22 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state);
/**
* extcon_set_cable_state_() - Set the status of a specific cable.
* @edev: the extcon device that has the cable.
- * @index: cable index that can be retrieved by
- * extcon_find_cable_index().
- * @cable_state: the new cable status. The default semantics is
+ * @id: the unique id of each external connector
+ * in extcon enumeration.
+ * @state: the new cable status. The default semantics is
* true: attached / false: detached.
*/
-int extcon_set_cable_state_(struct extcon_dev *edev,
- int index, bool cable_state)
+int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id,
+ bool cable_state)
{
u32 state;
+ int index;
+
+ index = find_cable_index_by_id(edev, id);
+ if (index < 0)
+ return index;
- if (index < 0 || (edev->max_supported && edev->max_supported <= index))
+ if (edev->max_supported && edev->max_supported <= index)
return -EINVAL;
state = cable_state ? (1 << index) : 0;
@@ -370,7 +404,7 @@ EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
int extcon_set_cable_state(struct extcon_dev *edev,
const char *cable_name, bool cable_state)
{
- return extcon_set_cable_state_(edev, extcon_find_cable_index
+ return extcon_set_cable_state_(edev, find_cable_index_by_name
(edev, cable_name), cable_state);
}
EXPORT_SYMBOL_GPL(extcon_set_cable_state);
@@ -395,29 +429,6 @@ out:
}
EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
-static int _call_per_cable(struct notifier_block *nb, unsigned long val,
- void *ptr)
-{
- struct extcon_specific_cable_nb *obj = container_of(nb,
- struct extcon_specific_cable_nb, internal_nb);
- struct extcon_dev *edev = ptr;
-
- if ((val & (1 << obj->cable_index)) !=
- (edev->state & (1 << obj->cable_index))) {
- bool cable_state = true;
-
- obj->previous_value = val;
-
- if (val & (1 << obj->cable_index))
- cable_state = false;
-
- return obj->user_nb->notifier_call(obj->user_nb,
- cable_state, ptr);
- }
-
- return NOTIFY_OK;
-}
-
/**
* extcon_register_interest() - Register a notifier for a state change of a
* specific cable, not an entier set of cables of a
@@ -456,20 +467,18 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
if (!obj->edev)
return -ENODEV;
- obj->cable_index = extcon_find_cable_index(obj->edev,
- cable_name);
+ obj->cable_index = find_cable_index_by_name(obj->edev,
+ cable_name);
if (obj->cable_index < 0)
return obj->cable_index;
obj->user_nb = nb;
- obj->internal_nb.notifier_call = _call_per_cable;
-
spin_lock_irqsave(&obj->edev->lock, flags);
- ret = raw_notifier_chain_register(&obj->edev->nh,
- &obj->internal_nb);
+ ret = raw_notifier_chain_register(
+ &obj->edev->nh[obj->cable_index],
+ obj->user_nb);
spin_unlock_irqrestore(&obj->edev->lock, flags);
- return ret;
} else {
struct class_dev_iter iter;
struct extcon_dev *extd;
@@ -481,7 +490,7 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
while ((dev = class_dev_iter_next(&iter))) {
extd = dev_get_drvdata(dev);
- if (extcon_find_cable_index(extd, cable_name) < 0)
+ if (find_cable_index_by_name(extd, cable_name) < 0)
continue;
class_dev_iter_exit(&iter);
@@ -489,8 +498,10 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
cable_name, nb);
}
- return -ENODEV;
+ ret = -ENODEV;
}
+
+ return ret;
}
EXPORT_SYMBOL_GPL(extcon_register_interest);
@@ -509,7 +520,8 @@ int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
return -EINVAL;
spin_lock_irqsave(&obj->edev->lock, flags);
- ret = raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
+ ret = raw_notifier_chain_unregister(
+ &obj->edev->nh[obj->cable_index], obj->user_nb);
spin_unlock_irqrestore(&obj->edev->lock, flags);
return ret;
@@ -519,21 +531,24 @@ EXPORT_SYMBOL_GPL(extcon_unregister_interest);
/**
* extcon_register_notifier() - Register a notifiee to get notified by
* any attach status changes from the extcon.
- * @edev: the extcon device.
+ * @edev: the extcon device that has the external connecotr.
+ * @id: the unique id of each external connector in extcon enumeration.
* @nb: a notifier block to be registered.
*
* Note that the second parameter given to the callback of nb (val) is
* "old_state", not the current state. The current state can be retrieved
* by looking at the third pameter (edev pointer)'s state value.
*/
-int extcon_register_notifier(struct extcon_dev *edev,
- struct notifier_block *nb)
+int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
+ struct notifier_block *nb)
{
unsigned long flags;
- int ret;
+ int ret, idx;
+
+ idx = find_cable_index_by_id(edev, id);
spin_lock_irqsave(&edev->lock, flags);
- ret = raw_notifier_chain_register(&edev->nh, nb);
+ ret = raw_notifier_chain_register(&edev->nh[idx], nb);
spin_unlock_irqrestore(&edev->lock, flags);
return ret;
@@ -542,17 +557,20 @@ EXPORT_SYMBOL_GPL(extcon_register_notifier);
/**
* extcon_unregister_notifier() - Unregister a notifiee from the extcon device.
- * @edev: the extcon device.
- * @nb: a registered notifier block to be unregistered.
+ * @edev: the extcon device that has the external connecotr.
+ * @id: the unique id of each external connector in extcon enumeration.
+ * @nb: a notifier block to be registered.
*/
-int extcon_unregister_notifier(struct extcon_dev *edev,
- struct notifier_block *nb)
+int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
+ struct notifier_block *nb)
{
unsigned long flags;
- int ret;
+ int ret, idx;
+
+ idx = find_cable_index_by_id(edev, id);
spin_lock_irqsave(&edev->lock, flags);
- ret = raw_notifier_chain_unregister(&edev->nh, nb);
+ ret = raw_notifier_chain_unregister(&edev->nh[idx], nb);
spin_unlock_irqrestore(&edev->lock, flags);
return ret;
@@ -595,7 +613,7 @@ static void dummy_sysfs_dev_release(struct device *dev)
/*
* extcon_dev_allocate() - Allocate the memory of extcon device.
- * @supported_cable: Array of supported cable names ending with NULL.
+ * @supported_cable: Array of supported extcon ending with EXTCON_NONE.
* If supported_cable is NULL, cable name related APIs
* are disabled.
*
@@ -605,7 +623,7 @@ static void dummy_sysfs_dev_release(struct device *dev)
*
* Return the pointer of extcon device if success or ERR_PTR(err) if fail
*/
-struct extcon_dev *extcon_dev_allocate(const char **supported_cable)
+struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable)
{
struct extcon_dev *edev;
@@ -647,7 +665,7 @@ static void devm_extcon_dev_release(struct device *dev, void *res)
/**
* devm_extcon_dev_allocate - Allocate managed extcon device
* @dev: device owning the extcon device being created
- * @supported_cable: Array of supported cable names ending with NULL.
+ * @supported_cable: Array of supported extcon ending with EXTCON_NONE.
* If supported_cable is NULL, cable name related APIs
* are disabled.
*
@@ -659,7 +677,7 @@ static void devm_extcon_dev_release(struct device *dev, void *res)
* or ERR_PTR(err) if fail
*/
struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
- const char **supported_cable)
+ const unsigned int *supported_cable)
{
struct extcon_dev **ptr, *edev;
@@ -701,6 +719,7 @@ EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
int extcon_dev_register(struct extcon_dev *edev)
{
int ret, index = 0;
+ static atomic_t edev_no = ATOMIC_INIT(-1);
if (!extcon_class) {
ret = create_extcon_class();
@@ -708,30 +727,29 @@ int extcon_dev_register(struct extcon_dev *edev)
return ret;
}
- if (edev->supported_cable) {
- /* Get size of array */
- for (index = 0; edev->supported_cable[index]; index++)
- ;
- edev->max_supported = index;
- } else {
- edev->max_supported = 0;
- }
+ if (!edev->supported_cable)
+ return -EINVAL;
+
+ for (; edev->supported_cable[index] != EXTCON_NONE; index++);
+ edev->max_supported = index;
if (index > SUPPORTED_CABLE_MAX) {
- dev_err(&edev->dev, "extcon: maximum number of supported cables exceeded.\n");
+ dev_err(&edev->dev,
+ "exceed the maximum number of supported cables\n");
return -EINVAL;
}
edev->dev.class = extcon_class;
edev->dev.release = extcon_dev_release;
- edev->name = edev->name ? edev->name : dev_name(edev->dev.parent);
+ edev->name = dev_name(edev->dev.parent);
if (IS_ERR_OR_NULL(edev->name)) {
dev_err(&edev->dev,
"extcon device name is null\n");
return -EINVAL;
}
- dev_set_name(&edev->dev, "%s", edev->name);
+ dev_set_name(&edev->dev, "extcon%lu",
+ (unsigned long)atomic_inc_return(&edev_no));
if (edev->max_supported) {
char buf[10];
@@ -864,7 +882,15 @@ int extcon_dev_register(struct extcon_dev *edev)
spin_lock_init(&edev->lock);
- RAW_INIT_NOTIFIER_HEAD(&edev->nh);
+ edev->nh = devm_kzalloc(&edev->dev,
+ sizeof(*edev->nh) * edev->max_supported, GFP_KERNEL);
+ if (!edev->nh) {
+ ret = -ENOMEM;
+ goto err_dev;
+ }
+
+ for (index = 0; index < edev->max_supported; index++)
+ RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]);
dev_set_drvdata(&edev->dev, edev);
edev->state = 0;
@@ -1044,6 +1070,15 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
#endif /* CONFIG_OF */
EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle);
+/**
+ * extcon_get_edev_name() - Get the name of the extcon device.
+ * @edev: the extcon device
+ */
+const char *extcon_get_edev_name(struct extcon_dev *edev)
+{
+ return !edev ? NULL : edev->name;
+}
+
static int __init extcon_class_init(void)
{
return create_extcon_class();
@@ -1059,6 +1094,7 @@ static void __exit extcon_class_exit(void)
}
module_exit(extcon_class_exit);
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index c22606fe3d44..6bac03999fd4 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -1611,7 +1611,6 @@ static struct scsi_host_template scsi_driver_template = {
.this_id = -1,
.sg_tablesize = SG_ALL,
.use_clustering = ENABLE_CLUSTERING,
- .cmd_per_lun = 1,
.can_queue = 1,
.sdev_attrs = sbp2_scsi_sysfs_attrs,
};
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 210c6e0550d3..4a4b897f9314 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -12,7 +12,8 @@ obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
-CFLAGS_qcom_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
+obj-$(CONFIG_QCOM_SCM) += qcom_scm-32.o
+CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
obj-y += broadcom/
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c
index e0f1cb3d3598..ef76e5eecf0b 100644
--- a/drivers/firmware/dmi-sysfs.c
+++ b/drivers/firmware/dmi-sysfs.c
@@ -566,7 +566,6 @@ static struct kobj_type dmi_sysfs_entry_ktype = {
.default_attrs = dmi_sysfs_entry_attrs,
};
-static struct kobject *dmi_kobj;
static struct kset *dmi_kset;
/* Global count of all instances seen. Only for setup */
@@ -648,17 +647,20 @@ static void cleanup_entry_list(void)
static int __init dmi_sysfs_init(void)
{
- int error = -ENOMEM;
+ int error;
int val;
- /* Set up our directory */
- dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
- if (!dmi_kobj)
+ if (!dmi_kobj) {
+ pr_err("dmi-sysfs: dmi entry is absent.\n");
+ error = -ENODATA;
goto err;
+ }
dmi_kset = kset_create_and_add("entries", NULL, dmi_kobj);
- if (!dmi_kset)
+ if (!dmi_kset) {
+ error = -ENOMEM;
goto err;
+ }
val = 0;
error = dmi_walk(dmi_sysfs_register_handle, &val);
@@ -675,7 +677,6 @@ static int __init dmi_sysfs_init(void)
err:
cleanup_entry_list();
kset_unregister(dmi_kset);
- kobject_put(dmi_kobj);
return error;
}
@@ -685,8 +686,6 @@ static void __exit dmi_sysfs_exit(void)
pr_debug("dmi-sysfs: unloading.\n");
cleanup_entry_list();
kset_unregister(dmi_kset);
- kobject_del(dmi_kobj);
- kobject_put(dmi_kobj);
}
module_init(dmi_sysfs_init);
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 97b1616aa391..ac1ce4a73edf 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -10,6 +10,9 @@
#include <asm/dmi.h>
#include <asm/unaligned.h>
+struct kobject *dmi_kobj;
+EXPORT_SYMBOL_GPL(dmi_kobj);
+
/*
* DMI stands for "Desktop Management Interface". It is part
* of and an antecedent to, SMBIOS, which stands for System
@@ -20,6 +23,9 @@ static const char dmi_empty_string[] = " ";
static u32 dmi_ver __initdata;
static u32 dmi_len;
static u16 dmi_num;
+static u8 smbios_entry_point[32];
+static int smbios_entry_point_size;
+
/*
* Catch too early calls to dmi_check_system():
*/
@@ -80,18 +86,18 @@ static const char * __init dmi_string(const struct dmi_header *dm, u8 s)
* We have to be cautious here. We have seen BIOSes with DMI pointers
* pointing to completely the wrong place for example
*/
-static void dmi_table(u8 *buf,
- void (*decode)(const struct dmi_header *, void *),
- void *private_data)
+static void dmi_decode_table(u8 *buf,
+ void (*decode)(const struct dmi_header *, void *),
+ void *private_data)
{
u8 *data = buf;
int i = 0;
/*
* Stop when we have seen all the items the table claimed to have
- * (SMBIOS < 3.0 only) OR we reach an end-of-table marker OR we run
- * off the end of the table (should never happen but sometimes does
- * on bogus implementations.)
+ * (SMBIOS < 3.0 only) OR we reach an end-of-table marker (SMBIOS
+ * >= 3.0 only) OR we run off the end of the table (should never
+ * happen but sometimes does on bogus implementations.)
*/
while ((!dmi_num || i < dmi_num) &&
(data - buf + sizeof(struct dmi_header)) <= dmi_len) {
@@ -108,15 +114,24 @@ static void dmi_table(u8 *buf,
if (data - buf < dmi_len - 1)
decode(dm, private_data);
+ data += 2;
+ i++;
+
/*
* 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
+ * For tables behind a 64-bit entry point, we have no item
+ * count and no exact table length, so stop on end-of-table
+ * marker. For tables behind a 32-bit entry point, we have
+ * seen OEM structures behind the end-of-table marker on
+ * some systems, so don't trust it.
*/
- if (dm->type == DMI_ENTRY_END_OF_TABLE)
+ if (!dmi_num && dm->type == DMI_ENTRY_END_OF_TABLE)
break;
-
- data += 2;
- i++;
}
+
+ /* Trim DMI table length if needed */
+ if (dmi_len > data - buf)
+ dmi_len = data - buf;
}
static phys_addr_t dmi_base;
@@ -125,16 +140,17 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
void *))
{
u8 *buf;
+ u32 orig_dmi_len = dmi_len;
- buf = dmi_early_remap(dmi_base, dmi_len);
+ buf = dmi_early_remap(dmi_base, orig_dmi_len);
if (buf == NULL)
return -1;
- dmi_table(buf, decode, NULL);
+ dmi_decode_table(buf, decode, NULL);
add_device_randomness(buf, dmi_len);
- dmi_early_unmap(buf, dmi_len);
+ dmi_early_unmap(buf, orig_dmi_len);
return 0;
}
@@ -478,17 +494,19 @@ static int __init dmi_present(const u8 *buf)
if (memcmp(buf, "_SM_", 4) == 0 &&
buf[5] < 32 && dmi_checksum(buf, buf[5])) {
smbios_ver = get_unaligned_be16(buf + 6);
+ smbios_entry_point_size = buf[5];
+ memcpy(smbios_entry_point, buf, smbios_entry_point_size);
/* Some BIOS report weird SMBIOS version, fix that up */
switch (smbios_ver) {
case 0x021F:
case 0x0221:
- pr_debug("SMBIOS version fixup(2.%d->2.%d)\n",
+ pr_debug("SMBIOS version fixup (2.%d->2.%d)\n",
smbios_ver & 0xFF, 3);
smbios_ver = 0x0203;
break;
case 0x0233:
- pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", 51, 6);
+ pr_debug("SMBIOS version fixup (2.%d->2.%d)\n", 51, 6);
smbios_ver = 0x0206;
break;
}
@@ -512,6 +530,9 @@ static int __init dmi_present(const u8 *buf)
pr_info("SMBIOS %d.%d present.\n",
dmi_ver >> 8, dmi_ver & 0xFF);
} else {
+ smbios_entry_point_size = 15;
+ memcpy(smbios_entry_point, buf,
+ smbios_entry_point_size);
pr_info("Legacy DMI %d.%d present.\n",
dmi_ver >> 8, dmi_ver & 0xFF);
}
@@ -533,11 +554,12 @@ static int __init dmi_smbios3_present(const u8 *buf)
{
if (memcmp(buf, "_SM3_", 5) == 0 &&
buf[6] < 32 && dmi_checksum(buf, buf[6])) {
- dmi_ver = get_unaligned_be32(buf + 6);
- dmi_ver &= 0xFFFFFF;
+ dmi_ver = get_unaligned_be32(buf + 6) & 0xFFFFFF;
dmi_num = 0; /* No longer specified */
dmi_len = get_unaligned_le32(buf + 12);
dmi_base = get_unaligned_le64(buf + 16);
+ smbios_entry_point_size = buf[6];
+ memcpy(smbios_entry_point, buf, smbios_entry_point_size);
if (dmi_walk_early(dmi_decode) == 0) {
pr_info("SMBIOS %d.%d.%d present.\n",
@@ -629,6 +651,71 @@ void __init dmi_scan_machine(void)
dmi_initialized = 1;
}
+static ssize_t raw_table_read(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t pos, size_t count)
+{
+ memcpy(buf, attr->private + pos, count);
+ return count;
+}
+
+static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0);
+static BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0);
+
+static int __init dmi_init(void)
+{
+ struct kobject *tables_kobj;
+ u8 *dmi_table;
+ int ret = -ENOMEM;
+
+ if (!dmi_available) {
+ ret = -ENODATA;
+ goto err;
+ }
+
+ /*
+ * Set up dmi directory at /sys/firmware/dmi. This entry should stay
+ * even after farther error, as it can be used by other modules like
+ * dmi-sysfs.
+ */
+ dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
+ if (!dmi_kobj)
+ goto err;
+
+ tables_kobj = kobject_create_and_add("tables", dmi_kobj);
+ if (!tables_kobj)
+ goto err;
+
+ dmi_table = dmi_remap(dmi_base, dmi_len);
+ if (!dmi_table)
+ goto err_tables;
+
+ bin_attr_smbios_entry_point.size = smbios_entry_point_size;
+ bin_attr_smbios_entry_point.private = smbios_entry_point;
+ ret = sysfs_create_bin_file(tables_kobj, &bin_attr_smbios_entry_point);
+ if (ret)
+ goto err_unmap;
+
+ bin_attr_DMI.size = dmi_len;
+ bin_attr_DMI.private = dmi_table;
+ ret = sysfs_create_bin_file(tables_kobj, &bin_attr_DMI);
+ if (!ret)
+ return 0;
+
+ sysfs_remove_bin_file(tables_kobj,
+ &bin_attr_smbios_entry_point);
+ err_unmap:
+ dmi_unmap(dmi_table);
+ err_tables:
+ kobject_del(tables_kobj);
+ kobject_put(tables_kobj);
+ err:
+ pr_err("dmi: Firmware registration failed.\n");
+
+ return ret;
+}
+subsys_initcall(dmi_init);
+
/**
* dmi_set_dump_stack_arch_desc - set arch description for dump_stack()
*
@@ -897,7 +984,7 @@ int dmi_walk(void (*decode)(const struct dmi_header *, void *),
if (buf == NULL)
return -1;
- dmi_table(buf, decode, private_data);
+ dmi_decode_table(buf, decode, private_data);
dmi_unmap(buf);
return 0;
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 8de4da5c9ab6..54071c148340 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -18,6 +18,11 @@ config EFI_VARS
Subsequent efibootmgr releases may be found at:
<http://github.com/vathpela/efibootmgr>
+config EFI_ESRT
+ bool
+ depends on EFI && !IA64
+ default y
+
config EFI_VARS_PSTORE
tristate "Register efivars backend for pstore"
depends on EFI_VARS && PSTORE
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index d8be608a9f3b..6fd3da938717 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_EFI) += efi.o vars.o reboot.o
obj-$(CONFIG_EFI_VARS) += efivars.o
+obj-$(CONFIG_EFI_ESRT) += esrt.o
obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o
obj-$(CONFIG_UEFI_CPER) += cper.o
obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 3061bb8629dc..ca617f40574a 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -39,6 +39,7 @@ struct efi __read_mostly efi = {
.fw_vendor = EFI_INVALID_TABLE_ADDR,
.runtime = EFI_INVALID_TABLE_ADDR,
.config_table = EFI_INVALID_TABLE_ADDR,
+ .esrt = EFI_INVALID_TABLE_ADDR,
};
EXPORT_SYMBOL(efi);
@@ -64,7 +65,7 @@ static int __init parse_efi_cmdline(char *str)
}
early_param("efi", parse_efi_cmdline);
-static struct kobject *efi_kobj;
+struct kobject *efi_kobj;
static struct kobject *efivars_kobj;
/*
@@ -85,10 +86,15 @@ static ssize_t systab_show(struct kobject *kobj,
str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
if (efi.acpi != EFI_INVALID_TABLE_ADDR)
str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
- if (efi.smbios != EFI_INVALID_TABLE_ADDR)
- str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
+ /*
+ * If both SMBIOS and SMBIOS3 entry points are implemented, the
+ * SMBIOS3 entry point shall be preferred, so we list it first to
+ * let applications stop parsing after the first match.
+ */
if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)
str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
+ if (efi.smbios != EFI_INVALID_TABLE_ADDR)
+ str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
@@ -232,6 +238,84 @@ err_put:
subsys_initcall(efisubsys_init);
+/*
+ * Find the efi memory descriptor for a given physical address. Given a
+ * physicall address, determine if it exists within an EFI Memory Map entry,
+ * and if so, populate the supplied memory descriptor with the appropriate
+ * data.
+ */
+int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
+{
+ struct efi_memory_map *map = efi.memmap;
+ void *p, *e;
+
+ if (!efi_enabled(EFI_MEMMAP)) {
+ pr_err_once("EFI_MEMMAP is not enabled.\n");
+ return -EINVAL;
+ }
+
+ if (!map) {
+ pr_err_once("efi.memmap is not set.\n");
+ return -EINVAL;
+ }
+ if (!out_md) {
+ pr_err_once("out_md is null.\n");
+ return -EINVAL;
+ }
+ if (WARN_ON_ONCE(!map->phys_map))
+ return -EINVAL;
+ if (WARN_ON_ONCE(map->nr_map == 0) || WARN_ON_ONCE(map->desc_size == 0))
+ return -EINVAL;
+
+ e = map->phys_map + map->nr_map * map->desc_size;
+ for (p = map->phys_map; p < e; p += map->desc_size) {
+ efi_memory_desc_t *md;
+ u64 size;
+ u64 end;
+
+ /*
+ * If a driver calls this after efi_free_boot_services,
+ * ->map will be NULL, and the target may also not be mapped.
+ * So just always get our own virtual map on the CPU.
+ *
+ */
+ md = early_memremap((phys_addr_t)p, sizeof (*md));
+ if (!md) {
+ pr_err_once("early_memremap(%p, %zu) failed.\n",
+ p, sizeof (*md));
+ return -ENOMEM;
+ }
+
+ if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
+ md->type != EFI_BOOT_SERVICES_DATA &&
+ md->type != EFI_RUNTIME_SERVICES_DATA) {
+ early_memunmap(md, sizeof (*md));
+ continue;
+ }
+
+ size = md->num_pages << EFI_PAGE_SHIFT;
+ end = md->phys_addr + size;
+ if (phys_addr >= md->phys_addr && phys_addr < end) {
+ memcpy(out_md, md, sizeof(*out_md));
+ early_memunmap(md, sizeof (*md));
+ return 0;
+ }
+
+ early_memunmap(md, sizeof (*md));
+ }
+ pr_err_once("requested map not found.\n");
+ return -ENOENT;
+}
+
+/*
+ * Calculate the highest address of an efi memory descriptor.
+ */
+u64 __init efi_mem_desc_end(efi_memory_desc_t *md)
+{
+ u64 size = md->num_pages << EFI_PAGE_SHIFT;
+ u64 end = md->phys_addr + size;
+ return end;
+}
/*
* We can't ioremap data in EFI boot services RAM, because we've already mapped
@@ -274,6 +358,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
{SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
{UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
+ {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
{NULL_GUID, NULL, NULL},
};
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 7b2e0496e0c0..756eca8c4cf8 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -535,7 +535,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
* efivar_create_sysfs_entry - create a new entry in sysfs
* @new_var: efivar entry to create
*
- * Returns 1 on failure, 0 on success
+ * Returns 0 on success, negative error code on failure
*/
static int
efivar_create_sysfs_entry(struct efivar_entry *new_var)
@@ -544,6 +544,7 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
char *short_name;
unsigned long variable_name_size;
efi_char16_t *variable_name;
+ int ret;
variable_name = new_var->var.VariableName;
variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);
@@ -558,7 +559,7 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
short_name = kzalloc(short_name_size, GFP_KERNEL);
if (!short_name)
- return 1;
+ return -ENOMEM;
/* Convert Unicode to normal chars (assume top bits are 0),
ala UTF-8 */
@@ -574,11 +575,11 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
new_var->kobj.kset = efivars_kset;
- i = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
+ ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
NULL, "%s", short_name);
kfree(short_name);
- if (i)
- return 1;
+ if (ret)
+ return ret;
kobject_uevent(&new_var->kobj, KOBJ_ADD);
efivar_entry_add(new_var, &efivar_sysfs_list);
diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c
new file mode 100644
index 000000000000..a5b95d61ae71
--- /dev/null
+++ b/drivers/firmware/efi/esrt.c
@@ -0,0 +1,471 @@
+/*
+ * esrt.c
+ *
+ * This module exports EFI System Resource Table (ESRT) entries into userspace
+ * through the sysfs file system. The ESRT provides a read-only catalog of
+ * system components for which the system accepts firmware upgrades via UEFI's
+ * "Capsule Update" feature. This module allows userland utilities to evaluate
+ * what firmware updates can be applied to this system, and potentially arrange
+ * for those updates to occur.
+ *
+ * Data is currently found below /sys/firmware/efi/esrt/...
+ */
+#define pr_fmt(fmt) "esrt: " fmt
+
+#include <linux/capability.h>
+#include <linux/device.h>
+#include <linux/efi.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/list.h>
+#include <linux/memblock.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+#include <asm/early_ioremap.h>
+
+struct efi_system_resource_entry_v1 {
+ efi_guid_t fw_class;
+ u32 fw_type;
+ u32 fw_version;
+ u32 lowest_supported_fw_version;
+ u32 capsule_flags;
+ u32 last_attempt_version;
+ u32 last_attempt_status;
+};
+
+/*
+ * _count and _version are what they seem like. _max is actually just
+ * accounting info for the firmware when creating the table; it should never
+ * have been exposed to us. To wit, the spec says:
+ * The maximum number of resource array entries that can be within the
+ * table without reallocating the table, must not be zero.
+ * Since there's no guidance about what that means in terms of memory layout,
+ * it means nothing to us.
+ */
+struct efi_system_resource_table {
+ u32 fw_resource_count;
+ u32 fw_resource_count_max;
+ u64 fw_resource_version;
+ u8 entries[];
+};
+
+static phys_addr_t esrt_data;
+static size_t esrt_data_size;
+
+static struct efi_system_resource_table *esrt;
+
+struct esre_entry {
+ union {
+ struct efi_system_resource_entry_v1 *esre1;
+ } esre;
+
+ struct kobject kobj;
+ struct list_head list;
+};
+
+/* global list of esre_entry. */
+static LIST_HEAD(entry_list);
+
+/* entry attribute */
+struct esre_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct esre_entry *entry, char *buf);
+ ssize_t (*store)(struct esre_entry *entry,
+ const char *buf, size_t count);
+};
+
+static struct esre_entry *to_entry(struct kobject *kobj)
+{
+ return container_of(kobj, struct esre_entry, kobj);
+}
+
+static struct esre_attribute *to_attr(struct attribute *attr)
+{
+ return container_of(attr, struct esre_attribute, attr);
+}
+
+static ssize_t esre_attr_show(struct kobject *kobj,
+ struct attribute *_attr, char *buf)
+{
+ struct esre_entry *entry = to_entry(kobj);
+ struct esre_attribute *attr = to_attr(_attr);
+
+ /* Don't tell normal users what firmware versions we've got... */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ return attr->show(entry, buf);
+}
+
+static const struct sysfs_ops esre_attr_ops = {
+ .show = esre_attr_show,
+};
+
+/* Generic ESRT Entry ("ESRE") support. */
+static ssize_t esre_fw_class_show(struct esre_entry *entry, char *buf)
+{
+ char *str = buf;
+
+ efi_guid_to_str(&entry->esre.esre1->fw_class, str);
+ str += strlen(str);
+ str += sprintf(str, "\n");
+
+ return str - buf;
+}
+
+static struct esre_attribute esre_fw_class = __ATTR(fw_class, 0400,
+ esre_fw_class_show, NULL);
+
+#define esre_attr_decl(name, size, fmt) \
+static ssize_t esre_##name##_show(struct esre_entry *entry, char *buf) \
+{ \
+ return sprintf(buf, fmt "\n", \
+ le##size##_to_cpu(entry->esre.esre1->name)); \
+} \
+\
+static struct esre_attribute esre_##name = __ATTR(name, 0400, \
+ esre_##name##_show, NULL)
+
+esre_attr_decl(fw_type, 32, "%u");
+esre_attr_decl(fw_version, 32, "%u");
+esre_attr_decl(lowest_supported_fw_version, 32, "%u");
+esre_attr_decl(capsule_flags, 32, "0x%x");
+esre_attr_decl(last_attempt_version, 32, "%u");
+esre_attr_decl(last_attempt_status, 32, "%u");
+
+static struct attribute *esre1_attrs[] = {
+ &esre_fw_class.attr,
+ &esre_fw_type.attr,
+ &esre_fw_version.attr,
+ &esre_lowest_supported_fw_version.attr,
+ &esre_capsule_flags.attr,
+ &esre_last_attempt_version.attr,
+ &esre_last_attempt_status.attr,
+ NULL
+};
+static void esre_release(struct kobject *kobj)
+{
+ struct esre_entry *entry = to_entry(kobj);
+
+ list_del(&entry->list);
+ kfree(entry);
+}
+
+static struct kobj_type esre1_ktype = {
+ .release = esre_release,
+ .sysfs_ops = &esre_attr_ops,
+ .default_attrs = esre1_attrs,
+};
+
+
+static struct kobject *esrt_kobj;
+static struct kset *esrt_kset;
+
+static int esre_create_sysfs_entry(void *esre, int entry_num)
+{
+ struct esre_entry *entry;
+ char name[20];
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ sprintf(name, "entry%d", entry_num);
+
+ entry->kobj.kset = esrt_kset;
+
+ if (esrt->fw_resource_version == 1) {
+ int rc = 0;
+
+ entry->esre.esre1 = esre;
+ rc = kobject_init_and_add(&entry->kobj, &esre1_ktype, NULL,
+ "%s", name);
+ if (rc) {
+ kfree(entry);
+ return rc;
+ }
+ }
+
+ list_add_tail(&entry->list, &entry_list);
+ return 0;
+}
+
+/* support for displaying ESRT fields at the top level */
+#define esrt_attr_decl(name, size, fmt) \
+static ssize_t esrt_##name##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, char *buf)\
+{ \
+ return sprintf(buf, fmt "\n", le##size##_to_cpu(esrt->name)); \
+} \
+\
+static struct kobj_attribute esrt_##name = __ATTR(name, 0400, \
+ esrt_##name##_show, NULL)
+
+esrt_attr_decl(fw_resource_count, 32, "%u");
+esrt_attr_decl(fw_resource_count_max, 32, "%u");
+esrt_attr_decl(fw_resource_version, 64, "%llu");
+
+static struct attribute *esrt_attrs[] = {
+ &esrt_fw_resource_count.attr,
+ &esrt_fw_resource_count_max.attr,
+ &esrt_fw_resource_version.attr,
+ NULL,
+};
+
+static inline int esrt_table_exists(void)
+{
+ if (!efi_enabled(EFI_CONFIG_TABLES))
+ return 0;
+ if (efi.esrt == EFI_INVALID_TABLE_ADDR)
+ return 0;
+ return 1;
+}
+
+static umode_t esrt_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ if (!esrt_table_exists())
+ return 0;
+ return attr->mode;
+}
+
+static struct attribute_group esrt_attr_group = {
+ .attrs = esrt_attrs,
+ .is_visible = esrt_attr_is_visible,
+};
+
+/*
+ * remap the table, copy it to kmalloced pages, and unmap it.
+ */
+void __init efi_esrt_init(void)
+{
+ void *va;
+ struct efi_system_resource_table tmpesrt;
+ struct efi_system_resource_entry_v1 *v1_entries;
+ size_t size, max, entry_size, entries_size;
+ efi_memory_desc_t md;
+ int rc;
+ phys_addr_t end;
+
+ pr_debug("esrt-init: loading.\n");
+ if (!esrt_table_exists())
+ return;
+
+ rc = efi_mem_desc_lookup(efi.esrt, &md);
+ if (rc < 0) {
+ pr_err("ESRT header is not in the memory map.\n");
+ return;
+ }
+
+ max = efi_mem_desc_end(&md);
+ if (max < efi.esrt) {
+ pr_err("EFI memory descriptor is invalid. (esrt: %p max: %p)\n",
+ (void *)efi.esrt, (void *)max);
+ return;
+ }
+
+ size = sizeof(*esrt);
+ max -= efi.esrt;
+
+ if (max < size) {
+ pr_err("ESRT header doen't fit on single memory map entry. (size: %zu max: %zu)\n",
+ size, max);
+ return;
+ }
+
+ va = early_memremap(efi.esrt, size);
+ if (!va) {
+ pr_err("early_memremap(%p, %zu) failed.\n", (void *)efi.esrt,
+ size);
+ return;
+ }
+
+ memcpy(&tmpesrt, va, sizeof(tmpesrt));
+
+ if (tmpesrt.fw_resource_version == 1) {
+ entry_size = sizeof (*v1_entries);
+ } else {
+ pr_err("Unsupported ESRT version %lld.\n",
+ tmpesrt.fw_resource_version);
+ return;
+ }
+
+ if (tmpesrt.fw_resource_count > 0 && max - size < entry_size) {
+ pr_err("ESRT memory map entry can only hold the header. (max: %zu size: %zu)\n",
+ max - size, entry_size);
+ goto err_memunmap;
+ }
+
+ /*
+ * The format doesn't really give us any boundary to test here,
+ * so I'm making up 128 as the max number of individually updatable
+ * components we support.
+ * 128 should be pretty excessive, but there's still some chance
+ * somebody will do that someday and we'll need to raise this.
+ */
+ if (tmpesrt.fw_resource_count > 128) {
+ pr_err("ESRT says fw_resource_count has very large value %d.\n",
+ tmpesrt.fw_resource_count);
+ goto err_memunmap;
+ }
+
+ /*
+ * We know it can't be larger than N * sizeof() here, and N is limited
+ * by the previous test to a small number, so there's no overflow.
+ */
+ entries_size = tmpesrt.fw_resource_count * entry_size;
+ if (max < size + entries_size) {
+ pr_err("ESRT does not fit on single memory map entry (size: %zu max: %zu)\n",
+ size, max);
+ goto err_memunmap;
+ }
+
+ /* remap it with our (plausible) new pages */
+ early_memunmap(va, size);
+ size += entries_size;
+ va = early_memremap(efi.esrt, size);
+ if (!va) {
+ pr_err("early_memremap(%p, %zu) failed.\n", (void *)efi.esrt,
+ size);
+ return;
+ }
+
+ esrt_data = (phys_addr_t)efi.esrt;
+ esrt_data_size = size;
+
+ end = esrt_data + size;
+ pr_info("Reserving ESRT space from %pa to %pa.\n", &esrt_data, &end);
+ memblock_reserve(esrt_data, esrt_data_size);
+
+ pr_debug("esrt-init: loaded.\n");
+err_memunmap:
+ early_memunmap(va, size);
+}
+
+static int __init register_entries(void)
+{
+ struct efi_system_resource_entry_v1 *v1_entries = (void *)esrt->entries;
+ int i, rc;
+
+ if (!esrt_table_exists())
+ return 0;
+
+ for (i = 0; i < le32_to_cpu(esrt->fw_resource_count); i++) {
+ void *esre = NULL;
+ if (esrt->fw_resource_version == 1) {
+ esre = &v1_entries[i];
+ } else {
+ pr_err("Unsupported ESRT version %lld.\n",
+ esrt->fw_resource_version);
+ return -EINVAL;
+ }
+
+ rc = esre_create_sysfs_entry(esre, i);
+ if (rc < 0) {
+ pr_err("ESRT entry creation failed with error %d.\n",
+ rc);
+ return rc;
+ }
+ }
+ return 0;
+}
+
+static void cleanup_entry_list(void)
+{
+ struct esre_entry *entry, *next;
+
+ list_for_each_entry_safe(entry, next, &entry_list, list) {
+ kobject_put(&entry->kobj);
+ }
+}
+
+static int __init esrt_sysfs_init(void)
+{
+ int error;
+ struct efi_system_resource_table __iomem *ioesrt;
+
+ pr_debug("esrt-sysfs: loading.\n");
+ if (!esrt_data || !esrt_data_size)
+ return -ENOSYS;
+
+ ioesrt = ioremap(esrt_data, esrt_data_size);
+ if (!ioesrt) {
+ pr_err("ioremap(%pa, %zu) failed.\n", &esrt_data,
+ esrt_data_size);
+ return -ENOMEM;
+ }
+
+ esrt = kmalloc(esrt_data_size, GFP_KERNEL);
+ if (!esrt) {
+ pr_err("kmalloc failed. (wanted %zu bytes)\n", esrt_data_size);
+ iounmap(ioesrt);
+ return -ENOMEM;
+ }
+
+ memcpy_fromio(esrt, ioesrt, esrt_data_size);
+
+ esrt_kobj = kobject_create_and_add("esrt", efi_kobj);
+ if (!esrt_kobj) {
+ pr_err("Firmware table registration failed.\n");
+ error = -ENOMEM;
+ goto err;
+ }
+
+ error = sysfs_create_group(esrt_kobj, &esrt_attr_group);
+ if (error) {
+ pr_err("Sysfs attribute export failed with error %d.\n",
+ error);
+ goto err_remove_esrt;
+ }
+
+ esrt_kset = kset_create_and_add("entries", NULL, esrt_kobj);
+ if (!esrt_kset) {
+ pr_err("kset creation failed.\n");
+ error = -ENOMEM;
+ goto err_remove_group;
+ }
+
+ error = register_entries();
+ if (error)
+ goto err_cleanup_list;
+
+ memblock_remove(esrt_data, esrt_data_size);
+
+ pr_debug("esrt-sysfs: loaded.\n");
+
+ return 0;
+err_cleanup_list:
+ cleanup_entry_list();
+ kset_unregister(esrt_kset);
+err_remove_group:
+ sysfs_remove_group(esrt_kobj, &esrt_attr_group);
+err_remove_esrt:
+ kobject_put(esrt_kobj);
+err:
+ kfree(esrt);
+ esrt = NULL;
+ return error;
+}
+
+static void __exit esrt_sysfs_exit(void)
+{
+ pr_debug("esrt-sysfs: unloading.\n");
+ cleanup_entry_list();
+ kset_unregister(esrt_kset);
+ sysfs_remove_group(esrt_kobj, &esrt_attr_group);
+ kfree(esrt);
+ esrt = NULL;
+ kobject_del(esrt_kobj);
+ kobject_put(esrt_kobj);
+}
+
+module_init(esrt_sysfs_init);
+module_exit(esrt_sysfs_exit);
+
+MODULE_AUTHOR("Peter Jones <pjones@redhat.com>");
+MODULE_DESCRIPTION("EFI System Resource Table support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c
index cc016c615c19..5de3ed29282c 100644
--- a/drivers/firmware/memmap.c
+++ b/drivers/firmware/memmap.c
@@ -144,7 +144,9 @@ static struct kobj_type __refdata memmap_ktype = {
*
* Common implementation of firmware_map_add() and firmware_map_add_early()
* which expects a pre-allocated struct firmware_map_entry.
- **/
+ *
+ * Return: 0 always
+ */
static int firmware_map_add_entry(u64 start, u64 end,
const char *type,
struct firmware_map_entry *entry)
@@ -170,7 +172,7 @@ static int firmware_map_add_entry(u64 start, u64 end,
* @entry: removed entry.
*
* The caller must hold map_entries_lock, and release it properly.
- **/
+ */
static inline void firmware_map_remove_entry(struct firmware_map_entry *entry)
{
list_del(&entry->list);
@@ -208,7 +210,7 @@ static inline void remove_sysfs_fw_map_entry(struct firmware_map_entry *entry)
kobject_put(&entry->kobj);
}
-/*
+/**
* firmware_map_find_entry_in_list() - Search memmap entry in a given list.
* @start: Start of the memory range.
* @end: End of the memory range (exclusive).
@@ -236,7 +238,7 @@ firmware_map_find_entry_in_list(u64 start, u64 end, const char *type,
return NULL;
}
-/*
+/**
* firmware_map_find_entry() - Search memmap entry in map_entries.
* @start: Start of the memory range.
* @end: End of the memory range (exclusive).
@@ -254,7 +256,7 @@ firmware_map_find_entry(u64 start, u64 end, const char *type)
return firmware_map_find_entry_in_list(start, end, type, &map_entries);
}
-/*
+/**
* firmware_map_find_entry_bootmem() - Search memmap entry in map_entries_bootmem.
* @start: Start of the memory range.
* @end: End of the memory range (exclusive).
@@ -283,8 +285,8 @@ firmware_map_find_entry_bootmem(u64 start, u64 end, const char *type)
* similar to function firmware_map_add_early(). The only difference is that
* it will create the syfs entry dynamically.
*
- * Returns 0 on success, or -ENOMEM if no memory could be allocated.
- **/
+ * Return: 0 on success, or -ENOMEM if no memory could be allocated.
+ */
int __meminit firmware_map_add_hotplug(u64 start, u64 end, const char *type)
{
struct firmware_map_entry *entry;
@@ -325,8 +327,8 @@ int __meminit firmware_map_add_hotplug(u64 start, u64 end, const char *type)
*
* That function must be called before late_initcall.
*
- * Returns 0 on success, or -ENOMEM if no memory could be allocated.
- **/
+ * Return: 0 on success, or -ENOMEM if no memory could be allocated.
+ */
int __init firmware_map_add_early(u64 start, u64 end, const char *type)
{
struct firmware_map_entry *entry;
@@ -346,8 +348,8 @@ int __init firmware_map_add_early(u64 start, u64 end, const char *type)
*
* removes a firmware mapping entry.
*
- * Returns 0 on success, or -EINVAL if no entry.
- **/
+ * Return: 0 on success, or -EINVAL if no entry.
+ */
int __meminit firmware_map_remove(u64 start, u64 end, const char *type)
{
struct firmware_map_entry *entry;
diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
new file mode 100644
index 000000000000..1bd6f9c34331
--- /dev/null
+++ b/drivers/firmware/qcom_scm-32.c
@@ -0,0 +1,503 @@
+/* Copyright (c) 2010,2015, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2015 Linaro 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 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/qcom_scm.h>
+
+#include <asm/outercache.h>
+#include <asm/cacheflush.h>
+
+#include "qcom_scm.h"
+
+#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
+#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
+#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
+#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
+
+#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
+#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
+#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
+#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
+
+struct qcom_scm_entry {
+ int flag;
+ void *entry;
+};
+
+static struct qcom_scm_entry qcom_scm_wb[] = {
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
+};
+
+static DEFINE_MUTEX(qcom_scm_lock);
+
+/**
+ * struct qcom_scm_command - one SCM command buffer
+ * @len: total available memory for command and response
+ * @buf_offset: start of command buffer
+ * @resp_hdr_offset: start of response buffer
+ * @id: command to be executed
+ * @buf: buffer returned from qcom_scm_get_command_buffer()
+ *
+ * An SCM command is laid out in memory as follows:
+ *
+ * ------------------- <--- struct qcom_scm_command
+ * | command header |
+ * ------------------- <--- qcom_scm_get_command_buffer()
+ * | command buffer |
+ * ------------------- <--- struct qcom_scm_response and
+ * | response header | qcom_scm_command_to_response()
+ * ------------------- <--- qcom_scm_get_response_buffer()
+ * | response buffer |
+ * -------------------
+ *
+ * There can be arbitrary padding between the headers and buffers so
+ * you should always use the appropriate qcom_scm_get_*_buffer() routines
+ * to access the buffers in a safe manner.
+ */
+struct qcom_scm_command {
+ __le32 len;
+ __le32 buf_offset;
+ __le32 resp_hdr_offset;
+ __le32 id;
+ __le32 buf[0];
+};
+
+/**
+ * struct qcom_scm_response - one SCM response buffer
+ * @len: total available memory for response
+ * @buf_offset: start of response data relative to start of qcom_scm_response
+ * @is_complete: indicates if the command has finished processing
+ */
+struct qcom_scm_response {
+ __le32 len;
+ __le32 buf_offset;
+ __le32 is_complete;
+};
+
+/**
+ * alloc_qcom_scm_command() - Allocate an SCM command
+ * @cmd_size: size of the command buffer
+ * @resp_size: size of the response buffer
+ *
+ * Allocate an SCM command, including enough room for the command
+ * and response headers as well as the command and response buffers.
+ *
+ * Returns a valid &qcom_scm_command on success or %NULL if the allocation fails.
+ */
+static struct qcom_scm_command *alloc_qcom_scm_command(size_t cmd_size, size_t resp_size)
+{
+ struct qcom_scm_command *cmd;
+ size_t len = sizeof(*cmd) + sizeof(struct qcom_scm_response) + cmd_size +
+ resp_size;
+ u32 offset;
+
+ cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
+ if (cmd) {
+ cmd->len = cpu_to_le32(len);
+ offset = offsetof(struct qcom_scm_command, buf);
+ cmd->buf_offset = cpu_to_le32(offset);
+ cmd->resp_hdr_offset = cpu_to_le32(offset + cmd_size);
+ }
+ return cmd;
+}
+
+/**
+ * free_qcom_scm_command() - Free an SCM command
+ * @cmd: command to free
+ *
+ * Free an SCM command.
+ */
+static inline void free_qcom_scm_command(struct qcom_scm_command *cmd)
+{
+ kfree(cmd);
+}
+
+/**
+ * qcom_scm_command_to_response() - Get a pointer to a qcom_scm_response
+ * @cmd: command
+ *
+ * Returns a pointer to a response for a command.
+ */
+static inline struct qcom_scm_response *qcom_scm_command_to_response(
+ const struct qcom_scm_command *cmd)
+{
+ return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
+}
+
+/**
+ * qcom_scm_get_command_buffer() - Get a pointer to a command buffer
+ * @cmd: command
+ *
+ * Returns a pointer to the command buffer of a command.
+ */
+static inline void *qcom_scm_get_command_buffer(const struct qcom_scm_command *cmd)
+{
+ return (void *)cmd->buf;
+}
+
+/**
+ * qcom_scm_get_response_buffer() - Get a pointer to a response buffer
+ * @rsp: response
+ *
+ * Returns a pointer to a response buffer of a response.
+ */
+static inline void *qcom_scm_get_response_buffer(const struct qcom_scm_response *rsp)
+{
+ return (void *)rsp + le32_to_cpu(rsp->buf_offset);
+}
+
+static int qcom_scm_remap_error(int err)
+{
+ pr_err("qcom_scm_call failed with error code %d\n", err);
+ switch (err) {
+ case QCOM_SCM_ERROR:
+ return -EIO;
+ case QCOM_SCM_EINVAL_ADDR:
+ case QCOM_SCM_EINVAL_ARG:
+ return -EINVAL;
+ case QCOM_SCM_EOPNOTSUPP:
+ return -EOPNOTSUPP;
+ case QCOM_SCM_ENOMEM:
+ return -ENOMEM;
+ }
+ return -EINVAL;
+}
+
+static u32 smc(u32 cmd_addr)
+{
+ int context_id;
+ register u32 r0 asm("r0") = 1;
+ register u32 r1 asm("r1") = (u32)&context_id;
+ register u32 r2 asm("r2") = cmd_addr;
+ do {
+ asm volatile(
+ __asmeq("%0", "r0")
+ __asmeq("%1", "r0")
+ __asmeq("%2", "r1")
+ __asmeq("%3", "r2")
+#ifdef REQUIRES_SEC
+ ".arch_extension sec\n"
+#endif
+ "smc #0 @ switch to secure world\n"
+ : "=r" (r0)
+ : "r" (r0), "r" (r1), "r" (r2)
+ : "r3");
+ } while (r0 == QCOM_SCM_INTERRUPTED);
+
+ return r0;
+}
+
+static int __qcom_scm_call(const struct qcom_scm_command *cmd)
+{
+ int ret;
+ u32 cmd_addr = virt_to_phys(cmd);
+
+ /*
+ * Flush the command buffer so that the secure world sees
+ * the correct data.
+ */
+ __cpuc_flush_dcache_area((void *)cmd, cmd->len);
+ outer_flush_range(cmd_addr, cmd_addr + cmd->len);
+
+ ret = smc(cmd_addr);
+ if (ret < 0)
+ ret = qcom_scm_remap_error(ret);
+
+ return ret;
+}
+
+static void qcom_scm_inv_range(unsigned long start, unsigned long end)
+{
+ u32 cacheline_size, ctr;
+
+ asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr));
+ cacheline_size = 4 << ((ctr >> 16) & 0xf);
+
+ start = round_down(start, cacheline_size);
+ end = round_up(end, cacheline_size);
+ outer_inv_range(start, end);
+ while (start < end) {
+ asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
+ : "memory");
+ start += cacheline_size;
+ }
+ dsb();
+ isb();
+}
+
+/**
+ * qcom_scm_call() - Send an SCM command
+ * @svc_id: service identifier
+ * @cmd_id: command identifier
+ * @cmd_buf: command buffer
+ * @cmd_len: length of the command buffer
+ * @resp_buf: response buffer
+ * @resp_len: length of the response buffer
+ *
+ * Sends a command to the SCM and waits for the command to finish processing.
+ *
+ * A note on cache maintenance:
+ * Note that any buffers that are expected to be accessed by the secure world
+ * must be flushed before invoking qcom_scm_call and invalidated in the cache
+ * immediately after qcom_scm_call returns. Cache maintenance on the command
+ * and response buffers is taken care of by qcom_scm_call; however, callers are
+ * responsible for any other cached buffers passed over to the secure world.
+ */
+static int qcom_scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf,
+ size_t cmd_len, void *resp_buf, size_t resp_len)
+{
+ int ret;
+ struct qcom_scm_command *cmd;
+ struct qcom_scm_response *rsp;
+ unsigned long start, end;
+
+ cmd = alloc_qcom_scm_command(cmd_len, resp_len);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->id = cpu_to_le32((svc_id << 10) | cmd_id);
+ if (cmd_buf)
+ memcpy(qcom_scm_get_command_buffer(cmd), cmd_buf, cmd_len);
+
+ mutex_lock(&qcom_scm_lock);
+ ret = __qcom_scm_call(cmd);
+ mutex_unlock(&qcom_scm_lock);
+ if (ret)
+ goto out;
+
+ rsp = qcom_scm_command_to_response(cmd);
+ start = (unsigned long)rsp;
+
+ do {
+ qcom_scm_inv_range(start, start + sizeof(*rsp));
+ } while (!rsp->is_complete);
+
+ end = (unsigned long)qcom_scm_get_response_buffer(rsp) + resp_len;
+ qcom_scm_inv_range(start, end);
+
+ if (resp_buf)
+ memcpy(resp_buf, qcom_scm_get_response_buffer(rsp), resp_len);
+out:
+ free_qcom_scm_command(cmd);
+ return ret;
+}
+
+#define SCM_CLASS_REGISTER (0x2 << 8)
+#define SCM_MASK_IRQS BIT(5)
+#define SCM_ATOMIC(svc, cmd, n) (((((svc) << 10)|((cmd) & 0x3ff)) << 12) | \
+ SCM_CLASS_REGISTER | \
+ SCM_MASK_IRQS | \
+ (n & 0xf))
+
+/**
+ * qcom_scm_call_atomic1() - Send an atomic SCM command with one argument
+ * @svc_id: service identifier
+ * @cmd_id: command identifier
+ * @arg1: first argument
+ *
+ * This shall only be used with commands that are guaranteed to be
+ * uninterruptable, atomic and SMP safe.
+ */
+static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
+{
+ int context_id;
+
+ register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 1);
+ register u32 r1 asm("r1") = (u32)&context_id;
+ register u32 r2 asm("r2") = arg1;
+
+ asm volatile(
+ __asmeq("%0", "r0")
+ __asmeq("%1", "r0")
+ __asmeq("%2", "r1")
+ __asmeq("%3", "r2")
+#ifdef REQUIRES_SEC
+ ".arch_extension sec\n"
+#endif
+ "smc #0 @ switch to secure world\n"
+ : "=r" (r0)
+ : "r" (r0), "r" (r1), "r" (r2)
+ : "r3");
+ return r0;
+}
+
+u32 qcom_scm_get_version(void)
+{
+ int context_id;
+ static u32 version = -1;
+ register u32 r0 asm("r0");
+ register u32 r1 asm("r1");
+
+ if (version != -1)
+ return version;
+
+ mutex_lock(&qcom_scm_lock);
+
+ r0 = 0x1 << 8;
+ r1 = (u32)&context_id;
+ do {
+ asm volatile(
+ __asmeq("%0", "r0")
+ __asmeq("%1", "r1")
+ __asmeq("%2", "r0")
+ __asmeq("%3", "r1")
+#ifdef REQUIRES_SEC
+ ".arch_extension sec\n"
+#endif
+ "smc #0 @ switch to secure world\n"
+ : "=r" (r0), "=r" (r1)
+ : "r" (r0), "r" (r1)
+ : "r2", "r3");
+ } while (r0 == QCOM_SCM_INTERRUPTED);
+
+ version = r1;
+ mutex_unlock(&qcom_scm_lock);
+
+ return version;
+}
+EXPORT_SYMBOL(qcom_scm_get_version);
+
+/*
+ * Set the cold/warm boot address for one of the CPU cores.
+ */
+static int qcom_scm_set_boot_addr(u32 addr, int flags)
+{
+ struct {
+ __le32 flags;
+ __le32 addr;
+ } cmd;
+
+ cmd.addr = cpu_to_le32(addr);
+ cmd.flags = cpu_to_le32(flags);
+ return qcom_scm_call(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
+ &cmd, sizeof(cmd), NULL, 0);
+}
+
+/**
+ * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
+ * @entry: Entry point function for the cpus
+ * @cpus: The cpumask of cpus that will use the entry point
+ *
+ * Set the cold boot address of the cpus. Any cpu outside the supported
+ * range would be removed from the cpu present mask.
+ */
+int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
+{
+ int flags = 0;
+ int cpu;
+ int scm_cb_flags[] = {
+ QCOM_SCM_FLAG_COLDBOOT_CPU0,
+ QCOM_SCM_FLAG_COLDBOOT_CPU1,
+ QCOM_SCM_FLAG_COLDBOOT_CPU2,
+ QCOM_SCM_FLAG_COLDBOOT_CPU3,
+ };
+
+ if (!cpus || (cpus && cpumask_empty(cpus)))
+ return -EINVAL;
+
+ for_each_cpu(cpu, cpus) {
+ if (cpu < ARRAY_SIZE(scm_cb_flags))
+ flags |= scm_cb_flags[cpu];
+ else
+ set_cpu_present(cpu, false);
+ }
+
+ return qcom_scm_set_boot_addr(virt_to_phys(entry), flags);
+}
+
+/**
+ * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
+ * @entry: Entry point function for the cpus
+ * @cpus: The cpumask of cpus that will use the entry point
+ *
+ * Set the Linux entry point for the SCM to transfer control to when coming
+ * out of a power down. CPU power down may be executed on cpuidle or hotplug.
+ */
+int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
+{
+ int ret;
+ int flags = 0;
+ int cpu;
+
+ /*
+ * Reassign only if we are switching from hotplug entry point
+ * to cpuidle entry point or vice versa.
+ */
+ for_each_cpu(cpu, cpus) {
+ if (entry == qcom_scm_wb[cpu].entry)
+ continue;
+ flags |= qcom_scm_wb[cpu].flag;
+ }
+
+ /* No change in entry function */
+ if (!flags)
+ return 0;
+
+ ret = qcom_scm_set_boot_addr(virt_to_phys(entry), flags);
+ if (!ret) {
+ for_each_cpu(cpu, cpus)
+ qcom_scm_wb[cpu].entry = entry;
+ }
+
+ return ret;
+}
+
+/**
+ * qcom_scm_cpu_power_down() - Power down the cpu
+ * @flags - Flags to flush cache
+ *
+ * This is an end point to power down cpu. If there was a pending interrupt,
+ * the control would return from this function, otherwise, the cpu jumps to the
+ * warm boot entry point set for this cpu upon reset.
+ */
+void __qcom_scm_cpu_power_down(u32 flags)
+{
+ qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_CMD_TERMINATE_PC,
+ flags & QCOM_SCM_FLUSH_FLAG_MASK);
+}
+
+int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id)
+{
+ int ret;
+ u32 svc_cmd = (svc_id << 10) | cmd_id;
+ u32 ret_val = 0;
+
+ ret = qcom_scm_call(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD, &svc_cmd,
+ sizeof(svc_cmd), &ret_val, sizeof(ret_val));
+ if (ret)
+ return ret;
+
+ return ret_val;
+}
+
+int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
+{
+ if (req_cnt > QCOM_SCM_HDCP_MAX_REQ_CNT)
+ return -ERANGE;
+
+ return qcom_scm_call(QCOM_SCM_SVC_HDCP, QCOM_SCM_CMD_HDCP,
+ req, req_cnt * sizeof(*req), resp, sizeof(*resp));
+}
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 994b50fd997c..45c008d68891 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010,2015, The Linux Foundation. All rights reserved.
* Copyright (C) 2015 Linaro Ltd.
*
* This program is free software; you can redistribute it and/or modify
@@ -16,393 +16,12 @@
* 02110-1301, USA.
*/
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/errno.h>
-#include <linux/err.h>
+#include <linux/cpumask.h>
+#include <linux/export.h>
+#include <linux/types.h>
#include <linux/qcom_scm.h>
-#include <asm/outercache.h>
-#include <asm/cacheflush.h>
-
-
-#define QCOM_SCM_ENOMEM -5
-#define QCOM_SCM_EOPNOTSUPP -4
-#define QCOM_SCM_EINVAL_ADDR -3
-#define QCOM_SCM_EINVAL_ARG -2
-#define QCOM_SCM_ERROR -1
-#define QCOM_SCM_INTERRUPTED 1
-
-#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
-#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
-#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
-#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
-
-#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
-#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
-#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
-#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
-
-struct qcom_scm_entry {
- int flag;
- void *entry;
-};
-
-static struct qcom_scm_entry qcom_scm_wb[] = {
- { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
- { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
- { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
- { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
-};
-
-static DEFINE_MUTEX(qcom_scm_lock);
-
-/**
- * struct qcom_scm_command - one SCM command buffer
- * @len: total available memory for command and response
- * @buf_offset: start of command buffer
- * @resp_hdr_offset: start of response buffer
- * @id: command to be executed
- * @buf: buffer returned from qcom_scm_get_command_buffer()
- *
- * An SCM command is laid out in memory as follows:
- *
- * ------------------- <--- struct qcom_scm_command
- * | command header |
- * ------------------- <--- qcom_scm_get_command_buffer()
- * | command buffer |
- * ------------------- <--- struct qcom_scm_response and
- * | response header | qcom_scm_command_to_response()
- * ------------------- <--- qcom_scm_get_response_buffer()
- * | response buffer |
- * -------------------
- *
- * There can be arbitrary padding between the headers and buffers so
- * you should always use the appropriate qcom_scm_get_*_buffer() routines
- * to access the buffers in a safe manner.
- */
-struct qcom_scm_command {
- __le32 len;
- __le32 buf_offset;
- __le32 resp_hdr_offset;
- __le32 id;
- __le32 buf[0];
-};
-
-/**
- * struct qcom_scm_response - one SCM response buffer
- * @len: total available memory for response
- * @buf_offset: start of response data relative to start of qcom_scm_response
- * @is_complete: indicates if the command has finished processing
- */
-struct qcom_scm_response {
- __le32 len;
- __le32 buf_offset;
- __le32 is_complete;
-};
-
-/**
- * alloc_qcom_scm_command() - Allocate an SCM command
- * @cmd_size: size of the command buffer
- * @resp_size: size of the response buffer
- *
- * Allocate an SCM command, including enough room for the command
- * and response headers as well as the command and response buffers.
- *
- * Returns a valid &qcom_scm_command on success or %NULL if the allocation fails.
- */
-static struct qcom_scm_command *alloc_qcom_scm_command(size_t cmd_size, size_t resp_size)
-{
- struct qcom_scm_command *cmd;
- size_t len = sizeof(*cmd) + sizeof(struct qcom_scm_response) + cmd_size +
- resp_size;
- u32 offset;
-
- cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
- if (cmd) {
- cmd->len = cpu_to_le32(len);
- offset = offsetof(struct qcom_scm_command, buf);
- cmd->buf_offset = cpu_to_le32(offset);
- cmd->resp_hdr_offset = cpu_to_le32(offset + cmd_size);
- }
- return cmd;
-}
-
-/**
- * free_qcom_scm_command() - Free an SCM command
- * @cmd: command to free
- *
- * Free an SCM command.
- */
-static inline void free_qcom_scm_command(struct qcom_scm_command *cmd)
-{
- kfree(cmd);
-}
-
-/**
- * qcom_scm_command_to_response() - Get a pointer to a qcom_scm_response
- * @cmd: command
- *
- * Returns a pointer to a response for a command.
- */
-static inline struct qcom_scm_response *qcom_scm_command_to_response(
- const struct qcom_scm_command *cmd)
-{
- return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
-}
-
-/**
- * qcom_scm_get_command_buffer() - Get a pointer to a command buffer
- * @cmd: command
- *
- * Returns a pointer to the command buffer of a command.
- */
-static inline void *qcom_scm_get_command_buffer(const struct qcom_scm_command *cmd)
-{
- return (void *)cmd->buf;
-}
-
-/**
- * qcom_scm_get_response_buffer() - Get a pointer to a response buffer
- * @rsp: response
- *
- * Returns a pointer to a response buffer of a response.
- */
-static inline void *qcom_scm_get_response_buffer(const struct qcom_scm_response *rsp)
-{
- return (void *)rsp + le32_to_cpu(rsp->buf_offset);
-}
-
-static int qcom_scm_remap_error(int err)
-{
- pr_err("qcom_scm_call failed with error code %d\n", err);
- switch (err) {
- case QCOM_SCM_ERROR:
- return -EIO;
- case QCOM_SCM_EINVAL_ADDR:
- case QCOM_SCM_EINVAL_ARG:
- return -EINVAL;
- case QCOM_SCM_EOPNOTSUPP:
- return -EOPNOTSUPP;
- case QCOM_SCM_ENOMEM:
- return -ENOMEM;
- }
- return -EINVAL;
-}
-
-static u32 smc(u32 cmd_addr)
-{
- int context_id;
- register u32 r0 asm("r0") = 1;
- register u32 r1 asm("r1") = (u32)&context_id;
- register u32 r2 asm("r2") = cmd_addr;
- do {
- asm volatile(
- __asmeq("%0", "r0")
- __asmeq("%1", "r0")
- __asmeq("%2", "r1")
- __asmeq("%3", "r2")
-#ifdef REQUIRES_SEC
- ".arch_extension sec\n"
-#endif
- "smc #0 @ switch to secure world\n"
- : "=r" (r0)
- : "r" (r0), "r" (r1), "r" (r2)
- : "r3");
- } while (r0 == QCOM_SCM_INTERRUPTED);
-
- return r0;
-}
-
-static int __qcom_scm_call(const struct qcom_scm_command *cmd)
-{
- int ret;
- u32 cmd_addr = virt_to_phys(cmd);
-
- /*
- * Flush the command buffer so that the secure world sees
- * the correct data.
- */
- __cpuc_flush_dcache_area((void *)cmd, cmd->len);
- outer_flush_range(cmd_addr, cmd_addr + cmd->len);
-
- ret = smc(cmd_addr);
- if (ret < 0)
- ret = qcom_scm_remap_error(ret);
-
- return ret;
-}
-
-static void qcom_scm_inv_range(unsigned long start, unsigned long end)
-{
- u32 cacheline_size, ctr;
-
- asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr));
- cacheline_size = 4 << ((ctr >> 16) & 0xf);
-
- start = round_down(start, cacheline_size);
- end = round_up(end, cacheline_size);
- outer_inv_range(start, end);
- while (start < end) {
- asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
- : "memory");
- start += cacheline_size;
- }
- dsb();
- isb();
-}
-
-/**
- * qcom_scm_call() - Send an SCM command
- * @svc_id: service identifier
- * @cmd_id: command identifier
- * @cmd_buf: command buffer
- * @cmd_len: length of the command buffer
- * @resp_buf: response buffer
- * @resp_len: length of the response buffer
- *
- * Sends a command to the SCM and waits for the command to finish processing.
- *
- * A note on cache maintenance:
- * Note that any buffers that are expected to be accessed by the secure world
- * must be flushed before invoking qcom_scm_call and invalidated in the cache
- * immediately after qcom_scm_call returns. Cache maintenance on the command
- * and response buffers is taken care of by qcom_scm_call; however, callers are
- * responsible for any other cached buffers passed over to the secure world.
- */
-static int qcom_scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf,
- size_t cmd_len, void *resp_buf, size_t resp_len)
-{
- int ret;
- struct qcom_scm_command *cmd;
- struct qcom_scm_response *rsp;
- unsigned long start, end;
-
- cmd = alloc_qcom_scm_command(cmd_len, resp_len);
- if (!cmd)
- return -ENOMEM;
-
- cmd->id = cpu_to_le32((svc_id << 10) | cmd_id);
- if (cmd_buf)
- memcpy(qcom_scm_get_command_buffer(cmd), cmd_buf, cmd_len);
-
- mutex_lock(&qcom_scm_lock);
- ret = __qcom_scm_call(cmd);
- mutex_unlock(&qcom_scm_lock);
- if (ret)
- goto out;
-
- rsp = qcom_scm_command_to_response(cmd);
- start = (unsigned long)rsp;
-
- do {
- qcom_scm_inv_range(start, start + sizeof(*rsp));
- } while (!rsp->is_complete);
-
- end = (unsigned long)qcom_scm_get_response_buffer(rsp) + resp_len;
- qcom_scm_inv_range(start, end);
-
- if (resp_buf)
- memcpy(resp_buf, qcom_scm_get_response_buffer(rsp), resp_len);
-out:
- free_qcom_scm_command(cmd);
- return ret;
-}
-
-#define SCM_CLASS_REGISTER (0x2 << 8)
-#define SCM_MASK_IRQS BIT(5)
-#define SCM_ATOMIC(svc, cmd, n) (((((svc) << 10)|((cmd) & 0x3ff)) << 12) | \
- SCM_CLASS_REGISTER | \
- SCM_MASK_IRQS | \
- (n & 0xf))
-
-/**
- * qcom_scm_call_atomic1() - Send an atomic SCM command with one argument
- * @svc_id: service identifier
- * @cmd_id: command identifier
- * @arg1: first argument
- *
- * This shall only be used with commands that are guaranteed to be
- * uninterruptable, atomic and SMP safe.
- */
-static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
-{
- int context_id;
-
- register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 1);
- register u32 r1 asm("r1") = (u32)&context_id;
- register u32 r2 asm("r2") = arg1;
-
- asm volatile(
- __asmeq("%0", "r0")
- __asmeq("%1", "r0")
- __asmeq("%2", "r1")
- __asmeq("%3", "r2")
-#ifdef REQUIRES_SEC
- ".arch_extension sec\n"
-#endif
- "smc #0 @ switch to secure world\n"
- : "=r" (r0)
- : "r" (r0), "r" (r1), "r" (r2)
- : "r3");
- return r0;
-}
-
-u32 qcom_scm_get_version(void)
-{
- int context_id;
- static u32 version = -1;
- register u32 r0 asm("r0");
- register u32 r1 asm("r1");
-
- if (version != -1)
- return version;
-
- mutex_lock(&qcom_scm_lock);
-
- r0 = 0x1 << 8;
- r1 = (u32)&context_id;
- do {
- asm volatile(
- __asmeq("%0", "r0")
- __asmeq("%1", "r1")
- __asmeq("%2", "r0")
- __asmeq("%3", "r1")
-#ifdef REQUIRES_SEC
- ".arch_extension sec\n"
-#endif
- "smc #0 @ switch to secure world\n"
- : "=r" (r0), "=r" (r1)
- : "r" (r0), "r" (r1)
- : "r2", "r3");
- } while (r0 == QCOM_SCM_INTERRUPTED);
-
- version = r1;
- mutex_unlock(&qcom_scm_lock);
-
- return version;
-}
-EXPORT_SYMBOL(qcom_scm_get_version);
-
-#define QCOM_SCM_SVC_BOOT 0x1
-#define QCOM_SCM_BOOT_ADDR 0x1
-/*
- * Set the cold/warm boot address for one of the CPU cores.
- */
-static int qcom_scm_set_boot_addr(u32 addr, int flags)
-{
- struct {
- __le32 flags;
- __le32 addr;
- } cmd;
-
- cmd.addr = cpu_to_le32(addr);
- cmd.flags = cpu_to_le32(flags);
- return qcom_scm_call(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR,
- &cmd, sizeof(cmd), NULL, 0);
-}
+#include "qcom_scm.h"
/**
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
@@ -414,26 +33,7 @@ static int qcom_scm_set_boot_addr(u32 addr, int flags)
*/
int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
{
- int flags = 0;
- int cpu;
- int scm_cb_flags[] = {
- QCOM_SCM_FLAG_COLDBOOT_CPU0,
- QCOM_SCM_FLAG_COLDBOOT_CPU1,
- QCOM_SCM_FLAG_COLDBOOT_CPU2,
- QCOM_SCM_FLAG_COLDBOOT_CPU3,
- };
-
- if (!cpus || (cpus && cpumask_empty(cpus)))
- return -EINVAL;
-
- for_each_cpu(cpu, cpus) {
- if (cpu < ARRAY_SIZE(scm_cb_flags))
- flags |= scm_cb_flags[cpu];
- else
- set_cpu_present(cpu, false);
- }
-
- return qcom_scm_set_boot_addr(virt_to_phys(entry), flags);
+ return __qcom_scm_set_cold_boot_addr(entry, cpus);
}
EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);
@@ -447,37 +47,10 @@ EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);
*/
int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
{
- int ret;
- int flags = 0;
- int cpu;
-
- /*
- * Reassign only if we are switching from hotplug entry point
- * to cpuidle entry point or vice versa.
- */
- for_each_cpu(cpu, cpus) {
- if (entry == qcom_scm_wb[cpu].entry)
- continue;
- flags |= qcom_scm_wb[cpu].flag;
- }
-
- /* No change in entry function */
- if (!flags)
- return 0;
-
- ret = qcom_scm_set_boot_addr(virt_to_phys(entry), flags);
- if (!ret) {
- for_each_cpu(cpu, cpus)
- qcom_scm_wb[cpu].entry = entry;
- }
-
- return ret;
+ return __qcom_scm_set_warm_boot_addr(entry, cpus);
}
EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
-#define QCOM_SCM_CMD_TERMINATE_PC 0x2
-#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
-
/**
* qcom_scm_cpu_power_down() - Power down the cpu
* @flags - Flags to flush cache
@@ -488,7 +61,36 @@ EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
*/
void qcom_scm_cpu_power_down(u32 flags)
{
- qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_CMD_TERMINATE_PC,
- flags & QCOM_SCM_FLUSH_FLAG_MASK);
+ __qcom_scm_cpu_power_down(flags);
}
EXPORT_SYMBOL(qcom_scm_cpu_power_down);
+
+/**
+ * qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
+ *
+ * Return true if HDCP is supported, false if not.
+ */
+bool qcom_scm_hdcp_available(void)
+{
+ int ret;
+
+ ret = __qcom_scm_is_call_available(QCOM_SCM_SVC_HDCP,
+ QCOM_SCM_CMD_HDCP);
+
+ return (ret > 0) ? true : false;
+}
+EXPORT_SYMBOL(qcom_scm_hdcp_available);
+
+/**
+ * qcom_scm_hdcp_req() - Send HDCP request.
+ * @req: HDCP request array
+ * @req_cnt: HDCP request array count
+ * @resp: response buffer passed to SCM
+ *
+ * Write HDCP register(s) through SCM.
+ */
+int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
+{
+ return __qcom_scm_hdcp_req(req, req_cnt, resp);
+}
+EXPORT_SYMBOL(qcom_scm_hdcp_req);
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
new file mode 100644
index 000000000000..2cce75c08b99
--- /dev/null
+++ b/drivers/firmware/qcom_scm.h
@@ -0,0 +1,47 @@
+/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QCOM_SCM_INT_H
+#define __QCOM_SCM_INT_H
+
+#define QCOM_SCM_SVC_BOOT 0x1
+#define QCOM_SCM_BOOT_ADDR 0x1
+#define QCOM_SCM_BOOT_ADDR_MC 0x11
+
+#define QCOM_SCM_FLAG_HLOS 0x01
+#define QCOM_SCM_FLAG_COLDBOOT_MC 0x02
+#define QCOM_SCM_FLAG_WARMBOOT_MC 0x04
+extern int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus);
+extern int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
+
+#define QCOM_SCM_CMD_TERMINATE_PC 0x2
+#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
+#define QCOM_SCM_CMD_CORE_HOTPLUGGED 0x10
+extern void __qcom_scm_cpu_power_down(u32 flags);
+
+#define QCOM_SCM_SVC_INFO 0x6
+#define QCOM_IS_CALL_AVAIL_CMD 0x1
+extern int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id);
+
+#define QCOM_SCM_SVC_HDCP 0x11
+#define QCOM_SCM_CMD_HDCP 0x01
+extern int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
+ u32 *resp);
+
+/* common error codes */
+#define QCOM_SCM_ENOMEM -5
+#define QCOM_SCM_EOPNOTSUPP -4
+#define QCOM_SCM_EINVAL_ADDR -3
+#define QCOM_SCM_EINVAL_ARG -2
+#define QCOM_SCM_ERROR -1
+#define QCOM_SCM_INTERRUPTED 1
+
+#endif
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index caefe806db5e..8f1fe739c985 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -126,6 +126,14 @@ config GPIO_BCM_KONA
help
Turn on GPIO support for Broadcom "Kona" chips.
+config GPIO_BRCMSTB
+ tristate "BRCMSTB GPIO support"
+ default y if ARCH_BRCMSTB
+ depends on OF_GPIO && (ARCH_BRCMSTB || COMPILE_TEST)
+ select GPIO_GENERIC
+ help
+ Say yes here to enable GPIO support for Broadcom STB (BCM7XXX) SoCs.
+
config GPIO_CLPS711X
tristate "CLPS711X GPIO support"
depends on ARCH_CLPS711X || COMPILE_TEST
@@ -159,6 +167,14 @@ config GPIO_EP93XX
depends on ARCH_EP93XX
select GPIO_GENERIC
+config GPIO_ETRAXFS
+ bool "Axis ETRAX FS General I/O"
+ depends on CRIS || COMPILE_TEST
+ depends on OF
+ select GPIO_GENERIC
+ help
+ Say yes here to support the GPIO controller on Axis ETRAX FS SoCs.
+
config GPIO_F7188X
tristate "F71869, F71869A, F71882FG and F71889F GPIO support"
depends on X86
@@ -230,6 +246,14 @@ config GPIO_LOONGSON
help
driver for GPIO functionality on Loongson-2F/3A/3B processors.
+config GPIO_LPC18XX
+ bool "NXP LPC18XX/43XX GPIO support"
+ default y if ARCH_LPC18XX
+ depends on OF_GPIO && (ARCH_LPC18XX || COMPILE_TEST)
+ help
+ Select this option to enable GPIO driver for
+ NXP LPC18XX/43XX devices.
+
config GPIO_LYNXPOINT
tristate "Intel Lynxpoint GPIO support"
depends on ACPI && X86
@@ -308,7 +332,7 @@ config GPIO_OCTEON
family of SOCs.
config GPIO_OMAP
- bool "TI OMAP GPIO support" if COMPILE_TEST && !ARCH_OMAP2PLUS
+ tristate "TI OMAP GPIO support" if ARCH_OMAP2PLUS || COMPILE_TEST
default y if ARCH_OMAP
depends on ARM
select GENERIC_IRQ_CHIP
@@ -488,6 +512,17 @@ config GPIO_XILINX
help
Say yes here to support the Xilinx FPGA GPIO device
+config GPIO_XLP
+ tristate "Netlogic XLP GPIO support"
+ depends on CPU_XLP
+ select GPIOLIB_IRQCHIP
+ help
+ This driver provides support for GPIO interface on Netlogic XLP MIPS64
+ SoCs. Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX,
+ XLP9XX and XLP5XX.
+
+ If unsure, say N.
+
config GPIO_XTENSA
bool "Xtensa GPIO32 support"
depends on XTENSA
@@ -505,7 +540,7 @@ config GPIO_ZEVIO
config GPIO_ZYNQ
tristate "Xilinx Zynq GPIO support"
- depends on ARCH_ZYNQ
+ depends on ARCH_ZYNQ || ARCH_ZYNQMP
select GPIOLIB_IRQCHIP
help
Say yes here to support Xilinx Zynq GPIO controller.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index f71bb971329c..f82cd678ce08 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
+obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
@@ -32,6 +33,7 @@ obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
+obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
@@ -44,6 +46,7 @@ obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o
obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
+obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o
obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
@@ -109,6 +112,7 @@ obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o
obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
+obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c
index 449fb46cb8a0..0f3d336d6303 100644
--- a/drivers/gpio/gpio-altera.c
+++ b/drivers/gpio/gpio-altera.c
@@ -107,7 +107,8 @@ static int altera_gpio_irq_set_type(struct irq_data *d,
return -EINVAL;
}
-static unsigned int altera_gpio_irq_startup(struct irq_data *d) {
+static unsigned int altera_gpio_irq_startup(struct irq_data *d)
+{
altera_gpio_irq_unmask(d);
return 0;
diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c
index b164ce837b43..8333f878919c 100644
--- a/drivers/gpio/gpio-bcm-kona.c
+++ b/drivers/gpio/gpio-bcm-kona.c
@@ -122,6 +122,16 @@ static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio,
spin_unlock_irqrestore(&kona_gpio->lock, flags);
}
+static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
+ void __iomem *reg_base = kona_gpio->reg_base;
+ u32 val;
+
+ val = readl(reg_base + GPIO_CONTROL(gpio)) & GPIO_GPCTR0_IOTR_MASK;
+ return val ? GPIOF_DIR_IN : GPIOF_DIR_OUT;
+}
+
static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
{
struct bcm_kona_gpio *kona_gpio;
@@ -135,12 +145,8 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
- /* determine the GPIO pin direction */
- val = readl(reg_base + GPIO_CONTROL(gpio));
- val &= GPIO_GPCTR0_IOTR_MASK;
-
/* this function only applies to output pin */
- if (GPIO_GPCTR0_IOTR_CMD_INPUT == val)
+ if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN)
goto out;
reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id);
@@ -166,13 +172,12 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
- /* determine the GPIO pin direction */
- val = readl(reg_base + GPIO_CONTROL(gpio));
- val &= GPIO_GPCTR0_IOTR_MASK;
+ if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN)
+ reg_offset = GPIO_IN_STATUS(bank_id);
+ else
+ reg_offset = GPIO_OUT_STATUS(bank_id);
/* read the GPIO bank status */
- reg_offset = (GPIO_GPCTR0_IOTR_CMD_INPUT == val) ?
- GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id);
val = readl(reg_base + reg_offset);
spin_unlock_irqrestore(&kona_gpio->lock, flags);
@@ -310,6 +315,7 @@ static struct gpio_chip template_chip = {
.owner = THIS_MODULE,
.request = bcm_kona_gpio_request,
.free = bcm_kona_gpio_free,
+ .get_direction = bcm_kona_gpio_get_dir,
.direction_input = bcm_kona_gpio_direction_input,
.get = bcm_kona_gpio_get,
.direction_output = bcm_kona_gpio_direction_output,
@@ -534,7 +540,7 @@ static void bcm_kona_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
irq_set_chip_data(irq, NULL);
}
-static struct irq_domain_ops bcm_kona_irq_ops = {
+static const struct irq_domain_ops bcm_kona_irq_ops = {
.map = bcm_kona_gpio_irq_map,
.unmap = bcm_kona_gpio_irq_unmap,
.xlate = irq_domain_xlate_twocell,
diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c
new file mode 100644
index 000000000000..7a3cb1fa0a76
--- /dev/null
+++ b/drivers/gpio/gpio-brcmstb.c
@@ -0,0 +1,252 @@
+/*
+ * 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/bitops.h>
+#include <linux/gpio/driver.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/module.h>
+#include <linux/basic_mmio_gpio.h>
+
+#define GIO_BANK_SIZE 0x20
+#define GIO_ODEN(bank) (((bank) * GIO_BANK_SIZE) + 0x00)
+#define GIO_DATA(bank) (((bank) * GIO_BANK_SIZE) + 0x04)
+#define GIO_IODIR(bank) (((bank) * GIO_BANK_SIZE) + 0x08)
+#define GIO_EC(bank) (((bank) * GIO_BANK_SIZE) + 0x0c)
+#define GIO_EI(bank) (((bank) * GIO_BANK_SIZE) + 0x10)
+#define GIO_MASK(bank) (((bank) * GIO_BANK_SIZE) + 0x14)
+#define GIO_LEVEL(bank) (((bank) * GIO_BANK_SIZE) + 0x18)
+#define GIO_STAT(bank) (((bank) * GIO_BANK_SIZE) + 0x1c)
+
+struct brcmstb_gpio_bank {
+ struct list_head node;
+ int id;
+ struct bgpio_chip bgc;
+ struct brcmstb_gpio_priv *parent_priv;
+ u32 width;
+};
+
+struct brcmstb_gpio_priv {
+ struct list_head bank_list;
+ void __iomem *reg_base;
+ int num_banks;
+ struct platform_device *pdev;
+ int gpio_base;
+};
+
+#define MAX_GPIO_PER_BANK 32
+#define GPIO_BANK(gpio) ((gpio) >> 5)
+/* 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);
+ return bank->parent_priv;
+}
+
+/* Make sure that the number of banks matches up between properties */
+static int brcmstb_gpio_sanity_check_banks(struct device *dev,
+ struct device_node *np, struct resource *res)
+{
+ int res_num_banks = resource_size(res) / GIO_BANK_SIZE;
+ int num_banks =
+ of_property_count_u32_elems(np, "brcm,gpio-bank-widths");
+
+ if (res_num_banks != num_banks) {
+ dev_err(dev, "Mismatch in banks: res had %d, bank-widths had %d\n",
+ res_num_banks, num_banks);
+ return -EINVAL;
+ } else {
+ return 0;
+ }
+}
+
+static int brcmstb_gpio_remove(struct platform_device *pdev)
+{
+ struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev);
+ struct list_head *pos;
+ struct brcmstb_gpio_bank *bank;
+ int ret = 0;
+
+ 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");
+ }
+ return ret;
+}
+
+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);
+ int offset;
+
+ if (gc->of_gpio_n_cells != 2) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
+ return -EINVAL;
+
+ offset = gpiospec->args[0] - (gc->base - priv->gpio_base);
+ if (offset >= gc->ngpio)
+ return -EINVAL;
+
+ if (unlikely(offset >= bank->width)) {
+ dev_warn_ratelimited(&priv->pdev->dev,
+ "Received request for invalid GPIO offset %d\n",
+ gpiospec->args[0]);
+ }
+
+ if (flags)
+ *flags = gpiospec->args[1];
+
+ return offset;
+}
+
+static int brcmstb_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ void __iomem *reg_base;
+ struct brcmstb_gpio_priv *priv;
+ struct resource *res;
+ struct property *prop;
+ const __be32 *p;
+ u32 bank_width;
+ int err;
+ static int gpio_base;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(reg_base))
+ return PTR_ERR(reg_base);
+
+ priv->gpio_base = gpio_base;
+ priv->reg_base = reg_base;
+ priv->pdev = pdev;
+
+ INIT_LIST_HEAD(&priv->bank_list);
+ if (brcmstb_gpio_sanity_check_banks(dev, np, res))
+ return -EINVAL;
+
+ 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);
+ if (!bank) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ bank->parent_priv = priv;
+ bank->id = priv->num_banks;
+ if (bank_width <= 0 || bank_width > MAX_GPIO_PER_BANK) {
+ dev_err(dev, "Invalid bank width %d\n", bank_width);
+ goto fail;
+ } else {
+ bank->width = bank_width;
+ }
+
+ /*
+ * 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,
+ reg_base + GIO_DATA(bank->id),
+ NULL, NULL, NULL,
+ reg_base + GIO_IODIR(bank->id), 0);
+ 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;
+ gc->base = gpio_base;
+ gc->of_gpio_n_cells = 2;
+ gc->of_xlate = brcmstb_gpio_of_xlate;
+ /* not all ngpio lines are valid, will use bank width later */
+ gc->ngpio = MAX_GPIO_PER_BANK;
+
+ err = gpiochip_add(gc);
+ if (err) {
+ dev_err(dev, "Could not add gpiochip for bank %d\n",
+ bank->id);
+ goto fail;
+ }
+ gpio_base += gc->ngpio;
+ dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id,
+ gc->base, gc->ngpio, bank->width);
+
+ /* Everything looks good, so add bank to list */
+ list_add(&bank->node, &priv->bank_list);
+
+ priv->num_banks++;
+ }
+
+ dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n",
+ priv->num_banks, priv->gpio_base, gpio_base - 1);
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+
+fail:
+ (void) brcmstb_gpio_remove(pdev);
+ return err;
+}
+
+static const struct of_device_id brcmstb_gpio_of_match[] = {
+ { .compatible = "brcm,brcmstb-gpio" },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, brcmstb_gpio_of_match);
+
+static struct platform_driver brcmstb_gpio_driver = {
+ .driver = {
+ .name = "brcmstb-gpio",
+ .of_match_table = brcmstb_gpio_of_match,
+ },
+ .probe = brcmstb_gpio_probe,
+ .remove = brcmstb_gpio_remove,
+};
+module_platform_driver(brcmstb_gpio_driver);
+
+MODULE_AUTHOR("Gregory Fong");
+MODULE_DESCRIPTION("Driver for Broadcom BRCMSTB SoC UPG GPIO");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c
index 91a7ffe83135..fddd204dc9b6 100644
--- a/drivers/gpio/gpio-crystalcove.c
+++ b/drivers/gpio/gpio-crystalcove.c
@@ -16,6 +16,7 @@
*/
#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/seq_file.h>
@@ -94,9 +95,8 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type)
{
int reg;
- if (gpio == 94) {
+ if (gpio == 94)
return GPIOPANELCTL;
- }
if (reg_type == CTRL_IN) {
if (gpio < 8)
@@ -255,6 +255,7 @@ static struct irq_chip crystalcove_irqchip = {
.irq_set_type = crystalcove_irq_type,
.irq_bus_lock = crystalcove_bus_lock,
.irq_bus_sync_unlock = crystalcove_bus_sync_unlock,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
};
static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c
index dbdb4de82c6d..6685712c15cf 100644
--- a/drivers/gpio/gpio-dln2.c
+++ b/drivers/gpio/gpio-dln2.c
@@ -466,7 +466,6 @@ static int dln2_gpio_probe(struct platform_device *pdev)
dln2->gpio.owner = THIS_MODULE;
dln2->gpio.base = -1;
dln2->gpio.ngpio = pins;
- dln2->gpio.exported = true;
dln2->gpio.can_sleep = true;
dln2->gpio.irq_not_threaded = true;
dln2->gpio.set = dln2_gpio_set;
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
index 3cfcfc620c8e..fbf287307c4c 100644
--- a/drivers/gpio/gpio-em.c
+++ b/drivers/gpio/gpio-em.c
@@ -266,7 +266,7 @@ static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int irq,
return 0;
}
-static struct irq_domain_ops em_gio_irq_domain_ops = {
+static const struct irq_domain_ops em_gio_irq_domain_ops = {
.map = em_gio_irq_domain_map,
.xlate = irq_domain_xlate_twocell,
};
diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c
new file mode 100644
index 000000000000..28071f4a5672
--- /dev/null
+++ b/drivers/gpio/gpio-etraxfs.c
@@ -0,0 +1,176 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/io.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
+#define ETRAX_FS_rw_pa_oe 8
+#define ETRAX_FS_rw_intr_cfg 12
+#define ETRAX_FS_rw_intr_mask 16
+#define ETRAX_FS_rw_ack_intr 20
+#define ETRAX_FS_r_intr 24
+#define ETRAX_FS_rw_pb_dout 32
+#define ETRAX_FS_r_pb_din 36
+#define ETRAX_FS_rw_pb_oe 40
+#define ETRAX_FS_rw_pc_dout 48
+#define ETRAX_FS_r_pc_din 52
+#define ETRAX_FS_rw_pc_oe 56
+#define ETRAX_FS_rw_pd_dout 64
+#define ETRAX_FS_r_pd_din 68
+#define ETRAX_FS_rw_pd_oe 72
+#define ETRAX_FS_rw_pe_dout 80
+#define ETRAX_FS_r_pe_din 84
+#define ETRAX_FS_rw_pe_oe 88
+
+struct etraxfs_gpio_port {
+ const char *label;
+ unsigned int oe;
+ unsigned int dout;
+ unsigned int din;
+ unsigned int ngpio;
+};
+
+struct etraxfs_gpio_info {
+ unsigned int num_ports;
+ const struct etraxfs_gpio_port *ports;
+};
+
+static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = {
+ {
+ .label = "A",
+ .ngpio = 8,
+ .oe = ETRAX_FS_rw_pa_oe,
+ .dout = ETRAX_FS_rw_pa_dout,
+ .din = ETRAX_FS_r_pa_din,
+ },
+ {
+ .label = "B",
+ .ngpio = 18,
+ .oe = ETRAX_FS_rw_pb_oe,
+ .dout = ETRAX_FS_rw_pb_dout,
+ .din = ETRAX_FS_r_pb_din,
+ },
+ {
+ .label = "C",
+ .ngpio = 18,
+ .oe = ETRAX_FS_rw_pc_oe,
+ .dout = ETRAX_FS_rw_pc_dout,
+ .din = ETRAX_FS_r_pc_din,
+ },
+ {
+ .label = "D",
+ .ngpio = 18,
+ .oe = ETRAX_FS_rw_pd_oe,
+ .dout = ETRAX_FS_rw_pd_dout,
+ .din = ETRAX_FS_r_pd_din,
+ },
+ {
+ .label = "E",
+ .ngpio = 18,
+ .oe = ETRAX_FS_rw_pe_oe,
+ .dout = ETRAX_FS_rw_pe_dout,
+ .din = ETRAX_FS_r_pe_din,
+ },
+};
+
+static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = {
+ .num_ports = ARRAY_SIZE(etraxfs_gpio_etraxfs_ports),
+ .ports = etraxfs_gpio_etraxfs_ports,
+};
+
+static int etraxfs_gpio_of_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec,
+ u32 *flags)
+{
+ /*
+ * Port numbers are A to E, and the properties are integers, so we
+ * specify them as 0xA - 0xE.
+ */
+ if (gc->label[0] - 'A' + 0xA != gpiospec->args[2])
+ return -EINVAL;
+
+ return of_gpio_simple_xlate(gc, gpiospec, flags);
+}
+
+static const struct of_device_id etraxfs_gpio_of_table[] = {
+ {
+ .compatible = "axis,etraxfs-gio",
+ .data = &etraxfs_gpio_etraxfs,
+ },
+ {},
+};
+
+static int etraxfs_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct etraxfs_gpio_info *info;
+ const struct of_device_id *match;
+ struct bgpio_chip *chips;
+ struct resource *res;
+ void __iomem *regs;
+ int ret;
+ int i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (!regs)
+ return -ENOMEM;
+
+ match = of_match_node(etraxfs_gpio_of_table, dev->of_node);
+ if (!match)
+ return -EINVAL;
+
+ info = match->data;
+
+ chips = devm_kzalloc(dev, sizeof(*chips) * info->num_ports, GFP_KERNEL);
+ if (!chips)
+ return -ENOMEM;
+
+ for (i = 0; i < info->num_ports; i++) {
+ struct bgpio_chip *bgc = &chips[i];
+ const struct etraxfs_gpio_port *port = &info->ports[i];
+
+ ret = bgpio_init(bgc, dev, 4,
+ regs + port->din, /* dat */
+ regs + port->dout, /* set */
+ NULL, /* clr */
+ regs + port->oe, /* dirout */
+ NULL, /* dirin */
+ BGPIOF_UNREADABLE_REG_SET);
+ if (ret)
+ return ret;
+
+ bgc->gc.ngpio = port->ngpio;
+ bgc->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;
+
+ ret = gpiochip_add(&bgc->gc);
+ if (ret)
+ dev_err(dev, "Unable to register port %s\n",
+ bgc->gc.label);
+ }
+
+ return 0;
+}
+
+static struct platform_driver etraxfs_gpio_driver = {
+ .driver = {
+ .name = "etraxfs-gpio",
+ .of_match_table = of_match_ptr(etraxfs_gpio_of_table),
+ },
+ .probe = etraxfs_gpio_probe,
+};
+
+static int __init etraxfs_gpio_init(void)
+{
+ return platform_driver_register(&etraxfs_gpio_driver);
+}
+
+device_initcall(etraxfs_gpio_init);
diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
index dbda8433c4f7..5e3c4fa67d82 100644
--- a/drivers/gpio/gpio-f7188x.c
+++ b/drivers/gpio/gpio-f7188x.c
@@ -172,7 +172,7 @@ static struct f7188x_gpio_bank f71869a_gpio_bank[] = {
};
static struct f7188x_gpio_bank f71882_gpio_bank[] = {
- F7188X_GPIO_BANK(0 , 8, 0xF0),
+ F7188X_GPIO_BANK(0, 8, 0xF0),
F7188X_GPIO_BANK(10, 8, 0xE0),
F7188X_GPIO_BANK(20, 8, 0xD0),
F7188X_GPIO_BANK(30, 4, 0xC0),
@@ -180,7 +180,7 @@ static struct f7188x_gpio_bank f71882_gpio_bank[] = {
};
static struct f7188x_gpio_bank f71889_gpio_bank[] = {
- F7188X_GPIO_BANK(0 , 7, 0xF0),
+ F7188X_GPIO_BANK(0, 7, 0xF0),
F7188X_GPIO_BANK(10, 7, 0xE0),
F7188X_GPIO_BANK(20, 8, 0xD0),
F7188X_GPIO_BANK(30, 8, 0xC0),
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index b92a690f5765..9bda3727fac1 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -135,6 +135,17 @@ static unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc,
return 1 << (bgc->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);
+
+ if (bgc->dir & pinmask)
+ return bgc->read_reg(bgc->reg_set) & pinmask;
+ else
+ return bgc->read_reg(bgc->reg_dat) & pinmask;
+}
+
static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
@@ -416,7 +427,8 @@ static int bgpio_setup_accessors(struct device *dev,
static int bgpio_setup_io(struct bgpio_chip *bgc,
void __iomem *dat,
void __iomem *set,
- void __iomem *clr)
+ void __iomem *clr,
+ unsigned long flags)
{
bgc->reg_dat = dat;
@@ -437,7 +449,11 @@ static int bgpio_setup_io(struct bgpio_chip *bgc,
bgc->gc.set_multiple = bgpio_set_multiple;
}
- bgc->gc.get = bgpio_get;
+ if (!(flags & BGPIOF_UNREADABLE_REG_SET) &&
+ (flags & BGPIOF_READ_OUTPUT_REG_SET))
+ bgc->gc.get = bgpio_get_set;
+ else
+ bgc->gc.get = bgpio_get;
return 0;
}
@@ -500,7 +516,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
bgc->gc.ngpio = bgc->bits;
bgc->gc.request = bgpio_request;
- ret = bgpio_setup_io(bgc, dat, set, clr);
+ ret = bgpio_setup_io(bgc, dat, set, clr, flags);
if (ret)
return ret;
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 35a02770c8b0..0a8f7617e72e 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -332,7 +332,7 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
spin_unlock_irqrestore(&priv->bgc.lock, flags);
}
-static struct irq_domain_ops grgpio_irq_domain_ops = {
+static const struct irq_domain_ops grgpio_irq_domain_ops = {
.map = grgpio_irq_map,
.unmap = grgpio_irq_unmap,
};
diff --git a/drivers/gpio/gpio-it8761e.c b/drivers/gpio/gpio-it8761e.c
index dadfc245cf09..30a8f24c92c5 100644
--- a/drivers/gpio/gpio-it8761e.c
+++ b/drivers/gpio/gpio-it8761e.c
@@ -123,7 +123,7 @@ static void it8761e_gpio_set(struct gpio_chip *gc,
curr_vals = inb(reg);
if (val)
- outb(curr_vals | (1 << bit) , reg);
+ outb(curr_vals | (1 << bit), reg);
else
outb(curr_vals & ~(1 << bit), reg);
diff --git a/drivers/gpio/gpio-lpc18xx.c b/drivers/gpio/gpio-lpc18xx.c
new file mode 100644
index 000000000000..eb68603136b0
--- /dev/null
+++ b/drivers/gpio/gpio-lpc18xx.c
@@ -0,0 +1,180 @@
+/*
+ * GPIO driver for NXP LPC18xx/43xx.
+ *
+ * Copyright (C) 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/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+
+/* LPC18xx GPIO register offsets */
+#define LPC18XX_REG_DIR(n) (0x2000 + n * sizeof(u32))
+
+#define LPC18XX_MAX_PORTS 8
+#define LPC18XX_PINS_PER_PORT 32
+
+struct lpc18xx_gpio_chip {
+ struct gpio_chip gpio;
+ void __iomem *base;
+ struct clk *clk;
+ 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 int lpc18xx_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(offset);
+}
+
+static void lpc18xx_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(offset);
+}
+
+static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(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);
+ 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);
+ unsigned long flags;
+ u32 port, pin, dir;
+
+ port = offset / LPC18XX_PINS_PER_PORT;
+ pin = offset % LPC18XX_PINS_PER_PORT;
+
+ spin_lock_irqsave(&gc->lock, flags);
+ dir = readl(gc->base + LPC18XX_REG_DIR(port));
+ if (out)
+ dir |= BIT(pin);
+ else
+ dir &= ~BIT(pin);
+ writel(dir, gc->base + LPC18XX_REG_DIR(port));
+ spin_unlock_irqrestore(&gc->lock, flags);
+
+ return 0;
+}
+
+static int lpc18xx_gpio_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ return lpc18xx_gpio_direction(chip, offset, false);
+}
+
+static int lpc18xx_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ lpc18xx_gpio_set(chip, offset, value);
+ return lpc18xx_gpio_direction(chip, offset, true);
+}
+
+static struct gpio_chip lpc18xx_chip = {
+ .label = "lpc18xx/43xx-gpio",
+ .request = lpc18xx_gpio_request,
+ .free = lpc18xx_gpio_free,
+ .direction_input = lpc18xx_gpio_direction_input,
+ .direction_output = lpc18xx_gpio_direction_output,
+ .set = lpc18xx_gpio_set,
+ .get = lpc18xx_gpio_get,
+ .ngpio = LPC18XX_MAX_PORTS * LPC18XX_PINS_PER_PORT,
+ .owner = THIS_MODULE,
+};
+
+static int lpc18xx_gpio_probe(struct platform_device *pdev)
+{
+ struct lpc18xx_gpio_chip *gc;
+ struct resource *res;
+ int ret;
+
+ gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+ if (!gc)
+ return -ENOMEM;
+
+ gc->gpio = lpc18xx_chip;
+ platform_set_drvdata(pdev, gc);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ gc->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gc->base))
+ return PTR_ERR(gc->base);
+
+ gc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(gc->clk)) {
+ dev_err(&pdev->dev, "input clock not found\n");
+ return PTR_ERR(gc->clk);
+ }
+
+ ret = clk_prepare_enable(gc->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable clock\n");
+ return ret;
+ }
+
+ spin_lock_init(&gc->lock);
+
+ gc->gpio.dev = &pdev->dev;
+
+ ret = gpiochip_add(&gc->gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add gpio chip\n");
+ clk_disable_unprepare(gc->clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int lpc18xx_gpio_remove(struct platform_device *pdev)
+{
+ struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&gc->gpio);
+ clk_disable_unprepare(gc->clk);
+
+ return 0;
+}
+
+static const struct of_device_id lpc18xx_gpio_match[] = {
+ { .compatible = "nxp,lpc1850-gpio" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lpc18xx_gpio_match);
+
+static struct platform_driver lpc18xx_gpio_driver = {
+ .probe = lpc18xx_gpio_probe,
+ .remove = lpc18xx_gpio_remove,
+ .driver = {
+ .name = "lpc18xx-gpio",
+ .of_match_table = lpc18xx_gpio_match,
+ },
+};
+module_platform_driver(lpc18xx_gpio_driver);
+
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_DESCRIPTION("GPIO driver for LPC18xx/43xx");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
index 127c755b38dc..153af464c7a7 100644
--- a/drivers/gpio/gpio-lynxpoint.c
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -72,7 +72,7 @@ struct lp_gpio {
*
* per gpio specific registers consist of two 32bit registers per gpio
* (LP_CONFIG1 and LP_CONFIG2), with 94 gpios there's a total of
- * 188 config registes.
+ * 188 config registers.
*
* A simplified view of the register layout look like this:
*
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 0fa4543c5e02..aed4ca9338bc 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -429,6 +429,14 @@ static int max732x_irq_set_type(struct irq_data *d, unsigned int type)
return 0;
}
+static int max732x_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+ struct max732x_chip *chip = irq_data_get_irq_chip_data(data);
+
+ irq_set_irq_wake(chip->client->irq, on);
+ return 0;
+}
+
static struct irq_chip max732x_irq_chip = {
.name = "max732x",
.irq_mask = max732x_irq_mask,
@@ -436,6 +444,7 @@ static struct irq_chip max732x_irq_chip = {
.irq_bus_lock = max732x_irq_bus_lock,
.irq_bus_sync_unlock = max732x_irq_bus_sync_unlock,
.irq_set_type = max732x_irq_set_type,
+ .irq_set_wake = max732x_irq_set_wake,
};
static uint8_t max732x_irq_pending(struct max732x_chip *chip)
@@ -507,12 +516,10 @@ static int max732x_irq_setup(struct max732x_chip *chip,
chip->irq_features = has_irq;
mutex_init(&chip->irq_lock);
- ret = devm_request_threaded_irq(&client->dev,
- client->irq,
- NULL,
- max732x_irq_handler,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- dev_name(&client->dev), chip);
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, max732x_irq_handler, IRQF_ONESHOT |
+ IRQF_TRIGGER_FALLING | IRQF_SHARED,
+ dev_name(&client->dev), chip);
if (ret) {
dev_err(&client->dev, "failed to request irq %d\n",
client->irq);
@@ -521,7 +528,7 @@ static int max732x_irq_setup(struct max732x_chip *chip,
ret = gpiochip_irqchip_add(&chip->gpio_chip,
&max732x_irq_chip,
irq_base,
- handle_edge_irq,
+ handle_simple_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_err(&client->dev,
diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c
index c3ab46e595da..abd8676ce2b6 100644
--- a/drivers/gpio/gpio-moxart.c
+++ b/drivers/gpio/gpio-moxart.c
@@ -39,17 +39,6 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset)
pinctrl_free_gpio(offset);
}
-static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct bgpio_chip *bgc = to_bgpio_chip(chip);
- u32 ret = bgc->read_reg(bgc->reg_dir);
-
- if (ret & BIT(offset))
- return !!(bgc->read_reg(bgc->reg_set) & BIT(offset));
- else
- return !!(bgc->read_reg(bgc->reg_dat) & BIT(offset));
-}
-
static int moxart_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -68,8 +57,9 @@ static int moxart_gpio_probe(struct platform_device *pdev)
return PTR_ERR(base);
ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN,
- base + GPIO_DATA_OUT, NULL,
- base + GPIO_PIN_DIRECTION, NULL, 0);
+ base + GPIO_DATA_OUT, NULL,
+ base + GPIO_PIN_DIRECTION, NULL,
+ BGPIOF_READ_OUTPUT_REG_SET);
if (ret) {
dev_err(&pdev->dev, "bgpio_init failed\n");
return ret;
@@ -78,7 +68,6 @@ static int moxart_gpio_probe(struct platform_device *pdev)
bgc->gc.label = "moxart-gpio";
bgc->gc.request = moxart_gpio_request;
bgc->gc.free = moxart_gpio_free;
- bgc->gc.get = moxart_gpio_get;
bgc->data = bgc->read_reg(bgc->reg_set);
bgc->gc.base = 0;
bgc->gc.ngpio = 32;
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index a65b75161aa4..20aa66f34f6e 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -329,7 +329,7 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq,
return 0;
}
-static struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
+static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
.map = mpc8xxx_gpio_irq_map,
.xlate = irq_domain_xlate_twocell,
};
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 9f7446a7ac64..ec1eb1b7250f 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -131,7 +131,7 @@ static struct mxc_gpio_hwdata *mxc_gpio_hwdata;
#define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge)
#define GPIO_INT_BOTH_EDGES 0x4
-static struct platform_device_id mxc_gpio_devtype[] = {
+static const struct platform_device_id mxc_gpio_devtype[] = {
{
.name = "imx1-gpio",
.driver_data = IMX1_GPIO,
@@ -437,20 +437,20 @@ static int mxc_gpio_probe(struct platform_device *pdev)
irq_set_chained_handler(port->irq, mx2_gpio_irq_handler);
} else {
/* setup one handler for each entry */
- irq_set_chained_handler(port->irq, mx3_gpio_irq_handler);
- irq_set_handler_data(port->irq, port);
- if (port->irq_high > 0) {
+ irq_set_chained_handler_and_data(port->irq,
+ mx3_gpio_irq_handler, port);
+ if (port->irq_high > 0)
/* setup handler for GPIO 16 to 31 */
- irq_set_chained_handler(port->irq_high,
- mx3_gpio_irq_handler);
- irq_set_handler_data(port->irq_high, port);
- }
+ irq_set_chained_handler_and_data(port->irq_high,
+ mx3_gpio_irq_handler,
+ port);
}
err = bgpio_init(&port->bgc, &pdev->dev, 4,
port->base + GPIO_PSR,
port->base + GPIO_DR, NULL,
- port->base + GPIO_GDIR, NULL, 0);
+ port->base + GPIO_GDIR, NULL,
+ BGPIOF_READ_OUTPUT_REG_SET);
if (err)
goto out_bgio;
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index 84cbda6acdda..551d15d7c369 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -239,7 +239,7 @@ static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
return !(dir & mask);
}
-static struct platform_device_id mxs_gpio_ids[] = {
+static const struct platform_device_id mxs_gpio_ids[] = {
{
.name = "imx23-gpio",
.driver_data = IMX23_GPIO,
@@ -320,8 +320,8 @@ static int mxs_gpio_probe(struct platform_device *pdev)
mxs_gpio_init_gc(port, irq_base);
/* setup one handler for each entry */
- irq_set_chained_handler(port->irq, mxs_gpio_irq_handler);
- irq_set_handler_data(port->irq, port);
+ irq_set_chained_handler_and_data(port->irq, mxs_gpio_irq_handler,
+ port);
err = bgpio_init(&port->bgc, &pdev->dev, 4,
port->base + PINCTRL_DIN(port),
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index b232397ad7ec..b0c57d505be7 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -488,9 +488,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
unsigned long flags;
unsigned offset = d->hwirq;
- if (!BANK_USED(bank))
- pm_runtime_get_sync(bank->dev);
-
if (type & ~IRQ_TYPE_SENSE_MASK)
return -EINVAL;
@@ -498,12 +495,18 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
(type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
return -EINVAL;
+ if (!BANK_USED(bank))
+ pm_runtime_get_sync(bank->dev);
+
spin_lock_irqsave(&bank->lock, flags);
retval = omap_set_gpio_triggering(bank, offset, type);
+ if (retval)
+ goto error;
omap_gpio_init_irq(bank, offset);
if (!omap_gpio_is_input(bank, offset)) {
spin_unlock_irqrestore(&bank->lock, flags);
- return -EINVAL;
+ retval = -EINVAL;
+ goto error;
}
spin_unlock_irqrestore(&bank->lock, flags);
@@ -512,6 +515,11 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
__irq_set_handler_locked(d->irq, handle_edge_irq);
+ return 0;
+
+error:
+ if (!BANK_USED(bank))
+ pm_runtime_put(bank->dev);
return retval;
}
@@ -638,15 +646,6 @@ static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset,
return 0;
}
-static void omap_reset_gpio(struct gpio_bank *bank, unsigned offset)
-{
- omap_set_gpio_direction(bank, offset, 1);
- omap_set_gpio_irqenable(bank, offset, 0);
- omap_clear_gpio_irqstatus(bank, offset);
- omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
- omap_clear_gpio_debounce(bank, offset);
-}
-
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
{
@@ -669,14 +668,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
pm_runtime_get_sync(bank->dev);
spin_lock_irqsave(&bank->lock, flags);
- /* Set trigger to none. You need to enable the desired trigger with
- * request_irq() or set_irq_type(). Only do this if the IRQ line has
- * not already been requested.
- */
- if (!LINE_USED(bank->irq_usage, offset)) {
- omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
- omap_enable_gpio_module(bank, offset);
- }
+ omap_enable_gpio_module(bank, offset);
bank->mod_usage |= BIT(offset);
spin_unlock_irqrestore(&bank->lock, flags);
@@ -690,8 +682,11 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
spin_lock_irqsave(&bank->lock, flags);
bank->mod_usage &= ~(BIT(offset));
+ if (!LINE_USED(bank->irq_usage, offset)) {
+ omap_set_gpio_direction(bank, offset, 1);
+ omap_clear_gpio_debounce(bank, offset);
+ }
omap_disable_gpio_module(bank, offset);
- omap_reset_gpio(bank, offset);
spin_unlock_irqrestore(&bank->lock, flags);
/*
@@ -795,11 +790,23 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
pm_runtime_get_sync(bank->dev);
spin_lock_irqsave(&bank->lock, flags);
- omap_gpio_init_irq(bank, offset);
+
+ if (!LINE_USED(bank->mod_usage, offset))
+ omap_set_gpio_direction(bank, offset, 1);
+ else if (!omap_gpio_is_input(bank, offset))
+ goto err;
+ omap_enable_gpio_module(bank, offset);
+ bank->irq_usage |= BIT(offset);
+
spin_unlock_irqrestore(&bank->lock, flags);
omap_gpio_unmask_irq(d);
return 0;
+err:
+ spin_unlock_irqrestore(&bank->lock, flags);
+ if (!BANK_USED(bank))
+ pm_runtime_put(bank->dev);
+ return -EINVAL;
}
static void omap_gpio_irq_shutdown(struct irq_data *d)
@@ -810,8 +817,12 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
spin_lock_irqsave(&bank->lock, flags);
bank->irq_usage &= ~(BIT(offset));
+ omap_set_gpio_irqenable(bank, offset, 0);
+ omap_clear_gpio_irqstatus(bank, offset);
+ omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+ if (!LINE_USED(bank->mod_usage, offset))
+ omap_clear_gpio_debounce(bank, offset);
omap_disable_gpio_module(bank, offset);
- omap_reset_gpio(bank, offset);
spin_unlock_irqrestore(&bank->lock, flags);
/*
@@ -1233,6 +1244,17 @@ static int omap_gpio_probe(struct platform_device *pdev)
return 0;
}
+static int omap_gpio_remove(struct platform_device *pdev)
+{
+ struct gpio_bank *bank = platform_get_drvdata(pdev);
+
+ list_del(&bank->node);
+ gpiochip_remove(&bank->chip);
+ pm_runtime_disable(bank->dev);
+
+ return 0;
+}
+
#ifdef CONFIG_ARCH_OMAP2PLUS
#if defined(CONFIG_PM)
@@ -1418,6 +1440,7 @@ static int omap_gpio_runtime_resume(struct device *dev)
}
#endif /* CONFIG_PM */
+#if IS_BUILTIN(CONFIG_GPIO_OMAP)
void omap2_gpio_prepare_for_idle(int pwr_mode)
{
struct gpio_bank *bank;
@@ -1443,6 +1466,7 @@ void omap2_gpio_resume_after_idle(void)
pm_runtime_get_sync(bank->dev);
}
}
+#endif
#if defined(CONFIG_PM)
static void omap_gpio_init_context(struct gpio_bank *p)
@@ -1598,6 +1622,7 @@ MODULE_DEVICE_TABLE(of, omap_gpio_match);
static struct platform_driver omap_gpio_driver = {
.probe = omap_gpio_probe,
+ .remove = omap_gpio_remove,
.driver = {
.name = "omap_gpio",
.pm = &gpio_pm_ops,
@@ -1615,3 +1640,13 @@ static int __init omap_gpio_drv_reg(void)
return platform_driver_register(&omap_gpio_driver);
}
postcore_initcall(omap_gpio_drv_reg);
+
+static void __exit omap_gpio_exit(void)
+{
+ platform_driver_unregister(&omap_gpio_driver);
+}
+module_exit(omap_gpio_exit);
+
+MODULE_DESCRIPTION("omap gpio driver");
+MODULE_ALIAS("platform:gpio-omap");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index e2da64abbccd..d233eb3b8132 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -443,12 +443,13 @@ static struct irq_chip pca953x_irq_chip = {
.irq_set_type = pca953x_irq_set_type,
};
-static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
+static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
{
u8 cur_stat[MAX_BANK];
u8 old_stat[MAX_BANK];
- u8 pendings = 0;
- u8 trigger[MAX_BANK], triggers = 0;
+ bool pending_seen = false;
+ bool trigger_seen = false;
+ u8 trigger[MAX_BANK];
int ret, i, offset = 0;
switch (chip->chip_type) {
@@ -461,7 +462,7 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
}
ret = pca953x_read_regs(chip, offset, cur_stat);
if (ret)
- return 0;
+ return false;
/* Remove output pins from the equation */
for (i = 0; i < NBANK(chip); i++)
@@ -471,11 +472,12 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
for (i = 0; i < NBANK(chip); i++) {
trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
- triggers += trigger[i];
+ if (trigger[i])
+ trigger_seen = true;
}
- if (!triggers)
- return 0;
+ if (!trigger_seen)
+ return false;
memcpy(chip->irq_stat, cur_stat, NBANK(chip));
@@ -483,10 +485,11 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
(cur_stat[i] & chip->irq_trig_raise[i]);
pending[i] &= trigger[i];
- pendings += pending[i];
+ if (pending[i])
+ pending_seen = true;
}
- return pendings;
+ return pending_seen;
}
static irqreturn_t pca953x_irq_handler(int irq, void *devid)
@@ -630,7 +633,7 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
memset(val, 0, NBANK(chip));
pca953x_write_regs(chip, PCA957X_INVRT, val);
- /* To enable register 6, 7 to controll pull up and pull down */
+ /* To enable register 6, 7 to control pull up and pull down */
memset(val, 0x02, NBANK(chip));
pca953x_write_regs(chip, PCA957X_BKEN, val);
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 945f0cda8529..404f3c61ef9b 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -91,6 +91,8 @@ struct pcf857x {
spinlock_t slock; /* protect irq demux */
unsigned out; /* software latch */
unsigned status; /* current status */
+ unsigned int irq_parent;
+ unsigned irq_enabled; /* enabled irqs */
int (*write)(struct i2c_client *client, unsigned data);
int (*read)(struct i2c_client *client);
@@ -194,7 +196,7 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
* interrupt source, just to avoid bad irqs
*/
- change = (gpio->status ^ status);
+ change = (gpio->status ^ status) & gpio->irq_enabled;
for_each_set_bit(i, &change, gpio->chip.ngpio)
handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i));
gpio->status = status;
@@ -209,29 +211,62 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
*/
static void noop(struct irq_data *data) { }
-static unsigned int noop_ret(struct irq_data *data)
+static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on)
{
- return 0;
+ struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
+
+ int error = 0;
+
+ if (gpio->irq_parent) {
+ error = irq_set_irq_wake(gpio->irq_parent, on);
+ if (error) {
+ dev_dbg(&gpio->client->dev,
+ "irq %u doesn't support irq_set_wake\n",
+ gpio->irq_parent);
+ gpio->irq_parent = 0;
+ }
+ }
+ return error;
}
-static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on)
+static void pcf857x_irq_enable(struct irq_data *data)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
- irq_set_irq_wake(gpio->client->irq, on);
- return 0;
+ gpio->irq_enabled |= (1 << data->hwirq);
+}
+
+static void pcf857x_irq_disable(struct irq_data *data)
+{
+ struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
+
+ gpio->irq_enabled &= ~(1 << data->hwirq);
+}
+
+static void pcf857x_irq_bus_lock(struct irq_data *data)
+{
+ struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
+
+ mutex_lock(&gpio->lock);
+}
+
+static void pcf857x_irq_bus_sync_unlock(struct irq_data *data)
+{
+ struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
+
+ mutex_unlock(&gpio->lock);
}
static struct irq_chip pcf857x_irq_chip = {
.name = "pcf857x",
- .irq_startup = noop_ret,
- .irq_shutdown = noop,
- .irq_enable = noop,
- .irq_disable = noop,
+ .irq_enable = pcf857x_irq_enable,
+ .irq_disable = pcf857x_irq_disable,
.irq_ack = noop,
.irq_mask = noop,
.irq_unmask = noop,
.irq_set_wake = pcf857x_irq_set_wake,
+ .irq_bus_lock = pcf857x_irq_bus_lock,
+ .irq_bus_sync_unlock = pcf857x_irq_bus_sync_unlock,
};
/*-------------------------------------------------------------------------*/
@@ -364,6 +399,7 @@ static int pcf857x_probe(struct i2c_client *client,
gpiochip_set_chained_irqchip(&gpio->chip, &pcf857x_irq_chip,
client->irq, NULL);
+ gpio->irq_parent = client->irq;
}
/* Let platform code set up the GPIOs and their users.
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index fd3977465948..1e14a6c74ed1 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -177,8 +177,17 @@ 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);
-
- irq_set_irq_wake(p->irq_parent, on);
+ int error;
+
+ if (p->irq_parent) {
+ error = irq_set_irq_wake(p->irq_parent, on);
+ if (error) {
+ dev_dbg(&p->pdev->dev,
+ "irq %u doesn't support irq_set_wake\n",
+ p->irq_parent);
+ p->irq_parent = 0;
+ }
+ }
if (!p->clk)
return 0;
diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c
index bec397a60204..3fa22dade243 100644
--- a/drivers/gpio/gpio-sa1100.c
+++ b/drivers/gpio/gpio-sa1100.c
@@ -160,7 +160,7 @@ static int sa1100_gpio_irqdomain_map(struct irq_domain *d,
return 0;
}
-static struct irq_domain_ops sa1100_gpio_irqdomain_ops = {
+static const struct irq_domain_ops sa1100_gpio_irqdomain_ops = {
.map = sa1100_gpio_irqdomain_map,
.xlate = irq_domain_xlate_onetwocell,
};
diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
index d8da36cd8123..65bc9f47a68e 100644
--- a/drivers/gpio/gpio-sodaville.c
+++ b/drivers/gpio/gpio-sodaville.c
@@ -125,7 +125,7 @@ static int sdv_xlate(struct irq_domain *h, struct device_node *node,
return 0;
}
-static struct irq_domain_ops irq_domain_sdv_ops = {
+static const struct irq_domain_ops irq_domain_sdv_ops = {
.xlate = sdv_xlate,
};
diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c
index 202361eb7279..81bdbe7ba2a4 100644
--- a/drivers/gpio/gpio-stp-xway.c
+++ b/drivers/gpio/gpio-stp-xway.c
@@ -58,7 +58,7 @@
#define XWAY_STP_ADSL_MASK 0x3
/* 2 groups of 3 bits can be driven by the phys */
-#define XWAY_STP_PHY_MASK 0x3
+#define XWAY_STP_PHY_MASK 0x7
#define XWAY_STP_PHY1_SHIFT 27
#define XWAY_STP_PHY2_SHIFT 15
@@ -200,7 +200,7 @@ static int xway_stp_hw_init(struct xway_stp *chip)
static int xway_stp_probe(struct platform_device *pdev)
{
struct resource *res;
- const __be32 *shadow, *groups, *dsl, *phy;
+ u32 shadow, groups, dsl, phy;
struct xway_stp *chip;
struct clk *clk;
int ret = 0;
@@ -223,33 +223,28 @@ static int xway_stp_probe(struct platform_device *pdev)
chip->gc.owner = THIS_MODULE;
/* store the shadow value if one was passed by the devicetree */
- shadow = of_get_property(pdev->dev.of_node, "lantiq,shadow", NULL);
- if (shadow)
- chip->shadow = be32_to_cpu(*shadow);
+ if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow))
+ chip->shadow = shadow;
/* find out which gpio groups should be enabled */
- groups = of_get_property(pdev->dev.of_node, "lantiq,groups", NULL);
- if (groups)
- chip->groups = be32_to_cpu(*groups) & XWAY_STP_GROUP_MASK;
+ if (!of_property_read_u32(pdev->dev.of_node, "lantiq,groups", &groups))
+ chip->groups = groups & XWAY_STP_GROUP_MASK;
else
chip->groups = XWAY_STP_GROUP0;
chip->gc.ngpio = fls(chip->groups) * 8;
/* find out which gpios are controlled by the dsl core */
- dsl = of_get_property(pdev->dev.of_node, "lantiq,dsl", NULL);
- if (dsl)
- chip->dsl = be32_to_cpu(*dsl) & XWAY_STP_ADSL_MASK;
+ if (!of_property_read_u32(pdev->dev.of_node, "lantiq,dsl", &dsl))
+ chip->dsl = dsl & XWAY_STP_ADSL_MASK;
/* find out which gpios are controlled by the phys */
if (of_machine_is_compatible("lantiq,ar9") ||
of_machine_is_compatible("lantiq,gr9") ||
of_machine_is_compatible("lantiq,vr9")) {
- phy = of_get_property(pdev->dev.of_node, "lantiq,phy1", NULL);
- if (phy)
- chip->phy1 = be32_to_cpu(*phy) & XWAY_STP_PHY_MASK;
- phy = of_get_property(pdev->dev.of_node, "lantiq,phy2", NULL);
- if (phy)
- chip->phy2 = be32_to_cpu(*phy) & XWAY_STP_PHY_MASK;
+ if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy1", &phy))
+ chip->phy1 = phy & XWAY_STP_PHY_MASK;
+ if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy2", &phy))
+ chip->phy2 = phy & XWAY_STP_PHY_MASK;
}
/* check which edge trigger we should use, default to a falling edge */
diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c
index 46b89614aa91..12c99d969b98 100644
--- a/drivers/gpio/gpio-tb10x.c
+++ b/drivers/gpio/gpio-tb10x.c
@@ -292,7 +292,6 @@ static int tb10x_gpio_remove(struct platform_device *pdev)
BIT(tb10x_gpio->gc.ngpio) - 1, 0, 0);
kfree(tb10x_gpio->domain->gc);
irq_domain_remove(tb10x_gpio->domain);
- free_irq(tb10x_gpio->irq, tb10x_gpio);
}
gpiochip_remove(&tb10x_gpio->gc);
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 1741981d53c8..9b25c90f725c 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -288,7 +288,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
tegra_gpio_writel(1 << pin, GPIO_INT_CLR(gpio));
/* if gpio is edge triggered, clear condition
- * before executing the hander so that we don't
+ * before executing the handler so that we don't
* miss edges
*/
if (lvl & (0x100 << pin)) {
@@ -515,8 +515,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)
for (i = 0; i < tegra_gpio_bank_count; i++) {
bank = &tegra_gpio_banks[i];
- irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler);
- irq_set_handler_data(bank->irq, bank);
+ irq_set_chained_handler_and_data(bank->irq,
+ tegra_gpio_irq_handler, bank);
for (j = 0; j < 4; j++)
spin_lock_init(&bank->lvl_lock[j]);
diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c
index 92fbabd82879..b29a102d136b 100644
--- a/drivers/gpio/gpio-ts5500.c
+++ b/drivers/gpio/gpio-ts5500.c
@@ -440,7 +440,7 @@ static int ts5500_dio_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_device_id ts5500_dio_ids[] = {
+static const struct platform_device_id ts5500_dio_ids[] = {
{ "ts5500-dio1", TS5500_DIO1 },
{ "ts5500-dio2", TS5500_DIO2 },
{ "ts5500-dio-lcd", TS5500_LCD },
diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c
index fb9d29a5d584..d57068b9083e 100644
--- a/drivers/gpio/gpio-xgene-sb.c
+++ b/drivers/gpio/gpio-xgene-sb.c
@@ -25,8 +25,11 @@
#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"
+
#define XGENE_MAX_GPIO_DS 22
#define XGENE_MAX_GPIO_DS_IRQ 6
@@ -112,7 +115,6 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!priv->irq)
return -ENOMEM;
- memset(priv->irq, 0, sizeof(u32) * XGENE_MAX_GPIO_DS);
for (i = 0; i < priv->nirq; i++) {
priv->irq[default_lines[i]] = platform_get_irq(pdev, i);
@@ -129,6 +131,11 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
else
dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n");
+ if (priv->nirq > 0) {
+ /* Register interrupt handlers for gpio signaled acpi events */
+ acpi_gpiochip_request_interrupts(&priv->bgc.gc);
+ }
+
return ret;
}
@@ -136,6 +143,10 @@ 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);
+ }
+
return bgpio_remove(&priv->bgc);
}
@@ -145,10 +156,19 @@ static const struct of_device_id xgene_gpio_sb_of_match[] = {
};
MODULE_DEVICE_TABLE(of, xgene_gpio_sb_of_match);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_gpio_sb_acpi_match[] = {
+ {"APMC0D15", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, xgene_gpio_sb_acpi_match);
+#endif
+
static struct platform_driver xgene_gpio_sb_driver = {
.driver = {
.name = "xgene-gpio-sb",
.of_match_table = xgene_gpio_sb_of_match,
+ .acpi_match_table = ACPI_PTR(xgene_gpio_sb_acpi_match),
},
.probe = xgene_gpio_sb_probe,
.remove = xgene_gpio_sb_remove,
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index 61243d177740..77fe5d3cb105 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -41,10 +41,10 @@
/**
* struct xgpio_instance - Stores information about GPIO device
* @mmchip: OF GPIO chip for memory mapped banks
+ * @gpio_width: GPIO width for every channel
* @gpio_state: GPIO state shadow register
* @gpio_dir: GPIO direction shadow register
* @gpio_lock: Lock used for synchronization
- * @inited: True if the port has been inited
*/
struct xgpio_instance {
struct of_mm_gpio_chip mmchip;
@@ -231,6 +231,8 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
* @pdev: pointer to the platform device
*
* This function remove gpiochips and frees all the allocated resources.
+ *
+ * Return: 0 always
*/
static int xgpio_remove(struct platform_device *pdev)
{
diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c
new file mode 100644
index 000000000000..9bdab7203d65
--- /dev/null
+++ b/drivers/gpio/gpio-xlp.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2003-2015 Broadcom 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/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+/*
+ * XLP GPIO has multiple 32 bit registers for each feature where each register
+ * controls 32 pins. So, pins up to 64 require 2 32-bit registers and up to 96
+ * require 3 32-bit registers for each feature.
+ * Here we only define offset of the first register for each feature. Offset of
+ * the registers for pins greater than 32 can be calculated as following(Use
+ * GPIO_INT_STAT as example):
+ *
+ * offset = (gpio / XLP_GPIO_REGSZ) * 4;
+ * reg_addr = addr + offset;
+ *
+ * where addr is base address of the that feature register and gpio is the pin.
+ */
+#define GPIO_OUTPUT_EN 0x00
+#define GPIO_PADDRV 0x08
+#define GPIO_INT_EN00 0x18
+#define GPIO_INT_EN10 0x20
+#define GPIO_INT_EN20 0x28
+#define GPIO_INT_EN30 0x30
+#define GPIO_INT_POL 0x38
+#define GPIO_INT_TYPE 0x40
+#define GPIO_INT_STAT 0x48
+
+#define GPIO_9XX_BYTESWAP 0X00
+#define GPIO_9XX_CTRL 0X04
+#define GPIO_9XX_OUTPUT_EN 0x14
+#define GPIO_9XX_PADDRV 0x24
+/*
+ * Only for 4 interrupt enable reg are defined for now,
+ * total reg available are 12.
+ */
+#define GPIO_9XX_INT_EN00 0x44
+#define GPIO_9XX_INT_EN10 0x54
+#define GPIO_9XX_INT_EN20 0x64
+#define GPIO_9XX_INT_EN30 0x74
+#define GPIO_9XX_INT_POL 0x104
+#define GPIO_9XX_INT_TYPE 0x114
+#define GPIO_9XX_INT_STAT 0x124
+
+#define GPIO_3XX_INT_EN00 0x18
+#define GPIO_3XX_INT_EN10 0x20
+#define GPIO_3XX_INT_EN20 0x28
+#define GPIO_3XX_INT_EN30 0x30
+#define GPIO_3XX_INT_POL 0x78
+#define GPIO_3XX_INT_TYPE 0x80
+#define GPIO_3XX_INT_STAT 0x88
+
+/* Interrupt type register mask */
+#define XLP_GPIO_IRQ_TYPE_LVL 0x0
+#define XLP_GPIO_IRQ_TYPE_EDGE 0x1
+
+/* Interrupt polarity register mask */
+#define XLP_GPIO_IRQ_POL_HIGH 0x0
+#define XLP_GPIO_IRQ_POL_LOW 0x1
+
+#define XLP_GPIO_REGSZ 32
+#define XLP_GPIO_IRQ_BASE 768
+#define XLP_MAX_NR_GPIO 96
+
+/* XLP variants supported by this driver */
+enum {
+ XLP_GPIO_VARIANT_XLP832 = 1,
+ XLP_GPIO_VARIANT_XLP316,
+ XLP_GPIO_VARIANT_XLP208,
+ XLP_GPIO_VARIANT_XLP980,
+ XLP_GPIO_VARIANT_XLP532
+};
+
+struct xlp_gpio_priv {
+ struct gpio_chip chip;
+ DECLARE_BITMAP(gpio_enabled_mask, XLP_MAX_NR_GPIO);
+ void __iomem *gpio_intr_en; /* pointer to first intr enable reg */
+ void __iomem *gpio_intr_stat; /* pointer to first intr status reg */
+ void __iomem *gpio_intr_type; /* pointer to first intr type reg */
+ void __iomem *gpio_intr_pol; /* pointer to first intr polarity reg */
+ void __iomem *gpio_out_en; /* pointer to first output enable reg */
+ void __iomem *gpio_paddrv; /* pointer to first pad drive reg */
+ 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;
+
+ pos = gpio % XLP_GPIO_REGSZ;
+ regset = (gpio / XLP_GPIO_REGSZ) * 4;
+ return !!(readl(addr + regset) & BIT(pos));
+}
+
+static void xlp_gpio_set_reg(void __iomem *addr, unsigned gpio, int state)
+{
+ u32 value, pos, regset;
+
+ pos = gpio % XLP_GPIO_REGSZ;
+ regset = (gpio / XLP_GPIO_REGSZ) * 4;
+ value = readl(addr + regset);
+
+ if (state)
+ value |= BIT(pos);
+ else
+ value &= ~BIT(pos);
+
+ writel(value, addr + regset);
+}
+
+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);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0);
+ __clear_bit(d->hwirq, priv->gpio_enabled_mask);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+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);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0);
+ xlp_gpio_set_reg(priv->gpio_intr_stat, d->hwirq, 0x1);
+ __clear_bit(d->hwirq, priv->gpio_enabled_mask);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+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);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x1);
+ __set_bit(d->hwirq, priv->gpio_enabled_mask);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+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);
+ int pol, irq_type;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ irq_type = XLP_GPIO_IRQ_TYPE_EDGE;
+ pol = XLP_GPIO_IRQ_POL_HIGH;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ irq_type = XLP_GPIO_IRQ_TYPE_EDGE;
+ pol = XLP_GPIO_IRQ_POL_LOW;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ irq_type = XLP_GPIO_IRQ_TYPE_LVL;
+ pol = XLP_GPIO_IRQ_POL_HIGH;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ irq_type = XLP_GPIO_IRQ_TYPE_LVL;
+ pol = XLP_GPIO_IRQ_POL_LOW;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ xlp_gpio_set_reg(priv->gpio_intr_type, d->hwirq, irq_type);
+ xlp_gpio_set_reg(priv->gpio_intr_pol, d->hwirq, pol);
+
+ return 0;
+}
+
+static struct irq_chip xlp_gpio_irq_chip = {
+ .name = "XLP-GPIO",
+ .irq_mask_ack = xlp_gpio_irq_mask_ack,
+ .irq_disable = xlp_gpio_irq_disable,
+ .irq_set_type = xlp_gpio_set_irq_type,
+ .irq_unmask = xlp_gpio_irq_unmask,
+ .flags = IRQCHIP_ONESHOT_SAFE,
+};
+
+static irqreturn_t xlp_gpio_generic_handler(int irq, void *data)
+{
+ struct xlp_gpio_priv *priv = data;
+ int gpio, regoff;
+ u32 gpio_stat;
+
+ regoff = -1;
+ gpio_stat = 0;
+ for_each_set_bit(gpio, priv->gpio_enabled_mask, XLP_MAX_NR_GPIO) {
+ if (regoff != gpio / XLP_GPIO_REGSZ) {
+ regoff = gpio / XLP_GPIO_REGSZ;
+ gpio_stat = readl(priv->gpio_intr_stat + regoff * 4);
+ }
+ if (gpio_stat & BIT(gpio % XLP_GPIO_REGSZ))
+ generic_handle_irq(irq_find_mapping(
+ priv->chip.irqdomain, gpio));
+ }
+
+ return IRQ_HANDLED;
+}
+
+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);
+
+ BUG_ON(gpio >= gc->ngpio);
+ xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x1);
+
+ return 0;
+}
+
+static int xlp_gpio_dir_input(struct gpio_chip *gc, unsigned gpio)
+{
+ struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+
+ BUG_ON(gpio >= gc->ngpio);
+ xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x0);
+
+ return 0;
+}
+
+static int xlp_gpio_get(struct gpio_chip *gc, unsigned gpio)
+{
+ struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
+
+ BUG_ON(gpio >= gc->ngpio);
+ return xlp_gpio_get_reg(priv->gpio_paddrv, 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);
+
+ BUG_ON(gpio >= gc->ngpio);
+ xlp_gpio_set_reg(priv->gpio_paddrv, gpio, state);
+}
+
+static const struct of_device_id xlp_gpio_of_ids[] = {
+ {
+ .compatible = "netlogic,xlp832-gpio",
+ .data = (void *)XLP_GPIO_VARIANT_XLP832,
+ },
+ {
+ .compatible = "netlogic,xlp316-gpio",
+ .data = (void *)XLP_GPIO_VARIANT_XLP316,
+ },
+ {
+ .compatible = "netlogic,xlp208-gpio",
+ .data = (void *)XLP_GPIO_VARIANT_XLP208,
+ },
+ {
+ .compatible = "netlogic,xlp980-gpio",
+ .data = (void *)XLP_GPIO_VARIANT_XLP980,
+ },
+ {
+ .compatible = "netlogic,xlp532-gpio",
+ .data = (void *)XLP_GPIO_VARIANT_XLP532,
+ },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids);
+
+static int xlp_gpio_probe(struct platform_device *pdev)
+{
+ struct gpio_chip *gc;
+ struct resource *iores;
+ struct xlp_gpio_priv *priv;
+ const struct of_device_id *of_id;
+ void __iomem *gpio_base;
+ int irq_base, irq, err;
+ int ngpio;
+ u32 soc_type;
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iores)
+ return -ENODEV;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ gpio_base = devm_ioremap_resource(&pdev->dev, iores);
+ if (IS_ERR(gpio_base))
+ return PTR_ERR(gpio_base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ of_id = of_match_device(xlp_gpio_of_ids, &pdev->dev);
+ if (!of_id) {
+ dev_err(&pdev->dev, "Failed to get soc type!\n");
+ return -ENODEV;
+ }
+
+ soc_type = (uintptr_t) of_id->data;
+
+ switch (soc_type) {
+ case XLP_GPIO_VARIANT_XLP832:
+ priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN;
+ priv->gpio_paddrv = gpio_base + GPIO_PADDRV;
+ priv->gpio_intr_stat = gpio_base + GPIO_INT_STAT;
+ priv->gpio_intr_type = gpio_base + GPIO_INT_TYPE;
+ priv->gpio_intr_pol = gpio_base + GPIO_INT_POL;
+ priv->gpio_intr_en = gpio_base + GPIO_INT_EN00;
+ ngpio = 41;
+ break;
+ case XLP_GPIO_VARIANT_XLP208:
+ case XLP_GPIO_VARIANT_XLP316:
+ priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN;
+ priv->gpio_paddrv = gpio_base + GPIO_PADDRV;
+ priv->gpio_intr_stat = gpio_base + GPIO_3XX_INT_STAT;
+ priv->gpio_intr_type = gpio_base + GPIO_3XX_INT_TYPE;
+ priv->gpio_intr_pol = gpio_base + GPIO_3XX_INT_POL;
+ priv->gpio_intr_en = gpio_base + GPIO_3XX_INT_EN00;
+
+ ngpio = (soc_type == XLP_GPIO_VARIANT_XLP208) ? 42 : 57;
+ break;
+ case XLP_GPIO_VARIANT_XLP980:
+ case XLP_GPIO_VARIANT_XLP532:
+ priv->gpio_out_en = gpio_base + GPIO_9XX_OUTPUT_EN;
+ priv->gpio_paddrv = gpio_base + GPIO_9XX_PADDRV;
+ priv->gpio_intr_stat = gpio_base + GPIO_9XX_INT_STAT;
+ priv->gpio_intr_type = gpio_base + GPIO_9XX_INT_TYPE;
+ priv->gpio_intr_pol = gpio_base + GPIO_9XX_INT_POL;
+ priv->gpio_intr_en = gpio_base + GPIO_9XX_INT_EN00;
+
+ ngpio = (soc_type == XLP_GPIO_VARIANT_XLP980) ? 66 : 67;
+ break;
+ default:
+ dev_err(&pdev->dev, "Unknown Processor type!\n");
+ return -ENODEV;
+ }
+
+ bitmap_zero(priv->gpio_enabled_mask, XLP_MAX_NR_GPIO);
+
+ gc = &priv->chip;
+
+ gc->owner = THIS_MODULE;
+ gc->label = dev_name(&pdev->dev);
+ gc->base = 0;
+ gc->dev = &pdev->dev;
+ gc->ngpio = ngpio;
+ gc->of_node = pdev->dev.of_node;
+ gc->direction_output = xlp_gpio_dir_output;
+ gc->direction_input = xlp_gpio_dir_input;
+ gc->set = xlp_gpio_set;
+ gc->get = xlp_gpio_get;
+
+ spin_lock_init(&priv->lock);
+
+ err = devm_request_irq(&pdev->dev, irq, xlp_gpio_generic_handler,
+ IRQ_TYPE_NONE, pdev->name, priv);
+ if (err)
+ return err;
+
+ irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0);
+ if (irq_base < 0) {
+ dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
+ return err;
+ }
+
+ err = gpiochip_add(gc);
+ if (err < 0)
+ goto out_free_desc;
+
+ err = gpiochip_irqchip_add(gc, &xlp_gpio_irq_chip, irq_base,
+ handle_level_irq, IRQ_TYPE_NONE);
+ if (err) {
+ dev_err(&pdev->dev, "Could not connect irqchip to gpiochip!\n");
+ goto out_gpio_remove;
+ }
+
+ dev_info(&pdev->dev, "registered %d GPIOs\n", gc->ngpio);
+
+ return 0;
+
+out_gpio_remove:
+ gpiochip_remove(gc);
+out_free_desc:
+ irq_free_descs(irq_base, gc->ngpio);
+ return err;
+}
+
+static struct platform_driver xlp_gpio_driver = {
+ .driver = {
+ .name = "xlp-gpio",
+ .of_match_table = xlp_gpio_of_ids,
+ },
+ .probe = xlp_gpio_probe,
+};
+module_platform_driver(xlp_gpio_driver);
+
+MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
+MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@broadcom.com>");
+MODULE_DESCRIPTION("Netlogic XLP GPIO Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 184c4b1b2558..2e87c4b8da26 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -18,34 +18,47 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
#define DRIVER_NAME "zynq-gpio"
/* Maximum banks */
#define ZYNQ_GPIO_MAX_BANK 4
+#define ZYNQMP_GPIO_MAX_BANK 6
#define ZYNQ_GPIO_BANK0_NGPIO 32
#define ZYNQ_GPIO_BANK1_NGPIO 22
#define ZYNQ_GPIO_BANK2_NGPIO 32
#define ZYNQ_GPIO_BANK3_NGPIO 32
-#define ZYNQ_GPIO_NR_GPIOS (ZYNQ_GPIO_BANK0_NGPIO + \
- ZYNQ_GPIO_BANK1_NGPIO + \
- ZYNQ_GPIO_BANK2_NGPIO + \
- ZYNQ_GPIO_BANK3_NGPIO)
-
-#define ZYNQ_GPIO_BANK0_PIN_MIN 0
-#define ZYNQ_GPIO_BANK0_PIN_MAX (ZYNQ_GPIO_BANK0_PIN_MIN + \
- ZYNQ_GPIO_BANK0_NGPIO - 1)
-#define ZYNQ_GPIO_BANK1_PIN_MIN (ZYNQ_GPIO_BANK0_PIN_MAX + 1)
-#define ZYNQ_GPIO_BANK1_PIN_MAX (ZYNQ_GPIO_BANK1_PIN_MIN + \
- ZYNQ_GPIO_BANK1_NGPIO - 1)
-#define ZYNQ_GPIO_BANK2_PIN_MIN (ZYNQ_GPIO_BANK1_PIN_MAX + 1)
-#define ZYNQ_GPIO_BANK2_PIN_MAX (ZYNQ_GPIO_BANK2_PIN_MIN + \
- ZYNQ_GPIO_BANK2_NGPIO - 1)
-#define ZYNQ_GPIO_BANK3_PIN_MIN (ZYNQ_GPIO_BANK2_PIN_MAX + 1)
-#define ZYNQ_GPIO_BANK3_PIN_MAX (ZYNQ_GPIO_BANK3_PIN_MIN + \
- ZYNQ_GPIO_BANK3_NGPIO - 1)
+#define ZYNQMP_GPIO_BANK0_NGPIO 26
+#define ZYNQMP_GPIO_BANK1_NGPIO 26
+#define ZYNQMP_GPIO_BANK2_NGPIO 26
+#define ZYNQMP_GPIO_BANK3_NGPIO 32
+#define ZYNQMP_GPIO_BANK4_NGPIO 32
+#define ZYNQMP_GPIO_BANK5_NGPIO 32
+
+#define ZYNQ_GPIO_NR_GPIOS 118
+#define ZYNQMP_GPIO_NR_GPIOS 174
+
+#define ZYNQ_GPIO_BANK0_PIN_MIN(str) 0
+#define ZYNQ_GPIO_BANK0_PIN_MAX(str) (ZYNQ_GPIO_BANK0_PIN_MIN(str) + \
+ ZYNQ##str##_GPIO_BANK0_NGPIO - 1)
+#define ZYNQ_GPIO_BANK1_PIN_MIN(str) (ZYNQ_GPIO_BANK0_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK1_PIN_MAX(str) (ZYNQ_GPIO_BANK1_PIN_MIN(str) + \
+ ZYNQ##str##_GPIO_BANK1_NGPIO - 1)
+#define ZYNQ_GPIO_BANK2_PIN_MIN(str) (ZYNQ_GPIO_BANK1_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK2_PIN_MAX(str) (ZYNQ_GPIO_BANK2_PIN_MIN(str) + \
+ ZYNQ##str##_GPIO_BANK2_NGPIO - 1)
+#define ZYNQ_GPIO_BANK3_PIN_MIN(str) (ZYNQ_GPIO_BANK2_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK3_PIN_MAX(str) (ZYNQ_GPIO_BANK3_PIN_MIN(str) + \
+ ZYNQ##str##_GPIO_BANK3_NGPIO - 1)
+#define ZYNQ_GPIO_BANK4_PIN_MIN(str) (ZYNQ_GPIO_BANK3_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK4_PIN_MAX(str) (ZYNQ_GPIO_BANK4_PIN_MIN(str) + \
+ ZYNQ##str##_GPIO_BANK4_NGPIO - 1)
+#define ZYNQ_GPIO_BANK5_PIN_MIN(str) (ZYNQ_GPIO_BANK4_PIN_MAX(str) + 1)
+#define ZYNQ_GPIO_BANK5_PIN_MAX(str) (ZYNQ_GPIO_BANK5_PIN_MIN(str) + \
+ ZYNQ##str##_GPIO_BANK5_NGPIO - 1)
/* Register offsets for the GPIO device */
@@ -89,12 +102,30 @@
* @base_addr: base address of the GPIO device
* @clk: clock resource for this controller
* @irq: interrupt for the GPIO device
+ * @p_data: pointer to platform data
*/
struct zynq_gpio {
struct gpio_chip chip;
void __iomem *base_addr;
struct clk *clk;
int irq;
+ const struct zynq_platform_data *p_data;
+};
+
+/**
+ * struct zynq_platform_data - zynq gpio platform data structure
+ * @label: string to store in gpio->label
+ * @ngpio: max number of gpio pins
+ * @max_bank: maximum number of gpio banks
+ * @bank_min: this array represents bank's min pin
+ * @bank_max: this array represents bank's max pin
+*/
+struct zynq_platform_data {
+ const char *label;
+ u16 ngpio;
+ int max_bank;
+ int bank_min[ZYNQMP_GPIO_MAX_BANK];
+ int bank_max[ZYNQMP_GPIO_MAX_BANK];
};
static struct irq_chip zynq_gpio_level_irqchip;
@@ -112,39 +143,26 @@ static struct irq_chip zynq_gpio_edge_irqchip;
*/
static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
unsigned int *bank_num,
- unsigned int *bank_pin_num)
+ unsigned int *bank_pin_num,
+ struct zynq_gpio *gpio)
{
- switch (pin_num) {
- case ZYNQ_GPIO_BANK0_PIN_MIN ... ZYNQ_GPIO_BANK0_PIN_MAX:
- *bank_num = 0;
- *bank_pin_num = pin_num;
- break;
- case ZYNQ_GPIO_BANK1_PIN_MIN ... ZYNQ_GPIO_BANK1_PIN_MAX:
- *bank_num = 1;
- *bank_pin_num = pin_num - ZYNQ_GPIO_BANK1_PIN_MIN;
- break;
- case ZYNQ_GPIO_BANK2_PIN_MIN ... ZYNQ_GPIO_BANK2_PIN_MAX:
- *bank_num = 2;
- *bank_pin_num = pin_num - ZYNQ_GPIO_BANK2_PIN_MIN;
- break;
- case ZYNQ_GPIO_BANK3_PIN_MIN ... ZYNQ_GPIO_BANK3_PIN_MAX:
- *bank_num = 3;
- *bank_pin_num = pin_num - ZYNQ_GPIO_BANK3_PIN_MIN;
- break;
- default:
- WARN(true, "invalid GPIO pin number: %u", pin_num);
- *bank_num = 0;
- *bank_pin_num = 0;
- break;
+ int bank;
+
+ for (bank = 0; bank < gpio->p_data->max_bank; bank++) {
+ if ((pin_num >= gpio->p_data->bank_min[bank]) &&
+ (pin_num <= gpio->p_data->bank_max[bank])) {
+ *bank_num = bank;
+ *bank_pin_num = pin_num -
+ gpio->p_data->bank_min[bank];
+ return;
+ }
}
-}
-static const unsigned int zynq_gpio_bank_offset[] = {
- ZYNQ_GPIO_BANK0_PIN_MIN,
- ZYNQ_GPIO_BANK1_PIN_MIN,
- ZYNQ_GPIO_BANK2_PIN_MIN,
- ZYNQ_GPIO_BANK3_PIN_MIN,
-};
+ /* default */
+ WARN(true, "invalid GPIO pin number: %u", pin_num);
+ *bank_num = 0;
+ *bank_pin_num = 0;
+}
/**
* zynq_gpio_get_value - Get the state of the specified pin of GPIO device
@@ -161,7 +179,7 @@ static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin)
unsigned int bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
- zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
+ zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
data = readl_relaxed(gpio->base_addr +
ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
@@ -185,7 +203,7 @@ static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin,
unsigned int reg_offset, bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
- zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
+ zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) {
/* only 16 data bits in bit maskable reg */
@@ -222,7 +240,7 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
unsigned int bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
- zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
+ zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
/* bank 0 pins 7 and 8 are special and cannot be used as inputs */
if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8))
@@ -255,7 +273,7 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
unsigned int bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
- zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
+ zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
/* set the GPIO pin as output */
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
@@ -286,7 +304,7 @@ static void zynq_gpio_irq_mask(struct irq_data *irq_data)
struct zynq_gpio *gpio = 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);
+ zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
}
@@ -306,7 +324,7 @@ static void zynq_gpio_irq_unmask(struct irq_data *irq_data)
struct zynq_gpio *gpio = 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);
+ zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_num));
}
@@ -325,7 +343,7 @@ static void zynq_gpio_irq_ack(struct irq_data *irq_data)
struct zynq_gpio *gpio = 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);
+ zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
}
@@ -335,7 +353,7 @@ static void zynq_gpio_irq_ack(struct irq_data *irq_data)
* @irq_data: irq data containing irq number of gpio pin for the interrupt
* to enable
*
- * Clears the INTSTS bit and unmasks the given interrrupt.
+ * Clears the INTSTS bit and unmasks the given interrupt.
*/
static void zynq_gpio_irq_enable(struct irq_data *irq_data)
{
@@ -375,7 +393,7 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
struct zynq_gpio *gpio = 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);
+ zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
int_type = readl_relaxed(gpio->base_addr +
ZYNQ_GPIO_INTTYPE_OFFSET(bank_num));
@@ -470,7 +488,7 @@ static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio,
unsigned int bank_num,
unsigned long pending)
{
- unsigned int bank_offset = zynq_gpio_bank_offset[bank_num];
+ unsigned int bank_offset = gpio->p_data->bank_min[bank_num];
struct irq_domain *irqdomain = gpio->chip.irqdomain;
int offset;
@@ -505,7 +523,7 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
chained_irq_enter(irqchip, desc);
- for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++) {
+ for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) {
int_sts = readl_relaxed(gpio->base_addr +
ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
int_enb = readl_relaxed(gpio->base_addr +
@@ -582,6 +600,46 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
zynq_gpio_runtime_resume, NULL)
};
+static const struct zynq_platform_data zynqmp_gpio_def = {
+ .label = "zynqmp_gpio",
+ .ngpio = ZYNQMP_GPIO_NR_GPIOS,
+ .max_bank = ZYNQMP_GPIO_MAX_BANK,
+ .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(MP),
+ .bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(MP),
+ .bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(MP),
+ .bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(MP),
+ .bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(MP),
+ .bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(MP),
+ .bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(MP),
+ .bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(MP),
+ .bank_min[4] = ZYNQ_GPIO_BANK4_PIN_MIN(MP),
+ .bank_max[4] = ZYNQ_GPIO_BANK4_PIN_MAX(MP),
+ .bank_min[5] = ZYNQ_GPIO_BANK5_PIN_MIN(MP),
+ .bank_max[5] = ZYNQ_GPIO_BANK5_PIN_MAX(MP),
+};
+
+static const struct zynq_platform_data zynq_gpio_def = {
+ .label = "zynq_gpio",
+ .ngpio = ZYNQ_GPIO_NR_GPIOS,
+ .max_bank = ZYNQ_GPIO_MAX_BANK,
+ .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(),
+ .bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(),
+ .bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(),
+ .bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(),
+ .bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(),
+ .bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(),
+ .bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(),
+ .bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(),
+};
+
+static const struct of_device_id zynq_gpio_of_match[] = {
+ { .compatible = "xlnx,zynq-gpio-1.0", .data = (void *)&zynq_gpio_def },
+ { .compatible = "xlnx,zynqmp-gpio-1.0",
+ .data = (void *)&zynqmp_gpio_def },
+ { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
+
/**
* zynq_gpio_probe - Initialization method for a zynq_gpio device
* @pdev: platform device instance
@@ -599,11 +657,18 @@ static int zynq_gpio_probe(struct platform_device *pdev)
struct zynq_gpio *gpio;
struct gpio_chip *chip;
struct resource *res;
+ const struct of_device_id *match;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
return -ENOMEM;
+ match = of_match_node(zynq_gpio_of_match, pdev->dev.of_node);
+ if (!match) {
+ dev_err(&pdev->dev, "of_match_node() failed\n");
+ return -EINVAL;
+ }
+ gpio->p_data = match->data;
platform_set_drvdata(pdev, gpio);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -619,7 +684,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
/* configure the gpio chip */
chip = &gpio->chip;
- chip->label = "zynq_gpio";
+ chip->label = gpio->p_data->label;
chip->owner = THIS_MODULE;
chip->dev = &pdev->dev;
chip->get = zynq_gpio_get_value;
@@ -629,7 +694,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
chip->direction_input = zynq_gpio_dir_in;
chip->direction_output = zynq_gpio_dir_out;
chip->base = -1;
- chip->ngpio = ZYNQ_GPIO_NR_GPIOS;
+ chip->ngpio = gpio->p_data->ngpio;
/* Enable GPIO clock */
gpio->clk = devm_clk_get(&pdev->dev, NULL);
@@ -651,7 +716,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
}
/* disable interrupts for all banks */
- for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++)
+ for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++)
writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
@@ -695,12 +760,6 @@ static int zynq_gpio_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id zynq_gpio_of_match[] = {
- { .compatible = "xlnx,zynq-gpio-1.0", },
- { /* end of table */ }
-};
-MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
-
static struct platform_driver zynq_gpio_driver = {
.driver = {
.name = DRIVER_NAME,
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 725d16138b74..533fe5dbe6f8 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -114,10 +114,11 @@ static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip,
* @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
* @pin: ACPI GPIO pin number (0-based, controller-relative)
*
- * Returns GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
- * error value
+ * Return: GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
+ * error value. Specifically returns %-EPROBE_DEFER if the referenced GPIO
+ * controller does not have gpiochip registered at the moment. This is to
+ * support probe deferral.
*/
-
static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
{
struct gpio_chip *chip;
@@ -131,7 +132,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
chip = gpiochip_find(handle, acpi_gpiochip_find);
if (!chip)
- return ERR_PTR(-ENODEV);
+ return ERR_PTR(-EPROBE_DEFER);
offset = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
if (offset < 0)
@@ -307,6 +308,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
acpi_walk_resources(handle, "_AEI",
acpi_gpiochip_request_interrupt, acpi_gpio);
}
+EXPORT_SYMBOL_GPL(acpi_gpiochip_request_interrupts);
/**
* acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
@@ -346,6 +348,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
kfree(event);
}
}
+EXPORT_SYMBOL_GPL(acpi_gpiochip_free_interrupts);
int acpi_dev_add_driver_gpios(struct acpi_device *adev,
const struct acpi_gpio_mapping *gpios)
@@ -514,6 +517,35 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
}
+/**
+ * acpi_dev_gpio_irq_get() - Find GpioInt and translate it to Linux IRQ number
+ * @adev: pointer to a ACPI device to get IRQ from
+ * @index: index of GpioInt resource (starting from %0)
+ *
+ * If the device has one or more GpioInt resources, this function can be
+ * used to translate from the GPIO offset in the resource to the Linux IRQ
+ * number.
+ *
+ * Return: Linux IRQ number (>%0) on success, negative errno on failure.
+ */
+int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
+{
+ int idx, i;
+
+ for (i = 0, idx = 0; idx <= index; i++) {
+ struct acpi_gpio_info info;
+ struct gpio_desc *desc;
+
+ desc = acpi_get_gpiod_by_index(adev, NULL, i, &info);
+ if (IS_ERR(desc))
+ break;
+ if (info.gpioint && idx++ == index)
+ return gpiod_to_irq(desc);
+ }
+ return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get);
+
static acpi_status
acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
u32 bits, u64 *value, void *handler_context,
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index a6c67c6b4680..9a0ec48a4737 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -242,7 +242,7 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
{
/*
* We're discouraging gpio_cells < 2, since that way you'll have to
- * write your own xlate function (that will have to retrive the GPIO
+ * write your own xlate function (that will have to retrieve the GPIO
* number and the flags from a single gpio cell -- this is possible,
* but not recommended).
*/
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index af3bc7a8033b..b57ed8e55ab5 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -6,14 +6,29 @@
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
+#include <linux/slab.h>
#include "gpiolib.h"
-static DEFINE_IDR(dirent_idr);
+#define GPIO_IRQF_TRIGGER_FALLING BIT(0)
+#define GPIO_IRQF_TRIGGER_RISING BIT(1)
+#define GPIO_IRQF_TRIGGER_BOTH (GPIO_IRQF_TRIGGER_FALLING | \
+ GPIO_IRQF_TRIGGER_RISING)
+struct gpiod_data {
+ struct gpio_desc *desc;
+
+ struct mutex mutex;
+ struct kernfs_node *value_kn;
+ int irq;
+ unsigned char irq_flags;
-/* lock protects against unexport_gpio() being called while
- * sysfs files are active.
+ bool direction_can_change;
+};
+
+/*
+ * Lock to serialise gpiod export and unexport, and prevent re-export of
+ * gpiod whose chip is being unregistered.
*/
static DEFINE_MUTEX(sysfs_lock);
@@ -38,38 +53,35 @@ static DEFINE_MUTEX(sysfs_lock);
* /edge configuration
*/
-static ssize_t gpio_direction_show(struct device *dev,
+static ssize_t direction_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct gpio_desc *desc = dev_get_drvdata(dev);
+ struct gpiod_data *data = dev_get_drvdata(dev);
+ struct gpio_desc *desc = data->desc;
ssize_t status;
- mutex_lock(&sysfs_lock);
+ mutex_lock(&data->mutex);
- if (!test_bit(FLAG_EXPORT, &desc->flags)) {
- status = -EIO;
- } else {
- gpiod_get_direction(desc);
- status = sprintf(buf, "%s\n",
+ gpiod_get_direction(desc);
+ status = sprintf(buf, "%s\n",
test_bit(FLAG_IS_OUT, &desc->flags)
? "out" : "in");
- }
- mutex_unlock(&sysfs_lock);
+ mutex_unlock(&data->mutex);
+
return status;
}
-static ssize_t gpio_direction_store(struct device *dev,
+static ssize_t direction_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
- struct gpio_desc *desc = dev_get_drvdata(dev);
+ struct gpiod_data *data = dev_get_drvdata(dev);
+ struct gpio_desc *desc = data->desc;
ssize_t status;
- mutex_lock(&sysfs_lock);
+ mutex_lock(&data->mutex);
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- status = -EIO;
- else if (sysfs_streq(buf, "high"))
+ if (sysfs_streq(buf, "high"))
status = gpiod_direction_output_raw(desc, 1);
else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
status = gpiod_direction_output_raw(desc, 0);
@@ -78,43 +90,40 @@ static ssize_t gpio_direction_store(struct device *dev,
else
status = -EINVAL;
- mutex_unlock(&sysfs_lock);
+ mutex_unlock(&data->mutex);
+
return status ? : size;
}
+static DEVICE_ATTR_RW(direction);
-static /* const */ DEVICE_ATTR(direction, 0644,
- gpio_direction_show, gpio_direction_store);
-
-static ssize_t gpio_value_show(struct device *dev,
+static ssize_t value_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct gpio_desc *desc = dev_get_drvdata(dev);
+ struct gpiod_data *data = dev_get_drvdata(dev);
+ struct gpio_desc *desc = data->desc;
ssize_t status;
- mutex_lock(&sysfs_lock);
+ mutex_lock(&data->mutex);
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- status = -EIO;
- else
- status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
+ status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
+
+ mutex_unlock(&data->mutex);
- mutex_unlock(&sysfs_lock);
return status;
}
-static ssize_t gpio_value_store(struct device *dev,
+static ssize_t value_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
- struct gpio_desc *desc = dev_get_drvdata(dev);
+ struct gpiod_data *data = dev_get_drvdata(dev);
+ struct gpio_desc *desc = data->desc;
ssize_t status;
- mutex_lock(&sysfs_lock);
+ mutex_lock(&data->mutex);
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- status = -EIO;
- else if (!test_bit(FLAG_IS_OUT, &desc->flags))
+ if (!test_bit(FLAG_IS_OUT, &desc->flags)) {
status = -EPERM;
- else {
+ } else {
long value;
status = kstrtol(buf, 0, &value);
@@ -124,172 +133,168 @@ static ssize_t gpio_value_store(struct device *dev,
}
}
- mutex_unlock(&sysfs_lock);
+ mutex_unlock(&data->mutex);
+
return status;
}
-
-static DEVICE_ATTR(value, 0644,
- gpio_value_show, gpio_value_store);
+static DEVICE_ATTR_RW(value);
static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
{
- struct kernfs_node *value_sd = priv;
+ struct gpiod_data *data = priv;
+
+ sysfs_notify_dirent(data->value_kn);
- sysfs_notify_dirent(value_sd);
return IRQ_HANDLED;
}
-static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
- unsigned long gpio_flags)
+/* Caller holds gpiod-data mutex. */
+static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
{
- struct kernfs_node *value_sd;
+ struct gpiod_data *data = dev_get_drvdata(dev);
+ struct gpio_desc *desc = data->desc;
unsigned long irq_flags;
- int ret, irq, id;
+ int ret;
- if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags)
- return 0;
-
- irq = gpiod_to_irq(desc);
- if (irq < 0)
+ data->irq = gpiod_to_irq(desc);
+ if (data->irq < 0)
return -EIO;
- id = desc->flags >> ID_SHIFT;
- value_sd = idr_find(&dirent_idr, id);
- if (value_sd)
- free_irq(irq, value_sd);
-
- desc->flags &= ~GPIO_TRIGGER_MASK;
-
- if (!gpio_flags) {
- gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
- ret = 0;
- goto free_id;
- }
+ data->value_kn = sysfs_get_dirent(dev->kobj.sd, "value");
+ if (!data->value_kn)
+ return -ENODEV;
irq_flags = IRQF_SHARED;
- if (test_bit(FLAG_TRIG_FALL, &gpio_flags))
+ if (flags & GPIO_IRQF_TRIGGER_FALLING)
irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
- if (test_bit(FLAG_TRIG_RISE, &gpio_flags))
+ if (flags & GPIO_IRQF_TRIGGER_RISING)
irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
- if (!value_sd) {
- value_sd = sysfs_get_dirent(dev->kobj.sd, "value");
- if (!value_sd) {
- ret = -ENODEV;
- goto err_out;
- }
-
- ret = idr_alloc(&dirent_idr, value_sd, 1, 0, GFP_KERNEL);
- if (ret < 0)
- goto free_sd;
- id = ret;
-
- desc->flags &= GPIO_FLAGS_MASK;
- desc->flags |= (unsigned long)id << ID_SHIFT;
-
- if (desc->flags >> ID_SHIFT != id) {
- ret = -ERANGE;
- goto free_id;
- }
- }
+ /*
+ * FIXME: This should be done in the irq_request_resources callback
+ * when the irq is requested, but a few drivers currently fail
+ * to do so.
+ *
+ * Remove this redundant call (along with the corresponding
+ * unlock) when those drivers have been fixed.
+ */
+ ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
+ if (ret < 0)
+ goto err_put_kn;
- ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags,
- "gpiolib", value_sd);
+ ret = request_any_context_irq(data->irq, gpio_sysfs_irq, irq_flags,
+ "gpiolib", data);
if (ret < 0)
- goto free_id;
+ goto err_unlock;
- ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
- if (ret < 0) {
- gpiod_warn(desc, "failed to flag the GPIO for IRQ\n");
- goto free_id;
- }
+ data->irq_flags = flags;
- desc->flags |= gpio_flags;
return 0;
-free_id:
- idr_remove(&dirent_idr, id);
- desc->flags &= GPIO_FLAGS_MASK;
-free_sd:
- if (value_sd)
- sysfs_put(value_sd);
-err_out:
+err_unlock:
+ gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
+err_put_kn:
+ sysfs_put(data->value_kn);
+
return ret;
}
+/*
+ * Caller holds gpiod-data mutex (unless called after class-device
+ * deregistration).
+ */
+static void gpio_sysfs_free_irq(struct device *dev)
+{
+ struct gpiod_data *data = dev_get_drvdata(dev);
+ struct gpio_desc *desc = data->desc;
+
+ data->irq_flags = 0;
+ free_irq(data->irq, data);
+ gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
+ sysfs_put(data->value_kn);
+}
+
static const struct {
const char *name;
- unsigned long flags;
+ unsigned char flags;
} trigger_types[] = {
{ "none", 0 },
- { "falling", BIT(FLAG_TRIG_FALL) },
- { "rising", BIT(FLAG_TRIG_RISE) },
- { "both", BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE) },
+ { "falling", GPIO_IRQF_TRIGGER_FALLING },
+ { "rising", GPIO_IRQF_TRIGGER_RISING },
+ { "both", GPIO_IRQF_TRIGGER_BOTH },
};
-static ssize_t gpio_edge_show(struct device *dev,
+static ssize_t edge_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- const struct gpio_desc *desc = dev_get_drvdata(dev);
- ssize_t status;
+ struct gpiod_data *data = dev_get_drvdata(dev);
+ ssize_t status = 0;
+ int i;
- mutex_lock(&sysfs_lock);
-
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- status = -EIO;
- else {
- int i;
+ mutex_lock(&data->mutex);
- status = 0;
- for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
- if ((desc->flags & GPIO_TRIGGER_MASK)
- == trigger_types[i].flags) {
- status = sprintf(buf, "%s\n",
- trigger_types[i].name);
- break;
- }
+ for (i = 0; i < ARRAY_SIZE(trigger_types); i++) {
+ if (data->irq_flags == trigger_types[i].flags) {
+ status = sprintf(buf, "%s\n", trigger_types[i].name);
+ break;
+ }
}
- mutex_unlock(&sysfs_lock);
+ mutex_unlock(&data->mutex);
+
return status;
}
-static ssize_t gpio_edge_store(struct device *dev,
+static ssize_t edge_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
- struct gpio_desc *desc = dev_get_drvdata(dev);
- ssize_t status;
- int i;
+ struct gpiod_data *data = dev_get_drvdata(dev);
+ unsigned char flags;
+ ssize_t status = size;
+ int i;
- for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
+ for (i = 0; i < ARRAY_SIZE(trigger_types); i++) {
if (sysfs_streq(trigger_types[i].name, buf))
- goto found;
- return -EINVAL;
+ break;
+ }
-found:
- mutex_lock(&sysfs_lock);
+ if (i == ARRAY_SIZE(trigger_types))
+ return -EINVAL;
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- status = -EIO;
- else {
- status = gpio_setup_irq(desc, dev, trigger_types[i].flags);
+ flags = trigger_types[i].flags;
+
+ mutex_lock(&data->mutex);
+
+ if (flags == data->irq_flags) {
+ status = size;
+ goto out_unlock;
+ }
+
+ if (data->irq_flags)
+ gpio_sysfs_free_irq(dev);
+
+ if (flags) {
+ status = gpio_sysfs_request_irq(dev, flags);
if (!status)
status = size;
}
- mutex_unlock(&sysfs_lock);
+out_unlock:
+ mutex_unlock(&data->mutex);
return status;
}
+static DEVICE_ATTR_RW(edge);
-static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store);
-
-static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
- int value)
+/* Caller holds gpiod-data mutex. */
+static int gpio_sysfs_set_active_low(struct device *dev, int value)
{
+ struct gpiod_data *data = dev_get_drvdata(dev);
+ struct gpio_desc *desc = data->desc;
int status = 0;
+ unsigned int flags = data->irq_flags;
if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value)
return 0;
@@ -300,69 +305,59 @@ static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
/* reconfigure poll(2) support if enabled on one edge only */
- if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^
- !!test_bit(FLAG_TRIG_FALL, &desc->flags))) {
- unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK;
-
- gpio_setup_irq(desc, dev, 0);
- status = gpio_setup_irq(desc, dev, trigger_flags);
+ if (flags == GPIO_IRQF_TRIGGER_FALLING ||
+ flags == GPIO_IRQF_TRIGGER_RISING) {
+ gpio_sysfs_free_irq(dev);
+ status = gpio_sysfs_request_irq(dev, flags);
}
return status;
}
-static ssize_t gpio_active_low_show(struct device *dev,
+static ssize_t active_low_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- const struct gpio_desc *desc = dev_get_drvdata(dev);
+ struct gpiod_data *data = dev_get_drvdata(dev);
+ struct gpio_desc *desc = data->desc;
ssize_t status;
- mutex_lock(&sysfs_lock);
+ mutex_lock(&data->mutex);
- if (!test_bit(FLAG_EXPORT, &desc->flags))
- status = -EIO;
- else
- status = sprintf(buf, "%d\n",
+ status = sprintf(buf, "%d\n",
!!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
- mutex_unlock(&sysfs_lock);
+ mutex_unlock(&data->mutex);
return status;
}
-static ssize_t gpio_active_low_store(struct device *dev,
+static ssize_t active_low_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
- struct gpio_desc *desc = dev_get_drvdata(dev);
+ struct gpiod_data *data = dev_get_drvdata(dev);
ssize_t status;
+ long value;
- mutex_lock(&sysfs_lock);
+ mutex_lock(&data->mutex);
- if (!test_bit(FLAG_EXPORT, &desc->flags)) {
- status = -EIO;
- } else {
- long value;
+ status = kstrtol(buf, 0, &value);
+ if (status == 0)
+ status = gpio_sysfs_set_active_low(dev, value);
- status = kstrtol(buf, 0, &value);
- if (status == 0)
- status = sysfs_set_active_low(desc, dev, value != 0);
- }
-
- mutex_unlock(&sysfs_lock);
+ mutex_unlock(&data->mutex);
return status ? : size;
}
-
-static DEVICE_ATTR(active_low, 0644,
- gpio_active_low_show, gpio_active_low_store);
+static DEVICE_ATTR_RW(active_low);
static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
- struct gpio_desc *desc = dev_get_drvdata(dev);
+ struct gpiod_data *data = dev_get_drvdata(dev);
+ struct gpio_desc *desc = data->desc;
umode_t mode = attr->mode;
- bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags);
+ bool show_direction = data->direction_can_change;
if (attr == &dev_attr_direction.attr) {
if (!show_direction)
@@ -402,32 +397,32 @@ static const struct attribute_group *gpio_groups[] = {
* /ngpio ... matching gpio_chip.ngpio
*/
-static ssize_t chip_base_show(struct device *dev,
+static ssize_t base_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_chip *chip = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", chip->base);
}
-static DEVICE_ATTR(base, 0444, chip_base_show, NULL);
+static DEVICE_ATTR_RO(base);
-static ssize_t chip_label_show(struct device *dev,
+static ssize_t label_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_chip *chip = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", chip->label ? : "");
}
-static DEVICE_ATTR(label, 0444, chip_label_show, NULL);
+static DEVICE_ATTR_RO(label);
-static ssize_t chip_ngpio_show(struct device *dev,
+static ssize_t ngpio_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_chip *chip = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", chip->ngpio);
}
-static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
+static DEVICE_ATTR_RO(ngpio);
static struct attribute *gpiochip_attrs[] = {
&dev_attr_base.attr,
@@ -552,6 +547,7 @@ static struct class gpio_class = {
int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
{
struct gpio_chip *chip;
+ struct gpiod_data *data;
unsigned long flags;
int status;
const char *ioname = NULL;
@@ -574,9 +570,9 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
mutex_lock(&sysfs_lock);
/* check if chip is being removed */
- if (!chip || !chip->exported) {
+ if (!chip || !chip->cdev) {
status = -ENODEV;
- goto fail_unlock;
+ goto err_unlock;
}
spin_lock_irqsave(&gpio_lock, flags);
@@ -588,43 +584,54 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
test_bit(FLAG_REQUESTED, &desc->flags),
test_bit(FLAG_EXPORT, &desc->flags));
status = -EPERM;
- goto fail_unlock;
+ goto err_unlock;
}
+ spin_unlock_irqrestore(&gpio_lock, flags);
- if (desc->chip->direction_input && desc->chip->direction_output &&
- direction_may_change) {
- set_bit(FLAG_SYSFS_DIR, &desc->flags);
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ status = -ENOMEM;
+ goto err_unlock;
}
- spin_unlock_irqrestore(&gpio_lock, flags);
+ data->desc = desc;
+ mutex_init(&data->mutex);
+ if (chip->direction_input && chip->direction_output)
+ data->direction_can_change = direction_may_change;
+ else
+ data->direction_can_change = false;
offset = gpio_chip_hwgpio(desc);
- if (desc->chip->names && desc->chip->names[offset])
- ioname = desc->chip->names[offset];
+ if (chip->names && chip->names[offset])
+ ioname = chip->names[offset];
- dev = device_create_with_groups(&gpio_class, desc->chip->dev,
- MKDEV(0, 0), desc, gpio_groups,
+ dev = device_create_with_groups(&gpio_class, chip->dev,
+ MKDEV(0, 0), data, gpio_groups,
ioname ? ioname : "gpio%u",
desc_to_gpio(desc));
if (IS_ERR(dev)) {
status = PTR_ERR(dev);
- goto fail_unlock;
+ goto err_free_data;
}
set_bit(FLAG_EXPORT, &desc->flags);
mutex_unlock(&sysfs_lock);
return 0;
-fail_unlock:
+err_free_data:
+ kfree(data);
+err_unlock:
mutex_unlock(&sysfs_lock);
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
EXPORT_SYMBOL_GPL(gpiod_export);
-static int match_export(struct device *dev, const void *data)
+static int match_export(struct device *dev, const void *desc)
{
- return dev_get_drvdata(dev) == data;
+ struct gpiod_data *data = dev_get_drvdata(dev);
+
+ return data->desc == desc;
}
/**
@@ -641,82 +648,26 @@ static int match_export(struct device *dev, const void *data)
int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc)
{
- int status = -EINVAL;
+ struct device *cdev;
+ int ret;
if (!desc) {
pr_warn("%s: invalid GPIO\n", __func__);
return -EINVAL;
}
- mutex_lock(&sysfs_lock);
-
- if (test_bit(FLAG_EXPORT, &desc->flags)) {
- struct device *tdev;
-
- tdev = class_find_device(&gpio_class, NULL, desc, match_export);
- if (tdev != NULL) {
- status = sysfs_create_link(&dev->kobj, &tdev->kobj,
- name);
- put_device(tdev);
- } else {
- status = -ENODEV;
- }
- }
-
- mutex_unlock(&sysfs_lock);
+ cdev = class_find_device(&gpio_class, NULL, desc, match_export);
+ if (!cdev)
+ return -ENODEV;
- if (status)
- gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+ ret = sysfs_create_link(&dev->kobj, &cdev->kobj, name);
+ put_device(cdev);
- return status;
+ return ret;
}
EXPORT_SYMBOL_GPL(gpiod_export_link);
/**
- * gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value
- * @gpio: gpio to change
- * @value: non-zero to use active low, i.e. inverted values
- *
- * Set the polarity of /sys/class/gpio/gpioN/value sysfs attribute.
- * The GPIO does not have to be exported yet. If poll(2) support has
- * been enabled for either rising or falling edge, it will be
- * reconfigured to follow the new polarity.
- *
- * Returns zero on success, else an error.
- */
-int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
-{
- struct device *dev = NULL;
- int status = -EINVAL;
-
- if (!desc) {
- pr_warn("%s: invalid GPIO\n", __func__);
- return -EINVAL;
- }
-
- mutex_lock(&sysfs_lock);
-
- if (test_bit(FLAG_EXPORT, &desc->flags)) {
- dev = class_find_device(&gpio_class, NULL, desc, match_export);
- if (dev == NULL) {
- status = -ENODEV;
- goto unlock;
- }
- }
-
- status = sysfs_set_active_low(desc, dev, value);
- put_device(dev);
-unlock:
- mutex_unlock(&sysfs_lock);
-
- if (status)
- gpiod_dbg(desc, "%s: status %d\n", __func__, status);
-
- return status;
-}
-EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low);
-
-/**
* gpiod_unexport - reverse effect of gpio_export()
* @gpio: gpio to make unavailable
*
@@ -724,8 +675,8 @@ EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low);
*/
void gpiod_unexport(struct gpio_desc *desc)
{
- int status = 0;
- struct device *dev = NULL;
+ struct gpiod_data *data;
+ struct device *dev;
if (!desc) {
pr_warn("%s: invalid GPIO\n", __func__);
@@ -734,82 +685,79 @@ void gpiod_unexport(struct gpio_desc *desc)
mutex_lock(&sysfs_lock);
- if (test_bit(FLAG_EXPORT, &desc->flags)) {
+ if (!test_bit(FLAG_EXPORT, &desc->flags))
+ goto err_unlock;
- dev = class_find_device(&gpio_class, NULL, desc, match_export);
- if (dev) {
- gpio_setup_irq(desc, dev, 0);
- clear_bit(FLAG_SYSFS_DIR, &desc->flags);
- clear_bit(FLAG_EXPORT, &desc->flags);
- } else
- status = -ENODEV;
- }
+ dev = class_find_device(&gpio_class, NULL, desc, match_export);
+ if (!dev)
+ goto err_unlock;
+
+ data = dev_get_drvdata(dev);
+
+ clear_bit(FLAG_EXPORT, &desc->flags);
+
+ device_unregister(dev);
+
+ /*
+ * Release irq after deregistration to prevent race with edge_store.
+ */
+ if (data->irq_flags)
+ gpio_sysfs_free_irq(dev);
mutex_unlock(&sysfs_lock);
- if (dev) {
- device_unregister(dev);
- put_device(dev);
- }
+ put_device(dev);
+ kfree(data);
- if (status)
- gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+ return;
+
+err_unlock:
+ mutex_unlock(&sysfs_lock);
}
EXPORT_SYMBOL_GPL(gpiod_unexport);
-int gpiochip_export(struct gpio_chip *chip)
+int gpiochip_sysfs_register(struct gpio_chip *chip)
{
- int status;
struct device *dev;
- /* Many systems register gpio chips for SOC support very early,
+ /*
+ * Many systems add gpio chips for SOC support very early,
* before driver model support is available. In those cases we
- * export this later, in gpiolib_sysfs_init() ... here we just
+ * register later, in gpiolib_sysfs_init() ... here we just
* verify that _some_ field of gpio_class got initialized.
*/
if (!gpio_class.p)
return 0;
/* use chip->base for the ID; it's already known to be unique */
- mutex_lock(&sysfs_lock);
dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0),
chip, gpiochip_groups,
"gpiochip%d", chip->base);
if (IS_ERR(dev))
- status = PTR_ERR(dev);
- else
- status = 0;
- chip->exported = (status == 0);
- mutex_unlock(&sysfs_lock);
+ return PTR_ERR(dev);
- if (status)
- chip_dbg(chip, "%s: status %d\n", __func__, status);
+ mutex_lock(&sysfs_lock);
+ chip->cdev = dev;
+ mutex_unlock(&sysfs_lock);
- return status;
+ return 0;
}
-void gpiochip_unexport(struct gpio_chip *chip)
+void gpiochip_sysfs_unregister(struct gpio_chip *chip)
{
- int status;
- struct device *dev;
struct gpio_desc *desc;
unsigned int i;
+ if (!chip->cdev)
+ return;
+
+ device_unregister(chip->cdev);
+
+ /* prevent further gpiod exports */
mutex_lock(&sysfs_lock);
- dev = class_find_device(&gpio_class, NULL, chip, match_export);
- if (dev) {
- put_device(dev);
- device_unregister(dev);
- /* prevent further gpiod exports */
- chip->exported = false;
- status = 0;
- } else
- status = -ENODEV;
+ chip->cdev = NULL;
mutex_unlock(&sysfs_lock);
- if (status)
- chip_dbg(chip, "%s: status %d\n", __func__, status);
-
/* unregister gpiod class devices owned by sysfs */
for (i = 0; i < chip->ngpio; i++) {
desc = &chip->desc[i];
@@ -836,19 +784,20 @@ static int __init gpiolib_sysfs_init(void)
*/
spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(chip, &gpio_chips, list) {
- if (chip->exported)
+ if (chip->cdev)
continue;
/*
- * TODO we yield gpio_lock here because gpiochip_export()
- * acquires a mutex. This is unsafe and needs to be fixed.
+ * TODO we yield gpio_lock here because
+ * gpiochip_sysfs_register() acquires a mutex. This is unsafe
+ * and needs to be fixed.
*
* Also it would be nice to use gpiochip_find() here so we
* can keep gpio_chips local to gpiolib.c, but the yield of
* gpio_lock prevents us from doing this.
*/
spin_unlock_irqrestore(&gpio_lock, flags);
- status = gpiochip_export(chip);
+ status = gpiochip_sysfs_register(chip);
spin_lock_irqsave(&gpio_lock, flags);
}
spin_unlock_irqrestore(&gpio_lock, flags);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 6bc612b8a49f..be42ab368a80 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -290,7 +290,7 @@ int gpiochip_add(struct gpio_chip *chip)
of_gpiochip_add(chip);
acpi_gpiochip_add(chip);
- status = gpiochip_export(chip);
+ status = gpiochip_sysfs_register(chip);
if (status)
goto err_remove_chip;
@@ -327,10 +327,12 @@ EXPORT_SYMBOL_GPL(gpiochip_add);
*/
void gpiochip_remove(struct gpio_chip *chip)
{
+ struct gpio_desc *desc;
unsigned long flags;
unsigned id;
+ bool requested = false;
- gpiochip_unexport(chip);
+ gpiochip_sysfs_unregister(chip);
gpiochip_irqchip_remove(chip);
@@ -341,15 +343,17 @@ void gpiochip_remove(struct gpio_chip *chip)
spin_lock_irqsave(&gpio_lock, flags);
for (id = 0; id < chip->ngpio; id++) {
- if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags))
- dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
+ desc = &chip->desc[id];
+ desc->chip = NULL;
+ if (test_bit(FLAG_REQUESTED, &desc->flags))
+ requested = true;
}
- for (id = 0; id < chip->ngpio; id++)
- chip->desc[id].chip = NULL;
-
list_del(&chip->list);
spin_unlock_irqrestore(&gpio_lock, flags);
+ if (requested)
+ dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
+
kfree(chip->desc);
chip->desc = NULL;
}
@@ -441,6 +445,8 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
*/
irq_set_handler_data(parent_irq, gpiochip);
irq_set_chained_handler(parent_irq, parent_handler);
+
+ gpiochip->irq_parent = parent_irq;
}
/* Set the parent IRQ for all affected IRQs */
@@ -549,6 +555,11 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
acpi_gpiochip_free_interrupts(gpiochip);
+ if (gpiochip->irq_parent) {
+ irq_set_chained_handler(gpiochip->irq_parent, NULL);
+ irq_set_handler_data(gpiochip->irq_parent, NULL);
+ }
+
/* Remove all IRQ mappings and delete the domain */
if (gpiochip->irqdomain) {
for (offset = 0; offset < gpiochip->ngpio; offset++)
@@ -608,7 +619,7 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
of_node = gpiochip->dev->of_node;
#ifdef CONFIG_OF_GPIO
/*
- * If the gpiochip has an assigned OF node this takes precendence
+ * If the gpiochip has an assigned OF node this takes precedence
* FIXME: get rid of this and use gpiochip->dev->of_node everywhere
*/
if (gpiochip->of_node)
@@ -1211,7 +1222,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
/*
* _gpio_set_open_drain_value() - Set the open drain gpio's value.
* @desc: gpio descriptor whose state need to be set.
- * @value: Non-zero for setting it HIGH otherise it will set to LOW.
+ * @value: Non-zero for setting it HIGH otherwise it will set to LOW.
*/
static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
{
@@ -1238,7 +1249,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
/*
* _gpio_set_open_source_value() - Set the open source gpio's value.
* @desc: gpio descriptor whose state need to be set.
- * @value: Non-zero for setting it HIGH otherise it will set to LOW.
+ * @value: Non-zero for setting it HIGH otherwise it will set to LOW.
*/
static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value)
{
@@ -1300,17 +1311,16 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip,
continue;
}
/* set outputs if the corresponding mask bit is set */
- if (__test_and_clear_bit(i, mask)) {
+ if (__test_and_clear_bit(i, mask))
chip->set(chip, i, test_bit(i, bits));
- }
}
}
}
-static void gpiod_set_array_priv(bool raw, bool can_sleep,
- unsigned int array_size,
- struct gpio_desc **desc_array,
- int *value_array)
+static void gpiod_set_array_value_priv(bool raw, bool can_sleep,
+ unsigned int array_size,
+ struct gpio_desc **desc_array,
+ int *value_array)
{
int i = 0;
@@ -1320,9 +1330,9 @@ static void gpiod_set_array_priv(bool raw, bool can_sleep,
unsigned long bits[BITS_TO_LONGS(chip->ngpio)];
int count = 0;
- if (!can_sleep) {
+ if (!can_sleep)
WARN_ON(chip->can_sleep);
- }
+
memset(mask, 0, sizeof(mask));
do {
struct gpio_desc *desc = desc_array[i];
@@ -1337,24 +1347,22 @@ static void gpiod_set_array_priv(bool raw, bool can_sleep,
* open drain and open source outputs are set individually
*/
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
- _gpio_set_open_drain_value(desc,value);
+ _gpio_set_open_drain_value(desc, value);
} else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
_gpio_set_open_source_value(desc, value);
} else {
__set_bit(hwgpio, mask);
- if (value) {
+ if (value)
__set_bit(hwgpio, bits);
- } else {
+ else
__clear_bit(hwgpio, bits);
- }
count++;
}
i++;
} while ((i < array_size) && (desc_array[i]->chip == chip));
/* push collected bits to outputs */
- if (count != 0) {
+ if (count != 0)
gpio_chip_set_multiple(chip, mask, bits);
- }
}
}
@@ -1403,7 +1411,7 @@ void gpiod_set_value(struct gpio_desc *desc, int value)
EXPORT_SYMBOL_GPL(gpiod_set_value);
/**
- * gpiod_set_raw_array() - assign values to an array of GPIOs
+ * gpiod_set_raw_array_value() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays
* @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign
@@ -1414,17 +1422,18 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
* This function should be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
-void gpiod_set_raw_array(unsigned int array_size,
+void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array)
{
if (!desc_array)
return;
- gpiod_set_array_priv(true, false, array_size, desc_array, value_array);
+ gpiod_set_array_value_priv(true, false, array_size, desc_array,
+ value_array);
}
-EXPORT_SYMBOL_GPL(gpiod_set_raw_array);
+EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
/**
- * gpiod_set_array() - assign values to an array of GPIOs
+ * gpiod_set_array_value() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays
* @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign
@@ -1435,14 +1444,15 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array);
* This function should be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
-void gpiod_set_array(unsigned int array_size,
- struct gpio_desc **desc_array, int *value_array)
+void gpiod_set_array_value(unsigned int array_size,
+ struct gpio_desc **desc_array, int *value_array)
{
if (!desc_array)
return;
- gpiod_set_array_priv(false, false, array_size, desc_array, value_array);
+ gpiod_set_array_value_priv(false, false, array_size, desc_array,
+ value_array);
}
-EXPORT_SYMBOL_GPL(gpiod_set_array);
+EXPORT_SYMBOL_GPL(gpiod_set_array_value);
/**
* gpiod_cansleep() - report whether gpio value access may sleep
@@ -1604,7 +1614,7 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
/**
- * gpiod_set_raw_array_cansleep() - assign values to an array of GPIOs
+ * gpiod_set_raw_array_value_cansleep() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays
* @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign
@@ -1614,19 +1624,20 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
*
* This function is to be called from contexts that can sleep.
*/
-void gpiod_set_raw_array_cansleep(unsigned int array_size,
- struct gpio_desc **desc_array,
- int *value_array)
+void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
+ struct gpio_desc **desc_array,
+ int *value_array)
{
might_sleep_if(extra_checks);
if (!desc_array)
return;
- gpiod_set_array_priv(true, true, array_size, desc_array, value_array);
+ gpiod_set_array_value_priv(true, true, array_size, desc_array,
+ value_array);
}
-EXPORT_SYMBOL_GPL(gpiod_set_raw_array_cansleep);
+EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep);
/**
- * gpiod_set_array_cansleep() - assign values to an array of GPIOs
+ * gpiod_set_array_value_cansleep() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays
* @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign
@@ -1636,16 +1647,17 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_cansleep);
*
* This function is to be called from contexts that can sleep.
*/
-void gpiod_set_array_cansleep(unsigned int array_size,
- struct gpio_desc **desc_array,
- int *value_array)
+void gpiod_set_array_value_cansleep(unsigned int array_size,
+ struct gpio_desc **desc_array,
+ int *value_array)
{
might_sleep_if(extra_checks);
if (!desc_array)
return;
- gpiod_set_array_priv(false, true, array_size, desc_array, value_array);
+ gpiod_set_array_value_priv(false, true, array_size, desc_array,
+ value_array);
}
-EXPORT_SYMBOL_GPL(gpiod_set_array_cansleep);
+EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep);
/**
* gpiod_add_lookup_table() - register GPIO device consumers
@@ -1880,7 +1892,7 @@ EXPORT_SYMBOL_GPL(gpiod_count);
*
* Return the GPIO descriptor corresponding to the function con_id of device
* dev, -ENOENT if no GPIO has been assigned to the requested function, or
- * another IS_ERR() code if an error occured while trying to acquire the GPIO.
+ * another IS_ERR() code if an error occurred while trying to acquire the GPIO.
*/
struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id,
enum gpiod_flags flags)
@@ -1960,7 +1972,7 @@ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
*
* Return a valid GPIO descriptor, -ENOENT if no GPIO has been assigned to the
* requested function and/or index, or another IS_ERR() code if an error
- * occured while trying to acquire the GPIO.
+ * occurred while trying to acquire the GPIO.
*/
struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
const char *con_id,
@@ -2118,13 +2130,15 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
local_desc = gpiochip_request_own_desc(chip, hwnum, name);
if (IS_ERR(local_desc)) {
- pr_debug("requesting own GPIO %s failed\n", name);
+ pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n",
+ name, chip->label, hwnum);
return PTR_ERR(local_desc);
}
status = gpiod_configure_flags(desc, name, lflags, dflags);
if (status < 0) {
- pr_debug("setup of GPIO %s failed\n", name);
+ pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n",
+ name, chip->label, hwnum);
gpiochip_free_own_desc(desc);
return status;
}
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 594b1798c0e7..bf343004b008 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -83,20 +83,12 @@ struct gpio_desc {
#define FLAG_IS_OUT 1
#define FLAG_EXPORT 2 /* protected by sysfs_lock */
#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
-#define FLAG_TRIG_FALL 4 /* trigger on falling edge */
-#define FLAG_TRIG_RISE 5 /* trigger on rising edge */
#define FLAG_ACTIVE_LOW 6 /* value has active low */
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
-#define FLAG_SYSFS_DIR 10 /* show sysfs direction attribute */
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */
-#define ID_SHIFT 16 /* add new flags before this one */
-
-#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
-#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
-
const char *label;
};
@@ -151,17 +143,17 @@ static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc)
#ifdef CONFIG_GPIO_SYSFS
-int gpiochip_export(struct gpio_chip *chip);
-void gpiochip_unexport(struct gpio_chip *chip);
+int gpiochip_sysfs_register(struct gpio_chip *chip);
+void gpiochip_sysfs_unregister(struct gpio_chip *chip);
#else
-static inline int gpiochip_export(struct gpio_chip *chip)
+static inline int gpiochip_sysfs_register(struct gpio_chip *chip)
{
return 0;
}
-static inline void gpiochip_unexport(struct gpio_chip *chip)
+static inline void gpiochip_sysfs_unregister(struct gpio_chip *chip)
{
}
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 47f2ce81b412..c46ca311d8c3 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -120,6 +120,27 @@ config DRM_RADEON
source "drivers/gpu/drm/radeon/Kconfig"
+config DRM_AMDGPU
+ tristate "AMD GPU"
+ depends on DRM && PCI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FW_LOADER
+ select DRM_KMS_HELPER
+ select DRM_KMS_FB_HELPER
+ select DRM_TTM
+ select POWER_SUPPLY
+ select HWMON
+ select BACKLIGHT_CLASS_DEVICE
+ select INTERVAL_TREE
+ help
+ Choose this option if you have a recent AMD Radeon graphics card.
+
+ If M is selected, the module will be called amdgpu.
+
+source "drivers/gpu/drm/amd/amdgpu/Kconfig"
+
source "drivers/gpu/drm/nouveau/Kconfig"
config DRM_I810
@@ -206,6 +227,8 @@ source "drivers/gpu/drm/qxl/Kconfig"
source "drivers/gpu/drm/bochs/Kconfig"
+source "drivers/gpu/drm/virtio/Kconfig"
+
source "drivers/gpu/drm/msm/Kconfig"
source "drivers/gpu/drm/tegra/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 7d4944e1a60c..5713d0534504 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -2,8 +2,6 @@
# 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
-
drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_context.o drm_dma.o \
drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
@@ -39,6 +37,7 @@ obj-$(CONFIG_DRM_TDFX) += tdfx/
obj-$(CONFIG_DRM_R128) += r128/
obj-$(CONFIG_HSA_AMD) += amd/amdkfd/
obj-$(CONFIG_DRM_RADEON)+= radeon/
+obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/
obj-$(CONFIG_DRM_MGA) += mga/
obj-$(CONFIG_DRM_I810) += i810/
obj-$(CONFIG_DRM_I915) += i915/
@@ -60,9 +59,10 @@ 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-$(CONFIG_DRM_TILCDC) += tilcdc/
+obj-y += tilcdc/
obj-$(CONFIG_DRM_QXL) += qxl/
obj-$(CONFIG_DRM_BOCHS) += bochs/
+obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/
obj-$(CONFIG_DRM_MSM) += msm/
obj-$(CONFIG_DRM_TEGRA) += tegra/
obj-$(CONFIG_DRM_STI) += sti/
diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig
new file mode 100644
index 000000000000..b30fcfa4b1f2
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -0,0 +1,17 @@
+config DRM_AMDGPU_CIK
+ bool "Enable amdgpu support for CIK parts"
+ depends on DRM_AMDGPU
+ help
+ Choose this option if you want to enable experimental support
+ for CIK asics.
+
+ CIK is already supported in radeon. CIK support in amdgpu
+ is for experimentation and testing.
+
+config DRM_AMDGPU_USERPTR
+ bool "Always enable userptr write support"
+ depends on DRM_AMDGPU
+ select MMU_NOTIFIER
+ help
+ This option selects CONFIG_MMU_NOTIFIER if it isn't already
+ selected to enabled full userptr support.
diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile
new file mode 100644
index 000000000000..616dfd4a1398
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/Makefile
@@ -0,0 +1,81 @@
+#
+# 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
+
+amdgpu-y := amdgpu_drv.o
+
+# add KMS driver
+amdgpu-y += amdgpu_device.o amdgpu_kms.o \
+ amdgpu_atombios.o atombios_crtc.o amdgpu_connectors.o \
+ atom.o amdgpu_fence.o amdgpu_ttm.o amdgpu_object.o amdgpu_gart.o \
+ amdgpu_encoders.o amdgpu_display.o amdgpu_i2c.o \
+ amdgpu_fb.o amdgpu_gem.o amdgpu_ring.o \
+ amdgpu_cs.o amdgpu_bios.o amdgpu_benchmark.o amdgpu_test.o \
+ amdgpu_pm.o atombios_dp.o amdgpu_afmt.o amdgpu_trace_points.o \
+ atombios_encoders.o amdgpu_semaphore.o amdgpu_sa.o atombios_i2c.o \
+ amdgpu_prime.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \
+ amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o
+
+# add asic specific block
+amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o gmc_v7_0.o cik_ih.o kv_smc.o kv_dpm.o \
+ ci_smc.o ci_dpm.o dce_v8_0.o gfx_v7_0.o cik_sdma.o uvd_v4_2.o vce_v2_0.o
+
+amdgpu-y += \
+ vi.o
+
+# add GMC block
+amdgpu-y += \
+ gmc_v8_0.o
+
+# add IH block
+amdgpu-y += \
+ amdgpu_irq.o \
+ amdgpu_ih.o \
+ iceland_ih.o \
+ tonga_ih.o \
+ cz_ih.o
+
+# add SMC block
+amdgpu-y += \
+ amdgpu_dpm.o \
+ cz_smc.o cz_dpm.o \
+ tonga_smc.o tonga_dpm.o \
+ iceland_smc.o iceland_dpm.o
+
+# add DCE block
+amdgpu-y += \
+ dce_v10_0.o \
+ dce_v11_0.o
+
+# add GFX block
+amdgpu-y += \
+ amdgpu_gfx.o \
+ gfx_v8_0.o
+
+# add async DMA block
+amdgpu-y += \
+ sdma_v2_4.o \
+ sdma_v3_0.o
+
+# add UVD block
+amdgpu-y += \
+ amdgpu_uvd.o \
+ uvd_v5_0.o \
+ uvd_v6_0.o
+
+# add VCE block
+amdgpu-y += \
+ amdgpu_vce.o \
+ vce_v3_0.o
+
+amdgpu-$(CONFIG_COMPAT) += amdgpu_ioc32.o
+amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o
+amdgpu-$(CONFIG_ACPI) += amdgpu_acpi.o
+amdgpu-$(CONFIG_MMU_NOTIFIER) += amdgpu_mn.o
+
+obj-$(CONFIG_DRM_AMDGPU)+= amdgpu.o
+
+CFLAGS_amdgpu_trace_points.o := -I$(src)
diff --git a/drivers/gpu/drm/amd/amdgpu/ObjectID.h b/drivers/gpu/drm/amd/amdgpu/ObjectID.h
new file mode 100644
index 000000000000..06192698bd96
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/ObjectID.h
@@ -0,0 +1,736 @@
+/*
+* Copyright 2006-2007 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.
+*/
+/* based on stg/asic_reg/drivers/inc/asic_reg/ObjectID.h ver 23 */
+
+#ifndef _OBJECTID_H
+#define _OBJECTID_H
+
+#if defined(_X86_)
+#pragma pack(1)
+#endif
+
+/****************************************************/
+/* Graphics Object Type Definition */
+/****************************************************/
+#define GRAPH_OBJECT_TYPE_NONE 0x0
+#define GRAPH_OBJECT_TYPE_GPU 0x1
+#define GRAPH_OBJECT_TYPE_ENCODER 0x2
+#define GRAPH_OBJECT_TYPE_CONNECTOR 0x3
+#define GRAPH_OBJECT_TYPE_ROUTER 0x4
+/* deleted */
+#define GRAPH_OBJECT_TYPE_DISPLAY_PATH 0x6
+#define GRAPH_OBJECT_TYPE_GENERIC 0x7
+
+/****************************************************/
+/* Encoder Object ID Definition */
+/****************************************************/
+#define ENCODER_OBJECT_ID_NONE 0x00
+
+/* Radeon Class Display Hardware */
+#define ENCODER_OBJECT_ID_INTERNAL_LVDS 0x01
+#define ENCODER_OBJECT_ID_INTERNAL_TMDS1 0x02
+#define ENCODER_OBJECT_ID_INTERNAL_TMDS2 0x03
+#define ENCODER_OBJECT_ID_INTERNAL_DAC1 0x04
+#define ENCODER_OBJECT_ID_INTERNAL_DAC2 0x05 /* TV/CV DAC */
+#define ENCODER_OBJECT_ID_INTERNAL_SDVOA 0x06
+#define ENCODER_OBJECT_ID_INTERNAL_SDVOB 0x07
+
+/* External Third Party Encoders */
+#define ENCODER_OBJECT_ID_SI170B 0x08
+#define ENCODER_OBJECT_ID_CH7303 0x09
+#define ENCODER_OBJECT_ID_CH7301 0x0A
+#define ENCODER_OBJECT_ID_INTERNAL_DVO1 0x0B /* This belongs to Radeon Class Display Hardware */
+#define ENCODER_OBJECT_ID_EXTERNAL_SDVOA 0x0C
+#define ENCODER_OBJECT_ID_EXTERNAL_SDVOB 0x0D
+#define ENCODER_OBJECT_ID_TITFP513 0x0E
+#define ENCODER_OBJECT_ID_INTERNAL_LVTM1 0x0F /* not used for Radeon */
+#define ENCODER_OBJECT_ID_VT1623 0x10
+#define ENCODER_OBJECT_ID_HDMI_SI1930 0x11
+#define ENCODER_OBJECT_ID_HDMI_INTERNAL 0x12
+#define ENCODER_OBJECT_ID_ALMOND 0x22
+#define ENCODER_OBJECT_ID_TRAVIS 0x23
+#define ENCODER_OBJECT_ID_NUTMEG 0x22
+#define ENCODER_OBJECT_ID_HDMI_ANX9805 0x26
+
+/* Kaleidoscope (KLDSCP) Class Display Hardware (internal) */
+#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 0x13
+#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 0x14
+#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1 0x15
+#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2 0x16 /* Shared with CV/TV and CRT */
+#define ENCODER_OBJECT_ID_SI178 0X17 /* External TMDS (dual link, no HDCP.) */
+#define ENCODER_OBJECT_ID_MVPU_FPGA 0x18 /* MVPU FPGA chip */
+#define ENCODER_OBJECT_ID_INTERNAL_DDI 0x19
+#define ENCODER_OBJECT_ID_VT1625 0x1A
+#define ENCODER_OBJECT_ID_HDMI_SI1932 0x1B
+#define ENCODER_OBJECT_ID_DP_AN9801 0x1C
+#define ENCODER_OBJECT_ID_DP_DP501 0x1D
+#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY 0x1E
+#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA 0x1F
+#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 0x20
+#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 0x21
+#define ENCODER_OBJECT_ID_INTERNAL_VCE 0x24
+#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY3 0x25
+#define ENCODER_OBJECT_ID_INTERNAL_AMCLK 0x27
+
+#define ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO 0xFF
+
+/****************************************************/
+/* Connector Object ID Definition */
+/****************************************************/
+#define CONNECTOR_OBJECT_ID_NONE 0x00
+#define CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I 0x01
+#define CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I 0x02
+#define CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D 0x03
+#define CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D 0x04
+#define CONNECTOR_OBJECT_ID_VGA 0x05
+#define CONNECTOR_OBJECT_ID_COMPOSITE 0x06
+#define CONNECTOR_OBJECT_ID_SVIDEO 0x07
+#define CONNECTOR_OBJECT_ID_YPbPr 0x08
+#define CONNECTOR_OBJECT_ID_D_CONNECTOR 0x09
+#define CONNECTOR_OBJECT_ID_9PIN_DIN 0x0A /* Supports both CV & TV */
+#define CONNECTOR_OBJECT_ID_SCART 0x0B
+#define CONNECTOR_OBJECT_ID_HDMI_TYPE_A 0x0C
+#define CONNECTOR_OBJECT_ID_HDMI_TYPE_B 0x0D
+#define CONNECTOR_OBJECT_ID_LVDS 0x0E
+#define CONNECTOR_OBJECT_ID_7PIN_DIN 0x0F
+#define CONNECTOR_OBJECT_ID_PCIE_CONNECTOR 0x10
+#define CONNECTOR_OBJECT_ID_CROSSFIRE 0x11
+#define CONNECTOR_OBJECT_ID_HARDCODE_DVI 0x12
+#define CONNECTOR_OBJECT_ID_DISPLAYPORT 0x13
+#define CONNECTOR_OBJECT_ID_eDP 0x14
+#define CONNECTOR_OBJECT_ID_MXM 0x15
+#define CONNECTOR_OBJECT_ID_LVDS_eDP 0x16
+
+/* deleted */
+
+/****************************************************/
+/* Router Object ID Definition */
+/****************************************************/
+#define ROUTER_OBJECT_ID_NONE 0x00
+#define ROUTER_OBJECT_ID_I2C_EXTENDER_CNTL 0x01
+
+/****************************************************/
+/* Generic Object ID Definition */
+/****************************************************/
+#define GENERIC_OBJECT_ID_NONE 0x00
+#define GENERIC_OBJECT_ID_GLSYNC 0x01
+#define GENERIC_OBJECT_ID_PX2_NON_DRIVABLE 0x02
+#define GENERIC_OBJECT_ID_MXM_OPM 0x03
+#define GENERIC_OBJECT_ID_STEREO_PIN 0x04 //This object could show up from Misc Object table, it follows ATOM_OBJECT format, and contains one ATOM_OBJECT_GPIO_CNTL_RECORD for the stereo pin
+
+/****************************************************/
+/* Graphics Object ENUM ID Definition */
+/****************************************************/
+#define GRAPH_OBJECT_ENUM_ID1 0x01
+#define GRAPH_OBJECT_ENUM_ID2 0x02
+#define GRAPH_OBJECT_ENUM_ID3 0x03
+#define GRAPH_OBJECT_ENUM_ID4 0x04
+#define GRAPH_OBJECT_ENUM_ID5 0x05
+#define GRAPH_OBJECT_ENUM_ID6 0x06
+#define GRAPH_OBJECT_ENUM_ID7 0x07
+
+/****************************************************/
+/* Graphics Object ID Bit definition */
+/****************************************************/
+#define OBJECT_ID_MASK 0x00FF
+#define ENUM_ID_MASK 0x0700
+#define RESERVED1_ID_MASK 0x0800
+#define OBJECT_TYPE_MASK 0x7000
+#define RESERVED2_ID_MASK 0x8000
+
+#define OBJECT_ID_SHIFT 0x00
+#define ENUM_ID_SHIFT 0x08
+#define OBJECT_TYPE_SHIFT 0x0C
+
+
+/****************************************************/
+/* Graphics Object family definition */
+/****************************************************/
+#define CONSTRUCTOBJECTFAMILYID(GRAPHICS_OBJECT_TYPE, GRAPHICS_OBJECT_ID) (GRAPHICS_OBJECT_TYPE << OBJECT_TYPE_SHIFT | \
+ GRAPHICS_OBJECT_ID << OBJECT_ID_SHIFT)
+/****************************************************/
+/* GPU Object ID definition - Shared with BIOS */
+/****************************************************/
+#define GPU_ENUM_ID1 ( GRAPH_OBJECT_TYPE_GPU << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT)
+
+/****************************************************/
+/* Encoder Object ID definition - Shared with BIOS */
+/****************************************************/
+/*
+#define ENCODER_INTERNAL_LVDS_ENUM_ID1 0x2101
+#define ENCODER_INTERNAL_TMDS1_ENUM_ID1 0x2102
+#define ENCODER_INTERNAL_TMDS2_ENUM_ID1 0x2103
+#define ENCODER_INTERNAL_DAC1_ENUM_ID1 0x2104
+#define ENCODER_INTERNAL_DAC2_ENUM_ID1 0x2105
+#define ENCODER_INTERNAL_SDVOA_ENUM_ID1 0x2106
+#define ENCODER_INTERNAL_SDVOB_ENUM_ID1 0x2107
+#define ENCODER_SIL170B_ENUM_ID1 0x2108
+#define ENCODER_CH7303_ENUM_ID1 0x2109
+#define ENCODER_CH7301_ENUM_ID1 0x210A
+#define ENCODER_INTERNAL_DVO1_ENUM_ID1 0x210B
+#define ENCODER_EXTERNAL_SDVOA_ENUM_ID1 0x210C
+#define ENCODER_EXTERNAL_SDVOB_ENUM_ID1 0x210D
+#define ENCODER_TITFP513_ENUM_ID1 0x210E
+#define ENCODER_INTERNAL_LVTM1_ENUM_ID1 0x210F
+#define ENCODER_VT1623_ENUM_ID1 0x2110
+#define ENCODER_HDMI_SI1930_ENUM_ID1 0x2111
+#define ENCODER_HDMI_INTERNAL_ENUM_ID1 0x2112
+#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1 0x2113
+#define ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1 0x2114
+#define ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1 0x2115
+#define ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1 0x2116
+#define ENCODER_SI178_ENUM_ID1 0x2117
+#define ENCODER_MVPU_FPGA_ENUM_ID1 0x2118
+#define ENCODER_INTERNAL_DDI_ENUM_ID1 0x2119
+#define ENCODER_VT1625_ENUM_ID1 0x211A
+#define ENCODER_HDMI_SI1932_ENUM_ID1 0x211B
+#define ENCODER_ENCODER_DP_AN9801_ENUM_ID1 0x211C
+#define ENCODER_DP_DP501_ENUM_ID1 0x211D
+#define ENCODER_INTERNAL_UNIPHY_ENUM_ID1 0x211E
+*/
+#define ENCODER_INTERNAL_LVDS_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_LVDS << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_TMDS1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_TMDS1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_TMDS2_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_TMDS2 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_DAC1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_DAC1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_DAC2_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_DAC2 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_SDVOA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_SDVOA << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_SDVOA_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_SDVOA << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_SDVOB_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_SDVOB << OBJECT_ID_SHIFT)
+
+#define ENCODER_SIL170B_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_SI170B << OBJECT_ID_SHIFT)
+
+#define ENCODER_CH7303_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_CH7303 << OBJECT_ID_SHIFT)
+
+#define ENCODER_CH7301_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_CH7301 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_DVO1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_DVO1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_EXTERNAL_SDVOA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_EXTERNAL_SDVOA << OBJECT_ID_SHIFT)
+
+#define ENCODER_EXTERNAL_SDVOA_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_EXTERNAL_SDVOA << OBJECT_ID_SHIFT)
+
+
+#define ENCODER_EXTERNAL_SDVOB_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_EXTERNAL_SDVOB << OBJECT_ID_SHIFT)
+
+
+#define ENCODER_TITFP513_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_TITFP513 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_LVTM1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_LVTM1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_VT1623_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_VT1623 << OBJECT_ID_SHIFT)
+
+#define ENCODER_HDMI_SI1930_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_HDMI_SI1930 << OBJECT_ID_SHIFT)
+
+#define ENCODER_HDMI_INTERNAL_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_HDMI_INTERNAL << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 << OBJECT_ID_SHIFT)
+
+
+#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 << OBJECT_ID_SHIFT)
+
+
+#define ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2 << OBJECT_ID_SHIFT) // Shared with CV/TV and CRT
+
+#define ENCODER_SI178_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_SI178 << OBJECT_ID_SHIFT)
+
+#define ENCODER_MVPU_FPGA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_MVPU_FPGA << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_DDI_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_DDI << OBJECT_ID_SHIFT)
+
+#define ENCODER_VT1625_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_VT1625 << OBJECT_ID_SHIFT)
+
+#define ENCODER_HDMI_SI1932_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_HDMI_SI1932 << OBJECT_ID_SHIFT)
+
+#define ENCODER_DP_DP501_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_DP_DP501 << OBJECT_ID_SHIFT)
+
+#define ENCODER_DP_AN9801_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_DP_AN9801 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_UNIPHY << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_UNIPHY << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_KLDSCP_LVTMA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY1_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY2_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY2_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY3_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_UNIPHY3 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY3_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_UNIPHY3 << OBJECT_ID_SHIFT)
+
+#define ENCODER_GENERAL_EXTERNAL_DVO_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO << OBJECT_ID_SHIFT)
+
+#define ENCODER_ALMOND_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_ALMOND << OBJECT_ID_SHIFT)
+
+#define ENCODER_ALMOND_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_ALMOND << OBJECT_ID_SHIFT)
+
+#define ENCODER_TRAVIS_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_TRAVIS << OBJECT_ID_SHIFT)
+
+#define ENCODER_TRAVIS_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_TRAVIS << OBJECT_ID_SHIFT)
+
+#define ENCODER_NUTMEG_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_NUTMEG << OBJECT_ID_SHIFT)
+
+#define ENCODER_VCE_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_INTERNAL_VCE << OBJECT_ID_SHIFT)
+
+#define ENCODER_HDMI_ANX9805_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ENCODER_OBJECT_ID_HDMI_ANX9805 << OBJECT_ID_SHIFT)
+
+/****************************************************/
+/* Connector Object ID definition - Shared with BIOS */
+/****************************************************/
+/*
+#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID1 0x3101
+#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID1 0x3102
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID1 0x3103
+#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 0x3104
+#define CONNECTOR_VGA_ENUM_ID1 0x3105
+#define CONNECTOR_COMPOSITE_ENUM_ID1 0x3106
+#define CONNECTOR_SVIDEO_ENUM_ID1 0x3107
+#define CONNECTOR_YPbPr_ENUM_ID1 0x3108
+#define CONNECTOR_D_CONNECTORE_ENUM_ID1 0x3109
+#define CONNECTOR_9PIN_DIN_ENUM_ID1 0x310A
+#define CONNECTOR_SCART_ENUM_ID1 0x310B
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID1 0x310C
+#define CONNECTOR_HDMI_TYPE_B_ENUM_ID1 0x310D
+#define CONNECTOR_LVDS_ENUM_ID1 0x310E
+#define CONNECTOR_7PIN_DIN_ENUM_ID1 0x310F
+#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID1 0x3110
+*/
+#define CONNECTOR_LVDS_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_LVDS << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_LVDS_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_LVDS << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_eDP_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_eDP << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_eDP_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_eDP << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID5 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID6 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_VGA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_VGA_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_COMPOSITE_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_COMPOSITE << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_COMPOSITE_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_COMPOSITE << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SVIDEO_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SVIDEO << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SVIDEO_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SVIDEO << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_YPbPr_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_YPbPr << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_YPbPr_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_YPbPr << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_D_CONNECTOR_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_D_CONNECTOR << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_D_CONNECTOR_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_D_CONNECTOR << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_9PIN_DIN_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_9PIN_DIN << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_9PIN_DIN_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_9PIN_DIN << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SCART_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SCART << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SCART_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_SCART << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID5 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID6 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_B_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_HDMI_TYPE_B << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_B_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_HDMI_TYPE_B << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_7PIN_DIN_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_7PIN_DIN << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_7PIN_DIN_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_7PIN_DIN << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_PCIE_CONNECTOR << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_PCIE_CONNECTOR << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_CROSSFIRE_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_CROSSFIRE << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_CROSSFIRE_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_CROSSFIRE << OBJECT_ID_SHIFT)
+
+
+#define CONNECTOR_HARDCODE_DVI_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_HARDCODE_DVI << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HARDCODE_DVI_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_HARDCODE_DVI << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DISPLAYPORT_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DISPLAYPORT_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DISPLAYPORT_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DISPLAYPORT_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DISPLAYPORT_ENUM_ID5 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DISPLAYPORT_ENUM_ID6 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_MXM_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DP_A
+
+#define CONNECTOR_MXM_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DP_B
+
+#define CONNECTOR_MXM_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DP_C
+
+#define CONNECTOR_MXM_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DP_D
+
+#define CONNECTOR_MXM_ENUM_ID5 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_LVDS_TXxx
+
+#define CONNECTOR_MXM_ENUM_ID6 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_LVDS_UXxx
+
+#define CONNECTOR_MXM_ENUM_ID7 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID7 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DAC
+
+#define CONNECTOR_LVDS_eDP_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_LVDS_eDP << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_LVDS_eDP_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ CONNECTOR_OBJECT_ID_LVDS_eDP << OBJECT_ID_SHIFT)
+
+/****************************************************/
+/* Router Object ID definition - Shared with BIOS */
+/****************************************************/
+#define ROUTER_I2C_EXTENDER_CNTL_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ROUTER << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ ROUTER_OBJECT_ID_I2C_EXTENDER_CNTL << OBJECT_ID_SHIFT)
+
+/* deleted */
+
+/****************************************************/
+/* Generic Object ID definition - Shared with BIOS */
+/****************************************************/
+#define GENERICOBJECT_GLSYNC_ENUM_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ GENERIC_OBJECT_ID_GLSYNC << OBJECT_ID_SHIFT)
+
+#define GENERICOBJECT_PX2_NON_DRIVABLE_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ GENERIC_OBJECT_ID_PX2_NON_DRIVABLE<< OBJECT_ID_SHIFT)
+
+#define GENERICOBJECT_PX2_NON_DRIVABLE_ID2 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+ GENERIC_OBJECT_ID_PX2_NON_DRIVABLE<< OBJECT_ID_SHIFT)
+
+#define GENERICOBJECT_MXM_OPM_ENUM_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ GENERIC_OBJECT_ID_MXM_OPM << OBJECT_ID_SHIFT)
+
+#define GENERICOBJECT_STEREO_PIN_ENUM_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\
+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+ GENERIC_OBJECT_ID_STEREO_PIN << OBJECT_ID_SHIFT)
+
+/****************************************************/
+/* Object Cap definition - Shared with BIOS */
+/****************************************************/
+#define GRAPHICS_OBJECT_CAP_I2C 0x00000001L
+#define GRAPHICS_OBJECT_CAP_TABLE_ID 0x00000002L
+
+
+#define GRAPHICS_OBJECT_I2CCOMMAND_TABLE_ID 0x01
+#define GRAPHICS_OBJECT_HOTPLUGDETECTIONINTERUPT_TABLE_ID 0x02
+#define GRAPHICS_OBJECT_ENCODER_OUTPUT_PROTECTION_TABLE_ID 0x03
+
+#if defined(_X86_)
+#pragma pack()
+#endif
+
+#endif /*GRAPHICTYPE */
+
+
+
+
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
new file mode 100644
index 000000000000..22866d1c3d69
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -0,0 +1,2337 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#ifndef __AMDGPU_H__
+#define __AMDGPU_H__
+
+#include <linux/atomic.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/kref.h>
+#include <linux/interval_tree.h>
+#include <linux/hashtable.h>
+#include <linux/fence.h>
+
+#include <ttm/ttm_bo_api.h>
+#include <ttm/ttm_bo_driver.h>
+#include <ttm/ttm_placement.h>
+#include <ttm/ttm_module.h>
+#include <ttm/ttm_execbuf_util.h>
+
+#include <drm/drm_gem.h>
+#include <drm/amdgpu_drm.h>
+
+#include "amd_shared.h"
+#include "amdgpu_family.h"
+#include "amdgpu_mode.h"
+#include "amdgpu_ih.h"
+#include "amdgpu_irq.h"
+#include "amdgpu_ucode.h"
+#include "amdgpu_gds.h"
+
+/*
+ * Modules parameters.
+ */
+extern int amdgpu_modeset;
+extern int amdgpu_vram_limit;
+extern int amdgpu_gart_size;
+extern int amdgpu_benchmarking;
+extern int amdgpu_testing;
+extern int amdgpu_audio;
+extern int amdgpu_disp_priority;
+extern int amdgpu_hw_i2c;
+extern int amdgpu_pcie_gen2;
+extern int amdgpu_msi;
+extern int amdgpu_lockup_timeout;
+extern int amdgpu_dpm;
+extern int amdgpu_smc_load_fw;
+extern int amdgpu_aspm;
+extern int amdgpu_runtime_pm;
+extern int amdgpu_hard_reset;
+extern unsigned amdgpu_ip_block_mask;
+extern int amdgpu_bapm;
+extern int amdgpu_deep_color;
+extern int amdgpu_vm_size;
+extern int amdgpu_vm_block_size;
+
+#define AMDGPU_MAX_USEC_TIMEOUT 100000 /* 100 ms */
+#define AMDGPU_FENCE_JIFFIES_TIMEOUT (HZ / 2)
+/* AMDGPU_IB_POOL_SIZE must be a power of 2 */
+#define AMDGPU_IB_POOL_SIZE 16
+#define AMDGPU_DEBUGFS_MAX_COMPONENTS 32
+#define AMDGPUFB_CONN_LIMIT 4
+#define AMDGPU_BIOS_NUM_SCRATCH 8
+
+/* max number of rings */
+#define AMDGPU_MAX_RINGS 16
+#define AMDGPU_MAX_GFX_RINGS 1
+#define AMDGPU_MAX_COMPUTE_RINGS 8
+#define AMDGPU_MAX_VCE_RINGS 2
+
+/* number of hw syncs before falling back on blocking */
+#define AMDGPU_NUM_SYNCS 4
+
+/* hardcode that limit for now */
+#define AMDGPU_VA_RESERVED_SIZE (8 << 20)
+
+/* hard reset data */
+#define AMDGPU_ASIC_RESET_DATA 0x39d5e86b
+
+/* reset flags */
+#define AMDGPU_RESET_GFX (1 << 0)
+#define AMDGPU_RESET_COMPUTE (1 << 1)
+#define AMDGPU_RESET_DMA (1 << 2)
+#define AMDGPU_RESET_CP (1 << 3)
+#define AMDGPU_RESET_GRBM (1 << 4)
+#define AMDGPU_RESET_DMA1 (1 << 5)
+#define AMDGPU_RESET_RLC (1 << 6)
+#define AMDGPU_RESET_SEM (1 << 7)
+#define AMDGPU_RESET_IH (1 << 8)
+#define AMDGPU_RESET_VMC (1 << 9)
+#define AMDGPU_RESET_MC (1 << 10)
+#define AMDGPU_RESET_DISPLAY (1 << 11)
+#define AMDGPU_RESET_UVD (1 << 12)
+#define AMDGPU_RESET_VCE (1 << 13)
+#define AMDGPU_RESET_VCE1 (1 << 14)
+
+/* CG block flags */
+#define AMDGPU_CG_BLOCK_GFX (1 << 0)
+#define AMDGPU_CG_BLOCK_MC (1 << 1)
+#define AMDGPU_CG_BLOCK_SDMA (1 << 2)
+#define AMDGPU_CG_BLOCK_UVD (1 << 3)
+#define AMDGPU_CG_BLOCK_VCE (1 << 4)
+#define AMDGPU_CG_BLOCK_HDP (1 << 5)
+#define AMDGPU_CG_BLOCK_BIF (1 << 6)
+
+/* CG flags */
+#define AMDGPU_CG_SUPPORT_GFX_MGCG (1 << 0)
+#define AMDGPU_CG_SUPPORT_GFX_MGLS (1 << 1)
+#define AMDGPU_CG_SUPPORT_GFX_CGCG (1 << 2)
+#define AMDGPU_CG_SUPPORT_GFX_CGLS (1 << 3)
+#define AMDGPU_CG_SUPPORT_GFX_CGTS (1 << 4)
+#define AMDGPU_CG_SUPPORT_GFX_CGTS_LS (1 << 5)
+#define AMDGPU_CG_SUPPORT_GFX_CP_LS (1 << 6)
+#define AMDGPU_CG_SUPPORT_GFX_RLC_LS (1 << 7)
+#define AMDGPU_CG_SUPPORT_MC_LS (1 << 8)
+#define AMDGPU_CG_SUPPORT_MC_MGCG (1 << 9)
+#define AMDGPU_CG_SUPPORT_SDMA_LS (1 << 10)
+#define AMDGPU_CG_SUPPORT_SDMA_MGCG (1 << 11)
+#define AMDGPU_CG_SUPPORT_BIF_LS (1 << 12)
+#define AMDGPU_CG_SUPPORT_UVD_MGCG (1 << 13)
+#define AMDGPU_CG_SUPPORT_VCE_MGCG (1 << 14)
+#define AMDGPU_CG_SUPPORT_HDP_LS (1 << 15)
+#define AMDGPU_CG_SUPPORT_HDP_MGCG (1 << 16)
+
+/* PG flags */
+#define AMDGPU_PG_SUPPORT_GFX_PG (1 << 0)
+#define AMDGPU_PG_SUPPORT_GFX_SMG (1 << 1)
+#define AMDGPU_PG_SUPPORT_GFX_DMG (1 << 2)
+#define AMDGPU_PG_SUPPORT_UVD (1 << 3)
+#define AMDGPU_PG_SUPPORT_VCE (1 << 4)
+#define AMDGPU_PG_SUPPORT_CP (1 << 5)
+#define AMDGPU_PG_SUPPORT_GDS (1 << 6)
+#define AMDGPU_PG_SUPPORT_RLC_SMU_HS (1 << 7)
+#define AMDGPU_PG_SUPPORT_SDMA (1 << 8)
+#define AMDGPU_PG_SUPPORT_ACP (1 << 9)
+#define AMDGPU_PG_SUPPORT_SAMU (1 << 10)
+
+/* GFX current status */
+#define AMDGPU_GFX_NORMAL_MODE 0x00000000L
+#define AMDGPU_GFX_SAFE_MODE 0x00000001L
+#define AMDGPU_GFX_PG_DISABLED_MODE 0x00000002L
+#define AMDGPU_GFX_CG_DISABLED_MODE 0x00000004L
+#define AMDGPU_GFX_LBPW_DISABLED_MODE 0x00000008L
+
+/* max cursor sizes (in pixels) */
+#define CIK_CURSOR_WIDTH 128
+#define CIK_CURSOR_HEIGHT 128
+
+struct amdgpu_device;
+struct amdgpu_fence;
+struct amdgpu_ib;
+struct amdgpu_vm;
+struct amdgpu_ring;
+struct amdgpu_semaphore;
+struct amdgpu_cs_parser;
+struct amdgpu_irq_src;
+
+enum amdgpu_cp_irq {
+ AMDGPU_CP_IRQ_GFX_EOP = 0,
+ AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP,
+ AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE1_EOP,
+ AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE2_EOP,
+ AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE3_EOP,
+ AMDGPU_CP_IRQ_COMPUTE_MEC2_PIPE0_EOP,
+ AMDGPU_CP_IRQ_COMPUTE_MEC2_PIPE1_EOP,
+ AMDGPU_CP_IRQ_COMPUTE_MEC2_PIPE2_EOP,
+ AMDGPU_CP_IRQ_COMPUTE_MEC2_PIPE3_EOP,
+
+ AMDGPU_CP_IRQ_LAST
+};
+
+enum amdgpu_sdma_irq {
+ AMDGPU_SDMA_IRQ_TRAP0 = 0,
+ AMDGPU_SDMA_IRQ_TRAP1,
+
+ AMDGPU_SDMA_IRQ_LAST
+};
+
+enum amdgpu_thermal_irq {
+ AMDGPU_THERMAL_IRQ_LOW_TO_HIGH = 0,
+ AMDGPU_THERMAL_IRQ_HIGH_TO_LOW,
+
+ AMDGPU_THERMAL_IRQ_LAST
+};
+
+int amdgpu_set_clockgating_state(struct amdgpu_device *adev,
+ enum amd_ip_block_type block_type,
+ enum amd_clockgating_state state);
+int amdgpu_set_powergating_state(struct amdgpu_device *adev,
+ enum amd_ip_block_type block_type,
+ enum amd_powergating_state state);
+
+struct amdgpu_ip_block_version {
+ enum amd_ip_block_type type;
+ u32 major;
+ u32 minor;
+ u32 rev;
+ const struct amd_ip_funcs *funcs;
+};
+
+int amdgpu_ip_block_version_cmp(struct amdgpu_device *adev,
+ enum amd_ip_block_type type,
+ u32 major, u32 minor);
+
+const struct amdgpu_ip_block_version * amdgpu_get_ip_block(
+ struct amdgpu_device *adev,
+ enum amd_ip_block_type type);
+
+/* provided by hw blocks that can move/clear data. e.g., gfx or sdma */
+struct amdgpu_buffer_funcs {
+ /* maximum bytes in a single operation */
+ uint32_t copy_max_bytes;
+
+ /* number of dw to reserve per operation */
+ unsigned copy_num_dw;
+
+ /* used for buffer migration */
+ void (*emit_copy_buffer)(struct amdgpu_ring *ring,
+ /* src addr in bytes */
+ uint64_t src_offset,
+ /* dst addr in bytes */
+ uint64_t dst_offset,
+ /* number of byte to transfer */
+ uint32_t byte_count);
+
+ /* maximum bytes in a single operation */
+ uint32_t fill_max_bytes;
+
+ /* number of dw to reserve per operation */
+ unsigned fill_num_dw;
+
+ /* used for buffer clearing */
+ void (*emit_fill_buffer)(struct amdgpu_ring *ring,
+ /* value to write to memory */
+ uint32_t src_data,
+ /* dst addr in bytes */
+ uint64_t dst_offset,
+ /* number of byte to fill */
+ uint32_t byte_count);
+};
+
+/* provided by hw blocks that can write ptes, e.g., sdma */
+struct amdgpu_vm_pte_funcs {
+ /* copy pte entries from GART */
+ void (*copy_pte)(struct amdgpu_ib *ib,
+ uint64_t pe, uint64_t src,
+ unsigned count);
+ /* write pte one entry at a time with addr mapping */
+ void (*write_pte)(struct amdgpu_ib *ib,
+ uint64_t pe,
+ uint64_t addr, unsigned count,
+ uint32_t incr, uint32_t flags);
+ /* for linear pte/pde updates without addr mapping */
+ void (*set_pte_pde)(struct amdgpu_ib *ib,
+ uint64_t pe,
+ uint64_t addr, unsigned count,
+ uint32_t incr, uint32_t flags);
+ /* pad the indirect buffer to the necessary number of dw */
+ void (*pad_ib)(struct amdgpu_ib *ib);
+};
+
+/* provided by the gmc block */
+struct amdgpu_gart_funcs {
+ /* flush the vm tlb via mmio */
+ void (*flush_gpu_tlb)(struct amdgpu_device *adev,
+ uint32_t vmid);
+ /* write pte/pde updates using the cpu */
+ int (*set_pte_pde)(struct amdgpu_device *adev,
+ void *cpu_pt_addr, /* cpu addr of page table */
+ uint32_t gpu_page_idx, /* pte/pde to update */
+ uint64_t addr, /* addr to write into pte/pde */
+ uint32_t flags); /* access flags */
+};
+
+/* provided by the ih block */
+struct amdgpu_ih_funcs {
+ /* ring read/write ptr handling, called from interrupt context */
+ u32 (*get_wptr)(struct amdgpu_device *adev);
+ void (*decode_iv)(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry);
+ void (*set_rptr)(struct amdgpu_device *adev);
+};
+
+/* provided by hw blocks that expose a ring buffer for commands */
+struct amdgpu_ring_funcs {
+ /* ring read/write ptr handling */
+ u32 (*get_rptr)(struct amdgpu_ring *ring);
+ u32 (*get_wptr)(struct amdgpu_ring *ring);
+ void (*set_wptr)(struct amdgpu_ring *ring);
+ /* validating and patching of IBs */
+ int (*parse_cs)(struct amdgpu_cs_parser *p, uint32_t ib_idx);
+ /* command emit functions */
+ void (*emit_ib)(struct amdgpu_ring *ring,
+ struct amdgpu_ib *ib);
+ void (*emit_fence)(struct amdgpu_ring *ring, uint64_t addr,
+ uint64_t seq, unsigned flags);
+ bool (*emit_semaphore)(struct amdgpu_ring *ring,
+ struct amdgpu_semaphore *semaphore,
+ bool emit_wait);
+ void (*emit_vm_flush)(struct amdgpu_ring *ring, unsigned vm_id,
+ uint64_t pd_addr);
+ void (*emit_hdp_flush)(struct amdgpu_ring *ring);
+ void (*emit_gds_switch)(struct amdgpu_ring *ring, uint32_t vmid,
+ uint32_t gds_base, uint32_t gds_size,
+ uint32_t gws_base, uint32_t gws_size,
+ uint32_t oa_base, uint32_t oa_size);
+ /* testing functions */
+ int (*test_ring)(struct amdgpu_ring *ring);
+ int (*test_ib)(struct amdgpu_ring *ring);
+ bool (*is_lockup)(struct amdgpu_ring *ring);
+};
+
+/*
+ * BIOS.
+ */
+bool amdgpu_get_bios(struct amdgpu_device *adev);
+bool amdgpu_read_bios(struct amdgpu_device *adev);
+
+/*
+ * Dummy page
+ */
+struct amdgpu_dummy_page {
+ struct page *page;
+ dma_addr_t addr;
+};
+int amdgpu_dummy_page_init(struct amdgpu_device *adev);
+void amdgpu_dummy_page_fini(struct amdgpu_device *adev);
+
+
+/*
+ * Clocks
+ */
+
+#define AMDGPU_MAX_PPLL 3
+
+struct amdgpu_clock {
+ struct amdgpu_pll ppll[AMDGPU_MAX_PPLL];
+ struct amdgpu_pll spll;
+ struct amdgpu_pll mpll;
+ /* 10 Khz units */
+ uint32_t default_mclk;
+ uint32_t default_sclk;
+ uint32_t default_dispclk;
+ uint32_t current_dispclk;
+ uint32_t dp_extclk;
+ uint32_t max_pixel_clock;
+};
+
+/*
+ * Fences.
+ */
+struct amdgpu_fence_driver {
+ struct amdgpu_ring *ring;
+ uint64_t gpu_addr;
+ volatile uint32_t *cpu_addr;
+ /* sync_seq is protected by ring emission lock */
+ uint64_t sync_seq[AMDGPU_MAX_RINGS];
+ atomic64_t last_seq;
+ bool initialized;
+ bool delayed_irq;
+ struct amdgpu_irq_src *irq_src;
+ unsigned irq_type;
+ struct delayed_work lockup_work;
+};
+
+/* some special values for the owner field */
+#define AMDGPU_FENCE_OWNER_UNDEFINED ((void*)0ul)
+#define AMDGPU_FENCE_OWNER_VM ((void*)1ul)
+#define AMDGPU_FENCE_OWNER_MOVE ((void*)2ul)
+
+#define AMDGPU_FENCE_FLAG_64BIT (1 << 0)
+#define AMDGPU_FENCE_FLAG_INT (1 << 1)
+
+struct amdgpu_fence {
+ struct fence base;
+
+ /* RB, DMA, etc. */
+ struct amdgpu_ring *ring;
+ uint64_t seq;
+
+ /* filp or special value for fence creator */
+ void *owner;
+
+ wait_queue_t fence_wake;
+};
+
+struct amdgpu_user_fence {
+ /* write-back bo */
+ struct amdgpu_bo *bo;
+ /* write-back address offset to bo start */
+ uint32_t offset;
+};
+
+int amdgpu_fence_driver_init(struct amdgpu_device *adev);
+void amdgpu_fence_driver_fini(struct amdgpu_device *adev);
+void amdgpu_fence_driver_force_completion(struct amdgpu_device *adev);
+
+void amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring);
+int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
+ struct amdgpu_irq_src *irq_src,
+ unsigned irq_type);
+int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner,
+ struct amdgpu_fence **fence);
+void amdgpu_fence_process(struct amdgpu_ring *ring);
+int amdgpu_fence_wait_next(struct amdgpu_ring *ring);
+int amdgpu_fence_wait_empty(struct amdgpu_ring *ring);
+unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring);
+
+bool amdgpu_fence_signaled(struct amdgpu_fence *fence);
+int amdgpu_fence_wait(struct amdgpu_fence *fence, bool interruptible);
+int amdgpu_fence_wait_any(struct amdgpu_device *adev,
+ struct amdgpu_fence **fences,
+ bool intr);
+long amdgpu_fence_wait_seq_timeout(struct amdgpu_device *adev,
+ u64 *target_seq, bool intr,
+ long timeout);
+struct amdgpu_fence *amdgpu_fence_ref(struct amdgpu_fence *fence);
+void amdgpu_fence_unref(struct amdgpu_fence **fence);
+
+bool amdgpu_fence_need_sync(struct amdgpu_fence *fence,
+ struct amdgpu_ring *ring);
+void amdgpu_fence_note_sync(struct amdgpu_fence *fence,
+ struct amdgpu_ring *ring);
+
+static inline struct amdgpu_fence *amdgpu_fence_later(struct amdgpu_fence *a,
+ struct amdgpu_fence *b)
+{
+ if (!a) {
+ return b;
+ }
+
+ if (!b) {
+ return a;
+ }
+
+ BUG_ON(a->ring != b->ring);
+
+ if (a->seq > b->seq) {
+ return a;
+ } else {
+ return b;
+ }
+}
+
+static inline bool amdgpu_fence_is_earlier(struct amdgpu_fence *a,
+ struct amdgpu_fence *b)
+{
+ if (!a) {
+ return false;
+ }
+
+ if (!b) {
+ return true;
+ }
+
+ BUG_ON(a->ring != b->ring);
+
+ return a->seq < b->seq;
+}
+
+int amdgpu_user_fence_emit(struct amdgpu_ring *ring, struct amdgpu_user_fence *user,
+ void *owner, struct amdgpu_fence **fence);
+
+/*
+ * TTM.
+ */
+struct amdgpu_mman {
+ struct ttm_bo_global_ref bo_global_ref;
+ struct drm_global_reference mem_global_ref;
+ struct ttm_bo_device bdev;
+ bool mem_global_referenced;
+ bool initialized;
+
+#if defined(CONFIG_DEBUG_FS)
+ struct dentry *vram;
+ struct dentry *gtt;
+#endif
+
+ /* buffer handling */
+ const struct amdgpu_buffer_funcs *buffer_funcs;
+ struct amdgpu_ring *buffer_funcs_ring;
+};
+
+int amdgpu_copy_buffer(struct amdgpu_ring *ring,
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ uint32_t byte_count,
+ struct reservation_object *resv,
+ struct amdgpu_fence **fence);
+int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma);
+
+struct amdgpu_bo_list_entry {
+ struct amdgpu_bo *robj;
+ struct ttm_validate_buffer tv;
+ struct amdgpu_bo_va *bo_va;
+ unsigned prefered_domains;
+ unsigned allowed_domains;
+ uint32_t priority;
+};
+
+struct amdgpu_bo_va_mapping {
+ struct list_head list;
+ struct interval_tree_node it;
+ uint64_t offset;
+ uint32_t flags;
+};
+
+/* bo virtual addresses in a specific vm */
+struct amdgpu_bo_va {
+ /* protected by bo being reserved */
+ struct list_head bo_list;
+ uint64_t addr;
+ struct amdgpu_fence *last_pt_update;
+ unsigned ref_count;
+
+ /* protected by vm mutex */
+ struct list_head mappings;
+ struct list_head vm_status;
+
+ /* constant after initialization */
+ struct amdgpu_vm *vm;
+ struct amdgpu_bo *bo;
+};
+
+#define AMDGPU_GEM_DOMAIN_MAX 0x3
+
+struct amdgpu_bo {
+ /* Protected by gem.mutex */
+ struct list_head list;
+ /* Protected by tbo.reserved */
+ u32 initial_domain;
+ struct ttm_place placements[AMDGPU_GEM_DOMAIN_MAX + 1];
+ struct ttm_placement placement;
+ struct ttm_buffer_object tbo;
+ struct ttm_bo_kmap_obj kmap;
+ u64 flags;
+ unsigned pin_count;
+ void *kptr;
+ u64 tiling_flags;
+ u64 metadata_flags;
+ void *metadata;
+ u32 metadata_size;
+ /* list of all virtual address to which this bo
+ * is associated to
+ */
+ struct list_head va;
+ /* Constant after initialization */
+ struct amdgpu_device *adev;
+ struct drm_gem_object gem_base;
+
+ struct ttm_bo_kmap_obj dma_buf_vmap;
+ pid_t pid;
+ struct amdgpu_mn *mn;
+ struct list_head mn_list;
+};
+#define gem_to_amdgpu_bo(gobj) container_of((gobj), struct amdgpu_bo, gem_base)
+
+void amdgpu_gem_object_free(struct drm_gem_object *obj);
+int amdgpu_gem_object_open(struct drm_gem_object *obj,
+ struct drm_file *file_priv);
+void amdgpu_gem_object_close(struct drm_gem_object *obj,
+ struct drm_file *file_priv);
+unsigned long amdgpu_gem_timeout(uint64_t timeout_ns);
+struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj);
+struct drm_gem_object *amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
+ struct dma_buf_attachment *attach,
+ struct sg_table *sg);
+struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *gobj,
+ int flags);
+int amdgpu_gem_prime_pin(struct drm_gem_object *obj);
+void amdgpu_gem_prime_unpin(struct drm_gem_object *obj);
+struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *);
+void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj);
+void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+int amdgpu_gem_debugfs_init(struct amdgpu_device *adev);
+
+/* sub-allocation manager, it has to be protected by another lock.
+ * By conception this is an helper for other part of the driver
+ * like the indirect buffer or semaphore, which both have their
+ * locking.
+ *
+ * Principe is simple, we keep a list of sub allocation in offset
+ * order (first entry has offset == 0, last entry has the highest
+ * offset).
+ *
+ * When allocating new object we first check if there is room at
+ * the end total_size - (last_object_offset + last_object_size) >=
+ * alloc_size. If so we allocate new object there.
+ *
+ * When there is not enough room at the end, we start waiting for
+ * each sub object until we reach object_offset+object_size >=
+ * alloc_size, this object then become the sub object we return.
+ *
+ * Alignment can't be bigger than page size.
+ *
+ * Hole are not considered for allocation to keep things simple.
+ * Assumption is that there won't be hole (all object on same
+ * alignment).
+ */
+struct amdgpu_sa_manager {
+ wait_queue_head_t wq;
+ struct amdgpu_bo *bo;
+ struct list_head *hole;
+ struct list_head flist[AMDGPU_MAX_RINGS];
+ struct list_head olist;
+ unsigned size;
+ uint64_t gpu_addr;
+ void *cpu_ptr;
+ uint32_t domain;
+ uint32_t align;
+};
+
+struct amdgpu_sa_bo;
+
+/* sub-allocation buffer */
+struct amdgpu_sa_bo {
+ struct list_head olist;
+ struct list_head flist;
+ struct amdgpu_sa_manager *manager;
+ unsigned soffset;
+ unsigned eoffset;
+ struct amdgpu_fence *fence;
+};
+
+/*
+ * GEM objects.
+ */
+struct amdgpu_gem {
+ struct mutex mutex;
+ struct list_head objects;
+};
+
+int amdgpu_gem_init(struct amdgpu_device *adev);
+void amdgpu_gem_fini(struct amdgpu_device *adev);
+int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size,
+ int alignment, u32 initial_domain,
+ u64 flags, bool kernel,
+ struct drm_gem_object **obj);
+
+int amdgpu_mode_dumb_create(struct drm_file *file_priv,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args);
+int amdgpu_mode_dumb_mmap(struct drm_file *filp,
+ struct drm_device *dev,
+ uint32_t handle, uint64_t *offset_p);
+
+/*
+ * Semaphores.
+ */
+struct amdgpu_semaphore {
+ struct amdgpu_sa_bo *sa_bo;
+ signed waiters;
+ uint64_t gpu_addr;
+};
+
+int amdgpu_semaphore_create(struct amdgpu_device *adev,
+ struct amdgpu_semaphore **semaphore);
+bool amdgpu_semaphore_emit_signal(struct amdgpu_ring *ring,
+ struct amdgpu_semaphore *semaphore);
+bool amdgpu_semaphore_emit_wait(struct amdgpu_ring *ring,
+ struct amdgpu_semaphore *semaphore);
+void amdgpu_semaphore_free(struct amdgpu_device *adev,
+ struct amdgpu_semaphore **semaphore,
+ struct amdgpu_fence *fence);
+
+/*
+ * Synchronization
+ */
+struct amdgpu_sync {
+ struct amdgpu_semaphore *semaphores[AMDGPU_NUM_SYNCS];
+ struct amdgpu_fence *sync_to[AMDGPU_MAX_RINGS];
+ struct amdgpu_fence *last_vm_update;
+};
+
+void amdgpu_sync_create(struct amdgpu_sync *sync);
+void amdgpu_sync_fence(struct amdgpu_sync *sync,
+ struct amdgpu_fence *fence);
+int amdgpu_sync_resv(struct amdgpu_device *adev,
+ struct amdgpu_sync *sync,
+ struct reservation_object *resv,
+ void *owner);
+int amdgpu_sync_rings(struct amdgpu_sync *sync,
+ struct amdgpu_ring *ring);
+void amdgpu_sync_free(struct amdgpu_device *adev, struct amdgpu_sync *sync,
+ struct amdgpu_fence *fence);
+
+/*
+ * GART structures, functions & helpers
+ */
+struct amdgpu_mc;
+
+#define AMDGPU_GPU_PAGE_SIZE 4096
+#define AMDGPU_GPU_PAGE_MASK (AMDGPU_GPU_PAGE_SIZE - 1)
+#define AMDGPU_GPU_PAGE_SHIFT 12
+#define AMDGPU_GPU_PAGE_ALIGN(a) (((a) + AMDGPU_GPU_PAGE_MASK) & ~AMDGPU_GPU_PAGE_MASK)
+
+struct amdgpu_gart {
+ dma_addr_t table_addr;
+ struct amdgpu_bo *robj;
+ void *ptr;
+ unsigned num_gpu_pages;
+ unsigned num_cpu_pages;
+ unsigned table_size;
+ struct page **pages;
+ dma_addr_t *pages_addr;
+ bool ready;
+ const struct amdgpu_gart_funcs *gart_funcs;
+};
+
+int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev);
+void amdgpu_gart_table_ram_free(struct amdgpu_device *adev);
+int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev);
+void amdgpu_gart_table_vram_free(struct amdgpu_device *adev);
+int amdgpu_gart_table_vram_pin(struct amdgpu_device *adev);
+void amdgpu_gart_table_vram_unpin(struct amdgpu_device *adev);
+int amdgpu_gart_init(struct amdgpu_device *adev);
+void amdgpu_gart_fini(struct amdgpu_device *adev);
+void amdgpu_gart_unbind(struct amdgpu_device *adev, unsigned offset,
+ int pages);
+int amdgpu_gart_bind(struct amdgpu_device *adev, unsigned offset,
+ int pages, struct page **pagelist,
+ dma_addr_t *dma_addr, uint32_t flags);
+
+/*
+ * GPU MC structures, functions & helpers
+ */
+struct amdgpu_mc {
+ resource_size_t aper_size;
+ resource_size_t aper_base;
+ resource_size_t agp_base;
+ /* for some chips with <= 32MB we need to lie
+ * about vram size near mc fb location */
+ u64 mc_vram_size;
+ u64 visible_vram_size;
+ u64 gtt_size;
+ u64 gtt_start;
+ u64 gtt_end;
+ u64 vram_start;
+ u64 vram_end;
+ unsigned vram_width;
+ u64 real_vram_size;
+ int vram_mtrr;
+ u64 gtt_base_align;
+ u64 mc_mask;
+ const struct firmware *fw; /* MC firmware */
+ uint32_t fw_version;
+ struct amdgpu_irq_src vm_fault;
+ uint32_t vram_type;
+};
+
+/*
+ * GPU doorbell structures, functions & helpers
+ */
+typedef enum _AMDGPU_DOORBELL_ASSIGNMENT
+{
+ AMDGPU_DOORBELL_KIQ = 0x000,
+ AMDGPU_DOORBELL_HIQ = 0x001,
+ AMDGPU_DOORBELL_DIQ = 0x002,
+ AMDGPU_DOORBELL_MEC_RING0 = 0x010,
+ AMDGPU_DOORBELL_MEC_RING1 = 0x011,
+ AMDGPU_DOORBELL_MEC_RING2 = 0x012,
+ AMDGPU_DOORBELL_MEC_RING3 = 0x013,
+ AMDGPU_DOORBELL_MEC_RING4 = 0x014,
+ AMDGPU_DOORBELL_MEC_RING5 = 0x015,
+ AMDGPU_DOORBELL_MEC_RING6 = 0x016,
+ AMDGPU_DOORBELL_MEC_RING7 = 0x017,
+ AMDGPU_DOORBELL_GFX_RING0 = 0x020,
+ AMDGPU_DOORBELL_sDMA_ENGINE0 = 0x1E0,
+ AMDGPU_DOORBELL_sDMA_ENGINE1 = 0x1E1,
+ AMDGPU_DOORBELL_IH = 0x1E8,
+ AMDGPU_DOORBELL_MAX_ASSIGNMENT = 0x3FF,
+ AMDGPU_DOORBELL_INVALID = 0xFFFF
+} AMDGPU_DOORBELL_ASSIGNMENT;
+
+struct amdgpu_doorbell {
+ /* doorbell mmio */
+ resource_size_t base;
+ resource_size_t size;
+ u32 __iomem *ptr;
+ u32 num_doorbells; /* Number of doorbells actually reserved for amdgpu. */
+};
+
+void amdgpu_doorbell_get_kfd_info(struct amdgpu_device *adev,
+ phys_addr_t *aperture_base,
+ size_t *aperture_size,
+ size_t *start_offset);
+
+/*
+ * IRQS.
+ */
+
+struct amdgpu_flip_work {
+ struct work_struct flip_work;
+ struct work_struct unpin_work;
+ struct amdgpu_device *adev;
+ int crtc_id;
+ uint64_t base;
+ struct drm_pending_vblank_event *event;
+ struct amdgpu_bo *old_rbo;
+ struct fence *fence;
+};
+
+
+/*
+ * CP & rings.
+ */
+
+struct amdgpu_ib {
+ struct amdgpu_sa_bo *sa_bo;
+ uint32_t length_dw;
+ uint64_t gpu_addr;
+ uint32_t *ptr;
+ struct amdgpu_ring *ring;
+ struct amdgpu_fence *fence;
+ struct amdgpu_user_fence *user;
+ struct amdgpu_vm *vm;
+ struct amdgpu_ctx *ctx;
+ struct amdgpu_sync sync;
+ uint32_t gds_base, gds_size;
+ uint32_t gws_base, gws_size;
+ uint32_t oa_base, oa_size;
+ uint32_t flags;
+};
+
+enum amdgpu_ring_type {
+ AMDGPU_RING_TYPE_GFX,
+ AMDGPU_RING_TYPE_COMPUTE,
+ AMDGPU_RING_TYPE_SDMA,
+ AMDGPU_RING_TYPE_UVD,
+ AMDGPU_RING_TYPE_VCE
+};
+
+struct amdgpu_ring {
+ struct amdgpu_device *adev;
+ const struct amdgpu_ring_funcs *funcs;
+ struct amdgpu_fence_driver fence_drv;
+
+ struct mutex *ring_lock;
+ struct amdgpu_bo *ring_obj;
+ volatile uint32_t *ring;
+ unsigned rptr_offs;
+ u64 next_rptr_gpu_addr;
+ volatile u32 *next_rptr_cpu_addr;
+ unsigned wptr;
+ unsigned wptr_old;
+ unsigned ring_size;
+ unsigned ring_free_dw;
+ int count_dw;
+ atomic_t last_rptr;
+ atomic64_t last_activity;
+ uint64_t gpu_addr;
+ uint32_t align_mask;
+ uint32_t ptr_mask;
+ bool ready;
+ u32 nop;
+ u32 idx;
+ u64 last_semaphore_signal_addr;
+ u64 last_semaphore_wait_addr;
+ u32 me;
+ u32 pipe;
+ u32 queue;
+ struct amdgpu_bo *mqd_obj;
+ u32 doorbell_index;
+ bool use_doorbell;
+ unsigned wptr_offs;
+ unsigned next_rptr_offs;
+ unsigned fence_offs;
+ struct amdgpu_ctx *current_ctx;
+ enum amdgpu_ring_type type;
+ char name[16];
+};
+
+/*
+ * VM
+ */
+
+/* maximum number of VMIDs */
+#define AMDGPU_NUM_VM 16
+
+/* number of entries in page table */
+#define AMDGPU_VM_PTE_COUNT (1 << amdgpu_vm_block_size)
+
+/* PTBs (Page Table Blocks) need to be aligned to 32K */
+#define AMDGPU_VM_PTB_ALIGN_SIZE 32768
+#define AMDGPU_VM_PTB_ALIGN_MASK (AMDGPU_VM_PTB_ALIGN_SIZE - 1)
+#define AMDGPU_VM_PTB_ALIGN(a) (((a) + AMDGPU_VM_PTB_ALIGN_MASK) & ~AMDGPU_VM_PTB_ALIGN_MASK)
+
+#define AMDGPU_PTE_VALID (1 << 0)
+#define AMDGPU_PTE_SYSTEM (1 << 1)
+#define AMDGPU_PTE_SNOOPED (1 << 2)
+
+/* VI only */
+#define AMDGPU_PTE_EXECUTABLE (1 << 4)
+
+#define AMDGPU_PTE_READABLE (1 << 5)
+#define AMDGPU_PTE_WRITEABLE (1 << 6)
+
+/* PTE (Page Table Entry) fragment field for different page sizes */
+#define AMDGPU_PTE_FRAG_4KB (0 << 7)
+#define AMDGPU_PTE_FRAG_64KB (4 << 7)
+#define AMDGPU_LOG2_PAGES_PER_FRAG 4
+
+struct amdgpu_vm_pt {
+ struct amdgpu_bo *bo;
+ uint64_t addr;
+};
+
+struct amdgpu_vm_id {
+ unsigned id;
+ uint64_t pd_gpu_addr;
+ /* last flushed PD/PT update */
+ struct amdgpu_fence *flushed_updates;
+ /* last use of vmid */
+ struct amdgpu_fence *last_id_use;
+};
+
+struct amdgpu_vm {
+ struct mutex mutex;
+
+ struct rb_root va;
+
+ /* protecting invalidated and freed */
+ spinlock_t status_lock;
+
+ /* BOs moved, but not yet updated in the PT */
+ struct list_head invalidated;
+
+ /* BOs freed, but not yet updated in the PT */
+ struct list_head freed;
+
+ /* contains the page directory */
+ struct amdgpu_bo *page_directory;
+ unsigned max_pde_used;
+
+ /* array of page tables, one for each page directory entry */
+ struct amdgpu_vm_pt *page_tables;
+
+ /* for id and flush management per ring */
+ struct amdgpu_vm_id ids[AMDGPU_MAX_RINGS];
+};
+
+struct amdgpu_vm_manager {
+ struct amdgpu_fence *active[AMDGPU_NUM_VM];
+ uint32_t max_pfn;
+ /* number of VMIDs */
+ unsigned nvm;
+ /* vram base address for page table entry */
+ u64 vram_base_offset;
+ /* is vm enabled? */
+ bool enabled;
+ /* for hw to save the PD addr on suspend/resume */
+ uint32_t saved_table_addr[AMDGPU_NUM_VM];
+ /* vm pte handling */
+ const struct amdgpu_vm_pte_funcs *vm_pte_funcs;
+ struct amdgpu_ring *vm_pte_funcs_ring;
+};
+
+/*
+ * context related structures
+ */
+
+struct amdgpu_ctx_state {
+ uint64_t flags;
+ uint32_t hangs;
+};
+
+struct amdgpu_ctx {
+ /* call kref_get()before CS start and kref_put() after CS fence signaled */
+ struct kref refcount;
+ struct amdgpu_fpriv *fpriv;
+ struct amdgpu_ctx_state state;
+ uint32_t id;
+ unsigned reset_counter;
+};
+
+struct amdgpu_ctx_mgr {
+ struct amdgpu_device *adev;
+ struct idr ctx_handles;
+ /* lock for IDR system */
+ struct mutex lock;
+};
+
+/*
+ * file private structure
+ */
+
+struct amdgpu_fpriv {
+ struct amdgpu_vm vm;
+ struct mutex bo_list_lock;
+ struct idr bo_list_handles;
+ struct amdgpu_ctx_mgr ctx_mgr;
+};
+
+/*
+ * residency list
+ */
+
+struct amdgpu_bo_list {
+ struct mutex lock;
+ struct amdgpu_bo *gds_obj;
+ struct amdgpu_bo *gws_obj;
+ struct amdgpu_bo *oa_obj;
+ bool has_userptr;
+ unsigned num_entries;
+ struct amdgpu_bo_list_entry *array;
+};
+
+struct amdgpu_bo_list *
+amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id);
+void amdgpu_bo_list_put(struct amdgpu_bo_list *list);
+void amdgpu_bo_list_free(struct amdgpu_bo_list *list);
+
+/*
+ * GFX stuff
+ */
+#include "clearstate_defs.h"
+
+struct amdgpu_rlc {
+ /* for power gating */
+ struct amdgpu_bo *save_restore_obj;
+ uint64_t save_restore_gpu_addr;
+ volatile uint32_t *sr_ptr;
+ const u32 *reg_list;
+ u32 reg_list_size;
+ /* for clear state */
+ struct amdgpu_bo *clear_state_obj;
+ uint64_t clear_state_gpu_addr;
+ volatile uint32_t *cs_ptr;
+ const struct cs_section_def *cs_data;
+ u32 clear_state_size;
+ /* for cp tables */
+ struct amdgpu_bo *cp_table_obj;
+ uint64_t cp_table_gpu_addr;
+ volatile uint32_t *cp_table_ptr;
+ u32 cp_table_size;
+};
+
+struct amdgpu_mec {
+ struct amdgpu_bo *hpd_eop_obj;
+ u64 hpd_eop_gpu_addr;
+ u32 num_pipe;
+ u32 num_mec;
+ u32 num_queue;
+};
+
+/*
+ * GPU scratch registers structures, functions & helpers
+ */
+struct amdgpu_scratch {
+ unsigned num_reg;
+ uint32_t reg_base;
+ bool free[32];
+ uint32_t reg[32];
+};
+
+/*
+ * GFX configurations
+ */
+struct amdgpu_gca_config {
+ unsigned max_shader_engines;
+ unsigned max_tile_pipes;
+ unsigned max_cu_per_sh;
+ unsigned max_sh_per_se;
+ unsigned max_backends_per_se;
+ unsigned max_texture_channel_caches;
+ unsigned max_gprs;
+ unsigned max_gs_threads;
+ unsigned max_hw_contexts;
+ unsigned sc_prim_fifo_size_frontend;
+ unsigned sc_prim_fifo_size_backend;
+ unsigned sc_hiz_tile_fifo_size;
+ unsigned sc_earlyz_tile_fifo_size;
+
+ unsigned num_tile_pipes;
+ unsigned backend_enable_mask;
+ unsigned mem_max_burst_length_bytes;
+ unsigned mem_row_size_in_kb;
+ unsigned shader_engine_tile_size;
+ unsigned num_gpus;
+ unsigned multi_gpu_tile_size;
+ unsigned mc_arb_ramcfg;
+ unsigned gb_addr_config;
+
+ uint32_t tile_mode_array[32];
+ uint32_t macrotile_mode_array[16];
+};
+
+struct amdgpu_gfx {
+ struct mutex gpu_clock_mutex;
+ struct amdgpu_gca_config config;
+ struct amdgpu_rlc rlc;
+ struct amdgpu_mec mec;
+ struct amdgpu_scratch scratch;
+ const struct firmware *me_fw; /* ME firmware */
+ uint32_t me_fw_version;
+ const struct firmware *pfp_fw; /* PFP firmware */
+ uint32_t pfp_fw_version;
+ const struct firmware *ce_fw; /* CE firmware */
+ uint32_t ce_fw_version;
+ const struct firmware *rlc_fw; /* RLC firmware */
+ uint32_t rlc_fw_version;
+ const struct firmware *mec_fw; /* MEC firmware */
+ uint32_t mec_fw_version;
+ const struct firmware *mec2_fw; /* MEC2 firmware */
+ uint32_t mec2_fw_version;
+ uint32_t me_feature_version;
+ uint32_t ce_feature_version;
+ uint32_t pfp_feature_version;
+ struct amdgpu_ring gfx_ring[AMDGPU_MAX_GFX_RINGS];
+ unsigned num_gfx_rings;
+ struct amdgpu_ring compute_ring[AMDGPU_MAX_COMPUTE_RINGS];
+ unsigned num_compute_rings;
+ struct amdgpu_irq_src eop_irq;
+ struct amdgpu_irq_src priv_reg_irq;
+ struct amdgpu_irq_src priv_inst_irq;
+ /* gfx status */
+ uint32_t gfx_current_status;
+ /* sync signal for const engine */
+ unsigned ce_sync_offs;
+ /* ce ram size*/
+ unsigned ce_ram_size;
+};
+
+int amdgpu_ib_get(struct amdgpu_ring *ring, struct amdgpu_vm *vm,
+ unsigned size, struct amdgpu_ib *ib);
+void amdgpu_ib_free(struct amdgpu_device *adev, struct amdgpu_ib *ib);
+int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs,
+ struct amdgpu_ib *ib, void *owner);
+int amdgpu_ib_pool_init(struct amdgpu_device *adev);
+void amdgpu_ib_pool_fini(struct amdgpu_device *adev);
+int amdgpu_ib_ring_tests(struct amdgpu_device *adev);
+/* Ring access between begin & end cannot sleep */
+void amdgpu_ring_free_size(struct amdgpu_ring *ring);
+int amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned ndw);
+int amdgpu_ring_lock(struct amdgpu_ring *ring, unsigned ndw);
+void amdgpu_ring_commit(struct amdgpu_ring *ring);
+void amdgpu_ring_unlock_commit(struct amdgpu_ring *ring);
+void amdgpu_ring_undo(struct amdgpu_ring *ring);
+void amdgpu_ring_unlock_undo(struct amdgpu_ring *ring);
+void amdgpu_ring_lockup_update(struct amdgpu_ring *ring);
+bool amdgpu_ring_test_lockup(struct amdgpu_ring *ring);
+unsigned amdgpu_ring_backup(struct amdgpu_ring *ring,
+ uint32_t **data);
+int amdgpu_ring_restore(struct amdgpu_ring *ring,
+ unsigned size, uint32_t *data);
+int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
+ unsigned ring_size, u32 nop, u32 align_mask,
+ struct amdgpu_irq_src *irq_src, unsigned irq_type,
+ enum amdgpu_ring_type ring_type);
+void amdgpu_ring_fini(struct amdgpu_ring *ring);
+
+/*
+ * CS.
+ */
+struct amdgpu_cs_chunk {
+ uint32_t chunk_id;
+ uint32_t length_dw;
+ uint32_t *kdata;
+ void __user *user_ptr;
+};
+
+struct amdgpu_cs_parser {
+ struct amdgpu_device *adev;
+ struct drm_file *filp;
+ struct amdgpu_ctx *ctx;
+ struct amdgpu_bo_list *bo_list;
+ /* chunks */
+ unsigned nchunks;
+ struct amdgpu_cs_chunk *chunks;
+ /* relocations */
+ struct amdgpu_bo_list_entry *vm_bos;
+ struct list_head validated;
+
+ struct amdgpu_ib *ibs;
+ uint32_t num_ibs;
+
+ struct ww_acquire_ctx ticket;
+
+ /* user fence */
+ struct amdgpu_user_fence uf;
+};
+
+static inline u32 amdgpu_get_ib_value(struct amdgpu_cs_parser *p, uint32_t ib_idx, int idx)
+{
+ return p->ibs[ib_idx].ptr[idx];
+}
+
+/*
+ * Writeback
+ */
+#define AMDGPU_MAX_WB 1024 /* Reserve at most 1024 WB slots for amdgpu-owned rings. */
+
+struct amdgpu_wb {
+ struct amdgpu_bo *wb_obj;
+ volatile uint32_t *wb;
+ uint64_t gpu_addr;
+ u32 num_wb; /* Number of wb slots actually reserved for amdgpu. */
+ unsigned long used[DIV_ROUND_UP(AMDGPU_MAX_WB, BITS_PER_LONG)];
+};
+
+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,
+ THERMAL_TYPE_EXTERNAL,
+ THERMAL_TYPE_EXTERNAL_GPIO,
+ THERMAL_TYPE_RV6XX,
+ THERMAL_TYPE_RV770,
+ THERMAL_TYPE_ADT7473_WITH_INTERNAL,
+ THERMAL_TYPE_EVERGREEN,
+ THERMAL_TYPE_SUMO,
+ THERMAL_TYPE_NI,
+ THERMAL_TYPE_SI,
+ THERMAL_TYPE_EMC2103_WITH_INTERNAL,
+ THERMAL_TYPE_CI,
+ THERMAL_TYPE_KV,
+};
+
+enum amdgpu_dpm_auto_throttle_src {
+ AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL,
+ AMDGPU_DPM_AUTO_THROTTLE_SRC_EXTERNAL
+};
+
+enum amdgpu_dpm_event_src {
+ AMDGPU_DPM_EVENT_SRC_ANALOG = 0,
+ AMDGPU_DPM_EVENT_SRC_EXTERNAL = 1,
+ AMDGPU_DPM_EVENT_SRC_DIGITAL = 2,
+ AMDGPU_DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,
+ AMDGPU_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL = 4
+};
+
+#define AMDGPU_MAX_VCE_LEVELS 6
+
+enum amdgpu_vce_level {
+ AMDGPU_VCE_LEVEL_AC_ALL = 0, /* AC, All cases */
+ AMDGPU_VCE_LEVEL_DC_EE = 1, /* DC, entropy encoding */
+ AMDGPU_VCE_LEVEL_DC_LL_LOW = 2, /* DC, low latency queue, res <= 720 */
+ AMDGPU_VCE_LEVEL_DC_LL_HIGH = 3, /* DC, low latency queue, 1080 >= res > 720 */
+ AMDGPU_VCE_LEVEL_DC_GP_LOW = 4, /* DC, general purpose queue, res <= 720 */
+ AMDGPU_VCE_LEVEL_DC_GP_HIGH = 5, /* DC, general purpose queue, 1080 >= res > 720 */
+};
+
+struct amdgpu_ps {
+ u32 caps; /* vbios flags */
+ u32 class; /* vbios flags */
+ u32 class2; /* vbios flags */
+ /* UVD clocks */
+ u32 vclk;
+ u32 dclk;
+ /* VCE clocks */
+ u32 evclk;
+ u32 ecclk;
+ bool vce_active;
+ enum amdgpu_vce_level vce_level;
+ /* asic priv */
+ void *ps_priv;
+};
+
+struct amdgpu_dpm_thermal {
+ /* thermal interrupt work */
+ struct work_struct work;
+ /* low temperature threshold */
+ int min_temp;
+ /* high temperature threshold */
+ int max_temp;
+ /* was last interrupt low to high or high to low */
+ bool high_to_low;
+ /* interrupt source */
+ struct amdgpu_irq_src irq;
+};
+
+enum amdgpu_clk_action
+{
+ AMDGPU_SCLK_UP = 1,
+ AMDGPU_SCLK_DOWN
+};
+
+struct amdgpu_blacklist_clocks
+{
+ u32 sclk;
+ u32 mclk;
+ enum amdgpu_clk_action action;
+};
+
+struct amdgpu_clock_and_voltage_limits {
+ u32 sclk;
+ u32 mclk;
+ u16 vddc;
+ u16 vddci;
+};
+
+struct amdgpu_clock_array {
+ u32 count;
+ u32 *values;
+};
+
+struct amdgpu_clock_voltage_dependency_entry {
+ u32 clk;
+ u16 v;
+};
+
+struct amdgpu_clock_voltage_dependency_table {
+ u32 count;
+ struct amdgpu_clock_voltage_dependency_entry *entries;
+};
+
+union amdgpu_cac_leakage_entry {
+ struct {
+ u16 vddc;
+ u32 leakage;
+ };
+ struct {
+ u16 vddc1;
+ u16 vddc2;
+ u16 vddc3;
+ };
+};
+
+struct amdgpu_cac_leakage_table {
+ u32 count;
+ union amdgpu_cac_leakage_entry *entries;
+};
+
+struct amdgpu_phase_shedding_limits_entry {
+ u16 voltage;
+ u32 sclk;
+ u32 mclk;
+};
+
+struct amdgpu_phase_shedding_limits_table {
+ u32 count;
+ struct amdgpu_phase_shedding_limits_entry *entries;
+};
+
+struct amdgpu_uvd_clock_voltage_dependency_entry {
+ u32 vclk;
+ u32 dclk;
+ u16 v;
+};
+
+struct amdgpu_uvd_clock_voltage_dependency_table {
+ u8 count;
+ struct amdgpu_uvd_clock_voltage_dependency_entry *entries;
+};
+
+struct amdgpu_vce_clock_voltage_dependency_entry {
+ u32 ecclk;
+ u32 evclk;
+ u16 v;
+};
+
+struct amdgpu_vce_clock_voltage_dependency_table {
+ u8 count;
+ struct amdgpu_vce_clock_voltage_dependency_entry *entries;
+};
+
+struct amdgpu_ppm_table {
+ u8 ppm_design;
+ u16 cpu_core_number;
+ u32 platform_tdp;
+ u32 small_ac_platform_tdp;
+ u32 platform_tdc;
+ u32 small_ac_platform_tdc;
+ u32 apu_tdp;
+ u32 dgpu_tdp;
+ u32 dgpu_ulv_power;
+ u32 tj_max;
+};
+
+struct amdgpu_cac_tdp_table {
+ u16 tdp;
+ u16 configurable_tdp;
+ u16 tdc;
+ u16 battery_power_limit;
+ u16 small_power_limit;
+ u16 low_cac_leakage;
+ u16 high_cac_leakage;
+ u16 maximum_power_delivery_limit;
+};
+
+struct amdgpu_dpm_dynamic_state {
+ struct amdgpu_clock_voltage_dependency_table vddc_dependency_on_sclk;
+ struct amdgpu_clock_voltage_dependency_table vddci_dependency_on_mclk;
+ struct amdgpu_clock_voltage_dependency_table vddc_dependency_on_mclk;
+ struct amdgpu_clock_voltage_dependency_table mvdd_dependency_on_mclk;
+ struct amdgpu_clock_voltage_dependency_table vddc_dependency_on_dispclk;
+ struct amdgpu_uvd_clock_voltage_dependency_table uvd_clock_voltage_dependency_table;
+ struct amdgpu_vce_clock_voltage_dependency_table vce_clock_voltage_dependency_table;
+ struct amdgpu_clock_voltage_dependency_table samu_clock_voltage_dependency_table;
+ struct amdgpu_clock_voltage_dependency_table acp_clock_voltage_dependency_table;
+ struct amdgpu_clock_voltage_dependency_table vddgfx_dependency_on_sclk;
+ struct amdgpu_clock_array valid_sclk_values;
+ struct amdgpu_clock_array valid_mclk_values;
+ struct amdgpu_clock_and_voltage_limits max_clock_voltage_on_dc;
+ struct amdgpu_clock_and_voltage_limits max_clock_voltage_on_ac;
+ u32 mclk_sclk_ratio;
+ u32 sclk_mclk_delta;
+ u16 vddc_vddci_delta;
+ u16 min_vddc_for_pcie_gen2;
+ struct amdgpu_cac_leakage_table cac_leakage_table;
+ struct amdgpu_phase_shedding_limits_table phase_shedding_limits_table;
+ struct amdgpu_ppm_table *ppm_table;
+ struct amdgpu_cac_tdp_table *cac_tdp_table;
+};
+
+struct amdgpu_dpm_fan {
+ u16 t_min;
+ u16 t_med;
+ u16 t_high;
+ u16 pwm_min;
+ u16 pwm_med;
+ u16 pwm_high;
+ u8 t_hyst;
+ u32 cycle_delay;
+ u16 t_max;
+ u8 control_mode;
+ u16 default_max_fan_pwm;
+ u16 default_fan_output_sensitivity;
+ u16 fan_output_sensitivity;
+ bool ucode_fan_control;
+};
+
+enum amdgpu_pcie_gen {
+ AMDGPU_PCIE_GEN1 = 0,
+ AMDGPU_PCIE_GEN2 = 1,
+ AMDGPU_PCIE_GEN3 = 2,
+ AMDGPU_PCIE_GEN_INVALID = 0xffff
+};
+
+enum amdgpu_dpm_forced_level {
+ AMDGPU_DPM_FORCED_LEVEL_AUTO = 0,
+ AMDGPU_DPM_FORCED_LEVEL_LOW = 1,
+ AMDGPU_DPM_FORCED_LEVEL_HIGH = 2,
+};
+
+struct amdgpu_vce_state {
+ /* vce clocks */
+ u32 evclk;
+ u32 ecclk;
+ /* gpu clocks */
+ u32 sclk;
+ u32 mclk;
+ u8 clk_idx;
+ u8 pstate;
+};
+
+struct amdgpu_dpm_funcs {
+ int (*get_temperature)(struct amdgpu_device *adev);
+ int (*pre_set_power_state)(struct amdgpu_device *adev);
+ int (*set_power_state)(struct amdgpu_device *adev);
+ void (*post_set_power_state)(struct amdgpu_device *adev);
+ void (*display_configuration_changed)(struct amdgpu_device *adev);
+ u32 (*get_sclk)(struct amdgpu_device *adev, bool low);
+ u32 (*get_mclk)(struct amdgpu_device *adev, bool low);
+ void (*print_power_state)(struct amdgpu_device *adev, struct amdgpu_ps *ps);
+ void (*debugfs_print_current_performance_level)(struct amdgpu_device *adev, struct seq_file *m);
+ int (*force_performance_level)(struct amdgpu_device *adev, enum amdgpu_dpm_forced_level level);
+ bool (*vblank_too_short)(struct amdgpu_device *adev);
+ void (*powergate_uvd)(struct amdgpu_device *adev, bool gate);
+ void (*powergate_vce)(struct amdgpu_device *adev, bool gate);
+ void (*enable_bapm)(struct amdgpu_device *adev, bool enable);
+ void (*set_fan_control_mode)(struct amdgpu_device *adev, u32 mode);
+ u32 (*get_fan_control_mode)(struct amdgpu_device *adev);
+ int (*set_fan_speed_percent)(struct amdgpu_device *adev, u32 speed);
+ int (*get_fan_speed_percent)(struct amdgpu_device *adev, u32 *speed);
+};
+
+struct amdgpu_dpm {
+ struct amdgpu_ps *ps;
+ /* number of valid power states */
+ int num_ps;
+ /* current power state that is active */
+ struct amdgpu_ps *current_ps;
+ /* requested power state */
+ struct amdgpu_ps *requested_ps;
+ /* boot up power state */
+ struct amdgpu_ps *boot_ps;
+ /* default uvd power state */
+ struct amdgpu_ps *uvd_ps;
+ /* 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;
+ u32 platform_caps;
+ u32 voltage_response_time;
+ u32 backbias_response_time;
+ void *priv;
+ u32 new_active_crtcs;
+ int new_active_crtc_count;
+ u32 current_active_crtcs;
+ int current_active_crtc_count;
+ struct amdgpu_dpm_dynamic_state dyn_state;
+ struct amdgpu_dpm_fan fan;
+ u32 tdp_limit;
+ u32 near_tdp_limit;
+ u32 near_tdp_limit_adjusted;
+ u32 sq_ramping_threshold;
+ u32 cac_leakage;
+ u16 tdp_od_limit;
+ u32 tdp_adjustment;
+ u16 load_line_slope;
+ bool power_control;
+ bool ac_power;
+ /* special states active */
+ bool thermal_active;
+ bool uvd_active;
+ bool vce_active;
+ /* thermal handling */
+ struct amdgpu_dpm_thermal thermal;
+ /* forced levels */
+ enum amdgpu_dpm_forced_level forced_level;
+};
+
+struct amdgpu_pm {
+ struct mutex mutex;
+ u32 current_sclk;
+ u32 current_mclk;
+ u32 default_sclk;
+ u32 default_mclk;
+ struct amdgpu_i2c_chan *i2c_bus;
+ /* internal thermal controller on rv6xx+ */
+ enum amdgpu_int_thermal_type int_thermal_type;
+ struct device *int_hwmon_dev;
+ /* fan control parameters */
+ bool no_fan;
+ u8 fan_pulses_per_revolution;
+ u8 fan_min_rpm;
+ u8 fan_max_rpm;
+ /* dpm */
+ bool dpm_enabled;
+ struct amdgpu_dpm dpm;
+ const struct firmware *fw; /* SMC firmware */
+ uint32_t fw_version;
+ const struct amdgpu_dpm_funcs *funcs;
+};
+
+/*
+ * UVD
+ */
+#define AMDGPU_MAX_UVD_HANDLES 10
+#define AMDGPU_UVD_STACK_SIZE (1024*1024)
+#define AMDGPU_UVD_HEAP_SIZE (1024*1024)
+#define AMDGPU_UVD_FIRMWARE_OFFSET 256
+
+struct amdgpu_uvd {
+ struct amdgpu_bo *vcpu_bo;
+ void *cpu_addr;
+ uint64_t gpu_addr;
+ void *saved_bo;
+ atomic_t handles[AMDGPU_MAX_UVD_HANDLES];
+ struct drm_file *filp[AMDGPU_MAX_UVD_HANDLES];
+ struct delayed_work idle_work;
+ const struct firmware *fw; /* UVD firmware */
+ struct amdgpu_ring ring;
+ struct amdgpu_irq_src irq;
+ bool address_64_bit;
+};
+
+/*
+ * VCE
+ */
+#define AMDGPU_MAX_VCE_HANDLES 16
+#define AMDGPU_VCE_FIRMWARE_OFFSET 256
+
+struct amdgpu_vce {
+ struct amdgpu_bo *vcpu_bo;
+ uint64_t gpu_addr;
+ unsigned fw_version;
+ unsigned fb_version;
+ atomic_t handles[AMDGPU_MAX_VCE_HANDLES];
+ struct drm_file *filp[AMDGPU_MAX_VCE_HANDLES];
+ struct delayed_work idle_work;
+ const struct firmware *fw; /* VCE firmware */
+ struct amdgpu_ring ring[AMDGPU_MAX_VCE_RINGS];
+ struct amdgpu_irq_src irq;
+};
+
+/*
+ * SDMA
+ */
+struct amdgpu_sdma {
+ /* SDMA firmware */
+ const struct firmware *fw;
+ uint32_t fw_version;
+
+ struct amdgpu_ring ring;
+};
+
+/*
+ * Firmware
+ */
+struct amdgpu_firmware {
+ struct amdgpu_firmware_info ucode[AMDGPU_UCODE_ID_MAXIMUM];
+ bool smu_load;
+ struct amdgpu_bo *fw_buf;
+ unsigned int fw_size;
+};
+
+/*
+ * Benchmarking
+ */
+void amdgpu_benchmark(struct amdgpu_device *adev, int test_number);
+
+
+/*
+ * Testing
+ */
+void amdgpu_test_moves(struct amdgpu_device *adev);
+void amdgpu_test_ring_sync(struct amdgpu_device *adev,
+ struct amdgpu_ring *cpA,
+ struct amdgpu_ring *cpB);
+void amdgpu_test_syncing(struct amdgpu_device *adev);
+
+/*
+ * MMU Notifier
+ */
+#if defined(CONFIG_MMU_NOTIFIER)
+int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr);
+void amdgpu_mn_unregister(struct amdgpu_bo *bo);
+#else
+static int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
+{
+ return -ENODEV;
+}
+static void amdgpu_mn_unregister(struct amdgpu_bo *bo) {}
+#endif
+
+/*
+ * Debugfs
+ */
+struct amdgpu_debugfs {
+ struct drm_info_list *files;
+ unsigned num_files;
+};
+
+int amdgpu_debugfs_add_files(struct amdgpu_device *adev,
+ struct drm_info_list *files,
+ unsigned nfiles);
+int amdgpu_debugfs_fence_init(struct amdgpu_device *adev);
+
+#if defined(CONFIG_DEBUG_FS)
+int amdgpu_debugfs_init(struct drm_minor *minor);
+void amdgpu_debugfs_cleanup(struct drm_minor *minor);
+#endif
+
+/*
+ * amdgpu smumgr functions
+ */
+struct amdgpu_smumgr_funcs {
+ int (*check_fw_load_finish)(struct amdgpu_device *adev, uint32_t fwtype);
+ int (*request_smu_load_fw)(struct amdgpu_device *adev);
+ int (*request_smu_specific_fw)(struct amdgpu_device *adev, uint32_t fwtype);
+};
+
+/*
+ * amdgpu smumgr
+ */
+struct amdgpu_smumgr {
+ struct amdgpu_bo *toc_buf;
+ struct amdgpu_bo *smu_buf;
+ /* asic priv smu data */
+ void *priv;
+ spinlock_t smu_lock;
+ /* smumgr functions */
+ const struct amdgpu_smumgr_funcs *smumgr_funcs;
+ /* ucode loading complete flag */
+ uint32_t fw_flags;
+};
+
+/*
+ * ASIC specific register table accessible by UMD
+ */
+struct amdgpu_allowed_register_entry {
+ uint32_t reg_offset;
+ bool untouched;
+ bool grbm_indexed;
+};
+
+struct amdgpu_cu_info {
+ uint32_t number; /* total active CU number */
+ uint32_t ao_cu_mask;
+ uint32_t bitmap[4][4];
+};
+
+
+/*
+ * ASIC specific functions.
+ */
+struct amdgpu_asic_funcs {
+ bool (*read_disabled_bios)(struct amdgpu_device *adev);
+ 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);
+ int (*reset)(struct amdgpu_device *adev);
+ /* wait for mc_idle */
+ int (*wait_for_mc_idle)(struct amdgpu_device *adev);
+ /* get the reference clock */
+ u32 (*get_xclk)(struct amdgpu_device *adev);
+ /* get the gpu clock counter */
+ uint64_t (*get_gpu_clock_counter)(struct amdgpu_device *adev);
+ int (*get_cu_info)(struct amdgpu_device *adev, struct amdgpu_cu_info *info);
+ /* MM block clocks */
+ int (*set_uvd_clocks)(struct amdgpu_device *adev, u32 vclk, u32 dclk);
+ int (*set_vce_clocks)(struct amdgpu_device *adev, u32 evclk, u32 ecclk);
+};
+
+/*
+ * IOCTL.
+ */
+int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+
+int amdgpu_gem_info_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+int amdgpu_gem_mmap_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+int amdgpu_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
+int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
+
+int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+
+/* VRAM scratch page for HDP bug, default vram page */
+struct amdgpu_vram_scratch {
+ struct amdgpu_bo *robj;
+ volatile uint32_t *ptr;
+ u64 gpu_addr;
+};
+
+/*
+ * ACPI
+ */
+struct amdgpu_atif_notification_cfg {
+ bool enabled;
+ int command_code;
+};
+
+struct amdgpu_atif_notifications {
+ bool display_switch;
+ bool expansion_mode_change;
+ bool thermal_state;
+ bool forced_power_state;
+ bool system_power_state;
+ bool display_conf_change;
+ bool px_gfx_switch;
+ bool brightness_change;
+ bool dgpu_display_event;
+};
+
+struct amdgpu_atif_functions {
+ bool system_params;
+ bool sbios_requests;
+ bool select_active_disp;
+ bool lid_state;
+ bool get_tv_standard;
+ bool set_tv_standard;
+ bool get_panel_expansion_mode;
+ bool set_panel_expansion_mode;
+ bool temperature_change;
+ bool graphics_device_types;
+};
+
+struct amdgpu_atif {
+ struct amdgpu_atif_notifications notifications;
+ struct amdgpu_atif_functions functions;
+ struct amdgpu_atif_notification_cfg notification_cfg;
+ struct amdgpu_encoder *encoder_for_bl;
+};
+
+struct amdgpu_atcs_functions {
+ bool get_ext_state;
+ bool pcie_perf_req;
+ bool pcie_dev_rdy;
+ bool pcie_bus_width;
+};
+
+struct amdgpu_atcs {
+ struct amdgpu_atcs_functions functions;
+};
+
+int amdgpu_ctx_alloc(struct amdgpu_device *adev,struct amdgpu_fpriv *fpriv,
+ uint32_t *id,uint32_t flags);
+int amdgpu_ctx_free(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv,
+ uint32_t id);
+
+void amdgpu_ctx_fini(struct amdgpu_fpriv *fpriv);
+struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id);
+int amdgpu_ctx_put(struct amdgpu_ctx *ctx);
+
+extern int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp);
+
+/*
+ * Core structure, functions and helpers.
+ */
+typedef uint32_t (*amdgpu_rreg_t)(struct amdgpu_device*, uint32_t);
+typedef void (*amdgpu_wreg_t)(struct amdgpu_device*, uint32_t, uint32_t);
+
+typedef uint32_t (*amdgpu_block_rreg_t)(struct amdgpu_device*, uint32_t, uint32_t);
+typedef void (*amdgpu_block_wreg_t)(struct amdgpu_device*, uint32_t, uint32_t, uint32_t);
+
+struct amdgpu_device {
+ struct device *dev;
+ struct drm_device *ddev;
+ struct pci_dev *pdev;
+ struct rw_semaphore exclusive_lock;
+
+ /* ASIC */
+ enum amdgpu_asic_type asic_type;
+ uint32_t family;
+ uint32_t rev_id;
+ uint32_t external_rev_id;
+ unsigned long flags;
+ int usec_timeout;
+ const struct amdgpu_asic_funcs *asic_funcs;
+ bool shutdown;
+ bool suspend;
+ bool need_dma32;
+ bool accel_working;
+ bool needs_reset;
+ struct work_struct reset_work;
+ struct notifier_block acpi_nb;
+ struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS];
+ struct amdgpu_debugfs debugfs[AMDGPU_DEBUGFS_MAX_COMPONENTS];
+ unsigned debugfs_count;
+#if defined(CONFIG_DEBUG_FS)
+ struct dentry *debugfs_regs;
+#endif
+ struct amdgpu_atif atif;
+ struct amdgpu_atcs atcs;
+ struct mutex srbm_mutex;
+ /* GRBM index mutex. Protects concurrent access to GRBM index */
+ struct mutex grbm_idx_mutex;
+ struct dev_pm_domain vga_pm_domain;
+ bool have_disp_power_ref;
+
+ /* BIOS */
+ uint8_t *bios;
+ bool is_atom_bios;
+ uint16_t bios_header_start;
+ struct amdgpu_bo *stollen_vga_memory;
+ uint32_t bios_scratch[AMDGPU_BIOS_NUM_SCRATCH];
+
+ /* Register/doorbell mmio */
+ resource_size_t rmmio_base;
+ resource_size_t rmmio_size;
+ void __iomem *rmmio;
+ /* protects concurrent MM_INDEX/DATA based register access */
+ spinlock_t mmio_idx_lock;
+ /* protects concurrent SMC based register access */
+ spinlock_t smc_idx_lock;
+ amdgpu_rreg_t smc_rreg;
+ amdgpu_wreg_t smc_wreg;
+ /* protects concurrent PCIE register access */
+ spinlock_t pcie_idx_lock;
+ amdgpu_rreg_t pcie_rreg;
+ amdgpu_wreg_t pcie_wreg;
+ /* protects concurrent UVD register access */
+ spinlock_t uvd_ctx_idx_lock;
+ amdgpu_rreg_t uvd_ctx_rreg;
+ amdgpu_wreg_t uvd_ctx_wreg;
+ /* protects concurrent DIDT register access */
+ spinlock_t didt_idx_lock;
+ amdgpu_rreg_t didt_rreg;
+ amdgpu_wreg_t didt_wreg;
+ /* protects concurrent ENDPOINT (audio) register access */
+ spinlock_t audio_endpt_idx_lock;
+ amdgpu_block_rreg_t audio_endpt_rreg;
+ amdgpu_block_wreg_t audio_endpt_wreg;
+ void __iomem *rio_mem;
+ resource_size_t rio_mem_size;
+ struct amdgpu_doorbell doorbell;
+
+ /* clock/pll info */
+ struct amdgpu_clock clock;
+
+ /* MC */
+ struct amdgpu_mc mc;
+ struct amdgpu_gart gart;
+ struct amdgpu_dummy_page dummy_page;
+ struct amdgpu_vm_manager vm_manager;
+
+ /* memory management */
+ struct amdgpu_mman mman;
+ struct amdgpu_gem gem;
+ struct amdgpu_vram_scratch vram_scratch;
+ struct amdgpu_wb wb;
+ atomic64_t vram_usage;
+ atomic64_t vram_vis_usage;
+ atomic64_t gtt_usage;
+ atomic64_t num_bytes_moved;
+ atomic_t gpu_reset_counter;
+
+ /* display */
+ struct amdgpu_mode_info mode_info;
+ struct work_struct hotplug_work;
+ struct amdgpu_irq_src crtc_irq;
+ struct amdgpu_irq_src pageflip_irq;
+ struct amdgpu_irq_src hpd_irq;
+
+ /* rings */
+ wait_queue_head_t fence_queue;
+ unsigned fence_context;
+ struct mutex ring_lock;
+ unsigned num_rings;
+ struct amdgpu_ring *rings[AMDGPU_MAX_RINGS];
+ bool ib_pool_ready;
+ struct amdgpu_sa_manager ring_tmp_bo;
+
+ /* interrupts */
+ struct amdgpu_irq irq;
+
+ /* dpm */
+ struct amdgpu_pm pm;
+ u32 cg_flags;
+ u32 pg_flags;
+
+ /* amdgpu smumgr */
+ struct amdgpu_smumgr smu;
+
+ /* gfx */
+ struct amdgpu_gfx gfx;
+
+ /* sdma */
+ struct amdgpu_sdma sdma[2];
+ struct amdgpu_irq_src sdma_trap_irq;
+ struct amdgpu_irq_src sdma_illegal_inst_irq;
+
+ /* uvd */
+ bool has_uvd;
+ struct amdgpu_uvd uvd;
+
+ /* vce */
+ struct amdgpu_vce vce;
+
+ /* firmwares */
+ struct amdgpu_firmware firmware;
+
+ /* GDS */
+ struct amdgpu_gds gds;
+
+ const struct amdgpu_ip_block_version *ip_blocks;
+ int num_ip_blocks;
+ bool *ip_block_enabled;
+ struct mutex mn_lock;
+ DECLARE_HASHTABLE(mn_hash, 7);
+
+ /* tracking pinned memory */
+ u64 vram_pin_size;
+ u64 gart_pin_size;
+};
+
+bool amdgpu_device_is_px(struct drm_device *dev);
+int amdgpu_device_init(struct amdgpu_device *adev,
+ struct drm_device *ddev,
+ struct pci_dev *pdev,
+ uint32_t flags);
+void amdgpu_device_fini(struct amdgpu_device *adev);
+int amdgpu_gpu_wait_for_idle(struct amdgpu_device *adev);
+
+uint32_t amdgpu_mm_rreg(struct amdgpu_device *adev, uint32_t reg,
+ bool always_indirect);
+void amdgpu_mm_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v,
+ bool always_indirect);
+u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg);
+void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v);
+
+u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 index);
+void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v);
+
+/*
+ * Cast helper
+ */
+extern const struct fence_ops amdgpu_fence_ops;
+static inline struct amdgpu_fence *to_amdgpu_fence(struct fence *f)
+{
+ struct amdgpu_fence *__f = container_of(f, struct amdgpu_fence, base);
+
+ if (__f->base.ops == &amdgpu_fence_ops)
+ return __f;
+
+ return NULL;
+}
+
+/*
+ * Registers read & write functions.
+ */
+#define RREG32(reg) amdgpu_mm_rreg(adev, (reg), false)
+#define RREG32_IDX(reg) amdgpu_mm_rreg(adev, (reg), true)
+#define DREG32(reg) printk(KERN_INFO "REGISTER: " #reg " : 0x%08X\n", amdgpu_mm_rreg(adev, (reg), false))
+#define WREG32(reg, v) amdgpu_mm_wreg(adev, (reg), (v), false)
+#define WREG32_IDX(reg, v) amdgpu_mm_wreg(adev, (reg), (v), true)
+#define REG_SET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK)
+#define REG_GET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK)
+#define RREG32_PCIE(reg) adev->pcie_rreg(adev, (reg))
+#define WREG32_PCIE(reg, v) adev->pcie_wreg(adev, (reg), (v))
+#define RREG32_SMC(reg) adev->smc_rreg(adev, (reg))
+#define WREG32_SMC(reg, v) adev->smc_wreg(adev, (reg), (v))
+#define RREG32_UVD_CTX(reg) adev->uvd_ctx_rreg(adev, (reg))
+#define WREG32_UVD_CTX(reg, v) adev->uvd_ctx_wreg(adev, (reg), (v))
+#define RREG32_DIDT(reg) adev->didt_rreg(adev, (reg))
+#define WREG32_DIDT(reg, v) adev->didt_wreg(adev, (reg), (v))
+#define RREG32_AUDIO_ENDPT(block, reg) adev->audio_endpt_rreg(adev, (block), (reg))
+#define WREG32_AUDIO_ENDPT(block, reg, v) adev->audio_endpt_wreg(adev, (block), (reg), (v))
+#define WREG32_P(reg, val, mask) \
+ do { \
+ uint32_t tmp_ = RREG32(reg); \
+ tmp_ &= (mask); \
+ tmp_ |= ((val) & ~(mask)); \
+ WREG32(reg, tmp_); \
+ } while (0)
+#define WREG32_AND(reg, and) WREG32_P(reg, 0, and)
+#define WREG32_OR(reg, or) WREG32_P(reg, or, ~(or))
+#define WREG32_PLL_P(reg, val, mask) \
+ do { \
+ uint32_t tmp_ = RREG32_PLL(reg); \
+ tmp_ &= (mask); \
+ tmp_ |= ((val) & ~(mask)); \
+ WREG32_PLL(reg, tmp_); \
+ } while (0)
+#define DREG32_SYS(sqf, adev, reg) seq_printf((sqf), #reg " : 0x%08X\n", amdgpu_mm_rreg((adev), (reg), false))
+#define RREG32_IO(reg) amdgpu_io_rreg(adev, (reg))
+#define WREG32_IO(reg, v) amdgpu_io_wreg(adev, (reg), (v))
+
+#define RDOORBELL32(index) amdgpu_mm_rdoorbell(adev, (index))
+#define WDOORBELL32(index, v) amdgpu_mm_wdoorbell(adev, (index), (v))
+
+#define REG_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT
+#define REG_FIELD_MASK(reg, field) reg##__##field##_MASK
+
+#define REG_SET_FIELD(orig_val, reg, field, field_val) \
+ (((orig_val) & ~REG_FIELD_MASK(reg, field)) | \
+ (REG_FIELD_MASK(reg, field) & ((field_val) << REG_FIELD_SHIFT(reg, field))))
+
+#define REG_GET_FIELD(value, reg, field) \
+ (((value) & REG_FIELD_MASK(reg, field)) >> REG_FIELD_SHIFT(reg, field))
+
+/*
+ * BIOS helpers.
+ */
+#define RBIOS8(i) (adev->bios[i])
+#define RBIOS16(i) (RBIOS8(i) | (RBIOS8((i)+1) << 8))
+#define RBIOS32(i) ((RBIOS16(i)) | (RBIOS16((i)+2) << 16))
+
+/*
+ * RING helpers.
+ */
+static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v)
+{
+ if (ring->count_dw <= 0)
+ DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n");
+ ring->ring[ring->wptr++] = v;
+ ring->wptr &= ring->ptr_mask;
+ ring->count_dw--;
+ ring->ring_free_dw--;
+}
+
+/*
+ * ASICs macro.
+ */
+#define amdgpu_asic_set_vga_state(adev, state) (adev)->asic_funcs->set_vga_state((adev), (state))
+#define amdgpu_asic_reset(adev) (adev)->asic_funcs->reset((adev))
+#define amdgpu_asic_wait_for_mc_idle(adev) (adev)->asic_funcs->wait_for_mc_idle((adev))
+#define amdgpu_asic_get_xclk(adev) (adev)->asic_funcs->get_xclk((adev))
+#define amdgpu_asic_set_uvd_clocks(adev, v, d) (adev)->asic_funcs->set_uvd_clocks((adev), (v), (d))
+#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_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))
+#define amdgpu_gart_set_pte_pde(adev, pt, idx, addr, flags) (adev)->gart.gart_funcs->set_pte_pde((adev), (pt), (idx), (addr), (flags))
+#define amdgpu_vm_copy_pte(adev, ib, pe, src, count) ((adev)->vm_manager.vm_pte_funcs->copy_pte((ib), (pe), (src), (count)))
+#define amdgpu_vm_write_pte(adev, ib, pe, addr, count, incr, flags) ((adev)->vm_manager.vm_pte_funcs->write_pte((ib), (pe), (addr), (count), (incr), (flags)))
+#define amdgpu_vm_set_pte_pde(adev, ib, pe, addr, count, incr, flags) ((adev)->vm_manager.vm_pte_funcs->set_pte_pde((ib), (pe), (addr), (count), (incr), (flags)))
+#define amdgpu_vm_pad_ib(adev, ib) ((adev)->vm_manager.vm_pte_funcs->pad_ib((ib)))
+#define amdgpu_ring_parse_cs(r, p, ib) ((r)->funcs->parse_cs((p), (ib)))
+#define amdgpu_ring_test_ring(r) (r)->funcs->test_ring((r))
+#define amdgpu_ring_test_ib(r) (r)->funcs->test_ib((r))
+#define amdgpu_ring_is_lockup(r) (r)->funcs->is_lockup((r))
+#define amdgpu_ring_get_rptr(r) (r)->funcs->get_rptr((r))
+#define amdgpu_ring_get_wptr(r) (r)->funcs->get_wptr((r))
+#define amdgpu_ring_set_wptr(r) (r)->funcs->set_wptr((r))
+#define amdgpu_ring_emit_ib(r, ib) (r)->funcs->emit_ib((r), (ib))
+#define amdgpu_ring_emit_vm_flush(r, vmid, addr) (r)->funcs->emit_vm_flush((r), (vmid), (addr))
+#define amdgpu_ring_emit_fence(r, addr, seq, flags) (r)->funcs->emit_fence((r), (addr), (seq), (flags))
+#define amdgpu_ring_emit_semaphore(r, semaphore, emit_wait) (r)->funcs->emit_semaphore((r), (semaphore), (emit_wait))
+#define amdgpu_ring_emit_gds_switch(r, v, db, ds, wb, ws, ab, as) (r)->funcs->emit_gds_switch((r), (v), (db), (ds), (wb), (ws), (ab), (as))
+#define amdgpu_ring_emit_hdp_flush(r) (r)->funcs->emit_hdp_flush((r))
+#define amdgpu_ih_get_wptr(adev) (adev)->irq.ih_funcs->get_wptr((adev))
+#define amdgpu_ih_decode_iv(adev, iv) (adev)->irq.ih_funcs->decode_iv((adev), (iv))
+#define amdgpu_ih_set_rptr(adev) (adev)->irq.ih_funcs->set_rptr((adev))
+#define amdgpu_display_set_vga_render_state(adev, r) (adev)->mode_info.funcs->set_vga_render_state((adev), (r))
+#define amdgpu_display_vblank_get_counter(adev, crtc) (adev)->mode_info.funcs->vblank_get_counter((adev), (crtc))
+#define amdgpu_display_vblank_wait(adev, crtc) (adev)->mode_info.funcs->vblank_wait((adev), (crtc))
+#define amdgpu_display_is_display_hung(adev) (adev)->mode_info.funcs->is_display_hung((adev))
+#define amdgpu_display_backlight_set_level(adev, e, l) (adev)->mode_info.funcs->backlight_set_level((e), (l))
+#define amdgpu_display_backlight_get_level(adev, e) (adev)->mode_info.funcs->backlight_get_level((e))
+#define amdgpu_display_hpd_sense(adev, h) (adev)->mode_info.funcs->hpd_sense((adev), (h))
+#define amdgpu_display_hpd_set_polarity(adev, h) (adev)->mode_info.funcs->hpd_set_polarity((adev), (h))
+#define amdgpu_display_hpd_get_gpio_reg(adev) (adev)->mode_info.funcs->hpd_get_gpio_reg((adev))
+#define amdgpu_display_bandwidth_update(adev) (adev)->mode_info.funcs->bandwidth_update((adev))
+#define amdgpu_display_page_flip(adev, crtc, base) (adev)->mode_info.funcs->page_flip((adev), (crtc), (base))
+#define amdgpu_display_page_flip_get_scanoutpos(adev, crtc, vbl, pos) (adev)->mode_info.funcs->page_flip_get_scanoutpos((adev), (crtc), (vbl), (pos))
+#define amdgpu_display_add_encoder(adev, e, s, c) (adev)->mode_info.funcs->add_encoder((adev), (e), (s), (c))
+#define amdgpu_display_add_connector(adev, ci, sd, ct, ib, coi, h, r) (adev)->mode_info.funcs->add_connector((adev), (ci), (sd), (ct), (ib), (coi), (h), (r))
+#define amdgpu_display_stop_mc_access(adev, s) (adev)->mode_info.funcs->stop_mc_access((adev), (s))
+#define amdgpu_display_resume_mc_access(adev, s) (adev)->mode_info.funcs->resume_mc_access((adev), (s))
+#define amdgpu_emit_copy_buffer(adev, r, s, d, b) (adev)->mman.buffer_funcs->emit_copy_buffer((r), (s), (d), (b))
+#define amdgpu_emit_fill_buffer(adev, r, s, d, b) (adev)->mman.buffer_funcs->emit_fill_buffer((r), (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_gds_switch(adev, r, v, d, w, a) (adev)->gds.funcs->patch_gds_switch((r), (v), (d), (w), (a))
+
+/* Common functions */
+int amdgpu_gpu_reset(struct amdgpu_device *adev);
+void amdgpu_pci_config_reset(struct amdgpu_device *adev);
+bool amdgpu_card_posted(struct amdgpu_device *adev);
+void amdgpu_update_display_priority(struct amdgpu_device *adev);
+bool amdgpu_boot_test_post_card(struct amdgpu_device *adev);
+int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data);
+int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
+ u32 ip_instance, u32 ring,
+ struct amdgpu_ring **out_ring);
+void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *rbo, u32 domain);
+bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo);
+int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
+ uint32_t flags);
+bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm);
+bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm);
+uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
+ struct ttm_mem_reg *mem);
+void amdgpu_vram_location(struct amdgpu_device *adev, struct amdgpu_mc *mc, u64 base);
+void amdgpu_gtt_location(struct amdgpu_device *adev, struct amdgpu_mc *mc);
+void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size);
+void amdgpu_program_register_sequence(struct amdgpu_device *adev,
+ const u32 *registers,
+ const u32 array_size);
+
+bool amdgpu_device_is_px(struct drm_device *dev);
+/* atpx handler */
+#if defined(CONFIG_VGA_SWITCHEROO)
+void amdgpu_register_atpx_handler(void);
+void amdgpu_unregister_atpx_handler(void);
+#else
+static inline void amdgpu_register_atpx_handler(void) {}
+static inline void amdgpu_unregister_atpx_handler(void) {}
+#endif
+
+/*
+ * KMS
+ */
+extern const struct drm_ioctl_desc amdgpu_ioctls_kms[];
+extern int amdgpu_max_kms_ioctl;
+
+int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags);
+int amdgpu_driver_unload_kms(struct drm_device *dev);
+void amdgpu_driver_lastclose_kms(struct drm_device *dev);
+int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv);
+void amdgpu_driver_postclose_kms(struct drm_device *dev,
+ struct drm_file *file_priv);
+void amdgpu_driver_preclose_kms(struct drm_device *dev,
+ struct drm_file *file_priv);
+int amdgpu_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon);
+int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon);
+u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, int crtc);
+int amdgpu_enable_vblank_kms(struct drm_device *dev, int crtc);
+void amdgpu_disable_vblank_kms(struct drm_device *dev, int crtc);
+int amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
+ int *max_error,
+ struct timeval *vblank_time,
+ unsigned flags);
+long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg);
+
+/*
+ * vm
+ */
+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);
+struct amdgpu_fence *amdgpu_vm_grab_id(struct amdgpu_ring *ring,
+ struct amdgpu_vm *vm);
+void amdgpu_vm_flush(struct amdgpu_ring *ring,
+ struct amdgpu_vm *vm,
+ struct amdgpu_fence *updates);
+void amdgpu_vm_fence(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm,
+ struct amdgpu_fence *fence);
+uint64_t amdgpu_vm_map_gart(struct amdgpu_device *adev, uint64_t addr);
+int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm);
+int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm);
+int amdgpu_vm_clear_invalids(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm, struct amdgpu_sync *sync);
+int amdgpu_vm_bo_update(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va,
+ struct ttm_mem_reg *mem);
+void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev,
+ struct amdgpu_bo *bo);
+struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm,
+ struct amdgpu_bo *bo);
+struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm,
+ struct amdgpu_bo *bo);
+int amdgpu_vm_bo_map(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va,
+ uint64_t addr, uint64_t offset,
+ uint64_t size, uint32_t flags);
+int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va,
+ uint64_t addr);
+void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va);
+
+/*
+ * functions used by amdgpu_encoder.c
+ */
+struct amdgpu_afmt_acr {
+ u32 clock;
+
+ int n_32khz;
+ int cts_32khz;
+
+ int n_44_1khz;
+ int cts_44_1khz;
+
+ int n_48khz;
+ int cts_48khz;
+
+};
+
+struct amdgpu_afmt_acr amdgpu_afmt_acr(uint32_t clock);
+
+/* amdgpu_acpi.c */
+#if defined(CONFIG_ACPI)
+int amdgpu_acpi_init(struct amdgpu_device *adev);
+void amdgpu_acpi_fini(struct amdgpu_device *adev);
+bool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *adev);
+int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev,
+ u8 perf_req, bool advertise);
+int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev);
+#else
+static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; }
+static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { }
+#endif
+
+struct amdgpu_bo_va_mapping *
+amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
+ uint64_t addr, struct amdgpu_bo **bo);
+
+#include "amdgpu_object.h"
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
new file mode 100644
index 000000000000..aef4a7aac0f7
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -0,0 +1,768 @@
+/*
+ * Copyright 2012 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/pci.h>
+#include <linux/acpi.h>
+#include <linux/slab.h>
+#include <linux/power_supply.h>
+#include <linux/vga_switcheroo.h>
+#include <acpi/video.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include "amdgpu.h"
+#include "amdgpu_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
+ */
+/**
+ * amdgpu_atif_call - call an ATIF method
+ *
+ * @handle: acpi handle
+ * @function: the ATIF function to execute
+ * @params: ATIF function params
+ *
+ * Executes the requested ATIF function (all asics).
+ * Returns a pointer to the acpi output buffer.
+ */
+static union acpi_object *amdgpu_atif_call(acpi_handle handle, int function,
+ struct acpi_buffer *params)
+{
+ acpi_status status;
+ union acpi_object atif_arg_elements[2];
+ struct acpi_object_list atif_arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ atif_arg.count = 2;
+ atif_arg.pointer = &atif_arg_elements[0];
+
+ atif_arg_elements[0].type = ACPI_TYPE_INTEGER;
+ atif_arg_elements[0].integer.value = function;
+
+ if (params) {
+ atif_arg_elements[1].type = ACPI_TYPE_BUFFER;
+ atif_arg_elements[1].buffer.length = params->length;
+ atif_arg_elements[1].buffer.pointer = params->pointer;
+ } else {
+ /* We need a second fake parameter */
+ atif_arg_elements[1].type = ACPI_TYPE_INTEGER;
+ atif_arg_elements[1].integer.value = 0;
+ }
+
+ status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer);
+
+ /* Fail only if calling the method fails and ATIF is supported */
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n",
+ acpi_format_exception(status));
+ kfree(buffer.pointer);
+ return NULL;
+ }
+
+ return buffer.pointer;
+}
+
+/**
+ * amdgpu_atif_parse_notification - parse supported notifications
+ *
+ * @n: supported notifications struct
+ * @mask: supported notifications mask from ATIF
+ *
+ * Use the supported notifications mask from ATIF function
+ * ATIF_FUNCTION_VERIFY_INTERFACE to determine what notifications
+ * are supported (all asics).
+ */
+static void amdgpu_atif_parse_notification(struct amdgpu_atif_notifications *n, u32 mask)
+{
+ n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED;
+ n->expansion_mode_change = mask & ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED;
+ n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED;
+ n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED;
+ n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED;
+ n->display_conf_change = mask & ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED;
+ n->px_gfx_switch = mask & ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED;
+ n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED;
+ n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED;
+}
+
+/**
+ * amdgpu_atif_parse_functions - parse supported functions
+ *
+ * @f: supported functions struct
+ * @mask: supported functions mask from ATIF
+ *
+ * Use the supported functions mask from ATIF function
+ * ATIF_FUNCTION_VERIFY_INTERFACE to determine what functions
+ * are supported (all asics).
+ */
+static void amdgpu_atif_parse_functions(struct amdgpu_atif_functions *f, u32 mask)
+{
+ f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED;
+ f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED;
+ f->select_active_disp = mask & ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED;
+ f->lid_state = mask & ATIF_GET_LID_STATE_SUPPORTED;
+ f->get_tv_standard = mask & ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED;
+ f->set_tv_standard = mask & ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED;
+ f->get_panel_expansion_mode = mask & ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED;
+ f->set_panel_expansion_mode = mask & ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED;
+ f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED;
+ f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED;
+}
+
+/**
+ * amdgpu_atif_verify_interface - verify ATIF
+ *
+ * @handle: acpi handle
+ * @atif: amdgpu atif struct
+ *
+ * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function
+ * to initialize ATIF and determine what features are supported
+ * (all asics).
+ * returns 0 on success, error on failure.
+ */
+static int amdgpu_atif_verify_interface(acpi_handle handle,
+ struct amdgpu_atif *atif)
+{
+ union acpi_object *info;
+ struct atif_verify_interface output;
+ size_t size;
+ int err = 0;
+
+ info = amdgpu_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL);
+ if (!info)
+ return -EIO;
+
+ memset(&output, 0, sizeof(output));
+
+ size = *(u16 *) info->buffer.pointer;
+ if (size < 12) {
+ DRM_INFO("ATIF buffer is too small: %zu\n", size);
+ err = -EINVAL;
+ goto out;
+ }
+ size = min(sizeof(output), size);
+
+ memcpy(&output, info->buffer.pointer, size);
+
+ /* TODO: check version? */
+ DRM_DEBUG_DRIVER("ATIF version %u\n", output.version);
+
+ amdgpu_atif_parse_notification(&atif->notifications, output.notification_mask);
+ amdgpu_atif_parse_functions(&atif->functions, output.function_bits);
+
+out:
+ kfree(info);
+ return err;
+}
+
+/**
+ * amdgpu_atif_get_notification_params - determine notify configuration
+ *
+ * @handle: acpi handle
+ * @n: atif notification configuration struct
+ *
+ * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function
+ * to determine if a notifier is used and if so which one
+ * (all asics). This is either Notify(VGA, 0x81) or Notify(VGA, n)
+ * where n is specified in the result if a notifier is used.
+ * Returns 0 on success, error on failure.
+ */
+static int amdgpu_atif_get_notification_params(acpi_handle handle,
+ struct amdgpu_atif_notification_cfg *n)
+{
+ union acpi_object *info;
+ struct atif_system_params params;
+ size_t size;
+ int err = 0;
+
+ info = amdgpu_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, NULL);
+ if (!info) {
+ err = -EIO;
+ goto out;
+ }
+
+ size = *(u16 *) info->buffer.pointer;
+ if (size < 10) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ memset(&params, 0, sizeof(params));
+ size = min(sizeof(params), size);
+ memcpy(&params, info->buffer.pointer, size);
+
+ DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n",
+ params.flags, params.valid_mask);
+ params.flags = params.flags & params.valid_mask;
+
+ if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) {
+ n->enabled = false;
+ n->command_code = 0;
+ } else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) {
+ n->enabled = true;
+ n->command_code = 0x81;
+ } else {
+ if (size < 11) {
+ err = -EINVAL;
+ goto out;
+ }
+ n->enabled = true;
+ n->command_code = params.command_code;
+ }
+
+out:
+ DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n",
+ (n->enabled ? "enabled" : "disabled"),
+ n->command_code);
+ kfree(info);
+ return err;
+}
+
+/**
+ * amdgpu_atif_get_sbios_requests - get requested sbios event
+ *
+ * @handle: acpi handle
+ * @req: atif sbios request struct
+ *
+ * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function
+ * to determine what requests the sbios is making to the driver
+ * (all asics).
+ * Returns 0 on success, error on failure.
+ */
+static int amdgpu_atif_get_sbios_requests(acpi_handle handle,
+ struct atif_sbios_requests *req)
+{
+ union acpi_object *info;
+ size_t size;
+ int count = 0;
+
+ info = amdgpu_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL);
+ if (!info)
+ return -EIO;
+
+ size = *(u16 *)info->buffer.pointer;
+ if (size < 0xd) {
+ count = -EINVAL;
+ goto out;
+ }
+ memset(req, 0, sizeof(*req));
+
+ size = min(sizeof(*req), size);
+ memcpy(req, info->buffer.pointer, size);
+ DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending);
+
+ count = hweight32(req->pending);
+
+out:
+ kfree(info);
+ return count;
+}
+
+/**
+ * amdgpu_atif_handler - handle ATIF notify requests
+ *
+ * @adev: amdgpu_device pointer
+ * @event: atif sbios request struct
+ *
+ * Checks the acpi event and if it matches an atif event,
+ * handles it.
+ * Returns NOTIFY code
+ */
+int amdgpu_atif_handler(struct amdgpu_device *adev,
+ struct acpi_bus_event *event)
+{
+ struct amdgpu_atif *atif = &adev->atif;
+ struct atif_sbios_requests req;
+ acpi_handle handle;
+ int count;
+
+ DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n",
+ event->device_class, event->type);
+
+ if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0)
+ return NOTIFY_DONE;
+
+ if (!atif->notification_cfg.enabled ||
+ event->type != atif->notification_cfg.command_code)
+ /* Not our event */
+ return NOTIFY_DONE;
+
+ /* Check pending SBIOS requests */
+ handle = ACPI_HANDLE(&adev->pdev->dev);
+ count = amdgpu_atif_get_sbios_requests(handle, &req);
+
+ if (count <= 0)
+ return NOTIFY_DONE;
+
+ DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count);
+
+ if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) {
+ struct amdgpu_encoder *enc = atif->encoder_for_bl;
+
+ if (enc) {
+ struct amdgpu_encoder_atom_dig *dig = enc->enc_priv;
+
+ DRM_DEBUG_DRIVER("Changing brightness to %d\n",
+ req.backlight_level);
+
+ amdgpu_display_backlight_set_level(adev, enc, req.backlight_level);
+
+#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
+ backlight_force_update(dig->bl_dev,
+ BACKLIGHT_UPDATE_HOTKEY);
+#endif
+ }
+ }
+ /* TODO: check other events */
+
+ /* We've handled the event, stop the notifier chain. The ACPI interface
+ * overloads ACPI_VIDEO_NOTIFY_PROBE, we don't want to send that to
+ * userspace if the event was generated only to signal a SBIOS
+ * request.
+ */
+ return NOTIFY_BAD;
+}
+
+/* Call the ATCS method
+ */
+/**
+ * amdgpu_atcs_call - call an ATCS method
+ *
+ * @handle: acpi handle
+ * @function: the ATCS function to execute
+ * @params: ATCS function params
+ *
+ * Executes the requested ATCS function (all asics).
+ * Returns a pointer to the acpi output buffer.
+ */
+static union acpi_object *amdgpu_atcs_call(acpi_handle handle, int function,
+ struct acpi_buffer *params)
+{
+ acpi_status status;
+ union acpi_object atcs_arg_elements[2];
+ struct acpi_object_list atcs_arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ atcs_arg.count = 2;
+ atcs_arg.pointer = &atcs_arg_elements[0];
+
+ atcs_arg_elements[0].type = ACPI_TYPE_INTEGER;
+ atcs_arg_elements[0].integer.value = function;
+
+ if (params) {
+ atcs_arg_elements[1].type = ACPI_TYPE_BUFFER;
+ atcs_arg_elements[1].buffer.length = params->length;
+ atcs_arg_elements[1].buffer.pointer = params->pointer;
+ } else {
+ /* We need a second fake parameter */
+ atcs_arg_elements[1].type = ACPI_TYPE_INTEGER;
+ atcs_arg_elements[1].integer.value = 0;
+ }
+
+ status = acpi_evaluate_object(handle, "ATCS", &atcs_arg, &buffer);
+
+ /* Fail only if calling the method fails and ATIF is supported */
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ DRM_DEBUG_DRIVER("failed to evaluate ATCS got %s\n",
+ acpi_format_exception(status));
+ kfree(buffer.pointer);
+ return NULL;
+ }
+
+ return buffer.pointer;
+}
+
+/**
+ * amdgpu_atcs_parse_functions - parse supported functions
+ *
+ * @f: supported functions struct
+ * @mask: supported functions mask from ATCS
+ *
+ * Use the supported functions mask from ATCS function
+ * ATCS_FUNCTION_VERIFY_INTERFACE to determine what functions
+ * are supported (all asics).
+ */
+static void amdgpu_atcs_parse_functions(struct amdgpu_atcs_functions *f, u32 mask)
+{
+ f->get_ext_state = mask & ATCS_GET_EXTERNAL_STATE_SUPPORTED;
+ f->pcie_perf_req = mask & ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED;
+ f->pcie_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED;
+ f->pcie_bus_width = mask & ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED;
+}
+
+/**
+ * amdgpu_atcs_verify_interface - verify ATCS
+ *
+ * @handle: acpi handle
+ * @atcs: amdgpu atcs struct
+ *
+ * Execute the ATCS_FUNCTION_VERIFY_INTERFACE ATCS function
+ * to initialize ATCS and determine what features are supported
+ * (all asics).
+ * returns 0 on success, error on failure.
+ */
+static int amdgpu_atcs_verify_interface(acpi_handle handle,
+ struct amdgpu_atcs *atcs)
+{
+ union acpi_object *info;
+ struct atcs_verify_interface output;
+ size_t size;
+ int err = 0;
+
+ info = amdgpu_atcs_call(handle, ATCS_FUNCTION_VERIFY_INTERFACE, NULL);
+ if (!info)
+ return -EIO;
+
+ memset(&output, 0, sizeof(output));
+
+ size = *(u16 *) info->buffer.pointer;
+ if (size < 8) {
+ DRM_INFO("ATCS buffer is too small: %zu\n", size);
+ err = -EINVAL;
+ goto out;
+ }
+ size = min(sizeof(output), size);
+
+ memcpy(&output, info->buffer.pointer, size);
+
+ /* TODO: check version? */
+ DRM_DEBUG_DRIVER("ATCS version %u\n", output.version);
+
+ amdgpu_atcs_parse_functions(&atcs->functions, output.function_bits);
+
+out:
+ kfree(info);
+ return err;
+}
+
+/**
+ * amdgpu_acpi_is_pcie_performance_request_supported
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Check if the ATCS pcie_perf_req and pcie_dev_rdy methods
+ * are supported (all asics).
+ * returns true if supported, false if not.
+ */
+bool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *adev)
+{
+ struct amdgpu_atcs *atcs = &adev->atcs;
+
+ if (atcs->functions.pcie_perf_req && atcs->functions.pcie_dev_rdy)
+ return true;
+
+ return false;
+}
+
+/**
+ * amdgpu_acpi_pcie_notify_device_ready
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Executes the PCIE_DEVICE_READY_NOTIFICATION method
+ * (all asics).
+ * returns 0 on success, error on failure.
+ */
+int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev)
+{
+ acpi_handle handle;
+ union acpi_object *info;
+ struct amdgpu_atcs *atcs = &adev->atcs;
+
+ /* Get the device handle */
+ handle = ACPI_HANDLE(&adev->pdev->dev);
+ if (!handle)
+ return -EINVAL;
+
+ if (!atcs->functions.pcie_dev_rdy)
+ return -EINVAL;
+
+ info = amdgpu_atcs_call(handle, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION, NULL);
+ if (!info)
+ return -EIO;
+
+ kfree(info);
+
+ return 0;
+}
+
+/**
+ * amdgpu_acpi_pcie_performance_request
+ *
+ * @adev: amdgpu_device pointer
+ * @perf_req: requested perf level (pcie gen speed)
+ * @advertise: set advertise caps flag if set
+ *
+ * Executes the PCIE_PERFORMANCE_REQUEST method to
+ * change the pcie gen speed (all asics).
+ * returns 0 on success, error on failure.
+ */
+int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev,
+ u8 perf_req, bool advertise)
+{
+ acpi_handle handle;
+ union acpi_object *info;
+ struct amdgpu_atcs *atcs = &adev->atcs;
+ struct atcs_pref_req_input atcs_input;
+ struct atcs_pref_req_output atcs_output;
+ struct acpi_buffer params;
+ size_t size;
+ u32 retry = 3;
+
+ /* Get the device handle */
+ handle = ACPI_HANDLE(&adev->pdev->dev);
+ if (!handle)
+ return -EINVAL;
+
+ if (!atcs->functions.pcie_perf_req)
+ return -EINVAL;
+
+ atcs_input.size = sizeof(struct atcs_pref_req_input);
+ /* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */
+ atcs_input.client_id = adev->pdev->devfn | (adev->pdev->bus->number << 8);
+ 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;
+
+ params.length = sizeof(struct atcs_pref_req_input);
+ params.pointer = &atcs_input;
+
+ while (retry--) {
+ info = amdgpu_atcs_call(handle, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST, &params);
+ if (!info)
+ return -EIO;
+
+ memset(&atcs_output, 0, sizeof(atcs_output));
+
+ size = *(u16 *) info->buffer.pointer;
+ if (size < 3) {
+ DRM_INFO("ATCS buffer is too small: %zu\n", size);
+ kfree(info);
+ return -EINVAL;
+ }
+ size = min(sizeof(atcs_output), size);
+
+ memcpy(&atcs_output, info->buffer.pointer, size);
+
+ kfree(info);
+
+ 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;
+}
+
+/**
+ * amdgpu_acpi_event - handle notify events
+ *
+ * @nb: notifier block
+ * @val: val
+ * @data: acpi event
+ *
+ * Calls relevant amdgpu functions in response to various
+ * acpi events.
+ * Returns NOTIFY code
+ */
+static int amdgpu_acpi_event(struct notifier_block *nb,
+ unsigned long val,
+ void *data)
+{
+ struct amdgpu_device *adev = container_of(nb, struct amdgpu_device, acpi_nb);
+ struct acpi_bus_event *entry = (struct acpi_bus_event *)data;
+
+ if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) {
+ if (power_supply_is_system_supplied() > 0)
+ DRM_DEBUG_DRIVER("pm: AC\n");
+ else
+ DRM_DEBUG_DRIVER("pm: DC\n");
+
+ amdgpu_pm_acpi_event_handler(adev);
+ }
+
+ /* Check for pending SBIOS requests */
+ return amdgpu_atif_handler(adev, entry);
+}
+
+/* Call all ACPI methods here */
+/**
+ * amdgpu_acpi_init - init driver acpi support
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Verifies the AMD ACPI interfaces and registers with the acpi
+ * notifier chain (all asics).
+ * Returns 0 on success, error on failure.
+ */
+int amdgpu_acpi_init(struct amdgpu_device *adev)
+{
+ acpi_handle handle;
+ struct amdgpu_atif *atif = &adev->atif;
+ struct amdgpu_atcs *atcs = &adev->atcs;
+ int ret;
+
+ /* Get the device handle */
+ handle = ACPI_HANDLE(&adev->pdev->dev);
+
+ if (!adev->bios || !handle)
+ return 0;
+
+ /* Call the ATCS method */
+ ret = amdgpu_atcs_verify_interface(handle, atcs);
+ if (ret) {
+ DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret);
+ }
+
+ /* Call the ATIF method */
+ ret = amdgpu_atif_verify_interface(handle, atif);
+ if (ret) {
+ DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret);
+ goto out;
+ }
+
+ if (atif->notifications.brightness_change) {
+ struct drm_encoder *tmp;
+
+ /* Find the encoder controlling the brightness */
+ list_for_each_entry(tmp, &adev->ddev->mode_config.encoder_list,
+ head) {
+ struct amdgpu_encoder *enc = to_amdgpu_encoder(tmp);
+
+ if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) &&
+ enc->enc_priv) {
+ if (adev->is_atom_bios) {
+ struct amdgpu_encoder_atom_dig *dig = enc->enc_priv;
+ if (dig->bl_dev) {
+ atif->encoder_for_bl = enc;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (atif->functions.sbios_requests && !atif->functions.system_params) {
+ /* XXX check this workraround, if sbios request function is
+ * present we have to see how it's configured in the system
+ * params
+ */
+ atif->functions.system_params = true;
+ }
+
+ if (atif->functions.system_params) {
+ ret = amdgpu_atif_get_notification_params(handle,
+ &atif->notification_cfg);
+ if (ret) {
+ DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n",
+ ret);
+ /* Disable notification */
+ atif->notification_cfg.enabled = false;
+ }
+ }
+
+out:
+ adev->acpi_nb.notifier_call = amdgpu_acpi_event;
+ register_acpi_notifier(&adev->acpi_nb);
+
+ return ret;
+}
+
+/**
+ * amdgpu_acpi_fini - tear down driver acpi support
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Unregisters with the acpi notifier chain (all asics).
+ */
+void amdgpu_acpi_fini(struct amdgpu_device *adev)
+{
+ unregister_acpi_notifier(&adev->acpi_nb);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h
new file mode 100644
index 000000000000..01a29c3d7011
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.h
@@ -0,0 +1,445 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef AMDGPU_ACPI_H
+#define AMDGPU_ACPI_H
+
+struct amdgpu_device;
+struct acpi_bus_event;
+
+int amdgpu_atif_handler(struct amdgpu_device *adev,
+ struct acpi_bus_event *event);
+
+/* AMD hw uses four ACPI control methods:
+ * 1. ATIF
+ * ARG0: (ACPI_INTEGER) function code
+ * ARG1: (ACPI_BUFFER) parameter buffer, 256 bytes
+ * OUTPUT: (ACPI_BUFFER) output buffer, 256 bytes
+ * ATIF provides an entry point for the gfx driver to interact with the sbios.
+ * The AMD ACPI notification mechanism uses Notify (VGA, 0x81) or a custom
+ * notification. Which notification is used as indicated by the ATIF Control
+ * Method GET_SYSTEM_PARAMETERS. When the driver receives Notify (VGA, 0x81) or
+ * a custom notification it invokes ATIF Control Method GET_SYSTEM_BIOS_REQUESTS
+ * to identify pending System BIOS requests and associated parameters. For
+ * example, if one of the pending requests is DISPLAY_SWITCH_REQUEST, the driver
+ * will perform display device detection and invoke ATIF Control Method
+ * SELECT_ACTIVE_DISPLAYS.
+ *
+ * 2. ATPX
+ * ARG0: (ACPI_INTEGER) function code
+ * ARG1: (ACPI_BUFFER) parameter buffer, 256 bytes
+ * OUTPUT: (ACPI_BUFFER) output buffer, 256 bytes
+ * ATPX methods are used on PowerXpress systems to handle mux switching and
+ * discrete GPU power control.
+ *
+ * 3. ATRM
+ * ARG0: (ACPI_INTEGER) offset of vbios rom data
+ * ARG1: (ACPI_BUFFER) size of the buffer to fill (up to 4K).
+ * OUTPUT: (ACPI_BUFFER) output buffer
+ * ATRM provides an interfacess to access the discrete GPU vbios image on
+ * PowerXpress systems with multiple GPUs.
+ *
+ * 4. ATCS
+ * ARG0: (ACPI_INTEGER) function code
+ * ARG1: (ACPI_BUFFER) parameter buffer, 256 bytes
+ * OUTPUT: (ACPI_BUFFER) output buffer, 256 bytes
+ * ATCS provides an interface to AMD chipset specific functionality.
+ *
+ */
+/* ATIF */
+#define ATIF_FUNCTION_VERIFY_INTERFACE 0x0
+/* ARG0: ATIF_FUNCTION_VERIFY_INTERFACE
+ * ARG1: none
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * WORD - version
+ * DWORD - supported notifications mask
+ * DWORD - supported functions bit vector
+ */
+/* Notifications mask */
+# define ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED (1 << 0)
+# define ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED (1 << 1)
+# define ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED (1 << 2)
+# define ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED (1 << 3)
+# define ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED (1 << 4)
+# define ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED (1 << 5)
+# define ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED (1 << 6)
+# define ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED (1 << 7)
+# define ATIF_DGPU_DISPLAY_EVENT_SUPPORTED (1 << 8)
+/* supported functions vector */
+# define ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED (1 << 0)
+# define ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED (1 << 1)
+# define ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED (1 << 2)
+# define ATIF_GET_LID_STATE_SUPPORTED (1 << 3)
+# define ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED (1 << 4)
+# define ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED (1 << 5)
+# define ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED (1 << 6)
+# define ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED (1 << 7)
+# define ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED (1 << 12)
+# define ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED (1 << 14)
+#define ATIF_FUNCTION_GET_SYSTEM_PARAMETERS 0x1
+/* ARG0: ATIF_FUNCTION_GET_SYSTEM_PARAMETERS
+ * ARG1: none
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * DWORD - valid flags mask
+ * DWORD - flags
+ *
+ * OR
+ *
+ * WORD - structure size in bytes (includes size field)
+ * DWORD - valid flags mask
+ * DWORD - flags
+ * BYTE - notify command code
+ *
+ * flags
+ * bits 1:0:
+ * 0 - Notify(VGA, 0x81) is not used for notification
+ * 1 - Notify(VGA, 0x81) is used for notification
+ * 2 - Notify(VGA, n) is used for notification where
+ * n (0xd0-0xd9) is specified in notify command code.
+ * bit 2:
+ * 1 - lid changes not reported though int10
+ */
+#define ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS 0x2
+/* ARG0: ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS
+ * ARG1: none
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * DWORD - pending sbios requests
+ * BYTE - panel expansion mode
+ * BYTE - thermal state: target gfx controller
+ * BYTE - thermal state: state id (0: exit state, non-0: state)
+ * BYTE - forced power state: target gfx controller
+ * BYTE - forced power state: state id
+ * BYTE - system power source
+ * BYTE - panel backlight level (0-255)
+ */
+/* pending sbios requests */
+# define ATIF_DISPLAY_SWITCH_REQUEST (1 << 0)
+# define ATIF_EXPANSION_MODE_CHANGE_REQUEST (1 << 1)
+# define ATIF_THERMAL_STATE_CHANGE_REQUEST (1 << 2)
+# define ATIF_FORCED_POWER_STATE_CHANGE_REQUEST (1 << 3)
+# define ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST (1 << 4)
+# define ATIF_DISPLAY_CONF_CHANGE_REQUEST (1 << 5)
+# define ATIF_PX_GFX_SWITCH_REQUEST (1 << 6)
+# define ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST (1 << 7)
+# define ATIF_DGPU_DISPLAY_EVENT (1 << 8)
+/* panel expansion mode */
+# define ATIF_PANEL_EXPANSION_DISABLE 0
+# define ATIF_PANEL_EXPANSION_FULL 1
+# define ATIF_PANEL_EXPANSION_ASPECT 2
+/* target gfx controller */
+# define ATIF_TARGET_GFX_SINGLE 0
+# define ATIF_TARGET_GFX_PX_IGPU 1
+# define ATIF_TARGET_GFX_PX_DGPU 2
+/* system power source */
+# define ATIF_POWER_SOURCE_AC 1
+# define ATIF_POWER_SOURCE_DC 2
+# define ATIF_POWER_SOURCE_RESTRICTED_AC_1 3
+# define ATIF_POWER_SOURCE_RESTRICTED_AC_2 4
+#define ATIF_FUNCTION_SELECT_ACTIVE_DISPLAYS 0x3
+/* ARG0: ATIF_FUNCTION_SELECT_ACTIVE_DISPLAYS
+ * ARG1:
+ * WORD - structure size in bytes (includes size field)
+ * WORD - selected displays
+ * WORD - connected displays
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * WORD - selected displays
+ */
+# define ATIF_LCD1 (1 << 0)
+# define ATIF_CRT1 (1 << 1)
+# define ATIF_TV (1 << 2)
+# define ATIF_DFP1 (1 << 3)
+# define ATIF_CRT2 (1 << 4)
+# define ATIF_LCD2 (1 << 5)
+# define ATIF_DFP2 (1 << 7)
+# define ATIF_CV (1 << 8)
+# define ATIF_DFP3 (1 << 9)
+# define ATIF_DFP4 (1 << 10)
+# define ATIF_DFP5 (1 << 11)
+# define ATIF_DFP6 (1 << 12)
+#define ATIF_FUNCTION_GET_LID_STATE 0x4
+/* ARG0: ATIF_FUNCTION_GET_LID_STATE
+ * ARG1: none
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * BYTE - lid state (0: open, 1: closed)
+ *
+ * GET_LID_STATE only works at boot and resume, for general lid
+ * status, use the kernel provided status
+ */
+#define ATIF_FUNCTION_GET_TV_STANDARD_FROM_CMOS 0x5
+/* ARG0: ATIF_FUNCTION_GET_TV_STANDARD_FROM_CMOS
+ * ARG1: none
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * BYTE - 0
+ * BYTE - TV standard
+ */
+# define ATIF_TV_STD_NTSC 0
+# define ATIF_TV_STD_PAL 1
+# define ATIF_TV_STD_PALM 2
+# define ATIF_TV_STD_PAL60 3
+# define ATIF_TV_STD_NTSCJ 4
+# define ATIF_TV_STD_PALCN 5
+# define ATIF_TV_STD_PALN 6
+# define ATIF_TV_STD_SCART_RGB 9
+#define ATIF_FUNCTION_SET_TV_STANDARD_IN_CMOS 0x6
+/* ARG0: ATIF_FUNCTION_SET_TV_STANDARD_IN_CMOS
+ * ARG1:
+ * WORD - structure size in bytes (includes size field)
+ * BYTE - 0
+ * BYTE - TV standard
+ * OUTPUT: none
+ */
+#define ATIF_FUNCTION_GET_PANEL_EXPANSION_MODE_FROM_CMOS 0x7
+/* ARG0: ATIF_FUNCTION_GET_PANEL_EXPANSION_MODE_FROM_CMOS
+ * ARG1: none
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * BYTE - panel expansion mode
+ */
+#define ATIF_FUNCTION_SET_PANEL_EXPANSION_MODE_IN_CMOS 0x8
+/* ARG0: ATIF_FUNCTION_SET_PANEL_EXPANSION_MODE_IN_CMOS
+ * ARG1:
+ * WORD - structure size in bytes (includes size field)
+ * BYTE - panel expansion mode
+ * OUTPUT: none
+ */
+#define ATIF_FUNCTION_TEMPERATURE_CHANGE_NOTIFICATION 0xD
+/* ARG0: ATIF_FUNCTION_TEMPERATURE_CHANGE_NOTIFICATION
+ * ARG1:
+ * WORD - structure size in bytes (includes size field)
+ * WORD - gfx controller id
+ * BYTE - current temperature (degress Celsius)
+ * OUTPUT: none
+ */
+#define ATIF_FUNCTION_GET_GRAPHICS_DEVICE_TYPES 0xF
+/* ARG0: ATIF_FUNCTION_GET_GRAPHICS_DEVICE_TYPES
+ * ARG1: none
+ * OUTPUT:
+ * WORD - number of gfx devices
+ * WORD - device structure size in bytes (excludes device size field)
+ * DWORD - flags \
+ * WORD - bus number } repeated structure
+ * WORD - device number /
+ */
+/* flags */
+# define ATIF_PX_REMOVABLE_GRAPHICS_DEVICE (1 << 0)
+# define ATIF_XGP_PORT (1 << 1)
+# define ATIF_VGA_ENABLED_GRAPHICS_DEVICE (1 << 2)
+# define ATIF_XGP_PORT_IN_DOCK (1 << 3)
+
+/* ATPX */
+#define ATPX_FUNCTION_VERIFY_INTERFACE 0x0
+/* ARG0: ATPX_FUNCTION_VERIFY_INTERFACE
+ * ARG1: none
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * WORD - version
+ * DWORD - supported functions bit vector
+ */
+/* supported functions vector */
+# define ATPX_GET_PX_PARAMETERS_SUPPORTED (1 << 0)
+# define ATPX_POWER_CONTROL_SUPPORTED (1 << 1)
+# define ATPX_DISPLAY_MUX_CONTROL_SUPPORTED (1 << 2)
+# define ATPX_I2C_MUX_CONTROL_SUPPORTED (1 << 3)
+# define ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED (1 << 4)
+# define ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED (1 << 5)
+# define ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED (1 << 7)
+# define ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED (1 << 8)
+#define ATPX_FUNCTION_GET_PX_PARAMETERS 0x1
+/* ARG0: ATPX_FUNCTION_GET_PX_PARAMETERS
+ * ARG1: none
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * DWORD - valid flags mask
+ * DWORD - flags
+ */
+/* flags */
+# define ATPX_LVDS_I2C_AVAILABLE_TO_BOTH_GPUS (1 << 0)
+# define ATPX_CRT1_I2C_AVAILABLE_TO_BOTH_GPUS (1 << 1)
+# define ATPX_DVI1_I2C_AVAILABLE_TO_BOTH_GPUS (1 << 2)
+# define ATPX_CRT1_RGB_SIGNAL_MUXED (1 << 3)
+# define ATPX_TV_SIGNAL_MUXED (1 << 4)
+# define ATPX_DFP_SIGNAL_MUXED (1 << 5)
+# define ATPX_SEPARATE_MUX_FOR_I2C (1 << 6)
+# define ATPX_DYNAMIC_PX_SUPPORTED (1 << 7)
+# define ATPX_ACF_NOT_SUPPORTED (1 << 8)
+# define ATPX_FIXED_NOT_SUPPORTED (1 << 9)
+# define ATPX_DYNAMIC_DGPU_POWER_OFF_SUPPORTED (1 << 10)
+# define ATPX_DGPU_REQ_POWER_FOR_DISPLAYS (1 << 11)
+#define ATPX_FUNCTION_POWER_CONTROL 0x2
+/* ARG0: ATPX_FUNCTION_POWER_CONTROL
+ * ARG1:
+ * WORD - structure size in bytes (includes size field)
+ * BYTE - dGPU power state (0: power off, 1: power on)
+ * OUTPUT: none
+ */
+#define ATPX_FUNCTION_DISPLAY_MUX_CONTROL 0x3
+/* ARG0: ATPX_FUNCTION_DISPLAY_MUX_CONTROL
+ * ARG1:
+ * WORD - structure size in bytes (includes size field)
+ * WORD - display mux control (0: iGPU, 1: dGPU)
+ * OUTPUT: none
+ */
+# define ATPX_INTEGRATED_GPU 0
+# define ATPX_DISCRETE_GPU 1
+#define ATPX_FUNCTION_I2C_MUX_CONTROL 0x4
+/* ARG0: ATPX_FUNCTION_I2C_MUX_CONTROL
+ * ARG1:
+ * WORD - structure size in bytes (includes size field)
+ * WORD - i2c/aux/hpd mux control (0: iGPU, 1: dGPU)
+ * OUTPUT: none
+ */
+#define ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION 0x5
+/* ARG0: ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION
+ * ARG1:
+ * WORD - structure size in bytes (includes size field)
+ * WORD - target gpu (0: iGPU, 1: dGPU)
+ * OUTPUT: none
+ */
+#define ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION 0x6
+/* ARG0: ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION
+ * ARG1:
+ * WORD - structure size in bytes (includes size field)
+ * WORD - target gpu (0: iGPU, 1: dGPU)
+ * OUTPUT: none
+ */
+#define ATPX_FUNCTION_GET_DISPLAY_CONNECTORS_MAPPING 0x8
+/* ARG0: ATPX_FUNCTION_GET_DISPLAY_CONNECTORS_MAPPING
+ * ARG1: none
+ * OUTPUT:
+ * WORD - number of display connectors
+ * WORD - connector structure size in bytes (excludes connector size field)
+ * BYTE - flags \
+ * BYTE - ATIF display vector bit position } repeated
+ * BYTE - adapter id (0: iGPU, 1-n: dGPU ordered by pcie bus number) } structure
+ * WORD - connector ACPI id /
+ */
+/* flags */
+# define ATPX_DISPLAY_OUTPUT_SUPPORTED_BY_ADAPTER_ID_DEVICE (1 << 0)
+# define ATPX_DISPLAY_HPD_SUPPORTED_BY_ADAPTER_ID_DEVICE (1 << 1)
+# define ATPX_DISPLAY_I2C_SUPPORTED_BY_ADAPTER_ID_DEVICE (1 << 2)
+#define ATPX_FUNCTION_GET_DISPLAY_DETECTION_PORTS 0x9
+/* ARG0: ATPX_FUNCTION_GET_DISPLAY_DETECTION_PORTS
+ * ARG1: none
+ * OUTPUT:
+ * WORD - number of HPD/DDC ports
+ * WORD - port structure size in bytes (excludes port size field)
+ * BYTE - ATIF display vector bit position \
+ * BYTE - hpd id } reapeated structure
+ * BYTE - ddc id /
+ *
+ * available on A+A systems only
+ */
+/* hpd id */
+# define ATPX_HPD_NONE 0
+# define ATPX_HPD1 1
+# define ATPX_HPD2 2
+# define ATPX_HPD3 3
+# define ATPX_HPD4 4
+# define ATPX_HPD5 5
+# define ATPX_HPD6 6
+/* ddc id */
+# define ATPX_DDC_NONE 0
+# define ATPX_DDC1 1
+# define ATPX_DDC2 2
+# define ATPX_DDC3 3
+# define ATPX_DDC4 4
+# define ATPX_DDC5 5
+# define ATPX_DDC6 6
+# define ATPX_DDC7 7
+# define ATPX_DDC8 8
+
+/* ATCS */
+#define ATCS_FUNCTION_VERIFY_INTERFACE 0x0
+/* ARG0: ATCS_FUNCTION_VERIFY_INTERFACE
+ * ARG1: none
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * WORD - version
+ * DWORD - supported functions bit vector
+ */
+/* supported functions vector */
+# define ATCS_GET_EXTERNAL_STATE_SUPPORTED (1 << 0)
+# define ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED (1 << 1)
+# define ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED (1 << 2)
+# define ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED (1 << 3)
+#define ATCS_FUNCTION_GET_EXTERNAL_STATE 0x1
+/* ARG0: ATCS_FUNCTION_GET_EXTERNAL_STATE
+ * ARG1: none
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * DWORD - valid flags mask
+ * DWORD - flags (0: undocked, 1: docked)
+ */
+/* flags */
+# define ATCS_DOCKED (1 << 0)
+#define ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST 0x2
+/* ARG0: ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST
+ * ARG1:
+ * WORD - structure size in bytes (includes size field)
+ * WORD - client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num)
+ * WORD - valid flags mask
+ * WORD - flags
+ * BYTE - request type
+ * BYTE - performance request
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * BYTE - return value
+ */
+/* flags */
+# define ATCS_ADVERTISE_CAPS (1 << 0)
+# define ATCS_WAIT_FOR_COMPLETION (1 << 1)
+/* request type */
+# define ATCS_PCIE_LINK_SPEED 1
+/* performance request */
+# define ATCS_REMOVE 0
+# define ATCS_FORCE_LOW_POWER 1
+# define ATCS_PERF_LEVEL_1 2 /* PCIE Gen 1 */
+# define ATCS_PERF_LEVEL_2 3 /* PCIE Gen 2 */
+# define ATCS_PERF_LEVEL_3 4 /* PCIE Gen 3 */
+/* return value */
+# define ATCS_REQUEST_REFUSED 1
+# define ATCS_REQUEST_COMPLETE 2
+# define ATCS_REQUEST_IN_PROGRESS 3
+#define ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION 0x3
+/* ARG0: ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION
+ * ARG1: none
+ * OUTPUT: none
+ */
+#define ATCS_FUNCTION_SET_PCIE_BUS_WIDTH 0x4
+/* ARG0: ATCS_FUNCTION_SET_PCIE_BUS_WIDTH
+ * ARG1:
+ * WORD - structure size in bytes (includes size field)
+ * WORD - client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num)
+ * BYTE - number of active lanes
+ * OUTPUT:
+ * WORD - structure size in bytes (includes size field)
+ * BYTE - number of active lanes
+ */
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_afmt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_afmt.c
new file mode 100644
index 000000000000..857ba0897159
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_afmt.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Christian König.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to 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: Christian König
+ */
+#include <linux/hdmi.h>
+#include <linux/gcd.h>
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+
+static const struct amdgpu_afmt_acr amdgpu_afmt_predefined_acr[] = {
+ /* 32kHz 44.1kHz 48kHz */
+ /* Clock N CTS N CTS N CTS */
+ { 25175, 4096, 25175, 28224, 125875, 6144, 25175 }, /* 25,20/1.001 MHz */
+ { 25200, 4096, 25200, 6272, 28000, 6144, 25200 }, /* 25.20 MHz */
+ { 27000, 4096, 27000, 6272, 30000, 6144, 27000 }, /* 27.00 MHz */
+ { 27027, 4096, 27027, 6272, 30030, 6144, 27027 }, /* 27.00*1.001 MHz */
+ { 54000, 4096, 54000, 6272, 60000, 6144, 54000 }, /* 54.00 MHz */
+ { 54054, 4096, 54054, 6272, 60060, 6144, 54054 }, /* 54.00*1.001 MHz */
+ { 74176, 4096, 74176, 5733, 75335, 6144, 74176 }, /* 74.25/1.001 MHz */
+ { 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */
+ { 148352, 4096, 148352, 5733, 150670, 6144, 148352 }, /* 148.50/1.001 MHz */
+ { 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */
+};
+
+
+/*
+ * calculate CTS and N values if they are not found in the table
+ */
+static void amdgpu_afmt_calc_cts(uint32_t clock, int *CTS, int *N, int freq)
+{
+ int n, cts;
+ unsigned long div, mul;
+
+ /* Safe, but overly large values */
+ n = 128 * freq;
+ cts = clock * 1000;
+
+ /* Smallest valid fraction */
+ div = gcd(n, cts);
+
+ n /= div;
+ cts /= div;
+
+ /*
+ * The optimal N is 128*freq/1000. Calculate the closest larger
+ * value that doesn't truncate any bits.
+ */
+ mul = ((128*freq/1000) + (n-1))/n;
+
+ n *= mul;
+ cts *= mul;
+
+ /* Check that we are in spec (not always possible) */
+ if (n < (128*freq/1500))
+ printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n");
+ if (n > (128*freq/300))
+ printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n");
+
+ *N = n;
+ *CTS = cts;
+
+ DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n",
+ *N, *CTS, freq);
+}
+
+struct amdgpu_afmt_acr amdgpu_afmt_acr(uint32_t clock)
+{
+ struct amdgpu_afmt_acr res;
+ u8 i;
+
+ /* Precalculated values for common clocks */
+ for (i = 0; i < ARRAY_SIZE(amdgpu_afmt_predefined_acr); i++) {
+ if (amdgpu_afmt_predefined_acr[i].clock == clock)
+ return amdgpu_afmt_predefined_acr[i];
+ }
+
+ /* And odd clocks get manually calculated */
+ amdgpu_afmt_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000);
+ amdgpu_afmt_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100);
+ amdgpu_afmt_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000);
+
+ return res;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
new file mode 100644
index 000000000000..6a588371d54a
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
@@ -0,0 +1,1598 @@
+/*
+ * Copyright 2007-8 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 shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ */
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "amdgpu_atombios.h"
+#include "amdgpu_i2c.h"
+
+#include "atom.h"
+#include "atom-bits.h"
+#include "atombios_encoders.h"
+#include "bif/bif_4_1_d.h"
+
+static void amdgpu_atombios_lookup_i2c_gpio_quirks(struct amdgpu_device *adev,
+ ATOM_GPIO_I2C_ASSIGMENT *gpio,
+ u8 index)
+{
+
+}
+
+static struct amdgpu_i2c_bus_rec amdgpu_atombios_get_bus_rec_for_i2c_gpio(ATOM_GPIO_I2C_ASSIGMENT *gpio)
+{
+ struct amdgpu_i2c_bus_rec i2c;
+
+ memset(&i2c, 0, sizeof(struct amdgpu_i2c_bus_rec));
+
+ i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex);
+ i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex);
+ i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex);
+ i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex);
+ i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex);
+ i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex);
+ i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex);
+ i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex);
+ i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);
+ i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);
+ i2c.en_clk_mask = (1 << gpio->ucClkEnShift);
+ i2c.en_data_mask = (1 << gpio->ucDataEnShift);
+ i2c.y_clk_mask = (1 << gpio->ucClkY_Shift);
+ i2c.y_data_mask = (1 << gpio->ucDataY_Shift);
+ i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);
+ i2c.a_data_mask = (1 << gpio->ucDataA_Shift);
+
+ if (gpio->sucI2cId.sbfAccess.bfHW_Capable)
+ i2c.hw_capable = true;
+ else
+ i2c.hw_capable = false;
+
+ if (gpio->sucI2cId.ucAccess == 0xa0)
+ i2c.mm_i2c = true;
+ else
+ i2c.mm_i2c = false;
+
+ i2c.i2c_id = gpio->sucI2cId.ucAccess;
+
+ if (i2c.mask_clk_reg)
+ i2c.valid = true;
+ else
+ i2c.valid = false;
+
+ return i2c;
+}
+
+struct amdgpu_i2c_bus_rec amdgpu_atombios_lookup_i2c_gpio(struct amdgpu_device *adev,
+ uint8_t id)
+{
+ struct atom_context *ctx = adev->mode_info.atom_context;
+ ATOM_GPIO_I2C_ASSIGMENT *gpio;
+ struct amdgpu_i2c_bus_rec i2c;
+ int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
+ struct _ATOM_GPIO_I2C_INFO *i2c_info;
+ uint16_t data_offset, size;
+ int i, num_indices;
+
+ memset(&i2c, 0, sizeof(struct amdgpu_i2c_bus_rec));
+ i2c.valid = false;
+
+ if (amdgpu_atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
+ i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
+
+ num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_GPIO_I2C_ASSIGMENT);
+
+ gpio = &i2c_info->asGPIO_Info[0];
+ for (i = 0; i < num_indices; i++) {
+
+ amdgpu_atombios_lookup_i2c_gpio_quirks(adev, gpio, i);
+
+ if (gpio->sucI2cId.ucAccess == id) {
+ i2c = amdgpu_atombios_get_bus_rec_for_i2c_gpio(gpio);
+ break;
+ }
+ gpio = (ATOM_GPIO_I2C_ASSIGMENT *)
+ ((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT));
+ }
+ }
+
+ return i2c;
+}
+
+void amdgpu_atombios_i2c_init(struct amdgpu_device *adev)
+{
+ struct atom_context *ctx = adev->mode_info.atom_context;
+ ATOM_GPIO_I2C_ASSIGMENT *gpio;
+ struct amdgpu_i2c_bus_rec i2c;
+ int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
+ struct _ATOM_GPIO_I2C_INFO *i2c_info;
+ uint16_t data_offset, size;
+ int i, num_indices;
+ char stmp[32];
+
+ if (amdgpu_atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
+ i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
+
+ num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_GPIO_I2C_ASSIGMENT);
+
+ gpio = &i2c_info->asGPIO_Info[0];
+ for (i = 0; i < num_indices; i++) {
+ amdgpu_atombios_lookup_i2c_gpio_quirks(adev, gpio, i);
+
+ i2c = amdgpu_atombios_get_bus_rec_for_i2c_gpio(gpio);
+
+ if (i2c.valid) {
+ sprintf(stmp, "0x%x", i2c.i2c_id);
+ adev->i2c_bus[i] = amdgpu_i2c_create(adev->ddev, &i2c, stmp);
+ }
+ gpio = (ATOM_GPIO_I2C_ASSIGMENT *)
+ ((u8 *)gpio + sizeof(ATOM_GPIO_I2C_ASSIGMENT));
+ }
+ }
+}
+
+struct amdgpu_gpio_rec
+amdgpu_atombios_lookup_gpio(struct amdgpu_device *adev,
+ u8 id)
+{
+ struct atom_context *ctx = adev->mode_info.atom_context;
+ struct amdgpu_gpio_rec gpio;
+ int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT);
+ struct _ATOM_GPIO_PIN_LUT *gpio_info;
+ ATOM_GPIO_PIN_ASSIGNMENT *pin;
+ u16 data_offset, size;
+ int i, num_indices;
+
+ memset(&gpio, 0, sizeof(struct amdgpu_gpio_rec));
+ gpio.valid = false;
+
+ if (amdgpu_atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
+ gpio_info = (struct _ATOM_GPIO_PIN_LUT *)(ctx->bios + data_offset);
+
+ num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
+
+ pin = gpio_info->asGPIO_Pin;
+ for (i = 0; i < num_indices; i++) {
+ if (id == pin->ucGPIO_ID) {
+ gpio.id = pin->ucGPIO_ID;
+ gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex);
+ gpio.shift = pin->ucGpioPinBitShift;
+ gpio.mask = (1 << pin->ucGpioPinBitShift);
+ gpio.valid = true;
+ break;
+ }
+ pin = (ATOM_GPIO_PIN_ASSIGNMENT *)
+ ((u8 *)pin + sizeof(ATOM_GPIO_PIN_ASSIGNMENT));
+ }
+ }
+
+ return gpio;
+}
+
+static struct amdgpu_hpd
+amdgpu_atombios_get_hpd_info_from_gpio(struct amdgpu_device *adev,
+ struct amdgpu_gpio_rec *gpio)
+{
+ struct amdgpu_hpd hpd;
+ u32 reg;
+
+ memset(&hpd, 0, sizeof(struct amdgpu_hpd));
+
+ reg = amdgpu_display_hpd_get_gpio_reg(adev);
+
+ hpd.gpio = *gpio;
+ if (gpio->reg == reg) {
+ switch(gpio->mask) {
+ case (1 << 0):
+ hpd.hpd = AMDGPU_HPD_1;
+ break;
+ case (1 << 8):
+ hpd.hpd = AMDGPU_HPD_2;
+ break;
+ case (1 << 16):
+ hpd.hpd = AMDGPU_HPD_3;
+ break;
+ case (1 << 24):
+ hpd.hpd = AMDGPU_HPD_4;
+ break;
+ case (1 << 26):
+ hpd.hpd = AMDGPU_HPD_5;
+ break;
+ case (1 << 28):
+ hpd.hpd = AMDGPU_HPD_6;
+ break;
+ default:
+ hpd.hpd = AMDGPU_HPD_NONE;
+ break;
+ }
+ } else
+ hpd.hpd = AMDGPU_HPD_NONE;
+ return hpd;
+}
+
+static bool amdgpu_atombios_apply_quirks(struct amdgpu_device *adev,
+ uint32_t supported_device,
+ int *connector_type,
+ struct amdgpu_i2c_bus_rec *i2c_bus,
+ uint16_t *line_mux,
+ struct amdgpu_hpd *hpd)
+{
+ return true;
+}
+
+static const int object_connector_convert[] = {
+ DRM_MODE_CONNECTOR_Unknown,
+ DRM_MODE_CONNECTOR_DVII,
+ DRM_MODE_CONNECTOR_DVII,
+ DRM_MODE_CONNECTOR_DVID,
+ DRM_MODE_CONNECTOR_DVID,
+ DRM_MODE_CONNECTOR_VGA,
+ DRM_MODE_CONNECTOR_Composite,
+ DRM_MODE_CONNECTOR_SVIDEO,
+ DRM_MODE_CONNECTOR_Unknown,
+ DRM_MODE_CONNECTOR_Unknown,
+ DRM_MODE_CONNECTOR_9PinDIN,
+ DRM_MODE_CONNECTOR_Unknown,
+ DRM_MODE_CONNECTOR_HDMIA,
+ DRM_MODE_CONNECTOR_HDMIB,
+ DRM_MODE_CONNECTOR_LVDS,
+ DRM_MODE_CONNECTOR_9PinDIN,
+ DRM_MODE_CONNECTOR_Unknown,
+ DRM_MODE_CONNECTOR_Unknown,
+ DRM_MODE_CONNECTOR_Unknown,
+ DRM_MODE_CONNECTOR_DisplayPort,
+ DRM_MODE_CONNECTOR_eDP,
+ DRM_MODE_CONNECTOR_Unknown
+};
+
+bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *adev)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ struct atom_context *ctx = mode_info->atom_context;
+ int index = GetIndexIntoMasterTable(DATA, Object_Header);
+ u16 size, data_offset;
+ u8 frev, crev;
+ ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
+ ATOM_ENCODER_OBJECT_TABLE *enc_obj;
+ ATOM_OBJECT_TABLE *router_obj;
+ ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
+ ATOM_OBJECT_HEADER *obj_header;
+ int i, j, k, path_size, device_support;
+ int connector_type;
+ u16 conn_id, connector_object_id;
+ struct amdgpu_i2c_bus_rec ddc_bus;
+ struct amdgpu_router router;
+ struct amdgpu_gpio_rec gpio;
+ struct amdgpu_hpd hpd;
+
+ if (!amdgpu_atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset))
+ return false;
+
+ if (crev < 2)
+ return false;
+
+ obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);
+ path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
+ (ctx->bios + data_offset +
+ le16_to_cpu(obj_header->usDisplayPathTableOffset));
+ con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
+ (ctx->bios + data_offset +
+ le16_to_cpu(obj_header->usConnectorObjectTableOffset));
+ enc_obj = (ATOM_ENCODER_OBJECT_TABLE *)
+ (ctx->bios + data_offset +
+ le16_to_cpu(obj_header->usEncoderObjectTableOffset));
+ router_obj = (ATOM_OBJECT_TABLE *)
+ (ctx->bios + data_offset +
+ le16_to_cpu(obj_header->usRouterObjectTableOffset));
+ device_support = le16_to_cpu(obj_header->usDeviceSupport);
+
+ path_size = 0;
+ for (i = 0; i < path_obj->ucNumOfDispPath; i++) {
+ uint8_t *addr = (uint8_t *) path_obj->asDispPath;
+ ATOM_DISPLAY_OBJECT_PATH *path;
+ addr += path_size;
+ path = (ATOM_DISPLAY_OBJECT_PATH *) addr;
+ path_size += le16_to_cpu(path->usSize);
+
+ if (device_support & le16_to_cpu(path->usDeviceTag)) {
+ uint8_t con_obj_id, con_obj_num, con_obj_type;
+
+ con_obj_id =
+ (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK)
+ >> OBJECT_ID_SHIFT;
+ con_obj_num =
+ (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK)
+ >> ENUM_ID_SHIFT;
+ con_obj_type =
+ (le16_to_cpu(path->usConnObjectId) &
+ OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
+
+ connector_type =
+ object_connector_convert[con_obj_id];
+ connector_object_id = con_obj_id;
+
+ if (connector_type == DRM_MODE_CONNECTOR_Unknown)
+ continue;
+
+ router.ddc_valid = false;
+ router.cd_valid = false;
+ for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
+ uint8_t grph_obj_id, grph_obj_num, grph_obj_type;
+
+ grph_obj_id =
+ (le16_to_cpu(path->usGraphicObjIds[j]) &
+ OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+ grph_obj_num =
+ (le16_to_cpu(path->usGraphicObjIds[j]) &
+ ENUM_ID_MASK) >> ENUM_ID_SHIFT;
+ grph_obj_type =
+ (le16_to_cpu(path->usGraphicObjIds[j]) &
+ OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
+
+ if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
+ for (k = 0; k < enc_obj->ucNumberOfObjects; k++) {
+ u16 encoder_obj = le16_to_cpu(enc_obj->asObjects[k].usObjectID);
+ if (le16_to_cpu(path->usGraphicObjIds[j]) == encoder_obj) {
+ ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
+ (ctx->bios + data_offset +
+ le16_to_cpu(enc_obj->asObjects[k].usRecordOffset));
+ ATOM_ENCODER_CAP_RECORD *cap_record;
+ u16 caps = 0;
+
+ while (record->ucRecordSize > 0 &&
+ record->ucRecordType > 0 &&
+ record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
+ switch (record->ucRecordType) {
+ case ATOM_ENCODER_CAP_RECORD_TYPE:
+ cap_record =(ATOM_ENCODER_CAP_RECORD *)
+ record;
+ caps = le16_to_cpu(cap_record->usEncoderCap);
+ break;
+ }
+ record = (ATOM_COMMON_RECORD_HEADER *)
+ ((char *)record + record->ucRecordSize);
+ }
+ amdgpu_display_add_encoder(adev, encoder_obj,
+ le16_to_cpu(path->usDeviceTag),
+ caps);
+ }
+ }
+ } else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {
+ for (k = 0; k < router_obj->ucNumberOfObjects; k++) {
+ u16 router_obj_id = le16_to_cpu(router_obj->asObjects[k].usObjectID);
+ if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {
+ ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
+ (ctx->bios + data_offset +
+ le16_to_cpu(router_obj->asObjects[k].usRecordOffset));
+ ATOM_I2C_RECORD *i2c_record;
+ ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
+ ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;
+ ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *cd_path;
+ ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =
+ (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
+ (ctx->bios + data_offset +
+ le16_to_cpu(router_obj->asObjects[k].usSrcDstTableOffset));
+ u8 *num_dst_objs = (u8 *)
+ ((u8 *)router_src_dst_table + 1 +
+ (router_src_dst_table->ucNumberOfSrc * 2));
+ u16 *dst_objs = (u16 *)(num_dst_objs + 1);
+ int enum_id;
+
+ router.router_id = router_obj_id;
+ for (enum_id = 0; enum_id < (*num_dst_objs); enum_id++) {
+ if (le16_to_cpu(path->usConnObjectId) ==
+ le16_to_cpu(dst_objs[enum_id]))
+ break;
+ }
+
+ while (record->ucRecordSize > 0 &&
+ record->ucRecordType > 0 &&
+ record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
+ switch (record->ucRecordType) {
+ case ATOM_I2C_RECORD_TYPE:
+ i2c_record =
+ (ATOM_I2C_RECORD *)
+ record;
+ i2c_config =
+ (ATOM_I2C_ID_CONFIG_ACCESS *)
+ &i2c_record->sucI2cId;
+ router.i2c_info =
+ amdgpu_atombios_lookup_i2c_gpio(adev,
+ i2c_config->
+ ucAccess);
+ router.i2c_addr = i2c_record->ucI2CAddr >> 1;
+ break;
+ case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
+ ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
+ record;
+ router.ddc_valid = true;
+ router.ddc_mux_type = ddc_path->ucMuxType;
+ router.ddc_mux_control_pin = ddc_path->ucMuxControlPin;
+ router.ddc_mux_state = ddc_path->ucMuxState[enum_id];
+ break;
+ case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE:
+ cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)
+ record;
+ router.cd_valid = true;
+ router.cd_mux_type = cd_path->ucMuxType;
+ router.cd_mux_control_pin = cd_path->ucMuxControlPin;
+ router.cd_mux_state = cd_path->ucMuxState[enum_id];
+ break;
+ }
+ record = (ATOM_COMMON_RECORD_HEADER *)
+ ((char *)record + record->ucRecordSize);
+ }
+ }
+ }
+ }
+ }
+
+ /* look up gpio for ddc, hpd */
+ ddc_bus.valid = false;
+ hpd.hpd = AMDGPU_HPD_NONE;
+ if ((le16_to_cpu(path->usDeviceTag) &
+ (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) {
+ for (j = 0; j < con_obj->ucNumberOfObjects; j++) {
+ if (le16_to_cpu(path->usConnObjectId) ==
+ le16_to_cpu(con_obj->asObjects[j].
+ usObjectID)) {
+ ATOM_COMMON_RECORD_HEADER
+ *record =
+ (ATOM_COMMON_RECORD_HEADER
+ *)
+ (ctx->bios + data_offset +
+ le16_to_cpu(con_obj->
+ asObjects[j].
+ usRecordOffset));
+ ATOM_I2C_RECORD *i2c_record;
+ ATOM_HPD_INT_RECORD *hpd_record;
+ ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
+
+ while (record->ucRecordSize > 0 &&
+ record->ucRecordType > 0 &&
+ record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
+ switch (record->ucRecordType) {
+ case ATOM_I2C_RECORD_TYPE:
+ i2c_record =
+ (ATOM_I2C_RECORD *)
+ record;
+ i2c_config =
+ (ATOM_I2C_ID_CONFIG_ACCESS *)
+ &i2c_record->sucI2cId;
+ ddc_bus = amdgpu_atombios_lookup_i2c_gpio(adev,
+ i2c_config->
+ ucAccess);
+ break;
+ case ATOM_HPD_INT_RECORD_TYPE:
+ hpd_record =
+ (ATOM_HPD_INT_RECORD *)
+ record;
+ gpio = amdgpu_atombios_lookup_gpio(adev,
+ hpd_record->ucHPDIntGPIOID);
+ hpd = amdgpu_atombios_get_hpd_info_from_gpio(adev, &gpio);
+ hpd.plugged_state = hpd_record->ucPlugged_PinState;
+ break;
+ }
+ record =
+ (ATOM_COMMON_RECORD_HEADER
+ *) ((char *)record
+ +
+ record->
+ ucRecordSize);
+ }
+ break;
+ }
+ }
+ }
+
+ /* needed for aux chan transactions */
+ ddc_bus.hpd = hpd.hpd;
+
+ conn_id = le16_to_cpu(path->usConnObjectId);
+
+ if (!amdgpu_atombios_apply_quirks
+ (adev, le16_to_cpu(path->usDeviceTag), &connector_type,
+ &ddc_bus, &conn_id, &hpd))
+ continue;
+
+ amdgpu_display_add_connector(adev,
+ conn_id,
+ le16_to_cpu(path->usDeviceTag),
+ connector_type, &ddc_bus,
+ connector_object_id,
+ &hpd,
+ &router);
+
+ }
+ }
+
+ amdgpu_link_encoder_connector(adev->ddev);
+
+ return true;
+}
+
+union firmware_info {
+ ATOM_FIRMWARE_INFO info;
+ ATOM_FIRMWARE_INFO_V1_2 info_12;
+ ATOM_FIRMWARE_INFO_V1_3 info_13;
+ ATOM_FIRMWARE_INFO_V1_4 info_14;
+ ATOM_FIRMWARE_INFO_V2_1 info_21;
+ ATOM_FIRMWARE_INFO_V2_2 info_22;
+};
+
+int amdgpu_atombios_get_clock_info(struct amdgpu_device *adev)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+ uint8_t frev, crev;
+ uint16_t data_offset;
+ int ret = -EINVAL;
+
+ if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset)) {
+ int i;
+ struct amdgpu_pll *ppll = &adev->clock.ppll[0];
+ struct amdgpu_pll *spll = &adev->clock.spll;
+ struct amdgpu_pll *mpll = &adev->clock.mpll;
+ union firmware_info *firmware_info =
+ (union firmware_info *)(mode_info->atom_context->bios +
+ data_offset);
+ /* pixel clocks */
+ ppll->reference_freq =
+ le16_to_cpu(firmware_info->info.usReferenceClock);
+ ppll->reference_div = 0;
+
+ if (crev < 2)
+ ppll->pll_out_min =
+ le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
+ else
+ ppll->pll_out_min =
+ le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output);
+ ppll->pll_out_max =
+ le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
+
+ if (crev >= 4) {
+ ppll->lcd_pll_out_min =
+ le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
+ if (ppll->lcd_pll_out_min == 0)
+ ppll->lcd_pll_out_min = ppll->pll_out_min;
+ ppll->lcd_pll_out_max =
+ le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100;
+ if (ppll->lcd_pll_out_max == 0)
+ ppll->lcd_pll_out_max = ppll->pll_out_max;
+ } else {
+ ppll->lcd_pll_out_min = ppll->pll_out_min;
+ ppll->lcd_pll_out_max = ppll->pll_out_max;
+ }
+
+ if (ppll->pll_out_min == 0)
+ ppll->pll_out_min = 64800;
+
+ ppll->pll_in_min =
+ le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input);
+ ppll->pll_in_max =
+ le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input);
+
+ ppll->min_post_div = 2;
+ ppll->max_post_div = 0x7f;
+ ppll->min_frac_feedback_div = 0;
+ ppll->max_frac_feedback_div = 9;
+ ppll->min_ref_div = 2;
+ ppll->max_ref_div = 0x3ff;
+ ppll->min_feedback_div = 4;
+ ppll->max_feedback_div = 0xfff;
+ ppll->best_vco = 0;
+
+ for (i = 1; i < AMDGPU_MAX_PPLL; i++)
+ adev->clock.ppll[i] = *ppll;
+
+ /* system clock */
+ spll->reference_freq =
+ le16_to_cpu(firmware_info->info_21.usCoreReferenceClock);
+ spll->reference_div = 0;
+
+ spll->pll_out_min =
+ le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Output);
+ spll->pll_out_max =
+ le32_to_cpu(firmware_info->info.ulMaxEngineClockPLL_Output);
+
+ /* ??? */
+ if (spll->pll_out_min == 0)
+ spll->pll_out_min = 64800;
+
+ spll->pll_in_min =
+ le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Input);
+ spll->pll_in_max =
+ le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input);
+
+ spll->min_post_div = 1;
+ spll->max_post_div = 1;
+ spll->min_ref_div = 2;
+ spll->max_ref_div = 0xff;
+ spll->min_feedback_div = 4;
+ spll->max_feedback_div = 0xff;
+ spll->best_vco = 0;
+
+ /* memory clock */
+ mpll->reference_freq =
+ le16_to_cpu(firmware_info->info_21.usMemoryReferenceClock);
+ mpll->reference_div = 0;
+
+ mpll->pll_out_min =
+ le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Output);
+ mpll->pll_out_max =
+ le32_to_cpu(firmware_info->info.ulMaxMemoryClockPLL_Output);
+
+ /* ??? */
+ if (mpll->pll_out_min == 0)
+ mpll->pll_out_min = 64800;
+
+ mpll->pll_in_min =
+ le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Input);
+ mpll->pll_in_max =
+ le16_to_cpu(firmware_info->info.usMaxMemoryClockPLL_Input);
+
+ adev->clock.default_sclk =
+ le32_to_cpu(firmware_info->info.ulDefaultEngineClock);
+ adev->clock.default_mclk =
+ le32_to_cpu(firmware_info->info.ulDefaultMemoryClock);
+
+ mpll->min_post_div = 1;
+ mpll->max_post_div = 1;
+ mpll->min_ref_div = 2;
+ mpll->max_ref_div = 0xff;
+ mpll->min_feedback_div = 4;
+ mpll->max_feedback_div = 0xff;
+ mpll->best_vco = 0;
+
+ /* disp clock */
+ adev->clock.default_dispclk =
+ le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq);
+ if (adev->clock.default_dispclk == 0)
+ adev->clock.default_dispclk = 54000; /* 540 Mhz */
+ adev->clock.dp_extclk =
+ le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq);
+ adev->clock.current_dispclk = adev->clock.default_dispclk;
+
+ adev->clock.max_pixel_clock = le16_to_cpu(firmware_info->info.usMaxPixelClock);
+ if (adev->clock.max_pixel_clock == 0)
+ adev->clock.max_pixel_clock = 40000;
+
+ /* not technically a clock, but... */
+ adev->mode_info.firmware_flags =
+ le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess);
+
+ ret = 0;
+ }
+
+ adev->pm.current_sclk = adev->clock.default_sclk;
+ adev->pm.current_mclk = adev->clock.default_mclk;
+
+ return ret;
+}
+
+union igp_info {
+ struct _ATOM_INTEGRATED_SYSTEM_INFO info;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_9 info_9;
+};
+
+static void amdgpu_atombios_get_igp_ss_overrides(struct amdgpu_device *adev,
+ struct amdgpu_atom_ss *ss,
+ int id)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
+ u16 data_offset, size;
+ union igp_info *igp_info;
+ u8 frev, crev;
+ u16 percentage = 0, rate = 0;
+
+ /* get any igp specific overrides */
+ if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ igp_info = (union igp_info *)
+ (mode_info->atom_context->bios + data_offset);
+ switch (crev) {
+ case 6:
+ switch (id) {
+ case ASIC_INTERNAL_SS_ON_TMDS:
+ percentage = le16_to_cpu(igp_info->info_6.usDVISSPercentage);
+ rate = le16_to_cpu(igp_info->info_6.usDVISSpreadRateIn10Hz);
+ break;
+ case ASIC_INTERNAL_SS_ON_HDMI:
+ percentage = le16_to_cpu(igp_info->info_6.usHDMISSPercentage);
+ rate = le16_to_cpu(igp_info->info_6.usHDMISSpreadRateIn10Hz);
+ break;
+ case ASIC_INTERNAL_SS_ON_LVDS:
+ percentage = le16_to_cpu(igp_info->info_6.usLvdsSSPercentage);
+ rate = le16_to_cpu(igp_info->info_6.usLvdsSSpreadRateIn10Hz);
+ break;
+ }
+ break;
+ case 7:
+ switch (id) {
+ case ASIC_INTERNAL_SS_ON_TMDS:
+ percentage = le16_to_cpu(igp_info->info_7.usDVISSPercentage);
+ rate = le16_to_cpu(igp_info->info_7.usDVISSpreadRateIn10Hz);
+ break;
+ case ASIC_INTERNAL_SS_ON_HDMI:
+ percentage = le16_to_cpu(igp_info->info_7.usHDMISSPercentage);
+ rate = le16_to_cpu(igp_info->info_7.usHDMISSpreadRateIn10Hz);
+ break;
+ case ASIC_INTERNAL_SS_ON_LVDS:
+ percentage = le16_to_cpu(igp_info->info_7.usLvdsSSPercentage);
+ rate = le16_to_cpu(igp_info->info_7.usLvdsSSpreadRateIn10Hz);
+ break;
+ }
+ break;
+ case 8:
+ switch (id) {
+ case ASIC_INTERNAL_SS_ON_TMDS:
+ percentage = le16_to_cpu(igp_info->info_8.usDVISSPercentage);
+ rate = le16_to_cpu(igp_info->info_8.usDVISSpreadRateIn10Hz);
+ break;
+ case ASIC_INTERNAL_SS_ON_HDMI:
+ percentage = le16_to_cpu(igp_info->info_8.usHDMISSPercentage);
+ rate = le16_to_cpu(igp_info->info_8.usHDMISSpreadRateIn10Hz);
+ break;
+ case ASIC_INTERNAL_SS_ON_LVDS:
+ percentage = le16_to_cpu(igp_info->info_8.usLvdsSSPercentage);
+ rate = le16_to_cpu(igp_info->info_8.usLvdsSSpreadRateIn10Hz);
+ break;
+ }
+ break;
+ case 9:
+ switch (id) {
+ case ASIC_INTERNAL_SS_ON_TMDS:
+ percentage = le16_to_cpu(igp_info->info_9.usDVISSPercentage);
+ rate = le16_to_cpu(igp_info->info_9.usDVISSpreadRateIn10Hz);
+ break;
+ case ASIC_INTERNAL_SS_ON_HDMI:
+ percentage = le16_to_cpu(igp_info->info_9.usHDMISSPercentage);
+ rate = le16_to_cpu(igp_info->info_9.usHDMISSpreadRateIn10Hz);
+ break;
+ case ASIC_INTERNAL_SS_ON_LVDS:
+ percentage = le16_to_cpu(igp_info->info_9.usLvdsSSPercentage);
+ rate = le16_to_cpu(igp_info->info_9.usLvdsSSpreadRateIn10Hz);
+ break;
+ }
+ break;
+ default:
+ DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
+ break;
+ }
+ if (percentage)
+ ss->percentage = percentage;
+ if (rate)
+ ss->rate = rate;
+ }
+}
+
+union asic_ss_info {
+ struct _ATOM_ASIC_INTERNAL_SS_INFO info;
+ struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2;
+ struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3;
+};
+
+union asic_ss_assignment {
+ struct _ATOM_ASIC_SS_ASSIGNMENT v1;
+ struct _ATOM_ASIC_SS_ASSIGNMENT_V2 v2;
+ struct _ATOM_ASIC_SS_ASSIGNMENT_V3 v3;
+};
+
+bool amdgpu_atombios_get_asic_ss_info(struct amdgpu_device *adev,
+ struct amdgpu_atom_ss *ss,
+ int id, u32 clock)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+ uint16_t data_offset, size;
+ union asic_ss_info *ss_info;
+ union asic_ss_assignment *ss_assign;
+ uint8_t frev, crev;
+ int i, num_indices;
+
+ if (id == ASIC_INTERNAL_MEMORY_SS) {
+ if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT))
+ return false;
+ }
+ if (id == ASIC_INTERNAL_ENGINE_SS) {
+ if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT))
+ return false;
+ }
+
+ memset(ss, 0, sizeof(struct amdgpu_atom_ss));
+ if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+
+ ss_info =
+ (union asic_ss_info *)(mode_info->atom_context->bios + data_offset);
+
+ switch (frev) {
+ case 1:
+ num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_ASIC_SS_ASSIGNMENT);
+
+ ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info.asSpreadSpectrum[0]);
+ for (i = 0; i < num_indices; i++) {
+ if ((ss_assign->v1.ucClockIndication == id) &&
+ (clock <= le32_to_cpu(ss_assign->v1.ulTargetClockRange))) {
+ ss->percentage =
+ le16_to_cpu(ss_assign->v1.usSpreadSpectrumPercentage);
+ ss->type = ss_assign->v1.ucSpreadSpectrumMode;
+ ss->rate = le16_to_cpu(ss_assign->v1.usSpreadRateInKhz);
+ ss->percentage_divider = 100;
+ return true;
+ }
+ ss_assign = (union asic_ss_assignment *)
+ ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT));
+ }
+ break;
+ case 2:
+ num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
+ ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_2.asSpreadSpectrum[0]);
+ for (i = 0; i < num_indices; i++) {
+ if ((ss_assign->v2.ucClockIndication == id) &&
+ (clock <= le32_to_cpu(ss_assign->v2.ulTargetClockRange))) {
+ ss->percentage =
+ le16_to_cpu(ss_assign->v2.usSpreadSpectrumPercentage);
+ ss->type = ss_assign->v2.ucSpreadSpectrumMode;
+ ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz);
+ ss->percentage_divider = 100;
+ if ((crev == 2) &&
+ ((id == ASIC_INTERNAL_ENGINE_SS) ||
+ (id == ASIC_INTERNAL_MEMORY_SS)))
+ ss->rate /= 100;
+ return true;
+ }
+ ss_assign = (union asic_ss_assignment *)
+ ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2));
+ }
+ break;
+ case 3:
+ num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
+ ss_assign = (union asic_ss_assignment *)((u8 *)&ss_info->info_3.asSpreadSpectrum[0]);
+ for (i = 0; i < num_indices; i++) {
+ if ((ss_assign->v3.ucClockIndication == id) &&
+ (clock <= le32_to_cpu(ss_assign->v3.ulTargetClockRange))) {
+ ss->percentage =
+ le16_to_cpu(ss_assign->v3.usSpreadSpectrumPercentage);
+ ss->type = ss_assign->v3.ucSpreadSpectrumMode;
+ ss->rate = le16_to_cpu(ss_assign->v3.usSpreadRateIn10Hz);
+ if (ss_assign->v3.ucSpreadSpectrumMode &
+ SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK)
+ ss->percentage_divider = 1000;
+ else
+ ss->percentage_divider = 100;
+ if ((id == ASIC_INTERNAL_ENGINE_SS) ||
+ (id == ASIC_INTERNAL_MEMORY_SS))
+ ss->rate /= 100;
+ if (adev->flags & AMDGPU_IS_APU)
+ amdgpu_atombios_get_igp_ss_overrides(adev, ss, id);
+ return true;
+ }
+ ss_assign = (union asic_ss_assignment *)
+ ((u8 *)ss_assign + sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3));
+ }
+ break;
+ default:
+ DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev);
+ break;
+ }
+
+ }
+ return false;
+}
+
+union get_clock_dividers {
+ struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS v1;
+ struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 v2;
+ struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3;
+ struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4;
+ struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5;
+ struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6 v6_in;
+ struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 v6_out;
+};
+
+int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
+ u8 clock_type,
+ u32 clock,
+ bool strobe_mode,
+ struct atom_clock_dividers *dividers)
+{
+ union get_clock_dividers args;
+ int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL);
+ u8 frev, crev;
+
+ memset(&args, 0, sizeof(args));
+ memset(dividers, 0, sizeof(struct atom_clock_dividers));
+
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
+ return -EINVAL;
+
+ switch (crev) {
+ case 4:
+ /* fusion */
+ args.v4.ulClock = cpu_to_le32(clock); /* 10 khz */
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ dividers->post_divider = dividers->post_div = args.v4.ucPostDiv;
+ dividers->real_clock = le32_to_cpu(args.v4.ulClock);
+ break;
+ case 6:
+ /* CI */
+ /* COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK, COMPUTE_GPUCLK_INPUT_FLAG_SCLK */
+ args.v6_in.ulClock.ulComputeClockFlag = clock_type;
+ args.v6_in.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ dividers->whole_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDiv);
+ dividers->frac_fb_div = le16_to_cpu(args.v6_out.ulFbDiv.usFbDivFrac);
+ dividers->ref_div = args.v6_out.ucPllRefDiv;
+ dividers->post_div = args.v6_out.ucPllPostDiv;
+ dividers->flags = args.v6_out.ucPllCntlFlag;
+ dividers->real_clock = le32_to_cpu(args.v6_out.ulClock.ulClock);
+ dividers->post_divider = args.v6_out.ulClock.ucPostDiv;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int amdgpu_atombios_get_memory_pll_dividers(struct amdgpu_device *adev,
+ u32 clock,
+ bool strobe_mode,
+ struct atom_mpll_param *mpll_param)
+{
+ COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 args;
+ int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam);
+ u8 frev, crev;
+
+ memset(&args, 0, sizeof(args));
+ memset(mpll_param, 0, sizeof(struct atom_mpll_param));
+
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
+ return -EINVAL;
+
+ switch (frev) {
+ case 2:
+ switch (crev) {
+ case 1:
+ /* SI */
+ args.ulClock = cpu_to_le32(clock); /* 10 khz */
+ args.ucInputFlag = 0;
+ if (strobe_mode)
+ args.ucInputFlag |= MPLL_INPUT_FLAG_STROBE_MODE_EN;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ mpll_param->clkfrac = le16_to_cpu(args.ulFbDiv.usFbDivFrac);
+ mpll_param->clkf = le16_to_cpu(args.ulFbDiv.usFbDiv);
+ mpll_param->post_div = args.ucPostDiv;
+ mpll_param->dll_speed = args.ucDllSpeed;
+ mpll_param->bwcntl = args.ucBWCntl;
+ mpll_param->vco_mode =
+ (args.ucPllCntlFlag & MPLL_CNTL_FLAG_VCO_MODE_MASK);
+ mpll_param->yclk_sel =
+ (args.ucPllCntlFlag & MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0;
+ mpll_param->qdr =
+ (args.ucPllCntlFlag & MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0;
+ mpll_param->half_rate =
+ (args.ucPllCntlFlag & MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+uint32_t amdgpu_atombios_get_engine_clock(struct amdgpu_device *adev)
+{
+ GET_ENGINE_CLOCK_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, GetEngineClock);
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+ return le32_to_cpu(args.ulReturnEngineClock);
+}
+
+uint32_t amdgpu_atombios_get_memory_clock(struct amdgpu_device *adev)
+{
+ GET_MEMORY_CLOCK_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, GetMemoryClock);
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+ return le32_to_cpu(args.ulReturnMemoryClock);
+}
+
+void amdgpu_atombios_set_engine_clock(struct amdgpu_device *adev,
+ uint32_t eng_clock)
+{
+ SET_ENGINE_CLOCK_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, SetEngineClock);
+
+ args.ulTargetEngineClock = cpu_to_le32(eng_clock); /* 10 khz */
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void amdgpu_atombios_set_memory_clock(struct amdgpu_device *adev,
+ uint32_t mem_clock)
+{
+ SET_MEMORY_CLOCK_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock);
+
+ if (adev->flags & AMDGPU_IS_APU)
+ return;
+
+ args.ulTargetMemoryClock = cpu_to_le32(mem_clock); /* 10 khz */
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev,
+ u32 eng_clock, u32 mem_clock)
+{
+ SET_ENGINE_CLOCK_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
+ u32 tmp;
+
+ memset(&args, 0, sizeof(args));
+
+ tmp = eng_clock & SET_CLOCK_FREQ_MASK;
+ tmp |= (COMPUTE_ENGINE_PLL_PARAM << 24);
+
+ args.ulTargetEngineClock = cpu_to_le32(tmp);
+ if (mem_clock)
+ args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK);
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+union set_voltage {
+ struct _SET_VOLTAGE_PS_ALLOCATION alloc;
+ struct _SET_VOLTAGE_PARAMETERS v1;
+ struct _SET_VOLTAGE_PARAMETERS_V2 v2;
+ struct _SET_VOLTAGE_PARAMETERS_V1_3 v3;
+};
+
+void amdgpu_atombios_set_voltage(struct amdgpu_device *adev,
+ u16 voltage_level,
+ u8 voltage_type)
+{
+ union set_voltage args;
+ int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
+ u8 frev, crev, volt_index = voltage_level;
+
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
+ return;
+
+ /* 0xff01 is a flag rather then an actual voltage */
+ if (voltage_level == 0xff01)
+ return;
+
+ switch (crev) {
+ case 1:
+ args.v1.ucVoltageType = voltage_type;
+ args.v1.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_ALL_SOURCE;
+ args.v1.ucVoltageIndex = volt_index;
+ break;
+ case 2:
+ args.v2.ucVoltageType = voltage_type;
+ args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE;
+ args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
+ break;
+ case 3:
+ args.v3.ucVoltageType = voltage_type;
+ args.v3.ucVoltageMode = ATOM_SET_VOLTAGE;
+ args.v3.usVoltageLevel = cpu_to_le16(voltage_level);
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ return;
+ }
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+int amdgpu_atombios_get_leakage_id_from_vbios(struct amdgpu_device *adev,
+ u16 *leakage_id)
+{
+ union set_voltage args;
+ int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
+ u8 frev, crev;
+
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
+ return -EINVAL;
+
+ switch (crev) {
+ case 3:
+ case 4:
+ args.v3.ucVoltageType = 0;
+ args.v3.ucVoltageMode = ATOM_GET_LEAKAGE_ID;
+ args.v3.usVoltageLevel = 0;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ *leakage_id = le16_to_cpu(args.v3.usVoltageLevel);
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int amdgpu_atombios_get_leakage_vddc_based_on_leakage_params(struct amdgpu_device *adev,
+ u16 *vddc, u16 *vddci,
+ u16 virtual_voltage_id,
+ u16 vbios_voltage_id)
+{
+ int index = GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo);
+ u8 frev, crev;
+ u16 data_offset, size;
+ int i, j;
+ ATOM_ASIC_PROFILING_INFO_V2_1 *profile;
+ u16 *leakage_bin, *vddc_id_buf, *vddc_buf, *vddci_id_buf, *vddci_buf;
+
+ *vddc = 0;
+ *vddci = 0;
+
+ if (!amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset))
+ return -EINVAL;
+
+ profile = (ATOM_ASIC_PROFILING_INFO_V2_1 *)
+ (adev->mode_info.atom_context->bios + data_offset);
+
+ switch (frev) {
+ case 1:
+ return -EINVAL;
+ case 2:
+ switch (crev) {
+ case 1:
+ if (size < sizeof(ATOM_ASIC_PROFILING_INFO_V2_1))
+ return -EINVAL;
+ leakage_bin = (u16 *)
+ (adev->mode_info.atom_context->bios + data_offset +
+ le16_to_cpu(profile->usLeakageBinArrayOffset));
+ vddc_id_buf = (u16 *)
+ (adev->mode_info.atom_context->bios + data_offset +
+ le16_to_cpu(profile->usElbVDDC_IdArrayOffset));
+ vddc_buf = (u16 *)
+ (adev->mode_info.atom_context->bios + data_offset +
+ le16_to_cpu(profile->usElbVDDC_LevelArrayOffset));
+ vddci_id_buf = (u16 *)
+ (adev->mode_info.atom_context->bios + data_offset +
+ le16_to_cpu(profile->usElbVDDCI_IdArrayOffset));
+ vddci_buf = (u16 *)
+ (adev->mode_info.atom_context->bios + data_offset +
+ le16_to_cpu(profile->usElbVDDCI_LevelArrayOffset));
+
+ if (profile->ucElbVDDC_Num > 0) {
+ for (i = 0; i < profile->ucElbVDDC_Num; i++) {
+ if (vddc_id_buf[i] == virtual_voltage_id) {
+ for (j = 0; j < profile->ucLeakageBinNum; j++) {
+ if (vbios_voltage_id <= leakage_bin[j]) {
+ *vddc = vddc_buf[j * profile->ucElbVDDC_Num + i];
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ if (profile->ucElbVDDCI_Num > 0) {
+ for (i = 0; i < profile->ucElbVDDCI_Num; i++) {
+ if (vddci_id_buf[i] == virtual_voltage_id) {
+ for (j = 0; j < profile->ucLeakageBinNum; j++) {
+ if (vbios_voltage_id <= leakage_bin[j]) {
+ *vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i];
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+union get_voltage_info {
+ struct _GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 in;
+ struct _GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 evv_out;
+};
+
+int amdgpu_atombios_get_voltage_evv(struct amdgpu_device *adev,
+ u16 virtual_voltage_id,
+ u16 *voltage)
+{
+ int index = GetIndexIntoMasterTable(COMMAND, GetVoltageInfo);
+ u32 entry_id;
+ u32 count = adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count;
+ union get_voltage_info args;
+
+ for (entry_id = 0; entry_id < count; entry_id++) {
+ if (adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].v ==
+ virtual_voltage_id)
+ break;
+ }
+
+ if (entry_id >= count)
+ return -EINVAL;
+
+ args.in.ucVoltageType = VOLTAGE_TYPE_VDDC;
+ args.in.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE;
+ args.in.usVoltageLevel = cpu_to_le16(virtual_voltage_id);
+ args.in.ulSCLKFreq =
+ cpu_to_le32(adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].clk);
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ *voltage = le16_to_cpu(args.evv_out.usVoltageLevel);
+
+ return 0;
+}
+
+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;
+};
+
+union voltage_object {
+ struct _ATOM_VOLTAGE_OBJECT v1;
+ struct _ATOM_VOLTAGE_OBJECT_V2 v2;
+ union _ATOM_VOLTAGE_OBJECT_V3 v3;
+};
+
+
+static ATOM_VOLTAGE_OBJECT_V3 *amdgpu_atombios_lookup_voltage_object_v3(ATOM_VOLTAGE_OBJECT_INFO_V3_1 *v3,
+ u8 voltage_type, u8 voltage_mode)
+{
+ u32 size = le16_to_cpu(v3->sHeader.usStructureSize);
+ u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);
+ u8 *start = (u8*)v3;
+
+ while (offset < size) {
+ ATOM_VOLTAGE_OBJECT_V3 *vo = (ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
+ if ((vo->asGpioVoltageObj.sHeader.ucVoltageType == voltage_type) &&
+ (vo->asGpioVoltageObj.sHeader.ucVoltageMode == voltage_mode))
+ return vo;
+ offset += le16_to_cpu(vo->asGpioVoltageObj.sHeader.usSize);
+ }
+ return NULL;
+}
+
+bool
+amdgpu_atombios_is_voltage_gpio(struct amdgpu_device *adev,
+ u8 voltage_type, u8 voltage_mode)
+{
+ int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+ u8 frev, crev;
+ u16 data_offset, size;
+ union voltage_object_info *voltage_info;
+
+ if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ voltage_info = (union voltage_object_info *)
+ (adev->mode_info.atom_context->bios + data_offset);
+
+ switch (frev) {
+ case 3:
+ switch (crev) {
+ case 1:
+ if (amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3,
+ voltage_type, voltage_mode))
+ return true;
+ break;
+ default:
+ DRM_ERROR("unknown voltage object table\n");
+ return false;
+ }
+ break;
+ default:
+ DRM_ERROR("unknown voltage object table\n");
+ return false;
+ }
+
+ }
+ return false;
+}
+
+int amdgpu_atombios_get_voltage_table(struct amdgpu_device *adev,
+ u8 voltage_type, u8 voltage_mode,
+ struct atom_voltage_table *voltage_table)
+{
+ int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+ u8 frev, crev;
+ u16 data_offset, size;
+ int i;
+ union voltage_object_info *voltage_info;
+ union voltage_object *voltage_object = NULL;
+
+ if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ voltage_info = (union voltage_object_info *)
+ (adev->mode_info.atom_context->bios + data_offset);
+
+ switch (frev) {
+ case 3:
+ switch (crev) {
+ case 1:
+ voltage_object = (union voltage_object *)
+ amdgpu_atombios_lookup_voltage_object_v3(&voltage_info->v3,
+ voltage_type, voltage_mode);
+ if (voltage_object) {
+ ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio =
+ &voltage_object->v3.asGpioVoltageObj;
+ VOLTAGE_LUT_ENTRY_V2 *lut;
+ if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES)
+ return -EINVAL;
+ lut = &gpio->asVolGpioLut[0];
+ for (i = 0; i < gpio->ucGpioEntryNum; i++) {
+ voltage_table->entries[i].value =
+ le16_to_cpu(lut->usVoltageValue);
+ voltage_table->entries[i].smio_low =
+ le32_to_cpu(lut->ulVoltageId);
+ lut = (VOLTAGE_LUT_ENTRY_V2 *)
+ ((u8 *)lut + sizeof(VOLTAGE_LUT_ENTRY_V2));
+ }
+ voltage_table->mask_low = le32_to_cpu(gpio->ulGpioMaskVal);
+ voltage_table->count = gpio->ucGpioEntryNum;
+ voltage_table->phase_delay = gpio->ucPhaseDelay;
+ return 0;
+ }
+ break;
+ default:
+ DRM_ERROR("unknown voltage object table\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ DRM_ERROR("unknown voltage object table\n");
+ return -EINVAL;
+ }
+ }
+ return -EINVAL;
+}
+
+union vram_info {
+ struct _ATOM_VRAM_INFO_V3 v1_3;
+ struct _ATOM_VRAM_INFO_V4 v1_4;
+ struct _ATOM_VRAM_INFO_HEADER_V2_1 v2_1;
+};
+
+#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
+
+int amdgpu_atombios_init_mc_reg_table(struct amdgpu_device *adev,
+ u8 module_index,
+ struct atom_mc_reg_table *reg_table)
+{
+ int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
+ u8 frev, crev, num_entries, t_mem_id, num_ranges = 0;
+ u32 i = 0, j;
+ u16 data_offset, size;
+ union vram_info *vram_info;
+
+ memset(reg_table, 0, sizeof(struct atom_mc_reg_table));
+
+ if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ vram_info = (union vram_info *)
+ (adev->mode_info.atom_context->bios + data_offset);
+ switch (frev) {
+ case 1:
+ DRM_ERROR("old table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ case 2:
+ switch (crev) {
+ case 1:
+ if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {
+ ATOM_INIT_REG_BLOCK *reg_block =
+ (ATOM_INIT_REG_BLOCK *)
+ ((u8 *)vram_info + le16_to_cpu(vram_info->v2_1.usMemClkPatchTblOffset));
+ ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data =
+ (ATOM_MEMORY_SETTING_DATA_BLOCK *)
+ ((u8 *)reg_block + (2 * sizeof(u16)) +
+ le16_to_cpu(reg_block->usRegIndexTblSize));
+ ATOM_INIT_REG_INDEX_FORMAT *format = &reg_block->asRegIndexBuf[0];
+ num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) /
+ sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1;
+ if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ while (i < num_entries) {
+ if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER)
+ break;
+ reg_table->mc_reg_address[i].s1 =
+ (u16)(le16_to_cpu(format->usRegIndex));
+ reg_table->mc_reg_address[i].pre_reg_data =
+ (u8)(format->ucPreRegDataLength);
+ i++;
+ format = (ATOM_INIT_REG_INDEX_FORMAT *)
+ ((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));
+ }
+ reg_table->last = i;
+ while ((le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) &&
+ (num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) {
+ t_mem_id = (u8)((le32_to_cpu(*(u32 *)reg_data) & MEM_ID_MASK)
+ >> MEM_ID_SHIFT);
+ if (module_index == t_mem_id) {
+ reg_table->mc_reg_table_entry[num_ranges].mclk_max =
+ (u32)((le32_to_cpu(*(u32 *)reg_data) & CLOCK_RANGE_MASK)
+ >> CLOCK_RANGE_SHIFT);
+ for (i = 0, j = 1; i < reg_table->last; i++) {
+ if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
+ reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
+ (u32)le32_to_cpu(*((u32 *)reg_data + j));
+ j++;
+ } else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
+ reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
+ reg_table->mc_reg_table_entry[num_ranges].mc_data[i - 1];
+ }
+ }
+ num_ranges++;
+ }
+ reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
+ ((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize));
+ }
+ if (le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK)
+ return -EINVAL;
+ reg_table->num_entries = num_ranges;
+ } else
+ return -EINVAL;
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ }
+ return 0;
+ }
+ return -EINVAL;
+}
+
+void amdgpu_atombios_scratch_regs_lock(struct amdgpu_device *adev, bool lock)
+{
+ uint32_t bios_6_scratch;
+
+ bios_6_scratch = RREG32(mmBIOS_SCRATCH_6);
+
+ if (lock) {
+ bios_6_scratch |= ATOM_S6_CRITICAL_STATE;
+ bios_6_scratch &= ~ATOM_S6_ACC_MODE;
+ } else {
+ bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE;
+ bios_6_scratch |= ATOM_S6_ACC_MODE;
+ }
+
+ WREG32(mmBIOS_SCRATCH_6, bios_6_scratch);
+}
+
+void amdgpu_atombios_scratch_regs_init(struct amdgpu_device *adev)
+{
+ uint32_t bios_2_scratch, bios_6_scratch;
+
+ bios_2_scratch = RREG32(mmBIOS_SCRATCH_2);
+ bios_6_scratch = RREG32(mmBIOS_SCRATCH_6);
+
+ /* let the bios control the backlight */
+ bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE;
+
+ /* tell the bios not to handle mode switching */
+ bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;
+
+ /* clear the vbios dpms state */
+ bios_2_scratch &= ~ATOM_S2_DEVICE_DPMS_STATE;
+
+ WREG32(mmBIOS_SCRATCH_2, bios_2_scratch);
+ WREG32(mmBIOS_SCRATCH_6, bios_6_scratch);
+}
+
+void amdgpu_atombios_scratch_regs_save(struct amdgpu_device *adev)
+{
+ int i;
+
+ for (i = 0; i < AMDGPU_BIOS_NUM_SCRATCH; i++)
+ adev->bios_scratch[i] = RREG32(mmBIOS_SCRATCH_0 + i);
+}
+
+void amdgpu_atombios_scratch_regs_restore(struct amdgpu_device *adev)
+{
+ int i;
+
+ for (i = 0; i < AMDGPU_BIOS_NUM_SCRATCH; i++)
+ WREG32(mmBIOS_SCRATCH_0 + i, adev->bios_scratch[i]);
+}
+
+/* Atom needs data in little endian format
+ * so swap as appropriate when copying data to
+ * or from atom. Note that atom operates on
+ * dw units.
+ */
+void amdgpu_atombios_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)
+{
+#ifdef __BIG_ENDIAN
+ u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */
+ u32 *dst32, *src32;
+ int i;
+
+ memcpy(src_tmp, src, num_bytes);
+ src32 = (u32 *)src_tmp;
+ dst32 = (u32 *)dst_tmp;
+ if (to_le) {
+ for (i = 0; i < ((num_bytes + 3) / 4); i++)
+ dst32[i] = cpu_to_le32(src32[i]);
+ memcpy(dst, dst_tmp, num_bytes);
+ } else {
+ u8 dws = num_bytes & ~3;
+ for (i = 0; i < ((num_bytes + 3) / 4); i++)
+ dst32[i] = le32_to_cpu(src32[i]);
+ memcpy(dst, dst_tmp, dws);
+ if (num_bytes % 4) {
+ for (i = 0; i < (num_bytes % 4); i++)
+ dst[dws+i] = dst_tmp[dws+i];
+ }
+ }
+#else
+ memcpy(dst, src, num_bytes);
+#endif
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h
new file mode 100644
index 000000000000..0ebb959ea435
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_ATOMBIOS_H__
+#define __AMDGPU_ATOMBIOS_H__
+
+struct atom_clock_dividers {
+ u32 post_div;
+ union {
+ struct {
+#ifdef __BIG_ENDIAN
+ u32 reserved : 6;
+ u32 whole_fb_div : 12;
+ u32 frac_fb_div : 14;
+#else
+ u32 frac_fb_div : 14;
+ u32 whole_fb_div : 12;
+ u32 reserved : 6;
+#endif
+ };
+ u32 fb_div;
+ };
+ u32 ref_div;
+ bool enable_post_div;
+ bool enable_dithen;
+ u32 vco_mode;
+ u32 real_clock;
+ /* added for CI */
+ u32 post_divider;
+ u32 flags;
+};
+
+struct atom_mpll_param {
+ union {
+ struct {
+#ifdef __BIG_ENDIAN
+ u32 reserved : 8;
+ u32 clkfrac : 12;
+ u32 clkf : 12;
+#else
+ u32 clkf : 12;
+ u32 clkfrac : 12;
+ u32 reserved : 8;
+#endif
+ };
+ u32 fb_div;
+ };
+ u32 post_div;
+ u32 bwcntl;
+ u32 dll_speed;
+ u32 vco_mode;
+ u32 yclk_sel;
+ u32 qdr;
+ u32 half_rate;
+};
+
+#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
+
+struct atom_memory_info {
+ u8 mem_vendor;
+ u8 mem_type;
+};
+
+#define MAX_AC_TIMING_ENTRIES 16
+
+struct atom_memory_clock_range_table
+{
+ u8 num_entries;
+ u8 rsv[3];
+ u32 mclk[MAX_AC_TIMING_ENTRIES];
+};
+
+#define VBIOS_MC_REGISTER_ARRAY_SIZE 32
+#define VBIOS_MAX_AC_TIMING_ENTRIES 20
+
+struct atom_mc_reg_entry {
+ u32 mclk_max;
+ u32 mc_data[VBIOS_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct atom_mc_register_address {
+ u16 s1;
+ u8 pre_reg_data;
+};
+
+struct atom_mc_reg_table {
+ u8 last;
+ u8 num_entries;
+ struct atom_mc_reg_entry mc_reg_table_entry[VBIOS_MAX_AC_TIMING_ENTRIES];
+ struct atom_mc_register_address mc_reg_address[VBIOS_MC_REGISTER_ARRAY_SIZE];
+};
+
+#define MAX_VOLTAGE_ENTRIES 32
+
+struct atom_voltage_table_entry
+{
+ u16 value;
+ u32 smio_low;
+};
+
+struct atom_voltage_table
+{
+ u32 count;
+ u32 mask_low;
+ u32 phase_delay;
+ struct atom_voltage_table_entry entries[MAX_VOLTAGE_ENTRIES];
+};
+
+struct amdgpu_gpio_rec
+amdgpu_atombios_lookup_gpio(struct amdgpu_device *adev,
+ u8 id);
+
+struct amdgpu_i2c_bus_rec amdgpu_atombios_lookup_i2c_gpio(struct amdgpu_device *adev,
+ uint8_t id);
+void amdgpu_atombios_i2c_init(struct amdgpu_device *adev);
+
+bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *adev);
+
+int amdgpu_atombios_get_clock_info(struct amdgpu_device *adev);
+
+bool amdgpu_atombios_get_asic_ss_info(struct amdgpu_device *adev,
+ struct amdgpu_atom_ss *ss,
+ int id, u32 clock);
+
+int amdgpu_atombios_get_clock_dividers(struct amdgpu_device *adev,
+ u8 clock_type,
+ u32 clock,
+ bool strobe_mode,
+ struct atom_clock_dividers *dividers);
+
+int amdgpu_atombios_get_memory_pll_dividers(struct amdgpu_device *adev,
+ u32 clock,
+ bool strobe_mode,
+ struct atom_mpll_param *mpll_param);
+
+uint32_t amdgpu_atombios_get_engine_clock(struct amdgpu_device *adev);
+uint32_t amdgpu_atombios_get_memory_clock(struct amdgpu_device *adev);
+void amdgpu_atombios_set_engine_clock(struct amdgpu_device *adev,
+ uint32_t eng_clock);
+void amdgpu_atombios_set_memory_clock(struct amdgpu_device *adev,
+ uint32_t mem_clock);
+void amdgpu_atombios_set_voltage(struct amdgpu_device *adev,
+ u16 voltage_level,
+ u8 voltage_type);
+
+void amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev,
+ u32 eng_clock, u32 mem_clock);
+
+int amdgpu_atombios_get_leakage_id_from_vbios(struct amdgpu_device *adev,
+ u16 *leakage_id);
+
+int amdgpu_atombios_get_leakage_vddc_based_on_leakage_params(struct amdgpu_device *adev,
+ u16 *vddc, u16 *vddci,
+ u16 virtual_voltage_id,
+ u16 vbios_voltage_id);
+
+int amdgpu_atombios_get_voltage_evv(struct amdgpu_device *adev,
+ u16 virtual_voltage_id,
+ u16 *voltage);
+
+bool
+amdgpu_atombios_is_voltage_gpio(struct amdgpu_device *adev,
+ u8 voltage_type, u8 voltage_mode);
+
+int amdgpu_atombios_get_voltage_table(struct amdgpu_device *adev,
+ u8 voltage_type, u8 voltage_mode,
+ struct atom_voltage_table *voltage_table);
+
+int amdgpu_atombios_init_mc_reg_table(struct amdgpu_device *adev,
+ u8 module_index,
+ struct atom_mc_reg_table *reg_table);
+
+void amdgpu_atombios_scratch_regs_lock(struct amdgpu_device *adev, bool lock);
+void amdgpu_atombios_scratch_regs_init(struct amdgpu_device *adev);
+void amdgpu_atombios_scratch_regs_save(struct amdgpu_device *adev);
+void amdgpu_atombios_scratch_regs_restore(struct amdgpu_device *adev);
+
+void amdgpu_atombios_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
new file mode 100644
index 000000000000..3f7aaa45bf8e
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2010 Red Hat Inc.
+ * Author : Dave Airlie <airlied@redhat.com>
+ *
+ * Licensed under GPLv2
+ *
+ * ATPX support for both Intel/ATI
+ */
+#include <linux/vga_switcheroo.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+
+#include "amdgpu_acpi.h"
+
+struct amdgpu_atpx_functions {
+ bool px_params;
+ bool power_cntl;
+ bool disp_mux_cntl;
+ bool i2c_mux_cntl;
+ bool switch_start;
+ bool switch_end;
+ bool disp_connectors_mapping;
+ bool disp_detetion_ports;
+};
+
+struct amdgpu_atpx {
+ acpi_handle handle;
+ struct amdgpu_atpx_functions functions;
+};
+
+static struct amdgpu_atpx_priv {
+ bool atpx_detected;
+ /* handle for device - and atpx */
+ acpi_handle dhandle;
+ acpi_handle other_handle;
+ struct amdgpu_atpx atpx;
+} amdgpu_atpx_priv;
+
+struct atpx_verify_interface {
+ u16 size; /* structure size in bytes (includes size field) */
+ u16 version; /* version */
+ u32 function_bits; /* supported functions bit vector */
+} __packed;
+
+struct atpx_px_params {
+ u16 size; /* structure size in bytes (includes size field) */
+ u32 valid_flags; /* which flags are valid */
+ u32 flags; /* flags */
+} __packed;
+
+struct atpx_power_control {
+ u16 size;
+ u8 dgpu_state;
+} __packed;
+
+struct atpx_mux {
+ u16 size;
+ u16 mux;
+} __packed;
+
+bool amdgpu_has_atpx(void) {
+ return amdgpu_atpx_priv.atpx_detected;
+}
+
+/**
+ * amdgpu_atpx_call - call an ATPX method
+ *
+ * @handle: acpi handle
+ * @function: the ATPX function to execute
+ * @params: ATPX function params
+ *
+ * Executes the requested ATPX function (all asics).
+ * Returns a pointer to the acpi output buffer.
+ */
+static union acpi_object *amdgpu_atpx_call(acpi_handle handle, int function,
+ struct acpi_buffer *params)
+{
+ acpi_status status;
+ union acpi_object atpx_arg_elements[2];
+ struct acpi_object_list atpx_arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ atpx_arg.count = 2;
+ atpx_arg.pointer = &atpx_arg_elements[0];
+
+ atpx_arg_elements[0].type = ACPI_TYPE_INTEGER;
+ atpx_arg_elements[0].integer.value = function;
+
+ if (params) {
+ atpx_arg_elements[1].type = ACPI_TYPE_BUFFER;
+ atpx_arg_elements[1].buffer.length = params->length;
+ atpx_arg_elements[1].buffer.pointer = params->pointer;
+ } else {
+ /* We need a second fake parameter */
+ atpx_arg_elements[1].type = ACPI_TYPE_INTEGER;
+ atpx_arg_elements[1].integer.value = 0;
+ }
+
+ status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer);
+
+ /* Fail only if calling the method fails and ATPX is supported */
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ printk("failed to evaluate ATPX got %s\n",
+ acpi_format_exception(status));
+ kfree(buffer.pointer);
+ return NULL;
+ }
+
+ return buffer.pointer;
+}
+
+/**
+ * amdgpu_atpx_parse_functions - parse supported functions
+ *
+ * @f: supported functions struct
+ * @mask: supported functions mask from ATPX
+ *
+ * Use the supported functions mask from ATPX function
+ * ATPX_FUNCTION_VERIFY_INTERFACE to determine what functions
+ * are supported (all asics).
+ */
+static void amdgpu_atpx_parse_functions(struct amdgpu_atpx_functions *f, u32 mask)
+{
+ f->px_params = mask & ATPX_GET_PX_PARAMETERS_SUPPORTED;
+ f->power_cntl = mask & ATPX_POWER_CONTROL_SUPPORTED;
+ f->disp_mux_cntl = mask & ATPX_DISPLAY_MUX_CONTROL_SUPPORTED;
+ f->i2c_mux_cntl = mask & ATPX_I2C_MUX_CONTROL_SUPPORTED;
+ f->switch_start = mask & ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED;
+ f->switch_end = mask & ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED;
+ f->disp_connectors_mapping = mask & ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED;
+ f->disp_detetion_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED;
+}
+
+/**
+ * amdgpu_atpx_validate_functions - validate ATPX functions
+ *
+ * @atpx: amdgpu atpx struct
+ *
+ * Validate that required functions are enabled (all asics).
+ * returns 0 on success, error on failure.
+ */
+static int amdgpu_atpx_validate(struct amdgpu_atpx *atpx)
+{
+ /* make sure required functions are enabled */
+ /* dGPU power control is required */
+ atpx->functions.power_cntl = true;
+
+ if (atpx->functions.px_params) {
+ union acpi_object *info;
+ struct atpx_px_params output;
+ size_t size;
+ u32 valid_bits;
+
+ info = amdgpu_atpx_call(atpx->handle, ATPX_FUNCTION_GET_PX_PARAMETERS, NULL);
+ if (!info)
+ return -EIO;
+
+ memset(&output, 0, sizeof(output));
+
+ size = *(u16 *) info->buffer.pointer;
+ if (size < 10) {
+ printk("ATPX buffer is too small: %zu\n", size);
+ kfree(info);
+ return -EINVAL;
+ }
+ size = min(sizeof(output), size);
+
+ memcpy(&output, info->buffer.pointer, size);
+
+ valid_bits = output.flags & output.valid_flags;
+ /* if separate mux flag is set, mux controls are required */
+ if (valid_bits & ATPX_SEPARATE_MUX_FOR_I2C) {
+ atpx->functions.i2c_mux_cntl = true;
+ atpx->functions.disp_mux_cntl = true;
+ }
+ /* if any outputs are muxed, mux controls are required */
+ if (valid_bits & (ATPX_CRT1_RGB_SIGNAL_MUXED |
+ ATPX_TV_SIGNAL_MUXED |
+ ATPX_DFP_SIGNAL_MUXED))
+ atpx->functions.disp_mux_cntl = true;
+
+ kfree(info);
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_atpx_verify_interface - verify ATPX
+ *
+ * @atpx: amdgpu atpx struct
+ *
+ * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function
+ * to initialize ATPX and determine what features are supported
+ * (all asics).
+ * returns 0 on success, error on failure.
+ */
+static int amdgpu_atpx_verify_interface(struct amdgpu_atpx *atpx)
+{
+ union acpi_object *info;
+ struct atpx_verify_interface output;
+ size_t size;
+ int err = 0;
+
+ info = amdgpu_atpx_call(atpx->handle, ATPX_FUNCTION_VERIFY_INTERFACE, NULL);
+ if (!info)
+ return -EIO;
+
+ memset(&output, 0, sizeof(output));
+
+ size = *(u16 *) info->buffer.pointer;
+ if (size < 8) {
+ printk("ATPX buffer is too small: %zu\n", size);
+ err = -EINVAL;
+ goto out;
+ }
+ size = min(sizeof(output), size);
+
+ memcpy(&output, info->buffer.pointer, size);
+
+ /* TODO: check version? */
+ printk("ATPX version %u, functions 0x%08x\n",
+ output.version, output.function_bits);
+
+ amdgpu_atpx_parse_functions(&atpx->functions, output.function_bits);
+
+out:
+ kfree(info);
+ return err;
+}
+
+/**
+ * amdgpu_atpx_set_discrete_state - power up/down discrete GPU
+ *
+ * @atpx: atpx info struct
+ * @state: discrete GPU state (0 = power down, 1 = power up)
+ *
+ * Execute the ATPX_FUNCTION_POWER_CONTROL ATPX function to
+ * power down/up the discrete GPU (all asics).
+ * Returns 0 on success, error on failure.
+ */
+static int amdgpu_atpx_set_discrete_state(struct amdgpu_atpx *atpx, u8 state)
+{
+ struct acpi_buffer params;
+ union acpi_object *info;
+ struct atpx_power_control input;
+
+ if (atpx->functions.power_cntl) {
+ input.size = 3;
+ input.dgpu_state = state;
+ params.length = input.size;
+ params.pointer = &input;
+ info = amdgpu_atpx_call(atpx->handle,
+ ATPX_FUNCTION_POWER_CONTROL,
+ &params);
+ if (!info)
+ return -EIO;
+ kfree(info);
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_atpx_switch_disp_mux - switch display mux
+ *
+ * @atpx: atpx info struct
+ * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
+ *
+ * Execute the ATPX_FUNCTION_DISPLAY_MUX_CONTROL ATPX function to
+ * switch the display mux between the discrete GPU and integrated GPU
+ * (all asics).
+ * Returns 0 on success, error on failure.
+ */
+static int amdgpu_atpx_switch_disp_mux(struct amdgpu_atpx *atpx, u16 mux_id)
+{
+ struct acpi_buffer params;
+ union acpi_object *info;
+ struct atpx_mux input;
+
+ if (atpx->functions.disp_mux_cntl) {
+ input.size = 4;
+ input.mux = mux_id;
+ params.length = input.size;
+ params.pointer = &input;
+ info = amdgpu_atpx_call(atpx->handle,
+ ATPX_FUNCTION_DISPLAY_MUX_CONTROL,
+ &params);
+ if (!info)
+ return -EIO;
+ kfree(info);
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_atpx_switch_i2c_mux - switch i2c/hpd mux
+ *
+ * @atpx: atpx info struct
+ * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
+ *
+ * Execute the ATPX_FUNCTION_I2C_MUX_CONTROL ATPX function to
+ * switch the i2c/hpd mux between the discrete GPU and integrated GPU
+ * (all asics).
+ * Returns 0 on success, error on failure.
+ */
+static int amdgpu_atpx_switch_i2c_mux(struct amdgpu_atpx *atpx, u16 mux_id)
+{
+ struct acpi_buffer params;
+ union acpi_object *info;
+ struct atpx_mux input;
+
+ if (atpx->functions.i2c_mux_cntl) {
+ input.size = 4;
+ input.mux = mux_id;
+ params.length = input.size;
+ params.pointer = &input;
+ info = amdgpu_atpx_call(atpx->handle,
+ ATPX_FUNCTION_I2C_MUX_CONTROL,
+ &params);
+ if (!info)
+ return -EIO;
+ kfree(info);
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_atpx_switch_start - notify the sbios of a GPU switch
+ *
+ * @atpx: atpx info struct
+ * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
+ *
+ * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION ATPX
+ * function to notify the sbios that a switch between the discrete GPU and
+ * integrated GPU has begun (all asics).
+ * Returns 0 on success, error on failure.
+ */
+static int amdgpu_atpx_switch_start(struct amdgpu_atpx *atpx, u16 mux_id)
+{
+ struct acpi_buffer params;
+ union acpi_object *info;
+ struct atpx_mux input;
+
+ if (atpx->functions.switch_start) {
+ input.size = 4;
+ input.mux = mux_id;
+ params.length = input.size;
+ params.pointer = &input;
+ info = amdgpu_atpx_call(atpx->handle,
+ ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION,
+ &params);
+ if (!info)
+ return -EIO;
+ kfree(info);
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_atpx_switch_end - notify the sbios of a GPU switch
+ *
+ * @atpx: atpx info struct
+ * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
+ *
+ * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION ATPX
+ * function to notify the sbios that a switch between the discrete GPU and
+ * integrated GPU has ended (all asics).
+ * Returns 0 on success, error on failure.
+ */
+static int amdgpu_atpx_switch_end(struct amdgpu_atpx *atpx, u16 mux_id)
+{
+ struct acpi_buffer params;
+ union acpi_object *info;
+ struct atpx_mux input;
+
+ if (atpx->functions.switch_end) {
+ input.size = 4;
+ input.mux = mux_id;
+ params.length = input.size;
+ params.pointer = &input;
+ info = amdgpu_atpx_call(atpx->handle,
+ ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION,
+ &params);
+ if (!info)
+ return -EIO;
+ kfree(info);
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_atpx_switchto - switch to the requested GPU
+ *
+ * @id: GPU to switch to
+ *
+ * Execute the necessary ATPX functions to switch between the discrete GPU and
+ * integrated GPU (all asics).
+ * Returns 0 on success, error on failure.
+ */
+static int amdgpu_atpx_switchto(enum vga_switcheroo_client_id id)
+{
+ u16 gpu_id;
+
+ if (id == VGA_SWITCHEROO_IGD)
+ gpu_id = ATPX_INTEGRATED_GPU;
+ else
+ gpu_id = ATPX_DISCRETE_GPU;
+
+ amdgpu_atpx_switch_start(&amdgpu_atpx_priv.atpx, gpu_id);
+ amdgpu_atpx_switch_disp_mux(&amdgpu_atpx_priv.atpx, gpu_id);
+ amdgpu_atpx_switch_i2c_mux(&amdgpu_atpx_priv.atpx, gpu_id);
+ amdgpu_atpx_switch_end(&amdgpu_atpx_priv.atpx, gpu_id);
+
+ return 0;
+}
+
+/**
+ * amdgpu_atpx_power_state - power down/up the requested GPU
+ *
+ * @id: GPU to power down/up
+ * @state: requested power state (0 = off, 1 = on)
+ *
+ * Execute the necessary ATPX function to power down/up the discrete GPU
+ * (all asics).
+ * Returns 0 on success, error on failure.
+ */
+static int amdgpu_atpx_power_state(enum vga_switcheroo_client_id id,
+ enum vga_switcheroo_state state)
+{
+ /* on w500 ACPI can't change intel gpu state */
+ if (id == VGA_SWITCHEROO_IGD)
+ return 0;
+
+ amdgpu_atpx_set_discrete_state(&amdgpu_atpx_priv.atpx, state);
+ return 0;
+}
+
+/**
+ * amdgpu_atpx_pci_probe_handle - look up the ATPX handle
+ *
+ * @pdev: pci device
+ *
+ * Look up the ATPX handles (all asics).
+ * Returns true if the handles are found, false if not.
+ */
+static bool amdgpu_atpx_pci_probe_handle(struct pci_dev *pdev)
+{
+ acpi_handle dhandle, atpx_handle;
+ acpi_status status;
+
+ dhandle = ACPI_HANDLE(&pdev->dev);
+ if (!dhandle)
+ return false;
+
+ status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
+ if (ACPI_FAILURE(status)) {
+ amdgpu_atpx_priv.other_handle = dhandle;
+ return false;
+ }
+ amdgpu_atpx_priv.dhandle = dhandle;
+ amdgpu_atpx_priv.atpx.handle = atpx_handle;
+ return true;
+}
+
+/**
+ * amdgpu_atpx_init - verify the ATPX interface
+ *
+ * Verify the ATPX interface (all asics).
+ * Returns 0 on success, error on failure.
+ */
+static int amdgpu_atpx_init(void)
+{
+ int r;
+
+ /* set up the ATPX handle */
+ r = amdgpu_atpx_verify_interface(&amdgpu_atpx_priv.atpx);
+ if (r)
+ return r;
+
+ /* validate the atpx setup */
+ r = amdgpu_atpx_validate(&amdgpu_atpx_priv.atpx);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+/**
+ * amdgpu_atpx_get_client_id - get the client id
+ *
+ * @pdev: pci device
+ *
+ * look up whether we are the integrated or discrete GPU (all asics).
+ * Returns the client id.
+ */
+static int amdgpu_atpx_get_client_id(struct pci_dev *pdev)
+{
+ if (amdgpu_atpx_priv.dhandle == ACPI_HANDLE(&pdev->dev))
+ return VGA_SWITCHEROO_IGD;
+ else
+ return VGA_SWITCHEROO_DIS;
+}
+
+static struct vga_switcheroo_handler amdgpu_atpx_handler = {
+ .switchto = amdgpu_atpx_switchto,
+ .power_state = amdgpu_atpx_power_state,
+ .init = amdgpu_atpx_init,
+ .get_client_id = amdgpu_atpx_get_client_id,
+};
+
+/**
+ * amdgpu_atpx_detect - detect whether we have PX
+ *
+ * Check if we have a PX system (all asics).
+ * Returns true if we have a PX system, false if not.
+ */
+static bool amdgpu_atpx_detect(void)
+{
+ char acpi_method_name[255] = { 0 };
+ struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
+ struct pci_dev *pdev = NULL;
+ bool has_atpx = false;
+ int vga_count = 0;
+
+ while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
+ vga_count++;
+
+ has_atpx |= (amdgpu_atpx_pci_probe_handle(pdev) == true);
+ }
+
+ while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
+ vga_count++;
+
+ has_atpx |= (amdgpu_atpx_pci_probe_handle(pdev) == true);
+ }
+
+ if (has_atpx && vga_count == 2) {
+ acpi_get_name(amdgpu_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer);
+ printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n",
+ acpi_method_name);
+ amdgpu_atpx_priv.atpx_detected = true;
+ return true;
+ }
+ return false;
+}
+
+/**
+ * amdgpu_register_atpx_handler - register with vga_switcheroo
+ *
+ * Register the PX callbacks with vga_switcheroo (all asics).
+ */
+void amdgpu_register_atpx_handler(void)
+{
+ bool r;
+
+ /* detect if we have any ATPX + 2 VGA in the system */
+ r = amdgpu_atpx_detect();
+ if (!r)
+ return;
+
+ vga_switcheroo_register_handler(&amdgpu_atpx_handler);
+}
+
+/**
+ * amdgpu_unregister_atpx_handler - unregister with vga_switcheroo
+ *
+ * Unregister the PX callbacks with vga_switcheroo (all asics).
+ */
+void amdgpu_unregister_atpx_handler(void)
+{
+ vga_switcheroo_unregister_handler();
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c
new file mode 100644
index 000000000000..2742b9a35cbc
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Jerome Glisse
+ */
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+
+#define AMDGPU_BENCHMARK_ITERATIONS 1024
+#define AMDGPU_BENCHMARK_COMMON_MODES_N 17
+
+static int amdgpu_benchmark_do_move(struct amdgpu_device *adev, unsigned size,
+ uint64_t saddr, uint64_t daddr, int n)
+{
+ unsigned long start_jiffies;
+ unsigned long end_jiffies;
+ struct amdgpu_fence *fence = NULL;
+ int i, r;
+
+ start_jiffies = jiffies;
+ for (i = 0; i < n; i++) {
+ struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
+ r = amdgpu_copy_buffer(ring, saddr, daddr, size, NULL, &fence);
+ if (r)
+ goto exit_do_move;
+ r = amdgpu_fence_wait(fence, false);
+ if (r)
+ goto exit_do_move;
+ amdgpu_fence_unref(&fence);
+ }
+ end_jiffies = jiffies;
+ r = jiffies_to_msecs(end_jiffies - start_jiffies);
+
+exit_do_move:
+ if (fence)
+ amdgpu_fence_unref(&fence);
+ return r;
+}
+
+
+static void amdgpu_benchmark_log_results(int n, unsigned size,
+ unsigned int time,
+ unsigned sdomain, unsigned ddomain,
+ char *kind)
+{
+ unsigned int throughput = (n * (size >> 10)) / time;
+ DRM_INFO("amdgpu: %s %u bo moves of %u kB from"
+ " %d to %d in %u ms, throughput: %u Mb/s or %u MB/s\n",
+ kind, n, size >> 10, sdomain, ddomain, time,
+ throughput * 8, throughput);
+}
+
+static void amdgpu_benchmark_move(struct amdgpu_device *adev, unsigned size,
+ unsigned sdomain, unsigned ddomain)
+{
+ struct amdgpu_bo *dobj = NULL;
+ struct amdgpu_bo *sobj = NULL;
+ uint64_t saddr, daddr;
+ int r, n;
+ int time;
+
+ n = AMDGPU_BENCHMARK_ITERATIONS;
+ r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, sdomain, 0, NULL, &sobj);
+ if (r) {
+ goto out_cleanup;
+ }
+ r = amdgpu_bo_reserve(sobj, false);
+ if (unlikely(r != 0))
+ goto out_cleanup;
+ r = amdgpu_bo_pin(sobj, sdomain, &saddr);
+ amdgpu_bo_unreserve(sobj);
+ if (r) {
+ goto out_cleanup;
+ }
+ r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, ddomain, 0, NULL, &dobj);
+ if (r) {
+ goto out_cleanup;
+ }
+ r = amdgpu_bo_reserve(dobj, false);
+ if (unlikely(r != 0))
+ goto out_cleanup;
+ r = amdgpu_bo_pin(dobj, ddomain, &daddr);
+ amdgpu_bo_unreserve(dobj);
+ if (r) {
+ goto out_cleanup;
+ }
+
+ if (adev->mman.buffer_funcs) {
+ time = amdgpu_benchmark_do_move(adev, size, saddr, daddr, n);
+ if (time < 0)
+ goto out_cleanup;
+ if (time > 0)
+ amdgpu_benchmark_log_results(n, size, time,
+ sdomain, ddomain, "dma");
+ }
+
+out_cleanup:
+ if (sobj) {
+ r = amdgpu_bo_reserve(sobj, false);
+ if (likely(r == 0)) {
+ amdgpu_bo_unpin(sobj);
+ amdgpu_bo_unreserve(sobj);
+ }
+ amdgpu_bo_unref(&sobj);
+ }
+ if (dobj) {
+ r = amdgpu_bo_reserve(dobj, false);
+ if (likely(r == 0)) {
+ amdgpu_bo_unpin(dobj);
+ amdgpu_bo_unreserve(dobj);
+ }
+ amdgpu_bo_unref(&dobj);
+ }
+
+ if (r) {
+ DRM_ERROR("Error while benchmarking BO move.\n");
+ }
+}
+
+void amdgpu_benchmark(struct amdgpu_device *adev, int test_number)
+{
+ int i;
+ int common_modes[AMDGPU_BENCHMARK_COMMON_MODES_N] = {
+ 640 * 480 * 4,
+ 720 * 480 * 4,
+ 800 * 600 * 4,
+ 848 * 480 * 4,
+ 1024 * 768 * 4,
+ 1152 * 768 * 4,
+ 1280 * 720 * 4,
+ 1280 * 800 * 4,
+ 1280 * 854 * 4,
+ 1280 * 960 * 4,
+ 1280 * 1024 * 4,
+ 1440 * 900 * 4,
+ 1400 * 1050 * 4,
+ 1680 * 1050 * 4,
+ 1600 * 1200 * 4,
+ 1920 * 1080 * 4,
+ 1920 * 1200 * 4
+ };
+
+ switch (test_number) {
+ case 1:
+ /* simple test, VRAM to GTT and GTT to VRAM */
+ amdgpu_benchmark_move(adev, 1024*1024, AMDGPU_GEM_DOMAIN_GTT,
+ AMDGPU_GEM_DOMAIN_VRAM);
+ amdgpu_benchmark_move(adev, 1024*1024, AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_GTT);
+ break;
+ case 2:
+ /* simple test, VRAM to VRAM */
+ amdgpu_benchmark_move(adev, 1024*1024, AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_VRAM);
+ break;
+ case 3:
+ /* GTT to VRAM, buffer size sweep, powers of 2 */
+ for (i = 1; i <= 16384; i <<= 1)
+ amdgpu_benchmark_move(adev, i * AMDGPU_GPU_PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_GTT,
+ AMDGPU_GEM_DOMAIN_VRAM);
+ break;
+ case 4:
+ /* VRAM to GTT, buffer size sweep, powers of 2 */
+ for (i = 1; i <= 16384; i <<= 1)
+ amdgpu_benchmark_move(adev, i * AMDGPU_GPU_PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_GTT);
+ break;
+ case 5:
+ /* VRAM to VRAM, buffer size sweep, powers of 2 */
+ for (i = 1; i <= 16384; i <<= 1)
+ amdgpu_benchmark_move(adev, i * AMDGPU_GPU_PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_VRAM);
+ break;
+ case 6:
+ /* GTT to VRAM, buffer size sweep, common modes */
+ for (i = 0; i < AMDGPU_BENCHMARK_COMMON_MODES_N; i++)
+ amdgpu_benchmark_move(adev, common_modes[i],
+ AMDGPU_GEM_DOMAIN_GTT,
+ AMDGPU_GEM_DOMAIN_VRAM);
+ break;
+ case 7:
+ /* VRAM to GTT, buffer size sweep, common modes */
+ for (i = 0; i < AMDGPU_BENCHMARK_COMMON_MODES_N; i++)
+ amdgpu_benchmark_move(adev, common_modes[i],
+ AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_GTT);
+ break;
+ case 8:
+ /* VRAM to VRAM, buffer size sweep, common modes */
+ for (i = 0; i < AMDGPU_BENCHMARK_COMMON_MODES_N; i++)
+ amdgpu_benchmark_move(adev, common_modes[i],
+ AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_VRAM);
+ break;
+
+ default:
+ DRM_ERROR("Unknown benchmark\n");
+ }
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
new file mode 100644
index 000000000000..ceb444f6d418
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#include <drm/drmP.h>
+#include "amdgpu.h"
+#include "atom.h"
+
+#include <linux/vga_switcheroo.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+/*
+ * BIOS.
+ */
+
+/* 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
+ * copy of the igp rom at the start of vram if a discrete card is
+ * present.
+ */
+static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
+{
+ uint8_t __iomem *bios;
+ resource_size_t vram_base;
+ resource_size_t size = 256 * 1024; /* ??? */
+
+ if (!(adev->flags & AMDGPU_IS_APU))
+ if (!amdgpu_card_posted(adev))
+ return false;
+
+ adev->bios = NULL;
+ vram_base = pci_resource_start(adev->pdev, 0);
+ bios = ioremap(vram_base, size);
+ if (!bios) {
+ return false;
+ }
+
+ if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+ iounmap(bios);
+ return false;
+ }
+ adev->bios = kmalloc(size, GFP_KERNEL);
+ if (adev->bios == NULL) {
+ iounmap(bios);
+ return false;
+ }
+ memcpy_fromio(adev->bios, bios, size);
+ iounmap(bios);
+ return true;
+}
+
+bool amdgpu_read_bios(struct amdgpu_device *adev)
+{
+ uint8_t __iomem *bios, val1, val2;
+ size_t size;
+
+ adev->bios = NULL;
+ /* XXX: some cards may return 0 for rom size? ddx has a workaround */
+ bios = pci_map_rom(adev->pdev, &size);
+ if (!bios) {
+ return false;
+ }
+
+ val1 = readb(&bios[0]);
+ val2 = readb(&bios[1]);
+
+ if (size == 0 || val1 != 0x55 || val2 != 0xaa) {
+ pci_unmap_rom(adev->pdev, bios);
+ return false;
+ }
+ adev->bios = kzalloc(size, GFP_KERNEL);
+ if (adev->bios == NULL) {
+ pci_unmap_rom(adev->pdev, bios);
+ return false;
+ }
+ memcpy_fromio(adev->bios, bios, size);
+ pci_unmap_rom(adev->pdev, bios);
+ return true;
+}
+
+static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
+{
+ uint8_t __iomem *bios;
+ size_t size;
+
+ adev->bios = NULL;
+
+ bios = pci_platform_rom(adev->pdev, &size);
+ if (!bios) {
+ return false;
+ }
+
+ if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+ return false;
+ }
+ adev->bios = kmemdup(bios, size, GFP_KERNEL);
+ if (adev->bios == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+#ifdef CONFIG_ACPI
+/* ATRM is used to get the BIOS on the discrete cards in
+ * dual-gpu systems.
+ */
+/* retrieve the ROM in 4k blocks */
+#define ATRM_BIOS_PAGE 4096
+/**
+ * amdgpu_atrm_call - fetch a chunk of the vbios
+ *
+ * @atrm_handle: acpi ATRM handle
+ * @bios: vbios image pointer
+ * @offset: offset of vbios image data to fetch
+ * @len: length of vbios image data to fetch
+ *
+ * Executes ATRM to fetch a chunk of the discrete
+ * vbios image on PX systems (all asics).
+ * Returns the length of the buffer fetched.
+ */
+static int amdgpu_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
+ int offset, int len)
+{
+ acpi_status status;
+ union acpi_object atrm_arg_elements[2], *obj;
+ struct acpi_object_list atrm_arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
+
+ atrm_arg.count = 2;
+ atrm_arg.pointer = &atrm_arg_elements[0];
+
+ atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
+ atrm_arg_elements[0].integer.value = offset;
+
+ atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
+ atrm_arg_elements[1].integer.value = len;
+
+ status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
+ return -ENODEV;
+ }
+
+ obj = (union acpi_object *)buffer.pointer;
+ memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length);
+ len = obj->buffer.length;
+ kfree(buffer.pointer);
+ return len;
+}
+
+static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
+{
+ int ret;
+ int size = 256 * 1024;
+ int i;
+ struct pci_dev *pdev = NULL;
+ acpi_handle dhandle, atrm_handle;
+ acpi_status status;
+ bool found = false;
+
+ /* ATRM is for the discrete card only */
+ if (adev->flags & AMDGPU_IS_APU)
+ return false;
+
+ while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
+ dhandle = ACPI_HANDLE(&pdev->dev);
+ if (!dhandle)
+ continue;
+
+ status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
+ if (!ACPI_FAILURE(status)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
+ dhandle = ACPI_HANDLE(&pdev->dev);
+ if (!dhandle)
+ continue;
+
+ status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
+ if (!ACPI_FAILURE(status)) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ return false;
+
+ adev->bios = kmalloc(size, GFP_KERNEL);
+ if (!adev->bios) {
+ DRM_ERROR("Unable to allocate bios\n");
+ return false;
+ }
+
+ for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
+ ret = amdgpu_atrm_call(atrm_handle,
+ adev->bios,
+ (i * ATRM_BIOS_PAGE),
+ ATRM_BIOS_PAGE);
+ if (ret < ATRM_BIOS_PAGE)
+ break;
+ }
+
+ if (i == 0 || adev->bios[0] != 0x55 || adev->bios[1] != 0xaa) {
+ kfree(adev->bios);
+ return false;
+ }
+ return true;
+}
+#else
+static inline bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
+{
+ return false;
+}
+#endif
+
+static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)
+{
+ if (adev->flags & AMDGPU_IS_APU)
+ return igp_read_bios_from_vram(adev);
+ else
+ return amdgpu_asic_read_disabled_bios(adev);
+}
+
+#ifdef CONFIG_ACPI
+static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
+{
+ bool ret = false;
+ struct acpi_table_header *hdr;
+ acpi_size tbl_size;
+ UEFI_ACPI_VFCT *vfct;
+ GOP_VBIOS_CONTENT *vbios;
+ VFCT_IMAGE_HEADER *vhdr;
+
+ if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size)))
+ return false;
+ if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
+ DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
+ goto out_unmap;
+ }
+
+ vfct = (UEFI_ACPI_VFCT *)hdr;
+ if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) {
+ DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
+ goto out_unmap;
+ }
+
+ vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset);
+ vhdr = &vbios->VbiosHeader;
+ DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n",
+ vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction,
+ vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength);
+
+ if (vhdr->PCIBus != adev->pdev->bus->number ||
+ vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) ||
+ vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn) ||
+ vhdr->VendorID != adev->pdev->vendor ||
+ vhdr->DeviceID != adev->pdev->device) {
+ DRM_INFO("ACPI VFCT table is not for this card\n");
+ goto out_unmap;
+ }
+
+ if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) {
+ DRM_ERROR("ACPI VFCT image truncated\n");
+ goto out_unmap;
+ }
+
+ adev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL);
+ ret = !!adev->bios;
+
+out_unmap:
+ return ret;
+}
+#else
+static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
+{
+ return false;
+}
+#endif
+
+bool amdgpu_get_bios(struct amdgpu_device *adev)
+{
+ bool r;
+ uint16_t tmp;
+
+ r = amdgpu_atrm_get_bios(adev);
+ if (r == false)
+ r = amdgpu_acpi_vfct_bios(adev);
+ if (r == false)
+ r = igp_read_bios_from_vram(adev);
+ if (r == false)
+ r = amdgpu_read_bios(adev);
+ if (r == false) {
+ r = amdgpu_read_disabled_bios(adev);
+ }
+ if (r == false) {
+ r = amdgpu_read_platform_bios(adev);
+ }
+ if (r == false || adev->bios == NULL) {
+ DRM_ERROR("Unable to locate a BIOS ROM\n");
+ adev->bios = NULL;
+ return false;
+ }
+ if (adev->bios[0] != 0x55 || adev->bios[1] != 0xaa) {
+ printk("BIOS signature incorrect %x %x\n", adev->bios[0], adev->bios[1]);
+ goto free_bios;
+ }
+
+ tmp = RBIOS16(0x18);
+ if (RBIOS8(tmp + 0x14) != 0x0) {
+ DRM_INFO("Not an x86 BIOS ROM, not using.\n");
+ goto free_bios;
+ }
+
+ adev->bios_header_start = RBIOS16(0x48);
+ if (!adev->bios_header_start) {
+ goto free_bios;
+ }
+ tmp = adev->bios_header_start + 4;
+ if (!memcmp(adev->bios + tmp, "ATOM", 4) ||
+ !memcmp(adev->bios + tmp, "MOTA", 4)) {
+ adev->is_atom_bios = true;
+ } else {
+ adev->is_atom_bios = false;
+ }
+
+ DRM_DEBUG("%sBIOS detected\n", adev->is_atom_bios ? "ATOM" : "COM");
+ return true;
+free_bios:
+ kfree(adev->bios);
+ adev->bios = NULL;
+ return false;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
new file mode 100644
index 000000000000..36d34e0afbc3
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2015 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ * Christian König <deathsimple@vodafone.de>
+ */
+
+#include <drm/drmP.h>
+#include "amdgpu.h"
+
+static int amdgpu_bo_list_create(struct amdgpu_fpriv *fpriv,
+ struct amdgpu_bo_list **result,
+ int *id)
+{
+ int r;
+
+ *result = kzalloc(sizeof(struct amdgpu_bo_list), GFP_KERNEL);
+ if (!*result)
+ return -ENOMEM;
+
+ mutex_lock(&fpriv->bo_list_lock);
+ r = idr_alloc(&fpriv->bo_list_handles, *result,
+ 1, 0, GFP_KERNEL);
+ if (r < 0) {
+ mutex_unlock(&fpriv->bo_list_lock);
+ kfree(*result);
+ return r;
+ }
+ *id = r;
+
+ mutex_init(&(*result)->lock);
+ (*result)->num_entries = 0;
+ (*result)->array = NULL;
+
+ mutex_lock(&(*result)->lock);
+ mutex_unlock(&fpriv->bo_list_lock);
+
+ return 0;
+}
+
+static void amdgpu_bo_list_destroy(struct amdgpu_fpriv *fpriv, int id)
+{
+ struct amdgpu_bo_list *list;
+
+ mutex_lock(&fpriv->bo_list_lock);
+ list = idr_find(&fpriv->bo_list_handles, id);
+ if (list) {
+ mutex_lock(&list->lock);
+ idr_remove(&fpriv->bo_list_handles, id);
+ mutex_unlock(&list->lock);
+ amdgpu_bo_list_free(list);
+ }
+ mutex_unlock(&fpriv->bo_list_lock);
+}
+
+static int amdgpu_bo_list_set(struct amdgpu_device *adev,
+ struct drm_file *filp,
+ struct amdgpu_bo_list *list,
+ struct drm_amdgpu_bo_list_entry *info,
+ unsigned num_entries)
+{
+ struct amdgpu_bo_list_entry *array;
+ struct amdgpu_bo *gds_obj = adev->gds.gds_gfx_bo;
+ struct amdgpu_bo *gws_obj = adev->gds.gws_gfx_bo;
+ struct amdgpu_bo *oa_obj = adev->gds.oa_gfx_bo;
+
+ bool has_userptr = false;
+ unsigned i;
+
+ array = drm_malloc_ab(num_entries, sizeof(struct amdgpu_bo_list_entry));
+ if (!array)
+ return -ENOMEM;
+ memset(array, 0, num_entries * sizeof(struct amdgpu_bo_list_entry));
+
+ for (i = 0; i < num_entries; ++i) {
+ struct amdgpu_bo_list_entry *entry = &array[i];
+ struct drm_gem_object *gobj;
+
+ gobj = drm_gem_object_lookup(adev->ddev, filp, info[i].bo_handle);
+ if (!gobj)
+ goto error_free;
+
+ entry->robj = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj));
+ drm_gem_object_unreference_unlocked(gobj);
+ entry->priority = info[i].bo_priority;
+ entry->prefered_domains = entry->robj->initial_domain;
+ entry->allowed_domains = entry->prefered_domains;
+ if (entry->allowed_domains == AMDGPU_GEM_DOMAIN_VRAM)
+ entry->allowed_domains |= AMDGPU_GEM_DOMAIN_GTT;
+ if (amdgpu_ttm_tt_has_userptr(entry->robj->tbo.ttm)) {
+ has_userptr = true;
+ entry->prefered_domains = AMDGPU_GEM_DOMAIN_GTT;
+ entry->allowed_domains = AMDGPU_GEM_DOMAIN_GTT;
+ }
+ entry->tv.bo = &entry->robj->tbo;
+ entry->tv.shared = true;
+
+ if (entry->prefered_domains == AMDGPU_GEM_DOMAIN_GDS)
+ gds_obj = entry->robj;
+ if (entry->prefered_domains == AMDGPU_GEM_DOMAIN_GWS)
+ gws_obj = entry->robj;
+ if (entry->prefered_domains == AMDGPU_GEM_DOMAIN_OA)
+ oa_obj = entry->robj;
+ }
+
+ for (i = 0; i < list->num_entries; ++i)
+ amdgpu_bo_unref(&list->array[i].robj);
+
+ drm_free_large(list->array);
+
+ list->gds_obj = gds_obj;
+ list->gws_obj = gws_obj;
+ list->oa_obj = oa_obj;
+ list->has_userptr = has_userptr;
+ list->array = array;
+ list->num_entries = num_entries;
+
+ return 0;
+
+error_free:
+ drm_free_large(array);
+ return -ENOENT;
+}
+
+struct amdgpu_bo_list *
+amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id)
+{
+ struct amdgpu_bo_list *result;
+
+ mutex_lock(&fpriv->bo_list_lock);
+ result = idr_find(&fpriv->bo_list_handles, id);
+ if (result)
+ mutex_lock(&result->lock);
+ mutex_unlock(&fpriv->bo_list_lock);
+ return result;
+}
+
+void amdgpu_bo_list_put(struct amdgpu_bo_list *list)
+{
+ mutex_unlock(&list->lock);
+}
+
+void amdgpu_bo_list_free(struct amdgpu_bo_list *list)
+{
+ unsigned i;
+
+ for (i = 0; i < list->num_entries; ++i)
+ amdgpu_bo_unref(&list->array[i].robj);
+
+ mutex_destroy(&list->lock);
+ drm_free_large(list->array);
+ kfree(list);
+}
+
+int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ const uint32_t info_size = sizeof(struct drm_amdgpu_bo_list_entry);
+
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_fpriv *fpriv = filp->driver_priv;
+ union drm_amdgpu_bo_list *args = data;
+ uint32_t handle = args->in.list_handle;
+ const void __user *uptr = (const void*)(long)args->in.bo_info_ptr;
+
+ struct drm_amdgpu_bo_list_entry *info;
+ struct amdgpu_bo_list *list;
+
+ int r;
+
+ info = drm_malloc_ab(args->in.bo_number,
+ sizeof(struct drm_amdgpu_bo_list_entry));
+ if (!info)
+ return -ENOMEM;
+
+ /* copy the handle array from userspace to a kernel buffer */
+ r = -EFAULT;
+ if (likely(info_size == args->in.bo_info_size)) {
+ unsigned long bytes = args->in.bo_number *
+ args->in.bo_info_size;
+
+ if (copy_from_user(info, uptr, bytes))
+ goto error_free;
+
+ } else {
+ unsigned long bytes = min(args->in.bo_info_size, info_size);
+ unsigned i;
+
+ memset(info, 0, args->in.bo_number * info_size);
+ for (i = 0; i < args->in.bo_number; ++i) {
+ if (copy_from_user(&info[i], uptr, bytes))
+ goto error_free;
+
+ uptr += args->in.bo_info_size;
+ }
+ }
+
+ switch (args->in.operation) {
+ case AMDGPU_BO_LIST_OP_CREATE:
+ r = amdgpu_bo_list_create(fpriv, &list, &handle);
+ if (r)
+ goto error_free;
+
+ r = amdgpu_bo_list_set(adev, filp, list, info,
+ args->in.bo_number);
+ amdgpu_bo_list_put(list);
+ if (r)
+ goto error_free;
+
+ break;
+
+ case AMDGPU_BO_LIST_OP_DESTROY:
+ amdgpu_bo_list_destroy(fpriv, handle);
+ handle = 0;
+ break;
+
+ case AMDGPU_BO_LIST_OP_UPDATE:
+ r = -ENOENT;
+ list = amdgpu_bo_list_get(fpriv, handle);
+ if (!list)
+ goto error_free;
+
+ r = amdgpu_bo_list_set(adev, filp, list, info,
+ args->in.bo_number);
+ amdgpu_bo_list_put(list);
+ if (r)
+ goto error_free;
+
+ break;
+
+ default:
+ r = -EINVAL;
+ goto error_free;
+ }
+
+ memset(args, 0, sizeof(*args));
+ args->out.list_handle = handle;
+ drm_free_large(info);
+
+ return 0;
+
+error_free:
+ drm_free_large(info);
+ return r;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
new file mode 100644
index 000000000000..27df17a0e620
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -0,0 +1,1907 @@
+/*
+ * Copyright 2007-8 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 shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ */
+#include <drm/drmP.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "atom.h"
+#include "atombios_encoders.h"
+#include "atombios_dp.h"
+#include "amdgpu_connectors.h"
+#include "amdgpu_i2c.h"
+
+#include <linux/pm_runtime.h>
+
+void amdgpu_connector_hotplug(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+ /* bail if the connector does not have hpd pin, e.g.,
+ * VGA, TV, etc.
+ */
+ if (amdgpu_connector->hpd.hpd == AMDGPU_HPD_NONE)
+ return;
+
+ amdgpu_display_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd);
+
+ /* if the connector is already off, don't turn it back on */
+ if (connector->dpms != DRM_MODE_DPMS_ON)
+ return;
+
+ /* just deal with DP (not eDP) here. */
+ if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+ struct amdgpu_connector_atom_dig *dig_connector =
+ amdgpu_connector->con_priv;
+
+ /* if existing sink type was not DP no need to retrain */
+ if (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT)
+ return;
+
+ /* first get sink type as it may be reset after (un)plug */
+ dig_connector->dp_sink_type = amdgpu_atombios_dp_get_sinktype(amdgpu_connector);
+ /* don't do anything if sink is not display port, i.e.,
+ * passive dp->(dvi|hdmi) adaptor
+ */
+ if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
+ int saved_dpms = connector->dpms;
+ /* Only turn off the display if it's physically disconnected */
+ if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) {
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+ } else if (amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) {
+ /* set it to OFF so that drm_helper_connector_dpms()
+ * won't return immediately since the current state
+ * is ON at this point.
+ */
+ connector->dpms = DRM_MODE_DPMS_OFF;
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+ }
+ connector->dpms = saved_dpms;
+ }
+ }
+}
+
+static void amdgpu_connector_property_change_mode(struct drm_encoder *encoder)
+{
+ struct drm_crtc *crtc = encoder->crtc;
+
+ if (crtc && crtc->enabled) {
+ drm_crtc_helper_set_mode(crtc, &crtc->mode,
+ crtc->x, crtc->y, crtc->primary->fb);
+ }
+}
+
+int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct amdgpu_connector_atom_dig *dig_connector;
+ int bpc = 8;
+ unsigned mode_clock, max_tmds_clock;
+
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ if (amdgpu_connector->use_digital) {
+ if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
+ if (connector->display_info.bpc)
+ bpc = connector->display_info.bpc;
+ }
+ }
+ break;
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_HDMIA:
+ if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
+ if (connector->display_info.bpc)
+ bpc = connector->display_info.bpc;
+ }
+ break;
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ dig_connector = amdgpu_connector->con_priv;
+ if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+ (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) ||
+ drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
+ if (connector->display_info.bpc)
+ bpc = connector->display_info.bpc;
+ }
+ break;
+ case DRM_MODE_CONNECTOR_eDP:
+ case DRM_MODE_CONNECTOR_LVDS:
+ if (connector->display_info.bpc)
+ bpc = connector->display_info.bpc;
+ else {
+ const struct drm_connector_helper_funcs *connector_funcs =
+ connector->helper_private;
+ struct drm_encoder *encoder = connector_funcs->best_encoder(connector);
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+
+ if (dig->lcd_misc & ATOM_PANEL_MISC_V13_6BIT_PER_COLOR)
+ bpc = 6;
+ else if (dig->lcd_misc & ATOM_PANEL_MISC_V13_8BIT_PER_COLOR)
+ bpc = 8;
+ }
+ break;
+ }
+
+ if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
+ /*
+ * Pre DCE-8 hw can't handle > 12 bpc, and more than 12 bpc doesn't make
+ * much sense without support for > 12 bpc framebuffers. RGB 4:4:4 at
+ * 12 bpc is always supported on hdmi deep color sinks, as this is
+ * required by the HDMI-1.3 spec. Clamp to a safe 12 bpc maximum.
+ */
+ if (bpc > 12) {
+ DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 12 bpc.\n",
+ connector->name, bpc);
+ bpc = 12;
+ }
+
+ /* Any defined maximum tmds clock limit we must not exceed? */
+ if (connector->max_tmds_clock > 0) {
+ /* mode_clock is clock in kHz for mode to be modeset on this connector */
+ mode_clock = amdgpu_connector->pixelclock_for_modeset;
+
+ /* Maximum allowable input clock in kHz */
+ max_tmds_clock = connector->max_tmds_clock * 1000;
+
+ DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n",
+ connector->name, mode_clock, max_tmds_clock);
+
+ /* Check if bpc is within clock limit. Try to degrade gracefully otherwise */
+ if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) {
+ if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) &&
+ (mode_clock * 5/4 <= max_tmds_clock))
+ bpc = 10;
+ else
+ bpc = 8;
+
+ DRM_DEBUG("%s: HDMI deep color 12 bpc exceeds max tmds clock. Using %d bpc.\n",
+ connector->name, bpc);
+ }
+
+ if ((bpc == 10) && (mode_clock * 5/4 > max_tmds_clock)) {
+ bpc = 8;
+ DRM_DEBUG("%s: HDMI deep color 10 bpc exceeds max tmds clock. Using %d bpc.\n",
+ connector->name, bpc);
+ } else if (bpc > 8) {
+ /* max_tmds_clock missing, but hdmi spec mandates it for deep color. */
+ DRM_DEBUG("%s: Required max tmds clock for HDMI deep color missing. Using 8 bpc.\n",
+ connector->name);
+ bpc = 8;
+ }
+ }
+ }
+
+ if ((amdgpu_deep_color == 0) && (bpc > 8)) {
+ DRM_DEBUG("%s: Deep color disabled. Set amdgpu module param deep_color=1 to enable.\n",
+ connector->name);
+ bpc = 8;
+ }
+
+ DRM_DEBUG("%s: Display bpc=%d, returned bpc=%d\n",
+ connector->name, connector->display_info.bpc, bpc);
+
+ return bpc;
+}
+
+static void
+amdgpu_connector_update_scratch_regs(struct drm_connector *connector,
+ enum drm_connector_status status)
+{
+ struct drm_encoder *best_encoder = NULL;
+ struct drm_encoder *encoder = NULL;
+ const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
+ bool connected;
+ int i;
+
+ best_encoder = connector_funcs->best_encoder(connector);
+
+ for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+ if (connector->encoder_ids[i] == 0)
+ break;
+
+ encoder = drm_encoder_find(connector->dev,
+ connector->encoder_ids[i]);
+ if (!encoder)
+ continue;
+
+ if ((encoder == best_encoder) && (status == connector_status_connected))
+ connected = true;
+ else
+ connected = false;
+
+ amdgpu_atombios_encoder_set_bios_scratch_regs(connector, encoder, connected);
+
+ }
+}
+
+static struct drm_encoder *
+amdgpu_connector_find_encoder(struct drm_connector *connector,
+ int encoder_type)
+{
+ struct drm_encoder *encoder;
+ int i;
+
+ for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+ if (connector->encoder_ids[i] == 0)
+ break;
+ encoder = drm_encoder_find(connector->dev,
+ connector->encoder_ids[i]);
+ if (!encoder)
+ continue;
+
+ if (encoder->encoder_type == encoder_type)
+ return encoder;
+ }
+ return NULL;
+}
+
+struct edid *amdgpu_connector_edid(struct drm_connector *connector)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct drm_property_blob *edid_blob = connector->edid_blob_ptr;
+
+ if (amdgpu_connector->edid) {
+ return amdgpu_connector->edid;
+ } else if (edid_blob) {
+ struct edid *edid = kmemdup(edid_blob->data, edid_blob->length, GFP_KERNEL);
+ if (edid)
+ amdgpu_connector->edid = edid;
+ }
+ return amdgpu_connector->edid;
+}
+
+static struct edid *
+amdgpu_connector_get_hardcoded_edid(struct amdgpu_device *adev)
+{
+ struct edid *edid;
+
+ if (adev->mode_info.bios_hardcoded_edid) {
+ edid = kmalloc(adev->mode_info.bios_hardcoded_edid_size, GFP_KERNEL);
+ if (edid) {
+ memcpy((unsigned char *)edid,
+ (unsigned char *)adev->mode_info.bios_hardcoded_edid,
+ adev->mode_info.bios_hardcoded_edid_size);
+ return edid;
+ }
+ }
+ return NULL;
+}
+
+static void amdgpu_connector_get_edid(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+ if (amdgpu_connector->edid)
+ return;
+
+ /* on hw with routers, select right port */
+ if (amdgpu_connector->router.ddc_valid)
+ amdgpu_i2c_router_select_ddc_port(amdgpu_connector);
+
+ if ((amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) !=
+ ENCODER_OBJECT_ID_NONE) &&
+ amdgpu_connector->ddc_bus->has_aux) {
+ amdgpu_connector->edid = drm_get_edid(connector,
+ &amdgpu_connector->ddc_bus->aux.ddc);
+ } else if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
+ (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
+ struct amdgpu_connector_atom_dig *dig = amdgpu_connector->con_priv;
+
+ if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
+ dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) &&
+ amdgpu_connector->ddc_bus->has_aux)
+ amdgpu_connector->edid = drm_get_edid(connector,
+ &amdgpu_connector->ddc_bus->aux.ddc);
+ else if (amdgpu_connector->ddc_bus)
+ amdgpu_connector->edid = drm_get_edid(connector,
+ &amdgpu_connector->ddc_bus->adapter);
+ } else if (amdgpu_connector->ddc_bus) {
+ amdgpu_connector->edid = drm_get_edid(connector,
+ &amdgpu_connector->ddc_bus->adapter);
+ }
+
+ if (!amdgpu_connector->edid) {
+ /* some laptops provide a hardcoded edid in rom for LCDs */
+ if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) ||
+ (connector->connector_type == DRM_MODE_CONNECTOR_eDP)))
+ amdgpu_connector->edid = amdgpu_connector_get_hardcoded_edid(adev);
+ }
+}
+
+static void amdgpu_connector_free_edid(struct drm_connector *connector)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+ if (amdgpu_connector->edid) {
+ kfree(amdgpu_connector->edid);
+ amdgpu_connector->edid = NULL;
+ }
+}
+
+static int amdgpu_connector_ddc_get_modes(struct drm_connector *connector)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ int ret;
+
+ if (amdgpu_connector->edid) {
+ drm_mode_connector_update_edid_property(connector, amdgpu_connector->edid);
+ ret = drm_add_edid_modes(connector, amdgpu_connector->edid);
+ drm_edid_to_eld(connector, amdgpu_connector->edid);
+ return ret;
+ }
+ drm_mode_connector_update_edid_property(connector, NULL);
+ return 0;
+}
+
+static struct drm_encoder *
+amdgpu_connector_best_single_encoder(struct drm_connector *connector)
+{
+ int enc_id = connector->encoder_ids[0];
+
+ /* pick the encoder ids */
+ if (enc_id)
+ return drm_encoder_find(connector->dev, enc_id);
+ return NULL;
+}
+
+static void amdgpu_get_native_mode(struct drm_connector *connector)
+{
+ struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
+ struct amdgpu_encoder *amdgpu_encoder;
+
+ if (encoder == NULL)
+ return;
+
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+ if (!list_empty(&connector->probed_modes)) {
+ struct drm_display_mode *preferred_mode =
+ list_first_entry(&connector->probed_modes,
+ struct drm_display_mode, head);
+
+ amdgpu_encoder->native_mode = *preferred_mode;
+ } else {
+ amdgpu_encoder->native_mode.clock = 0;
+ }
+}
+
+static struct drm_display_mode *
+amdgpu_connector_lcd_native_mode(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_display_mode *mode = NULL;
+ struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
+
+ if (native_mode->hdisplay != 0 &&
+ native_mode->vdisplay != 0 &&
+ native_mode->clock != 0) {
+ mode = drm_mode_duplicate(dev, native_mode);
+ mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
+ drm_mode_set_name(mode);
+
+ DRM_DEBUG_KMS("Adding native panel mode %s\n", mode->name);
+ } else if (native_mode->hdisplay != 0 &&
+ native_mode->vdisplay != 0) {
+ /* mac laptops without an edid */
+ /* Note that this is not necessarily the exact panel mode,
+ * but an approximation based on the cvt formula. For these
+ * systems we should ideally read the mode info out of the
+ * registers or add a mode table, but this works and is much
+ * simpler.
+ */
+ mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false);
+ mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
+ DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name);
+ }
+ return mode;
+}
+
+static void amdgpu_connector_add_common_modes(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_display_mode *mode = NULL;
+ struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
+ int i;
+ struct mode_size {
+ int w;
+ int h;
+ } common_modes[17] = {
+ { 640, 480},
+ { 720, 480},
+ { 800, 600},
+ { 848, 480},
+ {1024, 768},
+ {1152, 768},
+ {1280, 720},
+ {1280, 800},
+ {1280, 854},
+ {1280, 960},
+ {1280, 1024},
+ {1440, 900},
+ {1400, 1050},
+ {1680, 1050},
+ {1600, 1200},
+ {1920, 1080},
+ {1920, 1200}
+ };
+
+ for (i = 0; i < 17; i++) {
+ if (amdgpu_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) {
+ if (common_modes[i].w > 1024 ||
+ common_modes[i].h > 768)
+ continue;
+ }
+ if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ if (common_modes[i].w > native_mode->hdisplay ||
+ common_modes[i].h > native_mode->vdisplay ||
+ (common_modes[i].w == native_mode->hdisplay &&
+ common_modes[i].h == native_mode->vdisplay))
+ continue;
+ }
+ if (common_modes[i].w < 320 || common_modes[i].h < 200)
+ continue;
+
+ mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false);
+ drm_mode_probed_add(connector, mode);
+ }
+}
+
+static int amdgpu_connector_set_property(struct drm_connector *connector,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct drm_encoder *encoder;
+ struct amdgpu_encoder *amdgpu_encoder;
+
+ if (property == adev->mode_info.coherent_mode_property) {
+ struct amdgpu_encoder_atom_dig *dig;
+ bool new_coherent_mode;
+
+ /* need to find digital encoder on connector */
+ encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+ if (!encoder)
+ return 0;
+
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+ if (!amdgpu_encoder->enc_priv)
+ return 0;
+
+ dig = amdgpu_encoder->enc_priv;
+ new_coherent_mode = val ? true : false;
+ if (dig->coherent_mode != new_coherent_mode) {
+ dig->coherent_mode = new_coherent_mode;
+ amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
+ }
+ }
+
+ if (property == adev->mode_info.audio_property) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ /* need to find digital encoder on connector */
+ encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+ if (!encoder)
+ return 0;
+
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+ if (amdgpu_connector->audio != val) {
+ amdgpu_connector->audio = val;
+ amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
+ }
+ }
+
+ if (property == adev->mode_info.dither_property) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ /* need to find digital encoder on connector */
+ encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+ if (!encoder)
+ return 0;
+
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+ if (amdgpu_connector->dither != val) {
+ amdgpu_connector->dither = val;
+ amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
+ }
+ }
+
+ if (property == adev->mode_info.underscan_property) {
+ /* need to find digital encoder on connector */
+ encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+ if (!encoder)
+ return 0;
+
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+ if (amdgpu_encoder->underscan_type != val) {
+ amdgpu_encoder->underscan_type = val;
+ amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
+ }
+ }
+
+ if (property == adev->mode_info.underscan_hborder_property) {
+ /* need to find digital encoder on connector */
+ encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+ if (!encoder)
+ return 0;
+
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+ if (amdgpu_encoder->underscan_hborder != val) {
+ amdgpu_encoder->underscan_hborder = val;
+ amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
+ }
+ }
+
+ if (property == adev->mode_info.underscan_vborder_property) {
+ /* need to find digital encoder on connector */
+ encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+ if (!encoder)
+ return 0;
+
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+ if (amdgpu_encoder->underscan_vborder != val) {
+ amdgpu_encoder->underscan_vborder = val;
+ amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
+ }
+ }
+
+ if (property == adev->mode_info.load_detect_property) {
+ struct amdgpu_connector *amdgpu_connector =
+ to_amdgpu_connector(connector);
+
+ if (val == 0)
+ amdgpu_connector->dac_load_detect = false;
+ else
+ amdgpu_connector->dac_load_detect = true;
+ }
+
+ if (property == dev->mode_config.scaling_mode_property) {
+ enum amdgpu_rmx_type rmx_type;
+
+ if (connector->encoder) {
+ amdgpu_encoder = to_amdgpu_encoder(connector->encoder);
+ } else {
+ const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
+ amdgpu_encoder = to_amdgpu_encoder(connector_funcs->best_encoder(connector));
+ }
+
+ switch (val) {
+ default:
+ case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
+ case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
+ case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
+ case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
+ }
+ if (amdgpu_encoder->rmx_type == rmx_type)
+ return 0;
+
+ if ((rmx_type != DRM_MODE_SCALE_NONE) &&
+ (amdgpu_encoder->native_mode.clock == 0))
+ return 0;
+
+ amdgpu_encoder->rmx_type = rmx_type;
+
+ amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
+ }
+
+ return 0;
+}
+
+static void
+amdgpu_connector_fixup_lcd_native_mode(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
+ struct drm_display_mode *t, *mode;
+
+ /* If the EDID preferred mode doesn't match the native mode, use it */
+ list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
+ if (mode->type & DRM_MODE_TYPE_PREFERRED) {
+ if (mode->hdisplay != native_mode->hdisplay ||
+ mode->vdisplay != native_mode->vdisplay)
+ memcpy(native_mode, mode, sizeof(*mode));
+ }
+ }
+
+ /* Try to get native mode details from EDID if necessary */
+ if (!native_mode->clock) {
+ list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
+ if (mode->hdisplay == native_mode->hdisplay &&
+ mode->vdisplay == native_mode->vdisplay) {
+ *native_mode = *mode;
+ drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V);
+ DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n");
+ break;
+ }
+ }
+ }
+
+ if (!native_mode->clock) {
+ DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
+ amdgpu_encoder->rmx_type = RMX_OFF;
+ }
+}
+
+static int amdgpu_connector_lvds_get_modes(struct drm_connector *connector)
+{
+ struct drm_encoder *encoder;
+ int ret = 0;
+ struct drm_display_mode *mode;
+
+ amdgpu_connector_get_edid(connector);
+ ret = amdgpu_connector_ddc_get_modes(connector);
+ if (ret > 0) {
+ encoder = amdgpu_connector_best_single_encoder(connector);
+ if (encoder) {
+ amdgpu_connector_fixup_lcd_native_mode(encoder, connector);
+ /* add scaled modes */
+ amdgpu_connector_add_common_modes(encoder, connector);
+ }
+ return ret;
+ }
+
+ encoder = amdgpu_connector_best_single_encoder(connector);
+ if (!encoder)
+ return 0;
+
+ /* we have no EDID modes */
+ mode = amdgpu_connector_lcd_native_mode(encoder);
+ if (mode) {
+ ret = 1;
+ drm_mode_probed_add(connector, mode);
+ /* add the width/height from vbios tables if available */
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
+ /* add scaled modes */
+ amdgpu_connector_add_common_modes(encoder, connector);
+ }
+
+ return ret;
+}
+
+static int amdgpu_connector_lvds_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
+
+ if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
+ return MODE_PANEL;
+
+ if (encoder) {
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
+
+ /* AVIVO hardware supports downscaling modes larger than the panel
+ * to the panel size, but I'm not sure this is desirable.
+ */
+ if ((mode->hdisplay > native_mode->hdisplay) ||
+ (mode->vdisplay > native_mode->vdisplay))
+ return MODE_PANEL;
+
+ /* if scaling is disabled, block non-native modes */
+ if (amdgpu_encoder->rmx_type == RMX_OFF) {
+ if ((mode->hdisplay != native_mode->hdisplay) ||
+ (mode->vdisplay != native_mode->vdisplay))
+ return MODE_PANEL;
+ }
+ }
+
+ return MODE_OK;
+}
+
+static enum drm_connector_status
+amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
+ enum drm_connector_status ret = connector_status_disconnected;
+ int r;
+
+ r = pm_runtime_get_sync(connector->dev->dev);
+ if (r < 0)
+ return connector_status_disconnected;
+
+ if (encoder) {
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
+
+ /* check if panel is valid */
+ if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
+ ret = connector_status_connected;
+
+ }
+
+ /* check for edid as well */
+ amdgpu_connector_get_edid(connector);
+ if (amdgpu_connector->edid)
+ ret = connector_status_connected;
+ /* check acpi lid status ??? */
+
+ amdgpu_connector_update_scratch_regs(connector, ret);
+ pm_runtime_mark_last_busy(connector->dev->dev);
+ pm_runtime_put_autosuspend(connector->dev->dev);
+ return ret;
+}
+
+static void amdgpu_connector_destroy(struct drm_connector *connector)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+ if (amdgpu_connector->ddc_bus->has_aux)
+ drm_dp_aux_unregister(&amdgpu_connector->ddc_bus->aux);
+ amdgpu_connector_free_edid(connector);
+ kfree(amdgpu_connector->con_priv);
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+ kfree(connector);
+}
+
+static int amdgpu_connector_set_lcd_property(struct drm_connector *connector,
+ struct drm_property *property,
+ uint64_t value)
+{
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_encoder *amdgpu_encoder;
+ enum amdgpu_rmx_type rmx_type;
+
+ DRM_DEBUG_KMS("\n");
+ if (property != dev->mode_config.scaling_mode_property)
+ return 0;
+
+ if (connector->encoder)
+ amdgpu_encoder = to_amdgpu_encoder(connector->encoder);
+ else {
+ const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
+ amdgpu_encoder = to_amdgpu_encoder(connector_funcs->best_encoder(connector));
+ }
+
+ switch (value) {
+ case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
+ case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
+ case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
+ default:
+ case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
+ }
+ if (amdgpu_encoder->rmx_type == rmx_type)
+ return 0;
+
+ amdgpu_encoder->rmx_type = rmx_type;
+
+ amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
+ return 0;
+}
+
+
+static const struct drm_connector_helper_funcs amdgpu_connector_lvds_helper_funcs = {
+ .get_modes = amdgpu_connector_lvds_get_modes,
+ .mode_valid = amdgpu_connector_lvds_mode_valid,
+ .best_encoder = amdgpu_connector_best_single_encoder,
+};
+
+static const struct drm_connector_funcs amdgpu_connector_lvds_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = amdgpu_connector_lvds_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = amdgpu_connector_destroy,
+ .set_property = amdgpu_connector_set_lcd_property,
+};
+
+static int amdgpu_connector_vga_get_modes(struct drm_connector *connector)
+{
+ int ret;
+
+ amdgpu_connector_get_edid(connector);
+ ret = amdgpu_connector_ddc_get_modes(connector);
+
+ return ret;
+}
+
+static int amdgpu_connector_vga_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+
+ /* XXX check mode bandwidth */
+
+ if ((mode->clock / 10) > adev->clock.max_pixel_clock)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static enum drm_connector_status
+amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct drm_encoder *encoder;
+ const struct drm_encoder_helper_funcs *encoder_funcs;
+ bool dret = false;
+ enum drm_connector_status ret = connector_status_disconnected;
+ int r;
+
+ r = pm_runtime_get_sync(connector->dev->dev);
+ if (r < 0)
+ return connector_status_disconnected;
+
+ encoder = amdgpu_connector_best_single_encoder(connector);
+ if (!encoder)
+ ret = connector_status_disconnected;
+
+ if (amdgpu_connector->ddc_bus)
+ dret = amdgpu_ddc_probe(amdgpu_connector, false);
+ if (dret) {
+ amdgpu_connector->detected_by_load = false;
+ amdgpu_connector_free_edid(connector);
+ amdgpu_connector_get_edid(connector);
+
+ if (!amdgpu_connector->edid) {
+ DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
+ connector->name);
+ ret = connector_status_connected;
+ } else {
+ amdgpu_connector->use_digital =
+ !!(amdgpu_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
+
+ /* some oems have boards with separate digital and analog connectors
+ * with a shared ddc line (often vga + hdmi)
+ */
+ if (amdgpu_connector->use_digital && amdgpu_connector->shared_ddc) {
+ amdgpu_connector_free_edid(connector);
+ ret = connector_status_disconnected;
+ } else {
+ ret = connector_status_connected;
+ }
+ }
+ } else {
+
+ /* if we aren't forcing don't do destructive polling */
+ if (!force) {
+ /* only return the previous status if we last
+ * detected a monitor via load.
+ */
+ if (amdgpu_connector->detected_by_load)
+ ret = connector->status;
+ goto out;
+ }
+
+ if (amdgpu_connector->dac_load_detect && encoder) {
+ encoder_funcs = encoder->helper_private;
+ ret = encoder_funcs->detect(encoder, connector);
+ if (ret != connector_status_disconnected)
+ amdgpu_connector->detected_by_load = true;
+ }
+ }
+
+ amdgpu_connector_update_scratch_regs(connector, ret);
+
+out:
+ pm_runtime_mark_last_busy(connector->dev->dev);
+ pm_runtime_put_autosuspend(connector->dev->dev);
+
+ return ret;
+}
+
+static const struct drm_connector_helper_funcs amdgpu_connector_vga_helper_funcs = {
+ .get_modes = amdgpu_connector_vga_get_modes,
+ .mode_valid = amdgpu_connector_vga_mode_valid,
+ .best_encoder = amdgpu_connector_best_single_encoder,
+};
+
+static const struct drm_connector_funcs amdgpu_connector_vga_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = amdgpu_connector_vga_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = amdgpu_connector_destroy,
+ .set_property = amdgpu_connector_set_property,
+};
+
+static bool
+amdgpu_connector_check_hpd_status_unchanged(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ enum drm_connector_status status;
+
+ if (amdgpu_connector->hpd.hpd != AMDGPU_HPD_NONE) {
+ if (amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd))
+ status = connector_status_connected;
+ else
+ status = connector_status_disconnected;
+ if (connector->status == status)
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * DVI is complicated
+ * Do a DDC probe, if DDC probe passes, get the full EDID so
+ * we can do analog/digital monitor detection at this point.
+ * If the monitor is an analog monitor or we got no DDC,
+ * we need to find the DAC encoder object for this connector.
+ * If we got no DDC, we do load detection on the DAC encoder object.
+ * If we got analog DDC or load detection passes on the DAC encoder
+ * we have to check if this analog encoder is shared with anyone else (TV)
+ * if its shared we have to set the other connector to disconnected.
+ */
+static enum drm_connector_status
+amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
+{
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct drm_encoder *encoder = NULL;
+ const struct drm_encoder_helper_funcs *encoder_funcs;
+ int i, r;
+ enum drm_connector_status ret = connector_status_disconnected;
+ bool dret = false, broken_edid = false;
+
+ r = pm_runtime_get_sync(connector->dev->dev);
+ if (r < 0)
+ return connector_status_disconnected;
+
+ if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
+ ret = connector->status;
+ goto exit;
+ }
+
+ if (amdgpu_connector->ddc_bus)
+ dret = amdgpu_ddc_probe(amdgpu_connector, false);
+ if (dret) {
+ amdgpu_connector->detected_by_load = false;
+ amdgpu_connector_free_edid(connector);
+ amdgpu_connector_get_edid(connector);
+
+ if (!amdgpu_connector->edid) {
+ DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
+ connector->name);
+ ret = connector_status_connected;
+ broken_edid = true; /* defer use_digital to later */
+ } else {
+ amdgpu_connector->use_digital =
+ !!(amdgpu_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
+
+ /* some oems have boards with separate digital and analog connectors
+ * with a shared ddc line (often vga + hdmi)
+ */
+ if ((!amdgpu_connector->use_digital) && amdgpu_connector->shared_ddc) {
+ amdgpu_connector_free_edid(connector);
+ ret = connector_status_disconnected;
+ } else {
+ ret = connector_status_connected;
+ }
+
+ /* This gets complicated. We have boards with VGA + HDMI with a
+ * shared DDC line and we have boards with DVI-D + HDMI with a shared
+ * DDC line. The latter is more complex because with DVI<->HDMI adapters
+ * you don't really know what's connected to which port as both are digital.
+ */
+ if (amdgpu_connector->shared_ddc && (ret == connector_status_connected)) {
+ struct drm_connector *list_connector;
+ struct amdgpu_connector *list_amdgpu_connector;
+ list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) {
+ if (connector == list_connector)
+ continue;
+ list_amdgpu_connector = to_amdgpu_connector(list_connector);
+ if (list_amdgpu_connector->shared_ddc &&
+ (list_amdgpu_connector->ddc_bus->rec.i2c_id ==
+ amdgpu_connector->ddc_bus->rec.i2c_id)) {
+ /* cases where both connectors are digital */
+ if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) {
+ /* hpd is our only option in this case */
+ if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) {
+ amdgpu_connector_free_edid(connector);
+ ret = connector_status_disconnected;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ((ret == connector_status_connected) && (amdgpu_connector->use_digital == true))
+ goto out;
+
+ /* DVI-D and HDMI-A are digital only */
+ if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) ||
+ (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA))
+ goto out;
+
+ /* if we aren't forcing don't do destructive polling */
+ if (!force) {
+ /* only return the previous status if we last
+ * detected a monitor via load.
+ */
+ if (amdgpu_connector->detected_by_load)
+ ret = connector->status;
+ goto out;
+ }
+
+ /* find analog encoder */
+ if (amdgpu_connector->dac_load_detect) {
+ for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+ if (connector->encoder_ids[i] == 0)
+ break;
+
+ encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
+ if (!encoder)
+ continue;
+
+ if (encoder->encoder_type != DRM_MODE_ENCODER_DAC &&
+ encoder->encoder_type != DRM_MODE_ENCODER_TVDAC)
+ continue;
+
+ encoder_funcs = encoder->helper_private;
+ if (encoder_funcs->detect) {
+ if (!broken_edid) {
+ if (ret != connector_status_connected) {
+ /* deal with analog monitors without DDC */
+ ret = encoder_funcs->detect(encoder, connector);
+ if (ret == connector_status_connected) {
+ amdgpu_connector->use_digital = false;
+ }
+ if (ret != connector_status_disconnected)
+ amdgpu_connector->detected_by_load = true;
+ }
+ } else {
+ enum drm_connector_status lret;
+ /* assume digital unless load detected otherwise */
+ amdgpu_connector->use_digital = true;
+ lret = encoder_funcs->detect(encoder, connector);
+ DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret);
+ if (lret == connector_status_connected)
+ amdgpu_connector->use_digital = false;
+ }
+ break;
+ }
+ }
+ }
+
+out:
+ /* updated in get modes as well since we need to know if it's analog or digital */
+ amdgpu_connector_update_scratch_regs(connector, ret);
+
+exit:
+ pm_runtime_mark_last_busy(connector->dev->dev);
+ pm_runtime_put_autosuspend(connector->dev->dev);
+
+ return ret;
+}
+
+/* okay need to be smart in here about which encoder to pick */
+static struct drm_encoder *
+amdgpu_connector_dvi_encoder(struct drm_connector *connector)
+{
+ int enc_id = connector->encoder_ids[0];
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct drm_encoder *encoder;
+ int i;
+ for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+ if (connector->encoder_ids[i] == 0)
+ break;
+
+ encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
+ if (!encoder)
+ continue;
+
+ if (amdgpu_connector->use_digital == true) {
+ if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
+ return encoder;
+ } else {
+ if (encoder->encoder_type == DRM_MODE_ENCODER_DAC ||
+ encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
+ return encoder;
+ }
+ }
+
+ /* see if we have a default encoder TODO */
+
+ /* then check use digitial */
+ /* pick the first one */
+ if (enc_id)
+ return drm_encoder_find(connector->dev, enc_id);
+ return NULL;
+}
+
+static void amdgpu_connector_dvi_force(struct drm_connector *connector)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ if (connector->force == DRM_FORCE_ON)
+ amdgpu_connector->use_digital = false;
+ if (connector->force == DRM_FORCE_ON_DIGITAL)
+ amdgpu_connector->use_digital = true;
+}
+
+static int amdgpu_connector_dvi_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+ /* XXX check mode bandwidth */
+
+ if (amdgpu_connector->use_digital && (mode->clock > 165000)) {
+ if ((amdgpu_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I) ||
+ (amdgpu_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) ||
+ (amdgpu_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B)) {
+ return MODE_OK;
+ } else if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
+ /* HDMI 1.3+ supports max clock of 340 Mhz */
+ if (mode->clock > 340000)
+ return MODE_CLOCK_HIGH;
+ else
+ return MODE_OK;
+ } else {
+ return MODE_CLOCK_HIGH;
+ }
+ }
+
+ /* check against the max pixel clock */
+ if ((mode->clock / 10) > adev->clock.max_pixel_clock)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs amdgpu_connector_dvi_helper_funcs = {
+ .get_modes = amdgpu_connector_vga_get_modes,
+ .mode_valid = amdgpu_connector_dvi_mode_valid,
+ .best_encoder = amdgpu_connector_dvi_encoder,
+};
+
+static const struct drm_connector_funcs amdgpu_connector_dvi_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = amdgpu_connector_dvi_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .set_property = amdgpu_connector_set_property,
+ .destroy = amdgpu_connector_destroy,
+ .force = amdgpu_connector_dvi_force,
+};
+
+static int amdgpu_connector_dp_get_modes(struct drm_connector *connector)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct amdgpu_connector_atom_dig *amdgpu_dig_connector = amdgpu_connector->con_priv;
+ struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
+ int ret;
+
+ if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
+ (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
+ struct drm_display_mode *mode;
+
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ if (!amdgpu_dig_connector->edp_on)
+ amdgpu_atombios_encoder_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_ON);
+ amdgpu_connector_get_edid(connector);
+ ret = amdgpu_connector_ddc_get_modes(connector);
+ if (!amdgpu_dig_connector->edp_on)
+ amdgpu_atombios_encoder_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_OFF);
+ } else {
+ /* need to setup ddc on the bridge */
+ if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) !=
+ ENCODER_OBJECT_ID_NONE) {
+ if (encoder)
+ amdgpu_atombios_encoder_setup_ext_encoder_ddc(encoder);
+ }
+ amdgpu_connector_get_edid(connector);
+ ret = amdgpu_connector_ddc_get_modes(connector);
+ }
+
+ if (ret > 0) {
+ if (encoder) {
+ amdgpu_connector_fixup_lcd_native_mode(encoder, connector);
+ /* add scaled modes */
+ amdgpu_connector_add_common_modes(encoder, connector);
+ }
+ return ret;
+ }
+
+ if (!encoder)
+ return 0;
+
+ /* we have no EDID modes */
+ mode = amdgpu_connector_lcd_native_mode(encoder);
+ if (mode) {
+ ret = 1;
+ drm_mode_probed_add(connector, mode);
+ /* add the width/height from vbios tables if available */
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
+ /* add scaled modes */
+ amdgpu_connector_add_common_modes(encoder, connector);
+ }
+ } else {
+ /* need to setup ddc on the bridge */
+ if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) !=
+ ENCODER_OBJECT_ID_NONE) {
+ if (encoder)
+ amdgpu_atombios_encoder_setup_ext_encoder_ddc(encoder);
+ }
+ amdgpu_connector_get_edid(connector);
+ ret = amdgpu_connector_ddc_get_modes(connector);
+
+ amdgpu_get_native_mode(connector);
+ }
+
+ return ret;
+}
+
+u16 amdgpu_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector)
+{
+ struct drm_encoder *encoder;
+ struct amdgpu_encoder *amdgpu_encoder;
+ int i;
+
+ for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+ if (connector->encoder_ids[i] == 0)
+ break;
+
+ encoder = drm_encoder_find(connector->dev,
+ connector->encoder_ids[i]);
+ if (!encoder)
+ continue;
+
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_TRAVIS:
+ case ENCODER_OBJECT_ID_NUTMEG:
+ return amdgpu_encoder->encoder_id;
+ default:
+ break;
+ }
+ }
+
+ return ENCODER_OBJECT_ID_NONE;
+}
+
+static bool amdgpu_connector_encoder_is_hbr2(struct drm_connector *connector)
+{
+ struct drm_encoder *encoder;
+ struct amdgpu_encoder *amdgpu_encoder;
+ int i;
+ bool found = false;
+
+ for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+ if (connector->encoder_ids[i] == 0)
+ break;
+ encoder = drm_encoder_find(connector->dev,
+ connector->encoder_ids[i]);
+ if (!encoder)
+ continue;
+
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+ if (amdgpu_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2)
+ found = true;
+ }
+
+ return found;
+}
+
+bool amdgpu_connector_is_dp12_capable(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+
+ if ((adev->clock.default_dispclk >= 53900) &&
+ amdgpu_connector_encoder_is_hbr2(connector)) {
+ return true;
+ }
+
+ return false;
+}
+
+static enum drm_connector_status
+amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)
+{
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ enum drm_connector_status ret = connector_status_disconnected;
+ struct amdgpu_connector_atom_dig *amdgpu_dig_connector = amdgpu_connector->con_priv;
+ struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
+ int r;
+
+ r = pm_runtime_get_sync(connector->dev->dev);
+ if (r < 0)
+ return connector_status_disconnected;
+
+ if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
+ ret = connector->status;
+ goto out;
+ }
+
+ amdgpu_connector_free_edid(connector);
+
+ if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
+ (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
+ if (encoder) {
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
+
+ /* check if panel is valid */
+ if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
+ ret = connector_status_connected;
+ }
+ /* eDP is always DP */
+ amdgpu_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
+ if (!amdgpu_dig_connector->edp_on)
+ amdgpu_atombios_encoder_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_ON);
+ if (!amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
+ ret = connector_status_connected;
+ if (!amdgpu_dig_connector->edp_on)
+ amdgpu_atombios_encoder_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_OFF);
+ } else if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) !=
+ ENCODER_OBJECT_ID_NONE) {
+ /* DP bridges are always DP */
+ amdgpu_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
+ /* get the DPCD from the bridge */
+ amdgpu_atombios_dp_get_dpcd(amdgpu_connector);
+
+ if (encoder) {
+ /* setup ddc on the bridge */
+ amdgpu_atombios_encoder_setup_ext_encoder_ddc(encoder);
+ /* bridge chips are always aux */
+ if (amdgpu_ddc_probe(amdgpu_connector, true)) /* try DDC */
+ ret = connector_status_connected;
+ else if (amdgpu_connector->dac_load_detect) { /* try load detection */
+ const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+ ret = encoder_funcs->detect(encoder, connector);
+ }
+ }
+ } else {
+ amdgpu_dig_connector->dp_sink_type =
+ amdgpu_atombios_dp_get_sinktype(amdgpu_connector);
+ if (amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) {
+ ret = connector_status_connected;
+ if (amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
+ amdgpu_atombios_dp_get_dpcd(amdgpu_connector);
+ } else {
+ if (amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
+ if (!amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
+ ret = connector_status_connected;
+ } else {
+ /* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */
+ if (amdgpu_ddc_probe(amdgpu_connector, false))
+ ret = connector_status_connected;
+ }
+ }
+ }
+
+ amdgpu_connector_update_scratch_regs(connector, ret);
+out:
+ pm_runtime_mark_last_busy(connector->dev->dev);
+ pm_runtime_put_autosuspend(connector->dev->dev);
+
+ return ret;
+}
+
+static int amdgpu_connector_dp_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct amdgpu_connector_atom_dig *amdgpu_dig_connector = amdgpu_connector->con_priv;
+
+ /* XXX check mode bandwidth */
+
+ if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
+ (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
+ struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
+
+ if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
+ return MODE_PANEL;
+
+ if (encoder) {
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
+
+ /* AVIVO hardware supports downscaling modes larger than the panel
+ * to the panel size, but I'm not sure this is desirable.
+ */
+ if ((mode->hdisplay > native_mode->hdisplay) ||
+ (mode->vdisplay > native_mode->vdisplay))
+ return MODE_PANEL;
+
+ /* if scaling is disabled, block non-native modes */
+ if (amdgpu_encoder->rmx_type == RMX_OFF) {
+ if ((mode->hdisplay != native_mode->hdisplay) ||
+ (mode->vdisplay != native_mode->vdisplay))
+ return MODE_PANEL;
+ }
+ }
+ return MODE_OK;
+ } else {
+ if ((amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+ (amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
+ return amdgpu_atombios_dp_mode_valid_helper(connector, mode);
+ } else {
+ if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
+ /* HDMI 1.3+ supports max clock of 340 Mhz */
+ if (mode->clock > 340000)
+ return MODE_CLOCK_HIGH;
+ } else {
+ if (mode->clock > 165000)
+ return MODE_CLOCK_HIGH;
+ }
+ }
+ }
+
+ return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs amdgpu_connector_dp_helper_funcs = {
+ .get_modes = amdgpu_connector_dp_get_modes,
+ .mode_valid = amdgpu_connector_dp_mode_valid,
+ .best_encoder = amdgpu_connector_dvi_encoder,
+};
+
+static const struct drm_connector_funcs amdgpu_connector_dp_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = amdgpu_connector_dp_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .set_property = amdgpu_connector_set_property,
+ .destroy = amdgpu_connector_destroy,
+ .force = amdgpu_connector_dvi_force,
+};
+
+static const struct drm_connector_funcs amdgpu_connector_edp_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = amdgpu_connector_dp_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .set_property = amdgpu_connector_set_lcd_property,
+ .destroy = amdgpu_connector_destroy,
+ .force = amdgpu_connector_dvi_force,
+};
+
+void
+amdgpu_connector_add(struct amdgpu_device *adev,
+ uint32_t connector_id,
+ uint32_t supported_device,
+ int connector_type,
+ struct amdgpu_i2c_bus_rec *i2c_bus,
+ uint16_t connector_object_id,
+ struct amdgpu_hpd *hpd,
+ struct amdgpu_router *router)
+{
+ struct drm_device *dev = adev->ddev;
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector;
+ struct amdgpu_connector_atom_dig *amdgpu_dig_connector;
+ struct drm_encoder *encoder;
+ struct amdgpu_encoder *amdgpu_encoder;
+ uint32_t subpixel_order = SubPixelNone;
+ bool shared_ddc = false;
+ bool is_dp_bridge = false;
+ bool has_aux = false;
+
+ if (connector_type == DRM_MODE_CONNECTOR_Unknown)
+ return;
+
+ /* see if we already added it */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ amdgpu_connector = to_amdgpu_connector(connector);
+ if (amdgpu_connector->connector_id == connector_id) {
+ amdgpu_connector->devices |= supported_device;
+ return;
+ }
+ if (amdgpu_connector->ddc_bus && i2c_bus->valid) {
+ if (amdgpu_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) {
+ amdgpu_connector->shared_ddc = true;
+ shared_ddc = true;
+ }
+ if (amdgpu_connector->router_bus && router->ddc_valid &&
+ (amdgpu_connector->router.router_id == router->router_id)) {
+ amdgpu_connector->shared_ddc = false;
+ shared_ddc = false;
+ }
+ }
+ }
+
+ /* check if it's a dp bridge */
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+ if (amdgpu_encoder->devices & supported_device) {
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_TRAVIS:
+ case ENCODER_OBJECT_ID_NUTMEG:
+ is_dp_bridge = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ amdgpu_connector = kzalloc(sizeof(struct amdgpu_connector), GFP_KERNEL);
+ if (!amdgpu_connector)
+ return;
+
+ connector = &amdgpu_connector->base;
+
+ amdgpu_connector->connector_id = connector_id;
+ amdgpu_connector->devices = supported_device;
+ amdgpu_connector->shared_ddc = shared_ddc;
+ amdgpu_connector->connector_object_id = connector_object_id;
+ amdgpu_connector->hpd = *hpd;
+
+ amdgpu_connector->router = *router;
+ if (router->ddc_valid || router->cd_valid) {
+ amdgpu_connector->router_bus = amdgpu_i2c_lookup(adev, &router->i2c_info);
+ if (!amdgpu_connector->router_bus)
+ DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n");
+ }
+
+ if (is_dp_bridge) {
+ amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
+ if (!amdgpu_dig_connector)
+ goto failed;
+ amdgpu_connector->con_priv = amdgpu_dig_connector;
+ if (i2c_bus->valid) {
+ amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
+ if (amdgpu_connector->ddc_bus)
+ has_aux = true;
+ else
+ DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
+ switch (connector_type) {
+ case DRM_MODE_CONNECTOR_VGA:
+ case DRM_MODE_CONNECTOR_DVIA:
+ default:
+ drm_connector_init(dev, &amdgpu_connector->base,
+ &amdgpu_connector_dp_funcs, connector_type);
+ drm_connector_helper_add(&amdgpu_connector->base,
+ &amdgpu_connector_dp_helper_funcs);
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
+ amdgpu_connector->dac_load_detect = true;
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.load_detect_property,
+ 1);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_NONE);
+ break;
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ drm_connector_init(dev, &amdgpu_connector->base,
+ &amdgpu_connector_dp_funcs, connector_type);
+ drm_connector_helper_add(&amdgpu_connector->base,
+ &amdgpu_connector_dp_helper_funcs);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.underscan_property,
+ UNDERSCAN_OFF);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.underscan_hborder_property,
+ 0);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.underscan_vborder_property,
+ 0);
+
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_NONE);
+
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.dither_property,
+ AMDGPU_FMT_DITHER_DISABLE);
+
+ if (amdgpu_audio != 0)
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.audio_property,
+ AMDGPU_AUDIO_AUTO);
+
+ subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = true;
+ if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
+ connector->doublescan_allowed = true;
+ else
+ connector->doublescan_allowed = false;
+ if (connector_type == DRM_MODE_CONNECTOR_DVII) {
+ amdgpu_connector->dac_load_detect = true;
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.load_detect_property,
+ 1);
+ }
+ break;
+ case DRM_MODE_CONNECTOR_LVDS:
+ case DRM_MODE_CONNECTOR_eDP:
+ drm_connector_init(dev, &amdgpu_connector->base,
+ &amdgpu_connector_edp_funcs, connector_type);
+ drm_connector_helper_add(&amdgpu_connector->base,
+ &amdgpu_connector_dp_helper_funcs);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_FULLSCREEN);
+ subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
+ break;
+ }
+ } else {
+ switch (connector_type) {
+ case DRM_MODE_CONNECTOR_VGA:
+ drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_vga_funcs, connector_type);
+ drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_vga_helper_funcs);
+ if (i2c_bus->valid) {
+ amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
+ if (!amdgpu_connector->ddc_bus)
+ DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
+ amdgpu_connector->dac_load_detect = true;
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.load_detect_property,
+ 1);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_NONE);
+ /* no HPD on analog connectors */
+ amdgpu_connector->hpd.hpd = AMDGPU_HPD_NONE;
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
+ break;
+ case DRM_MODE_CONNECTOR_DVIA:
+ drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_vga_funcs, connector_type);
+ drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_vga_helper_funcs);
+ if (i2c_bus->valid) {
+ amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
+ if (!amdgpu_connector->ddc_bus)
+ DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
+ amdgpu_connector->dac_load_detect = true;
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.load_detect_property,
+ 1);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_NONE);
+ /* no HPD on analog connectors */
+ amdgpu_connector->hpd.hpd = AMDGPU_HPD_NONE;
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
+ break;
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_DVID:
+ amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
+ if (!amdgpu_dig_connector)
+ goto failed;
+ amdgpu_connector->con_priv = amdgpu_dig_connector;
+ drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_dvi_funcs, connector_type);
+ drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dvi_helper_funcs);
+ if (i2c_bus->valid) {
+ amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
+ if (!amdgpu_connector->ddc_bus)
+ DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
+ subpixel_order = SubPixelHorizontalRGB;
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.coherent_mode_property,
+ 1);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.underscan_property,
+ UNDERSCAN_OFF);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.underscan_hborder_property,
+ 0);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.underscan_vborder_property,
+ 0);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_NONE);
+
+ if (amdgpu_audio != 0) {
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.audio_property,
+ AMDGPU_AUDIO_AUTO);
+ }
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.dither_property,
+ AMDGPU_FMT_DITHER_DISABLE);
+ if (connector_type == DRM_MODE_CONNECTOR_DVII) {
+ amdgpu_connector->dac_load_detect = true;
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.load_detect_property,
+ 1);
+ }
+ connector->interlace_allowed = true;
+ if (connector_type == DRM_MODE_CONNECTOR_DVII)
+ connector->doublescan_allowed = true;
+ else
+ connector->doublescan_allowed = false;
+ break;
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
+ if (!amdgpu_dig_connector)
+ goto failed;
+ amdgpu_connector->con_priv = amdgpu_dig_connector;
+ drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_dvi_funcs, connector_type);
+ drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dvi_helper_funcs);
+ if (i2c_bus->valid) {
+ amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
+ if (!amdgpu_connector->ddc_bus)
+ DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.coherent_mode_property,
+ 1);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.underscan_property,
+ UNDERSCAN_OFF);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.underscan_hborder_property,
+ 0);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.underscan_vborder_property,
+ 0);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_NONE);
+ if (amdgpu_audio != 0) {
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.audio_property,
+ AMDGPU_AUDIO_AUTO);
+ }
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.dither_property,
+ AMDGPU_FMT_DITHER_DISABLE);
+ subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = true;
+ if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
+ connector->doublescan_allowed = true;
+ else
+ connector->doublescan_allowed = false;
+ break;
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
+ if (!amdgpu_dig_connector)
+ goto failed;
+ amdgpu_connector->con_priv = amdgpu_dig_connector;
+ drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_dp_funcs, connector_type);
+ drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dp_helper_funcs);
+ if (i2c_bus->valid) {
+ amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
+ if (amdgpu_connector->ddc_bus)
+ has_aux = true;
+ else
+ DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
+ subpixel_order = SubPixelHorizontalRGB;
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.coherent_mode_property,
+ 1);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.underscan_property,
+ UNDERSCAN_OFF);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.underscan_hborder_property,
+ 0);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.underscan_vborder_property,
+ 0);
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_NONE);
+ if (amdgpu_audio != 0) {
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.audio_property,
+ AMDGPU_AUDIO_AUTO);
+ }
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ adev->mode_info.dither_property,
+ AMDGPU_FMT_DITHER_DISABLE);
+ connector->interlace_allowed = true;
+ /* in theory with a DP to VGA converter... */
+ connector->doublescan_allowed = false;
+ break;
+ case DRM_MODE_CONNECTOR_eDP:
+ amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
+ if (!amdgpu_dig_connector)
+ goto failed;
+ amdgpu_connector->con_priv = amdgpu_dig_connector;
+ drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_edp_funcs, connector_type);
+ drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dp_helper_funcs);
+ if (i2c_bus->valid) {
+ amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
+ if (amdgpu_connector->ddc_bus)
+ has_aux = true;
+ else
+ DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_FULLSCREEN);
+ subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
+ break;
+ case DRM_MODE_CONNECTOR_LVDS:
+ amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
+ if (!amdgpu_dig_connector)
+ goto failed;
+ amdgpu_connector->con_priv = amdgpu_dig_connector;
+ drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_lvds_funcs, connector_type);
+ drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_lvds_helper_funcs);
+ if (i2c_bus->valid) {
+ amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
+ if (!amdgpu_connector->ddc_bus)
+ DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
+ drm_object_attach_property(&amdgpu_connector->base.base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_FULLSCREEN);
+ subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
+ break;
+ }
+ }
+
+ if (amdgpu_connector->hpd.hpd == AMDGPU_HPD_NONE) {
+ if (i2c_bus->valid)
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ } else
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+ connector->display_info.subpixel_order = subpixel_order;
+ drm_connector_register(connector);
+
+ if (has_aux)
+ amdgpu_atombios_dp_aux_init(amdgpu_connector);
+
+ return;
+
+failed:
+ drm_connector_cleanup(connector);
+ kfree(connector);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.h
new file mode 100644
index 000000000000..61fcef15ad72
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_CONNECTORS_H__
+#define __AMDGPU_CONNECTORS_H__
+
+struct edid *amdgpu_connector_edid(struct drm_connector *connector);
+void amdgpu_connector_hotplug(struct drm_connector *connector);
+int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector);
+u16 amdgpu_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector);
+bool amdgpu_connector_is_dp12_capable(struct drm_connector *connector);
+void
+amdgpu_connector_add(struct amdgpu_device *adev,
+ uint32_t connector_id,
+ uint32_t supported_device,
+ int connector_type,
+ struct amdgpu_i2c_bus_rec *i2c_bus,
+ uint16_t connector_object_id,
+ struct amdgpu_hpd *hpd,
+ struct amdgpu_router *router);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
new file mode 100644
index 000000000000..f09b2cba40ca
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -0,0 +1,796 @@
+/*
+ * Copyright 2008 Jerome Glisse.
+ * 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:
+ * Jerome Glisse <glisse@freedesktop.org>
+ */
+#include <linux/list_sort.h>
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "amdgpu_trace.h"
+
+#define AMDGPU_CS_MAX_PRIORITY 32u
+#define AMDGPU_CS_NUM_BUCKETS (AMDGPU_CS_MAX_PRIORITY + 1)
+
+/* This is based on the bucket sort with O(n) time complexity.
+ * An item with priority "i" is added to bucket[i]. The lists are then
+ * concatenated in descending order.
+ */
+struct amdgpu_cs_buckets {
+ struct list_head bucket[AMDGPU_CS_NUM_BUCKETS];
+};
+
+static void amdgpu_cs_buckets_init(struct amdgpu_cs_buckets *b)
+{
+ unsigned i;
+
+ for (i = 0; i < AMDGPU_CS_NUM_BUCKETS; i++)
+ INIT_LIST_HEAD(&b->bucket[i]);
+}
+
+static void amdgpu_cs_buckets_add(struct amdgpu_cs_buckets *b,
+ struct list_head *item, unsigned priority)
+{
+ /* Since buffers which appear sooner in the relocation list are
+ * likely to be used more often than buffers which appear later
+ * in the list, the sort mustn't change the ordering of buffers
+ * with the same priority, i.e. it must be stable.
+ */
+ list_add_tail(item, &b->bucket[min(priority, AMDGPU_CS_MAX_PRIORITY)]);
+}
+
+static void amdgpu_cs_buckets_get_list(struct amdgpu_cs_buckets *b,
+ struct list_head *out_list)
+{
+ unsigned i;
+
+ /* Connect the sorted buckets in the output list. */
+ for (i = 0; i < AMDGPU_CS_NUM_BUCKETS; i++) {
+ list_splice(&b->bucket[i], out_list);
+ }
+}
+
+int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
+ u32 ip_instance, u32 ring,
+ struct amdgpu_ring **out_ring)
+{
+ /* Right now all IPs have only one instance - multiple rings. */
+ if (ip_instance != 0) {
+ DRM_ERROR("invalid ip instance: %d\n", ip_instance);
+ return -EINVAL;
+ }
+
+ switch (ip_type) {
+ default:
+ DRM_ERROR("unknown ip type: %d\n", ip_type);
+ return -EINVAL;
+ case AMDGPU_HW_IP_GFX:
+ if (ring < adev->gfx.num_gfx_rings) {
+ *out_ring = &adev->gfx.gfx_ring[ring];
+ } else {
+ DRM_ERROR("only %d gfx rings are supported now\n",
+ adev->gfx.num_gfx_rings);
+ return -EINVAL;
+ }
+ break;
+ case AMDGPU_HW_IP_COMPUTE:
+ if (ring < adev->gfx.num_compute_rings) {
+ *out_ring = &adev->gfx.compute_ring[ring];
+ } else {
+ DRM_ERROR("only %d compute rings are supported now\n",
+ adev->gfx.num_compute_rings);
+ return -EINVAL;
+ }
+ break;
+ case AMDGPU_HW_IP_DMA:
+ if (ring < 2) {
+ *out_ring = &adev->sdma[ring].ring;
+ } else {
+ DRM_ERROR("only two SDMA rings are supported\n");
+ return -EINVAL;
+ }
+ break;
+ case AMDGPU_HW_IP_UVD:
+ *out_ring = &adev->uvd.ring;
+ break;
+ case AMDGPU_HW_IP_VCE:
+ if (ring < 2){
+ *out_ring = &adev->vce.ring[ring];
+ } else {
+ DRM_ERROR("only two VCE rings are supported\n");
+ return -EINVAL;
+ }
+ break;
+ }
+ return 0;
+}
+
+int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
+{
+ union drm_amdgpu_cs *cs = data;
+ uint64_t *chunk_array_user;
+ uint64_t *chunk_array = NULL;
+ struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
+ unsigned size, i;
+ int r = 0;
+
+ if (!cs->in.num_chunks)
+ goto out;
+
+ p->ctx = amdgpu_ctx_get(fpriv, cs->in.ctx_id);
+ if (!p->ctx) {
+ r = -EINVAL;
+ goto out;
+ }
+ p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle);
+
+ /* get chunks */
+ INIT_LIST_HEAD(&p->validated);
+ chunk_array = kcalloc(cs->in.num_chunks, sizeof(uint64_t), GFP_KERNEL);
+ if (chunk_array == NULL) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ chunk_array_user = (uint64_t *)(unsigned long)(cs->in.chunks);
+ if (copy_from_user(chunk_array, chunk_array_user,
+ sizeof(uint64_t)*cs->in.num_chunks)) {
+ r = -EFAULT;
+ goto out;
+ }
+
+ p->nchunks = cs->in.num_chunks;
+ p->chunks = kcalloc(p->nchunks, sizeof(struct amdgpu_cs_chunk),
+ GFP_KERNEL);
+ if (p->chunks == NULL) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < p->nchunks; i++) {
+ struct drm_amdgpu_cs_chunk __user **chunk_ptr = NULL;
+ struct drm_amdgpu_cs_chunk user_chunk;
+ uint32_t __user *cdata;
+
+ chunk_ptr = (void __user *)(unsigned long)chunk_array[i];
+ if (copy_from_user(&user_chunk, chunk_ptr,
+ sizeof(struct drm_amdgpu_cs_chunk))) {
+ r = -EFAULT;
+ goto out;
+ }
+ p->chunks[i].chunk_id = user_chunk.chunk_id;
+ p->chunks[i].length_dw = user_chunk.length_dw;
+ if (p->chunks[i].chunk_id == AMDGPU_CHUNK_ID_IB)
+ p->num_ibs++;
+
+ size = p->chunks[i].length_dw;
+ cdata = (void __user *)(unsigned long)user_chunk.chunk_data;
+ p->chunks[i].user_ptr = cdata;
+
+ p->chunks[i].kdata = drm_malloc_ab(size, sizeof(uint32_t));
+ if (p->chunks[i].kdata == NULL) {
+ r = -ENOMEM;
+ goto out;
+ }
+ size *= sizeof(uint32_t);
+ if (copy_from_user(p->chunks[i].kdata, cdata, size)) {
+ r = -EFAULT;
+ goto out;
+ }
+
+ if (p->chunks[i].chunk_id == AMDGPU_CHUNK_ID_FENCE) {
+ size = sizeof(struct drm_amdgpu_cs_chunk_fence);
+ if (p->chunks[i].length_dw * sizeof(uint32_t) >= size) {
+ uint32_t handle;
+ struct drm_gem_object *gobj;
+ struct drm_amdgpu_cs_chunk_fence *fence_data;
+
+ fence_data = (void *)p->chunks[i].kdata;
+ handle = fence_data->handle;
+ gobj = drm_gem_object_lookup(p->adev->ddev,
+ p->filp, handle);
+ if (gobj == NULL) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ p->uf.bo = gem_to_amdgpu_bo(gobj);
+ p->uf.offset = fence_data->offset;
+ } else {
+ r = -EINVAL;
+ goto out;
+ }
+ }
+ }
+
+ p->ibs = kcalloc(p->num_ibs, sizeof(struct amdgpu_ib), GFP_KERNEL);
+ if (!p->ibs) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+out:
+ kfree(chunk_array);
+ return r;
+}
+
+/* Returns how many bytes TTM can move per IB.
+ */
+static u64 amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev)
+{
+ u64 real_vram_size = adev->mc.real_vram_size;
+ u64 vram_usage = atomic64_read(&adev->vram_usage);
+
+ /* This function is based on the current VRAM usage.
+ *
+ * - If all of VRAM is free, allow relocating the number of bytes that
+ * is equal to 1/4 of the size of VRAM for this IB.
+
+ * - If more than one half of VRAM is occupied, only allow relocating
+ * 1 MB of data for this IB.
+ *
+ * - From 0 to one half of used VRAM, the threshold decreases
+ * linearly.
+ * __________________
+ * 1/4 of -|\ |
+ * VRAM | \ |
+ * | \ |
+ * | \ |
+ * | \ |
+ * | \ |
+ * | \ |
+ * | \________|1 MB
+ * |----------------|
+ * VRAM 0 % 100 %
+ * used used
+ *
+ * Note: It's a threshold, not a limit. The threshold must be crossed
+ * for buffer relocations to stop, so any buffer of an arbitrary size
+ * can be moved as long as the threshold isn't crossed before
+ * the relocation takes place. We don't want to disable buffer
+ * relocations completely.
+ *
+ * The idea is that buffers should be placed in VRAM at creation time
+ * and TTM should only do a minimum number of relocations during
+ * command submission. In practice, you need to submit at least
+ * a dozen IBs to move all buffers to VRAM if they are in GTT.
+ *
+ * Also, things can get pretty crazy under memory pressure and actual
+ * VRAM usage can change a lot, so playing safe even at 50% does
+ * consistently increase performance.
+ */
+
+ u64 half_vram = real_vram_size >> 1;
+ u64 half_free_vram = vram_usage >= half_vram ? 0 : half_vram - vram_usage;
+ u64 bytes_moved_threshold = half_free_vram >> 1;
+ return max(bytes_moved_threshold, 1024*1024ull);
+}
+
+int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p)
+{
+ struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
+ struct amdgpu_vm *vm = &fpriv->vm;
+ struct amdgpu_device *adev = p->adev;
+ struct amdgpu_bo_list_entry *lobj;
+ struct list_head duplicates;
+ struct amdgpu_bo *bo;
+ u64 bytes_moved = 0, initial_bytes_moved;
+ u64 bytes_moved_threshold = amdgpu_cs_get_threshold_for_moves(adev);
+ int r;
+
+ INIT_LIST_HEAD(&duplicates);
+ r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true, &duplicates);
+ if (unlikely(r != 0)) {
+ return r;
+ }
+
+ list_for_each_entry(lobj, &p->validated, tv.head) {
+ bo = lobj->robj;
+ if (!bo->pin_count) {
+ u32 domain = lobj->prefered_domains;
+ u32 current_domain =
+ amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type);
+
+ /* Check if this buffer will be moved and don't move it
+ * if we have moved too many buffers for this IB already.
+ *
+ * Note that this allows moving at least one buffer of
+ * any size, because it doesn't take the current "bo"
+ * into account. We don't want to disallow buffer moves
+ * completely.
+ */
+ if (current_domain != AMDGPU_GEM_DOMAIN_CPU &&
+ (domain & current_domain) == 0 && /* will be moved */
+ bytes_moved > bytes_moved_threshold) {
+ /* don't move it */
+ domain = current_domain;
+ }
+
+ retry:
+ amdgpu_ttm_placement_from_domain(bo, domain);
+ initial_bytes_moved = atomic64_read(&adev->num_bytes_moved);
+ r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
+ bytes_moved += atomic64_read(&adev->num_bytes_moved) -
+ initial_bytes_moved;
+
+ if (unlikely(r)) {
+ if (r != -ERESTARTSYS && domain != lobj->allowed_domains) {
+ domain = lobj->allowed_domains;
+ goto retry;
+ }
+ ttm_eu_backoff_reservation(&p->ticket, &p->validated);
+ return r;
+ }
+ }
+ lobj->bo_va = amdgpu_vm_bo_find(vm, bo);
+ }
+ return 0;
+}
+
+static int amdgpu_cs_parser_relocs(struct amdgpu_cs_parser *p)
+{
+ struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
+ struct amdgpu_cs_buckets buckets;
+ bool need_mmap_lock = false;
+ int i, r;
+
+ if (p->bo_list) {
+ need_mmap_lock = p->bo_list->has_userptr;
+ amdgpu_cs_buckets_init(&buckets);
+ for (i = 0; i < p->bo_list->num_entries; i++)
+ amdgpu_cs_buckets_add(&buckets, &p->bo_list->array[i].tv.head,
+ p->bo_list->array[i].priority);
+
+ amdgpu_cs_buckets_get_list(&buckets, &p->validated);
+ }
+
+ p->vm_bos = amdgpu_vm_get_bos(p->adev, &fpriv->vm,
+ &p->validated);
+
+ if (need_mmap_lock)
+ down_read(&current->mm->mmap_sem);
+
+ r = amdgpu_cs_list_validate(p);
+
+ if (need_mmap_lock)
+ up_read(&current->mm->mmap_sem);
+
+ return r;
+}
+
+static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)
+{
+ struct amdgpu_bo_list_entry *e;
+ int r;
+
+ list_for_each_entry(e, &p->validated, tv.head) {
+ struct reservation_object *resv = e->robj->tbo.resv;
+ r = amdgpu_sync_resv(p->adev, &p->ibs[0].sync, resv, p->filp);
+
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
+static int cmp_size_smaller_first(void *priv, struct list_head *a,
+ struct list_head *b)
+{
+ struct amdgpu_bo_list_entry *la = list_entry(a, struct amdgpu_bo_list_entry, tv.head);
+ struct amdgpu_bo_list_entry *lb = list_entry(b, struct amdgpu_bo_list_entry, tv.head);
+
+ /* Sort A before B if A is smaller. */
+ return (int)la->robj->tbo.num_pages - (int)lb->robj->tbo.num_pages;
+}
+
+/**
+ * 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 amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bool backoff)
+{
+ unsigned i;
+
+ if (!error) {
+ /* Sort the buffer list from the smallest to largest buffer,
+ * which affects the order of buffers in the LRU list.
+ * This assures that the smallest buffers are added first
+ * to the LRU list, so they are likely to be later evicted
+ * first, instead of large buffers whose eviction is more
+ * expensive.
+ *
+ * This slightly lowers the number of bytes moved by TTM
+ * per frame under memory pressure.
+ */
+ list_sort(NULL, &parser->validated, cmp_size_smaller_first);
+
+ ttm_eu_fence_buffer_objects(&parser->ticket,
+ &parser->validated,
+ &parser->ibs[parser->num_ibs-1].fence->base);
+ } else if (backoff) {
+ ttm_eu_backoff_reservation(&parser->ticket,
+ &parser->validated);
+ }
+
+ if (parser->ctx)
+ amdgpu_ctx_put(parser->ctx);
+ 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);
+ for (i = 0; i < parser->num_ibs; i++)
+ amdgpu_ib_free(parser->adev, &parser->ibs[i]);
+ kfree(parser->ibs);
+ if (parser->uf.bo)
+ drm_gem_object_unreference_unlocked(&parser->uf.bo->gem_base);
+}
+
+static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p,
+ struct amdgpu_vm *vm)
+{
+ struct amdgpu_device *adev = p->adev;
+ struct amdgpu_bo_va *bo_va;
+ struct amdgpu_bo *bo;
+ int i, r;
+
+ r = amdgpu_vm_update_page_directory(adev, vm);
+ if (r)
+ return r;
+
+ r = amdgpu_vm_clear_freed(adev, vm);
+ if (r)
+ return r;
+
+ if (p->bo_list) {
+ for (i = 0; i < p->bo_list->num_entries; i++) {
+ /* ignore duplicates */
+ bo = p->bo_list->array[i].robj;
+ if (!bo)
+ continue;
+
+ bo_va = p->bo_list->array[i].bo_va;
+ if (bo_va == NULL)
+ continue;
+
+ r = amdgpu_vm_bo_update(adev, bo_va, &bo->tbo.mem);
+ if (r)
+ return r;
+
+ amdgpu_sync_fence(&p->ibs[0].sync, bo_va->last_pt_update);
+ }
+ }
+
+ return amdgpu_vm_clear_invalids(adev, vm, &p->ibs[0].sync);
+}
+
+static int amdgpu_cs_ib_vm_chunk(struct amdgpu_device *adev,
+ struct amdgpu_cs_parser *parser)
+{
+ struct amdgpu_fpriv *fpriv = parser->filp->driver_priv;
+ struct amdgpu_vm *vm = &fpriv->vm;
+ struct amdgpu_ring *ring;
+ int i, r;
+
+ if (parser->num_ibs == 0)
+ return 0;
+
+ /* Only for UVD/VCE VM emulation */
+ for (i = 0; i < parser->num_ibs; i++) {
+ ring = parser->ibs[i].ring;
+ if (ring->funcs->parse_cs) {
+ r = amdgpu_ring_parse_cs(ring, parser, i);
+ if (r)
+ return r;
+ }
+ }
+
+ mutex_lock(&vm->mutex);
+ r = amdgpu_bo_vm_update_pte(parser, vm);
+ if (r) {
+ goto out;
+ }
+ amdgpu_cs_sync_rings(parser);
+
+ r = amdgpu_ib_schedule(adev, parser->num_ibs, parser->ibs,
+ parser->filp);
+
+out:
+ mutex_unlock(&vm->mutex);
+ return r;
+}
+
+static int amdgpu_cs_handle_lockup(struct amdgpu_device *adev, int r)
+{
+ if (r == -EDEADLK) {
+ r = amdgpu_gpu_reset(adev);
+ if (!r)
+ r = -EAGAIN;
+ }
+ return r;
+}
+
+static int amdgpu_cs_ib_fill(struct amdgpu_device *adev,
+ struct amdgpu_cs_parser *parser)
+{
+ struct amdgpu_fpriv *fpriv = parser->filp->driver_priv;
+ struct amdgpu_vm *vm = &fpriv->vm;
+ int i, j;
+ int r;
+
+ for (i = 0, j = 0; i < parser->nchunks && j < parser->num_ibs; i++) {
+ struct amdgpu_cs_chunk *chunk;
+ struct amdgpu_ib *ib;
+ struct drm_amdgpu_cs_chunk_ib *chunk_ib;
+ struct amdgpu_ring *ring;
+
+ chunk = &parser->chunks[i];
+ ib = &parser->ibs[j];
+ chunk_ib = (struct drm_amdgpu_cs_chunk_ib *)chunk->kdata;
+
+ if (chunk->chunk_id != AMDGPU_CHUNK_ID_IB)
+ continue;
+
+ r = amdgpu_cs_get_ring(adev, chunk_ib->ip_type,
+ chunk_ib->ip_instance, chunk_ib->ring,
+ &ring);
+ if (r)
+ return r;
+
+ if (ring->funcs->parse_cs) {
+ struct amdgpu_bo_va_mapping *m;
+ struct amdgpu_bo *aobj = NULL;
+ uint64_t offset;
+ uint8_t *kptr;
+
+ m = amdgpu_cs_find_mapping(parser, chunk_ib->va_start,
+ &aobj);
+ if (!aobj) {
+ DRM_ERROR("IB va_start is invalid\n");
+ return -EINVAL;
+ }
+
+ if ((chunk_ib->va_start + chunk_ib->ib_bytes) >
+ (m->it.last + 1) * AMDGPU_GPU_PAGE_SIZE) {
+ DRM_ERROR("IB va_start+ib_bytes is invalid\n");
+ return -EINVAL;
+ }
+
+ /* the IB should be reserved at this point */
+ r = amdgpu_bo_kmap(aobj, (void **)&kptr);
+ if (r) {
+ return r;
+ }
+
+ offset = ((uint64_t)m->it.start) * AMDGPU_GPU_PAGE_SIZE;
+ kptr += chunk_ib->va_start - offset;
+
+ r = amdgpu_ib_get(ring, NULL, chunk_ib->ib_bytes, ib);
+ if (r) {
+ DRM_ERROR("Failed to get ib !\n");
+ return r;
+ }
+
+ memcpy(ib->ptr, kptr, chunk_ib->ib_bytes);
+ amdgpu_bo_kunmap(aobj);
+ } else {
+ r = amdgpu_ib_get(ring, vm, 0, ib);
+ if (r) {
+ DRM_ERROR("Failed to get ib !\n");
+ return r;
+ }
+
+ ib->gpu_addr = chunk_ib->va_start;
+ }
+
+ ib->length_dw = chunk_ib->ib_bytes / 4;
+ ib->flags = chunk_ib->flags;
+ ib->ctx = parser->ctx;
+ j++;
+ }
+
+ if (!parser->num_ibs)
+ return 0;
+
+ /* add GDS resources to first IB */
+ if (parser->bo_list) {
+ struct amdgpu_bo *gds = parser->bo_list->gds_obj;
+ struct amdgpu_bo *gws = parser->bo_list->gws_obj;
+ struct amdgpu_bo *oa = parser->bo_list->oa_obj;
+ struct amdgpu_ib *ib = &parser->ibs[0];
+
+ if (gds) {
+ ib->gds_base = amdgpu_bo_gpu_offset(gds);
+ ib->gds_size = amdgpu_bo_size(gds);
+ }
+ if (gws) {
+ ib->gws_base = amdgpu_bo_gpu_offset(gws);
+ ib->gws_size = amdgpu_bo_size(gws);
+ }
+ if (oa) {
+ ib->oa_base = amdgpu_bo_gpu_offset(oa);
+ ib->oa_size = amdgpu_bo_size(oa);
+ }
+ }
+
+ /* wrap the last IB with user fence */
+ if (parser->uf.bo) {
+ struct amdgpu_ib *ib = &parser->ibs[parser->num_ibs - 1];
+
+ /* UVD & VCE fw doesn't support user fences */
+ if (ib->ring->type == AMDGPU_RING_TYPE_UVD ||
+ ib->ring->type == AMDGPU_RING_TYPE_VCE)
+ return -EINVAL;
+
+ ib->user = &parser->uf;
+ }
+
+ return 0;
+}
+
+int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ union drm_amdgpu_cs *cs = data;
+ struct amdgpu_cs_parser parser;
+ int r, i;
+ bool reserved_buffers = false;
+
+ down_read(&adev->exclusive_lock);
+ if (!adev->accel_working) {
+ up_read(&adev->exclusive_lock);
+ return -EBUSY;
+ }
+ /* initialize parser */
+ memset(&parser, 0, sizeof(struct amdgpu_cs_parser));
+ parser.filp = filp;
+ parser.adev = adev;
+ r = amdgpu_cs_parser_init(&parser, data);
+ if (r) {
+ DRM_ERROR("Failed to initialize parser !\n");
+ amdgpu_cs_parser_fini(&parser, r, false);
+ up_read(&adev->exclusive_lock);
+ r = amdgpu_cs_handle_lockup(adev, r);
+ return r;
+ }
+
+ r = amdgpu_cs_parser_relocs(&parser);
+ if (r) {
+ if (r != -ERESTARTSYS) {
+ if (r == -ENOMEM)
+ DRM_ERROR("Not enough memory for command submission!\n");
+ else
+ DRM_ERROR("Failed to process the buffer list %d!\n", r);
+ }
+ } else {
+ reserved_buffers = true;
+ r = amdgpu_cs_ib_fill(adev, &parser);
+ }
+
+ if (r) {
+ amdgpu_cs_parser_fini(&parser, r, reserved_buffers);
+ up_read(&adev->exclusive_lock);
+ r = amdgpu_cs_handle_lockup(adev, r);
+ return r;
+ }
+
+ for (i = 0; i < parser.num_ibs; i++)
+ trace_amdgpu_cs(&parser, i);
+
+ r = amdgpu_cs_ib_vm_chunk(adev, &parser);
+ if (r) {
+ goto out;
+ }
+
+ cs->out.handle = parser.ibs[parser.num_ibs - 1].fence->seq;
+out:
+ amdgpu_cs_parser_fini(&parser, r, true);
+ up_read(&adev->exclusive_lock);
+ r = amdgpu_cs_handle_lockup(adev, r);
+ return r;
+}
+
+/**
+ * amdgpu_cs_wait_ioctl - wait for a command submission to finish
+ *
+ * @dev: drm device
+ * @data: data from userspace
+ * @filp: file private
+ *
+ * Wait for the command submission identified by handle to finish.
+ */
+int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ union drm_amdgpu_wait_cs *wait = data;
+ struct amdgpu_device *adev = dev->dev_private;
+ uint64_t seq[AMDGPU_MAX_RINGS] = {0};
+ struct amdgpu_ring *ring = NULL;
+ unsigned long timeout = amdgpu_gem_timeout(wait->in.timeout);
+ struct amdgpu_ctx *ctx;
+ long r;
+
+ ctx = amdgpu_ctx_get(filp->driver_priv, wait->in.ctx_id);
+ if (ctx == NULL)
+ return -EINVAL;
+
+ r = amdgpu_cs_get_ring(adev, wait->in.ip_type, wait->in.ip_instance,
+ wait->in.ring, &ring);
+ if (r)
+ return r;
+
+ seq[ring->idx] = wait->in.handle;
+
+ r = amdgpu_fence_wait_seq_timeout(adev, seq, true, timeout);
+ amdgpu_ctx_put(ctx);
+ if (r < 0)
+ return r;
+
+ memset(wait, 0, sizeof(*wait));
+ wait->out.status = (r == 0);
+
+ return 0;
+}
+
+/**
+ * amdgpu_cs_find_bo_va - find bo_va for VM address
+ *
+ * @parser: command submission parser context
+ * @addr: VM address
+ * @bo: resulting BO of the mapping found
+ *
+ * Search the buffer objects in the command submission context for a certain
+ * virtual memory address. Returns allocation structure when found, NULL
+ * otherwise.
+ */
+struct amdgpu_bo_va_mapping *
+amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
+ uint64_t addr, struct amdgpu_bo **bo)
+{
+ struct amdgpu_bo_list_entry *reloc;
+ struct amdgpu_bo_va_mapping *mapping;
+
+ addr /= AMDGPU_GPU_PAGE_SIZE;
+
+ list_for_each_entry(reloc, &parser->validated, tv.head) {
+ if (!reloc->bo_va)
+ continue;
+
+ list_for_each_entry(mapping, &reloc->bo_va->mappings, list) {
+ if (mapping->it.start > addr ||
+ addr > mapping->it.last)
+ continue;
+
+ *bo = reloc->bo_va->bo;
+ return mapping;
+ }
+ }
+
+ return NULL;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
new file mode 100644
index 000000000000..6c66ac8a1891
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
@@ -0,0 +1,193 @@
+/*
+ * 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: monk liu <monk.liu@amd.com>
+ */
+
+#include <drm/drmP.h>
+#include "amdgpu.h"
+
+static void amdgpu_ctx_do_release(struct kref *ref)
+{
+ struct amdgpu_ctx *ctx;
+ struct amdgpu_ctx_mgr *mgr;
+
+ ctx = container_of(ref, struct amdgpu_ctx, refcount);
+ mgr = &ctx->fpriv->ctx_mgr;
+
+ idr_remove(&mgr->ctx_handles, ctx->id);
+ kfree(ctx);
+}
+
+int amdgpu_ctx_alloc(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv, uint32_t *id, uint32_t flags)
+{
+ int r;
+ struct amdgpu_ctx *ctx;
+ struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
+
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ mutex_lock(&mgr->lock);
+ r = idr_alloc(&mgr->ctx_handles, ctx, 0, 0, GFP_KERNEL);
+ if (r < 0) {
+ mutex_unlock(&mgr->lock);
+ kfree(ctx);
+ return r;
+ }
+ *id = (uint32_t)r;
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->id = *id;
+ ctx->fpriv = fpriv;
+ kref_init(&ctx->refcount);
+ mutex_unlock(&mgr->lock);
+
+ return 0;
+}
+
+int amdgpu_ctx_free(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv, uint32_t id)
+{
+ struct amdgpu_ctx *ctx;
+ struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
+
+ mutex_lock(&mgr->lock);
+ ctx = idr_find(&mgr->ctx_handles, id);
+ if (ctx) {
+ kref_put(&ctx->refcount, amdgpu_ctx_do_release);
+ mutex_unlock(&mgr->lock);
+ return 0;
+ }
+ mutex_unlock(&mgr->lock);
+ return -EINVAL;
+}
+
+static int amdgpu_ctx_query(struct amdgpu_device *adev,
+ struct amdgpu_fpriv *fpriv, uint32_t id,
+ union drm_amdgpu_ctx_out *out)
+{
+ struct amdgpu_ctx *ctx;
+ struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
+ unsigned reset_counter;
+
+ mutex_lock(&mgr->lock);
+ ctx = idr_find(&mgr->ctx_handles, id);
+ if (!ctx) {
+ mutex_unlock(&mgr->lock);
+ return -EINVAL;
+ }
+
+ /* TODO: these two are always zero */
+ out->state.flags = ctx->state.flags;
+ out->state.hangs = ctx->state.hangs;
+
+ /* determine if a GPU reset has occured since the last call */
+ reset_counter = atomic_read(&adev->gpu_reset_counter);
+ /* TODO: this should ideally return NO, GUILTY, or INNOCENT. */
+ if (ctx->reset_counter == reset_counter)
+ out->state.reset_status = AMDGPU_CTX_NO_RESET;
+ else
+ out->state.reset_status = AMDGPU_CTX_UNKNOWN_RESET;
+ ctx->reset_counter = reset_counter;
+
+ mutex_unlock(&mgr->lock);
+ return 0;
+}
+
+void amdgpu_ctx_fini(struct amdgpu_fpriv *fpriv)
+{
+ struct idr *idp;
+ struct amdgpu_ctx *ctx;
+ uint32_t id;
+ struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
+ idp = &mgr->ctx_handles;
+
+ idr_for_each_entry(idp,ctx,id) {
+ if (kref_put(&ctx->refcount, amdgpu_ctx_do_release) != 1)
+ DRM_ERROR("ctx (id=%ul) is still alive\n",ctx->id);
+ }
+
+ mutex_destroy(&mgr->lock);
+}
+
+int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ int r;
+ uint32_t id;
+ uint32_t flags;
+
+ union drm_amdgpu_ctx *args = data;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_fpriv *fpriv = filp->driver_priv;
+
+ r = 0;
+ id = args->in.ctx_id;
+ flags = args->in.flags;
+
+ switch (args->in.op) {
+ case AMDGPU_CTX_OP_ALLOC_CTX:
+ r = amdgpu_ctx_alloc(adev, fpriv, &id, flags);
+ args->out.alloc.ctx_id = id;
+ break;
+ case AMDGPU_CTX_OP_FREE_CTX:
+ r = amdgpu_ctx_free(adev, fpriv, id);
+ break;
+ case AMDGPU_CTX_OP_QUERY_STATE:
+ r = amdgpu_ctx_query(adev, fpriv, id, &args->out);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return r;
+}
+
+struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id)
+{
+ struct amdgpu_ctx *ctx;
+ struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
+
+ mutex_lock(&mgr->lock);
+ ctx = idr_find(&mgr->ctx_handles, id);
+ if (ctx)
+ kref_get(&ctx->refcount);
+ mutex_unlock(&mgr->lock);
+ return ctx;
+}
+
+int amdgpu_ctx_put(struct amdgpu_ctx *ctx)
+{
+ struct amdgpu_fpriv *fpriv;
+ struct amdgpu_ctx_mgr *mgr;
+
+ if (ctx == NULL)
+ return -EINVAL;
+
+ fpriv = ctx->fpriv;
+ mgr = &fpriv->ctx_mgr;
+ mutex_lock(&mgr->lock);
+ kref_put(&ctx->refcount, amdgpu_ctx_do_release);
+ mutex_unlock(&mgr->lock);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
new file mode 100644
index 000000000000..fec487d1c870
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -0,0 +1,2003 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#include <linux/console.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/amdgpu_drm.h>
+#include <linux/vgaarb.h>
+#include <linux/vga_switcheroo.h>
+#include <linux/efi.h>
+#include "amdgpu.h"
+#include "amdgpu_i2c.h"
+#include "atom.h"
+#include "amdgpu_atombios.h"
+#ifdef CONFIG_DRM_AMDGPU_CIK
+#include "cik.h"
+#endif
+#include "vi.h"
+#include "bif/bif_4_1_d.h"
+
+static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev);
+static void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev);
+
+static const char *amdgpu_asic_name[] = {
+ "BONAIRE",
+ "KAVERI",
+ "KABINI",
+ "HAWAII",
+ "MULLINS",
+ "TOPAZ",
+ "TONGA",
+ "CARRIZO",
+ "LAST",
+};
+
+bool amdgpu_device_is_px(struct drm_device *dev)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+
+ if (adev->flags & AMDGPU_IS_PX)
+ return true;
+ return false;
+}
+
+/*
+ * MMIO register access helper functions.
+ */
+uint32_t amdgpu_mm_rreg(struct amdgpu_device *adev, uint32_t reg,
+ bool always_indirect)
+{
+ if ((reg * 4) < adev->rmmio_size && !always_indirect)
+ return readl(((void __iomem *)adev->rmmio) + (reg * 4));
+ else {
+ unsigned long flags;
+ uint32_t ret;
+
+ spin_lock_irqsave(&adev->mmio_idx_lock, flags);
+ writel((reg * 4), ((void __iomem *)adev->rmmio) + (mmMM_INDEX * 4));
+ ret = readl(((void __iomem *)adev->rmmio) + (mmMM_DATA * 4));
+ spin_unlock_irqrestore(&adev->mmio_idx_lock, flags);
+
+ return ret;
+ }
+}
+
+void amdgpu_mm_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v,
+ bool always_indirect)
+{
+ if ((reg * 4) < adev->rmmio_size && !always_indirect)
+ writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
+ else {
+ unsigned long flags;
+
+ spin_lock_irqsave(&adev->mmio_idx_lock, flags);
+ writel((reg * 4), ((void __iomem *)adev->rmmio) + (mmMM_INDEX * 4));
+ writel(v, ((void __iomem *)adev->rmmio) + (mmMM_DATA * 4));
+ spin_unlock_irqrestore(&adev->mmio_idx_lock, flags);
+ }
+}
+
+u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg)
+{
+ if ((reg * 4) < adev->rio_mem_size)
+ return ioread32(adev->rio_mem + (reg * 4));
+ else {
+ iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4));
+ return ioread32(adev->rio_mem + (mmMM_DATA * 4));
+ }
+}
+
+void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
+{
+
+ if ((reg * 4) < adev->rio_mem_size)
+ iowrite32(v, adev->rio_mem + (reg * 4));
+ else {
+ iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4));
+ iowrite32(v, adev->rio_mem + (mmMM_DATA * 4));
+ }
+}
+
+/**
+ * amdgpu_mm_rdoorbell - read a doorbell dword
+ *
+ * @adev: amdgpu_device pointer
+ * @index: doorbell index
+ *
+ * Returns the value in the doorbell aperture at the
+ * requested doorbell index (CIK).
+ */
+u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 index)
+{
+ if (index < adev->doorbell.num_doorbells) {
+ return readl(adev->doorbell.ptr + index);
+ } else {
+ DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index);
+ return 0;
+ }
+}
+
+/**
+ * amdgpu_mm_wdoorbell - write a doorbell dword
+ *
+ * @adev: amdgpu_device pointer
+ * @index: doorbell index
+ * @v: value to write
+ *
+ * Writes @v to the doorbell aperture at the
+ * requested doorbell index (CIK).
+ */
+void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v)
+{
+ if (index < adev->doorbell.num_doorbells) {
+ writel(v, adev->doorbell.ptr + index);
+ } else {
+ DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
+ }
+}
+
+/**
+ * amdgpu_invalid_rreg - dummy reg read function
+ *
+ * @adev: amdgpu device pointer
+ * @reg: offset of register
+ *
+ * Dummy register read function. Used for register blocks
+ * that certain asics don't have (all asics).
+ * Returns the value in the register.
+ */
+static uint32_t amdgpu_invalid_rreg(struct amdgpu_device *adev, uint32_t reg)
+{
+ DRM_ERROR("Invalid callback to read register 0x%04X\n", reg);
+ BUG();
+ return 0;
+}
+
+/**
+ * amdgpu_invalid_wreg - dummy reg write function
+ *
+ * @adev: amdgpu device pointer
+ * @reg: offset of register
+ * @v: value to write to the register
+ *
+ * Dummy register read function. Used for register blocks
+ * that certain asics don't have (all asics).
+ */
+static void amdgpu_invalid_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v)
+{
+ DRM_ERROR("Invalid callback to write register 0x%04X with 0x%08X\n",
+ reg, v);
+ BUG();
+}
+
+/**
+ * amdgpu_block_invalid_rreg - dummy reg read function
+ *
+ * @adev: amdgpu device pointer
+ * @block: offset of instance
+ * @reg: offset of register
+ *
+ * Dummy register read function. Used for register blocks
+ * that certain asics don't have (all asics).
+ * Returns the value in the register.
+ */
+static uint32_t amdgpu_block_invalid_rreg(struct amdgpu_device *adev,
+ uint32_t block, uint32_t reg)
+{
+ DRM_ERROR("Invalid callback to read register 0x%04X in block 0x%04X\n",
+ reg, block);
+ BUG();
+ return 0;
+}
+
+/**
+ * amdgpu_block_invalid_wreg - dummy reg write function
+ *
+ * @adev: amdgpu device pointer
+ * @block: offset of instance
+ * @reg: offset of register
+ * @v: value to write to the register
+ *
+ * Dummy register read function. Used for register blocks
+ * that certain asics don't have (all asics).
+ */
+static void amdgpu_block_invalid_wreg(struct amdgpu_device *adev,
+ uint32_t block,
+ uint32_t reg, uint32_t v)
+{
+ DRM_ERROR("Invalid block callback to write register 0x%04X in block 0x%04X with 0x%08X\n",
+ reg, block, v);
+ BUG();
+}
+
+static int amdgpu_vram_scratch_init(struct amdgpu_device *adev)
+{
+ int r;
+
+ if (adev->vram_scratch.robj == NULL) {
+ r = amdgpu_bo_create(adev, AMDGPU_GPU_PAGE_SIZE,
+ PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, 0,
+ NULL, &adev->vram_scratch.robj);
+ if (r) {
+ return r;
+ }
+ }
+
+ r = amdgpu_bo_reserve(adev->vram_scratch.robj, false);
+ if (unlikely(r != 0))
+ return r;
+ r = amdgpu_bo_pin(adev->vram_scratch.robj,
+ AMDGPU_GEM_DOMAIN_VRAM, &adev->vram_scratch.gpu_addr);
+ if (r) {
+ amdgpu_bo_unreserve(adev->vram_scratch.robj);
+ return r;
+ }
+ r = amdgpu_bo_kmap(adev->vram_scratch.robj,
+ (void **)&adev->vram_scratch.ptr);
+ if (r)
+ amdgpu_bo_unpin(adev->vram_scratch.robj);
+ amdgpu_bo_unreserve(adev->vram_scratch.robj);
+
+ return r;
+}
+
+static void amdgpu_vram_scratch_fini(struct amdgpu_device *adev)
+{
+ int r;
+
+ if (adev->vram_scratch.robj == NULL) {
+ return;
+ }
+ r = amdgpu_bo_reserve(adev->vram_scratch.robj, false);
+ if (likely(r == 0)) {
+ amdgpu_bo_kunmap(adev->vram_scratch.robj);
+ amdgpu_bo_unpin(adev->vram_scratch.robj);
+ amdgpu_bo_unreserve(adev->vram_scratch.robj);
+ }
+ amdgpu_bo_unref(&adev->vram_scratch.robj);
+}
+
+/**
+ * amdgpu_program_register_sequence - program an array of registers.
+ *
+ * @adev: amdgpu_device pointer
+ * @registers: pointer to the register array
+ * @array_size: size of the register array
+ *
+ * Programs an array or registers with and and or masks.
+ * This is a helper for setting golden registers.
+ */
+void amdgpu_program_register_sequence(struct amdgpu_device *adev,
+ const u32 *registers,
+ const u32 array_size)
+{
+ u32 tmp, reg, and_mask, or_mask;
+ int i;
+
+ if (array_size % 3)
+ return;
+
+ for (i = 0; i < array_size; i +=3) {
+ reg = registers[i + 0];
+ and_mask = registers[i + 1];
+ or_mask = registers[i + 2];
+
+ if (and_mask == 0xffffffff) {
+ tmp = or_mask;
+ } else {
+ tmp = RREG32(reg);
+ tmp &= ~and_mask;
+ tmp |= or_mask;
+ }
+ WREG32(reg, tmp);
+ }
+}
+
+void amdgpu_pci_config_reset(struct amdgpu_device *adev)
+{
+ pci_write_config_dword(adev->pdev, 0x7c, AMDGPU_ASIC_RESET_DATA);
+}
+
+/*
+ * GPU doorbell aperture helpers function.
+ */
+/**
+ * amdgpu_doorbell_init - Init doorbell driver information.
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Init doorbell driver information (CIK)
+ * Returns 0 on success, error on failure.
+ */
+static int amdgpu_doorbell_init(struct amdgpu_device *adev)
+{
+ /* doorbell bar mapping */
+ adev->doorbell.base = pci_resource_start(adev->pdev, 2);
+ adev->doorbell.size = pci_resource_len(adev->pdev, 2);
+
+ adev->doorbell.num_doorbells = min_t(u32, adev->doorbell.size / sizeof(u32),
+ AMDGPU_DOORBELL_MAX_ASSIGNMENT+1);
+ if (adev->doorbell.num_doorbells == 0)
+ return -EINVAL;
+
+ adev->doorbell.ptr = ioremap(adev->doorbell.base, adev->doorbell.num_doorbells * sizeof(u32));
+ if (adev->doorbell.ptr == NULL) {
+ return -ENOMEM;
+ }
+ DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)adev->doorbell.base);
+ DRM_INFO("doorbell mmio size: %u\n", (unsigned)adev->doorbell.size);
+
+ return 0;
+}
+
+/**
+ * amdgpu_doorbell_fini - Tear down doorbell driver information.
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Tear down doorbell driver information (CIK)
+ */
+static void amdgpu_doorbell_fini(struct amdgpu_device *adev)
+{
+ iounmap(adev->doorbell.ptr);
+ adev->doorbell.ptr = NULL;
+}
+
+/**
+ * amdgpu_doorbell_get_kfd_info - Report doorbell configuration required to
+ * setup amdkfd
+ *
+ * @adev: amdgpu_device pointer
+ * @aperture_base: output returning doorbell aperture base physical address
+ * @aperture_size: output returning doorbell aperture size in bytes
+ * @start_offset: output returning # of doorbell bytes reserved for amdgpu.
+ *
+ * amdgpu and amdkfd share the doorbell aperture. amdgpu sets it up,
+ * takes doorbells required for its own rings and reports the setup to amdkfd.
+ * amdgpu reserved doorbells are at the start of the doorbell aperture.
+ */
+void amdgpu_doorbell_get_kfd_info(struct amdgpu_device *adev,
+ phys_addr_t *aperture_base,
+ size_t *aperture_size,
+ size_t *start_offset)
+{
+ /*
+ * The first num_doorbells are used by amdgpu.
+ * amdkfd takes whatever's left in the aperture.
+ */
+ if (adev->doorbell.size > adev->doorbell.num_doorbells * sizeof(u32)) {
+ *aperture_base = adev->doorbell.base;
+ *aperture_size = adev->doorbell.size;
+ *start_offset = adev->doorbell.num_doorbells * sizeof(u32);
+ } else {
+ *aperture_base = 0;
+ *aperture_size = 0;
+ *start_offset = 0;
+ }
+}
+
+/*
+ * amdgpu_wb_*()
+ * Writeback is the the method by which the the GPU updates special pages
+ * in memory with the status of certain GPU events (fences, ring pointers,
+ * etc.).
+ */
+
+/**
+ * amdgpu_wb_fini - Disable Writeback and free memory
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Disables Writeback and frees the Writeback memory (all asics).
+ * Used at driver shutdown.
+ */
+static void amdgpu_wb_fini(struct amdgpu_device *adev)
+{
+ if (adev->wb.wb_obj) {
+ if (!amdgpu_bo_reserve(adev->wb.wb_obj, false)) {
+ amdgpu_bo_kunmap(adev->wb.wb_obj);
+ amdgpu_bo_unpin(adev->wb.wb_obj);
+ amdgpu_bo_unreserve(adev->wb.wb_obj);
+ }
+ amdgpu_bo_unref(&adev->wb.wb_obj);
+ adev->wb.wb = NULL;
+ adev->wb.wb_obj = NULL;
+ }
+}
+
+/**
+ * amdgpu_wb_init- Init Writeback driver info and allocate memory
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Disables Writeback and frees the Writeback memory (all asics).
+ * Used at driver startup.
+ * Returns 0 on success or an -error on failure.
+ */
+static int amdgpu_wb_init(struct amdgpu_device *adev)
+{
+ int r;
+
+ if (adev->wb.wb_obj == NULL) {
+ r = amdgpu_bo_create(adev, AMDGPU_MAX_WB * 4, PAGE_SIZE, true,
+ AMDGPU_GEM_DOMAIN_GTT, 0, NULL, &adev->wb.wb_obj);
+ if (r) {
+ dev_warn(adev->dev, "(%d) create WB bo failed\n", r);
+ return r;
+ }
+ r = amdgpu_bo_reserve(adev->wb.wb_obj, false);
+ if (unlikely(r != 0)) {
+ amdgpu_wb_fini(adev);
+ return r;
+ }
+ r = amdgpu_bo_pin(adev->wb.wb_obj, AMDGPU_GEM_DOMAIN_GTT,
+ &adev->wb.gpu_addr);
+ if (r) {
+ amdgpu_bo_unreserve(adev->wb.wb_obj);
+ dev_warn(adev->dev, "(%d) pin WB bo failed\n", r);
+ amdgpu_wb_fini(adev);
+ return r;
+ }
+ r = amdgpu_bo_kmap(adev->wb.wb_obj, (void **)&adev->wb.wb);
+ amdgpu_bo_unreserve(adev->wb.wb_obj);
+ if (r) {
+ dev_warn(adev->dev, "(%d) map WB bo failed\n", r);
+ amdgpu_wb_fini(adev);
+ return r;
+ }
+
+ adev->wb.num_wb = AMDGPU_MAX_WB;
+ memset(&adev->wb.used, 0, sizeof(adev->wb.used));
+
+ /* clear wb memory */
+ memset((char *)adev->wb.wb, 0, AMDGPU_GPU_PAGE_SIZE);
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_wb_get - Allocate a wb entry
+ *
+ * @adev: amdgpu_device pointer
+ * @wb: wb index
+ *
+ * Allocate a wb slot for use by the driver (all asics).
+ * Returns 0 on success or -EINVAL on failure.
+ */
+int amdgpu_wb_get(struct amdgpu_device *adev, u32 *wb)
+{
+ unsigned long offset = find_first_zero_bit(adev->wb.used, adev->wb.num_wb);
+ if (offset < adev->wb.num_wb) {
+ __set_bit(offset, adev->wb.used);
+ *wb = offset;
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+}
+
+/**
+ * amdgpu_wb_free - Free a wb entry
+ *
+ * @adev: amdgpu_device pointer
+ * @wb: wb index
+ *
+ * Free a wb slot allocated for use by the driver (all asics)
+ */
+void amdgpu_wb_free(struct amdgpu_device *adev, u32 wb)
+{
+ if (wb < adev->wb.num_wb)
+ __clear_bit(wb, adev->wb.used);
+}
+
+/**
+ * amdgpu_vram_location - try to find VRAM location
+ * @adev: amdgpu device structure holding all necessary informations
+ * @mc: memory controller structure holding memory informations
+ * @base: base address at which to put VRAM
+ *
+ * Function will place try to place VRAM at base address provided
+ * as parameter (which is so far either PCI aperture address or
+ * for IGP TOM base address).
+ *
+ * If there is not enough space to fit the unvisible VRAM in the 32bits
+ * address space then we limit the VRAM size to the aperture.
+ *
+ * Note: We don't explicitly enforce VRAM start to be aligned on VRAM size,
+ * this shouldn't be a problem as we are using the PCI aperture as a reference.
+ * Otherwise this would be needed for rv280, all r3xx, and all r4xx, but
+ * not IGP.
+ *
+ * Note: we use mc_vram_size as on some board we need to program the mc to
+ * cover the whole aperture even if VRAM size is inferior to aperture size
+ * Novell bug 204882 + along with lots of ubuntu ones
+ *
+ * Note: when limiting vram it's safe to overwritte real_vram_size because
+ * we are not in case where real_vram_size is inferior to mc_vram_size (ie
+ * note afected by bogus hw of Novell bug 204882 + along with lots of ubuntu
+ * ones)
+ *
+ * Note: IGP TOM addr should be the same as the aperture addr, we don't
+ * explicitly check for that thought.
+ *
+ * FIXME: when reducing VRAM size align new size on power of 2.
+ */
+void amdgpu_vram_location(struct amdgpu_device *adev, struct amdgpu_mc *mc, u64 base)
+{
+ uint64_t limit = (uint64_t)amdgpu_vram_limit << 20;
+
+ mc->vram_start = base;
+ if (mc->mc_vram_size > (adev->mc.mc_mask - base + 1)) {
+ dev_warn(adev->dev, "limiting VRAM to PCI aperture size\n");
+ mc->real_vram_size = mc->aper_size;
+ mc->mc_vram_size = mc->aper_size;
+ }
+ mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
+ if (limit && limit < mc->real_vram_size)
+ mc->real_vram_size = limit;
+ dev_info(adev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n",
+ mc->mc_vram_size >> 20, mc->vram_start,
+ mc->vram_end, mc->real_vram_size >> 20);
+}
+
+/**
+ * amdgpu_gtt_location - try to find GTT location
+ * @adev: amdgpu device structure holding all necessary informations
+ * @mc: memory controller structure holding memory informations
+ *
+ * Function will place try to place GTT before or after VRAM.
+ *
+ * If GTT size is bigger than space left then we ajust GTT size.
+ * Thus function will never fails.
+ *
+ * FIXME: when reducing GTT size align new size on power of 2.
+ */
+void amdgpu_gtt_location(struct amdgpu_device *adev, struct amdgpu_mc *mc)
+{
+ u64 size_af, size_bf;
+
+ size_af = ((adev->mc.mc_mask - mc->vram_end) + mc->gtt_base_align) & ~mc->gtt_base_align;
+ size_bf = mc->vram_start & ~mc->gtt_base_align;
+ if (size_bf > size_af) {
+ if (mc->gtt_size > size_bf) {
+ dev_warn(adev->dev, "limiting GTT\n");
+ mc->gtt_size = size_bf;
+ }
+ mc->gtt_start = (mc->vram_start & ~mc->gtt_base_align) - mc->gtt_size;
+ } else {
+ if (mc->gtt_size > size_af) {
+ dev_warn(adev->dev, "limiting GTT\n");
+ mc->gtt_size = size_af;
+ }
+ mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align;
+ }
+ mc->gtt_end = mc->gtt_start + mc->gtt_size - 1;
+ dev_info(adev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n",
+ mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end);
+}
+
+/*
+ * GPU helpers function.
+ */
+/**
+ * amdgpu_card_posted - check if the hw has already been initialized
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Check if the asic has been initialized (all asics).
+ * Used at driver startup.
+ * Returns true if initialized or false if not.
+ */
+bool amdgpu_card_posted(struct amdgpu_device *adev)
+{
+ uint32_t reg;
+
+ /* then check MEM_SIZE, in case the crtcs are off */
+ reg = RREG32(mmCONFIG_MEMSIZE);
+
+ if (reg)
+ return true;
+
+ return false;
+
+}
+
+/**
+ * amdgpu_boot_test_post_card - check and possibly initialize the hw
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Check if the asic is initialized and if not, attempt to initialize
+ * it (all asics).
+ * Returns true if initialized or false if not.
+ */
+bool amdgpu_boot_test_post_card(struct amdgpu_device *adev)
+{
+ if (amdgpu_card_posted(adev))
+ return true;
+
+ if (adev->bios) {
+ DRM_INFO("GPU not posted. posting now...\n");
+ if (adev->is_atom_bios)
+ amdgpu_atom_asic_init(adev->mode_info.atom_context);
+ return true;
+ } else {
+ dev_err(adev->dev, "Card not posted and no BIOS - ignoring\n");
+ return false;
+ }
+}
+
+/**
+ * amdgpu_dummy_page_init - init dummy page used by the driver
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Allocate the dummy page used by the driver (all asics).
+ * This dummy page is used by the driver as a filler for gart entries
+ * when pages are taken out of the GART
+ * Returns 0 on sucess, -ENOMEM on failure.
+ */
+int amdgpu_dummy_page_init(struct amdgpu_device *adev)
+{
+ if (adev->dummy_page.page)
+ return 0;
+ adev->dummy_page.page = alloc_page(GFP_DMA32 | GFP_KERNEL | __GFP_ZERO);
+ if (adev->dummy_page.page == NULL)
+ return -ENOMEM;
+ adev->dummy_page.addr = pci_map_page(adev->pdev, adev->dummy_page.page,
+ 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(adev->pdev, adev->dummy_page.addr)) {
+ dev_err(&adev->pdev->dev, "Failed to DMA MAP the dummy page\n");
+ __free_page(adev->dummy_page.page);
+ adev->dummy_page.page = NULL;
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_dummy_page_fini - free dummy page used by the driver
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Frees the dummy page used by the driver (all asics).
+ */
+void amdgpu_dummy_page_fini(struct amdgpu_device *adev)
+{
+ if (adev->dummy_page.page == NULL)
+ return;
+ pci_unmap_page(adev->pdev, adev->dummy_page.addr,
+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ __free_page(adev->dummy_page.page);
+ adev->dummy_page.page = NULL;
+}
+
+
+/* ATOM accessor methods */
+/*
+ * ATOM is an interpreted byte code stored in tables in the vbios. The
+ * driver registers callbacks to access registers and the interpreter
+ * in the driver parses the tables and executes then to program specific
+ * actions (set display modes, asic init, etc.). See amdgpu_atombios.c,
+ * atombios.h, and atom.c
+ */
+
+/**
+ * cail_pll_read - read PLL register
+ *
+ * @info: atom card_info pointer
+ * @reg: PLL register offset
+ *
+ * Provides a PLL register accessor for the atom interpreter (r4xx+).
+ * Returns the value of the PLL register.
+ */
+static uint32_t cail_pll_read(struct card_info *info, uint32_t reg)
+{
+ return 0;
+}
+
+/**
+ * cail_pll_write - write PLL register
+ *
+ * @info: atom card_info pointer
+ * @reg: PLL register offset
+ * @val: value to write to the pll register
+ *
+ * Provides a PLL register accessor for the atom interpreter (r4xx+).
+ */
+static void cail_pll_write(struct card_info *info, uint32_t reg, uint32_t val)
+{
+
+}
+
+/**
+ * cail_mc_read - read MC (Memory Controller) register
+ *
+ * @info: atom card_info pointer
+ * @reg: MC register offset
+ *
+ * Provides an MC register accessor for the atom interpreter (r4xx+).
+ * Returns the value of the MC register.
+ */
+static uint32_t cail_mc_read(struct card_info *info, uint32_t reg)
+{
+ return 0;
+}
+
+/**
+ * cail_mc_write - write MC (Memory Controller) register
+ *
+ * @info: atom card_info pointer
+ * @reg: MC register offset
+ * @val: value to write to the pll register
+ *
+ * Provides a MC register accessor for the atom interpreter (r4xx+).
+ */
+static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val)
+{
+
+}
+
+/**
+ * cail_reg_write - write MMIO register
+ *
+ * @info: atom card_info pointer
+ * @reg: MMIO register offset
+ * @val: value to write to the pll register
+ *
+ * Provides a MMIO register accessor for the atom interpreter (r4xx+).
+ */
+static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val)
+{
+ struct amdgpu_device *adev = info->dev->dev_private;
+
+ WREG32(reg, val);
+}
+
+/**
+ * cail_reg_read - read MMIO register
+ *
+ * @info: atom card_info pointer
+ * @reg: MMIO register offset
+ *
+ * Provides an MMIO register accessor for the atom interpreter (r4xx+).
+ * Returns the value of the MMIO register.
+ */
+static uint32_t cail_reg_read(struct card_info *info, uint32_t reg)
+{
+ struct amdgpu_device *adev = info->dev->dev_private;
+ uint32_t r;
+
+ r = RREG32(reg);
+ return r;
+}
+
+/**
+ * cail_ioreg_write - write IO register
+ *
+ * @info: atom card_info pointer
+ * @reg: IO register offset
+ * @val: value to write to the pll register
+ *
+ * Provides a IO register accessor for the atom interpreter (r4xx+).
+ */
+static void cail_ioreg_write(struct card_info *info, uint32_t reg, uint32_t val)
+{
+ struct amdgpu_device *adev = info->dev->dev_private;
+
+ WREG32_IO(reg, val);
+}
+
+/**
+ * cail_ioreg_read - read IO register
+ *
+ * @info: atom card_info pointer
+ * @reg: IO register offset
+ *
+ * Provides an IO register accessor for the atom interpreter (r4xx+).
+ * Returns the value of the IO register.
+ */
+static uint32_t cail_ioreg_read(struct card_info *info, uint32_t reg)
+{
+ struct amdgpu_device *adev = info->dev->dev_private;
+ uint32_t r;
+
+ r = RREG32_IO(reg);
+ return r;
+}
+
+/**
+ * amdgpu_atombios_fini - free the driver info and callbacks for atombios
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Frees the driver info and register access callbacks for the ATOM
+ * interpreter (r4xx+).
+ * Called at driver shutdown.
+ */
+static void amdgpu_atombios_fini(struct amdgpu_device *adev)
+{
+ if (adev->mode_info.atom_context)
+ kfree(adev->mode_info.atom_context->scratch);
+ kfree(adev->mode_info.atom_context);
+ adev->mode_info.atom_context = NULL;
+ kfree(adev->mode_info.atom_card_info);
+ adev->mode_info.atom_card_info = NULL;
+}
+
+/**
+ * amdgpu_atombios_init - init the driver info and callbacks for atombios
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Initializes the driver info and register access callbacks for the
+ * ATOM interpreter (r4xx+).
+ * Returns 0 on sucess, -ENOMEM on failure.
+ * Called at driver startup.
+ */
+static int amdgpu_atombios_init(struct amdgpu_device *adev)
+{
+ struct card_info *atom_card_info =
+ kzalloc(sizeof(struct card_info), GFP_KERNEL);
+
+ if (!atom_card_info)
+ return -ENOMEM;
+
+ adev->mode_info.atom_card_info = atom_card_info;
+ atom_card_info->dev = adev->ddev;
+ atom_card_info->reg_read = cail_reg_read;
+ atom_card_info->reg_write = cail_reg_write;
+ /* needed for iio ops */
+ if (adev->rio_mem) {
+ atom_card_info->ioreg_read = cail_ioreg_read;
+ atom_card_info->ioreg_write = cail_ioreg_write;
+ } else {
+ DRM_ERROR("Unable to find PCI I/O BAR; using MMIO for ATOM IIO\n");
+ atom_card_info->ioreg_read = cail_reg_read;
+ atom_card_info->ioreg_write = cail_reg_write;
+ }
+ atom_card_info->mc_read = cail_mc_read;
+ atom_card_info->mc_write = cail_mc_write;
+ atom_card_info->pll_read = cail_pll_read;
+ atom_card_info->pll_write = cail_pll_write;
+
+ adev->mode_info.atom_context = amdgpu_atom_parse(atom_card_info, adev->bios);
+ if (!adev->mode_info.atom_context) {
+ amdgpu_atombios_fini(adev);
+ return -ENOMEM;
+ }
+
+ mutex_init(&adev->mode_info.atom_context->mutex);
+ amdgpu_atombios_scratch_regs_init(adev);
+ amdgpu_atom_allocate_fb_scratch(adev->mode_info.atom_context);
+ return 0;
+}
+
+/* if we get transitioned to only one device, take VGA back */
+/**
+ * amdgpu_vga_set_decode - enable/disable vga decode
+ *
+ * @cookie: amdgpu_device pointer
+ * @state: enable/disable vga decode
+ *
+ * Enable/disable vga decode (all asics).
+ * Returns VGA resource flags.
+ */
+static unsigned int amdgpu_vga_set_decode(void *cookie, bool state)
+{
+ struct amdgpu_device *adev = cookie;
+ amdgpu_asic_set_vga_state(adev, state);
+ if (state)
+ return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
+ VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+ else
+ return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+}
+
+/**
+ * amdgpu_check_pot_argument - check that argument is a power of two
+ *
+ * @arg: value to check
+ *
+ * Validates that a certain argument is a power of two (all asics).
+ * Returns true if argument is valid.
+ */
+static bool amdgpu_check_pot_argument(int arg)
+{
+ return (arg & (arg - 1)) == 0;
+}
+
+/**
+ * amdgpu_check_arguments - validate module params
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Validates certain module parameters and updates
+ * the associated values used by the driver (all asics).
+ */
+static void amdgpu_check_arguments(struct amdgpu_device *adev)
+{
+ /* 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",
+ amdgpu_vram_limit);
+ amdgpu_vram_limit = 0;
+ }
+
+ if (amdgpu_gart_size != -1) {
+ /* gtt size must be power of two and greater or equal to 32M */
+ if (amdgpu_gart_size < 32) {
+ dev_warn(adev->dev, "gart size (%d) too small\n",
+ amdgpu_gart_size);
+ amdgpu_gart_size = -1;
+ } else if (!amdgpu_check_pot_argument(amdgpu_gart_size)) {
+ dev_warn(adev->dev, "gart size (%d) must be a power of 2\n",
+ amdgpu_gart_size);
+ amdgpu_gart_size = -1;
+ }
+ }
+
+ if (!amdgpu_check_pot_argument(amdgpu_vm_size)) {
+ dev_warn(adev->dev, "VM size (%d) must be a power of 2\n",
+ amdgpu_vm_size);
+ amdgpu_vm_size = 8;
+ }
+
+ if (amdgpu_vm_size < 1) {
+ dev_warn(adev->dev, "VM size (%d) too small, min is 1GB\n",
+ amdgpu_vm_size);
+ amdgpu_vm_size = 8;
+ }
+
+ /*
+ * Max GPUVM size for Cayman, SI and CI are 40 bits.
+ */
+ if (amdgpu_vm_size > 1024) {
+ dev_warn(adev->dev, "VM size (%d) too large, max is 1TB\n",
+ amdgpu_vm_size);
+ amdgpu_vm_size = 8;
+ }
+
+ /* defines number of bits in page table versus page directory,
+ * a page is 4KB so we have 12 bits offset, minimum 9 bits in the
+ * page table and the remaining bits are in the page directory */
+ if (amdgpu_vm_block_size == -1) {
+
+ /* Total bits covered by PD + PTs */
+ unsigned bits = ilog2(amdgpu_vm_size) + 18;
+
+ /* Make sure the PD is 4K in size up to 8GB address space.
+ Above that split equal between PD and PTs */
+ if (amdgpu_vm_size <= 8)
+ amdgpu_vm_block_size = bits - 9;
+ else
+ amdgpu_vm_block_size = (bits + 3) / 2;
+
+ } else if (amdgpu_vm_block_size < 9) {
+ dev_warn(adev->dev, "VM page table size (%d) too small\n",
+ amdgpu_vm_block_size);
+ amdgpu_vm_block_size = 9;
+ }
+
+ if (amdgpu_vm_block_size > 24 ||
+ (amdgpu_vm_size * 1024) < (1ull << amdgpu_vm_block_size)) {
+ dev_warn(adev->dev, "VM page table size (%d) too large\n",
+ amdgpu_vm_block_size);
+ amdgpu_vm_block_size = 9;
+ }
+}
+
+/**
+ * amdgpu_switcheroo_set_state - set switcheroo state
+ *
+ * @pdev: pci dev pointer
+ * @state: vga switcheroo state
+ *
+ * Callback for the switcheroo driver. Suspends or resumes the
+ * the asics before or after it is powered up using ACPI methods.
+ */
+static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+
+ if (amdgpu_device_is_px(dev) && state == VGA_SWITCHEROO_OFF)
+ return;
+
+ if (state == VGA_SWITCHEROO_ON) {
+ unsigned d3_delay = dev->pdev->d3_delay;
+
+ printk(KERN_INFO "amdgpu: switched on\n");
+ /* don't suspend or resume card normally */
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
+
+ amdgpu_resume_kms(dev, true, true);
+
+ dev->pdev->d3_delay = d3_delay;
+
+ dev->switch_power_state = DRM_SWITCH_POWER_ON;
+ drm_kms_helper_poll_enable(dev);
+ } else {
+ printk(KERN_INFO "amdgpu: switched off\n");
+ drm_kms_helper_poll_disable(dev);
+ dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
+ amdgpu_suspend_kms(dev, true, true);
+ dev->switch_power_state = DRM_SWITCH_POWER_OFF;
+ }
+}
+
+/**
+ * amdgpu_switcheroo_can_switch - see if switcheroo state can change
+ *
+ * @pdev: pci dev pointer
+ *
+ * Callback for the switcheroo driver. Check of the switcheroo
+ * state can be changed.
+ * Returns true if the state can be changed, false if not.
+ */
+static bool amdgpu_switcheroo_can_switch(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+
+ /*
+ * FIXME: open_count is protected by drm_global_mutex but that would lead to
+ * locking inversion with the driver load path. And the access here is
+ * completely racy anyway. So don't bother with locking for now.
+ */
+ return dev->open_count == 0;
+}
+
+static const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = {
+ .set_gpu_state = amdgpu_switcheroo_set_state,
+ .reprobe = NULL,
+ .can_switch = amdgpu_switcheroo_can_switch,
+};
+
+int amdgpu_set_clockgating_state(struct amdgpu_device *adev,
+ enum amd_ip_block_type block_type,
+ enum amd_clockgating_state state)
+{
+ int i, r = 0;
+
+ for (i = 0; i < adev->num_ip_blocks; i++) {
+ if (adev->ip_blocks[i].type == block_type) {
+ r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
+ state);
+ if (r)
+ return r;
+ }
+ }
+ return r;
+}
+
+int amdgpu_set_powergating_state(struct amdgpu_device *adev,
+ enum amd_ip_block_type block_type,
+ enum amd_powergating_state state)
+{
+ int i, r = 0;
+
+ for (i = 0; i < adev->num_ip_blocks; i++) {
+ if (adev->ip_blocks[i].type == block_type) {
+ r = adev->ip_blocks[i].funcs->set_powergating_state((void *)adev,
+ state);
+ if (r)
+ return r;
+ }
+ }
+ return r;
+}
+
+const struct amdgpu_ip_block_version * amdgpu_get_ip_block(
+ struct amdgpu_device *adev,
+ enum amd_ip_block_type type)
+{
+ int i;
+
+ for (i = 0; i < adev->num_ip_blocks; i++)
+ if (adev->ip_blocks[i].type == type)
+ return &adev->ip_blocks[i];
+
+ return NULL;
+}
+
+/**
+ * amdgpu_ip_block_version_cmp
+ *
+ * @adev: amdgpu_device pointer
+ * @type: enum amd_ip_block_type
+ * @major: major version
+ * @minor: minor version
+ *
+ * return 0 if equal or greater
+ * return 1 if smaller or the ip_block doesn't exist
+ */
+int amdgpu_ip_block_version_cmp(struct amdgpu_device *adev,
+ enum amd_ip_block_type type,
+ u32 major, u32 minor)
+{
+ const struct amdgpu_ip_block_version *ip_block;
+ ip_block = amdgpu_get_ip_block(adev, type);
+
+ if (ip_block && ((ip_block->major > major) ||
+ ((ip_block->major == major) &&
+ (ip_block->minor >= minor))))
+ return 0;
+
+ return 1;
+}
+
+static int amdgpu_early_init(struct amdgpu_device *adev)
+{
+ int i, r;
+
+ switch (adev->asic_type) {
+ case CHIP_TOPAZ:
+ case CHIP_TONGA:
+ case CHIP_CARRIZO:
+ if (adev->asic_type == CHIP_CARRIZO)
+ adev->family = AMDGPU_FAMILY_CZ;
+ else
+ adev->family = AMDGPU_FAMILY_VI;
+
+ r = vi_set_ip_blocks(adev);
+ if (r)
+ return r;
+ break;
+#ifdef CONFIG_DRM_AMDGPU_CIK
+ case CHIP_BONAIRE:
+ case CHIP_HAWAII:
+ case CHIP_KAVERI:
+ case CHIP_KABINI:
+ case CHIP_MULLINS:
+ if ((adev->asic_type == CHIP_BONAIRE) || (adev->asic_type == CHIP_HAWAII))
+ adev->family = AMDGPU_FAMILY_CI;
+ else
+ adev->family = AMDGPU_FAMILY_KV;
+
+ r = cik_set_ip_blocks(adev);
+ if (r)
+ return r;
+ break;
+#endif
+ default:
+ /* FIXME: not supported yet */
+ return -EINVAL;
+ }
+
+
+
+ if (adev->ip_blocks == NULL) {
+ DRM_ERROR("No IP blocks found!\n");
+ return r;
+ }
+
+ for (i = 0; i < adev->num_ip_blocks; i++) {
+ if ((amdgpu_ip_block_mask & (1 << i)) == 0) {
+ DRM_ERROR("disabled ip block: %d\n", i);
+ adev->ip_block_enabled[i] = false;
+ } else {
+ if (adev->ip_blocks[i].funcs->early_init) {
+ r = adev->ip_blocks[i].funcs->early_init((void *)adev);
+ if (r)
+ return r;
+ }
+ adev->ip_block_enabled[i] = true;
+ }
+ }
+
+ return 0;
+}
+
+static int amdgpu_init(struct amdgpu_device *adev)
+{
+ int i, r;
+
+ for (i = 0; i < adev->num_ip_blocks; i++) {
+ if (!adev->ip_block_enabled[i])
+ continue;
+ r = adev->ip_blocks[i].funcs->sw_init((void *)adev);
+ if (r)
+ return r;
+ /* 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)
+ return r;
+ r = adev->ip_blocks[i].funcs->hw_init((void *)adev);
+ if (r)
+ return r;
+ r = amdgpu_wb_init(adev);
+ if (r)
+ return r;
+ }
+ }
+
+ for (i = 0; i < adev->num_ip_blocks; i++) {
+ if (!adev->ip_block_enabled[i])
+ continue;
+ /* gmc hw init is done early */
+ if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC)
+ continue;
+ r = adev->ip_blocks[i].funcs->hw_init((void *)adev);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+static int amdgpu_late_init(struct amdgpu_device *adev)
+{
+ int i = 0, r;
+
+ for (i = 0; i < adev->num_ip_blocks; i++) {
+ if (!adev->ip_block_enabled[i])
+ continue;
+ /* enable clockgating to save power */
+ r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
+ AMD_CG_STATE_GATE);
+ if (r)
+ return r;
+ if (adev->ip_blocks[i].funcs->late_init) {
+ r = adev->ip_blocks[i].funcs->late_init((void *)adev);
+ if (r)
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+static int amdgpu_fini(struct amdgpu_device *adev)
+{
+ int i, r;
+
+ for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
+ if (!adev->ip_block_enabled[i])
+ continue;
+ if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) {
+ amdgpu_wb_fini(adev);
+ amdgpu_vram_scratch_fini(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)
+ return r;
+ r = adev->ip_blocks[i].funcs->hw_fini((void *)adev);
+ /* XXX handle errors */
+ }
+
+ for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
+ if (!adev->ip_block_enabled[i])
+ continue;
+ r = adev->ip_blocks[i].funcs->sw_fini((void *)adev);
+ /* XXX handle errors */
+ adev->ip_block_enabled[i] = false;
+ }
+
+ return 0;
+}
+
+static int amdgpu_suspend(struct amdgpu_device *adev)
+{
+ int i, r;
+
+ for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
+ if (!adev->ip_block_enabled[i])
+ continue;
+ /* 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);
+ /* XXX handle errors */
+ r = adev->ip_blocks[i].funcs->suspend(adev);
+ /* XXX handle errors */
+ }
+
+ return 0;
+}
+
+static int amdgpu_resume(struct amdgpu_device *adev)
+{
+ int i, r;
+
+ for (i = 0; i < adev->num_ip_blocks; i++) {
+ if (!adev->ip_block_enabled[i])
+ continue;
+ r = adev->ip_blocks[i].funcs->resume(adev);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_device_init - initialize the driver
+ *
+ * @adev: amdgpu_device pointer
+ * @pdev: drm dev pointer
+ * @pdev: pci dev pointer
+ * @flags: driver flags
+ *
+ * Initializes the driver info and hw (all asics).
+ * Returns 0 for success or an error on failure.
+ * Called at driver startup.
+ */
+int amdgpu_device_init(struct amdgpu_device *adev,
+ struct drm_device *ddev,
+ struct pci_dev *pdev,
+ uint32_t flags)
+{
+ int r, i;
+ bool runtime = false;
+
+ adev->shutdown = false;
+ adev->dev = &pdev->dev;
+ adev->ddev = ddev;
+ adev->pdev = pdev;
+ adev->flags = flags;
+ adev->asic_type = flags & AMDGPU_ASIC_MASK;
+ adev->is_atom_bios = false;
+ adev->usec_timeout = AMDGPU_MAX_USEC_TIMEOUT;
+ adev->mc.gtt_size = 512 * 1024 * 1024;
+ adev->accel_working = false;
+ adev->num_rings = 0;
+ adev->mman.buffer_funcs = NULL;
+ adev->mman.buffer_funcs_ring = NULL;
+ adev->vm_manager.vm_pte_funcs = NULL;
+ adev->vm_manager.vm_pte_funcs_ring = NULL;
+ adev->gart.gart_funcs = NULL;
+ adev->fence_context = fence_context_alloc(AMDGPU_MAX_RINGS);
+
+ adev->smc_rreg = &amdgpu_invalid_rreg;
+ adev->smc_wreg = &amdgpu_invalid_wreg;
+ adev->pcie_rreg = &amdgpu_invalid_rreg;
+ adev->pcie_wreg = &amdgpu_invalid_wreg;
+ adev->uvd_ctx_rreg = &amdgpu_invalid_rreg;
+ adev->uvd_ctx_wreg = &amdgpu_invalid_wreg;
+ adev->didt_rreg = &amdgpu_invalid_rreg;
+ adev->didt_wreg = &amdgpu_invalid_wreg;
+ adev->audio_endpt_rreg = &amdgpu_block_invalid_rreg;
+ adev->audio_endpt_wreg = &amdgpu_block_invalid_wreg;
+
+ DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X 0x%02X).\n",
+ amdgpu_asic_name[adev->asic_type], pdev->vendor, pdev->device,
+ pdev->subsystem_vendor, pdev->subsystem_device, pdev->revision);
+
+ /* mutex initialization are all done here so we
+ * can recall function without having locking issues */
+ mutex_init(&adev->ring_lock);
+ atomic_set(&adev->irq.ih.lock, 0);
+ mutex_init(&adev->gem.mutex);
+ mutex_init(&adev->pm.mutex);
+ mutex_init(&adev->gfx.gpu_clock_mutex);
+ mutex_init(&adev->srbm_mutex);
+ mutex_init(&adev->grbm_idx_mutex);
+ init_rwsem(&adev->exclusive_lock);
+ mutex_init(&adev->mn_lock);
+ hash_init(adev->mn_hash);
+
+ amdgpu_check_arguments(adev);
+
+ /* Registers mapping */
+ /* TODO: block userspace mapping of io register */
+ spin_lock_init(&adev->mmio_idx_lock);
+ spin_lock_init(&adev->smc_idx_lock);
+ spin_lock_init(&adev->pcie_idx_lock);
+ spin_lock_init(&adev->uvd_ctx_idx_lock);
+ spin_lock_init(&adev->didt_idx_lock);
+ spin_lock_init(&adev->audio_endpt_idx_lock);
+
+ adev->rmmio_base = pci_resource_start(adev->pdev, 5);
+ adev->rmmio_size = pci_resource_len(adev->pdev, 5);
+ adev->rmmio = ioremap(adev->rmmio_base, adev->rmmio_size);
+ if (adev->rmmio == NULL) {
+ return -ENOMEM;
+ }
+ DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)adev->rmmio_base);
+ DRM_INFO("register mmio size: %u\n", (unsigned)adev->rmmio_size);
+
+ /* doorbell bar mapping */
+ amdgpu_doorbell_init(adev);
+
+ /* io port mapping */
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ if (pci_resource_flags(adev->pdev, i) & IORESOURCE_IO) {
+ adev->rio_mem_size = pci_resource_len(adev->pdev, i);
+ adev->rio_mem = pci_iomap(adev->pdev, i, adev->rio_mem_size);
+ break;
+ }
+ }
+ if (adev->rio_mem == NULL)
+ DRM_ERROR("Unable to find PCI I/O BAR\n");
+
+ /* early init functions */
+ r = amdgpu_early_init(adev);
+ if (r)
+ return r;
+
+ /* if we have > 1 VGA cards, then disable the amdgpu VGA resources */
+ /* this will fail for cards that aren't VGA class devices, just
+ * ignore it */
+ vga_client_register(adev->pdev, adev, NULL, amdgpu_vga_set_decode);
+
+ if (amdgpu_runtime_pm == 1)
+ runtime = true;
+ if (amdgpu_device_is_px(ddev))
+ runtime = true;
+ vga_switcheroo_register_client(adev->pdev, &amdgpu_switcheroo_ops, runtime);
+ if (runtime)
+ vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain);
+
+ /* Read BIOS */
+ if (!amdgpu_get_bios(adev))
+ return -EINVAL;
+ /* Must be an ATOMBIOS */
+ if (!adev->is_atom_bios) {
+ dev_err(adev->dev, "Expecting atombios for GPU\n");
+ return -EINVAL;
+ }
+ r = amdgpu_atombios_init(adev);
+ if (r)
+ return r;
+
+ /* Post card if necessary */
+ if (!amdgpu_card_posted(adev)) {
+ if (!adev->bios) {
+ dev_err(adev->dev, "Card not posted and no BIOS - ignoring\n");
+ return -EINVAL;
+ }
+ DRM_INFO("GPU not posted. posting now...\n");
+ amdgpu_atom_asic_init(adev->mode_info.atom_context);
+ }
+
+ /* Initialize clocks */
+ r = amdgpu_atombios_get_clock_info(adev);
+ if (r)
+ return r;
+ /* init i2c buses */
+ amdgpu_atombios_i2c_init(adev);
+
+ /* Fence driver */
+ r = amdgpu_fence_driver_init(adev);
+ if (r)
+ return r;
+
+ /* init the mode config */
+ drm_mode_config_init(adev->ddev);
+
+ r = amdgpu_init(adev);
+ if (r) {
+ amdgpu_fini(adev);
+ return r;
+ }
+
+ adev->accel_working = true;
+
+ amdgpu_fbdev_init(adev);
+
+ r = amdgpu_ib_pool_init(adev);
+ if (r) {
+ dev_err(adev->dev, "IB initialization failed (%d).\n", r);
+ return r;
+ }
+
+ r = amdgpu_ib_ring_tests(adev);
+ if (r)
+ DRM_ERROR("ib ring test failed (%d).\n", r);
+
+ r = amdgpu_gem_debugfs_init(adev);
+ if (r) {
+ DRM_ERROR("registering gem debugfs failed (%d).\n", r);
+ }
+
+ r = amdgpu_debugfs_regs_init(adev);
+ if (r) {
+ DRM_ERROR("registering register debugfs failed (%d).\n", r);
+ }
+
+ if ((amdgpu_testing & 1)) {
+ if (adev->accel_working)
+ amdgpu_test_moves(adev);
+ else
+ DRM_INFO("amdgpu: acceleration disabled, skipping move tests\n");
+ }
+ if ((amdgpu_testing & 2)) {
+ if (adev->accel_working)
+ amdgpu_test_syncing(adev);
+ else
+ DRM_INFO("amdgpu: acceleration disabled, skipping sync tests\n");
+ }
+ if (amdgpu_benchmarking) {
+ if (adev->accel_working)
+ amdgpu_benchmark(adev, amdgpu_benchmarking);
+ else
+ DRM_INFO("amdgpu: acceleration disabled, skipping benchmarks\n");
+ }
+
+ /* enable clockgating, etc. after ib tests, etc. since some blocks require
+ * explicit gating rather than handling it automatically.
+ */
+ r = amdgpu_late_init(adev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void amdgpu_debugfs_remove_files(struct amdgpu_device *adev);
+
+/**
+ * amdgpu_device_fini - tear down the driver
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Tear down the driver info (all asics).
+ * Called at driver shutdown.
+ */
+void amdgpu_device_fini(struct amdgpu_device *adev)
+{
+ int r;
+
+ DRM_INFO("amdgpu: finishing device.\n");
+ adev->shutdown = true;
+ /* evict vram memory */
+ amdgpu_bo_evict_vram(adev);
+ amdgpu_ib_pool_fini(adev);
+ amdgpu_fence_driver_fini(adev);
+ amdgpu_fbdev_fini(adev);
+ r = amdgpu_fini(adev);
+ if (adev->ip_block_enabled)
+ kfree(adev->ip_block_enabled);
+ adev->ip_block_enabled = NULL;
+ adev->accel_working = false;
+ /* free i2c buses */
+ amdgpu_i2c_fini(adev);
+ amdgpu_atombios_fini(adev);
+ kfree(adev->bios);
+ adev->bios = NULL;
+ vga_switcheroo_unregister_client(adev->pdev);
+ vga_client_register(adev->pdev, NULL, NULL, NULL);
+ if (adev->rio_mem)
+ pci_iounmap(adev->pdev, adev->rio_mem);
+ adev->rio_mem = NULL;
+ iounmap(adev->rmmio);
+ adev->rmmio = NULL;
+ amdgpu_doorbell_fini(adev);
+ amdgpu_debugfs_regs_cleanup(adev);
+ amdgpu_debugfs_remove_files(adev);
+}
+
+
+/*
+ * Suspend & resume.
+ */
+/**
+ * amdgpu_suspend_kms - initiate device suspend
+ *
+ * @pdev: drm dev pointer
+ * @state: suspend state
+ *
+ * Puts the hw in the suspend state (all asics).
+ * Returns 0 for success or an error on failure.
+ * Called at driver suspend.
+ */
+int amdgpu_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
+{
+ struct amdgpu_device *adev;
+ struct drm_crtc *crtc;
+ struct drm_connector *connector;
+ int i, r;
+ bool force_completion = false;
+
+ if (dev == NULL || dev->dev_private == NULL) {
+ return -ENODEV;
+ }
+
+ adev = dev->dev_private;
+
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
+ drm_kms_helper_poll_disable(dev);
+
+ /* turn off display hw */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+ }
+
+ /* unpin the front buffers */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct amdgpu_framebuffer *rfb = to_amdgpu_framebuffer(crtc->primary->fb);
+ struct amdgpu_bo *robj;
+
+ if (rfb == NULL || rfb->obj == NULL) {
+ continue;
+ }
+ robj = gem_to_amdgpu_bo(rfb->obj);
+ /* don't unpin kernel fb objects */
+ if (!amdgpu_fbdev_robj_is_fb(adev, robj)) {
+ r = amdgpu_bo_reserve(robj, false);
+ if (r == 0) {
+ amdgpu_bo_unpin(robj);
+ amdgpu_bo_unreserve(robj);
+ }
+ }
+ }
+ /* evict vram memory */
+ amdgpu_bo_evict_vram(adev);
+
+ /* wait for gpu to finish processing current batch */
+ for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
+ struct amdgpu_ring *ring = adev->rings[i];
+ if (!ring)
+ continue;
+
+ r = amdgpu_fence_wait_empty(ring);
+ if (r) {
+ /* delay GPU reset to resume */
+ force_completion = true;
+ }
+ }
+ if (force_completion) {
+ amdgpu_fence_driver_force_completion(adev);
+ }
+
+ r = amdgpu_suspend(adev);
+
+ /* evict remaining vram memory */
+ amdgpu_bo_evict_vram(adev);
+
+ pci_save_state(dev->pdev);
+ if (suspend) {
+ /* Shut down the device */
+ pci_disable_device(dev->pdev);
+ pci_set_power_state(dev->pdev, PCI_D3hot);
+ }
+
+ if (fbcon) {
+ console_lock();
+ amdgpu_fbdev_set_suspend(adev, 1);
+ console_unlock();
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_resume_kms - initiate device resume
+ *
+ * @pdev: drm dev pointer
+ *
+ * Bring the hw back to operating state (all asics).
+ * Returns 0 for success or an error on failure.
+ * Called at driver resume.
+ */
+int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
+{
+ struct drm_connector *connector;
+ struct amdgpu_device *adev = dev->dev_private;
+ int r;
+
+ if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
+ if (fbcon) {
+ console_lock();
+ }
+ if (resume) {
+ pci_set_power_state(dev->pdev, PCI_D0);
+ pci_restore_state(dev->pdev);
+ if (pci_enable_device(dev->pdev)) {
+ if (fbcon)
+ console_unlock();
+ return -1;
+ }
+ }
+
+ /* post card */
+ amdgpu_atom_asic_init(adev->mode_info.atom_context);
+
+ r = amdgpu_resume(adev);
+
+ r = amdgpu_ib_ring_tests(adev);
+ if (r)
+ DRM_ERROR("ib ring test failed (%d).\n", r);
+
+ r = amdgpu_late_init(adev);
+ if (r)
+ return r;
+
+ /* blat the mode back in */
+ if (fbcon) {
+ drm_helper_resume_force_mode(dev);
+ /* turn on display hw */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+ }
+ }
+
+ drm_kms_helper_poll_enable(dev);
+
+ if (fbcon) {
+ amdgpu_fbdev_set_suspend(adev, 0);
+ console_unlock();
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_gpu_reset - reset the asic
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Attempt the reset the GPU if it has hung (all asics).
+ * Returns 0 for success or an error on failure.
+ */
+int amdgpu_gpu_reset(struct amdgpu_device *adev)
+{
+ unsigned ring_sizes[AMDGPU_MAX_RINGS];
+ uint32_t *ring_data[AMDGPU_MAX_RINGS];
+
+ bool saved = false;
+
+ int i, r;
+ int resched;
+
+ down_write(&adev->exclusive_lock);
+
+ if (!adev->needs_reset) {
+ up_write(&adev->exclusive_lock);
+ return 0;
+ }
+
+ adev->needs_reset = false;
+ atomic_inc(&adev->gpu_reset_counter);
+
+ /* block TTM */
+ resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
+
+ r = amdgpu_suspend(adev);
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_ring *ring = adev->rings[i];
+ if (!ring)
+ continue;
+
+ ring_sizes[i] = amdgpu_ring_backup(ring, &ring_data[i]);
+ if (ring_sizes[i]) {
+ saved = true;
+ dev_info(adev->dev, "Saved %d dwords of commands "
+ "on ring %d.\n", ring_sizes[i], i);
+ }
+ }
+
+retry:
+ r = amdgpu_asic_reset(adev);
+ if (!r) {
+ dev_info(adev->dev, "GPU reset succeeded, trying to resume\n");
+ r = amdgpu_resume(adev);
+ }
+
+ if (!r) {
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_ring *ring = adev->rings[i];
+ if (!ring)
+ continue;
+
+ amdgpu_ring_restore(ring, ring_sizes[i], ring_data[i]);
+ ring_sizes[i] = 0;
+ ring_data[i] = NULL;
+ }
+
+ r = amdgpu_ib_ring_tests(adev);
+ if (r) {
+ dev_err(adev->dev, "ib ring test failed (%d).\n", r);
+ if (saved) {
+ saved = false;
+ r = amdgpu_suspend(adev);
+ goto retry;
+ }
+ }
+ } else {
+ amdgpu_fence_driver_force_completion(adev);
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ if (adev->rings[i])
+ kfree(ring_data[i]);
+ }
+ }
+
+ drm_helper_resume_force_mode(adev->ddev);
+
+ ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched);
+ if (r) {
+ /* bad news, how to tell it to userspace ? */
+ dev_info(adev->dev, "GPU reset failed\n");
+ }
+
+ up_write(&adev->exclusive_lock);
+ return r;
+}
+
+
+/*
+ * Debugfs
+ */
+int amdgpu_debugfs_add_files(struct amdgpu_device *adev,
+ struct drm_info_list *files,
+ unsigned nfiles)
+{
+ unsigned i;
+
+ for (i = 0; i < adev->debugfs_count; i++) {
+ if (adev->debugfs[i].files == files) {
+ /* Already registered */
+ return 0;
+ }
+ }
+
+ i = adev->debugfs_count + 1;
+ if (i > AMDGPU_DEBUGFS_MAX_COMPONENTS) {
+ DRM_ERROR("Reached maximum number of debugfs components.\n");
+ DRM_ERROR("Report so we increase "
+ "AMDGPU_DEBUGFS_MAX_COMPONENTS.\n");
+ return -EINVAL;
+ }
+ adev->debugfs[adev->debugfs_count].files = files;
+ adev->debugfs[adev->debugfs_count].num_files = nfiles;
+ adev->debugfs_count = i;
+#if defined(CONFIG_DEBUG_FS)
+ drm_debugfs_create_files(files, nfiles,
+ adev->ddev->control->debugfs_root,
+ adev->ddev->control);
+ drm_debugfs_create_files(files, nfiles,
+ adev->ddev->primary->debugfs_root,
+ adev->ddev->primary);
+#endif
+ return 0;
+}
+
+static void amdgpu_debugfs_remove_files(struct amdgpu_device *adev)
+{
+#if defined(CONFIG_DEBUG_FS)
+ unsigned i;
+
+ for (i = 0; i < adev->debugfs_count; i++) {
+ drm_debugfs_remove_files(adev->debugfs[i].files,
+ adev->debugfs[i].num_files,
+ adev->ddev->control);
+ drm_debugfs_remove_files(adev->debugfs[i].files,
+ adev->debugfs[i].num_files,
+ adev->ddev->primary);
+ }
+#endif
+}
+
+#if defined(CONFIG_DEBUG_FS)
+
+static ssize_t amdgpu_debugfs_regs_read(struct file *f, char __user *buf,
+ size_t size, loff_t *pos)
+{
+ struct amdgpu_device *adev = f->f_inode->i_private;
+ ssize_t result = 0;
+ int r;
+
+ if (size & 0x3 || *pos & 0x3)
+ return -EINVAL;
+
+ while (size) {
+ uint32_t value;
+
+ if (*pos > adev->rmmio_size)
+ return result;
+
+ value = RREG32(*pos >> 2);
+ r = put_user(value, (uint32_t *)buf);
+ if (r)
+ return r;
+
+ result += 4;
+ buf += 4;
+ *pos += 4;
+ size -= 4;
+ }
+
+ return result;
+}
+
+static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf,
+ size_t size, loff_t *pos)
+{
+ struct amdgpu_device *adev = f->f_inode->i_private;
+ ssize_t result = 0;
+ int r;
+
+ if (size & 0x3 || *pos & 0x3)
+ return -EINVAL;
+
+ while (size) {
+ uint32_t value;
+
+ if (*pos > adev->rmmio_size)
+ return result;
+
+ r = get_user(value, (uint32_t *)buf);
+ if (r)
+ return r;
+
+ WREG32(*pos >> 2, value);
+
+ result += 4;
+ buf += 4;
+ *pos += 4;
+ size -= 4;
+ }
+
+ return result;
+}
+
+static const struct file_operations amdgpu_debugfs_regs_fops = {
+ .owner = THIS_MODULE,
+ .read = amdgpu_debugfs_regs_read,
+ .write = amdgpu_debugfs_regs_write,
+ .llseek = default_llseek
+};
+
+static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
+{
+ struct drm_minor *minor = adev->ddev->primary;
+ struct dentry *ent, *root = minor->debugfs_root;
+
+ ent = debugfs_create_file("amdgpu_regs", S_IFREG | S_IRUGO, root,
+ adev, &amdgpu_debugfs_regs_fops);
+ if (IS_ERR(ent))
+ return PTR_ERR(ent);
+ i_size_write(ent->d_inode, adev->rmmio_size);
+ adev->debugfs_regs = ent;
+
+ return 0;
+}
+
+static void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev)
+{
+ debugfs_remove(adev->debugfs_regs);
+ adev->debugfs_regs = NULL;
+}
+
+int amdgpu_debugfs_init(struct drm_minor *minor)
+{
+ return 0;
+}
+
+void amdgpu_debugfs_cleanup(struct drm_minor *minor)
+{
+}
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
new file mode 100644
index 000000000000..b16b9256883e
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -0,0 +1,832 @@
+/*
+ * Copyright 2007-8 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 shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ */
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "amdgpu_i2c.h"
+#include "atom.h"
+#include "amdgpu_connectors.h"
+#include <asm/div64.h>
+
+#include <linux/pm_runtime.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+
+
+static void amdgpu_flip_work_func(struct work_struct *__work)
+{
+ struct amdgpu_flip_work *work =
+ container_of(__work, struct amdgpu_flip_work, flip_work);
+ struct amdgpu_device *adev = work->adev;
+ struct amdgpu_crtc *amdgpuCrtc = adev->mode_info.crtcs[work->crtc_id];
+
+ struct drm_crtc *crtc = &amdgpuCrtc->base;
+ struct amdgpu_fence *fence;
+ unsigned long flags;
+ int r;
+
+ down_read(&adev->exclusive_lock);
+ if (work->fence) {
+ fence = to_amdgpu_fence(work->fence);
+ if (fence) {
+ r = amdgpu_fence_wait(fence, false);
+ if (r == -EDEADLK) {
+ up_read(&adev->exclusive_lock);
+ r = amdgpu_gpu_reset(adev);
+ down_read(&adev->exclusive_lock);
+ }
+ } else
+ r = fence_wait(work->fence, false);
+
+ if (r)
+ DRM_ERROR("failed to wait on page flip fence (%d)!\n", r);
+
+ /* We continue with the page flip even if we failed to wait on
+ * the fence, otherwise the DRM core and userspace will be
+ * confused about which BO the CRTC is scanning out
+ */
+
+ fence_put(work->fence);
+ work->fence = NULL;
+ }
+
+ /* We borrow the event spin lock for protecting flip_status */
+ spin_lock_irqsave(&crtc->dev->event_lock, flags);
+
+ /* set the proper interrupt */
+ amdgpu_irq_get(adev, &adev->pageflip_irq, work->crtc_id);
+ /* do the flip (mmio) */
+ adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base);
+ /* set the flip status */
+ amdgpuCrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
+
+ spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+ up_read(&adev->exclusive_lock);
+}
+
+/*
+ * Handle unpin events outside the interrupt handler proper.
+ */
+static void amdgpu_unpin_work_func(struct work_struct *__work)
+{
+ struct amdgpu_flip_work *work =
+ container_of(__work, struct amdgpu_flip_work, unpin_work);
+ int r;
+
+ /* unpin of the old buffer */
+ r = amdgpu_bo_reserve(work->old_rbo, false);
+ if (likely(r == 0)) {
+ r = amdgpu_bo_unpin(work->old_rbo);
+ if (unlikely(r != 0)) {
+ DRM_ERROR("failed to unpin buffer after flip\n");
+ }
+ amdgpu_bo_unreserve(work->old_rbo);
+ } else
+ DRM_ERROR("failed to reserve buffer after flip\n");
+
+ drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
+ kfree(work);
+}
+
+int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event,
+ uint32_t page_flip_flags)
+{
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct amdgpu_framebuffer *old_amdgpu_fb;
+ struct amdgpu_framebuffer *new_amdgpu_fb;
+ struct drm_gem_object *obj;
+ struct amdgpu_flip_work *work;
+ struct amdgpu_bo *new_rbo;
+ unsigned long flags;
+ u64 tiling_flags;
+ u64 base;
+ int r;
+
+ work = kzalloc(sizeof *work, GFP_KERNEL);
+ if (work == NULL)
+ return -ENOMEM;
+
+ INIT_WORK(&work->flip_work, amdgpu_flip_work_func);
+ INIT_WORK(&work->unpin_work, amdgpu_unpin_work_func);
+
+ work->event = event;
+ work->adev = adev;
+ work->crtc_id = amdgpu_crtc->crtc_id;
+
+ /* schedule unpin of the old buffer */
+ old_amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);
+ obj = old_amdgpu_fb->obj;
+
+ /* take a reference to the old object */
+ drm_gem_object_reference(obj);
+ work->old_rbo = gem_to_amdgpu_bo(obj);
+
+ new_amdgpu_fb = to_amdgpu_framebuffer(fb);
+ obj = new_amdgpu_fb->obj;
+ new_rbo = gem_to_amdgpu_bo(obj);
+
+ /* pin the new buffer */
+ r = amdgpu_bo_reserve(new_rbo, false);
+ if (unlikely(r != 0)) {
+ DRM_ERROR("failed to reserve new rbo buffer before flip\n");
+ goto cleanup;
+ }
+
+ r = amdgpu_bo_pin_restricted(new_rbo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, &base);
+ if (unlikely(r != 0)) {
+ amdgpu_bo_unreserve(new_rbo);
+ r = -EINVAL;
+ DRM_ERROR("failed to pin new rbo buffer before flip\n");
+ goto cleanup;
+ }
+
+ work->fence = fence_get(reservation_object_get_excl(new_rbo->tbo.resv));
+ amdgpu_bo_get_tiling_flags(new_rbo, &tiling_flags);
+ amdgpu_bo_unreserve(new_rbo);
+
+ work->base = base;
+
+ r = drm_vblank_get(crtc->dev, amdgpu_crtc->crtc_id);
+ if (r) {
+ DRM_ERROR("failed to get vblank before flip\n");
+ goto pflip_cleanup;
+ }
+
+ /* we borrow the event spin lock for protecting flip_wrok */
+ spin_lock_irqsave(&crtc->dev->event_lock, flags);
+ if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_NONE) {
+ DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
+ spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+ r = -EBUSY;
+ goto vblank_cleanup;
+ }
+
+ amdgpu_crtc->pflip_status = AMDGPU_FLIP_PENDING;
+ amdgpu_crtc->pflip_works = work;
+
+ /* update crtc fb */
+ crtc->primary->fb = fb;
+ spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+ queue_work(amdgpu_crtc->pflip_queue, &work->flip_work);
+ return 0;
+
+vblank_cleanup:
+ drm_vblank_put(crtc->dev, amdgpu_crtc->crtc_id);
+
+pflip_cleanup:
+ if (unlikely(amdgpu_bo_reserve(new_rbo, false) != 0)) {
+ DRM_ERROR("failed to reserve new rbo in error path\n");
+ goto cleanup;
+ }
+ if (unlikely(amdgpu_bo_unpin(new_rbo) != 0)) {
+ DRM_ERROR("failed to unpin new rbo in error path\n");
+ }
+ amdgpu_bo_unreserve(new_rbo);
+
+cleanup:
+ drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
+ fence_put(work->fence);
+ kfree(work);
+
+ return r;
+}
+
+int amdgpu_crtc_set_config(struct drm_mode_set *set)
+{
+ struct drm_device *dev;
+ struct amdgpu_device *adev;
+ struct drm_crtc *crtc;
+ bool active = false;
+ int ret;
+
+ if (!set || !set->crtc)
+ return -EINVAL;
+
+ dev = set->crtc->dev;
+
+ ret = pm_runtime_get_sync(dev->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = drm_crtc_helper_set_config(set);
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+ if (crtc->enabled)
+ active = true;
+
+ pm_runtime_mark_last_busy(dev->dev);
+
+ adev = dev->dev_private;
+ /* if we have active crtcs and we don't have a power ref,
+ take the current one */
+ if (active && !adev->have_disp_power_ref) {
+ adev->have_disp_power_ref = true;
+ return ret;
+ }
+ /* if we have no active crtcs, then drop the power ref
+ we got before */
+ if (!active && adev->have_disp_power_ref) {
+ pm_runtime_put_autosuspend(dev->dev);
+ adev->have_disp_power_ref = false;
+ }
+
+ /* drop the power reference we got coming in here */
+ pm_runtime_put_autosuspend(dev->dev);
+ return ret;
+}
+
+static const char *encoder_names[38] = {
+ "NONE",
+ "INTERNAL_LVDS",
+ "INTERNAL_TMDS1",
+ "INTERNAL_TMDS2",
+ "INTERNAL_DAC1",
+ "INTERNAL_DAC2",
+ "INTERNAL_SDVOA",
+ "INTERNAL_SDVOB",
+ "SI170B",
+ "CH7303",
+ "CH7301",
+ "INTERNAL_DVO1",
+ "EXTERNAL_SDVOA",
+ "EXTERNAL_SDVOB",
+ "TITFP513",
+ "INTERNAL_LVTM1",
+ "VT1623",
+ "HDMI_SI1930",
+ "HDMI_INTERNAL",
+ "INTERNAL_KLDSCP_TMDS1",
+ "INTERNAL_KLDSCP_DVO1",
+ "INTERNAL_KLDSCP_DAC1",
+ "INTERNAL_KLDSCP_DAC2",
+ "SI178",
+ "MVPU_FPGA",
+ "INTERNAL_DDI",
+ "VT1625",
+ "HDMI_SI1932",
+ "DP_AN9801",
+ "DP_DP501",
+ "INTERNAL_UNIPHY",
+ "INTERNAL_KLDSCP_LVTMA",
+ "INTERNAL_UNIPHY1",
+ "INTERNAL_UNIPHY2",
+ "NUTMEG",
+ "TRAVIS",
+ "INTERNAL_VCE",
+ "INTERNAL_UNIPHY3",
+};
+
+static const char *hpd_names[6] = {
+ "HPD1",
+ "HPD2",
+ "HPD3",
+ "HPD4",
+ "HPD5",
+ "HPD6",
+};
+
+void amdgpu_print_display_setup(struct drm_device *dev)
+{
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector;
+ struct drm_encoder *encoder;
+ struct amdgpu_encoder *amdgpu_encoder;
+ uint32_t devices;
+ int i = 0;
+
+ DRM_INFO("AMDGPU Display Connectors\n");
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ amdgpu_connector = to_amdgpu_connector(connector);
+ DRM_INFO("Connector %d:\n", i);
+ DRM_INFO(" %s\n", connector->name);
+ if (amdgpu_connector->hpd.hpd != AMDGPU_HPD_NONE)
+ DRM_INFO(" %s\n", hpd_names[amdgpu_connector->hpd.hpd]);
+ if (amdgpu_connector->ddc_bus) {
+ DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ amdgpu_connector->ddc_bus->rec.mask_clk_reg,
+ amdgpu_connector->ddc_bus->rec.mask_data_reg,
+ amdgpu_connector->ddc_bus->rec.a_clk_reg,
+ amdgpu_connector->ddc_bus->rec.a_data_reg,
+ amdgpu_connector->ddc_bus->rec.en_clk_reg,
+ amdgpu_connector->ddc_bus->rec.en_data_reg,
+ amdgpu_connector->ddc_bus->rec.y_clk_reg,
+ amdgpu_connector->ddc_bus->rec.y_data_reg);
+ if (amdgpu_connector->router.ddc_valid)
+ DRM_INFO(" DDC Router 0x%x/0x%x\n",
+ amdgpu_connector->router.ddc_mux_control_pin,
+ amdgpu_connector->router.ddc_mux_state);
+ if (amdgpu_connector->router.cd_valid)
+ DRM_INFO(" Clock/Data Router 0x%x/0x%x\n",
+ amdgpu_connector->router.cd_mux_control_pin,
+ amdgpu_connector->router.cd_mux_state);
+ } else {
+ if (connector->connector_type == DRM_MODE_CONNECTOR_VGA ||
+ connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
+ connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
+ connector->connector_type == DRM_MODE_CONNECTOR_DVIA ||
+ connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
+ connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)
+ DRM_INFO(" DDC: no ddc bus - possible BIOS bug - please report to xorg-driver-ati@lists.x.org\n");
+ }
+ DRM_INFO(" Encoders:\n");
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+ devices = amdgpu_encoder->devices & amdgpu_connector->devices;
+ if (devices) {
+ if (devices & ATOM_DEVICE_CRT1_SUPPORT)
+ DRM_INFO(" CRT1: %s\n", encoder_names[amdgpu_encoder->encoder_id]);
+ if (devices & ATOM_DEVICE_CRT2_SUPPORT)
+ DRM_INFO(" CRT2: %s\n", encoder_names[amdgpu_encoder->encoder_id]);
+ if (devices & ATOM_DEVICE_LCD1_SUPPORT)
+ DRM_INFO(" LCD1: %s\n", encoder_names[amdgpu_encoder->encoder_id]);
+ if (devices & ATOM_DEVICE_DFP1_SUPPORT)
+ DRM_INFO(" DFP1: %s\n", encoder_names[amdgpu_encoder->encoder_id]);
+ if (devices & ATOM_DEVICE_DFP2_SUPPORT)
+ DRM_INFO(" DFP2: %s\n", encoder_names[amdgpu_encoder->encoder_id]);
+ if (devices & ATOM_DEVICE_DFP3_SUPPORT)
+ DRM_INFO(" DFP3: %s\n", encoder_names[amdgpu_encoder->encoder_id]);
+ if (devices & ATOM_DEVICE_DFP4_SUPPORT)
+ DRM_INFO(" DFP4: %s\n", encoder_names[amdgpu_encoder->encoder_id]);
+ if (devices & ATOM_DEVICE_DFP5_SUPPORT)
+ DRM_INFO(" DFP5: %s\n", encoder_names[amdgpu_encoder->encoder_id]);
+ if (devices & ATOM_DEVICE_DFP6_SUPPORT)
+ DRM_INFO(" DFP6: %s\n", encoder_names[amdgpu_encoder->encoder_id]);
+ if (devices & ATOM_DEVICE_TV1_SUPPORT)
+ DRM_INFO(" TV1: %s\n", encoder_names[amdgpu_encoder->encoder_id]);
+ if (devices & ATOM_DEVICE_CV_SUPPORT)
+ DRM_INFO(" CV: %s\n", encoder_names[amdgpu_encoder->encoder_id]);
+ }
+ }
+ i++;
+ }
+}
+
+/**
+ * amdgpu_ddc_probe
+ *
+ */
+bool amdgpu_ddc_probe(struct amdgpu_connector *amdgpu_connector,
+ bool use_aux)
+{
+ u8 out = 0x0;
+ u8 buf[8];
+ int ret;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = DDC_ADDR,
+ .flags = 0,
+ .len = 1,
+ .buf = &out,
+ },
+ {
+ .addr = DDC_ADDR,
+ .flags = I2C_M_RD,
+ .len = 8,
+ .buf = buf,
+ }
+ };
+
+ /* on hw with routers, select right port */
+ if (amdgpu_connector->router.ddc_valid)
+ amdgpu_i2c_router_select_ddc_port(amdgpu_connector);
+
+ if (use_aux) {
+ ret = i2c_transfer(&amdgpu_connector->ddc_bus->aux.ddc, msgs, 2);
+ } else {
+ ret = i2c_transfer(&amdgpu_connector->ddc_bus->adapter, msgs, 2);
+ }
+
+ if (ret != 2)
+ /* Couldn't find an accessible DDC on this connector */
+ return false;
+ /* Probe also for valid EDID header
+ * EDID header starts with:
+ * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00.
+ * Only the first 6 bytes must be valid as
+ * drm_edid_block_valid() can fix the last 2 bytes */
+ if (drm_edid_header_is_valid(buf) < 6) {
+ /* Couldn't find an accessible EDID on this
+ * connector */
+ return false;
+ }
+ return true;
+}
+
+static void amdgpu_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+ struct amdgpu_framebuffer *amdgpu_fb = to_amdgpu_framebuffer(fb);
+
+ if (amdgpu_fb->obj) {
+ drm_gem_object_unreference_unlocked(amdgpu_fb->obj);
+ }
+ drm_framebuffer_cleanup(fb);
+ kfree(amdgpu_fb);
+}
+
+static int amdgpu_user_framebuffer_create_handle(struct drm_framebuffer *fb,
+ struct drm_file *file_priv,
+ unsigned int *handle)
+{
+ struct amdgpu_framebuffer *amdgpu_fb = to_amdgpu_framebuffer(fb);
+
+ return drm_gem_handle_create(file_priv, amdgpu_fb->obj, handle);
+}
+
+static const struct drm_framebuffer_funcs amdgpu_fb_funcs = {
+ .destroy = amdgpu_user_framebuffer_destroy,
+ .create_handle = amdgpu_user_framebuffer_create_handle,
+};
+
+int
+amdgpu_framebuffer_init(struct drm_device *dev,
+ struct amdgpu_framebuffer *rfb,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object *obj)
+{
+ int ret;
+ rfb->obj = obj;
+ drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd);
+ ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs);
+ if (ret) {
+ rfb->obj = NULL;
+ return ret;
+ }
+ return 0;
+}
+
+static struct drm_framebuffer *
+amdgpu_user_framebuffer_create(struct drm_device *dev,
+ struct drm_file *file_priv,
+ struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct drm_gem_object *obj;
+ struct amdgpu_framebuffer *amdgpu_fb;
+ int ret;
+
+ obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
+ if (obj == NULL) {
+ dev_err(&dev->pdev->dev, "No GEM object associated to handle 0x%08X, "
+ "can't create framebuffer\n", mode_cmd->handles[0]);
+ return ERR_PTR(-ENOENT);
+ }
+
+ amdgpu_fb = kzalloc(sizeof(*amdgpu_fb), GFP_KERNEL);
+ if (amdgpu_fb == NULL) {
+ drm_gem_object_unreference_unlocked(obj);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = amdgpu_framebuffer_init(dev, amdgpu_fb, mode_cmd, obj);
+ if (ret) {
+ kfree(amdgpu_fb);
+ drm_gem_object_unreference_unlocked(obj);
+ return ERR_PTR(ret);
+ }
+
+ return &amdgpu_fb->base;
+}
+
+static void amdgpu_output_poll_changed(struct drm_device *dev)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ amdgpu_fb_output_poll_changed(adev);
+}
+
+const struct drm_mode_config_funcs amdgpu_mode_funcs = {
+ .fb_create = amdgpu_user_framebuffer_create,
+ .output_poll_changed = amdgpu_output_poll_changed
+};
+
+static struct drm_prop_enum_list amdgpu_underscan_enum_list[] =
+{ { UNDERSCAN_OFF, "off" },
+ { UNDERSCAN_ON, "on" },
+ { UNDERSCAN_AUTO, "auto" },
+};
+
+static struct drm_prop_enum_list amdgpu_audio_enum_list[] =
+{ { AMDGPU_AUDIO_DISABLE, "off" },
+ { AMDGPU_AUDIO_ENABLE, "on" },
+ { AMDGPU_AUDIO_AUTO, "auto" },
+};
+
+/* XXX support different dither options? spatial, temporal, both, etc. */
+static struct drm_prop_enum_list amdgpu_dither_enum_list[] =
+{ { AMDGPU_FMT_DITHER_DISABLE, "off" },
+ { AMDGPU_FMT_DITHER_ENABLE, "on" },
+};
+
+int amdgpu_modeset_create_props(struct amdgpu_device *adev)
+{
+ int sz;
+
+ if (adev->is_atom_bios) {
+ adev->mode_info.coherent_mode_property =
+ drm_property_create_range(adev->ddev, 0 , "coherent", 0, 1);
+ if (!adev->mode_info.coherent_mode_property)
+ return -ENOMEM;
+ }
+
+ adev->mode_info.load_detect_property =
+ drm_property_create_range(adev->ddev, 0, "load detection", 0, 1);
+ if (!adev->mode_info.load_detect_property)
+ return -ENOMEM;
+
+ drm_mode_create_scaling_mode_property(adev->ddev);
+
+ sz = ARRAY_SIZE(amdgpu_underscan_enum_list);
+ adev->mode_info.underscan_property =
+ drm_property_create_enum(adev->ddev, 0,
+ "underscan",
+ amdgpu_underscan_enum_list, sz);
+
+ adev->mode_info.underscan_hborder_property =
+ drm_property_create_range(adev->ddev, 0,
+ "underscan hborder", 0, 128);
+ if (!adev->mode_info.underscan_hborder_property)
+ return -ENOMEM;
+
+ adev->mode_info.underscan_vborder_property =
+ drm_property_create_range(adev->ddev, 0,
+ "underscan vborder", 0, 128);
+ if (!adev->mode_info.underscan_vborder_property)
+ return -ENOMEM;
+
+ sz = ARRAY_SIZE(amdgpu_audio_enum_list);
+ adev->mode_info.audio_property =
+ drm_property_create_enum(adev->ddev, 0,
+ "audio",
+ amdgpu_audio_enum_list, sz);
+
+ sz = ARRAY_SIZE(amdgpu_dither_enum_list);
+ adev->mode_info.dither_property =
+ drm_property_create_enum(adev->ddev, 0,
+ "dither",
+ amdgpu_dither_enum_list, sz);
+
+ return 0;
+}
+
+void amdgpu_update_display_priority(struct amdgpu_device *adev)
+{
+ /* adjustment options for the display watermarks */
+ if ((amdgpu_disp_priority == 0) || (amdgpu_disp_priority > 2))
+ adev->mode_info.disp_priority = 0;
+ else
+ adev->mode_info.disp_priority = amdgpu_disp_priority;
+
+}
+
+static bool is_hdtv_mode(const struct drm_display_mode *mode)
+{
+ /* try and guess if this is a tv or a monitor */
+ if ((mode->vdisplay == 480 && mode->hdisplay == 720) || /* 480p */
+ (mode->vdisplay == 576) || /* 576p */
+ (mode->vdisplay == 720) || /* 720p */
+ (mode->vdisplay == 1080)) /* 1080p */
+ return true;
+ else
+ return false;
+}
+
+bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_encoder *encoder;
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct amdgpu_encoder *amdgpu_encoder;
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector;
+ u32 src_v = 1, dst_v = 1;
+ u32 src_h = 1, dst_h = 1;
+
+ amdgpu_crtc->h_border = 0;
+ amdgpu_crtc->v_border = 0;
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ if (encoder->crtc != crtc)
+ continue;
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+ connector = amdgpu_get_connector_for_encoder(encoder);
+ amdgpu_connector = to_amdgpu_connector(connector);
+
+ /* set scaling */
+ if (amdgpu_encoder->rmx_type == RMX_OFF)
+ amdgpu_crtc->rmx_type = RMX_OFF;
+ else if (mode->hdisplay < amdgpu_encoder->native_mode.hdisplay ||
+ mode->vdisplay < amdgpu_encoder->native_mode.vdisplay)
+ amdgpu_crtc->rmx_type = amdgpu_encoder->rmx_type;
+ else
+ amdgpu_crtc->rmx_type = RMX_OFF;
+ /* copy native mode */
+ memcpy(&amdgpu_crtc->native_mode,
+ &amdgpu_encoder->native_mode,
+ sizeof(struct drm_display_mode));
+ src_v = crtc->mode.vdisplay;
+ dst_v = amdgpu_crtc->native_mode.vdisplay;
+ src_h = crtc->mode.hdisplay;
+ dst_h = amdgpu_crtc->native_mode.hdisplay;
+
+ /* fix up for overscan on hdmi */
+ if ((!(mode->flags & DRM_MODE_FLAG_INTERLACE)) &&
+ ((amdgpu_encoder->underscan_type == UNDERSCAN_ON) ||
+ ((amdgpu_encoder->underscan_type == UNDERSCAN_AUTO) &&
+ drm_detect_hdmi_monitor(amdgpu_connector_edid(connector)) &&
+ is_hdtv_mode(mode)))) {
+ if (amdgpu_encoder->underscan_hborder != 0)
+ amdgpu_crtc->h_border = amdgpu_encoder->underscan_hborder;
+ else
+ amdgpu_crtc->h_border = (mode->hdisplay >> 5) + 16;
+ if (amdgpu_encoder->underscan_vborder != 0)
+ amdgpu_crtc->v_border = amdgpu_encoder->underscan_vborder;
+ else
+ amdgpu_crtc->v_border = (mode->vdisplay >> 5) + 16;
+ amdgpu_crtc->rmx_type = RMX_FULL;
+ src_v = crtc->mode.vdisplay;
+ dst_v = crtc->mode.vdisplay - (amdgpu_crtc->v_border * 2);
+ src_h = crtc->mode.hdisplay;
+ dst_h = crtc->mode.hdisplay - (amdgpu_crtc->h_border * 2);
+ }
+ }
+ if (amdgpu_crtc->rmx_type != RMX_OFF) {
+ fixed20_12 a, b;
+ a.full = dfixed_const(src_v);
+ b.full = dfixed_const(dst_v);
+ amdgpu_crtc->vsc.full = dfixed_div(a, b);
+ a.full = dfixed_const(src_h);
+ b.full = dfixed_const(dst_h);
+ amdgpu_crtc->hsc.full = dfixed_div(a, b);
+ } else {
+ amdgpu_crtc->vsc.full = dfixed_const(1);
+ amdgpu_crtc->hsc.full = dfixed_const(1);
+ }
+ return true;
+}
+
+/*
+ * Retrieve current video scanout position of crtc on a given gpu, and
+ * an optional accurate timestamp of when query happened.
+ *
+ * \param dev Device to query.
+ * \param crtc Crtc to query.
+ * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0).
+ * \param *vpos Location where vertical scanout position should be stored.
+ * \param *hpos Location where horizontal scanout position should go.
+ * \param *stime Target location for timestamp taken immediately before
+ * scanout position query. Can be NULL to skip timestamp.
+ * \param *etime Target location for timestamp taken immediately after
+ * scanout position query. Can be NULL to skip timestamp.
+ *
+ * Returns vpos as a positive number while in active scanout area.
+ * Returns vpos as a negative number inside vblank, counting the number
+ * of scanlines to go until end of vblank, e.g., -1 means "one scanline
+ * until start of active scanout / end of vblank."
+ *
+ * \return Flags, or'ed together as follows:
+ *
+ * DRM_SCANOUTPOS_VALID = Query successful.
+ * DRM_SCANOUTPOS_INVBL = Inside vblank.
+ * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of
+ * this flag means that returned position may be offset by a constant but
+ * unknown small number of scanlines wrt. real scanout position.
+ *
+ */
+int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags,
+ int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
+{
+ u32 vbl = 0, position = 0;
+ int vbl_start, vbl_end, vtotal, ret = 0;
+ bool in_vbl = true;
+
+ struct amdgpu_device *adev = dev->dev_private;
+
+ /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
+
+ /* Get optional system timestamp before query. */
+ if (stime)
+ *stime = ktime_get();
+
+ if (amdgpu_display_page_flip_get_scanoutpos(adev, crtc, &vbl, &position) == 0)
+ ret |= DRM_SCANOUTPOS_VALID;
+
+ /* Get optional system timestamp after query. */
+ if (etime)
+ *etime = ktime_get();
+
+ /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
+
+ /* Decode into vertical and horizontal scanout position. */
+ *vpos = position & 0x1fff;
+ *hpos = (position >> 16) & 0x1fff;
+
+ /* Valid vblank area boundaries from gpu retrieved? */
+ if (vbl > 0) {
+ /* Yes: Decode. */
+ ret |= DRM_SCANOUTPOS_ACCURATE;
+ vbl_start = vbl & 0x1fff;
+ vbl_end = (vbl >> 16) & 0x1fff;
+ }
+ else {
+ /* No: Fake something reasonable which gives at least ok results. */
+ vbl_start = adev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay;
+ vbl_end = 0;
+ }
+
+ /* Test scanout position against vblank region. */
+ if ((*vpos < vbl_start) && (*vpos >= vbl_end))
+ in_vbl = false;
+
+ /* Check if inside vblank area and apply corrective offsets:
+ * vpos will then be >=0 in video scanout area, but negative
+ * within vblank area, counting down the number of lines until
+ * start of scanout.
+ */
+
+ /* Inside "upper part" of vblank area? Apply corrective offset if so: */
+ if (in_vbl && (*vpos >= vbl_start)) {
+ vtotal = adev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal;
+ *vpos = *vpos - vtotal;
+ }
+
+ /* Correct for shifted end of vbl at vbl_end. */
+ *vpos = *vpos - vbl_end;
+
+ /* In vblank? */
+ if (in_vbl)
+ ret |= DRM_SCANOUTPOS_IN_VBLANK;
+
+ /* Is vpos outside nominal vblank area, but less than
+ * 1/100 of a frame height away from start of vblank?
+ * If so, assume this isn't a massively delayed vblank
+ * interrupt, but a vblank interrupt that fired a few
+ * microseconds before true start of vblank. Compensate
+ * by adding a full frame duration to the final timestamp.
+ * Happens, e.g., on ATI R500, R600.
+ *
+ * We only do this if DRM_CALLED_FROM_VBLIRQ.
+ */
+ if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) {
+ vbl_start = adev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay;
+ vtotal = adev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal;
+
+ if (vbl_start - *vpos < vtotal / 100) {
+ *vpos -= vtotal;
+
+ /* Signal this correction as "applied". */
+ ret |= 0x8;
+ }
+ }
+
+ return ret;
+}
+
+int amdgpu_crtc_idx_to_irq_type(struct amdgpu_device *adev, int crtc)
+{
+ if (crtc < 0 || crtc >= adev->mode_info.num_crtc)
+ return AMDGPU_CRTC_IRQ_NONE;
+
+ switch (crtc) {
+ case 0:
+ return AMDGPU_CRTC_IRQ_VBLANK1;
+ case 1:
+ return AMDGPU_CRTC_IRQ_VBLANK2;
+ case 2:
+ return AMDGPU_CRTC_IRQ_VBLANK3;
+ case 3:
+ return AMDGPU_CRTC_IRQ_VBLANK4;
+ case 4:
+ return AMDGPU_CRTC_IRQ_VBLANK5;
+ case 5:
+ return AMDGPU_CRTC_IRQ_VBLANK6;
+ default:
+ return AMDGPU_CRTC_IRQ_NONE;
+ }
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c
new file mode 100644
index 000000000000..7b7f4aba60c0
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c
@@ -0,0 +1,955 @@
+/*
+ * Copyright 2011 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: Alex Deucher
+ */
+
+#include "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_atombios.h"
+#include "amdgpu_i2c.h"
+#include "amdgpu_dpm.h"
+#include "atom.h"
+
+void amdgpu_dpm_print_class_info(u32 class, u32 class2)
+{
+ printk("\tui class: ");
+ switch (class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
+ case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
+ default:
+ printk("none\n");
+ break;
+ case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
+ printk("battery\n");
+ break;
+ case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
+ printk("balanced\n");
+ break;
+ case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
+ printk("performance\n");
+ break;
+ }
+ printk("\tinternal class: ");
+ if (((class & ~ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 0) &&
+ (class2 == 0))
+ printk("none");
+ else {
+ if (class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+ printk("boot ");
+ if (class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+ printk("thermal ");
+ if (class & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
+ printk("limited_pwr ");
+ if (class & ATOM_PPLIB_CLASSIFICATION_REST)
+ printk("rest ");
+ if (class & ATOM_PPLIB_CLASSIFICATION_FORCED)
+ printk("forced ");
+ if (class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
+ printk("3d_perf ");
+ if (class & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE)
+ printk("ovrdrv ");
+ if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+ printk("uvd ");
+ if (class & ATOM_PPLIB_CLASSIFICATION_3DLOW)
+ printk("3d_low ");
+ if (class & ATOM_PPLIB_CLASSIFICATION_ACPI)
+ printk("acpi ");
+ if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
+ printk("uvd_hd2 ");
+ if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
+ printk("uvd_hd ");
+ if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
+ printk("uvd_sd ");
+ if (class2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
+ printk("limited_pwr2 ");
+ if (class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
+ printk("ulv ");
+ if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
+ printk("uvd_mvc ");
+ }
+ printk("\n");
+}
+
+void amdgpu_dpm_print_cap_info(u32 caps)
+{
+ printk("\tcaps: ");
+ if (caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
+ printk("single_disp ");
+ if (caps & ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK)
+ printk("video ");
+ if (caps & ATOM_PPLIB_DISALLOW_ON_DC)
+ printk("no_dc ");
+ printk("\n");
+}
+
+void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps)
+{
+ printk("\tstatus: ");
+ if (rps == adev->pm.dpm.current_ps)
+ printk("c ");
+ if (rps == adev->pm.dpm.requested_ps)
+ printk("r ");
+ if (rps == adev->pm.dpm.boot_ps)
+ printk("b ");
+ printk("\n");
+}
+
+u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev)
+{
+ struct drm_device *dev = adev->ddev;
+ struct drm_crtc *crtc;
+ struct amdgpu_crtc *amdgpu_crtc;
+ u32 line_time_us, vblank_lines;
+ u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */
+
+ if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ amdgpu_crtc = to_amdgpu_crtc(crtc);
+ if (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);
+ vblank_time_us = vblank_lines * line_time_us;
+ break;
+ }
+ }
+ }
+
+ return vblank_time_us;
+}
+
+u32 amdgpu_dpm_get_vrefresh(struct amdgpu_device *adev)
+{
+ struct drm_device *dev = adev->ddev;
+ struct drm_crtc *crtc;
+ struct amdgpu_crtc *amdgpu_crtc;
+ u32 vrefresh = 0;
+
+ if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ amdgpu_crtc = to_amdgpu_crtc(crtc);
+ if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) {
+ vrefresh = amdgpu_crtc->hw_mode.vrefresh;
+ break;
+ }
+ }
+ }
+
+ return vrefresh;
+}
+
+void amdgpu_calculate_u_and_p(u32 i, u32 r_c, u32 p_b,
+ u32 *p, u32 *u)
+{
+ u32 b_c = 0;
+ u32 i_c;
+ u32 tmp;
+
+ i_c = (i * r_c) / 100;
+ tmp = i_c >> p_b;
+
+ while (tmp) {
+ b_c++;
+ tmp >>= 1;
+ }
+
+ *u = (b_c + 1) / 2;
+ *p = i_c / (1 << (2 * (*u)));
+}
+
+int amdgpu_calculate_at(u32 t, u32 h, u32 fh, u32 fl, u32 *tl, u32 *th)
+{
+ u32 k, a, ah, al;
+ u32 t1;
+
+ if ((fl == 0) || (fh == 0) || (fl > fh))
+ return -EINVAL;
+
+ k = (100 * fh) / fl;
+ t1 = (t * (k - 100));
+ a = (1000 * (100 * h + t1)) / (10000 + (t1 / 100));
+ a = (a + 5) / 10;
+ ah = ((a * t) + 5000) / 10000;
+ al = a - ah;
+
+ *th = t - ah;
+ *tl = t + al;
+
+ return 0;
+}
+
+bool amdgpu_is_uvd_state(u32 class, u32 class2)
+{
+ if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+ return true;
+ if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
+ return true;
+ if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
+ return true;
+ if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
+ return true;
+ if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
+ return true;
+ return false;
+}
+
+bool amdgpu_is_internal_thermal_sensor(enum amdgpu_int_thermal_type sensor)
+{
+ switch (sensor) {
+ case THERMAL_TYPE_RV6XX:
+ case THERMAL_TYPE_RV770:
+ case THERMAL_TYPE_EVERGREEN:
+ case THERMAL_TYPE_SUMO:
+ case THERMAL_TYPE_NI:
+ case THERMAL_TYPE_SI:
+ case THERMAL_TYPE_CI:
+ case THERMAL_TYPE_KV:
+ return true;
+ case THERMAL_TYPE_ADT7473_WITH_INTERNAL:
+ case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
+ return false; /* need special handling */
+ case THERMAL_TYPE_NONE:
+ case THERMAL_TYPE_EXTERNAL:
+ case THERMAL_TYPE_EXTERNAL_GPIO:
+ default:
+ return false;
+ }
+}
+
+union power_info {
+ struct _ATOM_POWERPLAY_INFO info;
+ struct _ATOM_POWERPLAY_INFO_V2 info_2;
+ struct _ATOM_POWERPLAY_INFO_V3 info_3;
+ struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+ struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+ struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+ struct _ATOM_PPLIB_POWERPLAYTABLE4 pplib4;
+ struct _ATOM_PPLIB_POWERPLAYTABLE5 pplib5;
+};
+
+union fan_info {
+ struct _ATOM_PPLIB_FANTABLE fan;
+ struct _ATOM_PPLIB_FANTABLE2 fan2;
+ struct _ATOM_PPLIB_FANTABLE3 fan3;
+};
+
+static int amdgpu_parse_clk_voltage_dep_table(struct amdgpu_clock_voltage_dependency_table *amdgpu_table,
+ ATOM_PPLIB_Clock_Voltage_Dependency_Table *atom_table)
+{
+ u32 size = atom_table->ucNumEntries *
+ sizeof(struct amdgpu_clock_voltage_dependency_entry);
+ int i;
+ ATOM_PPLIB_Clock_Voltage_Dependency_Record *entry;
+
+ amdgpu_table->entries = kzalloc(size, GFP_KERNEL);
+ if (!amdgpu_table->entries)
+ return -ENOMEM;
+
+ entry = &atom_table->entries[0];
+ for (i = 0; i < atom_table->ucNumEntries; i++) {
+ amdgpu_table->entries[i].clk = le16_to_cpu(entry->usClockLow) |
+ (entry->ucClockHigh << 16);
+ amdgpu_table->entries[i].v = le16_to_cpu(entry->usVoltage);
+ entry = (ATOM_PPLIB_Clock_Voltage_Dependency_Record *)
+ ((u8 *)entry + sizeof(ATOM_PPLIB_Clock_Voltage_Dependency_Record));
+ }
+ amdgpu_table->count = atom_table->ucNumEntries;
+
+ return 0;
+}
+
+int amdgpu_get_platform_caps(struct amdgpu_device *adev)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ union power_info *power_info;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ u16 data_offset;
+ u8 frev, crev;
+
+ if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset))
+ return -EINVAL;
+ power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+ adev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+ adev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+ adev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+
+ return 0;
+}
+
+/* sizeof(ATOM_PPLIB_EXTENDEDHEADER) */
+#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
+
+int amdgpu_parse_extended_power_table(struct amdgpu_device *adev)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ union power_info *power_info;
+ union fan_info *fan_info;
+ ATOM_PPLIB_Clock_Voltage_Dependency_Table *dep_table;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ u16 data_offset;
+ u8 frev, crev;
+ int ret, i;
+
+ if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset))
+ return -EINVAL;
+ power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+ /* fan table */
+ if (le16_to_cpu(power_info->pplib.usTableSize) >=
+ sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) {
+ if (power_info->pplib3.usFanTableOffset) {
+ fan_info = (union fan_info *)(mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib3.usFanTableOffset));
+ adev->pm.dpm.fan.t_hyst = fan_info->fan.ucTHyst;
+ adev->pm.dpm.fan.t_min = le16_to_cpu(fan_info->fan.usTMin);
+ adev->pm.dpm.fan.t_med = le16_to_cpu(fan_info->fan.usTMed);
+ adev->pm.dpm.fan.t_high = le16_to_cpu(fan_info->fan.usTHigh);
+ adev->pm.dpm.fan.pwm_min = le16_to_cpu(fan_info->fan.usPWMMin);
+ adev->pm.dpm.fan.pwm_med = le16_to_cpu(fan_info->fan.usPWMMed);
+ adev->pm.dpm.fan.pwm_high = le16_to_cpu(fan_info->fan.usPWMHigh);
+ if (fan_info->fan.ucFanTableFormat >= 2)
+ adev->pm.dpm.fan.t_max = le16_to_cpu(fan_info->fan2.usTMax);
+ else
+ adev->pm.dpm.fan.t_max = 10900;
+ adev->pm.dpm.fan.cycle_delay = 100000;
+ if (fan_info->fan.ucFanTableFormat >= 3) {
+ adev->pm.dpm.fan.control_mode = fan_info->fan3.ucFanControlMode;
+ adev->pm.dpm.fan.default_max_fan_pwm =
+ le16_to_cpu(fan_info->fan3.usFanPWMMax);
+ adev->pm.dpm.fan.default_fan_output_sensitivity = 4836;
+ adev->pm.dpm.fan.fan_output_sensitivity =
+ le16_to_cpu(fan_info->fan3.usFanOutputSensitivity);
+ }
+ adev->pm.dpm.fan.ucode_fan_control = true;
+ }
+ }
+
+ /* clock dependancy tables, shedding tables */
+ if (le16_to_cpu(power_info->pplib.usTableSize) >=
+ sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE4)) {
+ if (power_info->pplib4.usVddcDependencyOnSCLKOffset) {
+ dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib4.usVddcDependencyOnSCLKOffset));
+ ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+ dep_table);
+ if (ret) {
+ amdgpu_free_extended_power_table(adev);
+ return ret;
+ }
+ }
+ if (power_info->pplib4.usVddciDependencyOnMCLKOffset) {
+ dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib4.usVddciDependencyOnMCLKOffset));
+ ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+ dep_table);
+ if (ret) {
+ amdgpu_free_extended_power_table(adev);
+ return ret;
+ }
+ }
+ if (power_info->pplib4.usVddcDependencyOnMCLKOffset) {
+ dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib4.usVddcDependencyOnMCLKOffset));
+ ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+ dep_table);
+ if (ret) {
+ amdgpu_free_extended_power_table(adev);
+ return ret;
+ }
+ }
+ if (power_info->pplib4.usMvddDependencyOnMCLKOffset) {
+ dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib4.usMvddDependencyOnMCLKOffset));
+ ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
+ dep_table);
+ if (ret) {
+ amdgpu_free_extended_power_table(adev);
+ return ret;
+ }
+ }
+ if (power_info->pplib4.usMaxClockVoltageOnDCOffset) {
+ ATOM_PPLIB_Clock_Voltage_Limit_Table *clk_v =
+ (ATOM_PPLIB_Clock_Voltage_Limit_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib4.usMaxClockVoltageOnDCOffset));
+ if (clk_v->ucNumEntries) {
+ adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk =
+ le16_to_cpu(clk_v->entries[0].usSclkLow) |
+ (clk_v->entries[0].ucSclkHigh << 16);
+ adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk =
+ le16_to_cpu(clk_v->entries[0].usMclkLow) |
+ (clk_v->entries[0].ucMclkHigh << 16);
+ adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc =
+ le16_to_cpu(clk_v->entries[0].usVddc);
+ adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddci =
+ le16_to_cpu(clk_v->entries[0].usVddci);
+ }
+ }
+ if (power_info->pplib4.usVddcPhaseShedLimitsTableOffset) {
+ ATOM_PPLIB_PhaseSheddingLimits_Table *psl =
+ (ATOM_PPLIB_PhaseSheddingLimits_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib4.usVddcPhaseShedLimitsTableOffset));
+ ATOM_PPLIB_PhaseSheddingLimits_Record *entry;
+
+ adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries =
+ kzalloc(psl->ucNumEntries *
+ sizeof(struct amdgpu_phase_shedding_limits_entry),
+ GFP_KERNEL);
+ if (!adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries) {
+ amdgpu_free_extended_power_table(adev);
+ return -ENOMEM;
+ }
+
+ entry = &psl->entries[0];
+ for (i = 0; i < psl->ucNumEntries; i++) {
+ adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].sclk =
+ le16_to_cpu(entry->usSclkLow) | (entry->ucSclkHigh << 16);
+ adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].mclk =
+ le16_to_cpu(entry->usMclkLow) | (entry->ucMclkHigh << 16);
+ adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].voltage =
+ le16_to_cpu(entry->usVoltage);
+ entry = (ATOM_PPLIB_PhaseSheddingLimits_Record *)
+ ((u8 *)entry + sizeof(ATOM_PPLIB_PhaseSheddingLimits_Record));
+ }
+ adev->pm.dpm.dyn_state.phase_shedding_limits_table.count =
+ psl->ucNumEntries;
+ }
+ }
+
+ /* cac data */
+ if (le16_to_cpu(power_info->pplib.usTableSize) >=
+ sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE5)) {
+ adev->pm.dpm.tdp_limit = le32_to_cpu(power_info->pplib5.ulTDPLimit);
+ adev->pm.dpm.near_tdp_limit = le32_to_cpu(power_info->pplib5.ulNearTDPLimit);
+ adev->pm.dpm.near_tdp_limit_adjusted = adev->pm.dpm.near_tdp_limit;
+ adev->pm.dpm.tdp_od_limit = le16_to_cpu(power_info->pplib5.usTDPODLimit);
+ if (adev->pm.dpm.tdp_od_limit)
+ adev->pm.dpm.power_control = true;
+ else
+ adev->pm.dpm.power_control = false;
+ adev->pm.dpm.tdp_adjustment = 0;
+ adev->pm.dpm.sq_ramping_threshold = le32_to_cpu(power_info->pplib5.ulSQRampingThreshold);
+ adev->pm.dpm.cac_leakage = le32_to_cpu(power_info->pplib5.ulCACLeakage);
+ adev->pm.dpm.load_line_slope = le16_to_cpu(power_info->pplib5.usLoadLineSlope);
+ if (power_info->pplib5.usCACLeakageTableOffset) {
+ ATOM_PPLIB_CAC_Leakage_Table *cac_table =
+ (ATOM_PPLIB_CAC_Leakage_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib5.usCACLeakageTableOffset));
+ ATOM_PPLIB_CAC_Leakage_Record *entry;
+ u32 size = cac_table->ucNumEntries * sizeof(struct amdgpu_cac_leakage_table);
+ adev->pm.dpm.dyn_state.cac_leakage_table.entries = kzalloc(size, GFP_KERNEL);
+ if (!adev->pm.dpm.dyn_state.cac_leakage_table.entries) {
+ amdgpu_free_extended_power_table(adev);
+ return -ENOMEM;
+ }
+ entry = &cac_table->entries[0];
+ for (i = 0; i < cac_table->ucNumEntries; i++) {
+ if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) {
+ adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc1 =
+ le16_to_cpu(entry->usVddc1);
+ adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc2 =
+ le16_to_cpu(entry->usVddc2);
+ adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc3 =
+ le16_to_cpu(entry->usVddc3);
+ } else {
+ adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc =
+ le16_to_cpu(entry->usVddc);
+ adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage =
+ le32_to_cpu(entry->ulLeakageValue);
+ }
+ entry = (ATOM_PPLIB_CAC_Leakage_Record *)
+ ((u8 *)entry + sizeof(ATOM_PPLIB_CAC_Leakage_Record));
+ }
+ adev->pm.dpm.dyn_state.cac_leakage_table.count = cac_table->ucNumEntries;
+ }
+ }
+
+ /* ext tables */
+ if (le16_to_cpu(power_info->pplib.usTableSize) >=
+ sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) {
+ ATOM_PPLIB_EXTENDEDHEADER *ext_hdr = (ATOM_PPLIB_EXTENDEDHEADER *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib3.usExtendendedHeaderOffset));
+ if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2) &&
+ ext_hdr->usVCETableOffset) {
+ VCEClockInfoArray *array = (VCEClockInfoArray *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(ext_hdr->usVCETableOffset) + 1);
+ ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *limits =
+ (ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(ext_hdr->usVCETableOffset) + 1 +
+ 1 + array->ucNumEntries * sizeof(VCEClockInfo));
+ ATOM_PPLIB_VCE_State_Table *states =
+ (ATOM_PPLIB_VCE_State_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(ext_hdr->usVCETableOffset) + 1 +
+ 1 + (array->ucNumEntries * sizeof (VCEClockInfo)) +
+ 1 + (limits->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record)));
+ ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *entry;
+ ATOM_PPLIB_VCE_State_Record *state_entry;
+ VCEClockInfo *vce_clk;
+ u32 size = limits->numEntries *
+ sizeof(struct amdgpu_vce_clock_voltage_dependency_entry);
+ adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries =
+ kzalloc(size, GFP_KERNEL);
+ if (!adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries) {
+ amdgpu_free_extended_power_table(adev);
+ return -ENOMEM;
+ }
+ adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count =
+ limits->numEntries;
+ entry = &limits->entries[0];
+ state_entry = &states->entries[0];
+ for (i = 0; i < limits->numEntries; i++) {
+ vce_clk = (VCEClockInfo *)
+ ((u8 *)&array->entries[0] +
+ (entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo)));
+ adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].evclk =
+ le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16);
+ adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].ecclk =
+ le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16);
+ adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].v =
+ le16_to_cpu(entry->usVoltage);
+ entry = (ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *)
+ ((u8 *)entry + sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record));
+ }
+ for (i = 0; i < states->numEntries; i++) {
+ if (i >= AMDGPU_MAX_VCE_LEVELS)
+ break;
+ vce_clk = (VCEClockInfo *)
+ ((u8 *)&array->entries[0] +
+ (state_entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo)));
+ adev->pm.dpm.vce_states[i].evclk =
+ le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16);
+ adev->pm.dpm.vce_states[i].ecclk =
+ le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16);
+ adev->pm.dpm.vce_states[i].clk_idx =
+ state_entry->ucClockInfoIndex & 0x3f;
+ adev->pm.dpm.vce_states[i].pstate =
+ (state_entry->ucClockInfoIndex & 0xc0) >> 6;
+ state_entry = (ATOM_PPLIB_VCE_State_Record *)
+ ((u8 *)state_entry + sizeof(ATOM_PPLIB_VCE_State_Record));
+ }
+ }
+ if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3) &&
+ ext_hdr->usUVDTableOffset) {
+ UVDClockInfoArray *array = (UVDClockInfoArray *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(ext_hdr->usUVDTableOffset) + 1);
+ ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *limits =
+ (ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(ext_hdr->usUVDTableOffset) + 1 +
+ 1 + (array->ucNumEntries * sizeof (UVDClockInfo)));
+ ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *entry;
+ u32 size = limits->numEntries *
+ sizeof(struct amdgpu_uvd_clock_voltage_dependency_entry);
+ adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries =
+ kzalloc(size, GFP_KERNEL);
+ if (!adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries) {
+ amdgpu_free_extended_power_table(adev);
+ return -ENOMEM;
+ }
+ adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count =
+ limits->numEntries;
+ entry = &limits->entries[0];
+ for (i = 0; i < limits->numEntries; i++) {
+ UVDClockInfo *uvd_clk = (UVDClockInfo *)
+ ((u8 *)&array->entries[0] +
+ (entry->ucUVDClockInfoIndex * sizeof(UVDClockInfo)));
+ adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].vclk =
+ le16_to_cpu(uvd_clk->usVClkLow) | (uvd_clk->ucVClkHigh << 16);
+ adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].dclk =
+ le16_to_cpu(uvd_clk->usDClkLow) | (uvd_clk->ucDClkHigh << 16);
+ adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].v =
+ le16_to_cpu(entry->usVoltage);
+ entry = (ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *)
+ ((u8 *)entry + sizeof(ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record));
+ }
+ }
+ if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4) &&
+ ext_hdr->usSAMUTableOffset) {
+ ATOM_PPLIB_SAMClk_Voltage_Limit_Table *limits =
+ (ATOM_PPLIB_SAMClk_Voltage_Limit_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(ext_hdr->usSAMUTableOffset) + 1);
+ ATOM_PPLIB_SAMClk_Voltage_Limit_Record *entry;
+ u32 size = limits->numEntries *
+ sizeof(struct amdgpu_clock_voltage_dependency_entry);
+ adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries =
+ kzalloc(size, GFP_KERNEL);
+ if (!adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries) {
+ amdgpu_free_extended_power_table(adev);
+ return -ENOMEM;
+ }
+ adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count =
+ limits->numEntries;
+ entry = &limits->entries[0];
+ for (i = 0; i < limits->numEntries; i++) {
+ adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].clk =
+ le16_to_cpu(entry->usSAMClockLow) | (entry->ucSAMClockHigh << 16);
+ adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].v =
+ le16_to_cpu(entry->usVoltage);
+ entry = (ATOM_PPLIB_SAMClk_Voltage_Limit_Record *)
+ ((u8 *)entry + sizeof(ATOM_PPLIB_SAMClk_Voltage_Limit_Record));
+ }
+ }
+ if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) &&
+ ext_hdr->usPPMTableOffset) {
+ ATOM_PPLIB_PPM_Table *ppm = (ATOM_PPLIB_PPM_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(ext_hdr->usPPMTableOffset));
+ adev->pm.dpm.dyn_state.ppm_table =
+ kzalloc(sizeof(struct amdgpu_ppm_table), GFP_KERNEL);
+ if (!adev->pm.dpm.dyn_state.ppm_table) {
+ amdgpu_free_extended_power_table(adev);
+ return -ENOMEM;
+ }
+ adev->pm.dpm.dyn_state.ppm_table->ppm_design = ppm->ucPpmDesign;
+ adev->pm.dpm.dyn_state.ppm_table->cpu_core_number =
+ le16_to_cpu(ppm->usCpuCoreNumber);
+ adev->pm.dpm.dyn_state.ppm_table->platform_tdp =
+ le32_to_cpu(ppm->ulPlatformTDP);
+ adev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdp =
+ le32_to_cpu(ppm->ulSmallACPlatformTDP);
+ adev->pm.dpm.dyn_state.ppm_table->platform_tdc =
+ le32_to_cpu(ppm->ulPlatformTDC);
+ adev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdc =
+ le32_to_cpu(ppm->ulSmallACPlatformTDC);
+ adev->pm.dpm.dyn_state.ppm_table->apu_tdp =
+ le32_to_cpu(ppm->ulApuTDP);
+ adev->pm.dpm.dyn_state.ppm_table->dgpu_tdp =
+ le32_to_cpu(ppm->ulDGpuTDP);
+ adev->pm.dpm.dyn_state.ppm_table->dgpu_ulv_power =
+ le32_to_cpu(ppm->ulDGpuUlvPower);
+ adev->pm.dpm.dyn_state.ppm_table->tj_max =
+ le32_to_cpu(ppm->ulTjmax);
+ }
+ if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6) &&
+ ext_hdr->usACPTableOffset) {
+ ATOM_PPLIB_ACPClk_Voltage_Limit_Table *limits =
+ (ATOM_PPLIB_ACPClk_Voltage_Limit_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(ext_hdr->usACPTableOffset) + 1);
+ ATOM_PPLIB_ACPClk_Voltage_Limit_Record *entry;
+ u32 size = limits->numEntries *
+ sizeof(struct amdgpu_clock_voltage_dependency_entry);
+ adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries =
+ kzalloc(size, GFP_KERNEL);
+ if (!adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries) {
+ amdgpu_free_extended_power_table(adev);
+ return -ENOMEM;
+ }
+ adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count =
+ limits->numEntries;
+ entry = &limits->entries[0];
+ for (i = 0; i < limits->numEntries; i++) {
+ adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].clk =
+ le16_to_cpu(entry->usACPClockLow) | (entry->ucACPClockHigh << 16);
+ adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].v =
+ le16_to_cpu(entry->usVoltage);
+ entry = (ATOM_PPLIB_ACPClk_Voltage_Limit_Record *)
+ ((u8 *)entry + sizeof(ATOM_PPLIB_ACPClk_Voltage_Limit_Record));
+ }
+ }
+ if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7) &&
+ ext_hdr->usPowerTuneTableOffset) {
+ u8 rev = *(u8 *)(mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
+ ATOM_PowerTune_Table *pt;
+ adev->pm.dpm.dyn_state.cac_tdp_table =
+ kzalloc(sizeof(struct amdgpu_cac_tdp_table), GFP_KERNEL);
+ if (!adev->pm.dpm.dyn_state.cac_tdp_table) {
+ amdgpu_free_extended_power_table(adev);
+ return -ENOMEM;
+ }
+ if (rev > 0) {
+ ATOM_PPLIB_POWERTUNE_Table_V1 *ppt = (ATOM_PPLIB_POWERTUNE_Table_V1 *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
+ adev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit =
+ ppt->usMaximumPowerDeliveryLimit;
+ pt = &ppt->power_tune_table;
+ } else {
+ ATOM_PPLIB_POWERTUNE_Table *ppt = (ATOM_PPLIB_POWERTUNE_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
+ adev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit = 255;
+ pt = &ppt->power_tune_table;
+ }
+ adev->pm.dpm.dyn_state.cac_tdp_table->tdp = le16_to_cpu(pt->usTDP);
+ adev->pm.dpm.dyn_state.cac_tdp_table->configurable_tdp =
+ le16_to_cpu(pt->usConfigurableTDP);
+ adev->pm.dpm.dyn_state.cac_tdp_table->tdc = le16_to_cpu(pt->usTDC);
+ adev->pm.dpm.dyn_state.cac_tdp_table->battery_power_limit =
+ le16_to_cpu(pt->usBatteryPowerLimit);
+ adev->pm.dpm.dyn_state.cac_tdp_table->small_power_limit =
+ le16_to_cpu(pt->usSmallPowerLimit);
+ adev->pm.dpm.dyn_state.cac_tdp_table->low_cac_leakage =
+ le16_to_cpu(pt->usLowCACLeakage);
+ adev->pm.dpm.dyn_state.cac_tdp_table->high_cac_leakage =
+ le16_to_cpu(pt->usHighCACLeakage);
+ }
+ if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8) &&
+ ext_hdr->usSclkVddgfxTableOffset) {
+ dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(ext_hdr->usSclkVddgfxTableOffset));
+ ret = amdgpu_parse_clk_voltage_dep_table(
+ &adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk,
+ dep_table);
+ if (ret) {
+ kfree(adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk.entries);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void amdgpu_free_extended_power_table(struct amdgpu_device *adev)
+{
+ struct amdgpu_dpm_dynamic_state *dyn_state = &adev->pm.dpm.dyn_state;
+
+ kfree(dyn_state->vddc_dependency_on_sclk.entries);
+ kfree(dyn_state->vddci_dependency_on_mclk.entries);
+ kfree(dyn_state->vddc_dependency_on_mclk.entries);
+ kfree(dyn_state->mvdd_dependency_on_mclk.entries);
+ kfree(dyn_state->cac_leakage_table.entries);
+ kfree(dyn_state->phase_shedding_limits_table.entries);
+ kfree(dyn_state->ppm_table);
+ kfree(dyn_state->cac_tdp_table);
+ kfree(dyn_state->vce_clock_voltage_dependency_table.entries);
+ kfree(dyn_state->uvd_clock_voltage_dependency_table.entries);
+ kfree(dyn_state->samu_clock_voltage_dependency_table.entries);
+ kfree(dyn_state->acp_clock_voltage_dependency_table.entries);
+ kfree(dyn_state->vddgfx_dependency_on_sclk.entries);
+}
+
+static const char *pp_lib_thermal_controller_names[] = {
+ "NONE",
+ "lm63",
+ "adm1032",
+ "adm1030",
+ "max6649",
+ "lm64",
+ "f75375",
+ "RV6xx",
+ "RV770",
+ "adt7473",
+ "NONE",
+ "External GPIO",
+ "Evergreen",
+ "emc2103",
+ "Sumo",
+ "Northern Islands",
+ "Southern Islands",
+ "lm96163",
+ "Sea Islands",
+ "Kaveri/Kabini",
+};
+
+void amdgpu_add_thermal_controller(struct amdgpu_device *adev)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ ATOM_PPLIB_POWERPLAYTABLE *power_table;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ ATOM_PPLIB_THERMALCONTROLLER *controller;
+ struct amdgpu_i2c_bus_rec i2c_bus;
+ u16 data_offset;
+ u8 frev, crev;
+
+ if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset))
+ return;
+ power_table = (ATOM_PPLIB_POWERPLAYTABLE *)
+ (mode_info->atom_context->bios + data_offset);
+ controller = &power_table->sThermalController;
+
+ /* add the i2c bus for thermal/fan chip */
+ if (controller->ucType > 0) {
+ if (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN)
+ adev->pm.no_fan = true;
+ adev->pm.fan_pulses_per_revolution =
+ controller->ucFanParameters & ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
+ if (adev->pm.fan_pulses_per_revolution) {
+ adev->pm.fan_min_rpm = controller->ucFanMinRPM;
+ adev->pm.fan_max_rpm = controller->ucFanMaxRPM;
+ }
+ if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ adev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ adev->pm.int_thermal_type = THERMAL_TYPE_RV770;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ adev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ adev->pm.int_thermal_type = THERMAL_TYPE_SUMO;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ adev->pm.int_thermal_type = THERMAL_TYPE_NI;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ adev->pm.int_thermal_type = THERMAL_TYPE_SI;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ adev->pm.int_thermal_type = THERMAL_TYPE_CI;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) {
+ DRM_INFO("Internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ adev->pm.int_thermal_type = THERMAL_TYPE_KV;
+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) {
+ DRM_INFO("External GPIO thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ adev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL_GPIO;
+ } else if (controller->ucType ==
+ ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) {
+ DRM_INFO("ADT7473 with internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ adev->pm.int_thermal_type = THERMAL_TYPE_ADT7473_WITH_INTERNAL;
+ } else if (controller->ucType ==
+ ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL) {
+ DRM_INFO("EMC2103 with internal thermal controller %s fan control\n",
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ adev->pm.int_thermal_type = THERMAL_TYPE_EMC2103_WITH_INTERNAL;
+ } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) {
+ DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
+ pp_lib_thermal_controller_names[controller->ucType],
+ controller->ucI2cAddress >> 1,
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ adev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL;
+ i2c_bus = amdgpu_atombios_lookup_i2c_gpio(adev, controller->ucI2cLine);
+ adev->pm.i2c_bus = amdgpu_i2c_lookup(adev, &i2c_bus);
+ if (adev->pm.i2c_bus) {
+ struct i2c_board_info info = { };
+ const char *name = pp_lib_thermal_controller_names[controller->ucType];
+ info.addr = controller->ucI2cAddress >> 1;
+ strlcpy(info.type, name, sizeof(info.type));
+ i2c_new_device(&adev->pm.i2c_bus->adapter, &info);
+ }
+ } else {
+ DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n",
+ controller->ucType,
+ controller->ucI2cAddress >> 1,
+ (controller->ucFanParameters &
+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
+ }
+ }
+}
+
+enum amdgpu_pcie_gen amdgpu_get_pcie_gen_support(struct amdgpu_device *adev,
+ u32 sys_mask,
+ enum amdgpu_pcie_gen asic_gen,
+ enum amdgpu_pcie_gen default_gen)
+{
+ switch (asic_gen) {
+ case AMDGPU_PCIE_GEN1:
+ return AMDGPU_PCIE_GEN1;
+ case AMDGPU_PCIE_GEN2:
+ return AMDGPU_PCIE_GEN2;
+ case AMDGPU_PCIE_GEN3:
+ return AMDGPU_PCIE_GEN3;
+ default:
+ if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == AMDGPU_PCIE_GEN3))
+ return AMDGPU_PCIE_GEN3;
+ else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == AMDGPU_PCIE_GEN2))
+ return AMDGPU_PCIE_GEN2;
+ else
+ return AMDGPU_PCIE_GEN1;
+ }
+ return AMDGPU_PCIE_GEN1;
+}
+
+u16 amdgpu_get_pcie_lane_support(struct amdgpu_device *adev,
+ u16 asic_lanes,
+ u16 default_lanes)
+{
+ switch (asic_lanes) {
+ case 0:
+ default:
+ return default_lanes;
+ case 1:
+ return 1;
+ case 2:
+ return 2;
+ case 4:
+ return 4;
+ case 8:
+ return 8;
+ case 12:
+ return 12;
+ case 16:
+ return 16;
+ }
+}
+
+u8 amdgpu_encode_pci_lane_width(u32 lanes)
+{
+ u8 encoded_lanes[] = { 0, 1, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6 };
+
+ if (lanes > 16)
+ return 0;
+
+ return encoded_lanes[lanes];
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
new file mode 100644
index 000000000000..3738a96c2619
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __AMDGPU_DPM_H__
+#define __AMDGPU_DPM_H__
+
+#define R600_SSTU_DFLT 0
+#define R600_SST_DFLT 0x00C8
+
+/* XXX are these ok? */
+#define R600_TEMP_RANGE_MIN (90 * 1000)
+#define R600_TEMP_RANGE_MAX (120 * 1000)
+
+#define FDO_PWM_MODE_STATIC 1
+#define FDO_PWM_MODE_STATIC_RPM 5
+
+enum amdgpu_td {
+ AMDGPU_TD_AUTO,
+ AMDGPU_TD_UP,
+ AMDGPU_TD_DOWN,
+};
+
+enum amdgpu_display_watermark {
+ AMDGPU_DISPLAY_WATERMARK_LOW = 0,
+ AMDGPU_DISPLAY_WATERMARK_HIGH = 1,
+};
+
+enum amdgpu_display_gap
+{
+ AMDGPU_PM_DISPLAY_GAP_VBLANK_OR_WM = 0,
+ AMDGPU_PM_DISPLAY_GAP_VBLANK = 1,
+ AMDGPU_PM_DISPLAY_GAP_WATERMARK = 2,
+ AMDGPU_PM_DISPLAY_GAP_IGNORE = 3,
+};
+
+void amdgpu_dpm_print_class_info(u32 class, u32 class2);
+void amdgpu_dpm_print_cap_info(u32 caps);
+void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps);
+u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev);
+u32 amdgpu_dpm_get_vrefresh(struct amdgpu_device *adev);
+bool amdgpu_is_uvd_state(u32 class, u32 class2);
+void amdgpu_calculate_u_and_p(u32 i, u32 r_c, u32 p_b,
+ u32 *p, u32 *u);
+int amdgpu_calculate_at(u32 t, u32 h, u32 fh, u32 fl, u32 *tl, u32 *th);
+
+bool amdgpu_is_internal_thermal_sensor(enum amdgpu_int_thermal_type sensor);
+
+int amdgpu_get_platform_caps(struct amdgpu_device *adev);
+
+int amdgpu_parse_extended_power_table(struct amdgpu_device *adev);
+void amdgpu_free_extended_power_table(struct amdgpu_device *adev);
+
+void amdgpu_add_thermal_controller(struct amdgpu_device *adev);
+
+enum amdgpu_pcie_gen amdgpu_get_pcie_gen_support(struct amdgpu_device *adev,
+ u32 sys_mask,
+ enum amdgpu_pcie_gen asic_gen,
+ enum amdgpu_pcie_gen default_gen);
+
+u16 amdgpu_get_pcie_lane_support(struct amdgpu_device *adev,
+ u16 asic_lanes,
+ u16 default_lanes);
+u8 amdgpu_encode_pci_lane_width(u32 lanes);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
new file mode 100644
index 000000000000..56da962231fc
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -0,0 +1,545 @@
+/**
+ * \file amdgpu_drv.c
+ * AMD Amdgpu driver
+ *
+ * \author Gareth Hughes <gareth@valinux.com>
+ */
+
+/*
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, 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
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include <drm/drm_gem.h>
+#include "amdgpu_drv.h"
+
+#include <drm/drm_pciids.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/vga_switcheroo.h>
+#include "drm_crtc_helper.h"
+
+#include "amdgpu.h"
+#include "amdgpu_irq.h"
+
+/*
+ * KMS wrapper.
+ * - 3.0.0 - initial driver
+ */
+#define KMS_DRIVER_MAJOR 3
+#define KMS_DRIVER_MINOR 0
+#define KMS_DRIVER_PATCHLEVEL 0
+
+int amdgpu_vram_limit = 0;
+int amdgpu_gart_size = -1; /* auto */
+int amdgpu_benchmarking = 0;
+int amdgpu_testing = 0;
+int amdgpu_audio = -1;
+int amdgpu_disp_priority = 0;
+int amdgpu_hw_i2c = 0;
+int amdgpu_pcie_gen2 = -1;
+int amdgpu_msi = -1;
+int amdgpu_lockup_timeout = 10000;
+int amdgpu_dpm = -1;
+int amdgpu_smc_load_fw = 1;
+int amdgpu_aspm = -1;
+int amdgpu_runtime_pm = -1;
+int amdgpu_hard_reset = 0;
+unsigned amdgpu_ip_block_mask = 0xffffffff;
+int amdgpu_bapm = -1;
+int amdgpu_deep_color = 0;
+int amdgpu_vm_size = 8;
+int amdgpu_vm_block_size = -1;
+int amdgpu_exp_hw_support = 0;
+
+MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes");
+module_param_named(vramlimit, amdgpu_vram_limit, int, 0600);
+
+MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32, 64, etc., -1 = auto)");
+module_param_named(gartsize, amdgpu_gart_size, int, 0600);
+
+MODULE_PARM_DESC(benchmark, "Run benchmark");
+module_param_named(benchmark, amdgpu_benchmarking, int, 0444);
+
+MODULE_PARM_DESC(test, "Run tests");
+module_param_named(test, amdgpu_testing, int, 0444);
+
+MODULE_PARM_DESC(audio, "Audio enable (-1 = auto, 0 = disable, 1 = enable)");
+module_param_named(audio, amdgpu_audio, int, 0444);
+
+MODULE_PARM_DESC(disp_priority, "Display Priority (0 = auto, 1 = normal, 2 = high)");
+module_param_named(disp_priority, amdgpu_disp_priority, int, 0444);
+
+MODULE_PARM_DESC(hw_i2c, "hw i2c engine enable (0 = disable)");
+module_param_named(hw_i2c, amdgpu_hw_i2c, int, 0444);
+
+MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (-1 = auto, 0 = disable, 1 = enable)");
+module_param_named(pcie_gen2, amdgpu_pcie_gen2, int, 0444);
+
+MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)");
+module_param_named(msi, amdgpu_msi, int, 0444);
+
+MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (defaul 10000 = 10 seconds, 0 = disable)");
+module_param_named(lockup_timeout, amdgpu_lockup_timeout, int, 0444);
+
+MODULE_PARM_DESC(dpm, "DPM support (1 = enable, 0 = disable, -1 = auto)");
+module_param_named(dpm, amdgpu_dpm, int, 0444);
+
+MODULE_PARM_DESC(smc_load_fw, "SMC firmware loading(1 = enable, 0 = disable)");
+module_param_named(smc_load_fw, amdgpu_smc_load_fw, int, 0444);
+
+MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)");
+module_param_named(aspm, amdgpu_aspm, int, 0444);
+
+MODULE_PARM_DESC(runpm, "PX runtime pm (1 = force enable, 0 = disable, -1 = PX only default)");
+module_param_named(runpm, amdgpu_runtime_pm, int, 0444);
+
+MODULE_PARM_DESC(hard_reset, "PCI config reset (1 = force enable, 0 = disable (default))");
+module_param_named(hard_reset, amdgpu_hard_reset, int, 0444);
+
+MODULE_PARM_DESC(ip_block_mask, "IP Block Mask (all blocks enabled (default))");
+module_param_named(ip_block_mask, amdgpu_ip_block_mask, uint, 0444);
+
+MODULE_PARM_DESC(bapm, "BAPM support (1 = enable, 0 = disable, -1 = auto)");
+module_param_named(bapm, amdgpu_bapm, int, 0444);
+
+MODULE_PARM_DESC(deep_color, "Deep Color support (1 = enable, 0 = disable (default))");
+module_param_named(deep_color, amdgpu_deep_color, int, 0444);
+
+MODULE_PARM_DESC(vm_size, "VM address space size in gigabytes (default 8GB)");
+module_param_named(vm_size, amdgpu_vm_size, int, 0444);
+
+MODULE_PARM_DESC(vm_block_size, "VM page table size in bits (default depending on vm_size)");
+module_param_named(vm_block_size, amdgpu_vm_block_size, int, 0444);
+
+MODULE_PARM_DESC(exp_hw_support, "experimental hw support (1 = enable, 0 = disable (default))");
+module_param_named(exp_hw_support, amdgpu_exp_hw_support, int, 0444);
+
+static struct pci_device_id pciidlist[] = {
+#ifdef CONFIG_DRM_AMDGPU_CIK
+ /* Kaveri */
+ {0x1002, 0x1304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x1305, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
+ {0x1002, 0x1306, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x1307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
+ {0x1002, 0x1309, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x130A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x130B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x130C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x130D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x130E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x130F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
+ {0x1002, 0x1310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
+ {0x1002, 0x1311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
+ {0x1002, 0x1312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
+ {0x1002, 0x1313, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
+ {0x1002, 0x1315, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
+ {0x1002, 0x1316, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
+ {0x1002, 0x1317, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x1318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x131B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
+ {0x1002, 0x131C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
+ {0x1002, 0x131D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|AMDGPU_IS_APU},
+ /* Bonaire */
+ {0x1002, 0x6640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMDGPU_IS_MOBILITY},
+ {0x1002, 0x6641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMDGPU_IS_MOBILITY},
+ {0x1002, 0x6646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMDGPU_IS_MOBILITY},
+ {0x1002, 0x6647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMDGPU_IS_MOBILITY},
+ {0x1002, 0x6649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
+ {0x1002, 0x6650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
+ {0x1002, 0x6651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
+ {0x1002, 0x6658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
+ {0x1002, 0x665c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
+ {0x1002, 0x665d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
+ {0x1002, 0x665f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE},
+ /* Hawaii */
+ {0x1002, 0x67A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
+ {0x1002, 0x67A1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
+ {0x1002, 0x67A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
+ {0x1002, 0x67A8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
+ {0x1002, 0x67A9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
+ {0x1002, 0x67AA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
+ {0x1002, 0x67B0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
+ {0x1002, 0x67B1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
+ {0x1002, 0x67B8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
+ {0x1002, 0x67B9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
+ {0x1002, 0x67BA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
+ {0x1002, 0x67BE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII},
+ /* Kabini */
+ {0x1002, 0x9830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
+ {0x1002, 0x9832, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9833, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
+ {0x1002, 0x9834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
+ {0x1002, 0x9836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
+ {0x1002, 0x9838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x983a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
+ {0x1002, 0x983b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x983c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
+ {0x1002, 0x983d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
+ {0x1002, 0x983e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
+ {0x1002, 0x983f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|AMDGPU_IS_APU},
+ /* mullins */
+ {0x1002, 0x9850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9851, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9852, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9853, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9854, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9855, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9856, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9857, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9858, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x9859, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x985A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x985B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x985C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x985D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x985E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+ {0x1002, 0x985F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMDGPU_IS_MOBILITY|AMDGPU_IS_APU},
+#endif
+ /* topaz */
+ {0x1002, 0x6900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+ {0x1002, 0x6901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+ {0x1002, 0x6902, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+ {0x1002, 0x6903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+ {0x1002, 0x6907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+ /* tonga */
+ {0x1002, 0x6920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
+ {0x1002, 0x6921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
+ {0x1002, 0x6928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
+ {0x1002, 0x6929, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
+ {0x1002, 0x692B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
+ {0x1002, 0x692F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
+ {0x1002, 0x6930, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
+ {0x1002, 0x6938, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
+ {0x1002, 0x6939, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
+ /* carrizo */
+ {0x1002, 0x9870, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMDGPU_IS_APU},
+ {0x1002, 0x9874, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMDGPU_IS_APU},
+ {0x1002, 0x9875, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMDGPU_IS_APU},
+ {0x1002, 0x9876, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMDGPU_IS_APU},
+ {0x1002, 0x9877, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CARRIZO|AMDGPU_IS_APU},
+
+ {0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, pciidlist);
+
+static struct drm_driver kms_driver;
+
+static int amdgpu_kick_out_firmware_fb(struct pci_dev *pdev)
+{
+ struct apertures_struct *ap;
+ bool primary = false;
+
+ ap = alloc_apertures(1);
+ if (!ap)
+ return -ENOMEM;
+
+ ap->ranges[0].base = pci_resource_start(pdev, 0);
+ ap->ranges[0].size = pci_resource_len(pdev, 0);
+
+#ifdef CONFIG_X86
+ primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
+#endif
+ remove_conflicting_framebuffers(ap, "amdgpudrmfb", primary);
+ kfree(ap);
+
+ return 0;
+}
+
+static int amdgpu_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ unsigned long flags = ent->driver_data;
+ int ret;
+
+ if ((flags & AMDGPU_EXP_HW_SUPPORT) && !amdgpu_exp_hw_support) {
+ DRM_INFO("This hardware requires experimental hardware support.\n"
+ "See modparam exp_hw_support\n");
+ return -ENODEV;
+ }
+
+ /* Get rid of things like offb */
+ ret = amdgpu_kick_out_firmware_fb(pdev);
+ if (ret)
+ return ret;
+
+ return drm_get_pci_dev(pdev, ent, &kms_driver);
+}
+
+static void
+amdgpu_pci_remove(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+
+ drm_put_dev(dev);
+}
+
+static int amdgpu_pmops_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ return amdgpu_suspend_kms(drm_dev, true, true);
+}
+
+static int amdgpu_pmops_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ return amdgpu_resume_kms(drm_dev, true, true);
+}
+
+static int amdgpu_pmops_freeze(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ return amdgpu_suspend_kms(drm_dev, false, true);
+}
+
+static int amdgpu_pmops_thaw(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ return amdgpu_resume_kms(drm_dev, false, true);
+}
+
+static int amdgpu_pmops_runtime_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ int ret;
+
+ if (!amdgpu_device_is_px(drm_dev)) {
+ pm_runtime_forbid(dev);
+ return -EBUSY;
+ }
+
+ drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
+ drm_kms_helper_poll_disable(drm_dev);
+ vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
+
+ ret = amdgpu_suspend_kms(drm_dev, false, false);
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_ignore_hotplug(pdev);
+ pci_set_power_state(pdev, PCI_D3cold);
+ drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
+
+ return 0;
+}
+
+static int amdgpu_pmops_runtime_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ int ret;
+
+ if (!amdgpu_device_is_px(drm_dev))
+ return -EINVAL;
+
+ drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+ pci_set_master(pdev);
+
+ ret = amdgpu_resume_kms(drm_dev, false, false);
+ drm_kms_helper_poll_enable(drm_dev);
+ vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
+ drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
+ return 0;
+}
+
+static int amdgpu_pmops_runtime_idle(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct drm_crtc *crtc;
+
+ if (!amdgpu_device_is_px(drm_dev)) {
+ pm_runtime_forbid(dev);
+ return -EBUSY;
+ }
+
+ list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
+ if (crtc->enabled) {
+ DRM_DEBUG_DRIVER("failing to power off - crtc active\n");
+ return -EBUSY;
+ }
+ }
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_autosuspend(dev);
+ /* we don't want the main rpm_idle to call suspend - we want to autosuspend */
+ return 1;
+}
+
+long amdgpu_drm_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct drm_file *file_priv = filp->private_data;
+ struct drm_device *dev;
+ long ret;
+ dev = file_priv->minor->dev;
+ ret = pm_runtime_get_sync(dev->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = drm_ioctl(filp, cmd, arg);
+
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
+ return ret;
+}
+
+static const struct dev_pm_ops amdgpu_pm_ops = {
+ .suspend = amdgpu_pmops_suspend,
+ .resume = amdgpu_pmops_resume,
+ .freeze = amdgpu_pmops_freeze,
+ .thaw = amdgpu_pmops_thaw,
+ .poweroff = amdgpu_pmops_freeze,
+ .restore = amdgpu_pmops_resume,
+ .runtime_suspend = amdgpu_pmops_runtime_suspend,
+ .runtime_resume = amdgpu_pmops_runtime_resume,
+ .runtime_idle = amdgpu_pmops_runtime_idle,
+};
+
+static const struct file_operations amdgpu_driver_kms_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = amdgpu_drm_ioctl,
+ .mmap = amdgpu_mmap,
+ .poll = drm_poll,
+ .read = drm_read,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = amdgpu_kms_compat_ioctl,
+#endif
+};
+
+static struct drm_driver kms_driver = {
+ .driver_features =
+ DRIVER_USE_AGP |
+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
+ DRIVER_PRIME | DRIVER_RENDER,
+ .dev_priv_size = 0,
+ .load = amdgpu_driver_load_kms,
+ .open = amdgpu_driver_open_kms,
+ .preclose = amdgpu_driver_preclose_kms,
+ .postclose = amdgpu_driver_postclose_kms,
+ .lastclose = amdgpu_driver_lastclose_kms,
+ .set_busid = drm_pci_set_busid,
+ .unload = amdgpu_driver_unload_kms,
+ .get_vblank_counter = amdgpu_get_vblank_counter_kms,
+ .enable_vblank = amdgpu_enable_vblank_kms,
+ .disable_vblank = amdgpu_disable_vblank_kms,
+ .get_vblank_timestamp = amdgpu_get_vblank_timestamp_kms,
+ .get_scanout_position = amdgpu_get_crtc_scanoutpos,
+#if defined(CONFIG_DEBUG_FS)
+ .debugfs_init = amdgpu_debugfs_init,
+ .debugfs_cleanup = amdgpu_debugfs_cleanup,
+#endif
+ .irq_preinstall = amdgpu_irq_preinstall,
+ .irq_postinstall = amdgpu_irq_postinstall,
+ .irq_uninstall = amdgpu_irq_uninstall,
+ .irq_handler = amdgpu_irq_handler,
+ .ioctls = amdgpu_ioctls_kms,
+ .gem_free_object = amdgpu_gem_object_free,
+ .gem_open_object = amdgpu_gem_object_open,
+ .gem_close_object = amdgpu_gem_object_close,
+ .dumb_create = amdgpu_mode_dumb_create,
+ .dumb_map_offset = amdgpu_mode_dumb_mmap,
+ .dumb_destroy = drm_gem_dumb_destroy,
+ .fops = &amdgpu_driver_kms_fops,
+
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = amdgpu_gem_prime_export,
+ .gem_prime_import = drm_gem_prime_import,
+ .gem_prime_pin = amdgpu_gem_prime_pin,
+ .gem_prime_unpin = amdgpu_gem_prime_unpin,
+ .gem_prime_res_obj = amdgpu_gem_prime_res_obj,
+ .gem_prime_get_sg_table = amdgpu_gem_prime_get_sg_table,
+ .gem_prime_import_sg_table = amdgpu_gem_prime_import_sg_table,
+ .gem_prime_vmap = amdgpu_gem_prime_vmap,
+ .gem_prime_vunmap = amdgpu_gem_prime_vunmap,
+
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = KMS_DRIVER_MAJOR,
+ .minor = KMS_DRIVER_MINOR,
+ .patchlevel = KMS_DRIVER_PATCHLEVEL,
+};
+
+static struct drm_driver *driver;
+static struct pci_driver *pdriver;
+
+static struct pci_driver amdgpu_kms_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
+ .probe = amdgpu_pci_probe,
+ .remove = amdgpu_pci_remove,
+ .driver.pm = &amdgpu_pm_ops,
+};
+
+static int __init amdgpu_init(void)
+{
+#ifdef CONFIG_VGA_CONSOLE
+ if (vgacon_text_force()) {
+ DRM_ERROR("VGACON disables amdgpu kernel modesetting.\n");
+ return -EINVAL;
+ }
+#endif
+ DRM_INFO("amdgpu kernel modesetting enabled.\n");
+ driver = &kms_driver;
+ pdriver = &amdgpu_kms_pci_driver;
+ driver->driver_features |= DRIVER_MODESET;
+ driver->num_ioctls = amdgpu_max_kms_ioctl;
+ amdgpu_register_atpx_handler();
+
+ /* let modprobe override vga console setting */
+ return drm_pci_init(driver, pdriver);
+}
+
+static void __exit amdgpu_exit(void)
+{
+ drm_pci_exit(driver, pdriver);
+ amdgpu_unregister_atpx_handler();
+}
+
+module_init(amdgpu_init);
+module_exit(amdgpu_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.h
new file mode 100644
index 000000000000..cceeb33c447a
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.h
@@ -0,0 +1,48 @@
+/* amdgpu_drv.h -- Private header for amdgpu driver -*- linux-c -*-
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * 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.
+ *
+ */
+
+#ifndef __AMDGPU_DRV_H__
+#define __AMDGPU_DRV_H__
+
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include "amdgpu_family.h"
+
+/* General customization:
+ */
+
+#define DRIVER_AUTHOR "AMD linux driver team"
+
+#define DRIVER_NAME "amdgpu"
+#define DRIVER_DESC "AMD GPU"
+#define DRIVER_DATE "20150101"
+
+long amdgpu_drm_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c
new file mode 100644
index 000000000000..94138abe093b
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2007-8 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 shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ */
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "amdgpu_connectors.h"
+#include "atom.h"
+#include "atombios_encoders.h"
+
+void
+amdgpu_link_encoder_connector(struct drm_device *dev)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector;
+ struct drm_encoder *encoder;
+ struct amdgpu_encoder *amdgpu_encoder;
+
+ /* walk the list and link encoders to connectors */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ amdgpu_connector = to_amdgpu_connector(connector);
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+ if (amdgpu_encoder->devices & amdgpu_connector->devices) {
+ drm_mode_connector_attach_encoder(connector, encoder);
+ if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ amdgpu_atombios_encoder_init_backlight(amdgpu_encoder, connector);
+ adev->mode_info.bl_encoder = amdgpu_encoder;
+ }
+ }
+ }
+ }
+}
+
+void amdgpu_encoder_set_active_device(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_connector *connector;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ if (connector->encoder == encoder) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ amdgpu_encoder->active_device = amdgpu_encoder->devices & amdgpu_connector->devices;
+ DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n",
+ amdgpu_encoder->active_device, amdgpu_encoder->devices,
+ amdgpu_connector->devices, encoder->encoder_type);
+ }
+ }
+}
+
+struct drm_connector *
+amdgpu_get_connector_for_encoder(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ amdgpu_connector = to_amdgpu_connector(connector);
+ if (amdgpu_encoder->active_device & amdgpu_connector->devices)
+ return connector;
+ }
+ return NULL;
+}
+
+struct drm_connector *
+amdgpu_get_connector_for_encoder_init(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ amdgpu_connector = to_amdgpu_connector(connector);
+ if (amdgpu_encoder->devices & amdgpu_connector->devices)
+ return connector;
+ }
+ return NULL;
+}
+
+struct drm_encoder *amdgpu_get_external_encoder(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_encoder *other_encoder;
+ struct amdgpu_encoder *other_amdgpu_encoder;
+
+ if (amdgpu_encoder->is_ext_encoder)
+ return NULL;
+
+ list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) {
+ if (other_encoder == encoder)
+ continue;
+ other_amdgpu_encoder = to_amdgpu_encoder(other_encoder);
+ if (other_amdgpu_encoder->is_ext_encoder &&
+ (amdgpu_encoder->devices & other_amdgpu_encoder->devices))
+ return other_encoder;
+ }
+ return NULL;
+}
+
+u16 amdgpu_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder)
+{
+ struct drm_encoder *other_encoder = amdgpu_get_external_encoder(encoder);
+
+ if (other_encoder) {
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(other_encoder);
+
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_TRAVIS:
+ case ENCODER_OBJECT_ID_NUTMEG:
+ return amdgpu_encoder->encoder_id;
+ default:
+ return ENCODER_OBJECT_ID_NONE;
+ }
+ }
+ return ENCODER_OBJECT_ID_NONE;
+}
+
+void amdgpu_panel_mode_fixup(struct drm_encoder *encoder,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
+ unsigned hblank = native_mode->htotal - native_mode->hdisplay;
+ unsigned vblank = native_mode->vtotal - native_mode->vdisplay;
+ unsigned hover = native_mode->hsync_start - native_mode->hdisplay;
+ unsigned vover = native_mode->vsync_start - native_mode->vdisplay;
+ unsigned hsync_width = native_mode->hsync_end - native_mode->hsync_start;
+ unsigned vsync_width = native_mode->vsync_end - native_mode->vsync_start;
+
+ adjusted_mode->clock = native_mode->clock;
+ adjusted_mode->flags = native_mode->flags;
+
+ adjusted_mode->hdisplay = native_mode->hdisplay;
+ adjusted_mode->vdisplay = native_mode->vdisplay;
+
+ adjusted_mode->htotal = native_mode->hdisplay + hblank;
+ adjusted_mode->hsync_start = native_mode->hdisplay + hover;
+ adjusted_mode->hsync_end = adjusted_mode->hsync_start + hsync_width;
+
+ adjusted_mode->vtotal = native_mode->vdisplay + vblank;
+ adjusted_mode->vsync_start = native_mode->vdisplay + vover;
+ adjusted_mode->vsync_end = adjusted_mode->vsync_start + vsync_width;
+
+ drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+
+ adjusted_mode->crtc_hdisplay = native_mode->hdisplay;
+ adjusted_mode->crtc_vdisplay = native_mode->vdisplay;
+
+ adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + hblank;
+ adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + hover;
+ adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + hsync_width;
+
+ adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + vblank;
+ adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + vover;
+ adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + vsync_width;
+
+}
+
+bool amdgpu_dig_monitor_is_duallink(struct drm_encoder *encoder,
+ u32 pixel_clock)
+{
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector;
+ struct amdgpu_connector_atom_dig *dig_connector;
+
+ connector = amdgpu_get_connector_for_encoder(encoder);
+ /* if we don't have an active device yet, just use one of
+ * the connectors tied to the encoder.
+ */
+ if (!connector)
+ connector = amdgpu_get_connector_for_encoder_init(encoder);
+ amdgpu_connector = to_amdgpu_connector(connector);
+
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ if (amdgpu_connector->use_digital) {
+ /* HDMI 1.3 supports up to 340 Mhz over single link */
+ if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
+ if (pixel_clock > 340000)
+ return true;
+ else
+ return false;
+ } else {
+ if (pixel_clock > 165000)
+ return true;
+ else
+ return false;
+ }
+ } else
+ return false;
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ dig_connector = amdgpu_connector->con_priv;
+ if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+ (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
+ return false;
+ else {
+ /* HDMI 1.3 supports up to 340 Mhz over single link */
+ if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
+ if (pixel_clock > 340000)
+ return true;
+ else
+ return false;
+ } else {
+ if (pixel_clock > 165000)
+ return true;
+ else
+ return false;
+ }
+ }
+ default:
+ return false;
+ }
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_family.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_family.h
new file mode 100644
index 000000000000..0698764354a2
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_family.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+
+/* this file defines the CHIP_ and family flags used in the pciids,
+ * its is common between kms and non-kms because duplicating it and
+ * changing one place is fail.
+ */
+#ifndef AMDGPU_FAMILY_H
+#define AMDGPU_FAMILY_H
+/*
+ * Supported ASIC types
+ */
+enum amdgpu_asic_type {
+ CHIP_BONAIRE = 0,
+ CHIP_KAVERI,
+ CHIP_KABINI,
+ CHIP_HAWAII,
+ CHIP_MULLINS,
+ CHIP_TOPAZ,
+ CHIP_TONGA,
+ CHIP_CARRIZO,
+ CHIP_LAST,
+};
+
+/*
+ * Chip flags
+ */
+enum amdgpu_chip_flags {
+ AMDGPU_ASIC_MASK = 0x0000ffffUL,
+ AMDGPU_FLAGS_MASK = 0xffff0000UL,
+ AMDGPU_IS_MOBILITY = 0x00010000UL,
+ AMDGPU_IS_APU = 0x00020000UL,
+ AMDGPU_IS_PX = 0x00040000UL,
+ AMDGPU_EXP_HW_SUPPORT = 0x00080000UL,
+};
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
new file mode 100644
index 000000000000..c1645d21f8e2
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright © 2007 David Airlie
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * David Airlie
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "cikd.h"
+
+#include <drm/drm_fb_helper.h>
+
+#include <linux/vga_switcheroo.h>
+
+/* object hierarchy -
+ this contains a helper + a amdgpu fb
+ the helper contains a pointer to amdgpu framebuffer baseclass.
+*/
+struct amdgpu_fbdev {
+ struct drm_fb_helper helper;
+ struct amdgpu_framebuffer rfb;
+ struct list_head fbdev_list;
+ struct amdgpu_device *adev;
+};
+
+static struct fb_ops amdgpufb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = drm_fb_helper_check_var,
+ .fb_set_par = drm_fb_helper_set_par,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_pan_display = drm_fb_helper_pan_display,
+ .fb_blank = drm_fb_helper_blank,
+ .fb_setcmap = drm_fb_helper_setcmap,
+ .fb_debug_enter = drm_fb_helper_debug_enter,
+ .fb_debug_leave = drm_fb_helper_debug_leave,
+};
+
+
+int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tiled)
+{
+ int aligned = width;
+ int pitch_mask = 0;
+
+ switch (bpp / 8) {
+ case 1:
+ pitch_mask = 255;
+ break;
+ case 2:
+ pitch_mask = 127;
+ break;
+ case 3:
+ case 4:
+ pitch_mask = 63;
+ break;
+ }
+
+ aligned += pitch_mask;
+ aligned &= ~pitch_mask;
+ return aligned;
+}
+
+static void amdgpufb_destroy_pinned_object(struct drm_gem_object *gobj)
+{
+ struct amdgpu_bo *rbo = gem_to_amdgpu_bo(gobj);
+ int ret;
+
+ ret = amdgpu_bo_reserve(rbo, false);
+ if (likely(ret == 0)) {
+ amdgpu_bo_kunmap(rbo);
+ amdgpu_bo_unpin(rbo);
+ amdgpu_bo_unreserve(rbo);
+ }
+ drm_gem_object_unreference_unlocked(gobj);
+}
+
+static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object **gobj_p)
+{
+ struct amdgpu_device *adev = rfbdev->adev;
+ struct drm_gem_object *gobj = NULL;
+ struct amdgpu_bo *rbo = NULL;
+ bool fb_tiled = false; /* useful for testing */
+ u32 tiling_flags = 0;
+ int ret;
+ int aligned_size, size;
+ int height = mode_cmd->height;
+ u32 bpp, depth;
+
+ drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp);
+
+ /* need to align pitch with crtc limits */
+ mode_cmd->pitches[0] = amdgpu_align_pitch(adev, mode_cmd->width, bpp,
+ fb_tiled) * ((bpp + 1) / 8);
+
+ height = ALIGN(mode_cmd->height, 8);
+ size = mode_cmd->pitches[0] * height;
+ aligned_size = ALIGN(size, PAGE_SIZE);
+ ret = amdgpu_gem_object_create(adev, aligned_size, 0,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ 0, true,
+ &gobj);
+ if (ret) {
+ printk(KERN_ERR "failed to allocate framebuffer (%d)\n",
+ aligned_size);
+ return -ENOMEM;
+ }
+ rbo = gem_to_amdgpu_bo(gobj);
+
+ if (fb_tiled)
+ tiling_flags = AMDGPU_TILING_SET(ARRAY_MODE, GRPH_ARRAY_2D_TILED_THIN1);
+
+ ret = amdgpu_bo_reserve(rbo, false);
+ if (unlikely(ret != 0))
+ goto out_unref;
+
+ if (tiling_flags) {
+ ret = amdgpu_bo_set_tiling_flags(rbo,
+ tiling_flags);
+ if (ret)
+ dev_err(adev->dev, "FB failed to set tiling flags\n");
+ }
+
+
+ ret = amdgpu_bo_pin_restricted(rbo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, NULL);
+ if (ret) {
+ amdgpu_bo_unreserve(rbo);
+ goto out_unref;
+ }
+ ret = amdgpu_bo_kmap(rbo, NULL);
+ amdgpu_bo_unreserve(rbo);
+ if (ret) {
+ goto out_unref;
+ }
+
+ *gobj_p = gobj;
+ return 0;
+out_unref:
+ amdgpufb_destroy_pinned_object(gobj);
+ *gobj_p = NULL;
+ return ret;
+}
+
+static int amdgpufb_create(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct amdgpu_fbdev *rfbdev = (struct amdgpu_fbdev *)helper;
+ struct amdgpu_device *adev = rfbdev->adev;
+ struct fb_info *info;
+ struct drm_framebuffer *fb = NULL;
+ struct drm_mode_fb_cmd2 mode_cmd;
+ struct drm_gem_object *gobj = NULL;
+ struct amdgpu_bo *rbo = NULL;
+ struct device *device = &adev->pdev->dev;
+ int ret;
+ unsigned long tmp;
+
+ mode_cmd.width = sizes->surface_width;
+ mode_cmd.height = sizes->surface_height;
+
+ if (sizes->surface_bpp == 24)
+ sizes->surface_bpp = 32;
+
+ mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+ sizes->surface_depth);
+
+ ret = amdgpufb_create_pinned_object(rfbdev, &mode_cmd, &gobj);
+ if (ret) {
+ DRM_ERROR("failed to create fbcon object %d\n", ret);
+ return ret;
+ }
+
+ rbo = gem_to_amdgpu_bo(gobj);
+
+ /* okay we have an object now allocate the framebuffer */
+ info = framebuffer_alloc(0, device);
+ if (info == NULL) {
+ ret = -ENOMEM;
+ goto out_unref;
+ }
+
+ info->par = rfbdev;
+
+ ret = amdgpu_framebuffer_init(adev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
+ if (ret) {
+ DRM_ERROR("failed to initialize framebuffer %d\n", ret);
+ goto out_unref;
+ }
+
+ fb = &rfbdev->rfb.base;
+
+ /* setup helper */
+ rfbdev->helper.fb = fb;
+ rfbdev->helper.fbdev = info;
+
+ memset_io(rbo->kptr, 0x0, amdgpu_bo_size(rbo));
+
+ strcpy(info->fix.id, "amdgpudrmfb");
+
+ drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+
+ info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
+ info->fbops = &amdgpufb_ops;
+
+ tmp = amdgpu_bo_gpu_offset(rbo) - adev->mc.vram_start;
+ info->fix.smem_start = adev->mc.aper_base + tmp;
+ info->fix.smem_len = amdgpu_bo_size(rbo);
+ info->screen_base = rbo->kptr;
+ info->screen_size = amdgpu_bo_size(rbo);
+
+ drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
+
+ /* setup aperture base/size for vesafb takeover */
+ info->apertures = alloc_apertures(1);
+ if (!info->apertures) {
+ ret = -ENOMEM;
+ goto out_unref;
+ }
+ info->apertures->ranges[0].base = adev->ddev->mode_config.fb_base;
+ info->apertures->ranges[0].size = adev->mc.aper_size;
+
+ /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
+
+ if (info->screen_base == NULL) {
+ ret = -ENOSPC;
+ goto out_unref;
+ }
+
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret) {
+ ret = -ENOMEM;
+ goto out_unref;
+ }
+
+ DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
+ DRM_INFO("vram apper at 0x%lX\n", (unsigned long)adev->mc.aper_base);
+ DRM_INFO("size %lu\n", (unsigned long)amdgpu_bo_size(rbo));
+ DRM_INFO("fb depth is %d\n", fb->depth);
+ DRM_INFO(" pitch is %d\n", fb->pitches[0]);
+
+ vga_switcheroo_client_fb_set(adev->ddev->pdev, info);
+ return 0;
+
+out_unref:
+ if (rbo) {
+
+ }
+ if (fb && ret) {
+ drm_gem_object_unreference(gobj);
+ drm_framebuffer_unregister_private(fb);
+ drm_framebuffer_cleanup(fb);
+ kfree(fb);
+ }
+ return ret;
+}
+
+void amdgpu_fb_output_poll_changed(struct amdgpu_device *adev)
+{
+ if (adev->mode_info.rfbdev)
+ drm_fb_helper_hotplug_event(&adev->mode_info.rfbdev->helper);
+}
+
+static int amdgpu_fbdev_destroy(struct drm_device *dev, struct amdgpu_fbdev *rfbdev)
+{
+ struct fb_info *info;
+ struct amdgpu_framebuffer *rfb = &rfbdev->rfb;
+
+ if (rfbdev->helper.fbdev) {
+ info = rfbdev->helper.fbdev;
+
+ unregister_framebuffer(info);
+ if (info->cmap.len)
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+
+ if (rfb->obj) {
+ amdgpufb_destroy_pinned_object(rfb->obj);
+ rfb->obj = NULL;
+ }
+ drm_fb_helper_fini(&rfbdev->helper);
+ drm_framebuffer_unregister_private(&rfb->base);
+ drm_framebuffer_cleanup(&rfb->base);
+
+ return 0;
+}
+
+/** Sets the color ramps on behalf of fbcon */
+static void amdgpu_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+ u16 blue, int regno)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+ amdgpu_crtc->lut_r[regno] = red >> 6;
+ amdgpu_crtc->lut_g[regno] = green >> 6;
+ amdgpu_crtc->lut_b[regno] = blue >> 6;
+}
+
+/** Gets the color ramps on behalf of fbcon */
+static void amdgpu_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+ *red = amdgpu_crtc->lut_r[regno] << 6;
+ *green = amdgpu_crtc->lut_g[regno] << 6;
+ *blue = amdgpu_crtc->lut_b[regno] << 6;
+}
+
+static const struct drm_fb_helper_funcs amdgpu_fb_helper_funcs = {
+ .gamma_set = amdgpu_crtc_fb_gamma_set,
+ .gamma_get = amdgpu_crtc_fb_gamma_get,
+ .fb_probe = amdgpufb_create,
+};
+
+int amdgpu_fbdev_init(struct amdgpu_device *adev)
+{
+ struct amdgpu_fbdev *rfbdev;
+ int bpp_sel = 32;
+ int ret;
+
+ /* don't init fbdev on hw without DCE */
+ if (!adev->mode_info.mode_config_initialized)
+ return 0;
+
+ /* select 8 bpp console on low vram cards */
+ if (adev->mc.real_vram_size <= (32*1024*1024))
+ bpp_sel = 8;
+
+ rfbdev = kzalloc(sizeof(struct amdgpu_fbdev), GFP_KERNEL);
+ if (!rfbdev)
+ return -ENOMEM;
+
+ rfbdev->adev = adev;
+ adev->mode_info.rfbdev = rfbdev;
+
+ drm_fb_helper_prepare(adev->ddev, &rfbdev->helper,
+ &amdgpu_fb_helper_funcs);
+
+ ret = drm_fb_helper_init(adev->ddev, &rfbdev->helper,
+ adev->mode_info.num_crtc,
+ AMDGPUFB_CONN_LIMIT);
+ if (ret) {
+ kfree(rfbdev);
+ return ret;
+ }
+
+ drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
+
+ /* disable all the possible outputs/crtcs before entering KMS mode */
+ drm_helper_disable_unused_functions(adev->ddev);
+
+ drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
+ return 0;
+}
+
+void amdgpu_fbdev_fini(struct amdgpu_device *adev)
+{
+ if (!adev->mode_info.rfbdev)
+ return;
+
+ amdgpu_fbdev_destroy(adev->ddev, adev->mode_info.rfbdev);
+ kfree(adev->mode_info.rfbdev);
+ adev->mode_info.rfbdev = NULL;
+}
+
+void amdgpu_fbdev_set_suspend(struct amdgpu_device *adev, int state)
+{
+ if (adev->mode_info.rfbdev)
+ fb_set_suspend(adev->mode_info.rfbdev->helper.fbdev, state);
+}
+
+int amdgpu_fbdev_total_size(struct amdgpu_device *adev)
+{
+ struct amdgpu_bo *robj;
+ int size = 0;
+
+ if (!adev->mode_info.rfbdev)
+ return 0;
+
+ robj = gem_to_amdgpu_bo(adev->mode_info.rfbdev->rfb.obj);
+ size += amdgpu_bo_size(robj);
+ return size;
+}
+
+bool amdgpu_fbdev_robj_is_fb(struct amdgpu_device *adev, struct amdgpu_bo *robj)
+{
+ if (!adev->mode_info.rfbdev)
+ return false;
+ if (robj == gem_to_amdgpu_bo(adev->mode_info.rfbdev->rfb.obj))
+ return true;
+ return false;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
new file mode 100644
index 000000000000..5c9918d01bf9
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
@@ -0,0 +1,1133 @@
+/*
+ * Copyright 2009 Jerome Glisse.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ * Jerome Glisse <glisse@freedesktop.org>
+ * Dave Airlie
+ */
+#include <linux/seq_file.h>
+#include <linux/atomic.h>
+#include <linux/wait.h>
+#include <linux/kref.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <drm/drmP.h>
+#include "amdgpu.h"
+#include "amdgpu_trace.h"
+
+/*
+ * Fences
+ * Fences mark an event in the GPUs pipeline and are used
+ * for GPU/CPU synchronization. When the fence is written,
+ * it is expected that all buffers associated with that fence
+ * are no longer in use by the associated ring on the GPU and
+ * that the the relevant GPU caches have been flushed.
+ */
+
+/**
+ * amdgpu_fence_write - write a fence value
+ *
+ * @ring: ring the fence is associated with
+ * @seq: sequence number to write
+ *
+ * Writes a fence value to memory (all asics).
+ */
+static void amdgpu_fence_write(struct amdgpu_ring *ring, u32 seq)
+{
+ struct amdgpu_fence_driver *drv = &ring->fence_drv;
+
+ if (drv->cpu_addr)
+ *drv->cpu_addr = cpu_to_le32(seq);
+}
+
+/**
+ * amdgpu_fence_read - read a fence value
+ *
+ * @ring: ring the fence is associated with
+ *
+ * Reads a fence value from memory (all asics).
+ * Returns the value of the fence read from memory.
+ */
+static u32 amdgpu_fence_read(struct amdgpu_ring *ring)
+{
+ struct amdgpu_fence_driver *drv = &ring->fence_drv;
+ u32 seq = 0;
+
+ if (drv->cpu_addr)
+ seq = le32_to_cpu(*drv->cpu_addr);
+ else
+ seq = lower_32_bits(atomic64_read(&drv->last_seq));
+
+ return seq;
+}
+
+/**
+ * amdgpu_fence_schedule_check - schedule lockup check
+ *
+ * @ring: pointer to struct amdgpu_ring
+ *
+ * Queues a delayed work item to check for lockups.
+ */
+static void amdgpu_fence_schedule_check(struct amdgpu_ring *ring)
+{
+ /*
+ * Do not reset the timer here with mod_delayed_work,
+ * this can livelock in an interaction with TTM delayed destroy.
+ */
+ queue_delayed_work(system_power_efficient_wq,
+ &ring->fence_drv.lockup_work,
+ AMDGPU_FENCE_JIFFIES_TIMEOUT);
+}
+
+/**
+ * amdgpu_fence_emit - emit a fence on the requested ring
+ *
+ * @ring: ring the fence is associated with
+ * @owner: creator of the fence
+ * @fence: amdgpu fence object
+ *
+ * Emits a fence command on the requested ring (all asics).
+ * Returns 0 on success, -ENOMEM on failure.
+ */
+int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner,
+ struct amdgpu_fence **fence)
+{
+ struct amdgpu_device *adev = ring->adev;
+
+ /* we are protected by the ring emission mutex */
+ *fence = kmalloc(sizeof(struct amdgpu_fence), GFP_KERNEL);
+ if ((*fence) == NULL) {
+ return -ENOMEM;
+ }
+ (*fence)->seq = ++ring->fence_drv.sync_seq[ring->idx];
+ (*fence)->ring = ring;
+ (*fence)->owner = owner;
+ fence_init(&(*fence)->base, &amdgpu_fence_ops,
+ &adev->fence_queue.lock, adev->fence_context + ring->idx,
+ (*fence)->seq);
+ amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
+ (*fence)->seq,
+ AMDGPU_FENCE_FLAG_INT);
+ trace_amdgpu_fence_emit(ring->adev->ddev, ring->idx, (*fence)->seq);
+ return 0;
+}
+
+/**
+ * amdgpu_fence_check_signaled - callback from fence_queue
+ *
+ * this function is called with fence_queue lock held, which is also used
+ * for the fence locking itself, so unlocked variants are used for
+ * fence_signal, and remove_wait_queue.
+ */
+static int amdgpu_fence_check_signaled(wait_queue_t *wait, unsigned mode, int flags, void *key)
+{
+ struct amdgpu_fence *fence;
+ struct amdgpu_device *adev;
+ u64 seq;
+ int ret;
+
+ fence = container_of(wait, struct amdgpu_fence, fence_wake);
+ adev = fence->ring->adev;
+
+ /*
+ * We cannot use amdgpu_fence_process here because we're already
+ * in the waitqueue, in a call from wake_up_all.
+ */
+ seq = atomic64_read(&fence->ring->fence_drv.last_seq);
+ if (seq >= fence->seq) {
+ ret = fence_signal_locked(&fence->base);
+ if (!ret)
+ FENCE_TRACE(&fence->base, "signaled from irq context\n");
+ else
+ FENCE_TRACE(&fence->base, "was already signaled\n");
+
+ amdgpu_irq_put(adev, fence->ring->fence_drv.irq_src,
+ fence->ring->fence_drv.irq_type);
+ __remove_wait_queue(&adev->fence_queue, &fence->fence_wake);
+ fence_put(&fence->base);
+ } else
+ FENCE_TRACE(&fence->base, "pending\n");
+ return 0;
+}
+
+/**
+ * amdgpu_fence_activity - check for fence activity
+ *
+ * @ring: pointer to struct amdgpu_ring
+ *
+ * Checks the current fence value and calculates the last
+ * signalled fence value. Returns true if activity occured
+ * on the ring, and the fence_queue should be waken up.
+ */
+static bool amdgpu_fence_activity(struct amdgpu_ring *ring)
+{
+ uint64_t seq, last_seq, last_emitted;
+ unsigned count_loop = 0;
+ bool wake = false;
+
+ /* Note there is a scenario here for an infinite loop but it's
+ * very unlikely to happen. For it to happen, the current polling
+ * process need to be interrupted by another process and another
+ * process needs to update the last_seq btw the atomic read and
+ * xchg of the current process.
+ *
+ * More over for this to go in infinite loop there need to be
+ * continuously new fence signaled ie amdgpu_fence_read needs
+ * to return a different value each time for both the currently
+ * polling process and the other process that xchg the last_seq
+ * btw atomic read and xchg of the current process. And the
+ * value the other process set as last seq must be higher than
+ * the seq value we just read. Which means that current process
+ * need to be interrupted after amdgpu_fence_read and before
+ * atomic xchg.
+ *
+ * To be even more safe we count the number of time we loop and
+ * we bail after 10 loop just accepting the fact that we might
+ * have temporarly set the last_seq not to the true real last
+ * seq but to an older one.
+ */
+ last_seq = atomic64_read(&ring->fence_drv.last_seq);
+ do {
+ last_emitted = ring->fence_drv.sync_seq[ring->idx];
+ seq = amdgpu_fence_read(ring);
+ seq |= last_seq & 0xffffffff00000000LL;
+ if (seq < last_seq) {
+ seq &= 0xffffffff;
+ seq |= last_emitted & 0xffffffff00000000LL;
+ }
+
+ if (seq <= last_seq || seq > last_emitted) {
+ break;
+ }
+ /* If we loop over we don't want to return without
+ * checking if a fence is signaled as it means that the
+ * seq we just read is different from the previous on.
+ */
+ wake = true;
+ last_seq = seq;
+ if ((count_loop++) > 10) {
+ /* We looped over too many time leave with the
+ * fact that we might have set an older fence
+ * seq then the current real last seq as signaled
+ * by the hw.
+ */
+ break;
+ }
+ } while (atomic64_xchg(&ring->fence_drv.last_seq, seq) > seq);
+
+ if (seq < last_emitted)
+ amdgpu_fence_schedule_check(ring);
+
+ return wake;
+}
+
+/**
+ * amdgpu_fence_check_lockup - check for hardware lockup
+ *
+ * @work: delayed work item
+ *
+ * Checks for fence activity and if there is none probe
+ * the hardware if a lockup occured.
+ */
+static void amdgpu_fence_check_lockup(struct work_struct *work)
+{
+ struct amdgpu_fence_driver *fence_drv;
+ struct amdgpu_ring *ring;
+
+ fence_drv = container_of(work, struct amdgpu_fence_driver,
+ lockup_work.work);
+ ring = fence_drv->ring;
+
+ if (!down_read_trylock(&ring->adev->exclusive_lock)) {
+ /* just reschedule the check if a reset is going on */
+ amdgpu_fence_schedule_check(ring);
+ return;
+ }
+
+ if (fence_drv->delayed_irq && ring->adev->ddev->irq_enabled) {
+ fence_drv->delayed_irq = false;
+ amdgpu_irq_update(ring->adev, fence_drv->irq_src,
+ fence_drv->irq_type);
+ }
+
+ if (amdgpu_fence_activity(ring))
+ wake_up_all(&ring->adev->fence_queue);
+ else if (amdgpu_ring_is_lockup(ring)) {
+ /* good news we believe it's a lockup */
+ dev_warn(ring->adev->dev, "GPU lockup (current fence id "
+ "0x%016llx last fence id 0x%016llx on ring %d)\n",
+ (uint64_t)atomic64_read(&fence_drv->last_seq),
+ fence_drv->sync_seq[ring->idx], ring->idx);
+
+ /* remember that we need an reset */
+ ring->adev->needs_reset = true;
+ wake_up_all(&ring->adev->fence_queue);
+ }
+ up_read(&ring->adev->exclusive_lock);
+}
+
+/**
+ * amdgpu_fence_process - process a fence
+ *
+ * @adev: amdgpu_device pointer
+ * @ring: ring index the fence is associated with
+ *
+ * Checks the current fence value and wakes the fence queue
+ * if the sequence number has increased (all asics).
+ */
+void amdgpu_fence_process(struct amdgpu_ring *ring)
+{
+ uint64_t seq, last_seq, last_emitted;
+ unsigned count_loop = 0;
+ bool wake = false;
+
+ /* Note there is a scenario here for an infinite loop but it's
+ * very unlikely to happen. For it to happen, the current polling
+ * process need to be interrupted by another process and another
+ * process needs to update the last_seq btw the atomic read and
+ * xchg of the current process.
+ *
+ * More over for this to go in infinite loop there need to be
+ * continuously new fence signaled ie amdgpu_fence_read needs
+ * to return a different value each time for both the currently
+ * polling process and the other process that xchg the last_seq
+ * btw atomic read and xchg of the current process. And the
+ * value the other process set as last seq must be higher than
+ * the seq value we just read. Which means that current process
+ * need to be interrupted after amdgpu_fence_read and before
+ * atomic xchg.
+ *
+ * To be even more safe we count the number of time we loop and
+ * we bail after 10 loop just accepting the fact that we might
+ * have temporarly set the last_seq not to the true real last
+ * seq but to an older one.
+ */
+ last_seq = atomic64_read(&ring->fence_drv.last_seq);
+ do {
+ last_emitted = ring->fence_drv.sync_seq[ring->idx];
+ seq = amdgpu_fence_read(ring);
+ seq |= last_seq & 0xffffffff00000000LL;
+ if (seq < last_seq) {
+ seq &= 0xffffffff;
+ seq |= last_emitted & 0xffffffff00000000LL;
+ }
+
+ if (seq <= last_seq || seq > last_emitted) {
+ break;
+ }
+ /* If we loop over we don't want to return without
+ * checking if a fence is signaled as it means that the
+ * seq we just read is different from the previous on.
+ */
+ wake = true;
+ last_seq = seq;
+ if ((count_loop++) > 10) {
+ /* We looped over too many time leave with the
+ * fact that we might have set an older fence
+ * seq then the current real last seq as signaled
+ * by the hw.
+ */
+ break;
+ }
+ } while (atomic64_xchg(&ring->fence_drv.last_seq, seq) > seq);
+
+ if (wake)
+ wake_up_all(&ring->adev->fence_queue);
+}
+
+/**
+ * amdgpu_fence_seq_signaled - check if a fence sequence number has signaled
+ *
+ * @ring: ring the fence is associated with
+ * @seq: sequence number
+ *
+ * Check if the last signaled fence sequnce number is >= the requested
+ * sequence number (all asics).
+ * Returns true if the fence has signaled (current fence value
+ * is >= requested value) or false if it has not (current fence
+ * value is < the requested value. Helper function for
+ * amdgpu_fence_signaled().
+ */
+static bool amdgpu_fence_seq_signaled(struct amdgpu_ring *ring, u64 seq)
+{
+ if (atomic64_read(&ring->fence_drv.last_seq) >= seq)
+ return true;
+
+ /* poll new last sequence at least once */
+ amdgpu_fence_process(ring);
+ if (atomic64_read(&ring->fence_drv.last_seq) >= seq)
+ return true;
+
+ return false;
+}
+
+static bool amdgpu_fence_is_signaled(struct fence *f)
+{
+ struct amdgpu_fence *fence = to_amdgpu_fence(f);
+ struct amdgpu_ring *ring = fence->ring;
+ struct amdgpu_device *adev = ring->adev;
+
+ if (atomic64_read(&ring->fence_drv.last_seq) >= fence->seq)
+ return true;
+
+ if (down_read_trylock(&adev->exclusive_lock)) {
+ amdgpu_fence_process(ring);
+ up_read(&adev->exclusive_lock);
+
+ if (atomic64_read(&ring->fence_drv.last_seq) >= fence->seq)
+ return true;
+ }
+ return false;
+}
+
+/**
+ * amdgpu_fence_enable_signaling - enable signalling on fence
+ * @fence: fence
+ *
+ * This function is called with fence_queue lock held, and adds a callback
+ * to fence_queue that checks if this fence is signaled, and if so it
+ * signals the fence and removes itself.
+ */
+static bool amdgpu_fence_enable_signaling(struct fence *f)
+{
+ struct amdgpu_fence *fence = to_amdgpu_fence(f);
+ struct amdgpu_ring *ring = fence->ring;
+ struct amdgpu_device *adev = ring->adev;
+
+ if (atomic64_read(&ring->fence_drv.last_seq) >= fence->seq)
+ return false;
+
+ if (down_read_trylock(&adev->exclusive_lock)) {
+ amdgpu_irq_get(adev, ring->fence_drv.irq_src,
+ ring->fence_drv.irq_type);
+ if (amdgpu_fence_activity(ring))
+ wake_up_all_locked(&adev->fence_queue);
+
+ /* did fence get signaled after we enabled the sw irq? */
+ if (atomic64_read(&ring->fence_drv.last_seq) >= fence->seq) {
+ amdgpu_irq_put(adev, ring->fence_drv.irq_src,
+ ring->fence_drv.irq_type);
+ up_read(&adev->exclusive_lock);
+ return false;
+ }
+
+ up_read(&adev->exclusive_lock);
+ } else {
+ /* we're probably in a lockup, lets not fiddle too much */
+ if (amdgpu_irq_get_delayed(adev, ring->fence_drv.irq_src,
+ ring->fence_drv.irq_type))
+ ring->fence_drv.delayed_irq = true;
+ amdgpu_fence_schedule_check(ring);
+ }
+
+ fence->fence_wake.flags = 0;
+ fence->fence_wake.private = NULL;
+ fence->fence_wake.func = amdgpu_fence_check_signaled;
+ __add_wait_queue(&adev->fence_queue, &fence->fence_wake);
+ fence_get(f);
+ FENCE_TRACE(&fence->base, "armed on ring %i!\n", ring->idx);
+ return true;
+}
+
+/**
+ * amdgpu_fence_signaled - check if a fence has signaled
+ *
+ * @fence: amdgpu fence object
+ *
+ * Check if the requested fence has signaled (all asics).
+ * Returns true if the fence has signaled or false if it has not.
+ */
+bool amdgpu_fence_signaled(struct amdgpu_fence *fence)
+{
+ if (!fence)
+ return true;
+
+ if (amdgpu_fence_seq_signaled(fence->ring, fence->seq)) {
+ if (!fence_signal(&fence->base))
+ FENCE_TRACE(&fence->base, "signaled from amdgpu_fence_signaled\n");
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * amdgpu_fence_any_seq_signaled - check if any sequence number is signaled
+ *
+ * @adev: amdgpu device pointer
+ * @seq: sequence numbers
+ *
+ * Check if the last signaled fence sequnce number is >= the requested
+ * sequence number (all asics).
+ * Returns true if any has signaled (current value is >= requested value)
+ * or false if it has not. Helper function for amdgpu_fence_wait_seq.
+ */
+static bool amdgpu_fence_any_seq_signaled(struct amdgpu_device *adev, u64 *seq)
+{
+ unsigned i;
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ if (!adev->rings[i] || !seq[i])
+ continue;
+
+ if (amdgpu_fence_seq_signaled(adev->rings[i], seq[i]))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * amdgpu_fence_wait_seq_timeout - wait for a specific sequence numbers
+ *
+ * @adev: amdgpu device pointer
+ * @target_seq: sequence number(s) we want to wait for
+ * @intr: use interruptable sleep
+ * @timeout: maximum time to wait, or MAX_SCHEDULE_TIMEOUT for infinite wait
+ *
+ * Wait for the requested sequence number(s) to be written by any ring
+ * (all asics). Sequnce number array is indexed by ring id.
+ * @intr selects whether to use interruptable (true) or non-interruptable
+ * (false) sleep when waiting for the sequence number. Helper function
+ * for amdgpu_fence_wait_*().
+ * Returns remaining time if the sequence number has passed, 0 when
+ * the wait timeout, or an error for all other cases.
+ * -EDEADLK is returned when a GPU lockup has been detected.
+ */
+long amdgpu_fence_wait_seq_timeout(struct amdgpu_device *adev, u64 *target_seq,
+ bool intr, long timeout)
+{
+ uint64_t last_seq[AMDGPU_MAX_RINGS];
+ bool signaled;
+ int i, r;
+
+ if (timeout == 0) {
+ return amdgpu_fence_any_seq_signaled(adev, target_seq);
+ }
+
+ while (!amdgpu_fence_any_seq_signaled(adev, target_seq)) {
+
+ /* Save current sequence values, used to check for GPU lockups */
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_ring *ring = adev->rings[i];
+
+ if (!ring || !target_seq[i])
+ continue;
+
+ last_seq[i] = atomic64_read(&ring->fence_drv.last_seq);
+ trace_amdgpu_fence_wait_begin(adev->ddev, i, target_seq[i]);
+ amdgpu_irq_get(adev, ring->fence_drv.irq_src,
+ ring->fence_drv.irq_type);
+ }
+
+ if (intr) {
+ r = wait_event_interruptible_timeout(adev->fence_queue, (
+ (signaled = amdgpu_fence_any_seq_signaled(adev, target_seq))
+ || adev->needs_reset), AMDGPU_FENCE_JIFFIES_TIMEOUT);
+ } else {
+ r = wait_event_timeout(adev->fence_queue, (
+ (signaled = amdgpu_fence_any_seq_signaled(adev, target_seq))
+ || adev->needs_reset), AMDGPU_FENCE_JIFFIES_TIMEOUT);
+ }
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_ring *ring = adev->rings[i];
+
+ if (!ring || !target_seq[i])
+ continue;
+
+ amdgpu_irq_put(adev, ring->fence_drv.irq_src,
+ ring->fence_drv.irq_type);
+ trace_amdgpu_fence_wait_end(adev->ddev, i, target_seq[i]);
+ }
+
+ if (unlikely(r < 0))
+ return r;
+
+ if (unlikely(!signaled)) {
+
+ if (adev->needs_reset)
+ return -EDEADLK;
+
+ /* we were interrupted for some reason and fence
+ * isn't signaled yet, resume waiting */
+ if (r)
+ continue;
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_ring *ring = adev->rings[i];
+
+ if (!ring || !target_seq[i])
+ continue;
+
+ if (last_seq[i] != atomic64_read(&ring->fence_drv.last_seq))
+ break;
+ }
+
+ if (i != AMDGPU_MAX_RINGS)
+ continue;
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ if (!adev->rings[i] || !target_seq[i])
+ continue;
+
+ if (amdgpu_ring_is_lockup(adev->rings[i]))
+ break;
+ }
+
+ if (i < AMDGPU_MAX_RINGS) {
+ /* good news we believe it's a lockup */
+ dev_warn(adev->dev, "GPU lockup (waiting for "
+ "0x%016llx last fence id 0x%016llx on"
+ " ring %d)\n",
+ target_seq[i], last_seq[i], i);
+
+ /* remember that we need an reset */
+ adev->needs_reset = true;
+ wake_up_all(&adev->fence_queue);
+ return -EDEADLK;
+ }
+
+ if (timeout < MAX_SCHEDULE_TIMEOUT) {
+ timeout -= AMDGPU_FENCE_JIFFIES_TIMEOUT;
+ if (timeout <= 0) {
+ return 0;
+ }
+ }
+ }
+ }
+ return timeout;
+}
+
+/**
+ * amdgpu_fence_wait - wait for a fence to signal
+ *
+ * @fence: amdgpu fence object
+ * @intr: use interruptable sleep
+ *
+ * Wait for the requested fence to signal (all asics).
+ * @intr selects whether to use interruptable (true) or non-interruptable
+ * (false) sleep when waiting for the fence.
+ * Returns 0 if the fence has passed, error for all other cases.
+ */
+int amdgpu_fence_wait(struct amdgpu_fence *fence, bool intr)
+{
+ uint64_t seq[AMDGPU_MAX_RINGS] = {};
+ long r;
+
+ seq[fence->ring->idx] = fence->seq;
+ r = amdgpu_fence_wait_seq_timeout(fence->ring->adev, seq, intr, MAX_SCHEDULE_TIMEOUT);
+ if (r < 0) {
+ return r;
+ }
+
+ r = fence_signal(&fence->base);
+ if (!r)
+ FENCE_TRACE(&fence->base, "signaled from fence_wait\n");
+ return 0;
+}
+
+/**
+ * amdgpu_fence_wait_any - wait for a fence to signal on any ring
+ *
+ * @adev: amdgpu device pointer
+ * @fences: amdgpu fence object(s)
+ * @intr: use interruptable sleep
+ *
+ * Wait for any requested fence to signal (all asics). Fence
+ * array is indexed by ring id. @intr selects whether to use
+ * interruptable (true) or non-interruptable (false) sleep when
+ * waiting for the fences. Used by the suballocator.
+ * Returns 0 if any fence has passed, error for all other cases.
+ */
+int amdgpu_fence_wait_any(struct amdgpu_device *adev,
+ struct amdgpu_fence **fences,
+ bool intr)
+{
+ uint64_t seq[AMDGPU_MAX_RINGS];
+ unsigned i, num_rings = 0;
+ long r;
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ seq[i] = 0;
+
+ if (!fences[i]) {
+ continue;
+ }
+
+ seq[i] = fences[i]->seq;
+ ++num_rings;
+ }
+
+ /* nothing to wait for ? */
+ if (num_rings == 0)
+ return -ENOENT;
+
+ r = amdgpu_fence_wait_seq_timeout(adev, seq, intr, MAX_SCHEDULE_TIMEOUT);
+ if (r < 0) {
+ return r;
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_fence_wait_next - wait for the next fence to signal
+ *
+ * @adev: amdgpu device pointer
+ * @ring: ring index the fence is associated with
+ *
+ * Wait for the next fence on the requested ring to signal (all asics).
+ * Returns 0 if the next fence has passed, error for all other cases.
+ * Caller must hold ring lock.
+ */
+int amdgpu_fence_wait_next(struct amdgpu_ring *ring)
+{
+ uint64_t seq[AMDGPU_MAX_RINGS] = {};
+ long r;
+
+ seq[ring->idx] = atomic64_read(&ring->fence_drv.last_seq) + 1ULL;
+ if (seq[ring->idx] >= ring->fence_drv.sync_seq[ring->idx]) {
+ /* nothing to wait for, last_seq is
+ already the last emited fence */
+ return -ENOENT;
+ }
+ r = amdgpu_fence_wait_seq_timeout(ring->adev, seq, false, MAX_SCHEDULE_TIMEOUT);
+ if (r < 0)
+ return r;
+ return 0;
+}
+
+/**
+ * amdgpu_fence_wait_empty - wait for all fences to signal
+ *
+ * @adev: amdgpu device pointer
+ * @ring: ring index the fence is associated with
+ *
+ * Wait for all fences on the requested ring to signal (all asics).
+ * Returns 0 if the fences have passed, error for all other cases.
+ * Caller must hold ring lock.
+ */
+int amdgpu_fence_wait_empty(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ uint64_t seq[AMDGPU_MAX_RINGS] = {};
+ long r;
+
+ seq[ring->idx] = ring->fence_drv.sync_seq[ring->idx];
+ if (!seq[ring->idx])
+ return 0;
+
+ r = amdgpu_fence_wait_seq_timeout(adev, seq, false, MAX_SCHEDULE_TIMEOUT);
+ if (r < 0) {
+ if (r == -EDEADLK)
+ return -EDEADLK;
+
+ dev_err(adev->dev, "error waiting for ring[%d] to become idle (%ld)\n",
+ ring->idx, r);
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_fence_ref - take a ref on a fence
+ *
+ * @fence: amdgpu fence object
+ *
+ * Take a reference on a fence (all asics).
+ * Returns the fence.
+ */
+struct amdgpu_fence *amdgpu_fence_ref(struct amdgpu_fence *fence)
+{
+ fence_get(&fence->base);
+ return fence;
+}
+
+/**
+ * amdgpu_fence_unref - remove a ref on a fence
+ *
+ * @fence: amdgpu fence object
+ *
+ * Remove a reference on a fence (all asics).
+ */
+void amdgpu_fence_unref(struct amdgpu_fence **fence)
+{
+ struct amdgpu_fence *tmp = *fence;
+
+ *fence = NULL;
+ if (tmp)
+ fence_put(&tmp->base);
+}
+
+/**
+ * amdgpu_fence_count_emitted - get the count of emitted fences
+ *
+ * @ring: ring the fence is associated with
+ *
+ * Get the number of fences emitted on the requested ring (all asics).
+ * Returns the number of emitted fences on the ring. Used by the
+ * dynpm code to ring track activity.
+ */
+unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring)
+{
+ uint64_t emitted;
+
+ /* We are not protected by ring lock when reading the last sequence
+ * but it's ok to report slightly wrong fence count here.
+ */
+ amdgpu_fence_process(ring);
+ emitted = ring->fence_drv.sync_seq[ring->idx]
+ - atomic64_read(&ring->fence_drv.last_seq);
+ /* to avoid 32bits warp around */
+ if (emitted > 0x10000000)
+ emitted = 0x10000000;
+
+ return (unsigned)emitted;
+}
+
+/**
+ * amdgpu_fence_need_sync - do we need a semaphore
+ *
+ * @fence: amdgpu fence object
+ * @dst_ring: which ring to check against
+ *
+ * Check if the fence needs to be synced against another ring
+ * (all asics). If so, we need to emit a semaphore.
+ * Returns true if we need to sync with another ring, false if
+ * not.
+ */
+bool amdgpu_fence_need_sync(struct amdgpu_fence *fence,
+ struct amdgpu_ring *dst_ring)
+{
+ struct amdgpu_fence_driver *fdrv;
+
+ if (!fence)
+ return false;
+
+ if (fence->ring == dst_ring)
+ return false;
+
+ /* we are protected by the ring mutex */
+ fdrv = &dst_ring->fence_drv;
+ if (fence->seq <= fdrv->sync_seq[fence->ring->idx])
+ return false;
+
+ return true;
+}
+
+/**
+ * amdgpu_fence_note_sync - record the sync point
+ *
+ * @fence: amdgpu fence object
+ * @dst_ring: which ring to check against
+ *
+ * Note the sequence number at which point the fence will
+ * be synced with the requested ring (all asics).
+ */
+void amdgpu_fence_note_sync(struct amdgpu_fence *fence,
+ struct amdgpu_ring *dst_ring)
+{
+ struct amdgpu_fence_driver *dst, *src;
+ unsigned i;
+
+ if (!fence)
+ return;
+
+ if (fence->ring == dst_ring)
+ return;
+
+ /* we are protected by the ring mutex */
+ src = &fence->ring->fence_drv;
+ dst = &dst_ring->fence_drv;
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ if (i == dst_ring->idx)
+ continue;
+
+ dst->sync_seq[i] = max(dst->sync_seq[i], src->sync_seq[i]);
+ }
+}
+
+/**
+ * amdgpu_fence_driver_start_ring - make the fence driver
+ * ready for use on the requested ring.
+ *
+ * @ring: ring to start the fence driver on
+ * @irq_src: interrupt source to use for this ring
+ * @irq_type: interrupt type to use for this ring
+ *
+ * Make the fence driver ready for processing (all asics).
+ * Not all asics have all rings, so each asic will only
+ * start the fence driver on the rings it has.
+ * Returns 0 for success, errors for failure.
+ */
+int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
+ struct amdgpu_irq_src *irq_src,
+ unsigned irq_type)
+{
+ struct amdgpu_device *adev = ring->adev;
+ uint64_t index;
+
+ if (ring != &adev->uvd.ring) {
+ ring->fence_drv.cpu_addr = &adev->wb.wb[ring->fence_offs];
+ ring->fence_drv.gpu_addr = adev->wb.gpu_addr + (ring->fence_offs * 4);
+ } else {
+ /* put fence directly behind firmware */
+ index = ALIGN(adev->uvd.fw->size, 8);
+ ring->fence_drv.cpu_addr = adev->uvd.cpu_addr + index;
+ ring->fence_drv.gpu_addr = adev->uvd.gpu_addr + index;
+ }
+ amdgpu_fence_write(ring, atomic64_read(&ring->fence_drv.last_seq));
+ ring->fence_drv.initialized = true;
+ ring->fence_drv.irq_src = irq_src;
+ ring->fence_drv.irq_type = irq_type;
+ dev_info(adev->dev, "fence driver on ring %d use gpu addr 0x%016llx, "
+ "cpu addr 0x%p\n", ring->idx,
+ ring->fence_drv.gpu_addr, ring->fence_drv.cpu_addr);
+ return 0;
+}
+
+/**
+ * amdgpu_fence_driver_init_ring - init the fence driver
+ * for the requested ring.
+ *
+ * @ring: ring to init the fence driver on
+ *
+ * Init the fence driver for the requested ring (all asics).
+ * Helper function for amdgpu_fence_driver_init().
+ */
+void amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring)
+{
+ int i;
+
+ ring->fence_drv.cpu_addr = NULL;
+ ring->fence_drv.gpu_addr = 0;
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
+ ring->fence_drv.sync_seq[i] = 0;
+
+ atomic64_set(&ring->fence_drv.last_seq, 0);
+ ring->fence_drv.initialized = false;
+
+ INIT_DELAYED_WORK(&ring->fence_drv.lockup_work,
+ amdgpu_fence_check_lockup);
+ ring->fence_drv.ring = ring;
+}
+
+/**
+ * amdgpu_fence_driver_init - init the fence driver
+ * for all possible rings.
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Init the fence driver for all possible rings (all asics).
+ * Not all asics have all rings, so each asic will only
+ * start the fence driver on the rings it has using
+ * amdgpu_fence_driver_start_ring().
+ * Returns 0 for success.
+ */
+int amdgpu_fence_driver_init(struct amdgpu_device *adev)
+{
+ init_waitqueue_head(&adev->fence_queue);
+ if (amdgpu_debugfs_fence_init(adev))
+ dev_err(adev->dev, "fence debugfs file creation failed\n");
+
+ return 0;
+}
+
+/**
+ * amdgpu_fence_driver_fini - tear down the fence driver
+ * for all possible rings.
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Tear down the fence driver for all possible rings (all asics).
+ */
+void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
+{
+ int i, r;
+
+ mutex_lock(&adev->ring_lock);
+ for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
+ struct amdgpu_ring *ring = adev->rings[i];
+ if (!ring || !ring->fence_drv.initialized)
+ continue;
+ r = amdgpu_fence_wait_empty(ring);
+ if (r) {
+ /* no need to trigger GPU reset as we are unloading */
+ amdgpu_fence_driver_force_completion(adev);
+ }
+ wake_up_all(&adev->fence_queue);
+ ring->fence_drv.initialized = false;
+ }
+ mutex_unlock(&adev->ring_lock);
+}
+
+/**
+ * amdgpu_fence_driver_force_completion - force all fence waiter to complete
+ *
+ * @adev: amdgpu device pointer
+ *
+ * In case of GPU reset failure make sure no process keep waiting on fence
+ * that will never complete.
+ */
+void amdgpu_fence_driver_force_completion(struct amdgpu_device *adev)
+{
+ int i;
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
+ struct amdgpu_ring *ring = adev->rings[i];
+ if (!ring || !ring->fence_drv.initialized)
+ continue;
+
+ amdgpu_fence_write(ring, ring->fence_drv.sync_seq[i]);
+ }
+}
+
+
+/*
+ * Fence debugfs
+ */
+#if defined(CONFIG_DEBUG_FS)
+static int amdgpu_debugfs_fence_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ int i, j;
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_ring *ring = adev->rings[i];
+ if (!ring || !ring->fence_drv.initialized)
+ continue;
+
+ amdgpu_fence_process(ring);
+
+ seq_printf(m, "--- ring %d ---\n", i);
+ seq_printf(m, "Last signaled fence 0x%016llx\n",
+ (unsigned long long)atomic64_read(&ring->fence_drv.last_seq));
+ seq_printf(m, "Last emitted 0x%016llx\n",
+ ring->fence_drv.sync_seq[i]);
+
+ for (j = 0; j < AMDGPU_MAX_RINGS; ++j) {
+ struct amdgpu_ring *other = adev->rings[j];
+ if (i != j && other && other->fence_drv.initialized)
+ seq_printf(m, "Last sync to ring %d 0x%016llx\n",
+ j, ring->fence_drv.sync_seq[j]);
+ }
+ }
+ return 0;
+}
+
+static struct drm_info_list amdgpu_debugfs_fence_list[] = {
+ {"amdgpu_fence_info", &amdgpu_debugfs_fence_info, 0, NULL},
+};
+#endif
+
+int amdgpu_debugfs_fence_init(struct amdgpu_device *adev)
+{
+#if defined(CONFIG_DEBUG_FS)
+ return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_fence_list, 1);
+#else
+ return 0;
+#endif
+}
+
+static const char *amdgpu_fence_get_driver_name(struct fence *fence)
+{
+ return "amdgpu";
+}
+
+static const char *amdgpu_fence_get_timeline_name(struct fence *f)
+{
+ struct amdgpu_fence *fence = to_amdgpu_fence(f);
+ return (const char *)fence->ring->name;
+}
+
+static inline bool amdgpu_test_signaled(struct amdgpu_fence *fence)
+{
+ return test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags);
+}
+
+struct amdgpu_wait_cb {
+ struct fence_cb base;
+ struct task_struct *task;
+};
+
+static void amdgpu_fence_wait_cb(struct fence *fence, struct fence_cb *cb)
+{
+ struct amdgpu_wait_cb *wait =
+ container_of(cb, struct amdgpu_wait_cb, base);
+ wake_up_process(wait->task);
+}
+
+static signed long amdgpu_fence_default_wait(struct fence *f, bool intr,
+ signed long t)
+{
+ struct amdgpu_fence *fence = to_amdgpu_fence(f);
+ struct amdgpu_device *adev = fence->ring->adev;
+ struct amdgpu_wait_cb cb;
+
+ cb.task = current;
+
+ if (fence_add_callback(f, &cb.base, amdgpu_fence_wait_cb))
+ return t;
+
+ while (t > 0) {
+ if (intr)
+ set_current_state(TASK_INTERRUPTIBLE);
+ else
+ set_current_state(TASK_UNINTERRUPTIBLE);
+
+ /*
+ * amdgpu_test_signaled must be called after
+ * set_current_state to prevent a race with wake_up_process
+ */
+ if (amdgpu_test_signaled(fence))
+ break;
+
+ if (adev->needs_reset) {
+ t = -EDEADLK;
+ break;
+ }
+
+ t = schedule_timeout(t);
+
+ if (t > 0 && intr && signal_pending(current))
+ t = -ERESTARTSYS;
+ }
+
+ __set_current_state(TASK_RUNNING);
+ fence_remove_callback(f, &cb.base);
+
+ return t;
+}
+
+const struct fence_ops amdgpu_fence_ops = {
+ .get_driver_name = amdgpu_fence_get_driver_name,
+ .get_timeline_name = amdgpu_fence_get_timeline_name,
+ .enable_signaling = amdgpu_fence_enable_signaling,
+ .signaled = amdgpu_fence_is_signaled,
+ .wait = amdgpu_fence_default_wait,
+ .release = NULL,
+};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
new file mode 100644
index 000000000000..e02db0b2e839
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+
+/*
+ * GART
+ * The GART (Graphics Aperture Remapping Table) is an aperture
+ * in the GPU's address space. System pages can be mapped into
+ * the aperture and look like contiguous pages from the GPU's
+ * perspective. A page table maps the pages in the aperture
+ * to the actual backing pages in system memory.
+ *
+ * Radeon GPUs support both an internal GART, as described above,
+ * and AGP. AGP works similarly, but the GART table is configured
+ * and maintained by the northbridge rather than the driver.
+ * Radeon hw has a separate AGP aperture that is programmed to
+ * point to the AGP aperture provided by the northbridge and the
+ * requests are passed through to the northbridge aperture.
+ * Both AGP and internal GART can be used at the same time, however
+ * that is not currently supported by the driver.
+ *
+ * This file handles the common internal GART management.
+ */
+
+/*
+ * Common GART table functions.
+ */
+/**
+ * amdgpu_gart_table_ram_alloc - allocate system ram for gart page table
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Allocate system memory for GART page table
+ * (r1xx-r3xx, non-pcie r4xx, rs400). These asics require the
+ * gart table to be in system memory.
+ * Returns 0 for success, -ENOMEM for failure.
+ */
+int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev)
+{
+ void *ptr;
+
+ ptr = pci_alloc_consistent(adev->pdev, adev->gart.table_size,
+ &adev->gart.table_addr);
+ if (ptr == NULL) {
+ return -ENOMEM;
+ }
+#ifdef CONFIG_X86
+ if (0) {
+ set_memory_uc((unsigned long)ptr,
+ adev->gart.table_size >> PAGE_SHIFT);
+ }
+#endif
+ adev->gart.ptr = ptr;
+ memset((void *)adev->gart.ptr, 0, adev->gart.table_size);
+ return 0;
+}
+
+/**
+ * amdgpu_gart_table_ram_free - free system ram for gart page table
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Free system memory for GART page table
+ * (r1xx-r3xx, non-pcie r4xx, rs400). These asics require the
+ * gart table to be in system memory.
+ */
+void amdgpu_gart_table_ram_free(struct amdgpu_device *adev)
+{
+ if (adev->gart.ptr == NULL) {
+ return;
+ }
+#ifdef CONFIG_X86
+ if (0) {
+ set_memory_wb((unsigned long)adev->gart.ptr,
+ adev->gart.table_size >> PAGE_SHIFT);
+ }
+#endif
+ pci_free_consistent(adev->pdev, adev->gart.table_size,
+ (void *)adev->gart.ptr,
+ adev->gart.table_addr);
+ adev->gart.ptr = NULL;
+ adev->gart.table_addr = 0;
+}
+
+/**
+ * amdgpu_gart_table_vram_alloc - allocate vram for gart page table
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Allocate video memory for GART page table
+ * (pcie r4xx, r5xx+). These asics require the
+ * gart table to be in video memory.
+ * Returns 0 for success, error for failure.
+ */
+int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev)
+{
+ int r;
+
+ if (adev->gart.robj == NULL) {
+ r = amdgpu_bo_create(adev, adev->gart.table_size,
+ PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, 0,
+ NULL, &adev->gart.robj);
+ if (r) {
+ return r;
+ }
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_gart_table_vram_pin - pin gart page table in vram
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Pin the GART page table in vram so it will not be moved
+ * by the memory manager (pcie r4xx, r5xx+). These asics require the
+ * gart table to be in video memory.
+ * Returns 0 for success, error for failure.
+ */
+int amdgpu_gart_table_vram_pin(struct amdgpu_device *adev)
+{
+ uint64_t gpu_addr;
+ int r;
+
+ r = amdgpu_bo_reserve(adev->gart.robj, false);
+ if (unlikely(r != 0))
+ return r;
+ r = amdgpu_bo_pin(adev->gart.robj,
+ AMDGPU_GEM_DOMAIN_VRAM, &gpu_addr);
+ if (r) {
+ amdgpu_bo_unreserve(adev->gart.robj);
+ return r;
+ }
+ r = amdgpu_bo_kmap(adev->gart.robj, &adev->gart.ptr);
+ if (r)
+ amdgpu_bo_unpin(adev->gart.robj);
+ amdgpu_bo_unreserve(adev->gart.robj);
+ adev->gart.table_addr = gpu_addr;
+ return r;
+}
+
+/**
+ * amdgpu_gart_table_vram_unpin - unpin gart page table in vram
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Unpin the GART page table in vram (pcie r4xx, r5xx+).
+ * These asics require the gart table to be in video memory.
+ */
+void amdgpu_gart_table_vram_unpin(struct amdgpu_device *adev)
+{
+ int r;
+
+ if (adev->gart.robj == NULL) {
+ return;
+ }
+ r = amdgpu_bo_reserve(adev->gart.robj, false);
+ if (likely(r == 0)) {
+ amdgpu_bo_kunmap(adev->gart.robj);
+ amdgpu_bo_unpin(adev->gart.robj);
+ amdgpu_bo_unreserve(adev->gart.robj);
+ adev->gart.ptr = NULL;
+ }
+}
+
+/**
+ * amdgpu_gart_table_vram_free - free gart page table vram
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Free the video memory used for the GART page table
+ * (pcie r4xx, r5xx+). These asics require the gart table to
+ * be in video memory.
+ */
+void amdgpu_gart_table_vram_free(struct amdgpu_device *adev)
+{
+ if (adev->gart.robj == NULL) {
+ return;
+ }
+ amdgpu_bo_unref(&adev->gart.robj);
+}
+
+/*
+ * Common gart functions.
+ */
+/**
+ * amdgpu_gart_unbind - unbind pages from the gart page table
+ *
+ * @adev: amdgpu_device pointer
+ * @offset: offset into the GPU's gart aperture
+ * @pages: number of pages to unbind
+ *
+ * Unbinds the requested pages from the gart page table and
+ * replaces them with the dummy page (all asics).
+ */
+void amdgpu_gart_unbind(struct amdgpu_device *adev, unsigned offset,
+ int pages)
+{
+ unsigned t;
+ unsigned p;
+ int i, j;
+ u64 page_base;
+ uint32_t flags = AMDGPU_PTE_SYSTEM;
+
+ if (!adev->gart.ready) {
+ WARN(1, "trying to unbind memory from uninitialized GART !\n");
+ return;
+ }
+
+ t = offset / AMDGPU_GPU_PAGE_SIZE;
+ p = t / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE);
+ for (i = 0; i < pages; i++, p++) {
+ if (adev->gart.pages[p]) {
+ adev->gart.pages[p] = NULL;
+ adev->gart.pages_addr[p] = adev->dummy_page.addr;
+ page_base = adev->gart.pages_addr[p];
+ if (!adev->gart.ptr)
+ continue;
+
+ for (j = 0; j < (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); j++, t++) {
+ amdgpu_gart_set_pte_pde(adev, adev->gart.ptr,
+ t, page_base, flags);
+ page_base += AMDGPU_GPU_PAGE_SIZE;
+ }
+ }
+ }
+ mb();
+ amdgpu_gart_flush_gpu_tlb(adev, 0);
+}
+
+/**
+ * amdgpu_gart_bind - bind pages into the gart page table
+ *
+ * @adev: amdgpu_device pointer
+ * @offset: offset into the GPU's gart aperture
+ * @pages: number of pages to bind
+ * @pagelist: pages to bind
+ * @dma_addr: DMA addresses of pages
+ *
+ * Binds the requested pages to the gart page table
+ * (all asics).
+ * Returns 0 for success, -EINVAL for failure.
+ */
+int amdgpu_gart_bind(struct amdgpu_device *adev, unsigned offset,
+ int pages, struct page **pagelist, dma_addr_t *dma_addr,
+ uint32_t flags)
+{
+ unsigned t;
+ unsigned p;
+ uint64_t page_base;
+ int i, j;
+
+ if (!adev->gart.ready) {
+ WARN(1, "trying to bind memory to uninitialized GART !\n");
+ return -EINVAL;
+ }
+
+ t = offset / AMDGPU_GPU_PAGE_SIZE;
+ p = t / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE);
+
+ for (i = 0; i < pages; i++, p++) {
+ adev->gart.pages_addr[p] = dma_addr[i];
+ adev->gart.pages[p] = pagelist[i];
+ if (adev->gart.ptr) {
+ page_base = adev->gart.pages_addr[p];
+ for (j = 0; j < (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); j++, t++) {
+ amdgpu_gart_set_pte_pde(adev, adev->gart.ptr, t, page_base, flags);
+ page_base += AMDGPU_GPU_PAGE_SIZE;
+ }
+ }
+ }
+ mb();
+ amdgpu_gart_flush_gpu_tlb(adev, 0);
+ return 0;
+}
+
+/**
+ * amdgpu_gart_init - init the driver info for managing the gart
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Allocate the dummy page and init the gart driver info (all asics).
+ * Returns 0 for success, error for failure.
+ */
+int amdgpu_gart_init(struct amdgpu_device *adev)
+{
+ int r, i;
+
+ if (adev->gart.pages) {
+ return 0;
+ }
+ /* We need PAGE_SIZE >= AMDGPU_GPU_PAGE_SIZE */
+ if (PAGE_SIZE < AMDGPU_GPU_PAGE_SIZE) {
+ DRM_ERROR("Page size is smaller than GPU page size!\n");
+ return -EINVAL;
+ }
+ r = amdgpu_dummy_page_init(adev);
+ if (r)
+ return r;
+ /* Compute table size */
+ adev->gart.num_cpu_pages = adev->mc.gtt_size / PAGE_SIZE;
+ adev->gart.num_gpu_pages = adev->mc.gtt_size / AMDGPU_GPU_PAGE_SIZE;
+ DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n",
+ adev->gart.num_cpu_pages, adev->gart.num_gpu_pages);
+ /* Allocate pages table */
+ adev->gart.pages = vzalloc(sizeof(void *) * adev->gart.num_cpu_pages);
+ if (adev->gart.pages == NULL) {
+ amdgpu_gart_fini(adev);
+ return -ENOMEM;
+ }
+ adev->gart.pages_addr = vzalloc(sizeof(dma_addr_t) *
+ adev->gart.num_cpu_pages);
+ if (adev->gart.pages_addr == NULL) {
+ amdgpu_gart_fini(adev);
+ return -ENOMEM;
+ }
+ /* set GART entry to point to the dummy page by default */
+ for (i = 0; i < adev->gart.num_cpu_pages; i++) {
+ adev->gart.pages_addr[i] = adev->dummy_page.addr;
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_gart_fini - tear down the driver info for managing the gart
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Tear down the gart driver info and free the dummy page (all asics).
+ */
+void amdgpu_gart_fini(struct amdgpu_device *adev)
+{
+ if (adev->gart.pages && adev->gart.pages_addr && adev->gart.ready) {
+ /* unbind pages */
+ amdgpu_gart_unbind(adev, 0, adev->gart.num_cpu_pages);
+ }
+ adev->gart.ready = false;
+ vfree(adev->gart.pages);
+ vfree(adev->gart.pages_addr);
+ adev->gart.pages = NULL;
+ adev->gart.pages_addr = NULL;
+
+ amdgpu_dummy_page_fini(adev);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h
new file mode 100644
index 000000000000..c3f4e85594ff
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gds.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_GDS_H__
+#define __AMDGPU_GDS_H__
+
+/* Because TTM request that alloacted buffer should be PAGE_SIZE aligned,
+ * we should report GDS/GWS/OA size as PAGE_SIZE aligned
+ * */
+#define AMDGPU_GDS_SHIFT 2
+#define AMDGPU_GWS_SHIFT PAGE_SHIFT
+#define AMDGPU_OA_SHIFT PAGE_SHIFT
+
+#define AMDGPU_PL_GDS TTM_PL_PRIV0
+#define AMDGPU_PL_GWS TTM_PL_PRIV1
+#define AMDGPU_PL_OA TTM_PL_PRIV2
+
+#define AMDGPU_PL_FLAG_GDS TTM_PL_FLAG_PRIV0
+#define AMDGPU_PL_FLAG_GWS TTM_PL_FLAG_PRIV1
+#define AMDGPU_PL_FLAG_OA TTM_PL_FLAG_PRIV2
+
+struct amdgpu_ring;
+struct amdgpu_bo;
+
+struct amdgpu_gds_asic_info {
+ uint32_t total_size;
+ uint32_t gfx_partition_size;
+ uint32_t cs_partition_size;
+};
+
+struct amdgpu_gds {
+ struct amdgpu_gds_asic_info mem;
+ struct amdgpu_gds_asic_info gws;
+ struct amdgpu_gds_asic_info oa;
+ /* At present, GDS, GWS and OA resources for gfx (graphics)
+ * is always pre-allocated and available for graphics operation.
+ * Such resource is shared between all gfx clients.
+ * TODO: move this operation to user space
+ * */
+ struct amdgpu_bo* gds_gfx_bo;
+ struct amdgpu_bo* gws_gfx_bo;
+ struct amdgpu_bo* oa_gfx_bo;
+};
+
+struct amdgpu_gds_reg_offset {
+ uint32_t mem_base;
+ uint32_t mem_size;
+ uint32_t gws;
+ uint32_t oa;
+};
+
+#endif /* __AMDGPU_GDS_H__ */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
new file mode 100644
index 000000000000..0ec222295fee
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -0,0 +1,716 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#include <linux/ktime.h>
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+
+void amdgpu_gem_object_free(struct drm_gem_object *gobj)
+{
+ struct amdgpu_bo *robj = gem_to_amdgpu_bo(gobj);
+
+ if (robj) {
+ if (robj->gem_base.import_attach)
+ drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg);
+ amdgpu_mn_unregister(robj);
+ amdgpu_bo_unref(&robj);
+ }
+}
+
+int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size,
+ int alignment, u32 initial_domain,
+ u64 flags, bool kernel,
+ struct drm_gem_object **obj)
+{
+ struct amdgpu_bo *robj;
+ unsigned long max_size;
+ int r;
+
+ *obj = NULL;
+ /* At least align on page size */
+ if (alignment < PAGE_SIZE) {
+ alignment = PAGE_SIZE;
+ }
+
+ if (!(initial_domain & (AMDGPU_GEM_DOMAIN_GDS | AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA))) {
+ /* Maximum bo size is the unpinned gtt size since we use the gtt to
+ * handle vram to system pool migrations.
+ */
+ max_size = adev->mc.gtt_size - adev->gart_pin_size;
+ if (size > max_size) {
+ DRM_DEBUG("Allocation size %ldMb bigger than %ldMb limit\n",
+ size >> 20, max_size >> 20);
+ return -ENOMEM;
+ }
+ }
+retry:
+ r = amdgpu_bo_create(adev, size, alignment, kernel, initial_domain, flags, NULL, &robj);
+ if (r) {
+ if (r != -ERESTARTSYS) {
+ if (initial_domain == AMDGPU_GEM_DOMAIN_VRAM) {
+ initial_domain |= AMDGPU_GEM_DOMAIN_GTT;
+ goto retry;
+ }
+ DRM_ERROR("Failed to allocate GEM object (%ld, %d, %u, %d)\n",
+ size, initial_domain, alignment, r);
+ }
+ return r;
+ }
+ *obj = &robj->gem_base;
+ robj->pid = task_pid_nr(current);
+
+ mutex_lock(&adev->gem.mutex);
+ list_add_tail(&robj->list, &adev->gem.objects);
+ mutex_unlock(&adev->gem.mutex);
+
+ return 0;
+}
+
+int amdgpu_gem_init(struct amdgpu_device *adev)
+{
+ INIT_LIST_HEAD(&adev->gem.objects);
+ return 0;
+}
+
+void amdgpu_gem_fini(struct amdgpu_device *adev)
+{
+ amdgpu_bo_force_delete(adev);
+}
+
+/*
+ * Call from drm_gem_handle_create which appear in both new and open ioctl
+ * case.
+ */
+int amdgpu_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv)
+{
+ struct amdgpu_bo *rbo = gem_to_amdgpu_bo(obj);
+ struct amdgpu_device *adev = rbo->adev;
+ struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
+ struct amdgpu_vm *vm = &fpriv->vm;
+ struct amdgpu_bo_va *bo_va;
+ int r;
+
+ r = amdgpu_bo_reserve(rbo, false);
+ if (r) {
+ return r;
+ }
+
+ bo_va = amdgpu_vm_bo_find(vm, rbo);
+ if (!bo_va) {
+ bo_va = amdgpu_vm_bo_add(adev, vm, rbo);
+ } else {
+ ++bo_va->ref_count;
+ }
+ amdgpu_bo_unreserve(rbo);
+
+ return 0;
+}
+
+void amdgpu_gem_object_close(struct drm_gem_object *obj,
+ struct drm_file *file_priv)
+{
+ struct amdgpu_bo *rbo = gem_to_amdgpu_bo(obj);
+ struct amdgpu_device *adev = rbo->adev;
+ struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
+ struct amdgpu_vm *vm = &fpriv->vm;
+ struct amdgpu_bo_va *bo_va;
+ int r;
+
+ r = amdgpu_bo_reserve(rbo, true);
+ if (r) {
+ dev_err(adev->dev, "leaking bo va because "
+ "we fail to reserve bo (%d)\n", r);
+ return;
+ }
+ bo_va = amdgpu_vm_bo_find(vm, rbo);
+ if (bo_va) {
+ if (--bo_va->ref_count == 0) {
+ amdgpu_vm_bo_rmv(adev, bo_va);
+ }
+ }
+ amdgpu_bo_unreserve(rbo);
+}
+
+static int amdgpu_gem_handle_lockup(struct amdgpu_device *adev, int r)
+{
+ if (r == -EDEADLK) {
+ r = amdgpu_gpu_reset(adev);
+ if (!r)
+ r = -EAGAIN;
+ }
+ return r;
+}
+
+/*
+ * GEM ioctls.
+ */
+int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ union drm_amdgpu_gem_create *args = data;
+ uint64_t size = args->in.bo_size;
+ struct drm_gem_object *gobj;
+ uint32_t handle;
+ bool kernel = false;
+ int r;
+
+ down_read(&adev->exclusive_lock);
+ /* create a gem object to contain this object in */
+ if (args->in.domains & (AMDGPU_GEM_DOMAIN_GDS |
+ AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA)) {
+ kernel = true;
+ if (args->in.domains == AMDGPU_GEM_DOMAIN_GDS)
+ size = size << AMDGPU_GDS_SHIFT;
+ else if (args->in.domains == AMDGPU_GEM_DOMAIN_GWS)
+ size = size << AMDGPU_GWS_SHIFT;
+ else if (args->in.domains == AMDGPU_GEM_DOMAIN_OA)
+ size = size << AMDGPU_OA_SHIFT;
+ else {
+ r = -EINVAL;
+ goto error_unlock;
+ }
+ }
+ size = roundup(size, PAGE_SIZE);
+
+ r = amdgpu_gem_object_create(adev, size, args->in.alignment,
+ (u32)(0xffffffff & args->in.domains),
+ args->in.domain_flags,
+ kernel, &gobj);
+ if (r)
+ goto error_unlock;
+
+ r = drm_gem_handle_create(filp, gobj, &handle);
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(gobj);
+ if (r)
+ goto error_unlock;
+
+ memset(args, 0, sizeof(*args));
+ args->out.handle = handle;
+ up_read(&adev->exclusive_lock);
+ return 0;
+
+error_unlock:
+ up_read(&adev->exclusive_lock);
+ r = amdgpu_gem_handle_lockup(adev, r);
+ return r;
+}
+
+int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ struct drm_amdgpu_gem_userptr *args = data;
+ struct drm_gem_object *gobj;
+ struct amdgpu_bo *bo;
+ uint32_t handle;
+ int r;
+
+ if (offset_in_page(args->addr | args->size))
+ return -EINVAL;
+
+ /* reject unknown flag values */
+ if (args->flags & ~(AMDGPU_GEM_USERPTR_READONLY |
+ AMDGPU_GEM_USERPTR_ANONONLY | AMDGPU_GEM_USERPTR_VALIDATE |
+ AMDGPU_GEM_USERPTR_REGISTER))
+ return -EINVAL;
+
+ if (!(args->flags & AMDGPU_GEM_USERPTR_ANONONLY) ||
+ !(args->flags & AMDGPU_GEM_USERPTR_REGISTER)) {
+
+ /* if we want to write to it we must require anonymous
+ memory and install a MMU notifier */
+ return -EACCES;
+ }
+
+ down_read(&adev->exclusive_lock);
+
+ /* create a gem object to contain this object in */
+ r = amdgpu_gem_object_create(adev, args->size, 0,
+ AMDGPU_GEM_DOMAIN_CPU, 0,
+ 0, &gobj);
+ if (r)
+ goto handle_lockup;
+
+ bo = gem_to_amdgpu_bo(gobj);
+ r = amdgpu_ttm_tt_set_userptr(bo->tbo.ttm, args->addr, args->flags);
+ if (r)
+ goto release_object;
+
+ if (args->flags & AMDGPU_GEM_USERPTR_REGISTER) {
+ r = amdgpu_mn_register(bo, args->addr);
+ if (r)
+ goto release_object;
+ }
+
+ if (args->flags & AMDGPU_GEM_USERPTR_VALIDATE) {
+ down_read(&current->mm->mmap_sem);
+ r = amdgpu_bo_reserve(bo, true);
+ if (r) {
+ up_read(&current->mm->mmap_sem);
+ goto release_object;
+ }
+
+ amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_GTT);
+ r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
+ amdgpu_bo_unreserve(bo);
+ up_read(&current->mm->mmap_sem);
+ if (r)
+ goto release_object;
+ }
+
+ r = drm_gem_handle_create(filp, gobj, &handle);
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(gobj);
+ if (r)
+ goto handle_lockup;
+
+ args->handle = handle;
+ up_read(&adev->exclusive_lock);
+ return 0;
+
+release_object:
+ drm_gem_object_unreference_unlocked(gobj);
+
+handle_lockup:
+ up_read(&adev->exclusive_lock);
+ r = amdgpu_gem_handle_lockup(adev, r);
+
+ return r;
+}
+
+int amdgpu_mode_dumb_mmap(struct drm_file *filp,
+ struct drm_device *dev,
+ uint32_t handle, uint64_t *offset_p)
+{
+ struct drm_gem_object *gobj;
+ struct amdgpu_bo *robj;
+
+ gobj = drm_gem_object_lookup(dev, filp, handle);
+ if (gobj == NULL) {
+ return -ENOENT;
+ }
+ robj = gem_to_amdgpu_bo(gobj);
+ if (amdgpu_ttm_tt_has_userptr(robj->tbo.ttm) ||
+ (robj->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)) {
+ drm_gem_object_unreference_unlocked(gobj);
+ return -EPERM;
+ }
+ *offset_p = amdgpu_bo_mmap_offset(robj);
+ drm_gem_object_unreference_unlocked(gobj);
+ return 0;
+}
+
+int amdgpu_gem_mmap_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ union drm_amdgpu_gem_mmap *args = data;
+ uint32_t handle = args->in.handle;
+ memset(args, 0, sizeof(*args));
+ return amdgpu_mode_dumb_mmap(filp, dev, handle, &args->out.addr_ptr);
+}
+
+/**
+ * amdgpu_gem_timeout - calculate jiffies timeout from absolute value
+ *
+ * @timeout_ns: timeout in ns
+ *
+ * Calculate the timeout in jiffies from an absolute timeout in ns.
+ */
+unsigned long amdgpu_gem_timeout(uint64_t timeout_ns)
+{
+ unsigned long timeout_jiffies;
+ ktime_t timeout;
+
+ /* clamp timeout if it's to large */
+ if (((int64_t)timeout_ns) < 0)
+ return MAX_SCHEDULE_TIMEOUT;
+
+ timeout = ktime_sub_ns(ktime_get(), timeout_ns);
+ if (ktime_to_ns(timeout) < 0)
+ return 0;
+
+ timeout_jiffies = nsecs_to_jiffies(ktime_to_ns(timeout));
+ /* clamp timeout to avoid unsigned-> signed overflow */
+ if (timeout_jiffies > MAX_SCHEDULE_TIMEOUT )
+ return MAX_SCHEDULE_TIMEOUT - 1;
+
+ return timeout_jiffies;
+}
+
+int amdgpu_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ union drm_amdgpu_gem_wait_idle *args = data;
+ struct drm_gem_object *gobj;
+ struct amdgpu_bo *robj;
+ uint32_t handle = args->in.handle;
+ unsigned long timeout = amdgpu_gem_timeout(args->in.timeout);
+ int r = 0;
+ long ret;
+
+ gobj = drm_gem_object_lookup(dev, filp, handle);
+ if (gobj == NULL) {
+ return -ENOENT;
+ }
+ robj = gem_to_amdgpu_bo(gobj);
+ if (timeout == 0)
+ ret = reservation_object_test_signaled_rcu(robj->tbo.resv, true);
+ else
+ ret = reservation_object_wait_timeout_rcu(robj->tbo.resv, true, true, timeout);
+
+ /* ret == 0 means not signaled,
+ * ret > 0 means signaled
+ * ret < 0 means interrupted before timeout
+ */
+ if (ret >= 0) {
+ memset(args, 0, sizeof(*args));
+ args->out.status = (ret == 0);
+ } else
+ r = ret;
+
+ drm_gem_object_unreference_unlocked(gobj);
+ r = amdgpu_gem_handle_lockup(adev, r);
+ return r;
+}
+
+int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ struct drm_amdgpu_gem_metadata *args = data;
+ struct drm_gem_object *gobj;
+ struct amdgpu_bo *robj;
+ int r = -1;
+
+ DRM_DEBUG("%d \n", args->handle);
+ gobj = drm_gem_object_lookup(dev, filp, args->handle);
+ if (gobj == NULL)
+ return -ENOENT;
+ robj = gem_to_amdgpu_bo(gobj);
+
+ r = amdgpu_bo_reserve(robj, false);
+ if (unlikely(r != 0))
+ goto out;
+
+ if (args->op == AMDGPU_GEM_METADATA_OP_GET_METADATA) {
+ amdgpu_bo_get_tiling_flags(robj, &args->data.tiling_info);
+ r = amdgpu_bo_get_metadata(robj, args->data.data,
+ sizeof(args->data.data),
+ &args->data.data_size_bytes,
+ &args->data.flags);
+ } else if (args->op == AMDGPU_GEM_METADATA_OP_SET_METADATA) {
+ r = amdgpu_bo_set_tiling_flags(robj, args->data.tiling_info);
+ if (!r)
+ r = amdgpu_bo_set_metadata(robj, args->data.data,
+ args->data.data_size_bytes,
+ args->data.flags);
+ }
+
+ amdgpu_bo_unreserve(robj);
+out:
+ drm_gem_object_unreference_unlocked(gobj);
+ return r;
+}
+
+/**
+ * amdgpu_gem_va_update_vm -update the bo_va in its VM
+ *
+ * @adev: amdgpu_device pointer
+ * @bo_va: bo_va to update
+ *
+ * Update the bo_va directly after setting it's address. Errors are not
+ * vital here, so they are not reported back to userspace.
+ */
+static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va)
+{
+ struct ttm_validate_buffer tv, *entry;
+ struct amdgpu_bo_list_entry *vm_bos;
+ struct ww_acquire_ctx ticket;
+ struct list_head list;
+ unsigned domain;
+ int r;
+
+ INIT_LIST_HEAD(&list);
+
+ tv.bo = &bo_va->bo->tbo;
+ tv.shared = true;
+ list_add(&tv.head, &list);
+
+ vm_bos = amdgpu_vm_get_bos(adev, bo_va->vm, &list);
+ if (!vm_bos)
+ return;
+
+ r = ttm_eu_reserve_buffers(&ticket, &list, true, NULL);
+ if (r)
+ goto error_free;
+
+ 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,
+ just abort and wait for the next CS */
+ if (domain == AMDGPU_GEM_DOMAIN_CPU)
+ goto error_unreserve;
+ }
+
+ mutex_lock(&bo_va->vm->mutex);
+ r = amdgpu_vm_clear_freed(adev, bo_va->vm);
+ if (r)
+ goto error_unlock;
+
+ r = amdgpu_vm_bo_update(adev, bo_va, &bo_va->bo->tbo.mem);
+
+error_unlock:
+ mutex_unlock(&bo_va->vm->mutex);
+
+error_unreserve:
+ ttm_eu_backoff_reservation(&ticket, &list);
+
+error_free:
+ drm_free_large(vm_bos);
+
+ if (r)
+ DRM_ERROR("Couldn't update BO_VA (%d)\n", r);
+}
+
+
+
+int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ struct drm_amdgpu_gem_va *args = data;
+ struct drm_gem_object *gobj;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_fpriv *fpriv = filp->driver_priv;
+ struct amdgpu_bo *rbo;
+ struct amdgpu_bo_va *bo_va;
+ uint32_t invalid_flags, va_flags = 0;
+ int r = 0;
+
+ if (!adev->vm_manager.enabled)
+ return -ENOTTY;
+
+ if (args->va_address < AMDGPU_VA_RESERVED_SIZE) {
+ dev_err(&dev->pdev->dev,
+ "va_address 0x%lX is in reserved area 0x%X\n",
+ (unsigned long)args->va_address,
+ AMDGPU_VA_RESERVED_SIZE);
+ return -EINVAL;
+ }
+
+ invalid_flags = ~(AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE |
+ AMDGPU_VM_PAGE_EXECUTABLE);
+ if ((args->flags & invalid_flags)) {
+ dev_err(&dev->pdev->dev, "invalid flags 0x%08X vs 0x%08X\n",
+ args->flags, invalid_flags);
+ return -EINVAL;
+ }
+
+ switch (args->operation) {
+ case AMDGPU_VA_OP_MAP:
+ case AMDGPU_VA_OP_UNMAP:
+ break;
+ default:
+ dev_err(&dev->pdev->dev, "unsupported operation %d\n",
+ args->operation);
+ return -EINVAL;
+ }
+
+ gobj = drm_gem_object_lookup(dev, filp, args->handle);
+ if (gobj == NULL)
+ return -ENOENT;
+
+ rbo = gem_to_amdgpu_bo(gobj);
+ r = amdgpu_bo_reserve(rbo, false);
+ if (r) {
+ drm_gem_object_unreference_unlocked(gobj);
+ return r;
+ }
+
+ bo_va = amdgpu_vm_bo_find(&fpriv->vm, rbo);
+ if (!bo_va) {
+ amdgpu_bo_unreserve(rbo);
+ return -ENOENT;
+ }
+
+ switch (args->operation) {
+ case AMDGPU_VA_OP_MAP:
+ if (args->flags & AMDGPU_VM_PAGE_READABLE)
+ va_flags |= AMDGPU_PTE_READABLE;
+ if (args->flags & AMDGPU_VM_PAGE_WRITEABLE)
+ va_flags |= AMDGPU_PTE_WRITEABLE;
+ if (args->flags & AMDGPU_VM_PAGE_EXECUTABLE)
+ va_flags |= AMDGPU_PTE_EXECUTABLE;
+ r = amdgpu_vm_bo_map(adev, bo_va, args->va_address,
+ args->offset_in_bo, args->map_size,
+ va_flags);
+ break;
+ case AMDGPU_VA_OP_UNMAP:
+ r = amdgpu_vm_bo_unmap(adev, bo_va, args->va_address);
+ break;
+ default:
+ break;
+ }
+
+ if (!r)
+ amdgpu_gem_va_update_vm(adev, bo_va);
+
+ drm_gem_object_unreference_unlocked(gobj);
+ return r;
+}
+
+int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *filp)
+{
+ struct drm_amdgpu_gem_op *args = data;
+ struct drm_gem_object *gobj;
+ struct amdgpu_bo *robj;
+ int r;
+
+ gobj = drm_gem_object_lookup(dev, filp, args->handle);
+ if (gobj == NULL) {
+ return -ENOENT;
+ }
+ robj = gem_to_amdgpu_bo(gobj);
+
+ r = amdgpu_bo_reserve(robj, false);
+ if (unlikely(r))
+ goto out;
+
+ switch (args->op) {
+ case AMDGPU_GEM_OP_GET_GEM_CREATE_INFO: {
+ struct drm_amdgpu_gem_create_in info;
+ void __user *out = (void __user *)(long)args->value;
+
+ info.bo_size = robj->gem_base.size;
+ info.alignment = robj->tbo.mem.page_alignment << PAGE_SHIFT;
+ info.domains = robj->initial_domain;
+ info.domain_flags = robj->flags;
+ if (copy_to_user(out, &info, sizeof(info)))
+ r = -EFAULT;
+ break;
+ }
+ case AMDGPU_GEM_OP_SET_PLACEMENT:
+ if (amdgpu_ttm_tt_has_userptr(robj->tbo.ttm)) {
+ r = -EPERM;
+ break;
+ }
+ robj->initial_domain = args->value & (AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT |
+ AMDGPU_GEM_DOMAIN_CPU);
+ break;
+ default:
+ r = -EINVAL;
+ }
+
+ amdgpu_bo_unreserve(robj);
+out:
+ drm_gem_object_unreference_unlocked(gobj);
+ return r;
+}
+
+int amdgpu_mode_dumb_create(struct drm_file *file_priv,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ struct drm_gem_object *gobj;
+ uint32_t handle;
+ int r;
+
+ args->pitch = amdgpu_align_pitch(adev, args->width, args->bpp, 0) * ((args->bpp + 1) / 8);
+ args->size = args->pitch * args->height;
+ args->size = ALIGN(args->size, PAGE_SIZE);
+
+ r = amdgpu_gem_object_create(adev, args->size, 0,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ 0, ttm_bo_type_device,
+ &gobj);
+ if (r)
+ return -ENOMEM;
+
+ r = drm_gem_handle_create(file_priv, gobj, &handle);
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(gobj);
+ if (r) {
+ return r;
+ }
+ args->handle = handle;
+ return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static int amdgpu_debugfs_gem_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_bo *rbo;
+ unsigned i = 0;
+
+ mutex_lock(&adev->gem.mutex);
+ list_for_each_entry(rbo, &adev->gem.objects, list) {
+ unsigned domain;
+ const char *placement;
+
+ domain = amdgpu_mem_type_to_domain(rbo->tbo.mem.mem_type);
+ switch (domain) {
+ case AMDGPU_GEM_DOMAIN_VRAM:
+ placement = "VRAM";
+ break;
+ case AMDGPU_GEM_DOMAIN_GTT:
+ placement = " GTT";
+ break;
+ case AMDGPU_GEM_DOMAIN_CPU:
+ default:
+ placement = " CPU";
+ break;
+ }
+ seq_printf(m, "bo[0x%08x] %8ldkB %8ldMB %s pid %8ld\n",
+ i, amdgpu_bo_size(rbo) >> 10, amdgpu_bo_size(rbo) >> 20,
+ placement, (unsigned long)rbo->pid);
+ i++;
+ }
+ mutex_unlock(&adev->gem.mutex);
+ return 0;
+}
+
+static struct drm_info_list amdgpu_debugfs_gem_list[] = {
+ {"amdgpu_gem_info", &amdgpu_debugfs_gem_info, 0, NULL},
+};
+#endif
+
+int amdgpu_gem_debugfs_init(struct amdgpu_device *adev)
+{
+#if defined(CONFIG_DEBUG_FS)
+ return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_gem_list, 1);
+#endif
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
new file mode 100644
index 000000000000..9f95da4f0536
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <drm/drmP.h>
+#include "amdgpu.h"
+
+/*
+ * GPU scratch registers helpers function.
+ */
+/**
+ * amdgpu_gfx_scratch_get - Allocate a scratch register
+ *
+ * @adev: amdgpu_device pointer
+ * @reg: scratch register mmio offset
+ *
+ * Allocate a CP scratch register for use by the driver (all asics).
+ * Returns 0 on success or -EINVAL on failure.
+ */
+int amdgpu_gfx_scratch_get(struct amdgpu_device *adev, uint32_t *reg)
+{
+ int i;
+
+ for (i = 0; i < adev->gfx.scratch.num_reg; i++) {
+ if (adev->gfx.scratch.free[i]) {
+ adev->gfx.scratch.free[i] = false;
+ *reg = adev->gfx.scratch.reg[i];
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/**
+ * amdgpu_gfx_scratch_free - Free a scratch register
+ *
+ * @adev: amdgpu_device pointer
+ * @reg: scratch register mmio offset
+ *
+ * Free a CP scratch register allocated for use by the driver (all asics)
+ */
+void amdgpu_gfx_scratch_free(struct amdgpu_device *adev, uint32_t reg)
+{
+ int i;
+
+ for (i = 0; i < adev->gfx.scratch.num_reg; i++) {
+ if (adev->gfx.scratch.reg[i] == reg) {
+ adev->gfx.scratch.free[i] = true;
+ return;
+ }
+ }
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
new file mode 100644
index 000000000000..dc06cbda7be6
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_GFX_H__
+#define __AMDGPU_GFX_H__
+
+int amdgpu_gfx_scratch_get(struct amdgpu_device *adev, uint32_t *reg);
+void amdgpu_gfx_scratch_free(struct amdgpu_device *adev, uint32_t reg);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
new file mode 100644
index 000000000000..31a676376d73
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2007-8 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 shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ */
+#include <linux/export.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_edid.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "amdgpu_i2c.h"
+#include "amdgpu_atombios.h"
+#include "atom.h"
+#include "atombios_dp.h"
+#include "atombios_i2c.h"
+
+/* bit banging i2c */
+static int amdgpu_i2c_pre_xfer(struct i2c_adapter *i2c_adap)
+{
+ struct amdgpu_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
+ struct amdgpu_device *adev = i2c->dev->dev_private;
+ struct amdgpu_i2c_bus_rec *rec = &i2c->rec;
+ uint32_t temp;
+
+ mutex_lock(&i2c->mutex);
+
+ /* switch the pads to ddc mode */
+ if (rec->hw_capable) {
+ temp = RREG32(rec->mask_clk_reg);
+ temp &= ~(1 << 16);
+ WREG32(rec->mask_clk_reg, temp);
+ }
+
+ /* clear the output pin values */
+ temp = RREG32(rec->a_clk_reg) & ~rec->a_clk_mask;
+ WREG32(rec->a_clk_reg, temp);
+
+ temp = RREG32(rec->a_data_reg) & ~rec->a_data_mask;
+ WREG32(rec->a_data_reg, temp);
+
+ /* set the pins to input */
+ temp = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask;
+ WREG32(rec->en_clk_reg, temp);
+
+ temp = RREG32(rec->en_data_reg) & ~rec->en_data_mask;
+ WREG32(rec->en_data_reg, temp);
+
+ /* mask the gpio pins for software use */
+ temp = RREG32(rec->mask_clk_reg) | rec->mask_clk_mask;
+ WREG32(rec->mask_clk_reg, temp);
+ temp = RREG32(rec->mask_clk_reg);
+
+ temp = RREG32(rec->mask_data_reg) | rec->mask_data_mask;
+ WREG32(rec->mask_data_reg, temp);
+ temp = RREG32(rec->mask_data_reg);
+
+ return 0;
+}
+
+static void amdgpu_i2c_post_xfer(struct i2c_adapter *i2c_adap)
+{
+ struct amdgpu_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
+ struct amdgpu_device *adev = i2c->dev->dev_private;
+ struct amdgpu_i2c_bus_rec *rec = &i2c->rec;
+ uint32_t temp;
+
+ /* unmask the gpio pins for software use */
+ temp = RREG32(rec->mask_clk_reg) & ~rec->mask_clk_mask;
+ WREG32(rec->mask_clk_reg, temp);
+ temp = RREG32(rec->mask_clk_reg);
+
+ temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask;
+ WREG32(rec->mask_data_reg, temp);
+ temp = RREG32(rec->mask_data_reg);
+
+ mutex_unlock(&i2c->mutex);
+}
+
+static int amdgpu_i2c_get_clock(void *i2c_priv)
+{
+ struct amdgpu_i2c_chan *i2c = i2c_priv;
+ struct amdgpu_device *adev = i2c->dev->dev_private;
+ struct amdgpu_i2c_bus_rec *rec = &i2c->rec;
+ uint32_t val;
+
+ /* read the value off the pin */
+ val = RREG32(rec->y_clk_reg);
+ val &= rec->y_clk_mask;
+
+ return (val != 0);
+}
+
+
+static int amdgpu_i2c_get_data(void *i2c_priv)
+{
+ struct amdgpu_i2c_chan *i2c = i2c_priv;
+ struct amdgpu_device *adev = i2c->dev->dev_private;
+ struct amdgpu_i2c_bus_rec *rec = &i2c->rec;
+ uint32_t val;
+
+ /* read the value off the pin */
+ val = RREG32(rec->y_data_reg);
+ val &= rec->y_data_mask;
+
+ return (val != 0);
+}
+
+static void amdgpu_i2c_set_clock(void *i2c_priv, int clock)
+{
+ struct amdgpu_i2c_chan *i2c = i2c_priv;
+ struct amdgpu_device *adev = i2c->dev->dev_private;
+ struct amdgpu_i2c_bus_rec *rec = &i2c->rec;
+ uint32_t val;
+
+ /* set pin direction */
+ val = RREG32(rec->en_clk_reg) & ~rec->en_clk_mask;
+ val |= clock ? 0 : rec->en_clk_mask;
+ WREG32(rec->en_clk_reg, val);
+}
+
+static void amdgpu_i2c_set_data(void *i2c_priv, int data)
+{
+ struct amdgpu_i2c_chan *i2c = i2c_priv;
+ struct amdgpu_device *adev = i2c->dev->dev_private;
+ struct amdgpu_i2c_bus_rec *rec = &i2c->rec;
+ uint32_t val;
+
+ /* set pin direction */
+ val = RREG32(rec->en_data_reg) & ~rec->en_data_mask;
+ val |= data ? 0 : rec->en_data_mask;
+ WREG32(rec->en_data_reg, val);
+}
+
+static const struct i2c_algorithm amdgpu_atombios_i2c_algo = {
+ .master_xfer = amdgpu_atombios_i2c_xfer,
+ .functionality = amdgpu_atombios_i2c_func,
+};
+
+struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev,
+ struct amdgpu_i2c_bus_rec *rec,
+ const char *name)
+{
+ struct amdgpu_i2c_chan *i2c;
+ int ret;
+
+ /* don't add the mm_i2c bus unless hw_i2c is enabled */
+ if (rec->mm_i2c && (amdgpu_hw_i2c == 0))
+ return NULL;
+
+ i2c = kzalloc(sizeof(struct amdgpu_i2c_chan), GFP_KERNEL);
+ if (i2c == NULL)
+ return NULL;
+
+ i2c->rec = *rec;
+ i2c->adapter.owner = THIS_MODULE;
+ i2c->adapter.class = I2C_CLASS_DDC;
+ i2c->adapter.dev.parent = &dev->pdev->dev;
+ i2c->dev = dev;
+ i2c_set_adapdata(&i2c->adapter, i2c);
+ mutex_init(&i2c->mutex);
+ if (rec->hw_capable &&
+ amdgpu_hw_i2c) {
+ /* hw i2c using atom */
+ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+ "AMDGPU i2c hw bus %s", name);
+ i2c->adapter.algo = &amdgpu_atombios_i2c_algo;
+ ret = i2c_add_adapter(&i2c->adapter);
+ if (ret) {
+ DRM_ERROR("Failed to register hw i2c %s\n", name);
+ goto out_free;
+ }
+ } else {
+ /* set the amdgpu bit adapter */
+ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+ "AMDGPU i2c bit bus %s", name);
+ i2c->adapter.algo_data = &i2c->bit;
+ i2c->bit.pre_xfer = amdgpu_i2c_pre_xfer;
+ i2c->bit.post_xfer = amdgpu_i2c_post_xfer;
+ i2c->bit.setsda = amdgpu_i2c_set_data;
+ i2c->bit.setscl = amdgpu_i2c_set_clock;
+ i2c->bit.getsda = amdgpu_i2c_get_data;
+ i2c->bit.getscl = amdgpu_i2c_get_clock;
+ i2c->bit.udelay = 10;
+ i2c->bit.timeout = usecs_to_jiffies(2200); /* from VESA */
+ i2c->bit.data = i2c;
+ ret = i2c_bit_add_bus(&i2c->adapter);
+ if (ret) {
+ DRM_ERROR("Failed to register bit i2c %s\n", name);
+ goto out_free;
+ }
+ }
+
+ return i2c;
+out_free:
+ kfree(i2c);
+ return NULL;
+
+}
+
+void amdgpu_i2c_destroy(struct amdgpu_i2c_chan *i2c)
+{
+ if (!i2c)
+ return;
+ i2c_del_adapter(&i2c->adapter);
+ kfree(i2c);
+}
+
+/* Add the default buses */
+void amdgpu_i2c_init(struct amdgpu_device *adev)
+{
+ if (amdgpu_hw_i2c)
+ DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n");
+
+ if (adev->is_atom_bios)
+ amdgpu_atombios_i2c_init(adev);
+}
+
+/* remove all the buses */
+void amdgpu_i2c_fini(struct amdgpu_device *adev)
+{
+ int i;
+
+ for (i = 0; i < AMDGPU_MAX_I2C_BUS; i++) {
+ if (adev->i2c_bus[i]) {
+ amdgpu_i2c_destroy(adev->i2c_bus[i]);
+ adev->i2c_bus[i] = NULL;
+ }
+ }
+}
+
+/* Add additional buses */
+void amdgpu_i2c_add(struct amdgpu_device *adev,
+ struct amdgpu_i2c_bus_rec *rec,
+ const char *name)
+{
+ struct drm_device *dev = adev->ddev;
+ int i;
+
+ for (i = 0; i < AMDGPU_MAX_I2C_BUS; i++) {
+ if (!adev->i2c_bus[i]) {
+ adev->i2c_bus[i] = amdgpu_i2c_create(dev, rec, name);
+ return;
+ }
+ }
+}
+
+/* looks up bus based on id */
+struct amdgpu_i2c_chan *
+amdgpu_i2c_lookup(struct amdgpu_device *adev,
+ struct amdgpu_i2c_bus_rec *i2c_bus)
+{
+ int i;
+
+ for (i = 0; i < AMDGPU_MAX_I2C_BUS; i++) {
+ if (adev->i2c_bus[i] &&
+ (adev->i2c_bus[i]->rec.i2c_id == i2c_bus->i2c_id)) {
+ return adev->i2c_bus[i];
+ }
+ }
+ return NULL;
+}
+
+static void amdgpu_i2c_get_byte(struct amdgpu_i2c_chan *i2c_bus,
+ u8 slave_addr,
+ u8 addr,
+ u8 *val)
+{
+ u8 out_buf[2];
+ u8 in_buf[2];
+ struct i2c_msg msgs[] = {
+ {
+ .addr = slave_addr,
+ .flags = 0,
+ .len = 1,
+ .buf = out_buf,
+ },
+ {
+ .addr = slave_addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = in_buf,
+ }
+ };
+
+ out_buf[0] = addr;
+ out_buf[1] = 0;
+
+ if (i2c_transfer(&i2c_bus->adapter, msgs, 2) == 2) {
+ *val = in_buf[0];
+ DRM_DEBUG("val = 0x%02x\n", *val);
+ } else {
+ DRM_DEBUG("i2c 0x%02x 0x%02x read failed\n",
+ addr, *val);
+ }
+}
+
+static void amdgpu_i2c_put_byte(struct amdgpu_i2c_chan *i2c_bus,
+ u8 slave_addr,
+ u8 addr,
+ u8 val)
+{
+ uint8_t out_buf[2];
+ struct i2c_msg msg = {
+ .addr = slave_addr,
+ .flags = 0,
+ .len = 2,
+ .buf = out_buf,
+ };
+
+ out_buf[0] = addr;
+ out_buf[1] = val;
+
+ if (i2c_transfer(&i2c_bus->adapter, &msg, 1) != 1)
+ DRM_DEBUG("i2c 0x%02x 0x%02x write failed\n",
+ addr, val);
+}
+
+/* ddc router switching */
+void
+amdgpu_i2c_router_select_ddc_port(struct amdgpu_connector *amdgpu_connector)
+{
+ u8 val;
+
+ if (!amdgpu_connector->router.ddc_valid)
+ return;
+
+ if (!amdgpu_connector->router_bus)
+ return;
+
+ amdgpu_i2c_get_byte(amdgpu_connector->router_bus,
+ amdgpu_connector->router.i2c_addr,
+ 0x3, &val);
+ val &= ~amdgpu_connector->router.ddc_mux_control_pin;
+ amdgpu_i2c_put_byte(amdgpu_connector->router_bus,
+ amdgpu_connector->router.i2c_addr,
+ 0x3, val);
+ amdgpu_i2c_get_byte(amdgpu_connector->router_bus,
+ amdgpu_connector->router.i2c_addr,
+ 0x1, &val);
+ val &= ~amdgpu_connector->router.ddc_mux_control_pin;
+ val |= amdgpu_connector->router.ddc_mux_state;
+ amdgpu_i2c_put_byte(amdgpu_connector->router_bus,
+ amdgpu_connector->router.i2c_addr,
+ 0x1, val);
+}
+
+/* clock/data router switching */
+void
+amdgpu_i2c_router_select_cd_port(struct amdgpu_connector *amdgpu_connector)
+{
+ u8 val;
+
+ if (!amdgpu_connector->router.cd_valid)
+ return;
+
+ if (!amdgpu_connector->router_bus)
+ return;
+
+ amdgpu_i2c_get_byte(amdgpu_connector->router_bus,
+ amdgpu_connector->router.i2c_addr,
+ 0x3, &val);
+ val &= ~amdgpu_connector->router.cd_mux_control_pin;
+ amdgpu_i2c_put_byte(amdgpu_connector->router_bus,
+ amdgpu_connector->router.i2c_addr,
+ 0x3, val);
+ amdgpu_i2c_get_byte(amdgpu_connector->router_bus,
+ amdgpu_connector->router.i2c_addr,
+ 0x1, &val);
+ val &= ~amdgpu_connector->router.cd_mux_control_pin;
+ val |= amdgpu_connector->router.cd_mux_state;
+ amdgpu_i2c_put_byte(amdgpu_connector->router_bus,
+ amdgpu_connector->router.i2c_addr,
+ 0x1, val);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h
new file mode 100644
index 000000000000..d81e19b53973
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_I2C_H__
+#define __AMDGPU_I2C_H__
+
+struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev,
+ struct amdgpu_i2c_bus_rec *rec,
+ const char *name);
+void amdgpu_i2c_destroy(struct amdgpu_i2c_chan *i2c);
+void amdgpu_i2c_init(struct amdgpu_device *adev);
+void amdgpu_i2c_fini(struct amdgpu_device *adev);
+void amdgpu_i2c_add(struct amdgpu_device *adev,
+ struct amdgpu_i2c_bus_rec *rec,
+ const char *name);
+struct amdgpu_i2c_chan *
+amdgpu_i2c_lookup(struct amdgpu_device *adev,
+ struct amdgpu_i2c_bus_rec *i2c_bus);
+void
+amdgpu_i2c_router_select_ddc_port(struct amdgpu_connector *amdgpu_connector);
+void
+amdgpu_i2c_router_select_cd_port(struct amdgpu_connector *amdgpu_connector);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
new file mode 100644
index 000000000000..52dff75aac6f
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ * Christian König
+ */
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "atom.h"
+
+/*
+ * IB
+ * IBs (Indirect Buffers) and areas of GPU accessible memory where
+ * commands are stored. You can put a pointer to the IB in the
+ * command ring and the hw will fetch the commands from the IB
+ * and execute them. Generally userspace acceleration drivers
+ * produce command buffers which are send to the kernel and
+ * put in IBs for execution by the requested ring.
+ */
+static int amdgpu_debugfs_sa_init(struct amdgpu_device *adev);
+
+/**
+ * amdgpu_ib_get - request an IB (Indirect Buffer)
+ *
+ * @ring: ring index the IB is associated with
+ * @size: requested IB size
+ * @ib: IB object returned
+ *
+ * Request an IB (all asics). IBs are allocated using the
+ * suballocator.
+ * Returns 0 on success, error on failure.
+ */
+int amdgpu_ib_get(struct amdgpu_ring *ring, struct amdgpu_vm *vm,
+ unsigned size, struct amdgpu_ib *ib)
+{
+ struct amdgpu_device *adev = ring->adev;
+ int r;
+
+ if (size) {
+ r = amdgpu_sa_bo_new(adev, &adev->ring_tmp_bo,
+ &ib->sa_bo, size, 256);
+ if (r) {
+ dev_err(adev->dev, "failed to get a new IB (%d)\n", r);
+ return r;
+ }
+
+ ib->ptr = amdgpu_sa_bo_cpu_addr(ib->sa_bo);
+
+ if (!vm)
+ ib->gpu_addr = amdgpu_sa_bo_gpu_addr(ib->sa_bo);
+ else
+ ib->gpu_addr = 0;
+
+ } else {
+ ib->sa_bo = NULL;
+ ib->ptr = NULL;
+ ib->gpu_addr = 0;
+ }
+
+ amdgpu_sync_create(&ib->sync);
+
+ ib->ring = ring;
+ ib->fence = NULL;
+ ib->user = NULL;
+ ib->vm = vm;
+ ib->gds_base = 0;
+ ib->gds_size = 0;
+ ib->gws_base = 0;
+ ib->gws_size = 0;
+ ib->oa_base = 0;
+ ib->oa_size = 0;
+ ib->flags = 0;
+
+ return 0;
+}
+
+/**
+ * amdgpu_ib_free - free an IB (Indirect Buffer)
+ *
+ * @adev: amdgpu_device pointer
+ * @ib: IB object to free
+ *
+ * Free an IB (all asics).
+ */
+void amdgpu_ib_free(struct amdgpu_device *adev, struct amdgpu_ib *ib)
+{
+ amdgpu_sync_free(adev, &ib->sync, ib->fence);
+ amdgpu_sa_bo_free(adev, &ib->sa_bo, ib->fence);
+ amdgpu_fence_unref(&ib->fence);
+}
+
+/**
+ * amdgpu_ib_schedule - schedule an IB (Indirect Buffer) on the ring
+ *
+ * @adev: amdgpu_device pointer
+ * @num_ibs: number of IBs to schedule
+ * @ibs: IB objects to schedule
+ * @owner: owner for creating the fences
+ *
+ * Schedule an IB on the associated ring (all asics).
+ * Returns 0 on success, error on failure.
+ *
+ * On SI, there are two parallel engines fed from the primary ring,
+ * the CE (Constant Engine) and the DE (Drawing Engine). Since
+ * resource descriptors have moved to memory, the CE allows you to
+ * prime the caches while the DE is updating register state so that
+ * the resource descriptors will be already in cache when the draw is
+ * processed. To accomplish this, the userspace driver submits two
+ * IBs, one for the CE and one for the DE. If there is a CE IB (called
+ * a CONST_IB), it will be put on the ring prior to the DE IB. Prior
+ * to SI there was just a DE IB.
+ */
+int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs,
+ struct amdgpu_ib *ibs, void *owner)
+{
+ struct amdgpu_ib *ib = &ibs[0];
+ struct amdgpu_ring *ring;
+ struct amdgpu_ctx *ctx, *old_ctx;
+ struct amdgpu_vm *vm;
+ unsigned i;
+ int r = 0;
+
+ if (num_ibs == 0)
+ return -EINVAL;
+
+ ring = ibs->ring;
+ ctx = ibs->ctx;
+ vm = ibs->vm;
+
+ if (!ring->ready) {
+ dev_err(adev->dev, "couldn't schedule ib\n");
+ return -EINVAL;
+ }
+
+ r = amdgpu_ring_lock(ring, (256 + AMDGPU_NUM_SYNCS * 8) * num_ibs);
+ if (r) {
+ dev_err(adev->dev, "scheduling IB failed (%d).\n", r);
+ return r;
+ }
+
+ if (vm) {
+ /* grab a vm id if necessary */
+ struct amdgpu_fence *vm_id_fence = NULL;
+ vm_id_fence = amdgpu_vm_grab_id(ibs->ring, ibs->vm);
+ amdgpu_sync_fence(&ibs->sync, vm_id_fence);
+ }
+
+ r = amdgpu_sync_rings(&ibs->sync, ring);
+ if (r) {
+ amdgpu_ring_unlock_undo(ring);
+ dev_err(adev->dev, "failed to sync rings (%d)\n", r);
+ return r;
+ }
+
+ if (vm) {
+ /* do context switch */
+ amdgpu_vm_flush(ring, vm, ib->sync.last_vm_update);
+ }
+
+ if (vm && ring->funcs->emit_gds_switch)
+ amdgpu_ring_emit_gds_switch(ring, ib->vm->ids[ring->idx].id,
+ ib->gds_base, ib->gds_size,
+ ib->gws_base, ib->gws_size,
+ ib->oa_base, ib->oa_size);
+
+ if (ring->funcs->emit_hdp_flush)
+ amdgpu_ring_emit_hdp_flush(ring);
+
+ old_ctx = ring->current_ctx;
+ for (i = 0; i < num_ibs; ++i) {
+ ib = &ibs[i];
+
+ if (ib->ring != ring || ib->ctx != ctx || ib->vm != vm) {
+ ring->current_ctx = old_ctx;
+ amdgpu_ring_unlock_undo(ring);
+ return -EINVAL;
+ }
+ amdgpu_ring_emit_ib(ring, ib);
+ ring->current_ctx = ctx;
+ }
+
+ r = amdgpu_fence_emit(ring, owner, &ib->fence);
+ if (r) {
+ dev_err(adev->dev, "failed to emit fence (%d)\n", r);
+ ring->current_ctx = old_ctx;
+ amdgpu_ring_unlock_undo(ring);
+ return r;
+ }
+
+ /* wrap the last IB with fence */
+ if (ib->user) {
+ uint64_t addr = amdgpu_bo_gpu_offset(ib->user->bo);
+ addr += ib->user->offset;
+ amdgpu_ring_emit_fence(ring, addr, ib->fence->seq,
+ AMDGPU_FENCE_FLAG_64BIT);
+ }
+
+ if (ib->vm)
+ amdgpu_vm_fence(adev, ib->vm, ib->fence);
+
+ amdgpu_ring_unlock_commit(ring);
+ return 0;
+}
+
+/**
+ * amdgpu_ib_pool_init - Init the IB (Indirect Buffer) pool
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Initialize the suballocator to manage a pool of memory
+ * for use as IBs (all asics).
+ * Returns 0 on success, error on failure.
+ */
+int amdgpu_ib_pool_init(struct amdgpu_device *adev)
+{
+ int r;
+
+ if (adev->ib_pool_ready) {
+ return 0;
+ }
+ r = amdgpu_sa_bo_manager_init(adev, &adev->ring_tmp_bo,
+ AMDGPU_IB_POOL_SIZE*64*1024,
+ AMDGPU_GPU_PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_GTT);
+ if (r) {
+ return r;
+ }
+
+ r = amdgpu_sa_bo_manager_start(adev, &adev->ring_tmp_bo);
+ if (r) {
+ return r;
+ }
+
+ adev->ib_pool_ready = true;
+ if (amdgpu_debugfs_sa_init(adev)) {
+ dev_err(adev->dev, "failed to register debugfs file for SA\n");
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_ib_pool_fini - Free the IB (Indirect Buffer) pool
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Tear down the suballocator managing the pool of memory
+ * for use as IBs (all asics).
+ */
+void amdgpu_ib_pool_fini(struct amdgpu_device *adev)
+{
+ if (adev->ib_pool_ready) {
+ amdgpu_sa_bo_manager_suspend(adev, &adev->ring_tmp_bo);
+ amdgpu_sa_bo_manager_fini(adev, &adev->ring_tmp_bo);
+ adev->ib_pool_ready = false;
+ }
+}
+
+/**
+ * amdgpu_ib_ring_tests - test IBs on the rings
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Test an IB (Indirect Buffer) on each ring.
+ * If the test fails, disable the ring.
+ * Returns 0 on success, error if the primary GFX ring
+ * IB test fails.
+ */
+int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
+{
+ unsigned i;
+ int r;
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_ring *ring = adev->rings[i];
+
+ if (!ring || !ring->ready)
+ continue;
+
+ r = amdgpu_ring_test_ib(ring);
+ if (r) {
+ ring->ready = false;
+ adev->needs_reset = false;
+
+ if (ring == &adev->gfx.gfx_ring[0]) {
+ /* oh, oh, that's really bad */
+ DRM_ERROR("amdgpu: failed testing IB on GFX ring (%d).\n", r);
+ adev->accel_working = false;
+ return r;
+
+ } else {
+ /* still not good, but we can live with it */
+ DRM_ERROR("amdgpu: failed testing IB on ring %d (%d).\n", i, r);
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * Debugfs info
+ */
+#if defined(CONFIG_DEBUG_FS)
+
+static int amdgpu_debugfs_sa_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+
+ amdgpu_sa_bo_dump_debug_info(&adev->ring_tmp_bo, m);
+
+ return 0;
+
+}
+
+static struct drm_info_list amdgpu_debugfs_sa_list[] = {
+ {"amdgpu_sa_info", &amdgpu_debugfs_sa_info, 0, NULL},
+};
+
+#endif
+
+static int amdgpu_debugfs_sa_init(struct amdgpu_device *adev)
+{
+#if defined(CONFIG_DEBUG_FS)
+ return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_sa_list, 1);
+#else
+ return 0;
+#endif
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
new file mode 100644
index 000000000000..db5422e65ec5
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <drm/drmP.h>
+#include "amdgpu.h"
+#include "amdgpu_ih.h"
+
+/**
+ * amdgpu_ih_ring_alloc - allocate memory for the IH ring
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Allocate a ring buffer for the interrupt controller.
+ * Returns 0 for success, errors for failure.
+ */
+static int amdgpu_ih_ring_alloc(struct amdgpu_device *adev)
+{
+ int r;
+
+ /* Allocate ring buffer */
+ if (adev->irq.ih.ring_obj == NULL) {
+ r = amdgpu_bo_create(adev, adev->irq.ih.ring_size,
+ PAGE_SIZE, true,
+ AMDGPU_GEM_DOMAIN_GTT, 0,
+ NULL, &adev->irq.ih.ring_obj);
+ if (r) {
+ DRM_ERROR("amdgpu: failed to create ih ring buffer (%d).\n", r);
+ return r;
+ }
+ r = amdgpu_bo_reserve(adev->irq.ih.ring_obj, false);
+ if (unlikely(r != 0))
+ return r;
+ r = amdgpu_bo_pin(adev->irq.ih.ring_obj,
+ AMDGPU_GEM_DOMAIN_GTT,
+ &adev->irq.ih.gpu_addr);
+ if (r) {
+ amdgpu_bo_unreserve(adev->irq.ih.ring_obj);
+ DRM_ERROR("amdgpu: failed to pin ih ring buffer (%d).\n", r);
+ return r;
+ }
+ r = amdgpu_bo_kmap(adev->irq.ih.ring_obj,
+ (void **)&adev->irq.ih.ring);
+ amdgpu_bo_unreserve(adev->irq.ih.ring_obj);
+ if (r) {
+ DRM_ERROR("amdgpu: failed to map ih ring buffer (%d).\n", r);
+ return r;
+ }
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_ih_ring_init - initialize the IH state
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Initializes the IH state and allocates a buffer
+ * for the IH ring buffer.
+ * Returns 0 for success, errors for failure.
+ */
+int amdgpu_ih_ring_init(struct amdgpu_device *adev, unsigned ring_size,
+ bool use_bus_addr)
+{
+ u32 rb_bufsz;
+ int r;
+
+ /* Align ring size */
+ rb_bufsz = order_base_2(ring_size / 4);
+ ring_size = (1 << rb_bufsz) * 4;
+ adev->irq.ih.ring_size = ring_size;
+ adev->irq.ih.ptr_mask = adev->irq.ih.ring_size - 1;
+ adev->irq.ih.rptr = 0;
+ adev->irq.ih.use_bus_addr = use_bus_addr;
+
+ if (adev->irq.ih.use_bus_addr) {
+ if (!adev->irq.ih.ring) {
+ /* add 8 bytes for the rptr/wptr shadows and
+ * add them to the end of the ring allocation.
+ */
+ adev->irq.ih.ring = kzalloc(adev->irq.ih.ring_size + 8, GFP_KERNEL);
+ if (adev->irq.ih.ring == NULL)
+ return -ENOMEM;
+ adev->irq.ih.rb_dma_addr = pci_map_single(adev->pdev,
+ (void *)adev->irq.ih.ring,
+ adev->irq.ih.ring_size,
+ PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(adev->pdev, adev->irq.ih.rb_dma_addr)) {
+ dev_err(&adev->pdev->dev, "Failed to DMA MAP the IH RB page\n");
+ kfree((void *)adev->irq.ih.ring);
+ return -ENOMEM;
+ }
+ adev->irq.ih.wptr_offs = (adev->irq.ih.ring_size / 4) + 0;
+ adev->irq.ih.rptr_offs = (adev->irq.ih.ring_size / 4) + 1;
+ }
+ return 0;
+ } else {
+ r = amdgpu_wb_get(adev, &adev->irq.ih.wptr_offs);
+ if (r) {
+ dev_err(adev->dev, "(%d) ih wptr_offs wb alloc failed\n", r);
+ return r;
+ }
+
+ r = amdgpu_wb_get(adev, &adev->irq.ih.rptr_offs);
+ if (r) {
+ amdgpu_wb_free(adev, adev->irq.ih.wptr_offs);
+ dev_err(adev->dev, "(%d) ih rptr_offs wb alloc failed\n", r);
+ return r;
+ }
+
+ return amdgpu_ih_ring_alloc(adev);
+ }
+}
+
+/**
+ * amdgpu_ih_ring_fini - tear down the IH state
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Tears down the IH state and frees buffer
+ * used for the IH ring buffer.
+ */
+void amdgpu_ih_ring_fini(struct amdgpu_device *adev)
+{
+ int r;
+
+ if (adev->irq.ih.use_bus_addr) {
+ if (adev->irq.ih.ring) {
+ /* add 8 bytes for the rptr/wptr shadows and
+ * add them to the end of the ring allocation.
+ */
+ pci_unmap_single(adev->pdev, adev->irq.ih.rb_dma_addr,
+ adev->irq.ih.ring_size + 8, PCI_DMA_BIDIRECTIONAL);
+ kfree((void *)adev->irq.ih.ring);
+ adev->irq.ih.ring = NULL;
+ }
+ } else {
+ if (adev->irq.ih.ring_obj) {
+ r = amdgpu_bo_reserve(adev->irq.ih.ring_obj, false);
+ if (likely(r == 0)) {
+ amdgpu_bo_kunmap(adev->irq.ih.ring_obj);
+ amdgpu_bo_unpin(adev->irq.ih.ring_obj);
+ amdgpu_bo_unreserve(adev->irq.ih.ring_obj);
+ }
+ amdgpu_bo_unref(&adev->irq.ih.ring_obj);
+ adev->irq.ih.ring = NULL;
+ adev->irq.ih.ring_obj = NULL;
+ }
+ amdgpu_wb_free(adev, adev->irq.ih.wptr_offs);
+ amdgpu_wb_free(adev, adev->irq.ih.rptr_offs);
+ }
+}
+
+/**
+ * amdgpu_ih_process - interrupt handler
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Interrupt hander (VI), walk the IH ring.
+ * Returns irq process return code.
+ */
+int amdgpu_ih_process(struct amdgpu_device *adev)
+{
+ struct amdgpu_iv_entry entry;
+ u32 wptr;
+
+ if (!adev->irq.ih.enabled || adev->shutdown)
+ return IRQ_NONE;
+
+ wptr = amdgpu_ih_get_wptr(adev);
+
+restart_ih:
+ /* is somebody else already processing irqs? */
+ if (atomic_xchg(&adev->irq.ih.lock, 1))
+ return IRQ_NONE;
+
+ DRM_DEBUG("%s: rptr %d, wptr %d\n", __func__, adev->irq.ih.rptr, wptr);
+
+ /* Order reading of wptr vs. reading of IH ring data */
+ rmb();
+
+ while (adev->irq.ih.rptr != wptr) {
+ amdgpu_ih_decode_iv(adev, &entry);
+ adev->irq.ih.rptr &= adev->irq.ih.ptr_mask;
+
+ amdgpu_irq_dispatch(adev, &entry);
+ }
+ amdgpu_ih_set_rptr(adev);
+ atomic_set(&adev->irq.ih.lock, 0);
+
+ /* make sure wptr hasn't changed while processing */
+ wptr = amdgpu_ih_get_wptr(adev);
+ if (wptr != adev->irq.ih.rptr)
+ goto restart_ih;
+
+ return IRQ_HANDLED;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
new file mode 100644
index 000000000000..c62b09e555d6
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_IH_H__
+#define __AMDGPU_IH_H__
+
+struct amdgpu_device;
+
+/*
+ * R6xx+ IH ring
+ */
+struct amdgpu_ih_ring {
+ struct amdgpu_bo *ring_obj;
+ volatile uint32_t *ring;
+ unsigned rptr;
+ unsigned ring_size;
+ uint64_t gpu_addr;
+ uint32_t ptr_mask;
+ atomic_t lock;
+ bool enabled;
+ unsigned wptr_offs;
+ unsigned rptr_offs;
+ u32 doorbell_index;
+ bool use_doorbell;
+ bool use_bus_addr;
+ dma_addr_t rb_dma_addr; /* only used when use_bus_addr = true */
+};
+
+struct amdgpu_iv_entry {
+ unsigned src_id;
+ unsigned src_data;
+ unsigned ring_id;
+ unsigned vm_id;
+ unsigned pas_id;
+};
+
+int amdgpu_ih_ring_init(struct amdgpu_device *adev, unsigned ring_size,
+ bool use_bus_addr);
+void amdgpu_ih_ring_fini(struct amdgpu_device *adev);
+int amdgpu_ih_process(struct amdgpu_device *adev);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ioc32.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ioc32.c
new file mode 100644
index 000000000000..26482914dc4b
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ioc32.c
@@ -0,0 +1,47 @@
+/**
+ * \file amdgpu_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the AMDGPU DRM.
+ *
+ * \author Paul Mackerras <paulus@samba.org>
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * 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
+ * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION 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/compat.h>
+
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu_drv.h"
+
+long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ unsigned int nr = DRM_IOCTL_NR(cmd);
+ int ret;
+
+ if (nr < DRM_COMMAND_BASE)
+ return drm_compat_ioctl(filp, cmd, arg);
+
+ ret = amdgpu_drm_ioctl(filp, cmd, arg);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
new file mode 100644
index 000000000000..b4d36f0f2153
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "amdgpu_ih.h"
+#include "atom.h"
+#include "amdgpu_connectors.h"
+
+#include <linux/pm_runtime.h>
+
+#define AMDGPU_WAIT_IDLE_TIMEOUT 200
+
+/*
+ * Handle hotplug events outside the interrupt handler proper.
+ */
+/**
+ * amdgpu_hotplug_work_func - display hotplug work handler
+ *
+ * @work: work struct
+ *
+ * This is the hot plug event work handler (all asics).
+ * The work gets scheduled from the irq handler if there
+ * was a hot plug interrupt. It walks the connector table
+ * and calls the hotplug handler for each one, then sends
+ * a drm hotplug event to alert userspace.
+ */
+static void amdgpu_hotplug_work_func(struct work_struct *work)
+{
+ struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
+ hotplug_work);
+ struct drm_device *dev = adev->ddev;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct drm_connector *connector;
+
+ mutex_lock(&mode_config->mutex);
+ if (mode_config->num_connector) {
+ list_for_each_entry(connector, &mode_config->connector_list, head)
+ amdgpu_connector_hotplug(connector);
+ }
+ mutex_unlock(&mode_config->mutex);
+ /* Just fire off a uevent and let userspace tell us what to do */
+ drm_helper_hpd_irq_event(dev);
+}
+
+/**
+ * amdgpu_irq_reset_work_func - execute gpu reset
+ *
+ * @work: work struct
+ *
+ * Execute scheduled gpu reset (cayman+).
+ * This function is called when the irq handler
+ * thinks we need a gpu reset.
+ */
+static void amdgpu_irq_reset_work_func(struct work_struct *work)
+{
+ struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
+ reset_work);
+
+ amdgpu_gpu_reset(adev);
+}
+
+/* Disable *all* interrupts */
+static void amdgpu_irq_disable_all(struct amdgpu_device *adev)
+{
+ unsigned long irqflags;
+ unsigned i, j;
+ int r;
+
+ spin_lock_irqsave(&adev->irq.lock, irqflags);
+ for (i = 0; i < AMDGPU_MAX_IRQ_SRC_ID; ++i) {
+ struct amdgpu_irq_src *src = adev->irq.sources[i];
+
+ if (!src || !src->funcs->set || !src->num_types)
+ continue;
+
+ for (j = 0; j < src->num_types; ++j) {
+ atomic_set(&src->enabled_types[j], 0);
+ r = src->funcs->set(adev, src, j,
+ AMDGPU_IRQ_STATE_DISABLE);
+ if (r)
+ DRM_ERROR("error disabling interrupt (%d)\n",
+ r);
+ }
+ }
+ spin_unlock_irqrestore(&adev->irq.lock, irqflags);
+}
+
+/**
+ * amdgpu_irq_preinstall - drm irq preinstall callback
+ *
+ * @dev: drm dev pointer
+ *
+ * Gets the hw ready to enable irqs (all asics).
+ * This function disables all interrupt sources on the GPU.
+ */
+void amdgpu_irq_preinstall(struct drm_device *dev)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+
+ /* Disable *all* interrupts */
+ amdgpu_irq_disable_all(adev);
+ /* Clear bits */
+ amdgpu_ih_process(adev);
+}
+
+/**
+ * amdgpu_irq_postinstall - drm irq preinstall callback
+ *
+ * @dev: drm dev pointer
+ *
+ * Handles stuff to be done after enabling irqs (all asics).
+ * Returns 0 on success.
+ */
+int amdgpu_irq_postinstall(struct drm_device *dev)
+{
+ dev->max_vblank_count = 0x001fffff;
+ return 0;
+}
+
+/**
+ * amdgpu_irq_uninstall - drm irq uninstall callback
+ *
+ * @dev: drm dev pointer
+ *
+ * This function disables all interrupt sources on the GPU (all asics).
+ */
+void amdgpu_irq_uninstall(struct drm_device *dev)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+
+ if (adev == NULL) {
+ return;
+ }
+ amdgpu_irq_disable_all(adev);
+}
+
+/**
+ * amdgpu_irq_handler - irq handler
+ *
+ * @int irq, void *arg: args
+ *
+ * This is the irq handler for the amdgpu driver (all asics).
+ */
+irqreturn_t amdgpu_irq_handler(int irq, void *arg)
+{
+ struct drm_device *dev = (struct drm_device *) arg;
+ struct amdgpu_device *adev = dev->dev_private;
+ irqreturn_t ret;
+
+ ret = amdgpu_ih_process(adev);
+ if (ret == IRQ_HANDLED)
+ pm_runtime_mark_last_busy(dev->dev);
+ return ret;
+}
+
+/**
+ * amdgpu_msi_ok - asic specific msi checks
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Handles asic specific MSI checks to determine if
+ * MSIs should be enabled on a particular chip (all asics).
+ * Returns true if MSIs should be enabled, false if MSIs
+ * should not be enabled.
+ */
+static bool amdgpu_msi_ok(struct amdgpu_device *adev)
+{
+ /* force MSI on */
+ if (amdgpu_msi == 1)
+ return true;
+ else if (amdgpu_msi == 0)
+ return false;
+
+ return true;
+}
+
+/**
+ * amdgpu_irq_init - init driver interrupt info
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Sets up the work irq handlers, vblank init, MSIs, etc. (all asics).
+ * Returns 0 for success, error for failure.
+ */
+int amdgpu_irq_init(struct amdgpu_device *adev)
+{
+ int r = 0;
+
+ spin_lock_init(&adev->irq.lock);
+ r = drm_vblank_init(adev->ddev, adev->mode_info.num_crtc);
+ if (r) {
+ return r;
+ }
+ /* enable msi */
+ adev->irq.msi_enabled = false;
+
+ if (amdgpu_msi_ok(adev)) {
+ int ret = pci_enable_msi(adev->pdev);
+ if (!ret) {
+ adev->irq.msi_enabled = true;
+ dev_info(adev->dev, "amdgpu: using MSI.\n");
+ }
+ }
+
+ INIT_WORK(&adev->hotplug_work, amdgpu_hotplug_work_func);
+ INIT_WORK(&adev->reset_work, amdgpu_irq_reset_work_func);
+
+ adev->irq.installed = true;
+ r = drm_irq_install(adev->ddev, adev->ddev->pdev->irq);
+ if (r) {
+ adev->irq.installed = false;
+ flush_work(&adev->hotplug_work);
+ return r;
+ }
+
+ DRM_INFO("amdgpu: irq initialized.\n");
+ return 0;
+}
+
+/**
+ * amdgpu_irq_fini - tear down driver interrupt info
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Tears down the work irq handlers, vblank handlers, MSIs, etc. (all asics).
+ */
+void amdgpu_irq_fini(struct amdgpu_device *adev)
+{
+ unsigned i;
+
+ drm_vblank_cleanup(adev->ddev);
+ if (adev->irq.installed) {
+ drm_irq_uninstall(adev->ddev);
+ adev->irq.installed = false;
+ if (adev->irq.msi_enabled)
+ pci_disable_msi(adev->pdev);
+ flush_work(&adev->hotplug_work);
+ }
+
+ for (i = 0; i < AMDGPU_MAX_IRQ_SRC_ID; ++i) {
+ struct amdgpu_irq_src *src = adev->irq.sources[i];
+
+ if (!src)
+ continue;
+
+ kfree(src->enabled_types);
+ src->enabled_types = NULL;
+ }
+}
+
+/**
+ * amdgpu_irq_add_id - register irq source
+ *
+ * @adev: amdgpu device pointer
+ * @src_id: source id for this source
+ * @source: irq source
+ *
+ */
+int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
+ struct amdgpu_irq_src *source)
+{
+ if (src_id >= AMDGPU_MAX_IRQ_SRC_ID)
+ return -EINVAL;
+
+ if (adev->irq.sources[src_id] != NULL)
+ return -EINVAL;
+
+ if (!source->funcs)
+ return -EINVAL;
+
+ if (source->num_types && !source->enabled_types) {
+ atomic_t *types;
+
+ types = kcalloc(source->num_types, sizeof(atomic_t),
+ GFP_KERNEL);
+ if (!types)
+ return -ENOMEM;
+
+ source->enabled_types = types;
+ }
+
+ adev->irq.sources[src_id] = source;
+ return 0;
+}
+
+/**
+ * amdgpu_irq_dispatch - dispatch irq to IP blocks
+ *
+ * @adev: amdgpu device pointer
+ * @entry: interrupt vector
+ *
+ * Dispatches the irq to the different IP blocks
+ */
+void amdgpu_irq_dispatch(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry)
+{
+ unsigned src_id = entry->src_id;
+ struct amdgpu_irq_src *src;
+ int r;
+
+ if (src_id >= AMDGPU_MAX_IRQ_SRC_ID) {
+ DRM_DEBUG("Invalid src_id in IV: %d\n", src_id);
+ return;
+ }
+
+ 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);
+}
+
+/**
+ * amdgpu_irq_update - update hw interrupt state
+ *
+ * @adev: amdgpu device pointer
+ * @src: interrupt src you want to enable
+ * @type: type of interrupt you want to update
+ *
+ * Updates the interrupt state for a specific src (all asics).
+ */
+int amdgpu_irq_update(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *src, unsigned type)
+{
+ unsigned long irqflags;
+ enum amdgpu_interrupt_state state;
+ int r;
+
+ spin_lock_irqsave(&adev->irq.lock, irqflags);
+
+ /* we need to determine after taking the lock, otherwise
+ we might disable just enabled interrupts again */
+ if (amdgpu_irq_enabled(adev, src, type))
+ state = AMDGPU_IRQ_STATE_ENABLE;
+ else
+ state = AMDGPU_IRQ_STATE_DISABLE;
+
+ r = src->funcs->set(adev, src, type, state);
+ spin_unlock_irqrestore(&adev->irq.lock, irqflags);
+ return r;
+}
+
+/**
+ * amdgpu_irq_get - enable interrupt
+ *
+ * @adev: amdgpu device pointer
+ * @src: interrupt src you want to enable
+ * @type: type of interrupt you want to enable
+ *
+ * Enables the interrupt type for a specific src (all asics).
+ */
+int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
+ unsigned type)
+{
+ if (!adev->ddev->irq_enabled)
+ return -ENOENT;
+
+ if (type >= src->num_types)
+ return -EINVAL;
+
+ if (!src->enabled_types || !src->funcs->set)
+ return -EINVAL;
+
+ if (atomic_inc_return(&src->enabled_types[type]) == 1)
+ return amdgpu_irq_update(adev, src, type);
+
+ return 0;
+}
+
+bool amdgpu_irq_get_delayed(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *src,
+ unsigned type)
+{
+ if ((type >= src->num_types) || !src->enabled_types)
+ return false;
+ return atomic_inc_return(&src->enabled_types[type]) == 1;
+}
+
+/**
+ * amdgpu_irq_put - disable interrupt
+ *
+ * @adev: amdgpu device pointer
+ * @src: interrupt src you want to disable
+ * @type: type of interrupt you want to disable
+ *
+ * Disables the interrupt type for a specific src (all asics).
+ */
+int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
+ unsigned type)
+{
+ if (!adev->ddev->irq_enabled)
+ return -ENOENT;
+
+ if (type >= src->num_types)
+ return -EINVAL;
+
+ if (!src->enabled_types || !src->funcs->set)
+ return -EINVAL;
+
+ if (atomic_dec_and_test(&src->enabled_types[type]))
+ return amdgpu_irq_update(adev, src, type);
+
+ return 0;
+}
+
+/**
+ * amdgpu_irq_enabled - test if irq is enabled or not
+ *
+ * @adev: amdgpu device pointer
+ * @idx: interrupt src you want to test
+ *
+ * Tests if the given interrupt source is enabled or not
+ */
+bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
+ unsigned type)
+{
+ if (!adev->ddev->irq_enabled)
+ return false;
+
+ if (type >= src->num_types)
+ return false;
+
+ if (!src->enabled_types || !src->funcs->set)
+ return false;
+
+ return !!atomic_read(&src->enabled_types[type]);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
new file mode 100644
index 000000000000..8299795f2b2d
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_IRQ_H__
+#define __AMDGPU_IRQ_H__
+
+#include "amdgpu_ih.h"
+
+#define AMDGPU_MAX_IRQ_SRC_ID 0x100
+
+struct amdgpu_device;
+struct amdgpu_iv_entry;
+
+enum amdgpu_interrupt_state {
+ AMDGPU_IRQ_STATE_DISABLE,
+ AMDGPU_IRQ_STATE_ENABLE,
+};
+
+struct amdgpu_irq_src {
+ unsigned num_types;
+ atomic_t *enabled_types;
+ const struct amdgpu_irq_src_funcs *funcs;
+};
+
+/* provided by interrupt generating IP blocks */
+struct amdgpu_irq_src_funcs {
+ int (*set)(struct amdgpu_device *adev, struct amdgpu_irq_src *source,
+ unsigned type, enum amdgpu_interrupt_state state);
+
+ int (*process)(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry);
+};
+
+struct amdgpu_irq {
+ bool installed;
+ spinlock_t lock;
+ /* interrupt sources */
+ struct amdgpu_irq_src *sources[AMDGPU_MAX_IRQ_SRC_ID];
+
+ /* status, etc. */
+ bool msi_enabled; /* msi enabled */
+
+ /* interrupt ring */
+ struct amdgpu_ih_ring ih;
+ const struct amdgpu_ih_funcs *ih_funcs;
+};
+
+void amdgpu_irq_preinstall(struct drm_device *dev);
+int amdgpu_irq_postinstall(struct drm_device *dev);
+void amdgpu_irq_uninstall(struct drm_device *dev);
+irqreturn_t amdgpu_irq_handler(int irq, void *arg);
+
+int amdgpu_irq_init(struct amdgpu_device *adev);
+void amdgpu_irq_fini(struct amdgpu_device *adev);
+int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
+ struct amdgpu_irq_src *source);
+void amdgpu_irq_dispatch(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry);
+int amdgpu_irq_update(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
+ unsigned type);
+int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
+ unsigned type);
+bool amdgpu_irq_get_delayed(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *src,
+ unsigned type);
+int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
+ unsigned type);
+bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
+ unsigned type);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
new file mode 100644
index 000000000000..5533434c7a8f
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#include <drm/drmP.h>
+#include "amdgpu.h"
+#include <drm/amdgpu_drm.h>
+#include "amdgpu_uvd.h"
+#include "amdgpu_vce.h"
+
+#include <linux/vga_switcheroo.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+#if defined(CONFIG_VGA_SWITCHEROO)
+bool amdgpu_has_atpx(void);
+#else
+static inline bool amdgpu_has_atpx(void) { return false; }
+#endif
+
+/**
+ * amdgpu_driver_unload_kms - Main unload function for KMS.
+ *
+ * @dev: drm dev pointer
+ *
+ * This is the main unload function for KMS (all asics).
+ * Returns 0 on success.
+ */
+int amdgpu_driver_unload_kms(struct drm_device *dev)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+
+ if (adev == NULL)
+ return 0;
+
+ if (adev->rmmio == NULL)
+ goto done_free;
+
+ pm_runtime_get_sync(dev->dev);
+
+ amdgpu_acpi_fini(adev);
+
+ amdgpu_device_fini(adev);
+
+done_free:
+ kfree(adev);
+ dev->dev_private = NULL;
+ return 0;
+}
+
+/**
+ * amdgpu_driver_load_kms - Main load function for KMS.
+ *
+ * @dev: drm dev pointer
+ * @flags: device flags
+ *
+ * This is the main load function for KMS (all asics).
+ * Returns 0 on success, error on failure.
+ */
+int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags)
+{
+ struct amdgpu_device *adev;
+ int r, acpi_status;
+
+ adev = kzalloc(sizeof(struct amdgpu_device), GFP_KERNEL);
+ if (adev == NULL) {
+ return -ENOMEM;
+ }
+ dev->dev_private = (void *)adev;
+
+ if ((amdgpu_runtime_pm != 0) &&
+ amdgpu_has_atpx() &&
+ ((flags & AMDGPU_IS_APU) == 0))
+ flags |= AMDGPU_IS_PX;
+
+ /* amdgpu_device_init should report only fatal error
+ * like memory allocation failure or iomapping failure,
+ * or memory manager initialization failure, it must
+ * properly initialize the GPU MC controller and permit
+ * VRAM allocation
+ */
+ r = amdgpu_device_init(adev, dev, dev->pdev, flags);
+ if (r) {
+ dev_err(&dev->pdev->dev, "Fatal error during GPU init\n");
+ goto out;
+ }
+
+ /* Call ACPI methods: require modeset init
+ * but failure is not fatal
+ */
+ if (!r) {
+ acpi_status = amdgpu_acpi_init(adev);
+ if (acpi_status)
+ dev_dbg(&dev->pdev->dev,
+ "Error during ACPI methods call\n");
+ }
+
+ if (amdgpu_device_is_px(dev)) {
+ pm_runtime_use_autosuspend(dev->dev);
+ pm_runtime_set_autosuspend_delay(dev->dev, 5000);
+ pm_runtime_set_active(dev->dev);
+ pm_runtime_allow(dev->dev);
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
+ }
+
+out:
+ if (r)
+ amdgpu_driver_unload_kms(dev);
+
+
+ return r;
+}
+
+/*
+ * Userspace get information ioctl
+ */
+/**
+ * amdgpu_info_ioctl - answer a device specific request.
+ *
+ * @adev: amdgpu device pointer
+ * @data: request object
+ * @filp: drm filp
+ *
+ * This function is used to pass device specific parameters to the userspace
+ * drivers. Examples include: pci device id, pipeline parms, tiling params,
+ * etc. (all asics).
+ * Returns 0 on success, -EINVAL on failure.
+ */
+static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ struct drm_amdgpu_info *info = data;
+ struct amdgpu_mode_info *minfo = &adev->mode_info;
+ void __user *out = (void __user *)(long)info->return_pointer;
+ uint32_t size = info->return_size;
+ struct drm_crtc *crtc;
+ uint32_t ui32 = 0;
+ uint64_t ui64 = 0;
+ int i, found;
+
+ if (!info->return_size || !info->return_pointer)
+ return -EINVAL;
+
+ switch (info->query) {
+ case AMDGPU_INFO_ACCEL_WORKING:
+ ui32 = adev->accel_working;
+ return copy_to_user(out, &ui32, min(size, 4u)) ? -EFAULT : 0;
+ case AMDGPU_INFO_CRTC_FROM_ID:
+ for (i = 0, found = 0; i < adev->mode_info.num_crtc; i++) {
+ crtc = (struct drm_crtc *)minfo->crtcs[i];
+ if (crtc && crtc->base.id == info->mode_crtc.id) {
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ ui32 = amdgpu_crtc->crtc_id;
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ DRM_DEBUG_KMS("unknown crtc id %d\n", info->mode_crtc.id);
+ return -EINVAL;
+ }
+ return copy_to_user(out, &ui32, min(size, 4u)) ? -EFAULT : 0;
+ case AMDGPU_INFO_HW_IP_INFO: {
+ struct drm_amdgpu_info_hw_ip ip = {};
+ enum amd_ip_block_type type;
+ uint32_t ring_mask = 0;
+ uint32_t ib_start_alignment = 0;
+ uint32_t ib_size_alignment = 0;
+
+ if (info->query_hw_ip.ip_instance >= AMDGPU_HW_IP_INSTANCE_MAX_COUNT)
+ return -EINVAL;
+
+ switch (info->query_hw_ip.type) {
+ case AMDGPU_HW_IP_GFX:
+ type = AMD_IP_BLOCK_TYPE_GFX;
+ for (i = 0; i < adev->gfx.num_gfx_rings; i++)
+ ring_mask |= ((adev->gfx.gfx_ring[i].ready ? 1 : 0) << i);
+ ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
+ ib_size_alignment = 8;
+ break;
+ case AMDGPU_HW_IP_COMPUTE:
+ type = AMD_IP_BLOCK_TYPE_GFX;
+ for (i = 0; i < adev->gfx.num_compute_rings; i++)
+ ring_mask |= ((adev->gfx.compute_ring[i].ready ? 1 : 0) << i);
+ ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
+ ib_size_alignment = 8;
+ break;
+ case AMDGPU_HW_IP_DMA:
+ type = AMD_IP_BLOCK_TYPE_SDMA;
+ ring_mask = adev->sdma[0].ring.ready ? 1 : 0;
+ ring_mask |= ((adev->sdma[1].ring.ready ? 1 : 0) << 1);
+ ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
+ ib_size_alignment = 1;
+ break;
+ case AMDGPU_HW_IP_UVD:
+ type = AMD_IP_BLOCK_TYPE_UVD;
+ ring_mask = adev->uvd.ring.ready ? 1 : 0;
+ ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
+ ib_size_alignment = 8;
+ break;
+ case AMDGPU_HW_IP_VCE:
+ type = AMD_IP_BLOCK_TYPE_VCE;
+ for (i = 0; i < AMDGPU_MAX_VCE_RINGS; i++)
+ ring_mask |= ((adev->vce.ring[i].ready ? 1 : 0) << i);
+ ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
+ ib_size_alignment = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0; i < adev->num_ip_blocks; i++) {
+ if (adev->ip_blocks[i].type == type &&
+ adev->ip_block_enabled[i]) {
+ ip.hw_ip_version_major = adev->ip_blocks[i].major;
+ ip.hw_ip_version_minor = adev->ip_blocks[i].minor;
+ ip.capabilities_flags = 0;
+ ip.available_rings = ring_mask;
+ ip.ib_start_alignment = ib_start_alignment;
+ ip.ib_size_alignment = ib_size_alignment;
+ break;
+ }
+ }
+ return copy_to_user(out, &ip,
+ min((size_t)size, sizeof(ip))) ? -EFAULT : 0;
+ }
+ case AMDGPU_INFO_HW_IP_COUNT: {
+ enum amd_ip_block_type type;
+ uint32_t count = 0;
+
+ switch (info->query_hw_ip.type) {
+ case AMDGPU_HW_IP_GFX:
+ type = AMD_IP_BLOCK_TYPE_GFX;
+ break;
+ case AMDGPU_HW_IP_COMPUTE:
+ type = AMD_IP_BLOCK_TYPE_GFX;
+ break;
+ case AMDGPU_HW_IP_DMA:
+ type = AMD_IP_BLOCK_TYPE_SDMA;
+ break;
+ case AMDGPU_HW_IP_UVD:
+ type = AMD_IP_BLOCK_TYPE_UVD;
+ break;
+ case AMDGPU_HW_IP_VCE:
+ type = AMD_IP_BLOCK_TYPE_VCE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0; i < adev->num_ip_blocks; i++)
+ if (adev->ip_blocks[i].type == type &&
+ adev->ip_block_enabled[i] &&
+ count < AMDGPU_HW_IP_INSTANCE_MAX_COUNT)
+ count++;
+
+ return copy_to_user(out, &count, min(size, 4u)) ? -EFAULT : 0;
+ }
+ case AMDGPU_INFO_TIMESTAMP:
+ ui64 = amdgpu_asic_get_gpu_clock_counter(adev);
+ return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
+ case AMDGPU_INFO_FW_VERSION: {
+ struct drm_amdgpu_info_firmware fw_info;
+
+ /* We only support one instance of each IP block right now. */
+ if (info->query_fw.ip_instance != 0)
+ return -EINVAL;
+
+ switch (info->query_fw.fw_type) {
+ case AMDGPU_INFO_FW_VCE:
+ fw_info.ver = adev->vce.fw_version;
+ fw_info.feature = adev->vce.fb_version;
+ break;
+ case AMDGPU_INFO_FW_UVD:
+ fw_info.ver = 0;
+ fw_info.feature = 0;
+ break;
+ case AMDGPU_INFO_FW_GMC:
+ fw_info.ver = adev->mc.fw_version;
+ fw_info.feature = 0;
+ break;
+ case AMDGPU_INFO_FW_GFX_ME:
+ fw_info.ver = adev->gfx.me_fw_version;
+ fw_info.feature = adev->gfx.me_feature_version;
+ break;
+ case AMDGPU_INFO_FW_GFX_PFP:
+ fw_info.ver = adev->gfx.pfp_fw_version;
+ fw_info.feature = adev->gfx.pfp_feature_version;
+ break;
+ case AMDGPU_INFO_FW_GFX_CE:
+ fw_info.ver = adev->gfx.ce_fw_version;
+ fw_info.feature = adev->gfx.ce_feature_version;
+ break;
+ case AMDGPU_INFO_FW_GFX_RLC:
+ fw_info.ver = adev->gfx.rlc_fw_version;
+ fw_info.feature = 0;
+ break;
+ case AMDGPU_INFO_FW_GFX_MEC:
+ if (info->query_fw.index == 0)
+ fw_info.ver = adev->gfx.mec_fw_version;
+ else if (info->query_fw.index == 1)
+ fw_info.ver = adev->gfx.mec2_fw_version;
+ else
+ return -EINVAL;
+ fw_info.feature = 0;
+ break;
+ case AMDGPU_INFO_FW_SMC:
+ fw_info.ver = adev->pm.fw_version;
+ fw_info.feature = 0;
+ break;
+ case AMDGPU_INFO_FW_SDMA:
+ if (info->query_fw.index >= 2)
+ return -EINVAL;
+ fw_info.ver = adev->sdma[info->query_fw.index].fw_version;
+ fw_info.feature = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return copy_to_user(out, &fw_info,
+ min((size_t)size, sizeof(fw_info))) ? -EFAULT : 0;
+ }
+ case AMDGPU_INFO_NUM_BYTES_MOVED:
+ ui64 = atomic64_read(&adev->num_bytes_moved);
+ return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
+ case AMDGPU_INFO_VRAM_USAGE:
+ ui64 = atomic64_read(&adev->vram_usage);
+ return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
+ case AMDGPU_INFO_VIS_VRAM_USAGE:
+ ui64 = atomic64_read(&adev->vram_vis_usage);
+ return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
+ case AMDGPU_INFO_GTT_USAGE:
+ ui64 = atomic64_read(&adev->gtt_usage);
+ return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0;
+ case AMDGPU_INFO_GDS_CONFIG: {
+ struct drm_amdgpu_info_gds gds_info;
+
+ memset(&gds_info, 0, sizeof(gds_info));
+ gds_info.gds_gfx_partition_size = adev->gds.mem.gfx_partition_size >> AMDGPU_GDS_SHIFT;
+ gds_info.compute_partition_size = adev->gds.mem.cs_partition_size >> AMDGPU_GDS_SHIFT;
+ gds_info.gds_total_size = adev->gds.mem.total_size >> AMDGPU_GDS_SHIFT;
+ gds_info.gws_per_gfx_partition = adev->gds.gws.gfx_partition_size >> AMDGPU_GWS_SHIFT;
+ gds_info.gws_per_compute_partition = adev->gds.gws.cs_partition_size >> AMDGPU_GWS_SHIFT;
+ gds_info.oa_per_gfx_partition = adev->gds.oa.gfx_partition_size >> AMDGPU_OA_SHIFT;
+ gds_info.oa_per_compute_partition = adev->gds.oa.cs_partition_size >> AMDGPU_OA_SHIFT;
+ return copy_to_user(out, &gds_info,
+ min((size_t)size, sizeof(gds_info))) ? -EFAULT : 0;
+ }
+ case AMDGPU_INFO_VRAM_GTT: {
+ struct drm_amdgpu_info_vram_gtt vram_gtt;
+
+ vram_gtt.vram_size = adev->mc.real_vram_size;
+ vram_gtt.vram_cpu_accessible_size = adev->mc.visible_vram_size;
+ vram_gtt.vram_cpu_accessible_size -= adev->vram_pin_size;
+ vram_gtt.gtt_size = adev->mc.gtt_size;
+ vram_gtt.gtt_size -= adev->gart_pin_size;
+ return copy_to_user(out, &vram_gtt,
+ min((size_t)size, sizeof(vram_gtt))) ? -EFAULT : 0;
+ }
+ case AMDGPU_INFO_READ_MMR_REG: {
+ unsigned n, alloc_size = info->read_mmr_reg.count * 4;
+ uint32_t *regs;
+ unsigned se_num = (info->read_mmr_reg.instance >>
+ AMDGPU_INFO_MMR_SE_INDEX_SHIFT) &
+ AMDGPU_INFO_MMR_SE_INDEX_MASK;
+ unsigned sh_num = (info->read_mmr_reg.instance >>
+ AMDGPU_INFO_MMR_SH_INDEX_SHIFT) &
+ AMDGPU_INFO_MMR_SH_INDEX_MASK;
+
+ /* set full masks if the userspace set all bits
+ * in the bitfields */
+ if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK)
+ se_num = 0xffffffff;
+ if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK)
+ sh_num = 0xffffffff;
+
+ regs = kmalloc(alloc_size, GFP_KERNEL);
+ if (!regs)
+ return -ENOMEM;
+
+ for (i = 0; i < info->read_mmr_reg.count; i++)
+ if (amdgpu_asic_read_register(adev, se_num, sh_num,
+ info->read_mmr_reg.dword_offset + i,
+ &regs[i])) {
+ DRM_DEBUG_KMS("unallowed offset %#x\n",
+ info->read_mmr_reg.dword_offset + i);
+ kfree(regs);
+ return -EFAULT;
+ }
+ n = copy_to_user(out, regs, min(size, alloc_size));
+ kfree(regs);
+ return n ? -EFAULT : 0;
+ }
+ case AMDGPU_INFO_DEV_INFO: {
+ struct drm_amdgpu_info_device dev_info;
+ struct amdgpu_cu_info cu_info;
+
+ dev_info.device_id = dev->pdev->device;
+ dev_info.chip_rev = adev->rev_id;
+ dev_info.external_rev = adev->external_rev_id;
+ dev_info.pci_rev = dev->pdev->revision;
+ dev_info.family = adev->family;
+ dev_info.num_shader_engines = adev->gfx.config.max_shader_engines;
+ dev_info.num_shader_arrays_per_engine = adev->gfx.config.max_sh_per_se;
+ /* return all clocks in KHz */
+ dev_info.gpu_counter_freq = amdgpu_asic_get_xclk(adev) * 10;
+ if (adev->pm.dpm_enabled) {
+ dev_info.max_engine_clock =
+ adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk * 10;
+ dev_info.max_memory_clock =
+ adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk * 10;
+ } else {
+ dev_info.max_engine_clock = adev->pm.default_sclk * 10;
+ dev_info.max_memory_clock = adev->pm.default_mclk * 10;
+ }
+ dev_info.enabled_rb_pipes_mask = adev->gfx.config.backend_enable_mask;
+ dev_info.num_rb_pipes = adev->gfx.config.max_backends_per_se *
+ adev->gfx.config.max_shader_engines;
+ dev_info.num_hw_gfx_contexts = adev->gfx.config.max_hw_contexts;
+ dev_info._pad = 0;
+ dev_info.ids_flags = 0;
+ if (adev->flags & AMDGPU_IS_APU)
+ dev_info.ids_flags |= AMDGPU_IDS_FLAGS_FUSION;
+ dev_info.virtual_address_offset = AMDGPU_VA_RESERVED_SIZE;
+ dev_info.virtual_address_max = (uint64_t)adev->vm_manager.max_pfn * AMDGPU_GPU_PAGE_SIZE;
+ dev_info.virtual_address_alignment = max(PAGE_SIZE, 0x10000UL);
+ dev_info.pte_fragment_size = (1 << AMDGPU_LOG2_PAGES_PER_FRAG) *
+ AMDGPU_GPU_PAGE_SIZE;
+ dev_info.gart_page_size = AMDGPU_GPU_PAGE_SIZE;
+
+ amdgpu_asic_get_cu_info(adev, &cu_info);
+ dev_info.cu_active_number = cu_info.number;
+ dev_info.cu_ao_mask = cu_info.ao_cu_mask;
+ dev_info.ce_ram_size = adev->gfx.ce_ram_size;
+ memcpy(&dev_info.cu_bitmap[0], &cu_info.bitmap[0], sizeof(cu_info.bitmap));
+ dev_info.vram_type = adev->mc.vram_type;
+ dev_info.vram_bit_width = adev->mc.vram_width;
+
+ return copy_to_user(out, &dev_info,
+ min((size_t)size, sizeof(dev_info))) ? -EFAULT : 0;
+ }
+ default:
+ DRM_DEBUG_KMS("Invalid request %d\n", info->query);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+/*
+ * Outdated mess for old drm with Xorg being in charge (void function now).
+ */
+/**
+ * amdgpu_driver_firstopen_kms - drm callback for last close
+ *
+ * @dev: drm dev pointer
+ *
+ * Switch vga switcheroo state after last close (all asics).
+ */
+void amdgpu_driver_lastclose_kms(struct drm_device *dev)
+{
+ vga_switcheroo_process_delayed_switch();
+}
+
+/**
+ * amdgpu_driver_open_kms - drm callback for open
+ *
+ * @dev: drm dev pointer
+ * @file_priv: drm file
+ *
+ * On device open, init vm on cayman+ (all asics).
+ * Returns 0 on success, error on failure.
+ */
+int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_fpriv *fpriv;
+ int r;
+
+ file_priv->driver_priv = NULL;
+
+ r = pm_runtime_get_sync(dev->dev);
+ if (r < 0)
+ return r;
+
+ fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
+ if (unlikely(!fpriv))
+ return -ENOMEM;
+
+ r = amdgpu_vm_init(adev, &fpriv->vm);
+ if (r)
+ goto error_free;
+
+ mutex_init(&fpriv->bo_list_lock);
+ idr_init(&fpriv->bo_list_handles);
+
+ /* init context manager */
+ mutex_init(&fpriv->ctx_mgr.lock);
+ idr_init(&fpriv->ctx_mgr.ctx_handles);
+ fpriv->ctx_mgr.adev = adev;
+
+ file_priv->driver_priv = fpriv;
+
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
+ return 0;
+
+error_free:
+ kfree(fpriv);
+
+ return r;
+}
+
+/**
+ * amdgpu_driver_postclose_kms - drm callback for post close
+ *
+ * @dev: drm dev pointer
+ * @file_priv: drm file
+ *
+ * On device post close, tear down vm on cayman+ (all asics).
+ */
+void amdgpu_driver_postclose_kms(struct drm_device *dev,
+ struct drm_file *file_priv)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
+ struct amdgpu_bo_list *list;
+ int handle;
+
+ if (!fpriv)
+ return;
+
+ amdgpu_vm_fini(adev, &fpriv->vm);
+
+ idr_for_each_entry(&fpriv->bo_list_handles, list, handle)
+ amdgpu_bo_list_free(list);
+
+ idr_destroy(&fpriv->bo_list_handles);
+ mutex_destroy(&fpriv->bo_list_lock);
+
+ /* release context */
+ amdgpu_ctx_fini(fpriv);
+
+ kfree(fpriv);
+ file_priv->driver_priv = NULL;
+}
+
+/**
+ * amdgpu_driver_preclose_kms - drm callback for pre close
+ *
+ * @dev: drm dev pointer
+ * @file_priv: drm file
+ *
+ * On device pre close, tear down hyperz and cmask filps on r1xx-r5xx
+ * (all asics).
+ */
+void amdgpu_driver_preclose_kms(struct drm_device *dev,
+ struct drm_file *file_priv)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+
+ amdgpu_uvd_free_handles(adev, file_priv);
+ amdgpu_vce_free_handles(adev, file_priv);
+}
+
+/*
+ * VBlank related functions.
+ */
+/**
+ * amdgpu_get_vblank_counter_kms - get frame count
+ *
+ * @dev: drm dev pointer
+ * @crtc: 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 amdgpu_get_vblank_counter_kms(struct drm_device *dev, int crtc)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+
+ if (crtc < 0 || crtc >= adev->mode_info.num_crtc) {
+ DRM_ERROR("Invalid crtc %d\n", crtc);
+ return -EINVAL;
+ }
+
+ return amdgpu_display_vblank_get_counter(adev, crtc);
+}
+
+/**
+ * amdgpu_enable_vblank_kms - enable vblank interrupt
+ *
+ * @dev: drm dev pointer
+ * @crtc: crtc to enable vblank interrupt for
+ *
+ * Enable the interrupt on the requested crtc (all asics).
+ * Returns 0 on success, -EINVAL on failure.
+ */
+int amdgpu_enable_vblank_kms(struct drm_device *dev, int crtc)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ int idx = amdgpu_crtc_idx_to_irq_type(adev, crtc);
+
+ return amdgpu_irq_get(adev, &adev->crtc_irq, idx);
+}
+
+/**
+ * amdgpu_disable_vblank_kms - disable vblank interrupt
+ *
+ * @dev: drm dev pointer
+ * @crtc: crtc to disable vblank interrupt for
+ *
+ * Disable the interrupt on the requested crtc (all asics).
+ */
+void amdgpu_disable_vblank_kms(struct drm_device *dev, int crtc)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ int idx = amdgpu_crtc_idx_to_irq_type(adev, crtc);
+
+ amdgpu_irq_put(adev, &adev->crtc_irq, idx);
+}
+
+/**
+ * amdgpu_get_vblank_timestamp_kms - get vblank timestamp
+ *
+ * @dev: drm dev pointer
+ * @crtc: crtc to get the timestamp for
+ * @max_error: max error
+ * @vblank_time: time value
+ * @flags: flags passed to the driver
+ *
+ * Gets the timestamp on the requested crtc based on the
+ * scanout position. (all asics).
+ * Returns postive status flags on success, negative error on failure.
+ */
+int amdgpu_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
+ int *max_error,
+ struct timeval *vblank_time,
+ unsigned flags)
+{
+ struct drm_crtc *drmcrtc;
+ struct amdgpu_device *adev = dev->dev_private;
+
+ if (crtc < 0 || crtc >= dev->num_crtcs) {
+ DRM_ERROR("Invalid crtc %d\n", crtc);
+ return -EINVAL;
+ }
+
+ /* Get associated drm_crtc: */
+ drmcrtc = &adev->mode_info.crtcs[crtc]->base;
+
+ /* Helper routine in DRM core does all the work: */
+ return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
+ vblank_time, flags,
+ drmcrtc, &drmcrtc->hwmode);
+}
+
+const struct drm_ioctl_desc amdgpu_ioctls_kms[] = {
+ DRM_IOCTL_DEF_DRV(AMDGPU_GEM_CREATE, amdgpu_gem_create_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(AMDGPU_CTX, amdgpu_ctx_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(AMDGPU_BO_LIST, amdgpu_bo_list_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ /* KMS */
+ DRM_IOCTL_DEF_DRV(AMDGPU_GEM_MMAP, amdgpu_gem_mmap_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(AMDGPU_GEM_WAIT_IDLE, amdgpu_gem_wait_idle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(AMDGPU_CS, amdgpu_cs_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(AMDGPU_INFO, amdgpu_info_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(AMDGPU_WAIT_CS, amdgpu_cs_wait_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(AMDGPU_GEM_METADATA, amdgpu_gem_metadata_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(AMDGPU_GEM_VA, amdgpu_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(AMDGPU_GEM_OP, amdgpu_gem_op_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(AMDGPU_GEM_USERPTR, amdgpu_gem_userptr_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+};
+int amdgpu_max_kms_ioctl = ARRAY_SIZE(amdgpu_ioctls_kms);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
new file mode 100644
index 000000000000..b1969f2b2038
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ * Christian König <christian.koenig@amd.com>
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/mmu_notifier.h>
+#include <drm/drmP.h>
+#include <drm/drm.h>
+
+#include "amdgpu.h"
+
+struct amdgpu_mn {
+ /* constant after initialisation */
+ struct amdgpu_device *adev;
+ struct mm_struct *mm;
+ struct mmu_notifier mn;
+
+ /* only used on destruction */
+ struct work_struct work;
+
+ /* protected by adev->mn_lock */
+ struct hlist_node node;
+
+ /* objects protected by lock */
+ struct mutex lock;
+ struct rb_root objects;
+};
+
+struct amdgpu_mn_node {
+ struct interval_tree_node it;
+ struct list_head bos;
+};
+
+/**
+ * amdgpu_mn_destroy - destroy the rmn
+ *
+ * @work: previously sheduled work item
+ *
+ * Lazy destroys the notifier from a work item
+ */
+static void amdgpu_mn_destroy(struct work_struct *work)
+{
+ struct amdgpu_mn *rmn = container_of(work, struct amdgpu_mn, work);
+ struct amdgpu_device *adev = rmn->adev;
+ struct amdgpu_mn_node *node, *next_node;
+ struct amdgpu_bo *bo, *next_bo;
+
+ mutex_lock(&adev->mn_lock);
+ mutex_lock(&rmn->lock);
+ hash_del(&rmn->node);
+ rbtree_postorder_for_each_entry_safe(node, next_node, &rmn->objects,
+ it.rb) {
+
+ interval_tree_remove(&node->it, &rmn->objects);
+ list_for_each_entry_safe(bo, next_bo, &node->bos, mn_list) {
+ bo->mn = NULL;
+ list_del_init(&bo->mn_list);
+ }
+ kfree(node);
+ }
+ mutex_unlock(&rmn->lock);
+ mutex_unlock(&adev->mn_lock);
+ mmu_notifier_unregister(&rmn->mn, rmn->mm);
+ kfree(rmn);
+}
+
+/**
+ * amdgpu_mn_release - callback to notify about mm destruction
+ *
+ * @mn: our notifier
+ * @mn: the mm this callback is about
+ *
+ * Shedule a work item to lazy destroy our notifier.
+ */
+static void amdgpu_mn_release(struct mmu_notifier *mn,
+ struct mm_struct *mm)
+{
+ struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn);
+ INIT_WORK(&rmn->work, amdgpu_mn_destroy);
+ schedule_work(&rmn->work);
+}
+
+/**
+ * amdgpu_mn_invalidate_range_start - callback to notify about mm change
+ *
+ * @mn: our notifier
+ * @mn: the mm this callback is about
+ * @start: start of updated range
+ * @end: end of updated range
+ *
+ * We block for all BOs between start and end to be idle and
+ * unmap them by move them into system domain again.
+ */
+static void amdgpu_mn_invalidate_range_start(struct mmu_notifier *mn,
+ struct mm_struct *mm,
+ unsigned long start,
+ unsigned long end)
+{
+ struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn);
+ struct interval_tree_node *it;
+
+ /* notification is exclusive, but interval is inclusive */
+ end -= 1;
+
+ mutex_lock(&rmn->lock);
+
+ it = interval_tree_iter_first(&rmn->objects, start, end);
+ while (it) {
+ struct amdgpu_mn_node *node;
+ struct amdgpu_bo *bo;
+ long r;
+
+ node = container_of(it, struct amdgpu_mn_node, it);
+ it = interval_tree_iter_next(it, start, end);
+
+ list_for_each_entry(bo, &node->bos, mn_list) {
+
+ if (!bo->tbo.ttm || bo->tbo.ttm->state != tt_bound)
+ continue;
+
+ r = amdgpu_bo_reserve(bo, true);
+ if (r) {
+ DRM_ERROR("(%ld) failed to reserve user bo\n", r);
+ continue;
+ }
+
+ r = reservation_object_wait_timeout_rcu(bo->tbo.resv,
+ true, false, MAX_SCHEDULE_TIMEOUT);
+ if (r <= 0)
+ DRM_ERROR("(%ld) failed to wait for user bo\n", r);
+
+ amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_CPU);
+ r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
+ if (r)
+ DRM_ERROR("(%ld) failed to validate user bo\n", r);
+
+ amdgpu_bo_unreserve(bo);
+ }
+ }
+
+ mutex_unlock(&rmn->lock);
+}
+
+static const struct mmu_notifier_ops amdgpu_mn_ops = {
+ .release = amdgpu_mn_release,
+ .invalidate_range_start = amdgpu_mn_invalidate_range_start,
+};
+
+/**
+ * amdgpu_mn_get - create notifier context
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Creates a notifier context for current->mm.
+ */
+static struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev)
+{
+ struct mm_struct *mm = current->mm;
+ struct amdgpu_mn *rmn;
+ int r;
+
+ down_write(&mm->mmap_sem);
+ mutex_lock(&adev->mn_lock);
+
+ hash_for_each_possible(adev->mn_hash, rmn, node, (unsigned long)mm)
+ if (rmn->mm == mm)
+ goto release_locks;
+
+ rmn = kzalloc(sizeof(*rmn), GFP_KERNEL);
+ if (!rmn) {
+ rmn = ERR_PTR(-ENOMEM);
+ goto release_locks;
+ }
+
+ rmn->adev = adev;
+ rmn->mm = mm;
+ rmn->mn.ops = &amdgpu_mn_ops;
+ mutex_init(&rmn->lock);
+ rmn->objects = RB_ROOT;
+
+ r = __mmu_notifier_register(&rmn->mn, mm);
+ if (r)
+ goto free_rmn;
+
+ hash_add(adev->mn_hash, &rmn->node, (unsigned long)mm);
+
+release_locks:
+ mutex_unlock(&adev->mn_lock);
+ up_write(&mm->mmap_sem);
+
+ return rmn;
+
+free_rmn:
+ mutex_unlock(&adev->mn_lock);
+ up_write(&mm->mmap_sem);
+ kfree(rmn);
+
+ return ERR_PTR(r);
+}
+
+/**
+ * amdgpu_mn_register - register a BO for notifier updates
+ *
+ * @bo: amdgpu buffer object
+ * @addr: userptr addr we should monitor
+ *
+ * Registers an MMU notifier for the given BO at the specified address.
+ * Returns 0 on success, -ERRNO if anything goes wrong.
+ */
+int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr)
+{
+ unsigned long end = addr + amdgpu_bo_size(bo) - 1;
+ struct amdgpu_device *adev = bo->adev;
+ struct amdgpu_mn *rmn;
+ struct amdgpu_mn_node *node = NULL;
+ struct list_head bos;
+ struct interval_tree_node *it;
+
+ rmn = amdgpu_mn_get(adev);
+ if (IS_ERR(rmn))
+ return PTR_ERR(rmn);
+
+ INIT_LIST_HEAD(&bos);
+
+ mutex_lock(&rmn->lock);
+
+ while ((it = interval_tree_iter_first(&rmn->objects, addr, end))) {
+ kfree(node);
+ node = container_of(it, struct amdgpu_mn_node, it);
+ interval_tree_remove(&node->it, &rmn->objects);
+ addr = min(it->start, addr);
+ end = max(it->last, end);
+ list_splice(&node->bos, &bos);
+ }
+
+ if (!node) {
+ node = kmalloc(sizeof(struct amdgpu_mn_node), GFP_KERNEL);
+ if (!node) {
+ mutex_unlock(&rmn->lock);
+ return -ENOMEM;
+ }
+ }
+
+ bo->mn = rmn;
+
+ node->it.start = addr;
+ node->it.last = end;
+ INIT_LIST_HEAD(&node->bos);
+ list_splice(&bos, &node->bos);
+ list_add(&bo->mn_list, &node->bos);
+
+ interval_tree_insert(&node->it, &rmn->objects);
+
+ mutex_unlock(&rmn->lock);
+
+ return 0;
+}
+
+/**
+ * amdgpu_mn_unregister - unregister a BO for notifier updates
+ *
+ * @bo: amdgpu buffer object
+ *
+ * Remove any registration of MMU notifier updates from the buffer object.
+ */
+void amdgpu_mn_unregister(struct amdgpu_bo *bo)
+{
+ struct amdgpu_device *adev = bo->adev;
+ struct amdgpu_mn *rmn;
+ struct list_head *head;
+
+ mutex_lock(&adev->mn_lock);
+ rmn = bo->mn;
+ if (rmn == NULL) {
+ mutex_unlock(&adev->mn_lock);
+ return;
+ }
+
+ mutex_lock(&rmn->lock);
+ /* save the next list entry for later */
+ head = bo->mn_list.next;
+
+ bo->mn = NULL;
+ list_del(&bo->mn_list);
+
+ if (list_empty(head)) {
+ struct amdgpu_mn_node *node;
+ node = container_of(head, struct amdgpu_mn_node, bos);
+ interval_tree_remove(&node->it, &rmn->objects);
+ kfree(node);
+ }
+
+ mutex_unlock(&rmn->lock);
+ mutex_unlock(&adev->mn_lock);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
new file mode 100644
index 000000000000..64efe5b52e65
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -0,0 +1,586 @@
+/*
+ * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
+ * VA Linux Systems Inc., Fremont, California.
+ * 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 shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Original Authors:
+ * Kevin E. Martin, Rickard E. Faith, Alan Hourihane
+ *
+ * Kernel port Author: Dave Airlie
+ */
+
+#ifndef AMDGPU_MODE_H
+#define AMDGPU_MODE_H
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_fixed.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+struct amdgpu_bo;
+struct amdgpu_device;
+struct amdgpu_encoder;
+struct amdgpu_router;
+struct amdgpu_hpd;
+
+#define to_amdgpu_crtc(x) container_of(x, struct amdgpu_crtc, base)
+#define to_amdgpu_connector(x) container_of(x, struct amdgpu_connector, base)
+#define to_amdgpu_encoder(x) container_of(x, struct amdgpu_encoder, base)
+#define to_amdgpu_framebuffer(x) container_of(x, struct amdgpu_framebuffer, base)
+
+#define AMDGPU_MAX_HPD_PINS 6
+#define AMDGPU_MAX_CRTCS 6
+#define AMDGPU_MAX_AFMT_BLOCKS 7
+
+enum amdgpu_rmx_type {
+ RMX_OFF,
+ RMX_FULL,
+ RMX_CENTER,
+ RMX_ASPECT
+};
+
+enum amdgpu_underscan_type {
+ UNDERSCAN_OFF,
+ UNDERSCAN_ON,
+ UNDERSCAN_AUTO,
+};
+
+#define AMDGPU_HPD_CONNECT_INT_DELAY_IN_MS 50
+#define AMDGPU_HPD_DISCONNECT_INT_DELAY_IN_MS 10
+
+enum amdgpu_hpd_id {
+ AMDGPU_HPD_1 = 0,
+ AMDGPU_HPD_2,
+ AMDGPU_HPD_3,
+ AMDGPU_HPD_4,
+ AMDGPU_HPD_5,
+ AMDGPU_HPD_6,
+ AMDGPU_HPD_LAST,
+ AMDGPU_HPD_NONE = 0xff,
+};
+
+enum amdgpu_crtc_irq {
+ AMDGPU_CRTC_IRQ_VBLANK1 = 0,
+ AMDGPU_CRTC_IRQ_VBLANK2,
+ AMDGPU_CRTC_IRQ_VBLANK3,
+ AMDGPU_CRTC_IRQ_VBLANK4,
+ AMDGPU_CRTC_IRQ_VBLANK5,
+ AMDGPU_CRTC_IRQ_VBLANK6,
+ AMDGPU_CRTC_IRQ_VLINE1,
+ AMDGPU_CRTC_IRQ_VLINE2,
+ AMDGPU_CRTC_IRQ_VLINE3,
+ AMDGPU_CRTC_IRQ_VLINE4,
+ AMDGPU_CRTC_IRQ_VLINE5,
+ AMDGPU_CRTC_IRQ_VLINE6,
+ AMDGPU_CRTC_IRQ_LAST,
+ AMDGPU_CRTC_IRQ_NONE = 0xff
+};
+
+enum amdgpu_pageflip_irq {
+ AMDGPU_PAGEFLIP_IRQ_D1 = 0,
+ AMDGPU_PAGEFLIP_IRQ_D2,
+ AMDGPU_PAGEFLIP_IRQ_D3,
+ AMDGPU_PAGEFLIP_IRQ_D4,
+ AMDGPU_PAGEFLIP_IRQ_D5,
+ AMDGPU_PAGEFLIP_IRQ_D6,
+ AMDGPU_PAGEFLIP_IRQ_LAST,
+ AMDGPU_PAGEFLIP_IRQ_NONE = 0xff
+};
+
+enum amdgpu_flip_status {
+ AMDGPU_FLIP_NONE,
+ AMDGPU_FLIP_PENDING,
+ AMDGPU_FLIP_SUBMITTED
+};
+
+#define AMDGPU_MAX_I2C_BUS 16
+
+/* amdgpu gpio-based i2c
+ * 1. "mask" reg and bits
+ * grabs the gpio pins for software use
+ * 0=not held 1=held
+ * 2. "a" reg and bits
+ * output pin value
+ * 0=low 1=high
+ * 3. "en" reg and bits
+ * sets the pin direction
+ * 0=input 1=output
+ * 4. "y" reg and bits
+ * input pin value
+ * 0=low 1=high
+ */
+struct amdgpu_i2c_bus_rec {
+ bool valid;
+ /* id used by atom */
+ uint8_t i2c_id;
+ /* id used by atom */
+ enum amdgpu_hpd_id hpd;
+ /* can be used with hw i2c engine */
+ bool hw_capable;
+ /* uses multi-media i2c engine */
+ bool mm_i2c;
+ /* regs and bits */
+ uint32_t mask_clk_reg;
+ uint32_t mask_data_reg;
+ uint32_t a_clk_reg;
+ uint32_t a_data_reg;
+ uint32_t en_clk_reg;
+ uint32_t en_data_reg;
+ uint32_t y_clk_reg;
+ uint32_t y_data_reg;
+ uint32_t mask_clk_mask;
+ uint32_t mask_data_mask;
+ uint32_t a_clk_mask;
+ uint32_t a_data_mask;
+ uint32_t en_clk_mask;
+ uint32_t en_data_mask;
+ uint32_t y_clk_mask;
+ uint32_t y_data_mask;
+};
+
+#define AMDGPU_MAX_BIOS_CONNECTOR 16
+
+/* pll flags */
+#define AMDGPU_PLL_USE_BIOS_DIVS (1 << 0)
+#define AMDGPU_PLL_NO_ODD_POST_DIV (1 << 1)
+#define AMDGPU_PLL_USE_REF_DIV (1 << 2)
+#define AMDGPU_PLL_LEGACY (1 << 3)
+#define AMDGPU_PLL_PREFER_LOW_REF_DIV (1 << 4)
+#define AMDGPU_PLL_PREFER_HIGH_REF_DIV (1 << 5)
+#define AMDGPU_PLL_PREFER_LOW_FB_DIV (1 << 6)
+#define AMDGPU_PLL_PREFER_HIGH_FB_DIV (1 << 7)
+#define AMDGPU_PLL_PREFER_LOW_POST_DIV (1 << 8)
+#define AMDGPU_PLL_PREFER_HIGH_POST_DIV (1 << 9)
+#define AMDGPU_PLL_USE_FRAC_FB_DIV (1 << 10)
+#define AMDGPU_PLL_PREFER_CLOSEST_LOWER (1 << 11)
+#define AMDGPU_PLL_USE_POST_DIV (1 << 12)
+#define AMDGPU_PLL_IS_LCD (1 << 13)
+#define AMDGPU_PLL_PREFER_MINM_OVER_MAXP (1 << 14)
+
+struct amdgpu_pll {
+ /* reference frequency */
+ uint32_t reference_freq;
+
+ /* fixed dividers */
+ uint32_t reference_div;
+ uint32_t post_div;
+
+ /* pll in/out limits */
+ uint32_t pll_in_min;
+ uint32_t pll_in_max;
+ uint32_t pll_out_min;
+ uint32_t pll_out_max;
+ uint32_t lcd_pll_out_min;
+ uint32_t lcd_pll_out_max;
+ uint32_t best_vco;
+
+ /* divider limits */
+ uint32_t min_ref_div;
+ uint32_t max_ref_div;
+ uint32_t min_post_div;
+ uint32_t max_post_div;
+ uint32_t min_feedback_div;
+ uint32_t max_feedback_div;
+ uint32_t min_frac_feedback_div;
+ uint32_t max_frac_feedback_div;
+
+ /* flags for the current clock */
+ uint32_t flags;
+
+ /* pll id */
+ uint32_t id;
+};
+
+struct amdgpu_i2c_chan {
+ struct i2c_adapter adapter;
+ struct drm_device *dev;
+ struct i2c_algo_bit_data bit;
+ struct amdgpu_i2c_bus_rec rec;
+ struct drm_dp_aux aux;
+ bool has_aux;
+ struct mutex mutex;
+};
+
+struct amdgpu_fbdev;
+
+struct amdgpu_afmt {
+ bool enabled;
+ int offset;
+ bool last_buffer_filled_status;
+ int id;
+ struct amdgpu_audio_pin *pin;
+};
+
+/*
+ * Audio
+ */
+struct amdgpu_audio_pin {
+ int channels;
+ int rate;
+ int bits_per_sample;
+ u8 status_bits;
+ u8 category_code;
+ u32 offset;
+ bool connected;
+ u32 id;
+};
+
+struct amdgpu_audio {
+ bool enabled;
+ struct amdgpu_audio_pin pin[AMDGPU_MAX_AFMT_BLOCKS];
+ int num_pins;
+};
+
+struct amdgpu_mode_mc_save {
+ u32 vga_render_control;
+ u32 vga_hdp_control;
+ bool crtc_enabled[AMDGPU_MAX_CRTCS];
+};
+
+struct amdgpu_display_funcs {
+ /* vga render */
+ void (*set_vga_render_state)(struct amdgpu_device *adev, bool render);
+ /* display watermarks */
+ void (*bandwidth_update)(struct amdgpu_device *adev);
+ /* get frame count */
+ u32 (*vblank_get_counter)(struct amdgpu_device *adev, int crtc);
+ /* wait for vblank */
+ void (*vblank_wait)(struct amdgpu_device *adev, int crtc);
+ /* is dce hung */
+ bool (*is_display_hung)(struct amdgpu_device *adev);
+ /* set backlight level */
+ void (*backlight_set_level)(struct amdgpu_encoder *amdgpu_encoder,
+ u8 level);
+ /* get backlight level */
+ u8 (*backlight_get_level)(struct amdgpu_encoder *amdgpu_encoder);
+ /* hotplug detect */
+ bool (*hpd_sense)(struct amdgpu_device *adev, enum amdgpu_hpd_id hpd);
+ void (*hpd_set_polarity)(struct amdgpu_device *adev,
+ enum amdgpu_hpd_id hpd);
+ u32 (*hpd_get_gpio_reg)(struct amdgpu_device *adev);
+ /* pageflipping */
+ void (*page_flip)(struct amdgpu_device *adev,
+ int crtc_id, u64 crtc_base);
+ int (*page_flip_get_scanoutpos)(struct amdgpu_device *adev, int crtc,
+ u32 *vbl, u32 *position);
+ /* display topology setup */
+ void (*add_encoder)(struct amdgpu_device *adev,
+ uint32_t encoder_enum,
+ uint32_t supported_device,
+ u16 caps);
+ void (*add_connector)(struct amdgpu_device *adev,
+ uint32_t connector_id,
+ uint32_t supported_device,
+ int connector_type,
+ struct amdgpu_i2c_bus_rec *i2c_bus,
+ uint16_t connector_object_id,
+ struct amdgpu_hpd *hpd,
+ struct amdgpu_router *router);
+ void (*stop_mc_access)(struct amdgpu_device *adev,
+ struct amdgpu_mode_mc_save *save);
+ void (*resume_mc_access)(struct amdgpu_device *adev,
+ struct amdgpu_mode_mc_save *save);
+};
+
+struct amdgpu_mode_info {
+ struct atom_context *atom_context;
+ struct card_info *atom_card_info;
+ bool mode_config_initialized;
+ struct amdgpu_crtc *crtcs[6];
+ struct amdgpu_afmt *afmt[7];
+ /* DVI-I properties */
+ struct drm_property *coherent_mode_property;
+ /* DAC enable load detect */
+ struct drm_property *load_detect_property;
+ /* underscan */
+ struct drm_property *underscan_property;
+ struct drm_property *underscan_hborder_property;
+ struct drm_property *underscan_vborder_property;
+ /* audio */
+ struct drm_property *audio_property;
+ /* FMT dithering */
+ struct drm_property *dither_property;
+ /* hardcoded DFP edid from BIOS */
+ struct edid *bios_hardcoded_edid;
+ int bios_hardcoded_edid_size;
+
+ /* pointer to fbdev info structure */
+ struct amdgpu_fbdev *rfbdev;
+ /* firmware flags */
+ u16 firmware_flags;
+ /* pointer to backlight encoder */
+ struct amdgpu_encoder *bl_encoder;
+ struct amdgpu_audio audio; /* audio stuff */
+ int num_crtc; /* number of crtcs */
+ int num_hpd; /* number of hpd pins */
+ int num_dig; /* number of dig blocks */
+ int disp_priority;
+ const struct amdgpu_display_funcs *funcs;
+};
+
+#define AMDGPU_MAX_BL_LEVEL 0xFF
+
+#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
+
+struct amdgpu_backlight_privdata {
+ struct amdgpu_encoder *encoder;
+ uint8_t negative;
+};
+
+#endif
+
+struct amdgpu_atom_ss {
+ uint16_t percentage;
+ uint16_t percentage_divider;
+ uint8_t type;
+ uint16_t step;
+ uint8_t delay;
+ uint8_t range;
+ uint8_t refdiv;
+ /* asic_ss */
+ uint16_t rate;
+ uint16_t amount;
+};
+
+struct amdgpu_crtc {
+ struct drm_crtc base;
+ int crtc_id;
+ u16 lut_r[256], lut_g[256], lut_b[256];
+ bool enabled;
+ bool can_tile;
+ uint32_t crtc_offset;
+ struct drm_gem_object *cursor_bo;
+ uint64_t cursor_addr;
+ int cursor_width;
+ int cursor_height;
+ int max_cursor_width;
+ int max_cursor_height;
+ enum amdgpu_rmx_type rmx_type;
+ u8 h_border;
+ u8 v_border;
+ fixed20_12 vsc;
+ fixed20_12 hsc;
+ struct drm_display_mode native_mode;
+ u32 pll_id;
+ /* page flipping */
+ struct workqueue_struct *pflip_queue;
+ struct amdgpu_flip_work *pflip_works;
+ enum amdgpu_flip_status pflip_status;
+ int deferred_flip_completion;
+ /* pll sharing */
+ struct amdgpu_atom_ss ss;
+ bool ss_enabled;
+ u32 adjusted_clock;
+ int bpc;
+ u32 pll_reference_div;
+ u32 pll_post_div;
+ u32 pll_flags;
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ /* for dpm */
+ u32 line_time;
+ u32 wm_low;
+ u32 wm_high;
+ struct drm_display_mode hw_mode;
+};
+
+struct amdgpu_encoder_atom_dig {
+ bool linkb;
+ /* atom dig */
+ bool coherent_mode;
+ int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB, etc. */
+ /* atom lvds/edp */
+ uint32_t lcd_misc;
+ uint16_t panel_pwr_delay;
+ uint32_t lcd_ss_id;
+ /* panel mode */
+ struct drm_display_mode native_mode;
+ struct backlight_device *bl_dev;
+ int dpms_mode;
+ uint8_t backlight_level;
+ int panel_mode;
+ struct amdgpu_afmt *afmt;
+};
+
+struct amdgpu_encoder {
+ struct drm_encoder base;
+ uint32_t encoder_enum;
+ uint32_t encoder_id;
+ uint32_t devices;
+ uint32_t active_device;
+ uint32_t flags;
+ uint32_t pixel_clock;
+ enum amdgpu_rmx_type rmx_type;
+ enum amdgpu_underscan_type underscan_type;
+ uint32_t underscan_hborder;
+ uint32_t underscan_vborder;
+ struct drm_display_mode native_mode;
+ void *enc_priv;
+ int audio_polling_active;
+ bool is_ext_encoder;
+ u16 caps;
+};
+
+struct amdgpu_connector_atom_dig {
+ /* displayport */
+ u8 dpcd[DP_RECEIVER_CAP_SIZE];
+ u8 dp_sink_type;
+ int dp_clock;
+ int dp_lane_count;
+ bool edp_on;
+};
+
+struct amdgpu_gpio_rec {
+ bool valid;
+ u8 id;
+ u32 reg;
+ u32 mask;
+ u32 shift;
+};
+
+struct amdgpu_hpd {
+ enum amdgpu_hpd_id hpd;
+ u8 plugged_state;
+ struct amdgpu_gpio_rec gpio;
+};
+
+struct amdgpu_router {
+ u32 router_id;
+ struct amdgpu_i2c_bus_rec i2c_info;
+ u8 i2c_addr;
+ /* i2c mux */
+ bool ddc_valid;
+ u8 ddc_mux_type;
+ u8 ddc_mux_control_pin;
+ u8 ddc_mux_state;
+ /* clock/data mux */
+ bool cd_valid;
+ u8 cd_mux_type;
+ u8 cd_mux_control_pin;
+ u8 cd_mux_state;
+};
+
+enum amdgpu_connector_audio {
+ AMDGPU_AUDIO_DISABLE = 0,
+ AMDGPU_AUDIO_ENABLE = 1,
+ AMDGPU_AUDIO_AUTO = 2
+};
+
+enum amdgpu_connector_dither {
+ AMDGPU_FMT_DITHER_DISABLE = 0,
+ AMDGPU_FMT_DITHER_ENABLE = 1,
+};
+
+struct amdgpu_connector {
+ struct drm_connector base;
+ uint32_t connector_id;
+ uint32_t devices;
+ struct amdgpu_i2c_chan *ddc_bus;
+ /* some systems have an hdmi and vga port with a shared ddc line */
+ bool shared_ddc;
+ bool use_digital;
+ /* we need to mind the EDID between detect
+ and get modes due to analog/digital/tvencoder */
+ struct edid *edid;
+ void *con_priv;
+ bool dac_load_detect;
+ bool detected_by_load; /* if the connection status was determined by load */
+ uint16_t connector_object_id;
+ struct amdgpu_hpd hpd;
+ struct amdgpu_router router;
+ struct amdgpu_i2c_chan *router_bus;
+ enum amdgpu_connector_audio audio;
+ enum amdgpu_connector_dither dither;
+ unsigned pixelclock_for_modeset;
+};
+
+struct amdgpu_framebuffer {
+ struct drm_framebuffer base;
+ struct drm_gem_object *obj;
+};
+
+#define ENCODER_MODE_IS_DP(em) (((em) == ATOM_ENCODER_MODE_DP) || \
+ ((em) == ATOM_ENCODER_MODE_DP_MST))
+
+void amdgpu_link_encoder_connector(struct drm_device *dev);
+
+struct drm_connector *
+amdgpu_get_connector_for_encoder(struct drm_encoder *encoder);
+struct drm_connector *
+amdgpu_get_connector_for_encoder_init(struct drm_encoder *encoder);
+bool amdgpu_dig_monitor_is_duallink(struct drm_encoder *encoder,
+ u32 pixel_clock);
+
+u16 amdgpu_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder);
+struct drm_encoder *amdgpu_get_external_encoder(struct drm_encoder *encoder);
+
+bool amdgpu_ddc_probe(struct amdgpu_connector *amdgpu_connector, bool use_aux);
+
+void amdgpu_encoder_set_active_device(struct drm_encoder *encoder);
+
+int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
+ unsigned int flags,
+ int *vpos, int *hpos, ktime_t *stime,
+ ktime_t *etime);
+
+int amdgpu_framebuffer_init(struct drm_device *dev,
+ struct amdgpu_framebuffer *rfb,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object *obj);
+
+int amdgpufb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
+
+void amdgpu_enc_destroy(struct drm_encoder *encoder);
+void amdgpu_copy_fb(struct drm_device *dev, struct drm_gem_object *dst_obj);
+bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+void amdgpu_panel_mode_fixup(struct drm_encoder *encoder,
+ struct drm_display_mode *adjusted_mode);
+int amdgpu_crtc_idx_to_irq_type(struct amdgpu_device *adev, int crtc);
+
+/* fbdev layer */
+int amdgpu_fbdev_init(struct amdgpu_device *adev);
+void amdgpu_fbdev_fini(struct amdgpu_device *adev);
+void amdgpu_fbdev_set_suspend(struct amdgpu_device *adev, int state);
+int amdgpu_fbdev_total_size(struct amdgpu_device *adev);
+bool amdgpu_fbdev_robj_is_fb(struct amdgpu_device *adev, struct amdgpu_bo *robj);
+
+void amdgpu_fb_output_poll_changed(struct amdgpu_device *adev);
+
+
+int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tiled);
+
+/* amdgpu_display.c */
+void amdgpu_print_display_setup(struct drm_device *dev);
+int amdgpu_modeset_create_props(struct amdgpu_device *adev);
+int amdgpu_crtc_set_config(struct drm_mode_set *set);
+int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event,
+ uint32_t page_flip_flags);
+extern const struct drm_mode_config_funcs amdgpu_mode_funcs;
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
new file mode 100644
index 000000000000..8da64245b31b
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright 2009 Jerome Glisse.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ * Jerome Glisse <glisse@freedesktop.org>
+ * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
+ * Dave Airlie
+ */
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "amdgpu_trace.h"
+
+
+int amdgpu_ttm_init(struct amdgpu_device *adev);
+void amdgpu_ttm_fini(struct amdgpu_device *adev);
+
+static u64 amdgpu_get_vis_part_size(struct amdgpu_device *adev,
+ struct ttm_mem_reg *mem)
+{
+ u64 ret = 0;
+ if (mem->start << PAGE_SHIFT < adev->mc.visible_vram_size) {
+ ret = (u64)((mem->start << PAGE_SHIFT) + mem->size) >
+ adev->mc.visible_vram_size ?
+ adev->mc.visible_vram_size - (mem->start << PAGE_SHIFT) :
+ mem->size;
+ }
+ return ret;
+}
+
+static void amdgpu_update_memory_usage(struct amdgpu_device *adev,
+ struct ttm_mem_reg *old_mem,
+ struct ttm_mem_reg *new_mem)
+{
+ u64 vis_size;
+ if (!adev)
+ return;
+
+ if (new_mem) {
+ switch (new_mem->mem_type) {
+ case TTM_PL_TT:
+ atomic64_add(new_mem->size, &adev->gtt_usage);
+ break;
+ case TTM_PL_VRAM:
+ atomic64_add(new_mem->size, &adev->vram_usage);
+ vis_size = amdgpu_get_vis_part_size(adev, new_mem);
+ atomic64_add(vis_size, &adev->vram_vis_usage);
+ break;
+ }
+ }
+
+ if (old_mem) {
+ switch (old_mem->mem_type) {
+ case TTM_PL_TT:
+ atomic64_sub(old_mem->size, &adev->gtt_usage);
+ break;
+ case TTM_PL_VRAM:
+ atomic64_sub(old_mem->size, &adev->vram_usage);
+ vis_size = amdgpu_get_vis_part_size(adev, old_mem);
+ atomic64_sub(vis_size, &adev->vram_vis_usage);
+ break;
+ }
+ }
+}
+
+static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
+{
+ struct amdgpu_bo *bo;
+
+ bo = container_of(tbo, struct amdgpu_bo, tbo);
+
+ amdgpu_update_memory_usage(bo->adev, &bo->tbo.mem, NULL);
+
+ mutex_lock(&bo->adev->gem.mutex);
+ list_del_init(&bo->list);
+ mutex_unlock(&bo->adev->gem.mutex);
+ drm_gem_object_release(&bo->gem_base);
+ kfree(bo->metadata);
+ kfree(bo);
+}
+
+bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo)
+{
+ if (bo->destroy == &amdgpu_ttm_bo_destroy)
+ return true;
+ return false;
+}
+
+static void amdgpu_ttm_placement_init(struct amdgpu_device *adev,
+ struct ttm_placement *placement,
+ struct ttm_place *placements,
+ u32 domain, u64 flags)
+{
+ u32 c = 0, i;
+
+ placement->placement = placements;
+ placement->busy_placement = placements;
+
+ if (domain & AMDGPU_GEM_DOMAIN_VRAM) {
+ if (flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS &&
+ adev->mc.visible_vram_size < adev->mc.real_vram_size) {
+ placements[c].fpfn =
+ adev->mc.visible_vram_size >> PAGE_SHIFT;
+ placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
+ TTM_PL_FLAG_VRAM;
+ }
+ placements[c].fpfn = 0;
+ placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
+ TTM_PL_FLAG_VRAM;
+ }
+
+ if (domain & AMDGPU_GEM_DOMAIN_GTT) {
+ if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) {
+ placements[c].fpfn = 0;
+ placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_TT |
+ TTM_PL_FLAG_UNCACHED;
+ } else {
+ placements[c].fpfn = 0;
+ placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT;
+ }
+ }
+
+ if (domain & AMDGPU_GEM_DOMAIN_CPU) {
+ if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) {
+ placements[c].fpfn = 0;
+ placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_SYSTEM |
+ TTM_PL_FLAG_UNCACHED;
+ } else {
+ placements[c].fpfn = 0;
+ placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM;
+ }
+ }
+
+ if (domain & AMDGPU_GEM_DOMAIN_GDS) {
+ placements[c].fpfn = 0;
+ placements[c++].flags = TTM_PL_FLAG_UNCACHED |
+ AMDGPU_PL_FLAG_GDS;
+ }
+ if (domain & AMDGPU_GEM_DOMAIN_GWS) {
+ placements[c].fpfn = 0;
+ placements[c++].flags = TTM_PL_FLAG_UNCACHED |
+ AMDGPU_PL_FLAG_GWS;
+ }
+ if (domain & AMDGPU_GEM_DOMAIN_OA) {
+ placements[c].fpfn = 0;
+ placements[c++].flags = TTM_PL_FLAG_UNCACHED |
+ AMDGPU_PL_FLAG_OA;
+ }
+
+ if (!c) {
+ placements[c].fpfn = 0;
+ placements[c++].flags = TTM_PL_MASK_CACHING |
+ TTM_PL_FLAG_SYSTEM;
+ }
+ placement->num_placement = c;
+ placement->num_busy_placement = c;
+
+ for (i = 0; i < c; i++) {
+ if ((flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) &&
+ (placements[i].flags & TTM_PL_FLAG_VRAM) &&
+ !placements[i].fpfn)
+ placements[i].lpfn =
+ adev->mc.visible_vram_size >> PAGE_SHIFT;
+ else
+ placements[i].lpfn = 0;
+ }
+}
+
+void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *rbo, u32 domain)
+{
+ amdgpu_ttm_placement_init(rbo->adev, &rbo->placement,
+ rbo->placements, domain, rbo->flags);
+}
+
+static void amdgpu_fill_placement_to_bo(struct amdgpu_bo *bo,
+ struct ttm_placement *placement)
+{
+ BUG_ON(placement->num_placement > (AMDGPU_GEM_DOMAIN_MAX + 1));
+
+ memcpy(bo->placements, placement->placement,
+ placement->num_placement * sizeof(struct ttm_place));
+ bo->placement.num_placement = placement->num_placement;
+ bo->placement.num_busy_placement = placement->num_busy_placement;
+ bo->placement.placement = bo->placements;
+ bo->placement.busy_placement = bo->placements;
+}
+
+int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
+ unsigned long size, int byte_align,
+ bool kernel, u32 domain, u64 flags,
+ struct sg_table *sg,
+ struct ttm_placement *placement,
+ struct amdgpu_bo **bo_ptr)
+{
+ struct amdgpu_bo *bo;
+ enum ttm_bo_type type;
+ unsigned long page_align;
+ size_t acc_size;
+ int r;
+
+ /* VI has a hw bug where VM PTEs have to be allocated in groups of 8.
+ * do this as a temporary workaround
+ */
+ if (!(domain & (AMDGPU_GEM_DOMAIN_GDS | AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA))) {
+ if (adev->asic_type >= CHIP_TOPAZ) {
+ if (byte_align & 0x7fff)
+ byte_align = ALIGN(byte_align, 0x8000);
+ if (size & 0x7fff)
+ size = ALIGN(size, 0x8000);
+ }
+ }
+
+ page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT;
+ size = ALIGN(size, PAGE_SIZE);
+
+ if (kernel) {
+ type = ttm_bo_type_kernel;
+ } else if (sg) {
+ type = ttm_bo_type_sg;
+ } else {
+ type = ttm_bo_type_device;
+ }
+ *bo_ptr = NULL;
+
+ acc_size = ttm_bo_dma_acc_size(&adev->mman.bdev, size,
+ sizeof(struct amdgpu_bo));
+
+ bo = kzalloc(sizeof(struct amdgpu_bo), GFP_KERNEL);
+ if (bo == NULL)
+ return -ENOMEM;
+ r = drm_gem_object_init(adev->ddev, &bo->gem_base, size);
+ if (unlikely(r)) {
+ kfree(bo);
+ return r;
+ }
+ bo->adev = adev;
+ INIT_LIST_HEAD(&bo->list);
+ INIT_LIST_HEAD(&bo->va);
+ bo->initial_domain = domain & (AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT |
+ AMDGPU_GEM_DOMAIN_CPU |
+ AMDGPU_GEM_DOMAIN_GDS |
+ AMDGPU_GEM_DOMAIN_GWS |
+ AMDGPU_GEM_DOMAIN_OA);
+
+ bo->flags = flags;
+ amdgpu_fill_placement_to_bo(bo, placement);
+ /* Kernel allocation are uninterruptible */
+ r = ttm_bo_init(&adev->mman.bdev, &bo->tbo, size, type,
+ &bo->placement, page_align, !kernel, NULL,
+ acc_size, sg, NULL, &amdgpu_ttm_bo_destroy);
+ if (unlikely(r != 0)) {
+ return r;
+ }
+ *bo_ptr = bo;
+
+ trace_amdgpu_bo_create(bo);
+
+ return 0;
+}
+
+int amdgpu_bo_create(struct amdgpu_device *adev,
+ unsigned long size, int byte_align,
+ bool kernel, u32 domain, u64 flags,
+ struct sg_table *sg, struct amdgpu_bo **bo_ptr)
+{
+ struct ttm_placement placement = {0};
+ struct ttm_place placements[AMDGPU_GEM_DOMAIN_MAX + 1];
+
+ memset(&placements, 0,
+ (AMDGPU_GEM_DOMAIN_MAX + 1) * sizeof(struct ttm_place));
+
+ amdgpu_ttm_placement_init(adev, &placement,
+ placements, domain, flags);
+
+ return amdgpu_bo_create_restricted(adev, size, byte_align,
+ kernel, domain, flags,
+ sg,
+ &placement,
+ bo_ptr);
+}
+
+int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
+{
+ bool is_iomem;
+ int r;
+
+ if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)
+ return -EPERM;
+
+ if (bo->kptr) {
+ if (ptr) {
+ *ptr = bo->kptr;
+ }
+ return 0;
+ }
+ r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.num_pages, &bo->kmap);
+ if (r) {
+ return r;
+ }
+ bo->kptr = ttm_kmap_obj_virtual(&bo->kmap, &is_iomem);
+ if (ptr) {
+ *ptr = bo->kptr;
+ }
+ return 0;
+}
+
+void amdgpu_bo_kunmap(struct amdgpu_bo *bo)
+{
+ if (bo->kptr == NULL)
+ return;
+ bo->kptr = NULL;
+ ttm_bo_kunmap(&bo->kmap);
+}
+
+struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo)
+{
+ if (bo == NULL)
+ return NULL;
+
+ ttm_bo_reference(&bo->tbo);
+ return bo;
+}
+
+void amdgpu_bo_unref(struct amdgpu_bo **bo)
+{
+ struct ttm_buffer_object *tbo;
+
+ if ((*bo) == NULL)
+ return;
+
+ tbo = &((*bo)->tbo);
+ ttm_bo_unref(&tbo);
+ if (tbo == NULL)
+ *bo = NULL;
+}
+
+int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
+ u64 min_offset, u64 max_offset,
+ u64 *gpu_addr)
+{
+ int r, i;
+ unsigned fpfn, lpfn;
+
+ if (amdgpu_ttm_tt_has_userptr(bo->tbo.ttm))
+ return -EPERM;
+
+ if (WARN_ON_ONCE(min_offset > max_offset))
+ return -EINVAL;
+
+ if (bo->pin_count) {
+ bo->pin_count++;
+ if (gpu_addr)
+ *gpu_addr = amdgpu_bo_gpu_offset(bo);
+
+ if (max_offset != 0) {
+ u64 domain_start;
+ if (domain == AMDGPU_GEM_DOMAIN_VRAM)
+ domain_start = bo->adev->mc.vram_start;
+ else
+ domain_start = bo->adev->mc.gtt_start;
+ WARN_ON_ONCE(max_offset <
+ (amdgpu_bo_gpu_offset(bo) - domain_start));
+ }
+
+ return 0;
+ }
+ amdgpu_ttm_placement_from_domain(bo, domain);
+ for (i = 0; i < bo->placement.num_placement; i++) {
+ /* force to pin into visible video ram */
+ if ((bo->placements[i].flags & TTM_PL_FLAG_VRAM) &&
+ !(bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) &&
+ (!max_offset || max_offset > bo->adev->mc.visible_vram_size)) {
+ if (WARN_ON_ONCE(min_offset >
+ bo->adev->mc.visible_vram_size))
+ return -EINVAL;
+ fpfn = min_offset >> PAGE_SHIFT;
+ lpfn = bo->adev->mc.visible_vram_size >> PAGE_SHIFT;
+ } else {
+ fpfn = min_offset >> PAGE_SHIFT;
+ lpfn = max_offset >> PAGE_SHIFT;
+ }
+ if (fpfn > bo->placements[i].fpfn)
+ bo->placements[i].fpfn = fpfn;
+ if (lpfn && lpfn < bo->placements[i].lpfn)
+ bo->placements[i].lpfn = lpfn;
+ bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
+ }
+
+ r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
+ if (likely(r == 0)) {
+ bo->pin_count = 1;
+ if (gpu_addr != NULL)
+ *gpu_addr = amdgpu_bo_gpu_offset(bo);
+ if (domain == AMDGPU_GEM_DOMAIN_VRAM)
+ bo->adev->vram_pin_size += amdgpu_bo_size(bo);
+ else
+ bo->adev->gart_pin_size += amdgpu_bo_size(bo);
+ } else {
+ dev_err(bo->adev->dev, "%p pin failed\n", bo);
+ }
+ return r;
+}
+
+int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain, u64 *gpu_addr)
+{
+ return amdgpu_bo_pin_restricted(bo, domain, 0, 0, gpu_addr);
+}
+
+int amdgpu_bo_unpin(struct amdgpu_bo *bo)
+{
+ int r, i;
+
+ if (!bo->pin_count) {
+ dev_warn(bo->adev->dev, "%p unpin not necessary\n", bo);
+ return 0;
+ }
+ bo->pin_count--;
+ if (bo->pin_count)
+ return 0;
+ for (i = 0; i < bo->placement.num_placement; i++) {
+ bo->placements[i].lpfn = 0;
+ bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
+ }
+ r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
+ if (likely(r == 0)) {
+ if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
+ bo->adev->vram_pin_size -= amdgpu_bo_size(bo);
+ else
+ bo->adev->gart_pin_size -= amdgpu_bo_size(bo);
+ } else {
+ dev_err(bo->adev->dev, "%p validate failed for unpin\n", bo);
+ }
+ return r;
+}
+
+int amdgpu_bo_evict_vram(struct amdgpu_device *adev)
+{
+ /* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */
+ if (0 && (adev->flags & AMDGPU_IS_APU)) {
+ /* Useless to evict on IGP chips */
+ return 0;
+ }
+ return ttm_bo_evict_mm(&adev->mman.bdev, TTM_PL_VRAM);
+}
+
+void amdgpu_bo_force_delete(struct amdgpu_device *adev)
+{
+ struct amdgpu_bo *bo, *n;
+
+ if (list_empty(&adev->gem.objects)) {
+ return;
+ }
+ dev_err(adev->dev, "Userspace still has active objects !\n");
+ list_for_each_entry_safe(bo, n, &adev->gem.objects, list) {
+ mutex_lock(&adev->ddev->struct_mutex);
+ dev_err(adev->dev, "%p %p %lu %lu force free\n",
+ &bo->gem_base, bo, (unsigned long)bo->gem_base.size,
+ *((unsigned long *)&bo->gem_base.refcount));
+ mutex_lock(&bo->adev->gem.mutex);
+ list_del_init(&bo->list);
+ mutex_unlock(&bo->adev->gem.mutex);
+ /* this should unref the ttm bo */
+ drm_gem_object_unreference(&bo->gem_base);
+ mutex_unlock(&adev->ddev->struct_mutex);
+ }
+}
+
+int amdgpu_bo_init(struct amdgpu_device *adev)
+{
+ /* Add an MTRR for the VRAM */
+ adev->mc.vram_mtrr = arch_phys_wc_add(adev->mc.aper_base,
+ adev->mc.aper_size);
+ DRM_INFO("Detected VRAM RAM=%lluM, BAR=%lluM\n",
+ adev->mc.mc_vram_size >> 20,
+ (unsigned long long)adev->mc.aper_size >> 20);
+ DRM_INFO("RAM width %dbits DDR\n",
+ adev->mc.vram_width);
+ return amdgpu_ttm_init(adev);
+}
+
+void amdgpu_bo_fini(struct amdgpu_device *adev)
+{
+ amdgpu_ttm_fini(adev);
+ arch_phys_wc_del(adev->mc.vram_mtrr);
+}
+
+int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo,
+ struct vm_area_struct *vma)
+{
+ return ttm_fbdev_mmap(vma, &bo->tbo);
+}
+
+int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags)
+{
+ if (AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT) > 6)
+ return -EINVAL;
+
+ bo->tiling_flags = tiling_flags;
+ return 0;
+}
+
+void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags)
+{
+ lockdep_assert_held(&bo->tbo.resv->lock.base);
+
+ if (tiling_flags)
+ *tiling_flags = bo->tiling_flags;
+}
+
+int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
+ uint32_t metadata_size, uint64_t flags)
+{
+ void *buffer;
+
+ if (!metadata_size) {
+ if (bo->metadata_size) {
+ kfree(bo->metadata);
+ bo->metadata_size = 0;
+ }
+ return 0;
+ }
+
+ if (metadata == NULL)
+ return -EINVAL;
+
+ buffer = kzalloc(metadata_size, GFP_KERNEL);
+ if (buffer == NULL)
+ return -ENOMEM;
+
+ memcpy(buffer, metadata, metadata_size);
+
+ kfree(bo->metadata);
+ bo->metadata_flags = flags;
+ bo->metadata = buffer;
+ bo->metadata_size = metadata_size;
+
+ return 0;
+}
+
+int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
+ size_t buffer_size, uint32_t *metadata_size,
+ uint64_t *flags)
+{
+ if (!buffer && !metadata_size)
+ return -EINVAL;
+
+ if (buffer) {
+ if (buffer_size < bo->metadata_size)
+ return -EINVAL;
+
+ if (bo->metadata_size)
+ memcpy(buffer, bo->metadata, bo->metadata_size);
+ }
+
+ if (metadata_size)
+ *metadata_size = bo->metadata_size;
+ if (flags)
+ *flags = bo->metadata_flags;
+
+ return 0;
+}
+
+void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *new_mem)
+{
+ struct amdgpu_bo *rbo;
+
+ if (!amdgpu_ttm_bo_is_amdgpu_bo(bo))
+ return;
+
+ rbo = container_of(bo, struct amdgpu_bo, tbo);
+ amdgpu_vm_bo_invalidate(rbo->adev, rbo);
+
+ /* update statistics */
+ if (!new_mem)
+ return;
+
+ /* move_notify is called before move happens */
+ amdgpu_update_memory_usage(rbo->adev, &bo->mem, new_mem);
+}
+
+int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
+{
+ struct amdgpu_device *adev;
+ struct amdgpu_bo *abo;
+ unsigned long offset, size, lpfn;
+ int i, r;
+
+ if (!amdgpu_ttm_bo_is_amdgpu_bo(bo))
+ return 0;
+
+ abo = container_of(bo, struct amdgpu_bo, tbo);
+ adev = abo->adev;
+ if (bo->mem.mem_type != TTM_PL_VRAM)
+ return 0;
+
+ size = bo->mem.num_pages << PAGE_SHIFT;
+ offset = bo->mem.start << PAGE_SHIFT;
+ if ((offset + size) <= adev->mc.visible_vram_size)
+ return 0;
+
+ /* hurrah the memory is not visible ! */
+ amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM);
+ lpfn = adev->mc.visible_vram_size >> PAGE_SHIFT;
+ for (i = 0; i < abo->placement.num_placement; i++) {
+ /* Force into visible VRAM */
+ if ((abo->placements[i].flags & TTM_PL_FLAG_VRAM) &&
+ (!abo->placements[i].lpfn || abo->placements[i].lpfn > lpfn))
+ abo->placements[i].lpfn = lpfn;
+ }
+ r = ttm_bo_validate(bo, &abo->placement, false, false);
+ if (unlikely(r == -ENOMEM)) {
+ amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_GTT);
+ return ttm_bo_validate(bo, &abo->placement, false, false);
+ } else if (unlikely(r != 0)) {
+ return r;
+ }
+
+ offset = bo->mem.start << PAGE_SHIFT;
+ /* this should never happen */
+ if ((offset + size) > adev->mc.visible_vram_size)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * amdgpu_bo_fence - add fence to buffer object
+ *
+ * @bo: buffer object in question
+ * @fence: fence to add
+ * @shared: true if fence should be added shared
+ *
+ */
+void amdgpu_bo_fence(struct amdgpu_bo *bo, struct amdgpu_fence *fence,
+ bool shared)
+{
+ struct reservation_object *resv = bo->tbo.resv;
+
+ if (shared)
+ reservation_object_add_shared_fence(resv, &fence->base);
+ else
+ reservation_object_add_excl_fence(resv, &fence->base);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
new file mode 100644
index 000000000000..675bdc30e41d
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#ifndef __AMDGPU_OBJECT_H__
+#define __AMDGPU_OBJECT_H__
+
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+
+/**
+ * amdgpu_mem_type_to_domain - return domain corresponding to mem_type
+ * @mem_type: ttm memory type
+ *
+ * Returns corresponding domain of the ttm mem_type
+ */
+static inline unsigned amdgpu_mem_type_to_domain(u32 mem_type)
+{
+ switch (mem_type) {
+ case TTM_PL_VRAM:
+ return AMDGPU_GEM_DOMAIN_VRAM;
+ case TTM_PL_TT:
+ return AMDGPU_GEM_DOMAIN_GTT;
+ case TTM_PL_SYSTEM:
+ return AMDGPU_GEM_DOMAIN_CPU;
+ case AMDGPU_PL_GDS:
+ return AMDGPU_GEM_DOMAIN_GDS;
+ case AMDGPU_PL_GWS:
+ return AMDGPU_GEM_DOMAIN_GWS;
+ case AMDGPU_PL_OA:
+ return AMDGPU_GEM_DOMAIN_OA;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_bo_reserve - reserve bo
+ * @bo: bo structure
+ * @no_intr: don't return -ERESTARTSYS on pending signal
+ *
+ * Returns:
+ * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by
+ * a signal. Release all buffer reservations and return to user-space.
+ */
+static inline int amdgpu_bo_reserve(struct amdgpu_bo *bo, bool no_intr)
+{
+ int r;
+
+ r = ttm_bo_reserve(&bo->tbo, !no_intr, false, false, 0);
+ if (unlikely(r != 0)) {
+ if (r != -ERESTARTSYS)
+ dev_err(bo->adev->dev, "%p reserve failed\n", bo);
+ return r;
+ }
+ return 0;
+}
+
+static inline void amdgpu_bo_unreserve(struct amdgpu_bo *bo)
+{
+ ttm_bo_unreserve(&bo->tbo);
+}
+
+/**
+ * amdgpu_bo_gpu_offset - return GPU offset of bo
+ * @bo: amdgpu object for which we query the offset
+ *
+ * Returns current GPU offset of the object.
+ *
+ * Note: object should either be pinned or reserved when calling this
+ * function, it might be useful to add check for this for debugging.
+ */
+static inline u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
+{
+ return bo->tbo.offset;
+}
+
+static inline unsigned long amdgpu_bo_size(struct amdgpu_bo *bo)
+{
+ return bo->tbo.num_pages << PAGE_SHIFT;
+}
+
+static inline unsigned amdgpu_bo_ngpu_pages(struct amdgpu_bo *bo)
+{
+ return (bo->tbo.num_pages << PAGE_SHIFT) / AMDGPU_GPU_PAGE_SIZE;
+}
+
+static inline unsigned amdgpu_bo_gpu_page_alignment(struct amdgpu_bo *bo)
+{
+ return (bo->tbo.mem.page_alignment << PAGE_SHIFT) / AMDGPU_GPU_PAGE_SIZE;
+}
+
+/**
+ * amdgpu_bo_mmap_offset - return mmap offset of bo
+ * @bo: amdgpu object for which we query the offset
+ *
+ * Returns mmap offset of the object.
+ */
+static inline u64 amdgpu_bo_mmap_offset(struct amdgpu_bo *bo)
+{
+ return drm_vma_node_offset_addr(&bo->tbo.vma_node);
+}
+
+int amdgpu_bo_create(struct amdgpu_device *adev,
+ unsigned long size, int byte_align,
+ bool kernel, u32 domain, u64 flags,
+ struct sg_table *sg,
+ struct amdgpu_bo **bo_ptr);
+int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
+ unsigned long size, int byte_align,
+ bool kernel, u32 domain, u64 flags,
+ struct sg_table *sg,
+ struct ttm_placement *placement,
+ struct amdgpu_bo **bo_ptr);
+int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr);
+void amdgpu_bo_kunmap(struct amdgpu_bo *bo);
+struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo);
+void amdgpu_bo_unref(struct amdgpu_bo **bo);
+int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain, u64 *gpu_addr);
+int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
+ u64 min_offset, u64 max_offset,
+ u64 *gpu_addr);
+int amdgpu_bo_unpin(struct amdgpu_bo *bo);
+int amdgpu_bo_evict_vram(struct amdgpu_device *adev);
+void amdgpu_bo_force_delete(struct amdgpu_device *adev);
+int amdgpu_bo_init(struct amdgpu_device *adev);
+void amdgpu_bo_fini(struct amdgpu_device *adev);
+int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo,
+ struct vm_area_struct *vma);
+int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags);
+void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags);
+int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
+ uint32_t metadata_size, uint64_t flags);
+int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
+ size_t buffer_size, uint32_t *metadata_size,
+ uint64_t *flags);
+void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *new_mem);
+int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
+void amdgpu_bo_fence(struct amdgpu_bo *bo, struct amdgpu_fence *fence,
+ bool shared);
+
+/*
+ * sub allocation
+ */
+
+static inline uint64_t amdgpu_sa_bo_gpu_addr(struct amdgpu_sa_bo *sa_bo)
+{
+ return sa_bo->manager->gpu_addr + sa_bo->soffset;
+}
+
+static inline void * amdgpu_sa_bo_cpu_addr(struct amdgpu_sa_bo *sa_bo)
+{
+ return sa_bo->manager->cpu_ptr + sa_bo->soffset;
+}
+
+int amdgpu_sa_bo_manager_init(struct amdgpu_device *adev,
+ struct amdgpu_sa_manager *sa_manager,
+ unsigned size, u32 align, u32 domain);
+void amdgpu_sa_bo_manager_fini(struct amdgpu_device *adev,
+ struct amdgpu_sa_manager *sa_manager);
+int amdgpu_sa_bo_manager_start(struct amdgpu_device *adev,
+ struct amdgpu_sa_manager *sa_manager);
+int amdgpu_sa_bo_manager_suspend(struct amdgpu_device *adev,
+ struct amdgpu_sa_manager *sa_manager);
+int amdgpu_sa_bo_new(struct amdgpu_device *adev,
+ struct amdgpu_sa_manager *sa_manager,
+ struct amdgpu_sa_bo **sa_bo,
+ unsigned size, unsigned align);
+void amdgpu_sa_bo_free(struct amdgpu_device *adev,
+ struct amdgpu_sa_bo **sa_bo,
+ struct amdgpu_fence *fence);
+#if defined(CONFIG_DEBUG_FS)
+void amdgpu_sa_bo_dump_debug_info(struct amdgpu_sa_manager *sa_manager,
+ struct seq_file *m);
+#endif
+
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pll.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pll.c
new file mode 100644
index 000000000000..d15314957732
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pll.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "atom.h"
+#include "atombios_encoders.h"
+#include <asm/div64.h>
+#include <linux/gcd.h>
+
+/**
+ * amdgpu_pll_reduce_ratio - fractional number reduction
+ *
+ * @nom: nominator
+ * @den: denominator
+ * @nom_min: minimum value for nominator
+ * @den_min: minimum value for denominator
+ *
+ * Find the greatest common divisor and apply it on both nominator and
+ * denominator, but make nominator and denominator are at least as large
+ * as their minimum values.
+ */
+static void amdgpu_pll_reduce_ratio(unsigned *nom, unsigned *den,
+ unsigned nom_min, unsigned den_min)
+{
+ unsigned tmp;
+
+ /* reduce the numbers to a simpler ratio */
+ tmp = gcd(*nom, *den);
+ *nom /= tmp;
+ *den /= tmp;
+
+ /* make sure nominator is large enough */
+ if (*nom < nom_min) {
+ tmp = DIV_ROUND_UP(nom_min, *nom);
+ *nom *= tmp;
+ *den *= tmp;
+ }
+
+ /* make sure the denominator is large enough */
+ if (*den < den_min) {
+ tmp = DIV_ROUND_UP(den_min, *den);
+ *nom *= tmp;
+ *den *= tmp;
+ }
+}
+
+/**
+ * amdgpu_pll_get_fb_ref_div - feedback and ref divider calculation
+ *
+ * @nom: nominator
+ * @den: denominator
+ * @post_div: post divider
+ * @fb_div_max: feedback divider maximum
+ * @ref_div_max: reference divider maximum
+ * @fb_div: resulting feedback divider
+ * @ref_div: resulting reference divider
+ *
+ * Calculate feedback and reference divider for a given post divider. Makes
+ * sure we stay within the limits.
+ */
+static void amdgpu_pll_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_div,
+ unsigned fb_div_max, unsigned ref_div_max,
+ unsigned *fb_div, unsigned *ref_div)
+{
+ /* limit reference * post divider to a maximum */
+ ref_div_max = min(128 / post_div, ref_div_max);
+
+ /* get matching reference and feedback divider */
+ *ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), ref_div_max);
+ *fb_div = DIV_ROUND_CLOSEST(nom * *ref_div * post_div, den);
+
+ /* limit fb divider to its maximum */
+ if (*fb_div > fb_div_max) {
+ *ref_div = DIV_ROUND_CLOSEST(*ref_div * fb_div_max, *fb_div);
+ *fb_div = fb_div_max;
+ }
+}
+
+/**
+ * amdgpu_pll_compute - compute PLL paramaters
+ *
+ * @pll: information about the PLL
+ * @dot_clock_p: resulting pixel clock
+ * fb_div_p: resulting feedback divider
+ * frac_fb_div_p: fractional part of the feedback divider
+ * ref_div_p: resulting reference divider
+ * post_div_p: resulting reference divider
+ *
+ * Try to calculate the PLL parameters to generate the given frequency:
+ * dot_clock = (ref_freq * feedback_div) / (ref_div * post_div)
+ */
+void amdgpu_pll_compute(struct amdgpu_pll *pll,
+ u32 freq,
+ u32 *dot_clock_p,
+ u32 *fb_div_p,
+ u32 *frac_fb_div_p,
+ u32 *ref_div_p,
+ u32 *post_div_p)
+{
+ unsigned target_clock = pll->flags & AMDGPU_PLL_USE_FRAC_FB_DIV ?
+ freq : freq / 10;
+
+ unsigned fb_div_min, fb_div_max, fb_div;
+ unsigned post_div_min, post_div_max, post_div;
+ unsigned ref_div_min, ref_div_max, ref_div;
+ unsigned post_div_best, diff_best;
+ unsigned nom, den;
+
+ /* determine allowed feedback divider range */
+ fb_div_min = pll->min_feedback_div;
+ fb_div_max = pll->max_feedback_div;
+
+ if (pll->flags & AMDGPU_PLL_USE_FRAC_FB_DIV) {
+ fb_div_min *= 10;
+ fb_div_max *= 10;
+ }
+
+ /* determine allowed ref divider range */
+ if (pll->flags & AMDGPU_PLL_USE_REF_DIV)
+ ref_div_min = pll->reference_div;
+ else
+ ref_div_min = pll->min_ref_div;
+
+ if (pll->flags & AMDGPU_PLL_USE_FRAC_FB_DIV &&
+ pll->flags & AMDGPU_PLL_USE_REF_DIV)
+ ref_div_max = pll->reference_div;
+ else
+ ref_div_max = pll->max_ref_div;
+
+ /* determine allowed post divider range */
+ if (pll->flags & AMDGPU_PLL_USE_POST_DIV) {
+ post_div_min = pll->post_div;
+ post_div_max = pll->post_div;
+ } else {
+ unsigned vco_min, vco_max;
+
+ if (pll->flags & AMDGPU_PLL_IS_LCD) {
+ vco_min = pll->lcd_pll_out_min;
+ vco_max = pll->lcd_pll_out_max;
+ } else {
+ vco_min = pll->pll_out_min;
+ vco_max = pll->pll_out_max;
+ }
+
+ if (pll->flags & AMDGPU_PLL_USE_FRAC_FB_DIV) {
+ vco_min *= 10;
+ vco_max *= 10;
+ }
+
+ post_div_min = vco_min / target_clock;
+ if ((target_clock * post_div_min) < vco_min)
+ ++post_div_min;
+ if (post_div_min < pll->min_post_div)
+ post_div_min = pll->min_post_div;
+
+ post_div_max = vco_max / target_clock;
+ if ((target_clock * post_div_max) > vco_max)
+ --post_div_max;
+ if (post_div_max > pll->max_post_div)
+ post_div_max = pll->max_post_div;
+ }
+
+ /* represent the searched ratio as fractional number */
+ nom = target_clock;
+ den = pll->reference_freq;
+
+ /* reduce the numbers to a simpler ratio */
+ amdgpu_pll_reduce_ratio(&nom, &den, fb_div_min, post_div_min);
+
+ /* now search for a post divider */
+ if (pll->flags & AMDGPU_PLL_PREFER_MINM_OVER_MAXP)
+ post_div_best = post_div_min;
+ else
+ post_div_best = post_div_max;
+ diff_best = ~0;
+
+ for (post_div = post_div_min; post_div <= post_div_max; ++post_div) {
+ unsigned diff;
+ amdgpu_pll_get_fb_ref_div(nom, den, post_div, fb_div_max,
+ ref_div_max, &fb_div, &ref_div);
+ diff = abs(target_clock - (pll->reference_freq * fb_div) /
+ (ref_div * post_div));
+
+ if (diff < diff_best || (diff == diff_best &&
+ !(pll->flags & AMDGPU_PLL_PREFER_MINM_OVER_MAXP))) {
+
+ post_div_best = post_div;
+ diff_best = diff;
+ }
+ }
+ post_div = post_div_best;
+
+ /* get the feedback and reference divider for the optimal value */
+ amdgpu_pll_get_fb_ref_div(nom, den, post_div, fb_div_max, ref_div_max,
+ &fb_div, &ref_div);
+
+ /* reduce the numbers to a simpler ratio once more */
+ /* this also makes sure that the reference divider is large enough */
+ amdgpu_pll_reduce_ratio(&fb_div, &ref_div, fb_div_min, ref_div_min);
+
+ /* avoid high jitter with small fractional dividers */
+ if (pll->flags & AMDGPU_PLL_USE_FRAC_FB_DIV && (fb_div % 10)) {
+ fb_div_min = max(fb_div_min, (9 - (fb_div % 10)) * 20 + 60);
+ if (fb_div < fb_div_min) {
+ unsigned tmp = DIV_ROUND_UP(fb_div_min, fb_div);
+ fb_div *= tmp;
+ ref_div *= tmp;
+ }
+ }
+
+ /* and finally save the result */
+ if (pll->flags & AMDGPU_PLL_USE_FRAC_FB_DIV) {
+ *fb_div_p = fb_div / 10;
+ *frac_fb_div_p = fb_div % 10;
+ } else {
+ *fb_div_p = fb_div;
+ *frac_fb_div_p = 0;
+ }
+
+ *dot_clock_p = ((pll->reference_freq * *fb_div_p * 10) +
+ (pll->reference_freq * *frac_fb_div_p)) /
+ (ref_div * post_div * 10);
+ *ref_div_p = ref_div;
+ *post_div_p = post_div;
+
+ DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
+ freq, *dot_clock_p * 10, *fb_div_p, *frac_fb_div_p,
+ ref_div, post_div);
+}
+
+/**
+ * amdgpu_pll_get_use_mask - look up a mask of which pplls are in use
+ *
+ * @crtc: drm crtc
+ *
+ * Returns the mask of which PPLLs (Pixel PLLs) are in use.
+ */
+u32 amdgpu_pll_get_use_mask(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_crtc *test_crtc;
+ struct amdgpu_crtc *test_amdgpu_crtc;
+ u32 pll_in_use = 0;
+
+ list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
+ if (crtc == test_crtc)
+ continue;
+
+ test_amdgpu_crtc = to_amdgpu_crtc(test_crtc);
+ if (test_amdgpu_crtc->pll_id != ATOM_PPLL_INVALID)
+ pll_in_use |= (1 << test_amdgpu_crtc->pll_id);
+ }
+ return pll_in_use;
+}
+
+/**
+ * amdgpu_pll_get_shared_dp_ppll - return the PPLL used by another crtc for DP
+ *
+ * @crtc: drm crtc
+ *
+ * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is
+ * also in DP mode. For DP, a single PPLL can be used for all DP
+ * crtcs/encoders.
+ */
+int amdgpu_pll_get_shared_dp_ppll(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_crtc *test_crtc;
+ struct amdgpu_crtc *test_amdgpu_crtc;
+
+ list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
+ if (crtc == test_crtc)
+ continue;
+ test_amdgpu_crtc = to_amdgpu_crtc(test_crtc);
+ if (test_amdgpu_crtc->encoder &&
+ ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(test_amdgpu_crtc->encoder))) {
+ /* for DP use the same PLL for all */
+ if (test_amdgpu_crtc->pll_id != ATOM_PPLL_INVALID)
+ return test_amdgpu_crtc->pll_id;
+ }
+ }
+ return ATOM_PPLL_INVALID;
+}
+
+/**
+ * amdgpu_pll_get_shared_nondp_ppll - return the PPLL used by another non-DP crtc
+ *
+ * @crtc: drm crtc
+ * @encoder: drm encoder
+ *
+ * Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can
+ * be shared (i.e., same clock).
+ */
+int amdgpu_pll_get_shared_nondp_ppll(struct drm_crtc *crtc)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct drm_crtc *test_crtc;
+ struct amdgpu_crtc *test_amdgpu_crtc;
+ u32 adjusted_clock, test_adjusted_clock;
+
+ adjusted_clock = amdgpu_crtc->adjusted_clock;
+
+ if (adjusted_clock == 0)
+ return ATOM_PPLL_INVALID;
+
+ list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
+ if (crtc == test_crtc)
+ continue;
+ test_amdgpu_crtc = to_amdgpu_crtc(test_crtc);
+ if (test_amdgpu_crtc->encoder &&
+ !ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(test_amdgpu_crtc->encoder))) {
+ /* check if we are already driving this connector with another crtc */
+ if (test_amdgpu_crtc->connector == amdgpu_crtc->connector) {
+ /* if we are, return that pll */
+ if (test_amdgpu_crtc->pll_id != ATOM_PPLL_INVALID)
+ return test_amdgpu_crtc->pll_id;
+ }
+ /* for non-DP check the clock */
+ test_adjusted_clock = test_amdgpu_crtc->adjusted_clock;
+ if ((crtc->mode.clock == test_crtc->mode.clock) &&
+ (adjusted_clock == test_adjusted_clock) &&
+ (amdgpu_crtc->ss_enabled == test_amdgpu_crtc->ss_enabled) &&
+ (test_amdgpu_crtc->pll_id != ATOM_PPLL_INVALID))
+ return test_amdgpu_crtc->pll_id;
+ }
+ }
+ return ATOM_PPLL_INVALID;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pll.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_pll.h
new file mode 100644
index 000000000000..db6136f68b82
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pll.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_PLL_H__
+#define __AMDGPU_PLL_H__
+
+void amdgpu_pll_compute(struct amdgpu_pll *pll,
+ u32 freq,
+ u32 *dot_clock_p,
+ u32 *fb_div_p,
+ u32 *frac_fb_div_p,
+ u32 *ref_div_p,
+ u32 *post_div_p);
+u32 amdgpu_pll_get_use_mask(struct drm_crtc *crtc);
+int amdgpu_pll_get_shared_dp_ppll(struct drm_crtc *crtc);
+int amdgpu_pll_get_shared_nondp_ppll(struct drm_crtc *crtc);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
new file mode 100644
index 000000000000..ed13baa7c976
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
@@ -0,0 +1,807 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to 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: Rafał Miłecki <zajec5@gmail.com>
+ * Alex Deucher <alexdeucher@gmail.com>
+ */
+#include <drm/drmP.h>
+#include "amdgpu.h"
+#include "amdgpu_drv.h"
+#include "amdgpu_pm.h"
+#include "amdgpu_dpm.h"
+#include "atom.h"
+#include <linux/power_supply.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+static int amdgpu_debugfs_pm_init(struct amdgpu_device *adev);
+
+void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
+{
+ if (adev->pm.dpm_enabled) {
+ mutex_lock(&adev->pm.mutex);
+ if (power_supply_is_system_supplied() > 0)
+ adev->pm.dpm.ac_power = true;
+ else
+ adev->pm.dpm.ac_power = false;
+ if (adev->pm.funcs->enable_bapm)
+ amdgpu_dpm_enable_bapm(adev, adev->pm.dpm.ac_power);
+ mutex_unlock(&adev->pm.mutex);
+ }
+}
+
+static ssize_t amdgpu_get_dpm_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ 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;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ (pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
+ (pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance");
+}
+
+static ssize_t amdgpu_set_dpm_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = ddev->dev_private;
+
+ mutex_lock(&adev->pm.mutex);
+ if (strncmp("battery", buf, strlen("battery")) == 0)
+ adev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY;
+ else if (strncmp("balanced", buf, strlen("balanced")) == 0)
+ adev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
+ else if (strncmp("performance", buf, strlen("performance")) == 0)
+ adev->pm.dpm.user_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 & AMDGPU_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 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");
+}
+
+static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct drm_device *ddev = dev_get_drvdata(dev);
+ struct amdgpu_device *adev = ddev->dev_private;
+ 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) {
+ level = AMDGPU_DPM_FORCED_LEVEL_HIGH;
+ } else if (strncmp("auto", buf, strlen("auto")) == 0) {
+ level = AMDGPU_DPM_FORCED_LEVEL_AUTO;
+ } else {
+ count = -EINVAL;
+ goto fail;
+ }
+ if (adev->pm.funcs->force_performance_level) {
+ if (adev->pm.dpm.thermal_active) {
+ count = -EINVAL;
+ goto fail;
+ }
+ ret = amdgpu_dpm_force_performance_level(adev, level);
+ if (ret)
+ count = -EINVAL;
+ }
+fail:
+ mutex_unlock(&adev->pm.mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, amdgpu_get_dpm_state, amdgpu_set_dpm_state);
+static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
+ amdgpu_get_dpm_forced_performance_level,
+ amdgpu_set_dpm_forced_performance_level);
+
+static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct amdgpu_device *adev = dev_get_drvdata(dev);
+ int temp;
+
+ if (adev->pm.funcs->get_temperature)
+ temp = amdgpu_dpm_get_temperature(adev);
+ else
+ temp = 0;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp);
+}
+
+static ssize_t amdgpu_hwmon_show_temp_thresh(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct amdgpu_device *adev = dev_get_drvdata(dev);
+ int hyst = to_sensor_dev_attr(attr)->index;
+ int temp;
+
+ if (hyst)
+ temp = adev->pm.dpm.thermal.min_temp;
+ else
+ temp = adev->pm.dpm.thermal.max_temp;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp);
+}
+
+static ssize_t amdgpu_hwmon_get_pwm1_enable(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ 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);
+
+ /* never 0 (full-speed), fuse or smc-controlled always */
+ return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC ? 1 : 2);
+}
+
+static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct amdgpu_device *adev = dev_get_drvdata(dev);
+ int err;
+ int value;
+
+ if(!adev->pm.funcs->set_fan_control_mode)
+ return -EINVAL;
+
+ err = kstrtoint(buf, 10, &value);
+ if (err)
+ return err;
+
+ switch (value) {
+ case 1: /* manual, percent-based */
+ amdgpu_dpm_set_fan_control_mode(adev, FDO_PWM_MODE_STATIC);
+ break;
+ default: /* disable */
+ amdgpu_dpm_set_fan_control_mode(adev, 0);
+ break;
+ }
+
+ return count;
+}
+
+static ssize_t amdgpu_hwmon_get_pwm1_min(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%i\n", 0);
+}
+
+static ssize_t amdgpu_hwmon_get_pwm1_max(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%i\n", 255);
+}
+
+static ssize_t amdgpu_hwmon_set_pwm1(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct amdgpu_device *adev = dev_get_drvdata(dev);
+ int err;
+ u32 value;
+
+ err = kstrtou32(buf, 10, &value);
+ if (err)
+ return err;
+
+ value = (value * 100) / 255;
+
+ err = amdgpu_dpm_set_fan_speed_percent(adev, value);
+ if (err)
+ return err;
+
+ return count;
+}
+
+static ssize_t amdgpu_hwmon_get_pwm1(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct amdgpu_device *adev = dev_get_drvdata(dev);
+ int err;
+ u32 speed;
+
+ err = amdgpu_dpm_get_fan_speed_percent(adev, &speed);
+ if (err)
+ return err;
+
+ speed = (speed * 255) / 100;
+
+ return sprintf(buf, "%i\n", speed);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, amdgpu_hwmon_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, amdgpu_hwmon_show_temp_thresh, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, amdgpu_hwmon_show_temp_thresh, NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, amdgpu_hwmon_get_pwm1, amdgpu_hwmon_set_pwm1, 0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, amdgpu_hwmon_get_pwm1_enable, amdgpu_hwmon_set_pwm1_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, amdgpu_hwmon_get_pwm1_min, NULL, 0);
+static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, amdgpu_hwmon_get_pwm1_max, NULL, 0);
+
+static struct attribute *hwmon_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_min.dev_attr.attr,
+ &sensor_dev_attr_pwm1_max.dev_attr.attr,
+ NULL
+};
+
+static umode_t hwmon_attributes_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct amdgpu_device *adev = dev_get_drvdata(dev);
+ umode_t effective_mode = attr->mode;
+
+ /* 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))
+ return 0;
+
+ /* Skip fan attributes if fan is not present */
+ if (adev->pm.no_fan &&
+ (attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
+ attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
+ attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
+ attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
+ return 0;
+
+ /* mask fan attributes if we have no bindings for this asic to expose */
+ if ((!adev->pm.funcs->get_fan_speed_percent &&
+ attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't query fan */
+ (!adev->pm.funcs->get_fan_control_mode &&
+ attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't query state */
+ effective_mode &= ~S_IRUGO;
+
+ if ((!adev->pm.funcs->set_fan_speed_percent &&
+ attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't manage fan */
+ (!adev->pm.funcs->set_fan_control_mode &&
+ attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */
+ effective_mode &= ~S_IWUSR;
+
+ /* hide max/min values if we can't both query and manage the fan */
+ if ((!adev->pm.funcs->set_fan_speed_percent &&
+ !adev->pm.funcs->get_fan_speed_percent) &&
+ (attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
+ attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
+ return 0;
+
+ return effective_mode;
+}
+
+static const struct attribute_group hwmon_attrgroup = {
+ .attrs = hwmon_attributes,
+ .is_visible = hwmon_attributes_visible,
+};
+
+static const struct attribute_group *hwmon_groups[] = {
+ &hwmon_attrgroup,
+ NULL
+};
+
+void amdgpu_dpm_thermal_work_handler(struct work_struct *work)
+{
+ struct amdgpu_device *adev =
+ 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;
+
+ if (!adev->pm.dpm_enabled)
+ return;
+
+ if (adev->pm.funcs->get_temperature) {
+ int temp = amdgpu_dpm_get_temperature(adev);
+
+ if (temp < adev->pm.dpm.thermal.min_temp)
+ /* switch back the user state */
+ dpm_state = adev->pm.dpm.user_state;
+ } else {
+ if (adev->pm.dpm.thermal.high_to_low)
+ /* switch back the user state */
+ dpm_state = adev->pm.dpm.user_state;
+ }
+ mutex_lock(&adev->pm.mutex);
+ if (dpm_state == POWER_STATE_TYPE_INTERNAL_THERMAL)
+ adev->pm.dpm.thermal_active = true;
+ else
+ adev->pm.dpm.thermal_active = false;
+ adev->pm.dpm.state = dpm_state;
+ mutex_unlock(&adev->pm.mutex);
+
+ amdgpu_pm_compute_clocks(adev);
+}
+
+static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev,
+ enum amdgpu_pm_state_type dpm_state)
+{
+ int i;
+ struct amdgpu_ps *ps;
+ u32 ui_class;
+ bool single_display = (adev->pm.dpm.new_active_crtc_count < 2) ?
+ true : false;
+
+ /* check if the vblank period is too short to adjust the mclk */
+ if (single_display && adev->pm.funcs->vblank_too_short) {
+ if (amdgpu_dpm_vblank_too_short(adev))
+ single_display = false;
+ }
+
+ /* certain older asics have a separare 3D performance state,
+ * so try that first if the user selected performance
+ */
+ if (dpm_state == POWER_STATE_TYPE_PERFORMANCE)
+ dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF;
+ /* balanced states don't exist at the moment */
+ if (dpm_state == POWER_STATE_TYPE_BALANCED)
+ dpm_state = POWER_STATE_TYPE_PERFORMANCE;
+
+restart_search:
+ /* Pick the best power state based on current conditions */
+ for (i = 0; i < adev->pm.dpm.num_ps; i++) {
+ ps = &adev->pm.dpm.ps[i];
+ ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK;
+ switch (dpm_state) {
+ /* user states */
+ case POWER_STATE_TYPE_BATTERY:
+ if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) {
+ if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
+ if (single_display)
+ return ps;
+ } else
+ return ps;
+ }
+ break;
+ case POWER_STATE_TYPE_BALANCED:
+ if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) {
+ if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
+ if (single_display)
+ return ps;
+ } else
+ return ps;
+ }
+ break;
+ case POWER_STATE_TYPE_PERFORMANCE:
+ if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
+ if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
+ if (single_display)
+ return ps;
+ } else
+ return ps;
+ }
+ break;
+ /* internal states */
+ case POWER_STATE_TYPE_INTERNAL_UVD:
+ if (adev->pm.dpm.uvd_ps)
+ return adev->pm.dpm.uvd_ps;
+ else
+ break;
+ case POWER_STATE_TYPE_INTERNAL_UVD_SD:
+ if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
+ return ps;
+ break;
+ case POWER_STATE_TYPE_INTERNAL_UVD_HD:
+ if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
+ return ps;
+ break;
+ case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
+ if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
+ return ps;
+ break;
+ case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
+ if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
+ return ps;
+ break;
+ case POWER_STATE_TYPE_INTERNAL_BOOT:
+ return adev->pm.dpm.boot_ps;
+ case POWER_STATE_TYPE_INTERNAL_THERMAL:
+ if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+ return ps;
+ break;
+ case POWER_STATE_TYPE_INTERNAL_ACPI:
+ if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI)
+ return ps;
+ break;
+ case POWER_STATE_TYPE_INTERNAL_ULV:
+ if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
+ return ps;
+ break;
+ case POWER_STATE_TYPE_INTERNAL_3DPERF:
+ if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
+ return ps;
+ break;
+ default:
+ break;
+ }
+ }
+ /* use a fallback state if we didn't match */
+ switch (dpm_state) {
+ case POWER_STATE_TYPE_INTERNAL_UVD_SD:
+ dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
+ goto restart_search;
+ case POWER_STATE_TYPE_INTERNAL_UVD_HD:
+ case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
+ case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
+ if (adev->pm.dpm.uvd_ps) {
+ return adev->pm.dpm.uvd_ps;
+ } else {
+ dpm_state = POWER_STATE_TYPE_PERFORMANCE;
+ goto restart_search;
+ }
+ case POWER_STATE_TYPE_INTERNAL_THERMAL:
+ dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI;
+ goto restart_search;
+ case POWER_STATE_TYPE_INTERNAL_ACPI:
+ dpm_state = POWER_STATE_TYPE_BATTERY;
+ goto restart_search;
+ case POWER_STATE_TYPE_BATTERY:
+ case POWER_STATE_TYPE_BALANCED:
+ case POWER_STATE_TYPE_INTERNAL_3DPERF:
+ dpm_state = POWER_STATE_TYPE_PERFORMANCE;
+ goto restart_search;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+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;
+ int ret;
+
+ /* if dpm init failed */
+ if (!adev->pm.dpm_enabled)
+ return;
+
+ if (adev->pm.dpm.user_state != adev->pm.dpm.state) {
+ /* add other state override checks here */
+ if ((!adev->pm.dpm.thermal_active) &&
+ (!adev->pm.dpm.uvd_active))
+ adev->pm.dpm.state = adev->pm.dpm.user_state;
+ }
+ dpm_state = adev->pm.dpm.state;
+
+ ps = amdgpu_dpm_pick_power_state(adev, dpm_state);
+ if (ps)
+ adev->pm.dpm.requested_ps = ps;
+ else
+ return;
+
+ /* no need to reprogram if nothing changed unless we are on BTC+ */
+ if (adev->pm.dpm.current_ps == adev->pm.dpm.requested_ps) {
+ /* vce just modifies an existing state so force a change */
+ if (ps->vce_active != adev->pm.dpm.vce_active)
+ goto force;
+ if (adev->flags & AMDGPU_IS_APU) {
+ /* for APUs if the num crtcs changed but state is the same,
+ * all we need to do is update the display configuration.
+ */
+ if (adev->pm.dpm.new_active_crtcs != adev->pm.dpm.current_active_crtcs) {
+ /* update display watermarks based on new power state */
+ amdgpu_display_bandwidth_update(adev);
+ /* update displays */
+ amdgpu_dpm_display_configuration_changed(adev);
+ adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
+ adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
+ }
+ return;
+ } else {
+ /* for BTC+ if the num crtcs hasn't changed and state is the same,
+ * nothing to do, if the num crtcs is > 1 and state is the same,
+ * update display configuration.
+ */
+ if (adev->pm.dpm.new_active_crtcs ==
+ adev->pm.dpm.current_active_crtcs) {
+ return;
+ } else if ((adev->pm.dpm.current_active_crtc_count > 1) &&
+ (adev->pm.dpm.new_active_crtc_count > 1)) {
+ /* update display watermarks based on new power state */
+ amdgpu_display_bandwidth_update(adev);
+ /* update displays */
+ amdgpu_dpm_display_configuration_changed(adev);
+ adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
+ adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
+ return;
+ }
+ }
+ }
+
+force:
+ if (amdgpu_dpm == 1) {
+ printk("switching from power state:\n");
+ amdgpu_dpm_print_power_state(adev, adev->pm.dpm.current_ps);
+ printk("switching to power state:\n");
+ amdgpu_dpm_print_power_state(adev, adev->pm.dpm.requested_ps);
+ }
+
+ mutex_lock(&adev->ddev->struct_mutex);
+ mutex_lock(&adev->ring_lock);
+
+ /* update whether vce is active */
+ ps->vce_active = adev->pm.dpm.vce_active;
+
+ ret = amdgpu_dpm_pre_set_power_state(adev);
+ if (ret)
+ goto done;
+
+ /* update display watermarks based on new power state */
+ amdgpu_display_bandwidth_update(adev);
+ /* update displays */
+ amdgpu_dpm_display_configuration_changed(adev);
+
+ adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
+ adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
+
+ /* wait for the rings to drain */
+ for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
+ struct amdgpu_ring *ring = adev->rings[i];
+ if (ring && ring->ready)
+ amdgpu_fence_wait_empty(ring);
+ }
+
+ /* program the new power state */
+ amdgpu_dpm_set_power_state(adev);
+
+ /* update current power state */
+ adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps;
+
+ amdgpu_dpm_post_set_power_state(adev);
+
+ if (adev->pm.funcs->force_performance_level) {
+ if (adev->pm.dpm.thermal_active) {
+ enum amdgpu_dpm_forced_level level = adev->pm.dpm.forced_level;
+ /* force low perf level for thermal */
+ amdgpu_dpm_force_performance_level(adev, AMDGPU_DPM_FORCED_LEVEL_LOW);
+ /* save the user's level */
+ adev->pm.dpm.forced_level = level;
+ } else {
+ /* otherwise, user selected level */
+ amdgpu_dpm_force_performance_level(adev, adev->pm.dpm.forced_level);
+ }
+ }
+
+done:
+ mutex_unlock(&adev->ring_lock);
+ mutex_unlock(&adev->ddev->struct_mutex);
+}
+
+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 */
+ amdgpu_dpm_powergate_uvd(adev, !enable);
+ mutex_unlock(&adev->pm.mutex);
+ } else {
+ 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);
+ }
+}
+
+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 */
+ amdgpu_dpm_powergate_vce(adev, !enable);
+
+ mutex_unlock(&adev->pm.mutex);
+ } else {
+ 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);
+ }
+}
+
+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);
+ amdgpu_dpm_print_power_state(adev, &adev->pm.dpm.ps[i]);
+ }
+}
+
+int amdgpu_pm_sysfs_init(struct amdgpu_device *adev)
+{
+ int ret;
+
+ 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);
+ if (IS_ERR(adev->pm.int_hwmon_dev)) {
+ ret = PTR_ERR(adev->pm.int_hwmon_dev);
+ dev_err(adev->dev,
+ "Unable to register hwmon device: %d\n", ret);
+ return ret;
+ }
+
+ ret = device_create_file(adev->dev, &dev_attr_power_dpm_state);
+ if (ret) {
+ DRM_ERROR("failed to create device file for dpm state\n");
+ return ret;
+ }
+ ret = device_create_file(adev->dev, &dev_attr_power_dpm_force_performance_level);
+ if (ret) {
+ DRM_ERROR("failed to create device file for dpm state\n");
+ return ret;
+ }
+ ret = amdgpu_debugfs_pm_init(adev);
+ if (ret) {
+ DRM_ERROR("Failed to register debugfs file for dpm!\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev)
+{
+ if (adev->pm.int_hwmon_dev)
+ hwmon_device_unregister(adev->pm.int_hwmon_dev);
+ device_remove_file(adev->dev, &dev_attr_power_dpm_state);
+ device_remove_file(adev->dev, &dev_attr_power_dpm_force_performance_level);
+}
+
+void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
+{
+ struct drm_device *ddev = adev->ddev;
+ struct drm_crtc *crtc;
+ struct amdgpu_crtc *amdgpu_crtc;
+
+ if (!adev->pm.dpm_enabled)
+ return;
+
+ mutex_lock(&adev->pm.mutex);
+
+ /* 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++;
+ }
+ }
+ }
+
+ /* 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);
+
+ mutex_unlock(&adev->pm.mutex);
+
+}
+
+/*
+ * Debugfs info
+ */
+#if defined(CONFIG_DEBUG_FS)
+
+static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+
+ if (adev->pm.dpm_enabled) {
+ mutex_lock(&adev->pm.mutex);
+ if (adev->pm.funcs->debugfs_print_current_performance_level)
+ amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
+ else
+ seq_printf(m, "Debugfs support not implemented for this asic\n");
+ mutex_unlock(&adev->pm.mutex);
+ }
+
+ return 0;
+}
+
+static struct drm_info_list amdgpu_pm_info_list[] = {
+ {"amdgpu_pm_info", amdgpu_debugfs_pm_info, 0, NULL},
+};
+#endif
+
+static int amdgpu_debugfs_pm_init(struct amdgpu_device *adev)
+{
+#if defined(CONFIG_DEBUG_FS)
+ return amdgpu_debugfs_add_files(adev, amdgpu_pm_info_list, ARRAY_SIZE(amdgpu_pm_info_list));
+#else
+ return 0;
+#endif
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h
new file mode 100644
index 000000000000..5fd7734f15ca
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_PM_H__
+#define __AMDGPU_PM_H__
+
+int amdgpu_pm_sysfs_init(struct amdgpu_device *adev);
+void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev);
+void amdgpu_pm_print_power_states(struct amdgpu_device *adev);
+void amdgpu_pm_compute_clocks(struct amdgpu_device *adev);
+void amdgpu_dpm_thermal_work_handler(struct work_struct *work);
+void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable);
+void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
new file mode 100644
index 000000000000..d9652fe32d6a
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2012 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.
+ *
+ * based on nouveau_prime.c
+ *
+ * Authors: Alex Deucher
+ */
+#include <drm/drmP.h>
+
+#include "amdgpu.h"
+#include <drm/amdgpu_drm.h>
+#include <linux/dma-buf.h>
+
+struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj)
+{
+ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+ int npages = bo->tbo.num_pages;
+
+ return drm_prime_pages_to_sg(bo->tbo.ttm->pages, npages);
+}
+
+void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj)
+{
+ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+ int ret;
+
+ ret = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.num_pages,
+ &bo->dma_buf_vmap);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return bo->dma_buf_vmap.virtual;
+}
+
+void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+
+ ttm_bo_kunmap(&bo->dma_buf_vmap);
+}
+
+struct drm_gem_object *amdgpu_gem_prime_import_sg_table(struct drm_device *dev,
+ struct dma_buf_attachment *attach,
+ struct sg_table *sg)
+{
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_bo *bo;
+ int ret;
+
+ ret = amdgpu_bo_create(adev, attach->dmabuf->size, PAGE_SIZE, false,
+ AMDGPU_GEM_DOMAIN_GTT, 0, sg, &bo);
+ if (ret)
+ return ERR_PTR(ret);
+
+ mutex_lock(&adev->gem.mutex);
+ list_add_tail(&bo->list, &adev->gem.objects);
+ mutex_unlock(&adev->gem.mutex);
+
+ return &bo->gem_base;
+}
+
+int amdgpu_gem_prime_pin(struct drm_gem_object *obj)
+{
+ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+ int ret = 0;
+
+ ret = amdgpu_bo_reserve(bo, false);
+ if (unlikely(ret != 0))
+ return ret;
+
+ /* pin buffer into GTT */
+ ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT, NULL);
+ amdgpu_bo_unreserve(bo);
+ return ret;
+}
+
+void amdgpu_gem_prime_unpin(struct drm_gem_object *obj)
+{
+ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+ int ret = 0;
+
+ ret = amdgpu_bo_reserve(bo, false);
+ if (unlikely(ret != 0))
+ return;
+
+ amdgpu_bo_unpin(bo);
+ amdgpu_bo_unreserve(bo);
+}
+
+struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj)
+{
+ struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+
+ return bo->tbo.resv;
+}
+
+struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *gobj,
+ int flags)
+{
+ struct amdgpu_bo *bo = gem_to_amdgpu_bo(gobj);
+
+ if (amdgpu_ttm_tt_has_userptr(bo->tbo.ttm))
+ return ERR_PTR(-EPERM);
+
+ return drm_gem_prime_export(dev, gobj, flags);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
new file mode 100644
index 000000000000..855e2196657a
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
@@ -0,0 +1,561 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ * Christian König
+ */
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "atom.h"
+
+/*
+ * Rings
+ * Most engines on the GPU are fed via ring buffers. Ring
+ * buffers are areas of GPU accessible memory that the host
+ * writes commands into and the GPU reads commands out of.
+ * There is a rptr (read pointer) that determines where the
+ * GPU is currently reading, and a wptr (write pointer)
+ * which determines where the host has written. When the
+ * pointers are equal, the ring is idle. When the host
+ * writes commands to the ring buffer, it increments the
+ * wptr. The GPU then starts fetching commands and executes
+ * them until the pointers are equal again.
+ */
+static int amdgpu_debugfs_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring);
+
+/**
+ * amdgpu_ring_free_size - update the free size
+ *
+ * @adev: amdgpu_device pointer
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Update the free dw slots in the ring buffer (all asics).
+ */
+void amdgpu_ring_free_size(struct amdgpu_ring *ring)
+{
+ uint32_t rptr = amdgpu_ring_get_rptr(ring);
+
+ /* This works because ring_size is a power of 2 */
+ ring->ring_free_dw = rptr + (ring->ring_size / 4);
+ ring->ring_free_dw -= ring->wptr;
+ ring->ring_free_dw &= ring->ptr_mask;
+ if (!ring->ring_free_dw) {
+ /* this is an empty ring */
+ ring->ring_free_dw = ring->ring_size / 4;
+ /* update lockup info to avoid false positive */
+ amdgpu_ring_lockup_update(ring);
+ }
+}
+
+/**
+ * amdgpu_ring_alloc - allocate space on the ring buffer
+ *
+ * @adev: amdgpu_device pointer
+ * @ring: amdgpu_ring structure holding ring information
+ * @ndw: number of dwords to allocate in the ring buffer
+ *
+ * Allocate @ndw dwords in the ring buffer (all asics).
+ * Returns 0 on success, error on failure.
+ */
+int amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned ndw)
+{
+ int r;
+
+ /* make sure we aren't trying to allocate more space than there is on the ring */
+ if (ndw > (ring->ring_size / 4))
+ return -ENOMEM;
+ /* Align requested size with padding so unlock_commit can
+ * pad safely */
+ amdgpu_ring_free_size(ring);
+ ndw = (ndw + ring->align_mask) & ~ring->align_mask;
+ while (ndw > (ring->ring_free_dw - 1)) {
+ amdgpu_ring_free_size(ring);
+ if (ndw < ring->ring_free_dw) {
+ break;
+ }
+ r = amdgpu_fence_wait_next(ring);
+ if (r)
+ return r;
+ }
+ ring->count_dw = ndw;
+ ring->wptr_old = ring->wptr;
+ return 0;
+}
+
+/**
+ * amdgpu_ring_lock - lock the ring and allocate space on it
+ *
+ * @adev: amdgpu_device pointer
+ * @ring: amdgpu_ring structure holding ring information
+ * @ndw: number of dwords to allocate in the ring buffer
+ *
+ * Lock the ring and allocate @ndw dwords in the ring buffer
+ * (all asics).
+ * Returns 0 on success, error on failure.
+ */
+int amdgpu_ring_lock(struct amdgpu_ring *ring, unsigned ndw)
+{
+ int r;
+
+ mutex_lock(ring->ring_lock);
+ r = amdgpu_ring_alloc(ring, ndw);
+ if (r) {
+ mutex_unlock(ring->ring_lock);
+ return r;
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_ring_commit - tell the GPU to execute the new
+ * commands on the ring buffer
+ *
+ * @adev: amdgpu_device pointer
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Update the wptr (write pointer) to tell the GPU to
+ * execute new commands on the ring buffer (all asics).
+ */
+void amdgpu_ring_commit(struct amdgpu_ring *ring)
+{
+ /* We pad to match fetch size */
+ while (ring->wptr & ring->align_mask) {
+ amdgpu_ring_write(ring, ring->nop);
+ }
+ mb();
+ amdgpu_ring_set_wptr(ring);
+}
+
+/**
+ * amdgpu_ring_unlock_commit - tell the GPU to execute the new
+ * commands on the ring buffer and unlock it
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Call amdgpu_ring_commit() then unlock the ring (all asics).
+ */
+void amdgpu_ring_unlock_commit(struct amdgpu_ring *ring)
+{
+ amdgpu_ring_commit(ring);
+ mutex_unlock(ring->ring_lock);
+}
+
+/**
+ * amdgpu_ring_undo - reset the wptr
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Reset the driver's copy of the wptr (all asics).
+ */
+void amdgpu_ring_undo(struct amdgpu_ring *ring)
+{
+ ring->wptr = ring->wptr_old;
+}
+
+/**
+ * amdgpu_ring_unlock_undo - reset the wptr and unlock the ring
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Call amdgpu_ring_undo() then unlock the ring (all asics).
+ */
+void amdgpu_ring_unlock_undo(struct amdgpu_ring *ring)
+{
+ amdgpu_ring_undo(ring);
+ mutex_unlock(ring->ring_lock);
+}
+
+/**
+ * amdgpu_ring_lockup_update - update lockup variables
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Update the last rptr value and timestamp (all asics).
+ */
+void amdgpu_ring_lockup_update(struct amdgpu_ring *ring)
+{
+ atomic_set(&ring->last_rptr, amdgpu_ring_get_rptr(ring));
+ atomic64_set(&ring->last_activity, jiffies_64);
+}
+
+/**
+ * amdgpu_ring_test_lockup() - check if ring is lockedup by recording information
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ */
+bool amdgpu_ring_test_lockup(struct amdgpu_ring *ring)
+{
+ uint32_t rptr = amdgpu_ring_get_rptr(ring);
+ uint64_t last = atomic64_read(&ring->last_activity);
+ uint64_t elapsed;
+
+ if (rptr != atomic_read(&ring->last_rptr)) {
+ /* ring is still working, no lockup */
+ amdgpu_ring_lockup_update(ring);
+ return false;
+ }
+
+ elapsed = jiffies_to_msecs(jiffies_64 - last);
+ if (amdgpu_lockup_timeout && elapsed >= amdgpu_lockup_timeout) {
+ dev_err(ring->adev->dev, "ring %d stalled for more than %llumsec\n",
+ ring->idx, elapsed);
+ return true;
+ }
+ /* give a chance to the GPU ... */
+ return false;
+}
+
+/**
+ * amdgpu_ring_backup - Back up the content of a ring
+ *
+ * @ring: the ring we want to back up
+ *
+ * Saves all unprocessed commits from a ring, returns the number of dwords saved.
+ */
+unsigned amdgpu_ring_backup(struct amdgpu_ring *ring,
+ uint32_t **data)
+{
+ unsigned size, ptr, i;
+
+ /* just in case lock the ring */
+ mutex_lock(ring->ring_lock);
+ *data = NULL;
+
+ if (ring->ring_obj == NULL) {
+ mutex_unlock(ring->ring_lock);
+ return 0;
+ }
+
+ /* it doesn't make sense to save anything if all fences are signaled */
+ if (!amdgpu_fence_count_emitted(ring)) {
+ mutex_unlock(ring->ring_lock);
+ return 0;
+ }
+
+ ptr = le32_to_cpu(*ring->next_rptr_cpu_addr);
+
+ size = ring->wptr + (ring->ring_size / 4);
+ size -= ptr;
+ size &= ring->ptr_mask;
+ if (size == 0) {
+ mutex_unlock(ring->ring_lock);
+ return 0;
+ }
+
+ /* and then save the content of the ring */
+ *data = kmalloc_array(size, sizeof(uint32_t), GFP_KERNEL);
+ if (!*data) {
+ mutex_unlock(ring->ring_lock);
+ return 0;
+ }
+ for (i = 0; i < size; ++i) {
+ (*data)[i] = ring->ring[ptr++];
+ ptr &= ring->ptr_mask;
+ }
+
+ mutex_unlock(ring->ring_lock);
+ return size;
+}
+
+/**
+ * amdgpu_ring_restore - append saved commands to the ring again
+ *
+ * @ring: ring to append commands to
+ * @size: number of dwords we want to write
+ * @data: saved commands
+ *
+ * Allocates space on the ring and restore the previously saved commands.
+ */
+int amdgpu_ring_restore(struct amdgpu_ring *ring,
+ unsigned size, uint32_t *data)
+{
+ int i, r;
+
+ if (!size || !data)
+ return 0;
+
+ /* restore the saved ring content */
+ r = amdgpu_ring_lock(ring, size);
+ if (r)
+ return r;
+
+ for (i = 0; i < size; ++i) {
+ amdgpu_ring_write(ring, data[i]);
+ }
+
+ amdgpu_ring_unlock_commit(ring);
+ kfree(data);
+ return 0;
+}
+
+/**
+ * amdgpu_ring_init - init driver ring struct.
+ *
+ * @adev: amdgpu_device pointer
+ * @ring: amdgpu_ring structure holding ring information
+ * @ring_size: size of the ring
+ * @nop: nop packet for this ring
+ *
+ * Initialize the driver information for the selected ring (all asics).
+ * Returns 0 on success, error on failure.
+ */
+int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
+ unsigned ring_size, u32 nop, u32 align_mask,
+ struct amdgpu_irq_src *irq_src, unsigned irq_type,
+ enum amdgpu_ring_type ring_type)
+{
+ u32 rb_bufsz;
+ int r;
+
+ if (ring->adev == NULL) {
+ if (adev->num_rings >= AMDGPU_MAX_RINGS)
+ return -EINVAL;
+
+ ring->adev = adev;
+ ring->idx = adev->num_rings++;
+ adev->rings[ring->idx] = ring;
+ amdgpu_fence_driver_init_ring(ring);
+ }
+
+ r = amdgpu_wb_get(adev, &ring->rptr_offs);
+ if (r) {
+ dev_err(adev->dev, "(%d) ring rptr_offs wb alloc failed\n", r);
+ return r;
+ }
+
+ r = amdgpu_wb_get(adev, &ring->wptr_offs);
+ if (r) {
+ dev_err(adev->dev, "(%d) ring wptr_offs wb alloc failed\n", r);
+ return r;
+ }
+
+ r = amdgpu_wb_get(adev, &ring->fence_offs);
+ if (r) {
+ dev_err(adev->dev, "(%d) ring fence_offs wb alloc failed\n", r);
+ return r;
+ }
+
+ r = amdgpu_wb_get(adev, &ring->next_rptr_offs);
+ if (r) {
+ dev_err(adev->dev, "(%d) ring next_rptr wb alloc failed\n", r);
+ return r;
+ }
+ ring->next_rptr_gpu_addr = adev->wb.gpu_addr + (ring->next_rptr_offs * 4);
+ ring->next_rptr_cpu_addr = &adev->wb.wb[ring->next_rptr_offs];
+
+ r = amdgpu_fence_driver_start_ring(ring, irq_src, irq_type);
+ if (r) {
+ dev_err(adev->dev, "failed initializing fences (%d).\n", r);
+ return r;
+ }
+
+ ring->ring_lock = &adev->ring_lock;
+ /* Align ring size */
+ rb_bufsz = order_base_2(ring_size / 8);
+ ring_size = (1 << (rb_bufsz + 1)) * 4;
+ ring->ring_size = ring_size;
+ ring->align_mask = align_mask;
+ ring->nop = nop;
+ ring->type = ring_type;
+
+ /* Allocate ring buffer */
+ if (ring->ring_obj == NULL) {
+ r = amdgpu_bo_create(adev, ring->ring_size, PAGE_SIZE, true,
+ AMDGPU_GEM_DOMAIN_GTT, 0,
+ NULL, &ring->ring_obj);
+ if (r) {
+ dev_err(adev->dev, "(%d) ring create failed\n", r);
+ return r;
+ }
+ r = amdgpu_bo_reserve(ring->ring_obj, false);
+ if (unlikely(r != 0))
+ return r;
+ r = amdgpu_bo_pin(ring->ring_obj, AMDGPU_GEM_DOMAIN_GTT,
+ &ring->gpu_addr);
+ if (r) {
+ amdgpu_bo_unreserve(ring->ring_obj);
+ dev_err(adev->dev, "(%d) ring pin failed\n", r);
+ return r;
+ }
+ r = amdgpu_bo_kmap(ring->ring_obj,
+ (void **)&ring->ring);
+ amdgpu_bo_unreserve(ring->ring_obj);
+ if (r) {
+ dev_err(adev->dev, "(%d) ring map failed\n", r);
+ return r;
+ }
+ }
+ ring->ptr_mask = (ring->ring_size / 4) - 1;
+ ring->ring_free_dw = ring->ring_size / 4;
+
+ if (amdgpu_debugfs_ring_init(adev, ring)) {
+ DRM_ERROR("Failed to register debugfs file for rings !\n");
+ }
+ amdgpu_ring_lockup_update(ring);
+ return 0;
+}
+
+/**
+ * amdgpu_ring_fini - tear down the driver ring struct.
+ *
+ * @adev: amdgpu_device pointer
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Tear down the driver information for the selected ring (all asics).
+ */
+void amdgpu_ring_fini(struct amdgpu_ring *ring)
+{
+ int r;
+ struct amdgpu_bo *ring_obj;
+
+ if (ring->ring_lock == NULL)
+ return;
+
+ mutex_lock(ring->ring_lock);
+ ring_obj = ring->ring_obj;
+ ring->ready = false;
+ ring->ring = NULL;
+ ring->ring_obj = NULL;
+ mutex_unlock(ring->ring_lock);
+
+ amdgpu_wb_free(ring->adev, ring->fence_offs);
+ amdgpu_wb_free(ring->adev, ring->rptr_offs);
+ amdgpu_wb_free(ring->adev, ring->wptr_offs);
+ amdgpu_wb_free(ring->adev, ring->next_rptr_offs);
+
+ if (ring_obj) {
+ r = amdgpu_bo_reserve(ring_obj, false);
+ if (likely(r == 0)) {
+ amdgpu_bo_kunmap(ring_obj);
+ amdgpu_bo_unpin(ring_obj);
+ amdgpu_bo_unreserve(ring_obj);
+ }
+ amdgpu_bo_unref(&ring_obj);
+ }
+}
+
+/*
+ * Debugfs info
+ */
+#if defined(CONFIG_DEBUG_FS)
+
+static int amdgpu_debugfs_ring_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ int roffset = *(int*)node->info_ent->data;
+ struct amdgpu_ring *ring = (void *)(((uint8_t*)adev) + roffset);
+
+ uint32_t rptr, wptr, rptr_next;
+ unsigned count, i, j;
+
+ amdgpu_ring_free_size(ring);
+ count = (ring->ring_size / 4) - ring->ring_free_dw;
+
+ wptr = amdgpu_ring_get_wptr(ring);
+ seq_printf(m, "wptr: 0x%08x [%5d]\n",
+ wptr, wptr);
+
+ rptr = amdgpu_ring_get_rptr(ring);
+ seq_printf(m, "rptr: 0x%08x [%5d]\n",
+ rptr, rptr);
+
+ rptr_next = ~0;
+
+ seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n",
+ ring->wptr, ring->wptr);
+ seq_printf(m, "last semaphore signal addr : 0x%016llx\n",
+ ring->last_semaphore_signal_addr);
+ seq_printf(m, "last semaphore wait addr : 0x%016llx\n",
+ ring->last_semaphore_wait_addr);
+ seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw);
+ seq_printf(m, "%u dwords in ring\n", count);
+
+ if (!ring->ready)
+ return 0;
+
+ /* print 8 dw before current rptr as often it's the last executed
+ * packet that is the root issue
+ */
+ i = (rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask;
+ for (j = 0; j <= (count + 32); j++) {
+ seq_printf(m, "r[%5d]=0x%08x", i, ring->ring[i]);
+ if (rptr == i)
+ seq_puts(m, " *");
+ if (rptr_next == i)
+ seq_puts(m, " #");
+ seq_puts(m, "\n");
+ i = (i + 1) & ring->ptr_mask;
+ }
+ return 0;
+}
+
+/* TODO: clean this up !*/
+static int amdgpu_gfx_index = offsetof(struct amdgpu_device, gfx.gfx_ring[0]);
+static int cayman_cp1_index = offsetof(struct amdgpu_device, gfx.compute_ring[0]);
+static int cayman_cp2_index = offsetof(struct amdgpu_device, gfx.compute_ring[1]);
+static int amdgpu_dma1_index = offsetof(struct amdgpu_device, sdma[0].ring);
+static int amdgpu_dma2_index = offsetof(struct amdgpu_device, sdma[1].ring);
+static int r600_uvd_index = offsetof(struct amdgpu_device, uvd.ring);
+static int si_vce1_index = offsetof(struct amdgpu_device, vce.ring[0]);
+static int si_vce2_index = offsetof(struct amdgpu_device, vce.ring[1]);
+
+static struct drm_info_list amdgpu_debugfs_ring_info_list[] = {
+ {"amdgpu_ring_gfx", amdgpu_debugfs_ring_info, 0, &amdgpu_gfx_index},
+ {"amdgpu_ring_cp1", amdgpu_debugfs_ring_info, 0, &cayman_cp1_index},
+ {"amdgpu_ring_cp2", amdgpu_debugfs_ring_info, 0, &cayman_cp2_index},
+ {"amdgpu_ring_dma1", amdgpu_debugfs_ring_info, 0, &amdgpu_dma1_index},
+ {"amdgpu_ring_dma2", amdgpu_debugfs_ring_info, 0, &amdgpu_dma2_index},
+ {"amdgpu_ring_uvd", amdgpu_debugfs_ring_info, 0, &r600_uvd_index},
+ {"amdgpu_ring_vce1", amdgpu_debugfs_ring_info, 0, &si_vce1_index},
+ {"amdgpu_ring_vce2", amdgpu_debugfs_ring_info, 0, &si_vce2_index},
+};
+
+#endif
+
+static int amdgpu_debugfs_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring)
+{
+#if defined(CONFIG_DEBUG_FS)
+ unsigned i;
+ for (i = 0; i < ARRAY_SIZE(amdgpu_debugfs_ring_info_list); ++i) {
+ struct drm_info_list *info = &amdgpu_debugfs_ring_info_list[i];
+ int roffset = *(int*)amdgpu_debugfs_ring_info_list[i].data;
+ struct amdgpu_ring *other = (void *)(((uint8_t*)adev) + roffset);
+ unsigned r;
+
+ if (other != ring)
+ continue;
+
+ r = amdgpu_debugfs_add_files(adev, info, 1);
+ if (r)
+ return r;
+ }
+#endif
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c
new file mode 100644
index 000000000000..eb20987ce18d
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ * Jerome Glisse <glisse@freedesktop.org>
+ */
+/* Algorithm:
+ *
+ * We store the last allocated bo in "hole", we always try to allocate
+ * after the last allocated bo. Principle is that in a linear GPU ring
+ * progression was is after last is the oldest bo we allocated and thus
+ * the first one that should no longer be in use by the GPU.
+ *
+ * If it's not the case we skip over the bo after last to the closest
+ * done bo if such one exist. If none exist and we are not asked to
+ * block we report failure to allocate.
+ *
+ * If we are asked to block we wait on all the oldest fence of all
+ * rings. We just wait for any of those fence to complete.
+ */
+#include <drm/drmP.h>
+#include "amdgpu.h"
+
+static void amdgpu_sa_bo_remove_locked(struct amdgpu_sa_bo *sa_bo);
+static void amdgpu_sa_bo_try_free(struct amdgpu_sa_manager *sa_manager);
+
+int amdgpu_sa_bo_manager_init(struct amdgpu_device *adev,
+ struct amdgpu_sa_manager *sa_manager,
+ unsigned size, u32 align, u32 domain)
+{
+ int i, r;
+
+ init_waitqueue_head(&sa_manager->wq);
+ sa_manager->bo = NULL;
+ sa_manager->size = size;
+ sa_manager->domain = domain;
+ sa_manager->align = align;
+ sa_manager->hole = &sa_manager->olist;
+ INIT_LIST_HEAD(&sa_manager->olist);
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ INIT_LIST_HEAD(&sa_manager->flist[i]);
+ }
+
+ r = amdgpu_bo_create(adev, size, align, true,
+ domain, 0, NULL, &sa_manager->bo);
+ if (r) {
+ dev_err(adev->dev, "(%d) failed to allocate bo for manager\n", r);
+ return r;
+ }
+
+ return r;
+}
+
+void amdgpu_sa_bo_manager_fini(struct amdgpu_device *adev,
+ struct amdgpu_sa_manager *sa_manager)
+{
+ struct amdgpu_sa_bo *sa_bo, *tmp;
+
+ if (!list_empty(&sa_manager->olist)) {
+ sa_manager->hole = &sa_manager->olist,
+ amdgpu_sa_bo_try_free(sa_manager);
+ if (!list_empty(&sa_manager->olist)) {
+ dev_err(adev->dev, "sa_manager is not empty, clearing anyway\n");
+ }
+ }
+ list_for_each_entry_safe(sa_bo, tmp, &sa_manager->olist, olist) {
+ amdgpu_sa_bo_remove_locked(sa_bo);
+ }
+ amdgpu_bo_unref(&sa_manager->bo);
+ sa_manager->size = 0;
+}
+
+int amdgpu_sa_bo_manager_start(struct amdgpu_device *adev,
+ struct amdgpu_sa_manager *sa_manager)
+{
+ int r;
+
+ if (sa_manager->bo == NULL) {
+ dev_err(adev->dev, "no bo for sa manager\n");
+ return -EINVAL;
+ }
+
+ /* map the buffer */
+ r = amdgpu_bo_reserve(sa_manager->bo, false);
+ if (r) {
+ dev_err(adev->dev, "(%d) failed to reserve manager bo\n", r);
+ return r;
+ }
+ r = amdgpu_bo_pin(sa_manager->bo, sa_manager->domain, &sa_manager->gpu_addr);
+ if (r) {
+ amdgpu_bo_unreserve(sa_manager->bo);
+ dev_err(adev->dev, "(%d) failed to pin manager bo\n", r);
+ return r;
+ }
+ r = amdgpu_bo_kmap(sa_manager->bo, &sa_manager->cpu_ptr);
+ amdgpu_bo_unreserve(sa_manager->bo);
+ return r;
+}
+
+int amdgpu_sa_bo_manager_suspend(struct amdgpu_device *adev,
+ struct amdgpu_sa_manager *sa_manager)
+{
+ int r;
+
+ if (sa_manager->bo == NULL) {
+ dev_err(adev->dev, "no bo for sa manager\n");
+ return -EINVAL;
+ }
+
+ r = amdgpu_bo_reserve(sa_manager->bo, false);
+ if (!r) {
+ amdgpu_bo_kunmap(sa_manager->bo);
+ amdgpu_bo_unpin(sa_manager->bo);
+ amdgpu_bo_unreserve(sa_manager->bo);
+ }
+ return r;
+}
+
+static void amdgpu_sa_bo_remove_locked(struct amdgpu_sa_bo *sa_bo)
+{
+ struct amdgpu_sa_manager *sa_manager = sa_bo->manager;
+ if (sa_manager->hole == &sa_bo->olist) {
+ sa_manager->hole = sa_bo->olist.prev;
+ }
+ list_del_init(&sa_bo->olist);
+ list_del_init(&sa_bo->flist);
+ amdgpu_fence_unref(&sa_bo->fence);
+ kfree(sa_bo);
+}
+
+static void amdgpu_sa_bo_try_free(struct amdgpu_sa_manager *sa_manager)
+{
+ struct amdgpu_sa_bo *sa_bo, *tmp;
+
+ if (sa_manager->hole->next == &sa_manager->olist)
+ return;
+
+ sa_bo = list_entry(sa_manager->hole->next, struct amdgpu_sa_bo, olist);
+ list_for_each_entry_safe_from(sa_bo, tmp, &sa_manager->olist, olist) {
+ if (sa_bo->fence == NULL || !amdgpu_fence_signaled(sa_bo->fence)) {
+ return;
+ }
+ amdgpu_sa_bo_remove_locked(sa_bo);
+ }
+}
+
+static inline unsigned amdgpu_sa_bo_hole_soffset(struct amdgpu_sa_manager *sa_manager)
+{
+ struct list_head *hole = sa_manager->hole;
+
+ if (hole != &sa_manager->olist) {
+ return list_entry(hole, struct amdgpu_sa_bo, olist)->eoffset;
+ }
+ return 0;
+}
+
+static inline unsigned amdgpu_sa_bo_hole_eoffset(struct amdgpu_sa_manager *sa_manager)
+{
+ struct list_head *hole = sa_manager->hole;
+
+ if (hole->next != &sa_manager->olist) {
+ return list_entry(hole->next, struct amdgpu_sa_bo, olist)->soffset;
+ }
+ return sa_manager->size;
+}
+
+static bool amdgpu_sa_bo_try_alloc(struct amdgpu_sa_manager *sa_manager,
+ struct amdgpu_sa_bo *sa_bo,
+ unsigned size, unsigned align)
+{
+ unsigned soffset, eoffset, wasted;
+
+ soffset = amdgpu_sa_bo_hole_soffset(sa_manager);
+ eoffset = amdgpu_sa_bo_hole_eoffset(sa_manager);
+ wasted = (align - (soffset % align)) % align;
+
+ if ((eoffset - soffset) >= (size + wasted)) {
+ soffset += wasted;
+
+ sa_bo->manager = sa_manager;
+ sa_bo->soffset = soffset;
+ sa_bo->eoffset = soffset + size;
+ list_add(&sa_bo->olist, sa_manager->hole);
+ INIT_LIST_HEAD(&sa_bo->flist);
+ sa_manager->hole = &sa_bo->olist;
+ return true;
+ }
+ return false;
+}
+
+/**
+ * amdgpu_sa_event - Check if we can stop waiting
+ *
+ * @sa_manager: pointer to the sa_manager
+ * @size: number of bytes we want to allocate
+ * @align: alignment we need to match
+ *
+ * Check if either there is a fence we can wait for or
+ * enough free memory to satisfy the allocation directly
+ */
+static bool amdgpu_sa_event(struct amdgpu_sa_manager *sa_manager,
+ unsigned size, unsigned align)
+{
+ unsigned soffset, eoffset, wasted;
+ int i;
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ if (!list_empty(&sa_manager->flist[i])) {
+ return true;
+ }
+ }
+
+ soffset = amdgpu_sa_bo_hole_soffset(sa_manager);
+ eoffset = amdgpu_sa_bo_hole_eoffset(sa_manager);
+ wasted = (align - (soffset % align)) % align;
+
+ if ((eoffset - soffset) >= (size + wasted)) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool amdgpu_sa_bo_next_hole(struct amdgpu_sa_manager *sa_manager,
+ struct amdgpu_fence **fences,
+ unsigned *tries)
+{
+ struct amdgpu_sa_bo *best_bo = NULL;
+ unsigned i, soffset, best, tmp;
+
+ /* if hole points to the end of the buffer */
+ if (sa_manager->hole->next == &sa_manager->olist) {
+ /* try again with its beginning */
+ sa_manager->hole = &sa_manager->olist;
+ return true;
+ }
+
+ soffset = amdgpu_sa_bo_hole_soffset(sa_manager);
+ /* to handle wrap around we add sa_manager->size */
+ best = sa_manager->size * 2;
+ /* go over all fence list and try to find the closest sa_bo
+ * of the current last
+ */
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_sa_bo *sa_bo;
+
+ if (list_empty(&sa_manager->flist[i])) {
+ continue;
+ }
+
+ sa_bo = list_first_entry(&sa_manager->flist[i],
+ struct amdgpu_sa_bo, flist);
+
+ if (!amdgpu_fence_signaled(sa_bo->fence)) {
+ fences[i] = sa_bo->fence;
+ continue;
+ }
+
+ /* limit the number of tries each ring gets */
+ if (tries[i] > 2) {
+ continue;
+ }
+
+ tmp = sa_bo->soffset;
+ if (tmp < soffset) {
+ /* wrap around, pretend it's after */
+ tmp += sa_manager->size;
+ }
+ tmp -= soffset;
+ if (tmp < best) {
+ /* this sa bo is the closest one */
+ best = tmp;
+ best_bo = sa_bo;
+ }
+ }
+
+ if (best_bo) {
+ ++tries[best_bo->fence->ring->idx];
+ sa_manager->hole = best_bo->olist.prev;
+
+ /* we knew that this one is signaled,
+ so it's save to remote it */
+ amdgpu_sa_bo_remove_locked(best_bo);
+ return true;
+ }
+ return false;
+}
+
+int amdgpu_sa_bo_new(struct amdgpu_device *adev,
+ struct amdgpu_sa_manager *sa_manager,
+ struct amdgpu_sa_bo **sa_bo,
+ unsigned size, unsigned align)
+{
+ struct amdgpu_fence *fences[AMDGPU_MAX_RINGS];
+ unsigned tries[AMDGPU_MAX_RINGS];
+ int i, r;
+
+ BUG_ON(align > sa_manager->align);
+ BUG_ON(size > sa_manager->size);
+
+ *sa_bo = kmalloc(sizeof(struct amdgpu_sa_bo), GFP_KERNEL);
+ if ((*sa_bo) == NULL) {
+ return -ENOMEM;
+ }
+ (*sa_bo)->manager = sa_manager;
+ (*sa_bo)->fence = NULL;
+ INIT_LIST_HEAD(&(*sa_bo)->olist);
+ INIT_LIST_HEAD(&(*sa_bo)->flist);
+
+ spin_lock(&sa_manager->wq.lock);
+ do {
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ fences[i] = NULL;
+ tries[i] = 0;
+ }
+
+ do {
+ amdgpu_sa_bo_try_free(sa_manager);
+
+ if (amdgpu_sa_bo_try_alloc(sa_manager, *sa_bo,
+ size, align)) {
+ spin_unlock(&sa_manager->wq.lock);
+ return 0;
+ }
+
+ /* see if we can skip over some allocations */
+ } while (amdgpu_sa_bo_next_hole(sa_manager, fences, tries));
+
+ spin_unlock(&sa_manager->wq.lock);
+ r = amdgpu_fence_wait_any(adev, fences, false);
+ spin_lock(&sa_manager->wq.lock);
+ /* if we have nothing to wait for block */
+ if (r == -ENOENT) {
+ r = wait_event_interruptible_locked(
+ sa_manager->wq,
+ amdgpu_sa_event(sa_manager, size, align)
+ );
+ }
+
+ } while (!r);
+
+ spin_unlock(&sa_manager->wq.lock);
+ kfree(*sa_bo);
+ *sa_bo = NULL;
+ return r;
+}
+
+void amdgpu_sa_bo_free(struct amdgpu_device *adev, struct amdgpu_sa_bo **sa_bo,
+ struct amdgpu_fence *fence)
+{
+ struct amdgpu_sa_manager *sa_manager;
+
+ if (sa_bo == NULL || *sa_bo == NULL) {
+ return;
+ }
+
+ sa_manager = (*sa_bo)->manager;
+ spin_lock(&sa_manager->wq.lock);
+ if (fence && !amdgpu_fence_signaled(fence)) {
+ (*sa_bo)->fence = amdgpu_fence_ref(fence);
+ list_add_tail(&(*sa_bo)->flist,
+ &sa_manager->flist[fence->ring->idx]);
+ } else {
+ amdgpu_sa_bo_remove_locked(*sa_bo);
+ }
+ wake_up_all_locked(&sa_manager->wq);
+ spin_unlock(&sa_manager->wq.lock);
+ *sa_bo = NULL;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+void amdgpu_sa_bo_dump_debug_info(struct amdgpu_sa_manager *sa_manager,
+ struct seq_file *m)
+{
+ struct amdgpu_sa_bo *i;
+
+ spin_lock(&sa_manager->wq.lock);
+ list_for_each_entry(i, &sa_manager->olist, olist) {
+ uint64_t soffset = i->soffset + sa_manager->gpu_addr;
+ uint64_t eoffset = i->eoffset + sa_manager->gpu_addr;
+ if (&i->olist == sa_manager->hole) {
+ seq_printf(m, ">");
+ } else {
+ seq_printf(m, " ");
+ }
+ seq_printf(m, "[0x%010llx 0x%010llx] size %8lld",
+ soffset, eoffset, eoffset - soffset);
+ if (i->fence) {
+ seq_printf(m, " protected by 0x%016llx on ring %d",
+ i->fence->seq, i->fence->ring->idx);
+ }
+ seq_printf(m, "\n");
+ }
+ spin_unlock(&sa_manager->wq.lock);
+}
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c
new file mode 100644
index 000000000000..d6d41a42ab65
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2011 Christian König.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ * Christian König <deathsimple@vodafone.de>
+ */
+#include <drm/drmP.h>
+#include "amdgpu.h"
+#include "amdgpu_trace.h"
+
+int amdgpu_semaphore_create(struct amdgpu_device *adev,
+ struct amdgpu_semaphore **semaphore)
+{
+ int r;
+
+ *semaphore = kmalloc(sizeof(struct amdgpu_semaphore), GFP_KERNEL);
+ if (*semaphore == NULL) {
+ return -ENOMEM;
+ }
+ r = amdgpu_sa_bo_new(adev, &adev->ring_tmp_bo,
+ &(*semaphore)->sa_bo, 8, 8);
+ if (r) {
+ kfree(*semaphore);
+ *semaphore = NULL;
+ return r;
+ }
+ (*semaphore)->waiters = 0;
+ (*semaphore)->gpu_addr = amdgpu_sa_bo_gpu_addr((*semaphore)->sa_bo);
+
+ *((uint64_t *)amdgpu_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0;
+
+ return 0;
+}
+
+bool amdgpu_semaphore_emit_signal(struct amdgpu_ring *ring,
+ struct amdgpu_semaphore *semaphore)
+{
+ trace_amdgpu_semaphore_signale(ring->idx, semaphore);
+
+ if (amdgpu_ring_emit_semaphore(ring, semaphore, false)) {
+ --semaphore->waiters;
+
+ /* for debugging lockup only, used by sysfs debug files */
+ ring->last_semaphore_signal_addr = semaphore->gpu_addr;
+ return true;
+ }
+ return false;
+}
+
+bool amdgpu_semaphore_emit_wait(struct amdgpu_ring *ring,
+ struct amdgpu_semaphore *semaphore)
+{
+ trace_amdgpu_semaphore_wait(ring->idx, semaphore);
+
+ if (amdgpu_ring_emit_semaphore(ring, semaphore, true)) {
+ ++semaphore->waiters;
+
+ /* for debugging lockup only, used by sysfs debug files */
+ ring->last_semaphore_wait_addr = semaphore->gpu_addr;
+ return true;
+ }
+ return false;
+}
+
+void amdgpu_semaphore_free(struct amdgpu_device *adev,
+ struct amdgpu_semaphore **semaphore,
+ struct amdgpu_fence *fence)
+{
+ if (semaphore == NULL || *semaphore == NULL) {
+ return;
+ }
+ if ((*semaphore)->waiters > 0) {
+ dev_err(adev->dev, "semaphore %p has more waiters than signalers,"
+ " hardware lockup imminent!\n", *semaphore);
+ }
+ amdgpu_sa_bo_free(adev, &(*semaphore)->sa_bo, fence);
+ kfree(*semaphore);
+ *semaphore = NULL;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
new file mode 100644
index 000000000000..21accbdd0a1a
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ * Christian König <christian.koenig@amd.com>
+ */
+
+#include <drm/drmP.h>
+#include "amdgpu.h"
+#include "amdgpu_trace.h"
+
+/**
+ * amdgpu_sync_create - zero init sync object
+ *
+ * @sync: sync object to initialize
+ *
+ * Just clear the sync object for now.
+ */
+void amdgpu_sync_create(struct amdgpu_sync *sync)
+{
+ unsigned i;
+
+ for (i = 0; i < AMDGPU_NUM_SYNCS; ++i)
+ sync->semaphores[i] = NULL;
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
+ sync->sync_to[i] = NULL;
+
+ sync->last_vm_update = NULL;
+}
+
+/**
+ * amdgpu_sync_fence - use the semaphore to sync to a fence
+ *
+ * @sync: sync object to add fence to
+ * @fence: fence to sync to
+ *
+ * Sync to the fence using the semaphore objects
+ */
+void amdgpu_sync_fence(struct amdgpu_sync *sync,
+ struct amdgpu_fence *fence)
+{
+ struct amdgpu_fence *other;
+
+ if (!fence)
+ return;
+
+ other = sync->sync_to[fence->ring->idx];
+ sync->sync_to[fence->ring->idx] = amdgpu_fence_ref(
+ amdgpu_fence_later(fence, other));
+ amdgpu_fence_unref(&other);
+
+ if (fence->owner == AMDGPU_FENCE_OWNER_VM) {
+ other = sync->last_vm_update;
+ sync->last_vm_update = amdgpu_fence_ref(
+ amdgpu_fence_later(fence, other));
+ amdgpu_fence_unref(&other);
+ }
+}
+
+/**
+ * amdgpu_sync_resv - use the semaphores to sync to a reservation object
+ *
+ * @sync: sync object to add fences from reservation object to
+ * @resv: reservation object with embedded fence
+ * @shared: true if we should only sync to the exclusive fence
+ *
+ * Sync to the fence using the semaphore objects
+ */
+int amdgpu_sync_resv(struct amdgpu_device *adev,
+ struct amdgpu_sync *sync,
+ struct reservation_object *resv,
+ void *owner)
+{
+ struct reservation_object_list *flist;
+ struct fence *f;
+ struct amdgpu_fence *fence;
+ unsigned i;
+ int r = 0;
+
+ if (resv == NULL)
+ return -EINVAL;
+
+ /* always sync to the exclusive fence */
+ f = reservation_object_get_excl(resv);
+ fence = f ? to_amdgpu_fence(f) : NULL;
+ if (fence && fence->ring->adev == adev)
+ amdgpu_sync_fence(sync, fence);
+ else if (f)
+ r = fence_wait(f, true);
+
+ flist = reservation_object_get_list(resv);
+ if (!flist || r)
+ return r;
+
+ for (i = 0; i < flist->shared_count; ++i) {
+ f = rcu_dereference_protected(flist->shared[i],
+ reservation_object_held(resv));
+ fence = f ? to_amdgpu_fence(f) : NULL;
+ if (fence && fence->ring->adev == adev) {
+ if (fence->owner != owner ||
+ fence->owner == AMDGPU_FENCE_OWNER_UNDEFINED)
+ amdgpu_sync_fence(sync, fence);
+ } else if (f) {
+ r = fence_wait(f, true);
+ if (r)
+ break;
+ }
+ }
+ return r;
+}
+
+/**
+ * amdgpu_sync_rings - sync ring to all registered fences
+ *
+ * @sync: sync object to use
+ * @ring: ring that needs sync
+ *
+ * Ensure that all registered fences are signaled before letting
+ * the ring continue. The caller must hold the ring lock.
+ */
+int amdgpu_sync_rings(struct amdgpu_sync *sync,
+ struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ unsigned count = 0;
+ int i, r;
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_fence *fence = sync->sync_to[i];
+ struct amdgpu_semaphore *semaphore;
+ struct amdgpu_ring *other = adev->rings[i];
+
+ /* check if we really need to sync */
+ if (!amdgpu_fence_need_sync(fence, ring))
+ continue;
+
+ /* prevent GPU deadlocks */
+ if (!other->ready) {
+ dev_err(adev->dev, "Syncing to a disabled ring!");
+ return -EINVAL;
+ }
+
+ if (count >= AMDGPU_NUM_SYNCS) {
+ /* not enough room, wait manually */
+ r = amdgpu_fence_wait(fence, false);
+ if (r)
+ return r;
+ continue;
+ }
+ r = amdgpu_semaphore_create(adev, &semaphore);
+ if (r)
+ return r;
+
+ sync->semaphores[count++] = semaphore;
+
+ /* allocate enough space for sync command */
+ r = amdgpu_ring_alloc(other, 16);
+ if (r)
+ return r;
+
+ /* emit the signal semaphore */
+ if (!amdgpu_semaphore_emit_signal(other, semaphore)) {
+ /* signaling wasn't successful wait manually */
+ amdgpu_ring_undo(other);
+ r = amdgpu_fence_wait(fence, false);
+ if (r)
+ return r;
+ continue;
+ }
+
+ /* we assume caller has already allocated space on waiters ring */
+ if (!amdgpu_semaphore_emit_wait(ring, semaphore)) {
+ /* waiting wasn't successful wait manually */
+ amdgpu_ring_undo(other);
+ r = amdgpu_fence_wait(fence, false);
+ if (r)
+ return r;
+ continue;
+ }
+
+ amdgpu_ring_commit(other);
+ amdgpu_fence_note_sync(fence, ring);
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_sync_free - free the sync object
+ *
+ * @adev: amdgpu_device pointer
+ * @sync: sync object to use
+ * @fence: fence to use for the free
+ *
+ * Free the sync object by freeing all semaphores in it.
+ */
+void amdgpu_sync_free(struct amdgpu_device *adev,
+ struct amdgpu_sync *sync,
+ struct amdgpu_fence *fence)
+{
+ unsigned i;
+
+ for (i = 0; i < AMDGPU_NUM_SYNCS; ++i)
+ amdgpu_semaphore_free(adev, &sync->semaphores[i], fence);
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
+ amdgpu_fence_unref(&sync->sync_to[i]);
+
+ amdgpu_fence_unref(&sync->last_vm_update);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c
new file mode 100644
index 000000000000..df202999fbfe
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright 2009 VMware, 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: Michel Dänzer
+ */
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "amdgpu_uvd.h"
+#include "amdgpu_vce.h"
+
+/* Test BO GTT->VRAM and VRAM->GTT GPU copies across the whole GTT aperture */
+static void amdgpu_do_test_moves(struct amdgpu_device *adev)
+{
+ struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
+ struct amdgpu_bo *vram_obj = NULL;
+ struct amdgpu_bo **gtt_obj = NULL;
+ uint64_t gtt_addr, vram_addr;
+ unsigned n, size;
+ int i, r;
+
+ size = 1024 * 1024;
+
+ /* Number of tests =
+ * (Total GTT - IB pool - writeback page - ring buffers) / test size
+ */
+ n = adev->mc.gtt_size - AMDGPU_IB_POOL_SIZE*64*1024;
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
+ if (adev->rings[i])
+ n -= adev->rings[i]->ring_size;
+ if (adev->wb.wb_obj)
+ n -= AMDGPU_GPU_PAGE_SIZE;
+ if (adev->irq.ih.ring_obj)
+ n -= adev->irq.ih.ring_size;
+ n /= size;
+
+ gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL);
+ if (!gtt_obj) {
+ DRM_ERROR("Failed to allocate %d pointers\n", n);
+ r = 1;
+ goto out_cleanup;
+ }
+
+ r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, 0,
+ NULL, &vram_obj);
+ if (r) {
+ DRM_ERROR("Failed to create VRAM object\n");
+ goto out_cleanup;
+ }
+ r = amdgpu_bo_reserve(vram_obj, false);
+ if (unlikely(r != 0))
+ goto out_unref;
+ r = amdgpu_bo_pin(vram_obj, AMDGPU_GEM_DOMAIN_VRAM, &vram_addr);
+ if (r) {
+ DRM_ERROR("Failed to pin VRAM object\n");
+ goto out_unres;
+ }
+ for (i = 0; i < n; i++) {
+ void *gtt_map, *vram_map;
+ void **gtt_start, **gtt_end;
+ void **vram_start, **vram_end;
+ struct amdgpu_fence *fence = NULL;
+
+ r = amdgpu_bo_create(adev, size, PAGE_SIZE, true,
+ AMDGPU_GEM_DOMAIN_GTT, 0, NULL, gtt_obj + i);
+ if (r) {
+ DRM_ERROR("Failed to create GTT object %d\n", i);
+ goto out_lclean;
+ }
+
+ r = amdgpu_bo_reserve(gtt_obj[i], false);
+ if (unlikely(r != 0))
+ goto out_lclean_unref;
+ r = amdgpu_bo_pin(gtt_obj[i], AMDGPU_GEM_DOMAIN_GTT, &gtt_addr);
+ if (r) {
+ DRM_ERROR("Failed to pin GTT object %d\n", i);
+ goto out_lclean_unres;
+ }
+
+ r = amdgpu_bo_kmap(gtt_obj[i], &gtt_map);
+ if (r) {
+ DRM_ERROR("Failed to map GTT object %d\n", i);
+ goto out_lclean_unpin;
+ }
+
+ for (gtt_start = gtt_map, gtt_end = gtt_map + size;
+ gtt_start < gtt_end;
+ gtt_start++)
+ *gtt_start = gtt_start;
+
+ amdgpu_bo_kunmap(gtt_obj[i]);
+
+ r = amdgpu_copy_buffer(ring, gtt_addr, vram_addr,
+ size, NULL, &fence);
+
+ if (r) {
+ DRM_ERROR("Failed GTT->VRAM copy %d\n", i);
+ goto out_lclean_unpin;
+ }
+
+ r = amdgpu_fence_wait(fence, false);
+ if (r) {
+ DRM_ERROR("Failed to wait for GTT->VRAM fence %d\n", i);
+ goto out_lclean_unpin;
+ }
+
+ amdgpu_fence_unref(&fence);
+
+ r = amdgpu_bo_kmap(vram_obj, &vram_map);
+ if (r) {
+ DRM_ERROR("Failed to map VRAM object after copy %d\n", i);
+ goto out_lclean_unpin;
+ }
+
+ for (gtt_start = gtt_map, gtt_end = gtt_map + size,
+ vram_start = vram_map, vram_end = vram_map + size;
+ vram_start < vram_end;
+ gtt_start++, vram_start++) {
+ if (*vram_start != gtt_start) {
+ DRM_ERROR("Incorrect GTT->VRAM copy %d: Got 0x%p, "
+ "expected 0x%p (GTT/VRAM offset "
+ "0x%16llx/0x%16llx)\n",
+ i, *vram_start, gtt_start,
+ (unsigned long long)
+ (gtt_addr - adev->mc.gtt_start +
+ (void*)gtt_start - gtt_map),
+ (unsigned long long)
+ (vram_addr - adev->mc.vram_start +
+ (void*)gtt_start - gtt_map));
+ amdgpu_bo_kunmap(vram_obj);
+ goto out_lclean_unpin;
+ }
+ *vram_start = vram_start;
+ }
+
+ amdgpu_bo_kunmap(vram_obj);
+
+ r = amdgpu_copy_buffer(ring, vram_addr, gtt_addr,
+ size, NULL, &fence);
+
+ if (r) {
+ DRM_ERROR("Failed VRAM->GTT copy %d\n", i);
+ goto out_lclean_unpin;
+ }
+
+ r = amdgpu_fence_wait(fence, false);
+ if (r) {
+ DRM_ERROR("Failed to wait for VRAM->GTT fence %d\n", i);
+ goto out_lclean_unpin;
+ }
+
+ amdgpu_fence_unref(&fence);
+
+ r = amdgpu_bo_kmap(gtt_obj[i], &gtt_map);
+ if (r) {
+ DRM_ERROR("Failed to map GTT object after copy %d\n", i);
+ goto out_lclean_unpin;
+ }
+
+ for (gtt_start = gtt_map, gtt_end = gtt_map + size,
+ vram_start = vram_map, vram_end = vram_map + size;
+ gtt_start < gtt_end;
+ gtt_start++, vram_start++) {
+ if (*gtt_start != vram_start) {
+ DRM_ERROR("Incorrect VRAM->GTT copy %d: Got 0x%p, "
+ "expected 0x%p (VRAM/GTT offset "
+ "0x%16llx/0x%16llx)\n",
+ i, *gtt_start, vram_start,
+ (unsigned long long)
+ (vram_addr - adev->mc.vram_start +
+ (void*)vram_start - vram_map),
+ (unsigned long long)
+ (gtt_addr - adev->mc.gtt_start +
+ (void*)vram_start - vram_map));
+ amdgpu_bo_kunmap(gtt_obj[i]);
+ goto out_lclean_unpin;
+ }
+ }
+
+ amdgpu_bo_kunmap(gtt_obj[i]);
+
+ DRM_INFO("Tested GTT->VRAM and VRAM->GTT copy for GTT offset 0x%llx\n",
+ gtt_addr - adev->mc.gtt_start);
+ continue;
+
+out_lclean_unpin:
+ amdgpu_bo_unpin(gtt_obj[i]);
+out_lclean_unres:
+ amdgpu_bo_unreserve(gtt_obj[i]);
+out_lclean_unref:
+ amdgpu_bo_unref(&gtt_obj[i]);
+out_lclean:
+ for (--i; i >= 0; --i) {
+ amdgpu_bo_unpin(gtt_obj[i]);
+ amdgpu_bo_unreserve(gtt_obj[i]);
+ amdgpu_bo_unref(&gtt_obj[i]);
+ }
+ if (fence)
+ amdgpu_fence_unref(&fence);
+ break;
+ }
+
+ amdgpu_bo_unpin(vram_obj);
+out_unres:
+ amdgpu_bo_unreserve(vram_obj);
+out_unref:
+ amdgpu_bo_unref(&vram_obj);
+out_cleanup:
+ kfree(gtt_obj);
+ if (r) {
+ printk(KERN_WARNING "Error while testing BO move.\n");
+ }
+}
+
+void amdgpu_test_moves(struct amdgpu_device *adev)
+{
+ if (adev->mman.buffer_funcs)
+ amdgpu_do_test_moves(adev);
+}
+
+static int amdgpu_test_create_and_emit_fence(struct amdgpu_device *adev,
+ struct amdgpu_ring *ring,
+ struct amdgpu_fence **fence)
+{
+ uint32_t handle = ring->idx ^ 0xdeafbeef;
+ int r;
+
+ if (ring == &adev->uvd.ring) {
+ r = amdgpu_uvd_get_create_msg(ring, handle, NULL);
+ if (r) {
+ DRM_ERROR("Failed to get dummy create msg\n");
+ return r;
+ }
+
+ r = amdgpu_uvd_get_destroy_msg(ring, handle, fence);
+ if (r) {
+ DRM_ERROR("Failed to get dummy destroy msg\n");
+ return r;
+ }
+
+ } else if (ring == &adev->vce.ring[0] ||
+ ring == &adev->vce.ring[1]) {
+ r = amdgpu_vce_get_create_msg(ring, handle, NULL);
+ if (r) {
+ DRM_ERROR("Failed to get dummy create msg\n");
+ return r;
+ }
+
+ r = amdgpu_vce_get_destroy_msg(ring, handle, fence);
+ if (r) {
+ DRM_ERROR("Failed to get dummy destroy msg\n");
+ return r;
+ }
+
+ } else {
+ r = amdgpu_ring_lock(ring, 64);
+ if (r) {
+ DRM_ERROR("Failed to lock ring A %d\n", ring->idx);
+ return r;
+ }
+ amdgpu_fence_emit(ring, AMDGPU_FENCE_OWNER_UNDEFINED, fence);
+ amdgpu_ring_unlock_commit(ring);
+ }
+ return 0;
+}
+
+void amdgpu_test_ring_sync(struct amdgpu_device *adev,
+ struct amdgpu_ring *ringA,
+ struct amdgpu_ring *ringB)
+{
+ struct amdgpu_fence *fence1 = NULL, *fence2 = NULL;
+ struct amdgpu_semaphore *semaphore = NULL;
+ int r;
+
+ r = amdgpu_semaphore_create(adev, &semaphore);
+ if (r) {
+ DRM_ERROR("Failed to create semaphore\n");
+ goto out_cleanup;
+ }
+
+ r = amdgpu_ring_lock(ringA, 64);
+ if (r) {
+ DRM_ERROR("Failed to lock ring A %d\n", ringA->idx);
+ goto out_cleanup;
+ }
+ amdgpu_semaphore_emit_wait(ringA, semaphore);
+ amdgpu_ring_unlock_commit(ringA);
+
+ r = amdgpu_test_create_and_emit_fence(adev, ringA, &fence1);
+ if (r)
+ goto out_cleanup;
+
+ r = amdgpu_ring_lock(ringA, 64);
+ if (r) {
+ DRM_ERROR("Failed to lock ring A %d\n", ringA->idx);
+ goto out_cleanup;
+ }
+ amdgpu_semaphore_emit_wait(ringA, semaphore);
+ amdgpu_ring_unlock_commit(ringA);
+
+ r = amdgpu_test_create_and_emit_fence(adev, ringA, &fence2);
+ if (r)
+ goto out_cleanup;
+
+ mdelay(1000);
+
+ if (amdgpu_fence_signaled(fence1)) {
+ DRM_ERROR("Fence 1 signaled without waiting for semaphore.\n");
+ goto out_cleanup;
+ }
+
+ r = amdgpu_ring_lock(ringB, 64);
+ if (r) {
+ DRM_ERROR("Failed to lock ring B %p\n", ringB);
+ goto out_cleanup;
+ }
+ amdgpu_semaphore_emit_signal(ringB, semaphore);
+ amdgpu_ring_unlock_commit(ringB);
+
+ r = amdgpu_fence_wait(fence1, false);
+ if (r) {
+ DRM_ERROR("Failed to wait for sync fence 1\n");
+ goto out_cleanup;
+ }
+
+ mdelay(1000);
+
+ if (amdgpu_fence_signaled(fence2)) {
+ DRM_ERROR("Fence 2 signaled without waiting for semaphore.\n");
+ goto out_cleanup;
+ }
+
+ r = amdgpu_ring_lock(ringB, 64);
+ if (r) {
+ DRM_ERROR("Failed to lock ring B %p\n", ringB);
+ goto out_cleanup;
+ }
+ amdgpu_semaphore_emit_signal(ringB, semaphore);
+ amdgpu_ring_unlock_commit(ringB);
+
+ r = amdgpu_fence_wait(fence2, false);
+ if (r) {
+ DRM_ERROR("Failed to wait for sync fence 1\n");
+ goto out_cleanup;
+ }
+
+out_cleanup:
+ amdgpu_semaphore_free(adev, &semaphore, NULL);
+
+ if (fence1)
+ amdgpu_fence_unref(&fence1);
+
+ if (fence2)
+ amdgpu_fence_unref(&fence2);
+
+ if (r)
+ printk(KERN_WARNING "Error while testing ring sync (%d).\n", r);
+}
+
+static void amdgpu_test_ring_sync2(struct amdgpu_device *adev,
+ struct amdgpu_ring *ringA,
+ struct amdgpu_ring *ringB,
+ struct amdgpu_ring *ringC)
+{
+ struct amdgpu_fence *fenceA = NULL, *fenceB = NULL;
+ struct amdgpu_semaphore *semaphore = NULL;
+ bool sigA, sigB;
+ int i, r;
+
+ r = amdgpu_semaphore_create(adev, &semaphore);
+ if (r) {
+ DRM_ERROR("Failed to create semaphore\n");
+ goto out_cleanup;
+ }
+
+ r = amdgpu_ring_lock(ringA, 64);
+ if (r) {
+ DRM_ERROR("Failed to lock ring A %d\n", ringA->idx);
+ goto out_cleanup;
+ }
+ amdgpu_semaphore_emit_wait(ringA, semaphore);
+ amdgpu_ring_unlock_commit(ringA);
+
+ r = amdgpu_test_create_and_emit_fence(adev, ringA, &fenceA);
+ if (r)
+ goto out_cleanup;
+
+ r = amdgpu_ring_lock(ringB, 64);
+ if (r) {
+ DRM_ERROR("Failed to lock ring B %d\n", ringB->idx);
+ goto out_cleanup;
+ }
+ amdgpu_semaphore_emit_wait(ringB, semaphore);
+ amdgpu_ring_unlock_commit(ringB);
+ r = amdgpu_test_create_and_emit_fence(adev, ringB, &fenceB);
+ if (r)
+ goto out_cleanup;
+
+ mdelay(1000);
+
+ if (amdgpu_fence_signaled(fenceA)) {
+ DRM_ERROR("Fence A signaled without waiting for semaphore.\n");
+ goto out_cleanup;
+ }
+ if (amdgpu_fence_signaled(fenceB)) {
+ DRM_ERROR("Fence B signaled without waiting for semaphore.\n");
+ goto out_cleanup;
+ }
+
+ r = amdgpu_ring_lock(ringC, 64);
+ if (r) {
+ DRM_ERROR("Failed to lock ring B %p\n", ringC);
+ goto out_cleanup;
+ }
+ amdgpu_semaphore_emit_signal(ringC, semaphore);
+ amdgpu_ring_unlock_commit(ringC);
+
+ for (i = 0; i < 30; ++i) {
+ mdelay(100);
+ sigA = amdgpu_fence_signaled(fenceA);
+ sigB = amdgpu_fence_signaled(fenceB);
+ if (sigA || sigB)
+ break;
+ }
+
+ if (!sigA && !sigB) {
+ DRM_ERROR("Neither fence A nor B has been signaled\n");
+ goto out_cleanup;
+ } else if (sigA && sigB) {
+ DRM_ERROR("Both fence A and B has been signaled\n");
+ goto out_cleanup;
+ }
+
+ DRM_INFO("Fence %c was first signaled\n", sigA ? 'A' : 'B');
+
+ r = amdgpu_ring_lock(ringC, 64);
+ if (r) {
+ DRM_ERROR("Failed to lock ring B %p\n", ringC);
+ goto out_cleanup;
+ }
+ amdgpu_semaphore_emit_signal(ringC, semaphore);
+ amdgpu_ring_unlock_commit(ringC);
+
+ mdelay(1000);
+
+ r = amdgpu_fence_wait(fenceA, false);
+ if (r) {
+ DRM_ERROR("Failed to wait for sync fence A\n");
+ goto out_cleanup;
+ }
+ r = amdgpu_fence_wait(fenceB, false);
+ if (r) {
+ DRM_ERROR("Failed to wait for sync fence B\n");
+ goto out_cleanup;
+ }
+
+out_cleanup:
+ amdgpu_semaphore_free(adev, &semaphore, NULL);
+
+ if (fenceA)
+ amdgpu_fence_unref(&fenceA);
+
+ if (fenceB)
+ amdgpu_fence_unref(&fenceB);
+
+ if (r)
+ printk(KERN_WARNING "Error while testing ring sync (%d).\n", r);
+}
+
+static bool amdgpu_test_sync_possible(struct amdgpu_ring *ringA,
+ struct amdgpu_ring *ringB)
+{
+ if (ringA == &ringA->adev->vce.ring[0] &&
+ ringB == &ringB->adev->vce.ring[1])
+ return false;
+
+ return true;
+}
+
+void amdgpu_test_syncing(struct amdgpu_device *adev)
+{
+ int i, j, k;
+
+ for (i = 1; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_ring *ringA = adev->rings[i];
+ if (!ringA || !ringA->ready)
+ continue;
+
+ for (j = 0; j < i; ++j) {
+ struct amdgpu_ring *ringB = adev->rings[j];
+ if (!ringB || !ringB->ready)
+ continue;
+
+ if (!amdgpu_test_sync_possible(ringA, ringB))
+ continue;
+
+ DRM_INFO("Testing syncing between rings %d and %d...\n", i, j);
+ amdgpu_test_ring_sync(adev, ringA, ringB);
+
+ DRM_INFO("Testing syncing between rings %d and %d...\n", j, i);
+ amdgpu_test_ring_sync(adev, ringB, ringA);
+
+ for (k = 0; k < j; ++k) {
+ struct amdgpu_ring *ringC = adev->rings[k];
+ if (!ringC || !ringC->ready)
+ continue;
+
+ if (!amdgpu_test_sync_possible(ringA, ringC))
+ continue;
+
+ if (!amdgpu_test_sync_possible(ringB, ringC))
+ continue;
+
+ DRM_INFO("Testing syncing between rings %d, %d and %d...\n", i, j, k);
+ amdgpu_test_ring_sync2(adev, ringA, ringB, ringC);
+
+ DRM_INFO("Testing syncing between rings %d, %d and %d...\n", i, k, j);
+ amdgpu_test_ring_sync2(adev, ringA, ringC, ringB);
+
+ DRM_INFO("Testing syncing between rings %d, %d and %d...\n", j, i, k);
+ amdgpu_test_ring_sync2(adev, ringB, ringA, ringC);
+
+ DRM_INFO("Testing syncing between rings %d, %d and %d...\n", j, k, i);
+ amdgpu_test_ring_sync2(adev, ringB, ringC, ringA);
+
+ DRM_INFO("Testing syncing between rings %d, %d and %d...\n", k, i, j);
+ amdgpu_test_ring_sync2(adev, ringC, ringA, ringB);
+
+ DRM_INFO("Testing syncing between rings %d, %d and %d...\n", k, j, i);
+ amdgpu_test_ring_sync2(adev, ringC, ringB, ringA);
+ }
+ }
+ }
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
new file mode 100644
index 000000000000..b56dd64bd4ea
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
@@ -0,0 +1,208 @@
+#if !defined(_AMDGPU_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _AMDGPU_TRACE_H_
+
+#include <linux/stringify.h>
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#include <drm/drmP.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM amdgpu
+#define TRACE_INCLUDE_FILE amdgpu_trace
+
+TRACE_EVENT(amdgpu_bo_create,
+ TP_PROTO(struct amdgpu_bo *bo),
+ TP_ARGS(bo),
+ TP_STRUCT__entry(
+ __field(struct amdgpu_bo *, bo)
+ __field(u32, pages)
+ ),
+
+ TP_fast_assign(
+ __entry->bo = bo;
+ __entry->pages = bo->tbo.num_pages;
+ ),
+ TP_printk("bo=%p, pages=%u", __entry->bo, __entry->pages)
+);
+
+TRACE_EVENT(amdgpu_cs,
+ TP_PROTO(struct amdgpu_cs_parser *p, int i),
+ TP_ARGS(p, i),
+ TP_STRUCT__entry(
+ __field(u32, ring)
+ __field(u32, dw)
+ __field(u32, fences)
+ ),
+
+ TP_fast_assign(
+ __entry->ring = p->ibs[i].ring->idx;
+ __entry->dw = p->ibs[i].length_dw;
+ __entry->fences = amdgpu_fence_count_emitted(
+ p->ibs[i].ring);
+ ),
+ TP_printk("ring=%u, dw=%u, fences=%u",
+ __entry->ring, __entry->dw,
+ __entry->fences)
+);
+
+TRACE_EVENT(amdgpu_vm_grab_id,
+ TP_PROTO(unsigned vmid, int ring),
+ TP_ARGS(vmid, ring),
+ TP_STRUCT__entry(
+ __field(u32, vmid)
+ __field(u32, ring)
+ ),
+
+ TP_fast_assign(
+ __entry->vmid = vmid;
+ __entry->ring = ring;
+ ),
+ TP_printk("vmid=%u, ring=%u", __entry->vmid, __entry->ring)
+);
+
+TRACE_EVENT(amdgpu_vm_bo_update,
+ TP_PROTO(struct amdgpu_bo_va_mapping *mapping),
+ TP_ARGS(mapping),
+ TP_STRUCT__entry(
+ __field(u64, soffset)
+ __field(u64, eoffset)
+ __field(u32, flags)
+ ),
+
+ TP_fast_assign(
+ __entry->soffset = mapping->it.start;
+ __entry->eoffset = mapping->it.last + 1;
+ __entry->flags = mapping->flags;
+ ),
+ TP_printk("soffs=%010llx, eoffs=%010llx, flags=%08x",
+ __entry->soffset, __entry->eoffset, __entry->flags)
+);
+
+TRACE_EVENT(amdgpu_vm_set_page,
+ TP_PROTO(uint64_t pe, uint64_t addr, unsigned count,
+ uint32_t incr, uint32_t flags),
+ TP_ARGS(pe, addr, count, incr, flags),
+ TP_STRUCT__entry(
+ __field(u64, pe)
+ __field(u64, addr)
+ __field(u32, count)
+ __field(u32, incr)
+ __field(u32, flags)
+ ),
+
+ TP_fast_assign(
+ __entry->pe = pe;
+ __entry->addr = addr;
+ __entry->count = count;
+ __entry->incr = incr;
+ __entry->flags = flags;
+ ),
+ TP_printk("pe=%010Lx, addr=%010Lx, incr=%u, flags=%08x, count=%u",
+ __entry->pe, __entry->addr, __entry->incr,
+ __entry->flags, __entry->count)
+);
+
+TRACE_EVENT(amdgpu_vm_flush,
+ TP_PROTO(uint64_t pd_addr, unsigned ring, unsigned id),
+ TP_ARGS(pd_addr, ring, id),
+ TP_STRUCT__entry(
+ __field(u64, pd_addr)
+ __field(u32, ring)
+ __field(u32, id)
+ ),
+
+ TP_fast_assign(
+ __entry->pd_addr = pd_addr;
+ __entry->ring = ring;
+ __entry->id = id;
+ ),
+ TP_printk("pd_addr=%010Lx, ring=%u, id=%u",
+ __entry->pd_addr, __entry->ring, __entry->id)
+);
+
+DECLARE_EVENT_CLASS(amdgpu_fence_request,
+
+ TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
+
+ TP_ARGS(dev, ring, seqno),
+
+ TP_STRUCT__entry(
+ __field(u32, dev)
+ __field(int, ring)
+ __field(u32, seqno)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dev->primary->index;
+ __entry->ring = ring;
+ __entry->seqno = seqno;
+ ),
+
+ TP_printk("dev=%u, ring=%d, seqno=%u",
+ __entry->dev, __entry->ring, __entry->seqno)
+);
+
+DEFINE_EVENT(amdgpu_fence_request, amdgpu_fence_emit,
+
+ TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
+
+ TP_ARGS(dev, ring, seqno)
+);
+
+DEFINE_EVENT(amdgpu_fence_request, amdgpu_fence_wait_begin,
+
+ TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
+
+ TP_ARGS(dev, ring, seqno)
+);
+
+DEFINE_EVENT(amdgpu_fence_request, amdgpu_fence_wait_end,
+
+ TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
+
+ TP_ARGS(dev, ring, seqno)
+);
+
+DECLARE_EVENT_CLASS(amdgpu_semaphore_request,
+
+ TP_PROTO(int ring, struct amdgpu_semaphore *sem),
+
+ TP_ARGS(ring, sem),
+
+ TP_STRUCT__entry(
+ __field(int, ring)
+ __field(signed, waiters)
+ __field(uint64_t, gpu_addr)
+ ),
+
+ TP_fast_assign(
+ __entry->ring = ring;
+ __entry->waiters = sem->waiters;
+ __entry->gpu_addr = sem->gpu_addr;
+ ),
+
+ TP_printk("ring=%u, waiters=%d, addr=%010Lx", __entry->ring,
+ __entry->waiters, __entry->gpu_addr)
+);
+
+DEFINE_EVENT(amdgpu_semaphore_request, amdgpu_semaphore_signale,
+
+ TP_PROTO(int ring, struct amdgpu_semaphore *sem),
+
+ TP_ARGS(ring, sem)
+);
+
+DEFINE_EVENT(amdgpu_semaphore_request, amdgpu_semaphore_wait,
+
+ TP_PROTO(int ring, struct amdgpu_semaphore *sem),
+
+ TP_ARGS(ring, sem)
+);
+
+#endif
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#include <trace/define_trace.h>
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace_points.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace_points.c
new file mode 100644
index 000000000000..385b7e1d72f9
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace_points.c
@@ -0,0 +1,9 @@
+/* Copyright Red Hat Inc 2010.
+ * Author : Dave Airlie <airlied@redhat.com>
+ */
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+
+#define CREATE_TRACE_POINTS
+#include "amdgpu_trace.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
new file mode 100644
index 000000000000..d3706a498293
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -0,0 +1,1215 @@
+/*
+ * Copyright 2009 Jerome Glisse.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ * Jerome Glisse <glisse@freedesktop.org>
+ * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
+ * Dave Airlie
+ */
+#include <ttm/ttm_bo_api.h>
+#include <ttm/ttm_bo_driver.h>
+#include <ttm/ttm_placement.h>
+#include <ttm/ttm_module.h>
+#include <ttm/ttm_page_alloc.h>
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/swiotlb.h>
+#include <linux/swap.h>
+#include <linux/pagemap.h>
+#include <linux/debugfs.h>
+#include "amdgpu.h"
+#include "bif/bif_4_1_d.h"
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+static int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev);
+static void amdgpu_ttm_debugfs_fini(struct amdgpu_device *adev);
+
+static struct amdgpu_device *amdgpu_get_adev(struct ttm_bo_device *bdev)
+{
+ struct amdgpu_mman *mman;
+ struct amdgpu_device *adev;
+
+ mman = container_of(bdev, struct amdgpu_mman, bdev);
+ adev = container_of(mman, struct amdgpu_device, mman);
+ return adev;
+}
+
+
+/*
+ * Global memory.
+ */
+static int amdgpu_ttm_mem_global_init(struct drm_global_reference *ref)
+{
+ return ttm_mem_global_init(ref->object);
+}
+
+static void amdgpu_ttm_mem_global_release(struct drm_global_reference *ref)
+{
+ ttm_mem_global_release(ref->object);
+}
+
+static int amdgpu_ttm_global_init(struct amdgpu_device *adev)
+{
+ struct drm_global_reference *global_ref;
+ int r;
+
+ adev->mman.mem_global_referenced = false;
+ global_ref = &adev->mman.mem_global_ref;
+ global_ref->global_type = DRM_GLOBAL_TTM_MEM;
+ global_ref->size = sizeof(struct ttm_mem_global);
+ global_ref->init = &amdgpu_ttm_mem_global_init;
+ global_ref->release = &amdgpu_ttm_mem_global_release;
+ r = drm_global_item_ref(global_ref);
+ if (r != 0) {
+ DRM_ERROR("Failed setting up TTM memory accounting "
+ "subsystem.\n");
+ return r;
+ }
+
+ adev->mman.bo_global_ref.mem_glob =
+ adev->mman.mem_global_ref.object;
+ global_ref = &adev->mman.bo_global_ref.ref;
+ global_ref->global_type = DRM_GLOBAL_TTM_BO;
+ global_ref->size = sizeof(struct ttm_bo_global);
+ global_ref->init = &ttm_bo_global_init;
+ global_ref->release = &ttm_bo_global_release;
+ r = drm_global_item_ref(global_ref);
+ if (r != 0) {
+ DRM_ERROR("Failed setting up TTM BO subsystem.\n");
+ drm_global_item_unref(&adev->mman.mem_global_ref);
+ return r;
+ }
+
+ adev->mman.mem_global_referenced = true;
+ return 0;
+}
+
+static void amdgpu_ttm_global_fini(struct amdgpu_device *adev)
+{
+ if (adev->mman.mem_global_referenced) {
+ drm_global_item_unref(&adev->mman.bo_global_ref.ref);
+ drm_global_item_unref(&adev->mman.mem_global_ref);
+ adev->mman.mem_global_referenced = false;
+ }
+}
+
+static int amdgpu_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
+{
+ return 0;
+}
+
+static int amdgpu_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+ struct ttm_mem_type_manager *man)
+{
+ struct amdgpu_device *adev;
+
+ adev = amdgpu_get_adev(bdev);
+
+ switch (type) {
+ case TTM_PL_SYSTEM:
+ /* System memory */
+ man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+ man->available_caching = TTM_PL_MASK_CACHING;
+ man->default_caching = TTM_PL_FLAG_CACHED;
+ break;
+ case TTM_PL_TT:
+ man->func = &ttm_bo_manager_func;
+ man->gpu_offset = adev->mc.gtt_start;
+ man->available_caching = TTM_PL_MASK_CACHING;
+ man->default_caching = TTM_PL_FLAG_CACHED;
+ man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | TTM_MEMTYPE_FLAG_CMA;
+ break;
+ case TTM_PL_VRAM:
+ /* "On-card" video ram */
+ man->func = &ttm_bo_manager_func;
+ man->gpu_offset = adev->mc.vram_start;
+ man->flags = TTM_MEMTYPE_FLAG_FIXED |
+ TTM_MEMTYPE_FLAG_MAPPABLE;
+ man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
+ man->default_caching = TTM_PL_FLAG_WC;
+ break;
+ case AMDGPU_PL_GDS:
+ case AMDGPU_PL_GWS:
+ case AMDGPU_PL_OA:
+ /* On-chip GDS memory*/
+ man->func = &ttm_bo_manager_func;
+ man->gpu_offset = 0;
+ man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_CMA;
+ man->available_caching = TTM_PL_FLAG_UNCACHED;
+ man->default_caching = TTM_PL_FLAG_UNCACHED;
+ break;
+ default:
+ DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void amdgpu_evict_flags(struct ttm_buffer_object *bo,
+ struct ttm_placement *placement)
+{
+ struct amdgpu_bo *rbo;
+ static struct ttm_place placements = {
+ .fpfn = 0,
+ .lpfn = 0,
+ .flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM
+ };
+
+ if (!amdgpu_ttm_bo_is_amdgpu_bo(bo)) {
+ placement->placement = &placements;
+ placement->busy_placement = &placements;
+ placement->num_placement = 1;
+ placement->num_busy_placement = 1;
+ return;
+ }
+ rbo = container_of(bo, struct amdgpu_bo, tbo);
+ switch (bo->mem.mem_type) {
+ case TTM_PL_VRAM:
+ if (rbo->adev->mman.buffer_funcs_ring->ready == false)
+ amdgpu_ttm_placement_from_domain(rbo, AMDGPU_GEM_DOMAIN_CPU);
+ else
+ amdgpu_ttm_placement_from_domain(rbo, AMDGPU_GEM_DOMAIN_GTT);
+ break;
+ case TTM_PL_TT:
+ default:
+ amdgpu_ttm_placement_from_domain(rbo, AMDGPU_GEM_DOMAIN_CPU);
+ }
+ *placement = rbo->placement;
+}
+
+static int amdgpu_verify_access(struct ttm_buffer_object *bo, struct file *filp)
+{
+ struct amdgpu_bo *rbo = container_of(bo, struct amdgpu_bo, tbo);
+
+ return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp);
+}
+
+static void amdgpu_move_null(struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *new_mem)
+{
+ struct ttm_mem_reg *old_mem = &bo->mem;
+
+ BUG_ON(old_mem->mm_node != NULL);
+ *old_mem = *new_mem;
+ new_mem->mm_node = NULL;
+}
+
+static int amdgpu_move_blit(struct ttm_buffer_object *bo,
+ bool evict, bool no_wait_gpu,
+ struct ttm_mem_reg *new_mem,
+ struct ttm_mem_reg *old_mem)
+{
+ struct amdgpu_device *adev;
+ struct amdgpu_ring *ring;
+ uint64_t old_start, new_start;
+ struct amdgpu_fence *fence;
+ int r;
+
+ adev = amdgpu_get_adev(bo->bdev);
+ ring = adev->mman.buffer_funcs_ring;
+ old_start = old_mem->start << PAGE_SHIFT;
+ new_start = new_mem->start << PAGE_SHIFT;
+
+ switch (old_mem->mem_type) {
+ case TTM_PL_VRAM:
+ old_start += adev->mc.vram_start;
+ break;
+ case TTM_PL_TT:
+ old_start += adev->mc.gtt_start;
+ break;
+ default:
+ DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
+ return -EINVAL;
+ }
+ switch (new_mem->mem_type) {
+ case TTM_PL_VRAM:
+ new_start += adev->mc.vram_start;
+ break;
+ case TTM_PL_TT:
+ new_start += adev->mc.gtt_start;
+ break;
+ default:
+ DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
+ return -EINVAL;
+ }
+ if (!ring->ready) {
+ DRM_ERROR("Trying to move memory with ring turned off.\n");
+ return -EINVAL;
+ }
+
+ BUILD_BUG_ON((PAGE_SIZE % AMDGPU_GPU_PAGE_SIZE) != 0);
+
+ r = amdgpu_copy_buffer(ring, old_start, new_start,
+ new_mem->num_pages * PAGE_SIZE, /* bytes */
+ bo->resv, &fence);
+ /* FIXME: handle copy error */
+ r = ttm_bo_move_accel_cleanup(bo, &fence->base,
+ evict, no_wait_gpu, new_mem);
+ amdgpu_fence_unref(&fence);
+ return r;
+}
+
+static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo,
+ bool evict, bool interruptible,
+ bool no_wait_gpu,
+ struct ttm_mem_reg *new_mem)
+{
+ struct amdgpu_device *adev;
+ struct ttm_mem_reg *old_mem = &bo->mem;
+ struct ttm_mem_reg tmp_mem;
+ struct ttm_place placements;
+ struct ttm_placement placement;
+ int r;
+
+ adev = amdgpu_get_adev(bo->bdev);
+ tmp_mem = *new_mem;
+ tmp_mem.mm_node = NULL;
+ placement.num_placement = 1;
+ placement.placement = &placements;
+ placement.num_busy_placement = 1;
+ placement.busy_placement = &placements;
+ placements.fpfn = 0;
+ placements.lpfn = 0;
+ placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
+ r = ttm_bo_mem_space(bo, &placement, &tmp_mem,
+ interruptible, no_wait_gpu);
+ if (unlikely(r)) {
+ return r;
+ }
+
+ r = ttm_tt_set_placement_caching(bo->ttm, tmp_mem.placement);
+ if (unlikely(r)) {
+ goto out_cleanup;
+ }
+
+ r = ttm_tt_bind(bo->ttm, &tmp_mem);
+ if (unlikely(r)) {
+ goto out_cleanup;
+ }
+ r = amdgpu_move_blit(bo, true, no_wait_gpu, &tmp_mem, old_mem);
+ if (unlikely(r)) {
+ goto out_cleanup;
+ }
+ r = ttm_bo_move_ttm(bo, true, no_wait_gpu, new_mem);
+out_cleanup:
+ ttm_bo_mem_put(bo, &tmp_mem);
+ return r;
+}
+
+static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo,
+ bool evict, bool interruptible,
+ bool no_wait_gpu,
+ struct ttm_mem_reg *new_mem)
+{
+ struct amdgpu_device *adev;
+ struct ttm_mem_reg *old_mem = &bo->mem;
+ struct ttm_mem_reg tmp_mem;
+ struct ttm_placement placement;
+ struct ttm_place placements;
+ int r;
+
+ adev = amdgpu_get_adev(bo->bdev);
+ tmp_mem = *new_mem;
+ tmp_mem.mm_node = NULL;
+ placement.num_placement = 1;
+ placement.placement = &placements;
+ placement.num_busy_placement = 1;
+ placement.busy_placement = &placements;
+ placements.fpfn = 0;
+ placements.lpfn = 0;
+ placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
+ r = ttm_bo_mem_space(bo, &placement, &tmp_mem,
+ interruptible, no_wait_gpu);
+ if (unlikely(r)) {
+ return r;
+ }
+ r = ttm_bo_move_ttm(bo, true, no_wait_gpu, &tmp_mem);
+ if (unlikely(r)) {
+ goto out_cleanup;
+ }
+ r = amdgpu_move_blit(bo, true, no_wait_gpu, new_mem, old_mem);
+ if (unlikely(r)) {
+ goto out_cleanup;
+ }
+out_cleanup:
+ ttm_bo_mem_put(bo, &tmp_mem);
+ return r;
+}
+
+static int amdgpu_bo_move(struct ttm_buffer_object *bo,
+ bool evict, bool interruptible,
+ bool no_wait_gpu,
+ struct ttm_mem_reg *new_mem)
+{
+ struct amdgpu_device *adev;
+ struct ttm_mem_reg *old_mem = &bo->mem;
+ int r;
+
+ adev = amdgpu_get_adev(bo->bdev);
+ if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
+ amdgpu_move_null(bo, new_mem);
+ return 0;
+ }
+ if ((old_mem->mem_type == TTM_PL_TT &&
+ new_mem->mem_type == TTM_PL_SYSTEM) ||
+ (old_mem->mem_type == TTM_PL_SYSTEM &&
+ new_mem->mem_type == TTM_PL_TT)) {
+ /* bind is enough */
+ amdgpu_move_null(bo, new_mem);
+ return 0;
+ }
+ if (adev->mman.buffer_funcs == NULL ||
+ adev->mman.buffer_funcs_ring == NULL ||
+ !adev->mman.buffer_funcs_ring->ready) {
+ /* use memcpy */
+ goto memcpy;
+ }
+
+ if (old_mem->mem_type == TTM_PL_VRAM &&
+ new_mem->mem_type == TTM_PL_SYSTEM) {
+ r = amdgpu_move_vram_ram(bo, evict, interruptible,
+ no_wait_gpu, new_mem);
+ } else if (old_mem->mem_type == TTM_PL_SYSTEM &&
+ new_mem->mem_type == TTM_PL_VRAM) {
+ r = amdgpu_move_ram_vram(bo, evict, interruptible,
+ no_wait_gpu, new_mem);
+ } else {
+ r = amdgpu_move_blit(bo, evict, no_wait_gpu, new_mem, old_mem);
+ }
+
+ if (r) {
+memcpy:
+ r = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem);
+ if (r) {
+ return r;
+ }
+ }
+
+ /* update statistics */
+ atomic64_add((u64)bo->num_pages << PAGE_SHIFT, &adev->num_bytes_moved);
+ return 0;
+}
+
+static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+{
+ struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+ struct amdgpu_device *adev = amdgpu_get_adev(bdev);
+
+ mem->bus.addr = NULL;
+ mem->bus.offset = 0;
+ mem->bus.size = mem->num_pages << PAGE_SHIFT;
+ mem->bus.base = 0;
+ mem->bus.is_iomem = false;
+ if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+ return -EINVAL;
+ switch (mem->mem_type) {
+ case TTM_PL_SYSTEM:
+ /* system memory */
+ return 0;
+ case TTM_PL_TT:
+ break;
+ case TTM_PL_VRAM:
+ mem->bus.offset = mem->start << PAGE_SHIFT;
+ /* check if it's visible */
+ if ((mem->bus.offset + mem->bus.size) > adev->mc.visible_vram_size)
+ return -EINVAL;
+ mem->bus.base = adev->mc.aper_base;
+ mem->bus.is_iomem = true;
+#ifdef __alpha__
+ /*
+ * Alpha: use bus.addr to hold the ioremap() return,
+ * so we can modify bus.base below.
+ */
+ if (mem->placement & TTM_PL_FLAG_WC)
+ mem->bus.addr =
+ ioremap_wc(mem->bus.base + mem->bus.offset,
+ mem->bus.size);
+ else
+ mem->bus.addr =
+ ioremap_nocache(mem->bus.base + mem->bus.offset,
+ mem->bus.size);
+
+ /*
+ * Alpha: Use just the bus offset plus
+ * the hose/domain memory base for bus.base.
+ * It then can be used to build PTEs for VRAM
+ * access, as done in ttm_bo_vm_fault().
+ */
+ mem->bus.base = (mem->bus.base & 0x0ffffffffUL) +
+ adev->ddev->hose->dense_mem_base;
+#endif
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void amdgpu_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+{
+}
+
+/*
+ * TTM backend functions.
+ */
+struct amdgpu_ttm_tt {
+ struct ttm_dma_tt ttm;
+ struct amdgpu_device *adev;
+ u64 offset;
+ uint64_t userptr;
+ struct mm_struct *usermm;
+ uint32_t userflags;
+};
+
+/* prepare the sg table with the user pages */
+static int amdgpu_ttm_tt_pin_userptr(struct ttm_tt *ttm)
+{
+ struct amdgpu_device *adev = amdgpu_get_adev(ttm->bdev);
+ struct amdgpu_ttm_tt *gtt = (void *)ttm;
+ unsigned pinned = 0, nents;
+ int r;
+
+ int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
+ enum dma_data_direction direction = write ?
+ DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
+
+ if (current->mm != gtt->usermm)
+ return -EPERM;
+
+ if (gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) {
+ /* check that we only pin down anonymous memory
+ to prevent problems with writeback */
+ unsigned long end = gtt->userptr + ttm->num_pages * PAGE_SIZE;
+ struct vm_area_struct *vma;
+
+ vma = find_vma(gtt->usermm, gtt->userptr);
+ if (!vma || vma->vm_file || vma->vm_end < end)
+ return -EPERM;
+ }
+
+ do {
+ unsigned num_pages = ttm->num_pages - pinned;
+ uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
+ struct page **pages = ttm->pages + pinned;
+
+ r = get_user_pages(current, current->mm, userptr, num_pages,
+ write, 0, pages, NULL);
+ if (r < 0)
+ goto release_pages;
+
+ pinned += r;
+
+ } while (pinned < ttm->num_pages);
+
+ r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0,
+ ttm->num_pages << PAGE_SHIFT,
+ GFP_KERNEL);
+ if (r)
+ goto release_sg;
+
+ r = -ENOMEM;
+ nents = dma_map_sg(adev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
+ if (nents != ttm->sg->nents)
+ goto release_sg;
+
+ drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
+ gtt->ttm.dma_address, ttm->num_pages);
+
+ return 0;
+
+release_sg:
+ kfree(ttm->sg);
+
+release_pages:
+ release_pages(ttm->pages, pinned, 0);
+ return r;
+}
+
+static void amdgpu_ttm_tt_unpin_userptr(struct ttm_tt *ttm)
+{
+ struct amdgpu_device *adev = amdgpu_get_adev(ttm->bdev);
+ struct amdgpu_ttm_tt *gtt = (void *)ttm;
+ struct sg_page_iter sg_iter;
+
+ int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
+ enum dma_data_direction direction = write ?
+ DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
+
+ /* double check that we don't free the table twice */
+ if (!ttm->sg->sgl)
+ return;
+
+ /* free the sg table and pages again */
+ dma_unmap_sg(adev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
+
+ for_each_sg_page(ttm->sg->sgl, &sg_iter, ttm->sg->nents, 0) {
+ struct page *page = sg_page_iter_page(&sg_iter);
+ if (!(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY))
+ set_page_dirty(page);
+
+ mark_page_accessed(page);
+ page_cache_release(page);
+ }
+
+ sg_free_table(ttm->sg);
+}
+
+static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm,
+ struct ttm_mem_reg *bo_mem)
+{
+ struct amdgpu_ttm_tt *gtt = (void*)ttm;
+ uint32_t flags = amdgpu_ttm_tt_pte_flags(gtt->adev, ttm, bo_mem);
+ int r;
+
+ if (gtt->userptr)
+ amdgpu_ttm_tt_pin_userptr(ttm);
+
+ gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT);
+ if (!ttm->num_pages) {
+ WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n",
+ ttm->num_pages, bo_mem, ttm);
+ }
+
+ if (bo_mem->mem_type == AMDGPU_PL_GDS ||
+ bo_mem->mem_type == AMDGPU_PL_GWS ||
+ bo_mem->mem_type == AMDGPU_PL_OA)
+ return -EINVAL;
+
+ r = amdgpu_gart_bind(gtt->adev, gtt->offset, ttm->num_pages,
+ ttm->pages, gtt->ttm.dma_address, flags);
+
+ if (r) {
+ DRM_ERROR("failed to bind %lu pages at 0x%08X\n",
+ ttm->num_pages, (unsigned)gtt->offset);
+ return r;
+ }
+ return 0;
+}
+
+static int amdgpu_ttm_backend_unbind(struct ttm_tt *ttm)
+{
+ struct amdgpu_ttm_tt *gtt = (void *)ttm;
+
+ /* unbind shouldn't be done for GDS/GWS/OA in ttm_bo_clean_mm */
+ if (gtt->adev->gart.ready)
+ amdgpu_gart_unbind(gtt->adev, gtt->offset, ttm->num_pages);
+
+ if (gtt->userptr)
+ amdgpu_ttm_tt_unpin_userptr(ttm);
+
+ return 0;
+}
+
+static void amdgpu_ttm_backend_destroy(struct ttm_tt *ttm)
+{
+ struct amdgpu_ttm_tt *gtt = (void *)ttm;
+
+ ttm_dma_tt_fini(&gtt->ttm);
+ kfree(gtt);
+}
+
+static struct ttm_backend_func amdgpu_backend_func = {
+ .bind = &amdgpu_ttm_backend_bind,
+ .unbind = &amdgpu_ttm_backend_unbind,
+ .destroy = &amdgpu_ttm_backend_destroy,
+};
+
+static struct ttm_tt *amdgpu_ttm_tt_create(struct ttm_bo_device *bdev,
+ unsigned long size, uint32_t page_flags,
+ struct page *dummy_read_page)
+{
+ struct amdgpu_device *adev;
+ struct amdgpu_ttm_tt *gtt;
+
+ adev = amdgpu_get_adev(bdev);
+
+ gtt = kzalloc(sizeof(struct amdgpu_ttm_tt), GFP_KERNEL);
+ if (gtt == NULL) {
+ return NULL;
+ }
+ gtt->ttm.ttm.func = &amdgpu_backend_func;
+ gtt->adev = adev;
+ if (ttm_dma_tt_init(&gtt->ttm, bdev, size, page_flags, dummy_read_page)) {
+ kfree(gtt);
+ return NULL;
+ }
+ return &gtt->ttm.ttm;
+}
+
+static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm)
+{
+ struct amdgpu_device *adev;
+ struct amdgpu_ttm_tt *gtt = (void *)ttm;
+ unsigned i;
+ int r;
+ bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
+
+ if (ttm->state != tt_unpopulated)
+ return 0;
+
+ if (gtt && gtt->userptr) {
+ ttm->sg = kcalloc(1, sizeof(struct sg_table), GFP_KERNEL);
+ if (!ttm->sg)
+ return -ENOMEM;
+
+ ttm->page_flags |= TTM_PAGE_FLAG_SG;
+ ttm->state = tt_unbound;
+ return 0;
+ }
+
+ if (slave && ttm->sg) {
+ drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
+ gtt->ttm.dma_address, ttm->num_pages);
+ ttm->state = tt_unbound;
+ return 0;
+ }
+
+ adev = amdgpu_get_adev(ttm->bdev);
+
+#ifdef CONFIG_SWIOTLB
+ if (swiotlb_nr_tbl()) {
+ return ttm_dma_populate(&gtt->ttm, adev->dev);
+ }
+#endif
+
+ r = ttm_pool_populate(ttm);
+ if (r) {
+ return r;
+ }
+
+ for (i = 0; i < ttm->num_pages; i++) {
+ gtt->ttm.dma_address[i] = pci_map_page(adev->pdev, ttm->pages[i],
+ 0, PAGE_SIZE,
+ PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(adev->pdev, gtt->ttm.dma_address[i])) {
+ while (--i) {
+ pci_unmap_page(adev->pdev, gtt->ttm.dma_address[i],
+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ gtt->ttm.dma_address[i] = 0;
+ }
+ ttm_pool_unpopulate(ttm);
+ return -EFAULT;
+ }
+ }
+ return 0;
+}
+
+static void amdgpu_ttm_tt_unpopulate(struct ttm_tt *ttm)
+{
+ struct amdgpu_device *adev;
+ struct amdgpu_ttm_tt *gtt = (void *)ttm;
+ unsigned i;
+ bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
+
+ if (gtt && gtt->userptr) {
+ kfree(ttm->sg);
+ ttm->page_flags &= ~TTM_PAGE_FLAG_SG;
+ return;
+ }
+
+ if (slave)
+ return;
+
+ adev = amdgpu_get_adev(ttm->bdev);
+
+#ifdef CONFIG_SWIOTLB
+ if (swiotlb_nr_tbl()) {
+ ttm_dma_unpopulate(&gtt->ttm, adev->dev);
+ return;
+ }
+#endif
+
+ for (i = 0; i < ttm->num_pages; i++) {
+ if (gtt->ttm.dma_address[i]) {
+ pci_unmap_page(adev->pdev, gtt->ttm.dma_address[i],
+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ }
+ }
+
+ ttm_pool_unpopulate(ttm);
+}
+
+int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
+ uint32_t flags)
+{
+ struct amdgpu_ttm_tt *gtt = (void *)ttm;
+
+ if (gtt == NULL)
+ return -EINVAL;
+
+ gtt->userptr = addr;
+ gtt->usermm = current->mm;
+ gtt->userflags = flags;
+ return 0;
+}
+
+bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm)
+{
+ struct amdgpu_ttm_tt *gtt = (void *)ttm;
+
+ if (gtt == NULL)
+ return false;
+
+ return !!gtt->userptr;
+}
+
+bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm)
+{
+ struct amdgpu_ttm_tt *gtt = (void *)ttm;
+
+ if (gtt == NULL)
+ return false;
+
+ return !!(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
+}
+
+uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
+ struct ttm_mem_reg *mem)
+{
+ uint32_t flags = 0;
+
+ if (mem && mem->mem_type != TTM_PL_SYSTEM)
+ flags |= AMDGPU_PTE_VALID;
+
+ if (mem && mem->mem_type == TTM_PL_TT)
+ flags |= AMDGPU_PTE_SYSTEM;
+
+ if (!ttm || ttm->caching_state == tt_cached)
+ flags |= AMDGPU_PTE_SNOOPED;
+
+ if (adev->asic_type >= CHIP_TOPAZ)
+ flags |= AMDGPU_PTE_EXECUTABLE;
+
+ flags |= AMDGPU_PTE_READABLE;
+
+ if (!amdgpu_ttm_tt_is_readonly(ttm))
+ flags |= AMDGPU_PTE_WRITEABLE;
+
+ return flags;
+}
+
+static struct ttm_bo_driver amdgpu_bo_driver = {
+ .ttm_tt_create = &amdgpu_ttm_tt_create,
+ .ttm_tt_populate = &amdgpu_ttm_tt_populate,
+ .ttm_tt_unpopulate = &amdgpu_ttm_tt_unpopulate,
+ .invalidate_caches = &amdgpu_invalidate_caches,
+ .init_mem_type = &amdgpu_init_mem_type,
+ .evict_flags = &amdgpu_evict_flags,
+ .move = &amdgpu_bo_move,
+ .verify_access = &amdgpu_verify_access,
+ .move_notify = &amdgpu_bo_move_notify,
+ .fault_reserve_notify = &amdgpu_bo_fault_reserve_notify,
+ .io_mem_reserve = &amdgpu_ttm_io_mem_reserve,
+ .io_mem_free = &amdgpu_ttm_io_mem_free,
+};
+
+int amdgpu_ttm_init(struct amdgpu_device *adev)
+{
+ int r;
+
+ r = amdgpu_ttm_global_init(adev);
+ if (r) {
+ return r;
+ }
+ /* No others user of address space so set it to 0 */
+ r = ttm_bo_device_init(&adev->mman.bdev,
+ adev->mman.bo_global_ref.ref.object,
+ &amdgpu_bo_driver,
+ adev->ddev->anon_inode->i_mapping,
+ DRM_FILE_PAGE_OFFSET,
+ adev->need_dma32);
+ if (r) {
+ DRM_ERROR("failed initializing buffer object driver(%d).\n", r);
+ return r;
+ }
+ adev->mman.initialized = true;
+ r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_VRAM,
+ adev->mc.real_vram_size >> PAGE_SHIFT);
+ if (r) {
+ DRM_ERROR("Failed initializing VRAM heap.\n");
+ return r;
+ }
+ /* Change the size here instead of the init above so only lpfn is affected */
+ amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size);
+
+ r = amdgpu_bo_create(adev, 256 * 1024, PAGE_SIZE, true,
+ AMDGPU_GEM_DOMAIN_VRAM, 0,
+ NULL, &adev->stollen_vga_memory);
+ if (r) {
+ return r;
+ }
+ r = amdgpu_bo_reserve(adev->stollen_vga_memory, false);
+ if (r)
+ return r;
+ r = amdgpu_bo_pin(adev->stollen_vga_memory, AMDGPU_GEM_DOMAIN_VRAM, NULL);
+ amdgpu_bo_unreserve(adev->stollen_vga_memory);
+ if (r) {
+ amdgpu_bo_unref(&adev->stollen_vga_memory);
+ return r;
+ }
+ DRM_INFO("amdgpu: %uM of VRAM memory ready\n",
+ (unsigned) (adev->mc.real_vram_size / (1024 * 1024)));
+ r = ttm_bo_init_mm(&adev->mman.bdev, TTM_PL_TT,
+ adev->mc.gtt_size >> PAGE_SHIFT);
+ if (r) {
+ DRM_ERROR("Failed initializing GTT heap.\n");
+ return r;
+ }
+ DRM_INFO("amdgpu: %uM of GTT memory ready.\n",
+ (unsigned)(adev->mc.gtt_size / (1024 * 1024)));
+
+ adev->gds.mem.total_size = adev->gds.mem.total_size << AMDGPU_GDS_SHIFT;
+ adev->gds.mem.gfx_partition_size = adev->gds.mem.gfx_partition_size << AMDGPU_GDS_SHIFT;
+ adev->gds.mem.cs_partition_size = adev->gds.mem.cs_partition_size << AMDGPU_GDS_SHIFT;
+ adev->gds.gws.total_size = adev->gds.gws.total_size << AMDGPU_GWS_SHIFT;
+ adev->gds.gws.gfx_partition_size = adev->gds.gws.gfx_partition_size << AMDGPU_GWS_SHIFT;
+ adev->gds.gws.cs_partition_size = adev->gds.gws.cs_partition_size << AMDGPU_GWS_SHIFT;
+ adev->gds.oa.total_size = adev->gds.oa.total_size << AMDGPU_OA_SHIFT;
+ adev->gds.oa.gfx_partition_size = adev->gds.oa.gfx_partition_size << AMDGPU_OA_SHIFT;
+ adev->gds.oa.cs_partition_size = adev->gds.oa.cs_partition_size << AMDGPU_OA_SHIFT;
+ /* GDS Memory */
+ r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GDS,
+ adev->gds.mem.total_size >> PAGE_SHIFT);
+ if (r) {
+ DRM_ERROR("Failed initializing GDS heap.\n");
+ return r;
+ }
+
+ /* GWS */
+ r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_GWS,
+ adev->gds.gws.total_size >> PAGE_SHIFT);
+ if (r) {
+ DRM_ERROR("Failed initializing gws heap.\n");
+ return r;
+ }
+
+ /* OA */
+ r = ttm_bo_init_mm(&adev->mman.bdev, AMDGPU_PL_OA,
+ adev->gds.oa.total_size >> PAGE_SHIFT);
+ if (r) {
+ DRM_ERROR("Failed initializing oa heap.\n");
+ return r;
+ }
+
+ r = amdgpu_ttm_debugfs_init(adev);
+ if (r) {
+ DRM_ERROR("Failed to init debugfs\n");
+ return r;
+ }
+ return 0;
+}
+
+void amdgpu_ttm_fini(struct amdgpu_device *adev)
+{
+ int r;
+
+ if (!adev->mman.initialized)
+ return;
+ amdgpu_ttm_debugfs_fini(adev);
+ if (adev->stollen_vga_memory) {
+ r = amdgpu_bo_reserve(adev->stollen_vga_memory, false);
+ if (r == 0) {
+ amdgpu_bo_unpin(adev->stollen_vga_memory);
+ amdgpu_bo_unreserve(adev->stollen_vga_memory);
+ }
+ amdgpu_bo_unref(&adev->stollen_vga_memory);
+ }
+ ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_VRAM);
+ ttm_bo_clean_mm(&adev->mman.bdev, TTM_PL_TT);
+ ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GDS);
+ ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_GWS);
+ ttm_bo_clean_mm(&adev->mman.bdev, AMDGPU_PL_OA);
+ ttm_bo_device_release(&adev->mman.bdev);
+ amdgpu_gart_fini(adev);
+ amdgpu_ttm_global_fini(adev);
+ adev->mman.initialized = false;
+ DRM_INFO("amdgpu: ttm finalized\n");
+}
+
+/* this should only be called at bootup or when userspace
+ * isn't running */
+void amdgpu_ttm_set_active_vram_size(struct amdgpu_device *adev, u64 size)
+{
+ struct ttm_mem_type_manager *man;
+
+ if (!adev->mman.initialized)
+ return;
+
+ man = &adev->mman.bdev.man[TTM_PL_VRAM];
+ /* this just adjusts TTM size idea, which sets lpfn to the correct value */
+ man->size = size >> PAGE_SHIFT;
+}
+
+int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct drm_file *file_priv;
+ struct amdgpu_device *adev;
+
+ if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+ return -EINVAL;
+
+ file_priv = filp->private_data;
+ adev = file_priv->minor->dev->dev_private;
+ if (adev == NULL)
+ return -EINVAL;
+
+ return ttm_bo_mmap(filp, vma, &adev->mman.bdev);
+}
+
+int amdgpu_copy_buffer(struct amdgpu_ring *ring,
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ uint32_t byte_count,
+ struct reservation_object *resv,
+ struct amdgpu_fence **fence)
+{
+ struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_sync sync;
+ uint32_t max_bytes;
+ unsigned num_loops, num_dw;
+ unsigned i;
+ int r;
+
+ /* sync other rings */
+ amdgpu_sync_create(&sync);
+ if (resv) {
+ r = amdgpu_sync_resv(adev, &sync, resv, false);
+ if (r) {
+ DRM_ERROR("sync failed (%d).\n", r);
+ amdgpu_sync_free(adev, &sync, NULL);
+ return r;
+ }
+ }
+
+ max_bytes = adev->mman.buffer_funcs->copy_max_bytes;
+ num_loops = DIV_ROUND_UP(byte_count, max_bytes);
+ num_dw = num_loops * adev->mman.buffer_funcs->copy_num_dw;
+
+ /* for fence and sync */
+ num_dw += 64 + AMDGPU_NUM_SYNCS * 8;
+
+ r = amdgpu_ring_lock(ring, num_dw);
+ if (r) {
+ DRM_ERROR("ring lock failed (%d).\n", r);
+ amdgpu_sync_free(adev, &sync, NULL);
+ return r;
+ }
+
+ amdgpu_sync_rings(&sync, ring);
+
+ for (i = 0; i < num_loops; i++) {
+ uint32_t cur_size_in_bytes = min(byte_count, max_bytes);
+
+ amdgpu_emit_copy_buffer(adev, ring, src_offset, dst_offset,
+ cur_size_in_bytes);
+
+ src_offset += cur_size_in_bytes;
+ dst_offset += cur_size_in_bytes;
+ byte_count -= cur_size_in_bytes;
+ }
+
+ r = amdgpu_fence_emit(ring, AMDGPU_FENCE_OWNER_MOVE, fence);
+ if (r) {
+ amdgpu_ring_unlock_undo(ring);
+ amdgpu_sync_free(adev, &sync, NULL);
+ return r;
+ }
+
+ amdgpu_ring_unlock_commit(ring);
+ amdgpu_sync_free(adev, &sync, *fence);
+
+ return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+
+static int amdgpu_mm_dump_table(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ unsigned ttm_pl = *(int *)node->info_ent->data;
+ struct drm_device *dev = node->minor->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct drm_mm *mm = (struct drm_mm *)adev->mman.bdev.man[ttm_pl].priv;
+ int ret;
+ struct ttm_bo_global *glob = adev->mman.bdev.glob;
+
+ spin_lock(&glob->lru_lock);
+ ret = drm_mm_dump_table(m, mm);
+ spin_unlock(&glob->lru_lock);
+ return ret;
+}
+
+static int ttm_pl_vram = TTM_PL_VRAM;
+static int ttm_pl_tt = TTM_PL_TT;
+
+static struct drm_info_list amdgpu_ttm_debugfs_list[] = {
+ {"amdgpu_vram_mm", amdgpu_mm_dump_table, 0, &ttm_pl_vram},
+ {"amdgpu_gtt_mm", amdgpu_mm_dump_table, 0, &ttm_pl_tt},
+ {"ttm_page_pool", ttm_page_alloc_debugfs, 0, NULL},
+#ifdef CONFIG_SWIOTLB
+ {"ttm_dma_page_pool", ttm_dma_page_alloc_debugfs, 0, NULL}
+#endif
+};
+
+static ssize_t amdgpu_ttm_vram_read(struct file *f, char __user *buf,
+ size_t size, loff_t *pos)
+{
+ struct amdgpu_device *adev = f->f_inode->i_private;
+ ssize_t result = 0;
+ int r;
+
+ if (size & 0x3 || *pos & 0x3)
+ return -EINVAL;
+
+ while (size) {
+ unsigned long flags;
+ uint32_t value;
+
+ if (*pos >= adev->mc.mc_vram_size)
+ return result;
+
+ spin_lock_irqsave(&adev->mmio_idx_lock, flags);
+ WREG32(mmMM_INDEX, ((uint32_t)*pos) | 0x80000000);
+ WREG32(mmMM_INDEX_HI, *pos >> 31);
+ value = RREG32(mmMM_DATA);
+ spin_unlock_irqrestore(&adev->mmio_idx_lock, flags);
+
+ r = put_user(value, (uint32_t *)buf);
+ if (r)
+ return r;
+
+ result += 4;
+ buf += 4;
+ *pos += 4;
+ size -= 4;
+ }
+
+ return result;
+}
+
+static const struct file_operations amdgpu_ttm_vram_fops = {
+ .owner = THIS_MODULE,
+ .read = amdgpu_ttm_vram_read,
+ .llseek = default_llseek
+};
+
+static ssize_t amdgpu_ttm_gtt_read(struct file *f, char __user *buf,
+ size_t size, loff_t *pos)
+{
+ struct amdgpu_device *adev = f->f_inode->i_private;
+ ssize_t result = 0;
+ int r;
+
+ while (size) {
+ loff_t p = *pos / PAGE_SIZE;
+ unsigned off = *pos & ~PAGE_MASK;
+ size_t cur_size = min_t(size_t, size, PAGE_SIZE - off);
+ struct page *page;
+ void *ptr;
+
+ if (p >= adev->gart.num_cpu_pages)
+ return result;
+
+ page = adev->gart.pages[p];
+ if (page) {
+ ptr = kmap(page);
+ ptr += off;
+
+ r = copy_to_user(buf, ptr, cur_size);
+ kunmap(adev->gart.pages[p]);
+ } else
+ r = clear_user(buf, cur_size);
+
+ if (r)
+ return -EFAULT;
+
+ result += cur_size;
+ buf += cur_size;
+ *pos += cur_size;
+ size -= cur_size;
+ }
+
+ return result;
+}
+
+static const struct file_operations amdgpu_ttm_gtt_fops = {
+ .owner = THIS_MODULE,
+ .read = amdgpu_ttm_gtt_read,
+ .llseek = default_llseek
+};
+
+#endif
+
+static int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev)
+{
+#if defined(CONFIG_DEBUG_FS)
+ unsigned count;
+
+ struct drm_minor *minor = adev->ddev->primary;
+ struct dentry *ent, *root = minor->debugfs_root;
+
+ ent = debugfs_create_file("amdgpu_vram", S_IFREG | S_IRUGO, root,
+ adev, &amdgpu_ttm_vram_fops);
+ if (IS_ERR(ent))
+ return PTR_ERR(ent);
+ i_size_write(ent->d_inode, adev->mc.mc_vram_size);
+ adev->mman.vram = ent;
+
+ ent = debugfs_create_file("amdgpu_gtt", S_IFREG | S_IRUGO, root,
+ adev, &amdgpu_ttm_gtt_fops);
+ if (IS_ERR(ent))
+ return PTR_ERR(ent);
+ i_size_write(ent->d_inode, adev->mc.gtt_size);
+ adev->mman.gtt = ent;
+
+ count = ARRAY_SIZE(amdgpu_ttm_debugfs_list);
+
+#ifdef CONFIG_SWIOTLB
+ if (!swiotlb_nr_tbl())
+ --count;
+#endif
+
+ return amdgpu_debugfs_add_files(adev, amdgpu_ttm_debugfs_list, count);
+#else
+
+ return 0;
+#endif
+}
+
+static void amdgpu_ttm_debugfs_fini(struct amdgpu_device *adev)
+{
+#if defined(CONFIG_DEBUG_FS)
+
+ debugfs_remove(adev->mman.vram);
+ adev->mman.vram = NULL;
+
+ debugfs_remove(adev->mman.gtt);
+ adev->mman.gtt = NULL;
+#endif
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
new file mode 100644
index 000000000000..482e66797ae6
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include "amdgpu.h"
+#include "amdgpu_ucode.h"
+
+static void amdgpu_ucode_print_common_hdr(const struct common_firmware_header *hdr)
+{
+ DRM_DEBUG("size_bytes: %u\n", le32_to_cpu(hdr->size_bytes));
+ DRM_DEBUG("header_size_bytes: %u\n", le32_to_cpu(hdr->header_size_bytes));
+ DRM_DEBUG("header_version_major: %u\n", le16_to_cpu(hdr->header_version_major));
+ DRM_DEBUG("header_version_minor: %u\n", le16_to_cpu(hdr->header_version_minor));
+ DRM_DEBUG("ip_version_major: %u\n", le16_to_cpu(hdr->ip_version_major));
+ DRM_DEBUG("ip_version_minor: %u\n", le16_to_cpu(hdr->ip_version_minor));
+ DRM_DEBUG("ucode_version: 0x%08x\n", le32_to_cpu(hdr->ucode_version));
+ DRM_DEBUG("ucode_size_bytes: %u\n", le32_to_cpu(hdr->ucode_size_bytes));
+ DRM_DEBUG("ucode_array_offset_bytes: %u\n",
+ le32_to_cpu(hdr->ucode_array_offset_bytes));
+ DRM_DEBUG("crc32: 0x%08x\n", le32_to_cpu(hdr->crc32));
+}
+
+void amdgpu_ucode_print_mc_hdr(const struct common_firmware_header *hdr)
+{
+ uint16_t version_major = le16_to_cpu(hdr->header_version_major);
+ uint16_t version_minor = le16_to_cpu(hdr->header_version_minor);
+
+ DRM_DEBUG("MC\n");
+ amdgpu_ucode_print_common_hdr(hdr);
+
+ if (version_major == 1) {
+ const struct mc_firmware_header_v1_0 *mc_hdr =
+ container_of(hdr, struct mc_firmware_header_v1_0, header);
+
+ DRM_DEBUG("io_debug_size_bytes: %u\n",
+ le32_to_cpu(mc_hdr->io_debug_size_bytes));
+ DRM_DEBUG("io_debug_array_offset_bytes: %u\n",
+ le32_to_cpu(mc_hdr->io_debug_array_offset_bytes));
+ } else {
+ DRM_ERROR("Unknown MC ucode version: %u.%u\n", version_major, version_minor);
+ }
+}
+
+void amdgpu_ucode_print_smc_hdr(const struct common_firmware_header *hdr)
+{
+ uint16_t version_major = le16_to_cpu(hdr->header_version_major);
+ uint16_t version_minor = le16_to_cpu(hdr->header_version_minor);
+
+ DRM_DEBUG("SMC\n");
+ amdgpu_ucode_print_common_hdr(hdr);
+
+ if (version_major == 1) {
+ const struct smc_firmware_header_v1_0 *smc_hdr =
+ container_of(hdr, struct smc_firmware_header_v1_0, header);
+
+ DRM_DEBUG("ucode_start_addr: %u\n", le32_to_cpu(smc_hdr->ucode_start_addr));
+ } else {
+ DRM_ERROR("Unknown SMC ucode version: %u.%u\n", version_major, version_minor);
+ }
+}
+
+void amdgpu_ucode_print_gfx_hdr(const struct common_firmware_header *hdr)
+{
+ uint16_t version_major = le16_to_cpu(hdr->header_version_major);
+ uint16_t version_minor = le16_to_cpu(hdr->header_version_minor);
+
+ DRM_DEBUG("GFX\n");
+ amdgpu_ucode_print_common_hdr(hdr);
+
+ if (version_major == 1) {
+ const struct gfx_firmware_header_v1_0 *gfx_hdr =
+ container_of(hdr, struct gfx_firmware_header_v1_0, header);
+
+ DRM_DEBUG("ucode_feature_version: %u\n",
+ le32_to_cpu(gfx_hdr->ucode_feature_version));
+ DRM_DEBUG("jt_offset: %u\n", le32_to_cpu(gfx_hdr->jt_offset));
+ DRM_DEBUG("jt_size: %u\n", le32_to_cpu(gfx_hdr->jt_size));
+ } else {
+ DRM_ERROR("Unknown GFX ucode version: %u.%u\n", version_major, version_minor);
+ }
+}
+
+void amdgpu_ucode_print_rlc_hdr(const struct common_firmware_header *hdr)
+{
+ uint16_t version_major = le16_to_cpu(hdr->header_version_major);
+ uint16_t version_minor = le16_to_cpu(hdr->header_version_minor);
+
+ DRM_DEBUG("RLC\n");
+ amdgpu_ucode_print_common_hdr(hdr);
+
+ if (version_major == 1) {
+ const struct rlc_firmware_header_v1_0 *rlc_hdr =
+ container_of(hdr, struct rlc_firmware_header_v1_0, header);
+
+ DRM_DEBUG("ucode_feature_version: %u\n",
+ le32_to_cpu(rlc_hdr->ucode_feature_version));
+ DRM_DEBUG("save_and_restore_offset: %u\n",
+ le32_to_cpu(rlc_hdr->save_and_restore_offset));
+ DRM_DEBUG("clear_state_descriptor_offset: %u\n",
+ le32_to_cpu(rlc_hdr->clear_state_descriptor_offset));
+ DRM_DEBUG("avail_scratch_ram_locations: %u\n",
+ le32_to_cpu(rlc_hdr->avail_scratch_ram_locations));
+ DRM_DEBUG("master_pkt_description_offset: %u\n",
+ le32_to_cpu(rlc_hdr->master_pkt_description_offset));
+ } else if (version_major == 2) {
+ const struct rlc_firmware_header_v2_0 *rlc_hdr =
+ container_of(hdr, struct rlc_firmware_header_v2_0, header);
+
+ DRM_DEBUG("ucode_feature_version: %u\n",
+ le32_to_cpu(rlc_hdr->ucode_feature_version));
+ DRM_DEBUG("jt_offset: %u\n", le32_to_cpu(rlc_hdr->jt_offset));
+ DRM_DEBUG("jt_size: %u\n", le32_to_cpu(rlc_hdr->jt_size));
+ DRM_DEBUG("save_and_restore_offset: %u\n",
+ le32_to_cpu(rlc_hdr->save_and_restore_offset));
+ DRM_DEBUG("clear_state_descriptor_offset: %u\n",
+ le32_to_cpu(rlc_hdr->clear_state_descriptor_offset));
+ DRM_DEBUG("avail_scratch_ram_locations: %u\n",
+ le32_to_cpu(rlc_hdr->avail_scratch_ram_locations));
+ DRM_DEBUG("reg_restore_list_size: %u\n",
+ le32_to_cpu(rlc_hdr->reg_restore_list_size));
+ DRM_DEBUG("reg_list_format_start: %u\n",
+ le32_to_cpu(rlc_hdr->reg_list_format_start));
+ DRM_DEBUG("reg_list_format_separate_start: %u\n",
+ le32_to_cpu(rlc_hdr->reg_list_format_separate_start));
+ DRM_DEBUG("starting_offsets_start: %u\n",
+ le32_to_cpu(rlc_hdr->starting_offsets_start));
+ DRM_DEBUG("reg_list_format_size_bytes: %u\n",
+ le32_to_cpu(rlc_hdr->reg_list_format_size_bytes));
+ DRM_DEBUG("reg_list_format_array_offset_bytes: %u\n",
+ le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes));
+ DRM_DEBUG("reg_list_size_bytes: %u\n",
+ le32_to_cpu(rlc_hdr->reg_list_size_bytes));
+ DRM_DEBUG("reg_list_array_offset_bytes: %u\n",
+ le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes));
+ DRM_DEBUG("reg_list_format_separate_size_bytes: %u\n",
+ le32_to_cpu(rlc_hdr->reg_list_format_separate_size_bytes));
+ DRM_DEBUG("reg_list_format_separate_array_offset_bytes: %u\n",
+ le32_to_cpu(rlc_hdr->reg_list_format_separate_array_offset_bytes));
+ DRM_DEBUG("reg_list_separate_size_bytes: %u\n",
+ le32_to_cpu(rlc_hdr->reg_list_separate_size_bytes));
+ DRM_DEBUG("reg_list_separate_size_bytes: %u\n",
+ le32_to_cpu(rlc_hdr->reg_list_separate_size_bytes));
+ } else {
+ DRM_ERROR("Unknown RLC ucode version: %u.%u\n", version_major, version_minor);
+ }
+}
+
+void amdgpu_ucode_print_sdma_hdr(const struct common_firmware_header *hdr)
+{
+ uint16_t version_major = le16_to_cpu(hdr->header_version_major);
+ uint16_t version_minor = le16_to_cpu(hdr->header_version_minor);
+
+ DRM_DEBUG("SDMA\n");
+ amdgpu_ucode_print_common_hdr(hdr);
+
+ if (version_major == 1) {
+ const struct sdma_firmware_header_v1_0 *sdma_hdr =
+ container_of(hdr, struct sdma_firmware_header_v1_0, header);
+
+ DRM_DEBUG("ucode_feature_version: %u\n",
+ le32_to_cpu(sdma_hdr->ucode_feature_version));
+ DRM_DEBUG("ucode_change_version: %u\n",
+ le32_to_cpu(sdma_hdr->ucode_change_version));
+ DRM_DEBUG("jt_offset: %u\n", le32_to_cpu(sdma_hdr->jt_offset));
+ DRM_DEBUG("jt_size: %u\n", le32_to_cpu(sdma_hdr->jt_size));
+ if (version_minor >= 1) {
+ const struct sdma_firmware_header_v1_1 *sdma_v1_1_hdr =
+ container_of(sdma_hdr, struct sdma_firmware_header_v1_1, v1_0);
+ DRM_DEBUG("digest_size: %u\n", le32_to_cpu(sdma_v1_1_hdr->digest_size));
+ }
+ } else {
+ DRM_ERROR("Unknown SDMA ucode version: %u.%u\n",
+ version_major, version_minor);
+ }
+}
+
+int amdgpu_ucode_validate(const struct firmware *fw)
+{
+ const struct common_firmware_header *hdr =
+ (const struct common_firmware_header *)fw->data;
+
+ if (fw->size == le32_to_cpu(hdr->size_bytes))
+ return 0;
+
+ return -EINVAL;
+}
+
+bool amdgpu_ucode_hdr_version(union amdgpu_firmware_header *hdr,
+ uint16_t hdr_major, uint16_t hdr_minor)
+{
+ if ((hdr->common.header_version_major == hdr_major) &&
+ (hdr->common.header_version_minor == hdr_minor))
+ return false;
+ return true;
+}
+
+static int amdgpu_ucode_init_single_fw(struct amdgpu_firmware_info *ucode,
+ uint64_t mc_addr, void *kptr)
+{
+ const struct common_firmware_header *header = NULL;
+
+ if (NULL == ucode->fw)
+ return 0;
+
+ ucode->mc_addr = mc_addr;
+ ucode->kaddr = kptr;
+
+ header = (const struct common_firmware_header *)ucode->fw->data;
+ memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data +
+ le32_to_cpu(header->ucode_array_offset_bytes)),
+ le32_to_cpu(header->ucode_size_bytes));
+
+ return 0;
+}
+
+int amdgpu_ucode_init_bo(struct amdgpu_device *adev)
+{
+ struct amdgpu_bo **bo = &adev->firmware.fw_buf;
+ uint64_t fw_mc_addr;
+ void *fw_buf_ptr = NULL;
+ uint64_t fw_offset = 0;
+ int i, err;
+ struct amdgpu_firmware_info *ucode = NULL;
+ const struct common_firmware_header *header = NULL;
+
+ err = amdgpu_bo_create(adev, adev->firmware.fw_size, PAGE_SIZE, true,
+ AMDGPU_GEM_DOMAIN_GTT, 0, NULL, bo);
+ if (err) {
+ dev_err(adev->dev, "(%d) Firmware buffer allocate failed\n", err);
+ err = -ENOMEM;
+ goto failed;
+ }
+
+ err = amdgpu_bo_reserve(*bo, false);
+ if (err) {
+ amdgpu_bo_unref(bo);
+ dev_err(adev->dev, "(%d) Firmware buffer reserve failed\n", err);
+ goto failed;
+ }
+
+ err = amdgpu_bo_pin(*bo, AMDGPU_GEM_DOMAIN_GTT, &fw_mc_addr);
+ if (err) {
+ amdgpu_bo_unreserve(*bo);
+ amdgpu_bo_unref(bo);
+ dev_err(adev->dev, "(%d) Firmware buffer pin failed\n", err);
+ goto failed;
+ }
+
+ err = amdgpu_bo_kmap(*bo, &fw_buf_ptr);
+ if (err) {
+ dev_err(adev->dev, "(%d) Firmware buffer kmap failed\n", err);
+ amdgpu_bo_unpin(*bo);
+ amdgpu_bo_unreserve(*bo);
+ amdgpu_bo_unref(bo);
+ goto failed;
+ }
+
+ amdgpu_bo_unreserve(*bo);
+
+ fw_offset = 0;
+ for (i = 0; i < AMDGPU_UCODE_ID_MAXIMUM; i++) {
+ ucode = &adev->firmware.ucode[i];
+ if (ucode->fw) {
+ header = (const struct common_firmware_header *)ucode->fw->data;
+ amdgpu_ucode_init_single_fw(ucode, fw_mc_addr + fw_offset,
+ fw_buf_ptr + fw_offset);
+ fw_offset += ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE);
+ }
+ }
+
+failed:
+ if (err)
+ adev->firmware.smu_load = false;
+
+ return err;
+}
+
+int amdgpu_ucode_fini_bo(struct amdgpu_device *adev)
+{
+ int i;
+ struct amdgpu_firmware_info *ucode = NULL;
+
+ for (i = 0; i < AMDGPU_UCODE_ID_MAXIMUM; i++) {
+ ucode = &adev->firmware.ucode[i];
+ if (ucode->fw) {
+ ucode->mc_addr = 0;
+ ucode->kaddr = NULL;
+ }
+ }
+ amdgpu_bo_unref(&adev->firmware.fw_buf);
+ adev->firmware.fw_buf = NULL;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
new file mode 100644
index 000000000000..e468be4e28fa
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __AMDGPU_UCODE_H__
+#define __AMDGPU_UCODE_H__
+
+struct common_firmware_header {
+ uint32_t size_bytes; /* size of the entire header+image(s) in bytes */
+ uint32_t header_size_bytes; /* size of just the header in bytes */
+ uint16_t header_version_major; /* header version */
+ uint16_t header_version_minor; /* header version */
+ uint16_t ip_version_major; /* IP version */
+ uint16_t ip_version_minor; /* IP version */
+ uint32_t ucode_version;
+ uint32_t ucode_size_bytes; /* size of ucode in bytes */
+ uint32_t ucode_array_offset_bytes; /* payload offset from the start of the header */
+ uint32_t crc32; /* crc32 checksum of the payload */
+};
+
+/* version_major=1, version_minor=0 */
+struct mc_firmware_header_v1_0 {
+ struct common_firmware_header header;
+ uint32_t io_debug_size_bytes; /* size of debug array in dwords */
+ uint32_t io_debug_array_offset_bytes; /* payload offset from the start of the header */
+};
+
+/* version_major=1, version_minor=0 */
+struct smc_firmware_header_v1_0 {
+ struct common_firmware_header header;
+ uint32_t ucode_start_addr;
+};
+
+/* version_major=1, version_minor=0 */
+struct gfx_firmware_header_v1_0 {
+ struct common_firmware_header header;
+ uint32_t ucode_feature_version;
+ uint32_t jt_offset; /* jt location */
+ uint32_t jt_size; /* size of jt */
+};
+
+/* version_major=1, version_minor=0 */
+struct rlc_firmware_header_v1_0 {
+ struct common_firmware_header header;
+ uint32_t ucode_feature_version;
+ uint32_t save_and_restore_offset;
+ uint32_t clear_state_descriptor_offset;
+ uint32_t avail_scratch_ram_locations;
+ uint32_t master_pkt_description_offset;
+};
+
+/* version_major=2, version_minor=0 */
+struct rlc_firmware_header_v2_0 {
+ struct common_firmware_header header;
+ uint32_t ucode_feature_version;
+ uint32_t jt_offset; /* jt location */
+ uint32_t jt_size; /* size of jt */
+ uint32_t save_and_restore_offset;
+ uint32_t clear_state_descriptor_offset;
+ uint32_t avail_scratch_ram_locations;
+ uint32_t reg_restore_list_size;
+ uint32_t reg_list_format_start;
+ uint32_t reg_list_format_separate_start;
+ uint32_t starting_offsets_start;
+ uint32_t reg_list_format_size_bytes; /* size of reg list format array in bytes */
+ uint32_t reg_list_format_array_offset_bytes; /* payload offset from the start of the header */
+ uint32_t reg_list_size_bytes; /* size of reg list array in bytes */
+ uint32_t reg_list_array_offset_bytes; /* payload offset from the start of the header */
+ uint32_t reg_list_format_separate_size_bytes; /* size of reg list format array in bytes */
+ uint32_t reg_list_format_separate_array_offset_bytes; /* payload offset from the start of the header */
+ uint32_t reg_list_separate_size_bytes; /* size of reg list array in bytes */
+ uint32_t reg_list_separate_array_offset_bytes; /* payload offset from the start of the header */
+};
+
+/* version_major=1, version_minor=0 */
+struct sdma_firmware_header_v1_0 {
+ struct common_firmware_header header;
+ uint32_t ucode_feature_version;
+ uint32_t ucode_change_version;
+ uint32_t jt_offset; /* jt location */
+ uint32_t jt_size; /* size of jt */
+};
+
+/* version_major=1, version_minor=1 */
+struct sdma_firmware_header_v1_1 {
+ struct sdma_firmware_header_v1_0 v1_0;
+ uint32_t digest_size;
+};
+
+/* header is fixed size */
+union amdgpu_firmware_header {
+ struct common_firmware_header common;
+ struct mc_firmware_header_v1_0 mc;
+ struct smc_firmware_header_v1_0 smc;
+ struct gfx_firmware_header_v1_0 gfx;
+ struct rlc_firmware_header_v1_0 rlc;
+ struct rlc_firmware_header_v2_0 rlc_v2_0;
+ struct sdma_firmware_header_v1_0 sdma;
+ struct sdma_firmware_header_v1_1 sdma_v1_1;
+ uint8_t raw[0x100];
+};
+
+/*
+ * fw loading support
+ */
+enum AMDGPU_UCODE_ID {
+ AMDGPU_UCODE_ID_SDMA0 = 0,
+ AMDGPU_UCODE_ID_SDMA1,
+ AMDGPU_UCODE_ID_CP_CE,
+ AMDGPU_UCODE_ID_CP_PFP,
+ AMDGPU_UCODE_ID_CP_ME,
+ AMDGPU_UCODE_ID_CP_MEC1,
+ AMDGPU_UCODE_ID_CP_MEC2,
+ AMDGPU_UCODE_ID_RLC_G,
+ AMDGPU_UCODE_ID_MAXIMUM,
+};
+
+/* engine firmware status */
+enum AMDGPU_UCODE_STATUS {
+ AMDGPU_UCODE_STATUS_INVALID,
+ AMDGPU_UCODE_STATUS_NOT_LOADED,
+ AMDGPU_UCODE_STATUS_LOADED,
+};
+
+/* conform to smu_ucode_xfer_cz.h */
+#define AMDGPU_SDMA0_UCODE_LOADED 0x00000001
+#define AMDGPU_SDMA1_UCODE_LOADED 0x00000002
+#define AMDGPU_CPCE_UCODE_LOADED 0x00000004
+#define AMDGPU_CPPFP_UCODE_LOADED 0x00000008
+#define AMDGPU_CPME_UCODE_LOADED 0x00000010
+#define AMDGPU_CPMEC1_UCODE_LOADED 0x00000020
+#define AMDGPU_CPMEC2_UCODE_LOADED 0x00000040
+#define AMDGPU_CPRLC_UCODE_LOADED 0x00000100
+
+/* amdgpu firmware info */
+struct amdgpu_firmware_info {
+ /* ucode ID */
+ enum AMDGPU_UCODE_ID ucode_id;
+ /* request_firmware */
+ const struct firmware *fw;
+ /* starting mc address */
+ uint64_t mc_addr;
+ /* kernel linear address */
+ void *kaddr;
+};
+
+void amdgpu_ucode_print_mc_hdr(const struct common_firmware_header *hdr);
+void amdgpu_ucode_print_smc_hdr(const struct common_firmware_header *hdr);
+void amdgpu_ucode_print_gfx_hdr(const struct common_firmware_header *hdr);
+void amdgpu_ucode_print_rlc_hdr(const struct common_firmware_header *hdr);
+void amdgpu_ucode_print_sdma_hdr(const struct common_firmware_header *hdr);
+int amdgpu_ucode_validate(const struct firmware *fw);
+bool amdgpu_ucode_hdr_version(union amdgpu_firmware_header *hdr,
+ uint16_t hdr_major, uint16_t hdr_minor);
+int amdgpu_ucode_init_bo(struct amdgpu_device *adev);
+int amdgpu_ucode_fini_bo(struct amdgpu_device *adev);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
new file mode 100644
index 000000000000..2f7a5efa21c2
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -0,0 +1,984 @@
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ * Christian König <deathsimple@vodafone.de>
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm.h>
+
+#include "amdgpu.h"
+#include "amdgpu_pm.h"
+#include "amdgpu_uvd.h"
+#include "cikd.h"
+#include "uvd/uvd_4_2_d.h"
+
+/* 1 second timeout */
+#define UVD_IDLE_TIMEOUT_MS 1000
+
+/* Firmware Names */
+#ifdef CONFIG_DRM_AMDGPU_CIK
+#define FIRMWARE_BONAIRE "radeon/bonaire_uvd.bin"
+#define FIRMWARE_KABINI "radeon/kabini_uvd.bin"
+#define FIRMWARE_KAVERI "radeon/kaveri_uvd.bin"
+#define FIRMWARE_HAWAII "radeon/hawaii_uvd.bin"
+#define FIRMWARE_MULLINS "radeon/mullins_uvd.bin"
+#endif
+#define FIRMWARE_TONGA "amdgpu/tonga_uvd.bin"
+#define FIRMWARE_CARRIZO "amdgpu/carrizo_uvd.bin"
+
+/**
+ * amdgpu_uvd_cs_ctx - Command submission parser context
+ *
+ * Used for emulating virtual memory support on UVD 4.2.
+ */
+struct amdgpu_uvd_cs_ctx {
+ struct amdgpu_cs_parser *parser;
+ unsigned reg, count;
+ unsigned data0, data1;
+ unsigned idx;
+ unsigned ib_idx;
+
+ /* does the IB has a msg command */
+ bool has_msg_cmd;
+
+ /* minimum buffer sizes */
+ unsigned *buf_sizes;
+};
+
+#ifdef CONFIG_DRM_AMDGPU_CIK
+MODULE_FIRMWARE(FIRMWARE_BONAIRE);
+MODULE_FIRMWARE(FIRMWARE_KABINI);
+MODULE_FIRMWARE(FIRMWARE_KAVERI);
+MODULE_FIRMWARE(FIRMWARE_HAWAII);
+MODULE_FIRMWARE(FIRMWARE_MULLINS);
+#endif
+MODULE_FIRMWARE(FIRMWARE_TONGA);
+MODULE_FIRMWARE(FIRMWARE_CARRIZO);
+
+static void amdgpu_uvd_note_usage(struct amdgpu_device *adev);
+static void amdgpu_uvd_idle_work_handler(struct work_struct *work);
+
+int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
+{
+ unsigned long bo_size;
+ const char *fw_name;
+ const struct common_firmware_header *hdr;
+ unsigned version_major, version_minor, family_id;
+ int i, r;
+
+ INIT_DELAYED_WORK(&adev->uvd.idle_work, amdgpu_uvd_idle_work_handler);
+
+ switch (adev->asic_type) {
+#ifdef CONFIG_DRM_AMDGPU_CIK
+ case CHIP_BONAIRE:
+ fw_name = FIRMWARE_BONAIRE;
+ break;
+ case CHIP_KABINI:
+ fw_name = FIRMWARE_KABINI;
+ break;
+ case CHIP_KAVERI:
+ fw_name = FIRMWARE_KAVERI;
+ break;
+ case CHIP_HAWAII:
+ fw_name = FIRMWARE_HAWAII;
+ break;
+ case CHIP_MULLINS:
+ fw_name = FIRMWARE_MULLINS;
+ break;
+#endif
+ case CHIP_TONGA:
+ fw_name = FIRMWARE_TONGA;
+ break;
+ case CHIP_CARRIZO:
+ fw_name = FIRMWARE_CARRIZO;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ r = request_firmware(&adev->uvd.fw, fw_name, adev->dev);
+ if (r) {
+ dev_err(adev->dev, "amdgpu_uvd: Can't load firmware \"%s\"\n",
+ fw_name);
+ return r;
+ }
+
+ r = amdgpu_ucode_validate(adev->uvd.fw);
+ if (r) {
+ dev_err(adev->dev, "amdgpu_uvd: Can't validate firmware \"%s\"\n",
+ fw_name);
+ release_firmware(adev->uvd.fw);
+ adev->uvd.fw = NULL;
+ return r;
+ }
+
+ hdr = (const struct common_firmware_header *)adev->uvd.fw->data;
+ family_id = le32_to_cpu(hdr->ucode_version) & 0xff;
+ version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff;
+ version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff;
+ DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n",
+ version_major, version_minor, family_id);
+
+ bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8)
+ + AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE;
+ r = amdgpu_bo_create(adev, bo_size, PAGE_SIZE, true,
+ AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->uvd.vcpu_bo);
+ if (r) {
+ dev_err(adev->dev, "(%d) failed to allocate UVD bo\n", r);
+ return r;
+ }
+
+ r = amdgpu_bo_reserve(adev->uvd.vcpu_bo, false);
+ if (r) {
+ amdgpu_bo_unref(&adev->uvd.vcpu_bo);
+ dev_err(adev->dev, "(%d) failed to reserve UVD bo\n", r);
+ return r;
+ }
+
+ r = amdgpu_bo_pin(adev->uvd.vcpu_bo, AMDGPU_GEM_DOMAIN_VRAM,
+ &adev->uvd.gpu_addr);
+ if (r) {
+ amdgpu_bo_unreserve(adev->uvd.vcpu_bo);
+ amdgpu_bo_unref(&adev->uvd.vcpu_bo);
+ dev_err(adev->dev, "(%d) UVD bo pin failed\n", r);
+ return r;
+ }
+
+ r = amdgpu_bo_kmap(adev->uvd.vcpu_bo, &adev->uvd.cpu_addr);
+ if (r) {
+ dev_err(adev->dev, "(%d) UVD map failed\n", r);
+ return r;
+ }
+
+ amdgpu_bo_unreserve(adev->uvd.vcpu_bo);
+
+ for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) {
+ atomic_set(&adev->uvd.handles[i], 0);
+ adev->uvd.filp[i] = NULL;
+ }
+
+ /* from uvd v5.0 HW addressing capacity increased to 64 bits */
+ if (!amdgpu_ip_block_version_cmp(adev, AMD_IP_BLOCK_TYPE_UVD, 5, 0))
+ adev->uvd.address_64_bit = true;
+
+ return 0;
+}
+
+int amdgpu_uvd_sw_fini(struct amdgpu_device *adev)
+{
+ int r;
+
+ if (adev->uvd.vcpu_bo == NULL)
+ return 0;
+
+ r = amdgpu_bo_reserve(adev->uvd.vcpu_bo, false);
+ if (!r) {
+ amdgpu_bo_kunmap(adev->uvd.vcpu_bo);
+ amdgpu_bo_unpin(adev->uvd.vcpu_bo);
+ amdgpu_bo_unreserve(adev->uvd.vcpu_bo);
+ }
+
+ amdgpu_bo_unref(&adev->uvd.vcpu_bo);
+
+ amdgpu_ring_fini(&adev->uvd.ring);
+
+ release_firmware(adev->uvd.fw);
+
+ return 0;
+}
+
+int amdgpu_uvd_suspend(struct amdgpu_device *adev)
+{
+ unsigned size;
+ void *ptr;
+ const struct common_firmware_header *hdr;
+ int i;
+
+ if (adev->uvd.vcpu_bo == NULL)
+ return 0;
+
+ for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i)
+ if (atomic_read(&adev->uvd.handles[i]))
+ break;
+
+ if (i == AMDGPU_MAX_UVD_HANDLES)
+ return 0;
+
+ hdr = (const struct common_firmware_header *)adev->uvd.fw->data;
+
+ size = amdgpu_bo_size(adev->uvd.vcpu_bo);
+ size -= le32_to_cpu(hdr->ucode_size_bytes);
+
+ ptr = adev->uvd.cpu_addr;
+ ptr += le32_to_cpu(hdr->ucode_size_bytes);
+
+ adev->uvd.saved_bo = kmalloc(size, GFP_KERNEL);
+ memcpy(adev->uvd.saved_bo, ptr, size);
+
+ return 0;
+}
+
+int amdgpu_uvd_resume(struct amdgpu_device *adev)
+{
+ unsigned size;
+ void *ptr;
+ const struct common_firmware_header *hdr;
+ unsigned offset;
+
+ if (adev->uvd.vcpu_bo == NULL)
+ return -EINVAL;
+
+ hdr = (const struct common_firmware_header *)adev->uvd.fw->data;
+ offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
+ memcpy(adev->uvd.cpu_addr, (adev->uvd.fw->data) + offset,
+ (adev->uvd.fw->size) - offset);
+
+ size = amdgpu_bo_size(adev->uvd.vcpu_bo);
+ size -= le32_to_cpu(hdr->ucode_size_bytes);
+ ptr = adev->uvd.cpu_addr;
+ ptr += le32_to_cpu(hdr->ucode_size_bytes);
+
+ if (adev->uvd.saved_bo != NULL) {
+ memcpy(ptr, adev->uvd.saved_bo, size);
+ kfree(adev->uvd.saved_bo);
+ adev->uvd.saved_bo = NULL;
+ } else
+ memset(ptr, 0, size);
+
+ return 0;
+}
+
+void amdgpu_uvd_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
+{
+ struct amdgpu_ring *ring = &adev->uvd.ring;
+ int i, r;
+
+ for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) {
+ uint32_t handle = atomic_read(&adev->uvd.handles[i]);
+ if (handle != 0 && adev->uvd.filp[i] == filp) {
+ struct amdgpu_fence *fence;
+
+ amdgpu_uvd_note_usage(adev);
+
+ r = amdgpu_uvd_get_destroy_msg(ring, handle, &fence);
+ if (r) {
+ DRM_ERROR("Error destroying UVD (%d)!\n", r);
+ continue;
+ }
+
+ amdgpu_fence_wait(fence, false);
+ amdgpu_fence_unref(&fence);
+
+ adev->uvd.filp[i] = NULL;
+ atomic_set(&adev->uvd.handles[i], 0);
+ }
+ }
+}
+
+static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *rbo)
+{
+ int i;
+ for (i = 0; i < rbo->placement.num_placement; ++i) {
+ rbo->placements[i].fpfn = 0 >> PAGE_SHIFT;
+ rbo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
+ }
+}
+
+/**
+ * amdgpu_uvd_cs_pass1 - first parsing round
+ *
+ * @ctx: UVD parser context
+ *
+ * Make sure UVD message and feedback buffers are in VRAM and
+ * nobody is violating an 256MB boundary.
+ */
+static int amdgpu_uvd_cs_pass1(struct amdgpu_uvd_cs_ctx *ctx)
+{
+ struct amdgpu_bo_va_mapping *mapping;
+ struct amdgpu_bo *bo;
+ uint32_t cmd, lo, hi;
+ uint64_t addr;
+ int r = 0;
+
+ lo = amdgpu_get_ib_value(ctx->parser, ctx->ib_idx, ctx->data0);
+ hi = amdgpu_get_ib_value(ctx->parser, ctx->ib_idx, ctx->data1);
+ addr = ((uint64_t)lo) | (((uint64_t)hi) << 32);
+
+ mapping = amdgpu_cs_find_mapping(ctx->parser, addr, &bo);
+ if (mapping == NULL) {
+ DRM_ERROR("Can't find BO for addr 0x%08Lx\n", addr);
+ return -EINVAL;
+ }
+
+ if (!ctx->parser->adev->uvd.address_64_bit) {
+ /* check if it's a message or feedback command */
+ cmd = amdgpu_get_ib_value(ctx->parser, ctx->ib_idx, ctx->idx) >> 1;
+ if (cmd == 0x0 || cmd == 0x3) {
+ /* yes, force it into VRAM */
+ uint32_t domain = AMDGPU_GEM_DOMAIN_VRAM;
+ amdgpu_ttm_placement_from_domain(bo, domain);
+ }
+ amdgpu_uvd_force_into_uvd_segment(bo);
+
+ r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
+ }
+
+ return r;
+}
+
+/**
+ * amdgpu_uvd_cs_msg_decode - handle UVD decode message
+ *
+ * @msg: pointer to message structure
+ * @buf_sizes: returned buffer sizes
+ *
+ * Peek into the decode message and calculate the necessary buffer sizes.
+ */
+static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
+{
+ unsigned stream_type = msg[4];
+ unsigned width = msg[6];
+ unsigned height = msg[7];
+ unsigned dpb_size = msg[9];
+ unsigned pitch = msg[28];
+ unsigned level = msg[57];
+
+ unsigned width_in_mb = width / 16;
+ unsigned height_in_mb = ALIGN(height / 16, 2);
+ unsigned fs_in_mb = width_in_mb * height_in_mb;
+
+ unsigned image_size, tmp, min_dpb_size, num_dpb_buffer;
+
+ image_size = width * height;
+ image_size += image_size / 2;
+ image_size = ALIGN(image_size, 1024);
+
+ switch (stream_type) {
+ case 0: /* H264 */
+ case 7: /* H264 Perf */
+ switch(level) {
+ case 30:
+ num_dpb_buffer = 8100 / fs_in_mb;
+ break;
+ case 31:
+ num_dpb_buffer = 18000 / fs_in_mb;
+ break;
+ case 32:
+ num_dpb_buffer = 20480 / fs_in_mb;
+ break;
+ case 41:
+ num_dpb_buffer = 32768 / fs_in_mb;
+ break;
+ case 42:
+ num_dpb_buffer = 34816 / fs_in_mb;
+ break;
+ case 50:
+ num_dpb_buffer = 110400 / fs_in_mb;
+ break;
+ case 51:
+ num_dpb_buffer = 184320 / fs_in_mb;
+ break;
+ default:
+ num_dpb_buffer = 184320 / fs_in_mb;
+ break;
+ }
+ num_dpb_buffer++;
+ if (num_dpb_buffer > 17)
+ num_dpb_buffer = 17;
+
+ /* reference picture buffer */
+ min_dpb_size = image_size * num_dpb_buffer;
+
+ /* macroblock context buffer */
+ min_dpb_size += width_in_mb * height_in_mb * num_dpb_buffer * 192;
+
+ /* IT surface buffer */
+ min_dpb_size += width_in_mb * height_in_mb * 32;
+ break;
+
+ case 1: /* VC1 */
+
+ /* reference picture buffer */
+ min_dpb_size = image_size * 3;
+
+ /* CONTEXT_BUFFER */
+ min_dpb_size += width_in_mb * height_in_mb * 128;
+
+ /* IT surface buffer */
+ min_dpb_size += width_in_mb * 64;
+
+ /* DB surface buffer */
+ min_dpb_size += width_in_mb * 128;
+
+ /* BP */
+ tmp = max(width_in_mb, height_in_mb);
+ min_dpb_size += ALIGN(tmp * 7 * 16, 64);
+ break;
+
+ case 3: /* MPEG2 */
+
+ /* reference picture buffer */
+ min_dpb_size = image_size * 3;
+ break;
+
+ case 4: /* MPEG4 */
+
+ /* reference picture buffer */
+ min_dpb_size = image_size * 3;
+
+ /* CM */
+ min_dpb_size += width_in_mb * height_in_mb * 64;
+
+ /* IT surface buffer */
+ min_dpb_size += ALIGN(width_in_mb * height_in_mb * 32, 64);
+ break;
+
+ case 16: /* H265 */
+ image_size = (ALIGN(width, 16) * ALIGN(height, 16) * 3) / 2;
+ image_size = ALIGN(image_size, 256);
+
+ num_dpb_buffer = (le32_to_cpu(msg[59]) & 0xff) + 2;
+ min_dpb_size = image_size * num_dpb_buffer;
+ break;
+
+ default:
+ DRM_ERROR("UVD codec not handled %d!\n", stream_type);
+ return -EINVAL;
+ }
+
+ if (width > pitch) {
+ DRM_ERROR("Invalid UVD decoding target pitch!\n");
+ return -EINVAL;
+ }
+
+ if (dpb_size < min_dpb_size) {
+ DRM_ERROR("Invalid dpb_size in UVD message (%d / %d)!\n",
+ dpb_size, min_dpb_size);
+ return -EINVAL;
+ }
+
+ buf_sizes[0x1] = dpb_size;
+ buf_sizes[0x2] = image_size;
+ return 0;
+}
+
+/**
+ * amdgpu_uvd_cs_msg - handle UVD message
+ *
+ * @ctx: UVD parser context
+ * @bo: buffer object containing the message
+ * @offset: offset into the buffer object
+ *
+ * Peek into the UVD message and extract the session id.
+ * Make sure that we don't open up to many sessions.
+ */
+static int amdgpu_uvd_cs_msg(struct amdgpu_uvd_cs_ctx *ctx,
+ struct amdgpu_bo *bo, unsigned offset)
+{
+ struct amdgpu_device *adev = ctx->parser->adev;
+ int32_t *msg, msg_type, handle;
+ struct fence *f;
+ void *ptr;
+
+ int i, r;
+
+ if (offset & 0x3F) {
+ DRM_ERROR("UVD messages must be 64 byte aligned!\n");
+ return -EINVAL;
+ }
+
+ f = reservation_object_get_excl(bo->tbo.resv);
+ if (f) {
+ r = amdgpu_fence_wait((struct amdgpu_fence *)f, false);
+ if (r) {
+ DRM_ERROR("Failed waiting for UVD message (%d)!\n", r);
+ return r;
+ }
+ }
+
+ r = amdgpu_bo_kmap(bo, &ptr);
+ if (r) {
+ DRM_ERROR("Failed mapping the UVD message (%d)!\n", r);
+ return r;
+ }
+
+ msg = ptr + offset;
+
+ msg_type = msg[1];
+ handle = msg[2];
+
+ if (handle == 0) {
+ DRM_ERROR("Invalid UVD handle!\n");
+ return -EINVAL;
+ }
+
+ if (msg_type == 1) {
+ /* it's a decode msg, calc buffer sizes */
+ r = amdgpu_uvd_cs_msg_decode(msg, ctx->buf_sizes);
+ amdgpu_bo_kunmap(bo);
+ if (r)
+ return r;
+
+ } else if (msg_type == 2) {
+ /* it's a destroy msg, free the handle */
+ for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i)
+ atomic_cmpxchg(&adev->uvd.handles[i], handle, 0);
+ amdgpu_bo_kunmap(bo);
+ return 0;
+ } else {
+ /* it's a create msg */
+ amdgpu_bo_kunmap(bo);
+
+ if (msg_type != 0) {
+ DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
+ return -EINVAL;
+ }
+
+ /* it's a create msg, no special handling needed */
+ }
+
+ /* create or decode, validate the handle */
+ for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) {
+ if (atomic_read(&adev->uvd.handles[i]) == handle)
+ return 0;
+ }
+
+ /* handle not found try to alloc a new one */
+ for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) {
+ if (!atomic_cmpxchg(&adev->uvd.handles[i], 0, handle)) {
+ adev->uvd.filp[i] = ctx->parser->filp;
+ return 0;
+ }
+ }
+
+ DRM_ERROR("No more free UVD handles!\n");
+ return -EINVAL;
+}
+
+/**
+ * amdgpu_uvd_cs_pass2 - second parsing round
+ *
+ * @ctx: UVD parser context
+ *
+ * Patch buffer addresses, make sure buffer sizes are correct.
+ */
+static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx)
+{
+ struct amdgpu_bo_va_mapping *mapping;
+ struct amdgpu_bo *bo;
+ struct amdgpu_ib *ib;
+ uint32_t cmd, lo, hi;
+ uint64_t start, end;
+ uint64_t addr;
+ int r;
+
+ lo = amdgpu_get_ib_value(ctx->parser, ctx->ib_idx, ctx->data0);
+ hi = amdgpu_get_ib_value(ctx->parser, ctx->ib_idx, ctx->data1);
+ addr = ((uint64_t)lo) | (((uint64_t)hi) << 32);
+
+ mapping = amdgpu_cs_find_mapping(ctx->parser, addr, &bo);
+ if (mapping == NULL)
+ return -EINVAL;
+
+ start = amdgpu_bo_gpu_offset(bo);
+
+ end = (mapping->it.last + 1 - mapping->it.start);
+ end = end * AMDGPU_GPU_PAGE_SIZE + start;
+
+ addr -= ((uint64_t)mapping->it.start) * AMDGPU_GPU_PAGE_SIZE;
+ start += addr;
+
+ ib = &ctx->parser->ibs[ctx->ib_idx];
+ ib->ptr[ctx->data0] = start & 0xFFFFFFFF;
+ ib->ptr[ctx->data1] = start >> 32;
+
+ cmd = amdgpu_get_ib_value(ctx->parser, ctx->ib_idx, ctx->idx) >> 1;
+ if (cmd < 0x4) {
+ if ((end - start) < ctx->buf_sizes[cmd]) {
+ DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
+ (unsigned)(end - start),
+ ctx->buf_sizes[cmd]);
+ return -EINVAL;
+ }
+
+ } else if ((cmd != 0x100) && (cmd != 0x204)) {
+ DRM_ERROR("invalid UVD command %X!\n", cmd);
+ return -EINVAL;
+ }
+
+ if (!ctx->parser->adev->uvd.address_64_bit) {
+ if ((start >> 28) != ((end - 1) >> 28)) {
+ DRM_ERROR("reloc %LX-%LX crossing 256MB boundary!\n",
+ start, end);
+ return -EINVAL;
+ }
+
+ if ((cmd == 0 || cmd == 0x3) &&
+ (start >> 28) != (ctx->parser->adev->uvd.gpu_addr >> 28)) {
+ DRM_ERROR("msg/fb buffer %LX-%LX out of 256MB segment!\n",
+ start, end);
+ return -EINVAL;
+ }
+ }
+
+ if (cmd == 0) {
+ ctx->has_msg_cmd = true;
+ r = amdgpu_uvd_cs_msg(ctx, bo, addr);
+ if (r)
+ return r;
+ } else if (!ctx->has_msg_cmd) {
+ DRM_ERROR("Message needed before other commands are send!\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_uvd_cs_reg - parse register writes
+ *
+ * @ctx: UVD parser context
+ * @cb: callback function
+ *
+ * Parse the register writes, call cb on each complete command.
+ */
+static int amdgpu_uvd_cs_reg(struct amdgpu_uvd_cs_ctx *ctx,
+ int (*cb)(struct amdgpu_uvd_cs_ctx *ctx))
+{
+ struct amdgpu_ib *ib = &ctx->parser->ibs[ctx->ib_idx];
+ int i, r;
+
+ ctx->idx++;
+ for (i = 0; i <= ctx->count; ++i) {
+ unsigned reg = ctx->reg + i;
+
+ if (ctx->idx >= ib->length_dw) {
+ DRM_ERROR("Register command after end of CS!\n");
+ return -EINVAL;
+ }
+
+ switch (reg) {
+ case mmUVD_GPCOM_VCPU_DATA0:
+ ctx->data0 = ctx->idx;
+ break;
+ case mmUVD_GPCOM_VCPU_DATA1:
+ ctx->data1 = ctx->idx;
+ break;
+ case mmUVD_GPCOM_VCPU_CMD:
+ r = cb(ctx);
+ if (r)
+ return r;
+ break;
+ case mmUVD_ENGINE_CNTL:
+ break;
+ default:
+ DRM_ERROR("Invalid reg 0x%X!\n", reg);
+ return -EINVAL;
+ }
+ ctx->idx++;
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_uvd_cs_packets - parse UVD packets
+ *
+ * @ctx: UVD parser context
+ * @cb: callback function
+ *
+ * Parse the command stream packets.
+ */
+static int amdgpu_uvd_cs_packets(struct amdgpu_uvd_cs_ctx *ctx,
+ int (*cb)(struct amdgpu_uvd_cs_ctx *ctx))
+{
+ struct amdgpu_ib *ib = &ctx->parser->ibs[ctx->ib_idx];
+ int r;
+
+ for (ctx->idx = 0 ; ctx->idx < ib->length_dw; ) {
+ uint32_t cmd = amdgpu_get_ib_value(ctx->parser, ctx->ib_idx, ctx->idx);
+ unsigned type = CP_PACKET_GET_TYPE(cmd);
+ switch (type) {
+ case PACKET_TYPE0:
+ ctx->reg = CP_PACKET0_GET_REG(cmd);
+ ctx->count = CP_PACKET_GET_COUNT(cmd);
+ r = amdgpu_uvd_cs_reg(ctx, cb);
+ if (r)
+ return r;
+ break;
+ case PACKET_TYPE2:
+ ++ctx->idx;
+ break;
+ default:
+ DRM_ERROR("Unknown packet type %d !\n", type);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/**
+ * amdgpu_uvd_ring_parse_cs - UVD command submission parser
+ *
+ * @parser: Command submission parser context
+ *
+ * Parse the command stream, patch in addresses as necessary.
+ */
+int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx)
+{
+ struct amdgpu_uvd_cs_ctx ctx = {};
+ unsigned buf_sizes[] = {
+ [0x00000000] = 2048,
+ [0x00000001] = 32 * 1024 * 1024,
+ [0x00000002] = 2048 * 1152 * 3,
+ [0x00000003] = 2048,
+ };
+ struct amdgpu_ib *ib = &parser->ibs[ib_idx];
+ int r;
+
+ if (ib->length_dw % 16) {
+ DRM_ERROR("UVD IB length (%d) not 16 dwords aligned!\n",
+ ib->length_dw);
+ return -EINVAL;
+ }
+
+ ctx.parser = parser;
+ ctx.buf_sizes = buf_sizes;
+ ctx.ib_idx = ib_idx;
+
+ /* first round, make sure the buffers are actually in the UVD segment */
+ r = amdgpu_uvd_cs_packets(&ctx, amdgpu_uvd_cs_pass1);
+ if (r)
+ return r;
+
+ /* second round, patch buffer addresses into the command stream */
+ r = amdgpu_uvd_cs_packets(&ctx, amdgpu_uvd_cs_pass2);
+ if (r)
+ return r;
+
+ if (!ctx.has_msg_cmd) {
+ DRM_ERROR("UVD-IBs need a msg command!\n");
+ return -EINVAL;
+ }
+
+ amdgpu_uvd_note_usage(ctx.parser->adev);
+
+ return 0;
+}
+
+static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring,
+ struct amdgpu_bo *bo,
+ struct amdgpu_fence **fence)
+{
+ struct ttm_validate_buffer tv;
+ struct ww_acquire_ctx ticket;
+ struct list_head head;
+ struct amdgpu_ib ib;
+ uint64_t addr;
+ int i, r;
+
+ memset(&tv, 0, sizeof(tv));
+ tv.bo = &bo->tbo;
+
+ INIT_LIST_HEAD(&head);
+ list_add(&tv.head, &head);
+
+ r = ttm_eu_reserve_buffers(&ticket, &head, true, NULL);
+ if (r)
+ return r;
+
+ if (!bo->adev->uvd.address_64_bit) {
+ amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_VRAM);
+ amdgpu_uvd_force_into_uvd_segment(bo);
+ }
+
+ r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
+ if (r)
+ goto err;
+
+ r = amdgpu_ib_get(ring, NULL, 64, &ib);
+ if (r)
+ goto err;
+
+ addr = amdgpu_bo_gpu_offset(bo);
+ ib.ptr[0] = PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0);
+ ib.ptr[1] = addr;
+ ib.ptr[2] = PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0);
+ ib.ptr[3] = addr >> 32;
+ ib.ptr[4] = PACKET0(mmUVD_GPCOM_VCPU_CMD, 0);
+ ib.ptr[5] = 0;
+ for (i = 6; i < 16; ++i)
+ ib.ptr[i] = PACKET2(0);
+ ib.length_dw = 16;
+
+ r = amdgpu_ib_schedule(ring->adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
+ if (r)
+ goto err;
+ ttm_eu_fence_buffer_objects(&ticket, &head, &ib.fence->base);
+
+ if (fence)
+ *fence = amdgpu_fence_ref(ib.fence);
+
+ amdgpu_ib_free(ring->adev, &ib);
+ amdgpu_bo_unref(&bo);
+ return 0;
+
+err:
+ ttm_eu_backoff_reservation(&ticket, &head);
+ return r;
+}
+
+/* multiple fence commands without any stream commands in between can
+ crash the vcpu so just try to emmit a dummy create/destroy msg to
+ avoid this */
+int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
+ struct amdgpu_fence **fence)
+{
+ struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_bo *bo;
+ uint32_t *msg;
+ int r, i;
+
+ r = amdgpu_bo_create(adev, 1024, PAGE_SIZE, true,
+ AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &bo);
+ if (r)
+ return r;
+
+ r = amdgpu_bo_reserve(bo, false);
+ if (r) {
+ amdgpu_bo_unref(&bo);
+ return r;
+ }
+
+ r = amdgpu_bo_kmap(bo, (void **)&msg);
+ if (r) {
+ amdgpu_bo_unreserve(bo);
+ amdgpu_bo_unref(&bo);
+ return r;
+ }
+
+ /* stitch together an UVD create msg */
+ msg[0] = cpu_to_le32(0x00000de4);
+ msg[1] = cpu_to_le32(0x00000000);
+ msg[2] = cpu_to_le32(handle);
+ msg[3] = cpu_to_le32(0x00000000);
+ msg[4] = cpu_to_le32(0x00000000);
+ msg[5] = cpu_to_le32(0x00000000);
+ msg[6] = cpu_to_le32(0x00000000);
+ msg[7] = cpu_to_le32(0x00000780);
+ msg[8] = cpu_to_le32(0x00000440);
+ msg[9] = cpu_to_le32(0x00000000);
+ msg[10] = cpu_to_le32(0x01b37000);
+ for (i = 11; i < 1024; ++i)
+ msg[i] = cpu_to_le32(0x0);
+
+ amdgpu_bo_kunmap(bo);
+ amdgpu_bo_unreserve(bo);
+
+ return amdgpu_uvd_send_msg(ring, bo, fence);
+}
+
+int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
+ struct amdgpu_fence **fence)
+{
+ struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_bo *bo;
+ uint32_t *msg;
+ int r, i;
+
+ r = amdgpu_bo_create(adev, 1024, PAGE_SIZE, true,
+ AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &bo);
+ if (r)
+ return r;
+
+ r = amdgpu_bo_reserve(bo, false);
+ if (r) {
+ amdgpu_bo_unref(&bo);
+ return r;
+ }
+
+ r = amdgpu_bo_kmap(bo, (void **)&msg);
+ if (r) {
+ amdgpu_bo_unreserve(bo);
+ amdgpu_bo_unref(&bo);
+ return r;
+ }
+
+ /* stitch together an UVD destroy msg */
+ msg[0] = cpu_to_le32(0x00000de4);
+ msg[1] = cpu_to_le32(0x00000002);
+ msg[2] = cpu_to_le32(handle);
+ msg[3] = cpu_to_le32(0x00000000);
+ for (i = 4; i < 1024; ++i)
+ msg[i] = cpu_to_le32(0x0);
+
+ amdgpu_bo_kunmap(bo);
+ amdgpu_bo_unreserve(bo);
+
+ return amdgpu_uvd_send_msg(ring, bo, fence);
+}
+
+static void amdgpu_uvd_idle_work_handler(struct work_struct *work)
+{
+ struct amdgpu_device *adev =
+ container_of(work, struct amdgpu_device, uvd.idle_work.work);
+ unsigned i, fences, handles = 0;
+
+ fences = amdgpu_fence_count_emitted(&adev->uvd.ring);
+
+ for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i)
+ if (atomic_read(&adev->uvd.handles[i]))
+ ++handles;
+
+ if (fences == 0 && handles == 0) {
+ if (adev->pm.dpm_enabled) {
+ amdgpu_dpm_enable_uvd(adev, false);
+ } else {
+ amdgpu_asic_set_uvd_clocks(adev, 0, 0);
+ }
+ } else {
+ schedule_delayed_work(&adev->uvd.idle_work,
+ msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
+ }
+}
+
+static void amdgpu_uvd_note_usage(struct amdgpu_device *adev)
+{
+ bool set_clocks = !cancel_delayed_work_sync(&adev->uvd.idle_work);
+ set_clocks &= schedule_delayed_work(&adev->uvd.idle_work,
+ msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
+
+ if (set_clocks) {
+ if (adev->pm.dpm_enabled) {
+ amdgpu_dpm_enable_uvd(adev, true);
+ } else {
+ amdgpu_asic_set_uvd_clocks(adev, 53300, 40000);
+ }
+ }
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h
new file mode 100644
index 000000000000..2255aa710e33
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_UVD_H__
+#define __AMDGPU_UVD_H__
+
+int amdgpu_uvd_sw_init(struct amdgpu_device *adev);
+int amdgpu_uvd_sw_fini(struct amdgpu_device *adev);
+int amdgpu_uvd_suspend(struct amdgpu_device *adev);
+int amdgpu_uvd_resume(struct amdgpu_device *adev);
+int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
+ struct amdgpu_fence **fence);
+int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
+ struct amdgpu_fence **fence);
+void amdgpu_uvd_free_handles(struct amdgpu_device *adev,
+ struct drm_file *filp);
+int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
new file mode 100644
index 000000000000..1127a504f118
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -0,0 +1,724 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * Authors: Christian König <christian.koenig@amd.com>
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm.h>
+
+#include "amdgpu.h"
+#include "amdgpu_pm.h"
+#include "amdgpu_vce.h"
+#include "cikd.h"
+
+/* 1 second timeout */
+#define VCE_IDLE_TIMEOUT_MS 1000
+
+/* Firmware Names */
+#ifdef CONFIG_DRM_AMDGPU_CIK
+#define FIRMWARE_BONAIRE "radeon/bonaire_vce.bin"
+#define FIRMWARE_KABINI "radeon/kabini_vce.bin"
+#define FIRMWARE_KAVERI "radeon/kaveri_vce.bin"
+#define FIRMWARE_HAWAII "radeon/hawaii_vce.bin"
+#define FIRMWARE_MULLINS "radeon/mullins_vce.bin"
+#endif
+#define FIRMWARE_TONGA "amdgpu/tonga_vce.bin"
+#define FIRMWARE_CARRIZO "amdgpu/carrizo_vce.bin"
+
+#ifdef CONFIG_DRM_AMDGPU_CIK
+MODULE_FIRMWARE(FIRMWARE_BONAIRE);
+MODULE_FIRMWARE(FIRMWARE_KABINI);
+MODULE_FIRMWARE(FIRMWARE_KAVERI);
+MODULE_FIRMWARE(FIRMWARE_HAWAII);
+MODULE_FIRMWARE(FIRMWARE_MULLINS);
+#endif
+MODULE_FIRMWARE(FIRMWARE_TONGA);
+MODULE_FIRMWARE(FIRMWARE_CARRIZO);
+
+static void amdgpu_vce_idle_work_handler(struct work_struct *work);
+
+/**
+ * amdgpu_vce_init - allocate memory, load vce firmware
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * First step to get VCE online, allocate memory and load the firmware
+ */
+int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
+{
+ const char *fw_name;
+ const struct common_firmware_header *hdr;
+ unsigned ucode_version, version_major, version_minor, binary_id;
+ int i, r;
+
+ INIT_DELAYED_WORK(&adev->vce.idle_work, amdgpu_vce_idle_work_handler);
+
+ switch (adev->asic_type) {
+#ifdef CONFIG_DRM_AMDGPU_CIK
+ case CHIP_BONAIRE:
+ fw_name = FIRMWARE_BONAIRE;
+ break;
+ case CHIP_KAVERI:
+ fw_name = FIRMWARE_KAVERI;
+ break;
+ case CHIP_KABINI:
+ fw_name = FIRMWARE_KABINI;
+ break;
+ case CHIP_HAWAII:
+ fw_name = FIRMWARE_HAWAII;
+ break;
+ case CHIP_MULLINS:
+ fw_name = FIRMWARE_MULLINS;
+ break;
+#endif
+ case CHIP_TONGA:
+ fw_name = FIRMWARE_TONGA;
+ break;
+ case CHIP_CARRIZO:
+ fw_name = FIRMWARE_CARRIZO;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ r = request_firmware(&adev->vce.fw, fw_name, adev->dev);
+ if (r) {
+ dev_err(adev->dev, "amdgpu_vce: Can't load firmware \"%s\"\n",
+ fw_name);
+ return r;
+ }
+
+ r = amdgpu_ucode_validate(adev->vce.fw);
+ if (r) {
+ dev_err(adev->dev, "amdgpu_vce: Can't validate firmware \"%s\"\n",
+ fw_name);
+ release_firmware(adev->vce.fw);
+ adev->vce.fw = NULL;
+ return r;
+ }
+
+ hdr = (const struct common_firmware_header *)adev->vce.fw->data;
+
+ ucode_version = le32_to_cpu(hdr->ucode_version);
+ version_major = (ucode_version >> 20) & 0xfff;
+ version_minor = (ucode_version >> 8) & 0xfff;
+ binary_id = ucode_version & 0xff;
+ DRM_INFO("Found VCE firmware Version: %hhd.%hhd Binary ID: %hhd\n",
+ version_major, version_minor, binary_id);
+ adev->vce.fw_version = ((version_major << 24) | (version_minor << 16) |
+ (binary_id << 8));
+
+ /* allocate firmware, stack and heap BO */
+
+ r = amdgpu_bo_create(adev, size, PAGE_SIZE, true,
+ AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->vce.vcpu_bo);
+ if (r) {
+ dev_err(adev->dev, "(%d) failed to allocate VCE bo\n", r);
+ return r;
+ }
+
+ r = amdgpu_bo_reserve(adev->vce.vcpu_bo, false);
+ if (r) {
+ amdgpu_bo_unref(&adev->vce.vcpu_bo);
+ dev_err(adev->dev, "(%d) failed to reserve VCE bo\n", r);
+ return r;
+ }
+
+ r = amdgpu_bo_pin(adev->vce.vcpu_bo, AMDGPU_GEM_DOMAIN_VRAM,
+ &adev->vce.gpu_addr);
+ amdgpu_bo_unreserve(adev->vce.vcpu_bo);
+ if (r) {
+ amdgpu_bo_unref(&adev->vce.vcpu_bo);
+ dev_err(adev->dev, "(%d) VCE bo pin failed\n", r);
+ return r;
+ }
+
+ for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
+ atomic_set(&adev->vce.handles[i], 0);
+ adev->vce.filp[i] = NULL;
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_vce_fini - free memory
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Last step on VCE teardown, free firmware memory
+ */
+int amdgpu_vce_sw_fini(struct amdgpu_device *adev)
+{
+ if (adev->vce.vcpu_bo == NULL)
+ return 0;
+
+ amdgpu_bo_unref(&adev->vce.vcpu_bo);
+
+ amdgpu_ring_fini(&adev->vce.ring[0]);
+ amdgpu_ring_fini(&adev->vce.ring[1]);
+
+ release_firmware(adev->vce.fw);
+
+ return 0;
+}
+
+/**
+ * amdgpu_vce_suspend - unpin VCE fw memory
+ *
+ * @adev: amdgpu_device pointer
+ *
+ */
+int amdgpu_vce_suspend(struct amdgpu_device *adev)
+{
+ int i;
+
+ if (adev->vce.vcpu_bo == NULL)
+ return 0;
+
+ for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
+ if (atomic_read(&adev->vce.handles[i]))
+ break;
+
+ if (i == AMDGPU_MAX_VCE_HANDLES)
+ return 0;
+
+ /* TODO: suspending running encoding sessions isn't supported */
+ return -EINVAL;
+}
+
+/**
+ * amdgpu_vce_resume - pin VCE fw memory
+ *
+ * @adev: amdgpu_device pointer
+ *
+ */
+int amdgpu_vce_resume(struct amdgpu_device *adev)
+{
+ void *cpu_addr;
+ const struct common_firmware_header *hdr;
+ unsigned offset;
+ int r;
+
+ if (adev->vce.vcpu_bo == NULL)
+ return -EINVAL;
+
+ r = amdgpu_bo_reserve(adev->vce.vcpu_bo, false);
+ if (r) {
+ dev_err(adev->dev, "(%d) failed to reserve VCE bo\n", r);
+ return r;
+ }
+
+ r = amdgpu_bo_kmap(adev->vce.vcpu_bo, &cpu_addr);
+ if (r) {
+ amdgpu_bo_unreserve(adev->vce.vcpu_bo);
+ dev_err(adev->dev, "(%d) VCE map failed\n", r);
+ return r;
+ }
+
+ hdr = (const struct common_firmware_header *)adev->vce.fw->data;
+ offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
+ memcpy(cpu_addr, (adev->vce.fw->data) + offset,
+ (adev->vce.fw->size) - offset);
+
+ amdgpu_bo_kunmap(adev->vce.vcpu_bo);
+
+ amdgpu_bo_unreserve(adev->vce.vcpu_bo);
+
+ return 0;
+}
+
+/**
+ * amdgpu_vce_idle_work_handler - power off VCE
+ *
+ * @work: pointer to work structure
+ *
+ * power of VCE when it's not used any more
+ */
+static void amdgpu_vce_idle_work_handler(struct work_struct *work)
+{
+ struct amdgpu_device *adev =
+ container_of(work, struct amdgpu_device, vce.idle_work.work);
+
+ if ((amdgpu_fence_count_emitted(&adev->vce.ring[0]) == 0) &&
+ (amdgpu_fence_count_emitted(&adev->vce.ring[1]) == 0)) {
+ if (adev->pm.dpm_enabled) {
+ amdgpu_dpm_enable_vce(adev, false);
+ } else {
+ amdgpu_asic_set_vce_clocks(adev, 0, 0);
+ }
+ } else {
+ schedule_delayed_work(&adev->vce.idle_work,
+ msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS));
+ }
+}
+
+/**
+ * amdgpu_vce_note_usage - power up VCE
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Make sure VCE is powerd up when we want to use it
+ */
+static void amdgpu_vce_note_usage(struct amdgpu_device *adev)
+{
+ bool streams_changed = false;
+ bool set_clocks = !cancel_delayed_work_sync(&adev->vce.idle_work);
+ set_clocks &= schedule_delayed_work(&adev->vce.idle_work,
+ msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS));
+
+ if (adev->pm.dpm_enabled) {
+ /* XXX figure out if the streams changed */
+ streams_changed = false;
+ }
+
+ if (set_clocks || streams_changed) {
+ if (adev->pm.dpm_enabled) {
+ amdgpu_dpm_enable_vce(adev, true);
+ } else {
+ amdgpu_asic_set_vce_clocks(adev, 53300, 40000);
+ }
+ }
+}
+
+/**
+ * amdgpu_vce_free_handles - free still open VCE handles
+ *
+ * @adev: amdgpu_device pointer
+ * @filp: drm file pointer
+ *
+ * Close all VCE handles still open by this file pointer
+ */
+void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
+{
+ struct amdgpu_ring *ring = &adev->vce.ring[0];
+ int i, r;
+ for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
+ uint32_t handle = atomic_read(&adev->vce.handles[i]);
+ if (!handle || adev->vce.filp[i] != filp)
+ continue;
+
+ amdgpu_vce_note_usage(adev);
+
+ r = amdgpu_vce_get_destroy_msg(ring, handle, NULL);
+ if (r)
+ DRM_ERROR("Error destroying VCE handle (%d)!\n", r);
+
+ adev->vce.filp[i] = NULL;
+ atomic_set(&adev->vce.handles[i], 0);
+ }
+}
+
+/**
+ * amdgpu_vce_get_create_msg - generate a VCE create msg
+ *
+ * @adev: amdgpu_device pointer
+ * @ring: ring we should submit the msg to
+ * @handle: VCE session handle to use
+ * @fence: optional fence to return
+ *
+ * Open up a stream for HW test
+ */
+int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
+ struct amdgpu_fence **fence)
+{
+ const unsigned ib_size_dw = 1024;
+ struct amdgpu_ib ib;
+ uint64_t dummy;
+ int i, r;
+
+ r = amdgpu_ib_get(ring, NULL, ib_size_dw * 4, &ib);
+ if (r) {
+ DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
+ return r;
+ }
+
+ dummy = ib.gpu_addr + 1024;
+
+ /* stitch together an VCE create msg */
+ ib.length_dw = 0;
+ ib.ptr[ib.length_dw++] = 0x0000000c; /* len */
+ ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */
+ ib.ptr[ib.length_dw++] = handle;
+
+ ib.ptr[ib.length_dw++] = 0x00000030; /* len */
+ ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */
+ ib.ptr[ib.length_dw++] = 0x00000000;
+ ib.ptr[ib.length_dw++] = 0x00000042;
+ ib.ptr[ib.length_dw++] = 0x0000000a;
+ ib.ptr[ib.length_dw++] = 0x00000001;
+ ib.ptr[ib.length_dw++] = 0x00000080;
+ ib.ptr[ib.length_dw++] = 0x00000060;
+ ib.ptr[ib.length_dw++] = 0x00000100;
+ ib.ptr[ib.length_dw++] = 0x00000100;
+ ib.ptr[ib.length_dw++] = 0x0000000c;
+ ib.ptr[ib.length_dw++] = 0x00000000;
+
+ ib.ptr[ib.length_dw++] = 0x00000014; /* len */
+ ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */
+ ib.ptr[ib.length_dw++] = upper_32_bits(dummy);
+ ib.ptr[ib.length_dw++] = dummy;
+ ib.ptr[ib.length_dw++] = 0x00000001;
+
+ for (i = ib.length_dw; i < ib_size_dw; ++i)
+ ib.ptr[i] = 0x0;
+
+ r = amdgpu_ib_schedule(ring->adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
+ if (r) {
+ DRM_ERROR("amdgpu: failed to schedule ib (%d).\n", r);
+ }
+
+ if (fence)
+ *fence = amdgpu_fence_ref(ib.fence);
+
+ amdgpu_ib_free(ring->adev, &ib);
+
+ return r;
+}
+
+/**
+ * amdgpu_vce_get_destroy_msg - generate a VCE destroy msg
+ *
+ * @adev: amdgpu_device pointer
+ * @ring: ring we should submit the msg to
+ * @handle: VCE session handle to use
+ * @fence: optional fence to return
+ *
+ * Close up a stream for HW test or if userspace failed to do so
+ */
+int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
+ struct amdgpu_fence **fence)
+{
+ const unsigned ib_size_dw = 1024;
+ struct amdgpu_ib ib;
+ uint64_t dummy;
+ int i, r;
+
+ r = amdgpu_ib_get(ring, NULL, ib_size_dw * 4, &ib);
+ if (r) {
+ DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
+ return r;
+ }
+
+ dummy = ib.gpu_addr + 1024;
+
+ /* stitch together an VCE destroy msg */
+ ib.length_dw = 0;
+ ib.ptr[ib.length_dw++] = 0x0000000c; /* len */
+ ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */
+ ib.ptr[ib.length_dw++] = handle;
+
+ ib.ptr[ib.length_dw++] = 0x00000014; /* len */
+ ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */
+ ib.ptr[ib.length_dw++] = upper_32_bits(dummy);
+ ib.ptr[ib.length_dw++] = dummy;
+ ib.ptr[ib.length_dw++] = 0x00000001;
+
+ ib.ptr[ib.length_dw++] = 0x00000008; /* len */
+ ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */
+
+ for (i = ib.length_dw; i < ib_size_dw; ++i)
+ ib.ptr[i] = 0x0;
+
+ r = amdgpu_ib_schedule(ring->adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
+ if (r) {
+ DRM_ERROR("amdgpu: failed to schedule ib (%d).\n", r);
+ }
+
+ if (fence)
+ *fence = amdgpu_fence_ref(ib.fence);
+
+ amdgpu_ib_free(ring->adev, &ib);
+
+ return r;
+}
+
+/**
+ * amdgpu_vce_cs_reloc - command submission relocation
+ *
+ * @p: parser context
+ * @lo: address of lower dword
+ * @hi: address of higher dword
+ *
+ * Patch relocation inside command stream with real buffer address
+ */
+int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int hi)
+{
+ struct amdgpu_bo_va_mapping *mapping;
+ struct amdgpu_ib *ib = &p->ibs[ib_idx];
+ struct amdgpu_bo *bo;
+ uint64_t addr;
+
+ addr = ((uint64_t)amdgpu_get_ib_value(p, ib_idx, lo)) |
+ ((uint64_t)amdgpu_get_ib_value(p, ib_idx, hi)) << 32;
+
+ mapping = amdgpu_cs_find_mapping(p, addr, &bo);
+ if (mapping == NULL) {
+ DRM_ERROR("Can't find BO for addr 0x%010Lx %d %d\n",
+ addr, lo, hi);
+ return -EINVAL;
+ }
+
+ addr -= ((uint64_t)mapping->it.start) * AMDGPU_GPU_PAGE_SIZE;
+ addr += amdgpu_bo_gpu_offset(bo);
+
+ ib->ptr[lo] = addr & 0xFFFFFFFF;
+ ib->ptr[hi] = addr >> 32;
+
+ return 0;
+}
+
+/**
+ * amdgpu_vce_cs_parse - parse and validate the command stream
+ *
+ * @p: parser context
+ *
+ */
+int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
+{
+ uint32_t handle = 0;
+ bool destroy = false;
+ int i, r, idx = 0;
+ struct amdgpu_ib *ib = &p->ibs[ib_idx];
+
+ amdgpu_vce_note_usage(p->adev);
+
+ while (idx < ib->length_dw) {
+ uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
+ uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1);
+
+ if ((len < 8) || (len & 3)) {
+ DRM_ERROR("invalid VCE command length (%d)!\n", len);
+ return -EINVAL;
+ }
+
+ switch (cmd) {
+ case 0x00000001: // session
+ handle = amdgpu_get_ib_value(p, ib_idx, idx + 2);
+ break;
+
+ case 0x00000002: // task info
+ case 0x01000001: // create
+ case 0x04000001: // config extension
+ case 0x04000002: // pic control
+ case 0x04000005: // rate control
+ case 0x04000007: // motion estimation
+ case 0x04000008: // rdo
+ case 0x04000009: // vui
+ case 0x05000002: // auxiliary buffer
+ break;
+
+ case 0x03000001: // encode
+ r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9);
+ if (r)
+ return r;
+
+ r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11);
+ if (r)
+ return r;
+ break;
+
+ case 0x02000001: // destroy
+ destroy = true;
+ break;
+
+ case 0x05000001: // context buffer
+ case 0x05000004: // video bitstream buffer
+ case 0x05000005: // feedback buffer
+ r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2);
+ if (r)
+ return r;
+ break;
+
+ default:
+ DRM_ERROR("invalid VCE command (0x%x)!\n", cmd);
+ return -EINVAL;
+ }
+
+ idx += len / 4;
+ }
+
+ if (destroy) {
+ /* IB contains a destroy msg, free the handle */
+ for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
+ atomic_cmpxchg(&p->adev->vce.handles[i], handle, 0);
+
+ return 0;
+ }
+
+ /* create or encode, validate the handle */
+ for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
+ if (atomic_read(&p->adev->vce.handles[i]) == handle)
+ return 0;
+ }
+
+ /* handle not found try to alloc a new one */
+ for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
+ if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) {
+ p->adev->vce.filp[i] = p->filp;
+ return 0;
+ }
+ }
+
+ DRM_ERROR("No more free VCE handles!\n");
+
+ return -EINVAL;
+}
+
+/**
+ * amdgpu_vce_ring_emit_semaphore - emit a semaphore command
+ *
+ * @ring: engine to use
+ * @semaphore: address of semaphore
+ * @emit_wait: true=emit wait, false=emit signal
+ *
+ */
+bool amdgpu_vce_ring_emit_semaphore(struct amdgpu_ring *ring,
+ struct amdgpu_semaphore *semaphore,
+ bool emit_wait)
+{
+ uint64_t addr = semaphore->gpu_addr;
+
+ amdgpu_ring_write(ring, VCE_CMD_SEMAPHORE);
+ amdgpu_ring_write(ring, (addr >> 3) & 0x000FFFFF);
+ amdgpu_ring_write(ring, (addr >> 23) & 0x000FFFFF);
+ amdgpu_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0));
+ if (!emit_wait)
+ amdgpu_ring_write(ring, VCE_CMD_END);
+
+ return true;
+}
+
+/**
+ * amdgpu_vce_ring_emit_ib - execute indirect buffer
+ *
+ * @ring: engine to use
+ * @ib: the IB to execute
+ *
+ */
+void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
+{
+ amdgpu_ring_write(ring, VCE_CMD_IB);
+ amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
+ amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
+ amdgpu_ring_write(ring, ib->length_dw);
+}
+
+/**
+ * amdgpu_vce_ring_emit_fence - add a fence command to the ring
+ *
+ * @ring: engine to use
+ * @fence: the fence
+ *
+ */
+void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
+ unsigned flags)
+{
+ WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
+
+ amdgpu_ring_write(ring, VCE_CMD_FENCE);
+ amdgpu_ring_write(ring, addr);
+ amdgpu_ring_write(ring, upper_32_bits(addr));
+ amdgpu_ring_write(ring, seq);
+ amdgpu_ring_write(ring, VCE_CMD_TRAP);
+ amdgpu_ring_write(ring, VCE_CMD_END);
+}
+
+/**
+ * amdgpu_vce_ring_test_ring - test if VCE ring is working
+ *
+ * @ring: the engine to test on
+ *
+ */
+int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ uint32_t rptr = amdgpu_ring_get_rptr(ring);
+ unsigned i;
+ int r;
+
+ r = amdgpu_ring_lock(ring, 16);
+ if (r) {
+ DRM_ERROR("amdgpu: vce failed to lock ring %d (%d).\n",
+ ring->idx, r);
+ return r;
+ }
+ amdgpu_ring_write(ring, VCE_CMD_END);
+ amdgpu_ring_unlock_commit(ring);
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if (amdgpu_ring_get_rptr(ring) != rptr)
+ break;
+ DRM_UDELAY(1);
+ }
+
+ if (i < adev->usec_timeout) {
+ DRM_INFO("ring test on %d succeeded in %d usecs\n",
+ ring->idx, i);
+ } else {
+ DRM_ERROR("amdgpu: ring %d test failed\n",
+ ring->idx);
+ r = -ETIMEDOUT;
+ }
+
+ return r;
+}
+
+/**
+ * amdgpu_vce_ring_test_ib - test if VCE IBs are working
+ *
+ * @ring: the engine to test on
+ *
+ */
+int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring)
+{
+ struct amdgpu_fence *fence = NULL;
+ int r;
+
+ r = amdgpu_vce_get_create_msg(ring, 1, NULL);
+ if (r) {
+ DRM_ERROR("amdgpu: failed to get create msg (%d).\n", r);
+ goto error;
+ }
+
+ r = amdgpu_vce_get_destroy_msg(ring, 1, &fence);
+ if (r) {
+ DRM_ERROR("amdgpu: failed to get destroy ib (%d).\n", r);
+ goto error;
+ }
+
+ r = amdgpu_fence_wait(fence, false);
+ if (r) {
+ DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
+ } else {
+ DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
+ }
+error:
+ amdgpu_fence_unref(&fence);
+ return r;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
new file mode 100644
index 000000000000..b6a9d0956c60
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __AMDGPU_VCE_H__
+#define __AMDGPU_VCE_H__
+
+int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size);
+int amdgpu_vce_sw_fini(struct amdgpu_device *adev);
+int amdgpu_vce_suspend(struct amdgpu_device *adev);
+int amdgpu_vce_resume(struct amdgpu_device *adev);
+int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
+ struct amdgpu_fence **fence);
+int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
+ struct amdgpu_fence **fence);
+void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp);
+int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int hi);
+int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx);
+bool amdgpu_vce_ring_emit_semaphore(struct amdgpu_ring *ring,
+ struct amdgpu_semaphore *semaphore,
+ bool emit_wait);
+void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib);
+void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
+ unsigned flags);
+int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring);
+int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
new file mode 100644
index 000000000000..407882b233c7
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -0,0 +1,1269 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "amdgpu_trace.h"
+
+/*
+ * GPUVM
+ * GPUVM is similar to the legacy gart on older asics, however
+ * rather than there being a single global gart table
+ * for the entire GPU, there are multiple VM page tables active
+ * at any given time. The VM page tables can contain a mix
+ * vram pages and system memory pages and system memory pages
+ * can be mapped as snooped (cached system pages) or unsnooped
+ * (uncached system pages).
+ * Each VM has an ID associated with it and there is a page table
+ * associated with each VMID. When execting a command buffer,
+ * the kernel tells the the ring what VMID to use for that command
+ * buffer. VMIDs are allocated dynamically as commands are submitted.
+ * The userspace drivers maintain their own address space and the kernel
+ * sets up their pages tables accordingly when they submit their
+ * command buffers and a VMID is assigned.
+ * Cayman/Trinity support up to 8 active VMs at any given time;
+ * SI supports 16.
+ */
+
+/**
+ * amdgpu_vm_num_pde - return the number of page directory entries
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Calculate the number of page directory entries (cayman+).
+ */
+static unsigned amdgpu_vm_num_pdes(struct amdgpu_device *adev)
+{
+ return adev->vm_manager.max_pfn >> amdgpu_vm_block_size;
+}
+
+/**
+ * amdgpu_vm_directory_size - returns the size of the page directory in bytes
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Calculate the size of the page directory in bytes (cayman+).
+ */
+static unsigned amdgpu_vm_directory_size(struct amdgpu_device *adev)
+{
+ return AMDGPU_GPU_PAGE_ALIGN(amdgpu_vm_num_pdes(adev) * 8);
+}
+
+/**
+ * amdgpu_vm_get_bos - add the vm BOs to a validation list
+ *
+ * @vm: vm providing the BOs
+ * @head: head of validation list
+ *
+ * Add the page directory to the list of BOs to
+ * validate for command submission (cayman+).
+ */
+struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm,
+ struct list_head *head)
+{
+ struct amdgpu_bo_list_entry *list;
+ unsigned i, idx;
+
+ mutex_lock(&vm->mutex);
+ list = drm_malloc_ab(vm->max_pde_used + 2,
+ sizeof(struct amdgpu_bo_list_entry));
+ if (!list) {
+ mutex_unlock(&vm->mutex);
+ return NULL;
+ }
+
+ /* 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)
+ 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);
+ }
+ mutex_unlock(&vm->mutex);
+
+ return list;
+}
+
+/**
+ * amdgpu_vm_grab_id - allocate the next free VMID
+ *
+ * @ring: ring we want to submit job to
+ * @vm: vm to allocate id for
+ *
+ * Allocate an id for the vm (cayman+).
+ * Returns the fence we need to sync to (if any).
+ *
+ * Global and local mutex must be locked!
+ */
+struct amdgpu_fence *amdgpu_vm_grab_id(struct amdgpu_ring *ring,
+ struct amdgpu_vm *vm)
+{
+ struct amdgpu_fence *best[AMDGPU_MAX_RINGS] = {};
+ struct amdgpu_vm_id *vm_id = &vm->ids[ring->idx];
+ struct amdgpu_device *adev = ring->adev;
+
+ unsigned choices[2] = {};
+ unsigned i;
+
+ /* check if the id is still valid */
+ if (vm_id->id && vm_id->last_id_use &&
+ vm_id->last_id_use == adev->vm_manager.active[vm_id->id])
+ return NULL;
+
+ /* we definately need to flush */
+ vm_id->pd_gpu_addr = ~0ll;
+
+ /* skip over VMID 0, since it is the system VM */
+ for (i = 1; i < adev->vm_manager.nvm; ++i) {
+ struct amdgpu_fence *fence = adev->vm_manager.active[i];
+
+ if (fence == NULL) {
+ /* found a free one */
+ vm_id->id = i;
+ trace_amdgpu_vm_grab_id(i, ring->idx);
+ return NULL;
+ }
+
+ if (amdgpu_fence_is_earlier(fence, best[fence->ring->idx])) {
+ best[fence->ring->idx] = fence;
+ choices[fence->ring == ring ? 0 : 1] = i;
+ }
+ }
+
+ for (i = 0; i < 2; ++i) {
+ if (choices[i]) {
+ vm_id->id = choices[i];
+ trace_amdgpu_vm_grab_id(choices[i], ring->idx);
+ return adev->vm_manager.active[choices[i]];
+ }
+ }
+
+ /* should never happen */
+ BUG();
+ return NULL;
+}
+
+/**
+ * amdgpu_vm_flush - hardware flush the vm
+ *
+ * @ring: ring to use for flush
+ * @vm: vm we want to flush
+ * @updates: last vm update that we waited for
+ *
+ * Flush the vm (cayman+).
+ *
+ * Global and local mutex must be locked!
+ */
+void amdgpu_vm_flush(struct amdgpu_ring *ring,
+ struct amdgpu_vm *vm,
+ struct amdgpu_fence *updates)
+{
+ uint64_t pd_addr = amdgpu_bo_gpu_offset(vm->page_directory);
+ struct amdgpu_vm_id *vm_id = &vm->ids[ring->idx];
+
+ if (pd_addr != vm_id->pd_gpu_addr || !vm_id->flushed_updates ||
+ amdgpu_fence_is_earlier(vm_id->flushed_updates, updates)) {
+
+ trace_amdgpu_vm_flush(pd_addr, ring->idx, vm_id->id);
+ amdgpu_fence_unref(&vm_id->flushed_updates);
+ vm_id->flushed_updates = amdgpu_fence_ref(updates);
+ vm_id->pd_gpu_addr = pd_addr;
+ amdgpu_ring_emit_vm_flush(ring, vm_id->id, vm_id->pd_gpu_addr);
+ }
+}
+
+/**
+ * amdgpu_vm_fence - remember fence for vm
+ *
+ * @adev: amdgpu_device pointer
+ * @vm: vm we want to fence
+ * @fence: fence to remember
+ *
+ * Fence the vm (cayman+).
+ * Set the fence used to protect page table and id.
+ *
+ * Global and local mutex must be locked!
+ */
+void amdgpu_vm_fence(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm,
+ struct amdgpu_fence *fence)
+{
+ unsigned ridx = fence->ring->idx;
+ unsigned vm_id = vm->ids[ridx].id;
+
+ amdgpu_fence_unref(&adev->vm_manager.active[vm_id]);
+ adev->vm_manager.active[vm_id] = amdgpu_fence_ref(fence);
+
+ amdgpu_fence_unref(&vm->ids[ridx].last_id_use);
+ vm->ids[ridx].last_id_use = amdgpu_fence_ref(fence);
+}
+
+/**
+ * amdgpu_vm_bo_find - find the bo_va for a specific vm & bo
+ *
+ * @vm: requested vm
+ * @bo: requested buffer object
+ *
+ * Find @bo inside the requested vm (cayman+).
+ * Search inside the @bos vm list for the requested vm
+ * Returns the found bo_va or NULL if none is found
+ *
+ * Object has to be reserved!
+ */
+struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm,
+ struct amdgpu_bo *bo)
+{
+ struct amdgpu_bo_va *bo_va;
+
+ list_for_each_entry(bo_va, &bo->va, bo_list) {
+ if (bo_va->vm == vm) {
+ return bo_va;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * amdgpu_vm_update_pages - helper to call the right asic function
+ *
+ * @adev: amdgpu_device pointer
+ * @ib: indirect buffer to fill with commands
+ * @pe: addr of the page entry
+ * @addr: dst addr to write into pe
+ * @count: number of page entries to update
+ * @incr: increase next addr by incr bytes
+ * @flags: hw access flags
+ * @gtt_flags: GTT hw access flags
+ *
+ * Traces the parameters and calls the right asic functions
+ * to setup the page table using the DMA.
+ */
+static void amdgpu_vm_update_pages(struct amdgpu_device *adev,
+ struct amdgpu_ib *ib,
+ uint64_t pe, uint64_t addr,
+ unsigned count, uint32_t incr,
+ uint32_t flags, uint32_t gtt_flags)
+{
+ trace_amdgpu_vm_set_page(pe, addr, count, incr, flags);
+
+ if ((flags & AMDGPU_PTE_SYSTEM) && (flags == gtt_flags)) {
+ uint64_t src = adev->gart.table_addr + (addr >> 12) * 8;
+ amdgpu_vm_copy_pte(adev, ib, pe, src, count);
+
+ } else if ((flags & AMDGPU_PTE_SYSTEM) || (count < 3)) {
+ amdgpu_vm_write_pte(adev, ib, pe, addr,
+ count, incr, flags);
+
+ } else {
+ amdgpu_vm_set_pte_pde(adev, ib, pe, addr,
+ count, incr, flags);
+ }
+}
+
+/**
+ * amdgpu_vm_clear_bo - initially clear the page dir/table
+ *
+ * @adev: amdgpu_device pointer
+ * @bo: bo to clear
+ */
+static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
+ struct amdgpu_bo *bo)
+{
+ struct amdgpu_ring *ring = adev->vm_manager.vm_pte_funcs_ring;
+ struct amdgpu_ib ib;
+ unsigned entries;
+ uint64_t addr;
+ int r;
+
+ r = amdgpu_bo_reserve(bo, false);
+ if (r)
+ return r;
+
+ r = reservation_object_reserve_shared(bo->tbo.resv);
+ if (r)
+ return r;
+
+ r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
+ if (r)
+ goto error_unreserve;
+
+ addr = amdgpu_bo_gpu_offset(bo);
+ entries = amdgpu_bo_size(bo) / 8;
+
+ r = amdgpu_ib_get(ring, NULL, entries * 2 + 64, &ib);
+ if (r)
+ goto error_unreserve;
+
+ ib.length_dw = 0;
+
+ amdgpu_vm_update_pages(adev, &ib, addr, 0, entries, 0, 0, 0);
+ amdgpu_vm_pad_ib(adev, &ib);
+ WARN_ON(ib.length_dw > 64);
+
+ r = amdgpu_ib_schedule(adev, 1, &ib, AMDGPU_FENCE_OWNER_VM);
+ if (r)
+ goto error_free;
+
+ amdgpu_bo_fence(bo, ib.fence, true);
+
+error_free:
+ amdgpu_ib_free(adev, &ib);
+
+error_unreserve:
+ amdgpu_bo_unreserve(bo);
+ return r;
+}
+
+/**
+ * amdgpu_vm_map_gart - get the physical address of a gart page
+ *
+ * @adev: amdgpu_device pointer
+ * @addr: the unmapped addr
+ *
+ * Look up the physical address of the page that the pte resolves
+ * to (cayman+).
+ * Returns the physical address of the page.
+ */
+uint64_t amdgpu_vm_map_gart(struct amdgpu_device *adev, uint64_t addr)
+{
+ uint64_t result;
+
+ /* page table offset */
+ result = adev->gart.pages_addr[addr >> PAGE_SHIFT];
+
+ /* in case cpu page size != gpu page size*/
+ result |= addr & (~PAGE_MASK);
+
+ return result;
+}
+
+/**
+ * amdgpu_vm_update_pdes - make sure that page directory is valid
+ *
+ * @adev: amdgpu_device pointer
+ * @vm: requested vm
+ * @start: start of GPU address range
+ * @end: end of GPU address range
+ *
+ * Allocates new page tables if necessary
+ * and updates the page directory (cayman+).
+ * Returns 0 for success, error for failure.
+ *
+ * Global and local mutex must be locked!
+ */
+int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm)
+{
+ struct amdgpu_ring *ring = adev->vm_manager.vm_pte_funcs_ring;
+ struct amdgpu_bo *pd = vm->page_directory;
+ uint64_t pd_addr = amdgpu_bo_gpu_offset(pd);
+ uint32_t incr = AMDGPU_VM_PTE_COUNT * 8;
+ uint64_t last_pde = ~0, last_pt = ~0;
+ unsigned count = 0, pt_idx, ndw;
+ struct amdgpu_ib ib;
+ int r;
+
+ /* padding, etc. */
+ ndw = 64;
+
+ /* assume the worst case */
+ ndw += vm->max_pde_used * 6;
+
+ /* update too big for an IB */
+ if (ndw > 0xfffff)
+ return -ENOMEM;
+
+ r = amdgpu_ib_get(ring, NULL, ndw * 4, &ib);
+ if (r)
+ return r;
+ ib.length_dw = 0;
+
+ /* 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;
+ uint64_t pde, pt;
+
+ if (bo == NULL)
+ continue;
+
+ pt = amdgpu_bo_gpu_offset(bo);
+ if (vm->page_tables[pt_idx].addr == pt)
+ continue;
+ vm->page_tables[pt_idx].addr = pt;
+
+ pde = pd_addr + pt_idx * 8;
+ if (((last_pde + 8 * count) != pde) ||
+ ((last_pt + incr * count) != pt)) {
+
+ if (count) {
+ amdgpu_vm_update_pages(adev, &ib, last_pde,
+ last_pt, count, incr,
+ AMDGPU_PTE_VALID, 0);
+ }
+
+ count = 1;
+ last_pde = pde;
+ last_pt = pt;
+ } else {
+ ++count;
+ }
+ }
+
+ if (count)
+ amdgpu_vm_update_pages(adev, &ib, last_pde, last_pt, count,
+ incr, AMDGPU_PTE_VALID, 0);
+
+ if (ib.length_dw != 0) {
+ amdgpu_vm_pad_ib(adev, &ib);
+ amdgpu_sync_resv(adev, &ib.sync, pd->tbo.resv, AMDGPU_FENCE_OWNER_VM);
+ WARN_ON(ib.length_dw > ndw);
+ r = amdgpu_ib_schedule(adev, 1, &ib, AMDGPU_FENCE_OWNER_VM);
+ if (r) {
+ amdgpu_ib_free(adev, &ib);
+ return r;
+ }
+ amdgpu_bo_fence(pd, ib.fence, true);
+ }
+ amdgpu_ib_free(adev, &ib);
+
+ return 0;
+}
+
+/**
+ * amdgpu_vm_frag_ptes - add fragment information to PTEs
+ *
+ * @adev: amdgpu_device pointer
+ * @ib: IB for the update
+ * @pe_start: first PTE to handle
+ * @pe_end: last PTE to handle
+ * @addr: addr those PTEs should point to
+ * @flags: hw mapping flags
+ * @gtt_flags: GTT hw mapping flags
+ *
+ * Global and local mutex must be locked!
+ */
+static void amdgpu_vm_frag_ptes(struct amdgpu_device *adev,
+ struct amdgpu_ib *ib,
+ uint64_t pe_start, uint64_t pe_end,
+ uint64_t addr, uint32_t flags,
+ uint32_t gtt_flags)
+{
+ /**
+ * The MC L1 TLB supports variable sized pages, based on a fragment
+ * field in the PTE. When this field is set to a non-zero value, page
+ * granularity is increased from 4KB to (1 << (12 + frag)). The PTE
+ * flags are considered valid for all PTEs within the fragment range
+ * and corresponding mappings are assumed to be physically contiguous.
+ *
+ * The L1 TLB can store a single PTE for the whole fragment,
+ * significantly increasing the space available for translation
+ * caching. This leads to large improvements in throughput when the
+ * TLB is under pressure.
+ *
+ * The L2 TLB distributes small and large fragments into two
+ * asymmetric partitions. The large fragment cache is significantly
+ * larger. Thus, we try to use large fragments wherever possible.
+ * Userspace can support this by aligning virtual base address and
+ * allocation size to the fragment size.
+ */
+
+ /* SI and newer are optimized for 64KB */
+ uint64_t frag_flags = AMDGPU_PTE_FRAG_64KB;
+ uint64_t frag_align = 0x80;
+
+ uint64_t frag_start = ALIGN(pe_start, frag_align);
+ uint64_t frag_end = pe_end & ~(frag_align - 1);
+
+ unsigned count;
+
+ /* system pages are non continuously */
+ if ((flags & AMDGPU_PTE_SYSTEM) || !(flags & AMDGPU_PTE_VALID) ||
+ (frag_start >= frag_end)) {
+
+ count = (pe_end - pe_start) / 8;
+ amdgpu_vm_update_pages(adev, ib, pe_start, addr, count,
+ AMDGPU_GPU_PAGE_SIZE, flags, gtt_flags);
+ return;
+ }
+
+ /* handle the 4K area at the beginning */
+ if (pe_start != frag_start) {
+ count = (frag_start - pe_start) / 8;
+ amdgpu_vm_update_pages(adev, ib, pe_start, addr, count,
+ AMDGPU_GPU_PAGE_SIZE, flags, gtt_flags);
+ addr += AMDGPU_GPU_PAGE_SIZE * count;
+ }
+
+ /* handle the area in the middle */
+ count = (frag_end - frag_start) / 8;
+ amdgpu_vm_update_pages(adev, ib, frag_start, addr, count,
+ AMDGPU_GPU_PAGE_SIZE, flags | frag_flags,
+ gtt_flags);
+
+ /* handle the 4K area at the end */
+ if (frag_end != pe_end) {
+ addr += AMDGPU_GPU_PAGE_SIZE * count;
+ count = (pe_end - frag_end) / 8;
+ amdgpu_vm_update_pages(adev, ib, frag_end, addr, count,
+ AMDGPU_GPU_PAGE_SIZE, flags, gtt_flags);
+ }
+}
+
+/**
+ * amdgpu_vm_update_ptes - make sure that page tables are valid
+ *
+ * @adev: amdgpu_device pointer
+ * @vm: requested vm
+ * @start: start of GPU address range
+ * @end: end of GPU address range
+ * @dst: destination address to map to
+ * @flags: mapping flags
+ *
+ * Update the page tables in the range @start - @end (cayman+).
+ *
+ * Global and local mutex must be locked!
+ */
+static int amdgpu_vm_update_ptes(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm,
+ struct amdgpu_ib *ib,
+ uint64_t start, uint64_t end,
+ uint64_t dst, uint32_t flags,
+ uint32_t gtt_flags)
+{
+ uint64_t mask = AMDGPU_VM_PTE_COUNT - 1;
+ uint64_t last_pte = ~0, last_dst = ~0;
+ unsigned count = 0;
+ uint64_t addr;
+
+ /* 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;
+ unsigned nptes;
+ uint64_t pte;
+ int r;
+
+ amdgpu_sync_resv(adev, &ib->sync, pt->tbo.resv,
+ AMDGPU_FENCE_OWNER_VM);
+ r = reservation_object_reserve_shared(pt->tbo.resv);
+ if (r)
+ return r;
+
+ if ((addr & ~mask) == (end & ~mask))
+ nptes = end - addr;
+ else
+ nptes = AMDGPU_VM_PTE_COUNT - (addr & mask);
+
+ pte = amdgpu_bo_gpu_offset(pt);
+ pte += (addr & mask) * 8;
+
+ if ((last_pte + 8 * count) != pte) {
+
+ if (count) {
+ amdgpu_vm_frag_ptes(adev, ib, last_pte,
+ last_pte + 8 * count,
+ last_dst, flags,
+ gtt_flags);
+ }
+
+ count = nptes;
+ last_pte = pte;
+ last_dst = dst;
+ } else {
+ count += nptes;
+ }
+
+ addr += nptes;
+ dst += nptes * AMDGPU_GPU_PAGE_SIZE;
+ }
+
+ if (count) {
+ amdgpu_vm_frag_ptes(adev, ib, last_pte,
+ last_pte + 8 * count,
+ last_dst, flags, gtt_flags);
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_vm_fence_pts - fence page tables after an update
+ *
+ * @vm: requested vm
+ * @start: start of GPU address range
+ * @end: end of GPU address range
+ * @fence: fence to use
+ *
+ * Fence the page tables in the range @start - @end (cayman+).
+ *
+ * Global and local mutex must be locked!
+ */
+static void amdgpu_vm_fence_pts(struct amdgpu_vm *vm,
+ uint64_t start, uint64_t end,
+ struct amdgpu_fence *fence)
+{
+ unsigned i;
+
+ start >>= amdgpu_vm_block_size;
+ end >>= amdgpu_vm_block_size;
+
+ for (i = start; i <= end; ++i)
+ amdgpu_bo_fence(vm->page_tables[i].bo, fence, true);
+}
+
+/**
+ * amdgpu_vm_bo_update_mapping - update a mapping in the vm page table
+ *
+ * @adev: amdgpu_device pointer
+ * @vm: requested vm
+ * @mapping: mapped range and flags to use for the update
+ * @addr: addr to set the area to
+ * @gtt_flags: flags as they are used for GTT
+ * @fence: optional resulting fence
+ *
+ * Fill in the page table entries for @mapping.
+ * Returns 0 for success, -EINVAL for failure.
+ *
+ * Object have to be reserved and mutex must be locked!
+ */
+static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm,
+ struct amdgpu_bo_va_mapping *mapping,
+ uint64_t addr, uint32_t gtt_flags,
+ struct amdgpu_fence **fence)
+{
+ struct amdgpu_ring *ring = adev->vm_manager.vm_pte_funcs_ring;
+ unsigned nptes, ncmds, ndw;
+ uint32_t flags = gtt_flags;
+ struct amdgpu_ib ib;
+ int r;
+
+ /* normally,bo_va->flags only contians READABLE and WIRTEABLE bit go here
+ * but in case of something, we filter the flags in first place
+ */
+ if (!(mapping->flags & AMDGPU_PTE_READABLE))
+ flags &= ~AMDGPU_PTE_READABLE;
+ if (!(mapping->flags & AMDGPU_PTE_WRITEABLE))
+ flags &= ~AMDGPU_PTE_WRITEABLE;
+
+ trace_amdgpu_vm_bo_update(mapping);
+
+ nptes = mapping->it.last - mapping->it.start + 1;
+
+ /*
+ * reserve space for one command every (1 << BLOCK_SIZE)
+ * entries or 2k dwords (whatever is smaller)
+ */
+ ncmds = (nptes >> min(amdgpu_vm_block_size, 11)) + 1;
+
+ /* padding, etc. */
+ ndw = 64;
+
+ if ((flags & AMDGPU_PTE_SYSTEM) && (flags == gtt_flags)) {
+ /* only copy commands needed */
+ ndw += ncmds * 7;
+
+ } else if (flags & AMDGPU_PTE_SYSTEM) {
+ /* header for write data commands */
+ ndw += ncmds * 4;
+
+ /* body of write data command */
+ ndw += nptes * 2;
+
+ } else {
+ /* set page commands needed */
+ ndw += ncmds * 10;
+
+ /* two extra commands for begin/end of fragment */
+ ndw += 2 * 10;
+ }
+
+ /* update too big for an IB */
+ if (ndw > 0xfffff)
+ return -ENOMEM;
+
+ r = amdgpu_ib_get(ring, NULL, ndw * 4, &ib);
+ if (r)
+ return r;
+ ib.length_dw = 0;
+
+ if (!(flags & AMDGPU_PTE_VALID)) {
+ unsigned i;
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ struct amdgpu_fence *f = vm->ids[i].last_id_use;
+ amdgpu_sync_fence(&ib.sync, f);
+ }
+ }
+
+ r = amdgpu_vm_update_ptes(adev, vm, &ib, mapping->it.start,
+ mapping->it.last + 1, addr + mapping->offset,
+ flags, gtt_flags);
+
+ if (r) {
+ amdgpu_ib_free(adev, &ib);
+ return r;
+ }
+
+ amdgpu_vm_pad_ib(adev, &ib);
+ WARN_ON(ib.length_dw > ndw);
+
+ r = amdgpu_ib_schedule(adev, 1, &ib, AMDGPU_FENCE_OWNER_VM);
+ if (r) {
+ amdgpu_ib_free(adev, &ib);
+ return r;
+ }
+ amdgpu_vm_fence_pts(vm, mapping->it.start,
+ mapping->it.last + 1, ib.fence);
+ if (fence) {
+ amdgpu_fence_unref(fence);
+ *fence = amdgpu_fence_ref(ib.fence);
+ }
+ amdgpu_ib_free(adev, &ib);
+
+ return 0;
+}
+
+/**
+ * amdgpu_vm_bo_update - update all BO mappings in the vm page table
+ *
+ * @adev: amdgpu_device pointer
+ * @bo_va: requested BO and VM object
+ * @mem: ttm mem
+ *
+ * Fill in the page table entries for @bo_va.
+ * Returns 0 for success, -EINVAL for failure.
+ *
+ * Object have to be reserved and mutex must be locked!
+ */
+int amdgpu_vm_bo_update(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va,
+ struct ttm_mem_reg *mem)
+{
+ struct amdgpu_vm *vm = bo_va->vm;
+ struct amdgpu_bo_va_mapping *mapping;
+ uint32_t flags;
+ uint64_t addr;
+ int r;
+
+ if (mem) {
+ addr = mem->start << PAGE_SHIFT;
+ if (mem->mem_type != TTM_PL_TT)
+ addr += adev->vm_manager.vram_base_offset;
+ } else {
+ addr = 0;
+ }
+
+ if (addr == bo_va->addr)
+ return 0;
+
+ flags = amdgpu_ttm_tt_pte_flags(adev, bo_va->bo->tbo.ttm, mem);
+
+ list_for_each_entry(mapping, &bo_va->mappings, list) {
+ r = amdgpu_vm_bo_update_mapping(adev, vm, mapping, addr,
+ flags, &bo_va->last_pt_update);
+ if (r)
+ return r;
+ }
+
+ bo_va->addr = addr;
+ spin_lock(&vm->status_lock);
+ list_del_init(&bo_va->vm_status);
+ spin_unlock(&vm->status_lock);
+
+ return 0;
+}
+
+/**
+ * amdgpu_vm_clear_freed - clear freed BOs in the PT
+ *
+ * @adev: amdgpu_device pointer
+ * @vm: requested vm
+ *
+ * Make sure all freed BOs are cleared in the PT.
+ * Returns 0 for success.
+ *
+ * PTs have to be reserved and mutex must be locked!
+ */
+int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm)
+{
+ struct amdgpu_bo_va_mapping *mapping;
+ int r;
+
+ while (!list_empty(&vm->freed)) {
+ mapping = list_first_entry(&vm->freed,
+ struct amdgpu_bo_va_mapping, list);
+ list_del(&mapping->list);
+
+ r = amdgpu_vm_bo_update_mapping(adev, vm, mapping, 0, 0, NULL);
+ kfree(mapping);
+ if (r)
+ return r;
+
+ }
+ return 0;
+
+}
+
+/**
+ * amdgpu_vm_clear_invalids - clear invalidated BOs in the PT
+ *
+ * @adev: amdgpu_device pointer
+ * @vm: requested vm
+ *
+ * Make sure all invalidated BOs are cleared in the PT.
+ * Returns 0 for success.
+ *
+ * PTs have to be reserved and mutex must be locked!
+ */
+int amdgpu_vm_clear_invalids(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm, struct amdgpu_sync *sync)
+{
+ struct amdgpu_bo_va *bo_va = NULL;
+ int r;
+
+ spin_lock(&vm->status_lock);
+ while (!list_empty(&vm->invalidated)) {
+ bo_va = list_first_entry(&vm->invalidated,
+ struct amdgpu_bo_va, vm_status);
+ spin_unlock(&vm->status_lock);
+
+ r = amdgpu_vm_bo_update(adev, bo_va, NULL);
+ if (r)
+ return r;
+
+ spin_lock(&vm->status_lock);
+ }
+ spin_unlock(&vm->status_lock);
+
+ if (bo_va)
+ amdgpu_sync_fence(sync, bo_va->last_pt_update);
+ return 0;
+}
+
+/**
+ * amdgpu_vm_bo_add - add a bo to a specific vm
+ *
+ * @adev: amdgpu_device pointer
+ * @vm: requested vm
+ * @bo: amdgpu buffer object
+ *
+ * Add @bo into the requested vm (cayman+).
+ * Add @bo to the list of bos associated with the vm
+ * Returns newly added bo_va or NULL for failure
+ *
+ * Object has to be reserved!
+ */
+struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm,
+ struct amdgpu_bo *bo)
+{
+ struct amdgpu_bo_va *bo_va;
+
+ bo_va = kzalloc(sizeof(struct amdgpu_bo_va), GFP_KERNEL);
+ if (bo_va == NULL) {
+ return NULL;
+ }
+ bo_va->vm = vm;
+ bo_va->bo = bo;
+ bo_va->addr = 0;
+ bo_va->ref_count = 1;
+ INIT_LIST_HEAD(&bo_va->bo_list);
+ INIT_LIST_HEAD(&bo_va->mappings);
+ INIT_LIST_HEAD(&bo_va->vm_status);
+
+ mutex_lock(&vm->mutex);
+ list_add_tail(&bo_va->bo_list, &bo->va);
+ mutex_unlock(&vm->mutex);
+
+ return bo_va;
+}
+
+/**
+ * amdgpu_vm_bo_map - map bo inside a vm
+ *
+ * @adev: amdgpu_device pointer
+ * @bo_va: bo_va to store the address
+ * @saddr: where to map the BO
+ * @offset: requested offset in the BO
+ * @flags: attributes of pages (read/write/valid/etc.)
+ *
+ * Add a mapping of the BO at the specefied addr into the VM.
+ * Returns 0 for success, error for failure.
+ *
+ * Object has to be reserved and gets unreserved by this function!
+ */
+int amdgpu_vm_bo_map(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va,
+ uint64_t saddr, uint64_t offset,
+ uint64_t size, uint32_t flags)
+{
+ struct amdgpu_bo_va_mapping *mapping;
+ struct amdgpu_vm *vm = bo_va->vm;
+ struct interval_tree_node *it;
+ unsigned last_pfn, pt_idx;
+ uint64_t eaddr;
+ int r;
+
+ /* validate the parameters */
+ if (saddr & AMDGPU_GPU_PAGE_MASK || offset & AMDGPU_GPU_PAGE_MASK ||
+ size == 0 || size & AMDGPU_GPU_PAGE_MASK) {
+ amdgpu_bo_unreserve(bo_va->bo);
+ return -EINVAL;
+ }
+
+ /* make sure object fit at this offset */
+ eaddr = saddr + size;
+ if ((saddr >= eaddr) || (offset + size > amdgpu_bo_size(bo_va->bo))) {
+ amdgpu_bo_unreserve(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",
+ last_pfn, adev->vm_manager.max_pfn);
+ amdgpu_bo_unreserve(bo_va->bo);
+ return -EINVAL;
+ }
+
+ mutex_lock(&vm->mutex);
+
+ saddr /= AMDGPU_GPU_PAGE_SIZE;
+ eaddr /= AMDGPU_GPU_PAGE_SIZE;
+
+ it = interval_tree_iter_first(&vm->va, saddr, eaddr - 1);
+ if (it) {
+ struct amdgpu_bo_va_mapping *tmp;
+ tmp = container_of(it, struct amdgpu_bo_va_mapping, it);
+ /* bo and tmp overlap, invalid addr */
+ dev_err(adev->dev, "bo %p va 0x%010Lx-0x%010Lx conflict with "
+ "0x%010lx-0x%010lx\n", bo_va->bo, saddr, eaddr,
+ tmp->it.start, tmp->it.last + 1);
+ amdgpu_bo_unreserve(bo_va->bo);
+ r = -EINVAL;
+ goto error_unlock;
+ }
+
+ mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
+ if (!mapping) {
+ amdgpu_bo_unreserve(bo_va->bo);
+ r = -ENOMEM;
+ goto error_unlock;
+ }
+
+ INIT_LIST_HEAD(&mapping->list);
+ mapping->it.start = saddr;
+ mapping->it.last = eaddr - 1;
+ mapping->offset = offset;
+ mapping->flags = flags;
+
+ list_add(&mapping->list, &bo_va->mappings);
+ interval_tree_insert(&mapping->it, &vm->va);
+
+ bo_va->addr = 0;
+
+ /* Make sure the page tables are allocated */
+ saddr >>= amdgpu_vm_block_size;
+ eaddr >>= amdgpu_vm_block_size;
+
+ BUG_ON(eaddr >= amdgpu_vm_num_pdes(adev));
+
+ if (eaddr > vm->max_pde_used)
+ vm->max_pde_used = eaddr;
+
+ amdgpu_bo_unreserve(bo_va->bo);
+
+ /* walk over the address space and allocate the page tables */
+ for (pt_idx = saddr; pt_idx <= eaddr; ++pt_idx) {
+ struct amdgpu_bo *pt;
+
+ if (vm->page_tables[pt_idx].bo)
+ continue;
+
+ /* drop mutex to allocate and clear page table */
+ mutex_unlock(&vm->mutex);
+
+ r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8,
+ AMDGPU_GPU_PAGE_SIZE, true,
+ AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &pt);
+ if (r)
+ goto error_free;
+
+ r = amdgpu_vm_clear_bo(adev, pt);
+ if (r) {
+ amdgpu_bo_unref(&pt);
+ goto error_free;
+ }
+
+ /* aquire mutex again */
+ mutex_lock(&vm->mutex);
+ if (vm->page_tables[pt_idx].bo) {
+ /* someone else allocated the pt in the meantime */
+ mutex_unlock(&vm->mutex);
+ amdgpu_bo_unref(&pt);
+ mutex_lock(&vm->mutex);
+ continue;
+ }
+
+ vm->page_tables[pt_idx].addr = 0;
+ vm->page_tables[pt_idx].bo = pt;
+ }
+
+ mutex_unlock(&vm->mutex);
+ return 0;
+
+error_free:
+ mutex_lock(&vm->mutex);
+ list_del(&mapping->list);
+ interval_tree_remove(&mapping->it, &vm->va);
+ kfree(mapping);
+
+error_unlock:
+ mutex_unlock(&vm->mutex);
+ return r;
+}
+
+/**
+ * amdgpu_vm_bo_unmap - remove bo mapping from vm
+ *
+ * @adev: amdgpu_device pointer
+ * @bo_va: bo_va to remove the address from
+ * @saddr: where to the BO is mapped
+ *
+ * Remove a mapping of the BO at the specefied addr from the VM.
+ * Returns 0 for success, error for failure.
+ *
+ * Object has to be reserved and gets unreserved by this function!
+ */
+int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va,
+ uint64_t saddr)
+{
+ struct amdgpu_bo_va_mapping *mapping;
+ struct amdgpu_vm *vm = bo_va->vm;
+
+ saddr /= AMDGPU_GPU_PAGE_SIZE;
+
+ list_for_each_entry(mapping, &bo_va->mappings, list) {
+ if (mapping->it.start == saddr)
+ break;
+ }
+
+ if (&mapping->list == &bo_va->mappings) {
+ amdgpu_bo_unreserve(bo_va->bo);
+ return -ENOENT;
+ }
+
+ mutex_lock(&vm->mutex);
+ list_del(&mapping->list);
+ interval_tree_remove(&mapping->it, &vm->va);
+
+ if (bo_va->addr) {
+ /* clear the old address */
+ list_add(&mapping->list, &vm->freed);
+ } else {
+ kfree(mapping);
+ }
+ mutex_unlock(&vm->mutex);
+ amdgpu_bo_unreserve(bo_va->bo);
+
+ return 0;
+}
+
+/**
+ * amdgpu_vm_bo_rmv - remove a bo to a specific vm
+ *
+ * @adev: amdgpu_device pointer
+ * @bo_va: requested bo_va
+ *
+ * Remove @bo_va->bo from the requested vm (cayman+).
+ *
+ * Object have to be reserved!
+ */
+void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va)
+{
+ struct amdgpu_bo_va_mapping *mapping, *next;
+ struct amdgpu_vm *vm = bo_va->vm;
+
+ list_del(&bo_va->bo_list);
+
+ mutex_lock(&vm->mutex);
+
+ spin_lock(&vm->status_lock);
+ list_del(&bo_va->vm_status);
+ spin_unlock(&vm->status_lock);
+
+ list_for_each_entry_safe(mapping, next, &bo_va->mappings, list) {
+ list_del(&mapping->list);
+ interval_tree_remove(&mapping->it, &vm->va);
+ if (bo_va->addr)
+ list_add(&mapping->list, &vm->freed);
+ else
+ kfree(mapping);
+ }
+ amdgpu_fence_unref(&bo_va->last_pt_update);
+ kfree(bo_va);
+
+ mutex_unlock(&vm->mutex);
+}
+
+/**
+ * amdgpu_vm_bo_invalidate - mark the bo as invalid
+ *
+ * @adev: amdgpu_device pointer
+ * @vm: requested vm
+ * @bo: amdgpu buffer object
+ *
+ * Mark @bo as invalid (cayman+).
+ */
+void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev,
+ struct amdgpu_bo *bo)
+{
+ struct amdgpu_bo_va *bo_va;
+
+ list_for_each_entry(bo_va, &bo->va, bo_list) {
+ if (bo_va->addr) {
+ spin_lock(&bo_va->vm->status_lock);
+ list_del(&bo_va->vm_status);
+ list_add(&bo_va->vm_status, &bo_va->vm->invalidated);
+ spin_unlock(&bo_va->vm->status_lock);
+ }
+ }
+}
+
+/**
+ * amdgpu_vm_init - initialize a vm instance
+ *
+ * @adev: amdgpu_device pointer
+ * @vm: requested vm
+ *
+ * Init @vm fields (cayman+).
+ */
+int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
+{
+ const unsigned align = min(AMDGPU_VM_PTB_ALIGN_SIZE,
+ AMDGPU_VM_PTE_COUNT * 8);
+ unsigned pd_size, pd_entries, pts_size;
+ int i, r;
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ vm->ids[i].id = 0;
+ vm->ids[i].flushed_updates = NULL;
+ vm->ids[i].last_id_use = NULL;
+ }
+ mutex_init(&vm->mutex);
+ vm->va = RB_ROOT;
+ spin_lock_init(&vm->status_lock);
+ INIT_LIST_HEAD(&vm->invalidated);
+ INIT_LIST_HEAD(&vm->freed);
+
+ pd_size = amdgpu_vm_directory_size(adev);
+ pd_entries = amdgpu_vm_num_pdes(adev);
+
+ /* allocate page table array */
+ pts_size = pd_entries * sizeof(struct amdgpu_vm_pt);
+ vm->page_tables = kzalloc(pts_size, GFP_KERNEL);
+ if (vm->page_tables == NULL) {
+ DRM_ERROR("Cannot allocate memory for page table array\n");
+ return -ENOMEM;
+ }
+
+ r = amdgpu_bo_create(adev, pd_size, align, true,
+ AMDGPU_GEM_DOMAIN_VRAM, 0,
+ NULL, &vm->page_directory);
+ if (r)
+ return r;
+
+ r = amdgpu_vm_clear_bo(adev, vm->page_directory);
+ if (r) {
+ amdgpu_bo_unref(&vm->page_directory);
+ vm->page_directory = NULL;
+ return r;
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_vm_fini - tear down a vm instance
+ *
+ * @adev: amdgpu_device pointer
+ * @vm: requested vm
+ *
+ * Tear down @vm (cayman+).
+ * Unbind the VM and remove all bos from the vm bo list
+ */
+void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
+{
+ struct amdgpu_bo_va_mapping *mapping, *tmp;
+ int i;
+
+ if (!RB_EMPTY_ROOT(&vm->va)) {
+ dev_err(adev->dev, "still active bo inside vm\n");
+ }
+ rbtree_postorder_for_each_entry_safe(mapping, tmp, &vm->va, it.rb) {
+ list_del(&mapping->list);
+ interval_tree_remove(&mapping->it, &vm->va);
+ kfree(mapping);
+ }
+ list_for_each_entry_safe(mapping, tmp, &vm->freed, list) {
+ list_del(&mapping->list);
+ kfree(mapping);
+ }
+
+ for (i = 0; i < amdgpu_vm_num_pdes(adev); i++)
+ amdgpu_bo_unref(&vm->page_tables[i].bo);
+ kfree(vm->page_tables);
+
+ amdgpu_bo_unref(&vm->page_directory);
+
+ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ amdgpu_fence_unref(&vm->ids[i].flushed_updates);
+ amdgpu_fence_unref(&vm->ids[i].last_id_use);
+ }
+
+ mutex_destroy(&vm->mutex);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/atom-bits.h b/drivers/gpu/drm/amd/amdgpu/atom-bits.h
new file mode 100644
index 000000000000..e8fae5c77514
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atom-bits.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Stanislaw Skowronek
+ */
+
+#ifndef ATOM_BITS_H
+#define ATOM_BITS_H
+
+static inline uint8_t get_u8(void *bios, int ptr)
+{
+ return ((unsigned char *)bios)[ptr];
+}
+#define U8(ptr) get_u8(ctx->ctx->bios, (ptr))
+#define CU8(ptr) get_u8(ctx->bios, (ptr))
+static inline uint16_t get_u16(void *bios, int ptr)
+{
+ return get_u8(bios ,ptr)|(((uint16_t)get_u8(bios, ptr+1))<<8);
+}
+#define U16(ptr) get_u16(ctx->ctx->bios, (ptr))
+#define CU16(ptr) get_u16(ctx->bios, (ptr))
+static inline uint32_t get_u32(void *bios, int ptr)
+{
+ return get_u16(bios, ptr)|(((uint32_t)get_u16(bios, ptr+2))<<16);
+}
+#define U32(ptr) get_u32(ctx->ctx->bios, (ptr))
+#define CU32(ptr) get_u32(ctx->bios, (ptr))
+#define CSTR(ptr) (((char *)(ctx->bios))+(ptr))
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/atom-names.h b/drivers/gpu/drm/amd/amdgpu/atom-names.h
new file mode 100644
index 000000000000..6f907a5ffa5f
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atom-names.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Stanislaw Skowronek
+ */
+
+#ifndef ATOM_NAMES_H
+#define ATOM_NAMES_H
+
+#include "atom.h"
+
+#ifdef ATOM_DEBUG
+
+#define ATOM_OP_NAMES_CNT 123
+static char *atom_op_names[ATOM_OP_NAMES_CNT] = {
+"RESERVED", "MOVE_REG", "MOVE_PS", "MOVE_WS", "MOVE_FB", "MOVE_PLL",
+"MOVE_MC", "AND_REG", "AND_PS", "AND_WS", "AND_FB", "AND_PLL", "AND_MC",
+"OR_REG", "OR_PS", "OR_WS", "OR_FB", "OR_PLL", "OR_MC", "SHIFT_LEFT_REG",
+"SHIFT_LEFT_PS", "SHIFT_LEFT_WS", "SHIFT_LEFT_FB", "SHIFT_LEFT_PLL",
+"SHIFT_LEFT_MC", "SHIFT_RIGHT_REG", "SHIFT_RIGHT_PS", "SHIFT_RIGHT_WS",
+"SHIFT_RIGHT_FB", "SHIFT_RIGHT_PLL", "SHIFT_RIGHT_MC", "MUL_REG",
+"MUL_PS", "MUL_WS", "MUL_FB", "MUL_PLL", "MUL_MC", "DIV_REG", "DIV_PS",
+"DIV_WS", "DIV_FB", "DIV_PLL", "DIV_MC", "ADD_REG", "ADD_PS", "ADD_WS",
+"ADD_FB", "ADD_PLL", "ADD_MC", "SUB_REG", "SUB_PS", "SUB_WS", "SUB_FB",
+"SUB_PLL", "SUB_MC", "SET_ATI_PORT", "SET_PCI_PORT", "SET_SYS_IO_PORT",
+"SET_REG_BLOCK", "SET_FB_BASE", "COMPARE_REG", "COMPARE_PS",
+"COMPARE_WS", "COMPARE_FB", "COMPARE_PLL", "COMPARE_MC", "SWITCH",
+"JUMP", "JUMP_EQUAL", "JUMP_BELOW", "JUMP_ABOVE", "JUMP_BELOW_OR_EQUAL",
+"JUMP_ABOVE_OR_EQUAL", "JUMP_NOT_EQUAL", "TEST_REG", "TEST_PS", "TEST_WS",
+"TEST_FB", "TEST_PLL", "TEST_MC", "DELAY_MILLISEC", "DELAY_MICROSEC",
+"CALL_TABLE", "REPEAT", "CLEAR_REG", "CLEAR_PS", "CLEAR_WS", "CLEAR_FB",
+"CLEAR_PLL", "CLEAR_MC", "NOP", "EOT", "MASK_REG", "MASK_PS", "MASK_WS",
+"MASK_FB", "MASK_PLL", "MASK_MC", "POST_CARD", "BEEP", "SAVE_REG",
+"RESTORE_REG", "SET_DATA_BLOCK", "XOR_REG", "XOR_PS", "XOR_WS", "XOR_FB",
+"XOR_PLL", "XOR_MC", "SHL_REG", "SHL_PS", "SHL_WS", "SHL_FB", "SHL_PLL",
+"SHL_MC", "SHR_REG", "SHR_PS", "SHR_WS", "SHR_FB", "SHR_PLL", "SHR_MC",
+"DEBUG", "CTB_DS",
+};
+
+#define ATOM_TABLE_NAMES_CNT 74
+static char *atom_table_names[ATOM_TABLE_NAMES_CNT] = {
+"ASIC_Init", "GetDisplaySurfaceSize", "ASIC_RegistersInit",
+"VRAM_BlockVenderDetection", "SetClocksRatio", "MemoryControllerInit",
+"GPIO_PinInit", "MemoryParamAdjust", "DVOEncoderControl",
+"GPIOPinControl", "SetEngineClock", "SetMemoryClock", "SetPixelClock",
+"DynamicClockGating", "ResetMemoryDLL", "ResetMemoryDevice",
+"MemoryPLLInit", "EnableMemorySelfRefresh", "AdjustMemoryController",
+"EnableASIC_StaticPwrMgt", "ASIC_StaticPwrMgtStatusChange",
+"DAC_LoadDetection", "TMDS2EncoderControl", "LCD1OutputControl",
+"DAC1EncoderControl", "DAC2EncoderControl", "DVOOutputControl",
+"CV1OutputControl", "SetCRTC_DPM_State", "TVEncoderControl",
+"TMDS1EncoderControl", "LVDSEncoderControl", "TV1OutputControl",
+"EnableScaler", "BlankCRTC", "EnableCRTC", "GetPixelClock",
+"EnableVGA_Render", "EnableVGA_Access", "SetCRTC_Timing",
+"SetCRTC_OverScan", "SetCRTC_Replication", "SelectCRTC_Source",
+"EnableGraphSurfaces", "UpdateCRTC_DoubleBufferRegisters",
+"LUT_AutoFill", "EnableHW_IconCursor", "GetMemoryClock",
+"GetEngineClock", "SetCRTC_UsingDTDTiming", "TVBootUpStdPinDetection",
+"DFP2OutputControl", "VRAM_BlockDetectionByStrap", "MemoryCleanUp",
+"ReadEDIDFromHWAssistedI2C", "WriteOneByteToHWAssistedI2C",
+"ReadHWAssistedI2CStatus", "SpeedFanControl", "PowerConnectorDetection",
+"MC_Synchronization", "ComputeMemoryEnginePLL", "MemoryRefreshConversion",
+"VRAM_GetCurrentInfoBlock", "DynamicMemorySettings", "MemoryTraining",
+"EnableLVDS_SS", "DFP1OutputControl", "SetVoltage", "CRT1OutputControl",
+"CRT2OutputControl", "SetupHWAssistedI2CStatus", "ClockSource",
+"MemoryDeviceInit", "EnableYUV",
+};
+
+#define ATOM_IO_NAMES_CNT 5
+static char *atom_io_names[ATOM_IO_NAMES_CNT] = {
+"MM", "PLL", "MC", "PCIE", "PCIE PORT",
+};
+
+#else
+
+#define ATOM_OP_NAMES_CNT 0
+#define ATOM_TABLE_NAMES_CNT 0
+#define ATOM_IO_NAMES_CNT 0
+
+#endif
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/atom-types.h b/drivers/gpu/drm/amd/amdgpu/atom-types.h
new file mode 100644
index 000000000000..1125b866cdb0
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atom-types.h
@@ -0,0 +1,42 @@
+/*
+ * 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 shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Dave Airlie
+ */
+
+#ifndef ATOM_TYPES_H
+#define ATOM_TYPES_H
+
+/* sync atom types to kernel types */
+
+typedef uint16_t USHORT;
+typedef uint32_t ULONG;
+typedef uint8_t UCHAR;
+
+
+#ifndef ATOM_BIG_ENDIAN
+#if defined(__BIG_ENDIAN)
+#define ATOM_BIG_ENDIAN 1
+#else
+#define ATOM_BIG_ENDIAN 0
+#endif
+#endif
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c
new file mode 100644
index 000000000000..a0346a90d805
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atom.c
@@ -0,0 +1,1408 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Stanislaw Skowronek
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#define ATOM_DEBUG
+
+#include "atom.h"
+#include "atom-names.h"
+#include "atom-bits.h"
+#include "amdgpu.h"
+
+#define ATOM_COND_ABOVE 0
+#define ATOM_COND_ABOVEOREQUAL 1
+#define ATOM_COND_ALWAYS 2
+#define ATOM_COND_BELOW 3
+#define ATOM_COND_BELOWOREQUAL 4
+#define ATOM_COND_EQUAL 5
+#define ATOM_COND_NOTEQUAL 6
+
+#define ATOM_PORT_ATI 0
+#define ATOM_PORT_PCI 1
+#define ATOM_PORT_SYSIO 2
+
+#define ATOM_UNIT_MICROSEC 0
+#define ATOM_UNIT_MILLISEC 1
+
+#define PLL_INDEX 2
+#define PLL_DATA 3
+
+typedef struct {
+ struct atom_context *ctx;
+ uint32_t *ps, *ws;
+ int ps_shift;
+ uint16_t start;
+ unsigned last_jump;
+ unsigned long last_jump_jiffies;
+ bool abort;
+} atom_exec_context;
+
+int amdgpu_atom_debug = 0;
+static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params);
+int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
+
+static uint32_t atom_arg_mask[8] =
+ { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
+0xFF000000 };
+static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
+
+static int atom_dst_to_src[8][4] = {
+ /* translate destination alignment field to the source alignment encoding */
+ {0, 0, 0, 0},
+ {1, 2, 3, 0},
+ {1, 2, 3, 0},
+ {1, 2, 3, 0},
+ {4, 5, 6, 7},
+ {4, 5, 6, 7},
+ {4, 5, 6, 7},
+ {4, 5, 6, 7},
+};
+static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
+
+static int debug_depth = 0;
+#ifdef ATOM_DEBUG
+static void debug_print_spaces(int n)
+{
+ while (n--)
+ printk(" ");
+}
+
+#define DEBUG(...) do if (amdgpu_atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0)
+#define SDEBUG(...) do if (amdgpu_atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0)
+#else
+#define DEBUG(...) do { } while (0)
+#define SDEBUG(...) do { } while (0)
+#endif
+
+static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
+ uint32_t index, uint32_t data)
+{
+ uint32_t temp = 0xCDCDCDCD;
+
+ while (1)
+ switch (CU8(base)) {
+ case ATOM_IIO_NOP:
+ base++;
+ break;
+ case ATOM_IIO_READ:
+ temp = ctx->card->ioreg_read(ctx->card, CU16(base + 1));
+ base += 3;
+ break;
+ case ATOM_IIO_WRITE:
+ ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp);
+ base += 3;
+ break;
+ case ATOM_IIO_CLEAR:
+ temp &=
+ ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
+ CU8(base + 2));
+ base += 3;
+ break;
+ case ATOM_IIO_SET:
+ temp |=
+ (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base +
+ 2);
+ base += 3;
+ break;
+ case ATOM_IIO_MOVE_INDEX:
+ temp &=
+ ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
+ CU8(base + 3));
+ temp |=
+ ((index >> CU8(base + 2)) &
+ (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
+ 3);
+ base += 4;
+ break;
+ case ATOM_IIO_MOVE_DATA:
+ temp &=
+ ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
+ CU8(base + 3));
+ temp |=
+ ((data >> CU8(base + 2)) &
+ (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
+ 3);
+ base += 4;
+ break;
+ case ATOM_IIO_MOVE_ATTR:
+ temp &=
+ ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
+ CU8(base + 3));
+ temp |=
+ ((ctx->
+ io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
+ CU8
+ (base
+ +
+ 1))))
+ << CU8(base + 3);
+ base += 4;
+ break;
+ case ATOM_IIO_END:
+ return temp;
+ default:
+ printk(KERN_INFO "Unknown IIO opcode.\n");
+ return 0;
+ }
+}
+
+static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
+ int *ptr, uint32_t *saved, int print)
+{
+ uint32_t idx, val = 0xCDCDCDCD, align, arg;
+ struct atom_context *gctx = ctx->ctx;
+ arg = attr & 7;
+ align = (attr >> 3) & 7;
+ switch (arg) {
+ case ATOM_ARG_REG:
+ idx = U16(*ptr);
+ (*ptr) += 2;
+ if (print)
+ DEBUG("REG[0x%04X]", idx);
+ idx += gctx->reg_block;
+ switch (gctx->io_mode) {
+ case ATOM_IO_MM:
+ val = gctx->card->reg_read(gctx->card, idx);
+ break;
+ case ATOM_IO_PCI:
+ printk(KERN_INFO
+ "PCI registers are not implemented.\n");
+ return 0;
+ case ATOM_IO_SYSIO:
+ printk(KERN_INFO
+ "SYSIO registers are not implemented.\n");
+ return 0;
+ default:
+ if (!(gctx->io_mode & 0x80)) {
+ printk(KERN_INFO "Bad IO mode.\n");
+ return 0;
+ }
+ if (!gctx->iio[gctx->io_mode & 0x7F]) {
+ printk(KERN_INFO
+ "Undefined indirect IO read method %d.\n",
+ gctx->io_mode & 0x7F);
+ return 0;
+ }
+ val =
+ atom_iio_execute(gctx,
+ gctx->iio[gctx->io_mode & 0x7F],
+ idx, 0);
+ }
+ break;
+ case ATOM_ARG_PS:
+ idx = U8(*ptr);
+ (*ptr)++;
+ /* get_unaligned_le32 avoids unaligned accesses from atombios
+ * tables, noticed on a DEC Alpha. */
+ val = get_unaligned_le32((u32 *)&ctx->ps[idx]);
+ if (print)
+ DEBUG("PS[0x%02X,0x%04X]", idx, val);
+ break;
+ case ATOM_ARG_WS:
+ idx = U8(*ptr);
+ (*ptr)++;
+ if (print)
+ DEBUG("WS[0x%02X]", idx);
+ switch (idx) {
+ case ATOM_WS_QUOTIENT:
+ val = gctx->divmul[0];
+ break;
+ case ATOM_WS_REMAINDER:
+ val = gctx->divmul[1];
+ break;
+ case ATOM_WS_DATAPTR:
+ val = gctx->data_block;
+ break;
+ case ATOM_WS_SHIFT:
+ val = gctx->shift;
+ break;
+ case ATOM_WS_OR_MASK:
+ val = 1 << gctx->shift;
+ break;
+ case ATOM_WS_AND_MASK:
+ val = ~(1 << gctx->shift);
+ break;
+ case ATOM_WS_FB_WINDOW:
+ val = gctx->fb_base;
+ break;
+ case ATOM_WS_ATTRIBUTES:
+ val = gctx->io_attr;
+ break;
+ case ATOM_WS_REGPTR:
+ val = gctx->reg_block;
+ break;
+ default:
+ val = ctx->ws[idx];
+ }
+ break;
+ case ATOM_ARG_ID:
+ idx = U16(*ptr);
+ (*ptr) += 2;
+ if (print) {
+ if (gctx->data_block)
+ DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
+ else
+ DEBUG("ID[0x%04X]", idx);
+ }
+ val = U32(idx + gctx->data_block);
+ break;
+ case ATOM_ARG_FB:
+ idx = U8(*ptr);
+ (*ptr)++;
+ if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
+ DRM_ERROR("ATOM: fb read beyond scratch region: %d vs. %d\n",
+ gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
+ val = 0;
+ } else
+ val = gctx->scratch[(gctx->fb_base / 4) + idx];
+ if (print)
+ DEBUG("FB[0x%02X]", idx);
+ break;
+ case ATOM_ARG_IMM:
+ switch (align) {
+ case ATOM_SRC_DWORD:
+ val = U32(*ptr);
+ (*ptr) += 4;
+ if (print)
+ DEBUG("IMM 0x%08X\n", val);
+ return val;
+ case ATOM_SRC_WORD0:
+ case ATOM_SRC_WORD8:
+ case ATOM_SRC_WORD16:
+ val = U16(*ptr);
+ (*ptr) += 2;
+ if (print)
+ DEBUG("IMM 0x%04X\n", val);
+ return val;
+ case ATOM_SRC_BYTE0:
+ case ATOM_SRC_BYTE8:
+ case ATOM_SRC_BYTE16:
+ case ATOM_SRC_BYTE24:
+ val = U8(*ptr);
+ (*ptr)++;
+ if (print)
+ DEBUG("IMM 0x%02X\n", val);
+ return val;
+ }
+ return 0;
+ case ATOM_ARG_PLL:
+ idx = U8(*ptr);
+ (*ptr)++;
+ if (print)
+ DEBUG("PLL[0x%02X]", idx);
+ val = gctx->card->pll_read(gctx->card, idx);
+ break;
+ case ATOM_ARG_MC:
+ idx = U8(*ptr);
+ (*ptr)++;
+ if (print)
+ DEBUG("MC[0x%02X]", idx);
+ val = gctx->card->mc_read(gctx->card, idx);
+ break;
+ }
+ if (saved)
+ *saved = val;
+ val &= atom_arg_mask[align];
+ val >>= atom_arg_shift[align];
+ if (print)
+ switch (align) {
+ case ATOM_SRC_DWORD:
+ DEBUG(".[31:0] -> 0x%08X\n", val);
+ break;
+ case ATOM_SRC_WORD0:
+ DEBUG(".[15:0] -> 0x%04X\n", val);
+ break;
+ case ATOM_SRC_WORD8:
+ DEBUG(".[23:8] -> 0x%04X\n", val);
+ break;
+ case ATOM_SRC_WORD16:
+ DEBUG(".[31:16] -> 0x%04X\n", val);
+ break;
+ case ATOM_SRC_BYTE0:
+ DEBUG(".[7:0] -> 0x%02X\n", val);
+ break;
+ case ATOM_SRC_BYTE8:
+ DEBUG(".[15:8] -> 0x%02X\n", val);
+ break;
+ case ATOM_SRC_BYTE16:
+ DEBUG(".[23:16] -> 0x%02X\n", val);
+ break;
+ case ATOM_SRC_BYTE24:
+ DEBUG(".[31:24] -> 0x%02X\n", val);
+ break;
+ }
+ return val;
+}
+
+static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
+{
+ uint32_t align = (attr >> 3) & 7, arg = attr & 7;
+ switch (arg) {
+ case ATOM_ARG_REG:
+ case ATOM_ARG_ID:
+ (*ptr) += 2;
+ break;
+ case ATOM_ARG_PLL:
+ case ATOM_ARG_MC:
+ case ATOM_ARG_PS:
+ case ATOM_ARG_WS:
+ case ATOM_ARG_FB:
+ (*ptr)++;
+ break;
+ case ATOM_ARG_IMM:
+ switch (align) {
+ case ATOM_SRC_DWORD:
+ (*ptr) += 4;
+ return;
+ case ATOM_SRC_WORD0:
+ case ATOM_SRC_WORD8:
+ case ATOM_SRC_WORD16:
+ (*ptr) += 2;
+ return;
+ case ATOM_SRC_BYTE0:
+ case ATOM_SRC_BYTE8:
+ case ATOM_SRC_BYTE16:
+ case ATOM_SRC_BYTE24:
+ (*ptr)++;
+ return;
+ }
+ return;
+ }
+}
+
+static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
+{
+ return atom_get_src_int(ctx, attr, ptr, NULL, 1);
+}
+
+static uint32_t atom_get_src_direct(atom_exec_context *ctx, uint8_t align, int *ptr)
+{
+ uint32_t val = 0xCDCDCDCD;
+
+ switch (align) {
+ case ATOM_SRC_DWORD:
+ val = U32(*ptr);
+ (*ptr) += 4;
+ break;
+ case ATOM_SRC_WORD0:
+ case ATOM_SRC_WORD8:
+ case ATOM_SRC_WORD16:
+ val = U16(*ptr);
+ (*ptr) += 2;
+ break;
+ case ATOM_SRC_BYTE0:
+ case ATOM_SRC_BYTE8:
+ case ATOM_SRC_BYTE16:
+ case ATOM_SRC_BYTE24:
+ val = U8(*ptr);
+ (*ptr)++;
+ break;
+ }
+ return val;
+}
+
+static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
+ int *ptr, uint32_t *saved, int print)
+{
+ return atom_get_src_int(ctx,
+ arg | atom_dst_to_src[(attr >> 3) &
+ 7][(attr >> 6) & 3] << 3,
+ ptr, saved, print);
+}
+
+static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
+{
+ atom_skip_src_int(ctx,
+ arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) &
+ 3] << 3, ptr);
+}
+
+static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
+ int *ptr, uint32_t val, uint32_t saved)
+{
+ uint32_t align =
+ atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val =
+ val, idx;
+ struct atom_context *gctx = ctx->ctx;
+ old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
+ val <<= atom_arg_shift[align];
+ val &= atom_arg_mask[align];
+ saved &= ~atom_arg_mask[align];
+ val |= saved;
+ switch (arg) {
+ case ATOM_ARG_REG:
+ idx = U16(*ptr);
+ (*ptr) += 2;
+ DEBUG("REG[0x%04X]", idx);
+ idx += gctx->reg_block;
+ switch (gctx->io_mode) {
+ case ATOM_IO_MM:
+ if (idx == 0)
+ gctx->card->reg_write(gctx->card, idx,
+ val << 2);
+ else
+ gctx->card->reg_write(gctx->card, idx, val);
+ break;
+ case ATOM_IO_PCI:
+ printk(KERN_INFO
+ "PCI registers are not implemented.\n");
+ return;
+ case ATOM_IO_SYSIO:
+ printk(KERN_INFO
+ "SYSIO registers are not implemented.\n");
+ return;
+ default:
+ if (!(gctx->io_mode & 0x80)) {
+ printk(KERN_INFO "Bad IO mode.\n");
+ return;
+ }
+ if (!gctx->iio[gctx->io_mode & 0xFF]) {
+ printk(KERN_INFO
+ "Undefined indirect IO write method %d.\n",
+ gctx->io_mode & 0x7F);
+ return;
+ }
+ atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
+ idx, val);
+ }
+ break;
+ case ATOM_ARG_PS:
+ idx = U8(*ptr);
+ (*ptr)++;
+ DEBUG("PS[0x%02X]", idx);
+ ctx->ps[idx] = cpu_to_le32(val);
+ break;
+ case ATOM_ARG_WS:
+ idx = U8(*ptr);
+ (*ptr)++;
+ DEBUG("WS[0x%02X]", idx);
+ switch (idx) {
+ case ATOM_WS_QUOTIENT:
+ gctx->divmul[0] = val;
+ break;
+ case ATOM_WS_REMAINDER:
+ gctx->divmul[1] = val;
+ break;
+ case ATOM_WS_DATAPTR:
+ gctx->data_block = val;
+ break;
+ case ATOM_WS_SHIFT:
+ gctx->shift = val;
+ break;
+ case ATOM_WS_OR_MASK:
+ case ATOM_WS_AND_MASK:
+ break;
+ case ATOM_WS_FB_WINDOW:
+ gctx->fb_base = val;
+ break;
+ case ATOM_WS_ATTRIBUTES:
+ gctx->io_attr = val;
+ break;
+ case ATOM_WS_REGPTR:
+ gctx->reg_block = val;
+ break;
+ default:
+ ctx->ws[idx] = val;
+ }
+ break;
+ case ATOM_ARG_FB:
+ idx = U8(*ptr);
+ (*ptr)++;
+ if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
+ DRM_ERROR("ATOM: fb write beyond scratch region: %d vs. %d\n",
+ gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
+ } else
+ gctx->scratch[(gctx->fb_base / 4) + idx] = val;
+ DEBUG("FB[0x%02X]", idx);
+ break;
+ case ATOM_ARG_PLL:
+ idx = U8(*ptr);
+ (*ptr)++;
+ DEBUG("PLL[0x%02X]", idx);
+ gctx->card->pll_write(gctx->card, idx, val);
+ break;
+ case ATOM_ARG_MC:
+ idx = U8(*ptr);
+ (*ptr)++;
+ DEBUG("MC[0x%02X]", idx);
+ gctx->card->mc_write(gctx->card, idx, val);
+ return;
+ }
+ switch (align) {
+ case ATOM_SRC_DWORD:
+ DEBUG(".[31:0] <- 0x%08X\n", old_val);
+ break;
+ case ATOM_SRC_WORD0:
+ DEBUG(".[15:0] <- 0x%04X\n", old_val);
+ break;
+ case ATOM_SRC_WORD8:
+ DEBUG(".[23:8] <- 0x%04X\n", old_val);
+ break;
+ case ATOM_SRC_WORD16:
+ DEBUG(".[31:16] <- 0x%04X\n", old_val);
+ break;
+ case ATOM_SRC_BYTE0:
+ DEBUG(".[7:0] <- 0x%02X\n", old_val);
+ break;
+ case ATOM_SRC_BYTE8:
+ DEBUG(".[15:8] <- 0x%02X\n", old_val);
+ break;
+ case ATOM_SRC_BYTE16:
+ DEBUG(".[23:16] <- 0x%02X\n", old_val);
+ break;
+ case ATOM_SRC_BYTE24:
+ DEBUG(".[31:24] <- 0x%02X\n", old_val);
+ break;
+ }
+}
+
+static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t dst, src, saved;
+ int dptr = *ptr;
+ SDEBUG(" dst: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ SDEBUG(" src: ");
+ src = atom_get_src(ctx, attr, ptr);
+ dst += src;
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t dst, src, saved;
+ int dptr = *ptr;
+ SDEBUG(" dst: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ SDEBUG(" src: ");
+ src = atom_get_src(ctx, attr, ptr);
+ dst &= src;
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
+{
+ printk("ATOM BIOS beeped!\n");
+}
+
+static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
+{
+ int idx = U8((*ptr)++);
+ int r = 0;
+
+ if (idx < ATOM_TABLE_NAMES_CNT)
+ SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]);
+ else
+ SDEBUG(" table: %d\n", idx);
+ if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
+ r = amdgpu_atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
+ if (r) {
+ ctx->abort = true;
+ }
+}
+
+static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t saved;
+ int dptr = *ptr;
+ attr &= 0x38;
+ attr |= atom_def_dst[attr >> 3] << 6;
+ atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
+}
+
+static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t dst, src;
+ SDEBUG(" src1: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
+ SDEBUG(" src2: ");
+ src = atom_get_src(ctx, attr, ptr);
+ ctx->ctx->cs_equal = (dst == src);
+ ctx->ctx->cs_above = (dst > src);
+ SDEBUG(" result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE",
+ ctx->ctx->cs_above ? "GT" : "LE");
+}
+
+static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
+{
+ unsigned count = U8((*ptr)++);
+ SDEBUG(" count: %d\n", count);
+ if (arg == ATOM_UNIT_MICROSEC)
+ udelay(count);
+ else if (!drm_can_sleep())
+ mdelay(count);
+ else
+ msleep(count);
+}
+
+static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t dst, src;
+ SDEBUG(" src1: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
+ SDEBUG(" src2: ");
+ src = atom_get_src(ctx, attr, ptr);
+ if (src != 0) {
+ ctx->ctx->divmul[0] = dst / src;
+ ctx->ctx->divmul[1] = dst % src;
+ } else {
+ ctx->ctx->divmul[0] = 0;
+ ctx->ctx->divmul[1] = 0;
+ }
+}
+
+static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
+{
+ /* functionally, a nop */
+}
+
+static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
+{
+ int execute = 0, target = U16(*ptr);
+ unsigned long cjiffies;
+
+ (*ptr) += 2;
+ switch (arg) {
+ case ATOM_COND_ABOVE:
+ execute = ctx->ctx->cs_above;
+ break;
+ case ATOM_COND_ABOVEOREQUAL:
+ execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
+ break;
+ case ATOM_COND_ALWAYS:
+ execute = 1;
+ break;
+ case ATOM_COND_BELOW:
+ execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
+ break;
+ case ATOM_COND_BELOWOREQUAL:
+ execute = !ctx->ctx->cs_above;
+ break;
+ case ATOM_COND_EQUAL:
+ execute = ctx->ctx->cs_equal;
+ break;
+ case ATOM_COND_NOTEQUAL:
+ execute = !ctx->ctx->cs_equal;
+ break;
+ }
+ if (arg != ATOM_COND_ALWAYS)
+ SDEBUG(" taken: %s\n", execute ? "yes" : "no");
+ SDEBUG(" target: 0x%04X\n", target);
+ if (execute) {
+ if (ctx->last_jump == (ctx->start + target)) {
+ cjiffies = jiffies;
+ if (time_after(cjiffies, ctx->last_jump_jiffies)) {
+ cjiffies -= ctx->last_jump_jiffies;
+ if ((jiffies_to_msecs(cjiffies) > 5000)) {
+ DRM_ERROR("atombios stuck in loop for more than 5secs aborting\n");
+ ctx->abort = true;
+ }
+ } else {
+ /* jiffies wrap around we will just wait a little longer */
+ ctx->last_jump_jiffies = jiffies;
+ }
+ } else {
+ ctx->last_jump = ctx->start + target;
+ ctx->last_jump_jiffies = jiffies;
+ }
+ *ptr = ctx->start + target;
+ }
+}
+
+static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t dst, mask, src, saved;
+ int dptr = *ptr;
+ SDEBUG(" dst: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ mask = atom_get_src_direct(ctx, ((attr >> 3) & 7), ptr);
+ SDEBUG(" mask: 0x%08x", mask);
+ SDEBUG(" src: ");
+ src = atom_get_src(ctx, attr, ptr);
+ dst &= mask;
+ dst |= src;
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t src, saved;
+ int dptr = *ptr;
+ if (((attr >> 3) & 7) != ATOM_SRC_DWORD)
+ atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
+ else {
+ atom_skip_dst(ctx, arg, attr, ptr);
+ saved = 0xCDCDCDCD;
+ }
+ SDEBUG(" src: ");
+ src = atom_get_src(ctx, attr, ptr);
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, src, saved);
+}
+
+static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t dst, src;
+ SDEBUG(" src1: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
+ SDEBUG(" src2: ");
+ src = atom_get_src(ctx, attr, ptr);
+ ctx->ctx->divmul[0] = dst * src;
+}
+
+static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
+{
+ /* nothing */
+}
+
+static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t dst, src, saved;
+ int dptr = *ptr;
+ SDEBUG(" dst: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ SDEBUG(" src: ");
+ src = atom_get_src(ctx, attr, ptr);
+ dst |= src;
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t val = U8((*ptr)++);
+ SDEBUG("POST card output: 0x%02X\n", val);
+}
+
+static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
+{
+ printk(KERN_INFO "unimplemented!\n");
+}
+
+static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
+{
+ printk(KERN_INFO "unimplemented!\n");
+}
+
+static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
+{
+ printk(KERN_INFO "unimplemented!\n");
+}
+
+static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
+{
+ int idx = U8(*ptr);
+ (*ptr)++;
+ SDEBUG(" block: %d\n", idx);
+ if (!idx)
+ ctx->ctx->data_block = 0;
+ else if (idx == 255)
+ ctx->ctx->data_block = ctx->start;
+ else
+ ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx);
+ SDEBUG(" base: 0x%04X\n", ctx->ctx->data_block);
+}
+
+static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ SDEBUG(" fb_base: ");
+ ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
+}
+
+static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
+{
+ int port;
+ switch (arg) {
+ case ATOM_PORT_ATI:
+ port = U16(*ptr);
+ if (port < ATOM_IO_NAMES_CNT)
+ SDEBUG(" port: %d (%s)\n", port, atom_io_names[port]);
+ else
+ SDEBUG(" port: %d\n", port);
+ if (!port)
+ ctx->ctx->io_mode = ATOM_IO_MM;
+ else
+ ctx->ctx->io_mode = ATOM_IO_IIO | port;
+ (*ptr) += 2;
+ break;
+ case ATOM_PORT_PCI:
+ ctx->ctx->io_mode = ATOM_IO_PCI;
+ (*ptr)++;
+ break;
+ case ATOM_PORT_SYSIO:
+ ctx->ctx->io_mode = ATOM_IO_SYSIO;
+ (*ptr)++;
+ break;
+ }
+}
+
+static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
+{
+ ctx->ctx->reg_block = U16(*ptr);
+ (*ptr) += 2;
+ SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block);
+}
+
+static void atom_op_shift_left(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++), shift;
+ uint32_t saved, dst;
+ int dptr = *ptr;
+ attr &= 0x38;
+ attr |= atom_def_dst[attr >> 3] << 6;
+ SDEBUG(" dst: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
+ SDEBUG(" shift: %d\n", shift);
+ dst <<= shift;
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_shift_right(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++), shift;
+ uint32_t saved, dst;
+ int dptr = *ptr;
+ attr &= 0x38;
+ attr |= atom_def_dst[attr >> 3] << 6;
+ SDEBUG(" dst: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
+ SDEBUG(" shift: %d\n", shift);
+ dst >>= shift;
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++), shift;
+ uint32_t saved, dst;
+ int dptr = *ptr;
+ uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
+ SDEBUG(" dst: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ /* op needs to full dst value */
+ dst = saved;
+ shift = atom_get_src(ctx, attr, ptr);
+ SDEBUG(" shift: %d\n", shift);
+ dst <<= shift;
+ dst &= atom_arg_mask[dst_align];
+ dst >>= atom_arg_shift[dst_align];
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++), shift;
+ uint32_t saved, dst;
+ int dptr = *ptr;
+ uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
+ SDEBUG(" dst: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ /* op needs to full dst value */
+ dst = saved;
+ shift = atom_get_src(ctx, attr, ptr);
+ SDEBUG(" shift: %d\n", shift);
+ dst >>= shift;
+ dst &= atom_arg_mask[dst_align];
+ dst >>= atom_arg_shift[dst_align];
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t dst, src, saved;
+ int dptr = *ptr;
+ SDEBUG(" dst: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ SDEBUG(" src: ");
+ src = atom_get_src(ctx, attr, ptr);
+ dst -= src;
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t src, val, target;
+ SDEBUG(" switch: ");
+ src = atom_get_src(ctx, attr, ptr);
+ while (U16(*ptr) != ATOM_CASE_END)
+ if (U8(*ptr) == ATOM_CASE_MAGIC) {
+ (*ptr)++;
+ SDEBUG(" case: ");
+ val =
+ atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
+ ptr);
+ target = U16(*ptr);
+ if (val == src) {
+ SDEBUG(" target: %04X\n", target);
+ *ptr = ctx->start + target;
+ return;
+ }
+ (*ptr) += 2;
+ } else {
+ printk(KERN_INFO "Bad case.\n");
+ return;
+ }
+ (*ptr) += 2;
+}
+
+static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t dst, src;
+ SDEBUG(" src1: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
+ SDEBUG(" src2: ");
+ src = atom_get_src(ctx, attr, ptr);
+ ctx->ctx->cs_equal = ((dst & src) == 0);
+ SDEBUG(" result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
+}
+
+static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
+{
+ uint8_t attr = U8((*ptr)++);
+ uint32_t dst, src, saved;
+ int dptr = *ptr;
+ SDEBUG(" dst: ");
+ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ SDEBUG(" src: ");
+ src = atom_get_src(ctx, attr, ptr);
+ dst ^= src;
+ SDEBUG(" dst: ");
+ atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
+{
+ printk(KERN_INFO "unimplemented!\n");
+}
+
+static struct {
+ void (*func) (atom_exec_context *, int *, int);
+ int arg;
+} opcode_table[ATOM_OP_CNT] = {
+ {
+ NULL, 0}, {
+ atom_op_move, ATOM_ARG_REG}, {
+ atom_op_move, ATOM_ARG_PS}, {
+ atom_op_move, ATOM_ARG_WS}, {
+ atom_op_move, ATOM_ARG_FB}, {
+ atom_op_move, ATOM_ARG_PLL}, {
+ atom_op_move, ATOM_ARG_MC}, {
+ atom_op_and, ATOM_ARG_REG}, {
+ atom_op_and, ATOM_ARG_PS}, {
+ atom_op_and, ATOM_ARG_WS}, {
+ atom_op_and, ATOM_ARG_FB}, {
+ atom_op_and, ATOM_ARG_PLL}, {
+ atom_op_and, ATOM_ARG_MC}, {
+ atom_op_or, ATOM_ARG_REG}, {
+ atom_op_or, ATOM_ARG_PS}, {
+ atom_op_or, ATOM_ARG_WS}, {
+ atom_op_or, ATOM_ARG_FB}, {
+ atom_op_or, ATOM_ARG_PLL}, {
+ atom_op_or, ATOM_ARG_MC}, {
+ atom_op_shift_left, ATOM_ARG_REG}, {
+ atom_op_shift_left, ATOM_ARG_PS}, {
+ atom_op_shift_left, ATOM_ARG_WS}, {
+ atom_op_shift_left, ATOM_ARG_FB}, {
+ atom_op_shift_left, ATOM_ARG_PLL}, {
+ atom_op_shift_left, ATOM_ARG_MC}, {
+ atom_op_shift_right, ATOM_ARG_REG}, {
+ atom_op_shift_right, ATOM_ARG_PS}, {
+ atom_op_shift_right, ATOM_ARG_WS}, {
+ atom_op_shift_right, ATOM_ARG_FB}, {
+ atom_op_shift_right, ATOM_ARG_PLL}, {
+ atom_op_shift_right, ATOM_ARG_MC}, {
+ atom_op_mul, ATOM_ARG_REG}, {
+ atom_op_mul, ATOM_ARG_PS}, {
+ atom_op_mul, ATOM_ARG_WS}, {
+ atom_op_mul, ATOM_ARG_FB}, {
+ atom_op_mul, ATOM_ARG_PLL}, {
+ atom_op_mul, ATOM_ARG_MC}, {
+ atom_op_div, ATOM_ARG_REG}, {
+ atom_op_div, ATOM_ARG_PS}, {
+ atom_op_div, ATOM_ARG_WS}, {
+ atom_op_div, ATOM_ARG_FB}, {
+ atom_op_div, ATOM_ARG_PLL}, {
+ atom_op_div, ATOM_ARG_MC}, {
+ atom_op_add, ATOM_ARG_REG}, {
+ atom_op_add, ATOM_ARG_PS}, {
+ atom_op_add, ATOM_ARG_WS}, {
+ atom_op_add, ATOM_ARG_FB}, {
+ atom_op_add, ATOM_ARG_PLL}, {
+ atom_op_add, ATOM_ARG_MC}, {
+ atom_op_sub, ATOM_ARG_REG}, {
+ atom_op_sub, ATOM_ARG_PS}, {
+ atom_op_sub, ATOM_ARG_WS}, {
+ atom_op_sub, ATOM_ARG_FB}, {
+ atom_op_sub, ATOM_ARG_PLL}, {
+ atom_op_sub, ATOM_ARG_MC}, {
+ atom_op_setport, ATOM_PORT_ATI}, {
+ atom_op_setport, ATOM_PORT_PCI}, {
+ atom_op_setport, ATOM_PORT_SYSIO}, {
+ atom_op_setregblock, 0}, {
+ atom_op_setfbbase, 0}, {
+ atom_op_compare, ATOM_ARG_REG}, {
+ atom_op_compare, ATOM_ARG_PS}, {
+ atom_op_compare, ATOM_ARG_WS}, {
+ atom_op_compare, ATOM_ARG_FB}, {
+ atom_op_compare, ATOM_ARG_PLL}, {
+ atom_op_compare, ATOM_ARG_MC}, {
+ atom_op_switch, 0}, {
+ atom_op_jump, ATOM_COND_ALWAYS}, {
+ atom_op_jump, ATOM_COND_EQUAL}, {
+ atom_op_jump, ATOM_COND_BELOW}, {
+ atom_op_jump, ATOM_COND_ABOVE}, {
+ atom_op_jump, ATOM_COND_BELOWOREQUAL}, {
+ atom_op_jump, ATOM_COND_ABOVEOREQUAL}, {
+ atom_op_jump, ATOM_COND_NOTEQUAL}, {
+ atom_op_test, ATOM_ARG_REG}, {
+ atom_op_test, ATOM_ARG_PS}, {
+ atom_op_test, ATOM_ARG_WS}, {
+ atom_op_test, ATOM_ARG_FB}, {
+ atom_op_test, ATOM_ARG_PLL}, {
+ atom_op_test, ATOM_ARG_MC}, {
+ atom_op_delay, ATOM_UNIT_MILLISEC}, {
+ atom_op_delay, ATOM_UNIT_MICROSEC}, {
+ atom_op_calltable, 0}, {
+ atom_op_repeat, 0}, {
+ atom_op_clear, ATOM_ARG_REG}, {
+ atom_op_clear, ATOM_ARG_PS}, {
+ atom_op_clear, ATOM_ARG_WS}, {
+ atom_op_clear, ATOM_ARG_FB}, {
+ atom_op_clear, ATOM_ARG_PLL}, {
+ atom_op_clear, ATOM_ARG_MC}, {
+ atom_op_nop, 0}, {
+ atom_op_eot, 0}, {
+ atom_op_mask, ATOM_ARG_REG}, {
+ atom_op_mask, ATOM_ARG_PS}, {
+ atom_op_mask, ATOM_ARG_WS}, {
+ atom_op_mask, ATOM_ARG_FB}, {
+ atom_op_mask, ATOM_ARG_PLL}, {
+ atom_op_mask, ATOM_ARG_MC}, {
+ atom_op_postcard, 0}, {
+ atom_op_beep, 0}, {
+ atom_op_savereg, 0}, {
+ atom_op_restorereg, 0}, {
+ atom_op_setdatablock, 0}, {
+ atom_op_xor, ATOM_ARG_REG}, {
+ atom_op_xor, ATOM_ARG_PS}, {
+ atom_op_xor, ATOM_ARG_WS}, {
+ atom_op_xor, ATOM_ARG_FB}, {
+ atom_op_xor, ATOM_ARG_PLL}, {
+ atom_op_xor, ATOM_ARG_MC}, {
+ atom_op_shl, ATOM_ARG_REG}, {
+ atom_op_shl, ATOM_ARG_PS}, {
+ atom_op_shl, ATOM_ARG_WS}, {
+ atom_op_shl, ATOM_ARG_FB}, {
+ atom_op_shl, ATOM_ARG_PLL}, {
+ atom_op_shl, ATOM_ARG_MC}, {
+ atom_op_shr, ATOM_ARG_REG}, {
+ atom_op_shr, ATOM_ARG_PS}, {
+ atom_op_shr, ATOM_ARG_WS}, {
+ atom_op_shr, ATOM_ARG_FB}, {
+ atom_op_shr, ATOM_ARG_PLL}, {
+ atom_op_shr, ATOM_ARG_MC}, {
+atom_op_debug, 0},};
+
+static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
+{
+ int base = CU16(ctx->cmd_table + 4 + 2 * index);
+ int len, ws, ps, ptr;
+ unsigned char op;
+ atom_exec_context ectx;
+ int ret = 0;
+
+ if (!base)
+ return -EINVAL;
+
+ len = CU16(base + ATOM_CT_SIZE_PTR);
+ ws = CU8(base + ATOM_CT_WS_PTR);
+ ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
+ ptr = base + ATOM_CT_CODE_PTR;
+
+ SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
+
+ ectx.ctx = ctx;
+ ectx.ps_shift = ps / 4;
+ ectx.start = base;
+ ectx.ps = params;
+ ectx.abort = false;
+ ectx.last_jump = 0;
+ if (ws)
+ ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
+ else
+ ectx.ws = NULL;
+
+ debug_depth++;
+ while (1) {
+ op = CU8(ptr++);
+ if (op < ATOM_OP_NAMES_CNT)
+ SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
+ else
+ SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
+ if (ectx.abort) {
+ DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
+ base, len, ws, ps, ptr - 1);
+ ret = -EINVAL;
+ goto free;
+ }
+
+ if (op < ATOM_OP_CNT && op > 0)
+ opcode_table[op].func(&ectx, &ptr,
+ opcode_table[op].arg);
+ else
+ break;
+
+ if (op == ATOM_OP_EOT)
+ break;
+ }
+ debug_depth--;
+ SDEBUG("<<\n");
+
+free:
+ if (ws)
+ kfree(ectx.ws);
+ return ret;
+}
+
+int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
+{
+ int r;
+
+ mutex_lock(&ctx->mutex);
+ /* reset data block */
+ ctx->data_block = 0;
+ /* reset reg block */
+ ctx->reg_block = 0;
+ /* reset fb window */
+ ctx->fb_base = 0;
+ /* reset io mode */
+ ctx->io_mode = ATOM_IO_MM;
+ /* reset divmul */
+ ctx->divmul[0] = 0;
+ ctx->divmul[1] = 0;
+ r = amdgpu_atom_execute_table_locked(ctx, index, params);
+ mutex_unlock(&ctx->mutex);
+ return r;
+}
+
+static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
+
+static void atom_index_iio(struct atom_context *ctx, int base)
+{
+ ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
+ if (!ctx->iio)
+ return;
+ while (CU8(base) == ATOM_IIO_START) {
+ ctx->iio[CU8(base + 1)] = base + 2;
+ base += 2;
+ while (CU8(base) != ATOM_IIO_END)
+ base += atom_iio_len[CU8(base)];
+ base += 3;
+ }
+}
+
+struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios)
+{
+ int base;
+ struct atom_context *ctx =
+ kzalloc(sizeof(struct atom_context), GFP_KERNEL);
+ char *str;
+ char name[512];
+ int i;
+
+ if (!ctx)
+ return NULL;
+
+ ctx->card = card;
+ ctx->bios = bios;
+
+ if (CU16(0) != ATOM_BIOS_MAGIC) {
+ printk(KERN_INFO "Invalid BIOS magic.\n");
+ kfree(ctx);
+ return NULL;
+ }
+ if (strncmp
+ (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
+ strlen(ATOM_ATI_MAGIC))) {
+ printk(KERN_INFO "Invalid ATI magic.\n");
+ kfree(ctx);
+ return NULL;
+ }
+
+ base = CU16(ATOM_ROM_TABLE_PTR);
+ if (strncmp
+ (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
+ strlen(ATOM_ROM_MAGIC))) {
+ printk(KERN_INFO "Invalid ATOM magic.\n");
+ kfree(ctx);
+ return NULL;
+ }
+
+ ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
+ ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
+ atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
+ if (!ctx->iio) {
+ amdgpu_atom_destroy(ctx);
+ return NULL;
+ }
+
+ str = CSTR(CU16(base + ATOM_ROM_MSG_PTR));
+ while (*str && ((*str == '\n') || (*str == '\r')))
+ str++;
+ /* name string isn't always 0 terminated */
+ for (i = 0; i < 511; i++) {
+ name[i] = str[i];
+ if (name[i] < '.' || name[i] > 'z') {
+ name[i] = 0;
+ break;
+ }
+ }
+ printk(KERN_INFO "ATOM BIOS: %s\n", name);
+
+ return ctx;
+}
+
+int amdgpu_atom_asic_init(struct atom_context *ctx)
+{
+ int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
+ uint32_t ps[16];
+ int ret;
+
+ memset(ps, 0, 64);
+
+ ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
+ ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
+ if (!ps[0] || !ps[1])
+ return 1;
+
+ if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
+ return 1;
+ ret = amdgpu_atom_execute_table(ctx, ATOM_CMD_INIT, ps);
+ if (ret)
+ return ret;
+
+ memset(ps, 0, 64);
+
+ return ret;
+}
+
+void amdgpu_atom_destroy(struct atom_context *ctx)
+{
+ kfree(ctx->iio);
+ kfree(ctx);
+}
+
+bool amdgpu_atom_parse_data_header(struct atom_context *ctx, int index,
+ uint16_t * size, uint8_t * frev, uint8_t * crev,
+ uint16_t * data_start)
+{
+ int offset = index * 2 + 4;
+ int idx = CU16(ctx->data_table + offset);
+ u16 *mdt = (u16 *)(ctx->bios + ctx->data_table + 4);
+
+ if (!mdt[index])
+ return false;
+
+ if (size)
+ *size = CU16(idx);
+ if (frev)
+ *frev = CU8(idx + 2);
+ if (crev)
+ *crev = CU8(idx + 3);
+ *data_start = idx;
+ return true;
+}
+
+bool amdgpu_atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev,
+ uint8_t * crev)
+{
+ int offset = index * 2 + 4;
+ int idx = CU16(ctx->cmd_table + offset);
+ u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4);
+
+ if (!mct[index])
+ return false;
+
+ if (frev)
+ *frev = CU8(idx + 2);
+ if (crev)
+ *crev = CU8(idx + 3);
+ return true;
+}
+
+int amdgpu_atom_allocate_fb_scratch(struct atom_context *ctx)
+{
+ int index = GetIndexIntoMasterTable(DATA, VRAM_UsageByFirmware);
+ uint16_t data_offset;
+ int usage_bytes = 0;
+ struct _ATOM_VRAM_USAGE_BY_FIRMWARE *firmware_usage;
+
+ if (amdgpu_atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
+ firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset);
+
+ DRM_DEBUG("atom firmware requested %08x %dkb\n",
+ le32_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware),
+ le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb));
+
+ usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024;
+ }
+ ctx->scratch_size_bytes = 0;
+ if (usage_bytes == 0)
+ usage_bytes = 20 * 1024;
+ /* allocate some scratch memory */
+ ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
+ if (!ctx->scratch)
+ return -ENOMEM;
+ ctx->scratch_size_bytes = usage_bytes;
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/atom.h b/drivers/gpu/drm/amd/amdgpu/atom.h
new file mode 100644
index 000000000000..09d0f8230708
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atom.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Stanislaw Skowronek
+ */
+
+#ifndef ATOM_H
+#define ATOM_H
+
+#include <linux/types.h>
+#include <drm/drmP.h>
+
+#define ATOM_BIOS_MAGIC 0xAA55
+#define ATOM_ATI_MAGIC_PTR 0x30
+#define ATOM_ATI_MAGIC " 761295520"
+#define ATOM_ROM_TABLE_PTR 0x48
+
+#define ATOM_ROM_MAGIC "ATOM"
+#define ATOM_ROM_MAGIC_PTR 4
+
+#define ATOM_ROM_MSG_PTR 0x10
+#define ATOM_ROM_CMD_PTR 0x1E
+#define ATOM_ROM_DATA_PTR 0x20
+
+#define ATOM_CMD_INIT 0
+#define ATOM_CMD_SETSCLK 0x0A
+#define ATOM_CMD_SETMCLK 0x0B
+#define ATOM_CMD_SETPCLK 0x0C
+#define ATOM_CMD_SPDFANCNTL 0x39
+
+#define ATOM_DATA_FWI_PTR 0xC
+#define ATOM_DATA_IIO_PTR 0x32
+
+#define ATOM_FWI_DEFSCLK_PTR 8
+#define ATOM_FWI_DEFMCLK_PTR 0xC
+#define ATOM_FWI_MAXSCLK_PTR 0x24
+#define ATOM_FWI_MAXMCLK_PTR 0x28
+
+#define ATOM_CT_SIZE_PTR 0
+#define ATOM_CT_WS_PTR 4
+#define ATOM_CT_PS_PTR 5
+#define ATOM_CT_PS_MASK 0x7F
+#define ATOM_CT_CODE_PTR 6
+
+#define ATOM_OP_CNT 123
+#define ATOM_OP_EOT 91
+
+#define ATOM_CASE_MAGIC 0x63
+#define ATOM_CASE_END 0x5A5A
+
+#define ATOM_ARG_REG 0
+#define ATOM_ARG_PS 1
+#define ATOM_ARG_WS 2
+#define ATOM_ARG_FB 3
+#define ATOM_ARG_ID 4
+#define ATOM_ARG_IMM 5
+#define ATOM_ARG_PLL 6
+#define ATOM_ARG_MC 7
+
+#define ATOM_SRC_DWORD 0
+#define ATOM_SRC_WORD0 1
+#define ATOM_SRC_WORD8 2
+#define ATOM_SRC_WORD16 3
+#define ATOM_SRC_BYTE0 4
+#define ATOM_SRC_BYTE8 5
+#define ATOM_SRC_BYTE16 6
+#define ATOM_SRC_BYTE24 7
+
+#define ATOM_WS_QUOTIENT 0x40
+#define ATOM_WS_REMAINDER 0x41
+#define ATOM_WS_DATAPTR 0x42
+#define ATOM_WS_SHIFT 0x43
+#define ATOM_WS_OR_MASK 0x44
+#define ATOM_WS_AND_MASK 0x45
+#define ATOM_WS_FB_WINDOW 0x46
+#define ATOM_WS_ATTRIBUTES 0x47
+#define ATOM_WS_REGPTR 0x48
+
+#define ATOM_IIO_NOP 0
+#define ATOM_IIO_START 1
+#define ATOM_IIO_READ 2
+#define ATOM_IIO_WRITE 3
+#define ATOM_IIO_CLEAR 4
+#define ATOM_IIO_SET 5
+#define ATOM_IIO_MOVE_INDEX 6
+#define ATOM_IIO_MOVE_ATTR 7
+#define ATOM_IIO_MOVE_DATA 8
+#define ATOM_IIO_END 9
+
+#define ATOM_IO_MM 0
+#define ATOM_IO_PCI 1
+#define ATOM_IO_SYSIO 2
+#define ATOM_IO_IIO 0x80
+
+struct card_info {
+ struct drm_device *dev;
+ void (* reg_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */
+ uint32_t (* reg_read)(struct card_info *, uint32_t); /* filled by driver */
+ void (* ioreg_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */
+ uint32_t (* ioreg_read)(struct card_info *, uint32_t); /* filled by driver */
+ void (* mc_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */
+ uint32_t (* mc_read)(struct card_info *, uint32_t); /* filled by driver */
+ void (* pll_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */
+ uint32_t (* pll_read)(struct card_info *, uint32_t); /* filled by driver */
+};
+
+struct atom_context {
+ struct card_info *card;
+ struct mutex mutex;
+ void *bios;
+ uint32_t cmd_table, data_table;
+ uint16_t *iio;
+
+ uint16_t data_block;
+ uint32_t fb_base;
+ uint32_t divmul[2];
+ uint16_t io_attr;
+ uint16_t reg_block;
+ uint8_t shift;
+ int cs_equal, cs_above;
+ int io_mode;
+ uint32_t *scratch;
+ int scratch_size_bytes;
+};
+
+extern int amdgpu_atom_debug;
+
+struct atom_context *amdgpu_atom_parse(struct card_info *, void *);
+int amdgpu_atom_execute_table(struct atom_context *, int, uint32_t *);
+int amdgpu_atom_asic_init(struct atom_context *);
+void amdgpu_atom_destroy(struct atom_context *);
+bool amdgpu_atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size,
+ uint8_t *frev, uint8_t *crev, uint16_t *data_start);
+bool amdgpu_atom_parse_cmd_header(struct atom_context *ctx, int index,
+ uint8_t *frev, uint8_t *crev);
+int amdgpu_atom_allocate_fb_scratch(struct atom_context *ctx);
+#include "atom-types.h"
+#include "atombios.h"
+#include "ObjectID.h"
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios.h b/drivers/gpu/drm/amd/amdgpu/atombios.h
new file mode 100644
index 000000000000..44c5d4a4d1bf
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atombios.h
@@ -0,0 +1,8555 @@
+/*
+ * Copyright 2006-2007 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.
+ */
+
+
+/****************************************************************************/
+/*Portion I: Definitions shared between VBIOS and Driver */
+/****************************************************************************/
+
+#ifndef _ATOMBIOS_H
+#define _ATOMBIOS_H
+
+#define ATOM_VERSION_MAJOR 0x00020000
+#define ATOM_VERSION_MINOR 0x00000002
+
+#define ATOM_HEADER_VERSION (ATOM_VERSION_MAJOR | ATOM_VERSION_MINOR)
+
+/* Endianness should be specified before inclusion,
+ * default to little endian
+ */
+#ifndef ATOM_BIG_ENDIAN
+#error Endian not specified
+#endif
+
+#ifdef _H2INC
+ #ifndef ULONG
+ typedef unsigned long ULONG;
+ #endif
+
+ #ifndef UCHAR
+ typedef unsigned char UCHAR;
+ #endif
+
+ #ifndef USHORT
+ typedef unsigned short USHORT;
+ #endif
+#endif
+
+#define ATOM_DAC_A 0
+#define ATOM_DAC_B 1
+#define ATOM_EXT_DAC 2
+
+#define ATOM_CRTC1 0
+#define ATOM_CRTC2 1
+#define ATOM_CRTC3 2
+#define ATOM_CRTC4 3
+#define ATOM_CRTC5 4
+#define ATOM_CRTC6 5
+
+#define ATOM_UNDERLAY_PIPE0 16
+#define ATOM_UNDERLAY_PIPE1 17
+
+#define ATOM_CRTC_INVALID 0xFF
+
+#define ATOM_DIGA 0
+#define ATOM_DIGB 1
+
+#define ATOM_PPLL1 0
+#define ATOM_PPLL2 1
+#define ATOM_DCPLL 2
+#define ATOM_PPLL0 2
+#define ATOM_PPLL3 3
+
+#define ATOM_EXT_PLL1 8
+#define ATOM_EXT_PLL2 9
+#define ATOM_EXT_CLOCK 10
+#define ATOM_PPLL_INVALID 0xFF
+
+#define ENCODER_REFCLK_SRC_P1PLL 0
+#define ENCODER_REFCLK_SRC_P2PLL 1
+#define ENCODER_REFCLK_SRC_DCPLL 2
+#define ENCODER_REFCLK_SRC_EXTCLK 3
+#define ENCODER_REFCLK_SRC_INVALID 0xFF
+
+#define ATOM_SCALER_DISABLE 0 //For Fudo, it's bypass and auto-cengter & no replication
+#define ATOM_SCALER_CENTER 1 //For Fudo, it's bypass and auto-center & auto replication
+#define ATOM_SCALER_EXPANSION 2 //For Fudo, it's 2 Tap alpha blending mode
+#define ATOM_SCALER_MULTI_EX 3 //For Fudo only, it's multi-tap mode only used to drive TV or CV, only used by Bios
+
+#define ATOM_DISABLE 0
+#define ATOM_ENABLE 1
+#define ATOM_LCD_BLOFF (ATOM_DISABLE+2)
+#define ATOM_LCD_BLON (ATOM_ENABLE+2)
+#define ATOM_LCD_BL_BRIGHTNESS_CONTROL (ATOM_ENABLE+3)
+#define ATOM_LCD_SELFTEST_START (ATOM_DISABLE+5)
+#define ATOM_LCD_SELFTEST_STOP (ATOM_ENABLE+5)
+#define ATOM_ENCODER_INIT (ATOM_DISABLE+7)
+#define ATOM_INIT (ATOM_DISABLE+7)
+#define ATOM_GET_STATUS (ATOM_DISABLE+8)
+
+#define ATOM_BLANKING 1
+#define ATOM_BLANKING_OFF 0
+
+
+#define ATOM_CRT1 0
+#define ATOM_CRT2 1
+
+#define ATOM_TV_NTSC 1
+#define ATOM_TV_NTSCJ 2
+#define ATOM_TV_PAL 3
+#define ATOM_TV_PALM 4
+#define ATOM_TV_PALCN 5
+#define ATOM_TV_PALN 6
+#define ATOM_TV_PAL60 7
+#define ATOM_TV_SECAM 8
+#define ATOM_TV_CV 16
+
+#define ATOM_DAC1_PS2 1
+#define ATOM_DAC1_CV 2
+#define ATOM_DAC1_NTSC 3
+#define ATOM_DAC1_PAL 4
+
+#define ATOM_DAC2_PS2 ATOM_DAC1_PS2
+#define ATOM_DAC2_CV ATOM_DAC1_CV
+#define ATOM_DAC2_NTSC ATOM_DAC1_NTSC
+#define ATOM_DAC2_PAL ATOM_DAC1_PAL
+
+#define ATOM_PM_ON 0
+#define ATOM_PM_STANDBY 1
+#define ATOM_PM_SUSPEND 2
+#define ATOM_PM_OFF 3
+
+// For ATOM_LVDS_INFO_V12
+// Bit0:{=0:single, =1:dual},
+// Bit1 {=0:666RGB, =1:888RGB},
+// Bit2:3:{Grey level}
+// Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888}
+#define ATOM_PANEL_MISC_DUAL 0x00000001
+#define ATOM_PANEL_MISC_888RGB 0x00000002
+#define ATOM_PANEL_MISC_GREY_LEVEL 0x0000000C
+#define ATOM_PANEL_MISC_FPDI 0x00000010
+#define ATOM_PANEL_MISC_GREY_LEVEL_SHIFT 2
+#define ATOM_PANEL_MISC_SPATIAL 0x00000020
+#define ATOM_PANEL_MISC_TEMPORAL 0x00000040
+#define ATOM_PANEL_MISC_API_ENABLED 0x00000080
+
+#define MEMTYPE_DDR1 "DDR1"
+#define MEMTYPE_DDR2 "DDR2"
+#define MEMTYPE_DDR3 "DDR3"
+#define MEMTYPE_DDR4 "DDR4"
+
+#define ASIC_BUS_TYPE_PCI "PCI"
+#define ASIC_BUS_TYPE_AGP "AGP"
+#define ASIC_BUS_TYPE_PCIE "PCI_EXPRESS"
+
+//Maximum size of that FireGL flag string
+#define ATOM_FIREGL_FLAG_STRING "FGL" //Flag used to enable FireGL Support
+#define ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING 3 //sizeof( ATOM_FIREGL_FLAG_STRING )
+
+#define ATOM_FAKE_DESKTOP_STRING "DSK" //Flag used to enable mobile ASIC on Desktop
+#define ATOM_MAX_SIZE_OF_FAKE_DESKTOP_STRING ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING
+
+#define ATOM_M54T_FLAG_STRING "M54T" //Flag used to enable M54T Support
+#define ATOM_MAX_SIZE_OF_M54T_FLAG_STRING 4 //sizeof( ATOM_M54T_FLAG_STRING )
+
+#define HW_ASSISTED_I2C_STATUS_FAILURE 2
+#define HW_ASSISTED_I2C_STATUS_SUCCESS 1
+
+#pragma pack(1) // BIOS data must use byte aligment
+
+// Define offset to location of ROM header.
+#define OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER 0x00000048L
+#define OFFSET_TO_ATOM_ROM_IMAGE_SIZE 0x00000002L
+
+#define OFFSET_TO_ATOMBIOS_ASIC_BUS_MEM_TYPE 0x94
+#define MAXSIZE_OF_ATOMBIOS_ASIC_BUS_MEM_TYPE 20 //including the terminator 0x0!
+#define OFFSET_TO_GET_ATOMBIOS_STRINGS_NUMBER 0x002f
+#define OFFSET_TO_GET_ATOMBIOS_STRINGS_START 0x006e
+
+/****************************************************************************/
+// Common header for all tables (Data table, Command table).
+// Every table pointed _ATOM_MASTER_DATA_TABLE has this common header.
+// And the pointer actually points to this header.
+/****************************************************************************/
+
+typedef struct _ATOM_COMMON_TABLE_HEADER
+{
+ USHORT usStructureSize;
+ UCHAR ucTableFormatRevision; //Change it when the Parser is not backward compatible
+ UCHAR ucTableContentRevision; //Change it only when the table needs to change but the firmware
+ //Image can't be updated, while Driver needs to carry the new table!
+}ATOM_COMMON_TABLE_HEADER;
+
+/****************************************************************************/
+// Structure stores the ROM header.
+/****************************************************************************/
+typedef struct _ATOM_ROM_HEADER
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR uaFirmWareSignature[4]; //Signature to distinguish between Atombios and non-atombios,
+ //atombios should init it as "ATOM", don't change the position
+ USHORT usBiosRuntimeSegmentAddress;
+ USHORT usProtectedModeInfoOffset;
+ USHORT usConfigFilenameOffset;
+ USHORT usCRC_BlockOffset;
+ USHORT usBIOS_BootupMessageOffset;
+ USHORT usInt10Offset;
+ USHORT usPciBusDevInitCode;
+ USHORT usIoBaseAddress;
+ USHORT usSubsystemVendorID;
+ USHORT usSubsystemID;
+ USHORT usPCI_InfoOffset;
+ USHORT usMasterCommandTableOffset;//Offest for SW to get all command table offsets, Don't change the position
+ USHORT usMasterDataTableOffset; //Offest for SW to get all data table offsets, Don't change the position
+ UCHAR ucExtendedFunctionCode;
+ UCHAR ucReserved;
+}ATOM_ROM_HEADER;
+
+//==============================Command Table Portion====================================
+
+
+/****************************************************************************/
+// Structures used in Command.mtb
+/****************************************************************************/
+typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
+ USHORT ASIC_Init; //Function Table, used by various SW components,latest version 1.1
+ USHORT GetDisplaySurfaceSize; //Atomic Table, Used by Bios when enabling HW ICON
+ USHORT ASIC_RegistersInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init
+ USHORT VRAM_BlockVenderDetection; //Atomic Table, used only by Bios
+ USHORT DIGxEncoderControl; //Only used by Bios
+ USHORT MemoryControllerInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init
+ USHORT EnableCRTCMemReq; //Function Table,directly used by various SW components,latest version 2.1
+ USHORT MemoryParamAdjust; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock if needed
+ USHORT DVOEncoderControl; //Function Table,directly used by various SW components,latest version 1.2
+ USHORT GPIOPinControl; //Atomic Table, only used by Bios
+ USHORT SetEngineClock; //Function Table,directly used by various SW components,latest version 1.1
+ USHORT SetMemoryClock; //Function Table,directly used by various SW components,latest version 1.1
+ USHORT SetPixelClock; //Function Table,directly used by various SW components,latest version 1.2
+ USHORT EnableDispPowerGating; //Atomic Table, indirectly used by various SW components,called from ASIC_Init
+ USHORT ResetMemoryDLL; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock
+ USHORT ResetMemoryDevice; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock
+ USHORT MemoryPLLInit; //Atomic Table, used only by Bios
+ USHORT AdjustDisplayPll; //Atomic Table, used by various SW componentes.
+ USHORT AdjustMemoryController; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock
+ USHORT EnableASIC_StaticPwrMgt; //Atomic Table, only used by Bios
+ USHORT SetUniphyInstance; //Atomic Table, only used by Bios
+ USHORT DAC_LoadDetection; //Atomic Table, directly used by various SW components,latest version 1.2
+ USHORT LVTMAEncoderControl; //Atomic Table,directly used by various SW components,latest version 1.3
+ USHORT HW_Misc_Operation; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT DAC1EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT DAC2EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT DVOOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT CV1OutputControl; //Atomic Table, Atomic Table, Obsolete from Ry6xx, use DAC2 Output instead
+ USHORT GetConditionalGoldenSetting; //Only used by Bios
+ USHORT SMC_Init; //Function Table,directly used by various SW components,latest version 1.1
+ USHORT PatchMCSetting; //only used by BIOS
+ USHORT MC_SEQ_Control; //only used by BIOS
+ USHORT Gfx_Harvesting; //Atomic Table, Obsolete from Ry6xx, Now only used by BIOS for GFX harvesting
+ USHORT EnableScaler; //Atomic Table, used only by Bios
+ USHORT BlankCRTC; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT EnableCRTC; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT GetPixelClock; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT EnableVGA_Render; //Function Table,directly used by various SW components,latest version 1.1
+ USHORT GetSCLKOverMCLKRatio; //Atomic Table, only used by Bios
+ USHORT SetCRTC_Timing; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT SetCRTC_OverScan; //Atomic Table, used by various SW components,latest version 1.1
+ USHORT SetCRTC_Replication; //Atomic Table, used only by Bios
+ USHORT SelectCRTC_Source; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT EnableGraphSurfaces; //Atomic Table, used only by Bios
+ USHORT UpdateCRTC_DoubleBufferRegisters; //Atomic Table, used only by Bios
+ USHORT LUT_AutoFill; //Atomic Table, only used by Bios
+ USHORT EnableHW_IconCursor; //Atomic Table, only used by Bios
+ USHORT GetMemoryClock; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT GetEngineClock; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT SetCRTC_UsingDTDTiming; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT ExternalEncoderControl; //Atomic Table, directly used by various SW components,latest version 2.1
+ USHORT LVTMAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT VRAM_BlockDetectionByStrap; //Atomic Table, used only by Bios
+ USHORT MemoryCleanUp; //Atomic Table, only used by Bios
+ USHORT ProcessI2cChannelTransaction; //Function Table,only used by Bios
+ USHORT WriteOneByteToHWAssistedI2C; //Function Table,indirectly used by various SW components
+ USHORT ReadHWAssistedI2CStatus; //Atomic Table, indirectly used by various SW components
+ USHORT SpeedFanControl; //Function Table,indirectly used by various SW components,called from ASIC_Init
+ USHORT PowerConnectorDetection; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT MC_Synchronization; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock
+ USHORT ComputeMemoryEnginePLL; //Atomic Table, indirectly used by various SW components,called from SetMemory/EngineClock
+ USHORT MemoryRefreshConversion; //Atomic Table, indirectly used by various SW components,called from SetMemory or SetEngineClock
+ USHORT VRAM_GetCurrentInfoBlock; //Atomic Table, used only by Bios
+ USHORT DynamicMemorySettings; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock
+ USHORT MemoryTraining; //Atomic Table, used only by Bios
+ USHORT EnableSpreadSpectrumOnPPLL; //Atomic Table, directly used by various SW components,latest version 1.2
+ USHORT TMDSAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT SetVoltage; //Function Table,directly and/or indirectly used by various SW components,latest version 1.1
+ USHORT DAC1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT ReadEfuseValue; //Atomic Table, directly used by various SW components,latest version 1.1
+ USHORT ComputeMemoryClockParam; //Function Table,only used by Bios, obsolete soon.Switch to use "ReadEDIDFromHWAssistedI2C"
+ USHORT ClockSource; //Atomic Table, indirectly used by various SW components,called from ASIC_Init
+ USHORT MemoryDeviceInit; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock
+ USHORT GetDispObjectInfo; //Atomic Table, indirectly used by various SW components,called from EnableVGARender
+ USHORT DIG1EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1
+ USHORT DIG2EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1
+ USHORT DIG1TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1
+ USHORT DIG2TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1
+ USHORT ProcessAuxChannelTransaction; //Function Table,only used by Bios
+ USHORT DPEncoderService; //Function Table,only used by Bios
+ USHORT GetVoltageInfo; //Function Table,only used by Bios since SI
+}ATOM_MASTER_LIST_OF_COMMAND_TABLES;
+
+// For backward compatible
+#define ReadEDIDFromHWAssistedI2C ProcessI2cChannelTransaction
+#define DPTranslatorControl DIG2EncoderControl
+#define UNIPHYTransmitterControl DIG1TransmitterControl
+#define LVTMATransmitterControl DIG2TransmitterControl
+#define SetCRTC_DPM_State GetConditionalGoldenSetting
+#define ASIC_StaticPwrMgtStatusChange SetUniphyInstance
+#define HPDInterruptService ReadHWAssistedI2CStatus
+#define EnableVGA_Access GetSCLKOverMCLKRatio
+#define EnableYUV GetDispObjectInfo
+#define DynamicClockGating EnableDispPowerGating
+#define SetupHWAssistedI2CStatus ComputeMemoryClockParam
+#define DAC2OutputControl ReadEfuseValue
+
+#define TMDSAEncoderControl PatchMCSetting
+#define LVDSEncoderControl MC_SEQ_Control
+#define LCD1OutputControl HW_Misc_Operation
+#define TV1OutputControl Gfx_Harvesting
+#define TVEncoderControl SMC_Init
+
+typedef struct _ATOM_MASTER_COMMAND_TABLE
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_MASTER_LIST_OF_COMMAND_TABLES ListOfCommandTables;
+}ATOM_MASTER_COMMAND_TABLE;
+
+/****************************************************************************/
+// Structures used in every command table
+/****************************************************************************/
+typedef struct _ATOM_TABLE_ATTRIBUTE
+{
+#if ATOM_BIG_ENDIAN
+ USHORT UpdatedByUtility:1; //[15]=Table updated by utility flag
+ USHORT PS_SizeInBytes:7; //[14:8]=Size of parameter space in Bytes (multiple of a dword),
+ USHORT WS_SizeInBytes:8; //[7:0]=Size of workspace in Bytes (in multiple of a dword),
+#else
+ USHORT WS_SizeInBytes:8; //[7:0]=Size of workspace in Bytes (in multiple of a dword),
+ USHORT PS_SizeInBytes:7; //[14:8]=Size of parameter space in Bytes (multiple of a dword),
+ USHORT UpdatedByUtility:1; //[15]=Table updated by utility flag
+#endif
+}ATOM_TABLE_ATTRIBUTE;
+
+/****************************************************************************/
+// Common header for all command tables.
+// Every table pointed by _ATOM_MASTER_COMMAND_TABLE has this common header.
+// And the pointer actually points to this header.
+/****************************************************************************/
+typedef struct _ATOM_COMMON_ROM_COMMAND_TABLE_HEADER
+{
+ ATOM_COMMON_TABLE_HEADER CommonHeader;
+ ATOM_TABLE_ATTRIBUTE TableAttribute;
+}ATOM_COMMON_ROM_COMMAND_TABLE_HEADER;
+
+/****************************************************************************/
+// Structures used by ComputeMemoryEnginePLLTable
+/****************************************************************************/
+
+#define COMPUTE_MEMORY_PLL_PARAM 1
+#define COMPUTE_ENGINE_PLL_PARAM 2
+#define ADJUST_MC_SETTING_PARAM 3
+
+/****************************************************************************/
+// Structures used by AdjustMemoryControllerTable
+/****************************************************************************/
+typedef struct _ATOM_ADJUST_MEMORY_CLOCK_FREQ
+{
+#if ATOM_BIG_ENDIAN
+ ULONG ulPointerReturnFlag:1; // BYTE_3[7]=1 - Return the pointer to the right Data Block; BYTE_3[7]=0 - Program the right Data Block
+ ULONG ulMemoryModuleNumber:7; // BYTE_3[6:0]
+ ULONG ulClockFreq:24;
+#else
+ ULONG ulClockFreq:24;
+ ULONG ulMemoryModuleNumber:7; // BYTE_3[6:0]
+ ULONG ulPointerReturnFlag:1; // BYTE_3[7]=1 - Return the pointer to the right Data Block; BYTE_3[7]=0 - Program the right Data Block
+#endif
+}ATOM_ADJUST_MEMORY_CLOCK_FREQ;
+#define POINTER_RETURN_FLAG 0x80
+
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS
+{
+ ULONG ulClock; //When returen, it's the re-calculated clock based on given Fb_div Post_Div and ref_div
+ UCHAR ucAction; //0:reserved //1:Memory //2:Engine
+ UCHAR ucReserved; //may expand to return larger Fbdiv later
+ UCHAR ucFbDiv; //return value
+ UCHAR ucPostDiv; //return value
+}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS;
+
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2
+{
+ ULONG ulClock; //When return, [23:0] return real clock
+ UCHAR ucAction; //0:reserved;COMPUTE_MEMORY_PLL_PARAM:Memory;COMPUTE_ENGINE_PLL_PARAM:Engine. it return ref_div to be written to register
+ USHORT usFbDiv; //return Feedback value to be written to register
+ UCHAR ucPostDiv; //return post div to be written to register
+}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2;
+
+#define COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS
+
+#define SET_CLOCK_FREQ_MASK 0x00FFFFFF //Clock change tables only take bit [23:0] as the requested clock value
+#define USE_NON_BUS_CLOCK_MASK 0x01000000 //Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa)
+#define USE_MEMORY_SELF_REFRESH_MASK 0x02000000 //Only applicable to memory clock change, when set, using memory self refresh during clock transition
+#define SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04000000 //Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change
+#define FIRST_TIME_CHANGE_CLOCK 0x08000000 //Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup
+#define SKIP_SW_PROGRAM_PLL 0x10000000 //Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL
+#define USE_SS_ENABLED_PIXEL_CLOCK USE_NON_BUS_CLOCK_MASK
+
+#define b3USE_NON_BUS_CLOCK_MASK 0x01 //Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa)
+#define b3USE_MEMORY_SELF_REFRESH 0x02 //Only applicable to memory clock change, when set, using memory self refresh during clock transition
+#define b3SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04 //Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change
+#define b3FIRST_TIME_CHANGE_CLOCK 0x08 //Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup
+#define b3SKIP_SW_PROGRAM_PLL 0x10 //Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL
+#define b3DRAM_SELF_REFRESH_EXIT 0x20 //Applicable to DRAM self refresh exit only. when set, it means it will go to program DRAM self refresh exit path
+
+typedef struct _ATOM_COMPUTE_CLOCK_FREQ
+{
+#if ATOM_BIG_ENDIAN
+ ULONG ulComputeClockFlag:8; // =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM
+ ULONG ulClockFreq:24; // in unit of 10kHz
+#else
+ ULONG ulClockFreq:24; // in unit of 10kHz
+ ULONG ulComputeClockFlag:8; // =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM
+#endif
+}ATOM_COMPUTE_CLOCK_FREQ;
+
+typedef struct _ATOM_S_MPLL_FB_DIVIDER
+{
+ USHORT usFbDivFrac;
+ USHORT usFbDiv;
+}ATOM_S_MPLL_FB_DIVIDER;
+
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3
+{
+ union
+ {
+ ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter
+ ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter
+ };
+ UCHAR ucRefDiv; //Output Parameter
+ UCHAR ucPostDiv; //Output Parameter
+ UCHAR ucCntlFlag; //Output Parameter
+ UCHAR ucReserved;
+}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3;
+
+// ucCntlFlag
+#define ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN 1
+#define ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE 2
+#define ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE 4
+#define ATOM_PLL_CNTL_FLAG_SPLL_ISPARE_9 8
+
+
+// V4 are only used for APU which PLL outside GPU
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4
+{
+#if ATOM_BIG_ENDIAN
+ ULONG ucPostDiv:8; //return parameter: post divider which is used to program to register directly
+ ULONG ulClock:24; //Input= target clock, output = actual clock
+#else
+ ULONG ulClock:24; //Input= target clock, output = actual clock
+ ULONG ucPostDiv:8; //return parameter: post divider which is used to program to register directly
+#endif
+}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4;
+
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5
+{
+ union
+ {
+ ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter
+ ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter
+ };
+ UCHAR ucRefDiv; //Output Parameter
+ UCHAR ucPostDiv; //Output Parameter
+ union
+ {
+ UCHAR ucCntlFlag; //Output Flags
+ UCHAR ucInputFlag; //Input Flags. ucInputFlag[0] - Strobe(1)/Performance(0) mode
+ };
+ UCHAR ucReserved;
+}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5;
+
+
+typedef struct _COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6
+{
+ ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter
+ ULONG ulReserved[2];
+}COMPUTE_GPU_CLOCK_INPUT_PARAMETERS_V1_6;
+
+//ATOM_COMPUTE_CLOCK_FREQ.ulComputeClockFlag
+#define COMPUTE_GPUCLK_INPUT_FLAG_CLK_TYPE_MASK 0x0f
+#define COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK 0x00
+#define COMPUTE_GPUCLK_INPUT_FLAG_SCLK 0x01
+
+
+typedef struct _COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6
+{
+ COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 ulClock; //Output Parameter: ucPostDiv=DFS divider
+ ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter: PLL FB divider
+ UCHAR ucPllRefDiv; //Output Parameter: PLL ref divider
+ UCHAR ucPllPostDiv; //Output Parameter: PLL post divider
+ UCHAR ucPllCntlFlag; //Output Flags: control flag
+ UCHAR ucReserved;
+}COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6;
+
+//ucPllCntlFlag
+#define SPLL_CNTL_FLAG_VCO_MODE_MASK 0x03
+
+
+// ucInputFlag
+#define ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN 1 // 1-StrobeMode, 0-PerformanceMode
+
+// use for ComputeMemoryClockParamTable
+typedef struct _COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1
+{
+ union
+ {
+ ULONG ulClock;
+ ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output:UPPER_WORD=FB_DIV_INTEGER, LOWER_WORD=FB_DIV_FRAC shl (16-FB_FRACTION_BITS)
+ };
+ UCHAR ucDllSpeed; //Output
+ UCHAR ucPostDiv; //Output
+ union{
+ UCHAR ucInputFlag; //Input : ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN: 1-StrobeMode, 0-PerformanceMode
+ UCHAR ucPllCntlFlag; //Output:
+ };
+ UCHAR ucBWCntl;
+}COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1;
+
+// definition of ucInputFlag
+#define MPLL_INPUT_FLAG_STROBE_MODE_EN 0x01
+// definition of ucPllCntlFlag
+#define MPLL_CNTL_FLAG_VCO_MODE_MASK 0x03
+#define MPLL_CNTL_FLAG_BYPASS_DQ_PLL 0x04
+#define MPLL_CNTL_FLAG_QDR_ENABLE 0x08
+#define MPLL_CNTL_FLAG_AD_HALF_RATE 0x10
+
+//MPLL_CNTL_FLAG_BYPASS_AD_PLL has a wrong name, should be BYPASS_DQ_PLL
+#define MPLL_CNTL_FLAG_BYPASS_AD_PLL 0x04
+
+typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER
+{
+ ATOM_COMPUTE_CLOCK_FREQ ulClock;
+ ULONG ulReserved[2];
+}DYNAMICE_MEMORY_SETTINGS_PARAMETER;
+
+typedef struct _DYNAMICE_ENGINE_SETTINGS_PARAMETER
+{
+ ATOM_COMPUTE_CLOCK_FREQ ulClock;
+ ULONG ulMemoryClock;
+ ULONG ulReserved;
+}DYNAMICE_ENGINE_SETTINGS_PARAMETER;
+
+/****************************************************************************/
+// Structures used by SetEngineClockTable
+/****************************************************************************/
+typedef struct _SET_ENGINE_CLOCK_PARAMETERS
+{
+ ULONG ulTargetEngineClock; //In 10Khz unit
+}SET_ENGINE_CLOCK_PARAMETERS;
+
+typedef struct _SET_ENGINE_CLOCK_PS_ALLOCATION
+{
+ ULONG ulTargetEngineClock; //In 10Khz unit
+ COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved;
+}SET_ENGINE_CLOCK_PS_ALLOCATION;
+
+/****************************************************************************/
+// Structures used by SetMemoryClockTable
+/****************************************************************************/
+typedef struct _SET_MEMORY_CLOCK_PARAMETERS
+{
+ ULONG ulTargetMemoryClock; //In 10Khz unit
+}SET_MEMORY_CLOCK_PARAMETERS;
+
+typedef struct _SET_MEMORY_CLOCK_PS_ALLOCATION
+{
+ ULONG ulTargetMemoryClock; //In 10Khz unit
+ COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved;
+}SET_MEMORY_CLOCK_PS_ALLOCATION;
+
+/****************************************************************************/
+// Structures used by ASIC_Init.ctb
+/****************************************************************************/
+typedef struct _ASIC_INIT_PARAMETERS
+{
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+}ASIC_INIT_PARAMETERS;
+
+typedef struct _ASIC_INIT_PS_ALLOCATION
+{
+ ASIC_INIT_PARAMETERS sASICInitClocks;
+ SET_ENGINE_CLOCK_PS_ALLOCATION sReserved; //Caller doesn't need to init this structure
+}ASIC_INIT_PS_ALLOCATION;
+
+typedef struct _ASIC_INIT_CLOCK_PARAMETERS
+{
+ ULONG ulClkFreqIn10Khz:24;
+ ULONG ucClkFlag:8;
+}ASIC_INIT_CLOCK_PARAMETERS;
+
+typedef struct _ASIC_INIT_PARAMETERS_V1_2
+{
+ ASIC_INIT_CLOCK_PARAMETERS asSclkClock; //In 10Khz unit
+ ASIC_INIT_CLOCK_PARAMETERS asMemClock; //In 10Khz unit
+}ASIC_INIT_PARAMETERS_V1_2;
+
+typedef struct _ASIC_INIT_PS_ALLOCATION_V1_2
+{
+ ASIC_INIT_PARAMETERS_V1_2 sASICInitClocks;
+ ULONG ulReserved[8];
+}ASIC_INIT_PS_ALLOCATION_V1_2;
+
+/****************************************************************************/
+// Structure used by DynamicClockGatingTable.ctb
+/****************************************************************************/
+typedef struct _DYNAMIC_CLOCK_GATING_PARAMETERS
+{
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucPadding[3];
+}DYNAMIC_CLOCK_GATING_PARAMETERS;
+#define DYNAMIC_CLOCK_GATING_PS_ALLOCATION DYNAMIC_CLOCK_GATING_PARAMETERS
+
+/****************************************************************************/
+// Structure used by EnableDispPowerGatingTable.ctb
+/****************************************************************************/
+typedef struct _ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1
+{
+ UCHAR ucDispPipeId; // ATOM_CRTC1, ATOM_CRTC2, ...
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucPadding[2];
+}ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1;
+
+typedef struct _ENABLE_DISP_POWER_GATING_PS_ALLOCATION
+{
+ UCHAR ucDispPipeId; // ATOM_CRTC1, ATOM_CRTC2, ...
+ UCHAR ucEnable; // ATOM_ENABLE/ATOM_DISABLE/ATOM_INIT
+ UCHAR ucPadding[2];
+ ULONG ulReserved[4];
+}ENABLE_DISP_POWER_GATING_PS_ALLOCATION;
+
+/****************************************************************************/
+// Structure used by EnableASIC_StaticPwrMgtTable.ctb
+/****************************************************************************/
+typedef struct _ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS
+{
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucPadding[3];
+}ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS;
+#define ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS
+
+/****************************************************************************/
+// Structures used by DAC_LoadDetectionTable.ctb
+/****************************************************************************/
+typedef struct _DAC_LOAD_DETECTION_PARAMETERS
+{
+ USHORT usDeviceID; //{ATOM_DEVICE_CRTx_SUPPORT,ATOM_DEVICE_TVx_SUPPORT,ATOM_DEVICE_CVx_SUPPORT}
+ UCHAR ucDacType; //{ATOM_DAC_A,ATOM_DAC_B, ATOM_EXT_DAC}
+ UCHAR ucMisc; //Valid only when table revision =1.3 and above
+}DAC_LOAD_DETECTION_PARAMETERS;
+
+// DAC_LOAD_DETECTION_PARAMETERS.ucMisc
+#define DAC_LOAD_MISC_YPrPb 0x01
+
+typedef struct _DAC_LOAD_DETECTION_PS_ALLOCATION
+{
+ DAC_LOAD_DETECTION_PARAMETERS sDacload;
+ ULONG Reserved[2];// Don't set this one, allocation for EXT DAC
+}DAC_LOAD_DETECTION_PS_ALLOCATION;
+
+/****************************************************************************/
+// Structures used by DAC1EncoderControlTable.ctb and DAC2EncoderControlTable.ctb
+/****************************************************************************/
+typedef struct _DAC_ENCODER_CONTROL_PARAMETERS
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ UCHAR ucDacStandard; // See definition of ATOM_DACx_xxx, For DEC3.0, bit 7 used as internal flag to indicate DAC2 (==1) or DAC1 (==0)
+ UCHAR ucAction; // 0: turn off encoder
+ // 1: setup and turn on encoder
+ // 7: ATOM_ENCODER_INIT Initialize DAC
+}DAC_ENCODER_CONTROL_PARAMETERS;
+
+#define DAC_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PARAMETERS
+
+/****************************************************************************/
+// Structures used by DIG1EncoderControlTable
+// DIG2EncoderControlTable
+// ExternalEncoderControlTable
+/****************************************************************************/
+typedef struct _DIG_ENCODER_CONTROL_PARAMETERS
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ UCHAR ucConfig;
+ // [2] Link Select:
+ // =0: PHY linkA if bfLane<3
+ // =1: PHY linkB if bfLanes<3
+ // =0: PHY linkA+B if bfLanes=3
+ // [3] Transmitter Sel
+ // =0: UNIPHY or PCIEPHY
+ // =1: LVTMA
+ UCHAR ucAction; // =0: turn off encoder
+ // =1: turn on encoder
+ UCHAR ucEncoderMode;
+ // =0: DP encoder
+ // =1: LVDS encoder
+ // =2: DVI encoder
+ // =3: HDMI encoder
+ // =4: SDVO encoder
+ UCHAR ucLaneNum; // how many lanes to enable
+ UCHAR ucReserved[2];
+}DIG_ENCODER_CONTROL_PARAMETERS;
+#define DIG_ENCODER_CONTROL_PS_ALLOCATION DIG_ENCODER_CONTROL_PARAMETERS
+#define EXTERNAL_ENCODER_CONTROL_PARAMETER DIG_ENCODER_CONTROL_PARAMETERS
+
+//ucConfig
+#define ATOM_ENCODER_CONFIG_DPLINKRATE_MASK 0x01
+#define ATOM_ENCODER_CONFIG_DPLINKRATE_1_62GHZ 0x00
+#define ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ 0x01
+#define ATOM_ENCODER_CONFIG_DPLINKRATE_5_40GHZ 0x02
+#define ATOM_ENCODER_CONFIG_LINK_SEL_MASK 0x04
+#define ATOM_ENCODER_CONFIG_LINKA 0x00
+#define ATOM_ENCODER_CONFIG_LINKB 0x04
+#define ATOM_ENCODER_CONFIG_LINKA_B ATOM_TRANSMITTER_CONFIG_LINKA
+#define ATOM_ENCODER_CONFIG_LINKB_A ATOM_ENCODER_CONFIG_LINKB
+#define ATOM_ENCODER_CONFIG_TRANSMITTER_SEL_MASK 0x08
+#define ATOM_ENCODER_CONFIG_UNIPHY 0x00
+#define ATOM_ENCODER_CONFIG_LVTMA 0x08
+#define ATOM_ENCODER_CONFIG_TRANSMITTER1 0x00
+#define ATOM_ENCODER_CONFIG_TRANSMITTER2 0x08
+#define ATOM_ENCODER_CONFIG_DIGB 0x80 // VBIOS Internal use, outside SW should set this bit=0
+// ucAction
+// ATOM_ENABLE: Enable Encoder
+// ATOM_DISABLE: Disable Encoder
+
+//ucEncoderMode
+#define ATOM_ENCODER_MODE_DP 0
+#define ATOM_ENCODER_MODE_LVDS 1
+#define ATOM_ENCODER_MODE_DVI 2
+#define ATOM_ENCODER_MODE_HDMI 3
+#define ATOM_ENCODER_MODE_SDVO 4
+#define ATOM_ENCODER_MODE_DP_AUDIO 5
+#define ATOM_ENCODER_MODE_TV 13
+#define ATOM_ENCODER_MODE_CV 14
+#define ATOM_ENCODER_MODE_CRT 15
+#define ATOM_ENCODER_MODE_DVO 16
+#define ATOM_ENCODER_MODE_DP_SST ATOM_ENCODER_MODE_DP // For DP1.2
+#define ATOM_ENCODER_MODE_DP_MST 5 // For DP1.2
+
+
+typedef struct _ATOM_DIG_ENCODER_CONFIG_V2
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucReserved1:2;
+ UCHAR ucTransmitterSel:2; // =0: UniphyAB, =1: UniphyCD =2: UniphyEF
+ UCHAR ucLinkSel:1; // =0: linkA/C/E =1: linkB/D/F
+ UCHAR ucReserved:1;
+ UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz
+#else
+ UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz
+ UCHAR ucReserved:1;
+ UCHAR ucLinkSel:1; // =0: linkA/C/E =1: linkB/D/F
+ UCHAR ucTransmitterSel:2; // =0: UniphyAB, =1: UniphyCD =2: UniphyEF
+ UCHAR ucReserved1:2;
+#endif
+}ATOM_DIG_ENCODER_CONFIG_V2;
+
+
+typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ ATOM_DIG_ENCODER_CONFIG_V2 acConfig;
+ UCHAR ucAction;
+ UCHAR ucEncoderMode;
+ // =0: DP encoder
+ // =1: LVDS encoder
+ // =2: DVI encoder
+ // =3: HDMI encoder
+ // =4: SDVO encoder
+ UCHAR ucLaneNum; // how many lanes to enable
+ UCHAR ucStatus; // = DP_LINK_TRAINING_COMPLETE or DP_LINK_TRAINING_INCOMPLETE, only used by VBIOS with command ATOM_ENCODER_CMD_QUERY_DP_LINK_TRAINING_STATUS
+ UCHAR ucReserved;
+}DIG_ENCODER_CONTROL_PARAMETERS_V2;
+
+//ucConfig
+#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_MASK 0x01
+#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_1_62GHZ 0x00
+#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_2_70GHZ 0x01
+#define ATOM_ENCODER_CONFIG_V2_LINK_SEL_MASK 0x04
+#define ATOM_ENCODER_CONFIG_V2_LINKA 0x00
+#define ATOM_ENCODER_CONFIG_V2_LINKB 0x04
+#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER_SEL_MASK 0x18
+#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER1 0x00
+#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER2 0x08
+#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER3 0x10
+
+// ucAction:
+// ATOM_DISABLE
+// ATOM_ENABLE
+#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_START 0x08
+#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1 0x09
+#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2 0x0a
+#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3 0x13
+#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE 0x0b
+#define ATOM_ENCODER_CMD_DP_VIDEO_OFF 0x0c
+#define ATOM_ENCODER_CMD_DP_VIDEO_ON 0x0d
+#define ATOM_ENCODER_CMD_QUERY_DP_LINK_TRAINING_STATUS 0x0e
+#define ATOM_ENCODER_CMD_SETUP 0x0f
+#define ATOM_ENCODER_CMD_SETUP_PANEL_MODE 0x10
+
+// ucStatus
+#define ATOM_ENCODER_STATUS_LINK_TRAINING_COMPLETE 0x10
+#define ATOM_ENCODER_STATUS_LINK_TRAINING_INCOMPLETE 0x00
+
+//ucTableFormatRevision=1
+//ucTableContentRevision=3
+// Following function ENABLE sub-function will be used by driver when TMDS/HDMI/LVDS is used, disable function will be used by driver
+typedef struct _ATOM_DIG_ENCODER_CONFIG_V3
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucReserved1:1;
+ UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also referred as DIGA/B/C/D/E/F)
+ UCHAR ucReserved:3;
+ UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz
+#else
+ UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz
+ UCHAR ucReserved:3;
+ UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also referred as DIGA/B/C/D/E/F)
+ UCHAR ucReserved1:1;
+#endif
+}ATOM_DIG_ENCODER_CONFIG_V3;
+
+#define ATOM_ENCODER_CONFIG_V3_DPLINKRATE_MASK 0x03
+#define ATOM_ENCODER_CONFIG_V3_DPLINKRATE_1_62GHZ 0x00
+#define ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ 0x01
+#define ATOM_ENCODER_CONFIG_V3_ENCODER_SEL 0x70
+#define ATOM_ENCODER_CONFIG_V3_DIG0_ENCODER 0x00
+#define ATOM_ENCODER_CONFIG_V3_DIG1_ENCODER 0x10
+#define ATOM_ENCODER_CONFIG_V3_DIG2_ENCODER 0x20
+#define ATOM_ENCODER_CONFIG_V3_DIG3_ENCODER 0x30
+#define ATOM_ENCODER_CONFIG_V3_DIG4_ENCODER 0x40
+#define ATOM_ENCODER_CONFIG_V3_DIG5_ENCODER 0x50
+
+typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V3
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ ATOM_DIG_ENCODER_CONFIG_V3 acConfig;
+ UCHAR ucAction;
+ union{
+ UCHAR ucEncoderMode;
+ // =0: DP encoder
+ // =1: LVDS encoder
+ // =2: DVI encoder
+ // =3: HDMI encoder
+ // =4: SDVO encoder
+ // =5: DP audio
+ UCHAR ucPanelMode; // only valid when ucAction == ATOM_ENCODER_CMD_SETUP_PANEL_MODE
+ // =0: external DP
+ // =0x1: internal DP2
+ // =0x11: internal DP1 for NutMeg/Travis DP translator
+ };
+ UCHAR ucLaneNum; // how many lanes to enable
+ UCHAR ucBitPerColor; // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP
+ UCHAR ucReserved;
+}DIG_ENCODER_CONTROL_PARAMETERS_V3;
+
+//ucTableFormatRevision=1
+//ucTableContentRevision=4
+// start from NI
+// Following function ENABLE sub-function will be used by driver when TMDS/HDMI/LVDS is used, disable function will be used by driver
+typedef struct _ATOM_DIG_ENCODER_CONFIG_V4
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucReserved1:1;
+ UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also referred as DIGA/B/C/D/E/F)
+ UCHAR ucReserved:2;
+ UCHAR ucDPLinkRate:2; // =0: 1.62Ghz, =1: 2.7Ghz, 2=5.4Ghz <= Changed comparing to previous version
+#else
+ UCHAR ucDPLinkRate:2; // =0: 1.62Ghz, =1: 2.7Ghz, 2=5.4Ghz <= Changed comparing to previous version
+ UCHAR ucReserved:2;
+ UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also referred as DIGA/B/C/D/E/F)
+ UCHAR ucReserved1:1;
+#endif
+}ATOM_DIG_ENCODER_CONFIG_V4;
+
+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_MASK 0x03
+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ 0x00
+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ 0x01
+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ 0x02
+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_3_24GHZ 0x03
+#define ATOM_ENCODER_CONFIG_V4_ENCODER_SEL 0x70
+#define ATOM_ENCODER_CONFIG_V4_DIG0_ENCODER 0x00
+#define ATOM_ENCODER_CONFIG_V4_DIG1_ENCODER 0x10
+#define ATOM_ENCODER_CONFIG_V4_DIG2_ENCODER 0x20
+#define ATOM_ENCODER_CONFIG_V4_DIG3_ENCODER 0x30
+#define ATOM_ENCODER_CONFIG_V4_DIG4_ENCODER 0x40
+#define ATOM_ENCODER_CONFIG_V4_DIG5_ENCODER 0x50
+#define ATOM_ENCODER_CONFIG_V4_DIG6_ENCODER 0x60
+
+typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V4
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ union{
+ ATOM_DIG_ENCODER_CONFIG_V4 acConfig;
+ UCHAR ucConfig;
+ };
+ UCHAR ucAction;
+ union{
+ UCHAR ucEncoderMode;
+ // =0: DP encoder
+ // =1: LVDS encoder
+ // =2: DVI encoder
+ // =3: HDMI encoder
+ // =4: SDVO encoder
+ // =5: DP audio
+ UCHAR ucPanelMode; // only valid when ucAction == ATOM_ENCODER_CMD_SETUP_PANEL_MODE
+ // =0: external DP
+ // =0x1: internal DP2
+ // =0x11: internal DP1 for NutMeg/Travis DP translator
+ };
+ UCHAR ucLaneNum; // how many lanes to enable
+ UCHAR ucBitPerColor; // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP
+ UCHAR ucHPD_ID; // HPD ID (1-6). =0 means to skip HDP programming. New comparing to previous version
+}DIG_ENCODER_CONTROL_PARAMETERS_V4;
+
+// define ucBitPerColor:
+#define PANEL_BPC_UNDEFINE 0x00
+#define PANEL_6BIT_PER_COLOR 0x01
+#define PANEL_8BIT_PER_COLOR 0x02
+#define PANEL_10BIT_PER_COLOR 0x03
+#define PANEL_12BIT_PER_COLOR 0x04
+#define PANEL_16BIT_PER_COLOR 0x05
+
+//define ucPanelMode
+#define DP_PANEL_MODE_EXTERNAL_DP_MODE 0x00
+#define DP_PANEL_MODE_INTERNAL_DP2_MODE 0x01
+#define DP_PANEL_MODE_INTERNAL_DP1_MODE 0x11
+
+/****************************************************************************/
+// Structures used by UNIPHYTransmitterControlTable
+// LVTMATransmitterControlTable
+// DVOOutputControlTable
+/****************************************************************************/
+typedef struct _ATOM_DP_VS_MODE
+{
+ UCHAR ucLaneSel;
+ UCHAR ucLaneSet;
+}ATOM_DP_VS_MODE;
+
+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS
+{
+ union
+ {
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h
+ ATOM_DP_VS_MODE asMode; // DP Voltage swing mode
+ };
+ UCHAR ucConfig;
+ // [0]=0: 4 lane Link,
+ // =1: 8 lane Link ( Dual Links TMDS )
+ // [1]=0: InCoherent mode
+ // =1: Coherent Mode
+ // [2] Link Select:
+ // =0: PHY linkA if bfLane<3
+ // =1: PHY linkB if bfLanes<3
+ // =0: PHY linkA+B if bfLanes=3
+ // [5:4]PCIE lane Sel
+ // =0: lane 0~3 or 0~7
+ // =1: lane 4~7
+ // =2: lane 8~11 or 8~15
+ // =3: lane 12~15
+ UCHAR ucAction; // =0: turn off encoder
+ // =1: turn on encoder
+ UCHAR ucReserved[4];
+}DIG_TRANSMITTER_CONTROL_PARAMETERS;
+
+#define DIG_TRANSMITTER_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PARAMETERS
+
+//ucInitInfo
+#define ATOM_TRAMITTER_INITINFO_CONNECTOR_MASK 0x00ff
+
+//ucConfig
+#define ATOM_TRANSMITTER_CONFIG_8LANE_LINK 0x01
+#define ATOM_TRANSMITTER_CONFIG_COHERENT 0x02
+#define ATOM_TRANSMITTER_CONFIG_LINK_SEL_MASK 0x04
+#define ATOM_TRANSMITTER_CONFIG_LINKA 0x00
+#define ATOM_TRANSMITTER_CONFIG_LINKB 0x04
+#define ATOM_TRANSMITTER_CONFIG_LINKA_B 0x00
+#define ATOM_TRANSMITTER_CONFIG_LINKB_A 0x04
+
+#define ATOM_TRANSMITTER_CONFIG_ENCODER_SEL_MASK 0x08 // only used when ATOM_TRANSMITTER_ACTION_ENABLE
+#define ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER 0x00 // only used when ATOM_TRANSMITTER_ACTION_ENABLE
+#define ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER 0x08 // only used when ATOM_TRANSMITTER_ACTION_ENABLE
+
+#define ATOM_TRANSMITTER_CONFIG_CLKSRC_MASK 0x30
+#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL 0x00
+#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PCIE 0x20
+#define ATOM_TRANSMITTER_CONFIG_CLKSRC_XTALIN 0x30
+#define ATOM_TRANSMITTER_CONFIG_LANE_SEL_MASK 0xc0
+#define ATOM_TRANSMITTER_CONFIG_LANE_0_3 0x00
+#define ATOM_TRANSMITTER_CONFIG_LANE_0_7 0x00
+#define ATOM_TRANSMITTER_CONFIG_LANE_4_7 0x40
+#define ATOM_TRANSMITTER_CONFIG_LANE_8_11 0x80
+#define ATOM_TRANSMITTER_CONFIG_LANE_8_15 0x80
+#define ATOM_TRANSMITTER_CONFIG_LANE_12_15 0xc0
+
+//ucAction
+#define ATOM_TRANSMITTER_ACTION_DISABLE 0
+#define ATOM_TRANSMITTER_ACTION_ENABLE 1
+#define ATOM_TRANSMITTER_ACTION_LCD_BLOFF 2
+#define ATOM_TRANSMITTER_ACTION_LCD_BLON 3
+#define ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL 4
+#define ATOM_TRANSMITTER_ACTION_LCD_SELFTEST_START 5
+#define ATOM_TRANSMITTER_ACTION_LCD_SELFTEST_STOP 6
+#define ATOM_TRANSMITTER_ACTION_INIT 7
+#define ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT 8
+#define ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT 9
+#define ATOM_TRANSMITTER_ACTION_SETUP 10
+#define ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH 11
+#define ATOM_TRANSMITTER_ACTION_POWER_ON 12
+#define ATOM_TRANSMITTER_ACTION_POWER_OFF 13
+
+// Following are used for DigTransmitterControlTable ver1.2
+typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V2
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB )
+ // =1 Dig Transmitter 2 ( Uniphy CD )
+ // =2 Dig Transmitter 3 ( Uniphy EF )
+ UCHAR ucReserved:1;
+ UCHAR fDPConnector:1; //bit4=0: DP connector =1: None DP connector
+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 )
+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E
+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F
+
+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode )
+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector
+#else
+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector
+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode )
+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E
+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F
+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 )
+ UCHAR fDPConnector:1; //bit4=0: DP connector =1: None DP connector
+ UCHAR ucReserved:1;
+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB )
+ // =1 Dig Transmitter 2 ( Uniphy CD )
+ // =2 Dig Transmitter 3 ( Uniphy EF )
+#endif
+}ATOM_DIG_TRANSMITTER_CONFIG_V2;
+
+//ucConfig
+//Bit0
+#define ATOM_TRANSMITTER_CONFIG_V2_DUAL_LINK_CONNECTOR 0x01
+
+//Bit1
+#define ATOM_TRANSMITTER_CONFIG_V2_COHERENT 0x02
+
+//Bit2
+#define ATOM_TRANSMITTER_CONFIG_V2_LINK_SEL_MASK 0x04
+#define ATOM_TRANSMITTER_CONFIG_V2_LINKA 0x00
+#define ATOM_TRANSMITTER_CONFIG_V2_LINKB 0x04
+
+// Bit3
+#define ATOM_TRANSMITTER_CONFIG_V2_ENCODER_SEL_MASK 0x08
+#define ATOM_TRANSMITTER_CONFIG_V2_DIG1_ENCODER 0x00 // only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP
+#define ATOM_TRANSMITTER_CONFIG_V2_DIG2_ENCODER 0x08 // only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP
+
+// Bit4
+#define ATOM_TRASMITTER_CONFIG_V2_DP_CONNECTOR 0x10
+
+// Bit7:6
+#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER_SEL_MASK 0xC0
+#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER1 0x00 //AB
+#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER2 0x40 //CD
+#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER3 0x80 //EF
+
+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V2
+{
+ union
+ {
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h
+ ATOM_DP_VS_MODE asMode; // DP Voltage swing mode
+ };
+ ATOM_DIG_TRANSMITTER_CONFIG_V2 acConfig;
+ UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_XXX
+ UCHAR ucReserved[4];
+}DIG_TRANSMITTER_CONTROL_PARAMETERS_V2;
+
+typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V3
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB )
+ // =1 Dig Transmitter 2 ( Uniphy CD )
+ // =2 Dig Transmitter 3 ( Uniphy EF )
+ UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, EXT_CLK=2
+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F
+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E
+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F
+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode )
+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector
+#else
+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector
+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode )
+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E
+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F
+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F
+ UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, EXT_CLK=2
+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB )
+ // =1 Dig Transmitter 2 ( Uniphy CD )
+ // =2 Dig Transmitter 3 ( Uniphy EF )
+#endif
+}ATOM_DIG_TRANSMITTER_CONFIG_V3;
+
+
+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V3
+{
+ union
+ {
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h
+ ATOM_DP_VS_MODE asMode; // DP Voltage swing mode
+ };
+ ATOM_DIG_TRANSMITTER_CONFIG_V3 acConfig;
+ UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_XXX
+ UCHAR ucLaneNum;
+ UCHAR ucReserved[3];
+}DIG_TRANSMITTER_CONTROL_PARAMETERS_V3;
+
+//ucConfig
+//Bit0
+#define ATOM_TRANSMITTER_CONFIG_V3_DUAL_LINK_CONNECTOR 0x01
+
+//Bit1
+#define ATOM_TRANSMITTER_CONFIG_V3_COHERENT 0x02
+
+//Bit2
+#define ATOM_TRANSMITTER_CONFIG_V3_LINK_SEL_MASK 0x04
+#define ATOM_TRANSMITTER_CONFIG_V3_LINKA 0x00
+#define ATOM_TRANSMITTER_CONFIG_V3_LINKB 0x04
+
+// Bit3
+#define ATOM_TRANSMITTER_CONFIG_V3_ENCODER_SEL_MASK 0x08
+#define ATOM_TRANSMITTER_CONFIG_V3_DIG1_ENCODER 0x00
+#define ATOM_TRANSMITTER_CONFIG_V3_DIG2_ENCODER 0x08
+
+// Bit5:4
+#define ATOM_TRASMITTER_CONFIG_V3_REFCLK_SEL_MASK 0x30
+#define ATOM_TRASMITTER_CONFIG_V3_P1PLL 0x00
+#define ATOM_TRASMITTER_CONFIG_V3_P2PLL 0x10
+#define ATOM_TRASMITTER_CONFIG_V3_REFCLK_SRC_EXT 0x20
+
+// Bit7:6
+#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER_SEL_MASK 0xC0
+#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER1 0x00 //AB
+#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER2 0x40 //CD
+#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER3 0x80 //EF
+
+
+/****************************************************************************/
+// Structures used by UNIPHYTransmitterControlTable V1.4
+// ASIC Families: NI
+// ucTableFormatRevision=1
+// ucTableContentRevision=4
+/****************************************************************************/
+typedef struct _ATOM_DP_VS_MODE_V4
+{
+ UCHAR ucLaneSel;
+ union
+ {
+ UCHAR ucLaneSet;
+ struct {
+#if ATOM_BIG_ENDIAN
+ UCHAR ucPOST_CURSOR2:2; //Bit[7:6] Post Cursor2 Level <= New in V4
+ UCHAR ucPRE_EMPHASIS:3; //Bit[5:3] Pre-emphasis Level
+ UCHAR ucVOLTAGE_SWING:3; //Bit[2:0] Voltage Swing Level
+#else
+ UCHAR ucVOLTAGE_SWING:3; //Bit[2:0] Voltage Swing Level
+ UCHAR ucPRE_EMPHASIS:3; //Bit[5:3] Pre-emphasis Level
+ UCHAR ucPOST_CURSOR2:2; //Bit[7:6] Post Cursor2 Level <= New in V4
+#endif
+ };
+ };
+}ATOM_DP_VS_MODE_V4;
+
+typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V4
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB )
+ // =1 Dig Transmitter 2 ( Uniphy CD )
+ // =2 Dig Transmitter 3 ( Uniphy EF )
+ UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, DCPLL=2, EXT_CLK=3 <= New
+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F
+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E
+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F
+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode )
+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector
+#else
+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector
+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode )
+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E
+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F
+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F
+ UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, DCPLL=2, EXT_CLK=3 <= New
+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB )
+ // =1 Dig Transmitter 2 ( Uniphy CD )
+ // =2 Dig Transmitter 3 ( Uniphy EF )
+#endif
+}ATOM_DIG_TRANSMITTER_CONFIG_V4;
+
+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V4
+{
+ union
+ {
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h
+ ATOM_DP_VS_MODE_V4 asMode; // DP Voltage swing mode Redefined comparing to previous version
+ };
+ union
+ {
+ ATOM_DIG_TRANSMITTER_CONFIG_V4 acConfig;
+ UCHAR ucConfig;
+ };
+ UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_XXX
+ UCHAR ucLaneNum;
+ UCHAR ucReserved[3];
+}DIG_TRANSMITTER_CONTROL_PARAMETERS_V4;
+
+//ucConfig
+//Bit0
+#define ATOM_TRANSMITTER_CONFIG_V4_DUAL_LINK_CONNECTOR 0x01
+//Bit1
+#define ATOM_TRANSMITTER_CONFIG_V4_COHERENT 0x02
+//Bit2
+#define ATOM_TRANSMITTER_CONFIG_V4_LINK_SEL_MASK 0x04
+#define ATOM_TRANSMITTER_CONFIG_V4_LINKA 0x00
+#define ATOM_TRANSMITTER_CONFIG_V4_LINKB 0x04
+// Bit3
+#define ATOM_TRANSMITTER_CONFIG_V4_ENCODER_SEL_MASK 0x08
+#define ATOM_TRANSMITTER_CONFIG_V4_DIG1_ENCODER 0x00
+#define ATOM_TRANSMITTER_CONFIG_V4_DIG2_ENCODER 0x08
+// Bit5:4
+#define ATOM_TRANSMITTER_CONFIG_V4_REFCLK_SEL_MASK 0x30
+#define ATOM_TRANSMITTER_CONFIG_V4_P1PLL 0x00
+#define ATOM_TRANSMITTER_CONFIG_V4_P2PLL 0x10
+#define ATOM_TRANSMITTER_CONFIG_V4_DCPLL 0x20 // New in _V4
+#define ATOM_TRANSMITTER_CONFIG_V4_REFCLK_SRC_EXT 0x30 // Changed comparing to V3
+// Bit7:6
+#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER_SEL_MASK 0xC0
+#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER1 0x00 //AB
+#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER2 0x40 //CD
+#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER3 0x80 //EF
+
+
+typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V5
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucReservd1:1;
+ UCHAR ucHPDSel:3;
+ UCHAR ucPhyClkSrcId:2;
+ UCHAR ucCoherentMode:1;
+ UCHAR ucReserved:1;
+#else
+ UCHAR ucReserved:1;
+ UCHAR ucCoherentMode:1;
+ UCHAR ucPhyClkSrcId:2;
+ UCHAR ucHPDSel:3;
+ UCHAR ucReservd1:1;
+#endif
+}ATOM_DIG_TRANSMITTER_CONFIG_V5;
+
+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5
+{
+ USHORT usSymClock; // Encoder Clock in 10kHz,(DP mode)= linkclock/10, (TMDS/LVDS/HDMI)= pixel clock, (HDMI deep color), =pixel clock * deep_color_ratio
+ UCHAR ucPhyId; // 0=UNIPHYA, 1=UNIPHYB, 2=UNIPHYC, 3=UNIPHYD, 4= UNIPHYE 5=UNIPHYF
+ UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_xxx
+ UCHAR ucLaneNum; // indicate lane number 1-8
+ UCHAR ucConnObjId; // Connector Object Id defined in ObjectId.h
+ UCHAR ucDigMode; // indicate DIG mode
+ union{
+ ATOM_DIG_TRANSMITTER_CONFIG_V5 asConfig;
+ UCHAR ucConfig;
+ };
+ UCHAR ucDigEncoderSel; // indicate DIG front end encoder
+ UCHAR ucDPLaneSet;
+ UCHAR ucReserved;
+ UCHAR ucReserved1;
+}DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5;
+
+//ucPhyId
+#define ATOM_PHY_ID_UNIPHYA 0
+#define ATOM_PHY_ID_UNIPHYB 1
+#define ATOM_PHY_ID_UNIPHYC 2
+#define ATOM_PHY_ID_UNIPHYD 3
+#define ATOM_PHY_ID_UNIPHYE 4
+#define ATOM_PHY_ID_UNIPHYF 5
+#define ATOM_PHY_ID_UNIPHYG 6
+
+// ucDigEncoderSel
+#define ATOM_TRANMSITTER_V5__DIGA_SEL 0x01
+#define ATOM_TRANMSITTER_V5__DIGB_SEL 0x02
+#define ATOM_TRANMSITTER_V5__DIGC_SEL 0x04
+#define ATOM_TRANMSITTER_V5__DIGD_SEL 0x08
+#define ATOM_TRANMSITTER_V5__DIGE_SEL 0x10
+#define ATOM_TRANMSITTER_V5__DIGF_SEL 0x20
+#define ATOM_TRANMSITTER_V5__DIGG_SEL 0x40
+
+// ucDigMode
+#define ATOM_TRANSMITTER_DIGMODE_V5_DP 0
+#define ATOM_TRANSMITTER_DIGMODE_V5_LVDS 1
+#define ATOM_TRANSMITTER_DIGMODE_V5_DVI 2
+#define ATOM_TRANSMITTER_DIGMODE_V5_HDMI 3
+#define ATOM_TRANSMITTER_DIGMODE_V5_SDVO 4
+#define ATOM_TRANSMITTER_DIGMODE_V5_DP_MST 5
+
+// ucDPLaneSet
+#define DP_LANE_SET__0DB_0_4V 0x00
+#define DP_LANE_SET__0DB_0_6V 0x01
+#define DP_LANE_SET__0DB_0_8V 0x02
+#define DP_LANE_SET__0DB_1_2V 0x03
+#define DP_LANE_SET__3_5DB_0_4V 0x08
+#define DP_LANE_SET__3_5DB_0_6V 0x09
+#define DP_LANE_SET__3_5DB_0_8V 0x0a
+#define DP_LANE_SET__6DB_0_4V 0x10
+#define DP_LANE_SET__6DB_0_6V 0x11
+#define DP_LANE_SET__9_5DB_0_4V 0x18
+
+// ATOM_DIG_TRANSMITTER_CONFIG_V5 asConfig;
+// Bit1
+#define ATOM_TRANSMITTER_CONFIG_V5_COHERENT 0x02
+
+// Bit3:2
+#define ATOM_TRANSMITTER_CONFIG_V5_REFCLK_SEL_MASK 0x0c
+#define ATOM_TRANSMITTER_CONFIG_V5_REFCLK_SEL_SHIFT 0x02
+
+#define ATOM_TRANSMITTER_CONFIG_V5_P1PLL 0x00
+#define ATOM_TRANSMITTER_CONFIG_V5_P2PLL 0x04
+#define ATOM_TRANSMITTER_CONFIG_V5_P0PLL 0x08
+#define ATOM_TRANSMITTER_CONFIG_V5_REFCLK_SRC_EXT 0x0c
+// Bit6:4
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD_SEL_MASK 0x70
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD_SEL_SHIFT 0x04
+
+#define ATOM_TRANSMITTER_CONFIG_V5_NO_HPD_SEL 0x00
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD1_SEL 0x10
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD2_SEL 0x20
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD3_SEL 0x30
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD4_SEL 0x40
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD5_SEL 0x50
+#define ATOM_TRANSMITTER_CONFIG_V5_HPD6_SEL 0x60
+
+#define DIG_TRANSMITTER_CONTROL_PS_ALLOCATION_V1_5 DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5
+
+
+/****************************************************************************/
+// Structures used by ExternalEncoderControlTable V1.3
+// ASIC Families: Evergreen, Llano, NI
+// ucTableFormatRevision=1
+// ucTableContentRevision=3
+/****************************************************************************/
+
+typedef struct _EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3
+{
+ union{
+ USHORT usPixelClock; // pixel clock in 10Khz, valid when ucAction=SETUP/ENABLE_OUTPUT
+ USHORT usConnectorId; // connector id, valid when ucAction = INIT
+ };
+ UCHAR ucConfig; // indicate which encoder, and DP link rate when ucAction = SETUP/ENABLE_OUTPUT
+ UCHAR ucAction; //
+ UCHAR ucEncoderMode; // encoder mode, only used when ucAction = SETUP/ENABLE_OUTPUT
+ UCHAR ucLaneNum; // lane number, only used when ucAction = SETUP/ENABLE_OUTPUT
+ UCHAR ucBitPerColor; // output bit per color, only valid when ucAction = SETUP/ENABLE_OUTPUT and ucEncodeMode= DP
+ UCHAR ucReserved;
+}EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3;
+
+// ucAction
+#define EXTERANL_ENCODER_ACTION_V3_DISABLE_OUTPUT 0x00
+#define EXTERANL_ENCODER_ACTION_V3_ENABLE_OUTPUT 0x01
+#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT 0x07
+#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP 0x0f
+#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF 0x10
+#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING 0x11
+#define EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION 0x12
+#define EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP 0x14
+
+// ucConfig
+#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_MASK 0x03
+#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_1_62GHZ 0x00
+#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ 0x01
+#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ 0x02
+#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER_SEL_MAKS 0x70
+#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER1 0x00
+#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER2 0x10
+#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER3 0x20
+
+typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3
+{
+ EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 sExtEncoder;
+ ULONG ulReserved[2];
+}EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3;
+
+
+/****************************************************************************/
+// Structures used by DAC1OuputControlTable
+// DAC2OuputControlTable
+// LVTMAOutputControlTable (Before DEC30)
+// TMDSAOutputControlTable (Before DEC30)
+/****************************************************************************/
+typedef struct _DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+{
+ UCHAR ucAction; // Possible input:ATOM_ENABLE||ATOMDISABLE
+ // When the display is LCD, in addition to above:
+ // ATOM_LCD_BLOFF|| ATOM_LCD_BLON ||ATOM_LCD_BL_BRIGHTNESS_CONTROL||ATOM_LCD_SELFTEST_START||
+ // ATOM_LCD_SELFTEST_STOP
+
+ UCHAR aucPadding[3]; // padding to DWORD aligned
+}DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS;
+
+#define DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+
+
+#define CRT1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define CRT1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define CRT2_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define CRT2_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define CV1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define CV1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define TV1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define TV1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define DFP1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define DFP1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define DFP2_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define DFP2_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define LCD1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define LCD1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define DVO_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define DVO_OUTPUT_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PS_ALLOCATION
+#define DVO_OUTPUT_CONTROL_PARAMETERS_V3 DIG_TRANSMITTER_CONTROL_PARAMETERS
+
+
+typedef struct _LVTMA_OUTPUT_CONTROL_PARAMETERS_V2
+{
+ // Possible value of ucAction
+ // ATOM_TRANSMITTER_ACTION_LCD_BLON
+ // ATOM_TRANSMITTER_ACTION_LCD_BLOFF
+ // ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL
+ // ATOM_TRANSMITTER_ACTION_POWER_ON
+ // ATOM_TRANSMITTER_ACTION_POWER_OFF
+ UCHAR ucAction;
+ UCHAR ucBriLevel;
+ USHORT usPwmFreq; // in unit of Hz, 200 means 200Hz
+}LVTMA_OUTPUT_CONTROL_PARAMETERS_V2;
+
+
+
+/****************************************************************************/
+// Structures used by BlankCRTCTable
+/****************************************************************************/
+typedef struct _BLANK_CRTC_PARAMETERS
+{
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucBlanking; // ATOM_BLANKING or ATOM_BLANKINGOFF
+ USHORT usBlackColorRCr;
+ USHORT usBlackColorGY;
+ USHORT usBlackColorBCb;
+}BLANK_CRTC_PARAMETERS;
+#define BLANK_CRTC_PS_ALLOCATION BLANK_CRTC_PARAMETERS
+
+/****************************************************************************/
+// Structures used by EnableCRTCTable
+// EnableCRTCMemReqTable
+// UpdateCRTC_DoubleBufferRegistersTable
+/****************************************************************************/
+typedef struct _ENABLE_CRTC_PARAMETERS
+{
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucPadding[2];
+}ENABLE_CRTC_PARAMETERS;
+#define ENABLE_CRTC_PS_ALLOCATION ENABLE_CRTC_PARAMETERS
+
+/****************************************************************************/
+// Structures used by SetCRTC_OverScanTable
+/****************************************************************************/
+typedef struct _SET_CRTC_OVERSCAN_PARAMETERS
+{
+ USHORT usOverscanRight; // right
+ USHORT usOverscanLeft; // left
+ USHORT usOverscanBottom; // bottom
+ USHORT usOverscanTop; // top
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucPadding[3];
+}SET_CRTC_OVERSCAN_PARAMETERS;
+#define SET_CRTC_OVERSCAN_PS_ALLOCATION SET_CRTC_OVERSCAN_PARAMETERS
+
+/****************************************************************************/
+// Structures used by SetCRTC_ReplicationTable
+/****************************************************************************/
+typedef struct _SET_CRTC_REPLICATION_PARAMETERS
+{
+ UCHAR ucH_Replication; // horizontal replication
+ UCHAR ucV_Replication; // vertical replication
+ UCHAR usCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucPadding;
+}SET_CRTC_REPLICATION_PARAMETERS;
+#define SET_CRTC_REPLICATION_PS_ALLOCATION SET_CRTC_REPLICATION_PARAMETERS
+
+/****************************************************************************/
+// Structures used by SelectCRTC_SourceTable
+/****************************************************************************/
+typedef struct _SELECT_CRTC_SOURCE_PARAMETERS
+{
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucDevice; // ATOM_DEVICE_CRT1|ATOM_DEVICE_CRT2|....
+ UCHAR ucPadding[2];
+}SELECT_CRTC_SOURCE_PARAMETERS;
+#define SELECT_CRTC_SOURCE_PS_ALLOCATION SELECT_CRTC_SOURCE_PARAMETERS
+
+typedef struct _SELECT_CRTC_SOURCE_PARAMETERS_V2
+{
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucEncoderID; // DAC1/DAC2/TVOUT/DIG1/DIG2/DVO
+ UCHAR ucEncodeMode; // Encoding mode, only valid when using DIG1/DIG2/DVO
+ UCHAR ucPadding;
+}SELECT_CRTC_SOURCE_PARAMETERS_V2;
+
+//ucEncoderID
+//#define ASIC_INT_DAC1_ENCODER_ID 0x00
+//#define ASIC_INT_TV_ENCODER_ID 0x02
+//#define ASIC_INT_DIG1_ENCODER_ID 0x03
+//#define ASIC_INT_DAC2_ENCODER_ID 0x04
+//#define ASIC_EXT_TV_ENCODER_ID 0x06
+//#define ASIC_INT_DVO_ENCODER_ID 0x07
+//#define ASIC_INT_DIG2_ENCODER_ID 0x09
+//#define ASIC_EXT_DIG_ENCODER_ID 0x05
+
+//ucEncodeMode
+//#define ATOM_ENCODER_MODE_DP 0
+//#define ATOM_ENCODER_MODE_LVDS 1
+//#define ATOM_ENCODER_MODE_DVI 2
+//#define ATOM_ENCODER_MODE_HDMI 3
+//#define ATOM_ENCODER_MODE_SDVO 4
+//#define ATOM_ENCODER_MODE_TV 13
+//#define ATOM_ENCODER_MODE_CV 14
+//#define ATOM_ENCODER_MODE_CRT 15
+
+
+typedef struct _SELECT_CRTC_SOURCE_PARAMETERS_V3
+{
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucEncoderID; // DAC1/DAC2/TVOUT/DIG1/DIG2/DVO
+ UCHAR ucEncodeMode; // Encoding mode, only valid when using DIG1/DIG2/DVO
+ UCHAR ucDstBpc; // PANEL_6/8/10/12BIT_PER_COLOR
+}SELECT_CRTC_SOURCE_PARAMETERS_V3;
+
+
+/****************************************************************************/
+// Structures used by SetPixelClockTable
+// GetPixelClockTable
+/****************************************************************************/
+//Major revision=1., Minor revision=1
+typedef struct _PIXEL_CLOCK_PARAMETERS
+{
+ USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div)
+ // 0 means disable PPLL
+ USHORT usRefDiv; // Reference divider
+ USHORT usFbDiv; // feedback divider
+ UCHAR ucPostDiv; // post divider
+ UCHAR ucFracFbDiv; // fractional feedback divider
+ UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2
+ UCHAR ucRefDivSrc; // ATOM_PJITTER or ATO_NONPJITTER
+ UCHAR ucCRTC; // Which CRTC uses this Ppll
+ UCHAR ucPadding;
+}PIXEL_CLOCK_PARAMETERS;
+
+//Major revision=1., Minor revision=2, add ucMiscIfno
+//ucMiscInfo:
+#define MISC_FORCE_REPROG_PIXEL_CLOCK 0x1
+#define MISC_DEVICE_INDEX_MASK 0xF0
+#define MISC_DEVICE_INDEX_SHIFT 4
+
+typedef struct _PIXEL_CLOCK_PARAMETERS_V2
+{
+ USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div)
+ // 0 means disable PPLL
+ USHORT usRefDiv; // Reference divider
+ USHORT usFbDiv; // feedback divider
+ UCHAR ucPostDiv; // post divider
+ UCHAR ucFracFbDiv; // fractional feedback divider
+ UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2
+ UCHAR ucRefDivSrc; // ATOM_PJITTER or ATO_NONPJITTER
+ UCHAR ucCRTC; // Which CRTC uses this Ppll
+ UCHAR ucMiscInfo; // Different bits for different purpose, bit [7:4] as device index, bit[0]=Force prog
+}PIXEL_CLOCK_PARAMETERS_V2;
+
+//Major revision=1., Minor revision=3, structure/definition change
+//ucEncoderMode:
+//ATOM_ENCODER_MODE_DP
+//ATOM_ENOCDER_MODE_LVDS
+//ATOM_ENOCDER_MODE_DVI
+//ATOM_ENOCDER_MODE_HDMI
+//ATOM_ENOCDER_MODE_SDVO
+//ATOM_ENCODER_MODE_TV 13
+//ATOM_ENCODER_MODE_CV 14
+//ATOM_ENCODER_MODE_CRT 15
+
+//ucDVOConfig
+//#define DVO_ENCODER_CONFIG_RATE_SEL 0x01
+//#define DVO_ENCODER_CONFIG_DDR_SPEED 0x00
+//#define DVO_ENCODER_CONFIG_SDR_SPEED 0x01
+//#define DVO_ENCODER_CONFIG_OUTPUT_SEL 0x0c
+//#define DVO_ENCODER_CONFIG_LOW12BIT 0x00
+//#define DVO_ENCODER_CONFIG_UPPER12BIT 0x04
+//#define DVO_ENCODER_CONFIG_24BIT 0x08
+
+//ucMiscInfo: also changed, see below
+#define PIXEL_CLOCK_MISC_FORCE_PROG_PPLL 0x01
+#define PIXEL_CLOCK_MISC_VGA_MODE 0x02
+#define PIXEL_CLOCK_MISC_CRTC_SEL_MASK 0x04
+#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1 0x00
+#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2 0x04
+#define PIXEL_CLOCK_MISC_USE_ENGINE_FOR_DISPCLK 0x08
+#define PIXEL_CLOCK_MISC_REF_DIV_SRC 0x10
+// V1.4 for RoadRunner
+#define PIXEL_CLOCK_V4_MISC_SS_ENABLE 0x10
+#define PIXEL_CLOCK_V4_MISC_COHERENT_MODE 0x20
+
+
+typedef struct _PIXEL_CLOCK_PARAMETERS_V3
+{
+ USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div)
+ // 0 means disable PPLL. For VGA PPLL,make sure this value is not 0.
+ USHORT usRefDiv; // Reference divider
+ USHORT usFbDiv; // feedback divider
+ UCHAR ucPostDiv; // post divider
+ UCHAR ucFracFbDiv; // fractional feedback divider
+ UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2
+ UCHAR ucTransmitterId; // graphic encoder id defined in objectId.h
+ union
+ {
+ UCHAR ucEncoderMode; // encoder type defined as ATOM_ENCODER_MODE_DP/DVI/HDMI/
+ UCHAR ucDVOConfig; // when use DVO, need to know SDR/DDR, 12bit or 24bit
+ };
+ UCHAR ucMiscInfo; // bit[0]=Force program, bit[1]= set pclk for VGA, b[2]= CRTC sel
+ // bit[3]=0:use PPLL for dispclk source, =1: use engine clock for dispclock source
+ // bit[4]=0:use XTALIN as the source of reference divider,=1 use the pre-defined clock as the source of reference divider
+}PIXEL_CLOCK_PARAMETERS_V3;
+
+#define PIXEL_CLOCK_PARAMETERS_LAST PIXEL_CLOCK_PARAMETERS_V2
+#define GET_PIXEL_CLOCK_PS_ALLOCATION PIXEL_CLOCK_PARAMETERS_LAST
+
+
+typedef struct _PIXEL_CLOCK_PARAMETERS_V5
+{
+ UCHAR ucCRTC; // ATOM_CRTC1~6, indicate the CRTC controller to
+ // drive the pixel clock. not used for DCPLL case.
+ union{
+ UCHAR ucReserved;
+ UCHAR ucFracFbDiv; // [gphan] temporary to prevent build problem. remove it after driver code is changed.
+ };
+ USHORT usPixelClock; // target the pixel clock to drive the CRTC timing
+ // 0 means disable PPLL/DCPLL.
+ USHORT usFbDiv; // feedback divider integer part.
+ UCHAR ucPostDiv; // post divider.
+ UCHAR ucRefDiv; // Reference divider
+ UCHAR ucPpll; // ATOM_PPLL1/ATOM_PPLL2/ATOM_DCPLL
+ UCHAR ucTransmitterID; // ASIC encoder id defined in objectId.h,
+ // indicate which graphic encoder will be used.
+ UCHAR ucEncoderMode; // Encoder mode:
+ UCHAR ucMiscInfo; // bit[0]= Force program PPLL
+ // bit[1]= when VGA timing is used.
+ // bit[3:2]= HDMI panel bit depth: =0: 24bpp =1:30bpp, =2:32bpp
+ // bit[4]= RefClock source for PPLL.
+ // =0: XTLAIN( default mode )
+ // =1: other external clock source, which is pre-defined
+ // by VBIOS depend on the feature required.
+ // bit[7:5]: reserved.
+ ULONG ulFbDivDecFrac; // 20 bit feedback divider decimal fraction part, range from 1~999999 ( 0.000001 to 0.999999 )
+
+}PIXEL_CLOCK_PARAMETERS_V5;
+
+#define PIXEL_CLOCK_V5_MISC_FORCE_PROG_PPLL 0x01
+#define PIXEL_CLOCK_V5_MISC_VGA_MODE 0x02
+#define PIXEL_CLOCK_V5_MISC_HDMI_BPP_MASK 0x0c
+#define PIXEL_CLOCK_V5_MISC_HDMI_24BPP 0x00
+#define PIXEL_CLOCK_V5_MISC_HDMI_30BPP 0x04
+#define PIXEL_CLOCK_V5_MISC_HDMI_32BPP 0x08
+#define PIXEL_CLOCK_V5_MISC_REF_DIV_SRC 0x10
+
+typedef struct _CRTC_PIXEL_CLOCK_FREQ
+{
+#if ATOM_BIG_ENDIAN
+ ULONG ucCRTC:8; // ATOM_CRTC1~6, indicate the CRTC controller to
+ // drive the pixel clock. not used for DCPLL case.
+ ULONG ulPixelClock:24; // target the pixel clock to drive the CRTC timing.
+ // 0 means disable PPLL/DCPLL. Expanded to 24 bits comparing to previous version.
+#else
+ ULONG ulPixelClock:24; // target the pixel clock to drive the CRTC timing.
+ // 0 means disable PPLL/DCPLL. Expanded to 24 bits comparing to previous version.
+ ULONG ucCRTC:8; // ATOM_CRTC1~6, indicate the CRTC controller to
+ // drive the pixel clock. not used for DCPLL case.
+#endif
+}CRTC_PIXEL_CLOCK_FREQ;
+
+typedef struct _PIXEL_CLOCK_PARAMETERS_V6
+{
+ union{
+ CRTC_PIXEL_CLOCK_FREQ ulCrtcPclkFreq; // pixel clock and CRTC id frequency
+ ULONG ulDispEngClkFreq; // dispclk frequency
+ };
+ USHORT usFbDiv; // feedback divider integer part.
+ UCHAR ucPostDiv; // post divider.
+ UCHAR ucRefDiv; // Reference divider
+ UCHAR ucPpll; // ATOM_PPLL1/ATOM_PPLL2/ATOM_DCPLL
+ UCHAR ucTransmitterID; // ASIC encoder id defined in objectId.h,
+ // indicate which graphic encoder will be used.
+ UCHAR ucEncoderMode; // Encoder mode:
+ UCHAR ucMiscInfo; // bit[0]= Force program PPLL
+ // bit[1]= when VGA timing is used.
+ // bit[3:2]= HDMI panel bit depth: =0: 24bpp =1:30bpp, =2:32bpp
+ // bit[4]= RefClock source for PPLL.
+ // =0: XTLAIN( default mode )
+ // =1: other external clock source, which is pre-defined
+ // by VBIOS depend on the feature required.
+ // bit[7:5]: reserved.
+ ULONG ulFbDivDecFrac; // 20 bit feedback divider decimal fraction part, range from 1~999999 ( 0.000001 to 0.999999 )
+
+}PIXEL_CLOCK_PARAMETERS_V6;
+
+#define PIXEL_CLOCK_V6_MISC_FORCE_PROG_PPLL 0x01
+#define PIXEL_CLOCK_V6_MISC_VGA_MODE 0x02
+#define PIXEL_CLOCK_V6_MISC_HDMI_BPP_MASK 0x0c
+#define PIXEL_CLOCK_V6_MISC_HDMI_24BPP 0x00
+#define PIXEL_CLOCK_V6_MISC_HDMI_36BPP 0x04
+#define PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6 0x08 //for V6, the correct defintion for 36bpp should be 2 for 36bpp(2:1)
+#define PIXEL_CLOCK_V6_MISC_HDMI_30BPP 0x08
+#define PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6 0x04 //for V6, the correct defintion for 30bpp should be 1 for 36bpp(5:4)
+#define PIXEL_CLOCK_V6_MISC_HDMI_48BPP 0x0c
+#define PIXEL_CLOCK_V6_MISC_REF_DIV_SRC 0x10
+#define PIXEL_CLOCK_V6_MISC_GEN_DPREFCLK 0x40
+#define PIXEL_CLOCK_V6_MISC_DPREFCLK_BYPASS 0x40
+
+typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2
+{
+ PIXEL_CLOCK_PARAMETERS_V3 sDispClkInput;
+}GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2;
+
+typedef struct _GET_DISP_PLL_STATUS_OUTPUT_PARAMETERS_V2
+{
+ UCHAR ucStatus;
+ UCHAR ucRefDivSrc; // =1: reference clock source from XTALIN, =0: source from PCIE ref clock
+ UCHAR ucReserved[2];
+}GET_DISP_PLL_STATUS_OUTPUT_PARAMETERS_V2;
+
+typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V3
+{
+ PIXEL_CLOCK_PARAMETERS_V5 sDispClkInput;
+}GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V3;
+
+
+/****************************************************************************/
+// Structures used by AdjustDisplayPllTable
+/****************************************************************************/
+typedef struct _ADJUST_DISPLAY_PLL_PARAMETERS
+{
+ USHORT usPixelClock;
+ UCHAR ucTransmitterID;
+ UCHAR ucEncodeMode;
+ union
+ {
+ UCHAR ucDVOConfig; //if DVO, need passing link rate and output 12bitlow or 24bit
+ UCHAR ucConfig; //if none DVO, not defined yet
+ };
+ UCHAR ucReserved[3];
+}ADJUST_DISPLAY_PLL_PARAMETERS;
+
+#define ADJUST_DISPLAY_CONFIG_SS_ENABLE 0x10
+#define ADJUST_DISPLAY_PLL_PS_ALLOCATION ADJUST_DISPLAY_PLL_PARAMETERS
+
+typedef struct _ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3
+{
+ USHORT usPixelClock; // target pixel clock
+ UCHAR ucTransmitterID; // GPU transmitter id defined in objectid.h
+ UCHAR ucEncodeMode; // encoder mode: CRT, LVDS, DP, TMDS or HDMI
+ UCHAR ucDispPllConfig; // display pll configure parameter defined as following DISPPLL_CONFIG_XXXX
+ UCHAR ucExtTransmitterID; // external encoder id.
+ UCHAR ucReserved[2];
+}ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3;
+
+// usDispPllConfig v1.2 for RoadRunner
+#define DISPPLL_CONFIG_DVO_RATE_SEL 0x0001 // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_DVO_DDR_SPEED 0x0000 // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_DVO_SDR_SPEED 0x0001 // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_DVO_OUTPUT_SEL 0x000c // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_DVO_LOW12BIT 0x0000 // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_DVO_UPPER12BIT 0x0004 // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_DVO_24BIT 0x0008 // need only when ucTransmitterID = DVO
+#define DISPPLL_CONFIG_SS_ENABLE 0x0010 // Only used when ucEncoderMode = DP or LVDS
+#define DISPPLL_CONFIG_COHERENT_MODE 0x0020 // Only used when ucEncoderMode = TMDS or HDMI
+#define DISPPLL_CONFIG_DUAL_LINK 0x0040 // Only used when ucEncoderMode = TMDS or LVDS
+
+
+typedef struct _ADJUST_DISPLAY_PLL_OUTPUT_PARAMETERS_V3
+{
+ ULONG ulDispPllFreq; // return display PPLL freq which is used to generate the pixclock, and related idclk, symclk etc
+ UCHAR ucRefDiv; // if it is none-zero, it is used to be calculated the other ppll parameter fb_divider and post_div ( if it is not given )
+ UCHAR ucPostDiv; // if it is none-zero, it is used to be calculated the other ppll parameter fb_divider
+ UCHAR ucReserved[2];
+}ADJUST_DISPLAY_PLL_OUTPUT_PARAMETERS_V3;
+
+typedef struct _ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3
+{
+ union
+ {
+ ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3 sInput;
+ ADJUST_DISPLAY_PLL_OUTPUT_PARAMETERS_V3 sOutput;
+ };
+} ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3;
+
+/****************************************************************************/
+// Structures used by EnableYUVTable
+/****************************************************************************/
+typedef struct _ENABLE_YUV_PARAMETERS
+{
+ UCHAR ucEnable; // ATOM_ENABLE:Enable YUV or ATOM_DISABLE:Disable YUV (RGB)
+ UCHAR ucCRTC; // Which CRTC needs this YUV or RGB format
+ UCHAR ucPadding[2];
+}ENABLE_YUV_PARAMETERS;
+#define ENABLE_YUV_PS_ALLOCATION ENABLE_YUV_PARAMETERS
+
+/****************************************************************************/
+// Structures used by GetMemoryClockTable
+/****************************************************************************/
+typedef struct _GET_MEMORY_CLOCK_PARAMETERS
+{
+ ULONG ulReturnMemoryClock; // current memory speed in 10KHz unit
+} GET_MEMORY_CLOCK_PARAMETERS;
+#define GET_MEMORY_CLOCK_PS_ALLOCATION GET_MEMORY_CLOCK_PARAMETERS
+
+/****************************************************************************/
+// Structures used by GetEngineClockTable
+/****************************************************************************/
+typedef struct _GET_ENGINE_CLOCK_PARAMETERS
+{
+ ULONG ulReturnEngineClock; // current engine speed in 10KHz unit
+} GET_ENGINE_CLOCK_PARAMETERS;
+#define GET_ENGINE_CLOCK_PS_ALLOCATION GET_ENGINE_CLOCK_PARAMETERS
+
+/****************************************************************************/
+// Following Structures and constant may be obsolete
+/****************************************************************************/
+//Maxium 8 bytes,the data read in will be placed in the parameter space.
+//Read operaion successeful when the paramter space is non-zero, otherwise read operation failed
+typedef struct _READ_EDID_FROM_HW_I2C_DATA_PARAMETERS
+{
+ USHORT usPrescale; //Ratio between Engine clock and I2C clock
+ USHORT usVRAMAddress; //Adress in Frame Buffer where to pace raw EDID
+ USHORT usStatus; //When use output: lower byte EDID checksum, high byte hardware status
+ //WHen use input: lower byte as 'byte to read':currently limited to 128byte or 1byte
+ UCHAR ucSlaveAddr; //Read from which slave
+ UCHAR ucLineNumber; //Read from which HW assisted line
+}READ_EDID_FROM_HW_I2C_DATA_PARAMETERS;
+#define READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION READ_EDID_FROM_HW_I2C_DATA_PARAMETERS
+
+
+#define ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSDATABYTE 0
+#define ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSTWODATABYTES 1
+#define ATOM_WRITE_I2C_FORMAT_PSCOUNTER_PSOFFSET_IDDATABLOCK 2
+#define ATOM_WRITE_I2C_FORMAT_PSCOUNTER_IDOFFSET_PLUS_IDDATABLOCK 3
+#define ATOM_WRITE_I2C_FORMAT_IDCOUNTER_IDOFFSET_IDDATABLOCK 4
+
+typedef struct _WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
+{
+ USHORT usPrescale; //Ratio between Engine clock and I2C clock
+ USHORT usByteOffset; //Write to which byte
+ //Upper portion of usByteOffset is Format of data
+ //1bytePS+offsetPS
+ //2bytesPS+offsetPS
+ //blockID+offsetPS
+ //blockID+offsetID
+ //blockID+counterID+offsetID
+ UCHAR ucData; //PS data1
+ UCHAR ucStatus; //Status byte 1=success, 2=failure, Also is used as PS data2
+ UCHAR ucSlaveAddr; //Write to which slave
+ UCHAR ucLineNumber; //Write from which HW assisted line
+}WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS;
+
+#define WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
+
+typedef struct _SET_UP_HW_I2C_DATA_PARAMETERS
+{
+ USHORT usPrescale; //Ratio between Engine clock and I2C clock
+ UCHAR ucSlaveAddr; //Write to which slave
+ UCHAR ucLineNumber; //Write from which HW assisted line
+}SET_UP_HW_I2C_DATA_PARAMETERS;
+
+/**************************************************************************/
+#define SPEED_FAN_CONTROL_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
+
+
+/****************************************************************************/
+// Structures used by PowerConnectorDetectionTable
+/****************************************************************************/
+typedef struct _POWER_CONNECTOR_DETECTION_PARAMETERS
+{
+ UCHAR ucPowerConnectorStatus; //Used for return value 0: detected, 1:not detected
+ UCHAR ucPwrBehaviorId;
+ USHORT usPwrBudget; //how much power currently boot to in unit of watt
+}POWER_CONNECTOR_DETECTION_PARAMETERS;
+
+typedef struct POWER_CONNECTOR_DETECTION_PS_ALLOCATION
+{
+ UCHAR ucPowerConnectorStatus; //Used for return value 0: detected, 1:not detected
+ UCHAR ucReserved;
+ USHORT usPwrBudget; //how much power currently boot to in unit of watt
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
+}POWER_CONNECTOR_DETECTION_PS_ALLOCATION;
+
+
+/****************************LVDS SS Command Table Definitions**********************/
+
+/****************************************************************************/
+// Structures used by EnableSpreadSpectrumOnPPLLTable
+/****************************************************************************/
+typedef struct _ENABLE_LVDS_SS_PARAMETERS
+{
+ USHORT usSpreadSpectrumPercentage;
+ UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD
+ UCHAR ucSpreadSpectrumStepSize_Delay; //bits3:2 SS_STEP_SIZE; bit 6:4 SS_DELAY
+ UCHAR ucEnable; //ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucPadding[3];
+}ENABLE_LVDS_SS_PARAMETERS;
+
+//ucTableFormatRevision=1,ucTableContentRevision=2
+typedef struct _ENABLE_LVDS_SS_PARAMETERS_V2
+{
+ USHORT usSpreadSpectrumPercentage;
+ UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD
+ UCHAR ucSpreadSpectrumStep; //
+ UCHAR ucEnable; //ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucSpreadSpectrumDelay;
+ UCHAR ucSpreadSpectrumRange;
+ UCHAR ucPadding;
+}ENABLE_LVDS_SS_PARAMETERS_V2;
+
+//This new structure is based on ENABLE_LVDS_SS_PARAMETERS but expands to SS on PPLL, so other devices can use SS.
+typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL
+{
+ USHORT usSpreadSpectrumPercentage;
+ UCHAR ucSpreadSpectrumType; // Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD
+ UCHAR ucSpreadSpectrumStep; //
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucSpreadSpectrumDelay;
+ UCHAR ucSpreadSpectrumRange;
+ UCHAR ucPpll; // ATOM_PPLL1/ATOM_PPLL2
+}ENABLE_SPREAD_SPECTRUM_ON_PPLL;
+
+ typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2
+{
+ USHORT usSpreadSpectrumPercentage;
+ UCHAR ucSpreadSpectrumType; // Bit[0]: 0-Down Spread,1-Center Spread.
+ // Bit[1]: 1-Ext. 0-Int.
+ // Bit[3:2]: =0 P1PLL =1 P2PLL =2 DCPLL
+ // Bits[7:4] reserved
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ USHORT usSpreadSpectrumAmount; // Includes SS_AMOUNT_FBDIV[7:0] and SS_AMOUNT_NFRAC_SLIP[11:8]
+ USHORT usSpreadSpectrumStep; // SS_STEP_SIZE_DSFRAC
+}ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2;
+
+#define ATOM_PPLL_SS_TYPE_V2_DOWN_SPREAD 0x00
+#define ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD 0x01
+#define ATOM_PPLL_SS_TYPE_V2_EXT_SPREAD 0x02
+#define ATOM_PPLL_SS_TYPE_V2_PPLL_SEL_MASK 0x0c
+#define ATOM_PPLL_SS_TYPE_V2_P1PLL 0x00
+#define ATOM_PPLL_SS_TYPE_V2_P2PLL 0x04
+#define ATOM_PPLL_SS_TYPE_V2_DCPLL 0x08
+#define ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK 0x00FF
+#define ATOM_PPLL_SS_AMOUNT_V2_FBDIV_SHIFT 0
+#define ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK 0x0F00
+#define ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT 8
+
+// Used by DCE5.0
+ typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3
+{
+ USHORT usSpreadSpectrumAmountFrac; // SS_AMOUNT_DSFRAC New in DCE5.0
+ UCHAR ucSpreadSpectrumType; // Bit[0]: 0-Down Spread,1-Center Spread.
+ // Bit[1]: 1-Ext. 0-Int.
+ // Bit[3:2]: =0 P1PLL =1 P2PLL =2 DCPLL
+ // Bits[7:4] reserved
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ USHORT usSpreadSpectrumAmount; // Includes SS_AMOUNT_FBDIV[7:0] and SS_AMOUNT_NFRAC_SLIP[11:8]
+ USHORT usSpreadSpectrumStep; // SS_STEP_SIZE_DSFRAC
+}ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3;
+
+
+#define ATOM_PPLL_SS_TYPE_V3_DOWN_SPREAD 0x00
+#define ATOM_PPLL_SS_TYPE_V3_CENTRE_SPREAD 0x01
+#define ATOM_PPLL_SS_TYPE_V3_EXT_SPREAD 0x02
+#define ATOM_PPLL_SS_TYPE_V3_PPLL_SEL_MASK 0x0c
+#define ATOM_PPLL_SS_TYPE_V3_P1PLL 0x00
+#define ATOM_PPLL_SS_TYPE_V3_P2PLL 0x04
+#define ATOM_PPLL_SS_TYPE_V3_DCPLL 0x08
+#define ATOM_PPLL_SS_TYPE_V3_P0PLL ATOM_PPLL_SS_TYPE_V3_DCPLL
+#define ATOM_PPLL_SS_AMOUNT_V3_FBDIV_MASK 0x00FF
+#define ATOM_PPLL_SS_AMOUNT_V3_FBDIV_SHIFT 0
+#define ATOM_PPLL_SS_AMOUNT_V3_NFRAC_MASK 0x0F00
+#define ATOM_PPLL_SS_AMOUNT_V3_NFRAC_SHIFT 8
+
+#define ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION ENABLE_SPREAD_SPECTRUM_ON_PPLL
+
+typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION
+{
+ PIXEL_CLOCK_PARAMETERS sPCLKInput;
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved;//Caller doesn't need to init this portion
+}SET_PIXEL_CLOCK_PS_ALLOCATION;
+
+
+
+#define ENABLE_VGA_RENDER_PS_ALLOCATION SET_PIXEL_CLOCK_PS_ALLOCATION
+
+/****************************************************************************/
+// Structures used by ###
+/****************************************************************************/
+typedef struct _MEMORY_TRAINING_PARAMETERS
+{
+ ULONG ulTargetMemoryClock; //In 10Khz unit
+}MEMORY_TRAINING_PARAMETERS;
+#define MEMORY_TRAINING_PS_ALLOCATION MEMORY_TRAINING_PARAMETERS
+
+
+typedef struct _MEMORY_TRAINING_PARAMETERS_V1_2
+{
+ USHORT usMemTrainingMode;
+ USHORT usReserved;
+}MEMORY_TRAINING_PARAMETERS_V1_2;
+
+//usMemTrainingMode
+#define NORMAL_MEMORY_TRAINING_MODE 0
+#define ENTER_DRAM_SELFREFRESH_MODE 1
+#define EXIT_DRAM_SELFRESH_MODE 2
+
+/****************************LVDS and other encoder command table definitions **********************/
+
+
+/****************************************************************************/
+// Structures used by LVDSEncoderControlTable (Before DEC30)
+// LVTMAEncoderControlTable (Before DEC30)
+// TMDSAEncoderControlTable (Before DEC30)
+/****************************************************************************/
+typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ UCHAR ucMisc; // bit0=0: Enable single link
+ // =1: Enable dual link
+ // Bit1=0: 666RGB
+ // =1: 888RGB
+ UCHAR ucAction; // 0: turn off encoder
+ // 1: setup and turn on encoder
+}LVDS_ENCODER_CONTROL_PARAMETERS;
+
+#define LVDS_ENCODER_CONTROL_PS_ALLOCATION LVDS_ENCODER_CONTROL_PARAMETERS
+
+#define TMDS1_ENCODER_CONTROL_PARAMETERS LVDS_ENCODER_CONTROL_PARAMETERS
+#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION TMDS1_ENCODER_CONTROL_PARAMETERS
+
+#define TMDS2_ENCODER_CONTROL_PARAMETERS TMDS1_ENCODER_CONTROL_PARAMETERS
+#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION TMDS2_ENCODER_CONTROL_PARAMETERS
+
+//ucTableFormatRevision=1,ucTableContentRevision=2
+typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS_V2
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ UCHAR ucMisc; // see PANEL_ENCODER_MISC_xx defintions below
+ UCHAR ucAction; // 0: turn off encoder
+ // 1: setup and turn on encoder
+ UCHAR ucTruncate; // bit0=0: Disable truncate
+ // =1: Enable truncate
+ // bit4=0: 666RGB
+ // =1: 888RGB
+ UCHAR ucSpatial; // bit0=0: Disable spatial dithering
+ // =1: Enable spatial dithering
+ // bit4=0: 666RGB
+ // =1: 888RGB
+ UCHAR ucTemporal; // bit0=0: Disable temporal dithering
+ // =1: Enable temporal dithering
+ // bit4=0: 666RGB
+ // =1: 888RGB
+ // bit5=0: Gray level 2
+ // =1: Gray level 4
+ UCHAR ucFRC; // bit4=0: 25FRC_SEL pattern E
+ // =1: 25FRC_SEL pattern F
+ // bit6:5=0: 50FRC_SEL pattern A
+ // =1: 50FRC_SEL pattern B
+ // =2: 50FRC_SEL pattern C
+ // =3: 50FRC_SEL pattern D
+ // bit7=0: 75FRC_SEL pattern E
+ // =1: 75FRC_SEL pattern F
+}LVDS_ENCODER_CONTROL_PARAMETERS_V2;
+
+#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2
+
+#define TMDS1_ENCODER_CONTROL_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2
+#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2
+
+#define TMDS2_ENCODER_CONTROL_PARAMETERS_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2
+#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS2_ENCODER_CONTROL_PARAMETERS_V2
+
+
+#define LVDS_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V2
+#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3
+
+#define TMDS1_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3
+#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS1_ENCODER_CONTROL_PARAMETERS_V3
+
+#define TMDS2_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3
+#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS2_ENCODER_CONTROL_PARAMETERS_V3
+
+/****************************************************************************/
+// Structures used by ###
+/****************************************************************************/
+typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS
+{
+ UCHAR ucEnable; // Enable or Disable External TMDS encoder
+ UCHAR ucMisc; // Bit0=0:Enable Single link;=1:Enable Dual link;Bit1 {=0:666RGB, =1:888RGB}
+ UCHAR ucPadding[2];
+}ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS;
+
+typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION
+{
+ ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS sXTmdsEncoder;
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion
+}ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION;
+
+#define ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2
+typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2
+{
+ ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 sXTmdsEncoder;
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion
+}ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2;
+
+typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION
+{
+ DIG_ENCODER_CONTROL_PARAMETERS sDigEncoder;
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
+}EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION;
+
+/****************************************************************************/
+// Structures used by DVOEncoderControlTable
+/****************************************************************************/
+//ucTableFormatRevision=1,ucTableContentRevision=3
+//ucDVOConfig:
+#define DVO_ENCODER_CONFIG_RATE_SEL 0x01
+#define DVO_ENCODER_CONFIG_DDR_SPEED 0x00
+#define DVO_ENCODER_CONFIG_SDR_SPEED 0x01
+#define DVO_ENCODER_CONFIG_OUTPUT_SEL 0x0c
+#define DVO_ENCODER_CONFIG_LOW12BIT 0x00
+#define DVO_ENCODER_CONFIG_UPPER12BIT 0x04
+#define DVO_ENCODER_CONFIG_24BIT 0x08
+
+typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3
+{
+ USHORT usPixelClock;
+ UCHAR ucDVOConfig;
+ UCHAR ucAction; //ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT
+ UCHAR ucReseved[4];
+}DVO_ENCODER_CONTROL_PARAMETERS_V3;
+#define DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 DVO_ENCODER_CONTROL_PARAMETERS_V3
+
+typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V1_4
+{
+ USHORT usPixelClock;
+ UCHAR ucDVOConfig;
+ UCHAR ucAction; //ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT
+ UCHAR ucBitPerColor; //please refer to definition of PANEL_xBIT_PER_COLOR
+ UCHAR ucReseved[3];
+}DVO_ENCODER_CONTROL_PARAMETERS_V1_4;
+#define DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4 DVO_ENCODER_CONTROL_PARAMETERS_V1_4
+
+
+//ucTableFormatRevision=1
+//ucTableContentRevision=3 structure is not changed but usMisc add bit 1 as another input for
+// bit1=0: non-coherent mode
+// =1: coherent mode
+
+//==========================================================================================
+//Only change is here next time when changing encoder parameter definitions again!
+#define LVDS_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3
+#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_LAST LVDS_ENCODER_CONTROL_PARAMETERS_LAST
+
+#define TMDS1_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3
+#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_LAST TMDS1_ENCODER_CONTROL_PARAMETERS_LAST
+
+#define TMDS2_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3
+#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_LAST TMDS2_ENCODER_CONTROL_PARAMETERS_LAST
+
+#define DVO_ENCODER_CONTROL_PARAMETERS_LAST DVO_ENCODER_CONTROL_PARAMETERS
+#define DVO_ENCODER_CONTROL_PS_ALLOCATION_LAST DVO_ENCODER_CONTROL_PS_ALLOCATION
+
+//==========================================================================================
+#define PANEL_ENCODER_MISC_DUAL 0x01
+#define PANEL_ENCODER_MISC_COHERENT 0x02
+#define PANEL_ENCODER_MISC_TMDS_LINKB 0x04
+#define PANEL_ENCODER_MISC_HDMI_TYPE 0x08
+
+#define PANEL_ENCODER_ACTION_DISABLE ATOM_DISABLE
+#define PANEL_ENCODER_ACTION_ENABLE ATOM_ENABLE
+#define PANEL_ENCODER_ACTION_COHERENTSEQ (ATOM_ENABLE+1)
+
+#define PANEL_ENCODER_TRUNCATE_EN 0x01
+#define PANEL_ENCODER_TRUNCATE_DEPTH 0x10
+#define PANEL_ENCODER_SPATIAL_DITHER_EN 0x01
+#define PANEL_ENCODER_SPATIAL_DITHER_DEPTH 0x10
+#define PANEL_ENCODER_TEMPORAL_DITHER_EN 0x01
+#define PANEL_ENCODER_TEMPORAL_DITHER_DEPTH 0x10
+#define PANEL_ENCODER_TEMPORAL_LEVEL_4 0x20
+#define PANEL_ENCODER_25FRC_MASK 0x10
+#define PANEL_ENCODER_25FRC_E 0x00
+#define PANEL_ENCODER_25FRC_F 0x10
+#define PANEL_ENCODER_50FRC_MASK 0x60
+#define PANEL_ENCODER_50FRC_A 0x00
+#define PANEL_ENCODER_50FRC_B 0x20
+#define PANEL_ENCODER_50FRC_C 0x40
+#define PANEL_ENCODER_50FRC_D 0x60
+#define PANEL_ENCODER_75FRC_MASK 0x80
+#define PANEL_ENCODER_75FRC_E 0x00
+#define PANEL_ENCODER_75FRC_F 0x80
+
+/****************************************************************************/
+// Structures used by SetVoltageTable
+/****************************************************************************/
+#define SET_VOLTAGE_TYPE_ASIC_VDDC 1
+#define SET_VOLTAGE_TYPE_ASIC_MVDDC 2
+#define SET_VOLTAGE_TYPE_ASIC_MVDDQ 3
+#define SET_VOLTAGE_TYPE_ASIC_VDDCI 4
+#define SET_VOLTAGE_INIT_MODE 5
+#define SET_VOLTAGE_GET_MAX_VOLTAGE 6 //Gets the Max. voltage for the soldered Asic
+
+#define SET_ASIC_VOLTAGE_MODE_ALL_SOURCE 0x1
+#define SET_ASIC_VOLTAGE_MODE_SOURCE_A 0x2
+#define SET_ASIC_VOLTAGE_MODE_SOURCE_B 0x4
+
+#define SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE 0x0
+#define SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL 0x1
+#define SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK 0x2
+
+typedef struct _SET_VOLTAGE_PARAMETERS
+{
+ UCHAR ucVoltageType; // To tell which voltage to set up, VDDC/MVDDC/MVDDQ
+ UCHAR ucVoltageMode; // To set all, to set source A or source B or ...
+ UCHAR ucVoltageIndex; // An index to tell which voltage level
+ UCHAR ucReserved;
+}SET_VOLTAGE_PARAMETERS;
+
+typedef struct _SET_VOLTAGE_PARAMETERS_V2
+{
+ UCHAR ucVoltageType; // To tell which voltage to set up, VDDC/MVDDC/MVDDQ
+ UCHAR ucVoltageMode; // Not used, maybe use for state machine for differen power mode
+ USHORT usVoltageLevel; // real voltage level
+}SET_VOLTAGE_PARAMETERS_V2;
+
+// used by both SetVoltageTable v1.3 and v1.4
+typedef struct _SET_VOLTAGE_PARAMETERS_V1_3
+{
+ UCHAR ucVoltageType; // To tell which voltage to set up, VDDC/MVDDC/MVDDQ/VDDCI
+ UCHAR ucVoltageMode; // Indicate action: Set voltage level
+ USHORT usVoltageLevel; // real voltage level in unit of mv or Voltage Phase (0, 1, 2, .. )
+}SET_VOLTAGE_PARAMETERS_V1_3;
+
+//ucVoltageType
+#define VOLTAGE_TYPE_VDDC 1
+#define VOLTAGE_TYPE_MVDDC 2
+#define VOLTAGE_TYPE_MVDDQ 3
+#define VOLTAGE_TYPE_VDDCI 4
+#define VOLTAGE_TYPE_VDDGFX 5
+#define VOLTAGE_TYPE_PCC 6
+
+#define VOLTAGE_TYPE_GENERIC_I2C_1 0x11
+#define VOLTAGE_TYPE_GENERIC_I2C_2 0x12
+#define VOLTAGE_TYPE_GENERIC_I2C_3 0x13
+#define VOLTAGE_TYPE_GENERIC_I2C_4 0x14
+#define VOLTAGE_TYPE_GENERIC_I2C_5 0x15
+#define VOLTAGE_TYPE_GENERIC_I2C_6 0x16
+#define VOLTAGE_TYPE_GENERIC_I2C_7 0x17
+#define VOLTAGE_TYPE_GENERIC_I2C_8 0x18
+#define VOLTAGE_TYPE_GENERIC_I2C_9 0x19
+#define VOLTAGE_TYPE_GENERIC_I2C_10 0x1A
+
+//SET_VOLTAGE_PARAMETERS_V3.ucVoltageMode
+#define ATOM_SET_VOLTAGE 0 //Set voltage Level
+#define ATOM_INIT_VOLTAGE_REGULATOR 3 //Init Regulator
+#define ATOM_SET_VOLTAGE_PHASE 4 //Set Vregulator Phase, only for SVID/PVID regulator
+#define ATOM_GET_MAX_VOLTAGE 6 //Get Max Voltage, not used from SetVoltageTable v1.3
+#define ATOM_GET_VOLTAGE_LEVEL 6 //Get Voltage level from vitual voltage ID, not used for SetVoltage v1.4
+#define ATOM_GET_LEAKAGE_ID 8 //Get Leakage Voltage Id ( starting from SMU7x IP ), SetVoltage v1.4
+
+// define vitual voltage id in usVoltageLevel
+#define ATOM_VIRTUAL_VOLTAGE_ID0 0xff01
+#define ATOM_VIRTUAL_VOLTAGE_ID1 0xff02
+#define ATOM_VIRTUAL_VOLTAGE_ID2 0xff03
+#define ATOM_VIRTUAL_VOLTAGE_ID3 0xff04
+#define ATOM_VIRTUAL_VOLTAGE_ID4 0xff05
+#define ATOM_VIRTUAL_VOLTAGE_ID5 0xff06
+#define ATOM_VIRTUAL_VOLTAGE_ID6 0xff07
+#define ATOM_VIRTUAL_VOLTAGE_ID7 0xff08
+
+typedef struct _SET_VOLTAGE_PS_ALLOCATION
+{
+ SET_VOLTAGE_PARAMETERS sASICSetVoltage;
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
+}SET_VOLTAGE_PS_ALLOCATION;
+
+// New Added from SI for GetVoltageInfoTable, input parameter structure
+typedef struct _GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_1
+{
+ UCHAR ucVoltageType; // Input: To tell which voltage to set up, VDDC/MVDDC/MVDDQ/VDDCI
+ UCHAR ucVoltageMode; // Input: Indicate action: Get voltage info
+ USHORT usVoltageLevel; // Input: real voltage level in unit of mv or Voltage Phase (0, 1, 2, .. ) or Leakage Id
+ ULONG ulReserved;
+}GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_1;
+
+// New Added from SI for GetVoltageInfoTable, output parameter structure when ucVotlageMode == ATOM_GET_VOLTAGE_VID
+typedef struct _GET_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_1
+{
+ ULONG ulVotlageGpioState;
+ ULONG ulVoltageGPioMask;
+}GET_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_1;
+
+// New Added from SI for GetVoltageInfoTable, output parameter structure when ucVotlageMode == ATOM_GET_VOLTAGE_STATEx_LEAKAGE_VID
+typedef struct _GET_LEAKAGE_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_1
+{
+ USHORT usVoltageLevel;
+ USHORT usVoltageId; // Voltage Id programmed in Voltage Regulator
+ ULONG ulReseved;
+}GET_LEAKAGE_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_1;
+
+// GetVoltageInfo v1.1 ucVoltageMode
+#define ATOM_GET_VOLTAGE_VID 0x00
+#define ATOM_GET_VOTLAGE_INIT_SEQ 0x03
+#define ATOM_GET_VOLTTAGE_PHASE_PHASE_VID 0x04
+#define ATOM_GET_VOLTAGE_SVID2 0x07 //Get SVI2 Regulator Info
+
+// for SI, this state map to 0xff02 voltage state in Power Play table, which is power boost state
+#define ATOM_GET_VOLTAGE_STATE0_LEAKAGE_VID 0x10
+// for SI, this state map to 0xff01 voltage state in Power Play table, which is performance state
+#define ATOM_GET_VOLTAGE_STATE1_LEAKAGE_VID 0x11
+
+#define ATOM_GET_VOLTAGE_STATE2_LEAKAGE_VID 0x12
+#define ATOM_GET_VOLTAGE_STATE3_LEAKAGE_VID 0x13
+
+
+// New Added from CI Hawaii for GetVoltageInfoTable, input parameter structure
+typedef struct _GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2
+{
+ UCHAR ucVoltageType; // Input: To tell which voltage to set up, VDDC/MVDDC/MVDDQ/VDDCI
+ UCHAR ucVoltageMode; // Input: Indicate action: Get voltage info
+ USHORT usVoltageLevel; // Input: real voltage level in unit of mv or Voltage Phase (0, 1, 2, .. ) or Leakage Id
+ ULONG ulSCLKFreq; // Input: when ucVoltageMode= ATOM_GET_VOLTAGE_EVV_VOLTAGE, DPM state SCLK frequency, Define in PPTable SCLK/Voltage dependence table
+}GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2;
+
+// New in GetVoltageInfo v1.2 ucVoltageMode
+#define ATOM_GET_VOLTAGE_EVV_VOLTAGE 0x09
+
+// New Added from CI Hawaii for EVV feature
+typedef struct _GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2
+{
+ USHORT usVoltageLevel; // real voltage level in unit of mv
+ USHORT usVoltageId; // Voltage Id programmed in Voltage Regulator
+ USHORT usTDP_Current; // TDP_Current in unit of 0.01A
+ USHORT usTDP_Power; // TDP_Current in unit of 0.1W
+}GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2;
+
+/****************************************************************************/
+// Structures used by TVEncoderControlTable
+/****************************************************************************/
+typedef struct _TV_ENCODER_CONTROL_PARAMETERS
+{
+ USHORT usPixelClock; // in 10KHz; for bios convenient
+ UCHAR ucTvStandard; // See definition "ATOM_TV_NTSC ..."
+ UCHAR ucAction; // 0: turn off encoder
+ // 1: setup and turn on encoder
+}TV_ENCODER_CONTROL_PARAMETERS;
+
+typedef struct _TV_ENCODER_CONTROL_PS_ALLOCATION
+{
+ TV_ENCODER_CONTROL_PARAMETERS sTVEncoder;
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; // Don't set this one
+}TV_ENCODER_CONTROL_PS_ALLOCATION;
+
+//==============================Data Table Portion====================================
+
+
+/****************************************************************************/
+// Structure used in Data.mtb
+/****************************************************************************/
+typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES
+{
+ USHORT UtilityPipeLine; // Offest for the utility to get parser info,Don't change this position!
+ USHORT MultimediaCapabilityInfo; // Only used by MM Lib,latest version 1.1, not configuable from Bios, need to include the table to build Bios
+ USHORT MultimediaConfigInfo; // Only used by MM Lib,latest version 2.1, not configuable from Bios, need to include the table to build Bios
+ USHORT StandardVESA_Timing; // Only used by Bios
+ USHORT FirmwareInfo; // Shared by various SW components,latest version 1.4
+ USHORT PaletteData; // Only used by BIOS
+ USHORT LCD_Info; // Shared by various SW components,latest version 1.3, was called LVDS_Info
+ USHORT DIGTransmitterInfo; // Internal used by VBIOS only version 3.1
+ USHORT AnalogTV_Info; // Shared by various SW components,latest version 1.1
+ USHORT SupportedDevicesInfo; // Will be obsolete from R600
+ USHORT GPIO_I2C_Info; // Shared by various SW components,latest version 1.2 will be used from R600
+ USHORT VRAM_UsageByFirmware; // Shared by various SW components,latest version 1.3 will be used from R600
+ USHORT GPIO_Pin_LUT; // Shared by various SW components,latest version 1.1
+ USHORT VESA_ToInternalModeLUT; // Only used by Bios
+ USHORT ComponentVideoInfo; // Shared by various SW components,latest version 2.1 will be used from R600
+ USHORT PowerPlayInfo; // Shared by various SW components,latest version 2.1,new design from R600
+ USHORT GPUVirtualizationInfo; // Will be obsolete from R600
+ USHORT SaveRestoreInfo; // Only used by Bios
+ USHORT PPLL_SS_Info; // Shared by various SW components,latest version 1.2, used to call SS_Info, change to new name because of int ASIC SS info
+ USHORT OemInfo; // Defined and used by external SW, should be obsolete soon
+ USHORT XTMDS_Info; // Will be obsolete from R600
+ USHORT MclkSS_Info; // Shared by various SW components,latest version 1.1, only enabled when ext SS chip is used
+ USHORT Object_Header; // Shared by various SW components,latest version 1.1
+ USHORT IndirectIOAccess; // Only used by Bios,this table position can't change at all!!
+ USHORT MC_InitParameter; // Only used by command table
+ USHORT ASIC_VDDC_Info; // Will be obsolete from R600
+ USHORT ASIC_InternalSS_Info; // New tabel name from R600, used to be called "ASIC_MVDDC_Info"
+ USHORT TV_VideoMode; // Only used by command table
+ USHORT VRAM_Info; // Only used by command table, latest version 1.3
+ USHORT MemoryTrainingInfo; // Used for VBIOS and Diag utility for memory training purpose since R600. the new table rev start from 2.1
+ USHORT IntegratedSystemInfo; // Shared by various SW components
+ USHORT ASIC_ProfilingInfo; // New table name from R600, used to be called "ASIC_VDDCI_Info" for pre-R600
+ USHORT VoltageObjectInfo; // Shared by various SW components, latest version 1.1
+ USHORT PowerSourceInfo; // Shared by various SW components, latest versoin 1.1
+ USHORT ServiceInfo;
+}ATOM_MASTER_LIST_OF_DATA_TABLES;
+
+typedef struct _ATOM_MASTER_DATA_TABLE
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_MASTER_LIST_OF_DATA_TABLES ListOfDataTables;
+}ATOM_MASTER_DATA_TABLE;
+
+// For backward compatible
+#define LVDS_Info LCD_Info
+#define DAC_Info PaletteData
+#define TMDS_Info DIGTransmitterInfo
+#define CompassionateData GPUVirtualizationInfo
+
+/****************************************************************************/
+// Structure used in MultimediaCapabilityInfoTable
+/****************************************************************************/
+typedef struct _ATOM_MULTIMEDIA_CAPABILITY_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulSignature; // HW info table signature string "$ATI"
+ UCHAR ucI2C_Type; // I2C type (normal GP_IO, ImpactTV GP_IO, Dedicated I2C pin, etc)
+ UCHAR ucTV_OutInfo; // Type of TV out supported (3:0) and video out crystal frequency (6:4) and TV data port (7)
+ UCHAR ucVideoPortInfo; // Provides the video port capabilities
+ UCHAR ucHostPortInfo; // Provides host port configuration information
+}ATOM_MULTIMEDIA_CAPABILITY_INFO;
+
+
+/****************************************************************************/
+// Structure used in MultimediaConfigInfoTable
+/****************************************************************************/
+typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulSignature; // MM info table signature sting "$MMT"
+ UCHAR ucTunerInfo; // Type of tuner installed on the adapter (4:0) and video input for tuner (7:5)
+ UCHAR ucAudioChipInfo; // List the audio chip type (3:0) product type (4) and OEM revision (7:5)
+ UCHAR ucProductID; // Defines as OEM ID or ATI board ID dependent on product type setting
+ UCHAR ucMiscInfo1; // Tuner voltage (1:0) HW teletext support (3:2) FM audio decoder (5:4) reserved (6) audio scrambling (7)
+ UCHAR ucMiscInfo2; // I2S input config (0) I2S output config (1) I2S Audio Chip (4:2) SPDIF Output Config (5) reserved (7:6)
+ UCHAR ucMiscInfo3; // Video Decoder Type (3:0) Video In Standard/Crystal (7:4)
+ UCHAR ucMiscInfo4; // Video Decoder Host Config (2:0) reserved (7:3)
+ UCHAR ucVideoInput0Info;// Video Input 0 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6)
+ UCHAR ucVideoInput1Info;// Video Input 1 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6)
+ UCHAR ucVideoInput2Info;// Video Input 2 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6)
+ UCHAR ucVideoInput3Info;// Video Input 3 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6)
+ UCHAR ucVideoInput4Info;// Video Input 4 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6)
+}ATOM_MULTIMEDIA_CONFIG_INFO;
+
+
+/****************************************************************************/
+// Structures used in FirmwareInfoTable
+/****************************************************************************/
+
+// usBIOSCapability Defintion:
+// Bit 0 = 0: Bios image is not Posted, =1:Bios image is Posted;
+// Bit 1 = 0: Dual CRTC is not supported, =1: Dual CRTC is supported;
+// Bit 2 = 0: Extended Desktop is not supported, =1: Extended Desktop is supported;
+// Others: Reserved
+#define ATOM_BIOS_INFO_ATOM_FIRMWARE_POSTED 0x0001
+#define ATOM_BIOS_INFO_DUAL_CRTC_SUPPORT 0x0002
+#define ATOM_BIOS_INFO_EXTENDED_DESKTOP_SUPPORT 0x0004
+#define ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT 0x0008 // (valid from v1.1 ~v1.4):=1: memclk SS enable, =0 memclk SS disable.
+#define ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT 0x0010 // (valid from v1.1 ~v1.4):=1: engclk SS enable, =0 engclk SS disable.
+#define ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU 0x0020
+#define ATOM_BIOS_INFO_WMI_SUPPORT 0x0040
+#define ATOM_BIOS_INFO_PPMODE_ASSIGNGED_BY_SYSTEM 0x0080
+#define ATOM_BIOS_INFO_HYPERMEMORY_SUPPORT 0x0100
+#define ATOM_BIOS_INFO_HYPERMEMORY_SIZE_MASK 0x1E00
+#define ATOM_BIOS_INFO_VPOST_WITHOUT_FIRST_MODE_SET 0x2000
+#define ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE 0x4000
+#define ATOM_BIOS_INFO_MEMORY_CLOCK_EXT_SS_SUPPORT 0x0008 // (valid from v2.1 ): =1: memclk ss enable with external ss chip
+#define ATOM_BIOS_INFO_ENGINE_CLOCK_EXT_SS_SUPPORT 0x0010 // (valid from v2.1 ): =1: engclk ss enable with external ss chip
+
+
+#ifndef _H2INC
+
+//Please don't add or expand this bitfield structure below, this one will retire soon.!
+typedef struct _ATOM_FIRMWARE_CAPABILITY
+{
+#if ATOM_BIG_ENDIAN
+ USHORT Reserved:1;
+ USHORT SCL2Redefined:1;
+ USHORT PostWithoutModeSet:1;
+ USHORT HyperMemory_Size:4;
+ USHORT HyperMemory_Support:1;
+ USHORT PPMode_Assigned:1;
+ USHORT WMI_SUPPORT:1;
+ USHORT GPUControlsBL:1;
+ USHORT EngineClockSS_Support:1;
+ USHORT MemoryClockSS_Support:1;
+ USHORT ExtendedDesktopSupport:1;
+ USHORT DualCRTC_Support:1;
+ USHORT FirmwarePosted:1;
+#else
+ USHORT FirmwarePosted:1;
+ USHORT DualCRTC_Support:1;
+ USHORT ExtendedDesktopSupport:1;
+ USHORT MemoryClockSS_Support:1;
+ USHORT EngineClockSS_Support:1;
+ USHORT GPUControlsBL:1;
+ USHORT WMI_SUPPORT:1;
+ USHORT PPMode_Assigned:1;
+ USHORT HyperMemory_Support:1;
+ USHORT HyperMemory_Size:4;
+ USHORT PostWithoutModeSet:1;
+ USHORT SCL2Redefined:1;
+ USHORT Reserved:1;
+#endif
+}ATOM_FIRMWARE_CAPABILITY;
+
+typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS
+{
+ ATOM_FIRMWARE_CAPABILITY sbfAccess;
+ USHORT susAccess;
+}ATOM_FIRMWARE_CAPABILITY_ACCESS;
+
+#else
+
+typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS
+{
+ USHORT susAccess;
+}ATOM_FIRMWARE_CAPABILITY_ACCESS;
+
+#endif
+
+typedef struct _ATOM_FIRMWARE_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulFirmwareRevision;
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+ ULONG ulDriverTargetEngineClock; //In 10Khz unit
+ ULONG ulDriverTargetMemoryClock; //In 10Khz unit
+ ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulASICMaxEngineClock; //In 10Khz unit
+ ULONG ulASICMaxMemoryClock; //In 10Khz unit
+ UCHAR ucASICMaxTemperature;
+ UCHAR ucPadding[3]; //Don't use them
+ ULONG aulReservedForBIOS[3]; //Don't use them
+ USHORT usMinEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMaxEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Output; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Output; //In 10Khz unit
+ USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk
+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMinPixelClockPLL_Output; //In 10Khz unit, the definitions above can't change!!!
+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+ USHORT usReferenceClock; //In 10Khz unit
+ USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit
+ UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit
+ UCHAR ucDesign_ID; //Indicate what is the board design
+ UCHAR ucMemoryModule_ID; //Indicate what is the board design
+}ATOM_FIRMWARE_INFO;
+
+typedef struct _ATOM_FIRMWARE_INFO_V1_2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulFirmwareRevision;
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+ ULONG ulDriverTargetEngineClock; //In 10Khz unit
+ ULONG ulDriverTargetMemoryClock; //In 10Khz unit
+ ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulASICMaxEngineClock; //In 10Khz unit
+ ULONG ulASICMaxMemoryClock; //In 10Khz unit
+ UCHAR ucASICMaxTemperature;
+ UCHAR ucMinAllowedBL_Level;
+ UCHAR ucPadding[2]; //Don't use them
+ ULONG aulReservedForBIOS[2]; //Don't use them
+ ULONG ulMinPixelClockPLL_Output; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMaxEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Output; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Output; //In 10Khz unit
+ USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk
+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output
+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+ USHORT usReferenceClock; //In 10Khz unit
+ USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit
+ UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit
+ UCHAR ucDesign_ID; //Indicate what is the board design
+ UCHAR ucMemoryModule_ID; //Indicate what is the board design
+}ATOM_FIRMWARE_INFO_V1_2;
+
+typedef struct _ATOM_FIRMWARE_INFO_V1_3
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulFirmwareRevision;
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+ ULONG ulDriverTargetEngineClock; //In 10Khz unit
+ ULONG ulDriverTargetMemoryClock; //In 10Khz unit
+ ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulASICMaxEngineClock; //In 10Khz unit
+ ULONG ulASICMaxMemoryClock; //In 10Khz unit
+ UCHAR ucASICMaxTemperature;
+ UCHAR ucMinAllowedBL_Level;
+ UCHAR ucPadding[2]; //Don't use them
+ ULONG aulReservedForBIOS; //Don't use them
+ ULONG ul3DAccelerationEngineClock;//In 10Khz unit
+ ULONG ulMinPixelClockPLL_Output; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMaxEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Output; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Output; //In 10Khz unit
+ USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk
+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output
+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+ USHORT usReferenceClock; //In 10Khz unit
+ USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit
+ UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit
+ UCHAR ucDesign_ID; //Indicate what is the board design
+ UCHAR ucMemoryModule_ID; //Indicate what is the board design
+}ATOM_FIRMWARE_INFO_V1_3;
+
+typedef struct _ATOM_FIRMWARE_INFO_V1_4
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulFirmwareRevision;
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+ ULONG ulDriverTargetEngineClock; //In 10Khz unit
+ ULONG ulDriverTargetMemoryClock; //In 10Khz unit
+ ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulASICMaxEngineClock; //In 10Khz unit
+ ULONG ulASICMaxMemoryClock; //In 10Khz unit
+ UCHAR ucASICMaxTemperature;
+ UCHAR ucMinAllowedBL_Level;
+ USHORT usBootUpVDDCVoltage; //In MV unit
+ USHORT usLcdMinPixelClockPLL_Output; // In MHz unit
+ USHORT usLcdMaxPixelClockPLL_Output; // In MHz unit
+ ULONG ul3DAccelerationEngineClock;//In 10Khz unit
+ ULONG ulMinPixelClockPLL_Output; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMaxEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Output; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Output; //In 10Khz unit
+ USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk
+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output
+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+ USHORT usReferenceClock; //In 10Khz unit
+ USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit
+ UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit
+ UCHAR ucDesign_ID; //Indicate what is the board design
+ UCHAR ucMemoryModule_ID; //Indicate what is the board design
+}ATOM_FIRMWARE_INFO_V1_4;
+
+//the structure below to be used from Cypress
+typedef struct _ATOM_FIRMWARE_INFO_V2_1
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulFirmwareRevision;
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+ ULONG ulReserved1;
+ ULONG ulReserved2;
+ ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit
+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulBinaryAlteredInfo; //Was ulASICMaxEngineClock
+ ULONG ulDefaultDispEngineClkFreq; //In 10Khz unit
+ UCHAR ucReserved1; //Was ucASICMaxTemperature;
+ UCHAR ucMinAllowedBL_Level;
+ USHORT usBootUpVDDCVoltage; //In MV unit
+ USHORT usLcdMinPixelClockPLL_Output; // In MHz unit
+ USHORT usLcdMaxPixelClockPLL_Output; // In MHz unit
+ ULONG ulReserved4; //Was ulAsicMaximumVoltage
+ ULONG ulMinPixelClockPLL_Output; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMaxEngineClockPLL_Input; //In 10Khz unit
+ USHORT usMinEngineClockPLL_Output; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit
+ USHORT usMinMemoryClockPLL_Output; //In 10Khz unit
+ USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk
+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output
+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+ USHORT usCoreReferenceClock; //In 10Khz unit
+ USHORT usMemoryReferenceClock; //In 10Khz unit
+ USHORT usUniphyDPModeExtClkFreq; //In 10Khz unit, if it is 0, In DP Mode Uniphy Input clock from internal PPLL, otherwise Input clock from external Spread clock
+ UCHAR ucMemoryModule_ID; //Indicate what is the board design
+ UCHAR ucReserved4[3];
+
+}ATOM_FIRMWARE_INFO_V2_1;
+
+//the structure below to be used from NI
+//ucTableFormatRevision=2
+//ucTableContentRevision=2
+
+typedef struct _PRODUCT_BRANDING
+{
+ UCHAR ucEMBEDDED_CAP:2; // Bit[1:0] Embedded feature level
+ UCHAR ucReserved:2; // Bit[3:2] Reserved
+ UCHAR ucBRANDING_ID:4; // Bit[7:4] Branding ID
+}PRODUCT_BRANDING;
+
+typedef struct _ATOM_FIRMWARE_INFO_V2_2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulFirmwareRevision;
+ ULONG ulDefaultEngineClock; //In 10Khz unit
+ ULONG ulDefaultMemoryClock; //In 10Khz unit
+ ULONG ulSPLL_OutputFreq; //In 10Khz unit
+ ULONG ulGPUPLL_OutputFreq; //In 10Khz unit
+ ULONG ulReserved1; //Was ulMaxEngineClockPLL_Output; //In 10Khz unit*
+ ULONG ulReserved2; //Was ulMaxMemoryClockPLL_Output; //In 10Khz unit*
+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit
+ ULONG ulBinaryAlteredInfo; //Was ulASICMaxEngineClock ?
+ ULONG ulDefaultDispEngineClkFreq; //In 10Khz unit. This is the frequency before DCDTO, corresponding to usBootUpVDDCVoltage.
+ UCHAR ucReserved3; //Was ucASICMaxTemperature;
+ UCHAR ucMinAllowedBL_Level;
+ USHORT usBootUpVDDCVoltage; //In MV unit
+ USHORT usLcdMinPixelClockPLL_Output; // In MHz unit
+ USHORT usLcdMaxPixelClockPLL_Output; // In MHz unit
+ ULONG ulReserved4; //Was ulAsicMaximumVoltage
+ ULONG ulMinPixelClockPLL_Output; //In 10Khz unit
+ UCHAR ucRemoteDisplayConfig;
+ UCHAR ucReserved5[3]; //Was usMinEngineClockPLL_Input and usMaxEngineClockPLL_Input
+ ULONG ulReserved6; //Was usMinEngineClockPLL_Output and usMinMemoryClockPLL_Input
+ ULONG ulReserved7; //Was usMaxMemoryClockPLL_Input and usMinMemoryClockPLL_Output
+ USHORT usReserved11; //Was usMaxPixelClock; //In 10Khz unit, Max. Pclk used only for DAC
+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit
+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit
+ USHORT usBootUpVDDCIVoltage; //In unit of mv; Was usMinPixelClockPLL_Output;
+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+ USHORT usCoreReferenceClock; //In 10Khz unit
+ USHORT usMemoryReferenceClock; //In 10Khz unit
+ USHORT usUniphyDPModeExtClkFreq; //In 10Khz unit, if it is 0, In DP Mode Uniphy Input clock from internal PPLL, otherwise Input clock from external Spread clock
+ UCHAR ucMemoryModule_ID; //Indicate what is the board design
+ UCHAR ucCoolingSolution_ID; //0: Air cooling; 1: Liquid cooling ... [COOLING_SOLUTION]
+ PRODUCT_BRANDING ucProductBranding; // Bit[7:4]ucBRANDING_ID: Branding ID, Bit[3:2]ucReserved: Reserved, Bit[1:0]ucEMBEDDED_CAP: Embedded feature level.
+ UCHAR ucReserved9;
+ USHORT usBootUpMVDDCVoltage; //In unit of mv; Was usMinPixelClockPLL_Output;
+ USHORT usBootUpVDDGFXVoltage; //In unit of mv;
+ ULONG ulReserved10[3]; // New added comparing to previous version
+}ATOM_FIRMWARE_INFO_V2_2;
+
+#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V2_2
+
+
+// definition of ucRemoteDisplayConfig
+#define REMOTE_DISPLAY_DISABLE 0x00
+#define REMOTE_DISPLAY_ENABLE 0x01
+
+/****************************************************************************/
+// Structures used in IntegratedSystemInfoTable
+/****************************************************************************/
+#define IGP_CAP_FLAG_DYNAMIC_CLOCK_EN 0x2
+#define IGP_CAP_FLAG_AC_CARD 0x4
+#define IGP_CAP_FLAG_SDVO_CARD 0x8
+#define IGP_CAP_FLAG_POSTDIV_BY_2_MODE 0x10
+
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulBootUpEngineClock; //in 10kHz unit
+ ULONG ulBootUpMemoryClock; //in 10kHz unit
+ ULONG ulMaxSystemMemoryClock; //in 10kHz unit
+ ULONG ulMinSystemMemoryClock; //in 10kHz unit
+ UCHAR ucNumberOfCyclesInPeriodHi;
+ UCHAR ucLCDTimingSel; //=0:not valid.!=0 sel this timing descriptor from LCD EDID.
+ USHORT usReserved1;
+ USHORT usInterNBVoltageLow; //An intermidiate PMW value to set the voltage
+ USHORT usInterNBVoltageHigh; //Another intermidiate PMW value to set the voltage
+ ULONG ulReserved[2];
+
+ USHORT usFSBClock; //In MHz unit
+ USHORT usCapabilityFlag; //Bit0=1 indicates the fake HDMI support,Bit1=0/1 for Dynamic clocking dis/enable
+ //Bit[3:2]== 0:No PCIE card, 1:AC card, 2:SDVO card
+ //Bit[4]==1: P/2 mode, ==0: P/1 mode
+ USHORT usPCIENBCfgReg7; //bit[7:0]=MUX_Sel, bit[9:8]=MUX_SEL_LEVEL2, bit[10]=Lane_Reversal
+ USHORT usK8MemoryClock; //in MHz unit
+ USHORT usK8SyncStartDelay; //in 0.01 us unit
+ USHORT usK8DataReturnTime; //in 0.01 us unit
+ UCHAR ucMaxNBVoltage;
+ UCHAR ucMinNBVoltage;
+ UCHAR ucMemoryType; //[7:4]=1:DDR1;=2:DDR2;=3:DDR3.[3:0] is reserved
+ UCHAR ucNumberOfCyclesInPeriod; //CG.FVTHROT_PWM_CTRL_REG0.NumberOfCyclesInPeriod
+ UCHAR ucStartingPWM_HighTime; //CG.FVTHROT_PWM_CTRL_REG0.StartingPWM_HighTime
+ UCHAR ucHTLinkWidth; //16 bit vs. 8 bit
+ UCHAR ucMaxNBVoltageHigh;
+ UCHAR ucMinNBVoltageHigh;
+}ATOM_INTEGRATED_SYSTEM_INFO;
+
+/* Explanation on entries in ATOM_INTEGRATED_SYSTEM_INFO
+ulBootUpMemoryClock: For Intel IGP,it's the UMA system memory clock
+ For AMD IGP,it's 0 if no SidePort memory installed or it's the boot-up SidePort memory clock
+ulMaxSystemMemoryClock: For Intel IGP,it's the Max freq from memory SPD if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0
+ For AMD IGP,for now this can be 0
+ulMinSystemMemoryClock: For Intel IGP,it's 133MHz if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0
+ For AMD IGP,for now this can be 0
+
+usFSBClock: For Intel IGP,it's FSB Freq
+ For AMD IGP,it's HT Link Speed
+
+usK8MemoryClock: For AMD IGP only. For RevF CPU, set it to 200
+usK8SyncStartDelay: For AMD IGP only. Memory access latency in K8, required for watermark calculation
+usK8DataReturnTime: For AMD IGP only. Memory access latency in K8, required for watermark calculation
+
+VC:Voltage Control
+ucMaxNBVoltage: Voltage regulator dependent PWM value. Low 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all.
+ucMinNBVoltage: Voltage regulator dependent PWM value. Low 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all.
+
+ucNumberOfCyclesInPeriod: Indicate how many cycles when PWM duty is 100%. low 8 bits of the value.
+ucNumberOfCyclesInPeriodHi: Indicate how many cycles when PWM duty is 100%. high 8 bits of the value.If the PWM has an inverter,set bit [7]==1,otherwise set it 0
+
+ucMaxNBVoltageHigh: Voltage regulator dependent PWM value. High 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all.
+ucMinNBVoltageHigh: Voltage regulator dependent PWM value. High 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all.
+
+
+usInterNBVoltageLow: Voltage regulator dependent PWM value. The value makes the the voltage >=Min NB voltage but <=InterNBVoltageHigh. Set this to 0x0000 if VC without PWM or no VC at all.
+usInterNBVoltageHigh: Voltage regulator dependent PWM value. The value makes the the voltage >=InterNBVoltageLow but <=Max NB voltage.Set this to 0x0000 if VC without PWM or no VC at all.
+*/
+
+
+/*
+The following IGP table is introduced from RS780, which is supposed to be put by SBIOS in FB before IGP VBIOS starts VPOST;
+Then VBIOS will copy the whole structure to its image so all GPU SW components can access this data structure to get whatever they need.
+The enough reservation should allow us to never change table revisions. Whenever needed, a GPU SW component can use reserved portion for new data entries.
+
+SW components can access the IGP system infor structure in the same way as before
+*/
+
+
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulBootUpEngineClock; //in 10kHz unit
+ ULONG ulReserved1[2]; //must be 0x0 for the reserved
+ ULONG ulBootUpUMAClock; //in 10kHz unit
+ ULONG ulBootUpSidePortClock; //in 10kHz unit
+ ULONG ulMinSidePortClock; //in 10kHz unit
+ ULONG ulReserved2[6]; //must be 0x0 for the reserved
+ ULONG ulSystemConfig; //see explanation below
+ ULONG ulBootUpReqDisplayVector;
+ ULONG ulOtherDisplayMisc;
+ ULONG ulDDISlot1Config;
+ ULONG ulDDISlot2Config;
+ UCHAR ucMemoryType; //[3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved
+ UCHAR ucUMAChannelNumber;
+ UCHAR ucDockingPinBit;
+ UCHAR ucDockingPinPolarity;
+ ULONG ulDockingPinCFGInfo;
+ ULONG ulCPUCapInfo;
+ USHORT usNumberOfCyclesInPeriod;
+ USHORT usMaxNBVoltage;
+ USHORT usMinNBVoltage;
+ USHORT usBootUpNBVoltage;
+ ULONG ulHTLinkFreq; //in 10Khz
+ USHORT usMinHTLinkWidth;
+ USHORT usMaxHTLinkWidth;
+ USHORT usUMASyncStartDelay;
+ USHORT usUMADataReturnTime;
+ USHORT usLinkStatusZeroTime;
+ USHORT usDACEfuse; //for storing badgap value (for RS880 only)
+ ULONG ulHighVoltageHTLinkFreq; // in 10Khz
+ ULONG ulLowVoltageHTLinkFreq; // in 10Khz
+ USHORT usMaxUpStreamHTLinkWidth;
+ USHORT usMaxDownStreamHTLinkWidth;
+ USHORT usMinUpStreamHTLinkWidth;
+ USHORT usMinDownStreamHTLinkWidth;
+ USHORT usFirmwareVersion; //0 means FW is not supported. Otherwise it's the FW version loaded by SBIOS and driver should enable FW.
+ USHORT usFullT0Time; // Input to calculate minimum HT link change time required by NB P-State. Unit is 0.01us.
+ ULONG ulReserved3[96]; //must be 0x0
+}ATOM_INTEGRATED_SYSTEM_INFO_V2;
+
+/*
+ulBootUpEngineClock: Boot-up Engine Clock in 10Khz;
+ulBootUpUMAClock: Boot-up UMA Clock in 10Khz; it must be 0x0 when UMA is not present
+ulBootUpSidePortClock: Boot-up SidePort Clock in 10Khz; it must be 0x0 when SidePort Memory is not present,this could be equal to or less than maximum supported Sideport memory clock
+
+ulSystemConfig:
+Bit[0]=1: PowerExpress mode =0 Non-PowerExpress mode;
+Bit[1]=1: system boots up at AMD overdrived state or user customized mode. In this case, driver will just stick to this boot-up mode. No other PowerPlay state
+ =0: system boots up at driver control state. Power state depends on PowerPlay table.
+Bit[2]=1: PWM method is used on NB voltage control. =0: GPIO method is used.
+Bit[3]=1: Only one power state(Performance) will be supported.
+ =0: Multiple power states supported from PowerPlay table.
+Bit[4]=1: CLMC is supported and enabled on current system.
+ =0: CLMC is not supported or enabled on current system. SBIOS need to support HT link/freq change through ATIF interface.
+Bit[5]=1: Enable CDLW for all driver control power states. Max HT width is from SBIOS, while Min HT width is determined by display requirement.
+ =0: CDLW is disabled. If CLMC is enabled case, Min HT width will be set equal to Max HT width. If CLMC disabled case, Max HT width will be applied.
+Bit[6]=1: High Voltage requested for all power states. In this case, voltage will be forced at 1.1v and powerplay table voltage drop/throttling request will be ignored.
+ =0: Voltage settings is determined by powerplay table.
+Bit[7]=1: Enable CLMC as hybrid Mode. CDLD and CILR will be disabled in this case and we're using legacy C1E. This is workaround for CPU(Griffin) performance issue.
+ =0: Enable CLMC as regular mode, CDLD and CILR will be enabled.
+Bit[8]=1: CDLF is supported and enabled on current system.
+ =0: CDLF is not supported or enabled on current system.
+Bit[9]=1: DLL Shut Down feature is enabled on current system.
+ =0: DLL Shut Down feature is not enabled or supported on current system.
+
+ulBootUpReqDisplayVector: This dword is a bit vector indicates what display devices are requested during boot-up. Refer to ATOM_DEVICE_xxx_SUPPORT for the bit vector definitions.
+
+ulOtherDisplayMisc: [15:8]- Bootup LCD Expansion selection; 0-center, 1-full panel size expansion;
+ [7:0] - BootupTV standard selection; This is a bit vector to indicate what TV standards are supported by the system. Refer to ucTVSuppportedStd definition;
+
+ulDDISlot1Config: Describes the PCIE lane configuration on this DDI PCIE slot (ADD2 card) or connector (Mobile design).
+ [3:0] - Bit vector to indicate PCIE lane config of the DDI slot/connector on chassis (bit 0=1 lane 3:0; bit 1=1 lane 7:4; bit 2=1 lane 11:8; bit 3=1 lane 15:12)
+ [7:4] - Bit vector to indicate PCIE lane config of the same DDI slot/connector on docking station (bit 4=1 lane 3:0; bit 5=1 lane 7:4; bit 6=1 lane 11:8; bit 7=1 lane 15:12)
+ When a DDI connector is not "paired" (meaming two connections mutualexclusive on chassis or docking, only one of them can be connected at one time.
+ in both chassis and docking, SBIOS has to duplicate the same PCIE lane info from chassis to docking or vice versa. For example:
+ one DDI connector is only populated in docking with PCIE lane 8-11, but there is no paired connection on chassis, SBIOS has to copy bit 6 to bit 2.
+
+ [15:8] - Lane configuration attribute;
+ [23:16]- Connector type, possible value:
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D
+ CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D
+ CONNECTOR_OBJECT_ID_HDMI_TYPE_A
+ CONNECTOR_OBJECT_ID_DISPLAYPORT
+ CONNECTOR_OBJECT_ID_eDP
+ [31:24]- Reserved
+
+ulDDISlot2Config: Same as Slot1.
+ucMemoryType: SidePort memory type, set it to 0x0 when Sideport memory is not installed. Driver needs this info to change sideport memory clock. Not for display in CCC.
+For IGP, Hypermemory is the only memory type showed in CCC.
+
+ucUMAChannelNumber: how many channels for the UMA;
+
+ulDockingPinCFGInfo: [15:0]-Bus/Device/Function # to CFG to read this Docking Pin; [31:16]-reg offset in CFG to read this pin
+ucDockingPinBit: which bit in this register to read the pin status;
+ucDockingPinPolarity:Polarity of the pin when docked;
+
+ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, [7:0]=4:Pharaoh, other bits reserved for now and must be 0x0
+
+usNumberOfCyclesInPeriod:Indicate how many cycles when PWM duty is 100%.
+
+usMaxNBVoltage:Max. voltage control value in either PWM or GPIO mode.
+usMinNBVoltage:Min. voltage control value in either PWM or GPIO mode.
+ GPIO mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=0
+ PWM mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=1
+ GPU SW don't control mode: usMaxNBVoltage & usMinNBVoltage=0 and no care about ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE
+
+usBootUpNBVoltage:Boot-up voltage regulator dependent PWM value.
+
+
+ulHTLinkFreq: Bootup HT link Frequency in 10Khz.
+usMinHTLinkWidth: Bootup minimum HT link width. If CDLW disabled, this is equal to usMaxHTLinkWidth.
+ If CDLW enabled, both upstream and downstream width should be the same during bootup.
+usMaxHTLinkWidth: Bootup maximum HT link width. If CDLW disabled, this is equal to usMinHTLinkWidth.
+ If CDLW enabled, both upstream and downstream width should be the same during bootup.
+
+usUMASyncStartDelay: Memory access latency, required for watermark calculation
+usUMADataReturnTime: Memory access latency, required for watermark calculation
+usLinkStatusZeroTime:Memory access latency required for watermark calculation, set this to 0x0 for K8 CPU, set a proper value in 0.01 the unit of us
+for Griffin or Greyhound. SBIOS needs to convert to actual time by:
+ if T0Ttime [5:4]=00b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.1us (0.0 to 1.5us)
+ if T0Ttime [5:4]=01b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.5us (0.0 to 7.5us)
+ if T0Ttime [5:4]=10b, then usLinkStatusZeroTime=T0Ttime [3:0]*2.0us (0.0 to 30us)
+ if T0Ttime [5:4]=11b, and T0Ttime [3:0]=0x0 to 0xa, then usLinkStatusZeroTime=T0Ttime [3:0]*20us (0.0 to 200us)
+
+ulHighVoltageHTLinkFreq: HT link frequency for power state with low voltage. If boot up runs in HT1, this must be 0.
+ This must be less than or equal to ulHTLinkFreq(bootup frequency).
+ulLowVoltageHTLinkFreq: HT link frequency for power state with low voltage or voltage scaling 1.0v~1.1v. If boot up runs in HT1, this must be 0.
+ This must be less than or equal to ulHighVoltageHTLinkFreq.
+
+usMaxUpStreamHTLinkWidth: Asymmetric link width support in the future, to replace usMaxHTLinkWidth. Not used for now.
+usMaxDownStreamHTLinkWidth: same as above.
+usMinUpStreamHTLinkWidth: Asymmetric link width support in the future, to replace usMinHTLinkWidth. Not used for now.
+usMinDownStreamHTLinkWidth: same as above.
+*/
+
+// ATOM_INTEGRATED_SYSTEM_INFO::ulCPUCapInfo - CPU type definition
+#define INTEGRATED_SYSTEM_INFO__UNKNOWN_CPU 0
+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__GRIFFIN 1
+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__GREYHOUND 2
+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__K8 3
+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__PHARAOH 4
+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__OROCHI 5
+
+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__MAX_CODE INTEGRATED_SYSTEM_INFO__AMD_CPU__OROCHI // this deff reflects max defined CPU code
+
+#define SYSTEM_CONFIG_POWEREXPRESS_ENABLE 0x00000001
+#define SYSTEM_CONFIG_RUN_AT_OVERDRIVE_ENGINE 0x00000002
+#define SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE 0x00000004
+#define SYSTEM_CONFIG_PERFORMANCE_POWERSTATE_ONLY 0x00000008
+#define SYSTEM_CONFIG_CLMC_ENABLED 0x00000010
+#define SYSTEM_CONFIG_CDLW_ENABLED 0x00000020
+#define SYSTEM_CONFIG_HIGH_VOLTAGE_REQUESTED 0x00000040
+#define SYSTEM_CONFIG_CLMC_HYBRID_MODE_ENABLED 0x00000080
+#define SYSTEM_CONFIG_CDLF_ENABLED 0x00000100
+#define SYSTEM_CONFIG_DLL_SHUTDOWN_ENABLED 0x00000200
+
+#define IGP_DDI_SLOT_LANE_CONFIG_MASK 0x000000FF
+
+#define b0IGP_DDI_SLOT_LANE_MAP_MASK 0x0F
+#define b0IGP_DDI_SLOT_DOCKING_LANE_MAP_MASK 0xF0
+#define b0IGP_DDI_SLOT_CONFIG_LANE_0_3 0x01
+#define b0IGP_DDI_SLOT_CONFIG_LANE_4_7 0x02
+#define b0IGP_DDI_SLOT_CONFIG_LANE_8_11 0x04
+#define b0IGP_DDI_SLOT_CONFIG_LANE_12_15 0x08
+
+#define IGP_DDI_SLOT_ATTRIBUTE_MASK 0x0000FF00
+#define IGP_DDI_SLOT_CONFIG_REVERSED 0x00000100
+#define b1IGP_DDI_SLOT_CONFIG_REVERSED 0x01
+
+#define IGP_DDI_SLOT_CONNECTOR_TYPE_MASK 0x00FF0000
+
+// IntegratedSystemInfoTable new Rev is V5 after V2, because of the real rev of V2 is v1.4. This rev is used for RR
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V5
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulBootUpEngineClock; //in 10kHz unit
+ ULONG ulDentistVCOFreq; //Dentist VCO clock in 10kHz unit, the source of GPU SCLK, LCLK, UCLK and VCLK.
+ ULONG ulLClockFreq; //GPU Lclk freq in 10kHz unit, have relationship with NCLK in NorthBridge
+ ULONG ulBootUpUMAClock; //in 10kHz unit
+ ULONG ulReserved1[8]; //must be 0x0 for the reserved
+ ULONG ulBootUpReqDisplayVector;
+ ULONG ulOtherDisplayMisc;
+ ULONG ulReserved2[4]; //must be 0x0 for the reserved
+ ULONG ulSystemConfig; //TBD
+ ULONG ulCPUCapInfo; //TBD
+ USHORT usMaxNBVoltage; //high NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse;
+ USHORT usMinNBVoltage; //low NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse;
+ USHORT usBootUpNBVoltage; //boot up NB voltage
+ UCHAR ucHtcTmpLmt; //bit [22:16] of D24F3x64 Hardware Thermal Control (HTC) Register, may not be needed, TBD
+ UCHAR ucTjOffset; //bit [28:22] of D24F3xE4 Thermtrip Status Register,may not be needed, TBD
+ ULONG ulReserved3[4]; //must be 0x0 for the reserved
+ ULONG ulDDISlot1Config; //see above ulDDISlot1Config definition
+ ULONG ulDDISlot2Config;
+ ULONG ulDDISlot3Config;
+ ULONG ulDDISlot4Config;
+ ULONG ulReserved4[4]; //must be 0x0 for the reserved
+ UCHAR ucMemoryType; //[3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved
+ UCHAR ucUMAChannelNumber;
+ USHORT usReserved;
+ ULONG ulReserved5[4]; //must be 0x0 for the reserved
+ ULONG ulCSR_M3_ARB_CNTL_DEFAULT[10];//arrays with values for CSR M3 arbiter for default
+ ULONG ulCSR_M3_ARB_CNTL_UVD[10]; //arrays with values for CSR M3 arbiter for UVD playback
+ ULONG ulCSR_M3_ARB_CNTL_FS3D[10];//arrays with values for CSR M3 arbiter for Full Screen 3D applications
+ ULONG ulReserved6[61]; //must be 0x0
+}ATOM_INTEGRATED_SYSTEM_INFO_V5;
+
+
+
+/****************************************************************************/
+// Structure used in GPUVirtualizationInfoTable
+/****************************************************************************/
+typedef struct _ATOM_GPU_VIRTUALIZATION_INFO_V2_1
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulMCUcodeRomStartAddr;
+ ULONG ulMCUcodeLength;
+ ULONG ulSMCUcodeRomStartAddr;
+ ULONG ulSMCUcodeLength;
+ ULONG ulRLCVUcodeRomStartAddr;
+ ULONG ulRLCVUcodeLength;
+ ULONG ulTOCUcodeStartAddr;
+ ULONG ulTOCUcodeLength;
+ ULONG ulSMCPatchTableStartAddr;
+ ULONG ulSmcPatchTableLength;
+ ULONG ulSystemFlag;
+}ATOM_GPU_VIRTUALIZATION_INFO_V2_1;
+
+
+#define ATOM_CRT_INT_ENCODER1_INDEX 0x00000000
+#define ATOM_LCD_INT_ENCODER1_INDEX 0x00000001
+#define ATOM_TV_INT_ENCODER1_INDEX 0x00000002
+#define ATOM_DFP_INT_ENCODER1_INDEX 0x00000003
+#define ATOM_CRT_INT_ENCODER2_INDEX 0x00000004
+#define ATOM_LCD_EXT_ENCODER1_INDEX 0x00000005
+#define ATOM_TV_EXT_ENCODER1_INDEX 0x00000006
+#define ATOM_DFP_EXT_ENCODER1_INDEX 0x00000007
+#define ATOM_CV_INT_ENCODER1_INDEX 0x00000008
+#define ATOM_DFP_INT_ENCODER2_INDEX 0x00000009
+#define ATOM_CRT_EXT_ENCODER1_INDEX 0x0000000A
+#define ATOM_CV_EXT_ENCODER1_INDEX 0x0000000B
+#define ATOM_DFP_INT_ENCODER3_INDEX 0x0000000C
+#define ATOM_DFP_INT_ENCODER4_INDEX 0x0000000D
+
+// define ASIC internal encoder id ( bit vector ), used for CRTC_SourceSelTable
+#define ASIC_INT_DAC1_ENCODER_ID 0x00
+#define ASIC_INT_TV_ENCODER_ID 0x02
+#define ASIC_INT_DIG1_ENCODER_ID 0x03
+#define ASIC_INT_DAC2_ENCODER_ID 0x04
+#define ASIC_EXT_TV_ENCODER_ID 0x06
+#define ASIC_INT_DVO_ENCODER_ID 0x07
+#define ASIC_INT_DIG2_ENCODER_ID 0x09
+#define ASIC_EXT_DIG_ENCODER_ID 0x05
+#define ASIC_EXT_DIG2_ENCODER_ID 0x08
+#define ASIC_INT_DIG3_ENCODER_ID 0x0a
+#define ASIC_INT_DIG4_ENCODER_ID 0x0b
+#define ASIC_INT_DIG5_ENCODER_ID 0x0c
+#define ASIC_INT_DIG6_ENCODER_ID 0x0d
+#define ASIC_INT_DIG7_ENCODER_ID 0x0e
+
+//define Encoder attribute
+#define ATOM_ANALOG_ENCODER 0
+#define ATOM_DIGITAL_ENCODER 1
+#define ATOM_DP_ENCODER 2
+
+#define ATOM_ENCODER_ENUM_MASK 0x70
+#define ATOM_ENCODER_ENUM_ID1 0x00
+#define ATOM_ENCODER_ENUM_ID2 0x10
+#define ATOM_ENCODER_ENUM_ID3 0x20
+#define ATOM_ENCODER_ENUM_ID4 0x30
+#define ATOM_ENCODER_ENUM_ID5 0x40
+#define ATOM_ENCODER_ENUM_ID6 0x50
+
+#define ATOM_DEVICE_CRT1_INDEX 0x00000000
+#define ATOM_DEVICE_LCD1_INDEX 0x00000001
+#define ATOM_DEVICE_TV1_INDEX 0x00000002
+#define ATOM_DEVICE_DFP1_INDEX 0x00000003
+#define ATOM_DEVICE_CRT2_INDEX 0x00000004
+#define ATOM_DEVICE_LCD2_INDEX 0x00000005
+#define ATOM_DEVICE_DFP6_INDEX 0x00000006
+#define ATOM_DEVICE_DFP2_INDEX 0x00000007
+#define ATOM_DEVICE_CV_INDEX 0x00000008
+#define ATOM_DEVICE_DFP3_INDEX 0x00000009
+#define ATOM_DEVICE_DFP4_INDEX 0x0000000A
+#define ATOM_DEVICE_DFP5_INDEX 0x0000000B
+
+#define ATOM_DEVICE_RESERVEDC_INDEX 0x0000000C
+#define ATOM_DEVICE_RESERVEDD_INDEX 0x0000000D
+#define ATOM_DEVICE_RESERVEDE_INDEX 0x0000000E
+#define ATOM_DEVICE_RESERVEDF_INDEX 0x0000000F
+#define ATOM_MAX_SUPPORTED_DEVICE_INFO (ATOM_DEVICE_DFP3_INDEX+1)
+#define ATOM_MAX_SUPPORTED_DEVICE_INFO_2 ATOM_MAX_SUPPORTED_DEVICE_INFO
+#define ATOM_MAX_SUPPORTED_DEVICE_INFO_3 (ATOM_DEVICE_DFP5_INDEX + 1 )
+
+#define ATOM_MAX_SUPPORTED_DEVICE (ATOM_DEVICE_RESERVEDF_INDEX+1)
+
+#define ATOM_DEVICE_CRT1_SUPPORT (0x1L << ATOM_DEVICE_CRT1_INDEX )
+#define ATOM_DEVICE_LCD1_SUPPORT (0x1L << ATOM_DEVICE_LCD1_INDEX )
+#define ATOM_DEVICE_TV1_SUPPORT (0x1L << ATOM_DEVICE_TV1_INDEX )
+#define ATOM_DEVICE_DFP1_SUPPORT (0x1L << ATOM_DEVICE_DFP1_INDEX )
+#define ATOM_DEVICE_CRT2_SUPPORT (0x1L << ATOM_DEVICE_CRT2_INDEX )
+#define ATOM_DEVICE_LCD2_SUPPORT (0x1L << ATOM_DEVICE_LCD2_INDEX )
+#define ATOM_DEVICE_DFP6_SUPPORT (0x1L << ATOM_DEVICE_DFP6_INDEX )
+#define ATOM_DEVICE_DFP2_SUPPORT (0x1L << ATOM_DEVICE_DFP2_INDEX )
+#define ATOM_DEVICE_CV_SUPPORT (0x1L << ATOM_DEVICE_CV_INDEX )
+#define ATOM_DEVICE_DFP3_SUPPORT (0x1L << ATOM_DEVICE_DFP3_INDEX )
+#define ATOM_DEVICE_DFP4_SUPPORT (0x1L << ATOM_DEVICE_DFP4_INDEX )
+#define ATOM_DEVICE_DFP5_SUPPORT (0x1L << ATOM_DEVICE_DFP5_INDEX )
+
+
+#define ATOM_DEVICE_CRT_SUPPORT (ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_CRT2_SUPPORT)
+#define ATOM_DEVICE_DFP_SUPPORT (ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | ATOM_DEVICE_DFP3_SUPPORT | ATOM_DEVICE_DFP4_SUPPORT | ATOM_DEVICE_DFP5_SUPPORT | ATOM_DEVICE_DFP6_SUPPORT)
+#define ATOM_DEVICE_TV_SUPPORT ATOM_DEVICE_TV1_SUPPORT
+#define ATOM_DEVICE_LCD_SUPPORT (ATOM_DEVICE_LCD1_SUPPORT | ATOM_DEVICE_LCD2_SUPPORT)
+
+#define ATOM_DEVICE_CONNECTOR_TYPE_MASK 0x000000F0
+#define ATOM_DEVICE_CONNECTOR_TYPE_SHIFT 0x00000004
+#define ATOM_DEVICE_CONNECTOR_VGA 0x00000001
+#define ATOM_DEVICE_CONNECTOR_DVI_I 0x00000002
+#define ATOM_DEVICE_CONNECTOR_DVI_D 0x00000003
+#define ATOM_DEVICE_CONNECTOR_DVI_A 0x00000004
+#define ATOM_DEVICE_CONNECTOR_SVIDEO 0x00000005
+#define ATOM_DEVICE_CONNECTOR_COMPOSITE 0x00000006
+#define ATOM_DEVICE_CONNECTOR_LVDS 0x00000007
+#define ATOM_DEVICE_CONNECTOR_DIGI_LINK 0x00000008
+#define ATOM_DEVICE_CONNECTOR_SCART 0x00000009
+#define ATOM_DEVICE_CONNECTOR_HDMI_TYPE_A 0x0000000A
+#define ATOM_DEVICE_CONNECTOR_HDMI_TYPE_B 0x0000000B
+#define ATOM_DEVICE_CONNECTOR_CASE_1 0x0000000E
+#define ATOM_DEVICE_CONNECTOR_DISPLAYPORT 0x0000000F
+
+
+#define ATOM_DEVICE_DAC_INFO_MASK 0x0000000F
+#define ATOM_DEVICE_DAC_INFO_SHIFT 0x00000000
+#define ATOM_DEVICE_DAC_INFO_NODAC 0x00000000
+#define ATOM_DEVICE_DAC_INFO_DACA 0x00000001
+#define ATOM_DEVICE_DAC_INFO_DACB 0x00000002
+#define ATOM_DEVICE_DAC_INFO_EXDAC 0x00000003
+
+#define ATOM_DEVICE_I2C_ID_NOI2C 0x00000000
+
+#define ATOM_DEVICE_I2C_LINEMUX_MASK 0x0000000F
+#define ATOM_DEVICE_I2C_LINEMUX_SHIFT 0x00000000
+
+#define ATOM_DEVICE_I2C_ID_MASK 0x00000070
+#define ATOM_DEVICE_I2C_ID_SHIFT 0x00000004
+#define ATOM_DEVICE_I2C_ID_IS_FOR_NON_MM_USE 0x00000001
+#define ATOM_DEVICE_I2C_ID_IS_FOR_MM_USE 0x00000002
+#define ATOM_DEVICE_I2C_ID_IS_FOR_SDVO_USE 0x00000003 //For IGP RS600
+#define ATOM_DEVICE_I2C_ID_IS_FOR_DAC_SCL 0x00000004 //For IGP RS690
+
+#define ATOM_DEVICE_I2C_HARDWARE_CAP_MASK 0x00000080
+#define ATOM_DEVICE_I2C_HARDWARE_CAP_SHIFT 0x00000007
+#define ATOM_DEVICE_USES_SOFTWARE_ASSISTED_I2C 0x00000000
+#define ATOM_DEVICE_USES_HARDWARE_ASSISTED_I2C 0x00000001
+
+// usDeviceSupport:
+// Bits0 = 0 - no CRT1 support= 1- CRT1 is supported
+// Bit 1 = 0 - no LCD1 support= 1- LCD1 is supported
+// Bit 2 = 0 - no TV1 support= 1- TV1 is supported
+// Bit 3 = 0 - no DFP1 support= 1- DFP1 is supported
+// Bit 4 = 0 - no CRT2 support= 1- CRT2 is supported
+// Bit 5 = 0 - no LCD2 support= 1- LCD2 is supported
+// Bit 6 = 0 - no DFP6 support= 1- DFP6 is supported
+// Bit 7 = 0 - no DFP2 support= 1- DFP2 is supported
+// Bit 8 = 0 - no CV support= 1- CV is supported
+// Bit 9 = 0 - no DFP3 support= 1- DFP3 is supported
+// Bit 10= 0 - no DFP4 support= 1- DFP4 is supported
+// Bit 11= 0 - no DFP5 support= 1- DFP5 is supported
+//
+//
+
+/****************************************************************************/
+// Structure used in MclkSS_InfoTable
+/****************************************************************************/
+// ucI2C_ConfigID
+// [7:0] - I2C LINE Associate ID
+// = 0 - no I2C
+// [7] - HW_Cap = 1, [6:0]=HW assisted I2C ID(HW line selection)
+// = 0, [6:0]=SW assisted I2C ID
+// [6-4] - HW_ENGINE_ID = 1, HW engine for NON multimedia use
+// = 2, HW engine for Multimedia use
+// = 3-7 Reserved for future I2C engines
+// [3-0] - I2C_LINE_MUX = A Mux number when it's HW assisted I2C or GPIO ID when it's SW I2C
+
+typedef struct _ATOM_I2C_ID_CONFIG
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR bfHW_Capable:1;
+ UCHAR bfHW_EngineID:3;
+ UCHAR bfI2C_LineMux:4;
+#else
+ UCHAR bfI2C_LineMux:4;
+ UCHAR bfHW_EngineID:3;
+ UCHAR bfHW_Capable:1;
+#endif
+}ATOM_I2C_ID_CONFIG;
+
+typedef union _ATOM_I2C_ID_CONFIG_ACCESS
+{
+ ATOM_I2C_ID_CONFIG sbfAccess;
+ UCHAR ucAccess;
+}ATOM_I2C_ID_CONFIG_ACCESS;
+
+
+/****************************************************************************/
+// Structure used in GPIO_I2C_InfoTable
+/****************************************************************************/
+typedef struct _ATOM_GPIO_I2C_ASSIGMENT
+{
+ USHORT usClkMaskRegisterIndex;
+ USHORT usClkEnRegisterIndex;
+ USHORT usClkY_RegisterIndex;
+ USHORT usClkA_RegisterIndex;
+ USHORT usDataMaskRegisterIndex;
+ USHORT usDataEnRegisterIndex;
+ USHORT usDataY_RegisterIndex;
+ USHORT usDataA_RegisterIndex;
+ ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;
+ UCHAR ucClkMaskShift;
+ UCHAR ucClkEnShift;
+ UCHAR ucClkY_Shift;
+ UCHAR ucClkA_Shift;
+ UCHAR ucDataMaskShift;
+ UCHAR ucDataEnShift;
+ UCHAR ucDataY_Shift;
+ UCHAR ucDataA_Shift;
+ UCHAR ucReserved1;
+ UCHAR ucReserved2;
+}ATOM_GPIO_I2C_ASSIGMENT;
+
+typedef struct _ATOM_GPIO_I2C_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_GPIO_I2C_ASSIGMENT asGPIO_Info[ATOM_MAX_SUPPORTED_DEVICE];
+}ATOM_GPIO_I2C_INFO;
+
+/****************************************************************************/
+// Common Structure used in other structures
+/****************************************************************************/
+
+#ifndef _H2INC
+
+//Please don't add or expand this bitfield structure below, this one will retire soon.!
+typedef struct _ATOM_MODE_MISC_INFO
+{
+#if ATOM_BIG_ENDIAN
+ USHORT Reserved:6;
+ USHORT RGB888:1;
+ USHORT DoubleClock:1;
+ USHORT Interlace:1;
+ USHORT CompositeSync:1;
+ USHORT V_ReplicationBy2:1;
+ USHORT H_ReplicationBy2:1;
+ USHORT VerticalCutOff:1;
+ USHORT VSyncPolarity:1; //0=Active High, 1=Active Low
+ USHORT HSyncPolarity:1; //0=Active High, 1=Active Low
+ USHORT HorizontalCutOff:1;
+#else
+ USHORT HorizontalCutOff:1;
+ USHORT HSyncPolarity:1; //0=Active High, 1=Active Low
+ USHORT VSyncPolarity:1; //0=Active High, 1=Active Low
+ USHORT VerticalCutOff:1;
+ USHORT H_ReplicationBy2:1;
+ USHORT V_ReplicationBy2:1;
+ USHORT CompositeSync:1;
+ USHORT Interlace:1;
+ USHORT DoubleClock:1;
+ USHORT RGB888:1;
+ USHORT Reserved:6;
+#endif
+}ATOM_MODE_MISC_INFO;
+
+typedef union _ATOM_MODE_MISC_INFO_ACCESS
+{
+ ATOM_MODE_MISC_INFO sbfAccess;
+ USHORT usAccess;
+}ATOM_MODE_MISC_INFO_ACCESS;
+
+#else
+
+typedef union _ATOM_MODE_MISC_INFO_ACCESS
+{
+ USHORT usAccess;
+}ATOM_MODE_MISC_INFO_ACCESS;
+
+#endif
+
+// usModeMiscInfo-
+#define ATOM_H_CUTOFF 0x01
+#define ATOM_HSYNC_POLARITY 0x02 //0=Active High, 1=Active Low
+#define ATOM_VSYNC_POLARITY 0x04 //0=Active High, 1=Active Low
+#define ATOM_V_CUTOFF 0x08
+#define ATOM_H_REPLICATIONBY2 0x10
+#define ATOM_V_REPLICATIONBY2 0x20
+#define ATOM_COMPOSITESYNC 0x40
+#define ATOM_INTERLACE 0x80
+#define ATOM_DOUBLE_CLOCK_MODE 0x100
+#define ATOM_RGB888_MODE 0x200
+
+//usRefreshRate-
+#define ATOM_REFRESH_43 43
+#define ATOM_REFRESH_47 47
+#define ATOM_REFRESH_56 56
+#define ATOM_REFRESH_60 60
+#define ATOM_REFRESH_65 65
+#define ATOM_REFRESH_70 70
+#define ATOM_REFRESH_72 72
+#define ATOM_REFRESH_75 75
+#define ATOM_REFRESH_85 85
+
+// ATOM_MODE_TIMING data are exactly the same as VESA timing data.
+// Translation from EDID to ATOM_MODE_TIMING, use the following formula.
+//
+// VESA_HTOTAL = VESA_ACTIVE + 2* VESA_BORDER + VESA_BLANK
+// = EDID_HA + EDID_HBL
+// VESA_HDISP = VESA_ACTIVE = EDID_HA
+// VESA_HSYNC_START = VESA_ACTIVE + VESA_BORDER + VESA_FRONT_PORCH
+// = EDID_HA + EDID_HSO
+// VESA_HSYNC_WIDTH = VESA_HSYNC_TIME = EDID_HSPW
+// VESA_BORDER = EDID_BORDER
+
+
+/****************************************************************************/
+// Structure used in SetCRTC_UsingDTDTimingTable
+/****************************************************************************/
+typedef struct _SET_CRTC_USING_DTD_TIMING_PARAMETERS
+{
+ USHORT usH_Size;
+ USHORT usH_Blanking_Time;
+ USHORT usV_Size;
+ USHORT usV_Blanking_Time;
+ USHORT usH_SyncOffset;
+ USHORT usH_SyncWidth;
+ USHORT usV_SyncOffset;
+ USHORT usV_SyncWidth;
+ ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
+ UCHAR ucH_Border; // From DFP EDID
+ UCHAR ucV_Border;
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucPadding[3];
+}SET_CRTC_USING_DTD_TIMING_PARAMETERS;
+
+/****************************************************************************/
+// Structure used in SetCRTC_TimingTable
+/****************************************************************************/
+typedef struct _SET_CRTC_TIMING_PARAMETERS
+{
+ USHORT usH_Total; // horizontal total
+ USHORT usH_Disp; // horizontal display
+ USHORT usH_SyncStart; // horozontal Sync start
+ USHORT usH_SyncWidth; // horizontal Sync width
+ USHORT usV_Total; // vertical total
+ USHORT usV_Disp; // vertical display
+ USHORT usV_SyncStart; // vertical Sync start
+ USHORT usV_SyncWidth; // vertical Sync width
+ ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
+ UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2
+ UCHAR ucOverscanRight; // right
+ UCHAR ucOverscanLeft; // left
+ UCHAR ucOverscanBottom; // bottom
+ UCHAR ucOverscanTop; // top
+ UCHAR ucReserved;
+}SET_CRTC_TIMING_PARAMETERS;
+#define SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION SET_CRTC_TIMING_PARAMETERS
+
+
+/****************************************************************************/
+// Structure used in StandardVESA_TimingTable
+// AnalogTV_InfoTable
+// ComponentVideoInfoTable
+/****************************************************************************/
+typedef struct _ATOM_MODE_TIMING
+{
+ USHORT usCRTC_H_Total;
+ USHORT usCRTC_H_Disp;
+ USHORT usCRTC_H_SyncStart;
+ USHORT usCRTC_H_SyncWidth;
+ USHORT usCRTC_V_Total;
+ USHORT usCRTC_V_Disp;
+ USHORT usCRTC_V_SyncStart;
+ USHORT usCRTC_V_SyncWidth;
+ USHORT usPixelClock; //in 10Khz unit
+ ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
+ USHORT usCRTC_OverscanRight;
+ USHORT usCRTC_OverscanLeft;
+ USHORT usCRTC_OverscanBottom;
+ USHORT usCRTC_OverscanTop;
+ USHORT usReserve;
+ UCHAR ucInternalModeNumber;
+ UCHAR ucRefreshRate;
+}ATOM_MODE_TIMING;
+
+typedef struct _ATOM_DTD_FORMAT
+{
+ USHORT usPixClk;
+ USHORT usHActive;
+ USHORT usHBlanking_Time;
+ USHORT usVActive;
+ USHORT usVBlanking_Time;
+ USHORT usHSyncOffset;
+ USHORT usHSyncWidth;
+ USHORT usVSyncOffset;
+ USHORT usVSyncWidth;
+ USHORT usImageHSize;
+ USHORT usImageVSize;
+ UCHAR ucHBorder;
+ UCHAR ucVBorder;
+ ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
+ UCHAR ucInternalModeNumber;
+ UCHAR ucRefreshRate;
+}ATOM_DTD_FORMAT;
+
+/****************************************************************************/
+// Structure used in LVDS_InfoTable
+// * Need a document to describe this table
+/****************************************************************************/
+#define SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004
+#define SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008
+#define SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010
+#define SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020
+#define SUPPORTED_LCD_REFRESHRATE_48Hz 0x0040
+
+//ucTableFormatRevision=1
+//ucTableContentRevision=1
+typedef struct _ATOM_LVDS_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_DTD_FORMAT sLCDTiming;
+ USHORT usModePatchTableOffset;
+ USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec.
+ USHORT usOffDelayInMs;
+ UCHAR ucPowerSequenceDigOntoDEin10Ms;
+ UCHAR ucPowerSequenceDEtoBLOnin10Ms;
+ UCHAR ucLVDS_Misc; // Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level}
+ // Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888}
+ // Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled}
+ // Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled}
+ UCHAR ucPanelDefaultRefreshRate;
+ UCHAR ucPanelIdentification;
+ UCHAR ucSS_Id;
+}ATOM_LVDS_INFO;
+
+//ucTableFormatRevision=1
+//ucTableContentRevision=2
+typedef struct _ATOM_LVDS_INFO_V12
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_DTD_FORMAT sLCDTiming;
+ USHORT usExtInfoTableOffset;
+ USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec.
+ USHORT usOffDelayInMs;
+ UCHAR ucPowerSequenceDigOntoDEin10Ms;
+ UCHAR ucPowerSequenceDEtoBLOnin10Ms;
+ UCHAR ucLVDS_Misc; // Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level}
+ // Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888}
+ // Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled}
+ // Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled}
+ UCHAR ucPanelDefaultRefreshRate;
+ UCHAR ucPanelIdentification;
+ UCHAR ucSS_Id;
+ USHORT usLCDVenderID;
+ USHORT usLCDProductID;
+ UCHAR ucLCDPanel_SpecialHandlingCap;
+ UCHAR ucPanelInfoSize; // start from ATOM_DTD_FORMAT to end of panel info, include ExtInfoTable
+ UCHAR ucReserved[2];
+}ATOM_LVDS_INFO_V12;
+
+//Definitions for ucLCDPanel_SpecialHandlingCap:
+
+//Once DAL sees this CAP is set, it will read EDID from LCD on its own instead of using sLCDTiming in ATOM_LVDS_INFO_V12.
+//Other entries in ATOM_LVDS_INFO_V12 are still valid/useful to DAL
+#define LCDPANEL_CAP_READ_EDID 0x1
+
+//If a design supports DRR (dynamic refresh rate) on internal panels (LVDS or EDP), this cap is set in ucLCDPanel_SpecialHandlingCap together
+//with multiple supported refresh rates@usSupportedRefreshRate. This cap should not be set when only slow refresh rate is supported (static
+//refresh rate switch by SW. This is only valid from ATOM_LVDS_INFO_V12
+#define LCDPANEL_CAP_DRR_SUPPORTED 0x2
+
+//Use this cap bit for a quick reference whether an embadded panel (LCD1 ) is LVDS or eDP.
+#define LCDPANEL_CAP_eDP 0x4
+
+
+//Color Bit Depth definition in EDID V1.4 @BYTE 14h
+//Bit 6 5 4
+ // 0 0 0 - Color bit depth is undefined
+ // 0 0 1 - 6 Bits per Primary Color
+ // 0 1 0 - 8 Bits per Primary Color
+ // 0 1 1 - 10 Bits per Primary Color
+ // 1 0 0 - 12 Bits per Primary Color
+ // 1 0 1 - 14 Bits per Primary Color
+ // 1 1 0 - 16 Bits per Primary Color
+ // 1 1 1 - Reserved
+
+#define PANEL_COLOR_BIT_DEPTH_MASK 0x70
+
+// Bit7:{=0:Random Dithering disabled;1 Random Dithering enabled}
+#define PANEL_RANDOM_DITHER 0x80
+#define PANEL_RANDOM_DITHER_MASK 0x80
+
+#define ATOM_LVDS_INFO_LAST ATOM_LVDS_INFO_V12 // no need to change this
+
+
+typedef struct _ATOM_LCD_REFRESH_RATE_SUPPORT
+{
+ UCHAR ucSupportedRefreshRate;
+ UCHAR ucMinRefreshRateForDRR;
+}ATOM_LCD_REFRESH_RATE_SUPPORT;
+
+/****************************************************************************/
+// Structures used by LCD_InfoTable V1.3 Note: previous version was called ATOM_LVDS_INFO_V12
+// ASIC Families: NI
+// ucTableFormatRevision=1
+// ucTableContentRevision=3
+/****************************************************************************/
+typedef struct _ATOM_LCD_INFO_V13
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_DTD_FORMAT sLCDTiming;
+ USHORT usExtInfoTableOffset;
+ union
+ {
+ USHORT usSupportedRefreshRate;
+ ATOM_LCD_REFRESH_RATE_SUPPORT sRefreshRateSupport;
+ };
+ ULONG ulReserved0;
+ UCHAR ucLCD_Misc; // Reorganized in V13
+ // Bit0: {=0:single, =1:dual},
+ // Bit1: {=0:LDI format for RGB888, =1 FPDI format for RGB888} // was {=0:666RGB, =1:888RGB},
+ // Bit3:2: {Grey level}
+ // Bit6:4 Color Bit Depth definition (see below definition in EDID V1.4 @BYTE 14h)
+ // Bit7 Reserved. was for ATOM_PANEL_MISC_API_ENABLED, still need it?
+ UCHAR ucPanelDefaultRefreshRate;
+ UCHAR ucPanelIdentification;
+ UCHAR ucSS_Id;
+ USHORT usLCDVenderID;
+ USHORT usLCDProductID;
+ UCHAR ucLCDPanel_SpecialHandlingCap; // Reorganized in V13
+ // Bit0: Once DAL sees this CAP is set, it will read EDID from LCD on its own
+ // Bit1: See LCDPANEL_CAP_DRR_SUPPORTED
+ // Bit2: a quick reference whether an embadded panel (LCD1 ) is LVDS (0) or eDP (1)
+ // Bit7-3: Reserved
+ UCHAR ucPanelInfoSize; // start from ATOM_DTD_FORMAT to end of panel info, include ExtInfoTable
+ USHORT usBacklightPWM; // Backlight PWM in Hz. New in _V13
+
+ UCHAR ucPowerSequenceDIGONtoDE_in4Ms;
+ UCHAR ucPowerSequenceDEtoVARY_BL_in4Ms;
+ UCHAR ucPowerSequenceVARY_BLtoDE_in4Ms;
+ UCHAR ucPowerSequenceDEtoDIGON_in4Ms;
+
+ UCHAR ucOffDelay_in4Ms;
+ UCHAR ucPowerSequenceVARY_BLtoBLON_in4Ms;
+ UCHAR ucPowerSequenceBLONtoVARY_BL_in4Ms;
+ UCHAR ucReserved1;
+
+ UCHAR ucDPCD_eDP_CONFIGURATION_CAP; // dpcd 0dh
+ UCHAR ucDPCD_MAX_LINK_RATE; // dpcd 01h
+ UCHAR ucDPCD_MAX_LANE_COUNT; // dpcd 02h
+ UCHAR ucDPCD_MAX_DOWNSPREAD; // dpcd 03h
+
+ USHORT usMaxPclkFreqInSingleLink; // Max PixelClock frequency in single link mode.
+ UCHAR uceDPToLVDSRxId;
+ UCHAR ucLcdReservd;
+ ULONG ulReserved[2];
+}ATOM_LCD_INFO_V13;
+
+#define ATOM_LCD_INFO_LAST ATOM_LCD_INFO_V13
+
+//Definitions for ucLCD_Misc
+#define ATOM_PANEL_MISC_V13_DUAL 0x00000001
+#define ATOM_PANEL_MISC_V13_FPDI 0x00000002
+#define ATOM_PANEL_MISC_V13_GREY_LEVEL 0x0000000C
+#define ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT 2
+#define ATOM_PANEL_MISC_V13_COLOR_BIT_DEPTH_MASK 0x70
+#define ATOM_PANEL_MISC_V13_6BIT_PER_COLOR 0x10
+#define ATOM_PANEL_MISC_V13_8BIT_PER_COLOR 0x20
+
+//Color Bit Depth definition in EDID V1.4 @BYTE 14h
+//Bit 6 5 4
+ // 0 0 0 - Color bit depth is undefined
+ // 0 0 1 - 6 Bits per Primary Color
+ // 0 1 0 - 8 Bits per Primary Color
+ // 0 1 1 - 10 Bits per Primary Color
+ // 1 0 0 - 12 Bits per Primary Color
+ // 1 0 1 - 14 Bits per Primary Color
+ // 1 1 0 - 16 Bits per Primary Color
+ // 1 1 1 - Reserved
+
+//Definitions for ucLCDPanel_SpecialHandlingCap:
+
+//Once DAL sees this CAP is set, it will read EDID from LCD on its own instead of using sLCDTiming in ATOM_LVDS_INFO_V12.
+//Other entries in ATOM_LVDS_INFO_V12 are still valid/useful to DAL
+#define LCDPANEL_CAP_V13_READ_EDID 0x1 // = LCDPANEL_CAP_READ_EDID no change comparing to previous version
+
+//If a design supports DRR (dynamic refresh rate) on internal panels (LVDS or EDP), this cap is set in ucLCDPanel_SpecialHandlingCap together
+//with multiple supported refresh rates@usSupportedRefreshRate. This cap should not be set when only slow refresh rate is supported (static
+//refresh rate switch by SW. This is only valid from ATOM_LVDS_INFO_V12
+#define LCDPANEL_CAP_V13_DRR_SUPPORTED 0x2 // = LCDPANEL_CAP_DRR_SUPPORTED no change comparing to previous version
+
+//Use this cap bit for a quick reference whether an embadded panel (LCD1 ) is LVDS or eDP.
+#define LCDPANEL_CAP_V13_eDP 0x4 // = LCDPANEL_CAP_eDP no change comparing to previous version
+
+//uceDPToLVDSRxId
+#define eDP_TO_LVDS_RX_DISABLE 0x00 // no eDP->LVDS translator chip
+#define eDP_TO_LVDS_COMMON_ID 0x01 // common eDP->LVDS translator chip without AMD SW init
+#define eDP_TO_LVDS_RT_ID 0x02 // RT tansaltor which require AMD SW init
+
+typedef struct _ATOM_PATCH_RECORD_MODE
+{
+ UCHAR ucRecordType;
+ USHORT usHDisp;
+ USHORT usVDisp;
+}ATOM_PATCH_RECORD_MODE;
+
+typedef struct _ATOM_LCD_RTS_RECORD
+{
+ UCHAR ucRecordType;
+ UCHAR ucRTSValue;
+}ATOM_LCD_RTS_RECORD;
+
+//!! If the record below exits, it shoud always be the first record for easy use in command table!!!
+// The record below is only used when LVDS_Info is present. From ATOM_LVDS_INFO_V12, use ucLCDPanel_SpecialHandlingCap instead.
+typedef struct _ATOM_LCD_MODE_CONTROL_CAP
+{
+ UCHAR ucRecordType;
+ USHORT usLCDCap;
+}ATOM_LCD_MODE_CONTROL_CAP;
+
+#define LCD_MODE_CAP_BL_OFF 1
+#define LCD_MODE_CAP_CRTC_OFF 2
+#define LCD_MODE_CAP_PANEL_OFF 4
+
+
+typedef struct _ATOM_FAKE_EDID_PATCH_RECORD
+{
+ UCHAR ucRecordType;
+ UCHAR ucFakeEDIDLength; // = 128 means EDID lenght is 128 bytes, otherwise the EDID length = ucFakeEDIDLength*128
+ UCHAR ucFakeEDIDString[1]; // This actually has ucFakeEdidLength elements.
+} ATOM_FAKE_EDID_PATCH_RECORD;
+
+typedef struct _ATOM_PANEL_RESOLUTION_PATCH_RECORD
+{
+ UCHAR ucRecordType;
+ USHORT usHSize;
+ USHORT usVSize;
+}ATOM_PANEL_RESOLUTION_PATCH_RECORD;
+
+#define LCD_MODE_PATCH_RECORD_MODE_TYPE 1
+#define LCD_RTS_RECORD_TYPE 2
+#define LCD_CAP_RECORD_TYPE 3
+#define LCD_FAKE_EDID_PATCH_RECORD_TYPE 4
+#define LCD_PANEL_RESOLUTION_RECORD_TYPE 5
+#define LCD_EDID_OFFSET_PATCH_RECORD_TYPE 6
+#define ATOM_RECORD_END_TYPE 0xFF
+
+/****************************Spread Spectrum Info Table Definitions **********************/
+
+//ucTableFormatRevision=1
+//ucTableContentRevision=2
+typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT
+{
+ USHORT usSpreadSpectrumPercentage;
+ UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Bit2=1: PCIE REFCLK SS =0 iternal PPLL SS Others:TBD
+ UCHAR ucSS_Step;
+ UCHAR ucSS_Delay;
+ UCHAR ucSS_Id;
+ UCHAR ucRecommendedRef_Div;
+ UCHAR ucSS_Range; //it was reserved for V11
+}ATOM_SPREAD_SPECTRUM_ASSIGNMENT;
+
+#define ATOM_MAX_SS_ENTRY 16
+#define ATOM_DP_SS_ID1 0x0f1 // SS ID for internal DP stream at 2.7Ghz. if ATOM_DP_SS_ID2 does not exist in SS_InfoTable, it is used for internal DP stream at 1.62Ghz as well.
+#define ATOM_DP_SS_ID2 0x0f2 // SS ID for internal DP stream at 1.62Ghz, if it exists in SS_InfoTable.
+#define ATOM_LVLINK_2700MHz_SS_ID 0x0f3 // SS ID for LV link translator chip at 2.7Ghz
+#define ATOM_LVLINK_1620MHz_SS_ID 0x0f4 // SS ID for LV link translator chip at 1.62Ghz
+
+
+
+#define ATOM_SS_DOWN_SPREAD_MODE_MASK 0x00000000
+#define ATOM_SS_DOWN_SPREAD_MODE 0x00000000
+#define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001
+#define ATOM_SS_CENTRE_SPREAD_MODE 0x00000001
+#define ATOM_INTERNAL_SS_MASK 0x00000000
+#define ATOM_EXTERNAL_SS_MASK 0x00000002
+#define EXEC_SS_STEP_SIZE_SHIFT 2
+#define EXEC_SS_DELAY_SHIFT 4
+#define ACTIVEDATA_TO_BLON_DELAY_SHIFT 4
+
+typedef struct _ATOM_SPREAD_SPECTRUM_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_SPREAD_SPECTRUM_ASSIGNMENT asSS_Info[ATOM_MAX_SS_ENTRY];
+}ATOM_SPREAD_SPECTRUM_INFO;
+
+
+/****************************************************************************/
+// Structure used in AnalogTV_InfoTable (Top level)
+/****************************************************************************/
+//ucTVBootUpDefaultStd definiton:
+
+//ATOM_TV_NTSC 1
+//ATOM_TV_NTSCJ 2
+//ATOM_TV_PAL 3
+//ATOM_TV_PALM 4
+//ATOM_TV_PALCN 5
+//ATOM_TV_PALN 6
+//ATOM_TV_PAL60 7
+//ATOM_TV_SECAM 8
+
+//ucTVSuppportedStd definition:
+#define NTSC_SUPPORT 0x1
+#define NTSCJ_SUPPORT 0x2
+
+#define PAL_SUPPORT 0x4
+#define PALM_SUPPORT 0x8
+#define PALCN_SUPPORT 0x10
+#define PALN_SUPPORT 0x20
+#define PAL60_SUPPORT 0x40
+#define SECAM_SUPPORT 0x80
+
+#define MAX_SUPPORTED_TV_TIMING 2
+
+typedef struct _ATOM_ANALOG_TV_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucTV_SuppportedStandard;
+ UCHAR ucTV_BootUpDefaultStandard;
+ UCHAR ucExt_TV_ASIC_ID;
+ UCHAR ucExt_TV_ASIC_SlaveAddr;
+ ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_TV_TIMING];
+}ATOM_ANALOG_TV_INFO;
+
+typedef struct _ATOM_DPCD_INFO
+{
+ UCHAR ucRevisionNumber; //10h : Revision 1.0; 11h : Revision 1.1
+ UCHAR ucMaxLinkRate; //06h : 1.62Gbps per lane; 0Ah = 2.7Gbps per lane
+ UCHAR ucMaxLane; //Bits 4:0 = MAX_LANE_COUNT (1/2/4). Bit 7 = ENHANCED_FRAME_CAP
+ UCHAR ucMaxDownSpread; //Bit0 = 0: No Down spread; Bit0 = 1: 0.5% (Subject to change according to DP spec)
+}ATOM_DPCD_INFO;
+
+#define ATOM_DPCD_MAX_LANE_MASK 0x1F
+
+/**************************************************************************/
+// VRAM usage and their defintions
+
+// One chunk of VRAM used by Bios are for HWICON surfaces,EDID data.
+// Current Mode timing and Dail Timing and/or STD timing data EACH device. They can be broken down as below.
+// All the addresses below are the offsets from the frame buffer start.They all MUST be Dword aligned!
+// To driver: The physical address of this memory portion=mmFB_START(4K aligned)+ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR
+// To Bios: ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR->MM_INDEX
+
+// Moved VESA_MEMORY_IN_64K_BLOCK definition to "AtomConfig.h" so that it can be redefined in design (SKU).
+//#ifndef VESA_MEMORY_IN_64K_BLOCK
+//#define VESA_MEMORY_IN_64K_BLOCK 0x100 //256*64K=16Mb (Max. VESA memory is 16Mb!)
+//#endif
+
+#define ATOM_EDID_RAW_DATASIZE 256 //In Bytes
+#define ATOM_HWICON_SURFACE_SIZE 4096 //In Bytes
+#define ATOM_HWICON_INFOTABLE_SIZE 32
+#define MAX_DTD_MODE_IN_VRAM 6
+#define ATOM_DTD_MODE_SUPPORT_TBL_SIZE (MAX_DTD_MODE_IN_VRAM*28) //28= (SIZEOF ATOM_DTD_FORMAT)
+#define ATOM_STD_MODE_SUPPORT_TBL_SIZE 32*8 //32 is a predefined number,8= (SIZEOF ATOM_STD_FORMAT)
+//20 bytes for Encoder Type and DPCD in STD EDID area
+#define DFP_ENCODER_TYPE_OFFSET (ATOM_EDID_RAW_DATASIZE + ATOM_DTD_MODE_SUPPORT_TBL_SIZE + ATOM_STD_MODE_SUPPORT_TBL_SIZE - 20)
+#define ATOM_DP_DPCD_OFFSET (DFP_ENCODER_TYPE_OFFSET + 4 )
+
+#define ATOM_HWICON1_SURFACE_ADDR 0
+#define ATOM_HWICON2_SURFACE_ADDR (ATOM_HWICON1_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE)
+#define ATOM_HWICON_INFOTABLE_ADDR (ATOM_HWICON2_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE)
+#define ATOM_CRT1_EDID_ADDR (ATOM_HWICON_INFOTABLE_ADDR + ATOM_HWICON_INFOTABLE_SIZE)
+#define ATOM_CRT1_DTD_MODE_TBL_ADDR (ATOM_CRT1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_CRT1_STD_MODE_TBL_ADDR (ATOM_CRT1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_LCD1_EDID_ADDR (ATOM_CRT1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_LCD1_DTD_MODE_TBL_ADDR (ATOM_LCD1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_LCD1_STD_MODE_TBL_ADDR (ATOM_LCD1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_TV1_DTD_MODE_TBL_ADDR (ATOM_LCD1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DFP1_EDID_ADDR (ATOM_TV1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP1_DTD_MODE_TBL_ADDR (ATOM_DFP1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_DFP1_STD_MODE_TBL_ADDR (ATOM_DFP1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_CRT2_EDID_ADDR (ATOM_DFP1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_CRT2_DTD_MODE_TBL_ADDR (ATOM_CRT2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_CRT2_STD_MODE_TBL_ADDR (ATOM_CRT2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_LCD2_EDID_ADDR (ATOM_CRT2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_LCD2_DTD_MODE_TBL_ADDR (ATOM_LCD2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_LCD2_STD_MODE_TBL_ADDR (ATOM_LCD2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DFP6_EDID_ADDR (ATOM_LCD2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP6_DTD_MODE_TBL_ADDR (ATOM_DFP6_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_DFP6_STD_MODE_TBL_ADDR (ATOM_DFP6_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DFP2_EDID_ADDR (ATOM_DFP6_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP2_DTD_MODE_TBL_ADDR (ATOM_DFP2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_DFP2_STD_MODE_TBL_ADDR (ATOM_DFP2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_CV_EDID_ADDR (ATOM_DFP2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_CV_DTD_MODE_TBL_ADDR (ATOM_CV_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_CV_STD_MODE_TBL_ADDR (ATOM_CV_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DFP3_EDID_ADDR (ATOM_CV_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP3_DTD_MODE_TBL_ADDR (ATOM_DFP3_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_DFP3_STD_MODE_TBL_ADDR (ATOM_DFP3_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DFP4_EDID_ADDR (ATOM_DFP3_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP4_DTD_MODE_TBL_ADDR (ATOM_DFP4_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_DFP4_STD_MODE_TBL_ADDR (ATOM_DFP4_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DFP5_EDID_ADDR (ATOM_DFP4_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP5_DTD_MODE_TBL_ADDR (ATOM_DFP5_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_DFP5_STD_MODE_TBL_ADDR (ATOM_DFP5_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR + 1024)
+#define ATOM_STACK_STORAGE_END ATOM_STACK_STORAGE_START + 512
+
+//The size below is in Kb!
+#define ATOM_VRAM_RESERVE_SIZE ((((ATOM_STACK_STORAGE_END - ATOM_HWICON1_SURFACE_ADDR)>>10)+4)&0xFFFC)
+
+#define ATOM_VRAM_RESERVE_V2_SIZE 32
+
+#define ATOM_VRAM_OPERATION_FLAGS_MASK 0xC0000000L
+#define ATOM_VRAM_OPERATION_FLAGS_SHIFT 30
+#define ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION 0x1
+#define ATOM_VRAM_BLOCK_NEEDS_RESERVATION 0x0
+
+/***********************************************************************************/
+// Structure used in VRAM_UsageByFirmwareTable
+// Note1: This table is filled by SetBiosReservationStartInFB in CoreCommSubs.asm
+// at running time.
+// note2: From RV770, the memory is more than 32bit addressable, so we will change
+// ucTableFormatRevision=1,ucTableContentRevision=4, the strcuture remains
+// exactly same as 1.1 and 1.2 (1.3 is never in use), but ulStartAddrUsedByFirmware
+// (in offset to start of memory address) is KB aligned instead of byte aligend.
+// Note3:
+/* If we change usReserved to "usFBUsedbyDrvInKB", then to VBIOS this usFBUsedbyDrvInKB is a predefined, unchanged
+constant across VGA or non VGA adapter,
+for CAIL, The size of FB access area is known, only thing missing is the Offset of FB Access area, so we can have:
+
+If (ulStartAddrUsedByFirmware!=0)
+FBAccessAreaOffset= ulStartAddrUsedByFirmware - usFBUsedbyDrvInKB;
+Reserved area has been claimed by VBIOS including this FB access area; CAIL doesn't need to reserve any extra area for this purpose
+else //Non VGA case
+ if (FB_Size<=2Gb)
+ FBAccessAreaOffset= FB_Size - usFBUsedbyDrvInKB;
+ else
+ FBAccessAreaOffset= Aper_Size - usFBUsedbyDrvInKB
+
+CAIL needs to claim an reserved area defined by FBAccessAreaOffset and usFBUsedbyDrvInKB in non VGA case.*/
+
+/***********************************************************************************/
+#define ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO 1
+
+typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO
+{
+ ULONG ulStartAddrUsedByFirmware;
+ USHORT usFirmwareUseInKb;
+ USHORT usReserved;
+}ATOM_FIRMWARE_VRAM_RESERVE_INFO;
+
+typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_FIRMWARE_VRAM_RESERVE_INFO asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO];
+}ATOM_VRAM_USAGE_BY_FIRMWARE;
+
+// change verion to 1.5, when allow driver to allocate the vram area for command table access.
+typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO_V1_5
+{
+ ULONG ulStartAddrUsedByFirmware;
+ USHORT usFirmwareUseInKb;
+ USHORT usFBUsedByDrvInKb;
+}ATOM_FIRMWARE_VRAM_RESERVE_INFO_V1_5;
+
+typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE_V1_5
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_FIRMWARE_VRAM_RESERVE_INFO_V1_5 asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO];
+}ATOM_VRAM_USAGE_BY_FIRMWARE_V1_5;
+
+/****************************************************************************/
+// Structure used in GPIO_Pin_LUTTable
+/****************************************************************************/
+typedef struct _ATOM_GPIO_PIN_ASSIGNMENT
+{
+ USHORT usGpioPin_AIndex;
+ UCHAR ucGpioPinBitShift;
+ UCHAR ucGPIO_ID;
+}ATOM_GPIO_PIN_ASSIGNMENT;
+
+//ucGPIO_ID pre-define id for multiple usage
+// GPIO use to control PCIE_VDDC in certain SLT board
+#define PCIE_VDDC_CONTROL_GPIO_PINID 56
+
+//from SMU7.x, if ucGPIO_ID=PP_AC_DC_SWITCH_GPIO_PINID in GPIO_LUTTable, AC/DC swithing feature is enable
+#define PP_AC_DC_SWITCH_GPIO_PINID 60
+//from SMU7.x, if ucGPIO_ID=VDDC_REGULATOR_VRHOT_GPIO_PINID in GPIO_LUTable, VRHot feature is enable
+#define VDDC_VRHOT_GPIO_PINID 61
+//if ucGPIO_ID=VDDC_PCC_GPIO_PINID in GPIO_LUTable, Peak Current Control feature is enabled
+#define VDDC_PCC_GPIO_PINID 62
+// Only used on certain SLT/PA board to allow utility to cut Efuse.
+#define EFUSE_CUT_ENABLE_GPIO_PINID 63
+// ucGPIO=DRAM_SELF_REFRESH_GPIO_PIND uses for memory self refresh (ucGPIO=0, DRAM self-refresh; ucGPIO=
+#define DRAM_SELF_REFRESH_GPIO_PINID 64
+// Thermal interrupt output->system thermal chip GPIO pin
+#define THERMAL_INT_OUTPUT_GPIO_PINID 65
+
+
+typedef struct _ATOM_GPIO_PIN_LUT
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_GPIO_PIN_ASSIGNMENT asGPIO_Pin[1];
+}ATOM_GPIO_PIN_LUT;
+
+/****************************************************************************/
+// Structure used in ComponentVideoInfoTable
+/****************************************************************************/
+#define GPIO_PIN_ACTIVE_HIGH 0x1
+#define MAX_SUPPORTED_CV_STANDARDS 5
+
+// definitions for ATOM_D_INFO.ucSettings
+#define ATOM_GPIO_SETTINGS_BITSHIFT_MASK 0x1F // [4:0]
+#define ATOM_GPIO_SETTINGS_RESERVED_MASK 0x60 // [6:5] = must be zeroed out
+#define ATOM_GPIO_SETTINGS_ACTIVE_MASK 0x80 // [7]
+
+typedef struct _ATOM_GPIO_INFO
+{
+ USHORT usAOffset;
+ UCHAR ucSettings;
+ UCHAR ucReserved;
+}ATOM_GPIO_INFO;
+
+// definitions for ATOM_COMPONENT_VIDEO_INFO.ucMiscInfo (bit vector)
+#define ATOM_CV_RESTRICT_FORMAT_SELECTION 0x2
+
+// definitions for ATOM_COMPONENT_VIDEO_INFO.uc480i/uc480p/uc720p/uc1080i
+#define ATOM_GPIO_DEFAULT_MODE_EN 0x80 //[7];
+#define ATOM_GPIO_SETTING_PERMODE_MASK 0x7F //[6:0]
+
+// definitions for ATOM_COMPONENT_VIDEO_INFO.ucLetterBoxMode
+//Line 3 out put 5V.
+#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_A 0x01 //represent gpio 3 state for 16:9
+#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_B 0x02 //represent gpio 4 state for 16:9
+#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_SHIFT 0x0
+
+//Line 3 out put 2.2V
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_A 0x04 //represent gpio 3 state for 4:3 Letter box
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_B 0x08 //represent gpio 4 state for 4:3 Letter box
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_SHIFT 0x2
+
+//Line 3 out put 0V
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_A 0x10 //represent gpio 3 state for 4:3
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_B 0x20 //represent gpio 4 state for 4:3
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_SHIFT 0x4
+
+#define ATOM_CV_LINE3_ASPECTRATIO_MASK 0x3F // bit [5:0]
+
+#define ATOM_CV_LINE3_ASPECTRATIO_EXIST 0x80 //bit 7
+
+//GPIO bit index in gpio setting per mode value, also represend the block no. in gpio blocks.
+#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_A 3 //bit 3 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode.
+#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_B 4 //bit 4 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode.
+
+
+typedef struct _ATOM_COMPONENT_VIDEO_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMask_PinRegisterIndex;
+ USHORT usEN_PinRegisterIndex;
+ USHORT usY_PinRegisterIndex;
+ USHORT usA_PinRegisterIndex;
+ UCHAR ucBitShift;
+ UCHAR ucPinActiveState; //ucPinActiveState: Bit0=1 active high, =0 active low
+ ATOM_DTD_FORMAT sReserved; // must be zeroed out
+ UCHAR ucMiscInfo;
+ UCHAR uc480i;
+ UCHAR uc480p;
+ UCHAR uc720p;
+ UCHAR uc1080i;
+ UCHAR ucLetterBoxMode;
+ UCHAR ucReserved[3];
+ UCHAR ucNumOfWbGpioBlocks; //For Component video D-Connector support. If zere, NTSC type connector
+ ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS];
+ ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS];
+}ATOM_COMPONENT_VIDEO_INFO;
+
+//ucTableFormatRevision=2
+//ucTableContentRevision=1
+typedef struct _ATOM_COMPONENT_VIDEO_INFO_V21
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucMiscInfo;
+ UCHAR uc480i;
+ UCHAR uc480p;
+ UCHAR uc720p;
+ UCHAR uc1080i;
+ UCHAR ucReserved;
+ UCHAR ucLetterBoxMode;
+ UCHAR ucNumOfWbGpioBlocks; //For Component video D-Connector support. If zere, NTSC type connector
+ ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS];
+ ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS];
+}ATOM_COMPONENT_VIDEO_INFO_V21;
+
+#define ATOM_COMPONENT_VIDEO_INFO_LAST ATOM_COMPONENT_VIDEO_INFO_V21
+
+/****************************************************************************/
+// Structure used in object_InfoTable
+/****************************************************************************/
+typedef struct _ATOM_OBJECT_HEADER
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDeviceSupport;
+ USHORT usConnectorObjectTableOffset;
+ USHORT usRouterObjectTableOffset;
+ USHORT usEncoderObjectTableOffset;
+ USHORT usProtectionObjectTableOffset; //only available when Protection block is independent.
+ USHORT usDisplayPathTableOffset;
+}ATOM_OBJECT_HEADER;
+
+typedef struct _ATOM_OBJECT_HEADER_V3
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDeviceSupport;
+ USHORT usConnectorObjectTableOffset;
+ USHORT usRouterObjectTableOffset;
+ USHORT usEncoderObjectTableOffset;
+ USHORT usProtectionObjectTableOffset; //only available when Protection block is independent.
+ USHORT usDisplayPathTableOffset;
+ USHORT usMiscObjectTableOffset;
+}ATOM_OBJECT_HEADER_V3;
+
+
+typedef struct _ATOM_DISPLAY_OBJECT_PATH
+{
+ USHORT usDeviceTag; //supported device
+ USHORT usSize; //the size of ATOM_DISPLAY_OBJECT_PATH
+ USHORT usConnObjectId; //Connector Object ID
+ USHORT usGPUObjectId; //GPU ID
+ USHORT usGraphicObjIds[1]; //1st Encoder Obj source from GPU to last Graphic Obj destinate to connector.
+}ATOM_DISPLAY_OBJECT_PATH;
+
+typedef struct _ATOM_DISPLAY_EXTERNAL_OBJECT_PATH
+{
+ USHORT usDeviceTag; //supported device
+ USHORT usSize; //the size of ATOM_DISPLAY_OBJECT_PATH
+ USHORT usConnObjectId; //Connector Object ID
+ USHORT usGPUObjectId; //GPU ID
+ USHORT usGraphicObjIds[2]; //usGraphicObjIds[0]= GPU internal encoder, usGraphicObjIds[1]= external encoder
+}ATOM_DISPLAY_EXTERNAL_OBJECT_PATH;
+
+typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE
+{
+ UCHAR ucNumOfDispPath;
+ UCHAR ucVersion;
+ UCHAR ucPadding[2];
+ ATOM_DISPLAY_OBJECT_PATH asDispPath[1];
+}ATOM_DISPLAY_OBJECT_PATH_TABLE;
+
+typedef struct _ATOM_OBJECT //each object has this structure
+{
+ USHORT usObjectID;
+ USHORT usSrcDstTableOffset;
+ USHORT usRecordOffset; //this pointing to a bunch of records defined below
+ USHORT usReserved;
+}ATOM_OBJECT;
+
+typedef struct _ATOM_OBJECT_TABLE //Above 4 object table offset pointing to a bunch of objects all have this structure
+{
+ UCHAR ucNumberOfObjects;
+ UCHAR ucPadding[3];
+ ATOM_OBJECT asObjects[1];
+}ATOM_OBJECT_TABLE;
+
+typedef struct _ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT //usSrcDstTableOffset pointing to this structure
+{
+ UCHAR ucNumberOfSrc;
+ USHORT usSrcObjectID[1];
+ UCHAR ucNumberOfDst;
+ USHORT usDstObjectID[1];
+}ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT;
+
+
+//Two definitions below are for OPM on MXM module designs
+
+#define EXT_HPDPIN_LUTINDEX_0 0
+#define EXT_HPDPIN_LUTINDEX_1 1
+#define EXT_HPDPIN_LUTINDEX_2 2
+#define EXT_HPDPIN_LUTINDEX_3 3
+#define EXT_HPDPIN_LUTINDEX_4 4
+#define EXT_HPDPIN_LUTINDEX_5 5
+#define EXT_HPDPIN_LUTINDEX_6 6
+#define EXT_HPDPIN_LUTINDEX_7 7
+#define MAX_NUMBER_OF_EXT_HPDPIN_LUT_ENTRIES (EXT_HPDPIN_LUTINDEX_7+1)
+
+#define EXT_AUXDDC_LUTINDEX_0 0
+#define EXT_AUXDDC_LUTINDEX_1 1
+#define EXT_AUXDDC_LUTINDEX_2 2
+#define EXT_AUXDDC_LUTINDEX_3 3
+#define EXT_AUXDDC_LUTINDEX_4 4
+#define EXT_AUXDDC_LUTINDEX_5 5
+#define EXT_AUXDDC_LUTINDEX_6 6
+#define EXT_AUXDDC_LUTINDEX_7 7
+#define MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES (EXT_AUXDDC_LUTINDEX_7+1)
+
+//ucChannelMapping are defined as following
+//for DP connector, eDP, DP to VGA/LVDS
+//Bit[1:0]: Define which pin connect to DP connector DP_Lane0, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+//Bit[3:2]: Define which pin connect to DP connector DP_Lane1, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+//Bit[5:4]: Define which pin connect to DP connector DP_Lane2, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+//Bit[7:6]: Define which pin connect to DP connector DP_Lane3, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+typedef struct _ATOM_DP_CONN_CHANNEL_MAPPING
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucDP_Lane3_Source:2;
+ UCHAR ucDP_Lane2_Source:2;
+ UCHAR ucDP_Lane1_Source:2;
+ UCHAR ucDP_Lane0_Source:2;
+#else
+ UCHAR ucDP_Lane0_Source:2;
+ UCHAR ucDP_Lane1_Source:2;
+ UCHAR ucDP_Lane2_Source:2;
+ UCHAR ucDP_Lane3_Source:2;
+#endif
+}ATOM_DP_CONN_CHANNEL_MAPPING;
+
+//for DVI/HDMI, in dual link case, both links have to have same mapping.
+//Bit[1:0]: Define which pin connect to DVI connector data Lane2, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+//Bit[3:2]: Define which pin connect to DVI connector data Lane1, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+//Bit[5:4]: Define which pin connect to DVI connector data Lane0, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+//Bit[7:6]: Define which pin connect to DVI connector clock lane, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3
+typedef struct _ATOM_DVI_CONN_CHANNEL_MAPPING
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR ucDVI_CLK_Source:2;
+ UCHAR ucDVI_DATA0_Source:2;
+ UCHAR ucDVI_DATA1_Source:2;
+ UCHAR ucDVI_DATA2_Source:2;
+#else
+ UCHAR ucDVI_DATA2_Source:2;
+ UCHAR ucDVI_DATA1_Source:2;
+ UCHAR ucDVI_DATA0_Source:2;
+ UCHAR ucDVI_CLK_Source:2;
+#endif
+}ATOM_DVI_CONN_CHANNEL_MAPPING;
+
+typedef struct _EXT_DISPLAY_PATH
+{
+ USHORT usDeviceTag; //A bit vector to show what devices are supported
+ USHORT usDeviceACPIEnum; //16bit device ACPI id.
+ USHORT usDeviceConnector; //A physical connector for displays to plug in, using object connector definitions
+ UCHAR ucExtAUXDDCLutIndex; //An index into external AUX/DDC channel LUT
+ UCHAR ucExtHPDPINLutIndex; //An index into external HPD pin LUT
+ USHORT usExtEncoderObjId; //external encoder object id
+ union{
+ UCHAR ucChannelMapping; // if ucChannelMapping=0, using default one to one mapping
+ ATOM_DP_CONN_CHANNEL_MAPPING asDPMapping;
+ ATOM_DVI_CONN_CHANNEL_MAPPING asDVIMapping;
+ };
+ UCHAR ucChPNInvert; // bit vector for up to 8 lanes, =0: P and N is not invert, =1 P and N is inverted
+ USHORT usCaps;
+ USHORT usReserved;
+}EXT_DISPLAY_PATH;
+
+#define NUMBER_OF_UCHAR_FOR_GUID 16
+#define MAX_NUMBER_OF_EXT_DISPLAY_PATH 7
+
+//usCaps
+#define EXT_DISPLAY_PATH_CAPS__HBR2_DISABLE 0x01
+#define EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN 0x02
+#define EXT_DISPLAY_PATH_CAPS__HDMI20_PI3EQX1204 0x04
+#define EXT_DISPLAY_PATH_CAPS__HDMI20_TISN65DP159RSBT 0x08
+
+typedef struct _ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucGuid [NUMBER_OF_UCHAR_FOR_GUID]; // a GUID is a 16 byte long string
+ EXT_DISPLAY_PATH sPath[MAX_NUMBER_OF_EXT_DISPLAY_PATH]; // total of fixed 7 entries.
+ UCHAR ucChecksum; // a simple Checksum of the sum of whole structure equal to 0x0.
+ UCHAR uc3DStereoPinId; // use for eDP panel
+ UCHAR ucRemoteDisplayConfig;
+ UCHAR uceDPToLVDSRxId;
+ UCHAR ucFixDPVoltageSwing; // usCaps[1]=1, this indicate DP_LANE_SET value
+ UCHAR Reserved[3]; // for potential expansion
+}ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO;
+
+//Related definitions, all records are differnt but they have a commond header
+typedef struct _ATOM_COMMON_RECORD_HEADER
+{
+ UCHAR ucRecordType; //An emun to indicate the record type
+ UCHAR ucRecordSize; //The size of the whole record in byte
+}ATOM_COMMON_RECORD_HEADER;
+
+
+#define ATOM_I2C_RECORD_TYPE 1
+#define ATOM_HPD_INT_RECORD_TYPE 2
+#define ATOM_OUTPUT_PROTECTION_RECORD_TYPE 3
+#define ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE 4
+#define ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD_TYPE 5 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE
+#define ATOM_ENCODER_FPGA_CONTROL_RECORD_TYPE 6 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE
+#define ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD_TYPE 7
+#define ATOM_JTAG_RECORD_TYPE 8 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE
+#define ATOM_OBJECT_GPIO_CNTL_RECORD_TYPE 9
+#define ATOM_ENCODER_DVO_CF_RECORD_TYPE 10
+#define ATOM_CONNECTOR_CF_RECORD_TYPE 11
+#define ATOM_CONNECTOR_HARDCODE_DTD_RECORD_TYPE 12
+#define ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE 13
+#define ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE 14
+#define ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE 15
+#define ATOM_CONNECTOR_HPDPIN_LUT_RECORD_TYPE 16 //This is for the case when connectors are not known to object table
+#define ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE 17 //This is for the case when connectors are not known to object table
+#define ATOM_OBJECT_LINK_RECORD_TYPE 18 //Once this record is present under one object, it indicats the oobject is linked to another obj described by the record
+#define ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE 19
+#define ATOM_ENCODER_CAP_RECORD_TYPE 20
+#define ATOM_BRACKET_LAYOUT_RECORD_TYPE 21
+
+
+//Must be updated when new record type is added,equal to that record definition!
+#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_ENCODER_CAP_RECORD_TYPE
+
+typedef struct _ATOM_I2C_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ ATOM_I2C_ID_CONFIG sucI2cId;
+ UCHAR ucI2CAddr; //The slave address, it's 0 when the record is attached to connector for DDC
+}ATOM_I2C_RECORD;
+
+typedef struct _ATOM_HPD_INT_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucHPDIntGPIOID; //Corresponding block in GPIO_PIN_INFO table gives the pin info
+ UCHAR ucPlugged_PinState;
+}ATOM_HPD_INT_RECORD;
+
+
+typedef struct _ATOM_OUTPUT_PROTECTION_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucProtectionFlag;
+ UCHAR ucReserved;
+}ATOM_OUTPUT_PROTECTION_RECORD;
+
+typedef struct _ATOM_CONNECTOR_DEVICE_TAG
+{
+ ULONG ulACPIDeviceEnum; //Reserved for now
+ USHORT usDeviceID; //This Id is same as "ATOM_DEVICE_XXX_SUPPORT"
+ USHORT usPadding;
+}ATOM_CONNECTOR_DEVICE_TAG;
+
+typedef struct _ATOM_CONNECTOR_DEVICE_TAG_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucNumberOfDevice;
+ UCHAR ucReserved;
+ ATOM_CONNECTOR_DEVICE_TAG asDeviceTag[1]; //This Id is same as "ATOM_DEVICE_XXX_SUPPORT", 1 is only for allocation
+}ATOM_CONNECTOR_DEVICE_TAG_RECORD;
+
+
+typedef struct _ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucConfigGPIOID;
+ UCHAR ucConfigGPIOState; //Set to 1 when it's active high to enable external flow in
+ UCHAR ucFlowinGPIPID;
+ UCHAR ucExtInGPIPID;
+}ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD;
+
+typedef struct _ATOM_ENCODER_FPGA_CONTROL_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucCTL1GPIO_ID;
+ UCHAR ucCTL1GPIOState; //Set to 1 when it's active high
+ UCHAR ucCTL2GPIO_ID;
+ UCHAR ucCTL2GPIOState; //Set to 1 when it's active high
+ UCHAR ucCTL3GPIO_ID;
+ UCHAR ucCTL3GPIOState; //Set to 1 when it's active high
+ UCHAR ucCTLFPGA_IN_ID;
+ UCHAR ucPadding[3];
+}ATOM_ENCODER_FPGA_CONTROL_RECORD;
+
+typedef struct _ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucGPIOID; //Corresponding block in GPIO_PIN_INFO table gives the pin info
+ UCHAR ucTVActiveState; //Indicating when the pin==0 or 1 when TV is connected
+}ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD;
+
+typedef struct _ATOM_JTAG_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucTMSGPIO_ID;
+ UCHAR ucTMSGPIOState; //Set to 1 when it's active high
+ UCHAR ucTCKGPIO_ID;
+ UCHAR ucTCKGPIOState; //Set to 1 when it's active high
+ UCHAR ucTDOGPIO_ID;
+ UCHAR ucTDOGPIOState; //Set to 1 when it's active high
+ UCHAR ucTDIGPIO_ID;
+ UCHAR ucTDIGPIOState; //Set to 1 when it's active high
+ UCHAR ucPadding[2];
+}ATOM_JTAG_RECORD;
+
+
+//The following generic object gpio pin control record type will replace JTAG_RECORD/FPGA_CONTROL_RECORD/DVI_EXT_INPUT_RECORD above gradually
+typedef struct _ATOM_GPIO_PIN_CONTROL_PAIR
+{
+ UCHAR ucGPIOID; // GPIO_ID, find the corresponding ID in GPIO_LUT table
+ UCHAR ucGPIO_PinState; // Pin state showing how to set-up the pin
+}ATOM_GPIO_PIN_CONTROL_PAIR;
+
+typedef struct _ATOM_OBJECT_GPIO_CNTL_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucFlags; // Future expnadibility
+ UCHAR ucNumberOfPins; // Number of GPIO pins used to control the object
+ ATOM_GPIO_PIN_CONTROL_PAIR asGpio[1]; // the real gpio pin pair determined by number of pins ucNumberOfPins
+}ATOM_OBJECT_GPIO_CNTL_RECORD;
+
+//Definitions for GPIO pin state
+#define GPIO_PIN_TYPE_INPUT 0x00
+#define GPIO_PIN_TYPE_OUTPUT 0x10
+#define GPIO_PIN_TYPE_HW_CONTROL 0x20
+
+//For GPIO_PIN_TYPE_OUTPUT the following is defined
+#define GPIO_PIN_OUTPUT_STATE_MASK 0x01
+#define GPIO_PIN_OUTPUT_STATE_SHIFT 0
+#define GPIO_PIN_STATE_ACTIVE_LOW 0x0
+#define GPIO_PIN_STATE_ACTIVE_HIGH 0x1
+
+// Indexes to GPIO array in GLSync record
+// GLSync record is for Frame Lock/Gen Lock feature.
+#define ATOM_GPIO_INDEX_GLSYNC_REFCLK 0
+#define ATOM_GPIO_INDEX_GLSYNC_HSYNC 1
+#define ATOM_GPIO_INDEX_GLSYNC_VSYNC 2
+#define ATOM_GPIO_INDEX_GLSYNC_SWAP_REQ 3
+#define ATOM_GPIO_INDEX_GLSYNC_SWAP_GNT 4
+#define ATOM_GPIO_INDEX_GLSYNC_INTERRUPT 5
+#define ATOM_GPIO_INDEX_GLSYNC_V_RESET 6
+#define ATOM_GPIO_INDEX_GLSYNC_SWAP_CNTL 7
+#define ATOM_GPIO_INDEX_GLSYNC_SWAP_SEL 8
+#define ATOM_GPIO_INDEX_GLSYNC_MAX 9
+
+typedef struct _ATOM_ENCODER_DVO_CF_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ ULONG ulStrengthControl; // DVOA strength control for CF
+ UCHAR ucPadding[2];
+}ATOM_ENCODER_DVO_CF_RECORD;
+
+// Bit maps for ATOM_ENCODER_CAP_RECORD.ucEncoderCap
+#define ATOM_ENCODER_CAP_RECORD_HBR2 0x01 // DP1.2 HBR2 is supported by HW encoder
+#define ATOM_ENCODER_CAP_RECORD_HBR2_EN 0x02 // DP1.2 HBR2 setting is qualified and HBR2 can be enabled
+#define ATOM_ENCODER_CAP_RECORD_HDMI6Gbps_EN 0x04 // HDMI2.0 6Gbps enable or not.
+
+typedef struct _ATOM_ENCODER_CAP_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ union {
+ USHORT usEncoderCap;
+ struct {
+#if ATOM_BIG_ENDIAN
+ USHORT usReserved:14; // Bit1-15 may be defined for other capability in future
+ USHORT usHBR2En:1; // Bit1 is for DP1.2 HBR2 enable
+ USHORT usHBR2Cap:1; // Bit0 is for DP1.2 HBR2 capability.
+#else
+ USHORT usHBR2Cap:1; // Bit0 is for DP1.2 HBR2 capability.
+ USHORT usHBR2En:1; // Bit1 is for DP1.2 HBR2 enable
+ USHORT usReserved:14; // Bit1-15 may be defined for other capability in future
+#endif
+ };
+ };
+}ATOM_ENCODER_CAP_RECORD;
+
+// value for ATOM_CONNECTOR_CF_RECORD.ucConnectedDvoBundle
+#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_UPPER12BITBUNDLEA 1
+#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_LOWER12BITBUNDLEB 2
+
+typedef struct _ATOM_CONNECTOR_CF_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ USHORT usMaxPixClk;
+ UCHAR ucFlowCntlGpioId;
+ UCHAR ucSwapCntlGpioId;
+ UCHAR ucConnectedDvoBundle;
+ UCHAR ucPadding;
+}ATOM_CONNECTOR_CF_RECORD;
+
+typedef struct _ATOM_CONNECTOR_HARDCODE_DTD_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ ATOM_DTD_FORMAT asTiming;
+}ATOM_CONNECTOR_HARDCODE_DTD_RECORD;
+
+typedef struct _ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader; //ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE
+ UCHAR ucSubConnectorType; //CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D|X_ID_DUAL_LINK_DVI_D|HDMI_TYPE_A
+ UCHAR ucReserved;
+}ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD;
+
+
+typedef struct _ATOM_ROUTER_DDC_PATH_SELECT_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucMuxType; //decide the number of ucMuxState, =0, no pin state, =1: single state with complement, >1: multiple state
+ UCHAR ucMuxControlPin;
+ UCHAR ucMuxState[2]; //for alligment purpose
+}ATOM_ROUTER_DDC_PATH_SELECT_RECORD;
+
+typedef struct _ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucMuxType;
+ UCHAR ucMuxControlPin;
+ UCHAR ucMuxState[2]; //for alligment purpose
+}ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD;
+
+// define ucMuxType
+#define ATOM_ROUTER_MUX_PIN_STATE_MASK 0x0f
+#define ATOM_ROUTER_MUX_PIN_SINGLE_STATE_COMPLEMENT 0x01
+
+typedef struct _ATOM_CONNECTOR_HPDPIN_LUT_RECORD //record for ATOM_CONNECTOR_HPDPIN_LUT_RECORD_TYPE
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucHPDPINMap[MAX_NUMBER_OF_EXT_HPDPIN_LUT_ENTRIES]; //An fixed size array which maps external pins to internal GPIO_PIN_INFO table
+}ATOM_CONNECTOR_HPDPIN_LUT_RECORD;
+
+typedef struct _ATOM_CONNECTOR_AUXDDC_LUT_RECORD //record for ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ ATOM_I2C_ID_CONFIG ucAUXDDCMap[MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES]; //An fixed size array which maps external pins to internal DDC ID
+}ATOM_CONNECTOR_AUXDDC_LUT_RECORD;
+
+typedef struct _ATOM_OBJECT_LINK_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ USHORT usObjectID; //could be connector, encorder or other object in object.h
+}ATOM_OBJECT_LINK_RECORD;
+
+typedef struct _ATOM_CONNECTOR_REMOTE_CAP_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ USHORT usReserved;
+}ATOM_CONNECTOR_REMOTE_CAP_RECORD;
+
+typedef struct _ATOM_CONNECTOR_LAYOUT_INFO
+{
+ USHORT usConnectorObjectId;
+ UCHAR ucConnectorType;
+ UCHAR ucPosition;
+}ATOM_CONNECTOR_LAYOUT_INFO;
+
+// define ATOM_CONNECTOR_LAYOUT_INFO.ucConnectorType to describe the display connector size
+#define CONNECTOR_TYPE_DVI_D 1
+#define CONNECTOR_TYPE_DVI_I 2
+#define CONNECTOR_TYPE_VGA 3
+#define CONNECTOR_TYPE_HDMI 4
+#define CONNECTOR_TYPE_DISPLAY_PORT 5
+#define CONNECTOR_TYPE_MINI_DISPLAY_PORT 6
+
+typedef struct _ATOM_BRACKET_LAYOUT_RECORD
+{
+ ATOM_COMMON_RECORD_HEADER sheader;
+ UCHAR ucLength;
+ UCHAR ucWidth;
+ UCHAR ucConnNum;
+ UCHAR ucReserved;
+ ATOM_CONNECTOR_LAYOUT_INFO asConnInfo[1];
+}ATOM_BRACKET_LAYOUT_RECORD;
+
+
+/****************************************************************************/
+// Structure used in XXXX
+/****************************************************************************/
+typedef struct _ATOM_VOLTAGE_INFO_HEADER
+{
+ USHORT usVDDCBaseLevel; //In number of 50mv unit
+ USHORT usReserved; //For possible extension table offset
+ UCHAR ucNumOfVoltageEntries;
+ UCHAR ucBytesPerVoltageEntry;
+ UCHAR ucVoltageStep; //Indicating in how many mv increament is one step, 0.5mv unit
+ UCHAR ucDefaultVoltageEntry;
+ UCHAR ucVoltageControlI2cLine;
+ UCHAR ucVoltageControlAddress;
+ UCHAR ucVoltageControlOffset;
+}ATOM_VOLTAGE_INFO_HEADER;
+
+typedef struct _ATOM_VOLTAGE_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_VOLTAGE_INFO_HEADER viHeader;
+ UCHAR ucVoltageEntries[64]; //64 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries*ucBytesPerVoltageEntry
+}ATOM_VOLTAGE_INFO;
+
+
+typedef struct _ATOM_VOLTAGE_FORMULA
+{
+ USHORT usVoltageBaseLevel; // In number of 1mv unit
+ USHORT usVoltageStep; // Indicating in how many mv increament is one step, 1mv unit
+ UCHAR ucNumOfVoltageEntries; // Number of Voltage Entry, which indicate max Voltage
+ UCHAR ucFlag; // bit0=0 :step is 1mv =1 0.5mv
+ UCHAR ucBaseVID; // if there is no lookup table, VID= BaseVID + ( Vol - BaseLevle ) /VoltageStep
+ UCHAR ucReserved;
+ UCHAR ucVIDAdjustEntries[32]; // 32 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries
+}ATOM_VOLTAGE_FORMULA;
+
+typedef struct _VOLTAGE_LUT_ENTRY
+{
+ USHORT usVoltageCode; // The Voltage ID, either GPIO or I2C code
+ USHORT usVoltageValue; // The corresponding Voltage Value, in mV
+}VOLTAGE_LUT_ENTRY;
+
+typedef struct _ATOM_VOLTAGE_FORMULA_V2
+{
+ UCHAR ucNumOfVoltageEntries; // Number of Voltage Entry, which indicate max Voltage
+ UCHAR ucReserved[3];
+ VOLTAGE_LUT_ENTRY asVIDAdjustEntries[32];// 32 is for allocation, the actual number of entries is in ucNumOfVoltageEntries
+}ATOM_VOLTAGE_FORMULA_V2;
+
+typedef struct _ATOM_VOLTAGE_CONTROL
+{
+ UCHAR ucVoltageControlId; //Indicate it is controlled by I2C or GPIO or HW state machine
+ UCHAR ucVoltageControlI2cLine;
+ UCHAR ucVoltageControlAddress;
+ UCHAR ucVoltageControlOffset;
+ USHORT usGpioPin_AIndex; //GPIO_PAD register index
+ UCHAR ucGpioPinBitShift[9]; //at most 8 pin support 255 VIDs, termintate with 0xff
+ UCHAR ucReserved;
+}ATOM_VOLTAGE_CONTROL;
+
+// Define ucVoltageControlId
+#define VOLTAGE_CONTROLLED_BY_HW 0x00
+#define VOLTAGE_CONTROLLED_BY_I2C_MASK 0x7F
+#define VOLTAGE_CONTROLLED_BY_GPIO 0x80
+#define VOLTAGE_CONTROL_ID_LM64 0x01 //I2C control, used for R5xx Core Voltage
+#define VOLTAGE_CONTROL_ID_DAC 0x02 //I2C control, used for R5xx/R6xx MVDDC,MVDDQ or VDDCI
+#define VOLTAGE_CONTROL_ID_VT116xM 0x03 //I2C control, used for R6xx Core Voltage
+#define VOLTAGE_CONTROL_ID_DS4402 0x04
+#define VOLTAGE_CONTROL_ID_UP6266 0x05
+#define VOLTAGE_CONTROL_ID_SCORPIO 0x06
+#define VOLTAGE_CONTROL_ID_VT1556M 0x07
+#define VOLTAGE_CONTROL_ID_CHL822x 0x08
+#define VOLTAGE_CONTROL_ID_VT1586M 0x09
+#define VOLTAGE_CONTROL_ID_UP1637 0x0A
+#define VOLTAGE_CONTROL_ID_CHL8214 0x0B
+#define VOLTAGE_CONTROL_ID_UP1801 0x0C
+#define VOLTAGE_CONTROL_ID_ST6788A 0x0D
+#define VOLTAGE_CONTROL_ID_CHLIR3564SVI2 0x0E
+#define VOLTAGE_CONTROL_ID_AD527x 0x0F
+#define VOLTAGE_CONTROL_ID_NCP81022 0x10
+#define VOLTAGE_CONTROL_ID_LTC2635 0x11
+#define VOLTAGE_CONTROL_ID_NCP4208 0x12
+#define VOLTAGE_CONTROL_ID_IR35xx 0x13
+#define VOLTAGE_CONTROL_ID_RT9403 0x14
+
+#define VOLTAGE_CONTROL_ID_GENERIC_I2C 0x40
+
+typedef struct _ATOM_VOLTAGE_OBJECT
+{
+ UCHAR ucVoltageType; //Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI
+ UCHAR ucSize; //Size of Object
+ ATOM_VOLTAGE_CONTROL asControl; //describ how to control
+ ATOM_VOLTAGE_FORMULA asFormula; //Indicate How to convert real Voltage to VID
+}ATOM_VOLTAGE_OBJECT;
+
+typedef struct _ATOM_VOLTAGE_OBJECT_V2
+{
+ UCHAR ucVoltageType; //Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI
+ UCHAR ucSize; //Size of Object
+ ATOM_VOLTAGE_CONTROL asControl; //describ how to control
+ ATOM_VOLTAGE_FORMULA_V2 asFormula; //Indicate How to convert real Voltage to VID
+}ATOM_VOLTAGE_OBJECT_V2;
+
+typedef struct _ATOM_VOLTAGE_OBJECT_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_VOLTAGE_OBJECT asVoltageObj[3]; //Info for Voltage control
+}ATOM_VOLTAGE_OBJECT_INFO;
+
+typedef struct _ATOM_VOLTAGE_OBJECT_INFO_V2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_VOLTAGE_OBJECT_V2 asVoltageObj[3]; //Info for Voltage control
+}ATOM_VOLTAGE_OBJECT_INFO_V2;
+
+typedef struct _ATOM_LEAKID_VOLTAGE
+{
+ UCHAR ucLeakageId;
+ UCHAR ucReserved;
+ USHORT usVoltage;
+}ATOM_LEAKID_VOLTAGE;
+
+typedef struct _ATOM_VOLTAGE_OBJECT_HEADER_V3{
+ UCHAR ucVoltageType; //Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI
+ UCHAR ucVoltageMode; //Indicate voltage control mode: Init/Set/Leakage/Set phase
+ USHORT usSize; //Size of Object
+}ATOM_VOLTAGE_OBJECT_HEADER_V3;
+
+// ATOM_VOLTAGE_OBJECT_HEADER_V3.ucVoltageMode
+#define VOLTAGE_OBJ_GPIO_LUT 0 //VOLTAGE and GPIO Lookup table ->ATOM_GPIO_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_VR_I2C_INIT_SEQ 3 //VOLTAGE REGULATOR INIT sequece through I2C -> ATOM_I2C_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_PHASE_LUT 4 //Set Vregulator Phase lookup table ->ATOM_GPIO_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_SVID2 7 //Indicate voltage control by SVID2 ->ATOM_SVID2_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_EVV 8
+#define VOLTAGE_OBJ_PWRBOOST_LEAKAGE_LUT 0x10 //Powerboost Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_HIGH_STATE_LEAKAGE_LUT 0x11 //High voltage state Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+#define VOLTAGE_OBJ_HIGH1_STATE_LEAKAGE_LUT 0x12 //High1 voltage state Voltage and LeakageId lookup table->ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+
+typedef struct _VOLTAGE_LUT_ENTRY_V2
+{
+ ULONG ulVoltageId; // The Voltage ID which is used to program GPIO register
+ USHORT usVoltageValue; // The corresponding Voltage Value, in mV
+}VOLTAGE_LUT_ENTRY_V2;
+
+typedef struct _LEAKAGE_VOLTAGE_LUT_ENTRY_V2
+{
+ USHORT usVoltageLevel; // The Voltage ID which is used to program GPIO register
+ USHORT usVoltageId;
+ USHORT usLeakageId; // The corresponding Voltage Value, in mV
+}LEAKAGE_VOLTAGE_LUT_ENTRY_V2;
+
+
+typedef struct _ATOM_I2C_VOLTAGE_OBJECT_V3
+{
+ ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader; // voltage mode = VOLTAGE_OBJ_VR_I2C_INIT_SEQ
+ UCHAR ucVoltageRegulatorId; //Indicate Voltage Regulator Id
+ UCHAR ucVoltageControlI2cLine;
+ UCHAR ucVoltageControlAddress;
+ UCHAR ucVoltageControlOffset;
+ UCHAR ucVoltageControlFlag; // Bit0: 0 - One byte data; 1 - Two byte data
+ UCHAR ulReserved[3];
+ VOLTAGE_LUT_ENTRY asVolI2cLut[1]; // end with 0xff
+}ATOM_I2C_VOLTAGE_OBJECT_V3;
+
+// ATOM_I2C_VOLTAGE_OBJECT_V3.ucVoltageControlFlag
+#define VOLTAGE_DATA_ONE_BYTE 0
+#define VOLTAGE_DATA_TWO_BYTE 1
+
+typedef struct _ATOM_GPIO_VOLTAGE_OBJECT_V3
+{
+ ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader; // voltage mode = VOLTAGE_OBJ_GPIO_LUT or VOLTAGE_OBJ_PHASE_LUT
+ UCHAR ucVoltageGpioCntlId; // default is 0 which indicate control through CG VID mode
+ UCHAR ucGpioEntryNum; // indiate the entry numbers of Votlage/Gpio value Look up table
+ UCHAR ucPhaseDelay; // phase delay in unit of micro second
+ UCHAR ucReserved;
+ ULONG ulGpioMaskVal; // GPIO Mask value
+ VOLTAGE_LUT_ENTRY_V2 asVolGpioLut[1];
+}ATOM_GPIO_VOLTAGE_OBJECT_V3;
+
+typedef struct _ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
+{
+ ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader; // voltage mode = 0x10/0x11/0x12
+ UCHAR ucLeakageCntlId; // default is 0
+ UCHAR ucLeakageEntryNum; // indicate the entry number of LeakageId/Voltage Lut table
+ UCHAR ucReserved[2];
+ ULONG ulMaxVoltageLevel;
+ LEAKAGE_VOLTAGE_LUT_ENTRY_V2 asLeakageIdLut[1];
+}ATOM_LEAKAGE_VOLTAGE_OBJECT_V3;
+
+
+typedef struct _ATOM_SVID2_VOLTAGE_OBJECT_V3
+{
+ ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader; // voltage mode = VOLTAGE_OBJ_SVID2
+// 14:7 � PSI0_VID
+// 6 � PSI0_EN
+// 5 � PSI1
+// 4:2 � load line slope trim.
+// 1:0 � offset trim,
+ USHORT usLoadLine_PSI;
+// GPU GPIO pin Id to SVID2 regulator VRHot pin. possible value 0~31. 0 means GPIO0, 31 means GPIO31
+ UCHAR ucSVDGpioId; //0~31 indicate GPIO0~31
+ UCHAR ucSVCGpioId; //0~31 indicate GPIO0~31
+ ULONG ulReserved;
+}ATOM_SVID2_VOLTAGE_OBJECT_V3;
+
+typedef union _ATOM_VOLTAGE_OBJECT_V3{
+ ATOM_GPIO_VOLTAGE_OBJECT_V3 asGpioVoltageObj;
+ ATOM_I2C_VOLTAGE_OBJECT_V3 asI2cVoltageObj;
+ ATOM_LEAKAGE_VOLTAGE_OBJECT_V3 asLeakageObj;
+ ATOM_SVID2_VOLTAGE_OBJECT_V3 asSVID2Obj;
+}ATOM_VOLTAGE_OBJECT_V3;
+
+typedef struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_VOLTAGE_OBJECT_V3 asVoltageObj[3]; //Info for Voltage control
+}ATOM_VOLTAGE_OBJECT_INFO_V3_1;
+
+
+typedef struct _ATOM_ASIC_PROFILE_VOLTAGE
+{
+ UCHAR ucProfileId;
+ UCHAR ucReserved;
+ USHORT usSize;
+ USHORT usEfuseSpareStartAddr;
+ USHORT usFuseIndex[8]; //from LSB to MSB, Max 8bit,end of 0xffff if less than 8 efuse id,
+ ATOM_LEAKID_VOLTAGE asLeakVol[2]; //Leakid and relatd voltage
+}ATOM_ASIC_PROFILE_VOLTAGE;
+
+//ucProfileId
+#define ATOM_ASIC_PROFILE_ID_EFUSE_VOLTAGE 1
+#define ATOM_ASIC_PROFILE_ID_EFUSE_PERFORMANCE_VOLTAGE 1
+#define ATOM_ASIC_PROFILE_ID_EFUSE_THERMAL_VOLTAGE 2
+
+typedef struct _ATOM_ASIC_PROFILING_INFO
+{
+ ATOM_COMMON_TABLE_HEADER asHeader;
+ ATOM_ASIC_PROFILE_VOLTAGE asVoltage;
+}ATOM_ASIC_PROFILING_INFO;
+
+typedef struct _ATOM_ASIC_PROFILING_INFO_V2_1
+{
+ ATOM_COMMON_TABLE_HEADER asHeader;
+ UCHAR ucLeakageBinNum; // indicate the entry number of LeakageId/Voltage Lut table
+ USHORT usLeakageBinArrayOffset; // offset of USHORT Leakage Bin list array ( from lower LeakageId to higher)
+
+ UCHAR ucElbVDDC_Num;
+ USHORT usElbVDDC_IdArrayOffset; // offset of USHORT virtual VDDC voltage id ( 0xff01~0xff08 )
+ USHORT usElbVDDC_LevelArrayOffset; // offset of 2 dimension voltage level USHORT array
+
+ UCHAR ucElbVDDCI_Num;
+ USHORT usElbVDDCI_IdArrayOffset; // offset of USHORT virtual VDDCI voltage id ( 0xff01~0xff08 )
+ USHORT usElbVDDCI_LevelArrayOffset; // offset of 2 dimension voltage level USHORT array
+}ATOM_ASIC_PROFILING_INFO_V2_1;
+
+
+//Here is parameter to convert Efuse value to Measure value
+//Measured = LN((2^Bitsize-1)/EFUSE-1)*(Range)/(-alpha)+(Max+Min)/2
+typedef struct _EFUSE_LOGISTIC_FUNC_PARAM
+{
+ USHORT usEfuseIndex; // Efuse Index in DWORD address, for example Index 911, usEuseIndex=112
+ UCHAR ucEfuseBitLSB; // Efuse bit LSB in DWORD address, for example Index 911, usEfuseBitLSB= 911-112*8=15
+ UCHAR ucEfuseLength; // Efuse bits length,
+ ULONG ulEfuseEncodeRange; // Range = Max - Min, bit31 indicate the efuse is negative number
+ ULONG ulEfuseEncodeAverage; // Average = ( Max + Min )/2
+}EFUSE_LOGISTIC_FUNC_PARAM;
+
+//Linear Function: Measured = Round ( Efuse * ( Max-Min )/(2^BitSize -1 ) + Min )
+typedef struct _EFUSE_LINEAR_FUNC_PARAM
+{
+ USHORT usEfuseIndex; // Efuse Index in DWORD address, for example Index 911, usEuseIndex=112
+ UCHAR ucEfuseBitLSB; // Efuse bit LSB in DWORD address, for example Index 911, usEfuseBitLSB= 911-112*8=15
+ UCHAR ucEfuseLength; // Efuse bits length,
+ ULONG ulEfuseEncodeRange; // Range = Max - Min, bit31 indicate the efuse is negative number
+ ULONG ulEfuseMin; // Min
+}EFUSE_LINEAR_FUNC_PARAM;
+
+
+typedef struct _ATOM_ASIC_PROFILING_INFO_V3_1
+{
+ ATOM_COMMON_TABLE_HEADER asHeader;
+ ULONG ulEvvDerateTdp;
+ ULONG ulEvvDerateTdc;
+ 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 usCurrentDpm0;
+ USHORT usPowerDpm1;
+ USHORT usCurrentDpm1;
+ USHORT usPowerDpm2;
+ USHORT usCurrentDpm2;
+ USHORT usPowerDpm3;
+ USHORT usCurrentDpm3;
+ USHORT usPowerDpm4;
+ USHORT usCurrentDpm4;
+ USHORT usPowerDpm5;
+ USHORT usCurrentDpm5;
+ USHORT usPowerDpm6;
+ USHORT usCurrentDpm6;
+ USHORT usPowerDpm7;
+ USHORT usCurrentDpm7;
+}ATOM_ASIC_PROFILING_INFO_V3_1;
+
+
+typedef struct _ATOM_ASIC_PROFILING_INFO_V3_2
+{
+ 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;
+}ATOM_ASIC_PROFILING_INFO_V3_2;
+
+
+// for Tonga/Fiji speed EVV algorithm
+typedef struct _ATOM_ASIC_PROFILING_INFO_V3_3
+{
+ 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 ulRoAlpha;
+ ULONG ulRoBeta;
+ ULONG ulRoGamma;
+ ULONG ulRoEpsilon;
+ ULONG ulATermRo;
+ ULONG ulBTermRo;
+ ULONG ulCTermRo;
+ ULONG ulSclkMargin;
+ ULONG ulFmaxPercent;
+ ULONG ulCRPercent;
+ ULONG ulSFmaxPercent;
+ ULONG ulSCRPercent;
+ ULONG ulSDCMargine;
+}ATOM_ASIC_PROFILING_INFO_V3_3;
+
+typedef struct _ATOM_POWER_SOURCE_OBJECT
+{
+ UCHAR ucPwrSrcId; // Power source
+ UCHAR ucPwrSensorType; // GPIO, I2C or none
+ UCHAR ucPwrSensId; // if GPIO detect, it is GPIO id, if I2C detect, it is I2C id
+ UCHAR ucPwrSensSlaveAddr; // Slave address if I2C detect
+ UCHAR ucPwrSensRegIndex; // I2C register Index if I2C detect
+ UCHAR ucPwrSensRegBitMask; // detect which bit is used if I2C detect
+ UCHAR ucPwrSensActiveState; // high active or low active
+ UCHAR ucReserve[3]; // reserve
+ USHORT usSensPwr; // in unit of watt
+}ATOM_POWER_SOURCE_OBJECT;
+
+typedef struct _ATOM_POWER_SOURCE_INFO
+{
+ ATOM_COMMON_TABLE_HEADER asHeader;
+ UCHAR asPwrbehave[16];
+ ATOM_POWER_SOURCE_OBJECT asPwrObj[1];
+}ATOM_POWER_SOURCE_INFO;
+
+
+//Define ucPwrSrcId
+#define POWERSOURCE_PCIE_ID1 0x00
+#define POWERSOURCE_6PIN_CONNECTOR_ID1 0x01
+#define POWERSOURCE_8PIN_CONNECTOR_ID1 0x02
+#define POWERSOURCE_6PIN_CONNECTOR_ID2 0x04
+#define POWERSOURCE_8PIN_CONNECTOR_ID2 0x08
+
+//define ucPwrSensorId
+#define POWER_SENSOR_ALWAYS 0x00
+#define POWER_SENSOR_GPIO 0x01
+#define POWER_SENSOR_I2C 0x02
+
+typedef struct _ATOM_CLK_VOLT_CAPABILITY
+{
+ ULONG ulVoltageIndex; // The Voltage Index indicated by FUSE, same voltage index shared with SCLK DPM fuse table
+ ULONG ulMaximumSupportedCLK; // Maximum clock supported with specified voltage index, unit in 10kHz
+}ATOM_CLK_VOLT_CAPABILITY;
+
+
+typedef struct _ATOM_CLK_VOLT_CAPABILITY_V2
+{
+ USHORT usVoltageLevel; // The real Voltage Level round up value in unit of mv,
+ ULONG ulMaximumSupportedCLK; // Maximum clock supported with specified voltage index, unit in 10kHz
+}ATOM_CLK_VOLT_CAPABILITY_V2;
+
+typedef struct _ATOM_AVAILABLE_SCLK_LIST
+{
+ ULONG ulSupportedSCLK; // Maximum clock supported with specified voltage index, unit in 10kHz
+ USHORT usVoltageIndex; // The Voltage Index indicated by FUSE for specified SCLK
+ USHORT usVoltageID; // The Voltage ID indicated by FUSE for specified SCLK
+}ATOM_AVAILABLE_SCLK_LIST;
+
+// ATOM_INTEGRATED_SYSTEM_INFO_V6 ulSystemConfig cap definition
+#define ATOM_IGP_INFO_V6_SYSTEM_CONFIG__PCIE_POWER_GATING_ENABLE 1 // refer to ulSystemConfig bit[0]
+
+// this IntegrateSystemInfoTable is used for Liano/Ontario APU
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V6
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulBootUpEngineClock;
+ ULONG ulDentistVCOFreq;
+ ULONG ulBootUpUMAClock;
+ ATOM_CLK_VOLT_CAPABILITY sDISPCLK_Voltage[4];
+ ULONG ulBootUpReqDisplayVector;
+ ULONG ulOtherDisplayMisc;
+ ULONG ulGPUCapInfo;
+ ULONG ulSB_MMIO_Base_Addr;
+ USHORT usRequestedPWMFreqInHz;
+ UCHAR ucHtcTmpLmt;
+ UCHAR ucHtcHystLmt;
+ ULONG ulMinEngineClock;
+ ULONG ulSystemConfig;
+ ULONG ulCPUCapInfo;
+ USHORT usNBP0Voltage;
+ USHORT usNBP1Voltage;
+ USHORT usBootUpNBVoltage;
+ USHORT usExtDispConnInfoOffset;
+ USHORT usPanelRefreshRateRange;
+ UCHAR ucMemoryType;
+ UCHAR ucUMAChannelNumber;
+ ULONG ulCSR_M3_ARB_CNTL_DEFAULT[10];
+ ULONG ulCSR_M3_ARB_CNTL_UVD[10];
+ ULONG ulCSR_M3_ARB_CNTL_FS3D[10];
+ ATOM_AVAILABLE_SCLK_LIST sAvail_SCLK[5];
+ ULONG ulGMCRestoreResetTime;
+ ULONG ulMinimumNClk;
+ ULONG ulIdleNClk;
+ ULONG ulDDR_DLL_PowerUpTime;
+ ULONG ulDDR_PLL_PowerUpTime;
+ USHORT usPCIEClkSSPercentage;
+ USHORT usPCIEClkSSType;
+ USHORT usLvdsSSPercentage;
+ USHORT usLvdsSSpreadRateIn10Hz;
+ USHORT usHDMISSPercentage;
+ USHORT usHDMISSpreadRateIn10Hz;
+ USHORT usDVISSPercentage;
+ USHORT usDVISSpreadRateIn10Hz;
+ ULONG SclkDpmBoostMargin;
+ ULONG SclkDpmThrottleMargin;
+ USHORT SclkDpmTdpLimitPG;
+ USHORT SclkDpmTdpLimitBoost;
+ ULONG ulBoostEngineCLock;
+ UCHAR ulBoostVid_2bit;
+ UCHAR EnableBoost;
+ USHORT GnbTdpLimit;
+ USHORT usMaxLVDSPclkFreqInSingleLink;
+ UCHAR ucLvdsMisc;
+ UCHAR ucLVDSReserved;
+ ULONG ulReserved3[15];
+ ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo;
+}ATOM_INTEGRATED_SYSTEM_INFO_V6;
+
+// ulGPUCapInfo
+#define INTEGRATED_SYSTEM_INFO_V6_GPUCAPINFO__TMDSHDMI_COHERENT_SINGLEPLL_MODE 0x01
+#define INTEGRATED_SYSTEM_INFO_V6_GPUCAPINFO__DISABLE_AUX_HW_MODE_DETECTION 0x08
+
+//ucLVDSMisc:
+#define SYS_INFO_LVDSMISC__888_FPDI_MODE 0x01
+#define SYS_INFO_LVDSMISC__DL_CH_SWAP 0x02
+#define SYS_INFO_LVDSMISC__888_BPC 0x04
+#define SYS_INFO_LVDSMISC__OVERRIDE_EN 0x08
+#define SYS_INFO_LVDSMISC__BLON_ACTIVE_LOW 0x10
+// new since Trinity
+#define SYS_INFO_LVDSMISC__TRAVIS_LVDS_VOL_OVERRIDE_EN 0x20
+
+// not used any more
+#define SYS_INFO_LVDSMISC__VSYNC_ACTIVE_LOW 0x04
+#define SYS_INFO_LVDSMISC__HSYNC_ACTIVE_LOW 0x08
+
+/**********************************************************************************************************************
+ ATOM_INTEGRATED_SYSTEM_INFO_V6 Description
+ulBootUpEngineClock: VBIOS bootup Engine clock frequency, in 10kHz unit. if it is equal 0, then VBIOS use pre-defined bootup engine clock
+ulDentistVCOFreq: Dentist VCO clock in 10kHz unit.
+ulBootUpUMAClock: System memory boot up clock frequency in 10Khz unit.
+sDISPCLK_Voltage: Report Display clock voltage requirement.
+
+ulBootUpReqDisplayVector: VBIOS boot up display IDs, following are supported devices in Liano/Ontaio projects:
+ ATOM_DEVICE_CRT1_SUPPORT 0x0001
+ ATOM_DEVICE_CRT2_SUPPORT 0x0010
+ ATOM_DEVICE_DFP1_SUPPORT 0x0008
+ ATOM_DEVICE_DFP6_SUPPORT 0x0040
+ ATOM_DEVICE_DFP2_SUPPORT 0x0080
+ ATOM_DEVICE_DFP3_SUPPORT 0x0200
+ ATOM_DEVICE_DFP4_SUPPORT 0x0400
+ ATOM_DEVICE_DFP5_SUPPORT 0x0800
+ ATOM_DEVICE_LCD1_SUPPORT 0x0002
+ulOtherDisplayMisc: Other display related flags, not defined yet.
+ulGPUCapInfo: bit[0]=0: TMDS/HDMI Coherent Mode use cascade PLL mode.
+ =1: TMDS/HDMI Coherent Mode use signel PLL mode.
+ bit[3]=0: Enable HW AUX mode detection logic
+ =1: Disable HW AUX mode dettion logic
+ulSB_MMIO_Base_Addr: Physical Base address to SB MMIO space. Driver needs to initialize it for SMU usage.
+
+usRequestedPWMFreqInHz: When it's set to 0x0 by SBIOS: the LCD BackLight is not controlled by GPU(SW).
+ Any attempt to change BL using VBIOS function or enable VariBri from PP table is not effective since ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==0;
+
+ When it's set to a non-zero frequency, the BackLight is controlled by GPU (SW) in one of two ways below:
+ 1. SW uses the GPU BL PWM output to control the BL, in chis case, this non-zero frequency determines what freq GPU should use;
+ VBIOS will set up proper PWM frequency and ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1,as the result,
+ Changing BL using VBIOS function is functional in both driver and non-driver present environment;
+ and enabling VariBri under the driver environment from PP table is optional.
+
+ 2. SW uses other means to control BL (like DPCD),this non-zero frequency serves as a flag only indicating
+ that BL control from GPU is expected.
+ VBIOS will NOT set up PWM frequency but make ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1
+ Changing BL using VBIOS function could be functional in both driver and non-driver present environment,but
+ it's per platform
+ and enabling VariBri under the driver environment from PP table is optional.
+
+ucHtcTmpLmt: Refer to D18F3x64 bit[22:16], HtcTmpLmt.
+ Threshold on value to enter HTC_active state.
+ucHtcHystLmt: Refer to D18F3x64 bit[27:24], HtcHystLmt.
+ To calculate threshold off value to exit HTC_active state, which is Threshold on vlaue minus ucHtcHystLmt.
+ulMinEngineClock: Minimum SCLK allowed in 10kHz unit. This is calculated based on WRCK Fuse settings.
+ulSystemConfig: Bit[0]=0: PCIE Power Gating Disabled
+ =1: PCIE Power Gating Enabled
+ Bit[1]=0: DDR-DLL shut-down feature disabled.
+ 1: DDR-DLL shut-down feature enabled.
+ Bit[2]=0: DDR-PLL Power down feature disabled.
+ 1: DDR-PLL Power down feature enabled.
+ulCPUCapInfo: TBD
+usNBP0Voltage: VID for voltage on NB P0 State
+usNBP1Voltage: VID for voltage on NB P1 State
+usBootUpNBVoltage: Voltage Index of GNB voltage configured by SBIOS, which is suffcient to support VBIOS DISPCLK requirement.
+usExtDispConnInfoOffset: Offset to sExtDispConnInfo inside the structure
+usPanelRefreshRateRange: Bit vector for LCD supported refresh rate range. If DRR is requestd by the platform, at least two bits need to be set
+ to indicate a range.
+ SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004
+ SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008
+ SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010
+ SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020
+ucMemoryType: [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved.
+ucUMAChannelNumber: System memory channel numbers.
+ulCSR_M3_ARB_CNTL_DEFAULT[10]: Arrays with values for CSR M3 arbiter for default
+ulCSR_M3_ARB_CNTL_UVD[10]: Arrays with values for CSR M3 arbiter for UVD playback.
+ulCSR_M3_ARB_CNTL_FS3D[10]: Arrays with values for CSR M3 arbiter for Full Screen 3D applications.
+sAvail_SCLK[5]: Arrays to provide availabe list of SLCK and corresponding voltage, order from low to high
+ulGMCRestoreResetTime: GMC power restore and GMC reset time to calculate data reconnection latency. Unit in ns.
+ulMinimumNClk: Minimum NCLK speed among all NB-Pstates to calcualte data reconnection latency. Unit in 10kHz.
+ulIdleNClk: NCLK speed while memory runs in self-refresh state. Unit in 10kHz.
+ulDDR_DLL_PowerUpTime: DDR PHY DLL power up time. Unit in ns.
+ulDDR_PLL_PowerUpTime: DDR PHY PLL power up time. Unit in ns.
+usPCIEClkSSPercentage: PCIE Clock Spred Spectrum Percentage in unit 0.01%; 100 mean 1%.
+usPCIEClkSSType: PCIE Clock Spred Spectrum Type. 0 for Down spread(default); 1 for Center spread.
+usLvdsSSPercentage: LVDS panel ( not include eDP ) Spread Spectrum Percentage in unit of 0.01%, =0, use VBIOS default setting.
+usLvdsSSpreadRateIn10Hz: LVDS panel ( not include eDP ) Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting.
+usHDMISSPercentage: HDMI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting.
+usHDMISSpreadRateIn10Hz: HDMI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting.
+usDVISSPercentage: DVI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting.
+usDVISSpreadRateIn10Hz: DVI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting.
+usMaxLVDSPclkFreqInSingleLink: Max pixel clock LVDS panel single link, if=0 means VBIOS use default threhold, right now it is 85Mhz
+ucLVDSMisc: [bit0] LVDS 888bit panel mode =0: LVDS 888 panel in LDI mode, =1: LVDS 888 panel in FPDI mode
+ [bit1] LVDS panel lower and upper link mapping =0: lower link and upper link not swap, =1: lower link and upper link are swapped
+ [bit2] LVDS 888bit per color mode =0: 666 bit per color =1:888 bit per color
+ [bit3] LVDS parameter override enable =0: ucLvdsMisc parameter are not used =1: ucLvdsMisc parameter should be used
+ [bit4] Polarity of signal sent to digital BLON output pin. =0: not inverted(active high) =1: inverted ( active low )
+**********************************************************************************************************************/
+
+// this Table is used for Liano/Ontario APU
+typedef struct _ATOM_FUSION_SYSTEM_INFO_V1
+{
+ ATOM_INTEGRATED_SYSTEM_INFO_V6 sIntegratedSysInfo;
+ ULONG ulPowerplayTable[128];
+}ATOM_FUSION_SYSTEM_INFO_V1;
+
+
+typedef struct _ATOM_TDP_CONFIG_BITS
+{
+#if ATOM_BIG_ENDIAN
+ ULONG uReserved:2;
+ ULONG uTDP_Value:14; // Original TDP value in tens of milli watts
+ ULONG uCTDP_Value:14; // Override value in tens of milli watts
+ ULONG uCTDP_Enable:2; // = (uCTDP_Value > uTDP_Value? 2: (uCTDP_Value < uTDP_Value))
+#else
+ ULONG uCTDP_Enable:2; // = (uCTDP_Value > uTDP_Value? 2: (uCTDP_Value < uTDP_Value))
+ ULONG uCTDP_Value:14; // Override value in tens of milli watts
+ ULONG uTDP_Value:14; // Original TDP value in tens of milli watts
+ ULONG uReserved:2;
+#endif
+}ATOM_TDP_CONFIG_BITS;
+
+typedef union _ATOM_TDP_CONFIG
+{
+ ATOM_TDP_CONFIG_BITS TDP_config;
+ ULONG TDP_config_all;
+}ATOM_TDP_CONFIG;
+
+/**********************************************************************************************************************
+ ATOM_FUSION_SYSTEM_INFO_V1 Description
+sIntegratedSysInfo: refer to ATOM_INTEGRATED_SYSTEM_INFO_V6 definition.
+ulPowerplayTable[128]: This 512 bytes memory is used to save ATOM_PPLIB_POWERPLAYTABLE3, starting form ulPowerplayTable[0]
+**********************************************************************************************************************/
+
+// this IntegrateSystemInfoTable is used for Trinity APU
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulBootUpEngineClock;
+ ULONG ulDentistVCOFreq;
+ ULONG ulBootUpUMAClock;
+ ATOM_CLK_VOLT_CAPABILITY sDISPCLK_Voltage[4];
+ ULONG ulBootUpReqDisplayVector;
+ ULONG ulOtherDisplayMisc;
+ ULONG ulGPUCapInfo;
+ ULONG ulSB_MMIO_Base_Addr;
+ USHORT usRequestedPWMFreqInHz;
+ UCHAR ucHtcTmpLmt;
+ UCHAR ucHtcHystLmt;
+ ULONG ulMinEngineClock;
+ ULONG ulSystemConfig;
+ ULONG ulCPUCapInfo;
+ USHORT usNBP0Voltage;
+ USHORT usNBP1Voltage;
+ USHORT usBootUpNBVoltage;
+ USHORT usExtDispConnInfoOffset;
+ USHORT usPanelRefreshRateRange;
+ UCHAR ucMemoryType;
+ UCHAR ucUMAChannelNumber;
+ UCHAR strVBIOSMsg[40];
+ ATOM_TDP_CONFIG asTdpConfig;
+ ULONG ulReserved[19];
+ ATOM_AVAILABLE_SCLK_LIST sAvail_SCLK[5];
+ ULONG ulGMCRestoreResetTime;
+ ULONG ulMinimumNClk;
+ ULONG ulIdleNClk;
+ ULONG ulDDR_DLL_PowerUpTime;
+ ULONG ulDDR_PLL_PowerUpTime;
+ USHORT usPCIEClkSSPercentage;
+ USHORT usPCIEClkSSType;
+ USHORT usLvdsSSPercentage;
+ USHORT usLvdsSSpreadRateIn10Hz;
+ USHORT usHDMISSPercentage;
+ USHORT usHDMISSpreadRateIn10Hz;
+ USHORT usDVISSPercentage;
+ USHORT usDVISSpreadRateIn10Hz;
+ ULONG SclkDpmBoostMargin;
+ ULONG SclkDpmThrottleMargin;
+ USHORT SclkDpmTdpLimitPG;
+ USHORT SclkDpmTdpLimitBoost;
+ ULONG ulBoostEngineCLock;
+ UCHAR ulBoostVid_2bit;
+ UCHAR EnableBoost;
+ USHORT GnbTdpLimit;
+ USHORT usMaxLVDSPclkFreqInSingleLink;
+ UCHAR ucLvdsMisc;
+ UCHAR ucTravisLVDSVolAdjust;
+ UCHAR ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
+ UCHAR ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
+ UCHAR ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
+ UCHAR ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
+ UCHAR ucLVDSOffToOnDelay_in4Ms;
+ UCHAR ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
+ UCHAR ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
+ UCHAR ucMinAllowedBL_Level;
+ ULONG ulLCDBitDepthControlVal;
+ ULONG ulNbpStateMemclkFreq[4];
+ USHORT usNBP2Voltage;
+ USHORT usNBP3Voltage;
+ ULONG ulNbpStateNClkFreq[4];
+ UCHAR ucNBDPMEnable;
+ UCHAR ucReserved[3];
+ UCHAR ucDPMState0VclkFid;
+ UCHAR ucDPMState0DclkFid;
+ UCHAR ucDPMState1VclkFid;
+ UCHAR ucDPMState1DclkFid;
+ UCHAR ucDPMState2VclkFid;
+ UCHAR ucDPMState2DclkFid;
+ UCHAR ucDPMState3VclkFid;
+ UCHAR ucDPMState3DclkFid;
+ ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo;
+}ATOM_INTEGRATED_SYSTEM_INFO_V1_7;
+
+// ulOtherDisplayMisc
+#define INTEGRATED_SYSTEM_INFO__GET_EDID_CALLBACK_FUNC_SUPPORT 0x01
+#define INTEGRATED_SYSTEM_INFO__GET_BOOTUP_DISPLAY_CALLBACK_FUNC_SUPPORT 0x02
+#define INTEGRATED_SYSTEM_INFO__GET_EXPANSION_CALLBACK_FUNC_SUPPORT 0x04
+#define INTEGRATED_SYSTEM_INFO__FAST_BOOT_SUPPORT 0x08
+
+// ulGPUCapInfo
+#define SYS_INFO_GPUCAPS__TMDSHDMI_COHERENT_SINGLEPLL_MODE 0x01
+#define SYS_INFO_GPUCAPS__DP_SINGLEPLL_MODE 0x02
+#define SYS_INFO_GPUCAPS__DISABLE_AUX_MODE_DETECT 0x08
+#define SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS 0x10
+//ulGPUCapInfo[16]=1 indicate SMC firmware is able to support GNB fast resume function, so that driver can call SMC to program most of GNB register during resuming, from ML
+#define SYS_INFO_GPUCAPS__GNB_FAST_RESUME_CAPABLE 0x00010000
+
+//ulGPUCapInfo[17]=1 indicate battery boost feature is enable, from ML
+#define SYS_INFO_GPUCAPS__BATTERY_BOOST_ENABLE 0x00020000
+
+/**********************************************************************************************************************
+ ATOM_INTEGRATED_SYSTEM_INFO_V1_7 Description
+ulBootUpEngineClock: VBIOS bootup Engine clock frequency, in 10kHz unit. if it is equal 0, then VBIOS use pre-defined bootup engine clock
+ulDentistVCOFreq: Dentist VCO clock in 10kHz unit.
+ulBootUpUMAClock: System memory boot up clock frequency in 10Khz unit.
+sDISPCLK_Voltage: Report Display clock voltage requirement.
+
+ulBootUpReqDisplayVector: VBIOS boot up display IDs, following are supported devices in Trinity projects:
+ ATOM_DEVICE_CRT1_SUPPORT 0x0001
+ ATOM_DEVICE_DFP1_SUPPORT 0x0008
+ ATOM_DEVICE_DFP6_SUPPORT 0x0040
+ ATOM_DEVICE_DFP2_SUPPORT 0x0080
+ ATOM_DEVICE_DFP3_SUPPORT 0x0200
+ ATOM_DEVICE_DFP4_SUPPORT 0x0400
+ ATOM_DEVICE_DFP5_SUPPORT 0x0800
+ ATOM_DEVICE_LCD1_SUPPORT 0x0002
+ulOtherDisplayMisc: bit[0]=0: INT15 callback function Get LCD EDID ( ax=4e08, bl=1b ) is not supported by SBIOS.
+ =1: INT15 callback function Get LCD EDID ( ax=4e08, bl=1b ) is supported by SBIOS.
+ bit[1]=0: INT15 callback function Get boot display( ax=4e08, bl=01h) is not supported by SBIOS
+ =1: INT15 callback function Get boot display( ax=4e08, bl=01h) is supported by SBIOS
+ bit[2]=0: INT15 callback function Get panel Expansion ( ax=4e08, bl=02h) is not supported by SBIOS
+ =1: INT15 callback function Get panel Expansion ( ax=4e08, bl=02h) is supported by SBIOS
+ bit[3]=0: VBIOS fast boot is disable
+ =1: VBIOS fast boot is enable. ( VBIOS skip display device detection in every set mode if LCD panel is connect and LID is open)
+ulGPUCapInfo: bit[0]=0: TMDS/HDMI Coherent Mode use cascade PLL mode.
+ =1: TMDS/HDMI Coherent Mode use signel PLL mode.
+ bit[1]=0: DP mode use cascade PLL mode ( New for Trinity )
+ =1: DP mode use single PLL mode
+ bit[3]=0: Enable AUX HW mode detection logic
+ =1: Disable AUX HW mode detection logic
+
+ulSB_MMIO_Base_Addr: Physical Base address to SB MMIO space. Driver needs to initialize it for SMU usage.
+
+usRequestedPWMFreqInHz: When it's set to 0x0 by SBIOS: the LCD BackLight is not controlled by GPU(SW).
+ Any attempt to change BL using VBIOS function or enable VariBri from PP table is not effective since ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==0;
+
+ When it's set to a non-zero frequency, the BackLight is controlled by GPU (SW) in one of two ways below:
+ 1. SW uses the GPU BL PWM output to control the BL, in chis case, this non-zero frequency determines what freq GPU should use;
+ VBIOS will set up proper PWM frequency and ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1,as the result,
+ Changing BL using VBIOS function is functional in both driver and non-driver present environment;
+ and enabling VariBri under the driver environment from PP table is optional.
+
+ 2. SW uses other means to control BL (like DPCD),this non-zero frequency serves as a flag only indicating
+ that BL control from GPU is expected.
+ VBIOS will NOT set up PWM frequency but make ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1
+ Changing BL using VBIOS function could be functional in both driver and non-driver present environment,but
+ it's per platform
+ and enabling VariBri under the driver environment from PP table is optional.
+
+ucHtcTmpLmt: Refer to D18F3x64 bit[22:16], HtcTmpLmt.
+ Threshold on value to enter HTC_active state.
+ucHtcHystLmt: Refer to D18F3x64 bit[27:24], HtcHystLmt.
+ To calculate threshold off value to exit HTC_active state, which is Threshold on vlaue minus ucHtcHystLmt.
+ulMinEngineClock: Minimum SCLK allowed in 10kHz unit. This is calculated based on WRCK Fuse settings.
+ulSystemConfig: Bit[0]=0: PCIE Power Gating Disabled
+ =1: PCIE Power Gating Enabled
+ Bit[1]=0: DDR-DLL shut-down feature disabled.
+ 1: DDR-DLL shut-down feature enabled.
+ Bit[2]=0: DDR-PLL Power down feature disabled.
+ 1: DDR-PLL Power down feature enabled.
+ulCPUCapInfo: TBD
+usNBP0Voltage: VID for voltage on NB P0 State
+usNBP1Voltage: VID for voltage on NB P1 State
+usNBP2Voltage: VID for voltage on NB P2 State
+usNBP3Voltage: VID for voltage on NB P3 State
+usBootUpNBVoltage: Voltage Index of GNB voltage configured by SBIOS, which is suffcient to support VBIOS DISPCLK requirement.
+usExtDispConnInfoOffset: Offset to sExtDispConnInfo inside the structure
+usPanelRefreshRateRange: Bit vector for LCD supported refresh rate range. If DRR is requestd by the platform, at least two bits need to be set
+ to indicate a range.
+ SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004
+ SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008
+ SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010
+ SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020
+ucMemoryType: [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved.
+ucUMAChannelNumber: System memory channel numbers.
+ulCSR_M3_ARB_CNTL_DEFAULT[10]: Arrays with values for CSR M3 arbiter for default
+ulCSR_M3_ARB_CNTL_UVD[10]: Arrays with values for CSR M3 arbiter for UVD playback.
+ulCSR_M3_ARB_CNTL_FS3D[10]: Arrays with values for CSR M3 arbiter for Full Screen 3D applications.
+sAvail_SCLK[5]: Arrays to provide availabe list of SLCK and corresponding voltage, order from low to high
+ulGMCRestoreResetTime: GMC power restore and GMC reset time to calculate data reconnection latency. Unit in ns.
+ulMinimumNClk: Minimum NCLK speed among all NB-Pstates to calcualte data reconnection latency. Unit in 10kHz.
+ulIdleNClk: NCLK speed while memory runs in self-refresh state. Unit in 10kHz.
+ulDDR_DLL_PowerUpTime: DDR PHY DLL power up time. Unit in ns.
+ulDDR_PLL_PowerUpTime: DDR PHY PLL power up time. Unit in ns.
+usPCIEClkSSPercentage: PCIE Clock Spread Spectrum Percentage in unit 0.01%; 100 mean 1%.
+usPCIEClkSSType: PCIE Clock Spread Spectrum Type. 0 for Down spread(default); 1 for Center spread.
+usLvdsSSPercentage: LVDS panel ( not include eDP ) Spread Spectrum Percentage in unit of 0.01%, =0, use VBIOS default setting.
+usLvdsSSpreadRateIn10Hz: LVDS panel ( not include eDP ) Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting.
+usHDMISSPercentage: HDMI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting.
+usHDMISSpreadRateIn10Hz: HDMI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting.
+usDVISSPercentage: DVI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting.
+usDVISSpreadRateIn10Hz: DVI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting.
+usMaxLVDSPclkFreqInSingleLink: Max pixel clock LVDS panel single link, if=0 means VBIOS use default threhold, right now it is 85Mhz
+ucLVDSMisc: [bit0] LVDS 888bit panel mode =0: LVDS 888 panel in LDI mode, =1: LVDS 888 panel in FPDI mode
+ [bit1] LVDS panel lower and upper link mapping =0: lower link and upper link not swap, =1: lower link and upper link are swapped
+ [bit2] LVDS 888bit per color mode =0: 666 bit per color =1:888 bit per color
+ [bit3] LVDS parameter override enable =0: ucLvdsMisc parameter are not used =1: ucLvdsMisc parameter should be used
+ [bit4] Polarity of signal sent to digital BLON output pin. =0: not inverted(active high) =1: inverted ( active low )
+ [bit5] Travid LVDS output voltage override enable, when =1, use ucTravisLVDSVolAdjust value to overwrite Traivs register LVDS_CTRL_4
+ucTravisLVDSVolAdjust When ucLVDSMisc[5]=1,it means platform SBIOS want to overwrite TravisLVDSVoltage. Then VBIOS will use ucTravisLVDSVolAdjust
+ value to program Travis register LVDS_CTRL_4
+ucLVDSPwrOnSeqDIGONtoDE_in4Ms: LVDS power up sequence time in unit of 4ms, time delay from DIGON signal active to data enable signal active( DE ).
+ =0 mean use VBIOS default which is 8 ( 32ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON.
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOnDEtoVARY_BL_in4Ms: LVDS power up sequence time in unit of 4ms., time delay from DE( data enable ) active to Vary Brightness enable signal active( VARY_BL ).
+ =0 mean use VBIOS default which is 90 ( 360ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON.
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSPwrOffVARY_BLtoDE_in4Ms: LVDS power down sequence time in unit of 4ms, time delay from data enable ( DE ) signal off to LCDVCC (DIGON) off.
+ =0 mean use VBIOS default delay which is 8 ( 32ms ). The LVDS power down sequence is as following: BLON->VARY_BL->DE->DIGON
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSPwrOffDEtoDIGON_in4Ms: LVDS power down sequence time in unit of 4ms, time delay from vary brightness enable signal( VARY_BL) off to data enable ( DE ) signal off.
+ =0 mean use VBIOS default which is 90 ( 360ms ). The LVDS power down sequence is as following: BLON->VARY_BL->DE->DIGON
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSOffToOnDelay_in4Ms: LVDS power down sequence time in unit of 4ms. Time delay from DIGON signal off to DIGON signal active.
+ =0 means to use VBIOS default delay which is 125 ( 500ms ).
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms:
+ LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active.
+ =0 means to use VBIOS default delay which is 0 ( 0ms ).
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms:
+ LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off.
+ =0 means to use VBIOS default delay which is 0 ( 0ms ).
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucMinAllowedBL_Level: Lowest LCD backlight PWM level. This is customer platform specific parameters. By default it is 0.
+
+ulNbpStateMemclkFreq[4]: system memory clock frequncey in unit of 10Khz in different NB pstate.
+
+**********************************************************************************************************************/
+
+// this IntegrateSystemInfoTable is used for Kaveri & Kabini APU
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulBootUpEngineClock;
+ ULONG ulDentistVCOFreq;
+ ULONG ulBootUpUMAClock;
+ ATOM_CLK_VOLT_CAPABILITY sDISPCLK_Voltage[4];
+ ULONG ulBootUpReqDisplayVector;
+ ULONG ulVBIOSMisc;
+ ULONG ulGPUCapInfo;
+ ULONG ulDISP_CLK2Freq;
+ USHORT usRequestedPWMFreqInHz;
+ UCHAR ucHtcTmpLmt;
+ UCHAR ucHtcHystLmt;
+ ULONG ulReserved2;
+ ULONG ulSystemConfig;
+ ULONG ulCPUCapInfo;
+ ULONG ulReserved3;
+ USHORT usGPUReservedSysMemSize;
+ USHORT usExtDispConnInfoOffset;
+ USHORT usPanelRefreshRateRange;
+ UCHAR ucMemoryType;
+ UCHAR ucUMAChannelNumber;
+ UCHAR strVBIOSMsg[40];
+ ATOM_TDP_CONFIG asTdpConfig;
+ ULONG ulReserved[19];
+ ATOM_AVAILABLE_SCLK_LIST sAvail_SCLK[5];
+ ULONG ulGMCRestoreResetTime;
+ ULONG ulReserved4;
+ ULONG ulIdleNClk;
+ ULONG ulDDR_DLL_PowerUpTime;
+ ULONG ulDDR_PLL_PowerUpTime;
+ USHORT usPCIEClkSSPercentage;
+ USHORT usPCIEClkSSType;
+ USHORT usLvdsSSPercentage;
+ USHORT usLvdsSSpreadRateIn10Hz;
+ USHORT usHDMISSPercentage;
+ USHORT usHDMISSpreadRateIn10Hz;
+ USHORT usDVISSPercentage;
+ USHORT usDVISSpreadRateIn10Hz;
+ ULONG ulGPUReservedSysMemBaseAddrLo;
+ ULONG ulGPUReservedSysMemBaseAddrHi;
+ ATOM_CLK_VOLT_CAPABILITY s5thDISPCLK_Voltage;
+ ULONG ulReserved5;
+ USHORT usMaxLVDSPclkFreqInSingleLink;
+ UCHAR ucLvdsMisc;
+ UCHAR ucTravisLVDSVolAdjust;
+ UCHAR ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
+ UCHAR ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
+ UCHAR ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
+ UCHAR ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
+ UCHAR ucLVDSOffToOnDelay_in4Ms;
+ UCHAR ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
+ UCHAR ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
+ UCHAR ucMinAllowedBL_Level;
+ ULONG ulLCDBitDepthControlVal;
+ ULONG ulNbpStateMemclkFreq[4];
+ ULONG ulPSPVersion;
+ ULONG ulNbpStateNClkFreq[4];
+ USHORT usNBPStateVoltage[4];
+ USHORT usBootUpNBVoltage;
+ USHORT usReserved2;
+ ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo;
+}ATOM_INTEGRATED_SYSTEM_INFO_V1_8;
+
+/**********************************************************************************************************************
+ ATOM_INTEGRATED_SYSTEM_INFO_V1_8 Description
+ulBootUpEngineClock: VBIOS bootup Engine clock frequency, in 10kHz unit. if it is equal 0, then VBIOS use pre-defined bootup engine clock
+ulDentistVCOFreq: Dentist VCO clock in 10kHz unit.
+ulBootUpUMAClock: System memory boot up clock frequency in 10Khz unit.
+sDISPCLK_Voltage: Report Display clock frequency requirement on GNB voltage(up to 4 voltage levels).
+
+ulBootUpReqDisplayVector: VBIOS boot up display IDs, following are supported devices in Trinity projects:
+ ATOM_DEVICE_CRT1_SUPPORT 0x0001
+ ATOM_DEVICE_DFP1_SUPPORT 0x0008
+ ATOM_DEVICE_DFP6_SUPPORT 0x0040
+ ATOM_DEVICE_DFP2_SUPPORT 0x0080
+ ATOM_DEVICE_DFP3_SUPPORT 0x0200
+ ATOM_DEVICE_DFP4_SUPPORT 0x0400
+ ATOM_DEVICE_DFP5_SUPPORT 0x0800
+ ATOM_DEVICE_LCD1_SUPPORT 0x0002
+
+ulVBIOSMisc: Miscellenous flags for VBIOS requirement and interface
+ bit[0]=0: INT15 callback function Get LCD EDID ( ax=4e08, bl=1b ) is not supported by SBIOS.
+ =1: INT15 callback function Get LCD EDID ( ax=4e08, bl=1b ) is supported by SBIOS.
+ bit[1]=0: INT15 callback function Get boot display( ax=4e08, bl=01h) is not supported by SBIOS
+ =1: INT15 callback function Get boot display( ax=4e08, bl=01h) is supported by SBIOS
+ bit[2]=0: INT15 callback function Get panel Expansion ( ax=4e08, bl=02h) is not supported by SBIOS
+ =1: INT15 callback function Get panel Expansion ( ax=4e08, bl=02h) is supported by SBIOS
+ bit[3]=0: VBIOS fast boot is disable
+ =1: VBIOS fast boot is enable. ( VBIOS skip display device detection in every set mode if LCD panel is connect and LID is open)
+
+ulGPUCapInfo: bit[0~2]= Reserved
+ bit[3]=0: Enable AUX HW mode detection logic
+ =1: Disable AUX HW mode detection logic
+ bit[4]=0: Disable DFS bypass feature
+ =1: Enable DFS bypass feature
+
+usRequestedPWMFreqInHz: When it's set to 0x0 by SBIOS: the LCD BackLight is not controlled by GPU(SW).
+ Any attempt to change BL using VBIOS function or enable VariBri from PP table is not effective since ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==0;
+
+ When it's set to a non-zero frequency, the BackLight is controlled by GPU (SW) in one of two ways below:
+ 1. SW uses the GPU BL PWM output to control the BL, in chis case, this non-zero frequency determines what freq GPU should use;
+ VBIOS will set up proper PWM frequency and ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1,as the result,
+ Changing BL using VBIOS function is functional in both driver and non-driver present environment;
+ and enabling VariBri under the driver environment from PP table is optional.
+
+ 2. SW uses other means to control BL (like DPCD),this non-zero frequency serves as a flag only indicating
+ that BL control from GPU is expected.
+ VBIOS will NOT set up PWM frequency but make ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1
+ Changing BL using VBIOS function could be functional in both driver and non-driver present environment,but
+ it's per platform
+ and enabling VariBri under the driver environment from PP table is optional.
+
+ucHtcTmpLmt: Refer to D18F3x64 bit[22:16], HtcTmpLmt. Threshold on value to enter HTC_active state.
+ucHtcHystLmt: Refer to D18F3x64 bit[27:24], HtcHystLmt.
+ To calculate threshold off value to exit HTC_active state, which is Threshold on vlaue minus ucHtcHystLmt.
+
+ulSystemConfig: Bit[0]=0: PCIE Power Gating Disabled
+ =1: PCIE Power Gating Enabled
+ Bit[1]=0: DDR-DLL shut-down feature disabled.
+ 1: DDR-DLL shut-down feature enabled.
+ Bit[2]=0: DDR-PLL Power down feature disabled.
+ 1: DDR-PLL Power down feature enabled.
+ Bit[3]=0: GNB DPM is disabled
+ =1: GNB DPM is enabled
+ulCPUCapInfo: TBD
+
+usExtDispConnInfoOffset: Offset to sExtDispConnInfo inside the structure
+usPanelRefreshRateRange: Bit vector for LCD supported refresh rate range. If DRR is requestd by the platform, at least two bits need to be set
+ to indicate a range.
+ SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004
+ SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008
+ SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010
+ SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020
+
+ucMemoryType: [3:0]=1:DDR1;=2:DDR2;=3:DDR3;=5:GDDR5; [7:4] is reserved.
+ucUMAChannelNumber: System memory channel numbers.
+
+strVBIOSMsg[40]: VBIOS boot up customized message string
+
+sAvail_SCLK[5]: Arrays to provide availabe list of SLCK and corresponding voltage, order from low to high
+
+ulGMCRestoreResetTime: GMC power restore and GMC reset time to calculate data reconnection latency. Unit in ns.
+ulIdleNClk: NCLK speed while memory runs in self-refresh state, used to calculate self-refresh latency. Unit in 10kHz.
+ulDDR_DLL_PowerUpTime: DDR PHY DLL power up time. Unit in ns.
+ulDDR_PLL_PowerUpTime: DDR PHY PLL power up time. Unit in ns.
+
+usPCIEClkSSPercentage: PCIE Clock Spread Spectrum Percentage in unit 0.01%; 100 mean 1%.
+usPCIEClkSSType: PCIE Clock Spread Spectrum Type. 0 for Down spread(default); 1 for Center spread.
+usLvdsSSPercentage: LVDS panel ( not include eDP ) Spread Spectrum Percentage in unit of 0.01%, =0, use VBIOS default setting.
+usLvdsSSpreadRateIn10Hz: LVDS panel ( not include eDP ) Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting.
+usHDMISSPercentage: HDMI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting.
+usHDMISSpreadRateIn10Hz: HDMI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting.
+usDVISSPercentage: DVI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting.
+usDVISSpreadRateIn10Hz: DVI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting.
+
+usGPUReservedSysMemSize: Reserved system memory size for ACP engine in APU GNB, units in MB. 0/2/4MB based on CMOS options, current default could be 0MB. KV only, not on KB.
+ulGPUReservedSysMemBaseAddrLo: Low 32 bits base address to the reserved system memory.
+ulGPUReservedSysMemBaseAddrHi: High 32 bits base address to the reserved system memory.
+
+usMaxLVDSPclkFreqInSingleLink: Max pixel clock LVDS panel single link, if=0 means VBIOS use default threhold, right now it is 85Mhz
+ucLVDSMisc: [bit0] LVDS 888bit panel mode =0: LVDS 888 panel in LDI mode, =1: LVDS 888 panel in FPDI mode
+ [bit1] LVDS panel lower and upper link mapping =0: lower link and upper link not swap, =1: lower link and upper link are swapped
+ [bit2] LVDS 888bit per color mode =0: 666 bit per color =1:888 bit per color
+ [bit3] LVDS parameter override enable =0: ucLvdsMisc parameter are not used =1: ucLvdsMisc parameter should be used
+ [bit4] Polarity of signal sent to digital BLON output pin. =0: not inverted(active high) =1: inverted ( active low )
+ [bit5] Travid LVDS output voltage override enable, when =1, use ucTravisLVDSVolAdjust value to overwrite Traivs register LVDS_CTRL_4
+ucTravisLVDSVolAdjust When ucLVDSMisc[5]=1,it means platform SBIOS want to overwrite TravisLVDSVoltage. Then VBIOS will use ucTravisLVDSVolAdjust
+ value to program Travis register LVDS_CTRL_4
+ucLVDSPwrOnSeqDIGONtoDE_in4Ms:
+ LVDS power up sequence time in unit of 4ms, time delay from DIGON signal active to data enable signal active( DE ).
+ =0 mean use VBIOS default which is 8 ( 32ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON.
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOnDEtoVARY_BL_in4Ms:
+ LVDS power up sequence time in unit of 4ms., time delay from DE( data enable ) active to Vary Brightness enable signal active( VARY_BL ).
+ =0 mean use VBIOS default which is 90 ( 360ms ). The LVDS power up sequence is as following: DIGON->DE->VARY_BL->BLON.
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOffVARY_BLtoDE_in4Ms:
+ LVDS power down sequence time in unit of 4ms, time delay from data enable ( DE ) signal off to LCDVCC (DIGON) off.
+ =0 mean use VBIOS default delay which is 8 ( 32ms ). The LVDS power down sequence is as following: BLON->VARY_BL->DE->DIGON
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOffDEtoDIGON_in4Ms:
+ LVDS power down sequence time in unit of 4ms, time delay from vary brightness enable signal( VARY_BL) off to data enable ( DE ) signal off.
+ =0 mean use VBIOS default which is 90 ( 360ms ). The LVDS power down sequence is as following: BLON->VARY_BL->DE->DIGON
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSOffToOnDelay_in4Ms:
+ LVDS power down sequence time in unit of 4ms. Time delay from DIGON signal off to DIGON signal active.
+ =0 means to use VBIOS default delay which is 125 ( 500ms ).
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms:
+ LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active.
+ =0 means to use VBIOS default delay which is 0 ( 0ms ).
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+
+ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms:
+ LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off.
+ =0 means to use VBIOS default delay which is 0 ( 0ms ).
+ This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
+ucMinAllowedBL_Level: Lowest LCD backlight PWM level. This is customer platform specific parameters. By default it is 0.
+
+ulLCDBitDepthControlVal: GPU display control encoder bit dither control setting, used to program register mmFMT_BIT_DEPTH_CONTROL
+
+ulNbpStateMemclkFreq[4]: system memory clock frequncey in unit of 10Khz in different NB P-State(P0, P1, P2 & P3).
+ulNbpStateNClkFreq[4]: NB P-State NClk frequency in different NB P-State
+usNBPStateVoltage[4]: NB P-State (P0/P1 & P2/P3) voltage; NBP3 refers to lowes voltage
+usBootUpNBVoltage: NB P-State voltage during boot up before driver loaded
+sExtDispConnInfo: Display connector information table provided to VBIOS
+
+**********************************************************************************************************************/
+
+// this Table is used for Kaveri/Kabini APU
+typedef struct _ATOM_FUSION_SYSTEM_INFO_V2
+{
+ ATOM_INTEGRATED_SYSTEM_INFO_V1_8 sIntegratedSysInfo; // refer to ATOM_INTEGRATED_SYSTEM_INFO_V1_8 definition
+ ULONG ulPowerplayTable[128]; // Update comments here to link new powerplay table definition structure
+}ATOM_FUSION_SYSTEM_INFO_V2;
+
+
+typedef struct _ATOM_I2C_REG_INFO
+{
+ UCHAR ucI2cRegIndex;
+ UCHAR ucI2cRegVal;
+}ATOM_I2C_REG_INFO;
+
+// this IntegrateSystemInfoTable is used for Carrizo
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_9
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulBootUpEngineClock;
+ ULONG ulDentistVCOFreq;
+ ULONG ulBootUpUMAClock;
+ ATOM_CLK_VOLT_CAPABILITY sDISPCLK_Voltage[4]; // no longer used, keep it as is to avoid driver compiling error
+ ULONG ulBootUpReqDisplayVector;
+ ULONG ulVBIOSMisc;
+ ULONG ulGPUCapInfo;
+ ULONG ulDISP_CLK2Freq;
+ USHORT usRequestedPWMFreqInHz;
+ UCHAR ucHtcTmpLmt;
+ UCHAR ucHtcHystLmt;
+ ULONG ulReserved2;
+ ULONG ulSystemConfig;
+ ULONG ulCPUCapInfo;
+ ULONG ulReserved3;
+ USHORT usGPUReservedSysMemSize;
+ USHORT usExtDispConnInfoOffset;
+ USHORT usPanelRefreshRateRange;
+ UCHAR ucMemoryType;
+ UCHAR ucUMAChannelNumber;
+ UCHAR strVBIOSMsg[40];
+ ATOM_TDP_CONFIG asTdpConfig;
+ UCHAR ucExtHDMIReDrvSlvAddr;
+ UCHAR ucExtHDMIReDrvRegNum;
+ ATOM_I2C_REG_INFO asExtHDMIRegSetting[9];
+ ULONG ulReserved[2];
+ ATOM_CLK_VOLT_CAPABILITY_V2 sDispClkVoltageMapping[8];
+ ATOM_AVAILABLE_SCLK_LIST sAvail_SCLK[5]; // no longer used, keep it as is to avoid driver compiling error
+ ULONG ulGMCRestoreResetTime;
+ ULONG ulReserved4;
+ ULONG ulIdleNClk;
+ ULONG ulDDR_DLL_PowerUpTime;
+ ULONG ulDDR_PLL_PowerUpTime;
+ USHORT usPCIEClkSSPercentage;
+ USHORT usPCIEClkSSType;
+ USHORT usLvdsSSPercentage;
+ USHORT usLvdsSSpreadRateIn10Hz;
+ USHORT usHDMISSPercentage;
+ USHORT usHDMISSpreadRateIn10Hz;
+ USHORT usDVISSPercentage;
+ USHORT usDVISSpreadRateIn10Hz;
+ ULONG ulGPUReservedSysMemBaseAddrLo;
+ ULONG ulGPUReservedSysMemBaseAddrHi;
+ ULONG ulReserved5[3];
+ USHORT usMaxLVDSPclkFreqInSingleLink;
+ UCHAR ucLvdsMisc;
+ UCHAR ucTravisLVDSVolAdjust;
+ UCHAR ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
+ UCHAR ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
+ UCHAR ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
+ UCHAR ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
+ UCHAR ucLVDSOffToOnDelay_in4Ms;
+ UCHAR ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
+ UCHAR ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
+ UCHAR ucMinAllowedBL_Level;
+ ULONG ulLCDBitDepthControlVal;
+ ULONG ulNbpStateMemclkFreq[4]; // only 2 level is changed.
+ ULONG ulPSPVersion;
+ ULONG ulNbpStateNClkFreq[4];
+ USHORT usNBPStateVoltage[4];
+ USHORT usBootUpNBVoltage;
+ UCHAR ucEDPv1_4VSMode;
+ UCHAR ucReserved2;
+ ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo;
+}ATOM_INTEGRATED_SYSTEM_INFO_V1_9;
+
+
+// definition for ucEDPv1_4VSMode
+#define EDP_VS_LEGACY_MODE 0
+#define EDP_VS_LOW_VDIFF_MODE 1
+#define EDP_VS_HIGH_VDIFF_MODE 2
+#define EDP_VS_STRETCH_MODE 3
+#define EDP_VS_SINGLE_VDIFF_MODE 4
+#define EDP_VS_VARIABLE_PREM_MODE 5
+
+
+// this IntegrateSystemInfoTable is used for Carrizo
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_10
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulBootUpEngineClock;
+ ULONG ulDentistVCOFreq;
+ ULONG ulBootUpUMAClock;
+ ULONG ulReserved0[8];
+ ULONG ulBootUpReqDisplayVector;
+ ULONG ulVBIOSMisc;
+ ULONG ulGPUCapInfo;
+ ULONG ulReserved1;
+ USHORT usRequestedPWMFreqInHz;
+ UCHAR ucHtcTmpLmt;
+ UCHAR ucHtcHystLmt;
+ ULONG ulReserved2;
+ ULONG ulSystemConfig;
+ ULONG ulCPUCapInfo;
+ ULONG ulReserved3;
+ USHORT usGPUReservedSysMemSize;
+ USHORT usExtDispConnInfoOffset;
+ USHORT usPanelRefreshRateRange;
+ UCHAR ucMemoryType;
+ UCHAR ucUMAChannelNumber;
+ UCHAR strVBIOSMsg[40];
+ ATOM_TDP_CONFIG asTdpConfig;
+ ULONG ulReserved[7];
+ ATOM_CLK_VOLT_CAPABILITY_V2 sDispClkVoltageMapping[8];
+ ULONG ulReserved6[10];
+ ULONG ulGMCRestoreResetTime;
+ ULONG ulReserved4;
+ ULONG ulIdleNClk;
+ ULONG ulDDR_DLL_PowerUpTime;
+ ULONG ulDDR_PLL_PowerUpTime;
+ USHORT usPCIEClkSSPercentage;
+ USHORT usPCIEClkSSType;
+ USHORT usLvdsSSPercentage;
+ USHORT usLvdsSSpreadRateIn10Hz;
+ USHORT usHDMISSPercentage;
+ USHORT usHDMISSpreadRateIn10Hz;
+ USHORT usDVISSPercentage;
+ USHORT usDVISSpreadRateIn10Hz;
+ ULONG ulGPUReservedSysMemBaseAddrLo;
+ ULONG ulGPUReservedSysMemBaseAddrHi;
+ ULONG ulReserved5[3];
+ USHORT usMaxLVDSPclkFreqInSingleLink;
+ UCHAR ucLvdsMisc;
+ UCHAR ucTravisLVDSVolAdjust;
+ UCHAR ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
+ UCHAR ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
+ UCHAR ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
+ UCHAR ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
+ UCHAR ucLVDSOffToOnDelay_in4Ms;
+ UCHAR ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
+ UCHAR ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
+ UCHAR ucMinAllowedBL_Level;
+ ULONG ulLCDBitDepthControlVal;
+ ULONG ulNbpStateMemclkFreq[2];
+ ULONG ulReserved7[2];
+ ULONG ulPSPVersion;
+ ULONG ulNbpStateNClkFreq[4];
+ USHORT usNBPStateVoltage[4];
+ USHORT usBootUpNBVoltage;
+ UCHAR ucEDPv1_4VSMode;
+ UCHAR ucReserved2;
+ ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo;
+}ATOM_INTEGRATED_SYSTEM_INFO_V1_10;
+
+/**************************************************************************/
+// This portion is only used when ext thermal chip or engine/memory clock SS chip is populated on a design
+//Memory SS Info Table
+//Define Memory Clock SS chip ID
+#define ICS91719 1
+#define ICS91720 2
+
+//Define one structure to inform SW a "block of data" writing to external SS chip via I2C protocol
+typedef struct _ATOM_I2C_DATA_RECORD
+{
+ UCHAR ucNunberOfBytes; //Indicates how many bytes SW needs to write to the external ASIC for one block, besides to "Start" and "Stop"
+ UCHAR ucI2CData[1]; //I2C data in bytes, should be less than 16 bytes usually
+}ATOM_I2C_DATA_RECORD;
+
+
+//Define one structure to inform SW how many blocks of data writing to external SS chip via I2C protocol, in addition to other information
+typedef struct _ATOM_I2C_DEVICE_SETUP_INFO
+{
+ ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; //I2C line and HW/SW assisted cap.
+ UCHAR ucSSChipID; //SS chip being used
+ UCHAR ucSSChipSlaveAddr; //Slave Address to set up this SS chip
+ UCHAR ucNumOfI2CDataRecords; //number of data block
+ ATOM_I2C_DATA_RECORD asI2CData[1];
+}ATOM_I2C_DEVICE_SETUP_INFO;
+
+//==========================================================================================
+typedef struct _ATOM_ASIC_MVDD_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_I2C_DEVICE_SETUP_INFO asI2CSetup[1];
+}ATOM_ASIC_MVDD_INFO;
+
+//==========================================================================================
+#define ATOM_MCLK_SS_INFO ATOM_ASIC_MVDD_INFO
+
+//==========================================================================================
+/**************************************************************************/
+
+typedef struct _ATOM_ASIC_SS_ASSIGNMENT
+{
+ ULONG ulTargetClockRange; //Clock Out frequence (VCO ), in unit of 10Khz
+ USHORT usSpreadSpectrumPercentage; //in unit of 0.01%
+ USHORT usSpreadRateInKhz; //in unit of kHz, modulation freq
+ UCHAR ucClockIndication; //Indicate which clock source needs SS
+ UCHAR ucSpreadSpectrumMode; //Bit1=0 Down Spread,=1 Center Spread.
+ UCHAR ucReserved[2];
+}ATOM_ASIC_SS_ASSIGNMENT;
+
+//Define ucClockIndication, SW uses the IDs below to search if the SS is requried/enabled on a clock branch/signal type.
+//SS is not required or enabled if a match is not found.
+#define ASIC_INTERNAL_MEMORY_SS 1
+#define ASIC_INTERNAL_ENGINE_SS 2
+#define ASIC_INTERNAL_UVD_SS 3
+#define ASIC_INTERNAL_SS_ON_TMDS 4
+#define ASIC_INTERNAL_SS_ON_HDMI 5
+#define ASIC_INTERNAL_SS_ON_LVDS 6
+#define ASIC_INTERNAL_SS_ON_DP 7
+#define ASIC_INTERNAL_SS_ON_DCPLL 8
+#define ASIC_EXTERNAL_SS_ON_DP_CLOCK 9
+#define ASIC_INTERNAL_VCE_SS 10
+#define ASIC_INTERNAL_GPUPLL_SS 11
+
+
+typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V2
+{
+ ULONG ulTargetClockRange; //For mem/engine/uvd, Clock Out frequence (VCO ), in unit of 10Khz
+ //For TMDS/HDMI/LVDS, it is pixel clock , for DP, it is link clock ( 27000 or 16200 )
+ USHORT usSpreadSpectrumPercentage; //in unit of 0.01%
+ USHORT usSpreadRateIn10Hz; //in unit of 10Hz, modulation freq
+ UCHAR ucClockIndication; //Indicate which clock source needs SS
+ UCHAR ucSpreadSpectrumMode; //Bit0=0 Down Spread,=1 Center Spread, bit1=0: internal SS bit1=1: external SS
+ UCHAR ucReserved[2];
+}ATOM_ASIC_SS_ASSIGNMENT_V2;
+
+//ucSpreadSpectrumMode
+//#define ATOM_SS_DOWN_SPREAD_MODE_MASK 0x00000000
+//#define ATOM_SS_DOWN_SPREAD_MODE 0x00000000
+//#define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001
+//#define ATOM_SS_CENTRE_SPREAD_MODE 0x00000001
+//#define ATOM_INTERNAL_SS_MASK 0x00000000
+//#define ATOM_EXTERNAL_SS_MASK 0x00000002
+
+typedef struct _ATOM_ASIC_INTERNAL_SS_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_ASIC_SS_ASSIGNMENT asSpreadSpectrum[4];
+}ATOM_ASIC_INTERNAL_SS_INFO;
+
+typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_ASIC_SS_ASSIGNMENT_V2 asSpreadSpectrum[1]; //this is point only.
+}ATOM_ASIC_INTERNAL_SS_INFO_V2;
+
+typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V3
+{
+ ULONG ulTargetClockRange; //For mem/engine/uvd, Clock Out frequence (VCO ), in unit of 10Khz
+ //For TMDS/HDMI/LVDS, it is pixel clock , for DP, it is link clock ( 27000 or 16200 )
+ USHORT usSpreadSpectrumPercentage; //in unit of 0.01% or 0.001%, decided by ucSpreadSpectrumMode bit4
+ USHORT usSpreadRateIn10Hz; //in unit of 10Hz, modulation freq
+ UCHAR ucClockIndication; //Indicate which clock source needs SS
+ UCHAR ucSpreadSpectrumMode; //Bit0=0 Down Spread,=1 Center Spread, bit1=0: internal SS bit1=1: external SS
+ UCHAR ucReserved[2];
+}ATOM_ASIC_SS_ASSIGNMENT_V3;
+
+//ATOM_ASIC_SS_ASSIGNMENT_V3.ucSpreadSpectrumMode
+#define SS_MODE_V3_CENTRE_SPREAD_MASK 0x01
+#define SS_MODE_V3_EXTERNAL_SS_MASK 0x02
+#define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10
+
+typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_ASIC_SS_ASSIGNMENT_V3 asSpreadSpectrum[1]; //this is pointer only.
+}ATOM_ASIC_INTERNAL_SS_INFO_V3;
+
+
+//==============================Scratch Pad Definition Portion===============================
+#define ATOM_DEVICE_CONNECT_INFO_DEF 0
+#define ATOM_ROM_LOCATION_DEF 1
+#define ATOM_TV_STANDARD_DEF 2
+#define ATOM_ACTIVE_INFO_DEF 3
+#define ATOM_LCD_INFO_DEF 4
+#define ATOM_DOS_REQ_INFO_DEF 5
+#define ATOM_ACC_CHANGE_INFO_DEF 6
+#define ATOM_DOS_MODE_INFO_DEF 7
+#define ATOM_I2C_CHANNEL_STATUS_DEF 8
+#define ATOM_I2C_CHANNEL_STATUS1_DEF 9
+#define ATOM_INTERNAL_TIMER_DEF 10
+
+// BIOS_0_SCRATCH Definition
+#define ATOM_S0_CRT1_MONO 0x00000001L
+#define ATOM_S0_CRT1_COLOR 0x00000002L
+#define ATOM_S0_CRT1_MASK (ATOM_S0_CRT1_MONO+ATOM_S0_CRT1_COLOR)
+
+#define ATOM_S0_TV1_COMPOSITE_A 0x00000004L
+#define ATOM_S0_TV1_SVIDEO_A 0x00000008L
+#define ATOM_S0_TV1_MASK_A (ATOM_S0_TV1_COMPOSITE_A+ATOM_S0_TV1_SVIDEO_A)
+
+#define ATOM_S0_CV_A 0x00000010L
+#define ATOM_S0_CV_DIN_A 0x00000020L
+#define ATOM_S0_CV_MASK_A (ATOM_S0_CV_A+ATOM_S0_CV_DIN_A)
+
+
+#define ATOM_S0_CRT2_MONO 0x00000100L
+#define ATOM_S0_CRT2_COLOR 0x00000200L
+#define ATOM_S0_CRT2_MASK (ATOM_S0_CRT2_MONO+ATOM_S0_CRT2_COLOR)
+
+#define ATOM_S0_TV1_COMPOSITE 0x00000400L
+#define ATOM_S0_TV1_SVIDEO 0x00000800L
+#define ATOM_S0_TV1_SCART 0x00004000L
+#define ATOM_S0_TV1_MASK (ATOM_S0_TV1_COMPOSITE+ATOM_S0_TV1_SVIDEO+ATOM_S0_TV1_SCART)
+
+#define ATOM_S0_CV 0x00001000L
+#define ATOM_S0_CV_DIN 0x00002000L
+#define ATOM_S0_CV_MASK (ATOM_S0_CV+ATOM_S0_CV_DIN)
+
+#define ATOM_S0_DFP1 0x00010000L
+#define ATOM_S0_DFP2 0x00020000L
+#define ATOM_S0_LCD1 0x00040000L
+#define ATOM_S0_LCD2 0x00080000L
+#define ATOM_S0_DFP6 0x00100000L
+#define ATOM_S0_DFP3 0x00200000L
+#define ATOM_S0_DFP4 0x00400000L
+#define ATOM_S0_DFP5 0x00800000L
+
+
+#define ATOM_S0_DFP_MASK ATOM_S0_DFP1 | ATOM_S0_DFP2 | ATOM_S0_DFP3 | ATOM_S0_DFP4 | ATOM_S0_DFP5 | ATOM_S0_DFP6
+
+#define ATOM_S0_FAD_REGISTER_BUG 0x02000000L // If set, indicates we are running a PCIE asic with
+ // the FAD/HDP reg access bug. Bit is read by DAL, this is obsolete from RV5xx
+
+#define ATOM_S0_THERMAL_STATE_MASK 0x1C000000L
+#define ATOM_S0_THERMAL_STATE_SHIFT 26
+
+#define ATOM_S0_SYSTEM_POWER_STATE_MASK 0xE0000000L
+#define ATOM_S0_SYSTEM_POWER_STATE_SHIFT 29
+
+#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_AC 1
+#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_DC 2
+#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LITEAC 3
+#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LIT2AC 4
+
+//Byte aligned defintion for BIOS usage
+#define ATOM_S0_CRT1_MONOb0 0x01
+#define ATOM_S0_CRT1_COLORb0 0x02
+#define ATOM_S0_CRT1_MASKb0 (ATOM_S0_CRT1_MONOb0+ATOM_S0_CRT1_COLORb0)
+
+#define ATOM_S0_TV1_COMPOSITEb0 0x04
+#define ATOM_S0_TV1_SVIDEOb0 0x08
+#define ATOM_S0_TV1_MASKb0 (ATOM_S0_TV1_COMPOSITEb0+ATOM_S0_TV1_SVIDEOb0)
+
+#define ATOM_S0_CVb0 0x10
+#define ATOM_S0_CV_DINb0 0x20
+#define ATOM_S0_CV_MASKb0 (ATOM_S0_CVb0+ATOM_S0_CV_DINb0)
+
+#define ATOM_S0_CRT2_MONOb1 0x01
+#define ATOM_S0_CRT2_COLORb1 0x02
+#define ATOM_S0_CRT2_MASKb1 (ATOM_S0_CRT2_MONOb1+ATOM_S0_CRT2_COLORb1)
+
+#define ATOM_S0_TV1_COMPOSITEb1 0x04
+#define ATOM_S0_TV1_SVIDEOb1 0x08
+#define ATOM_S0_TV1_SCARTb1 0x40
+#define ATOM_S0_TV1_MASKb1 (ATOM_S0_TV1_COMPOSITEb1+ATOM_S0_TV1_SVIDEOb1+ATOM_S0_TV1_SCARTb1)
+
+#define ATOM_S0_CVb1 0x10
+#define ATOM_S0_CV_DINb1 0x20
+#define ATOM_S0_CV_MASKb1 (ATOM_S0_CVb1+ATOM_S0_CV_DINb1)
+
+#define ATOM_S0_DFP1b2 0x01
+#define ATOM_S0_DFP2b2 0x02
+#define ATOM_S0_LCD1b2 0x04
+#define ATOM_S0_LCD2b2 0x08
+#define ATOM_S0_DFP6b2 0x10
+#define ATOM_S0_DFP3b2 0x20
+#define ATOM_S0_DFP4b2 0x40
+#define ATOM_S0_DFP5b2 0x80
+
+
+#define ATOM_S0_THERMAL_STATE_MASKb3 0x1C
+#define ATOM_S0_THERMAL_STATE_SHIFTb3 2
+
+#define ATOM_S0_SYSTEM_POWER_STATE_MASKb3 0xE0
+#define ATOM_S0_LCD1_SHIFT 18
+
+// BIOS_1_SCRATCH Definition
+#define ATOM_S1_ROM_LOCATION_MASK 0x0000FFFFL
+#define ATOM_S1_PCI_BUS_DEV_MASK 0xFFFF0000L
+
+// BIOS_2_SCRATCH Definition
+#define ATOM_S2_TV1_STANDARD_MASK 0x0000000FL
+#define ATOM_S2_CURRENT_BL_LEVEL_MASK 0x0000FF00L
+#define ATOM_S2_CURRENT_BL_LEVEL_SHIFT 8
+
+#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK 0x0C000000L
+#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK_SHIFT 26
+#define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGE 0x10000000L
+
+#define ATOM_S2_DEVICE_DPMS_STATE 0x00010000L
+#define ATOM_S2_VRI_BRIGHT_ENABLE 0x20000000L
+
+#define ATOM_S2_DISPLAY_ROTATION_0_DEGREE 0x0
+#define ATOM_S2_DISPLAY_ROTATION_90_DEGREE 0x1
+#define ATOM_S2_DISPLAY_ROTATION_180_DEGREE 0x2
+#define ATOM_S2_DISPLAY_ROTATION_270_DEGREE 0x3
+#define ATOM_S2_DISPLAY_ROTATION_DEGREE_SHIFT 30
+#define ATOM_S2_DISPLAY_ROTATION_ANGLE_MASK 0xC0000000L
+
+
+//Byte aligned defintion for BIOS usage
+#define ATOM_S2_TV1_STANDARD_MASKb0 0x0F
+#define ATOM_S2_CURRENT_BL_LEVEL_MASKb1 0xFF
+#define ATOM_S2_DEVICE_DPMS_STATEb2 0x01
+
+#define ATOM_S2_TMDS_COHERENT_MODEb3 0x10 // used by VBIOS code only, use coherent mode for TMDS/HDMI mode
+#define ATOM_S2_VRI_BRIGHT_ENABLEb3 0x20
+#define ATOM_S2_ROTATION_STATE_MASKb3 0xC0
+
+
+// BIOS_3_SCRATCH Definition
+#define ATOM_S3_CRT1_ACTIVE 0x00000001L
+#define ATOM_S3_LCD1_ACTIVE 0x00000002L
+#define ATOM_S3_TV1_ACTIVE 0x00000004L
+#define ATOM_S3_DFP1_ACTIVE 0x00000008L
+#define ATOM_S3_CRT2_ACTIVE 0x00000010L
+#define ATOM_S3_LCD2_ACTIVE 0x00000020L
+#define ATOM_S3_DFP6_ACTIVE 0x00000040L
+#define ATOM_S3_DFP2_ACTIVE 0x00000080L
+#define ATOM_S3_CV_ACTIVE 0x00000100L
+#define ATOM_S3_DFP3_ACTIVE 0x00000200L
+#define ATOM_S3_DFP4_ACTIVE 0x00000400L
+#define ATOM_S3_DFP5_ACTIVE 0x00000800L
+
+
+#define ATOM_S3_DEVICE_ACTIVE_MASK 0x00000FFFL
+
+#define ATOM_S3_LCD_FULLEXPANSION_ACTIVE 0x00001000L
+#define ATOM_S3_LCD_EXPANSION_ASPEC_RATIO_ACTIVE 0x00002000L
+
+#define ATOM_S3_CRT1_CRTC_ACTIVE 0x00010000L
+#define ATOM_S3_LCD1_CRTC_ACTIVE 0x00020000L
+#define ATOM_S3_TV1_CRTC_ACTIVE 0x00040000L
+#define ATOM_S3_DFP1_CRTC_ACTIVE 0x00080000L
+#define ATOM_S3_CRT2_CRTC_ACTIVE 0x00100000L
+#define ATOM_S3_LCD2_CRTC_ACTIVE 0x00200000L
+#define ATOM_S3_DFP6_CRTC_ACTIVE 0x00400000L
+#define ATOM_S3_DFP2_CRTC_ACTIVE 0x00800000L
+#define ATOM_S3_CV_CRTC_ACTIVE 0x01000000L
+#define ATOM_S3_DFP3_CRTC_ACTIVE 0x02000000L
+#define ATOM_S3_DFP4_CRTC_ACTIVE 0x04000000L
+#define ATOM_S3_DFP5_CRTC_ACTIVE 0x08000000L
+
+
+#define ATOM_S3_DEVICE_CRTC_ACTIVE_MASK 0x0FFF0000L
+#define ATOM_S3_ASIC_GUI_ENGINE_HUNG 0x20000000L
+//Below two definitions are not supported in pplib, but in the old powerplay in DAL
+#define ATOM_S3_ALLOW_FAST_PWR_SWITCH 0x40000000L
+#define ATOM_S3_RQST_GPU_USE_MIN_PWR 0x80000000L
+
+
+
+//Byte aligned defintion for BIOS usage
+#define ATOM_S3_CRT1_ACTIVEb0 0x01
+#define ATOM_S3_LCD1_ACTIVEb0 0x02
+#define ATOM_S3_TV1_ACTIVEb0 0x04
+#define ATOM_S3_DFP1_ACTIVEb0 0x08
+#define ATOM_S3_CRT2_ACTIVEb0 0x10
+#define ATOM_S3_LCD2_ACTIVEb0 0x20
+#define ATOM_S3_DFP6_ACTIVEb0 0x40
+#define ATOM_S3_DFP2_ACTIVEb0 0x80
+#define ATOM_S3_CV_ACTIVEb1 0x01
+#define ATOM_S3_DFP3_ACTIVEb1 0x02
+#define ATOM_S3_DFP4_ACTIVEb1 0x04
+#define ATOM_S3_DFP5_ACTIVEb1 0x08
+
+
+#define ATOM_S3_ACTIVE_CRTC1w0 0xFFF
+
+#define ATOM_S3_CRT1_CRTC_ACTIVEb2 0x01
+#define ATOM_S3_LCD1_CRTC_ACTIVEb2 0x02
+#define ATOM_S3_TV1_CRTC_ACTIVEb2 0x04
+#define ATOM_S3_DFP1_CRTC_ACTIVEb2 0x08
+#define ATOM_S3_CRT2_CRTC_ACTIVEb2 0x10
+#define ATOM_S3_LCD2_CRTC_ACTIVEb2 0x20
+#define ATOM_S3_DFP6_CRTC_ACTIVEb2 0x40
+#define ATOM_S3_DFP2_CRTC_ACTIVEb2 0x80
+#define ATOM_S3_CV_CRTC_ACTIVEb3 0x01
+#define ATOM_S3_DFP3_CRTC_ACTIVEb3 0x02
+#define ATOM_S3_DFP4_CRTC_ACTIVEb3 0x04
+#define ATOM_S3_DFP5_CRTC_ACTIVEb3 0x08
+
+
+#define ATOM_S3_ACTIVE_CRTC2w1 0xFFF
+
+
+// BIOS_4_SCRATCH Definition
+#define ATOM_S4_LCD1_PANEL_ID_MASK 0x000000FFL
+#define ATOM_S4_LCD1_REFRESH_MASK 0x0000FF00L
+#define ATOM_S4_LCD1_REFRESH_SHIFT 8
+
+//Byte aligned defintion for BIOS usage
+#define ATOM_S4_LCD1_PANEL_ID_MASKb0 0x0FF
+#define ATOM_S4_LCD1_REFRESH_MASKb1 ATOM_S4_LCD1_PANEL_ID_MASKb0
+#define ATOM_S4_VRAM_INFO_MASKb2 ATOM_S4_LCD1_PANEL_ID_MASKb0
+
+// BIOS_5_SCRATCH Definition, BIOS_5_SCRATCH is used by Firmware only !!!!
+#define ATOM_S5_DOS_REQ_CRT1b0 0x01
+#define ATOM_S5_DOS_REQ_LCD1b0 0x02
+#define ATOM_S5_DOS_REQ_TV1b0 0x04
+#define ATOM_S5_DOS_REQ_DFP1b0 0x08
+#define ATOM_S5_DOS_REQ_CRT2b0 0x10
+#define ATOM_S5_DOS_REQ_LCD2b0 0x20
+#define ATOM_S5_DOS_REQ_DFP6b0 0x40
+#define ATOM_S5_DOS_REQ_DFP2b0 0x80
+#define ATOM_S5_DOS_REQ_CVb1 0x01
+#define ATOM_S5_DOS_REQ_DFP3b1 0x02
+#define ATOM_S5_DOS_REQ_DFP4b1 0x04
+#define ATOM_S5_DOS_REQ_DFP5b1 0x08
+
+
+#define ATOM_S5_DOS_REQ_DEVICEw0 0x0FFF
+
+#define ATOM_S5_DOS_REQ_CRT1 0x0001
+#define ATOM_S5_DOS_REQ_LCD1 0x0002
+#define ATOM_S5_DOS_REQ_TV1 0x0004
+#define ATOM_S5_DOS_REQ_DFP1 0x0008
+#define ATOM_S5_DOS_REQ_CRT2 0x0010
+#define ATOM_S5_DOS_REQ_LCD2 0x0020
+#define ATOM_S5_DOS_REQ_DFP6 0x0040
+#define ATOM_S5_DOS_REQ_DFP2 0x0080
+#define ATOM_S5_DOS_REQ_CV 0x0100
+#define ATOM_S5_DOS_REQ_DFP3 0x0200
+#define ATOM_S5_DOS_REQ_DFP4 0x0400
+#define ATOM_S5_DOS_REQ_DFP5 0x0800
+
+#define ATOM_S5_DOS_FORCE_CRT1b2 ATOM_S5_DOS_REQ_CRT1b0
+#define ATOM_S5_DOS_FORCE_TV1b2 ATOM_S5_DOS_REQ_TV1b0
+#define ATOM_S5_DOS_FORCE_CRT2b2 ATOM_S5_DOS_REQ_CRT2b0
+#define ATOM_S5_DOS_FORCE_CVb3 ATOM_S5_DOS_REQ_CVb1
+#define ATOM_S5_DOS_FORCE_DEVICEw1 (ATOM_S5_DOS_FORCE_CRT1b2+ATOM_S5_DOS_FORCE_TV1b2+ATOM_S5_DOS_FORCE_CRT2b2+\
+ (ATOM_S5_DOS_FORCE_CVb3<<8))
+// BIOS_6_SCRATCH Definition
+#define ATOM_S6_DEVICE_CHANGE 0x00000001L
+#define ATOM_S6_SCALER_CHANGE 0x00000002L
+#define ATOM_S6_LID_CHANGE 0x00000004L
+#define ATOM_S6_DOCKING_CHANGE 0x00000008L
+#define ATOM_S6_ACC_MODE 0x00000010L
+#define ATOM_S6_EXT_DESKTOP_MODE 0x00000020L
+#define ATOM_S6_LID_STATE 0x00000040L
+#define ATOM_S6_DOCK_STATE 0x00000080L
+#define ATOM_S6_CRITICAL_STATE 0x00000100L
+#define ATOM_S6_HW_I2C_BUSY_STATE 0x00000200L
+#define ATOM_S6_THERMAL_STATE_CHANGE 0x00000400L
+#define ATOM_S6_INTERRUPT_SET_BY_BIOS 0x00000800L
+#define ATOM_S6_REQ_LCD_EXPANSION_FULL 0x00001000L //Normal expansion Request bit for LCD
+#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO 0x00002000L //Aspect ratio expansion Request bit for LCD
+
+#define ATOM_S6_DISPLAY_STATE_CHANGE 0x00004000L //This bit is recycled when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_H_expansion
+#define ATOM_S6_I2C_STATE_CHANGE 0x00008000L //This bit is recycled,when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_V_expansion
+
+#define ATOM_S6_ACC_REQ_CRT1 0x00010000L
+#define ATOM_S6_ACC_REQ_LCD1 0x00020000L
+#define ATOM_S6_ACC_REQ_TV1 0x00040000L
+#define ATOM_S6_ACC_REQ_DFP1 0x00080000L
+#define ATOM_S6_ACC_REQ_CRT2 0x00100000L
+#define ATOM_S6_ACC_REQ_LCD2 0x00200000L
+#define ATOM_S6_ACC_REQ_DFP6 0x00400000L
+#define ATOM_S6_ACC_REQ_DFP2 0x00800000L
+#define ATOM_S6_ACC_REQ_CV 0x01000000L
+#define ATOM_S6_ACC_REQ_DFP3 0x02000000L
+#define ATOM_S6_ACC_REQ_DFP4 0x04000000L
+#define ATOM_S6_ACC_REQ_DFP5 0x08000000L
+
+#define ATOM_S6_ACC_REQ_MASK 0x0FFF0000L
+#define ATOM_S6_SYSTEM_POWER_MODE_CHANGE 0x10000000L
+#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH 0x20000000L
+#define ATOM_S6_VRI_BRIGHTNESS_CHANGE 0x40000000L
+#define ATOM_S6_CONFIG_DISPLAY_CHANGE_MASK 0x80000000L
+
+//Byte aligned defintion for BIOS usage
+#define ATOM_S6_DEVICE_CHANGEb0 0x01
+#define ATOM_S6_SCALER_CHANGEb0 0x02
+#define ATOM_S6_LID_CHANGEb0 0x04
+#define ATOM_S6_DOCKING_CHANGEb0 0x08
+#define ATOM_S6_ACC_MODEb0 0x10
+#define ATOM_S6_EXT_DESKTOP_MODEb0 0x20
+#define ATOM_S6_LID_STATEb0 0x40
+#define ATOM_S6_DOCK_STATEb0 0x80
+#define ATOM_S6_CRITICAL_STATEb1 0x01
+#define ATOM_S6_HW_I2C_BUSY_STATEb1 0x02
+#define ATOM_S6_THERMAL_STATE_CHANGEb1 0x04
+#define ATOM_S6_INTERRUPT_SET_BY_BIOSb1 0x08
+#define ATOM_S6_REQ_LCD_EXPANSION_FULLb1 0x10
+#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIOb1 0x20
+
+#define ATOM_S6_ACC_REQ_CRT1b2 0x01
+#define ATOM_S6_ACC_REQ_LCD1b2 0x02
+#define ATOM_S6_ACC_REQ_TV1b2 0x04
+#define ATOM_S6_ACC_REQ_DFP1b2 0x08
+#define ATOM_S6_ACC_REQ_CRT2b2 0x10
+#define ATOM_S6_ACC_REQ_LCD2b2 0x20
+#define ATOM_S6_ACC_REQ_DFP6b2 0x40
+#define ATOM_S6_ACC_REQ_DFP2b2 0x80
+#define ATOM_S6_ACC_REQ_CVb3 0x01
+#define ATOM_S6_ACC_REQ_DFP3b3 0x02
+#define ATOM_S6_ACC_REQ_DFP4b3 0x04
+#define ATOM_S6_ACC_REQ_DFP5b3 0x08
+
+#define ATOM_S6_ACC_REQ_DEVICEw1 ATOM_S5_DOS_REQ_DEVICEw0
+#define ATOM_S6_SYSTEM_POWER_MODE_CHANGEb3 0x10
+#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCHb3 0x20
+#define ATOM_S6_VRI_BRIGHTNESS_CHANGEb3 0x40
+#define ATOM_S6_CONFIG_DISPLAY_CHANGEb3 0x80
+
+#define ATOM_S6_DEVICE_CHANGE_SHIFT 0
+#define ATOM_S6_SCALER_CHANGE_SHIFT 1
+#define ATOM_S6_LID_CHANGE_SHIFT 2
+#define ATOM_S6_DOCKING_CHANGE_SHIFT 3
+#define ATOM_S6_ACC_MODE_SHIFT 4
+#define ATOM_S6_EXT_DESKTOP_MODE_SHIFT 5
+#define ATOM_S6_LID_STATE_SHIFT 6
+#define ATOM_S6_DOCK_STATE_SHIFT 7
+#define ATOM_S6_CRITICAL_STATE_SHIFT 8
+#define ATOM_S6_HW_I2C_BUSY_STATE_SHIFT 9
+#define ATOM_S6_THERMAL_STATE_CHANGE_SHIFT 10
+#define ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT 11
+#define ATOM_S6_REQ_SCALER_SHIFT 12
+#define ATOM_S6_REQ_SCALER_ARATIO_SHIFT 13
+#define ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT 14
+#define ATOM_S6_I2C_STATE_CHANGE_SHIFT 15
+#define ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT 28
+#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH_SHIFT 29
+#define ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT 30
+#define ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT 31
+
+// BIOS_7_SCRATCH Definition, BIOS_7_SCRATCH is used by Firmware only !!!!
+#define ATOM_S7_DOS_MODE_TYPEb0 0x03
+#define ATOM_S7_DOS_MODE_VGAb0 0x00
+#define ATOM_S7_DOS_MODE_VESAb0 0x01
+#define ATOM_S7_DOS_MODE_EXTb0 0x02
+#define ATOM_S7_DOS_MODE_PIXEL_DEPTHb0 0x0C
+#define ATOM_S7_DOS_MODE_PIXEL_FORMATb0 0xF0
+#define ATOM_S7_DOS_8BIT_DAC_ENb1 0x01
+#define ATOM_S7_ASIC_INIT_COMPLETEb1 0x02
+#define ATOM_S7_ASIC_INIT_COMPLETE_MASK 0x00000200
+#define ATOM_S7_DOS_MODE_NUMBERw1 0x0FFFF
+
+#define ATOM_S7_DOS_8BIT_DAC_EN_SHIFT 8
+
+// BIOS_8_SCRATCH Definition
+#define ATOM_S8_I2C_CHANNEL_BUSY_MASK 0x00000FFFF
+#define ATOM_S8_I2C_HW_ENGINE_BUSY_MASK 0x0FFFF0000
+
+#define ATOM_S8_I2C_CHANNEL_BUSY_SHIFT 0
+#define ATOM_S8_I2C_ENGINE_BUSY_SHIFT 16
+
+// BIOS_9_SCRATCH Definition
+#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_MASK
+#define ATOM_S9_I2C_CHANNEL_COMPLETED_MASK 0x0000FFFF
+#endif
+#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_MASK
+#define ATOM_S9_I2C_CHANNEL_ABORTED_MASK 0xFFFF0000
+#endif
+#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT
+#define ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT 0
+#endif
+#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT
+#define ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT 16
+#endif
+
+
+#define ATOM_FLAG_SET 0x20
+#define ATOM_FLAG_CLEAR 0
+#define CLEAR_ATOM_S6_ACC_MODE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_ACC_MODE_SHIFT | ATOM_FLAG_CLEAR)
+#define SET_ATOM_S6_DEVICE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DEVICE_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_VRI_BRIGHTNESS_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_SCALER_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_SCALER_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_LID_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_CHANGE_SHIFT | ATOM_FLAG_SET)
+
+#define SET_ATOM_S6_LID_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S6_LID_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_CLEAR)
+
+#define SET_ATOM_S6_DOCK_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCKING_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_DOCK_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S6_DOCK_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_CLEAR)
+
+#define SET_ATOM_S6_THERMAL_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_THERMAL_STATE_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_SYSTEM_POWER_MODE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_INTERRUPT_SET_BY_BIOS ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT | ATOM_FLAG_SET)
+
+#define SET_ATOM_S6_CRITICAL_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S6_CRITICAL_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_CLEAR)
+
+#define SET_ATOM_S6_REQ_SCALER ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S6_REQ_SCALER ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_CLEAR )
+
+#define SET_ATOM_S6_REQ_SCALER_ARATIO ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_SET )
+#define CLEAR_ATOM_S6_REQ_SCALER_ARATIO ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_CLEAR )
+
+#define SET_ATOM_S6_I2C_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_I2C_STATE_CHANGE_SHIFT | ATOM_FLAG_SET )
+
+#define SET_ATOM_S6_DISPLAY_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT | ATOM_FLAG_SET )
+
+#define SET_ATOM_S6_DEVICE_RECONFIG ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S0_LCD1 ((ATOM_DEVICE_CONNECT_INFO_DEF << 8 )| ATOM_S0_LCD1_SHIFT | ATOM_FLAG_CLEAR )
+#define SET_ATOM_S7_DOS_8BIT_DAC_EN ((ATOM_DOS_MODE_INFO_DEF << 8 )|ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_SET )
+#define CLEAR_ATOM_S7_DOS_8BIT_DAC_EN ((ATOM_DOS_MODE_INFO_DEF << 8 )|ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_CLEAR )
+
+/****************************************************************************/
+//Portion II: Definitinos only used in Driver
+/****************************************************************************/
+
+// Macros used by driver
+
+#ifdef __cplusplus
+#define GetIndexIntoMasterTable(MasterOrData, FieldName) ((reinterpret_cast<char*>(&(static_cast<ATOM_MASTER_LIST_OF_##MasterOrData##_TABLES*>(0))->FieldName)-static_cast<char*>(0))/sizeof(USHORT))
+
+#define GET_COMMAND_TABLE_COMMANDSET_REVISION(TABLE_HEADER_OFFSET) (((static_cast<ATOM_COMMON_TABLE_HEADER*>(TABLE_HEADER_OFFSET))->ucTableFormatRevision )&0x3F)
+#define GET_COMMAND_TABLE_PARAMETER_REVISION(TABLE_HEADER_OFFSET) (((static_cast<ATOM_COMMON_TABLE_HEADER*>(TABLE_HEADER_OFFSET))->ucTableContentRevision)&0x3F)
+#else // not __cplusplus
+#define GetIndexIntoMasterTable(MasterOrData, FieldName) (((char*)(&((ATOM_MASTER_LIST_OF_##MasterOrData##_TABLES*)0)->FieldName)-(char*)0)/sizeof(USHORT))
+
+#define GET_COMMAND_TABLE_COMMANDSET_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableFormatRevision)&0x3F)
+#define GET_COMMAND_TABLE_PARAMETER_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableContentRevision)&0x3F)
+#endif // __cplusplus
+
+#define GET_DATA_TABLE_MAJOR_REVISION GET_COMMAND_TABLE_COMMANDSET_REVISION
+#define GET_DATA_TABLE_MINOR_REVISION GET_COMMAND_TABLE_PARAMETER_REVISION
+
+/****************************************************************************/
+//Portion III: Definitinos only used in VBIOS
+/****************************************************************************/
+#define ATOM_DAC_SRC 0x80
+#define ATOM_SRC_DAC1 0
+#define ATOM_SRC_DAC2 0x80
+
+
+
+typedef struct _MEMORY_PLLINIT_PARAMETERS
+{
+ ULONG ulTargetMemoryClock; //In 10Khz unit
+ UCHAR ucAction; //not define yet
+ UCHAR ucFbDiv_Hi; //Fbdiv Hi byte
+ UCHAR ucFbDiv; //FB value
+ UCHAR ucPostDiv; //Post div
+}MEMORY_PLLINIT_PARAMETERS;
+
+#define MEMORY_PLLINIT_PS_ALLOCATION MEMORY_PLLINIT_PARAMETERS
+
+
+#define GPIO_PIN_WRITE 0x01
+#define GPIO_PIN_READ 0x00
+
+typedef struct _GPIO_PIN_CONTROL_PARAMETERS
+{
+ UCHAR ucGPIO_ID; //return value, read from GPIO pins
+ UCHAR ucGPIOBitShift; //define which bit in uGPIOBitVal need to be update
+ UCHAR ucGPIOBitVal; //Set/Reset corresponding bit defined in ucGPIOBitMask
+ UCHAR ucAction; //=GPIO_PIN_WRITE: Read; =GPIO_PIN_READ: Write
+}GPIO_PIN_CONTROL_PARAMETERS;
+
+typedef struct _ENABLE_SCALER_PARAMETERS
+{
+ UCHAR ucScaler; // ATOM_SCALER1, ATOM_SCALER2
+ UCHAR ucEnable; // ATOM_SCALER_DISABLE or ATOM_SCALER_CENTER or ATOM_SCALER_EXPANSION
+ UCHAR ucTVStandard; //
+ UCHAR ucPadding[1];
+}ENABLE_SCALER_PARAMETERS;
+#define ENABLE_SCALER_PS_ALLOCATION ENABLE_SCALER_PARAMETERS
+
+//ucEnable:
+#define SCALER_BYPASS_AUTO_CENTER_NO_REPLICATION 0
+#define SCALER_BYPASS_AUTO_CENTER_AUTO_REPLICATION 1
+#define SCALER_ENABLE_2TAP_ALPHA_MODE 2
+#define SCALER_ENABLE_MULTITAP_MODE 3
+
+typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS
+{
+ ULONG usHWIconHorzVertPosn; // Hardware Icon Vertical position
+ UCHAR ucHWIconVertOffset; // Hardware Icon Vertical offset
+ UCHAR ucHWIconHorzOffset; // Hardware Icon Horizontal offset
+ UCHAR ucSelection; // ATOM_CURSOR1 or ATOM_ICON1 or ATOM_CURSOR2 or ATOM_ICON2
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+}ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS;
+
+typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION
+{
+ ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS sEnableIcon;
+ ENABLE_CRTC_PARAMETERS sReserved;
+}ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION;
+
+typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS
+{
+ USHORT usHight; // Image Hight
+ USHORT usWidth; // Image Width
+ UCHAR ucSurface; // Surface 1 or 2
+ UCHAR ucPadding[3];
+}ENABLE_GRAPH_SURFACE_PARAMETERS;
+
+typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2
+{
+ USHORT usHight; // Image Hight
+ USHORT usWidth; // Image Width
+ UCHAR ucSurface; // Surface 1 or 2
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucPadding[2];
+}ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2;
+
+typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_3
+{
+ USHORT usHight; // Image Hight
+ USHORT usWidth; // Image Width
+ UCHAR ucSurface; // Surface 1 or 2
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ USHORT usDeviceId; // Active Device Id for this surface. If no device, set to 0.
+}ENABLE_GRAPH_SURFACE_PARAMETERS_V1_3;
+
+typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_4
+{
+ USHORT usHight; // Image Hight
+ USHORT usWidth; // Image Width
+ USHORT usGraphPitch;
+ UCHAR ucColorDepth;
+ UCHAR ucPixelFormat;
+ UCHAR ucSurface; // Surface 1 or 2
+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE
+ UCHAR ucModeType;
+ UCHAR ucReserved;
+}ENABLE_GRAPH_SURFACE_PARAMETERS_V1_4;
+
+// ucEnable
+#define ATOM_GRAPH_CONTROL_SET_PITCH 0x0f
+#define ATOM_GRAPH_CONTROL_SET_DISP_START 0x10
+
+typedef struct _ENABLE_GRAPH_SURFACE_PS_ALLOCATION
+{
+ ENABLE_GRAPH_SURFACE_PARAMETERS sSetSurface;
+ ENABLE_YUV_PS_ALLOCATION sReserved; // Don't set this one
+}ENABLE_GRAPH_SURFACE_PS_ALLOCATION;
+
+typedef struct _MEMORY_CLEAN_UP_PARAMETERS
+{
+ USHORT usMemoryStart; //in 8Kb boundry, offset from memory base address
+ USHORT usMemorySize; //8Kb blocks aligned
+}MEMORY_CLEAN_UP_PARAMETERS;
+
+#define MEMORY_CLEAN_UP_PS_ALLOCATION MEMORY_CLEAN_UP_PARAMETERS
+
+typedef struct _GET_DISPLAY_SURFACE_SIZE_PARAMETERS
+{
+ USHORT usX_Size; //When use as input parameter, usX_Size indicates which CRTC
+ USHORT usY_Size;
+}GET_DISPLAY_SURFACE_SIZE_PARAMETERS;
+
+typedef struct _GET_DISPLAY_SURFACE_SIZE_PARAMETERS_V2
+{
+ union{
+ USHORT usX_Size; //When use as input parameter, usX_Size indicates which CRTC
+ USHORT usSurface;
+ };
+ USHORT usY_Size;
+ USHORT usDispXStart;
+ USHORT usDispYStart;
+}GET_DISPLAY_SURFACE_SIZE_PARAMETERS_V2;
+
+
+typedef struct _PALETTE_DATA_CONTROL_PARAMETERS_V3
+{
+ UCHAR ucLutId;
+ UCHAR ucAction;
+ USHORT usLutStartIndex;
+ USHORT usLutLength;
+ USHORT usLutOffsetInVram;
+}PALETTE_DATA_CONTROL_PARAMETERS_V3;
+
+// ucAction:
+#define PALETTE_DATA_AUTO_FILL 1
+#define PALETTE_DATA_READ 2
+#define PALETTE_DATA_WRITE 3
+
+
+typedef struct _INTERRUPT_SERVICE_PARAMETERS_V2
+{
+ UCHAR ucInterruptId;
+ UCHAR ucServiceId;
+ UCHAR ucStatus;
+ UCHAR ucReserved;
+}INTERRUPT_SERVICE_PARAMETER_V2;
+
+// ucInterruptId
+#define HDP1_INTERRUPT_ID 1
+#define HDP2_INTERRUPT_ID 2
+#define HDP3_INTERRUPT_ID 3
+#define HDP4_INTERRUPT_ID 4
+#define HDP5_INTERRUPT_ID 5
+#define HDP6_INTERRUPT_ID 6
+#define SW_INTERRUPT_ID 11
+
+// ucAction
+#define INTERRUPT_SERVICE_GEN_SW_INT 1
+#define INTERRUPT_SERVICE_GET_STATUS 2
+
+ // ucStatus
+#define INTERRUPT_STATUS__INT_TRIGGER 1
+#define INTERRUPT_STATUS__HPD_HIGH 2
+
+typedef struct _EFUSE_INPUT_PARAMETER
+{
+ USHORT usEfuseIndex;
+ UCHAR ucBitShift;
+ UCHAR ucBitLength;
+}EFUSE_INPUT_PARAMETER;
+
+// ReadEfuseValue command table input/output parameter
+typedef union _READ_EFUSE_VALUE_PARAMETER
+{
+ EFUSE_INPUT_PARAMETER sEfuse;
+ ULONG ulEfuseValue;
+}READ_EFUSE_VALUE_PARAMETER;
+
+typedef struct _INDIRECT_IO_ACCESS
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR IOAccessSequence[256];
+} INDIRECT_IO_ACCESS;
+
+#define INDIRECT_READ 0x00
+#define INDIRECT_WRITE 0x80
+
+#define INDIRECT_IO_MM 0
+#define INDIRECT_IO_PLL 1
+#define INDIRECT_IO_MC 2
+#define INDIRECT_IO_PCIE 3
+#define INDIRECT_IO_PCIEP 4
+#define INDIRECT_IO_NBMISC 5
+#define INDIRECT_IO_SMU 5
+
+#define INDIRECT_IO_PLL_READ INDIRECT_IO_PLL | INDIRECT_READ
+#define INDIRECT_IO_PLL_WRITE INDIRECT_IO_PLL | INDIRECT_WRITE
+#define INDIRECT_IO_MC_READ INDIRECT_IO_MC | INDIRECT_READ
+#define INDIRECT_IO_MC_WRITE INDIRECT_IO_MC | INDIRECT_WRITE
+#define INDIRECT_IO_PCIE_READ INDIRECT_IO_PCIE | INDIRECT_READ
+#define INDIRECT_IO_PCIE_WRITE INDIRECT_IO_PCIE | INDIRECT_WRITE
+#define INDIRECT_IO_PCIEP_READ INDIRECT_IO_PCIEP | INDIRECT_READ
+#define INDIRECT_IO_PCIEP_WRITE INDIRECT_IO_PCIEP | INDIRECT_WRITE
+#define INDIRECT_IO_NBMISC_READ INDIRECT_IO_NBMISC | INDIRECT_READ
+#define INDIRECT_IO_NBMISC_WRITE INDIRECT_IO_NBMISC | INDIRECT_WRITE
+#define INDIRECT_IO_SMU_READ INDIRECT_IO_SMU | INDIRECT_READ
+#define INDIRECT_IO_SMU_WRITE INDIRECT_IO_SMU | INDIRECT_WRITE
+
+
+typedef struct _ATOM_OEM_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;
+}ATOM_OEM_INFO;
+
+typedef struct _ATOM_TV_MODE
+{
+ UCHAR ucVMode_Num; //Video mode number
+ UCHAR ucTV_Mode_Num; //Internal TV mode number
+}ATOM_TV_MODE;
+
+typedef struct _ATOM_BIOS_INT_TVSTD_MODE
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usTV_Mode_LUT_Offset; // Pointer to standard to internal number conversion table
+ USHORT usTV_FIFO_Offset; // Pointer to FIFO entry table
+ USHORT usNTSC_Tbl_Offset; // Pointer to SDTV_Mode_NTSC table
+ USHORT usPAL_Tbl_Offset; // Pointer to SDTV_Mode_PAL table
+ USHORT usCV_Tbl_Offset; // Pointer to SDTV_Mode_PAL table
+}ATOM_BIOS_INT_TVSTD_MODE;
+
+
+typedef struct _ATOM_TV_MODE_SCALER_PTR
+{
+ USHORT ucFilter0_Offset; //Pointer to filter format 0 coefficients
+ USHORT usFilter1_Offset; //Pointer to filter format 0 coefficients
+ UCHAR ucTV_Mode_Num;
+}ATOM_TV_MODE_SCALER_PTR;
+
+typedef struct _ATOM_STANDARD_VESA_TIMING
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_DTD_FORMAT aModeTimings[16]; // 16 is not the real array number, just for initial allocation
+}ATOM_STANDARD_VESA_TIMING;
+
+
+typedef struct _ATOM_STD_FORMAT
+{
+ USHORT usSTD_HDisp;
+ USHORT usSTD_VDisp;
+ USHORT usSTD_RefreshRate;
+ USHORT usReserved;
+}ATOM_STD_FORMAT;
+
+typedef struct _ATOM_VESA_TO_EXTENDED_MODE
+{
+ USHORT usVESA_ModeNumber;
+ USHORT usExtendedModeNumber;
+}ATOM_VESA_TO_EXTENDED_MODE;
+
+typedef struct _ATOM_VESA_TO_INTENAL_MODE_LUT
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ATOM_VESA_TO_EXTENDED_MODE asVESA_ToExtendedModeInfo[76];
+}ATOM_VESA_TO_INTENAL_MODE_LUT;
+
+/*************** ATOM Memory Related Data Structure ***********************/
+typedef struct _ATOM_MEMORY_VENDOR_BLOCK{
+ UCHAR ucMemoryType;
+ UCHAR ucMemoryVendor;
+ UCHAR ucAdjMCId;
+ UCHAR ucDynClkId;
+ ULONG ulDllResetClkRange;
+}ATOM_MEMORY_VENDOR_BLOCK;
+
+
+typedef struct _ATOM_MEMORY_SETTING_ID_CONFIG{
+#if ATOM_BIG_ENDIAN
+ ULONG ucMemBlkId:8;
+ ULONG ulMemClockRange:24;
+#else
+ ULONG ulMemClockRange:24;
+ ULONG ucMemBlkId:8;
+#endif
+}ATOM_MEMORY_SETTING_ID_CONFIG;
+
+typedef union _ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS
+{
+ ATOM_MEMORY_SETTING_ID_CONFIG slAccess;
+ ULONG ulAccess;
+}ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS;
+
+
+typedef struct _ATOM_MEMORY_SETTING_DATA_BLOCK{
+ ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS ulMemoryID;
+ ULONG aulMemData[1];
+}ATOM_MEMORY_SETTING_DATA_BLOCK;
+
+
+typedef struct _ATOM_INIT_REG_INDEX_FORMAT{
+ USHORT usRegIndex; // MC register index
+ UCHAR ucPreRegDataLength; // offset in ATOM_INIT_REG_DATA_BLOCK.saRegDataBuf
+}ATOM_INIT_REG_INDEX_FORMAT;
+
+
+typedef struct _ATOM_INIT_REG_BLOCK{
+ USHORT usRegIndexTblSize; //size of asRegIndexBuf
+ USHORT usRegDataBlkSize; //size of ATOM_MEMORY_SETTING_DATA_BLOCK
+ ATOM_INIT_REG_INDEX_FORMAT asRegIndexBuf[1];
+ ATOM_MEMORY_SETTING_DATA_BLOCK asRegDataBuf[1];
+}ATOM_INIT_REG_BLOCK;
+
+#define END_OF_REG_INDEX_BLOCK 0x0ffff
+#define END_OF_REG_DATA_BLOCK 0x00000000
+#define ATOM_INIT_REG_MASK_FLAG 0x80 //Not used in BIOS
+#define CLOCK_RANGE_HIGHEST 0x00ffffff
+
+#define VALUE_DWORD SIZEOF ULONG
+#define VALUE_SAME_AS_ABOVE 0
+#define VALUE_MASK_DWORD 0x84
+
+#define INDEX_ACCESS_RANGE_BEGIN (VALUE_DWORD + 1)
+#define INDEX_ACCESS_RANGE_END (INDEX_ACCESS_RANGE_BEGIN + 1)
+#define VALUE_INDEX_ACCESS_SINGLE (INDEX_ACCESS_RANGE_END + 1)
+//#define ACCESS_MCIODEBUGIND 0x40 //defined in BIOS code
+#define ACCESS_PLACEHOLDER 0x80
+
+
+typedef struct _ATOM_MC_INIT_PARAM_TABLE
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usAdjustARB_SEQDataOffset;
+ USHORT usMCInitMemTypeTblOffset;
+ USHORT usMCInitCommonTblOffset;
+ USHORT usMCInitPowerDownTblOffset;
+ ULONG ulARB_SEQDataBuf[32];
+ ATOM_INIT_REG_BLOCK asMCInitMemType;
+ ATOM_INIT_REG_BLOCK asMCInitCommon;
+}ATOM_MC_INIT_PARAM_TABLE;
+
+
+typedef struct _ATOM_REG_INIT_SETTING
+{
+ USHORT usRegIndex;
+ ULONG ulRegValue;
+}ATOM_REG_INIT_SETTING;
+
+typedef struct _ATOM_MC_INIT_PARAM_TABLE_V2_1
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ ULONG ulMCUcodeVersion;
+ ULONG ulMCUcodeRomStartAddr;
+ ULONG ulMCUcodeLength;
+ USHORT usMcRegInitTableOffset; // offset of ATOM_REG_INIT_SETTING array for MC core register settings.
+ USHORT usReserved; // offset of ATOM_INIT_REG_BLOCK for MC SEQ/PHY regsiter setting
+}ATOM_MC_INIT_PARAM_TABLE_V2_1;
+
+
+#define _4Mx16 0x2
+#define _4Mx32 0x3
+#define _8Mx16 0x12
+#define _8Mx32 0x13
+#define _8Mx128 0x15
+#define _16Mx16 0x22
+#define _16Mx32 0x23
+#define _16Mx128 0x25
+#define _32Mx16 0x32
+#define _32Mx32 0x33
+#define _32Mx128 0x35
+#define _64Mx32 0x43
+#define _64Mx8 0x41
+#define _64Mx16 0x42
+#define _128Mx8 0x51
+#define _128Mx16 0x52
+#define _128Mx32 0x53
+#define _256Mx8 0x61
+#define _256Mx16 0x62
+#define _512Mx8 0x71
+
+
+#define SAMSUNG 0x1
+#define INFINEON 0x2
+#define ELPIDA 0x3
+#define ETRON 0x4
+#define NANYA 0x5
+#define HYNIX 0x6
+#define MOSEL 0x7
+#define WINBOND 0x8
+#define ESMT 0x9
+#define MICRON 0xF
+
+#define QIMONDA INFINEON
+#define PROMOS MOSEL
+#define KRETON INFINEON
+#define ELIXIR NANYA
+#define MEZZA ELPIDA
+
+
+/////////////Support for GDDR5 MC uCode to reside in upper 64K of ROM/////////////
+
+#define UCODE_ROM_START_ADDRESS 0x1b800
+#define UCODE_SIGNATURE 0x4375434d // 'MCuC' - MC uCode
+
+//uCode block header for reference
+
+typedef struct _MCuCodeHeader
+{
+ ULONG ulSignature;
+ UCHAR ucRevision;
+ UCHAR ucChecksum;
+ UCHAR ucReserved1;
+ UCHAR ucReserved2;
+ USHORT usParametersLength;
+ USHORT usUCodeLength;
+ USHORT usReserved1;
+ USHORT usReserved2;
+} MCuCodeHeader;
+
+//////////////////////////////////////////////////////////////////////////////////
+
+#define ATOM_MAX_NUMBER_OF_VRAM_MODULE 16
+
+#define ATOM_VRAM_MODULE_MEMORY_VENDOR_ID_MASK 0xF
+typedef struct _ATOM_VRAM_MODULE_V1
+{
+ ULONG ulReserved;
+ USHORT usEMRSValue;
+ USHORT usMRSValue;
+ USHORT usReserved;
+ UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module
+ UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] reserved;
+ UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender
+ UCHAR ucMemoryDeviceCfg; // [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32...
+ UCHAR ucRow; // Number of Row,in power of 2;
+ UCHAR ucColumn; // Number of Column,in power of 2;
+ UCHAR ucBank; // Nunber of Bank;
+ UCHAR ucRank; // Number of Rank, in power of 2
+ UCHAR ucChannelNum; // Number of channel;
+ UCHAR ucChannelConfig; // [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2
+ UCHAR ucDefaultMVDDQ_ID; // Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data;
+ UCHAR ucDefaultMVDDC_ID; // Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data;
+ UCHAR ucReserved[2];
+}ATOM_VRAM_MODULE_V1;
+
+
+typedef struct _ATOM_VRAM_MODULE_V2
+{
+ ULONG ulReserved;
+ ULONG ulFlags; // To enable/disable functionalities based on memory type
+ ULONG ulEngineClock; // Override of default engine clock for particular memory type
+ ULONG ulMemoryClock; // Override of default memory clock for particular memory type
+ USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usEMRSValue;
+ USHORT usMRSValue;
+ USHORT usReserved;
+ UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module
+ UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now;
+ UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed
+ UCHAR ucMemoryDeviceCfg; // [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32...
+ UCHAR ucRow; // Number of Row,in power of 2;
+ UCHAR ucColumn; // Number of Column,in power of 2;
+ UCHAR ucBank; // Nunber of Bank;
+ UCHAR ucRank; // Number of Rank, in power of 2
+ UCHAR ucChannelNum; // Number of channel;
+ UCHAR ucChannelConfig; // [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2
+ UCHAR ucDefaultMVDDQ_ID; // Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data;
+ UCHAR ucDefaultMVDDC_ID; // Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data;
+ UCHAR ucRefreshRateFactor;
+ UCHAR ucReserved[3];
+}ATOM_VRAM_MODULE_V2;
+
+
+typedef struct _ATOM_MEMORY_TIMING_FORMAT
+{
+ ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing
+ union{
+ USHORT usMRS; // mode register
+ USHORT usDDR3_MR0;
+ };
+ union{
+ USHORT usEMRS; // extended mode register
+ USHORT usDDR3_MR1;
+ };
+ UCHAR ucCL; // CAS latency
+ UCHAR ucWL; // WRITE Latency
+ UCHAR uctRAS; // tRAS
+ UCHAR uctRC; // tRC
+ UCHAR uctRFC; // tRFC
+ UCHAR uctRCDR; // tRCDR
+ UCHAR uctRCDW; // tRCDW
+ UCHAR uctRP; // tRP
+ UCHAR uctRRD; // tRRD
+ UCHAR uctWR; // tWR
+ UCHAR uctWTR; // tWTR
+ UCHAR uctPDIX; // tPDIX
+ UCHAR uctFAW; // tFAW
+ UCHAR uctAOND; // tAOND
+ union
+ {
+ struct {
+ UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon
+ UCHAR ucReserved;
+ };
+ USHORT usDDR3_MR2;
+ };
+}ATOM_MEMORY_TIMING_FORMAT;
+
+
+typedef struct _ATOM_MEMORY_TIMING_FORMAT_V1
+{
+ ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing
+ USHORT usMRS; // mode register
+ USHORT usEMRS; // extended mode register
+ UCHAR ucCL; // CAS latency
+ UCHAR ucWL; // WRITE Latency
+ UCHAR uctRAS; // tRAS
+ UCHAR uctRC; // tRC
+ UCHAR uctRFC; // tRFC
+ UCHAR uctRCDR; // tRCDR
+ UCHAR uctRCDW; // tRCDW
+ UCHAR uctRP; // tRP
+ UCHAR uctRRD; // tRRD
+ UCHAR uctWR; // tWR
+ UCHAR uctWTR; // tWTR
+ UCHAR uctPDIX; // tPDIX
+ UCHAR uctFAW; // tFAW
+ UCHAR uctAOND; // tAOND
+ UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon
+////////////////////////////////////GDDR parameters///////////////////////////////////
+ UCHAR uctCCDL; //
+ UCHAR uctCRCRL; //
+ UCHAR uctCRCWL; //
+ UCHAR uctCKE; //
+ UCHAR uctCKRSE; //
+ UCHAR uctCKRSX; //
+ UCHAR uctFAW32; //
+ UCHAR ucMR5lo; //
+ UCHAR ucMR5hi; //
+ UCHAR ucTerminator;
+}ATOM_MEMORY_TIMING_FORMAT_V1;
+
+
+
+
+typedef struct _ATOM_MEMORY_TIMING_FORMAT_V2
+{
+ ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing
+ USHORT usMRS; // mode register
+ USHORT usEMRS; // extended mode register
+ UCHAR ucCL; // CAS latency
+ UCHAR ucWL; // WRITE Latency
+ UCHAR uctRAS; // tRAS
+ UCHAR uctRC; // tRC
+ UCHAR uctRFC; // tRFC
+ UCHAR uctRCDR; // tRCDR
+ UCHAR uctRCDW; // tRCDW
+ UCHAR uctRP; // tRP
+ UCHAR uctRRD; // tRRD
+ UCHAR uctWR; // tWR
+ UCHAR uctWTR; // tWTR
+ UCHAR uctPDIX; // tPDIX
+ UCHAR uctFAW; // tFAW
+ UCHAR uctAOND; // tAOND
+ UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon
+////////////////////////////////////GDDR parameters///////////////////////////////////
+ UCHAR uctCCDL; //
+ UCHAR uctCRCRL; //
+ UCHAR uctCRCWL; //
+ UCHAR uctCKE; //
+ UCHAR uctCKRSE; //
+ UCHAR uctCKRSX; //
+ UCHAR uctFAW32; //
+ UCHAR ucMR4lo; //
+ UCHAR ucMR4hi; //
+ UCHAR ucMR5lo; //
+ UCHAR ucMR5hi; //
+ UCHAR ucTerminator;
+ UCHAR ucReserved;
+}ATOM_MEMORY_TIMING_FORMAT_V2;
+
+
+typedef struct _ATOM_MEMORY_FORMAT
+{
+ ULONG ulDllDisClock; // memory DLL will be disable when target memory clock is below this clock
+ union{
+ USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usDDR3_Reserved; // Not used for DDR3 memory
+ };
+ union{
+ USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usDDR3_MR3; // Used for DDR3 memory
+ };
+ UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now;
+ UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed
+ UCHAR ucRow; // Number of Row,in power of 2;
+ UCHAR ucColumn; // Number of Column,in power of 2;
+ UCHAR ucBank; // Nunber of Bank;
+ UCHAR ucRank; // Number of Rank, in power of 2
+ UCHAR ucBurstSize; // burst size, 0= burst size=4 1= burst size=8
+ UCHAR ucDllDisBit; // position of DLL Enable/Disable bit in EMRS ( Extended Mode Register )
+ UCHAR ucRefreshRateFactor; // memory refresh rate in unit of ms
+ UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16
+ UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble
+ UCHAR ucMemAttrib; // Memory Device Addribute, like RDBI/WDBI etc
+ ATOM_MEMORY_TIMING_FORMAT asMemTiming[5]; // Memory Timing block sort from lower clock to higher clock
+}ATOM_MEMORY_FORMAT;
+
+
+typedef struct _ATOM_VRAM_MODULE_V3
+{
+ ULONG ulChannelMapCfg; // board dependent paramenter:Channel combination
+ USHORT usSize; // size of ATOM_VRAM_MODULE_V3
+ USHORT usDefaultMVDDQ; // board dependent parameter:Default Memory Core Voltage
+ USHORT usDefaultMVDDC; // board dependent parameter:Default Memory IO Voltage
+ UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module
+ UCHAR ucChannelNum; // board dependent parameter:Number of channel;
+ UCHAR ucChannelSize; // board dependent parameter:32bit or 64bit
+ UCHAR ucVREFI; // board dependnt parameter: EXT or INT +160mv to -140mv
+ UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters
+ UCHAR ucFlag; // To enable/disable functionalities based on memory type
+ ATOM_MEMORY_FORMAT asMemory; // describ all of video memory parameters from memory spec
+}ATOM_VRAM_MODULE_V3;
+
+
+//ATOM_VRAM_MODULE_V3.ucNPL_RT
+#define NPL_RT_MASK 0x0f
+#define BATTERY_ODT_MASK 0xc0
+
+#define ATOM_VRAM_MODULE ATOM_VRAM_MODULE_V3
+
+typedef struct _ATOM_VRAM_MODULE_V4
+{
+ ULONG ulChannelMapCfg; // board dependent parameter: Channel combination
+ USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE
+ USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!!
+ // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS)
+ USHORT usReserved;
+ UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module
+ UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now;
+ UCHAR ucChannelNum; // Number of channels present in this module config
+ UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits
+ UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16
+ UCHAR ucFlag; // To enable/disable functionalities based on memory type
+ UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8
+ UCHAR ucVREFI; // board dependent parameter
+ UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters
+ UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble
+ UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!!
+ // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros
+ UCHAR ucReserved[3];
+
+//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level
+ union{
+ USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usDDR3_Reserved;
+ };
+ union{
+ USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usDDR3_MR3; // Used for DDR3 memory
+ };
+ UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed
+ UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms)
+ UCHAR ucReserved2[2];
+ ATOM_MEMORY_TIMING_FORMAT asMemTiming[5];//Memory Timing block sort from lower clock to higher clock
+}ATOM_VRAM_MODULE_V4;
+
+#define VRAM_MODULE_V4_MISC_RANK_MASK 0x3
+#define VRAM_MODULE_V4_MISC_DUAL_RANK 0x1
+#define VRAM_MODULE_V4_MISC_BL_MASK 0x4
+#define VRAM_MODULE_V4_MISC_BL8 0x4
+#define VRAM_MODULE_V4_MISC_DUAL_CS 0x10
+
+typedef struct _ATOM_VRAM_MODULE_V5
+{
+ ULONG ulChannelMapCfg; // board dependent parameter: Channel combination
+ USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE
+ USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!!
+ // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS)
+ USHORT usReserved;
+ UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module
+ UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now;
+ UCHAR ucChannelNum; // Number of channels present in this module config
+ UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits
+ UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16
+ UCHAR ucFlag; // To enable/disable functionalities based on memory type
+ UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8
+ UCHAR ucVREFI; // board dependent parameter
+ UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters
+ UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble
+ UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!!
+ // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros
+ UCHAR ucReserved[3];
+
+//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level
+ USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type
+ UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed
+ UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms)
+ UCHAR ucFIFODepth; // FIFO depth supposes to be detected during vendor detection, but if we dont do vendor detection we have to hardcode FIFO Depth
+ UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth
+ ATOM_MEMORY_TIMING_FORMAT_V1 asMemTiming[5];//Memory Timing block sort from lower clock to higher clock
+}ATOM_VRAM_MODULE_V5;
+
+
+typedef struct _ATOM_VRAM_MODULE_V6
+{
+ ULONG ulChannelMapCfg; // board dependent parameter: Channel combination
+ USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE
+ USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!!
+ // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS)
+ USHORT usReserved;
+ UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module
+ UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now;
+ UCHAR ucChannelNum; // Number of channels present in this module config
+ UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits
+ UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16
+ UCHAR ucFlag; // To enable/disable functionalities based on memory type
+ UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8
+ UCHAR ucVREFI; // board dependent parameter
+ UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters
+ UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble
+ UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!!
+ // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros
+ UCHAR ucReserved[3];
+
+//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level
+ USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type
+ USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type
+ UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed
+ UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms)
+ UCHAR ucFIFODepth; // FIFO depth supposes to be detected during vendor detection, but if we dont do vendor detection we have to hardcode FIFO Depth
+ UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth
+ ATOM_MEMORY_TIMING_FORMAT_V2 asMemTiming[5];//Memory Timing block sort from lower clock to higher clock
+}ATOM_VRAM_MODULE_V6;
+
+typedef struct _ATOM_VRAM_MODULE_V7
+{
+// Design Specific Values
+ ULONG ulChannelMapCfg; // mmMC_SHARED_CHREMAP
+ USHORT usModuleSize; // Size of ATOM_VRAM_MODULE_V7
+ USHORT usPrivateReserved; // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS)
+ USHORT usEnableChannels; // bit vector which indicate which channels are enabled
+ UCHAR ucExtMemoryID; // Current memory module ID
+ UCHAR ucMemoryType; // MEM_TYPE_DDR2/DDR3/GDDR3/GDDR5
+ UCHAR ucChannelNum; // Number of mem. channels supported in this module
+ UCHAR ucChannelWidth; // CHANNEL_16BIT/CHANNEL_32BIT/CHANNEL_64BIT
+ UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16
+ UCHAR ucReserve; // In MC7x, the lower 4 bits are used as bit8-11 of memory size. In other MC code, it's not used.
+ UCHAR ucMisc; // RANK_OF_THISMEMORY etc.
+ UCHAR ucVREFI; // Not used.
+ UCHAR ucNPL_RT; // Round trip delay (MC_SEQ_CAS_TIMING [28:24]:TCL=CL+NPL_RT-2). Always 2.
+ UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble
+ UCHAR ucMemorySize; // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros
+ USHORT usSEQSettingOffset;
+ UCHAR ucReserved;
+// Memory Module specific values
+ USHORT usEMRS2Value; // EMRS2/MR2 Value.
+ USHORT usEMRS3Value; // EMRS3/MR3 Value.
+ UCHAR ucMemoryVenderID; // [7:4] Revision, [3:0] Vendor code
+ UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms)
+ UCHAR ucFIFODepth; // FIFO depth can be detected during vendor detection, here is hardcoded per memory
+ UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth
+ char strMemPNString[20]; // part number end with '0'.
+}ATOM_VRAM_MODULE_V7;
+
+
+typedef struct _ATOM_VRAM_MODULE_V8
+{
+// Design Specific Values
+ ULONG ulChannelMapCfg; // mmMC_SHARED_CHREMAP
+ USHORT usModuleSize; // Size of ATOM_VRAM_MODULE_V7
+ USHORT usMcRamCfg; // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS)
+ USHORT usEnableChannels; // bit vector which indicate which channels are enabled
+ UCHAR ucExtMemoryID; // Current memory module ID
+ UCHAR ucMemoryType; // MEM_TYPE_DDR2/DDR3/GDDR3/GDDR5
+ UCHAR ucChannelNum; // Number of mem. channels supported in this module
+ UCHAR ucChannelWidth; // CHANNEL_16BIT/CHANNEL_32BIT/CHANNEL_64BIT
+ UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16
+ UCHAR ucBankCol; // bit[3:2]= BANK ( =2:16bank, =1:8bank, =0:4bank ) bit[1:0]=Col ( =2: 10 bit, =1:9bit, =0:8bit )
+ UCHAR ucMisc; // RANK_OF_THISMEMORY etc.
+ UCHAR ucVREFI; // Not used.
+ USHORT usReserved; // Not used
+ USHORT usMemorySize; // Total memory size in unit of MB for CONFIG_MEMSIZE zeros
+ UCHAR ucMcTunningSetId; // MC phy registers set per.
+ UCHAR ucRowNum;
+// Memory Module specific values
+ USHORT usEMRS2Value; // EMRS2/MR2 Value.
+ USHORT usEMRS3Value; // EMRS3/MR3 Value.
+ UCHAR ucMemoryVenderID; // [7:4] Revision, [3:0] Vendor code
+ UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms)
+ UCHAR ucFIFODepth; // FIFO depth can be detected during vendor detection, here is hardcoded per memory
+ UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth
+
+ ULONG ulChannelMapCfg1; // channel mapping for channel8~15
+ ULONG ulBankMapCfg;
+ ULONG ulReserved;
+ char strMemPNString[20]; // part number end with '0'.
+}ATOM_VRAM_MODULE_V8;
+
+
+typedef struct _ATOM_VRAM_INFO_V2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucNumOfVRAMModule;
+ ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule;
+}ATOM_VRAM_INFO_V2;
+
+typedef struct _ATOM_VRAM_INFO_V3
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting
+ USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting
+ USHORT usRerseved;
+ UCHAR aVID_PinsShift[9]; // 8 bit strap maximum+terminator
+ UCHAR ucNumOfVRAMModule;
+ ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule;
+ ATOM_INIT_REG_BLOCK asMemPatch; // for allocation
+
+}ATOM_VRAM_INFO_V3;
+
+#define ATOM_VRAM_INFO_LAST ATOM_VRAM_INFO_V3
+
+typedef struct _ATOM_VRAM_INFO_V4
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting
+ USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting
+ USHORT usRerseved;
+ UCHAR ucMemDQ7_0ByteRemap; // DQ line byte remap, =0: Memory Data line BYTE0, =1: BYTE1, =2: BYTE2, =3: BYTE3
+ ULONG ulMemDQ7_0BitRemap; // each DQ line ( 7~0) use 3bits, like: DQ0=Bit[2:0], DQ1:[5:3], ... DQ7:[23:21]
+ UCHAR ucReservde[4];
+ UCHAR ucNumOfVRAMModule;
+ ATOM_VRAM_MODULE_V4 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule;
+ ATOM_INIT_REG_BLOCK asMemPatch; // for allocation
+}ATOM_VRAM_INFO_V4;
+
+typedef struct _ATOM_VRAM_INFO_HEADER_V2_1
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting
+ USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting
+ USHORT usPerBytePresetOffset; // offset of ATOM_INIT_REG_BLOCK structure for Per Byte Offset Preset Settings
+ USHORT usReserved[3];
+ UCHAR ucNumOfVRAMModule; // indicate number of VRAM module
+ UCHAR ucMemoryClkPatchTblVer; // version of memory AC timing register list
+ UCHAR ucVramModuleVer; // indicate ATOM_VRAM_MODUE version
+ UCHAR ucReserved;
+ ATOM_VRAM_MODULE_V7 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule;
+}ATOM_VRAM_INFO_HEADER_V2_1;
+
+typedef struct _ATOM_VRAM_INFO_HEADER_V2_2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting
+ USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting
+ USHORT usMcAdjustPerTileTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for Per Byte Offset Preset Settings
+ USHORT usMcPhyInitTableOffset; // offset of ATOM_INIT_REG_BLOCK structure for MC phy init set
+ USHORT usDramDataRemapTblOffset; // offset of ATOM_DRAM_DATA_REMAP array to indicate DRAM data lane to GPU mapping
+ USHORT usReserved1;
+ UCHAR ucNumOfVRAMModule; // indicate number of VRAM module
+ UCHAR ucMemoryClkPatchTblVer; // version of memory AC timing register list
+ UCHAR ucVramModuleVer; // indicate ATOM_VRAM_MODUE version
+ UCHAR ucMcPhyTileNum; // indicate the MCD tile number which use in DramDataRemapTbl and usMcAdjustPerTileTblOffset
+ ATOM_VRAM_MODULE_V8 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule;
+}ATOM_VRAM_INFO_HEADER_V2_2;
+
+
+typedef struct _ATOM_DRAM_DATA_REMAP
+{
+ UCHAR ucByteRemapCh0;
+ UCHAR ucByteRemapCh1;
+ ULONG ulByte0BitRemapCh0;
+ ULONG ulByte1BitRemapCh0;
+ ULONG ulByte2BitRemapCh0;
+ ULONG ulByte3BitRemapCh0;
+ ULONG ulByte0BitRemapCh1;
+ ULONG ulByte1BitRemapCh1;
+ ULONG ulByte2BitRemapCh1;
+ ULONG ulByte3BitRemapCh1;
+}ATOM_DRAM_DATA_REMAP;
+
+typedef struct _ATOM_VRAM_GPIO_DETECTION_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR aVID_PinsShift[9]; // 8 bit strap maximum+terminator
+}ATOM_VRAM_GPIO_DETECTION_INFO;
+
+
+typedef struct _ATOM_MEMORY_TRAINING_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucTrainingLoop;
+ UCHAR ucReserved[3];
+ ATOM_INIT_REG_BLOCK asMemTrainingSetting;
+}ATOM_MEMORY_TRAINING_INFO;
+
+
+typedef struct SW_I2C_CNTL_DATA_PARAMETERS
+{
+ UCHAR ucControl;
+ UCHAR ucData;
+ UCHAR ucSatus;
+ UCHAR ucTemp;
+} SW_I2C_CNTL_DATA_PARAMETERS;
+
+#define SW_I2C_CNTL_DATA_PS_ALLOCATION SW_I2C_CNTL_DATA_PARAMETERS
+
+typedef struct _SW_I2C_IO_DATA_PARAMETERS
+{
+ USHORT GPIO_Info;
+ UCHAR ucAct;
+ UCHAR ucData;
+ } SW_I2C_IO_DATA_PARAMETERS;
+
+#define SW_I2C_IO_DATA_PS_ALLOCATION SW_I2C_IO_DATA_PARAMETERS
+
+/****************************SW I2C CNTL DEFINITIONS**********************/
+#define SW_I2C_IO_RESET 0
+#define SW_I2C_IO_GET 1
+#define SW_I2C_IO_DRIVE 2
+#define SW_I2C_IO_SET 3
+#define SW_I2C_IO_START 4
+
+#define SW_I2C_IO_CLOCK 0
+#define SW_I2C_IO_DATA 0x80
+
+#define SW_I2C_IO_ZERO 0
+#define SW_I2C_IO_ONE 0x100
+
+#define SW_I2C_CNTL_READ 0
+#define SW_I2C_CNTL_WRITE 1
+#define SW_I2C_CNTL_START 2
+#define SW_I2C_CNTL_STOP 3
+#define SW_I2C_CNTL_OPEN 4
+#define SW_I2C_CNTL_CLOSE 5
+#define SW_I2C_CNTL_WRITE1BIT 6
+
+//==============================VESA definition Portion===============================
+#define VESA_OEM_PRODUCT_REV '01.00'
+#define VESA_MODE_ATTRIBUTE_MODE_SUPPORT 0xBB //refer to VBE spec p.32, no TTY support
+#define VESA_MODE_WIN_ATTRIBUTE 7
+#define VESA_WIN_SIZE 64
+
+typedef struct _PTR_32_BIT_STRUCTURE
+{
+ USHORT Offset16;
+ USHORT Segment16;
+} PTR_32_BIT_STRUCTURE;
+
+typedef union _PTR_32_BIT_UNION
+{
+ PTR_32_BIT_STRUCTURE SegmentOffset;
+ ULONG Ptr32_Bit;
+} PTR_32_BIT_UNION;
+
+typedef struct _VBE_1_2_INFO_BLOCK_UPDATABLE
+{
+ UCHAR VbeSignature[4];
+ USHORT VbeVersion;
+ PTR_32_BIT_UNION OemStringPtr;
+ UCHAR Capabilities[4];
+ PTR_32_BIT_UNION VideoModePtr;
+ USHORT TotalMemory;
+} VBE_1_2_INFO_BLOCK_UPDATABLE;
+
+
+typedef struct _VBE_2_0_INFO_BLOCK_UPDATABLE
+{
+ VBE_1_2_INFO_BLOCK_UPDATABLE CommonBlock;
+ USHORT OemSoftRev;
+ PTR_32_BIT_UNION OemVendorNamePtr;
+ PTR_32_BIT_UNION OemProductNamePtr;
+ PTR_32_BIT_UNION OemProductRevPtr;
+} VBE_2_0_INFO_BLOCK_UPDATABLE;
+
+typedef union _VBE_VERSION_UNION
+{
+ VBE_2_0_INFO_BLOCK_UPDATABLE VBE_2_0_InfoBlock;
+ VBE_1_2_INFO_BLOCK_UPDATABLE VBE_1_2_InfoBlock;
+} VBE_VERSION_UNION;
+
+typedef struct _VBE_INFO_BLOCK
+{
+ VBE_VERSION_UNION UpdatableVBE_Info;
+ UCHAR Reserved[222];
+ UCHAR OemData[256];
+} VBE_INFO_BLOCK;
+
+typedef struct _VBE_FP_INFO
+{
+ USHORT HSize;
+ USHORT VSize;
+ USHORT FPType;
+ UCHAR RedBPP;
+ UCHAR GreenBPP;
+ UCHAR BlueBPP;
+ UCHAR ReservedBPP;
+ ULONG RsvdOffScrnMemSize;
+ ULONG RsvdOffScrnMEmPtr;
+ UCHAR Reserved[14];
+} VBE_FP_INFO;
+
+typedef struct _VESA_MODE_INFO_BLOCK
+{
+// Mandatory information for all VBE revisions
+ USHORT ModeAttributes; // dw ? ; mode attributes
+ UCHAR WinAAttributes; // db ? ; window A attributes
+ UCHAR WinBAttributes; // db ? ; window B attributes
+ USHORT WinGranularity; // dw ? ; window granularity
+ USHORT WinSize; // dw ? ; window size
+ USHORT WinASegment; // dw ? ; window A start segment
+ USHORT WinBSegment; // dw ? ; window B start segment
+ ULONG WinFuncPtr; // dd ? ; real mode pointer to window function
+ USHORT BytesPerScanLine;// dw ? ; bytes per scan line
+
+//; Mandatory information for VBE 1.2 and above
+ USHORT XResolution; // dw ? ; horizontal resolution in pixels or characters
+ USHORT YResolution; // dw ? ; vertical resolution in pixels or characters
+ UCHAR XCharSize; // db ? ; character cell width in pixels
+ UCHAR YCharSize; // db ? ; character cell height in pixels
+ UCHAR NumberOfPlanes; // db ? ; number of memory planes
+ UCHAR BitsPerPixel; // db ? ; bits per pixel
+ UCHAR NumberOfBanks; // db ? ; number of banks
+ UCHAR MemoryModel; // db ? ; memory model type
+ UCHAR BankSize; // db ? ; bank size in KB
+ UCHAR NumberOfImagePages;// db ? ; number of images
+ UCHAR ReservedForPageFunction;//db 1 ; reserved for page function
+
+//; Direct Color fields(required for direct/6 and YUV/7 memory models)
+ UCHAR RedMaskSize; // db ? ; size of direct color red mask in bits
+ UCHAR RedFieldPosition; // db ? ; bit position of lsb of red mask
+ UCHAR GreenMaskSize; // db ? ; size of direct color green mask in bits
+ UCHAR GreenFieldPosition; // db ? ; bit position of lsb of green mask
+ UCHAR BlueMaskSize; // db ? ; size of direct color blue mask in bits
+ UCHAR BlueFieldPosition; // db ? ; bit position of lsb of blue mask
+ UCHAR RsvdMaskSize; // db ? ; size of direct color reserved mask in bits
+ UCHAR RsvdFieldPosition; // db ? ; bit position of lsb of reserved mask
+ UCHAR DirectColorModeInfo;// db ? ; direct color mode attributes
+
+//; Mandatory information for VBE 2.0 and above
+ ULONG PhysBasePtr; // dd ? ; physical address for flat memory frame buffer
+ ULONG Reserved_1; // dd 0 ; reserved - always set to 0
+ USHORT Reserved_2; // dw 0 ; reserved - always set to 0
+
+//; Mandatory information for VBE 3.0 and above
+ USHORT LinBytesPerScanLine; // dw ? ; bytes per scan line for linear modes
+ UCHAR BnkNumberOfImagePages;// db ? ; number of images for banked modes
+ UCHAR LinNumberOfImagPages; // db ? ; number of images for linear modes
+ UCHAR LinRedMaskSize; // db ? ; size of direct color red mask(linear modes)
+ UCHAR LinRedFieldPosition; // db ? ; bit position of lsb of red mask(linear modes)
+ UCHAR LinGreenMaskSize; // db ? ; size of direct color green mask(linear modes)
+ UCHAR LinGreenFieldPosition;// db ? ; bit position of lsb of green mask(linear modes)
+ UCHAR LinBlueMaskSize; // db ? ; size of direct color blue mask(linear modes)
+ UCHAR LinBlueFieldPosition; // db ? ; bit position of lsb of blue mask(linear modes)
+ UCHAR LinRsvdMaskSize; // db ? ; size of direct color reserved mask(linear modes)
+ UCHAR LinRsvdFieldPosition; // db ? ; bit position of lsb of reserved mask(linear modes)
+ ULONG MaxPixelClock; // dd ? ; maximum pixel clock(in Hz) for graphics mode
+ UCHAR Reserved; // db 190 dup (0)
+} VESA_MODE_INFO_BLOCK;
+
+// BIOS function CALLS
+#define ATOM_BIOS_EXTENDED_FUNCTION_CODE 0xA0 // ATI Extended Function code
+#define ATOM_BIOS_FUNCTION_COP_MODE 0x00
+#define ATOM_BIOS_FUNCTION_SHORT_QUERY1 0x04
+#define ATOM_BIOS_FUNCTION_SHORT_QUERY2 0x05
+#define ATOM_BIOS_FUNCTION_SHORT_QUERY3 0x06
+#define ATOM_BIOS_FUNCTION_GET_DDC 0x0B
+#define ATOM_BIOS_FUNCTION_ASIC_DSTATE 0x0E
+#define ATOM_BIOS_FUNCTION_DEBUG_PLAY 0x0F
+#define ATOM_BIOS_FUNCTION_STV_STD 0x16
+#define ATOM_BIOS_FUNCTION_DEVICE_DET 0x17
+#define ATOM_BIOS_FUNCTION_DEVICE_SWITCH 0x18
+
+#define ATOM_BIOS_FUNCTION_PANEL_CONTROL 0x82
+#define ATOM_BIOS_FUNCTION_OLD_DEVICE_DET 0x83
+#define ATOM_BIOS_FUNCTION_OLD_DEVICE_SWITCH 0x84
+#define ATOM_BIOS_FUNCTION_HW_ICON 0x8A
+#define ATOM_BIOS_FUNCTION_SET_CMOS 0x8B
+#define SUB_FUNCTION_UPDATE_DISPLAY_INFO 0x8000 // Sub function 80
+#define SUB_FUNCTION_UPDATE_EXPANSION_INFO 0x8100 // Sub function 80
+
+#define ATOM_BIOS_FUNCTION_DISPLAY_INFO 0x8D
+#define ATOM_BIOS_FUNCTION_DEVICE_ON_OFF 0x8E
+#define ATOM_BIOS_FUNCTION_VIDEO_STATE 0x8F
+#define ATOM_SUB_FUNCTION_GET_CRITICAL_STATE 0x0300 // Sub function 03
+#define ATOM_SUB_FUNCTION_GET_LIDSTATE 0x0700 // Sub function 7
+#define ATOM_SUB_FUNCTION_THERMAL_STATE_NOTICE 0x1400 // Notify caller the current thermal state
+#define ATOM_SUB_FUNCTION_CRITICAL_STATE_NOTICE 0x8300 // Notify caller the current critical state
+#define ATOM_SUB_FUNCTION_SET_LIDSTATE 0x8500 // Sub function 85
+#define ATOM_SUB_FUNCTION_GET_REQ_DISPLAY_FROM_SBIOS_MODE 0x8900// Sub function 89
+#define ATOM_SUB_FUNCTION_INFORM_ADC_SUPPORT 0x9400 // Notify caller that ADC is supported
+
+
+#define ATOM_BIOS_FUNCTION_VESA_DPMS 0x4F10 // Set DPMS
+#define ATOM_SUB_FUNCTION_SET_DPMS 0x0001 // BL: Sub function 01
+#define ATOM_SUB_FUNCTION_GET_DPMS 0x0002 // BL: Sub function 02
+#define ATOM_PARAMETER_VESA_DPMS_ON 0x0000 // BH Parameter for DPMS ON.
+#define ATOM_PARAMETER_VESA_DPMS_STANDBY 0x0100 // BH Parameter for DPMS STANDBY
+#define ATOM_PARAMETER_VESA_DPMS_SUSPEND 0x0200 // BH Parameter for DPMS SUSPEND
+#define ATOM_PARAMETER_VESA_DPMS_OFF 0x0400 // BH Parameter for DPMS OFF
+#define ATOM_PARAMETER_VESA_DPMS_REDUCE_ON 0x0800 // BH Parameter for DPMS REDUCE ON (NOT SUPPORTED)
+
+#define ATOM_BIOS_RETURN_CODE_MASK 0x0000FF00L
+#define ATOM_BIOS_REG_HIGH_MASK 0x0000FF00L
+#define ATOM_BIOS_REG_LOW_MASK 0x000000FFL
+
+// structure used for VBIOS only
+
+//DispOutInfoTable
+typedef struct _ASIC_TRANSMITTER_INFO
+{
+ USHORT usTransmitterObjId;
+ USHORT usSupportDevice;
+ UCHAR ucTransmitterCmdTblId;
+ UCHAR ucConfig;
+ UCHAR ucEncoderID; //available 1st encoder ( default )
+ UCHAR ucOptionEncoderID; //available 2nd encoder ( optional )
+ UCHAR uc2ndEncoderID;
+ UCHAR ucReserved;
+}ASIC_TRANSMITTER_INFO;
+
+#define ASIC_TRANSMITTER_INFO_CONFIG__DVO_SDR_MODE 0x01
+#define ASIC_TRANSMITTER_INFO_CONFIG__COHERENT_MODE 0x02
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODEROBJ_ID_MASK 0xc4
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_A 0x00
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_B 0x04
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_C 0x40
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_D 0x44
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_E 0x80
+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_F 0x84
+
+typedef struct _ASIC_ENCODER_INFO
+{
+ UCHAR ucEncoderID;
+ UCHAR ucEncoderConfig;
+ USHORT usEncoderCmdTblId;
+}ASIC_ENCODER_INFO;
+
+typedef struct _ATOM_DISP_OUT_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT ptrTransmitterInfo;
+ USHORT ptrEncoderInfo;
+ ASIC_TRANSMITTER_INFO asTransmitterInfo[1];
+ ASIC_ENCODER_INFO asEncoderInfo[1];
+}ATOM_DISP_OUT_INFO;
+
+
+typedef struct _ATOM_DISP_OUT_INFO_V2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT ptrTransmitterInfo;
+ USHORT ptrEncoderInfo;
+ USHORT ptrMainCallParserFar; // direct address of main parser call in VBIOS binary.
+ ASIC_TRANSMITTER_INFO asTransmitterInfo[1];
+ ASIC_ENCODER_INFO asEncoderInfo[1];
+}ATOM_DISP_OUT_INFO_V2;
+
+
+typedef struct _ATOM_DISP_CLOCK_ID {
+ UCHAR ucPpllId;
+ UCHAR ucPpllAttribute;
+}ATOM_DISP_CLOCK_ID;
+
+// ucPpllAttribute
+#define CLOCK_SOURCE_SHAREABLE 0x01
+#define CLOCK_SOURCE_DP_MODE 0x02
+#define CLOCK_SOURCE_NONE_DP_MODE 0x04
+
+//DispOutInfoTable
+typedef struct _ASIC_TRANSMITTER_INFO_V2
+{
+ USHORT usTransmitterObjId;
+ USHORT usDispClkIdOffset; // point to clock source id list supported by Encoder Object
+ UCHAR ucTransmitterCmdTblId;
+ UCHAR ucConfig;
+ UCHAR ucEncoderID; // available 1st encoder ( default )
+ UCHAR ucOptionEncoderID; // available 2nd encoder ( optional )
+ UCHAR uc2ndEncoderID;
+ UCHAR ucReserved;
+}ASIC_TRANSMITTER_INFO_V2;
+
+typedef struct _ATOM_DISP_OUT_INFO_V3
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT ptrTransmitterInfo;
+ USHORT ptrEncoderInfo;
+ USHORT ptrMainCallParserFar; // direct address of main parser call in VBIOS binary.
+ USHORT usReserved;
+ UCHAR ucDCERevision;
+ UCHAR ucMaxDispEngineNum;
+ UCHAR ucMaxActiveDispEngineNum;
+ UCHAR ucMaxPPLLNum;
+ UCHAR ucCoreRefClkSource; // value of CORE_REF_CLK_SOURCE
+ UCHAR ucDispCaps;
+ UCHAR ucReserved[2];
+ ASIC_TRANSMITTER_INFO_V2 asTransmitterInfo[1]; // for alligment only
+}ATOM_DISP_OUT_INFO_V3;
+
+//ucDispCaps
+#define DISPLAY_CAPS__DP_PCLK_FROM_PPLL 0x01
+#define DISPLAY_CAPS__FORCE_DISPDEV_CONNECTED 0x02
+
+typedef enum CORE_REF_CLK_SOURCE{
+ CLOCK_SRC_XTALIN=0,
+ CLOCK_SRC_XO_IN=1,
+ CLOCK_SRC_XO_IN2=2,
+}CORE_REF_CLK_SOURCE;
+
+// DispDevicePriorityInfo
+typedef struct _ATOM_DISPLAY_DEVICE_PRIORITY_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT asDevicePriority[16];
+}ATOM_DISPLAY_DEVICE_PRIORITY_INFO;
+
+//ProcessAuxChannelTransactionTable
+typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS
+{
+ USHORT lpAuxRequest;
+ USHORT lpDataOut;
+ UCHAR ucChannelID;
+ union
+ {
+ UCHAR ucReplyStatus;
+ UCHAR ucDelay;
+ };
+ UCHAR ucDataOutLen;
+ UCHAR ucReserved;
+}PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS;
+
+//ProcessAuxChannelTransactionTable
+typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2
+{
+ USHORT lpAuxRequest;
+ USHORT lpDataOut;
+ UCHAR ucChannelID;
+ union
+ {
+ UCHAR ucReplyStatus;
+ UCHAR ucDelay;
+ };
+ UCHAR ucDataOutLen;
+ UCHAR ucHPD_ID; //=0: HPD1, =1: HPD2, =2: HPD3, =3: HPD4, =4: HPD5, =5: HPD6
+}PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2;
+
+#define PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS
+
+//GetSinkType
+
+typedef struct _DP_ENCODER_SERVICE_PARAMETERS
+{
+ USHORT ucLinkClock;
+ union
+ {
+ UCHAR ucConfig; // for DP training command
+ UCHAR ucI2cId; // use for GET_SINK_TYPE command
+ };
+ UCHAR ucAction;
+ UCHAR ucStatus;
+ UCHAR ucLaneNum;
+ UCHAR ucReserved[2];
+}DP_ENCODER_SERVICE_PARAMETERS;
+
+// ucAction
+#define ATOM_DP_ACTION_GET_SINK_TYPE 0x01
+
+#define DP_ENCODER_SERVICE_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
+
+
+typedef struct _DP_ENCODER_SERVICE_PARAMETERS_V2
+{
+ USHORT usExtEncoderObjId; // External Encoder Object Id, output parameter only, use when ucAction = DP_SERVICE_V2_ACTION_DET_EXT_CONNECTION
+ UCHAR ucAuxId;
+ UCHAR ucAction;
+ UCHAR ucSinkType; // Iput and Output parameters.
+ UCHAR ucHPDId; // Input parameter, used when ucAction = DP_SERVICE_V2_ACTION_DET_EXT_CONNECTION
+ UCHAR ucReserved[2];
+}DP_ENCODER_SERVICE_PARAMETERS_V2;
+
+typedef struct _DP_ENCODER_SERVICE_PS_ALLOCATION_V2
+{
+ DP_ENCODER_SERVICE_PARAMETERS_V2 asDPServiceParam;
+ PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 asAuxParam;
+}DP_ENCODER_SERVICE_PS_ALLOCATION_V2;
+
+// ucAction
+#define DP_SERVICE_V2_ACTION_GET_SINK_TYPE 0x01
+#define DP_SERVICE_V2_ACTION_DET_LCD_CONNECTION 0x02
+
+
+// DP_TRAINING_TABLE
+#define DPCD_SET_LINKRATE_LANENUM_PATTERN1_TBL_ADDR ATOM_DP_TRAINING_TBL_ADDR
+#define DPCD_SET_SS_CNTL_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 8 )
+#define DPCD_SET_LANE_VSWING_PREEMP_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 16 )
+#define DPCD_SET_TRAINING_PATTERN0_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 24 )
+#define DPCD_SET_TRAINING_PATTERN2_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 32)
+#define DPCD_GET_LINKRATE_LANENUM_SS_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 40)
+#define DPCD_GET_LANE_STATUS_ADJUST_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 48)
+#define DP_I2C_AUX_DDC_WRITE_START_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 60)
+#define DP_I2C_AUX_DDC_WRITE_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 64)
+#define DP_I2C_AUX_DDC_READ_START_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 72)
+#define DP_I2C_AUX_DDC_READ_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 76)
+#define DP_I2C_AUX_DDC_WRITE_END_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 80)
+#define DP_I2C_AUX_DDC_READ_END_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 84)
+
+
+typedef struct _PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS
+{
+ UCHAR ucI2CSpeed;
+ union
+ {
+ UCHAR ucRegIndex;
+ UCHAR ucStatus;
+ };
+ USHORT lpI2CDataOut;
+ UCHAR ucFlag;
+ UCHAR ucTransBytes;
+ UCHAR ucSlaveAddr;
+ UCHAR ucLineNumber;
+}PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS;
+
+#define PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS
+
+//ucFlag
+#define HW_I2C_WRITE 1
+#define HW_I2C_READ 0
+#define I2C_2BYTE_ADDR 0x02
+
+/****************************************************************************/
+// Structures used by HW_Misc_OperationTable
+/****************************************************************************/
+typedef struct _ATOM_HW_MISC_OPERATION_INPUT_PARAMETER_V1_1
+{
+ UCHAR ucCmd; // Input: To tell which action to take
+ UCHAR ucReserved[3];
+ ULONG ulReserved;
+}ATOM_HW_MISC_OPERATION_INPUT_PARAMETER_V1_1;
+
+typedef struct _ATOM_HW_MISC_OPERATION_OUTPUT_PARAMETER_V1_1
+{
+ UCHAR ucReturnCode; // Output: Return value base on action was taken
+ UCHAR ucReserved[3];
+ ULONG ulReserved;
+}ATOM_HW_MISC_OPERATION_OUTPUT_PARAMETER_V1_1;
+
+// Actions code
+#define ATOM_GET_SDI_SUPPORT 0xF0
+
+// Return code
+#define ATOM_UNKNOWN_CMD 0
+#define ATOM_FEATURE_NOT_SUPPORTED 1
+#define ATOM_FEATURE_SUPPORTED 2
+
+typedef struct _ATOM_HW_MISC_OPERATION_PS_ALLOCATION
+{
+ ATOM_HW_MISC_OPERATION_INPUT_PARAMETER_V1_1 sInput_Output;
+ PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS sReserved;
+}ATOM_HW_MISC_OPERATION_PS_ALLOCATION;
+
+/****************************************************************************/
+
+typedef struct _SET_HWBLOCK_INSTANCE_PARAMETER_V2
+{
+ UCHAR ucHWBlkInst; // HW block instance, 0, 1, 2, ...
+ UCHAR ucReserved[3];
+}SET_HWBLOCK_INSTANCE_PARAMETER_V2;
+
+#define HWBLKINST_INSTANCE_MASK 0x07
+#define HWBLKINST_HWBLK_MASK 0xF0
+#define HWBLKINST_HWBLK_SHIFT 0x04
+
+//ucHWBlock
+#define SELECT_DISP_ENGINE 0
+#define SELECT_DISP_PLL 1
+#define SELECT_DCIO_UNIPHY_LINK0 2
+#define SELECT_DCIO_UNIPHY_LINK1 3
+#define SELECT_DCIO_IMPCAL 4
+#define SELECT_DCIO_DIG 6
+#define SELECT_CRTC_PIXEL_RATE 7
+#define SELECT_VGA_BLK 8
+
+// DIGTransmitterInfoTable structure used to program UNIPHY settings
+typedef struct _DIG_TRANSMITTER_INFO_HEADER_V3_1{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDPVsPreEmphSettingOffset; // offset of PHY_ANALOG_SETTING_INFO * with DP Voltage Swing and Pre-Emphasis for each Link clock
+ USHORT usPhyAnalogRegListOffset; // offset of CLOCK_CONDITION_REGESTER_INFO* with None-DP mode Analog Setting's register Info
+ USHORT usPhyAnalogSettingOffset; // offset of CLOCK_CONDITION_SETTING_ENTRY* with None-DP mode Analog Setting for each link clock range
+ USHORT usPhyPllRegListOffset; // offset of CLOCK_CONDITION_REGESTER_INFO* with Phy Pll register Info
+ USHORT usPhyPllSettingOffset; // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy Pll Settings
+}DIG_TRANSMITTER_INFO_HEADER_V3_1;
+
+typedef struct _DIG_TRANSMITTER_INFO_HEADER_V3_2{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDPVsPreEmphSettingOffset; // offset of PHY_ANALOG_SETTING_INFO * with DP Voltage Swing and Pre-Emphasis for each Link clock
+ USHORT usPhyAnalogRegListOffset; // offset of CLOCK_CONDITION_REGESTER_INFO* with None-DP mode Analog Setting's register Info
+ USHORT usPhyAnalogSettingOffset; // offset of CLOCK_CONDITION_SETTING_ENTRY* with None-DP mode Analog Setting for each link clock range
+ USHORT usPhyPllRegListOffset; // offset of CLOCK_CONDITION_REGESTER_INFO* with Phy Pll register Info
+ USHORT usPhyPllSettingOffset; // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy Pll Settings
+ USHORT usDPSSRegListOffset; // offset of CLOCK_CONDITION_REGESTER_INFO* with Phy SS Pll register Info
+ USHORT usDPSSSettingOffset; // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy SS Pll Settings
+}DIG_TRANSMITTER_INFO_HEADER_V3_2;
+
+
+typedef struct _DIG_TRANSMITTER_INFO_HEADER_V3_3{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDPVsPreEmphSettingOffset; // offset of PHY_ANALOG_SETTING_INFO * with DP Voltage Swing and Pre-Emphasis for each Link clock
+ USHORT usPhyAnalogRegListOffset; // offset of CLOCK_CONDITION_REGESTER_INFO* with None-DP mode Analog Setting's register Info
+ USHORT usPhyAnalogSettingOffset; // offset of CLOCK_CONDITION_SETTING_ENTRY* with None-DP mode Analog Setting for each link clock range
+ USHORT usPhyPllRegListOffset; // offset of CLOCK_CONDITION_REGESTER_INFO* with Phy Pll register Info
+ USHORT usPhyPllSettingOffset; // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy Pll Settings
+ USHORT usDPSSRegListOffset; // offset of CLOCK_CONDITION_REGESTER_INFO* with Phy SS Pll register Info
+ USHORT usDPSSSettingOffset; // offset of CLOCK_CONDITION_SETTING_ENTRY* with Phy SS Pll Settings
+ USHORT usEDPVsLegacyModeOffset; // offset of PHY_ANALOG_SETTING_INFO * with eDP Legacy Mode Voltage Swing and Pre-Emphasis for each Link clock
+ USHORT useDPVsLowVdiffModeOffset; // offset of PHY_ANALOG_SETTING_INFO * with eDP Low VDiff Mode Voltage Swing and Pre-Emphasis for each Link clock
+ USHORT useDPVsHighVdiffModeOffset; // offset of PHY_ANALOG_SETTING_INFO * with eDP High VDiff Mode Voltage Swing and Pre-Emphasis for each Link clock
+ USHORT useDPVsStretchModeOffset; // offset of PHY_ANALOG_SETTING_INFO * with eDP Stretch Mode Voltage Swing and Pre-Emphasis for each Link clock
+ USHORT useDPVsSingleVdiffModeOffset; // offset of PHY_ANALOG_SETTING_INFO * with eDP Single Vdiff Mode Voltage Swing and Pre-Emphasis for each Link clock
+ USHORT useDPVsVariablePremModeOffset; // offset of PHY_ANALOG_SETTING_INFO * with eDP Single Vidff+Variable PreEmphasis Voltage Swing and Pre-Emphasis for each Link clock
+}DIG_TRANSMITTER_INFO_HEADER_V3_3;
+
+
+typedef struct _CLOCK_CONDITION_REGESTER_INFO{
+ USHORT usRegisterIndex;
+ UCHAR ucStartBit;
+ UCHAR ucEndBit;
+}CLOCK_CONDITION_REGESTER_INFO;
+
+typedef struct _CLOCK_CONDITION_SETTING_ENTRY{
+ USHORT usMaxClockFreq;
+ UCHAR ucEncodeMode;
+ UCHAR ucPhySel;
+ ULONG ulAnalogSetting[1];
+}CLOCK_CONDITION_SETTING_ENTRY;
+
+typedef struct _CLOCK_CONDITION_SETTING_INFO{
+ USHORT usEntrySize;
+ CLOCK_CONDITION_SETTING_ENTRY asClkCondSettingEntry[1];
+}CLOCK_CONDITION_SETTING_INFO;
+
+typedef struct _PHY_CONDITION_REG_VAL{
+ ULONG ulCondition;
+ ULONG ulRegVal;
+}PHY_CONDITION_REG_VAL;
+
+typedef struct _PHY_CONDITION_REG_VAL_V2{
+ ULONG ulCondition;
+ UCHAR ucCondition2;
+ ULONG ulRegVal;
+}PHY_CONDITION_REG_VAL_V2;
+
+typedef struct _PHY_CONDITION_REG_INFO{
+ USHORT usRegIndex;
+ USHORT usSize;
+ PHY_CONDITION_REG_VAL asRegVal[1];
+}PHY_CONDITION_REG_INFO;
+
+typedef struct _PHY_CONDITION_REG_INFO_V2{
+ USHORT usRegIndex;
+ USHORT usSize;
+ PHY_CONDITION_REG_VAL_V2 asRegVal[1];
+}PHY_CONDITION_REG_INFO_V2;
+
+typedef struct _PHY_ANALOG_SETTING_INFO{
+ UCHAR ucEncodeMode;
+ UCHAR ucPhySel;
+ USHORT usSize;
+ PHY_CONDITION_REG_INFO asAnalogSetting[1];
+}PHY_ANALOG_SETTING_INFO;
+
+typedef struct _PHY_ANALOG_SETTING_INFO_V2{
+ UCHAR ucEncodeMode;
+ UCHAR ucPhySel;
+ USHORT usSize;
+ PHY_CONDITION_REG_INFO_V2 asAnalogSetting[1];
+}PHY_ANALOG_SETTING_INFO_V2;
+
+
+typedef struct _GFX_HAVESTING_PARAMETERS {
+ UCHAR ucGfxBlkId; //GFX blk id to be harvested, like CU, RB or PRIM
+ UCHAR ucReserved; //reserved
+ UCHAR ucActiveUnitNumPerSH; //requested active CU/RB/PRIM number per shader array
+ UCHAR ucMaxUnitNumPerSH; //max CU/RB/PRIM number per shader array
+} GFX_HAVESTING_PARAMETERS;
+
+//ucGfxBlkId
+#define GFX_HARVESTING_CU_ID 0
+#define GFX_HARVESTING_RB_ID 1
+#define GFX_HARVESTING_PRIM_ID 2
+
+
+typedef struct _VBIOS_ROM_HEADER{
+ UCHAR PciRomSignature[2];
+ UCHAR ucPciRomSizeIn512bytes;
+ UCHAR ucJumpCoreMainInitBIOS;
+ USHORT usLabelCoreMainInitBIOS;
+ UCHAR PciReservedSpace[18];
+ USHORT usPciDataStructureOffset;
+ UCHAR Rsvd1d_1a[4];
+ char strIbm[3];
+ UCHAR CheckSum[14];
+ UCHAR ucBiosMsgNumber;
+ char str761295520[16];
+ USHORT usLabelCoreVPOSTNoMode;
+ USHORT usSpecialPostOffset;
+ UCHAR ucSpeicalPostImageSizeIn512Bytes;
+ UCHAR Rsved47_45[3];
+ USHORT usROM_HeaderInformationTableOffset;
+ UCHAR Rsved4f_4a[6];
+ char strBuildTimeStamp[20];
+ UCHAR ucJumpCoreXFuncFarHandler;
+ USHORT usCoreXFuncFarHandlerOffset;
+ UCHAR ucRsved67;
+ UCHAR ucJumpCoreVFuncFarHandler;
+ USHORT usCoreVFuncFarHandlerOffset;
+ UCHAR Rsved6d_6b[3];
+ USHORT usATOM_BIOS_MESSAGE_Offset;
+}VBIOS_ROM_HEADER;
+
+/****************************************************************************/
+//Portion VI: Definitinos for vbios MC scratch registers that driver used
+/****************************************************************************/
+
+#define MC_MISC0__MEMORY_TYPE_MASK 0xF0000000
+#define MC_MISC0__MEMORY_TYPE__GDDR1 0x10000000
+#define MC_MISC0__MEMORY_TYPE__DDR2 0x20000000
+#define MC_MISC0__MEMORY_TYPE__GDDR3 0x30000000
+#define MC_MISC0__MEMORY_TYPE__GDDR4 0x40000000
+#define MC_MISC0__MEMORY_TYPE__GDDR5 0x50000000
+#define MC_MISC0__MEMORY_TYPE__HBM 0x60000000
+#define MC_MISC0__MEMORY_TYPE__DDR3 0xB0000000
+
+#define ATOM_MEM_TYPE_DDR_STRING "DDR"
+#define ATOM_MEM_TYPE_DDR2_STRING "DDR2"
+#define ATOM_MEM_TYPE_GDDR3_STRING "GDDR3"
+#define ATOM_MEM_TYPE_GDDR4_STRING "GDDR4"
+#define ATOM_MEM_TYPE_GDDR5_STRING "GDDR5"
+#define ATOM_MEM_TYPE_HBM_STRING "HBM"
+#define ATOM_MEM_TYPE_DDR3_STRING "DDR3"
+
+/****************************************************************************/
+//Portion VII: Definitinos being oboselete
+/****************************************************************************/
+
+//==========================================================================================
+//Remove the definitions below when driver is ready!
+typedef struct _ATOM_DAC_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMaxFrequency; // in 10kHz unit
+ USHORT usReserved;
+}ATOM_DAC_INFO;
+
+
+typedef struct _COMPASSIONATE_DATA
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+
+ //============================== DAC1 portion
+ UCHAR ucDAC1_BG_Adjustment;
+ UCHAR ucDAC1_DAC_Adjustment;
+ USHORT usDAC1_FORCE_Data;
+ //============================== DAC2 portion
+ UCHAR ucDAC2_CRT2_BG_Adjustment;
+ UCHAR ucDAC2_CRT2_DAC_Adjustment;
+ USHORT usDAC2_CRT2_FORCE_Data;
+ USHORT usDAC2_CRT2_MUX_RegisterIndex;
+ UCHAR ucDAC2_CRT2_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low
+ UCHAR ucDAC2_NTSC_BG_Adjustment;
+ UCHAR ucDAC2_NTSC_DAC_Adjustment;
+ USHORT usDAC2_TV1_FORCE_Data;
+ USHORT usDAC2_TV1_MUX_RegisterIndex;
+ UCHAR ucDAC2_TV1_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low
+ UCHAR ucDAC2_CV_BG_Adjustment;
+ UCHAR ucDAC2_CV_DAC_Adjustment;
+ USHORT usDAC2_CV_FORCE_Data;
+ USHORT usDAC2_CV_MUX_RegisterIndex;
+ UCHAR ucDAC2_CV_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low
+ UCHAR ucDAC2_PAL_BG_Adjustment;
+ UCHAR ucDAC2_PAL_DAC_Adjustment;
+ USHORT usDAC2_TV2_FORCE_Data;
+}COMPASSIONATE_DATA;
+
+/****************************Supported Device Info Table Definitions**********************/
+// ucConnectInfo:
+// [7:4] - connector type
+// = 1 - VGA connector
+// = 2 - DVI-I
+// = 3 - DVI-D
+// = 4 - DVI-A
+// = 5 - SVIDEO
+// = 6 - COMPOSITE
+// = 7 - LVDS
+// = 8 - DIGITAL LINK
+// = 9 - SCART
+// = 0xA - HDMI_type A
+// = 0xB - HDMI_type B
+// = 0xE - Special case1 (DVI+DIN)
+// Others=TBD
+// [3:0] - DAC Associated
+// = 0 - no DAC
+// = 1 - DACA
+// = 2 - DACB
+// = 3 - External DAC
+// Others=TBD
+//
+
+typedef struct _ATOM_CONNECTOR_INFO
+{
+#if ATOM_BIG_ENDIAN
+ UCHAR bfConnectorType:4;
+ UCHAR bfAssociatedDAC:4;
+#else
+ UCHAR bfAssociatedDAC:4;
+ UCHAR bfConnectorType:4;
+#endif
+}ATOM_CONNECTOR_INFO;
+
+typedef union _ATOM_CONNECTOR_INFO_ACCESS
+{
+ ATOM_CONNECTOR_INFO sbfAccess;
+ UCHAR ucAccess;
+}ATOM_CONNECTOR_INFO_ACCESS;
+
+typedef struct _ATOM_CONNECTOR_INFO_I2C
+{
+ ATOM_CONNECTOR_INFO_ACCESS sucConnectorInfo;
+ ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;
+}ATOM_CONNECTOR_INFO_I2C;
+
+
+typedef struct _ATOM_SUPPORTED_DEVICES_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDeviceSupport;
+ ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO];
+}ATOM_SUPPORTED_DEVICES_INFO;
+
+#define NO_INT_SRC_MAPPED 0xFF
+
+typedef struct _ATOM_CONNECTOR_INC_SRC_BITMAP
+{
+ UCHAR ucIntSrcBitmap;
+}ATOM_CONNECTOR_INC_SRC_BITMAP;
+
+typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDeviceSupport;
+ ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2];
+ ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2];
+}ATOM_SUPPORTED_DEVICES_INFO_2;
+
+typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2d1
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usDeviceSupport;
+ ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE];
+ ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE];
+}ATOM_SUPPORTED_DEVICES_INFO_2d1;
+
+#define ATOM_SUPPORTED_DEVICES_INFO_LAST ATOM_SUPPORTED_DEVICES_INFO_2d1
+
+
+
+typedef struct _ATOM_MISC_CONTROL_INFO
+{
+ USHORT usFrequency;
+ UCHAR ucPLL_ChargePump; // PLL charge-pump gain control
+ UCHAR ucPLL_DutyCycle; // PLL duty cycle control
+ UCHAR ucPLL_VCO_Gain; // PLL VCO gain control
+ UCHAR ucPLL_VoltageSwing; // PLL driver voltage swing control
+}ATOM_MISC_CONTROL_INFO;
+
+
+#define ATOM_MAX_MISC_INFO 4
+
+typedef struct _ATOM_TMDS_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usMaxFrequency; // in 10Khz
+ ATOM_MISC_CONTROL_INFO asMiscInfo[ATOM_MAX_MISC_INFO];
+}ATOM_TMDS_INFO;
+
+
+typedef struct _ATOM_ENCODER_ANALOG_ATTRIBUTE
+{
+ UCHAR ucTVStandard; //Same as TV standards defined above,
+ UCHAR ucPadding[1];
+}ATOM_ENCODER_ANALOG_ATTRIBUTE;
+
+typedef struct _ATOM_ENCODER_DIGITAL_ATTRIBUTE
+{
+ UCHAR ucAttribute; //Same as other digital encoder attributes defined above
+ UCHAR ucPadding[1];
+}ATOM_ENCODER_DIGITAL_ATTRIBUTE;
+
+typedef union _ATOM_ENCODER_ATTRIBUTE
+{
+ ATOM_ENCODER_ANALOG_ATTRIBUTE sAlgAttrib;
+ ATOM_ENCODER_DIGITAL_ATTRIBUTE sDigAttrib;
+}ATOM_ENCODER_ATTRIBUTE;
+
+
+typedef struct _DVO_ENCODER_CONTROL_PARAMETERS
+{
+ USHORT usPixelClock;
+ USHORT usEncoderID;
+ UCHAR ucDeviceType; //Use ATOM_DEVICE_xxx1_Index to indicate device type only.
+ UCHAR ucAction; //ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT
+ ATOM_ENCODER_ATTRIBUTE usDevAttr;
+}DVO_ENCODER_CONTROL_PARAMETERS;
+
+typedef struct _DVO_ENCODER_CONTROL_PS_ALLOCATION
+{
+ DVO_ENCODER_CONTROL_PARAMETERS sDVOEncoder;
+ WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion
+}DVO_ENCODER_CONTROL_PS_ALLOCATION;
+
+
+#define ATOM_XTMDS_ASIC_SI164_ID 1
+#define ATOM_XTMDS_ASIC_SI178_ID 2
+#define ATOM_XTMDS_ASIC_TFP513_ID 3
+#define ATOM_XTMDS_SUPPORTED_SINGLELINK 0x00000001
+#define ATOM_XTMDS_SUPPORTED_DUALLINK 0x00000002
+#define ATOM_XTMDS_MVPU_FPGA 0x00000004
+
+
+typedef struct _ATOM_XTMDS_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ USHORT usSingleLinkMaxFrequency;
+ ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; //Point the ID on which I2C is used to control external chip
+ UCHAR ucXtransimitterID;
+ UCHAR ucSupportedLink; // Bit field, bit0=1, single link supported;bit1=1,dual link supported
+ UCHAR ucSequnceAlterID; // Even with the same external TMDS asic, it's possible that the program seqence alters
+ // due to design. This ID is used to alert driver that the sequence is not "standard"!
+ UCHAR ucMasterAddress; // Address to control Master xTMDS Chip
+ UCHAR ucSlaveAddress; // Address to control Slave xTMDS Chip
+}ATOM_XTMDS_INFO;
+
+typedef struct _DFP_DPMS_STATUS_CHANGE_PARAMETERS
+{
+ UCHAR ucEnable; // ATOM_ENABLE=On or ATOM_DISABLE=Off
+ UCHAR ucDevice; // ATOM_DEVICE_DFP1_INDEX....
+ UCHAR ucPadding[2];
+}DFP_DPMS_STATUS_CHANGE_PARAMETERS;
+
+/****************************Legacy Power Play Table Definitions **********************/
+
+//Definitions for ulPowerPlayMiscInfo
+#define ATOM_PM_MISCINFO_SPLIT_CLOCK 0x00000000L
+#define ATOM_PM_MISCINFO_USING_MCLK_SRC 0x00000001L
+#define ATOM_PM_MISCINFO_USING_SCLK_SRC 0x00000002L
+
+#define ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT 0x00000004L
+#define ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH 0x00000008L
+
+#define ATOM_PM_MISCINFO_LOAD_PERFORMANCE_EN 0x00000010L
+
+#define ATOM_PM_MISCINFO_ENGINE_CLOCK_CONTRL_EN 0x00000020L
+#define ATOM_PM_MISCINFO_MEMORY_CLOCK_CONTRL_EN 0x00000040L
+#define ATOM_PM_MISCINFO_PROGRAM_VOLTAGE 0x00000080L //When this bit set, ucVoltageDropIndex is not an index for GPIO pin, but a voltage ID that SW needs program
+
+#define ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN 0x00000100L
+#define ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN 0x00000200L
+#define ATOM_PM_MISCINFO_ASIC_SLEEP_MODE_EN 0x00000400L
+#define ATOM_PM_MISCINFO_LOAD_BALANCE_EN 0x00000800L
+#define ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE 0x00001000L
+#define ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE 0x00002000L
+#define ATOM_PM_MISCINFO_LOW_LCD_REFRESH_RATE 0x00004000L
+
+#define ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE 0x00008000L
+#define ATOM_PM_MISCINFO_OVER_CLOCK_MODE 0x00010000L
+#define ATOM_PM_MISCINFO_OVER_DRIVE_MODE 0x00020000L
+#define ATOM_PM_MISCINFO_POWER_SAVING_MODE 0x00040000L
+#define ATOM_PM_MISCINFO_THERMAL_DIODE_MODE 0x00080000L
+
+#define ATOM_PM_MISCINFO_FRAME_MODULATION_MASK 0x00300000L //0-FM Disable, 1-2 level FM, 2-4 level FM, 3-Reserved
+#define ATOM_PM_MISCINFO_FRAME_MODULATION_SHIFT 20
+
+#define ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE 0x00400000L
+#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2 0x00800000L
+#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4 0x01000000L
+#define ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN 0x02000000L //When set, Dynamic
+#define ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN 0x04000000L //When set, Dynamic
+#define ATOM_PM_MISCINFO_3D_ACCELERATION_EN 0x08000000L //When set, This mode is for acceleated 3D mode
+
+#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_MASK 0x70000000L //1-Optimal Battery Life Group, 2-High Battery, 3-Balanced, 4-High Performance, 5- Optimal Performance (Default state with Default clocks)
+#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_SHIFT 28
+#define ATOM_PM_MISCINFO_ENABLE_BACK_BIAS 0x80000000L
+
+#define ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE 0x00000001L
+#define ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT 0x00000002L
+#define ATOM_PM_MISCINFO2_DYNAMIC_BACK_BIAS_EN 0x00000004L
+#define ATOM_PM_MISCINFO2_FS3D_OVERDRIVE_INFO 0x00000008L
+#define ATOM_PM_MISCINFO2_FORCEDLOWPWR_MODE 0x00000010L
+#define ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN 0x00000020L
+#define ATOM_PM_MISCINFO2_VIDEO_PLAYBACK_CAPABLE 0x00000040L //If this bit is set in multi-pp mode, then driver will pack up one with the minior power consumption.
+ //If it's not set in any pp mode, driver will use its default logic to pick a pp mode in video playback
+#define ATOM_PM_MISCINFO2_NOT_VALID_ON_DC 0x00000080L
+#define ATOM_PM_MISCINFO2_STUTTER_MODE_EN 0x00000100L
+#define ATOM_PM_MISCINFO2_UVD_SUPPORT_MODE 0x00000200L
+
+//ucTableFormatRevision=1
+//ucTableContentRevision=1
+typedef struct _ATOM_POWERMODE_INFO
+{
+ ULONG ulMiscInfo; //The power level should be arranged in ascending order
+ ULONG ulReserved1; // must set to 0
+ ULONG ulReserved2; // must set to 0
+ USHORT usEngineClock;
+ USHORT usMemoryClock;
+ UCHAR ucVoltageDropIndex; // index to GPIO table
+ UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate
+ UCHAR ucMinTemperature;
+ UCHAR ucMaxTemperature;
+ UCHAR ucNumPciELanes; // number of PCIE lanes
+}ATOM_POWERMODE_INFO;
+
+//ucTableFormatRevision=2
+//ucTableContentRevision=1
+typedef struct _ATOM_POWERMODE_INFO_V2
+{
+ ULONG ulMiscInfo; //The power level should be arranged in ascending order
+ ULONG ulMiscInfo2;
+ ULONG ulEngineClock;
+ ULONG ulMemoryClock;
+ UCHAR ucVoltageDropIndex; // index to GPIO table
+ UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate
+ UCHAR ucMinTemperature;
+ UCHAR ucMaxTemperature;
+ UCHAR ucNumPciELanes; // number of PCIE lanes
+}ATOM_POWERMODE_INFO_V2;
+
+//ucTableFormatRevision=2
+//ucTableContentRevision=2
+typedef struct _ATOM_POWERMODE_INFO_V3
+{
+ ULONG ulMiscInfo; //The power level should be arranged in ascending order
+ ULONG ulMiscInfo2;
+ ULONG ulEngineClock;
+ ULONG ulMemoryClock;
+ UCHAR ucVoltageDropIndex; // index to Core (VDDC) votage table
+ UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate
+ UCHAR ucMinTemperature;
+ UCHAR ucMaxTemperature;
+ UCHAR ucNumPciELanes; // number of PCIE lanes
+ UCHAR ucVDDCI_VoltageDropIndex; // index to VDDCI votage table
+}ATOM_POWERMODE_INFO_V3;
+
+
+#define ATOM_MAX_NUMBEROF_POWER_BLOCK 8
+
+#define ATOM_PP_OVERDRIVE_INTBITMAP_AUXWIN 0x01
+#define ATOM_PP_OVERDRIVE_INTBITMAP_OVERDRIVE 0x02
+
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM63 0x01
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ADM1032 0x02
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ADM1030 0x03
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_MUA6649 0x04
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM64 0x05
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_F75375 0x06
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ASC7512 0x07 // Andigilog
+
+
+typedef struct _ATOM_POWERPLAY_INFO
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucOverdriveThermalController;
+ UCHAR ucOverdriveI2cLine;
+ UCHAR ucOverdriveIntBitmap;
+ UCHAR ucOverdriveControllerAddress;
+ UCHAR ucSizeOfPowerModeEntry;
+ UCHAR ucNumOfPowerModeEntries;
+ ATOM_POWERMODE_INFO asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
+}ATOM_POWERPLAY_INFO;
+
+typedef struct _ATOM_POWERPLAY_INFO_V2
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucOverdriveThermalController;
+ UCHAR ucOverdriveI2cLine;
+ UCHAR ucOverdriveIntBitmap;
+ UCHAR ucOverdriveControllerAddress;
+ UCHAR ucSizeOfPowerModeEntry;
+ UCHAR ucNumOfPowerModeEntries;
+ ATOM_POWERMODE_INFO_V2 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
+}ATOM_POWERPLAY_INFO_V2;
+
+typedef struct _ATOM_POWERPLAY_INFO_V3
+{
+ ATOM_COMMON_TABLE_HEADER sHeader;
+ UCHAR ucOverdriveThermalController;
+ UCHAR ucOverdriveI2cLine;
+ UCHAR ucOverdriveIntBitmap;
+ UCHAR ucOverdriveControllerAddress;
+ UCHAR ucSizeOfPowerModeEntry;
+ UCHAR ucNumOfPowerModeEntries;
+ ATOM_POWERMODE_INFO_V3 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
+}ATOM_POWERPLAY_INFO_V3;
+
+
+
+/**************************************************************************/
+
+
+// Following definitions are for compatiblity issue in different SW components.
+#define ATOM_MASTER_DATA_TABLE_REVISION 0x01
+#define Object_Info Object_Header
+#define AdjustARB_SEQ MC_InitParameter
+#define VRAM_GPIO_DetectionInfo VoltageObjectInfo
+#define ASIC_VDDCI_Info ASIC_ProfilingInfo
+#define ASIC_MVDDQ_Info MemoryTrainingInfo
+#define SS_Info PPLL_SS_Info
+#define ASIC_MVDDC_Info ASIC_InternalSS_Info
+#define DispDevicePriorityInfo SaveRestoreInfo
+#define DispOutInfo TV_VideoMode
+
+
+#define ATOM_ENCODER_OBJECT_TABLE ATOM_OBJECT_TABLE
+#define ATOM_CONNECTOR_OBJECT_TABLE ATOM_OBJECT_TABLE
+
+//New device naming, remove them when both DAL/VBIOS is ready
+#define DFP2I_OUTPUT_CONTROL_PARAMETERS CRT1_OUTPUT_CONTROL_PARAMETERS
+#define DFP2I_OUTPUT_CONTROL_PS_ALLOCATION DFP2I_OUTPUT_CONTROL_PARAMETERS
+
+#define DFP1X_OUTPUT_CONTROL_PARAMETERS CRT1_OUTPUT_CONTROL_PARAMETERS
+#define DFP1X_OUTPUT_CONTROL_PS_ALLOCATION DFP1X_OUTPUT_CONTROL_PARAMETERS
+
+#define DFP1I_OUTPUT_CONTROL_PARAMETERS DFP1_OUTPUT_CONTROL_PARAMETERS
+#define DFP1I_OUTPUT_CONTROL_PS_ALLOCATION DFP1_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define ATOM_DEVICE_DFP1I_SUPPORT ATOM_DEVICE_DFP1_SUPPORT
+#define ATOM_DEVICE_DFP1X_SUPPORT ATOM_DEVICE_DFP2_SUPPORT
+
+#define ATOM_DEVICE_DFP1I_INDEX ATOM_DEVICE_DFP1_INDEX
+#define ATOM_DEVICE_DFP1X_INDEX ATOM_DEVICE_DFP2_INDEX
+
+#define ATOM_DEVICE_DFP2I_INDEX 0x00000009
+#define ATOM_DEVICE_DFP2I_SUPPORT (0x1L << ATOM_DEVICE_DFP2I_INDEX)
+
+#define ATOM_S0_DFP1I ATOM_S0_DFP1
+#define ATOM_S0_DFP1X ATOM_S0_DFP2
+
+#define ATOM_S0_DFP2I 0x00200000L
+#define ATOM_S0_DFP2Ib2 0x20
+
+#define ATOM_S2_DFP1I_DPMS_STATE ATOM_S2_DFP1_DPMS_STATE
+#define ATOM_S2_DFP1X_DPMS_STATE ATOM_S2_DFP2_DPMS_STATE
+
+#define ATOM_S2_DFP2I_DPMS_STATE 0x02000000L
+#define ATOM_S2_DFP2I_DPMS_STATEb3 0x02
+
+#define ATOM_S3_DFP2I_ACTIVEb1 0x02
+
+#define ATOM_S3_DFP1I_ACTIVE ATOM_S3_DFP1_ACTIVE
+#define ATOM_S3_DFP1X_ACTIVE ATOM_S3_DFP2_ACTIVE
+
+#define ATOM_S3_DFP2I_ACTIVE 0x00000200L
+
+#define ATOM_S3_DFP1I_CRTC_ACTIVE ATOM_S3_DFP1_CRTC_ACTIVE
+#define ATOM_S3_DFP1X_CRTC_ACTIVE ATOM_S3_DFP2_CRTC_ACTIVE
+#define ATOM_S3_DFP2I_CRTC_ACTIVE 0x02000000L
+
+
+#define ATOM_S3_DFP2I_CRTC_ACTIVEb3 0x02
+#define ATOM_S5_DOS_REQ_DFP2Ib1 0x02
+
+#define ATOM_S5_DOS_REQ_DFP2I 0x0200
+#define ATOM_S6_ACC_REQ_DFP1I ATOM_S6_ACC_REQ_DFP1
+#define ATOM_S6_ACC_REQ_DFP1X ATOM_S6_ACC_REQ_DFP2
+
+#define ATOM_S6_ACC_REQ_DFP2Ib3 0x02
+#define ATOM_S6_ACC_REQ_DFP2I 0x02000000L
+
+#define TMDS1XEncoderControl DVOEncoderControl
+#define DFP1XOutputControl DVOOutputControl
+
+#define ExternalDFPOutputControl DFP1XOutputControl
+#define EnableExternalTMDS_Encoder TMDS1XEncoderControl
+
+#define DFP1IOutputControl TMDSAOutputControl
+#define DFP2IOutputControl LVTMAOutputControl
+
+#define DAC1_ENCODER_CONTROL_PARAMETERS DAC_ENCODER_CONTROL_PARAMETERS
+#define DAC1_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION
+
+#define DAC2_ENCODER_CONTROL_PARAMETERS DAC_ENCODER_CONTROL_PARAMETERS
+#define DAC2_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION
+
+#define ucDac1Standard ucDacStandard
+#define ucDac2Standard ucDacStandard
+
+#define TMDS1EncoderControl TMDSAEncoderControl
+#define TMDS2EncoderControl LVTMAEncoderControl
+
+#define DFP1OutputControl TMDSAOutputControl
+#define DFP2OutputControl LVTMAOutputControl
+#define CRT1OutputControl DAC1OutputControl
+#define CRT2OutputControl DAC2OutputControl
+
+//These two lines will be removed for sure in a few days, will follow up with Michael V.
+#define EnableLVDS_SS EnableSpreadSpectrumOnPPLL
+#define ENABLE_LVDS_SS_PARAMETERS_V3 ENABLE_SPREAD_SPECTRUM_ON_PPLL
+
+#define ATOM_S2_CRT1_DPMS_STATE 0x00010000L
+#define ATOM_S2_LCD1_DPMS_STATE ATOM_S2_CRT1_DPMS_STATE
+#define ATOM_S2_TV1_DPMS_STATE ATOM_S2_CRT1_DPMS_STATE
+#define ATOM_S2_DFP1_DPMS_STATE ATOM_S2_CRT1_DPMS_STATE
+#define ATOM_S2_CRT2_DPMS_STATE ATOM_S2_CRT1_DPMS_STATE
+
+#define ATOM_S6_ACC_REQ_TV2 0x00400000L
+#define ATOM_DEVICE_TV2_INDEX 0x00000006
+#define ATOM_DEVICE_TV2_SUPPORT (0x1L << ATOM_DEVICE_TV2_INDEX)
+#define ATOM_S0_TV2 0x00100000L
+#define ATOM_S3_TV2_ACTIVE ATOM_S3_DFP6_ACTIVE
+#define ATOM_S3_TV2_CRTC_ACTIVE ATOM_S3_DFP6_CRTC_ACTIVE
+
+/*********************************************************************************/
+
+#pragma pack() // BIOS data must use byte aligment
+
+#pragma pack(1)
+
+typedef struct _ATOM_HOLE_INFO
+{
+ USHORT usOffset; // offset of the hole ( from the start of the binary )
+ USHORT usLength; // length of the hole ( in bytes )
+}ATOM_HOLE_INFO;
+
+typedef struct _ATOM_SERVICE_DESCRIPTION
+{
+ UCHAR ucRevision; // Holes set revision
+ UCHAR ucAlgorithm; // Hash algorithm
+ UCHAR ucSignatureType; // Signature type ( 0 - no signature, 1 - test, 2 - production )
+ UCHAR ucReserved;
+ USHORT usSigOffset; // Signature offset ( from the start of the binary )
+ USHORT usSigLength; // Signature length
+}ATOM_SERVICE_DESCRIPTION;
+
+
+typedef struct _ATOM_SERVICE_INFO
+{
+ ATOM_COMMON_TABLE_HEADER asHeader;
+ ATOM_SERVICE_DESCRIPTION asDescr;
+ UCHAR ucholesNo; // number of holes that follow
+ ATOM_HOLE_INFO holes[1]; // array of hole descriptions
+}ATOM_SERVICE_INFO;
+
+
+
+#pragma pack() // BIOS data must use byte aligment
+
+//
+// AMD ACPI Table
+//
+#pragma pack(1)
+
+typedef struct {
+ ULONG Signature;
+ ULONG TableLength; //Length
+ UCHAR Revision;
+ UCHAR Checksum;
+ UCHAR OemId[6];
+ UCHAR OemTableId[8]; //UINT64 OemTableId;
+ ULONG OemRevision;
+ ULONG CreatorId;
+ ULONG CreatorRevision;
+} AMD_ACPI_DESCRIPTION_HEADER;
+/*
+//EFI_ACPI_DESCRIPTION_HEADER from AcpiCommon.h
+typedef struct {
+ UINT32 Signature; //0x0
+ UINT32 Length; //0x4
+ UINT8 Revision; //0x8
+ UINT8 Checksum; //0x9
+ UINT8 OemId[6]; //0xA
+ UINT64 OemTableId; //0x10
+ UINT32 OemRevision; //0x18
+ UINT32 CreatorId; //0x1C
+ UINT32 CreatorRevision; //0x20
+}EFI_ACPI_DESCRIPTION_HEADER;
+*/
+typedef struct {
+ AMD_ACPI_DESCRIPTION_HEADER SHeader;
+ UCHAR TableUUID[16]; //0x24
+ ULONG VBIOSImageOffset; //0x34. Offset to the first GOP_VBIOS_CONTENT block from the beginning of the stucture.
+ ULONG Lib1ImageOffset; //0x38. Offset to the first GOP_LIB1_CONTENT block from the beginning of the stucture.
+ ULONG Reserved[4]; //0x3C
+}UEFI_ACPI_VFCT;
+
+typedef struct {
+ ULONG PCIBus; //0x4C
+ ULONG PCIDevice; //0x50
+ ULONG PCIFunction; //0x54
+ USHORT VendorID; //0x58
+ USHORT DeviceID; //0x5A
+ USHORT SSVID; //0x5C
+ USHORT SSID; //0x5E
+ ULONG Revision; //0x60
+ ULONG ImageLength; //0x64
+}VFCT_IMAGE_HEADER;
+
+
+typedef struct {
+ VFCT_IMAGE_HEADER VbiosHeader;
+ UCHAR VbiosContent[1];
+}GOP_VBIOS_CONTENT;
+
+typedef struct {
+ VFCT_IMAGE_HEADER Lib1Header;
+ UCHAR Lib1Content[1];
+}GOP_LIB1_CONTENT;
+
+#pragma pack()
+
+
+#endif /* _ATOMBIOS_H */
+
+#include "pptable.h"
+
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c
new file mode 100644
index 000000000000..49aa35016653
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c
@@ -0,0 +1,807 @@
+/*
+ * Copyright 2007-8 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 shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ */
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/amdgpu_drm.h>
+#include <drm/drm_fixed.h>
+#include "amdgpu.h"
+#include "atom.h"
+#include "atom-bits.h"
+#include "atombios_encoders.h"
+#include "amdgpu_atombios.h"
+#include "amdgpu_pll.h"
+#include "amdgpu_connectors.h"
+
+void amdgpu_atombios_crtc_overscan_setup(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ SET_CRTC_OVERSCAN_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
+ int a1, a2;
+
+ memset(&args, 0, sizeof(args));
+
+ args.ucCRTC = amdgpu_crtc->crtc_id;
+
+ switch (amdgpu_crtc->rmx_type) {
+ case RMX_CENTER:
+ args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
+ args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
+ args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
+ args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
+ break;
+ case RMX_ASPECT:
+ a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
+ a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
+
+ if (a1 > a2) {
+ args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
+ args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
+ } else if (a2 > a1) {
+ args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
+ args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
+ }
+ break;
+ case RMX_FULL:
+ default:
+ args.usOverscanRight = cpu_to_le16(amdgpu_crtc->h_border);
+ args.usOverscanLeft = cpu_to_le16(amdgpu_crtc->h_border);
+ args.usOverscanBottom = cpu_to_le16(amdgpu_crtc->v_border);
+ args.usOverscanTop = cpu_to_le16(amdgpu_crtc->v_border);
+ break;
+ }
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void amdgpu_atombios_crtc_scaler_setup(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ ENABLE_SCALER_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
+
+ memset(&args, 0, sizeof(args));
+
+ args.ucScaler = amdgpu_crtc->crtc_id;
+
+ switch (amdgpu_crtc->rmx_type) {
+ case RMX_FULL:
+ args.ucEnable = ATOM_SCALER_EXPANSION;
+ break;
+ case RMX_CENTER:
+ args.ucEnable = ATOM_SCALER_CENTER;
+ break;
+ case RMX_ASPECT:
+ args.ucEnable = ATOM_SCALER_EXPANSION;
+ break;
+ default:
+ args.ucEnable = ATOM_SCALER_DISABLE;
+ break;
+ }
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void amdgpu_atombios_crtc_lock(struct drm_crtc *crtc, int lock)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ int index =
+ GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
+ ENABLE_CRTC_PS_ALLOCATION args;
+
+ memset(&args, 0, sizeof(args));
+
+ args.ucCRTC = amdgpu_crtc->crtc_id;
+ args.ucEnable = lock;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void amdgpu_atombios_crtc_enable(struct drm_crtc *crtc, int state)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
+ ENABLE_CRTC_PS_ALLOCATION args;
+
+ memset(&args, 0, sizeof(args));
+
+ args.ucCRTC = amdgpu_crtc->crtc_id;
+ args.ucEnable = state;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void amdgpu_atombios_crtc_blank(struct drm_crtc *crtc, int state)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
+ BLANK_CRTC_PS_ALLOCATION args;
+
+ memset(&args, 0, sizeof(args));
+
+ args.ucCRTC = amdgpu_crtc->crtc_id;
+ args.ucBlanking = state;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
+ ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args;
+
+ memset(&args, 0, sizeof(args));
+
+ args.ucDispPipeId = amdgpu_crtc->crtc_id;
+ args.ucEnable = state;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev)
+{
+ int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
+ ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 args;
+
+ memset(&args, 0, sizeof(args));
+
+ args.ucEnable = ATOM_INIT;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void amdgpu_atombios_crtc_set_dtd_timing(struct drm_crtc *crtc,
+ struct drm_display_mode *mode)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
+ int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
+ u16 misc = 0;
+
+ memset(&args, 0, sizeof(args));
+ args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (amdgpu_crtc->h_border * 2));
+ args.usH_Blanking_Time =
+ cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (amdgpu_crtc->h_border * 2));
+ args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (amdgpu_crtc->v_border * 2));
+ args.usV_Blanking_Time =
+ cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (amdgpu_crtc->v_border * 2));
+ args.usH_SyncOffset =
+ cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + amdgpu_crtc->h_border);
+ args.usH_SyncWidth =
+ cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
+ args.usV_SyncOffset =
+ cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + amdgpu_crtc->v_border);
+ args.usV_SyncWidth =
+ cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
+ args.ucH_Border = amdgpu_crtc->h_border;
+ args.ucV_Border = amdgpu_crtc->v_border;
+
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ misc |= ATOM_VSYNC_POLARITY;
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ misc |= ATOM_HSYNC_POLARITY;
+ if (mode->flags & DRM_MODE_FLAG_CSYNC)
+ misc |= ATOM_COMPOSITESYNC;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ misc |= ATOM_INTERLACE;
+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+ misc |= ATOM_DOUBLE_CLOCK_MODE;
+
+ args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
+ args.ucCRTC = amdgpu_crtc->crtc_id;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+union atom_enable_ss {
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3;
+};
+
+static void amdgpu_atombios_crtc_program_ss(struct amdgpu_device *adev,
+ int enable,
+ int pll_id,
+ int crtc_id,
+ struct amdgpu_atom_ss *ss)
+{
+ unsigned i;
+ int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
+ union atom_enable_ss args;
+
+ if (enable) {
+ /* Don't mess with SS if percentage is 0 or external ss.
+ * SS is already disabled previously, and disabling it
+ * again can cause display problems if the pll is already
+ * programmed.
+ */
+ if (ss->percentage == 0)
+ return;
+ if (ss->type & ATOM_EXTERNAL_SS_MASK)
+ return;
+ } else {
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ if (adev->mode_info.crtcs[i] &&
+ adev->mode_info.crtcs[i]->enabled &&
+ i != crtc_id &&
+ pll_id == adev->mode_info.crtcs[i]->pll_id) {
+ /* one other crtc is using this pll don't turn
+ * off spread spectrum as it might turn off
+ * display on active crtc
+ */
+ return;
+ }
+ }
+ }
+
+ memset(&args, 0, sizeof(args));
+
+ args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
+ args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
+ switch (pll_id) {
+ case ATOM_PPLL1:
+ args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
+ break;
+ case ATOM_PPLL2:
+ args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
+ break;
+ case ATOM_DCPLL:
+ args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
+ break;
+ case ATOM_PPLL_INVALID:
+ return;
+ }
+ args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
+ args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
+ args.v3.ucEnable = enable;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+union adjust_pixel_clock {
+ ADJUST_DISPLAY_PLL_PS_ALLOCATION v1;
+ ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
+};
+
+static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc,
+ struct drm_display_mode *mode)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct drm_encoder *encoder = amdgpu_crtc->encoder;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+ u32 adjusted_clock = mode->clock;
+ int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
+ u32 dp_clock = mode->clock;
+ u32 clock = mode->clock;
+ int bpc = amdgpu_crtc->bpc;
+ bool is_duallink = amdgpu_dig_monitor_is_duallink(encoder, mode->clock);
+ union adjust_pixel_clock args;
+ u8 frev, crev;
+ int index;
+
+ amdgpu_crtc->pll_flags = AMDGPU_PLL_USE_FRAC_FB_DIV;
+
+ if ((amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
+ (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) {
+ if (connector) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct amdgpu_connector_atom_dig *dig_connector =
+ amdgpu_connector->con_priv;
+
+ dp_clock = dig_connector->dp_clock;
+ }
+ }
+
+ /* use recommended ref_div for ss */
+ if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ if (amdgpu_crtc->ss_enabled) {
+ if (amdgpu_crtc->ss.refdiv) {
+ amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV;
+ amdgpu_crtc->pll_reference_div = amdgpu_crtc->ss.refdiv;
+ amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
+ }
+ }
+ }
+
+ /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
+ if (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
+ adjusted_clock = mode->clock * 2;
+ if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
+ amdgpu_crtc->pll_flags |= AMDGPU_PLL_PREFER_CLOSEST_LOWER;
+ if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+ amdgpu_crtc->pll_flags |= AMDGPU_PLL_IS_LCD;
+
+
+ /* adjust pll for deep color modes */
+ if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
+ switch (bpc) {
+ case 8:
+ default:
+ break;
+ case 10:
+ clock = (clock * 5) / 4;
+ break;
+ case 12:
+ clock = (clock * 3) / 2;
+ break;
+ case 16:
+ clock = clock * 2;
+ break;
+ }
+ }
+
+ /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
+ * accordingly based on the encoder/transmitter to work around
+ * special hw requirements.
+ */
+ index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
+ &crev))
+ return adjusted_clock;
+
+ memset(&args, 0, sizeof(args));
+
+ switch (frev) {
+ case 1:
+ switch (crev) {
+ case 1:
+ case 2:
+ args.v1.usPixelClock = cpu_to_le16(clock / 10);
+ args.v1.ucTransmitterID = amdgpu_encoder->encoder_id;
+ args.v1.ucEncodeMode = encoder_mode;
+ if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage)
+ args.v1.ucConfig |=
+ ADJUST_DISPLAY_CONFIG_SS_ENABLE;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context,
+ index, (uint32_t *)&args);
+ adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
+ break;
+ case 3:
+ args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10);
+ args.v3.sInput.ucTransmitterID = amdgpu_encoder->encoder_id;
+ args.v3.sInput.ucEncodeMode = encoder_mode;
+ args.v3.sInput.ucDispPllConfig = 0;
+ if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage)
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_SS_ENABLE;
+ if (ENCODER_MODE_IS_DP(encoder_mode)) {
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_COHERENT_MODE;
+ /* 16200 or 27000 */
+ args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
+ } else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ if (dig->coherent_mode)
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_COHERENT_MODE;
+ if (is_duallink)
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_DUAL_LINK;
+ }
+ if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) !=
+ ENCODER_OBJECT_ID_NONE)
+ args.v3.sInput.ucExtTransmitterID =
+ amdgpu_encoder_get_dp_bridge_encoder_id(encoder);
+ else
+ args.v3.sInput.ucExtTransmitterID = 0;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context,
+ index, (uint32_t *)&args);
+ adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
+ if (args.v3.sOutput.ucRefDiv) {
+ amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
+ amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV;
+ amdgpu_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv;
+ }
+ if (args.v3.sOutput.ucPostDiv) {
+ amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
+ amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_POST_DIV;
+ amdgpu_crtc->pll_post_div = args.v3.sOutput.ucPostDiv;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d %d\n", frev, crev);
+ return adjusted_clock;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d %d\n", frev, crev);
+ return adjusted_clock;
+ }
+
+ return adjusted_clock;
+}
+
+union set_pixel_clock {
+ SET_PIXEL_CLOCK_PS_ALLOCATION base;
+ PIXEL_CLOCK_PARAMETERS v1;
+ PIXEL_CLOCK_PARAMETERS_V2 v2;
+ PIXEL_CLOCK_PARAMETERS_V3 v3;
+ PIXEL_CLOCK_PARAMETERS_V5 v5;
+ PIXEL_CLOCK_PARAMETERS_V6 v6;
+};
+
+/* on DCE5, make sure the voltage is high enough to support the
+ * required disp clk.
+ */
+void amdgpu_atombios_crtc_set_disp_eng_pll(struct amdgpu_device *adev,
+ u32 dispclk)
+{
+ u8 frev, crev;
+ int index;
+ union set_pixel_clock args;
+
+ memset(&args, 0, sizeof(args));
+
+ index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
+ &crev))
+ return;
+
+ switch (frev) {
+ case 1:
+ switch (crev) {
+ case 5:
+ /* if the default dcpll clock is specified,
+ * SetPixelClock provides the dividers
+ */
+ args.v5.ucCRTC = ATOM_CRTC_INVALID;
+ args.v5.usPixelClock = cpu_to_le16(dispclk);
+ args.v5.ucPpll = ATOM_DCPLL;
+ break;
+ case 6:
+ /* if the default dcpll clock is specified,
+ * SetPixelClock provides the dividers
+ */
+ args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
+ args.v6.ucPpll = ATOM_EXT_PLL1;
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d %d\n", frev, crev);
+ return;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d %d\n", frev, crev);
+ return;
+ }
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+static bool is_pixel_clock_source_from_pll(u32 encoder_mode, int pll_id)
+{
+ if (ENCODER_MODE_IS_DP(encoder_mode)) {
+ if (pll_id < ATOM_EXT_PLL1)
+ return true;
+ else
+ return false;
+ } else {
+ return true;
+ }
+}
+
+void amdgpu_atombios_crtc_program_pll(struct drm_crtc *crtc,
+ u32 crtc_id,
+ int pll_id,
+ u32 encoder_mode,
+ u32 encoder_id,
+ u32 clock,
+ u32 ref_div,
+ u32 fb_div,
+ u32 frac_fb_div,
+ u32 post_div,
+ int bpc,
+ bool ss_enabled,
+ struct amdgpu_atom_ss *ss)
+{
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ u8 frev, crev;
+ int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
+ union set_pixel_clock args;
+
+ memset(&args, 0, sizeof(args));
+
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
+ &crev))
+ return;
+
+ switch (frev) {
+ case 1:
+ switch (crev) {
+ case 1:
+ if (clock == ATOM_DISABLE)
+ return;
+ args.v1.usPixelClock = cpu_to_le16(clock / 10);
+ args.v1.usRefDiv = cpu_to_le16(ref_div);
+ args.v1.usFbDiv = cpu_to_le16(fb_div);
+ args.v1.ucFracFbDiv = frac_fb_div;
+ args.v1.ucPostDiv = post_div;
+ args.v1.ucPpll = pll_id;
+ args.v1.ucCRTC = crtc_id;
+ args.v1.ucRefDivSrc = 1;
+ break;
+ case 2:
+ args.v2.usPixelClock = cpu_to_le16(clock / 10);
+ args.v2.usRefDiv = cpu_to_le16(ref_div);
+ args.v2.usFbDiv = cpu_to_le16(fb_div);
+ args.v2.ucFracFbDiv = frac_fb_div;
+ args.v2.ucPostDiv = post_div;
+ args.v2.ucPpll = pll_id;
+ args.v2.ucCRTC = crtc_id;
+ args.v2.ucRefDivSrc = 1;
+ break;
+ case 3:
+ args.v3.usPixelClock = cpu_to_le16(clock / 10);
+ args.v3.usRefDiv = cpu_to_le16(ref_div);
+ args.v3.usFbDiv = cpu_to_le16(fb_div);
+ args.v3.ucFracFbDiv = frac_fb_div;
+ args.v3.ucPostDiv = post_div;
+ args.v3.ucPpll = pll_id;
+ if (crtc_id == ATOM_CRTC2)
+ args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2;
+ else
+ args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1;
+ if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
+ args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
+ args.v3.ucTransmitterId = encoder_id;
+ args.v3.ucEncoderMode = encoder_mode;
+ break;
+ case 5:
+ args.v5.ucCRTC = crtc_id;
+ args.v5.usPixelClock = cpu_to_le16(clock / 10);
+ args.v5.ucRefDiv = ref_div;
+ args.v5.usFbDiv = cpu_to_le16(fb_div);
+ args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
+ args.v5.ucPostDiv = post_div;
+ args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
+ if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) &&
+ (pll_id < ATOM_EXT_PLL1))
+ args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
+ if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
+ switch (bpc) {
+ case 8:
+ default:
+ args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
+ break;
+ case 10:
+ /* yes this is correct, the atom define is wrong */
+ args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP;
+ break;
+ case 12:
+ /* yes this is correct, the atom define is wrong */
+ args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
+ break;
+ }
+ }
+ args.v5.ucTransmitterID = encoder_id;
+ args.v5.ucEncoderMode = encoder_mode;
+ args.v5.ucPpll = pll_id;
+ break;
+ case 6:
+ args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10);
+ args.v6.ucRefDiv = ref_div;
+ args.v6.usFbDiv = cpu_to_le16(fb_div);
+ args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
+ args.v6.ucPostDiv = post_div;
+ args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
+ if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) &&
+ (pll_id < ATOM_EXT_PLL1) &&
+ !is_pixel_clock_source_from_pll(encoder_mode, pll_id))
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
+ if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
+ switch (bpc) {
+ case 8:
+ default:
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
+ break;
+ case 10:
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6;
+ break;
+ case 12:
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6;
+ break;
+ case 16:
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
+ break;
+ }
+ }
+ args.v6.ucTransmitterID = encoder_id;
+ args.v6.ucEncoderMode = encoder_mode;
+ args.v6.ucPpll = pll_id;
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d %d\n", frev, crev);
+ return;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d %d\n", frev, crev);
+ return;
+ }
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc,
+ struct drm_display_mode *mode)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder =
+ to_amdgpu_encoder(amdgpu_crtc->encoder);
+ int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
+
+ amdgpu_crtc->bpc = 8;
+ amdgpu_crtc->ss_enabled = false;
+
+ if ((amdgpu_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
+ (amdgpu_encoder_get_dp_bridge_encoder_id(amdgpu_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) {
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct drm_connector *connector =
+ amdgpu_get_connector_for_encoder(amdgpu_crtc->encoder);
+ struct amdgpu_connector *amdgpu_connector =
+ to_amdgpu_connector(connector);
+ struct amdgpu_connector_atom_dig *dig_connector =
+ amdgpu_connector->con_priv;
+ int dp_clock;
+
+ /* Assign mode clock for hdmi deep color max clock limit check */
+ amdgpu_connector->pixelclock_for_modeset = mode->clock;
+ amdgpu_crtc->bpc = amdgpu_connector_get_monitor_bpc(connector);
+
+ switch (encoder_mode) {
+ case ATOM_ENCODER_MODE_DP_MST:
+ case ATOM_ENCODER_MODE_DP:
+ /* DP/eDP */
+ dp_clock = dig_connector->dp_clock / 10;
+ amdgpu_crtc->ss_enabled =
+ amdgpu_atombios_get_asic_ss_info(adev, &amdgpu_crtc->ss,
+ ASIC_INTERNAL_SS_ON_DP,
+ dp_clock);
+ break;
+ case ATOM_ENCODER_MODE_LVDS:
+ amdgpu_crtc->ss_enabled =
+ amdgpu_atombios_get_asic_ss_info(adev,
+ &amdgpu_crtc->ss,
+ dig->lcd_ss_id,
+ mode->clock / 10);
+ break;
+ case ATOM_ENCODER_MODE_DVI:
+ amdgpu_crtc->ss_enabled =
+ amdgpu_atombios_get_asic_ss_info(adev,
+ &amdgpu_crtc->ss,
+ ASIC_INTERNAL_SS_ON_TMDS,
+ mode->clock / 10);
+ break;
+ case ATOM_ENCODER_MODE_HDMI:
+ amdgpu_crtc->ss_enabled =
+ amdgpu_atombios_get_asic_ss_info(adev,
+ &amdgpu_crtc->ss,
+ ASIC_INTERNAL_SS_ON_HDMI,
+ mode->clock / 10);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* adjust pixel clock as needed */
+ amdgpu_crtc->adjusted_clock = amdgpu_atombios_crtc_adjust_pll(crtc, mode);
+
+ return 0;
+}
+
+void amdgpu_atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder =
+ to_amdgpu_encoder(amdgpu_crtc->encoder);
+ u32 pll_clock = mode->clock;
+ u32 clock = mode->clock;
+ u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
+ struct amdgpu_pll *pll;
+ int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
+
+ /* pass the actual clock to amdgpu_atombios_crtc_program_pll for HDMI */
+ if ((encoder_mode == ATOM_ENCODER_MODE_HDMI) &&
+ (amdgpu_crtc->bpc > 8))
+ clock = amdgpu_crtc->adjusted_clock;
+
+ switch (amdgpu_crtc->pll_id) {
+ case ATOM_PPLL1:
+ pll = &adev->clock.ppll[0];
+ break;
+ case ATOM_PPLL2:
+ pll = &adev->clock.ppll[1];
+ break;
+ case ATOM_PPLL0:
+ case ATOM_PPLL_INVALID:
+ default:
+ pll = &adev->clock.ppll[2];
+ break;
+ }
+
+ /* update pll params */
+ pll->flags = amdgpu_crtc->pll_flags;
+ pll->reference_div = amdgpu_crtc->pll_reference_div;
+ pll->post_div = amdgpu_crtc->pll_post_div;
+
+ amdgpu_pll_compute(pll, amdgpu_crtc->adjusted_clock, &pll_clock,
+ &fb_div, &frac_fb_div, &ref_div, &post_div);
+
+ amdgpu_atombios_crtc_program_ss(adev, ATOM_DISABLE, amdgpu_crtc->pll_id,
+ amdgpu_crtc->crtc_id, &amdgpu_crtc->ss);
+
+ amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id, amdgpu_crtc->pll_id,
+ encoder_mode, amdgpu_encoder->encoder_id, clock,
+ ref_div, fb_div, frac_fb_div, post_div,
+ amdgpu_crtc->bpc, amdgpu_crtc->ss_enabled, &amdgpu_crtc->ss);
+
+ if (amdgpu_crtc->ss_enabled) {
+ /* calculate ss amount and step size */
+ u32 step_size;
+ u32 amount = (((fb_div * 10) + frac_fb_div) *
+ (u32)amdgpu_crtc->ss.percentage) /
+ (100 * (u32)amdgpu_crtc->ss.percentage_divider);
+ amdgpu_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
+ amdgpu_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
+ ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
+ if (amdgpu_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
+ step_size = (4 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) /
+ (125 * 25 * pll->reference_freq / 100);
+ else
+ step_size = (2 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) /
+ (125 * 25 * pll->reference_freq / 100);
+ amdgpu_crtc->ss.step = step_size;
+
+ amdgpu_atombios_crtc_program_ss(adev, ATOM_ENABLE, amdgpu_crtc->pll_id,
+ amdgpu_crtc->crtc_id, &amdgpu_crtc->ss);
+ }
+}
+
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.h b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.h
new file mode 100644
index 000000000000..c67083335b13
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.h
@@ -0,0 +1,58 @@
+/*
+ * 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 __ATOMBIOS_CRTC_H__
+#define __ATOMBIOS_CRTC_H__
+
+void amdgpu_atombios_crtc_overscan_setup(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+void amdgpu_atombios_crtc_scaler_setup(struct drm_crtc *crtc);
+void amdgpu_atombios_crtc_lock(struct drm_crtc *crtc, int lock);
+void amdgpu_atombios_crtc_enable(struct drm_crtc *crtc, int state);
+void amdgpu_atombios_crtc_blank(struct drm_crtc *crtc, int state);
+void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state);
+void amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev);
+void amdgpu_atombios_crtc_set_dtd_timing(struct drm_crtc *crtc,
+ struct drm_display_mode *mode);
+void amdgpu_atombios_crtc_set_disp_eng_pll(struct amdgpu_device *adev,
+ u32 dispclk);
+void amdgpu_atombios_crtc_program_pll(struct drm_crtc *crtc,
+ u32 crtc_id,
+ int pll_id,
+ u32 encoder_mode,
+ u32 encoder_id,
+ u32 clock,
+ u32 ref_div,
+ u32 fb_div,
+ u32 frac_fb_div,
+ u32 post_div,
+ int bpc,
+ bool ss_enabled,
+ struct amdgpu_atom_ss *ss);
+int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc,
+ struct drm_display_mode *mode);
+void amdgpu_atombios_crtc_set_pll(struct drm_crtc *crtc,
+ struct drm_display_mode *mode);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
new file mode 100644
index 000000000000..9ba0a7d5bc8e
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
@@ -0,0 +1,775 @@
+/*
+ * Copyright 2007-8 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 shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+
+#include "atom.h"
+#include "atom-bits.h"
+#include "atombios_encoders.h"
+#include "atombios_dp.h"
+#include "amdgpu_connectors.h"
+#include "amdgpu_atombios.h"
+#include <drm/drm_dp_helper.h>
+
+/* move these to drm_dp_helper.c/h */
+#define DP_LINK_CONFIGURATION_SIZE 9
+#define DP_DPCD_SIZE DP_RECEIVER_CAP_SIZE
+
+static char *voltage_names[] = {
+ "0.4V", "0.6V", "0.8V", "1.2V"
+};
+static char *pre_emph_names[] = {
+ "0dB", "3.5dB", "6dB", "9.5dB"
+};
+
+/***** amdgpu AUX functions *****/
+
+union aux_channel_transaction {
+ PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
+ PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
+};
+
+static int amdgpu_atombios_dp_process_aux_ch(struct amdgpu_i2c_chan *chan,
+ u8 *send, int send_bytes,
+ u8 *recv, int recv_size,
+ u8 delay, u8 *ack)
+{
+ struct drm_device *dev = chan->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ union aux_channel_transaction args;
+ int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
+ unsigned char *base;
+ int recv_bytes;
+ int r = 0;
+
+ memset(&args, 0, sizeof(args));
+
+ mutex_lock(&chan->mutex);
+
+ base = (unsigned char *)(adev->mode_info.atom_context->scratch + 1);
+
+ amdgpu_atombios_copy_swap(base, send, send_bytes, true);
+
+ args.v2.lpAuxRequest = cpu_to_le16((u16)(0 + 4));
+ args.v2.lpDataOut = cpu_to_le16((u16)(16 + 4));
+ args.v2.ucDataOutLen = 0;
+ args.v2.ucChannelID = chan->rec.i2c_id;
+ args.v2.ucDelay = delay / 10;
+ args.v2.ucHPD_ID = chan->rec.hpd;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ *ack = args.v2.ucReplyStatus;
+
+ /* timeout */
+ if (args.v2.ucReplyStatus == 1) {
+ DRM_DEBUG_KMS("dp_aux_ch timeout\n");
+ r = -ETIMEDOUT;
+ goto done;
+ }
+
+ /* flags not zero */
+ if (args.v2.ucReplyStatus == 2) {
+ DRM_DEBUG_KMS("dp_aux_ch flags not zero\n");
+ r = -EIO;
+ goto done;
+ }
+
+ /* error */
+ if (args.v2.ucReplyStatus == 3) {
+ DRM_DEBUG_KMS("dp_aux_ch error\n");
+ r = -EIO;
+ goto done;
+ }
+
+ recv_bytes = args.v1.ucDataOutLen;
+ if (recv_bytes > recv_size)
+ recv_bytes = recv_size;
+
+ if (recv && recv_size)
+ amdgpu_atombios_copy_swap(recv, base + 16, recv_bytes, false);
+
+ r = recv_bytes;
+done:
+ mutex_unlock(&chan->mutex);
+
+ return r;
+}
+
+#define BARE_ADDRESS_SIZE 3
+#define HEADER_SIZE (BARE_ADDRESS_SIZE + 1)
+
+static ssize_t
+amdgpu_atombios_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
+{
+ struct amdgpu_i2c_chan *chan =
+ container_of(aux, struct amdgpu_i2c_chan, aux);
+ int ret;
+ u8 tx_buf[20];
+ size_t tx_size;
+ u8 ack, delay = 0;
+
+ if (WARN_ON(msg->size > 16))
+ return -E2BIG;
+
+ tx_buf[0] = msg->address & 0xff;
+ tx_buf[1] = msg->address >> 8;
+ tx_buf[2] = msg->request << 4;
+ tx_buf[3] = msg->size ? (msg->size - 1) : 0;
+
+ switch (msg->request & ~DP_AUX_I2C_MOT) {
+ case DP_AUX_NATIVE_WRITE:
+ case DP_AUX_I2C_WRITE:
+ /* tx_size needs to be 4 even for bare address packets since the atom
+ * table needs the info in tx_buf[3].
+ */
+ tx_size = HEADER_SIZE + msg->size;
+ if (msg->size == 0)
+ tx_buf[3] |= BARE_ADDRESS_SIZE << 4;
+ else
+ tx_buf[3] |= tx_size << 4;
+ memcpy(tx_buf + HEADER_SIZE, msg->buffer, msg->size);
+ ret = amdgpu_atombios_dp_process_aux_ch(chan,
+ tx_buf, tx_size, NULL, 0, delay, &ack);
+ if (ret >= 0)
+ /* Return payload size. */
+ ret = msg->size;
+ break;
+ case DP_AUX_NATIVE_READ:
+ case DP_AUX_I2C_READ:
+ /* tx_size needs to be 4 even for bare address packets since the atom
+ * table needs the info in tx_buf[3].
+ */
+ tx_size = HEADER_SIZE;
+ if (msg->size == 0)
+ tx_buf[3] |= BARE_ADDRESS_SIZE << 4;
+ else
+ tx_buf[3] |= tx_size << 4;
+ ret = amdgpu_atombios_dp_process_aux_ch(chan,
+ tx_buf, tx_size, msg->buffer, msg->size, delay, &ack);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret >= 0)
+ msg->reply = ack >> 4;
+
+ return ret;
+}
+
+void amdgpu_atombios_dp_aux_init(struct amdgpu_connector *amdgpu_connector)
+{
+ int ret;
+
+ amdgpu_connector->ddc_bus->rec.hpd = amdgpu_connector->hpd.hpd;
+ amdgpu_connector->ddc_bus->aux.dev = amdgpu_connector->base.kdev;
+ amdgpu_connector->ddc_bus->aux.transfer = amdgpu_atombios_dp_aux_transfer;
+ ret = drm_dp_aux_register(&amdgpu_connector->ddc_bus->aux);
+ if (!ret)
+ amdgpu_connector->ddc_bus->has_aux = true;
+
+ WARN(ret, "drm_dp_aux_register_i2c_bus() failed with error %d\n", ret);
+}
+
+/***** general DP utility functions *****/
+
+#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_LEVEL_3
+#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPH_LEVEL_3
+
+static void amdgpu_atombios_dp_get_adjust_train(const u8 link_status[DP_LINK_STATUS_SIZE],
+ int lane_count,
+ u8 train_set[4])
+{
+ u8 v = 0;
+ u8 p = 0;
+ int lane;
+
+ for (lane = 0; lane < lane_count; lane++) {
+ u8 this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
+ u8 this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
+
+ DRM_DEBUG_KMS("requested signal parameters: lane %d voltage %s pre_emph %s\n",
+ lane,
+ voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
+ pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
+
+ if (this_v > v)
+ v = this_v;
+ if (this_p > p)
+ p = this_p;
+ }
+
+ if (v >= DP_VOLTAGE_MAX)
+ v |= DP_TRAIN_MAX_SWING_REACHED;
+
+ if (p >= DP_PRE_EMPHASIS_MAX)
+ p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+
+ DRM_DEBUG_KMS("using signal parameters: voltage %s pre_emph %s\n",
+ voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
+ pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
+
+ for (lane = 0; lane < 4; lane++)
+ train_set[lane] = v | p;
+}
+
+/* convert bits per color to bits per pixel */
+/* get bpc from the EDID */
+static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
+{
+ if (bpc == 0)
+ return 24;
+ else
+ 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,
+ 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)
+{
+ 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;
+ }
+
+ return drm_dp_max_link_rate(dpcd);
+}
+
+static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev,
+ int action, int dp_clock,
+ u8 ucconfig, u8 lane_num)
+{
+ DP_ENCODER_SERVICE_PARAMETERS args;
+ int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
+
+ memset(&args, 0, sizeof(args));
+ args.ucLinkClock = dp_clock / 10;
+ args.ucConfig = ucconfig;
+ args.ucAction = action;
+ args.ucLaneNum = lane_num;
+ args.ucStatus = 0;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+ return args.ucStatus;
+}
+
+u8 amdgpu_atombios_dp_get_sinktype(struct amdgpu_connector *amdgpu_connector)
+{
+ struct drm_device *dev = amdgpu_connector->base.dev;
+ struct amdgpu_device *adev = dev->dev_private;
+
+ return amdgpu_atombios_dp_encoder_service(adev, ATOM_DP_ACTION_GET_SINK_TYPE, 0,
+ amdgpu_connector->ddc_bus->rec.i2c_id, 0);
+}
+
+static void amdgpu_atombios_dp_probe_oui(struct amdgpu_connector *amdgpu_connector)
+{
+ struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
+ u8 buf[3];
+
+ if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
+ return;
+
+ if (drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_SINK_OUI, buf, 3) == 3)
+ DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n",
+ buf[0], buf[1], buf[2]);
+
+ if (drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_BRANCH_OUI, buf, 3) == 3)
+ DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
+ buf[0], buf[1], buf[2]);
+}
+
+int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector)
+{
+ struct amdgpu_connector_atom_dig *dig_connector = amdgpu_connector->con_priv;
+ u8 msg[DP_DPCD_SIZE];
+ int ret, i;
+
+ for (i = 0; i < 7; i++) {
+ ret = drm_dp_dpcd_read(&amdgpu_connector->ddc_bus->aux, DP_DPCD_REV, msg,
+ DP_DPCD_SIZE);
+ if (ret == DP_DPCD_SIZE) {
+ memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
+
+ DRM_DEBUG_KMS("DPCD: %*ph\n", (int)sizeof(dig_connector->dpcd),
+ dig_connector->dpcd);
+
+ amdgpu_atombios_dp_probe_oui(amdgpu_connector);
+
+ return 0;
+ }
+ }
+ dig_connector->dpcd[0] = 0;
+ return -EINVAL;
+}
+
+int amdgpu_atombios_dp_get_panel_mode(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct amdgpu_connector_atom_dig *dig_connector;
+ int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
+ u16 dp_bridge = amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector);
+ u8 tmp;
+
+ if (!amdgpu_connector->con_priv)
+ return panel_mode;
+
+ dig_connector = amdgpu_connector->con_priv;
+
+ if (dp_bridge != ENCODER_OBJECT_ID_NONE) {
+ /* DP bridge chips */
+ if (drm_dp_dpcd_readb(&amdgpu_connector->ddc_bus->aux,
+ DP_EDP_CONFIGURATION_CAP, &tmp) == 1) {
+ if (tmp & 1)
+ panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
+ else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) ||
+ (dp_bridge == ENCODER_OBJECT_ID_TRAVIS))
+ panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE;
+ else
+ panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
+ }
+ } else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ /* eDP */
+ if (drm_dp_dpcd_readb(&amdgpu_connector->ddc_bus->aux,
+ DP_EDP_CONFIGURATION_CAP, &tmp) == 1) {
+ if (tmp & 1)
+ panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
+ }
+ }
+
+ return panel_mode;
+}
+
+void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector,
+ const struct drm_display_mode *mode)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct amdgpu_connector_atom_dig *dig_connector;
+
+ if (!amdgpu_connector->con_priv)
+ return;
+ dig_connector = amdgpu_connector->con_priv;
+
+ 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);
+ }
+}
+
+int amdgpu_atombios_dp_mode_valid_helper(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct amdgpu_connector_atom_dig *dig_connector;
+ int dp_clock;
+
+ 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);
+
+ if ((dp_clock == 540000) &&
+ (!amdgpu_connector_is_dp12_capable(connector)))
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+bool amdgpu_atombios_dp_needs_link_train(struct amdgpu_connector *amdgpu_connector)
+{
+ u8 link_status[DP_LINK_STATUS_SIZE];
+ struct amdgpu_connector_atom_dig *dig = amdgpu_connector->con_priv;
+
+ if (drm_dp_dpcd_read_link_status(&amdgpu_connector->ddc_bus->aux, link_status)
+ <= 0)
+ return false;
+ if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count))
+ return false;
+ return true;
+}
+
+void amdgpu_atombios_dp_set_rx_power_state(struct drm_connector *connector,
+ u8 power_state)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct amdgpu_connector_atom_dig *dig_connector;
+
+ if (!amdgpu_connector->con_priv)
+ return;
+
+ dig_connector = amdgpu_connector->con_priv;
+
+ /* power up/down the sink */
+ if (dig_connector->dpcd[0] >= 0x11) {
+ drm_dp_dpcd_writeb(&amdgpu_connector->ddc_bus->aux,
+ DP_SET_POWER, power_state);
+ usleep_range(1000, 2000);
+ }
+}
+
+struct amdgpu_atombios_dp_link_train_info {
+ struct amdgpu_device *adev;
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ int dp_clock;
+ int dp_lane_count;
+ bool tp3_supported;
+ u8 dpcd[DP_RECEIVER_CAP_SIZE];
+ u8 train_set[4];
+ u8 link_status[DP_LINK_STATUS_SIZE];
+ u8 tries;
+ struct drm_dp_aux *aux;
+};
+
+static void
+amdgpu_atombios_dp_update_vs_emph(struct amdgpu_atombios_dp_link_train_info *dp_info)
+{
+ /* set the initial vs/emph on the source */
+ amdgpu_atombios_encoder_setup_dig_transmitter(dp_info->encoder,
+ ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,
+ 0, dp_info->train_set[0]); /* sets all lanes at once */
+
+ /* set the vs/emph on the sink */
+ drm_dp_dpcd_write(dp_info->aux, DP_TRAINING_LANE0_SET,
+ dp_info->train_set, dp_info->dp_lane_count);
+}
+
+static void
+amdgpu_atombios_dp_set_tp(struct amdgpu_atombios_dp_link_train_info *dp_info, int tp)
+{
+ int rtp = 0;
+
+ /* set training pattern on the source */
+ switch (tp) {
+ case DP_TRAINING_PATTERN_1:
+ rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;
+ break;
+ case DP_TRAINING_PATTERN_2:
+ rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2;
+ break;
+ case DP_TRAINING_PATTERN_3:
+ rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3;
+ break;
+ }
+ amdgpu_atombios_encoder_setup_dig_encoder(dp_info->encoder, rtp, 0);
+
+ /* enable training pattern on the sink */
+ drm_dp_dpcd_writeb(dp_info->aux, DP_TRAINING_PATTERN_SET, tp);
+}
+
+static int
+amdgpu_atombios_dp_link_train_init(struct amdgpu_atombios_dp_link_train_info *dp_info)
+{
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(dp_info->encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ u8 tmp;
+
+ /* power up the sink */
+ amdgpu_atombios_dp_set_rx_power_state(dp_info->connector, DP_SET_POWER_D0);
+
+ /* possibly enable downspread on the sink */
+ if (dp_info->dpcd[3] & 0x1)
+ drm_dp_dpcd_writeb(dp_info->aux,
+ DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
+ else
+ drm_dp_dpcd_writeb(dp_info->aux,
+ DP_DOWNSPREAD_CTRL, 0);
+
+ if (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)
+ drm_dp_dpcd_writeb(dp_info->aux, DP_EDP_CONFIGURATION_SET, 1);
+
+ /* set the lane count on the sink */
+ tmp = dp_info->dp_lane_count;
+ if (drm_dp_enhanced_frame_cap(dp_info->dpcd))
+ tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+ drm_dp_dpcd_writeb(dp_info->aux, DP_LANE_COUNT_SET, tmp);
+
+ /* set the link rate on the sink */
+ tmp = drm_dp_link_rate_to_bw_code(dp_info->dp_clock);
+ drm_dp_dpcd_writeb(dp_info->aux, DP_LINK_BW_SET, tmp);
+
+ /* start training on the source */
+ amdgpu_atombios_encoder_setup_dig_encoder(dp_info->encoder,
+ ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0);
+
+ /* disable the training pattern on the sink */
+ drm_dp_dpcd_writeb(dp_info->aux,
+ DP_TRAINING_PATTERN_SET,
+ DP_TRAINING_PATTERN_DISABLE);
+
+ return 0;
+}
+
+static int
+amdgpu_atombios_dp_link_train_finish(struct amdgpu_atombios_dp_link_train_info *dp_info)
+{
+ udelay(400);
+
+ /* disable the training pattern on the sink */
+ drm_dp_dpcd_writeb(dp_info->aux,
+ DP_TRAINING_PATTERN_SET,
+ DP_TRAINING_PATTERN_DISABLE);
+
+ /* disable the training pattern on the source */
+ amdgpu_atombios_encoder_setup_dig_encoder(dp_info->encoder,
+ ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE, 0);
+
+ return 0;
+}
+
+static int
+amdgpu_atombios_dp_link_train_cr(struct amdgpu_atombios_dp_link_train_info *dp_info)
+{
+ bool clock_recovery;
+ u8 voltage;
+ int i;
+
+ amdgpu_atombios_dp_set_tp(dp_info, DP_TRAINING_PATTERN_1);
+ memset(dp_info->train_set, 0, 4);
+ amdgpu_atombios_dp_update_vs_emph(dp_info);
+
+ udelay(400);
+
+ /* clock recovery loop */
+ clock_recovery = false;
+ dp_info->tries = 0;
+ voltage = 0xff;
+ while (1) {
+ drm_dp_link_train_clock_recovery_delay(dp_info->dpcd);
+
+ if (drm_dp_dpcd_read_link_status(dp_info->aux,
+ dp_info->link_status) <= 0) {
+ DRM_ERROR("displayport link status failed\n");
+ break;
+ }
+
+ if (drm_dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) {
+ clock_recovery = true;
+ break;
+ }
+
+ for (i = 0; i < dp_info->dp_lane_count; i++) {
+ if ((dp_info->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+ break;
+ }
+ if (i == dp_info->dp_lane_count) {
+ DRM_ERROR("clock recovery reached max voltage\n");
+ break;
+ }
+
+ if ((dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+ ++dp_info->tries;
+ if (dp_info->tries == 5) {
+ DRM_ERROR("clock recovery tried 5 times\n");
+ break;
+ }
+ } else
+ dp_info->tries = 0;
+
+ voltage = dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+
+ /* Compute new train_set as requested by sink */
+ amdgpu_atombios_dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count,
+ dp_info->train_set);
+
+ amdgpu_atombios_dp_update_vs_emph(dp_info);
+ }
+ if (!clock_recovery) {
+ DRM_ERROR("clock recovery failed\n");
+ return -1;
+ } else {
+ DRM_DEBUG_KMS("clock recovery at voltage %d pre-emphasis %d\n",
+ dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
+ (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
+ DP_TRAIN_PRE_EMPHASIS_SHIFT);
+ return 0;
+ }
+}
+
+static int
+amdgpu_atombios_dp_link_train_ce(struct amdgpu_atombios_dp_link_train_info *dp_info)
+{
+ bool channel_eq;
+
+ if (dp_info->tp3_supported)
+ amdgpu_atombios_dp_set_tp(dp_info, DP_TRAINING_PATTERN_3);
+ else
+ amdgpu_atombios_dp_set_tp(dp_info, DP_TRAINING_PATTERN_2);
+
+ /* channel equalization loop */
+ dp_info->tries = 0;
+ channel_eq = false;
+ while (1) {
+ drm_dp_link_train_channel_eq_delay(dp_info->dpcd);
+
+ if (drm_dp_dpcd_read_link_status(dp_info->aux,
+ dp_info->link_status) <= 0) {
+ DRM_ERROR("displayport link status failed\n");
+ break;
+ }
+
+ if (drm_dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) {
+ channel_eq = true;
+ break;
+ }
+
+ /* Try 5 times */
+ if (dp_info->tries > 5) {
+ DRM_ERROR("channel eq failed: 5 tries\n");
+ break;
+ }
+
+ /* Compute new train_set as requested by sink */
+ amdgpu_atombios_dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count,
+ dp_info->train_set);
+
+ amdgpu_atombios_dp_update_vs_emph(dp_info);
+ dp_info->tries++;
+ }
+
+ if (!channel_eq) {
+ DRM_ERROR("channel eq failed\n");
+ return -1;
+ } else {
+ DRM_DEBUG_KMS("channel eq at voltage %d pre-emphasis %d\n",
+ dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
+ (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
+ >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
+ return 0;
+ }
+}
+
+void amdgpu_atombios_dp_link_train(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig;
+ struct amdgpu_connector *amdgpu_connector;
+ struct amdgpu_connector_atom_dig *dig_connector;
+ struct amdgpu_atombios_dp_link_train_info dp_info;
+ u8 tmp;
+
+ if (!amdgpu_encoder->enc_priv)
+ return;
+ dig = amdgpu_encoder->enc_priv;
+
+ amdgpu_connector = to_amdgpu_connector(connector);
+ if (!amdgpu_connector->con_priv)
+ return;
+ dig_connector = amdgpu_connector->con_priv;
+
+ if ((dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT) &&
+ (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_eDP))
+ return;
+
+ if (drm_dp_dpcd_readb(&amdgpu_connector->ddc_bus->aux, DP_MAX_LANE_COUNT, &tmp)
+ == 1) {
+ if (tmp & DP_TPS3_SUPPORTED)
+ dp_info.tp3_supported = true;
+ else
+ dp_info.tp3_supported = false;
+ } else {
+ dp_info.tp3_supported = false;
+ }
+
+ memcpy(dp_info.dpcd, dig_connector->dpcd, DP_RECEIVER_CAP_SIZE);
+ dp_info.adev = adev;
+ dp_info.encoder = encoder;
+ dp_info.connector = connector;
+ dp_info.dp_lane_count = dig_connector->dp_lane_count;
+ dp_info.dp_clock = dig_connector->dp_clock;
+ dp_info.aux = &amdgpu_connector->ddc_bus->aux;
+
+ if (amdgpu_atombios_dp_link_train_init(&dp_info))
+ goto done;
+ if (amdgpu_atombios_dp_link_train_cr(&dp_info))
+ goto done;
+ if (amdgpu_atombios_dp_link_train_ce(&dp_info))
+ goto done;
+done:
+ if (amdgpu_atombios_dp_link_train_finish(&dp_info))
+ return;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.h b/drivers/gpu/drm/amd/amdgpu/atombios_dp.h
new file mode 100644
index 000000000000..f59d85eaddf0
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.h
@@ -0,0 +1,42 @@
+/*
+ * 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 __ATOMBIOS_DP_H__
+#define __ATOMBIOS_DP_H__
+
+void amdgpu_atombios_dp_aux_init(struct amdgpu_connector *amdgpu_connector);
+u8 amdgpu_atombios_dp_get_sinktype(struct amdgpu_connector *amdgpu_connector);
+int amdgpu_atombios_dp_get_dpcd(struct amdgpu_connector *amdgpu_connector);
+int amdgpu_atombios_dp_get_panel_mode(struct drm_encoder *encoder,
+ struct drm_connector *connector);
+void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector,
+ const struct drm_display_mode *mode);
+int amdgpu_atombios_dp_mode_valid_helper(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+bool amdgpu_atombios_dp_needs_link_train(struct amdgpu_connector *amdgpu_connector);
+void amdgpu_atombios_dp_set_rx_power_state(struct drm_connector *connector,
+ u8 power_state);
+void amdgpu_atombios_dp_link_train(struct drm_encoder *encoder,
+ struct drm_connector *connector);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
new file mode 100644
index 000000000000..ae8caca61e04
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
@@ -0,0 +1,2066 @@
+/*
+ * Copyright 2007-11 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 shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ */
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "amdgpu_connectors.h"
+#include "atom.h"
+#include "atombios_encoders.h"
+#include "atombios_dp.h"
+#include <linux/backlight.h>
+#include "bif/bif_4_1_d.h"
+
+static u8
+amdgpu_atombios_encoder_get_backlight_level_from_reg(struct amdgpu_device *adev)
+{
+ u8 backlight_level;
+ u32 bios_2_scratch;
+
+ bios_2_scratch = RREG32(mmBIOS_SCRATCH_2);
+
+ backlight_level = ((bios_2_scratch & ATOM_S2_CURRENT_BL_LEVEL_MASK) >>
+ ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
+
+ return backlight_level;
+}
+
+static void
+amdgpu_atombios_encoder_set_backlight_level_to_reg(struct amdgpu_device *adev,
+ u8 backlight_level)
+{
+ u32 bios_2_scratch;
+
+ bios_2_scratch = RREG32(mmBIOS_SCRATCH_2);
+
+ bios_2_scratch &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;
+ bios_2_scratch |= ((backlight_level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT) &
+ ATOM_S2_CURRENT_BL_LEVEL_MASK);
+
+ WREG32(mmBIOS_SCRATCH_2, bios_2_scratch);
+}
+
+u8
+amdgpu_atombios_encoder_get_backlight_level(struct amdgpu_encoder *amdgpu_encoder)
+{
+ struct drm_device *dev = amdgpu_encoder->base.dev;
+ struct amdgpu_device *adev = dev->dev_private;
+
+ if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
+ return 0;
+
+ return amdgpu_atombios_encoder_get_backlight_level_from_reg(adev);
+}
+
+void
+amdgpu_atombios_encoder_set_backlight_level(struct amdgpu_encoder *amdgpu_encoder,
+ u8 level)
+{
+ struct drm_encoder *encoder = &amdgpu_encoder->base;
+ struct drm_device *dev = amdgpu_encoder->base.dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder_atom_dig *dig;
+
+ if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
+ return;
+
+ if ((amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) &&
+ amdgpu_encoder->enc_priv) {
+ dig = amdgpu_encoder->enc_priv;
+ dig->backlight_level = level;
+ amdgpu_atombios_encoder_set_backlight_level_to_reg(adev, dig->backlight_level);
+
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ if (dig->backlight_level == 0)
+ amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
+ ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
+ else {
+ amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
+ ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL, 0, 0);
+ amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
+ ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
+
+static u8 amdgpu_atombios_encoder_backlight_level(struct backlight_device *bd)
+{
+ u8 level;
+
+ /* Convert brightness to hardware level */
+ if (bd->props.brightness < 0)
+ level = 0;
+ else if (bd->props.brightness > AMDGPU_MAX_BL_LEVEL)
+ level = AMDGPU_MAX_BL_LEVEL;
+ else
+ level = bd->props.brightness;
+
+ return level;
+}
+
+static int amdgpu_atombios_encoder_update_backlight_status(struct backlight_device *bd)
+{
+ struct amdgpu_backlight_privdata *pdata = bl_get_data(bd);
+ struct amdgpu_encoder *amdgpu_encoder = pdata->encoder;
+
+ amdgpu_atombios_encoder_set_backlight_level(amdgpu_encoder,
+ amdgpu_atombios_encoder_backlight_level(bd));
+
+ return 0;
+}
+
+static int
+amdgpu_atombios_encoder_get_backlight_brightness(struct backlight_device *bd)
+{
+ struct amdgpu_backlight_privdata *pdata = bl_get_data(bd);
+ struct amdgpu_encoder *amdgpu_encoder = pdata->encoder;
+ struct drm_device *dev = amdgpu_encoder->base.dev;
+ struct amdgpu_device *adev = dev->dev_private;
+
+ return amdgpu_atombios_encoder_get_backlight_level_from_reg(adev);
+}
+
+static const struct backlight_ops amdgpu_atombios_encoder_backlight_ops = {
+ .get_brightness = amdgpu_atombios_encoder_get_backlight_brightness,
+ .update_status = amdgpu_atombios_encoder_update_backlight_status,
+};
+
+void amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder *amdgpu_encoder,
+ struct drm_connector *drm_connector)
+{
+ struct drm_device *dev = amdgpu_encoder->base.dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct backlight_device *bd;
+ struct backlight_properties props;
+ struct amdgpu_backlight_privdata *pdata;
+ struct amdgpu_encoder_atom_dig *dig;
+ u8 backlight_level;
+ char bl_name[16];
+
+ /* Mac laptops with multiple GPUs use the gmux driver for backlight
+ * so don't register a backlight device
+ */
+ if ((adev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
+ (adev->pdev->device == 0x6741))
+ return;
+
+ if (!amdgpu_encoder->enc_priv)
+ return;
+
+ if (!adev->is_atom_bios)
+ return;
+
+ if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
+ return;
+
+ pdata = kmalloc(sizeof(struct amdgpu_backlight_privdata), GFP_KERNEL);
+ if (!pdata) {
+ DRM_ERROR("Memory allocation failed\n");
+ goto error;
+ }
+
+ memset(&props, 0, sizeof(props));
+ props.max_brightness = AMDGPU_MAX_BL_LEVEL;
+ props.type = BACKLIGHT_RAW;
+ snprintf(bl_name, sizeof(bl_name),
+ "amdgpu_bl%d", dev->primary->index);
+ bd = backlight_device_register(bl_name, drm_connector->kdev,
+ pdata, &amdgpu_atombios_encoder_backlight_ops, &props);
+ if (IS_ERR(bd)) {
+ DRM_ERROR("Backlight registration failed\n");
+ goto error;
+ }
+
+ pdata->encoder = amdgpu_encoder;
+
+ backlight_level = amdgpu_atombios_encoder_get_backlight_level_from_reg(adev);
+
+ dig = amdgpu_encoder->enc_priv;
+ dig->bl_dev = bd;
+
+ bd->props.brightness = amdgpu_atombios_encoder_get_backlight_brightness(bd);
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
+
+ DRM_INFO("amdgpu atom DIG backlight initialized\n");
+
+ return;
+
+error:
+ kfree(pdata);
+ return;
+}
+
+void
+amdgpu_atombios_encoder_fini_backlight(struct amdgpu_encoder *amdgpu_encoder)
+{
+ struct drm_device *dev = amdgpu_encoder->base.dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct backlight_device *bd = NULL;
+ struct amdgpu_encoder_atom_dig *dig;
+
+ if (!amdgpu_encoder->enc_priv)
+ return;
+
+ if (!adev->is_atom_bios)
+ return;
+
+ if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
+ return;
+
+ dig = amdgpu_encoder->enc_priv;
+ bd = dig->bl_dev;
+ dig->bl_dev = NULL;
+
+ if (bd) {
+ struct amdgpu_legacy_backlight_privdata *pdata;
+
+ pdata = bl_get_data(bd);
+ backlight_device_unregister(bd);
+ kfree(pdata);
+
+ DRM_INFO("amdgpu atom LVDS backlight unloaded\n");
+ }
+}
+
+#else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */
+
+void amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder *encoder)
+{
+}
+
+void amdgpu_atombios_encoder_fini_backlight(struct amdgpu_encoder *encoder)
+{
+}
+
+#endif
+
+bool amdgpu_atombios_encoder_is_digital(struct drm_encoder *encoder)
+{
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool amdgpu_atombios_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+ /* set the active encoder to connector routing */
+ amdgpu_encoder_set_active_device(encoder);
+ drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+ /* hw bug */
+ if ((mode->flags & DRM_MODE_FLAG_INTERLACE)
+ && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2)))
+ adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2;
+
+ /* get the native mode for scaling */
+ if (amdgpu_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT))
+ amdgpu_panel_mode_fixup(encoder, adjusted_mode);
+ else if (amdgpu_encoder->rmx_type != RMX_OFF)
+ amdgpu_panel_mode_fixup(encoder, adjusted_mode);
+
+ if ((amdgpu_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) ||
+ (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) {
+ struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+ amdgpu_atombios_dp_set_link_config(connector, adjusted_mode);
+ }
+
+ return true;
+}
+
+static void
+amdgpu_atombios_encoder_setup_dac(struct drm_encoder *encoder, int action)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ DAC_ENCODER_CONTROL_PS_ALLOCATION args;
+ int index = 0;
+
+ memset(&args, 0, sizeof(args));
+
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_DAC1:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+ index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl);
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_DAC2:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+ index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl);
+ break;
+ }
+
+ args.ucAction = action;
+ args.ucDacStandard = ATOM_DAC1_PS2;
+ args.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+}
+
+static u8 amdgpu_atombios_encoder_get_bpc(struct drm_encoder *encoder)
+{
+ int bpc = 8;
+
+ if (encoder->crtc) {
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
+ bpc = amdgpu_crtc->bpc;
+ }
+
+ switch (bpc) {
+ case 0:
+ return PANEL_BPC_UNDEFINE;
+ case 6:
+ return PANEL_6BIT_PER_COLOR;
+ case 8:
+ default:
+ return PANEL_8BIT_PER_COLOR;
+ case 10:
+ return PANEL_10BIT_PER_COLOR;
+ case 12:
+ return PANEL_12BIT_PER_COLOR;
+ case 16:
+ return PANEL_16BIT_PER_COLOR;
+ }
+}
+
+union dvo_encoder_control {
+ ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds;
+ DVO_ENCODER_CONTROL_PS_ALLOCATION dvo;
+ DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3;
+ DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4 dvo_v4;
+};
+
+static void
+amdgpu_atombios_encoder_setup_dvo(struct drm_encoder *encoder, int action)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ union dvo_encoder_control args;
+ int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
+ uint8_t frev, crev;
+
+ memset(&args, 0, sizeof(args));
+
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
+ return;
+
+ switch (frev) {
+ case 1:
+ switch (crev) {
+ case 1:
+ /* R4xx, R5xx */
+ args.ext_tmds.sXTmdsEncoder.ucEnable = action;
+
+ if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL;
+
+ args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB;
+ break;
+ case 2:
+ /* RS600/690/740 */
+ args.dvo.sDVOEncoder.ucAction = action;
+ args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+ /* DFP1, CRT1, TV1 depending on the type of port */
+ args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX;
+
+ if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL;
+ break;
+ case 3:
+ /* R6xx */
+ args.dvo_v3.ucAction = action;
+ args.dvo_v3.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+ args.dvo_v3.ucDVOConfig = 0; /* XXX */
+ break;
+ case 4:
+ /* DCE8 */
+ args.dvo_v4.ucAction = action;
+ args.dvo_v4.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+ args.dvo_v4.ucDVOConfig = 0; /* XXX */
+ args.dvo_v4.ucBitPerColor = amdgpu_atombios_encoder_get_bpc(encoder);
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ break;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ break;
+ }
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+int amdgpu_atombios_encoder_get_encoder_mode(struct drm_encoder *encoder)
+{
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector;
+ struct amdgpu_connector_atom_dig *dig_connector;
+
+ /* dp bridges are always DP */
+ if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)
+ return ATOM_ENCODER_MODE_DP;
+
+ /* DVO is always DVO */
+ if ((amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DVO1) ||
+ (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1))
+ return ATOM_ENCODER_MODE_DVO;
+
+ connector = amdgpu_get_connector_for_encoder(encoder);
+ /* if we don't have an active device yet, just use one of
+ * the connectors tied to the encoder.
+ */
+ if (!connector)
+ connector = amdgpu_get_connector_for_encoder_init(encoder);
+ amdgpu_connector = to_amdgpu_connector(connector);
+
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
+ if (amdgpu_audio != 0) {
+ if (amdgpu_connector->use_digital &&
+ (amdgpu_connector->audio == AMDGPU_AUDIO_ENABLE))
+ return ATOM_ENCODER_MODE_HDMI;
+ else if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector)) &&
+ (amdgpu_connector->audio == AMDGPU_AUDIO_AUTO))
+ return ATOM_ENCODER_MODE_HDMI;
+ else if (amdgpu_connector->use_digital)
+ return ATOM_ENCODER_MODE_DVI;
+ else
+ return ATOM_ENCODER_MODE_CRT;
+ } else if (amdgpu_connector->use_digital) {
+ return ATOM_ENCODER_MODE_DVI;
+ } else {
+ return ATOM_ENCODER_MODE_CRT;
+ }
+ break;
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_HDMIA:
+ default:
+ if (amdgpu_audio != 0) {
+ if (amdgpu_connector->audio == AMDGPU_AUDIO_ENABLE)
+ return ATOM_ENCODER_MODE_HDMI;
+ else if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector)) &&
+ (amdgpu_connector->audio == AMDGPU_AUDIO_AUTO))
+ return ATOM_ENCODER_MODE_HDMI;
+ else
+ return ATOM_ENCODER_MODE_DVI;
+ } else {
+ return ATOM_ENCODER_MODE_DVI;
+ }
+ break;
+ case DRM_MODE_CONNECTOR_LVDS:
+ return ATOM_ENCODER_MODE_LVDS;
+ break;
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ dig_connector = amdgpu_connector->con_priv;
+ if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+ (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
+ return ATOM_ENCODER_MODE_DP;
+ } else if (amdgpu_audio != 0) {
+ if (amdgpu_connector->audio == AMDGPU_AUDIO_ENABLE)
+ return ATOM_ENCODER_MODE_HDMI;
+ else if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector)) &&
+ (amdgpu_connector->audio == AMDGPU_AUDIO_AUTO))
+ return ATOM_ENCODER_MODE_HDMI;
+ else
+ return ATOM_ENCODER_MODE_DVI;
+ } else {
+ return ATOM_ENCODER_MODE_DVI;
+ }
+ break;
+ case DRM_MODE_CONNECTOR_eDP:
+ return ATOM_ENCODER_MODE_DP;
+ case DRM_MODE_CONNECTOR_DVIA:
+ case DRM_MODE_CONNECTOR_VGA:
+ return ATOM_ENCODER_MODE_CRT;
+ break;
+ case DRM_MODE_CONNECTOR_Composite:
+ case DRM_MODE_CONNECTOR_SVIDEO:
+ case DRM_MODE_CONNECTOR_9PinDIN:
+ /* fix me */
+ return ATOM_ENCODER_MODE_TV;
+ /*return ATOM_ENCODER_MODE_CV;*/
+ break;
+ }
+}
+
+/*
+ * DIG Encoder/Transmitter Setup
+ *
+ * DCE 6.0
+ * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B).
+ * Supports up to 6 digital outputs
+ * - 6 DIG encoder blocks.
+ * - DIG to PHY mapping is hardcoded
+ * DIG1 drives UNIPHY0 link A, A+B
+ * DIG2 drives UNIPHY0 link B
+ * DIG3 drives UNIPHY1 link A, A+B
+ * DIG4 drives UNIPHY1 link B
+ * DIG5 drives UNIPHY2 link A, A+B
+ * DIG6 drives UNIPHY2 link B
+ *
+ * Routing
+ * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links)
+ * Examples:
+ * crtc0 -> dig2 -> LVTMA links A+B -> TMDS/HDMI
+ * crtc1 -> dig1 -> UNIPHY0 link B -> DP
+ * crtc0 -> dig1 -> UNIPHY2 link A -> LVDS
+ * crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI
+ */
+
+union dig_encoder_control {
+ DIG_ENCODER_CONTROL_PS_ALLOCATION v1;
+ DIG_ENCODER_CONTROL_PARAMETERS_V2 v2;
+ DIG_ENCODER_CONTROL_PARAMETERS_V3 v3;
+ DIG_ENCODER_CONTROL_PARAMETERS_V4 v4;
+};
+
+void
+amdgpu_atombios_encoder_setup_dig_encoder(struct drm_encoder *encoder,
+ int action, int panel_mode)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+ union dig_encoder_control args;
+ int index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl);
+ uint8_t frev, crev;
+ int dp_clock = 0;
+ int dp_lane_count = 0;
+ int hpd_id = AMDGPU_HPD_NONE;
+
+ if (connector) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct amdgpu_connector_atom_dig *dig_connector =
+ amdgpu_connector->con_priv;
+
+ dp_clock = dig_connector->dp_clock;
+ dp_lane_count = dig_connector->dp_lane_count;
+ hpd_id = amdgpu_connector->hpd.hpd;
+ }
+
+ /* no dig encoder assigned */
+ if (dig->dig_encoder == -1)
+ return;
+
+ memset(&args, 0, sizeof(args));
+
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
+ return;
+
+ switch (frev) {
+ case 1:
+ switch (crev) {
+ case 1:
+ args.v1.ucAction = action;
+ args.v1.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+ if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
+ args.v3.ucPanelMode = panel_mode;
+ else
+ args.v1.ucEncoderMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
+
+ if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode))
+ args.v1.ucLaneNum = dp_lane_count;
+ else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v1.ucLaneNum = 8;
+ else
+ args.v1.ucLaneNum = 4;
+
+ if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000))
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
+ break;
+ }
+ if (dig->linkb)
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
+ else
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
+ break;
+ case 2:
+ case 3:
+ args.v3.ucAction = action;
+ args.v3.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+ if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
+ args.v3.ucPanelMode = panel_mode;
+ else
+ args.v3.ucEncoderMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
+
+ if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode))
+ args.v3.ucLaneNum = dp_lane_count;
+ else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v3.ucLaneNum = 8;
+ else
+ args.v3.ucLaneNum = 4;
+
+ if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000))
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
+ args.v3.acConfig.ucDigSel = dig->dig_encoder;
+ args.v3.ucBitPerColor = amdgpu_atombios_encoder_get_bpc(encoder);
+ break;
+ case 4:
+ args.v4.ucAction = action;
+ args.v4.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+ if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
+ args.v4.ucPanelMode = panel_mode;
+ else
+ args.v4.ucEncoderMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
+
+ if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode))
+ args.v4.ucLaneNum = dp_lane_count;
+ else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v4.ucLaneNum = 8;
+ else
+ args.v4.ucLaneNum = 4;
+
+ if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) {
+ if (dp_clock == 540000)
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
+ else if (dp_clock == 324000)
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_3_24GHZ;
+ else if (dp_clock == 270000)
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
+ else
+ args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ;
+ }
+ args.v4.acConfig.ucDigSel = dig->dig_encoder;
+ args.v4.ucBitPerColor = amdgpu_atombios_encoder_get_bpc(encoder);
+ if (hpd_id == AMDGPU_HPD_NONE)
+ args.v4.ucHPD_ID = 0;
+ else
+ args.v4.ucHPD_ID = hpd_id + 1;
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ break;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ break;
+ }
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+}
+
+union dig_transmitter_control {
+ DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
+ DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
+ DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3;
+ DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4;
+ DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5 v5;
+};
+
+void
+amdgpu_atombios_encoder_setup_dig_transmitter(struct drm_encoder *encoder, int action,
+ uint8_t lane_num, uint8_t lane_set)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct drm_connector *connector;
+ union dig_transmitter_control args;
+ int index = 0;
+ uint8_t frev, crev;
+ bool is_dp = false;
+ int pll_id = 0;
+ int dp_clock = 0;
+ int dp_lane_count = 0;
+ int connector_object_id = 0;
+ int igp_lane_info = 0;
+ int dig_encoder = dig->dig_encoder;
+ int hpd_id = AMDGPU_HPD_NONE;
+
+ if (action == ATOM_TRANSMITTER_ACTION_INIT) {
+ connector = amdgpu_get_connector_for_encoder_init(encoder);
+ /* just needed to avoid bailing in the encoder check. the encoder
+ * isn't used for init
+ */
+ dig_encoder = 0;
+ } else
+ connector = amdgpu_get_connector_for_encoder(encoder);
+
+ if (connector) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct amdgpu_connector_atom_dig *dig_connector =
+ amdgpu_connector->con_priv;
+
+ hpd_id = amdgpu_connector->hpd.hpd;
+ dp_clock = dig_connector->dp_clock;
+ dp_lane_count = dig_connector->dp_lane_count;
+ connector_object_id =
+ (amdgpu_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+ }
+
+ if (encoder->crtc) {
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
+ pll_id = amdgpu_crtc->pll_id;
+ }
+
+ /* no dig encoder assigned */
+ if (dig_encoder == -1)
+ return;
+
+ if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(encoder)))
+ is_dp = true;
+
+ memset(&args, 0, sizeof(args));
+
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+ index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl);
+ break;
+ }
+
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
+ return;
+
+ switch (frev) {
+ case 1:
+ switch (crev) {
+ case 1:
+ args.v1.ucAction = action;
+ if (action == ATOM_TRANSMITTER_ACTION_INIT) {
+ args.v1.usInitInfo = cpu_to_le16(connector_object_id);
+ } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
+ args.v1.asMode.ucLaneSel = lane_num;
+ args.v1.asMode.ucLaneSet = lane_set;
+ } else {
+ if (is_dp)
+ args.v1.usPixelClock = cpu_to_le16(dp_clock / 10);
+ else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v1.usPixelClock = cpu_to_le16((amdgpu_encoder->pixel_clock / 2) / 10);
+ else
+ args.v1.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+ }
+
+ args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
+
+ if (dig_encoder)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
+ else
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
+
+ if ((adev->flags & AMDGPU_IS_APU) &&
+ (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) {
+ if (is_dp ||
+ !amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock)) {
+ if (igp_lane_info & 0x1)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
+ else if (igp_lane_info & 0x2)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7;
+ else if (igp_lane_info & 0x4)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11;
+ else if (igp_lane_info & 0x8)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
+ } else {
+ if (igp_lane_info & 0x3)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
+ else if (igp_lane_info & 0xc)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
+ }
+ }
+
+ if (dig->linkb)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB;
+ else
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
+
+ if (is_dp)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
+ else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+ if (dig->coherent_mode)
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
+ if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK;
+ }
+ break;
+ case 2:
+ args.v2.ucAction = action;
+ if (action == ATOM_TRANSMITTER_ACTION_INIT) {
+ args.v2.usInitInfo = cpu_to_le16(connector_object_id);
+ } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
+ args.v2.asMode.ucLaneSel = lane_num;
+ args.v2.asMode.ucLaneSet = lane_set;
+ } else {
+ if (is_dp)
+ args.v2.usPixelClock = cpu_to_le16(dp_clock / 10);
+ else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v2.usPixelClock = cpu_to_le16((amdgpu_encoder->pixel_clock / 2) / 10);
+ else
+ args.v2.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+ }
+
+ args.v2.acConfig.ucEncoderSel = dig_encoder;
+ if (dig->linkb)
+ args.v2.acConfig.ucLinkSel = 1;
+
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ args.v2.acConfig.ucTransmitterSel = 0;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ args.v2.acConfig.ucTransmitterSel = 1;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ args.v2.acConfig.ucTransmitterSel = 2;
+ break;
+ }
+
+ if (is_dp) {
+ args.v2.acConfig.fCoherentMode = 1;
+ args.v2.acConfig.fDPConnector = 1;
+ } else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+ if (dig->coherent_mode)
+ args.v2.acConfig.fCoherentMode = 1;
+ if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v2.acConfig.fDualLinkConnector = 1;
+ }
+ break;
+ case 3:
+ args.v3.ucAction = action;
+ if (action == ATOM_TRANSMITTER_ACTION_INIT) {
+ args.v3.usInitInfo = cpu_to_le16(connector_object_id);
+ } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
+ args.v3.asMode.ucLaneSel = lane_num;
+ args.v3.asMode.ucLaneSet = lane_set;
+ } else {
+ if (is_dp)
+ args.v3.usPixelClock = cpu_to_le16(dp_clock / 10);
+ else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v3.usPixelClock = cpu_to_le16((amdgpu_encoder->pixel_clock / 2) / 10);
+ else
+ args.v3.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+ }
+
+ if (is_dp)
+ args.v3.ucLaneNum = dp_lane_count;
+ else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v3.ucLaneNum = 8;
+ else
+ args.v3.ucLaneNum = 4;
+
+ if (dig->linkb)
+ args.v3.acConfig.ucLinkSel = 1;
+ if (dig_encoder & 1)
+ args.v3.acConfig.ucEncoderSel = 1;
+
+ /* Select the PLL for the PHY
+ * DP PHY should be clocked from external src if there is
+ * one.
+ */
+ /* On DCE4, if there is an external clock, it generates the DP ref clock */
+ if (is_dp && adev->clock.dp_extclk)
+ args.v3.acConfig.ucRefClkSource = 2; /* external src */
+ else
+ args.v3.acConfig.ucRefClkSource = pll_id;
+
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ args.v3.acConfig.ucTransmitterSel = 0;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ args.v3.acConfig.ucTransmitterSel = 1;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ args.v3.acConfig.ucTransmitterSel = 2;
+ break;
+ }
+
+ if (is_dp)
+ args.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */
+ else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+ if (dig->coherent_mode)
+ args.v3.acConfig.fCoherentMode = 1;
+ if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v3.acConfig.fDualLinkConnector = 1;
+ }
+ break;
+ case 4:
+ args.v4.ucAction = action;
+ if (action == ATOM_TRANSMITTER_ACTION_INIT) {
+ args.v4.usInitInfo = cpu_to_le16(connector_object_id);
+ } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
+ args.v4.asMode.ucLaneSel = lane_num;
+ args.v4.asMode.ucLaneSet = lane_set;
+ } else {
+ if (is_dp)
+ args.v4.usPixelClock = cpu_to_le16(dp_clock / 10);
+ else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v4.usPixelClock = cpu_to_le16((amdgpu_encoder->pixel_clock / 2) / 10);
+ else
+ args.v4.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+ }
+
+ if (is_dp)
+ args.v4.ucLaneNum = dp_lane_count;
+ else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v4.ucLaneNum = 8;
+ else
+ args.v4.ucLaneNum = 4;
+
+ if (dig->linkb)
+ args.v4.acConfig.ucLinkSel = 1;
+ if (dig_encoder & 1)
+ args.v4.acConfig.ucEncoderSel = 1;
+
+ /* Select the PLL for the PHY
+ * DP PHY should be clocked from external src if there is
+ * one.
+ */
+ /* On DCE5 DCPLL usually generates the DP ref clock */
+ if (is_dp) {
+ if (adev->clock.dp_extclk)
+ args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK;
+ else
+ args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL;
+ } else
+ args.v4.acConfig.ucRefClkSource = pll_id;
+
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ args.v4.acConfig.ucTransmitterSel = 0;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ args.v4.acConfig.ucTransmitterSel = 1;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ args.v4.acConfig.ucTransmitterSel = 2;
+ break;
+ }
+
+ if (is_dp)
+ args.v4.acConfig.fCoherentMode = 1; /* DP requires coherent */
+ else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+ if (dig->coherent_mode)
+ args.v4.acConfig.fCoherentMode = 1;
+ if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v4.acConfig.fDualLinkConnector = 1;
+ }
+ break;
+ case 5:
+ args.v5.ucAction = action;
+ if (is_dp)
+ args.v5.usSymClock = cpu_to_le16(dp_clock / 10);
+ else
+ args.v5.usSymClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ if (dig->linkb)
+ args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYB;
+ else
+ args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYA;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ if (dig->linkb)
+ args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYD;
+ else
+ args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYC;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ if (dig->linkb)
+ args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYF;
+ else
+ args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+ args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYG;
+ break;
+ }
+ if (is_dp)
+ args.v5.ucLaneNum = dp_lane_count;
+ else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v5.ucLaneNum = 8;
+ else
+ args.v5.ucLaneNum = 4;
+ args.v5.ucConnObjId = connector_object_id;
+ args.v5.ucDigMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
+
+ if (is_dp && adev->clock.dp_extclk)
+ args.v5.asConfig.ucPhyClkSrcId = ENCODER_REFCLK_SRC_EXTCLK;
+ else
+ args.v5.asConfig.ucPhyClkSrcId = pll_id;
+
+ if (is_dp)
+ args.v5.asConfig.ucCoherentMode = 1; /* DP requires coherent */
+ else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+ if (dig->coherent_mode)
+ args.v5.asConfig.ucCoherentMode = 1;
+ }
+ if (hpd_id == AMDGPU_HPD_NONE)
+ args.v5.asConfig.ucHPDSel = 0;
+ else
+ args.v5.asConfig.ucHPDSel = hpd_id + 1;
+ args.v5.ucDigEncoderSel = 1 << dig_encoder;
+ args.v5.ucDPLaneSet = lane_set;
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ break;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ break;
+ }
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+bool
+amdgpu_atombios_encoder_set_edp_panel_power(struct drm_connector *connector,
+ int action)
+{
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct drm_device *dev = amdgpu_connector->base.dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ union dig_transmitter_control args;
+ int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
+ uint8_t frev, crev;
+
+ if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
+ goto done;
+
+ if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) &&
+ (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
+ goto done;
+
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
+ goto done;
+
+ memset(&args, 0, sizeof(args));
+
+ args.v1.ucAction = action;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ /* wait for the panel to power up */
+ if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) {
+ int i;
+
+ for (i = 0; i < 300; i++) {
+ if (amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd))
+ return true;
+ mdelay(1);
+ }
+ return false;
+ }
+done:
+ return true;
+}
+
+union external_encoder_control {
+ EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1;
+ EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3;
+};
+
+static void
+amdgpu_atombios_encoder_setup_external_encoder(struct drm_encoder *encoder,
+ struct drm_encoder *ext_encoder,
+ int action)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder *ext_amdgpu_encoder = to_amdgpu_encoder(ext_encoder);
+ union external_encoder_control args;
+ struct drm_connector *connector;
+ int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
+ u8 frev, crev;
+ int dp_clock = 0;
+ int dp_lane_count = 0;
+ int connector_object_id = 0;
+ u32 ext_enum = (ext_amdgpu_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
+
+ if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
+ connector = amdgpu_get_connector_for_encoder_init(encoder);
+ else
+ connector = amdgpu_get_connector_for_encoder(encoder);
+
+ if (connector) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct amdgpu_connector_atom_dig *dig_connector =
+ amdgpu_connector->con_priv;
+
+ dp_clock = dig_connector->dp_clock;
+ dp_lane_count = dig_connector->dp_lane_count;
+ connector_object_id =
+ (amdgpu_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+ }
+
+ memset(&args, 0, sizeof(args));
+
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
+ return;
+
+ switch (frev) {
+ case 1:
+ /* no params on frev 1 */
+ break;
+ case 2:
+ switch (crev) {
+ case 1:
+ case 2:
+ args.v1.sDigEncoder.ucAction = action;
+ args.v1.sDigEncoder.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+ args.v1.sDigEncoder.ucEncoderMode =
+ amdgpu_atombios_encoder_get_encoder_mode(encoder);
+
+ if (ENCODER_MODE_IS_DP(args.v1.sDigEncoder.ucEncoderMode)) {
+ if (dp_clock == 270000)
+ args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
+ args.v1.sDigEncoder.ucLaneNum = dp_lane_count;
+ } else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v1.sDigEncoder.ucLaneNum = 8;
+ else
+ args.v1.sDigEncoder.ucLaneNum = 4;
+ break;
+ case 3:
+ args.v3.sExtEncoder.ucAction = action;
+ if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
+ args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id);
+ else
+ args.v3.sExtEncoder.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
+ args.v3.sExtEncoder.ucEncoderMode =
+ amdgpu_atombios_encoder_get_encoder_mode(encoder);
+
+ if (ENCODER_MODE_IS_DP(args.v3.sExtEncoder.ucEncoderMode)) {
+ if (dp_clock == 270000)
+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
+ else if (dp_clock == 540000)
+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ;
+ args.v3.sExtEncoder.ucLaneNum = dp_lane_count;
+ } else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
+ args.v3.sExtEncoder.ucLaneNum = 8;
+ else
+ args.v3.sExtEncoder.ucLaneNum = 4;
+ switch (ext_enum) {
+ case GRAPH_OBJECT_ENUM_ID1:
+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1;
+ break;
+ case GRAPH_OBJECT_ENUM_ID2:
+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2;
+ break;
+ case GRAPH_OBJECT_ENUM_ID3:
+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3;
+ break;
+ }
+ args.v3.sExtEncoder.ucBitPerColor = amdgpu_atombios_encoder_get_bpc(encoder);
+ break;
+ default:
+ DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
+ return;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
+ return;
+ }
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+static void
+amdgpu_atombios_encoder_setup_dig(struct drm_encoder *encoder, int action)
+{
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_encoder *ext_encoder = amdgpu_get_external_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+ struct amdgpu_connector *amdgpu_connector = NULL;
+ struct amdgpu_connector_atom_dig *amdgpu_dig_connector = NULL;
+
+ if (connector) {
+ amdgpu_connector = to_amdgpu_connector(connector);
+ amdgpu_dig_connector = amdgpu_connector->con_priv;
+ }
+
+ if (action == ATOM_ENABLE) {
+ if (!connector)
+ dig->panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
+ else
+ dig->panel_mode = amdgpu_atombios_dp_get_panel_mode(encoder, connector);
+
+ /* setup and enable the encoder */
+ amdgpu_atombios_encoder_setup_dig_encoder(encoder, ATOM_ENCODER_CMD_SETUP, 0);
+ amdgpu_atombios_encoder_setup_dig_encoder(encoder,
+ ATOM_ENCODER_CMD_SETUP_PANEL_MODE,
+ dig->panel_mode);
+ if (ext_encoder)
+ amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder,
+ EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);
+ if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(encoder)) &&
+ connector) {
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ amdgpu_atombios_encoder_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_ON);
+ amdgpu_dig_connector->edp_on = true;
+ }
+ }
+ /* enable the transmitter */
+ amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
+ ATOM_TRANSMITTER_ACTION_ENABLE,
+ 0, 0);
+ if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(encoder)) &&
+ connector) {
+ /* DP_SET_POWER_D0 is set in amdgpu_atombios_dp_link_train */
+ amdgpu_atombios_dp_link_train(encoder, connector);
+ amdgpu_atombios_encoder_setup_dig_encoder(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
+ }
+ if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+ amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
+ ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
+ if (ext_encoder)
+ amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder, ATOM_ENABLE);
+ } else {
+ if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(encoder)) &&
+ connector)
+ amdgpu_atombios_encoder_setup_dig_encoder(encoder,
+ ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
+ if (ext_encoder)
+ amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder, ATOM_DISABLE);
+ if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+ amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
+ ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
+
+ if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(encoder)) &&
+ connector)
+ amdgpu_atombios_dp_set_rx_power_state(connector, DP_SET_POWER_D3);
+ /* disable the transmitter */
+ amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
+ ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
+ if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(encoder)) &&
+ connector) {
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ amdgpu_atombios_encoder_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_OFF);
+ amdgpu_dig_connector->edp_on = false;
+ }
+ }
+ }
+}
+
+void
+amdgpu_atombios_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+ DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n",
+ amdgpu_encoder->encoder_id, mode, amdgpu_encoder->devices,
+ amdgpu_encoder->active_device);
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ amdgpu_atombios_encoder_setup_dig(encoder, ATOM_ENABLE);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ amdgpu_atombios_encoder_setup_dig(encoder, ATOM_DISABLE);
+ break;
+ }
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ amdgpu_atombios_encoder_setup_dvo(encoder, ATOM_ENABLE);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ amdgpu_atombios_encoder_setup_dvo(encoder, ATOM_DISABLE);
+ break;
+ }
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ amdgpu_atombios_encoder_setup_dac(encoder, ATOM_ENABLE);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ amdgpu_atombios_encoder_setup_dac(encoder, ATOM_DISABLE);
+ break;
+ }
+ break;
+ default:
+ return;
+ }
+}
+
+union crtc_source_param {
+ SELECT_CRTC_SOURCE_PS_ALLOCATION v1;
+ SELECT_CRTC_SOURCE_PARAMETERS_V2 v2;
+ SELECT_CRTC_SOURCE_PARAMETERS_V3 v3;
+};
+
+void
+amdgpu_atombios_encoder_set_crtc_source(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
+ union crtc_source_param args;
+ int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
+ uint8_t frev, crev;
+ struct amdgpu_encoder_atom_dig *dig;
+
+ memset(&args, 0, sizeof(args));
+
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
+ return;
+
+ switch (frev) {
+ case 1:
+ switch (crev) {
+ case 1:
+ default:
+ args.v1.ucCRTC = amdgpu_crtc->crtc_id;
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
+ args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+ case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+ if (amdgpu_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT)
+ args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX;
+ else
+ args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_DVO1:
+ case ENCODER_OBJECT_ID_INTERNAL_DDI:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_DAC1:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+ if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
+ args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
+ else if (amdgpu_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
+ args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
+ else
+ args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_DAC2:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+ if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
+ args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
+ else if (amdgpu_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
+ args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
+ else
+ args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX;
+ break;
+ }
+ break;
+ case 2:
+ args.v2.ucCRTC = amdgpu_crtc->crtc_id;
+ if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) {
+ struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+
+ if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
+ args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
+ else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA)
+ args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT;
+ else
+ args.v2.ucEncodeMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
+ } else if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
+ } else {
+ args.v2.ucEncodeMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
+ }
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ dig = amdgpu_encoder->enc_priv;
+ switch (dig->dig_encoder) {
+ case 0:
+ args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+ break;
+ case 1:
+ args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
+ break;
+ case 2:
+ args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
+ break;
+ case 3:
+ args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
+ break;
+ case 4:
+ args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
+ break;
+ case 5:
+ args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
+ break;
+ case 6:
+ args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID;
+ break;
+ }
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+ if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
+ args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
+ else if (amdgpu_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
+ args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
+ else
+ args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+ if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
+ args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
+ else if (amdgpu_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
+ args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
+ else
+ args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
+ break;
+ }
+ break;
+ case 3:
+ args.v3.ucCRTC = amdgpu_crtc->crtc_id;
+ if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) {
+ struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+
+ if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
+ args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
+ else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA)
+ args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT;
+ else
+ args.v2.ucEncodeMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
+ } else if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+ args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
+ } else {
+ args.v2.ucEncodeMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
+ }
+ args.v3.ucDstBpc = amdgpu_atombios_encoder_get_bpc(encoder);
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ dig = amdgpu_encoder->enc_priv;
+ switch (dig->dig_encoder) {
+ case 0:
+ args.v3.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+ break;
+ case 1:
+ args.v3.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
+ break;
+ case 2:
+ args.v3.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
+ break;
+ case 3:
+ args.v3.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
+ break;
+ case 4:
+ args.v3.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
+ break;
+ case 5:
+ args.v3.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
+ break;
+ case 6:
+ args.v3.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID;
+ break;
+ }
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ args.v3.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+ if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
+ args.v3.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
+ else if (amdgpu_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
+ args.v3.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
+ else
+ args.v3.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+ if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
+ args.v3.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
+ else if (amdgpu_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
+ args.v3.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
+ else
+ args.v3.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
+ break;
+ }
+ break;
+ }
+ break;
+ default:
+ DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
+ return;
+ }
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+/* This only needs to be called once at startup */
+void
+amdgpu_atombios_encoder_init_dig(struct amdgpu_device *adev)
+{
+ struct drm_device *dev = adev->ddev;
+ struct drm_encoder *encoder;
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_encoder *ext_encoder = amdgpu_get_external_encoder(encoder);
+
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+ amdgpu_atombios_encoder_setup_dig_transmitter(encoder, ATOM_TRANSMITTER_ACTION_INIT,
+ 0, 0);
+ break;
+ }
+
+ if (ext_encoder)
+ amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder,
+ EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
+ }
+}
+
+static bool
+amdgpu_atombios_encoder_dac_load_detect(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+ if (amdgpu_encoder->devices & (ATOM_DEVICE_TV_SUPPORT |
+ ATOM_DEVICE_CV_SUPPORT |
+ ATOM_DEVICE_CRT_SUPPORT)) {
+ DAC_LOAD_DETECTION_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);
+ uint8_t frev, crev;
+
+ memset(&args, 0, sizeof(args));
+
+ if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
+ return false;
+
+ args.sDacload.ucMisc = 0;
+
+ if ((amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
+ (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))
+ args.sDacload.ucDacType = ATOM_DAC_A;
+ else
+ args.sDacload.ucDacType = ATOM_DAC_B;
+
+ if (amdgpu_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)
+ args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT);
+ else if (amdgpu_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)
+ args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT);
+ else if (amdgpu_connector->devices & ATOM_DEVICE_CV_SUPPORT) {
+ args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT);
+ if (crev >= 3)
+ args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
+ } else if (amdgpu_connector->devices & ATOM_DEVICE_TV1_SUPPORT) {
+ args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT);
+ if (crev >= 3)
+ args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
+ }
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ return true;
+ } else
+ return false;
+}
+
+enum drm_connector_status
+amdgpu_atombios_encoder_dac_detect(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ uint32_t bios_0_scratch;
+
+ if (!amdgpu_atombios_encoder_dac_load_detect(encoder, connector)) {
+ DRM_DEBUG_KMS("detect returned false \n");
+ return connector_status_unknown;
+ }
+
+ bios_0_scratch = RREG32(mmBIOS_SCRATCH_0);
+
+ DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, amdgpu_encoder->devices);
+ if (amdgpu_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) {
+ if (bios_0_scratch & ATOM_S0_CRT1_MASK)
+ return connector_status_connected;
+ }
+ if (amdgpu_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) {
+ if (bios_0_scratch & ATOM_S0_CRT2_MASK)
+ return connector_status_connected;
+ }
+ if (amdgpu_connector->devices & ATOM_DEVICE_CV_SUPPORT) {
+ if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A))
+ return connector_status_connected;
+ }
+ if (amdgpu_connector->devices & ATOM_DEVICE_TV1_SUPPORT) {
+ if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
+ return connector_status_connected; /* CTV */
+ else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
+ return connector_status_connected; /* STV */
+ }
+ return connector_status_disconnected;
+}
+
+enum drm_connector_status
+amdgpu_atombios_encoder_dig_detect(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ struct drm_encoder *ext_encoder = amdgpu_get_external_encoder(encoder);
+ u32 bios_0_scratch;
+
+ if (!ext_encoder)
+ return connector_status_unknown;
+
+ if ((amdgpu_connector->devices & ATOM_DEVICE_CRT_SUPPORT) == 0)
+ return connector_status_unknown;
+
+ /* load detect on the dp bridge */
+ amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder,
+ EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION);
+
+ bios_0_scratch = RREG32(mmBIOS_SCRATCH_0);
+
+ DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, amdgpu_encoder->devices);
+ if (amdgpu_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) {
+ if (bios_0_scratch & ATOM_S0_CRT1_MASK)
+ return connector_status_connected;
+ }
+ if (amdgpu_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) {
+ if (bios_0_scratch & ATOM_S0_CRT2_MASK)
+ return connector_status_connected;
+ }
+ if (amdgpu_connector->devices & ATOM_DEVICE_CV_SUPPORT) {
+ if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A))
+ return connector_status_connected;
+ }
+ if (amdgpu_connector->devices & ATOM_DEVICE_TV1_SUPPORT) {
+ if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
+ return connector_status_connected; /* CTV */
+ else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
+ return connector_status_connected; /* STV */
+ }
+ return connector_status_disconnected;
+}
+
+void
+amdgpu_atombios_encoder_setup_ext_encoder_ddc(struct drm_encoder *encoder)
+{
+ struct drm_encoder *ext_encoder = amdgpu_get_external_encoder(encoder);
+
+ if (ext_encoder)
+ /* ddc_setup on the dp bridge */
+ amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder,
+ EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP);
+
+}
+
+void
+amdgpu_atombios_encoder_set_bios_scratch_regs(struct drm_connector *connector,
+ struct drm_encoder *encoder,
+ bool connected)
+{
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_connector *amdgpu_connector =
+ to_amdgpu_connector(connector);
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ uint32_t bios_0_scratch, bios_3_scratch, bios_6_scratch;
+
+ bios_0_scratch = RREG32(mmBIOS_SCRATCH_0);
+ bios_3_scratch = RREG32(mmBIOS_SCRATCH_3);
+ bios_6_scratch = RREG32(mmBIOS_SCRATCH_6);
+
+ if ((amdgpu_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) &&
+ (amdgpu_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) {
+ if (connected) {
+ DRM_DEBUG_KMS("LCD1 connected\n");
+ bios_0_scratch |= ATOM_S0_LCD1;
+ bios_3_scratch |= ATOM_S3_LCD1_ACTIVE;
+ bios_6_scratch |= ATOM_S6_ACC_REQ_LCD1;
+ } else {
+ DRM_DEBUG_KMS("LCD1 disconnected\n");
+ bios_0_scratch &= ~ATOM_S0_LCD1;
+ bios_3_scratch &= ~ATOM_S3_LCD1_ACTIVE;
+ bios_6_scratch &= ~ATOM_S6_ACC_REQ_LCD1;
+ }
+ }
+ if ((amdgpu_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) &&
+ (amdgpu_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) {
+ if (connected) {
+ DRM_DEBUG_KMS("CRT1 connected\n");
+ bios_0_scratch |= ATOM_S0_CRT1_COLOR;
+ bios_3_scratch |= ATOM_S3_CRT1_ACTIVE;
+ bios_6_scratch |= ATOM_S6_ACC_REQ_CRT1;
+ } else {
+ DRM_DEBUG_KMS("CRT1 disconnected\n");
+ bios_0_scratch &= ~ATOM_S0_CRT1_MASK;
+ bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE;
+ bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT1;
+ }
+ }
+ if ((amdgpu_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) &&
+ (amdgpu_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) {
+ if (connected) {
+ DRM_DEBUG_KMS("CRT2 connected\n");
+ bios_0_scratch |= ATOM_S0_CRT2_COLOR;
+ bios_3_scratch |= ATOM_S3_CRT2_ACTIVE;
+ bios_6_scratch |= ATOM_S6_ACC_REQ_CRT2;
+ } else {
+ DRM_DEBUG_KMS("CRT2 disconnected\n");
+ bios_0_scratch &= ~ATOM_S0_CRT2_MASK;
+ bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE;
+ bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT2;
+ }
+ }
+ if ((amdgpu_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) &&
+ (amdgpu_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) {
+ if (connected) {
+ DRM_DEBUG_KMS("DFP1 connected\n");
+ bios_0_scratch |= ATOM_S0_DFP1;
+ bios_3_scratch |= ATOM_S3_DFP1_ACTIVE;
+ bios_6_scratch |= ATOM_S6_ACC_REQ_DFP1;
+ } else {
+ DRM_DEBUG_KMS("DFP1 disconnected\n");
+ bios_0_scratch &= ~ATOM_S0_DFP1;
+ bios_3_scratch &= ~ATOM_S3_DFP1_ACTIVE;
+ bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP1;
+ }
+ }
+ if ((amdgpu_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) &&
+ (amdgpu_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) {
+ if (connected) {
+ DRM_DEBUG_KMS("DFP2 connected\n");
+ bios_0_scratch |= ATOM_S0_DFP2;
+ bios_3_scratch |= ATOM_S3_DFP2_ACTIVE;
+ bios_6_scratch |= ATOM_S6_ACC_REQ_DFP2;
+ } else {
+ DRM_DEBUG_KMS("DFP2 disconnected\n");
+ bios_0_scratch &= ~ATOM_S0_DFP2;
+ bios_3_scratch &= ~ATOM_S3_DFP2_ACTIVE;
+ bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP2;
+ }
+ }
+ if ((amdgpu_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) &&
+ (amdgpu_connector->devices & ATOM_DEVICE_DFP3_SUPPORT)) {
+ if (connected) {
+ DRM_DEBUG_KMS("DFP3 connected\n");
+ bios_0_scratch |= ATOM_S0_DFP3;
+ bios_3_scratch |= ATOM_S3_DFP3_ACTIVE;
+ bios_6_scratch |= ATOM_S6_ACC_REQ_DFP3;
+ } else {
+ DRM_DEBUG_KMS("DFP3 disconnected\n");
+ bios_0_scratch &= ~ATOM_S0_DFP3;
+ bios_3_scratch &= ~ATOM_S3_DFP3_ACTIVE;
+ bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP3;
+ }
+ }
+ if ((amdgpu_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) &&
+ (amdgpu_connector->devices & ATOM_DEVICE_DFP4_SUPPORT)) {
+ if (connected) {
+ DRM_DEBUG_KMS("DFP4 connected\n");
+ bios_0_scratch |= ATOM_S0_DFP4;
+ bios_3_scratch |= ATOM_S3_DFP4_ACTIVE;
+ bios_6_scratch |= ATOM_S6_ACC_REQ_DFP4;
+ } else {
+ DRM_DEBUG_KMS("DFP4 disconnected\n");
+ bios_0_scratch &= ~ATOM_S0_DFP4;
+ bios_3_scratch &= ~ATOM_S3_DFP4_ACTIVE;
+ bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP4;
+ }
+ }
+ if ((amdgpu_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) &&
+ (amdgpu_connector->devices & ATOM_DEVICE_DFP5_SUPPORT)) {
+ if (connected) {
+ DRM_DEBUG_KMS("DFP5 connected\n");
+ bios_0_scratch |= ATOM_S0_DFP5;
+ bios_3_scratch |= ATOM_S3_DFP5_ACTIVE;
+ bios_6_scratch |= ATOM_S6_ACC_REQ_DFP5;
+ } else {
+ DRM_DEBUG_KMS("DFP5 disconnected\n");
+ bios_0_scratch &= ~ATOM_S0_DFP5;
+ bios_3_scratch &= ~ATOM_S3_DFP5_ACTIVE;
+ bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP5;
+ }
+ }
+ if ((amdgpu_encoder->devices & ATOM_DEVICE_DFP6_SUPPORT) &&
+ (amdgpu_connector->devices & ATOM_DEVICE_DFP6_SUPPORT)) {
+ if (connected) {
+ DRM_DEBUG_KMS("DFP6 connected\n");
+ bios_0_scratch |= ATOM_S0_DFP6;
+ bios_3_scratch |= ATOM_S3_DFP6_ACTIVE;
+ bios_6_scratch |= ATOM_S6_ACC_REQ_DFP6;
+ } else {
+ DRM_DEBUG_KMS("DFP6 disconnected\n");
+ bios_0_scratch &= ~ATOM_S0_DFP6;
+ bios_3_scratch &= ~ATOM_S3_DFP6_ACTIVE;
+ bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP6;
+ }
+ }
+
+ WREG32(mmBIOS_SCRATCH_0, bios_0_scratch);
+ WREG32(mmBIOS_SCRATCH_3, bios_3_scratch);
+ WREG32(mmBIOS_SCRATCH_6, bios_6_scratch);
+}
+
+union lvds_info {
+ struct _ATOM_LVDS_INFO info;
+ struct _ATOM_LVDS_INFO_V12 info_12;
+};
+
+struct amdgpu_encoder_atom_dig *
+amdgpu_atombios_encoder_get_lcd_info(struct amdgpu_encoder *encoder)
+{
+ struct drm_device *dev = encoder->base.dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, LVDS_Info);
+ uint16_t data_offset, misc;
+ union lvds_info *lvds_info;
+ uint8_t frev, crev;
+ struct amdgpu_encoder_atom_dig *lvds = NULL;
+ int encoder_enum = (encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
+
+ if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset)) {
+ lvds_info =
+ (union lvds_info *)(mode_info->atom_context->bios + data_offset);
+ lvds =
+ kzalloc(sizeof(struct amdgpu_encoder_atom_dig), GFP_KERNEL);
+
+ if (!lvds)
+ return NULL;
+
+ lvds->native_mode.clock =
+ le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10;
+ lvds->native_mode.hdisplay =
+ le16_to_cpu(lvds_info->info.sLCDTiming.usHActive);
+ lvds->native_mode.vdisplay =
+ le16_to_cpu(lvds_info->info.sLCDTiming.usVActive);
+ lvds->native_mode.htotal = lvds->native_mode.hdisplay +
+ le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time);
+ lvds->native_mode.hsync_start = lvds->native_mode.hdisplay +
+ le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset);
+ lvds->native_mode.hsync_end = lvds->native_mode.hsync_start +
+ le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth);
+ lvds->native_mode.vtotal = lvds->native_mode.vdisplay +
+ le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time);
+ lvds->native_mode.vsync_start = lvds->native_mode.vdisplay +
+ le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset);
+ lvds->native_mode.vsync_end = lvds->native_mode.vsync_start +
+ le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
+ lvds->panel_pwr_delay =
+ le16_to_cpu(lvds_info->info.usOffDelayInMs);
+ lvds->lcd_misc = lvds_info->info.ucLVDS_Misc;
+
+ misc = le16_to_cpu(lvds_info->info.sLCDTiming.susModeMiscInfo.usAccess);
+ if (misc & ATOM_VSYNC_POLARITY)
+ lvds->native_mode.flags |= DRM_MODE_FLAG_NVSYNC;
+ if (misc & ATOM_HSYNC_POLARITY)
+ lvds->native_mode.flags |= DRM_MODE_FLAG_NHSYNC;
+ if (misc & ATOM_COMPOSITESYNC)
+ lvds->native_mode.flags |= DRM_MODE_FLAG_CSYNC;
+ if (misc & ATOM_INTERLACE)
+ lvds->native_mode.flags |= DRM_MODE_FLAG_INTERLACE;
+ if (misc & ATOM_DOUBLE_CLOCK_MODE)
+ lvds->native_mode.flags |= DRM_MODE_FLAG_DBLSCAN;
+
+ lvds->native_mode.width_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageHSize);
+ lvds->native_mode.height_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageVSize);
+
+ /* set crtc values */
+ drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
+
+ lvds->lcd_ss_id = lvds_info->info.ucSS_Id;
+
+ encoder->native_mode = lvds->native_mode;
+
+ if (encoder_enum == 2)
+ lvds->linkb = true;
+ else
+ lvds->linkb = false;
+
+ /* parse the lcd record table */
+ if (le16_to_cpu(lvds_info->info.usModePatchTableOffset)) {
+ ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record;
+ ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record;
+ bool bad_record = false;
+ u8 *record;
+
+ if ((frev == 1) && (crev < 2))
+ /* absolute */
+ record = (u8 *)(mode_info->atom_context->bios +
+ le16_to_cpu(lvds_info->info.usModePatchTableOffset));
+ else
+ /* relative */
+ record = (u8 *)(mode_info->atom_context->bios +
+ data_offset +
+ le16_to_cpu(lvds_info->info.usModePatchTableOffset));
+ while (*record != ATOM_RECORD_END_TYPE) {
+ switch (*record) {
+ case LCD_MODE_PATCH_RECORD_MODE_TYPE:
+ record += sizeof(ATOM_PATCH_RECORD_MODE);
+ break;
+ case LCD_RTS_RECORD_TYPE:
+ record += sizeof(ATOM_LCD_RTS_RECORD);
+ break;
+ case LCD_CAP_RECORD_TYPE:
+ record += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
+ break;
+ case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
+ fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
+ if (fake_edid_record->ucFakeEDIDLength) {
+ struct edid *edid;
+ int edid_size =
+ max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength);
+ edid = kmalloc(edid_size, GFP_KERNEL);
+ if (edid) {
+ memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0],
+ fake_edid_record->ucFakeEDIDLength);
+
+ if (drm_edid_is_valid(edid)) {
+ adev->mode_info.bios_hardcoded_edid = edid;
+ adev->mode_info.bios_hardcoded_edid_size = edid_size;
+ } else
+ kfree(edid);
+ }
+ }
+ record += fake_edid_record->ucFakeEDIDLength ?
+ fake_edid_record->ucFakeEDIDLength + 2 :
+ sizeof(ATOM_FAKE_EDID_PATCH_RECORD);
+ break;
+ case LCD_PANEL_RESOLUTION_RECORD_TYPE:
+ panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;
+ lvds->native_mode.width_mm = panel_res_record->usHSize;
+ lvds->native_mode.height_mm = panel_res_record->usVSize;
+ record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
+ break;
+ default:
+ DRM_ERROR("Bad LCD record %d\n", *record);
+ bad_record = true;
+ break;
+ }
+ if (bad_record)
+ break;
+ }
+ }
+ }
+ return lvds;
+}
+
+struct amdgpu_encoder_atom_dig *
+amdgpu_atombios_encoder_get_dig_info(struct amdgpu_encoder *amdgpu_encoder)
+{
+ int encoder_enum = (amdgpu_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
+ struct amdgpu_encoder_atom_dig *dig = kzalloc(sizeof(struct amdgpu_encoder_atom_dig), GFP_KERNEL);
+
+ if (!dig)
+ return NULL;
+
+ /* coherent mode by default */
+ dig->coherent_mode = true;
+ dig->dig_encoder = -1;
+
+ if (encoder_enum == 2)
+ dig->linkb = true;
+ else
+ dig->linkb = false;
+
+ return dig;
+}
+
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.h b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.h
new file mode 100644
index 000000000000..2bdec40515ce
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.h
@@ -0,0 +1,73 @@
+/*
+ * 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 __ATOMBIOS_ENCODER_H__
+#define __ATOMBIOS_ENCODER_H__
+
+u8
+amdgpu_atombios_encoder_get_backlight_level(struct amdgpu_encoder *amdgpu_encoder);
+void
+amdgpu_atombios_encoder_set_backlight_level(struct amdgpu_encoder *amdgpu_encoder,
+ u8 level);
+void amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder *amdgpu_encoder,
+ struct drm_connector *drm_connector);
+void
+amdgpu_atombios_encoder_fini_backlight(struct amdgpu_encoder *amdgpu_encoder);
+bool amdgpu_atombios_encoder_is_digital(struct drm_encoder *encoder);
+bool amdgpu_atombios_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+int amdgpu_atombios_encoder_get_encoder_mode(struct drm_encoder *encoder);
+void
+amdgpu_atombios_encoder_setup_dig_encoder(struct drm_encoder *encoder,
+ int action, int panel_mode);
+void
+amdgpu_atombios_encoder_setup_dig_transmitter(struct drm_encoder *encoder, int action,
+ uint8_t lane_num, uint8_t lane_set);
+bool
+amdgpu_atombios_encoder_set_edp_panel_power(struct drm_connector *connector,
+ int action);
+void
+amdgpu_atombios_encoder_dpms(struct drm_encoder *encoder, int mode);
+void
+amdgpu_atombios_encoder_set_crtc_source(struct drm_encoder *encoder);
+void
+amdgpu_atombios_encoder_init_dig(struct amdgpu_device *adev);
+enum drm_connector_status
+amdgpu_atombios_encoder_dac_detect(struct drm_encoder *encoder,
+ struct drm_connector *connector);
+enum drm_connector_status
+amdgpu_atombios_encoder_dig_detect(struct drm_encoder *encoder,
+ struct drm_connector *connector);
+void
+amdgpu_atombios_encoder_setup_ext_encoder_ddc(struct drm_encoder *encoder);
+void
+amdgpu_atombios_encoder_set_bios_scratch_regs(struct drm_connector *connector,
+ struct drm_encoder *encoder,
+ bool connected);
+struct amdgpu_encoder_atom_dig *
+amdgpu_atombios_encoder_get_lcd_info(struct amdgpu_encoder *encoder);
+struct amdgpu_encoder_atom_dig *
+amdgpu_atombios_encoder_get_dig_info(struct amdgpu_encoder *amdgpu_encoder);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c
new file mode 100644
index 000000000000..13cdb01e9b45
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2011 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: Alex Deucher
+ *
+ */
+#include <drm/drmP.h>
+#include <drm/amdgpu_drm.h>
+#include "amdgpu.h"
+#include "atom.h"
+#include "amdgpu_atombios.h"
+
+#define TARGET_HW_I2C_CLOCK 50
+
+/* these are a limitation of ProcessI2cChannelTransaction not the hw */
+#define ATOM_MAX_HW_I2C_WRITE 3
+#define ATOM_MAX_HW_I2C_READ 255
+
+static int amdgpu_atombios_i2c_process_i2c_ch(struct amdgpu_i2c_chan *chan,
+ u8 slave_addr, u8 flags,
+ u8 *buf, u8 num)
+{
+ struct drm_device *dev = chan->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction);
+ unsigned char *base;
+ u16 out = cpu_to_le16(0);
+ int r = 0;
+
+ memset(&args, 0, sizeof(args));
+
+ mutex_lock(&chan->mutex);
+
+ base = (unsigned char *)adev->mode_info.atom_context->scratch;
+
+ if (flags & HW_I2C_WRITE) {
+ if (num > ATOM_MAX_HW_I2C_WRITE) {
+ DRM_ERROR("hw i2c: tried to write too many bytes (%d vs 3)\n", num);
+ r = -EINVAL;
+ goto done;
+ }
+ if (buf == NULL)
+ args.ucRegIndex = 0;
+ else
+ args.ucRegIndex = buf[0];
+ if (num)
+ num--;
+ if (num)
+ memcpy(&out, &buf[1], num);
+ args.lpI2CDataOut = cpu_to_le16(out);
+ } else {
+ if (num > ATOM_MAX_HW_I2C_READ) {
+ DRM_ERROR("hw i2c: tried to read too many bytes (%d vs 255)\n", num);
+ r = -EINVAL;
+ goto done;
+ }
+ args.ucRegIndex = 0;
+ args.lpI2CDataOut = 0;
+ }
+
+ args.ucFlag = flags;
+ args.ucI2CSpeed = TARGET_HW_I2C_CLOCK;
+ args.ucTransBytes = num;
+ args.ucSlaveAddr = slave_addr << 1;
+ args.ucLineNumber = chan->rec.i2c_id;
+
+ amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ /* error */
+ if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) {
+ DRM_DEBUG_KMS("hw_i2c error\n");
+ r = -EIO;
+ goto done;
+ }
+
+ if (!(flags & HW_I2C_WRITE))
+ amdgpu_atombios_copy_swap(buf, base, num, false);
+
+done:
+ mutex_unlock(&chan->mutex);
+
+ return r;
+}
+
+int amdgpu_atombios_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct amdgpu_i2c_chan *i2c = i2c_get_adapdata(i2c_adap);
+ struct i2c_msg *p;
+ int i, remaining, current_count, buffer_offset, max_bytes, ret;
+ u8 flags;
+
+ /* check for bus probe */
+ p = &msgs[0];
+ if ((num == 1) && (p->len == 0)) {
+ ret = amdgpu_atombios_i2c_process_i2c_ch(i2c,
+ p->addr, HW_I2C_WRITE,
+ NULL, 0);
+ if (ret)
+ return ret;
+ else
+ return num;
+ }
+
+ for (i = 0; i < num; i++) {
+ p = &msgs[i];
+ remaining = p->len;
+ buffer_offset = 0;
+ /* max_bytes are a limitation of ProcessI2cChannelTransaction not the hw */
+ if (p->flags & I2C_M_RD) {
+ max_bytes = ATOM_MAX_HW_I2C_READ;
+ flags = HW_I2C_READ;
+ } else {
+ max_bytes = ATOM_MAX_HW_I2C_WRITE;
+ flags = HW_I2C_WRITE;
+ }
+ while (remaining) {
+ if (remaining > max_bytes)
+ current_count = max_bytes;
+ else
+ current_count = remaining;
+ ret = amdgpu_atombios_i2c_process_i2c_ch(i2c,
+ p->addr, flags,
+ &p->buf[buffer_offset], current_count);
+ if (ret)
+ return ret;
+ remaining -= current_count;
+ buffer_offset += current_count;
+ }
+ }
+
+ return num;
+}
+
+u32 amdgpu_atombios_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_i2c.h b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.h
new file mode 100644
index 000000000000..d6128d9de56e
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.h
@@ -0,0 +1,31 @@
+/*
+ * 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 __ATOMBIOS_I2C_H__
+#define __ATOMBIOS_I2C_H__
+
+int amdgpu_atombios_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num);
+u32 amdgpu_atombios_i2c_func(struct i2c_adapter *adap);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
new file mode 100644
index 000000000000..82e8d0730517
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
@@ -0,0 +1,6699 @@
+/*
+ * Copyright 2013 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/firmware.h>
+#include "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_pm.h"
+#include "amdgpu_ucode.h"
+#include "cikd.h"
+#include "amdgpu_dpm.h"
+#include "ci_dpm.h"
+#include "gfx_v7_0.h"
+#include "atom.h"
+#include <linux/seq_file.h>
+
+#include "smu/smu_7_0_1_d.h"
+#include "smu/smu_7_0_1_sh_mask.h"
+
+#include "dce/dce_8_0_d.h"
+#include "dce/dce_8_0_sh_mask.h"
+
+#include "bif/bif_4_1_d.h"
+#include "bif/bif_4_1_sh_mask.h"
+
+#include "gca/gfx_7_2_d.h"
+#include "gca/gfx_7_2_sh_mask.h"
+
+#include "gmc/gmc_7_1_d.h"
+#include "gmc/gmc_7_1_sh_mask.h"
+
+MODULE_FIRMWARE("radeon/bonaire_smc.bin");
+MODULE_FIRMWARE("radeon/hawaii_smc.bin");
+
+#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 SMC_RAM_END 0x40000
+
+#define VOLTAGE_SCALE 4
+#define VOLTAGE_VID_OFFSET_SCALE1 625
+#define VOLTAGE_VID_OFFSET_SCALE2 100
+
+static const struct ci_pt_defaults defaults_hawaii_xt =
+{
+ 1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0xB0000,
+ { 0x2E, 0x00, 0x00, 0x88, 0x00, 0x00, 0x72, 0x60, 0x51, 0xA7, 0x79, 0x6B, 0x90, 0xBD, 0x79 },
+ { 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
+};
+
+static const struct ci_pt_defaults defaults_hawaii_pro =
+{
+ 1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0x65062,
+ { 0x2E, 0x00, 0x00, 0x88, 0x00, 0x00, 0x72, 0x60, 0x51, 0xA7, 0x79, 0x6B, 0x90, 0xBD, 0x79 },
+ { 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
+};
+
+static const struct ci_pt_defaults defaults_bonaire_xt =
+{
+ 1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
+ { 0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61 },
+ { 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 }
+};
+
+static const struct ci_pt_defaults defaults_bonaire_pro =
+{
+ 1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x65062,
+ { 0x8C, 0x23F, 0x244, 0xA6, 0x83, 0x85, 0x86, 0x86, 0x83, 0xDB, 0xDB, 0xDA, 0x67, 0x60, 0x5F },
+ { 0x187, 0x193, 0x193, 0x1C7, 0x1D1, 0x1D1, 0x210, 0x219, 0x219, 0x266, 0x26C, 0x26C, 0x2C9, 0x2CB, 0x2CB }
+};
+
+static const struct ci_pt_defaults defaults_saturn_xt =
+{
+ 1, 0xF, 0xFD, 0x19, 5, 55, 0, 0x70000,
+ { 0x8C, 0x247, 0x249, 0xA6, 0x80, 0x81, 0x8B, 0x89, 0x86, 0xC9, 0xCA, 0xC9, 0x4D, 0x4D, 0x4D },
+ { 0x187, 0x187, 0x187, 0x1C7, 0x1C7, 0x1C7, 0x210, 0x210, 0x210, 0x266, 0x266, 0x266, 0x2C9, 0x2C9, 0x2C9 }
+};
+
+static const struct ci_pt_defaults defaults_saturn_pro =
+{
+ 1, 0xF, 0xFD, 0x19, 5, 55, 0, 0x30000,
+ { 0x96, 0x21D, 0x23B, 0xA1, 0x85, 0x87, 0x83, 0x84, 0x81, 0xE6, 0xE6, 0xE6, 0x71, 0x6A, 0x6A },
+ { 0x193, 0x19E, 0x19E, 0x1D2, 0x1DC, 0x1DC, 0x21A, 0x223, 0x223, 0x26E, 0x27E, 0x274, 0x2CF, 0x2D2, 0x2D2 }
+};
+
+static const struct ci_pt_config_reg didt_config_ci[] =
+{
+ { 0x10, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x10, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x10, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x10, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x11, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x11, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x11, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x11, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x12, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x12, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x12, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x12, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x2, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x2, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x2, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x1, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x1, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x0, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x30, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x30, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x30, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x30, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x31, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x31, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x31, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x31, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x32, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x32, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x32, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x32, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x22, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x22, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x22, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x21, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x21, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x20, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x50, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x50, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x50, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x50, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x51, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x51, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x51, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x51, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x52, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x52, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x52, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x52, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x42, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x42, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x42, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x41, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x41, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x40, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x70, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x70, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x70, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x70, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x71, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x71, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x71, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x71, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x72, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x72, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x72, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x72, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x62, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x62, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x62, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x61, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x61, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0x60, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
+ { 0xFFFFFFFF }
+};
+
+static u8 ci_get_memory_module_index(struct amdgpu_device *adev)
+{
+ return (u8) ((RREG32(mmBIOS_SCRATCH_4) >> 16) & 0xff);
+}
+
+#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
+
+static int ci_copy_and_switch_arb_sets(struct amdgpu_device *adev,
+ u32 arb_freq_src, u32 arb_freq_dest)
+{
+ u32 mc_arb_dram_timing;
+ u32 mc_arb_dram_timing2;
+ u32 burst_time;
+ u32 mc_cg_config;
+
+ switch (arb_freq_src) {
+ case MC_CG_ARB_FREQ_F0:
+ mc_arb_dram_timing = RREG32(mmMC_ARB_DRAM_TIMING);
+ mc_arb_dram_timing2 = RREG32(mmMC_ARB_DRAM_TIMING2);
+ burst_time = (RREG32(mmMC_ARB_BURST_TIME) & MC_ARB_BURST_TIME__STATE0_MASK) >>
+ MC_ARB_BURST_TIME__STATE0__SHIFT;
+ break;
+ case MC_CG_ARB_FREQ_F1:
+ mc_arb_dram_timing = RREG32(mmMC_ARB_DRAM_TIMING_1);
+ mc_arb_dram_timing2 = RREG32(mmMC_ARB_DRAM_TIMING2_1);
+ burst_time = (RREG32(mmMC_ARB_BURST_TIME) & MC_ARB_BURST_TIME__STATE1_MASK) >>
+ MC_ARB_BURST_TIME__STATE1__SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (arb_freq_dest) {
+ case MC_CG_ARB_FREQ_F0:
+ WREG32(mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing);
+ WREG32(mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
+ WREG32_P(mmMC_ARB_BURST_TIME, (burst_time << MC_ARB_BURST_TIME__STATE0__SHIFT),
+ ~MC_ARB_BURST_TIME__STATE0_MASK);
+ break;
+ case MC_CG_ARB_FREQ_F1:
+ WREG32(mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
+ WREG32(mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
+ WREG32_P(mmMC_ARB_BURST_TIME, (burst_time << MC_ARB_BURST_TIME__STATE1__SHIFT),
+ ~MC_ARB_BURST_TIME__STATE1_MASK);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mc_cg_config = RREG32(mmMC_CG_CONFIG) | 0x0000000F;
+ WREG32(mmMC_CG_CONFIG, mc_cg_config);
+ WREG32_P(mmMC_ARB_CG, (arb_freq_dest) << MC_ARB_CG__CG_ARB_REQ__SHIFT,
+ ~MC_ARB_CG__CG_ARB_REQ_MASK);
+
+ return 0;
+}
+
+static u8 ci_get_ddr3_mclk_frequency_ratio(u32 memory_clock)
+{
+ u8 mc_para_index;
+
+ if (memory_clock < 10000)
+ mc_para_index = 0;
+ else if (memory_clock >= 80000)
+ mc_para_index = 0x0f;
+ else
+ mc_para_index = (u8)((memory_clock - 10000) / 5000 + 1);
+ return mc_para_index;
+}
+
+static u8 ci_get_mclk_frequency_ratio(u32 memory_clock, bool strobe_mode)
+{
+ u8 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 = (u8)((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 = (u8)((memory_clock - 60000) / 5000);
+ }
+ return mc_para_index;
+}
+
+static void ci_trim_voltage_table_to_fit_state_table(struct amdgpu_device *adev,
+ u32 max_voltage_steps,
+ struct atom_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;
+}
+
+static int ci_get_std_voltage_value_sidd(struct amdgpu_device *adev,
+ struct atom_voltage_table_entry *voltage_table,
+ u16 *std_voltage_hi_sidd, u16 *std_voltage_lo_sidd);
+static int ci_set_power_limit(struct amdgpu_device *adev, u32 n);
+static int ci_set_overdrive_target_tdp(struct amdgpu_device *adev,
+ u32 target_tdp);
+static int ci_update_uvd_dpm(struct amdgpu_device *adev, bool gate);
+static void ci_dpm_set_dpm_funcs(struct amdgpu_device *adev);
+static void ci_dpm_set_irq_funcs(struct amdgpu_device *adev);
+
+static PPSMC_Result amdgpu_ci_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
+ PPSMC_Msg msg, u32 parameter);
+static void ci_thermal_start_smc_fan_control(struct amdgpu_device *adev);
+static void ci_fan_ctrl_set_default_mode(struct amdgpu_device *adev);
+
+static struct ci_power_info *ci_get_pi(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = adev->pm.dpm.priv;
+
+ return pi;
+}
+
+static struct ci_ps *ci_get_ps(struct amdgpu_ps *rps)
+{
+ struct ci_ps *ps = rps->ps_priv;
+
+ return ps;
+}
+
+static void ci_initialize_powertune_defaults(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ switch (adev->pdev->device) {
+ case 0x6649:
+ case 0x6650:
+ case 0x6651:
+ case 0x6658:
+ case 0x665C:
+ case 0x665D:
+ default:
+ pi->powertune_defaults = &defaults_bonaire_xt;
+ break;
+ case 0x6640:
+ case 0x6641:
+ case 0x6646:
+ case 0x6647:
+ pi->powertune_defaults = &defaults_saturn_xt;
+ break;
+ case 0x67B8:
+ case 0x67B0:
+ pi->powertune_defaults = &defaults_hawaii_xt;
+ break;
+ case 0x67BA:
+ case 0x67B1:
+ pi->powertune_defaults = &defaults_hawaii_pro;
+ break;
+ case 0x67A0:
+ case 0x67A1:
+ case 0x67A2:
+ case 0x67A8:
+ case 0x67A9:
+ case 0x67AA:
+ case 0x67B9:
+ case 0x67BE:
+ pi->powertune_defaults = &defaults_bonaire_xt;
+ break;
+ }
+
+ pi->dte_tj_offset = 0;
+
+ pi->caps_power_containment = true;
+ pi->caps_cac = false;
+ pi->caps_sq_ramping = false;
+ pi->caps_db_ramping = false;
+ pi->caps_td_ramping = false;
+ pi->caps_tcp_ramping = false;
+
+ if (pi->caps_power_containment) {
+ pi->caps_cac = true;
+ if (adev->asic_type == CHIP_HAWAII)
+ pi->enable_bapm_feature = false;
+ else
+ pi->enable_bapm_feature = true;
+ pi->enable_tdc_limit_feature = true;
+ pi->enable_pkg_pwr_tracking_feature = true;
+ }
+}
+
+static u8 ci_convert_to_vid(u16 vddc)
+{
+ return (6200 - (vddc * VOLTAGE_SCALE)) / 25;
+}
+
+static int ci_populate_bapm_vddc_vid_sidd(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u8 *hi_vid = pi->smc_powertune_table.BapmVddCVidHiSidd;
+ u8 *lo_vid = pi->smc_powertune_table.BapmVddCVidLoSidd;
+ u8 *hi2_vid = pi->smc_powertune_table.BapmVddCVidHiSidd2;
+ u32 i;
+
+ if (adev->pm.dpm.dyn_state.cac_leakage_table.entries == NULL)
+ return -EINVAL;
+ if (adev->pm.dpm.dyn_state.cac_leakage_table.count > 8)
+ return -EINVAL;
+ if (adev->pm.dpm.dyn_state.cac_leakage_table.count !=
+ adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count)
+ return -EINVAL;
+
+ for (i = 0; i < adev->pm.dpm.dyn_state.cac_leakage_table.count; i++) {
+ if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) {
+ lo_vid[i] = ci_convert_to_vid(adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc1);
+ hi_vid[i] = ci_convert_to_vid(adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc2);
+ hi2_vid[i] = ci_convert_to_vid(adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc3);
+ } else {
+ lo_vid[i] = ci_convert_to_vid(adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc);
+ hi_vid[i] = ci_convert_to_vid((u16)adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage);
+ }
+ }
+ return 0;
+}
+
+static int ci_populate_vddc_vid(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u8 *vid = pi->smc_powertune_table.VddCVid;
+ u32 i;
+
+ if (pi->vddc_voltage_table.count > 8)
+ return -EINVAL;
+
+ for (i = 0; i < pi->vddc_voltage_table.count; i++)
+ vid[i] = ci_convert_to_vid(pi->vddc_voltage_table.entries[i].value);
+
+ return 0;
+}
+
+static int ci_populate_svi_load_line(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
+
+ pi->smc_powertune_table.SviLoadLineEn = pt_defaults->svi_load_line_en;
+ pi->smc_powertune_table.SviLoadLineVddC = pt_defaults->svi_load_line_vddc;
+ pi->smc_powertune_table.SviLoadLineTrimVddC = 3;
+ pi->smc_powertune_table.SviLoadLineOffsetVddC = 0;
+
+ return 0;
+}
+
+static int ci_populate_tdc_limit(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
+ u16 tdc_limit;
+
+ tdc_limit = adev->pm.dpm.dyn_state.cac_tdp_table->tdc * 256;
+ pi->smc_powertune_table.TDC_VDDC_PkgLimit = cpu_to_be16(tdc_limit);
+ pi->smc_powertune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
+ pt_defaults->tdc_vddc_throttle_release_limit_perc;
+ pi->smc_powertune_table.TDC_MAWt = pt_defaults->tdc_mawt;
+
+ return 0;
+}
+
+static int ci_populate_dw8(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
+ int ret;
+
+ ret = amdgpu_ci_read_smc_sram_dword(adev,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU7_Firmware_Header, PmFuseTable) +
+ offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl),
+ (u32 *)&pi->smc_powertune_table.TdcWaterfallCtl,
+ pi->sram_end);
+ if (ret)
+ return -EINVAL;
+ else
+ pi->smc_powertune_table.TdcWaterfallCtl = pt_defaults->tdc_waterfall_ctl;
+
+ return 0;
+}
+
+static int ci_populate_fuzzy_fan(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ if ((adev->pm.dpm.fan.fan_output_sensitivity & (1 << 15)) ||
+ (adev->pm.dpm.fan.fan_output_sensitivity == 0))
+ adev->pm.dpm.fan.fan_output_sensitivity =
+ adev->pm.dpm.fan.default_fan_output_sensitivity;
+
+ pi->smc_powertune_table.FuzzyFan_PwmSetDelta =
+ cpu_to_be16(adev->pm.dpm.fan.fan_output_sensitivity);
+
+ return 0;
+}
+
+static int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u8 *hi_vid = pi->smc_powertune_table.BapmVddCVidHiSidd;
+ u8 *lo_vid = pi->smc_powertune_table.BapmVddCVidLoSidd;
+ int i, min, max;
+
+ min = max = hi_vid[0];
+ for (i = 0; i < 8; i++) {
+ if (0 != hi_vid[i]) {
+ if (min > hi_vid[i])
+ min = hi_vid[i];
+ if (max < hi_vid[i])
+ max = hi_vid[i];
+ }
+
+ if (0 != lo_vid[i]) {
+ if (min > lo_vid[i])
+ min = lo_vid[i];
+ if (max < lo_vid[i])
+ max = lo_vid[i];
+ }
+ }
+
+ if ((min == 0) || (max == 0))
+ return -EINVAL;
+ pi->smc_powertune_table.GnbLPMLMaxVid = (u8)max;
+ pi->smc_powertune_table.GnbLPMLMinVid = (u8)min;
+
+ return 0;
+}
+
+static int ci_populate_bapm_vddc_base_leakage_sidd(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u16 hi_sidd = pi->smc_powertune_table.BapmVddCBaseLeakageHiSidd;
+ u16 lo_sidd = pi->smc_powertune_table.BapmVddCBaseLeakageLoSidd;
+ struct amdgpu_cac_tdp_table *cac_tdp_table =
+ adev->pm.dpm.dyn_state.cac_tdp_table;
+
+ hi_sidd = cac_tdp_table->high_cac_leakage / 100 * 256;
+ lo_sidd = cac_tdp_table->low_cac_leakage / 100 * 256;
+
+ pi->smc_powertune_table.BapmVddCBaseLeakageHiSidd = cpu_to_be16(hi_sidd);
+ pi->smc_powertune_table.BapmVddCBaseLeakageLoSidd = cpu_to_be16(lo_sidd);
+
+ return 0;
+}
+
+static int ci_populate_bapm_parameters_in_dpm_table(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
+ SMU7_Discrete_DpmTable *dpm_table = &pi->smc_state_table;
+ struct amdgpu_cac_tdp_table *cac_tdp_table =
+ adev->pm.dpm.dyn_state.cac_tdp_table;
+ struct amdgpu_ppm_table *ppm = adev->pm.dpm.dyn_state.ppm_table;
+ int i, j, k;
+ const u16 *def1;
+ const u16 *def2;
+
+ dpm_table->DefaultTdp = cac_tdp_table->tdp * 256;
+ dpm_table->TargetTdp = cac_tdp_table->configurable_tdp * 256;
+
+ dpm_table->DTETjOffset = (u8)pi->dte_tj_offset;
+ dpm_table->GpuTjMax =
+ (u8)(pi->thermal_temp_setting.temperature_high / 1000);
+ dpm_table->GpuTjHyst = 8;
+
+ dpm_table->DTEAmbientTempBase = pt_defaults->dte_ambient_temp_base;
+
+ if (ppm) {
+ dpm_table->PPM_PkgPwrLimit = cpu_to_be16((u16)ppm->dgpu_tdp * 256 / 1000);
+ dpm_table->PPM_TemperatureLimit = cpu_to_be16((u16)ppm->tj_max * 256);
+ } else {
+ dpm_table->PPM_PkgPwrLimit = cpu_to_be16(0);
+ dpm_table->PPM_TemperatureLimit = cpu_to_be16(0);
+ }
+
+ dpm_table->BAPM_TEMP_GRADIENT = cpu_to_be32(pt_defaults->bapm_temp_gradient);
+ def1 = pt_defaults->bapmti_r;
+ def2 = pt_defaults->bapmti_rc;
+
+ for (i = 0; i < SMU7_DTE_ITERATIONS; i++) {
+ for (j = 0; j < SMU7_DTE_SOURCES; j++) {
+ for (k = 0; k < SMU7_DTE_SINKS; k++) {
+ dpm_table->BAPMTI_R[i][j][k] = cpu_to_be16(*def1);
+ dpm_table->BAPMTI_RC[i][j][k] = cpu_to_be16(*def2);
+ def1++;
+ def2++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int ci_populate_pm_base(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 pm_fuse_table_offset;
+ int ret;
+
+ if (pi->caps_power_containment) {
+ ret = amdgpu_ci_read_smc_sram_dword(adev,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU7_Firmware_Header, PmFuseTable),
+ &pm_fuse_table_offset, pi->sram_end);
+ if (ret)
+ return ret;
+ ret = ci_populate_bapm_vddc_vid_sidd(adev);
+ if (ret)
+ return ret;
+ ret = ci_populate_vddc_vid(adev);
+ if (ret)
+ return ret;
+ ret = ci_populate_svi_load_line(adev);
+ if (ret)
+ return ret;
+ ret = ci_populate_tdc_limit(adev);
+ if (ret)
+ return ret;
+ ret = ci_populate_dw8(adev);
+ if (ret)
+ return ret;
+ ret = ci_populate_fuzzy_fan(adev);
+ if (ret)
+ return ret;
+ ret = ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(adev);
+ if (ret)
+ return ret;
+ ret = ci_populate_bapm_vddc_base_leakage_sidd(adev);
+ if (ret)
+ return ret;
+ ret = amdgpu_ci_copy_bytes_to_smc(adev, pm_fuse_table_offset,
+ (u8 *)&pi->smc_powertune_table,
+ sizeof(SMU7_Discrete_PmFuses), pi->sram_end);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ci_do_enable_didt(struct amdgpu_device *adev, const bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 data;
+
+ if (pi->caps_sq_ramping) {
+ data = RREG32_DIDT(ixDIDT_SQ_CTRL0);
+ if (enable)
+ data |= DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK;
+ else
+ data &= ~DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK;
+ WREG32_DIDT(ixDIDT_SQ_CTRL0, data);
+ }
+
+ if (pi->caps_db_ramping) {
+ data = RREG32_DIDT(ixDIDT_DB_CTRL0);
+ if (enable)
+ data |= DIDT_DB_CTRL0__DIDT_CTRL_EN_MASK;
+ else
+ data &= ~DIDT_DB_CTRL0__DIDT_CTRL_EN_MASK;
+ WREG32_DIDT(ixDIDT_DB_CTRL0, data);
+ }
+
+ if (pi->caps_td_ramping) {
+ data = RREG32_DIDT(ixDIDT_TD_CTRL0);
+ if (enable)
+ data |= DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK;
+ else
+ data &= ~DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK;
+ WREG32_DIDT(ixDIDT_TD_CTRL0, data);
+ }
+
+ if (pi->caps_tcp_ramping) {
+ data = RREG32_DIDT(ixDIDT_TCP_CTRL0);
+ if (enable)
+ data |= DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK;
+ else
+ data &= ~DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK;
+ WREG32_DIDT(ixDIDT_TCP_CTRL0, data);
+ }
+}
+
+static int ci_program_pt_config_registers(struct amdgpu_device *adev,
+ const struct ci_pt_config_reg *cac_config_regs)
+{
+ const struct ci_pt_config_reg *config_regs = cac_config_regs;
+ u32 data;
+ u32 cache = 0;
+
+ if (config_regs == NULL)
+ return -EINVAL;
+
+ while (config_regs->offset != 0xFFFFFFFF) {
+ if (config_regs->type == CISLANDS_CONFIGREG_CACHE) {
+ cache |= ((config_regs->value << config_regs->shift) & config_regs->mask);
+ } else {
+ switch (config_regs->type) {
+ case CISLANDS_CONFIGREG_SMC_IND:
+ data = RREG32_SMC(config_regs->offset);
+ break;
+ case CISLANDS_CONFIGREG_DIDT_IND:
+ data = RREG32_DIDT(config_regs->offset);
+ break;
+ default:
+ data = RREG32(config_regs->offset);
+ break;
+ }
+
+ data &= ~config_regs->mask;
+ data |= ((config_regs->value << config_regs->shift) & config_regs->mask);
+ data |= cache;
+
+ switch (config_regs->type) {
+ case CISLANDS_CONFIGREG_SMC_IND:
+ WREG32_SMC(config_regs->offset, data);
+ break;
+ case CISLANDS_CONFIGREG_DIDT_IND:
+ WREG32_DIDT(config_regs->offset, data);
+ break;
+ default:
+ WREG32(config_regs->offset, data);
+ break;
+ }
+ cache = 0;
+ }
+ config_regs++;
+ }
+ return 0;
+}
+
+static int ci_enable_didt(struct amdgpu_device *adev, bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ int ret;
+
+ if (pi->caps_sq_ramping || pi->caps_db_ramping ||
+ pi->caps_td_ramping || pi->caps_tcp_ramping) {
+ gfx_v7_0_enter_rlc_safe_mode(adev);
+
+ if (enable) {
+ ret = ci_program_pt_config_registers(adev, didt_config_ci);
+ if (ret) {
+ gfx_v7_0_exit_rlc_safe_mode(adev);
+ return ret;
+ }
+ }
+
+ ci_do_enable_didt(adev, enable);
+
+ gfx_v7_0_exit_rlc_safe_mode(adev);
+ }
+
+ return 0;
+}
+
+static int ci_enable_power_containment(struct amdgpu_device *adev, bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ PPSMC_Result smc_result;
+ int ret = 0;
+
+ if (enable) {
+ pi->power_containment_features = 0;
+ if (pi->caps_power_containment) {
+ if (pi->enable_bapm_feature) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_EnableDTE);
+ if (smc_result != PPSMC_Result_OK)
+ ret = -EINVAL;
+ else
+ pi->power_containment_features |= POWERCONTAINMENT_FEATURE_BAPM;
+ }
+
+ if (pi->enable_tdc_limit_feature) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_TDCLimitEnable);
+ if (smc_result != PPSMC_Result_OK)
+ ret = -EINVAL;
+ else
+ pi->power_containment_features |= POWERCONTAINMENT_FEATURE_TDCLimit;
+ }
+
+ if (pi->enable_pkg_pwr_tracking_feature) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_PkgPwrLimitEnable);
+ if (smc_result != PPSMC_Result_OK) {
+ ret = -EINVAL;
+ } else {
+ struct amdgpu_cac_tdp_table *cac_tdp_table =
+ adev->pm.dpm.dyn_state.cac_tdp_table;
+ u32 default_pwr_limit =
+ (u32)(cac_tdp_table->maximum_power_delivery_limit * 256);
+
+ pi->power_containment_features |= POWERCONTAINMENT_FEATURE_PkgPwrLimit;
+
+ ci_set_power_limit(adev, default_pwr_limit);
+ }
+ }
+ }
+ } else {
+ if (pi->caps_power_containment && pi->power_containment_features) {
+ if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_TDCLimit)
+ amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_TDCLimitDisable);
+
+ if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_BAPM)
+ amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_DisableDTE);
+
+ if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_PkgPwrLimit)
+ amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_PkgPwrLimitDisable);
+ pi->power_containment_features = 0;
+ }
+ }
+
+ return ret;
+}
+
+static int ci_enable_smc_cac(struct amdgpu_device *adev, bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ PPSMC_Result smc_result;
+ int ret = 0;
+
+ if (pi->caps_cac) {
+ if (enable) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_EnableCac);
+ if (smc_result != PPSMC_Result_OK) {
+ ret = -EINVAL;
+ pi->cac_enabled = false;
+ } else {
+ pi->cac_enabled = true;
+ }
+ } else if (pi->cac_enabled) {
+ amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_DisableCac);
+ pi->cac_enabled = false;
+ }
+ }
+
+ return ret;
+}
+
+static int ci_enable_thermal_based_sclk_dpm(struct amdgpu_device *adev,
+ bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ PPSMC_Result smc_result = PPSMC_Result_OK;
+
+ if (pi->thermal_sclk_dpm_enabled) {
+ if (enable)
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_ENABLE_THERMAL_DPM);
+ else
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_DISABLE_THERMAL_DPM);
+ }
+
+ if (smc_result == PPSMC_Result_OK)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static int ci_power_control_set_level(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct amdgpu_cac_tdp_table *cac_tdp_table =
+ adev->pm.dpm.dyn_state.cac_tdp_table;
+ s32 adjust_percent;
+ s32 target_tdp;
+ int ret = 0;
+ bool adjust_polarity = false; /* ??? */
+
+ if (pi->caps_power_containment) {
+ adjust_percent = adjust_polarity ?
+ adev->pm.dpm.tdp_adjustment : (-1 * adev->pm.dpm.tdp_adjustment);
+ target_tdp = ((100 + adjust_percent) *
+ (s32)cac_tdp_table->configurable_tdp) / 100;
+
+ ret = ci_set_overdrive_target_tdp(adev, (u32)target_tdp);
+ }
+
+ return ret;
+}
+
+static void ci_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ if (pi->uvd_power_gated == gate)
+ return;
+
+ pi->uvd_power_gated = gate;
+
+ ci_update_uvd_dpm(adev, gate);
+}
+
+static bool ci_dpm_vblank_too_short(struct amdgpu_device *adev)
+{
+ u32 vblank_time = amdgpu_dpm_get_vblank_time(adev);
+ u32 switch_limit = adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 300;
+
+ if (vblank_time < switch_limit)
+ return true;
+ else
+ return false;
+
+}
+
+static void ci_apply_state_adjust_rules(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps)
+{
+ struct ci_ps *ps = ci_get_ps(rps);
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct amdgpu_clock_and_voltage_limits *max_limits;
+ bool disable_mclk_switching;
+ u32 sclk, mclk;
+ int i;
+
+ if (rps->vce_active) {
+ rps->evclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].evclk;
+ rps->ecclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].ecclk;
+ } else {
+ rps->evclk = 0;
+ rps->ecclk = 0;
+ }
+
+ if ((adev->pm.dpm.new_active_crtc_count > 1) ||
+ ci_dpm_vblank_too_short(adev))
+ disable_mclk_switching = true;
+ else
+ disable_mclk_switching = false;
+
+ if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)
+ pi->battery_state = true;
+ else
+ pi->battery_state = false;
+
+ if (adev->pm.dpm.ac_power)
+ max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+ else
+ max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
+
+ if (adev->pm.dpm.ac_power == false) {
+ for (i = 0; i < ps->performance_level_count; i++) {
+ if (ps->performance_levels[i].mclk > max_limits->mclk)
+ ps->performance_levels[i].mclk = max_limits->mclk;
+ if (ps->performance_levels[i].sclk > max_limits->sclk)
+ ps->performance_levels[i].sclk = max_limits->sclk;
+ }
+ }
+
+ /* XXX validate the min clocks required for display */
+
+ if (disable_mclk_switching) {
+ mclk = ps->performance_levels[ps->performance_level_count - 1].mclk;
+ sclk = ps->performance_levels[0].sclk;
+ } else {
+ mclk = ps->performance_levels[0].mclk;
+ sclk = ps->performance_levels[0].sclk;
+ }
+
+ if (rps->vce_active) {
+ if (sclk < adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].sclk)
+ sclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].sclk;
+ if (mclk < adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].mclk)
+ mclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].mclk;
+ }
+
+ ps->performance_levels[0].sclk = sclk;
+ ps->performance_levels[0].mclk = mclk;
+
+ if (ps->performance_levels[1].sclk < ps->performance_levels[0].sclk)
+ ps->performance_levels[1].sclk = ps->performance_levels[0].sclk;
+
+ if (disable_mclk_switching) {
+ if (ps->performance_levels[0].mclk < ps->performance_levels[1].mclk)
+ ps->performance_levels[0].mclk = ps->performance_levels[1].mclk;
+ } else {
+ if (ps->performance_levels[1].mclk < ps->performance_levels[0].mclk)
+ ps->performance_levels[1].mclk = ps->performance_levels[0].mclk;
+ }
+}
+
+static int ci_thermal_set_temperature_range(struct amdgpu_device *adev,
+ int min_temp, int max_temp)
+{
+ int low_temp = 0 * 1000;
+ int high_temp = 255 * 1000;
+ u32 tmp;
+
+ if (low_temp < min_temp)
+ low_temp = min_temp;
+ if (high_temp > max_temp)
+ high_temp = max_temp;
+ if (high_temp < low_temp) {
+ DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
+ return -EINVAL;
+ }
+
+ tmp = RREG32_SMC(ixCG_THERMAL_INT);
+ tmp &= ~(CG_THERMAL_INT__DIG_THERM_INTH_MASK | CG_THERMAL_INT__DIG_THERM_INTL_MASK);
+ tmp |= ((high_temp / 1000) << CG_THERMAL_INT__DIG_THERM_INTH__SHIFT) |
+ ((low_temp / 1000)) << CG_THERMAL_INT__DIG_THERM_INTL__SHIFT;
+ WREG32_SMC(ixCG_THERMAL_INT, tmp);
+
+#if 0
+ /* XXX: need to figure out how to handle this properly */
+ tmp = RREG32_SMC(ixCG_THERMAL_CTRL);
+ tmp &= DIG_THERM_DPM_MASK;
+ tmp |= DIG_THERM_DPM(high_temp / 1000);
+ WREG32_SMC(ixCG_THERMAL_CTRL, tmp);
+#endif
+
+ adev->pm.dpm.thermal.min_temp = low_temp;
+ adev->pm.dpm.thermal.max_temp = high_temp;
+ return 0;
+}
+
+static int ci_thermal_enable_alert(struct amdgpu_device *adev,
+ bool enable)
+{
+ u32 thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
+ PPSMC_Result result;
+
+ if (enable) {
+ thermal_int &= ~(CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK |
+ CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK);
+ WREG32_SMC(ixCG_THERMAL_INT, thermal_int);
+ result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_Thermal_Cntl_Enable);
+ if (result != PPSMC_Result_OK) {
+ DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+ return -EINVAL;
+ }
+ } else {
+ thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK |
+ CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+ WREG32_SMC(ixCG_THERMAL_INT, thermal_int);
+ result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_Thermal_Cntl_Disable);
+ if (result != PPSMC_Result_OK) {
+ DRM_DEBUG_KMS("Could not disable thermal interrupts.\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void ci_fan_ctrl_set_static_mode(struct amdgpu_device *adev, u32 mode)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 tmp;
+
+ if (pi->fan_ctrl_is_in_default_mode) {
+ tmp = (RREG32_SMC(ixCG_FDO_CTRL2) & CG_FDO_CTRL2__FDO_PWM_MODE_MASK)
+ >> CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT;
+ pi->fan_ctrl_default_mode = tmp;
+ tmp = (RREG32_SMC(ixCG_FDO_CTRL2) & CG_FDO_CTRL2__TMIN_MASK)
+ >> CG_FDO_CTRL2__TMIN__SHIFT;
+ pi->t_min = tmp;
+ pi->fan_ctrl_is_in_default_mode = false;
+ }
+
+ tmp = RREG32_SMC(ixCG_FDO_CTRL2) & ~CG_FDO_CTRL2__TMIN_MASK;
+ tmp |= 0 << CG_FDO_CTRL2__TMIN__SHIFT;
+ WREG32_SMC(ixCG_FDO_CTRL2, tmp);
+
+ tmp = RREG32_SMC(ixCG_FDO_CTRL2) & ~CG_FDO_CTRL2__FDO_PWM_MODE_MASK;
+ tmp |= mode << CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT;
+ WREG32_SMC(ixCG_FDO_CTRL2, tmp);
+}
+
+static int ci_thermal_setup_fan_table(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ SMU7_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
+ u32 duty100;
+ u32 t_diff1, t_diff2, pwm_diff1, pwm_diff2;
+ u16 fdo_min, slope1, slope2;
+ u32 reference_clock, tmp;
+ int ret;
+ u64 tmp64;
+
+ if (!pi->fan_table_start) {
+ adev->pm.dpm.fan.ucode_fan_control = false;
+ return 0;
+ }
+
+ duty100 = (RREG32_SMC(ixCG_FDO_CTRL1) & CG_FDO_CTRL1__FMAX_DUTY100_MASK)
+ >> CG_FDO_CTRL1__FMAX_DUTY100__SHIFT;
+
+ if (duty100 == 0) {
+ adev->pm.dpm.fan.ucode_fan_control = false;
+ return 0;
+ }
+
+ tmp64 = (u64)adev->pm.dpm.fan.pwm_min * duty100;
+ do_div(tmp64, 10000);
+ fdo_min = (u16)tmp64;
+
+ t_diff1 = adev->pm.dpm.fan.t_med - adev->pm.dpm.fan.t_min;
+ t_diff2 = adev->pm.dpm.fan.t_high - adev->pm.dpm.fan.t_med;
+
+ pwm_diff1 = adev->pm.dpm.fan.pwm_med - adev->pm.dpm.fan.pwm_min;
+ pwm_diff2 = adev->pm.dpm.fan.pwm_high - adev->pm.dpm.fan.pwm_med;
+
+ slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
+ slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+
+ fan_table.TempMin = cpu_to_be16((50 + adev->pm.dpm.fan.t_min) / 100);
+ fan_table.TempMed = cpu_to_be16((50 + adev->pm.dpm.fan.t_med) / 100);
+ fan_table.TempMax = cpu_to_be16((50 + adev->pm.dpm.fan.t_max) / 100);
+
+ fan_table.Slope1 = cpu_to_be16(slope1);
+ fan_table.Slope2 = cpu_to_be16(slope2);
+
+ fan_table.FdoMin = cpu_to_be16(fdo_min);
+
+ fan_table.HystDown = cpu_to_be16(adev->pm.dpm.fan.t_hyst);
+
+ fan_table.HystUp = cpu_to_be16(1);
+
+ fan_table.HystSlope = cpu_to_be16(1);
+
+ fan_table.TempRespLim = cpu_to_be16(5);
+
+ reference_clock = amdgpu_asic_get_xclk(adev);
+
+ fan_table.RefreshPeriod = cpu_to_be32((adev->pm.dpm.fan.cycle_delay *
+ reference_clock) / 1600);
+
+ fan_table.FdoMax = cpu_to_be16((u16)duty100);
+
+ tmp = (RREG32_SMC(ixCG_MULT_THERMAL_CTRL) & CG_MULT_THERMAL_CTRL__TEMP_SEL_MASK)
+ >> CG_MULT_THERMAL_CTRL__TEMP_SEL__SHIFT;
+ fan_table.TempSrc = (uint8_t)tmp;
+
+ ret = amdgpu_ci_copy_bytes_to_smc(adev,
+ pi->fan_table_start,
+ (u8 *)(&fan_table),
+ sizeof(fan_table),
+ pi->sram_end);
+
+ if (ret) {
+ DRM_ERROR("Failed to load fan table to the SMC.");
+ adev->pm.dpm.fan.ucode_fan_control = false;
+ }
+
+ return 0;
+}
+
+static int ci_fan_ctrl_start_smc_fan_control(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ PPSMC_Result ret;
+
+ if (pi->caps_od_fuzzy_fan_control_support) {
+ ret = amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_StartFanControl,
+ FAN_CONTROL_FUZZY);
+ if (ret != PPSMC_Result_OK)
+ return -EINVAL;
+ ret = amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetFanPwmMax,
+ adev->pm.dpm.fan.default_max_fan_pwm);
+ if (ret != PPSMC_Result_OK)
+ return -EINVAL;
+ } else {
+ ret = amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_StartFanControl,
+ FAN_CONTROL_TABLE);
+ if (ret != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ pi->fan_is_controlled_by_smc = true;
+ return 0;
+}
+
+
+static int ci_fan_ctrl_stop_smc_fan_control(struct amdgpu_device *adev)
+{
+ PPSMC_Result ret;
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ ret = amdgpu_ci_send_msg_to_smc(adev, PPSMC_StopFanControl);
+ if (ret == PPSMC_Result_OK) {
+ pi->fan_is_controlled_by_smc = false;
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+}
+
+static int ci_dpm_get_fan_speed_percent(struct amdgpu_device *adev,
+ u32 *speed)
+{
+ u32 duty, duty100;
+ u64 tmp64;
+
+ if (adev->pm.no_fan)
+ return -ENOENT;
+
+ duty100 = (RREG32_SMC(ixCG_FDO_CTRL1) & CG_FDO_CTRL1__FMAX_DUTY100_MASK)
+ >> CG_FDO_CTRL1__FMAX_DUTY100__SHIFT;
+ duty = (RREG32_SMC(ixCG_THERMAL_STATUS) & CG_THERMAL_STATUS__FDO_PWM_DUTY_MASK)
+ >> CG_THERMAL_STATUS__FDO_PWM_DUTY__SHIFT;
+
+ if (duty100 == 0)
+ return -EINVAL;
+
+ tmp64 = (u64)duty * 100;
+ do_div(tmp64, duty100);
+ *speed = (u32)tmp64;
+
+ if (*speed > 100)
+ *speed = 100;
+
+ return 0;
+}
+
+static int ci_dpm_set_fan_speed_percent(struct amdgpu_device *adev,
+ u32 speed)
+{
+ u32 tmp;
+ u32 duty, duty100;
+ u64 tmp64;
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ if (adev->pm.no_fan)
+ return -ENOENT;
+
+ if (pi->fan_is_controlled_by_smc)
+ return -EINVAL;
+
+ if (speed > 100)
+ return -EINVAL;
+
+ duty100 = (RREG32_SMC(ixCG_FDO_CTRL1) & CG_FDO_CTRL1__FMAX_DUTY100_MASK)
+ >> CG_FDO_CTRL1__FMAX_DUTY100__SHIFT;
+
+ if (duty100 == 0)
+ return -EINVAL;
+
+ tmp64 = (u64)speed * duty100;
+ do_div(tmp64, 100);
+ duty = (u32)tmp64;
+
+ tmp = RREG32_SMC(ixCG_FDO_CTRL0) & ~CG_FDO_CTRL0__FDO_STATIC_DUTY_MASK;
+ tmp |= duty << CG_FDO_CTRL0__FDO_STATIC_DUTY__SHIFT;
+ WREG32_SMC(ixCG_FDO_CTRL0, tmp);
+
+ return 0;
+}
+
+static void ci_dpm_set_fan_control_mode(struct amdgpu_device *adev, u32 mode)
+{
+ if (mode) {
+ /* stop auto-manage */
+ if (adev->pm.dpm.fan.ucode_fan_control)
+ ci_fan_ctrl_stop_smc_fan_control(adev);
+ ci_fan_ctrl_set_static_mode(adev, mode);
+ } else {
+ /* restart auto-manage */
+ if (adev->pm.dpm.fan.ucode_fan_control)
+ ci_thermal_start_smc_fan_control(adev);
+ else
+ ci_fan_ctrl_set_default_mode(adev);
+ }
+}
+
+static u32 ci_dpm_get_fan_control_mode(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 tmp;
+
+ if (pi->fan_is_controlled_by_smc)
+ return 0;
+
+ tmp = RREG32_SMC(ixCG_FDO_CTRL2) & CG_FDO_CTRL2__FDO_PWM_MODE_MASK;
+ return (tmp >> CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT);
+}
+
+#if 0
+static int ci_fan_ctrl_get_fan_speed_rpm(struct amdgpu_device *adev,
+ u32 *speed)
+{
+ u32 tach_period;
+ u32 xclk = amdgpu_asic_get_xclk(adev);
+
+ if (adev->pm.no_fan)
+ return -ENOENT;
+
+ if (adev->pm.fan_pulses_per_revolution == 0)
+ return -ENOENT;
+
+ tach_period = (RREG32_SMC(ixCG_TACH_STATUS) & CG_TACH_STATUS__TACH_PERIOD_MASK)
+ >> CG_TACH_STATUS__TACH_PERIOD__SHIFT;
+ if (tach_period == 0)
+ return -ENOENT;
+
+ *speed = 60 * xclk * 10000 / tach_period;
+
+ return 0;
+}
+
+static int ci_fan_ctrl_set_fan_speed_rpm(struct amdgpu_device *adev,
+ u32 speed)
+{
+ u32 tach_period, tmp;
+ u32 xclk = amdgpu_asic_get_xclk(adev);
+
+ if (adev->pm.no_fan)
+ return -ENOENT;
+
+ if (adev->pm.fan_pulses_per_revolution == 0)
+ return -ENOENT;
+
+ if ((speed < adev->pm.fan_min_rpm) ||
+ (speed > adev->pm.fan_max_rpm))
+ return -EINVAL;
+
+ if (adev->pm.dpm.fan.ucode_fan_control)
+ ci_fan_ctrl_stop_smc_fan_control(adev);
+
+ tach_period = 60 * xclk * 10000 / (8 * speed);
+ tmp = RREG32_SMC(ixCG_TACH_CTRL) & ~CG_TACH_CTRL__TARGET_PERIOD_MASK;
+ tmp |= tach_period << CG_TACH_CTRL__TARGET_PERIOD__SHIFT;
+ WREG32_SMC(CG_TACH_CTRL, tmp);
+
+ ci_fan_ctrl_set_static_mode(adev, FDO_PWM_MODE_STATIC_RPM);
+
+ return 0;
+}
+#endif
+
+static void ci_fan_ctrl_set_default_mode(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 tmp;
+
+ if (!pi->fan_ctrl_is_in_default_mode) {
+ tmp = RREG32_SMC(ixCG_FDO_CTRL2) & ~CG_FDO_CTRL2__FDO_PWM_MODE_MASK;
+ tmp |= pi->fan_ctrl_default_mode << CG_FDO_CTRL2__FDO_PWM_MODE__SHIFT;
+ WREG32_SMC(ixCG_FDO_CTRL2, tmp);
+
+ tmp = RREG32_SMC(ixCG_FDO_CTRL2) & ~CG_FDO_CTRL2__TMIN_MASK;
+ tmp |= pi->t_min << CG_FDO_CTRL2__TMIN__SHIFT;
+ WREG32_SMC(ixCG_FDO_CTRL2, tmp);
+ pi->fan_ctrl_is_in_default_mode = true;
+ }
+}
+
+static void ci_thermal_start_smc_fan_control(struct amdgpu_device *adev)
+{
+ if (adev->pm.dpm.fan.ucode_fan_control) {
+ ci_fan_ctrl_start_smc_fan_control(adev);
+ ci_fan_ctrl_set_static_mode(adev, FDO_PWM_MODE_STATIC);
+ }
+}
+
+static void ci_thermal_initialize(struct amdgpu_device *adev)
+{
+ u32 tmp;
+
+ if (adev->pm.fan_pulses_per_revolution) {
+ tmp = RREG32_SMC(ixCG_TACH_CTRL) & ~CG_TACH_CTRL__EDGE_PER_REV_MASK;
+ tmp |= (adev->pm.fan_pulses_per_revolution - 1)
+ << CG_TACH_CTRL__EDGE_PER_REV__SHIFT;
+ WREG32_SMC(ixCG_TACH_CTRL, tmp);
+ }
+
+ tmp = RREG32_SMC(ixCG_FDO_CTRL2) & ~CG_FDO_CTRL2__TACH_PWM_RESP_RATE_MASK;
+ tmp |= 0x28 << CG_FDO_CTRL2__TACH_PWM_RESP_RATE__SHIFT;
+ WREG32_SMC(ixCG_FDO_CTRL2, tmp);
+}
+
+static int ci_thermal_start_thermal_controller(struct amdgpu_device *adev)
+{
+ int ret;
+
+ ci_thermal_initialize(adev);
+ ret = ci_thermal_set_temperature_range(adev, CISLANDS_TEMP_RANGE_MIN, CISLANDS_TEMP_RANGE_MAX);
+ if (ret)
+ return ret;
+ ret = ci_thermal_enable_alert(adev, true);
+ if (ret)
+ return ret;
+ if (adev->pm.dpm.fan.ucode_fan_control) {
+ ret = ci_thermal_setup_fan_table(adev);
+ if (ret)
+ return ret;
+ ci_thermal_start_smc_fan_control(adev);
+ }
+
+ return 0;
+}
+
+static void ci_thermal_stop_thermal_controller(struct amdgpu_device *adev)
+{
+ if (!adev->pm.no_fan)
+ 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)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ return amdgpu_ci_read_smc_sram_dword(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)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ return amdgpu_ci_write_smc_sram_dword(adev,
+ pi->soft_regs_start + reg_offset,
+ value, pi->sram_end);
+}
+
+static void ci_init_fps_limits(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ SMU7_Discrete_DpmTable *table = &pi->smc_state_table;
+
+ if (pi->caps_fps) {
+ u16 tmp;
+
+ tmp = 45;
+ table->FpsHighT = cpu_to_be16(tmp);
+
+ tmp = 30;
+ table->FpsLowT = cpu_to_be16(tmp);
+ }
+}
+
+static int ci_update_sclk_t(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ int ret = 0;
+ u32 low_sclk_interrupt_t = 0;
+
+ if (pi->caps_sclk_throttle_low_notification) {
+ low_sclk_interrupt_t = cpu_to_be32(pi->low_sclk_interrupt_t);
+
+ ret = amdgpu_ci_copy_bytes_to_smc(adev,
+ pi->dpm_table_start +
+ offsetof(SMU7_Discrete_DpmTable, LowSclkInterruptT),
+ (u8 *)&low_sclk_interrupt_t,
+ sizeof(u32), pi->sram_end);
+
+ }
+
+ return ret;
+}
+
+static void ci_get_leakage_voltages(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u16 leakage_id, virtual_voltage_id;
+ u16 vddc, vddci;
+ int i;
+
+ pi->vddc_leakage.count = 0;
+ pi->vddci_leakage.count = 0;
+
+ if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) {
+ for (i = 0; i < CISLANDS_MAX_LEAKAGE_COUNT; i++) {
+ virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
+ if (amdgpu_atombios_get_voltage_evv(adev, virtual_voltage_id, &vddc) != 0)
+ continue;
+ if (vddc != 0 && vddc != virtual_voltage_id) {
+ pi->vddc_leakage.actual_voltage[pi->vddc_leakage.count] = vddc;
+ pi->vddc_leakage.leakage_id[pi->vddc_leakage.count] = virtual_voltage_id;
+ pi->vddc_leakage.count++;
+ }
+ }
+ } else if (amdgpu_atombios_get_leakage_id_from_vbios(adev, &leakage_id) == 0) {
+ for (i = 0; i < CISLANDS_MAX_LEAKAGE_COUNT; i++) {
+ virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
+ if (amdgpu_atombios_get_leakage_vddc_based_on_leakage_params(adev, &vddc, &vddci,
+ virtual_voltage_id,
+ leakage_id) == 0) {
+ if (vddc != 0 && vddc != virtual_voltage_id) {
+ pi->vddc_leakage.actual_voltage[pi->vddc_leakage.count] = vddc;
+ pi->vddc_leakage.leakage_id[pi->vddc_leakage.count] = virtual_voltage_id;
+ pi->vddc_leakage.count++;
+ }
+ if (vddci != 0 && vddci != virtual_voltage_id) {
+ pi->vddci_leakage.actual_voltage[pi->vddci_leakage.count] = vddci;
+ pi->vddci_leakage.leakage_id[pi->vddci_leakage.count] = virtual_voltage_id;
+ pi->vddci_leakage.count++;
+ }
+ }
+ }
+ }
+}
+
+static void ci_set_dpm_event_sources(struct amdgpu_device *adev, u32 sources)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ bool want_thermal_protection;
+ enum amdgpu_dpm_event_src dpm_event_src;
+ u32 tmp;
+
+ switch (sources) {
+ case 0:
+ default:
+ want_thermal_protection = false;
+ break;
+ case (1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL):
+ want_thermal_protection = true;
+ dpm_event_src = AMDGPU_DPM_EVENT_SRC_DIGITAL;
+ break;
+ case (1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
+ want_thermal_protection = true;
+ dpm_event_src = AMDGPU_DPM_EVENT_SRC_EXTERNAL;
+ break;
+ case ((1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
+ (1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL)):
+ want_thermal_protection = true;
+ dpm_event_src = AMDGPU_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL;
+ break;
+ }
+
+ if (want_thermal_protection) {
+#if 0
+ /* XXX: need to figure out how to handle this properly */
+ tmp = RREG32_SMC(ixCG_THERMAL_CTRL);
+ tmp &= DPM_EVENT_SRC_MASK;
+ tmp |= DPM_EVENT_SRC(dpm_event_src);
+ WREG32_SMC(ixCG_THERMAL_CTRL, tmp);
+#endif
+
+ tmp = RREG32_SMC(ixGENERAL_PWRMGT);
+ if (pi->thermal_protection)
+ tmp &= ~GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK;
+ else
+ tmp |= GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK;
+ WREG32_SMC(ixGENERAL_PWRMGT, tmp);
+ } else {
+ tmp = RREG32_SMC(ixGENERAL_PWRMGT);
+ tmp |= GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK;
+ WREG32_SMC(ixGENERAL_PWRMGT, tmp);
+ }
+}
+
+static void ci_enable_auto_throttle_source(struct amdgpu_device *adev,
+ enum amdgpu_dpm_auto_throttle_src source,
+ bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ if (enable) {
+ if (!(pi->active_auto_throttle_sources & (1 << source))) {
+ pi->active_auto_throttle_sources |= 1 << source;
+ ci_set_dpm_event_sources(adev, pi->active_auto_throttle_sources);
+ }
+ } else {
+ if (pi->active_auto_throttle_sources & (1 << source)) {
+ pi->active_auto_throttle_sources &= ~(1 << source);
+ ci_set_dpm_event_sources(adev, pi->active_auto_throttle_sources);
+ }
+ }
+}
+
+static void ci_enable_vr_hot_gpio_interrupt(struct amdgpu_device *adev)
+{
+ if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT)
+ amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_EnableVRHotGPIOInterrupt);
+}
+
+static int ci_unfreeze_sclk_mclk_dpm(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ PPSMC_Result smc_result;
+
+ if (!pi->need_update_smu7_dpm_table)
+ return 0;
+
+ if ((!pi->sclk_dpm_key_disabled) &&
+ (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_SCLKDPM_UnfreezeLevel);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ if ((!pi->mclk_dpm_key_disabled) &&
+ (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MCLKDPM_UnfreezeLevel);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ pi->need_update_smu7_dpm_table = 0;
+ return 0;
+}
+
+static int ci_enable_sclk_mclk_dpm(struct amdgpu_device *adev, bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ PPSMC_Result smc_result;
+
+ if (enable) {
+ if (!pi->sclk_dpm_key_disabled) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_DPM_Enable);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ if (!pi->mclk_dpm_key_disabled) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MCLKDPM_Enable);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+
+ WREG32_P(mmMC_SEQ_CNTL_3, MC_SEQ_CNTL_3__CAC_EN_MASK,
+ ~MC_SEQ_CNTL_3__CAC_EN_MASK);
+
+ WREG32_SMC(ixLCAC_MC0_CNTL, 0x05);
+ WREG32_SMC(ixLCAC_MC1_CNTL, 0x05);
+ WREG32_SMC(ixLCAC_CPL_CNTL, 0x100005);
+
+ udelay(10);
+
+ WREG32_SMC(ixLCAC_MC0_CNTL, 0x400005);
+ WREG32_SMC(ixLCAC_MC1_CNTL, 0x400005);
+ WREG32_SMC(ixLCAC_CPL_CNTL, 0x500005);
+ }
+ } else {
+ if (!pi->sclk_dpm_key_disabled) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_DPM_Disable);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ if (!pi->mclk_dpm_key_disabled) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MCLKDPM_Disable);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int ci_start_dpm(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ PPSMC_Result smc_result;
+ int ret;
+ u32 tmp;
+
+ tmp = RREG32_SMC(ixGENERAL_PWRMGT);
+ tmp |= GENERAL_PWRMGT__GLOBAL_PWRMGT_EN_MASK;
+ WREG32_SMC(ixGENERAL_PWRMGT, tmp);
+
+ tmp = RREG32_SMC(ixSCLK_PWRMGT_CNTL);
+ tmp |= SCLK_PWRMGT_CNTL__DYNAMIC_PM_EN_MASK;
+ WREG32_SMC(ixSCLK_PWRMGT_CNTL, tmp);
+
+ ci_write_smc_soft_register(adev, offsetof(SMU7_SoftRegisters, VoltageChangeTimeout), 0x1000);
+
+ WREG32_P(mmBIF_LNCNT_RESET, 0, ~BIF_LNCNT_RESET__RESET_LNCNT_EN_MASK);
+
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_Voltage_Cntl_Enable);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+
+ ret = ci_enable_sclk_mclk_dpm(adev, true);
+ if (ret)
+ return ret;
+
+ if (!pi->pcie_dpm_key_disabled) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_PCIeDPM_Enable);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ci_freeze_sclk_mclk_dpm(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ PPSMC_Result smc_result;
+
+ if (!pi->need_update_smu7_dpm_table)
+ return 0;
+
+ if ((!pi->sclk_dpm_key_disabled) &&
+ (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_SCLKDPM_FreezeLevel);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ if ((!pi->mclk_dpm_key_disabled) &&
+ (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MCLKDPM_FreezeLevel);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ci_stop_dpm(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ PPSMC_Result smc_result;
+ int ret;
+ u32 tmp;
+
+ tmp = RREG32_SMC(ixGENERAL_PWRMGT);
+ tmp &= ~GENERAL_PWRMGT__GLOBAL_PWRMGT_EN_MASK;
+ WREG32_SMC(ixGENERAL_PWRMGT, tmp);
+
+ tmp = RREG32_SMC(ixSCLK_PWRMGT_CNTL);
+ tmp &= ~SCLK_PWRMGT_CNTL__DYNAMIC_PM_EN_MASK;
+ WREG32_SMC(ixSCLK_PWRMGT_CNTL, tmp);
+
+ if (!pi->pcie_dpm_key_disabled) {
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_PCIeDPM_Disable);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ ret = ci_enable_sclk_mclk_dpm(adev, false);
+ if (ret)
+ return ret;
+
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_Voltage_Cntl_Disable);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void ci_enable_sclk_control(struct amdgpu_device *adev, bool enable)
+{
+ u32 tmp = RREG32_SMC(ixSCLK_PWRMGT_CNTL);
+
+ if (enable)
+ tmp &= ~SCLK_PWRMGT_CNTL__SCLK_PWRMGT_OFF_MASK;
+ else
+ tmp |= SCLK_PWRMGT_CNTL__SCLK_PWRMGT_OFF_MASK;
+ WREG32_SMC(ixSCLK_PWRMGT_CNTL, tmp);
+}
+
+#if 0
+static int ci_notify_hw_of_power_source(struct amdgpu_device *adev,
+ bool ac_power)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct amdgpu_cac_tdp_table *cac_tdp_table =
+ adev->pm.dpm.dyn_state.cac_tdp_table;
+ u32 power_limit;
+
+ if (ac_power)
+ power_limit = (u32)(cac_tdp_table->maximum_power_delivery_limit * 256);
+ else
+ power_limit = (u32)(cac_tdp_table->battery_power_limit * 256);
+
+ ci_set_power_limit(adev, power_limit);
+
+ if (pi->caps_automatic_dc_transition) {
+ if (ac_power)
+ amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_RunningOnAC);
+ else
+ amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_Remove_DC_Clamp);
+ }
+
+ return 0;
+}
+#endif
+
+static PPSMC_Result amdgpu_ci_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
+ PPSMC_Msg msg, u32 parameter)
+{
+ WREG32(mmSMC_MSG_ARG_0, parameter);
+ return amdgpu_ci_send_msg_to_smc(adev, msg);
+}
+
+static PPSMC_Result amdgpu_ci_send_msg_to_smc_return_parameter(struct amdgpu_device *adev,
+ PPSMC_Msg msg, u32 *parameter)
+{
+ PPSMC_Result smc_result;
+
+ smc_result = amdgpu_ci_send_msg_to_smc(adev, msg);
+
+ if ((smc_result == PPSMC_Result_OK) && parameter)
+ *parameter = RREG32(mmSMC_MSG_ARG_0);
+
+ return smc_result;
+}
+
+static int ci_dpm_force_state_sclk(struct amdgpu_device *adev, u32 n)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ if (!pi->sclk_dpm_key_disabled) {
+ PPSMC_Result smc_result =
+ amdgpu_ci_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SCLKDPM_SetEnabledMask, 1 << n);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ci_dpm_force_state_mclk(struct amdgpu_device *adev, u32 n)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ if (!pi->mclk_dpm_key_disabled) {
+ PPSMC_Result smc_result =
+ amdgpu_ci_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_MCLKDPM_SetEnabledMask, 1 << n);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ci_dpm_force_state_pcie(struct amdgpu_device *adev, u32 n)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ if (!pi->pcie_dpm_key_disabled) {
+ PPSMC_Result smc_result =
+ amdgpu_ci_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_PCIeDPM_ForceLevel, n);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ci_set_power_limit(struct amdgpu_device *adev, u32 n)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_PkgPwrLimit) {
+ PPSMC_Result smc_result =
+ amdgpu_ci_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_PkgPwrSetLimit, n);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ci_set_overdrive_target_tdp(struct amdgpu_device *adev,
+ u32 target_tdp)
+{
+ PPSMC_Result smc_result =
+ amdgpu_ci_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ return 0;
+}
+
+#if 0
+static int ci_set_boot_state(struct amdgpu_device *adev)
+{
+ return ci_enable_sclk_mclk_dpm(adev, false);
+}
+#endif
+
+static u32 ci_get_average_sclk_freq(struct amdgpu_device *adev)
+{
+ u32 sclk_freq;
+ PPSMC_Result smc_result =
+ amdgpu_ci_send_msg_to_smc_return_parameter(adev,
+ PPSMC_MSG_API_GetSclkFrequency,
+ &sclk_freq);
+ if (smc_result != PPSMC_Result_OK)
+ sclk_freq = 0;
+
+ return sclk_freq;
+}
+
+static u32 ci_get_average_mclk_freq(struct amdgpu_device *adev)
+{
+ u32 mclk_freq;
+ PPSMC_Result smc_result =
+ amdgpu_ci_send_msg_to_smc_return_parameter(adev,
+ PPSMC_MSG_API_GetMclkFrequency,
+ &mclk_freq);
+ if (smc_result != PPSMC_Result_OK)
+ mclk_freq = 0;
+
+ return mclk_freq;
+}
+
+static void ci_dpm_start_smc(struct amdgpu_device *adev)
+{
+ int i;
+
+ amdgpu_ci_program_jump_on_start(adev);
+ amdgpu_ci_start_smc_clock(adev);
+ amdgpu_ci_start_smc(adev);
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if (RREG32_SMC(ixFIRMWARE_FLAGS) & FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK)
+ break;
+ }
+}
+
+static void ci_dpm_stop_smc(struct amdgpu_device *adev)
+{
+ amdgpu_ci_reset_smc(adev);
+ amdgpu_ci_stop_smc_clock(adev);
+}
+
+static int ci_process_firmware_header(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 tmp;
+ int ret;
+
+ ret = amdgpu_ci_read_smc_sram_dword(adev,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU7_Firmware_Header, DpmTable),
+ &tmp, pi->sram_end);
+ if (ret)
+ return ret;
+
+ pi->dpm_table_start = tmp;
+
+ ret = amdgpu_ci_read_smc_sram_dword(adev,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU7_Firmware_Header, SoftRegisters),
+ &tmp, pi->sram_end);
+ if (ret)
+ return ret;
+
+ pi->soft_regs_start = tmp;
+
+ ret = amdgpu_ci_read_smc_sram_dword(adev,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU7_Firmware_Header, mcRegisterTable),
+ &tmp, pi->sram_end);
+ if (ret)
+ return ret;
+
+ pi->mc_reg_table_start = tmp;
+
+ ret = amdgpu_ci_read_smc_sram_dword(adev,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU7_Firmware_Header, FanTable),
+ &tmp, pi->sram_end);
+ if (ret)
+ return ret;
+
+ pi->fan_table_start = tmp;
+
+ ret = amdgpu_ci_read_smc_sram_dword(adev,
+ SMU7_FIRMWARE_HEADER_LOCATION +
+ offsetof(SMU7_Firmware_Header, mcArbDramTimingTable),
+ &tmp, pi->sram_end);
+ if (ret)
+ return ret;
+
+ pi->arb_table_start = tmp;
+
+ return 0;
+}
+
+static void ci_read_clock_registers(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ pi->clock_registers.cg_spll_func_cntl =
+ RREG32_SMC(ixCG_SPLL_FUNC_CNTL);
+ pi->clock_registers.cg_spll_func_cntl_2 =
+ RREG32_SMC(ixCG_SPLL_FUNC_CNTL_2);
+ pi->clock_registers.cg_spll_func_cntl_3 =
+ RREG32_SMC(ixCG_SPLL_FUNC_CNTL_3);
+ pi->clock_registers.cg_spll_func_cntl_4 =
+ RREG32_SMC(ixCG_SPLL_FUNC_CNTL_4);
+ pi->clock_registers.cg_spll_spread_spectrum =
+ RREG32_SMC(ixCG_SPLL_SPREAD_SPECTRUM);
+ pi->clock_registers.cg_spll_spread_spectrum_2 =
+ RREG32_SMC(ixCG_SPLL_SPREAD_SPECTRUM_2);
+ pi->clock_registers.dll_cntl = RREG32(mmDLL_CNTL);
+ pi->clock_registers.mclk_pwrmgt_cntl = RREG32(mmMCLK_PWRMGT_CNTL);
+ pi->clock_registers.mpll_ad_func_cntl = RREG32(mmMPLL_AD_FUNC_CNTL);
+ pi->clock_registers.mpll_dq_func_cntl = RREG32(mmMPLL_DQ_FUNC_CNTL);
+ pi->clock_registers.mpll_func_cntl = RREG32(mmMPLL_FUNC_CNTL);
+ pi->clock_registers.mpll_func_cntl_1 = RREG32(mmMPLL_FUNC_CNTL_1);
+ pi->clock_registers.mpll_func_cntl_2 = RREG32(mmMPLL_FUNC_CNTL_2);
+ pi->clock_registers.mpll_ss1 = RREG32(mmMPLL_SS1);
+ pi->clock_registers.mpll_ss2 = RREG32(mmMPLL_SS2);
+}
+
+static void ci_init_sclk_t(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ pi->low_sclk_interrupt_t = 0;
+}
+
+static void ci_enable_thermal_protection(struct amdgpu_device *adev,
+ bool enable)
+{
+ u32 tmp = RREG32_SMC(ixGENERAL_PWRMGT);
+
+ if (enable)
+ tmp &= ~GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK;
+ else
+ tmp |= GENERAL_PWRMGT__THERMAL_PROTECTION_DIS_MASK;
+ WREG32_SMC(ixGENERAL_PWRMGT, tmp);
+}
+
+static void ci_enable_acpi_power_management(struct amdgpu_device *adev)
+{
+ u32 tmp = RREG32_SMC(ixGENERAL_PWRMGT);
+
+ tmp |= GENERAL_PWRMGT__STATIC_PM_EN_MASK;
+
+ WREG32_SMC(ixGENERAL_PWRMGT, tmp);
+}
+
+#if 0
+static int ci_enter_ulp_state(struct amdgpu_device *adev)
+{
+
+ WREG32(mmSMC_MESSAGE_0, PPSMC_MSG_SwitchToMinimumPower);
+
+ udelay(25000);
+
+ return 0;
+}
+
+static int ci_exit_ulp_state(struct amdgpu_device *adev)
+{
+ int i;
+
+ WREG32(mmSMC_MESSAGE_0, PPSMC_MSG_ResumeFromMinimumPower);
+
+ udelay(7000);
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if (RREG32(mmSMC_RESP_0) == 1)
+ break;
+ udelay(1000);
+ }
+
+ return 0;
+}
+#endif
+
+static int ci_notify_smc_display_change(struct amdgpu_device *adev,
+ bool has_display)
+{
+ PPSMC_Msg msg = has_display ? PPSMC_MSG_HasDisplay : PPSMC_MSG_NoDisplay;
+
+ return (amdgpu_ci_send_msg_to_smc(adev, msg) == PPSMC_Result_OK) ? 0 : -EINVAL;
+}
+
+static int ci_enable_ds_master_switch(struct amdgpu_device *adev,
+ bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ if (enable) {
+ if (pi->caps_sclk_ds) {
+ if (amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MASTER_DeepSleep_ON) != PPSMC_Result_OK)
+ return -EINVAL;
+ } else {
+ if (amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MASTER_DeepSleep_OFF) != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+ } else {
+ if (pi->caps_sclk_ds) {
+ if (amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_MASTER_DeepSleep_OFF) != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void ci_program_display_gap(struct amdgpu_device *adev)
+{
+ u32 tmp = RREG32_SMC(ixCG_DISPLAY_GAP_CNTL);
+ u32 pre_vbi_time_in_us;
+ u32 frame_time_in_us;
+ u32 ref_clock = adev->clock.spll.reference_freq;
+ u32 refresh_rate = amdgpu_dpm_get_vrefresh(adev);
+ u32 vblank_time = amdgpu_dpm_get_vblank_time(adev);
+
+ tmp &= ~CG_DISPLAY_GAP_CNTL__DISP_GAP_MASK;
+ if (adev->pm.dpm.new_active_crtc_count > 0)
+ tmp |= (AMDGPU_PM_DISPLAY_GAP_VBLANK_OR_WM << CG_DISPLAY_GAP_CNTL__DISP_GAP__SHIFT);
+ else
+ tmp |= (AMDGPU_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP_GAP__SHIFT);
+ WREG32_SMC(ixCG_DISPLAY_GAP_CNTL, tmp);
+
+ if (refresh_rate == 0)
+ refresh_rate = 60;
+ if (vblank_time == 0xffffffff)
+ vblank_time = 500;
+ frame_time_in_us = 1000000 / refresh_rate;
+ pre_vbi_time_in_us =
+ frame_time_in_us - 200 - vblank_time;
+ tmp = pre_vbi_time_in_us * (ref_clock / 100);
+
+ WREG32_SMC(ixCG_DISPLAY_GAP_CNTL2, tmp);
+ ci_write_smc_soft_register(adev, offsetof(SMU7_SoftRegisters, PreVBlankGap), 0x64);
+ ci_write_smc_soft_register(adev, offsetof(SMU7_SoftRegisters, VBlankTimeout), (frame_time_in_us - pre_vbi_time_in_us));
+
+
+ ci_notify_smc_display_change(adev, (adev->pm.dpm.new_active_crtc_count == 1));
+
+}
+
+static void ci_enable_spread_spectrum(struct amdgpu_device *adev, bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 tmp;
+
+ if (enable) {
+ if (pi->caps_sclk_ss_support) {
+ tmp = RREG32_SMC(ixGENERAL_PWRMGT);
+ tmp |= GENERAL_PWRMGT__DYN_SPREAD_SPECTRUM_EN_MASK;
+ WREG32_SMC(ixGENERAL_PWRMGT, tmp);
+ }
+ } else {
+ tmp = RREG32_SMC(ixCG_SPLL_SPREAD_SPECTRUM);
+ tmp &= ~CG_SPLL_SPREAD_SPECTRUM__SSEN_MASK;
+ WREG32_SMC(ixCG_SPLL_SPREAD_SPECTRUM, tmp);
+
+ tmp = RREG32_SMC(ixGENERAL_PWRMGT);
+ tmp &= ~GENERAL_PWRMGT__DYN_SPREAD_SPECTRUM_EN_MASK;
+ WREG32_SMC(ixGENERAL_PWRMGT, tmp);
+ }
+}
+
+static void ci_program_sstp(struct amdgpu_device *adev)
+{
+ WREG32_SMC(ixCG_STATIC_SCREEN_PARAMETER,
+ ((CISLANDS_SSTU_DFLT << CG_STATIC_SCREEN_PARAMETER__STATIC_SCREEN_THRESHOLD_UNIT__SHIFT) |
+ (CISLANDS_SST_DFLT << CG_STATIC_SCREEN_PARAMETER__STATIC_SCREEN_THRESHOLD__SHIFT)));
+}
+
+static void ci_enable_display_gap(struct amdgpu_device *adev)
+{
+ u32 tmp = RREG32_SMC(ixCG_DISPLAY_GAP_CNTL);
+
+ tmp &= ~(CG_DISPLAY_GAP_CNTL__DISP_GAP_MASK |
+ CG_DISPLAY_GAP_CNTL__DISP_GAP_MCHG_MASK);
+ tmp |= ((AMDGPU_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP_GAP__SHIFT) |
+ (AMDGPU_PM_DISPLAY_GAP_VBLANK << CG_DISPLAY_GAP_CNTL__DISP_GAP_MCHG__SHIFT));
+
+ WREG32_SMC(ixCG_DISPLAY_GAP_CNTL, tmp);
+}
+
+static void ci_program_vc(struct amdgpu_device *adev)
+{
+ u32 tmp;
+
+ tmp = RREG32_SMC(ixSCLK_PWRMGT_CNTL);
+ tmp &= ~(SCLK_PWRMGT_CNTL__RESET_SCLK_CNT_MASK | SCLK_PWRMGT_CNTL__RESET_BUSY_CNT_MASK);
+ WREG32_SMC(ixSCLK_PWRMGT_CNTL, tmp);
+
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_0, CISLANDS_VRC_DFLT0);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_1, CISLANDS_VRC_DFLT1);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_2, CISLANDS_VRC_DFLT2);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_3, CISLANDS_VRC_DFLT3);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_4, CISLANDS_VRC_DFLT4);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_5, CISLANDS_VRC_DFLT5);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_6, CISLANDS_VRC_DFLT6);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_7, CISLANDS_VRC_DFLT7);
+}
+
+static void ci_clear_vc(struct amdgpu_device *adev)
+{
+ u32 tmp;
+
+ tmp = RREG32_SMC(ixSCLK_PWRMGT_CNTL);
+ tmp |= (SCLK_PWRMGT_CNTL__RESET_SCLK_CNT_MASK | SCLK_PWRMGT_CNTL__RESET_BUSY_CNT_MASK);
+ WREG32_SMC(ixSCLK_PWRMGT_CNTL, tmp);
+
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_0, 0);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_1, 0);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_2, 0);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_3, 0);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_4, 0);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_5, 0);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_6, 0);
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_7, 0);
+}
+
+static int ci_upload_firmware(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ int i, ret;
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if (RREG32_SMC(ixRCU_UC_EVENTS) & RCU_UC_EVENTS__boot_seq_done_MASK)
+ break;
+ }
+ WREG32_SMC(ixSMC_SYSCON_MISC_CNTL, 1);
+
+ amdgpu_ci_stop_smc_clock(adev);
+ amdgpu_ci_reset_smc(adev);
+
+ ret = amdgpu_ci_load_smc_ucode(adev, pi->sram_end);
+
+ return ret;
+
+}
+
+static int ci_get_svi2_voltage_table(struct amdgpu_device *adev,
+ struct amdgpu_clock_voltage_dependency_table *voltage_dependency_table,
+ struct atom_voltage_table *voltage_table)
+{
+ u32 i;
+
+ if (voltage_dependency_table == NULL)
+ return -EINVAL;
+
+ voltage_table->mask_low = 0;
+ voltage_table->phase_delay = 0;
+
+ voltage_table->count = voltage_dependency_table->count;
+ for (i = 0; i < voltage_table->count; i++) {
+ voltage_table->entries[i].value = voltage_dependency_table->entries[i].v;
+ voltage_table->entries[i].smio_low = 0;
+ }
+
+ return 0;
+}
+
+static int ci_construct_voltage_tables(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ int ret;
+
+ if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) {
+ ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_VDDC,
+ VOLTAGE_OBJ_GPIO_LUT,
+ &pi->vddc_voltage_table);
+ if (ret)
+ return ret;
+ } else if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
+ ret = ci_get_svi2_voltage_table(adev,
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+ &pi->vddc_voltage_table);
+ if (ret)
+ return ret;
+ }
+
+ if (pi->vddc_voltage_table.count > SMU7_MAX_LEVELS_VDDC)
+ ci_trim_voltage_table_to_fit_state_table(adev, SMU7_MAX_LEVELS_VDDC,
+ &pi->vddc_voltage_table);
+
+ if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) {
+ ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_VDDCI,
+ VOLTAGE_OBJ_GPIO_LUT,
+ &pi->vddci_voltage_table);
+ if (ret)
+ return ret;
+ } else if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
+ ret = ci_get_svi2_voltage_table(adev,
+ &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+ &pi->vddci_voltage_table);
+ if (ret)
+ return ret;
+ }
+
+ if (pi->vddci_voltage_table.count > SMU7_MAX_LEVELS_VDDCI)
+ ci_trim_voltage_table_to_fit_state_table(adev, SMU7_MAX_LEVELS_VDDCI,
+ &pi->vddci_voltage_table);
+
+ if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) {
+ ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_MVDDC,
+ VOLTAGE_OBJ_GPIO_LUT,
+ &pi->mvdd_voltage_table);
+ if (ret)
+ return ret;
+ } else if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
+ ret = ci_get_svi2_voltage_table(adev,
+ &adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
+ &pi->mvdd_voltage_table);
+ if (ret)
+ return ret;
+ }
+
+ if (pi->mvdd_voltage_table.count > SMU7_MAX_LEVELS_MVDD)
+ ci_trim_voltage_table_to_fit_state_table(adev, SMU7_MAX_LEVELS_MVDD,
+ &pi->mvdd_voltage_table);
+
+ return 0;
+}
+
+static void ci_populate_smc_voltage_table(struct amdgpu_device *adev,
+ struct atom_voltage_table_entry *voltage_table,
+ SMU7_Discrete_VoltageLevel *smc_voltage_table)
+{
+ int ret;
+
+ ret = ci_get_std_voltage_value_sidd(adev, voltage_table,
+ &smc_voltage_table->StdVoltageHiSidd,
+ &smc_voltage_table->StdVoltageLoSidd);
+
+ if (ret) {
+ smc_voltage_table->StdVoltageHiSidd = voltage_table->value * VOLTAGE_SCALE;
+ smc_voltage_table->StdVoltageLoSidd = voltage_table->value * VOLTAGE_SCALE;
+ }
+
+ smc_voltage_table->Voltage = cpu_to_be16(voltage_table->value * VOLTAGE_SCALE);
+ smc_voltage_table->StdVoltageHiSidd =
+ cpu_to_be16(smc_voltage_table->StdVoltageHiSidd);
+ smc_voltage_table->StdVoltageLoSidd =
+ cpu_to_be16(smc_voltage_table->StdVoltageLoSidd);
+}
+
+static int ci_populate_smc_vddc_table(struct amdgpu_device *adev,
+ SMU7_Discrete_DpmTable *table)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ unsigned int count;
+
+ table->VddcLevelCount = pi->vddc_voltage_table.count;
+ for (count = 0; count < table->VddcLevelCount; count++) {
+ ci_populate_smc_voltage_table(adev,
+ &pi->vddc_voltage_table.entries[count],
+ &table->VddcLevel[count]);
+
+ if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO)
+ table->VddcLevel[count].Smio |=
+ pi->vddc_voltage_table.entries[count].smio_low;
+ else
+ table->VddcLevel[count].Smio = 0;
+ }
+ table->VddcLevelCount = cpu_to_be32(table->VddcLevelCount);
+
+ return 0;
+}
+
+static int ci_populate_smc_vddci_table(struct amdgpu_device *adev,
+ SMU7_Discrete_DpmTable *table)
+{
+ unsigned int count;
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ table->VddciLevelCount = pi->vddci_voltage_table.count;
+ for (count = 0; count < table->VddciLevelCount; count++) {
+ ci_populate_smc_voltage_table(adev,
+ &pi->vddci_voltage_table.entries[count],
+ &table->VddciLevel[count]);
+
+ if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO)
+ table->VddciLevel[count].Smio |=
+ pi->vddci_voltage_table.entries[count].smio_low;
+ else
+ table->VddciLevel[count].Smio = 0;
+ }
+ table->VddciLevelCount = cpu_to_be32(table->VddciLevelCount);
+
+ return 0;
+}
+
+static int ci_populate_smc_mvdd_table(struct amdgpu_device *adev,
+ SMU7_Discrete_DpmTable *table)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ unsigned int count;
+
+ table->MvddLevelCount = pi->mvdd_voltage_table.count;
+ for (count = 0; count < table->MvddLevelCount; count++) {
+ ci_populate_smc_voltage_table(adev,
+ &pi->mvdd_voltage_table.entries[count],
+ &table->MvddLevel[count]);
+
+ if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO)
+ table->MvddLevel[count].Smio |=
+ pi->mvdd_voltage_table.entries[count].smio_low;
+ else
+ table->MvddLevel[count].Smio = 0;
+ }
+ table->MvddLevelCount = cpu_to_be32(table->MvddLevelCount);
+
+ return 0;
+}
+
+static int ci_populate_smc_voltage_tables(struct amdgpu_device *adev,
+ SMU7_Discrete_DpmTable *table)
+{
+ int ret;
+
+ ret = ci_populate_smc_vddc_table(adev, table);
+ if (ret)
+ return ret;
+
+ ret = ci_populate_smc_vddci_table(adev, table);
+ if (ret)
+ return ret;
+
+ ret = ci_populate_smc_mvdd_table(adev, table);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ci_populate_mvdd_value(struct amdgpu_device *adev, u32 mclk,
+ SMU7_Discrete_VoltageLevel *voltage)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 i = 0;
+
+ if (pi->mvdd_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
+ for (i = 0; i < adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.count; i++) {
+ if (mclk <= adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.entries[i].clk) {
+ voltage->Voltage = pi->mvdd_voltage_table.entries[i].value;
+ break;
+ }
+ }
+
+ if (i >= adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.count)
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+static int ci_get_std_voltage_value_sidd(struct amdgpu_device *adev,
+ struct atom_voltage_table_entry *voltage_table,
+ u16 *std_voltage_hi_sidd, u16 *std_voltage_lo_sidd)
+{
+ u16 v_index, idx;
+ bool voltage_found = false;
+ *std_voltage_hi_sidd = voltage_table->value * VOLTAGE_SCALE;
+ *std_voltage_lo_sidd = voltage_table->value * VOLTAGE_SCALE;
+
+ if (adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries == NULL)
+ return -EINVAL;
+
+ if (adev->pm.dpm.dyn_state.cac_leakage_table.entries) {
+ for (v_index = 0; (u32)v_index < adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
+ if (voltage_table->value ==
+ adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
+ voltage_found = true;
+ if ((u32)v_index < adev->pm.dpm.dyn_state.cac_leakage_table.count)
+ idx = v_index;
+ else
+ idx = adev->pm.dpm.dyn_state.cac_leakage_table.count - 1;
+ *std_voltage_lo_sidd =
+ adev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].vddc * VOLTAGE_SCALE;
+ *std_voltage_hi_sidd =
+ adev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].leakage * VOLTAGE_SCALE;
+ break;
+ }
+ }
+
+ if (!voltage_found) {
+ for (v_index = 0; (u32)v_index < adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
+ if (voltage_table->value <=
+ adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
+ voltage_found = true;
+ if ((u32)v_index < adev->pm.dpm.dyn_state.cac_leakage_table.count)
+ idx = v_index;
+ else
+ idx = adev->pm.dpm.dyn_state.cac_leakage_table.count - 1;
+ *std_voltage_lo_sidd =
+ adev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].vddc * VOLTAGE_SCALE;
+ *std_voltage_hi_sidd =
+ adev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].leakage * VOLTAGE_SCALE;
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void ci_populate_phase_value_based_on_sclk(struct amdgpu_device *adev,
+ const struct amdgpu_phase_shedding_limits_table *limits,
+ u32 sclk,
+ u32 *phase_shedding)
+{
+ unsigned int i;
+
+ *phase_shedding = 1;
+
+ for (i = 0; i < limits->count; i++) {
+ if (sclk < limits->entries[i].sclk) {
+ *phase_shedding = i;
+ break;
+ }
+ }
+}
+
+static void ci_populate_phase_value_based_on_mclk(struct amdgpu_device *adev,
+ const struct amdgpu_phase_shedding_limits_table *limits,
+ u32 mclk,
+ u32 *phase_shedding)
+{
+ unsigned int i;
+
+ *phase_shedding = 1;
+
+ for (i = 0; i < limits->count; i++) {
+ if (mclk < limits->entries[i].mclk) {
+ *phase_shedding = i;
+ break;
+ }
+ }
+}
+
+static int ci_init_arb_table_index(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 tmp;
+ int ret;
+
+ ret = amdgpu_ci_read_smc_sram_dword(adev, pi->arb_table_start,
+ &tmp, pi->sram_end);
+ if (ret)
+ return ret;
+
+ tmp &= 0x00FFFFFF;
+ tmp |= MC_CG_ARB_FREQ_F1 << 24;
+
+ return amdgpu_ci_write_smc_sram_dword(adev, pi->arb_table_start,
+ tmp, pi->sram_end);
+}
+
+static int ci_get_dependency_volt_by_clk(struct amdgpu_device *adev,
+ struct amdgpu_clock_voltage_dependency_table *allowed_clock_voltage_table,
+ u32 clock, u32 *voltage)
+{
+ u32 i = 0;
+
+ if (allowed_clock_voltage_table->count == 0)
+ return -EINVAL;
+
+ for (i = 0; i < allowed_clock_voltage_table->count; i++) {
+ if (allowed_clock_voltage_table->entries[i].clk >= clock) {
+ *voltage = allowed_clock_voltage_table->entries[i].v;
+ return 0;
+ }
+ }
+
+ *voltage = allowed_clock_voltage_table->entries[i-1].v;
+
+ return 0;
+}
+
+static u8 ci_get_sleep_divider_id_from_clock(struct amdgpu_device *adev,
+ u32 sclk, u32 min_sclk_in_sr)
+{
+ u32 i;
+ u32 tmp;
+ u32 min = (min_sclk_in_sr > CISLAND_MINIMUM_ENGINE_CLOCK) ?
+ min_sclk_in_sr : CISLAND_MINIMUM_ENGINE_CLOCK;
+
+ if (sclk < min)
+ return 0;
+
+ for (i = CISLAND_MAX_DEEPSLEEP_DIVIDER_ID; ; i--) {
+ tmp = sclk / (1 << i);
+ if (tmp >= min || i == 0)
+ break;
+ }
+
+ return (u8)i;
+}
+
+static int ci_initial_switch_from_arb_f0_to_f1(struct amdgpu_device *adev)
+{
+ return ci_copy_and_switch_arb_sets(adev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
+}
+
+static int ci_reset_to_default(struct amdgpu_device *adev)
+{
+ return (amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_ResetToDefaults) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+
+static int ci_force_switch_to_arb_f0(struct amdgpu_device *adev)
+{
+ u32 tmp;
+
+ tmp = (RREG32_SMC(ixSMC_SCRATCH9) & 0x0000ff00) >> 8;
+
+ if (tmp == MC_CG_ARB_FREQ_F0)
+ return 0;
+
+ return ci_copy_and_switch_arb_sets(adev, tmp, MC_CG_ARB_FREQ_F0);
+}
+
+static void ci_register_patching_mc_arb(struct amdgpu_device *adev,
+ const u32 engine_clock,
+ const u32 memory_clock,
+ u32 *dram_timimg2)
+{
+ bool patch;
+ u32 tmp, tmp2;
+
+ tmp = RREG32(mmMC_SEQ_MISC0);
+ patch = ((tmp & 0x0000f00) == 0x300) ? true : false;
+
+ if (patch &&
+ ((adev->pdev->device == 0x67B0) ||
+ (adev->pdev->device == 0x67B1))) {
+ if ((memory_clock > 100000) && (memory_clock <= 125000)) {
+ tmp2 = (((0x31 * engine_clock) / 125000) - 1) & 0xff;
+ *dram_timimg2 &= ~0x00ff0000;
+ *dram_timimg2 |= tmp2 << 16;
+ } else if ((memory_clock > 125000) && (memory_clock <= 137500)) {
+ tmp2 = (((0x36 * engine_clock) / 137500) - 1) & 0xff;
+ *dram_timimg2 &= ~0x00ff0000;
+ *dram_timimg2 |= tmp2 << 16;
+ }
+ }
+}
+
+static int ci_populate_memory_timing_parameters(struct amdgpu_device *adev,
+ u32 sclk,
+ u32 mclk,
+ SMU7_Discrete_MCArbDramTimingTableEntry *arb_regs)
+{
+ u32 dram_timing;
+ u32 dram_timing2;
+ u32 burst_time;
+
+ amdgpu_atombios_set_engine_dram_timings(adev, sclk, mclk);
+
+ dram_timing = RREG32(mmMC_ARB_DRAM_TIMING);
+ dram_timing2 = RREG32(mmMC_ARB_DRAM_TIMING2);
+ burst_time = RREG32(mmMC_ARB_BURST_TIME) & MC_ARB_BURST_TIME__STATE0_MASK;
+
+ ci_register_patching_mc_arb(adev, sclk, mclk, &dram_timing2);
+
+ arb_regs->McArbDramTiming = cpu_to_be32(dram_timing);
+ arb_regs->McArbDramTiming2 = cpu_to_be32(dram_timing2);
+ arb_regs->McArbBurstTime = (u8)burst_time;
+
+ return 0;
+}
+
+static int ci_do_program_memory_timing_parameters(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ SMU7_Discrete_MCArbDramTimingTable arb_regs;
+ u32 i, j;
+ int ret = 0;
+
+ memset(&arb_regs, 0, sizeof(SMU7_Discrete_MCArbDramTimingTable));
+
+ for (i = 0; i < pi->dpm_table.sclk_table.count; i++) {
+ for (j = 0; j < pi->dpm_table.mclk_table.count; j++) {
+ ret = ci_populate_memory_timing_parameters(adev,
+ pi->dpm_table.sclk_table.dpm_levels[i].value,
+ pi->dpm_table.mclk_table.dpm_levels[j].value,
+ &arb_regs.entries[i][j]);
+ if (ret)
+ break;
+ }
+ }
+
+ if (ret == 0)
+ ret = amdgpu_ci_copy_bytes_to_smc(adev,
+ pi->arb_table_start,
+ (u8 *)&arb_regs,
+ sizeof(SMU7_Discrete_MCArbDramTimingTable),
+ pi->sram_end);
+
+ return ret;
+}
+
+static int ci_program_memory_timing_parameters(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ if (pi->need_update_smu7_dpm_table == 0)
+ return 0;
+
+ return ci_do_program_memory_timing_parameters(adev);
+}
+
+static void ci_populate_smc_initial_state(struct amdgpu_device *adev,
+ struct amdgpu_ps *amdgpu_boot_state)
+{
+ struct ci_ps *boot_state = ci_get_ps(amdgpu_boot_state);
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 level = 0;
+
+ for (level = 0; level < adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; level++) {
+ if (adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[level].clk >=
+ boot_state->performance_levels[0].sclk) {
+ pi->smc_state_table.GraphicsBootLevel = level;
+ break;
+ }
+ }
+
+ for (level = 0; level < adev->pm.dpm.dyn_state.vddc_dependency_on_mclk.count; level++) {
+ if (adev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries[level].clk >=
+ boot_state->performance_levels[0].mclk) {
+ pi->smc_state_table.MemoryBootLevel = level;
+ break;
+ }
+ }
+}
+
+static u32 ci_get_dpm_level_enable_mask_value(struct ci_single_dpm_table *dpm_table)
+{
+ u32 i;
+ u32 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;
+}
+
+static void ci_populate_smc_link_level(struct amdgpu_device *adev,
+ SMU7_Discrete_DpmTable *table)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_dpm_table *dpm_table = &pi->dpm_table;
+ u32 i;
+
+ for (i = 0; i < dpm_table->pcie_speed_table.count; i++) {
+ table->LinkLevel[i].PcieGenSpeed =
+ (u8)dpm_table->pcie_speed_table.dpm_levels[i].value;
+ table->LinkLevel[i].PcieLaneCount =
+ amdgpu_encode_pci_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
+ table->LinkLevel[i].EnabledForActivity = 1;
+ table->LinkLevel[i].DownT = cpu_to_be32(5);
+ table->LinkLevel[i].UpT = cpu_to_be32(30);
+ }
+
+ pi->smc_state_table.LinkLevelCount = (u8)dpm_table->pcie_speed_table.count;
+ pi->dpm_level_enable_mask.pcie_dpm_enable_mask =
+ ci_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
+}
+
+static int ci_populate_smc_uvd_level(struct amdgpu_device *adev,
+ SMU7_Discrete_DpmTable *table)
+{
+ u32 count;
+ struct atom_clock_dividers dividers;
+ int ret = -EINVAL;
+
+ table->UvdLevelCount =
+ adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count;
+
+ for (count = 0; count < table->UvdLevelCount; count++) {
+ table->UvdLevel[count].VclkFrequency =
+ adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].vclk;
+ table->UvdLevel[count].DclkFrequency =
+ adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].dclk;
+ table->UvdLevel[count].MinVddc =
+ adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE;
+ table->UvdLevel[count].MinVddcPhases = 1;
+
+ ret = amdgpu_atombios_get_clock_dividers(adev,
+ COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ table->UvdLevel[count].VclkFrequency, false, &dividers);
+ if (ret)
+ return ret;
+
+ table->UvdLevel[count].VclkDivider = (u8)dividers.post_divider;
+
+ ret = amdgpu_atombios_get_clock_dividers(adev,
+ COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ table->UvdLevel[count].DclkFrequency, false, &dividers);
+ if (ret)
+ return ret;
+
+ table->UvdLevel[count].DclkDivider = (u8)dividers.post_divider;
+
+ table->UvdLevel[count].VclkFrequency = cpu_to_be32(table->UvdLevel[count].VclkFrequency);
+ table->UvdLevel[count].DclkFrequency = cpu_to_be32(table->UvdLevel[count].DclkFrequency);
+ table->UvdLevel[count].MinVddc = cpu_to_be16(table->UvdLevel[count].MinVddc);
+ }
+
+ return ret;
+}
+
+static int ci_populate_smc_vce_level(struct amdgpu_device *adev,
+ SMU7_Discrete_DpmTable *table)
+{
+ u32 count;
+ struct atom_clock_dividers dividers;
+ int ret = -EINVAL;
+
+ table->VceLevelCount =
+ adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count;
+
+ for (count = 0; count < table->VceLevelCount; count++) {
+ table->VceLevel[count].Frequency =
+ adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[count].evclk;
+ table->VceLevel[count].MinVoltage =
+ (u16)adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE;
+ table->VceLevel[count].MinPhases = 1;
+
+ ret = amdgpu_atombios_get_clock_dividers(adev,
+ COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ table->VceLevel[count].Frequency, false, &dividers);
+ if (ret)
+ return ret;
+
+ table->VceLevel[count].Divider = (u8)dividers.post_divider;
+
+ table->VceLevel[count].Frequency = cpu_to_be32(table->VceLevel[count].Frequency);
+ table->VceLevel[count].MinVoltage = cpu_to_be16(table->VceLevel[count].MinVoltage);
+ }
+
+ return ret;
+
+}
+
+static int ci_populate_smc_acp_level(struct amdgpu_device *adev,
+ SMU7_Discrete_DpmTable *table)
+{
+ u32 count;
+ struct atom_clock_dividers dividers;
+ int ret = -EINVAL;
+
+ table->AcpLevelCount = (u8)
+ (adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count);
+
+ for (count = 0; count < table->AcpLevelCount; count++) {
+ table->AcpLevel[count].Frequency =
+ adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[count].clk;
+ table->AcpLevel[count].MinVoltage =
+ adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[count].v;
+ table->AcpLevel[count].MinPhases = 1;
+
+ ret = amdgpu_atombios_get_clock_dividers(adev,
+ COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ table->AcpLevel[count].Frequency, false, &dividers);
+ if (ret)
+ return ret;
+
+ table->AcpLevel[count].Divider = (u8)dividers.post_divider;
+
+ table->AcpLevel[count].Frequency = cpu_to_be32(table->AcpLevel[count].Frequency);
+ table->AcpLevel[count].MinVoltage = cpu_to_be16(table->AcpLevel[count].MinVoltage);
+ }
+
+ return ret;
+}
+
+static int ci_populate_smc_samu_level(struct amdgpu_device *adev,
+ SMU7_Discrete_DpmTable *table)
+{
+ u32 count;
+ struct atom_clock_dividers dividers;
+ int ret = -EINVAL;
+
+ table->SamuLevelCount =
+ adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count;
+
+ for (count = 0; count < table->SamuLevelCount; count++) {
+ table->SamuLevel[count].Frequency =
+ adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[count].clk;
+ table->SamuLevel[count].MinVoltage =
+ adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE;
+ table->SamuLevel[count].MinPhases = 1;
+
+ ret = amdgpu_atombios_get_clock_dividers(adev,
+ COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ table->SamuLevel[count].Frequency, false, &dividers);
+ if (ret)
+ return ret;
+
+ table->SamuLevel[count].Divider = (u8)dividers.post_divider;
+
+ table->SamuLevel[count].Frequency = cpu_to_be32(table->SamuLevel[count].Frequency);
+ table->SamuLevel[count].MinVoltage = cpu_to_be16(table->SamuLevel[count].MinVoltage);
+ }
+
+ return ret;
+}
+
+static int ci_calculate_mclk_params(struct amdgpu_device *adev,
+ u32 memory_clock,
+ SMU7_Discrete_MemoryLevel *mclk,
+ bool strobe_mode,
+ bool dll_state_on)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 dll_cntl = pi->clock_registers.dll_cntl;
+ u32 mclk_pwrmgt_cntl = pi->clock_registers.mclk_pwrmgt_cntl;
+ u32 mpll_ad_func_cntl = pi->clock_registers.mpll_ad_func_cntl;
+ u32 mpll_dq_func_cntl = pi->clock_registers.mpll_dq_func_cntl;
+ u32 mpll_func_cntl = pi->clock_registers.mpll_func_cntl;
+ u32 mpll_func_cntl_1 = pi->clock_registers.mpll_func_cntl_1;
+ u32 mpll_func_cntl_2 = pi->clock_registers.mpll_func_cntl_2;
+ u32 mpll_ss1 = pi->clock_registers.mpll_ss1;
+ u32 mpll_ss2 = pi->clock_registers.mpll_ss2;
+ struct atom_mpll_param mpll_param;
+ int ret;
+
+ ret = amdgpu_atombios_get_memory_pll_dividers(adev, memory_clock, strobe_mode, &mpll_param);
+ if (ret)
+ return ret;
+
+ mpll_func_cntl &= ~MPLL_FUNC_CNTL__BWCTRL_MASK;
+ mpll_func_cntl |= (mpll_param.bwcntl << MPLL_FUNC_CNTL__BWCTRL__SHIFT);
+
+ mpll_func_cntl_1 &= ~(MPLL_FUNC_CNTL_1__CLKF_MASK | MPLL_FUNC_CNTL_1__CLKFRAC_MASK |
+ MPLL_FUNC_CNTL_1__VCO_MODE_MASK);
+ mpll_func_cntl_1 |= (mpll_param.clkf) << MPLL_FUNC_CNTL_1__CLKF__SHIFT |
+ (mpll_param.clkfrac << MPLL_FUNC_CNTL_1__CLKFRAC__SHIFT) |
+ (mpll_param.vco_mode << MPLL_FUNC_CNTL_1__VCO_MODE__SHIFT);
+
+ mpll_ad_func_cntl &= ~MPLL_AD_FUNC_CNTL__YCLK_POST_DIV_MASK;
+ mpll_ad_func_cntl |= (mpll_param.post_div << MPLL_AD_FUNC_CNTL__YCLK_POST_DIV__SHIFT);
+
+ if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) {
+ mpll_dq_func_cntl &= ~(MPLL_DQ_FUNC_CNTL__YCLK_SEL_MASK |
+ MPLL_AD_FUNC_CNTL__YCLK_POST_DIV_MASK);
+ mpll_dq_func_cntl |= (mpll_param.yclk_sel << MPLL_DQ_FUNC_CNTL__YCLK_SEL__SHIFT) |
+ (mpll_param.post_div << MPLL_AD_FUNC_CNTL__YCLK_POST_DIV__SHIFT);
+ }
+
+ if (pi->caps_mclk_ss_support) {
+ struct amdgpu_atom_ss ss;
+ u32 freq_nom;
+ u32 tmp;
+ u32 reference_clock = adev->clock.mpll.reference_freq;
+
+ if (mpll_param.qdr == 1)
+ freq_nom = memory_clock * 4 * (1 << mpll_param.post_div);
+ else
+ freq_nom = memory_clock * 2 * (1 << mpll_param.post_div);
+
+ tmp = (freq_nom / reference_clock);
+ tmp = tmp * tmp;
+ if (amdgpu_atombios_get_asic_ss_info(adev, &ss,
+ ASIC_INTERNAL_MEMORY_SS, freq_nom)) {
+ u32 clks = reference_clock * 5 / ss.rate;
+ u32 clkv = (u32)((((131 * ss.percentage * ss.rate) / 100) * tmp) / freq_nom);
+
+ mpll_ss1 &= ~MPLL_SS1__CLKV_MASK;
+ mpll_ss1 |= (clkv << MPLL_SS1__CLKV__SHIFT);
+
+ mpll_ss2 &= ~MPLL_SS2__CLKS_MASK;
+ mpll_ss2 |= (clks << MPLL_SS2__CLKS__SHIFT);
+ }
+ }
+
+ mclk_pwrmgt_cntl &= ~MCLK_PWRMGT_CNTL__DLL_SPEED_MASK;
+ mclk_pwrmgt_cntl |= (mpll_param.dll_speed << MCLK_PWRMGT_CNTL__DLL_SPEED__SHIFT);
+
+ if (dll_state_on)
+ mclk_pwrmgt_cntl |= MCLK_PWRMGT_CNTL__MRDCK0_PDNB_MASK |
+ MCLK_PWRMGT_CNTL__MRDCK1_PDNB_MASK;
+ else
+ mclk_pwrmgt_cntl &= ~(MCLK_PWRMGT_CNTL__MRDCK0_PDNB_MASK |
+ MCLK_PWRMGT_CNTL__MRDCK1_PDNB_MASK);
+
+ 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 int ci_populate_single_memory_level(struct amdgpu_device *adev,
+ u32 memory_clock,
+ SMU7_Discrete_MemoryLevel *memory_level)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ int ret;
+ bool dll_state_on;
+
+ if (adev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries) {
+ ret = ci_get_dependency_volt_by_clk(adev,
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+ memory_clock, &memory_level->MinVddc);
+ if (ret)
+ return ret;
+ }
+
+ if (adev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries) {
+ ret = ci_get_dependency_volt_by_clk(adev,
+ &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+ memory_clock, &memory_level->MinVddci);
+ if (ret)
+ return ret;
+ }
+
+ if (adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.entries) {
+ ret = ci_get_dependency_volt_by_clk(adev,
+ &adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
+ memory_clock, &memory_level->MinMvdd);
+ if (ret)
+ return ret;
+ }
+
+ memory_level->MinVddcPhases = 1;
+
+ if (pi->vddc_phase_shed_control)
+ ci_populate_phase_value_based_on_mclk(adev,
+ &adev->pm.dpm.dyn_state.phase_shedding_limits_table,
+ memory_clock,
+ &memory_level->MinVddcPhases);
+
+ memory_level->EnabledForThrottle = 1;
+ memory_level->EnabledForActivity = 1;
+ memory_level->UpH = 0;
+ memory_level->DownH = 100;
+ memory_level->VoltageDownH = 0;
+ memory_level->ActivityLevel = (u16)pi->mclk_activity_target;
+
+ memory_level->StutterEnable = false;
+ memory_level->StrobeEnable = false;
+ memory_level->EdcReadEnable = false;
+ memory_level->EdcWriteEnable = false;
+ memory_level->RttEnable = false;
+
+ memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+ if (pi->mclk_stutter_mode_threshold &&
+ (memory_clock <= pi->mclk_stutter_mode_threshold) &&
+ (pi->uvd_enabled == false) &&
+ (RREG32(mmDPG_PIPE_STUTTER_CONTROL) & DPG_PIPE_STUTTER_CONTROL__STUTTER_ENABLE_MASK) &&
+ (adev->pm.dpm.new_active_crtc_count <= 2))
+ memory_level->StutterEnable = true;
+
+ if (pi->mclk_strobe_mode_threshold &&
+ (memory_clock <= pi->mclk_strobe_mode_threshold))
+ memory_level->StrobeEnable = 1;
+
+ if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) {
+ memory_level->StrobeRatio =
+ ci_get_mclk_frequency_ratio(memory_clock, memory_level->StrobeEnable);
+ if (pi->mclk_edc_enable_threshold &&
+ (memory_clock > pi->mclk_edc_enable_threshold))
+ memory_level->EdcReadEnable = true;
+
+ if (pi->mclk_edc_wr_enable_threshold &&
+ (memory_clock > pi->mclk_edc_wr_enable_threshold))
+ memory_level->EdcWriteEnable = true;
+
+ if (memory_level->StrobeEnable) {
+ if (ci_get_mclk_frequency_ratio(memory_clock, true) >=
+ ((RREG32(mmMC_SEQ_MISC7) >> 16) & 0xf))
+ dll_state_on = ((RREG32(mmMC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
+ else
+ dll_state_on = ((RREG32(mmMC_SEQ_MISC6) >> 1) & 0x1) ? true : false;
+ } else {
+ dll_state_on = pi->dll_default_on;
+ }
+ } else {
+ memory_level->StrobeRatio = ci_get_ddr3_mclk_frequency_ratio(memory_clock);
+ dll_state_on = ((RREG32(mmMC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
+ }
+
+ ret = ci_calculate_mclk_params(adev, memory_clock, memory_level, memory_level->StrobeEnable, dll_state_on);
+ if (ret)
+ return ret;
+
+ memory_level->MinVddc = cpu_to_be32(memory_level->MinVddc * VOLTAGE_SCALE);
+ memory_level->MinVddcPhases = cpu_to_be32(memory_level->MinVddcPhases);
+ memory_level->MinVddci = cpu_to_be32(memory_level->MinVddci * VOLTAGE_SCALE);
+ memory_level->MinMvdd = cpu_to_be32(memory_level->MinMvdd * VOLTAGE_SCALE);
+
+ memory_level->MclkFrequency = cpu_to_be32(memory_level->MclkFrequency);
+ memory_level->ActivityLevel = cpu_to_be16(memory_level->ActivityLevel);
+ memory_level->MpllFuncCntl = cpu_to_be32(memory_level->MpllFuncCntl);
+ memory_level->MpllFuncCntl_1 = cpu_to_be32(memory_level->MpllFuncCntl_1);
+ memory_level->MpllFuncCntl_2 = cpu_to_be32(memory_level->MpllFuncCntl_2);
+ memory_level->MpllAdFuncCntl = cpu_to_be32(memory_level->MpllAdFuncCntl);
+ memory_level->MpllDqFuncCntl = cpu_to_be32(memory_level->MpllDqFuncCntl);
+ memory_level->MclkPwrmgtCntl = cpu_to_be32(memory_level->MclkPwrmgtCntl);
+ memory_level->DllCntl = cpu_to_be32(memory_level->DllCntl);
+ memory_level->MpllSs1 = cpu_to_be32(memory_level->MpllSs1);
+ memory_level->MpllSs2 = cpu_to_be32(memory_level->MpllSs2);
+
+ return 0;
+}
+
+static int ci_populate_smc_acpi_level(struct amdgpu_device *adev,
+ SMU7_Discrete_DpmTable *table)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct atom_clock_dividers dividers;
+ SMU7_Discrete_VoltageLevel voltage_level;
+ u32 spll_func_cntl = pi->clock_registers.cg_spll_func_cntl;
+ u32 spll_func_cntl_2 = pi->clock_registers.cg_spll_func_cntl_2;
+ u32 dll_cntl = pi->clock_registers.dll_cntl;
+ u32 mclk_pwrmgt_cntl = pi->clock_registers.mclk_pwrmgt_cntl;
+ int ret;
+
+ table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+ if (pi->acpi_vddc)
+ table->ACPILevel.MinVddc = cpu_to_be32(pi->acpi_vddc * VOLTAGE_SCALE);
+ else
+ table->ACPILevel.MinVddc = cpu_to_be32(pi->min_vddc_in_pp_table * VOLTAGE_SCALE);
+
+ table->ACPILevel.MinVddcPhases = pi->vddc_phase_shed_control ? 0 : 1;
+
+ table->ACPILevel.SclkFrequency = adev->clock.spll.reference_freq;
+
+ ret = amdgpu_atombios_get_clock_dividers(adev,
+ COMPUTE_GPUCLK_INPUT_FLAG_SCLK,
+ table->ACPILevel.SclkFrequency, false, &dividers);
+ if (ret)
+ return ret;
+
+ table->ACPILevel.SclkDid = (u8)dividers.post_divider;
+ table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+ table->ACPILevel.DeepSleepDivId = 0;
+
+ spll_func_cntl &= ~CG_SPLL_FUNC_CNTL__SPLL_PWRON_MASK;
+ spll_func_cntl |= CG_SPLL_FUNC_CNTL__SPLL_RESET_MASK;
+
+ spll_func_cntl_2 &= ~CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= (4 << CG_SPLL_FUNC_CNTL_2__SCLK_MUX_SEL__SHIFT);
+
+ table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
+ table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
+ table->ACPILevel.CgSpllFuncCntl3 = pi->clock_registers.cg_spll_func_cntl_3;
+ table->ACPILevel.CgSpllFuncCntl4 = pi->clock_registers.cg_spll_func_cntl_4;
+ table->ACPILevel.SpllSpreadSpectrum = pi->clock_registers.cg_spll_spread_spectrum;
+ table->ACPILevel.SpllSpreadSpectrum2 = pi->clock_registers.cg_spll_spread_spectrum_2;
+ table->ACPILevel.CcPwrDynRm = 0;
+ table->ACPILevel.CcPwrDynRm1 = 0;
+
+ table->ACPILevel.Flags = cpu_to_be32(table->ACPILevel.Flags);
+ table->ACPILevel.MinVddcPhases = cpu_to_be32(table->ACPILevel.MinVddcPhases);
+ table->ACPILevel.SclkFrequency = cpu_to_be32(table->ACPILevel.SclkFrequency);
+ table->ACPILevel.CgSpllFuncCntl = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl);
+ table->ACPILevel.CgSpllFuncCntl2 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl2);
+ table->ACPILevel.CgSpllFuncCntl3 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl3);
+ table->ACPILevel.CgSpllFuncCntl4 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl4);
+ table->ACPILevel.SpllSpreadSpectrum = cpu_to_be32(table->ACPILevel.SpllSpreadSpectrum);
+ table->ACPILevel.SpllSpreadSpectrum2 = cpu_to_be32(table->ACPILevel.SpllSpreadSpectrum2);
+ table->ACPILevel.CcPwrDynRm = cpu_to_be32(table->ACPILevel.CcPwrDynRm);
+ table->ACPILevel.CcPwrDynRm1 = cpu_to_be32(table->ACPILevel.CcPwrDynRm1);
+
+ table->MemoryACPILevel.MinVddc = table->ACPILevel.MinVddc;
+ table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;
+
+ if (pi->vddci_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
+ if (pi->acpi_vddci)
+ table->MemoryACPILevel.MinVddci =
+ cpu_to_be32(pi->acpi_vddci * VOLTAGE_SCALE);
+ else
+ table->MemoryACPILevel.MinVddci =
+ cpu_to_be32(pi->min_vddci_in_pp_table * VOLTAGE_SCALE);
+ }
+
+ if (ci_populate_mvdd_value(adev, 0, &voltage_level))
+ table->MemoryACPILevel.MinMvdd = 0;
+ else
+ table->MemoryACPILevel.MinMvdd =
+ cpu_to_be32(voltage_level.Voltage * VOLTAGE_SCALE);
+
+ mclk_pwrmgt_cntl |= MCLK_PWRMGT_CNTL__MRDCK0_RESET_MASK |
+ MCLK_PWRMGT_CNTL__MRDCK1_RESET_MASK;
+ mclk_pwrmgt_cntl &= ~(MCLK_PWRMGT_CNTL__MRDCK0_PDNB_MASK |
+ MCLK_PWRMGT_CNTL__MRDCK1_PDNB_MASK);
+
+ dll_cntl &= ~(DLL_CNTL__MRDCK0_BYPASS_MASK | DLL_CNTL__MRDCK1_BYPASS_MASK);
+
+ table->MemoryACPILevel.DllCntl = cpu_to_be32(dll_cntl);
+ table->MemoryACPILevel.MclkPwrmgtCntl = cpu_to_be32(mclk_pwrmgt_cntl);
+ table->MemoryACPILevel.MpllAdFuncCntl =
+ cpu_to_be32(pi->clock_registers.mpll_ad_func_cntl);
+ table->MemoryACPILevel.MpllDqFuncCntl =
+ cpu_to_be32(pi->clock_registers.mpll_dq_func_cntl);
+ table->MemoryACPILevel.MpllFuncCntl =
+ cpu_to_be32(pi->clock_registers.mpll_func_cntl);
+ table->MemoryACPILevel.MpllFuncCntl_1 =
+ cpu_to_be32(pi->clock_registers.mpll_func_cntl_1);
+ table->MemoryACPILevel.MpllFuncCntl_2 =
+ cpu_to_be32(pi->clock_registers.mpll_func_cntl_2);
+ table->MemoryACPILevel.MpllSs1 = cpu_to_be32(pi->clock_registers.mpll_ss1);
+ table->MemoryACPILevel.MpllSs2 = cpu_to_be32(pi->clock_registers.mpll_ss2);
+
+ table->MemoryACPILevel.EnabledForThrottle = 0;
+ table->MemoryACPILevel.EnabledForActivity = 0;
+ table->MemoryACPILevel.UpH = 0;
+ table->MemoryACPILevel.DownH = 100;
+ table->MemoryACPILevel.VoltageDownH = 0;
+ table->MemoryACPILevel.ActivityLevel =
+ cpu_to_be16((u16)pi->mclk_activity_target);
+
+ table->MemoryACPILevel.StutterEnable = false;
+ table->MemoryACPILevel.StrobeEnable = false;
+ table->MemoryACPILevel.EdcReadEnable = false;
+ table->MemoryACPILevel.EdcWriteEnable = false;
+ table->MemoryACPILevel.RttEnable = false;
+
+ return 0;
+}
+
+
+static int ci_enable_ulv(struct amdgpu_device *adev, bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_ulv_parm *ulv = &pi->ulv;
+
+ if (ulv->supported) {
+ if (enable)
+ return (amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_EnableULV) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+ else
+ return (amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_DisableULV) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ci_populate_ulv_level(struct amdgpu_device *adev,
+ SMU7_Discrete_Ulv *state)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u16 ulv_voltage = adev->pm.dpm.backbias_response_time;
+
+ state->CcPwrDynRm = 0;
+ state->CcPwrDynRm1 = 0;
+
+ if (ulv_voltage == 0) {
+ pi->ulv.supported = false;
+ return 0;
+ }
+
+ if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
+ if (ulv_voltage > adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v)
+ state->VddcOffset = 0;
+ else
+ state->VddcOffset =
+ adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v - ulv_voltage;
+ } else {
+ if (ulv_voltage > adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v)
+ state->VddcOffsetVid = 0;
+ else
+ state->VddcOffsetVid = (u8)
+ ((adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v - ulv_voltage) *
+ VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
+ }
+ state->VddcPhase = pi->vddc_phase_shed_control ? 0 : 1;
+
+ state->CcPwrDynRm = cpu_to_be32(state->CcPwrDynRm);
+ state->CcPwrDynRm1 = cpu_to_be32(state->CcPwrDynRm1);
+ state->VddcOffset = cpu_to_be16(state->VddcOffset);
+
+ return 0;
+}
+
+static int ci_calculate_sclk_params(struct amdgpu_device *adev,
+ u32 engine_clock,
+ SMU7_Discrete_GraphicsLevel *sclk)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct atom_clock_dividers dividers;
+ u32 spll_func_cntl_3 = pi->clock_registers.cg_spll_func_cntl_3;
+ u32 spll_func_cntl_4 = pi->clock_registers.cg_spll_func_cntl_4;
+ u32 cg_spll_spread_spectrum = pi->clock_registers.cg_spll_spread_spectrum;
+ u32 cg_spll_spread_spectrum_2 = pi->clock_registers.cg_spll_spread_spectrum_2;
+ u32 reference_clock = adev->clock.spll.reference_freq;
+ u32 reference_divider;
+ u32 fbdiv;
+ int ret;
+
+ ret = amdgpu_atombios_get_clock_dividers(adev,
+ COMPUTE_GPUCLK_INPUT_FLAG_SCLK,
+ engine_clock, false, &dividers);
+ if (ret)
+ return ret;
+
+ reference_divider = 1 + dividers.ref_div;
+ fbdiv = dividers.fb_div & 0x3FFFFFF;
+
+ spll_func_cntl_3 &= ~CG_SPLL_FUNC_CNTL_3__SPLL_FB_DIV_MASK;
+ spll_func_cntl_3 |= (fbdiv << CG_SPLL_FUNC_CNTL_3__SPLL_FB_DIV__SHIFT);
+ spll_func_cntl_3 |= CG_SPLL_FUNC_CNTL_3__SPLL_DITHEN_MASK;
+
+ if (pi->caps_sclk_ss_support) {
+ struct amdgpu_atom_ss ss;
+ u32 vco_freq = engine_clock * dividers.post_div;
+
+ if (amdgpu_atombios_get_asic_ss_info(adev, &ss,
+ ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
+ u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
+ u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000);
+
+ cg_spll_spread_spectrum &= ~(CG_SPLL_SPREAD_SPECTRUM__CLKS_MASK | CG_SPLL_SPREAD_SPECTRUM__SSEN_MASK);
+ cg_spll_spread_spectrum |= (clk_s << CG_SPLL_SPREAD_SPECTRUM__CLKS__SHIFT);
+ cg_spll_spread_spectrum |= (1 << CG_SPLL_SPREAD_SPECTRUM__SSEN__SHIFT);
+
+ cg_spll_spread_spectrum_2 &= ~CG_SPLL_SPREAD_SPECTRUM_2__CLKV_MASK;
+ cg_spll_spread_spectrum_2 |= (clk_v << CG_SPLL_SPREAD_SPECTRUM_2__CLKV__SHIFT);
+ }
+ }
+
+ 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 = (u8)dividers.post_divider;
+
+ return 0;
+}
+
+static int ci_populate_single_graphic_level(struct amdgpu_device *adev,
+ u32 engine_clock,
+ u16 sclk_activity_level_t,
+ SMU7_Discrete_GraphicsLevel *graphic_level)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ int ret;
+
+ ret = ci_calculate_sclk_params(adev, engine_clock, graphic_level);
+ if (ret)
+ return ret;
+
+ ret = ci_get_dependency_volt_by_clk(adev,
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+ engine_clock, &graphic_level->MinVddc);
+ if (ret)
+ return ret;
+
+ graphic_level->SclkFrequency = engine_clock;
+
+ graphic_level->Flags = 0;
+ graphic_level->MinVddcPhases = 1;
+
+ if (pi->vddc_phase_shed_control)
+ ci_populate_phase_value_based_on_sclk(adev,
+ &adev->pm.dpm.dyn_state.phase_shedding_limits_table,
+ engine_clock,
+ &graphic_level->MinVddcPhases);
+
+ graphic_level->ActivityLevel = sclk_activity_level_t;
+
+ graphic_level->CcPwrDynRm = 0;
+ graphic_level->CcPwrDynRm1 = 0;
+ graphic_level->EnabledForThrottle = 1;
+ graphic_level->UpH = 0;
+ graphic_level->DownH = 0;
+ graphic_level->VoltageDownH = 0;
+ graphic_level->PowerThrottle = 0;
+
+ if (pi->caps_sclk_ds)
+ graphic_level->DeepSleepDivId = ci_get_sleep_divider_id_from_clock(adev,
+ engine_clock,
+ CISLAND_MINIMUM_ENGINE_CLOCK);
+
+ graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
+
+ graphic_level->Flags = cpu_to_be32(graphic_level->Flags);
+ graphic_level->MinVddc = cpu_to_be32(graphic_level->MinVddc * VOLTAGE_SCALE);
+ graphic_level->MinVddcPhases = cpu_to_be32(graphic_level->MinVddcPhases);
+ graphic_level->SclkFrequency = cpu_to_be32(graphic_level->SclkFrequency);
+ graphic_level->ActivityLevel = cpu_to_be16(graphic_level->ActivityLevel);
+ graphic_level->CgSpllFuncCntl3 = cpu_to_be32(graphic_level->CgSpllFuncCntl3);
+ graphic_level->CgSpllFuncCntl4 = cpu_to_be32(graphic_level->CgSpllFuncCntl4);
+ graphic_level->SpllSpreadSpectrum = cpu_to_be32(graphic_level->SpllSpreadSpectrum);
+ graphic_level->SpllSpreadSpectrum2 = cpu_to_be32(graphic_level->SpllSpreadSpectrum2);
+ graphic_level->CcPwrDynRm = cpu_to_be32(graphic_level->CcPwrDynRm);
+ graphic_level->CcPwrDynRm1 = cpu_to_be32(graphic_level->CcPwrDynRm1);
+ graphic_level->EnabledForActivity = 1;
+
+ return 0;
+}
+
+static int ci_populate_all_graphic_levels(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_dpm_table *dpm_table = &pi->dpm_table;
+ u32 level_array_address = pi->dpm_table_start +
+ offsetof(SMU7_Discrete_DpmTable, GraphicsLevel);
+ u32 level_array_size = sizeof(SMU7_Discrete_GraphicsLevel) *
+ SMU7_MAX_LEVELS_GRAPHICS;
+ SMU7_Discrete_GraphicsLevel *levels = pi->smc_state_table.GraphicsLevel;
+ u32 i, ret;
+
+ memset(levels, 0, level_array_size);
+
+ for (i = 0; i < dpm_table->sclk_table.count; i++) {
+ ret = ci_populate_single_graphic_level(adev,
+ dpm_table->sclk_table.dpm_levels[i].value,
+ (u16)pi->activity_target[i],
+ &pi->smc_state_table.GraphicsLevel[i]);
+ if (ret)
+ return ret;
+ if (i > 1)
+ pi->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
+ if (i == (dpm_table->sclk_table.count - 1))
+ pi->smc_state_table.GraphicsLevel[i].DisplayWatermark =
+ PPSMC_DISPLAY_WATERMARK_HIGH;
+ }
+
+ pi->smc_state_table.GraphicsDpmLevelCount = (u8)dpm_table->sclk_table.count;
+ pi->dpm_level_enable_mask.sclk_dpm_enable_mask =
+ ci_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
+
+ ret = amdgpu_ci_copy_bytes_to_smc(adev, level_array_address,
+ (u8 *)levels, level_array_size,
+ pi->sram_end);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ci_populate_ulv_state(struct amdgpu_device *adev,
+ SMU7_Discrete_Ulv *ulv_level)
+{
+ return ci_populate_ulv_level(adev, ulv_level);
+}
+
+static int ci_populate_all_memory_levels(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_dpm_table *dpm_table = &pi->dpm_table;
+ u32 level_array_address = pi->dpm_table_start +
+ offsetof(SMU7_Discrete_DpmTable, MemoryLevel);
+ u32 level_array_size = sizeof(SMU7_Discrete_MemoryLevel) *
+ SMU7_MAX_LEVELS_MEMORY;
+ SMU7_Discrete_MemoryLevel *levels = pi->smc_state_table.MemoryLevel;
+ u32 i, ret;
+
+ memset(levels, 0, level_array_size);
+
+ for (i = 0; i < dpm_table->mclk_table.count; i++) {
+ if (dpm_table->mclk_table.dpm_levels[i].value == 0)
+ return -EINVAL;
+ ret = ci_populate_single_memory_level(adev,
+ dpm_table->mclk_table.dpm_levels[i].value,
+ &pi->smc_state_table.MemoryLevel[i]);
+ if (ret)
+ return ret;
+ }
+
+ if ((dpm_table->mclk_table.count >= 2) &&
+ ((adev->pdev->device == 0x67B0) || (adev->pdev->device == 0x67B1))) {
+ pi->smc_state_table.MemoryLevel[1].MinVddc =
+ pi->smc_state_table.MemoryLevel[0].MinVddc;
+ pi->smc_state_table.MemoryLevel[1].MinVddcPhases =
+ pi->smc_state_table.MemoryLevel[0].MinVddcPhases;
+ }
+
+ pi->smc_state_table.MemoryLevel[0].ActivityLevel = cpu_to_be16(0x1F);
+
+ pi->smc_state_table.MemoryDpmLevelCount = (u8)dpm_table->mclk_table.count;
+ pi->dpm_level_enable_mask.mclk_dpm_enable_mask =
+ ci_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
+
+ pi->smc_state_table.MemoryLevel[dpm_table->mclk_table.count - 1].DisplayWatermark =
+ PPSMC_DISPLAY_WATERMARK_HIGH;
+
+ ret = amdgpu_ci_copy_bytes_to_smc(adev, level_array_address,
+ (u8 *)levels, level_array_size,
+ pi->sram_end);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void ci_reset_single_dpm_table(struct amdgpu_device *adev,
+ struct ci_single_dpm_table* dpm_table,
+ u32 count)
+{
+ u32 i;
+
+ dpm_table->count = count;
+ for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++)
+ dpm_table->dpm_levels[i].enabled = false;
+}
+
+static void ci_setup_pcie_table_entry(struct ci_single_dpm_table* dpm_table,
+ u32 index, u32 pcie_gen, u32 pcie_lanes)
+{
+ dpm_table->dpm_levels[index].value = pcie_gen;
+ dpm_table->dpm_levels[index].param1 = pcie_lanes;
+ dpm_table->dpm_levels[index].enabled = true;
+}
+
+static int ci_setup_default_pcie_tables(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ if (!pi->use_pcie_performance_levels && !pi->use_pcie_powersaving_levels)
+ return -EINVAL;
+
+ if (pi->use_pcie_performance_levels && !pi->use_pcie_powersaving_levels) {
+ pi->pcie_gen_powersaving = pi->pcie_gen_performance;
+ pi->pcie_lane_powersaving = pi->pcie_lane_performance;
+ } else if (!pi->use_pcie_performance_levels && pi->use_pcie_powersaving_levels) {
+ pi->pcie_gen_performance = pi->pcie_gen_powersaving;
+ pi->pcie_lane_performance = pi->pcie_lane_powersaving;
+ }
+
+ ci_reset_single_dpm_table(adev,
+ &pi->dpm_table.pcie_speed_table,
+ SMU7_MAX_LEVELS_LINK);
+
+ if (adev->asic_type == CHIP_BONAIRE)
+ ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0,
+ pi->pcie_gen_powersaving.min,
+ pi->pcie_lane_powersaving.max);
+ else
+ ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0,
+ pi->pcie_gen_powersaving.min,
+ pi->pcie_lane_powersaving.min);
+ ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 1,
+ pi->pcie_gen_performance.min,
+ pi->pcie_lane_performance.min);
+ ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 2,
+ pi->pcie_gen_powersaving.min,
+ pi->pcie_lane_powersaving.max);
+ ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 3,
+ pi->pcie_gen_performance.min,
+ pi->pcie_lane_performance.max);
+ ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 4,
+ pi->pcie_gen_powersaving.max,
+ pi->pcie_lane_powersaving.max);
+ ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 5,
+ pi->pcie_gen_performance.max,
+ pi->pcie_lane_performance.max);
+
+ pi->dpm_table.pcie_speed_table.count = 6;
+
+ return 0;
+}
+
+static int ci_setup_default_dpm_tables(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct amdgpu_clock_voltage_dependency_table *allowed_sclk_vddc_table =
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
+ struct amdgpu_clock_voltage_dependency_table *allowed_mclk_table =
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk;
+ struct amdgpu_cac_leakage_table *std_voltage_table =
+ &adev->pm.dpm.dyn_state.cac_leakage_table;
+ u32 i;
+
+ if (allowed_sclk_vddc_table == NULL)
+ return -EINVAL;
+ if (allowed_sclk_vddc_table->count < 1)
+ return -EINVAL;
+ if (allowed_mclk_table == NULL)
+ return -EINVAL;
+ if (allowed_mclk_table->count < 1)
+ return -EINVAL;
+
+ memset(&pi->dpm_table, 0, sizeof(struct ci_dpm_table));
+
+ ci_reset_single_dpm_table(adev,
+ &pi->dpm_table.sclk_table,
+ SMU7_MAX_LEVELS_GRAPHICS);
+ ci_reset_single_dpm_table(adev,
+ &pi->dpm_table.mclk_table,
+ SMU7_MAX_LEVELS_MEMORY);
+ ci_reset_single_dpm_table(adev,
+ &pi->dpm_table.vddc_table,
+ SMU7_MAX_LEVELS_VDDC);
+ ci_reset_single_dpm_table(adev,
+ &pi->dpm_table.vddci_table,
+ SMU7_MAX_LEVELS_VDDCI);
+ ci_reset_single_dpm_table(adev,
+ &pi->dpm_table.mvdd_table,
+ SMU7_MAX_LEVELS_MVDD);
+
+ pi->dpm_table.sclk_table.count = 0;
+ for (i = 0; i < allowed_sclk_vddc_table->count; i++) {
+ if ((i == 0) ||
+ (pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count-1].value !=
+ allowed_sclk_vddc_table->entries[i].clk)) {
+ pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].value =
+ allowed_sclk_vddc_table->entries[i].clk;
+ pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].enabled =
+ (i == 0) ? true : false;
+ pi->dpm_table.sclk_table.count++;
+ }
+ }
+
+ pi->dpm_table.mclk_table.count = 0;
+ for (i = 0; i < allowed_mclk_table->count; i++) {
+ if ((i == 0) ||
+ (pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count-1].value !=
+ allowed_mclk_table->entries[i].clk)) {
+ pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].value =
+ allowed_mclk_table->entries[i].clk;
+ pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].enabled =
+ (i == 0) ? true : false;
+ pi->dpm_table.mclk_table.count++;
+ }
+ }
+
+ for (i = 0; i < allowed_sclk_vddc_table->count; i++) {
+ pi->dpm_table.vddc_table.dpm_levels[i].value =
+ allowed_sclk_vddc_table->entries[i].v;
+ pi->dpm_table.vddc_table.dpm_levels[i].param1 =
+ std_voltage_table->entries[i].leakage;
+ pi->dpm_table.vddc_table.dpm_levels[i].enabled = true;
+ }
+ pi->dpm_table.vddc_table.count = allowed_sclk_vddc_table->count;
+
+ allowed_mclk_table = &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk;
+ if (allowed_mclk_table) {
+ for (i = 0; i < allowed_mclk_table->count; i++) {
+ pi->dpm_table.vddci_table.dpm_levels[i].value =
+ allowed_mclk_table->entries[i].v;
+ pi->dpm_table.vddci_table.dpm_levels[i].enabled = true;
+ }
+ pi->dpm_table.vddci_table.count = allowed_mclk_table->count;
+ }
+
+ allowed_mclk_table = &adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk;
+ if (allowed_mclk_table) {
+ for (i = 0; i < allowed_mclk_table->count; i++) {
+ pi->dpm_table.mvdd_table.dpm_levels[i].value =
+ allowed_mclk_table->entries[i].v;
+ pi->dpm_table.mvdd_table.dpm_levels[i].enabled = true;
+ }
+ pi->dpm_table.mvdd_table.count = allowed_mclk_table->count;
+ }
+
+ ci_setup_default_pcie_tables(adev);
+
+ return 0;
+}
+
+static int ci_find_boot_level(struct ci_single_dpm_table *table,
+ u32 value, u32 *boot_level)
+{
+ u32 i;
+ int ret = -EINVAL;
+
+ for(i = 0; i < table->count; i++) {
+ if (value == table->dpm_levels[i].value) {
+ *boot_level = i;
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+static int ci_init_smc_table(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_ulv_parm *ulv = &pi->ulv;
+ struct amdgpu_ps *amdgpu_boot_state = adev->pm.dpm.boot_ps;
+ SMU7_Discrete_DpmTable *table = &pi->smc_state_table;
+ int ret;
+
+ ret = ci_setup_default_dpm_tables(adev);
+ if (ret)
+ return ret;
+
+ if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE)
+ ci_populate_smc_voltage_tables(adev, table);
+
+ ci_init_fps_limits(adev);
+
+ if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
+ table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+ if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+ table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+ if (adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5)
+ table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+ if (ulv->supported) {
+ ret = ci_populate_ulv_state(adev, &pi->smc_state_table.Ulv);
+ if (ret)
+ return ret;
+ WREG32_SMC(ixCG_ULV_PARAMETER, ulv->cg_ulv_parameter);
+ }
+
+ ret = ci_populate_all_graphic_levels(adev);
+ if (ret)
+ return ret;
+
+ ret = ci_populate_all_memory_levels(adev);
+ if (ret)
+ return ret;
+
+ ci_populate_smc_link_level(adev, table);
+
+ ret = ci_populate_smc_acpi_level(adev, table);
+ if (ret)
+ return ret;
+
+ ret = ci_populate_smc_vce_level(adev, table);
+ if (ret)
+ return ret;
+
+ ret = ci_populate_smc_acp_level(adev, table);
+ if (ret)
+ return ret;
+
+ ret = ci_populate_smc_samu_level(adev, table);
+ if (ret)
+ return ret;
+
+ ret = ci_do_program_memory_timing_parameters(adev);
+ if (ret)
+ return ret;
+
+ ret = ci_populate_smc_uvd_level(adev, table);
+ if (ret)
+ return ret;
+
+ table->UvdBootLevel = 0;
+ table->VceBootLevel = 0;
+ table->AcpBootLevel = 0;
+ table->SamuBootLevel = 0;
+ table->GraphicsBootLevel = 0;
+ table->MemoryBootLevel = 0;
+
+ ret = ci_find_boot_level(&pi->dpm_table.sclk_table,
+ pi->vbios_boot_state.sclk_bootup_value,
+ (u32 *)&pi->smc_state_table.GraphicsBootLevel);
+
+ ret = ci_find_boot_level(&pi->dpm_table.mclk_table,
+ pi->vbios_boot_state.mclk_bootup_value,
+ (u32 *)&pi->smc_state_table.MemoryBootLevel);
+
+ table->BootVddc = pi->vbios_boot_state.vddc_bootup_value;
+ table->BootVddci = pi->vbios_boot_state.vddci_bootup_value;
+ table->BootMVdd = pi->vbios_boot_state.mvdd_bootup_value;
+
+ ci_populate_smc_initial_state(adev, amdgpu_boot_state);
+
+ ret = ci_populate_bapm_parameters_in_dpm_table(adev);
+ if (ret)
+ return ret;
+
+ table->UVDInterval = 1;
+ table->VCEInterval = 1;
+ table->ACPInterval = 1;
+ table->SAMUInterval = 1;
+ table->GraphicsVoltageChangeEnable = 1;
+ table->GraphicsThermThrottleEnable = 1;
+ table->GraphicsInterval = 1;
+ table->VoltageInterval = 1;
+ table->ThermalInterval = 1;
+ table->TemperatureLimitHigh = (u16)((pi->thermal_temp_setting.temperature_high *
+ CISLANDS_Q88_FORMAT_CONVERSION_UNIT) / 1000);
+ table->TemperatureLimitLow = (u16)((pi->thermal_temp_setting.temperature_low *
+ CISLANDS_Q88_FORMAT_CONVERSION_UNIT) / 1000);
+ table->MemoryVoltageChangeEnable = 1;
+ table->MemoryInterval = 1;
+ table->VoltageResponseTime = 0;
+ table->VddcVddciDelta = 4000;
+ table->PhaseResponseTime = 0;
+ table->MemoryThermThrottleEnable = 1;
+ table->PCIeBootLinkLevel = pi->dpm_table.pcie_speed_table.count - 1;
+ table->PCIeGenInterval = 1;
+ if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2)
+ table->SVI2Enable = 1;
+ else
+ table->SVI2Enable = 0;
+
+ table->ThermGpio = 17;
+ table->SclkStepSize = 0x4000;
+
+ table->SystemFlags = cpu_to_be32(table->SystemFlags);
+ table->SmioMaskVddcVid = cpu_to_be32(table->SmioMaskVddcVid);
+ table->SmioMaskVddcPhase = cpu_to_be32(table->SmioMaskVddcPhase);
+ table->SmioMaskVddciVid = cpu_to_be32(table->SmioMaskVddciVid);
+ table->SmioMaskMvddVid = cpu_to_be32(table->SmioMaskMvddVid);
+ table->SclkStepSize = cpu_to_be32(table->SclkStepSize);
+ table->TemperatureLimitHigh = cpu_to_be16(table->TemperatureLimitHigh);
+ table->TemperatureLimitLow = cpu_to_be16(table->TemperatureLimitLow);
+ table->VddcVddciDelta = cpu_to_be16(table->VddcVddciDelta);
+ table->VoltageResponseTime = cpu_to_be16(table->VoltageResponseTime);
+ table->PhaseResponseTime = cpu_to_be16(table->PhaseResponseTime);
+ table->BootVddc = cpu_to_be16(table->BootVddc * VOLTAGE_SCALE);
+ table->BootVddci = cpu_to_be16(table->BootVddci * VOLTAGE_SCALE);
+ table->BootMVdd = cpu_to_be16(table->BootMVdd * VOLTAGE_SCALE);
+
+ ret = amdgpu_ci_copy_bytes_to_smc(adev,
+ pi->dpm_table_start +
+ offsetof(SMU7_Discrete_DpmTable, SystemFlags),
+ (u8 *)&table->SystemFlags,
+ sizeof(SMU7_Discrete_DpmTable) - 3 * sizeof(SMU7_PIDController),
+ pi->sram_end);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void ci_trim_single_dpm_states(struct amdgpu_device *adev,
+ struct ci_single_dpm_table *dpm_table,
+ u32 low_limit, u32 high_limit)
+{
+ u32 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;
+ }
+}
+
+static void ci_trim_pcie_dpm_states(struct amdgpu_device *adev,
+ u32 speed_low, u32 lanes_low,
+ u32 speed_high, u32 lanes_high)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_single_dpm_table *pcie_table = &pi->dpm_table.pcie_speed_table;
+ u32 i, j;
+
+ for (i = 0; i < pcie_table->count; i++) {
+ if ((pcie_table->dpm_levels[i].value < speed_low) ||
+ (pcie_table->dpm_levels[i].param1 < lanes_low) ||
+ (pcie_table->dpm_levels[i].value > speed_high) ||
+ (pcie_table->dpm_levels[i].param1 > lanes_high))
+ pcie_table->dpm_levels[i].enabled = false;
+ else
+ pcie_table->dpm_levels[i].enabled = true;
+ }
+
+ for (i = 0; i < pcie_table->count; i++) {
+ if (pcie_table->dpm_levels[i].enabled) {
+ for (j = i + 1; j < pcie_table->count; j++) {
+ if (pcie_table->dpm_levels[j].enabled) {
+ if ((pcie_table->dpm_levels[i].value == pcie_table->dpm_levels[j].value) &&
+ (pcie_table->dpm_levels[i].param1 == pcie_table->dpm_levels[j].param1))
+ pcie_table->dpm_levels[j].enabled = false;
+ }
+ }
+ }
+ }
+}
+
+static int ci_trim_dpm_states(struct amdgpu_device *adev,
+ struct amdgpu_ps *amdgpu_state)
+{
+ struct ci_ps *state = ci_get_ps(amdgpu_state);
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 high_limit_count;
+
+ if (state->performance_level_count < 1)
+ return -EINVAL;
+
+ if (state->performance_level_count == 1)
+ high_limit_count = 0;
+ else
+ high_limit_count = 1;
+
+ ci_trim_single_dpm_states(adev,
+ &pi->dpm_table.sclk_table,
+ state->performance_levels[0].sclk,
+ state->performance_levels[high_limit_count].sclk);
+
+ ci_trim_single_dpm_states(adev,
+ &pi->dpm_table.mclk_table,
+ state->performance_levels[0].mclk,
+ state->performance_levels[high_limit_count].mclk);
+
+ ci_trim_pcie_dpm_states(adev,
+ state->performance_levels[0].pcie_gen,
+ state->performance_levels[0].pcie_lane,
+ state->performance_levels[high_limit_count].pcie_gen,
+ state->performance_levels[high_limit_count].pcie_lane);
+
+ return 0;
+}
+
+static int ci_apply_disp_minimum_voltage_request(struct amdgpu_device *adev)
+{
+ struct amdgpu_clock_voltage_dependency_table *disp_voltage_table =
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk;
+ struct amdgpu_clock_voltage_dependency_table *vddc_table =
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
+ u32 requested_voltage = 0;
+ u32 i;
+
+ if (disp_voltage_table == NULL)
+ return -EINVAL;
+ if (!disp_voltage_table->count)
+ return -EINVAL;
+
+ for (i = 0; i < disp_voltage_table->count; i++) {
+ if (adev->clock.current_dispclk == disp_voltage_table->entries[i].clk)
+ requested_voltage = disp_voltage_table->entries[i].v;
+ }
+
+ for (i = 0; i < vddc_table->count; i++) {
+ if (requested_voltage <= vddc_table->entries[i].v) {
+ requested_voltage = vddc_table->entries[i].v;
+ return (amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_VddC_Request,
+ requested_voltage * VOLTAGE_SCALE) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int ci_upload_dpm_level_enable_mask(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ PPSMC_Result result;
+
+ ci_apply_disp_minimum_voltage_request(adev);
+
+ if (!pi->sclk_dpm_key_disabled) {
+ if (pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+ result = amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SCLKDPM_SetEnabledMask,
+ pi->dpm_level_enable_mask.sclk_dpm_enable_mask);
+ if (result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+ }
+
+ if (!pi->mclk_dpm_key_disabled) {
+ if (pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+ result = amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_MCLKDPM_SetEnabledMask,
+ pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
+ if (result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+ }
+
+#if 0
+ if (!pi->pcie_dpm_key_disabled) {
+ if (pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
+ result = amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_PCIeDPM_SetEnabledMask,
+ pi->dpm_level_enable_mask.pcie_dpm_enable_mask);
+ if (result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static void ci_find_dpm_states_clocks_in_dpm_table(struct amdgpu_device *adev,
+ struct amdgpu_ps *amdgpu_state)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_ps *state = ci_get_ps(amdgpu_state);
+ struct ci_single_dpm_table *sclk_table = &pi->dpm_table.sclk_table;
+ u32 sclk = state->performance_levels[state->performance_level_count-1].sclk;
+ struct ci_single_dpm_table *mclk_table = &pi->dpm_table.mclk_table;
+ u32 mclk = state->performance_levels[state->performance_level_count-1].mclk;
+ u32 i;
+
+ pi->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) {
+ pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
+ } else {
+ /* XXX check display min clock requirements */
+ if (CISLAND_MINIMUM_ENGINE_CLOCK != CISLAND_MINIMUM_ENGINE_CLOCK)
+ pi->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)
+ pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
+
+ if (adev->pm.dpm.current_active_crtc_count !=
+ adev->pm.dpm.new_active_crtc_count)
+ pi->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
+}
+
+static int ci_populate_and_upload_sclk_mclk_dpm_levels(struct amdgpu_device *adev,
+ struct amdgpu_ps *amdgpu_state)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_ps *state = ci_get_ps(amdgpu_state);
+ u32 sclk = state->performance_levels[state->performance_level_count-1].sclk;
+ u32 mclk = state->performance_levels[state->performance_level_count-1].mclk;
+ struct ci_dpm_table *dpm_table = &pi->dpm_table;
+ int ret;
+
+ if (!pi->need_update_smu7_dpm_table)
+ return 0;
+
+ if (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK)
+ dpm_table->sclk_table.dpm_levels[dpm_table->sclk_table.count-1].value = sclk;
+
+ if (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)
+ dpm_table->mclk_table.dpm_levels[dpm_table->mclk_table.count-1].value = mclk;
+
+ if (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK)) {
+ ret = ci_populate_all_graphic_levels(adev);
+ if (ret)
+ return ret;
+ }
+
+ if (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_MCLK | DPMTABLE_UPDATE_MCLK)) {
+ ret = ci_populate_all_memory_levels(adev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ci_enable_uvd_dpm(struct amdgpu_device *adev, bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ const struct amdgpu_clock_and_voltage_limits *max_limits;
+ int i;
+
+ if (adev->pm.dpm.ac_power)
+ max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+ else
+ max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
+
+ if (enable) {
+ pi->dpm_level_enable_mask.uvd_dpm_enable_mask = 0;
+
+ for (i = adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
+ if (adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
+ pi->dpm_level_enable_mask.uvd_dpm_enable_mask |= 1 << i;
+
+ if (!pi->caps_uvd_dpm)
+ break;
+ }
+ }
+
+ amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_UVDDPM_SetEnabledMask,
+ pi->dpm_level_enable_mask.uvd_dpm_enable_mask);
+
+ if (pi->last_mclk_dpm_enable_mask & 0x1) {
+ pi->uvd_enabled = true;
+ pi->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
+ amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_MCLKDPM_SetEnabledMask,
+ pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
+ }
+ } else {
+ if (pi->last_mclk_dpm_enable_mask & 0x1) {
+ pi->uvd_enabled = false;
+ pi->dpm_level_enable_mask.mclk_dpm_enable_mask |= 1;
+ amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_MCLKDPM_SetEnabledMask,
+ pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
+ }
+ }
+
+ return (amdgpu_ci_send_msg_to_smc(adev, enable ?
+ PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+
+static int ci_enable_vce_dpm(struct amdgpu_device *adev, bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ const struct amdgpu_clock_and_voltage_limits *max_limits;
+ int i;
+
+ if (adev->pm.dpm.ac_power)
+ max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+ else
+ max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
+
+ if (enable) {
+ pi->dpm_level_enable_mask.vce_dpm_enable_mask = 0;
+ for (i = adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
+ if (adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
+ pi->dpm_level_enable_mask.vce_dpm_enable_mask |= 1 << i;
+
+ if (!pi->caps_vce_dpm)
+ break;
+ }
+ }
+
+ amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_VCEDPM_SetEnabledMask,
+ pi->dpm_level_enable_mask.vce_dpm_enable_mask);
+ }
+
+ return (amdgpu_ci_send_msg_to_smc(adev, enable ?
+ PPSMC_MSG_VCEDPM_Enable : PPSMC_MSG_VCEDPM_Disable) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+
+#if 0
+static int ci_enable_samu_dpm(struct amdgpu_device *adev, bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ const struct amdgpu_clock_and_voltage_limits *max_limits;
+ int i;
+
+ if (adev->pm.dpm.ac_power)
+ max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+ else
+ max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
+
+ if (enable) {
+ pi->dpm_level_enable_mask.samu_dpm_enable_mask = 0;
+ for (i = adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
+ if (adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
+ pi->dpm_level_enable_mask.samu_dpm_enable_mask |= 1 << i;
+
+ if (!pi->caps_samu_dpm)
+ break;
+ }
+ }
+
+ amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SAMUDPM_SetEnabledMask,
+ pi->dpm_level_enable_mask.samu_dpm_enable_mask);
+ }
+ return (amdgpu_ci_send_msg_to_smc(adev, enable ?
+ PPSMC_MSG_SAMUDPM_Enable : PPSMC_MSG_SAMUDPM_Disable) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+
+static int ci_enable_acp_dpm(struct amdgpu_device *adev, bool enable)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ const struct amdgpu_clock_and_voltage_limits *max_limits;
+ int i;
+
+ if (adev->pm.dpm.ac_power)
+ max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+ else
+ max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
+
+ if (enable) {
+ pi->dpm_level_enable_mask.acp_dpm_enable_mask = 0;
+ for (i = adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
+ if (adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
+ pi->dpm_level_enable_mask.acp_dpm_enable_mask |= 1 << i;
+
+ if (!pi->caps_acp_dpm)
+ break;
+ }
+ }
+
+ amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_ACPDPM_SetEnabledMask,
+ pi->dpm_level_enable_mask.acp_dpm_enable_mask);
+ }
+
+ return (amdgpu_ci_send_msg_to_smc(adev, enable ?
+ PPSMC_MSG_ACPDPM_Enable : PPSMC_MSG_ACPDPM_Disable) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+#endif
+
+static int ci_update_uvd_dpm(struct amdgpu_device *adev, bool gate)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 tmp;
+
+ if (!gate) {
+ if (pi->caps_uvd_dpm ||
+ (adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count <= 0))
+ pi->smc_state_table.UvdBootLevel = 0;
+ else
+ pi->smc_state_table.UvdBootLevel =
+ adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count - 1;
+
+ tmp = RREG32_SMC(ixDPM_TABLE_475);
+ tmp &= ~DPM_TABLE_475__UvdBootLevel_MASK;
+ tmp |= (pi->smc_state_table.UvdBootLevel << DPM_TABLE_475__UvdBootLevel__SHIFT);
+ WREG32_SMC(ixDPM_TABLE_475, tmp);
+ }
+
+ return ci_enable_uvd_dpm(adev, !gate);
+}
+
+static u8 ci_get_vce_boot_level(struct amdgpu_device *adev)
+{
+ u8 i;
+ u32 min_evclk = 30000; /* ??? */
+ struct amdgpu_vce_clock_voltage_dependency_table *table =
+ &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
+
+ for (i = 0; i < table->count; i++) {
+ if (table->entries[i].evclk >= min_evclk)
+ return i;
+ }
+
+ return table->count - 1;
+}
+
+static int ci_update_vce_dpm(struct amdgpu_device *adev,
+ struct amdgpu_ps *amdgpu_new_state,
+ struct amdgpu_ps *amdgpu_current_state)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ int ret = 0;
+ u32 tmp;
+
+ if (amdgpu_current_state->evclk != amdgpu_new_state->evclk) {
+ if (amdgpu_new_state->evclk) {
+ /* turn the clocks on when encoding */
+ ret = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+ AMD_CG_STATE_UNGATE);
+ if (ret)
+ return ret;
+
+ pi->smc_state_table.VceBootLevel = ci_get_vce_boot_level(adev);
+ tmp = RREG32_SMC(ixDPM_TABLE_475);
+ tmp &= ~DPM_TABLE_475__VceBootLevel_MASK;
+ tmp |= (pi->smc_state_table.VceBootLevel << DPM_TABLE_475__VceBootLevel__SHIFT);
+ WREG32_SMC(ixDPM_TABLE_475, tmp);
+
+ ret = ci_enable_vce_dpm(adev, true);
+ } else {
+ /* turn the clocks off when not encoding */
+ ret = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+ AMD_CG_STATE_GATE);
+ if (ret)
+ return ret;
+
+ ret = ci_enable_vce_dpm(adev, false);
+ }
+ }
+ return ret;
+}
+
+#if 0
+static int ci_update_samu_dpm(struct amdgpu_device *adev, bool gate)
+{
+ return ci_enable_samu_dpm(adev, gate);
+}
+
+static int ci_update_acp_dpm(struct amdgpu_device *adev, bool gate)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 tmp;
+
+ if (!gate) {
+ pi->smc_state_table.AcpBootLevel = 0;
+
+ tmp = RREG32_SMC(ixDPM_TABLE_475);
+ tmp &= ~AcpBootLevel_MASK;
+ tmp |= AcpBootLevel(pi->smc_state_table.AcpBootLevel);
+ WREG32_SMC(ixDPM_TABLE_475, tmp);
+ }
+
+ return ci_enable_acp_dpm(adev, !gate);
+}
+#endif
+
+static int ci_generate_dpm_level_enable_mask(struct amdgpu_device *adev,
+ struct amdgpu_ps *amdgpu_state)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ int ret;
+
+ ret = ci_trim_dpm_states(adev, amdgpu_state);
+ if (ret)
+ return ret;
+
+ pi->dpm_level_enable_mask.sclk_dpm_enable_mask =
+ ci_get_dpm_level_enable_mask_value(&pi->dpm_table.sclk_table);
+ pi->dpm_level_enable_mask.mclk_dpm_enable_mask =
+ ci_get_dpm_level_enable_mask_value(&pi->dpm_table.mclk_table);
+ pi->last_mclk_dpm_enable_mask =
+ pi->dpm_level_enable_mask.mclk_dpm_enable_mask;
+ if (pi->uvd_enabled) {
+ if (pi->dpm_level_enable_mask.mclk_dpm_enable_mask & 1)
+ pi->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
+ }
+ pi->dpm_level_enable_mask.pcie_dpm_enable_mask =
+ ci_get_dpm_level_enable_mask_value(&pi->dpm_table.pcie_speed_table);
+
+ return 0;
+}
+
+static u32 ci_get_lowest_enabled_level(struct amdgpu_device *adev,
+ u32 level_mask)
+{
+ u32 level = 0;
+
+ while ((level_mask & (1 << level)) == 0)
+ level++;
+
+ return level;
+}
+
+
+static int ci_dpm_force_performance_level(struct amdgpu_device *adev,
+ enum amdgpu_dpm_forced_level level)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 tmp, levels, i;
+ int ret;
+
+ if (level == AMDGPU_DPM_FORCED_LEVEL_HIGH) {
+ if ((!pi->pcie_dpm_key_disabled) &&
+ pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
+ levels = 0;
+ tmp = pi->dpm_level_enable_mask.pcie_dpm_enable_mask;
+ while (tmp >>= 1)
+ levels++;
+ if (levels) {
+ ret = ci_dpm_force_state_pcie(adev, level);
+ if (ret)
+ return ret;
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX_1) &
+ TARGET_AND_CURRENT_PROFILE_INDEX_1__CURR_PCIE_INDEX_MASK) >>
+ TARGET_AND_CURRENT_PROFILE_INDEX_1__CURR_PCIE_INDEX__SHIFT;
+ if (tmp == levels)
+ break;
+ udelay(1);
+ }
+ }
+ }
+ if ((!pi->sclk_dpm_key_disabled) &&
+ pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+ levels = 0;
+ tmp = pi->dpm_level_enable_mask.sclk_dpm_enable_mask;
+ while (tmp >>= 1)
+ levels++;
+ if (levels) {
+ ret = ci_dpm_force_state_sclk(adev, levels);
+ if (ret)
+ return ret;
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX) &
+ TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX_MASK) >>
+ TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX__SHIFT;
+ if (tmp == levels)
+ break;
+ udelay(1);
+ }
+ }
+ }
+ if ((!pi->mclk_dpm_key_disabled) &&
+ pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+ levels = 0;
+ tmp = pi->dpm_level_enable_mask.mclk_dpm_enable_mask;
+ while (tmp >>= 1)
+ levels++;
+ if (levels) {
+ ret = ci_dpm_force_state_mclk(adev, levels);
+ if (ret)
+ return ret;
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX) &
+ TARGET_AND_CURRENT_PROFILE_INDEX__CURR_MCLK_INDEX_MASK) >>
+ TARGET_AND_CURRENT_PROFILE_INDEX__CURR_MCLK_INDEX__SHIFT;
+ if (tmp == levels)
+ break;
+ udelay(1);
+ }
+ }
+ }
+ if ((!pi->pcie_dpm_key_disabled) &&
+ pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
+ levels = 0;
+ tmp = pi->dpm_level_enable_mask.pcie_dpm_enable_mask;
+ while (tmp >>= 1)
+ levels++;
+ if (levels) {
+ ret = ci_dpm_force_state_pcie(adev, level);
+ if (ret)
+ return ret;
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX_1) &
+ TARGET_AND_CURRENT_PROFILE_INDEX_1__CURR_PCIE_INDEX_MASK) >>
+ TARGET_AND_CURRENT_PROFILE_INDEX_1__CURR_PCIE_INDEX__SHIFT;
+ if (tmp == levels)
+ break;
+ udelay(1);
+ }
+ }
+ }
+ } else if (level == AMDGPU_DPM_FORCED_LEVEL_LOW) {
+ if ((!pi->sclk_dpm_key_disabled) &&
+ pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
+ levels = ci_get_lowest_enabled_level(adev,
+ pi->dpm_level_enable_mask.sclk_dpm_enable_mask);
+ ret = ci_dpm_force_state_sclk(adev, levels);
+ if (ret)
+ return ret;
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX) &
+ TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX_MASK) >>
+ TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX__SHIFT;
+ if (tmp == levels)
+ break;
+ udelay(1);
+ }
+ }
+ if ((!pi->mclk_dpm_key_disabled) &&
+ pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
+ levels = ci_get_lowest_enabled_level(adev,
+ pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
+ ret = ci_dpm_force_state_mclk(adev, levels);
+ if (ret)
+ return ret;
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX) &
+ TARGET_AND_CURRENT_PROFILE_INDEX__CURR_MCLK_INDEX_MASK) >>
+ TARGET_AND_CURRENT_PROFILE_INDEX__CURR_MCLK_INDEX__SHIFT;
+ if (tmp == levels)
+ break;
+ udelay(1);
+ }
+ }
+ if ((!pi->pcie_dpm_key_disabled) &&
+ pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
+ levels = ci_get_lowest_enabled_level(adev,
+ pi->dpm_level_enable_mask.pcie_dpm_enable_mask);
+ ret = ci_dpm_force_state_pcie(adev, levels);
+ if (ret)
+ return ret;
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX_1) &
+ TARGET_AND_CURRENT_PROFILE_INDEX_1__CURR_PCIE_INDEX_MASK) >>
+ TARGET_AND_CURRENT_PROFILE_INDEX_1__CURR_PCIE_INDEX__SHIFT;
+ if (tmp == levels)
+ break;
+ udelay(1);
+ }
+ }
+ } else if (level == AMDGPU_DPM_FORCED_LEVEL_AUTO) {
+ if (!pi->pcie_dpm_key_disabled) {
+ PPSMC_Result smc_result;
+
+ smc_result = amdgpu_ci_send_msg_to_smc(adev,
+ PPSMC_MSG_PCIeDPM_UnForceLevel);
+ if (smc_result != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+ ret = ci_upload_dpm_level_enable_mask(adev);
+ if (ret)
+ return ret;
+ }
+
+ adev->pm.dpm.forced_level = level;
+
+ return 0;
+}
+
+static int ci_set_mc_special_registers(struct amdgpu_device *adev,
+ struct ci_mc_reg_table *table)
+{
+ u8 i, j, k;
+ u32 temp_reg;
+
+ for (i = 0, j = table->last; i < table->last; i++) {
+ if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ switch(table->mc_reg_address[i].s1) {
+ case mmMC_SEQ_MISC1:
+ temp_reg = RREG32(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++;
+ if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+
+ temp_reg = RREG32(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 (adev->mc.vram_type != AMDGPU_VRAM_TYPE_GDDR5)
+ table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
+ }
+ j++;
+ if (j > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+
+ if (adev->mc.vram_type != AMDGPU_VRAM_TYPE_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++;
+ if (j > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ }
+ break;
+ case mmMC_SEQ_RESERVE_M:
+ temp_reg = RREG32(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++;
+ if (j > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ table->last = j;
+
+ return 0;
+}
+
+static bool ci_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg)
+{
+ bool result = true;
+
+ switch(in_reg) {
+ case mmMC_SEQ_RAS_TIMING:
+ *out_reg = mmMC_SEQ_RAS_TIMING_LP;
+ break;
+ case mmMC_SEQ_DLL_STBY:
+ *out_reg = mmMC_SEQ_DLL_STBY_LP;
+ break;
+ case mmMC_SEQ_G5PDX_CMD0:
+ *out_reg = mmMC_SEQ_G5PDX_CMD0_LP;
+ break;
+ case mmMC_SEQ_G5PDX_CMD1:
+ *out_reg = mmMC_SEQ_G5PDX_CMD1_LP;
+ break;
+ case mmMC_SEQ_G5PDX_CTRL:
+ *out_reg = mmMC_SEQ_G5PDX_CTRL_LP;
+ break;
+ case mmMC_SEQ_CAS_TIMING:
+ *out_reg = mmMC_SEQ_CAS_TIMING_LP;
+ break;
+ case mmMC_SEQ_MISC_TIMING:
+ *out_reg = mmMC_SEQ_MISC_TIMING_LP;
+ break;
+ case mmMC_SEQ_MISC_TIMING2:
+ *out_reg = mmMC_SEQ_MISC_TIMING2_LP;
+ break;
+ case mmMC_SEQ_PMG_DVS_CMD:
+ *out_reg = mmMC_SEQ_PMG_DVS_CMD_LP;
+ break;
+ case mmMC_SEQ_PMG_DVS_CTL:
+ *out_reg = mmMC_SEQ_PMG_DVS_CTL_LP;
+ break;
+ case mmMC_SEQ_RD_CTL_D0:
+ *out_reg = mmMC_SEQ_RD_CTL_D0_LP;
+ break;
+ case mmMC_SEQ_RD_CTL_D1:
+ *out_reg = mmMC_SEQ_RD_CTL_D1_LP;
+ break;
+ case mmMC_SEQ_WR_CTL_D0:
+ *out_reg = mmMC_SEQ_WR_CTL_D0_LP;
+ break;
+ case mmMC_SEQ_WR_CTL_D1:
+ *out_reg = mmMC_SEQ_WR_CTL_D1_LP;
+ break;
+ case mmMC_PMG_CMD_EMRS:
+ *out_reg = mmMC_SEQ_PMG_CMD_EMRS_LP;
+ break;
+ case mmMC_PMG_CMD_MRS:
+ *out_reg = mmMC_SEQ_PMG_CMD_MRS_LP;
+ break;
+ case mmMC_PMG_CMD_MRS1:
+ *out_reg = mmMC_SEQ_PMG_CMD_MRS1_LP;
+ break;
+ case mmMC_SEQ_PMG_TIMING:
+ *out_reg = mmMC_SEQ_PMG_TIMING_LP;
+ break;
+ case mmMC_PMG_CMD_MRS2:
+ *out_reg = mmMC_SEQ_PMG_CMD_MRS2_LP;
+ break;
+ case mmMC_SEQ_WR_CTL_2:
+ *out_reg = mmMC_SEQ_WR_CTL_2_LP;
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
+static void ci_set_valid_flag(struct ci_mc_reg_table *table)
+{
+ u8 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->valid_flag |= 1 << i;
+ break;
+ }
+ }
+ }
+}
+
+static void ci_set_s0_mc_reg_index(struct ci_mc_reg_table *table)
+{
+ u32 i;
+ u16 address;
+
+ for (i = 0; i < table->last; i++) {
+ table->mc_reg_address[i].s0 =
+ ci_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ?
+ address : table->mc_reg_address[i].s1;
+ }
+}
+
+static int ci_copy_vbios_mc_reg_table(const struct atom_mc_reg_table *table,
+ struct ci_mc_reg_table *ci_table)
+{
+ u8 i, j;
+
+ if (table->last > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ if (table->num_entries > MAX_AC_TIMING_ENTRIES)
+ return -EINVAL;
+
+ for (i = 0; i < table->last; i++)
+ ci_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
+
+ ci_table->last = table->last;
+
+ for (i = 0; i < table->num_entries; i++) {
+ ci_table->mc_reg_table_entry[i].mclk_max =
+ table->mc_reg_table_entry[i].mclk_max;
+ for (j = 0; j < table->last; j++)
+ ci_table->mc_reg_table_entry[i].mc_data[j] =
+ table->mc_reg_table_entry[i].mc_data[j];
+ }
+ ci_table->num_entries = table->num_entries;
+
+ return 0;
+}
+
+static int ci_register_patching_mc_seq(struct amdgpu_device *adev,
+ struct ci_mc_reg_table *table)
+{
+ u8 i, k;
+ u32 tmp;
+ bool patch;
+
+ tmp = RREG32(mmMC_SEQ_MISC0);
+ patch = ((tmp & 0x0000f00) == 0x300) ? true : false;
+
+ if (patch &&
+ ((adev->pdev->device == 0x67B0) ||
+ (adev->pdev->device == 0x67B1))) {
+ for (i = 0; i < table->last; i++) {
+ if (table->last >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ switch (table->mc_reg_address[i].s1) {
+ case mmMC_SEQ_MISC1:
+ for (k = 0; k < table->num_entries; k++) {
+ if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
+ (table->mc_reg_table_entry[k].mclk_max == 137500))
+ table->mc_reg_table_entry[k].mc_data[i] =
+ (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFF8) |
+ 0x00000007;
+ }
+ break;
+ case mmMC_SEQ_WR_CTL_D0:
+ for (k = 0; k < table->num_entries; k++) {
+ if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
+ (table->mc_reg_table_entry[k].mclk_max == 137500))
+ table->mc_reg_table_entry[k].mc_data[i] =
+ (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) |
+ 0x0000D0DD;
+ }
+ break;
+ case mmMC_SEQ_WR_CTL_D1:
+ for (k = 0; k < table->num_entries; k++) {
+ if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
+ (table->mc_reg_table_entry[k].mclk_max == 137500))
+ table->mc_reg_table_entry[k].mc_data[i] =
+ (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) |
+ 0x0000D0DD;
+ }
+ break;
+ case mmMC_SEQ_WR_CTL_2:
+ for (k = 0; k < table->num_entries; k++) {
+ if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
+ (table->mc_reg_table_entry[k].mclk_max == 137500))
+ table->mc_reg_table_entry[k].mc_data[i] = 0;
+ }
+ break;
+ case mmMC_SEQ_CAS_TIMING:
+ for (k = 0; k < table->num_entries; k++) {
+ if (table->mc_reg_table_entry[k].mclk_max == 125000)
+ table->mc_reg_table_entry[k].mc_data[i] =
+ (table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) |
+ 0x000C0140;
+ else if (table->mc_reg_table_entry[k].mclk_max == 137500)
+ table->mc_reg_table_entry[k].mc_data[i] =
+ (table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) |
+ 0x000C0150;
+ }
+ break;
+ case mmMC_SEQ_MISC_TIMING:
+ for (k = 0; k < table->num_entries; k++) {
+ if (table->mc_reg_table_entry[k].mclk_max == 125000)
+ table->mc_reg_table_entry[k].mc_data[i] =
+ (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) |
+ 0x00000030;
+ else if (table->mc_reg_table_entry[k].mclk_max == 137500)
+ table->mc_reg_table_entry[k].mc_data[i] =
+ (table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) |
+ 0x00000035;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ WREG32(mmMC_SEQ_IO_DEBUG_INDEX, 3);
+ tmp = RREG32(mmMC_SEQ_IO_DEBUG_DATA);
+ tmp = (tmp & 0xFFF8FFFF) | (1 << 16);
+ WREG32(mmMC_SEQ_IO_DEBUG_INDEX, 3);
+ WREG32(mmMC_SEQ_IO_DEBUG_DATA, tmp);
+ }
+
+ return 0;
+}
+
+static int ci_initialize_mc_reg_table(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct atom_mc_reg_table *table;
+ struct ci_mc_reg_table *ci_table = &pi->mc_reg_table;
+ u8 module_index = ci_get_memory_module_index(adev);
+ int ret;
+
+ table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL);
+ if (!table)
+ return -ENOMEM;
+
+ WREG32(mmMC_SEQ_RAS_TIMING_LP, RREG32(mmMC_SEQ_RAS_TIMING));
+ WREG32(mmMC_SEQ_CAS_TIMING_LP, RREG32(mmMC_SEQ_CAS_TIMING));
+ WREG32(mmMC_SEQ_DLL_STBY_LP, RREG32(mmMC_SEQ_DLL_STBY));
+ WREG32(mmMC_SEQ_G5PDX_CMD0_LP, RREG32(mmMC_SEQ_G5PDX_CMD0));
+ WREG32(mmMC_SEQ_G5PDX_CMD1_LP, RREG32(mmMC_SEQ_G5PDX_CMD1));
+ WREG32(mmMC_SEQ_G5PDX_CTRL_LP, RREG32(mmMC_SEQ_G5PDX_CTRL));
+ WREG32(mmMC_SEQ_PMG_DVS_CMD_LP, RREG32(mmMC_SEQ_PMG_DVS_CMD));
+ WREG32(mmMC_SEQ_PMG_DVS_CTL_LP, RREG32(mmMC_SEQ_PMG_DVS_CTL));
+ WREG32(mmMC_SEQ_MISC_TIMING_LP, RREG32(mmMC_SEQ_MISC_TIMING));
+ WREG32(mmMC_SEQ_MISC_TIMING2_LP, RREG32(mmMC_SEQ_MISC_TIMING2));
+ WREG32(mmMC_SEQ_PMG_CMD_EMRS_LP, RREG32(mmMC_PMG_CMD_EMRS));
+ WREG32(mmMC_SEQ_PMG_CMD_MRS_LP, RREG32(mmMC_PMG_CMD_MRS));
+ WREG32(mmMC_SEQ_PMG_CMD_MRS1_LP, RREG32(mmMC_PMG_CMD_MRS1));
+ WREG32(mmMC_SEQ_WR_CTL_D0_LP, RREG32(mmMC_SEQ_WR_CTL_D0));
+ WREG32(mmMC_SEQ_WR_CTL_D1_LP, RREG32(mmMC_SEQ_WR_CTL_D1));
+ WREG32(mmMC_SEQ_RD_CTL_D0_LP, RREG32(mmMC_SEQ_RD_CTL_D0));
+ WREG32(mmMC_SEQ_RD_CTL_D1_LP, RREG32(mmMC_SEQ_RD_CTL_D1));
+ WREG32(mmMC_SEQ_PMG_TIMING_LP, RREG32(mmMC_SEQ_PMG_TIMING));
+ WREG32(mmMC_SEQ_PMG_CMD_MRS2_LP, RREG32(mmMC_PMG_CMD_MRS2));
+ WREG32(mmMC_SEQ_WR_CTL_2_LP, RREG32(mmMC_SEQ_WR_CTL_2));
+
+ ret = amdgpu_atombios_init_mc_reg_table(adev, module_index, table);
+ if (ret)
+ goto init_mc_done;
+
+ ret = ci_copy_vbios_mc_reg_table(table, ci_table);
+ if (ret)
+ goto init_mc_done;
+
+ ci_set_s0_mc_reg_index(ci_table);
+
+ ret = ci_register_patching_mc_seq(adev, ci_table);
+ if (ret)
+ goto init_mc_done;
+
+ ret = ci_set_mc_special_registers(adev, ci_table);
+ if (ret)
+ goto init_mc_done;
+
+ ci_set_valid_flag(ci_table);
+
+init_mc_done:
+ kfree(table);
+
+ return ret;
+}
+
+static int ci_populate_mc_reg_addresses(struct amdgpu_device *adev,
+ SMU7_Discrete_MCRegisters *mc_reg_table)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 i, j;
+
+ for (i = 0, j = 0; j < pi->mc_reg_table.last; j++) {
+ if (pi->mc_reg_table.valid_flag & (1 << j)) {
+ if (i >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ mc_reg_table->address[i].s0 = cpu_to_be16(pi->mc_reg_table.mc_reg_address[j].s0);
+ mc_reg_table->address[i].s1 = cpu_to_be16(pi->mc_reg_table.mc_reg_address[j].s1);
+ i++;
+ }
+ }
+
+ mc_reg_table->last = (u8)i;
+
+ return 0;
+}
+
+static void ci_convert_mc_registers(const struct ci_mc_reg_entry *entry,
+ SMU7_Discrete_MCRegisterSet *data,
+ u32 num_entries, u32 valid_flag)
+{
+ u32 i, j;
+
+ for (i = 0, j = 0; j < num_entries; j++) {
+ if (valid_flag & (1 << j)) {
+ data->value[i] = cpu_to_be32(entry->mc_data[j]);
+ i++;
+ }
+ }
+}
+
+static void ci_convert_mc_reg_table_entry_to_smc(struct amdgpu_device *adev,
+ const u32 memory_clock,
+ SMU7_Discrete_MCRegisterSet *mc_reg_table_data)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 i = 0;
+
+ for(i = 0; i < pi->mc_reg_table.num_entries; i++) {
+ if (memory_clock <= pi->mc_reg_table.mc_reg_table_entry[i].mclk_max)
+ break;
+ }
+
+ if ((i == pi->mc_reg_table.num_entries) && (i > 0))
+ --i;
+
+ ci_convert_mc_registers(&pi->mc_reg_table.mc_reg_table_entry[i],
+ mc_reg_table_data, pi->mc_reg_table.last,
+ pi->mc_reg_table.valid_flag);
+}
+
+static void ci_convert_mc_reg_table_to_smc(struct amdgpu_device *adev,
+ SMU7_Discrete_MCRegisters *mc_reg_table)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ u32 i;
+
+ for (i = 0; i < pi->dpm_table.mclk_table.count; i++)
+ ci_convert_mc_reg_table_entry_to_smc(adev,
+ pi->dpm_table.mclk_table.dpm_levels[i].value,
+ &mc_reg_table->data[i]);
+}
+
+static int ci_populate_initial_mc_reg_table(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ int ret;
+
+ memset(&pi->smc_mc_reg_table, 0, sizeof(SMU7_Discrete_MCRegisters));
+
+ ret = ci_populate_mc_reg_addresses(adev, &pi->smc_mc_reg_table);
+ if (ret)
+ return ret;
+ ci_convert_mc_reg_table_to_smc(adev, &pi->smc_mc_reg_table);
+
+ return amdgpu_ci_copy_bytes_to_smc(adev,
+ pi->mc_reg_table_start,
+ (u8 *)&pi->smc_mc_reg_table,
+ sizeof(SMU7_Discrete_MCRegisters),
+ pi->sram_end);
+}
+
+static int ci_update_and_upload_mc_reg_table(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ if (!(pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
+ return 0;
+
+ memset(&pi->smc_mc_reg_table, 0, sizeof(SMU7_Discrete_MCRegisters));
+
+ ci_convert_mc_reg_table_to_smc(adev, &pi->smc_mc_reg_table);
+
+ return amdgpu_ci_copy_bytes_to_smc(adev,
+ pi->mc_reg_table_start +
+ offsetof(SMU7_Discrete_MCRegisters, data[0]),
+ (u8 *)&pi->smc_mc_reg_table.data[0],
+ sizeof(SMU7_Discrete_MCRegisterSet) *
+ pi->dpm_table.mclk_table.count,
+ pi->sram_end);
+}
+
+static void ci_enable_voltage_control(struct amdgpu_device *adev)
+{
+ u32 tmp = RREG32_SMC(ixGENERAL_PWRMGT);
+
+ tmp |= GENERAL_PWRMGT__VOLT_PWRMGT_EN_MASK;
+ WREG32_SMC(ixGENERAL_PWRMGT, tmp);
+}
+
+static enum amdgpu_pcie_gen ci_get_maximum_link_speed(struct amdgpu_device *adev,
+ struct amdgpu_ps *amdgpu_state)
+{
+ struct ci_ps *state = ci_get_ps(amdgpu_state);
+ int i;
+ u16 pcie_speed, max_speed = 0;
+
+ for (i = 0; i < state->performance_level_count; i++) {
+ pcie_speed = state->performance_levels[i].pcie_gen;
+ if (max_speed < pcie_speed)
+ max_speed = pcie_speed;
+ }
+
+ return max_speed;
+}
+
+static u16 ci_get_current_pcie_speed(struct amdgpu_device *adev)
+{
+ u32 speed_cntl = 0;
+
+ speed_cntl = RREG32_PCIE(ixPCIE_LC_SPEED_CNTL) &
+ PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK;
+ speed_cntl >>= PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
+
+ return (u16)speed_cntl;
+}
+
+static int ci_get_current_pcie_lane_number(struct amdgpu_device *adev)
+{
+ u32 link_width = 0;
+
+ link_width = RREG32_PCIE(ixPCIE_LC_LINK_WIDTH_CNTL) &
+ PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK;
+ link_width >>= PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT;
+
+ switch (link_width) {
+ case 1:
+ return 1;
+ case 2:
+ return 2;
+ case 3:
+ return 4;
+ case 4:
+ return 8;
+ case 0:
+ case 6:
+ default:
+ return 16;
+ }
+}
+
+static void ci_request_link_speed_change_before_state_change(struct amdgpu_device *adev,
+ struct amdgpu_ps *amdgpu_new_state,
+ struct amdgpu_ps *amdgpu_current_state)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ enum amdgpu_pcie_gen target_link_speed =
+ ci_get_maximum_link_speed(adev, amdgpu_new_state);
+ enum amdgpu_pcie_gen current_link_speed;
+
+ if (pi->force_pcie_gen == AMDGPU_PCIE_GEN_INVALID)
+ current_link_speed = ci_get_maximum_link_speed(adev, amdgpu_current_state);
+ else
+ current_link_speed = pi->force_pcie_gen;
+
+ pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID;
+ pi->pspp_notify_required = false;
+ if (target_link_speed > current_link_speed) {
+ switch (target_link_speed) {
+#ifdef CONFIG_ACPI
+ case AMDGPU_PCIE_GEN3:
+ if (amdgpu_acpi_pcie_performance_request(adev, PCIE_PERF_REQ_PECI_GEN3, false) == 0)
+ break;
+ pi->force_pcie_gen = AMDGPU_PCIE_GEN2;
+ if (current_link_speed == AMDGPU_PCIE_GEN2)
+ break;
+ case AMDGPU_PCIE_GEN2:
+ if (amdgpu_acpi_pcie_performance_request(adev, PCIE_PERF_REQ_PECI_GEN2, false) == 0)
+ break;
+#endif
+ default:
+ pi->force_pcie_gen = ci_get_current_pcie_speed(adev);
+ break;
+ }
+ } else {
+ if (target_link_speed < current_link_speed)
+ pi->pspp_notify_required = true;
+ }
+}
+
+static void ci_notify_link_speed_change_after_state_change(struct amdgpu_device *adev,
+ struct amdgpu_ps *amdgpu_new_state,
+ struct amdgpu_ps *amdgpu_current_state)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ enum amdgpu_pcie_gen target_link_speed =
+ ci_get_maximum_link_speed(adev, amdgpu_new_state);
+ u8 request;
+
+ if (pi->pspp_notify_required) {
+ if (target_link_speed == AMDGPU_PCIE_GEN3)
+ request = PCIE_PERF_REQ_PECI_GEN3;
+ else if (target_link_speed == AMDGPU_PCIE_GEN2)
+ request = PCIE_PERF_REQ_PECI_GEN2;
+ else
+ request = PCIE_PERF_REQ_PECI_GEN1;
+
+ if ((request == PCIE_PERF_REQ_PECI_GEN1) &&
+ (ci_get_current_pcie_speed(adev) > 0))
+ return;
+
+#ifdef CONFIG_ACPI
+ amdgpu_acpi_pcie_performance_request(adev, request, false);
+#endif
+ }
+}
+
+static int ci_set_private_data_variables_based_on_pptable(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct amdgpu_clock_voltage_dependency_table *allowed_sclk_vddc_table =
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
+ struct amdgpu_clock_voltage_dependency_table *allowed_mclk_vddc_table =
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk;
+ struct amdgpu_clock_voltage_dependency_table *allowed_mclk_vddci_table =
+ &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk;
+
+ if (allowed_sclk_vddc_table == NULL)
+ return -EINVAL;
+ if (allowed_sclk_vddc_table->count < 1)
+ return -EINVAL;
+ if (allowed_mclk_vddc_table == NULL)
+ return -EINVAL;
+ if (allowed_mclk_vddc_table->count < 1)
+ return -EINVAL;
+ if (allowed_mclk_vddci_table == NULL)
+ return -EINVAL;
+ if (allowed_mclk_vddci_table->count < 1)
+ return -EINVAL;
+
+ pi->min_vddc_in_pp_table = allowed_sclk_vddc_table->entries[0].v;
+ pi->max_vddc_in_pp_table =
+ allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v;
+
+ pi->min_vddci_in_pp_table = allowed_mclk_vddci_table->entries[0].v;
+ pi->max_vddci_in_pp_table =
+ allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v;
+
+ adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk =
+ allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk;
+ adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk =
+ allowed_mclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk;
+ adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc =
+ allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v;
+ adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci =
+ allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v;
+
+ return 0;
+}
+
+static void ci_patch_with_vddc_leakage(struct amdgpu_device *adev, u16 *vddc)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_leakage_voltage *leakage_table = &pi->vddc_leakage;
+ u32 leakage_index;
+
+ for (leakage_index = 0; leakage_index < leakage_table->count; leakage_index++) {
+ if (leakage_table->leakage_id[leakage_index] == *vddc) {
+ *vddc = leakage_table->actual_voltage[leakage_index];
+ break;
+ }
+ }
+}
+
+static void ci_patch_with_vddci_leakage(struct amdgpu_device *adev, u16 *vddci)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_leakage_voltage *leakage_table = &pi->vddci_leakage;
+ u32 leakage_index;
+
+ for (leakage_index = 0; leakage_index < leakage_table->count; leakage_index++) {
+ if (leakage_table->leakage_id[leakage_index] == *vddci) {
+ *vddci = leakage_table->actual_voltage[leakage_index];
+ break;
+ }
+ }
+}
+
+static void ci_patch_clock_voltage_dependency_table_with_vddc_leakage(struct amdgpu_device *adev,
+ struct amdgpu_clock_voltage_dependency_table *table)
+{
+ u32 i;
+
+ if (table) {
+ for (i = 0; i < table->count; i++)
+ ci_patch_with_vddc_leakage(adev, &table->entries[i].v);
+ }
+}
+
+static void ci_patch_clock_voltage_dependency_table_with_vddci_leakage(struct amdgpu_device *adev,
+ struct amdgpu_clock_voltage_dependency_table *table)
+{
+ u32 i;
+
+ if (table) {
+ for (i = 0; i < table->count; i++)
+ ci_patch_with_vddci_leakage(adev, &table->entries[i].v);
+ }
+}
+
+static void ci_patch_vce_clock_voltage_dependency_table_with_vddc_leakage(struct amdgpu_device *adev,
+ struct amdgpu_vce_clock_voltage_dependency_table *table)
+{
+ u32 i;
+
+ if (table) {
+ for (i = 0; i < table->count; i++)
+ ci_patch_with_vddc_leakage(adev, &table->entries[i].v);
+ }
+}
+
+static void ci_patch_uvd_clock_voltage_dependency_table_with_vddc_leakage(struct amdgpu_device *adev,
+ struct amdgpu_uvd_clock_voltage_dependency_table *table)
+{
+ u32 i;
+
+ if (table) {
+ for (i = 0; i < table->count; i++)
+ ci_patch_with_vddc_leakage(adev, &table->entries[i].v);
+ }
+}
+
+static void ci_patch_vddc_phase_shed_limit_table_with_vddc_leakage(struct amdgpu_device *adev,
+ struct amdgpu_phase_shedding_limits_table *table)
+{
+ u32 i;
+
+ if (table) {
+ for (i = 0; i < table->count; i++)
+ ci_patch_with_vddc_leakage(adev, &table->entries[i].voltage);
+ }
+}
+
+static void ci_patch_clock_voltage_limits_with_vddc_leakage(struct amdgpu_device *adev,
+ struct amdgpu_clock_and_voltage_limits *table)
+{
+ if (table) {
+ ci_patch_with_vddc_leakage(adev, (u16 *)&table->vddc);
+ ci_patch_with_vddci_leakage(adev, (u16 *)&table->vddci);
+ }
+}
+
+static void ci_patch_cac_leakage_table_with_vddc_leakage(struct amdgpu_device *adev,
+ struct amdgpu_cac_leakage_table *table)
+{
+ u32 i;
+
+ if (table) {
+ for (i = 0; i < table->count; i++)
+ ci_patch_with_vddc_leakage(adev, &table->entries[i].vddc);
+ }
+}
+
+static void ci_patch_dependency_tables_with_leakage(struct amdgpu_device *adev)
+{
+
+ ci_patch_clock_voltage_dependency_table_with_vddc_leakage(adev,
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk);
+ ci_patch_clock_voltage_dependency_table_with_vddc_leakage(adev,
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk);
+ ci_patch_clock_voltage_dependency_table_with_vddc_leakage(adev,
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk);
+ ci_patch_clock_voltage_dependency_table_with_vddci_leakage(adev,
+ &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk);
+ ci_patch_vce_clock_voltage_dependency_table_with_vddc_leakage(adev,
+ &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table);
+ ci_patch_uvd_clock_voltage_dependency_table_with_vddc_leakage(adev,
+ &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table);
+ ci_patch_clock_voltage_dependency_table_with_vddc_leakage(adev,
+ &adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table);
+ ci_patch_clock_voltage_dependency_table_with_vddc_leakage(adev,
+ &adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table);
+ ci_patch_vddc_phase_shed_limit_table_with_vddc_leakage(adev,
+ &adev->pm.dpm.dyn_state.phase_shedding_limits_table);
+ ci_patch_clock_voltage_limits_with_vddc_leakage(adev,
+ &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac);
+ ci_patch_clock_voltage_limits_with_vddc_leakage(adev,
+ &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc);
+ ci_patch_cac_leakage_table_with_vddc_leakage(adev,
+ &adev->pm.dpm.dyn_state.cac_leakage_table);
+
+}
+
+static void ci_update_current_ps(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps)
+{
+ struct ci_ps *new_ps = ci_get_ps(rps);
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ pi->current_rps = *rps;
+ pi->current_ps = *new_ps;
+ pi->current_rps.ps_priv = &pi->current_ps;
+}
+
+static void ci_update_requested_ps(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps)
+{
+ struct ci_ps *new_ps = ci_get_ps(rps);
+ struct ci_power_info *pi = ci_get_pi(adev);
+
+ pi->requested_rps = *rps;
+ pi->requested_ps = *new_ps;
+ pi->requested_rps.ps_priv = &pi->requested_ps;
+}
+
+static int ci_dpm_pre_set_power_state(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct amdgpu_ps requested_ps = *adev->pm.dpm.requested_ps;
+ struct amdgpu_ps *new_ps = &requested_ps;
+
+ ci_update_requested_ps(adev, new_ps);
+
+ ci_apply_state_adjust_rules(adev, &pi->requested_rps);
+
+ return 0;
+}
+
+static void ci_dpm_post_set_power_state(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct amdgpu_ps *new_ps = &pi->requested_rps;
+
+ ci_update_current_ps(adev, new_ps);
+}
+
+
+static void ci_dpm_setup_asic(struct amdgpu_device *adev)
+{
+ ci_read_clock_registers(adev);
+ ci_enable_acpi_power_management(adev);
+ ci_init_sclk_t(adev);
+}
+
+static int ci_dpm_enable(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct amdgpu_ps *boot_ps = adev->pm.dpm.boot_ps;
+ int ret;
+
+ if (amdgpu_ci_is_smc_running(adev))
+ return -EINVAL;
+ if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
+ ci_enable_voltage_control(adev);
+ ret = ci_construct_voltage_tables(adev);
+ if (ret) {
+ DRM_ERROR("ci_construct_voltage_tables failed\n");
+ return ret;
+ }
+ }
+ if (pi->caps_dynamic_ac_timing) {
+ ret = ci_initialize_mc_reg_table(adev);
+ if (ret)
+ pi->caps_dynamic_ac_timing = false;
+ }
+ if (pi->dynamic_ss)
+ ci_enable_spread_spectrum(adev, true);
+ if (pi->thermal_protection)
+ ci_enable_thermal_protection(adev, true);
+ ci_program_sstp(adev);
+ ci_enable_display_gap(adev);
+ ci_program_vc(adev);
+ ret = ci_upload_firmware(adev);
+ if (ret) {
+ DRM_ERROR("ci_upload_firmware failed\n");
+ return ret;
+ }
+ ret = ci_process_firmware_header(adev);
+ if (ret) {
+ DRM_ERROR("ci_process_firmware_header failed\n");
+ return ret;
+ }
+ ret = ci_initial_switch_from_arb_f0_to_f1(adev);
+ if (ret) {
+ DRM_ERROR("ci_initial_switch_from_arb_f0_to_f1 failed\n");
+ return ret;
+ }
+ ret = ci_init_smc_table(adev);
+ if (ret) {
+ DRM_ERROR("ci_init_smc_table failed\n");
+ return ret;
+ }
+ ret = ci_init_arb_table_index(adev);
+ if (ret) {
+ DRM_ERROR("ci_init_arb_table_index failed\n");
+ return ret;
+ }
+ if (pi->caps_dynamic_ac_timing) {
+ ret = ci_populate_initial_mc_reg_table(adev);
+ if (ret) {
+ DRM_ERROR("ci_populate_initial_mc_reg_table failed\n");
+ return ret;
+ }
+ }
+ ret = ci_populate_pm_base(adev);
+ if (ret) {
+ DRM_ERROR("ci_populate_pm_base failed\n");
+ return ret;
+ }
+ ci_dpm_start_smc(adev);
+ ci_enable_vr_hot_gpio_interrupt(adev);
+ ret = ci_notify_smc_display_change(adev, false);
+ if (ret) {
+ DRM_ERROR("ci_notify_smc_display_change failed\n");
+ return ret;
+ }
+ ci_enable_sclk_control(adev, true);
+ ret = ci_enable_ulv(adev, true);
+ if (ret) {
+ DRM_ERROR("ci_enable_ulv failed\n");
+ return ret;
+ }
+ ret = ci_enable_ds_master_switch(adev, true);
+ if (ret) {
+ DRM_ERROR("ci_enable_ds_master_switch failed\n");
+ return ret;
+ }
+ ret = ci_start_dpm(adev);
+ if (ret) {
+ DRM_ERROR("ci_start_dpm failed\n");
+ return ret;
+ }
+ ret = ci_enable_didt(adev, true);
+ if (ret) {
+ DRM_ERROR("ci_enable_didt failed\n");
+ return ret;
+ }
+ ret = ci_enable_smc_cac(adev, true);
+ if (ret) {
+ DRM_ERROR("ci_enable_smc_cac failed\n");
+ return ret;
+ }
+ ret = ci_enable_power_containment(adev, true);
+ if (ret) {
+ DRM_ERROR("ci_enable_power_containment failed\n");
+ return ret;
+ }
+
+ ret = ci_power_control_set_level(adev);
+ if (ret) {
+ DRM_ERROR("ci_power_control_set_level failed\n");
+ return ret;
+ }
+
+ ci_enable_auto_throttle_source(adev, AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+ ret = ci_enable_thermal_based_sclk_dpm(adev, true);
+ if (ret) {
+ DRM_ERROR("ci_enable_thermal_based_sclk_dpm failed\n");
+ return ret;
+ }
+
+ ci_thermal_start_thermal_controller(adev);
+
+ ci_update_current_ps(adev, boot_ps);
+
+ if (adev->irq.installed &&
+ amdgpu_is_internal_thermal_sensor(adev->pm.int_thermal_type)) {
+#if 0
+ PPSMC_Result result;
+#endif
+ ret = ci_thermal_set_temperature_range(adev, CISLANDS_TEMP_RANGE_MIN,
+ CISLANDS_TEMP_RANGE_MAX);
+ if (ret) {
+ DRM_ERROR("ci_thermal_set_temperature_range failed\n");
+ return ret;
+ }
+ amdgpu_irq_get(adev, &adev->pm.dpm.thermal.irq,
+ AMDGPU_THERMAL_IRQ_LOW_TO_HIGH);
+ amdgpu_irq_get(adev, &adev->pm.dpm.thermal.irq,
+ AMDGPU_THERMAL_IRQ_HIGH_TO_LOW);
+
+#if 0
+ result = amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_EnableThermalInterrupt);
+
+ if (result != PPSMC_Result_OK)
+ DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+#endif
+ }
+
+ return 0;
+}
+
+static void ci_dpm_disable(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct amdgpu_ps *boot_ps = adev->pm.dpm.boot_ps;
+
+ amdgpu_irq_put(adev, &adev->pm.dpm.thermal.irq,
+ AMDGPU_THERMAL_IRQ_LOW_TO_HIGH);
+ amdgpu_irq_put(adev, &adev->pm.dpm.thermal.irq,
+ AMDGPU_THERMAL_IRQ_HIGH_TO_LOW);
+
+ ci_dpm_powergate_uvd(adev, false);
+
+ if (!amdgpu_ci_is_smc_running(adev))
+ return;
+
+ ci_thermal_stop_thermal_controller(adev);
+
+ if (pi->thermal_protection)
+ ci_enable_thermal_protection(adev, false);
+ ci_enable_power_containment(adev, false);
+ ci_enable_smc_cac(adev, false);
+ ci_enable_didt(adev, false);
+ ci_enable_spread_spectrum(adev, false);
+ ci_enable_auto_throttle_source(adev, AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL, false);
+ ci_stop_dpm(adev);
+ ci_enable_ds_master_switch(adev, false);
+ ci_enable_ulv(adev, false);
+ ci_clear_vc(adev);
+ ci_reset_to_default(adev);
+ ci_dpm_stop_smc(adev);
+ ci_force_switch_to_arb_f0(adev);
+ ci_enable_thermal_based_sclk_dpm(adev, false);
+
+ ci_update_current_ps(adev, boot_ps);
+}
+
+static int ci_dpm_set_power_state(struct amdgpu_device *adev)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct amdgpu_ps *new_ps = &pi->requested_rps;
+ struct amdgpu_ps *old_ps = &pi->current_rps;
+ int ret;
+
+ ci_find_dpm_states_clocks_in_dpm_table(adev, new_ps);
+ if (pi->pcie_performance_request)
+ ci_request_link_speed_change_before_state_change(adev, new_ps, old_ps);
+ ret = ci_freeze_sclk_mclk_dpm(adev);
+ if (ret) {
+ DRM_ERROR("ci_freeze_sclk_mclk_dpm failed\n");
+ return ret;
+ }
+ ret = ci_populate_and_upload_sclk_mclk_dpm_levels(adev, new_ps);
+ if (ret) {
+ DRM_ERROR("ci_populate_and_upload_sclk_mclk_dpm_levels failed\n");
+ return ret;
+ }
+ ret = ci_generate_dpm_level_enable_mask(adev, new_ps);
+ if (ret) {
+ DRM_ERROR("ci_generate_dpm_level_enable_mask failed\n");
+ return ret;
+ }
+
+ ret = ci_update_vce_dpm(adev, new_ps, old_ps);
+ if (ret) {
+ DRM_ERROR("ci_update_vce_dpm failed\n");
+ return ret;
+ }
+
+ ret = ci_update_sclk_t(adev);
+ if (ret) {
+ DRM_ERROR("ci_update_sclk_t failed\n");
+ return ret;
+ }
+ if (pi->caps_dynamic_ac_timing) {
+ ret = ci_update_and_upload_mc_reg_table(adev);
+ if (ret) {
+ DRM_ERROR("ci_update_and_upload_mc_reg_table failed\n");
+ return ret;
+ }
+ }
+ ret = ci_program_memory_timing_parameters(adev);
+ if (ret) {
+ DRM_ERROR("ci_program_memory_timing_parameters failed\n");
+ return ret;
+ }
+ ret = ci_unfreeze_sclk_mclk_dpm(adev);
+ if (ret) {
+ DRM_ERROR("ci_unfreeze_sclk_mclk_dpm failed\n");
+ return ret;
+ }
+ ret = ci_upload_dpm_level_enable_mask(adev);
+ if (ret) {
+ DRM_ERROR("ci_upload_dpm_level_enable_mask failed\n");
+ return ret;
+ }
+ if (pi->pcie_performance_request)
+ ci_notify_link_speed_change_after_state_change(adev, new_ps, old_ps);
+
+ return 0;
+}
+
+#if 0
+static void ci_dpm_reset_asic(struct amdgpu_device *adev)
+{
+ ci_set_boot_state(adev);
+}
+#endif
+
+static void ci_dpm_display_configuration_changed(struct amdgpu_device *adev)
+{
+ ci_program_display_gap(adev);
+}
+
+union power_info {
+ struct _ATOM_POWERPLAY_INFO info;
+ struct _ATOM_POWERPLAY_INFO_V2 info_2;
+ struct _ATOM_POWERPLAY_INFO_V3 info_3;
+ struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+ struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+ struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+};
+
+union pplib_clock_info {
+ struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
+ struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
+ struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
+ struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
+ struct _ATOM_PPLIB_SI_CLOCK_INFO si;
+ struct _ATOM_PPLIB_CI_CLOCK_INFO ci;
+};
+
+union pplib_power_state {
+ struct _ATOM_PPLIB_STATE v1;
+ struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void ci_parse_pplib_non_clock_info(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps,
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
+ u8 table_rev)
+{
+ rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
+ rps->class = le16_to_cpu(non_clock_info->usClassification);
+ rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
+
+ if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
+ rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
+ rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
+ } else {
+ rps->vclk = 0;
+ rps->dclk = 0;
+ }
+
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+ adev->pm.dpm.boot_ps = rps;
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+ adev->pm.dpm.uvd_ps = rps;
+}
+
+static void ci_parse_pplib_clock_info(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps, int index,
+ union pplib_clock_info *clock_info)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_ps *ps = ci_get_ps(rps);
+ struct ci_pl *pl = &ps->performance_levels[index];
+
+ ps->performance_level_count = index + 1;
+
+ pl->sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
+ pl->sclk |= clock_info->ci.ucEngineClockHigh << 16;
+ pl->mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
+ pl->mclk |= clock_info->ci.ucMemoryClockHigh << 16;
+
+ pl->pcie_gen = amdgpu_get_pcie_gen_support(adev,
+ pi->sys_pcie_mask,
+ pi->vbios_boot_state.pcie_gen_bootup_value,
+ clock_info->ci.ucPCIEGen);
+ pl->pcie_lane = amdgpu_get_pcie_lane_support(adev,
+ pi->vbios_boot_state.pcie_lane_bootup_value,
+ le16_to_cpu(clock_info->ci.usPCIELane));
+
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
+ pi->acpi_pcie_gen = pl->pcie_gen;
+ }
+
+ if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) {
+ pi->ulv.supported = true;
+ pi->ulv.pl = *pl;
+ pi->ulv.cg_ulv_parameter = CISLANDS_CGULVPARAMETER_DFLT;
+ }
+
+ /* patch up boot state */
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+ pl->mclk = pi->vbios_boot_state.mclk_bootup_value;
+ pl->sclk = pi->vbios_boot_state.sclk_bootup_value;
+ pl->pcie_gen = pi->vbios_boot_state.pcie_gen_bootup_value;
+ pl->pcie_lane = pi->vbios_boot_state.pcie_lane_bootup_value;
+ }
+
+ switch (rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
+ case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
+ pi->use_pcie_powersaving_levels = true;
+ if (pi->pcie_gen_powersaving.max < pl->pcie_gen)
+ pi->pcie_gen_powersaving.max = pl->pcie_gen;
+ if (pi->pcie_gen_powersaving.min > pl->pcie_gen)
+ pi->pcie_gen_powersaving.min = pl->pcie_gen;
+ if (pi->pcie_lane_powersaving.max < pl->pcie_lane)
+ pi->pcie_lane_powersaving.max = pl->pcie_lane;
+ if (pi->pcie_lane_powersaving.min > pl->pcie_lane)
+ pi->pcie_lane_powersaving.min = pl->pcie_lane;
+ break;
+ case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
+ pi->use_pcie_performance_levels = true;
+ if (pi->pcie_gen_performance.max < pl->pcie_gen)
+ pi->pcie_gen_performance.max = pl->pcie_gen;
+ if (pi->pcie_gen_performance.min > pl->pcie_gen)
+ pi->pcie_gen_performance.min = pl->pcie_gen;
+ if (pi->pcie_lane_performance.max < pl->pcie_lane)
+ pi->pcie_lane_performance.max = pl->pcie_lane;
+ if (pi->pcie_lane_performance.min > pl->pcie_lane)
+ pi->pcie_lane_performance.min = pl->pcie_lane;
+ break;
+ default:
+ break;
+ }
+}
+
+static int ci_parse_power_table(struct amdgpu_device *adev)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+ union pplib_power_state *power_state;
+ int i, j, k, non_clock_array_index, clock_array_index;
+ union pplib_clock_info *clock_info;
+ struct _StateArray *state_array;
+ struct _ClockInfoArray *clock_info_array;
+ struct _NonClockInfoArray *non_clock_info_array;
+ union power_info *power_info;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ u16 data_offset;
+ u8 frev, crev;
+ u8 *power_state_offset;
+ struct ci_ps *ps;
+
+ if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset))
+ return -EINVAL;
+ power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+ amdgpu_add_thermal_controller(adev);
+
+ state_array = (struct _StateArray *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usStateArrayOffset));
+ clock_info_array = (struct _ClockInfoArray *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
+ non_clock_info_array = (struct _NonClockInfoArray *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
+
+ adev->pm.dpm.ps = kzalloc(sizeof(struct amdgpu_ps) *
+ state_array->ucNumEntries, GFP_KERNEL);
+ if (!adev->pm.dpm.ps)
+ return -ENOMEM;
+ power_state_offset = (u8 *)state_array->states;
+ for (i = 0; i < state_array->ucNumEntries; i++) {
+ u8 *idx;
+ power_state = (union pplib_power_state *)power_state_offset;
+ non_clock_array_index = power_state->v2.nonClockInfoIndex;
+ non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+ &non_clock_info_array->nonClockInfo[non_clock_array_index];
+ ps = kzalloc(sizeof(struct ci_ps), GFP_KERNEL);
+ if (ps == NULL) {
+ kfree(adev->pm.dpm.ps);
+ return -ENOMEM;
+ }
+ adev->pm.dpm.ps[i].ps_priv = ps;
+ ci_parse_pplib_non_clock_info(adev, &adev->pm.dpm.ps[i],
+ non_clock_info,
+ non_clock_info_array->ucEntrySize);
+ k = 0;
+ idx = (u8 *)&power_state->v2.clockInfoIndex[0];
+ for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
+ clock_array_index = idx[j];
+ if (clock_array_index >= clock_info_array->ucNumEntries)
+ continue;
+ if (k >= CISLANDS_MAX_HARDWARE_POWERLEVELS)
+ break;
+ clock_info = (union pplib_clock_info *)
+ ((u8 *)&clock_info_array->clockInfo[0] +
+ (clock_array_index * clock_info_array->ucEntrySize));
+ ci_parse_pplib_clock_info(adev,
+ &adev->pm.dpm.ps[i], k,
+ clock_info);
+ k++;
+ }
+ power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
+ }
+ adev->pm.dpm.num_ps = state_array->ucNumEntries;
+
+ /* fill in the vce power states */
+ for (i = 0; i < AMDGPU_MAX_VCE_LEVELS; i++) {
+ u32 sclk, mclk;
+ clock_array_index = adev->pm.dpm.vce_states[i].clk_idx;
+ clock_info = (union pplib_clock_info *)
+ &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
+ sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
+ sclk |= clock_info->ci.ucEngineClockHigh << 16;
+ mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
+ mclk |= clock_info->ci.ucMemoryClockHigh << 16;
+ adev->pm.dpm.vce_states[i].sclk = sclk;
+ adev->pm.dpm.vce_states[i].mclk = mclk;
+ }
+
+ return 0;
+}
+
+static int ci_get_vbios_boot_values(struct amdgpu_device *adev,
+ struct ci_vbios_boot_state *boot_state)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+ ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
+ u8 frev, crev;
+ u16 data_offset;
+
+ if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset)) {
+ firmware_info =
+ (ATOM_FIRMWARE_INFO_V2_2 *)(mode_info->atom_context->bios +
+ data_offset);
+ boot_state->mvdd_bootup_value = le16_to_cpu(firmware_info->usBootUpMVDDCVoltage);
+ boot_state->vddc_bootup_value = le16_to_cpu(firmware_info->usBootUpVDDCVoltage);
+ boot_state->vddci_bootup_value = le16_to_cpu(firmware_info->usBootUpVDDCIVoltage);
+ boot_state->pcie_gen_bootup_value = ci_get_current_pcie_speed(adev);
+ boot_state->pcie_lane_bootup_value = ci_get_current_pcie_lane_number(adev);
+ boot_state->sclk_bootup_value = le32_to_cpu(firmware_info->ulDefaultEngineClock);
+ boot_state->mclk_bootup_value = le32_to_cpu(firmware_info->ulDefaultMemoryClock);
+
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void ci_dpm_fini(struct amdgpu_device *adev)
+{
+ int i;
+
+ for (i = 0; i < adev->pm.dpm.num_ps; i++) {
+ kfree(adev->pm.dpm.ps[i].ps_priv);
+ }
+ kfree(adev->pm.dpm.ps);
+ kfree(adev->pm.dpm.priv);
+ kfree(adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries);
+ amdgpu_free_extended_power_table(adev);
+}
+
+/**
+ * ci_dpm_init_microcode - load ucode images from disk
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Use the firmware interface to load the ucode images into
+ * the driver (not loaded into hw).
+ * Returns 0 on success, error on failure.
+ */
+static int ci_dpm_init_microcode(struct amdgpu_device *adev)
+{
+ const char *chip_name;
+ char fw_name[30];
+ int err;
+
+ DRM_DEBUG("\n");
+
+ switch (adev->asic_type) {
+ case CHIP_BONAIRE:
+ chip_name = "bonaire";
+ break;
+ case CHIP_HAWAII:
+ chip_name = "hawaii";
+ break;
+ case CHIP_KAVERI:
+ case CHIP_KABINI:
+ default: BUG();
+ }
+
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
+ err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
+ if (err)
+ goto out;
+ err = amdgpu_ucode_validate(adev->pm.fw);
+
+out:
+ if (err) {
+ printk(KERN_ERR
+ "cik_smc: Failed to load firmware \"%s\"\n",
+ fw_name);
+ release_firmware(adev->pm.fw);
+ adev->pm.fw = NULL;
+ }
+ return err;
+}
+
+static int ci_dpm_init(struct amdgpu_device *adev)
+{
+ int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+ SMU7_Discrete_DpmTable *dpm_table;
+ struct amdgpu_gpio_rec gpio;
+ u16 data_offset, size;
+ u8 frev, crev;
+ struct ci_power_info *pi;
+ int ret;
+ u32 mask;
+
+ pi = kzalloc(sizeof(struct ci_power_info), GFP_KERNEL);
+ if (pi == NULL)
+ return -ENOMEM;
+ adev->pm.dpm.priv = pi;
+
+ ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
+ if (ret)
+ pi->sys_pcie_mask = 0;
+ else
+ pi->sys_pcie_mask = mask;
+ pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID;
+
+ pi->pcie_gen_performance.max = AMDGPU_PCIE_GEN1;
+ pi->pcie_gen_performance.min = AMDGPU_PCIE_GEN3;
+ pi->pcie_gen_powersaving.max = AMDGPU_PCIE_GEN1;
+ pi->pcie_gen_powersaving.min = AMDGPU_PCIE_GEN3;
+
+ pi->pcie_lane_performance.max = 0;
+ pi->pcie_lane_performance.min = 16;
+ pi->pcie_lane_powersaving.max = 0;
+ pi->pcie_lane_powersaving.min = 16;
+
+ ret = ci_get_vbios_boot_values(adev, &pi->vbios_boot_state);
+ if (ret) {
+ ci_dpm_fini(adev);
+ return ret;
+ }
+
+ ret = amdgpu_get_platform_caps(adev);
+ if (ret) {
+ ci_dpm_fini(adev);
+ return ret;
+ }
+
+ ret = amdgpu_parse_extended_power_table(adev);
+ if (ret) {
+ ci_dpm_fini(adev);
+ return ret;
+ }
+
+ ret = ci_parse_power_table(adev);
+ if (ret) {
+ ci_dpm_fini(adev);
+ return ret;
+ }
+
+ pi->dll_default_on = false;
+ pi->sram_end = SMC_RAM_END;
+
+ pi->activity_target[0] = CISLAND_TARGETACTIVITY_DFLT;
+ pi->activity_target[1] = CISLAND_TARGETACTIVITY_DFLT;
+ pi->activity_target[2] = CISLAND_TARGETACTIVITY_DFLT;
+ pi->activity_target[3] = CISLAND_TARGETACTIVITY_DFLT;
+ pi->activity_target[4] = CISLAND_TARGETACTIVITY_DFLT;
+ pi->activity_target[5] = CISLAND_TARGETACTIVITY_DFLT;
+ pi->activity_target[6] = CISLAND_TARGETACTIVITY_DFLT;
+ pi->activity_target[7] = CISLAND_TARGETACTIVITY_DFLT;
+
+ pi->mclk_activity_target = CISLAND_MCLK_TARGETACTIVITY_DFLT;
+
+ pi->sclk_dpm_key_disabled = 0;
+ pi->mclk_dpm_key_disabled = 0;
+ pi->pcie_dpm_key_disabled = 0;
+ pi->thermal_sclk_dpm_enabled = 0;
+
+ pi->caps_sclk_ds = true;
+
+ pi->mclk_strobe_mode_threshold = 40000;
+ pi->mclk_stutter_mode_threshold = 40000;
+ pi->mclk_edc_enable_threshold = 40000;
+ pi->mclk_edc_wr_enable_threshold = 40000;
+
+ ci_initialize_powertune_defaults(adev);
+
+ pi->caps_fps = false;
+
+ pi->caps_sclk_throttle_low_notification = false;
+
+ pi->caps_uvd_dpm = true;
+ pi->caps_vce_dpm = true;
+
+ ci_get_leakage_voltages(adev);
+ ci_patch_dependency_tables_with_leakage(adev);
+ ci_set_private_data_variables_based_on_pptable(adev);
+
+ adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries =
+ kzalloc(4 * sizeof(struct amdgpu_clock_voltage_dependency_entry), GFP_KERNEL);
+ if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) {
+ ci_dpm_fini(adev);
+ return -ENOMEM;
+ }
+ adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4;
+ adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0;
+ adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0;
+ adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].clk = 36000;
+ adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].v = 720;
+ adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].clk = 54000;
+ adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].v = 810;
+ adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].clk = 72000;
+ adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].v = 900;
+
+ adev->pm.dpm.dyn_state.mclk_sclk_ratio = 4;
+ adev->pm.dpm.dyn_state.sclk_mclk_delta = 15000;
+ adev->pm.dpm.dyn_state.vddc_vddci_delta = 200;
+
+ adev->pm.dpm.dyn_state.valid_sclk_values.count = 0;
+ adev->pm.dpm.dyn_state.valid_sclk_values.values = NULL;
+ adev->pm.dpm.dyn_state.valid_mclk_values.count = 0;
+ adev->pm.dpm.dyn_state.valid_mclk_values.values = NULL;
+
+ if (adev->asic_type == CHIP_HAWAII) {
+ pi->thermal_temp_setting.temperature_low = 94500;
+ pi->thermal_temp_setting.temperature_high = 95000;
+ pi->thermal_temp_setting.temperature_shutdown = 104000;
+ } else {
+ pi->thermal_temp_setting.temperature_low = 99500;
+ pi->thermal_temp_setting.temperature_high = 100000;
+ pi->thermal_temp_setting.temperature_shutdown = 104000;
+ }
+
+ pi->uvd_enabled = false;
+
+ dpm_table = &pi->smc_state_table;
+
+ gpio = amdgpu_atombios_lookup_gpio(adev, VDDC_VRHOT_GPIO_PINID);
+ if (gpio.valid) {
+ dpm_table->VRHotGpio = gpio.shift;
+ adev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_REGULATOR_HOT;
+ } else {
+ dpm_table->VRHotGpio = CISLANDS_UNUSED_GPIO_PIN;
+ adev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_REGULATOR_HOT;
+ }
+
+ gpio = amdgpu_atombios_lookup_gpio(adev, PP_AC_DC_SWITCH_GPIO_PINID);
+ if (gpio.valid) {
+ dpm_table->AcDcGpio = gpio.shift;
+ adev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_HARDWAREDC;
+ } else {
+ dpm_table->AcDcGpio = CISLANDS_UNUSED_GPIO_PIN;
+ adev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_HARDWAREDC;
+ }
+
+ gpio = amdgpu_atombios_lookup_gpio(adev, VDDC_PCC_GPIO_PINID);
+ if (gpio.valid) {
+ u32 tmp = RREG32_SMC(ixCNB_PWRMGT_CNTL);
+
+ switch (gpio.shift) {
+ case 0:
+ tmp &= ~CNB_PWRMGT_CNTL__GNB_SLOW_MODE_MASK;
+ tmp |= 1 << CNB_PWRMGT_CNTL__GNB_SLOW_MODE__SHIFT;
+ break;
+ case 1:
+ tmp &= ~CNB_PWRMGT_CNTL__GNB_SLOW_MODE_MASK;
+ tmp |= 2 << CNB_PWRMGT_CNTL__GNB_SLOW_MODE__SHIFT;
+ break;
+ case 2:
+ tmp |= CNB_PWRMGT_CNTL__GNB_SLOW_MASK;
+ break;
+ case 3:
+ tmp |= CNB_PWRMGT_CNTL__FORCE_NB_PS1_MASK;
+ break;
+ case 4:
+ tmp |= CNB_PWRMGT_CNTL__DPM_ENABLED_MASK;
+ break;
+ default:
+ DRM_ERROR("Invalid PCC GPIO: %u!\n", gpio.shift);
+ break;
+ }
+ WREG32_SMC(ixCNB_PWRMGT_CNTL, tmp);
+ }
+
+ pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_NONE;
+ pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_NONE;
+ pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_NONE;
+ if (amdgpu_atombios_is_voltage_gpio(adev, VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_GPIO_LUT))
+ pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO;
+ else if (amdgpu_atombios_is_voltage_gpio(adev, VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
+ pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2;
+
+ if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL) {
+ if (amdgpu_atombios_is_voltage_gpio(adev, VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
+ pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO;
+ else if (amdgpu_atombios_is_voltage_gpio(adev, VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
+ pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2;
+ else
+ adev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL;
+ }
+
+ if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_MVDDCONTROL) {
+ if (amdgpu_atombios_is_voltage_gpio(adev, VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
+ pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO;
+ else if (amdgpu_atombios_is_voltage_gpio(adev, VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2))
+ pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2;
+ else
+ adev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_MVDDCONTROL;
+ }
+
+ pi->vddc_phase_shed_control = true;
+
+#if defined(CONFIG_ACPI)
+ pi->pcie_performance_request =
+ amdgpu_acpi_is_pcie_performance_request_supported(adev);
+#else
+ pi->pcie_performance_request = false;
+#endif
+
+ if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ pi->caps_sclk_ss_support = true;
+ pi->caps_mclk_ss_support = true;
+ pi->dynamic_ss = true;
+ } else {
+ pi->caps_sclk_ss_support = false;
+ pi->caps_mclk_ss_support = false;
+ pi->dynamic_ss = true;
+ }
+
+ if (adev->pm.int_thermal_type != THERMAL_TYPE_NONE)
+ pi->thermal_protection = true;
+ else
+ pi->thermal_protection = false;
+
+ pi->caps_dynamic_ac_timing = true;
+
+ pi->uvd_power_gated = false;
+
+ /* make sure dc limits are valid */
+ if ((adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk == 0) ||
+ (adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk == 0))
+ adev->pm.dpm.dyn_state.max_clock_voltage_on_dc =
+ adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+
+ pi->fan_ctrl_is_in_default_mode = true;
+
+ return 0;
+}
+
+static void
+ci_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev,
+ struct seq_file *m)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct amdgpu_ps *rps = &pi->current_rps;
+ u32 sclk = ci_get_average_sclk_freq(adev);
+ u32 mclk = ci_get_average_mclk_freq(adev);
+
+ 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);
+}
+
+static void ci_dpm_print_power_state(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps)
+{
+ struct ci_ps *ps = ci_get_ps(rps);
+ struct ci_pl *pl;
+ int i;
+
+ amdgpu_dpm_print_class_info(rps->class, rps->class2);
+ amdgpu_dpm_print_cap_info(rps->caps);
+ printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ for (i = 0; i < ps->performance_level_count; i++) {
+ pl = &ps->performance_levels[i];
+ printk("\t\tpower level %d sclk: %u mclk: %u pcie gen: %u pcie lanes: %u\n",
+ i, pl->sclk, pl->mclk, pl->pcie_gen + 1, pl->pcie_lane);
+ }
+ amdgpu_dpm_print_ps_status(adev, rps);
+}
+
+static u32 ci_dpm_get_sclk(struct amdgpu_device *adev, bool low)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_ps *requested_state = ci_get_ps(&pi->requested_rps);
+
+ if (low)
+ return requested_state->performance_levels[0].sclk;
+ else
+ return requested_state->performance_levels[requested_state->performance_level_count - 1].sclk;
+}
+
+static u32 ci_dpm_get_mclk(struct amdgpu_device *adev, bool low)
+{
+ struct ci_power_info *pi = ci_get_pi(adev);
+ struct ci_ps *requested_state = ci_get_ps(&pi->requested_rps);
+
+ if (low)
+ return requested_state->performance_levels[0].mclk;
+ else
+ return requested_state->performance_levels[requested_state->performance_level_count - 1].mclk;
+}
+
+/* get temperature in millidegrees */
+static int ci_dpm_get_temp(struct amdgpu_device *adev)
+{
+ u32 temp;
+ int actual_temp = 0;
+
+ temp = (RREG32_SMC(ixCG_MULT_THERMAL_STATUS) & CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >>
+ CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT;
+
+ if (temp & 0x200)
+ actual_temp = 255;
+ else
+ actual_temp = temp & 0x1ff;
+
+ actual_temp = actual_temp * 1000;
+
+ return actual_temp;
+}
+
+static int ci_set_temperature_range(struct amdgpu_device *adev)
+{
+ int ret;
+
+ ret = ci_thermal_enable_alert(adev, false);
+ if (ret)
+ return ret;
+ ret = ci_thermal_set_temperature_range(adev, CISLANDS_TEMP_RANGE_MIN,
+ CISLANDS_TEMP_RANGE_MAX);
+ if (ret)
+ return ret;
+ ret = ci_thermal_enable_alert(adev, true);
+ if (ret)
+ return ret;
+ return ret;
+}
+
+static int ci_dpm_early_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ ci_dpm_set_dpm_funcs(adev);
+ ci_dpm_set_irq_funcs(adev);
+
+ return 0;
+}
+
+static int ci_dpm_late_init(void *handle)
+{
+ int ret;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (!amdgpu_dpm)
+ return 0;
+
+ ret = ci_set_temperature_range(adev);
+ if (ret)
+ return ret;
+
+ ci_dpm_powergate_uvd(adev, true);
+
+ return 0;
+}
+
+static int ci_dpm_sw_init(void *handle)
+{
+ int ret;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ ret = amdgpu_irq_add_id(adev, 230, &adev->pm.dpm.thermal.irq);
+ if (ret)
+ return ret;
+
+ ret = amdgpu_irq_add_id(adev, 231, &adev->pm.dpm.thermal.irq);
+ if (ret)
+ return ret;
+
+ /* default to balanced state */
+ adev->pm.dpm.state = POWER_STATE_TYPE_BALANCED;
+ adev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
+ adev->pm.dpm.forced_level = AMDGPU_DPM_FORCED_LEVEL_AUTO;
+ adev->pm.default_sclk = adev->clock.default_sclk;
+ adev->pm.default_mclk = adev->clock.default_mclk;
+ adev->pm.current_sclk = adev->clock.default_sclk;
+ adev->pm.current_mclk = adev->clock.default_mclk;
+ adev->pm.int_thermal_type = THERMAL_TYPE_NONE;
+
+ if (amdgpu_dpm == 0)
+ return 0;
+
+ ret = ci_dpm_init_microcode(adev);
+ if (ret)
+ return ret;
+
+ INIT_WORK(&adev->pm.dpm.thermal.work, amdgpu_dpm_thermal_work_handler);
+ mutex_lock(&adev->pm.mutex);
+ ret = ci_dpm_init(adev);
+ if (ret)
+ goto dpm_failed;
+ adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps;
+ if (amdgpu_dpm == 1)
+ amdgpu_pm_print_power_states(adev);
+ ret = amdgpu_pm_sysfs_init(adev);
+ if (ret)
+ goto dpm_failed;
+ mutex_unlock(&adev->pm.mutex);
+ DRM_INFO("amdgpu: dpm initialized\n");
+
+ return 0;
+
+dpm_failed:
+ ci_dpm_fini(adev);
+ mutex_unlock(&adev->pm.mutex);
+ DRM_ERROR("amdgpu: dpm initialization failed\n");
+ return ret;
+}
+
+static int ci_dpm_sw_fini(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ mutex_lock(&adev->pm.mutex);
+ amdgpu_pm_sysfs_fini(adev);
+ ci_dpm_fini(adev);
+ mutex_unlock(&adev->pm.mutex);
+
+ return 0;
+}
+
+static int ci_dpm_hw_init(void *handle)
+{
+ int ret;
+
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (!amdgpu_dpm)
+ return 0;
+
+ mutex_lock(&adev->pm.mutex);
+ ci_dpm_setup_asic(adev);
+ ret = ci_dpm_enable(adev);
+ if (ret)
+ adev->pm.dpm_enabled = false;
+ else
+ adev->pm.dpm_enabled = true;
+ mutex_unlock(&adev->pm.mutex);
+
+ return ret;
+}
+
+static int ci_dpm_hw_fini(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->pm.dpm_enabled) {
+ mutex_lock(&adev->pm.mutex);
+ ci_dpm_disable(adev);
+ mutex_unlock(&adev->pm.mutex);
+ }
+
+ return 0;
+}
+
+static int ci_dpm_suspend(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->pm.dpm_enabled) {
+ mutex_lock(&adev->pm.mutex);
+ /* disable dpm */
+ ci_dpm_disable(adev);
+ /* reset the power state */
+ adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps;
+ mutex_unlock(&adev->pm.mutex);
+ }
+ return 0;
+}
+
+static int ci_dpm_resume(void *handle)
+{
+ int ret;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->pm.dpm_enabled) {
+ /* asic init will reset to the boot state */
+ mutex_lock(&adev->pm.mutex);
+ ci_dpm_setup_asic(adev);
+ ret = ci_dpm_enable(adev);
+ if (ret)
+ adev->pm.dpm_enabled = false;
+ else
+ adev->pm.dpm_enabled = true;
+ mutex_unlock(&adev->pm.mutex);
+ if (adev->pm.dpm_enabled)
+ amdgpu_pm_compute_clocks(adev);
+ }
+ return 0;
+}
+
+static bool ci_dpm_is_idle(void *handle)
+{
+ /* XXX */
+ return true;
+}
+
+static int ci_dpm_wait_for_idle(void *handle)
+{
+ /* XXX */
+ return 0;
+}
+
+static void ci_dpm_print_status(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ dev_info(adev->dev, "CIK DPM registers\n");
+ dev_info(adev->dev, " BIOS_SCRATCH_4=0x%08X\n",
+ RREG32(mmBIOS_SCRATCH_4));
+ dev_info(adev->dev, " MC_ARB_DRAM_TIMING=0x%08X\n",
+ RREG32(mmMC_ARB_DRAM_TIMING));
+ dev_info(adev->dev, " MC_ARB_DRAM_TIMING2=0x%08X\n",
+ RREG32(mmMC_ARB_DRAM_TIMING2));
+ dev_info(adev->dev, " MC_ARB_BURST_TIME=0x%08X\n",
+ RREG32(mmMC_ARB_BURST_TIME));
+ dev_info(adev->dev, " MC_ARB_DRAM_TIMING_1=0x%08X\n",
+ RREG32(mmMC_ARB_DRAM_TIMING_1));
+ dev_info(adev->dev, " MC_ARB_DRAM_TIMING2_1=0x%08X\n",
+ RREG32(mmMC_ARB_DRAM_TIMING2_1));
+ dev_info(adev->dev, " MC_CG_CONFIG=0x%08X\n",
+ RREG32(mmMC_CG_CONFIG));
+ dev_info(adev->dev, " MC_ARB_CG=0x%08X\n",
+ RREG32(mmMC_ARB_CG));
+ dev_info(adev->dev, " DIDT_SQ_CTRL0=0x%08X\n",
+ RREG32_DIDT(ixDIDT_SQ_CTRL0));
+ dev_info(adev->dev, " DIDT_DB_CTRL0=0x%08X\n",
+ RREG32_DIDT(ixDIDT_DB_CTRL0));
+ dev_info(adev->dev, " DIDT_TD_CTRL0=0x%08X\n",
+ RREG32_DIDT(ixDIDT_TD_CTRL0));
+ dev_info(adev->dev, " DIDT_TCP_CTRL0=0x%08X\n",
+ RREG32_DIDT(ixDIDT_TCP_CTRL0));
+ dev_info(adev->dev, " CG_THERMAL_INT=0x%08X\n",
+ RREG32_SMC(ixCG_THERMAL_INT));
+ dev_info(adev->dev, " CG_THERMAL_CTRL=0x%08X\n",
+ RREG32_SMC(ixCG_THERMAL_CTRL));
+ dev_info(adev->dev, " GENERAL_PWRMGT=0x%08X\n",
+ RREG32_SMC(ixGENERAL_PWRMGT));
+ dev_info(adev->dev, " MC_SEQ_CNTL_3=0x%08X\n",
+ RREG32(mmMC_SEQ_CNTL_3));
+ dev_info(adev->dev, " LCAC_MC0_CNTL=0x%08X\n",
+ RREG32_SMC(ixLCAC_MC0_CNTL));
+ dev_info(adev->dev, " LCAC_MC1_CNTL=0x%08X\n",
+ RREG32_SMC(ixLCAC_MC1_CNTL));
+ dev_info(adev->dev, " LCAC_CPL_CNTL=0x%08X\n",
+ RREG32_SMC(ixLCAC_CPL_CNTL));
+ dev_info(adev->dev, " SCLK_PWRMGT_CNTL=0x%08X\n",
+ RREG32_SMC(ixSCLK_PWRMGT_CNTL));
+ dev_info(adev->dev, " BIF_LNCNT_RESET=0x%08X\n",
+ RREG32(mmBIF_LNCNT_RESET));
+ dev_info(adev->dev, " FIRMWARE_FLAGS=0x%08X\n",
+ RREG32_SMC(ixFIRMWARE_FLAGS));
+ dev_info(adev->dev, " CG_SPLL_FUNC_CNTL=0x%08X\n",
+ RREG32_SMC(ixCG_SPLL_FUNC_CNTL));
+ dev_info(adev->dev, " CG_SPLL_FUNC_CNTL_2=0x%08X\n",
+ RREG32_SMC(ixCG_SPLL_FUNC_CNTL_2));
+ dev_info(adev->dev, " CG_SPLL_FUNC_CNTL_3=0x%08X\n",
+ RREG32_SMC(ixCG_SPLL_FUNC_CNTL_3));
+ dev_info(adev->dev, " CG_SPLL_FUNC_CNTL_4=0x%08X\n",
+ RREG32_SMC(ixCG_SPLL_FUNC_CNTL_4));
+ dev_info(adev->dev, " CG_SPLL_SPREAD_SPECTRUM=0x%08X\n",
+ RREG32_SMC(ixCG_SPLL_SPREAD_SPECTRUM));
+ dev_info(adev->dev, " CG_SPLL_SPREAD_SPECTRUM_2=0x%08X\n",
+ RREG32_SMC(ixCG_SPLL_SPREAD_SPECTRUM_2));
+ dev_info(adev->dev, " DLL_CNTL=0x%08X\n",
+ RREG32(mmDLL_CNTL));
+ dev_info(adev->dev, " MCLK_PWRMGT_CNTL=0x%08X\n",
+ RREG32(mmMCLK_PWRMGT_CNTL));
+ dev_info(adev->dev, " MPLL_AD_FUNC_CNTL=0x%08X\n",
+ RREG32(mmMPLL_AD_FUNC_CNTL));
+ dev_info(adev->dev, " MPLL_DQ_FUNC_CNTL=0x%08X\n",
+ RREG32(mmMPLL_DQ_FUNC_CNTL));
+ dev_info(adev->dev, " MPLL_FUNC_CNTL=0x%08X\n",
+ RREG32(mmMPLL_FUNC_CNTL));
+ dev_info(adev->dev, " MPLL_FUNC_CNTL_1=0x%08X\n",
+ RREG32(mmMPLL_FUNC_CNTL_1));
+ dev_info(adev->dev, " MPLL_FUNC_CNTL_2=0x%08X\n",
+ RREG32(mmMPLL_FUNC_CNTL_2));
+ dev_info(adev->dev, " MPLL_SS1=0x%08X\n",
+ RREG32(mmMPLL_SS1));
+ dev_info(adev->dev, " MPLL_SS2=0x%08X\n",
+ RREG32(mmMPLL_SS2));
+ dev_info(adev->dev, " CG_DISPLAY_GAP_CNTL=0x%08X\n",
+ RREG32_SMC(ixCG_DISPLAY_GAP_CNTL));
+ dev_info(adev->dev, " CG_DISPLAY_GAP_CNTL2=0x%08X\n",
+ RREG32_SMC(ixCG_DISPLAY_GAP_CNTL2));
+ dev_info(adev->dev, " CG_STATIC_SCREEN_PARAMETER=0x%08X\n",
+ RREG32_SMC(ixCG_STATIC_SCREEN_PARAMETER));
+ dev_info(adev->dev, " CG_FREQ_TRAN_VOTING_0=0x%08X\n",
+ RREG32_SMC(ixCG_FREQ_TRAN_VOTING_0));
+ dev_info(adev->dev, " CG_FREQ_TRAN_VOTING_1=0x%08X\n",
+ RREG32_SMC(ixCG_FREQ_TRAN_VOTING_1));
+ dev_info(adev->dev, " CG_FREQ_TRAN_VOTING_2=0x%08X\n",
+ RREG32_SMC(ixCG_FREQ_TRAN_VOTING_2));
+ dev_info(adev->dev, " CG_FREQ_TRAN_VOTING_3=0x%08X\n",
+ RREG32_SMC(ixCG_FREQ_TRAN_VOTING_3));
+ dev_info(adev->dev, " CG_FREQ_TRAN_VOTING_4=0x%08X\n",
+ RREG32_SMC(ixCG_FREQ_TRAN_VOTING_4));
+ dev_info(adev->dev, " CG_FREQ_TRAN_VOTING_5=0x%08X\n",
+ RREG32_SMC(ixCG_FREQ_TRAN_VOTING_5));
+ dev_info(adev->dev, " CG_FREQ_TRAN_VOTING_6=0x%08X\n",
+ RREG32_SMC(ixCG_FREQ_TRAN_VOTING_6));
+ dev_info(adev->dev, " CG_FREQ_TRAN_VOTING_7=0x%08X\n",
+ RREG32_SMC(ixCG_FREQ_TRAN_VOTING_7));
+ dev_info(adev->dev, " RCU_UC_EVENTS=0x%08X\n",
+ RREG32_SMC(ixRCU_UC_EVENTS));
+ dev_info(adev->dev, " DPM_TABLE_475=0x%08X\n",
+ RREG32_SMC(ixDPM_TABLE_475));
+ dev_info(adev->dev, " MC_SEQ_RAS_TIMING_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_RAS_TIMING_LP));
+ dev_info(adev->dev, " MC_SEQ_RAS_TIMING=0x%08X\n",
+ RREG32(mmMC_SEQ_RAS_TIMING));
+ dev_info(adev->dev, " MC_SEQ_CAS_TIMING_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_CAS_TIMING_LP));
+ dev_info(adev->dev, " MC_SEQ_CAS_TIMING=0x%08X\n",
+ RREG32(mmMC_SEQ_CAS_TIMING));
+ dev_info(adev->dev, " MC_SEQ_DLL_STBY_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_DLL_STBY_LP));
+ dev_info(adev->dev, " MC_SEQ_DLL_STBY=0x%08X\n",
+ RREG32(mmMC_SEQ_DLL_STBY));
+ dev_info(adev->dev, " MC_SEQ_G5PDX_CMD0_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_G5PDX_CMD0_LP));
+ dev_info(adev->dev, " MC_SEQ_G5PDX_CMD0=0x%08X\n",
+ RREG32(mmMC_SEQ_G5PDX_CMD0));
+ dev_info(adev->dev, " MC_SEQ_G5PDX_CMD1_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_G5PDX_CMD1_LP));
+ dev_info(adev->dev, " MC_SEQ_G5PDX_CMD1=0x%08X\n",
+ RREG32(mmMC_SEQ_G5PDX_CMD1));
+ dev_info(adev->dev, " MC_SEQ_G5PDX_CTRL_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_G5PDX_CTRL_LP));
+ dev_info(adev->dev, " MC_SEQ_G5PDX_CTRL=0x%08X\n",
+ RREG32(mmMC_SEQ_G5PDX_CTRL));
+ dev_info(adev->dev, " MC_SEQ_PMG_DVS_CMD_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_PMG_DVS_CMD_LP));
+ dev_info(adev->dev, " MC_SEQ_PMG_DVS_CMD=0x%08X\n",
+ RREG32(mmMC_SEQ_PMG_DVS_CMD));
+ dev_info(adev->dev, " MC_SEQ_PMG_DVS_CTL_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_PMG_DVS_CTL_LP));
+ dev_info(adev->dev, " MC_SEQ_PMG_DVS_CTL=0x%08X\n",
+ RREG32(mmMC_SEQ_PMG_DVS_CTL));
+ dev_info(adev->dev, " MC_SEQ_MISC_TIMING_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_MISC_TIMING_LP));
+ dev_info(adev->dev, " MC_SEQ_MISC_TIMING=0x%08X\n",
+ RREG32(mmMC_SEQ_MISC_TIMING));
+ dev_info(adev->dev, " MC_SEQ_MISC_TIMING2_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_MISC_TIMING2_LP));
+ dev_info(adev->dev, " MC_SEQ_MISC_TIMING2=0x%08X\n",
+ RREG32(mmMC_SEQ_MISC_TIMING2));
+ dev_info(adev->dev, " MC_SEQ_PMG_CMD_EMRS_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_PMG_CMD_EMRS_LP));
+ dev_info(adev->dev, " MC_PMG_CMD_EMRS=0x%08X\n",
+ RREG32(mmMC_PMG_CMD_EMRS));
+ dev_info(adev->dev, " MC_SEQ_PMG_CMD_MRS_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_PMG_CMD_MRS_LP));
+ dev_info(adev->dev, " MC_PMG_CMD_MRS=0x%08X\n",
+ RREG32(mmMC_PMG_CMD_MRS));
+ dev_info(adev->dev, " MC_SEQ_PMG_CMD_MRS1_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_PMG_CMD_MRS1_LP));
+ dev_info(adev->dev, " MC_PMG_CMD_MRS1=0x%08X\n",
+ RREG32(mmMC_PMG_CMD_MRS1));
+ dev_info(adev->dev, " MC_SEQ_WR_CTL_D0_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_WR_CTL_D0_LP));
+ dev_info(adev->dev, " MC_SEQ_WR_CTL_D0=0x%08X\n",
+ RREG32(mmMC_SEQ_WR_CTL_D0));
+ dev_info(adev->dev, " MC_SEQ_WR_CTL_D1_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_WR_CTL_D1_LP));
+ dev_info(adev->dev, " MC_SEQ_WR_CTL_D1=0x%08X\n",
+ RREG32(mmMC_SEQ_WR_CTL_D1));
+ dev_info(adev->dev, " MC_SEQ_RD_CTL_D0_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_RD_CTL_D0_LP));
+ dev_info(adev->dev, " MC_SEQ_RD_CTL_D0=0x%08X\n",
+ RREG32(mmMC_SEQ_RD_CTL_D0));
+ dev_info(adev->dev, " MC_SEQ_RD_CTL_D1_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_RD_CTL_D1_LP));
+ dev_info(adev->dev, " MC_SEQ_RD_CTL_D1=0x%08X\n",
+ RREG32(mmMC_SEQ_RD_CTL_D1));
+ dev_info(adev->dev, " MC_SEQ_PMG_TIMING_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_PMG_TIMING_LP));
+ dev_info(adev->dev, " MC_SEQ_PMG_TIMING=0x%08X\n",
+ RREG32(mmMC_SEQ_PMG_TIMING));
+ dev_info(adev->dev, " MC_SEQ_PMG_CMD_MRS2_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_PMG_CMD_MRS2_LP));
+ dev_info(adev->dev, " MC_PMG_CMD_MRS2=0x%08X\n",
+ RREG32(mmMC_PMG_CMD_MRS2));
+ dev_info(adev->dev, " MC_SEQ_WR_CTL_2_LP=0x%08X\n",
+ RREG32(mmMC_SEQ_WR_CTL_2_LP));
+ dev_info(adev->dev, " MC_SEQ_WR_CTL_2=0x%08X\n",
+ RREG32(mmMC_SEQ_WR_CTL_2));
+ dev_info(adev->dev, " PCIE_LC_SPEED_CNTL=0x%08X\n",
+ RREG32_PCIE(ixPCIE_LC_SPEED_CNTL));
+ dev_info(adev->dev, " PCIE_LC_LINK_WIDTH_CNTL=0x%08X\n",
+ RREG32_PCIE(ixPCIE_LC_LINK_WIDTH_CNTL));
+ dev_info(adev->dev, " SMC_IND_INDEX_0=0x%08X\n",
+ RREG32(mmSMC_IND_INDEX_0));
+ dev_info(adev->dev, " SMC_IND_DATA_0=0x%08X\n",
+ RREG32(mmSMC_IND_DATA_0));
+ dev_info(adev->dev, " SMC_IND_ACCESS_CNTL=0x%08X\n",
+ RREG32(mmSMC_IND_ACCESS_CNTL));
+ dev_info(adev->dev, " SMC_RESP_0=0x%08X\n",
+ RREG32(mmSMC_RESP_0));
+ dev_info(adev->dev, " SMC_MESSAGE_0=0x%08X\n",
+ RREG32(mmSMC_MESSAGE_0));
+ dev_info(adev->dev, " SMC_SYSCON_RESET_CNTL=0x%08X\n",
+ RREG32_SMC(ixSMC_SYSCON_RESET_CNTL));
+ dev_info(adev->dev, " SMC_SYSCON_CLOCK_CNTL_0=0x%08X\n",
+ RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0));
+ dev_info(adev->dev, " SMC_SYSCON_MISC_CNTL=0x%08X\n",
+ RREG32_SMC(ixSMC_SYSCON_MISC_CNTL));
+ dev_info(adev->dev, " SMC_PC_C=0x%08X\n",
+ RREG32_SMC(ixSMC_PC_C));
+}
+
+static int ci_dpm_soft_reset(void *handle)
+{
+ return 0;
+}
+
+static int ci_dpm_set_interrupt_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ unsigned type,
+ enum amdgpu_interrupt_state state)
+{
+ u32 cg_thermal_int;
+
+ switch (type) {
+ case AMDGPU_THERMAL_IRQ_LOW_TO_HIGH:
+ switch (state) {
+ case AMDGPU_IRQ_STATE_DISABLE:
+ cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
+ cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+ WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
+ break;
+ case AMDGPU_IRQ_STATE_ENABLE:
+ cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
+ cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+ WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case AMDGPU_THERMAL_IRQ_HIGH_TO_LOW:
+ switch (state) {
+ case AMDGPU_IRQ_STATE_DISABLE:
+ cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
+ cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+ WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
+ break;
+ case AMDGPU_IRQ_STATE_ENABLE:
+ cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
+ cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+ WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int ci_dpm_process_interrupt(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ bool queue_thermal = false;
+
+ if (entry == NULL)
+ return -EINVAL;
+
+ switch (entry->src_id) {
+ case 230: /* thermal low to high */
+ DRM_DEBUG("IH: thermal low to high\n");
+ adev->pm.dpm.thermal.high_to_low = false;
+ queue_thermal = true;
+ break;
+ case 231: /* thermal high to low */
+ DRM_DEBUG("IH: thermal high to low\n");
+ adev->pm.dpm.thermal.high_to_low = true;
+ queue_thermal = true;
+ break;
+ default:
+ break;
+ }
+
+ if (queue_thermal)
+ schedule_work(&adev->pm.dpm.thermal.work);
+
+ return 0;
+}
+
+static int ci_dpm_set_clockgating_state(void *handle,
+ enum amd_clockgating_state state)
+{
+ return 0;
+}
+
+static int ci_dpm_set_powergating_state(void *handle,
+ enum amd_powergating_state state)
+{
+ return 0;
+}
+
+const struct amd_ip_funcs ci_dpm_ip_funcs = {
+ .early_init = ci_dpm_early_init,
+ .late_init = ci_dpm_late_init,
+ .sw_init = ci_dpm_sw_init,
+ .sw_fini = ci_dpm_sw_fini,
+ .hw_init = ci_dpm_hw_init,
+ .hw_fini = ci_dpm_hw_fini,
+ .suspend = ci_dpm_suspend,
+ .resume = ci_dpm_resume,
+ .is_idle = ci_dpm_is_idle,
+ .wait_for_idle = ci_dpm_wait_for_idle,
+ .soft_reset = ci_dpm_soft_reset,
+ .print_status = ci_dpm_print_status,
+ .set_clockgating_state = ci_dpm_set_clockgating_state,
+ .set_powergating_state = ci_dpm_set_powergating_state,
+};
+
+static const struct amdgpu_dpm_funcs ci_dpm_funcs = {
+ .get_temperature = &ci_dpm_get_temp,
+ .pre_set_power_state = &ci_dpm_pre_set_power_state,
+ .set_power_state = &ci_dpm_set_power_state,
+ .post_set_power_state = &ci_dpm_post_set_power_state,
+ .display_configuration_changed = &ci_dpm_display_configuration_changed,
+ .get_sclk = &ci_dpm_get_sclk,
+ .get_mclk = &ci_dpm_get_mclk,
+ .print_power_state = &ci_dpm_print_power_state,
+ .debugfs_print_current_performance_level = &ci_dpm_debugfs_print_current_performance_level,
+ .force_performance_level = &ci_dpm_force_performance_level,
+ .vblank_too_short = &ci_dpm_vblank_too_short,
+ .powergate_uvd = &ci_dpm_powergate_uvd,
+ .set_fan_control_mode = &ci_dpm_set_fan_control_mode,
+ .get_fan_control_mode = &ci_dpm_get_fan_control_mode,
+ .set_fan_speed_percent = &ci_dpm_set_fan_speed_percent,
+ .get_fan_speed_percent = &ci_dpm_get_fan_speed_percent,
+};
+
+static void ci_dpm_set_dpm_funcs(struct amdgpu_device *adev)
+{
+ if (adev->pm.funcs == NULL)
+ adev->pm.funcs = &ci_dpm_funcs;
+}
+
+static const struct amdgpu_irq_src_funcs ci_dpm_irq_funcs = {
+ .set = ci_dpm_set_interrupt_state,
+ .process = ci_dpm_process_interrupt,
+};
+
+static void ci_dpm_set_irq_funcs(struct amdgpu_device *adev)
+{
+ adev->pm.dpm.thermal.irq.num_types = AMDGPU_THERMAL_IRQ_LAST;
+ adev->pm.dpm.thermal.irq.funcs = &ci_dpm_irq_funcs;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.h b/drivers/gpu/drm/amd/amdgpu/ci_dpm.h
new file mode 100644
index 000000000000..faccc30c93bf
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.h
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2013 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 __CI_DPM_H__
+#define __CI_DPM_H__
+
+#include "amdgpu_atombios.h"
+#include "ppsmc.h"
+
+#define SMU__NUM_SCLK_DPM_STATE 8
+#define SMU__NUM_MCLK_DPM_LEVELS 6
+#define SMU__NUM_LCLK_DPM_LEVELS 8
+#define SMU__NUM_PCIE_DPM_LEVELS 8
+#include "smu7_discrete.h"
+
+#define CISLANDS_MAX_HARDWARE_POWERLEVELS 2
+
+#define CISLANDS_UNUSED_GPIO_PIN 0x7F
+
+struct ci_pl {
+ u32 mclk;
+ u32 sclk;
+ enum amdgpu_pcie_gen pcie_gen;
+ u16 pcie_lane;
+};
+
+struct ci_ps {
+ u16 performance_level_count;
+ bool dc_compatible;
+ u32 sclk_t;
+ struct ci_pl performance_levels[CISLANDS_MAX_HARDWARE_POWERLEVELS];
+};
+
+struct ci_dpm_level {
+ bool enabled;
+ u32 value;
+ u32 param1;
+};
+
+#define CISLAND_MAX_DEEPSLEEP_DIVIDER_ID 5
+#define MAX_REGULAR_DPM_NUMBER 8
+#define CISLAND_MINIMUM_ENGINE_CLOCK 800
+
+struct ci_single_dpm_table {
+ u32 count;
+ struct ci_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
+};
+
+struct ci_dpm_table {
+ struct ci_single_dpm_table sclk_table;
+ struct ci_single_dpm_table mclk_table;
+ struct ci_single_dpm_table pcie_speed_table;
+ struct ci_single_dpm_table vddc_table;
+ struct ci_single_dpm_table vddci_table;
+ struct ci_single_dpm_table mvdd_table;
+};
+
+struct ci_mc_reg_entry {
+ u32 mclk_max;
+ u32 mc_data[SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct ci_mc_reg_table {
+ u8 last;
+ u8 num_entries;
+ u16 valid_flag;
+ struct ci_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+ SMU7_Discrete_MCRegisterAddress mc_reg_address[SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct ci_ulv_parm
+{
+ bool supported;
+ u32 cg_ulv_parameter;
+ u32 volt_change_delay;
+ struct ci_pl pl;
+};
+
+#define CISLANDS_MAX_LEAKAGE_COUNT 8
+
+struct ci_leakage_voltage {
+ u16 count;
+ u16 leakage_id[CISLANDS_MAX_LEAKAGE_COUNT];
+ u16 actual_voltage[CISLANDS_MAX_LEAKAGE_COUNT];
+};
+
+struct ci_dpm_level_enable_mask {
+ u32 uvd_dpm_enable_mask;
+ u32 vce_dpm_enable_mask;
+ u32 acp_dpm_enable_mask;
+ u32 samu_dpm_enable_mask;
+ u32 sclk_dpm_enable_mask;
+ u32 mclk_dpm_enable_mask;
+ u32 pcie_dpm_enable_mask;
+};
+
+struct ci_vbios_boot_state
+{
+ u16 mvdd_bootup_value;
+ u16 vddc_bootup_value;
+ u16 vddci_bootup_value;
+ u32 sclk_bootup_value;
+ u32 mclk_bootup_value;
+ u16 pcie_gen_bootup_value;
+ u16 pcie_lane_bootup_value;
+};
+
+struct ci_clock_registers {
+ u32 cg_spll_func_cntl;
+ u32 cg_spll_func_cntl_2;
+ u32 cg_spll_func_cntl_3;
+ u32 cg_spll_func_cntl_4;
+ u32 cg_spll_spread_spectrum;
+ u32 cg_spll_spread_spectrum_2;
+ u32 dll_cntl;
+ u32 mclk_pwrmgt_cntl;
+ u32 mpll_ad_func_cntl;
+ u32 mpll_dq_func_cntl;
+ u32 mpll_func_cntl;
+ u32 mpll_func_cntl_1;
+ u32 mpll_func_cntl_2;
+ u32 mpll_ss1;
+ u32 mpll_ss2;
+};
+
+struct ci_thermal_temperature_setting {
+ s32 temperature_low;
+ s32 temperature_high;
+ s32 temperature_shutdown;
+};
+
+struct ci_pcie_perf_range {
+ u16 max;
+ u16 min;
+};
+
+enum ci_pt_config_reg_type {
+ CISLANDS_CONFIGREG_MMR = 0,
+ CISLANDS_CONFIGREG_SMC_IND,
+ CISLANDS_CONFIGREG_DIDT_IND,
+ CISLANDS_CONFIGREG_CACHE,
+ CISLANDS_CONFIGREG_MAX
+};
+
+#define POWERCONTAINMENT_FEATURE_BAPM 0x00000001
+#define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002
+#define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004
+
+struct ci_pt_config_reg {
+ u32 offset;
+ u32 mask;
+ u32 shift;
+ u32 value;
+ enum ci_pt_config_reg_type type;
+};
+
+struct ci_pt_defaults {
+ u8 svi_load_line_en;
+ u8 svi_load_line_vddc;
+ u8 tdc_vddc_throttle_release_limit_perc;
+ u8 tdc_mawt;
+ u8 tdc_waterfall_ctl;
+ u8 dte_ambient_temp_base;
+ u32 display_cac;
+ u32 bapm_temp_gradient;
+ u16 bapmti_r[SMU7_DTE_ITERATIONS * SMU7_DTE_SOURCES * SMU7_DTE_SINKS];
+ u16 bapmti_rc[SMU7_DTE_ITERATIONS * SMU7_DTE_SOURCES * SMU7_DTE_SINKS];
+};
+
+#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
+#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
+#define DPMTABLE_UPDATE_SCLK 0x00000004
+#define DPMTABLE_UPDATE_MCLK 0x00000008
+
+struct ci_power_info {
+ struct ci_dpm_table dpm_table;
+ u32 voltage_control;
+ u32 mvdd_control;
+ u32 vddci_control;
+ u32 active_auto_throttle_sources;
+ struct ci_clock_registers clock_registers;
+ u16 acpi_vddc;
+ u16 acpi_vddci;
+ enum amdgpu_pcie_gen force_pcie_gen;
+ enum amdgpu_pcie_gen acpi_pcie_gen;
+ struct ci_leakage_voltage vddc_leakage;
+ struct ci_leakage_voltage vddci_leakage;
+ u16 max_vddc_in_pp_table;
+ u16 min_vddc_in_pp_table;
+ u16 max_vddci_in_pp_table;
+ u16 min_vddci_in_pp_table;
+ u32 mclk_strobe_mode_threshold;
+ u32 mclk_stutter_mode_threshold;
+ u32 mclk_edc_enable_threshold;
+ u32 mclk_edc_wr_enable_threshold;
+ struct ci_vbios_boot_state vbios_boot_state;
+ /* smc offsets */
+ u32 sram_end;
+ u32 dpm_table_start;
+ u32 soft_regs_start;
+ u32 mc_reg_table_start;
+ u32 fan_table_start;
+ u32 arb_table_start;
+ /* smc tables */
+ SMU7_Discrete_DpmTable smc_state_table;
+ SMU7_Discrete_MCRegisters smc_mc_reg_table;
+ SMU7_Discrete_PmFuses smc_powertune_table;
+ /* other stuff */
+ struct ci_mc_reg_table mc_reg_table;
+ struct atom_voltage_table vddc_voltage_table;
+ struct atom_voltage_table vddci_voltage_table;
+ struct atom_voltage_table mvdd_voltage_table;
+ struct ci_ulv_parm ulv;
+ u32 power_containment_features;
+ const struct ci_pt_defaults *powertune_defaults;
+ u32 dte_tj_offset;
+ bool vddc_phase_shed_control;
+ struct ci_thermal_temperature_setting thermal_temp_setting;
+ struct ci_dpm_level_enable_mask dpm_level_enable_mask;
+ u32 need_update_smu7_dpm_table;
+ u32 sclk_dpm_key_disabled;
+ u32 mclk_dpm_key_disabled;
+ u32 pcie_dpm_key_disabled;
+ u32 thermal_sclk_dpm_enabled;
+ struct ci_pcie_perf_range pcie_gen_performance;
+ struct ci_pcie_perf_range pcie_lane_performance;
+ struct ci_pcie_perf_range pcie_gen_powersaving;
+ struct ci_pcie_perf_range pcie_lane_powersaving;
+ u32 activity_target[SMU7_MAX_LEVELS_GRAPHICS];
+ u32 mclk_activity_target;
+ u32 low_sclk_interrupt_t;
+ u32 last_mclk_dpm_enable_mask;
+ u32 sys_pcie_mask;
+ /* caps */
+ bool caps_power_containment;
+ bool caps_cac;
+ bool caps_sq_ramping;
+ bool caps_db_ramping;
+ bool caps_td_ramping;
+ bool caps_tcp_ramping;
+ bool caps_fps;
+ bool caps_sclk_ds;
+ bool caps_sclk_ss_support;
+ bool caps_mclk_ss_support;
+ bool caps_uvd_dpm;
+ bool caps_vce_dpm;
+ bool caps_samu_dpm;
+ bool caps_acp_dpm;
+ bool caps_automatic_dc_transition;
+ bool caps_sclk_throttle_low_notification;
+ bool caps_dynamic_ac_timing;
+ bool caps_od_fuzzy_fan_control_support;
+ /* flags */
+ bool thermal_protection;
+ bool pcie_performance_request;
+ bool dynamic_ss;
+ bool dll_default_on;
+ bool cac_enabled;
+ bool uvd_enabled;
+ bool battery_state;
+ bool pspp_notify_required;
+ bool enable_bapm_feature;
+ bool enable_tdc_limit_feature;
+ bool enable_pkg_pwr_tracking_feature;
+ bool use_pcie_performance_levels;
+ bool use_pcie_powersaving_levels;
+ bool uvd_power_gated;
+ /* driver states */
+ struct amdgpu_ps current_rps;
+ struct ci_ps current_ps;
+ struct amdgpu_ps requested_rps;
+ struct ci_ps requested_ps;
+ /* fan control */
+ bool fan_ctrl_is_in_default_mode;
+ bool fan_is_controlled_by_smc;
+ u32 t_min;
+ u32 fan_ctrl_default_mode;
+};
+
+#define CISLANDS_VOLTAGE_CONTROL_NONE 0x0
+#define CISLANDS_VOLTAGE_CONTROL_BY_GPIO 0x1
+#define CISLANDS_VOLTAGE_CONTROL_BY_SVID2 0x2
+
+#define CISLANDS_Q88_FORMAT_CONVERSION_UNIT 256
+
+#define CISLANDS_VRC_DFLT0 0x3FFFC000
+#define CISLANDS_VRC_DFLT1 0x000400
+#define CISLANDS_VRC_DFLT2 0xC00080
+#define CISLANDS_VRC_DFLT3 0xC00200
+#define CISLANDS_VRC_DFLT4 0xC01680
+#define CISLANDS_VRC_DFLT5 0xC00033
+#define CISLANDS_VRC_DFLT6 0xC00033
+#define CISLANDS_VRC_DFLT7 0x3FFFC000
+
+#define CISLANDS_CGULVPARAMETER_DFLT 0x00040035
+#define CISLAND_TARGETACTIVITY_DFLT 30
+#define CISLAND_MCLK_TARGETACTIVITY_DFLT 10
+
+#define PCIE_PERF_REQ_REMOVE_REGISTRY 0
+#define PCIE_PERF_REQ_FORCE_LOWPOWER 1
+#define PCIE_PERF_REQ_PECI_GEN1 2
+#define PCIE_PERF_REQ_PECI_GEN2 3
+#define PCIE_PERF_REQ_PECI_GEN3 4
+
+#define CISLANDS_SSTU_DFLT 0
+#define CISLANDS_SST_DFLT 0x00C8
+
+/* XXX are these ok? */
+#define CISLANDS_TEMP_RANGE_MIN (90 * 1000)
+#define CISLANDS_TEMP_RANGE_MAX (120 * 1000)
+
+int amdgpu_ci_copy_bytes_to_smc(struct amdgpu_device *adev,
+ u32 smc_start_address,
+ const u8 *src, u32 byte_count, u32 limit);
+void amdgpu_ci_start_smc(struct amdgpu_device *adev);
+void amdgpu_ci_reset_smc(struct amdgpu_device *adev);
+int amdgpu_ci_program_jump_on_start(struct amdgpu_device *adev);
+void amdgpu_ci_stop_smc_clock(struct amdgpu_device *adev);
+void amdgpu_ci_start_smc_clock(struct amdgpu_device *adev);
+bool amdgpu_ci_is_smc_running(struct amdgpu_device *adev);
+PPSMC_Result amdgpu_ci_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg);
+PPSMC_Result amdgpu_ci_wait_for_smc_inactive(struct amdgpu_device *adev);
+int amdgpu_ci_load_smc_ucode(struct amdgpu_device *adev, u32 limit);
+int amdgpu_ci_read_smc_sram_dword(struct amdgpu_device *adev,
+ u32 smc_address, u32 *value, u32 limit);
+int amdgpu_ci_write_smc_sram_dword(struct amdgpu_device *adev,
+ u32 smc_address, u32 value, u32 limit);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_smc.c b/drivers/gpu/drm/amd/amdgpu/ci_smc.c
new file mode 100644
index 000000000000..7eb9069db8e3
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/ci_smc.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2011 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: Alex Deucher
+ */
+
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "amdgpu.h"
+#include "cikd.h"
+#include "ppsmc.h"
+#include "amdgpu_ucode.h"
+#include "ci_dpm.h"
+
+#include "smu/smu_7_0_1_d.h"
+#include "smu/smu_7_0_1_sh_mask.h"
+
+static int ci_set_smc_sram_address(struct amdgpu_device *adev,
+ u32 smc_address, u32 limit)
+{
+ if (smc_address & 3)
+ return -EINVAL;
+ if ((smc_address + 3) > limit)
+ return -EINVAL;
+
+ WREG32(mmSMC_IND_INDEX_0, smc_address);
+ WREG32_P(mmSMC_IND_ACCESS_CNTL, 0, ~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK);
+
+ return 0;
+}
+
+int amdgpu_ci_copy_bytes_to_smc(struct amdgpu_device *adev,
+ u32 smc_start_address,
+ const u8 *src, u32 byte_count, u32 limit)
+{
+ unsigned long flags;
+ u32 data, original_data;
+ u32 addr;
+ u32 extra_shift;
+ int ret = 0;
+
+ if (smc_start_address & 3)
+ return -EINVAL;
+ if ((smc_start_address + byte_count) > limit)
+ return -EINVAL;
+
+ addr = smc_start_address;
+
+ spin_lock_irqsave(&adev->smc_idx_lock, flags);
+ while (byte_count >= 4) {
+ /* SMC address space is BE */
+ data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+
+ ret = ci_set_smc_sram_address(adev, addr, limit);
+ if (ret)
+ goto done;
+
+ WREG32(mmSMC_IND_DATA_0, data);
+
+ src += 4;
+ byte_count -= 4;
+ addr += 4;
+ }
+
+ /* RMW for the final bytes */
+ if (byte_count > 0) {
+ data = 0;
+
+ ret = ci_set_smc_sram_address(adev, addr, limit);
+ if (ret)
+ goto done;
+
+ original_data = RREG32(mmSMC_IND_DATA_0);
+
+ extra_shift = 8 * (4 - byte_count);
+
+ while (byte_count > 0) {
+ data = (data << 8) + *src++;
+ byte_count--;
+ }
+
+ data <<= extra_shift;
+
+ data |= (original_data & ~((~0UL) << extra_shift));
+
+ ret = ci_set_smc_sram_address(adev, addr, limit);
+ if (ret)
+ goto done;
+
+ WREG32(mmSMC_IND_DATA_0, data);
+ }
+
+done:
+ spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+
+ return ret;
+}
+
+void amdgpu_ci_start_smc(struct amdgpu_device *adev)
+{
+ u32 tmp = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
+
+ tmp &= ~SMC_SYSCON_RESET_CNTL__rst_reg_MASK;
+ WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, tmp);
+}
+
+void amdgpu_ci_reset_smc(struct amdgpu_device *adev)
+{
+ u32 tmp = RREG32_SMC(ixSMC_SYSCON_RESET_CNTL);
+
+ tmp |= SMC_SYSCON_RESET_CNTL__rst_reg_MASK;
+ WREG32_SMC(ixSMC_SYSCON_RESET_CNTL, tmp);
+}
+
+int amdgpu_ci_program_jump_on_start(struct amdgpu_device *adev)
+{
+ static u8 data[] = { 0xE0, 0x00, 0x80, 0x40 };
+
+ return amdgpu_ci_copy_bytes_to_smc(adev, 0x0, data, 4, sizeof(data)+1);
+}
+
+void amdgpu_ci_stop_smc_clock(struct amdgpu_device *adev)
+{
+ u32 tmp = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
+
+ tmp |= SMC_SYSCON_CLOCK_CNTL_0__ck_disable_MASK;
+
+ WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, tmp);
+}
+
+void amdgpu_ci_start_smc_clock(struct amdgpu_device *adev)
+{
+ u32 tmp = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
+
+ tmp &= ~SMC_SYSCON_CLOCK_CNTL_0__ck_disable_MASK;
+
+ WREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0, tmp);
+}
+
+bool amdgpu_ci_is_smc_running(struct amdgpu_device *adev)
+{
+ u32 clk = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
+ u32 pc_c = RREG32_SMC(ixSMC_PC_C);
+
+ if (!(clk & SMC_SYSCON_CLOCK_CNTL_0__ck_disable_MASK) && (0x20100 <= pc_c))
+ return true;
+
+ return false;
+}
+
+PPSMC_Result amdgpu_ci_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg)
+{
+ u32 tmp;
+ int i;
+
+ if (!amdgpu_ci_is_smc_running(adev))
+ return PPSMC_Result_Failed;
+
+ WREG32(mmSMC_MESSAGE_0, msg);
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = RREG32(mmSMC_RESP_0);
+ if (tmp != 0)
+ break;
+ udelay(1);
+ }
+ tmp = RREG32(mmSMC_RESP_0);
+
+ return (PPSMC_Result)tmp;
+}
+
+PPSMC_Result amdgpu_ci_wait_for_smc_inactive(struct amdgpu_device *adev)
+{
+ u32 tmp;
+ int i;
+
+ if (!amdgpu_ci_is_smc_running(adev))
+ return PPSMC_Result_OK;
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = RREG32_SMC(ixSMC_SYSCON_CLOCK_CNTL_0);
+ if ((tmp & SMC_SYSCON_CLOCK_CNTL_0__cken_MASK) == 0)
+ break;
+ udelay(1);
+ }
+
+ return PPSMC_Result_OK;
+}
+
+int amdgpu_ci_load_smc_ucode(struct amdgpu_device *adev, u32 limit)
+{
+ const struct smc_firmware_header_v1_0 *hdr;
+ unsigned long flags;
+ u32 ucode_start_address;
+ u32 ucode_size;
+ const u8 *src;
+ u32 data;
+
+ if (!adev->pm.fw)
+ return -EINVAL;
+
+ hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data;
+ amdgpu_ucode_print_smc_hdr(&hdr->header);
+
+ adev->pm.fw_version = le32_to_cpu(hdr->header.ucode_version);
+ ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
+ ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
+ src = (const u8 *)
+ (adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+
+ if (ucode_size & 3)
+ return -EINVAL;
+
+ spin_lock_irqsave(&adev->smc_idx_lock, flags);
+ WREG32(mmSMC_IND_INDEX_0, ucode_start_address);
+ WREG32_P(mmSMC_IND_ACCESS_CNTL, SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK,
+ ~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK);
+ while (ucode_size >= 4) {
+ /* SMC address space is BE */
+ data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+
+ WREG32(mmSMC_IND_DATA_0, data);
+
+ src += 4;
+ ucode_size -= 4;
+ }
+ WREG32_P(mmSMC_IND_ACCESS_CNTL, 0, ~SMC_IND_ACCESS_CNTL__AUTO_INCREMENT_IND_0_MASK);
+ spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+
+ return 0;
+}
+
+int amdgpu_ci_read_smc_sram_dword(struct amdgpu_device *adev,
+ u32 smc_address, u32 *value, u32 limit)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&adev->smc_idx_lock, flags);
+ ret = ci_set_smc_sram_address(adev, smc_address, limit);
+ if (ret == 0)
+ *value = RREG32(mmSMC_IND_DATA_0);
+ spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+
+ return ret;
+}
+
+int amdgpu_ci_write_smc_sram_dword(struct amdgpu_device *adev,
+ u32 smc_address, u32 value, u32 limit)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&adev->smc_idx_lock, flags);
+ ret = ci_set_smc_sram_address(adev, smc_address, limit);
+ if (ret == 0)
+ WREG32(mmSMC_IND_DATA_0, value);
+ spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c
new file mode 100644
index 000000000000..5dab578d6462
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cik.c
@@ -0,0 +1,2513 @@
+/*
+ * Copyright 2012 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: Alex Deucher
+ */
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_atombios.h"
+#include "amdgpu_ih.h"
+#include "amdgpu_uvd.h"
+#include "amdgpu_vce.h"
+#include "cikd.h"
+#include "atom.h"
+
+#include "cik.h"
+#include "gmc_v7_0.h"
+#include "cik_ih.h"
+#include "dce_v8_0.h"
+#include "gfx_v7_0.h"
+#include "cik_sdma.h"
+#include "uvd_v4_2.h"
+#include "vce_v2_0.h"
+#include "cik_dpm.h"
+
+#include "uvd/uvd_4_2_d.h"
+
+#include "smu/smu_7_0_1_d.h"
+#include "smu/smu_7_0_1_sh_mask.h"
+
+#include "dce/dce_8_0_d.h"
+#include "dce/dce_8_0_sh_mask.h"
+
+#include "bif/bif_4_1_d.h"
+#include "bif/bif_4_1_sh_mask.h"
+
+#include "gca/gfx_7_2_d.h"
+#include "gca/gfx_7_2_enum.h"
+#include "gca/gfx_7_2_sh_mask.h"
+
+#include "gmc/gmc_7_1_d.h"
+#include "gmc/gmc_7_1_sh_mask.h"
+
+#include "oss/oss_2_0_d.h"
+#include "oss/oss_2_0_sh_mask.h"
+
+/*
+ * Indirect registers accessor
+ */
+static u32 cik_pcie_rreg(struct amdgpu_device *adev, u32 reg)
+{
+ unsigned long flags;
+ u32 r;
+
+ spin_lock_irqsave(&adev->pcie_idx_lock, flags);
+ WREG32(mmPCIE_INDEX, reg);
+ (void)RREG32(mmPCIE_INDEX);
+ r = RREG32(mmPCIE_DATA);
+ spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
+ return r;
+}
+
+static void cik_pcie_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&adev->pcie_idx_lock, flags);
+ WREG32(mmPCIE_INDEX, reg);
+ (void)RREG32(mmPCIE_INDEX);
+ WREG32(mmPCIE_DATA, v);
+ (void)RREG32(mmPCIE_DATA);
+ spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
+}
+
+static u32 cik_smc_rreg(struct amdgpu_device *adev, u32 reg)
+{
+ unsigned long flags;
+ u32 r;
+
+ spin_lock_irqsave(&adev->smc_idx_lock, flags);
+ WREG32(mmSMC_IND_INDEX_0, (reg));
+ r = RREG32(mmSMC_IND_DATA_0);
+ spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+ return r;
+}
+
+static void cik_smc_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&adev->smc_idx_lock, flags);
+ WREG32(mmSMC_IND_INDEX_0, (reg));
+ WREG32(mmSMC_IND_DATA_0, (v));
+ spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+}
+
+static u32 cik_uvd_ctx_rreg(struct amdgpu_device *adev, u32 reg)
+{
+ unsigned long flags;
+ u32 r;
+
+ spin_lock_irqsave(&adev->uvd_ctx_idx_lock, flags);
+ WREG32(mmUVD_CTX_INDEX, ((reg) & 0x1ff));
+ r = RREG32(mmUVD_CTX_DATA);
+ spin_unlock_irqrestore(&adev->uvd_ctx_idx_lock, flags);
+ return r;
+}
+
+static void cik_uvd_ctx_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&adev->uvd_ctx_idx_lock, flags);
+ WREG32(mmUVD_CTX_INDEX, ((reg) & 0x1ff));
+ WREG32(mmUVD_CTX_DATA, (v));
+ spin_unlock_irqrestore(&adev->uvd_ctx_idx_lock, flags);
+}
+
+static u32 cik_didt_rreg(struct amdgpu_device *adev, u32 reg)
+{
+ unsigned long flags;
+ u32 r;
+
+ spin_lock_irqsave(&adev->didt_idx_lock, flags);
+ WREG32(mmDIDT_IND_INDEX, (reg));
+ r = RREG32(mmDIDT_IND_DATA);
+ spin_unlock_irqrestore(&adev->didt_idx_lock, flags);
+ return r;
+}
+
+static void cik_didt_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&adev->didt_idx_lock, flags);
+ WREG32(mmDIDT_IND_INDEX, (reg));
+ WREG32(mmDIDT_IND_DATA, (v));
+ spin_unlock_irqrestore(&adev->didt_idx_lock, flags);
+}
+
+static const u32 bonaire_golden_spm_registers[] =
+{
+ 0xc200, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 bonaire_golden_common_registers[] =
+{
+ 0x31dc, 0xffffffff, 0x00000800,
+ 0x31dd, 0xffffffff, 0x00000800,
+ 0x31e6, 0xffffffff, 0x00007fbf,
+ 0x31e7, 0xffffffff, 0x00007faf
+};
+
+static const u32 bonaire_golden_registers[] =
+{
+ 0xcd5, 0x00000333, 0x00000333,
+ 0xcd4, 0x000c0fc0, 0x00040200,
+ 0x2684, 0x00010000, 0x00058208,
+ 0xf000, 0xffff1fff, 0x00140000,
+ 0xf080, 0xfdfc0fff, 0x00000100,
+ 0xf08d, 0x40000000, 0x40000200,
+ 0x260c, 0xffffffff, 0x00000000,
+ 0x260d, 0xf00fffff, 0x00000400,
+ 0x260e, 0x0002021c, 0x00020200,
+ 0x31e, 0x00000080, 0x00000000,
+ 0x16ec, 0x000000f0, 0x00000070,
+ 0x16f0, 0xf0311fff, 0x80300000,
+ 0x263e, 0x73773777, 0x12010001,
+ 0xd43, 0x00810000, 0x408af000,
+ 0x1c0c, 0x31000111, 0x00000011,
+ 0xbd2, 0x73773777, 0x12010001,
+ 0x883, 0x00007fb6, 0x0021a1b1,
+ 0x884, 0x00007fb6, 0x002021b1,
+ 0x860, 0x00007fb6, 0x00002191,
+ 0x886, 0x00007fb6, 0x002121b1,
+ 0x887, 0x00007fb6, 0x002021b1,
+ 0x877, 0x00007fb6, 0x00002191,
+ 0x878, 0x00007fb6, 0x00002191,
+ 0xd8a, 0x0000003f, 0x0000000a,
+ 0xd8b, 0x0000003f, 0x0000000a,
+ 0xab9, 0x00073ffe, 0x000022a2,
+ 0x903, 0x000007ff, 0x00000000,
+ 0x2285, 0xf000003f, 0x00000007,
+ 0x22fc, 0x00002001, 0x00000001,
+ 0x22c9, 0xffffffff, 0x00ffffff,
+ 0xc281, 0x0000ff0f, 0x00000000,
+ 0xa293, 0x07ffffff, 0x06000000,
+ 0x136, 0x00000fff, 0x00000100,
+ 0xf9e, 0x00000001, 0x00000002,
+ 0x2440, 0x03000000, 0x0362c688,
+ 0x2300, 0x000000ff, 0x00000001,
+ 0x390, 0x00001fff, 0x00001fff,
+ 0x2418, 0x0000007f, 0x00000020,
+ 0x2542, 0x00010000, 0x00010000,
+ 0x2b05, 0x000003ff, 0x000000f3,
+ 0x2b03, 0xffffffff, 0x00001032
+};
+
+static const u32 bonaire_mgcg_cgcg_init[] =
+{
+ 0x3108, 0xffffffff, 0xfffffffc,
+ 0xc200, 0xffffffff, 0xe0000000,
+ 0xf0a8, 0xffffffff, 0x00000100,
+ 0xf082, 0xffffffff, 0x00000100,
+ 0xf0b0, 0xffffffff, 0xc0000100,
+ 0xf0b2, 0xffffffff, 0xc0000100,
+ 0xf0b1, 0xffffffff, 0xc0000100,
+ 0x1579, 0xffffffff, 0x00600100,
+ 0xf0a0, 0xffffffff, 0x00000100,
+ 0xf085, 0xffffffff, 0x06000100,
+ 0xf088, 0xffffffff, 0x00000100,
+ 0xf086, 0xffffffff, 0x06000100,
+ 0xf081, 0xffffffff, 0x00000100,
+ 0xf0b8, 0xffffffff, 0x00000100,
+ 0xf089, 0xffffffff, 0x00000100,
+ 0xf080, 0xffffffff, 0x00000100,
+ 0xf08c, 0xffffffff, 0x00000100,
+ 0xf08d, 0xffffffff, 0x00000100,
+ 0xf094, 0xffffffff, 0x00000100,
+ 0xf095, 0xffffffff, 0x00000100,
+ 0xf096, 0xffffffff, 0x00000100,
+ 0xf097, 0xffffffff, 0x00000100,
+ 0xf098, 0xffffffff, 0x00000100,
+ 0xf09f, 0xffffffff, 0x00000100,
+ 0xf09e, 0xffffffff, 0x00000100,
+ 0xf084, 0xffffffff, 0x06000100,
+ 0xf0a4, 0xffffffff, 0x00000100,
+ 0xf09d, 0xffffffff, 0x00000100,
+ 0xf0ad, 0xffffffff, 0x00000100,
+ 0xf0ac, 0xffffffff, 0x00000100,
+ 0xf09c, 0xffffffff, 0x00000100,
+ 0xc200, 0xffffffff, 0xe0000000,
+ 0xf008, 0xffffffff, 0x00010000,
+ 0xf009, 0xffffffff, 0x00030002,
+ 0xf00a, 0xffffffff, 0x00040007,
+ 0xf00b, 0xffffffff, 0x00060005,
+ 0xf00c, 0xffffffff, 0x00090008,
+ 0xf00d, 0xffffffff, 0x00010000,
+ 0xf00e, 0xffffffff, 0x00030002,
+ 0xf00f, 0xffffffff, 0x00040007,
+ 0xf010, 0xffffffff, 0x00060005,
+ 0xf011, 0xffffffff, 0x00090008,
+ 0xf012, 0xffffffff, 0x00010000,
+ 0xf013, 0xffffffff, 0x00030002,
+ 0xf014, 0xffffffff, 0x00040007,
+ 0xf015, 0xffffffff, 0x00060005,
+ 0xf016, 0xffffffff, 0x00090008,
+ 0xf017, 0xffffffff, 0x00010000,
+ 0xf018, 0xffffffff, 0x00030002,
+ 0xf019, 0xffffffff, 0x00040007,
+ 0xf01a, 0xffffffff, 0x00060005,
+ 0xf01b, 0xffffffff, 0x00090008,
+ 0xf01c, 0xffffffff, 0x00010000,
+ 0xf01d, 0xffffffff, 0x00030002,
+ 0xf01e, 0xffffffff, 0x00040007,
+ 0xf01f, 0xffffffff, 0x00060005,
+ 0xf020, 0xffffffff, 0x00090008,
+ 0xf021, 0xffffffff, 0x00010000,
+ 0xf022, 0xffffffff, 0x00030002,
+ 0xf023, 0xffffffff, 0x00040007,
+ 0xf024, 0xffffffff, 0x00060005,
+ 0xf025, 0xffffffff, 0x00090008,
+ 0xf026, 0xffffffff, 0x00010000,
+ 0xf027, 0xffffffff, 0x00030002,
+ 0xf028, 0xffffffff, 0x00040007,
+ 0xf029, 0xffffffff, 0x00060005,
+ 0xf02a, 0xffffffff, 0x00090008,
+ 0xf000, 0xffffffff, 0x96e00200,
+ 0x21c2, 0xffffffff, 0x00900100,
+ 0x3109, 0xffffffff, 0x0020003f,
+ 0xe, 0xffffffff, 0x0140001c,
+ 0xf, 0x000f0000, 0x000f0000,
+ 0x88, 0xffffffff, 0xc060000c,
+ 0x89, 0xc0000fff, 0x00000100,
+ 0x3e4, 0xffffffff, 0x00000100,
+ 0x3e6, 0x00000101, 0x00000000,
+ 0x82a, 0xffffffff, 0x00000104,
+ 0x1579, 0xff000fff, 0x00000100,
+ 0xc33, 0xc0000fff, 0x00000104,
+ 0x3079, 0x00000001, 0x00000001,
+ 0x3403, 0xff000ff0, 0x00000100,
+ 0x3603, 0xff000ff0, 0x00000100
+};
+
+static const u32 spectre_golden_spm_registers[] =
+{
+ 0xc200, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 spectre_golden_common_registers[] =
+{
+ 0x31dc, 0xffffffff, 0x00000800,
+ 0x31dd, 0xffffffff, 0x00000800,
+ 0x31e6, 0xffffffff, 0x00007fbf,
+ 0x31e7, 0xffffffff, 0x00007faf
+};
+
+static const u32 spectre_golden_registers[] =
+{
+ 0xf000, 0xffff1fff, 0x96940200,
+ 0xf003, 0xffff0001, 0xff000000,
+ 0xf080, 0xfffc0fff, 0x00000100,
+ 0x1bb6, 0x00010101, 0x00010000,
+ 0x260d, 0xf00fffff, 0x00000400,
+ 0x260e, 0xfffffffc, 0x00020200,
+ 0x16ec, 0x000000f0, 0x00000070,
+ 0x16f0, 0xf0311fff, 0x80300000,
+ 0x263e, 0x73773777, 0x12010001,
+ 0x26df, 0x00ff0000, 0x00fc0000,
+ 0xbd2, 0x73773777, 0x12010001,
+ 0x2285, 0xf000003f, 0x00000007,
+ 0x22c9, 0xffffffff, 0x00ffffff,
+ 0xa0d4, 0x3f3f3fff, 0x00000082,
+ 0xa0d5, 0x0000003f, 0x00000000,
+ 0xf9e, 0x00000001, 0x00000002,
+ 0x244f, 0xffff03df, 0x00000004,
+ 0x31da, 0x00000008, 0x00000008,
+ 0x2300, 0x000008ff, 0x00000800,
+ 0x2542, 0x00010000, 0x00010000,
+ 0x2b03, 0xffffffff, 0x54763210,
+ 0x853e, 0x01ff01ff, 0x00000002,
+ 0x8526, 0x007ff800, 0x00200000,
+ 0x8057, 0xffffffff, 0x00000f40,
+ 0xc24d, 0xffffffff, 0x00000001
+};
+
+static const u32 spectre_mgcg_cgcg_init[] =
+{
+ 0x3108, 0xffffffff, 0xfffffffc,
+ 0xc200, 0xffffffff, 0xe0000000,
+ 0xf0a8, 0xffffffff, 0x00000100,
+ 0xf082, 0xffffffff, 0x00000100,
+ 0xf0b0, 0xffffffff, 0x00000100,
+ 0xf0b2, 0xffffffff, 0x00000100,
+ 0xf0b1, 0xffffffff, 0x00000100,
+ 0x1579, 0xffffffff, 0x00600100,
+ 0xf0a0, 0xffffffff, 0x00000100,
+ 0xf085, 0xffffffff, 0x06000100,
+ 0xf088, 0xffffffff, 0x00000100,
+ 0xf086, 0xffffffff, 0x06000100,
+ 0xf081, 0xffffffff, 0x00000100,
+ 0xf0b8, 0xffffffff, 0x00000100,
+ 0xf089, 0xffffffff, 0x00000100,
+ 0xf080, 0xffffffff, 0x00000100,
+ 0xf08c, 0xffffffff, 0x00000100,
+ 0xf08d, 0xffffffff, 0x00000100,
+ 0xf094, 0xffffffff, 0x00000100,
+ 0xf095, 0xffffffff, 0x00000100,
+ 0xf096, 0xffffffff, 0x00000100,
+ 0xf097, 0xffffffff, 0x00000100,
+ 0xf098, 0xffffffff, 0x00000100,
+ 0xf09f, 0xffffffff, 0x00000100,
+ 0xf09e, 0xffffffff, 0x00000100,
+ 0xf084, 0xffffffff, 0x06000100,
+ 0xf0a4, 0xffffffff, 0x00000100,
+ 0xf09d, 0xffffffff, 0x00000100,
+ 0xf0ad, 0xffffffff, 0x00000100,
+ 0xf0ac, 0xffffffff, 0x00000100,
+ 0xf09c, 0xffffffff, 0x00000100,
+ 0xc200, 0xffffffff, 0xe0000000,
+ 0xf008, 0xffffffff, 0x00010000,
+ 0xf009, 0xffffffff, 0x00030002,
+ 0xf00a, 0xffffffff, 0x00040007,
+ 0xf00b, 0xffffffff, 0x00060005,
+ 0xf00c, 0xffffffff, 0x00090008,
+ 0xf00d, 0xffffffff, 0x00010000,
+ 0xf00e, 0xffffffff, 0x00030002,
+ 0xf00f, 0xffffffff, 0x00040007,
+ 0xf010, 0xffffffff, 0x00060005,
+ 0xf011, 0xffffffff, 0x00090008,
+ 0xf012, 0xffffffff, 0x00010000,
+ 0xf013, 0xffffffff, 0x00030002,
+ 0xf014, 0xffffffff, 0x00040007,
+ 0xf015, 0xffffffff, 0x00060005,
+ 0xf016, 0xffffffff, 0x00090008,
+ 0xf017, 0xffffffff, 0x00010000,
+ 0xf018, 0xffffffff, 0x00030002,
+ 0xf019, 0xffffffff, 0x00040007,
+ 0xf01a, 0xffffffff, 0x00060005,
+ 0xf01b, 0xffffffff, 0x00090008,
+ 0xf01c, 0xffffffff, 0x00010000,
+ 0xf01d, 0xffffffff, 0x00030002,
+ 0xf01e, 0xffffffff, 0x00040007,
+ 0xf01f, 0xffffffff, 0x00060005,
+ 0xf020, 0xffffffff, 0x00090008,
+ 0xf021, 0xffffffff, 0x00010000,
+ 0xf022, 0xffffffff, 0x00030002,
+ 0xf023, 0xffffffff, 0x00040007,
+ 0xf024, 0xffffffff, 0x00060005,
+ 0xf025, 0xffffffff, 0x00090008,
+ 0xf026, 0xffffffff, 0x00010000,
+ 0xf027, 0xffffffff, 0x00030002,
+ 0xf028, 0xffffffff, 0x00040007,
+ 0xf029, 0xffffffff, 0x00060005,
+ 0xf02a, 0xffffffff, 0x00090008,
+ 0xf02b, 0xffffffff, 0x00010000,
+ 0xf02c, 0xffffffff, 0x00030002,
+ 0xf02d, 0xffffffff, 0x00040007,
+ 0xf02e, 0xffffffff, 0x00060005,
+ 0xf02f, 0xffffffff, 0x00090008,
+ 0xf000, 0xffffffff, 0x96e00200,
+ 0x21c2, 0xffffffff, 0x00900100,
+ 0x3109, 0xffffffff, 0x0020003f,
+ 0xe, 0xffffffff, 0x0140001c,
+ 0xf, 0x000f0000, 0x000f0000,
+ 0x88, 0xffffffff, 0xc060000c,
+ 0x89, 0xc0000fff, 0x00000100,
+ 0x3e4, 0xffffffff, 0x00000100,
+ 0x3e6, 0x00000101, 0x00000000,
+ 0x82a, 0xffffffff, 0x00000104,
+ 0x1579, 0xff000fff, 0x00000100,
+ 0xc33, 0xc0000fff, 0x00000104,
+ 0x3079, 0x00000001, 0x00000001,
+ 0x3403, 0xff000ff0, 0x00000100,
+ 0x3603, 0xff000ff0, 0x00000100
+};
+
+static const u32 kalindi_golden_spm_registers[] =
+{
+ 0xc200, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 kalindi_golden_common_registers[] =
+{
+ 0x31dc, 0xffffffff, 0x00000800,
+ 0x31dd, 0xffffffff, 0x00000800,
+ 0x31e6, 0xffffffff, 0x00007fbf,
+ 0x31e7, 0xffffffff, 0x00007faf
+};
+
+static const u32 kalindi_golden_registers[] =
+{
+ 0xf000, 0xffffdfff, 0x6e944040,
+ 0x1579, 0xff607fff, 0xfc000100,
+ 0xf088, 0xff000fff, 0x00000100,
+ 0xf089, 0xff000fff, 0x00000100,
+ 0xf080, 0xfffc0fff, 0x00000100,
+ 0x1bb6, 0x00010101, 0x00010000,
+ 0x260c, 0xffffffff, 0x00000000,
+ 0x260d, 0xf00fffff, 0x00000400,
+ 0x16ec, 0x000000f0, 0x00000070,
+ 0x16f0, 0xf0311fff, 0x80300000,
+ 0x263e, 0x73773777, 0x12010001,
+ 0x263f, 0xffffffff, 0x00000010,
+ 0x26df, 0x00ff0000, 0x00fc0000,
+ 0x200c, 0x00001f0f, 0x0000100a,
+ 0xbd2, 0x73773777, 0x12010001,
+ 0x902, 0x000fffff, 0x000c007f,
+ 0x2285, 0xf000003f, 0x00000007,
+ 0x22c9, 0x3fff3fff, 0x00ffcfff,
+ 0xc281, 0x0000ff0f, 0x00000000,
+ 0xa293, 0x07ffffff, 0x06000000,
+ 0x136, 0x00000fff, 0x00000100,
+ 0xf9e, 0x00000001, 0x00000002,
+ 0x31da, 0x00000008, 0x00000008,
+ 0x2300, 0x000000ff, 0x00000003,
+ 0x853e, 0x01ff01ff, 0x00000002,
+ 0x8526, 0x007ff800, 0x00200000,
+ 0x8057, 0xffffffff, 0x00000f40,
+ 0x2231, 0x001f3ae3, 0x00000082,
+ 0x2235, 0x0000001f, 0x00000010,
+ 0xc24d, 0xffffffff, 0x00000000
+};
+
+static const u32 kalindi_mgcg_cgcg_init[] =
+{
+ 0x3108, 0xffffffff, 0xfffffffc,
+ 0xc200, 0xffffffff, 0xe0000000,
+ 0xf0a8, 0xffffffff, 0x00000100,
+ 0xf082, 0xffffffff, 0x00000100,
+ 0xf0b0, 0xffffffff, 0x00000100,
+ 0xf0b2, 0xffffffff, 0x00000100,
+ 0xf0b1, 0xffffffff, 0x00000100,
+ 0x1579, 0xffffffff, 0x00600100,
+ 0xf0a0, 0xffffffff, 0x00000100,
+ 0xf085, 0xffffffff, 0x06000100,
+ 0xf088, 0xffffffff, 0x00000100,
+ 0xf086, 0xffffffff, 0x06000100,
+ 0xf081, 0xffffffff, 0x00000100,
+ 0xf0b8, 0xffffffff, 0x00000100,
+ 0xf089, 0xffffffff, 0x00000100,
+ 0xf080, 0xffffffff, 0x00000100,
+ 0xf08c, 0xffffffff, 0x00000100,
+ 0xf08d, 0xffffffff, 0x00000100,
+ 0xf094, 0xffffffff, 0x00000100,
+ 0xf095, 0xffffffff, 0x00000100,
+ 0xf096, 0xffffffff, 0x00000100,
+ 0xf097, 0xffffffff, 0x00000100,
+ 0xf098, 0xffffffff, 0x00000100,
+ 0xf09f, 0xffffffff, 0x00000100,
+ 0xf09e, 0xffffffff, 0x00000100,
+ 0xf084, 0xffffffff, 0x06000100,
+ 0xf0a4, 0xffffffff, 0x00000100,
+ 0xf09d, 0xffffffff, 0x00000100,
+ 0xf0ad, 0xffffffff, 0x00000100,
+ 0xf0ac, 0xffffffff, 0x00000100,
+ 0xf09c, 0xffffffff, 0x00000100,
+ 0xc200, 0xffffffff, 0xe0000000,
+ 0xf008, 0xffffffff, 0x00010000,
+ 0xf009, 0xffffffff, 0x00030002,
+ 0xf00a, 0xffffffff, 0x00040007,
+ 0xf00b, 0xffffffff, 0x00060005,
+ 0xf00c, 0xffffffff, 0x00090008,
+ 0xf00d, 0xffffffff, 0x00010000,
+ 0xf00e, 0xffffffff, 0x00030002,
+ 0xf00f, 0xffffffff, 0x00040007,
+ 0xf010, 0xffffffff, 0x00060005,
+ 0xf011, 0xffffffff, 0x00090008,
+ 0xf000, 0xffffffff, 0x96e00200,
+ 0x21c2, 0xffffffff, 0x00900100,
+ 0x3109, 0xffffffff, 0x0020003f,
+ 0xe, 0xffffffff, 0x0140001c,
+ 0xf, 0x000f0000, 0x000f0000,
+ 0x88, 0xffffffff, 0xc060000c,
+ 0x89, 0xc0000fff, 0x00000100,
+ 0x82a, 0xffffffff, 0x00000104,
+ 0x1579, 0xff000fff, 0x00000100,
+ 0xc33, 0xc0000fff, 0x00000104,
+ 0x3079, 0x00000001, 0x00000001,
+ 0x3403, 0xff000ff0, 0x00000100,
+ 0x3603, 0xff000ff0, 0x00000100
+};
+
+static const u32 hawaii_golden_spm_registers[] =
+{
+ 0xc200, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 hawaii_golden_common_registers[] =
+{
+ 0xc200, 0xffffffff, 0xe0000000,
+ 0xa0d4, 0xffffffff, 0x3a00161a,
+ 0xa0d5, 0xffffffff, 0x0000002e,
+ 0x2684, 0xffffffff, 0x00018208,
+ 0x263e, 0xffffffff, 0x12011003
+};
+
+static const u32 hawaii_golden_registers[] =
+{
+ 0xcd5, 0x00000333, 0x00000333,
+ 0x2684, 0x00010000, 0x00058208,
+ 0x260c, 0xffffffff, 0x00000000,
+ 0x260d, 0xf00fffff, 0x00000400,
+ 0x260e, 0x0002021c, 0x00020200,
+ 0x31e, 0x00000080, 0x00000000,
+ 0x16ec, 0x000000f0, 0x00000070,
+ 0x16f0, 0xf0311fff, 0x80300000,
+ 0xd43, 0x00810000, 0x408af000,
+ 0x1c0c, 0x31000111, 0x00000011,
+ 0xbd2, 0x73773777, 0x12010001,
+ 0x848, 0x0000007f, 0x0000001b,
+ 0x877, 0x00007fb6, 0x00002191,
+ 0xd8a, 0x0000003f, 0x0000000a,
+ 0xd8b, 0x0000003f, 0x0000000a,
+ 0xab9, 0x00073ffe, 0x000022a2,
+ 0x903, 0x000007ff, 0x00000000,
+ 0x22fc, 0x00002001, 0x00000001,
+ 0x22c9, 0xffffffff, 0x00ffffff,
+ 0xc281, 0x0000ff0f, 0x00000000,
+ 0xa293, 0x07ffffff, 0x06000000,
+ 0xf9e, 0x00000001, 0x00000002,
+ 0x31da, 0x00000008, 0x00000008,
+ 0x31dc, 0x00000f00, 0x00000800,
+ 0x31dd, 0x00000f00, 0x00000800,
+ 0x31e6, 0x00ffffff, 0x00ff7fbf,
+ 0x31e7, 0x00ffffff, 0x00ff7faf,
+ 0x2300, 0x000000ff, 0x00000800,
+ 0x390, 0x00001fff, 0x00001fff,
+ 0x2418, 0x0000007f, 0x00000020,
+ 0x2542, 0x00010000, 0x00010000,
+ 0x2b80, 0x00100000, 0x000ff07c,
+ 0x2b05, 0x000003ff, 0x0000000f,
+ 0x2b04, 0xffffffff, 0x7564fdec,
+ 0x2b03, 0xffffffff, 0x3120b9a8,
+ 0x2b02, 0x20000000, 0x0f9c0000
+};
+
+static const u32 hawaii_mgcg_cgcg_init[] =
+{
+ 0x3108, 0xffffffff, 0xfffffffd,
+ 0xc200, 0xffffffff, 0xe0000000,
+ 0xf0a8, 0xffffffff, 0x00000100,
+ 0xf082, 0xffffffff, 0x00000100,
+ 0xf0b0, 0xffffffff, 0x00000100,
+ 0xf0b2, 0xffffffff, 0x00000100,
+ 0xf0b1, 0xffffffff, 0x00000100,
+ 0x1579, 0xffffffff, 0x00200100,
+ 0xf0a0, 0xffffffff, 0x00000100,
+ 0xf085, 0xffffffff, 0x06000100,
+ 0xf088, 0xffffffff, 0x00000100,
+ 0xf086, 0xffffffff, 0x06000100,
+ 0xf081, 0xffffffff, 0x00000100,
+ 0xf0b8, 0xffffffff, 0x00000100,
+ 0xf089, 0xffffffff, 0x00000100,
+ 0xf080, 0xffffffff, 0x00000100,
+ 0xf08c, 0xffffffff, 0x00000100,
+ 0xf08d, 0xffffffff, 0x00000100,
+ 0xf094, 0xffffffff, 0x00000100,
+ 0xf095, 0xffffffff, 0x00000100,
+ 0xf096, 0xffffffff, 0x00000100,
+ 0xf097, 0xffffffff, 0x00000100,
+ 0xf098, 0xffffffff, 0x00000100,
+ 0xf09f, 0xffffffff, 0x00000100,
+ 0xf09e, 0xffffffff, 0x00000100,
+ 0xf084, 0xffffffff, 0x06000100,
+ 0xf0a4, 0xffffffff, 0x00000100,
+ 0xf09d, 0xffffffff, 0x00000100,
+ 0xf0ad, 0xffffffff, 0x00000100,
+ 0xf0ac, 0xffffffff, 0x00000100,
+ 0xf09c, 0xffffffff, 0x00000100,
+ 0xc200, 0xffffffff, 0xe0000000,
+ 0xf008, 0xffffffff, 0x00010000,
+ 0xf009, 0xffffffff, 0x00030002,
+ 0xf00a, 0xffffffff, 0x00040007,
+ 0xf00b, 0xffffffff, 0x00060005,
+ 0xf00c, 0xffffffff, 0x00090008,
+ 0xf00d, 0xffffffff, 0x00010000,
+ 0xf00e, 0xffffffff, 0x00030002,
+ 0xf00f, 0xffffffff, 0x00040007,
+ 0xf010, 0xffffffff, 0x00060005,
+ 0xf011, 0xffffffff, 0x00090008,
+ 0xf012, 0xffffffff, 0x00010000,
+ 0xf013, 0xffffffff, 0x00030002,
+ 0xf014, 0xffffffff, 0x00040007,
+ 0xf015, 0xffffffff, 0x00060005,
+ 0xf016, 0xffffffff, 0x00090008,
+ 0xf017, 0xffffffff, 0x00010000,
+ 0xf018, 0xffffffff, 0x00030002,
+ 0xf019, 0xffffffff, 0x00040007,
+ 0xf01a, 0xffffffff, 0x00060005,
+ 0xf01b, 0xffffffff, 0x00090008,
+ 0xf01c, 0xffffffff, 0x00010000,
+ 0xf01d, 0xffffffff, 0x00030002,
+ 0xf01e, 0xffffffff, 0x00040007,
+ 0xf01f, 0xffffffff, 0x00060005,
+ 0xf020, 0xffffffff, 0x00090008,
+ 0xf021, 0xffffffff, 0x00010000,
+ 0xf022, 0xffffffff, 0x00030002,
+ 0xf023, 0xffffffff, 0x00040007,
+ 0xf024, 0xffffffff, 0x00060005,
+ 0xf025, 0xffffffff, 0x00090008,
+ 0xf026, 0xffffffff, 0x00010000,
+ 0xf027, 0xffffffff, 0x00030002,
+ 0xf028, 0xffffffff, 0x00040007,
+ 0xf029, 0xffffffff, 0x00060005,
+ 0xf02a, 0xffffffff, 0x00090008,
+ 0xf02b, 0xffffffff, 0x00010000,
+ 0xf02c, 0xffffffff, 0x00030002,
+ 0xf02d, 0xffffffff, 0x00040007,
+ 0xf02e, 0xffffffff, 0x00060005,
+ 0xf02f, 0xffffffff, 0x00090008,
+ 0xf030, 0xffffffff, 0x00010000,
+ 0xf031, 0xffffffff, 0x00030002,
+ 0xf032, 0xffffffff, 0x00040007,
+ 0xf033, 0xffffffff, 0x00060005,
+ 0xf034, 0xffffffff, 0x00090008,
+ 0xf035, 0xffffffff, 0x00010000,
+ 0xf036, 0xffffffff, 0x00030002,
+ 0xf037, 0xffffffff, 0x00040007,
+ 0xf038, 0xffffffff, 0x00060005,
+ 0xf039, 0xffffffff, 0x00090008,
+ 0xf03a, 0xffffffff, 0x00010000,
+ 0xf03b, 0xffffffff, 0x00030002,
+ 0xf03c, 0xffffffff, 0x00040007,
+ 0xf03d, 0xffffffff, 0x00060005,
+ 0xf03e, 0xffffffff, 0x00090008,
+ 0x30c6, 0xffffffff, 0x00020200,
+ 0xcd4, 0xffffffff, 0x00000200,
+ 0x570, 0xffffffff, 0x00000400,
+ 0x157a, 0xffffffff, 0x00000000,
+ 0xbd4, 0xffffffff, 0x00000902,
+ 0xf000, 0xffffffff, 0x96940200,
+ 0x21c2, 0xffffffff, 0x00900100,
+ 0x3109, 0xffffffff, 0x0020003f,
+ 0xe, 0xffffffff, 0x0140001c,
+ 0xf, 0x000f0000, 0x000f0000,
+ 0x88, 0xffffffff, 0xc060000c,
+ 0x89, 0xc0000fff, 0x00000100,
+ 0x3e4, 0xffffffff, 0x00000100,
+ 0x3e6, 0x00000101, 0x00000000,
+ 0x82a, 0xffffffff, 0x00000104,
+ 0x1579, 0xff000fff, 0x00000100,
+ 0xc33, 0xc0000fff, 0x00000104,
+ 0x3079, 0x00000001, 0x00000001,
+ 0x3403, 0xff000ff0, 0x00000100,
+ 0x3603, 0xff000ff0, 0x00000100
+};
+
+static const u32 godavari_golden_registers[] =
+{
+ 0x1579, 0xff607fff, 0xfc000100,
+ 0x1bb6, 0x00010101, 0x00010000,
+ 0x260c, 0xffffffff, 0x00000000,
+ 0x260c0, 0xf00fffff, 0x00000400,
+ 0x184c, 0xffffffff, 0x00010000,
+ 0x16ec, 0x000000f0, 0x00000070,
+ 0x16f0, 0xf0311fff, 0x80300000,
+ 0x263e, 0x73773777, 0x12010001,
+ 0x263f, 0xffffffff, 0x00000010,
+ 0x200c, 0x00001f0f, 0x0000100a,
+ 0xbd2, 0x73773777, 0x12010001,
+ 0x902, 0x000fffff, 0x000c007f,
+ 0x2285, 0xf000003f, 0x00000007,
+ 0x22c9, 0xffffffff, 0x00ff0fff,
+ 0xc281, 0x0000ff0f, 0x00000000,
+ 0xa293, 0x07ffffff, 0x06000000,
+ 0x136, 0x00000fff, 0x00000100,
+ 0x3405, 0x00010000, 0x00810001,
+ 0x3605, 0x00010000, 0x00810001,
+ 0xf9e, 0x00000001, 0x00000002,
+ 0x31da, 0x00000008, 0x00000008,
+ 0x31dc, 0x00000f00, 0x00000800,
+ 0x31dd, 0x00000f00, 0x00000800,
+ 0x31e6, 0x00ffffff, 0x00ff7fbf,
+ 0x31e7, 0x00ffffff, 0x00ff7faf,
+ 0x2300, 0x000000ff, 0x00000001,
+ 0x853e, 0x01ff01ff, 0x00000002,
+ 0x8526, 0x007ff800, 0x00200000,
+ 0x8057, 0xffffffff, 0x00000f40,
+ 0x2231, 0x001f3ae3, 0x00000082,
+ 0x2235, 0x0000001f, 0x00000010,
+ 0xc24d, 0xffffffff, 0x00000000
+};
+
+static void cik_init_golden_registers(struct amdgpu_device *adev)
+{
+ /* Some of the registers might be dependent on GRBM_GFX_INDEX */
+ mutex_lock(&adev->grbm_idx_mutex);
+
+ switch (adev->asic_type) {
+ case CHIP_BONAIRE:
+ amdgpu_program_register_sequence(adev,
+ bonaire_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(bonaire_mgcg_cgcg_init));
+ amdgpu_program_register_sequence(adev,
+ bonaire_golden_registers,
+ (const u32)ARRAY_SIZE(bonaire_golden_registers));
+ amdgpu_program_register_sequence(adev,
+ bonaire_golden_common_registers,
+ (const u32)ARRAY_SIZE(bonaire_golden_common_registers));
+ amdgpu_program_register_sequence(adev,
+ bonaire_golden_spm_registers,
+ (const u32)ARRAY_SIZE(bonaire_golden_spm_registers));
+ break;
+ case CHIP_KABINI:
+ amdgpu_program_register_sequence(adev,
+ kalindi_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(kalindi_mgcg_cgcg_init));
+ amdgpu_program_register_sequence(adev,
+ kalindi_golden_registers,
+ (const u32)ARRAY_SIZE(kalindi_golden_registers));
+ amdgpu_program_register_sequence(adev,
+ kalindi_golden_common_registers,
+ (const u32)ARRAY_SIZE(kalindi_golden_common_registers));
+ amdgpu_program_register_sequence(adev,
+ kalindi_golden_spm_registers,
+ (const u32)ARRAY_SIZE(kalindi_golden_spm_registers));
+ break;
+ case CHIP_MULLINS:
+ amdgpu_program_register_sequence(adev,
+ kalindi_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(kalindi_mgcg_cgcg_init));
+ amdgpu_program_register_sequence(adev,
+ godavari_golden_registers,
+ (const u32)ARRAY_SIZE(godavari_golden_registers));
+ amdgpu_program_register_sequence(adev,
+ kalindi_golden_common_registers,
+ (const u32)ARRAY_SIZE(kalindi_golden_common_registers));
+ amdgpu_program_register_sequence(adev,
+ kalindi_golden_spm_registers,
+ (const u32)ARRAY_SIZE(kalindi_golden_spm_registers));
+ break;
+ case CHIP_KAVERI:
+ amdgpu_program_register_sequence(adev,
+ spectre_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(spectre_mgcg_cgcg_init));
+ amdgpu_program_register_sequence(adev,
+ spectre_golden_registers,
+ (const u32)ARRAY_SIZE(spectre_golden_registers));
+ amdgpu_program_register_sequence(adev,
+ spectre_golden_common_registers,
+ (const u32)ARRAY_SIZE(spectre_golden_common_registers));
+ amdgpu_program_register_sequence(adev,
+ spectre_golden_spm_registers,
+ (const u32)ARRAY_SIZE(spectre_golden_spm_registers));
+ break;
+ case CHIP_HAWAII:
+ amdgpu_program_register_sequence(adev,
+ hawaii_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(hawaii_mgcg_cgcg_init));
+ amdgpu_program_register_sequence(adev,
+ hawaii_golden_registers,
+ (const u32)ARRAY_SIZE(hawaii_golden_registers));
+ amdgpu_program_register_sequence(adev,
+ hawaii_golden_common_registers,
+ (const u32)ARRAY_SIZE(hawaii_golden_common_registers));
+ amdgpu_program_register_sequence(adev,
+ hawaii_golden_spm_registers,
+ (const u32)ARRAY_SIZE(hawaii_golden_spm_registers));
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&adev->grbm_idx_mutex);
+}
+
+/**
+ * cik_get_xclk - get the xclk
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Returns the reference clock used by the gfx engine
+ * (CIK).
+ */
+static u32 cik_get_xclk(struct amdgpu_device *adev)
+{
+ u32 reference_clock = adev->clock.spll.reference_freq;
+
+ if (adev->flags & AMDGPU_IS_APU) {
+ if (RREG32_SMC(ixGENERAL_PWRMGT) & GENERAL_PWRMGT__GPU_COUNTER_CLK_MASK)
+ return reference_clock / 2;
+ } else {
+ if (RREG32_SMC(ixCG_CLKPIN_CNTL) & CG_CLKPIN_CNTL__XTALIN_DIVIDE_MASK)
+ return reference_clock / 4;
+ }
+ return reference_clock;
+}
+
+/**
+ * cik_srbm_select - select specific register instances
+ *
+ * @adev: amdgpu_device pointer
+ * @me: selected ME (micro engine)
+ * @pipe: pipe
+ * @queue: queue
+ * @vmid: VMID
+ *
+ * Switches the currently active registers instances. Some
+ * registers are instanced per VMID, others are instanced per
+ * me/pipe/queue combination.
+ */
+void cik_srbm_select(struct amdgpu_device *adev,
+ u32 me, u32 pipe, u32 queue, u32 vmid)
+{
+ u32 srbm_gfx_cntl =
+ (((pipe << SRBM_GFX_CNTL__PIPEID__SHIFT) & SRBM_GFX_CNTL__PIPEID_MASK)|
+ ((me << SRBM_GFX_CNTL__MEID__SHIFT) & SRBM_GFX_CNTL__MEID_MASK)|
+ ((vmid << SRBM_GFX_CNTL__VMID__SHIFT) & SRBM_GFX_CNTL__VMID_MASK)|
+ ((queue << SRBM_GFX_CNTL__QUEUEID__SHIFT) & SRBM_GFX_CNTL__QUEUEID_MASK));
+ WREG32(mmSRBM_GFX_CNTL, srbm_gfx_cntl);
+}
+
+static void cik_vga_set_state(struct amdgpu_device *adev, bool state)
+{
+ uint32_t tmp;
+
+ tmp = RREG32(mmCONFIG_CNTL);
+ if (state == false)
+ tmp |= CONFIG_CNTL__VGA_DIS_MASK;
+ else
+ tmp &= ~CONFIG_CNTL__VGA_DIS_MASK;
+ WREG32(mmCONFIG_CNTL, tmp);
+}
+
+static bool cik_read_disabled_bios(struct amdgpu_device *adev)
+{
+ u32 bus_cntl;
+ u32 d1vga_control = 0;
+ u32 d2vga_control = 0;
+ u32 vga_render_control = 0;
+ u32 rom_cntl;
+ bool r;
+
+ bus_cntl = RREG32(mmBUS_CNTL);
+ if (adev->mode_info.num_crtc) {
+ d1vga_control = RREG32(mmD1VGA_CONTROL);
+ d2vga_control = RREG32(mmD2VGA_CONTROL);
+ vga_render_control = RREG32(mmVGA_RENDER_CONTROL);
+ }
+ rom_cntl = RREG32_SMC(ixROM_CNTL);
+
+ /* enable the rom */
+ WREG32(mmBUS_CNTL, (bus_cntl & ~BUS_CNTL__BIOS_ROM_DIS_MASK));
+ if (adev->mode_info.num_crtc) {
+ /* Disable VGA mode */
+ WREG32(mmD1VGA_CONTROL,
+ (d1vga_control & ~(D1VGA_CONTROL__D1VGA_MODE_ENABLE_MASK |
+ D1VGA_CONTROL__D1VGA_TIMING_SELECT_MASK)));
+ WREG32(mmD2VGA_CONTROL,
+ (d2vga_control & ~(D1VGA_CONTROL__D1VGA_MODE_ENABLE_MASK |
+ D1VGA_CONTROL__D1VGA_TIMING_SELECT_MASK)));
+ WREG32(mmVGA_RENDER_CONTROL,
+ (vga_render_control & ~VGA_RENDER_CONTROL__VGA_VSTATUS_CNTL_MASK));
+ }
+ WREG32_SMC(ixROM_CNTL, rom_cntl | ROM_CNTL__SCK_OVERWRITE_MASK);
+
+ r = amdgpu_read_bios(adev);
+
+ /* restore regs */
+ WREG32(mmBUS_CNTL, bus_cntl);
+ if (adev->mode_info.num_crtc) {
+ WREG32(mmD1VGA_CONTROL, d1vga_control);
+ WREG32(mmD2VGA_CONTROL, d2vga_control);
+ WREG32(mmVGA_RENDER_CONTROL, vga_render_control);
+ }
+ WREG32_SMC(ixROM_CNTL, rom_cntl);
+ return r;
+}
+
+static struct amdgpu_allowed_register_entry cik_allowed_read_registers[] = {
+ {mmGRBM_STATUS, false},
+ {mmGB_ADDR_CONFIG, false},
+ {mmMC_ARB_RAMCFG, false},
+ {mmGB_TILE_MODE0, false},
+ {mmGB_TILE_MODE1, false},
+ {mmGB_TILE_MODE2, false},
+ {mmGB_TILE_MODE3, false},
+ {mmGB_TILE_MODE4, false},
+ {mmGB_TILE_MODE5, false},
+ {mmGB_TILE_MODE6, false},
+ {mmGB_TILE_MODE7, false},
+ {mmGB_TILE_MODE8, false},
+ {mmGB_TILE_MODE9, false},
+ {mmGB_TILE_MODE10, false},
+ {mmGB_TILE_MODE11, false},
+ {mmGB_TILE_MODE12, false},
+ {mmGB_TILE_MODE13, false},
+ {mmGB_TILE_MODE14, false},
+ {mmGB_TILE_MODE15, false},
+ {mmGB_TILE_MODE16, false},
+ {mmGB_TILE_MODE17, false},
+ {mmGB_TILE_MODE18, false},
+ {mmGB_TILE_MODE19, false},
+ {mmGB_TILE_MODE20, false},
+ {mmGB_TILE_MODE21, false},
+ {mmGB_TILE_MODE22, false},
+ {mmGB_TILE_MODE23, false},
+ {mmGB_TILE_MODE24, false},
+ {mmGB_TILE_MODE25, false},
+ {mmGB_TILE_MODE26, false},
+ {mmGB_TILE_MODE27, false},
+ {mmGB_TILE_MODE28, false},
+ {mmGB_TILE_MODE29, false},
+ {mmGB_TILE_MODE30, false},
+ {mmGB_TILE_MODE31, false},
+ {mmGB_MACROTILE_MODE0, false},
+ {mmGB_MACROTILE_MODE1, false},
+ {mmGB_MACROTILE_MODE2, false},
+ {mmGB_MACROTILE_MODE3, false},
+ {mmGB_MACROTILE_MODE4, false},
+ {mmGB_MACROTILE_MODE5, false},
+ {mmGB_MACROTILE_MODE6, false},
+ {mmGB_MACROTILE_MODE7, false},
+ {mmGB_MACROTILE_MODE8, false},
+ {mmGB_MACROTILE_MODE9, false},
+ {mmGB_MACROTILE_MODE10, false},
+ {mmGB_MACROTILE_MODE11, false},
+ {mmGB_MACROTILE_MODE12, false},
+ {mmGB_MACROTILE_MODE13, false},
+ {mmGB_MACROTILE_MODE14, false},
+ {mmGB_MACROTILE_MODE15, false},
+ {mmCC_RB_BACKEND_DISABLE, false, true},
+ {mmGC_USER_RB_BACKEND_DISABLE, false, true},
+ {mmGB_BACKEND_MAP, false, false},
+ {mmPA_SC_RASTER_CONFIG, false, true},
+ {mmPA_SC_RASTER_CONFIG_1, false, true},
+};
+
+static uint32_t cik_read_indexed_register(struct amdgpu_device *adev,
+ u32 se_num, u32 sh_num,
+ u32 reg_offset)
+{
+ uint32_t val;
+
+ mutex_lock(&adev->grbm_idx_mutex);
+ if (se_num != 0xffffffff || sh_num != 0xffffffff)
+ gfx_v7_0_select_se_sh(adev, se_num, sh_num);
+
+ val = RREG32(reg_offset);
+
+ if (se_num != 0xffffffff || sh_num != 0xffffffff)
+ gfx_v7_0_select_se_sh(adev, 0xffffffff, 0xffffffff);
+ mutex_unlock(&adev->grbm_idx_mutex);
+ return val;
+}
+
+static int cik_read_register(struct amdgpu_device *adev, u32 se_num,
+ u32 sh_num, u32 reg_offset, u32 *value)
+{
+ uint32_t i;
+
+ *value = 0;
+ for (i = 0; i < ARRAY_SIZE(cik_allowed_read_registers); i++) {
+ if (reg_offset != cik_allowed_read_registers[i].reg_offset)
+ continue;
+
+ if (!cik_allowed_read_registers[i].untouched)
+ *value = cik_allowed_read_registers[i].grbm_indexed ?
+ cik_read_indexed_register(adev, se_num,
+ sh_num, reg_offset) :
+ RREG32(reg_offset);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void cik_print_gpu_status_regs(struct amdgpu_device *adev)
+{
+ dev_info(adev->dev, " GRBM_STATUS=0x%08X\n",
+ RREG32(mmGRBM_STATUS));
+ dev_info(adev->dev, " GRBM_STATUS2=0x%08X\n",
+ RREG32(mmGRBM_STATUS2));
+ dev_info(adev->dev, " GRBM_STATUS_SE0=0x%08X\n",
+ RREG32(mmGRBM_STATUS_SE0));
+ dev_info(adev->dev, " GRBM_STATUS_SE1=0x%08X\n",
+ RREG32(mmGRBM_STATUS_SE1));
+ dev_info(adev->dev, " GRBM_STATUS_SE2=0x%08X\n",
+ RREG32(mmGRBM_STATUS_SE2));
+ dev_info(adev->dev, " GRBM_STATUS_SE3=0x%08X\n",
+ RREG32(mmGRBM_STATUS_SE3));
+ dev_info(adev->dev, " SRBM_STATUS=0x%08X\n",
+ RREG32(mmSRBM_STATUS));
+ dev_info(adev->dev, " SRBM_STATUS2=0x%08X\n",
+ RREG32(mmSRBM_STATUS2));
+ dev_info(adev->dev, " SDMA0_STATUS_REG = 0x%08X\n",
+ RREG32(mmSDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET));
+ dev_info(adev->dev, " SDMA1_STATUS_REG = 0x%08X\n",
+ RREG32(mmSDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET));
+ dev_info(adev->dev, " CP_STAT = 0x%08x\n", RREG32(mmCP_STAT));
+ dev_info(adev->dev, " CP_STALLED_STAT1 = 0x%08x\n",
+ RREG32(mmCP_STALLED_STAT1));
+ dev_info(adev->dev, " CP_STALLED_STAT2 = 0x%08x\n",
+ RREG32(mmCP_STALLED_STAT2));
+ dev_info(adev->dev, " CP_STALLED_STAT3 = 0x%08x\n",
+ RREG32(mmCP_STALLED_STAT3));
+ dev_info(adev->dev, " CP_CPF_BUSY_STAT = 0x%08x\n",
+ RREG32(mmCP_CPF_BUSY_STAT));
+ dev_info(adev->dev, " CP_CPF_STALLED_STAT1 = 0x%08x\n",
+ RREG32(mmCP_CPF_STALLED_STAT1));
+ dev_info(adev->dev, " CP_CPF_STATUS = 0x%08x\n", RREG32(mmCP_CPF_STATUS));
+ dev_info(adev->dev, " CP_CPC_BUSY_STAT = 0x%08x\n", RREG32(mmCP_CPC_BUSY_STAT));
+ dev_info(adev->dev, " CP_CPC_STALLED_STAT1 = 0x%08x\n",
+ RREG32(mmCP_CPC_STALLED_STAT1));
+ dev_info(adev->dev, " CP_CPC_STATUS = 0x%08x\n", RREG32(mmCP_CPC_STATUS));
+}
+
+/**
+ * cik_gpu_check_soft_reset - check which blocks are busy
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Check which blocks are busy and return the relevant reset
+ * mask to be used by cik_gpu_soft_reset().
+ * Returns a mask of the blocks to be reset.
+ */
+u32 amdgpu_cik_gpu_check_soft_reset(struct amdgpu_device *adev)
+{
+ u32 reset_mask = 0;
+ u32 tmp;
+
+ /* GRBM_STATUS */
+ tmp = RREG32(mmGRBM_STATUS);
+ if (tmp & (GRBM_STATUS__PA_BUSY_MASK | GRBM_STATUS__SC_BUSY_MASK |
+ GRBM_STATUS__BCI_BUSY_MASK | GRBM_STATUS__SX_BUSY_MASK |
+ GRBM_STATUS__TA_BUSY_MASK | GRBM_STATUS__VGT_BUSY_MASK |
+ GRBM_STATUS__DB_BUSY_MASK | GRBM_STATUS__CB_BUSY_MASK |
+ GRBM_STATUS__GDS_BUSY_MASK | GRBM_STATUS__SPI_BUSY_MASK |
+ GRBM_STATUS__IA_BUSY_MASK | GRBM_STATUS__IA_BUSY_NO_DMA_MASK))
+ reset_mask |= AMDGPU_RESET_GFX;
+
+ if (tmp & (GRBM_STATUS__CP_BUSY_MASK | GRBM_STATUS__CP_COHERENCY_BUSY_MASK))
+ reset_mask |= AMDGPU_RESET_CP;
+
+ /* GRBM_STATUS2 */
+ tmp = RREG32(mmGRBM_STATUS2);
+ if (tmp & GRBM_STATUS2__RLC_BUSY_MASK)
+ reset_mask |= AMDGPU_RESET_RLC;
+
+ /* SDMA0_STATUS_REG */
+ tmp = RREG32(mmSDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET);
+ if (!(tmp & SDMA0_STATUS_REG__IDLE_MASK))
+ reset_mask |= AMDGPU_RESET_DMA;
+
+ /* SDMA1_STATUS_REG */
+ tmp = RREG32(mmSDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET);
+ if (!(tmp & SDMA0_STATUS_REG__IDLE_MASK))
+ reset_mask |= AMDGPU_RESET_DMA1;
+
+ /* SRBM_STATUS2 */
+ tmp = RREG32(mmSRBM_STATUS2);
+ if (tmp & SRBM_STATUS2__SDMA_BUSY_MASK)
+ reset_mask |= AMDGPU_RESET_DMA;
+
+ if (tmp & SRBM_STATUS2__SDMA1_BUSY_MASK)
+ reset_mask |= AMDGPU_RESET_DMA1;
+
+ /* SRBM_STATUS */
+ tmp = RREG32(mmSRBM_STATUS);
+
+ if (tmp & SRBM_STATUS__IH_BUSY_MASK)
+ reset_mask |= AMDGPU_RESET_IH;
+
+ if (tmp & SRBM_STATUS__SEM_BUSY_MASK)
+ reset_mask |= AMDGPU_RESET_SEM;
+
+ if (tmp & SRBM_STATUS__GRBM_RQ_PENDING_MASK)
+ reset_mask |= AMDGPU_RESET_GRBM;
+
+ if (tmp & SRBM_STATUS__VMC_BUSY_MASK)
+ reset_mask |= AMDGPU_RESET_VMC;
+
+ if (tmp & (SRBM_STATUS__MCB_BUSY_MASK | SRBM_STATUS__MCB_NON_DISPLAY_BUSY_MASK |
+ SRBM_STATUS__MCC_BUSY_MASK | SRBM_STATUS__MCD_BUSY_MASK))
+ reset_mask |= AMDGPU_RESET_MC;
+
+ if (amdgpu_display_is_display_hung(adev))
+ reset_mask |= AMDGPU_RESET_DISPLAY;
+
+ /* Skip MC reset as it's mostly likely not hung, just busy */
+ if (reset_mask & AMDGPU_RESET_MC) {
+ DRM_DEBUG("MC busy: 0x%08X, clearing.\n", reset_mask);
+ reset_mask &= ~AMDGPU_RESET_MC;
+ }
+
+ return reset_mask;
+}
+
+/**
+ * cik_gpu_soft_reset - soft reset GPU
+ *
+ * @adev: amdgpu_device pointer
+ * @reset_mask: mask of which blocks to reset
+ *
+ * Soft reset the blocks specified in @reset_mask.
+ */
+static void cik_gpu_soft_reset(struct amdgpu_device *adev, u32 reset_mask)
+{
+ struct amdgpu_mode_mc_save save;
+ u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
+ u32 tmp;
+
+ if (reset_mask == 0)
+ return;
+
+ dev_info(adev->dev, "GPU softreset: 0x%08X\n", reset_mask);
+
+ cik_print_gpu_status_regs(adev);
+ dev_info(adev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n",
+ RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_ADDR));
+ dev_info(adev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
+ RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_STATUS));
+
+ /* disable CG/PG */
+
+ /* stop the rlc */
+ gfx_v7_0_rlc_stop(adev);
+
+ /* Disable GFX parsing/prefetching */
+ WREG32(mmCP_ME_CNTL, CP_ME_CNTL__ME_HALT_MASK | CP_ME_CNTL__PFP_HALT_MASK | CP_ME_CNTL__CE_HALT_MASK);
+
+ /* Disable MEC parsing/prefetching */
+ WREG32(mmCP_MEC_CNTL, CP_MEC_CNTL__MEC_ME1_HALT_MASK | CP_MEC_CNTL__MEC_ME2_HALT_MASK);
+
+ if (reset_mask & AMDGPU_RESET_DMA) {
+ /* sdma0 */
+ tmp = RREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET);
+ tmp |= SDMA0_F32_CNTL__HALT_MASK;
+ WREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET, tmp);
+ }
+ if (reset_mask & AMDGPU_RESET_DMA1) {
+ /* sdma1 */
+ tmp = RREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET);
+ tmp |= SDMA0_F32_CNTL__HALT_MASK;
+ WREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET, tmp);
+ }
+
+ gmc_v7_0_mc_stop(adev, &save);
+ if (amdgpu_asic_wait_for_mc_idle(adev)) {
+ dev_warn(adev->dev, "Wait for MC idle timedout !\n");
+ }
+
+ if (reset_mask & (AMDGPU_RESET_GFX | AMDGPU_RESET_COMPUTE | AMDGPU_RESET_CP))
+ grbm_soft_reset = GRBM_SOFT_RESET__SOFT_RESET_CP_MASK |
+ GRBM_SOFT_RESET__SOFT_RESET_GFX_MASK;
+
+ if (reset_mask & AMDGPU_RESET_CP) {
+ grbm_soft_reset |= GRBM_SOFT_RESET__SOFT_RESET_CP_MASK;
+
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_GRBM_MASK;
+ }
+
+ if (reset_mask & AMDGPU_RESET_DMA)
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA_MASK;
+
+ if (reset_mask & AMDGPU_RESET_DMA1)
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA1_MASK;
+
+ if (reset_mask & AMDGPU_RESET_DISPLAY)
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK;
+
+ if (reset_mask & AMDGPU_RESET_RLC)
+ grbm_soft_reset |= GRBM_SOFT_RESET__SOFT_RESET_RLC_MASK;
+
+ if (reset_mask & AMDGPU_RESET_SEM)
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SEM_MASK;
+
+ if (reset_mask & AMDGPU_RESET_IH)
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_IH_MASK;
+
+ if (reset_mask & AMDGPU_RESET_GRBM)
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_GRBM_MASK;
+
+ if (reset_mask & AMDGPU_RESET_VMC)
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_VMC_MASK;
+
+ if (!(adev->flags & AMDGPU_IS_APU)) {
+ if (reset_mask & AMDGPU_RESET_MC)
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_MC_MASK;
+ }
+
+ if (grbm_soft_reset) {
+ tmp = RREG32(mmGRBM_SOFT_RESET);
+ tmp |= grbm_soft_reset;
+ dev_info(adev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp);
+ WREG32(mmGRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmGRBM_SOFT_RESET);
+
+ udelay(50);
+
+ tmp &= ~grbm_soft_reset;
+ WREG32(mmGRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmGRBM_SOFT_RESET);
+ }
+
+ if (srbm_soft_reset) {
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+ tmp |= srbm_soft_reset;
+ dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+ WREG32(mmSRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+
+ udelay(50);
+
+ tmp &= ~srbm_soft_reset;
+ WREG32(mmSRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+ }
+
+ /* Wait a little for things to settle down */
+ udelay(50);
+
+ gmc_v7_0_mc_resume(adev, &save);
+ udelay(50);
+
+ cik_print_gpu_status_regs(adev);
+}
+
+struct kv_reset_save_regs {
+ u32 gmcon_reng_execute;
+ u32 gmcon_misc;
+ u32 gmcon_misc3;
+};
+
+static void kv_save_regs_for_reset(struct amdgpu_device *adev,
+ struct kv_reset_save_regs *save)
+{
+ save->gmcon_reng_execute = RREG32(mmGMCON_RENG_EXECUTE);
+ save->gmcon_misc = RREG32(mmGMCON_MISC);
+ save->gmcon_misc3 = RREG32(mmGMCON_MISC3);
+
+ WREG32(mmGMCON_RENG_EXECUTE, save->gmcon_reng_execute &
+ ~GMCON_RENG_EXECUTE__RENG_EXECUTE_ON_PWR_UP_MASK);
+ WREG32(mmGMCON_MISC, save->gmcon_misc &
+ ~(GMCON_MISC__RENG_EXECUTE_ON_REG_UPDATE_MASK |
+ GMCON_MISC__STCTRL_STUTTER_EN_MASK));
+}
+
+static void kv_restore_regs_for_reset(struct amdgpu_device *adev,
+ struct kv_reset_save_regs *save)
+{
+ int i;
+
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+ WREG32(mmGMCON_PGFSM_CONFIG, 0x200010ff);
+
+ for (i = 0; i < 5; i++)
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+ WREG32(mmGMCON_PGFSM_CONFIG, 0x300010ff);
+
+ for (i = 0; i < 5; i++)
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+
+ WREG32(mmGMCON_PGFSM_WRITE, 0x210000);
+ WREG32(mmGMCON_PGFSM_CONFIG, 0xa00010ff);
+
+ for (i = 0; i < 5; i++)
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+
+ WREG32(mmGMCON_PGFSM_WRITE, 0x21003);
+ WREG32(mmGMCON_PGFSM_CONFIG, 0xb00010ff);
+
+ for (i = 0; i < 5; i++)
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+
+ WREG32(mmGMCON_PGFSM_WRITE, 0x2b00);
+ WREG32(mmGMCON_PGFSM_CONFIG, 0xc00010ff);
+
+ for (i = 0; i < 5; i++)
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+ WREG32(mmGMCON_PGFSM_CONFIG, 0xd00010ff);
+
+ for (i = 0; i < 5; i++)
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+
+ WREG32(mmGMCON_PGFSM_WRITE, 0x420000);
+ WREG32(mmGMCON_PGFSM_CONFIG, 0x100010ff);
+
+ for (i = 0; i < 5; i++)
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+
+ WREG32(mmGMCON_PGFSM_WRITE, 0x120202);
+ WREG32(mmGMCON_PGFSM_CONFIG, 0x500010ff);
+
+ for (i = 0; i < 5; i++)
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+
+ WREG32(mmGMCON_PGFSM_WRITE, 0x3e3e36);
+ WREG32(mmGMCON_PGFSM_CONFIG, 0x600010ff);
+
+ for (i = 0; i < 5; i++)
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+
+ WREG32(mmGMCON_PGFSM_WRITE, 0x373f3e);
+ WREG32(mmGMCON_PGFSM_CONFIG, 0x700010ff);
+
+ for (i = 0; i < 5; i++)
+ WREG32(mmGMCON_PGFSM_WRITE, 0);
+
+ WREG32(mmGMCON_PGFSM_WRITE, 0x3e1332);
+ WREG32(mmGMCON_PGFSM_CONFIG, 0xe00010ff);
+
+ WREG32(mmGMCON_MISC3, save->gmcon_misc3);
+ WREG32(mmGMCON_MISC, save->gmcon_misc);
+ WREG32(mmGMCON_RENG_EXECUTE, save->gmcon_reng_execute);
+}
+
+static void cik_gpu_pci_config_reset(struct amdgpu_device *adev)
+{
+ struct amdgpu_mode_mc_save save;
+ struct kv_reset_save_regs kv_save = { 0 };
+ u32 tmp, i;
+
+ dev_info(adev->dev, "GPU pci config reset\n");
+
+ /* disable dpm? */
+
+ /* disable cg/pg */
+
+ /* Disable GFX parsing/prefetching */
+ WREG32(mmCP_ME_CNTL, CP_ME_CNTL__ME_HALT_MASK |
+ CP_ME_CNTL__PFP_HALT_MASK | CP_ME_CNTL__CE_HALT_MASK);
+
+ /* Disable MEC parsing/prefetching */
+ WREG32(mmCP_MEC_CNTL,
+ CP_MEC_CNTL__MEC_ME1_HALT_MASK | CP_MEC_CNTL__MEC_ME2_HALT_MASK);
+
+ /* sdma0 */
+ tmp = RREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET);
+ tmp |= SDMA0_F32_CNTL__HALT_MASK;
+ WREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET, tmp);
+ /* sdma1 */
+ tmp = RREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET);
+ tmp |= SDMA0_F32_CNTL__HALT_MASK;
+ WREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET, tmp);
+ /* XXX other engines? */
+
+ /* halt the rlc, disable cp internal ints */
+ gfx_v7_0_rlc_stop(adev);
+
+ udelay(50);
+
+ /* disable mem access */
+ gmc_v7_0_mc_stop(adev, &save);
+ if (amdgpu_asic_wait_for_mc_idle(adev)) {
+ dev_warn(adev->dev, "Wait for MC idle timed out !\n");
+ }
+
+ if (adev->flags & AMDGPU_IS_APU)
+ kv_save_regs_for_reset(adev, &kv_save);
+
+ /* disable BM */
+ pci_clear_master(adev->pdev);
+ /* reset */
+ amdgpu_pci_config_reset(adev);
+
+ udelay(100);
+
+ /* wait for asic to come out of reset */
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if (RREG32(mmCONFIG_MEMSIZE) != 0xffffffff)
+ break;
+ udelay(1);
+ }
+
+ /* does asic init need to be run first??? */
+ if (adev->flags & AMDGPU_IS_APU)
+ kv_restore_regs_for_reset(adev, &kv_save);
+}
+
+static void cik_set_bios_scratch_engine_hung(struct amdgpu_device *adev, bool hung)
+{
+ u32 tmp = RREG32(mmBIOS_SCRATCH_3);
+
+ if (hung)
+ tmp |= ATOM_S3_ASIC_GUI_ENGINE_HUNG;
+ else
+ tmp &= ~ATOM_S3_ASIC_GUI_ENGINE_HUNG;
+
+ WREG32(mmBIOS_SCRATCH_3, tmp);
+}
+
+/**
+ * cik_asic_reset - soft reset GPU
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Look up which blocks are hung and attempt
+ * to reset them.
+ * Returns 0 for success.
+ */
+static int cik_asic_reset(struct amdgpu_device *adev)
+{
+ u32 reset_mask;
+
+ reset_mask = amdgpu_cik_gpu_check_soft_reset(adev);
+
+ if (reset_mask)
+ cik_set_bios_scratch_engine_hung(adev, true);
+
+ /* try soft reset */
+ cik_gpu_soft_reset(adev, reset_mask);
+
+ reset_mask = amdgpu_cik_gpu_check_soft_reset(adev);
+
+ /* try pci config reset */
+ if (reset_mask && amdgpu_hard_reset)
+ cik_gpu_pci_config_reset(adev);
+
+ reset_mask = amdgpu_cik_gpu_check_soft_reset(adev);
+
+ if (!reset_mask)
+ cik_set_bios_scratch_engine_hung(adev, false);
+
+ return 0;
+}
+
+static int cik_set_uvd_clock(struct amdgpu_device *adev, u32 clock,
+ u32 cntl_reg, u32 status_reg)
+{
+ int r, i;
+ struct atom_clock_dividers dividers;
+ uint32_t tmp;
+
+ r = amdgpu_atombios_get_clock_dividers(adev,
+ COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ clock, false, &dividers);
+ if (r)
+ return r;
+
+ tmp = RREG32_SMC(cntl_reg);
+ tmp &= ~(CG_DCLK_CNTL__DCLK_DIR_CNTL_EN_MASK |
+ CG_DCLK_CNTL__DCLK_DIVIDER_MASK);
+ tmp |= dividers.post_divider;
+ WREG32_SMC(cntl_reg, tmp);
+
+ for (i = 0; i < 100; i++) {
+ if (RREG32_SMC(status_reg) & CG_DCLK_STATUS__DCLK_STATUS_MASK)
+ break;
+ mdelay(10);
+ }
+ if (i == 100)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int cik_set_uvd_clocks(struct amdgpu_device *adev, u32 vclk, u32 dclk)
+{
+ int r = 0;
+
+ r = cik_set_uvd_clock(adev, vclk, ixCG_VCLK_CNTL, ixCG_VCLK_STATUS);
+ if (r)
+ return r;
+
+ r = cik_set_uvd_clock(adev, dclk, ixCG_DCLK_CNTL, ixCG_DCLK_STATUS);
+ return r;
+}
+
+static int cik_set_vce_clocks(struct amdgpu_device *adev, u32 evclk, u32 ecclk)
+{
+ int r, i;
+ struct atom_clock_dividers dividers;
+ u32 tmp;
+
+ r = amdgpu_atombios_get_clock_dividers(adev,
+ COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ ecclk, false, &dividers);
+ if (r)
+ return r;
+
+ for (i = 0; i < 100; i++) {
+ if (RREG32_SMC(ixCG_ECLK_STATUS) & CG_ECLK_STATUS__ECLK_STATUS_MASK)
+ break;
+ mdelay(10);
+ }
+ if (i == 100)
+ return -ETIMEDOUT;
+
+ tmp = RREG32_SMC(ixCG_ECLK_CNTL);
+ tmp &= ~(CG_ECLK_CNTL__ECLK_DIR_CNTL_EN_MASK |
+ CG_ECLK_CNTL__ECLK_DIVIDER_MASK);
+ tmp |= dividers.post_divider;
+ WREG32_SMC(ixCG_ECLK_CNTL, tmp);
+
+ for (i = 0; i < 100; i++) {
+ if (RREG32_SMC(ixCG_ECLK_STATUS) & CG_ECLK_STATUS__ECLK_STATUS_MASK)
+ break;
+ mdelay(10);
+ }
+ if (i == 100)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+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;
+ u16 tmp16;
+
+ if (amdgpu_pcie_gen2 == 0)
+ return;
+
+ if (adev->flags & AMDGPU_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)))
+ 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 (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) {
+ if (current_data_rate == 1) {
+ DRM_INFO("PCIE gen 2 link speeds already enabled\n");
+ return;
+ }
+ DRM_INFO("enabling PCIE gen 2 link speeds, disable with amdgpu.pcie_gen2=0\n");
+ }
+
+ bridge_pos = pci_pcie_cap(root);
+ if (!bridge_pos)
+ return;
+
+ gpu_pos = pci_pcie_cap(adev->pdev);
+ if (!gpu_pos)
+ return;
+
+ if (mask & DRM_PCIE_SPEED_80) {
+ /* re-try equalization if gen3 is not already enabled */
+ if (current_data_rate != 2) {
+ u16 bridge_cfg, gpu_cfg;
+ u16 bridge_cfg2, gpu_cfg2;
+ u32 max_lw, current_lw, tmp;
+
+ pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
+ pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+
+ tmp16 = bridge_cfg | PCI_EXP_LNKCTL_HAWD;
+ pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
+
+ tmp16 = gpu_cfg | PCI_EXP_LNKCTL_HAWD;
+ pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+
+ tmp = RREG32_PCIE(ixPCIE_LC_STATUS1);
+ max_lw = (tmp & PCIE_LC_STATUS1__LC_DETECTED_LINK_WIDTH_MASK) >>
+ PCIE_LC_STATUS1__LC_DETECTED_LINK_WIDTH__SHIFT;
+ current_lw = (tmp & PCIE_LC_STATUS1__LC_OPERATING_LINK_WIDTH_MASK)
+ >> PCIE_LC_STATUS1__LC_OPERATING_LINK_WIDTH__SHIFT;
+
+ if (current_lw < max_lw) {
+ tmp = RREG32_PCIE(ixPCIE_LC_LINK_WIDTH_CNTL);
+ if (tmp & PCIE_LC_LINK_WIDTH_CNTL__LC_RENEGOTIATION_SUPPORT_MASK) {
+ tmp &= ~(PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_MASK |
+ PCIE_LC_LINK_WIDTH_CNTL__LC_UPCONFIGURE_DIS_MASK);
+ tmp |= (max_lw <<
+ PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH__SHIFT);
+ tmp |= PCIE_LC_LINK_WIDTH_CNTL__LC_UPCONFIGURE_SUPPORT_MASK |
+ PCIE_LC_LINK_WIDTH_CNTL__LC_RENEGOTIATE_EN_MASK |
+ PCIE_LC_LINK_WIDTH_CNTL__LC_RECONFIG_NOW_MASK;
+ WREG32_PCIE(ixPCIE_LC_LINK_WIDTH_CNTL, tmp);
+ }
+ }
+
+ for (i = 0; i < 10; i++) {
+ /* check status */
+ pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_DEVSTA, &tmp16);
+ if (tmp16 & PCI_EXP_DEVSTA_TRPND)
+ break;
+
+ pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &bridge_cfg);
+ pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+
+ pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2);
+ pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2);
+
+ tmp = RREG32_PCIE(ixPCIE_LC_CNTL4);
+ tmp |= PCIE_LC_CNTL4__LC_SET_QUIESCE_MASK;
+ WREG32_PCIE(ixPCIE_LC_CNTL4, tmp);
+
+ tmp = RREG32_PCIE(ixPCIE_LC_CNTL4);
+ tmp |= PCIE_LC_CNTL4__LC_REDO_EQ_MASK;
+ WREG32_PCIE(ixPCIE_LC_CNTL4, tmp);
+
+ mdelay(100);
+
+ /* linkctl */
+ pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16);
+ tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
+ tmp16 |= (bridge_cfg & PCI_EXP_LNKCTL_HAWD);
+ pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL, tmp16);
+
+ pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16);
+ tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
+ tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
+ pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+
+ /* linkctl2 */
+ pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &tmp16);
+ tmp16 &= ~((1 << 4) | (7 << 9));
+ tmp16 |= (bridge_cfg2 & ((1 << 4) | (7 << 9)));
+ pci_write_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, tmp16);
+
+ pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
+ tmp16 &= ~((1 << 4) | (7 << 9));
+ tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9)));
+ pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+
+ tmp = RREG32_PCIE(ixPCIE_LC_CNTL4);
+ tmp &= ~PCIE_LC_CNTL4__LC_SET_QUIESCE_MASK;
+ WREG32_PCIE(ixPCIE_LC_CNTL4, tmp);
+ }
+ }
+ }
+
+ /* set the link speed */
+ speed_cntl |= PCIE_LC_SPEED_CNTL__LC_FORCE_EN_SW_SPEED_CHANGE_MASK |
+ PCIE_LC_SPEED_CNTL__LC_FORCE_DIS_HW_SPEED_CHANGE_MASK;
+ speed_cntl &= ~PCIE_LC_SPEED_CNTL__LC_FORCE_DIS_SW_SPEED_CHANGE_MASK;
+ WREG32_PCIE(ixPCIE_LC_SPEED_CNTL, speed_cntl);
+
+ pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
+ tmp16 &= ~0xf;
+ if (mask & DRM_PCIE_SPEED_80)
+ tmp16 |= 3; /* gen3 */
+ else if (mask & DRM_PCIE_SPEED_50)
+ tmp16 |= 2; /* gen2 */
+ else
+ tmp16 |= 1; /* gen1 */
+ pci_write_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+
+ speed_cntl = RREG32_PCIE(ixPCIE_LC_SPEED_CNTL);
+ speed_cntl |= PCIE_LC_SPEED_CNTL__LC_INITIATE_LINK_SPEED_CHANGE_MASK;
+ WREG32_PCIE(ixPCIE_LC_SPEED_CNTL, speed_cntl);
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ speed_cntl = RREG32_PCIE(ixPCIE_LC_SPEED_CNTL);
+ if ((speed_cntl & PCIE_LC_SPEED_CNTL__LC_INITIATE_LINK_SPEED_CHANGE_MASK) == 0)
+ break;
+ udelay(1);
+ }
+}
+
+static void cik_program_aspm(struct amdgpu_device *adev)
+{
+ u32 data, orig;
+ bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false;
+ bool disable_clkreq = false;
+
+ if (amdgpu_aspm == 0)
+ return;
+
+ /* XXX double check APUs */
+ if (adev->flags & AMDGPU_IS_APU)
+ return;
+
+ orig = data = RREG32_PCIE(ixPCIE_LC_N_FTS_CNTL);
+ data &= ~PCIE_LC_N_FTS_CNTL__LC_XMIT_N_FTS_MASK;
+ data |= (0x24 << PCIE_LC_N_FTS_CNTL__LC_XMIT_N_FTS__SHIFT) |
+ PCIE_LC_N_FTS_CNTL__LC_XMIT_N_FTS_OVERRIDE_EN_MASK;
+ if (orig != data)
+ WREG32_PCIE(ixPCIE_LC_N_FTS_CNTL, data);
+
+ orig = data = RREG32_PCIE(ixPCIE_LC_CNTL3);
+ data |= PCIE_LC_CNTL3__LC_GO_TO_RECOVERY_MASK;
+ if (orig != data)
+ WREG32_PCIE(ixPCIE_LC_CNTL3, data);
+
+ orig = data = RREG32_PCIE(ixPCIE_P_CNTL);
+ data |= PCIE_P_CNTL__P_IGNORE_EDB_ERR_MASK;
+ if (orig != data)
+ WREG32_PCIE(ixPCIE_P_CNTL, data);
+
+ orig = data = RREG32_PCIE(ixPCIE_LC_CNTL);
+ data &= ~(PCIE_LC_CNTL__LC_L0S_INACTIVITY_MASK |
+ PCIE_LC_CNTL__LC_L1_INACTIVITY_MASK);
+ data |= PCIE_LC_CNTL__LC_PMI_TO_L1_DIS_MASK;
+ if (!disable_l0s)
+ data |= (7 << PCIE_LC_CNTL__LC_L0S_INACTIVITY__SHIFT);
+
+ if (!disable_l1) {
+ data |= (7 << PCIE_LC_CNTL__LC_L1_INACTIVITY__SHIFT);
+ data &= ~PCIE_LC_CNTL__LC_PMI_TO_L1_DIS_MASK;
+ if (orig != data)
+ WREG32_PCIE(ixPCIE_LC_CNTL, data);
+
+ if (!disable_plloff_in_l1) {
+ bool clk_req_support;
+
+ orig = data = RREG32_PCIE(ixPB0_PIF_PWRDOWN_0);
+ data &= ~(PB0_PIF_PWRDOWN_0__PLL_POWER_STATE_IN_OFF_0_MASK |
+ PB0_PIF_PWRDOWN_0__PLL_POWER_STATE_IN_TXS2_0_MASK);
+ data |= (7 << PB0_PIF_PWRDOWN_0__PLL_POWER_STATE_IN_OFF_0__SHIFT) |
+ (7 << PB0_PIF_PWRDOWN_0__PLL_POWER_STATE_IN_TXS2_0__SHIFT);
+ if (orig != data)
+ WREG32_PCIE(ixPB0_PIF_PWRDOWN_0, data);
+
+ orig = data = RREG32_PCIE(ixPB0_PIF_PWRDOWN_1);
+ data &= ~(PB0_PIF_PWRDOWN_1__PLL_POWER_STATE_IN_OFF_1_MASK |
+ PB0_PIF_PWRDOWN_1__PLL_POWER_STATE_IN_TXS2_1_MASK);
+ data |= (7 << PB0_PIF_PWRDOWN_1__PLL_POWER_STATE_IN_OFF_1__SHIFT) |
+ (7 << PB0_PIF_PWRDOWN_1__PLL_POWER_STATE_IN_TXS2_1__SHIFT);
+ if (orig != data)
+ WREG32_PCIE(ixPB0_PIF_PWRDOWN_1, data);
+
+ orig = data = RREG32_PCIE(ixPB1_PIF_PWRDOWN_0);
+ data &= ~(PB1_PIF_PWRDOWN_0__PLL_POWER_STATE_IN_OFF_0_MASK |
+ PB1_PIF_PWRDOWN_0__PLL_POWER_STATE_IN_TXS2_0_MASK);
+ data |= (7 << PB1_PIF_PWRDOWN_0__PLL_POWER_STATE_IN_OFF_0__SHIFT) |
+ (7 << PB1_PIF_PWRDOWN_0__PLL_POWER_STATE_IN_TXS2_0__SHIFT);
+ if (orig != data)
+ WREG32_PCIE(ixPB1_PIF_PWRDOWN_0, data);
+
+ orig = data = RREG32_PCIE(ixPB1_PIF_PWRDOWN_1);
+ data &= ~(PB1_PIF_PWRDOWN_1__PLL_POWER_STATE_IN_OFF_1_MASK |
+ PB1_PIF_PWRDOWN_1__PLL_POWER_STATE_IN_TXS2_1_MASK);
+ data |= (7 << PB1_PIF_PWRDOWN_1__PLL_POWER_STATE_IN_OFF_1__SHIFT) |
+ (7 << PB1_PIF_PWRDOWN_1__PLL_POWER_STATE_IN_TXS2_1__SHIFT);
+ if (orig != data)
+ WREG32_PCIE(ixPB1_PIF_PWRDOWN_1, data);
+
+ orig = data = RREG32_PCIE(ixPCIE_LC_LINK_WIDTH_CNTL);
+ data &= ~PCIE_LC_LINK_WIDTH_CNTL__LC_DYN_LANES_PWR_STATE_MASK;
+ data |= ~(3 << PCIE_LC_LINK_WIDTH_CNTL__LC_DYN_LANES_PWR_STATE__SHIFT);
+ if (orig != data)
+ WREG32_PCIE(ixPCIE_LC_LINK_WIDTH_CNTL, data);
+
+ if (!disable_clkreq) {
+ struct pci_dev *root = adev->pdev->bus->self;
+ u32 lnkcap;
+
+ clk_req_support = false;
+ pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap);
+ if (lnkcap & PCI_EXP_LNKCAP_CLKPM)
+ clk_req_support = true;
+ } else {
+ clk_req_support = false;
+ }
+
+ if (clk_req_support) {
+ orig = data = RREG32_PCIE(ixPCIE_LC_CNTL2);
+ data |= PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L1_MASK |
+ PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L23_MASK;
+ if (orig != data)
+ WREG32_PCIE(ixPCIE_LC_CNTL2, data);
+
+ orig = data = RREG32_SMC(ixTHM_CLK_CNTL);
+ data &= ~(THM_CLK_CNTL__CMON_CLK_SEL_MASK |
+ THM_CLK_CNTL__TMON_CLK_SEL_MASK);
+ data |= (1 << THM_CLK_CNTL__CMON_CLK_SEL__SHIFT) |
+ (1 << THM_CLK_CNTL__TMON_CLK_SEL__SHIFT);
+ if (orig != data)
+ WREG32_SMC(ixTHM_CLK_CNTL, data);
+
+ orig = data = RREG32_SMC(ixMISC_CLK_CTRL);
+ data &= ~(MISC_CLK_CTRL__DEEP_SLEEP_CLK_SEL_MASK |
+ MISC_CLK_CTRL__ZCLK_SEL_MASK);
+ data |= (1 << MISC_CLK_CTRL__DEEP_SLEEP_CLK_SEL__SHIFT) |
+ (1 << MISC_CLK_CTRL__ZCLK_SEL__SHIFT);
+ if (orig != data)
+ WREG32_SMC(ixMISC_CLK_CTRL, data);
+
+ orig = data = RREG32_SMC(ixCG_CLKPIN_CNTL);
+ data &= ~CG_CLKPIN_CNTL__BCLK_AS_XCLK_MASK;
+ if (orig != data)
+ WREG32_SMC(ixCG_CLKPIN_CNTL, data);
+
+ orig = data = RREG32_SMC(ixCG_CLKPIN_CNTL_2);
+ data &= ~CG_CLKPIN_CNTL_2__FORCE_BIF_REFCLK_EN_MASK;
+ if (orig != data)
+ WREG32_SMC(ixCG_CLKPIN_CNTL_2, data);
+
+ orig = data = RREG32_SMC(ixMPLL_BYPASSCLK_SEL);
+ data &= ~MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL_MASK;
+ data |= (4 << MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL__SHIFT);
+ if (orig != data)
+ WREG32_SMC(ixMPLL_BYPASSCLK_SEL, data);
+ }
+ }
+ } else {
+ if (orig != data)
+ WREG32_PCIE(ixPCIE_LC_CNTL, data);
+ }
+
+ orig = data = RREG32_PCIE(ixPCIE_CNTL2);
+ data |= PCIE_CNTL2__SLV_MEM_LS_EN_MASK |
+ PCIE_CNTL2__MST_MEM_LS_EN_MASK |
+ PCIE_CNTL2__REPLAY_MEM_LS_EN_MASK;
+ if (orig != data)
+ WREG32_PCIE(ixPCIE_CNTL2, data);
+
+ if (!disable_l0s) {
+ data = RREG32_PCIE(ixPCIE_LC_N_FTS_CNTL);
+ if ((data & PCIE_LC_N_FTS_CNTL__LC_N_FTS_MASK) ==
+ PCIE_LC_N_FTS_CNTL__LC_N_FTS_MASK) {
+ data = RREG32_PCIE(ixPCIE_LC_STATUS1);
+ if ((data & PCIE_LC_STATUS1__LC_REVERSE_XMIT_MASK) &&
+ (data & PCIE_LC_STATUS1__LC_REVERSE_RCVR_MASK)) {
+ orig = data = RREG32_PCIE(ixPCIE_LC_CNTL);
+ data &= ~PCIE_LC_CNTL__LC_L0S_INACTIVITY_MASK;
+ if (orig != data)
+ WREG32_PCIE(ixPCIE_LC_CNTL, data);
+ }
+ }
+ }
+}
+
+static uint32_t cik_get_rev_id(struct amdgpu_device *adev)
+{
+ return (RREG32(mmCC_DRM_ID_STRAPS) & CC_DRM_ID_STRAPS__ATI_REV_ID_MASK)
+ >> CC_DRM_ID_STRAPS__ATI_REV_ID__SHIFT;
+}
+
+static const struct amdgpu_ip_block_version bonaire_ip_blocks[] =
+{
+ /* ORDER MATTERS! */
+ {
+ .type = AMD_IP_BLOCK_TYPE_COMMON,
+ .major = 1,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_common_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_GMC,
+ .major = 7,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &gmc_v7_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_IH,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_ih_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_SMC,
+ .major = 7,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &ci_dpm_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_DCE,
+ .major = 8,
+ .minor = 2,
+ .rev = 0,
+ .funcs = &dce_v8_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_GFX,
+ .major = 7,
+ .minor = 2,
+ .rev = 0,
+ .funcs = &gfx_v7_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_SDMA,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_sdma_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_UVD,
+ .major = 4,
+ .minor = 2,
+ .rev = 0,
+ .funcs = &uvd_v4_2_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_VCE,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &vce_v2_0_ip_funcs,
+ },
+};
+
+static const struct amdgpu_ip_block_version hawaii_ip_blocks[] =
+{
+ /* ORDER MATTERS! */
+ {
+ .type = AMD_IP_BLOCK_TYPE_COMMON,
+ .major = 1,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_common_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_GMC,
+ .major = 7,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &gmc_v7_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_IH,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_ih_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_SMC,
+ .major = 7,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &ci_dpm_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_DCE,
+ .major = 8,
+ .minor = 5,
+ .rev = 0,
+ .funcs = &dce_v8_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_GFX,
+ .major = 7,
+ .minor = 3,
+ .rev = 0,
+ .funcs = &gfx_v7_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_SDMA,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_sdma_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_UVD,
+ .major = 4,
+ .minor = 2,
+ .rev = 0,
+ .funcs = &uvd_v4_2_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_VCE,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &vce_v2_0_ip_funcs,
+ },
+};
+
+static const struct amdgpu_ip_block_version kabini_ip_blocks[] =
+{
+ /* ORDER MATTERS! */
+ {
+ .type = AMD_IP_BLOCK_TYPE_COMMON,
+ .major = 1,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_common_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_GMC,
+ .major = 7,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &gmc_v7_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_IH,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_ih_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_SMC,
+ .major = 7,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &kv_dpm_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_DCE,
+ .major = 8,
+ .minor = 3,
+ .rev = 0,
+ .funcs = &dce_v8_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_GFX,
+ .major = 7,
+ .minor = 2,
+ .rev = 0,
+ .funcs = &gfx_v7_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_SDMA,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_sdma_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_UVD,
+ .major = 4,
+ .minor = 2,
+ .rev = 0,
+ .funcs = &uvd_v4_2_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_VCE,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &vce_v2_0_ip_funcs,
+ },
+};
+
+static const struct amdgpu_ip_block_version mullins_ip_blocks[] =
+{
+ /* ORDER MATTERS! */
+ {
+ .type = AMD_IP_BLOCK_TYPE_COMMON,
+ .major = 1,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_common_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_GMC,
+ .major = 7,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &gmc_v7_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_IH,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_ih_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_SMC,
+ .major = 7,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &kv_dpm_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_DCE,
+ .major = 8,
+ .minor = 3,
+ .rev = 0,
+ .funcs = &dce_v8_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_GFX,
+ .major = 7,
+ .minor = 2,
+ .rev = 0,
+ .funcs = &gfx_v7_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_SDMA,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_sdma_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_UVD,
+ .major = 4,
+ .minor = 2,
+ .rev = 0,
+ .funcs = &uvd_v4_2_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_VCE,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &vce_v2_0_ip_funcs,
+ },
+};
+
+static const struct amdgpu_ip_block_version kaveri_ip_blocks[] =
+{
+ /* ORDER MATTERS! */
+ {
+ .type = AMD_IP_BLOCK_TYPE_COMMON,
+ .major = 1,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_common_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_GMC,
+ .major = 7,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &gmc_v7_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_IH,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_ih_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_SMC,
+ .major = 7,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &kv_dpm_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_DCE,
+ .major = 8,
+ .minor = 1,
+ .rev = 0,
+ .funcs = &dce_v8_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_GFX,
+ .major = 7,
+ .minor = 1,
+ .rev = 0,
+ .funcs = &gfx_v7_0_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_SDMA,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &cik_sdma_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_UVD,
+ .major = 4,
+ .minor = 2,
+ .rev = 0,
+ .funcs = &uvd_v4_2_ip_funcs,
+ },
+ {
+ .type = AMD_IP_BLOCK_TYPE_VCE,
+ .major = 2,
+ .minor = 0,
+ .rev = 0,
+ .funcs = &vce_v2_0_ip_funcs,
+ },
+};
+
+int cik_set_ip_blocks(struct amdgpu_device *adev)
+{
+ switch (adev->asic_type) {
+ case CHIP_BONAIRE:
+ adev->ip_blocks = bonaire_ip_blocks;
+ adev->num_ip_blocks = ARRAY_SIZE(bonaire_ip_blocks);
+ break;
+ case CHIP_HAWAII:
+ adev->ip_blocks = hawaii_ip_blocks;
+ adev->num_ip_blocks = ARRAY_SIZE(hawaii_ip_blocks);
+ break;
+ case CHIP_KAVERI:
+ adev->ip_blocks = kaveri_ip_blocks;
+ adev->num_ip_blocks = ARRAY_SIZE(kaveri_ip_blocks);
+ break;
+ case CHIP_KABINI:
+ adev->ip_blocks = kabini_ip_blocks;
+ adev->num_ip_blocks = ARRAY_SIZE(kabini_ip_blocks);
+ break;
+ case CHIP_MULLINS:
+ adev->ip_blocks = mullins_ip_blocks;
+ adev->num_ip_blocks = ARRAY_SIZE(mullins_ip_blocks);
+ break;
+ default:
+ /* FIXME: not supported yet */
+ return -EINVAL;
+ }
+
+ adev->ip_block_enabled = kcalloc(adev->num_ip_blocks, sizeof(bool), GFP_KERNEL);
+ if (adev->ip_block_enabled == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static const struct amdgpu_asic_funcs cik_asic_funcs =
+{
+ .read_disabled_bios = &cik_read_disabled_bios,
+ .read_register = &cik_read_register,
+ .reset = &cik_asic_reset,
+ .set_vga_state = &cik_vga_set_state,
+ .get_xclk = &cik_get_xclk,
+ .set_uvd_clocks = &cik_set_uvd_clocks,
+ .set_vce_clocks = &cik_set_vce_clocks,
+ .get_cu_info = &gfx_v7_0_get_cu_info,
+ /* these should be moved to their own ip modules */
+ .get_gpu_clock_counter = &gfx_v7_0_get_gpu_clock_counter,
+ .wait_for_mc_idle = &gmc_v7_0_mc_wait_for_idle,
+};
+
+static int cik_common_early_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ adev->smc_rreg = &cik_smc_rreg;
+ adev->smc_wreg = &cik_smc_wreg;
+ adev->pcie_rreg = &cik_pcie_rreg;
+ adev->pcie_wreg = &cik_pcie_wreg;
+ adev->uvd_ctx_rreg = &cik_uvd_ctx_rreg;
+ adev->uvd_ctx_wreg = &cik_uvd_ctx_wreg;
+ adev->didt_rreg = &cik_didt_rreg;
+ adev->didt_wreg = &cik_didt_wreg;
+
+ adev->asic_funcs = &cik_asic_funcs;
+
+ adev->has_uvd = true;
+
+ adev->rev_id = cik_get_rev_id(adev);
+ adev->external_rev_id = 0xFF;
+ switch (adev->asic_type) {
+ case CHIP_BONAIRE:
+ adev->cg_flags =
+ AMDGPU_CG_SUPPORT_GFX_MGCG |
+ AMDGPU_CG_SUPPORT_GFX_MGLS |
+ /*AMDGPU_CG_SUPPORT_GFX_CGCG |*/
+ AMDGPU_CG_SUPPORT_GFX_CGLS |
+ AMDGPU_CG_SUPPORT_GFX_CGTS |
+ AMDGPU_CG_SUPPORT_GFX_CGTS_LS |
+ AMDGPU_CG_SUPPORT_GFX_CP_LS |
+ AMDGPU_CG_SUPPORT_MC_LS |
+ AMDGPU_CG_SUPPORT_MC_MGCG |
+ AMDGPU_CG_SUPPORT_SDMA_MGCG |
+ AMDGPU_CG_SUPPORT_SDMA_LS |
+ AMDGPU_CG_SUPPORT_BIF_LS |
+ AMDGPU_CG_SUPPORT_VCE_MGCG |
+ AMDGPU_CG_SUPPORT_UVD_MGCG |
+ AMDGPU_CG_SUPPORT_HDP_LS |
+ AMDGPU_CG_SUPPORT_HDP_MGCG;
+ adev->pg_flags = 0;
+ adev->external_rev_id = adev->rev_id + 0x14;
+ break;
+ case CHIP_HAWAII:
+ adev->cg_flags =
+ AMDGPU_CG_SUPPORT_GFX_MGCG |
+ AMDGPU_CG_SUPPORT_GFX_MGLS |
+ /*AMDGPU_CG_SUPPORT_GFX_CGCG |*/
+ AMDGPU_CG_SUPPORT_GFX_CGLS |
+ AMDGPU_CG_SUPPORT_GFX_CGTS |
+ AMDGPU_CG_SUPPORT_GFX_CP_LS |
+ AMDGPU_CG_SUPPORT_MC_LS |
+ AMDGPU_CG_SUPPORT_MC_MGCG |
+ AMDGPU_CG_SUPPORT_SDMA_MGCG |
+ AMDGPU_CG_SUPPORT_SDMA_LS |
+ AMDGPU_CG_SUPPORT_BIF_LS |
+ AMDGPU_CG_SUPPORT_VCE_MGCG |
+ AMDGPU_CG_SUPPORT_UVD_MGCG |
+ AMDGPU_CG_SUPPORT_HDP_LS |
+ AMDGPU_CG_SUPPORT_HDP_MGCG;
+ adev->pg_flags = 0;
+ adev->external_rev_id = 0x28;
+ break;
+ case CHIP_KAVERI:
+ adev->cg_flags =
+ AMDGPU_CG_SUPPORT_GFX_MGCG |
+ AMDGPU_CG_SUPPORT_GFX_MGLS |
+ /*AMDGPU_CG_SUPPORT_GFX_CGCG |*/
+ AMDGPU_CG_SUPPORT_GFX_CGLS |
+ AMDGPU_CG_SUPPORT_GFX_CGTS |
+ AMDGPU_CG_SUPPORT_GFX_CGTS_LS |
+ AMDGPU_CG_SUPPORT_GFX_CP_LS |
+ AMDGPU_CG_SUPPORT_SDMA_MGCG |
+ AMDGPU_CG_SUPPORT_SDMA_LS |
+ AMDGPU_CG_SUPPORT_BIF_LS |
+ AMDGPU_CG_SUPPORT_VCE_MGCG |
+ AMDGPU_CG_SUPPORT_UVD_MGCG |
+ AMDGPU_CG_SUPPORT_HDP_LS |
+ AMDGPU_CG_SUPPORT_HDP_MGCG;
+ adev->pg_flags =
+ /*AMDGPU_PG_SUPPORT_GFX_PG |
+ AMDGPU_PG_SUPPORT_GFX_SMG |
+ AMDGPU_PG_SUPPORT_GFX_DMG |*/
+ AMDGPU_PG_SUPPORT_UVD |
+ /*AMDGPU_PG_SUPPORT_VCE |
+ AMDGPU_PG_SUPPORT_CP |
+ AMDGPU_PG_SUPPORT_GDS |
+ AMDGPU_PG_SUPPORT_RLC_SMU_HS |
+ AMDGPU_PG_SUPPORT_ACP |
+ AMDGPU_PG_SUPPORT_SAMU |*/
+ 0;
+ if (adev->pdev->device == 0x1312 ||
+ adev->pdev->device == 0x1316 ||
+ adev->pdev->device == 0x1317)
+ adev->external_rev_id = 0x41;
+ else
+ adev->external_rev_id = 0x1;
+ break;
+ case CHIP_KABINI:
+ case CHIP_MULLINS:
+ adev->cg_flags =
+ AMDGPU_CG_SUPPORT_GFX_MGCG |
+ AMDGPU_CG_SUPPORT_GFX_MGLS |
+ /*AMDGPU_CG_SUPPORT_GFX_CGCG |*/
+ AMDGPU_CG_SUPPORT_GFX_CGLS |
+ AMDGPU_CG_SUPPORT_GFX_CGTS |
+ AMDGPU_CG_SUPPORT_GFX_CGTS_LS |
+ AMDGPU_CG_SUPPORT_GFX_CP_LS |
+ AMDGPU_CG_SUPPORT_SDMA_MGCG |
+ AMDGPU_CG_SUPPORT_SDMA_LS |
+ AMDGPU_CG_SUPPORT_BIF_LS |
+ AMDGPU_CG_SUPPORT_VCE_MGCG |
+ AMDGPU_CG_SUPPORT_UVD_MGCG |
+ AMDGPU_CG_SUPPORT_HDP_LS |
+ AMDGPU_CG_SUPPORT_HDP_MGCG;
+ adev->pg_flags =
+ /*AMDGPU_PG_SUPPORT_GFX_PG |
+ AMDGPU_PG_SUPPORT_GFX_SMG | */
+ AMDGPU_PG_SUPPORT_UVD |
+ /*AMDGPU_PG_SUPPORT_VCE |
+ AMDGPU_PG_SUPPORT_CP |
+ AMDGPU_PG_SUPPORT_GDS |
+ AMDGPU_PG_SUPPORT_RLC_SMU_HS |
+ AMDGPU_PG_SUPPORT_SAMU |*/
+ 0;
+ if (adev->asic_type == CHIP_KABINI) {
+ if (adev->rev_id == 0)
+ adev->external_rev_id = 0x81;
+ else if (adev->rev_id == 1)
+ adev->external_rev_id = 0x82;
+ else if (adev->rev_id == 2)
+ adev->external_rev_id = 0x85;
+ } else
+ adev->external_rev_id = adev->rev_id + 0xa1;
+ break;
+ default:
+ /* FIXME: not supported yet */
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cik_common_sw_init(void *handle)
+{
+ return 0;
+}
+
+static int cik_common_sw_fini(void *handle)
+{
+ return 0;
+}
+
+static int cik_common_hw_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ /* move the golden regs per IP block */
+ cik_init_golden_registers(adev);
+ /* enable pcie gen2/3 link */
+ cik_pcie_gen3_enable(adev);
+ /* enable aspm */
+ cik_program_aspm(adev);
+
+ return 0;
+}
+
+static int cik_common_hw_fini(void *handle)
+{
+ return 0;
+}
+
+static int cik_common_suspend(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ return cik_common_hw_fini(adev);
+}
+
+static int cik_common_resume(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ return cik_common_hw_init(adev);
+}
+
+static bool cik_common_is_idle(void *handle)
+{
+ return true;
+}
+
+static int cik_common_wait_for_idle(void *handle)
+{
+ return 0;
+}
+
+static void cik_common_print_status(void *handle)
+{
+
+}
+
+static int cik_common_soft_reset(void *handle)
+{
+ /* XXX hard reset?? */
+ return 0;
+}
+
+static int cik_common_set_clockgating_state(void *handle,
+ enum amd_clockgating_state state)
+{
+ return 0;
+}
+
+static int cik_common_set_powergating_state(void *handle,
+ enum amd_powergating_state state)
+{
+ return 0;
+}
+
+const struct amd_ip_funcs cik_common_ip_funcs = {
+ .early_init = cik_common_early_init,
+ .late_init = NULL,
+ .sw_init = cik_common_sw_init,
+ .sw_fini = cik_common_sw_fini,
+ .hw_init = cik_common_hw_init,
+ .hw_fini = cik_common_hw_fini,
+ .suspend = cik_common_suspend,
+ .resume = cik_common_resume,
+ .is_idle = cik_common_is_idle,
+ .wait_for_idle = cik_common_wait_for_idle,
+ .soft_reset = cik_common_soft_reset,
+ .print_status = cik_common_print_status,
+ .set_clockgating_state = cik_common_set_clockgating_state,
+ .set_powergating_state = cik_common_set_powergating_state,
+};
diff --git a/drivers/gpu/drm/amd/amdgpu/cik.h b/drivers/gpu/drm/amd/amdgpu/cik.h
new file mode 100644
index 000000000000..5ebd2d7a0327
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cik.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __CIK_H__
+#define __CIK_H__
+
+extern const struct amd_ip_funcs cik_common_ip_funcs;
+
+void cik_srbm_select(struct amdgpu_device *adev,
+ u32 me, u32 pipe, u32 queue, u32 vmid);
+int cik_set_ip_blocks(struct amdgpu_device *adev);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_dpm.h b/drivers/gpu/drm/amd/amdgpu/cik_dpm.h
new file mode 100644
index 000000000000..b1c8e7b446ea
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cik_dpm.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __CIK_DPM_H__
+#define __CIK_DPM_H__
+
+extern const struct amd_ip_funcs ci_dpm_ip_funcs;
+extern const struct amd_ip_funcs kv_dpm_ip_funcs;
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.c b/drivers/gpu/drm/amd/amdgpu/cik_ih.c
new file mode 100644
index 000000000000..8993c50cb89f
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.c
@@ -0,0 +1,471 @@
+/*
+ * Copyright 2012 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 "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_ih.h"
+#include "cikd.h"
+
+#include "bif/bif_4_1_d.h"
+#include "bif/bif_4_1_sh_mask.h"
+
+#include "oss/oss_2_0_d.h"
+#include "oss/oss_2_0_sh_mask.h"
+
+/*
+ * Interrupts
+ * Starting with r6xx, interrupts are handled via a ring buffer.
+ * Ring buffers are areas of GPU accessible memory that the GPU
+ * writes interrupt vectors into and the host reads vectors out of.
+ * There is a rptr (read pointer) that determines where the
+ * host is currently reading, and a wptr (write pointer)
+ * which determines where the GPU has written. When the
+ * pointers are equal, the ring is idle. When the GPU
+ * writes vectors to the ring buffer, it increments the
+ * wptr. When there is an interrupt, the host then starts
+ * fetching commands and processing them until the pointers are
+ * equal again at which point it updates the rptr.
+ */
+
+static void cik_ih_set_interrupt_funcs(struct amdgpu_device *adev);
+
+/**
+ * cik_ih_enable_interrupts - Enable the interrupt ring buffer
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Enable the interrupt ring buffer (CIK).
+ */
+static void cik_ih_enable_interrupts(struct amdgpu_device *adev)
+{
+ u32 ih_cntl = RREG32(mmIH_CNTL);
+ u32 ih_rb_cntl = RREG32(mmIH_RB_CNTL);
+
+ ih_cntl |= IH_CNTL__ENABLE_INTR_MASK;
+ ih_rb_cntl |= IH_RB_CNTL__RB_ENABLE_MASK;
+ WREG32(mmIH_CNTL, ih_cntl);
+ WREG32(mmIH_RB_CNTL, ih_rb_cntl);
+ adev->irq.ih.enabled = true;
+}
+
+/**
+ * cik_ih_disable_interrupts - Disable the interrupt ring buffer
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Disable the interrupt ring buffer (CIK).
+ */
+static void cik_ih_disable_interrupts(struct amdgpu_device *adev)
+{
+ u32 ih_rb_cntl = RREG32(mmIH_RB_CNTL);
+ u32 ih_cntl = RREG32(mmIH_CNTL);
+
+ ih_rb_cntl &= ~IH_RB_CNTL__RB_ENABLE_MASK;
+ ih_cntl &= ~IH_CNTL__ENABLE_INTR_MASK;
+ WREG32(mmIH_RB_CNTL, ih_rb_cntl);
+ WREG32(mmIH_CNTL, ih_cntl);
+ /* set rptr, wptr to 0 */
+ WREG32(mmIH_RB_RPTR, 0);
+ WREG32(mmIH_RB_WPTR, 0);
+ adev->irq.ih.enabled = false;
+ adev->irq.ih.rptr = 0;
+}
+
+/**
+ * cik_ih_irq_init - init and enable the interrupt ring
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Allocate a ring buffer for the interrupt controller,
+ * enable the RLC, disable interrupts, enable the IH
+ * ring buffer and enable it (CIK).
+ * Called at device load and reume.
+ * Returns 0 for success, errors for failure.
+ */
+static int cik_ih_irq_init(struct amdgpu_device *adev)
+{
+ int ret = 0;
+ int rb_bufsz;
+ u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
+ u64 wptr_off;
+
+ /* disable irqs */
+ cik_ih_disable_interrupts(adev);
+
+ /* setup interrupt control */
+ WREG32(mmINTERRUPT_CNTL2, adev->dummy_page.addr >> 8);
+ interrupt_cntl = RREG32(mmINTERRUPT_CNTL);
+ /* INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi
+ * INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN
+ */
+ interrupt_cntl &= ~INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK;
+ /* INTERRUPT_CNTL__IH_REQ_NONSNOOP_EN_MASK=1 if ring is in non-cacheable memory, e.g., vram */
+ interrupt_cntl &= ~INTERRUPT_CNTL__IH_REQ_NONSNOOP_EN_MASK;
+ WREG32(mmINTERRUPT_CNTL, interrupt_cntl);
+
+ WREG32(mmIH_RB_BASE, adev->irq.ih.gpu_addr >> 8);
+ rb_bufsz = order_base_2(adev->irq.ih.ring_size / 4);
+
+ ih_rb_cntl = (IH_RB_CNTL__WPTR_OVERFLOW_ENABLE_MASK |
+ IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK |
+ (rb_bufsz << 1));
+
+ ih_rb_cntl |= IH_RB_CNTL__WPTR_WRITEBACK_ENABLE_MASK;
+
+ /* set the writeback address whether it's enabled or not */
+ wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4);
+ WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(wptr_off));
+ WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFF);
+
+ WREG32(mmIH_RB_CNTL, ih_rb_cntl);
+
+ /* set rptr, wptr to 0 */
+ WREG32(mmIH_RB_RPTR, 0);
+ WREG32(mmIH_RB_WPTR, 0);
+
+ /* Default settings for IH_CNTL (disabled at first) */
+ ih_cntl = (0x10 << IH_CNTL__MC_WRREQ_CREDIT__SHIFT) |
+ (0x10 << IH_CNTL__MC_WR_CLEAN_CNT__SHIFT) |
+ (0 << IH_CNTL__MC_VMID__SHIFT);
+ /* IH_CNTL__RPTR_REARM_MASK only works if msi's are enabled */
+ if (adev->irq.msi_enabled)
+ ih_cntl |= IH_CNTL__RPTR_REARM_MASK;
+ WREG32(mmIH_CNTL, ih_cntl);
+
+ pci_set_master(adev->pdev);
+
+ /* enable irqs */
+ cik_ih_enable_interrupts(adev);
+
+ return ret;
+}
+
+/**
+ * cik_ih_irq_disable - disable interrupts
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Disable interrupts on the hw (CIK).
+ */
+static void cik_ih_irq_disable(struct amdgpu_device *adev)
+{
+ cik_ih_disable_interrupts(adev);
+ /* Wait and acknowledge irq */
+ mdelay(1);
+}
+
+/**
+ * cik_ih_get_wptr - get the IH ring buffer wptr
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Get the IH ring buffer wptr from either the register
+ * or the writeback memory buffer (CIK). Also check for
+ * ring buffer overflow and deal with it.
+ * Used by cik_irq_process().
+ * Returns the value of the wptr.
+ */
+static u32 cik_ih_get_wptr(struct amdgpu_device *adev)
+{
+ u32 wptr, tmp;
+
+ wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
+
+ if (wptr & IH_RB_WPTR__RB_OVERFLOW_MASK) {
+ wptr &= ~IH_RB_WPTR__RB_OVERFLOW_MASK;
+ /* When a ring buffer overflow happen start parsing interrupt
+ * from the last not overwritten vector (wptr + 16). Hopefully
+ * this should allow us to catchup.
+ */
+ dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
+ wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
+ adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
+ tmp = RREG32(mmIH_RB_CNTL);
+ tmp |= IH_RB_CNTL__WPTR_OVERFLOW_CLEAR_MASK;
+ WREG32(mmIH_RB_CNTL, tmp);
+ }
+ return (wptr & adev->irq.ih.ptr_mask);
+}
+
+/* CIK IV Ring
+ * Each IV ring entry is 128 bits:
+ * [7:0] - interrupt source id
+ * [31:8] - reserved
+ * [59:32] - interrupt source data
+ * [63:60] - reserved
+ * [71:64] - RINGID
+ * CP:
+ * ME_ID [1:0], PIPE_ID[1:0], QUEUE_ID[2:0]
+ * QUEUE_ID - for compute, which of the 8 queues owned by the dispatcher
+ * - for gfx, hw shader state (0=PS...5=LS, 6=CS)
+ * ME_ID - 0 = gfx, 1 = first 4 CS pipes, 2 = second 4 CS pipes
+ * PIPE_ID - ME0 0=3D
+ * - ME1&2 compute dispatcher (4 pipes each)
+ * SDMA:
+ * INSTANCE_ID [1:0], QUEUE_ID[1:0]
+ * INSTANCE_ID - 0 = sdma0, 1 = sdma1
+ * QUEUE_ID - 0 = gfx, 1 = rlc0, 2 = rlc1
+ * [79:72] - VMID
+ * [95:80] - PASID
+ * [127:96] - reserved
+ */
+
+ /**
+ * cik_ih_decode_iv - decode an interrupt vector
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Decodes the interrupt vector at the current rptr
+ * position and also advance the position.
+ */
+static void cik_ih_decode_iv(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry)
+{
+ /* wptr/rptr are in bytes! */
+ u32 ring_index = adev->irq.ih.rptr >> 2;
+ uint32_t dw[4];
+
+ dw[0] = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]);
+ dw[1] = le32_to_cpu(adev->irq.ih.ring[ring_index + 1]);
+ dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]);
+ dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
+
+ entry->src_id = dw[0] & 0xff;
+ entry->src_data = dw[1] & 0xfffffff;
+ entry->ring_id = dw[2] & 0xff;
+ entry->vm_id = (dw[2] >> 8) & 0xff;
+ entry->pas_id = (dw[2] >> 16) & 0xffff;
+
+ /* wptr/rptr are in bytes! */
+ adev->irq.ih.rptr += 16;
+}
+
+/**
+ * cik_ih_set_rptr - set the IH ring buffer rptr
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Set the IH ring buffer rptr.
+ */
+static void cik_ih_set_rptr(struct amdgpu_device *adev)
+{
+ WREG32(mmIH_RB_RPTR, adev->irq.ih.rptr);
+}
+
+static int cik_ih_early_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ cik_ih_set_interrupt_funcs(adev);
+
+ return 0;
+}
+
+static int cik_ih_sw_init(void *handle)
+{
+ int r;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ r = amdgpu_ih_ring_init(adev, 64 * 1024, false);
+ if (r)
+ return r;
+
+ r = amdgpu_irq_init(adev);
+
+ return r;
+}
+
+static int cik_ih_sw_fini(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ amdgpu_irq_fini(adev);
+ amdgpu_ih_ring_fini(adev);
+
+ return 0;
+}
+
+static int cik_ih_hw_init(void *handle)
+{
+ int r;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ r = cik_ih_irq_init(adev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int cik_ih_hw_fini(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ cik_ih_irq_disable(adev);
+
+ return 0;
+}
+
+static int cik_ih_suspend(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ return cik_ih_hw_fini(adev);
+}
+
+static int cik_ih_resume(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ return cik_ih_hw_init(adev);
+}
+
+static bool cik_ih_is_idle(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ u32 tmp = RREG32(mmSRBM_STATUS);
+
+ if (tmp & SRBM_STATUS__IH_BUSY_MASK)
+ return false;
+
+ return true;
+}
+
+static int cik_ih_wait_for_idle(void *handle)
+{
+ unsigned i;
+ u32 tmp;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ /* read MC_STATUS */
+ tmp = RREG32(mmSRBM_STATUS) & SRBM_STATUS__IH_BUSY_MASK;
+ if (!tmp)
+ return 0;
+ udelay(1);
+ }
+ return -ETIMEDOUT;
+}
+
+static void cik_ih_print_status(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ dev_info(adev->dev, "CIK IH registers\n");
+ dev_info(adev->dev, " SRBM_STATUS=0x%08X\n",
+ RREG32(mmSRBM_STATUS));
+ dev_info(adev->dev, " SRBM_STATUS2=0x%08X\n",
+ RREG32(mmSRBM_STATUS2));
+ dev_info(adev->dev, " INTERRUPT_CNTL=0x%08X\n",
+ RREG32(mmINTERRUPT_CNTL));
+ dev_info(adev->dev, " INTERRUPT_CNTL2=0x%08X\n",
+ RREG32(mmINTERRUPT_CNTL2));
+ dev_info(adev->dev, " IH_CNTL=0x%08X\n",
+ RREG32(mmIH_CNTL));
+ dev_info(adev->dev, " IH_RB_CNTL=0x%08X\n",
+ RREG32(mmIH_RB_CNTL));
+ dev_info(adev->dev, " IH_RB_BASE=0x%08X\n",
+ RREG32(mmIH_RB_BASE));
+ dev_info(adev->dev, " IH_RB_WPTR_ADDR_LO=0x%08X\n",
+ RREG32(mmIH_RB_WPTR_ADDR_LO));
+ dev_info(adev->dev, " IH_RB_WPTR_ADDR_HI=0x%08X\n",
+ RREG32(mmIH_RB_WPTR_ADDR_HI));
+ dev_info(adev->dev, " IH_RB_RPTR=0x%08X\n",
+ RREG32(mmIH_RB_RPTR));
+ dev_info(adev->dev, " IH_RB_WPTR=0x%08X\n",
+ RREG32(mmIH_RB_WPTR));
+}
+
+static int cik_ih_soft_reset(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ u32 srbm_soft_reset = 0;
+ u32 tmp = RREG32(mmSRBM_STATUS);
+
+ if (tmp & SRBM_STATUS__IH_BUSY_MASK)
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_IH_MASK;
+
+ if (srbm_soft_reset) {
+ cik_ih_print_status((void *)adev);
+
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+ tmp |= srbm_soft_reset;
+ dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+ WREG32(mmSRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+
+ udelay(50);
+
+ tmp &= ~srbm_soft_reset;
+ WREG32(mmSRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+
+ /* Wait a little for things to settle down */
+ udelay(50);
+
+ cik_ih_print_status((void *)adev);
+ }
+
+ return 0;
+}
+
+static int cik_ih_set_clockgating_state(void *handle,
+ enum amd_clockgating_state state)
+{
+ return 0;
+}
+
+static int cik_ih_set_powergating_state(void *handle,
+ enum amd_powergating_state state)
+{
+ return 0;
+}
+
+const struct amd_ip_funcs cik_ih_ip_funcs = {
+ .early_init = cik_ih_early_init,
+ .late_init = NULL,
+ .sw_init = cik_ih_sw_init,
+ .sw_fini = cik_ih_sw_fini,
+ .hw_init = cik_ih_hw_init,
+ .hw_fini = cik_ih_hw_fini,
+ .suspend = cik_ih_suspend,
+ .resume = cik_ih_resume,
+ .is_idle = cik_ih_is_idle,
+ .wait_for_idle = cik_ih_wait_for_idle,
+ .soft_reset = cik_ih_soft_reset,
+ .print_status = cik_ih_print_status,
+ .set_clockgating_state = cik_ih_set_clockgating_state,
+ .set_powergating_state = cik_ih_set_powergating_state,
+};
+
+static const struct amdgpu_ih_funcs cik_ih_funcs = {
+ .get_wptr = cik_ih_get_wptr,
+ .decode_iv = cik_ih_decode_iv,
+ .set_rptr = cik_ih_set_rptr
+};
+
+static void cik_ih_set_interrupt_funcs(struct amdgpu_device *adev)
+{
+ if (adev->irq.ih_funcs == NULL)
+ adev->irq.ih_funcs = &cik_ih_funcs;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.h b/drivers/gpu/drm/amd/amdgpu/cik_ih.h
new file mode 100644
index 000000000000..6b0f375ec244
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __CIK_IH_H__
+#define __CIK_IH_H__
+
+extern const struct amd_ip_funcs cik_ih_ip_funcs;
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
new file mode 100644
index 000000000000..ab83cc1ca4cc
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
@@ -0,0 +1,1407 @@
+/*
+ * Copyright 2013 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: Alex Deucher
+ */
+#include <linux/firmware.h>
+#include <drm/drmP.h>
+#include "amdgpu.h"
+#include "amdgpu_ucode.h"
+#include "amdgpu_trace.h"
+#include "cikd.h"
+#include "cik.h"
+
+#include "bif/bif_4_1_d.h"
+#include "bif/bif_4_1_sh_mask.h"
+
+#include "gca/gfx_7_2_d.h"
+#include "gca/gfx_7_2_enum.h"
+#include "gca/gfx_7_2_sh_mask.h"
+
+#include "gmc/gmc_7_1_d.h"
+#include "gmc/gmc_7_1_sh_mask.h"
+
+#include "oss/oss_2_0_d.h"
+#include "oss/oss_2_0_sh_mask.h"
+
+static const u32 sdma_offsets[SDMA_MAX_INSTANCE] =
+{
+ SDMA0_REGISTER_OFFSET,
+ SDMA1_REGISTER_OFFSET
+};
+
+static void cik_sdma_set_ring_funcs(struct amdgpu_device *adev);
+static void cik_sdma_set_irq_funcs(struct amdgpu_device *adev);
+static void cik_sdma_set_buffer_funcs(struct amdgpu_device *adev);
+static void cik_sdma_set_vm_pte_funcs(struct amdgpu_device *adev);
+
+MODULE_FIRMWARE("radeon/bonaire_sdma.bin");
+MODULE_FIRMWARE("radeon/bonaire_sdma1.bin");
+MODULE_FIRMWARE("radeon/hawaii_sdma.bin");
+MODULE_FIRMWARE("radeon/hawaii_sdma1.bin");
+MODULE_FIRMWARE("radeon/kaveri_sdma.bin");
+MODULE_FIRMWARE("radeon/kaveri_sdma1.bin");
+MODULE_FIRMWARE("radeon/kabini_sdma.bin");
+MODULE_FIRMWARE("radeon/kabini_sdma1.bin");
+MODULE_FIRMWARE("radeon/mullins_sdma.bin");
+MODULE_FIRMWARE("radeon/mullins_sdma1.bin");
+
+u32 amdgpu_cik_gpu_check_soft_reset(struct amdgpu_device *adev);
+
+/*
+ * sDMA - System DMA
+ * Starting with CIK, the GPU has new asynchronous
+ * DMA engines. These engines are used for compute
+ * and gfx. There are two DMA engines (SDMA0, SDMA1)
+ * and each one supports 1 ring buffer used for gfx
+ * and 2 queues used for compute.
+ *
+ * The programming model is very similar to the CP
+ * (ring buffer, IBs, etc.), but sDMA has it's own
+ * packet format that is different from the PM4 format
+ * used by the CP. sDMA supports copying data, writing
+ * embedded data, solid fills, and a number of other
+ * things. It also has support for tiling/detiling of
+ * buffers.
+ */
+
+/**
+ * cik_sdma_init_microcode - load ucode images from disk
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Use the firmware interface to load the ucode images into
+ * the driver (not loaded into hw).
+ * Returns 0 on success, error on failure.
+ */
+static int cik_sdma_init_microcode(struct amdgpu_device *adev)
+{
+ const char *chip_name;
+ char fw_name[30];
+ int err, i;
+
+ DRM_DEBUG("\n");
+
+ switch (adev->asic_type) {
+ case CHIP_BONAIRE:
+ chip_name = "bonaire";
+ break;
+ case CHIP_HAWAII:
+ chip_name = "hawaii";
+ break;
+ case CHIP_KAVERI:
+ chip_name = "kaveri";
+ break;
+ case CHIP_KABINI:
+ chip_name = "kabini";
+ break;
+ case CHIP_MULLINS:
+ chip_name = "mullins";
+ break;
+ default: BUG();
+ }
+
+ for (i = 0; i < SDMA_MAX_INSTANCE; i++) {
+ if (i == 0)
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name);
+ else
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma1.bin", chip_name);
+ err = request_firmware(&adev->sdma[i].fw, fw_name, adev->dev);
+ if (err)
+ goto out;
+ err = amdgpu_ucode_validate(adev->sdma[i].fw);
+ }
+out:
+ if (err) {
+ printk(KERN_ERR
+ "cik_sdma: Failed to load firmware \"%s\"\n",
+ fw_name);
+ for (i = 0; i < SDMA_MAX_INSTANCE; i++) {
+ release_firmware(adev->sdma[i].fw);
+ adev->sdma[i].fw = NULL;
+ }
+ }
+ return err;
+}
+
+/**
+ * cik_sdma_ring_get_rptr - get the current read pointer
+ *
+ * @ring: amdgpu ring pointer
+ *
+ * Get the current rptr from the hardware (CIK+).
+ */
+static uint32_t cik_sdma_ring_get_rptr(struct amdgpu_ring *ring)
+{
+ u32 rptr;
+
+ rptr = ring->adev->wb.wb[ring->rptr_offs];
+
+ return (rptr & 0x3fffc) >> 2;
+}
+
+/**
+ * cik_sdma_ring_get_wptr - get the current write pointer
+ *
+ * @ring: amdgpu ring pointer
+ *
+ * Get the current wptr from the hardware (CIK+).
+ */
+static uint32_t cik_sdma_ring_get_wptr(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ u32 me = (ring == &adev->sdma[0].ring) ? 0 : 1;
+
+ return (RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me]) & 0x3fffc) >> 2;
+}
+
+/**
+ * cik_sdma_ring_set_wptr - commit the write pointer
+ *
+ * @ring: amdgpu ring pointer
+ *
+ * Write the wptr back to the hardware (CIK+).
+ */
+static void cik_sdma_ring_set_wptr(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ u32 me = (ring == &adev->sdma[0].ring) ? 0 : 1;
+
+ WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], (ring->wptr << 2) & 0x3fffc);
+}
+
+/**
+ * cik_sdma_ring_emit_ib - Schedule an IB on the DMA engine
+ *
+ * @ring: amdgpu ring pointer
+ * @ib: IB object to schedule
+ *
+ * Schedule an IB in the DMA ring (CIK).
+ */
+static void cik_sdma_ring_emit_ib(struct amdgpu_ring *ring,
+ struct amdgpu_ib *ib)
+{
+ u32 extra_bits = (ib->vm ? ib->vm->ids[ring->idx].id : 0) & 0xf;
+ u32 next_rptr = ring->wptr + 5;
+
+ while ((next_rptr & 7) != 4)
+ next_rptr++;
+
+ next_rptr += 4;
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0));
+ amdgpu_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
+ amdgpu_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff);
+ amdgpu_ring_write(ring, 1); /* number of DWs to follow */
+ amdgpu_ring_write(ring, next_rptr);
+
+ /* IB packet must end on a 8 DW boundary */
+ while ((ring->wptr & 7) != 4)
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_INDIRECT_BUFFER, 0, extra_bits));
+ amdgpu_ring_write(ring, ib->gpu_addr & 0xffffffe0); /* base must be 32 byte aligned */
+ amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xffffffff);
+ amdgpu_ring_write(ring, ib->length_dw);
+
+}
+
+/**
+ * cik_sdma_ring_emit_hdp_flush - emit an hdp flush on the DMA ring
+ *
+ * @ring: amdgpu ring pointer
+ *
+ * Emit an hdp flush packet on the requested DMA ring.
+ */
+static void cik_sdma_ring_emit_hdp_flush(struct amdgpu_ring *ring)
+{
+ u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) |
+ SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */
+ u32 ref_and_mask;
+
+ if (ring == &ring->adev->sdma[0].ring)
+ ref_and_mask = GPU_HDP_FLUSH_DONE__SDMA0_MASK;
+ else
+ ref_and_mask = GPU_HDP_FLUSH_DONE__SDMA1_MASK;
+
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
+ amdgpu_ring_write(ring, mmGPU_HDP_FLUSH_DONE << 2);
+ amdgpu_ring_write(ring, mmGPU_HDP_FLUSH_REQ << 2);
+ amdgpu_ring_write(ring, ref_and_mask); /* reference */
+ amdgpu_ring_write(ring, ref_and_mask); /* mask */
+ amdgpu_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */
+}
+
+/**
+ * cik_sdma_ring_emit_fence - emit a fence on the DMA ring
+ *
+ * @ring: amdgpu ring pointer
+ * @fence: amdgpu fence object
+ *
+ * Add a DMA fence packet to the ring to write
+ * the fence seq number and DMA trap packet to generate
+ * an interrupt if needed (CIK).
+ */
+static void cik_sdma_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
+ unsigned flags)
+{
+ bool write64bit = flags & AMDGPU_FENCE_FLAG_64BIT;
+ /* write the fence */
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_FENCE, 0, 0));
+ amdgpu_ring_write(ring, lower_32_bits(addr));
+ amdgpu_ring_write(ring, upper_32_bits(addr));
+ amdgpu_ring_write(ring, lower_32_bits(seq));
+
+ /* optionally write high bits as well */
+ if (write64bit) {
+ addr += 4;
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_FENCE, 0, 0));
+ amdgpu_ring_write(ring, lower_32_bits(addr));
+ amdgpu_ring_write(ring, upper_32_bits(addr));
+ amdgpu_ring_write(ring, upper_32_bits(seq));
+ }
+
+ /* generate an interrupt */
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_TRAP, 0, 0));
+}
+
+/**
+ * cik_sdma_ring_emit_semaphore - emit a semaphore on the dma ring
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ * @semaphore: amdgpu semaphore object
+ * @emit_wait: wait or signal semaphore
+ *
+ * Add a DMA semaphore packet to the ring wait on or signal
+ * other rings (CIK).
+ */
+static bool cik_sdma_ring_emit_semaphore(struct amdgpu_ring *ring,
+ struct amdgpu_semaphore *semaphore,
+ bool emit_wait)
+{
+ u64 addr = semaphore->gpu_addr;
+ u32 extra_bits = emit_wait ? 0 : SDMA_SEMAPHORE_EXTRA_S;
+
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SEMAPHORE, 0, extra_bits));
+ amdgpu_ring_write(ring, addr & 0xfffffff8);
+ amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
+
+ return true;
+}
+
+/**
+ * cik_sdma_gfx_stop - stop the gfx async dma engines
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Stop the gfx async dma ring buffers (CIK).
+ */
+static void cik_sdma_gfx_stop(struct amdgpu_device *adev)
+{
+ struct amdgpu_ring *sdma0 = &adev->sdma[0].ring;
+ struct amdgpu_ring *sdma1 = &adev->sdma[1].ring;
+ u32 rb_cntl;
+ int i;
+
+ if ((adev->mman.buffer_funcs_ring == sdma0) ||
+ (adev->mman.buffer_funcs_ring == sdma1))
+ amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size);
+
+ for (i = 0; i < SDMA_MAX_INSTANCE; i++) {
+ rb_cntl = RREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i]);
+ rb_cntl &= ~SDMA0_GFX_RB_CNTL__RB_ENABLE_MASK;
+ WREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i], rb_cntl);
+ WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], 0);
+ }
+ sdma0->ready = false;
+ sdma1->ready = false;
+}
+
+/**
+ * cik_sdma_rlc_stop - stop the compute async dma engines
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Stop the compute async dma queues (CIK).
+ */
+static void cik_sdma_rlc_stop(struct amdgpu_device *adev)
+{
+ /* XXX todo */
+}
+
+/**
+ * cik_sdma_enable - stop the async dma engines
+ *
+ * @adev: amdgpu_device pointer
+ * @enable: enable/disable the DMA MEs.
+ *
+ * Halt or unhalt the async dma engines (CIK).
+ */
+static void cik_sdma_enable(struct amdgpu_device *adev, bool enable)
+{
+ u32 me_cntl;
+ int i;
+
+ if (enable == false) {
+ cik_sdma_gfx_stop(adev);
+ cik_sdma_rlc_stop(adev);
+ }
+
+ for (i = 0; i < SDMA_MAX_INSTANCE; i++) {
+ me_cntl = RREG32(mmSDMA0_F32_CNTL + sdma_offsets[i]);
+ if (enable)
+ me_cntl &= ~SDMA0_F32_CNTL__HALT_MASK;
+ else
+ me_cntl |= SDMA0_F32_CNTL__HALT_MASK;
+ WREG32(mmSDMA0_F32_CNTL + sdma_offsets[i], me_cntl);
+ }
+}
+
+/**
+ * cik_sdma_gfx_resume - setup and start the async dma engines
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Set up the gfx DMA ring buffers and enable them (CIK).
+ * Returns 0 for success, error for failure.
+ */
+static int cik_sdma_gfx_resume(struct amdgpu_device *adev)
+{
+ struct amdgpu_ring *ring;
+ u32 rb_cntl, ib_cntl;
+ u32 rb_bufsz;
+ u32 wb_offset;
+ int i, j, r;
+
+ for (i = 0; i < SDMA_MAX_INSTANCE; i++) {
+ ring = &adev->sdma[i].ring;
+ wb_offset = (ring->rptr_offs * 4);
+
+ mutex_lock(&adev->srbm_mutex);
+ for (j = 0; j < 16; j++) {
+ cik_srbm_select(adev, 0, 0, 0, j);
+ /* SDMA GFX */
+ WREG32(mmSDMA0_GFX_VIRTUAL_ADDR + sdma_offsets[i], 0);
+ WREG32(mmSDMA0_GFX_APE1_CNTL + sdma_offsets[i], 0);
+ /* XXX SDMA RLC - todo */
+ }
+ cik_srbm_select(adev, 0, 0, 0, 0);
+ mutex_unlock(&adev->srbm_mutex);
+
+ WREG32(mmSDMA0_SEM_INCOMPLETE_TIMER_CNTL + sdma_offsets[i], 0);
+ WREG32(mmSDMA0_SEM_WAIT_FAIL_TIMER_CNTL + sdma_offsets[i], 0);
+
+ /* Set ring buffer size in dwords */
+ rb_bufsz = order_base_2(ring->ring_size / 4);
+ rb_cntl = rb_bufsz << 1;
+#ifdef __BIG_ENDIAN
+ rb_cntl |= SDMA0_GFX_RB_CNTL__RB_SWAP_ENABLE_MASK |
+ SDMA0_GFX_RB_CNTL__RPTR_WRITEBACK_SWAP_ENABLE_MASK;
+#endif
+ WREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i], rb_cntl);
+
+ /* Initialize the ring buffer's read and write pointers */
+ WREG32(mmSDMA0_GFX_RB_RPTR + sdma_offsets[i], 0);
+ WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[i], 0);
+
+ /* set the wb address whether it's enabled or not */
+ WREG32(mmSDMA0_GFX_RB_RPTR_ADDR_HI + sdma_offsets[i],
+ upper_32_bits(adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFF);
+ WREG32(mmSDMA0_GFX_RB_RPTR_ADDR_LO + sdma_offsets[i],
+ ((adev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC));
+
+ rb_cntl |= SDMA0_GFX_RB_CNTL__RPTR_WRITEBACK_ENABLE_MASK;
+
+ WREG32(mmSDMA0_GFX_RB_BASE + sdma_offsets[i], ring->gpu_addr >> 8);
+ WREG32(mmSDMA0_GFX_RB_BASE_HI + sdma_offsets[i], ring->gpu_addr >> 40);
+
+ ring->wptr = 0;
+ WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[i], ring->wptr << 2);
+
+ /* enable DMA RB */
+ WREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i],
+ rb_cntl | SDMA0_GFX_RB_CNTL__RB_ENABLE_MASK);
+
+ ib_cntl = SDMA0_GFX_IB_CNTL__IB_ENABLE_MASK;
+#ifdef __BIG_ENDIAN
+ ib_cntl |= SDMA0_GFX_IB_CNTL__IB_SWAP_ENABLE_MASK;
+#endif
+ /* enable DMA IBs */
+ WREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i], ib_cntl);
+
+ ring->ready = true;
+
+ r = amdgpu_ring_test_ring(ring);
+ if (r) {
+ ring->ready = false;
+ return r;
+ }
+
+ if (adev->mman.buffer_funcs_ring == ring)
+ amdgpu_ttm_set_active_vram_size(adev, adev->mc.real_vram_size);
+ }
+
+ return 0;
+}
+
+/**
+ * cik_sdma_rlc_resume - setup and start the async dma engines
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Set up the compute DMA queues and enable them (CIK).
+ * Returns 0 for success, error for failure.
+ */
+static int cik_sdma_rlc_resume(struct amdgpu_device *adev)
+{
+ /* XXX todo */
+ return 0;
+}
+
+/**
+ * cik_sdma_load_microcode - load the sDMA ME ucode
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Loads the sDMA0/1 ucode.
+ * Returns 0 for success, -EINVAL if the ucode is not available.
+ */
+static int cik_sdma_load_microcode(struct amdgpu_device *adev)
+{
+ const struct sdma_firmware_header_v1_0 *hdr;
+ const __le32 *fw_data;
+ u32 fw_size;
+ int i, j;
+
+ if (!adev->sdma[0].fw || !adev->sdma[1].fw)
+ return -EINVAL;
+
+ /* halt the MEs */
+ cik_sdma_enable(adev, false);
+
+ for (i = 0; i < SDMA_MAX_INSTANCE; i++) {
+ hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
+ amdgpu_ucode_print_sdma_hdr(&hdr->header);
+ fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
+ adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+ fw_data = (const __le32 *)
+ (adev->sdma[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
+ WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], 0);
+ for (j = 0; j < fw_size; j++)
+ WREG32(mmSDMA0_UCODE_DATA + sdma_offsets[i], le32_to_cpup(fw_data++));
+ WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], adev->sdma[i].fw_version);
+ }
+
+ return 0;
+}
+
+/**
+ * cik_sdma_start - setup and start the async dma engines
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Set up the DMA engines and enable them (CIK).
+ * Returns 0 for success, error for failure.
+ */
+static int cik_sdma_start(struct amdgpu_device *adev)
+{
+ int r;
+
+ r = cik_sdma_load_microcode(adev);
+ if (r)
+ return r;
+
+ /* unhalt the MEs */
+ cik_sdma_enable(adev, true);
+
+ /* start the gfx rings and rlc compute queues */
+ r = cik_sdma_gfx_resume(adev);
+ if (r)
+ return r;
+ r = cik_sdma_rlc_resume(adev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+/**
+ * cik_sdma_ring_test_ring - simple async dma engine test
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Test the DMA engine by writing using it to write an
+ * value to memory. (CIK).
+ * Returns 0 for success, error for failure.
+ */
+static int cik_sdma_ring_test_ring(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ unsigned i;
+ unsigned index;
+ int r;
+ u32 tmp;
+ u64 gpu_addr;
+
+ r = amdgpu_wb_get(adev, &index);
+ if (r) {
+ dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+ return r;
+ }
+
+ gpu_addr = adev->wb.gpu_addr + (index * 4);
+ tmp = 0xCAFEDEAD;
+ adev->wb.wb[index] = cpu_to_le32(tmp);
+
+ r = amdgpu_ring_lock(ring, 5);
+ if (r) {
+ DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r);
+ amdgpu_wb_free(adev, index);
+ return r;
+ }
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0));
+ amdgpu_ring_write(ring, lower_32_bits(gpu_addr));
+ amdgpu_ring_write(ring, upper_32_bits(gpu_addr));
+ amdgpu_ring_write(ring, 1); /* number of DWs to follow */
+ amdgpu_ring_write(ring, 0xDEADBEEF);
+ amdgpu_ring_unlock_commit(ring);
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = le32_to_cpu(adev->wb.wb[index]);
+ if (tmp == 0xDEADBEEF)
+ break;
+ DRM_UDELAY(1);
+ }
+
+ if (i < adev->usec_timeout) {
+ DRM_INFO("ring test on %d succeeded in %d usecs\n", ring->idx, i);
+ } else {
+ DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n",
+ ring->idx, tmp);
+ r = -EINVAL;
+ }
+ amdgpu_wb_free(adev, index);
+
+ return r;
+}
+
+/**
+ * cik_sdma_ring_test_ib - test an IB on the DMA engine
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Test a simple IB in the DMA ring (CIK).
+ * Returns 0 on success, error on failure.
+ */
+static int cik_sdma_ring_test_ib(struct amdgpu_ring *ring)
+{
+ struct amdgpu_device *adev = ring->adev;
+ struct amdgpu_ib ib;
+ unsigned i;
+ unsigned index;
+ int r;
+ u32 tmp = 0;
+ u64 gpu_addr;
+
+ r = amdgpu_wb_get(adev, &index);
+ if (r) {
+ dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r);
+ return r;
+ }
+
+ gpu_addr = adev->wb.gpu_addr + (index * 4);
+ tmp = 0xCAFEDEAD;
+ adev->wb.wb[index] = cpu_to_le32(tmp);
+
+ r = amdgpu_ib_get(ring, NULL, 256, &ib);
+ if (r) {
+ amdgpu_wb_free(adev, index);
+ DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
+ return r;
+ }
+
+ ib.ptr[0] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+ ib.ptr[1] = lower_32_bits(gpu_addr);
+ ib.ptr[2] = upper_32_bits(gpu_addr);
+ ib.ptr[3] = 1;
+ ib.ptr[4] = 0xDEADBEEF;
+ ib.length_dw = 5;
+
+ r = amdgpu_ib_schedule(adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
+ if (r) {
+ amdgpu_ib_free(adev, &ib);
+ amdgpu_wb_free(adev, index);
+ DRM_ERROR("amdgpu: failed to schedule ib (%d).\n", r);
+ return r;
+ }
+ r = amdgpu_fence_wait(ib.fence, false);
+ if (r) {
+ amdgpu_ib_free(adev, &ib);
+ amdgpu_wb_free(adev, index);
+ DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
+ return r;
+ }
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = le32_to_cpu(adev->wb.wb[index]);
+ if (tmp == 0xDEADBEEF)
+ break;
+ DRM_UDELAY(1);
+ }
+ if (i < adev->usec_timeout) {
+ DRM_INFO("ib test on ring %d succeeded in %u usecs\n",
+ ib.fence->ring->idx, i);
+ } else {
+ DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp);
+ r = -EINVAL;
+ }
+ amdgpu_ib_free(adev, &ib);
+ amdgpu_wb_free(adev, index);
+ return r;
+}
+
+/**
+ * cik_sdma_vm_copy_pages - update PTEs by copying them from the GART
+ *
+ * @ib: indirect buffer to fill with commands
+ * @pe: addr of the page entry
+ * @src: src addr to copy from
+ * @count: number of page entries to update
+ *
+ * Update PTEs by copying them from the GART using sDMA (CIK).
+ */
+static void cik_sdma_vm_copy_pte(struct amdgpu_ib *ib,
+ uint64_t pe, uint64_t src,
+ unsigned count)
+{
+ while (count) {
+ unsigned bytes = count * 8;
+ if (bytes > 0x1FFFF8)
+ bytes = 0x1FFFF8;
+
+ ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_COPY,
+ SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+ ib->ptr[ib->length_dw++] = bytes;
+ ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */
+ ib->ptr[ib->length_dw++] = lower_32_bits(src);
+ ib->ptr[ib->length_dw++] = upper_32_bits(src);
+ ib->ptr[ib->length_dw++] = lower_32_bits(pe);
+ ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+
+ pe += bytes;
+ src += bytes;
+ count -= bytes / 8;
+ }
+}
+
+/**
+ * cik_sdma_vm_write_pages - update PTEs by writing them manually
+ *
+ * @ib: indirect buffer to fill with commands
+ * @pe: addr of the page entry
+ * @addr: dst addr to write into pe
+ * @count: number of page entries to update
+ * @incr: increase next addr by incr bytes
+ * @flags: access flags
+ *
+ * Update PTEs by writing them manually using sDMA (CIK).
+ */
+static void cik_sdma_vm_write_pte(struct amdgpu_ib *ib,
+ uint64_t pe,
+ uint64_t addr, unsigned count,
+ uint32_t incr, uint32_t flags)
+{
+ uint64_t value;
+ unsigned ndw;
+
+ while (count) {
+ ndw = count * 2;
+ if (ndw > 0xFFFFE)
+ ndw = 0xFFFFE;
+
+ /* for non-physically contiguous pages (system) */
+ ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_WRITE,
+ SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
+ ib->ptr[ib->length_dw++] = pe;
+ ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+ ib->ptr[ib->length_dw++] = ndw;
+ for (; ndw > 0; ndw -= 2, --count, pe += 8) {
+ if (flags & AMDGPU_PTE_SYSTEM) {
+ value = amdgpu_vm_map_gart(ib->ring->adev, addr);
+ value &= 0xFFFFFFFFFFFFF000ULL;
+ } else if (flags & AMDGPU_PTE_VALID) {
+ value = addr;
+ } else {
+ value = 0;
+ }
+ addr += incr;
+ value |= flags;
+ ib->ptr[ib->length_dw++] = value;
+ ib->ptr[ib->length_dw++] = upper_32_bits(value);
+ }
+ }
+}
+
+/**
+ * cik_sdma_vm_set_pages - update the page tables using sDMA
+ *
+ * @ib: indirect buffer to fill with commands
+ * @pe: addr of the page entry
+ * @addr: dst addr to write into pe
+ * @count: number of page entries to update
+ * @incr: increase next addr by incr bytes
+ * @flags: access flags
+ *
+ * Update the page tables using sDMA (CIK).
+ */
+static void cik_sdma_vm_set_pte_pde(struct amdgpu_ib *ib,
+ uint64_t pe,
+ uint64_t addr, unsigned count,
+ uint32_t incr, uint32_t flags)
+{
+ uint64_t value;
+ unsigned ndw;
+
+ while (count) {
+ ndw = count;
+ if (ndw > 0x7FFFF)
+ ndw = 0x7FFFF;
+
+ if (flags & AMDGPU_PTE_VALID)
+ value = addr;
+ else
+ value = 0;
+
+ /* for physically contiguous pages (vram) */
+ ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_GENERATE_PTE_PDE, 0, 0);
+ ib->ptr[ib->length_dw++] = pe; /* dst addr */
+ ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+ ib->ptr[ib->length_dw++] = flags; /* mask */
+ ib->ptr[ib->length_dw++] = 0;
+ ib->ptr[ib->length_dw++] = value; /* value */
+ ib->ptr[ib->length_dw++] = upper_32_bits(value);
+ ib->ptr[ib->length_dw++] = incr; /* increment size */
+ ib->ptr[ib->length_dw++] = 0;
+ ib->ptr[ib->length_dw++] = ndw; /* number of entries */
+
+ pe += ndw * 8;
+ addr += ndw * incr;
+ count -= ndw;
+ }
+}
+
+/**
+ * cik_sdma_vm_pad_ib - pad the IB to the required number of dw
+ *
+ * @ib: indirect buffer to fill with padding
+ *
+ */
+static void cik_sdma_vm_pad_ib(struct amdgpu_ib *ib)
+{
+ while (ib->length_dw & 0x7)
+ ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0);
+}
+
+/**
+ * cik_sdma_ring_emit_vm_flush - cik vm flush using sDMA
+ *
+ * @ring: amdgpu_ring pointer
+ * @vm: amdgpu_vm pointer
+ *
+ * Update the page table base and flush the VM TLB
+ * using sDMA (CIK).
+ */
+static void cik_sdma_ring_emit_vm_flush(struct amdgpu_ring *ring,
+ unsigned vm_id, uint64_t pd_addr)
+{
+ u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(0) |
+ SDMA_POLL_REG_MEM_EXTRA_FUNC(0)); /* always */
+
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+ if (vm_id < 8) {
+ amdgpu_ring_write(ring, (mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vm_id));
+ } else {
+ amdgpu_ring_write(ring, (mmVM_CONTEXT8_PAGE_TABLE_BASE_ADDR + vm_id - 8));
+ }
+ amdgpu_ring_write(ring, pd_addr >> 12);
+
+ /* flush TLB */
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+ amdgpu_ring_write(ring, mmVM_INVALIDATE_REQUEST);
+ amdgpu_ring_write(ring, 1 << vm_id);
+
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
+ amdgpu_ring_write(ring, mmVM_INVALIDATE_REQUEST << 2);
+ amdgpu_ring_write(ring, 0);
+ amdgpu_ring_write(ring, 0); /* reference */
+ amdgpu_ring_write(ring, 0); /* mask */
+ amdgpu_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */
+}
+
+static void cik_enable_sdma_mgcg(struct amdgpu_device *adev,
+ bool enable)
+{
+ u32 orig, data;
+
+ if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_SDMA_MGCG)) {
+ WREG32(mmSDMA0_CLK_CTRL + SDMA0_REGISTER_OFFSET, 0x00000100);
+ WREG32(mmSDMA0_CLK_CTRL + SDMA1_REGISTER_OFFSET, 0x00000100);
+ } else {
+ orig = data = RREG32(mmSDMA0_CLK_CTRL + SDMA0_REGISTER_OFFSET);
+ data |= 0xff000000;
+ if (data != orig)
+ WREG32(mmSDMA0_CLK_CTRL + SDMA0_REGISTER_OFFSET, data);
+
+ orig = data = RREG32(mmSDMA0_CLK_CTRL + SDMA1_REGISTER_OFFSET);
+ data |= 0xff000000;
+ if (data != orig)
+ WREG32(mmSDMA0_CLK_CTRL + SDMA1_REGISTER_OFFSET, data);
+ }
+}
+
+static void cik_enable_sdma_mgls(struct amdgpu_device *adev,
+ bool enable)
+{
+ u32 orig, data;
+
+ if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_SDMA_LS)) {
+ orig = data = RREG32(mmSDMA0_POWER_CNTL + SDMA0_REGISTER_OFFSET);
+ data |= 0x100;
+ if (orig != data)
+ WREG32(mmSDMA0_POWER_CNTL + SDMA0_REGISTER_OFFSET, data);
+
+ orig = data = RREG32(mmSDMA0_POWER_CNTL + SDMA1_REGISTER_OFFSET);
+ data |= 0x100;
+ if (orig != data)
+ WREG32(mmSDMA0_POWER_CNTL + SDMA1_REGISTER_OFFSET, data);
+ } else {
+ orig = data = RREG32(mmSDMA0_POWER_CNTL + SDMA0_REGISTER_OFFSET);
+ data &= ~0x100;
+ if (orig != data)
+ WREG32(mmSDMA0_POWER_CNTL + SDMA0_REGISTER_OFFSET, data);
+
+ orig = data = RREG32(mmSDMA0_POWER_CNTL + SDMA1_REGISTER_OFFSET);
+ data &= ~0x100;
+ if (orig != data)
+ WREG32(mmSDMA0_POWER_CNTL + SDMA1_REGISTER_OFFSET, data);
+ }
+}
+
+static int cik_sdma_early_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ cik_sdma_set_ring_funcs(adev);
+ cik_sdma_set_irq_funcs(adev);
+ cik_sdma_set_buffer_funcs(adev);
+ cik_sdma_set_vm_pte_funcs(adev);
+
+ return 0;
+}
+
+static int cik_sdma_sw_init(void *handle)
+{
+ struct amdgpu_ring *ring;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int r;
+
+ r = cik_sdma_init_microcode(adev);
+ if (r) {
+ DRM_ERROR("Failed to load sdma firmware!\n");
+ return r;
+ }
+
+ /* SDMA trap event */
+ r = amdgpu_irq_add_id(adev, 224, &adev->sdma_trap_irq);
+ if (r)
+ return r;
+
+ /* SDMA Privileged inst */
+ r = amdgpu_irq_add_id(adev, 241, &adev->sdma_illegal_inst_irq);
+ if (r)
+ return r;
+
+ /* SDMA Privileged inst */
+ r = amdgpu_irq_add_id(adev, 247, &adev->sdma_illegal_inst_irq);
+ if (r)
+ return r;
+
+ ring = &adev->sdma[0].ring;
+ ring->ring_obj = NULL;
+
+ ring = &adev->sdma[1].ring;
+ ring->ring_obj = NULL;
+
+ ring = &adev->sdma[0].ring;
+ sprintf(ring->name, "sdma0");
+ r = amdgpu_ring_init(adev, ring, 256 * 1024,
+ SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0), 0xf,
+ &adev->sdma_trap_irq, AMDGPU_SDMA_IRQ_TRAP0,
+ AMDGPU_RING_TYPE_SDMA);
+ if (r)
+ return r;
+
+ ring = &adev->sdma[1].ring;
+ sprintf(ring->name, "sdma1");
+ r = amdgpu_ring_init(adev, ring, 256 * 1024,
+ SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0), 0xf,
+ &adev->sdma_trap_irq, AMDGPU_SDMA_IRQ_TRAP1,
+ AMDGPU_RING_TYPE_SDMA);
+ if (r)
+ return r;
+
+ return r;
+}
+
+static int cik_sdma_sw_fini(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ amdgpu_ring_fini(&adev->sdma[0].ring);
+ amdgpu_ring_fini(&adev->sdma[1].ring);
+
+ return 0;
+}
+
+static int cik_sdma_hw_init(void *handle)
+{
+ int r;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ r = cik_sdma_start(adev);
+ if (r)
+ return r;
+
+ return r;
+}
+
+static int cik_sdma_hw_fini(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ cik_sdma_enable(adev, false);
+
+ return 0;
+}
+
+static int cik_sdma_suspend(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ return cik_sdma_hw_fini(adev);
+}
+
+static int cik_sdma_resume(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ return cik_sdma_hw_init(adev);
+}
+
+static bool cik_sdma_is_idle(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ u32 tmp = RREG32(mmSRBM_STATUS2);
+
+ if (tmp & (SRBM_STATUS2__SDMA_BUSY_MASK |
+ SRBM_STATUS2__SDMA1_BUSY_MASK))
+ return false;
+
+ return true;
+}
+
+static int cik_sdma_wait_for_idle(void *handle)
+{
+ unsigned i;
+ u32 tmp;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = RREG32(mmSRBM_STATUS2) & (SRBM_STATUS2__SDMA_BUSY_MASK |
+ SRBM_STATUS2__SDMA1_BUSY_MASK);
+
+ if (!tmp)
+ return 0;
+ udelay(1);
+ }
+ return -ETIMEDOUT;
+}
+
+static void cik_sdma_print_status(void *handle)
+{
+ int i, j;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ dev_info(adev->dev, "CIK SDMA registers\n");
+ dev_info(adev->dev, " SRBM_STATUS2=0x%08X\n",
+ RREG32(mmSRBM_STATUS2));
+ for (i = 0; i < SDMA_MAX_INSTANCE; i++) {
+ dev_info(adev->dev, " SDMA%d_STATUS_REG=0x%08X\n",
+ i, RREG32(mmSDMA0_STATUS_REG + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA%d_ME_CNTL=0x%08X\n",
+ i, RREG32(mmSDMA0_F32_CNTL + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA%d_CNTL=0x%08X\n",
+ i, RREG32(mmSDMA0_CNTL + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA%d_SEM_INCOMPLETE_TIMER_CNTL=0x%08X\n",
+ i, RREG32(mmSDMA0_SEM_INCOMPLETE_TIMER_CNTL + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA%d_SEM_WAIT_FAIL_TIMER_CNTL=0x%08X\n",
+ i, RREG32(mmSDMA0_SEM_WAIT_FAIL_TIMER_CNTL + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA%d_GFX_IB_CNTL=0x%08X\n",
+ i, RREG32(mmSDMA0_GFX_IB_CNTL + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA%d_GFX_RB_CNTL=0x%08X\n",
+ i, RREG32(mmSDMA0_GFX_RB_CNTL + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA%d_GFX_RB_RPTR=0x%08X\n",
+ i, RREG32(mmSDMA0_GFX_RB_RPTR + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA%d_GFX_RB_WPTR=0x%08X\n",
+ i, RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA%d_GFX_RB_RPTR_ADDR_HI=0x%08X\n",
+ i, RREG32(mmSDMA0_GFX_RB_RPTR_ADDR_HI + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA%d_GFX_RB_RPTR_ADDR_LO=0x%08X\n",
+ i, RREG32(mmSDMA0_GFX_RB_RPTR_ADDR_LO + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA%d_GFX_RB_BASE=0x%08X\n",
+ i, RREG32(mmSDMA0_GFX_RB_BASE + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA%d_GFX_RB_BASE_HI=0x%08X\n",
+ i, RREG32(mmSDMA0_GFX_RB_BASE_HI + sdma_offsets[i]));
+ mutex_lock(&adev->srbm_mutex);
+ for (j = 0; j < 16; j++) {
+ cik_srbm_select(adev, 0, 0, 0, j);
+ dev_info(adev->dev, " VM %d:\n", j);
+ dev_info(adev->dev, " SDMA0_GFX_VIRTUAL_ADDR=0x%08X\n",
+ RREG32(mmSDMA0_GFX_VIRTUAL_ADDR + sdma_offsets[i]));
+ dev_info(adev->dev, " SDMA0_GFX_APE1_CNTL=0x%08X\n",
+ RREG32(mmSDMA0_GFX_APE1_CNTL + sdma_offsets[i]));
+ }
+ cik_srbm_select(adev, 0, 0, 0, 0);
+ mutex_unlock(&adev->srbm_mutex);
+ }
+}
+
+static int cik_sdma_soft_reset(void *handle)
+{
+ u32 srbm_soft_reset = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ u32 tmp = RREG32(mmSRBM_STATUS2);
+
+ if (tmp & SRBM_STATUS2__SDMA_BUSY_MASK) {
+ /* sdma0 */
+ tmp = RREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET);
+ tmp |= SDMA0_F32_CNTL__HALT_MASK;
+ WREG32(mmSDMA0_F32_CNTL + SDMA0_REGISTER_OFFSET, tmp);
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA_MASK;
+ }
+ if (tmp & SRBM_STATUS2__SDMA1_BUSY_MASK) {
+ /* sdma1 */
+ tmp = RREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET);
+ tmp |= SDMA0_F32_CNTL__HALT_MASK;
+ WREG32(mmSDMA0_F32_CNTL + SDMA1_REGISTER_OFFSET, tmp);
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA1_MASK;
+ }
+
+ if (srbm_soft_reset) {
+ cik_sdma_print_status((void *)adev);
+
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+ tmp |= srbm_soft_reset;
+ dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+ WREG32(mmSRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+
+ udelay(50);
+
+ tmp &= ~srbm_soft_reset;
+ WREG32(mmSRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+
+ /* Wait a little for things to settle down */
+ udelay(50);
+
+ cik_sdma_print_status((void *)adev);
+ }
+
+ return 0;
+}
+
+static int cik_sdma_set_trap_irq_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *src,
+ unsigned type,
+ enum amdgpu_interrupt_state state)
+{
+ u32 sdma_cntl;
+
+ switch (type) {
+ case AMDGPU_SDMA_IRQ_TRAP0:
+ switch (state) {
+ case AMDGPU_IRQ_STATE_DISABLE:
+ sdma_cntl = RREG32(mmSDMA0_CNTL + SDMA0_REGISTER_OFFSET);
+ sdma_cntl &= ~SDMA0_CNTL__TRAP_ENABLE_MASK;
+ WREG32(mmSDMA0_CNTL + SDMA0_REGISTER_OFFSET, sdma_cntl);
+ break;
+ case AMDGPU_IRQ_STATE_ENABLE:
+ sdma_cntl = RREG32(mmSDMA0_CNTL + SDMA0_REGISTER_OFFSET);
+ sdma_cntl |= SDMA0_CNTL__TRAP_ENABLE_MASK;
+ WREG32(mmSDMA0_CNTL + SDMA0_REGISTER_OFFSET, sdma_cntl);
+ break;
+ default:
+ break;
+ }
+ break;
+ case AMDGPU_SDMA_IRQ_TRAP1:
+ switch (state) {
+ case AMDGPU_IRQ_STATE_DISABLE:
+ sdma_cntl = RREG32(mmSDMA0_CNTL + SDMA1_REGISTER_OFFSET);
+ sdma_cntl &= ~SDMA0_CNTL__TRAP_ENABLE_MASK;
+ WREG32(mmSDMA0_CNTL + SDMA1_REGISTER_OFFSET, sdma_cntl);
+ break;
+ case AMDGPU_IRQ_STATE_ENABLE:
+ sdma_cntl = RREG32(mmSDMA0_CNTL + SDMA1_REGISTER_OFFSET);
+ sdma_cntl |= SDMA0_CNTL__TRAP_ENABLE_MASK;
+ WREG32(mmSDMA0_CNTL + SDMA1_REGISTER_OFFSET, sdma_cntl);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int cik_sdma_process_trap_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ u8 instance_id, queue_id;
+
+ instance_id = (entry->ring_id & 0x3) >> 0;
+ queue_id = (entry->ring_id & 0xc) >> 2;
+ DRM_DEBUG("IH: SDMA trap\n");
+ switch (instance_id) {
+ case 0:
+ switch (queue_id) {
+ case 0:
+ amdgpu_fence_process(&adev->sdma[0].ring);
+ break;
+ case 1:
+ /* XXX compute */
+ break;
+ case 2:
+ /* XXX compute */
+ break;
+ }
+ break;
+ case 1:
+ switch (queue_id) {
+ case 0:
+ amdgpu_fence_process(&adev->sdma[1].ring);
+ break;
+ case 1:
+ /* XXX compute */
+ break;
+ case 2:
+ /* XXX compute */
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int cik_sdma_process_illegal_inst_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ DRM_ERROR("Illegal instruction in SDMA command stream\n");
+ schedule_work(&adev->reset_work);
+ return 0;
+}
+
+static int cik_sdma_set_clockgating_state(void *handle,
+ enum amd_clockgating_state state)
+{
+ bool gate = false;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (state == AMD_CG_STATE_GATE)
+ gate = true;
+
+ cik_enable_sdma_mgcg(adev, gate);
+ cik_enable_sdma_mgls(adev, gate);
+
+ return 0;
+}
+
+static int cik_sdma_set_powergating_state(void *handle,
+ enum amd_powergating_state state)
+{
+ return 0;
+}
+
+const struct amd_ip_funcs cik_sdma_ip_funcs = {
+ .early_init = cik_sdma_early_init,
+ .late_init = NULL,
+ .sw_init = cik_sdma_sw_init,
+ .sw_fini = cik_sdma_sw_fini,
+ .hw_init = cik_sdma_hw_init,
+ .hw_fini = cik_sdma_hw_fini,
+ .suspend = cik_sdma_suspend,
+ .resume = cik_sdma_resume,
+ .is_idle = cik_sdma_is_idle,
+ .wait_for_idle = cik_sdma_wait_for_idle,
+ .soft_reset = cik_sdma_soft_reset,
+ .print_status = cik_sdma_print_status,
+ .set_clockgating_state = cik_sdma_set_clockgating_state,
+ .set_powergating_state = cik_sdma_set_powergating_state,
+};
+
+/**
+ * cik_sdma_ring_is_lockup - Check if the DMA engine is locked up
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ *
+ * Check if the async DMA engine is locked up (CIK).
+ * Returns true if the engine appears to be locked up, false if not.
+ */
+static bool cik_sdma_ring_is_lockup(struct amdgpu_ring *ring)
+{
+
+ if (cik_sdma_is_idle(ring->adev)) {
+ amdgpu_ring_lockup_update(ring);
+ return false;
+ }
+ return amdgpu_ring_test_lockup(ring);
+}
+
+static const struct amdgpu_ring_funcs cik_sdma_ring_funcs = {
+ .get_rptr = cik_sdma_ring_get_rptr,
+ .get_wptr = cik_sdma_ring_get_wptr,
+ .set_wptr = cik_sdma_ring_set_wptr,
+ .parse_cs = NULL,
+ .emit_ib = cik_sdma_ring_emit_ib,
+ .emit_fence = cik_sdma_ring_emit_fence,
+ .emit_semaphore = cik_sdma_ring_emit_semaphore,
+ .emit_vm_flush = cik_sdma_ring_emit_vm_flush,
+ .emit_hdp_flush = cik_sdma_ring_emit_hdp_flush,
+ .test_ring = cik_sdma_ring_test_ring,
+ .test_ib = cik_sdma_ring_test_ib,
+ .is_lockup = cik_sdma_ring_is_lockup,
+};
+
+static void cik_sdma_set_ring_funcs(struct amdgpu_device *adev)
+{
+ adev->sdma[0].ring.funcs = &cik_sdma_ring_funcs;
+ adev->sdma[1].ring.funcs = &cik_sdma_ring_funcs;
+}
+
+static const struct amdgpu_irq_src_funcs cik_sdma_trap_irq_funcs = {
+ .set = cik_sdma_set_trap_irq_state,
+ .process = cik_sdma_process_trap_irq,
+};
+
+static const struct amdgpu_irq_src_funcs cik_sdma_illegal_inst_irq_funcs = {
+ .process = cik_sdma_process_illegal_inst_irq,
+};
+
+static void cik_sdma_set_irq_funcs(struct amdgpu_device *adev)
+{
+ adev->sdma_trap_irq.num_types = AMDGPU_SDMA_IRQ_LAST;
+ adev->sdma_trap_irq.funcs = &cik_sdma_trap_irq_funcs;
+ adev->sdma_illegal_inst_irq.funcs = &cik_sdma_illegal_inst_irq_funcs;
+}
+
+/**
+ * cik_sdma_emit_copy_buffer - copy buffer using the sDMA engine
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ * @src_offset: src GPU address
+ * @dst_offset: dst GPU address
+ * @byte_count: number of bytes to xfer
+ *
+ * Copy GPU buffers using the DMA engine (CIK).
+ * Used by the amdgpu ttm implementation to move pages if
+ * registered as the asic copy callback.
+ */
+static void cik_sdma_emit_copy_buffer(struct amdgpu_ring *ring,
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ uint32_t byte_count)
+{
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_COPY_SUB_OPCODE_LINEAR, 0));
+ amdgpu_ring_write(ring, byte_count);
+ amdgpu_ring_write(ring, 0); /* src/dst endian swap */
+ amdgpu_ring_write(ring, lower_32_bits(src_offset));
+ amdgpu_ring_write(ring, upper_32_bits(src_offset));
+ amdgpu_ring_write(ring, lower_32_bits(dst_offset));
+ amdgpu_ring_write(ring, upper_32_bits(dst_offset));
+}
+
+/**
+ * cik_sdma_emit_fill_buffer - fill buffer using the sDMA engine
+ *
+ * @ring: amdgpu_ring structure holding ring information
+ * @src_data: value to write to buffer
+ * @dst_offset: dst GPU address
+ * @byte_count: number of bytes to xfer
+ *
+ * Fill GPU buffers using the DMA engine (CIK).
+ */
+static void cik_sdma_emit_fill_buffer(struct amdgpu_ring *ring,
+ uint32_t src_data,
+ uint64_t dst_offset,
+ uint32_t byte_count)
+{
+ amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_CONSTANT_FILL, 0, 0));
+ amdgpu_ring_write(ring, lower_32_bits(dst_offset));
+ amdgpu_ring_write(ring, upper_32_bits(dst_offset));
+ amdgpu_ring_write(ring, src_data);
+ amdgpu_ring_write(ring, byte_count);
+}
+
+static const struct amdgpu_buffer_funcs cik_sdma_buffer_funcs = {
+ .copy_max_bytes = 0x1fffff,
+ .copy_num_dw = 7,
+ .emit_copy_buffer = cik_sdma_emit_copy_buffer,
+
+ .fill_max_bytes = 0x1fffff,
+ .fill_num_dw = 5,
+ .emit_fill_buffer = cik_sdma_emit_fill_buffer,
+};
+
+static void cik_sdma_set_buffer_funcs(struct amdgpu_device *adev)
+{
+ if (adev->mman.buffer_funcs == NULL) {
+ adev->mman.buffer_funcs = &cik_sdma_buffer_funcs;
+ adev->mman.buffer_funcs_ring = &adev->sdma[0].ring;
+ }
+}
+
+static const struct amdgpu_vm_pte_funcs cik_sdma_vm_pte_funcs = {
+ .copy_pte = cik_sdma_vm_copy_pte,
+ .write_pte = cik_sdma_vm_write_pte,
+ .set_pte_pde = cik_sdma_vm_set_pte_pde,
+ .pad_ib = cik_sdma_vm_pad_ib,
+};
+
+static void cik_sdma_set_vm_pte_funcs(struct amdgpu_device *adev)
+{
+ if (adev->vm_manager.vm_pte_funcs == NULL) {
+ adev->vm_manager.vm_pte_funcs = &cik_sdma_vm_pte_funcs;
+ adev->vm_manager.vm_pte_funcs_ring = &adev->sdma[0].ring;
+ }
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.h b/drivers/gpu/drm/amd/amdgpu/cik_sdma.h
new file mode 100644
index 000000000000..027727c677b8
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __CIK_SDMA_H__
+#define __CIK_SDMA_H__
+
+extern const struct amd_ip_funcs cik_sdma_ip_funcs;
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/cikd.h b/drivers/gpu/drm/amd/amdgpu/cikd.h
new file mode 100644
index 000000000000..220865a44814
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cikd.h
@@ -0,0 +1,555 @@
+/*
+ * Copyright 2012 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: Alex Deucher
+ */
+#ifndef CIK_H
+#define CIK_H
+
+#define MC_SEQ_MISC0__MT__MASK 0xf0000000
+#define MC_SEQ_MISC0__MT__GDDR1 0x10000000
+#define MC_SEQ_MISC0__MT__DDR2 0x20000000
+#define MC_SEQ_MISC0__MT__GDDR3 0x30000000
+#define MC_SEQ_MISC0__MT__GDDR4 0x40000000
+#define MC_SEQ_MISC0__MT__GDDR5 0x50000000
+#define MC_SEQ_MISC0__MT__HBM 0x60000000
+#define MC_SEQ_MISC0__MT__DDR3 0xB0000000
+
+#define CP_ME_TABLE_SIZE 96
+
+/* display controller offsets used for crtc/cur/lut/grph/viewport/etc. */
+#define CRTC0_REGISTER_OFFSET (0x1b7c - 0x1b7c)
+#define CRTC1_REGISTER_OFFSET (0x1e7c - 0x1b7c)
+#define CRTC2_REGISTER_OFFSET (0x417c - 0x1b7c)
+#define CRTC3_REGISTER_OFFSET (0x447c - 0x1b7c)
+#define CRTC4_REGISTER_OFFSET (0x477c - 0x1b7c)
+#define CRTC5_REGISTER_OFFSET (0x4a7c - 0x1b7c)
+
+#define BONAIRE_GB_ADDR_CONFIG_GOLDEN 0x12010001
+#define HAWAII_GB_ADDR_CONFIG_GOLDEN 0x12011003
+
+#define CIK_RB_BITMAP_WIDTH_PER_SH 2
+#define HAWAII_RB_BITMAP_WIDTH_PER_SH 4
+
+#define AMDGPU_NUM_OF_VMIDS 8
+
+#define PIPEID(x) ((x) << 0)
+#define MEID(x) ((x) << 2)
+#define VMID(x) ((x) << 4)
+#define QUEUEID(x) ((x) << 8)
+
+#define mmCC_DRM_ID_STRAPS 0x1559
+#define CC_DRM_ID_STRAPS__ATI_REV_ID_MASK 0xf0000000
+
+#define mmCHUB_CONTROL 0x619
+#define BYPASS_VM (1 << 0)
+
+#define SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU (0 << 5)
+
+#define mmGRPH_LUT_10BIT_BYPASS_CONTROL 0x1a02
+#define LUT_10BIT_BYPASS_EN (1 << 8)
+
+# define CURSOR_MONO 0
+# define CURSOR_24_1 1
+# define CURSOR_24_8_PRE_MULT 2
+# define CURSOR_24_8_UNPRE_MULT 3
+# define CURSOR_URGENT_ALWAYS 0
+# define CURSOR_URGENT_1_8 1
+# define CURSOR_URGENT_1_4 2
+# define CURSOR_URGENT_3_8 3
+# define CURSOR_URGENT_1_2 4
+
+# define GRPH_DEPTH_8BPP 0
+# define GRPH_DEPTH_16BPP 1
+# define GRPH_DEPTH_32BPP 2
+/* 8 BPP */
+# define GRPH_FORMAT_INDEXED 0
+/* 16 BPP */
+# define GRPH_FORMAT_ARGB1555 0
+# define GRPH_FORMAT_ARGB565 1
+# define GRPH_FORMAT_ARGB4444 2
+# define GRPH_FORMAT_AI88 3
+# define GRPH_FORMAT_MONO16 4
+# define GRPH_FORMAT_BGRA5551 5
+/* 32 BPP */
+# define GRPH_FORMAT_ARGB8888 0
+# define GRPH_FORMAT_ARGB2101010 1
+# define GRPH_FORMAT_32BPP_DIG 2
+# define GRPH_FORMAT_8B_ARGB2101010 3
+# define GRPH_FORMAT_BGRA1010102 4
+# define GRPH_FORMAT_8B_BGRA1010102 5
+# define GRPH_FORMAT_RGB111110 6
+# define GRPH_FORMAT_BGR101111 7
+# define ADDR_SURF_MACRO_TILE_ASPECT_1 0
+# define ADDR_SURF_MACRO_TILE_ASPECT_2 1
+# define ADDR_SURF_MACRO_TILE_ASPECT_4 2
+# define ADDR_SURF_MACRO_TILE_ASPECT_8 3
+# define GRPH_ARRAY_LINEAR_GENERAL 0
+# define GRPH_ARRAY_LINEAR_ALIGNED 1
+# define GRPH_ARRAY_1D_TILED_THIN1 2
+# define GRPH_ARRAY_2D_TILED_THIN1 4
+# define DISPLAY_MICRO_TILING 0
+# define THIN_MICRO_TILING 1
+# define DEPTH_MICRO_TILING 2
+# define ROTATED_MICRO_TILING 4
+# define GRPH_ENDIAN_NONE 0
+# define GRPH_ENDIAN_8IN16 1
+# define GRPH_ENDIAN_8IN32 2
+# define GRPH_ENDIAN_8IN64 3
+# define GRPH_RED_SEL_R 0
+# define GRPH_RED_SEL_G 1
+# define GRPH_RED_SEL_B 2
+# define GRPH_RED_SEL_A 3
+# define GRPH_GREEN_SEL_G 0
+# define GRPH_GREEN_SEL_B 1
+# define GRPH_GREEN_SEL_A 2
+# define GRPH_GREEN_SEL_R 3
+# define GRPH_BLUE_SEL_B 0
+# define GRPH_BLUE_SEL_A 1
+# define GRPH_BLUE_SEL_R 2
+# define GRPH_BLUE_SEL_G 3
+# define GRPH_ALPHA_SEL_A 0
+# define GRPH_ALPHA_SEL_R 1
+# define GRPH_ALPHA_SEL_G 2
+# define GRPH_ALPHA_SEL_B 3
+# define INPUT_GAMMA_USE_LUT 0
+# define INPUT_GAMMA_BYPASS 1
+# define INPUT_GAMMA_SRGB_24 2
+# define INPUT_GAMMA_XVYCC_222 3
+
+# define INPUT_CSC_BYPASS 0
+# define INPUT_CSC_PROG_COEFF 1
+# define INPUT_CSC_PROG_SHARED_MATRIXA 2
+
+# define OUTPUT_CSC_BYPASS 0
+# define OUTPUT_CSC_TV_RGB 1
+# define OUTPUT_CSC_YCBCR_601 2
+# define OUTPUT_CSC_YCBCR_709 3
+# define OUTPUT_CSC_PROG_COEFF 4
+# define OUTPUT_CSC_PROG_SHARED_MATRIXB 5
+
+# define DEGAMMA_BYPASS 0
+# define DEGAMMA_SRGB_24 1
+# define DEGAMMA_XVYCC_222 2
+# define GAMUT_REMAP_BYPASS 0
+# define GAMUT_REMAP_PROG_COEFF 1
+# define GAMUT_REMAP_PROG_SHARED_MATRIXA 2
+# define GAMUT_REMAP_PROG_SHARED_MATRIXB 3
+
+# define REGAMMA_BYPASS 0
+# define REGAMMA_SRGB_24 1
+# define REGAMMA_XVYCC_222 2
+# define REGAMMA_PROG_A 3
+# define REGAMMA_PROG_B 4
+
+# define FMT_CLAMP_6BPC 0
+# define FMT_CLAMP_8BPC 1
+# define FMT_CLAMP_10BPC 2
+
+# define HDMI_24BIT_DEEP_COLOR 0
+# define HDMI_30BIT_DEEP_COLOR 1
+# define HDMI_36BIT_DEEP_COLOR 2
+# define HDMI_ACR_HW 0
+# define HDMI_ACR_32 1
+# define HDMI_ACR_44 2
+# define HDMI_ACR_48 3
+# define HDMI_ACR_X1 1
+# define HDMI_ACR_X2 2
+# define HDMI_ACR_X4 4
+# define AFMT_AVI_INFO_Y_RGB 0
+# define AFMT_AVI_INFO_Y_YCBCR422 1
+# define AFMT_AVI_INFO_Y_YCBCR444 2
+
+#define NO_AUTO 0
+#define ES_AUTO 1
+#define GS_AUTO 2
+#define ES_AND_GS_AUTO 3
+
+# define ARRAY_MODE(x) ((x) << 2)
+# define PIPE_CONFIG(x) ((x) << 6)
+# define TILE_SPLIT(x) ((x) << 11)
+# define MICRO_TILE_MODE_NEW(x) ((x) << 22)
+# define SAMPLE_SPLIT(x) ((x) << 25)
+# define BANK_WIDTH(x) ((x) << 0)
+# define BANK_HEIGHT(x) ((x) << 2)
+# define MACRO_TILE_ASPECT(x) ((x) << 4)
+# define NUM_BANKS(x) ((x) << 6)
+
+#define MSG_ENTER_RLC_SAFE_MODE 1
+#define MSG_EXIT_RLC_SAFE_MODE 0
+
+/*
+ * PM4
+ */
+#define PACKET_TYPE0 0
+#define PACKET_TYPE1 1
+#define PACKET_TYPE2 2
+#define PACKET_TYPE3 3
+
+#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3)
+#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF)
+#define CP_PACKET0_GET_REG(h) ((h) & 0xFFFF)
+#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF)
+#define PACKET0(reg, n) ((PACKET_TYPE0 << 30) | \
+ ((reg) & 0xFFFF) | \
+ ((n) & 0x3FFF) << 16)
+#define CP_PACKET2 0x80000000
+#define PACKET2_PAD_SHIFT 0
+#define PACKET2_PAD_MASK (0x3fffffff << 0)
+
+#define PACKET2(v) (CP_PACKET2 | REG_SET(PACKET2_PAD, (v)))
+
+#define PACKET3(op, n) ((PACKET_TYPE3 << 30) | \
+ (((op) & 0xFF) << 8) | \
+ ((n) & 0x3FFF) << 16)
+
+#define PACKET3_COMPUTE(op, n) (PACKET3(op, n) | 1 << 1)
+
+/* Packet 3 types */
+#define PACKET3_NOP 0x10
+#define PACKET3_SET_BASE 0x11
+#define PACKET3_BASE_INDEX(x) ((x) << 0)
+#define CE_PARTITION_BASE 3
+#define PACKET3_CLEAR_STATE 0x12
+#define PACKET3_INDEX_BUFFER_SIZE 0x13
+#define PACKET3_DISPATCH_DIRECT 0x15
+#define PACKET3_DISPATCH_INDIRECT 0x16
+#define PACKET3_ATOMIC_GDS 0x1D
+#define PACKET3_ATOMIC_MEM 0x1E
+#define PACKET3_OCCLUSION_QUERY 0x1F
+#define PACKET3_SET_PREDICATION 0x20
+#define PACKET3_REG_RMW 0x21
+#define PACKET3_COND_EXEC 0x22
+#define PACKET3_PRED_EXEC 0x23
+#define PACKET3_DRAW_INDIRECT 0x24
+#define PACKET3_DRAW_INDEX_INDIRECT 0x25
+#define PACKET3_INDEX_BASE 0x26
+#define PACKET3_DRAW_INDEX_2 0x27
+#define PACKET3_CONTEXT_CONTROL 0x28
+#define PACKET3_INDEX_TYPE 0x2A
+#define PACKET3_DRAW_INDIRECT_MULTI 0x2C
+#define PACKET3_DRAW_INDEX_AUTO 0x2D
+#define PACKET3_NUM_INSTANCES 0x2F
+#define PACKET3_DRAW_INDEX_MULTI_AUTO 0x30
+#define PACKET3_INDIRECT_BUFFER_CONST 0x33
+#define PACKET3_STRMOUT_BUFFER_UPDATE 0x34
+#define PACKET3_DRAW_INDEX_OFFSET_2 0x35
+#define PACKET3_DRAW_PREAMBLE 0x36
+#define PACKET3_WRITE_DATA 0x37
+#define WRITE_DATA_DST_SEL(x) ((x) << 8)
+ /* 0 - register
+ * 1 - memory (sync - via GRBM)
+ * 2 - gl2
+ * 3 - gds
+ * 4 - reserved
+ * 5 - memory (async - direct)
+ */
+#define WR_ONE_ADDR (1 << 16)
+#define WR_CONFIRM (1 << 20)
+#define WRITE_DATA_CACHE_POLICY(x) ((x) << 25)
+ /* 0 - LRU
+ * 1 - Stream
+ */
+#define WRITE_DATA_ENGINE_SEL(x) ((x) << 30)
+ /* 0 - me
+ * 1 - pfp
+ * 2 - ce
+ */
+#define PACKET3_DRAW_INDEX_INDIRECT_MULTI 0x38
+#define PACKET3_MEM_SEMAPHORE 0x39
+# define PACKET3_SEM_USE_MAILBOX (0x1 << 16)
+# define PACKET3_SEM_SEL_SIGNAL_TYPE (0x1 << 20) /* 0 = increment, 1 = write 1 */
+# define PACKET3_SEM_CLIENT_CODE ((x) << 24) /* 0 = CP, 1 = CB, 2 = DB */
+# define PACKET3_SEM_SEL_SIGNAL (0x6 << 29)
+# define PACKET3_SEM_SEL_WAIT (0x7 << 29)
+#define PACKET3_COPY_DW 0x3B
+#define PACKET3_WAIT_REG_MEM 0x3C
+#define WAIT_REG_MEM_FUNCTION(x) ((x) << 0)
+ /* 0 - always
+ * 1 - <
+ * 2 - <=
+ * 3 - ==
+ * 4 - !=
+ * 5 - >=
+ * 6 - >
+ */
+#define WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4)
+ /* 0 - reg
+ * 1 - mem
+ */
+#define WAIT_REG_MEM_OPERATION(x) ((x) << 6)
+ /* 0 - wait_reg_mem
+ * 1 - wr_wait_wr_reg
+ */
+#define WAIT_REG_MEM_ENGINE(x) ((x) << 8)
+ /* 0 - me
+ * 1 - pfp
+ */
+#define PACKET3_INDIRECT_BUFFER 0x3F
+#define INDIRECT_BUFFER_TCL2_VOLATILE (1 << 22)
+#define INDIRECT_BUFFER_VALID (1 << 23)
+#define INDIRECT_BUFFER_CACHE_POLICY(x) ((x) << 28)
+ /* 0 - LRU
+ * 1 - Stream
+ * 2 - Bypass
+ */
+#define PACKET3_COPY_DATA 0x40
+#define PACKET3_PFP_SYNC_ME 0x42
+#define PACKET3_SURFACE_SYNC 0x43
+# define PACKET3_DEST_BASE_0_ENA (1 << 0)
+# define PACKET3_DEST_BASE_1_ENA (1 << 1)
+# define PACKET3_CB0_DEST_BASE_ENA (1 << 6)
+# define PACKET3_CB1_DEST_BASE_ENA (1 << 7)
+# define PACKET3_CB2_DEST_BASE_ENA (1 << 8)
+# define PACKET3_CB3_DEST_BASE_ENA (1 << 9)
+# define PACKET3_CB4_DEST_BASE_ENA (1 << 10)
+# define PACKET3_CB5_DEST_BASE_ENA (1 << 11)
+# define PACKET3_CB6_DEST_BASE_ENA (1 << 12)
+# define PACKET3_CB7_DEST_BASE_ENA (1 << 13)
+# define PACKET3_DB_DEST_BASE_ENA (1 << 14)
+# define PACKET3_TCL1_VOL_ACTION_ENA (1 << 15)
+# define PACKET3_TC_VOL_ACTION_ENA (1 << 16) /* L2 */
+# define PACKET3_TC_WB_ACTION_ENA (1 << 18) /* L2 */
+# define PACKET3_DEST_BASE_2_ENA (1 << 19)
+# define PACKET3_DEST_BASE_3_ENA (1 << 21)
+# define PACKET3_TCL1_ACTION_ENA (1 << 22)
+# define PACKET3_TC_ACTION_ENA (1 << 23) /* L2 */
+# define PACKET3_CB_ACTION_ENA (1 << 25)
+# define PACKET3_DB_ACTION_ENA (1 << 26)
+# define PACKET3_SH_KCACHE_ACTION_ENA (1 << 27)
+# define PACKET3_SH_KCACHE_VOL_ACTION_ENA (1 << 28)
+# define PACKET3_SH_ICACHE_ACTION_ENA (1 << 29)
+#define PACKET3_COND_WRITE 0x45
+#define PACKET3_EVENT_WRITE 0x46
+#define EVENT_TYPE(x) ((x) << 0)
+#define EVENT_INDEX(x) ((x) << 8)
+ /* 0 - any non-TS event
+ * 1 - ZPASS_DONE, PIXEL_PIPE_STAT_*
+ * 2 - SAMPLE_PIPELINESTAT
+ * 3 - SAMPLE_STREAMOUTSTAT*
+ * 4 - *S_PARTIAL_FLUSH
+ * 5 - EOP events
+ * 6 - EOS events
+ */
+#define PACKET3_EVENT_WRITE_EOP 0x47
+#define EOP_TCL1_VOL_ACTION_EN (1 << 12)
+#define EOP_TC_VOL_ACTION_EN (1 << 13) /* L2 */
+#define EOP_TC_WB_ACTION_EN (1 << 15) /* L2 */
+#define EOP_TCL1_ACTION_EN (1 << 16)
+#define EOP_TC_ACTION_EN (1 << 17) /* L2 */
+#define EOP_TCL2_VOLATILE (1 << 24)
+#define EOP_CACHE_POLICY(x) ((x) << 25)
+ /* 0 - LRU
+ * 1 - Stream
+ * 2 - Bypass
+ */
+#define DATA_SEL(x) ((x) << 29)
+ /* 0 - discard
+ * 1 - send low 32bit data
+ * 2 - send 64bit data
+ * 3 - send 64bit GPU counter value
+ * 4 - send 64bit sys counter value
+ */
+#define INT_SEL(x) ((x) << 24)
+ /* 0 - none
+ * 1 - interrupt only (DATA_SEL = 0)
+ * 2 - interrupt when data write is confirmed
+ */
+#define DST_SEL(x) ((x) << 16)
+ /* 0 - MC
+ * 1 - TC/L2
+ */
+#define PACKET3_EVENT_WRITE_EOS 0x48
+#define PACKET3_RELEASE_MEM 0x49
+#define PACKET3_PREAMBLE_CNTL 0x4A
+# define PACKET3_PREAMBLE_BEGIN_CLEAR_STATE (2 << 28)
+# define PACKET3_PREAMBLE_END_CLEAR_STATE (3 << 28)
+#define PACKET3_DMA_DATA 0x50
+/* 1. header
+ * 2. CONTROL
+ * 3. SRC_ADDR_LO or DATA [31:0]
+ * 4. SRC_ADDR_HI [31:0]
+ * 5. DST_ADDR_LO [31:0]
+ * 6. DST_ADDR_HI [7:0]
+ * 7. COMMAND [30:21] | BYTE_COUNT [20:0]
+ */
+/* CONTROL */
+# define PACKET3_DMA_DATA_ENGINE(x) ((x) << 0)
+ /* 0 - ME
+ * 1 - PFP
+ */
+# define PACKET3_DMA_DATA_SRC_CACHE_POLICY(x) ((x) << 13)
+ /* 0 - LRU
+ * 1 - Stream
+ * 2 - Bypass
+ */
+# define PACKET3_DMA_DATA_SRC_VOLATILE (1 << 15)
+# define PACKET3_DMA_DATA_DST_SEL(x) ((x) << 20)
+ /* 0 - DST_ADDR using DAS
+ * 1 - GDS
+ * 3 - DST_ADDR using L2
+ */
+# define PACKET3_DMA_DATA_DST_CACHE_POLICY(x) ((x) << 25)
+ /* 0 - LRU
+ * 1 - Stream
+ * 2 - Bypass
+ */
+# define PACKET3_DMA_DATA_DST_VOLATILE (1 << 27)
+# define PACKET3_DMA_DATA_SRC_SEL(x) ((x) << 29)
+ /* 0 - SRC_ADDR using SAS
+ * 1 - GDS
+ * 2 - DATA
+ * 3 - SRC_ADDR using L2
+ */
+# define PACKET3_DMA_DATA_CP_SYNC (1 << 31)
+/* COMMAND */
+# define PACKET3_DMA_DATA_DIS_WC (1 << 21)
+# define PACKET3_DMA_DATA_CMD_SRC_SWAP(x) ((x) << 22)
+ /* 0 - none
+ * 1 - 8 in 16
+ * 2 - 8 in 32
+ * 3 - 8 in 64
+ */
+# define PACKET3_DMA_DATA_CMD_DST_SWAP(x) ((x) << 24)
+ /* 0 - none
+ * 1 - 8 in 16
+ * 2 - 8 in 32
+ * 3 - 8 in 64
+ */
+# define PACKET3_DMA_DATA_CMD_SAS (1 << 26)
+ /* 0 - memory
+ * 1 - register
+ */
+# define PACKET3_DMA_DATA_CMD_DAS (1 << 27)
+ /* 0 - memory
+ * 1 - register
+ */
+# define PACKET3_DMA_DATA_CMD_SAIC (1 << 28)
+# define PACKET3_DMA_DATA_CMD_DAIC (1 << 29)
+# define PACKET3_DMA_DATA_CMD_RAW_WAIT (1 << 30)
+#define PACKET3_AQUIRE_MEM 0x58
+#define PACKET3_REWIND 0x59
+#define PACKET3_LOAD_UCONFIG_REG 0x5E
+#define PACKET3_LOAD_SH_REG 0x5F
+#define PACKET3_LOAD_CONFIG_REG 0x60
+#define PACKET3_LOAD_CONTEXT_REG 0x61
+#define PACKET3_SET_CONFIG_REG 0x68
+#define PACKET3_SET_CONFIG_REG_START 0x00002000
+#define PACKET3_SET_CONFIG_REG_END 0x00002c00
+#define PACKET3_SET_CONTEXT_REG 0x69
+#define PACKET3_SET_CONTEXT_REG_START 0x0000a000
+#define PACKET3_SET_CONTEXT_REG_END 0x0000a400
+#define PACKET3_SET_CONTEXT_REG_INDIRECT 0x73
+#define PACKET3_SET_SH_REG 0x76
+#define PACKET3_SET_SH_REG_START 0x00002c00
+#define PACKET3_SET_SH_REG_END 0x00003000
+#define PACKET3_SET_SH_REG_OFFSET 0x77
+#define PACKET3_SET_QUEUE_REG 0x78
+#define PACKET3_SET_UCONFIG_REG 0x79
+#define PACKET3_SET_UCONFIG_REG_START 0x0000c000
+#define PACKET3_SET_UCONFIG_REG_END 0x0000c400
+#define PACKET3_SCRATCH_RAM_WRITE 0x7D
+#define PACKET3_SCRATCH_RAM_READ 0x7E
+#define PACKET3_LOAD_CONST_RAM 0x80
+#define PACKET3_WRITE_CONST_RAM 0x81
+#define PACKET3_DUMP_CONST_RAM 0x83
+#define PACKET3_INCREMENT_CE_COUNTER 0x84
+#define PACKET3_INCREMENT_DE_COUNTER 0x85
+#define PACKET3_WAIT_ON_CE_COUNTER 0x86
+#define PACKET3_WAIT_ON_DE_COUNTER_DIFF 0x88
+#define PACKET3_SWITCH_BUFFER 0x8B
+
+/* SDMA - first instance at 0xd000, second at 0xd800 */
+#define SDMA0_REGISTER_OFFSET 0x0 /* not a register */
+#define SDMA1_REGISTER_OFFSET 0x200 /* not a register */
+#define SDMA_MAX_INSTANCE 2
+
+#define SDMA_PACKET(op, sub_op, e) ((((e) & 0xFFFF) << 16) | \
+ (((sub_op) & 0xFF) << 8) | \
+ (((op) & 0xFF) << 0))
+/* sDMA opcodes */
+#define SDMA_OPCODE_NOP 0
+#define SDMA_OPCODE_COPY 1
+# define SDMA_COPY_SUB_OPCODE_LINEAR 0
+# define SDMA_COPY_SUB_OPCODE_TILED 1
+# define SDMA_COPY_SUB_OPCODE_SOA 3
+# define SDMA_COPY_SUB_OPCODE_LINEAR_SUB_WINDOW 4
+# define SDMA_COPY_SUB_OPCODE_TILED_SUB_WINDOW 5
+# define SDMA_COPY_SUB_OPCODE_T2T_SUB_WINDOW 6
+#define SDMA_OPCODE_WRITE 2
+# define SDMA_WRITE_SUB_OPCODE_LINEAR 0
+# define SDMA_WRTIE_SUB_OPCODE_TILED 1
+#define SDMA_OPCODE_INDIRECT_BUFFER 4
+#define SDMA_OPCODE_FENCE 5
+#define SDMA_OPCODE_TRAP 6
+#define SDMA_OPCODE_SEMAPHORE 7
+# define SDMA_SEMAPHORE_EXTRA_O (1 << 13)
+ /* 0 - increment
+ * 1 - write 1
+ */
+# define SDMA_SEMAPHORE_EXTRA_S (1 << 14)
+ /* 0 - wait
+ * 1 - signal
+ */
+# define SDMA_SEMAPHORE_EXTRA_M (1 << 15)
+ /* mailbox */
+#define SDMA_OPCODE_POLL_REG_MEM 8
+# define SDMA_POLL_REG_MEM_EXTRA_OP(x) ((x) << 10)
+ /* 0 - wait_reg_mem
+ * 1 - wr_wait_wr_reg
+ */
+# define SDMA_POLL_REG_MEM_EXTRA_FUNC(x) ((x) << 12)
+ /* 0 - always
+ * 1 - <
+ * 2 - <=
+ * 3 - ==
+ * 4 - !=
+ * 5 - >=
+ * 6 - >
+ */
+# define SDMA_POLL_REG_MEM_EXTRA_M (1 << 15)
+ /* 0 = register
+ * 1 = memory
+ */
+#define SDMA_OPCODE_COND_EXEC 9
+#define SDMA_OPCODE_CONSTANT_FILL 11
+# define SDMA_CONSTANT_FILL_EXTRA_SIZE(x) ((x) << 14)
+ /* 0 = byte fill
+ * 2 = DW fill
+ */
+#define SDMA_OPCODE_GENERATE_PTE_PDE 12
+#define SDMA_OPCODE_TIMESTAMP 13
+# define SDMA_TIMESTAMP_SUB_OPCODE_SET_LOCAL 0
+# define SDMA_TIMESTAMP_SUB_OPCODE_GET_LOCAL 1
+# define SDMA_TIMESTAMP_SUB_OPCODE_GET_GLOBAL 2
+#define SDMA_OPCODE_SRBM_WRITE 14
+# define SDMA_SRBM_WRITE_EXTRA_BYTE_ENABLE(x) ((x) << 12)
+ /* byte mask */
+
+#define VCE_CMD_NO_OP 0x00000000
+#define VCE_CMD_END 0x00000001
+#define VCE_CMD_IB 0x00000002
+#define VCE_CMD_FENCE 0x00000003
+#define VCE_CMD_TRAP 0x00000004
+#define VCE_CMD_IB_AUTO 0x00000005
+#define VCE_CMD_SEMAPHORE 0x00000006
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/clearstate_ci.h b/drivers/gpu/drm/amd/amdgpu/clearstate_ci.h
new file mode 100644
index 000000000000..c3982f9475fb
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/clearstate_ci.h
@@ -0,0 +1,944 @@
+/*
+ * Copyright 2013 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.
+ *
+ */
+
+static const unsigned int ci_SECT_CONTEXT_def_1[] =
+{
+ 0x00000000, // DB_RENDER_CONTROL
+ 0x00000000, // DB_COUNT_CONTROL
+ 0x00000000, // DB_DEPTH_VIEW
+ 0x00000000, // DB_RENDER_OVERRIDE
+ 0x00000000, // DB_RENDER_OVERRIDE2
+ 0x00000000, // DB_HTILE_DATA_BASE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // DB_DEPTH_BOUNDS_MIN
+ 0x00000000, // DB_DEPTH_BOUNDS_MAX
+ 0x00000000, // DB_STENCIL_CLEAR
+ 0x00000000, // DB_DEPTH_CLEAR
+ 0x00000000, // PA_SC_SCREEN_SCISSOR_TL
+ 0x40004000, // PA_SC_SCREEN_SCISSOR_BR
+ 0, // HOLE
+ 0x00000000, // DB_DEPTH_INFO
+ 0x00000000, // DB_Z_INFO
+ 0x00000000, // DB_STENCIL_INFO
+ 0x00000000, // DB_Z_READ_BASE
+ 0x00000000, // DB_STENCIL_READ_BASE
+ 0x00000000, // DB_Z_WRITE_BASE
+ 0x00000000, // DB_STENCIL_WRITE_BASE
+ 0x00000000, // DB_DEPTH_SIZE
+ 0x00000000, // DB_DEPTH_SLICE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // TA_BC_BASE_ADDR
+ 0x00000000, // TA_BC_BASE_ADDR_HI
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // COHER_DEST_BASE_HI_0
+ 0x00000000, // COHER_DEST_BASE_HI_1
+ 0x00000000, // COHER_DEST_BASE_HI_2
+ 0x00000000, // COHER_DEST_BASE_HI_3
+ 0x00000000, // COHER_DEST_BASE_2
+ 0x00000000, // COHER_DEST_BASE_3
+ 0x00000000, // PA_SC_WINDOW_OFFSET
+ 0x80000000, // PA_SC_WINDOW_SCISSOR_TL
+ 0x40004000, // PA_SC_WINDOW_SCISSOR_BR
+ 0x0000ffff, // PA_SC_CLIPRECT_RULE
+ 0x00000000, // PA_SC_CLIPRECT_0_TL
+ 0x40004000, // PA_SC_CLIPRECT_0_BR
+ 0x00000000, // PA_SC_CLIPRECT_1_TL
+ 0x40004000, // PA_SC_CLIPRECT_1_BR
+ 0x00000000, // PA_SC_CLIPRECT_2_TL
+ 0x40004000, // PA_SC_CLIPRECT_2_BR
+ 0x00000000, // PA_SC_CLIPRECT_3_TL
+ 0x40004000, // PA_SC_CLIPRECT_3_BR
+ 0xaa99aaaa, // PA_SC_EDGERULE
+ 0x00000000, // PA_SU_HARDWARE_SCREEN_OFFSET
+ 0xffffffff, // CB_TARGET_MASK
+ 0xffffffff, // CB_SHADER_MASK
+ 0x80000000, // PA_SC_GENERIC_SCISSOR_TL
+ 0x40004000, // PA_SC_GENERIC_SCISSOR_BR
+ 0x00000000, // COHER_DEST_BASE_0
+ 0x00000000, // COHER_DEST_BASE_1
+ 0x80000000, // PA_SC_VPORT_SCISSOR_0_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_0_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_1_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_1_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_2_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_2_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_3_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_3_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_4_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_4_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_5_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_5_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_6_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_6_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_7_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_7_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_8_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_8_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_9_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_9_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_10_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_10_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_11_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_11_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_12_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_12_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_13_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_13_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_14_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_14_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_15_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_15_BR
+ 0x00000000, // PA_SC_VPORT_ZMIN_0
+ 0x3f800000, // PA_SC_VPORT_ZMAX_0
+ 0x00000000, // PA_SC_VPORT_ZMIN_1
+ 0x3f800000, // PA_SC_VPORT_ZMAX_1
+ 0x00000000, // PA_SC_VPORT_ZMIN_2
+ 0x3f800000, // PA_SC_VPORT_ZMAX_2
+ 0x00000000, // PA_SC_VPORT_ZMIN_3
+ 0x3f800000, // PA_SC_VPORT_ZMAX_3
+ 0x00000000, // PA_SC_VPORT_ZMIN_4
+ 0x3f800000, // PA_SC_VPORT_ZMAX_4
+ 0x00000000, // PA_SC_VPORT_ZMIN_5
+ 0x3f800000, // PA_SC_VPORT_ZMAX_5
+ 0x00000000, // PA_SC_VPORT_ZMIN_6
+ 0x3f800000, // PA_SC_VPORT_ZMAX_6
+ 0x00000000, // PA_SC_VPORT_ZMIN_7
+ 0x3f800000, // PA_SC_VPORT_ZMAX_7
+ 0x00000000, // PA_SC_VPORT_ZMIN_8
+ 0x3f800000, // PA_SC_VPORT_ZMAX_8
+ 0x00000000, // PA_SC_VPORT_ZMIN_9
+ 0x3f800000, // PA_SC_VPORT_ZMAX_9
+ 0x00000000, // PA_SC_VPORT_ZMIN_10
+ 0x3f800000, // PA_SC_VPORT_ZMAX_10
+ 0x00000000, // PA_SC_VPORT_ZMIN_11
+ 0x3f800000, // PA_SC_VPORT_ZMAX_11
+ 0x00000000, // PA_SC_VPORT_ZMIN_12
+ 0x3f800000, // PA_SC_VPORT_ZMAX_12
+ 0x00000000, // PA_SC_VPORT_ZMIN_13
+ 0x3f800000, // PA_SC_VPORT_ZMAX_13
+ 0x00000000, // PA_SC_VPORT_ZMIN_14
+ 0x3f800000, // PA_SC_VPORT_ZMAX_14
+ 0x00000000, // PA_SC_VPORT_ZMIN_15
+ 0x3f800000, // PA_SC_VPORT_ZMAX_15
+};
+static const unsigned int ci_SECT_CONTEXT_def_2[] =
+{
+ 0x00000000, // PA_SC_SCREEN_EXTENT_CONTROL
+ 0, // HOLE
+ 0x00000000, // CP_PERFMON_CNTX_CNTL
+ 0x00000000, // CP_RINGID
+ 0x00000000, // CP_VMID
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0xffffffff, // VGT_MAX_VTX_INDX
+ 0x00000000, // VGT_MIN_VTX_INDX
+ 0x00000000, // VGT_INDX_OFFSET
+ 0x00000000, // VGT_MULTI_PRIM_IB_RESET_INDX
+ 0, // HOLE
+ 0x00000000, // CB_BLEND_RED
+ 0x00000000, // CB_BLEND_GREEN
+ 0x00000000, // CB_BLEND_BLUE
+ 0x00000000, // CB_BLEND_ALPHA
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // DB_STENCIL_CONTROL
+ 0x00000000, // DB_STENCILREFMASK
+ 0x00000000, // DB_STENCILREFMASK_BF
+ 0, // HOLE
+ 0x00000000, // PA_CL_VPORT_XSCALE
+ 0x00000000, // PA_CL_VPORT_XOFFSET
+ 0x00000000, // PA_CL_VPORT_YSCALE
+ 0x00000000, // PA_CL_VPORT_YOFFSET
+ 0x00000000, // PA_CL_VPORT_ZSCALE
+ 0x00000000, // PA_CL_VPORT_ZOFFSET
+ 0x00000000, // PA_CL_VPORT_XSCALE_1
+ 0x00000000, // PA_CL_VPORT_XOFFSET_1
+ 0x00000000, // PA_CL_VPORT_YSCALE_1
+ 0x00000000, // PA_CL_VPORT_YOFFSET_1
+ 0x00000000, // PA_CL_VPORT_ZSCALE_1
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_1
+ 0x00000000, // PA_CL_VPORT_XSCALE_2
+ 0x00000000, // PA_CL_VPORT_XOFFSET_2
+ 0x00000000, // PA_CL_VPORT_YSCALE_2
+ 0x00000000, // PA_CL_VPORT_YOFFSET_2
+ 0x00000000, // PA_CL_VPORT_ZSCALE_2
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_2
+ 0x00000000, // PA_CL_VPORT_XSCALE_3
+ 0x00000000, // PA_CL_VPORT_XOFFSET_3
+ 0x00000000, // PA_CL_VPORT_YSCALE_3
+ 0x00000000, // PA_CL_VPORT_YOFFSET_3
+ 0x00000000, // PA_CL_VPORT_ZSCALE_3
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_3
+ 0x00000000, // PA_CL_VPORT_XSCALE_4
+ 0x00000000, // PA_CL_VPORT_XOFFSET_4
+ 0x00000000, // PA_CL_VPORT_YSCALE_4
+ 0x00000000, // PA_CL_VPORT_YOFFSET_4
+ 0x00000000, // PA_CL_VPORT_ZSCALE_4
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_4
+ 0x00000000, // PA_CL_VPORT_XSCALE_5
+ 0x00000000, // PA_CL_VPORT_XOFFSET_5
+ 0x00000000, // PA_CL_VPORT_YSCALE_5
+ 0x00000000, // PA_CL_VPORT_YOFFSET_5
+ 0x00000000, // PA_CL_VPORT_ZSCALE_5
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_5
+ 0x00000000, // PA_CL_VPORT_XSCALE_6
+ 0x00000000, // PA_CL_VPORT_XOFFSET_6
+ 0x00000000, // PA_CL_VPORT_YSCALE_6
+ 0x00000000, // PA_CL_VPORT_YOFFSET_6
+ 0x00000000, // PA_CL_VPORT_ZSCALE_6
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_6
+ 0x00000000, // PA_CL_VPORT_XSCALE_7
+ 0x00000000, // PA_CL_VPORT_XOFFSET_7
+ 0x00000000, // PA_CL_VPORT_YSCALE_7
+ 0x00000000, // PA_CL_VPORT_YOFFSET_7
+ 0x00000000, // PA_CL_VPORT_ZSCALE_7
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_7
+ 0x00000000, // PA_CL_VPORT_XSCALE_8
+ 0x00000000, // PA_CL_VPORT_XOFFSET_8
+ 0x00000000, // PA_CL_VPORT_YSCALE_8
+ 0x00000000, // PA_CL_VPORT_YOFFSET_8
+ 0x00000000, // PA_CL_VPORT_ZSCALE_8
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_8
+ 0x00000000, // PA_CL_VPORT_XSCALE_9
+ 0x00000000, // PA_CL_VPORT_XOFFSET_9
+ 0x00000000, // PA_CL_VPORT_YSCALE_9
+ 0x00000000, // PA_CL_VPORT_YOFFSET_9
+ 0x00000000, // PA_CL_VPORT_ZSCALE_9
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_9
+ 0x00000000, // PA_CL_VPORT_XSCALE_10
+ 0x00000000, // PA_CL_VPORT_XOFFSET_10
+ 0x00000000, // PA_CL_VPORT_YSCALE_10
+ 0x00000000, // PA_CL_VPORT_YOFFSET_10
+ 0x00000000, // PA_CL_VPORT_ZSCALE_10
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_10
+ 0x00000000, // PA_CL_VPORT_XSCALE_11
+ 0x00000000, // PA_CL_VPORT_XOFFSET_11
+ 0x00000000, // PA_CL_VPORT_YSCALE_11
+ 0x00000000, // PA_CL_VPORT_YOFFSET_11
+ 0x00000000, // PA_CL_VPORT_ZSCALE_11
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_11
+ 0x00000000, // PA_CL_VPORT_XSCALE_12
+ 0x00000000, // PA_CL_VPORT_XOFFSET_12
+ 0x00000000, // PA_CL_VPORT_YSCALE_12
+ 0x00000000, // PA_CL_VPORT_YOFFSET_12
+ 0x00000000, // PA_CL_VPORT_ZSCALE_12
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_12
+ 0x00000000, // PA_CL_VPORT_XSCALE_13
+ 0x00000000, // PA_CL_VPORT_XOFFSET_13
+ 0x00000000, // PA_CL_VPORT_YSCALE_13
+ 0x00000000, // PA_CL_VPORT_YOFFSET_13
+ 0x00000000, // PA_CL_VPORT_ZSCALE_13
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_13
+ 0x00000000, // PA_CL_VPORT_XSCALE_14
+ 0x00000000, // PA_CL_VPORT_XOFFSET_14
+ 0x00000000, // PA_CL_VPORT_YSCALE_14
+ 0x00000000, // PA_CL_VPORT_YOFFSET_14
+ 0x00000000, // PA_CL_VPORT_ZSCALE_14
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_14
+ 0x00000000, // PA_CL_VPORT_XSCALE_15
+ 0x00000000, // PA_CL_VPORT_XOFFSET_15
+ 0x00000000, // PA_CL_VPORT_YSCALE_15
+ 0x00000000, // PA_CL_VPORT_YOFFSET_15
+ 0x00000000, // PA_CL_VPORT_ZSCALE_15
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_15
+ 0x00000000, // PA_CL_UCP_0_X
+ 0x00000000, // PA_CL_UCP_0_Y
+ 0x00000000, // PA_CL_UCP_0_Z
+ 0x00000000, // PA_CL_UCP_0_W
+ 0x00000000, // PA_CL_UCP_1_X
+ 0x00000000, // PA_CL_UCP_1_Y
+ 0x00000000, // PA_CL_UCP_1_Z
+ 0x00000000, // PA_CL_UCP_1_W
+ 0x00000000, // PA_CL_UCP_2_X
+ 0x00000000, // PA_CL_UCP_2_Y
+ 0x00000000, // PA_CL_UCP_2_Z
+ 0x00000000, // PA_CL_UCP_2_W
+ 0x00000000, // PA_CL_UCP_3_X
+ 0x00000000, // PA_CL_UCP_3_Y
+ 0x00000000, // PA_CL_UCP_3_Z
+ 0x00000000, // PA_CL_UCP_3_W
+ 0x00000000, // PA_CL_UCP_4_X
+ 0x00000000, // PA_CL_UCP_4_Y
+ 0x00000000, // PA_CL_UCP_4_Z
+ 0x00000000, // PA_CL_UCP_4_W
+ 0x00000000, // PA_CL_UCP_5_X
+ 0x00000000, // PA_CL_UCP_5_Y
+ 0x00000000, // PA_CL_UCP_5_Z
+ 0x00000000, // PA_CL_UCP_5_W
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SPI_PS_INPUT_CNTL_0
+ 0x00000000, // SPI_PS_INPUT_CNTL_1
+ 0x00000000, // SPI_PS_INPUT_CNTL_2
+ 0x00000000, // SPI_PS_INPUT_CNTL_3
+ 0x00000000, // SPI_PS_INPUT_CNTL_4
+ 0x00000000, // SPI_PS_INPUT_CNTL_5
+ 0x00000000, // SPI_PS_INPUT_CNTL_6
+ 0x00000000, // SPI_PS_INPUT_CNTL_7
+ 0x00000000, // SPI_PS_INPUT_CNTL_8
+ 0x00000000, // SPI_PS_INPUT_CNTL_9
+ 0x00000000, // SPI_PS_INPUT_CNTL_10
+ 0x00000000, // SPI_PS_INPUT_CNTL_11
+ 0x00000000, // SPI_PS_INPUT_CNTL_12
+ 0x00000000, // SPI_PS_INPUT_CNTL_13
+ 0x00000000, // SPI_PS_INPUT_CNTL_14
+ 0x00000000, // SPI_PS_INPUT_CNTL_15
+ 0x00000000, // SPI_PS_INPUT_CNTL_16
+ 0x00000000, // SPI_PS_INPUT_CNTL_17
+ 0x00000000, // SPI_PS_INPUT_CNTL_18
+ 0x00000000, // SPI_PS_INPUT_CNTL_19
+ 0x00000000, // SPI_PS_INPUT_CNTL_20
+ 0x00000000, // SPI_PS_INPUT_CNTL_21
+ 0x00000000, // SPI_PS_INPUT_CNTL_22
+ 0x00000000, // SPI_PS_INPUT_CNTL_23
+ 0x00000000, // SPI_PS_INPUT_CNTL_24
+ 0x00000000, // SPI_PS_INPUT_CNTL_25
+ 0x00000000, // SPI_PS_INPUT_CNTL_26
+ 0x00000000, // SPI_PS_INPUT_CNTL_27
+ 0x00000000, // SPI_PS_INPUT_CNTL_28
+ 0x00000000, // SPI_PS_INPUT_CNTL_29
+ 0x00000000, // SPI_PS_INPUT_CNTL_30
+ 0x00000000, // SPI_PS_INPUT_CNTL_31
+ 0x00000000, // SPI_VS_OUT_CONFIG
+ 0, // HOLE
+ 0x00000000, // SPI_PS_INPUT_ENA
+ 0x00000000, // SPI_PS_INPUT_ADDR
+ 0x00000000, // SPI_INTERP_CONTROL_0
+ 0x00000002, // SPI_PS_IN_CONTROL
+ 0, // HOLE
+ 0x00000000, // SPI_BARYC_CNTL
+ 0, // HOLE
+ 0x00000000, // SPI_TMPRING_SIZE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SPI_SHADER_POS_FORMAT
+ 0x00000000, // SPI_SHADER_Z_FORMAT
+ 0x00000000, // SPI_SHADER_COL_FORMAT
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // CB_BLEND0_CONTROL
+ 0x00000000, // CB_BLEND1_CONTROL
+ 0x00000000, // CB_BLEND2_CONTROL
+ 0x00000000, // CB_BLEND3_CONTROL
+ 0x00000000, // CB_BLEND4_CONTROL
+ 0x00000000, // CB_BLEND5_CONTROL
+ 0x00000000, // CB_BLEND6_CONTROL
+ 0x00000000, // CB_BLEND7_CONTROL
+};
+static const unsigned int ci_SECT_CONTEXT_def_3[] =
+{
+ 0x00000000, // PA_CL_POINT_X_RAD
+ 0x00000000, // PA_CL_POINT_Y_RAD
+ 0x00000000, // PA_CL_POINT_SIZE
+ 0x00000000, // PA_CL_POINT_CULL_RAD
+ 0x00000000, // VGT_DMA_BASE_HI
+ 0x00000000, // VGT_DMA_BASE
+};
+static const unsigned int ci_SECT_CONTEXT_def_4[] =
+{
+ 0x00000000, // DB_DEPTH_CONTROL
+ 0x00000000, // DB_EQAA
+ 0x00000000, // CB_COLOR_CONTROL
+ 0x00000000, // DB_SHADER_CONTROL
+ 0x00090000, // PA_CL_CLIP_CNTL
+ 0x00000004, // PA_SU_SC_MODE_CNTL
+ 0x00000000, // PA_CL_VTE_CNTL
+ 0x00000000, // PA_CL_VS_OUT_CNTL
+ 0x00000000, // PA_CL_NANINF_CNTL
+ 0x00000000, // PA_SU_LINE_STIPPLE_CNTL
+ 0x00000000, // PA_SU_LINE_STIPPLE_SCALE
+ 0x00000000, // PA_SU_PRIM_FILTER_CNTL
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // PA_SU_POINT_SIZE
+ 0x00000000, // PA_SU_POINT_MINMAX
+ 0x00000000, // PA_SU_LINE_CNTL
+ 0x00000000, // PA_SC_LINE_STIPPLE
+ 0x00000000, // VGT_OUTPUT_PATH_CNTL
+ 0x00000000, // VGT_HOS_CNTL
+ 0x00000000, // VGT_HOS_MAX_TESS_LEVEL
+ 0x00000000, // VGT_HOS_MIN_TESS_LEVEL
+ 0x00000000, // VGT_HOS_REUSE_DEPTH
+ 0x00000000, // VGT_GROUP_PRIM_TYPE
+ 0x00000000, // VGT_GROUP_FIRST_DECR
+ 0x00000000, // VGT_GROUP_DECR
+ 0x00000000, // VGT_GROUP_VECT_0_CNTL
+ 0x00000000, // VGT_GROUP_VECT_1_CNTL
+ 0x00000000, // VGT_GROUP_VECT_0_FMT_CNTL
+ 0x00000000, // VGT_GROUP_VECT_1_FMT_CNTL
+ 0x00000000, // VGT_GS_MODE
+ 0x00000000, // VGT_GS_ONCHIP_CNTL
+ 0x00000000, // PA_SC_MODE_CNTL_0
+ 0x00000000, // PA_SC_MODE_CNTL_1
+ 0x00000000, // VGT_ENHANCE
+ 0x00000100, // VGT_GS_PER_ES
+ 0x00000080, // VGT_ES_PER_GS
+ 0x00000002, // VGT_GS_PER_VS
+ 0x00000000, // VGT_GSVS_RING_OFFSET_1
+ 0x00000000, // VGT_GSVS_RING_OFFSET_2
+ 0x00000000, // VGT_GSVS_RING_OFFSET_3
+ 0x00000000, // VGT_GS_OUT_PRIM_TYPE
+ 0x00000000, // IA_ENHANCE
+};
+static const unsigned int ci_SECT_CONTEXT_def_5[] =
+{
+ 0x00000000, // WD_ENHANCE
+ 0x00000000, // VGT_PRIMITIVEID_EN
+};
+static const unsigned int ci_SECT_CONTEXT_def_6[] =
+{
+ 0x00000000, // VGT_PRIMITIVEID_RESET
+};
+static const unsigned int ci_SECT_CONTEXT_def_7[] =
+{
+ 0x00000000, // VGT_MULTI_PRIM_IB_RESET_EN
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // VGT_INSTANCE_STEP_RATE_0
+ 0x00000000, // VGT_INSTANCE_STEP_RATE_1
+ 0x000000ff, // IA_MULTI_VGT_PARAM
+ 0x00000000, // VGT_ESGS_RING_ITEMSIZE
+ 0x00000000, // VGT_GSVS_RING_ITEMSIZE
+ 0x00000000, // VGT_REUSE_OFF
+ 0x00000000, // VGT_VTX_CNT_EN
+ 0x00000000, // DB_HTILE_SURFACE
+ 0x00000000, // DB_SRESULTS_COMPARE_STATE0
+ 0x00000000, // DB_SRESULTS_COMPARE_STATE1
+ 0x00000000, // DB_PRELOAD_CONTROL
+ 0, // HOLE
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_0
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_0
+ 0, // HOLE
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_0
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_1
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_1
+ 0, // HOLE
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_1
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_2
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_2
+ 0, // HOLE
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_2
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_3
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_3
+ 0, // HOLE
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_3
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_OFFSET
+ 0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE
+ 0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE
+ 0, // HOLE
+ 0x00000000, // VGT_GS_MAX_VERT_OUT
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // VGT_SHADER_STAGES_EN
+ 0x00000000, // VGT_LS_HS_CONFIG
+ 0x00000000, // VGT_GS_VERT_ITEMSIZE
+ 0x00000000, // VGT_GS_VERT_ITEMSIZE_1
+ 0x00000000, // VGT_GS_VERT_ITEMSIZE_2
+ 0x00000000, // VGT_GS_VERT_ITEMSIZE_3
+ 0x00000000, // VGT_TF_PARAM
+ 0x00000000, // DB_ALPHA_TO_MASK
+ 0, // HOLE
+ 0x00000000, // PA_SU_POLY_OFFSET_DB_FMT_CNTL
+ 0x00000000, // PA_SU_POLY_OFFSET_CLAMP
+ 0x00000000, // PA_SU_POLY_OFFSET_FRONT_SCALE
+ 0x00000000, // PA_SU_POLY_OFFSET_FRONT_OFFSET
+ 0x00000000, // PA_SU_POLY_OFFSET_BACK_SCALE
+ 0x00000000, // PA_SU_POLY_OFFSET_BACK_OFFSET
+ 0x00000000, // VGT_GS_INSTANCE_CNT
+ 0x00000000, // VGT_STRMOUT_CONFIG
+ 0x00000000, // VGT_STRMOUT_BUFFER_CONFIG
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // PA_SC_CENTROID_PRIORITY_0
+ 0x00000000, // PA_SC_CENTROID_PRIORITY_1
+ 0x00001000, // PA_SC_LINE_CNTL
+ 0x00000000, // PA_SC_AA_CONFIG
+ 0x00000005, // PA_SU_VTX_CNTL
+ 0x3f800000, // PA_CL_GB_VERT_CLIP_ADJ
+ 0x3f800000, // PA_CL_GB_VERT_DISC_ADJ
+ 0x3f800000, // PA_CL_GB_HORZ_CLIP_ADJ
+ 0x3f800000, // PA_CL_GB_HORZ_DISC_ADJ
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_1
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_2
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_3
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_1
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_2
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_3
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_1
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_2
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_3
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_0
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_1
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_2
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_3
+ 0xffffffff, // PA_SC_AA_MASK_X0Y0_X1Y0
+ 0xffffffff, // PA_SC_AA_MASK_X0Y1_X1Y1
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x0000000e, // VGT_VERTEX_REUSE_BLOCK_CNTL
+ 0x00000010, // VGT_OUT_DEALLOC_CNTL
+ 0x00000000, // CB_COLOR0_BASE
+ 0x00000000, // CB_COLOR0_PITCH
+ 0x00000000, // CB_COLOR0_SLICE
+ 0x00000000, // CB_COLOR0_VIEW
+ 0x00000000, // CB_COLOR0_INFO
+ 0x00000000, // CB_COLOR0_ATTRIB
+ 0, // HOLE
+ 0x00000000, // CB_COLOR0_CMASK
+ 0x00000000, // CB_COLOR0_CMASK_SLICE
+ 0x00000000, // CB_COLOR0_FMASK
+ 0x00000000, // CB_COLOR0_FMASK_SLICE
+ 0x00000000, // CB_COLOR0_CLEAR_WORD0
+ 0x00000000, // CB_COLOR0_CLEAR_WORD1
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR1_BASE
+ 0x00000000, // CB_COLOR1_PITCH
+ 0x00000000, // CB_COLOR1_SLICE
+ 0x00000000, // CB_COLOR1_VIEW
+ 0x00000000, // CB_COLOR1_INFO
+ 0x00000000, // CB_COLOR1_ATTRIB
+ 0, // HOLE
+ 0x00000000, // CB_COLOR1_CMASK
+ 0x00000000, // CB_COLOR1_CMASK_SLICE
+ 0x00000000, // CB_COLOR1_FMASK
+ 0x00000000, // CB_COLOR1_FMASK_SLICE
+ 0x00000000, // CB_COLOR1_CLEAR_WORD0
+ 0x00000000, // CB_COLOR1_CLEAR_WORD1
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR2_BASE
+ 0x00000000, // CB_COLOR2_PITCH
+ 0x00000000, // CB_COLOR2_SLICE
+ 0x00000000, // CB_COLOR2_VIEW
+ 0x00000000, // CB_COLOR2_INFO
+ 0x00000000, // CB_COLOR2_ATTRIB
+ 0, // HOLE
+ 0x00000000, // CB_COLOR2_CMASK
+ 0x00000000, // CB_COLOR2_CMASK_SLICE
+ 0x00000000, // CB_COLOR2_FMASK
+ 0x00000000, // CB_COLOR2_FMASK_SLICE
+ 0x00000000, // CB_COLOR2_CLEAR_WORD0
+ 0x00000000, // CB_COLOR2_CLEAR_WORD1
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR3_BASE
+ 0x00000000, // CB_COLOR3_PITCH
+ 0x00000000, // CB_COLOR3_SLICE
+ 0x00000000, // CB_COLOR3_VIEW
+ 0x00000000, // CB_COLOR3_INFO
+ 0x00000000, // CB_COLOR3_ATTRIB
+ 0, // HOLE
+ 0x00000000, // CB_COLOR3_CMASK
+ 0x00000000, // CB_COLOR3_CMASK_SLICE
+ 0x00000000, // CB_COLOR3_FMASK
+ 0x00000000, // CB_COLOR3_FMASK_SLICE
+ 0x00000000, // CB_COLOR3_CLEAR_WORD0
+ 0x00000000, // CB_COLOR3_CLEAR_WORD1
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR4_BASE
+ 0x00000000, // CB_COLOR4_PITCH
+ 0x00000000, // CB_COLOR4_SLICE
+ 0x00000000, // CB_COLOR4_VIEW
+ 0x00000000, // CB_COLOR4_INFO
+ 0x00000000, // CB_COLOR4_ATTRIB
+ 0, // HOLE
+ 0x00000000, // CB_COLOR4_CMASK
+ 0x00000000, // CB_COLOR4_CMASK_SLICE
+ 0x00000000, // CB_COLOR4_FMASK
+ 0x00000000, // CB_COLOR4_FMASK_SLICE
+ 0x00000000, // CB_COLOR4_CLEAR_WORD0
+ 0x00000000, // CB_COLOR4_CLEAR_WORD1
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR5_BASE
+ 0x00000000, // CB_COLOR5_PITCH
+ 0x00000000, // CB_COLOR5_SLICE
+ 0x00000000, // CB_COLOR5_VIEW
+ 0x00000000, // CB_COLOR5_INFO
+ 0x00000000, // CB_COLOR5_ATTRIB
+ 0, // HOLE
+ 0x00000000, // CB_COLOR5_CMASK
+ 0x00000000, // CB_COLOR5_CMASK_SLICE
+ 0x00000000, // CB_COLOR5_FMASK
+ 0x00000000, // CB_COLOR5_FMASK_SLICE
+ 0x00000000, // CB_COLOR5_CLEAR_WORD0
+ 0x00000000, // CB_COLOR5_CLEAR_WORD1
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR6_BASE
+ 0x00000000, // CB_COLOR6_PITCH
+ 0x00000000, // CB_COLOR6_SLICE
+ 0x00000000, // CB_COLOR6_VIEW
+ 0x00000000, // CB_COLOR6_INFO
+ 0x00000000, // CB_COLOR6_ATTRIB
+ 0, // HOLE
+ 0x00000000, // CB_COLOR6_CMASK
+ 0x00000000, // CB_COLOR6_CMASK_SLICE
+ 0x00000000, // CB_COLOR6_FMASK
+ 0x00000000, // CB_COLOR6_FMASK_SLICE
+ 0x00000000, // CB_COLOR6_CLEAR_WORD0
+ 0x00000000, // CB_COLOR6_CLEAR_WORD1
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR7_BASE
+ 0x00000000, // CB_COLOR7_PITCH
+ 0x00000000, // CB_COLOR7_SLICE
+ 0x00000000, // CB_COLOR7_VIEW
+ 0x00000000, // CB_COLOR7_INFO
+ 0x00000000, // CB_COLOR7_ATTRIB
+ 0, // HOLE
+ 0x00000000, // CB_COLOR7_CMASK
+ 0x00000000, // CB_COLOR7_CMASK_SLICE
+ 0x00000000, // CB_COLOR7_FMASK
+ 0x00000000, // CB_COLOR7_FMASK_SLICE
+ 0x00000000, // CB_COLOR7_CLEAR_WORD0
+ 0x00000000, // CB_COLOR7_CLEAR_WORD1
+};
+static const struct cs_extent_def ci_SECT_CONTEXT_defs[] =
+{
+ {ci_SECT_CONTEXT_def_1, 0x0000a000, 212 },
+ {ci_SECT_CONTEXT_def_2, 0x0000a0d6, 274 },
+ {ci_SECT_CONTEXT_def_3, 0x0000a1f5, 6 },
+ {ci_SECT_CONTEXT_def_4, 0x0000a200, 157 },
+ {ci_SECT_CONTEXT_def_5, 0x0000a2a0, 2 },
+ {ci_SECT_CONTEXT_def_6, 0x0000a2a3, 1 },
+ {ci_SECT_CONTEXT_def_7, 0x0000a2a5, 233 },
+ { 0, 0, 0 }
+};
+static const struct cs_section_def ci_cs_data[] = {
+ { ci_SECT_CONTEXT_defs, SECT_CONTEXT },
+ { 0, SECT_NONE }
+};
diff --git a/drivers/gpu/drm/amd/amdgpu/clearstate_defs.h b/drivers/gpu/drm/amd/amdgpu/clearstate_defs.h
new file mode 100644
index 000000000000..3eda707d7388
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/clearstate_defs.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 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 CLEARSTATE_DEFS_H
+#define CLEARSTATE_DEFS_H
+
+enum section_id {
+ SECT_NONE,
+ SECT_CONTEXT,
+ SECT_CLEAR,
+ SECT_CTRLCONST
+};
+
+struct cs_extent_def {
+ const unsigned int *extent;
+ const unsigned int reg_index;
+ const unsigned int reg_count;
+};
+
+struct cs_section_def {
+ const struct cs_extent_def *section;
+ const enum section_id id;
+};
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/clearstate_vi.h b/drivers/gpu/drm/amd/amdgpu/clearstate_vi.h
new file mode 100644
index 000000000000..1aab9bef9349
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/clearstate_vi.h
@@ -0,0 +1,944 @@
+/*
+ * 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.
+ *
+ */
+
+static const unsigned int vi_SECT_CONTEXT_def_1[] =
+{
+ 0x00000000, // DB_RENDER_CONTROL
+ 0x00000000, // DB_COUNT_CONTROL
+ 0x00000000, // DB_DEPTH_VIEW
+ 0x00000000, // DB_RENDER_OVERRIDE
+ 0x00000000, // DB_RENDER_OVERRIDE2
+ 0x00000000, // DB_HTILE_DATA_BASE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // DB_DEPTH_BOUNDS_MIN
+ 0x00000000, // DB_DEPTH_BOUNDS_MAX
+ 0x00000000, // DB_STENCIL_CLEAR
+ 0x00000000, // DB_DEPTH_CLEAR
+ 0x00000000, // PA_SC_SCREEN_SCISSOR_TL
+ 0x40004000, // PA_SC_SCREEN_SCISSOR_BR
+ 0, // HOLE
+ 0x00000000, // DB_DEPTH_INFO
+ 0x00000000, // DB_Z_INFO
+ 0x00000000, // DB_STENCIL_INFO
+ 0x00000000, // DB_Z_READ_BASE
+ 0x00000000, // DB_STENCIL_READ_BASE
+ 0x00000000, // DB_Z_WRITE_BASE
+ 0x00000000, // DB_STENCIL_WRITE_BASE
+ 0x00000000, // DB_DEPTH_SIZE
+ 0x00000000, // DB_DEPTH_SLICE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // TA_BC_BASE_ADDR
+ 0x00000000, // TA_BC_BASE_ADDR_HI
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // COHER_DEST_BASE_HI_0
+ 0x00000000, // COHER_DEST_BASE_HI_1
+ 0x00000000, // COHER_DEST_BASE_HI_2
+ 0x00000000, // COHER_DEST_BASE_HI_3
+ 0x00000000, // COHER_DEST_BASE_2
+ 0x00000000, // COHER_DEST_BASE_3
+ 0x00000000, // PA_SC_WINDOW_OFFSET
+ 0x80000000, // PA_SC_WINDOW_SCISSOR_TL
+ 0x40004000, // PA_SC_WINDOW_SCISSOR_BR
+ 0x0000ffff, // PA_SC_CLIPRECT_RULE
+ 0x00000000, // PA_SC_CLIPRECT_0_TL
+ 0x40004000, // PA_SC_CLIPRECT_0_BR
+ 0x00000000, // PA_SC_CLIPRECT_1_TL
+ 0x40004000, // PA_SC_CLIPRECT_1_BR
+ 0x00000000, // PA_SC_CLIPRECT_2_TL
+ 0x40004000, // PA_SC_CLIPRECT_2_BR
+ 0x00000000, // PA_SC_CLIPRECT_3_TL
+ 0x40004000, // PA_SC_CLIPRECT_3_BR
+ 0xaa99aaaa, // PA_SC_EDGERULE
+ 0x00000000, // PA_SU_HARDWARE_SCREEN_OFFSET
+ 0xffffffff, // CB_TARGET_MASK
+ 0xffffffff, // CB_SHADER_MASK
+ 0x80000000, // PA_SC_GENERIC_SCISSOR_TL
+ 0x40004000, // PA_SC_GENERIC_SCISSOR_BR
+ 0x00000000, // COHER_DEST_BASE_0
+ 0x00000000, // COHER_DEST_BASE_1
+ 0x80000000, // PA_SC_VPORT_SCISSOR_0_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_0_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_1_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_1_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_2_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_2_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_3_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_3_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_4_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_4_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_5_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_5_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_6_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_6_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_7_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_7_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_8_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_8_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_9_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_9_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_10_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_10_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_11_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_11_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_12_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_12_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_13_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_13_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_14_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_14_BR
+ 0x80000000, // PA_SC_VPORT_SCISSOR_15_TL
+ 0x40004000, // PA_SC_VPORT_SCISSOR_15_BR
+ 0x00000000, // PA_SC_VPORT_ZMIN_0
+ 0x3f800000, // PA_SC_VPORT_ZMAX_0
+ 0x00000000, // PA_SC_VPORT_ZMIN_1
+ 0x3f800000, // PA_SC_VPORT_ZMAX_1
+ 0x00000000, // PA_SC_VPORT_ZMIN_2
+ 0x3f800000, // PA_SC_VPORT_ZMAX_2
+ 0x00000000, // PA_SC_VPORT_ZMIN_3
+ 0x3f800000, // PA_SC_VPORT_ZMAX_3
+ 0x00000000, // PA_SC_VPORT_ZMIN_4
+ 0x3f800000, // PA_SC_VPORT_ZMAX_4
+ 0x00000000, // PA_SC_VPORT_ZMIN_5
+ 0x3f800000, // PA_SC_VPORT_ZMAX_5
+ 0x00000000, // PA_SC_VPORT_ZMIN_6
+ 0x3f800000, // PA_SC_VPORT_ZMAX_6
+ 0x00000000, // PA_SC_VPORT_ZMIN_7
+ 0x3f800000, // PA_SC_VPORT_ZMAX_7
+ 0x00000000, // PA_SC_VPORT_ZMIN_8
+ 0x3f800000, // PA_SC_VPORT_ZMAX_8
+ 0x00000000, // PA_SC_VPORT_ZMIN_9
+ 0x3f800000, // PA_SC_VPORT_ZMAX_9
+ 0x00000000, // PA_SC_VPORT_ZMIN_10
+ 0x3f800000, // PA_SC_VPORT_ZMAX_10
+ 0x00000000, // PA_SC_VPORT_ZMIN_11
+ 0x3f800000, // PA_SC_VPORT_ZMAX_11
+ 0x00000000, // PA_SC_VPORT_ZMIN_12
+ 0x3f800000, // PA_SC_VPORT_ZMAX_12
+ 0x00000000, // PA_SC_VPORT_ZMIN_13
+ 0x3f800000, // PA_SC_VPORT_ZMAX_13
+ 0x00000000, // PA_SC_VPORT_ZMIN_14
+ 0x3f800000, // PA_SC_VPORT_ZMAX_14
+ 0x00000000, // PA_SC_VPORT_ZMIN_15
+ 0x3f800000, // PA_SC_VPORT_ZMAX_15
+};
+static const unsigned int vi_SECT_CONTEXT_def_2[] =
+{
+ 0x00000000, // PA_SC_SCREEN_EXTENT_CONTROL
+ 0, // HOLE
+ 0x00000000, // CP_PERFMON_CNTX_CNTL
+ 0x00000000, // CP_RINGID
+ 0x00000000, // CP_VMID
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0xffffffff, // VGT_MAX_VTX_INDX
+ 0x00000000, // VGT_MIN_VTX_INDX
+ 0x00000000, // VGT_INDX_OFFSET
+ 0x00000000, // VGT_MULTI_PRIM_IB_RESET_INDX
+ 0, // HOLE
+ 0x00000000, // CB_BLEND_RED
+ 0x00000000, // CB_BLEND_GREEN
+ 0x00000000, // CB_BLEND_BLUE
+ 0x00000000, // CB_BLEND_ALPHA
+ 0x00000000, // CB_DCC_CONTROL
+ 0, // HOLE
+ 0x00000000, // DB_STENCIL_CONTROL
+ 0x00000000, // DB_STENCILREFMASK
+ 0x00000000, // DB_STENCILREFMASK_BF
+ 0, // HOLE
+ 0x00000000, // PA_CL_VPORT_XSCALE
+ 0x00000000, // PA_CL_VPORT_XOFFSET
+ 0x00000000, // PA_CL_VPORT_YSCALE
+ 0x00000000, // PA_CL_VPORT_YOFFSET
+ 0x00000000, // PA_CL_VPORT_ZSCALE
+ 0x00000000, // PA_CL_VPORT_ZOFFSET
+ 0x00000000, // PA_CL_VPORT_XSCALE_1
+ 0x00000000, // PA_CL_VPORT_XOFFSET_1
+ 0x00000000, // PA_CL_VPORT_YSCALE_1
+ 0x00000000, // PA_CL_VPORT_YOFFSET_1
+ 0x00000000, // PA_CL_VPORT_ZSCALE_1
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_1
+ 0x00000000, // PA_CL_VPORT_XSCALE_2
+ 0x00000000, // PA_CL_VPORT_XOFFSET_2
+ 0x00000000, // PA_CL_VPORT_YSCALE_2
+ 0x00000000, // PA_CL_VPORT_YOFFSET_2
+ 0x00000000, // PA_CL_VPORT_ZSCALE_2
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_2
+ 0x00000000, // PA_CL_VPORT_XSCALE_3
+ 0x00000000, // PA_CL_VPORT_XOFFSET_3
+ 0x00000000, // PA_CL_VPORT_YSCALE_3
+ 0x00000000, // PA_CL_VPORT_YOFFSET_3
+ 0x00000000, // PA_CL_VPORT_ZSCALE_3
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_3
+ 0x00000000, // PA_CL_VPORT_XSCALE_4
+ 0x00000000, // PA_CL_VPORT_XOFFSET_4
+ 0x00000000, // PA_CL_VPORT_YSCALE_4
+ 0x00000000, // PA_CL_VPORT_YOFFSET_4
+ 0x00000000, // PA_CL_VPORT_ZSCALE_4
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_4
+ 0x00000000, // PA_CL_VPORT_XSCALE_5
+ 0x00000000, // PA_CL_VPORT_XOFFSET_5
+ 0x00000000, // PA_CL_VPORT_YSCALE_5
+ 0x00000000, // PA_CL_VPORT_YOFFSET_5
+ 0x00000000, // PA_CL_VPORT_ZSCALE_5
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_5
+ 0x00000000, // PA_CL_VPORT_XSCALE_6
+ 0x00000000, // PA_CL_VPORT_XOFFSET_6
+ 0x00000000, // PA_CL_VPORT_YSCALE_6
+ 0x00000000, // PA_CL_VPORT_YOFFSET_6
+ 0x00000000, // PA_CL_VPORT_ZSCALE_6
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_6
+ 0x00000000, // PA_CL_VPORT_XSCALE_7
+ 0x00000000, // PA_CL_VPORT_XOFFSET_7
+ 0x00000000, // PA_CL_VPORT_YSCALE_7
+ 0x00000000, // PA_CL_VPORT_YOFFSET_7
+ 0x00000000, // PA_CL_VPORT_ZSCALE_7
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_7
+ 0x00000000, // PA_CL_VPORT_XSCALE_8
+ 0x00000000, // PA_CL_VPORT_XOFFSET_8
+ 0x00000000, // PA_CL_VPORT_YSCALE_8
+ 0x00000000, // PA_CL_VPORT_YOFFSET_8
+ 0x00000000, // PA_CL_VPORT_ZSCALE_8
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_8
+ 0x00000000, // PA_CL_VPORT_XSCALE_9
+ 0x00000000, // PA_CL_VPORT_XOFFSET_9
+ 0x00000000, // PA_CL_VPORT_YSCALE_9
+ 0x00000000, // PA_CL_VPORT_YOFFSET_9
+ 0x00000000, // PA_CL_VPORT_ZSCALE_9
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_9
+ 0x00000000, // PA_CL_VPORT_XSCALE_10
+ 0x00000000, // PA_CL_VPORT_XOFFSET_10
+ 0x00000000, // PA_CL_VPORT_YSCALE_10
+ 0x00000000, // PA_CL_VPORT_YOFFSET_10
+ 0x00000000, // PA_CL_VPORT_ZSCALE_10
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_10
+ 0x00000000, // PA_CL_VPORT_XSCALE_11
+ 0x00000000, // PA_CL_VPORT_XOFFSET_11
+ 0x00000000, // PA_CL_VPORT_YSCALE_11
+ 0x00000000, // PA_CL_VPORT_YOFFSET_11
+ 0x00000000, // PA_CL_VPORT_ZSCALE_11
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_11
+ 0x00000000, // PA_CL_VPORT_XSCALE_12
+ 0x00000000, // PA_CL_VPORT_XOFFSET_12
+ 0x00000000, // PA_CL_VPORT_YSCALE_12
+ 0x00000000, // PA_CL_VPORT_YOFFSET_12
+ 0x00000000, // PA_CL_VPORT_ZSCALE_12
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_12
+ 0x00000000, // PA_CL_VPORT_XSCALE_13
+ 0x00000000, // PA_CL_VPORT_XOFFSET_13
+ 0x00000000, // PA_CL_VPORT_YSCALE_13
+ 0x00000000, // PA_CL_VPORT_YOFFSET_13
+ 0x00000000, // PA_CL_VPORT_ZSCALE_13
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_13
+ 0x00000000, // PA_CL_VPORT_XSCALE_14
+ 0x00000000, // PA_CL_VPORT_XOFFSET_14
+ 0x00000000, // PA_CL_VPORT_YSCALE_14
+ 0x00000000, // PA_CL_VPORT_YOFFSET_14
+ 0x00000000, // PA_CL_VPORT_ZSCALE_14
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_14
+ 0x00000000, // PA_CL_VPORT_XSCALE_15
+ 0x00000000, // PA_CL_VPORT_XOFFSET_15
+ 0x00000000, // PA_CL_VPORT_YSCALE_15
+ 0x00000000, // PA_CL_VPORT_YOFFSET_15
+ 0x00000000, // PA_CL_VPORT_ZSCALE_15
+ 0x00000000, // PA_CL_VPORT_ZOFFSET_15
+ 0x00000000, // PA_CL_UCP_0_X
+ 0x00000000, // PA_CL_UCP_0_Y
+ 0x00000000, // PA_CL_UCP_0_Z
+ 0x00000000, // PA_CL_UCP_0_W
+ 0x00000000, // PA_CL_UCP_1_X
+ 0x00000000, // PA_CL_UCP_1_Y
+ 0x00000000, // PA_CL_UCP_1_Z
+ 0x00000000, // PA_CL_UCP_1_W
+ 0x00000000, // PA_CL_UCP_2_X
+ 0x00000000, // PA_CL_UCP_2_Y
+ 0x00000000, // PA_CL_UCP_2_Z
+ 0x00000000, // PA_CL_UCP_2_W
+ 0x00000000, // PA_CL_UCP_3_X
+ 0x00000000, // PA_CL_UCP_3_Y
+ 0x00000000, // PA_CL_UCP_3_Z
+ 0x00000000, // PA_CL_UCP_3_W
+ 0x00000000, // PA_CL_UCP_4_X
+ 0x00000000, // PA_CL_UCP_4_Y
+ 0x00000000, // PA_CL_UCP_4_Z
+ 0x00000000, // PA_CL_UCP_4_W
+ 0x00000000, // PA_CL_UCP_5_X
+ 0x00000000, // PA_CL_UCP_5_Y
+ 0x00000000, // PA_CL_UCP_5_Z
+ 0x00000000, // PA_CL_UCP_5_W
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SPI_PS_INPUT_CNTL_0
+ 0x00000000, // SPI_PS_INPUT_CNTL_1
+ 0x00000000, // SPI_PS_INPUT_CNTL_2
+ 0x00000000, // SPI_PS_INPUT_CNTL_3
+ 0x00000000, // SPI_PS_INPUT_CNTL_4
+ 0x00000000, // SPI_PS_INPUT_CNTL_5
+ 0x00000000, // SPI_PS_INPUT_CNTL_6
+ 0x00000000, // SPI_PS_INPUT_CNTL_7
+ 0x00000000, // SPI_PS_INPUT_CNTL_8
+ 0x00000000, // SPI_PS_INPUT_CNTL_9
+ 0x00000000, // SPI_PS_INPUT_CNTL_10
+ 0x00000000, // SPI_PS_INPUT_CNTL_11
+ 0x00000000, // SPI_PS_INPUT_CNTL_12
+ 0x00000000, // SPI_PS_INPUT_CNTL_13
+ 0x00000000, // SPI_PS_INPUT_CNTL_14
+ 0x00000000, // SPI_PS_INPUT_CNTL_15
+ 0x00000000, // SPI_PS_INPUT_CNTL_16
+ 0x00000000, // SPI_PS_INPUT_CNTL_17
+ 0x00000000, // SPI_PS_INPUT_CNTL_18
+ 0x00000000, // SPI_PS_INPUT_CNTL_19
+ 0x00000000, // SPI_PS_INPUT_CNTL_20
+ 0x00000000, // SPI_PS_INPUT_CNTL_21
+ 0x00000000, // SPI_PS_INPUT_CNTL_22
+ 0x00000000, // SPI_PS_INPUT_CNTL_23
+ 0x00000000, // SPI_PS_INPUT_CNTL_24
+ 0x00000000, // SPI_PS_INPUT_CNTL_25
+ 0x00000000, // SPI_PS_INPUT_CNTL_26
+ 0x00000000, // SPI_PS_INPUT_CNTL_27
+ 0x00000000, // SPI_PS_INPUT_CNTL_28
+ 0x00000000, // SPI_PS_INPUT_CNTL_29
+ 0x00000000, // SPI_PS_INPUT_CNTL_30
+ 0x00000000, // SPI_PS_INPUT_CNTL_31
+ 0x00000000, // SPI_VS_OUT_CONFIG
+ 0, // HOLE
+ 0x00000000, // SPI_PS_INPUT_ENA
+ 0x00000000, // SPI_PS_INPUT_ADDR
+ 0x00000000, // SPI_INTERP_CONTROL_0
+ 0x00000002, // SPI_PS_IN_CONTROL
+ 0, // HOLE
+ 0x00000000, // SPI_BARYC_CNTL
+ 0, // HOLE
+ 0x00000000, // SPI_TMPRING_SIZE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SPI_SHADER_POS_FORMAT
+ 0x00000000, // SPI_SHADER_Z_FORMAT
+ 0x00000000, // SPI_SHADER_COL_FORMAT
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // CB_BLEND0_CONTROL
+ 0x00000000, // CB_BLEND1_CONTROL
+ 0x00000000, // CB_BLEND2_CONTROL
+ 0x00000000, // CB_BLEND3_CONTROL
+ 0x00000000, // CB_BLEND4_CONTROL
+ 0x00000000, // CB_BLEND5_CONTROL
+ 0x00000000, // CB_BLEND6_CONTROL
+ 0x00000000, // CB_BLEND7_CONTROL
+};
+static const unsigned int vi_SECT_CONTEXT_def_3[] =
+{
+ 0x00000000, // PA_CL_POINT_X_RAD
+ 0x00000000, // PA_CL_POINT_Y_RAD
+ 0x00000000, // PA_CL_POINT_SIZE
+ 0x00000000, // PA_CL_POINT_CULL_RAD
+ 0x00000000, // VGT_DMA_BASE_HI
+ 0x00000000, // VGT_DMA_BASE
+};
+static const unsigned int vi_SECT_CONTEXT_def_4[] =
+{
+ 0x00000000, // DB_DEPTH_CONTROL
+ 0x00000000, // DB_EQAA
+ 0x00000000, // CB_COLOR_CONTROL
+ 0x00000000, // DB_SHADER_CONTROL
+ 0x00090000, // PA_CL_CLIP_CNTL
+ 0x00000004, // PA_SU_SC_MODE_CNTL
+ 0x00000000, // PA_CL_VTE_CNTL
+ 0x00000000, // PA_CL_VS_OUT_CNTL
+ 0x00000000, // PA_CL_NANINF_CNTL
+ 0x00000000, // PA_SU_LINE_STIPPLE_CNTL
+ 0x00000000, // PA_SU_LINE_STIPPLE_SCALE
+ 0x00000000, // PA_SU_PRIM_FILTER_CNTL
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // PA_SU_POINT_SIZE
+ 0x00000000, // PA_SU_POINT_MINMAX
+ 0x00000000, // PA_SU_LINE_CNTL
+ 0x00000000, // PA_SC_LINE_STIPPLE
+ 0x00000000, // VGT_OUTPUT_PATH_CNTL
+ 0x00000000, // VGT_HOS_CNTL
+ 0x00000000, // VGT_HOS_MAX_TESS_LEVEL
+ 0x00000000, // VGT_HOS_MIN_TESS_LEVEL
+ 0x00000000, // VGT_HOS_REUSE_DEPTH
+ 0x00000000, // VGT_GROUP_PRIM_TYPE
+ 0x00000000, // VGT_GROUP_FIRST_DECR
+ 0x00000000, // VGT_GROUP_DECR
+ 0x00000000, // VGT_GROUP_VECT_0_CNTL
+ 0x00000000, // VGT_GROUP_VECT_1_CNTL
+ 0x00000000, // VGT_GROUP_VECT_0_FMT_CNTL
+ 0x00000000, // VGT_GROUP_VECT_1_FMT_CNTL
+ 0x00000000, // VGT_GS_MODE
+ 0x00000000, // VGT_GS_ONCHIP_CNTL
+ 0x00000000, // PA_SC_MODE_CNTL_0
+ 0x00000000, // PA_SC_MODE_CNTL_1
+ 0x00000000, // VGT_ENHANCE
+ 0x00000100, // VGT_GS_PER_ES
+ 0x00000080, // VGT_ES_PER_GS
+ 0x00000002, // VGT_GS_PER_VS
+ 0x00000000, // VGT_GSVS_RING_OFFSET_1
+ 0x00000000, // VGT_GSVS_RING_OFFSET_2
+ 0x00000000, // VGT_GSVS_RING_OFFSET_3
+ 0x00000000, // VGT_GS_OUT_PRIM_TYPE
+ 0x00000000, // IA_ENHANCE
+};
+static const unsigned int vi_SECT_CONTEXT_def_5[] =
+{
+ 0x00000000, // WD_ENHANCE
+ 0x00000000, // VGT_PRIMITIVEID_EN
+};
+static const unsigned int vi_SECT_CONTEXT_def_6[] =
+{
+ 0x00000000, // VGT_PRIMITIVEID_RESET
+};
+static const unsigned int vi_SECT_CONTEXT_def_7[] =
+{
+ 0x00000000, // VGT_MULTI_PRIM_IB_RESET_EN
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // VGT_INSTANCE_STEP_RATE_0
+ 0x00000000, // VGT_INSTANCE_STEP_RATE_1
+ 0x000000ff, // IA_MULTI_VGT_PARAM
+ 0x00000000, // VGT_ESGS_RING_ITEMSIZE
+ 0x00000000, // VGT_GSVS_RING_ITEMSIZE
+ 0x00000000, // VGT_REUSE_OFF
+ 0x00000000, // VGT_VTX_CNT_EN
+ 0x00000000, // DB_HTILE_SURFACE
+ 0x00000000, // DB_SRESULTS_COMPARE_STATE0
+ 0x00000000, // DB_SRESULTS_COMPARE_STATE1
+ 0x00000000, // DB_PRELOAD_CONTROL
+ 0, // HOLE
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_0
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_0
+ 0, // HOLE
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_0
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_1
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_1
+ 0, // HOLE
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_1
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_2
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_2
+ 0, // HOLE
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_2
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_3
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_3
+ 0, // HOLE
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_3
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_OFFSET
+ 0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE
+ 0x00000000, // VGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE
+ 0, // HOLE
+ 0x00000000, // VGT_GS_MAX_VERT_OUT
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // VGT_TESS_DISTRIBUTION
+ 0x00000000, // VGT_SHADER_STAGES_EN
+ 0x00000000, // VGT_LS_HS_CONFIG
+ 0x00000000, // VGT_GS_VERT_ITEMSIZE
+ 0x00000000, // VGT_GS_VERT_ITEMSIZE_1
+ 0x00000000, // VGT_GS_VERT_ITEMSIZE_2
+ 0x00000000, // VGT_GS_VERT_ITEMSIZE_3
+ 0x00000000, // VGT_TF_PARAM
+ 0x00000000, // DB_ALPHA_TO_MASK
+ 0x00000000, // VGT_DISPATCH_DRAW_INDEX
+ 0x00000000, // PA_SU_POLY_OFFSET_DB_FMT_CNTL
+ 0x00000000, // PA_SU_POLY_OFFSET_CLAMP
+ 0x00000000, // PA_SU_POLY_OFFSET_FRONT_SCALE
+ 0x00000000, // PA_SU_POLY_OFFSET_FRONT_OFFSET
+ 0x00000000, // PA_SU_POLY_OFFSET_BACK_SCALE
+ 0x00000000, // PA_SU_POLY_OFFSET_BACK_OFFSET
+ 0x00000000, // VGT_GS_INSTANCE_CNT
+ 0x00000000, // VGT_STRMOUT_CONFIG
+ 0x00000000, // VGT_STRMOUT_BUFFER_CONFIG
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // PA_SC_CENTROID_PRIORITY_0
+ 0x00000000, // PA_SC_CENTROID_PRIORITY_1
+ 0x00001000, // PA_SC_LINE_CNTL
+ 0x00000000, // PA_SC_AA_CONFIG
+ 0x00000005, // PA_SU_VTX_CNTL
+ 0x3f800000, // PA_CL_GB_VERT_CLIP_ADJ
+ 0x3f800000, // PA_CL_GB_VERT_DISC_ADJ
+ 0x3f800000, // PA_CL_GB_HORZ_CLIP_ADJ
+ 0x3f800000, // PA_CL_GB_HORZ_DISC_ADJ
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_1
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_2
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_3
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_1
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_2
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_3
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_1
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_2
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_3
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_0
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_1
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_2
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y1_3
+ 0xffffffff, // PA_SC_AA_MASK_X0Y0_X1Y0
+ 0xffffffff, // PA_SC_AA_MASK_X0Y1_X1Y1
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x0000001e, // VGT_VERTEX_REUSE_BLOCK_CNTL
+ 0x00000020, // VGT_OUT_DEALLOC_CNTL
+ 0x00000000, // CB_COLOR0_BASE
+ 0x00000000, // CB_COLOR0_PITCH
+ 0x00000000, // CB_COLOR0_SLICE
+ 0x00000000, // CB_COLOR0_VIEW
+ 0x00000000, // CB_COLOR0_INFO
+ 0x00000000, // CB_COLOR0_ATTRIB
+ 0x00000000, // CB_COLOR0_DCC_CONTROL
+ 0x00000000, // CB_COLOR0_CMASK
+ 0x00000000, // CB_COLOR0_CMASK_SLICE
+ 0x00000000, // CB_COLOR0_FMASK
+ 0x00000000, // CB_COLOR0_FMASK_SLICE
+ 0x00000000, // CB_COLOR0_CLEAR_WORD0
+ 0x00000000, // CB_COLOR0_CLEAR_WORD1
+ 0x00000000, // CB_COLOR0_DCC_BASE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR1_BASE
+ 0x00000000, // CB_COLOR1_PITCH
+ 0x00000000, // CB_COLOR1_SLICE
+ 0x00000000, // CB_COLOR1_VIEW
+ 0x00000000, // CB_COLOR1_INFO
+ 0x00000000, // CB_COLOR1_ATTRIB
+ 0x00000000, // CB_COLOR1_DCC_CONTROL
+ 0x00000000, // CB_COLOR1_CMASK
+ 0x00000000, // CB_COLOR1_CMASK_SLICE
+ 0x00000000, // CB_COLOR1_FMASK
+ 0x00000000, // CB_COLOR1_FMASK_SLICE
+ 0x00000000, // CB_COLOR1_CLEAR_WORD0
+ 0x00000000, // CB_COLOR1_CLEAR_WORD1
+ 0x00000000, // CB_COLOR1_DCC_BASE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR2_BASE
+ 0x00000000, // CB_COLOR2_PITCH
+ 0x00000000, // CB_COLOR2_SLICE
+ 0x00000000, // CB_COLOR2_VIEW
+ 0x00000000, // CB_COLOR2_INFO
+ 0x00000000, // CB_COLOR2_ATTRIB
+ 0x00000000, // CB_COLOR2_DCC_CONTROL
+ 0x00000000, // CB_COLOR2_CMASK
+ 0x00000000, // CB_COLOR2_CMASK_SLICE
+ 0x00000000, // CB_COLOR2_FMASK
+ 0x00000000, // CB_COLOR2_FMASK_SLICE
+ 0x00000000, // CB_COLOR2_CLEAR_WORD0
+ 0x00000000, // CB_COLOR2_CLEAR_WORD1
+ 0x00000000, // CB_COLOR2_DCC_BASE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR3_BASE
+ 0x00000000, // CB_COLOR3_PITCH
+ 0x00000000, // CB_COLOR3_SLICE
+ 0x00000000, // CB_COLOR3_VIEW
+ 0x00000000, // CB_COLOR3_INFO
+ 0x00000000, // CB_COLOR3_ATTRIB
+ 0x00000000, // CB_COLOR3_DCC_CONTROL
+ 0x00000000, // CB_COLOR3_CMASK
+ 0x00000000, // CB_COLOR3_CMASK_SLICE
+ 0x00000000, // CB_COLOR3_FMASK
+ 0x00000000, // CB_COLOR3_FMASK_SLICE
+ 0x00000000, // CB_COLOR3_CLEAR_WORD0
+ 0x00000000, // CB_COLOR3_CLEAR_WORD1
+ 0x00000000, // CB_COLOR3_DCC_BASE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR4_BASE
+ 0x00000000, // CB_COLOR4_PITCH
+ 0x00000000, // CB_COLOR4_SLICE
+ 0x00000000, // CB_COLOR4_VIEW
+ 0x00000000, // CB_COLOR4_INFO
+ 0x00000000, // CB_COLOR4_ATTRIB
+ 0x00000000, // CB_COLOR4_DCC_CONTROL
+ 0x00000000, // CB_COLOR4_CMASK
+ 0x00000000, // CB_COLOR4_CMASK_SLICE
+ 0x00000000, // CB_COLOR4_FMASK
+ 0x00000000, // CB_COLOR4_FMASK_SLICE
+ 0x00000000, // CB_COLOR4_CLEAR_WORD0
+ 0x00000000, // CB_COLOR4_CLEAR_WORD1
+ 0x00000000, // CB_COLOR4_DCC_BASE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR5_BASE
+ 0x00000000, // CB_COLOR5_PITCH
+ 0x00000000, // CB_COLOR5_SLICE
+ 0x00000000, // CB_COLOR5_VIEW
+ 0x00000000, // CB_COLOR5_INFO
+ 0x00000000, // CB_COLOR5_ATTRIB
+ 0x00000000, // CB_COLOR5_DCC_CONTROL
+ 0x00000000, // CB_COLOR5_CMASK
+ 0x00000000, // CB_COLOR5_CMASK_SLICE
+ 0x00000000, // CB_COLOR5_FMASK
+ 0x00000000, // CB_COLOR5_FMASK_SLICE
+ 0x00000000, // CB_COLOR5_CLEAR_WORD0
+ 0x00000000, // CB_COLOR5_CLEAR_WORD1
+ 0x00000000, // CB_COLOR5_DCC_BASE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR6_BASE
+ 0x00000000, // CB_COLOR6_PITCH
+ 0x00000000, // CB_COLOR6_SLICE
+ 0x00000000, // CB_COLOR6_VIEW
+ 0x00000000, // CB_COLOR6_INFO
+ 0x00000000, // CB_COLOR6_ATTRIB
+ 0x00000000, // CB_COLOR6_DCC_CONTROL
+ 0x00000000, // CB_COLOR6_CMASK
+ 0x00000000, // CB_COLOR6_CMASK_SLICE
+ 0x00000000, // CB_COLOR6_FMASK
+ 0x00000000, // CB_COLOR6_FMASK_SLICE
+ 0x00000000, // CB_COLOR6_CLEAR_WORD0
+ 0x00000000, // CB_COLOR6_CLEAR_WORD1
+ 0x00000000, // CB_COLOR6_DCC_BASE
+ 0, // HOLE
+ 0x00000000, // CB_COLOR7_BASE
+ 0x00000000, // CB_COLOR7_PITCH
+ 0x00000000, // CB_COLOR7_SLICE
+ 0x00000000, // CB_COLOR7_VIEW
+ 0x00000000, // CB_COLOR7_INFO
+ 0x00000000, // CB_COLOR7_ATTRIB
+ 0x00000000, // CB_COLOR7_DCC_CONTROL
+ 0x00000000, // CB_COLOR7_CMASK
+ 0x00000000, // CB_COLOR7_CMASK_SLICE
+ 0x00000000, // CB_COLOR7_FMASK
+ 0x00000000, // CB_COLOR7_FMASK_SLICE
+ 0x00000000, // CB_COLOR7_CLEAR_WORD0
+ 0x00000000, // CB_COLOR7_CLEAR_WORD1
+};
+static const struct cs_extent_def vi_SECT_CONTEXT_defs[] =
+{
+ {vi_SECT_CONTEXT_def_1, 0x0000a000, 212 },
+ {vi_SECT_CONTEXT_def_2, 0x0000a0d6, 274 },
+ {vi_SECT_CONTEXT_def_3, 0x0000a1f5, 6 },
+ {vi_SECT_CONTEXT_def_4, 0x0000a200, 157 },
+ {vi_SECT_CONTEXT_def_5, 0x0000a2a0, 2 },
+ {vi_SECT_CONTEXT_def_6, 0x0000a2a3, 1 },
+ {vi_SECT_CONTEXT_def_7, 0x0000a2a5, 233 },
+ { 0, 0, 0 }
+};
+static const struct cs_section_def vi_cs_data[] = {
+ { vi_SECT_CONTEXT_defs, SECT_CONTEXT },
+ { 0, SECT_NONE }
+};
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
new file mode 100644
index 000000000000..e4936a452bc6
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
@@ -0,0 +1,1941 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/firmware.h>
+#include <linux/seq_file.h>
+#include "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_pm.h"
+#include "amdgpu_atombios.h"
+#include "vid.h"
+#include "vi_dpm.h"
+#include "amdgpu_dpm.h"
+#include "cz_dpm.h"
+#include "cz_ppsmc.h"
+#include "atom.h"
+
+#include "smu/smu_8_0_d.h"
+#include "smu/smu_8_0_sh_mask.h"
+#include "gca/gfx_8_0_d.h"
+#include "gca/gfx_8_0_sh_mask.h"
+#include "gmc/gmc_8_1_d.h"
+#include "bif/bif_5_1_d.h"
+#include "gfx_v8_0.h"
+
+static void cz_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate);
+static void cz_dpm_powergate_vce(struct amdgpu_device *adev, bool gate);
+
+static struct cz_ps *cz_get_ps(struct amdgpu_ps *rps)
+{
+ struct cz_ps *ps = rps->ps_priv;
+
+ return ps;
+}
+
+static struct cz_power_info *cz_get_pi(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = adev->pm.dpm.priv;
+
+ return pi;
+}
+
+static uint16_t cz_convert_8bit_index_to_voltage(struct amdgpu_device *adev,
+ uint16_t voltage)
+{
+ uint16_t tmp = 6200 - voltage * 25;
+
+ return tmp;
+}
+
+static void cz_construct_max_power_limits_table(struct amdgpu_device *adev,
+ struct amdgpu_clock_and_voltage_limits *table)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_clock_voltage_dependency_table *dep_table =
+ &adev->pm.dpm.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(adev,
+ dep_table->entries[dep_table->count - 1].v);
+ }
+
+ table->mclk = pi->sys_info.nbp_memory_clock[0];
+
+}
+
+union igp_info {
+ struct _ATOM_INTEGRATED_SYSTEM_INFO info;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_9 info_9;
+};
+
+static int cz_parse_sys_info_table(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
+ union igp_info *igp_info;
+ u8 frev, crev;
+ u16 data_offset;
+ int i = 0;
+
+ if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset)) {
+ igp_info = (union igp_info *)(mode_info->atom_context->bios +
+ data_offset);
+
+ if (crev != 9) {
+ DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
+ return -EINVAL;
+ }
+ pi->sys_info.bootup_sclk =
+ le32_to_cpu(igp_info->info_9.ulBootUpEngineClock);
+ pi->sys_info.bootup_uma_clk =
+ le32_to_cpu(igp_info->info_9.ulBootUpUMAClock);
+ pi->sys_info.dentist_vco_freq =
+ le32_to_cpu(igp_info->info_9.ulDentistVCOFreq);
+ pi->sys_info.bootup_nb_voltage_index =
+ le16_to_cpu(igp_info->info_9.usBootUpNBVoltage);
+
+ if (igp_info->info_9.ucHtcTmpLmt == 0)
+ pi->sys_info.htc_tmp_lmt = 203;
+ else
+ pi->sys_info.htc_tmp_lmt = igp_info->info_9.ucHtcTmpLmt;
+
+ if (igp_info->info_9.ucHtcHystLmt == 0)
+ pi->sys_info.htc_hyst_lmt = 5;
+ else
+ pi->sys_info.htc_hyst_lmt = igp_info->info_9.ucHtcHystLmt;
+
+ if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
+ DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
+ return -EINVAL;
+ }
+
+ if (le32_to_cpu(igp_info->info_9.ulSystemConfig) & (1 << 3) &&
+ pi->enable_nb_ps_policy)
+ pi->sys_info.nb_dpm_enable = true;
+ else
+ pi->sys_info.nb_dpm_enable = false;
+
+ for (i = 0; i < CZ_NUM_NBPSTATES; i++) {
+ if (i < CZ_NUM_NBPMEMORY_CLOCK)
+ pi->sys_info.nbp_memory_clock[i] =
+ le32_to_cpu(igp_info->info_9.ulNbpStateMemclkFreq[i]);
+ pi->sys_info.nbp_n_clock[i] =
+ le32_to_cpu(igp_info->info_9.ulNbpStateNClkFreq[i]);
+ }
+
+ for (i = 0; i < CZ_MAX_DISPLAY_CLOCK_LEVEL; i++)
+ pi->sys_info.display_clock[i] =
+ le32_to_cpu(igp_info->info_9.sDispClkVoltageMapping[i].ulMaximumSupportedCLK);
+
+ for (i = 0; i < CZ_NUM_NBPSTATES; i++)
+ pi->sys_info.nbp_voltage_index[i] =
+ le32_to_cpu(igp_info->info_9.usNBPStateVoltage[i]);
+
+ if (le32_to_cpu(igp_info->info_9.ulGPUCapInfo) &
+ SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS)
+ pi->caps_enable_dfs_bypass = true;
+
+ pi->sys_info.uma_channel_number =
+ igp_info->info_9.ucUMAChannelNumber;
+
+ cz_construct_max_power_limits_table(adev,
+ &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac);
+ }
+
+ return 0;
+}
+
+static void cz_patch_voltage_values(struct amdgpu_device *adev)
+{
+ int i;
+ struct amdgpu_uvd_clock_voltage_dependency_table *uvd_table =
+ &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
+ struct amdgpu_vce_clock_voltage_dependency_table *vce_table =
+ &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
+ struct amdgpu_clock_voltage_dependency_table *acp_table =
+ &adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table;
+
+ if (uvd_table->count) {
+ for (i = 0; i < uvd_table->count; i++)
+ uvd_table->entries[i].v =
+ cz_convert_8bit_index_to_voltage(adev,
+ uvd_table->entries[i].v);
+ }
+
+ if (vce_table->count) {
+ for (i = 0; i < vce_table->count; i++)
+ vce_table->entries[i].v =
+ cz_convert_8bit_index_to_voltage(adev,
+ vce_table->entries[i].v);
+ }
+
+ if (acp_table->count) {
+ for (i = 0; i < acp_table->count; i++)
+ acp_table->entries[i].v =
+ cz_convert_8bit_index_to_voltage(adev,
+ acp_table->entries[i].v);
+ }
+
+}
+
+static void cz_construct_boot_state(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
+ pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
+ pi->boot_pl.ds_divider_index = 0;
+ pi->boot_pl.ss_divider_index = 0;
+ pi->boot_pl.allow_gnb_slow = 1;
+ pi->boot_pl.force_nbp_state = 0;
+ pi->boot_pl.display_wm = 0;
+ pi->boot_pl.vce_wm = 0;
+
+}
+
+static void cz_patch_boot_state(struct amdgpu_device *adev,
+ struct cz_ps *ps)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ ps->num_levels = 1;
+ ps->levels[0] = pi->boot_pl;
+}
+
+union pplib_clock_info {
+ struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
+ struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
+ struct _ATOM_PPLIB_CZ_CLOCK_INFO carrizo;
+};
+
+static void cz_parse_pplib_clock_info(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps, int index,
+ union pplib_clock_info *clock_info)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct cz_ps *ps = cz_get_ps(rps);
+ struct cz_pl *pl = &ps->levels[index];
+ struct amdgpu_clock_voltage_dependency_table *table =
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
+
+ pl->sclk = table->entries[clock_info->carrizo.index].clk;
+ pl->vddc_index = table->entries[clock_info->carrizo.index].v;
+
+ ps->num_levels = index + 1;
+
+ if (pi->caps_sclk_ds) {
+ pl->ds_divider_index = 5;
+ pl->ss_divider_index = 5;
+ }
+
+}
+
+static void cz_parse_pplib_non_clock_info(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps,
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
+ u8 table_rev)
+{
+ struct cz_ps *ps = cz_get_ps(rps);
+
+ rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
+ rps->class = le16_to_cpu(non_clock_info->usClassification);
+ rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
+
+ if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
+ rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
+ rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
+ } else {
+ rps->vclk = 0;
+ rps->dclk = 0;
+ }
+
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+ adev->pm.dpm.boot_ps = rps;
+ cz_patch_boot_state(adev, ps);
+ }
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+ adev->pm.dpm.uvd_ps = rps;
+
+}
+
+union power_info {
+ struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+ struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+ struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+ struct _ATOM_PPLIB_POWERPLAYTABLE4 pplib4;
+ struct _ATOM_PPLIB_POWERPLAYTABLE5 pplib5;
+};
+
+union pplib_power_state {
+ struct _ATOM_PPLIB_STATE v1;
+ struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static int cz_parse_power_table(struct amdgpu_device *adev)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+ union pplib_power_state *power_state;
+ int i, j, k, non_clock_array_index, clock_array_index;
+ union pplib_clock_info *clock_info;
+ struct _StateArray *state_array;
+ struct _ClockInfoArray *clock_info_array;
+ struct _NonClockInfoArray *non_clock_info_array;
+ union power_info *power_info;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ u16 data_offset;
+ u8 frev, crev;
+ u8 *power_state_offset;
+ struct cz_ps *ps;
+
+ if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
+ &frev, &crev, &data_offset))
+ return -EINVAL;
+ power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+ state_array = (struct _StateArray *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usStateArrayOffset));
+ clock_info_array = (struct _ClockInfoArray *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
+ non_clock_info_array = (struct _NonClockInfoArray *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
+
+ adev->pm.dpm.ps = kzalloc(sizeof(struct amdgpu_ps) *
+ state_array->ucNumEntries, GFP_KERNEL);
+
+ if (!adev->pm.dpm.ps)
+ return -ENOMEM;
+
+ power_state_offset = (u8 *)state_array->states;
+ adev->pm.dpm.platform_caps =
+ le32_to_cpu(power_info->pplib.ulPlatformCaps);
+ adev->pm.dpm.backbias_response_time =
+ le16_to_cpu(power_info->pplib.usBackbiasTime);
+ adev->pm.dpm.voltage_response_time =
+ le16_to_cpu(power_info->pplib.usVoltageTime);
+
+ for (i = 0; i < state_array->ucNumEntries; i++) {
+ power_state = (union pplib_power_state *)power_state_offset;
+ non_clock_array_index = power_state->v2.nonClockInfoIndex;
+ non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+ &non_clock_info_array->nonClockInfo[non_clock_array_index];
+
+ ps = kzalloc(sizeof(struct cz_ps), GFP_KERNEL);
+ if (ps == NULL) {
+ kfree(adev->pm.dpm.ps);
+ return -ENOMEM;
+ }
+
+ adev->pm.dpm.ps[i].ps_priv = ps;
+ k = 0;
+ for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
+ clock_array_index = power_state->v2.clockInfoIndex[j];
+ if (clock_array_index >= clock_info_array->ucNumEntries)
+ continue;
+ if (k >= CZ_MAX_HARDWARE_POWERLEVELS)
+ break;
+ clock_info = (union pplib_clock_info *)
+ &clock_info_array->clockInfo[clock_array_index *
+ clock_info_array->ucEntrySize];
+ cz_parse_pplib_clock_info(adev, &adev->pm.dpm.ps[i],
+ k, clock_info);
+ k++;
+ }
+ cz_parse_pplib_non_clock_info(adev, &adev->pm.dpm.ps[i],
+ non_clock_info,
+ non_clock_info_array->ucEntrySize);
+ power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
+ }
+ adev->pm.dpm.num_ps = state_array->ucNumEntries;
+
+ return 0;
+}
+
+static int cz_process_firmware_header(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ u32 tmp;
+ int ret;
+
+ ret = cz_read_smc_sram_dword(adev, SMU8_FIRMWARE_HEADER_LOCATION +
+ offsetof(struct SMU8_Firmware_Header,
+ DpmTable),
+ &tmp, pi->sram_end);
+
+ if (ret == 0)
+ pi->dpm_table_start = tmp;
+
+ return ret;
+}
+
+static int cz_dpm_init(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi;
+ int ret, i;
+
+ pi = kzalloc(sizeof(struct cz_power_info), GFP_KERNEL);
+ if (NULL == pi)
+ return -ENOMEM;
+
+ adev->pm.dpm.priv = pi;
+
+ ret = amdgpu_get_platform_caps(adev);
+ if (ret)
+ return ret;
+
+ ret = amdgpu_parse_extended_power_table(adev);
+ if (ret)
+ return ret;
+
+ pi->sram_end = SMC_RAM_END;
+
+ /* set up DPM defaults */
+ for (i = 0; i < CZ_MAX_HARDWARE_POWERLEVELS; i++)
+ pi->active_target[i] = CZ_AT_DFLT;
+
+ pi->mgcg_cgtt_local0 = 0x0;
+ pi->mgcg_cgtt_local1 = 0x0;
+ pi->clock_slow_down_step = 25000;
+ pi->skip_clock_slow_down = 1;
+ pi->enable_nb_ps_policy = 1;
+ pi->caps_power_containment = true;
+ pi->caps_cac = true;
+ pi->didt_enabled = false;
+ if (pi->didt_enabled) {
+ pi->caps_sq_ramping = true;
+ pi->caps_db_ramping = true;
+ pi->caps_td_ramping = true;
+ pi->caps_tcp_ramping = true;
+ }
+ pi->caps_sclk_ds = true;
+ pi->voting_clients = 0x00c00033;
+ pi->auto_thermal_throttling_enabled = true;
+ pi->bapm_enabled = false;
+ pi->disable_nb_ps3_in_battery = false;
+ pi->voltage_drop_threshold = 0;
+ pi->caps_sclk_throttle_low_notification = false;
+ pi->gfx_pg_threshold = 500;
+ pi->caps_fps = true;
+ /* uvd */
+ pi->caps_uvd_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_UVD) ? true : false;
+ pi->caps_uvd_dpm = true;
+ /* vce */
+ pi->caps_vce_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_VCE) ? true : false;
+ pi->caps_vce_dpm = true;
+ /* acp */
+ pi->caps_acp_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_ACP) ? true : false;
+ pi->caps_acp_dpm = true;
+
+ pi->caps_stable_power_state = false;
+ pi->nb_dpm_enabled_by_driver = true;
+ pi->nb_dpm_enabled = false;
+ pi->caps_voltage_island = false;
+ /* flags which indicate need to upload pptable */
+ pi->need_pptable_upload = true;
+
+ ret = cz_parse_sys_info_table(adev);
+ if (ret)
+ return ret;
+
+ cz_patch_voltage_values(adev);
+ cz_construct_boot_state(adev);
+
+ ret = cz_parse_power_table(adev);
+ if (ret)
+ return ret;
+
+ ret = cz_process_firmware_header(adev);
+ if (ret)
+ return ret;
+
+ pi->dpm_enabled = true;
+ pi->uvd_dynamic_pg = false;
+
+ return 0;
+}
+
+static void cz_dpm_fini(struct amdgpu_device *adev)
+{
+ int i;
+
+ for (i = 0; i < adev->pm.dpm.num_ps; i++)
+ kfree(adev->pm.dpm.ps[i].ps_priv);
+
+ kfree(adev->pm.dpm.ps);
+ kfree(adev->pm.dpm.priv);
+ amdgpu_free_extended_power_table(adev);
+}
+
+static void
+cz_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev,
+ struct seq_file *m)
+{
+ struct amdgpu_clock_voltage_dependency_table *table =
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
+ u32 current_index =
+ (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX) &
+ TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX_MASK) >>
+ TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX__SHIFT;
+ u32 sclk, tmp;
+ u16 vddc;
+
+ if (current_index >= NUM_SCLK_LEVELS) {
+ seq_printf(m, "invalid dpm profile %d\n", current_index);
+ } else {
+ sclk = table->entries[current_index].clk;
+ tmp = (RREG32_SMC(ixSMU_VOLTAGE_STATUS) &
+ SMU_VOLTAGE_STATUS__SMU_VOLTAGE_CURRENT_LEVEL_MASK) >>
+ SMU_VOLTAGE_STATUS__SMU_VOLTAGE_CURRENT_LEVEL__SHIFT;
+ vddc = cz_convert_8bit_index_to_voltage(adev, (u16)tmp);
+ seq_printf(m, "power level %d sclk: %u vddc: %u\n",
+ current_index, sclk, vddc);
+ }
+}
+
+static void cz_dpm_print_power_state(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps)
+{
+ int i;
+ struct cz_ps *ps = cz_get_ps(rps);
+
+ amdgpu_dpm_print_class_info(rps->class, rps->class2);
+ amdgpu_dpm_print_cap_info(rps->caps);
+
+ DRM_INFO("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ for (i = 0; i < ps->num_levels; i++) {
+ struct cz_pl *pl = &ps->levels[i];
+
+ DRM_INFO("\t\tpower level %d sclk: %u vddc: %u\n",
+ i, pl->sclk,
+ cz_convert_8bit_index_to_voltage(adev, pl->vddc_index));
+ }
+
+ amdgpu_dpm_print_ps_status(adev, rps);
+}
+
+static void cz_dpm_set_funcs(struct amdgpu_device *adev);
+
+static int cz_dpm_early_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ cz_dpm_set_funcs(adev);
+
+ return 0;
+}
+
+
+static int cz_dpm_late_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (amdgpu_dpm) {
+ /* powerdown unused blocks for now */
+ cz_dpm_powergate_uvd(adev, true);
+ cz_dpm_powergate_vce(adev, true);
+ }
+
+ return 0;
+}
+
+static int cz_dpm_sw_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int ret = 0;
+ /* fix me to add thermal support TODO */
+
+ /* default to balanced state */
+ adev->pm.dpm.state = POWER_STATE_TYPE_BALANCED;
+ adev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
+ adev->pm.dpm.forced_level = AMDGPU_DPM_FORCED_LEVEL_AUTO;
+ adev->pm.default_sclk = adev->clock.default_sclk;
+ adev->pm.default_mclk = adev->clock.default_mclk;
+ adev->pm.current_sclk = adev->clock.default_sclk;
+ adev->pm.current_mclk = adev->clock.default_mclk;
+ adev->pm.int_thermal_type = THERMAL_TYPE_NONE;
+
+ if (amdgpu_dpm == 0)
+ return 0;
+
+ mutex_lock(&adev->pm.mutex);
+ ret = cz_dpm_init(adev);
+ if (ret)
+ goto dpm_init_failed;
+
+ adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps;
+ if (amdgpu_dpm == 1)
+ amdgpu_pm_print_power_states(adev);
+
+ ret = amdgpu_pm_sysfs_init(adev);
+ if (ret)
+ goto dpm_init_failed;
+
+ mutex_unlock(&adev->pm.mutex);
+ DRM_INFO("amdgpu: dpm initialized\n");
+
+ return 0;
+
+dpm_init_failed:
+ cz_dpm_fini(adev);
+ mutex_unlock(&adev->pm.mutex);
+ DRM_ERROR("amdgpu: dpm initialization failed\n");
+
+ return ret;
+}
+
+static int cz_dpm_sw_fini(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ mutex_lock(&adev->pm.mutex);
+ amdgpu_pm_sysfs_fini(adev);
+ cz_dpm_fini(adev);
+ mutex_unlock(&adev->pm.mutex);
+
+ return 0;
+}
+
+static void cz_reset_ap_mask(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ pi->active_process_mask = 0;
+
+}
+
+static int cz_dpm_download_pptable_from_smu(struct amdgpu_device *adev,
+ void **table)
+{
+ int ret = 0;
+
+ ret = cz_smu_download_pptable(adev, table);
+
+ return ret;
+}
+
+static int cz_dpm_upload_pptable_to_smu(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct SMU8_Fusion_ClkTable *clock_table;
+ struct atom_clock_dividers dividers;
+ void *table = NULL;
+ uint8_t i = 0;
+ int ret = 0;
+
+ struct amdgpu_clock_voltage_dependency_table *vddc_table =
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
+ struct amdgpu_clock_voltage_dependency_table *vddgfx_table =
+ &adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk;
+ struct amdgpu_uvd_clock_voltage_dependency_table *uvd_table =
+ &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
+ struct amdgpu_vce_clock_voltage_dependency_table *vce_table =
+ &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
+ struct amdgpu_clock_voltage_dependency_table *acp_table =
+ &adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table;
+
+ if (!pi->need_pptable_upload)
+ return 0;
+
+ ret = cz_dpm_download_pptable_from_smu(adev, &table);
+ if (ret) {
+ DRM_ERROR("amdgpu: Failed to get power play table from SMU!\n");
+ return -EINVAL;
+ }
+
+ clock_table = (struct SMU8_Fusion_ClkTable *)table;
+ /* patch clock table */
+ if (vddc_table->count > CZ_MAX_HARDWARE_POWERLEVELS ||
+ vddgfx_table->count > CZ_MAX_HARDWARE_POWERLEVELS ||
+ uvd_table->count > CZ_MAX_HARDWARE_POWERLEVELS ||
+ vce_table->count > CZ_MAX_HARDWARE_POWERLEVELS ||
+ acp_table->count > CZ_MAX_HARDWARE_POWERLEVELS) {
+ DRM_ERROR("amdgpu: Invalid Clock Voltage Dependency Table!\n");
+ 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;
+ ret = amdgpu_atombios_get_clock_dividers(adev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ clock_table->SclkBreakdownTable.ClkLevel[i].Frequency,
+ false, &dividers);
+ if (ret)
+ return ret;
+ clock_table->SclkBreakdownTable.ClkLevel[i].DfsDid =
+ (uint8_t)dividers.post_divider;
+
+ /* vddgfx sclk */
+ clock_table->SclkBreakdownTable.ClkLevel[i].GfxVid =
+ (i < vddgfx_table->count) ? (uint8_t)vddgfx_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].clk : 0;
+ ret = amdgpu_atombios_get_clock_dividers(adev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ clock_table->SclkBreakdownTable.ClkLevel[i].Frequency,
+ false, &dividers);
+ if (ret)
+ return ret;
+ clock_table->AclkBreakdownTable.ClkLevel[i].DfsDid =
+ (uint8_t)dividers.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;
+ ret = amdgpu_atombios_get_clock_dividers(adev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ clock_table->VclkBreakdownTable.ClkLevel[i].Frequency,
+ false, &dividers);
+ if (ret)
+ return ret;
+ clock_table->VclkBreakdownTable.ClkLevel[i].DfsDid =
+ (uint8_t)dividers.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;
+ ret = amdgpu_atombios_get_clock_dividers(adev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ clock_table->DclkBreakdownTable.ClkLevel[i].Frequency,
+ false, &dividers);
+ if (ret)
+ return ret;
+ clock_table->DclkBreakdownTable.ClkLevel[i].DfsDid =
+ (uint8_t)dividers.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;
+ ret = amdgpu_atombios_get_clock_dividers(adev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ clock_table->EclkBreakdownTable.ClkLevel[i].Frequency,
+ false, &dividers);
+ if (ret)
+ return ret;
+ clock_table->EclkBreakdownTable.ClkLevel[i].DfsDid =
+ (uint8_t)dividers.post_divider;
+ }
+
+ /* its time to upload to SMU */
+ ret = cz_smu_upload_pptable(adev);
+ if (ret) {
+ DRM_ERROR("amdgpu: Failed to put power play table to SMU!\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void cz_init_sclk_limit(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_clock_voltage_dependency_table *table =
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
+ uint32_t clock = 0, level;
+
+ if (!table || !table->count) {
+ DRM_ERROR("Invalid Voltage Dependency table.\n");
+ return;
+ }
+
+ pi->sclk_dpm.soft_min_clk = 0;
+ pi->sclk_dpm.hard_min_clk = 0;
+ cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxSclkLevel);
+ level = cz_get_argument(adev);
+ if (level < table->count)
+ clock = table->entries[level].clk;
+ else {
+ DRM_ERROR("Invalid SLCK Voltage Dependency table entry.\n");
+ clock = table->entries[table->count - 1].clk;
+ }
+
+ pi->sclk_dpm.soft_max_clk = clock;
+ pi->sclk_dpm.hard_max_clk = clock;
+
+}
+
+static void cz_init_uvd_limit(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_uvd_clock_voltage_dependency_table *table =
+ &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
+ uint32_t clock = 0, level;
+
+ if (!table || !table->count) {
+ DRM_ERROR("Invalid Voltage Dependency table.\n");
+ return;
+ }
+
+ pi->uvd_dpm.soft_min_clk = 0;
+ pi->uvd_dpm.hard_min_clk = 0;
+ cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxUvdLevel);
+ level = cz_get_argument(adev);
+ if (level < table->count)
+ clock = table->entries[level].vclk;
+ else {
+ DRM_ERROR("Invalid UVD Voltage Dependency table entry.\n");
+ clock = table->entries[table->count - 1].vclk;
+ }
+
+ pi->uvd_dpm.soft_max_clk = clock;
+ pi->uvd_dpm.hard_max_clk = clock;
+
+}
+
+static void cz_init_vce_limit(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_vce_clock_voltage_dependency_table *table =
+ &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
+ uint32_t clock = 0, level;
+
+ if (!table || !table->count) {
+ DRM_ERROR("Invalid Voltage Dependency table.\n");
+ return;
+ }
+
+ pi->vce_dpm.soft_min_clk = table->entries[0].ecclk;
+ pi->vce_dpm.hard_min_clk = table->entries[0].ecclk;
+ cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxEclkLevel);
+ level = cz_get_argument(adev);
+ if (level < table->count)
+ clock = table->entries[level].ecclk;
+ else {
+ /* future BIOS would fix this error */
+ DRM_ERROR("Invalid VCE Voltage Dependency table entry.\n");
+ clock = table->entries[table->count - 1].ecclk;
+ }
+
+ pi->vce_dpm.soft_max_clk = clock;
+ pi->vce_dpm.hard_max_clk = clock;
+
+}
+
+static void cz_init_acp_limit(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_clock_voltage_dependency_table *table =
+ &adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table;
+ uint32_t clock = 0, level;
+
+ if (!table || !table->count) {
+ DRM_ERROR("Invalid Voltage Dependency table.\n");
+ return;
+ }
+
+ pi->acp_dpm.soft_min_clk = 0;
+ pi->acp_dpm.hard_min_clk = 0;
+ cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxAclkLevel);
+ level = cz_get_argument(adev);
+ if (level < table->count)
+ clock = table->entries[level].clk;
+ else {
+ DRM_ERROR("Invalid ACP Voltage Dependency table entry.\n");
+ clock = table->entries[table->count - 1].clk;
+ }
+
+ pi->acp_dpm.soft_max_clk = clock;
+ pi->acp_dpm.hard_max_clk = clock;
+
+}
+
+static void cz_init_pg_state(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ pi->uvd_power_gated = false;
+ pi->vce_power_gated = false;
+ pi->acp_power_gated = false;
+
+}
+
+static void cz_init_sclk_threshold(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ pi->low_sclk_interrupt_threshold = 0;
+
+}
+
+static void cz_dpm_setup_asic(struct amdgpu_device *adev)
+{
+ cz_reset_ap_mask(adev);
+ cz_dpm_upload_pptable_to_smu(adev);
+ cz_init_sclk_limit(adev);
+ cz_init_uvd_limit(adev);
+ cz_init_vce_limit(adev);
+ cz_init_acp_limit(adev);
+ cz_init_pg_state(adev);
+ cz_init_sclk_threshold(adev);
+
+}
+
+static bool cz_check_smu_feature(struct amdgpu_device *adev,
+ uint32_t feature)
+{
+ uint32_t smu_feature = 0;
+ int ret;
+
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_GetFeatureStatus, 0);
+ if (ret) {
+ DRM_ERROR("Failed to get SMU features from SMC.\n");
+ return false;
+ } else {
+ smu_feature = cz_get_argument(adev);
+ if (feature & smu_feature)
+ return true;
+ }
+
+ return false;
+}
+
+static bool cz_check_for_dpm_enabled(struct amdgpu_device *adev)
+{
+ if (cz_check_smu_feature(adev,
+ SMU_EnabledFeatureScoreboard_SclkDpmOn))
+ return true;
+
+ return false;
+}
+
+static void cz_program_voting_clients(struct amdgpu_device *adev)
+{
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_0, PPCZ_VOTINGRIGHTSCLIENTS_DFLT0);
+}
+
+static void cz_clear_voting_clients(struct amdgpu_device *adev)
+{
+ WREG32_SMC(ixCG_FREQ_TRAN_VOTING_0, 0);
+}
+
+static int cz_start_dpm(struct amdgpu_device *adev)
+{
+ int ret = 0;
+
+ if (amdgpu_dpm) {
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_EnableAllSmuFeatures, SCLK_DPM_MASK);
+ if (ret) {
+ DRM_ERROR("SMU feature: SCLK_DPM enable failed\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int cz_stop_dpm(struct amdgpu_device *adev)
+{
+ int ret = 0;
+
+ if (amdgpu_dpm && adev->pm.dpm_enabled) {
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_DisableAllSmuFeatures, SCLK_DPM_MASK);
+ if (ret) {
+ DRM_ERROR("SMU feature: SCLK_DPM disable failed\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static uint32_t cz_get_sclk_level(struct amdgpu_device *adev,
+ uint32_t clock, uint16_t msg)
+{
+ int i = 0;
+ struct amdgpu_clock_voltage_dependency_table *table =
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
+
+ switch (msg) {
+ case PPSMC_MSG_SetSclkSoftMin:
+ case PPSMC_MSG_SetSclkHardMin:
+ for (i = 0; i < table->count; i++)
+ if (clock <= table->entries[i].clk)
+ break;
+ if (i == table->count)
+ i = table->count - 1;
+ break;
+ case PPSMC_MSG_SetSclkSoftMax:
+ case PPSMC_MSG_SetSclkHardMax:
+ for (i = table->count - 1; i >= 0; i--)
+ if (clock >= table->entries[i].clk)
+ break;
+ if (i < 0)
+ i = 0;
+ break;
+ default:
+ break;
+ }
+
+ return i;
+}
+
+static uint32_t cz_get_eclk_level(struct amdgpu_device *adev,
+ uint32_t clock, uint16_t msg)
+{
+ int i = 0;
+ struct amdgpu_vce_clock_voltage_dependency_table *table =
+ &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
+
+ if (table->count == 0)
+ return 0;
+
+ switch (msg) {
+ case PPSMC_MSG_SetEclkSoftMin:
+ case PPSMC_MSG_SetEclkHardMin:
+ for (i = 0; i < table->count-1; i++)
+ if (clock <= table->entries[i].ecclk)
+ break;
+ break;
+ case PPSMC_MSG_SetEclkSoftMax:
+ case PPSMC_MSG_SetEclkHardMax:
+ for (i = table->count - 1; i > 0; i--)
+ if (clock >= table->entries[i].ecclk)
+ break;
+ break;
+ default:
+ break;
+ }
+
+ return i;
+}
+
+static int cz_program_bootup_state(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ uint32_t soft_min_clk = 0;
+ uint32_t soft_max_clk = 0;
+ int ret = 0;
+
+ pi->sclk_dpm.soft_min_clk = pi->sys_info.bootup_sclk;
+ pi->sclk_dpm.soft_max_clk = pi->sys_info.bootup_sclk;
+
+ soft_min_clk = cz_get_sclk_level(adev,
+ pi->sclk_dpm.soft_min_clk,
+ PPSMC_MSG_SetSclkSoftMin);
+ soft_max_clk = cz_get_sclk_level(adev,
+ pi->sclk_dpm.soft_max_clk,
+ PPSMC_MSG_SetSclkSoftMax);
+
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetSclkSoftMin, soft_min_clk);
+ if (ret)
+ return -EINVAL;
+
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetSclkSoftMax, soft_max_clk);
+ if (ret)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* TODO */
+static int cz_disable_cgpg(struct amdgpu_device *adev)
+{
+ return 0;
+}
+
+/* TODO */
+static int cz_enable_cgpg(struct amdgpu_device *adev)
+{
+ return 0;
+}
+
+/* TODO */
+static int cz_program_pt_config_registers(struct amdgpu_device *adev)
+{
+ return 0;
+}
+
+static void cz_do_enable_didt(struct amdgpu_device *adev, bool enable)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ uint32_t reg = 0;
+
+ if (pi->caps_sq_ramping) {
+ reg = RREG32_DIDT(ixDIDT_SQ_CTRL0);
+ if (enable)
+ reg = REG_SET_FIELD(reg, DIDT_SQ_CTRL0, DIDT_CTRL_EN, 1);
+ else
+ reg = REG_SET_FIELD(reg, DIDT_SQ_CTRL0, DIDT_CTRL_EN, 0);
+ WREG32_DIDT(ixDIDT_SQ_CTRL0, reg);
+ }
+ if (pi->caps_db_ramping) {
+ reg = RREG32_DIDT(ixDIDT_DB_CTRL0);
+ if (enable)
+ reg = REG_SET_FIELD(reg, DIDT_DB_CTRL0, DIDT_CTRL_EN, 1);
+ else
+ reg = REG_SET_FIELD(reg, DIDT_DB_CTRL0, DIDT_CTRL_EN, 0);
+ WREG32_DIDT(ixDIDT_DB_CTRL0, reg);
+ }
+ if (pi->caps_td_ramping) {
+ reg = RREG32_DIDT(ixDIDT_TD_CTRL0);
+ if (enable)
+ reg = REG_SET_FIELD(reg, DIDT_TD_CTRL0, DIDT_CTRL_EN, 1);
+ else
+ reg = REG_SET_FIELD(reg, DIDT_TD_CTRL0, DIDT_CTRL_EN, 0);
+ WREG32_DIDT(ixDIDT_TD_CTRL0, reg);
+ }
+ if (pi->caps_tcp_ramping) {
+ reg = RREG32_DIDT(ixDIDT_TCP_CTRL0);
+ if (enable)
+ reg = REG_SET_FIELD(reg, DIDT_SQ_CTRL0, DIDT_CTRL_EN, 1);
+ else
+ reg = REG_SET_FIELD(reg, DIDT_SQ_CTRL0, DIDT_CTRL_EN, 0);
+ WREG32_DIDT(ixDIDT_TCP_CTRL0, reg);
+ }
+
+}
+
+static int cz_enable_didt(struct amdgpu_device *adev, bool enable)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ int ret;
+
+ if (pi->caps_sq_ramping || pi->caps_db_ramping ||
+ pi->caps_td_ramping || pi->caps_tcp_ramping) {
+ if (adev->gfx.gfx_current_status != AMDGPU_GFX_SAFE_MODE) {
+ ret = cz_disable_cgpg(adev);
+ if (ret) {
+ DRM_ERROR("Pre Di/Dt disable cg/pg failed\n");
+ return -EINVAL;
+ }
+ adev->gfx.gfx_current_status = AMDGPU_GFX_SAFE_MODE;
+ }
+
+ ret = cz_program_pt_config_registers(adev);
+ if (ret) {
+ DRM_ERROR("Di/Dt config failed\n");
+ return -EINVAL;
+ }
+ cz_do_enable_didt(adev, enable);
+
+ if (adev->gfx.gfx_current_status == AMDGPU_GFX_SAFE_MODE) {
+ ret = cz_enable_cgpg(adev);
+ if (ret) {
+ DRM_ERROR("Post Di/Dt enable cg/pg failed\n");
+ return -EINVAL;
+ }
+ adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE;
+ }
+ }
+
+ return 0;
+}
+
+/* TODO */
+static void cz_reset_acp_boot_level(struct amdgpu_device *adev)
+{
+}
+
+static void cz_update_current_ps(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct cz_ps *ps = cz_get_ps(rps);
+
+ pi->current_ps = *ps;
+ pi->current_rps = *rps;
+ pi->current_rps.ps_priv = ps;
+
+}
+
+static void cz_update_requested_ps(struct amdgpu_device *adev,
+ struct amdgpu_ps *rps)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct cz_ps *ps = cz_get_ps(rps);
+
+ pi->requested_ps = *ps;
+ pi->requested_rps = *rps;
+ pi->requested_rps.ps_priv = ps;
+
+}
+
+/* PP arbiter support needed TODO */
+static void cz_apply_state_adjust_rules(struct amdgpu_device *adev,
+ struct amdgpu_ps *new_rps,
+ struct amdgpu_ps *old_rps)
+{
+ struct cz_ps *ps = cz_get_ps(new_rps);
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_clock_and_voltage_limits *limits =
+ &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+ /* 10kHz memory clock */
+ uint32_t mclk = 0;
+
+ ps->force_high = false;
+ ps->need_dfs_bypass = true;
+ pi->video_start = new_rps->dclk || new_rps->vclk ||
+ new_rps->evclk || new_rps->ecclk;
+
+ if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
+ ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)
+ pi->battery_state = true;
+ else
+ pi->battery_state = false;
+
+ if (pi->caps_stable_power_state)
+ mclk = limits->mclk;
+
+ if (mclk > pi->sys_info.nbp_memory_clock[CZ_NUM_NBPMEMORY_CLOCK - 1])
+ ps->force_high = true;
+
+}
+
+static int cz_dpm_enable(struct amdgpu_device *adev)
+{
+ int ret = 0;
+
+ /* renable will hang up SMU, so check first */
+ if (cz_check_for_dpm_enabled(adev))
+ return -EINVAL;
+
+ cz_program_voting_clients(adev);
+
+ ret = cz_start_dpm(adev);
+ if (ret) {
+ DRM_ERROR("Carrizo DPM enable failed\n");
+ return -EINVAL;
+ }
+
+ ret = cz_program_bootup_state(adev);
+ if (ret) {
+ DRM_ERROR("Carrizo bootup state program failed\n");
+ return -EINVAL;
+ }
+
+ ret = cz_enable_didt(adev, true);
+ if (ret) {
+ DRM_ERROR("Carrizo enable di/dt failed\n");
+ return -EINVAL;
+ }
+
+ cz_reset_acp_boot_level(adev);
+
+ cz_update_current_ps(adev, adev->pm.dpm.boot_ps);
+
+ return 0;
+}
+
+static int cz_dpm_hw_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int ret = 0;
+
+ mutex_lock(&adev->pm.mutex);
+
+ /* smu init only needs to be called at startup, not resume.
+ * It should be in sw_init, but requires the fw info gathered
+ * in sw_init from other IP modules.
+ */
+ ret = cz_smu_init(adev);
+ if (ret) {
+ DRM_ERROR("amdgpu: smc initialization failed\n");
+ mutex_unlock(&adev->pm.mutex);
+ return ret;
+ }
+
+ /* do the actual fw loading */
+ ret = cz_smu_start(adev);
+ if (ret) {
+ DRM_ERROR("amdgpu: smc start failed\n");
+ mutex_unlock(&adev->pm.mutex);
+ return ret;
+ }
+
+ if (!amdgpu_dpm) {
+ adev->pm.dpm_enabled = false;
+ mutex_unlock(&adev->pm.mutex);
+ return ret;
+ }
+
+ /* cz dpm setup asic */
+ cz_dpm_setup_asic(adev);
+
+ /* cz dpm enable */
+ ret = cz_dpm_enable(adev);
+ if (ret)
+ adev->pm.dpm_enabled = false;
+ else
+ adev->pm.dpm_enabled = true;
+
+ mutex_unlock(&adev->pm.mutex);
+
+ return 0;
+}
+
+static int cz_dpm_disable(struct amdgpu_device *adev)
+{
+ int ret = 0;
+
+ if (!cz_check_for_dpm_enabled(adev))
+ return -EINVAL;
+
+ ret = cz_enable_didt(adev, false);
+ if (ret) {
+ DRM_ERROR("Carrizo disable di/dt failed\n");
+ return -EINVAL;
+ }
+
+ /* powerup blocks */
+ cz_dpm_powergate_uvd(adev, false);
+ cz_dpm_powergate_vce(adev, false);
+
+ cz_clear_voting_clients(adev);
+ cz_stop_dpm(adev);
+ cz_update_current_ps(adev, adev->pm.dpm.boot_ps);
+
+ return 0;
+}
+
+static int cz_dpm_hw_fini(void *handle)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ mutex_lock(&adev->pm.mutex);
+
+ /* smu fini only needs to be called at teardown, not suspend.
+ * It should be in sw_fini, but we put it here for symmetry
+ * with smu init.
+ */
+ cz_smu_fini(adev);
+
+ if (adev->pm.dpm_enabled) {
+ ret = cz_dpm_disable(adev);
+
+ adev->pm.dpm.current_ps =
+ adev->pm.dpm.requested_ps =
+ adev->pm.dpm.boot_ps;
+ }
+
+ adev->pm.dpm_enabled = false;
+
+ mutex_unlock(&adev->pm.mutex);
+
+ return ret;
+}
+
+static int cz_dpm_suspend(void *handle)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (adev->pm.dpm_enabled) {
+ mutex_lock(&adev->pm.mutex);
+
+ ret = cz_dpm_disable(adev);
+
+ adev->pm.dpm.current_ps =
+ adev->pm.dpm.requested_ps =
+ adev->pm.dpm.boot_ps;
+
+ mutex_unlock(&adev->pm.mutex);
+ }
+
+ return ret;
+}
+
+static int cz_dpm_resume(void *handle)
+{
+ int ret = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ mutex_lock(&adev->pm.mutex);
+
+ /* do the actual fw loading */
+ ret = cz_smu_start(adev);
+ if (ret) {
+ DRM_ERROR("amdgpu: smc start failed\n");
+ mutex_unlock(&adev->pm.mutex);
+ return ret;
+ }
+
+ if (!amdgpu_dpm) {
+ adev->pm.dpm_enabled = false;
+ mutex_unlock(&adev->pm.mutex);
+ return ret;
+ }
+
+ /* cz dpm setup asic */
+ cz_dpm_setup_asic(adev);
+
+ /* cz dpm enable */
+ ret = cz_dpm_enable(adev);
+ if (ret)
+ adev->pm.dpm_enabled = false;
+ else
+ adev->pm.dpm_enabled = true;
+
+ mutex_unlock(&adev->pm.mutex);
+ /* upon resume, re-compute the clocks */
+ if (adev->pm.dpm_enabled)
+ amdgpu_pm_compute_clocks(adev);
+
+ return 0;
+}
+
+static int cz_dpm_set_clockgating_state(void *handle,
+ enum amd_clockgating_state state)
+{
+ return 0;
+}
+
+static int cz_dpm_set_powergating_state(void *handle,
+ enum amd_powergating_state state)
+{
+ return 0;
+}
+
+/* borrowed from KV, need future unify */
+static int cz_dpm_get_temperature(struct amdgpu_device *adev)
+{
+ int actual_temp = 0;
+ uint32_t temp = RREG32_SMC(0xC0300E0C);
+
+ if (temp)
+ actual_temp = 1000 * ((temp / 8) - 49);
+
+ return actual_temp;
+}
+
+static int cz_dpm_pre_set_power_state(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_ps requested_ps = *adev->pm.dpm.requested_ps;
+ struct amdgpu_ps *new_ps = &requested_ps;
+
+ cz_update_requested_ps(adev, new_ps);
+ cz_apply_state_adjust_rules(adev, &pi->requested_rps,
+ &pi->current_rps);
+
+ return 0;
+}
+
+static int cz_dpm_update_sclk_limit(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_clock_and_voltage_limits *limits =
+ &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+ uint32_t clock, stable_ps_clock = 0;
+
+ clock = pi->sclk_dpm.soft_min_clk;
+
+ if (pi->caps_stable_power_state) {
+ stable_ps_clock = limits->sclk * 75 / 100;
+ if (clock < stable_ps_clock)
+ clock = stable_ps_clock;
+ }
+
+ if (clock != pi->sclk_dpm.soft_min_clk) {
+ pi->sclk_dpm.soft_min_clk = clock;
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetSclkSoftMin,
+ cz_get_sclk_level(adev, clock,
+ PPSMC_MSG_SetSclkSoftMin));
+ }
+
+ if (pi->caps_stable_power_state &&
+ pi->sclk_dpm.soft_max_clk != clock) {
+ pi->sclk_dpm.soft_max_clk = clock;
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetSclkSoftMax,
+ cz_get_sclk_level(adev, clock,
+ PPSMC_MSG_SetSclkSoftMax));
+ } else {
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetSclkSoftMax,
+ cz_get_sclk_level(adev,
+ pi->sclk_dpm.soft_max_clk,
+ PPSMC_MSG_SetSclkSoftMax));
+ }
+
+ return 0;
+}
+
+static int cz_dpm_set_deep_sleep_sclk_threshold(struct amdgpu_device *adev)
+{
+ int ret = 0;
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ if (pi->caps_sclk_ds) {
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetMinDeepSleepSclk,
+ CZ_MIN_DEEP_SLEEP_SCLK);
+ }
+
+ return ret;
+}
+
+/* ?? without dal support, is this still needed in setpowerstate list*/
+static int cz_dpm_set_watermark_threshold(struct amdgpu_device *adev)
+{
+ int ret = 0;
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetWatermarkFrequency,
+ pi->sclk_dpm.soft_max_clk);
+
+ return ret;
+}
+
+static int cz_dpm_enable_nbdpm(struct amdgpu_device *adev)
+{
+ int ret = 0;
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ /* also depend on dal NBPStateDisableRequired */
+ if (pi->nb_dpm_enabled_by_driver && !pi->nb_dpm_enabled) {
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_EnableAllSmuFeatures,
+ NB_DPM_MASK);
+ if (ret) {
+ DRM_ERROR("amdgpu: nb dpm enable failed\n");
+ return ret;
+ }
+ pi->nb_dpm_enabled = true;
+ }
+
+ return ret;
+}
+
+static void cz_dpm_nbdpm_lm_pstate_enable(struct amdgpu_device *adev,
+ bool enable)
+{
+ if (enable)
+ cz_send_msg_to_smc(adev, PPSMC_MSG_EnableLowMemoryPstate);
+ else
+ cz_send_msg_to_smc(adev, PPSMC_MSG_DisableLowMemoryPstate);
+
+}
+
+static int cz_dpm_update_low_memory_pstate(struct amdgpu_device *adev)
+{
+ int ret = 0;
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct cz_ps *ps = &pi->requested_ps;
+
+ if (pi->sys_info.nb_dpm_enable) {
+ if (ps->force_high)
+ cz_dpm_nbdpm_lm_pstate_enable(adev, true);
+ else
+ cz_dpm_nbdpm_lm_pstate_enable(adev, false);
+ }
+
+ return ret;
+}
+
+/* with dpm enabled */
+static int cz_dpm_set_power_state(struct amdgpu_device *adev)
+{
+ int ret = 0;
+
+ cz_dpm_update_sclk_limit(adev);
+ cz_dpm_set_deep_sleep_sclk_threshold(adev);
+ cz_dpm_set_watermark_threshold(adev);
+ cz_dpm_enable_nbdpm(adev);
+ cz_dpm_update_low_memory_pstate(adev);
+
+ return ret;
+}
+
+static void cz_dpm_post_set_power_state(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_ps *ps = &pi->requested_rps;
+
+ cz_update_current_ps(adev, ps);
+
+}
+
+static int cz_dpm_force_highest(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ int ret = 0;
+
+ if (pi->sclk_dpm.soft_min_clk != pi->sclk_dpm.soft_max_clk) {
+ pi->sclk_dpm.soft_min_clk =
+ pi->sclk_dpm.soft_max_clk;
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetSclkSoftMin,
+ cz_get_sclk_level(adev,
+ pi->sclk_dpm.soft_min_clk,
+ PPSMC_MSG_SetSclkSoftMin));
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int cz_dpm_force_lowest(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ int ret = 0;
+
+ if (pi->sclk_dpm.soft_max_clk != pi->sclk_dpm.soft_min_clk) {
+ pi->sclk_dpm.soft_max_clk = pi->sclk_dpm.soft_min_clk;
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetSclkSoftMax,
+ cz_get_sclk_level(adev,
+ pi->sclk_dpm.soft_max_clk,
+ PPSMC_MSG_SetSclkSoftMax));
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static uint32_t cz_dpm_get_max_sclk_level(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ if (!pi->max_sclk_level) {
+ cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxSclkLevel);
+ pi->max_sclk_level = cz_get_argument(adev) + 1;
+ }
+
+ if (pi->max_sclk_level > CZ_MAX_HARDWARE_POWERLEVELS) {
+ DRM_ERROR("Invalid max sclk level!\n");
+ return -EINVAL;
+ }
+
+ return pi->max_sclk_level;
+}
+
+static int cz_dpm_unforce_dpm_levels(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_clock_voltage_dependency_table *dep_table =
+ &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
+ uint32_t level = 0;
+ int ret = 0;
+
+ pi->sclk_dpm.soft_min_clk = dep_table->entries[0].clk;
+ level = cz_dpm_get_max_sclk_level(adev) - 1;
+ if (level < dep_table->count)
+ pi->sclk_dpm.soft_max_clk = dep_table->entries[level].clk;
+ else
+ pi->sclk_dpm.soft_max_clk =
+ dep_table->entries[dep_table->count - 1].clk;
+
+ /* get min/max sclk soft value
+ * notify SMU to execute */
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetSclkSoftMin,
+ cz_get_sclk_level(adev,
+ pi->sclk_dpm.soft_min_clk,
+ PPSMC_MSG_SetSclkSoftMin));
+ if (ret)
+ return ret;
+
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetSclkSoftMax,
+ cz_get_sclk_level(adev,
+ pi->sclk_dpm.soft_max_clk,
+ PPSMC_MSG_SetSclkSoftMax));
+ if (ret)
+ return ret;
+
+ DRM_INFO("DPM unforce state min=%d, max=%d.\n",
+ pi->sclk_dpm.soft_min_clk,
+ pi->sclk_dpm.soft_max_clk);
+
+ return 0;
+}
+
+static int cz_dpm_force_dpm_level(struct amdgpu_device *adev,
+ enum amdgpu_dpm_forced_level level)
+{
+ int ret = 0;
+
+ switch (level) {
+ case AMDGPU_DPM_FORCED_LEVEL_HIGH:
+ ret = cz_dpm_force_highest(adev);
+ if (ret)
+ return ret;
+ break;
+ case AMDGPU_DPM_FORCED_LEVEL_LOW:
+ ret = cz_dpm_force_lowest(adev);
+ if (ret)
+ return ret;
+ break;
+ case AMDGPU_DPM_FORCED_LEVEL_AUTO:
+ ret = cz_dpm_unforce_dpm_levels(adev);
+ if (ret)
+ return ret;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/* fix me, display configuration change lists here
+ * mostly dal related*/
+static void cz_dpm_display_configuration_changed(struct amdgpu_device *adev)
+{
+}
+
+static uint32_t cz_dpm_get_sclk(struct amdgpu_device *adev, bool low)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct cz_ps *requested_state = cz_get_ps(&pi->requested_rps);
+
+ if (low)
+ return requested_state->levels[0].sclk;
+ else
+ return requested_state->levels[requested_state->num_levels - 1].sclk;
+
+}
+
+static uint32_t cz_dpm_get_mclk(struct amdgpu_device *adev, bool low)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ return pi->sys_info.bootup_uma_clk;
+}
+
+static int cz_enable_uvd_dpm(struct amdgpu_device *adev, bool enable)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ int ret = 0;
+
+ if (enable && pi->caps_uvd_dpm ) {
+ pi->dpm_flags |= DPMFlags_UVD_Enabled;
+ DRM_DEBUG("UVD DPM Enabled.\n");
+
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_EnableAllSmuFeatures, UVD_DPM_MASK);
+ } else {
+ pi->dpm_flags &= ~DPMFlags_UVD_Enabled;
+ DRM_DEBUG("UVD DPM Stopped\n");
+
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_DisableAllSmuFeatures, UVD_DPM_MASK);
+ }
+
+ return ret;
+}
+
+static int cz_update_uvd_dpm(struct amdgpu_device *adev, bool gate)
+{
+ return cz_enable_uvd_dpm(adev, !gate);
+}
+
+
+static void cz_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ int ret;
+
+ if (pi->uvd_power_gated == gate)
+ return;
+
+ pi->uvd_power_gated = gate;
+
+ if (gate) {
+ if (pi->caps_uvd_pg) {
+ /* disable clockgating so we can properly shut down the block */
+ ret = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
+ AMD_CG_STATE_UNGATE);
+ /* shutdown the UVD block */
+ ret = amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
+ AMD_PG_STATE_GATE);
+ /* XXX: check for errors */
+ }
+ cz_update_uvd_dpm(adev, gate);
+ if (pi->caps_uvd_pg)
+ /* power off the UVD block */
+ cz_send_msg_to_smc(adev, PPSMC_MSG_UVDPowerOFF);
+ } else {
+ if (pi->caps_uvd_pg) {
+ /* power on the UVD block */
+ if (pi->uvd_dynamic_pg)
+ cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 1);
+ else
+ cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 0);
+ /* re-init the UVD block */
+ ret = amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
+ AMD_PG_STATE_UNGATE);
+ /* enable clockgating. hw will dynamically gate/ungate clocks on the fly */
+ ret = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD,
+ AMD_CG_STATE_GATE);
+ /* XXX: check for errors */
+ }
+ cz_update_uvd_dpm(adev, gate);
+ }
+}
+
+static int cz_enable_vce_dpm(struct amdgpu_device *adev, bool enable)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ int ret = 0;
+
+ if (enable && pi->caps_vce_dpm) {
+ pi->dpm_flags |= DPMFlags_VCE_Enabled;
+ DRM_DEBUG("VCE DPM Enabled.\n");
+
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_EnableAllSmuFeatures, VCE_DPM_MASK);
+
+ } else {
+ pi->dpm_flags &= ~DPMFlags_VCE_Enabled;
+ DRM_DEBUG("VCE DPM Stopped\n");
+
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_DisableAllSmuFeatures, VCE_DPM_MASK);
+ }
+
+ return ret;
+}
+
+static int cz_update_vce_dpm(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_vce_clock_voltage_dependency_table *table =
+ &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
+
+ /* Stable Pstate is enabled and we need to set the VCE DPM to highest level */
+ if (pi->caps_stable_power_state) {
+ 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;
+ }
+
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetEclkHardMin,
+ cz_get_eclk_level(adev,
+ pi->vce_dpm.hard_min_clk,
+ PPSMC_MSG_SetEclkHardMin));
+ return 0;
+}
+
+static void cz_dpm_powergate_vce(struct amdgpu_device *adev, bool gate)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ if (pi->caps_vce_pg) {
+ if (pi->vce_power_gated != gate) {
+ if (gate) {
+ /* disable clockgating so we can properly shut down the block */
+ amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+ AMD_CG_STATE_UNGATE);
+ /* shutdown the VCE block */
+ amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+ AMD_PG_STATE_GATE);
+
+ cz_enable_vce_dpm(adev, false);
+ /* TODO: to figure out why vce can't be poweroff. */
+ /* cz_send_msg_to_smc(adev, PPSMC_MSG_VCEPowerOFF); */
+ pi->vce_power_gated = true;
+ } else {
+ cz_send_msg_to_smc(adev, PPSMC_MSG_VCEPowerON);
+ pi->vce_power_gated = false;
+
+ /* re-init the VCE block */
+ amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+ AMD_PG_STATE_UNGATE);
+ /* enable clockgating. hw will dynamically gate/ungate clocks on the fly */
+ amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+ AMD_CG_STATE_GATE);
+
+ cz_update_vce_dpm(adev);
+ cz_enable_vce_dpm(adev, true);
+ }
+ } else {
+ if (! pi->vce_power_gated) {
+ cz_update_vce_dpm(adev);
+ }
+ }
+ } else { /*pi->caps_vce_pg*/
+ cz_update_vce_dpm(adev);
+ cz_enable_vce_dpm(adev, true);
+ }
+
+ return;
+}
+
+const struct amd_ip_funcs cz_dpm_ip_funcs = {
+ .early_init = cz_dpm_early_init,
+ .late_init = cz_dpm_late_init,
+ .sw_init = cz_dpm_sw_init,
+ .sw_fini = cz_dpm_sw_fini,
+ .hw_init = cz_dpm_hw_init,
+ .hw_fini = cz_dpm_hw_fini,
+ .suspend = cz_dpm_suspend,
+ .resume = cz_dpm_resume,
+ .is_idle = NULL,
+ .wait_for_idle = NULL,
+ .soft_reset = NULL,
+ .print_status = NULL,
+ .set_clockgating_state = cz_dpm_set_clockgating_state,
+ .set_powergating_state = cz_dpm_set_powergating_state,
+};
+
+static const struct amdgpu_dpm_funcs cz_dpm_funcs = {
+ .get_temperature = cz_dpm_get_temperature,
+ .pre_set_power_state = cz_dpm_pre_set_power_state,
+ .set_power_state = cz_dpm_set_power_state,
+ .post_set_power_state = cz_dpm_post_set_power_state,
+ .display_configuration_changed = cz_dpm_display_configuration_changed,
+ .get_sclk = cz_dpm_get_sclk,
+ .get_mclk = cz_dpm_get_mclk,
+ .print_power_state = cz_dpm_print_power_state,
+ .debugfs_print_current_performance_level =
+ cz_dpm_debugfs_print_current_performance_level,
+ .force_performance_level = cz_dpm_force_dpm_level,
+ .vblank_too_short = NULL,
+ .powergate_uvd = cz_dpm_powergate_uvd,
+ .powergate_vce = cz_dpm_powergate_vce,
+};
+
+static void cz_dpm_set_funcs(struct amdgpu_device *adev)
+{
+ if (NULL == adev->pm.funcs)
+ adev->pm.funcs = &cz_dpm_funcs;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.h b/drivers/gpu/drm/amd/amdgpu/cz_dpm.h
new file mode 100644
index 000000000000..782a74107664
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.h
@@ -0,0 +1,237 @@
+/*
+ * 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 __CZ_DPM_H__
+#define __CZ_DPM_H__
+
+#include "smu8_fusion.h"
+
+#define CZ_AT_DFLT 30
+#define CZ_NUM_NBPSTATES 4
+#define CZ_NUM_NBPMEMORY_CLOCK 2
+#define CZ_MAX_HARDWARE_POWERLEVELS 8
+#define CZ_MAX_DISPLAY_CLOCK_LEVEL 8
+#define CZ_MAX_DISPLAYPHY_IDS 10
+
+#define PPCZ_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102
+
+#define SMC_RAM_END 0x40000
+
+#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
+
+/* Do not change the following, it is also defined in SMU8.h */
+#define SMU_EnabledFeatureScoreboard_AcpDpmOn 0x00000001
+#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00100000
+#define SMU_EnabledFeatureScoreboard_UvdDpmOn 0x00800000
+#define SMU_EnabledFeatureScoreboard_VceDpmOn 0x01000000
+
+/* temporary solution to SetMinDeepSleepSclk
+ * should indicate by display adaptor
+ * 10k Hz unit*/
+#define CZ_MIN_DEEP_SLEEP_SCLK 800
+
+enum cz_pt_config_reg_type {
+ CZ_CONFIGREG_MMR = 0,
+ CZ_CONFIGREG_SMC_IND,
+ CZ_CONFIGREG_DIDT_IND,
+ CZ_CONFIGREG_CACHE,
+ CZ_CONFIGREG_MAX
+};
+
+struct cz_pt_config_reg {
+ uint32_t offset;
+ uint32_t mask;
+ uint32_t shift;
+ uint32_t value;
+ enum cz_pt_config_reg_type type;
+};
+
+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_pl {
+ uint32_t sclk;
+ uint8_t vddc_index;
+ uint8_t ds_divider_index;
+ uint8_t ss_divider_index;
+ uint8_t allow_gnb_slow;
+ uint8_t force_nbp_state;
+ uint8_t display_wm;
+ uint8_t vce_wm;
+};
+
+struct cz_ps {
+ struct cz_pl levels[CZ_MAX_HARDWARE_POWERLEVELS];
+ uint32_t num_levels;
+ bool need_dfs_bypass;
+ uint8_t dpm0_pg_nb_ps_lo;
+ uint8_t dpm0_pg_nb_ps_hi;
+ uint8_t dpmx_nb_ps_lo;
+ uint8_t dpmx_nb_ps_hi;
+ bool force_high;
+};
+
+struct cz_displayphy_entry {
+ uint8_t phy_present;
+ uint8_t active_lane_mapping;
+ uint8_t display_conf_type;
+ uint8_t num_active_lanes;
+};
+
+struct cz_displayphy_info {
+ bool phy_access_initialized;
+ struct cz_displayphy_entry entries[CZ_MAX_DISPLAYPHY_IDS];
+};
+
+struct cz_sys_info {
+ uint32_t bootup_uma_clk;
+ uint32_t bootup_sclk;
+ uint32_t dentist_vco_freq;
+ uint32_t nb_dpm_enable;
+ uint32_t nbp_memory_clock[CZ_NUM_NBPMEMORY_CLOCK];
+ uint32_t nbp_n_clock[CZ_NUM_NBPSTATES];
+ uint8_t nbp_voltage_index[CZ_NUM_NBPSTATES];
+ uint32_t display_clock[CZ_MAX_DISPLAY_CLOCK_LEVEL];
+ uint16_t bootup_nb_voltage_index;
+ uint8_t htc_tmp_lmt;
+ uint8_t htc_hyst_lmt;
+ uint32_t uma_channel_number;
+};
+
+struct cz_power_info {
+ uint32_t active_target[CZ_MAX_HARDWARE_POWERLEVELS];
+ struct cz_sys_info sys_info;
+ struct cz_pl boot_pl;
+ bool disable_nb_ps3_in_battery;
+ bool battery_state;
+ uint32_t lowest_valid;
+ uint32_t highest_valid;
+ uint16_t high_voltage_threshold;
+ /* smc offsets */
+ uint32_t sram_end;
+ uint32_t dpm_table_start;
+ uint32_t soft_regs_start;
+ /* dpm SMU tables */
+ uint8_t uvd_level_count;
+ uint8_t vce_level_count;
+ uint8_t acp_level_count;
+ uint32_t fps_high_threshold;
+ uint32_t fps_low_threshold;
+ /* dpm table */
+ 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 uvd_interval;
+ uint8_t vce_boot_level;
+ uint8_t vce_interval;
+ uint8_t acp_boot_level;
+ uint8_t acp_interval;
+
+ uint8_t graphics_boot_level;
+ 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 low_sclk_interrupt_threshold;
+ bool uvd_power_gated;
+ bool vce_power_gated;
+ bool acp_power_gated;
+
+ uint32_t active_process_mask;
+
+ uint32_t mgcg_cgtt_local0;
+ uint32_t mgcg_cgtt_local1;
+ uint32_t clock_slow_down_step;
+ uint32_t skip_clock_slow_down;
+ bool enable_nb_ps_policy;
+ uint32_t voting_clients;
+ uint32_t voltage_drop_threshold;
+ uint32_t gfx_pg_threshold;
+ uint32_t max_sclk_level;
+ /* flags */
+ bool didt_enabled;
+ bool video_start;
+ bool cac_enabled;
+ bool bapm_enabled;
+ bool nb_dpm_enabled_by_driver;
+ bool nb_dpm_enabled;
+ bool auto_thermal_throttling_enabled;
+ bool dpm_enabled;
+ bool need_pptable_upload;
+ /* caps */
+ bool caps_cac;
+ bool caps_power_containment;
+ bool caps_sq_ramping;
+ bool caps_db_ramping;
+ bool caps_td_ramping;
+ bool caps_tcp_ramping;
+ bool caps_sclk_throttle_low_notification;
+ bool caps_fps;
+ bool caps_uvd_dpm;
+ bool caps_uvd_pg;
+ bool caps_vce_dpm;
+ bool caps_vce_pg;
+ bool caps_acp_dpm;
+ bool caps_acp_pg;
+ bool caps_stable_power_state;
+ bool caps_enable_dfs_bypass;
+ bool caps_sclk_ds;
+ bool caps_voltage_island;
+ /* power state */
+ struct amdgpu_ps current_rps;
+ struct cz_ps current_ps;
+ struct amdgpu_ps requested_rps;
+ struct cz_ps requested_ps;
+
+ bool uvd_power_down;
+ bool vce_power_down;
+ bool acp_power_down;
+
+ bool uvd_dynamic_pg;
+};
+
+/* cz_smc.c */
+uint32_t cz_get_argument(struct amdgpu_device *adev);
+int cz_send_msg_to_smc(struct amdgpu_device *adev, uint16_t msg);
+int cz_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
+ uint16_t msg, uint32_t parameter);
+int cz_read_smc_sram_dword(struct amdgpu_device *adev,
+ uint32_t smc_address, uint32_t *value, uint32_t limit);
+int cz_smu_upload_pptable(struct amdgpu_device *adev);
+int cz_smu_download_pptable(struct amdgpu_device *adev, void **table);
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.c b/drivers/gpu/drm/amd/amdgpu/cz_ih.c
new file mode 100644
index 000000000000..bc751bfbcae2
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_ih.h"
+#include "vid.h"
+
+#include "oss/oss_3_0_1_d.h"
+#include "oss/oss_3_0_1_sh_mask.h"
+
+#include "bif/bif_5_1_d.h"
+#include "bif/bif_5_1_sh_mask.h"
+
+/*
+ * Interrupts
+ * Starting with r6xx, interrupts are handled via a ring buffer.
+ * Ring buffers are areas of GPU accessible memory that the GPU
+ * writes interrupt vectors into and the host reads vectors out of.
+ * There is a rptr (read pointer) that determines where the
+ * host is currently reading, and a wptr (write pointer)
+ * which determines where the GPU has written. When the
+ * pointers are equal, the ring is idle. When the GPU
+ * writes vectors to the ring buffer, it increments the
+ * wptr. When there is an interrupt, the host then starts
+ * fetching commands and processing them until the pointers are
+ * equal again at which point it updates the rptr.
+ */
+
+static void cz_ih_set_interrupt_funcs(struct amdgpu_device *adev);
+
+/**
+ * cz_ih_enable_interrupts - Enable the interrupt ring buffer
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Enable the interrupt ring buffer (VI).
+ */
+static void cz_ih_enable_interrupts(struct amdgpu_device *adev)
+{
+ u32 ih_cntl = RREG32(mmIH_CNTL);
+ u32 ih_rb_cntl = RREG32(mmIH_RB_CNTL);
+
+ ih_cntl = REG_SET_FIELD(ih_cntl, IH_CNTL, ENABLE_INTR, 1);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 1);
+ WREG32(mmIH_CNTL, ih_cntl);
+ WREG32(mmIH_RB_CNTL, ih_rb_cntl);
+ adev->irq.ih.enabled = true;
+}
+
+/**
+ * cz_ih_disable_interrupts - Disable the interrupt ring buffer
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Disable the interrupt ring buffer (VI).
+ */
+static void cz_ih_disable_interrupts(struct amdgpu_device *adev)
+{
+ u32 ih_rb_cntl = RREG32(mmIH_RB_CNTL);
+ u32 ih_cntl = RREG32(mmIH_CNTL);
+
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_ENABLE, 0);
+ ih_cntl = REG_SET_FIELD(ih_cntl, IH_CNTL, ENABLE_INTR, 0);
+ WREG32(mmIH_RB_CNTL, ih_rb_cntl);
+ WREG32(mmIH_CNTL, ih_cntl);
+ /* set rptr, wptr to 0 */
+ WREG32(mmIH_RB_RPTR, 0);
+ WREG32(mmIH_RB_WPTR, 0);
+ adev->irq.ih.enabled = false;
+ adev->irq.ih.rptr = 0;
+}
+
+/**
+ * cz_ih_irq_init - init and enable the interrupt ring
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Allocate a ring buffer for the interrupt controller,
+ * enable the RLC, disable interrupts, enable the IH
+ * ring buffer and enable it (VI).
+ * Called at device load and reume.
+ * Returns 0 for success, errors for failure.
+ */
+static int cz_ih_irq_init(struct amdgpu_device *adev)
+{
+ int ret = 0;
+ int rb_bufsz;
+ u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
+ u64 wptr_off;
+
+ /* disable irqs */
+ cz_ih_disable_interrupts(adev);
+
+ /* setup interrupt control */
+ WREG32(mmINTERRUPT_CNTL2, adev->dummy_page.addr >> 8);
+ interrupt_cntl = RREG32(mmINTERRUPT_CNTL);
+ /* INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi
+ * INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN
+ */
+ interrupt_cntl = REG_SET_FIELD(interrupt_cntl, INTERRUPT_CNTL, IH_DUMMY_RD_OVERRIDE, 0);
+ /* INTERRUPT_CNTL__IH_REQ_NONSNOOP_EN_MASK=1 if ring is in non-cacheable memory, e.g., vram */
+ interrupt_cntl = REG_SET_FIELD(interrupt_cntl, INTERRUPT_CNTL, IH_REQ_NONSNOOP_EN, 0);
+ WREG32(mmINTERRUPT_CNTL, interrupt_cntl);
+
+ /* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
+ WREG32(mmIH_RB_BASE, adev->irq.ih.gpu_addr >> 8);
+
+ rb_bufsz = order_base_2(adev->irq.ih.ring_size / 4);
+ ih_rb_cntl = REG_SET_FIELD(0, IH_RB_CNTL, WPTR_OVERFLOW_ENABLE, 1);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_SIZE, rb_bufsz);
+
+ /* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register value is written to memory */
+ ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, WPTR_WRITEBACK_ENABLE, 1);
+
+ /* set the writeback address whether it's enabled or not */
+ wptr_off = adev->wb.gpu_addr + (adev->irq.ih.wptr_offs * 4);
+ WREG32(mmIH_RB_WPTR_ADDR_LO, lower_32_bits(wptr_off));
+ WREG32(mmIH_RB_WPTR_ADDR_HI, upper_32_bits(wptr_off) & 0xFF);
+
+ WREG32(mmIH_RB_CNTL, ih_rb_cntl);
+
+ /* set rptr, wptr to 0 */
+ WREG32(mmIH_RB_RPTR, 0);
+ WREG32(mmIH_RB_WPTR, 0);
+
+ /* Default settings for IH_CNTL (disabled at first) */
+ ih_cntl = RREG32(mmIH_CNTL);
+ ih_cntl = REG_SET_FIELD(ih_cntl, IH_CNTL, MC_VMID, 0);
+
+ if (adev->irq.msi_enabled)
+ ih_cntl = REG_SET_FIELD(ih_cntl, IH_CNTL, RPTR_REARM, 1);
+ WREG32(mmIH_CNTL, ih_cntl);
+
+ pci_set_master(adev->pdev);
+
+ /* enable interrupts */
+ cz_ih_enable_interrupts(adev);
+
+ return ret;
+}
+
+/**
+ * cz_ih_irq_disable - disable interrupts
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Disable interrupts on the hw (VI).
+ */
+static void cz_ih_irq_disable(struct amdgpu_device *adev)
+{
+ cz_ih_disable_interrupts(adev);
+
+ /* Wait and acknowledge irq */
+ mdelay(1);
+}
+
+/**
+ * cz_ih_get_wptr - get the IH ring buffer wptr
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Get the IH ring buffer wptr from either the register
+ * or the writeback memory buffer (VI). Also check for
+ * ring buffer overflow and deal with it.
+ * Used by cz_irq_process(VI).
+ * Returns the value of the wptr.
+ */
+static u32 cz_ih_get_wptr(struct amdgpu_device *adev)
+{
+ u32 wptr, tmp;
+
+ wptr = le32_to_cpu(adev->wb.wb[adev->irq.ih.wptr_offs]);
+
+ if (REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW)) {
+ wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
+ /* When a ring buffer overflow happen start parsing interrupt
+ * from the last not overwritten vector (wptr + 16). Hopefully
+ * this should allow us to catchup.
+ */
+ dev_warn(adev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n",
+ wptr, adev->irq.ih.rptr, (wptr + 16) & adev->irq.ih.ptr_mask);
+ adev->irq.ih.rptr = (wptr + 16) & adev->irq.ih.ptr_mask;
+ tmp = RREG32(mmIH_RB_CNTL);
+ tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
+ WREG32(mmIH_RB_CNTL, tmp);
+ }
+ return (wptr & adev->irq.ih.ptr_mask);
+}
+
+/**
+ * cz_ih_decode_iv - decode an interrupt vector
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Decodes the interrupt vector at the current rptr
+ * position and also advance the position.
+ */
+static void cz_ih_decode_iv(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry)
+{
+ /* wptr/rptr are in bytes! */
+ u32 ring_index = adev->irq.ih.rptr >> 2;
+ uint32_t dw[4];
+
+ dw[0] = le32_to_cpu(adev->irq.ih.ring[ring_index + 0]);
+ dw[1] = le32_to_cpu(adev->irq.ih.ring[ring_index + 1]);
+ dw[2] = le32_to_cpu(adev->irq.ih.ring[ring_index + 2]);
+ dw[3] = le32_to_cpu(adev->irq.ih.ring[ring_index + 3]);
+
+ entry->src_id = dw[0] & 0xff;
+ entry->src_data = dw[1] & 0xfffffff;
+ entry->ring_id = dw[2] & 0xff;
+ entry->vm_id = (dw[2] >> 8) & 0xff;
+ entry->pas_id = (dw[2] >> 16) & 0xffff;
+
+ /* wptr/rptr are in bytes! */
+ adev->irq.ih.rptr += 16;
+}
+
+/**
+ * cz_ih_set_rptr - set the IH ring buffer rptr
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Set the IH ring buffer rptr.
+ */
+static void cz_ih_set_rptr(struct amdgpu_device *adev)
+{
+ WREG32(mmIH_RB_RPTR, adev->irq.ih.rptr);
+}
+
+static int cz_ih_early_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ cz_ih_set_interrupt_funcs(adev);
+ return 0;
+}
+
+static int cz_ih_sw_init(void *handle)
+{
+ int r;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ r = amdgpu_ih_ring_init(adev, 64 * 1024, false);
+ if (r)
+ return r;
+
+ r = amdgpu_irq_init(adev);
+
+ return r;
+}
+
+static int cz_ih_sw_fini(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ amdgpu_irq_fini(adev);
+ amdgpu_ih_ring_fini(adev);
+
+ return 0;
+}
+
+static int cz_ih_hw_init(void *handle)
+{
+ int r;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ r = cz_ih_irq_init(adev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int cz_ih_hw_fini(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ cz_ih_irq_disable(adev);
+
+ return 0;
+}
+
+static int cz_ih_suspend(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ return cz_ih_hw_fini(adev);
+}
+
+static int cz_ih_resume(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ return cz_ih_hw_init(adev);
+}
+
+static bool cz_ih_is_idle(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ u32 tmp = RREG32(mmSRBM_STATUS);
+
+ if (REG_GET_FIELD(tmp, SRBM_STATUS, IH_BUSY))
+ return false;
+
+ return true;
+}
+
+static int cz_ih_wait_for_idle(void *handle)
+{
+ unsigned i;
+ u32 tmp;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ /* read MC_STATUS */
+ tmp = RREG32(mmSRBM_STATUS);
+ if (!REG_GET_FIELD(tmp, SRBM_STATUS, IH_BUSY))
+ return 0;
+ udelay(1);
+ }
+ return -ETIMEDOUT;
+}
+
+static void cz_ih_print_status(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ dev_info(adev->dev, "CZ IH registers\n");
+ dev_info(adev->dev, " SRBM_STATUS=0x%08X\n",
+ RREG32(mmSRBM_STATUS));
+ dev_info(adev->dev, " SRBM_STATUS2=0x%08X\n",
+ RREG32(mmSRBM_STATUS2));
+ dev_info(adev->dev, " INTERRUPT_CNTL=0x%08X\n",
+ RREG32(mmINTERRUPT_CNTL));
+ dev_info(adev->dev, " INTERRUPT_CNTL2=0x%08X\n",
+ RREG32(mmINTERRUPT_CNTL2));
+ dev_info(adev->dev, " IH_CNTL=0x%08X\n",
+ RREG32(mmIH_CNTL));
+ dev_info(adev->dev, " IH_RB_CNTL=0x%08X\n",
+ RREG32(mmIH_RB_CNTL));
+ dev_info(adev->dev, " IH_RB_BASE=0x%08X\n",
+ RREG32(mmIH_RB_BASE));
+ dev_info(adev->dev, " IH_RB_WPTR_ADDR_LO=0x%08X\n",
+ RREG32(mmIH_RB_WPTR_ADDR_LO));
+ dev_info(adev->dev, " IH_RB_WPTR_ADDR_HI=0x%08X\n",
+ RREG32(mmIH_RB_WPTR_ADDR_HI));
+ dev_info(adev->dev, " IH_RB_RPTR=0x%08X\n",
+ RREG32(mmIH_RB_RPTR));
+ dev_info(adev->dev, " IH_RB_WPTR=0x%08X\n",
+ RREG32(mmIH_RB_WPTR));
+}
+
+static int cz_ih_soft_reset(void *handle)
+{
+ u32 srbm_soft_reset = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ u32 tmp = RREG32(mmSRBM_STATUS);
+
+ if (tmp & SRBM_STATUS__IH_BUSY_MASK)
+ srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET,
+ SOFT_RESET_IH, 1);
+
+ if (srbm_soft_reset) {
+ cz_ih_print_status((void *)adev);
+
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+ tmp |= srbm_soft_reset;
+ dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+ WREG32(mmSRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+
+ udelay(50);
+
+ tmp &= ~srbm_soft_reset;
+ WREG32(mmSRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+
+ /* Wait a little for things to settle down */
+ udelay(50);
+
+ cz_ih_print_status((void *)adev);
+ }
+
+ return 0;
+}
+
+static int cz_ih_set_clockgating_state(void *handle,
+ enum amd_clockgating_state state)
+{
+ // TODO
+ return 0;
+}
+
+static int cz_ih_set_powergating_state(void *handle,
+ enum amd_powergating_state state)
+{
+ // TODO
+ return 0;
+}
+
+const struct amd_ip_funcs cz_ih_ip_funcs = {
+ .early_init = cz_ih_early_init,
+ .late_init = NULL,
+ .sw_init = cz_ih_sw_init,
+ .sw_fini = cz_ih_sw_fini,
+ .hw_init = cz_ih_hw_init,
+ .hw_fini = cz_ih_hw_fini,
+ .suspend = cz_ih_suspend,
+ .resume = cz_ih_resume,
+ .is_idle = cz_ih_is_idle,
+ .wait_for_idle = cz_ih_wait_for_idle,
+ .soft_reset = cz_ih_soft_reset,
+ .print_status = cz_ih_print_status,
+ .set_clockgating_state = cz_ih_set_clockgating_state,
+ .set_powergating_state = cz_ih_set_powergating_state,
+};
+
+static const struct amdgpu_ih_funcs cz_ih_funcs = {
+ .get_wptr = cz_ih_get_wptr,
+ .decode_iv = cz_ih_decode_iv,
+ .set_rptr = cz_ih_set_rptr
+};
+
+static void cz_ih_set_interrupt_funcs(struct amdgpu_device *adev)
+{
+ if (adev->irq.ih_funcs == NULL)
+ adev->irq.ih_funcs = &cz_ih_funcs;
+}
+
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.h b/drivers/gpu/drm/amd/amdgpu/cz_ih.h
new file mode 100644
index 000000000000..fc4057a2ecb9
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.h
@@ -0,0 +1,29 @@
+/*
+ * 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 __CZ_IH_H__
+#define __CZ_IH_H__
+
+extern const struct amd_ip_funcs cz_ih_ip_funcs;
+
+#endif /* __CZ_IH_H__ */
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ppsmc.h b/drivers/gpu/drm/amd/amdgpu/cz_ppsmc.h
new file mode 100644
index 000000000000..273616ab43db
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cz_ppsmc.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef CZ_PP_SMC_H
+#define CZ_PP_SMC_H
+
+#pragma pack(push, 1)
+
+/* Fan control algorithm:*/
+#define FDO_MODE_HARDWARE 0
+#define FDO_MODE_PIECE_WISE_LINEAR 1
+
+enum FAN_CONTROL {
+ FAN_CONTROL_FUZZY,
+ FAN_CONTROL_TABLE
+};
+
+enum DPM_ARRAY {
+ DPM_ARRAY_HARD_MAX,
+ DPM_ARRAY_HARD_MIN,
+ DPM_ARRAY_SOFT_MAX,
+ DPM_ARRAY_SOFT_MIN
+};
+
+/*
+ * Return codes for driver to SMC communication.
+ * Leave these #define-s, enums might not be exactly 8-bits on the microcontroller.
+ */
+#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))
+
+/*
+ * Supported driver messages
+ */
+#define PPSMC_MSG_Test ((uint16_t) 0x1)
+#define PPSMC_MSG_GetFeatureStatus ((uint16_t) 0x2)
+#define PPSMC_MSG_EnableAllSmuFeatures ((uint16_t) 0x3)
+#define PPSMC_MSG_DisableAllSmuFeatures ((uint16_t) 0x4)
+#define PPSMC_MSG_OptimizeBattery ((uint16_t) 0x5)
+#define PPSMC_MSG_MaximizePerf ((uint16_t) 0x6)
+#define PPSMC_MSG_UVDPowerOFF ((uint16_t) 0x7)
+#define PPSMC_MSG_UVDPowerON ((uint16_t) 0x8)
+#define PPSMC_MSG_VCEPowerOFF ((uint16_t) 0x9)
+#define PPSMC_MSG_VCEPowerON ((uint16_t) 0xA)
+#define PPSMC_MSG_ACPPowerOFF ((uint16_t) 0xB)
+#define PPSMC_MSG_ACPPowerON ((uint16_t) 0xC)
+#define PPSMC_MSG_SDMAPowerOFF ((uint16_t) 0xD)
+#define PPSMC_MSG_SDMAPowerON ((uint16_t) 0xE)
+#define PPSMC_MSG_XDMAPowerOFF ((uint16_t) 0xF)
+#define PPSMC_MSG_XDMAPowerON ((uint16_t) 0x10)
+#define PPSMC_MSG_SetMinDeepSleepSclk ((uint16_t) 0x11)
+#define PPSMC_MSG_SetSclkSoftMin ((uint16_t) 0x12)
+#define PPSMC_MSG_SetSclkSoftMax ((uint16_t) 0x13)
+#define PPSMC_MSG_SetSclkHardMin ((uint16_t) 0x14)
+#define PPSMC_MSG_SetSclkHardMax ((uint16_t) 0x15)
+#define PPSMC_MSG_SetLclkSoftMin ((uint16_t) 0x16)
+#define PPSMC_MSG_SetLclkSoftMax ((uint16_t) 0x17)
+#define PPSMC_MSG_SetLclkHardMin ((uint16_t) 0x18)
+#define PPSMC_MSG_SetLclkHardMax ((uint16_t) 0x19)
+#define PPSMC_MSG_SetUvdSoftMin ((uint16_t) 0x1A)
+#define PPSMC_MSG_SetUvdSoftMax ((uint16_t) 0x1B)
+#define PPSMC_MSG_SetUvdHardMin ((uint16_t) 0x1C)
+#define PPSMC_MSG_SetUvdHardMax ((uint16_t) 0x1D)
+#define PPSMC_MSG_SetEclkSoftMin ((uint16_t) 0x1E)
+#define PPSMC_MSG_SetEclkSoftMax ((uint16_t) 0x1F)
+#define PPSMC_MSG_SetEclkHardMin ((uint16_t) 0x20)
+#define PPSMC_MSG_SetEclkHardMax ((uint16_t) 0x21)
+#define PPSMC_MSG_SetAclkSoftMin ((uint16_t) 0x22)
+#define PPSMC_MSG_SetAclkSoftMax ((uint16_t) 0x23)
+#define PPSMC_MSG_SetAclkHardMin ((uint16_t) 0x24)
+#define PPSMC_MSG_SetAclkHardMax ((uint16_t) 0x25)
+#define PPSMC_MSG_SetNclkSoftMin ((uint16_t) 0x26)
+#define PPSMC_MSG_SetNclkSoftMax ((uint16_t) 0x27)
+#define PPSMC_MSG_SetNclkHardMin ((uint16_t) 0x28)
+#define PPSMC_MSG_SetNclkHardMax ((uint16_t) 0x29)
+#define PPSMC_MSG_SetPstateSoftMin ((uint16_t) 0x2A)
+#define PPSMC_MSG_SetPstateSoftMax ((uint16_t) 0x2B)
+#define PPSMC_MSG_SetPstateHardMin ((uint16_t) 0x2C)
+#define PPSMC_MSG_SetPstateHardMax ((uint16_t) 0x2D)
+#define PPSMC_MSG_DisableLowMemoryPstate ((uint16_t) 0x2E)
+#define PPSMC_MSG_EnableLowMemoryPstate ((uint16_t) 0x2F)
+#define PPSMC_MSG_UcodeAddressLow ((uint16_t) 0x30)
+#define PPSMC_MSG_UcodeAddressHigh ((uint16_t) 0x31)
+#define PPSMC_MSG_UcodeLoadStatus ((uint16_t) 0x32)
+#define PPSMC_MSG_DriverDramAddrHi ((uint16_t) 0x33)
+#define PPSMC_MSG_DriverDramAddrLo ((uint16_t) 0x34)
+#define PPSMC_MSG_CondExecDramAddrHi ((uint16_t) 0x35)
+#define PPSMC_MSG_CondExecDramAddrLo ((uint16_t) 0x36)
+#define PPSMC_MSG_LoadUcodes ((uint16_t) 0x37)
+#define PPSMC_MSG_DriverResetMode ((uint16_t) 0x38)
+#define PPSMC_MSG_PowerStateNotify ((uint16_t) 0x39)
+#define PPSMC_MSG_SetDisplayPhyConfig ((uint16_t) 0x3A)
+#define PPSMC_MSG_GetMaxSclkLevel ((uint16_t) 0x3B)
+#define PPSMC_MSG_GetMaxLclkLevel ((uint16_t) 0x3C)
+#define PPSMC_MSG_GetMaxUvdLevel ((uint16_t) 0x3D)
+#define PPSMC_MSG_GetMaxEclkLevel ((uint16_t) 0x3E)
+#define PPSMC_MSG_GetMaxAclkLevel ((uint16_t) 0x3F)
+#define PPSMC_MSG_GetMaxNclkLevel ((uint16_t) 0x40)
+#define PPSMC_MSG_GetMaxPstate ((uint16_t) 0x41)
+#define PPSMC_MSG_DramAddrHiVirtual ((uint16_t) 0x42)
+#define PPSMC_MSG_DramAddrLoVirtual ((uint16_t) 0x43)
+#define PPSMC_MSG_DramAddrHiPhysical ((uint16_t) 0x44)
+#define PPSMC_MSG_DramAddrLoPhysical ((uint16_t) 0x45)
+#define PPSMC_MSG_DramBufferSize ((uint16_t) 0x46)
+#define PPSMC_MSG_SetMmPwrLogDramAddrHi ((uint16_t) 0x47)
+#define PPSMC_MSG_SetMmPwrLogDramAddrLo ((uint16_t) 0x48)
+#define PPSMC_MSG_SetClkTableAddrHi ((uint16_t) 0x49)
+#define PPSMC_MSG_SetClkTableAddrLo ((uint16_t) 0x4A)
+#define PPSMC_MSG_GetConservativePowerLimit ((uint16_t) 0x4B)
+
+#define PPSMC_MSG_InitJobs ((uint16_t) 0x252)
+#define PPSMC_MSG_ExecuteJob ((uint16_t) 0x254)
+
+#define PPSMC_MSG_NBDPM_Enable ((uint16_t) 0x140)
+#define PPSMC_MSG_NBDPM_Disable ((uint16_t) 0x141)
+
+#define PPSMC_MSG_DPM_FPS_Mode ((uint16_t) 0x15d)
+#define PPSMC_MSG_DPM_Activity_Mode ((uint16_t) 0x15e)
+
+#define PPSMC_MSG_PmStatusLogStart ((uint16_t) 0x170)
+#define PPSMC_MSG_PmStatusLogSample ((uint16_t) 0x171)
+
+#define PPSMC_MSG_AllowLowSclkInterrupt ((uint16_t) 0x184)
+#define PPSMC_MSG_MmPowerMonitorStart ((uint16_t) 0x18F)
+#define PPSMC_MSG_MmPowerMonitorStop ((uint16_t) 0x190)
+#define PPSMC_MSG_MmPowerMonitorRestart ((uint16_t) 0x191)
+
+#define PPSMC_MSG_SetClockGateMask ((uint16_t) 0x260)
+#define PPSMC_MSG_SetFpsThresholdLo ((uint16_t) 0x264)
+#define PPSMC_MSG_SetFpsThresholdHi ((uint16_t) 0x265)
+#define PPSMC_MSG_SetLowSclkIntrThreshold ((uint16_t) 0x266)
+
+#define PPSMC_MSG_ClkTableXferToDram ((uint16_t) 0x267)
+#define PPSMC_MSG_ClkTableXferToSmu ((uint16_t) 0x268)
+#define PPSMC_MSG_GetAverageGraphicsActivity ((uint16_t) 0x269)
+#define PPSMC_MSG_GetAverageGioActivity ((uint16_t) 0x26A)
+#define PPSMC_MSG_SetLoggerBufferSize ((uint16_t) 0x26B)
+#define PPSMC_MSG_SetLoggerAddressHigh ((uint16_t) 0x26C)
+#define PPSMC_MSG_SetLoggerAddressLow ((uint16_t) 0x26D)
+#define PPSMC_MSG_SetWatermarkFrequency ((uint16_t) 0x26E)
+
+/* REMOVE LATER*/
+#define PPSMC_MSG_DPM_ForceState ((uint16_t) 0x104)
+
+/* Feature Enable Masks*/
+#define NB_DPM_MASK 0x00000800
+#define VDDGFX_MASK 0x00800000
+#define VCE_DPM_MASK 0x00400000
+#define ACP_DPM_MASK 0x00040000
+#define UVD_DPM_MASK 0x00010000
+#define GFX_CU_PG_MASK 0x00004000
+#define SCLK_DPM_MASK 0x00080000
+
+#if !defined(SMC_MICROCODE)
+#pragma pack(pop)
+
+#endif
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_smc.c b/drivers/gpu/drm/amd/amdgpu/cz_smc.c
new file mode 100644
index 000000000000..a72ffc7d6c26
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cz_smc.c
@@ -0,0 +1,962 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "amdgpu.h"
+#include "smu8.h"
+#include "smu8_fusion.h"
+#include "cz_ppsmc.h"
+#include "cz_smumgr.h"
+#include "smu_ucode_xfer_cz.h"
+#include "amdgpu_ucode.h"
+
+#include "smu/smu_8_0_d.h"
+#include "smu/smu_8_0_sh_mask.h"
+#include "gca/gfx_8_0_d.h"
+#include "gca/gfx_8_0_sh_mask.h"
+
+uint32_t cz_get_argument(struct amdgpu_device *adev)
+{
+ return RREG32(mmSMU_MP1_SRBM2P_ARG_0);
+}
+
+static struct cz_smu_private_data *cz_smu_get_priv(struct amdgpu_device *adev)
+{
+ struct cz_smu_private_data *priv =
+ (struct cz_smu_private_data *)(adev->smu.priv);
+
+ return priv;
+}
+
+int cz_send_msg_to_smc_async(struct amdgpu_device *adev, u16 msg)
+{
+ int i;
+ u32 content = 0, tmp;
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = REG_GET_FIELD(RREG32(mmSMU_MP1_SRBM2P_RESP_0),
+ SMU_MP1_SRBM2P_RESP_0, CONTENT);
+ if (content != tmp)
+ break;
+ udelay(1);
+ }
+
+ /* timeout means wrong logic*/
+ if (i == adev->usec_timeout)
+ return -EINVAL;
+
+ WREG32(mmSMU_MP1_SRBM2P_RESP_0, 0);
+ WREG32(mmSMU_MP1_SRBM2P_MSG_0, msg);
+
+ return 0;
+}
+
+int cz_send_msg_to_smc(struct amdgpu_device *adev, u16 msg)
+{
+ int i;
+ u32 content = 0, tmp = 0;
+
+ if (cz_send_msg_to_smc_async(adev, msg))
+ return -EINVAL;
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = REG_GET_FIELD(RREG32(mmSMU_MP1_SRBM2P_RESP_0),
+ SMU_MP1_SRBM2P_RESP_0, CONTENT);
+ if (content != tmp)
+ break;
+ udelay(1);
+ }
+
+ /* timeout means wrong logic*/
+ if (i == adev->usec_timeout)
+ return -EINVAL;
+
+ if (PPSMC_Result_OK != tmp) {
+ dev_err(adev->dev, "SMC Failed to send Message.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int cz_send_msg_to_smc_with_parameter_async(struct amdgpu_device *adev,
+ u16 msg, u32 parameter)
+{
+ WREG32(mmSMU_MP1_SRBM2P_ARG_0, parameter);
+ return cz_send_msg_to_smc_async(adev, msg);
+}
+
+int cz_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
+ u16 msg, u32 parameter)
+{
+ WREG32(mmSMU_MP1_SRBM2P_ARG_0, parameter);
+ return cz_send_msg_to_smc(adev, msg);
+}
+
+static int cz_set_smc_sram_address(struct amdgpu_device *adev,
+ u32 smc_address, u32 limit)
+{
+ if (smc_address & 3)
+ return -EINVAL;
+ if ((smc_address + 3) > limit)
+ return -EINVAL;
+
+ WREG32(mmMP0PUB_IND_INDEX_0, SMN_MP1_SRAM_START_ADDR + smc_address);
+
+ return 0;
+}
+
+int cz_read_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
+ u32 *value, u32 limit)
+{
+ int ret;
+
+ ret = cz_set_smc_sram_address(adev, smc_address, limit);
+ if (ret)
+ return ret;
+
+ *value = RREG32(mmMP0PUB_IND_DATA_0);
+
+ return 0;
+}
+
+int cz_write_smc_sram_dword(struct amdgpu_device *adev, u32 smc_address,
+ u32 value, u32 limit)
+{
+ int ret;
+
+ ret = cz_set_smc_sram_address(adev, smc_address, limit);
+ if (ret)
+ return ret;
+
+ WREG32(mmMP0PUB_IND_DATA_0, value);
+
+ return 0;
+}
+
+static int cz_smu_request_load_fw(struct amdgpu_device *adev)
+{
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+
+ uint32_t smc_addr = SMU8_FIRMWARE_HEADER_LOCATION +
+ offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
+
+ cz_write_smc_sram_dword(adev, smc_addr, 0, smc_addr + 4);
+
+ /*prepare toc buffers*/
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_DriverDramAddrHi,
+ priv->toc_buffer.mc_addr_high);
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_DriverDramAddrLo,
+ priv->toc_buffer.mc_addr_low);
+ cz_send_msg_to_smc(adev, PPSMC_MSG_InitJobs);
+
+ /*execute jobs*/
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_ExecuteJob,
+ priv->toc_entry_aram);
+
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_ExecuteJob,
+ priv->toc_entry_power_profiling_index);
+
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_ExecuteJob,
+ priv->toc_entry_initialize_index);
+
+ return 0;
+}
+
+/*
+ *Check if the FW has been loaded, SMU will not return if loading
+ *has not finished.
+ */
+static int cz_smu_check_fw_load_finish(struct amdgpu_device *adev,
+ uint32_t fw_mask)
+{
+ int i;
+ uint32_t index = SMN_MP1_SRAM_START_ADDR +
+ SMU8_FIRMWARE_HEADER_LOCATION +
+ offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus);
+
+ WREG32(mmMP0PUB_IND_INDEX, index);
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if (fw_mask == (RREG32(mmMP0PUB_IND_DATA) & fw_mask))
+ break;
+ udelay(1);
+ }
+
+ if (i >= adev->usec_timeout) {
+ dev_err(adev->dev,
+ "SMU check loaded firmware failed, expecting 0x%x, getting 0x%x",
+ fw_mask, RREG32(mmMP0PUB_IND_DATA));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * interfaces for different ip blocks to check firmware loading status
+ * 0 for success otherwise failed
+ */
+static int cz_smu_check_finished(struct amdgpu_device *adev,
+ enum AMDGPU_UCODE_ID id)
+{
+ switch (id) {
+ case AMDGPU_UCODE_ID_SDMA0:
+ if (adev->smu.fw_flags & AMDGPU_SDMA0_UCODE_LOADED)
+ return 0;
+ break;
+ case AMDGPU_UCODE_ID_SDMA1:
+ if (adev->smu.fw_flags & AMDGPU_SDMA1_UCODE_LOADED)
+ return 0;
+ break;
+ case AMDGPU_UCODE_ID_CP_CE:
+ if (adev->smu.fw_flags & AMDGPU_CPCE_UCODE_LOADED)
+ return 0;
+ break;
+ case AMDGPU_UCODE_ID_CP_PFP:
+ if (adev->smu.fw_flags & AMDGPU_CPPFP_UCODE_LOADED)
+ return 0;
+ case AMDGPU_UCODE_ID_CP_ME:
+ if (adev->smu.fw_flags & AMDGPU_CPME_UCODE_LOADED)
+ return 0;
+ break;
+ case AMDGPU_UCODE_ID_CP_MEC1:
+ if (adev->smu.fw_flags & AMDGPU_CPMEC1_UCODE_LOADED)
+ return 0;
+ break;
+ case AMDGPU_UCODE_ID_CP_MEC2:
+ if (adev->smu.fw_flags & AMDGPU_CPMEC2_UCODE_LOADED)
+ return 0;
+ break;
+ case AMDGPU_UCODE_ID_RLC_G:
+ if (adev->smu.fw_flags & AMDGPU_CPRLC_UCODE_LOADED)
+ return 0;
+ break;
+ case AMDGPU_UCODE_ID_MAXIMUM:
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+static int cz_load_mec_firmware(struct amdgpu_device *adev)
+{
+ struct amdgpu_firmware_info *ucode =
+ &adev->firmware.ucode[AMDGPU_UCODE_ID_CP_MEC1];
+ uint32_t reg_data;
+ uint32_t tmp;
+
+ if (ucode->fw == NULL)
+ return -EINVAL;
+
+ /* Disable MEC parsing/prefetching */
+ tmp = RREG32(mmCP_MEC_CNTL);
+ tmp = REG_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME1_HALT, 1);
+ tmp = REG_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME2_HALT, 1);
+ WREG32(mmCP_MEC_CNTL, tmp);
+
+ tmp = RREG32(mmCP_CPC_IC_BASE_CNTL);
+ tmp = REG_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, VMID, 0);
+ tmp = REG_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, ATC, 0);
+ tmp = REG_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0);
+ tmp = REG_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, MTYPE, 1);
+ WREG32(mmCP_CPC_IC_BASE_CNTL, tmp);
+
+ reg_data = lower_32_bits(ucode->mc_addr) &
+ REG_FIELD_MASK(CP_CPC_IC_BASE_LO, IC_BASE_LO);
+ WREG32(mmCP_CPC_IC_BASE_LO, reg_data);
+
+ reg_data = upper_32_bits(ucode->mc_addr) &
+ REG_FIELD_MASK(CP_CPC_IC_BASE_HI, IC_BASE_HI);
+ WREG32(mmCP_CPC_IC_BASE_HI, reg_data);
+
+ return 0;
+}
+
+int cz_smu_start(struct amdgpu_device *adev)
+{
+ 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_smu_request_load_fw(adev);
+ ret = cz_smu_check_fw_load_finish(adev, fw_to_check);
+ if (ret)
+ return ret;
+
+ /* manually load MEC firmware for CZ */
+ if (adev->asic_type == CHIP_CARRIZO) {
+ ret = cz_load_mec_firmware(adev);
+ if (ret) {
+ dev_err(adev->dev, "(%d) Mec Firmware load failed\n", ret);
+ return ret;
+ }
+ }
+
+ /* setup fw load flag */
+ adev->smu.fw_flags = AMDGPU_SDMA0_UCODE_LOADED |
+ AMDGPU_SDMA1_UCODE_LOADED |
+ AMDGPU_CPCE_UCODE_LOADED |
+ AMDGPU_CPPFP_UCODE_LOADED |
+ AMDGPU_CPME_UCODE_LOADED |
+ AMDGPU_CPMEC1_UCODE_LOADED |
+ AMDGPU_CPMEC2_UCODE_LOADED |
+ AMDGPU_CPRLC_UCODE_LOADED;
+
+ return ret;
+}
+
+static uint32_t cz_convert_fw_type(uint32_t fw_type)
+{
+ enum AMDGPU_UCODE_ID result = AMDGPU_UCODE_ID_MAXIMUM;
+
+ switch (fw_type) {
+ case UCODE_ID_SDMA0:
+ result = AMDGPU_UCODE_ID_SDMA0;
+ break;
+ case UCODE_ID_SDMA1:
+ result = AMDGPU_UCODE_ID_SDMA1;
+ break;
+ case UCODE_ID_CP_CE:
+ result = AMDGPU_UCODE_ID_CP_CE;
+ break;
+ case UCODE_ID_CP_PFP:
+ result = AMDGPU_UCODE_ID_CP_PFP;
+ break;
+ case UCODE_ID_CP_ME:
+ result = AMDGPU_UCODE_ID_CP_ME;
+ break;
+ case UCODE_ID_CP_MEC_JT1:
+ case UCODE_ID_CP_MEC_JT2:
+ result = AMDGPU_UCODE_ID_CP_MEC1;
+ break;
+ case UCODE_ID_RLC_G:
+ result = AMDGPU_UCODE_ID_RLC_G;
+ break;
+ default:
+ DRM_ERROR("UCode type is out of range!");
+ }
+
+ return result;
+}
+
+static uint8_t cz_smu_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 int cz_smu_populate_single_firmware_entry(struct amdgpu_device *adev,
+ enum cz_scratch_entry firmware_enum,
+ struct cz_buffer_entry *entry)
+{
+ uint64_t gpu_addr;
+ uint32_t data_size;
+ uint8_t ucode_id = cz_smu_translate_firmware_enum_to_arg(firmware_enum);
+ enum AMDGPU_UCODE_ID id = cz_convert_fw_type(ucode_id);
+ struct amdgpu_firmware_info *ucode = &adev->firmware.ucode[id];
+ const struct gfx_firmware_header_v1_0 *header;
+
+ if (ucode->fw == NULL)
+ return -EINVAL;
+
+ gpu_addr = ucode->mc_addr;
+ header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data;
+ data_size = le32_to_cpu(header->header.ucode_size_bytes);
+
+ if ((firmware_enum == CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1) ||
+ (firmware_enum == CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2)) {
+ gpu_addr += le32_to_cpu(header->jt_offset) << 2;
+ data_size = le32_to_cpu(header->jt_size) << 2;
+ }
+
+ entry->mc_addr_low = lower_32_bits(gpu_addr);
+ entry->mc_addr_high = upper_32_bits(gpu_addr);
+ entry->data_size = data_size;
+ entry->firmware_ID = firmware_enum;
+
+ return 0;
+}
+
+static int cz_smu_populate_single_scratch_entry(struct amdgpu_device *adev,
+ enum cz_scratch_entry scratch_type,
+ uint32_t size_in_byte,
+ struct cz_buffer_entry *entry)
+{
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+ uint64_t mc_addr = (((uint64_t) priv->smu_buffer.mc_addr_high) << 32) |
+ priv->smu_buffer.mc_addr_low;
+ mc_addr += size_in_byte;
+
+ priv->smu_buffer_used_bytes += size_in_byte;
+ entry->data_size = size_in_byte;
+ entry->kaddr = priv->smu_buffer.kaddr + priv->smu_buffer_used_bytes;
+ entry->mc_addr_low = lower_32_bits(mc_addr);
+ entry->mc_addr_high = upper_32_bits(mc_addr);
+ entry->firmware_ID = scratch_type;
+
+ return 0;
+}
+
+static int cz_smu_populate_single_ucode_load_task(struct amdgpu_device *adev,
+ enum cz_scratch_entry firmware_enum,
+ bool is_last)
+{
+ uint8_t i;
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+ struct TOC *toc = (struct TOC *)priv->toc_buffer.kaddr;
+ struct SMU_Task *task = &toc->tasks[priv->toc_entry_used_count++];
+
+ task->type = TASK_TYPE_UCODE_LOAD;
+ task->arg = cz_smu_translate_firmware_enum_to_arg(firmware_enum);
+ task->next = is_last ? END_OF_TASK_LIST : priv->toc_entry_used_count;
+
+ for (i = 0; i < priv->driver_buffer_length; i++)
+ if (priv->driver_buffer[i].firmware_ID == firmware_enum)
+ break;
+
+ if (i >= priv->driver_buffer_length) {
+ dev_err(adev->dev, "Invalid Firmware Type\n");
+ return -EINVAL;
+ }
+
+ task->addr.low = priv->driver_buffer[i].mc_addr_low;
+ task->addr.high = priv->driver_buffer[i].mc_addr_high;
+ task->size_bytes = priv->driver_buffer[i].data_size;
+
+ return 0;
+}
+
+static int cz_smu_populate_single_scratch_task(struct amdgpu_device *adev,
+ enum cz_scratch_entry firmware_enum,
+ uint8_t type, bool is_last)
+{
+ uint8_t i;
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+ struct TOC *toc = (struct TOC *)priv->toc_buffer.kaddr;
+ struct SMU_Task *task = &toc->tasks[priv->toc_entry_used_count++];
+
+ task->type = type;
+ task->arg = cz_smu_translate_firmware_enum_to_arg(firmware_enum);
+ task->next = is_last ? END_OF_TASK_LIST : priv->toc_entry_used_count;
+
+ for (i = 0; i < priv->scratch_buffer_length; i++)
+ if (priv->scratch_buffer[i].firmware_ID == firmware_enum)
+ break;
+
+ if (i >= priv->scratch_buffer_length) {
+ dev_err(adev->dev, "Invalid Firmware Type\n");
+ return -EINVAL;
+ }
+
+ task->addr.low = priv->scratch_buffer[i].mc_addr_low;
+ task->addr.high = priv->scratch_buffer[i].mc_addr_high;
+ task->size_bytes = priv->scratch_buffer[i].data_size;
+
+ if (CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS == firmware_enum) {
+ struct cz_ih_meta_data *pIHReg_restore =
+ (struct cz_ih_meta_data *)priv->scratch_buffer[i].kaddr;
+ pIHReg_restore->command =
+ METADATA_CMD_MODE0 | METADATA_PERFORM_ON_LOAD;
+ }
+
+ return 0;
+}
+
+static int cz_smu_construct_toc_for_rlc_aram_save(struct amdgpu_device *adev)
+{
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+ priv->toc_entry_aram = priv->toc_entry_used_count;
+ cz_smu_populate_single_scratch_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
+ TASK_TYPE_UCODE_SAVE, true);
+
+ return 0;
+}
+
+static int cz_smu_construct_toc_for_vddgfx_enter(struct amdgpu_device *adev)
+{
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+ struct TOC *toc = (struct TOC *)priv->toc_buffer.kaddr;
+
+ toc->JobList[JOB_GFX_SAVE] = (uint8_t)priv->toc_entry_used_count;
+ cz_smu_populate_single_scratch_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
+ TASK_TYPE_UCODE_SAVE, false);
+ cz_smu_populate_single_scratch_task(adev,
+ 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 amdgpu_device *adev)
+{
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+ struct TOC *toc = (struct TOC *)priv->toc_buffer.kaddr;
+
+ toc->JobList[JOB_GFX_RESTORE] = (uint8_t)priv->toc_entry_used_count;
+
+ /* populate ucode */
+ if (adev->firmware.smu_load) {
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false);
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false);
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, false);
+ }
+
+ /* populate scratch */
+ cz_smu_populate_single_scratch_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
+ TASK_TYPE_UCODE_LOAD, false);
+ cz_smu_populate_single_scratch_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
+ TASK_TYPE_UCODE_LOAD, false);
+ cz_smu_populate_single_scratch_task(adev,
+ 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 amdgpu_device *adev)
+{
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+
+ priv->toc_entry_power_profiling_index = priv->toc_entry_used_count;
+
+ cz_smu_populate_single_scratch_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
+ TASK_TYPE_INITIALIZE, true);
+ return 0;
+}
+
+static int cz_smu_construct_toc_for_bootup(struct amdgpu_device *adev)
+{
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+
+ priv->toc_entry_initialize_index = priv->toc_entry_used_count;
+
+ if (adev->firmware.smu_load) {
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false);
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, false);
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false);
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false);
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false);
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false);
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false);
+ cz_smu_populate_single_ucode_load_task(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, true);
+ }
+
+ return 0;
+}
+
+static int cz_smu_construct_toc_for_clock_table(struct amdgpu_device *adev)
+{
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+
+ priv->toc_entry_clock_table = priv->toc_entry_used_count;
+
+ cz_smu_populate_single_scratch_task(adev,
+ CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
+ TASK_TYPE_INITIALIZE, true);
+
+ return 0;
+}
+
+static int cz_smu_initialize_toc_empty_job_list(struct amdgpu_device *adev)
+{
+ int i;
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+ struct TOC *toc = (struct TOC *)priv->toc_buffer.kaddr;
+
+ for (i = 0; i < NUM_JOBLIST_ENTRIES; i++)
+ toc->JobList[i] = (uint8_t)IGNORE_JOB;
+
+ return 0;
+}
+
+/*
+ * cz smu uninitialization
+ */
+int cz_smu_fini(struct amdgpu_device *adev)
+{
+ amdgpu_bo_unref(&adev->smu.toc_buf);
+ amdgpu_bo_unref(&adev->smu.smu_buf);
+ kfree(adev->smu.priv);
+ adev->smu.priv = NULL;
+ if (adev->firmware.smu_load)
+ amdgpu_ucode_fini_bo(adev);
+
+ return 0;
+}
+
+int cz_smu_download_pptable(struct amdgpu_device *adev, void **table)
+{
+ uint8_t i;
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+
+ for (i = 0; i < priv->scratch_buffer_length; i++)
+ if (priv->scratch_buffer[i].firmware_ID ==
+ CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE)
+ break;
+
+ if (i >= priv->scratch_buffer_length) {
+ dev_err(adev->dev, "Invalid Scratch Type\n");
+ return -EINVAL;
+ }
+
+ *table = (struct SMU8_Fusion_ClkTable *)priv->scratch_buffer[i].kaddr;
+
+ /* prepare buffer for pptable */
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetClkTableAddrHi,
+ priv->scratch_buffer[i].mc_addr_high);
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetClkTableAddrLo,
+ priv->scratch_buffer[i].mc_addr_low);
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_ExecuteJob,
+ priv->toc_entry_clock_table);
+
+ /* actual downloading */
+ cz_send_msg_to_smc(adev, PPSMC_MSG_ClkTableXferToDram);
+
+ return 0;
+}
+
+int cz_smu_upload_pptable(struct amdgpu_device *adev)
+{
+ uint8_t i;
+ struct cz_smu_private_data *priv = cz_smu_get_priv(adev);
+
+ for (i = 0; i < priv->scratch_buffer_length; i++)
+ if (priv->scratch_buffer[i].firmware_ID ==
+ CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE)
+ break;
+
+ if (i >= priv->scratch_buffer_length) {
+ dev_err(adev->dev, "Invalid Scratch Type\n");
+ return -EINVAL;
+ }
+
+ /* prepare SMU */
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetClkTableAddrHi,
+ priv->scratch_buffer[i].mc_addr_high);
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetClkTableAddrLo,
+ priv->scratch_buffer[i].mc_addr_low);
+ cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_ExecuteJob,
+ priv->toc_entry_clock_table);
+
+ /* actual uploading */
+ cz_send_msg_to_smc(adev, PPSMC_MSG_ClkTableXferToSmu);
+
+ return 0;
+}
+
+/*
+ * cz smumgr functions initialization
+ */
+static const struct amdgpu_smumgr_funcs cz_smumgr_funcs = {
+ .check_fw_load_finish = cz_smu_check_finished,
+ .request_smu_load_fw = NULL,
+ .request_smu_specific_fw = NULL,
+};
+
+/*
+ * cz smu initialization
+ */
+int cz_smu_init(struct amdgpu_device *adev)
+{
+ int ret = -EINVAL;
+ uint64_t mc_addr = 0;
+ struct amdgpu_bo **toc_buf = &adev->smu.toc_buf;
+ struct amdgpu_bo **smu_buf = &adev->smu.smu_buf;
+ void *toc_buf_ptr = NULL;
+ void *smu_buf_ptr = NULL;
+
+ struct cz_smu_private_data *priv =
+ kzalloc(sizeof(struct cz_smu_private_data), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ /* allocate firmware buffers */
+ if (adev->firmware.smu_load)
+ amdgpu_ucode_init_bo(adev);
+
+ adev->smu.priv = priv;
+ adev->smu.fw_flags = 0;
+ priv->toc_buffer.data_size = 4096;
+
+ priv->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);
+
+ /* prepare toc buffer and smu buffer:
+ * 1. create amdgpu_bo for toc buffer and smu buffer
+ * 2. pin mc address
+ * 3. map kernel virtual address
+ */
+ ret = amdgpu_bo_create(adev, priv->toc_buffer.data_size, PAGE_SIZE,
+ true, AMDGPU_GEM_DOMAIN_GTT, 0, NULL, toc_buf);
+
+ if (ret) {
+ dev_err(adev->dev, "(%d) SMC TOC buffer allocation failed\n", ret);
+ return ret;
+ }
+
+ ret = amdgpu_bo_create(adev, priv->smu_buffer.data_size, PAGE_SIZE,
+ true, AMDGPU_GEM_DOMAIN_GTT, 0, NULL, smu_buf);
+
+ if (ret) {
+ dev_err(adev->dev, "(%d) SMC Internal buffer allocation failed\n", ret);
+ return ret;
+ }
+
+ /* toc buffer reserve/pin/map */
+ ret = amdgpu_bo_reserve(adev->smu.toc_buf, false);
+ if (ret) {
+ amdgpu_bo_unref(&adev->smu.toc_buf);
+ dev_err(adev->dev, "(%d) SMC TOC buffer reserve failed\n", ret);
+ return ret;
+ }
+
+ ret = amdgpu_bo_pin(adev->smu.toc_buf, AMDGPU_GEM_DOMAIN_GTT, &mc_addr);
+ if (ret) {
+ amdgpu_bo_unreserve(adev->smu.toc_buf);
+ amdgpu_bo_unref(&adev->smu.toc_buf);
+ dev_err(adev->dev, "(%d) SMC TOC buffer pin failed\n", ret);
+ return ret;
+ }
+
+ ret = amdgpu_bo_kmap(*toc_buf, &toc_buf_ptr);
+ if (ret)
+ goto smu_init_failed;
+
+ amdgpu_bo_unreserve(adev->smu.toc_buf);
+
+ priv->toc_buffer.mc_addr_low = lower_32_bits(mc_addr);
+ priv->toc_buffer.mc_addr_high = upper_32_bits(mc_addr);
+ priv->toc_buffer.kaddr = toc_buf_ptr;
+
+ /* smu buffer reserve/pin/map */
+ ret = amdgpu_bo_reserve(adev->smu.smu_buf, false);
+ if (ret) {
+ amdgpu_bo_unref(&adev->smu.smu_buf);
+ dev_err(adev->dev, "(%d) SMC Internal buffer reserve failed\n", ret);
+ return ret;
+ }
+
+ ret = amdgpu_bo_pin(adev->smu.smu_buf, AMDGPU_GEM_DOMAIN_GTT, &mc_addr);
+ if (ret) {
+ amdgpu_bo_unreserve(adev->smu.smu_buf);
+ amdgpu_bo_unref(&adev->smu.smu_buf);
+ dev_err(adev->dev, "(%d) SMC Internal buffer pin failed\n", ret);
+ return ret;
+ }
+
+ ret = amdgpu_bo_kmap(*smu_buf, &smu_buf_ptr);
+ if (ret)
+ goto smu_init_failed;
+
+ amdgpu_bo_unreserve(adev->smu.smu_buf);
+
+ priv->smu_buffer.mc_addr_low = lower_32_bits(mc_addr);
+ priv->smu_buffer.mc_addr_high = upper_32_bits(mc_addr);
+ priv->smu_buffer.kaddr = smu_buf_ptr;
+
+ if (adev->firmware.smu_load) {
+ if (cz_smu_populate_single_firmware_entry(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0,
+ &priv->driver_buffer[priv->driver_buffer_length++]))
+ goto smu_init_failed;
+ if (cz_smu_populate_single_firmware_entry(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1,
+ &priv->driver_buffer[priv->driver_buffer_length++]))
+ goto smu_init_failed;
+ if (cz_smu_populate_single_firmware_entry(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE,
+ &priv->driver_buffer[priv->driver_buffer_length++]))
+ goto smu_init_failed;
+ if (cz_smu_populate_single_firmware_entry(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP,
+ &priv->driver_buffer[priv->driver_buffer_length++]))
+ goto smu_init_failed;
+ if (cz_smu_populate_single_firmware_entry(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME,
+ &priv->driver_buffer[priv->driver_buffer_length++]))
+ goto smu_init_failed;
+ if (cz_smu_populate_single_firmware_entry(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1,
+ &priv->driver_buffer[priv->driver_buffer_length++]))
+ goto smu_init_failed;
+ if (cz_smu_populate_single_firmware_entry(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2,
+ &priv->driver_buffer[priv->driver_buffer_length++]))
+ goto smu_init_failed;
+ if (cz_smu_populate_single_firmware_entry(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G,
+ &priv->driver_buffer[priv->driver_buffer_length++]))
+ goto smu_init_failed;
+ }
+
+ if (cz_smu_populate_single_scratch_entry(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH,
+ UCODE_ID_RLC_SCRATCH_SIZE_BYTE,
+ &priv->scratch_buffer[priv->scratch_buffer_length++]))
+ goto smu_init_failed;
+ if (cz_smu_populate_single_scratch_entry(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM,
+ UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE,
+ &priv->scratch_buffer[priv->scratch_buffer_length++]))
+ goto smu_init_failed;
+ if (cz_smu_populate_single_scratch_entry(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM,
+ UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE,
+ &priv->scratch_buffer[priv->scratch_buffer_length++]))
+ goto smu_init_failed;
+ if (cz_smu_populate_single_scratch_entry(adev,
+ CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING,
+ sizeof(struct SMU8_MultimediaPowerLogData),
+ &priv->scratch_buffer[priv->scratch_buffer_length++]))
+ goto smu_init_failed;
+ if (cz_smu_populate_single_scratch_entry(adev,
+ CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE,
+ sizeof(struct SMU8_Fusion_ClkTable),
+ &priv->scratch_buffer[priv->scratch_buffer_length++]))
+ goto smu_init_failed;
+
+ cz_smu_initialize_toc_empty_job_list(adev);
+ cz_smu_construct_toc_for_rlc_aram_save(adev);
+ cz_smu_construct_toc_for_vddgfx_enter(adev);
+ cz_smu_construct_toc_for_vddgfx_exit(adev);
+ cz_smu_construct_toc_for_power_profiling(adev);
+ cz_smu_construct_toc_for_bootup(adev);
+ cz_smu_construct_toc_for_clock_table(adev);
+ /* init the smumgr functions */
+ adev->smu.smumgr_funcs = &cz_smumgr_funcs;
+
+ return 0;
+
+smu_init_failed:
+ amdgpu_bo_unref(toc_buf);
+ amdgpu_bo_unref(smu_buf);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_smumgr.h b/drivers/gpu/drm/amd/amdgpu/cz_smumgr.h
new file mode 100644
index 000000000000..924d355b4e2c
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/cz_smumgr.h
@@ -0,0 +1,94 @@
+/*
+ * 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 __CZ_SMC_H__
+#define __CZ_SMC_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;
+};
+
+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_smu_private_data {
+ 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 driver_buffer[MAX_NUM_FIRMWARE];
+ struct cz_buffer_entry scratch_buffer[MAX_NUM_SCRATCH];
+};
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
new file mode 100644
index 000000000000..5cde635978f9
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -0,0 +1,3802 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_pm.h"
+#include "amdgpu_i2c.h"
+#include "vid.h"
+#include "atom.h"
+#include "amdgpu_atombios.h"
+#include "atombios_crtc.h"
+#include "atombios_encoders.h"
+#include "amdgpu_pll.h"
+#include "amdgpu_connectors.h"
+
+#include "dce/dce_10_0_d.h"
+#include "dce/dce_10_0_sh_mask.h"
+#include "dce/dce_10_0_enum.h"
+#include "oss/oss_3_0_d.h"
+#include "oss/oss_3_0_sh_mask.h"
+#include "gmc/gmc_8_1_d.h"
+#include "gmc/gmc_8_1_sh_mask.h"
+
+static void dce_v10_0_set_display_funcs(struct amdgpu_device *adev);
+static void dce_v10_0_set_irq_funcs(struct amdgpu_device *adev);
+
+static const u32 crtc_offsets[] =
+{
+ CRTC0_REGISTER_OFFSET,
+ CRTC1_REGISTER_OFFSET,
+ CRTC2_REGISTER_OFFSET,
+ CRTC3_REGISTER_OFFSET,
+ CRTC4_REGISTER_OFFSET,
+ CRTC5_REGISTER_OFFSET,
+ CRTC6_REGISTER_OFFSET
+};
+
+static const u32 hpd_offsets[] =
+{
+ HPD0_REGISTER_OFFSET,
+ HPD1_REGISTER_OFFSET,
+ HPD2_REGISTER_OFFSET,
+ HPD3_REGISTER_OFFSET,
+ HPD4_REGISTER_OFFSET,
+ HPD5_REGISTER_OFFSET
+};
+
+static const uint32_t dig_offsets[] = {
+ DIG0_REGISTER_OFFSET,
+ DIG1_REGISTER_OFFSET,
+ DIG2_REGISTER_OFFSET,
+ DIG3_REGISTER_OFFSET,
+ DIG4_REGISTER_OFFSET,
+ DIG5_REGISTER_OFFSET,
+ DIG6_REGISTER_OFFSET
+};
+
+static const struct {
+ uint32_t reg;
+ uint32_t vblank;
+ uint32_t vline;
+ uint32_t hpd;
+
+} interrupt_status_offsets[] = { {
+ .reg = mmDISP_INTERRUPT_STATUS,
+ .vblank = DISP_INTERRUPT_STATUS__LB_D1_VBLANK_INTERRUPT_MASK,
+ .vline = DISP_INTERRUPT_STATUS__LB_D1_VLINE_INTERRUPT_MASK,
+ .hpd = DISP_INTERRUPT_STATUS__DC_HPD1_INTERRUPT_MASK
+}, {
+ .reg = mmDISP_INTERRUPT_STATUS_CONTINUE,
+ .vblank = DISP_INTERRUPT_STATUS_CONTINUE__LB_D2_VBLANK_INTERRUPT_MASK,
+ .vline = DISP_INTERRUPT_STATUS_CONTINUE__LB_D2_VLINE_INTERRUPT_MASK,
+ .hpd = DISP_INTERRUPT_STATUS_CONTINUE__DC_HPD2_INTERRUPT_MASK
+}, {
+ .reg = mmDISP_INTERRUPT_STATUS_CONTINUE2,
+ .vblank = DISP_INTERRUPT_STATUS_CONTINUE2__LB_D3_VBLANK_INTERRUPT_MASK,
+ .vline = DISP_INTERRUPT_STATUS_CONTINUE2__LB_D3_VLINE_INTERRUPT_MASK,
+ .hpd = DISP_INTERRUPT_STATUS_CONTINUE2__DC_HPD3_INTERRUPT_MASK
+}, {
+ .reg = mmDISP_INTERRUPT_STATUS_CONTINUE3,
+ .vblank = DISP_INTERRUPT_STATUS_CONTINUE3__LB_D4_VBLANK_INTERRUPT_MASK,
+ .vline = DISP_INTERRUPT_STATUS_CONTINUE3__LB_D4_VLINE_INTERRUPT_MASK,
+ .hpd = DISP_INTERRUPT_STATUS_CONTINUE3__DC_HPD4_INTERRUPT_MASK
+}, {
+ .reg = mmDISP_INTERRUPT_STATUS_CONTINUE4,
+ .vblank = DISP_INTERRUPT_STATUS_CONTINUE4__LB_D5_VBLANK_INTERRUPT_MASK,
+ .vline = DISP_INTERRUPT_STATUS_CONTINUE4__LB_D5_VLINE_INTERRUPT_MASK,
+ .hpd = DISP_INTERRUPT_STATUS_CONTINUE4__DC_HPD5_INTERRUPT_MASK
+}, {
+ .reg = mmDISP_INTERRUPT_STATUS_CONTINUE5,
+ .vblank = DISP_INTERRUPT_STATUS_CONTINUE5__LB_D6_VBLANK_INTERRUPT_MASK,
+ .vline = DISP_INTERRUPT_STATUS_CONTINUE5__LB_D6_VLINE_INTERRUPT_MASK,
+ .hpd = DISP_INTERRUPT_STATUS_CONTINUE5__DC_HPD6_INTERRUPT_MASK
+} };
+
+static const u32 golden_settings_tonga_a11[] =
+{
+ mmDCI_CLK_CNTL, 0x00000080, 0x00000000,
+ mmFBC_DEBUG_COMP, 0x000000f0, 0x00000070,
+ mmFBC_MISC, 0x1f311fff, 0x12300000,
+ mmHDMI_CONTROL, 0x31000111, 0x00000011,
+};
+
+static const u32 tonga_mgcg_cgcg_init[] =
+{
+ mmXDMA_CLOCK_GATING_CNTL, 0xffffffff, 0x00000100,
+ mmXDMA_MEM_POWER_CNTL, 0x00000101, 0x00000000,
+};
+
+static void dce_v10_0_init_golden_registers(struct amdgpu_device *adev)
+{
+ switch (adev->asic_type) {
+ case CHIP_TONGA:
+ amdgpu_program_register_sequence(adev,
+ tonga_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(tonga_mgcg_cgcg_init));
+ amdgpu_program_register_sequence(adev,
+ golden_settings_tonga_a11,
+ (const u32)ARRAY_SIZE(golden_settings_tonga_a11));
+ break;
+ default:
+ break;
+ }
+}
+
+static u32 dce_v10_0_audio_endpt_rreg(struct amdgpu_device *adev,
+ u32 block_offset, u32 reg)
+{
+ unsigned long flags;
+ u32 r;
+
+ spin_lock_irqsave(&adev->audio_endpt_idx_lock, flags);
+ WREG32(mmAZALIA_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
+ r = RREG32(mmAZALIA_F0_CODEC_ENDPOINT_DATA + block_offset);
+ spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags);
+
+ return r;
+}
+
+static void dce_v10_0_audio_endpt_wreg(struct amdgpu_device *adev,
+ u32 block_offset, u32 reg, u32 v)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&adev->audio_endpt_idx_lock, flags);
+ WREG32(mmAZALIA_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
+ WREG32(mmAZALIA_F0_CODEC_ENDPOINT_DATA + block_offset, v);
+ spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags);
+}
+
+static bool dce_v10_0_is_in_vblank(struct amdgpu_device *adev, int crtc)
+{
+ if (RREG32(mmCRTC_STATUS + crtc_offsets[crtc]) &
+ CRTC_V_BLANK_START_END__CRTC_V_BLANK_START_MASK)
+ return true;
+ else
+ return false;
+}
+
+static bool dce_v10_0_is_counter_moving(struct amdgpu_device *adev, int crtc)
+{
+ u32 pos1, pos2;
+
+ pos1 = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]);
+ pos2 = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]);
+
+ if (pos1 != pos2)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * dce_v10_0_vblank_wait - vblank wait asic callback.
+ *
+ * @adev: amdgpu_device pointer
+ * @crtc: crtc to wait for vblank on
+ *
+ * Wait for vblank on the requested crtc (evergreen+).
+ */
+static void dce_v10_0_vblank_wait(struct amdgpu_device *adev, int crtc)
+{
+ unsigned i = 0;
+
+ if (crtc >= adev->mode_info.num_crtc)
+ return;
+
+ if (!(RREG32(mmCRTC_CONTROL + crtc_offsets[crtc]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK))
+ return;
+
+ /* depending on when we hit vblank, we may be close to active; if so,
+ * wait for another frame.
+ */
+ while (dce_v10_0_is_in_vblank(adev, crtc)) {
+ if (i++ % 100 == 0) {
+ if (!dce_v10_0_is_counter_moving(adev, crtc))
+ break;
+ }
+ }
+
+ while (!dce_v10_0_is_in_vblank(adev, crtc)) {
+ if (i++ % 100 == 0) {
+ if (!dce_v10_0_is_counter_moving(adev, crtc))
+ break;
+ }
+ }
+}
+
+static u32 dce_v10_0_vblank_get_counter(struct amdgpu_device *adev, int crtc)
+{
+ if (crtc >= adev->mode_info.num_crtc)
+ return 0;
+ else
+ return RREG32(mmCRTC_STATUS_FRAME_COUNT + crtc_offsets[crtc]);
+}
+
+/**
+ * dce_v10_0_page_flip - pageflip callback.
+ *
+ * @adev: amdgpu_device pointer
+ * @crtc_id: crtc to cleanup pageflip on
+ * @crtc_base: new address of the crtc (GPU MC address)
+ *
+ * Does the actual pageflip (evergreen+).
+ * During vblank we take the crtc lock and wait for the update_pending
+ * bit to go high, when it does, we release the lock, and allow the
+ * double buffered update to take place.
+ * Returns the current update pending status.
+ */
+static void dce_v10_0_page_flip(struct amdgpu_device *adev,
+ int crtc_id, u64 crtc_base)
+{
+ struct amdgpu_crtc *amdgpu_crtc = adev->mode_info.crtcs[crtc_id];
+ u32 tmp = RREG32(mmGRPH_UPDATE + amdgpu_crtc->crtc_offset);
+ int i;
+
+ /* Lock the graphics update lock */
+ tmp = REG_SET_FIELD(tmp, GRPH_UPDATE, GRPH_UPDATE_LOCK, 1);
+ WREG32(mmGRPH_UPDATE + amdgpu_crtc->crtc_offset, tmp);
+
+ /* update the scanout addresses */
+ WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
+ upper_32_bits(crtc_base));
+ WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset,
+ lower_32_bits(crtc_base));
+
+ WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
+ upper_32_bits(crtc_base));
+ WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset,
+ lower_32_bits(crtc_base));
+
+ /* Wait for update_pending to go high. */
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if (RREG32(mmGRPH_UPDATE + amdgpu_crtc->crtc_offset) &
+ GRPH_UPDATE__GRPH_SURFACE_UPDATE_PENDING_MASK)
+ break;
+ udelay(1);
+ }
+ DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");
+
+ /* Unlock the lock, so double-buffering can take place inside vblank */
+ tmp = REG_SET_FIELD(tmp, GRPH_UPDATE, GRPH_UPDATE_LOCK, 0);
+ WREG32(mmGRPH_UPDATE + amdgpu_crtc->crtc_offset, tmp);
+}
+
+static int dce_v10_0_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
+ u32 *vbl, u32 *position)
+{
+ if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc))
+ return -EINVAL;
+
+ *vbl = RREG32(mmCRTC_V_BLANK_START_END + crtc_offsets[crtc]);
+ *position = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]);
+
+ return 0;
+}
+
+/**
+ * dce_v10_0_hpd_sense - hpd sense callback.
+ *
+ * @adev: amdgpu_device pointer
+ * @hpd: hpd (hotplug detect) pin
+ *
+ * Checks if a digital monitor is connected (evergreen+).
+ * Returns true if connected, false if not connected.
+ */
+static bool dce_v10_0_hpd_sense(struct amdgpu_device *adev,
+ enum amdgpu_hpd_id hpd)
+{
+ int idx;
+ bool connected = false;
+
+ switch (hpd) {
+ case AMDGPU_HPD_1:
+ idx = 0;
+ break;
+ case AMDGPU_HPD_2:
+ idx = 1;
+ break;
+ case AMDGPU_HPD_3:
+ idx = 2;
+ break;
+ case AMDGPU_HPD_4:
+ idx = 3;
+ break;
+ case AMDGPU_HPD_5:
+ idx = 4;
+ break;
+ case AMDGPU_HPD_6:
+ idx = 5;
+ break;
+ default:
+ return connected;
+ }
+
+ if (RREG32(mmDC_HPD_INT_STATUS + hpd_offsets[idx]) &
+ DC_HPD_INT_STATUS__DC_HPD_SENSE_MASK)
+ connected = true;
+
+ return connected;
+}
+
+/**
+ * dce_v10_0_hpd_set_polarity - hpd set polarity callback.
+ *
+ * @adev: amdgpu_device pointer
+ * @hpd: hpd (hotplug detect) pin
+ *
+ * Set the polarity of the hpd pin (evergreen+).
+ */
+static void dce_v10_0_hpd_set_polarity(struct amdgpu_device *adev,
+ enum amdgpu_hpd_id hpd)
+{
+ u32 tmp;
+ bool connected = dce_v10_0_hpd_sense(adev, hpd);
+ int idx;
+
+ switch (hpd) {
+ case AMDGPU_HPD_1:
+ idx = 0;
+ break;
+ case AMDGPU_HPD_2:
+ idx = 1;
+ break;
+ case AMDGPU_HPD_3:
+ idx = 2;
+ break;
+ case AMDGPU_HPD_4:
+ idx = 3;
+ break;
+ case AMDGPU_HPD_5:
+ idx = 4;
+ break;
+ case AMDGPU_HPD_6:
+ idx = 5;
+ break;
+ default:
+ return;
+ }
+
+ tmp = RREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx]);
+ if (connected)
+ tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_POLARITY, 0);
+ else
+ tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_POLARITY, 1);
+ WREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx], tmp);
+}
+
+/**
+ * dce_v10_0_hpd_init - hpd setup callback.
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Setup the hpd pins used by the card (evergreen+).
+ * Enable the pin, set the polarity, and enable the hpd interrupts.
+ */
+static void dce_v10_0_hpd_init(struct amdgpu_device *adev)
+{
+ struct drm_device *dev = adev->ddev;
+ struct drm_connector *connector;
+ u32 tmp;
+ int idx;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+ connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+ /* don't try to enable hpd on eDP or LVDS avoid breaking the
+ * aux dp channel on imac and help (but not completely fix)
+ * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+ * also avoid interrupt storms during dpms.
+ */
+ continue;
+ }
+
+ switch (amdgpu_connector->hpd.hpd) {
+ case AMDGPU_HPD_1:
+ idx = 0;
+ break;
+ case AMDGPU_HPD_2:
+ idx = 1;
+ break;
+ case AMDGPU_HPD_3:
+ idx = 2;
+ break;
+ case AMDGPU_HPD_4:
+ idx = 3;
+ break;
+ case AMDGPU_HPD_5:
+ idx = 4;
+ break;
+ case AMDGPU_HPD_6:
+ idx = 5;
+ break;
+ default:
+ continue;
+ }
+
+ tmp = RREG32(mmDC_HPD_CONTROL + hpd_offsets[idx]);
+ tmp = REG_SET_FIELD(tmp, DC_HPD_CONTROL, DC_HPD_EN, 1);
+ WREG32(mmDC_HPD_CONTROL + hpd_offsets[idx], tmp);
+
+ tmp = RREG32(mmDC_HPD_TOGGLE_FILT_CNTL + hpd_offsets[idx]);
+ tmp = REG_SET_FIELD(tmp, DC_HPD_TOGGLE_FILT_CNTL,
+ DC_HPD_CONNECT_INT_DELAY,
+ AMDGPU_HPD_CONNECT_INT_DELAY_IN_MS);
+ tmp = REG_SET_FIELD(tmp, DC_HPD_TOGGLE_FILT_CNTL,
+ DC_HPD_DISCONNECT_INT_DELAY,
+ AMDGPU_HPD_DISCONNECT_INT_DELAY_IN_MS);
+ WREG32(mmDC_HPD_TOGGLE_FILT_CNTL + hpd_offsets[idx], tmp);
+
+ dce_v10_0_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd);
+ amdgpu_irq_get(adev, &adev->hpd_irq,
+ amdgpu_connector->hpd.hpd);
+ }
+}
+
+/**
+ * dce_v10_0_hpd_fini - hpd tear down callback.
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Tear down the hpd pins used by the card (evergreen+).
+ * Disable the hpd interrupts.
+ */
+static void dce_v10_0_hpd_fini(struct amdgpu_device *adev)
+{
+ struct drm_device *dev = adev->ddev;
+ struct drm_connector *connector;
+ u32 tmp;
+ int idx;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+ switch (amdgpu_connector->hpd.hpd) {
+ case AMDGPU_HPD_1:
+ idx = 0;
+ break;
+ case AMDGPU_HPD_2:
+ idx = 1;
+ break;
+ case AMDGPU_HPD_3:
+ idx = 2;
+ break;
+ case AMDGPU_HPD_4:
+ idx = 3;
+ break;
+ case AMDGPU_HPD_5:
+ idx = 4;
+ break;
+ case AMDGPU_HPD_6:
+ idx = 5;
+ break;
+ default:
+ continue;
+ }
+
+ tmp = RREG32(mmDC_HPD_CONTROL + hpd_offsets[idx]);
+ tmp = REG_SET_FIELD(tmp, DC_HPD_CONTROL, DC_HPD_EN, 0);
+ WREG32(mmDC_HPD_CONTROL + hpd_offsets[idx], tmp);
+
+ amdgpu_irq_put(adev, &adev->hpd_irq,
+ amdgpu_connector->hpd.hpd);
+ }
+}
+
+static u32 dce_v10_0_hpd_get_gpio_reg(struct amdgpu_device *adev)
+{
+ return mmDC_GPIO_HPD_A;
+}
+
+static bool dce_v10_0_is_display_hung(struct amdgpu_device *adev)
+{
+ u32 crtc_hung = 0;
+ u32 crtc_status[6];
+ u32 i, j, tmp;
+
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, CRTC_CONTROL, CRTC_MASTER_EN)) {
+ crtc_status[i] = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]);
+ crtc_hung |= (1 << i);
+ }
+ }
+
+ for (j = 0; j < 10; j++) {
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ if (crtc_hung & (1 << i)) {
+ tmp = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]);
+ if (tmp != crtc_status[i])
+ crtc_hung &= ~(1 << i);
+ }
+ }
+ if (crtc_hung == 0)
+ return false;
+ udelay(100);
+ }
+
+ return true;
+}
+
+static void dce_v10_0_stop_mc_access(struct amdgpu_device *adev,
+ struct amdgpu_mode_mc_save *save)
+{
+ u32 crtc_enabled, tmp;
+ int i;
+
+ save->vga_render_control = RREG32(mmVGA_RENDER_CONTROL);
+ save->vga_hdp_control = RREG32(mmVGA_HDP_CONTROL);
+
+ /* disable VGA render */
+ tmp = RREG32(mmVGA_RENDER_CONTROL);
+ tmp = REG_SET_FIELD(tmp, VGA_RENDER_CONTROL, VGA_VSTATUS_CNTL, 0);
+ WREG32(mmVGA_RENDER_CONTROL, tmp);
+
+ /* blank the display controllers */
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ crtc_enabled = REG_GET_FIELD(RREG32(mmCRTC_CONTROL + crtc_offsets[i]),
+ CRTC_CONTROL, CRTC_MASTER_EN);
+ if (crtc_enabled) {
+#if 0
+ u32 frame_count;
+ int j;
+
+ save->crtc_enabled[i] = true;
+ tmp = RREG32(mmCRTC_BLANK_CONTROL + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, CRTC_BLANK_CONTROL, CRTC_BLANK_DATA_EN) == 0) {
+ amdgpu_display_vblank_wait(adev, i);
+ WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+ tmp = REG_SET_FIELD(tmp, CRTC_BLANK_CONTROL, CRTC_BLANK_DATA_EN, 1);
+ WREG32(mmCRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
+ WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+ }
+ /* wait for the next frame */
+ frame_count = amdgpu_display_vblank_get_counter(adev, i);
+ for (j = 0; j < adev->usec_timeout; j++) {
+ if (amdgpu_display_vblank_get_counter(adev, i) != frame_count)
+ break;
+ udelay(1);
+ }
+ tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, GRPH_UPDATE, GRPH_UPDATE_LOCK) == 0) {
+ tmp = REG_SET_FIELD(tmp, GRPH_UPDATE, GRPH_UPDATE_LOCK, 1);
+ WREG32(mmGRPH_UPDATE + crtc_offsets[i], tmp);
+ }
+ tmp = RREG32(mmMASTER_UPDATE_LOCK + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, MASTER_UPDATE_LOCK, MASTER_UPDATE_LOCK) == 0) {
+ tmp = REG_SET_FIELD(tmp, MASTER_UPDATE_LOCK, MASTER_UPDATE_LOCK, 1);
+ WREG32(mmMASTER_UPDATE_LOCK + crtc_offsets[i], tmp);
+ }
+#else
+ /* XXX this is a hack to avoid strange behavior with EFI on certain systems */
+ WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+ tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]);
+ tmp = REG_SET_FIELD(tmp, CRTC_CONTROL, CRTC_MASTER_EN, 0);
+ WREG32(mmCRTC_CONTROL + crtc_offsets[i], tmp);
+ WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+ save->crtc_enabled[i] = false;
+ /* ***** */
+#endif
+ } else {
+ save->crtc_enabled[i] = false;
+ }
+ }
+}
+
+static void dce_v10_0_resume_mc_access(struct amdgpu_device *adev,
+ struct amdgpu_mode_mc_save *save)
+{
+ u32 tmp, frame_count;
+ int i, j;
+
+ /* update crtc base addresses */
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
+ upper_32_bits(adev->mc.vram_start));
+ WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
+ upper_32_bits(adev->mc.vram_start));
+ WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i],
+ (u32)adev->mc.vram_start);
+ WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i],
+ (u32)adev->mc.vram_start);
+
+ if (save->crtc_enabled[i]) {
+ tmp = RREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, MASTER_UPDATE_MODE, MASTER_UPDATE_MODE) != 3) {
+ tmp = REG_SET_FIELD(tmp, MASTER_UPDATE_MODE, MASTER_UPDATE_MODE, 3);
+ WREG32(mmMASTER_UPDATE_MODE + crtc_offsets[i], tmp);
+ }
+ tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, GRPH_UPDATE, GRPH_UPDATE_LOCK)) {
+ tmp = REG_SET_FIELD(tmp, GRPH_UPDATE, GRPH_UPDATE_LOCK, 0);
+ WREG32(mmGRPH_UPDATE + crtc_offsets[i], tmp);
+ }
+ tmp = RREG32(mmMASTER_UPDATE_LOCK + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, MASTER_UPDATE_LOCK, MASTER_UPDATE_LOCK)) {
+ tmp = REG_SET_FIELD(tmp, MASTER_UPDATE_LOCK, MASTER_UPDATE_LOCK, 0);
+ WREG32(mmMASTER_UPDATE_LOCK + crtc_offsets[i], tmp);
+ }
+ for (j = 0; j < adev->usec_timeout; j++) {
+ tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, GRPH_UPDATE, GRPH_SURFACE_UPDATE_PENDING) == 0)
+ break;
+ udelay(1);
+ }
+ tmp = RREG32(mmCRTC_BLANK_CONTROL + crtc_offsets[i]);
+ tmp = REG_SET_FIELD(tmp, CRTC_BLANK_CONTROL, CRTC_BLANK_DATA_EN, 0);
+ WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+ WREG32(mmCRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
+ WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+ /* wait for the next frame */
+ frame_count = amdgpu_display_vblank_get_counter(adev, i);
+ for (j = 0; j < adev->usec_timeout; j++) {
+ if (amdgpu_display_vblank_get_counter(adev, i) != frame_count)
+ break;
+ udelay(1);
+ }
+ }
+ }
+
+ WREG32(mmVGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(adev->mc.vram_start));
+ WREG32(mmVGA_MEMORY_BASE_ADDRESS, lower_32_bits(adev->mc.vram_start));
+
+ /* Unlock vga access */
+ WREG32(mmVGA_HDP_CONTROL, save->vga_hdp_control);
+ mdelay(1);
+ WREG32(mmVGA_RENDER_CONTROL, save->vga_render_control);
+}
+
+static void dce_v10_0_set_vga_render_state(struct amdgpu_device *adev,
+ bool render)
+{
+ u32 tmp;
+
+ /* Lockout access through VGA aperture*/
+ tmp = RREG32(mmVGA_HDP_CONTROL);
+ if (render)
+ tmp = REG_SET_FIELD(tmp, VGA_HDP_CONTROL, VGA_MEMORY_DISABLE, 0);
+ else
+ tmp = REG_SET_FIELD(tmp, VGA_HDP_CONTROL, VGA_MEMORY_DISABLE, 1);
+ WREG32(mmVGA_HDP_CONTROL, tmp);
+
+ /* disable VGA render */
+ tmp = RREG32(mmVGA_RENDER_CONTROL);
+ if (render)
+ tmp = REG_SET_FIELD(tmp, VGA_RENDER_CONTROL, VGA_VSTATUS_CNTL, 1);
+ else
+ tmp = REG_SET_FIELD(tmp, VGA_RENDER_CONTROL, VGA_VSTATUS_CNTL, 0);
+ WREG32(mmVGA_RENDER_CONTROL, tmp);
+}
+
+static void dce_v10_0_program_fmt(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
+ struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+ int bpc = 0;
+ u32 tmp = 0;
+ enum amdgpu_connector_dither dither = AMDGPU_FMT_DITHER_DISABLE;
+
+ if (connector) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ bpc = amdgpu_connector_get_monitor_bpc(connector);
+ dither = amdgpu_connector->dither;
+ }
+
+ /* LVDS/eDP FMT is set up by atom */
+ if (amdgpu_encoder->devices & ATOM_DEVICE_LCD_SUPPORT)
+ return;
+
+ /* not needed for analog */
+ if ((amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1) ||
+ (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2))
+ return;
+
+ if (bpc == 0)
+ return;
+
+ switch (bpc) {
+ case 6:
+ if (dither == AMDGPU_FMT_DITHER_ENABLE) {
+ /* XXX sort out optimal dither settings */
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_FRAME_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_HIGHPASS_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_EN, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_DEPTH, 0);
+ } else {
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH, 0);
+ }
+ break;
+ case 8:
+ if (dither == AMDGPU_FMT_DITHER_ENABLE) {
+ /* XXX sort out optimal dither settings */
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_FRAME_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_HIGHPASS_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_RGB_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_EN, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_DEPTH, 1);
+ } else {
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH, 1);
+ }
+ break;
+ case 10:
+ if (dither == AMDGPU_FMT_DITHER_ENABLE) {
+ /* XXX sort out optimal dither settings */
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_FRAME_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_HIGHPASS_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_RGB_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_EN, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_DEPTH, 2);
+ } else {
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH, 2);
+ }
+ break;
+ default:
+ /* not needed */
+ break;
+ }
+
+ WREG32(mmFMT_BIT_DEPTH_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+}
+
+
+/* display watermark setup */
+/**
+ * dce_v10_0_line_buffer_adjust - Set up the line buffer
+ *
+ * @adev: amdgpu_device pointer
+ * @amdgpu_crtc: the selected display controller
+ * @mode: the current display mode on the selected display
+ * controller
+ *
+ * Setup up the line buffer allocation for
+ * the selected display controller (CIK).
+ * Returns the line buffer size in pixels.
+ */
+static u32 dce_v10_0_line_buffer_adjust(struct amdgpu_device *adev,
+ struct amdgpu_crtc *amdgpu_crtc,
+ struct drm_display_mode *mode)
+{
+ u32 tmp, buffer_alloc, i, mem_cfg;
+ u32 pipe_offset = amdgpu_crtc->crtc_id;
+ /*
+ * Line Buffer Setup
+ * There are 6 line buffers, one for each display controllers.
+ * There are 3 partitions per LB. Select the number of partitions
+ * to enable based on the display width. For display widths larger
+ * than 4096, you need use to use 2 display controllers and combine
+ * them using the stereo blender.
+ */
+ if (amdgpu_crtc->base.enabled && mode) {
+ if (mode->crtc_hdisplay < 1920) {
+ mem_cfg = 1;
+ buffer_alloc = 2;
+ } else if (mode->crtc_hdisplay < 2560) {
+ mem_cfg = 2;
+ buffer_alloc = 2;
+ } else if (mode->crtc_hdisplay < 4096) {
+ mem_cfg = 0;
+ buffer_alloc = (adev->flags & AMDGPU_IS_APU) ? 2 : 4;
+ } else {
+ DRM_DEBUG_KMS("Mode too big for LB!\n");
+ mem_cfg = 0;
+ buffer_alloc = (adev->flags & AMDGPU_IS_APU) ? 2 : 4;
+ }
+ } else {
+ mem_cfg = 1;
+ buffer_alloc = 0;
+ }
+
+ tmp = RREG32(mmLB_MEMORY_CTRL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, LB_MEMORY_CTRL, LB_MEMORY_CONFIG, mem_cfg);
+ WREG32(mmLB_MEMORY_CTRL + amdgpu_crtc->crtc_offset, tmp);
+
+ tmp = RREG32(mmPIPE0_DMIF_BUFFER_CONTROL + pipe_offset);
+ tmp = REG_SET_FIELD(tmp, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED, buffer_alloc);
+ WREG32(mmPIPE0_DMIF_BUFFER_CONTROL + pipe_offset, tmp);
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = RREG32(mmPIPE0_DMIF_BUFFER_CONTROL + pipe_offset);
+ if (REG_GET_FIELD(tmp, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATION_COMPLETED))
+ break;
+ udelay(1);
+ }
+
+ if (amdgpu_crtc->base.enabled && mode) {
+ switch (mem_cfg) {
+ case 0:
+ default:
+ return 4096 * 2;
+ case 1:
+ return 1920 * 2;
+ case 2:
+ return 2560 * 2;
+ }
+ }
+
+ /* controller not enabled, so no lb used */
+ return 0;
+}
+
+/**
+ * cik_get_number_of_dram_channels - get the number of dram channels
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Look up the number of video ram channels (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the number of dram channels
+ */
+static u32 cik_get_number_of_dram_channels(struct amdgpu_device *adev)
+{
+ u32 tmp = RREG32(mmMC_SHARED_CHMAP);
+
+ switch (REG_GET_FIELD(tmp, MC_SHARED_CHMAP, NOOFCHAN)) {
+ case 0:
+ default:
+ return 1;
+ case 1:
+ return 2;
+ case 2:
+ return 4;
+ case 3:
+ return 8;
+ case 4:
+ return 3;
+ case 5:
+ return 6;
+ case 6:
+ return 10;
+ case 7:
+ return 12;
+ case 8:
+ return 16;
+ }
+}
+
+struct dce10_wm_params {
+ u32 dram_channels; /* number of dram channels */
+ u32 yclk; /* bandwidth per dram data pin in kHz */
+ u32 sclk; /* engine clock in kHz */
+ u32 disp_clk; /* display clock in kHz */
+ u32 src_width; /* viewport width */
+ u32 active_time; /* active display time in ns */
+ u32 blank_time; /* blank time in ns */
+ bool interlaced; /* mode is interlaced */
+ fixed20_12 vsc; /* vertical scale ratio */
+ u32 num_heads; /* number of active crtcs */
+ u32 bytes_per_pixel; /* bytes per pixel display + overlay */
+ u32 lb_size; /* line buffer allocated to pipe */
+ u32 vtaps; /* vertical scaler taps */
+};
+
+/**
+ * dce_v10_0_dram_bandwidth - get the dram bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the raw dram bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dram bandwidth in MBytes/s
+ */
+static u32 dce_v10_0_dram_bandwidth(struct dce10_wm_params *wm)
+{
+ /* Calculate raw DRAM Bandwidth */
+ fixed20_12 dram_efficiency; /* 0.7 */
+ fixed20_12 yclk, dram_channels, bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ yclk.full = dfixed_const(wm->yclk);
+ yclk.full = dfixed_div(yclk, a);
+ dram_channels.full = dfixed_const(wm->dram_channels * 4);
+ a.full = dfixed_const(10);
+ dram_efficiency.full = dfixed_const(7);
+ dram_efficiency.full = dfixed_div(dram_efficiency, a);
+ bandwidth.full = dfixed_mul(dram_channels, yclk);
+ bandwidth.full = dfixed_mul(bandwidth, dram_efficiency);
+
+ return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v10_0_dram_bandwidth_for_display - get the dram bandwidth for display
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the dram bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dram bandwidth for display in MBytes/s
+ */
+static u32 dce_v10_0_dram_bandwidth_for_display(struct dce10_wm_params *wm)
+{
+ /* Calculate DRAM Bandwidth and the part allocated to display. */
+ fixed20_12 disp_dram_allocation; /* 0.3 to 0.7 */
+ fixed20_12 yclk, dram_channels, bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ yclk.full = dfixed_const(wm->yclk);
+ yclk.full = dfixed_div(yclk, a);
+ dram_channels.full = dfixed_const(wm->dram_channels * 4);
+ a.full = dfixed_const(10);
+ disp_dram_allocation.full = dfixed_const(3); /* XXX worse case value 0.3 */
+ disp_dram_allocation.full = dfixed_div(disp_dram_allocation, a);
+ bandwidth.full = dfixed_mul(dram_channels, yclk);
+ bandwidth.full = dfixed_mul(bandwidth, disp_dram_allocation);
+
+ return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v10_0_data_return_bandwidth - get the data return bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the data return bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the data return bandwidth in MBytes/s
+ */
+static u32 dce_v10_0_data_return_bandwidth(struct dce10_wm_params *wm)
+{
+ /* Calculate the display Data return Bandwidth */
+ fixed20_12 return_efficiency; /* 0.8 */
+ fixed20_12 sclk, bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ sclk.full = dfixed_const(wm->sclk);
+ sclk.full = dfixed_div(sclk, a);
+ a.full = dfixed_const(10);
+ return_efficiency.full = dfixed_const(8);
+ return_efficiency.full = dfixed_div(return_efficiency, a);
+ a.full = dfixed_const(32);
+ bandwidth.full = dfixed_mul(a, sclk);
+ bandwidth.full = dfixed_mul(bandwidth, return_efficiency);
+
+ return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v10_0_dmif_request_bandwidth - get the dmif bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the dmif bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dmif bandwidth in MBytes/s
+ */
+static u32 dce_v10_0_dmif_request_bandwidth(struct dce10_wm_params *wm)
+{
+ /* Calculate the DMIF Request Bandwidth */
+ fixed20_12 disp_clk_request_efficiency; /* 0.8 */
+ fixed20_12 disp_clk, bandwidth;
+ fixed20_12 a, b;
+
+ a.full = dfixed_const(1000);
+ disp_clk.full = dfixed_const(wm->disp_clk);
+ disp_clk.full = dfixed_div(disp_clk, a);
+ a.full = dfixed_const(32);
+ b.full = dfixed_mul(a, disp_clk);
+
+ a.full = dfixed_const(10);
+ disp_clk_request_efficiency.full = dfixed_const(8);
+ disp_clk_request_efficiency.full = dfixed_div(disp_clk_request_efficiency, a);
+
+ bandwidth.full = dfixed_mul(b, disp_clk_request_efficiency);
+
+ return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v10_0_available_bandwidth - get the min available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the min available bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the min available bandwidth in MBytes/s
+ */
+static u32 dce_v10_0_available_bandwidth(struct dce10_wm_params *wm)
+{
+ /* Calculate the Available bandwidth. Display can use this temporarily but not in average. */
+ u32 dram_bandwidth = dce_v10_0_dram_bandwidth(wm);
+ u32 data_return_bandwidth = dce_v10_0_data_return_bandwidth(wm);
+ u32 dmif_req_bandwidth = dce_v10_0_dmif_request_bandwidth(wm);
+
+ return min(dram_bandwidth, min(data_return_bandwidth, dmif_req_bandwidth));
+}
+
+/**
+ * dce_v10_0_average_bandwidth - get the average available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the average available bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the average available bandwidth in MBytes/s
+ */
+static u32 dce_v10_0_average_bandwidth(struct dce10_wm_params *wm)
+{
+ /* Calculate the display mode Average Bandwidth
+ * DisplayMode should contain the source and destination dimensions,
+ * timing, etc.
+ */
+ fixed20_12 bpp;
+ fixed20_12 line_time;
+ fixed20_12 src_width;
+ fixed20_12 bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ line_time.full = dfixed_const(wm->active_time + wm->blank_time);
+ line_time.full = dfixed_div(line_time, a);
+ bpp.full = dfixed_const(wm->bytes_per_pixel);
+ src_width.full = dfixed_const(wm->src_width);
+ bandwidth.full = dfixed_mul(src_width, bpp);
+ bandwidth.full = dfixed_mul(bandwidth, wm->vsc);
+ bandwidth.full = dfixed_div(bandwidth, line_time);
+
+ return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v10_0_latency_watermark - get the latency watermark
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the latency watermark (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the latency watermark in ns
+ */
+static u32 dce_v10_0_latency_watermark(struct dce10_wm_params *wm)
+{
+ /* First calculate the latency in ns */
+ u32 mc_latency = 2000; /* 2000 ns. */
+ u32 available_bandwidth = dce_v10_0_available_bandwidth(wm);
+ u32 worst_chunk_return_time = (512 * 8 * 1000) / available_bandwidth;
+ u32 cursor_line_pair_return_time = (128 * 4 * 1000) / available_bandwidth;
+ u32 dc_latency = 40000000 / wm->disp_clk; /* dc pipe latency */
+ u32 other_heads_data_return_time = ((wm->num_heads + 1) * worst_chunk_return_time) +
+ (wm->num_heads * cursor_line_pair_return_time);
+ u32 latency = mc_latency + other_heads_data_return_time + dc_latency;
+ u32 max_src_lines_per_dst_line, lb_fill_bw, line_fill_time;
+ u32 tmp, dmif_size = 12288;
+ fixed20_12 a, b, c;
+
+ if (wm->num_heads == 0)
+ return 0;
+
+ a.full = dfixed_const(2);
+ b.full = dfixed_const(1);
+ if ((wm->vsc.full > a.full) ||
+ ((wm->vsc.full > b.full) && (wm->vtaps >= 3)) ||
+ (wm->vtaps >= 5) ||
+ ((wm->vsc.full >= a.full) && wm->interlaced))
+ max_src_lines_per_dst_line = 4;
+ else
+ max_src_lines_per_dst_line = 2;
+
+ a.full = dfixed_const(available_bandwidth);
+ b.full = dfixed_const(wm->num_heads);
+ a.full = dfixed_div(a, b);
+
+ b.full = dfixed_const(mc_latency + 512);
+ c.full = dfixed_const(wm->disp_clk);
+ b.full = dfixed_div(b, c);
+
+ c.full = dfixed_const(dmif_size);
+ b.full = dfixed_div(c, b);
+
+ tmp = min(dfixed_trunc(a), dfixed_trunc(b));
+
+ b.full = dfixed_const(1000);
+ c.full = dfixed_const(wm->disp_clk);
+ b.full = dfixed_div(c, b);
+ c.full = dfixed_const(wm->bytes_per_pixel);
+ b.full = dfixed_mul(b, c);
+
+ lb_fill_bw = min(tmp, dfixed_trunc(b));
+
+ a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
+ b.full = dfixed_const(1000);
+ c.full = dfixed_const(lb_fill_bw);
+ b.full = dfixed_div(c, b);
+ a.full = dfixed_div(a, b);
+ line_fill_time = dfixed_trunc(a);
+
+ if (line_fill_time < wm->active_time)
+ return latency;
+ else
+ return latency + (line_fill_time - wm->active_time);
+
+}
+
+/**
+ * dce_v10_0_average_bandwidth_vs_dram_bandwidth_for_display - check
+ * average and available dram bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Check if the display average bandwidth fits in the display
+ * dram bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce_v10_0_average_bandwidth_vs_dram_bandwidth_for_display(struct dce10_wm_params *wm)
+{
+ if (dce_v10_0_average_bandwidth(wm) <=
+ (dce_v10_0_dram_bandwidth_for_display(wm) / wm->num_heads))
+ return true;
+ else
+ return false;
+}
+
+/**
+ * dce_v10_0_average_bandwidth_vs_available_bandwidth - check
+ * average and available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Check if the display average bandwidth fits in the display
+ * available bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce_v10_0_average_bandwidth_vs_available_bandwidth(struct dce10_wm_params *wm)
+{
+ if (dce_v10_0_average_bandwidth(wm) <=
+ (dce_v10_0_available_bandwidth(wm) / wm->num_heads))
+ return true;
+ else
+ return false;
+}
+
+/**
+ * dce_v10_0_check_latency_hiding - check latency hiding
+ *
+ * @wm: watermark calculation data
+ *
+ * Check latency hiding (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce_v10_0_check_latency_hiding(struct dce10_wm_params *wm)
+{
+ u32 lb_partitions = wm->lb_size / wm->src_width;
+ u32 line_time = wm->active_time + wm->blank_time;
+ u32 latency_tolerant_lines;
+ u32 latency_hiding;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1);
+ if (wm->vsc.full > a.full)
+ latency_tolerant_lines = 1;
+ else {
+ if (lb_partitions <= (wm->vtaps + 1))
+ latency_tolerant_lines = 1;
+ else
+ latency_tolerant_lines = 2;
+ }
+
+ latency_hiding = (latency_tolerant_lines * line_time + wm->blank_time);
+
+ if (dce_v10_0_latency_watermark(wm) <= latency_hiding)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * dce_v10_0_program_watermarks - program display watermarks
+ *
+ * @adev: amdgpu_device pointer
+ * @amdgpu_crtc: the selected display controller
+ * @lb_size: line buffer size
+ * @num_heads: number of display controllers in use
+ *
+ * Calculate and program the display watermarks for the
+ * selected display controller (CIK).
+ */
+static void dce_v10_0_program_watermarks(struct amdgpu_device *adev,
+ struct amdgpu_crtc *amdgpu_crtc,
+ u32 lb_size, u32 num_heads)
+{
+ struct drm_display_mode *mode = &amdgpu_crtc->base.mode;
+ struct dce10_wm_params wm_low, wm_high;
+ u32 pixel_period;
+ u32 line_time = 0;
+ u32 latency_watermark_a = 0, latency_watermark_b = 0;
+ u32 tmp, wm_mask;
+
+ if (amdgpu_crtc->base.enabled && num_heads && mode) {
+ pixel_period = 1000000 / (u32)mode->clock;
+ line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+
+ /* watermark for high clocks */
+ if (adev->pm.dpm_enabled) {
+ wm_high.yclk =
+ amdgpu_dpm_get_mclk(adev, false) * 10;
+ wm_high.sclk =
+ amdgpu_dpm_get_sclk(adev, false) * 10;
+ } else {
+ wm_high.yclk = adev->pm.current_mclk * 10;
+ wm_high.sclk = adev->pm.current_sclk * 10;
+ }
+
+ wm_high.disp_clk = mode->clock;
+ wm_high.src_width = mode->crtc_hdisplay;
+ wm_high.active_time = mode->crtc_hdisplay * pixel_period;
+ wm_high.blank_time = line_time - wm_high.active_time;
+ wm_high.interlaced = false;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ wm_high.interlaced = true;
+ wm_high.vsc = amdgpu_crtc->vsc;
+ wm_high.vtaps = 1;
+ if (amdgpu_crtc->rmx_type != RMX_OFF)
+ wm_high.vtaps = 2;
+ wm_high.bytes_per_pixel = 4; /* XXX: get this from fb config */
+ wm_high.lb_size = lb_size;
+ wm_high.dram_channels = cik_get_number_of_dram_channels(adev);
+ wm_high.num_heads = num_heads;
+
+ /* set for high clocks */
+ latency_watermark_a = min(dce_v10_0_latency_watermark(&wm_high), (u32)65535);
+
+ /* possibly force display priority to high */
+ /* should really do this at mode validation time... */
+ if (!dce_v10_0_average_bandwidth_vs_dram_bandwidth_for_display(&wm_high) ||
+ !dce_v10_0_average_bandwidth_vs_available_bandwidth(&wm_high) ||
+ !dce_v10_0_check_latency_hiding(&wm_high) ||
+ (adev->mode_info.disp_priority == 2)) {
+ DRM_DEBUG_KMS("force priority to high\n");
+ }
+
+ /* watermark for low clocks */
+ if (adev->pm.dpm_enabled) {
+ wm_low.yclk =
+ amdgpu_dpm_get_mclk(adev, true) * 10;
+ wm_low.sclk =
+ amdgpu_dpm_get_sclk(adev, true) * 10;
+ } else {
+ wm_low.yclk = adev->pm.current_mclk * 10;
+ wm_low.sclk = adev->pm.current_sclk * 10;
+ }
+
+ wm_low.disp_clk = mode->clock;
+ wm_low.src_width = mode->crtc_hdisplay;
+ wm_low.active_time = mode->crtc_hdisplay * pixel_period;
+ wm_low.blank_time = line_time - wm_low.active_time;
+ wm_low.interlaced = false;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ wm_low.interlaced = true;
+ wm_low.vsc = amdgpu_crtc->vsc;
+ wm_low.vtaps = 1;
+ if (amdgpu_crtc->rmx_type != RMX_OFF)
+ wm_low.vtaps = 2;
+ wm_low.bytes_per_pixel = 4; /* XXX: get this from fb config */
+ wm_low.lb_size = lb_size;
+ wm_low.dram_channels = cik_get_number_of_dram_channels(adev);
+ wm_low.num_heads = num_heads;
+
+ /* set for low clocks */
+ latency_watermark_b = min(dce_v10_0_latency_watermark(&wm_low), (u32)65535);
+
+ /* possibly force display priority to high */
+ /* should really do this at mode validation time... */
+ if (!dce_v10_0_average_bandwidth_vs_dram_bandwidth_for_display(&wm_low) ||
+ !dce_v10_0_average_bandwidth_vs_available_bandwidth(&wm_low) ||
+ !dce_v10_0_check_latency_hiding(&wm_low) ||
+ (adev->mode_info.disp_priority == 2)) {
+ DRM_DEBUG_KMS("force priority to high\n");
+ }
+ }
+
+ /* select wm A */
+ wm_mask = RREG32(mmDPG_WATERMARK_MASK_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(wm_mask, DPG_WATERMARK_MASK_CONTROL, URGENCY_WATERMARK_MASK, 1);
+ WREG32(mmDPG_WATERMARK_MASK_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+ tmp = RREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, latency_watermark_a);
+ tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_HIGH_WATERMARK, line_time);
+ WREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+ /* select wm B */
+ tmp = REG_SET_FIELD(wm_mask, DPG_WATERMARK_MASK_CONTROL, URGENCY_WATERMARK_MASK, 2);
+ WREG32(mmDPG_WATERMARK_MASK_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+ tmp = RREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, latency_watermark_a);
+ tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_HIGH_WATERMARK, line_time);
+ WREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+ /* restore original selection */
+ WREG32(mmDPG_WATERMARK_MASK_CONTROL + amdgpu_crtc->crtc_offset, wm_mask);
+
+ /* save values for DPM */
+ amdgpu_crtc->line_time = line_time;
+ amdgpu_crtc->wm_high = latency_watermark_a;
+ amdgpu_crtc->wm_low = latency_watermark_b;
+}
+
+/**
+ * dce_v10_0_bandwidth_update - program display watermarks
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Calculate and program the display watermarks and line
+ * buffer allocation (CIK).
+ */
+static void dce_v10_0_bandwidth_update(struct amdgpu_device *adev)
+{
+ struct drm_display_mode *mode = NULL;
+ u32 num_heads = 0, lb_size;
+ int i;
+
+ amdgpu_update_display_priority(adev);
+
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ if (adev->mode_info.crtcs[i]->base.enabled)
+ num_heads++;
+ }
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ mode = &adev->mode_info.crtcs[i]->base.mode;
+ lb_size = dce_v10_0_line_buffer_adjust(adev, adev->mode_info.crtcs[i], mode);
+ dce_v10_0_program_watermarks(adev, adev->mode_info.crtcs[i],
+ lb_size, num_heads);
+ }
+}
+
+static void dce_v10_0_audio_get_connected_pins(struct amdgpu_device *adev)
+{
+ int i;
+ u32 offset, tmp;
+
+ for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+ offset = adev->mode_info.audio.pin[i].offset;
+ tmp = RREG32_AUDIO_ENDPT(offset,
+ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
+ if (((tmp &
+ AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT__PORT_CONNECTIVITY_MASK) >>
+ AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT__PORT_CONNECTIVITY__SHIFT) == 1)
+ adev->mode_info.audio.pin[i].connected = false;
+ else
+ adev->mode_info.audio.pin[i].connected = true;
+ }
+}
+
+static struct amdgpu_audio_pin *dce_v10_0_audio_get_pin(struct amdgpu_device *adev)
+{
+ int i;
+
+ dce_v10_0_audio_get_connected_pins(adev);
+
+ for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+ if (adev->mode_info.audio.pin[i].connected)
+ return &adev->mode_info.audio.pin[i];
+ }
+ DRM_ERROR("No connected audio pins found!\n");
+ return NULL;
+}
+
+static void dce_v10_0_afmt_audio_select_pin(struct drm_encoder *encoder)
+{
+ struct amdgpu_device *adev = encoder->dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ u32 tmp;
+
+ if (!dig || !dig->afmt || !dig->afmt->pin)
+ return;
+
+ tmp = RREG32(mmAFMT_AUDIO_SRC_CONTROL + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_SRC_CONTROL, AFMT_AUDIO_SRC_SELECT, dig->afmt->pin->id);
+ WREG32(mmAFMT_AUDIO_SRC_CONTROL + dig->afmt->offset, tmp);
+}
+
+static void dce_v10_0_audio_write_latency_fields(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ struct amdgpu_device *adev = encoder->dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector = NULL;
+ u32 tmp;
+ int interlace = 0;
+
+ if (!dig || !dig->afmt || !dig->afmt->pin)
+ return;
+
+ list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
+ if (connector->encoder == encoder) {
+ amdgpu_connector = to_amdgpu_connector(connector);
+ break;
+ }
+ }
+
+ if (!amdgpu_connector) {
+ DRM_ERROR("Couldn't find encoder's connector\n");
+ return;
+ }
+
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ interlace = 1;
+ if (connector->latency_present[interlace]) {
+ tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+ VIDEO_LIPSYNC, connector->video_latency[interlace]);
+ tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+ AUDIO_LIPSYNC, connector->audio_latency[interlace]);
+ } else {
+ tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+ VIDEO_LIPSYNC, 0);
+ tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+ AUDIO_LIPSYNC, 0);
+ }
+ WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
+ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
+}
+
+static void dce_v10_0_audio_write_speaker_allocation(struct drm_encoder *encoder)
+{
+ struct amdgpu_device *adev = encoder->dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector = NULL;
+ u32 tmp;
+ u8 *sadb = NULL;
+ int sad_count;
+
+ if (!dig || !dig->afmt || !dig->afmt->pin)
+ return;
+
+ list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
+ if (connector->encoder == encoder) {
+ amdgpu_connector = to_amdgpu_connector(connector);
+ break;
+ }
+ }
+
+ if (!amdgpu_connector) {
+ DRM_ERROR("Couldn't find encoder's connector\n");
+ return;
+ }
+
+ sad_count = drm_edid_to_speaker_allocation(amdgpu_connector_edid(connector), &sadb);
+ if (sad_count < 0) {
+ DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
+ sad_count = 0;
+ }
+
+ /* program the speaker allocation */
+ tmp = RREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
+ ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+ DP_CONNECTION, 0);
+ /* set HDMI mode */
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+ HDMI_CONNECTION, 1);
+ if (sad_count)
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+ SPEAKER_ALLOCATION, sadb[0]);
+ else
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+ SPEAKER_ALLOCATION, 5); /* stereo */
+ WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
+ ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
+
+ kfree(sadb);
+}
+
+static void dce_v10_0_audio_write_sad_regs(struct drm_encoder *encoder)
+{
+ struct amdgpu_device *adev = encoder->dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector = NULL;
+ struct cea_sad *sads;
+ int i, sad_count;
+
+ static const u16 eld_reg_to_type[][2] = {
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
+ };
+
+ if (!dig || !dig->afmt || !dig->afmt->pin)
+ return;
+
+ list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
+ if (connector->encoder == encoder) {
+ amdgpu_connector = to_amdgpu_connector(connector);
+ break;
+ }
+ }
+
+ if (!amdgpu_connector) {
+ DRM_ERROR("Couldn't find encoder's connector\n");
+ return;
+ }
+
+ sad_count = drm_edid_to_sad(amdgpu_connector_edid(connector), &sads);
+ if (sad_count <= 0) {
+ DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
+ return;
+ }
+ BUG_ON(!sads);
+
+ for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
+ u32 tmp = 0;
+ u8 stereo_freqs = 0;
+ int max_channels = -1;
+ int j;
+
+ for (j = 0; j < sad_count; j++) {
+ struct cea_sad *sad = &sads[j];
+
+ if (sad->format == eld_reg_to_type[i][1]) {
+ if (sad->channels > max_channels) {
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+ MAX_CHANNELS, sad->channels);
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+ DESCRIPTOR_BYTE_2, sad->byte2);
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+ SUPPORTED_FREQUENCIES, sad->freq);
+ max_channels = sad->channels;
+ }
+
+ if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
+ stereo_freqs |= sad->freq;
+ else
+ break;
+ }
+ }
+
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+ SUPPORTED_FREQUENCIES_STEREO, stereo_freqs);
+ WREG32_AUDIO_ENDPT(dig->afmt->pin->offset, eld_reg_to_type[i][0], tmp);
+ }
+
+ kfree(sads);
+}
+
+static void dce_v10_0_audio_enable(struct amdgpu_device *adev,
+ struct amdgpu_audio_pin *pin,
+ bool enable)
+{
+ if (!pin)
+ return;
+
+ WREG32_AUDIO_ENDPT(pin->offset, ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
+ enable ? AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL__AUDIO_ENABLED_MASK : 0);
+}
+
+static const u32 pin_offsets[] =
+{
+ AUD0_REGISTER_OFFSET,
+ AUD1_REGISTER_OFFSET,
+ AUD2_REGISTER_OFFSET,
+ AUD3_REGISTER_OFFSET,
+ AUD4_REGISTER_OFFSET,
+ AUD5_REGISTER_OFFSET,
+ AUD6_REGISTER_OFFSET,
+};
+
+static int dce_v10_0_audio_init(struct amdgpu_device *adev)
+{
+ int i;
+
+ if (!amdgpu_audio)
+ return 0;
+
+ adev->mode_info.audio.enabled = true;
+
+ adev->mode_info.audio.num_pins = 7;
+
+ for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+ adev->mode_info.audio.pin[i].channels = -1;
+ adev->mode_info.audio.pin[i].rate = -1;
+ adev->mode_info.audio.pin[i].bits_per_sample = -1;
+ adev->mode_info.audio.pin[i].status_bits = 0;
+ adev->mode_info.audio.pin[i].category_code = 0;
+ adev->mode_info.audio.pin[i].connected = false;
+ adev->mode_info.audio.pin[i].offset = pin_offsets[i];
+ adev->mode_info.audio.pin[i].id = i;
+ /* disable audio. it will be set up later */
+ /* XXX remove once we switch to ip funcs */
+ dce_v10_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
+ }
+
+ return 0;
+}
+
+static void dce_v10_0_audio_fini(struct amdgpu_device *adev)
+{
+ int i;
+
+ if (!adev->mode_info.audio.enabled)
+ return;
+
+ for (i = 0; i < adev->mode_info.audio.num_pins; i++)
+ dce_v10_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
+
+ adev->mode_info.audio.enabled = false;
+}
+
+/*
+ * update the N and CTS parameters for a given pixel clock rate
+ */
+static void dce_v10_0_afmt_update_ACR(struct drm_encoder *encoder, uint32_t clock)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_afmt_acr acr = amdgpu_afmt_acr(clock);
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ u32 tmp;
+
+ tmp = RREG32(mmHDMI_ACR_32_0 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_32_0, HDMI_ACR_CTS_32, acr.cts_32khz);
+ WREG32(mmHDMI_ACR_32_0 + dig->afmt->offset, tmp);
+ tmp = RREG32(mmHDMI_ACR_32_1 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_32_1, HDMI_ACR_N_32, acr.n_32khz);
+ WREG32(mmHDMI_ACR_32_1 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_ACR_44_0 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_44_0, HDMI_ACR_CTS_44, acr.cts_44_1khz);
+ WREG32(mmHDMI_ACR_44_0 + dig->afmt->offset, tmp);
+ tmp = RREG32(mmHDMI_ACR_44_1 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_44_1, HDMI_ACR_N_44, acr.n_44_1khz);
+ WREG32(mmHDMI_ACR_44_1 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_ACR_48_0 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_48_0, HDMI_ACR_CTS_48, acr.cts_48khz);
+ WREG32(mmHDMI_ACR_48_0 + dig->afmt->offset, tmp);
+ tmp = RREG32(mmHDMI_ACR_48_1 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_48_1, HDMI_ACR_N_48, acr.n_48khz);
+ WREG32(mmHDMI_ACR_48_1 + dig->afmt->offset, tmp);
+
+}
+
+/*
+ * build a HDMI Video Info Frame
+ */
+static void dce_v10_0_afmt_update_avi_infoframe(struct drm_encoder *encoder,
+ void *buffer, size_t size)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ uint8_t *frame = buffer + 3;
+ uint8_t *header = buffer;
+
+ WREG32(mmAFMT_AVI_INFO0 + dig->afmt->offset,
+ frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
+ WREG32(mmAFMT_AVI_INFO1 + dig->afmt->offset,
+ frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24));
+ WREG32(mmAFMT_AVI_INFO2 + dig->afmt->offset,
+ frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
+ WREG32(mmAFMT_AVI_INFO3 + dig->afmt->offset,
+ frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
+}
+
+static void dce_v10_0_audio_set_dto(struct drm_encoder *encoder, u32 clock)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
+ u32 dto_phase = 24 * 1000;
+ u32 dto_modulo = clock;
+ u32 tmp;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ /* XXX two dtos; generally use dto0 for hdmi */
+ /* Express [24MHz / target pixel clock] as an exact rational
+ * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
+ * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+ */
+ tmp = RREG32(mmDCCG_AUDIO_DTO_SOURCE);
+ tmp = REG_SET_FIELD(tmp, DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL,
+ amdgpu_crtc->crtc_id);
+ WREG32(mmDCCG_AUDIO_DTO_SOURCE, tmp);
+ WREG32(mmDCCG_AUDIO_DTO0_PHASE, dto_phase);
+ WREG32(mmDCCG_AUDIO_DTO0_MODULE, dto_modulo);
+}
+
+/*
+ * update the info frames with the data from the current display mode
+ */
+static void dce_v10_0_afmt_setmode(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+ u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
+ struct hdmi_avi_infoframe frame;
+ ssize_t err;
+ u32 tmp;
+ int bpc = 8;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ /* Silent, r600_hdmi_enable will raise WARN for us */
+ if (!dig->afmt->enabled)
+ return;
+
+ /* hdmi deep color mode general control packets setup, if bpc > 8 */
+ if (encoder->crtc) {
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
+ bpc = amdgpu_crtc->bpc;
+ }
+
+ /* disable audio prior to setting up hw */
+ dig->afmt->pin = dce_v10_0_audio_get_pin(adev);
+ dce_v10_0_audio_enable(adev, dig->afmt->pin, false);
+
+ dce_v10_0_audio_set_dto(encoder, mode->clock);
+
+ tmp = RREG32(mmHDMI_VBI_PACKET_CONTROL + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_VBI_PACKET_CONTROL, HDMI_NULL_SEND, 1);
+ WREG32(mmHDMI_VBI_PACKET_CONTROL + dig->afmt->offset, tmp); /* send null packets when required */
+
+ WREG32(mmAFMT_AUDIO_CRC_CONTROL + dig->afmt->offset, 0x1000);
+
+ tmp = RREG32(mmHDMI_CONTROL + dig->afmt->offset);
+ switch (bpc) {
+ case 0:
+ case 6:
+ case 8:
+ case 16:
+ default:
+ tmp = REG_SET_FIELD(tmp, HDMI_CONTROL, HDMI_DEEP_COLOR_ENABLE, 0);
+ tmp = REG_SET_FIELD(tmp, HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 0);
+ DRM_DEBUG("%s: Disabling hdmi deep color for %d bpc.\n",
+ connector->name, bpc);
+ break;
+ case 10:
+ tmp = REG_SET_FIELD(tmp, HDMI_CONTROL, HDMI_DEEP_COLOR_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 1);
+ DRM_DEBUG("%s: Enabling hdmi deep color 30 for 10 bpc.\n",
+ connector->name);
+ break;
+ case 12:
+ tmp = REG_SET_FIELD(tmp, HDMI_CONTROL, HDMI_DEEP_COLOR_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 2);
+ DRM_DEBUG("%s: Enabling hdmi deep color 36 for 12 bpc.\n",
+ connector->name);
+ break;
+ }
+ WREG32(mmHDMI_CONTROL + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_VBI_PACKET_CONTROL + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_VBI_PACKET_CONTROL, HDMI_NULL_SEND, 1); /* send null packets when required */
+ tmp = REG_SET_FIELD(tmp, HDMI_VBI_PACKET_CONTROL, HDMI_GC_SEND, 1); /* send general control packets */
+ tmp = REG_SET_FIELD(tmp, HDMI_VBI_PACKET_CONTROL, HDMI_GC_CONT, 1); /* send general control packets every frame */
+ WREG32(mmHDMI_VBI_PACKET_CONTROL + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_INFOFRAME_CONTROL0 + dig->afmt->offset);
+ /* enable audio info frames (frames won't be set until audio is enabled) */
+ tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_SEND, 1);
+ /* required for audio info values to be updated */
+ tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_CONT, 1);
+ WREG32(mmHDMI_INFOFRAME_CONTROL0 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmAFMT_INFOFRAME_CONTROL0 + dig->afmt->offset);
+ /* required for audio info values to be updated */
+ tmp = REG_SET_FIELD(tmp, AFMT_INFOFRAME_CONTROL0, AFMT_AUDIO_INFO_UPDATE, 1);
+ WREG32(mmAFMT_INFOFRAME_CONTROL0 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset);
+ /* anything other than 0 */
+ tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL1, HDMI_AUDIO_INFO_LINE, 2);
+ WREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset, tmp);
+
+ WREG32(mmHDMI_GC + dig->afmt->offset, 0); /* unset HDMI_GC_AVMUTE */
+
+ tmp = RREG32(mmHDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset);
+ /* set the default audio delay */
+ tmp = REG_SET_FIELD(tmp, HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_DELAY_EN, 1);
+ /* should be suffient for all audio modes and small enough for all hblanks */
+ tmp = REG_SET_FIELD(tmp, HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_PACKETS_PER_LINE, 3);
+ WREG32(mmHDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset);
+ /* allow 60958 channel status fields to be updated */
+ tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_60958_CS_UPDATE, 1);
+ WREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_ACR_PACKET_CONTROL + dig->afmt->offset);
+ if (bpc > 8)
+ /* clear SW CTS value */
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_PACKET_CONTROL, HDMI_ACR_SOURCE, 0);
+ else
+ /* select SW CTS value */
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_PACKET_CONTROL, HDMI_ACR_SOURCE, 1);
+ /* allow hw to sent ACR packets when required */
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_PACKET_CONTROL, HDMI_ACR_AUTO_SEND, 1);
+ WREG32(mmHDMI_ACR_PACKET_CONTROL + dig->afmt->offset, tmp);
+
+ dce_v10_0_afmt_update_ACR(encoder, mode->clock);
+
+ tmp = RREG32(mmAFMT_60958_0 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_0, AFMT_60958_CS_CHANNEL_NUMBER_L, 1);
+ WREG32(mmAFMT_60958_0 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmAFMT_60958_1 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_1, AFMT_60958_CS_CHANNEL_NUMBER_R, 2);
+ WREG32(mmAFMT_60958_1 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmAFMT_60958_2 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_2, 3);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_3, 4);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_4, 5);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_5, 6);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_6, 7);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_7, 8);
+ WREG32(mmAFMT_60958_2 + dig->afmt->offset, tmp);
+
+ dce_v10_0_audio_write_speaker_allocation(encoder);
+
+ WREG32(mmAFMT_AUDIO_PACKET_CONTROL2 + dig->afmt->offset,
+ (0xff << AFMT_AUDIO_PACKET_CONTROL2__AFMT_AUDIO_CHANNEL_ENABLE__SHIFT));
+
+ dce_v10_0_afmt_audio_select_pin(encoder);
+ dce_v10_0_audio_write_sad_regs(encoder);
+ dce_v10_0_audio_write_latency_fields(encoder, mode);
+
+ err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+ if (err < 0) {
+ DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
+ return;
+ }
+
+ err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
+ if (err < 0) {
+ DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
+ return;
+ }
+
+ dce_v10_0_afmt_update_avi_infoframe(encoder, buffer, sizeof(buffer));
+
+ tmp = RREG32(mmHDMI_INFOFRAME_CONTROL0 + dig->afmt->offset);
+ /* enable AVI info frames */
+ tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL0, HDMI_AVI_INFO_SEND, 1);
+ /* required for audio info values to be updated */
+ tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL0, HDMI_AVI_INFO_CONT, 1);
+ WREG32(mmHDMI_INFOFRAME_CONTROL0 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL1, HDMI_AVI_INFO_LINE, 2);
+ WREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset);
+ /* send audio packets */
+ tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, 1);
+ WREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
+
+ WREG32(mmAFMT_RAMP_CONTROL0 + dig->afmt->offset, 0x00FFFFFF);
+ WREG32(mmAFMT_RAMP_CONTROL1 + dig->afmt->offset, 0x007FFFFF);
+ WREG32(mmAFMT_RAMP_CONTROL2 + dig->afmt->offset, 0x00000001);
+ WREG32(mmAFMT_RAMP_CONTROL3 + dig->afmt->offset, 0x00000001);
+
+ /* enable audio after to setting up hw */
+ dce_v10_0_audio_enable(adev, dig->afmt->pin, true);
+}
+
+static void dce_v10_0_afmt_enable(struct drm_encoder *encoder, bool enable)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ /* Silent, r600_hdmi_enable will raise WARN for us */
+ if (enable && dig->afmt->enabled)
+ return;
+ if (!enable && !dig->afmt->enabled)
+ return;
+
+ if (!enable && dig->afmt->pin) {
+ dce_v10_0_audio_enable(adev, dig->afmt->pin, false);
+ dig->afmt->pin = NULL;
+ }
+
+ dig->afmt->enabled = enable;
+
+ DRM_DEBUG("%sabling AFMT interface @ 0x%04X for encoder 0x%x\n",
+ enable ? "En" : "Dis", dig->afmt->offset, amdgpu_encoder->encoder_id);
+}
+
+static void dce_v10_0_afmt_init(struct amdgpu_device *adev)
+{
+ int i;
+
+ for (i = 0; i < adev->mode_info.num_dig; i++)
+ adev->mode_info.afmt[i] = NULL;
+
+ /* DCE10 has audio blocks tied to DIG encoders */
+ for (i = 0; i < adev->mode_info.num_dig; i++) {
+ adev->mode_info.afmt[i] = kzalloc(sizeof(struct amdgpu_afmt), GFP_KERNEL);
+ if (adev->mode_info.afmt[i]) {
+ adev->mode_info.afmt[i]->offset = dig_offsets[i];
+ adev->mode_info.afmt[i]->id = i;
+ }
+ }
+}
+
+static void dce_v10_0_afmt_fini(struct amdgpu_device *adev)
+{
+ int i;
+
+ for (i = 0; i < adev->mode_info.num_dig; i++) {
+ kfree(adev->mode_info.afmt[i]);
+ adev->mode_info.afmt[i] = NULL;
+ }
+}
+
+static const u32 vga_control_regs[6] =
+{
+ mmD1VGA_CONTROL,
+ mmD2VGA_CONTROL,
+ mmD3VGA_CONTROL,
+ mmD4VGA_CONTROL,
+ mmD5VGA_CONTROL,
+ mmD6VGA_CONTROL,
+};
+
+static void dce_v10_0_vga_enable(struct drm_crtc *crtc, bool enable)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ u32 vga_control;
+
+ vga_control = RREG32(vga_control_regs[amdgpu_crtc->crtc_id]) & ~1;
+ if (enable)
+ WREG32(vga_control_regs[amdgpu_crtc->crtc_id], vga_control | 1);
+ else
+ WREG32(vga_control_regs[amdgpu_crtc->crtc_id], vga_control);
+}
+
+static void dce_v10_0_grph_enable(struct drm_crtc *crtc, bool enable)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+
+ if (enable)
+ WREG32(mmGRPH_ENABLE + amdgpu_crtc->crtc_offset, 1);
+ else
+ WREG32(mmGRPH_ENABLE + amdgpu_crtc->crtc_offset, 0);
+}
+
+static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, int atomic)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_framebuffer *amdgpu_fb;
+ struct drm_framebuffer *target_fb;
+ struct drm_gem_object *obj;
+ struct amdgpu_bo *rbo;
+ uint64_t fb_location, tiling_flags;
+ uint32_t fb_format, fb_pitch_pixels;
+ u32 fb_swap = REG_SET_FIELD(0, GRPH_SWAP_CNTL, GRPH_ENDIAN_SWAP, ENDIAN_NONE);
+ u32 pipe_config;
+ u32 tmp, viewport_w, viewport_h;
+ int r;
+ bool bypass_lut = false;
+
+ /* no fb bound */
+ if (!atomic && !crtc->primary->fb) {
+ DRM_DEBUG_KMS("No FB bound\n");
+ return 0;
+ }
+
+ if (atomic) {
+ amdgpu_fb = to_amdgpu_framebuffer(fb);
+ target_fb = fb;
+ }
+ else {
+ amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);
+ target_fb = crtc->primary->fb;
+ }
+
+ /* If atomic, assume fb object is pinned & idle & fenced and
+ * just update base pointers
+ */
+ obj = amdgpu_fb->obj;
+ rbo = gem_to_amdgpu_bo(obj);
+ r = amdgpu_bo_reserve(rbo, false);
+ if (unlikely(r != 0))
+ return r;
+
+ if (atomic)
+ fb_location = amdgpu_bo_gpu_offset(rbo);
+ else {
+ r = amdgpu_bo_pin(rbo, AMDGPU_GEM_DOMAIN_VRAM, &fb_location);
+ if (unlikely(r != 0)) {
+ amdgpu_bo_unreserve(rbo);
+ return -EINVAL;
+ }
+ }
+
+ amdgpu_bo_get_tiling_flags(rbo, &tiling_flags);
+ amdgpu_bo_unreserve(rbo);
+
+ pipe_config = AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
+
+ switch (target_fb->pixel_format) {
+ case DRM_FORMAT_C8:
+ fb_format = REG_SET_FIELD(0, GRPH_CONTROL, GRPH_DEPTH, 0);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_FORMAT, 0);
+ break;
+ case DRM_FORMAT_XRGB4444:
+ case DRM_FORMAT_ARGB4444:
+ fb_format = REG_SET_FIELD(0, GRPH_CONTROL, GRPH_DEPTH, 1);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_FORMAT, 2);
+#ifdef __BIG_ENDIAN
+ fb_swap = REG_SET_FIELD(fb_swap, GRPH_SWAP_CNTL, GRPH_ENDIAN_SWAP,
+ ENDIAN_8IN16);
+#endif
+ break;
+ case DRM_FORMAT_XRGB1555:
+ case DRM_FORMAT_ARGB1555:
+ fb_format = REG_SET_FIELD(0, GRPH_CONTROL, GRPH_DEPTH, 1);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_FORMAT, 0);
+#ifdef __BIG_ENDIAN
+ fb_swap = REG_SET_FIELD(fb_swap, GRPH_SWAP_CNTL, GRPH_ENDIAN_SWAP,
+ ENDIAN_8IN16);
+#endif
+ break;
+ case DRM_FORMAT_BGRX5551:
+ case DRM_FORMAT_BGRA5551:
+ fb_format = REG_SET_FIELD(0, GRPH_CONTROL, GRPH_DEPTH, 1);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_FORMAT, 5);
+#ifdef __BIG_ENDIAN
+ fb_swap = REG_SET_FIELD(fb_swap, GRPH_SWAP_CNTL, GRPH_ENDIAN_SWAP,
+ ENDIAN_8IN16);
+#endif
+ break;
+ case DRM_FORMAT_RGB565:
+ fb_format = REG_SET_FIELD(0, GRPH_CONTROL, GRPH_DEPTH, 1);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_FORMAT, 1);
+#ifdef __BIG_ENDIAN
+ fb_swap = REG_SET_FIELD(fb_swap, GRPH_SWAP_CNTL, GRPH_ENDIAN_SWAP,
+ ENDIAN_8IN16);
+#endif
+ break;
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ARGB8888:
+ fb_format = REG_SET_FIELD(0, GRPH_CONTROL, GRPH_DEPTH, 2);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_FORMAT, 0);
+#ifdef __BIG_ENDIAN
+ fb_swap = REG_SET_FIELD(fb_swap, GRPH_SWAP_CNTL, GRPH_ENDIAN_SWAP,
+ ENDIAN_8IN32);
+#endif
+ break;
+ case DRM_FORMAT_XRGB2101010:
+ case DRM_FORMAT_ARGB2101010:
+ fb_format = REG_SET_FIELD(0, GRPH_CONTROL, GRPH_DEPTH, 2);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_FORMAT, 1);
+#ifdef __BIG_ENDIAN
+ fb_swap = REG_SET_FIELD(fb_swap, GRPH_SWAP_CNTL, GRPH_ENDIAN_SWAP,
+ ENDIAN_8IN32);
+#endif
+ /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */
+ bypass_lut = true;
+ break;
+ case DRM_FORMAT_BGRX1010102:
+ case DRM_FORMAT_BGRA1010102:
+ fb_format = REG_SET_FIELD(0, GRPH_CONTROL, GRPH_DEPTH, 2);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_FORMAT, 4);
+#ifdef __BIG_ENDIAN
+ fb_swap = REG_SET_FIELD(fb_swap, GRPH_SWAP_CNTL, GRPH_ENDIAN_SWAP,
+ ENDIAN_8IN32);
+#endif
+ /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */
+ bypass_lut = true;
+ break;
+ default:
+ DRM_ERROR("Unsupported screen format %s\n",
+ drm_get_format_name(target_fb->pixel_format));
+ return -EINVAL;
+ }
+
+ if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == ARRAY_2D_TILED_THIN1) {
+ unsigned bankw, bankh, mtaspect, tile_split, num_banks;
+
+ bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH);
+ bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT);
+ mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT);
+ tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT);
+ num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS);
+
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_NUM_BANKS, num_banks);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_ARRAY_MODE,
+ ARRAY_2D_TILED_THIN1);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_TILE_SPLIT,
+ tile_split);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_BANK_WIDTH, bankw);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_BANK_HEIGHT, bankh);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_MACRO_TILE_ASPECT,
+ mtaspect);
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_MICRO_TILE_MODE,
+ ADDR_SURF_MICRO_TILING_DISPLAY);
+ } else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == ARRAY_1D_TILED_THIN1) {
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_ARRAY_MODE,
+ ARRAY_1D_TILED_THIN1);
+ }
+
+ fb_format = REG_SET_FIELD(fb_format, GRPH_CONTROL, GRPH_PIPE_CONFIG,
+ pipe_config);
+
+ dce_v10_0_vga_enable(crtc, false);
+
+ WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
+ upper_32_bits(fb_location));
+ WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
+ upper_32_bits(fb_location));
+ WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset,
+ (u32)fb_location & GRPH_PRIMARY_SURFACE_ADDRESS__GRPH_PRIMARY_SURFACE_ADDRESS_MASK);
+ WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset,
+ (u32) fb_location & GRPH_SECONDARY_SURFACE_ADDRESS__GRPH_SECONDARY_SURFACE_ADDRESS_MASK);
+ WREG32(mmGRPH_CONTROL + amdgpu_crtc->crtc_offset, fb_format);
+ WREG32(mmGRPH_SWAP_CNTL + amdgpu_crtc->crtc_offset, fb_swap);
+
+ /*
+ * The LUT only has 256 slots for indexing by a 8 bpc fb. Bypass the LUT
+ * for > 8 bpc scanout to avoid truncation of fb indices to 8 msb's, to
+ * retain the full precision throughout the pipeline.
+ */
+ tmp = RREG32(mmGRPH_LUT_10BIT_BYPASS + amdgpu_crtc->crtc_offset);
+ if (bypass_lut)
+ tmp = REG_SET_FIELD(tmp, GRPH_LUT_10BIT_BYPASS, GRPH_LUT_10BIT_BYPASS_EN, 1);
+ else
+ tmp = REG_SET_FIELD(tmp, GRPH_LUT_10BIT_BYPASS, GRPH_LUT_10BIT_BYPASS_EN, 0);
+ WREG32(mmGRPH_LUT_10BIT_BYPASS + amdgpu_crtc->crtc_offset, tmp);
+
+ if (bypass_lut)
+ DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n");
+
+ WREG32(mmGRPH_SURFACE_OFFSET_X + amdgpu_crtc->crtc_offset, 0);
+ WREG32(mmGRPH_SURFACE_OFFSET_Y + amdgpu_crtc->crtc_offset, 0);
+ WREG32(mmGRPH_X_START + amdgpu_crtc->crtc_offset, 0);
+ WREG32(mmGRPH_Y_START + amdgpu_crtc->crtc_offset, 0);
+ WREG32(mmGRPH_X_END + amdgpu_crtc->crtc_offset, target_fb->width);
+ WREG32(mmGRPH_Y_END + amdgpu_crtc->crtc_offset, target_fb->height);
+
+ fb_pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8);
+ WREG32(mmGRPH_PITCH + amdgpu_crtc->crtc_offset, fb_pitch_pixels);
+
+ dce_v10_0_grph_enable(crtc, true);
+
+ WREG32(mmLB_DESKTOP_HEIGHT + amdgpu_crtc->crtc_offset,
+ target_fb->height);
+
+ x &= ~3;
+ y &= ~1;
+ WREG32(mmVIEWPORT_START + amdgpu_crtc->crtc_offset,
+ (x << 16) | y);
+ viewport_w = crtc->mode.hdisplay;
+ viewport_h = (crtc->mode.vdisplay + 1) & ~1;
+ WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset,
+ (viewport_w << 16) | viewport_h);
+
+ /* pageflip setup */
+ /* make sure flip is at vb rather than hb */
+ tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL,
+ GRPH_SURFACE_UPDATE_H_RETRACE_EN, 0);
+ WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+
+ /* set pageflip to happen only at start of vblank interval (front porch) */
+ WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3);
+
+ if (!atomic && fb && fb != crtc->primary->fb) {
+ amdgpu_fb = to_amdgpu_framebuffer(fb);
+ rbo = gem_to_amdgpu_bo(amdgpu_fb->obj);
+ r = amdgpu_bo_reserve(rbo, false);
+ if (unlikely(r != 0))
+ return r;
+ amdgpu_bo_unpin(rbo);
+ amdgpu_bo_unreserve(rbo);
+ }
+
+ /* Bytes per pixel may have changed */
+ dce_v10_0_bandwidth_update(adev);
+
+ return 0;
+}
+
+static void dce_v10_0_set_interleave(struct drm_crtc *crtc,
+ struct drm_display_mode *mode)
+{
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ u32 tmp;
+
+ tmp = RREG32(mmLB_DATA_FORMAT + amdgpu_crtc->crtc_offset);
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ tmp = REG_SET_FIELD(tmp, LB_DATA_FORMAT, INTERLEAVE_EN, 1);
+ else
+ tmp = REG_SET_FIELD(tmp, LB_DATA_FORMAT, INTERLEAVE_EN, 0);
+ WREG32(mmLB_DATA_FORMAT + amdgpu_crtc->crtc_offset, tmp);
+}
+
+static void dce_v10_0_crtc_load_lut(struct drm_crtc *crtc)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ int i;
+ u32 tmp;
+
+ DRM_DEBUG_KMS("%d\n", amdgpu_crtc->crtc_id);
+
+ tmp = RREG32(mmINPUT_CSC_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, INPUT_CSC_CONTROL, INPUT_CSC_GRPH_MODE, 0);
+ tmp = REG_SET_FIELD(tmp, INPUT_CSC_CONTROL, INPUT_CSC_OVL_MODE, 0);
+ WREG32(mmINPUT_CSC_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+
+ tmp = RREG32(mmPRESCALE_GRPH_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, PRESCALE_GRPH_CONTROL, GRPH_PRESCALE_BYPASS, 1);
+ WREG32(mmPRESCALE_GRPH_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+
+ tmp = RREG32(mmPRESCALE_OVL_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, PRESCALE_OVL_CONTROL, OVL_PRESCALE_BYPASS, 1);
+ WREG32(mmPRESCALE_OVL_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+
+ tmp = RREG32(mmINPUT_GAMMA_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, INPUT_GAMMA_CONTROL, GRPH_INPUT_GAMMA_MODE, 0);
+ tmp = REG_SET_FIELD(tmp, INPUT_GAMMA_CONTROL, OVL_INPUT_GAMMA_MODE, 0);
+ WREG32(mmINPUT_GAMMA_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+
+ WREG32(mmDC_LUT_CONTROL + amdgpu_crtc->crtc_offset, 0);
+
+ WREG32(mmDC_LUT_BLACK_OFFSET_BLUE + amdgpu_crtc->crtc_offset, 0);
+ WREG32(mmDC_LUT_BLACK_OFFSET_GREEN + amdgpu_crtc->crtc_offset, 0);
+ WREG32(mmDC_LUT_BLACK_OFFSET_RED + amdgpu_crtc->crtc_offset, 0);
+
+ WREG32(mmDC_LUT_WHITE_OFFSET_BLUE + amdgpu_crtc->crtc_offset, 0xffff);
+ WREG32(mmDC_LUT_WHITE_OFFSET_GREEN + amdgpu_crtc->crtc_offset, 0xffff);
+ WREG32(mmDC_LUT_WHITE_OFFSET_RED + amdgpu_crtc->crtc_offset, 0xffff);
+
+ WREG32(mmDC_LUT_RW_MODE + amdgpu_crtc->crtc_offset, 0);
+ WREG32(mmDC_LUT_WRITE_EN_MASK + amdgpu_crtc->crtc_offset, 0x00000007);
+
+ WREG32(mmDC_LUT_RW_INDEX + amdgpu_crtc->crtc_offset, 0);
+ for (i = 0; i < 256; i++) {
+ WREG32(mmDC_LUT_30_COLOR + amdgpu_crtc->crtc_offset,
+ (amdgpu_crtc->lut_r[i] << 20) |
+ (amdgpu_crtc->lut_g[i] << 10) |
+ (amdgpu_crtc->lut_b[i] << 0));
+ }
+
+ tmp = RREG32(mmDEGAMMA_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, DEGAMMA_CONTROL, GRPH_DEGAMMA_MODE, 0);
+ tmp = REG_SET_FIELD(tmp, DEGAMMA_CONTROL, OVL_DEGAMMA_MODE, 0);
+ tmp = REG_SET_FIELD(tmp, DEGAMMA_CONTROL, CURSOR_DEGAMMA_MODE, 0);
+ WREG32(mmDEGAMMA_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+
+ tmp = RREG32(mmGAMUT_REMAP_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, GAMUT_REMAP_CONTROL, GRPH_GAMUT_REMAP_MODE, 0);
+ tmp = REG_SET_FIELD(tmp, GAMUT_REMAP_CONTROL, OVL_GAMUT_REMAP_MODE, 0);
+ WREG32(mmGAMUT_REMAP_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+
+ tmp = RREG32(mmREGAMMA_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, REGAMMA_CONTROL, GRPH_REGAMMA_MODE, 0);
+ tmp = REG_SET_FIELD(tmp, REGAMMA_CONTROL, OVL_REGAMMA_MODE, 0);
+ WREG32(mmREGAMMA_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+
+ tmp = RREG32(mmOUTPUT_CSC_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, OUTPUT_CSC_CONTROL, OUTPUT_CSC_GRPH_MODE, 0);
+ tmp = REG_SET_FIELD(tmp, OUTPUT_CSC_CONTROL, OUTPUT_CSC_OVL_MODE, 0);
+ WREG32(mmOUTPUT_CSC_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+
+ /* XXX match this to the depth of the crtc fmt block, move to modeset? */
+ WREG32(mmDENORM_CONTROL + amdgpu_crtc->crtc_offset, 0);
+ /* XXX this only needs to be programmed once per crtc at startup,
+ * not sure where the best place for it is
+ */
+ tmp = RREG32(mmALPHA_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, ALPHA_CONTROL, CURSOR_ALPHA_BLND_ENA, 1);
+ WREG32(mmALPHA_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+}
+
+static int dce_v10_0_pick_dig_encoder(struct drm_encoder *encoder)
+{
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+
+ switch (amdgpu_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ if (dig->linkb)
+ return 1;
+ else
+ return 0;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ if (dig->linkb)
+ return 3;
+ else
+ return 2;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ if (dig->linkb)
+ return 5;
+ else
+ return 4;
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+ return 6;
+ break;
+ default:
+ DRM_ERROR("invalid encoder_id: 0x%x\n", amdgpu_encoder->encoder_id);
+ return 0;
+ }
+}
+
+/**
+ * dce_v10_0_pick_pll - Allocate a PPLL for use by the crtc.
+ *
+ * @crtc: drm crtc
+ *
+ * Returns the PPLL (Pixel PLL) to be used by the crtc. For DP monitors
+ * a single PPLL can be used for all DP crtcs/encoders. For non-DP
+ * monitors a dedicated PPLL must be used. If a particular board has
+ * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming
+ * as there is no need to program the PLL itself. If we are not able to
+ * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to
+ * avoid messing up an existing monitor.
+ *
+ * Asic specific PLL information
+ *
+ * DCE 10.x
+ * Tonga
+ * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP)
+ * CI
+ * - PPLL0, PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
+ *
+ */
+static u32 dce_v10_0_pick_pll(struct drm_crtc *crtc)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ u32 pll_in_use;
+ int pll;
+
+ if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder))) {
+ if (adev->clock.dp_extclk)
+ /* skip PPLL programming if using ext clock */
+ return ATOM_PPLL_INVALID;
+ else {
+ /* use the same PPLL for all DP monitors */
+ pll = amdgpu_pll_get_shared_dp_ppll(crtc);
+ if (pll != ATOM_PPLL_INVALID)
+ return pll;
+ }
+ } else {
+ /* use the same PPLL for all monitors with the same clock */
+ pll = amdgpu_pll_get_shared_nondp_ppll(crtc);
+ if (pll != ATOM_PPLL_INVALID)
+ return pll;
+ }
+
+ /* DCE10 has PPLL0, PPLL1, and PPLL2 */
+ pll_in_use = amdgpu_pll_get_use_mask(crtc);
+ if (!(pll_in_use & (1 << ATOM_PPLL2)))
+ return ATOM_PPLL2;
+ if (!(pll_in_use & (1 << ATOM_PPLL1)))
+ return ATOM_PPLL1;
+ if (!(pll_in_use & (1 << ATOM_PPLL0)))
+ return ATOM_PPLL0;
+ DRM_ERROR("unable to allocate a PPLL\n");
+ return ATOM_PPLL_INVALID;
+}
+
+static void dce_v10_0_lock_cursor(struct drm_crtc *crtc, bool lock)
+{
+ struct amdgpu_device *adev = crtc->dev->dev_private;
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ uint32_t cur_lock;
+
+ cur_lock = RREG32(mmCUR_UPDATE + amdgpu_crtc->crtc_offset);
+ if (lock)
+ cur_lock = REG_SET_FIELD(cur_lock, CUR_UPDATE, CURSOR_UPDATE_LOCK, 1);
+ else
+ cur_lock = REG_SET_FIELD(cur_lock, CUR_UPDATE, CURSOR_UPDATE_LOCK, 0);
+ WREG32(mmCUR_UPDATE + amdgpu_crtc->crtc_offset, cur_lock);
+}
+
+static void dce_v10_0_hide_cursor(struct drm_crtc *crtc)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct amdgpu_device *adev = crtc->dev->dev_private;
+ u32 tmp;
+
+ tmp = RREG32_IDX(mmCUR_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, CUR_CONTROL, CURSOR_EN, 0);
+ WREG32_IDX(mmCUR_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+}
+
+static void dce_v10_0_show_cursor(struct drm_crtc *crtc)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct amdgpu_device *adev = crtc->dev->dev_private;
+ u32 tmp;
+
+ tmp = RREG32_IDX(mmCUR_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, CUR_CONTROL, CURSOR_EN, 1);
+ tmp = REG_SET_FIELD(tmp, CUR_CONTROL, CURSOR_MODE, 2);
+ WREG32_IDX(mmCUR_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+}
+
+static void dce_v10_0_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
+ uint64_t gpu_addr)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct amdgpu_device *adev = crtc->dev->dev_private;
+
+ WREG32(mmCUR_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
+ upper_32_bits(gpu_addr));
+ WREG32(mmCUR_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset,
+ lower_32_bits(gpu_addr));
+}
+
+static int dce_v10_0_crtc_cursor_move(struct drm_crtc *crtc,
+ int x, int y)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct amdgpu_device *adev = crtc->dev->dev_private;
+ int xorigin = 0, yorigin = 0;
+
+ /* avivo cursor are offset into the total surface */
+ x += crtc->x;
+ y += crtc->y;
+ DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
+
+ if (x < 0) {
+ xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
+ x = 0;
+ }
+ if (y < 0) {
+ yorigin = min(-y, amdgpu_crtc->max_cursor_height - 1);
+ y = 0;
+ }
+
+ dce_v10_0_lock_cursor(crtc, true);
+ WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
+ WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
+ WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+ ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
+ dce_v10_0_lock_cursor(crtc, false);
+
+ return 0;
+}
+
+static int dce_v10_0_crtc_cursor_set(struct drm_crtc *crtc,
+ struct drm_file *file_priv,
+ uint32_t handle,
+ uint32_t width,
+ uint32_t height)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_gem_object *obj;
+ struct amdgpu_bo *robj;
+ uint64_t gpu_addr;
+ int ret;
+
+ if (!handle) {
+ /* turn off cursor */
+ dce_v10_0_hide_cursor(crtc);
+ obj = NULL;
+ goto unpin;
+ }
+
+ if ((width > amdgpu_crtc->max_cursor_width) ||
+ (height > amdgpu_crtc->max_cursor_height)) {
+ DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
+ return -EINVAL;
+ }
+
+ obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
+ if (!obj) {
+ DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, amdgpu_crtc->crtc_id);
+ return -ENOENT;
+ }
+
+ robj = gem_to_amdgpu_bo(obj);
+ ret = amdgpu_bo_reserve(robj, false);
+ if (unlikely(ret != 0))
+ goto fail;
+ ret = amdgpu_bo_pin_restricted(robj, AMDGPU_GEM_DOMAIN_VRAM,
+ 0, 0, &gpu_addr);
+ amdgpu_bo_unreserve(robj);
+ if (ret)
+ goto fail;
+
+ amdgpu_crtc->cursor_width = width;
+ amdgpu_crtc->cursor_height = height;
+
+ dce_v10_0_lock_cursor(crtc, true);
+ dce_v10_0_set_cursor(crtc, obj, gpu_addr);
+ dce_v10_0_show_cursor(crtc);
+ dce_v10_0_lock_cursor(crtc, false);
+
+unpin:
+ if (amdgpu_crtc->cursor_bo) {
+ robj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo);
+ ret = amdgpu_bo_reserve(robj, false);
+ if (likely(ret == 0)) {
+ amdgpu_bo_unpin(robj);
+ amdgpu_bo_unreserve(robj);
+ }
+ drm_gem_object_unreference_unlocked(amdgpu_crtc->cursor_bo);
+ }
+
+ amdgpu_crtc->cursor_bo = obj;
+ return 0;
+fail:
+ drm_gem_object_unreference_unlocked(obj);
+
+ return ret;
+}
+
+static void dce_v10_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, uint32_t start, uint32_t size)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ int end = (start + size > 256) ? 256 : start + size, i;
+
+ /* userspace palettes are always correct as is */
+ for (i = start; i < end; i++) {
+ amdgpu_crtc->lut_r[i] = red[i] >> 6;
+ amdgpu_crtc->lut_g[i] = green[i] >> 6;
+ amdgpu_crtc->lut_b[i] = blue[i] >> 6;
+ }
+ dce_v10_0_crtc_load_lut(crtc);
+}
+
+static void dce_v10_0_crtc_destroy(struct drm_crtc *crtc)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+ drm_crtc_cleanup(crtc);
+ destroy_workqueue(amdgpu_crtc->pflip_queue);
+ kfree(amdgpu_crtc);
+}
+
+static const struct drm_crtc_funcs dce_v10_0_crtc_funcs = {
+ .cursor_set = dce_v10_0_crtc_cursor_set,
+ .cursor_move = dce_v10_0_crtc_cursor_move,
+ .gamma_set = dce_v10_0_crtc_gamma_set,
+ .set_config = amdgpu_crtc_set_config,
+ .destroy = dce_v10_0_crtc_destroy,
+ .page_flip = amdgpu_crtc_page_flip,
+};
+
+static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ amdgpu_crtc->enabled = true;
+ amdgpu_atombios_crtc_enable(crtc, ATOM_ENABLE);
+ dce_v10_0_vga_enable(crtc, true);
+ amdgpu_atombios_crtc_blank(crtc, ATOM_DISABLE);
+ dce_v10_0_vga_enable(crtc, false);
+ drm_vblank_post_modeset(dev, amdgpu_crtc->crtc_id);
+ dce_v10_0_crtc_load_lut(crtc);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ drm_vblank_pre_modeset(dev, amdgpu_crtc->crtc_id);
+ if (amdgpu_crtc->enabled) {
+ dce_v10_0_vga_enable(crtc, true);
+ amdgpu_atombios_crtc_blank(crtc, ATOM_ENABLE);
+ dce_v10_0_vga_enable(crtc, false);
+ }
+ amdgpu_atombios_crtc_enable(crtc, ATOM_DISABLE);
+ amdgpu_crtc->enabled = false;
+ break;
+ }
+ /* adjust pm to dpms */
+ amdgpu_pm_compute_clocks(adev);
+}
+
+static void dce_v10_0_crtc_prepare(struct drm_crtc *crtc)
+{
+ /* disable crtc pair power gating before programming */
+ amdgpu_atombios_crtc_powergate(crtc, ATOM_DISABLE);
+ amdgpu_atombios_crtc_lock(crtc, ATOM_ENABLE);
+ dce_v10_0_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void dce_v10_0_crtc_commit(struct drm_crtc *crtc)
+{
+ dce_v10_0_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+ amdgpu_atombios_crtc_lock(crtc, ATOM_DISABLE);
+}
+
+static void dce_v10_0_crtc_disable(struct drm_crtc *crtc)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_atom_ss ss;
+ int i;
+
+ dce_v10_0_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+ if (crtc->primary->fb) {
+ int r;
+ struct amdgpu_framebuffer *amdgpu_fb;
+ struct amdgpu_bo *rbo;
+
+ amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);
+ rbo = gem_to_amdgpu_bo(amdgpu_fb->obj);
+ r = amdgpu_bo_reserve(rbo, false);
+ if (unlikely(r))
+ DRM_ERROR("failed to reserve rbo before unpin\n");
+ else {
+ amdgpu_bo_unpin(rbo);
+ amdgpu_bo_unreserve(rbo);
+ }
+ }
+ /* disable the GRPH */
+ dce_v10_0_grph_enable(crtc, false);
+
+ amdgpu_atombios_crtc_powergate(crtc, ATOM_ENABLE);
+
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ if (adev->mode_info.crtcs[i] &&
+ adev->mode_info.crtcs[i]->enabled &&
+ i != amdgpu_crtc->crtc_id &&
+ amdgpu_crtc->pll_id == adev->mode_info.crtcs[i]->pll_id) {
+ /* one other crtc is using this pll don't turn
+ * off the pll
+ */
+ goto done;
+ }
+ }
+
+ switch (amdgpu_crtc->pll_id) {
+ case ATOM_PPLL0:
+ case ATOM_PPLL1:
+ case ATOM_PPLL2:
+ /* disable the ppll */
+ amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id, amdgpu_crtc->pll_id,
+ 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
+ break;
+ default:
+ break;
+ }
+done:
+ amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
+ amdgpu_crtc->adjusted_clock = 0;
+ amdgpu_crtc->encoder = NULL;
+ amdgpu_crtc->connector = NULL;
+}
+
+static int dce_v10_0_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y, struct drm_framebuffer *old_fb)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+ if (!amdgpu_crtc->adjusted_clock)
+ return -EINVAL;
+
+ amdgpu_atombios_crtc_set_pll(crtc, adjusted_mode);
+ amdgpu_atombios_crtc_set_dtd_timing(crtc, adjusted_mode);
+ dce_v10_0_crtc_do_set_base(crtc, old_fb, x, y, 0);
+ amdgpu_atombios_crtc_overscan_setup(crtc, mode, adjusted_mode);
+ amdgpu_atombios_crtc_scaler_setup(crtc);
+ /* update the hw version fpr dpm */
+ amdgpu_crtc->hw_mode = *adjusted_mode;
+
+ return 0;
+}
+
+static bool dce_v10_0_crtc_mode_fixup(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct drm_encoder *encoder;
+
+ /* assign the encoder to the amdgpu crtc to avoid repeated lookups later */
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ if (encoder->crtc == crtc) {
+ amdgpu_crtc->encoder = encoder;
+ amdgpu_crtc->connector = amdgpu_get_connector_for_encoder(encoder);
+ break;
+ }
+ }
+ if ((amdgpu_crtc->encoder == NULL) || (amdgpu_crtc->connector == NULL)) {
+ amdgpu_crtc->encoder = NULL;
+ amdgpu_crtc->connector = NULL;
+ return false;
+ }
+ if (!amdgpu_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
+ return false;
+ if (amdgpu_atombios_crtc_prepare_pll(crtc, adjusted_mode))
+ return false;
+ /* pick pll */
+ amdgpu_crtc->pll_id = dce_v10_0_pick_pll(crtc);
+ /* if we can't get a PPLL for a non-DP encoder, fail */
+ if ((amdgpu_crtc->pll_id == ATOM_PPLL_INVALID) &&
+ !ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder)))
+ return false;
+
+ return true;
+}
+
+static int dce_v10_0_crtc_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ return dce_v10_0_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+static int dce_v10_0_crtc_set_base_atomic(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, enum mode_set_atomic state)
+{
+ return dce_v10_0_crtc_do_set_base(crtc, fb, x, y, 1);
+}
+
+static const struct drm_crtc_helper_funcs dce_v10_0_crtc_helper_funcs = {
+ .dpms = dce_v10_0_crtc_dpms,
+ .mode_fixup = dce_v10_0_crtc_mode_fixup,
+ .mode_set = dce_v10_0_crtc_mode_set,
+ .mode_set_base = dce_v10_0_crtc_set_base,
+ .mode_set_base_atomic = dce_v10_0_crtc_set_base_atomic,
+ .prepare = dce_v10_0_crtc_prepare,
+ .commit = dce_v10_0_crtc_commit,
+ .load_lut = dce_v10_0_crtc_load_lut,
+ .disable = dce_v10_0_crtc_disable,
+};
+
+static int dce_v10_0_crtc_init(struct amdgpu_device *adev, int index)
+{
+ struct amdgpu_crtc *amdgpu_crtc;
+ int i;
+
+ amdgpu_crtc = kzalloc(sizeof(struct amdgpu_crtc) +
+ (AMDGPUFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
+ if (amdgpu_crtc == NULL)
+ return -ENOMEM;
+
+ drm_crtc_init(adev->ddev, &amdgpu_crtc->base, &dce_v10_0_crtc_funcs);
+
+ drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256);
+ amdgpu_crtc->crtc_id = index;
+ amdgpu_crtc->pflip_queue = create_singlethread_workqueue("amdgpu-pageflip-queue");
+ adev->mode_info.crtcs[index] = amdgpu_crtc;
+
+ amdgpu_crtc->max_cursor_width = 128;
+ amdgpu_crtc->max_cursor_height = 128;
+ adev->ddev->mode_config.cursor_width = amdgpu_crtc->max_cursor_width;
+ adev->ddev->mode_config.cursor_height = amdgpu_crtc->max_cursor_height;
+
+ for (i = 0; i < 256; i++) {
+ amdgpu_crtc->lut_r[i] = i << 2;
+ amdgpu_crtc->lut_g[i] = i << 2;
+ amdgpu_crtc->lut_b[i] = i << 2;
+ }
+
+ switch (amdgpu_crtc->crtc_id) {
+ case 0:
+ default:
+ amdgpu_crtc->crtc_offset = CRTC0_REGISTER_OFFSET;
+ break;
+ case 1:
+ amdgpu_crtc->crtc_offset = CRTC1_REGISTER_OFFSET;
+ break;
+ case 2:
+ amdgpu_crtc->crtc_offset = CRTC2_REGISTER_OFFSET;
+ break;
+ case 3:
+ amdgpu_crtc->crtc_offset = CRTC3_REGISTER_OFFSET;
+ break;
+ case 4:
+ amdgpu_crtc->crtc_offset = CRTC4_REGISTER_OFFSET;
+ break;
+ case 5:
+ amdgpu_crtc->crtc_offset = CRTC5_REGISTER_OFFSET;
+ break;
+ }
+
+ amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
+ amdgpu_crtc->adjusted_clock = 0;
+ amdgpu_crtc->encoder = NULL;
+ amdgpu_crtc->connector = NULL;
+ drm_crtc_helper_add(&amdgpu_crtc->base, &dce_v10_0_crtc_helper_funcs);
+
+ return 0;
+}
+
+static int dce_v10_0_early_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ adev->audio_endpt_rreg = &dce_v10_0_audio_endpt_rreg;
+ adev->audio_endpt_wreg = &dce_v10_0_audio_endpt_wreg;
+
+ dce_v10_0_set_display_funcs(adev);
+ dce_v10_0_set_irq_funcs(adev);
+
+ switch (adev->asic_type) {
+ case CHIP_TONGA:
+ adev->mode_info.num_crtc = 6; /* XXX 7??? */
+ adev->mode_info.num_hpd = 6;
+ adev->mode_info.num_dig = 7;
+ break;
+ default:
+ /* FIXME: not supported yet */
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int dce_v10_0_sw_init(void *handle)
+{
+ int r, i;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ r = amdgpu_irq_add_id(adev, i + 1, &adev->crtc_irq);
+ if (r)
+ return r;
+ }
+
+ for (i = 8; i < 20; i += 2) {
+ r = amdgpu_irq_add_id(adev, i, &adev->pageflip_irq);
+ if (r)
+ return r;
+ }
+
+ /* HPD hotplug */
+ r = amdgpu_irq_add_id(adev, 42, &adev->hpd_irq);
+ if (r)
+ return r;
+
+ adev->mode_info.mode_config_initialized = true;
+
+ adev->ddev->mode_config.funcs = &amdgpu_mode_funcs;
+
+ adev->ddev->mode_config.max_width = 16384;
+ adev->ddev->mode_config.max_height = 16384;
+
+ adev->ddev->mode_config.preferred_depth = 24;
+ adev->ddev->mode_config.prefer_shadow = 1;
+
+ adev->ddev->mode_config.fb_base = adev->mc.aper_base;
+
+ r = amdgpu_modeset_create_props(adev);
+ if (r)
+ return r;
+
+ adev->ddev->mode_config.max_width = 16384;
+ adev->ddev->mode_config.max_height = 16384;
+
+ /* allocate crtcs */
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ r = dce_v10_0_crtc_init(adev, i);
+ if (r)
+ return r;
+ }
+
+ if (amdgpu_atombios_get_connector_info_from_object_table(adev))
+ amdgpu_print_display_setup(adev->ddev);
+ else
+ return -EINVAL;
+
+ /* setup afmt */
+ dce_v10_0_afmt_init(adev);
+
+ r = dce_v10_0_audio_init(adev);
+ if (r)
+ return r;
+
+ drm_kms_helper_poll_init(adev->ddev);
+
+ return r;
+}
+
+static int dce_v10_0_sw_fini(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ kfree(adev->mode_info.bios_hardcoded_edid);
+
+ drm_kms_helper_poll_fini(adev->ddev);
+
+ dce_v10_0_audio_fini(adev);
+
+ dce_v10_0_afmt_fini(adev);
+
+ drm_mode_config_cleanup(adev->ddev);
+ adev->mode_info.mode_config_initialized = false;
+
+ return 0;
+}
+
+static int dce_v10_0_hw_init(void *handle)
+{
+ int i;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ dce_v10_0_init_golden_registers(adev);
+
+ /* init dig PHYs, disp eng pll */
+ amdgpu_atombios_encoder_init_dig(adev);
+ amdgpu_atombios_crtc_set_disp_eng_pll(adev, adev->clock.default_dispclk);
+
+ /* initialize hpd */
+ dce_v10_0_hpd_init(adev);
+
+ for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+ dce_v10_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
+ }
+
+ return 0;
+}
+
+static int dce_v10_0_hw_fini(void *handle)
+{
+ int i;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ dce_v10_0_hpd_fini(adev);
+
+ for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+ dce_v10_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
+ }
+
+ return 0;
+}
+
+static int dce_v10_0_suspend(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ amdgpu_atombios_scratch_regs_save(adev);
+
+ dce_v10_0_hpd_fini(adev);
+
+ return 0;
+}
+
+static int dce_v10_0_resume(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ dce_v10_0_init_golden_registers(adev);
+
+ amdgpu_atombios_scratch_regs_restore(adev);
+
+ /* init dig PHYs, disp eng pll */
+ amdgpu_atombios_encoder_init_dig(adev);
+ amdgpu_atombios_crtc_set_disp_eng_pll(adev, adev->clock.default_dispclk);
+ /* turn on the BL */
+ if (adev->mode_info.bl_encoder) {
+ u8 bl_level = amdgpu_display_backlight_get_level(adev,
+ adev->mode_info.bl_encoder);
+ amdgpu_display_backlight_set_level(adev, adev->mode_info.bl_encoder,
+ bl_level);
+ }
+
+ /* initialize hpd */
+ dce_v10_0_hpd_init(adev);
+
+ return 0;
+}
+
+static bool dce_v10_0_is_idle(void *handle)
+{
+ return true;
+}
+
+static int dce_v10_0_wait_for_idle(void *handle)
+{
+ return 0;
+}
+
+static void dce_v10_0_print_status(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ dev_info(adev->dev, "DCE 10.x registers\n");
+ /* XXX todo */
+}
+
+static int dce_v10_0_soft_reset(void *handle)
+{
+ u32 srbm_soft_reset = 0, tmp;
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+ if (dce_v10_0_is_display_hung(adev))
+ srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK;
+
+ if (srbm_soft_reset) {
+ dce_v10_0_print_status((void *)adev);
+
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+ tmp |= srbm_soft_reset;
+ dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+ WREG32(mmSRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+
+ udelay(50);
+
+ tmp &= ~srbm_soft_reset;
+ WREG32(mmSRBM_SOFT_RESET, tmp);
+ tmp = RREG32(mmSRBM_SOFT_RESET);
+
+ /* Wait a little for things to settle down */
+ udelay(50);
+ dce_v10_0_print_status((void *)adev);
+ }
+ return 0;
+}
+
+static void dce_v10_0_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev,
+ int crtc,
+ enum amdgpu_interrupt_state state)
+{
+ u32 lb_interrupt_mask;
+
+ if (crtc >= adev->mode_info.num_crtc) {
+ DRM_DEBUG("invalid crtc %d\n", crtc);
+ return;
+ }
+
+ switch (state) {
+ case AMDGPU_IRQ_STATE_DISABLE:
+ lb_interrupt_mask = RREG32(mmLB_INTERRUPT_MASK + crtc_offsets[crtc]);
+ lb_interrupt_mask = REG_SET_FIELD(lb_interrupt_mask, LB_INTERRUPT_MASK,
+ VBLANK_INTERRUPT_MASK, 0);
+ WREG32(mmLB_INTERRUPT_MASK + crtc_offsets[crtc], lb_interrupt_mask);
+ break;
+ case AMDGPU_IRQ_STATE_ENABLE:
+ lb_interrupt_mask = RREG32(mmLB_INTERRUPT_MASK + crtc_offsets[crtc]);
+ lb_interrupt_mask = REG_SET_FIELD(lb_interrupt_mask, LB_INTERRUPT_MASK,
+ VBLANK_INTERRUPT_MASK, 1);
+ WREG32(mmLB_INTERRUPT_MASK + crtc_offsets[crtc], lb_interrupt_mask);
+ break;
+ default:
+ break;
+ }
+}
+
+static void dce_v10_0_set_crtc_vline_interrupt_state(struct amdgpu_device *adev,
+ int crtc,
+ enum amdgpu_interrupt_state state)
+{
+ u32 lb_interrupt_mask;
+
+ if (crtc >= adev->mode_info.num_crtc) {
+ DRM_DEBUG("invalid crtc %d\n", crtc);
+ return;
+ }
+
+ switch (state) {
+ case AMDGPU_IRQ_STATE_DISABLE:
+ lb_interrupt_mask = RREG32(mmLB_INTERRUPT_MASK + crtc_offsets[crtc]);
+ lb_interrupt_mask = REG_SET_FIELD(lb_interrupt_mask, LB_INTERRUPT_MASK,
+ VLINE_INTERRUPT_MASK, 0);
+ WREG32(mmLB_INTERRUPT_MASK + crtc_offsets[crtc], lb_interrupt_mask);
+ break;
+ case AMDGPU_IRQ_STATE_ENABLE:
+ lb_interrupt_mask = RREG32(mmLB_INTERRUPT_MASK + crtc_offsets[crtc]);
+ lb_interrupt_mask = REG_SET_FIELD(lb_interrupt_mask, LB_INTERRUPT_MASK,
+ VLINE_INTERRUPT_MASK, 1);
+ WREG32(mmLB_INTERRUPT_MASK + crtc_offsets[crtc], lb_interrupt_mask);
+ break;
+ default:
+ break;
+ }
+}
+
+static int dce_v10_0_set_hpd_irq_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ unsigned hpd,
+ enum amdgpu_interrupt_state state)
+{
+ u32 tmp;
+
+ if (hpd >= adev->mode_info.num_hpd) {
+ DRM_DEBUG("invalid hdp %d\n", hpd);
+ return 0;
+ }
+
+ switch (state) {
+ case AMDGPU_IRQ_STATE_DISABLE:
+ tmp = RREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[hpd]);
+ tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_EN, 0);
+ WREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[hpd], tmp);
+ break;
+ case AMDGPU_IRQ_STATE_ENABLE:
+ tmp = RREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[hpd]);
+ tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_EN, 1);
+ WREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[hpd], tmp);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int dce_v10_0_set_crtc_irq_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ unsigned type,
+ enum amdgpu_interrupt_state state)
+{
+ switch (type) {
+ case AMDGPU_CRTC_IRQ_VBLANK1:
+ dce_v10_0_set_crtc_vblank_interrupt_state(adev, 0, state);
+ break;
+ case AMDGPU_CRTC_IRQ_VBLANK2:
+ dce_v10_0_set_crtc_vblank_interrupt_state(adev, 1, state);
+ break;
+ case AMDGPU_CRTC_IRQ_VBLANK3:
+ dce_v10_0_set_crtc_vblank_interrupt_state(adev, 2, state);
+ break;
+ case AMDGPU_CRTC_IRQ_VBLANK4:
+ dce_v10_0_set_crtc_vblank_interrupt_state(adev, 3, state);
+ break;
+ case AMDGPU_CRTC_IRQ_VBLANK5:
+ dce_v10_0_set_crtc_vblank_interrupt_state(adev, 4, state);
+ break;
+ case AMDGPU_CRTC_IRQ_VBLANK6:
+ dce_v10_0_set_crtc_vblank_interrupt_state(adev, 5, state);
+ break;
+ case AMDGPU_CRTC_IRQ_VLINE1:
+ dce_v10_0_set_crtc_vline_interrupt_state(adev, 0, state);
+ break;
+ case AMDGPU_CRTC_IRQ_VLINE2:
+ dce_v10_0_set_crtc_vline_interrupt_state(adev, 1, state);
+ break;
+ case AMDGPU_CRTC_IRQ_VLINE3:
+ dce_v10_0_set_crtc_vline_interrupt_state(adev, 2, state);
+ break;
+ case AMDGPU_CRTC_IRQ_VLINE4:
+ dce_v10_0_set_crtc_vline_interrupt_state(adev, 3, state);
+ break;
+ case AMDGPU_CRTC_IRQ_VLINE5:
+ dce_v10_0_set_crtc_vline_interrupt_state(adev, 4, state);
+ break;
+ case AMDGPU_CRTC_IRQ_VLINE6:
+ dce_v10_0_set_crtc_vline_interrupt_state(adev, 5, state);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int dce_v10_0_set_pageflip_irq_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *src,
+ unsigned type,
+ enum amdgpu_interrupt_state state)
+{
+ u32 reg, reg_block;
+ /* now deal with page flip IRQ */
+ switch (type) {
+ case AMDGPU_PAGEFLIP_IRQ_D1:
+ reg_block = CRTC0_REGISTER_OFFSET;
+ break;
+ case AMDGPU_PAGEFLIP_IRQ_D2:
+ reg_block = CRTC1_REGISTER_OFFSET;
+ break;
+ case AMDGPU_PAGEFLIP_IRQ_D3:
+ reg_block = CRTC2_REGISTER_OFFSET;
+ break;
+ case AMDGPU_PAGEFLIP_IRQ_D4:
+ reg_block = CRTC3_REGISTER_OFFSET;
+ break;
+ case AMDGPU_PAGEFLIP_IRQ_D5:
+ reg_block = CRTC4_REGISTER_OFFSET;
+ break;
+ case AMDGPU_PAGEFLIP_IRQ_D6:
+ reg_block = CRTC5_REGISTER_OFFSET;
+ break;
+ default:
+ DRM_ERROR("invalid pageflip crtc %d\n", type);
+ return -EINVAL;
+ }
+
+ reg = RREG32(mmGRPH_INTERRUPT_CONTROL + reg_block);
+ if (state == AMDGPU_IRQ_STATE_DISABLE)
+ WREG32(mmGRPH_INTERRUPT_CONTROL + reg_block, reg & ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK);
+ else
+ WREG32(mmGRPH_INTERRUPT_CONTROL + reg_block, reg | GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK);
+
+ return 0;
+}
+
+static int dce_v10_0_pageflip_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ int reg_block;
+ unsigned long flags;
+ unsigned crtc_id;
+ struct amdgpu_crtc *amdgpu_crtc;
+ struct amdgpu_flip_work *works;
+
+ crtc_id = (entry->src_id - 8) >> 1;
+ amdgpu_crtc = adev->mode_info.crtcs[crtc_id];
+
+ /* ack the interrupt */
+ switch(crtc_id){
+ case AMDGPU_PAGEFLIP_IRQ_D1:
+ reg_block = CRTC0_REGISTER_OFFSET;
+ break;
+ case AMDGPU_PAGEFLIP_IRQ_D2:
+ reg_block = CRTC1_REGISTER_OFFSET;
+ break;
+ case AMDGPU_PAGEFLIP_IRQ_D3:
+ reg_block = CRTC2_REGISTER_OFFSET;
+ break;
+ case AMDGPU_PAGEFLIP_IRQ_D4:
+ reg_block = CRTC3_REGISTER_OFFSET;
+ break;
+ case AMDGPU_PAGEFLIP_IRQ_D5:
+ reg_block = CRTC4_REGISTER_OFFSET;
+ break;
+ case AMDGPU_PAGEFLIP_IRQ_D6:
+ reg_block = CRTC5_REGISTER_OFFSET;
+ break;
+ default:
+ DRM_ERROR("invalid pageflip crtc %d\n", crtc_id);
+ return -EINVAL;
+ }
+
+ if (RREG32(mmGRPH_INTERRUPT_STATUS + reg_block) & GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_OCCURRED_MASK)
+ WREG32(mmGRPH_INTERRUPT_STATUS + reg_block, GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK);
+
+ /* IRQ could occur when in initial stage */
+ if (amdgpu_crtc == NULL)
+ return 0;
+
+ spin_lock_irqsave(&adev->ddev->event_lock, flags);
+ works = amdgpu_crtc->pflip_works;
+ if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) {
+ DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != "
+ "AMDGPU_FLIP_SUBMITTED(%d)\n",
+ amdgpu_crtc->pflip_status,
+ AMDGPU_FLIP_SUBMITTED);
+ spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+ return 0;
+ }
+
+ /* page flip completed. clean up */
+ amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
+ amdgpu_crtc->pflip_works = NULL;
+
+ /* wakeup usersapce */
+ if (works->event)
+ drm_send_vblank_event(adev->ddev, crtc_id, works->event);
+
+ spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+
+ drm_vblank_put(adev->ddev, amdgpu_crtc->crtc_id);
+ amdgpu_irq_put(adev, &adev->pageflip_irq, crtc_id);
+ queue_work(amdgpu_crtc->pflip_queue, &works->unpin_work);
+
+ return 0;
+}
+
+static void dce_v10_0_hpd_int_ack(struct amdgpu_device *adev,
+ int hpd)
+{
+ u32 tmp;
+
+ if (hpd >= adev->mode_info.num_hpd) {
+ DRM_DEBUG("invalid hdp %d\n", hpd);
+ return;
+ }
+
+ tmp = RREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[hpd]);
+ tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_ACK, 1);
+ WREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[hpd], tmp);
+}
+
+static void dce_v10_0_crtc_vblank_int_ack(struct amdgpu_device *adev,
+ int crtc)
+{
+ u32 tmp;
+
+ if (crtc >= adev->mode_info.num_crtc) {
+ DRM_DEBUG("invalid crtc %d\n", crtc);
+ return;
+ }
+
+ tmp = RREG32(mmLB_VBLANK_STATUS + crtc_offsets[crtc]);
+ tmp = REG_SET_FIELD(tmp, LB_VBLANK_STATUS, VBLANK_ACK, 1);
+ WREG32(mmLB_VBLANK_STATUS + crtc_offsets[crtc], tmp);
+}
+
+static void dce_v10_0_crtc_vline_int_ack(struct amdgpu_device *adev,
+ int crtc)
+{
+ u32 tmp;
+
+ if (crtc >= adev->mode_info.num_crtc) {
+ DRM_DEBUG("invalid crtc %d\n", crtc);
+ return;
+ }
+
+ tmp = RREG32(mmLB_VLINE_STATUS + crtc_offsets[crtc]);
+ tmp = REG_SET_FIELD(tmp, LB_VLINE_STATUS, VLINE_ACK, 1);
+ WREG32(mmLB_VLINE_STATUS + crtc_offsets[crtc], tmp);
+}
+
+static int dce_v10_0_crtc_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ unsigned crtc = entry->src_id - 1;
+ uint32_t disp_int = RREG32(interrupt_status_offsets[crtc].reg);
+ unsigned irq_type = amdgpu_crtc_idx_to_irq_type(adev, crtc);
+
+ switch (entry->src_data) {
+ case 0: /* vblank */
+ if (disp_int & interrupt_status_offsets[crtc].vblank) {
+ dce_v10_0_crtc_vblank_int_ack(adev, crtc);
+ if (amdgpu_irq_enabled(adev, source, irq_type)) {
+ drm_handle_vblank(adev->ddev, crtc);
+ }
+ DRM_DEBUG("IH: D%d vblank\n", crtc + 1);
+ }
+ break;
+ case 1: /* vline */
+ if (disp_int & interrupt_status_offsets[crtc].vline) {
+ dce_v10_0_crtc_vline_int_ack(adev, crtc);
+ DRM_DEBUG("IH: D%d vline\n", crtc + 1);
+ }
+ break;
+ default:
+ DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data);
+ break;
+ }
+
+ return 0;
+}
+
+static int dce_v10_0_hpd_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ uint32_t disp_int, mask;
+ unsigned hpd;
+
+ if (entry->src_data >= adev->mode_info.num_hpd) {
+ DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data);
+ return 0;
+ }
+
+ hpd = entry->src_data;
+ disp_int = RREG32(interrupt_status_offsets[hpd].reg);
+ mask = interrupt_status_offsets[hpd].hpd;
+
+ if (disp_int & mask) {
+ dce_v10_0_hpd_int_ack(adev, hpd);
+ schedule_work(&adev->hotplug_work);
+ DRM_DEBUG("IH: HPD%d\n", hpd + 1);
+ }
+
+ return 0;
+}
+
+static int dce_v10_0_set_clockgating_state(void *handle,
+ enum amd_clockgating_state state)
+{
+ return 0;
+}
+
+static int dce_v10_0_set_powergating_state(void *handle,
+ enum amd_powergating_state state)
+{
+ return 0;
+}
+
+const struct amd_ip_funcs dce_v10_0_ip_funcs = {
+ .early_init = dce_v10_0_early_init,
+ .late_init = NULL,
+ .sw_init = dce_v10_0_sw_init,
+ .sw_fini = dce_v10_0_sw_fini,
+ .hw_init = dce_v10_0_hw_init,
+ .hw_fini = dce_v10_0_hw_fini,
+ .suspend = dce_v10_0_suspend,
+ .resume = dce_v10_0_resume,
+ .is_idle = dce_v10_0_is_idle,
+ .wait_for_idle = dce_v10_0_wait_for_idle,
+ .soft_reset = dce_v10_0_soft_reset,
+ .print_status = dce_v10_0_print_status,
+ .set_clockgating_state = dce_v10_0_set_clockgating_state,
+ .set_powergating_state = dce_v10_0_set_powergating_state,
+};
+
+static void
+dce_v10_0_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+ amdgpu_encoder->pixel_clock = adjusted_mode->clock;
+
+ /* need to call this here rather than in prepare() since we need some crtc info */
+ amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+ /* set scaler clears this on some chips */
+ dce_v10_0_set_interleave(encoder->crtc, mode);
+
+ if (amdgpu_atombios_encoder_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
+ dce_v10_0_afmt_enable(encoder, true);
+ dce_v10_0_afmt_setmode(encoder, adjusted_mode);
+ }
+}
+
+static void dce_v10_0_encoder_prepare(struct drm_encoder *encoder)
+{
+ struct amdgpu_device *adev = encoder->dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+
+ if ((amdgpu_encoder->active_device &
+ (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) ||
+ (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) !=
+ ENCODER_OBJECT_ID_NONE)) {
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ if (dig) {
+ dig->dig_encoder = dce_v10_0_pick_dig_encoder(encoder);
+ if (amdgpu_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT)
+ dig->afmt = adev->mode_info.afmt[dig->dig_encoder];
+ }
+ }
+
+ amdgpu_atombios_scratch_regs_lock(adev, true);
+
+ if (connector) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+ /* select the clock/data port if it uses a router */
+ if (amdgpu_connector->router.cd_valid)
+ amdgpu_i2c_router_select_cd_port(amdgpu_connector);
+
+ /* turn eDP panel on for mode set */
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+ amdgpu_atombios_encoder_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_ON);
+ }
+
+ /* this is needed for the pll/ss setup to work correctly in some cases */
+ amdgpu_atombios_encoder_set_crtc_source(encoder);
+ /* set up the FMT blocks */
+ dce_v10_0_program_fmt(encoder);
+}
+
+static void dce_v10_0_encoder_commit(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+
+ /* need to call this here as we need the crtc set up */
+ amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+ amdgpu_atombios_scratch_regs_lock(adev, false);
+}
+
+static void dce_v10_0_encoder_disable(struct drm_encoder *encoder)
+{
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig;
+
+ amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+ if (amdgpu_atombios_encoder_is_digital(encoder)) {
+ if (amdgpu_atombios_encoder_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI)
+ dce_v10_0_afmt_enable(encoder, false);
+ dig = amdgpu_encoder->enc_priv;
+ dig->dig_encoder = -1;
+ }
+ amdgpu_encoder->active_device = 0;
+}
+
+/* these are handled by the primary encoders */
+static void dce_v10_0_ext_prepare(struct drm_encoder *encoder)
+{
+
+}
+
+static void dce_v10_0_ext_commit(struct drm_encoder *encoder)
+{
+
+}
+
+static void
+dce_v10_0_ext_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+
+}
+
+static void dce_v10_0_ext_disable(struct drm_encoder *encoder)
+{
+
+}
+
+static void
+dce_v10_0_ext_dpms(struct drm_encoder *encoder, int mode)
+{
+
+}
+
+static bool dce_v10_0_ext_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static const struct drm_encoder_helper_funcs dce_v10_0_ext_helper_funcs = {
+ .dpms = dce_v10_0_ext_dpms,
+ .mode_fixup = dce_v10_0_ext_mode_fixup,
+ .prepare = dce_v10_0_ext_prepare,
+ .mode_set = dce_v10_0_ext_mode_set,
+ .commit = dce_v10_0_ext_commit,
+ .disable = dce_v10_0_ext_disable,
+ /* no detect for TMDS/LVDS yet */
+};
+
+static const struct drm_encoder_helper_funcs dce_v10_0_dig_helper_funcs = {
+ .dpms = amdgpu_atombios_encoder_dpms,
+ .mode_fixup = amdgpu_atombios_encoder_mode_fixup,
+ .prepare = dce_v10_0_encoder_prepare,
+ .mode_set = dce_v10_0_encoder_mode_set,
+ .commit = dce_v10_0_encoder_commit,
+ .disable = dce_v10_0_encoder_disable,
+ .detect = amdgpu_atombios_encoder_dig_detect,
+};
+
+static const struct drm_encoder_helper_funcs dce_v10_0_dac_helper_funcs = {
+ .dpms = amdgpu_atombios_encoder_dpms,
+ .mode_fixup = amdgpu_atombios_encoder_mode_fixup,
+ .prepare = dce_v10_0_encoder_prepare,
+ .mode_set = dce_v10_0_encoder_mode_set,
+ .commit = dce_v10_0_encoder_commit,
+ .detect = amdgpu_atombios_encoder_dac_detect,
+};
+
+static void dce_v10_0_encoder_destroy(struct drm_encoder *encoder)
+{
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+ amdgpu_atombios_encoder_fini_backlight(amdgpu_encoder);
+ kfree(amdgpu_encoder->enc_priv);
+ drm_encoder_cleanup(encoder);
+ kfree(amdgpu_encoder);
+}
+
+static const struct drm_encoder_funcs dce_v10_0_encoder_funcs = {
+ .destroy = dce_v10_0_encoder_destroy,
+};
+
+static void dce_v10_0_encoder_add(struct amdgpu_device *adev,
+ uint32_t encoder_enum,
+ uint32_t supported_device,
+ u16 caps)
+{
+ struct drm_device *dev = adev->ddev;
+ struct drm_encoder *encoder;
+ struct amdgpu_encoder *amdgpu_encoder;
+
+ /* see if we already added it */
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ amdgpu_encoder = to_amdgpu_encoder(encoder);
+ if (amdgpu_encoder->encoder_enum == encoder_enum) {
+ amdgpu_encoder->devices |= supported_device;
+ return;
+ }
+
+ }
+
+ /* add a new one */
+ amdgpu_encoder = kzalloc(sizeof(struct amdgpu_encoder), GFP_KERNEL);
+ if (!amdgpu_encoder)
+ return;
+
+ encoder = &amdgpu_encoder->base;
+ switch (adev->mode_info.num_crtc) {
+ case 1:
+ encoder->possible_crtcs = 0x1;
+ break;
+ case 2:
+ default:
+ encoder->possible_crtcs = 0x3;
+ break;
+ case 4:
+ encoder->possible_crtcs = 0xf;
+ break;
+ case 6:
+ encoder->possible_crtcs = 0x3f;
+ break;
+ }
+
+ amdgpu_encoder->enc_priv = NULL;
+
+ amdgpu_encoder->encoder_enum = encoder_enum;
+ amdgpu_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+ amdgpu_encoder->devices = supported_device;
+ amdgpu_encoder->rmx_type = RMX_OFF;
+ amdgpu_encoder->underscan_type = UNDERSCAN_OFF;
+ amdgpu_encoder->is_ext_encoder = false;
+ amdgpu_encoder->caps = caps;
+
+ switch (amdgpu_encoder->encoder_id) {
+ 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_encoder_helper_add(encoder, &dce_v10_0_dac_helper_funcs);
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+ 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);
+ 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);
+ 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);
+ amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_dig_info(amdgpu_encoder);
+ }
+ drm_encoder_helper_add(encoder, &dce_v10_0_dig_helper_funcs);
+ break;
+ case ENCODER_OBJECT_ID_SI170B:
+ case ENCODER_OBJECT_ID_CH7303:
+ case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
+ case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
+ case ENCODER_OBJECT_ID_TITFP513:
+ case ENCODER_OBJECT_ID_VT1623:
+ case ENCODER_OBJECT_ID_HDMI_SI1930:
+ case ENCODER_OBJECT_ID_TRAVIS:
+ case ENCODER_OBJECT_ID_NUTMEG:
+ /* these are handled by the primary encoders */
+ 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);
+ else if (amdgpu_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
+ drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
+ DRM_MODE_ENCODER_DAC);
+ else
+ drm_encoder_init(dev, encoder, &dce_v10_0_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+ drm_encoder_helper_add(encoder, &dce_v10_0_ext_helper_funcs);
+ break;
+ }
+}
+
+static const struct amdgpu_display_funcs dce_v10_0_display_funcs = {
+ .set_vga_render_state = &dce_v10_0_set_vga_render_state,
+ .bandwidth_update = &dce_v10_0_bandwidth_update,
+ .vblank_get_counter = &dce_v10_0_vblank_get_counter,
+ .vblank_wait = &dce_v10_0_vblank_wait,
+ .is_display_hung = &dce_v10_0_is_display_hung,
+ .backlight_set_level = &amdgpu_atombios_encoder_set_backlight_level,
+ .backlight_get_level = &amdgpu_atombios_encoder_get_backlight_level,
+ .hpd_sense = &dce_v10_0_hpd_sense,
+ .hpd_set_polarity = &dce_v10_0_hpd_set_polarity,
+ .hpd_get_gpio_reg = &dce_v10_0_hpd_get_gpio_reg,
+ .page_flip = &dce_v10_0_page_flip,
+ .page_flip_get_scanoutpos = &dce_v10_0_crtc_get_scanoutpos,
+ .add_encoder = &dce_v10_0_encoder_add,
+ .add_connector = &amdgpu_connector_add,
+ .stop_mc_access = &dce_v10_0_stop_mc_access,
+ .resume_mc_access = &dce_v10_0_resume_mc_access,
+};
+
+static void dce_v10_0_set_display_funcs(struct amdgpu_device *adev)
+{
+ if (adev->mode_info.funcs == NULL)
+ adev->mode_info.funcs = &dce_v10_0_display_funcs;
+}
+
+static const struct amdgpu_irq_src_funcs dce_v10_0_crtc_irq_funcs = {
+ .set = dce_v10_0_set_crtc_irq_state,
+ .process = dce_v10_0_crtc_irq,
+};
+
+static const struct amdgpu_irq_src_funcs dce_v10_0_pageflip_irq_funcs = {
+ .set = dce_v10_0_set_pageflip_irq_state,
+ .process = dce_v10_0_pageflip_irq,
+};
+
+static const struct amdgpu_irq_src_funcs dce_v10_0_hpd_irq_funcs = {
+ .set = dce_v10_0_set_hpd_irq_state,
+ .process = dce_v10_0_hpd_irq,
+};
+
+static void dce_v10_0_set_irq_funcs(struct amdgpu_device *adev)
+{
+ adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_LAST;
+ adev->crtc_irq.funcs = &dce_v10_0_crtc_irq_funcs;
+
+ adev->pageflip_irq.num_types = AMDGPU_PAGEFLIP_IRQ_LAST;
+ adev->pageflip_irq.funcs = &dce_v10_0_pageflip_irq_funcs;
+
+ adev->hpd_irq.num_types = AMDGPU_HPD_LAST;
+ adev->hpd_irq.funcs = &dce_v10_0_hpd_irq_funcs;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.h b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.h
new file mode 100644
index 000000000000..1bfa48ddd8a6
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.h
@@ -0,0 +1,29 @@
+/*
+ * 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 __DCE_V10_0_H__
+#define __DCE_V10_0_H__
+
+extern const struct amd_ip_funcs dce_v10_0_ip_funcs;
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
new file mode 100644
index 000000000000..95efd98b202d
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
@@ -0,0 +1,3801 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "drmP.h"
+#include "amdgpu.h"
+#include "amdgpu_pm.h"
+#include "amdgpu_i2c.h"
+#include "vid.h"
+#include "atom.h"
+#include "amdgpu_atombios.h"
+#include "atombios_crtc.h"
+#include "atombios_encoders.h"
+#include "amdgpu_pll.h"
+#include "amdgpu_connectors.h"
+
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+#include "dce/dce_11_0_enum.h"
+#include "oss/oss_3_0_d.h"
+#include "oss/oss_3_0_sh_mask.h"
+#include "gmc/gmc_8_1_d.h"
+#include "gmc/gmc_8_1_sh_mask.h"
+
+static void dce_v11_0_set_display_funcs(struct amdgpu_device *adev);
+static void dce_v11_0_set_irq_funcs(struct amdgpu_device *adev);
+
+static const u32 crtc_offsets[] =
+{
+ CRTC0_REGISTER_OFFSET,
+ CRTC1_REGISTER_OFFSET,
+ CRTC2_REGISTER_OFFSET,
+ CRTC3_REGISTER_OFFSET,
+ CRTC4_REGISTER_OFFSET,
+ CRTC5_REGISTER_OFFSET,
+ CRTC6_REGISTER_OFFSET
+};
+
+static const u32 hpd_offsets[] =
+{
+ HPD0_REGISTER_OFFSET,
+ HPD1_REGISTER_OFFSET,
+ HPD2_REGISTER_OFFSET,
+ HPD3_REGISTER_OFFSET,
+ HPD4_REGISTER_OFFSET,
+ HPD5_REGISTER_OFFSET
+};
+
+static const uint32_t dig_offsets[] = {
+ DIG0_REGISTER_OFFSET,
+ DIG1_REGISTER_OFFSET,
+ DIG2_REGISTER_OFFSET,
+ DIG3_REGISTER_OFFSET,
+ DIG4_REGISTER_OFFSET,
+ DIG5_REGISTER_OFFSET,
+ DIG6_REGISTER_OFFSET,
+ DIG7_REGISTER_OFFSET,
+ DIG8_REGISTER_OFFSET
+};
+
+static const struct {
+ uint32_t reg;
+ uint32_t vblank;
+ uint32_t vline;
+ uint32_t hpd;
+
+} interrupt_status_offsets[] = { {
+ .reg = mmDISP_INTERRUPT_STATUS,
+ .vblank = DISP_INTERRUPT_STATUS__LB_D1_VBLANK_INTERRUPT_MASK,
+ .vline = DISP_INTERRUPT_STATUS__LB_D1_VLINE_INTERRUPT_MASK,
+ .hpd = DISP_INTERRUPT_STATUS__DC_HPD1_INTERRUPT_MASK
+}, {
+ .reg = mmDISP_INTERRUPT_STATUS_CONTINUE,
+ .vblank = DISP_INTERRUPT_STATUS_CONTINUE__LB_D2_VBLANK_INTERRUPT_MASK,
+ .vline = DISP_INTERRUPT_STATUS_CONTINUE__LB_D2_VLINE_INTERRUPT_MASK,
+ .hpd = DISP_INTERRUPT_STATUS_CONTINUE__DC_HPD2_INTERRUPT_MASK
+}, {
+ .reg = mmDISP_INTERRUPT_STATUS_CONTINUE2,
+ .vblank = DISP_INTERRUPT_STATUS_CONTINUE2__LB_D3_VBLANK_INTERRUPT_MASK,
+ .vline = DISP_INTERRUPT_STATUS_CONTINUE2__LB_D3_VLINE_INTERRUPT_MASK,
+ .hpd = DISP_INTERRUPT_STATUS_CONTINUE2__DC_HPD3_INTERRUPT_MASK
+}, {
+ .reg = mmDISP_INTERRUPT_STATUS_CONTINUE3,
+ .vblank = DISP_INTERRUPT_STATUS_CONTINUE3__LB_D4_VBLANK_INTERRUPT_MASK,
+ .vline = DISP_INTERRUPT_STATUS_CONTINUE3__LB_D4_VLINE_INTERRUPT_MASK,
+ .hpd = DISP_INTERRUPT_STATUS_CONTINUE3__DC_HPD4_INTERRUPT_MASK
+}, {
+ .reg = mmDISP_INTERRUPT_STATUS_CONTINUE4,
+ .vblank = DISP_INTERRUPT_STATUS_CONTINUE4__LB_D5_VBLANK_INTERRUPT_MASK,
+ .vline = DISP_INTERRUPT_STATUS_CONTINUE4__LB_D5_VLINE_INTERRUPT_MASK,
+ .hpd = DISP_INTERRUPT_STATUS_CONTINUE4__DC_HPD5_INTERRUPT_MASK
+}, {
+ .reg = mmDISP_INTERRUPT_STATUS_CONTINUE5,
+ .vblank = DISP_INTERRUPT_STATUS_CONTINUE5__LB_D6_VBLANK_INTERRUPT_MASK,
+ .vline = DISP_INTERRUPT_STATUS_CONTINUE5__LB_D6_VLINE_INTERRUPT_MASK,
+ .hpd = DISP_INTERRUPT_STATUS_CONTINUE5__DC_HPD6_INTERRUPT_MASK
+} };
+
+static const u32 cz_golden_settings_a11[] =
+{
+ mmCRTC_DOUBLE_BUFFER_CONTROL, 0x00010101, 0x00010000,
+ mmFBC_MISC, 0x1f311fff, 0x14300000,
+};
+
+static const u32 cz_mgcg_cgcg_init[] =
+{
+ mmXDMA_CLOCK_GATING_CNTL, 0xffffffff, 0x00000100,
+ mmXDMA_MEM_POWER_CNTL, 0x00000101, 0x00000000,
+};
+
+static void dce_v11_0_init_golden_registers(struct amdgpu_device *adev)
+{
+ switch (adev->asic_type) {
+ case CHIP_CARRIZO:
+ amdgpu_program_register_sequence(adev,
+ cz_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(cz_mgcg_cgcg_init));
+ amdgpu_program_register_sequence(adev,
+ cz_golden_settings_a11,
+ (const u32)ARRAY_SIZE(cz_golden_settings_a11));
+ break;
+ default:
+ break;
+ }
+}
+
+static u32 dce_v11_0_audio_endpt_rreg(struct amdgpu_device *adev,
+ u32 block_offset, u32 reg)
+{
+ unsigned long flags;
+ u32 r;
+
+ spin_lock_irqsave(&adev->audio_endpt_idx_lock, flags);
+ WREG32(mmAZALIA_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
+ r = RREG32(mmAZALIA_F0_CODEC_ENDPOINT_DATA + block_offset);
+ spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags);
+
+ return r;
+}
+
+static void dce_v11_0_audio_endpt_wreg(struct amdgpu_device *adev,
+ u32 block_offset, u32 reg, u32 v)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&adev->audio_endpt_idx_lock, flags);
+ WREG32(mmAZALIA_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
+ WREG32(mmAZALIA_F0_CODEC_ENDPOINT_DATA + block_offset, v);
+ spin_unlock_irqrestore(&adev->audio_endpt_idx_lock, flags);
+}
+
+static bool dce_v11_0_is_in_vblank(struct amdgpu_device *adev, int crtc)
+{
+ if (RREG32(mmCRTC_STATUS + crtc_offsets[crtc]) &
+ CRTC_V_BLANK_START_END__CRTC_V_BLANK_START_MASK)
+ return true;
+ else
+ return false;
+}
+
+static bool dce_v11_0_is_counter_moving(struct amdgpu_device *adev, int crtc)
+{
+ u32 pos1, pos2;
+
+ pos1 = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]);
+ pos2 = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]);
+
+ if (pos1 != pos2)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * dce_v11_0_vblank_wait - vblank wait asic callback.
+ *
+ * @adev: amdgpu_device pointer
+ * @crtc: crtc to wait for vblank on
+ *
+ * Wait for vblank on the requested crtc (evergreen+).
+ */
+static void dce_v11_0_vblank_wait(struct amdgpu_device *adev, int crtc)
+{
+ unsigned i = 0;
+
+ if (crtc >= adev->mode_info.num_crtc)
+ return;
+
+ if (!(RREG32(mmCRTC_CONTROL + crtc_offsets[crtc]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK))
+ return;
+
+ /* depending on when we hit vblank, we may be close to active; if so,
+ * wait for another frame.
+ */
+ while (dce_v11_0_is_in_vblank(adev, crtc)) {
+ if (i++ % 100 == 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 (!dce_v11_0_is_counter_moving(adev, crtc))
+ break;
+ }
+ }
+}
+
+static u32 dce_v11_0_vblank_get_counter(struct amdgpu_device *adev, int crtc)
+{
+ if (crtc >= adev->mode_info.num_crtc)
+ return 0;
+ else
+ return RREG32(mmCRTC_STATUS_FRAME_COUNT + crtc_offsets[crtc]);
+}
+
+/**
+ * dce_v11_0_page_flip - pageflip callback.
+ *
+ * @adev: amdgpu_device pointer
+ * @crtc_id: crtc to cleanup pageflip on
+ * @crtc_base: new address of the crtc (GPU MC address)
+ *
+ * Does the actual pageflip (evergreen+).
+ * During vblank we take the crtc lock and wait for the update_pending
+ * bit to go high, when it does, we release the lock, and allow the
+ * double buffered update to take place.
+ * Returns the current update pending status.
+ */
+static void dce_v11_0_page_flip(struct amdgpu_device *adev,
+ int crtc_id, u64 crtc_base)
+{
+ struct amdgpu_crtc *amdgpu_crtc = adev->mode_info.crtcs[crtc_id];
+ u32 tmp = RREG32(mmGRPH_UPDATE + amdgpu_crtc->crtc_offset);
+ int i;
+
+ /* Lock the graphics update lock */
+ tmp = REG_SET_FIELD(tmp, GRPH_UPDATE, GRPH_UPDATE_LOCK, 1);
+ WREG32(mmGRPH_UPDATE + amdgpu_crtc->crtc_offset, tmp);
+
+ /* update the scanout addresses */
+ WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
+ upper_32_bits(crtc_base));
+ WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset,
+ lower_32_bits(crtc_base));
+
+ WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
+ upper_32_bits(crtc_base));
+ WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS + amdgpu_crtc->crtc_offset,
+ lower_32_bits(crtc_base));
+
+ /* Wait for update_pending to go high. */
+ for (i = 0; i < adev->usec_timeout; i++) {
+ if (RREG32(mmGRPH_UPDATE + amdgpu_crtc->crtc_offset) &
+ GRPH_UPDATE__GRPH_SURFACE_UPDATE_PENDING_MASK)
+ break;
+ udelay(1);
+ }
+ DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");
+
+ /* Unlock the lock, so double-buffering can take place inside vblank */
+ tmp = REG_SET_FIELD(tmp, GRPH_UPDATE, GRPH_UPDATE_LOCK, 0);
+ WREG32(mmGRPH_UPDATE + amdgpu_crtc->crtc_offset, tmp);
+}
+
+static int dce_v11_0_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
+ u32 *vbl, u32 *position)
+{
+ if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc))
+ return -EINVAL;
+
+ *vbl = RREG32(mmCRTC_V_BLANK_START_END + crtc_offsets[crtc]);
+ *position = RREG32(mmCRTC_STATUS_POSITION + crtc_offsets[crtc]);
+
+ return 0;
+}
+
+/**
+ * dce_v11_0_hpd_sense - hpd sense callback.
+ *
+ * @adev: amdgpu_device pointer
+ * @hpd: hpd (hotplug detect) pin
+ *
+ * Checks if a digital monitor is connected (evergreen+).
+ * Returns true if connected, false if not connected.
+ */
+static bool dce_v11_0_hpd_sense(struct amdgpu_device *adev,
+ enum amdgpu_hpd_id hpd)
+{
+ int idx;
+ bool connected = false;
+
+ switch (hpd) {
+ case AMDGPU_HPD_1:
+ idx = 0;
+ break;
+ case AMDGPU_HPD_2:
+ idx = 1;
+ break;
+ case AMDGPU_HPD_3:
+ idx = 2;
+ break;
+ case AMDGPU_HPD_4:
+ idx = 3;
+ break;
+ case AMDGPU_HPD_5:
+ idx = 4;
+ break;
+ case AMDGPU_HPD_6:
+ idx = 5;
+ break;
+ default:
+ return connected;
+ }
+
+ if (RREG32(mmDC_HPD_INT_STATUS + hpd_offsets[idx]) &
+ DC_HPD_INT_STATUS__DC_HPD_SENSE_MASK)
+ connected = true;
+
+ return connected;
+}
+
+/**
+ * dce_v11_0_hpd_set_polarity - hpd set polarity callback.
+ *
+ * @adev: amdgpu_device pointer
+ * @hpd: hpd (hotplug detect) pin
+ *
+ * Set the polarity of the hpd pin (evergreen+).
+ */
+static void dce_v11_0_hpd_set_polarity(struct amdgpu_device *adev,
+ enum amdgpu_hpd_id hpd)
+{
+ u32 tmp;
+ bool connected = dce_v11_0_hpd_sense(adev, hpd);
+ int idx;
+
+ switch (hpd) {
+ case AMDGPU_HPD_1:
+ idx = 0;
+ break;
+ case AMDGPU_HPD_2:
+ idx = 1;
+ break;
+ case AMDGPU_HPD_3:
+ idx = 2;
+ break;
+ case AMDGPU_HPD_4:
+ idx = 3;
+ break;
+ case AMDGPU_HPD_5:
+ idx = 4;
+ break;
+ case AMDGPU_HPD_6:
+ idx = 5;
+ break;
+ default:
+ return;
+ }
+
+ tmp = RREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx]);
+ if (connected)
+ tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_POLARITY, 0);
+ else
+ tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_POLARITY, 1);
+ WREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx], tmp);
+}
+
+/**
+ * dce_v11_0_hpd_init - hpd setup callback.
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Setup the hpd pins used by the card (evergreen+).
+ * Enable the pin, set the polarity, and enable the hpd interrupts.
+ */
+static void dce_v11_0_hpd_init(struct amdgpu_device *adev)
+{
+ struct drm_device *dev = adev->ddev;
+ struct drm_connector *connector;
+ u32 tmp;
+ int idx;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+ connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+ /* don't try to enable hpd on eDP or LVDS avoid breaking the
+ * aux dp channel on imac and help (but not completely fix)
+ * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+ * also avoid interrupt storms during dpms.
+ */
+ continue;
+ }
+
+ switch (amdgpu_connector->hpd.hpd) {
+ case AMDGPU_HPD_1:
+ idx = 0;
+ break;
+ case AMDGPU_HPD_2:
+ idx = 1;
+ break;
+ case AMDGPU_HPD_3:
+ idx = 2;
+ break;
+ case AMDGPU_HPD_4:
+ idx = 3;
+ break;
+ case AMDGPU_HPD_5:
+ idx = 4;
+ break;
+ case AMDGPU_HPD_6:
+ idx = 5;
+ break;
+ default:
+ continue;
+ }
+
+ tmp = RREG32(mmDC_HPD_CONTROL + hpd_offsets[idx]);
+ tmp = REG_SET_FIELD(tmp, DC_HPD_CONTROL, DC_HPD_EN, 1);
+ WREG32(mmDC_HPD_CONTROL + hpd_offsets[idx], tmp);
+
+ tmp = RREG32(mmDC_HPD_TOGGLE_FILT_CNTL + hpd_offsets[idx]);
+ tmp = REG_SET_FIELD(tmp, DC_HPD_TOGGLE_FILT_CNTL,
+ DC_HPD_CONNECT_INT_DELAY,
+ AMDGPU_HPD_CONNECT_INT_DELAY_IN_MS);
+ tmp = REG_SET_FIELD(tmp, DC_HPD_TOGGLE_FILT_CNTL,
+ DC_HPD_DISCONNECT_INT_DELAY,
+ AMDGPU_HPD_DISCONNECT_INT_DELAY_IN_MS);
+ WREG32(mmDC_HPD_TOGGLE_FILT_CNTL + hpd_offsets[idx], tmp);
+
+ dce_v11_0_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd);
+ amdgpu_irq_get(adev, &adev->hpd_irq, amdgpu_connector->hpd.hpd);
+ }
+}
+
+/**
+ * dce_v11_0_hpd_fini - hpd tear down callback.
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Tear down the hpd pins used by the card (evergreen+).
+ * Disable the hpd interrupts.
+ */
+static void dce_v11_0_hpd_fini(struct amdgpu_device *adev)
+{
+ struct drm_device *dev = adev->ddev;
+ struct drm_connector *connector;
+ u32 tmp;
+ int idx;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+
+ switch (amdgpu_connector->hpd.hpd) {
+ case AMDGPU_HPD_1:
+ idx = 0;
+ break;
+ case AMDGPU_HPD_2:
+ idx = 1;
+ break;
+ case AMDGPU_HPD_3:
+ idx = 2;
+ break;
+ case AMDGPU_HPD_4:
+ idx = 3;
+ break;
+ case AMDGPU_HPD_5:
+ idx = 4;
+ break;
+ case AMDGPU_HPD_6:
+ idx = 5;
+ break;
+ default:
+ continue;
+ }
+
+ tmp = RREG32(mmDC_HPD_CONTROL + hpd_offsets[idx]);
+ tmp = REG_SET_FIELD(tmp, DC_HPD_CONTROL, DC_HPD_EN, 0);
+ WREG32(mmDC_HPD_CONTROL + hpd_offsets[idx], tmp);
+
+ amdgpu_irq_put(adev, &adev->hpd_irq, amdgpu_connector->hpd.hpd);
+ }
+}
+
+static u32 dce_v11_0_hpd_get_gpio_reg(struct amdgpu_device *adev)
+{
+ return mmDC_GPIO_HPD_A;
+}
+
+static bool dce_v11_0_is_display_hung(struct amdgpu_device *adev)
+{
+ u32 crtc_hung = 0;
+ u32 crtc_status[6];
+ u32 i, j, tmp;
+
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, CRTC_CONTROL, CRTC_MASTER_EN)) {
+ crtc_status[i] = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]);
+ crtc_hung |= (1 << i);
+ }
+ }
+
+ for (j = 0; j < 10; j++) {
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ if (crtc_hung & (1 << i)) {
+ tmp = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]);
+ if (tmp != crtc_status[i])
+ crtc_hung &= ~(1 << i);
+ }
+ }
+ if (crtc_hung == 0)
+ return false;
+ udelay(100);
+ }
+
+ return true;
+}
+
+static void dce_v11_0_stop_mc_access(struct amdgpu_device *adev,
+ struct amdgpu_mode_mc_save *save)
+{
+ u32 crtc_enabled, tmp;
+ int i;
+
+ save->vga_render_control = RREG32(mmVGA_RENDER_CONTROL);
+ save->vga_hdp_control = RREG32(mmVGA_HDP_CONTROL);
+
+ /* disable VGA render */
+ tmp = RREG32(mmVGA_RENDER_CONTROL);
+ tmp = REG_SET_FIELD(tmp, VGA_RENDER_CONTROL, VGA_VSTATUS_CNTL, 0);
+ WREG32(mmVGA_RENDER_CONTROL, tmp);
+
+ /* blank the display controllers */
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ crtc_enabled = REG_GET_FIELD(RREG32(mmCRTC_CONTROL + crtc_offsets[i]),
+ CRTC_CONTROL, CRTC_MASTER_EN);
+ if (crtc_enabled) {
+#if 0
+ u32 frame_count;
+ int j;
+
+ save->crtc_enabled[i] = true;
+ tmp = RREG32(mmCRTC_BLANK_CONTROL + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, CRTC_BLANK_CONTROL, CRTC_BLANK_DATA_EN) == 0) {
+ amdgpu_display_vblank_wait(adev, i);
+ WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+ tmp = REG_SET_FIELD(tmp, CRTC_BLANK_CONTROL, CRTC_BLANK_DATA_EN, 1);
+ WREG32(mmCRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
+ WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+ }
+ /* wait for the next frame */
+ frame_count = amdgpu_display_vblank_get_counter(adev, i);
+ for (j = 0; j < adev->usec_timeout; j++) {
+ if (amdgpu_display_vblank_get_counter(adev, i) != frame_count)
+ break;
+ udelay(1);
+ }
+ tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, GRPH_UPDATE, GRPH_UPDATE_LOCK) == 0) {
+ tmp = REG_SET_FIELD(tmp, GRPH_UPDATE, GRPH_UPDATE_LOCK, 1);
+ WREG32(mmGRPH_UPDATE + crtc_offsets[i], tmp);
+ }
+ tmp = RREG32(mmCRTC_MASTER_UPDATE_LOCK + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, CRTC_MASTER_UPDATE_LOCK, MASTER_UPDATE_LOCK) == 0) {
+ tmp = REG_SET_FIELD(tmp, CRTC_MASTER_UPDATE_LOCK, MASTER_UPDATE_LOCK, 1);
+ WREG32(mmCRTC_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp);
+ }
+#else
+ /* XXX this is a hack to avoid strange behavior with EFI on certain systems */
+ WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+ tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]);
+ tmp = REG_SET_FIELD(tmp, CRTC_CONTROL, CRTC_MASTER_EN, 0);
+ WREG32(mmCRTC_CONTROL + crtc_offsets[i], tmp);
+ WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+ save->crtc_enabled[i] = false;
+ /* ***** */
+#endif
+ } else {
+ save->crtc_enabled[i] = false;
+ }
+ }
+}
+
+static void dce_v11_0_resume_mc_access(struct amdgpu_device *adev,
+ struct amdgpu_mode_mc_save *save)
+{
+ u32 tmp, frame_count;
+ int i, j;
+
+ /* update crtc base addresses */
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
+ upper_32_bits(adev->mc.vram_start));
+ WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + crtc_offsets[i],
+ upper_32_bits(adev->mc.vram_start));
+ WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS + crtc_offsets[i],
+ (u32)adev->mc.vram_start);
+ WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i],
+ (u32)adev->mc.vram_start);
+
+ if (save->crtc_enabled[i]) {
+ tmp = RREG32(mmCRTC_MASTER_UPDATE_MODE + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, CRTC_MASTER_UPDATE_MODE, MASTER_UPDATE_MODE) != 3) {
+ tmp = REG_SET_FIELD(tmp, CRTC_MASTER_UPDATE_MODE, MASTER_UPDATE_MODE, 3);
+ WREG32(mmCRTC_MASTER_UPDATE_MODE + crtc_offsets[i], tmp);
+ }
+ tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, GRPH_UPDATE, GRPH_UPDATE_LOCK)) {
+ tmp = REG_SET_FIELD(tmp, GRPH_UPDATE, GRPH_UPDATE_LOCK, 0);
+ WREG32(mmGRPH_UPDATE + crtc_offsets[i], tmp);
+ }
+ tmp = RREG32(mmCRTC_MASTER_UPDATE_LOCK + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, CRTC_MASTER_UPDATE_LOCK, MASTER_UPDATE_LOCK)) {
+ tmp = REG_SET_FIELD(tmp, CRTC_MASTER_UPDATE_LOCK, MASTER_UPDATE_LOCK, 0);
+ WREG32(mmCRTC_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp);
+ }
+ for (j = 0; j < adev->usec_timeout; j++) {
+ tmp = RREG32(mmGRPH_UPDATE + crtc_offsets[i]);
+ if (REG_GET_FIELD(tmp, GRPH_UPDATE, GRPH_SURFACE_UPDATE_PENDING) == 0)
+ break;
+ udelay(1);
+ }
+ tmp = RREG32(mmCRTC_BLANK_CONTROL + crtc_offsets[i]);
+ tmp = REG_SET_FIELD(tmp, CRTC_BLANK_CONTROL, CRTC_BLANK_DATA_EN, 0);
+ WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 1);
+ WREG32(mmCRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
+ WREG32(mmCRTC_UPDATE_LOCK + crtc_offsets[i], 0);
+ /* wait for the next frame */
+ frame_count = amdgpu_display_vblank_get_counter(adev, i);
+ for (j = 0; j < adev->usec_timeout; j++) {
+ if (amdgpu_display_vblank_get_counter(adev, i) != frame_count)
+ break;
+ udelay(1);
+ }
+ }
+ }
+
+ WREG32(mmVGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(adev->mc.vram_start));
+ WREG32(mmVGA_MEMORY_BASE_ADDRESS, lower_32_bits(adev->mc.vram_start));
+
+ /* Unlock vga access */
+ WREG32(mmVGA_HDP_CONTROL, save->vga_hdp_control);
+ mdelay(1);
+ WREG32(mmVGA_RENDER_CONTROL, save->vga_render_control);
+}
+
+static void dce_v11_0_set_vga_render_state(struct amdgpu_device *adev,
+ bool render)
+{
+ u32 tmp;
+
+ /* Lockout access through VGA aperture*/
+ tmp = RREG32(mmVGA_HDP_CONTROL);
+ if (render)
+ tmp = REG_SET_FIELD(tmp, VGA_HDP_CONTROL, VGA_MEMORY_DISABLE, 0);
+ else
+ tmp = REG_SET_FIELD(tmp, VGA_HDP_CONTROL, VGA_MEMORY_DISABLE, 1);
+ WREG32(mmVGA_HDP_CONTROL, tmp);
+
+ /* disable VGA render */
+ tmp = RREG32(mmVGA_RENDER_CONTROL);
+ if (render)
+ tmp = REG_SET_FIELD(tmp, VGA_RENDER_CONTROL, VGA_VSTATUS_CNTL, 1);
+ else
+ tmp = REG_SET_FIELD(tmp, VGA_RENDER_CONTROL, VGA_VSTATUS_CNTL, 0);
+ WREG32(mmVGA_RENDER_CONTROL, tmp);
+}
+
+static void dce_v11_0_program_fmt(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
+ struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+ int bpc = 0;
+ u32 tmp = 0;
+ enum amdgpu_connector_dither dither = AMDGPU_FMT_DITHER_DISABLE;
+
+ if (connector) {
+ struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
+ bpc = amdgpu_connector_get_monitor_bpc(connector);
+ dither = amdgpu_connector->dither;
+ }
+
+ /* LVDS/eDP FMT is set up by atom */
+ if (amdgpu_encoder->devices & ATOM_DEVICE_LCD_SUPPORT)
+ return;
+
+ /* not needed for analog */
+ if ((amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1) ||
+ (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2))
+ return;
+
+ if (bpc == 0)
+ return;
+
+ switch (bpc) {
+ case 6:
+ if (dither == AMDGPU_FMT_DITHER_ENABLE) {
+ /* XXX sort out optimal dither settings */
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_FRAME_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_HIGHPASS_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_EN, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_DEPTH, 0);
+ } else {
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH, 0);
+ }
+ break;
+ case 8:
+ if (dither == AMDGPU_FMT_DITHER_ENABLE) {
+ /* XXX sort out optimal dither settings */
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_FRAME_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_HIGHPASS_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_RGB_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_EN, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_DEPTH, 1);
+ } else {
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH, 1);
+ }
+ break;
+ case 10:
+ if (dither == AMDGPU_FMT_DITHER_ENABLE) {
+ /* XXX sort out optimal dither settings */
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_FRAME_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_HIGHPASS_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_RGB_RANDOM_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_EN, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_DEPTH, 2);
+ } else {
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN, 1);
+ tmp = REG_SET_FIELD(tmp, FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH, 2);
+ }
+ break;
+ default:
+ /* not needed */
+ break;
+ }
+
+ WREG32(mmFMT_BIT_DEPTH_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+}
+
+
+/* display watermark setup */
+/**
+ * dce_v11_0_line_buffer_adjust - Set up the line buffer
+ *
+ * @adev: amdgpu_device pointer
+ * @amdgpu_crtc: the selected display controller
+ * @mode: the current display mode on the selected display
+ * controller
+ *
+ * Setup up the line buffer allocation for
+ * the selected display controller (CIK).
+ * Returns the line buffer size in pixels.
+ */
+static u32 dce_v11_0_line_buffer_adjust(struct amdgpu_device *adev,
+ struct amdgpu_crtc *amdgpu_crtc,
+ struct drm_display_mode *mode)
+{
+ u32 tmp, buffer_alloc, i, mem_cfg;
+ u32 pipe_offset = amdgpu_crtc->crtc_id;
+ /*
+ * Line Buffer Setup
+ * There are 6 line buffers, one for each display controllers.
+ * There are 3 partitions per LB. Select the number of partitions
+ * to enable based on the display width. For display widths larger
+ * than 4096, you need use to use 2 display controllers and combine
+ * them using the stereo blender.
+ */
+ if (amdgpu_crtc->base.enabled && mode) {
+ if (mode->crtc_hdisplay < 1920) {
+ mem_cfg = 1;
+ buffer_alloc = 2;
+ } else if (mode->crtc_hdisplay < 2560) {
+ mem_cfg = 2;
+ buffer_alloc = 2;
+ } else if (mode->crtc_hdisplay < 4096) {
+ mem_cfg = 0;
+ buffer_alloc = (adev->flags & AMDGPU_IS_APU) ? 2 : 4;
+ } else {
+ DRM_DEBUG_KMS("Mode too big for LB!\n");
+ mem_cfg = 0;
+ buffer_alloc = (adev->flags & AMDGPU_IS_APU) ? 2 : 4;
+ }
+ } else {
+ mem_cfg = 1;
+ buffer_alloc = 0;
+ }
+
+ tmp = RREG32(mmLB_MEMORY_CTRL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, LB_MEMORY_CTRL, LB_MEMORY_CONFIG, mem_cfg);
+ WREG32(mmLB_MEMORY_CTRL + amdgpu_crtc->crtc_offset, tmp);
+
+ tmp = RREG32(mmPIPE0_DMIF_BUFFER_CONTROL + pipe_offset);
+ tmp = REG_SET_FIELD(tmp, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED, buffer_alloc);
+ WREG32(mmPIPE0_DMIF_BUFFER_CONTROL + pipe_offset, tmp);
+
+ for (i = 0; i < adev->usec_timeout; i++) {
+ tmp = RREG32(mmPIPE0_DMIF_BUFFER_CONTROL + pipe_offset);
+ if (REG_GET_FIELD(tmp, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATION_COMPLETED))
+ break;
+ udelay(1);
+ }
+
+ if (amdgpu_crtc->base.enabled && mode) {
+ switch (mem_cfg) {
+ case 0:
+ default:
+ return 4096 * 2;
+ case 1:
+ return 1920 * 2;
+ case 2:
+ return 2560 * 2;
+ }
+ }
+
+ /* controller not enabled, so no lb used */
+ return 0;
+}
+
+/**
+ * cik_get_number_of_dram_channels - get the number of dram channels
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Look up the number of video ram channels (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the number of dram channels
+ */
+static u32 cik_get_number_of_dram_channels(struct amdgpu_device *adev)
+{
+ u32 tmp = RREG32(mmMC_SHARED_CHMAP);
+
+ switch (REG_GET_FIELD(tmp, MC_SHARED_CHMAP, NOOFCHAN)) {
+ case 0:
+ default:
+ return 1;
+ case 1:
+ return 2;
+ case 2:
+ return 4;
+ case 3:
+ return 8;
+ case 4:
+ return 3;
+ case 5:
+ return 6;
+ case 6:
+ return 10;
+ case 7:
+ return 12;
+ case 8:
+ return 16;
+ }
+}
+
+struct dce10_wm_params {
+ u32 dram_channels; /* number of dram channels */
+ u32 yclk; /* bandwidth per dram data pin in kHz */
+ u32 sclk; /* engine clock in kHz */
+ u32 disp_clk; /* display clock in kHz */
+ u32 src_width; /* viewport width */
+ u32 active_time; /* active display time in ns */
+ u32 blank_time; /* blank time in ns */
+ bool interlaced; /* mode is interlaced */
+ fixed20_12 vsc; /* vertical scale ratio */
+ u32 num_heads; /* number of active crtcs */
+ u32 bytes_per_pixel; /* bytes per pixel display + overlay */
+ u32 lb_size; /* line buffer allocated to pipe */
+ u32 vtaps; /* vertical scaler taps */
+};
+
+/**
+ * dce_v11_0_dram_bandwidth - get the dram bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the raw dram bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dram bandwidth in MBytes/s
+ */
+static u32 dce_v11_0_dram_bandwidth(struct dce10_wm_params *wm)
+{
+ /* Calculate raw DRAM Bandwidth */
+ fixed20_12 dram_efficiency; /* 0.7 */
+ fixed20_12 yclk, dram_channels, bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ yclk.full = dfixed_const(wm->yclk);
+ yclk.full = dfixed_div(yclk, a);
+ dram_channels.full = dfixed_const(wm->dram_channels * 4);
+ a.full = dfixed_const(10);
+ dram_efficiency.full = dfixed_const(7);
+ dram_efficiency.full = dfixed_div(dram_efficiency, a);
+ bandwidth.full = dfixed_mul(dram_channels, yclk);
+ bandwidth.full = dfixed_mul(bandwidth, dram_efficiency);
+
+ return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v11_0_dram_bandwidth_for_display - get the dram bandwidth for display
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the dram bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dram bandwidth for display in MBytes/s
+ */
+static u32 dce_v11_0_dram_bandwidth_for_display(struct dce10_wm_params *wm)
+{
+ /* Calculate DRAM Bandwidth and the part allocated to display. */
+ fixed20_12 disp_dram_allocation; /* 0.3 to 0.7 */
+ fixed20_12 yclk, dram_channels, bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ yclk.full = dfixed_const(wm->yclk);
+ yclk.full = dfixed_div(yclk, a);
+ dram_channels.full = dfixed_const(wm->dram_channels * 4);
+ a.full = dfixed_const(10);
+ disp_dram_allocation.full = dfixed_const(3); /* XXX worse case value 0.3 */
+ disp_dram_allocation.full = dfixed_div(disp_dram_allocation, a);
+ bandwidth.full = dfixed_mul(dram_channels, yclk);
+ bandwidth.full = dfixed_mul(bandwidth, disp_dram_allocation);
+
+ return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v11_0_data_return_bandwidth - get the data return bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the data return bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the data return bandwidth in MBytes/s
+ */
+static u32 dce_v11_0_data_return_bandwidth(struct dce10_wm_params *wm)
+{
+ /* Calculate the display Data return Bandwidth */
+ fixed20_12 return_efficiency; /* 0.8 */
+ fixed20_12 sclk, bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ sclk.full = dfixed_const(wm->sclk);
+ sclk.full = dfixed_div(sclk, a);
+ a.full = dfixed_const(10);
+ return_efficiency.full = dfixed_const(8);
+ return_efficiency.full = dfixed_div(return_efficiency, a);
+ a.full = dfixed_const(32);
+ bandwidth.full = dfixed_mul(a, sclk);
+ bandwidth.full = dfixed_mul(bandwidth, return_efficiency);
+
+ return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v11_0_dmif_request_bandwidth - get the dmif bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the dmif bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the dmif bandwidth in MBytes/s
+ */
+static u32 dce_v11_0_dmif_request_bandwidth(struct dce10_wm_params *wm)
+{
+ /* Calculate the DMIF Request Bandwidth */
+ fixed20_12 disp_clk_request_efficiency; /* 0.8 */
+ fixed20_12 disp_clk, bandwidth;
+ fixed20_12 a, b;
+
+ a.full = dfixed_const(1000);
+ disp_clk.full = dfixed_const(wm->disp_clk);
+ disp_clk.full = dfixed_div(disp_clk, a);
+ a.full = dfixed_const(32);
+ b.full = dfixed_mul(a, disp_clk);
+
+ a.full = dfixed_const(10);
+ disp_clk_request_efficiency.full = dfixed_const(8);
+ disp_clk_request_efficiency.full = dfixed_div(disp_clk_request_efficiency, a);
+
+ bandwidth.full = dfixed_mul(b, disp_clk_request_efficiency);
+
+ return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v11_0_available_bandwidth - get the min available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the min available bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the min available bandwidth in MBytes/s
+ */
+static u32 dce_v11_0_available_bandwidth(struct dce10_wm_params *wm)
+{
+ /* Calculate the Available bandwidth. Display can use this temporarily but not in average. */
+ u32 dram_bandwidth = dce_v11_0_dram_bandwidth(wm);
+ u32 data_return_bandwidth = dce_v11_0_data_return_bandwidth(wm);
+ u32 dmif_req_bandwidth = dce_v11_0_dmif_request_bandwidth(wm);
+
+ return min(dram_bandwidth, min(data_return_bandwidth, dmif_req_bandwidth));
+}
+
+/**
+ * dce_v11_0_average_bandwidth - get the average available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the average available bandwidth used for display (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the average available bandwidth in MBytes/s
+ */
+static u32 dce_v11_0_average_bandwidth(struct dce10_wm_params *wm)
+{
+ /* Calculate the display mode Average Bandwidth
+ * DisplayMode should contain the source and destination dimensions,
+ * timing, etc.
+ */
+ fixed20_12 bpp;
+ fixed20_12 line_time;
+ fixed20_12 src_width;
+ fixed20_12 bandwidth;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1000);
+ line_time.full = dfixed_const(wm->active_time + wm->blank_time);
+ line_time.full = dfixed_div(line_time, a);
+ bpp.full = dfixed_const(wm->bytes_per_pixel);
+ src_width.full = dfixed_const(wm->src_width);
+ bandwidth.full = dfixed_mul(src_width, bpp);
+ bandwidth.full = dfixed_mul(bandwidth, wm->vsc);
+ bandwidth.full = dfixed_div(bandwidth, line_time);
+
+ return dfixed_trunc(bandwidth);
+}
+
+/**
+ * dce_v11_0_latency_watermark - get the latency watermark
+ *
+ * @wm: watermark calculation data
+ *
+ * Calculate the latency watermark (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns the latency watermark in ns
+ */
+static u32 dce_v11_0_latency_watermark(struct dce10_wm_params *wm)
+{
+ /* First calculate the latency in ns */
+ u32 mc_latency = 2000; /* 2000 ns. */
+ u32 available_bandwidth = dce_v11_0_available_bandwidth(wm);
+ u32 worst_chunk_return_time = (512 * 8 * 1000) / available_bandwidth;
+ u32 cursor_line_pair_return_time = (128 * 4 * 1000) / available_bandwidth;
+ u32 dc_latency = 40000000 / wm->disp_clk; /* dc pipe latency */
+ u32 other_heads_data_return_time = ((wm->num_heads + 1) * worst_chunk_return_time) +
+ (wm->num_heads * cursor_line_pair_return_time);
+ u32 latency = mc_latency + other_heads_data_return_time + dc_latency;
+ u32 max_src_lines_per_dst_line, lb_fill_bw, line_fill_time;
+ u32 tmp, dmif_size = 12288;
+ fixed20_12 a, b, c;
+
+ if (wm->num_heads == 0)
+ return 0;
+
+ a.full = dfixed_const(2);
+ b.full = dfixed_const(1);
+ if ((wm->vsc.full > a.full) ||
+ ((wm->vsc.full > b.full) && (wm->vtaps >= 3)) ||
+ (wm->vtaps >= 5) ||
+ ((wm->vsc.full >= a.full) && wm->interlaced))
+ max_src_lines_per_dst_line = 4;
+ else
+ max_src_lines_per_dst_line = 2;
+
+ a.full = dfixed_const(available_bandwidth);
+ b.full = dfixed_const(wm->num_heads);
+ a.full = dfixed_div(a, b);
+
+ b.full = dfixed_const(mc_latency + 512);
+ c.full = dfixed_const(wm->disp_clk);
+ b.full = dfixed_div(b, c);
+
+ c.full = dfixed_const(dmif_size);
+ b.full = dfixed_div(c, b);
+
+ tmp = min(dfixed_trunc(a), dfixed_trunc(b));
+
+ b.full = dfixed_const(1000);
+ c.full = dfixed_const(wm->disp_clk);
+ b.full = dfixed_div(c, b);
+ c.full = dfixed_const(wm->bytes_per_pixel);
+ b.full = dfixed_mul(b, c);
+
+ lb_fill_bw = min(tmp, dfixed_trunc(b));
+
+ a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
+ b.full = dfixed_const(1000);
+ c.full = dfixed_const(lb_fill_bw);
+ b.full = dfixed_div(c, b);
+ a.full = dfixed_div(a, b);
+ line_fill_time = dfixed_trunc(a);
+
+ if (line_fill_time < wm->active_time)
+ return latency;
+ else
+ return latency + (line_fill_time - wm->active_time);
+
+}
+
+/**
+ * dce_v11_0_average_bandwidth_vs_dram_bandwidth_for_display - check
+ * average and available dram bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Check if the display average bandwidth fits in the display
+ * dram bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce_v11_0_average_bandwidth_vs_dram_bandwidth_for_display(struct dce10_wm_params *wm)
+{
+ if (dce_v11_0_average_bandwidth(wm) <=
+ (dce_v11_0_dram_bandwidth_for_display(wm) / wm->num_heads))
+ return true;
+ else
+ return false;
+}
+
+/**
+ * dce_v11_0_average_bandwidth_vs_available_bandwidth - check
+ * average and available bandwidth
+ *
+ * @wm: watermark calculation data
+ *
+ * Check if the display average bandwidth fits in the display
+ * available bandwidth (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce_v11_0_average_bandwidth_vs_available_bandwidth(struct dce10_wm_params *wm)
+{
+ if (dce_v11_0_average_bandwidth(wm) <=
+ (dce_v11_0_available_bandwidth(wm) / wm->num_heads))
+ return true;
+ else
+ return false;
+}
+
+/**
+ * dce_v11_0_check_latency_hiding - check latency hiding
+ *
+ * @wm: watermark calculation data
+ *
+ * Check latency hiding (CIK).
+ * Used for display watermark bandwidth calculations
+ * Returns true if the display fits, false if not.
+ */
+static bool dce_v11_0_check_latency_hiding(struct dce10_wm_params *wm)
+{
+ u32 lb_partitions = wm->lb_size / wm->src_width;
+ u32 line_time = wm->active_time + wm->blank_time;
+ u32 latency_tolerant_lines;
+ u32 latency_hiding;
+ fixed20_12 a;
+
+ a.full = dfixed_const(1);
+ if (wm->vsc.full > a.full)
+ latency_tolerant_lines = 1;
+ else {
+ if (lb_partitions <= (wm->vtaps + 1))
+ latency_tolerant_lines = 1;
+ else
+ latency_tolerant_lines = 2;
+ }
+
+ latency_hiding = (latency_tolerant_lines * line_time + wm->blank_time);
+
+ if (dce_v11_0_latency_watermark(wm) <= latency_hiding)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * dce_v11_0_program_watermarks - program display watermarks
+ *
+ * @adev: amdgpu_device pointer
+ * @amdgpu_crtc: the selected display controller
+ * @lb_size: line buffer size
+ * @num_heads: number of display controllers in use
+ *
+ * Calculate and program the display watermarks for the
+ * selected display controller (CIK).
+ */
+static void dce_v11_0_program_watermarks(struct amdgpu_device *adev,
+ struct amdgpu_crtc *amdgpu_crtc,
+ u32 lb_size, u32 num_heads)
+{
+ struct drm_display_mode *mode = &amdgpu_crtc->base.mode;
+ struct dce10_wm_params wm_low, wm_high;
+ u32 pixel_period;
+ u32 line_time = 0;
+ u32 latency_watermark_a = 0, latency_watermark_b = 0;
+ u32 tmp, wm_mask;
+
+ if (amdgpu_crtc->base.enabled && num_heads && mode) {
+ pixel_period = 1000000 / (u32)mode->clock;
+ line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+
+ /* watermark for high clocks */
+ if (adev->pm.dpm_enabled) {
+ wm_high.yclk =
+ amdgpu_dpm_get_mclk(adev, false) * 10;
+ wm_high.sclk =
+ amdgpu_dpm_get_sclk(adev, false) * 10;
+ } else {
+ wm_high.yclk = adev->pm.current_mclk * 10;
+ wm_high.sclk = adev->pm.current_sclk * 10;
+ }
+
+ wm_high.disp_clk = mode->clock;
+ wm_high.src_width = mode->crtc_hdisplay;
+ wm_high.active_time = mode->crtc_hdisplay * pixel_period;
+ wm_high.blank_time = line_time - wm_high.active_time;
+ wm_high.interlaced = false;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ wm_high.interlaced = true;
+ wm_high.vsc = amdgpu_crtc->vsc;
+ wm_high.vtaps = 1;
+ if (amdgpu_crtc->rmx_type != RMX_OFF)
+ wm_high.vtaps = 2;
+ wm_high.bytes_per_pixel = 4; /* XXX: get this from fb config */
+ wm_high.lb_size = lb_size;
+ wm_high.dram_channels = cik_get_number_of_dram_channels(adev);
+ wm_high.num_heads = num_heads;
+
+ /* set for high clocks */
+ latency_watermark_a = min(dce_v11_0_latency_watermark(&wm_high), (u32)65535);
+
+ /* possibly force display priority to high */
+ /* should really do this at mode validation time... */
+ if (!dce_v11_0_average_bandwidth_vs_dram_bandwidth_for_display(&wm_high) ||
+ !dce_v11_0_average_bandwidth_vs_available_bandwidth(&wm_high) ||
+ !dce_v11_0_check_latency_hiding(&wm_high) ||
+ (adev->mode_info.disp_priority == 2)) {
+ DRM_DEBUG_KMS("force priority to high\n");
+ }
+
+ /* watermark for low clocks */
+ if (adev->pm.dpm_enabled) {
+ wm_low.yclk =
+ amdgpu_dpm_get_mclk(adev, true) * 10;
+ wm_low.sclk =
+ amdgpu_dpm_get_sclk(adev, true) * 10;
+ } else {
+ wm_low.yclk = adev->pm.current_mclk * 10;
+ wm_low.sclk = adev->pm.current_sclk * 10;
+ }
+
+ wm_low.disp_clk = mode->clock;
+ wm_low.src_width = mode->crtc_hdisplay;
+ wm_low.active_time = mode->crtc_hdisplay * pixel_period;
+ wm_low.blank_time = line_time - wm_low.active_time;
+ wm_low.interlaced = false;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ wm_low.interlaced = true;
+ wm_low.vsc = amdgpu_crtc->vsc;
+ wm_low.vtaps = 1;
+ if (amdgpu_crtc->rmx_type != RMX_OFF)
+ wm_low.vtaps = 2;
+ wm_low.bytes_per_pixel = 4; /* XXX: get this from fb config */
+ wm_low.lb_size = lb_size;
+ wm_low.dram_channels = cik_get_number_of_dram_channels(adev);
+ wm_low.num_heads = num_heads;
+
+ /* set for low clocks */
+ latency_watermark_b = min(dce_v11_0_latency_watermark(&wm_low), (u32)65535);
+
+ /* possibly force display priority to high */
+ /* should really do this at mode validation time... */
+ if (!dce_v11_0_average_bandwidth_vs_dram_bandwidth_for_display(&wm_low) ||
+ !dce_v11_0_average_bandwidth_vs_available_bandwidth(&wm_low) ||
+ !dce_v11_0_check_latency_hiding(&wm_low) ||
+ (adev->mode_info.disp_priority == 2)) {
+ DRM_DEBUG_KMS("force priority to high\n");
+ }
+ }
+
+ /* select wm A */
+ wm_mask = RREG32(mmDPG_WATERMARK_MASK_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(wm_mask, DPG_WATERMARK_MASK_CONTROL, URGENCY_WATERMARK_MASK, 1);
+ WREG32(mmDPG_WATERMARK_MASK_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+ tmp = RREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, latency_watermark_a);
+ tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_HIGH_WATERMARK, line_time);
+ WREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+ /* select wm B */
+ tmp = REG_SET_FIELD(wm_mask, DPG_WATERMARK_MASK_CONTROL, URGENCY_WATERMARK_MASK, 2);
+ WREG32(mmDPG_WATERMARK_MASK_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+ tmp = RREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset);
+ tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, latency_watermark_a);
+ tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_HIGH_WATERMARK, line_time);
+ WREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset, tmp);
+ /* restore original selection */
+ WREG32(mmDPG_WATERMARK_MASK_CONTROL + amdgpu_crtc->crtc_offset, wm_mask);
+
+ /* save values for DPM */
+ amdgpu_crtc->line_time = line_time;
+ amdgpu_crtc->wm_high = latency_watermark_a;
+ amdgpu_crtc->wm_low = latency_watermark_b;
+}
+
+/**
+ * dce_v11_0_bandwidth_update - program display watermarks
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Calculate and program the display watermarks and line
+ * buffer allocation (CIK).
+ */
+static void dce_v11_0_bandwidth_update(struct amdgpu_device *adev)
+{
+ struct drm_display_mode *mode = NULL;
+ u32 num_heads = 0, lb_size;
+ int i;
+
+ amdgpu_update_display_priority(adev);
+
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ if (adev->mode_info.crtcs[i]->base.enabled)
+ num_heads++;
+ }
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ mode = &adev->mode_info.crtcs[i]->base.mode;
+ lb_size = dce_v11_0_line_buffer_adjust(adev, adev->mode_info.crtcs[i], mode);
+ dce_v11_0_program_watermarks(adev, adev->mode_info.crtcs[i],
+ lb_size, num_heads);
+ }
+}
+
+static void dce_v11_0_audio_get_connected_pins(struct amdgpu_device *adev)
+{
+ int i;
+ u32 offset, tmp;
+
+ for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+ offset = adev->mode_info.audio.pin[i].offset;
+ tmp = RREG32_AUDIO_ENDPT(offset,
+ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
+ if (((tmp &
+ AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT__PORT_CONNECTIVITY_MASK) >>
+ AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT__PORT_CONNECTIVITY__SHIFT) == 1)
+ adev->mode_info.audio.pin[i].connected = false;
+ else
+ adev->mode_info.audio.pin[i].connected = true;
+ }
+}
+
+static struct amdgpu_audio_pin *dce_v11_0_audio_get_pin(struct amdgpu_device *adev)
+{
+ int i;
+
+ dce_v11_0_audio_get_connected_pins(adev);
+
+ for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+ if (adev->mode_info.audio.pin[i].connected)
+ return &adev->mode_info.audio.pin[i];
+ }
+ DRM_ERROR("No connected audio pins found!\n");
+ return NULL;
+}
+
+static void dce_v11_0_afmt_audio_select_pin(struct drm_encoder *encoder)
+{
+ struct amdgpu_device *adev = encoder->dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ u32 tmp;
+
+ if (!dig || !dig->afmt || !dig->afmt->pin)
+ return;
+
+ tmp = RREG32(mmAFMT_AUDIO_SRC_CONTROL + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_SRC_CONTROL, AFMT_AUDIO_SRC_SELECT, dig->afmt->pin->id);
+ WREG32(mmAFMT_AUDIO_SRC_CONTROL + dig->afmt->offset, tmp);
+}
+
+static void dce_v11_0_audio_write_latency_fields(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ struct amdgpu_device *adev = encoder->dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector = NULL;
+ u32 tmp;
+ int interlace = 0;
+
+ if (!dig || !dig->afmt || !dig->afmt->pin)
+ return;
+
+ list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
+ if (connector->encoder == encoder) {
+ amdgpu_connector = to_amdgpu_connector(connector);
+ break;
+ }
+ }
+
+ if (!amdgpu_connector) {
+ DRM_ERROR("Couldn't find encoder's connector\n");
+ return;
+ }
+
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ interlace = 1;
+ if (connector->latency_present[interlace]) {
+ tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+ VIDEO_LIPSYNC, connector->video_latency[interlace]);
+ tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+ AUDIO_LIPSYNC, connector->audio_latency[interlace]);
+ } else {
+ tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+ VIDEO_LIPSYNC, 0);
+ tmp = REG_SET_FIELD(0, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
+ AUDIO_LIPSYNC, 0);
+ }
+ WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
+ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
+}
+
+static void dce_v11_0_audio_write_speaker_allocation(struct drm_encoder *encoder)
+{
+ struct amdgpu_device *adev = encoder->dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector = NULL;
+ u32 tmp;
+ u8 *sadb = NULL;
+ int sad_count;
+
+ if (!dig || !dig->afmt || !dig->afmt->pin)
+ return;
+
+ list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
+ if (connector->encoder == encoder) {
+ amdgpu_connector = to_amdgpu_connector(connector);
+ break;
+ }
+ }
+
+ if (!amdgpu_connector) {
+ DRM_ERROR("Couldn't find encoder's connector\n");
+ return;
+ }
+
+ sad_count = drm_edid_to_speaker_allocation(amdgpu_connector_edid(connector), &sadb);
+ if (sad_count < 0) {
+ DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
+ sad_count = 0;
+ }
+
+ /* program the speaker allocation */
+ tmp = RREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
+ ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+ DP_CONNECTION, 0);
+ /* set HDMI mode */
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+ HDMI_CONNECTION, 1);
+ if (sad_count)
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+ SPEAKER_ALLOCATION, sadb[0]);
+ else
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
+ SPEAKER_ALLOCATION, 5); /* stereo */
+ WREG32_AUDIO_ENDPT(dig->afmt->pin->offset,
+ ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
+
+ kfree(sadb);
+}
+
+static void dce_v11_0_audio_write_sad_regs(struct drm_encoder *encoder)
+{
+ struct amdgpu_device *adev = encoder->dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct drm_connector *connector;
+ struct amdgpu_connector *amdgpu_connector = NULL;
+ struct cea_sad *sads;
+ int i, sad_count;
+
+ static const u16 eld_reg_to_type[][2] = {
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP },
+ { ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
+ };
+
+ if (!dig || !dig->afmt || !dig->afmt->pin)
+ return;
+
+ list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
+ if (connector->encoder == encoder) {
+ amdgpu_connector = to_amdgpu_connector(connector);
+ break;
+ }
+ }
+
+ if (!amdgpu_connector) {
+ DRM_ERROR("Couldn't find encoder's connector\n");
+ return;
+ }
+
+ sad_count = drm_edid_to_sad(amdgpu_connector_edid(connector), &sads);
+ if (sad_count <= 0) {
+ DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
+ return;
+ }
+ BUG_ON(!sads);
+
+ for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
+ u32 tmp = 0;
+ u8 stereo_freqs = 0;
+ int max_channels = -1;
+ int j;
+
+ for (j = 0; j < sad_count; j++) {
+ struct cea_sad *sad = &sads[j];
+
+ if (sad->format == eld_reg_to_type[i][1]) {
+ if (sad->channels > max_channels) {
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+ MAX_CHANNELS, sad->channels);
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+ DESCRIPTOR_BYTE_2, sad->byte2);
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+ SUPPORTED_FREQUENCIES, sad->freq);
+ max_channels = sad->channels;
+ }
+
+ if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
+ stereo_freqs |= sad->freq;
+ else
+ break;
+ }
+ }
+
+ tmp = REG_SET_FIELD(tmp, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
+ SUPPORTED_FREQUENCIES_STEREO, stereo_freqs);
+ WREG32_AUDIO_ENDPT(dig->afmt->pin->offset, eld_reg_to_type[i][0], tmp);
+ }
+
+ kfree(sads);
+}
+
+static void dce_v11_0_audio_enable(struct amdgpu_device *adev,
+ struct amdgpu_audio_pin *pin,
+ bool enable)
+{
+ if (!pin)
+ return;
+
+ WREG32_AUDIO_ENDPT(pin->offset, ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
+ enable ? AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL__AUDIO_ENABLED_MASK : 0);
+}
+
+static const u32 pin_offsets[] =
+{
+ AUD0_REGISTER_OFFSET,
+ AUD1_REGISTER_OFFSET,
+ AUD2_REGISTER_OFFSET,
+ AUD3_REGISTER_OFFSET,
+ AUD4_REGISTER_OFFSET,
+ AUD5_REGISTER_OFFSET,
+ AUD6_REGISTER_OFFSET,
+};
+
+static int dce_v11_0_audio_init(struct amdgpu_device *adev)
+{
+ int i;
+
+ if (!amdgpu_audio)
+ return 0;
+
+ adev->mode_info.audio.enabled = true;
+
+ adev->mode_info.audio.num_pins = 7;
+
+ for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
+ adev->mode_info.audio.pin[i].channels = -1;
+ adev->mode_info.audio.pin[i].rate = -1;
+ adev->mode_info.audio.pin[i].bits_per_sample = -1;
+ adev->mode_info.audio.pin[i].status_bits = 0;
+ adev->mode_info.audio.pin[i].category_code = 0;
+ adev->mode_info.audio.pin[i].connected = false;
+ adev->mode_info.audio.pin[i].offset = pin_offsets[i];
+ adev->mode_info.audio.pin[i].id = i;
+ /* disable audio. it will be set up later */
+ /* XXX remove once we switch to ip funcs */
+ dce_v11_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
+ }
+
+ return 0;
+}
+
+static void dce_v11_0_audio_fini(struct amdgpu_device *adev)
+{
+ int i;
+
+ if (!adev->mode_info.audio.enabled)
+ return;
+
+ for (i = 0; i < adev->mode_info.audio.num_pins; i++)
+ dce_v11_0_audio_enable(adev, &adev->mode_info.audio.pin[i], false);
+
+ adev->mode_info.audio.enabled = false;
+}
+
+/*
+ * update the N and CTS parameters for a given pixel clock rate
+ */
+static void dce_v11_0_afmt_update_ACR(struct drm_encoder *encoder, uint32_t clock)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_afmt_acr acr = amdgpu_afmt_acr(clock);
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ u32 tmp;
+
+ tmp = RREG32(mmHDMI_ACR_32_0 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_32_0, HDMI_ACR_CTS_32, acr.cts_32khz);
+ WREG32(mmHDMI_ACR_32_0 + dig->afmt->offset, tmp);
+ tmp = RREG32(mmHDMI_ACR_32_1 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_32_1, HDMI_ACR_N_32, acr.n_32khz);
+ WREG32(mmHDMI_ACR_32_1 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_ACR_44_0 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_44_0, HDMI_ACR_CTS_44, acr.cts_44_1khz);
+ WREG32(mmHDMI_ACR_44_0 + dig->afmt->offset, tmp);
+ tmp = RREG32(mmHDMI_ACR_44_1 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_44_1, HDMI_ACR_N_44, acr.n_44_1khz);
+ WREG32(mmHDMI_ACR_44_1 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_ACR_48_0 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_48_0, HDMI_ACR_CTS_48, acr.cts_48khz);
+ WREG32(mmHDMI_ACR_48_0 + dig->afmt->offset, tmp);
+ tmp = RREG32(mmHDMI_ACR_48_1 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_48_1, HDMI_ACR_N_48, acr.n_48khz);
+ WREG32(mmHDMI_ACR_48_1 + dig->afmt->offset, tmp);
+
+}
+
+/*
+ * build a HDMI Video Info Frame
+ */
+static void dce_v11_0_afmt_update_avi_infoframe(struct drm_encoder *encoder,
+ void *buffer, size_t size)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ uint8_t *frame = buffer + 3;
+ uint8_t *header = buffer;
+
+ WREG32(mmAFMT_AVI_INFO0 + dig->afmt->offset,
+ frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
+ WREG32(mmAFMT_AVI_INFO1 + dig->afmt->offset,
+ frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24));
+ WREG32(mmAFMT_AVI_INFO2 + dig->afmt->offset,
+ frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
+ WREG32(mmAFMT_AVI_INFO3 + dig->afmt->offset,
+ frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
+}
+
+static void dce_v11_0_audio_set_dto(struct drm_encoder *encoder, u32 clock)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
+ u32 dto_phase = 24 * 1000;
+ u32 dto_modulo = clock;
+ u32 tmp;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ /* XXX two dtos; generally use dto0 for hdmi */
+ /* Express [24MHz / target pixel clock] as an exact rational
+ * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
+ * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+ */
+ tmp = RREG32(mmDCCG_AUDIO_DTO_SOURCE);
+ tmp = REG_SET_FIELD(tmp, DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL,
+ amdgpu_crtc->crtc_id);
+ WREG32(mmDCCG_AUDIO_DTO_SOURCE, tmp);
+ WREG32(mmDCCG_AUDIO_DTO0_PHASE, dto_phase);
+ WREG32(mmDCCG_AUDIO_DTO0_MODULE, dto_modulo);
+}
+
+/*
+ * update the info frames with the data from the current display mode
+ */
+static void dce_v11_0_afmt_setmode(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ struct drm_device *dev = encoder->dev;
+ struct amdgpu_device *adev = dev->dev_private;
+ struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+ struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+ struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
+ u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
+ struct hdmi_avi_infoframe frame;
+ ssize_t err;
+ u32 tmp;
+ int bpc = 8;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ /* Silent, r600_hdmi_enable will raise WARN for us */
+ if (!dig->afmt->enabled)
+ return;
+
+ /* hdmi deep color mode general control packets setup, if bpc > 8 */
+ if (encoder->crtc) {
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
+ bpc = amdgpu_crtc->bpc;
+ }
+
+ /* disable audio prior to setting up hw */
+ dig->afmt->pin = dce_v11_0_audio_get_pin(adev);
+ dce_v11_0_audio_enable(adev, dig->afmt->pin, false);
+
+ dce_v11_0_audio_set_dto(encoder, mode->clock);
+
+ tmp = RREG32(mmHDMI_VBI_PACKET_CONTROL + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_VBI_PACKET_CONTROL, HDMI_NULL_SEND, 1);
+ WREG32(mmHDMI_VBI_PACKET_CONTROL + dig->afmt->offset, tmp); /* send null packets when required */
+
+ WREG32(mmAFMT_AUDIO_CRC_CONTROL + dig->afmt->offset, 0x1000);
+
+ tmp = RREG32(mmHDMI_CONTROL + dig->afmt->offset);
+ switch (bpc) {
+ case 0:
+ case 6:
+ case 8:
+ case 16:
+ default:
+ tmp = REG_SET_FIELD(tmp, HDMI_CONTROL, HDMI_DEEP_COLOR_ENABLE, 0);
+ tmp = REG_SET_FIELD(tmp, HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 0);
+ DRM_DEBUG("%s: Disabling hdmi deep color for %d bpc.\n",
+ connector->name, bpc);
+ break;
+ case 10:
+ tmp = REG_SET_FIELD(tmp, HDMI_CONTROL, HDMI_DEEP_COLOR_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 1);
+ DRM_DEBUG("%s: Enabling hdmi deep color 30 for 10 bpc.\n",
+ connector->name);
+ break;
+ case 12:
+ tmp = REG_SET_FIELD(tmp, HDMI_CONTROL, HDMI_DEEP_COLOR_ENABLE, 1);
+ tmp = REG_SET_FIELD(tmp, HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 2);
+ DRM_DEBUG("%s: Enabling hdmi deep color 36 for 12 bpc.\n",
+ connector->name);
+ break;
+ }
+ WREG32(mmHDMI_CONTROL + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_VBI_PACKET_CONTROL + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, HDMI_VBI_PACKET_CONTROL, HDMI_NULL_SEND, 1); /* send null packets when required */
+ tmp = REG_SET_FIELD(tmp, HDMI_VBI_PACKET_CONTROL, HDMI_GC_SEND, 1); /* send general control packets */
+ tmp = REG_SET_FIELD(tmp, HDMI_VBI_PACKET_CONTROL, HDMI_GC_CONT, 1); /* send general control packets every frame */
+ WREG32(mmHDMI_VBI_PACKET_CONTROL + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_INFOFRAME_CONTROL0 + dig->afmt->offset);
+ /* enable audio info frames (frames won't be set until audio is enabled) */
+ tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_SEND, 1);
+ /* required for audio info values to be updated */
+ tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_CONT, 1);
+ WREG32(mmHDMI_INFOFRAME_CONTROL0 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmAFMT_INFOFRAME_CONTROL0 + dig->afmt->offset);
+ /* required for audio info values to be updated */
+ tmp = REG_SET_FIELD(tmp, AFMT_INFOFRAME_CONTROL0, AFMT_AUDIO_INFO_UPDATE, 1);
+ WREG32(mmAFMT_INFOFRAME_CONTROL0 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset);
+ /* anything other than 0 */
+ tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL1, HDMI_AUDIO_INFO_LINE, 2);
+ WREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset, tmp);
+
+ WREG32(mmHDMI_GC + dig->afmt->offset, 0); /* unset HDMI_GC_AVMUTE */
+
+ tmp = RREG32(mmHDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset);
+ /* set the default audio delay */
+ tmp = REG_SET_FIELD(tmp, HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_DELAY_EN, 1);
+ /* should be suffient for all audio modes and small enough for all hblanks */
+ tmp = REG_SET_FIELD(tmp, HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_PACKETS_PER_LINE, 3);
+ WREG32(mmHDMI_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset);
+ /* allow 60958 channel status fields to be updated */
+ tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_60958_CS_UPDATE, 1);
+ WREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmHDMI_ACR_PACKET_CONTROL + dig->afmt->offset);
+ if (bpc > 8)
+ /* clear SW CTS value */
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_PACKET_CONTROL, HDMI_ACR_SOURCE, 0);
+ else
+ /* select SW CTS value */
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_PACKET_CONTROL, HDMI_ACR_SOURCE, 1);
+ /* allow hw to sent ACR packets when required */
+ tmp = REG_SET_FIELD(tmp, HDMI_ACR_PACKET_CONTROL, HDMI_ACR_AUTO_SEND, 1);
+ WREG32(mmHDMI_ACR_PACKET_CONTROL + dig->afmt->offset, tmp);
+
+ dce_v11_0_afmt_update_ACR(encoder, mode->clock);
+
+ tmp = RREG32(mmAFMT_60958_0 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_0, AFMT_60958_CS_CHANNEL_NUMBER_L, 1);
+ WREG32(mmAFMT_60958_0 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmAFMT_60958_1 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_1, AFMT_60958_CS_CHANNEL_NUMBER_R, 2);
+ WREG32(mmAFMT_60958_1 + dig->afmt->offset, tmp);
+
+ tmp = RREG32(mmAFMT_60958_2 + dig->afmt->offset);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_2, 3);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_3, 4);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_4, 5);
+ tmp = REG_SET_FIELD(tmp, AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_5, 6);
+